]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_shared.c
Also actually include the .enc file for the key.
[xonotic/darkplaces.git] / model_shared.c
index 55b4673ea351138c79d11f01c6998a9856e21831..e7d3228d13f8ed5e1fc377ccaf412ffaa1bea85c 100644 (file)
@@ -55,6 +55,7 @@ static modloader_t loader[] =
        {NULL, "BSP2", 4, Mod_BSP2_Load},
        {NULL, "2PSB", 4, Mod_2PSB_Load},
        {NULL, "IBSP", 4, Mod_IBSP_Load},
+       {NULL, "VBSP", 4, Mod_VBSP_Load},
        {NULL, "ZYMOTICMODEL", 13, Mod_ZYMOTICMODEL_Load},
        {NULL, "DARKPLACESMODEL", 16, Mod_DARKPLACESMODEL_Load},
        {NULL, "PSKMODEL", 9, Mod_PSKMODEL_Load},
@@ -517,10 +518,10 @@ model_t *Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk)
                // all models use memory, so allocate a memory pool
                mod->mempool = Mem_AllocPool(mod->name, 0, NULL);
 
-               // call the apropriate loader
+               // We need to have a reference to the base model in case we're parsing submodels
                loadmodel = mod;
 
-               // Try matching magic bytes.
+               // Call the appropriate loader. Try matching magic bytes.
                for (i = 0; loader[i].Load; i++)
                {
                        // Headerless formats can just load based on extension. Otherwise match the magic string.
@@ -540,6 +541,7 @@ model_t *Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk)
                                        Mem_Free(buf);
                                }
 
+                               Mod_SetDrawSkyAndWater(mod);
                                Mod_BuildVBOs();
                                break;
                        }
@@ -1197,9 +1199,9 @@ void Mod_CreateCollisionMesh(model_t *mod)
        // make a single combined collision mesh for physics engine use
        // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface
        numcollisionmeshtriangles = 0;
