typedef union prvm_eval_s
{
- string_t string;
- float _float;
- float vector[3];
- func_t function;
- int ivector[3];
- int _int;
- int edict;
+ prvm_int_t string;
+ prvm_vec_t _float;
+ prvm_vec_t vector[3];
+ prvm_int_t function;
+ prvm_int_t ivector[3];
+ prvm_int_t _int;
+ prvm_int_t edict;
} prvm_eval_t;
typedef struct prvm_required_field_s
typedef struct prvm_edict_private_s
{
qboolean free;
- float freetime;
+ float freetime; // realtime of last change to "free" (i.e. also set on allocation)
int mark; // used during leaktest (0 = unref, >0 = referenced); special values during server physics:
#define PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN -1
#define PRVM_EDICT_MARK_SETORIGIN_CAUGHT -2
union
{
prvm_edict_private_t *required;
- vec_t *vp;
+ prvm_vec_t *fp;
+ prvm_int_t *ip;
// FIXME: this server pointer really means world, not server
// (it is used by both server qc and client qc, but not menu qc)
edict_engineprivate_t *server;
// QuakeC fields (stored in dynamically resized array)
union
{
- vec_t *vp;
+ prvm_vec_t *fp;
+ prvm_int_t *ip;
// entvars_t *server;
// cl_entvars_t *client;
} fields;
} prvm_edict_t;
-#define VMPOLYGONS_MAXPOINTS 64
-
-typedef struct vmpolygons_triangle_s
-{
- rtexture_t *texture;
- int drawflag;
- qboolean hasalpha;
- unsigned short elements[3];
-} vmpolygons_triangle_t;
-
-typedef struct vmpolygons_s
-{
- mempool_t *pool;
- qboolean initialized;
-
- int max_vertices;
- int num_vertices;
- float *data_vertex3f;
- float *data_color4f;
- float *data_texcoord2f;
-
- int max_triangles;
- int num_triangles;
- vmpolygons_triangle_t *data_triangles;
- unsigned short *data_sortedelement3s;
-
- qboolean begin_active;
- int begin_draw2d;
- rtexture_t *begin_texture;
- int begin_drawflag;
- int begin_vertices;
- float begin_vertex[VMPOLYGONS_MAXPOINTS][3];
- float begin_color[VMPOLYGONS_MAXPOINTS][4];
- float begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
- qboolean begin_texture_hasalpha;
-} vmpolygons_t;
-
extern prvm_eval_t prvm_badvalue;
#define PRVM_alledictfloat(ed, fieldname) (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname))
#define PRVM_menufunction(funcname) (prog->funcoffsets.funcname)
#if 1
-#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) (fieldoffset < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))
+#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) ((fieldoffset) < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)((ed)->fields.fp + (fieldoffset)))
#define PRVM_EDICTFIELDFLOAT(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->_float)
#define PRVM_EDICTFIELDVECTOR(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->vector)
#define PRVM_EDICTFIELDSTRING(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->string)
#define PRVM_EDICTFIELDEDICT(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->edict)
#define PRVM_EDICTFIELDFUNCTION(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->function)
-#define PRVM_GLOBALFIELDVALUE(fieldoffset) (fieldoffset < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))
+#define PRVM_GLOBALFIELDVALUE(fieldoffset) ((fieldoffset) < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)(prog->globals.fp + (fieldoffset)))
#define PRVM_GLOBALFIELDFLOAT(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->_float)
#define PRVM_GLOBALFIELDVECTOR(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->vector)
#define PRVM_GLOBALFIELDSTRING(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->string)
#define PRVM_GLOBALFIELDEDICT(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->edict)
#define PRVM_GLOBALFIELDFUNCTION(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->function)
#else
-#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) ((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))
-#define PRVM_EDICTFIELDFLOAT(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->_float)
-#define PRVM_EDICTFIELDVECTOR(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->vector)
-#define PRVM_EDICTFIELDSTRING(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->string)
-#define PRVM_EDICTFIELDEDICT(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->edict)
-#define PRVM_EDICTFIELDFUNCTION(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->function)
-#define PRVM_GLOBALFIELDVALUE(fieldoffset) ((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))
-#define PRVM_GLOBALFIELDFLOAT(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->_float)
-#define PRVM_GLOBALFIELDVECTOR(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->vector)
-#define PRVM_GLOBALFIELDSTRING(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->string)
-#define PRVM_GLOBALFIELDEDICT(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->edict)
-#define PRVM_GLOBALFIELDFUNCTION(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->function)
+#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) ((prvm_eval_t *)(ed->fields.fp + fieldoffset))
+#define PRVM_EDICTFIELDFLOAT(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->_float)
+#define PRVM_EDICTFIELDVECTOR(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->vector)
+#define PRVM_EDICTFIELDSTRING(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->string)
+#define PRVM_EDICTFIELDEDICT(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->edict)
+#define PRVM_EDICTFIELDFUNCTION(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->function)
+#define PRVM_GLOBALFIELDVALUE(fieldoffset) ((prvm_eval_t *)(prog->globals.fp + fieldoffset))
+#define PRVM_GLOBALFIELDFLOAT(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->_float)
+#define PRVM_GLOBALFIELDVECTOR(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->vector)
+#define PRVM_GLOBALFIELDSTRING(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->string)
+#define PRVM_GLOBALFIELDEDICT(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->edict)
+#define PRVM_GLOBALFIELDFUNCTION(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->function)
#endif
//============================================================================
prvm_prog_funcoffsets_t;
// stringbuffer flags
-#define STRINGBUFFER_SAVED 1 // saved in savegames
-
+#define STRINGBUFFER_SAVED 1 // saved in savegames
+#define STRINGBUFFER_QCFLAGS 1 // allowed to be set by QC
+#define STRINGBUFFER_TEMP 128 // internal use ONLY
typedef struct prvm_stringbuffer_s
{
int max_strings;
}
prvm_stringbuffer_t;
+// flags for knownstrings
+#define KNOWNSTRINGFLAG_ENGINE 1
+#define KNOWNSTRINGFLAG_GCMARK 2
+#define KNOWNSTRINGFLAG_GCPRUNE 4 // cleared by GCMARK code, string is freed if prune remains after two sweeps
+
+typedef enum prvm_prog_garbagecollection_state_stage_e
+{
+ PRVM_GC_START = 0,
+ PRVM_GC_GLOBALS_MARK,
+ PRVM_GC_FIELDS_MARK,
+ PRVM_GC_KNOWNSTRINGS_SWEEP,
+ PRVM_GC_RESET,
+}
+prvm_prog_garbagecollection_state_stage_t;
+
+typedef struct prvm_prog_garbagecollection_state_s
+{
+ prvm_prog_garbagecollection_state_stage_t stage;
+ int globals_mark_progress;
+ int fields_mark_progress;
+ int fields_mark_progress_entity;
+ int knownstrings_sweep_progress;
+}
+prvm_prog_garbagecollection_state_t;
+
// [INIT] variables flagged with this token can be initialized by 'you'
// NOTE: external code has to create and free the mempools but everything else is done by prvm !
typedef struct prvm_prog_s
{
double starttime; // system time when PRVM_Prog_Load was called
+ double inittime; // system time when QC initialization code finished (any entity created before is not a leak)
double profiletime; // system time when last PRVM_CallProfile was called (or PRVM_Prog_Load initially)
- unsigned int id; // increasing unique id of progs instance
mfunction_t *functions;
+ int functions_covered;
char *strings;
int stringssize;
ddef_t *fielddefs;
ddef_t *globaldefs;
mstatement_t *statements;
int entityfields; // number of vec_t fields in progs (some variables are 3)
- int entityfieldsarea; // LordHavoc: equal to max_edicts * entityfields (for bounds checking)
+ int entityfieldsarea; // LadyHavoc: equal to max_edicts * entityfields (for bounds checking)
// loaded values from the disk format
int progs_version;
int numglobals;
int *statement_linenums; // NULL if not available
+ int *statement_columnnums; // NULL if not available
double *statement_profile; // only incremented if prvm_statementprofiling is on
+ int statements_covered;
+ double *explicit_profile; // only incremented if prvm_statementprofiling is on
+ int explicit_covered;
+ int numexplicitcoveragestatements;
union {
- vec_t *generic;
+ prvm_vec_t *fp;
+ prvm_int_t *ip;
// globalvars_t *server;
// cl_globalvars_t *client;
} globals;
// (simple optimization of the free string search)
int firstfreeknownstring;
const char **knownstrings;
- unsigned char *knownstrings_freeable;
+ unsigned char *knownstrings_flags;
const char **knownstrings_origin;
const char ***stringshash;
memexpandablearray_t stringbuffersarray;
+ // garbage collection status
+ prvm_prog_garbagecollection_state_t gc;
+
// all memory allocations related to this vm_prog (code, edicts, strings)
mempool_t *progs_mempool; // [INIT]
int argc;
int trace;
+ int break_statement;
+ int break_stack_index;
+ int watch_global;
+ etype_t watch_global_type;
+ prvm_eval_t watch_global_value;
+ int watch_edict;
+ int watch_field;
+ etype_t watch_field_type;
+ prvm_eval_t watch_edictfield_value;
+
mfunction_t *xfunction;
int xstatement;
prvm_stack_t stack[PRVM_MAX_STACK_DEPTH+1];
int depth;
- int localstack[PRVM_LOCALSTACK_SIZE];
+ prvm_int_t localstack[PRVM_LOCALSTACK_SIZE];
int localstack_used;
unsigned short filecrc;
fssearch_t *opensearches[PRVM_MAX_OPENSEARCHES];
const char * opensearches_origin[PRVM_MAX_OPENSEARCHES];
skeleton_t *skeletons[MAX_EDICTS];
+ cmd_state_t *console_cmd; // points to the relevant console command interpreter for this vm (&cmd_client or &cmd_server), also used to access cvars
// buffer for storing all tempstrings created during one invocation of ExecuteProgram
sizebuf_t tempstringsbuf;
- // LordHavoc: moved this here to clean up things that relied on prvm_prog_list too much
- // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
- vmpolygons_t vmpolygons;
+ // in csqc the polygonbegin,polygonvertex,polygonend sequencing is
+ // stateful, so this tracks the last polygonbegin's choice of
+ // CL_Mesh_CSQC or CL_Mesh_UI for this polygon
+ dp_model_t *polygonbegin_model;
+ // indicates if polygonbegin should be interpreted as 2d
+ // (clearscene sets this to false, renderscene sets this to true, drawpic
+ // also sets this to true)
+ // note that in FTEQW polygonbegin with 2 args is handled very differently,
+ // where the behavior is always 3D unless DRAWFLAG_2D is passed, but
+ // DRAWFLAG_2D conflicts with our DRAWFLAG_SCREEN.
+ qboolean polygonbegin_guess2d;
// copies of some vars that were former read from sv
int num_edicts;
int reserved_edicts; // [INIT]
prvm_edict_t *edicts;
- vec_t *edictsfields;
- void *edictprivate;
+ union
+ {
+ prvm_vec_t *fp;
+ prvm_int_t *ip;
+ } edictsfields;
+ void *edictprivate;
// size of the engine private struct
int edictprivate_size; // [INIT]
// printed together with backtraces
const char *statestring;
+ struct animatemodel_cache *animatemodel_cache;
+
// prvm_builtin_mem_t *mem_list;
// now passed as parameter of PRVM_LoadProgs
#define PRVM_ProgLoaded(n) (PRVM_GetProg(n)->loaded)
#define SVVM_prog (&prvm_prog_list[PRVM_PROG_SERVER])
#define CLVM_prog (&prvm_prog_list[PRVM_PROG_CLIENT])
+#ifdef CONFIG_MENU
#define MVM_prog (&prvm_prog_list[PRVM_PROG_MENU])
+#endif
//============================================================================
// prvm_cmds part
void CLVM_init_cmd(prvm_prog_t *prog);
void CLVM_reset_cmd(prvm_prog_t *prog);
+#ifdef CONFIG_MENU
void MVM_init_cmd(prvm_prog_t *prog);
void MVM_reset_cmd(prvm_prog_t *prog);
+#endif
void VM_Cmd_Init(prvm_prog_t *prog);
void VM_Cmd_Reset(prvm_prog_t *prog);
#ifdef PROFILING
void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage);
void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage);
+#ifdef CONFIG_MENU
void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage);
+#endif
#else
#define SVVM_ExecuteProgram PRVM_ExecuteProgram
#define CLVM_ExecuteProgram PRVM_ExecuteProgram
+#ifdef CONFIG_MENU
#define MVM_ExecuteProgram PRVM_ExecuteProgram
+#endif
void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage);
#endif
#define PRVM_Free(buffer) Mem_Free(buffer)
void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby);
-void PRVM_Profile_f (void);
-void PRVM_ChildProfile_f (void);
-void PRVM_CallProfile_f (void);
-void PRVM_PrintFunction_f (void);
+void PRVM_Profile_f(cmd_state_t *cmd);
+void PRVM_ChildProfile_f(cmd_state_t *cmd);
+void PRVM_CallProfile_f(cmd_state_t *cmd);
+void PRVM_PrintFunction_f(cmd_state_t *cmd);
-void PRVM_PrintState(prvm_prog_t *prog);
+void PRVM_PrintState(prvm_prog_t *prog, int stack_index);
void PRVM_Crash(prvm_prog_t *prog);
void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize);
const char *PRVM_AllocationOrigin(prvm_prog_t *prog);
+void PRVM_GarbageCollection(prvm_prog_t *prog);
ddef_t *PRVM_ED_FindField(prvm_prog_t *prog, const char *name);
ddef_t *PRVM_ED_FindGlobal(prvm_prog_t *prog, const char *name);
//============================================================================
-#define PRVM_G_FLOAT(o) (prog->globals.generic[o])
-#define PRVM_G_INT(o) (*(int *)&prog->globals.generic[o])
-#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(*(int *)&prog->globals.generic[o]))
+#define PRVM_G_FLOAT(o) (prog->globals.fp[o])
+#define PRVM_G_INT(o) (prog->globals.ip[o])
+#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(prog->globals.ip[o]))
#define PRVM_G_EDICTNUM(o) PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(o))
-#define PRVM_G_VECTOR(o) (&prog->globals.generic[o])
-#define PRVM_G_STRING(o) (PRVM_GetString(prog, *(string_t *)&prog->globals.generic[o]))
-//#define PRVM_G_FUNCTION(prog, o) (*(func_t *)&prog->globals.generic[o])
+#define PRVM_G_VECTOR(o) (&prog->globals.fp[o])
+#define PRVM_G_STRING(o) (PRVM_GetString(prog, prog->globals.ip[o]))
+//#define PRVM_G_FUNCTION(prog, o) (prog->globals.ip[o])
// FIXME: make these go away?
-#define PRVM_E_FLOAT(e,o) (((float*)e->fields.vp)[o])
-#define PRVM_E_INT(e,o) (((int*)e->fields.vp)[o])
-//#define PRVM_E_VECTOR(e,o) (&((float*)e->fields.vp)[o])
-#define PRVM_E_STRING(e,o) (PRVM_GetString(prog, *(string_t *)&((float*)e->fields.vp)[o]))
+#define PRVM_E_FLOAT(e,o) (e->fields.fp[o])
+#define PRVM_E_INT(e,o) (e->fields.ip[o])
+//#define PRVM_E_VECTOR(e,o) (&(e->fields.fp[o]))
+#define PRVM_E_STRING(e,o) (PRVM_GetString(prog, e->fields.ip[o]))
extern int prvm_type_size[8]; // for consistency : I think a goal of this sub-project is to
// make the new vm mostly independent from the old one, thus if it's necessary, I copy everything
void PRVM_Init_Exec(prvm_prog_t *prog);
-void PRVM_ED_PrintEdicts_f (void);
+void PRVM_ED_PrintEdicts_f(cmd_state_t *cmd);
void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname);
const char *PRVM_GetString(prvm_prog_t *prog, int num);
Set up the fields marked with [INIT] in the prog struct
Load a program with LoadProgs
*/
-// Load expects to be called right after Init
-void PRVM_Prog_Init(prvm_prog_t *prog);
-void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global);
+// Load expects to be called right after Reset
+void PRVM_Prog_Init(prvm_prog_t *prog, cmd_state_t *cmd);
+void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global);
void PRVM_Prog_Reset(prvm_prog_t *prog);
void PRVM_StackTrace(prvm_prog_t *prog);
+void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text);
+void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype_t type, prvm_eval_t *o, prvm_eval_t *n);
void VM_Warning(prvm_prog_t *prog, const char *fmt, ...) DP_FUNC_PRINTF(2);
void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, framegroupblend_t *framegroupblend, const prvm_edict_t *ed);
-void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const dp_model_t *model);
+void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const dp_model_t *model, double curtime);
void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const dp_model_t *edmodel, const frameblend_t *frameblend);
void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed);
+void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement);
+
#endif