From 37cbdb9130477c1f628beb962b85252fb33e6dde Mon Sep 17 00:00:00 2001 From: Unreal Karaulov Date: Tue, 24 Dec 2024 14:37:34 +0300 Subject: [PATCH] HotFix missing origin! Bugfixes! ! Added new featu HotFix missing origin! Bugfixes! ! Added new feature : generate map overlay (for example for special effects) --- src/bsp/Bsp.cpp | 88 ++++++++++++++++++++++++++++-- src/bsp/Bsp.h | 7 ++- src/bsp/Keyvalue.cpp | 46 ++++++---------- src/bsp/Keyvalue.h | 3 + src/editor/Gui.cpp | 118 +++++++++++++++++++++++++++++++++++++++- src/editor/Renderer.cpp | 48 +++++----------- src/editor/Renderer.h | 3 - src/util/util.cpp | 4 +- 8 files changed, 242 insertions(+), 75 deletions(-) diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index a0e7bbac..61b71a70 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -4535,7 +4535,7 @@ void Bsp::update_ent_lump(bool stripNodes) vec3 Bsp::get_model_center(int modelIdx) { - if (modelIdx < 0 || modelIdx > bsp_header.lump[LUMP_MODELS].nLength / (int)sizeof(BSPMODEL)) + if (modelIdx < 0 || modelIdx >= modelCount) { print_log(get_localized_string(LANG_0072), modelIdx); return vec3(); @@ -6461,7 +6461,7 @@ void Bsp::print_clipnode_tree(int iNode, int depth) void Bsp::print_model_hull(int modelIdx, int hull_number) { - if (modelIdx < 0 || modelIdx > bsp_header.lump[LUMP_MODELS].nLength / (int)sizeof(BSPMODEL)) + if (modelIdx < 0 || modelIdx >= modelCount) { print_log(PRINT_RED | PRINT_INTENSITY, get_localized_string(LANG_1024), modelIdx); return; @@ -8581,7 +8581,7 @@ int Bsp::create_node_box(const vec3& mins, const vec3& maxs, BSPMODEL* targetMod { int sharedSolidLeaf = 0; int anyEmptyLeaf = leafIdx; - if (anyEmptyLeaf == 0) + if (anyEmptyLeaf == -1) { for (int i = 0; i < leafCount; i++) { @@ -8591,7 +8591,7 @@ int Bsp::create_node_box(const vec3& mins, const vec3& maxs, BSPMODEL* targetMod break; } } - if (anyEmptyLeaf == 0) + if (anyEmptyLeaf == -1) { anyEmptyLeaf = create_leaf(CONTENTS_EMPTY); targetModel->nVisLeafs += 1; @@ -14803,6 +14803,67 @@ bool Bsp::is_texture_with_pal(int textureid) return is_texture_has_pal; } +void Bsp::fix_all_duplicate_vertices() +{ + std::set verts_usage; + std::set edges_usage; + + for (int faceIdx = 0; faceIdx < faceCount; faceIdx++) + { + BSPFACE32 face = faces[faceIdx]; + + for (int e = face.iFirstEdge; e < face.iFirstEdge + face.nEdges; e++) + { + int edgeIdx = surfedges[e]; + BSPEDGE32& edge = edges[abs(edgeIdx)]; + + if (edges_usage.count(abs(edgeIdx))) + { + int newedge_id = create_edge(); + + if (edgeIdx >= 0) + { + edgeIdx = newedge_id; + } + else + { + edgeIdx = -newedge_id; + } + + BSPEDGE32& newedge = edges[newedge_id]; + newedge = edge; + + int v1 = create_vert(); + verts[v1] = verts[edge.iVertex[0]]; + newedge.iVertex[0] = v1; + + int v2 = create_vert(); + verts[v2] = verts[edge.iVertex[1]]; + newedge.iVertex[1] = v1; + } + else + { + int vert1 = edge.iVertex[0]; + int vert2 = edge.iVertex[1]; + + if (verts_usage.count(vert1) || verts_usage.count(vert2)) + { + int v1 = create_vert(); + verts[v1] = verts[vert1]; + edge.iVertex[0] = v1; + int v2 = create_vert(); + verts[v2] = verts[vert2]; + edge.iVertex[1] = v2; + } + + edges_usage.insert(abs(edgeIdx)); + verts_usage.insert(vert2); + verts_usage.insert(vert1); + } + } + } +} + void Bsp::face_fix_duplicate_edges_index(int faceIdx) { if (faceIdx < 0 || faceIdx >= faceCount) @@ -15071,4 +15132,23 @@ int Bsp::AddTriggerTexture() { //print_log(get_localized_string(LANG_0295)); return add_texture("aaatrigger", aaatriggerTex->get_data(), aaatriggerTex->width, aaatriggerTex->height); +} + +vec3 Bsp::getEntOrigin(Entity* ent) +{ + vec3 origin = ent->origin; + return origin + getEntOffset(ent); +} + +vec3 Bsp::getEntOffset(Entity* ent) +{ + if (ent->isBspModel()) + { + int mdl = ent->getBspModelIdx(); + if (mdl >= 0 && mdl < modelCount) + { + return get_model_center(mdl); + } + } + return vec3(); } \ No newline at end of file diff --git a/src/bsp/Bsp.h b/src/bsp/Bsp.h index 89b669d0..2a70bd78 100644 --- a/src/bsp/Bsp.h +++ b/src/bsp/Bsp.h @@ -322,7 +322,7 @@ class Bsp void create_solid_nodes(Solid& solid, BSPMODEL* targetModel); // returns index of the solid node - int create_node_box(const vec3& mins, const vec3& maxs, BSPMODEL* targetModel, bool empty = false, int leafIdx = 0); + int create_node_box(const vec3& mins, const vec3& maxs, BSPMODEL* targetModel, bool empty = false, int leafIdx = -1); int create_clipnode_box(const vec3& mins, const vec3& maxs, BSPMODEL* targetModel, int targetHull = 0, bool skipEmpty = false, bool empty = false); // copies a model from the sourceMap into this one void add_model(Bsp* sourceMap, int modelIdx); @@ -389,6 +389,8 @@ class Bsp std::vector get_face_verts(int faceIdx, int limited = INT_MAX); std::vector get_face_verts_idx(int faceIdx, int limited = INT_MAX); + void fix_all_duplicate_vertices(); + bool is_worldspawn_ent(int entIdx); int get_ent_from_model(int modelIdx); @@ -499,6 +501,9 @@ class Bsp std::vector get_model_ents(int modelIdx); std::vector get_model_ents_ids(int modelIdx); + vec3 getEntOrigin(Entity* ent); + vec3 getEntOffset(Entity* ent); + void write_csg_polys(int nodeIdx, FILE* fout, int flipPlaneSkip, bool debug); diff --git a/src/bsp/Keyvalue.cpp b/src/bsp/Keyvalue.cpp index 56c90c9c..f7fba6a7 100644 --- a/src/bsp/Keyvalue.cpp +++ b/src/bsp/Keyvalue.cpp @@ -1,38 +1,24 @@ #include "Keyvalue.h" #include "util.h" +const std::regex Keyvalues::kv_regex("\"(.*?)\"\\s*\"(.*?)\""); + Keyvalues::Keyvalues(std::string& line) { - keys.clear(); - values.clear(); - std::vector allstrings = splitString(line, "\""); - if (allstrings.size() > 1) - { - if (allstrings[0].find('{') != std::string::npos) - { - allstrings.erase(allstrings.begin()); - } - while (allstrings.size() >= 2) - { - std::string tmpkey = allstrings[0]; - std::string tmpvalue = ""; - if (allstrings.size() > 2) - tmpvalue = allstrings[2]; - allstrings.erase(allstrings.begin()); - allstrings.erase(allstrings.begin()); - if (allstrings.size() > 1) - allstrings.erase(allstrings.begin()); - if (allstrings.size() > 1) - allstrings.erase(allstrings.begin()); - keys.push_back(tmpkey); - values.push_back(tmpvalue); - } - } - line.clear(); - if (!allstrings.empty()) - { - line = allstrings[allstrings.size() - 1]; - } + keys.clear(); + values.clear(); + + std::smatch matches; + std::string remaining_line = line; + + while (std::regex_search(remaining_line, matches, kv_regex)) + { + keys.push_back(matches[1]); + values.push_back(matches[2]); + remaining_line = matches.suffix().str(); + } + + line = remaining_line; } Keyvalues::Keyvalues(void) diff --git a/src/bsp/Keyvalue.h b/src/bsp/Keyvalue.h index a911141f..b7e5f187 100644 --- a/src/bsp/Keyvalue.h +++ b/src/bsp/Keyvalue.h @@ -1,5 +1,6 @@ #pragma once #include "util.h" +#include class Keyvalues { @@ -11,5 +12,7 @@ class Keyvalues Keyvalues(const std::string& key, const std::string& value); Keyvalues(void); ~Keyvalues(void) = default; +private: + static const std::regex kv_regex; }; diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index eaa3e7ae..2dab83de 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -4516,7 +4516,7 @@ void Gui::drawMenuBar() ImGui::EndTooltip(); } - if (ImGui::BeginMenu("Porting tools")) + if (ImGui::BeginMenu("Additional tools")) { if (ImGui::BeginMenu("Delete OOB Data", !app->isLoading && app->getSelectedMap() && rend)) { @@ -4663,6 +4663,122 @@ void Gui::drawMenuBar() } IMGUI_TOOLTIP(g, "Create a point entity for use with the culling tool. 2 of these define the bounding box for structure culling operations.\n"); + + + + if (ImGui::MenuItem("Make map overlay")) + { + for (int m = map->modelCount - 1; m >= 1; m--) + { + int e = map->get_ent_from_model(m); + if (e >= 0 && !starts_with(map->ents[e]->classname, "func_wa") && + !starts_with(map->ents[e]->classname, "func_ill")) + { + map->delete_model(m); + } + } + + map->remove_faces_by_content(CONTENTS_SKY); + map->remove_faces_by_content(CONTENTS_SOLID); + + for (int f = map->faceCount - 1; f >= 0; f--) + { + BSPFACE32 face = map->faces[f]; + + if (face.iTextureInfo >= 0) + { + BSPTEXTUREINFO texinfo = map->texinfos[face.iTextureInfo]; + if (texinfo.iMiptex >= 0) + { + int texOffset = ((int*)map->textures)[texinfo.iMiptex + 1]; + if (texOffset >= 0) + { + BSPMIPTEX tex = *((BSPMIPTEX*)(map->textures + texOffset)); + std::string texname = toLowerCase(tex.szName); + if (starts_with(texname, "sky")) + { + map->remove_face(f); + } + } + } + } + } + + map->remove_unused_model_structures(); + + for (int i = map->modelCount - 1; i >= 1; i--) + { + int e = map->get_ent_from_model(i); + + map->duplicate_model_structures(i); + auto offset = map->ents[e]->origin; + auto verts = map->getModelVertsIds(i); + for (int v : verts) + { + map->verts[v] += offset; + } + map->remove_unused_model_structures(); + } + + map->remove_unused_model_structures(); + + map->save_undo_lightmaps(); + + // MAGIC! :) + map->fix_all_duplicate_vertices(); + + for (int f = 0; f < map->faceCount; f++) + { + auto verts = map->get_face_verts_idx(f); + vec3 plane_z_normalized = map->getPlaneFromFace(&map->faces[f]).vNormal.normalize(); + + for (auto v : verts) + { + map->verts[v] += plane_z_normalized * 0.15f; + } + } + + map->remove_unused_model_structures(); + map->resize_all_lightmaps(); + + rend->loadLightmaps(); + rend->preRenderFaces(); + + BSPMODEL tmpMdl{}; + tmpMdl.iFirstFace = 0; + tmpMdl.nFaces = map->faceCount; + map->get_bounding_box(tmpMdl.nMins, tmpMdl.nMaxs); + + tmpMdl.vOrigin = map->models[0].vOrigin; + tmpMdl.nVisLeafs = 0; + tmpMdl.iHeadnodes[0] = tmpMdl.iHeadnodes[1] = tmpMdl.iHeadnodes[2] = tmpMdl.iHeadnodes[3] = -1; + map->replace_lump(LUMP_MODELS, &tmpMdl, sizeof(BSPMODEL)); + + + tmpMdl.iHeadnodes[0] = map->create_node_box(map->models[0].nMins, map->models[0].nMaxs, &map->models[0], true, 0); + + map->ents.erase(map->ents.begin() + 1, map->ents.end()); + map->update_ent_lump(); + + map->remove_unused_model_structures(CLEAN_LIGHTMAP | CLEAN_PLANES | CLEAN_NODES | CLEAN_CLIPNODES | CLEAN_MARKSURFACES | CLEAN_FACES | CLEAN_SURFEDGES | CLEAN_TEXINFOS | + CLEAN_EDGES | CLEAN_VERTICES | CLEAN_TEXTURES | CLEAN_VISDATA | CLEAN_MODELS); + + + BSPLEAF32 tmpLeaf{}; + tmpLeaf.iFirstMarkSurface = 0; + tmpLeaf.nMarkSurfaces = map->marksurfCount; + tmpLeaf.nContents = CONTENTS_EMPTY; + tmpLeaf.nVisOffset = -1; + tmpLeaf.nMins = tmpMdl.nMins; + tmpLeaf.nMaxs = tmpMdl.nMaxs; + map->replace_lump(LUMP_LEAVES, &tmpLeaf, sizeof(BSPLEAF32)); + + + rend->pushUndoState("Create map BSP model overlay", EDIT_MODEL_LUMPS); + } + + IMGUI_TOOLTIP(g, "Create overlay for every map face.\n"); + ImGui::EndMenu(); } diff --git a/src/editor/Renderer.cpp b/src/editor/Renderer.cpp index 74910c35..38b0c609 100644 --- a/src/editor/Renderer.cpp +++ b/src/editor/Renderer.cpp @@ -2393,7 +2393,7 @@ void Renderer::moveGrabbedEnt() Entity* ent = map->ents[i]; vec3 tmpOrigin = grabStartEntOrigin; - vec3 offset = getEntOffset(map, ent); + vec3 offset = map->getEntOffset(ent); vec3 newOrigin = (tmpOrigin + delta) - offset; vec3 rounded = gridSnappingEnabled ? snapToGrid(newOrigin) : newOrigin; @@ -2655,7 +2655,7 @@ bool Renderer::transformAxisControls() curLeftMouse == GLFW_PRESS && oldLeftMouse == GLFW_RELEASE) { deltaMoveOffset = vec3(); - axisDragEntOriginStart = getEntOrigin(map, ent); + axisDragEntOriginStart = map->getEntOrigin(ent); axisDragStart = getAxisDragPoint(axisDragEntOriginStart); } @@ -2718,7 +2718,7 @@ bool Renderer::transformAxisControls() if (!tmpEnt) continue; - vec3 ent_offset = getEntOffset(map, tmpEnt); + vec3 ent_offset = map->getEntOffset(tmpEnt); vec3 offset = tmpEnt->origin + delta + ent_offset; @@ -3406,26 +3406,6 @@ void Renderer::drawNodes(Bsp* map, int iNode, int& currentPlane, int activePlane } } -vec3 Renderer::getEntOrigin(Bsp* map, Entity* ent) -{ - vec3 origin = ent->origin; - return origin + getEntOffset(map, ent); -} - -vec3 Renderer::getEntOffset(Bsp* map, Entity* ent) -{ - if (ent->isBspModel()) - { - int mdl = ent->getBspModelIdx(); - if (mdl >= 0 && mdl < map->modelCount) - { - BSPMODEL& tmodel = map->models[ent->getBspModelIdx()]; - return tmodel.nMins + (tmodel.nMaxs - tmodel.nMins) * 0.5f; - } - } - return vec3(); -} - void Renderer::updateDragAxes() { Bsp* map = SelectedMap; @@ -3509,7 +3489,7 @@ void Renderer::updateDragAxes() } else { - moveAxes.origin = getEntOrigin(map, ent); + moveAxes.origin = map->getEntOrigin(ent); moveAxes.origin += deltaMoveOffset; } } @@ -3913,7 +3893,7 @@ void Renderer::updateEntConnections() const COLOR4 callerColor = { 0, 255, 255, 255 }; const COLOR4 bothColor = { 0, 255, 0, 255 }; - vec3 srcPos = getEntOrigin(map, ent).flip(); + vec3 srcPos = map->getEntOrigin(ent).flip(); size_t idx = 0; size_t cidx = 0; float s = 1.5f; @@ -3921,7 +3901,7 @@ void Renderer::updateEntConnections() for (size_t i = 0; i < targets.size(); i++) { - vec3 ori = getEntOrigin(map, targets[i]).flip(); + vec3 ori = map->getEntOrigin(targets[i]).flip(); if (cidx < numPoints) { points[cidx++] = cCube(ori - extent, ori + extent, targetColor); } @@ -3932,7 +3912,7 @@ void Renderer::updateEntConnections() } for (size_t i = 0; i < callers.size(); i++) { - vec3 ori = getEntOrigin(map, callers[i]).flip(); + vec3 ori = map->getEntOrigin(callers[i]).flip(); if (cidx < numPoints) { points[cidx++] = cCube(ori - extent, ori + extent, callerColor); } @@ -3944,7 +3924,7 @@ void Renderer::updateEntConnections() for (size_t i = 0; i < callerAndTarget.size(); i++) { - vec3 ori = getEntOrigin(map, callerAndTarget[i]).flip(); + vec3 ori = map->getEntOrigin(callerAndTarget[i]).flip(); if (cidx < numPoints) { points[cidx++] = cCube(ori - extent, ori + extent, bothColor); } @@ -3964,10 +3944,10 @@ void Renderer::updateEntConnections() void Renderer::updateEntConnectionPositions() { auto entIdx = pickInfo.selectedEnts; - if (entConnections && entIdx.size()) + if (SelectedMap && entConnections && entIdx.size()) { Entity* ent = SelectedMap->ents[entIdx[0]]; - vec3 pos = getEntOrigin(getSelectedMap(), ent).flip(); + vec3 pos = SelectedMap->getEntOrigin(ent).flip(); cVert* verts = (cVert*)entConnections->get_data(); for (int i = 0; i < entConnections->numVerts; i += 2) @@ -4614,7 +4594,7 @@ void Renderer::grabEnt() Bsp* map = SelectedMap; vec3 mapOffset = map->getBspRender()->mapOffset; vec3 localCamOrigin = cameraOrigin - mapOffset; - grabDist = (getEntOrigin(map, map->ents[entIdx[0]]) - localCamOrigin).length(); + grabDist = (map->getEntOrigin(map->ents[entIdx[0]]) - localCamOrigin).length(); grabStartOrigin = localCamOrigin + cameraForward * grabDist; grabStartEntOrigin = localCamOrigin + cameraForward * grabDist; } @@ -4712,11 +4692,11 @@ void Renderer::pasteEnt(bool noModifyOrigin, bool copyModel) rend->refreshModelClipnodes(mdlIdx); } - vec3 baseOrigin = copyModel ? copiedEnts[0]->origin : getEntOffset(map, copiedEnts[0]); + vec3 baseOrigin = copyModel ? copiedEnts[0]->origin : map->getEntOffset(copiedEnts[0]); if (!noModifyOrigin) { - vec3 entOrigin = copyModel ? copiedEnts[i]->origin : getEntOrigin(map, copiedEnts[i]); + vec3 entOrigin = copyModel ? copiedEnts[i]->origin : map->getEntOrigin(copiedEnts[i]); vec3 offset = entOrigin - baseOrigin; vec3 mapOffset = map->getBspRender()->mapOffset; vec3 moveDist = (cameraOrigin + cameraForward * 100) - entOrigin; @@ -5026,7 +5006,7 @@ void Renderer::goToEnt(Bsp* map, int entIdx) size = cube->maxs - cube->mins * 0.5f; } - cameraOrigin = getEntOrigin(map, ent) - cameraForward * (size.length() + 64.0f); + cameraOrigin = map->getEntOrigin(ent) - cameraForward * (size.length() + 64.0f); } void Renderer::ungrabEnt() diff --git a/src/editor/Renderer.h b/src/editor/Renderer.h index 7378bb61..5dffafb1 100644 --- a/src/editor/Renderer.h +++ b/src/editor/Renderer.h @@ -337,9 +337,6 @@ class Renderer void drawClipnodes(Bsp* map, int iNode, int& currentPlane, int activePlane, vec3 offset = vec3()); void drawNodes(Bsp* map, int iNode, int& currentPlane, int activePlane, vec3 offset = vec3()); - vec3 getEntOrigin(Bsp* map, Entity* ent); - vec3 getEntOffset(Bsp* map, Entity* ent); - vec3 getAxisDragPoint(vec3 origin); void updateDragAxes(); diff --git a/src/util/util.cpp b/src/util/util.cpp index ed40616a..e92a887e 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -129,8 +129,8 @@ std::vector splitString(const std::string& str, const std::string& } s.erase(0, pos + delimiter.length()); } - if (!s.empty()) - split.push_back(s); + split.push_back(s); + return split; }