Add ability to place and select things in the map editor

This commit is contained in:
kp 2024-08-09 23:52:33 -05:00
parent 5b36b9820a
commit 2f155d3fe9
9 changed files with 13909 additions and 248 deletions

File diff suppressed because it is too large Load diff

View file

@ -561,15 +561,11 @@ void Map::Init()
sectors.clear(); sectors.clear();
m_mesh.Reset(); m_mesh.Reset();
sectors.reserve(10000); sectors.reserve(10000);
things.reserve(100000);
BuildSkybox(res::texture_cache["skyboxes/skybox_14.jpg"].get()); BuildSkybox(res::texture_cache["skyboxes/skybox_14.jpg"].get());
BuildGrid(); BuildGrid();
//static Texture tex, tex2, tex3, tex4;
//tex.Load("GRASS2.png", true);
//tex2.Load("floor0.png", true);
//tex3.Load("FLAT5_7.png", true);
//tex4.Load("block.png", true);
m_dot.Load("dot.png"); m_dot.Load("dot.png");
static Material* tex; static Material* tex;
@ -582,8 +578,6 @@ void Map::Init()
tex3 = res::material_cache["FLAT5_7.png"].get(); tex3 = res::material_cache["FLAT5_7.png"].get();
tex4 = res::material_cache["block.png"].get(); tex4 = res::material_cache["block.png"].get();
// Build a stupid little test map // Build a stupid little test map
// ------------------------------ // ------------------------------
// Main sector // Main sector
@ -793,7 +787,9 @@ void Map::Rebuild(NormalGenType gen_normals)
void Map::Update() void Map::Update()
{ {
// ... // Things
for (Thing& thing: things)
thing.Update();
} }
void Map::Render() void Map::Render()
@ -807,6 +803,10 @@ void Map::Render()
kp3d::Renderer3D::DrawMesh(m_mesh, m_transform, true, ShouldHighlight); kp3d::Renderer3D::DrawMesh(m_mesh, m_transform, true, ShouldHighlight);
kp3d::Renderer3D::PopShader(); kp3d::Renderer3D::PopShader();
// Things
for (Thing& thing: things)
thing.Render();
// Debug dots // Debug dots
for (Vec3 v: m_dots) for (Vec3 v: m_dots)
kp3d::Renderer3D::DrawBillboard(m_dot, {v.x, v.y, -v.z}, {0.1f, 0.1f}, true); kp3d::Renderer3D::DrawBillboard(m_dot, {v.x, v.y, -v.z}, {0.1f, 0.1f}, true);

View file

