implement basic level editing
This commit is contained in:
@@ -10,8 +10,8 @@ struct position final : strong::alias<glm::vec2, position> {
|
||||
using strong::alias<glm::vec2, position>::alias;
|
||||
};
|
||||
|
||||
struct tile_position final : strong::alias<glm::vec2, tile_position> {
|
||||
using strong::alias<glm::vec2, tile_position>::alias;
|
||||
struct tile_position final : strong::alias<glm::uvec2, tile_position> {
|
||||
using strong::alias<glm::uvec2, tile_position>::alias;
|
||||
};
|
||||
|
||||
struct render_id : strong::alias<std::uint32_t, render_id> {
|
||||
|
||||
@@ -290,6 +290,50 @@ engine::add_single_tile_to_render_request(render::request request,
|
||||
|
||||
return request.add_lines(lines, glm::vec3(1.0f, 1.0f, 0.0f));
|
||||
}
|
||||
|
||||
std::optional<glm::uvec2>
|
||||
engine::calculate_intersected_tile(glm::mat4 view, glm::mat4 projection,
|
||||
glm::vec2 mouse) const {
|
||||
const float width = static_cast<float>(display.extent().x);
|
||||
const float height = static_cast<float>(display.extent().y);
|
||||
|
||||
float x = (2.0f * mouse.x) / width - 1.0f;
|
||||
float y = 1.0f - (2.0f * mouse.y) / height;
|
||||
|
||||
glm::vec4 near_clip = glm::vec4(x, y, -1.0f, 1.0f);
|
||||
glm::vec4 far_clip = glm::vec4(x, y, 1.0f, 1.0f);
|
||||
|
||||
glm::vec4 near_world = glm::inverse(projection * view) * near_clip;
|
||||
glm::vec4 far_world = glm::inverse(projection * view) * far_clip;
|
||||
|
||||
near_world /= near_world.w;
|
||||
far_world /= far_world.w;
|
||||
|
||||
glm::vec3 ray_world = glm::normalize(glm::vec3(far_world - near_world));
|
||||
glm::vec3 cam_pos = glm::vec3(near_world);
|
||||
|
||||
if (std::abs(ray_world.y) < 1e-5f) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
float t = -cam_pos.y / ray_world.y;
|
||||
glm::vec3 hit = cam_pos + ray_world * t;
|
||||
|
||||
const auto full_dimensions = area_size * 2.0f;
|
||||
const float cell_width = full_dimensions.x / 22.0f;
|
||||
const float cell_depth = full_dimensions.z / 16.0f;
|
||||
|
||||
const auto start = area_origin - area_size;
|
||||
|
||||
int tile_x = static_cast<int>((hit.x - start.x) / cell_width);
|
||||
int tile_y = static_cast<int>((hit.z - start.z) / cell_depth);
|
||||
|
||||
tile_x = std::clamp(tile_x, 0, 21);
|
||||
tile_y = std::clamp(tile_y, 0, 15);
|
||||
|
||||
return glm::uvec2(tile_x, tile_y);
|
||||
}
|
||||
|
||||
engine::mesh_bounds engine::compute_size_of_mesh(const mesh_node &mesh) {
|
||||
auto bounds = mesh_bounds();
|
||||
|
||||
@@ -441,6 +485,28 @@ void engine::do_level_editor_ui() {
|
||||
|
||||
ImGui::Checkbox("Enabled", &is_editing_level);
|
||||
|
||||
static int wall_type = 0;
|
||||
ImGui::Combo("Wall Type", &wall_type, "cork\0solid\0\0");
|
||||
level_editing_data.type_to_write =
|
||||
static_cast<components::wall_type>(wall_type);
|
||||
|
||||
static int wall_height = 0;
|
||||
ImGui::Combo("Wall Height", &wall_height, "half\0full\0\0");
|
||||
level_editing_data.height_to_write =
|
||||
static_cast<components::wall_height>(wall_height);
|
||||
|
||||
if (level_editing_data.intersected_tile.has_value()) {
|
||||
// Todo: Check for validity based on same types
|
||||
if (ImGui::Button("Add Wall To Tile")) {
|
||||
auto entity = current_level->get_or_create_entity_at(
|
||||
*level_editing_data.intersected_tile);
|
||||
auto &wall = current_level->get_entities()
|
||||
->get_or_emplace<components::wall_definition>(entity);
|
||||
wall.type = level_editing_data.type_to_write;
|
||||
wall.heights[wall.wall_count++] = level_editing_data.height_to_write;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -479,12 +545,6 @@ void engine::run() {
|
||||
|
||||
auto request = render::request();
|
||||
|
||||
if (!ImGui::GetIO().WantCaptureMouse) {
|
||||
const auto mx = ImGui::GetIO().MousePos;
|
||||
std::println("mouse {}, {}", mx.x, mx.y);
|
||||
// request = request.add_circle({mx.x, mx.y}, 1.0f);
|
||||
}
|
||||
|
||||
request = add_level_bounds_to_render_request(request);
|
||||
if (current_level.has_value()) {
|
||||
request = add_level_to_render_request(request, &(*current_level));
|
||||
@@ -498,10 +558,18 @@ void engine::run() {
|
||||
request = add_tiles_to_render_request(request);
|
||||
}
|
||||
|
||||
level_editing_data.intersected_tile = glm::uvec2(5, 5);
|
||||
if (level_editing_data.intersected_tile.has_value()) {
|
||||
request = add_single_tile_to_render_request(
|
||||
request, *level_editing_data.intersected_tile);
|
||||
if (debug_drawing.level_editor) {
|
||||
if (!ImGui::GetIO().WantCaptureMouse) {
|
||||
const auto mx = ImGui::GetIO().MousePos;
|
||||
if (ImGui::GetIO().MouseDown[0]) {
|
||||
level_editing_data.intersected_tile =
|
||||
calculate_intersected_tile(view, projection, {mx.x, mx.y});
|
||||
}
|
||||
if (level_editing_data.intersected_tile.has_value()) {
|
||||
request = add_single_tile_to_render_request(
|
||||
request, *level_editing_data.intersected_tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderer.render(request, view, projection);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef TANKS_ENGINE_HPP
|
||||
#define TANKS_ENGINE_HPP
|
||||
|
||||
#include "game/components.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
@@ -47,6 +48,9 @@ private:
|
||||
std::optional<level> current_level = level();
|
||||
struct {
|
||||
std::optional<glm::uvec2> intersected_tile;
|
||||
|
||||
components::wall_height height_to_write;
|
||||
components::wall_type type_to_write;
|
||||
} level_editing_data;
|
||||
bool is_editing_level = false;
|
||||
struct {
|
||||
@@ -81,6 +85,10 @@ private:
|
||||
add_single_tile_to_render_request(render::request request,
|
||||
glm::uvec2 tile) const;
|
||||
|
||||
[[nodiscard]] std::optional<glm::uvec2>
|
||||
calculate_intersected_tile(glm::mat4 view, glm::mat4 projection,
|
||||
glm::vec2 mouse) const;
|
||||
|
||||
struct mesh_bounds {
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
|
||||
@@ -44,4 +44,18 @@ entt::basic_registry<std::uint32_t> *level::get_entities() { return &entities; }
|
||||
|
||||
glm::uvec2 level::get_bounds() const noexcept { return {WIDTH, HEIGHT}; }
|
||||
|
||||
std::uint32_t level::get_or_create_entity_at(glm::uvec2 tile) {
|
||||
for (const auto [entity, e_tile] :
|
||||
entities.view<components::tile_position>()->each()) {
|
||||
if (static_cast<glm::uvec2>(e_tile) == tile) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
auto created = entities.create();
|
||||
entities.emplace<components::tile_position>(created, tile);
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
} // namespace trb::game
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
[[nodiscard]] glm::uvec2 get_bounds() const noexcept;
|
||||
|
||||
[[nodiscard]] entt::basic_registry<std::uint32_t> *get_entities();
|
||||
|
||||
[[nodiscard]] std::uint32_t get_or_create_entity_at(glm::uvec2 tile);
|
||||
};
|
||||
} // namespace trb::game
|
||||
|
||||
|
||||
Reference in New Issue
Block a user