Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More rendering refactoring #1838

Merged
merged 2 commits into from
Feb 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
117 changes: 117 additions & 0 deletions src/OpenLoco/src/Drawing/SoftwareDrawingEngine.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "SoftwareDrawingEngine.h"
#include "Config.h"
#include "Ui.h"
#include "Ui/WindowManager.h"
#include <OpenLoco/Console/Console.h>
#include <OpenLoco/Interop/Interop.hpp>
#include <SDL2/SDL.h>
#include <algorithm>
Expand Down Expand Up @@ -32,6 +34,12 @@ namespace OpenLoco::Drawing
}
}

void SoftwareDrawingEngine::initialize(SDL_Window* window)
{
_window = window;
createPalette();
}

// T[m][n]
template<typename T>
class Grid
Expand Down Expand Up @@ -73,6 +81,62 @@ namespace OpenLoco::Drawing
}
};

void SoftwareDrawingEngine::resize(int32_t width, int32_t height)
{
// Scale the width and height by configured scale factor
auto scaleFactor = Config::get().scaleFactor;
width = (int32_t)(width / scaleFactor);
height = (int32_t)(height / scaleFactor);

int32_t widthShift = 6;
int16_t blockWidth = 1 << widthShift;
int32_t heightShift = 3;
int16_t blockHeight = 1 << heightShift;

if (_screenSurface != nullptr)
{
SDL_FreeSurface(_screenSurface);
}
if (_screenRGBASurface != nullptr)
{
SDL_FreeSurface(_screenRGBASurface);
}

_screenSurface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0);

_screenRGBASurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
SDL_SetSurfaceBlendMode(_screenRGBASurface, SDL_BLENDMODE_NONE);

SDL_SetSurfacePalette(_screenSurface, Gfx::getDrawingEngine().getPalette());

int32_t pitch = _screenSurface->pitch;

auto& rt = Gfx::getScreenRT();
if (rt.bits != nullptr)
{
delete[] rt.bits;
}
rt.bits = new uint8_t[_screenSurface->pitch * height];
rt.width = width;
rt.height = height;
rt.pitch = pitch - width;

_screenInfo->width = width;
_screenInfo->height = height;
_screenInfo->width_2 = width;
_screenInfo->height_2 = height;
_screenInfo->width_3 = width;
_screenInfo->height_3 = height;

_screenInvalidation->blockWidth = blockWidth;
_screenInvalidation->blockHeight = blockHeight;
_screenInvalidation->columnCount = (width / blockWidth) + 1;
_screenInvalidation->rowCount = (height / blockHeight) + 1;
_screenInvalidation->columnShift = widthShift;
_screenInvalidation->rowShift = heightShift;
_screenInvalidation->initialised = 1;
}

