Why doesn't my SDL2 code display images with SDL_Texture* - c++

I have a C++ project where I'm initially trying to display a PNG image to the screen.
This is my code.
RenderWindow.hpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
class RenderWindow
{
public:
RenderWindow(const char *p_title, int p_width, int p_height);
void render();
void cleanUp();
private:
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Surface *image = IMG_Load("~/SDL2_Game/images/Green_Tile.png");
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, image);
};
RenderWindow.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "RenderWindow.hpp"
RenderWindow::RenderWindow(const char* p_title, int p_w, int p_h):window(NULL), renderer(NULL)
{
window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);
if (window == NULL) std::cout << "Window failed to init: " << SDL_GetError() << std::endl;
renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
}
void RenderWindow::render(){
SDL_RenderClear(renderer);
//SDL_Rect dstrect = { 5, 5, 320, 240 };
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
void RenderWindow::cleanUp(){
SDL_DestroyTexture(texture);
SDL_FreeSurface(image);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
}
main.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "RenderWindow.hpp"
int main(int argc, char** argv){
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cout << "Problem with initialization. " << SDL_GetError() << std::endl;
}
else {
std::cout << "Initialization success!" <<std::endl;
}
if (!IMG_Init(IMG_INIT_PNG)){
std::cout << "Problem with Image initialization " <<SDL_GetError() << std::endl;
}
RenderWindow win("RPG_Game_v_1.0", 800, 600);
win.render();
bool gameRunning = true;
SDL_Event event;
while(gameRunning){
while(SDL_PollEvent(&event)){
if (event.type == SDL_QUIT) gameRunning = false;
}
}
win.cleanUp();
IMG_Quit();
SDL_Quit();
return 0;
}
I'm on a Linux machine.
I compile this with
g++ -g -o game ./*.cpp -lSDL2main -lSDL2 -lSDL2_image
Only a window is displaying. There is no image. I've tried refactoring my code with SDL_BlitSurface() and it does indeed display the PNG image. But why is this code not working? is it due to the fact that I'm using SDL_Texture* and my current system does not have a discrete graphics card?

I think that the call to SDL_CreateTextureFromSurface fails because it is called before SDL_CreateWindow and SDL_CreateRenderer, thereby initializing texture to NULL.
Please move the initizalization of texture (and image) to after window and renderer are initialized.
To further help with such issues, please check if the result of SDL functions != NULL and print SDL_GetError() to get more information about what went wrong.

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

SDL2 can't render PNG file as texture

I am trying to make a simple racing game with C++ using SDL2. When i tried rendering my car asset(PNG Image) it simply did not render saying in the console that it couldn't access the file. Note that the source files are located in an exclusive directory (src/), the headers are in /include and the images are located in /assets. Here is my code:
main.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <Headers/RenderWindow.hpp>
int main(int argc, char *args[])
{
if (SDL_Init(SDL_INIT_VIDEO) > 0)
{
std::cout << "SDL_Init has failed..." << std::endl;
}
if (!(IMG_Init(IMG_INIT_PNG)))
{
std::cout << "IMG_Init has failed" << std::endl;
}
RenderWindow window("Untitled Racing Game", 1280, 720);
SDL_Texture *blueCar = window.LoadTexture("../assets/blue_car.png");
bool run = true;
SDL_Event event;
while (run)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
run = false;
}
}
window.Clear();
window.Render(blueCar);
window.Display();
}
window.CleanUp();
SDL_Quit();
return 0;
}
RenderWindow.hpp
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
class RenderWindow
{
public:
RenderWindow(const char *title, int width, int height);
SDL_Texture *LoadTexture(const char *filePath);
void CleanUp();
void Clear();
void Render(SDL_Texture *texture);
void Display();
private:
SDL_Window *window;
SDL_Renderer *renderer;
};
RenderWindow.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "Headers/RenderWindow.hpp"
RenderWindow::RenderWindow(const char *title, int width, int height)
: window(NULL), renderer(NULL)
{
window = (SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN));
if (window == NULL)
{
std::cout << "Window Failed to Load. Error " << SDL_GetError() << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
}
SDL_Texture *RenderWindow::LoadTexture(const char *filePath)
{
SDL_Texture *texture = NULL;
texture = IMG_LoadTexture(renderer, filePath);
if (texture == NULL)
{
std::cout << "Failed to load texture, " << SDL_GetError() << std::endl;
}
return texture;
}
void RenderWindow::CleanUp()
{
SDL_DestroyWindow(window);
}
void RenderWindow::Clear()
{
SDL_RenderClear(renderer);
}
void RenderWindow::Render(SDL_Texture *texture)
{
SDL_RenderCopy(renderer, texture, NULL, NULL);
}
void RenderWindow::Display()
{
SDL_RenderPresent(renderer);
}

window doesnt show image SDL

The program doesnt show the image in the window i have created , also i dont get any of the fail messages that i have set , which means the values are not null.
What is the problem?
Here is the code:
#include "SDL.h"
#include "SDL_image.h"
#include <iostream>
int main(int argc,char* argv[])
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Event event;
bool quit = false;
SDL_Surface *tmpsur = NULL;
SDL_Texture *tex = NULL;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("First window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, 0);
tmpsur = IMG_Load("assets/player.png");
if (tmpsur == NULL)
{
std::cout << "fail" << std::endl;
}
tex = SDL_CreateTextureFromSurface(renderer,tmpsur);
if (tex == NULL)
{
std::cout << "fail 2" << std::endl;
}
SDL_FreeSurface(tmpsur);
SDL_RenderPresent(renderer);
while (!quit)
{
while (SDL_PollEvent(&event) != 0)
{
if(event.type == SDL_QUIT)
{
quit = true;
}
}
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
You need to copy your texture onto the render target. Before presenting your renderer you need to call SDL_RenderCopy like this:
SDL_RenderCopy(renderer, text, nullptr, nullptr);
SDL_RenderPresent(renderer);
The nullptrs in the argument will make it copy the texture over all your target (the window).

C++ transfer SDL_renderer to a class

I am currently learning SDL2 and just managed to create a ping pong game. Some friends told me that I should start using classes for managing as an example player1 and player2. I know how to create a class but I do not understand how I would be able to pass SDL_Renderer between classes in order to render an object from within the class to the main.cpp file.
#include "SDL2/SDL.h"
#include "SDL2/SDL_render.h"
#include <iostream>
#include <windows.h>
#include <thread>
#include "player.h"
Player Player; //defining the class
const int WINDOW_WIDTH = 1280;
const int WINDOW_HEIGHT = 720;
int main(int argc, char *args[]) {
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window;
SDL_Renderer *renderer;
window = SDL_CreateWindow ("Test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH,
WINDOW_HEIGHT,
0
);
if (window == NULL) {
std::cout << "Window could not load" << SDL_GetError() << std::endl;
return 0;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
while (running) //running is a bool (true) {
Player.draw();
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
What do I have to do in my player.cpp draw function in order to draw an object on the screen?
Using C++ windows, compiling the code with g++ main.cpp player.cpp -o main.exe -IC:\MinGW\i686-w64-mingw32\include -LC:\MinGW\i686-w64-mingw32\lib -lmingw32 -lSDL2main -lSDL2
In main.cpp
Player.draw(renderer)
(presuming you are using the same code as above, just pass "renderer" to the Player.draw() function.)
In player.h
class Player {
public:
void draw(SDL_Renderer *renderer)
};
In player.cpp
void Player::draw(SDL_Renderer *renderer) {
SDL_Rect object;
object.x = 0;
object.y = 0;
object.h = 10;
object.w = 10;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &object);
SDL_RenderFillRect(renderer, &object);
}
// will draw a white box with at position (0,0)
I believe this is a simple way to do it

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