From 32bea9b074a4ee3e82fe0bbe82005da9f2d6f418 Mon Sep 17 00:00:00 2001 From: divverent Date: Tue, 26 Jan 2010 11:32:14 +0000 Subject: [PATCH] make getsurface* functions shared between VMs add getsurfacenumtriangles, getsurfacetriangle git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9862 d7cf8633-e32d-0410-b094-e92efae38249 --- clvm_cmds.c | 237 ++---------------------------------- clvm_cmds.h | 1 + prvm_cmds.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++++ prvm_cmds.h | 10 ++ server.h | 1 + svvm_cmds.c | 270 ++--------------------------------------- 6 files changed, 374 insertions(+), 486 deletions(-) diff --git a/clvm_cmds.c b/clvm_cmds.c index 32e0300f..4ae832cf 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -1939,225 +1939,6 @@ static void VM_CL_te_flamejet (void) } -//==================================================================== -//DP_QC_GETSURFACE - -extern void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out); - -static msurface_t *cl_getsurface(dp_model_t *model, int surfacenum) -{ - if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces) - return NULL; - return model->data_surfaces + surfacenum + model->firstmodelsurface; -} - -// #434 float(entity e, float s) getsurfacenumpoints -static void VM_CL_getsurfacenumpoints(void) -{ - dp_model_t *model; - msurface_t *surface; - VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints); - // return 0 if no such surface - if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - { - PRVM_G_FLOAT(OFS_RETURN) = 0; - return; - } - - // note: this (incorrectly) assumes it is a simple polygon - PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices; -} - -// #435 vector(entity e, float s, float n) getsurfacepoint -static void VM_CL_getsurfacepoint(void) -{ - prvm_edict_t *ed; - dp_model_t *model; - msurface_t *surface; - int pointnum; - VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - ed = PRVM_G_EDICT(OFS_PARM0); - if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // note: this (incorrectly) assumes it is a simple polygon - pointnum = (int)PRVM_G_FLOAT(OFS_PARM2); - if (pointnum < 0 || pointnum >= surface->num_vertices) - return; - // FIXME: implement rotation/scaling - VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN)); -} -//PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; -// float SPA_POSITION = 0; -// float SPA_S_AXIS = 1; -// float SPA_T_AXIS = 2; -// float SPA_R_AXIS = 3; // same as SPA_NORMAL -// float SPA_TEXCOORDS0 = 4; -// float SPA_LIGHTMAP0_TEXCOORDS = 5; -// float SPA_LIGHTMAP0_COLOR = 6; -// TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black] -static void VM_CL_getsurfacepointattribute(void) -{ - prvm_edict_t *ed; - dp_model_t *model; - msurface_t *surface; - int pointnum; - int attributetype; - - VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - ed = PRVM_G_EDICT(OFS_PARM0); - if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // note: this (incorrectly) assumes it is a simple polygon - pointnum = (int)PRVM_G_FLOAT(OFS_PARM2); - if (pointnum < 0 || pointnum >= surface->num_vertices) - return; - - // FIXME: implement rotation/scaling - attributetype = (int) PRVM_G_FLOAT(OFS_PARM3); - - switch( attributetype ) { - // float SPA_POSITION = 0; - case 0: - VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_S_AXIS = 1; - case 1: - VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_T_AXIS = 2; - case 2: - VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_R_AXIS = 3; // same as SPA_NORMAL - case 3: - VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_TEXCOORDS0 = 4; - case 4: { - float *ret = PRVM_G_VECTOR(OFS_RETURN); - float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2]; - ret[0] = texcoord[0]; - ret[1] = texcoord[1]; - ret[2] = 0.0f; - break; - } - // float SPA_LIGHTMAP0_TEXCOORDS = 5; - case 5: { - float *ret = PRVM_G_VECTOR(OFS_RETURN); - float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2]; - ret[0] = texcoord[0]; - ret[1] = texcoord[1]; - ret[2] = 0.0f; - break; - } - // float SPA_LIGHTMAP0_COLOR = 6; - case 6: - // ignore alpha for now.. - VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN)); - break; - default: - VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f ); - break; - } -} -// #436 vector(entity e, float s) getsurfacenormal -static void VM_CL_getsurfacenormal(void) -{ - dp_model_t *model; - msurface_t *surface; - vec3_t normal; - VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // FIXME: implement rotation/scaling - // note: this (incorrectly) assumes it is a simple polygon - // 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); - VectorNormalize(normal); - VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN)); -} - -// #437 string(entity e, float s) getsurfacetexture -static void VM_CL_getsurfacetexture(void) -{ - dp_model_t *model; - msurface_t *surface; - VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture); - PRVM_G_INT(OFS_RETURN) = OFS_NULL; - if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name); -} - -// #438 float(entity e, vector p) getsurfacenearpoint -static void VM_CL_getsurfacenearpoint(void) -{ - int surfacenum, best; - vec3_t clipped, p; - vec_t dist, bestdist; - prvm_edict_t *ed; - dp_model_t *model = NULL; - msurface_t *surface; - vec_t *point; - VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint); - PRVM_G_FLOAT(OFS_RETURN) = -1; - ed = PRVM_G_EDICT(OFS_PARM0); - if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces) - return; - - // FIXME: implement rotation/scaling - point = PRVM_G_VECTOR(OFS_PARM1); - VectorSubtract(point, ed->fields.client->origin, p); - best = -1; - bestdist = 1000000000; - for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++) - { - surface = model->data_surfaces + surfacenum + model->firstmodelsurface; - // first see if the nearest point on the surface's box is closer than the previous match - clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0]; - clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1]; - clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2]; - dist = VectorLength2(clipped); - if (dist < bestdist) - { - // it is, check the nearest point on the actual geometry - clippointtosurface(model, surface, p, clipped); - VectorSubtract(clipped, p, clipped); - dist += VectorLength2(clipped); - if (dist < bestdist) - { - // that's closer too, store it as the best match - best = surfacenum; - bestdist = dist; - } - } - } - PRVM_G_FLOAT(OFS_RETURN) = best; -} - -// #439 vector(entity e, float s, vector p) getsurfaceclippedpoint -static void VM_CL_getsurfaceclippedpoint(void) -{ - prvm_edict_t *ed; - dp_model_t *model; - msurface_t *surface; - vec3_t p, out; - VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - ed = PRVM_G_EDICT(OFS_PARM0); - if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // FIXME: implement rotation/scaling - VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p); - clippointtosurface(model, surface, p, out); - // FIXME: implement rotation/scaling - VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN)); -} - // #443 void(entity e, entity tagentity, string tagname) setattachment void VM_CL_setattachment (void) { @@ -4393,12 +4174,12 @@ VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lig VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS) VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS) VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN) -VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) -VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE) -VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE) -VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) -VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) -VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) +VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) +VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE) +VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE) +VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) +VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) +VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND) VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND) @@ -4445,7 +4226,7 @@ VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTR VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND) VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE) VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE) -VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute +VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute VM_gecko_create, // #487 float gecko_create( string name ) VM_gecko_destroy, // #488 void gecko_destroy( string name ) VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI ) @@ -4587,7 +4368,9 @@ VM_CL_getextresponse, // #624 string getextresponse(void) NULL, // #625 NULL, // #626 VM_sprintf, // #627 string sprintf(string format, ...) -NULL, // #628 +VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE) +VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE) +NULL, // #630 }; const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t); diff --git a/clvm_cmds.h b/clvm_cmds.h index 32aebeb8..8835dae6 100644 --- a/clvm_cmds.h +++ b/clvm_cmds.h @@ -3,6 +3,7 @@ int CL_GetPitchSign(prvm_edict_t *ent); int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex); +void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix); /* These are VM built-ins that originate in the client-side programs support but are reused by the other programs (usually the menu). */ diff --git a/prvm_cmds.c b/prvm_cmds.c index 5d365042..145efd8a 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -10,6 +10,8 @@ #include "libcurl.h" #include +#include "cl_collision.h" +#include "clvm_cmds.h" #include "ft2.h" extern cvar_t prvm_backtraceforwarnings; @@ -5962,3 +5964,342 @@ finished: *o = 0; PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(outbuf); } + + +// surface querying + +static dp_model_t *getmodel(prvm_edict_t *ed) +{ + switch(PRVM_GetProgNr()) + { + case PRVM_SERVERPROG: + return SV_GetModelFromEdict(ed); + case PRVM_CLIENTPROG: + return CL_GetModelFromEdict(ed); + default: + return NULL; + } +} + +static void getmatrix(prvm_edict_t *ed, matrix4x4_t *out) +{ + switch(PRVM_GetProgNr()) + { + case PRVM_SERVERPROG: + SV_GetEntityMatrix(ed, out, false); + break; + case PRVM_CLIENTPROG: + CL_GetEntityMatrix(ed, out, false); + break; + default: + *out = identitymatrix; + break; + } +} + +static void applytransform_forward(const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m; + getmatrix(ed, &m); + Matrix4x4_Transform(&m, in, out); +} + +static void applytransform_forward_direction(const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m; + getmatrix(ed, &m); + Matrix4x4_Transform3x3(&m, in, out); +} + +static void applytransform_inverted(const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m, n; + getmatrix(ed, &m); + Matrix4x4_Invert_Full(&m, &n); + Matrix4x4_Transform3x3(&n, in, out); +} + +static void applytransform_forward_normal(const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m; + float p[4]; + getmatrix(ed, &m); + Matrix4x4_TransformPositivePlane(&m, in[0], in[1], in[2], 0, p); + VectorCopy(p, out); +} + +static void clippointtosurface(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; + 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; + TriangleNormal(v[0], v[1], v[2], facenormal); + VectorNormalize(facenormal); + offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal); + VectorMA(p, offsetdist, facenormal, temp); + for (j = 0, k = 2;j < 3;k = j, j++) + { + VectorSubtract(v[k], v[j], edgenormal); + CrossProduct(edgenormal, facenormal, sidenormal); + VectorNormalize(sidenormal); + offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal); + if (offsetdist < 0) + VectorMA(temp, offsetdist, sidenormal, temp); + } + dist = VectorDistance2(temp, p); + if (bestdist > dist) + { + bestdist = dist; + VectorCopy(temp, out); + } + } +} + +static msurface_t *getsurface(dp_model_t *model, int surfacenum) +{ + if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces) + return NULL; + return model->data_surfaces + surfacenum + model->firstmodelsurface; +} + + +//PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434; +void VM_getsurfacenumpoints(void) +{ + dp_model_t *model; + msurface_t *surface; + VM_SAFEPARMCOUNT(2, VM_getsurfacenumpoints); + // return 0 if no such surface + if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + // note: this (incorrectly) assumes it is a simple polygon + PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices; +} +//PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435; +void VM_getsurfacepoint(void) +{ + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + int pointnum; + VM_SAFEPARMCOUNT(3, VM_getsurfacepoint); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + // note: this (incorrectly) assumes it is a simple polygon + 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)); +} +//PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; +// float SPA_POSITION = 0; +// float SPA_S_AXIS = 1; +// float SPA_T_AXIS = 2; +// float SPA_R_AXIS = 3; // same as SPA_NORMAL +// float SPA_TEXCOORDS0 = 4; +// float SPA_LIGHTMAP0_TEXCOORDS = 5; +// float SPA_LIGHTMAP0_COLOR = 6; +void VM_getsurfacepointattribute(void) +{ + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + int pointnum; + int attributetype; + + VM_SAFEPARMCOUNT(4, VM_getsurfacepoint); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + pointnum = (int)PRVM_G_FLOAT(OFS_PARM2); + if (pointnum < 0 || pointnum >= surface->num_vertices) + return; + attributetype = (int) PRVM_G_FLOAT(OFS_PARM3); + + 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)); + 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)); + 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)); + 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)); + break; + // float SPA_TEXCOORDS0 = 4; + case 4: { + float *ret = PRVM_G_VECTOR(OFS_RETURN); + float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2]; + ret[0] = texcoord[0]; + ret[1] = texcoord[1]; + ret[2] = 0.0f; + break; + } + // float SPA_LIGHTMAP0_TEXCOORDS = 5; + case 5: { + float *ret = PRVM_G_VECTOR(OFS_RETURN); + float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2]; + ret[0] = texcoord[0]; + ret[1] = texcoord[1]; + ret[2] = 0.0f; + break; + } + // float SPA_LIGHTMAP0_COLOR = 6; + case 6: + // ignore alpha for now.. + VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN)); + break; + default: + VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f ); + break; + } +} +//PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436; +void VM_getsurfacenormal(void) +{ + dp_model_t *model; + msurface_t *surface; + vec3_t normal; + VM_SAFEPARMCOUNT(2, VM_getsurfacenormal); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + 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); + applytransform_forward_normal(normal, PRVM_G_EDICT(OFS_PARM0), PRVM_G_VECTOR(OFS_RETURN)); + VectorNormalize(PRVM_G_VECTOR(OFS_RETURN)); +} +//PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437; +void VM_getsurfacetexture(void) +{ + dp_model_t *model; + msurface_t *surface; + VM_SAFEPARMCOUNT(2, VM_getsurfacetexture); + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name); +} +//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438; +void VM_getsurfacenearpoint(void) +{ + int surfacenum, best; + vec3_t clipped, p; + vec_t dist, bestdist; + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + vec_t *point; + VM_SAFEPARMCOUNT(2, VM_getsurfacenearpoint); + PRVM_G_FLOAT(OFS_RETURN) = -1; + ed = PRVM_G_EDICT(OFS_PARM0); + point = PRVM_G_VECTOR(OFS_PARM1); + + if (!ed || ed->priv.server->free) + return; + model = getmodel(ed); + if (!model || !model->num_surfaces) + return; + + applytransform_inverted(point, ed, p); + best = -1; + bestdist = 1000000000; + for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++) + { + surface = model->data_surfaces + surfacenum + model->firstmodelsurface; + // first see if the nearest point on the surface's box is closer than the previous match + clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0]; + clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1]; + clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2]; + dist = VectorLength2(clipped); + if (dist < bestdist) + { + // it is, check the nearest point on the actual geometry + clippointtosurface(model, surface, p, clipped); + VectorSubtract(clipped, p, clipped); + dist += VectorLength2(clipped); + if (dist < bestdist) + { + // that's closer too, store it as the best match + best = surfacenum; + bestdist = dist; + } + } + } + PRVM_G_FLOAT(OFS_RETURN) = best; +} +//PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; +void VM_getsurfaceclippedpoint(void) +{ + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + vec3_t p, out; + VM_SAFEPARMCOUNT(3, VM_te_getsurfaceclippedpoint); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + applytransform_inverted(PRVM_G_VECTOR(OFS_PARM2), ed, p); + clippointtosurface(model, surface, p, out); + VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN)); +} + +//PF_getsurfacenumtriangles, // #??? float(entity e, float s) getsurfacenumtriangles = #???; +void VM_getsurfacenumtriangles(void) +{ + dp_model_t *model; + msurface_t *surface; + VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumtriangles); + // return 0 if no such surface + if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + // note: this (incorrectly) assumes it is a simple polygon + PRVM_G_FLOAT(OFS_RETURN) = surface->num_triangles; +} +//PF_getsurfacetriangle, // #??? vector(entity e, float s, float n) getsurfacetriangle = #???; +void VM_getsurfacetriangle(void) +{ + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + int trinum; + VM_SAFEPARMCOUNT(3, VM_SV_getsurfacetriangle); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + trinum = (int)PRVM_G_FLOAT(OFS_PARM2); + 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)); +} diff --git a/prvm_cmds.h b/prvm_cmds.h index 0a3eafe5..ad7e9638 100644 --- a/prvm_cmds.h +++ b/prvm_cmds.h @@ -450,3 +450,13 @@ void VM_isfunction(void); void VM_callfunction(void); void VM_sprintf(void); + +void VM_getsurfacenumpoints(void); +void VM_getsurfacepoint(void); +void VM_getsurfacepointattribute(void); +void VM_getsurfacenormal(void); +void VM_getsurfacetexture(void); +void VM_getsurfacenearpoint(void); +void VM_getsurfaceclippedpoint(void); +void VM_getsurfacenumtriangles(void); +void VM_getsurfacetriangle(void); diff --git a/server.h b/server.h index d8a10902..94a53cf5 100644 --- a/server.h +++ b/server.h @@ -563,6 +563,7 @@ void SV_VM_End(void); const char *Host_TimingReport(void); ///< for output in Host_Status_f int SV_GetPitchSign(prvm_edict_t *ent); +void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix); #endif diff --git a/svvm_cmds.c b/svvm_cmds.c index 42d29acf..889a8fbb 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -89,6 +89,7 @@ char *vm_sv_extensions = "DP_QC_FS_SEARCH " "DP_QC_GETLIGHT " "DP_QC_GETSURFACE " +"DP_QC_GETSURFACETRIANGLE " "DP_QC_GETSURFACEPOINTATTRIBUTE " "DP_QC_GETTAGINFO " "DP_QC_GETTAGINFO_BONEPROPERTIES " @@ -2250,257 +2251,6 @@ static void VM_SV_te_flamejet (void) SV_FlushBroadcastMessages(); } -void clippointtosurface(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; - 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; - TriangleNormal(v[0], v[1], v[2], facenormal); - VectorNormalize(facenormal); - offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal); - VectorMA(p, offsetdist, facenormal, temp); - for (j = 0, k = 2;j < 3;k = j, j++) - { - VectorSubtract(v[k], v[j], edgenormal); - CrossProduct(edgenormal, facenormal, sidenormal); - VectorNormalize(sidenormal); - offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal); - if (offsetdist < 0) - VectorMA(temp, offsetdist, sidenormal, temp); - } - dist = VectorDistance2(temp, p); - if (bestdist > dist) - { - bestdist = dist; - VectorCopy(temp, out); - } - } -} - -#define getmodel SV_GetModelFromEdict - -static msurface_t *getsurface(dp_model_t *model, int surfacenum) -{ - if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces) - return NULL; - return model->data_surfaces + surfacenum + model->firstmodelsurface; -} - - -//PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434; -static void VM_SV_getsurfacenumpoints(void) -{ - dp_model_t *model; - msurface_t *surface; - VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints); - // return 0 if no such surface - if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - { - PRVM_G_FLOAT(OFS_RETURN) = 0; - return; - } - - // note: this (incorrectly) assumes it is a simple polygon - PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices; -} -//PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435; -static void VM_SV_getsurfacepoint(void) -{ - prvm_edict_t *ed; - dp_model_t *model; - msurface_t *surface; - int pointnum; - VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - ed = PRVM_G_EDICT(OFS_PARM0); - if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // note: this (incorrectly) assumes it is a simple polygon - pointnum = (int)PRVM_G_FLOAT(OFS_PARM2); - if (pointnum < 0 || pointnum >= surface->num_vertices) - return; - // FIXME: implement rotation/scaling - VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN)); -} -//PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; -// float SPA_POSITION = 0; -// float SPA_S_AXIS = 1; -// float SPA_T_AXIS = 2; -// float SPA_R_AXIS = 3; // same as SPA_NORMAL -// float SPA_TEXCOORDS0 = 4; -// float SPA_LIGHTMAP0_TEXCOORDS = 5; -// float SPA_LIGHTMAP0_COLOR = 6; -static void VM_SV_getsurfacepointattribute(void) -{ - prvm_edict_t *ed; - dp_model_t *model; - msurface_t *surface; - int pointnum; - int attributetype; - - VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - ed = PRVM_G_EDICT(OFS_PARM0); - if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // note: this (incorrectly) assumes it is a simple polygon - pointnum = (int)PRVM_G_FLOAT(OFS_PARM2); - if (pointnum < 0 || pointnum >= surface->num_vertices) - return; - // FIXME: implement rotation/scaling - attributetype = (int) PRVM_G_FLOAT(OFS_PARM3); - - switch( attributetype ) { - // float SPA_POSITION = 0; - case 0: - VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_S_AXIS = 1; - case 1: - VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_T_AXIS = 2; - case 2: - VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_R_AXIS = 3; // same as SPA_NORMAL - case 3: - VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN)); - break; - // float SPA_TEXCOORDS0 = 4; - case 4: { - float *ret = PRVM_G_VECTOR(OFS_RETURN); - float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2]; - ret[0] = texcoord[0]; - ret[1] = texcoord[1]; - ret[2] = 0.0f; - break; - } - // float SPA_LIGHTMAP0_TEXCOORDS = 5; - case 5: { - float *ret = PRVM_G_VECTOR(OFS_RETURN); - float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2]; - ret[0] = texcoord[0]; - ret[1] = texcoord[1]; - ret[2] = 0.0f; - break; - } - // float SPA_LIGHTMAP0_COLOR = 6; - case 6: - // ignore alpha for now.. - VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN)); - break; - default: - VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f ); - break; - } -} -//PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436; -static void VM_SV_getsurfacenormal(void) -{ - dp_model_t *model; - msurface_t *surface; - vec3_t normal; - VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // FIXME: implement rotation/scaling - // note: this (incorrectly) assumes it is a simple polygon - // 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); - VectorNormalize(normal); - VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN)); -} -//PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437; -static void VM_SV_getsurfacetexture(void) -{ - dp_model_t *model; - msurface_t *surface; - VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture); - PRVM_G_INT(OFS_RETURN) = OFS_NULL; - if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name); -} -//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438; -static void VM_SV_getsurfacenearpoint(void) -{ - int surfacenum, best; - vec3_t clipped, p; - vec_t dist, bestdist; - prvm_edict_t *ed; - dp_model_t *model; - msurface_t *surface; - vec_t *point; - VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint); - PRVM_G_FLOAT(OFS_RETURN) = -1; - ed = PRVM_G_EDICT(OFS_PARM0); - point = PRVM_G_VECTOR(OFS_PARM1); - - if (!ed || ed->priv.server->free) - return; - model = getmodel(ed); - if (!model || !model->num_surfaces) - return; - - // FIXME: implement rotation/scaling - VectorSubtract(point, ed->fields.server->origin, p); - best = -1; - bestdist = 1000000000; - for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++) - { - surface = model->data_surfaces + surfacenum + model->firstmodelsurface; - // first see if the nearest point on the surface's box is closer than the previous match - clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0]; - clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1]; - clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2]; - dist = VectorLength2(clipped); - if (dist < bestdist) - { - // it is, check the nearest point on the actual geometry - clippointtosurface(model, surface, p, clipped); - VectorSubtract(clipped, p, clipped); - dist += VectorLength2(clipped); - if (dist < bestdist) - { - // that's closer too, store it as the best match - best = surfacenum; - bestdist = dist; - } - } - } - PRVM_G_FLOAT(OFS_RETURN) = best; -} -//PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; -static void VM_SV_getsurfaceclippedpoint(void) -{ - prvm_edict_t *ed; - dp_model_t *model; - msurface_t *surface; - vec3_t p, out; - VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint); - VectorClear(PRVM_G_VECTOR(OFS_RETURN)); - ed = PRVM_G_EDICT(OFS_PARM0); - if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) - return; - // FIXME: implement rotation/scaling - VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p); - clippointtosurface(model, surface, p, out); - // FIXME: implement rotation/scaling - VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN)); -} - //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client //this function originally written by KrimZon, made shorter by LordHavoc static void VM_SV_clientcommand (void) @@ -3808,12 +3558,12 @@ VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lig VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS) VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS) VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN) -VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) -VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE) -VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE) -VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) -VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) -VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) +VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) +VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE) +VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE) +VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) +VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) +VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND) VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND) @@ -3860,7 +3610,7 @@ VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTR VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND) VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE) VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE) -VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; +VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; NULL, // #487 NULL, // #488 NULL, // #489 @@ -4002,7 +3752,9 @@ VM_SV_getextresponse, // #624 string getextresponse(void) NULL, // #625 NULL, // #626 VM_sprintf, // #627 string sprintf(string format, ...) -NULL, // #628 +VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE) +VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE) +NULL, // #630 }; const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t); -- 2.39.2