/**
* 0x004C5C69
*
Expand Down Expand Up @@ -220,6 +284,59 @@ namespace OpenLoco::Drawing
Ui::WindowManager::render(rt, rect);
}

void SoftwareDrawingEngine::present()
{
// Lock the surface before setting its pixels
if (SDL_MUSTLOCK(_screenSurface))
{
if (SDL_LockSurface(_screenSurface) < 0)
{
return;
}
}

// Copy pixels from the virtual screen buffer to the surface
auto& rt = Gfx::getScreenRT();
if (rt.bits != nullptr)
{
std::memcpy(_screenSurface->pixels, rt.bits, _screenSurface->pitch * _screenSurface->h);
}

// Unlock the surface
if (SDL_MUSTLOCK(_screenSurface))
{
SDL_UnlockSurface(_screenSurface);
}

auto scaleFactor = Config::get().scaleFactor;
if (scaleFactor == 1 || scaleFactor <= 0)
{
if (SDL_BlitSurface(_screenSurface, nullptr, SDL_GetWindowSurface(_window), nullptr))
{
Console::error("SDL_BlitSurface %s", SDL_GetError());
exit(1);
}
}
else
{
// first blit to rgba surface to change the pixel format
if (SDL_BlitSurface(_screenSurface, nullptr, _screenRGBASurface, nullptr))
{
Console::error("SDL_BlitSurface %s", SDL_GetError());
exit(1);
}
// then scale to window size. Without changing to RGBA first, SDL complains
// about blit configurations being incompatible.
if (SDL_BlitScaled(_screenRGBASurface, nullptr, SDL_GetWindowSurface(_window), nullptr))
{
Console::error("SDL_BlitScaled %s", SDL_GetError());
exit(1);
}
}

SDL_UpdateWindowSurface(_window);
}

SoftwareDrawingContext& SoftwareDrawingEngine::getDrawingContext()
{
return _ctx;
Expand Down
14 changes: 13 additions & 1 deletion src/OpenLoco/src/Drawing/SoftwareDrawingEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <cstddef>

struct SDL_Palette;
struct SDL_Surface;
struct SDL_Window;

namespace OpenLoco::Drawing
{
Expand All @@ -25,12 +27,19 @@ namespace OpenLoco::Drawing
public:
~SoftwareDrawingEngine();

void initialize(SDL_Window* window);

void resize(int32_t width, int32_t height);

// Renders all invalidated regions.
void render();

// Renders a specific region.
void render(const Ui::Rect& rect);

// Presents the final image to the screen.
void present();

// Invalidates a region, this forces it to be rendered next frame.
void invalidateRegion(int32_t left, int32_t top, int32_t right, int32_t bottom);

Expand All @@ -43,7 +52,10 @@ namespace OpenLoco::Drawing
private:
void render(size_t x, size_t y, size_t dx, size_t dy);

SDL_Palette* _palette;
SDL_Window* _window{};
SDL_Palette* _palette{};
SDL_Surface* _screenSurface{};
SDL_Surface* _screenRGBASurface{};
SoftwareDrawingContext _ctx;
};
}
126 changes: 11 additions & 115 deletions src/OpenLoco/src/Ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,9 @@ namespace OpenLoco::Ui
std::vector<Resolution> _fsResolutions;

static SDL_Window* window;
static SDL_Surface* surface;
static SDL_Surface* RGBASurface;
static std::map<CursorId, SDL_Cursor*> _cursors;

static void setWindowIcon();
static void update(int32_t width, int32_t height);
static void resize(int32_t width, int32_t height);
static Config::Resolution getDisplayResolutionByMode(Config::ScreenMode mode);

Expand Down Expand Up @@ -176,9 +173,9 @@ namespace OpenLoco::Ui
setWindowIcon();

// Create a palette for the window
Gfx::getDrawingEngine().createPalette();

update(desc.width, desc.height);
auto& drawingEngine = Gfx::getDrawingEngine();
drawingEngine.initialize(window);
drawingEngine.resize(desc.width, desc.height);
}

static void setWindowIcon()
Expand Down Expand Up @@ -345,63 +342,6 @@ namespace OpenLoco::Ui
{
}

// TODO: Move this into rendering engine, this is just resize and not really an update.
void update(int32_t width, int32_t height)
{
// Scale the width and height by configured scale factor
auto scaleFactor = Config::get().scaleFactor;
width = (int32_t)(width / scaleFactor);
height = (int32_t)(height / scaleFactor);

int32_t widthShift = 6;
int16_t blockWidth = 1 << widthShift;
int32_t heightShift = 3;
int16_t blockHeight = 1 << heightShift;

if (surface != nullptr)
{
SDL_FreeSurface(surface);
}
if (RGBASurface != nullptr)
{
SDL_FreeSurface(RGBASurface);
}

surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0);

RGBASurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
SDL_SetSurfaceBlendMode(RGBASurface, SDL_BLENDMODE_NONE);

SDL_SetSurfacePalette(surface, Gfx::getDrawingEngine().getPalette());

int32_t pitch = surface->pitch;

auto& rt = Gfx::getScreenRT();
if (rt.bits != nullptr)
{
delete[] rt.bits;
}
rt.bits = new uint8_t[surface->pitch * height];
rt.width = width;
rt.height = height;
rt.pitch = pitch - width;

_screenInfo->width = width;
_screenInfo->height = height;
_screenInfo->width_2 = width;
_screenInfo->height_2 = height;
_screenInfo->width_3 = width;
_screenInfo->height_3 = height;

_screenInvalidation->blockWidth = blockWidth;
_screenInvalidation->blockHeight = blockHeight;
_screenInvalidation->columnCount = (width / blockWidth) + 1;
_screenInvalidation->rowCount = (height / blockHeight) + 1;
_screenInvalidation->columnShift = widthShift;
_screenInvalidation->rowShift = heightShift;
_screenInvalidation->initialised = 1;
}

static void positionChanged(int32_t x, int32_t y)
{
auto displayIndex = SDL_GetWindowDisplayIndex(window);
Expand All @@ -416,7 +356,9 @@ namespace OpenLoco::Ui

void resize(int32_t width, int32_t height)
{
update(width, height);
auto& drawingEngine = Gfx::getDrawingEngine();
drawingEngine.resize(width, height);

Gui::resize();
Gfx::invalidateScreen();

Expand All @@ -443,9 +385,11 @@ namespace OpenLoco::Ui

void render()
{
if (window == nullptr || surface == nullptr)
if (window == nullptr)
return;

auto& drawingEngine = Gfx::getDrawingEngine();

if (!Ui::dirtyBlocksInitialised())
{
return;
Expand All @@ -455,16 +399,7 @@ namespace OpenLoco::Ui

if (!Intro::isActive())
{
Gfx::render();
}

// Lock the surface before setting its pixels
if (SDL_MUSTLOCK(surface))
{
if (SDL_LockSurface(surface) < 0)
{
return;
}
drawingEngine.render();
}

// Draw FPS counter?
Expand All @@ -473,46 +408,7 @@ namespace OpenLoco::Ui
Drawing::drawFPS();
}

// Copy pixels from the virtual screen buffer to the surface
auto& rt = Gfx::getScreenRT();
if (rt.bits != nullptr)
{
std::memcpy(surface->pixels, rt.bits, surface->pitch * surface->h);
}

// Unlock the surface
if (SDL_MUSTLOCK(surface))
{
SDL_UnlockSurface(surface);
}

auto scaleFactor = Config::get().scaleFactor;
if (scaleFactor == 1 || scaleFactor <= 0)
{
if (SDL_BlitSurface(surface, nullptr, SDL_GetWindowSurface(window), nullptr))
{
Console::error("SDL_BlitSurface %s", SDL_GetError());
exit(1);
}
}
else
{
// first blit to rgba surface to change the pixel format
if (SDL_BlitSurface(surface, nullptr, RGBASurface, nullptr))
{
Console::error("SDL_BlitSurface %s", SDL_GetError());
exit(1);
}
// then scale to window size. Without changing to RGBA first, SDL complains
// about blit configurations being incompatible.
if (SDL_BlitScaled(RGBASurface, nullptr, SDL_GetWindowSurface(window), nullptr))
{
Console::error("SDL_BlitScaled %s", SDL_GetError());
exit(1);
}
}

SDL_UpdateWindowSurface(window);
drawingEngine.present();
}

// 0x00406FBA
Expand Down