Add ability to select multiple things in editor

This commit is contained in:
KP 2024-07-30 21:19:10 -05:00
parent 7cd5cb59d3
commit 62dd36d7d6
6 changed files with 194 additions and 57 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,48 @@
[09:17:25 PM] Info: Starting...
KP3D version 2
===============================
Copyright (C) kpworld.xyz 2018-2024
Contact me! @kp_cftsz
[09:17:25 PM] Info: Initializing SDL
[09:17:25 PM] Info: Initializing OpenGL
[09:17:25 PM] Info: OpenGL version: 4.6.0 NVIDIA 536.23
[09:17:25 PM] Info: Initializing GLEW
[09:17:25 PM] Info: Initializing SDL_mixer
[09:17:25 PM] Info: Reticulating splines...
[09:17:25 PM] Info: Ready!
[09:17:25 PM] Info: Loading material resource: block.png
[09:17:25 PM] Info: Found normal map texture: materials/block_n.png
[09:17:25 PM] Info: Loading material resource: FLAT5_7.png
[09:17:25 PM] Info: Found normal map texture: materials/FLAT5_7_n.png
[09:17:25 PM] Info: Loading material resource: floor0.png
[09:17:25 PM] Info: Found normal map texture: materials/floor0_n.png
[09:17:25 PM] Info: Loading material resource: floor1.png
[09:17:25 PM] Info: Found normal map texture: materials/floor1_n.png
[09:17:25 PM] Info: Loading material resource: GRASS2.png
[09:17:25 PM] Info: Found normal map texture: materials/GRASS2_n.png
[09:17:25 PM] Info: Map init
[09:17:25 PM] Info: Finalized mesh with 45 batches
[09:17:30 PM] Info: Finalized mesh with 50 batches
[09:17:39 PM] Info: Finalized mesh with 50 batches
[09:17:42 PM] Info: Finalized mesh with 50 batches
[09:17:47 PM] Info: Finalized mesh with 50 batches
[09:17:53 PM] Info: Finalized mesh with 50 batches
[09:17:54 PM] Info: Finalized mesh with 50 batches
[09:18:05 PM] Info: Finalized mesh with 52 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:07 PM] Info: Finalized mesh with 56 batches
[09:18:12 PM] Info: Finalized mesh with 56 batches

View file

@ -60,11 +60,16 @@ bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner, Sector
// kind of ugly the way this works...
kp3d::uint ShouldHighlight(const kp3d::RenderBatch3D& batch)
{
if (!kp3d::editor_hovered_batch)
using namespace kp3d;
if (editor_hovered_batch.empty())
return 0xFFFFFFFF;
if (&batch != kp3d::editor_hovered_batch)
if (std::find(editor_hovered_batch.begin(), editor_hovered_batch.end(), &batch) == editor_hovered_batch.end())
return 0xFFFFFFFF;
kp3d::BatchSectorInfo info = std::any_cast<kp3d::BatchSectorInfo>(batch.userdata);
// if (!kp3d::editor_hovered_batch)
// return 0xFFFFFFFF;
// if (&batch != kp3d::editor_hovered_batch)
// return 0xFFFFFFFF;
BatchSectorInfo info = std::any_cast<BatchSectorInfo>(batch.userdata);
if (info.sector)
return 0x5555FFFF;
}
@ -73,7 +78,7 @@ kp3d::uint ShouldHighlight(const kp3d::RenderBatch3D& batch)
namespace kp3d {
RenderBatch3D* editor_hovered_batch = nullptr;
std::vector<RenderBatch3D*> editor_hovered_batch;
Map::Map()
{

View file

@ -173,6 +173,6 @@ private:
};
extern RenderBatch3D* editor_hovered_batch; // hack
extern std::vector<RenderBatch3D*> editor_hovered_batch; // hack
}

View file

