Add CL_MeshEntities_*, every frame in the client all MESH_ entities are added to...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 25 Mar 2018 19:58:39 +0000 (19:58 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 25 Mar 2018 19:58:39 +0000 (19:58 +0000)
Add Mod_Mesh functions - these allow creation of dynamic mesh models.

Add Mod_LoadCustomMaterial which initializes a texture_t using a skinframe and some parameters, useful with Mod_Mesh and CL_MeshEntities.

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

cl_main.c
client.h
host.c
model_shared.c
model_shared.h

index 44dc047..b13cb5f 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -1895,6 +1895,8 @@ void CSQC_RelinkAllEntities (int drawmask)
 
        // update view blend
        V_CalcViewBlend();
+
+       CL_MeshEntities_AddToScene();
 }
 
 /*
@@ -2368,6 +2370,83 @@ void CL_Locs_Reload_f(void)
        }
 }
 
+entity_t cl_meshentities[NUM_MESHENTITIES];
+dp_model_t cl_meshentitymodels[NUM_MESHENTITIES];
+const char *cl_meshentitynames[NUM_MESHENTITIES] =
+{
+       "MESH_DEBUG",
+       "MESH_CSQC_POLYGONS",
+       "MESH_PARTICLES",
+       "MESH_UI",
+};
+
+void CL_MeshEntities_Restart(void)
+{
+       int i;
+       entity_t *ent;
+       for (i = 0; i < NUM_MESHENTITIES; i++)
+       {
+               ent = cl_meshentities + i;
+               Mod_Mesh_Create(ent->render.model, cl_meshentitynames[i]);
+       }
+}
+
+void CL_MeshEntities_Init(void)
+{
+       int i;
+       entity_t *ent;
+       for (i = 0; i < NUM_MESHENTITIES; i++)
+       {
+               ent = cl_meshentities + i;
+               ent->state_current.active = true;
+               ent->render.model = cl_meshentitymodels + i;
+               ent->render.alpha = 1;
+               ent->render.flags = RENDER_LIGHT;
+               ent->render.framegroupblend[0].lerp = 1;
+               ent->render.frameblend[0].lerp = 1;
+               VectorSet(ent->render.colormod, 1, 1, 1);
+               VectorSet(ent->render.glowmod, 1, 1, 1);
+               VectorSet(ent->render.modellight_ambient, 1, 1, 1);
+               VectorSet(ent->render.modellight_diffuse, 0, 0, 0);
+               VectorSet(ent->render.modellight_lightdir, 0, 0, 1);
+               Matrix4x4_CreateIdentity(&ent->render.matrix);
+               CL_UpdateRenderEntity(&ent->render);
+       }
+       cl_meshentities[MESH_CSQCPOLYGONS].render.flags = RENDER_SHADOW | RENDER_LIGHT;
+       R_RegisterModule("cl_meshentities", CL_MeshEntities_Restart, CL_MeshEntities_Restart, CL_MeshEntities_Restart, CL_MeshEntities_Restart, CL_MeshEntities_Restart);
+}
+
+void CL_MeshEntities_AddToScene(void)
+{
+       int i;
+       entity_t *ent;
+       for (i = 0; i < NUM_MESHENTITIES && r_refdef.scene.numentities < r_refdef.scene.maxentities; i++)
+       {
+               ent = cl_meshentities + i;
+               if (ent->render.model->num_surfaces == 0)
+                       continue;
+               Mod_Mesh_Finalize(ent->render.model);
+               VectorCopy(ent->render.model->normalmins, ent->render.mins);
+               VectorCopy(ent->render.model->normalmaxs, ent->render.maxs);
+               r_refdef.scene.entities[r_refdef.scene.numentities++] = &ent->render;
+       }
+}
+
+void CL_MeshEntities_Reset(void)
+{
+       int i;
+       entity_t *ent;
+       for (i = 0; i < NUM_MESHENTITIES && r_refdef.scene.numentities < r_refdef.scene.maxentities; i++)
+       {
+               ent = cl_meshentities + i;
+               Mod_Mesh_Reset(ent->render.model);
+       }
+}
+
+void CL_MeshEntities_Shutdown(void)
+{
+}
+
 /*
 ===========
 CL_Shutdown
@@ -2378,6 +2457,7 @@ void CL_Shutdown (void)
        CL_Screen_Shutdown();
        CL_Particles_Shutdown();
        CL_Parse_Shutdown();
+       CL_MeshEntities_Shutdown();
 
        Mem_FreePool (&cls.permanentmempool);
        Mem_FreePool (&cls.levelmempool);
@@ -2497,6 +2577,7 @@ void CL_Init (void)
        CL_Parse_Init();
        CL_Particles_Init();
        CL_Screen_Init();
+       CL_MeshEntities_Init();
 
        CL_Video_Init();
 }
index e3120c0..05bed86 100644 (file)
--- a/client.h
+++ b/client.h
@@ -2020,6 +2020,23 @@ void CL_ClientMovement_PlayerMove_Frame(cl_clientmovement_state_t *s);
 // warpzone prediction hack (CSQC builtin)
 void CL_RotateMoves(const matrix4x4_t *m);
 
+typedef enum meshname_e {
+       MESH_DEBUG,
+       MESH_CSQCPOLYGONS,
+       MESH_PARTICLES,
+       MESH_UI,
+       NUM_MESHENTITIES,
+} meshname_t;
+extern entity_t cl_meshentities[NUM_MESHENTITIES];
+extern dp_model_t cl_meshentitymodels[NUM_MESHENTITIES];
+extern const char *cl_meshentitynames[NUM_MESHENTITIES];
+#define CL_Mesh_Debug() (&cl_meshentitymodels[MESH_DEBUG])
+#define CL_Mesh_CSQC() (&cl_meshentitymodels[MESH_CSQCPOLYGONS])
+#define CL_Mesh_Particles() (&cl_meshentitymodels[MESH_PARTICLES])
+#define CL_Mesh_UI() (&cl_meshentitymodels[MESH_UI])
+void CL_MeshEntities_AddToScene(void);
+void CL_MeshEntities_Reset(void);
+
 void CL_NewFrameReceived(int num);
 void CL_ParseEntityLump(char *entitystring);
 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
diff --git a/host.c b/host.c
index 7e7bc56..62dcf47 100644 (file)
--- a/host.c
+++ b/host.c
@@ -1021,6 +1021,7 @@ void Host_Main(void)
                        R_TimeReport("client");
 
                        CL_UpdateScreen();
+                       CL_MeshEntities_Reset();
                        R_TimeReport("render");
 
                        if (host_speeds.integer)
index 2de58bd..b6225fd 100644 (file)
@@ -2837,6 +2837,39 @@ nothing                GL_ZERO GL_ONE
        return success;
 }
 
+void Mod_LoadCustomMaterial(texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
+{
+       if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY)))
+               Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", loadmodel->name, texture->name);
+       strlcpy(texture->name, name, sizeof(texture->name));
+       texture->basealpha = 1.0f;
+       texture->basematerialflags = texture->currentmaterialflags = materialflags;
+       texture->supercontents = supercontents;
+
+       texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
+       texture->offsetscale = 1;
+       texture->offsetbias = 0;
+       texture->specularscalemod = 1;
+       texture->specularpowermod = 1;
+       texture->rtlightambient = 0;
+       texture->transparentsort = TRANSPARENTSORT_DISTANCE;
+       // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
+       // JUST GREP FOR "specularscalemod = 1".
+
+       if (developer_extra.integer)
+               Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\"\n", loadmodel->name, texture->name);
+       texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
+
+       // init the animation variables
+       texture->currentframe = texture;
+       if (!texture->materialshaderpass)
+               texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing());
+       if (!texture->materialshaderpass->skinframes[0])
+               texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
+       texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
+       texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
+}
+
 skinfile_t *Mod_LoadSkinFiles(void)
 {
        int i, words, line, wordsoverflow;
@@ -4542,3 +4575,277 @@ static void Mod_GenerateLightmaps_f(void)
        }
        Mod_GenerateLightmaps(cl.worldmodel);
 }
+
+void Mod_Mesh_Create(dp_model_t *mod, const char *name)
+{
+       memset(mod, 0, sizeof(*mod));
+       strlcpy(mod->name, name, sizeof(mod->name));
+       mod->mempool = Mem_AllocPool(name, 0, NULL);
+       mod->texturepool = R_AllocTexturePool();
+       mod->Draw = R_Q1BSP_Draw;
+       mod->DrawDepth = R_Q1BSP_DrawDepth;
+       mod->DrawDebug = R_Q1BSP_DrawDebug;
+       mod->DrawPrepass = R_Q1BSP_DrawPrepass;
+       mod->GetLightInfo = R_Q1BSP_GetLightInfo;
+       mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
+       mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       mod->DrawLight = R_Q1BSP_DrawLight;
+}
+
+void Mod_Mesh_Destroy(dp_model_t *mod)
+{
+       Mod_UnloadModel(mod);
+}
+
+// resets the mesh model to have no geometry to render, ready for a new frame -
+// the mesh will be prepared for rendering later using Mod_Mesh_Finalize
+void Mod_Mesh_Reset(dp_model_t *mod)
+{
+       mod->num_surfaces = 0;
+       mod->surfmesh.num_vertices = 0;
+       mod->surfmesh.num_triangles = 0;
+       memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
+       mod->DrawSky = NULL; // will be set if a texture needs it
+       mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
+}
+
+texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name)
+{
+       int i;
+       texture_t *t;
+       for (i = 0; i < mod->num_textures; i++)
+               if (!strcmp(mod->data_textures[i].name, name))
+                       return mod->data_textures + i;
+       if (mod->max_textures <= mod->num_textures)
+       {
+               texture_t *oldtextures = mod->data_textures;
+               mod->max_textures = max(mod->max_textures * 2, 1024);
+               mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
+               // update the pointers
+               for (i = 0; i < mod->num_surfaces; i++)
+                       mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
+       }
+       t = &mod->data_textures[mod->num_textures++];
+       Mod_LoadTextureFromQ3Shader(t, name, false, true, 0);
+       return t;
+}
+
+msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex)
+{
+       msurface_t *surf;
+       // check if the proposed surface matches the last one we created
+       if (mod->num_surfaces == 0 || mod->data_surfaces[mod->num_surfaces - 1].texture != tex)
+       {
+               if (mod->max_surfaces == mod->num_surfaces)
+               {
+                       mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
+                       mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
+                       mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
+               }
+               surf = mod->data_surfaces + mod->num_surfaces;
+               mod->num_surfaces++;
+               memset(surf, 0, sizeof(*surf));
+               surf->texture = tex;
+               surf->num_firsttriangle = mod->surfmesh.num_triangles;
+               surf->num_firstvertex = mod->surfmesh.num_vertices;
+               if (tex->basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+               return surf;
+       }
+       return mod->data_surfaces + mod->num_surfaces - 1;
+}
+
+int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
+{
+       int hashindex, h, vnum, mask;
+       surfmesh_t *mesh = &mod->surfmesh;
+       if (mesh->max_vertices == mesh->num_vertices)
+       {
+               mesh->max_vertices = max(mesh->num_vertices * 2, 256);
+               mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
+               mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
+               mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
+               mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
+               mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
+               mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
+               mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
+               // rebuild the hash table
+               mesh->num_vertexhashsize = 4 * mesh->max_vertices;
+               mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
+               mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
+               memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
+               mask = mod->surfmesh.num_vertexhashsize - 1;
+               // no need to hash the vertices for the entire model, the latest surface will suffice.
+               for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
+               {
+                       // this uses prime numbers intentionally for computing the hash
+                       hashindex = (unsigned int)(mesh->data_vertex3f[vnum * 3 + 0] * 2003 + mesh->data_vertex3f[vnum * 3 + 1] * 4001 + mesh->data_vertex3f[vnum * 3 + 2] * 7919 + mesh->data_normal3f[vnum * 3 + 0] * 4097 + mesh->data_normal3f[vnum * 3 + 1] * 257 + mesh->data_normal3f[vnum * 3 + 2] * 17) & mask;
+                       for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
+                               ; // just iterate until we find the terminator
+                       mesh->data_vertexhash[h] = vnum;
+               }
+       }
+       mask = mod->surfmesh.num_vertexhashsize - 1;
+       // this uses prime numbers intentionally for computing the hash
+       hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
+       // when possible find an identical vertex within the same surface and return it
+       for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
+       {
+               if (vnum >= surf->num_firstvertex
+                && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
+                && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
+                && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
+                && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
+                && mesh->data_lightmapcolor4f[vnum * 4 + 0] == r && mesh->data_lightmapcolor4f[vnum * 4 + 1] == g && mesh->data_lightmapcolor4f[vnum * 4 + 2] == b && mesh->data_lightmapcolor4f[vnum * 4 + 3] == a)
+                       return vnum;
+       }
+       // add the new vertex
+       vnum = mesh->num_vertices++;
+       if (surf->num_vertices > 0)
+       {
+               if (surf->mins[0] > x) surf->mins[0] = x;
+               if (surf->mins[1] > y) surf->mins[1] = y;
+               if (surf->mins[2] > z) surf->mins[2] = z;
+               if (surf->maxs[0] < x) surf->maxs[0] = x;
+               if (surf->maxs[1] < y) surf->maxs[1] = y;
+               if (surf->maxs[2] < z) surf->maxs[2] = z;
+       }
+       else
+       {
+               VectorSet(surf->mins, x, y, z);
+               VectorSet(surf->maxs, x, y, z);
+       }
+       surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
+       mesh->data_vertexhash[h] = vnum;
+       mesh->data_vertex3f[vnum * 3 + 0] = x;
+       mesh->data_vertex3f[vnum * 3 + 1] = y;
+       mesh->data_vertex3f[vnum * 3 + 2] = z;
+       mesh->data_normal3f[vnum * 3 + 0] = nx;
+       mesh->data_normal3f[vnum * 3 + 1] = ny;
+       mesh->data_normal3f[vnum * 3 + 2] = nz;
+       mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
+       mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
+       mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
+       mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
+       mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
+       mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
+       mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
+       mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
+       return vnum;
+}
+
+void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
+{
+       surfmesh_t *mesh = &mod->surfmesh;
+       if (mesh->max_triangles == mesh->num_triangles)
+       {
+               mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
+               mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
+               mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
+       }
+       mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
+       mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
+       mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
+       mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
+       mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
+       mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
+       mesh->num_triangles++;
+       surf->num_triangles++;
+}
+
+static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
+{
+       int i, j;
+       texture_t *tex;
+       msurface_t *surf, *surf2;
+
+       // build the sorted surfaces list properly to reduce material setup
+       // this is easy because we're just sorting on texture and don't care about the order of textures
+       mod->nummodelsurfaces = 0;
+       for (i = 0; i < mod->num_surfaces; i++)
+               mod->data_surfaces[i].included = false;
+       for (i = 0; i < mod->num_surfaces; i++)
+       {
+               surf = mod->data_surfaces + i;
+               if (surf->included)
+                       continue;
+               tex = surf->texture;
+               // j = i is intentional
+               for (j = i; j < mod->num_surfaces; j++)
+               {
+                       surf2 = mod->data_surfaces + j;
+                       if (surf2->included)
+                               continue;
+                       if (surf2->texture == tex)
+                       {
+                               surf2->included = true;
+                               mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
+                       }
+               }
+       }
+}
+
+void Mod_Mesh_ComputeBounds(dp_model_t *mod)
+{
+       int i;
+       vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
+
+       if (mod->surfmesh.num_vertices > 0)
+       {
+               // calculate normalmins/normalmaxs
+               VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
+               VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
+               for (i = 1; i < mod->surfmesh.num_vertices; i++)
+               {
+                       float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
+                       float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
+                       float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
+                       // expand bounds to include this vertex
+                       if (mod->normalmins[0] > x) mod->normalmins[0] = x;
+                       if (mod->normalmins[1] > y) mod->normalmins[1] = y;
+                       if (mod->normalmins[2] > z) mod->normalmins[2] = z;
+                       if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
+                       if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
+                       if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
+               }
+               // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
+               // (fast but less accurate than doing it per vertex)
+               x2a = mod->normalmins[0] * mod->normalmins[0];
+               x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
+               y2a = mod->normalmins[1] * mod->normalmins[1];
+               y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
+               z2a = mod->normalmins[2] * mod->normalmins[2];
+               z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
+               x2 = max(x2a, x2b);
+               y2 = max(y2a, y2b);
+               z2 = max(z2a, z2b);
+               yawradius = sqrt(x2 + y2);
+               rotatedradius = sqrt(x2 + y2 + z2);
+               VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
+               VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
+               VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
+               VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
+               mod->radius = rotatedradius;
+               mod->radius2 = x2 + y2 + z2;
+       }
+       else
+       {
+               VectorClear(mod->normalmins);
+               VectorClear(mod->normalmaxs);
+               VectorClear(mod->yawmins);
+               VectorClear(mod->yawmaxs);
+               VectorClear(mod->rotatedmins);
+               VectorClear(mod->rotatedmaxs);
+               mod->radius = 0;
+               mod->radius2 = 0;
+       }
+}
+
+void Mod_Mesh_Finalize(dp_model_t *mod)
+{
+       Mod_Mesh_ComputeBounds(mod);
+       Mod_Mesh_MakeSortedSurfaces(mod);
+       Mod_BuildTextureVectorsFromNormals(0, mod->surfmesh.num_vertices, mod->surfmesh.num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_texcoordtexture2f, mod->surfmesh.data_normal3f, mod->surfmesh.data_element3i, mod->surfmesh.data_svector3f, mod->surfmesh.data_tvector3f, true);
+}
index 94957c4..f48a1bb 100644 (file)
@@ -193,6 +193,12 @@ typedef struct surfmesh_s
 
        // vertex and index buffers for rendering
        r_meshbuffer_t *vertexmesh_vertexbuffer;
+
+       // dynamic mesh building support (Mod_Mesh_*)
+       int num_vertexhashsize; // always pow2 for simple masking
+       int *data_vertexhash; // hash table - wrapping buffer for storing index of similar vertex with -1 as terminator
+       int max_vertices; // preallocated size of data_vertex3f and friends (always >= num_vertices)
+       int max_triangles; // preallocated size of data_element3i
 }
 surfmesh_t;
 
@@ -736,6 +742,9 @@ typedef struct msurface_s
        int deprecatedq3num_bboxstride;
        // FIXME: collisionmarkframe should be kept in a separate array
        int deprecatedq3collisionmarkframe; // q3bsp // don't collide twice in one trace
+
+       // used by Mod_Mesh_Finalize when building sortedmodelsurfaces
+       qboolean included;
 }
 msurface_t;
 
@@ -1039,12 +1048,14 @@ typedef struct model_s
        float                   *data_baseboneposeinverse;
        // textures of this model
        int                             num_textures;
+       int                             max_textures; // preallocated for expansion (Mod_Mesh_*)
        int                             num_texturesperskin;
        texture_t               *data_textures;
        qboolean                wantnormals;
        qboolean                wanttangents;
        // surfaces of this model
        int                             num_surfaces;
+       int                             max_surfaces; // preallocated for expansion (Mod_Mesh_*)
        msurface_t              *data_surfaces;
        // optional lightmapinfo data for surface lightmap updates
        msurface_lightmapinfo_t *data_surfaces_lightmapinfo;
@@ -1160,6 +1171,8 @@ q3shaderinfo_t *Mod_LookupQ3Shader(const char *name);
 qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags);
 texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe);
 texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename);
+/// Sets up a material to render the provided skinframe.  See also R_SkinFrame_LoadInternalBGRA.
+void Mod_LoadCustomMaterial(texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe);
 
 extern cvar_t r_mipskins;
 extern cvar_t r_mipnormalmaps;
@@ -1233,6 +1246,16 @@ void R_Q1BSP_CompileShadowVolume(struct entity_render_s *ent, vec3_t relativelig
 void R_Q1BSP_DrawShadowVolume(struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
 void R_Q1BSP_DrawLight(struct entity_render_s *ent, int numsurfaces, const int *surfacelist, const unsigned char *trispvs);
 
+// dynamic mesh building (every frame) for debugging and other uses
+void Mod_Mesh_Create(dp_model_t *mod, const char *name);
+void Mod_Mesh_Destroy(dp_model_t *mod);
+void Mod_Mesh_Reset(dp_model_t *mod);
+texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name);
+msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex);
+int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a);
+void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2);
+void Mod_Mesh_Finalize(dp_model_t *mod);
+
 // Collision optimization using Bounding Interval Hierarchy
 void Mod_CollisionBIH_TracePoint(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask);
 void Mod_CollisionBIH_TraceLine(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask);