diff --git a/common/bspfile.cc b/common/bspfile.cc index 68a33f1c..10a1f908 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -20,6 +20,7 @@ #include #include #include +#include bool q1_surf_is_lightmapped(const surfflags_t &flags) { return !(flags.native & TEX_SPECIAL); @@ -972,6 +973,60 @@ BSP29toM_Leafs(const bsp29_dleaf_t *dleafs29, int numleafs) { return newdata; } +static bool +OverflowsInt16(float input) { + constexpr float minvalue = static_cast(INT16_MIN); + constexpr float maxvalue = static_cast(INT16_MAX); + + if (input < minvalue) { + return true; + } + if (input > maxvalue) { + return true; + } + return false; +} + +static bool +OverflowsInt16(int32_t input) { + if (input < INT16_MIN) { + return true; + } + if (input > INT16_MAX) { + return true; + } + return false; +} + +static bool +OverflowsUint16(uint32_t input) { + if (input > INT16_MAX) { + return true; + } + return false; +} + +static bool +MBSPto29_Leafs_Validate(const mleaf_t *mleafs, int numleafs) { + const mleaf_t *mleaf = mleafs; + + for (int i = 0; i < numleafs; i++, mleaf++) { + for (int j = 0; j < 3; j++) { + const float min_j = floor(mleaf->mins[j]); + const float max_j = ceil(mleaf->maxs[j]); + + if (OverflowsInt16(min_j) || OverflowsInt16(max_j)) { + return false; + } + } + if (OverflowsUint16(mleaf->firstmarksurface) + || OverflowsUint16(mleaf->nummarksurfaces)) { + return false; + } + } + return true; +} + static bsp29_dleaf_t * MBSPto29_Leafs(const mleaf_t *mleafs, int numleafs) { const mleaf_t *mleaf = mleafs; @@ -984,8 +1039,8 @@ MBSPto29_Leafs(const mleaf_t *mleafs, int numleafs) { dleaf29->contents = mleaf->contents; dleaf29->visofs = mleaf->visofs; for (j = 0; j < 3; j++) { - dleaf29->mins[j] = mleaf->mins[j]; - dleaf29->maxs[j] = mleaf->maxs[j]; + dleaf29->mins[j] = floor(mleaf->mins[j]); + dleaf29->maxs[j] = ceil(mleaf->maxs[j]); } dleaf29->firstmarksurface = mleaf->firstmarksurface; dleaf29->nummarksurfaces = mleaf->nummarksurfaces; @@ -1662,6 +1717,31 @@ BSP29to2_Nodes(const bsp29_dnode_t *dnodes29, int numnodes) { return newdata; } +static bool +BSP2to29_Nodes_Validate(const bsp2_dnode_t *dnodes2, int numnodes) { + const bsp2_dnode_t *dnode2 = dnodes2; + + for (int i = 0; i < numnodes; i++, dnode2++) { + if (OverflowsInt16(dnode2->children[0]) || OverflowsInt16(dnode2->children[1])) { + return false; + } + for (int j = 0; j < 3; j++) { + const float min_j = floor(dnode2->mins[j]); + const float max_j = ceil(dnode2->maxs[j]); + + if (OverflowsInt16(min_j) || OverflowsInt16(max_j)) { + return false; + } + } + if (OverflowsUint16(dnode2->firstface) + || OverflowsUint16(dnode2->numfaces)) { + return false; + } + } + + return true; +} + static bsp29_dnode_t * BSP2to29_Nodes(const bsp2_dnode_t *dnodes2, int numnodes) { const bsp2_dnode_t *dnode2 = dnodes2; @@ -1675,8 +1755,8 @@ BSP2to29_Nodes(const bsp2_dnode_t *dnodes2, int numnodes) { dnode29->children[0] = dnode2->children[0]; dnode29->children[1] = dnode2->children[1]; for (j = 0; j < 3; j++) { - dnode29->mins[j] = dnode2->mins[j]; - dnode29->maxs[j] = dnode2->maxs[j]; + dnode29->mins[j] = floor(dnode2->mins[j]); + dnode29->maxs[j] = ceil(dnode2->maxs[j]); } dnode29->firstface = dnode2->firstface; dnode29->numfaces = dnode2->numfaces; @@ -1707,6 +1787,28 @@ BSP29to2_Faces(const bsp29_dface_t *dfaces29, int numfaces) { return newdata; } +static bool +BSP2to29_Faces_Validate(const bsp2_dface_t *dfaces2, int numfaces) { + const bsp2_dface_t *dface2 = dfaces2; + + for (int i = 0; i < numfaces; i++, dface2++) { + if (OverflowsInt16(dface2->planenum)) { + return false; + } + if (OverflowsInt16(dface2->side)) { + return false; + } + if (OverflowsInt16(dface2->numedges)) { + return false; + } + if (OverflowsInt16(dface2->texinfo)) { + return false; + } + } + + return true; +} + static bsp29_dface_t * BSP2to29_Faces(const bsp2_dface_t *dfaces2, int numfaces) { const bsp2_dface_t *dface2 = dfaces2; @@ -1749,6 +1851,23 @@ BSP29to2_Clipnodes(const bsp29_dclipnode_t *dclipnodes29, int numclipnodes) { return newdata; } +static bool +BSP2to29_Clipnodes_Validate(const bsp2_dclipnode_t *dclipnodes2, int numclipnodes) { + const bsp2_dclipnode_t *dclipnode2 = dclipnodes2; + + for (int i = 0; i < numclipnodes; i++, dclipnode2++) { + for (int j = 0; j < 2; j++) { + /* Slightly tricky since we support > 32k clipnodes */ + int32_t child = dclipnode2->children[j]; + if (child < -15 || child > 0xFFF0) { + return false; + } + } + } + + return true; +} + static bsp29_dclipnode_t * BSP2to29_Clipnodes(const bsp2_dclipnode_t *dclipnodes2, int numclipnodes) { const bsp2_dclipnode_t *dclipnode2 = dclipnodes2; @@ -1786,6 +1905,21 @@ BSP29to2_Edges(const bsp29_dedge_t *dedges29, int numedges) return newdata; } +static bool +BSP2to29_Edges_Validate(const bsp2_dedge_t *dedges2, int numedges) +{ + const bsp2_dedge_t *dedge2 = dedges2; + + for (int i = 0; i < numedges; i++, dedge2++) { + if (OverflowsUint16(dedge2->v[0]) + || OverflowsUint16(dedge2->v[1])) { + return false; + } + } + + return true; +} + static bsp29_dedge_t * BSP2to29_Edges(const bsp2_dedge_t *dedges2, int numedges) { @@ -1818,6 +1952,20 @@ BSP29to2_Marksurfaces(const uint16_t *dmarksurfaces29, int nummarksurfaces) return newdata; } +static bool +BSP2to29_Marksurfaces_Validate(const uint32_t *dmarksurfaces2, int nummarksurfaces) +{ + const uint32_t *dmarksurface2 = dmarksurfaces2; + + for (int i = 0; i < nummarksurfaces; i++, dmarksurface2++) { + if (OverflowsUint16(*dmarksurface2)) { + return false; + } + } + + return true; +} + static uint16_t * BSP2to29_Marksurfaces(const uint32_t *dmarksurfaces2, int nummarksurfaces) { @@ -2209,14 +2357,16 @@ ConvertBSPToMFormatComplete(const bspversion_t **mbsp_loadversion, const bspvers * - No checks are done here (yet) for overflow of values when down-converting * ========================================================================= */ -void +bool ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) { if (bspdata->version == to_version) - return; + return true; - // conversions to bspver_generic if (to_version == &bspver_generic) { + // Conversions to bspver_generic + // NOTE: these always succeed + if (bspdata->version == &bspver_q1 || bspdata->version == &bspver_h2 || bspdata->version == &bspver_hl) { // bspver_q1, bspver_h2, bspver_hl -> bspver_generic @@ -2269,7 +2419,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ ConvertBSPToMFormatComplete(&mbsp->loadversion, to_version, bspdata); - return; + return true; } else if (bspdata->version == &bspver_q2) { // bspver_q2 -> bspver_generic @@ -2327,7 +2477,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ ConvertBSPToMFormatComplete(&mbsp->loadversion, to_version, bspdata); - return; + return true; } else if (bspdata->version == &bspver_qbism) { // bspver_qbism -> bspver_generic @@ -2385,7 +2535,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ ConvertBSPToMFormatComplete(&mbsp->loadversion, to_version, bspdata); - return; + return true; } else if (bspdata->version == &bspver_bsp2rmq || bspdata->version == &bspver_h2bsp2rmq) { // bspver_bsp2rmq, bspver_h2bsp2rmq -> bspver_generic @@ -2438,7 +2588,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ ConvertBSPToMFormatComplete(&mbsp->loadversion, to_version, bspdata); - return; + return true; } else if (bspdata->version == &bspver_bsp2 || bspdata->version == &bspver_h2bsp2) { // bspver_bsp2, bspver_h2bsp2 -> bspver_generic @@ -2491,17 +2641,39 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ ConvertBSPToMFormatComplete(&mbsp->loadversion, to_version, bspdata); - return; + return true; } } - // conversions from GENERIC_BSP else if (bspdata->version == &bspver_generic) { + // Conversions from bspver_generic + if (to_version == &bspver_q1 || to_version == &bspver_h2 || to_version == &bspver_hl) { // bspver_generic -> bspver_q1, bspver_h2, bspver_hl bsp29_t *bsp29 = &bspdata->data.bsp29; mbsp_t *mbsp = &bspdata->data.mbsp; + // validate that the conversion is possible + if (!MBSPto29_Leafs_Validate(mbsp->dleafs, mbsp->numleafs)) { + return false; + } + if (!BSP2to29_Nodes_Validate(mbsp->dnodes, mbsp->numnodes)) { + return false; + } + if (!BSP2to29_Faces_Validate(mbsp->dfaces, mbsp->numfaces)) { + return false; + } + if (!BSP2to29_Clipnodes_Validate(mbsp->dclipnodes, mbsp->numclipnodes)) { + return false; + } + if (!BSP2to29_Edges_Validate(mbsp->dedges, mbsp->numedges)) { + return false; + } + if (!BSP2to29_Marksurfaces_Validate(mbsp->dleaffaces, mbsp->numleaffaces)) { + return false; + } + + // zero destination struct memset(bsp29, 0, sizeof(*bsp29)); // copy counts @@ -2548,7 +2720,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ bspdata->version = to_version; - return; + return true; } else if (to_version == &bspver_q2) { // bspver_generic -> bspver_q2 @@ -2605,7 +2777,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ bspdata->version = to_version; - return; + return true; } else if (to_version == &bspver_qbism) { // bspver_generic -> bspver_qbism @@ -2662,7 +2834,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ bspdata->version = to_version; - return; + return true; } else if (to_version == &bspver_bsp2rmq || to_version == &bspver_h2bsp2rmq) { // bspver_generic -> bspver_bsp2rmq, bspver_h2bsp2rmq @@ -2715,7 +2887,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ bspdata->version = to_version; - return; + return true; } else if (to_version == &bspver_bsp2 || to_version == &bspver_h2bsp2) { // bspver_generic -> bspver_bsp2, bspver_h2bsp2 @@ -2768,7 +2940,7 @@ ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version) /* Conversion complete! */ bspdata->version = to_version; - return; + return true; } } diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index 3392308d..97ce22e8 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -1025,7 +1025,10 @@ constexpr const bspversion_t *const bspversions[] = { void LoadBSPFile(char *filename, bspdata_t *bspdata); //returns the filename as contained inside a bsp void WriteBSPFile(const char *filename, bspdata_t *bspdata); void PrintBSPFileSizes(const bspdata_t *bspdata); -void ConvertBSPFormat(bspdata_t *bspdata, const bspversion_t *to_version); +/** + * Returns false if the conversion failed. + */ +bool 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); diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index afa9b308..98519c63 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -162,8 +162,8 @@ typedef struct mapdata_s { // Final, exported data std::vector exported_texinfos; std::vector exported_planes; - std::vector exported_leafs_bsp29; - std::vector exported_nodes_bsp29; + std::vector exported_leafs; + std::vector exported_nodes; std::vector exported_marksurfaces; std::vector exported_clipnodes; std::vector exported_edges; @@ -177,6 +177,7 @@ typedef struct mapdata_s { // bspx data std::vector exported_lmshifts; bool needslmshifts = false; + std::vector exported_bspxbrushes; // helpers const std::string &miptexTextureName(int mt) const { @@ -238,11 +239,8 @@ int MakeFaceEdges(mapentity_t *entity, node_t *headnode); void ExportClipNodes(mapentity_t *entity, node_t *headnode, const int hullnum); void ExportDrawNodes(mapentity_t *entity, node_t *headnode, int firstface); -struct bspxbrushes_s -{ - uint8_t *lumpinfo; - size_t lumpsize; - size_t lumpmaxsize; +struct bspxbrushes_s { + std::vector lumpdata; }; void BSPX_Brushes_Finalize(struct bspxbrushes_s *ctx); void BSPX_Brushes_Init(struct bspxbrushes_s *ctx); diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 62c01a9e..883d7f49 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -316,14 +316,21 @@ This lump replaces the clipnodes stuff for custom collision sizes. */ void BSPX_Brushes_Finalize(struct bspxbrushes_s *ctx) { - //BSPX_AddLump("BRUSHLIST", ctx->lumpinfo, ctx->lumpsize); // FIXME: fix bspx - -// free(ctx->lumpinfo); + // Actually written in WriteBSPFile() + map.exported_bspxbrushes = std::move(ctx->lumpdata); } void BSPX_Brushes_Init(struct bspxbrushes_s *ctx) { - memset(ctx, 0, sizeof(*ctx)); + ctx->lumpdata.clear(); } + +static void +vec_push_bytes(std::vector& vec, const void* data, size_t count) { + const uint8_t* bytes = static_cast(data); + + vec.insert(vec.end(), bytes, bytes + count); +} + /* WriteBrushes Generates a submodel's direct brush information to a separate file, so the engine doesn't need to depend upon specific hull sizes @@ -372,18 +379,11 @@ void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, brush_t *bru } } - if (ctx->lumpmaxsize < ctx->lumpsize + sizeof(permodel) + permodel.numbrushes*sizeof(perbrush) + permodel.numfaces*sizeof(perface)) - { - ctx->lumpmaxsize = (ctx->lumpsize + sizeof(permodel) + permodel.numbrushes*sizeof(perbrush) + permodel.numfaces*sizeof(perface))*2; - ctx->lumpinfo = (uint8_t *) realloc(ctx->lumpinfo, ctx->lumpmaxsize); - } - permodel.ver = LittleLong(1); permodel.modelnum = LittleLong(modelnum); permodel.numbrushes = LittleLong(permodel.numbrushes); permodel.numfaces = LittleLong(permodel.numfaces); - memcpy(ctx->lumpinfo+ctx->lumpsize, &permodel, sizeof(permodel)); - ctx->lumpsize += sizeof(permodel); + vec_push_bytes(ctx->lumpdata, &permodel, sizeof(permodel)); for (b = brushes; b; b = b->next) { @@ -426,8 +426,7 @@ void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, brush_t *bru } perbrush.contents = LittleShort(perbrush.contents); perbrush.numfaces = LittleShort(perbrush.numfaces); - memcpy(ctx->lumpinfo+ctx->lumpsize, &perbrush, sizeof(perbrush)); - ctx->lumpsize += sizeof(perbrush); + vec_push_bytes(ctx->lumpdata, &perbrush, sizeof(perbrush)); for (f = b->faces; f; f = f->next) { @@ -452,11 +451,11 @@ void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, brush_t *bru perface.dist = map.planes[f->planenum].dist; } - memcpy(ctx->lumpinfo+ctx->lumpsize, &perface, sizeof(perface)); - ctx->lumpsize += sizeof(perface); + vec_push_bytes(ctx->lumpdata, &perface, sizeof(perface)); } } } + /* for generating BRUSHLIST bspx lump */ static void BSPX_CreateBrushList(void) { diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index 2a9903a2..c07fc7d9 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -223,8 +223,8 @@ ExportLeaf static void ExportLeaf(mapentity_t *entity, node_t *node) { - map.exported_leafs_bsp29.push_back({}); - mleaf_t *dleaf = &map.exported_leafs_bsp29.back(); + map.exported_leafs.push_back({}); + mleaf_t *dleaf = &map.exported_leafs.back(); dleaf->contents = RemapContentsForExport(node->contents); AssertVanillaContentType(dleaf->contents); @@ -232,9 +232,9 @@ ExportLeaf(mapentity_t *entity, node_t *node) /* * write bounding box info */ - for (int32_t i = 0; i < 3; i++) { - dleaf->mins[i] = node->mins[i]; - dleaf->maxs[i] = node->maxs[i]; + for (int32_t i = 0; i < 3; ++i) { + dleaf->mins[i] = floor(node->mins[i]); + dleaf->maxs[i] = ceil(node->maxs[i]); } dleaf->visofs = -1; // no vis info yet @@ -272,14 +272,15 @@ ExportDrawNodes(mapentity_t *entity, node_t *node) bsp2_dnode_t *dnode; int i; - const size_t ourNodeIndex = map.exported_nodes_bsp29.size(); - map.exported_nodes_bsp29.push_back({}); + const size_t ourNodeIndex = map.exported_nodes.size(); + map.exported_nodes.push_back({}); - dnode = &map.exported_nodes_bsp29[ourNodeIndex]; + dnode = &map.exported_nodes[ourNodeIndex]; - for (int32_t i = 0; i < 3; i++) { - dnode->mins[i] = node->mins[i]; - dnode->maxs[i] = node->maxs[i]; + // VectorCopy doesn't work since dest are shorts + for (int32_t i = 0; i < 3; ++i) { + dnode->mins[i] = floor(node->mins[i]); + dnode->maxs[i] = ceil(node->maxs[i]); } dnode->planenum = ExportMapPlane(node->planenum); @@ -294,19 +295,19 @@ ExportDrawNodes(mapentity_t *entity, node_t *node) if (options.target_version->game != GAME_QUAKE_II && node->children[i]->contents == CONTENTS_SOLID) dnode->children[i] = -1; else { - int nextLeafIndex = static_cast(map.exported_leafs_bsp29.size()); + int nextLeafIndex = static_cast(map.exported_leafs.size()); const int childnum = -(nextLeafIndex + 1); dnode->children[i] = childnum; ExportLeaf(entity, node->children[i]); } } else { - const int childnum = static_cast(map.exported_nodes_bsp29.size()); + const int childnum = static_cast(map.exported_nodes.size()); dnode->children[i] = childnum; ExportDrawNodes(entity, node->children[i]); // Important: our dnode pointer may be invalid after the recursive call, if the vector got resized. // So re-set the pointer. - dnode = &map.exported_nodes_bsp29[ourNodeIndex]; + dnode = &map.exported_nodes[ourNodeIndex]; } } @@ -331,11 +332,11 @@ ExportDrawNodes(mapentity_t *entity, node_t *headnode, int firstface) // populate model struct (which was emitted previously) dmodel = &map.exported_models.at(static_cast(entity->outputmodelnumber)); - dmodel->headnode[0] = static_cast(map.exported_nodes_bsp29.size()); + dmodel->headnode[0] = static_cast(map.exported_nodes.size()); dmodel->firstface = firstface; dmodel->numfaces = static_cast(map.exported_faces.size()) - firstface; - const size_t mapleafsAtStart = map.exported_leafs_bsp29.size(); + const size_t mapleafsAtStart = map.exported_leafs.size(); if (headnode->planenum == PLANENUM_LEAF) ExportLeaf(entity, headnode); @@ -343,7 +344,7 @@ ExportDrawNodes(mapentity_t *entity, node_t *headnode, int firstface) ExportDrawNodes(entity, headnode); // count how many leafs were exported by the above calls - dmodel->visleafs = static_cast(map.exported_leafs_bsp29.size() - mapleafsAtStart); + dmodel->visleafs = static_cast(map.exported_leafs.size() - mapleafsAtStart); /* remove the headnode padding */ for (i = 0; i < 3; i++) { @@ -367,9 +368,9 @@ BeginBSPFile(void) Q_assert(map.exported_edges.size() == 1); // Leave room for leaf 0 (must be solid) - map.exported_leafs_bsp29.push_back({}); - map.exported_leafs_bsp29.back().contents = RemapContentsForExport(CONTENTS_SOLID); - Q_assert(map.exported_leafs_bsp29.size() == 1); + map.exported_leafs.push_back({}); + map.exported_leafs.back().contents = RemapContentsForExport(CONTENTS_SOLID); + Q_assert(map.exported_leafs.size() == 1); } /* @@ -463,9 +464,9 @@ WriteBSPFile() bspdata.version = &bspver_generic; CopyVector(map.exported_planes, &bspdata.data.mbsp.numplanes, &bspdata.data.mbsp.dplanes); - CopyVector(map.exported_leafs_bsp29, &bspdata.data.mbsp.numleafs, &bspdata.data.mbsp.dleafs); + CopyVector(map.exported_leafs, &bspdata.data.mbsp.numleafs, &bspdata.data.mbsp.dleafs); CopyVector(map.exported_vertexes, &bspdata.data.mbsp.numvertexes, &bspdata.data.mbsp.dvertexes); - CopyVector(map.exported_nodes_bsp29, &bspdata.data.mbsp.numnodes, &bspdata.data.mbsp.dnodes); + CopyVector(map.exported_nodes, &bspdata.data.mbsp.numnodes, &bspdata.data.mbsp.dnodes); CopyVector(map.exported_texinfos, &bspdata.data.mbsp.numtexinfo, &bspdata.data.mbsp.texinfo); CopyVector(map.exported_faces, &bspdata.data.mbsp.numfaces, &bspdata.data.mbsp.dfaces); CopyVector(map.exported_clipnodes, &bspdata.data.mbsp.numclipnodes, &bspdata.data.mbsp.dclipnodes); @@ -477,15 +478,33 @@ WriteBSPFile() CopyString(map.exported_entities, true, &bspdata.data.mbsp.entdatasize, (void**)&bspdata.data.mbsp.dentdata); CopyString(map.exported_texdata, false, &bspdata.data.mbsp.texdatasize, (void**)&bspdata.data.mbsp.dtexdata); + if (map.needslmshifts) { + BSPX_AddLump(&bspdata, "LMSHIFT", map.exported_lmshifts.data(), map.exported_lmshifts.size()); + } + if (!map.exported_bspxbrushes.empty()) { + BSPX_AddLump(&bspdata, "BRUSHLIST", map.exported_bspxbrushes.data(), map.exported_bspxbrushes.size()); + } + bspdata.data.mbsp.numareas = 1; bspdata.data.mbsp.dareas = (darea_t *) malloc(sizeof(darea_t)); bspdata.data.mbsp.dareas->firstareaportal = bspdata.data.mbsp.dareas->numareaportals = 0; + if (!ConvertBSPFormat(&bspdata, options.target_version)) { + const bspversion_t* highLimitsFormat = nullptr; - // TODO: pass bspx lumps to generic bsp code so they are written + if (options.target_version == &bspver_q1) { + highLimitsFormat = &bspver_bsp2; + } else if (options.target_version == &bspver_h2) { + highLimitsFormat = &bspver_h2bsp2; + } else if (options.target_version == &bspver_q2) { + highLimitsFormat = &bspver_qbism; + } else { + Error("No high limits version of %s available", options.target_version->name); + } - //GenLump("LMSHIFT", BSPX_LMSHIFT, 1); + logprint("NOTE: limits exceeded for %s - switching to %s\n", options.target_version->name, highLimitsFormat->name); - ConvertBSPFormat(&bspdata, options.target_version); + Q_assert(ConvertBSPFormat(&bspdata, highLimitsFormat)); + } StripExtension(options.szBSPName); strcat(options.szBSPName, ".bsp"); diff --git a/testmaps/phongtest2.map b/testmaps/phongtest2.map new file mode 100644 index 00000000..2acad374 --- /dev/null +++ b/testmaps/phongtest2.map @@ -0,0 +1,142 @@ +// Game: Quake +// Format: Standard +// entity 0 +{ +"spawnflags" "0" +"classname" "worldspawn" +"wad" "free_wad.wad" +"_sun_mangle" "-60 -35 0" +"_sunlight_color" "1 0.631373 0.631373" +"_sunlight" "300" +"_sunlight2" "300" +// brush 0 +{ +( -3136 -1600 640 ) ( -3136 -544 640 ) ( -3136 -1600 672 ) sky3 192 64 0 1 1 +( -1440 -3584 640 ) ( -1440 -3584 672 ) ( 672 -3584 640 ) sky3 0 64 0 1 1 +( -1440 -1600 2512 ) ( 672 -1600 2512 ) ( -1440 -544 2512 ) sky3 0 -80 0 1 1 +( 672 -544 2544 ) ( 672 -1600 2544 ) ( -1440 -544 2544 ) sky3 0 -64 0 1 1 +( 672 544 672 ) ( -1440 544 672 ) ( 672 544 640 ) sky3 0 64 0 1 1 +( 1568 -544 672 ) ( 1568 -544 640 ) ( 1568 -1600 672 ) sky3 192 64 0 1 1 +} +// brush 1 +{ +( -3136 -1600 640 ) ( -3136 -544 640 ) ( -3136 -1600 672 ) sky3 192 64 0 1 1 +( -1440 -3584 640 ) ( -1440 -3584 672 ) ( 672 -3584 640 ) sky3 0 64 0 1 1 +( -1440 -1600 624 ) ( 672 -1600 624 ) ( -1440 -544 624 ) sky3 0 -64 0 1 1 +( 672 -544 3120 ) ( 672 -1600 3120 ) ( -1440 -544 3120 ) sky3 0 -64 0 1 1 +( 672 544 672 ) ( -1440 544 672 ) ( 672 544 640 ) sky3 0 64 0 1 1 +( -3072 -544 672 ) ( -3072 -544 640 ) ( -3072 -1600 672 ) sky3 192 64 0 1 1 +} +// brush 2 +{ +( -3136 -1600 640 ) ( -3136 -544 640 ) ( -3136 -1600 672 ) sky3 192 64 0 1 1 +( -1440 480 640 ) ( -1440 480 672 ) ( 672 480 640 ) sky3 0 64 0 1 1 +( -1440 -1600 624 ) ( 672 -1600 624 ) ( -1440 -544 624 ) sky3 0 -64 0 1 1 +( 672 -544 2544 ) ( 672 -1600 2544 ) ( -1440 -544 2544 ) sky3 0 -64 0 1 1 +( 672 544 672 ) ( -1440 544 672 ) ( 672 544 640 ) sky3 0 64 0 1 1 +( 1568 -544 672 ) ( 1568 -544 640 ) ( 1568 -1600 672 ) sky3 192 64 0 1 1 +} +// brush 3 +{ +( -3136 -1600 640 ) ( -3136 -544 640 ) ( -3136 -1600 672 ) sky3 192 64 0 1 1 +( -1440 -3584 640 ) ( -1440 -3584 672 ) ( 672 -3584 640 ) sky3 0 64 0 1 1 +( -1440 -1600 624 ) ( 672 -1600 624 ) ( -1440 -544 624 ) sky3 0 -64 0 1 1 +( 672 -544 2736 ) ( 672 -1600 2736 ) ( -1440 -544 2736 ) sky3 0 -64 0 1 1 +( 672 -3456 672 ) ( -1440 -3456 672 ) ( 672 -3456 640 ) sky3 0 64 0 1 1 +( 1568 -544 672 ) ( 1568 -544 640 ) ( 1568 -1600 672 ) sky3 192 64 0 1 1 +} +// brush 4 +{ +( -3136 -1600 640 ) ( -3136 -544 640 ) ( -3136 -1600 672 ) brownstone 0 0 0 1 1 +( -1440 -3584 640 ) ( -1440 -3584 672 ) ( 672 -3584 640 ) brownstone 0 0 0 1 1 +( -1440 -1600 624 ) ( 672 -1600 624 ) ( -1440 -544 624 ) brownstone 0 0 0 1 1 +( 672 -544 752 ) ( 672 -1600 752 ) ( -1440 -544 752 ) brownstone 0 0 0 1 1 +( 672 512 672 ) ( -1440 512 672 ) ( 672 512 640 ) brownstone 0 0 0 1 1 +( 1568 -544 672 ) ( 1568 -544 640 ) ( 1568 -1600 672 ) brownstone 0 0 0 1 1 +} +// brush 5 +{ +( 1536 -1600 640 ) ( 1536 -544 640 ) ( 1536 -1600 672 ) sky3 192 64 0 1 1 +( -1440 -3584 640 ) ( -1440 -3584 672 ) ( 672 -3584 640 ) sky3 0 64 0 1 1 +( -1440 -1600 624 ) ( 672 -1600 624 ) ( -1440 -544 624 ) sky3 0 -64 0 1 1 +( 672 -544 2576 ) ( 672 -1600 2576 ) ( -1440 -544 2576 ) sky3 0 -64 0 1 1 +( 672 544 672 ) ( -1440 544 672 ) ( 672 544 640 ) sky3 0 64 0 1 1 +( 1568 -544 672 ) ( 1568 -544 640 ) ( 1568 -1600 672 ) sky3 192 64 0 1 1 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-1952 -2368 776" +} +// entity 2 +{ +"classname" "func_detail" +"_phong" "1" +// brush 0 +{ +( -1616 -2272 752 ) ( -1616 -2271 752 ) ( -1616 -2272 753 ) bolt1 0 0 0 1 1 +( -1616 -2256 912 ) ( -1600 -2272 1040 ) ( -1600 -2272 912 ) bolt1 0 0 0 1 1 +( -1600 -2160 912 ) ( -1616 -2176 1040 ) ( -1616 -2176 912 ) bolt1 0 0 0 1 1 +( -1616 -2272 752 ) ( -1616 -2272 753 ) ( -1615 -2272 752 ) bolt1 0 0 0 1 1 +( -1616 -2272 752 ) ( -1615 -2272 752 ) ( -1616 -2271 752 ) bolt1 0 0 0 1 1 +( -1488 -2160 912 ) ( -1488 -2159 912 ) ( -1487 -2160 912 ) bolt1 0 0 0 1 1 +( -1488 -2160 768 ) ( -1487 -2160 768 ) ( -1488 -2160 769 ) bolt1 0 0 0 1 1 +( -1584 -2176 912 ) ( -1584 -2208 912 ) ( -1584 -2208 1040 ) bolt1 0 0 0 1 1 +} +// brush 1 +{ +( -1584 -2176 912 ) ( -1584 -2208 1040 ) ( -1584 -2208 912 ) bolt1 0 0 0 1 1 +( -1616 -2256 752 ) ( -1616 -2256 753 ) ( -1615 -2256 752 ) bolt1 0 0 0 1 1 +( -1616 -2272 752 ) ( -1615 -2272 752 ) ( -1616 -2271 752 ) bolt1 0 0 0 1 1 +( -1488 -2160 912 ) ( -1488 -2159 912 ) ( -1487 -2160 912 ) bolt1 0 0 0 1 1 +( -1488 -2176 768 ) ( -1487 -2176 768 ) ( -1488 -2176 769 ) bolt1 0 0 0 1 1 +( -1536 -2176 912 ) ( -1536 -2208 912 ) ( -1536 -2208 1040 ) bolt1 0 0 0 1 1 +} +// brush 2 +{ +( -1536 -2176 912 ) ( -1536 -2208 1040 ) ( -1536 -2208 912 ) bolt1 0 0 0 1 1 +( -1616 -2272 752 ) ( -1616 -2272 753 ) ( -1615 -2272 752 ) bolt1 0 0 0 1 1 +( -1616 -2272 752 ) ( -1615 -2272 752 ) ( -1616 -2271 752 ) bolt1 0 0 0 1 1 +( -1488 -2160 912 ) ( -1488 -2159 912 ) ( -1487 -2160 912 ) bolt1 0 0 0 1 1 +( -1488 -2160 768 ) ( -1487 -2160 768 ) ( -1488 -2160 769 ) bolt1 0 0 0 1 1 +( -1504 -2272 912 ) ( -1488 -2256 1040 ) ( -1488 -2256 912 ) bolt1 0 0 0 1 1 +( -1488 -2176 912 ) ( -1504 -2160 1040 ) ( -1504 -2160 912 ) bolt1 0 0 0 1 1 +( -1488 -2160 768 ) ( -1488 -2160 769 ) ( -1488 -2159 768 ) bolt1 0 0 0 1 1 +} +} +// entity 3 +{ +"classname" "func_detail" +// brush 0 +{ +( -1616 -2560 752 ) ( -1616 -2559 752 ) ( -1616 -2560 753 ) bolt1 32 0 0 1 1 +( -1616 -2544 912 ) ( -1600 -2560 1040 ) ( -1600 -2560 912 ) bolt1 32 0 0 1 1 +( -1600 -2448 912 ) ( -1616 -2464 1040 ) ( -1616 -2464 912 ) bolt1 32 0 0 1 1 +( -1616 -2560 752 ) ( -1616 -2560 753 ) ( -1615 -2560 752 ) bolt1 0 0 0 1 1 +( -1616 -2560 752 ) ( -1615 -2560 752 ) ( -1616 -2559 752 ) bolt1 0 -32 0 1 1 +( -1488 -2448 912 ) ( -1488 -2447 912 ) ( -1487 -2448 912 ) bolt1 0 -32 0 1 1 +( -1488 -2448 768 ) ( -1487 -2448 768 ) ( -1488 -2448 769 ) bolt1 0 0 0 1 1 +( -1584 -2176 912 ) ( -1584 -2208 912 ) ( -1584 -2208 1040 ) bolt1 32 0 0 1 1 +} +// brush 1 +{ +( -1584 -2176 912 ) ( -1584 -2208 1040 ) ( -1584 -2208 912 ) bolt1 32 0 0 1 1 +( -1616 -2544 752 ) ( -1616 -2544 753 ) ( -1615 -2544 752 ) bolt1 0 0 0 1 1 +( -1616 -2560 752 ) ( -1615 -2560 752 ) ( -1616 -2559 752 ) bolt1 0 -32 0 1 1 +( -1488 -2448 912 ) ( -1488 -2447 912 ) ( -1487 -2448 912 ) bolt1 0 -32 0 1 1 +( -1488 -2464 768 ) ( -1487 -2464 768 ) ( -1488 -2464 769 ) bolt1 0 0 0 1 1 +( -1536 -2176 912 ) ( -1536 -2208 912 ) ( -1536 -2208 1040 ) bolt1 32 0 0 1 1 +} +// brush 2 +{ +( -1536 -2176 912 ) ( -1536 -2208 1040 ) ( -1536 -2208 912 ) bolt1 32 0 0 1 1 +( -1616 -2560 752 ) ( -1616 -2560 753 ) ( -1615 -2560 752 ) bolt1 0 0 0 1 1 +( -1616 -2560 752 ) ( -1615 -2560 752 ) ( -1616 -2559 752 ) bolt1 0 -32 0 1 1 +( -1488 -2448 912 ) ( -1488 -2447 912 ) ( -1487 -2448 912 ) bolt1 0 -32 0 1 1 +( -1488 -2448 768 ) ( -1487 -2448 768 ) ( -1488 -2448 769 ) bolt1 0 0 0 1 1 +( -1504 -2560 912 ) ( -1488 -2544 1040 ) ( -1488 -2544 912 ) bolt1 32 0 0 1 1 +( -1488 -2464 912 ) ( -1504 -2448 1040 ) ( -1504 -2448 912 ) bolt1 32 0 0 1 1 +( -1488 -2448 768 ) ( -1488 -2448 769 ) ( -1488 -2447 768 ) bolt1 32 0 0 1 1 +} +}