Refactor Engine, Window, and Panel drawing

This commit is contained in:
mniip 2023-04-10 23:05:44 +02:00
parent 4b70eeab55
commit f443eeff2f
11 changed files with 121 additions and 184 deletions

View File

@ -96,26 +96,21 @@ void TickClient()
void BlueScreen(String detailMessage)
{
auto &engine = ui::Engine::Ref();
engine.g->fillrect(0, 0, engine.GetWidth(), engine.GetHeight(), 17, 114, 169, 210);
engine.g->BlendFilledRect(engine.g->Size().OriginRect(), 0x1172A9_rgb .WithAlpha(0xD2));
String errorTitle = "ERROR";
String errorDetails = "Details: " + detailMessage;
String errorHelp = String("An unrecoverable fault has occurred, please report the error by visiting the website below\n") + SCHEME + SERVER;
int currentY = 0, width, height;
int errorWidth = 0;
Graphics::textsize(errorHelp, errorWidth, height);
engine.g->drawtext((engine.GetWidth()/2)-(errorWidth/2), ((engine.GetHeight()/2)-100) + currentY, errorTitle.c_str(), 255, 255, 255, 255);
Graphics::textsize(errorTitle, width, height);
Graphics::textsize(errorTitle, errorWidth, height);
engine.g->BlendText(engine.g->Size() / 2 - Vec2(errorWidth / 2, 100 - currentY), errorTitle, 0xFFFFFF_rgb .WithAlpha(0xFF));
currentY += height + 4;
engine.g->drawtext((engine.GetWidth()/2)-(errorWidth/2), ((engine.GetHeight()/2)-100) + currentY, errorDetails.c_str(), 255, 255, 255, 255);
Graphics::textsize(errorTitle, width, height);
currentY += height + 4;
engine.g->drawtext((engine.GetWidth()/2)-(errorWidth/2), ((engine.GetHeight()/2)-100) + currentY, errorHelp.c_str(), 255, 255, 255, 255);
Graphics::textsize(errorTitle, width, height);
Graphics::textsize(errorDetails, width, height);
engine.g->BlendText(engine.g->Size() / 2 - Vec2(errorWidth / 2, 100 - currentY), errorDetails, 0xFFFFFF_rgb .WithAlpha(0xFF));
currentY += height + 4;
Graphics::textsize(errorHelp, width, height);
engine.g->BlendText(engine.g->Size() / 2 - Vec2(errorWidth / 2, 100 - currentY), errorHelp, 0xFFFFFF_rgb .WithAlpha(0xFF));
//Death loop
SDL_Event event;
@ -383,8 +378,7 @@ int main(int argc, char * argv[])
engine.SetForceIntegerScaling(forceIntegerScaling);
engine.MomentumScroll = momentumScroll;
engine.ShowAvatars = showAvatars;
engine.SetMaxSize(desktopWidth, desktopHeight);
engine.Begin(WINDOWW, WINDOWH);
engine.Begin();
engine.SetFastQuit(prefs.Get("FastQuit", true));
bool enableBluescreen = !DEBUG && !true_arg(arguments["disable-bluescreen"]);
@ -448,9 +442,9 @@ int main(int argc, char * argv[])
if (ptsaveArg.has_value())
{
engine.g->Clear();
engine.g->fillrect((engine.GetWidth()/2)-101, (engine.GetHeight()/2)-26, 202, 52, 0, 0, 0, 210);
engine.g->drawrect((engine.GetWidth()/2)-100, (engine.GetHeight()/2)-25, 200, 50, 255, 255, 255, 180);
engine.g->drawtext((engine.GetWidth()/2)-(Graphics::textwidth("Loading save...")/2), (engine.GetHeight()/2)-5, "Loading save...", style::Colour::InformationTitle.Red, style::Colour::InformationTitle.Green, style::Colour::InformationTitle.Blue, 255);
engine.g->DrawRect(RectSized(engine.g->Size() / 2 - Vec2(100, 25), Vec2(200, 50)), 0xB4B4B4_rgb);
String loadingText = "Loading save...";
engine.g->BlendText(engine.g->Size() / 2 - Vec2(Graphics::textwidth(loadingText) / 2, 5), loadingText, style::Colour::InformationTitle);
blit(engine.g->vid);
try

View File

@ -345,7 +345,17 @@ private:
};
public:
constexpr operator bool() const
constexpr bool operator==(Rect other) const
{
return TopLeft == other.TopLeft && BottomRight == other.BottomRight;
}
constexpr bool operator!=(Rect other) const
{
return TopLeft != other.TopLeft || BottomRight != other.BottomRight;
}
constexpr explicit operator bool() const
{
return BottomRight.X >= TopLeft.X || BottomRight.Y >= TopLeft.Y;
}

View File

@ -67,11 +67,21 @@ class Graphics: public RasterDrawMethods<Graphics>
friend struct RasterDrawMethods<Graphics>;
public:
Vec2<int> Size() const
{
return video.Size();
}
pixel const *Data() const
{
return video.data();
}
pixel *Data()
{
return video.data();
}
[[deprecated("Use Data()")]]
pixel *vid = video.data();

View File

@ -36,7 +36,7 @@ ConfirmPrompt::ConfirmPrompt(String title, String message, ResultCallback callba
if (messageLabel->Size.Y < messagePanel->Size.Y)
messagePanel->Size.Y = messageLabel->Size.Y+4;
Size.Y += messagePanel->Size.Y+12;
Position.Y = (ui::Engine::Ref().GetHeight()-Size.Y)/2;
Position.Y = (GetGraphics()->Size().Y - Size.Y)/2;
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X-75, 16), "Cancel");
cancelButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;

