ed->priv.server->skeleton.relativetransforms = Mem_Alloc(prog->progs_mempool, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
if (ed->priv.server->skeleton.relativetransforms)
{
- int skeletonindex = 0;
+ int skeletonindex = -1;
skeleton_t *skeleton;
prvm_eval_t *val;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float;
- if (skeletonindex > 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
+ if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float - 1;
+ if (skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
{
// custom skeleton controlled by the game (FTE_CSQC_SKELETONOBJECTS)
memcpy(ed->priv.server->skeleton.relativetransforms, skeleton->relativetransforms, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
}
}
+/*
+=========
+VM_getsoundtime
+
+float getsoundtime(void)
+=========
+*/
+
+void VM_getsoundtime (void)
+{
+ int entnum, entchannel, pnum;
+ VM_SAFEPARMCOUNT(2,VM_getsoundtime);
+
+ pnum = PRVM_GetProgNr();
+ if (pnum == PRVM_MENUPROG)
+ {
+ VM_Warning("VM_getsoundtime: %s: not supported on this progs\n", PRVM_NAME);
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return;
+ }
+ entnum = ((pnum == PRVM_CLIENTPROG) ? MAX_EDICTS : 0) + PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0));
+ entchannel = (int)PRVM_G_FLOAT(OFS_PARM1);
+ if (entchannel <= 0 || entchannel > 8)
+ VM_Warning("VM_getsoundtime: %s: bad channel %i\n", PRVM_NAME, entchannel);
+ PRVM_G_FLOAT(OFS_RETURN) = (float)S_GetEntChannelPosition(entnum, entchannel);
+}
+
+/*
+=========
+VM_GetSoundLen
+
+string soundlength (string sample)
+=========
+*/
+void VM_soundlength (void)
+{
+ const char *s;
+
+ VM_SAFEPARMCOUNT(1, VM_soundlength);
+
+ s = PRVM_G_STRING(OFS_PARM0);
+ PRVM_G_FLOAT(OFS_RETURN) = S_SoundLength(s);
+}
+
/*
=========
VM_loadfromdata
{
float *pos,*scale;
const char *string;
- int flag,color;
+ int flag;
float sx, sy;
VM_SAFEPARMCOUNT(5,VM_drawstring);
if(pos[2] || scale[2])
Con_Printf("VM_drawcolorcodedstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
- color = -1;
getdrawfontscale(&sx, &sy);
DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, 1, 1, 1, PRVM_G_FLOAT(OFS_PARM3), flag, NULL, false, getdrawfont());
PRVM_G_FLOAT(OFS_RETURN) = 1;
VM_CheckEmptyString( file );
VM_CheckEmptyString( name );
- if( CL_OpenVideo( file, name, MENUOWNER ) )
+ if( CL_OpenVideo( file, name, MENUOWNER, "" ) )
PRVM_G_FLOAT( OFS_RETURN ) = 1;
else
PRVM_G_FLOAT( OFS_RETURN ) = 0;
void VM_altstr_ins(void)
{
int num;
- const char *setstr;
const char *set;
- const char *instr;
const char *in;
char *out;
char outstr[VM_STRINGTEMP_LENGTH];
VM_SAFEPARMCOUNT(3, VM_altstr_ins);
- in = instr = PRVM_G_STRING( OFS_PARM0 );
+ in = PRVM_G_STRING( OFS_PARM0 );
num = (int)PRVM_G_FLOAT( OFS_PARM1 );
- set = setstr = PRVM_G_STRING( OFS_PARM2 );
+ set = PRVM_G_STRING( OFS_PARM2 );
out = outstr;
for( num = num * 2 + 2 ; *in && num > 0 ; *out++ = *in++ )
VM_buf_create
creates new buffer, and returns it's index, returns -1 if failed
float buf_create(void) = #460;
+float newbuf(string format, float flags) = #460;
========================
*/
+
void VM_buf_create (void)
{
prvm_stringbuffer_t *stringbuffer;
int i;
- VM_SAFEPARMCOUNT(0, VM_buf_create);
+
+ VM_SAFEPARMCOUNTRANGE(0, 2, VM_buf_create);
+
+ // VorteX: optional parm1 (buffer format) is unfinished, to keep intact with future databuffers extension must be set to "string"
+ if(prog->argc >= 1 && strcmp(PRVM_G_STRING(OFS_PARM0), "string"))
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return;
+ }
stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray);
for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++);
stringbuffer->origin = PRVM_AllocationOrigin();
+ // optional flags parm
+ if(prog->argc == 2)
+ stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & 0xFF;
PRVM_G_FLOAT(OFS_RETURN) = i;
}
+
+
/*
========================
VM_buf_del
if (!match)
PRVM_G_FLOAT(OFS_RETURN) = -1;
else
- PRVM_G_FLOAT(OFS_RETURN) = match - instr;
+ PRVM_G_FLOAT(OFS_RETURN) = u8_strnlen(instr, match-instr);
}
//#222 string(string s, float index) str2chr (FTE_STRINGS)
|| (*p >= 'a' && *p <= 'z')
|| (*p >= '0' && *p <= '9')
|| (*p == '-') || (*p == '_') || (*p == '.')
- || (*p == '!') || (*p == '~') || (*p == '*')
+ || (*p == '!') || (*p == '~')
|| (*p == '\'') || (*p == '(') || (*p == ')'))
*q++ = *p;
else
handle->prognr = PRVM_GetProgNr();
handle->starttime = prog->starttime;
handle->id = id;
- ret = Curl_Begin_ToMemory(url, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
+ ret = Curl_Begin_ToMemory(url, 0, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
if(ret)
{
PRVM_G_INT(OFS_RETURN) = 1;
}
}
+/*
+=========
+Common functions between menu.dat and clsprogs
+=========
+*/
+
+//#349 float() isdemo
+void VM_CL_isdemo (void)
+{
+ VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
+ PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
+}
+
+//#355 float() videoplaying
+void VM_CL_videoplaying (void)
+{
+ VM_SAFEPARMCOUNT(0, VM_CL_videoplaying);
+ PRVM_G_FLOAT(OFS_RETURN) = cl_videoplaying;
+}
+
/*
=========
VM_M_callfunction
char formatbuf[16];
char *f;
qboolean isfloat;
+ static int dummyivec[3] = {0, 0, 0};
+ static float dummyvec[3] = {0, 0, 0};
+
#define PRINTF_ALTERNATE 1
#define PRINTF_ZEROPAD 2
#define PRINTF_LEFT 4
s = PRVM_G_STRING(OFS_PARM0);
#define GETARG_FLOAT(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
+#define GETARG_VECTOR(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyvec)
#define GETARG_INT(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_INT(OFS_PARM0 + 3 * (a))) : 0)
+#define GETARG_INTVECTOR(a) (((a)>=1 && (a)<prog->argc) ? ((int*) PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyivec)
#define GETARG_STRING(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_STRING(OFS_PARM0 + 3 * (a))) : "")
for(;;)
{
case 0:
goto finished;
- break;
case '%':
++s;
precision = 6;
o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
break;
+ case 'v': case 'V':
+ f[-2] += 'g' - 'v';
+ if(precision < 0) // not set
+ precision = 6;
+ o += dpsnprintf(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
+ width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
+ width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
+ width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
+ );
+ break;
case 'c':
if(precision < 0) // not set
precision = end - o - 1;
}
}
+typedef struct
+{
+ unsigned int progid;
+ dp_model_t *model;
+ frameblend_t frameblend[MAX_FRAMEBLENDS];
+ skeleton_t *skeleton_p;
+ skeleton_t skeleton;
+ float *data_vertex3f;
+ float *data_svector3f;
+ float *data_tvector3f;
+ float *data_normal3f;
+ int max_vertices;
+ float *buf_vertex3f;
+ float *buf_svector3f;
+ float *buf_tvector3f;
+ float *buf_normal3f;
+}
+animatemodel_cache_t;
+static animatemodel_cache_t animatemodel_cache;
+
+void animatemodel(dp_model_t *model, prvm_edict_t *ed)
+{
+ prvm_eval_t *val;
+ skeleton_t *skeleton;
+ int skeletonindex = -1;
+ qboolean need = false;
+ if(!model->AnimateVertices)
+ {
+ animatemodel_cache.data_vertex3f = model->surfmesh.data_vertex3f;
+ animatemodel_cache.data_svector3f = model->surfmesh.data_svector3f;
+ animatemodel_cache.data_tvector3f = model->surfmesh.data_tvector3f;
+ animatemodel_cache.data_normal3f = model->surfmesh.data_normal3f;
+ return;
+ }
+ if(animatemodel_cache.progid != prog->id)
+ memset(&animatemodel_cache, 0, sizeof(animatemodel_cache));
+ need |= (animatemodel_cache.model != model);
+ VM_GenerateFrameGroupBlend(ed->priv.server->framegroupblend, ed);
+ VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model);
+ need |= (memcmp(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend)));
+ if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float - 1;
+ if (!(skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones))
+ skeleton = NULL;
+ need |= (animatemodel_cache.skeleton_p != skeleton);
+ if(skeleton)
+ need |= (memcmp(&animatemodel_cache.skeleton, skeleton, sizeof(ed->priv.server->skeleton)));
+ if(!need)
+ return;
+ if(model->surfmesh.num_vertices > animatemodel_cache.max_vertices)
+ {
+ animatemodel_cache.max_vertices = model->surfmesh.num_vertices * 2;
+ if(animatemodel_cache.buf_vertex3f) Mem_Free(animatemodel_cache.buf_vertex3f);
+ if(animatemodel_cache.buf_svector3f) Mem_Free(animatemodel_cache.buf_svector3f);
+ if(animatemodel_cache.buf_tvector3f) Mem_Free(animatemodel_cache.buf_tvector3f);
+ if(animatemodel_cache.buf_normal3f) Mem_Free(animatemodel_cache.buf_normal3f);
+ animatemodel_cache.buf_vertex3f = Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ animatemodel_cache.buf_svector3f = Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ animatemodel_cache.buf_tvector3f = Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ animatemodel_cache.buf_normal3f = Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ }
+ animatemodel_cache.data_vertex3f = animatemodel_cache.buf_vertex3f;
+ animatemodel_cache.data_svector3f = animatemodel_cache.buf_svector3f;
+ animatemodel_cache.data_tvector3f = animatemodel_cache.buf_tvector3f;
+ animatemodel_cache.data_normal3f = animatemodel_cache.buf_normal3f;
+ VM_UpdateEdictSkeleton(ed, model, ed->priv.server->frameblend);
+ model->AnimateVertices(model, ed->priv.server->frameblend, &ed->priv.server->skeleton, animatemodel_cache.data_vertex3f, animatemodel_cache.data_normal3f, animatemodel_cache.data_svector3f, animatemodel_cache.data_tvector3f);
+ animatemodel_cache.progid = prog->id;
+ animatemodel_cache.model = model;
+ memcpy(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend));
+ animatemodel_cache.skeleton_p = skeleton;
+ if(skeleton)
+ memcpy(&animatemodel_cache.skeleton, skeleton, sizeof(ed->priv.server->skeleton));
+}
+
static void getmatrix(prvm_edict_t *ed, matrix4x4_t *out)
{
switch(PRVM_GetProgNr())
VectorCopy(p, out);
}
-static void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
+static void clippointtosurface(prvm_edict_t *ed, dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
{
int i, j, k;
float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
const int *e;
+ animatemodel(model, ed);
bestdist = 1000000000;
VectorCopy(p, out);
for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
{
// clip original point to each triangle of the surface and find the
// triangle that is closest
- v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
- v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
- v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
+ v[0] = animatemodel_cache.data_vertex3f + e[0] * 3;
+ v[1] = animatemodel_cache.data_vertex3f + e[1] * 3;
+ v[2] = animatemodel_cache.data_vertex3f + e[2] * 3;
TriangleNormal(v[0], v[1], v[2], facenormal);
VectorNormalize(facenormal);
offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
if (pointnum < 0 || pointnum >= surface->num_vertices)
return;
- applytransform_forward(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ animatemodel(model, ed);
+ applytransform_forward(&(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
}
//PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
// float SPA_POSITION = 0;
return;
attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
+ animatemodel(model, ed);
+
switch( attributetype ) {
// float SPA_POSITION = 0;
case 0:
- applytransform_forward(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ applytransform_forward(&(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
break;
// float SPA_S_AXIS = 1;
case 1:
- applytransform_forward_direction(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ applytransform_forward_direction(&(animatemodel_cache.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
break;
// float SPA_T_AXIS = 2;
case 2:
- applytransform_forward_direction(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ applytransform_forward_direction(&(animatemodel_cache.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
break;
// float SPA_R_AXIS = 3; // same as SPA_NORMAL
case 3:
- applytransform_forward_direction(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ applytransform_forward_direction(&(animatemodel_cache.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
break;
// float SPA_TEXCOORDS0 = 4;
case 4: {
return;
// note: this only returns the first triangle, so it doesn't work very
// well for curved surfaces or arbitrary meshes
- TriangleNormal((model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 3, (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
+ animatemodel(model, PRVM_G_EDICT(OFS_PARM0));
+ TriangleNormal((animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex), (animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex) + 3, (animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
applytransform_forward_normal(normal, PRVM_G_EDICT(OFS_PARM0), PRVM_G_VECTOR(OFS_RETURN));
VectorNormalize(PRVM_G_VECTOR(OFS_RETURN));
}
if (!model || !model->num_surfaces)
return;
+ animatemodel(model, ed);
+
applytransform_inverted(point, ed, p);
best = -1;
bestdist = 1000000000;
if (dist < bestdist)
{
// it is, check the nearest point on the actual geometry
- clippointtosurface(model, surface, p, clipped);
+ clippointtosurface(ed, model, surface, p, clipped);
VectorSubtract(clipped, p, clipped);
dist += VectorLength2(clipped);
if (dist < bestdist)
ed = PRVM_G_EDICT(OFS_PARM0);
if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
return;
+ animatemodel(model, ed);
applytransform_inverted(PRVM_G_VECTOR(OFS_PARM2), ed, p);
- clippointtosurface(model, surface, p, out);
+ clippointtosurface(ed, model, surface, p, out);
VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
}
//PF_getsurfacetriangle, // #??? vector(entity e, float s, float n) getsurfacetriangle = #???;
void VM_getsurfacetriangle(void)
{
+ const vec3_t d = {-1, -1, -1};
prvm_edict_t *ed;
dp_model_t *model;
msurface_t *surface;
if (trinum < 0 || trinum >= surface->num_triangles)
return;
// FIXME: implement rotation/scaling
- VectorCopy(&(model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[trinum * 3], PRVM_G_VECTOR(OFS_RETURN));
+ VectorMA(&(model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[trinum * 3], surface->num_firstvertex, d, PRVM_G_VECTOR(OFS_RETURN));
}