]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_shared.c
Refactored and improved Mod_ValidateElements so it also validates element3s and has...
[xonotic/darkplaces.git] / model_shared.c
index 9d7d449db9794438063afc51b963c7dba6e99a49..c4a716a72fc8c2b8d873e91573d3562f80857549 100644 (file)
@@ -816,21 +816,71 @@ void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtria
 }
 #endif
 
-void Mod_ValidateElements(int *elements, int numtriangles, int firstvertex, int numverts, const char *filename, int fileline)
+qboolean Mod_ValidateElements(int *element3i, unsigned short *element3s, int numtriangles, int firstvertex, int numvertices, const char *filename, int fileline)
 {
-       int i, warned = false, endvertex = firstvertex + numverts;
-       for (i = 0;i < numtriangles * 3;i++)
+       int first = firstvertex, last = first + numvertices - 1, numelements = numtriangles * 3;
+       int i;
+       int invalidintcount = 0, invalidintexample = 0;
+       int invalidshortcount = 0, invalidshortexample = 0;
+       int invalidmismatchcount = 0, invalidmismatchexample = 0;
+       if (element3i)
+       {
+               for (i = 0; i < numelements; i++)
+               {
+                       if (element3i[i] < first || element3i[i] > last)
+                       {
+                               invalidintcount++;
+                               invalidintexample = i;
+                       }
+               }
+       }
+       if (element3s)
        {
-               if (elements[i] < firstvertex || elements[i] >= endvertex)
+               for (i = 0; i < numelements; i++)
                {
-                       if (!warned)
+                       if (element3s[i] < first || element3s[i] > last)
                        {
-                               warned = true;
-                               Con_Printf("Mod_ValidateElements: out of bounds elements detected at %s:%d\n", filename, fileline);
+                               invalidintcount++;
+                               invalidintexample = i;
                        }
-                       elements[i] = firstvertex;
                }
        }
+       if (element3i && element3s)
+       {
+               for (i = 0; i < numelements; i++)
+               {
+                       if (element3s[i] != element3i[i])
+                       {
+                               invalidmismatchcount++;
+                               invalidmismatchexample = i;
+                       }
+               }
+       }
+       if (invalidintcount || invalidshortcount || invalidmismatchcount)
+       {
+               Con_Printf("Mod_ValidateElements(%i, %i, %i, %p, %p) called at %s:%d", numelements, first, last, element3i, element3s, filename, fileline);
+               Con_Printf(", %i elements are invalid in element3i (example: element3i[%i] == %i)", invalidintcount, invalidintexample, element3i ? element3i[invalidintexample] : 0);
+               Con_Printf(", %i elements are invalid in element3s (example: element3s[%i] == %i)", invalidshortcount, invalidshortexample, element3s ? element3s[invalidshortexample] : 0);
+               Con_Printf(", %i elements mismatch between element3i and element3s (example: element3s[%i] is %i and element3i[i] is %i)", invalidmismatchcount, invalidmismatchexample, element3i ? element3i[invalidmismatchexample] : 0, invalidmismatchexample, element3s ? element3s[invalidmismatchexample] : 0);
+               Con_Print(".  Please debug the engine code - these elements have been modified to not crash, but nothing more.\n");
+
+               // edit the elements to make them safer, as the driver will crash otherwise
+               if (element3i)
+                       for (i = 0; i < numelements; i++)
+                               if (element3i[i] < first || element3i[i] > last)
+                                       element3i[i] = first;
+               if (element3s)
+                       for (i = 0; i < numelements; i++)
+                               if (element3s[i] < first || element3s[i] > last)
+                                       element3s[i] = first;
+               if (element3i && element3s)
+                       for (i = 0; i < numelements; i++)
+                               if (element3s[i] != element3i[i])
+                                       element3s[i] = element3i[i];
+
+               return false;
+       }
+       return true;
 }
 
 // warning: this is an expensive function!
@@ -1214,6 +1264,9 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
        if (!mesh->numverts)
                return;
 
+       // make sure we don't crash inside the driver if something went wrong, as it's annoying to debug
+       Mod_ValidateElements(mesh->element3i, mesh->element3s, mesh->numtriangles, 0, mesh->numverts, __FILE__, __LINE__);
+
        // build r_vertexmesh_t array
        // (compressed interleaved array for D3D)
        if (!mesh->vertexmesh && mesh->texcoord2f && vid.useinterleavedarrays)
@@ -1234,11 +1287,11 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
 
        // upload short indices as a buffer
        if (mesh->element3s && !mesh->element3s_indexbuffer)
-               mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false, false, true);
+               mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), "shadowmesh", true, false, false, true);
 
        // upload int indices as a buffer
        if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
-               mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false, false, false);
+               mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), "shadowmesh", true, false, false, false);
 
        // vertex buffer is several arrays and we put them in the same buffer
        //
@@ -2446,7 +2499,7 @@ texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool,
        return shaderpass;
 }
 
-qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags)
+qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags, int defaultmaterialflags)
 {
        int texflagsmask, texflagsor;
        qboolean success = true;
@@ -2613,6 +2666,9 @@ nothing                GL_ZERO GL_ONE
                                materiallayer = rgbgenvertexlayer;
                                endofprelayers = rgbgenvertexlayer;
                                firstpostlayer = rgbgenvertexlayer + 1;
+                               // special case for rgbgen vertex if MATERIALFLAG_VERTEXCOLOR is expected on this material
+                               if (defaultmaterialflags & MATERIALFLAG_VERTEXCOLOR)
+                                       texture->basematerialflags |= MATERIALFLAG_VERTEXCOLOR;
                        }
                        else if (rgbgendiffuselayer >= 0)
                        {
@@ -2777,17 +2833,17 @@ nothing                GL_ZERO GL_ONE
                        Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", modelname, texture->name);
                if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
                {
-                       texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
+                       texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
                        texture->supercontents = SUPERCONTENTS_SOLID;
                }
                else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
                {
-                       texture->basematerialflags |= MATERIALFLAG_SKY;
+                       texture->basematerialflags = MATERIALFLAG_SKY;
                        texture->supercontents = SUPERCONTENTS_SKY;
                }
                else
                {
-                       texture->basematerialflags |= MATERIALFLAG_WALL;
+                       texture->basematerialflags = defaultmaterialflags;
                        texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
                }
                if(cls.state == ca_dedicated)
@@ -2797,9 +2853,10 @@ nothing                GL_ZERO GL_ONE
                }
                else
                {
-                       if (fallback)
+                       skinframe_t *skinframe = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false, fallback);
+                       if (skinframe)
                        {
-                               texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false, true));
+                               texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
                                if (texture->materialshaderpass->skinframes[0]->hasalpha)
                                        texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
                                if (texture->q2contents)
@@ -4614,7 +4671,7 @@ void Mod_Mesh_Reset(dp_model_t *mod)
        mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
 }
 
-texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int addmaterialflags)
+texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
 {
        int i;
        texture_t *t;
@@ -4631,8 +4688,7 @@ texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdra
                        mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
        }
        t = &mod->data_textures[mod->num_textures++];
-       Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags);
-       t->basematerialflags |= addmaterialflags;
+       Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags, defaultmaterialflags);
        switch (defaultdrawflags & DRAWFLAG_MASK)
        {
        case DRAWFLAG_ADDITIVE: