Getting an image on screen with SDL2 - c++

I've been trying to have a bitmap image displayed on screen but I can't figure out why it's not displaying it for the life of me. Here's the code:
#include <iostream>
#include <SDL.h>
bool init(SDL_Window *window, SDL_Surface *surface) {
bool success {true};
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
std::cout << "Could not initialize video: " << SDL_GetError() << "\n";
success = false;
}
window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
if (window == NULL) {
std::cout << "Could not create window: " << SDL_GetError() << "\n";
success = false;
}
surface = SDL_GetWindowSurface(window);
return success;
}
bool loadMedia(SDL_Surface *image) {
bool success {true};
image = SDL_LoadBMP("C:\\Users\\Admin\\Documents\\Files\\Programming\\C++\\game\\Untitled.bmp");
if (image == NULL) {
std::cout << "Could not load image: " << SDL_GetError() << "\n";
success = false;
}
return success;
}
void close(SDL_Window *window, SDL_Surface *surface, SDL_Surface *image) {
SDL_FreeSurface(surface);
surface = nullptr;
SDL_FreeSurface(image);
image = nullptr;
SDL_DestroyWindow(window);
window = nullptr;
SDL_Quit();
}
int main(int argc, char *argv[]) {
bool quit {false};
SDL_Event event;
SDL_Window *window {nullptr};
SDL_Surface *surface {nullptr};
SDL_Surface *image {nullptr};
if (!init(window, surface)) {
std::cout << "Initialization failed\n";
return 1;
}
if (!loadMedia(image)) {
std::cout << "Loading media failed\n";
return 1;
}
SDL_BlitSurface(image, NULL, surface, NULL);
SDL_UpdateWindowSurface(window);
while (!quit) {
SDL_WaitEvent(&event);
switch (event.type) {
case SDL_QUIT:
quit = true;
break;
default: break;
}
}
close(window, surface, image);
return 0;
}
The file structure is like so:
-game/
-image.bmp
-main.cpp
-main.exe
-Makefile
Makefile is like so:
all : main.cpp
g++ main.cpp -IC:\SDL2\include\SDL2 -LC:\SDL2\lib -w -lmingw32 -lSDL2main -lSDL2 -o main
SDL version 2.0.14 64-bit
mingw 64-bit
Windows 10 64-bit
I don't even know how much more information is necessary.
I have tried using events, not using events, using an absolute path, making the variables global, different file formats, trying to display it using a renderer and a texture, putting everything in main, making the image the same size as the screen, using ImageMagick convert as per the suggestion of an answer on some other thread on here, disabling the console window with the -Wl,-subsystem,windows compiler flag, but nothing I did has worked. Any help here?

You are passing parameters to init() - but the function receives a copy of those things. Then you change the copies passed into the function so they point somewhere else - but that doesn't change where the original pointers point. Then when you return to main() you use the original pointers which are still pointing to null.
It's the same as writing this:
void f(int x) {
x=2; // change the copy of x passed to this function
}
int main() {
int x=1;
f(x);
printf("%d\n",x); // prints the original value: 1
}
When what you should do is pass pointers to the things you want to change and then inside the function change the contents of the parameters:
void f(int *x) {
*x=2; // change the contents of the pointer: the original x
}
int main() {
int x=1;
f(&x); // pass a pointer to x
printf("%d\n",x); // prints the changed value: 2
}
So, in your case, what you need to do is pass pointers to the things you want to change (a pointer to window and a pointer to surface) and then inside init() change the contents of the parameters:
bool init(SDL_Window **window, SDL_Surface **surface) {
// ...
*window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
// ...
*surface = SDL_GetWindowSurface(window);
// ...
}
int main(int argc, char *argv[]) {
// ...
SDL_Window *window {nullptr};
SDL_Surface *surface {nullptr};
// ...
if (!init(&window, &surface)) {
std::cout << "Initialization failed\n";
return 1;
}
// ...
}

Related

Mix_OpenAudio Closes Program Without Creating Window