@ -3,6 +3,7 @@
#include <imgui.h>
#include "KP3D_Renderer3D.h"
#include "KP3D_StaticMesh.h"
#include "KP3D_Raycast.h"
#include "KP3D_Math.h"
#include "KP3D_Geometry.h"
@ -59,6 +60,9 @@ void Editor::Update()
KEY_SHORTCUT(V, m_mode = MODE_BUILD);
KEY_SHORTCUT(C, m_mode = MODE_SECTOR_EDIT);
if (anything_hovered)
return;
if (m_mode == MODE_BUILD)
{
UpdateModeBuild();
@ -66,6 +70,8 @@ void Editor::Update()
}
// Raycast through everything on the map
if (sandbox->IsMouseButtonDown(kp3d::MOUSE_BUTTON_LEFT))
{
using namespace kp3d;
struct Target
{
@ -74,12 +80,12 @@ void Editor::Update()
RenderBatch3D* b;
};
std::vector<Target> targets;
for (RenderBatch3D& b: sandbox->map.GetMeshRef().GetBatchesRef())
for (RenderBatch3D& b : sandbox->map.GetMeshRef().GetBatchesRef())
{
for (size_t i = 0; i < b.vertex_data.size(); i += 3)
{
Vec3 pos;
Triangle tri = {b.vertex_data[i].position, b.vertex_data[i + 1].position, b.vertex_data[i + 2].position};
Triangle tri = { b.vertex_data[i].position, b.vertex_data[i + 1].position, b.vertex_data[i + 2].position };
auto ray = GetRayFromCamera(sandbox->camera);
bool raycast = RayIntersectsTriangle(ray[0], ray[1], &tri, pos);
if (raycast)
@ -89,19 +95,52 @@ void Editor::Update()
pow(pos.y - sandbox->camera.position.y, 2) +
pow(pos.z - sandbox->camera.position.z, 2)
);
targets.push_back({pos, dist, &b});
targets.push_back({ pos, dist, &b });
}
}
if (!targets.empty())
{
std::sort(targets.begin(), targets.end(), [&](const Target& a, const Target& b) { return a.distance > b.distance; });
const Target& target = targets.back();
editor_hovered_batch = target.b;
if (editor_hovered_batch.empty())
{
if (std::find(editor_hovered_batch.begin(), editor_hovered_batch.end(), target.b) == editor_hovered_batch.end())
editor_hovered_batch.push_back(target.b);
}
else
editor_hovered_batch = nullptr;
{
try
{
const auto& info = std::any_cast<kp3d::BatchSectorInfo>(kp3d::editor_hovered_batch[0]->userdata);
const auto& target_info = std::any_cast<kp3d::BatchSectorInfo>(target.b->userdata);
if (info.wall && target_info.wall)
{
if (std::find(editor_hovered_batch.begin(), editor_hovered_batch.end(), target.b) == editor_hovered_batch.end())
editor_hovered_batch.push_back(target.b);
}
else if (info.flat && target_info.flat)
{
if (std::find(editor_hovered_batch.begin(), editor_hovered_batch.end(), target.b) == editor_hovered_batch.end())
editor_hovered_batch.push_back(target.b);
}
}
catch (std::bad_any_cast& e)
{
KP3D_LOG_ERROR("Bad any cast: {}", e.what());
}
}
}
else
{
// editor_hovered_batch = nullptr;
if (!sandbox->IsKeyDown(kp3d::KEY_LSHIFT))
{
editor_hovered_batch.clear();
}
}
}
sandbox->MouseButtonReset(kp3d::MOUSE_BUTTON_LEFT);
}
}
void Editor::RenderMap()
@ -292,11 +331,11 @@ void Editor::RenderUI()
}
else
{
if (kp3d::editor_hovered_batch)
if (!kp3d::editor_hovered_batch.empty())
{
try
{
const auto& info = std::any_cast<kp3d::BatchSectorInfo>(kp3d::editor_hovered_batch->userdata);
const auto& info = std::any_cast<kp3d::BatchSectorInfo>(kp3d::editor_hovered_batch[0]->userdata);
ImGui::SeparatorText("Type");
ImGui::Text(info.wall ? "Wall" : "Flat/Sector");
if (info.wall)
@ -309,9 +348,9 @@ void Editor::RenderUI()
ImGui::CheckboxFlags("Double-sided", (unsigned*)&info.wall->user_flags, kp3d::Wall::UFLAG_DOUBLESIDED);
ImGui::SeparatorText("Materials");
RenderUIMaterialSelect("Middle", &info.wall->materials[kp3d::TEX_FRONT]);
RenderUIMaterialSelect("Upper", &info.wall->materials[kp3d::TEX_UPPER]);
RenderUIMaterialSelect("Lower", &info.wall->materials[kp3d::TEX_LOWER]);
RenderUIMaterialSelect("Middle", MAT_MIDDLE_TEX, &info.wall->materials[kp3d::TEX_FRONT]);
RenderUIMaterialSelect("Upper", MAT_UPPER_TEX, &info.wall->materials[kp3d::TEX_UPPER]);
RenderUIMaterialSelect("Lower", MAT_LOWER_TEX, &info.wall->materials[kp3d::TEX_LOWER]);
}
else if (info.sector)
{
@ -331,8 +370,8 @@ void Editor::RenderUI()
if (changed)
sandbox->map.Rebuild(kp3d::GEN_NORMALS);
ImGui::SeparatorText("Materials");
RenderUIMaterialSelect("Floor", &info.sector->floor.material);
RenderUIMaterialSelect("Ceiling", &info.sector->ceiling.material);
RenderUIMaterialSelect("Floor", MAT_FLOOR_TEX, &info.sector->floor.material);
RenderUIMaterialSelect("Ceiling", MAT_CEILING_TEX, &info.sector->ceiling.material);
}
}
catch (std::bad_any_cast& e)
@ -340,16 +379,20 @@ void Editor::RenderUI()
KP3D_LOG_ERROR("Bad any cast: {}", e.what());
}
}
else
{
ImGui::Text("No selection");
}
}
ImGui::End();
}
}
//ImGui::ShowDemoWindow();
if (m_material_to_update)
if (!m_materials_to_update.empty())
RenderUIMaterialModal();
anything_hovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) || ImGui::IsAnyItemHovered();
}
void Editor::RenderUIInfo()
@ -403,15 +446,40 @@ void Editor::RenderUIAbout()
}
}
void Editor::RenderUIMaterialSelect(const char* name, const kp3d::Material** material)
void Editor::RenderUIMaterialSelect(const char* name, int type, const kp3d::Material** material)
{
ImGui::Text("%s:", name);
if (material && *material)
{
ImGui::PushID(material); // not safe, not ideal
ImGui::PushID(name + type); // not safe, not ideal
if (ImGui::ImageButton((ImTextureID)(*material)->textures[kp3d::MAT_TEX_DIFFUSE].GetGLID(), {96, 96}))
{
m_material_to_update = material;
//m_material_to_update = material;
// m_materials_to_update.push_back(material);
for (auto* batch: kp3d::editor_hovered_batch)
{
try
{
auto info = std::any_cast<kp3d::BatchSectorInfo>(batch->userdata);
if (info.wall)
{
switch (type)
{
case MAT_UPPER_TEX: m_materials_to_update.push_back(&info.wall->materials[kp3d::TEX_UPPER]);
case MAT_LOWER_TEX: m_materials_to_update.push_back(&info.wall->materials[kp3d::TEX_LOWER]);
case MAT_MIDDLE_TEX: m_materials_to_update.push_back(&info.wall->materials[kp3d::TEX_FRONT]);
}
}
else if (info.flat)
{
m_materials_to_update.push_back(&info.flat->material);
}
}
catch (std::bad_any_cast& e)
{
// ...
}
}
should_show_material_modal = true;
}
ImGui::PopID();
@ -496,7 +564,8 @@ void Editor::RenderUIMaterialModal()
// Should we rebuild the map when we change stuff? I guess.
if (should_remove_texture)
{
*m_material_to_update = nullptr;
//*m_material_to_update = nullptr;
m_materials_to_update.clear();
ImGui::CloseCurrentPopup();
should_show_material_modal = false;
sandbox->map.Rebuild(kp3d::GEN_NORMALS);
@ -511,7 +580,9 @@ void Editor::RenderUIMaterialModal()
if (should_update_texture)
{
*m_material_to_update = chosen_tex;
for (auto mats: m_materials_to_update)
*mats = chosen_tex;
m_materials_to_update.clear();
ImGui::CloseCurrentPopup();
should_show_material_modal = false;
sandbox->map.Rebuild(kp3d::GEN_NORMALS);
@ -526,16 +597,19 @@ void Editor::OnScrollWheel(const kp3d::ScrollWheelEvent* e)
{
using namespace kp3d;
if (!editor_hovered_batch)
if (editor_hovered_batch.empty())
return;
auto factor = (2.0f / 128.0f) * e->length;
auto info = std::any_cast<BatchSectorInfo>(editor_hovered_batch->userdata);
for (auto* batch: editor_hovered_batch)
{
auto info = std::any_cast<BatchSectorInfo>(batch->userdata);
if (info.flat)
{
info.flat->base_height += factor;
sandbox->map.Rebuild(GEN_NORMALS);
}
}
}
void Editor::OnKeyPress(const kp3d::KeyPressEvent* e)

View file

@ -12,6 +12,15 @@ enum EditMode
MODE_SECTOR_EDIT
};
enum MaterialType
{
MAT_FLOOR_TEX,
MAT_CEILING_TEX,
MAT_UPPER_TEX,
MAT_LOWER_TEX,
MAT_MIDDLE_TEX
};
class Editor
{
public:
@ -31,7 +40,7 @@ public:
void RenderUI();
void RenderUIInfo();
void RenderUIAbout();
void RenderUIMaterialSelect(const char* name, const kp3d::Material** material);
void RenderUIMaterialSelect(const char* name, int type, const kp3d::Material** material);
void RenderUIMaterialModal();
void OnScrollWheel(const kp3d::ScrollWheelEvent* e);
@ -52,6 +61,7 @@ private:
bool show_about_view = false;
bool should_show_material_modal = false;
char m_tex_filter_buf[512];
const kp3d::Material** m_material_to_update = nullptr;
bool anything_hovered = false;
std::vector<const kp3d::Material**> m_materials_to_update;
};