6e3f69f504
fte particle scripts are disabled (classic works). I'll fix these in the new year. Redid framestate stuff again. Slightly better now, but this is the bulk of the changes here. Reworked the renderqueue to provide batches of items instead of individual items. This cleans up the particle rendering code significantly, and is a step towards multiple concurrent particle systems. fte's scripted particles are broken as I'm trying to find a way to rework them to batch types together, rather than having to restart each batch after each particle when you have two particles in a trail. I'll fix it some time. Reworked some alias model code regarding skeletal models. Added some conceptual skeletal bone control builtins available to csqc. Currently it can query the bone names and save off animation states, but can't animate - its just not complete. Added more info to glsl custom shaders. Updated surface sorting on halflife maps to properly cope with alphaed entities, rather than just texture-based blends (q2-style). git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3095 fc73d0e0-1445-4013-8a0c-d673dee63da5
773 lines
16 KiB
C
773 lines
16 KiB
C
#define PROGSUSED
|
|
#include "progsint.h"
|
|
#include <stdlib.h>
|
|
|
|
typedef struct prmemb_s {
|
|
struct prmemb_s *prev;
|
|
int level;
|
|
} prmemb_t;
|
|
void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount)
|
|
{
|
|
prmemb_t *mem;
|
|
ammount = sizeof(prmemb_t)+((ammount + 3)&~3);
|
|
mem = memalloc(ammount);
|
|
memset(mem, 0, ammount);
|
|
mem->prev = memb;
|
|
if (!memb)
|
|
mem->level = 1;
|
|
else
|
|
mem->level = ((prmemb_t *)memb)->level+1;
|
|
memb = mem;
|
|
|
|
return ((char *)mem)+sizeof(prmemb_t);
|
|
}
|
|
|
|
int PRHunkMark(progfuncs_t *progfuncs)
|
|
{
|
|
return ((prmemb_t *)memb)->level;
|
|
}
|
|
void PRHunkFree(progfuncs_t *progfuncs, int mark)
|
|
{
|
|
prmemb_t *omem;
|
|
while(memb)
|
|
{
|
|
if (memb->level <= mark)
|
|
return;
|
|
|
|
omem = memb;
|
|
memb = memb->prev;
|
|
memfree(omem);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//for 64bit systems. :)
|
|
//addressable memory is memory available to the vm itself for writing.
|
|
//once allocated, it cannot be freed for the lifetime of the VM.
|
|
void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount)
|
|
{
|
|
ammount = (ammount + 4)&~3; //round up to 4
|
|
if (addressableused + ammount > addressablesize)
|
|
Sys_Error("Not enough addressable memory for progs VM");
|
|
|
|
addressableused += ammount;
|
|
|
|
#ifdef _WIN32
|
|
if (!VirtualAlloc (addressablehunk, addressableused, MEM_COMMIT, PAGE_READWRITE))
|
|
Sys_Error("VirtualAlloc failed. Blame windows.");
|
|
#endif
|
|
|
|
return &addressablehunk[addressableused-ammount];
|
|
}
|
|
|
|
void PRAddressableFlush(progfuncs_t *progfuncs, int totalammount)
|
|
{
|
|
addressableused = 0;
|
|
if (totalammount < 0) //flush
|
|
{
|
|
totalammount = addressablesize;
|
|
// return;
|
|
}
|
|
|
|
if (addressablehunk)
|
|
#ifdef _WIN32
|
|
VirtualFree(addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
|
|
addressablehunk = VirtualAlloc (NULL, totalammount, MEM_RESERVE, PAGE_NOACCESS);
|
|
#else
|
|
free(addressablehunk);
|
|
addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy.
|
|
// memset(addressablehunk, 0xff, totalammount);
|
|
#endif
|
|
if (!addressablehunk)
|
|
Sys_Error("Out of memory\n");
|
|
addressablesize = totalammount;
|
|
}
|
|
|
|
int PR_InitEnts(progfuncs_t *progfuncs, int max_ents)
|
|
{
|
|
maxedicts = max_ents;
|
|
|
|
sv_num_edicts = 0;
|
|
|
|
max_fields_size = fields_size;
|
|
|
|
prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *));
|
|
sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize);
|
|
prinst->edicttable[0] = sv_edicts;
|
|
((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableAlloc(progfuncs, max_fields_size);
|
|
ED_ClearEdict(progfuncs, (edictrun_t *)sv_edicts);
|
|
sv_num_edicts = 1;
|
|
|
|
return max_fields_size;
|
|
}
|
|
edictrun_t tempedict; //used as a safty buffer
|
|
float tempedictfields[2048];
|
|
|
|
void PR_Configure (progfuncs_t *progfuncs, int addressable_size, int max_progs) //can be used to wipe all memory
|
|
{
|
|
unsigned int i;
|
|
edictrun_t *e;
|
|
|
|
// int a;
|
|
max_fields_size=0;
|
|
fields_size = 0;
|
|
progfuncs->stringtable = 0;
|
|
QC_StartShares(progfuncs);
|
|
QC_InitShares(progfuncs);
|
|
|
|
for ( i=1 ; i<maxedicts; i++)
|
|
{
|
|
e = (edictrun_t *)(prinst->edicttable[i]);
|
|
prinst->edicttable[i] = NULL;
|
|
// e->entnum = i;
|
|
if (e)
|
|
memfree(e);
|
|
}
|
|
|
|
PRHunkFree(progfuncs, 0); //clear mem - our hunk may not be a real hunk.
|
|
if (addressable_size<0)
|
|
addressable_size = 8*1024*1024;
|
|
PRAddressableFlush(progfuncs, addressable_size);
|
|
|
|
pr_progstate = PRHunkAlloc(progfuncs, sizeof(progstate_t) * max_progs);
|
|
|
|
/* for(a = 0; a < max_progs; a++)
|
|
{
|
|
pr_progstate[a].progs = NULL;
|
|
}
|
|
*/
|
|
|
|
maxprogs = max_progs;
|
|
pr_typecurrent=-1;
|
|
|
|
prinst->reorganisefields = false;
|
|
|
|
maxedicts = 1;
|
|
prinst->edicttable = &sv_edicts;
|
|
sv_num_edicts = 1; //set up a safty buffer so things won't go horribly wrong too often
|
|
sv_edicts=(struct edict_s *)&tempedict;
|
|
tempedict.readonly = true;
|
|
tempedict.fields = tempedictfields;
|
|
tempedict.isfree = false;
|
|
}
|
|
|
|
|
|
|
|
struct globalvars_s *PR_globals (progfuncs_t *progfuncs, progsnum_t pnum)
|
|
{
|
|
if (pnum < 0)
|
|
{
|
|
if (!current_progstate)
|
|
return NULL; //err.. you've not loaded one yet.
|
|
return (struct globalvars_s *)current_progstate->globals;
|
|
}
|
|
return (struct globalvars_s *)pr_progstate[pnum].globals;
|
|
}
|
|
|
|
struct entvars_s *PR_entvars (progfuncs_t *progfuncs, struct edict_s *ed)
|
|
{
|
|
if (((edictrun_t *)ed)->isfree)
|
|
return NULL;
|
|
|
|
return (struct entvars_s *)edvars(ed);
|
|
}
|
|
|
|
func_t PR_FindFunc(progfuncs_t *progfuncs, char *funcname, progsnum_t pnum)
|
|
{
|
|
dfunction_t *f=NULL;
|
|
if (pnum == PR_ANY)
|
|
{
|
|
for (pnum = 0; (unsigned)pnum < maxprogs; pnum++)
|
|
{
|
|
if (!pr_progstate[pnum].progs)
|
|
continue;
|
|
f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
|
|
if (f)
|
|
break;
|
|
}
|
|
}
|
|
else if (pnum == PR_ANYBACK) //run backwards
|
|
{
|
|
for (pnum = maxprogs-1; pnum >= 0; pnum--)
|
|
{
|
|
if (!pr_progstate[pnum].progs)
|
|
continue;
|
|
f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
|
|
if (f)
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
|
|
if (!f)
|
|
return 0;
|
|
|
|
{
|
|
ddef16_t *var16;
|
|
ddef32_t *var32;
|
|
switch(pr_progstate[pnum].intsize)
|
|
{
|
|
case 24:
|
|
case 16:
|
|
var16 = ED_FindTypeGlobalFromProgs16(progfuncs, funcname, pnum, ev_function); //we must make sure we actually have a function def - 'light' is defined as a field before it is defined as a function.
|
|
if (!var16)
|
|
return (f - pr_progstate[pnum].functions) | (pnum << 24);
|
|
return *(int *)&pr_progstate[pnum].globals[var16->ofs];
|
|
case 32:
|
|
var32 = ED_FindTypeGlobalFromProgs32(progfuncs, funcname, pnum, ev_function); //we must make sure we actually have a function def - 'light' is defined as a field before it is defined as a function.
|
|
if (!var32)
|
|
return (f - pr_progstate[pnum].functions) | (pnum << 24);
|
|
return *(int *)&pr_progstate[pnum].globals[var32->ofs];
|
|
}
|
|
Sys_Error("Error with def size (PR_FindFunc)");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
eval_t *PR_FindGlobal(progfuncs_t *progfuncs, char *globname, progsnum_t pnum)
|
|
{
|
|
unsigned int i;
|
|
ddef16_t *var16;
|
|
ddef32_t *var32;
|
|
if (pnum == PR_CURRENT)
|
|
pnum = pr_typecurrent;
|
|
if (pnum == PR_ANY)
|
|
{
|
|
eval_t *ev;
|
|
for (i = 0; i < maxprogs; i++)
|
|
{
|
|
if (!pr_progstate[i].progs)
|
|
continue;
|
|
ev = PR_FindGlobal(progfuncs, globname, i);
|
|
if (ev)
|
|
return ev;
|
|
}
|
|
return NULL;
|
|
}
|
|
if (pnum < 0 || (unsigned)pnum >= maxprogs || !pr_progstate[pnum].progs)
|
|
return NULL;
|
|
switch(pr_progstate[pnum].intsize)
|
|
{
|
|
case 16:
|
|
case 24:
|
|
if (!(var16 = ED_FindGlobalFromProgs16(progfuncs, globname, pnum)))
|
|
return NULL;
|
|
|
|
return (eval_t *)&pr_progstate[pnum].globals[var16->ofs];
|
|
case 32:
|
|
if (!(var32 = ED_FindGlobalFromProgs32(progfuncs, globname, pnum)))
|
|
return NULL;
|
|
|
|
return (eval_t *)&pr_progstate[pnum].globals[var32->ofs];
|
|
}
|
|
Sys_Error("Error with def size (PR_FindGlobal)");
|
|
return NULL;
|
|
}
|
|
|
|
void SetGlobalEdict(progfuncs_t *progfuncs, struct edict_s *ed, int ofs)
|
|
{
|
|
((int*)pr_globals)[ofs] = EDICT_TO_PROG(progfuncs, ed);
|
|
}
|
|
|
|
char *PR_VarString (progfuncs_t *progfuncs, int first)
|
|
{
|
|
int i;
|
|
static char out[1024];
|
|
char *s;
|
|
|
|
out[0] = 0;
|
|
for (i=first ; i<pr_argc ; i++)
|
|
{
|
|
if (G_STRING(OFS_PARM0+i*3))
|
|
{
|
|
s=G_STRING((OFS_PARM0+i*3)) + progfuncs->stringtable;
|
|
strcat (out, s);
|
|
|
|
//#ifdef PARANOID
|
|
if (strlen(out)+1 >= sizeof(out))
|
|
Sys_Error("VarString (builtin call ending with strings) exceeded maximum string length of %i chars", sizeof(out));
|
|
//#endif
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
int PR_QueryField (progfuncs_t *progfuncs, unsigned int fieldoffset, etype_t *type, char **name, evalc_t *fieldcache)
|
|
{
|
|
fdef_t *var;
|
|
var = ED_FieldAtOfs(progfuncs, fieldoffset);
|
|
if (!var)
|
|
return false;
|
|
|
|
if (type)
|
|
*type = var->type & ~(DEF_SAVEGLOBAL|DEF_SHARED);
|
|
if (name)
|
|
*name = var->name;
|
|
if (fieldcache)
|
|
{
|
|
fieldcache->ofs32 = var;
|
|
fieldcache->varname = var->name;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
eval_t *GetEdictFieldValue(progfuncs_t *progfuncs, struct edict_s *ed, char *name, evalc_t *cache)
|
|
{
|
|
fdef_t *var;
|
|
if (!cache)
|
|
{
|
|
var = ED_FindField(progfuncs, name);
|
|
if (!var)
|
|
return NULL;
|
|
return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[var->ofs]);
|
|
}
|
|
if (!cache->varname)
|
|
{
|
|
cache->varname = name;
|
|
var = ED_FindField(progfuncs, name);
|
|
if (!var)
|
|
{
|
|
cache->ofs32 = NULL;
|
|
return NULL;
|
|
}
|
|
cache->ofs32 = var;
|
|
cache->varname = var->name;
|
|
if (!ed)
|
|
return (void*)~0; //something not null
|
|
return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[var->ofs]);
|
|
}
|
|
if (cache->ofs32 == NULL)
|
|
return NULL;
|
|
return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[cache->ofs32->ofs]);
|
|
}
|
|
|
|
struct edict_s *ProgsToEdict (progfuncs_t *progfuncs, int progs)
|
|
{
|
|
if ((unsigned)progs >= (unsigned)maxedicts)
|
|
{
|
|
printf("Bad entity index %i\n", progs);
|
|
progs = 0;
|
|
}
|
|
return (struct edict_s *)PROG_TO_EDICT(progfuncs, progs);
|
|
}
|
|
int EdictToProgs (progfuncs_t *progfuncs, struct edict_s *ed)
|
|
{
|
|
return EDICT_TO_PROG(progfuncs, ed);
|
|
}
|
|
|
|
string_t PR_StringToProgs (progfuncs_t *progfuncs, char *str)
|
|
{
|
|
char **ntable;
|
|
int i, free=-1;
|
|
|
|
if (!str)
|
|
return 0;
|
|
|
|
// if (str-progfuncs->stringtable < progfuncs->stringtablesize)
|
|
// return str - progfuncs->stringtable;
|
|
|
|
for (i = prinst->numallocedstrings-1; i >= 0; i--)
|
|
{
|
|
if (prinst->allocedstrings[i] == str)
|
|
return (string_t)((unsigned int)i | 0x80000000);
|
|
if (!prinst->allocedstrings[i])
|
|
free = i;
|
|
}
|
|
|
|
if (free != -1)
|
|
{
|
|
i = free;
|
|
prinst->allocedstrings[i] = str;
|
|
return (string_t)((unsigned int)i | 0x80000000);
|
|
}
|
|
|
|
prinst->maxallocedstrings += 1024;
|
|
ntable = memalloc(sizeof(char*) * prinst->maxallocedstrings);
|
|
memcpy(ntable, prinst->allocedstrings, sizeof(char*) * prinst->numallocedstrings);
|
|
memset(ntable + prinst->numallocedstrings, 0, sizeof(char*) * (prinst->maxallocedstrings - prinst->numallocedstrings));
|
|
prinst->numallocedstrings = prinst->maxallocedstrings;
|
|
if (prinst->allocedstrings)
|
|
memfree(prinst->allocedstrings);
|
|
prinst->allocedstrings = ntable;
|
|
|
|
for (i = prinst->numallocedstrings-1; i >= 0; i--)
|
|
{
|
|
if (!prinst->allocedstrings[i])
|
|
{
|
|
prinst->allocedstrings[i] = str;
|
|
return (string_t)((unsigned int)i | 0x80000000);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *PR_StringToNative (progfuncs_t *progfuncs, string_t str)
|
|
{
|
|
if ((unsigned int)str & 0xc0000000)
|
|
{
|
|
if ((unsigned int)str & 0x80000000)
|
|
{
|
|
int i = str & ~0x80000000;
|
|
if (i >= prinst->numallocedstrings)
|
|
{
|
|
pr_trace = 1;
|
|
return "";
|
|
}
|
|
if (prinst->allocedstrings[i])
|
|
return prinst->allocedstrings[i];
|
|
else
|
|
{
|
|
pr_trace = 1;
|
|
return ""; //urm, was freed...
|
|
}
|
|
}
|
|
if ((unsigned int)str & 0x40000000)
|
|
{
|
|
int i = str & ~0x40000000;
|
|
if (i >= prinst->numtempstrings)
|
|
{
|
|
pr_trace = 1;
|
|
return "";
|
|
}
|
|
return prinst->tempstrings[i];
|
|
}
|
|
}
|
|
|
|
if (str >= progfuncs->stringtablesize)
|
|
{
|
|
pr_trace = 1;
|
|
return "";
|
|
}
|
|
return progfuncs->stringtable + str;
|
|
}
|
|
|
|
|
|
string_t PR_AllocTempString (progfuncs_t *progfuncs, char *str)
|
|
{
|
|
char **ntable;
|
|
int newmax;
|
|
int i;
|
|
|
|
if (!str)
|
|
return 0;
|
|
|
|
if (prinst->numtempstrings == prinst->maxtempstrings)
|
|
{
|
|
newmax = prinst->maxtempstrings += 1024;
|
|
prinst->maxtempstrings += 1024;
|
|
ntable = memalloc(sizeof(char*) * newmax);
|
|
memcpy(ntable, prinst->tempstrings, sizeof(char*) * prinst->numtempstrings);
|
|
prinst->maxtempstrings = newmax;
|
|
if (prinst->tempstrings)
|
|
memfree(prinst->tempstrings);
|
|
prinst->tempstrings = ntable;
|
|
}
|
|
|
|
i = prinst->numtempstrings;
|
|
if (i == 0x10000000)
|
|
return 0;
|
|
|
|
prinst->numtempstrings++;
|
|
|
|
prinst->tempstrings[i] = memalloc(strlen(str)+1);
|
|
strcpy(prinst->tempstrings[i], str);
|
|
|
|
return (string_t)((unsigned int)i | 0x40000000);
|
|
}
|
|
|
|
void PR_FreeTemps (progfuncs_t *progfuncs, int depth)
|
|
{
|
|
int i;
|
|
if (depth > prinst->numtempstrings)
|
|
{
|
|
Sys_Error("QC Temp stack inverted\n");
|
|
return;
|
|
}
|
|
for (i = depth; i < prinst->numtempstrings; i++)
|
|
{
|
|
memfree(prinst->tempstrings[i]);
|
|
}
|
|
|
|
prinst->numtempstrings = depth;
|
|
}
|
|
|
|
|
|
struct qcthread_s *PR_ForkStack (progfuncs_t *progfuncs);
|
|
void PR_ResumeThread (progfuncs_t *progfuncs, struct qcthread_s *thread);
|
|
void PR_AbortStack (progfuncs_t *progfuncs);
|
|
|
|
|
|
void RegisterBuiltin(progfuncs_t *progfncs, char *name, builtin_t func);
|
|
|
|
progfuncs_t deffuncs = {
|
|
PROGSTRUCT_VERSION,
|
|
PR_Configure,
|
|
PR_LoadProgs,
|
|
PR_InitEnts,
|
|
PR_ExecuteProgram,
|
|
PR_SwitchProgs,
|
|
PR_globals,
|
|
PR_entvars,
|
|
PR_RunError,
|
|
ED_Print,
|
|
ED_Alloc,
|
|
ED_Free,
|
|
|
|
EDICT_NUM,
|
|
NUM_FOR_EDICT,
|
|
|
|
|
|
SetGlobalEdict,
|
|
|
|
PR_VarString,
|
|
|
|
NULL,
|
|
PR_FindFunc,
|
|
#ifdef MINIMAL
|
|
NULL,
|
|
NULL,
|
|
#else
|
|
Comp_Begin,
|
|
Comp_Continue,
|
|
#endif
|
|
|
|
filefromprogs,
|
|
filefromnewprogs,
|
|
|
|
SaveEnts,
|
|
LoadEnts,
|
|
|
|
SaveEnt,
|
|
RestoreEnt,
|
|
|
|
PR_FindGlobal,
|
|
ED_NewString,
|
|
(void*)PRHunkAlloc,
|
|
|
|
GetEdictFieldValue,
|
|
ProgsToEdict,
|
|
EdictToProgs,
|
|
|
|
EvaluateDebugString,
|
|
|
|
NULL,
|
|
PR_StackTrace,
|
|
|
|
PR_ToggleBreakpoint,
|
|
0,
|
|
NULL,
|
|
#ifdef MINIMAL
|
|
NULL,
|
|
#else
|
|
Decompile,
|
|
#endif
|
|
NULL,
|
|
NULL,
|
|
RegisterBuiltin,
|
|
|
|
0,
|
|
0,
|
|
|
|
PR_ForkStack,
|
|
PR_ResumeThread,
|
|
PR_AbortStack,
|
|
|
|
0,
|
|
|
|
QC_RegisterFieldVar,
|
|
|
|
0,
|
|
0,
|
|
|
|
PR_AllocTempString,
|
|
|
|
PR_StringToProgs,
|
|
PR_StringToNative,
|
|
0,
|
|
PR_QueryField
|
|
};
|
|
#undef printf
|
|
|
|
//defs incase following structure is not passed.
|
|
struct edict_s *safesv_edicts;
|
|
int safesv_num_edicts;
|
|
double safetime=0;
|
|
|
|
progexterns_t defexterns = {
|
|
PROGSTRUCT_VERSION,
|
|
|
|
NULL, //char *(*ReadFile) (char *fname, void *buffer, int len);
|
|
NULL, //int (*FileSize) (char *fname); //-1 if file does not exist
|
|
NULL, //bool (*WriteFile) (char *name, void *data, int len);
|
|
printf, //void (*printf) (char *, ...);
|
|
(void*)exit, //void (*Sys_Error) (char *, ...);
|
|
NULL, //void (*Abort) (char *, ...);
|
|
sizeof(edictrun_t), //int edictsize; //size of edict_t
|
|
|
|
NULL, //void (*entspawn) (struct edict_s *ent); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
|
|
NULL, //bool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed
|
|
NULL, //void (*stateop) (float var, func_t func);
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
|
|
//used when loading a game
|
|
NULL, //builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved.
|
|
NULL, //void (*loadcompleate) (int edictsize); //notification to reset any pointers.
|
|
|
|
(void*)malloc, //void *(*memalloc) (int size); //small string allocation malloced and freed randomly by the executor. (use memalloc if you want)
|
|
free, //void (*memfree) (void * mem);
|
|
|
|
|
|
NULL, //builtin_t *globalbuiltins; //these are available to all progs
|
|
0, //int numglobalbuiltins;
|
|
|
|
PR_NOCOMPILE,
|
|
|
|
&safetime, //double *gametime;
|
|
|
|
&safesv_edicts, //struct edict_s **sv_edicts;
|
|
&safesv_num_edicts, //int *sv_num_edicts;
|
|
|
|
NULL, //int (*useeditor) (char *filename, int line, int nump, char **parms);
|
|
};
|
|
|
|
//progfuncs_t *progfuncs = NULL;
|
|
#undef memfree
|
|
#undef prinst
|
|
#undef extensionbuiltin
|
|
#undef field
|
|
#undef shares
|
|
#undef sv_num_edicts
|
|
|
|
|
|
#ifdef QCLIBDLL_EXPORTS
|
|
__declspec(dllexport)
|
|
#endif
|
|
void CloseProgs(progfuncs_t *inst)
|
|
{
|
|
// extensionbuiltin_t *eb;
|
|
void (VARGS *f) (void *);
|
|
|
|
unsigned int i;
|
|
edictrun_t *e;
|
|
|
|
f = inst->parms->memfree;
|
|
|
|
for ( i=1 ; i<inst->maxedicts; i++)
|
|
{
|
|
e = (edictrun_t *)(inst->prinst->edicttable[i]);
|
|
inst->prinst->edicttable[i] = NULL;
|
|
if (e)
|
|
{
|
|
// e->entnum = i;
|
|
f(e);
|
|
}
|
|
}
|
|
|
|
PRHunkFree(inst, 0);
|
|
|
|
#ifdef _WIN32
|
|
VirtualFree(inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
|
|
#else
|
|
free(inst->addressablehunk);
|
|
#endif
|
|
|
|
/*
|
|
while(inst->prinst->extensionbuiltin)
|
|
{
|
|
eb = inst->prinst->extensionbuiltin->prev;
|
|
f(inst->prinst->extensionbuiltin);
|
|
inst->prinst->extensionbuiltin = eb;
|
|
}
|
|
*/
|
|
if (inst->prinst->field)
|
|
f(inst->prinst->field);
|
|
if (inst->prinst->shares)
|
|
f(inst->prinst->shares); //free memory
|
|
f(inst->prinst);
|
|
f(inst);
|
|
}
|
|
|
|
void RegisterBuiltin(progfuncs_t *progfuncs, char *name, builtin_t func)
|
|
{
|
|
/*
|
|
extensionbuiltin_t *eb;
|
|
eb = memalloc(sizeof(extensionbuiltin_t));
|
|
eb->prev = progfuncs->prinst->extensionbuiltin;
|
|
progfuncs->prinst->extensionbuiltin = eb;
|
|
eb->name = name;
|
|
eb->func = func;
|
|
*/
|
|
}
|
|
|
|
#ifndef WIN32
|
|
#define QCLIBINT //don't use dllspecifications
|
|
#endif
|
|
|
|
#if defined(QCLIBDLL_EXPORTS)
|
|
__declspec(dllexport)
|
|
#endif
|
|
progfuncs_t * InitProgs(progexterns_t *ext)
|
|
{
|
|
progfuncs_t *funcs;
|
|
|
|
if (!ext)
|
|
ext = &defexterns;
|
|
else
|
|
{
|
|
int i;
|
|
if (ext->progsversion > PROGSTRUCT_VERSION)
|
|
return NULL;
|
|
|
|
for (i=0;i<sizeof(progexterns_t); i+=4) //make sure there are no items left out.
|
|
if (!*(int *)((char *)ext+i))
|
|
*(int *)((char *)ext+i) = *(int *)((char *)&defexterns+i);
|
|
}
|
|
#undef memalloc
|
|
#undef pr_trace
|
|
funcs = ext->memalloc(sizeof(progfuncs_t));
|
|
memcpy(funcs, &deffuncs, sizeof(progfuncs_t));
|
|
|
|
funcs->prinst = ext->memalloc(sizeof(prinst_t));
|
|
memset(funcs->prinst,0, sizeof(prinst_t));
|
|
|
|
funcs->pr_trace = &funcs->prinst->pr_trace;
|
|
funcs->progstate = &funcs->pr_progstate;
|
|
funcs->callargc = &funcs->pr_argc;
|
|
|
|
funcs->parms = ext;
|
|
|
|
SetEndian();
|
|
|
|
return funcs;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef QCC
|
|
void main (int argc, char **argv)
|
|
{
|
|
progexterns_t ext;
|
|
|
|
progfuncs_t *funcs;
|
|
funcs = InitProgs(&ext);
|
|
if (funcs->PR_StartCompile(argc, argv))
|
|
while(funcs->PR_ContinueCompile());
|
|
}
|
|
#endif
|