Skip to content

Commit

Permalink
Render to a small texture, then scale up to the screen size
Browse files Browse the repository at this point in the history
To be honest, I thought this is what SDL_RenderSetLogicalSize() did, but
actually it scales up each object that you draw with SDL_RenderCopy().
This is necessary because on some GPUs, scaling up can cause a sprite to
bleed into an adjacent frame in the spritesheet texture.

This shouldn't happen with nearest neighbor scaling, but it nevertheless
does happen on some GPUs such as my laptop's embedded Intel GPU. On this
GPU I saw a one pixel wide strip on the top and left of every sprite
that showed the neighboring sprite frame. The strip was one pixel wide
in my screen's pixels, not the logical resolution's pixels. Rendering
everything to a 320x240 texture and then scaling up the whole texture at
once makes strange bugs like this impossible.
  • Loading branch information
xordspar0 committed Apr 26, 2023
1 parent b7bd4e8 commit 6a1768d
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/endgame/island.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void island_draw()
{

// draw the scene
Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);

Renderer::getInstance()->setClip(island.scene_x, island.scene_y, Renderer::getInstance()->sprites.sprites[SPR_ISLAND_SCENE].w, Renderer::getInstance()->sprites.sprites[SPR_ISLAND_SCENE].h);

Expand Down
4 changes: 2 additions & 2 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ bool Game::pause(int pausemode, int param)

void Game::tick(void)
{
Renderer::getInstance()->clearScreen();
Renderer::getInstance()->clearScreen(BLACK);
debug_clear();

if (game.paused)
Expand Down Expand Up @@ -353,7 +353,7 @@ void DrawScene(void)
{
int scr_x, scr_y;
extern int flipacceltime;
Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);

// draw background map tiles
if (!flipacceltime)
Expand Down
49 changes: 38 additions & 11 deletions src/graphics/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ bool Renderer::initVideo(int scale)
{
uint32_t window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;

//TODO: sync this with setResolution
if (widescreen) {
screenWidth = 432;
screenHeight = 243;
Expand Down Expand Up @@ -138,6 +139,9 @@ bool Renderer::initVideo(int scale)
return false;
}

if (!createRenderTarget(screenWidth, screenHeight))
return false;

std::string spotpath = ResourceManager::getInstance()->getPath("spot.png");

SDL_Surface *image;
Expand All @@ -148,6 +152,24 @@ bool Renderer::initVideo(int scale)
return true;
}

bool Renderer::createRenderTarget(int width, int height)
{
SDL_RendererInfo info;
SDL_GetRendererInfo(_renderer, &info);

_texture = SDL_CreateTexture(_renderer,
info.texture_formats[0],
SDL_TEXTUREACCESS_TARGET,
width, height);
if (SDL_SetRenderTarget(_renderer, _texture)) {
LOG_ERROR("Renderer::createRenderTarget: SDL_SetRenderTarget failed: {}", SDL_GetError());
return false;
}
SDL_RenderClear(_renderer);

return true;
}

bool Renderer::flushAll()
{
LOG_DEBUG("Renderer::flushAll()");
Expand Down Expand Up @@ -200,18 +222,24 @@ bool Renderer::setResolution(int scale, bool newWidescreen)
LOG_INFO("Renderer logical resolution: {}x{}", newWidth, newHeight);

SDL_SetWindowSize(_window, newWidth * scale, newHeight * scale);

SDL_SetRenderTarget(_renderer, NULL);
SDL_DestroyTexture(_texture);
if (SDL_RenderSetLogicalSize(_renderer, newWidth, newHeight)) {
LOG_ERROR("Renderer::setResolution: SDL_RenderSetLogicalSize failed: {}", SDL_GetError());
return false;
}

if (!flushAll())
return false;

if (!createRenderTarget(newWidth, newHeight))
return false;

screenWidth = newWidth;
screenHeight = newHeight;
widescreen = newWidescreen;

if (!flushAll())
return false;

recalc_map_offsets();
textbox.RecalculateOffsets();

Expand All @@ -237,7 +265,7 @@ void Renderer::showLoadingScreen()
int x = (screenWidth / 2) - (loading.width() / 2);
int y = (screenHeight / 2) - loading.height();

fillScreen(BLACK);
clearScreen(BLACK);
drawSurface(&loading, x, y);
flip();
}
Expand All @@ -252,16 +280,15 @@ SDL_Window* Renderer::window()
return _window;
}

void Renderer::clearScreen()
{
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(_renderer);
}

void Renderer::flip()
{
// LOG_INFO("===FLIPPING===\n");
SDL_SetRenderTarget(_renderer, NULL);
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(_renderer);
SDL_RenderCopy(_renderer, _texture, NULL, NULL);
SDL_RenderPresent(_renderer);
SDL_SetRenderTarget(_renderer, _texture);
// LOG_INFO("===FLIPPED===\n");
}

Expand Down Expand Up @@ -390,7 +417,7 @@ void Renderer::drawPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b)
fillRect(x, y, x, y, r, g, b);
}

