From 14bb9b845920e931d02f7e3c5d9ca950860d3de8 Mon Sep 17 00:00:00 2001 From: Unreal Karaulov Date: Sun, 10 Mar 2024 20:52:59 +0300 Subject: [PATCH] MAP MIRROR X/Y FEATURE. BUGFIXES. --- src/bsp/Bsp.cpp | 8 +----- src/bsp/Wad.cpp | 66 ++++++++++++++++++++-------------------------- src/bsp/Wad.h | 10 ++----- src/editor/Gui.cpp | 65 +++++++++++++++++++++++++++++++++++++++++---- src/main.cpp | 53 +++++++++---------------------------- src/util/util.cpp | 13 +++++++++ src/util/util.h | 41 ++++++++++++++++++++++++++++ 7 files changed, 157 insertions(+), 99 deletions(-) diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index 8f52e322..6c19b1c8 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -11719,13 +11719,7 @@ int Bsp::getBspTextureSize(int textureid) sz += sizeof(COLOR3) * 256; // pallette } - for (int i = 0; i < MIPLEVELS; i++) - { - int div = 1 << i; - int mipWidth = tex->nWidth / div; - int mipHeight = tex->nHeight / div; - sz += mipWidth * mipHeight; - } + sz += calcMipsSize(tex->nWidth, tex->nHeight); } return sz; } diff --git a/src/bsp/Wad.cpp b/src/bsp/Wad.cpp index 850c7707..b6d46dac 100644 --- a/src/bsp/Wad.cpp +++ b/src/bsp/Wad.cpp @@ -64,7 +64,7 @@ bool Wad::readInfo() if (!fileExists(file)) { - print_log(get_localized_string(LANG_0247),filename); + print_log(get_localized_string(LANG_0247), filename); return false; } @@ -72,7 +72,7 @@ bool Wad::readInfo() if (!filedata) { - print_log(get_localized_string(LANG_1043),filename); + print_log(get_localized_string(LANG_1043), filename); filedata = NULL; return false; } @@ -81,7 +81,7 @@ bool Wad::readInfo() { delete[] filedata; filedata = NULL; - print_log(get_localized_string(LANG_0248),filename); + print_log(get_localized_string(LANG_0248), filename); return false; } @@ -93,7 +93,7 @@ bool Wad::readInfo() { delete[] filedata; filedata = NULL; - print_log(get_localized_string(LANG_0249),filename); + print_log(get_localized_string(LANG_0249), filename); return false; } @@ -101,7 +101,7 @@ bool Wad::readInfo() { delete[] filedata; filedata = NULL; - print_log(get_localized_string(LANG_0250),filename); + print_log(get_localized_string(LANG_0250), filename); return false; } @@ -215,14 +215,11 @@ WADTEX* Wad::readTexture(const std::string& texname, int* texturetype) memcpy((char*)&mtex, &filedata[offset], sizeof(BSPMIPTEX)); offset += sizeof(BSPMIPTEX); if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0255),mtex.szName,mtex.nWidth,mtex.nHeight); + print_log(get_localized_string(LANG_0255), mtex.szName, mtex.nWidth, mtex.nHeight); int w = mtex.nWidth; int h = mtex.nHeight; - int sz = w * h; // miptex 0 - int sz2 = sz / 4; // miptex 1 - int sz3 = sz2 / 4; // miptex 2 - int sz4 = sz3 / 4; // miptex 3 - int szAll = sz + sz2 + sz3 + sz4 + sizeof(short) + /*pal size*/ sizeof(COLOR3) * 256; + + int szAll = calcMipsSize(w, h) + sizeof(short) + /*pal size*/ sizeof(COLOR3) * 256; unsigned char* data = new unsigned char[szAll];/* 4 bytes padding */ @@ -232,15 +229,16 @@ WADTEX* Wad::readTexture(const std::string& texname, int* texturetype) WADTEX* tex = new WADTEX(); memcpy(tex->szName, mtex.szName, MAXTEXTURENAME); + for (int i = 0; i < MIPLEVELS; i++) tex->nOffsets[i] = mtex.nOffsets[i]; - tex->nWidth = mtex.nWidth; - tex->nHeight = mtex.nHeight; + tex->nWidth = w; + tex->nHeight = h; tex->data = data; tex->dataLen = szAll; tex->needclean = true; if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0256),tex->szName,tex->nWidth,tex->nHeight); + print_log(get_localized_string(LANG_0256), tex->szName, tex->nWidth, tex->nHeight); return tex; } @@ -272,11 +270,8 @@ bool Wad::write(const std::string& _filename, std::vector textures) { int w = textures[i]->nWidth; int h = textures[i]->nHeight; - int sz = w * h; // miptex 0 - int sz2 = sz / 4; // miptex 1 - int sz3 = sz2 / 4; // miptex 2 - int sz4 = sz3 / 4; // miptex 3 - int szAll = sz + sz2 + sz3 + sz4 + sizeof(short) + /* pal num */ sizeof(COLOR3) * 256; + + int szAll = calcMipsSize(w, h) + sizeof(short) + /* pal num */ sizeof(COLOR3) * 256; szAll = (szAll + 3) & ~3; // 4 bytes padding @@ -302,7 +297,7 @@ bool Wad::write(const std::string& _filename, std::vector textures) int szAll = sz + sz2 + sz3 + sz4 + sizeof(short) /* pal num*/ + sizeof(COLOR3) * 256; int padding = ((szAll + 3) & ~3) - szAll; // 4 bytes padding - + miptex.nWidth = w; miptex.nHeight = h; miptex.nOffsets[0] = sizeof(BSPMIPTEX); @@ -321,7 +316,7 @@ bool Wad::write(const std::string& _filename, std::vector textures) { unsigned char* zeropad = new unsigned char[padding]; memset(zeropad, 0, padding); - myFile.write((const char *)zeropad, padding); + myFile.write((const char*)zeropad, padding); delete[] zeropad; } } @@ -331,13 +326,8 @@ bool Wad::write(const std::string& _filename, std::vector textures) { WADDIRENTRY entry = WADDIRENTRY(); entry.nFilePos = offset; - int w = textures[i]->nWidth; - int h = textures[i]->nHeight; - int sz = w * h; // miptex 0 - int sz2 = sz / 4; // miptex 1 - int sz3 = sz2 / 4; // miptex 2 - int sz4 = sz3 / 4; // miptex 3 - int szAll = sz + sz2 + sz3 + sz4 + sizeof(short) + /* pal num */ sizeof(COLOR3) * 256; + + int szAll = calcMipsSize(textures[i]->nWidth, textures[i]->nHeight) + sizeof(short) + /* pal num */ sizeof(COLOR3) * 256; szAll = (szAll + 3) & ~3; // 4 bytes padding @@ -381,7 +371,7 @@ WADTEX* create_wadtex(const char* name, COLOR3* rgbdata, int width, int height) mip[0] = new unsigned char[width * height]; bool do_magic = false; - if ( name[0] == '{' ) + if (name[0] == '{') { int sz = width * height; for (int i = 0; i < sz; i++) @@ -522,7 +512,7 @@ WADTEX* create_wadtex(const char* name, COLOR3* rgbdata, int width, int height) COLOR3* ConvertWadTexToRGB(WADTEX* wadTex, COLOR3* palette) { if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0257),wadTex->szName,wadTex->nWidth,wadTex->nHeight); + print_log(get_localized_string(LANG_0257), wadTex->szName, wadTex->nWidth, wadTex->nHeight); int lastMipSize = (wadTex->nWidth >> 3) * (wadTex->nHeight >> 3); if (palette == NULL) palette = (COLOR3*)(wadTex->data + wadTex->nOffsets[3] + lastMipSize + sizeof(short) - sizeof(BSPMIPTEX)); @@ -538,14 +528,14 @@ COLOR3* ConvertWadTexToRGB(WADTEX* wadTex, COLOR3* palette) } if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0258),wadTex->szName,wadTex->nWidth,wadTex->nHeight); + print_log(get_localized_string(LANG_0258), wadTex->szName, wadTex->nWidth, wadTex->nHeight); return imageData; } COLOR3* ConvertMipTexToRGB(BSPMIPTEX* tex, COLOR3* palette) { if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0259),tex->szName,tex->nWidth,tex->nHeight); + print_log(get_localized_string(LANG_0259), tex->szName, tex->nWidth, tex->nHeight); int lastMipSize = (tex->nWidth >> 3) * (tex->nHeight >> 3); if (palette == NULL) @@ -561,7 +551,7 @@ COLOR3* ConvertMipTexToRGB(BSPMIPTEX* tex, COLOR3* palette) } if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0260),tex->szName,tex->nWidth,tex->nHeight); + print_log(get_localized_string(LANG_0260), tex->szName, tex->nWidth, tex->nHeight); return imageData; } @@ -569,7 +559,7 @@ COLOR3* ConvertMipTexToRGB(BSPMIPTEX* tex, COLOR3* palette) COLOR4* ConvertWadTexToRGBA(WADTEX* wadTex, COLOR3* palette, int colors) { if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0261),wadTex->szName,wadTex->nWidth,wadTex->nHeight); + print_log(get_localized_string(LANG_0261), wadTex->szName, wadTex->nWidth, wadTex->nHeight); int lastMipSize = (wadTex->nWidth >> 3) * (wadTex->nHeight >> 3); if (palette == NULL) @@ -592,14 +582,14 @@ COLOR4* ConvertWadTexToRGBA(WADTEX* wadTex, COLOR3* palette, int colors) } if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0262),wadTex->szName,wadTex->nWidth,wadTex->nHeight); + print_log(get_localized_string(LANG_0262), wadTex->szName, wadTex->nWidth, wadTex->nHeight); return imageData; } COLOR4* ConvertMipTexToRGBA(BSPMIPTEX* tex, COLOR3* palette, int colors) { if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0263),tex->szName,tex->nWidth,tex->nHeight); + print_log(get_localized_string(LANG_0263), tex->szName, tex->nWidth, tex->nHeight); int lastMipSize = (tex->nWidth >> 3) * (tex->nHeight >> 3); if (palette == NULL) @@ -611,7 +601,7 @@ COLOR4* ConvertMipTexToRGBA(BSPMIPTEX* tex, COLOR3* palette, int colors) for (int k = 0; k < sz; k++) { - if (tex->szName[0] == '{' && (colors - 1 == src[k] || palette[src[k]] == COLOR3(0, 0, 255))) + if (tex->szName[0] == '{' && (colors - 1 == src[k] || palette[src[k]] == COLOR3(0, 0, 255))) { imageData[k] = COLOR4(0, 0, 0, 0); } @@ -622,7 +612,7 @@ COLOR4* ConvertMipTexToRGBA(BSPMIPTEX* tex, COLOR3* palette, int colors) } if (g_settings.verboseLogs) - print_log(get_localized_string(LANG_0264),tex->szName,tex->nWidth,tex->nHeight); + print_log(get_localized_string(LANG_0264), tex->szName, tex->nWidth, tex->nHeight); return imageData; } diff --git a/src/bsp/Wad.h b/src/bsp/Wad.h index 00316add..117ee501 100644 --- a/src/bsp/Wad.h +++ b/src/bsp/Wad.h @@ -3,6 +3,7 @@ #include #include "bsplimits.h" #include "bsptypes.h" +int calcMipsSize(int w, int h); #pragma pack(push, 1) @@ -75,14 +76,7 @@ struct WADTEX return; } - int sz = 0; - for (int i = 0; i < MIPLEVELS; i++) - { - int div = 1 << i; - int mipWidth = tex->nWidth / div; - int mipHeight = tex->nHeight / div; - sz += mipWidth * mipHeight; - } + int sz = calcMipsSize(tex->nWidth,tex->nHeight); dataLen = sz + sizeof(short) + sizeof(COLOR3) * 256; data = new unsigned char[dataLen]; diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index 1d6655a5..cbf74e3c 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -3862,6 +3862,63 @@ void Gui::drawMenuBar() ImGui::EndTooltip(); } + if (ImGui::MenuItem("Mirror map x/y [WIP]", NULL, false, map)) + { + for (int i = 0; i < map->vertCount; i++) + { + std::swap(map->verts[i].x, map->verts[i].y); + } + + for (int i = 0; i < map->faceCount; i++) + { + int* start = &map->surfedges[map->faces[i].iFirstEdge]; + int* end = &map->surfedges[map->faces[i].iFirstEdge + map->faces[i].nEdges]; + std::reverse(start, end); + } + + for (int i = 0; i < map->planeCount; i++) + { + std::swap(map->planes[i].vNormal.x, map->planes[i].vNormal.y); + map->planes[i].update_plane(false); + } + + for (int i = 0; i < map->texinfoCount; i++) + { + std::swap(map->texinfos[i].vS.x, map->texinfos[i].vS.y); + std::swap(map->texinfos[i].vT.x, map->texinfos[i].vT.y); + } + + for (int i = 0; i < map->ents.size(); i++) + { + if (!map->ents[i]->origin.IsZero()) + { + std::swap(map->ents[i]->origin.x, map->ents[i]->origin.y); + map->ents[i]->setOrAddKeyvalue("origin", map->ents[i]->origin.toKeyvalueString()); + } + } + + for (int i = 0; i < map->leafCount; i++) + { + std::swap(map->leaves[i].nMins.x, map->leaves[i].nMins.y); + std::swap(map->leaves[i].nMaxs.x, map->leaves[i].nMaxs.y); + } + + for (int i = 0; i < map->modelCount; i++) + { + std::swap(map->models[i].nMins.x, map->models[i].nMins.y); + std::swap(map->models[i].nMaxs.x, map->models[i].nMaxs.y); + } + + for (int i = 0; i < map->nodeCount; i++) + { + std::swap(map->nodes[i].nMins.x, map->nodes[i].nMins.y); + std::swap(map->nodes[i].nMaxs.x, map->nodes[i].nMaxs.y); + } + app->reloading = true; + rend->reload(); + app->reloading = false; + } + if (ImGui::BeginMenu("Scale map (WIP)", map)) { static bool ScaleOnlySelected = false; @@ -4782,11 +4839,9 @@ void Gui::drawMenuBar() { int w = tex->nWidth; int h = tex->nHeight; - int sz = w * h; // miptex 0 - int sz2 = sz / 4; // miptex 1 - int sz3 = sz2 / 4; // miptex 2 - int sz4 = sz3 / 4; // miptex 3 - int szAll = sz + sz2 + sz3 + sz4; + + int szAll = calcMipsSize(w,h); + unsigned char* texdata = (unsigned char*)(((unsigned char*)tex) + tex->nOffsets[0]); colors = (int)*(unsigned short*)(texdata + szAll); } diff --git a/src/main.cpp b/src/main.cpp index fe1deddb..b3611326 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,6 @@ // update merge logic for v2 scripts // abort scale/vertex edits if an overflow occurs // 3d axes don't appear until moving mouse over 3D view sometimes -// "Hide" axes setting not loaded properly // crash using 3d scale axes // todo: @@ -30,21 +29,15 @@ // merge redundant submodels and duplicate structures // no lightmap renders black faces if no lightmap data for face // select overlapping entities by holding mouse down -// multi-select with ctrl -// recalculate lightmaps when scaling objects // normalized clip type for clipnode regeneration (fixes broken collision around 90+ degree angle edges) // lerp plane distance in regenerated clipnodes between bbox height and width // uniform scaling // highlight non-planar faces in vertex edit mode // subdivided faces can't be transformed in verte edit mode // auto-clean after a while? Unused data will pile up after a lot of face splitting -// scale fps overlay + toolbar offset with font size // reference aaatrigger from wad instead of embedding it if it doesnt exist // red highlight not working with lightmaps disabled -// undo history -// invalid solid log spam // scaling allowing concave solids (merge0.bsp angled wedge) -// can't select faces sometimes // make all commands available in the 3d editor // transforms gradually waste more and more planes+clipnodes until the map overflows (need smarter updates) // "Validate" doesn't return any response.. -Sparks (add a results window or something for that + clean/optimize) @@ -98,7 +91,7 @@ // Removing HULL 0 from solid model crashes game when standing on it -std::string g_version_string = "NewBSPGuy v4.19"; +std::string g_version_string = "NewBSPGuy v4.20"; bool g_verbose = false; @@ -131,16 +124,12 @@ bool start_viewer(const char* map) SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); #endif - //TestSprite(); renderer.renderLoop(); return true; } int test() { - //start_viewer("hl_c09.bsp"); - //return 0; - std::vector maps; for (int i = 1; i < 22; i++) @@ -149,11 +138,6 @@ int test() maps.push_back(map); } - //maps.push_back(new Bsp("op4/of1a1.bsp")); - //maps.push_back(new Bsp("op4/of1a2.bsp")); - //maps.push_back(new Bsp("op4/of1a3.bsp")); - //maps.push_back(new Bsp("op4/of1a4.bsp")); - STRUCTCOUNT removed; memset(&removed, 0, sizeof(removed)); @@ -974,27 +958,6 @@ struct UVVERT { vec3 vec3mix(const vec3& a, const vec3& b, float t) { return a * (1.0f - t) + b * t; } -//void WriteObjFile(const std::vector& vertices, const std::string& filename) { -// std::ofstream objFile(filename); -// if (!objFile.is_open()) return; -// -// for (const auto& vert : vertices) { -// objFile << "v " << vert.vert.x << " " << vert.vert.y << " " << vert.vert.z << "\n"; -// } -// -// // Writing texture names for each vertex -// for (const auto& vert : vertices) { -// objFile << "vt " << vert.texname << "\n"; -// } -// -// // Assuming all vertices are part of a single object -// // Writing faces (triangles) assuming vertices are in order -// for (size_t i = 0; i < vertices.size(); i += 3) { -// objFile << "f " << (i + 1) << "/" << (i + 1) << " " << (i + 2) << "/" << (i + 2) << " " << (i + 3) << "/" << (i + 3) << "\n"; -// } -// -// objFile.close(); -//} void CreateSkybox(std::vector& vertices, vec3 mins, vec3 maxs) { std::string sides[6] = { "right", "left", "up", "down", "front", "back" }; @@ -1049,12 +1012,10 @@ int main(int argc, char* argv[]) setlocale(LC_ALL, ".utf8"); setlocale(LC_NUMERIC, "C"); - //set_console_colors; - set_console_colors(PRINT_RED | PRINT_GREEN | PRINT_INTENSITY); std::cout << "BSPGUY:" << g_version_string << std::endl; set_console_colors(); - //std::fesetround(FE_TONEAREST); + try { #ifdef WIN32 @@ -1131,6 +1092,16 @@ int main(int argc, char* argv[]) g_verbose = true; } + if constexpr (sizeof(vec4) != 16 || + sizeof(vec3) != 12 || + sizeof(vec2) != 8 || + sizeof(COLOR3) != 3 || + sizeof(COLOR4) != 4 ) + { + print_log(PRINT_RED | PRINT_INTENSITY, "sizeof() fatal error!\n"); + return 1; + } + g_progress.simpleMode = false; if (cli.command == "exportobj") diff --git a/src/util/util.cpp b/src/util/util.cpp index 6109acf4..7b27ee87 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -2784,4 +2784,17 @@ float getMaxDistPoints(std::vector& points) } } return maxDistance; +} + +int calcMipsSize(int w, int h) +{ + int sz = 0; + for (int i = 0; i < MIPLEVELS; i++) + { + int div = 1 << i; + int mipWidth = w / div; + int mipHeight = h / div; + sz += mipWidth * mipHeight; + } + return sz; } \ No newline at end of file diff --git a/src/util/util.h b/src/util/util.h index c9779a8b..1312178f 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -348,6 +348,7 @@ vec3 findBestBrushCenter(std::vector& points); float getMaxDistPoints(std::vector& points); +int calcMipsSize(int w, int h); class JackWriter { @@ -386,3 +387,43 @@ class JackWriter { private: std::ofstream file; }; + +class JackReader { +public: + JackReader(const std::string& filename) : file(filename, std::ios::binary) {} + + ~JackReader() { + if (file.is_open()) { + file.close(); + } + } + + template + bool read(T& value) { + file.read(reinterpret_cast(&value), sizeof(T)); + return file.good(); + } + + bool readLenStr(std::string& str) { + int size = 0; + if (!read(size)) { + return false; + } + str.resize(size); + if (size > 0) { + file.read(&str[0], size); + } + return file.good(); + } + + bool readKeyVal(std::string& key, std::string& val) { + return readLenStr(key) && readLenStr(val); + } + + bool is_open() const { + return file && file.is_open(); + } + +private: + std::ifstream file; +}; \ No newline at end of file