@ -8,6 +8,7 @@
#include "KP3D_Transform.h" #include "KP3D_Transform.h"
#include "KP3D_Shader.h" #include "KP3D_Shader.h"
#include "KP3D_Material.h" #include "KP3D_Material.h"
#include "KP3D_Thing.h"
namespace kp3d { namespace kp3d {
@ -173,6 +174,7 @@ public:
public: public:
bool join_disabled = false; bool join_disabled = false;
std::vector<std::shared_ptr<Sector>> sectors; std::vector<std::shared_ptr<Sector>> sectors;
std::vector<Thing> things;
bool render_wireframe = false; bool render_wireframe = false;
float texture_scale = 128.0f; float texture_scale = 128.0f;
Vec3 grid_box[6]; Vec3 grid_box[6];

View file

@ -308,7 +308,7 @@ void Renderer3D::DrawBillboard(const Texture& texture, const Vec3& position, Vec
} }
void Renderer3D::DrawBillboardSprites( void Renderer3D::DrawBillboardSprites(
const Texture** textures, const Texture* textures[8],
float degrees, float degrees,
const Vec3& position, const Vec3& position,
Vec2 size, Vec2 size,

View file

@ -25,7 +25,7 @@ public:
static void DrawMesh(StaticMesh& mesh, Transform& m, bool bind_shader = true, uint (*func_highlight)(const RenderBatch3D&) = nullptr); static void DrawMesh(StaticMesh& mesh, Transform& m, bool bind_shader = true, uint (*func_highlight)(const RenderBatch3D&) = nullptr);
static void DrawBillboard(const Texture& texture, const Vec3& position, Vec2 size, bool both_axes = false, float yaw = 90.0f); static void DrawBillboard(const Texture& texture, const Vec3& position, Vec2 size, bool both_axes = false, float yaw = 90.0f);
static void DrawBillboardSprites( static void DrawBillboardSprites(
const Texture** textures, const Texture* textures[8],
float degrees, float degrees,
const Vec3& position, const Vec3& position,
Vec2 size, Vec2 size,

View file

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include "KP3D_Renderer3D.h" #include "KP3D_Renderer3D.h"
#include "KP3D_Renderer2D.h"
namespace { namespace {
@ -20,10 +21,13 @@ void LoadDefaultSprite()
namespace kp3d { namespace kp3d {
Thing::Thing(): Thing::Thing(Vec3 position):
display{Display::NONE} display{Display::NONE}
{ {
LoadDefaultSprite(); LoadDefaultSprite();
transform.translation = position;
transform.scale = {0.5f, 0.5f, 0.5f};
} }
Thing::~Thing() Thing::~Thing()
@ -39,15 +43,94 @@ void Thing::Render()
switch (display.type) switch (display.type)
{ {
case Display::NONE: case Display::NONE:
// Debug:
Renderer3D::DrawBillboard(*default_sprite.get(), transform.translation, {1.0f, 1.0f}); Renderer3D::DrawBillboard(*default_sprite.get(), transform.translation, {1.0f, 1.0f});
break; break;
case Display::MESH: case Display::MESH:
Renderer3D::DrawModel(*display.data.mesh.model, transform); Renderer3D::DrawModel(*display.data.mesh.model, transform);
break; break;
case Display::SPRITES: case Display::SPRITES:
Renderer3D::DrawBillboardSprites(display.data.sprites.textures, transform.rotation.y, transform.translation, {1.0f, 1.0f}); Renderer3D::DrawBillboardSprites(display.data.sprites.textures[display.data.sprites.current_sprite], transform.rotation.y, transform.translation, {1.0f, 1.0f});
break; break;
} }
} }
// For debugging, use by the map editor, etc.
void Thing::RenderBox(Vec3 color)
{
static StaticMesh box_mesh;
if (box_mesh.GetBatchesRef().empty())
{
std::vector<Vertex3D> box_vertex_data = GetBox();
box_mesh.AddBatch(&Renderer2D::GetDefaultTexture(), box_vertex_data);
box_mesh.Finalize();
}
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
Renderer3D::PushShader(Renderer3D::GetWireframeShader());
Renderer3D::GetShader().Bind();
Renderer3D::GetShader().SetUniform("u_wireframe_color", color);
Renderer3D::GetShader().SetUniform("u_wireframe_alpha", 1.0f);
Renderer3D::DrawMesh(box_mesh, transform);
Renderer3D::PopShader();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
std::vector<Vertex3D> Thing::GetBox(bool apply_transform)
{
std::vector<Vertex3D> box_vertex_data;
box_vertex_data = {
Vertex3D(Vec3(-1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, -1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3(-1.0f, 1.0f, 1.0f), Vec2(0.0f, 0.0f)),
Vertex3D(Vec3( 1.0f, -1.0f, 1.0f), Vec2(0.0f, 0.0f))
};
if (apply_transform)
{
for (Vertex3D& v: box_vertex_data)
{
Mat4 scale = Mat4().InitScale(transform.scale);
Mat4 rot = Mat4().InitRotation(transform.rotation);
Mat4 trans = Mat4().InitTranslation(v.position * 0.5f + transform.translation);
Mat4 mat = trans * rot * scale;
v.position = {mat.mat[12], mat.mat[13], mat.mat[14]};
}
}
return box_vertex_data;
}
} // namespace kp3d } // namespace kp3d

View file

@ -14,6 +14,7 @@
namespace kp3d { namespace kp3d {
inline static constexpr size_t NUM_SPRITES_PER_DISPLAY = 8; inline static constexpr size_t NUM_SPRITES_PER_DISPLAY = 8;
inline static constexpr size_t NUM_SPRITES = 4;
struct Display struct Display
{ {
@ -25,17 +26,6 @@ struct Display
OTHER OTHER
} type; } type;
enum Flags: byte
{
NO_FLAGS,
FLAG_FACE_CAMERA = 1 << 0,
FLAG_GROUNDED = 1 << 1,
FLAG_VISIBLE = 1 << 2,
FLAG_DELETE = 1 << 3,
FLAG_COLLISIONS = 1 << 4,
FLAG_RELATIVE_HR = 1 << 5
};
union Data union Data
{ {
struct Mesh struct Mesh
@ -48,7 +38,9 @@ struct Display
struct Sprites struct Sprites
{ {
Texture* textures[NUM_SPRITES_PER_DISPLAY]; const Texture* textures[NUM_SPRITES][NUM_SPRITES_PER_DISPLAY];
size_t num_sprites;
size_t current_sprite;
} sprites; } sprites;
} data; } data;
}; };
@ -56,16 +48,29 @@ struct Display
class Thing class Thing
{ {
public: public:
Thing(); Thing(Vec3 position = {});
virtual ~Thing(); virtual ~Thing();
void Update(); void Update();
void Render(); void Render();
void RenderBox(Vec3 color = {0.33f, 0.33f, 1.0f});
std::vector<Vertex3D> GetBox(bool apply_transform = false);
public: public:
Display display; Display display;
Transform transform; Transform transform;
enum Flags: byte
{
NO_FLAGS,
FLAG_FACE_CAMERA = 1 << 0,
FLAG_GROUNDED = 1 << 1,
FLAG_VISIBLE = 1 << 2,
FLAG_DELETE = 1 << 3,
FLAG_COLLISIONS = 1 << 4,
FLAG_RELATIVE_HR = 1 << 5
} flags;
}; };
} // namespace kp3d } // namespace kp3d

View file

@ -240,6 +240,7 @@ void Editor::Update()
KEY_SHORTCUT(SPACE, m_mode = MODE_NORMAL); KEY_SHORTCUT(SPACE, m_mode = MODE_NORMAL);
KEY_SHORTCUT(V, m_mode = MODE_BUILD); KEY_SHORTCUT(V, m_mode = MODE_BUILD);
KEY_SHORTCUT(T, m_mode = MODE_THINGS);
KEY_SHORTCUT(Z, { KEY_SHORTCUT(Z, {
if (sandbox->IsKeyDown(kp3d::KEY_LCTRL)) if (sandbox->IsKeyDown(kp3d::KEY_LCTRL))
Undo(); Undo();
@ -256,6 +257,7 @@ void Editor::Update()
{ {
case MODE_BUILD: UpdateModeBuild(); break; case MODE_BUILD: UpdateModeBuild(); break;
case MODE_NORMAL: UpdateModeNormal(); break; case MODE_NORMAL: UpdateModeNormal(); break;
case MODE_THINGS: UpdateModeThings(); break;
} }
} }
@ -268,6 +270,7 @@ void Editor::RenderMap()
{ {
case MODE_BUILD: RenderModeBuild(); break; case MODE_BUILD: RenderModeBuild(); break;
case MODE_NORMAL: RenderModeNormal(); break; case MODE_NORMAL: RenderModeNormal(); break;
case MODE_THINGS: RenderModeThings(); break;
} }
} }
@ -510,7 +513,7 @@ void Editor::UpdateModeNormal()
} }
if (!targets.empty()) if (!targets.empty())
{ {
std::sort(targets.begin(), targets.end(), [&](const Target& a, const Target& b) { return a.distance > b.distance; }); std::sort(targets.begin(), targets.end(), [](const Target& a, const Target& b) { return a.distance > b.distance; });
const Target& target = targets.back(); const Target& target = targets.back();
ray_pos = target.position; ray_pos = target.position;
} }
@ -858,6 +861,108 @@ void Editor::RenderModeNormal()
} }
} }
void Editor::UpdateModeThings()
{
using namespace kp3d;
struct Target
{
Vec3 position;
float distance;
union Data { RenderBatch3D* b; Thing* t; } object;
enum { BATCH, THING } object_type;
};
std::vector<Target> targets;
for (Thing& thing: sandbox->map.things)
{
std::vector<Vertex3D> vertex_data = thing.GetBox(true);
for (size_t i = 0; i < vertex_data.size(); i += 3)
{
Vec3 pos;
Triangle tri = {vertex_data[i].position, vertex_data[i + 1].position, vertex_data[i + 2].position};
auto ray = GetRayFromCamera(sandbox->camera);
bool raycast = RayIntersectsTriangle(ray[0], ray[1], &tri, pos);
if (raycast)
{
Target target;
target.position = pos;
target.distance = sqrtf(
pow(pos.x - sandbox->camera.position.x, 2) +
pow(pos.y - sandbox->camera.position.y, 2) +
pow(pos.z - sandbox->camera.position.z, 2)
);
target.object.b = nullptr;
target.object.t = &thing;
target.object_type = Target::THING;
targets.push_back(target);
}
}
}
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};
auto ray = GetRayFromCamera(sandbox->camera);
bool raycast = RayIntersectsTriangle(ray[0], ray[1], &tri, pos);
if (raycast)
{
Target target;
target.position = pos;
target.distance = sqrtf(
pow(pos.x - sandbox->camera.position.x, 2) +
pow(pos.y - sandbox->camera.position.y, 2) +
pow(pos.z - sandbox->camera.position.z, 2)
);
target.object.b = &b;
target.object.t = nullptr;
target.object_type = Target::BATCH;
targets.push_back(target);
}
}
}
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();
if (target.object_type == Target::BATCH)
{
ray_pos = target.position;
if (sandbox->IsMouseButtonDown(MOUSE_BUTTON_LEFT))
{
KP3D_LOG_INFO("Placed thing at {}", ray_pos);
PushAction();
sandbox->map.things.push_back(Thing(ray_pos));
sandbox->MouseButtonReset(MOUSE_BUTTON_LEFT);
}
m_hovered_thing = nullptr;
}
else
{
m_hovered_thing = target.object.t;
if (sandbox->IsMouseButtonDown(MOUSE_BUTTON_LEFT))
{
m_selected_thing = m_hovered_thing;
sandbox->MouseButtonReset(MOUSE_BUTTON_LEFT);
}
}
}
else
{
m_hovered_thing = nullptr;
}
}
void Editor::RenderModeThings()
{
for (kp3d::Thing& thing: sandbox->map.things)
thing.RenderBox(
&thing == m_selected_thing ? kp3d::Vec3{0.33f, 0.33f, 1.0f} :
(&thing == m_hovered_thing ? kp3d::Vec3{1.0f, 1.0f, 1.0f} : kp3d::Vec3{0.5f, 0.5f, 0.5f})
);
}
void Editor::RenderUI() void Editor::RenderUI()
{ {
// Menu bar // Menu bar
@ -881,8 +986,9 @@ void Editor::RenderUI()
} }
if (ImGui::BeginMenu("Mode")) if (ImGui::BeginMenu("Mode"))
{ {
if (ImGui::MenuItem("Normal Mode", "Space")) m_mode = MODE_NORMAL; if (ImGui::MenuItem("Normal Mode", "Space", m_mode == MODE_NORMAL)) m_mode = MODE_NORMAL;
if (ImGui::MenuItem("Build Mode", "V")) m_mode = MODE_BUILD; if (ImGui::MenuItem("Build Mode", "V", m_mode == MODE_BUILD)) m_mode = MODE_BUILD;
if (ImGui::MenuItem("Things Mode", "T", m_mode == MODE_THINGS)) m_mode = MODE_THINGS;
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("View")) if (ImGui::BeginMenu("View"))
@ -1006,6 +1112,7 @@ void Editor::RenderUIInfo()
{ {
case MODE_NORMAL: mode_str = "Normal"; break; case MODE_NORMAL: mode_str = "Normal"; break;
case MODE_BUILD: mode_str = "Build"; break; case MODE_BUILD: mode_str = "Build"; break;
case MODE_THINGS: mode_str = "Things"; break;
} }
ImGui::Text("Mode: %s\n", mode_str.c_str()); ImGui::Text("Mode: %s\n", mode_str.c_str());
if (m_mode == MODE_BUILD) if (m_mode == MODE_BUILD)
@ -1022,8 +1129,11 @@ void Editor::RenderUIInfo()
ImGui::EndPopup(); ImGui::EndPopup();
} }
} }
ImGui::Separator(); if (m_build_time > 0)
ImGui::Text("Map built in %fms\n", m_build_time); {
ImGui::Separator();
ImGui::Text("Map built in %fms\n", m_build_time);
}
ImGui::End(); ImGui::End();
} }
} }

