diff --git a/editor/editor.exe b/editor/editor.exe index 215fd83..6b6c178 100644 Binary files a/editor/editor.exe and b/editor/editor.exe differ diff --git a/editor/project.eblanproj b/editor/project.eblanproj new file mode 100644 index 0000000..2427b9e --- /dev/null +++ b/editor/project.eblanproj @@ -0,0 +1,11 @@ +[Project] +Title=EBLAN_GAME +Author=Developer +Version=1.0.0 +StartupMap=assets/map.dat +WindowTitle=EBLAN ENGINE 3D - Standalone Retro Game +DefaultWidth=1280 +DefaultHeight=960 +GameMode=1 +ShowWeapons=1 +ShowCrosshair=1 diff --git a/editor/src/editor_app.cpp b/editor/src/editor_app.cpp index c386fa3..4810e88 100644 --- a/editor/src/editor_app.cpp +++ b/editor/src/editor_app.cpp @@ -1104,7 +1104,13 @@ void EditorApp::RenderAssetManagerModal() { ImGui::SetNextWindowSize(ImVec2(820, 580), ImGuiCond_FirstUseEver); if (ImGui::Begin("Менеджер ассетов (Texture & Audio Manager)", &showAssetManagerModal)) { - if (ImGui::BeginTabBar("AssetManagerTabs")) { + RenderAssetManagerContents(); + } + ImGui::End(); +} + +void EditorApp::RenderAssetManagerContents() { + if (ImGui::BeginTabBar("AssetManagerTabs")) { if (ImGui::BeginTabItem("Текстурный пакет (16 слотов)")) { ImGui::Text("Файл пакета: %s", GetTexturePackPath().c_str()); ImGui::SameLine(); @@ -1225,8 +1231,6 @@ void EditorApp::RenderAssetManagerModal() { ImGui::EndTabBar(); } - } - ImGui::End(); } // ----------------------------------------------------------------------------- @@ -1334,6 +1338,51 @@ void EditorApp::FloodFill(int startX, int startY, uint8_t targetType, uint8_t fi for (const auto& [x, y] : cells) SetCell(x, y, fillType); } +void EditorApp::DuplicateSelectedEntity() { + if (selectedSpriteIdx >= 0 && selectedSpriteIdx < static_cast(sprites.size())) { + if (sprites.size() >= MAX_LEVEL_SPRITES) { + statusMessage = "Лимит спрайтов на карте достигнут (макс. 32)."; + return; + } + PushUndo(); + SpriteEntry copy = sprites[selectedSpriteIdx]; + copy.x = (std::min)(copy.x + 64, (MAP_GRID_W - 2) * 64); + copy.y = (std::min)(copy.y + 64, (MAP_GRID_H - 2) * 64); + sprites.push_back(copy); + selectedSpriteIdx = static_cast(sprites.size()) - 1; + statusMessage = "Сущность дублирована (Ctrl+D)."; + } +} + +void EditorApp::DeleteSelectedEntity() { + if (selectedSpriteIdx >= 0 && selectedSpriteIdx < static_cast(sprites.size())) { + PushUndo(); + sprites.erase(sprites.begin() + selectedSpriteIdx); + selectedSpriteIdx = -1; + statusMessage = "Сущность удалена (Del)."; + } else if (selectedTransitionIdx >= 0 && selectedTransitionIdx < static_cast(transitions.size())) { + PushUndo(); + RemoveCutsceneTransition(selectedTransitionIdx); + transitions.erase(transitions.begin() + selectedTransitionIdx); + selectedTransitionIdx = -1; + statusMessage = "Портал перехода удален (Del)."; + } +} + +void EditorApp::FocusSelectedEntity() { + if (selectedSpriteIdx >= 0 && selectedSpriteIdx < static_cast(sprites.size())) { + int gx = sprites[selectedSpriteIdx].x / 64; + int gy = sprites[selectedSpriteIdx].y / 64; + canvasPanX = 150.0f - (gx * canvasZoom); + canvasPanY = 150.0f - (gy * canvasZoom); + statusMessage = "Камера сфокусирована на объекте (F)."; + } else { + canvasPanX = 150.0f - (playerStartX * canvasZoom); + canvasPanY = 150.0f - (playerStartY * canvasZoom); + statusMessage = "Камера сфокусирована на игроке (F)."; + } +} + // ----------------------------------------------------------------------------- // Hotkeys // ----------------------------------------------------------------------------- @@ -1363,14 +1412,17 @@ void EditorApp::HandleHotkeys() { SaveLevel(currentFilePath); } } + if (ImGui::IsKeyPressed(ImGuiKey_D, false)) DuplicateSelectedEntity(); if (ImGui::IsKeyPressed(ImGuiKey_Z, false)) Undo(); if (ImGui::IsKeyPressed(ImGuiKey_Y, false)) Redo(); return; // no single-letter tool hotkeys while Ctrl held } - if (ImGui::IsKeyPressed(ImGuiKey_F4, false)) { - showAssetManagerModal = !showAssetManagerModal; - } + if (ImGui::IsKeyPressed(ImGuiKey_Delete, false)) DeleteSelectedEntity(); + if (ImGui::IsKeyPressed(ImGuiKey_F, false)) FocusSelectedEntity(); + if (ImGui::IsKeyPressed(ImGuiKey_1, false)) viewportMode = 2; // 2D Map + if (ImGui::IsKeyPressed(ImGuiKey_2, false)) viewportMode = 1; // 3D View + if (ImGui::IsKeyPressed(ImGuiKey_3, false)) viewportMode = 0; // Split if (ImGui::IsKeyPressed(ImGuiKey_B, false)) currentTool = TOOL_BRUSH; if (ImGui::IsKeyPressed(ImGuiKey_E, false)) currentTool = TOOL_ERASER; @@ -1410,54 +1462,111 @@ void EditorApp::RenderUI() { ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus); - // Columns: Left = Palette & Hierarchy, Middle = Grid Canvas, Right = Inspector - float leftWidth = 220.0f; - float rightWidth = 280.0f; + // Columns: Left = Hierarchy & Tile Palette, Middle = Workspace Viewport/IDE, Right = Inspector + float leftWidth = 260.0f; + float rightWidth = 320.0f; float canvasWidth = ImGui::GetContentRegionAvail().x - leftWidth - rightWidth - 20.0f; - // Left Panel + // Left Panel (Unity / Unreal Docked Tabs) ImGui::BeginChild("LeftPanel", ImVec2(leftWidth, 0), true); - RenderTilePalette(); - ImGui::Separator(); - RenderHierarchy(); + if (ImGui::BeginTabBar("LeftPanelTabs", ImGuiTabBarFlags_None)) { + if (ImGui::BeginTabItem("🗂 Сцена")) { + RenderHierarchy(); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("🎨 Палитра")) { + RenderTilePalette(); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("📁 Файлы")) { + ImGui::TextColored(ImVec4(0.2f, 0.8f, 1.0f, 1.0f), "Браузер ассетов"); + ImGui::Separator(); + RenderAssetManagerContents(); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } ImGui::EndChild(); ImGui::SameLine(); - // Center Panel (Grid Canvas) + // Center Panel (Grid Canvas / 3D Scene Viewport / MASM32 IDE / Asset Browser) ImGui::BeginChild("CenterPanel", ImVec2(canvasWidth, 0), false); - float timelineHeight = showCutsceneTimeline ? (std::min)(340.0f, ImGui::GetContentRegionAvail().y * 0.48f) : 0.0f; - ImGui::BeginChild("CanvasPanel", ImVec2(0, showCutsceneTimeline ? -timelineHeight - 6 : 0), true); - if (ImGui::RadioButton("Рядом", viewportMode == 0)) viewportMode = 0; - ImGui::SameLine(); if (ImGui::RadioButton("Игровой вид", viewportMode == 1)) viewportMode = 1; - ImGui::SameLine(); if (ImGui::RadioButton("Карта", viewportMode == 2)) viewportMode = 2; - ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); - if (ImGui::SmallButton(" - ")) { canvasZoom = (std::max)(8.0f, canvasZoom - 4.0f); } - ImGui::SameLine(); if (ImGui::SmallButton(" 100% ")) { canvasZoom = 20.0f; canvasPanX = 20.0f; canvasPanY = 20.0f; } - ImGui::SameLine(); if (ImGui::SmallButton(" + ")) { canvasZoom = (std::min)(48.0f, canvasZoom + 4.0f); } - float sceneWidth = viewportMode == 0 ? ImGui::GetContentRegionAvail().x * 0.5f : 0; - if (viewportMode != 2) { - ImGui::BeginChild("SceneViewport", ImVec2(sceneWidth,0), true); - RenderSceneViewport(); - ImGui::EndChild(); - if (viewportMode == 0) ImGui::SameLine(); + + // Workspace Mode Tabs (Godot 4 / Unreal Engine 5 style) + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4.0f, 4.0f)); + + auto ModeTabButton = [&](const char* label, int modeId) { + bool active = (viewportMode == modeId); + if (active) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.06f, 0.48f, 0.88f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.12f, 0.58f, 0.98f, 1.0f)); + } else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.16f, 0.18f, 0.22f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.24f, 0.27f, 0.33f, 1.0f)); + } + if (ImGui::Button(label)) { + viewportMode = modeId; + } + ImGui::PopStyleColor(2); + }; + + ModeTabButton("🗺 2D Карта", 2); + ImGui::SameLine(); + ModeTabButton("🎮 3D Сцена", 1); + ImGui::SameLine(); + ModeTabButton("🪟 2D + 3D", 0); + ImGui::SameLine(); + ModeTabButton("💻 Скрипты (IDE)", 3); + ImGui::SameLine(); + ModeTabButton("📦 Ассеты", 4); + + if (viewportMode == 0 || viewportMode == 2) { + ImGui::SameLine(); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(); + if (ImGui::SmallButton(" - ")) { canvasZoom = (std::max)(8.0f, canvasZoom - 4.0f); } + ImGui::SameLine(); if (ImGui::SmallButton(" 100% ")) { canvasZoom = 20.0f; canvasPanX = 20.0f; canvasPanY = 20.0f; } + ImGui::SameLine(); if (ImGui::SmallButton(" + ")) { canvasZoom = (std::min)(48.0f, canvasZoom + 4.0f); } } - if (viewportMode != 1) { - ImGui::BeginChild("MapViewport", ImVec2(0,0), false); - RenderGridCanvas(); - ImGui::EndChild(); - } - ImGui::EndChild(); - if (showCutsceneTimeline) { - ImGui::BeginChild("CutsceneTimeline", ImVec2(0, 0), true); - RenderCutsceneTimeline(); + ImGui::PopStyleVar(2); + + if (viewportMode == 3) { + // Integrated MASM32 IDE docked directly in center workspace! + std::string root = fs::path(currentFilePath).parent_path().parent_path().string(); + if (root.empty()) root = "."; + RenderCodeEditorContents(root); + } else if (viewportMode == 4) { + // Texture & Audio Asset Browser docked in center workspace! + RenderAssetManagerContents(); + } else { + float timelineHeight = showCutsceneTimeline ? (std::min)(340.0f, ImGui::GetContentRegionAvail().y * 0.48f) : 0.0f; + ImGui::BeginChild("CanvasPanel", ImVec2(0, showCutsceneTimeline ? -timelineHeight - 6 : 0), true); + float sceneWidth = viewportMode == 0 ? ImGui::GetContentRegionAvail().x * 0.5f : 0; + if (viewportMode != 2) { + ImGui::BeginChild("SceneViewport", ImVec2(sceneWidth,0), true); + RenderSceneViewport(); + ImGui::EndChild(); + if (viewportMode == 0) ImGui::SameLine(); + } + if (viewportMode != 1) { + ImGui::BeginChild("MapViewport", ImVec2(0,0), false); + RenderGridCanvas(); + ImGui::EndChild(); + } ImGui::EndChild(); + if (showCutsceneTimeline) { + ImGui::BeginChild("CutsceneTimeline", ImVec2(0, 0), true); + RenderCutsceneTimeline(); + ImGui::EndChild(); + } } ImGui::EndChild(); ImGui::SameLine(); - // Right Panel (Inspector) + // Right Panel (Unity / Unreal Component Inspector) ImGui::BeginChild("RightPanel", ImVec2(rightWidth, 0), true); RenderInspector(); ImGui::EndChild(); @@ -2058,46 +2167,197 @@ void EditorApp::RenderTilePalette() { } void EditorApp::RenderHierarchy() { - ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "СУЩНОСТИ (ИЕРАРХИЯ)"); + ImGui::TextColored(ImVec4(0.2f, 0.8f, 1.0f, 1.0f), "ИЕРАРХИЯ СЦЕНЫ (SCENE TREE)"); ImGui::Separator(); - ImGui::Text("Игрок: Spawn (%d, %d)", playerStartX, playerStartY); + // Search filter + Quick Add button (Unity / Unreal style) + ImGui::InputTextWithHint("##HierarchySearch", "🔍 Поиск...", searchHierarchyBuf, sizeof(searchHierarchyBuf)); + ImGui::SameLine(); + if (ImGui::Button("+ Добавить")) { + ImGui::OpenPopup("QuickEntitySpawnPopup"); + } + if (ImGui::BeginPopup("QuickEntitySpawnPopup")) { + auto AddEntityItem = [&](const char* label, uint8_t archetype) { + if (ImGui::MenuItem(label)) { + if (sprites.size() < MAX_LEVEL_SPRITES) { + PushUndo(); + SpriteEntry spr{}; + spr.x = (playerStartX + 1) * 64 + 32; + spr.y = (playerStartY + 1) * 64 + 32; + spr.scale = 65536; + uint32_t defaultTex = 11; + if (archetype == ENTITY_ARCHETYPE_GUARD) defaultTex = 14; + else if (archetype == ENTITY_ARCHETYPE_MEDKIT) defaultTex = 12; + else if (archetype == ENTITY_ARCHETYPE_AMMO) defaultTex = 13; + else if (archetype == ENTITY_ARCHETYPE_KEY) defaultTex = 15; + else if (archetype == ENTITY_ARCHETYPE_SWITCH) defaultTex = 10; + else if (archetype == ENTITY_ARCHETYPE_BARREL) defaultTex = 11; + spr.textureId = defaultTex; + SetSpriteEntityData(spr, archetype, (archetype == ENTITY_ARCHETYPE_GUARD ? 60 : 100), (archetype == ENTITY_ARCHETYPE_GUARD ? 2 : 0), (archetype == ENTITY_ARCHETYPE_GUARD ? 6 : 0)); + sprites.push_back(spr); + selectedSpriteIdx = static_cast(sprites.size()) - 1; + selectedTransitionIdx = -1; + statusMessage = "Сущность создана на сцене."; + } else { + statusMessage = "Лимит спрайтов достигнут (макс. 32)."; + } + } + }; + AddEntityItem("⚔ Враг (Guard AI)", ENTITY_ARCHETYPE_GUARD); + AddEntityItem("🩹 Аптечка (+25 HP)", ENTITY_ARCHETYPE_MEDKIT); + AddEntityItem("📦 Патроны (+20)", ENTITY_ARCHETYPE_AMMO); + AddEntityItem("🔑 Ключ от двери", ENTITY_ARCHETYPE_KEY); + AddEntityItem("🕹 Рычаг / Переключатель", ENTITY_ARCHETYPE_SWITCH); + AddEntityItem("💥 Взрывная бочка", ENTITY_ARCHETYPE_BARREL); + AddEntityItem("🏺 Декорация / Проп", ENTITY_ARCHETYPE_PROP); + ImGui::EndPopup(); + } + ImGui::Separator(); - ImGui::Text("Спрайты на карте (%zu / %d):", sprites.size(), MAX_LEVEL_SPRITES); + auto MatchesSearch = [&](const char* text) { + if (!searchHierarchyBuf[0]) return true; + std::string query = searchHierarchyBuf; + std::string target = text; + for (auto& c : query) c = (char)tolower(c); + for (auto& c : target) c = (char)tolower(c); + return target.find(query) != std::string::npos; + }; + + // 1. Player Spawn (Always at top of hierarchy) + char playerLabel[96]; + snprintf(playerLabel, sizeof(playerLabel), "👤 Игрок [Spawn: (%d, %d)]", playerStartX, playerStartY); + if (MatchesSearch(playerLabel) || MatchesSearch("player") || MatchesSearch("игрок")) { + bool isPlayerSelected = (selectedSpriteIdx == -1 && selectedTransitionIdx == -1); + if (ImGui::Selectable(playerLabel, isPlayerSelected)) { + selectedSpriteIdx = -1; + selectedTransitionIdx = -1; + } + if (ImGui::BeginPopupContextItem("PlayerContextMenu")) { + if (ImGui::MenuItem("🎯 Сфокусировать камеру", "F")) { + FocusSelectedEntity(); + } + ImGui::EndPopup(); + } + } + + // 2. Sprite Entities grouped by categories + size_t guardCount = 0, pickupCount = 0, objectCount = 0; for (size_t i = 0; i < sprites.size(); ++i) { + uint8_t a = GetSpriteEntityType(sprites[i]); + if (a == ENTITY_ARCHETYPE_GUARD) guardCount++; + else if (a == ENTITY_ARCHETYPE_MEDKIT || a == ENTITY_ARCHETYPE_AMMO || a == ENTITY_ARCHETYPE_KEY) pickupCount++; + else objectCount++; + } + + auto RenderSpriteItem = [&](size_t i) { int gx = sprites[i].x / 64; int gy = sprites[i].y / 64; uint8_t aType = GetSpriteEntityType(sprites[i]); const char* typeTag = "Проп"; if (aType == ENTITY_ARCHETYPE_GUARD) typeTag = "Враг"; - else if (aType == ENTITY_ARCHETYPE_MEDKIT) typeTag = "+HP"; - else if (aType == ENTITY_ARCHETYPE_AMMO) typeTag = "+Ammo"; + else if (aType == ENTITY_ARCHETYPE_MEDKIT) typeTag = "Аптечка"; + else if (aType == ENTITY_ARCHETYPE_AMMO) typeTag = "Патроны"; else if (aType == ENTITY_ARCHETYPE_KEY) typeTag = "Ключ"; else if (aType == ENTITY_ARCHETYPE_SWITCH) typeTag = "Рычаг"; else if (aType == ENTITY_ARCHETYPE_BARREL) typeTag = "Бочка"; - char label[64]; - snprintf(label, sizeof(label), "[%s] #%zu (%d, %d)", typeTag, i + 1, gx, gy); + char label[96]; + snprintf(label, sizeof(label), "[%s] #%zu (%d, %d)##spr_%zu", typeTag, i + 1, gx, gy, i); - if (ImGui::Selectable(label, selectedSpriteIdx == static_cast(i))) { + if (!MatchesSearch(label)) return; + + bool isSel = (selectedSpriteIdx == static_cast(i)); + if (ImGui::Selectable(label, isSel)) { selectedSpriteIdx = static_cast(i); selectedTransitionIdx = -1; } + if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { + selectedSpriteIdx = static_cast(i); + FocusSelectedEntity(); + } + if (ImGui::BeginPopupContextItem()) { + if (ImGui::MenuItem("📋 Дублировать", "Ctrl+D")) { + selectedSpriteIdx = static_cast(i); + DuplicateSelectedEntity(); + } + if (ImGui::MenuItem("🎯 Сфокусировать", "F")) { + selectedSpriteIdx = static_cast(i); + FocusSelectedEntity(); + } + ImGui::Separator(); + if (ImGui::MenuItem("🗑 Удалить", "Del")) { + selectedSpriteIdx = static_cast(i); + DeleteSelectedEntity(); + } + ImGui::EndPopup(); + } + }; + + // Enemies Category + char enemyHdr[64]; + snprintf(enemyHdr, sizeof(enemyHdr), "⚔ Враги и Guard AI (%zu)", guardCount); + if (ImGui::TreeNodeEx(enemyHdr, ImGuiTreeNodeFlags_DefaultOpen)) { + for (size_t i = 0; i < sprites.size(); ++i) { + if (GetSpriteEntityType(sprites[i]) == ENTITY_ARCHETYPE_GUARD) RenderSpriteItem(i); + } + ImGui::TreePop(); } - ImGui::Separator(); - ImGui::Text("Порталы перехода (%zu / %d):", transitions.size(), MAX_LEVEL_TRANSITIONS); - for (size_t i = 0; i < transitions.size(); ++i) { - char label[96]; - snprintf(label, sizeof(label), "Портал #%zu (%d, %d) -> %s", - i + 1, transitions[i].triggerCellX, transitions[i].triggerCellY, - transitions[i].targetMap[0] ? transitions[i].targetMap : ""); - - if (ImGui::Selectable(label, selectedTransitionIdx == static_cast(i))) { - selectedTransitionIdx = static_cast(i); - selectedSpriteIdx = -1; + // Pickups Category + char pickupHdr[64]; + snprintf(pickupHdr, sizeof(pickupHdr), "📦 Лут и предметы (%zu)", pickupCount); + if (ImGui::TreeNodeEx(pickupHdr, ImGuiTreeNodeFlags_DefaultOpen)) { + for (size_t i = 0; i < sprites.size(); ++i) { + uint8_t a = GetSpriteEntityType(sprites[i]); + if (a == ENTITY_ARCHETYPE_MEDKIT || a == ENTITY_ARCHETYPE_AMMO || a == ENTITY_ARCHETYPE_KEY) RenderSpriteItem(i); } + ImGui::TreePop(); + } + + // Interactive & Props Category + char objHdr[64]; + snprintf(objHdr, sizeof(objHdr), "⚙ Объекты и окружение (%zu)", objectCount); + if (ImGui::TreeNodeEx(objHdr, ImGuiTreeNodeFlags_DefaultOpen)) { + for (size_t i = 0; i < sprites.size(); ++i) { + uint8_t a = GetSpriteEntityType(sprites[i]); + if (a != ENTITY_ARCHETYPE_GUARD && a != ENTITY_ARCHETYPE_MEDKIT && a != ENTITY_ARCHETYPE_AMMO && a != ENTITY_ARCHETYPE_KEY) RenderSpriteItem(i); + } + ImGui::TreePop(); + } + + // 3. Sublevel Transitions Category + char transHdr[64]; + snprintf(transHdr, sizeof(transHdr), "🌀 Порталы перехода (%zu)", transitions.size()); + if (ImGui::TreeNodeEx(transHdr, ImGuiTreeNodeFlags_DefaultOpen)) { + for (size_t i = 0; i < transitions.size(); ++i) { + char label[96]; + snprintf(label, sizeof(label), "Портал #%zu (%d, %d) -> %s##trans_%zu", + i + 1, transitions[i].triggerCellX, transitions[i].triggerCellY, + transitions[i].targetMap[0] ? transitions[i].targetMap : "", i); + + if (!MatchesSearch(label)) continue; + + bool isSel = (selectedTransitionIdx == static_cast(i)); + if (ImGui::Selectable(label, isSel)) { + selectedTransitionIdx = static_cast(i); + selectedSpriteIdx = -1; + } + if (ImGui::BeginPopupContextItem()) { + if (ImGui::MenuItem("🎯 Сфокусировать", "F")) { + selectedTransitionIdx = static_cast(i); + canvasPanX = 150.0f - (transitions[i].triggerCellX * canvasZoom); + canvasPanY = 150.0f - (transitions[i].triggerCellY * canvasZoom); + } + ImGui::Separator(); + if (ImGui::MenuItem("🗑 Удалить портал", "Del")) { + selectedTransitionIdx = static_cast(i); + DeleteSelectedEntity(); + } + ImGui::EndPopup(); + } + } + ImGui::TreePop(); } } @@ -2106,96 +2366,68 @@ void EditorApp::RenderInspector() { RenderCutsceneInspector(); ImGui::Separator(); } - ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "ИНСПЕКТОР СВОЙСТВ"); + + ImGui::TextColored(ImVec4(0.2f, 0.8f, 1.0f, 1.0f), "ИНСПЕКТОР СВОЙСТВ (INSPECTOR)"); ImGui::Separator(); - if (ImGui::CollapsingHeader("Спавн игрока", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::SliderInt("Spawn X", &playerStartX, 0, MAP_GRID_W - 1); - ImGui::SliderInt("Spawn Y", &playerStartY, 0, MAP_GRID_H - 1); - - float degrees = (playerStartAngle * 360.0f) / 512.0f; - if (ImGui::SliderFloat("Угол обзора (°)", °rees, 0.0f, 360.0f, "%.0f°")) { - playerStartAngle = static_cast((degrees * 512.0f) / 360.0f) & 511; - } - - const char* dirName = "Восток (East)"; - if (playerStartAngle >= 64 && playerStartAngle < 192) dirName = "Юг (South)"; - else if (playerStartAngle >= 192 && playerStartAngle < 320) dirName = "Запад (West)"; - else if (playerStartAngle >= 320 && playerStartAngle < 448) dirName = "Север (North)"; - ImGui::Text("Направление: %s", dirName); - } - - if (ImGui::CollapsingHeader("Окружение сцены", ImGuiTreeNodeFlags_DefaultOpen)) { - // Floor & Ceiling Color Pickers - float ceilCol[3] = { - ((ceilingColor >> 16) & 0xFF) / 255.0f, - ((ceilingColor >> 8) & 0xFF) / 255.0f, - (ceilingColor & 0xFF) / 255.0f - }; - if (ImGui::ColorEdit3("Цвет потолка", ceilCol)) { - ceilingColor = (static_cast(ceilCol[0] * 255.0f) << 16) | - (static_cast(ceilCol[1] * 255.0f) << 8) | - static_cast(ceilCol[2] * 255.0f); - } - - float floorCol[3] = { - ((floorColor >> 16) & 0xFF) / 255.0f, - ((floorColor >> 8) & 0xFF) / 255.0f, - (floorColor & 0xFF) / 255.0f - }; - if (ImGui::ColorEdit3("Цвет пола", floorCol)) { - floorColor = (static_cast(floorCol[0] * 255.0f) << 16) | - (static_cast(floorCol[1] * 255.0f) << 8) | - static_cast(floorCol[2] * 255.0f); - } - } - + // Case 1: Sprite Entity Selected if (selectedSpriteIdx >= 0 && selectedSpriteIdx < static_cast(sprites.size())) { - if (ImGui::CollapsingHeader("Выбранный спрайт", ImGuiTreeNodeFlags_DefaultOpen)) { - auto& spr = sprites[selectedSpriteIdx]; + auto& spr = sprites[selectedSpriteIdx]; + uint8_t aType = GetSpriteEntityType(spr); + const char* typeName = "Декорация (Проп)"; + if (aType == ENTITY_ARCHETYPE_GUARD) typeName = "Враг (Guard AI)"; + else if (aType == ENTITY_ARCHETYPE_MEDKIT) typeName = "Аптечка (+25 HP)"; + else if (aType == ENTITY_ARCHETYPE_AMMO) typeName = "Патроны (+20)"; + else if (aType == ENTITY_ARCHETYPE_KEY) typeName = "Ключ от двери"; + else if (aType == ENTITY_ARCHETYPE_SWITCH) typeName = "Рычаг [E]"; + else if (aType == ENTITY_ARCHETYPE_BARREL) typeName = "Взрывная бочка"; - // Position (raw world units -> cell coords for UI) + // Entity Header Card (Unity / Unreal style) + ImGui::TextColored(ImVec4(0.4f, 0.9f, 1.0f, 1.0f), "Сущность #%d: %s", selectedSpriteIdx + 1, typeName); + if (ImGui::SmallButton("📋 Дублировать (Ctrl+D)")) { DuplicateSelectedEntity(); } + ImGui::SameLine(); + if (ImGui::SmallButton("🎯 Фокус (F)")) { FocusSelectedEntity(); } + ImGui::SameLine(); + if (ImGui::SmallButton("🗑 Удалить (Del)")) { DeleteSelectedEntity(); return; } + ImGui::Separator(); + + // Component 1: Transform + if (ImGui::CollapsingHeader("📍 Transform (Координаты и масштаб)", ImGuiTreeNodeFlags_DefaultOpen)) { float sx = spr.x / 64.0f; float sy = spr.y / 64.0f; - if (ImGui::SliderFloat("Sprite X", &sx, 0.0f, MAP_GRID_W - 0.01f)) { + if (ImGui::SliderFloat("Позиция X", &sx, 0.0f, MAP_GRID_W - 0.01f, "%.2f ячеек")) { spr.x = static_cast(sx * 64.0f); } - if (ImGui::SliderFloat("Sprite Y", &sy, 0.0f, MAP_GRID_H - 0.01f)) { + if (ImGui::SliderFloat("Позиция Y", &sy, 0.0f, MAP_GRID_H - 0.01f, "%.2f ячеек")) { spr.y = static_cast(sy * 64.0f); } + ImGui::TextDisabled("Мировые единицы (x86 ASM): X=%d, Y=%d", spr.x, spr.y); - // Texture slot + float scaleF = spr.scale / 65536.0f; + if (ImGui::SliderFloat("Масштаб", &scaleF, 0.25f, 4.0f, "%.2fx")) { + spr.scale = static_cast(scaleF * 65536.0f); + } + } + + // Component 2: Sprite Renderer + if (ImGui::CollapsingHeader("🖼 Sprite Renderer (Текстура)", ImGuiTreeNodeFlags_DefaultOpen)) { int tid = static_cast(spr.textureId & 15); - if (ImGui::Combo("Текстура", &tid, g_TexSlotNames, 16)) { + if (ImGui::Combo("Слот текстуры", &tid, g_TexSlotNames, 16)) { spr.textureId = static_cast(tid); } - if (tid >= 0 && tid < 16 && textureSRVs[tid]) { - ImGui::Text("Превью спрайта:"); ImGui::Image(reinterpret_cast(textureSRVs[tid]), ImVec2(64, 64)); ImGui::SameLine(); ImGui::BeginGroup(); - if (ImGui::Button("Заменить PNG...")) { - ImportTextureImage(tid, true); - } - if (ImGui::Button("Экспорт PNG")) { - ExportTextureImage(tid); - } - if (ImGui::Button("Сброс")) { - ResetTextureSlotToDefault(tid); - } + if (ImGui::Button("Заменить PNG...")) { ImportTextureImage(tid, true); } + if (ImGui::Button("Экспорт PNG")) { ExportTextureImage(tid); } + if (ImGui::Button("Сброс слота")) { ResetTextureSlotToDefault(tid); } ImGui::EndGroup(); } + } - // Scale (16.16 fixed -> float for UI) - float scaleF = spr.scale / 65536.0f; - if (ImGui::SliderFloat("Масштаб", &scaleF, 0.25f, 4.0f, "%.2f")) { - spr.scale = static_cast(scaleF * 65536.0f); - } - - // Entity Archetype & Logic - ImGui::Separator(); - ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Геймплей / Архетип сущности:"); + // Component 3: Gameplay & AI Controller + if (ImGui::CollapsingHeader("🧠 Gameplay & AI Controller", ImGuiTreeNodeFlags_DefaultOpen)) { static const char* s_ArchetypeNames[7] = { "0: Декорация / Проп (Static)", "1: Враг (Enemy Guard AI)", @@ -2210,7 +2442,7 @@ void EditorApp::RenderInspector() { int spd = static_cast(GetSpriteSpeed(spr)); int agg = static_cast(GetSpriteAggro(spr)); - if (ImGui::Combo("Тип сущности", &archType, s_ArchetypeNames, 7)) { + if (ImGui::Combo("Архетип сущности", &archType, s_ArchetypeNames, 7)) { PushUndo(); SetSpriteEntityData(spr, static_cast(archType), static_cast(hp), static_cast(spd), static_cast(agg)); } @@ -2219,39 +2451,85 @@ void EditorApp::RenderInspector() { if (ImGui::SliderInt("Здоровье (HP)", &hp, 10, 500)) { SetSpriteEntityData(spr, static_cast(archType), static_cast(hp), static_cast(spd), static_cast(agg)); } - if (ImGui::SliderInt("Скорость", &spd, 1, 8)) { + if (ImGui::SliderInt("Скорость бега", &spd, 1, 8)) { SetSpriteEntityData(spr, static_cast(archType), static_cast(hp), static_cast(spd), static_cast(agg)); } - if (ImGui::SliderInt("Радиус агрессии (ячейки)", &agg, 1, 15)) { + if (ImGui::SliderInt("Радиус агро (ячейки)", &agg, 1, 15)) { SetSpriteEntityData(spr, static_cast(archType), static_cast(hp), static_cast(spd), static_cast(agg)); } + ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "● Отображается красным кругом на 2D карте"); } else if (archType == ENTITY_ARCHETYPE_MEDKIT) { - ImGui::TextColored(ImVec4(0.2f, 1.0f, 0.4f, 1.0f), "Восстанавливает +25 HP игроку при подборе"); + ImGui::TextColored(ImVec4(0.2f, 1.0f, 0.4f, 1.0f), "● Восстанавливает +25 HP игроку при подборе"); } else if (archType == ENTITY_ARCHETYPE_AMMO) { - ImGui::TextColored(ImVec4(1.0f, 0.9f, 0.2f, 1.0f), "Пополняет +20 патронов игроку при подборе"); + ImGui::TextColored(ImVec4(1.0f, 0.9f, 0.2f, 1.0f), "● Пополняет +20 патронов игроку при подборе"); } else if (archType == ENTITY_ARCHETYPE_KEY) { - ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "Ключ для открытия запертых дверей"); + ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "● Ключ для открытия запертых дверей"); } else if (archType == ENTITY_ARCHETYPE_SWITCH) { - ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.2f, 1.0f), "Активируется нажатием клавиши [E] рядом с объектом"); + ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.2f, 1.0f), "● Активируется нажатием [E] рядом с объектом"); } else if (archType == ENTITY_ARCHETYPE_BARREL) { - ImGui::TextColored(ImVec4(1.0f, 0.45f, 0.15f, 1.0f), "Взрывается от выстрелов, нанося 60 AOE урона всем вокруг!"); + ImGui::TextColored(ImVec4(1.0f, 0.45f, 0.15f, 1.0f), "● Взрывается от пуль, нанося 60 AOE урона вокруг!"); } - if (ImGui::Button("Редактировать логику в Редакторе кода (F7)")) { - showCodeEditorModal = true; - } - ImGui::Separator(); - - if (ImGui::Button("Удалить спрайт")) { - PushUndo(); - sprites.erase(sprites.begin() + selectedSpriteIdx); - selectedSpriteIdx = -1; + if (ImGui::Button("💻 Открыть логику в MASM32 IDE (F7)", ImVec2(-1, 28))) { + viewportMode = 3; } } + + // Component 4: Interaction & Lore Notes + if (ImGui::CollapsingHeader("💬 Интерактивный диалог / Записка", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::TextDisabled("При взаимодействии [E] вызывается ShowGameDialog:"); + static char szSpeaker[32] = "ПЕРСОНАЖ"; + static char szDialog[128] = "ПРИВЕТСТВУЮ В EBLAN ENGINE 3D!"; + ImGui::InputText("Говорящий", szSpeaker, sizeof(szSpeaker)); + ImGui::InputTextMultiline("Текст", szDialog, sizeof(szDialog), ImVec2(-1, 45)); + if (ImGui::Button("Вставить хук диалога в код (F7)")) { + viewportMode = 3; + } + } + + // Unity style [+ Сменить компонент...] + ImGui::Spacing(); + ImGui::Separator(); + if (ImGui::Button("+ Добавить / Сменить компонент...", ImVec2(-1, 28))) { + ImGui::OpenPopup("AddComponentPopup"); + } + if (ImGui::BeginPopup("AddComponentPopup")) { + if (ImGui::MenuItem("🧠 Guard AI Controller")) { + PushUndo(); + SetSpriteEntityData(spr, ENTITY_ARCHETYPE_GUARD, 60, 2, 6); + } + if (ImGui::MenuItem("🩹 Medkit Heal Component")) { + PushUndo(); + SetSpriteEntityData(spr, ENTITY_ARCHETYPE_MEDKIT, 100, 0, 0); + } + if (ImGui::MenuItem("📦 Ammo Pickup Component")) { + PushUndo(); + SetSpriteEntityData(spr, ENTITY_ARCHETYPE_AMMO, 100, 0, 0); + } + if (ImGui::MenuItem("🔑 Keycard Door Component")) { + PushUndo(); + SetSpriteEntityData(spr, ENTITY_ARCHETYPE_KEY, 100, 0, 0); + } + if (ImGui::MenuItem("🕹 Switch Trigger Component")) { + PushUndo(); + SetSpriteEntityData(spr, ENTITY_ARCHETYPE_SWITCH, 100, 0, 0); + } + if (ImGui::MenuItem("💥 Explosive Barrel Component")) { + PushUndo(); + SetSpriteEntityData(spr, ENTITY_ARCHETYPE_BARREL, 100, 0, 0); + } + if (ImGui::MenuItem("🏺 Static Prop Decorator")) { + PushUndo(); + SetSpriteEntityData(spr, ENTITY_ARCHETYPE_PROP, 100, 0, 0); + } + ImGui::EndPopup(); + } + return; } + // Case 2: Portal Selected if (selectedTransitionIdx >= 0 && selectedTransitionIdx < static_cast(transitions.size())) { - if (ImGui::CollapsingHeader("Свойства портала перехода", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader("🌀 Портал перехода (Sublevel Portal)", ImGuiTreeNodeFlags_DefaultOpen)) { auto& trans = transitions[selectedTransitionIdx]; ImGui::TextColored(ImVec4(0.7f, 0.4f, 1.0f, 1.0f), "Триггер-ячейка: (%d, %d)", trans.triggerCellX, trans.triggerCellY); @@ -2314,6 +2592,71 @@ void EditorApp::RenderInspector() { selectedTransitionIdx = -1; } } + return; + } + + // Case 3: Level / Player Spawn Selected (Default) + if (ImGui::CollapsingHeader("👤 Спавн игрока (Player Transform)", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::SliderInt("Spawn X", &playerStartX, 0, MAP_GRID_W - 1); + ImGui::SliderInt("Spawn Y", &playerStartY, 0, MAP_GRID_H - 1); + + float degrees = (playerStartAngle * 360.0f) / 512.0f; + if (ImGui::SliderFloat("Угол обзора (°)", °rees, 0.0f, 360.0f, "%.0f°")) { + playerStartAngle = static_cast((degrees * 512.0f) / 360.0f) & 511; + } + + const char* dirName = "Восток (East)"; + if (playerStartAngle >= 64 && playerStartAngle < 192) dirName = "Юг (South)"; + else if (playerStartAngle >= 192 && playerStartAngle < 320) dirName = "Запад (West)"; + else if (playerStartAngle >= 320 && playerStartAngle < 448) dirName = "Север (North)"; + ImGui::Text("Направление: %s", dirName); + if (ImGui::SmallButton("🎯 Сфокусировать камеру на игроке (F)")) { + FocusSelectedEntity(); + } + } + + if (ImGui::CollapsingHeader("🌐 Окружение сцены (Environment)", ImGuiTreeNodeFlags_DefaultOpen)) { + // Floor & Ceiling Color Pickers + float ceilCol[3] = { + ((ceilingColor >> 16) & 0xFF) / 255.0f, + ((ceilingColor >> 8) & 0xFF) / 255.0f, + (ceilingColor & 0xFF) / 255.0f + }; + if (ImGui::ColorEdit3("Цвет потолка", ceilCol)) { + ceilingColor = (static_cast(ceilCol[0] * 255.0f) << 16) | + (static_cast(ceilCol[1] * 255.0f) << 8) | + static_cast(ceilCol[2] * 255.0f); + } + + float floorCol[3] = { + ((floorColor >> 16) & 0xFF) / 255.0f, + ((floorColor >> 8) & 0xFF) / 255.0f, + (floorColor & 0xFF) / 255.0f + }; + if (ImGui::ColorEdit3("Цвет пола", floorCol)) { + floorColor = (static_cast(floorCol[0] * 255.0f) << 16) | + (static_cast(floorCol[1] * 255.0f) << 8) | + static_cast(floorCol[2] * 255.0f); + } + + ImGui::Spacing(); + ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.2f, 1.0f), "Быстрые пресеты освещения:"); + if (ImGui::SmallButton("Подземелье")) { ceilingColor = 0x00222222; floorColor = 0x00151515; } + ImGui::SameLine(); + if (ImGui::SmallButton("Бункер")) { ceilingColor = 0x00383838; floorColor = 0x00242424; } + ImGui::SameLine(); + if (ImGui::SmallButton("Неон")) { ceilingColor = 0x000F172A; floorColor = 0x00022C22; } + ImGui::SameLine(); + if (ImGui::SmallButton("Хоррор")) { ceilingColor = 0x003B0710; floorColor = 0x001C1917; } + } + + if (ImGui::CollapsingHeader("⚙ Настройки проекта & Сборка", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::Button("Настройки проекта (Жанр, Оружие)...", ImVec2(-1, 26))) { + showProjectSettingsModal = true; + } + if (ImGui::Button("Экспорт автономной игры (.exe)...", ImVec2(-1, 26))) { + showExportGameModal = true; + } } } diff --git a/editor/src/editor_app.h b/editor/src/editor_app.h index b1515d3..a9f1f26 100644 --- a/editor/src/editor_app.h +++ b/editor/src/editor_app.h @@ -67,10 +67,18 @@ public: void StopAudioSound(); void RenderAssetManagerModal(); + void RenderAssetManagerContents(); void RenderCodeEditorWindow(); + void RenderCodeEditorContents(const std::string& root); void RenderProjectSettingsModal(); void RenderExportGameModal(); + void DuplicateSelectedEntity(); + void DeleteSelectedEntity(); + void FocusSelectedEntity(); + char searchHierarchyBuf[64] = ""; + int leftPanelTab = 0; // 0 = Hierarchy, 1 = Tile Palette, 2 = Project Assets + bool showAssetManagerModal = false; bool showCutsceneTimeline = false; bool showCodeEditorModal = false; diff --git a/editor/src/editor_code.inl b/editor/src/editor_code.inl index ecb4f6e..b1c10b6 100644 --- a/editor/src/editor_code.inl +++ b/editor/src/editor_code.inl @@ -449,6 +449,13 @@ void EditorApp::RenderCodeEditorWindow() { ImGui::EndMenuBar(); } + RenderCodeEditorContents(root); + ImGui::End(); +} + +void EditorApp::RenderCodeEditorContents(const std::string& root) { + g_CodeEditor.PollBuild(); + // Top Toolbar ImGui::BeginGroup(); if (ImGui::Button("Сохранить (Ctrl+S)")) { @@ -661,5 +668,4 @@ void EditorApp::RenderCodeEditorWindow() { ImGui::EndTabBar(); ImGui::Columns(1); - ImGui::End(); } diff --git a/editor/src/main.cpp b/editor/src/main.cpp index 0ab5474..69a75ce 100644 --- a/editor/src/main.cpp +++ b/editor/src/main.cpp @@ -30,51 +30,51 @@ void SetupGodotStyle() { ImGuiStyle& style = ImGui::GetStyle(); ImVec4* colors = style.Colors; - style.WindowRounding = 6.0f; - style.ChildRounding = 5.0f; - style.FrameRounding = 4.0f; - style.PopupRounding = 6.0f; - style.ScrollbarRounding = 6.0f; - style.GrabRounding = 4.0f; - style.TabRounding = 5.0f; + style.WindowRounding = 8.0f; + style.ChildRounding = 6.0f; + style.FrameRounding = 5.0f; + style.PopupRounding = 8.0f; + style.ScrollbarRounding = 7.0f; + style.GrabRounding = 5.0f; + style.TabRounding = 6.0f; style.FrameBorderSize = 1.0f; style.WindowBorderSize = 1.0f; style.WindowPadding = ImVec2(10.0f, 10.0f); - style.FramePadding = ImVec2(7.0f, 4.0f); + style.FramePadding = ImVec2(8.0f, 5.0f); style.ItemSpacing = ImVec2(8.0f, 6.0f); style.ItemInnerSpacing = ImVec2(6.0f, 4.0f); - // Modern Game Studio Dark Slate Palette with Electric Cyan & Neon Amber accents - colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.52f, 0.55f, 0.60f, 1.00f); + // Modern Game Studio Dark Palette (Unreal / Unity / Godot Pro) + colors[ImGuiCol_Text] = ImVec4(0.96f, 0.97f, 0.99f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.54f, 0.60f, 1.00f); colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.12f, 0.14f, 1.00f); - colors[ImGuiCol_ChildBg] = ImVec4(0.13f, 0.14f, 0.17f, 1.00f); - colors[ImGuiCol_PopupBg] = ImVec4(0.14f, 0.15f, 0.18f, 0.98f); - colors[ImGuiCol_Border] = ImVec4(0.22f, 0.24f, 0.28f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.14f, 0.15f, 0.18f, 1.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.14f, 0.16f, 0.20f, 0.98f); + colors[ImGuiCol_Border] = ImVec4(0.24f, 0.26f, 0.31f, 1.00f); colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_FrameBg] = ImVec4(0.18f, 0.20f, 0.24f, 1.00f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.24f, 0.28f, 0.34f, 1.00f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.28f, 0.33f, 0.40f, 1.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.18f, 0.20f, 0.25f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.25f, 0.29f, 0.36f, 1.00f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.30f, 0.36f, 0.45f, 1.00f); colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.10f, 0.12f, 1.00f); - colors[ImGuiCol_TitleBgActive] = ImVec4(0.14f, 0.16f, 0.20f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.13f, 0.15f, 0.19f, 1.00f); colors[ImGuiCol_MenuBarBg] = ImVec4(0.10f, 0.11f, 0.13f, 1.00f); colors[ImGuiCol_ScrollbarBg] = ImVec4(0.09f, 0.10f, 0.12f, 0.80f); - colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.24f, 0.27f, 0.33f, 1.00f); - colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.32f, 0.37f, 0.45f, 1.00f); - colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.40f, 0.46f, 0.56f, 1.00f); - colors[ImGuiCol_CheckMark] = ImVec4(0.20f, 0.75f, 1.00f, 1.00f); - colors[ImGuiCol_SliderGrab] = ImVec4(0.20f, 0.70f, 0.98f, 1.00f); - colors[ImGuiCol_SliderGrabActive] = ImVec4(0.35f, 0.82f, 1.00f, 1.00f); - colors[ImGuiCol_Button] = ImVec4(0.20f, 0.23f, 0.28f, 1.00f); - colors[ImGuiCol_ButtonHovered] = ImVec4(0.28f, 0.34f, 0.42f, 1.00f); - colors[ImGuiCol_ButtonActive] = ImVec4(0.34f, 0.42f, 0.52f, 1.00f); - colors[ImGuiCol_Header] = ImVec4(0.20f, 0.24f, 0.30f, 1.00f); - colors[ImGuiCol_HeaderHovered] = ImVec4(0.28f, 0.34f, 0.42f, 1.00f); - colors[ImGuiCol_HeaderActive] = ImVec4(0.34f, 0.42f, 0.52f, 1.00f); - colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.22f, 0.26f, 1.00f); - colors[ImGuiCol_Tab] = ImVec4(0.14f, 0.16f, 0.19f, 1.00f); - colors[ImGuiCol_TabHovered] = ImVec4(0.28f, 0.33f, 0.40f, 1.00f); - colors[ImGuiCol_TabActive] = ImVec4(0.22f, 0.26f, 0.33f, 1.00f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.25f, 0.28f, 0.35f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.34f, 0.39f, 0.48f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.42f, 0.48f, 0.60f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.05f, 0.65f, 0.95f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.05f, 0.60f, 0.92f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.20f, 0.75f, 1.00f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.20f, 0.23f, 0.29f, 1.00f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.28f, 0.34f, 0.43f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.35f, 0.43f, 0.55f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.32f, 1.00f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.28f, 0.35f, 0.45f, 1.00f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.35f, 0.44f, 0.56f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.22f, 0.24f, 0.29f, 1.00f); + colors[ImGuiCol_Tab] = ImVec4(0.14f, 0.16f, 0.20f, 1.00f); + colors[ImGuiCol_TabHovered] = ImVec4(0.28f, 0.34f, 0.42f, 1.00f); + colors[ImGuiCol_TabActive] = ImVec4(0.22f, 0.27f, 0.35f, 1.00f); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {