X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_shared.c;h=bcf683e33f5a6677f3ca4777d9fb814fd68b8dd7;hp=15e9fd9895c6e7e5e0fa54083b39587c3dccd9d3;hb=HEAD;hpb=b0eed6836380693b544f871309e8530ae90dc526 diff --git a/model_shared.c b/model_shared.c index 15e9fd98..d6cea915 100644 --- a/model_shared.c +++ b/model_shared.c @@ -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}, @@ -216,7 +217,7 @@ void Mod_UnloadModel (model_t *mod) if (developer_loading.integer) Con_Printf("unloading model %s\n", mod->name); - strlcpy(name, mod->name, sizeof(name)); + dp_strlcpy(name, mod->name, sizeof(name)); parentmodel = mod->brush.parentmodel; used = mod->used; if (mod->mempool) @@ -245,7 +246,7 @@ void Mod_UnloadModel (model_t *mod) // clear the struct to make it available memset(mod, 0, sizeof(model_t)); // restore the fields we want to preserve - strlcpy(mod->name, name, sizeof(mod->name)); + dp_strlcpy(mod->name, name, sizeof(mod->name)); mod->brush.parentmodel = parentmodel; mod->used = used; mod->loaded = false; @@ -314,7 +315,7 @@ static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_pars name[0] = 0; if (bufptr && strcmp(com_token, "\n")) { - strlcpy(name, com_token, sizeof(name)); + dp_strlcpy(name, com_token, sizeof(name)); COM_ParseToken_Simple(&bufptr, true, false, true); } @@ -337,7 +338,7 @@ static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int model_t *mod = (model_t *) pass; animscene_t *anim = &mod->animscenes[i]; if(name) - strlcpy(anim->name, name, sizeof(anim[i].name)); + dp_strlcpy(anim->name, name, sizeof(anim[i].name)); else dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i); anim->firstframe = bound(0, start, mod->num_poses - 1); @@ -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; } @@ -616,7 +618,7 @@ model_t *Mod_FindName(const char *name, const char *parentname) // no match found, create a new one mod = (model_t *) Mem_ExpandableArray_AllocRecord(&models); - strlcpy(mod->name, name, sizeof(mod->name)); + dp_strlcpy(mod->name, name, sizeof(mod->name)); if (parentname[0]) mod->brush.parentmodel = Mod_FindName(parentname, NULL); else @@ -1042,6 +1044,12 @@ void Mod_ShadowMesh_AddMesh(shadowmesh_t *mesh, const float *vertex3f, int numtr for (i = 0;i < numtris;i++) { + if ((mesh->numtriangles * 3 + 2) * sizeof(int) + 1 >= ((memheader_t *)((unsigned char *)mesh->element3i - sizeof(memheader_t)))->size) + { + // FIXME: we didn't allocate enough space for all the tris, see R_Mod_CompileShadowMap + Con_Print(CON_WARN "Mod_ShadowMesh_AddMesh: insufficient memory allocated!\n"); + return; + } mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 0]); mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 1]); mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 2]); @@ -1510,7 +1518,7 @@ void Mod_LoadQ3Shaders(void) // name j = (int)strlen(com_token)+1; custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j); - strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1); + dp_strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1); // value if (COM_ParseToken_QuakeC(&text, false)) custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0); @@ -1572,7 +1580,7 @@ void Mod_LoadQ3Shaders(void) // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS // JUST GREP FOR "specularscalemod = 1". - strlcpy(shader.name, com_token, sizeof(shader.name)); + dp_strlcpy(shader.name, com_token, sizeof(shader.name)); if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) { Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token); @@ -1615,7 +1623,7 @@ void Mod_LoadQ3Shaders(void) if(j == 0 && !strncasecmp(com_token, "dp_", 3)) dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]); else - strlcpy(parameter[j], com_token, sizeof(parameter[j])); + dp_strlcpy(parameter[j], com_token, sizeof(parameter[j])); numparameters = j + 1; } if (!COM_ParseToken_QuakeC(&text, true)) @@ -1870,7 +1878,7 @@ void Mod_LoadQ3Shaders(void) if(j == 0 && !strncasecmp(com_token, "dp_", 3)) dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]); else - strlcpy(parameter[j], com_token, sizeof(parameter[j])); + dp_strlcpy(parameter[j], com_token, sizeof(parameter[j])); numparameters = j + 1; } if (!COM_ParseToken_QuakeC(&text, true)) @@ -1980,7 +1988,7 @@ void Mod_LoadQ3Shaders(void) else if (!strcasecmp(parameter[0], "dpnortlight")) shader.dpnortlight = true; else if (!strcasecmp(parameter[0], "dpreflectcube")) - strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube)); + dp_strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube)); else if (!strcasecmp(parameter[0], "dpmeshcollisions")) shader.dpmeshcollisions = true; // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used @@ -2039,14 +2047,14 @@ void Mod_LoadQ3Shaders(void) { // some q3 skies don't have the sky parm set shader.surfaceparms |= Q3SURFACEPARM_SKY; - strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname)); + dp_strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname)); } else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2) { // some q3 skies don't have the sky parm set shader.surfaceparms |= Q3SURFACEPARM_SKY; if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-")) - strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname)); + dp_strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname)); } else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2) { @@ -2255,12 +2263,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; } @@ -2271,7 +2274,7 @@ qbool Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, tex shader_t *shader; if (!name) name = ""; - strlcpy(texture->name, name, sizeof(texture->name)); + dp_strlcpy(texture->name, name, sizeof(texture->name)); texture->basealpha = 1.0f; shader = name[0] ? Mod_LookupQ3Shader(name) : NULL; @@ -2652,7 +2655,7 @@ void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char * if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY))) Con_DPrintf("^1Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", texture->name); - strlcpy(texture->name, name, sizeof(texture->name)); + dp_strlcpy(texture->name, name, sizeof(texture->name)); texture->basealpha = 1.0f; texture->basematerialflags = materialflags; texture->supercontents = supercontents; @@ -2752,7 +2755,7 @@ tag_torso, do { if (words < 10) - strlcpy(word[words++], com_token, sizeof (word[0])); + dp_strlcpy(word[words++], com_token, sizeof (word[0])); else wordsoverflow = true; } @@ -2772,8 +2775,8 @@ tag_torso, skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t)); skinfileitem->next = skinfile->items; skinfile->items = skinfileitem; - strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name)); - strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement)); + dp_strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name)); + dp_strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement)); } else Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: wrong number of parameters to command \"%s\", see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line, word[0]); @@ -2791,8 +2794,8 @@ tag_torso, skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t)); skinfileitem->next = skinfile->items; skinfile->items = skinfileitem; - strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name)); - strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement)); + dp_strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name)); + dp_strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement)); } else Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: does not look like tag or mesh specification, or replace command, see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line); @@ -2881,9 +2884,25 @@ 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 submodel; int surfaceindex; q3deffect_t* effect; texture_t* texture; @@ -2895,10 +2914,6 @@ 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->submodel < r->submodel) - return -1; - if (l->submodel > r->submodel) - return 1; if (l->effect < r->effect) return -1; if (l->effect > r->effect) @@ -2922,24 +2937,28 @@ void Mod_MakeSortedSurfaces(model_t *mod) { // make an optimal set of texture-sorted batches to draw... int j, k; - Mod_MakeSortedSurfaces_qsortsurface_t *info = (Mod_MakeSortedSurfaces_qsortsurface_t*)R_FrameData_Alloc(mod->num_surfaces * sizeof(*info)); + Mod_MakeSortedSurfaces_qsortsurface_t *info; + + if(cls.state == ca_dedicated) + return; + + info = (Mod_MakeSortedSurfaces_qsortsurface_t*)Mem_Alloc(loadmodel->mempool, 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++) { - info[j].submodel = 0; 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; } for (k = 0; k < mod->brush.numsubmodels; k++) - for (j = mod->brush.submodels[k]->submodelsurfaces_start; j < mod->brush.submodels[k]->submodelsurfaces_end; j++) - info[j].submodel = k; - qsort(info, mod->num_surfaces, sizeof(*info), Mod_MakeSortedSurfaces_qsortfunc); + 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; + Mem_Free(info); } void Mod_BuildVBOs(void) @@ -3045,7 +3064,7 @@ static void Mod_Decompile_OBJ(model_t *model, const char *filename, const char * if (textureindex >= maxtextures) continue; // just a precaution textureindex = counttextures++; - strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH); + dp_strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH); if (outbufferpos >= outbuffermax >> 1) { outbuffermax *= 2; @@ -3190,7 +3209,7 @@ static void Mod_Decompile_SMD(model_t *model, const char *filename, int firstpos // strangely the smd angles are for a transposed matrix, so we // have to generate a transposed matrix, then convert that... Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex)); - Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]); + Matrix4x4_ToArray12FloatGL(&posematrix, mtest); AnglesFromVectors(angles, mtest[0], mtest[2], false); if (angles[0] >= 180) angles[0] -= 360; if (angles[1] >= 180) angles[1] -= 360; @@ -3320,7 +3339,7 @@ static void Mod_Decompile_f(cmd_state_t *cmd) return; } - strlcpy(inname, Cmd_Argv(cmd, 1), sizeof(inname)); + dp_strlcpy(inname, Cmd_Argv(cmd, 1), sizeof(inname)); FS_StripExtension(inname, basename, sizeof(basename)); mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL); @@ -3361,7 +3380,7 @@ static void Mod_Decompile_f(cmd_state_t *cmd) if (l > 0) dpmtextsize += l; for (i = 0;i < mod->numframes;i = j) { - strlcpy(animname, mod->animscenes[i].name, sizeof(animname)); + dp_strlcpy(animname, mod->animscenes[i].name, sizeof(animname)); first = mod->animscenes[i].firstframe; if (mod->animscenes[i].framecount > 1) { @@ -3382,7 +3401,7 @@ static void Mod_Decompile_f(cmd_state_t *cmd) count = mod->num_poses - first; for (j = i + 1;j < mod->numframes;j++) { - strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2)); + dp_strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2)); for (l = 0, k = (int)strlen(animname2);animname2[l];l++) if(animname2[l] < '0' || animname2[l] > '9') k = l + 1; @@ -3397,7 +3416,7 @@ static void Mod_Decompile_f(cmd_state_t *cmd) } // if it's only one frame, use the original frame name if (j == i + 1) - strlcpy(animname, mod->animscenes[i].name, sizeof(animname)); + dp_strlcpy(animname, mod->animscenes[i].name, sizeof(animname)); } dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname); @@ -4424,7 +4443,7 @@ static void Mod_GenerateLightmaps_f(cmd_state_t *cmd) void Mod_Mesh_Create(model_t *mod, const char *name) { memset(mod, 0, sizeof(*mod)); - strlcpy(mod->name, name, sizeof(mod->name)); + dp_strlcpy(mod->name, name, sizeof(mod->name)); mod->mempool = Mem_AllocPool(name, 0, NULL); mod->texturepool = R_AllocTexturePool(); mod->Draw = R_Mod_Draw; @@ -4448,7 +4467,8 @@ void Mod_Mesh_Reset(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)); + if (mod->surfmesh.data_vertexhash) // UBSan: memset arg 1 isn't allowed to be null, but sometimes this is NULL. + 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 } @@ -4531,31 +4551,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); @@ -4566,15 +4565,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) @@ -4592,6 +4612,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; @@ -4609,32 +4630,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; @@ -4658,25 +4653,24 @@ static void Mod_Mesh_MakeSortedSurfaces(model_t *mod) { int i, j; texture_t *tex; - 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->submodelsurfaces_start = 0; mod->submodelsurfaces_end = 0; for (i = 0; i < mod->num_surfaces; i++) - included[i] = 0; + mod->data_surfaces[i].included = false; for (i = 0; i < mod->num_surfaces; i++) { - if (included[i]) + if (mod->data_surfaces[i].included) continue; tex = mod->data_surfaces[i].texture; // j = i is intentional for (j = i; j < mod->num_surfaces; j++) { - if (!included[j] && mod->data_surfaces[j].texture == tex) + if (!mod->data_surfaces[j].included && mod->data_surfaces[j].texture == tex) { - included[j] = 1; + mod->data_surfaces[j].included = 1; mod->modelsurfaces_sorted[mod->submodelsurfaces_end++] = j; } }