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)
// 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;
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);
}
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);
// 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.
// 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
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]);
// 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);
// 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);
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))
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))
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
{
// 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)
{
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;
}
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;
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;
do
{
if (words < 10)
- strlcpy(word[words++], com_token, sizeof (word[0]));
+ dp_strlcpy(word[words++], com_token, sizeof (word[0]));
else
wordsoverflow = true;
}
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]);
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);
void Mod_SetDrawSkyAndWater(model_t* mod)
{
- size_t j;
+ int j;
uint64_t basematerialflags = 0;
// by default assume there is no sky or water used in this model
mod->DrawSky = NULL;
{
// 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
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)
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;
// 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;
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);
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)
{
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;
}
// 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);
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;
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
}
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);
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)
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;
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;
{
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;
}
}