SDL_image as a subproject with cmake failing - c++

I am trying to use SDL and SDL_image as a subprojects in my project. Folder structure:
testRepos
├── build //build files inside
├── src
│ ├── main.cpp
│ ├── texture.png
│ └── CMakeLists.txt
├── third_party
│ ├── SDL //SDL repo inside
│ ├── SDL_image //SDL_image repo inside
│ └── CMakeLists.txt
└── CMakeLists.txt
main.cpp
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
using namespace std;
SDL_Window *m_window;
SDL_Renderer *m_renderer;
bool init();
void close();
SDL_Texture* loadTexture(const char* file_);
void renderTexture(SDL_Texture* tex_, int x_, int y_, int w_, int h_);
void renderTexture(SDL_Texture* tex_, int x_, int y_);
int SDL_main(int argc, char* args[])
{
if (!init())
{
cout << "Cannot init SDL\n";
}
bool isRunning = true;
SDL_Event e;
SDL_Texture* tex = loadTexture("texture.png");
while (isRunning)
{
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT)
isRunning = false;
}
SDL_RenderClear(m_renderer);
renderTexture(tex, 0, 0);
SDL_RenderPresent(m_renderer);
}
close();
system("pause");
return 0;
}
bool init()
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cout << "SDL initialization error: " << SDL_GetError() << std::endl;
return false;
}
if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) != IMG_INIT_PNG)
{
std::cout << "IMG initialization error: " << SDL_GetError() << std::endl;
return false;
}
m_window = SDL_CreateWindow("TestName", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_SHOWN);
if (m_window == NULL)
{
std::cout << "Window creation error: " << SDL_GetError() << std::endl;
return false;
}
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
if (m_renderer == nullptr) {
std::cout << "Renderer creation error: " << SDL_GetError() << std::endl;
return false;
}
}
void close()
{
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
IMG_Quit();
SDL_Quit();
}
SDL_Texture* loadTexture(const char* file_)
{
SDL_Texture* texture = IMG_LoadTexture(m_renderer, file_);
if (!texture) {
std::cout << "Texture loading problem: " << file_ << " | " << IMG_GetError() << std::endl;
}
return texture;
}
void renderTexture(SDL_Texture* tex_, int x_, int y_, int w_, int h_)
{
SDL_Rect dst;
dst.x = x_;
dst.y = y_;
dst.w = w_;
dst.h = h_;
SDL_RenderCopy(m_renderer, tex_, NULL, &dst);
}
void renderTexture(SDL_Texture* tex_, int x_, int y_)
{
int w, h;
SDL_QueryTexture(tex_, NULL, NULL, &w, &h);
renderTexture(tex_, x_, y_, w, h);
}
testRepos/CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project (ProjectRoot)
add_subdirectory (third_party)
add_subdirectory (src)
testRepos/third_party/CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project(third_party)
add_subdirectory(SDL)
set(SDL_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/SDL/include)
add_subdirectory(SDL_image)
set(SDL_IMAGE_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/SDL_image)
testRepos/src/CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project(main)
add_executable (main main.cpp)
# Connecting the library, specify where to get the header files
target_include_directories(main PUBLIC ${SDL_INCLUDE_DIR} ${SDL_IMAGE_INCLUDE_DIR})
# And also we specify dependence on static library
target_link_libraries(main SDL2main SDL2-static SDL2_image)
It works perfectly fine without SDL_image (ofc without SDL_image code in sources). After adding SDL_image, it still builds, but requires to manually add SDL2_image.dll, SDL2d.dll , zlibd1.dll and libpng16d.dll and fails after running .exe with this:
WARN:
Assertion failure at SDL_CreateTextureFromSurface_REAL (T:\testRepos\third_party\SDL\src\render\SDL_render.c:1252), triggered 1 time:
'renderer && renderer->magic == &renderer_magic'
Texture loading problem: texture.png |
WARN:
Assertion failure at SDL_QueryTexture_REAL (T:\testRepos\third_party\SDL\src\render\SDL_render.c:1390), triggered 1 time:
'texture && texture->magic == &texture_magic'
WARN:
Assertion failure at SDL_RenderCopyF_REAL (T:\testRepos\third_party\SDL\src\render\SDL_render.c:3199), triggered 1 time:
'texture && texture->magic == &texture_magic'
It fails inside the IMG_LoadTexture, so everything definitely was initialized properly. Since I use libraries as a subprojects, I cannot use solution with packages. How can I solve this problem?

