While trying to load a .png file with IMG_LoadTexture(renderer, "idle.png")
SDL_GetError() says: "Couldn't open idle.png"
There are no compiler errors, just a black window appears.
This is my main.cpp
#include <stdlib.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
int main(int argc, char** argv) {
SDL_Event event;
SDL_Renderer *renderer = NULL;
SDL_Texture *texture = NULL;
SDL_Window *window = NULL;
SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(
800, 600,
0, &window, &renderer
);
IMG_Init(IMG_INIT_PNG);
texture = IMG_LoadTexture(renderer, "idle.png");
std::cout << SDL_GetError();
while (1) {
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
break;
}
SDL_DestroyTexture(texture);
IMG_Quit();
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
But I guess the problem is the way I link the library. I installed sdl2, sdl2_image and libpng.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project(untitled)
set(CMAKE_CXX_STANDARD 17)
add_executable(untitled main.cpp)
INCLUDE(FindPkgConfig)
PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)
PKG_SEARCH_MODULE(SDL2IMAGE REQUIRED SDL2_image>=2.0.0)
INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS} ${SDL2IMAGE_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(untitled ${SDL2_LIBRARIES} ${SDL2IMAGE_LIBRARIES})
You are loading the image from the current working directory (CWD) of your application. That is not necessarily the same directory as your executable is in (it depends on how it is launched), which you seem to assume.
3 easy ways to fix:
change the cwd at runtime to where the file is and load as you do now.
provide an absolute path to the file when loading, so cwd is irrelevant.
obtain the path to the executable at runtime and then construct a path to the file relative to where the executable is. (best option in my opinion since it's robust against moving your project around/installing to a different location).
Related
I'm trying to run the executable of my application made with CLion and I get the error 0xc000007b (STATUS_INVALID_IMAGE_FORMAT).
If I launch the program from CLion the application start normally without any error, the problem occurs only if I try to launch the EXE.
I use SDL2, SDL2_image and SDL2_ttf. I always had this problem with SDL.
Project structure:
./cmake-build-debug
/SDL2.dll, SDL2_image.dll, SDL2_ttf.dll
/myProgram.exe
./include
/SDL2/
/*.a
./lib
/SDL2/
/*.h
./src
/main.cpp
main.cpp:
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow(
"GameEngine",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
0
);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
bool should_quit = false;
while (!should_quit) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
should_quit = true;
break;
}
break;
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
CMakeList.txt:
cmake_minimum_required(VERSION 3.21)
project(GameEngine)
set(CMAKE_CXX_STANDARD 20)
set(SDL2_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include/SDL2)
set(SDL2_LIB_DIR ${CMAKE_SOURCE_DIR}/lib/SDL2)
include_directories(${SDL2_INCLUDE_DIR})
link_directories(${SDL2_LIB_DIR})
file(GLOB_RECURSE SOURCES
${PROJECT_SOURCE_DIR}/src/*.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} mingw32 SDL2main SDL2 SDL2_image SDL2_ttf)
I'm trying to make a game on vscode with CMake. Everything was fine until I try to show a png image on the screen. I had initialized and linked everything correctly and there are no errors that occur except this:
"Couldn't open ./Images/Mountain.png"
Here is my code:
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
#undef main
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *tex;
int main(int argc, char const *argv[])
{
if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
std::cout << "Initialize SDL" << std::endl;
window = SDL_CreateWindow("SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 640, SDL_WINDOW_SHOWN);
if (window)
std::cout << "Window created" << std::endl;
renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer)
{
std::cout << "Render created" << std::endl;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
}
SDL_Surface *tempSurface = IMG_Load("./Images/Mountain.png");
if (!tempSurface)
std::cout << "Can't load image! Error: " << IMG_GetError() << std::endl;
tex = SDL_CreateTextureFromSurface(renderer, tempSurface);
SDL_FreeSurface(tempSurface);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
And here is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.19)
project(SDL2 VERSION 1.0.0)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(SDL2_PATH "E:\\Code\\SDL2")
set(SDL2_IMAGE_PATH "E:\\Code\\SDL2")
set(SDL2_TTF_PATH "E:\\Code\\SDL2")
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
find_package(SDL2_ttf REQUIRED)
include_directories(
${SDL2_INCLUDE_DIR}
${SDL2_IMAGE_INCLUDE_DIRS}
${SDL2_TTF_INCLUDE_DIR})
set(SOURCES
src/main.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(
${PROJECT_NAME}
${SDL2_LIBRARY}
${SDL2_IMAGE_LIBRARIES}
${SDL2_TTF_LIBRARIES}
)
I use Visual Studio Build Tools 2019 Release - x86 kit for CMake and build it successfully with CMake extension. The error only appears when I run the program although my path is correct.
I have been trying to figure out why CMake is not adding the static libraries of SDL2. If I add the SDL2.dll file next to the executable, then it does work.
It al builds fine and the headers can be found nice and easily.
The error
My CMakeList.txt looks like this. Trust me, I have tried everything but clearly I am doing something wrong.
cmake_minimum_required(VERSION 3.7)
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
SET(SDL2_DIR ./lib)
project(SDL2Test)
find_package(SDL2 REQUIRED)
include_directories(SDL2Test ${SDL2_INCLUDE_DIRS})
add_executable(SDL2Test Main.cpp)
target_link_libraries(SDL2Test ${SDL2_LIBRARIES})
This is the sdl2-config.cmake:
set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/../include")
# Support both 32 and 64 bit builds
if (${CMAKE_SIZEOF_VOID_P} MATCHES 8)
set(SDL2_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/x64/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/x64/SDL2main.lib")
else ()
set(SDL2_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/x86/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/x86/SDL2main.lib")
endif ()
string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES)
This is the Main.cpp
#include "SDL.h"
using namespace std;
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow(
"SDL2Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
0
);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Delay(3000);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Your SDL2.lib is import library, that requires accompanying DLL in the runtime.
To use static library (one that is completely linked with your EXE and does not require DLL), you will need to build static version of SDL2.lib yourself.
Keep in mind that this is discouraged by the author of SDL
I am trying to start using SDL2 (with CLion as my IDE), but I'm running into errors. I'm on Pop!_OS 19.10 (based on ubuntu)
Here are the relevant project files:
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(sdlpractice)
set(CMAKE_CXX_STANDARD 20)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
add_executable(sdlpractice main.cpp)
target_link_libraries(sdlpractice ${SDL2_LIBRARIES})
Main.cpp
#include "SDL2/SDL.h"
#include "stdio.h"
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main(int argc, char* args[]) {
// The window we will be rendering to
SDL_Window * ptrWindow = NULL;
// The surface contained by the window
SDL_Surface * ptrScreenSurface = NULL;
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
} else {
// Create window
ptrWindow = SDL_CreateWindow("SDL Practice",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (ptrWindow == nullptr) {
printf("Window creation failed: %s\n", SDL_GetError());
}
// Get window surface
ptrScreenSurface = SDL_GetWindowSurface(ptrWindow);
// Fill the surface white
SDL_FillRect(ptrScreenSurface, NULL, SDL_MapRGB(ptrScreenSurface->format, 0xFF, 0xFF, 0xFF));
// Update the surface
SDL_UpdateWindowSurface(ptrWindow);
// Wait 2 seconds
SDL_Delay(2000);
// Destroy window, quit SDL subsystems
SDL_DestroyWindow(ptrWindow);
SDL_Quit();
return 0;
}
}
I get the following error:
SDL could not initialize! SDL_Error: No available video device
I have tried setting DISPLAY=:0.0 in CLion's run configurations. Same error results. Futhermore, I ran
echo $DISPLAY
:1
and tried using :1 as well, same error persists.
Removing /usr/local/bin/sdl2-config,/usr/local/include/SDL2 and /usr/local/lib/libSDL2* (as suggested by Botje) solved the problem due to the self-built version of SDL2 missing the required video headers.
I have a Parent CMake project and a Child CMake project, inside the parent cmake project I can call any OpenGL function and it works perfectly fine, but inside the child project I can't call any OpenGL functions directly, only through the parent projects functions will it work.
Parent Project:
cmake_minimum_required (VERSION 3.8)
project(LumiumEngine)
set(CMAKE_DEBUG_POSTFIX "-d")
set(LUMI_DIR "LumiumEngine")
# SDL2
find_package(SDL2 CONFIG REQUIRED)
add_library(${PROJECT_NAME} SHARED "${LUMI_DIR}/System/Window.hpp" "${LUMI_DIR}/System/Window.cpp")
# glad
set(GLAD_DIR "${CMAKE_HOME_DIRECTORY}/external/glad")
add_library("glad" "${GLAD_DIR}/src/glad.c")
target_include_directories("glad" PUBLIC "${GLAD_DIR}/include")
target_include_directories(${PROJECT_NAME} PUBLIC "${SDL2_INCLUDE_DIRS}" "${GLAD_DIR}/include")
target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2 SDL2::SDL2main "glad" "${CMAKE_DL_LIBS}")
set_target_properties(${PROJECT_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/${PROJECT_NAME}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/${PROJECT_NAME}/bin"
)
install(DIRECTORY bin
DESTINATION "${CMAKE_HOME_DIRECTORY}/Lumin"
FILES_MATCHING
PATTERN "*.dll"
PATTERN "*.ilk" EXCLUDE
PATTERN "*.pdb" EXCLUDE
)
Child Project:
cmake_minimum_required (VERSION 3.8)
project(Lumin)
set(CMAKE_DEBUG_POSTFIX "-d")
# find OpenGL
find_package(OpenGL REQUIRED)
add_executable(${PROJECT_NAME} "main.cpp" "${CMAKE_HOME_DIRECTORY}/external/glad/src/glad.c")
target_link_libraries(${PROJECT_NAME} PUBLIC "${OPENGL_LIBRARIES}" LumiumEngine)
set_target_properties(${PROJECT_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/${PROJECT_NAME}/bin"
)
The child project is dependent on parent project, (in the parent-parent directory i just add both of these project as sub directories and add_dependency(Child Parent), the proper .dlls and .libs should be loaded in, from my understanding I load SDL2, SDL2main, glad in the parent project and then load in OpenGL + all the libraries from Parent since they were added with the PUBLIC tag
The code is not the issue, since I created a project with two sub projects in Visual Studio with the same code which worked. Is there a library that i'm missing? It also might be an issue with compiling the OpenGL Loader `glad'.
I think the main issue that is confusing me is why do OpenGL functions hidden by an abstraction layer in my Parent project work fine but when i call OpenGL functions in my Child project I get an "Exception Thrown at 0x00010..." at the OpenGL call. Thanks for any help or guidance.
Edit: Adding a code example:
This is my Window.cpp from the Parent project LumiumEngine
#include "Window.hpp"
#include <glad/glad.h>
lumi::Window::Window()
{
m_shouldClose = true;
}
lumi::Window::~Window()
{
SDL_Quit();
}
bool lumi::Window::createWindow(std::string title, int xPos, int yPos, int width, int height, unsigned int flags)
{
// Set SDL as ready and init SDL
SDL_SetMainReady();
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL Init Error", "Could not init SDL2", NULL);
SDL_Quit();
return false;
}
SDL_GL_LoadLibrary(NULL); // Default OpenGL is fine.
// Request an OpenGL 4.5 context (should be core)
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
// Also request a depth buffer
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
// create the window
m_pWindow = SDL_CreateWindow(title.c_str(), xPos, yPos, width, height, flags);
if (m_pWindow == nullptr)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL Window Error", "Could not create a window", NULL);
SDL_Quit();
return false;
}
// create the openGL context
m_glContext = SDL_GL_CreateContext(m_pWindow);
if (m_glContext == nullptr)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL Window Error", "Could not create an openGL context with version 4.5", NULL);
SDL_Quit();
return false;
}
printf("OpenGL loaded\n");
gladLoadGLLoader(SDL_GL_GetProcAddress);
printf("Vendor: %s\n", glGetString(GL_VENDOR));
printf("Renderer: %s\n", glGetString(GL_RENDERER));
printf("Version: %s\n", glGetString(GL_VERSION));
m_shouldClose = false;
glViewport(0, 0, width, height);
glClearColor(.2f, .4f, .6f, 1.0f);
return true;
}
bool lumi::Window::isOpen()
{
return !m_shouldClose;
}
Child Project main.cpp
#include <LumiumEngine/System/Window.hpp>
#include <glad/glad.h>
int main(int argc, char **argv)
{
lumi::Window window;
if (window.createWindow("Hello World", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL))
{
glClearColor(0.2f, 0.4f, 0.6f, 1.0f); // exception occurs here, as you can see it's after i create a valid OpenGL context
while (window.isOpen())
{
//window.display();
}
}
return 1;
}
Notice how i call the same exact OpenGL function glClearColor() inside my createWindow function and it runs perfectly fine. I can verify that it works by calling window.display which calls glClear(GL_COLOR_BUFFER_BIT); then SDL_GL_SwapBuffers()
Side note: I tried just getting rid of the child project and making the Parent project into a executable instead of a library and it works fine, but i really would like to be able to make LumiumEngine a library so i can call it from multiple projects in the future. I'm completely stumped at the moment.
Blahhh!
So for some reason you have to manually load OpenGL through glad again in the Child Project, even though it has already been called in the parent project and we have verified that we had a valid OpenGL Context. The simple fix for this was to add a:
gladLoadGLLoader(SDL_GL_GetProcAddress)
call after the SDL window was created:
#include <LumiumEngine/System/Window.hpp>
#include <glad/glad.h>
int main(int argc, char **argv)
{
lumi::Window window;
if (window.createWindow("Hello World", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL))
{
gladLoadGLLoader(SDL_GL_GetProcAddress);
glClearColor(0.2f, 0.4f, 0.6f, 1.0f); // THIS WORKS NOW!!
while (window.isOpen())
{
window.display();
}
}
return 1;
}
Such a simple fix for a simple problem that was giving me a major headache.