I want to create a simple program that lets me move around a little sprite with some music.
I'm able to bring up a window, my next step is getting some music. I have everything setup properly as when I build my main.exe with make it builds perfectly. I've narrowed the issue down to the first instance when the mixer is used in the line Mix_OpenAudio(48000, AUDIO_S16SYS, 2, 1024.
I'm not sure why it's not working, but when this line is included, the program simply doesn't open the window and ends the program. On the contrary, when the line isn't included, then the window opens just fine. I've provided a screencap to further illustrate:
Here is my main.cpp code:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDl2/SDL_mixer.h>
//Define window size
const int WIDTH = 800;
const int HEIGHT = 600;
bool init();
void closeWindow();
SDL_Window *window = NULL;
bool init() {
window = SDL_CreateWindow("test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI);
if (NULL == window) {
std::cout << "Could not create window: " << SDL_GetError() << std::endl;
return 1;
}
else {
return 0;
}
}
void closeWindow() {
SDL_DestroyWindow(window);
SDL_Quit();
return;
}
int main(int argc, char *argv[]) {
/* Initialize the SDL library */
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
exit(2);
}
/* Opens the audio device */
if (Mix_OpenAudio(48000, AUDIO_S16SYS, 2, 1024) < 0 ) {
fprintf(stderr, "Warning: Couldn't set 48000Hz 16-bit audio\n- Reason: %s\n", SDL_GetError());
}
init();
SDL_Event windowEvent;
while(true) {
if(SDL_PollEvent(&windowEvent)) {
if (SDL_QUIT == windowEvent.type) {
break;
}
}
}
closeWindow();
Mix_CloseAudio();
return EXIT_SUCCESS;
}
How do I fix this issue?

SDL_LoadBMP() displaying a black surface while surface is referenced

Trying to load an image onto an SDL_Surface. However the surface is always black although the bmp is clearly not.
NOTE
This is a working SDL_Window and creating a surface pointer is successful, what is unsuccessful is loading "Kassadin.bmp" which is located in the Code::Blocks project folder. It displays a black surface.
ALL answers on this particular question have NOT solved this problem, before marking this as a duplicate.
#include <iostream>
#include <SDL.h>
#include <stdio.h>
using namespace std;
const int SCREEN_WIDTH = 700;
const int SCREEN_HEIGHT = SCREEN_WIDTH / 12 * 9;
//Create an SDL_Window pointer
SDL_Window* window = NULL;
//Create an SDL_Surface pointer
SDL_Surface* surface = NULL;
//SDL_Surface for an image
SDL_Surface* imgSurface = NULL;
bool init(){
//try init SDL
if(SDL_Init(SDL_INIT_VIDEO) < 0){
cout << "Failed init SDL" << endl;
return false;
}else{
//create window title x pos y pos width height flags
//This doesnt include a surface ie it will be a plain window
window = SDL_CreateWindow("An SDL Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
}
if(window == NULL){
cout << "Failed creating SDL window" << endl;
return false;
}else{
// creates surface with an SDL_Window object
surface = SDL_GetWindowSurface(window);
}
return true;
}
bool loadMedia(){
imgSurface = SDL_LoadBMP("Kassadin.bmp");
return true;
}
void close(){
//Sets the SDL_Window pointer to NULL again
SDL_DestroyWindow(window);
window = NULL;
SDL_FreeSurface (imgSurface);
imgSurface = NULL;
//quits
SDL_Quit();
}
int main(int argc, char* argv[]){
if(!init()){
cout << "error init sdl" << endl;
}else{
if(!loadMedia){
cout << "Trouble loading media..." << endl;
}else{
SDL_BlitSurface(imgSurface, NULL, surface, NULL);
}
}
//This is so it's not just a static window ie it can update
SDL_UpdateWindowSurface(window);
SDL_Delay(5000);
close();
return 0;
}
Problemmatic line is
if(!loadMedia){
It is not a function call. What it does is checks address of function loadMedia is NULL, which is always false because function address assigned by linker (as opposed to funciton pointers which you manually assign at runtime).
As you mentioned codeblocks, I suppose you use gcc to compile your code. If only you've added at least -Wall flag (which is a very good practice) compiler would have warned you that you're doing something that very much looks like a mistake:
test2.cpp:70:9: warning: the address of ‘bool loadMedia()’ will always evaluate as ‘true’ [-Waddress]

SDL UpdateWindowSurface() returns -1 if called from a class (in separate file)

Today I started a C++/SDL2 Snake clone, and I've been looking for ways to make my code neater, -particularly with classes. I tried to put all the SDL code used for the window/display in a class. When I run the code, the window closes instantly. From the error tests I set up in display.cpp, it also tells me through the console that SDL_UpdateWindowSurface() (in display.update()) is always returning -1. Why does this happen when I rearrange my code like this?
With this code I load an image in main() and display it through my class' function applySurface(). The idea is to have classes/objects for the game's grid/board, the snake, etc., -each calling applySurface() for their own images. Feel free to tell me if this is a bad idea altogether.
main.cpp:
#include <SDL.h>
#include "display.h"
SDL_Event event;
SDL_Surface* image = nullptr;
int main(int argc, char* args[])
{
Display display;
display.loadImage("image.bmp");
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
return false;
bool quit = false;
while (!quit)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = true;
}
display.applySurface(0, 0, image, display.windowSurface);
display.update();
}
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}
display.h:
#pragma once
#include <SDL.h>
#include <string>
#include <iostream>
class Display
{
public:
SDL_Window* window;
SDL_Surface* windowSurface;
Display();
SDL_Surface *loadImage(std::string fileName);
void applySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = nullptr);
void update();
~Display();
private:
const int WINDOW_WIDTH = 612;
const int WINDOW_HEIGHT = 632;
const int SCREEN_BPP = 2;
};
display.cpp:
#pragma once
#include "display.h"
Display::Display()
{
window = SDL_CreateWindow("Snake", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL)
std::cout << "Error: SDL_CreateWindow failed." << std::endl;
windowSurface = SDL_GetWindowSurface(window);
}
SDL_Surface* Display::loadImage(std::string fileName)
{
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = SDL_LoadBMP(fileName.c_str());
if (loadedImage != NULL)
{
optimizedImage = SDL_ConvertSurface(loadedImage, windowSurface->format, 0);
SDL_FreeSurface(loadedImage);
if (optimizedImage != NULL)
SDL_SetColorKey(optimizedImage, SDL_TRUE, SDL_MapRGB(optimizedImage->format, 255, 255, 255));
}
return optimizedImage;
}
void Display::applySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(source, clip, destination, &offset);
}
void Display::update()
{
if (SDL_UpdateWindowSurface(window) == -1)
std::cout << "Error: SDL_UpdateWindowSurface() failed." << std::endl;
}
Display::~Display()
{
SDL_FreeSurface(windowSurface);
windowSurface = NULL;
SDL_DestroyWindow(window);
window = NULL;
}
This is a valid use of classes to structure your code. SDL_Init needs to come before any other SDL functions, which means you're best off moving SDL_Init to the top of main or adding it to the display constructor. If you add it to the beginning of the display constructor this means that you can only have one display class object running at a time, which would likely be fine in this case.

