From 2e2e06bbc5d62dac518de58471a95c767b1160cd Mon Sep 17 00:00:00 2001 From: Unreal Karaulov Date: Mon, 25 Mar 2024 12:42:15 +0300 Subject: [PATCH] XashNT .csm VIEWER [not textures] --- resources/languages/language.ini | 1 + resources/languages/language_ru.ini | 1 + src/bsp/Bsp.cpp | 14 ++++ src/bsp/Bsp.h | 2 + src/editor/Gui.cpp | 21 ++++- src/editor/Renderer.cpp | 14 ++++ src/mdl/mdl_studio.cpp | 2 +- src/mdl/mdl_studio.h | 16 ++-- src/res/Sprite.cpp | 2 +- src/res/Sprite.h | 2 +- src/res/XASH_csm.cpp | 120 +++++++++++++++++++++++++++- src/res/XASH_csm.h | 47 ++++++++++- 12 files changed, 224 insertions(+), 18 deletions(-) diff --git a/resources/languages/language.ini b/resources/languages/language.ini index a7354e81..7d7d3f04 100644 --- a/resources/languages/language.ini +++ b/resources/languages/language.ini @@ -527,6 +527,7 @@ LANG_0524 = Map (.bsp) LANG_0525 = Open map in new Window LANG_0526 = Model (.mdl) OPEN_SPR_VIEW = Sprite (.spr) +OPEN_XASHNT_CSM_VIEW = XashNT (.csm) LANG_0527 = Open model in new Window LANG_0528 = Wad LANG_0529 = Add wad file path to current map diff --git a/resources/languages/language_ru.ini b/resources/languages/language_ru.ini index b879d367..3f458dd2 100644 --- a/resources/languages/language_ru.ini +++ b/resources/languages/language_ru.ini @@ -527,6 +527,7 @@ LANG_0524 = Карту (BSP) LANG_0525 = Открыть карту в новом окне. LANG_0526 = Модель (MDL) OPEN_SPR_VIEW = Спрайт (SPR) +OPEN_XASHNT_CSM_VIEW = XashNT (.csm) LANG_0527 = Открыть модель в новом окне. LANG_0528 = Файл текстур (WAD) LANG_0529 = Указать путь к WAD-файлу для текущей карты. diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index 68a77592..8c244c95 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -111,8 +111,10 @@ Bsp::Bsp() is_protected = false; is_bsp_model = false; is_mdl_model = false; + map_mdl = NULL; map_spr = NULL; + map_csm = NULL; undo_lightmaps.clear(); @@ -150,8 +152,10 @@ Bsp::Bsp(std::string fpath) is_protected = false; is_bsp_model = false; is_mdl_model = false; + map_mdl = NULL; map_spr = NULL; + map_csm = NULL; undo_lightmaps.clear(); @@ -206,6 +210,16 @@ Bsp::Bsp(std::string fpath) init_empty_bsp(); return; } + if (lowerpath.ends_with(".csm")) + { + is_mdl_model = true; + if (fileExists(fpath)) + { + map_csm = AddNewXashCsmToRender(fpath); + } + init_empty_bsp(); + return; + } } if (!fileExists(fpath)) { diff --git a/src/bsp/Bsp.h b/src/bsp/Bsp.h index 2e5c0382..c6041256 100644 --- a/src/bsp/Bsp.h +++ b/src/bsp/Bsp.h @@ -11,6 +11,7 @@ #include "bsptypes.h" #include "mdl_studio.h" #include "Sprite.h" +#include "XASH_csm.h" class BspRenderer; @@ -111,6 +112,7 @@ class Bsp StudioModel* map_mdl; Sprite* map_spr; + CSMFile* map_csm; Bsp* parentMap; void selectModelEnt(); diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index 03b5c19b..64f08714 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -1925,6 +1925,13 @@ void Gui::drawMenuBar() app->addMap(tmpMap); app->selectMap(tmpMap); } + else if (pathlowercase.ends_with(".csm")) + { + Bsp* tmpMap = new Bsp(res.string()); + tmpMap->is_mdl_model = true; + app->addMap(tmpMap); + app->selectMap(tmpMap); + } else { Bsp* tmpMap = new Bsp(res.string()); @@ -2690,7 +2697,6 @@ void Gui::drawMenuBar() ImGui::EndTooltip(); } - if (ImGui::MenuItem(get_localized_string("OPEN_SPR_VIEW").c_str())) { filterNeeded = true; @@ -2704,6 +2710,19 @@ void Gui::drawMenuBar() ImGui::EndTooltip(); } + if (ImGui::MenuItem(get_localized_string("OPEN_XASHNT_CSM_VIEW").c_str())) + { + filterNeeded = true; + ifd::FileDialog::Instance().Open("MapOpenDialog", "Select XashNT CSM path", "XashNT CSM model (*.csm){.csm}", false, g_settings.lastdir); + } + + if (ImGui::IsItemHovered() && g.HoveredIdTimer > g_tooltip_delay) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(get_localized_string(LANG_0527).c_str()); + ImGui::EndTooltip(); + } + if (ImGui::MenuItem(get_localized_string(LANG_0528).c_str())) { filterNeeded = true; diff --git a/src/editor/Renderer.cpp b/src/editor/Renderer.cpp index 75c56848..ee81122a 100644 --- a/src/editor/Renderer.cpp +++ b/src/editor/Renderer.cpp @@ -87,6 +87,11 @@ void drop_callback(GLFWwindow* window, int count, const char** paths) print_log(get_localized_string(LANG_0897), tmpPath.string()); g_app->addMap(new Bsp(tmpPath.string())); } + else if (lowerPath.ends_with(".csm")) + { + print_log(get_localized_string(LANG_0897), tmpPath.string()); + g_app->addMap(new Bsp(tmpPath.string())); + } else { print_log(get_localized_string(LANG_0898), tmpPath.string()); @@ -662,6 +667,15 @@ void Renderer::renderLoop() continue; } + if (SelectedMap->is_mdl_model && SelectedMap->map_csm) + { + matmodel.loadIdentity(); + modelShader->bind(); + modelShader->updateMatrixes(); + SelectedMap->map_csm->draw(); + continue; + } + std::set modelidskip; if (curMap->ents.size() && !isLoading) diff --git a/src/mdl/mdl_studio.cpp b/src/mdl/mdl_studio.cpp index 3df79ef8..8ff6c8c4 100644 --- a/src/mdl/mdl_studio.cpp +++ b/src/mdl/mdl_studio.cpp @@ -1290,7 +1290,7 @@ int StudioModel::SetSkin(int iValue) return iValue; } -std::map mdl_models; +std::map mdl_models; StudioModel* AddNewModelToRender(const std::string& path, unsigned int sum) { diff --git a/src/mdl/mdl_studio.h b/src/mdl/mdl_studio.h index b2973ece..e7cc8216 100644 --- a/src/mdl/mdl_studio.h +++ b/src/mdl/mdl_studio.h @@ -487,6 +487,9 @@ class StudioModel { delete tex; } + + mdl_textures.clear(); + for (int i = 0; i < 32; i++) { if (m_panimhdr[i]) @@ -496,18 +499,15 @@ class StudioModel } for (auto& body : mdl_mesh_groups) { - //for (auto& subbody : body) + for (auto& submesh : body) { - //for (auto& submesh : subbody) - for (auto& submesh : body) + if (submesh.buffer) { - if (submesh.buffer) - { - delete submesh.buffer; - } + delete submesh.buffer; } } } + mdl_mesh_groups.clear(); } void DrawMDL(int mesh = -1); @@ -561,5 +561,5 @@ class StudioModel //float colorData[MAX_VERTS_PER_CALL * 4]; }; -extern std::map mdl_models; +extern std::map mdl_models; StudioModel* AddNewModelToRender(const std::string& path, unsigned int sum = 0); \ No newline at end of file diff --git a/src/res/Sprite.cpp b/src/res/Sprite.cpp index 158faebe..6a8c2b7c 100644 --- a/src/res/Sprite.cpp +++ b/src/res/Sprite.cpp @@ -237,7 +237,7 @@ Sprite::Sprite(const std::string& filename) } -std::map spr_models; +std::map spr_models; Sprite* AddNewSpriteToRender(const std::string& path, unsigned int sum) diff --git a/src/res/Sprite.h b/src/res/Sprite.h index d3688b88..feb27900 100644 --- a/src/res/Sprite.h +++ b/src/res/Sprite.h @@ -88,5 +88,5 @@ class Sprite { void TestSprite(); -extern std::map spr_models; +extern std::map spr_models; Sprite* AddNewSpriteToRender(const std::string & path, unsigned int sum = 0); \ No newline at end of file diff --git a/src/res/XASH_csm.cpp b/src/res/XASH_csm.cpp index 24b35388..73cf19fd 100644 --- a/src/res/XASH_csm.cpp +++ b/src/res/XASH_csm.cpp @@ -1,6 +1,9 @@ #include "XASH_csm.h" #include "util.h" #include "log.h" +#include "forcecrc32.h" +#include "Settings.h" +#include "Renderer.h" void CSMFile::parseMaterialsFromString(const std::string& materialsStr) { @@ -27,11 +30,29 @@ std::string CSMFile::getStringFromMaterials() CSMFile::CSMFile() { readed = false; + for (auto& m : model) + delete m; + model.clear(); } CSMFile::CSMFile(std::string path) { readed = read(path); + for (auto& m : model) + delete m; + model.clear(); +} + +CSMFile::~CSMFile() +{ + for (auto& tex : mat_textures) + { + delete tex; + } + mat_textures.clear(); + for (auto& m : model) + delete m; + model.clear(); } bool CSMFile::validate() @@ -170,13 +191,13 @@ bool CSMFile::write(const std::string& filePath) { header.version = IDCSM_VERSION; std::string matstr = getStringFromMaterials(); - + header.mat_size = (unsigned int)matstr.size() + 1; header.vertex_size = sizeof(csm_vertex); header.face_size = sizeof(csm_face); header.mat_ofs = sizeof(csm_header); - header.vertex_ofs = header.mat_ofs + header.mat_size ; + header.vertex_ofs = header.mat_ofs + header.mat_size; header.faces_ofs = header.vertex_ofs + (header.vertex_size * header.vertex_count); file.write(reinterpret_cast(&header), sizeof(header)); @@ -192,3 +213,98 @@ bool CSMFile::write(const std::string& filePath) { file.close(); return true; } + +void CSMFile::upload() +{ + for (auto& m : model) + delete m; + model.clear(); + + if (readed) + { + for (auto& f : faces) + { + bool added = false; + + for (auto& m : model) + { + if (m->matid == f.matIdx) + { + added = true; + for (int i = 0; i < 3; i++) + { + modelVert tmpVert; + tmpVert.pos = vertices[f.vertIdx[i]].point.flip(); + tmpVert.u = f.uvs->uv[i].x; + tmpVert.v = f.uvs->uv[i].y; + m->verts.push_back(tmpVert); + } + break; + } + } + + if (!added) + { + CSM_MDL_MESH* tmpModel = new CSM_MDL_MESH(); + tmpModel->matid = f.matIdx; + tmpModel->buffer = new VertexBuffer(g_app->modelShader, NULL, 0, GL_TRIANGLES); + + for (int i = 0; i < 3; i++) + { + modelVert tmpVert; + tmpVert.pos = vertices[f.vertIdx[i]].point.flip(); + tmpVert.u = f.uvs->uv[i].x; + tmpVert.v = f.uvs->uv[i].y; + tmpModel->verts.push_back(tmpVert); + } + + model.push_back(tmpModel); + } + } + } + + if (model.size()) + { + for (auto& m : model) + { + m->buffer->setData(&m->verts[0], m->verts.size()); + m->buffer->uploaded = false; + } + } +} + +void CSMFile::draw() +{ + if (!model.size()) + { + upload(); + } + + if (model.size()) + { + missingTex->bind(0); + for (auto& m : model) + { + if (m && m->buffer) + m->buffer->drawFull(); + } + } +} + + +std::map csm_models; +CSMFile* AddNewXashCsmToRender(const std::string& path, unsigned int sum) +{ + unsigned int crc32 = GetCrc32InMemory((unsigned char*)path.data(), (unsigned int)path.size(), sum); + + if (csm_models.find(crc32) != csm_models.end()) + { + return csm_models[crc32]; + } + else + { + CSMFile* newModel = new CSMFile(path); + csm_models[crc32] = newModel; + return newModel; + } +} \ No newline at end of file diff --git a/src/res/XASH_csm.h b/src/res/XASH_csm.h index e2860d8b..4591faca 100644 --- a/src/res/XASH_csm.h +++ b/src/res/XASH_csm.h @@ -1,7 +1,12 @@ #pragma once -#include "vectors.h" #include #include +#include + +#include "vectors.h" +#include "Texture.h" +#include "VertexBuffer.h" +#include "primitives.h" // enumerate coordinate channels @@ -76,6 +81,29 @@ struct csm_face #pragma pack(pop) +struct CSM_MDL_MESH +{ + VertexBuffer* buffer; + unsigned int matid; + std::vector verts; + CSM_MDL_MESH() + { + buffer = NULL; + matid = 0; + verts = std::vector(); + } + ~CSM_MDL_MESH() + { + if (buffer) + { + delete buffer; + } + buffer = NULL; + matid = 0; + verts = std::vector(); + } +}; + #define IDCSMMODHEADER (('M'<<24)+('S'<<16)+('C'<<8)+'I') // little-endian "ICSM" #define IDCSM_VERSION 2 @@ -85,16 +113,20 @@ struct csm_face class CSMFile { private: bool readed; + std::vector mat_textures; + std::vector model; void parseMaterialsFromString(const std::string& materialsStr); - std::string getStringFromMaterials(); - + void upload(); + public: CSMFile(); CSMFile(std::string path); + ~CSMFile(); + csm_header header; std::vector materials; @@ -104,4 +136,11 @@ class CSMFile { bool validate(); bool read(const std::string& filePath); bool write(const std::string& filePath); -}; \ No newline at end of file + + void draw(); +}; + + + +extern std::map csm_models; +CSMFile* AddNewXashCsmToRender(const std::string& path, unsigned int sum = 0); \ No newline at end of file