View file

@ -9,11 +9,13 @@
#include "KP3D_IOEvents.h" #include "KP3D_IOEvents.h"
#include "KP3D_Material.h" #include "KP3D_Material.h"
#include "KP3D_Map.h" #include "KP3D_Map.h"
#include "KP3D_Thing.h"
enum EditMode enum EditMode
{ {
MODE_NORMAL, MODE_NORMAL,
MODE_BUILD, MODE_BUILD,
MODE_THINGS
}; };
enum WallPoint enum WallPoint
@ -45,6 +47,8 @@ public:
void RenderModeBuild(); void RenderModeBuild();
void UpdateModeNormal(); void UpdateModeNormal();
void RenderModeNormal(); void RenderModeNormal();
void UpdateModeThings();
void RenderModeThings();
void RenderUI(); void RenderUI();
void RenderUIInfo(); void RenderUIInfo();
@ -96,6 +100,7 @@ private:
char m_tex_filter_buf[512]; char m_tex_filter_buf[512];
std::vector<const kp3d::Material**> m_materials_to_update; std::vector<const kp3d::Material**> m_materials_to_update;
std::vector<const kp3d::Texture**> m_textures_to_update; std::vector<const kp3d::Texture**> m_textures_to_update;
kp3d::Thing* m_hovered_thing = nullptr,* m_selected_thing = nullptr;
WallUpdate wall_update; WallUpdate wall_update;
bool can_wall_update = false; bool can_wall_update = false;