Related

Cant execute a simple "SDL2HelloWorld" on Windows with CMake

I don't understand why when I run the program nothing happens (no windows or cout):
.\src\main.cpp :
#include <SDL2/SDL.h>
#include <iostream>
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
int main(int argc, char* args[]) {
std::cout << "Le programme se lance"; // should at least show
SDL_Window* window = NULL;
SDL_Surface* screenSurface = NULL;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cout << "could not initialize sdl2 :" << SDL_GetError() << std::endl;
return 1;
}
window = SDL_CreateWindow(
"hello_sdl2",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_SHOWN
);
if (window == NULL) {
std::cout << "could not create window:" << SDL_GetError() << std::endl;
return 1;
}
screenSurface = SDL_GetWindowSurface(window);
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF));
SDL_UpdateWindowSurface(window);
SDL_Delay(10000);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
.\CMakeLists.txt :
cmake_minimum_required(VERSION 3.25.1)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
project("Test")
set(SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(SDL2_DIR "${SRC_DIR}/lib/cmake/SDL2")
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
add_executable(MAIN "${SRC_DIR}/src/main.cpp")
target_link_libraries(MAIN ${SDL2_LIBRARIES})
The architecture of my project is the following :
All files are from the assets SDL2-devel-2.26.1-mingw.zip
The commands I used in order :
cd .\build\
cmake .. -G "MinGW Makefiles"
make
.\MAIN.exe
make and .\Main.exe results :
In fact I just had to copy SDL2.dll in the build folder.

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

I get an "unresolved external symbol" error, but it can access them in visual studio LNK2019/LNK 1120

So I'm just trying to set up a game loop and window, but it won't even start with a blank screen. When I run it, it gives me an error every time I try to use any function from SDL. I have the .dll in the same folder as the project files and in the Debug folder. I'm pretty sure I have them linked in the project properties, too, but I don't know. When I'm in visual studio, I can hover over the functions and it has the declarations of them (I think)
SDL2\include is in VC++ Directories -> Include Directories
SDL2\lib\x64 is in VC++ Directories -> Library Directories
SDL2\include is also in C/C++ -> General -> Additional Include Directories
SDL2\lib\x64 is also in Linker -> General -> Additional Library Directories
SDL.lib and SDLmain.lib are both in Linker -> Input -> Additional Dependencies
edit: forgot to show project properties
This is Game.hpp
#include "SDL.h"
#include <iostream>
class Game
{
public:
Game();
~Game();
void init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen);
void handleEvents();
void update();
void render();
void clean();
bool running() { return isRunning; }
private:
int cnt = 0;
bool isRunning;
SDL_Window *window;
SDL_Renderer *renderer;
};
This is Game.cpp
#include "Game.hpp"
Game::Game()
{}
Game::~Game()
{}
void Game::init(const char *title, int xpos, int ypos, int width, int height, bool fullscreen)
{
int flags = 0;
if (fullscreen)
{
flags = SDL_WINDOW_FULLSCREEN;
}
if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
std::cout << "Subsystems initialized" << std::endl;
window = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
if (window)
{
std::cout << "Window created" << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer)
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
std::cout << "Renderer created" << std::endl;
}
isRunning = true;
} else {
isRunning = false;
}
}
void Game::handleEvents()
{
SDL_Event event;
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
isRunning = false;
break;
default:
break;
}
}
void Game::update()
{
cnt++;
std::cout << cnt << std::endl;
}
void Game::render()
{
SDL_RenderClear(renderer);
//add stuff to render
SDL_RenderPresent(renderer);
}
void Game::clean()
{
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
std::cout << "Game cleaned" << std::endl;
}
And this is main.cpp
#include "Game.hpp"
Game *game = nullptr;
int main(int argc, char *argv[]) {
game = new Game();
game->init("Maxgame", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, false);
while (game->running()) {
game->handleEvents();
game->update();
game->render();
}
game->clean();
return 0;
}
And these are the
errors
I'm getting.
You could set Linker -> Advanced -> Target Machine -> MachineX64 in Properties.

