/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // // cm_q3_main.c // Quake3 BSP map model loading // FIXME TODO: // - A lot of these allocations can be better sized (entity string for example). // #include "cm_q3_local.h" static byte *cm_q3_mapBuffer; static int cm_q3_numEntityChars; static char cm_q3_emptyEntityString[1]; static char *cm_q3_entityString = cm_q3_emptyEntityString; int cm_q3_numBrushSides; cbrushside_t *cm_q3_brushSides; int cm_q3_numShaderRefs; cBspSurface_t *cm_q3_surfaces; int cm_q3_numPlanes; cBspPlane_t *cm_q3_planes; int cm_q3_numNodes; cnode_t *cm_q3_nodes; int cm_q3_numLeafs = 1; // allow leaf funcs to be called without a map cleaf_t *cm_q3_leafs; int cm_q3_numLeafBrushes; int *cm_q3_leafBrushes; int cm_q3_numBrushes; cbrush_t *cm_q3_brushes; static int cm_q3_numVisibility; dQ3BspVis_t *cm_q3_visData; dQ3BspVis_t *cm_q3_hearData; byte *cm_q3_nullRow; // each area has a list of portals that lead into other areas // when portals are closed, other areas may not be visible or // hearable even if the vis info says that it should be int cm_q3_numAreaPortals = 1; careaportal_t *cm_q3_areaPortals; int cm_q3_numAreas = 1; carea_t *cm_q3_areas; cBspSurface_t cm_q3_nullSurface; int cm_q3_emptyLeaf; int cm_q3_numPatches; cpatch_t *cm_q3_patches; int cm_q3_numLeafPatches; int *cm_q3_leafPatches; // These are only used during load static int cm_q3_numVertexes; static vec4_t *cm_q3_mapVerts; static int cm_q3_numFaces; static cface_t *cm_q3_mapFaces; static int cm_q3_numLeafFaces; static int *cm_q3_leafFaces; /* ============================================================================= PATCH LOADING ============================================================================= */ /* =============== Patch_FlatnessTest2 =============== */ static int Patch_FlatnessTest2 (float maxflat, vec4_t point0, vec4_t point1, vec4_t point2) { vec3_t v1, v2, v3; vec3_t t, n; float dist, d, l; int ft0, ft1; Vec3Subtract (point2, point0, n); l = VectorNormalizef (n, n); if (!l) return 0; Vec3Subtract (point1, point0, t); d = -DotProduct (t, n); Vec3MA (t, d, n, t); dist = Vec3Length (t); if (fabs(dist) <= maxflat) return 0; Vec3Average (point1, point0, v1); Vec3Average (point2, point1, v2); Vec3Average (v1, v2, v3); ft0 = Patch_FlatnessTest2 (maxflat, point0, v1, v3); ft1 = Patch_FlatnessTest2 (maxflat, v3, v2, point2); return 1 + (int)floor(max (ft0, ft1) + 0.5f); } /* =============== Patch_GetFlatness2 =============== */ static void Patch_GetFlatness2 (float maxflat, vec4_t *points, int *patch_cp, int *flat) { int i, p, u, v; flat[0] = flat[1] = 0; for (v=0 ; vnormal); plane->dist = -mainplane.dist; // Axial planes for (i=0 ; i<3 ; i++) { for (sign=-1 ; sign<=1 ; sign+=2) { plane = &patchplanes[numPatchPlanes++]; Vec3Clear (plane->normal); plane->normal[i] = sign; if (sign > 0) plane->dist = absMaxs[i]; else plane->dist = -absMins[i]; } } // Edge planes for (i=0 ; i<3 ; i++) { Vec3Copy (verts[i], v1); Vec3Copy (verts[(i + 1) % 3], v2); for (k=0 ; k<3 ; k++) { normal[k] = 0; normal[(k+1)%3] = v1[(k+2)%3] - v2[(k+2)%3]; normal[(k+2)%3] = -(v1[(k+1)%3] - v2[(k+1)%3]); if (Vec3Compare (normal, vec3Origin)) continue; plane = &patchplanes[numPatchPlanes++]; VectorNormalizef ( normal, normal ); Vec3Copy ( normal, plane->normal ); plane->dist = DotProduct (plane->normal, v1); if (DotProduct(verts[(i+2)%3], normal) - plane->dist > 0) { // Invert Vec3Inverse (plane->normal); plane->dist = -plane->dist; } } } // Set plane->type and mark duplicate planes for removal for (i=0 ; inumSides = 0; brush->firstBrushSide = cm_q3_numBrushSides; for (k=0 ; k<2 ; k++) { for (i=0 ; i= 3) continue; skip[i] = qTrue; if (cm_q3_numPlanes == MAX_Q3BSP_CM_PLANES) Com_Error (ERR_DROP, "CM_Q3BSP_CreateBrush: cm_q3_numPlanes == MAX_Q3BSP_CM_PLANES"); plane = &cm_q3_planes[cm_q3_numPlanes++]; *plane = patchplanes[i]; if (cm_q3_numBrushSides == MAX_Q3BSP_CM_BRUSHSIDES) Com_Error (ERR_DROP, "CM_Q3BSP_CreateBrush: cm_q3_numBrushSides == MAX_Q3BSP_CM_BRUSHSIDES"); side = &cm_q3_brushSides[cm_q3_numBrushSides++]; side->plane = plane; if (DotProduct(plane->normal, mainplane.normal) >= 0) side->surface = surface; else side->surface = NULL; // don't clip against this side brush->numSides++; } } } /* =============== CM_Q3BSP_CreatePatch =============== */ static void CM_Q3BSP_CreatePatch (cpatch_t *patch, int numverts, vec4_t *verts, int *patch_cp) { int step[2], size[2], flat[2], i, u, v; vec4_t points[MAX_Q3BSP_CM_PATCH_VERTS]; vec3_t tverts[4], tverts2[4]; cbrush_t *brush; cBspPlane_t mainplane; // Find the degree of subdivision in the u and v directions Patch_GetFlatness2 (CM_SUBDIVLEVEL, verts, patch_cp, flat); step[0] = (1 << flat[0]); step[1] = (1 << flat[1]); size[0] = (patch_cp[0] / 2) * step[0] + 1; size[1] = (patch_cp[1] / 2) * step[1] + 1; if (size[0]*size[1] > MAX_Q3BSP_CM_PATCH_VERTS) { Com_Error (ERR_DROP, "CM_Q3BSP_CreatePatch: patch has too many vertices"); return; } // Fill in Patch_Evaluate2 (verts, patch_cp, step, points); patch->brushes = brush = cm_q3_brushes + cm_q3_numBrushes; patch->numBrushes = 0; ClearBounds (patch->absMins, patch->absMaxs); // Create a set of brushes for (v=0 ; v= MAX_Q3BSP_CM_BRUSHES) Com_Error (ERR_DROP, "CM_Q3BSP_CreatePatch: too many patch brushes"); i = v * size[0] + u; Vec3Copy (points[i], tverts[0]); Vec3Copy (points[i + size[0]], tverts[1]); Vec3Copy (points[i + 1], tverts[2]); Vec3Copy (points[i + size[0] + 1], tverts[3]); // Add to bounds AddPointToBounds (tverts[0], patch->absMins, patch->absMaxs); AddPointToBounds (tverts[1], patch->absMins, patch->absMaxs); AddPointToBounds (tverts[2], patch->absMins, patch->absMaxs); AddPointToBounds (tverts[3], patch->absMins, patch->absMaxs); PlaneFromPoints (tverts, &mainplane); // Create two brushes CM_Q3BSP_CreateBrush (brush, tverts, patch->surface); brush->contents = patch->surface->contents; brush++; cm_q3_numBrushes++; patch->numBrushes++; Vec3Copy (tverts[2], tverts2[0]); Vec3Copy (tverts[1], tverts2[1]); Vec3Copy (tverts[3], tverts2[2]); CM_Q3BSP_CreateBrush (brush, tverts2, patch->surface); brush->contents = patch->surface->contents; brush++; cm_q3_numBrushes++; patch->numBrushes++; } } } // ========================================================================== /* ================= CM_Q3BSP_CreatePatchesForLeafs ================= */ static void CM_Q3BSP_CreatePatchesForLeafs (void) { int i, j, k; cleaf_t *leaf; cface_t *face; cBspSurface_t *surf; cpatch_t *patch; int checkout[MAX_Q3BSP_CM_FACES]; memset (checkout, -1, sizeof(int)*MAX_Q3BSP_CM_FACES); for (i=0, leaf=cm_q3_leafs ; inumLeafPatches = 0; leaf->firstLeafPatch = cm_q3_numLeafPatches; if (leaf->cluster == -1) continue; for (j=0 ; jnumLeafFaces ; j++) { k = leaf->firstLeafFace + j; if (k >= cm_q3_numLeafFaces) break; k = cm_q3_leafFaces[k]; face = &cm_q3_mapFaces[k]; if (face->faceType != FACETYPE_PATCH || face->numVerts <= 0) continue; if (face->patch_cp[0] <= 0 || face->patch_cp[1] <= 0) continue; if (face->shaderNum < 0 || face->shaderNum >= cm_q3_numShaderRefs) continue; surf = &cm_q3_surfaces[face->shaderNum]; if (!surf->contents || surf->flags & SHREF_NONSOLID) continue; if (cm_q3_numLeafPatches >= MAX_Q3BSP_CM_LEAFFACES) Com_Error (ERR_DROP, "CM_Q3BSP_CreatePatchesForLeafs: map has too many faces"); // The patch was already built if (checkout[k] != -1) { cm_q3_leafPatches[cm_q3_numLeafPatches] = checkout[k]; patch = &cm_q3_patches[checkout[k]]; } else { if (cm_q3_numPatches >= MAX_Q3BSP_CM_PATCHES) Com_Error (ERR_DROP, "CM_Q3BSP_CreatePatchesForLeafs: map has too many patches"); patch = &cm_q3_patches[cm_q3_numPatches]; patch->surface = surf; cm_q3_leafPatches[cm_q3_numLeafPatches] = cm_q3_numPatches; checkout[k] = cm_q3_numPatches++; CM_Q3BSP_CreatePatch (patch, face->numVerts, cm_q3_mapVerts + face->firstVert, face->patch_cp); } leaf->contents |= patch->surface->contents; leaf->numLeafPatches++; cm_q3_numLeafPatches++; } } } /* ============================================================================= QUAKE3 BSP LOADING ============================================================================= */ /* ================= CM_Q3BSP_LoadVertexes ================= */ static void CM_Q3BSP_LoadVertexes (dQ3BspLump_t *l) { dQ3BspVertex_t *in; vec4_t *out; int i; // Check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof (*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadVertexes: funny lump size"); // Check data size cm_q3_numVertexes = l->fileLen / sizeof (*in); if (cm_q3_numVertexes > MAX_Q3BSP_CM_VERTEXES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadVertexes: Map has too many vertexes"); cm_q3_mapVerts = out = Mem_AllocExt (cm_q3_numVertexes * sizeof (*out), qFalse); // Byte swap for (i=0 ; ipoint[0]); out[i][1] = LittleFloat (in->point[1]); out[i][2] = LittleFloat (in->point[2]); } } /* ================= CM_Q3BSP_LoadFaces ================= */ static void CM_Q3BSP_LoadFaces (dQ3BspLump_t *l) { dQ3BspFace_t *in; cface_t *out; int i; // Check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof (*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadFaces: funny lump size"); // Check data size cm_q3_numFaces = l->fileLen / sizeof (*in); if (cm_q3_numFaces > MAX_Q3BSP_CM_FACES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadFaces: Map has too many faces"); cm_q3_mapFaces = out = Mem_AllocExt (cm_q3_numFaces * sizeof (*out), qFalse); // Byte swap for (i=0 ; ifaceType = LittleLong (in->faceType); out->shaderNum = LittleLong (in->shaderNum); out->numVerts = LittleLong (in->numVerts); out->firstVert = LittleLong (in->firstVert); out->patch_cp[0] = LittleLong (in->patch_cp[0]); out->patch_cp[1] = LittleLong (in->patch_cp[1]); } } /* ================= CM_Q3BSP_LoadLeafFaces ================= */ static void CM_Q3BSP_LoadLeafFaces (dQ3BspLump_t *l) { int i, j; int *in; int *out; // Check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof (*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafFaces: funny lump size"); // Check data size cm_q3_numLeafFaces = l->fileLen / sizeof(*in); if (cm_q3_numLeafFaces > MAX_Q3BSP_CM_LEAFFACES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafFaces: Map has too many leaffaces"); cm_q3_leafFaces = out = Mem_AllocExt (cm_q3_numLeafFaces*sizeof(*out), qFalse); // Byte swap for (i=0 ; i= cm_q3_numFaces) Com_Error (ERR_DROP, "CMod_LoadLeafFaces: bad surface number"); out[i] = j; } } /* ================= CM_Q3BSP_LoadSubmodels ================= */ static void CM_Q3BSP_LoadSubmodels (dQ3BspLump_t *l) { dQ3BspModel_t *in; cBspModel_t *out; cleaf_t *bleaf; int *leafbrush; int i, j; // Check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof (*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadSubmodels: funny lump size"); // Check data size cm_numCModels = l->fileLen / sizeof (*in); if (cm_numCModels < 1) Com_Error (ERR_DROP, "CM_Q3BSP_LoadSubmodels: Map with no models"); else if (cm_numCModels > MAX_Q3BSP_CM_MODELS) Com_Error (ERR_DROP, "CM_Q3BSP_LoadSubmodels: Map has too many models"); // Byte swap for (i=0 ; iheadNode = 0; } else { out->headNode = -1 - cm_q3_numLeafs; bleaf = &cm_q3_leafs[cm_q3_numLeafs++]; bleaf->numLeafBrushes = LittleLong (in->numBrushes); bleaf->firstLeafBrush = cm_q3_numLeafBrushes; bleaf->contents = 0; leafbrush = &cm_q3_leafBrushes[cm_q3_numLeafBrushes]; for (j=0 ; jnumLeafBrushes ; j++, leafbrush++) { *leafbrush = LittleLong (in->firstBrush) + j; bleaf->contents |= cm_q3_brushes[*leafbrush].contents; } cm_q3_numLeafBrushes += bleaf->numLeafBrushes; } // Spread the mins / maxs by a pixel for (j=0 ; j<3 ; j++) { out->mins[j] = LittleFloat (in->mins[j]) - 1; out->maxs[j] = LittleFloat (in->maxs[j]) + 1; } } } /* ================= CM_Q3BSP_LoadSurfaces ================= */ static void CM_Q3BSP_LoadSurfaces (dQ3BspLump_t *l) { dQ3BspShaderRef_t *in; cBspSurface_t *out; int i; // Sanity check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof(*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadSurfaces: funny lump size"); // Find the size and allocate cm_q3_numShaderRefs = l->fileLen / sizeof(*in); if (cm_q3_numShaderRefs < 1) Com_Error (ERR_DROP, "CM_Q3BSP_LoadSurfaces: Map with no shaders"); else if (cm_q3_numShaderRefs > MAX_Q3BSP_CM_SHADERS) Com_Error (ERR_DROP, "CM_Q3BSP_LoadSurfaces: Map has too many shaders"); cm_q3_surfaces = Mem_PoolAlloc (sizeof(cBspSurface_t) * cm_q3_numShaderRefs, com_cmodelSysPool, 0); // Byte swap out = cm_q3_surfaces; for (i=0 ; iflags = LittleLong (in->flags); out->contents = LittleLong (in->contents); } } /* ================= CM_Q3BSP_LoadNodes ================= */ static void CM_Q3BSP_LoadNodes (dQ3BspLump_t *l) { dQ3BspNode_t *in; int child; cnode_t *out; int i, j; // Sanity check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof(*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadNodes: funny lump size"); // Find the size and allocate (with extra for box hull) cm_q3_numNodes = l->fileLen / sizeof (*in); if (cm_q3_numNodes < 1) Com_Error (ERR_DROP, "CM_Q3BSP_LoadNodes: Map has no nodes"); else if (cm_q3_numNodes > MAX_Q3BSP_CM_NODES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadNodes: Map has too many nodes"); cm_q3_nodes = Mem_PoolAlloc (sizeof(cnode_t) * (cm_q3_numNodes+6), com_cmodelSysPool, 0); // Byte swap out = cm_q3_nodes; for (i=0 ; iplane = cm_q3_planes + LittleLong (in->planeNum); for (j=0 ; j<2 ; j++) { child = LittleLong (in->children[j]); out->children[j] = child; } } } /* ================= CM_Q3BSP_LoadBrushes ================= */ static void CM_Q3BSP_LoadBrushes (dQ3BspLump_t *l) { dQ3BspBrush_t *in; cbrush_t *out; int i, shaderRef; // Check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof(*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadBrushes: funny lump size"); // Check data size cm_q3_numBrushes = l->fileLen / sizeof(*in); if (cm_q3_numBrushes > MAX_Q3BSP_CM_BRUSHES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadBrushes: Map has too many brushes"); // Byte swap out = cm_q3_brushes; for (i=0 ; ishaderNum); out->contents = cm_q3_surfaces[shaderRef].contents; out->firstBrushSide = LittleLong (in->firstSide); out->numSides = LittleLong (in->numSides); } } /* ================= CM_Q3BSP_LoadLeafs ================= */ static void CM_Q3BSP_LoadLeafs (dQ3BspLump_t *l) { int i, j; cleaf_t *out; dQ3BspLeaf_t *in; cbrush_t *brush; // Check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof(*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafs: funny lump size"); // Check data size cm_q3_numLeafs = l->fileLen / sizeof(*in); if (cm_q3_numLeafs < 1) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafs: Map with no leafs"); else if (cm_q3_numLeafs > MAX_Q3BSP_CM_LEAFS) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafs: Map has too many leafs"); // Byte swap out = cm_q3_leafs; cm_q3_emptyLeaf = -1; for (i=0 ; icluster = LittleLong (in->cluster); out->area = LittleLong (in->area) + 1; out->firstLeafFace = LittleLong (in->firstLeafFace); out->numLeafFaces = LittleLong (in->numLeafFaces); out->contents = 0; out->firstLeafBrush = LittleLong (in->firstLeafBrush); out->numLeafBrushes = LittleLong (in->numLeafBrushes); for (j=0 ; jnumLeafBrushes ; j++) { brush = &cm_q3_brushes[cm_q3_leafBrushes[out->firstLeafBrush+j]]; out->contents |= brush->contents; } if (out->area >= cm_q3_numAreas) cm_q3_numAreas = out->area + 1; if (!out->contents) cm_q3_emptyLeaf = i; } // If map doesn't have an empty leaf - force one if (cm_q3_emptyLeaf == -1) { if (cm_q3_numLeafs >= MAX_Q3BSP_CM_LEAFS-1) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafs: Map does not have an empty leaf"); out->cluster = -1; out->area = -1; out->numLeafBrushes = 0; out->contents = 0; out->firstLeafBrush = 0; Com_DevPrintf (0, "CM_Q3BSP_LoadLeafs: Forcing an empty leaf: %i\n", cm_q3_numLeafs); cm_q3_emptyLeaf = cm_q3_numLeafs++; } } /* ================= CM_Q3BSP_LoadPlanes ================= */ static void CM_Q3BSP_LoadPlanes (dQ3BspLump_t *l) { int i; cBspPlane_t *out; dQ3BspPlane_t *in; // Sanity check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof(*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadPlanes: funny lump size"); // Find the size and allocate (with extra for box hull) cm_q3_numPlanes = l->fileLen / sizeof(*in); if (cm_q3_numPlanes < 1) Com_Error (ERR_DROP, "CM_Q3BSP_LoadPlanes: Map with no planes"); else if (cm_q3_numPlanes > MAX_Q3BSP_CM_PLANES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadPlanes: Map has too many planes"); cm_q3_planes = Mem_PoolAlloc (sizeof(cBspPlane_t) * (MAX_Q3BSP_CM_PLANES+12), com_cmodelSysPool, 0); // FIXME // Byte swap out = cm_q3_planes; for (i=0 ; inormal[0] = LittleFloat (in->normal[0]); out->normal[1] = LittleFloat (in->normal[1]); out->normal[2] = LittleFloat (in->normal[2]); out->dist = LittleFloat (in->dist); CategorizePlane (out); } } /* ================= CM_Q3BSP_LoadLeafBrushes ================= */ static void CM_Q3BSP_LoadLeafBrushes (dQ3BspLump_t *l) { int i; int *out; int *in; // Check lump size in = (void *)(cm_q3_mapBuffer + l->fileOfs); if (l->fileLen % sizeof(*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafBrushes: funny lump size"); // Check data size cm_q3_numLeafBrushes = l->fileLen / sizeof(*in); if (cm_q3_numLeafBrushes < 1) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafBrushes: Map with no planes"); else if (cm_q3_numLeafBrushes > MAX_Q3BSP_CM_LEAFBRUSHES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadLeafBrushes: Map has too many leafbrushes"); // Byte swap out = cm_q3_leafBrushes; for ( i=0 ; ifileOfs); if (l->fileLen % sizeof(*in)) Com_Error (ERR_DROP, "CM_Q3BSP_LoadBrushSides: funny lump size"); // Check data size cm_q3_numBrushSides = l->fileLen / sizeof(*in); if (cm_q3_numBrushSides > MAX_Q3BSP_CM_BRUSHSIDES) Com_Error (ERR_DROP, "CM_Q3BSP_LoadBrushSides: Map has too many brushSides"); // Byte swap out = cm_q3_brushSides; for (i=0 ; iplane = cm_q3_planes + LittleLong (in->planeNum); j = LittleLong (in->shaderNum); if (j >= cm_q3_numShaderRefs) Com_Error (ERR_DROP, "CM_Q3BSP_LoadBrushSides: Bad brushside texinfo"); out->surface = &cm_q3_surfaces[j]; } } /* ================= CM_Q3BSP_LoadVisibility ================= */ static void CM_Q3BSP_LoadVisibility (dQ3BspLump_t *l) { // Check data size cm_q3_numVisibility = l->fileLen; if (l->fileLen > MAX_Q3BSP_CM_VISIBILITY) Com_Error (ERR_DROP, "CM_Q3BSP_LoadVisibility: Map has too large visibility lump"); // Byte swap memcpy (cm_q3_visData, cm_q3_mapBuffer + l->fileOfs, l->fileLen); cm_q3_visData->numClusters = LittleLong (cm_q3_visData->numClusters); cm_q3_visData->rowSize = LittleLong (cm_q3_visData->rowSize); } /* ================= CM_Q3BSP_LoadEntityString ================= */ static void CM_Q3BSP_LoadEntityString (dQ3BspLump_t *l) { // Find the size and allocate (with extra for NULL termination) cm_q3_numEntityChars = l->fileLen; if (l->fileLen > MAX_Q3BSP_CM_ENTSTRING) Com_Error (ERR_DROP, "CM_Q3BSP_LoadEntityString: Map has too large entity lump"); cm_q3_entityString = Mem_PoolAlloc (sizeof(char) * (cm_q3_numEntityChars+1), com_cmodelSysPool, 0); // Copy data memcpy (cm_q3_entityString, cm_q3_mapBuffer + l->fileOfs, l->fileLen); } /* ================= CM_Q3BSP_CalcPHS ================= */ static void CM_Q3BSP_CalcPHS (void) { int rowbytes, rowwords; int i, j, k, l, index; int bitbyte; uint32 *dest, *src; byte *scan; int count, vcount; int numClusters; Com_DevPrintf (0, "CM_Q3BSP_CalcPHS: Building PHS...\n"); rowwords = cm_q3_visData->rowSize / sizeof(long); rowbytes = cm_q3_visData->rowSize; memset (cm_q3_hearData, 0, MAX_Q3BSP_CM_VISIBILITY); cm_q3_hearData->rowSize = cm_q3_visData->rowSize; cm_q3_hearData->numClusters = numClusters = cm_q3_visData->numClusters; vcount = 0; for (i=0 ; i>3] & (1<<(j&7))) vcount++; } } count = 0; scan = (byte *)cm_q3_visData->data; dest = (uint32 *)cm_q3_hearData->data; for (i=0 ; i= numClusters) Com_Error (ERR_DROP, "CM_Q3BSP_CalcPHS: Bad bit in PVS"); // pad bits should be 0 src = (unsigned *)((byte*)cm_q3_visData->data) + index*rowwords; for (l=0 ; l>3] & (1<<(j&7))) count++; } Com_DevPrintf (0, "CM_Q3BSP_CalcPHS: Average clusters visible / hearable / total: %i / %i / %i\n" , vcount ? vcount/numClusters : 0, count ? count/numClusters : 0, numClusters); } // ========================================================================== /* ================= CM_Q3BSP_LoadMap ================= */ cBspModel_t *CM_Q3BSP_LoadMap (uint32 *buffer) { dQ3BspHeader_t header; int i; // // Allocate space // cm_q3_areaPortals = Mem_PoolAlloc (sizeof(careaportal_t) * MAX_Q3BSP_CM_AREAPORTALS, com_cmodelSysPool, 0); cm_q3_areas = Mem_PoolAlloc (sizeof(carea_t) * MAX_Q3BSP_CM_AREAS, com_cmodelSysPool, 0); cm_q3_brushes = Mem_PoolAlloc (sizeof(cbrush_t) * (MAX_Q3BSP_CM_BRUSHES+1), com_cmodelSysPool, 0); // extra for box hull cm_q3_brushSides = Mem_PoolAlloc (sizeof(cbrushside_t) * (MAX_Q3BSP_CM_BRUSHSIDES+6), com_cmodelSysPool, 0); // extra for box hull cm_q3_hearData = Mem_PoolAlloc (sizeof(byte) * MAX_Q3BSP_CM_VISIBILITY, com_cmodelSysPool, 0); cm_q3_leafBrushes = Mem_PoolAlloc (sizeof(int) * (MAX_Q3BSP_CM_LEAFBRUSHES+1), com_cmodelSysPool, 0); // extra for box hull cm_q3_leafPatches = Mem_PoolAlloc (sizeof(int) * MAX_Q3BSP_CM_LEAFFACES, com_cmodelSysPool, 0); cm_q3_leafs = Mem_PoolAlloc (sizeof(cleaf_t) * MAX_Q3BSP_CM_LEAFS, com_cmodelSysPool, 0); cm_q3_nullRow = Mem_PoolAllocExt (sizeof(byte) * (MAX_Q3BSP_CM_LEAFS / 8), qFalse, com_cmodelSysPool, 0); cm_q3_patches = Mem_PoolAlloc (sizeof(cpatch_t) * MAX_Q3BSP_CM_PATCHES, com_cmodelSysPool, 0); cm_q3_visData = Mem_PoolAlloc (sizeof(byte) * MAX_Q3BSP_CM_VISIBILITY, com_cmodelSysPool, 0); // Default values memset (cm_q3_nullRow, 255, MAX_Q3BSP_CM_LEAFS / 8); // // Byte swap lumps // header = *(dQ3BspHeader_t *)buffer; for (i=0 ; inumClusters : 1; } /* ================== CM_Q3BSP_NumTexInfo ================== */ int CM_Q3BSP_NumTexInfo (void) { // FIXME return 0; }