-       for (k = 0;k < mod->nummodelsurfaces;k++)
+       for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++)
        {
-               surface = mod->data_surfaces + mod->firstmodelsurface + k;
+               surface = mod->data_surfaces + k;
                if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
                {
                        usesinglecollisionmesh = true;
@@ -1215,9 +1217,9 @@ void Mod_CreateCollisionMesh(model_t *mod)
                Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
        else
        {
-               for (k = 0;k < mod->nummodelsurfaces;k++)
+               for (k = mod->submodelsurfaces_start; k < mod->submodelsurfaces_end; k++)
                {
-                       surface = mod->data_surfaces + mod->firstmodelsurface + k;
+                       surface = mod->data_surfaces + k;
                        if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
                                continue;
                        Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
@@ -2255,12 +2257,7 @@ texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool,
        for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
                shaderpass->tcmods[j] = layer->tcmods[j];
        for (j = 0; j < layer->numframes; j++)
-       {
-               for (int i = 0; layer->texturename[j][i]; i++)
-                       if(layer->texturename[j][i] == '\\')
-                               layer->texturename[j][i] = '/';
                shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false, true);
-       }
        return shaderpass;
 }
 
@@ -2881,41 +2878,80 @@ void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firs
                *lastvertexpointer = lastvertex;
 }
 
+void Mod_SetDrawSkyAndWater(model_t* mod)
+{
+       int j;
+       uint64_t basematerialflags = 0;
+       // by default assume there is no sky or water used in this model
+       mod->DrawSky = NULL;
+       mod->DrawAddWaterPlanes = NULL;
+       // combine all basematerialflags observed in the submodelsurfaces range, then check for special flags
+       for (j = mod->submodelsurfaces_start; j < mod->submodelsurfaces_end; j++)
+               if (mod->data_surfaces[j].texture)
+                       basematerialflags |= mod->data_surfaces[j].texture->basematerialflags;
+       if (basematerialflags & MATERIALFLAG_SKY)
+               mod->DrawSky = R_Mod_DrawSky;
+       if (basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+               mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
+}
+
+typedef struct Mod_MakeSortedSurfaces_qsortsurface_s
+{
+       int surfaceindex;
+       q3deffect_t* effect;
+       texture_t* texture;
+       rtexture_t* lightmaptexture;
+}
+Mod_MakeSortedSurfaces_qsortsurface_t;
+
+static int Mod_MakeSortedSurfaces_qsortfunc(const void *a, const void *b)
+{
+       const Mod_MakeSortedSurfaces_qsortsurface_t* l = (Mod_MakeSortedSurfaces_qsortsurface_t*)a;
+       const Mod_MakeSortedSurfaces_qsortsurface_t* r = (Mod_MakeSortedSurfaces_qsortsurface_t*)b;
+       if (l->effect < r->effect)
+               return -1;
+       if (l->effect > r->effect)
+               return 1;
+       if (l->texture < r->texture)
+               return -1;
+       if (l->texture > r->texture)
+               return 1;
+       if (l->lightmaptexture < r->lightmaptexture)
+               return -1;
+       if (l->lightmaptexture > r->lightmaptexture)
+               return 1;
+       if (l->surfaceindex < r->surfaceindex)
+               return -1;
+       if (l->surfaceindex > r->surfaceindex)
+               return 1;
+       return 0;
+}
+
 void Mod_MakeSortedSurfaces(model_t *mod)
 {
        // make an optimal set of texture-sorted batches to draw...
-       int j, t;
-       int *firstsurfacefortexture;
-       int *numsurfacesfortexture;
-       if (!mod->sortedmodelsurfaces)
-               mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
-       firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture));
-       numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture));
-       memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture));
-       for (j = 0;j < mod->nummodelsurfaces;j++)
-       {
-               const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
-               if(!surface->texture)
-                       continue;
-               t = (int)(surface->texture - mod->data_textures);
-               numsurfacesfortexture[t]++;
-       }
-       j = 0;
-       for (t = 0;t < mod->num_textures;t++)
-       {
-               firstsurfacefortexture[t] = j;
-               j += numsurfacesfortexture[t];
-       }
-       for (j = 0;j < mod->nummodelsurfaces;j++)
+       int j, k;
+       Mod_MakeSortedSurfaces_qsortsurface_t *info;
+
+       if(cls.state == ca_dedicated)
+               return;
+
+       info = (Mod_MakeSortedSurfaces_qsortsurface_t*)R_FrameData_Alloc(mod->num_surfaces * sizeof(*info));
+       if (!mod->modelsurfaces_sorted)
+               mod->modelsurfaces_sorted = (int *) Mem_Alloc(loadmodel->mempool, mod->num_surfaces * sizeof(*mod->modelsurfaces_sorted));
+       // the goal is to sort by submodel (can't change which submodel a surface belongs to), and then by effects and textures
+       for (j = 0; j < mod->num_surfaces; j++)
        {
-               const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
-               if (!surface->texture)
-                       continue;
-               t = (int)(surface->texture - mod->data_textures);
-               mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
+               info[j].surfaceindex = j;
+               info[j].effect = mod->data_surfaces[j].effect;
+               info[j].texture = mod->data_surfaces[j].texture;
+               info[j].lightmaptexture = mod->data_surfaces[j].lightmaptexture;
        }
-       Mem_Free(firstsurfacefortexture);
-       Mem_Free(numsurfacesfortexture);
+       for (k = 0; k < mod->brush.numsubmodels; k++)
+               if (mod->brush.submodels[k]->submodelsurfaces_end > mod->brush.submodels[k]->submodelsurfaces_start + 1)
+                       qsort(info + mod->brush.submodels[k]->submodelsurfaces_start, (size_t)mod->brush.submodels[k]->submodelsurfaces_end - mod->brush.submodels[k]->submodelsurfaces_start, sizeof(*info), Mod_MakeSortedSurfaces_qsortfunc);
+       for (j = 0; j < mod->num_surfaces; j++)
+               mod->modelsurfaces_sorted[j] = info[j].surfaceindex;
 }
 
 void Mod_BuildVBOs(void)