Already Defined / Multiple Object Definitions / Visual Studio

I'm following along with a video tut on SDL. When I do exactly as he has done, by putting an SDL_Texture* in the Game.h and use the object in Game.cpp, I get an error about multiple definitions. Yet, the video creator has no error of such. I can, however, copy and paste the SDL_Texture* to the .cpp and it work just fine.
Why is it that the same code will work on one, but not another machine, in Visual Studio
Game.cpp
#include "Game.h"
Game::Game()
{
}
Game::~Game()
{
}
void Game::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen)
{
int flags = 0;
if (fullscreen)
{
flags = SDL_WINDOW_FULLSCREEN;
}
if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
std::cout << "Successfully Initialized Subsystem . . . " << std::endl;
window = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
if (window)
{
std::cout << "Successfully Created Window . . . " << std::endl;
}
else
{
std::cout << "Something went wrong. Error: " << SDL_GetError() << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer)
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
std::cout << "Successfully Created Renderer . . . " << std::endl;
}
else
{
std::cout << "Something went wrong. Error: " << SDL_GetError() << std::endl;
}
is_running = true;
}
else
{
is_running = false;
}
SDL_Surface* surf_temp = IMG_Load("assets/player.png");
tex_player = SDL_CreateTextureFromSurface(renderer, surf_temp);
SDL_FreeSurface(surf_temp);
}
void Game::event_handle()
{
SDL_Event event;
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
is_running = false;
}
}
void Game::update()
{
cnt++;
std::cout << cnt << std::endl;
}
void Game::render()
{
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, tex_player, NULL, NULL);
SDL_RenderPresent(renderer);
}
void Game::clean()
{
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
std::cout << "Game cleaned . . . " << std::endl;
}
Game.h
#include "SDL.h"
#include "SDL_image.h"
#include <iostream>
#include <stdio.h>
#include <string>
SDL_Texture* tex_player;
class Game
{
public:
Game();
~Game();
void init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen);
void event_handle();
void update();
void render();
void clean();
bool running() { return is_running; }
private:
int cnt;
bool is_running;
SDL_Window *window;
SDL_Renderer *renderer;
};
main.cpp
#include "Game.h"
Game *game = nullptr;
int main(int argc, char *argv[])
{
game = new Game();
game->init("Yeah", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, false);
while (game->running())
{
game->event_handle();
game->update();
game->render();
}
game->clean();
return 0;
}
Error:
1>------ Build started: Project: SDL_Template, Configuration: Debug Win32 ------
1>main.cpp
1>LINK : C:\Users\Onion\documents\visual studio 2017\Projects\SDL_Template\Debug\SDL_Template.exe not found or not built by the last incremental link; performing full link
1>main.obj : error LNK2005: "struct SDL_Texture * tex_player" (?tex_player##3PAUSDL_Texture##A) already defined in Game.obj
1>C:\Users\Onion\documents\visual studio 2017\Projects\SDL_Template\Debug\SDL_Template.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Done building project "SDL_Template.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Think of #include as "please copy-paste the content of this file here."
Since you #includeGame.h in both main.cpp and Game.cpp, the line SDL_Texture* tex_player; which is a global variable definition (as opposed to declaration) appears in both files, which confuses the linker.
The immediate fix is to declare the variable in game.h:
extern SDL_Texture* tex_player;
and define it in game.cpp
SDL_Texture* tex_player;
The better fix would be to make tex_player a member variable of Game (or some other class).

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