SDL not responding after running for a few seconds on linux

I was following the SDL Game development book and I cant even get the first file to work right. Upon the application starting it renders the window and then after a few seconds Linux says the game is not responding and ask me to force quit. This repeats every few seconds if I click wait. One thing I have noticed is that SDL_PollEvent never returns true.I am not sure why things are not working. Here is my code.
Main.cpp
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include "Game.h"
// our Game object
Game* g_game = 0;
int main(int argc, char* argv[]) {
g_game = new Game();
g_game->init("Chapter 1", 100, 100, 640, 480, 0);
while(g_game->running()) {
g_game->handleEvents();
//g_game->update();
g_game->render();
}
g_game->clean();
return 0;
}
Game.h
#ifndef __Game__
#define __Game__
#if !WINDOWS
#include <SDL2/SDL.h>
#else
#include <SDL.h>
#endif
class Game {
public:
Game() {}
~Game() {}
// simply set the running variable to true
bool init(const char* title, int xpos, int ypos, int width, int
height, bool fullscreen);
void render();
void update();
void handleEvents();
void clean();
// a function to access the private running variable
bool running() {
return m_bRunning;
}
private:
SDL_Window* m_pWindow;
SDL_Renderer* m_pRenderer;
bool m_bRunning;
};
#endif /* defined(__Game__) */
Game.cpp
#include "Game.h"
#include <iostream>
bool Game::init(const char* title, int xpos, int ypos, int width,
int height, bool fullscreen) {
// attempt to initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) == 0) {
std::cout << "SDL init success\n";
// init the window
int flags = 0;
if(fullscreen) {
flags = SDL_WINDOW_FULLSCREEN;
}
m_pWindow = SDL_CreateWindow(title, xpos, ypos,
width, height, flags);
if(m_pWindow != 0) { // window init success
std::cout << "window creation success\n";
m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);
if(m_pRenderer != 0) { // renderer init success
std::cout << "renderer creation success\n";
SDL_SetRenderDrawColor(m_pRenderer,
255,0,255,255);
} else {
std::cout << "renderer init fail\n";
return false; // renderer init fail
}
} else {
std::cout << "window init fail\n";
return false; // window init fail
}
} else {
std::cout << "SDL init fail\n";
return false; // SDL init fail
}
std::cout << "init success\n";
m_bRunning = true; // everything inited successfully, start the main loop
return true;
}
void Game::render() {
SDL_RenderClear(m_pRenderer); // clear the renderer to the draw color
SDL_RenderPresent(m_pRenderer); // draw to the screen
}
void Game::clean() {
std::cout << "cleaning game\n";
SDL_DestroyWindow(m_pWindow);
SDL_DestroyRenderer(m_pRenderer);
SDL_Quit();
}
void Game::handleEvents() {
SDL_Event event;
while(SDL_PollEvent(&event)) {
std::cout << "Checking Events";
switch(event.type) {
case SDL_QUIT:
std::cout << "Quiting";
m_bRunning = false;
break;
default:
break;
}
}
}
Edit:
so I made a minamal version of the code and now i get a new error. The error says "Segmentation Fault (core dumped)". Based on running it to a specific line in debug the error seems to appear at the line that says "SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);" I am not sure what the error is though
Here is the minial code:
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, char** argv) {
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
if(win == NULL) {
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if(ren == NULL) {
SDL_DestroyWindow(win);
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
std::string imagePath = "cb.bmp";
SDL_Surface *bmp = SDL_LoadBMP(imagePath.c_str());
if(bmp == NULL) {
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
std::cout << "SDL_LoadBMP Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);
if(tex == NULL) {
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
std::cout << "SDL_CreateTextureFromSurface Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_FreeSurface(bmp);
SDL_Event e;
bool quit = false;
while(!quit) {
while(SDL_PollEvent(&e)) {
//If user closes the window
if(e.type == SDL_QUIT) {
quit = true;
}
//If user presses any key
if(e.type == SDL_KEYDOWN) {
quit = true;
}
//If user clicks the mouse
if(e.type == SDL_MOUSEBUTTONDOWN) {
quit = true;
}
}
SDL_RenderClear(ren);
SDL_RenderPresent(ren);
}
SDL_DestroyTexture(tex);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
I have compiled and run your minimal code successfully under Linux with SDL 2.0.4. I used a simple image as "cb.bmp".
Try the following :
compile like this : g++ -Wall -ggdb $(sdl2-config --cflags) -o program main.cpp -lSDL2
gdb ./program, then type 'run'
when it crashes, type 'bt' (for backtrace)
copy the output here
My guess is : either the "bmp" file format is not supported or the rendering driver is not supported. try to use :
SDL_CreateRenderer(win, -1, 0);

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;
}