Dissapearing SDL Rects. How to update window with new additional shapes - c++

I'm trying to update the window with a new additional rect upon key pressing, but it keeps disappearing due to SDL_RenderClear. Is it recommended to remove SDL_RenderClear?
while (!quit) {
while (SDL_PollEvent( & e) != 0) {
if (e.type == SDL_QUIT)
quit = true;
}
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer); //if i remove this line, the new rectangle will remain there
SDL_Rect fillRect = {
0,
0,
SCREEN_WIDTH / 5 - 5,
SCREEN_HEIGHT / 5 - 5
};
SDL_SetRenderDrawColor(gRenderer, 255, 205, 51, 0xFF);
SDL_RenderFillRect(gRenderer, & fillRect);
switch (e.type) {
case SDL_KEYDOWN:
if (e.key.keysym.sym == SDLK_RIGHT) {
SDL_Rect fillRect = {
0,
200,
SCREEN_WIDTH / 5 - 5,
SCREEN_HEIGHT / 5 - 5
};
SDL_SetRenderDrawColor(gRenderer, 255, 205, 51, 0xFF);
SDL_RenderFillRect(gRenderer, & fillRect);
}
break;
}
SDL_RenderPresent(gRenderer);
}

SDL_RenderClear() is perfectly fine and in fact you should be using it. Your problem (aka the rect disappearing) is caused by the way you handle input. SDL_KEYDOWN is an event that only occurs on the frame that you press a key for, and while you're holding it down after a short delay. What you are doing is drawing the rect if the key has been pressed on that exact frame, not if it's been pressed on any previous frames. A solution via a bool could look like this:
bool keyPressed = false;
while( !quit ) {
while( SDL_PollEvent( &e ) != 0 ) {
if( e.type == SDL_QUIT )
quit = true;
}
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer ); //if i remove this line, the new rectangle will remain there
SDL_Rect fillRect = { 0, 0, SCREEN_WIDTH / 5-5, SCREEN_HEIGHT / 5-5 };
SDL_SetRenderDrawColor( gRenderer, 255, 205, 51, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
if(keyPressed){
SDL_Rect fillRect = { 0, 200, SCREEN_WIDTH / 5-5, SCREEN_HEIGHT / 5-5 };
SDL_SetRenderDrawColor( gRenderer, 255, 205, 51, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
}
switch(e.type){
case SDL_KEYDOWN:
if(e.key.keysym.sym==SDLK_RIGHT){
keyPressed = true;
}
break;
}
SDL_RenderPresent( gRenderer );
}
Screen clearing is something that should absolutely be done in graphics, because otherwise the shapes you've drawn on previous frames will just remain there.

Related

Issues with rendering 2 images in one window in SDL

I am making a simples possible jigsaw game using SDL.
Currently i am having trouble applying image texutes to Rects that serve as a puzzle pieces.
The way I applied texture to background doesnt work for pieces(rect1-9).
All pieces are 100x100 and picture is 300x300.
Tell me what is wrong, how to do it right and also explain how to Clip render(apply only part of the texture) with SDL_RenderCopy
#include <list>
#include <SDL.h>
int main(int argc, char ** argv)
{
// variables
bool quit = false;
SDL_Event event;
bool leftMouseButtonDown = false;
SDL_Point mousePos;
SDL_Point clickOffset;
// init SDL
SDL_Init(SDL_INIT_VIDEO);
SDL_Window * window = SDL_CreateWindow("SDL2 Drag and Drop",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 600, 400, 0);
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Surface* bgSurface = SDL_LoadBMP("background.bmp");
SDL_Texture* bgTexture = SDL_CreateTextureFromSurface (renderer,bgSurface);
SDL_Surface* picSurface = SDL_LoadBMP("picture.bmp");
SDL_Texture* picTexture = SDL_CreateTextureFromSurface (renderer,bgSurface);
SDL_Rect rect1 = { 52, 51, 100, 100 };
SDL_Rect rect2 = { 152, 51, 100, 100 };
SDL_Rect rect3 = { 250, 51, 100, 100 };
SDL_Rect rect4 = { 52, 151, 100, 100 };
SDL_Rect rect5 = { 152, 151, 100, 100 };
SDL_Rect rect6 = { 250, 151, 100, 100 };
SDL_Rect rect7 = { 52, 249, 100, 100 };
SDL_Rect rect8 = { 152, 249, 100, 100 };
SDL_Rect rect9 = { 250, 249, 100, 100 };
SDL_Rect background = { 0, 0, 600, 400 };
SDL_Rect * selectedRect = NULL;
std::list<SDL_Rect *> rectangles;
rectangles.push_back(&rect1);
rectangles.push_back(&rect2);
rectangles.push_back(&rect3);
rectangles.push_back(&rect4);
rectangles.push_back(&rect5);
rectangles.push_back(&rect6);
rectangles.push_back(&rect7);
rectangles.push_back(&rect8);
rectangles.push_back(&rect9);
// handle events
while (!quit)
{
SDL_Delay(10);
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_MOUSEBUTTONUP:
if (leftMouseButtonDown && event.button.button == SDL_BUTTON_LEFT)
{
leftMouseButtonDown = false;
selectedRect = NULL;
}
break;
case SDL_MOUSEBUTTONDOWN:
if (!leftMouseButtonDown && event.button.button == SDL_BUTTON_LEFT)
{
leftMouseButtonDown = true;
for (auto rect : rectangles)
{
if (SDL_PointInRect(&mousePos, rect))
{
selectedRect = rect;
clickOffset.x = mousePos.x - rect->x;
clickOffset.y = mousePos.y - rect->y;
break;
}
}
}
break;
case SDL_MOUSEMOTION:
{
mousePos = { event.motion.x, event.motion.y };
if (leftMouseButtonDown && selectedRect != NULL)
{
selectedRect->x = mousePos.x - clickOffset.x;
selectedRect->y = mousePos.y - clickOffset.y;
}
}
break;
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer,bgTexture,NULL,&background );
SDL_RenderCopy(renderer,bgTexture,NULL,&rect1 );
for (auto const& rect : rectangles)
{
if (rect == selectedRect)
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 100);
else
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 0);
SDL_RenderFillRect(renderer, rect);
}
SDL_RenderPresent(renderer);
}
// cleanup SDL
SDL_DestroyTexture (bgTexture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

How do I render a box to the screen in C++ using SDL2?

I am trying to figure out the SDL2 library in C++, and can't seem to properly configure code to simply draw a rectangle to the screen. What should I do differently?
#include <SDL.h>
bool success = true; //success flag for functions, etc
int ScreenWidth = 640; //screen width and height for SDL window
int ScreenHeight = 480; //
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
SDL_Window* window = SDL_CreateWindow( "Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, ScreenWidth, ScreenHeight, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF);
bool quit = false;
SDL_Event event;
while (!quit)
{
SDL_RenderClear(renderer);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = true;
}
SDL_Rect box;
box.w = 30;
box.h = 30;
box.x = 50;
box.y = 50;
SDL_SetRenderDrawColor(renderer, 0xFF,0x00,0x00,0xFF);
SDL_RenderFillRect(renderer, &box);
SDL_RenderPresent(renderer);
}
return 0; //because main is an int task
}
EDIT: This is the full file.
I expect it to draw a red rectangle on the screen, but the window is completely red (of the correct size, name, etc. that quits correctly).
You must call SDL_RenderPresent after all your rendering calls. In this case after SDL_RenderFillRect(...)
SDL_RenderClear is used at the beginning of a rendering loop to clear the buffer.
Example from SDL2's Wiki
SDL_SetRenderDrawColor() affects both SDL_RenderFillRect() and SDL_RenderClear().
After drawing the red square you need to re-set the color to white before the next SDL_RenderClear() call:
#include <SDL2/SDL.h>
int main( int argc, char** argv )
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" );
SDL_Window* window = SDL_CreateWindow( "Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN );
SDL_Renderer* renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
bool running = true;
while( running )
{
SDL_Event ev;
while( SDL_PollEvent( &ev ) )
{
if( SDL_QUIT == ev.type )
{
running = false;
break;
}
}
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( renderer );
SDL_Rect box;
box.w = 30;
box.h = 30;
box.x = 50;
box.y = 50;
SDL_SetRenderDrawColor( renderer, 0xFF, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &box );
SDL_RenderPresent( renderer );
}
return 0;
}
I figured it out!
I needed to put SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); inside of the loop so it would reset the renderer to white each tick. I just had it set it back to white once at the beginning so SDL_RenderClear was filling the window with the current draw color (which was red). Thanks to TinfoilPancakes and genpfault for helping me!

