X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_shared.c;h=c4d89707556af87a3413c82318e1d0e7d757f498;hp=4c66d78e3fa422d6fa82fe56c14169f34bcd9319;hb=HEAD;hpb=f13419f00e3f8335e9a25498560a433597f28f50 diff --git a/model_shared.c b/model_shared.c index 4c66d78e..adf8a867 100644 --- a/model_shared.c +++ b/model_shared.c @@ -39,7 +39,7 @@ cvar_t mod_generatelightmaps_lightmapradius = {CF_CLIENT | CF_ARCHIVE, "mod_gene cvar_t mod_generatelightmaps_vertexradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"}; cvar_t mod_generatelightmaps_gridradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"}; -dp_model_t *loadmodel; +model_t *loadmodel; // Supported model formats static modloader_t loader[] = @@ -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}, @@ -85,16 +86,16 @@ static void mod_start(void) { int i, count; int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; + model_t *mod; SCR_PushLoadingScreen("Loading models", 1.0); count = 0; for (i = 0;i < nummodels;i++) - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') if (mod->used) ++count; for (i = 0;i < nummodels;i++) - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') if (mod->used) { SCR_PushLoadingScreen(mod->name, 1.0 / count); @@ -108,10 +109,10 @@ static void mod_shutdown(void) { int i; int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; + model_t *mod; for (i = 0;i < nummodels;i++) - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool)) + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool)) Mod_UnloadModel(mod); Mod_FreeQ3Shaders(); @@ -123,11 +124,11 @@ static void mod_newmap(void) msurface_t *surface; int i, j, k, l, surfacenum, ssize, tsize; int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; + model_t *mod; for (i = 0;i < nummodels;i++) { - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool) + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool) { for (j = 0;j < mod->num_textures && mod->data_textures;j++) { @@ -149,7 +150,7 @@ static void mod_newmap(void) for (i = 0;i < nummodels;i++) { - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces) + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces) { for (surfacenum = 0, surface = mod->data_surfaces;surfacenum < mod->num_surfaces;surfacenum++, surface++) { @@ -177,7 +178,7 @@ static void Mod_GenerateLightmaps_f(cmd_state_t *cmd); void Mod_Init (void) { mod_mempool = Mem_AllocPool("modelinfo", 0, NULL); - Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(dp_model_t), 16); + Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(model_t), 16); Mod_BrushInit(); Mod_AliasInit(); @@ -207,16 +208,16 @@ void Mod_RenderInit(void) R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap, NULL, NULL); } -void Mod_UnloadModel (dp_model_t *mod) +void Mod_UnloadModel (model_t *mod) { char name[MAX_QPATH]; qbool used; - dp_model_t *parentmodel; + model_t *parentmodel; 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) @@ -243,9 +244,9 @@ void Mod_UnloadModel (dp_model_t *mod) R_FreeTexturePool(&mod->texturepool); Mem_FreePool(&mod->mempool); // clear the struct to make it available - memset(mod, 0, sizeof(dp_model_t)); + 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); } @@ -334,10 +335,10 @@ static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_pars static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qbool loop, const char *name, void *pass) { - dp_model_t *mod = (dp_model_t *) pass; + 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); @@ -347,7 +348,7 @@ static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop); } -static void Mod_FrameGroupify(dp_model_t *mod, const char *buf) +static void Mod_FrameGroupify(model_t *mod, const char *buf) { unsigned int cnt; @@ -368,7 +369,7 @@ static void Mod_FrameGroupify(dp_model_t *mod, const char *buf) Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod); } -static void Mod_FindPotentialDeforms(dp_model_t *mod) +static void Mod_FindPotentialDeforms(model_t *mod) { int i, j; texture_t *texture; @@ -402,7 +403,7 @@ Mod_LoadModel Loads a model ================== */ -dp_model_t *Mod_LoadModel(dp_model_t *mod, qbool crash, qbool checkdisk) +model_t *Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk) { unsigned int crc; void *buf; @@ -517,10 +518,10 @@ dp_model_t *Mod_LoadModel(dp_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 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qbool crash, qbool checkdisk) Mem_Free(buf); } + Mod_SetDrawSkyAndWater(mod); Mod_BuildVBOs(); break; } @@ -563,9 +565,9 @@ void Mod_ClearUsed(void) { int i; int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; + model_t *mod; for (i = 0;i < nummodels;i++) - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0]) + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0]) mod->used = false; } @@ -573,10 +575,10 @@ void Mod_PurgeUnused(void) { int i; int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; + model_t *mod; for (i = 0;i < nummodels;i++) { - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used) + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used) { Mod_UnloadModel(mod); Mem_ExpandableArray_FreeRecord(&models, mod); @@ -590,11 +592,11 @@ Mod_FindName ================== */ -dp_model_t *Mod_FindName(const char *name, const char *parentname) +model_t *Mod_FindName(const char *name, const char *parentname) { int i; int nummodels; - dp_model_t *mod; + model_t *mod; if (!parentname) parentname = ""; @@ -607,7 +609,7 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname) // search the currently loaded models for (i = 0;i < nummodels;i++) { - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name) && ((!mod->brush.parentmodel && !parentname[0]) || (mod->brush.parentmodel && parentname[0] && !strcmp(mod->brush.parentmodel->name, parentname)))) + if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name) && ((!mod->brush.parentmodel && !parentname[0]) || (mod->brush.parentmodel && parentname[0] && !strcmp(mod->brush.parentmodel->name, parentname)))) { mod->used = true; return mod; @@ -615,8 +617,8 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname) } // no match found, create a new one - mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models); - strlcpy(mod->name, name, sizeof(mod->name)); + mod = (model_t *) Mem_ExpandableArray_AllocRecord(&models); + dp_strlcpy(mod->name, name, sizeof(mod->name)); if (parentname[0]) mod->brush.parentmodel = Mod_FindName(parentname, NULL); else @@ -626,6 +628,8 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname) return mod; } +extern qbool vid_opened; + /* ================== Mod_ForName @@ -633,9 +637,14 @@ Mod_ForName Loads in a model for the given name ================== */ -dp_model_t *Mod_ForName(const char *name, qbool crash, qbool checkdisk, const char *parentname) +model_t *Mod_ForName(const char *name, qbool crash, qbool checkdisk, const char *parentname) { - dp_model_t *model; + model_t *model; + + // FIXME: So we don't crash if a server is started early. + if(!vid_opened) + CL_StartVideo(); + model = Mod_FindName(name, parentname); if (!model->loaded || checkdisk) Mod_LoadModel(model, crash, checkdisk); @@ -653,15 +662,15 @@ void Mod_Reload(void) { int i, count; int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; + model_t *mod; SCR_PushLoadingScreen("Reloading models", 1.0); count = 0; for (i = 0;i < nummodels;i++) - if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used) + if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used) ++count; for (i = 0;i < nummodels;i++) - if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used) + if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used) { SCR_PushLoadingScreen(mod->name, 1.0 / count); Mod_LoadModel(mod, true, true); @@ -684,12 +693,12 @@ static void Mod_Print_f(cmd_state_t *cmd) { int i; int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; + model_t *mod; Con_Print("Loaded models:\n"); for (i = 0;i < nummodels;i++) { - if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') + if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') { if (mod->brush.numsubmodels) Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels); @@ -1035,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 >= Mem_Size(mesh->element3i)) + { + // 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]); @@ -1178,7 +1193,7 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh) Mem_Free(mesh); } -void Mod_CreateCollisionMesh(dp_model_t *mod) +void Mod_CreateCollisionMesh(model_t *mod) { int k, numcollisionmeshtriangles; qbool usesinglecollisionmesh = false; @@ -1190,9 +1205,9 @@ void Mod_CreateCollisionMesh(dp_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; @@ -1208,9 +1223,9 @@ void Mod_CreateCollisionMesh(dp_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)); @@ -1284,7 +1299,7 @@ static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, #endif #if 0 -void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y) +void Mod_Terrain_SurfaceRecurseChunk(model_t *model, int stepsize, int x, int y) { float mins[3]; float maxs[3]; @@ -1355,7 +1370,7 @@ void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int // TODO: emit skirt vertices } -void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model) +void Mod_Terrain_UpdateSurfacesForViewOrigin(model_t *model) { for (y = 0;y < model->terrain.size[1];y += model->terrain. Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y); @@ -1503,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); @@ -1565,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); @@ -1608,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)) @@ -1863,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)) @@ -1973,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 @@ -2032,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) { @@ -2248,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; } @@ -2264,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; @@ -2645,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; @@ -2745,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; } @@ -2765,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]); @@ -2784,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); @@ -2874,41 +2884,81 @@ void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firs *lastvertexpointer = lastvertex; } -void Mod_MakeSortedSurfaces(dp_model_t *mod) +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*)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++) { - 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; + Mem_Free(info); } void Mod_BuildVBOs(void) @@ -2980,7 +3030,7 @@ void Mod_BuildVBOs(void) } extern cvar_t mod_obj_orientation; -static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename) +static void Mod_Decompile_OBJ(model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename) { int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0; int a, b, c; @@ -2994,7 +3044,7 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha const msurface_t *surface; const int maxtextures = 256; char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH); - dp_model_t *submodel; + model_t *submodel; // construct the mtllib file l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename); @@ -3014,7 +3064,7 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha 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; @@ -3061,9 +3111,9 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha 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; @@ -3101,7 +3151,7 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures); } -static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qbool writetriangles) +static void Mod_Decompile_SMD(model_t *model, const char *filename, int firstpose, int numposes, qbool writetriangles) { int countnodes = 0, counttriangles = 0, countframes = 0; int surfaceindex; @@ -3159,7 +3209,7 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first // 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; @@ -3268,7 +3318,7 @@ decompiles a model to editable files static void Mod_Decompile_f(cmd_state_t *cmd) { int i, j, k, l, first, count; - dp_model_t *mod; + model_t *mod; char inname[MAX_QPATH]; char outname[MAX_QPATH]; char mtlname[MAX_QPATH]; @@ -3289,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); @@ -3330,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) { @@ -3351,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; @@ -3366,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); @@ -3529,7 +3579,7 @@ static lightmaplight_t *mod_generatelightmaps_lightinfo; extern cvar_t r_shadow_lightattenuationdividebias; extern cvar_t r_shadow_lightattenuationlinearscale; -static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir) +static void Mod_GenerateLightmaps_LightPoint(model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir) { int i; int index; @@ -3598,7 +3648,7 @@ static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos VectorCopy(dir, lightdir); } -static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs) +static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs) { int surfaceindex; int triangleindex; @@ -3607,8 +3657,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) @@ -3623,7 +3674,7 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const } } -static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo) +static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model_t *model, lightmaplight_t *lightinfo) { int maxnodes = 1<<14; svbsp_node_t *nodes; @@ -3662,7 +3713,7 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, l Mem_Free(nodes); } -static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model) +static void Mod_GenerateLightmaps_CreateLights(model_t *model) { int index; int result; @@ -3701,7 +3752,7 @@ static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model) } } -static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model) +static void Mod_GenerateLightmaps_DestroyLights(model_t *model) { int i; if (mod_generatelightmaps_lightinfo) @@ -3864,7 +3915,7 @@ static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s else {s->diffusepitch = (unsigned char)(acos(dir[2]) * (127.5f/M_PI));s->diffuseyaw = (unsigned char)(atan2(dir[1], dir[0]) * (127.5f/M_PI));} } -static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model) +static void Mod_GenerateLightmaps_InitSampleOffsets(model_t *model) { float radius[3]; float temp[3]; @@ -3886,7 +3937,7 @@ static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model) } } -static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model) +static void Mod_GenerateLightmaps_DestroyLightmaps(model_t *model) { msurface_t *surface; int surfaceindex; @@ -3915,7 +3966,7 @@ static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model) } } -static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model) +static void Mod_GenerateLightmaps_UnweldTriangles(model_t *model) { msurface_t *surface; int surfaceindex; @@ -4018,7 +4069,7 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model) model->brush.submodels[i]->surfmesh = model->surfmesh; } -static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model) +static void Mod_GenerateLightmaps_CreateTriangleInformation(model_t *model) { msurface_t *surface; int surfaceindex; @@ -4060,7 +4111,7 @@ static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model) } } -static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model) +static void Mod_GenerateLightmaps_DestroyTriangleInformation(model_t *model) { if (mod_generatelightmaps_lightmaptriangles) Mem_Free(mod_generatelightmaps_lightmaptriangles); @@ -4069,7 +4120,7 @@ static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model) float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; -static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) +static void Mod_GenerateLightmaps_CreateLightmaps(model_t *model) { msurface_t *surface; int surfaceindex; @@ -4323,14 +4374,14 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) } } -static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model) +static void Mod_GenerateLightmaps_UpdateVertexColors(model_t *model) { int i; for (i = 0;i < model->surfmesh.num_vertices;i++) Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i); } -static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model) +static void Mod_GenerateLightmaps_UpdateLightGrid(model_t *model) { int x; int y; @@ -4353,10 +4404,10 @@ static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model) } extern cvar_t mod_q3bsp_nolightmaps; -static void Mod_GenerateLightmaps(dp_model_t *model) +static void Mod_GenerateLightmaps(model_t *model) { //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t)); - dp_model_t *oldloadmodel = loadmodel; + model_t *oldloadmodel = loadmodel; loadmodel = model; Mod_GenerateLightmaps_InitSampleOffsets(model); @@ -4389,10 +4440,10 @@ static void Mod_GenerateLightmaps_f(cmd_state_t *cmd) Mod_GenerateLightmaps(cl.worldmodel); } -void Mod_Mesh_Create(dp_model_t *mod, const char *name) +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; @@ -4404,24 +4455,25 @@ void Mod_Mesh_Create(dp_model_t *mod, const char *name) mod->DrawLight = R_Mod_DrawLight; } -void Mod_Mesh_Destroy(dp_model_t *mod) +void Mod_Mesh_Destroy(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) +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 } -texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags) +texture_t *Mod_Mesh_GetTexture(model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags) { int i; texture_t *t; @@ -4473,7 +4525,7 @@ texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdra return t; } -msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qbool batchwithprevioussurface) +msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithprevioussurface) { msurface_t *surf; // batch if possible; primarily useful for UI rendering where bounding boxes don't matter @@ -4484,7 +4536,7 @@ msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qbool batchwith { 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++; @@ -4499,7 +4551,7 @@ msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qbool batchwith return surf; } -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 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; @@ -4578,7 +4630,7 @@ int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, return vnum; } -void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2) +void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2) { surfmesh_t *mesh = &mod->surfmesh; if (mesh->max_triangles == mesh->num_triangles) @@ -4597,39 +4649,35 @@ void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int surf->num_triangles++; } -static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod) +static void Mod_Mesh_MakeSortedSurfaces(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; + mod->submodelsurfaces_start = 0; + mod->submodelsurfaces_end = 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) + if (mod->data_surfaces[i].included) 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 (!mod->data_surfaces[j].included && mod->data_surfaces[j].texture == tex) { - surf2->included = true; - mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j; + mod->data_surfaces[j].included = 1; + mod->modelsurfaces_sorted[mod->submodelsurfaces_end++] = j; } } } } -static void Mod_Mesh_ComputeBounds(dp_model_t *mod) +static void Mod_Mesh_ComputeBounds(model_t *mod) { int i; vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius; @@ -4685,7 +4733,7 @@ static void Mod_Mesh_ComputeBounds(dp_model_t *mod) } } -void Mod_Mesh_Validate(dp_model_t *mod) +void Mod_Mesh_Validate(model_t *mod) { int i; qbool warned = false; @@ -4709,7 +4757,7 @@ void Mod_Mesh_Validate(dp_model_t *mod) } } -static void Mod_Mesh_UploadDynamicBuffers(dp_model_t *mod) +static void Mod_Mesh_UploadDynamicBuffers(model_t *mod) { mod->surfmesh.data_element3s_indexbuffer = mod->surfmesh.data_element3s ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(short[3]), mod->surfmesh.data_element3s, R_BUFFERDATA_INDEX16, &mod->surfmesh.data_element3s_bufferoffset) : NULL; mod->surfmesh.data_element3i_indexbuffer = mod->surfmesh.data_element3i ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(int[3]), mod->surfmesh.data_element3i, R_BUFFERDATA_INDEX32, &mod->surfmesh.data_element3i_bufferoffset) : NULL; @@ -4724,7 +4772,7 @@ static void Mod_Mesh_UploadDynamicBuffers(dp_model_t *mod) mod->surfmesh.data_skeletalweight4ub_vertexbuffer = mod->surfmesh.data_skeletalweight4ub ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(unsigned char[4]), mod->surfmesh.data_skeletalweight4ub, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_skeletalweight4ub_bufferoffset) : NULL; } -void Mod_Mesh_Finalize(dp_model_t *mod) +void Mod_Mesh_Finalize(model_t *mod) { if (gl_paranoid.integer) Mod_Mesh_Validate(mod);