@@ -3068,9 +3104,9 @@ static void Mod_Decompile_OBJ(model_t *model, const char *filename, const char *
                if (l > 0)
                        outbufferpos += l;
                submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
-               for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
+               for (surfaceindex = submodel->submodelsurfaces_start;surfaceindex < submodel->submodelsurfaces_end;surfaceindex++)
                {
-                       surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
+                       surface = model->data_surfaces + surfaceindex;
                        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
                        if (l > 0)
                                outbufferpos += l;
@@ -3614,8 +3650,9 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const
        const int *element3i = model->surfmesh.data_element3i;
        const int *e;
        float v2[3][3];
-       for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
+       for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
        {
+               surface = model->data_surfaces + surfaceindex;
                if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
                        continue;
                if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
@@ -4491,7 +4528,7 @@ msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithpre
        {
                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));
+               mod->modelsurfaces_sorted = (int *)Mem_Realloc(mod->mempool, mod->modelsurfaces_sorted, mod->max_surfaces * sizeof(*mod->modelsurfaces_sorted));
        }
        surf = mod->data_surfaces + mod->num_surfaces;
        mod->num_surfaces++;
@@ -4506,31 +4543,10 @@ msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithpre
        return surf;
 }
 
-static void Mod_Mesh_RebuildHashTable(model_t *mod, msurface_t *surf)
+int Mod_Mesh_IndexForVertex(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;
-
-       // 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;
-       }
-}
-
-void Mod_Mesh_CheckResize_Vertex(model_t *mod, msurface_t *surf)
-{
-       surfmesh_t *mesh = &mod->surfmesh;
        if (mesh->max_vertices == mesh->num_vertices)
        {
                mesh->max_vertices = max(mesh->num_vertices * 2, 256);
@@ -4541,15 +4557,36 @@ void Mod_Mesh_CheckResize_Vertex(model_t *mod, msurface_t *surf)
                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]));
-               Mod_Mesh_RebuildHashTable(mod, surf);
+               // 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;
        }
-}
-
-int Mod_Mesh_AddVertex(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 vnum;
-       surfmesh_t *mesh = &mod->surfmesh;
-
        // add the new vertex
        vnum = mesh->num_vertices++;
        if (surf->num_vertices > 0)
@@ -4567,6 +4604,7 @@ int Mod_Mesh_AddVertex(model_t *mod, msurface_t *surf, float x, float y, float 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;
@@ -4584,32 +4622,6 @@ int Mod_Mesh_AddVertex(model_t *mod, msurface_t *surf, float x, float y, float z
        return vnum;
 }
 
-int Mod_Mesh_IndexForVertex(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;
-
-       Mod_Mesh_CheckResize_Vertex(mod, surf);
-
-       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;
-       }
-       vnum = Mod_Mesh_AddVertex(mod, surf, x, y, z, nx, ny, nz, s, t, u, v, r, g, b, a);
-       mesh->data_vertexhash[h] = vnum;
-       return vnum;
-}
-
 void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2)
 {
        surfmesh_t *mesh = &mod->surfmesh;
@@ -4633,29 +4645,26 @@ static void Mod_Mesh_MakeSortedSurfaces(model_t *mod)
 {
        int i, j;
        texture_t *tex;
-       msurface_t *surf, *surf2;
+       unsigned char* included = (unsigned char *)R_FrameData_Alloc(mod->num_surfaces * sizeof(unsigned char));
 
        // 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;
+       mod->submodelsurfaces_start = 0;
+       mod->submodelsurfaces_end = 0;
        for (i = 0; i < mod->num_surfaces; i++)
-               mod->data_surfaces[i].included = false;
+               included[i] = 0;
        for (i = 0; i < mod->num_surfaces; i++)
        {
-               surf = mod->data_surfaces + i;
-               if (surf->included)
+               if (included[i])
                        continue;
-               tex = surf->texture;
+               tex = mod->data_surfaces[i].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)
+                       if (!included[j] && mod->data_surfaces[j].texture == tex)
                        {
-                               surf2->included = true;
-                               mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
+                               included[j] = 1;
+                               mod->modelsurfaces_sorted[mod->submodelsurfaces_end++] = j;
                        }
                }
        }