diff --git a/cfg/language.ini b/cfg/language.ini index 9da45ac6..a077cce8 100644 --- a/cfg/language.ini +++ b/cfg/language.ini @@ -138,7 +138,7 @@ LANG_0136 = Tex size {}. Tex name "{}". Tex offset {}. Data offset {}. \n LANG_0137 = Unable to show model stats while BSP limits are exceeded.\n LANG_0138 = Classname Targetname Model {:>10} Usage\n LANG_0139 = Data Type Current / Max Fullness\n -LANG_0140 = NODE ({:.2f}, {:.2f}, {:.2f} @ {:.2}\n +LANG_0140 = NODE ({:.2f}, {:.2f}, {:.2f} @ {:.2f})\n LANG_0141 = Invalid hull number. Clipnode hull numbers are 0 - {}\n LANG_0142 = Model {} Hull {} - {}\n LANG_0143 = (LEAF {})\n diff --git a/cfg/language_ru.ini b/cfg/language_ru.ini index 65d1381a..6d78db67 100644 --- a/cfg/language_ru.ini +++ b/cfg/language_ru.ini @@ -138,10 +138,10 @@ LANG_0136 = Размер текстуры {}. Имя текстуры "{}". См LANG_0137 = Невозможно отобразить статистику моделей при превышении лимитов BSP.\n LANG_0138 = Имя класса Имя сущности Модель {:>10} Проц.\n LANG_0139 = Тип данных Текущее / Макс. Лимит\n -LANG_0140 = НОДА ({:.2f}, {:.2f}, {:.2f} @ {:.2}\n +LANG_0140 = NODE ({:.2f}, {:.2f}, {:.2f} @ {:.2f})\n LANG_0141 = Некорректный номер хулла клипнод. Допустимы значения от 0 до {}\n -LANG_0142 = Модель {} ХУЛЛ {} - {}\n -LANG_0143 = (ЛИФ {})\n +LANG_0142 = Модель {} HULL {} - {}\n +LANG_0143 = (LEAF {})\n LANG_0144 = Внимание! Найдена некорректная плоскость. Пропущено.\n LANG_0145 = Внимание! Найдена некорректная нода. Пропущено.\n LANG_0146 = Внимание! Найдена некорректная клипнода. Пропущено.\n @@ -587,7 +587,7 @@ LANG_0587 = Создать LANG_0588 = Точечную сущность LANG_0589 = Проходимую браш-модель LANG_0590 = Браш-модель триггера -LANG_0591 = Плотную браш-модель (солид) +LANG_0591 = Непроходимую браш-модель LANG_0592 = Виджеты LANG_0593 = Ctrl+G LANG_0594 = Журнал событий @@ -786,8 +786,8 @@ LANG_0786 = Особые солиды LANG_0787 = Особые фейсы мира LANG_0788 = Модели LANG_0789 = Анимация моделей -LANG_0790 = Лифы мира -LANG_0791 = Лифы сущностей +LANG_0790 = Клипноды мира +LANG_0791 = Клипноды сущностей LANG_0792 = Прозрачные клипноды LANG_0793 = Текстуры c принудительной прозрачностью: LANG_0794 = Добавить 'прозрачную текстуру' diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index 27f31456..2e002e55 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -1217,7 +1217,7 @@ void Bsp::resize_all_lightmaps(bool logged) newLight.height = size[1]; newLight.layers = lightmap_count(i); - LIGHTMAP & oldLight = newLight; + LIGHTMAP& oldLight = newLight; if (i < undo_lightmaps_count) { oldLight = undo_lightmaps[i]; @@ -1806,7 +1806,7 @@ unsigned int Bsp::remove_unused_visdata(bool* usedLeaves, BSPLEAF32* oldLeaves, int decompressedVisSize = oldLeafCount * oldVisRowSize; unsigned char* decompressedVis = new unsigned char[decompressedVisSize]; memset(decompressedVis, 0xFF, decompressedVisSize); - decompress_vis_lump(this,oldLeaves, lumps[LUMP_VISIBILITY], decompressedVis, + decompress_vis_lump(this, oldLeaves, lumps[LUMP_VISIBILITY], decompressedVis, oldWorldLeaves, oldVisLeafCount - 1, oldVisLeafCount - 1, oldLeavesMemSize, bsp_header.lump[LUMP_VISIBILITY].nLength); if (oldVisRowSize != newVisRowSize) @@ -4302,7 +4302,7 @@ bool Bsp::validate() int decompressedVisSize = leafCount * newVisRowSize; unsigned char* decompressedVis = new unsigned char[decompressedVisSize]; memset(decompressedVis, 0xFF, decompressedVisSize); - decompress_vis_lump(this,leaves, visdata, decompressedVis, + decompress_vis_lump(this, leaves, visdata, decompressedVis, models[0].nVisLeafs, leafCount, leafCount, decompressedVisSize, bsp_header.lump[LUMP_VISIBILITY].nLength); delete decompressedVis; @@ -4520,6 +4520,35 @@ void Bsp::recurse_node(int nodeIdx, int depth) recurse_node(nodes[nodeIdx].iChildren[1], depth + 1); } + +void Bsp::get_last_node(int nodeIdx, int& node, int& count) +{ + if (nodeIdx < 0) + { + return; + } + + count++; + node = nodeIdx; + + get_last_node(nodes[nodeIdx].iChildren[0], node, count); + get_last_node(nodes[nodeIdx].iChildren[1], node, count); +} + +void Bsp::get_last_clipnode(int nodeIdx, int& node, int& count) +{ + if (nodeIdx < 0) + { + return; + } + + count++; + node = nodeIdx; + + get_last_clipnode(clipnodes[nodeIdx].iChildren[0], node, count); + get_last_clipnode(clipnodes[nodeIdx].iChildren[1], node, count); +} + void Bsp::print_node(const BSPNODE32& node) { BSPPLANE& plane = planes[node.iPlane]; @@ -6218,8 +6247,8 @@ void Bsp::copy_bsp_model(int modelIdx, Bsp* targetMap, STRUCTREMAP& remap, std:: memset(face.nStyles, 255, MAX_LIGHTMAPS); } } - - + + newFaces.push_back(face); lightmapAppendSz += lightmapSz * sizeof(COLOR3); @@ -6342,10 +6371,86 @@ int Bsp::duplicate_model(int modelIdx) newModel.iHeadnodes[i] = remap.clipnodes[oldModel.iHeadnodes[i]]; } newModel.nVisLeafs = 0; // techinically should match the old model, but leaves aren't duplicated yet - return newModelIdx; } +int Bsp::add_model_to_worldspawn(int modelIdx) +{ + int newfaces = models[modelIdx].nFaces; + + std::vector all_faces; + + for (int f = 0; f < faceCount; f++) + { + all_faces.push_back(faces[f]); + if (f == models[0].iFirstFace + models[0].nFaces) + { + for (int f2 = 0; f2 < models[modelIdx].nFaces; f2++) + { + all_faces.push_back(faces[models[modelIdx].iFirstFace + f2]); + } + } + } + + for (int m = 1; m < modelCount; m++) + { + if (models[m].iFirstFace >= models[0].iFirstFace + models[0].nFaces) + { + models[m].iFirstFace += newfaces; + } + } + + for (int m = 0; m < nodeCount; m++) + { + if (nodes[m].firstFace >= models[0].iFirstFace + models[0].nFaces) + { + nodes[m].firstFace += newfaces; + } + } + + for (int m = 0; m < marksurfCount; m++) + { + if (marksurfs[m] >= models[0].iFirstFace + models[0].nFaces) + { + marksurfs[m] += newfaces; + } + } + + models[0].nFaces += newfaces; + //models[0].nVisLeafs += models[modelIdx].nVisLeafs; //0 + + int nodecount = 0; + int nodeidx = 0; + get_last_node(models[modelIdx].iHeadnodes[0], nodeidx, nodecount); + nodes[nodeidx].iChildren[0] = nodes[models[modelIdx].iHeadnodes[0]].iChildren[1]; + nodes[nodeidx].iChildren[1] = nodes[models[modelIdx].iHeadnodes[0]].iChildren[0]; + + for (int i = 1; i < MAX_MAP_HULLS; i++) + { + int clipnodecount = 0; + int clipnodeidx = 0; + get_last_clipnode(models[modelIdx].iHeadnodes[i], clipnodeidx, clipnodecount); + clipnodes[clipnodeidx].iChildren[0] = nodes[models[modelIdx].iHeadnodes[i]].iChildren[1]; + clipnodes[clipnodeidx].iChildren[1] = nodes[models[modelIdx].iHeadnodes[i]].iChildren[0]; + } + + unsigned char* newLump = new unsigned char[sizeof(BSPFACE32) * all_faces.size()]; + memcpy(newLump, &all_faces[0], sizeof(BSPFACE32) * all_faces.size()); + replace_lump(LUMP_FACES, newLump, sizeof(BSPFACE32) * all_faces.size()); + + int tmplefs = models[modelIdx].nVisLeafs; + + models[modelIdx].nFaces = 0; + models[modelIdx].nVisLeafs = 0; + models[modelIdx].iHeadnodes[0] = models[modelIdx].iHeadnodes[1] = + models[modelIdx].iHeadnodes[2] = models[modelIdx].iHeadnodes[3] = CONTENTS_EMPTY; + + update_lump_pointers(); + + /*return newModelIdx;*/ + return modelIdx; +} + BSPTEXTUREINFO* Bsp::get_unique_texinfo(int faceIdx) { BSPFACE32& targetFace = faces[faceIdx]; @@ -7069,7 +7174,7 @@ void Bsp::ExportToObjWIP(const std::string& path, ExportObjOrder order, int isca } -void recurse_node(Bsp* map, int nodeIdx) +void recurse_node_map(Bsp* map, int nodeIdx) { if (nodeIdx < 0) { @@ -7078,8 +7183,8 @@ void recurse_node(Bsp* map, int nodeIdx) return; } - recurse_node(map, map->nodes[nodeIdx].iChildren[0]); - recurse_node(map, map->nodes[nodeIdx].iChildren[1]); + recurse_node_map(map, map->nodes[nodeIdx].iChildren[0]); + recurse_node_map(map, map->nodes[nodeIdx].iChildren[1]); } void Bsp::ExportPortalFile() diff --git a/src/bsp/Bsp.h b/src/bsp/Bsp.h index 731031f4..b9e3968b 100644 --- a/src/bsp/Bsp.h +++ b/src/bsp/Bsp.h @@ -126,6 +126,10 @@ class Bsp void print_model_hull(int modelIdx, int hull); void print_clipnode_tree(int iNode, int depth); void recurse_node(int node, int depth); + + void get_last_node(int nodeIdx, int& node, int& count); + void get_last_clipnode(int nodeIdx, int& node, int& count); + int pointContents(int iNode, const vec3& p, int hull, std::vector& nodeBranch, int& leafIdx, int& childIdx); int pointContents(int iNode, const vec3& p, int hull); const char* getLeafContentsName(int contents); @@ -246,6 +250,7 @@ class Bsp std::vector& newClipnodes); int duplicate_model(int modelIdx); + int add_model_to_worldspawn(int modelIdx); // if the face's texinfo is not unique, a new one is created and returned. Otherwise, it's current texinfo is returned BSPTEXTUREINFO* get_unique_texinfo(int faceIdx); diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index bdf75683..cdbe82bc 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -438,7 +438,7 @@ void ExportModel(Bsp* src_map, int id, int ExportType, bool movemodel) while (tmpMap->models[0].nVisLeafs >= tmpMap->leafCount) tmpMap->create_leaf(CONTENTS_EMPTY); - + tmpMap->models[0].nVisLeafs = tmpMap->leafCount - 1; for (int i = 0; i < tmpMap->leafCount; i++) @@ -825,7 +825,24 @@ void Gui::drawBspContexMenu() ImGui::BeginTooltip(); ImGui::TextUnformatted(get_localized_string(LANG_0465).c_str()); ImGui::EndTooltip(); - } + } + + /*if (ImGui::MenuItem("ADD TO WORLDSPAWN!", 0, false, !app->isLoading && allowDuplicate)) + { + print_log(get_localized_string(LANG_1054), app->pickInfo.selectedEnts.size()); + for (auto& ent : app->pickInfo.selectedEnts) + { + if (map->ents[ent]->isBspModel()) + { + map->add_model_to_worldspawn(map->ents[ent]->getBspModelIdx()); + map->ents[ent]->removeKeyvalue("model"); + } + } + map->getBspRender()->loadLightmaps(); + map->getBspRender()->calcFaceMaths(); + map->getBspRender()->preRenderFaces(); + map->getBspRender()->preRenderEnts(); + }*/ } if (ImGui::BeginMenu(get_localized_string(LANG_0466).c_str(), !app->isLoading)) { @@ -2492,6 +2509,23 @@ void Gui::drawMenuBar() } } + /*if (ImGui::MenuItem("ADD TO WORLDSPAWN!", 0, false, !app->isLoading && allowDuplicate)) + { + print_log(get_localized_string(LANG_1054), app->pickInfo.selectedEnts.size()); + for (auto& ent : app->pickInfo.selectedEnts) + { + if (map->ents[ent]->isBspModel()) + { + map->add_model_to_worldspawn(map->ents[ent]->getBspModelIdx()); + map->ents[ent]->removeKeyvalue("model"); + } + } + rend->loadLightmaps(); + rend->calcFaceMaths(); + rend->preRenderFaces(); + rend->preRenderEnts(); + }*/ + if (ImGui::MenuItem(app->movingEnt ? "Ungrab" : "Grab", get_localized_string(LANG_1088).c_str(), false, nonWorldspawnEntSelected)) { if (!app->movingEnt) @@ -2889,7 +2923,7 @@ void Gui::drawMenuBar() } } - if (ImGui::MenuItem(get_localized_string(LANG_0590).c_str(), 0, false, !app->isLoading && map)) + if (ImGui::MenuItem(get_localized_string(LANG_0591).c_str(), 0, false, !app->isLoading && map)) { vec3 origin = cameraOrigin + app->cameraForward * 100; if (app->gridSnappingEnabled) @@ -2897,10 +2931,9 @@ void Gui::drawMenuBar() Entity* newEnt = new Entity(); newEnt->addKeyvalue("origin", origin.toKeyvalueString()); - newEnt->addKeyvalue("classname", "trigger_once"); + newEnt->addKeyvalue("classname", "func_wall"); float snapSize = pow(2.0f, app->gridSnapLevel * 1.0f); - if (snapSize < 16) { snapSize = 16; @@ -2915,12 +2948,14 @@ void Gui::drawMenuBar() if (newEnt && newEnt->getBspModelIdx() >= 0) { BSPMODEL& model = map->models[newEnt->getBspModelIdx()]; - model.iFirstFace = 0; - model.nFaces = 0; + for (int i = 0; i < model.nFaces; i++) + { + map->faces[model.iFirstFace + i].nStyles[0] = 0; + } } } - if (ImGui::MenuItem(get_localized_string(LANG_0591).c_str(), 0, false, !app->isLoading && map)) + if (ImGui::MenuItem(get_localized_string(LANG_0590).c_str(), 0, false, !app->isLoading && map)) { vec3 origin = cameraOrigin + app->cameraForward * 100; if (app->gridSnappingEnabled) @@ -2928,9 +2963,10 @@ void Gui::drawMenuBar() Entity* newEnt = new Entity(); newEnt->addKeyvalue("origin", origin.toKeyvalueString()); - newEnt->addKeyvalue("classname", "func_wall"); + newEnt->addKeyvalue("classname", "trigger_once"); float snapSize = pow(2.0f, app->gridSnapLevel * 1.0f); + if (snapSize < 16) { snapSize = 16; @@ -2945,12 +2981,11 @@ void Gui::drawMenuBar() if (newEnt && newEnt->getBspModelIdx() >= 0) { BSPMODEL& model = map->models[newEnt->getBspModelIdx()]; - for (int i = 0; i < model.nFaces; i++) - { - map->faces[model.iFirstFace + i].nStyles[0] = 0; - } + model.iFirstFace = 0; + model.nFaces = 0; } } + ImGui::EndMenu(); } @@ -5496,7 +5531,7 @@ void Gui::drawLog() ImGui::PushStyleColor(ImGuiCol_Text, imguiColorFromConsole(color_buffer_copy[line_no])); clipper.ItemsHeight = ImGui::GetTextLineHeight(); ImGui::TextUnformatted(log_buffer_copy[line_no].c_str()); - if (line_no + 1 < log_buffer_copy.size() && log_buffer_copy[line_no].size() && log_buffer_copy[line_no][log_buffer_copy[line_no].size() - 1] != '\n') + if (line_no < log_buffer_copy.size() && log_buffer_copy[line_no].size() && log_buffer_copy[line_no][log_buffer_copy[line_no].size() - 1] != '\n') { clipper.ItemsHeight = 0.0f; ImGui::SameLine(); diff --git a/src/editor/Renderer.cpp b/src/editor/Renderer.cpp index b897b142..c6e493ae 100644 --- a/src/editor/Renderer.cpp +++ b/src/editor/Renderer.cpp @@ -349,6 +349,8 @@ void Renderer::renderLoop() glDepthMask(GL_TRUE); glDepthFunc(GL_LESS); + glLineWidth(1.25); + //Update keyboard / mouse state oldLeftMouse = curLeftMouse; curLeftMouse = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);