X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_shared.c;h=8e707337afe4fe8c9b8d4273ddae4247272112c5;hp=55b4673ea351138c79d11f01c6998a9856e21831;hb=45e243af848a57db51089ede24ff46d4f05d3047;hpb=5ad6c0e8577478422c10d7ae79fb61b88ac5ae85 diff --git a/model_shared.c b/model_shared.c index 55b4673e..8e707337 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}, @@ -517,10 +518,10 @@ model_t *Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk) // all models use memory, so allocate a memory pool mod->mempool = Mem_AllocPool(mod->name, 0, NULL); - // call the apropriate loader + // We need to have a reference to the base model in case we're parsing submodels loadmodel = mod; - // Try matching magic bytes. + // Call the appropriate loader. Try matching magic bytes. for (i = 0; loader[i].Load; i++) { // Headerless formats can just load based on extension. Otherwise match the magic string. @@ -540,6 +541,7 @@ model_t *Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk) Mem_Free(buf); } + Mod_SetDrawSkyAndWater(mod); Mod_BuildVBOs(); break; } @@ -1197,9 +1199,9 @@ void Mod_CreateCollisionMesh(model_t *mod) // make a single combined collision mesh for physics engine use // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface numcollisionmeshtriangles = 0; - for (k = 0;k < mod->nummodelsurfaces;k++) + for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++) { - surface = mod->data_surfaces + mod->firstmodelsurface + k; + surface = mod->data_surfaces + k; if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh { usesinglecollisionmesh = true; @@ -1215,9 +1217,9 @@ void Mod_CreateCollisionMesh(model_t *mod) Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); else { - for (k = 0;k < mod->nummodelsurfaces;k++) + for (k = mod->submodelsurfaces_start; k < mod->submodelsurfaces_end; k++) { - surface = mod->data_surfaces + mod->firstmodelsurface + k; + surface = mod->data_surfaces + k; if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID)) continue; Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); @@ -2255,12 +2257,7 @@ texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++) shaderpass->tcmods[j] = layer->tcmods[j]; for (j = 0; j < layer->numframes; j++) - { - for (int i = 0; layer->texturename[j][i]; i++) - if(layer->texturename[j][i] == '\\') - layer->texturename[j][i] = '/'; shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false, true); - } return shaderpass; } @@ -2881,41 +2878,81 @@ void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firs *lastvertexpointer = lastvertex; } +void Mod_SetDrawSkyAndWater(model_t* mod) +{ + int j; + uint64_t basematerialflags = 0; + // by default assume there is no sky or water used in this model + mod->DrawSky = NULL; + mod->DrawAddWaterPlanes = NULL; + // combine all basematerialflags observed in the submodelsurfaces range, then check for special flags + for (j = mod->submodelsurfaces_start; j < mod->submodelsurfaces_end; j++) + if (mod->data_surfaces[j].texture) + basematerialflags |= mod->data_surfaces[j].texture->basematerialflags; + if (basematerialflags & MATERIALFLAG_SKY) + mod->DrawSky = R_Mod_DrawSky; + if (basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes; +} + +typedef struct Mod_MakeSortedSurfaces_qsortsurface_s +{ + int surfaceindex; + q3deffect_t* effect; + texture_t* texture; + rtexture_t* lightmaptexture; +} +Mod_MakeSortedSurfaces_qsortsurface_t; + +static int Mod_MakeSortedSurfaces_qsortfunc(const void *a, const void *b) +{ + const Mod_MakeSortedSurfaces_qsortsurface_t* l = (Mod_MakeSortedSurfaces_qsortsurface_t*)a; + const Mod_MakeSortedSurfaces_qsortsurface_t* r = (Mod_MakeSortedSurfaces_qsortsurface_t*)b; + if (l->effect < r->effect) + return -1; + if (l->effect > r->effect) + return 1; + if (l->texture < r->texture) + return -1; + if (l->texture > r->texture) + return 1; + if (l->lightmaptexture < r->lightmaptexture) + return -1; + if (l->lightmaptexture > r->lightmaptexture) + return 1; + if (l->surfaceindex < r->surfaceindex) + return -1; + if (l->surfaceindex > r->surfaceindex) + return 1; + return 0; +} + void Mod_MakeSortedSurfaces(model_t *mod) { // make an optimal set of texture-sorted batches to draw... - int j, t; - int *firstsurfacefortexture; - int *numsurfacesfortexture; - if (!mod->sortedmodelsurfaces) - mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces)); - firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture)); - numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture)); - memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture)); - for (j = 0;j < mod->nummodelsurfaces;j++) - { - const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; - if(!surface->texture) - continue; - t = (int)(surface->texture - mod->data_textures); - numsurfacesfortexture[t]++; - } - j = 0; - for (t = 0;t < mod->num_textures;t++) - { - firstsurfacefortexture[t] = j; - j += numsurfacesfortexture[t]; - } - for (j = 0;j < mod->nummodelsurfaces;j++) + int j, k; + Mod_MakeSortedSurfaces_qsortsurface_t *info; + + if(cls.state == ca_dedicated) + return; + + info = (Mod_MakeSortedSurfaces_qsortsurface_t*)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) @@ -3068,9 +3105,9 @@ static void Mod_Decompile_OBJ(model_t *model, const char *filename, const char * if (l > 0) outbufferpos += l; submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model; - for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++) + for (surfaceindex = submodel->submodelsurfaces_start;surfaceindex < submodel->submodelsurfaces_end;surfaceindex++) { - surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex]; + surface = model->data_surfaces + surfaceindex; l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default"); if (l > 0) outbufferpos += l; @@ -3614,8 +3651,9 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const const int *element3i = model->surfmesh.data_element3i; const int *e; float v2[3][3]; - for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++) + for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++) { + surface = model->data_surfaces + surfaceindex; if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs)) continue; if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW) @@ -4491,7 +4529,7 @@ msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithpre { mod->max_surfaces = 2 * max(mod->num_surfaces, 64); mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces)); - mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces)); + mod->modelsurfaces_sorted = (int *)Mem_Realloc(mod->mempool, mod->modelsurfaces_sorted, mod->max_surfaces * sizeof(*mod->modelsurfaces_sorted)); } surf = mod->data_surfaces + mod->num_surfaces; mod->num_surfaces++; @@ -4506,31 +4544,10 @@ msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithpre return surf; } -static void Mod_Mesh_RebuildHashTable(model_t *mod, msurface_t *surf) +int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a) { int hashindex, h, vnum, mask; surfmesh_t *mesh = &mod->surfmesh; - - // rebuild the hash table - mesh->num_vertexhashsize = 4 * mesh->max_vertices; - mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2 - mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash)); - memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash)); - mask = mod->surfmesh.num_vertexhashsize - 1; - // no need to hash the vertices for the entire model, the latest surface will suffice. - for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++) - { - // this uses prime numbers intentionally for computing the hash - hashindex = (unsigned int)(mesh->data_vertex3f[vnum * 3 + 0] * 2003 + mesh->data_vertex3f[vnum * 3 + 1] * 4001 + mesh->data_vertex3f[vnum * 3 + 2] * 7919 + mesh->data_normal3f[vnum * 3 + 0] * 4097 + mesh->data_normal3f[vnum * 3 + 1] * 257 + mesh->data_normal3f[vnum * 3 + 2] * 17) & mask; - for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask) - ; // just iterate until we find the terminator - mesh->data_vertexhash[h] = vnum; - } -} - -void Mod_Mesh_CheckResize_Vertex(model_t *mod, msurface_t *surf) -{ - surfmesh_t *mesh = &mod->surfmesh; if (mesh->max_vertices == mesh->num_vertices) { mesh->max_vertices = max(mesh->num_vertices * 2, 256); @@ -4541,15 +4558,36 @@ void Mod_Mesh_CheckResize_Vertex(model_t *mod, msurface_t *surf) mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2])); mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2])); mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4])); - Mod_Mesh_RebuildHashTable(mod, surf); + // rebuild the hash table + mesh->num_vertexhashsize = 4 * mesh->max_vertices; + mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2 + mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash)); + memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash)); + mask = mod->surfmesh.num_vertexhashsize - 1; + // no need to hash the vertices for the entire model, the latest surface will suffice. + for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++) + { + // this uses prime numbers intentionally for computing the hash + hashindex = (unsigned int)(mesh->data_vertex3f[vnum * 3 + 0] * 2003 + mesh->data_vertex3f[vnum * 3 + 1] * 4001 + mesh->data_vertex3f[vnum * 3 + 2] * 7919 + mesh->data_normal3f[vnum * 3 + 0] * 4097 + mesh->data_normal3f[vnum * 3 + 1] * 257 + mesh->data_normal3f[vnum * 3 + 2] * 17) & mask; + for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask) + ; // just iterate until we find the terminator + mesh->data_vertexhash[h] = vnum; + } + } + mask = mod->surfmesh.num_vertexhashsize - 1; + // this uses prime numbers intentionally for computing the hash + hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask; + // when possible find an identical vertex within the same surface and return it + for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask) + { + if (vnum >= surf->num_firstvertex + && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z + && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz + && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t + && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v + && mesh->data_lightmapcolor4f[vnum * 4 + 0] == r && mesh->data_lightmapcolor4f[vnum * 4 + 1] == g && mesh->data_lightmapcolor4f[vnum * 4 + 2] == b && mesh->data_lightmapcolor4f[vnum * 4 + 3] == a) + return vnum; } -} - -int Mod_Mesh_AddVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a) -{ - int vnum; - surfmesh_t *mesh = &mod->surfmesh; - // add the new vertex vnum = mesh->num_vertices++; if (surf->num_vertices > 0) @@ -4567,6 +4605,7 @@ int Mod_Mesh_AddVertex(model_t *mod, msurface_t *surf, float x, float y, float z VectorSet(surf->maxs, x, y, z); } surf->num_vertices = mesh->num_vertices - surf->num_firstvertex; + mesh->data_vertexhash[h] = vnum; mesh->data_vertex3f[vnum * 3 + 0] = x; mesh->data_vertex3f[vnum * 3 + 1] = y; mesh->data_vertex3f[vnum * 3 + 2] = z; @@ -4584,32 +4623,6 @@ int Mod_Mesh_AddVertex(model_t *mod, msurface_t *surf, float x, float y, float z return vnum; } -int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a) -{ - int hashindex, h, vnum, mask; - surfmesh_t *mesh = &mod->surfmesh; - - Mod_Mesh_CheckResize_Vertex(mod, surf); - - mask = mod->surfmesh.num_vertexhashsize - 1; - // this uses prime numbers intentionally for computing the hash - hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask; - // when possible find an identical vertex within the same surface and return it - for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask) - { - if (vnum >= surf->num_firstvertex - && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z - && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz - && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t - && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v - && mesh->data_lightmapcolor4f[vnum * 4 + 0] == r && mesh->data_lightmapcolor4f[vnum * 4 + 1] == g && mesh->data_lightmapcolor4f[vnum * 4 + 2] == b && mesh->data_lightmapcolor4f[vnum * 4 + 3] == a) - return vnum; - } - vnum = Mod_Mesh_AddVertex(mod, surf, x, y, z, nx, ny, nz, s, t, u, v, r, g, b, a); - mesh->data_vertexhash[h] = vnum; - return vnum; -} - void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2) { surfmesh_t *mesh = &mod->surfmesh; @@ -4633,29 +4646,25 @@ 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; } } }