From 90973e1198aafc299aa6ec762b16942fc852b926 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 1 Sep 2021 00:38:12 -0400 Subject: [PATCH] Q2bsp VIS support (#315) * Add QBSP - the BSP2-esque variant to Q2BSP - to bspinfo, and all of its accompanying structures. * pass around ident, since Q2 needs it - admittedly it's a bit ugly, but it works for now. conversion for QBSP * Fix light * _qbsp_ -> _qbism_ * Introduced bspversion_t, a struct that holds pertinent information about different BSP versions and also acts as a tagged pointer type for direct comparisons. This makes a lot of code paths simpler. I'm not entirely set on the wordings or usages yet, and maybe we can stuff boolean flags inside of them for different behaviors (for instance Q2, QBism and HL would have the "colored lightmap" boolean set to true, which replaces the check-for-all-three in the lightmapper) Swapped arguments to ConvertBSPFormat to have the conversion target last instead of first Finished rename of qbsp -> qbism Tested: - bspinfo on various BSPs I had laying around (Q1, Q2, Qbism) - bsputil converting between Q2 and Qbism, and that they loaded in engine/roundtripped properly Not tested: - vis/rad on anything major (I still can't run rad due to embree being weird) - bsputil conversion of Q1-esque maps * Q2 VIS Almost working, just in-game is not 100% functional * PHS! Q2 VIS! * Fix missing loadversion assignment Fix missing \n * Implement q2bsp -> mbsp visdata copy fix sky lighting to use arghrad compat --- common/bspfile.cc | 229 +++++++++++++++++++++++++++++++++++++- common/cmdlib.cc | 2 +- include/common/bspfile.hh | 12 +- light/trace_embree.cc | 4 +- qbsp3/common/bspfile.cc | 72 ------------ qbsp3/common/bspfile.h | 3 - vis/vis.cc | 121 +++++++++++--------- 7 files changed, 304 insertions(+), 139 deletions(-) diff --git a/common/bspfile.cc b/common/bspfile.cc index 91584f63..3d985849 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -962,6 +962,36 @@ Q2BSPtoM_Models(const q2_dmodel_t *dmodelsq2, int nummodels) { return newdata; } +static uint8_t * +Q2BSPtoM_CopyVisData(const dvis_t *dvisq2, int vissize, int *outvissize, mleaf_t *leafs, int numleafs) { + + if (!*outvissize) { + return ((uint8_t *) dvisq2); + } + + // FIXME: assumes PHS always follows PVS. + int32_t phs_start = INT_MAX, pvs_start = INT_MAX; + size_t header_offset = sizeof(dvis_t) + (sizeof(int32_t) * dvisq2->numclusters * 2); + + for (int32_t i = 0; i < dvisq2->numclusters; i++) { + pvs_start = std::min(pvs_start, (int32_t) (dvisq2->bitofs[i][DVIS_PVS])); + phs_start = std::min(phs_start, (int32_t) (dvisq2->bitofs[i][DVIS_PHS] - header_offset)); + + for (int32_t l = 0; l < numleafs; l++) { + if (leafs[l].cluster == i) { + leafs[l].visofs = dvisq2->bitofs[i][DVIS_PVS] - header_offset; + } + } + } + + // cut off the PHS and header + *outvissize -= header_offset + ((*outvissize - header_offset) - phs_start); + + uint8_t *vis = (uint8_t *) calloc(1, *outvissize); + memcpy(vis, ((uint8_t *) dvisq2) + pvs_start, *outvissize); + return vis; +} + static q2_dmodel_t * MBSPtoQ2_Models(const dmodelh2_t *dmodelsh2, int nummodels) { const dmodelh2_t *dmodelh2 = dmodelsh2; @@ -984,6 +1014,128 @@ MBSPtoQ2_Models(const dmodelh2_t *dmodelsh2, int nummodels) { return newdata; } + +/* +================ +CalcPHS + +Calculate the PHS (Potentially Hearable Set) +by ORing together all the PVS visible from a leaf +================ +*/ +static std::vector CalcPHS(int32_t portalclusters, const uint8_t *visdata, int *visdatasize, int32_t bitofs[][2]) +{ + const int32_t leafbytes = (portalclusters + 7) >> 3; + const int32_t leaflongs = leafbytes / sizeof(long); + std::vector compressed_phs; + uint8_t *uncompressed = (uint8_t *) calloc(1, leafbytes); + uint8_t *uncompressed_2 = (uint8_t *) calloc(1, leafbytes); + uint8_t *compressed = (uint8_t *) calloc(1, leafbytes * 2); + uint8_t *uncompressed_orig = (uint8_t *) calloc(1, leafbytes); + + printf ("Building PHS...\n"); + + int32_t count = 0; + for (int32_t i = 0; i < portalclusters; i++) + { + const uint8_t *scan = &visdata[bitofs[i][DVIS_PVS]]; + + DecompressRow(scan, leafbytes, uncompressed); + memset(uncompressed_orig, 0, leafbytes); + memcpy(uncompressed_orig, uncompressed, leafbytes); + + scan = uncompressed_orig; + + for (int32_t j = 0; j < leafbytes; j++) + { + uint8_t bitbyte = scan[j]; + if (!bitbyte) + continue; + for (int32_t k = 0; k < 8; k++) + { + if (! (bitbyte & (1<= portalclusters) + Error ("Bad bit in PVS"); // pad bits should be 0 + const uint8_t *src_compressed = &visdata[bitofs[index][DVIS_PVS]]; + DecompressRow(src_compressed, leafbytes, uncompressed_2); + const long *src = (long *) uncompressed_2; + long *dest = (long *) uncompressed; + for (int32_t l = 0; l < leaflongs; l++) + ((long *)uncompressed)[l] |= src[l]; + } + } + for (int32_t j = 0; j < portalclusters; j++) + if (uncompressed[j>>3] & (1<<(j&7)) ) + count++; + + // + // compress the bit string + // + int32_t j = CompressRow (uncompressed, leafbytes, compressed); + + bitofs[i][DVIS_PHS] = compressed_phs.size(); + + compressed_phs.insert(compressed_phs.end(), compressed, compressed + j); + } + + free(uncompressed); + free(uncompressed_2); + free(compressed); + free(uncompressed_orig); + + printf ("Average clusters hearable: %i\n", count / portalclusters); + + return compressed_phs; +} + +static dvis_t * +MBSPtoQ2_CopyVisData(const uint8_t *visdata, int *visdatasize, int numleafs, const mleaf_t *leafs) { + int32_t num_clusters = 0; + + for (int32_t i = 0; i < numleafs; i++) { + num_clusters = std::max(num_clusters, leafs[i].cluster + 1); + } + + size_t vis_offset = sizeof(dvis_t) + (sizeof(int32_t) * num_clusters * 2); + dvis_t *vis = (dvis_t *)calloc(1, vis_offset + *visdatasize); + + vis->numclusters = num_clusters; + + // the leaves are already using a per-cluster visofs, so just find one matching + // cluster and note it down under bitofs. + // we're also not worrying about PHS currently. + for (int32_t i = 0; i < num_clusters; i++) { + for (int32_t l = 0; l < numleafs; l++) { + if (leafs[l].cluster == i) { + // copy PVS visofs + vis->bitofs[i][DVIS_PVS] = leafs[l].visofs; + break; + } + } + } + + std::vector phs = CalcPHS(num_clusters, visdata, visdatasize, vis->bitofs); + + vis = (dvis_t *) realloc(vis, vis_offset + *visdatasize + phs.size()); + + // offset the pvs/phs properly + for (int32_t i = 0; i < num_clusters; i++) { + vis->bitofs[i][DVIS_PVS] += vis_offset; + vis->bitofs[i][DVIS_PHS] += vis_offset + *visdatasize; + } + + memcpy(((uint8_t *) vis) + vis_offset, visdata, *visdatasize); + *visdatasize += vis_offset; + + memcpy(((uint8_t *) vis) + *visdatasize, phs.data(), phs.size()); + *visdatasize += phs.size(); + + return vis; +} + static mleaf_t * Q2BSPtoM_Leafs(const q2_dleaf_t *dleafsq2, int numleafs) { const q2_dleaf_t *dleafq2 = dleafsq2; @@ -1938,7 +2090,7 @@ static void FreeMBSP(mbsp_t *bsp) inline void ConvertBSPToMFormatComplete(const bspversion_t **mbsp_loadversion, const bspversion_t *version, bspdata_t *bspdata) { - *mbsp_loadversion = bspdata->version; + bspdata->loadversion = *mbsp_loadversion = bspdata->version; bspdata->version = version; } @@ -2034,7 +2186,6 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) // copy or convert data mbsp->dmodels = Q2BSPtoM_Models(q2bsp->dmodels, q2bsp->nummodels); - mbsp->dvisdata = (uint8_t *)CopyArray(q2bsp->dvis, q2bsp->visdatasize, 1); mbsp->dlightdata = BSP29_CopyLightData(q2bsp->dlightdata, q2bsp->lightdatasize); mbsp->dentdata = BSP29_CopyEntData(q2bsp->dentdata, q2bsp->entdatasize); mbsp->dleafs = Q2BSPtoM_Leafs(q2bsp->dleafs, q2bsp->numleafs); @@ -2047,6 +2198,8 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) mbsp->dleaffaces = BSP29to2_Marksurfaces(q2bsp->dleaffaces, q2bsp->numleaffaces); mbsp->dleafbrushes = Q2BSPtoM_CopyLeafBrushes(q2bsp->dleafbrushes, q2bsp->numleafbrushes); mbsp->dsurfedges = BSP29_CopySurfedges(q2bsp->dsurfedges, q2bsp->numsurfedges); + + mbsp->dvisdata = Q2BSPtoM_CopyVisData(q2bsp->dvis, q2bsp->visdatasize, &mbsp->visdatasize, mbsp->dleafs, mbsp->numleafs); mbsp->dareas = Q2BSP_CopyAreas(q2bsp->dareas, q2bsp->numareas); mbsp->dareaportals = Q2BSP_CopyAreaPortals(q2bsp->dareaportals, q2bsp->numareaportals); @@ -2089,7 +2242,6 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) // copy or convert data mbsp->dmodels = Q2BSPtoM_Models(q2bsp->dmodels, q2bsp->nummodels); - mbsp->dvisdata = (uint8_t *)CopyArray(q2bsp->dvis, q2bsp->visdatasize, 1); mbsp->dlightdata = BSP29_CopyLightData(q2bsp->dlightdata, q2bsp->lightdatasize); mbsp->dentdata = BSP29_CopyEntData(q2bsp->dentdata, q2bsp->entdatasize); mbsp->dleafs = Q2BSP_QBSPtoM_Leafs(q2bsp->dleafs, q2bsp->numleafs); @@ -2102,6 +2254,8 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) mbsp->dleaffaces = BSP2_CopyMarksurfaces(q2bsp->dleaffaces, q2bsp->numleaffaces); mbsp->dleafbrushes = Q2BSP_Qbism_CopyLeafBrushes(q2bsp->dleafbrushes, q2bsp->numleafbrushes); mbsp->dsurfedges = BSP29_CopySurfedges(q2bsp->dsurfedges, q2bsp->numsurfedges); + + mbsp->dvisdata = Q2BSPtoM_CopyVisData(q2bsp->dvis, q2bsp->visdatasize, &mbsp->visdatasize, mbsp->dleafs, mbsp->numleafs); mbsp->dareas = Q2BSP_CopyAreas(q2bsp->dareas, q2bsp->numareas); mbsp->dareaportals = Q2BSP_CopyAreaPortals(q2bsp->dareaportals, q2bsp->numareaportals); @@ -2295,7 +2449,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) // copy or convert data q2bsp->dmodels = MBSPtoQ2_Models(mbsp->dmodels, mbsp->nummodels); - q2bsp->dvis = (dvis_t *)CopyArray(mbsp->dvisdata, mbsp->visdatasize, 1); + q2bsp->dvis = MBSPtoQ2_CopyVisData(mbsp->dvisdata, &q2bsp->visdatasize, mbsp->numleafs, mbsp->dleafs); q2bsp->dlightdata = BSP29_CopyLightData(mbsp->dlightdata, mbsp->lightdatasize); q2bsp->dentdata = BSP29_CopyEntData(mbsp->dentdata, mbsp->entdatasize); q2bsp->dleafs = MBSPtoQ2_Leafs(mbsp->dleafs, mbsp->numleafs); @@ -2350,7 +2504,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) // copy or convert data q2bsp->dmodels = MBSPtoQ2_Models(mbsp->dmodels, mbsp->nummodels); - q2bsp->dvis = (dvis_t *)CopyArray(mbsp->dvisdata, mbsp->visdatasize, 1); + q2bsp->dvis = MBSPtoQ2_CopyVisData(mbsp->dvisdata, &q2bsp->visdatasize, mbsp->numleafs, mbsp->dleafs); q2bsp->dlightdata = BSP29_CopyLightData(mbsp->dlightdata, mbsp->lightdatasize); q2bsp->dentdata = BSP29_CopyEntData(mbsp->dentdata, mbsp->entdatasize); q2bsp->dleafs = MBSPtoQ2_Qbism_Leafs(mbsp->dleafs, mbsp->numleafs); @@ -3408,3 +3562,68 @@ PrintBSPFileSizes(const bspdata_t *bspdata) logprint("%7s %-12s %10i\n", "", "entdata", bsp->entdatasize); } } + +/* + =============== + CompressRow + =============== +*/ +int +CompressRow(const uint8_t *vis, const int numbytes, uint8_t *out) +{ + int i, rep; + uint8_t *dst; + + dst = out; + for (i = 0; i < numbytes; i++) { + *dst++ = vis[i]; + if (vis[i]) + continue; + + rep = 1; + for (i++; i < numbytes; i++) + if (vis[i] || rep == 255) + break; + else + rep++; + *dst++ = rep; + i--; + } + + return dst - out; +} + +/* +=================== +DecompressRow +=================== +*/ +void +DecompressRow (const uint8_t *in, const int numbytes, uint8_t *decompressed) +{ + int c; + uint8_t *out; + int row; + + row = numbytes; + out = decompressed; + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + if (!c) + Error ("DecompressVis: 0 repeat"); + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); +} \ No newline at end of file diff --git a/common/cmdlib.cc b/common/cmdlib.cc index 7dc1b61a..acf6b921 100644 --- a/common/cmdlib.cc +++ b/common/cmdlib.cc @@ -217,7 +217,7 @@ SetQdirFromPath(const char *basedirname, const char *path) } if (pos == -1) { - logprint("SetQ2dirFromPath: failed to find %s in '%s'", basedir, path); + logprint("SetQ2dirFromPath: failed to find %s in '%s'\n", basedir, path); ClearQdir(); return; } diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index 9183755b..68463364 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -575,10 +575,10 @@ typedef struct { // compressed bit vectors #define DVIS_PVS 0 #define DVIS_PHS 1 -typedef struct { +struct dvis_t { int32_t numclusters; - int32_t bitofs[8][2]; // bitofs[numclusters][2] -} dvis_t; + int32_t bitofs[][2]; // bitofs[numclusters][2] +}; // each area has a list of portals that lead into other areas // when portals are closed, other areas may not be visible or @@ -965,4 +965,10 @@ void ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version); void BSPX_AddLump(bspdata_t *bspdata, const char *xname, const void *xdata, size_t xsize); const void *BSPX_GetLump(bspdata_t *bspdata, const char *xname, size_t *xsize); +void +DecompressRow (const uint8_t *in, const int numbytes, uint8_t *decompressed); + +int +CompressRow(const uint8_t *vis, const int numbytes, uint8_t *out); + #endif /* __COMMON_BSPFILE_H__ */ diff --git a/light/trace_embree.cc b/light/trace_embree.cc index f9a5322e..0575f804 100644 --- a/light/trace_embree.cc +++ b/light/trace_embree.cc @@ -657,8 +657,8 @@ Embree_TraceInit(const mbsp_t *bsp) // Q2: arghrad compat: sky faces only emit sunlight if: // sky flag set, light flag set, value nonzero if ((contents & Q2_SURF_SKY) != 0 - && (contents & Q2_SURF_LIGHT) != 0 - && texinfo->value != 0) + && (!arghradcompat || ((contents & Q2_SURF_LIGHT) != 0 + && texinfo->value != 0))) { skyfaces.push_back(face); continue; diff --git a/qbsp3/common/bspfile.cc b/qbsp3/common/bspfile.cc index 61997668..6f01ea62 100644 --- a/qbsp3/common/bspfile.cc +++ b/qbsp3/common/bspfile.cc @@ -86,78 +86,6 @@ dareaportal_t dareaportals[MAX_MAP_AREAPORTALS]; uint8_t dpop[256]; -/* -=============== -CompressVis - -=============== -*/ -int CompressVis (uint8_t *vis, uint8_t *dest) -{ - int j; - int rep; - int visrow; - uint8_t *dest_p; - - dest_p = dest; -// visrow = (r_numvisleafs + 7)>>3; - visrow = (dvis->numclusters + 7)>>3; - - for (j=0 ; j>3; - row = (dvis->numclusters+7)>>3; - out = decompressed; - - do - { - if (*in) - { - *out++ = *in++; - continue; - } - - c = in[1]; - if (!c) - Error ("DecompressVis: 0 repeat"); - in += 2; - while (c) - { - *out++ = 0; - c--; - } - } while (out - decompressed < row); -} - //============================================================================= /* diff --git a/qbsp3/common/bspfile.h b/qbsp3/common/bspfile.h index 7e388a4b..02f11053 100644 --- a/qbsp3/common/bspfile.h +++ b/qbsp3/common/bspfile.h @@ -80,9 +80,6 @@ extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; extern uint8_t dpop[256]; -void DecompressVis (uint8_t *in, uint8_t *decompressed); -int CompressVis (uint8_t *vis, uint8_t *dest); - void LoadBSPFile (char *filename); void LoadBSPFileTexinfo (char *filename); // just for qdata void WriteBSPFile (char *filename); diff --git a/vis/vis.cc b/vis/vis.cc index afe29eaf..84c1813f 100644 --- a/vis/vis.cc +++ b/vis/vis.cc @@ -31,10 +31,12 @@ static uint8_t *vismap; static uint8_t *vismap_p; static uint8_t *vismap_end; // past visfile -int originalvismapsize; +uint32_t originalvismapsize; uint8_t *uncompressed; // [leafbytes_real*portalleafs] +uint8_t *uncompressed_q2; // [leafbytes*portalleafs] + int leafbytes; // (portalleafs+63)>>3 int leaflongs; int leafbytes_real; // (portalleafs_real+63)>>3 @@ -545,36 +547,6 @@ LeafThread(void *arg) return NULL; } -/* - =============== - CompressRow - =============== -*/ -static int -CompressRow(const uint8_t *vis, const int numbytes, uint8_t *out) -{ - int i, rep; - uint8_t *dst; - - dst = out; - for (i = 0; i < numbytes; i++) { - *dst++ = vis[i]; - if (vis[i]) - continue; - - rep = 1; - for (i++; i < numbytes; i++) - if (vis[i] || rep == 255) - break; - else - rep++; - *dst++ = rep; - i--; - } - - return dst - out; -} - /* =============== @@ -586,7 +558,7 @@ CompressRow(const uint8_t *vis, const int numbytes, uint8_t *out) int64_t totalvis; static void -LeafFlow(int leafnum, mleaf_t *dleaf) +LeafFlow(int leafnum, mleaf_t *dleaf, const mbsp_t *bsp) { leaf_t *leaf; uint8_t *outbuffer; @@ -599,7 +571,7 @@ LeafFlow(int leafnum, mleaf_t *dleaf) /* * flow through all portals, collecting visible bits */ - outbuffer = uncompressed + leafnum * leafbytes; + outbuffer = (bsp->loadversion == &bspver_q2 || bsp->loadversion == &bspver_qbism ? uncompressed_q2 : uncompressed) + leafnum * leafbytes; leaf = &leafs[leafnum]; for (i = 0; i < leaf->numportals; i++) { p = leaf->portals[i]; @@ -645,8 +617,8 @@ LeafFlow(int leafnum, mleaf_t *dleaf) } -void -ClusterFlow(int clusternum, leafbits_t *buffer) +static void +ClusterFlow(int clusternum, leafbits_t *buffer, const mbsp_t *bsp) { leaf_t *leaf; uint8_t *outbuffer; @@ -680,11 +652,22 @@ ClusterFlow(int clusternum, leafbits_t *buffer) * Now expand the clusters into the full leaf visibility map */ numvis = 0; - outbuffer = uncompressed + clusternum * leafbytes_real; - for (i = 0; i < portalleafs_real; i++) { - if (TestLeafBit(buffer, clustermap[i])) { - outbuffer[i >> 3] |= (1 << (i & 7)); - numvis++; + + if (bsp->loadversion == &bspver_q2 || bsp->loadversion == &bspver_qbism) { + outbuffer = uncompressed_q2 + clusternum * leafbytes; + for (i = 0; i < portalleafs; i++) { + if (TestLeafBit(buffer, i)) { + outbuffer[i >> 3] |= (1 << (i & 7)); + numvis++; + } + } + } else { + outbuffer = uncompressed + clusternum * leafbytes_real; + for (i = 0; i < portalleafs_real; i++) { + if (TestLeafBit(buffer, clustermap[i])) { + outbuffer[i >> 3] |= (1 << (i & 7)); + numvis++; + } } } @@ -705,8 +688,13 @@ ClusterFlow(int clusternum, leafbits_t *buffer) } /* Allocate for worst case where RLE might grow the data (unlikely) */ - compressed = static_cast(malloc(portalleafs_real * 2 / 8)); - len = CompressRow(outbuffer, (portalleafs_real + 7) >> 3, compressed); + if (bsp->loadversion == &bspver_q2 || bsp->loadversion == &bspver_qbism) { + compressed = static_cast(malloc(portalleafs * 2 / 8)); + len = CompressRow(outbuffer, (portalleafs + 7) >> 3, compressed); + } else { + compressed = static_cast(malloc(portalleafs_real * 2 / 8)); + len = CompressRow(outbuffer, (portalleafs_real + 7) >> 3, compressed); + } dest = vismap_p; vismap_p += len; @@ -751,6 +739,8 @@ CalcPortalVis(const mbsp_t *bsp) } RunThreadsOn(startcount, numportals * 2, LeafThread, NULL); + SaveVisState(); + if (verbose) { logprint("portalcheck: %i portaltest: %i portalpass: %i\n", c_portalcheck, c_portaltest, c_portalpass); @@ -785,7 +775,7 @@ CalcVis(const mbsp_t *bsp) // if (portalleafs == portalleafs_real) { for (i = 0; i < portalleafs; i++) - LeafFlow(i, &bsp->dleafs[i + 1]); + LeafFlow(i, &bsp->dleafs[i + 1], bsp); } else { leafbits_t *buffer; @@ -793,7 +783,7 @@ CalcVis(const mbsp_t *bsp) buffer = static_cast(malloc(LeafbitsSize(portalleafs))); for (i = 0; i < portalleafs; i++) { memset(buffer, 0, LeafbitsSize(portalleafs)); - ClusterFlow(i, buffer); + ClusterFlow(i, buffer, bsp); } free(buffer); @@ -1070,9 +1060,17 @@ LoadPortals(char *name, mbsp_t *bsp) count = fscanf(f, "%i\n%i\n", &portalleafs, &numportals); if (count != 2) Error("%s: unable to parse %s HEADER\n", __func__, PORTALFILE); - portalleafs_real = portalleafs; - logprint("%6d leafs\n", portalleafs); - logprint("%6d portals\n", numportals); + + if (bsp->loadversion == &bspver_q2 || bsp->loadversion == &bspver_qbism) { + portalleafs_real = bsp->numleafs; + logprint("%6d leafs\n", portalleafs_real); + logprint("%6d clusters\n", portalleafs); + logprint("%6d portals\n", numportals); + } else { + portalleafs_real = portalleafs; + logprint("%6d leafs\n", portalleafs); + logprint("%6d portals\n", numportals); + } } else if (!strcmp(magic, PORTALFILE2)) { count = fscanf(f, "%i\n%i\n%i\n", &portalleafs_real, &portalleafs, &numportals); @@ -1103,7 +1101,11 @@ LoadPortals(char *name, mbsp_t *bsp) leafs = static_cast(malloc(portalleafs * sizeof(leaf_t))); memset(leafs, 0, portalleafs * sizeof(leaf_t)); - originalvismapsize = portalleafs_real * ((portalleafs_real + 7) / 8); + if (bsp->loadversion == &bspver_q2 || bsp->loadversion == &bspver_qbism) { + originalvismapsize = portalleafs * ((portalleafs + 7) / 8); + } else { + originalvismapsize = portalleafs_real * ((portalleafs_real + 7) / 8); + } // FIXME - more intelligent allocation? bsp->dvisdata = static_cast(malloc(MAX_MAP_VISIBILITY)); @@ -1178,7 +1180,13 @@ LoadPortals(char *name, mbsp_t *bsp) } /* Load the cluster expansion map if needed */ - if (portalleafs != portalleafs_real) { + if (bsp->loadversion == &bspver_q2 || bsp->loadversion == &bspver_qbism) { + clustermap = static_cast(malloc(portalleafs_real * sizeof(int))); + + for (int32_t i = 0; i < bsp->numleafs; i++) { + clustermap[i] = bsp->dleafs[i + 1].cluster; + } + } else if (portalleafs != portalleafs_real) { clustermap = static_cast(malloc(portalleafs_real * sizeof(int))); if (!strcmp(magic, PORTALFILE2)) { for (i = 0; i < portalleafs; i++) { @@ -1325,7 +1333,11 @@ main(int argc, char **argv) StripExtension(statetmpfile); DefaultExtension(statetmpfile, ".vi0"); - uncompressed = static_cast(calloc(portalleafs, leafbytes_real)); + if (bsp->loadversion != &bspver_q2 && bsp->loadversion != &bspver_qbism) { + uncompressed = static_cast(calloc(portalleafs, leafbytes_real)); + } else { + uncompressed_q2 = static_cast(calloc(portalleafs, leafbytes)); + } // CalcPassages (); @@ -1335,10 +1347,13 @@ main(int argc, char **argv) logprint("c_chains: %lu\n", c_chains); bsp->visdatasize = vismap_p - bsp->dvisdata; - logprint("visdatasize:%i compressed from %i\n", + logprint("visdatasize:%i compressed from %u\n", bsp->visdatasize, originalvismapsize); - - CalcAmbientSounds(bsp); + + // no ambient sounds for Q2 + if (bsp->loadversion != &bspver_q2 && bsp->loadversion != &bspver_qbism) { + CalcAmbientSounds(bsp); + } /* Convert data format back if necessary */ ConvertBSPFormat(&bspdata, loadversion);