Sunday, December 4, 2016

c++ - Rescale pixel art scenery before rendering in SDL2


I looked at this page that mentions the SDL2_gfx library for rescaling SDL_Surfaces without the image getting blurry: SDL zooming/upscaling without images becoming blurry?


I wanted to know if it was a good idea and if there was any way (instead of individually resizing each texture, all relationships of space, and fixing the proportions of the speed for each object) to take the tiny scene of little sprites and tiles and rescale it before the image blits on the screen.


If there's a more reasonable solution, someone tell me, but this seems to make the most sense to me.



Thanks for the help!



Answer



In SDL 2, you must set the scaling interpolation algorithm for the whole renderer, using


SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, Value);

where Value should be, in your case (pixel art) 0. 1 means linear interpolation, and 2 is anistropic (only supported if the app runs on D3D/Windows) (documentation)


As far as saying itself is concerned, you can do it when you copy a texture to the renderer by specifying a target rectangle larger/smaller than the source rectangle.


// let's say the texture is 16*16px
SDL_Rect dest = {.x = 0, .y = 0, .w = 32, .h = 32}; // Scale by 2 -> 32*32.
// If SDL_SetHint was called properly, it will scale without blurring.

SDL_RenderCopy(renderer, texture, nullptr, dest);

Other possibility, you could set the renderer's logical scale to a fixed value (SDL_RenderSetLogicalSize(renderer, width, height)) that's smaller than the window's size. SDL will scale the renderer to fit the window using the algorithm given in SDL_SetHint().


The way I go about it when making pixel art game is the one you were hinting at: work at 1x resolution (sprites are not upscaled), and scale everything at the end.


If you want to scale only certain bits (let's say, HUD layer), you could render everything to a texture, and then upscale that texture before rendering it to the screen. To do that, the target texture must be created with the right flag (SDL_TEXTUREACCESS_TARGET), and then the renderer must be set to draw on it:


SDL_Texture* target = SDL_CreateTexture(renderer, PIXEL_FORMAT, SDL_TEXTUREACCESS_TARGET, width, height);
SDL_SetRenderTarget(renderer, target);
SDL_RenderClear(renderer); // to make sure the texture is "clean"
//
// render everything you want here

SDL_SetRenderTarget(renderer, nullptr); // to switch the renderer back to the screen
// render your target texture here, after upscaling it if you want

Hope all that helps! :)


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...