user (csqc) controllable wavefuncs
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 17 Jun 2010 21:39:09 +0000 (21:39 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 17 Jun 2010 21:39:09 +0000 (21:39 +0000)
From: Rudolf Polzer <divverent@alientrap.org>

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10236 d7cf8633-e32d-0410-b094-e92efae38249

client.h
csprogs.c
gl_rmain.c
model_shared.c
model_shared.h
progsvm.h
prvm_edict.c
render.h

index 270db45..633335b 100644 (file)
--- a/client.h
+++ b/client.h
@@ -387,6 +387,9 @@ typedef struct entity_render_s
        // FIELDS UPDATED BY RENDERER:
        // last time visible during trace culling
        double last_trace_visibility;
+
+       // user wavefunc parameters (from csqc)
+       float userwavefunc_param[Q3WAVEFUNC_USER_COUNT];
 }
 entity_render_t;
 
index d417fa9..3e82840 100644 (file)
--- a/csprogs.c
+++ b/csprogs.c
@@ -190,6 +190,11 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
                        return false;
        }
 
+       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param0)))    entrender->userwavefunc_param[0] = val->_float;
+       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param1)))    entrender->userwavefunc_param[1] = val->_float;
+       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param2)))    entrender->userwavefunc_param[2] = val->_float;
+       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param3)))    entrender->userwavefunc_param[3] = val->_float;
+
        entrender->model = model;
        entrender->skinnum = (int)ed->fields.client->skin;
        entrender->effects |= entrender->model->effects;
index 2e83774..fc88e5b 100644 (file)
@@ -9109,12 +9109,22 @@ static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1,
        layer->color[3] = a;
 }
 
+static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
+{
+       if(parms[0] == 0 && parms[1] == 0)
+               return false;
+       if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
+               if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT)] == 0);
+                       return false;
+       return true;
+}
+
 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
 {
        double index, f;
        index = parms[2] + r_refdef.scene.time * parms[3];
        index -= floor(index);
-       switch (func)
+       switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
        {
        default:
        case Q3WAVEFUNC_NONE:
@@ -9139,7 +9149,10 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
                        f = -(1 - f);
                break;
        }
-       return (float)(parms[0] + parms[1] * f);
+       f = parms[0] + parms[1] * f;
+       if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
+               f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT)];
+       return (float) f;
 }
 
 void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
@@ -9576,6 +9589,7 @@ void RSurf_ActiveWorldEntity(void)
        //      return;
        rsurface.entity = r_refdef.scene.worldentity;
        rsurface.skeleton = NULL;
+       memset(rsurface.userwavefunc_param, 0, sizeof(rsurface.userwavefunc_param));
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
        rsurface.ent_shadertime = 0;
@@ -9690,6 +9704,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        //      return;
        rsurface.entity = (entity_render_t *)ent;
        rsurface.skeleton = ent->skeleton;
+       memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
        rsurface.ent_skinnum = ent->skinnum;
        rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
        rsurface.ent_shadertime = ent->shadertime;
@@ -10691,6 +10706,8 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                        waveparms[1] = deform->waveparms[1];
                        waveparms[2] = deform->waveparms[2];
                        waveparms[3] = deform->waveparms[3];
+                       if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
+                               break; // if wavefunc is a nop, don't make a dynamic vertex array
                        // this is how a divisor of vertex influence on deformation
                        animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
                        scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
@@ -10743,6 +10760,8 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                        break;
                case Q3DEFORM_MOVE:
                        // deform vertex array
+                       if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
+                               break; // if wavefunc is a nop, don't make a dynamic vertex array
                        scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
                        VectorScale(deform->parms, scale, waveparms);
                        for (j = 0;j < rsurface.batchnumvertices;j++)
index 0269989..97c4dea 100644 (file)
@@ -1532,16 +1532,26 @@ void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
 }
 #endif
 