View File

@ -27,7 +27,7 @@ ErrorMessage::ErrorMessage(String title, String message, DismissCallback callbac
AddComponent(messageLabel);
Size.Y += messageLabel->Size.Y+12;
Position.Y = (ui::Engine::Ref().GetHeight()-Size.Y)/2;
Position.Y = (GetGraphics()->Size().Y - Size.Y)/2;
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "Dismiss");
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;

View File

@ -46,7 +46,7 @@ InformationMessage::InformationMessage(String title, String message, bool large)
if (messageLabel->Size.Y < messagePanel->Size.Y)
messagePanel->Size.Y = messageLabel->Size.Y+4;
Size.Y += messagePanel->Size.Y+12;
Position.Y = (ui::Engine::Ref().GetHeight()-Size.Y)/2;
Position.Y = (GetGraphics()->Size().Y - Size.Y) / 2;
}
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 16), title);

View File

@ -17,7 +17,6 @@ Engine::Engine():
FrameIndex(0),
altFullscreen(false),
resizable(false),
lastBuffer(NULL),
state_(NULL),
windowTargetPosition(0, 0),
break_(false),
@ -27,9 +26,7 @@ Engine::Engine():
mousex_(0),
mousey_(0),
mousexp_(0),
mouseyp_(0),
maxWidth(0),
maxHeight(0)
mouseyp_(0)
{
SetFps(FpsLimit); // populate dt with whatever that makes any sort of sense
}
@ -38,21 +35,17 @@ Engine::~Engine()
{
delete state_;
//Dispose of any Windows.
while(!windows.empty())
while (!windows.empty())
{
delete windows.top();
windows.pop();
}
free(lastBuffer);
}
void Engine::Begin(int width, int height)
void Engine::Begin()
{
//engine is now ready
running_ = true;
width_ = width;
height_ = height;
}
void Engine::Break()
@ -80,16 +73,15 @@ void Engine::ConfirmExit()
void Engine::ShowWindow(Window * window)
{
windowOpenState = 0;
if (state_)
ignoreEvents = true;
if(window->Position.X==-1)
{
window->Position.X = (width_-window->Size.X)/2;
window->Position.X = (g->Size().X - window->Size.X) / 2;
}
if(window->Position.Y==-1)
{
window->Position.Y = (height_-window->Size.Y)/2;
window->Position.Y = (g->Size().Y - window->Size.Y) / 2;
}
/*if(window->Position.Y > 0)
{
@ -98,13 +90,8 @@ void Engine::ShowWindow(Window * window)
}*/
if(state_)
{
if(lastBuffer)
{
prevBuffers.push(lastBuffer);
}
lastBuffer = (pixel*)malloc((width_ * height_) * PIXELSIZE);
memcpy(lastBuffer, g->vid, (width_ * height_) * PIXELSIZE);
frozenGraphics.emplace(FrozenGraphics{0, std::make_unique<pixel []>(g->Size().X * g->Size().Y)});
std::copy_n(g->Data(), g->Size().X * g->Size().Y, frozenGraphics.top().screen.get());
windows.push(state_);
mousePositions.push(ui::Point(mousex_, mousey_));
@ -120,16 +107,7 @@ int Engine::CloseWindow()
{
if(!windows.empty())
{
if (lastBuffer)
{
free(lastBuffer);
lastBuffer = NULL;
}
if(!prevBuffers.empty())
{
lastBuffer = prevBuffers.top();
prevBuffers.pop();
}
frozenGraphics.pop();
state_ = windows.top();
windows.pop();
@ -168,17 +146,6 @@ int Engine::CloseWindow()
}
}*/
void Engine::SetSize(int width, int height)
{
width_ = width;
height_ = height;
}
void Engine::SetMaxSize(int width, int height)
{
maxWidth = width;
maxHeight = height;
}
void Engine::Tick()
{
@ -207,13 +174,21 @@ void Engine::Tick()
void Engine::Draw()
{
if(lastBuffer && !(state_ && state_->Position.X == 0 && state_->Position.Y == 0 && state_->Size.X == width_ && state_->Size.Y == height_))
if (!frozenGraphics.empty() && !(state_ && RectSized(state_->Position, state_->Size) == g->Size().OriginRect()))
{
g->Clear();
memcpy(g->vid, lastBuffer, (width_ * height_) * PIXELSIZE);
if(windowOpenState < 20)
windowOpenState++;
g->fillrect(0, 0, width_, height_, 0, 0, 0, int(255-std::pow(.98, windowOpenState)*255));
auto &frozen = frozenGraphics.top();
std::copy_n(frozen.screen.get(), g->Size().X * g->Size().Y, g->Data());
if (frozen.fadeTicks <= maxFadeTicks)
{
// from 0x00 at 0 to about 0x54 at 20
uint8_t alpha = (1 - std::pow(0.98, frozen.fadeTicks)) * 0xFF;
g->BlendFilledRect(g->Size().OriginRect(), 0x000000_rgb .WithAlpha(alpha));
}
// If this is the last frame in the fade, save what the faded image looks like
if (frozen.fadeTicks == maxFadeTicks)
std::copy_n(g->Data(), g->Size().X * g->Size().Y, frozen.screen.get());
if (frozen.fadeTicks <= maxFadeTicks)
frozen.fadeTicks++;
}
else
{
@ -322,11 +297,6 @@ void Engine::onMouseWheel(int x, int y, int delta)
state_->DoMouseWheel(x, y, delta);
}
void Engine::onResize(int newWidth, int newHeight)
{
SetSize(newWidth, newHeight);
}
void Engine::onClose()
{
if (state_)

View File

@ -1,9 +1,10 @@
#pragma once
#include <memory>
#include <stack>
#include "common/String.h"
#include "common/ExplicitSingleton.h"
#include "graphics/Pixel.h"
#include "gui/interface/Point.h"
#include <stack>
class Graphics;
namespace ui
@ -33,11 +34,10 @@ namespace ui
void onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
void onTextInput(String text);
void onTextEditing(String text, int start);
void onResize(int newWidth, int newHeight);
void onClose();
void onFileDrop(ByteString filename);
void Begin(int width, int height);
void Begin();
inline bool Running() { return running_; }
inline bool Broken() { return break_; }
inline long unsigned int LastTick() { return lastTick; }
@ -70,14 +70,6 @@ namespace ui
inline int GetMouseButton() { return mouseb_; }
inline int GetMouseX() { return mousex_; }
inline int GetMouseY() { return mousey_; }
inline int GetWidth() { return width_; }
inline int GetHeight() { return height_; }
inline int GetMaxWidth() { return maxWidth; }
inline int GetMaxHeight() { return maxHeight; }
void SetMaxSize(int width, int height);
inline void SetSize(int width, int height);
void StartTextInput();
void StopTextInput();
@ -102,16 +94,23 @@ namespace ui
float dt;
float fps;
pixel * lastBuffer;
std::stack<pixel*> prevBuffers;
std::stack<Window*> windows;
std::stack<Point> mousePositions;
//Window* statequeued_;
Window* state_;
Point windowTargetPosition;
int windowOpenState;
bool ignoreEvents = false;
// saved appearances of windows that are in the backround and
// thus are not currently being redrawn
struct FrozenGraphics
{
int fadeTicks;
std::unique_ptr<pixel []> screen;
};
constexpr static int maxFadeTicks = 20;
std::stack<FrozenGraphics> frozenGraphics;
bool running_;
bool break_;
bool FastQuit;
@ -122,11 +121,6 @@ namespace ui
int mousey_;
int mousexp_;
int mouseyp_;
int width_;
int height_;
int maxWidth;
int maxHeight;
String textEditingBuf;

View File

@ -67,31 +67,21 @@ void Panel::Draw(const Point& screenPos)
// draw ourself first
XDraw(screenPos);
int x = screenPos.X;
int y = screenPos.Y;
int w = Size.X;
int h = Size.Y;
ui::Engine::Ref().g->SetClipRect(x, y, w, h); // old cliprect is now in x, y, w, h
auto clip = RectSized(screenPos, Size);
GetGraphics()->SwapClipRect(clip);
// attempt to draw all children
for (size_t i = 0; i < children.size(); ++i)
{
for (auto const child : children)
// the component must be visible
if (children[i]->Visible)
if (child->Visible)
{
auto rect = RectSized(child->Position + ViewportPosition, child->Size);
//check if the component is in the screen, draw if it is
if (children[i]->Position.X + ViewportPosition.X + children[i]->Size.X >= 0 &&
children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y >= 0 &&
children[i]->Position.X + ViewportPosition.X < ui::Engine::Ref().GetWidth() &&
children[i]->Position.Y + ViewportPosition.Y < ui::Engine::Ref().GetHeight() )
{
Point scrpos = screenPos + children[i]->Position + ViewportPosition;
children[i]->Draw(scrpos);
}
if (rect & Size.OriginRect())
child->Draw(screenPos + rect.TopLeft);
}
}
ui::Engine::Ref().g->SetClipRect(x, y, w, h); // apply old cliprect
GetGraphics()->SwapClipRect(clip); // apply old cliprect
}
void Panel::Tick(float dt)

View File

@ -179,85 +179,53 @@ void Window::DoFileDrop(ByteString filename)
void Window::DoDraw()
{
OnDraw();
for (int i = 0, sz = Components.size(); i < sz; ++i)
if (Components[i]->Visible && ((Components[i] != focusedComponent_ && Components[i] != hoverComponent) || Components[i]->GetParent()))
auto drawChild = [this](Component *child) {
if (child->Visible)
{
Point scrpos(Components[i]->Position.X + Position.X, Components[i]->Position.Y + Position.Y);
if (AllowExclusiveDrawing)
{
Components[i]->Draw(scrpos);
}
else
{
if (scrpos.X + Components[i]->Size.X >= 0 &&
scrpos.Y + Components[i]->Size.Y >= 0 &&
scrpos.X < ui::Engine::Ref().GetWidth() &&
scrpos.Y < ui::Engine::Ref().GetHeight())
{
Components[i]->Draw(scrpos);
}
}
auto rect = RectSized(Position + child->Position, child->Size);
if (AllowExclusiveDrawing || bool(rect & GetGraphics()->Size().OriginRect()))
child->Draw(rect.TopLeft);
}
};
for (auto child : Components)
if ((child != focusedComponent_ && child != hoverComponent) || child->GetParent())
{
drawChild(child);
if (debugMode)
{
if (focusedComponent_==Components[i])
{
ui::Engine::Ref().g->fillrect(Components[i]->Position.X+Position.X, Components[i]->Position.Y+Position.Y, Components[i]->Size.X, Components[i]->Size.Y, 0, 255, 0, 90);
}
else
{
ui::Engine::Ref().g->fillrect(Components[i]->Position.X+Position.X, Components[i]->Position.Y+Position.Y, Components[i]->Size.X, Components[i]->Size.Y, 255, 0, 0, 90);
}
}
GetGraphics()->BlendFilledRect(RectSized(Position + child->Position, child->Size),
(focusedComponent_ == child ? 0x00FF00_rgb : 0xFF0000_rgb).WithAlpha(0x5A));
}
// the component the mouse is hovering over and the focused component are always drawn last
if (hoverComponent && hoverComponent->Visible && hoverComponent->GetParent() == NULL)
if (hoverComponent && hoverComponent->GetParent() == NULL)
drawChild(hoverComponent);
if (focusedComponent_ && focusedComponent_ != hoverComponent && focusedComponent_->GetParent() == NULL)
drawChild(focusedComponent_);
if (debugMode && focusedComponent_)
{
Point scrpos(hoverComponent->Position.X + Position.X, hoverComponent->Position.Y + Position.Y);
if ((scrpos.X + hoverComponent->Size.X >= 0 &&
scrpos.Y + hoverComponent->Size.Y >= 0 &&
scrpos.X < ui::Engine::Ref().GetWidth() &&
scrpos.Y < ui::Engine::Ref().GetHeight()
) || AllowExclusiveDrawing)
{
hoverComponent->Draw(scrpos);
}
Graphics *g = ui::Engine::Ref().g;
auto invPos = Size - (focusedComponent_->Position + focusedComponent_->Size);
String posText = String::Build(
"Position: L ", focusedComponent_->Position.X,
", R ", invPos.X,
", T: ", focusedComponent_->Position.Y,
", B: ", invPos.Y
);
String sizeText = String::Build(
"Size: ", focusedComponent_->Size.X,
", ", focusedComponent_->Size.Y
);
auto pos = focusedComponent_->Position + Position + Vec2(focusedComponent_->Size.X + 5, 0);
pos.X = std::min(pos.X, g->Size().X - Graphics::textwidth(posText) - 5);
pos.X = std::min(pos.X, g->Size().X - Graphics::textwidth(sizeText) - 5);
g->BlendText(pos + Vec2(0, 1), posText, 0x000000_rgb .WithAlpha(0xC8));
g->BlendText(pos + Vec2(0, 0), posText, 0xFFFFFF_rgb .WithAlpha(0xFF));
g->BlendText(pos + Vec2(0, 13), sizeText, 0x000000_rgb .WithAlpha(0xC8));
g->BlendText(pos + Vec2(0, 12), sizeText, 0xFFFFFF_rgb .WithAlpha(0xFF));
}
if (focusedComponent_ && focusedComponent_ != hoverComponent && focusedComponent_->Visible && focusedComponent_->GetParent() == NULL)
{
Point scrpos(focusedComponent_->Position.X + Position.X, focusedComponent_->Position.Y + Position.Y);
if ((scrpos.X + focusedComponent_->Size.X >= 0 &&
scrpos.Y + focusedComponent_->Size.Y >= 0 &&
scrpos.X < ui::Engine::Ref().GetWidth() &&
scrpos.Y < ui::Engine::Ref().GetHeight()
) || AllowExclusiveDrawing)
{
focusedComponent_->Draw(scrpos);
}
}
if (debugMode)
{
if (focusedComponent_)
{
int xPos = focusedComponent_->Position.X+focusedComponent_->Size.X+5+Position.X;
Graphics * g = ui::Engine::Ref().g;
String tempString, tempString2;
tempString = String::Build("Position: L ", focusedComponent_->Position.X, ", R ", Size.X-(focusedComponent_->Position.X+focusedComponent_->Size.X), ", T: ", focusedComponent_->Position.Y, ", B: ", Size.Y-(focusedComponent_->Position.Y+focusedComponent_->Size.Y));
tempString2 = String::Build("Size: ", focusedComponent_->Size.X, ", ", focusedComponent_->Size.Y);
if (Graphics::textwidth(tempString)+xPos > WINDOWW)
xPos = WINDOWW-(Graphics::textwidth(tempString)+5);
if (Graphics::textwidth(tempString2)+xPos > WINDOWW)
xPos = WINDOWW-(Graphics::textwidth(tempString2)+5);
g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y+1, tempString, 0, 0, 0, 200);
g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y, tempString, 255, 255, 255, 255);
g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y+13, tempString2, 0, 0, 0, 200);
g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y+12, tempString2, 255, 255, 255, 255);
}
return;
}
}
void Window::DoTick(float dt)

View File

@ -17,6 +17,7 @@
#include "gui/interface/Label.h"
#include "gui/interface/Textbox.h"
#include "gui/interface/DirectionSelector.h"
#include "PowderToySDL.h"
#include <cstdio>
#include <cstring>
#include <cmath>
@ -264,7 +265,7 @@ OptionsView::OptionsView():
scale->AddOption(std::pair<String, int>(String::Build(ix_scale), ix_scale));
ix_scale += 1;
}
while (ui::Engine::Ref().GetMaxWidth() >= ui::Engine::Ref().GetWidth() * ix_scale && ui::Engine::Ref().GetMaxHeight() >= ui::Engine::Ref().GetHeight() * ix_scale);
while (desktopWidth >= GetGraphics()->Size().X * ix_scale && desktopHeight >= GetGraphics()->Size().Y * ix_scale);
if (!current_scale_valid)
scale->AddOption(std::pair<String, int>("current", current_scale));
}