I'm trying to make a program that renders several colored rectangles within a window, then disappears after a few seconds. Basically, the following should appear (and I'll shortly explain how I got it to in the first place despite the problems I'm having):
The result (I'm new here by the way, is it possible to directly show images in a post instead of having to just include a link to it?)
The code I'm trying to run is as follows, obviously withstanding the inclusion of < stdio.h > and < SDL2/SDL.h > as well as definitions for "WINDOW_WIDTH" and "WINDOW_HEIGHT" which both appear in the code below (and are set to 800 and 640, respectively).
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
if (window == NULL) {
// In the case that the window could not be made...
printf("Could not create window: %s\n", SDL_GetError());
return 1;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);
SDL_Rect rect = { 0, 0, 800, 640 };
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);
SDL_Rect rect2 = { 40, 40, 720, 560 };
SDL_RenderFillRect(renderer, &rect2);
SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);
SDL_Rect rect3 = { 80, 80, 640, 480 };
SDL_RenderFillRect(renderer, &rect3);
SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);
SDL_Rect rect4 = { 120, 120, 560, 400 };
SDL_RenderFillRect(renderer, &rect4);
SDL_RenderPresent(renderer);
SDL_Delay(2000);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
This code seems like it should work fine, and it in fact does for the person in the aforementioned video (who, like me, is running this using Xcode on MacOS, albeit a far older version of it). However, the same thing that happens in the video does not seem to happen for me when I run my written code. Instead, the window simply doesn't appear at all. The code itself does indeed run, and perfectly fine for that matter without any errors or warnings, but the window with the multicolored rectangles doesn't show up at all before the delay is over and the SDL window is destroyed.
I realize that this question has been asked before on this website, and each with very similar issues, and I need to make it clear that yes, I've tried using an event loop instead and it works perfectly fine. For instance, if I run the following code- which is identical to the first batch of code except with "SDL_DELAY" replaced by an event handler which detects when the keyboard or mouse is pressed (and also includes < stdbool.h > for the boolean variable used)- the window appears just fine:
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
if (window == NULL) {
// In the case that the window could not be made...
printf("Could not create window: %s\n", SDL_GetError());
return 1;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);
SDL_Rect rect = { 0, 0, 800, 640 };
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);
SDL_Rect rect2 = { 40, 40, 720, 560 };
SDL_RenderFillRect(renderer, &rect2);
SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);
SDL_Rect rect3 = { 80, 80, 640, 480 };
SDL_RenderFillRect(renderer, &rect3);
SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);
SDL_Rect rect4 = { 120, 120, 560, 400 };
SDL_RenderFillRect(renderer, &rect4);
SDL_RenderPresent(renderer);
SDL_Event e;
bool quit = false;
while (!quit){
while (SDL_PollEvent(&e)){
if (e.type == SDL_QUIT){
quit = true;
}
if (e.type == SDL_KEYDOWN){
quit = true;
}
if (e.type == SDL_MOUSEBUTTONDOWN){
quit = true;
}
}
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
However, this is different from what the first attempt was trying to achieve, which as I said is a window that is rendered and then gets destroyed after a brief period of time. How am I supposed to get this to happen if I can't use the first set of code shown above? Moreover, why does such a set-up using SDL_DELAY clearly work for the person in the video (which for the sake of convenience, can again be found here) but not when I try to input it?
You're right it was asked many times before. Short answer is "window managers behave differently, and worse, they may have compositing enabled". Basically you create window, start drawing, tell window manager you're done, and some time later get signal that your window you thought you're drawing into was created just now, so would you kindly redraw whatever you wanted to display. The same thing happens when your window is resized, restored from minimised state, overshadowed by other windows, etc - that was always a thing, simple 3-line examples just ignored it; window manager is not responsible for keeping your image, whenever something happens it just sends you signal to redraw (doesn't mean it isn't allowed to keep image for its own purposes, mostly for compositing, previews, etc.). Before compositing age it "worked most of the times".
Window manager also may rely on target application's event processing to show "application not responding" dialog.
So actually your second version is still incorrect as you draw only once and don't watch for redraw events. Games often don't bother with these events as their image is very dynamic anyway and redraw unconditionally. You not only need event loop but also redraw.
As for how you can break loop when some time is passed - you need to look at the time and when given interval have passed trigger your quit or break loop in other way. Aside from OS provided time functions there are SDL_GetTicks, SDL_AddTimer, etc..
Here is an example:
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdbool.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
int main(int argc, char **argv) {
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
if (window == NULL) { return 1; }
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) { return 1; }
const Uint32 time_started = SDL_GetTicks();
SDL_Event e;
bool quit = false;
while (!quit){
// check for timeout
if(SDL_GetTicks() - time_started > 2000) { quit = true; }
while (SDL_PollEvent(&e)){
if (e.type == SDL_QUIT){
quit = true;
}
if (e.type == SDL_KEYDOWN){
quit = true;
}
if (e.type == SDL_MOUSEBUTTONDOWN){
quit = true;
}
}
// break early - doesn't really matter
if(quit) { break; }
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);
SDL_Rect rect = { 0, 0, 800, 640 };
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);
SDL_Rect rect2 = { 40, 40, 720, 560 };
SDL_RenderFillRect(renderer, &rect2);
SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);
SDL_Rect rect3 = { 80, 80, 640, 480 };
SDL_RenderFillRect(renderer, &rect3);
SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);
SDL_Rect rect4 = { 120, 120, 560, 400 };
SDL_RenderFillRect(renderer, &rect4);
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I want a quick fix to this issue:
I wrote a simple program to play around with the SDL2 libraries. A cyan box moves along a blue background from left to right. Then the window closes.
The problem is that the window's color "fades out" while the program is running. The contrast decreases significantly and it's annoying. Sometimes it happens when the box is in the middle of the window. Sometimes it happens when the box reaches the right side of the window. Sometimes it doesn't happen at all. This fading of colors seems to be sporadic and random. It is a run time issue. Theoretically, I do not see any issue with the code. What is wrong?
#include "SDL.h"
#include <stdio.h>
#ifdef __cplusplus
extern "C"
#endif
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
window = SDL_CreateWindow("Boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Rect myBox = { 200, 150, 50, 50 };
int go = 0;
while (go <= 590) {
myBox.x = go;
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
SDL_RenderFillRect(renderer, &myBox);
SDL_RenderPresent(renderer);
if (go == 0)
SDL_Delay(2000);
SDL_Delay(100);
go += 10;
}
SDL_Delay(2000);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return EXIT_SUCCESS;
}
That's a classical SDL mistake.
You're not handling events that your window receives, and because of that your OS assumes that your program has hung up.
Inside of your while loop, add following:
SDL_Event e;
while (SDL_PollEvent(&e))
if (e.type == SDL_QUIT)
return 0;
My program is about drawing the Mandelbrot set. I discovered that when I click another window in the operating system (eg. Chrome, or text editor ...) my program clears the screen to black but continues drawing where it finished. It is during drawing. If the drawing is finished and I click another window then nothing clearing happens.
Is there a solution to fix this (eg. switching something on or off in SDL) without tracking all the pixels onto the screen and print the entire pixel matrix all the times?
Minimal code:
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
enum {WIDTH = 1700, HEIGHT = 950};
int main(){
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("Minimal", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_Event event;
bool exit_ = false;
while (! exit_){
for (int i = 1; i < WIDTH; i++){
for (int j = 1; j < HEIGHT; j++){
SDL_RenderDrawPoint(renderer, i, j);
}
SDL_RenderPresent(renderer);
}
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT) exit_ = true;
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
(Note: I haven't got any window event handling in the program.)
I think you need to put SDL_RenderClear(Renderer) at the top of the while loop.
If you do like that, window will be never cleared after rendering.
For example if you don't clear the window, a moving dot will leave his traces..
I work woth SDL too, and i always do this
I just started with SDL and made a small square moving around on a window.
I used DL_GetKeyboardState, and got it moving kind of smoothly. However, just when I start moving it one direction by holding down one key, it moves a bit, stops, then move like I want. This messes up the smoothness. My best guess is that it waits for a doubleclick from the mouse, but im not sure. Any suggestions?
The code:
#include <stdio.h>
#include <SDL.h>
int main(int argc, char * argv[])
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Yelda!", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1600, 1200, 0);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
const Uint8 *state;
int run = 1;
int xpos=300;
int ypos=300;
int projectileYPos;
int projectileXPos;
int loop;
int lanceLength = 10;
while(run)
{
while(SDL_PollEvent(&event))
{
state=SDL_GetKeyboardState(NULL);
if(state[SDL_SCANCODE_ESCAPE])
run=0;
if(state[SDL_SCANCODE_W])
ypos-=10;
if(state[SDL_SCANCODE_S])
ypos+=10;
if(state[SDL_SCANCODE_A])
xpos-=10;
if(state[SDL_SCANCODE_D])
xpos+=10;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255 ,255);
SDL_Rect rect = {xpos, ypos, 20, 20 };
SDL_RenderFillRect(renderer, &rect);
SDL_RenderPresent(renderer);
SDL_Delay(20);
}
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
The SDL wiki says that you should use SDL_PumpEvents() to update the keyboard state array.
And indeed, if we
remove the while(SDL_PollEvent(&event)) loop (not its contents) as it's unneeded,
move state=SDL_GetKeyboardState(NULL); before the while(run) loop (the address of the array "will be valid for the whole lifetime of the application", so it always returns the same pointer), and
only call SDL_PumpEvents() inside the loop,
then the movement is smooth.
I just started using SDL2 and I already have a problem.
I want to create a window and paint it in red.
But it remains white, and I don't understand why.
Here is the code :
int main (int argc, char** argv) {
SDL_Window* pWindow = NULL;
pWindow = SDL_CreateWindow("Jeu de la vie", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN);
SDL_Surface* pSurface = NULL;
pSurface = SDL_GetWindowSurface(pWindow);
SDL_FillRect(pSurface, NULL, SDL_MapRGB(pSurface->format, 255, 0, 0));
while(1);
SDL_FreeSurface(pSurface);
SDL_DestroyWindow(pWindow);
SDL_Quit();
return EXIT_SUCCESS;
}
There are several issues with your code, I'll try to address most of them.
Initialize SDL
SDL and SDL2 needs to be initialized before you can use it. The way to initialize SDL is the following function.
int SDL_Init(Uint32 flags)
Where flags can be a different value for different subsystems. Use SDL_INIT_EVERYTHING, to initialize everything.
int SDL_Init(SDL_INIT_EVERYTHING)
Read more about it here..
Initialize SDL_Window and SDL_Renderer
SDL_Renderer and SDL_Window needs to be set up before you can use them. You already create your window properly, so I won't cover that. Here's how to set up an SDL_Renderer
SDL_Renderer* SDL_CreateRenderer(SDL_Window* window,
int index,
Uint32 flags)
index defines what driver to use. Set it to -1 to use the first driver that supports the other arguments.
flags are used to make the rendering optimized, software rendiring, prevent vsync, etc.. Set it to SDL_RENDERER_ACCELERATED.
Read more about SDL_CreateRenderer here.
Mixing SDL and SDL2
SDL_Surface is primarily something used in SDL, not SDL2. SDL2_image, SDL2_ttf etc still used SDL_Surface, but they are converted into an SDL_Texture before they can be used.
SDL_FillRect(...); is also mostly a SDL thing. But as stated above, the SDL_Surface can be used, but you need to convert it to an SDL_Texture first :
SDL_Texture* SDL_CreateTextureFromSurface(SDL_Renderer* renderer,
SDL_Surface* surface)
Read more here.
And use
int SDL_RenderCopy(SDL_Renderer* renderer,
SDL_Texture* texture,
const SDL_Rect* srcrect,
const SDL_Rect* dstrect)
To render it, read more here.
Infinite loop ( while(1); )
You REALLY shouldn't do this, it'll just loop forever. Use SDL_Delay( 5000 ); to pause for 5000msec or 5 seconds.
A simpler way
You can use
int SDL_RenderDrawRect(SDL_Renderer* renderer,
const SDL_Rect* rect)
To draw a rect.
You should use
int SDL_SetRenderDrawColor(SDL_Renderer* renderer,
Uint8 r,
Uint8 g,
Uint8 b,
Uint8 a)
To set the color of what you are drawing, use
int SDL_RenderClear(SDL_Renderer* renderer)
After which you call your SDL_RenderDrawRect()
Up until this point, everything has been drawn "behind the scenes." To render it to the screen, use
void SDL_RenderPresent(SDL_Renderer* renderer)
Example
#include <SDL2/SDL.h>
int main (int argc, char** argv)
{
SDL_Window* window = NULL;
window = SDL_CreateWindow
(
"Jeu de la vie", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN
);
// Setup renderer
SDL_Renderer* renderer = NULL;
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
// Set render color to red ( background will be rendered in this color )
SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 );
// Clear winow
SDL_RenderClear( renderer );
// Creat a rect at pos ( 50, 50 ) that's 50 pixels wide and 50 pixels high.
SDL_Rect r;
r.x = 50;
r.y = 50;
r.w = 50;
r.h = 50;
// Set render color to blue ( rect will be rendered in this color )
SDL_SetRenderDrawColor( renderer, 0, 0, 255, 255 );
// Render rect
SDL_RenderFillRect( renderer, &r );
// Render the rect to the screen
SDL_RenderPresent(renderer);
// Wait for 5 sec
SDL_Delay( 5000 );
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
Result
You can read more about SDL2 on my blog.