properly rendering an SDL rectangle to the screen

Here is my code, I am following lazyfoos tutorials on SDL, here is the exact tutorial I am following - http://lazyfoo.net/tutorials/SDL/08_geometry_rendering/index.php
Notice the call to SDL_SetRenderDrawColor. We're using 255 red and 255
green which combine together to make yellow. Remember that call to
SDL_SetRenderDrawColor at the top of the loop? If that wasn't there,
the screen would be cleared with whatever color was last set with
SDL_SetRenderDrawColor, resulting in a yellow background in this case.
Lazyfoo does explain it above but it still doesn't make sense to me.
To draw a filled rectangle to the screen is a pretty trivial task but it's a task that sometimes causes a lot of confusion,for example you need to call SDL_SetRenderDrawColor() not once but twice,once before you clear the renderer,and also once before you call SDL_RenderFillRect().
Why do you need to call SDL_SetRenderDrawColor() twice and why in that order? I noticed if I comment out the first SDL_SetRenderDrawColor() just before the call to SDL_RenderFillRect(),the full window will be the colour you set the rectangle to be,but when you include the two calls to SDL_SetRenderDrawColor() in the order I specified the window shows a coloured rectangle in the centre of the screen with the rest of the screen being white(first SDL_SetRenderDrawColor() call).
Here is my game loop where the calls are made.
while( !quit )
{
while( SDL_PollEvent( &event ) != 0 )
{
if( event.type == SDL_QUIT )
{
quit = true;
}
}
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 0 ); // line of code in question
SDL_RenderClear( renderer );
SDL_Rect fillRect = { 500 / 4, 500 / 4, 500 / 2, 500 / 2 };
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF ); // 2nd line of code in question
SDL_RenderFillRect( renderer, &fillRect );
SDL_RenderPresent( renderer );
}
Why do you need to call SDL_SetRenderDrawColor() twice and why in that
order?
The name of SDL_RenderClear is a bit misleading. It doesn't clear the screen to "empty" or anything - it just fills it with whatever color was set by SDL_SetRenderDrawColor. So if you don't change the color between "clearing" and drawing the rectangle, then you won't see the rectangle because you're drawing it with the same color that you just filled the entire screen with.
So here
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
You make the whole screen white. We do this by setting white, and then painting over the entire screen with white.
Then here
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0x00, 0x00, 0xFF );
We set red so the rectangle here
SDL_RenderFillRect( gRenderer, &fillRect );
Will be red (not white).
And if I remember the tutorial correctly, it also draws a line and some other things, every time calling SDL_SetRenderDrawColor right before to set the correct color.
I noticed if I comment out the first SDL_SetRenderDrawColor() just
before the call to SDL_RenderFillRect(),the full window will be the
colour you set the rectangle to be
Very good observation! You see, since you're looping (while(!quit){) you do SDL_RenderClear and then SDL_RenderFillRect... but then SDL_RenderClear comes again, and so on. So when SDL_RenderClear happens, the color was actually set from right before SDL_RenderFillRect in the last run through the loop. Hence why it has that color, too.
So actually, I don't know what the color is at the very first time because it's not set yet (might be a default value of white, or something), but we probably can't see it because that's just on the first run through the loop anyway. So what happens roughly is:
...
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &fillRect );
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &fillRect );
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor( renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &fillRect );
...
So you see, with only that second SDL_SetRenderDrawColor call, both SDL_RenderClear and SDL_RenderFillRect will always draw in green, except the very first SDL_RenderClear call in the first frame.

