Off the bat, I am very much a beginner C++ and SDL, so I apologize if I’m missing something obvious here. I have been spending some time trying to get to grips with basic SDL useage, and have been unable to overcome a problem I’ve encountered.
I was investigating texture rendering in the context of low resolution pixel-art, and attempted to implement a fullscreen scaling system beyond simply stretching a low-res image with nearest neighbour scaling. The purpose behind this was to avoid uneven nearest neighbour stretching that occurs when scaling images with non-integer multiples (as what often happens when scaling small images to a fullscreen resolution).
The design was simple:
- Scale the original image with nearest neighbour interpolation to a size close to the final desired output size, sticking with integer multiples to avoid unevenness.
- Scale again to fit the screen resolution using linear interpolation. This results in a slight softness, but is more desirable to my eye than using non-integer nearest neighbour scaling by itself.
My implementation below is the problem. It only somewhat works. It gives my intended result initially, however fails upon toggling the window from fullscreen and back (spacebar in my example). While rendering still occurs after this, it is highly blurred, appearing as though the “nearest” scaling qualities are being ignored.
#include "SDL.h"
int main(int argc, char *argv[]){
SDL_Init(SDL_INIT_EVERYTHING);
//Relevant texture initialization
SDL_Window *window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 240, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED);
SDL_Surface *temp = SDL_LoadBMP("testimage.bmp");
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, temp);
SDL_FreeSurface(temp);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
SDL_Texture *renderTexture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_TARGET, 400, 240);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
SDL_Texture *scaleTexture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_TARGET, 2000, 1200);
//Largely irrelevant (I believe), event handling. Only point of note is that setting the window to fullscreen
//happens here
bool gameloop = true;
bool fullscreen =true;
SDL_Event e;
while (gameloop){
while (SDL_PollEvent(&e)){
if (e.type == SDL_QUIT)
gameloop = false;
else if (e.type == SDL_KEYUP && e.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
gameloop = false;
else if (e.type == SDL_KEYUP && e.key.keysym.scancode == SDL_SCANCODE_SPACE){
if (fullscreen)
SDL_SetWindowFullscreen(window, 0);
else
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
fullscreen = !fullscreen;
}
}
//Relevant rendering code
SDL_RenderClear(renderer);
SDL_SetRenderTarget(renderer, renderTexture);
//Although this call to RenderCopy could introduce scaling problems, I believe it to be a non-issue
//in my case as texture and renderTexture have equal sizes.
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
SDL_SetRenderTarget(renderer, scaleTexture);
SDL_RenderCopy(renderer, renderTexture, nullptr, nullptr);
SDL_SetRenderTarget(renderer, nullptr);
SDL_RenderCopy(renderer, scaleTexture, nullptr, nullptr);
SDL_RenderPresent(renderer);
SDL_Delay(1000 / 60);
}
SDL_DestroyTexture(scaleTexture);
SDL_DestroyTexture(renderTexture);
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I admit to some confusion regarding the use of SDL_SetHint, but I believe I’m correct in that it only needs to be set before texture creation, and not before the various SDL_Render… functions.
In trying to solve my problem, I found that the scaling works correctly, if renderTexture is taken out entirely, and texture is rendered directly to scaleTexture. Maybe there is something I’m missing regarding rendering from a target texture to another target texture?
In any case, while this works for this little test, I feel it is not an appropriate solution. In a larger project it would necessitate any pixel-art rendering to be scaled individually, rather than scaling renderTexture the once.
As mentioned, I’ve been unable to find a solution to my problem. Hopefully I was able to explain myself well enough. Any insights would be greatly appreciated.