From e812406a15bf1b9ab66e9ab60668e1d2fc413fdb Mon Sep 17 00:00:00 2001 From: mniip Date: Fri, 14 Apr 2023 10:45:36 +0200 Subject: [PATCH] Refactor zoom window --- src/common/Vec2.h | 16 +++-- src/graphics/RasterDrawMethods.h | 1 + src/graphics/RasterDrawMethodsImpl.h | 8 +++ src/graphics/Renderer.h | 22 ++++-- src/graphics/RendererBasic.cpp | 50 ++++--------- src/gui/game/GameController.cpp | 20 +++--- src/gui/game/GameModel.cpp | 103 +++++++++++++++------------ src/gui/game/GameModel.h | 43 ++++++----- src/lua/LuaScriptInterface.cpp | 63 ++++++++-------- 9 files changed, 178 insertions(+), 148 deletions(-) diff --git a/src/common/Vec2.h b/src/common/Vec2.h index e39276fe0..4bf106b69 100644 --- a/src/common/Vec2.h +++ b/src/common/Vec2.h @@ -128,7 +128,7 @@ struct Vec2 // Return a rectangle starting at origin, whose dimensions match this vector template>> - constexpr inline Rect OriginRect() const + constexpr Rect OriginRect() const { return RectSized(Vec2(0, 0), *this); } @@ -379,23 +379,29 @@ public: ); } - inline Rect &operator|=(Rect other) + Rect &operator|=(Rect other) { return *this = *this | other; } - inline Rect &operator&=(Rect other) + Rect &operator&=(Rect other) { return *this = *this & other; } - inline bool Contains(Vec2 point) const + bool Contains(Vec2 point) const { return point.X >= TopLeft.X && point.X <= BottomRight.X && point.Y >= TopLeft.Y && point.Y <= BottomRight.Y; } + // Whether rect fits inside this, assuming **rect is not empty** + bool Contains(Rect rect) const + { + return rect.TopLeft.X >= TopLeft.X && rect.BottomRight.X <= BottomRight.X && rect.TopLeft.Y >= TopLeft.Y && rect.BottomRight.Y <= BottomRight.Y; + } + template>> - inline Vec2 Size() const + Vec2 Size() const { return BottomRight - TopLeft + Vec2(1, 1); } diff --git a/src/graphics/RasterDrawMethods.h b/src/graphics/RasterDrawMethods.h index 83add64d3..722978f54 100644 --- a/src/graphics/RasterDrawMethods.h +++ b/src/graphics/RasterDrawMethods.h @@ -22,6 +22,7 @@ struct RasterDrawMethods void DrawRect(Rect, RGB); void BlendRect(Rect, RGBA); + void XorRect(Rect); void XorDottedRect(Rect); diff --git a/src/graphics/RasterDrawMethodsImpl.h b/src/graphics/RasterDrawMethodsImpl.h index a177a41d2..9f50a5cd7 100644 --- a/src/graphics/RasterDrawMethodsImpl.h +++ b/src/graphics/RasterDrawMethodsImpl.h @@ -111,6 +111,14 @@ void RasterDrawMethods::BlendRect(Rect rect, RGBA colour) }); } +template +void RasterDrawMethods::XorRect(Rect rect) +{ + RasterizeRect(rect, [this](Vec2 pos) { + XorPixel(pos); + }); +} + template void RasterDrawMethods::XorDottedRect(Rect rect) { diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index 55df6f507..e4ad1cf67 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "Graphics.h" #include "gui/interface/Point.h" @@ -47,6 +48,8 @@ class Renderer: public RasterDrawMethods friend struct RasterDrawMethods; + void renderZoom(); + public: Vec2 Size() const { @@ -86,17 +89,24 @@ public: ui::Point mousePos; //Zoom window - ui::Point zoomWindowPosition; - ui::Point zoomScopePosition; - int zoomScopeSize; - bool zoomEnabled; - int ZFACTOR; + struct ZoomSettings + { + Vec2 ScopePosition; + int ScopeSize; + int Factor; + Vec2 WindowPosition; + + static int WindowSize(int scopeSize, int factor) + { + return scopeSize * factor - 1; + } + }; + std::optional Zoom; //Renderers void RenderBegin(); void RenderEnd(); - void RenderZoom(); void DrawBlob(int x, int y, unsigned char cr, unsigned char cg, unsigned char cb); void DrawWalls(); void DrawSigns(); diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index 5a452d15b..701d439ee 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -44,7 +44,7 @@ void Renderer::RenderBegin() void Renderer::RenderEnd() { - RenderZoom(); + renderZoom(); } void Renderer::SetSample(int x, int y) @@ -73,39 +73,24 @@ void Renderer::FinaliseParts() } } -void Renderer::RenderZoom() +void Renderer::renderZoom() { - if(!zoomEnabled) + if (!Zoom) return; + + auto const factor = Zoom->Factor; + auto const size = Zoom->ScopeSize; + auto const scope = RectSized(Zoom->ScopePosition, Vec2(1, 1) * size); + auto const window = RectSized(Zoom->WindowPosition, Vec2(1, 1) * ZoomSettings::WindowSize(Zoom->ScopeSize, factor)); + DrawFilledRect(window.Inset(-1), 0x000000_rgb); + DrawRect(window.Inset(-2), 0xC0C0C0_rgb); + for (auto offset : (Vec2(1, 1) * size).OriginRect()) { - int x, y, i, j; - pixel pix; - pixel * img = vid; - clearrect(zoomWindowPosition.X-1, zoomWindowPosition.Y-1, zoomScopeSize*ZFACTOR+1, zoomScopeSize*ZFACTOR+1); - drawrect(zoomWindowPosition.X-2, zoomWindowPosition.Y-2, zoomScopeSize*ZFACTOR+3, zoomScopeSize*ZFACTOR+3, 192, 192, 192, 255); - drawrect(zoomWindowPosition.X-1, zoomWindowPosition.Y-1, zoomScopeSize*ZFACTOR+1, zoomScopeSize*ZFACTOR+1, 0, 0, 0, 255); - for (j=0; jScopePosition + offset]; + for (auto pxOffset : Vec2(factor - 1, factor - 1).OriginRect()) + video[Zoom->WindowPosition + offset * factor + pxOffset] = px; } + XorRect(scope.Inset(-1)); } void Renderer::DrawBlob(int x, int y, unsigned char cr, unsigned char cg, unsigned char cb) @@ -275,11 +260,6 @@ Renderer::Renderer(Simulation * sim): findingElement(0), foundElements(0), mousePos(0, 0), - zoomWindowPosition(0, 0), - zoomScopePosition(0, 0), - zoomScopeSize(32), - zoomEnabled(false), - ZFACTOR(8), gridSize(0) { PopulateTables(); diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index 9d9588b27..a4c0bff98 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -299,14 +299,14 @@ void GameController::AdjustZoomSize(int delta, bool logarithmic) { int newSize; if(logarithmic) - newSize = gameModel->GetZoomSize() + std::max(gameModel->GetZoomSize() / 10, 1) * delta; + newSize = gameModel->GetZoomScopeSize() + std::max(gameModel->GetZoomScopeSize() / 10, 1) * delta; else - newSize = gameModel->GetZoomSize() + delta; + newSize = gameModel->GetZoomScopeSize() + delta; if(newSize<5) newSize = 5; if(newSize>64) newSize = 64; - gameModel->SetZoomSize(newSize); + gameModel->SetZoomScopeSize(newSize); int newZoomFactor = 256/newSize; if(newZoomFactor<3) @@ -928,21 +928,21 @@ void GameController::SetToolStrength(float value) void GameController::SetZoomPosition(ui::Point position) { - ui::Point zoomPosition = position-(gameModel->GetZoomSize()/2); + ui::Point zoomPosition = position-(gameModel->GetZoomScopeSize()/2); if(zoomPosition.X < 0) zoomPosition.X = 0; if(zoomPosition.Y < 0) zoomPosition.Y = 0; - if(zoomPosition.X >= XRES-gameModel->GetZoomSize()) - zoomPosition.X = XRES-gameModel->GetZoomSize(); - if(zoomPosition.Y >= YRES-gameModel->GetZoomSize()) - zoomPosition.Y = YRES-gameModel->GetZoomSize(); + if(zoomPosition.X >= XRES-gameModel->GetZoomScopeSize()) + zoomPosition.X = XRES-gameModel->GetZoomScopeSize(); + if(zoomPosition.Y >= YRES-gameModel->GetZoomScopeSize()) + zoomPosition.Y = YRES-gameModel->GetZoomScopeSize(); ui::Point zoomWindowPosition = ui::Point(0, 0); if(position.X < XRES/2) - zoomWindowPosition.X = XRES-(gameModel->GetZoomSize()*gameModel->GetZoomFactor()); + zoomWindowPosition.X = XRES-(gameModel->GetZoomScopeSize()*gameModel->GetZoomFactor()); - gameModel->SetZoomPosition(zoomPosition); + gameModel->SetZoomScopePosition(zoomPosition); gameModel->SetZoomWindowPosition(zoomWindowPosition); } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index d8a56f114..84dce290f 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -1075,85 +1075,96 @@ void GameModel::SetLastTool(Tool * newTool) void GameModel::SetZoomEnabled(bool enabled) { - ren->zoomEnabled = enabled; + if (enabled) + ren->Zoom = zoomSettings; + else + ren->Zoom = std::nullopt; notifyZoomChanged(); } -bool GameModel::GetZoomEnabled() +bool GameModel::GetZoomEnabled() const { - return ren->zoomEnabled; + return bool(ren->Zoom); } -void GameModel::SetZoomPosition(ui::Point position) +void GameModel::SetZoomScopePosition(Vec2 position) { - ren->zoomScopePosition = position; + zoomSettings.ScopePosition = position; + if (ren->Zoom) + ren->Zoom->ScopePosition = position; notifyZoomChanged(); } -ui::Point GameModel::GetZoomPosition() +Vec2 GameModel::GetZoomScopePosition() const { - return ren->zoomScopePosition; + return zoomSettings.ScopePosition; } -bool GameModel::MouseInZoom(ui::Point position) +void GameModel::SetZoomWindowPosition(Vec2 position) { - if (!GetZoomEnabled()) - return false; - - int zoomFactor = GetZoomFactor(); - ui::Point zoomWindowPosition = GetZoomWindowPosition(); - ui::Point zoomWindowSize = ui::Point(GetZoomSize()*zoomFactor, GetZoomSize()*zoomFactor); - - if (position.X >= zoomWindowPosition.X && position.Y >= zoomWindowPosition.Y && position.X < zoomWindowPosition.X+zoomWindowSize.X && position.Y < zoomWindowPosition.Y+zoomWindowSize.Y) - return true; - return false; -} - -ui::Point GameModel::AdjustZoomCoords(ui::Point position) -{ - if (!GetZoomEnabled()) - return position; - - int zoomFactor = GetZoomFactor(); - ui::Point zoomWindowPosition = GetZoomWindowPosition(); - ui::Point zoomWindowSize = ui::Point(GetZoomSize()*zoomFactor, GetZoomSize()*zoomFactor); - - if (position.X >= zoomWindowPosition.X && position.Y >= zoomWindowPosition.Y && position.X < zoomWindowPosition.X+zoomWindowSize.X && position.Y < zoomWindowPosition.Y+zoomWindowSize.Y) - return ((position-zoomWindowPosition)/GetZoomFactor())+GetZoomPosition(); - return position; -} - -void GameModel::SetZoomWindowPosition(ui::Point position) -{ - ren->zoomWindowPosition = position; + zoomSettings.WindowPosition = position; + if (ren->Zoom) + ren->Zoom->WindowPosition = position; notifyZoomChanged(); } -ui::Point GameModel::GetZoomWindowPosition() +Vec2 GameModel::GetZoomWindowPosition() const { - return ren->zoomWindowPosition; + return zoomSettings.WindowPosition; } -void GameModel::SetZoomSize(int size) +void GameModel::SetZoomScopeSize(int size) { - ren->zoomScopeSize = size; + zoomSettings.ScopeSize = size; + if (ren->Zoom) + ren->Zoom->ScopeSize = size; notifyZoomChanged(); } -int GameModel::GetZoomSize() +int GameModel::GetZoomScopeSize() const { - return ren->zoomScopeSize; + return zoomSettings.ScopeSize; } void GameModel::SetZoomFactor(int factor) { - ren->ZFACTOR = factor; + zoomSettings.Factor = factor; + if (ren->Zoom) + ren->Zoom->Factor = factor; notifyZoomChanged(); } -int GameModel::GetZoomFactor() +int GameModel::GetZoomFactor() const { - return ren->ZFACTOR; + return zoomSettings.Factor; +} + +bool GameModel::MouseInZoom(Vec2 position) const +{ + if (!GetZoomEnabled()) + return false; + + auto const window = RectSized( + GetZoomWindowPosition(), + Vec2(1, 1) * Renderer::ZoomSettings::WindowSize(GetZoomScopeSize(), GetZoomFactor()) + ); + return window.Contains(position); +} + +Vec2 GameModel::AdjustZoomCoords(Vec2 position) const +{ + if (!GetZoomEnabled()) + return position; + + auto const factor = GetZoomFactor(); + auto const window = RectSized( + GetZoomWindowPosition(), + Vec2(1, 1) * Renderer::ZoomSettings::WindowSize(GetZoomScopeSize(), factor) + ); + if (window.Contains(position)) + return (position - window.TopLeft) / factor + GetZoomScopePosition(); + else + return position; } void GameModel::SetActiveColourPreset(size_t preset) diff --git a/src/gui/game/GameModel.h b/src/gui/game/GameModel.h index 17a3135e1..bd8ba8ed3 100644 --- a/src/gui/game/GameModel.h +++ b/src/gui/game/GameModel.h @@ -1,10 +1,11 @@ #pragma once -#include "gui/interface/Colour.h" -#include "client/User.h" -#include "gui/interface/Point.h" -#include #include #include +#include +#include "client/User.h" +#include "graphics/Renderer.h" +#include "gui/interface/Colour.h" +#include "gui/interface/Point.h" class Menu; class Tool; @@ -16,7 +17,6 @@ class GameController; class SaveInfo; class SaveFile; class Simulation; -class Renderer; class Snapshot; struct SnapshotDelta; class GameSave; @@ -90,7 +90,14 @@ private: String infoTip; String toolTip; - //bool zoomEnabled; + + Renderer::ZoomSettings zoomSettings = { + Vec2::Zero, + 32, + 8, + Vec2::Zero, + }; + void notifyRendererChanged(); void notifySimulationChanged(); void notifyPausedChanged(); @@ -208,18 +215,18 @@ public: void SetUser(User user); Simulation * GetSimulation(); Renderer * GetRenderer(); - void SetZoomEnabled(bool enabled); - bool GetZoomEnabled(); - void SetZoomSize(int size); - int GetZoomSize(); - void SetZoomFactor(int factor); - int GetZoomFactor(); - void SetZoomPosition(ui::Point position); - ui::Point GetZoomPosition(); - bool MouseInZoom(ui::Point position); - ui::Point AdjustZoomCoords(ui::Point position); - void SetZoomWindowPosition(ui::Point position); - ui::Point GetZoomWindowPosition(); + void SetZoomEnabled(bool); + bool GetZoomEnabled() const; + void SetZoomScopeSize(int); + int GetZoomScopeSize() const; + void SetZoomFactor(int); + int GetZoomFactor() const; + void SetZoomScopePosition(Vec2); + Vec2 GetZoomScopePosition() const; + void SetZoomWindowPosition(Vec2); + Vec2 GetZoomWindowPosition() const; + bool MouseInZoom(Vec2) const; + Vec2 AdjustZoomCoords(Vec2) const; void SetClipboard(GameSave * save); void SetPlaceSave(GameSave * save); void Log(String message, bool printToFile); diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 8d0b365c5..922482efd 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -2724,13 +2724,13 @@ int LuaScriptInterface::renderer_zoomEnabled(lua_State * l) { if (lua_gettop(l) == 0) { - lua_pushboolean(l, luacon_ren->zoomEnabled); + lua_pushboolean(l, luacon_model->GetZoomEnabled()); return 1; } else { luaL_checktype(l, -1, LUA_TBOOLEAN); - luacon_ren->zoomEnabled = lua_toboolean(l, -1); + luacon_model->SetZoomEnabled(lua_toboolean(l, -1)); return 0; } } @@ -2738,53 +2738,60 @@ int LuaScriptInterface::renderer_zoomWindowInfo(lua_State * l) { if (lua_gettop(l) == 0) { - ui::Point location = luacon_ren->zoomWindowPosition; - lua_pushnumber(l, location.X); - lua_pushnumber(l, location.Y); - lua_pushnumber(l, luacon_ren->ZFACTOR); - lua_pushnumber(l, luacon_ren->zoomScopeSize * luacon_ren->ZFACTOR); + Vec2 const windowPos = luacon_model->GetZoomWindowPosition(); + lua_pushnumber(l, windowPos.X); + lua_pushnumber(l, windowPos.Y); + lua_pushnumber(l, luacon_model->GetZoomFactor()); + lua_pushnumber(l, luacon_model->GetZoomScopeSize() * luacon_model->GetZoomFactor()); return 4; } - int x = luaL_optint(l, 1, 0); - int y = luaL_optint(l, 2, 0); - int f = luaL_optint(l, 3, 0); - if (f <= 0) + int const x = luaL_optint(l, 1, 0); + int const y = luaL_optint(l, 2, 0); + int const factor = luaL_optint(l, 3, 0); + if (factor <= 0) return luaL_error(l, "Zoom factor must be greater than 0"); + auto const window = RectSized( + Vec2(x, y), + Vec2(1, 1) * Renderer::ZoomSettings::WindowSize(luacon_model->GetZoomScopeSize(), factor) + ); // To prevent crash when zoom window is outside screen - if (x < 0 || y < 0 || luacon_ren->zoomScopeSize * f + x > XRES || luacon_ren->zoomScopeSize * f + y > YRES) + if (!RES.OriginRect().Contains(window)) return luaL_error(l, "Zoom window outside of bounds"); - luacon_ren->zoomWindowPosition = ui::Point(x, y); - luacon_ren->ZFACTOR = f; + luacon_model->SetZoomWindowPosition(Vec2(x, y)); + luacon_model->SetZoomFactor(factor); return 0; } int LuaScriptInterface::renderer_zoomScopeInfo(lua_State * l) { if (lua_gettop(l) == 0) { - ui::Point location = luacon_ren->zoomScopePosition; - lua_pushnumber(l, location.X); - lua_pushnumber(l, location.Y); - lua_pushnumber(l, luacon_ren->zoomScopeSize); + Vec2 const scopePos = luacon_model->GetZoomScopePosition(); + lua_pushnumber(l, scopePos.X); + lua_pushnumber(l, scopePos.Y); + lua_pushnumber(l, luacon_model->GetZoomScopeSize()); return 3; } - int x = luaL_optint(l, 1, 0); - int y = luaL_optint(l, 2, 0); - int s = luaL_optint(l, 3, 0); - if (s <= 0) + int const x = luaL_optint(l, 1, 0); + int const y = luaL_optint(l, 2, 0); + int const size = luaL_optint(l, 3, 0); + if (size <= 0) return luaL_error(l, "Zoom scope size must be greater than 0"); + auto const scope = RectSized(Vec2(x, y), Vec2(1, 1) * size); + auto const window = RectSized( + luacon_model->GetZoomWindowPosition(), + Vec2(1, 1) * Renderer::ZoomSettings::WindowSize(size, luacon_model->GetZoomFactor()) + ); // To prevent crash when zoom or scope window is outside screen - int windowEdgeRight = luacon_ren->ZFACTOR * s + luacon_ren->zoomWindowPosition.X; - int windowEdgeBottom = luacon_ren->ZFACTOR * s + luacon_ren->zoomWindowPosition.Y; - if (x < 0 || y < 0 || x + s > XRES || y + s > YRES) + if (!RES.OriginRect().Contains(scope)) return luaL_error(l, "Zoom scope outside of bounds"); - if (windowEdgeRight > XRES || windowEdgeBottom > YRES) + if (!RES.OriginRect().Contains(window)) return luaL_error(l, "Zoom window outside of bounds"); - luacon_ren->zoomScopePosition = ui::Point(x, y); - luacon_ren->zoomScopeSize = s; + luacon_model->SetZoomScopePosition(Vec2(x, y)); + luacon_model->SetZoomScopeSize(size); return 0; }