void Renderer::fillScreen(uint8_t r, uint8_t g, uint8_t b)
void Renderer::clearScreen(uint8_t r, uint8_t g, uint8_t b)
{
SDL_SetRenderDrawColor(_renderer, r, g, b, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(_renderer, NULL);
Expand Down
13 changes: 7 additions & 6 deletions src/graphics/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,14 @@ class Renderer

void showLoadingScreen();

void clearScreen();

void drawSurface(Surface *src, int x, int y);
void drawSurface(Surface *src, int dstx, int dsty, int srcx, int srcy, int wd, int ht);
void drawSurfaceMirrored(Surface *src, int dstx, int dsty, int srcx, int srcy, int wd, int ht);

void blitPatternAcross(Surface *sfc, int x_dst, int y_dst, int y_src, int height);

void fillScreen(NXColor color);
void fillScreen(uint8_t r, uint8_t g, uint8_t b);
void clearScreen(NXColor color);
void clearScreen(uint8_t r, uint8_t g, uint8_t b);

void drawLine(int x1, int y1, int x2, int y2, NXColor color);

Expand Down Expand Up @@ -96,12 +94,15 @@ class Renderer
private:
SDL_Window *_window = nullptr;
SDL_Renderer *_renderer = nullptr;
SDL_Texture *_texture = nullptr;
int _current_res = -1;
bool _need_clip = false;
SDL_Rect _clip_rect;
SDL_Texture* _spot_light;
bool _fullscreen = false;

bool createRenderTarget(int width, int height);

protected:
friend class Singleton<Renderer>;

Expand Down Expand Up @@ -151,9 +152,9 @@ void inline Renderer::drawPixel(int x, int y, NXColor color)
drawPixel(x, y, color.r, color.g, color.b);
}

void inline Renderer::fillScreen(NXColor color)
void inline Renderer::clearScreen(NXColor color)
{
fillScreen(color.r, color.g, color.b);
clearScreen(color.r, color.g, color.b);
}

void inline Renderer::setClip(NXRect *rect)
Expand Down
2 changes: 1 addition & 1 deletion src/intro/intro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void intro_tick()
}
if (blanktimer > 0)
{
Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);

if (--blanktimer == 0)
game.setmode(GM_TITLE);
Expand Down
6 changes: 3 additions & 3 deletions src/intro/title.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ std::vector<menuitem> _menuitems;
static void draw_title()
{
// background is dk grey, not pure black
Renderer::getInstance()->fillScreen(0x20, 0x20, 0x20);
Renderer::getInstance()->clearScreen(0x20, 0x20, 0x20);
map_draw_backdrop();
// DrawFastLeftLayered();

Expand Down Expand Up @@ -343,7 +343,7 @@ void title_tick()
{
if (title.seldelay > 0)
{
Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);

title.seldelay--;
if (!title.seldelay)
Expand All @@ -357,7 +357,7 @@ void title_tick()
}
else
{
Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);

if (!textbox.SaveSelect.IsVisible())
{ // selection was made, and settings.last_save_slot is now set appropriately
Expand Down
14 changes: 7 additions & 7 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,9 +588,9 @@ void map_draw_backdrop(void)
case BK_HIDE3:
{
if (game.curmap == STAGE_KINGS) // intro cutscene
Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);
else
Renderer::getInstance()->fillScreen(DK_BLUE);
Renderer::getInstance()->clearScreen(DK_BLUE);
}
return;

Expand Down Expand Up @@ -644,15 +644,15 @@ void DrawFastLeftLayered(void)
y1 = x = 0;
// fix for extra height
if (map.backdrop == 9)
Renderer::getInstance()->fillScreen(111, 156, 214);
Renderer::getInstance()->clearScreen(111, 156, 214);
else if (map.backdrop == 10 && game.curmap != 64)
Renderer::getInstance()->fillScreen(107, 105, 82);
Renderer::getInstance()->clearScreen(107, 105, 82);
else if (map.backdrop == 12)
Renderer::getInstance()->fillScreen(179, 190, 210);
Renderer::getInstance()->clearScreen(179, 190, 210);
else if (map.backdrop == 13)
Renderer::getInstance()->fillScreen(170, 101, 0);
Renderer::getInstance()->clearScreen(170, 101, 0);
else if (map.backdrop == 14)
Renderer::getInstance()->fillScreen(202, 97, 97);
Renderer::getInstance()->clearScreen(202, 97, 97);

for (i = 0; i < nlayers; i++)
{
Expand Down
2 changes: 1 addition & 1 deletion src/pause/mods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ bool mods_init(int param)
void mods_tick()
{
if (moddlg != NULL) {
Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);
moddlg->Draw();
moddlg->RunInput();
}
Expand Down
2 changes: 1 addition & 1 deletion src/pause/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ void options_tick()
unsigned int i;
FocusHolder *fh;

Renderer::getInstance()->fillScreen(BLACK);
Renderer::getInstance()->clearScreen(BLACK);
Options::run_and_draw_objects();

fh = (FocusHolder *)optionstack.at(optionstack.size() - 1);
Expand Down
4 changes: 2 additions & 2 deletions src/screeneffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void SE_FlashScreen::Draw(void)
}

if (flashstate)
Renderer::getInstance()->fillScreen(0xff, 0xff, 0xff);
Renderer::getInstance()->clearScreen(0xff, 0xff, 0xff);
}

/*
Expand Down Expand Up @@ -170,7 +170,7 @@ void SE_Fade::Draw(void)
}
else if (state == FS_FADED_OUT)
{
Renderer::getInstance()->fillScreen(DK_BLUE);
Renderer::getInstance()->clearScreen(DK_BLUE);
return;
}

Expand Down

0 comments on commit 6a1768d

Please sign in to comment.