From a33d7f3c86d3559f45bdaf09656697f8c470e051 Mon Sep 17 00:00:00 2001 From: Tim Nebel Date: Mon, 28 Aug 2023 21:23:47 +0200 Subject: [PATCH] Post big vgcore upgrade push --- CMakeLists.txt | 5 +- Tools/MapTools/include/Element.h | 6 +- Tools/MapTools/include/Rail.h | 2 +- Tools/MapTools/src/Element.cpp | 4 +- Tools/MapTools/src/Rail.cpp | 6 +- src/Config/Configs.cpp | 1 + src/Config/Configs.h | 1 + src/MainViewport.cpp | 126 +++++++++++++++++-------------- src/MainViewport.h | 10 ++- src/MainWindow.cpp | 11 ++- src/Model.cpp | 12 +-- src/PropertiesWidget.cpp | 10 +-- 12 files changed, 103 insertions(+), 91 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a95f62..9cb9624 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,12 +10,11 @@ add_subdirectory(deps/vgcore) add_subdirectory(Tools/MapTools) add_executable(SpoonEdit src/main.cpp src/MainWindow.cpp src/MainWindow.h src/PropertiesWidget.cpp src/PropertiesWidget.h src/ObjectSelectWidget.cpp src/ObjectSelectWidget.h src/MainViewport.cpp src/MainViewport.h src/Model.cpp src/Model.h src/RailSelectWidget.cpp src/RailSelectWidget.h src/Config/Configs.h src/Config/Configs.cpp) +set(CMAKE_CXX_FLAGS_DEBUG "-g") +set(CMAKE_CXX_FLAGS_RELEASE "-O3") target_link_libraries(SpoonEdit PUBLIC GCore SpoonMapTools Boost::thread Boost::chrono) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") - install(TARGETS SpoonEdit CONFIGURATIONS Debug RUNTIME DESTINATION Debug diff --git a/Tools/MapTools/include/Element.h b/Tools/MapTools/include/Element.h index 7a4c3fd..eac8909 100644 --- a/Tools/MapTools/include/Element.h +++ b/Tools/MapTools/include/Element.h @@ -79,7 +79,7 @@ inline LayerConfig ToLayerConfig(std::string cfg){ return Day; } else if(cfg == "Tmp") { return Temporary; - } + } else return Temporary; } class Element{ @@ -95,9 +95,9 @@ public: std::string ModelName = "null"; - LayerConfig Layer = Common; + std::string Layer = "Cmn"; - std::vector Parameters = std::vector(); + std::vector Parameters = std::vector(); std::vector FloatParameters = std::vector(); //std::map> Links = std::map>(); diff --git a/Tools/MapTools/include/Rail.h b/Tools/MapTools/include/Rail.h index a4d36a4..714427c 100644 --- a/Tools/MapTools/include/Rail.h +++ b/Tools/MapTools/include/Rail.h @@ -43,7 +43,7 @@ struct Rail: public Element{ std::list Points = std::list(); - RailType RailType = Linear; + RailType m_railType = RailType::Linear; bool IsClosed = false; bool IsLadder = false; long Priority = 100; diff --git a/Tools/MapTools/src/Element.cpp b/Tools/MapTools/src/Element.cpp index a68d3ca..f560adc 100644 --- a/Tools/MapTools/src/Element.cpp +++ b/Tools/MapTools/src/Element.cpp @@ -24,7 +24,7 @@ Element::Element(const YAML::Node &ObjNode,std::list PropertyBlockL TF.Rotation = ObjNode["Rotate"]; TF.Scale = ObjNode["Scale"]; - Layer = ToLayerConfig(ObjNode["LayerConfigName"].as()); + Layer = ObjNode["LayerConfigName"].as(); ModelName = ObjNode["ModelName"].as(); IsLinkDest = ObjNode["IsLinkDest"].as(); @@ -89,7 +89,7 @@ void Element::YamlInsertBody(YAML::Emitter &Emitter) { Emitter << YAML::Key << "UnitConfigName" << YAML::Value << Type; - Emitter << YAML::Key << "LayerConfigName" << YAML::Value << ToStringYaml(Layer); + Emitter << YAML::Key << "LayerConfigName" << YAML::Value << Layer; if(ModelName == "null") { Emitter << YAML::Key << "ModelName" << YAML::Value << YAML::LowerNull << YAML::Null; } else { diff --git a/Tools/MapTools/src/Rail.cpp b/Tools/MapTools/src/Rail.cpp index fceffe5..ab1a084 100644 --- a/Tools/MapTools/src/Rail.cpp +++ b/Tools/MapTools/src/Rail.cpp @@ -2,14 +2,14 @@ -Rail::Rail(const YAML::Node &ObjNode) : Element(ObjNode, {"RailPoints","RailType","IsClosed","IsLadder","Priority"}) { +Rail::Rail(const YAML::Node &ObjNode) : Element(ObjNode, {"RailPoints","m_railType","IsClosed","IsLadder","Priority"}) { YAML::Node railPointsNode = ObjNode["RailPoints"]; for (auto rlpoint: railPointsNode) { Points.emplace_back(rlpoint); } - RailType = ToRailType(ObjNode["RailType"].as()); + m_railType = ToRailType(ObjNode["RailType"].as()); IsClosed = ObjNode["IsClosed"].as(); IsLadder = ObjNode["IsLadder"].as(); Priority = ObjNode["Priority"].as(); @@ -31,7 +31,7 @@ void Rail::YamlInsertBody(YAML::Emitter &Emitter) { } Emitter << YAML::EndSeq; - Emitter << YAML::Key << "RailType" << YAML::Key << ToString(RailType); + Emitter << YAML::Key << "RailType" << YAML::Key << ToString(m_railType); Emitter << YAML::Key << "IsClosed" << YAML::Key << IsClosed; Emitter << YAML::Key << "IsLadder" << YAML::Key << IsLadder; Emitter << YAML::Key << "Priority" << YAML::Key << YAML::LocalTag("l") << Priority; diff --git a/src/Config/Configs.cpp b/src/Config/Configs.cpp index 401179a..96dd7bb 100644 --- a/src/Config/Configs.cpp +++ b/src/Config/Configs.cpp @@ -37,6 +37,7 @@ namespace Configs { g_areas = loadStringListConfig(gameCfgPath / "Areas.yaml"); g_dropIdOpts = loadValueDisplayConfig(gameCfgPath / "DropIds.yaml"); g_teams = loadValueDisplayConfig(gameCfgPath / "Teams.yaml"); + g_layers = loadValueDisplayConfig(gameCfgPath / "Layers.yaml"); } diff --git a/src/Config/Configs.h b/src/Config/Configs.h index eae797d..573f99a 100644 --- a/src/Config/Configs.h +++ b/src/Config/Configs.h @@ -50,6 +50,7 @@ namespace Configs { inline std::vector g_areas; inline std::vector> g_dropIdOpts; inline std::vector> g_teams; + inline std::vector> g_layers; diff --git a/src/MainViewport.cpp b/src/MainViewport.cpp index 10fb9be..3ad6afd 100644 --- a/src/MainViewport.cpp +++ b/src/MainViewport.cpp @@ -72,8 +72,12 @@ MainViewport::MainViewport() : Graphics::ViewportWidget("Main Viewport", true), //ObjMesh = Graphics::Mesh(); - GLint ObjColPos = m_internalFramebuf->m_shader.getUniformLocation("ObjColor"); - glUniform4f(ObjColPos, 1, 1, 1, 1); + ObjIdPos = m_internalFramebuf->m_shader.getUniformLocation("ObjIdIn"); + ObjColPos = m_internalFramebuf->m_shader.getUniformLocation("ObjColor"); + TeamId = m_internalFramebuf->m_shader.getUniformLocation("TeamId"); + CamPosLoc = m_internalFramebuf->m_shader.getUniformLocation("CameraPosition"); + LightDirId = m_internalFramebuf->m_shader.getUniformLocation("LightDirection"); + SunVpLoc = m_internalFramebuf->m_shader.getUniformLocation("SunVP"); } @@ -99,12 +103,7 @@ void MainViewport::Draw() { m_internalFramebuf->m_shader.use(); - GLint ObjIdPos = m_internalFramebuf->m_shader.getUniformLocation("ObjIdIn"); - GLint ObjColPos = m_internalFramebuf->m_shader.getUniformLocation("ObjColor"); - GLint TeamId = m_internalFramebuf->m_shader.getUniformLocation("TeamId"); - - GLint CamPosLoc = m_internalFramebuf->m_shader.getUniformLocation("CameraPosition"); static auto lasttime = boost::chrono::high_resolution_clock::now(); @@ -193,6 +192,13 @@ void MainViewport::Draw() { m_internalFramebuf->m_shader = flatShader; + ObjIdPos = m_internalFramebuf->m_shader.getUniformLocation("ObjIdIn"); + ObjColPos = m_internalFramebuf->m_shader.getUniformLocation("ObjColor"); + TeamId = m_internalFramebuf->m_shader.getUniformLocation("TeamId"); + CamPosLoc = m_internalFramebuf->m_shader.getUniformLocation("CameraPosition"); + LightDirId = m_internalFramebuf->m_shader.getUniformLocation("LightDirection"); + SunVpLoc = m_internalFramebuf->m_shader.getUniformLocation("SunVP"); + flatShading = !flatShading; } ImGui::EndPopup(); @@ -200,12 +206,12 @@ void MainViewport::Draw() { m_internalFramebuf->m_shader.use(); - GLint LightDirId = m_internalFramebuf->m_shader.getUniformLocation("LightDirection"); - glUniform3f(LightDirId, LightDir.x , LightDir.y,LightDir.z); - + if(!flatShading) + glUniform3f(LightDirId, LightDir.x , LightDir.y,LightDir.z); + glUniform4f(ObjColPos, 1, 1, 1, 1); auto &map = GetMainWindow()->loadedMap; @@ -222,66 +228,79 @@ void MainViewport::Draw() { unsigned int ObjID = 16; + if(!flatShading) { + glm::vec3 SunPos = (glm::normalize(LightDir) * 1500.0f) + camPos; - glm::vec3 SunPos = (glm::normalize(LightDir) * 1500.0f) + camPos; + glm::mat4 SunProj = glm::ortho(-shadowArea, shadowArea, -shadowArea, shadowArea, 1.0f, 4000.0f); - glm::mat4 SunProj = glm::ortho(-shadowArea,shadowArea,-shadowArea,shadowArea,1.0f,4000.0f); + glm::mat4 SunView = glm::lookAt(SunPos, camPos, {0, 1, 0}); - glm::mat4 SunView = glm::lookAt(SunPos,camPos,{0,1,0}); + glm::mat4 SunVP = SunProj * SunView; - glm::mat4 SunVP = SunProj * SunView; + SunCam->bind(); + SunCam->m_shader.use(); - SunCam->bind(); - SunCam->m_shader.use(); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); + glDisable(GL_BLEND); - glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); - for (auto &obj: map.Objects) { - if (IsArea(obj.Type)) { - continue; - } - - if (!MdlFromObj.contains(obj.Type)) { - if (boost::filesystem::exists( - boost::filesystem::current_path() / "Models" / obj.Type / (obj.Type + ".dae"))) - MdlFromObj.insert({obj.Type, Model(obj.Type)}); - else { - MdlFromObj.insert({obj.Type, Model("St_Default")}); - std::cout << "Model missing: \n\t" << obj.Type << std::endl; + for (auto &obj: map.Objects) { + if (IsArea(obj.Type)) { + continue; } + + if (!MdlFromObj.contains(obj.Type)) { + if (boost::filesystem::exists( + boost::filesystem::current_path() / "Models" / obj.Type / (obj.Type + ".dae"))) + MdlFromObj.insert({obj.Type, Model(obj.Type)}); + else { + MdlFromObj.insert({obj.Type, Model("St_Default")}); + std::cout << "Model missing: \n\t" << obj.Type << std::endl; + } + } + + + auto &mdl = MdlFromObj.find(obj.Type)->second; + + mdl.Draw(obj.TF, SunCam->m_shader, SunVP); } + m_internalFramebuf->bind(); + m_internalFramebuf->m_shader.use(); - auto &mdl = MdlFromObj.find(obj.Type)->second; + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); - mdl.Draw(obj.TF, SunCam->m_shader, SunVP); + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + auto &tex = SunCam->getFbTexByAttachment(GL_DEPTH_ATTACHMENT); + tex.m_texture->setActive(5); + + + + glUniformMatrix4fv(SunVpLoc,1,GL_FALSE,&SunVP[0][0]); } - m_internalFramebuf->bind(); - m_internalFramebuf->m_shader.use(); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); - auto &tex = SunCam->getFbTexByAttachment(GL_DEPTH_ATTACHMENT); - tex.m_texture->setActive(5); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - GLint SunVpLoc = m_internalFramebuf->m_shader.getUniformLocation("SunVP"); - - glUniformMatrix4fv(SunVpLoc,1,GL_FALSE,&SunVP[0][0]); for (auto &obj: map.Objects) { - glUniform1i(TeamId,(GLint)obj.Team); + if(!flatShading) + glUniform1i(TeamId,(GLint)obj.Team); if (IsArea(obj.Type) && !drawAllAreas) { ObjID++; @@ -289,7 +308,6 @@ void MainViewport::Draw() { } else if (IsArea(obj.Type) && drawAllAreas) { static auto AreaMdl = Model("St_Area"); glUniform1ui(ObjIdPos, ObjID); - glUniform4f(ObjColPos, 1, 1, 1, 1); AreaMdl.Draw(obj.TF, m_internalFramebuf->m_shader, VP); ObjID++; continue; @@ -308,12 +326,13 @@ void MainViewport::Draw() { auto &mdl = MdlFromObj.find(obj.Type)->second; glUniform1ui(ObjIdPos, ObjID); - glUniform4f(ObjColPos, 1, 1, 1, 1); if (&obj == GetMainWindow()->selectedElem) glUniform4f(ObjColPos, 1, .7, .7, 1); mdl.Draw(obj.TF, m_internalFramebuf->m_shader, VP); + if (&obj == GetMainWindow()->selectedElem) + glUniform4f(ObjColPos, 1, 1, 1, 1); ObjID++; } @@ -321,19 +340,17 @@ void MainViewport::Draw() { if (GetMainWindow()->selectedElem != nullptr) { auto selobj = GetMainWindow()->selectedElem; + glUniform1ui(ObjIdPos, 0); if (IsArea(selobj->Type)) { static auto AreaMdl = Model("St_Area"); - glUniform1ui(ObjIdPos, 0); - AreaMdl.Draw(selobj->TF, m_internalFramebuf->m_shader, VP); } glClear(GL_DEPTH_BUFFER_BIT); for (Link &link: GetMainWindow()->selectedElem->Links) { - glUniform1ui(ObjIdPos, 0); Element *elem = GetMainWindow()->loadedMap.GetElementById(link.Destination); if (elem == nullptr) continue; @@ -344,15 +361,14 @@ void MainViewport::Draw() { } if (Rail *rail = dynamic_cast(GetMainWindow()->selectedElem)) { - glUniform1ui(ObjIdPos, 0); RenderRail(rail); } //mdl.DrawSelection(selobj->TF); - glClear(GL_DEPTH_BUFFER_BIT); + //glClear(GL_DEPTH_BUFFER_BIT); - if (CurrentGizmoType == Move) { + /*if (CurrentGizmoType == Move) { static Model Arrow = Model("St_Arrow"); auto tf = Transform(); @@ -445,12 +461,10 @@ void MainViewport::Draw() { Rotator.Draw(tf, m_internalFramebuf->m_shader, VP); glUniform4f(ObjColPos, 1, 1, 1, 1); - } + }*/ } - - glDisable(GL_DEPTH_TEST); } template diff --git a/src/MainViewport.h b/src/MainViewport.h index d21b07f..9d423d3 100644 --- a/src/MainViewport.h +++ b/src/MainViewport.h @@ -55,7 +55,7 @@ private: unsigned int HoveredObjId = 0; - std::map MdlFromObj; + std::unordered_map MdlFromObj; float FarClippingPlane = 10000.0f; float NearClippingPlane = 0.1f; @@ -79,6 +79,14 @@ public: private: void Draw() override; + + //GLUniform Location Cache + GLint ObjIdPos; + GLint ObjColPos; + GLint TeamId; + GLint CamPosLoc; + GLint LightDirId; + GLint SunVpLoc; }; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 669365b..ee76dfe 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -126,7 +126,7 @@ MainWindow::MainWindow(): Graphics::Window("SpoonEdit") { ObjCpy.TF.Rotation = {0, 0, 0}; ObjCpy.TF.Position = {0, 0, 0}; - for(long ¶m: ObjCpy.Parameters){ + for(int ¶m: ObjCpy.Parameters){ param = -99; } @@ -134,7 +134,7 @@ MainWindow::MainWindow(): Graphics::Window("SpoonEdit") { param = -99.0f; } - ObjCpy.Layer = Common; + ObjCpy.Layer = "Cmn"; ExportObj(ObjCpy); } @@ -156,7 +156,7 @@ MainWindow::MainWindow(): Graphics::Window("SpoonEdit") { ObjCpy.Name = ObjCpy.Type; ObjCpy.Links = std::vector(); - for(long ¶m: ObjCpy.Parameters){ + for(int ¶m: ObjCpy.Parameters){ param = -99; } @@ -164,7 +164,7 @@ MainWindow::MainWindow(): Graphics::Window("SpoonEdit") { param = -99.0f; } - ObjCpy.Layer = Common; + ObjCpy.Layer = "Cmn"; ObjCpy.TF.Scale = {1, 1, 1}; ObjCpy.TF.Rotation = {0, 0, 0}; @@ -182,8 +182,7 @@ MainWindow::MainWindow(): Graphics::Window("SpoonEdit") { Configs::g_loadConfigs("Gambit"); - glfwMakeContextCurrent(GetGlfwWindow()); - glfwSwapInterval(0); + //Graphics::EnableVsync(); } void MainWindow::Update() { diff --git a/src/Model.cpp b/src/Model.cpp index 49765e9..11ba085 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -91,19 +91,13 @@ void Model::Draw(const Transform &tf, Graphics::Shader &shader, const glm::mat4 glm::vec3 scale(tf.Scale.X,tf.Scale.Y,tf.Scale.Z); glm::mat4 translationMatrix = glm::translate(glm::mat4(1),glm::vec3(pos.x,pos.y,pos.z)); - glm::mat4 translationNoYInvertMatrix = glm::translate(glm::mat4(1),glm::vec3(pos.x,pos.y,pos.z)); glm::mat4 rotationMatrixZ = glm::rotate(glm::mat4(1),glm::radians(rot.z), glm::vec3(0,0,1)); glm::mat4 rotationMatrixY = glm::rotate(rotationMatrixZ,glm::radians(rot.y), glm::vec3(0,1,0)); glm::mat4 rotationMatrix = glm::rotate(rotationMatrixY,glm::radians(rot.x), glm::vec3(1,0,0)); - - glm::mat4 nrmRotationMatrixZ = glm::rotate(glm::mat4(1),glm::radians(normalRot.z), glm::vec3(0,0,1)); - glm::mat4 nrmRotationMatrixY = glm::rotate(nrmRotationMatrixZ,glm::radians(normalRot.y), glm::vec3(0,1,0)); - glm::mat4 nrmRotationMatrix = glm::rotate(nrmRotationMatrixY,glm::radians(normalRot.x), glm::vec3(1,0,0)); glm::mat4 scaleMatrix = glm::scale(glm::mat4(1),scale); glm::mat4 matrix = VP * translationMatrix * rotationMatrix * scaleMatrix; glm::mat4 ModelMatrix = translationMatrix * rotationMatrix * scaleMatrix; - glm::mat4 noYInvertMatrix = translationNoYInvertMatrix * nrmRotationMatrix * scaleMatrix; GLuint MatrixID = shader.getUniformLocation("MVP"); glUniformMatrix4fv(MatrixID,1,GL_FALSE,&matrix[0][0]); @@ -111,16 +105,12 @@ void Model::Draw(const Transform &tf, Graphics::Shader &shader, const glm::mat4 GLuint ModelMatrixID = shader.getUniformLocation("ModelMatrix"); glUniformMatrix4fv(ModelMatrixID,1,GL_FALSE,&ModelMatrix[0][0]); - GLuint MatrixNoYInvID = shader.getUniformLocation("TransformationMatrixNoYInv"); - glUniformMatrix4fv(MatrixNoYInvID,1,GL_FALSE,&noYInvertMatrix[0][0]); - GLuint RotationMatrixID = shader.getUniformLocation("NormalRotationMatrix"); - glUniformMatrix4fv(RotationMatrixID,1,GL_FALSE,&nrmRotationMatrix[0][0]); + glUniformMatrix4fv(RotationMatrixID,1,GL_FALSE,&rotationMatrix[0][0]); mesh->Draw(*Materials[texnum]); texnum++; } - } void Model::DrawSelection(Transform tf, Graphics::Shader &shader, glm::mat4 VP) { diff --git a/src/PropertiesWidget.cpp b/src/PropertiesWidget.cpp index 4d9bf0b..821f23f 100644 --- a/src/PropertiesWidget.cpp +++ b/src/PropertiesWidget.cpp @@ -44,7 +44,7 @@ void ImGuiDrawSelection(std::string id, t &val, iter optsBegin, iter optsEnd, st } -template +/*template void ImGuiDrawLayer(t *obj) { if (ImGui::BeginCombo("Layer##PropWind", ToString(obj->Layer).c_str())) { if (ImGui::Selectable("Common##TeamsPropWind")) @@ -65,7 +65,7 @@ void ImGuiDrawLayer(t *obj) { obj->Layer = Temporary; ImGui::EndCombo(); } -}; +};*/ void ImGuiDrawTransform(Transform &tf, std::string id) { ImGui::Text("Transform:"); @@ -103,7 +103,7 @@ void ImGuiDrawElem(Element *elem, std::string Id = "") { ImGui::InputText(("##PropWindInputType" + Id).c_str(), &elem->Type); ImGui::PopItemWidth(); ImGuiDrawTransform(elem->TF, "PropWind" + Id); - ImGuiDrawLayer(elem); + Configs::g_imguiDrawOpts("Layer##" + Id, Configs::g_layers, elem->Layer); ImGui::Checkbox(("Is Link Destination?##PropWindowIsLinkDest" + Id).c_str(), &elem->IsLinkDest); if (ImGui::CollapsingHeader(("Links##" + Id).c_str())) { ImGui::Indent(); @@ -117,7 +117,7 @@ void ImGuiDrawElem(Element *elem, std::string Id = "") { if (Element *gotoElem = GetMainWindow()->loadedMap.GetElementById(link.Destination)) { ImGui::SameLine(); - if (ImGui::Button(ICON_FA_CHEVRON_RIGHT)) { + if (ImGui::Button((ICON_FA_CHEVRON_RIGHT + std::string("##GotoDest") + std::to_string(i)).c_str())) { GetMainWindow()->selectedElem = gotoElem; } } @@ -144,7 +144,7 @@ void ImGuiDrawElem(Element *elem, std::string Id = "") { ImGui::Checkbox(("Is Closed?##" + Id).c_str(), &rail->IsClosed); ImGui::Checkbox(("Is Ladder?##" + Id).c_str(), &rail->IsLadder); ImGui::InputInt(("Priority?##" + Id).c_str(), (int *) &rail->Priority); - ImGuiDrawSelection("Rail Type", rail->RailType, AllRailTypeOptions.begin(), AllRailTypeOptions.end(), + ImGuiDrawSelection("Rail Type", rail->m_railType, AllRailTypeOptions.begin(), AllRailTypeOptions.end(), [](RailType t) { return ToString(t); }); if (ImGui::CollapsingHeader(("Rail Points##" + Id).c_str())) { ImGui::Indent();