diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index e4a831d7..688b7b02 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -9423,7 +9423,7 @@ void Bsp::ExportToSmdWIP(const std::string& path, bool split, bool oneRoot) renderer->pushModelUndoState("EXPORT .SMD EDITED", EDIT_MODEL_LUMPS | FL_ENTITIES); } -void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, bool with_mdl, bool export_csm) +void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, bool with_mdl, bool export_csm, int grouping) { if (!createDir(path)) { @@ -9475,7 +9475,7 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, int normoffset = 0; int materialid = -1; - int lastmaterialid = 0; + int lastmaterialid = -2; std::set refreshedModels; @@ -9615,10 +9615,12 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, if (materialid == -1) { materialid = (int)matnames.size(); + matnames.emplace_back(tex.szName); + if (!export_csm) { materials.emplace_back(""); - materials.emplace_back("newmtl " + materialid); + materials.emplace_back("newmtl " + matnames[materialid]); materials.emplace_back("Ns 0"); materials.emplace_back("Ka 1 1 1"); @@ -9649,8 +9651,6 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, materials.emplace_back("map_Kd " + std::string("textures/") + tex.szName + std::string(".bmp")); } - matnames.emplace_back(tex.szName); - if (export_csm) { csm_export->materials.push_back(std::string("textures/") + tex.szName + std::string(".bmp")); @@ -9736,16 +9736,16 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, vec3 origin_offset = ent->origin.flip(); - if ("Model_" + std::to_string(mdlid) + "_ent_" + std::to_string(tmpentid) != groupname) + std::string next_group_name = "M_" + std::to_string(mdlid) + "_ENT_" + std::to_string(tmpentid); + + if (next_group_name != groupname) { - groupname = "Model_" + std::to_string(mdlid) + "_ent_" + std::to_string(tmpentid); + groupname = next_group_name; if (std::find(group_list.begin(), group_list.end(), groupname) == group_list.end()) group_list.push_back(groupname); csm_groups++; - - //print_log(PRINT_RED, "Entity {} angles {}\n", tmpentid, rendEnt->angles.toKeyvalueString()); } mat4x4 angle_mat; @@ -9790,8 +9790,6 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, org_pos *= scale; group_verts[groupname] << "v " << org_pos.toKeyvalueString() << "\n"; - - } group_normals[groupname] << "vn " << org_norm.toKeyvalueString() << "\n"; @@ -9876,8 +9874,14 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, if (lastmaterialid != materialid) { group_vert_groups[groupname]++; - - //group_objects[groupname] << "g " << groupname << "_face" << group_vert_groups[groupname] << "\n"; + if (grouping == 1) + { + group_objects[groupname] << "g " << groupname << "_f" << group_vert_groups[groupname] << "\n"; + } + else if (grouping == 2) + { + group_objects[groupname] << "o " << groupname << "_f" << group_vert_groups[groupname] << "\n"; + } if (!export_csm) { if (materialid >= 0) @@ -9886,6 +9890,7 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, } } } + lastmaterialid = materialid; if (!export_csm) @@ -9916,7 +9921,10 @@ void Bsp::ExportToObjWIP(const std::string& path, int iscale, bool lightmapmode, for (auto& group : group_list) { - obj_file << "o " << group << "\n"; + if (grouping == 0 || grouping == 1) + obj_file << "o " << group << "\n"; + else if (grouping == 2) + obj_file << "g " << group << "\n"; obj_file << group_verts[group].str(); diff --git a/src/bsp/Bsp.h b/src/bsp/Bsp.h index 9c2e678a..e2c9e8f4 100644 --- a/src/bsp/Bsp.h +++ b/src/bsp/Bsp.h @@ -329,7 +329,7 @@ class Bsp void ExportToSmdWIP(const std::string& path, bool split, bool oneRoot); - void ExportToObjWIP(const std::string& path, int iscale = 1, bool lightmap_mode = false, bool with_mdl = false, bool export_csm = false); + void ExportToObjWIP(const std::string& path, int iscale = 1, bool lightmap_mode = false, bool with_mdl = false, bool export_csm = false, int grouping = 0); void ExportToMapWIP(const std::string& path, bool selected, bool merge_faces, bool use_one_back_vert); diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index 5c19f8e5..466ac7b2 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -2810,9 +2810,11 @@ void Gui::drawMenuBar() static int g_scale = 1; + static bool g_group_faces = false; + static bool g_group_as_objects = false; + if (ImGui::BeginMenu("Wavefront(.obj)/XashNT(.csm) [WIP]", map && !map->is_mdl_model)) { - if (ImGui::BeginMenu("Select scale")) { if (ImGui::MenuItem(get_localized_string(LANG_0535).c_str(), NULL, g_scale == 1)) @@ -2841,32 +2843,43 @@ void Gui::drawMenuBar() ImGui::EndMenu(); } - if (ImGui::BeginMenu("Export only bsp")) + if (ImGui::MenuItem("Create face groups[OBJ]", NULL, &g_group_faces)) + { + if (g_group_faces) + g_group_as_objects = !g_group_faces; + } + + if (ImGui::MenuItem("Create face objects[OBJ]", NULL, &g_group_as_objects)) + { + if (g_group_faces) + g_group_faces = !g_group_as_objects; + } + + if (ImGui::BeginMenu("Export .obj")) { - if (ImGui::MenuItem("Export .obj")) + if (ImGui::MenuItem("Export only bsp")) { - map->ExportToObjWIP(g_working_dir, g_scale); + map->ExportToObjWIP(g_working_dir, g_scale, false, false, false, !g_group_faces && + !g_group_as_objects ? 0 : (g_group_faces ? 1 : 2)); } - if (ImGui::MenuItem("Export .csm")) + if (ImGui::MenuItem("Export with models")) { - map->ExportToObjWIP(g_working_dir, g_scale, false, false, true); + map->ExportToObjWIP(g_working_dir, g_scale, false, true); } ImGui::EndMenu(); } - - if (ImGui::BeginMenu("Export with models")) + if (ImGui::BeginMenu("Export .csm")) { - if (ImGui::MenuItem("Export .obj")) + if (ImGui::MenuItem("Export only bsp")) { - map->ExportToObjWIP(g_working_dir, g_scale, false, true); + map->ExportToObjWIP(g_working_dir, g_scale, false, false, true); } - if (ImGui::MenuItem("Export .csm")) + if (ImGui::MenuItem("Export with models")) { map->ExportToObjWIP(g_working_dir, g_scale, false, true, true); } ImGui::EndMenu(); } - ImGui::EndMenu(); } @@ -3258,7 +3271,7 @@ void Gui::drawMenuBar() if (fileSize(g_settings_path) == 0) { print_log(PRINT_RED | PRINT_INTENSITY, get_localized_string(LANG_0359)); - } + } else { glfwTerminate(); @@ -3268,10 +3281,10 @@ void Gui::drawMenuBar() #else std::quick_exit(0); #endif - } - } + } + } ImGui::EndMenu(); -} + } if (ImGui::BeginMenu(get_localized_string(LANG_0556).c_str(), (map && !map->is_mdl_model))) { @@ -5244,7 +5257,7 @@ void Gui::drawMenuBar() } ImGui::EndMainMenuBar(); - } +} if (ImGui::BeginViewportSideBar("BottomBar", ImGui::GetMainViewport(), ImGuiDir_Down, ImGui::GetTextLineHeightWithSpacing(), ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar)) { @@ -8127,7 +8140,7 @@ void Gui::drawSettings() ImGui::TextUnformatted(get_localized_string(LANG_0740).c_str()); ImGui::EndTooltip(); } - } + } else if (settingsTab == 1) { for (size_t i = 0; i < g_settings.fgdPaths.size(); i++) @@ -8655,7 +8668,7 @@ void Gui::drawSettings() ImGui::EndChild(); ImGui::EndGroup(); - } + } ImGui::End(); @@ -8679,7 +8692,7 @@ void Gui::drawSettings() } oldShowSettings = showSettingsWidget = apply_settings_pressed; } - } +} void Gui::drawHelp() { diff --git a/src/util/util.h b/src/util/util.h index c94f11a2..f34954d4 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -508,6 +508,7 @@ struct csm_face #define IDCSM_VERSION 2 + class CSMFile { private: bool readed; @@ -516,11 +517,9 @@ class CSMFile { { std::istringstream ss(materialsStr); std::string material; - while (ss.str().find('"', (size_t)ss.tellg()) != std::string::npos && ss >> std::quoted(material)) { materials.push_back(material); - material.clear(); } } @@ -535,15 +534,10 @@ class CSMFile { ret.pop_back(); return ret; } - + public: - CSMFile() { - header = {}; - materials = {}; - vertices = {}; - faces = {}; readed = false; } @@ -563,24 +557,24 @@ class CSMFile { if (header.face_size != sizeof(csm_face)) { print_log(PRINT_RED, "Error: Invalid CSM header face size {}!\n", header.face_size); - //return false; + return false; } if (header.vertex_size != sizeof(csm_vertex)) { print_log(PRINT_RED, "Error: Invalid CSM header vertex size {}!\n", header.vertex_size); - //return false; + return false; } if (!faces.size() || !vertices.size()) { print_log(PRINT_RED, "Error: Empty CSM structure!\n"); - //return false; + return false; } for (auto& f : faces) { if (f.matIdx >= materials.size()) { print_log(PRINT_RED, "Error: Invalid matIdx in face!\n"); - // return false; + return false; } for (int i = 0; i < 3; i++) @@ -588,7 +582,7 @@ class CSMFile { if (f.vertIdx[i] >= vertices.size()) { print_log(PRINT_RED, "Error: Invalid vertIdx[{}] in face = {}! Vertices: {}\n", i, f.vertIdx[i], vertices.size()); - // return false; + return false; } } } @@ -678,7 +672,7 @@ class CSMFile { bool write(const std::string& filePath) { std::ofstream file(filePath, std::ios::binary); if (!file) { - std::cerr << "Failed to open file for writing: " << filePath << std::endl; + print_log(PRINT_RED, "Error: Failed to open file for writing: {}\n", filePath); return false; }