SDL_RenderDrawPoint not working

If i use this code:
SDL_SetRenderDrawColor( renderer.get(), 0x00, 0x00, 0xFF, 0xFF );
SDL_RenderDrawLine( renderer.get(), 0, 480 / 2, 640, 480 / 2 );
//Draw vertical line of yellow dots
SDL_SetRenderDrawColor( renderer.get(), 0xFF, 0xFF, 0x00, 0xFF );
for( int i = 0; i < 480; i += 4 )
{
SDL_RenderDrawPoint( renderer.get(), 640 / 2, i );
}
It will draw yellow points and blue line, but if i comment SDL_RenderDrawLine, it will draw nothing. What is wrong?
This will happen too, if i use this code and somewhere in code (after a while) i want to use SDL_RenderDrawPoint or SDL_RenderDrawPoints.
I am using lastest SDL library and Linux Mint.

SDL_DisplayFormat works, but not SDL_DisplayFormatAlpha

The following code is intended to display a green square on a black background. It executes, but the green square does not show up. However, if I change SDL_DisplayFormatAlpha to SDL_DisplayFormat the square is rendered correctly.
So what don't I understand? It seems to me that I am creating *surface with an alpha mask and I am using SDL_MapRGBA to map my green color, so it would be consistent to use SDL_DisplayFormatAlpha as well.
(I removed error-checking for clarity, but none of the SDL API calls fail in this example.)
#include <SDL.h>
int main(int argc, const char *argv[])
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_Surface *screen = SDL_SetVideoMode(
640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF
);
SDL_Surface *temp = SDL_CreateRGBSurface(
SDL_HWSURFACE, 100, 100, 32, 0, 0, 0,
( SDL_BYTEORDER == SDL_BIG_ENDIAN ? 0x000000ff : 0xff000000 )
);
SDL_Surface *surface = SDL_DisplayFormatAlpha( temp );
SDL_FreeSurface( temp );
SDL_FillRect(
surface, &surface->clip_rect, SDL_MapRGBA(
screen->format, 0x00, 0xff, 0x00, 0xff
)
);
SDL_Rect r;
r.x = 50;
r.y = 50;
SDL_BlitSurface( surface, NULL, screen, &r );
SDL_Flip( screen );
SDL_Delay( 1000 );
SDL_Quit();
return 0;
}
I was using the wrong format for SDL_MapRGBA. Should have been
SDL_FillRect(
surface, NULL, SDL_MapRGBA(
surface->format, 0xff, 0xff, 0x00, 0xff
)
);
(surface->format instead of screen->format.) I thought the two would be equivalent. And they are after calling SDL_DisplayFormat(), but not after calling SDL_DisplayFormatAlpha(). The screen surface doesn't have an alpha channel, so the format is different between the two.
(Cross-posted from gamedev.stackexchange.com)