SDL2 empty transparent window in Linux - c++

Here is some sample SDL2 code I tried to run on my Linux computer running Ubuntu 18.04 with KDE Plasma Desktop Environment (I have multiple desktop environments installed in case it is relevant):
#include<iostream>
#include<SDL2/SDL.h>
int main(int argc, char** argv)
{
if(SDL_Init(SDL_INIT_VIDEO) != 0){
std::cerr << "SDL_Init() Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window* win = SDL_CreateWindow(
"Hello world",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
640,480,
0
);
if(win == nullptr){
std::cerr << "SDL_CreateWindow() Error: " << SDL_GetError() << std::endl;
return 1;
}
//Create and init the renderer
SDL_Renderer* ren = SDL_CreateRenderer(win, -1, 0);
if(ren == nullptr){
std::cerr << "SDL_CreateRenderer() Error: " << SDL_GetError() << std::endl;
SDL_DestroyWindow(win);
return 1;
}
//Render something
SDL_RenderSetLogicalSize(ren,640,480);
//Set colour of renderer
SDL_SetRenderDrawColor(ren,255,0,0,255);
//Clear the screen to the set colour
SDL_RenderClear(ren);
//Show all the has been done behind the scenes
SDL_RenderPresent(ren);
//Delay so that we can see what is on the screen
SDL_Delay(5000);
//Clean Up
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
The red window that is supposed to appear appears only once when I run the program for the first time. All subsequent executions produce an empty transparent window with whatever is in the background. The background image drags along with the window.
I have tried SDL_WINDOW_SHOWN flag in SDL_CreateWindow() as well as SDL_RENDER_ACCELERATED flag for SDL_CreateRenderer().
The only way to produce the red screen again is to reboot the system.
I even compiled and ran this with an IDE (CodeLite) and I still got the same results.
This particular question on SO shows similar problems. But the OP isn't using Linux and the problem isn't exactly the same.
Other posts on this website mention event processing but I haven't gotten that far. If at all it is necessary, I would be grateful for some resources on it as the documentation doesn't explain much.
Update:This program runs fine on another computer running Lubuntu 18.10.

Replace the SDL_Delay() (which blocks all event processing like notifying X11/Wayland & your window manager that your process is still alive) with a loop that calls SDL_PumpEvents() somehow, either directly (like below) or indirectly via SDL_PollEvent()/SDL_WaitEvent():
const Uint32 startMs = SDL_GetTicks();
while( SDL_GetTicks() - startMs < 5000 )
{
SDL_PumpEvents();
//Render something
SDL_RenderSetLogicalSize(ren,640,480);
//Set colour of renderer
SDL_SetRenderDrawColor(ren,255,0,0,255);
//Clear the screen to the set colour
SDL_RenderClear(ren);
//Show all the has been done behind the scenes
SDL_RenderPresent(ren);
}
All together:
#include <iostream>
#include <SDL2/SDL.h>
int main( int argc, char** argv )
{
if( SDL_Init( SDL_INIT_VIDEO ) != 0 )
{
std::cerr << "SDL_Init() Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window* win = SDL_CreateWindow
(
"Hello world",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
640, 480,
0
);
if( win == nullptr )
{
std::cerr << "SDL_CreateWindow() Error: " << SDL_GetError() << std::endl;
return 1;
}
//Create and init the renderer
SDL_Renderer* ren = SDL_CreateRenderer( win, -1, 0 );
if( ren == nullptr )
{
std::cerr << "SDL_CreateRenderer() Error: " << SDL_GetError() << std::endl;
SDL_DestroyWindow( win );
return 1;
}
const Uint32 startMs = SDL_GetTicks();
while( SDL_GetTicks() - startMs < 5000 )
{
SDL_PumpEvents();
//Render something
SDL_RenderSetLogicalSize( ren, 640, 480 );
//Set colour of renderer
SDL_SetRenderDrawColor( ren, 255, 0, 0, 255 );
//Clear the screen to the set colour
SDL_RenderClear( ren );
//Show all the has been done behind the scenes
SDL_RenderPresent( ren );
}
//Clean Up
SDL_DestroyRenderer( ren );
SDL_DestroyWindow( win );
SDL_Quit();
return 0;
}

Related

SDL doesn't render BMP image on mac

I have the following code in main.cpp:
#include <SDL2/SDL.h>
#include <iostream>
int main(){
SDL_Init(SDL_INIT_VIDEO);
bool quit = false;
SDL_Event event;
SDL_Window * window = SDL_CreateWindow("Chess",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 720, 640, 0);
SDL_Delay(100);
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_Surface * board = SDL_LoadBMP("board.bmp");
if (board == NULL) {
std::cout << "The image 'board.bmp' could not be loaded due to the following SDL error: " << SDL_GetError() << std::endl;
return 1;
}
else {
std::cout << "The image 'board.bmp' was loaded successfully" << std::endl;
}
SDL_Texture * board_texture = SDL_CreateTextureFromSurface(renderer, board);
if (board_texture == nullptr){
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
std::cout << "SDL_CreateTextureFromSurface Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_RenderCopy(renderer, board_texture, NULL, NULL);
while (!quit)
{
SDL_WaitEvent(&event);
SDL_RenderPresent(renderer);
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
}
SDL_Delay(15);
}
SDL_DestroyTexture(board_texture);
SDL_FreeSurface(board);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Both error checks return nothing, and I can't figure out why.
Also, I build using:
g++ chess.cpp -o chess -I include -L lib -l SDL2-2.0.0
This seems to work for my Windows PC, but not on my Intel Macbook Pro. Are there any solutions/workarounds available?
As documentation says
The backbuffer should be considered invalidated after each present; do
not assume that previous contents will exist between frames. You are
strongly encouraged to call SDL_RenderClear() to initialize the
backbuffer before starting each new frame's drawing, even if you plan
to overwrite every pixel.
So it should be:
SDL_WaitEvent(&event);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, board_texture, NULL, NULL);
SDL_RenderPresent(renderer);

SDL_Renderer works as global variable, but not if declared in main, and passed to the functions that require it instead

I've been going back over some SDL tutorials I did a while back to practice pointers/references, but I got stuck on something.
If I declare the SDL_Renderer globally everything works, but if I try to declare it in main, and pass the renderer to the functions that need it, I eventually get an SDL_Error saying "invalid renderer".
What works:
...
// Global vars
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
SDL_Rect gSpriteClips[ 4 ];
LTexture gSpriteSheetTexture;
...
// called from main after SDL initialization
bool loadMedia()
{
bool success = true;
//Load sprite sheet texture
if( !gSpriteSheetTexture.loadFromFile( gRenderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
What doesn't work:
...
bool init( SDL_Window* window, SDL_Renderer* renderer, const int SCREEN_WIDTH, const int SCREEN_HEIGHT )
{
...
}
...
bool load_media( SDL_Renderer* renderer, LTexture& sprite_sheet_texture, SDL_Rect* sprite_clips )
{
bool success = true;
//Load sprite sheet texture
if( !sprite_sheet_texture.loadFromFile( renderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
int main(int argc, char* args[])
{
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect sprite_clips[ 4 ];
LTexture sprite_sheet_texture;
if( !init( window, renderer, SCREEN_WIDTH, SCREEN_HEIGHT ) )
{
std::cout << "Failed to initialize!\n";
}
else
{
if( !load_media( renderer, sprite_sheet_texture, sprite_clips ) )
{
std::cout << "Failed to load media!\n";
}
...
The texture class: (same file for both versions)
bool LTexture::loadFromFile( SDL_Renderer* gRenderer, const std::string &path )
{
// Get rid of preexisting texture
free();
// The final texture
SDL_Texture* newTexture = NULL;
// Load image at specified path
SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
if( loadedSurface == NULL )
{
std::cout << "Unable to load image! SDL_Image error: " << IMG_GetError() << std::endl;
}
else
{
// color key image
SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );
// Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface ); <-- POINT OF FAILURE
if( newTexture == NULL )
{
std::cout << "Unable to create texture! SDL error: " << SDL_GetError() << std::endl; <-- THE ERROR I GET
}
...
The way I see it, SDL_CreateTextureFromSurface expects a pointer to an SDL_Renderer, which is what I'm passing. I don't understand why it matters if it's globally declared or declared in main. It should still just be a chunk of memory I'm pointing to somewhere.
I understand I must be passing it wrong, but I can't figure out how to do it correctly, and everything I've tried has produced the same error (passing the pointer as a reference, as a pointer to the pointer, etc.).
Side-note: I know I could just declare it globally or create a Singleton and be done with it, but this is more a learning exercise for me - so the point is to understand the pointer/reference aspect of the problem.
In the second snippet, if init changes the variable renderer, it will only change its local copy of the variable. It will not change the original variable renderer in the function main. This is because you are passing the variable by value. If you instead pass it by pointer or by reference, you will also modify the original variable's value. That way, your program will behave the same way as your global variable version.
Note that in order to pass a pointer to another function by pointer, you will need a pointer to a pointer. In your case you will need an SDL_Renderer **.
From the answer and advice by Andreas Wenzel, I now have a working solution. I thought I was passing by pointer, when I was actually passing by value. By passing a pointer to a pointer instead it works as intended.
I've included snippets below to show the difference from the code in the original question.
int main(int argc, char* args[])
{
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect sprite_clips[ 4 ];
LTexture sprite_sheet_texture;
if( !init( &window, &renderer, SCREEN_WIDTH, SCREEN_HEIGHT ) )
{
std::cout << "Failed to initialize!\n";
}
else
{
if( !load_media( &renderer, sprite_sheet_texture, sprite_clips ) )
{
std::cout << "Failed to load media!\n";
}
...
bool init( SDL_Window** window, SDL_Renderer** renderer, const int SCREEN_WIDTH, const int SCREEN_HEIGHT )
{
bool success = true;
// initialize SDL
if( SDL_Init( SDL_INIT_VIDEO) < 0 )
{
std::cout << "SDL could not initialize! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
{
std::cout << "Warning: Linear texture filtering not enabled!\n";
}
// Create window
*window = SDL_CreateWindow(
"SDL Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN
);
if( window == NULL )
{
std::cout << "Window could not be created! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
// Create renderer for window
*renderer = SDL_CreateRenderer( *window, -1, SDL_RENDERER_ACCELERATED );
if( renderer == NULL )
{
std::cout << "Renderer could not be created! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
...
bool load_media( SDL_Renderer** renderer, LTexture& sprite_sheet_texture, SDL_Rect* sprite_clips )
{
bool success = true;
//Load sprite sheet texture
if( !sprite_sheet_texture.loadFromFile( *renderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
void close( SDL_Window** window, SDL_Renderer** renderer )
{
//Destroy Window
SDL_DestroyRenderer( *renderer );
SDL_DestroyWindow( *window );
*window = NULL;
*renderer = NULL;
IMG_Quit();
SDL_Quit();
}

SDL: Blitting BMP to window surface black screen mystery

I've written the following code to load a BMP image as a surface and then blit that image onto the window:
#include "stdafx.h"
#include "SDL.h"
#include <iostream>
int main(int argc, char *argv[])
{
//init
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Playground", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 500, 500, 0);
std::cout << SDL_GetError() << std::endl;
SDL_Surface* surface = SDL_GetWindowSurface(window);
//load file and convert to texture
SDL_Surface* bmp = SDL_LoadBMP("sample.bmp");
std::cout << SDL_GetError() << std::endl;
//render texture
SDL_Rect area;
area.x, area.y = 3;
area.h, area.w = 25;
SDL_BlitSurface(bmp, &area, surface, &area);
std::cout << SDL_GetError() << std::endl;
SDL_UpdateWindowSurface(window);
std::cout << SDL_GetError() << std::endl;
SDL_Delay(3000);
//clean up
SDL_FreeSurface(bmp);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
When I press F5 (I'm working in Visual Studio Express 2017) to build and run the program, the program created runs, creates a window, and then the window remains entirely black as the program runs. I receive no error messages from V.S., SDL_GetError(), or Windows.
There appears to be no problems but the image just gets lost somewhere, it seems. Would anyone be able to help me?
P.S. Here is the bmp I am trying to display:
This code doesn't do what you think it does:
area.x, area.y = 3;
area.h, area.w = 25;
You should change it to
area.x = area.y = 3;
area.h = area.w = 25;
to have multiple assignments. Or even better just initialize SDL_Rect inline:
SDL_Rect area = { 3, 3, 25, 25 };

SDL_CreateWindow fails, SDL_GetError shows nothing. Why does it fail?

I have a project that uses SDL 1.2 and want to migrate it to SDL 2.0. To keep things simple I tried writing a simple program just to get familiar with the changes.
However, SDL_CreateWindow is failing, and SDL_GetError is not showing anything. So I don't know why creating the window isn't working.
The window is actually created, but then disappears.
#include <SDL.h>
#include <stdio.h> // printf etc
#include <stdlib.h> // abs, malloc, realloc
#include <stdint.h> // uint8_t, uint16_t, int32_t
#define WIDTH 853
#define HEIGHT 480
int main(int argc, char** argv) {
SDL_Renderer* renderer;
SDL_Window* window;
SDL_Texture* screenTexture;
SDL_Event event;
Uint8* screenBuffer;
FILE* fp;
int quit = 0;
fp = fopen("SDL2test.log", "w");
if (!fp) {
printf("\nCould not create log file");
return -1;
}
if (SDL_Init(SDL_INIT_VIDEO) < 0 ) {
fprintf(fp, "\nCould not initialise SDL: %s\n", SDL_GetError() );
return -2;
}
window = NULL;
if ( NULL == ( window = SDL_CreateWindow("SDL2 test",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, 0)));{
fprintf(fp, "Could not create SDL window: %s\n", SDL_GetError() );
SDL_Delay(3000);
SDL_Quit();
return -3;
}
if ( !( renderer = SDL_CreateRenderer(window, -1, 0) ) ); {
SDL_Quit();
return -4;
}
if ( !( screenTexture = SDL_CreateTexture(renderer,SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STATIC, WIDTH, HEIGHT)));
screenBuffer = (Uint8*)malloc( sizeof(Uint8) * 3 * WIDTH * HEIGHT );
if (NULL == screenBuffer){
SDL_Quit();
return -5;
}
memset(screenBuffer, 0, 3 * WIDTH * HEIGHT); //set to black
SDL_UpdateTexture( screenTexture,
NULL,
screenBuffer,
WIDTH * sizeof(Uint8) );
while( !quit && ( SDL_WaitEvent(&event) ) ) {
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, screenTexture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_Delay(3000);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
This is your create window if statement:
if ( NULL == ( window = SDL_CreateWindow( ...code... ) ) ); //what is ; doing here
{
fprintf(fp, "Could not create SDL window: %s\n", SDL_GetError() );
SDL_Delay(3000);
SDL_Quit();
return -3;
}
Did you notice the ; at the end of first line?
This means the part of the code in the brackets gets executed every time. Basically the code looks like this:
if ( NULL == ( window = SDL_CreateWindow( ...code... ) ) ); //end of if
{ //gets executed every time
fprintf(fp, "Could not create SDL window: %s\n", SDL_GetError() );
SDL_Delay(3000);
SDL_Quit();
return -3;
}
There is at least one such error in the code.

Why the game window closes after specific time?

Why the window that created by SDL Game Library are automatically closed after specific time.
I know the reason is SDL_Delay() function, but if not used that function, the game will appear runtime error.
How can I create a window that continuously work without appear in specific period time ?
My code(Simplest code):
SDL_Window *window;
SDL_Renderer *render;
int main(int argc, char* args[]){
if(SDL_Init(SDL_INIT_EVERYTHING) >= 0){
window = SDL_CreateWindow("Simple game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
if(window != 0){
render = SDL_CreateRenderer(window, -1, 0);
}
}else{
return 1;
}
SDL_SetRenderDrawColor(render, 0, 0, 0, 255);
SDL_RenderClear(render);
SDL_RenderPresent(render);
SDL_Delay(3000);
SDL_Quit();
return 0
}
You need to loop forever and call SDL update screen functions. Read LazyFoo tutorials found here: http://lazyfoo.net/SDL_tutorials
Or here a short code to get you started:
#include <iostream>
#include "SDL/SDL.h" // basic SDL
#include <string>
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BBP = 32; // bits per-pixel
SDL_Surface* screen = NULL; // display screen
SDL_Event event; // grab events
using namespace std;
bool init() {
// initialize SDL
if(SDL_Init( SDL_INIT_EVERYTHING ) == -1)
return false;
//the screen image
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT,
SCREEN_BBP, SDL_SWSURFACE );
if(!screen) {
cout << "error creating screen" << endl;
return false;
}
//Set the window caption
SDL_WM_SetCaption("Event Test", NULL );
return true;
}
int main(int argc, char* argv[])
{
try
{
// make sure the program waits for a quit
bool quit = false;
cout << "Starting SDL..." << endl;
// Start SDL
if(!init()) {
cout << "initialize error" << endl;
return false;
}
// main loop
while( quit == false )
{
if (SDL_PollEvent(&event))
{
// The x button click
if(event.type == SDL_QUIT)
{
//quit the program
quit = true;
}
}
// Fill the screen white
SDL_FillRect( screen, &screen->clip_rect, SDL_MapRGB(
screen->format, 0xFF, 0xFF, 0xFF ) );
//Update screen
if(SDL_Flip(screen) == -1)
return -1;
}
}
catch (exception& e)
{
cerr << "exception caught: " << e.what() << endl;
return -1;
}
return 0;
}