Skip to content

Commit

Permalink
Add orthogonal renderer skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
albin-johansson committed Aug 25, 2024
1 parent b75cacf commit ee3281d
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 75 deletions.
2 changes: 2 additions & 0 deletions source/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ target_sources(tactile-core
"src/tactile/core/ui/menu/tileset_menu.cpp"
"src/tactile/core/ui/menu/view_menu.cpp"
"src/tactile/core/ui/render/hexagon_info.cpp"
"src/tactile/core/ui/render/orthogonal_renderer.cpp"
"src/tactile/core/ui/canvas_overlay.cpp"
"src/tactile/core/ui/canvas_renderer.cpp"
"src/tactile/core/ui/fonts.cpp"
Expand Down Expand Up @@ -259,6 +260,7 @@ target_sources(tactile-core
"inc/tactile/core/ui/menu/tileset_menu.hpp"
"inc/tactile/core/ui/menu/view_menu.hpp"
"inc/tactile/core/ui/render/hexagon_info.hpp"
"inc/tactile/core/ui/render/orthogonal_renderer.hpp"
"inc/tactile/core/ui/render/primitives.hpp"
"inc/tactile/core/ui/canvas_overlay.hpp"
"inc/tactile/core/ui/canvas_renderer.hpp"
Expand Down
15 changes: 15 additions & 0 deletions source/core/inc/tactile/core/ui/canvas_renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ class CanvasRenderer final
[[nodiscard]]
auto get_canvas_tile_size() const -> Float2;

/**
* Returns the canvas scale factor.
*
* \return
* A scale factor.
*/
[[nodiscard]]
auto get_scale() const -> float;

/**
* Converts a screen-space position to the corresponding world-space position.
*
Expand All @@ -197,6 +206,9 @@ class CanvasRenderer final
[[nodiscard]]
auto to_screen_pos(const Float2& world_pos) const noexcept -> Float2;

[[nodiscard]]
auto to_screen_pos(const MatrixIndex& tile_pos) const noexcept -> Float2;

/**
* Returns the draw list associated with the window.
*
Expand All @@ -222,6 +234,9 @@ class CanvasRenderer final
/** The bottom-right window corner position (screen-space). */
Float2 mWindowBR;

/** The scale factor of rendered content. */
float mScale;

/** The region visible via the current viewport. */
VisibleRegion mVisibleRegion;

Expand Down
22 changes: 22 additions & 0 deletions source/core/inc/tactile/core/ui/render/orthogonal_renderer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2024 Albin Johansson (GNU General Public License v3.0)

#pragma once

#include "tactile/base/prelude.hpp"
#include "tactile/core/entity/entity.hpp"
#include "tactile/core/ui/canvas_renderer.hpp"

namespace tactile {

class Registry;

namespace ui {

class CanvasRenderer;

void render_orthogonal_map(const CanvasRenderer& canvas_renderer,
const Registry& registry,
EntityID map_id);

} // namespace ui
} // namespace tactile
62 changes: 61 additions & 1 deletion source/core/inc/tactile/core/ui/render/primitives.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#include <imgui.h>

#include "tactile/base/meta/color.hpp"
#include "tactile/base/numeric/vec.hpp"
#include "tactile/base/prelude.hpp"
#include "tactile/core/meta/color.hpp"
Expand Down Expand Up @@ -37,6 +36,15 @@ inline void draw_rect(const Float2& screen_pos,
}
}

inline void draw_rect_shadowed(const Float2& screen_pos,
const Float2& size,
const UColor& color,
const float thickness = 1.0f)
{
draw_rect(screen_pos + Float2 {thickness, thickness}, size, kColorBlack, thickness);
draw_rect(screen_pos, size, color, thickness);
}

/**
* Renders a filled rectangle.
*
Expand Down Expand Up @@ -110,4 +118,56 @@ inline void draw_hexagon(const Float2& screen_pos,
draw_ngon(screen_pos, radius, color_mask, 6, thickness, half_pi);
}

inline void draw_hexagon_shadowed(const Float2& screen_pos,
const float radius,
const uint32 color_mask,
const float thickness = 1.0f)
{
draw_hexagon(screen_pos + Float2 {thickness, thickness}, radius, IM_COL32_BLACK, thickness);
draw_hexagon(screen_pos, radius, color_mask, thickness);
}

inline void draw_ellipse(const Float2& center_pos,
const Float2& radius,
const UColor& color,
const float thickness = 1.0f)
{
if (auto* draw_list = ImGui::GetWindowDrawList()) {
draw_list->AddEllipse(to_imvec2(center_pos),
to_imvec2(radius),
to_uint32_abgr(color),
0.0f,
50,
thickness);
}
}

inline void draw_ellipse_shadowed(const Float2& center_pos,
const Float2& radius,
const UColor& color,
const float thickness = 1.0f)
{
draw_ellipse(center_pos + Float2 {thickness, thickness}, radius, kColorBlack, thickness);
draw_ellipse(center_pos, radius, color, thickness);
}

inline void draw_circle(const Float2& center_pos,
const float radius,
const UColor& color,
const float thickness = 1.0f)
{
if (auto* draw_list = ImGui::GetWindowDrawList()) {
draw_list->AddCircle(to_imvec2(center_pos), radius, to_uint32_abgr(color), 0, thickness);
}
}

inline void draw_circle_shadowed(const Float2& center_pos,
const float radius,
const UColor& color,
const float thickness = 1.0f)
{
draw_circle(center_pos + Float2 {thickness, thickness}, radius, kColorBlack, thickness);
draw_circle(center_pos, radius, color, thickness);
}

} // namespace tactile::ui
11 changes: 11 additions & 0 deletions source/core/src/tactile/core/ui/canvas_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ CanvasRenderer::CanvasRenderer(const Float2& canvas_tl,
mCanvasTileSize {vec_cast<Float2>(tile_size) * viewport.scale},
mWindowTL {canvas_tl},
mWindowBR {canvas_br},
mScale {viewport.scale},
mVisibleRegion {_get_visible_region(mViewportPos, mWindowBR - mWindowTL)},
mVisibleTiles {_get_visible_tiles(mVisibleRegion, mCanvasTileSize)},
mRenderBounds {_get_render_bounds(mVisibleTiles, mExtent)}
Expand Down Expand Up @@ -181,6 +182,11 @@ auto CanvasRenderer::get_canvas_tile_size() const -> Float2
return mCanvasTileSize;
}

auto CanvasRenderer::get_scale() const -> float
{
return mScale;
}

auto CanvasRenderer::to_world_pos(const Float2& screen_pos) const noexcept -> Float2
{
return screen_pos + mViewportPos;
Expand All @@ -191,6 +197,11 @@ auto CanvasRenderer::to_screen_pos(const Float2& world_pos) const noexcept -> Fl
return world_pos - mViewportPos + mWindowTL;
}

auto CanvasRenderer::to_screen_pos(const MatrixIndex& tile_pos) const noexcept -> Float2
{
return to_screen_pos(to_float2(tile_pos) * mCanvasTileSize);
}

auto CanvasRenderer::get_draw_list() noexcept -> ImDrawList&
{
auto* const draw_list = ImGui::GetWindowDrawList();
Expand Down
152 changes: 78 additions & 74 deletions source/core/src/tactile/core/ui/dock/document_dock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,102 +11,113 @@
#include "tactile/core/event/event_dispatcher.hpp"
#include "tactile/core/event/viewport_events.hpp"
#include "tactile/core/map/map.hpp"
#include "tactile/core/meta/color.hpp"
#include "tactile/core/model/model.hpp"
#include "tactile/core/ui/canvas_overlay.hpp"
#include "tactile/core/ui/canvas_renderer.hpp"
#include "tactile/core/ui/common/buttons.hpp"
#include "tactile/core/ui/common/overlays.hpp"
#include "tactile/core/ui/common/widgets.hpp"
#include "tactile/core/ui/common/window.hpp"
#include "tactile/core/ui/i18n/language.hpp"
#include "tactile/core/ui/render/orthogonal_renderer.hpp"
#include "tactile/core/ui/viewport.hpp"

namespace tactile::ui {
namespace {

void _render_map(const Float2& canvas_tl,
const Float2& canvas_br,
const Registry& registry,
const EntityID map_id)
void _push_map_document_overlay(const Registry& registry,
const EntityID map_id,
const CanvasRenderer& canvas_renderer)
{
const auto& map = registry.get<CMap>(map_id);
const auto& viewport = registry.get<CViewport>(map_id);

const CanvasRenderer canvas_renderer {canvas_tl,
canvas_br,
map.extent,
map.tile_size,
viewport};

constexpr UColor bg_color {0x33, 0x33, 0x33, 0xFF};
canvas_renderer.clear_canvas(bg_color);
canvas_renderer.draw_orthogonal_grid(kColorBlack);
if (const OverlayScope overlay {"##MapDocumentOverlay", Float2 {1.0f, 0.0f}, 0.5f};
overlay.is_open()) {
const auto& viewport = registry.get<CViewport>(map_id);

push_viewport_info_section(viewport);
push_canvas_info_section(canvas_renderer);
push_viewport_mouse_info_section(canvas_renderer);
}
}

void _push_document_tab(const IDocument& document, EventDispatcher& dispatcher)
{
const auto canvas_tl = ImGui::GetCursorScreenPos();
const auto canvas_br = canvas_tl + ImGui::GetContentRegionAvail();
const auto canvas_size = canvas_br - canvas_tl;

const auto& registry = document.get_registry();
const auto& document_info = registry.get<CDocumentInfo>();

const auto& viewport = registry.get<CViewport>(document_info.root);
if (viewport.size != to_float2(canvas_size)) {
dispatcher.push<UpdateViewportSizeEvent>(document_info.root, to_float2(canvas_size));
}
const IdScope document_scope {document_info.root};

if (is_map(registry, document_info.root)) {
_render_map(to_float2(canvas_tl), to_float2(canvas_br), registry, document_info.root);
}
else {
// TODO render tileset
}
if (const TabItemScope tab {document_info.name.c_str()}; tab.is_open()) {
const auto canvas_tl = ImGui::GetCursorScreenPos();
const auto canvas_br = canvas_tl + ImGui::GetContentRegionAvail();
const auto canvas_size = canvas_br - canvas_tl;

ImGui::InvisibleButton("##Canvas", canvas_size, ImGuiButtonFlags_MouseButtonLeft);
const auto& viewport = registry.get<CViewport>(document_info.root);
if (viewport.size != to_float2(canvas_size)) {
dispatcher.push<UpdateViewportSizeEvent>(document_info.root, to_float2(canvas_size));
}

if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, 0.0f)) {
const auto delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left, 0.0f);
dispatcher.push<OffsetViewportEvent>(document_info.root, to_float2(-delta));
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Left);
}
const auto tile_size = document.get_tile_size();
const auto extent = document.get_extent();

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_8, ImGuiInputFlags_RouteFocused)) {
dispatcher.push<ResetViewportZoomEvent>(document_info.root);
}
const CanvasRenderer canvas_renderer {to_float2(canvas_tl),
to_float2(canvas_br),
extent,
tile_size,
viewport};

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_9,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<DecreaseViewportZoomEvent>(document_info.root);
}
if (is_map(registry, document_info.root)) {
render_orthogonal_map(canvas_renderer, registry, document_info.root);
_push_map_document_overlay(registry, document_info.root, canvas_renderer);
}
else {
// TODO render tileset
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_0,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<IncreaseViewportZoomEvent>(document_info.root);
}
ImGui::InvisibleButton("##Canvas", canvas_size, ImGuiButtonFlags_MouseButtonLeft);

if (ImGui::Shortcut(ImGuiMod_Shift | ImGuiKey_Space, ImGuiInputFlags_RouteFocused)) {
dispatcher.push<CenterViewportEvent>(document_info.root, document.get_content_size());
}
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, 0.0f)) {
const auto delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left, 0.0f);
dispatcher.push<OffsetViewportEvent>(document_info.root, to_float2(-delta));
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Left);
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_UpArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportUpEvent>(document_info.root);
}
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_8, ImGuiInputFlags_RouteFocused)) {
dispatcher.push<ResetViewportZoomEvent>(document_info.root);
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_DownArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportDownEvent>(document_info.root);
}
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_9,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<DecreaseViewportZoomEvent>(document_info.root);
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_LeftArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportLeftEvent>(document_info.root);
}
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_0,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<IncreaseViewportZoomEvent>(document_info.root);
}

if (ImGui::Shortcut(ImGuiMod_Shift | ImGuiKey_Space, ImGuiInputFlags_RouteFocused)) {
dispatcher.push<CenterViewportEvent>(document_info.root, document.get_content_size());
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_UpArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportUpEvent>(document_info.root);
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_DownArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportDownEvent>(document_info.root);
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_LeftArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportLeftEvent>(document_info.root);
}

if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_RightArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportRightEvent>(document_info.root);
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_RightArrow,
ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat)) {
dispatcher.push<PanViewportRightEvent>(document_info.root);
}
}
}

Expand All @@ -118,14 +129,7 @@ void _push_document_tabs(const Model& model, EventDispatcher& dispatcher)

for (const auto& document_uuid : open_documents) {
const auto& document = document_manager.get_document(document_uuid);

const auto& registry = document.get_registry();
const auto& document_info = registry.get<CDocumentInfo>();

const IdScope document_scope {document_info.root};
if (const TabItemScope tab {document_info.name.c_str()}; tab.is_open()) {
_push_document_tab(document, dispatcher);
}
_push_document_tab(document, dispatcher);
}
}
}
Expand Down
Loading

0 comments on commit ee3281d

Please sign in to comment.