-q3wavefunc_t Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
+int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
 {
-       if (!strcasecmp(s, "sin"))             return Q3WAVEFUNC_SIN;
-       if (!strcasecmp(s, "square"))          return Q3WAVEFUNC_SQUARE;
-       if (!strcasecmp(s, "triangle"))        return Q3WAVEFUNC_TRIANGLE;
-       if (!strcasecmp(s, "sawtooth"))        return Q3WAVEFUNC_SAWTOOTH;
-       if (!strcasecmp(s, "inversesawtooth")) return Q3WAVEFUNC_INVERSESAWTOOTH;
-       if (!strcasecmp(s, "noise"))           return Q3WAVEFUNC_NOISE;
+       int offset = 0;
+       if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
+       {
+               offset = bound(0, s[4] - '0', 9);
+               offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT;
+               s += 4;
+               if(*s)
+                       ++s;
+       }
+       if (!strcasecmp(s, "sin"))             return offset | Q3WAVEFUNC_SIN;
+       if (!strcasecmp(s, "square"))          return offset | Q3WAVEFUNC_SQUARE;
+       if (!strcasecmp(s, "triangle"))        return offset | Q3WAVEFUNC_TRIANGLE;
+       if (!strcasecmp(s, "sawtooth"))        return offset | Q3WAVEFUNC_SAWTOOTH;
+       if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH;
+       if (!strcasecmp(s, "noise"))           return offset | Q3WAVEFUNC_NOISE;
+       if (!strcasecmp(s, "none"))            return offset | Q3WAVEFUNC_NONE;
        Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s);
-       return Q3WAVEFUNC_NONE;
+       return offset | Q3WAVEFUNC_NONE;
 }
 
 void Mod_FreeQ3Shaders(void)
index eca7ef3..f8a8dab 100644 (file)
@@ -283,7 +283,10 @@ typedef enum q3wavefunc_e
        Q3WAVEFUNC_TRIANGLE,
        Q3WAVEFUNC_COUNT
 }
-q3wavefunc_t;
+q3wavefunc_e;
+typedef int q3wavefunc_t;
+#define Q3WAVEFUNC_USER_COUNT 4
+#define Q3WAVEFUNC_USER_SHIFT 8 // use 8 bits for wave func type
 
 typedef enum q3deform_e
 {
index fd9af60..a5a5a98 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -269,6 +269,11 @@ typedef struct prvm_prog_fieldoffsets_s
        int movedir; // ssqc / csqc (physics)
 
        int camera_transform; // csqc (warpzones)
+
+       int userwavefunc_param0; // csqc (userwavefunc)
+       int userwavefunc_param1; // csqc (userwavefunc)
+       int userwavefunc_param2; // csqc (userwavefunc)
+       int userwavefunc_param3; // csqc (userwavefunc)
 }
 prvm_prog_fieldoffsets_t;
 
index ceb0e3c..5a51bab 100644 (file)
@@ -1656,6 +1656,10 @@ void PRVM_FindOffsets(void)
        prog->fieldoffsets.movedir                        = PRVM_ED_FindFieldOffset("movedir");
 
        prog->fieldoffsets.camera_transform               = PRVM_ED_FindFieldOffset("camera_transform");
+       prog->fieldoffsets.userwavefunc_param0            = PRVM_ED_FindFieldOffset("userwavefunc_param0");
+       prog->fieldoffsets.userwavefunc_param1            = PRVM_ED_FindFieldOffset("userwavefunc_param1");
+       prog->fieldoffsets.userwavefunc_param2            = PRVM_ED_FindFieldOffset("userwavefunc_param2");
+       prog->fieldoffsets.userwavefunc_param3            = PRVM_ED_FindFieldOffset("userwavefunc_param3");
 
        prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
        prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
index aa90252..7cc1ae2 100644 (file)
--- a/render.h
+++ b/render.h
@@ -410,6 +410,9 @@ typedef struct rsurfacestate_s
        // this transforms only the Z to S, and T is always 0.5
        matrix4x4_t entitytoattenuationz;
 
+       // user wavefunc parameters (from csqc)
+       float userwavefunc_param[Q3WAVEFUNC_USER_COUNT];
+
        // pointer to an entity_render_t used only by R_GetCurrentTexture and
        // RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity as a unique id within
        // each frame (see r_frame also)