Refactor zoom window

This commit is contained in:
mniip 2023-04-14 10:45:36 +02:00
parent c23eba1921
commit e812406a15
9 changed files with 178 additions and 148 deletions

View File

@ -128,7 +128,7 @@ struct Vec2
// Return a rectangle starting at origin, whose dimensions match this vector
template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>>
constexpr inline Rect<T> OriginRect() const
constexpr Rect<T> OriginRect() const
{
return RectSized(Vec2<T>(0, 0), *this);
}
@ -379,23 +379,29 @@ public:
);
}
inline Rect<T> &operator|=(Rect<T> other)
Rect<T> &operator|=(Rect<T> other)
{
return *this = *this | other;
}
inline Rect<T> &operator&=(Rect<T> other)
Rect<T> &operator&=(Rect<T> other)
{
return *this = *this & other;
}
inline bool Contains(Vec2<T> point) const
bool Contains(Vec2<T> 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<T> rect) const
{
return rect.TopLeft.X >= TopLeft.X && rect.BottomRight.X <= BottomRight.X && rect.TopLeft.Y >= TopLeft.Y && rect.BottomRight.Y <= BottomRight.Y;
}
template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>>
inline Vec2<T> Size() const
Vec2<T> Size() const
{
return BottomRight - TopLeft + Vec2<T>(1, 1);
}

View File

@ -22,6 +22,7 @@ struct RasterDrawMethods
void DrawRect(Rect<int>, RGB<uint8_t>);
void BlendRect(Rect<int>, RGBA<uint8_t>);
void XorRect(Rect<int>);
void XorDottedRect(Rect<int>);

View File

@ -111,6 +111,14 @@ void RasterDrawMethods<Derived>::BlendRect(Rect<int> rect, RGBA<uint8_t> colour)
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::XorRect(Rect<int> rect)
{
RasterizeRect(rect, [this](Vec2<int> pos) {
XorPixel(pos);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::XorDottedRect(Rect<int> rect)
{

View File

@ -2,6 +2,7 @@
#include <array>
#include <memory>
#include <mutex>
#include <optional>
#include <vector>
#include "Graphics.h"
#include "gui/interface/Point.h"
@ -47,6 +48,8 @@ class Renderer: public RasterDrawMethods<Renderer>
friend struct RasterDrawMethods<Renderer>;
void renderZoom();
public:
Vec2<int> 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<int> ScopePosition;
int ScopeSize;
int Factor;
Vec2<int> WindowPosition;
static int WindowSize(int scopeSize, int factor)
{
return scopeSize * factor - 1;
}
};
std::optional<ZoomSettings> 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();

View File

@ -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; j<zoomScopeSize; j++)
for (i=0; i<zoomScopeSize; i++)
{
pix = img[(j+zoomScopePosition.Y)*(VIDXRES)+(i+zoomScopePosition.X)];
for (y=0; y<ZFACTOR-1; y++)
for (x=0; x<ZFACTOR-1; x++)
img[(j*ZFACTOR+y+zoomWindowPosition.Y)*(VIDXRES)+(i*ZFACTOR+x+zoomWindowPosition.X)] = pix;
}
if (zoomEnabled)
{
for (j=-1; j<=zoomScopeSize; j++)
{
xor_pixel(zoomScopePosition.X+j, zoomScopePosition.Y-1);
xor_pixel(zoomScopePosition.X+j, zoomScopePosition.Y+zoomScopeSize);
}
for (j=0; j<zoomScopeSize; j++)
{
xor_pixel(zoomScopePosition.X-1, zoomScopePosition.Y+j);
xor_pixel(zoomScopePosition.X+zoomScopeSize, zoomScopePosition.Y+j);
}
}
pixel px = video[Zoom->ScopePosition + 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();

View File

@ -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);
}

View File

@ -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<int> position)
{
ren->zoomScopePosition = position;
zoomSettings.ScopePosition = position;
if (ren->Zoom)
ren->Zoom->ScopePosition = position;
notifyZoomChanged();
}
ui::Point GameModel::GetZoomPosition()
Vec2<int> GameModel::GetZoomScopePosition() const
{
return ren->zoomScopePosition;
return zoomSettings.ScopePosition;
}
bool GameModel::MouseInZoom(ui::Point position)
void GameModel::SetZoomWindowPosition(Vec2<int> 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<int> 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<int> position) const
{
if (!GetZoomEnabled())
return false;
auto const window = RectSized(
GetZoomWindowPosition(),
Vec2(1, 1) * Renderer::ZoomSettings::WindowSize(GetZoomScopeSize(), GetZoomFactor())
);
return window.Contains(position);
}
Vec2<int> GameModel::AdjustZoomCoords(Vec2<int> 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)

View File

@ -1,10 +1,11 @@
#pragma once
#include "gui/interface/Colour.h"
#include "client/User.h"
#include "gui/interface/Point.h"
#include <vector>
#include <deque>
#include <memory>
#include <vector>
#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<int>::Zero,
32,
8,
Vec2<int>::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<int>);
Vec2<int> GetZoomScopePosition() const;
void SetZoomWindowPosition(Vec2<int>);
Vec2<int> GetZoomWindowPosition() const;
bool MouseInZoom(Vec2<int>) const;
Vec2<int> AdjustZoomCoords(Vec2<int>) const;
void SetClipboard(GameSave * save);
void SetPlaceSave(GameSave * save);
void Log(String message, bool printToFile);

View File

@ -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<int> 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<int> 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;
}