cmake --version
mingw32-make --version
cmake -G "MinGW Makefiles" --fresh -S . -B dist -DCMAKE_INSTALL_PREFIX=E:\libs\sdl3-desktop-prefix
cmake -G "MinGW Makefiles" --fresh -S . -B dist -DCMAKE_INSTALL_PREFIX=E:\libs\sdl3-desktop-prefix -DSDL_AUDIO=OFF -DSDL_CAMERA=OFF -DSDL_HAPTIC=OFF -DSDL_HIDAPI=OFF -DSDL_POWER=OFF -DSDL_SENSOR=OFF -DSDL_DIALOG=OFF
cmake --build dist -j4
cmake --install dist
upx.exe --best SDL3.dll
mkdir my-project
cd my-project
cmake_minimum_required(VERSION 3.20)
project(my_project)
find_package(SDL3)
file(WRITE main.cpp "#include <SDL3/SDL.h>\nint main() {SDL_Init(0);SDL_Quit();return 0;}")
add_executable(app main.cpp)
target_link_libraries(app PRIVATE SDL3::SDL3)
# This code copies the "SDL3.dll" file to the build directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
)
mkdir dist\win
cd dist
cmake -G "MinGW Makefiles" --fresh -S .. -B ..\dist\win -DSDL3_DIR=E:\libs\sdl3-desktop-prefix\lib\cmake\SDL3
cd win
mingw32-make
app
target_link_options(app PRIVATE -static-libgcc -static-libstdc++)
The previous example creates "main.cpp" inside of the "CMakeLists.txt" using "file(WRITE... )":
file(WRITE main.cpp "#include <SDL3/SDL.h>\nint main() {SDL_Init(0);SDL_Quit();return 0;}")
Let's create our "main.cpp" and a window.
mkdir create-a-window
cd create-a-window
cmake_minimum_required(VERSION 3.20)
project(create_a_window)
add_executable(app main.cpp)
# This code copies the "SDL3.dll" file to the build directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
)
find_package(SDL3)
target_link_libraries(app PRIVATE SDL3::SDL3)
target_compile_definitions(app PRIVATE SDL_MAIN_USE_CALLBACKS)
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
struct AppContext
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_AppResult app_quit = SDL_APP_CONTINUE;
};
SDL_AppResult SDL_Fail()
{
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (SDL_Init(SDL_INIT_VIDEO))
{
return SDL_Fail();
}
SDL_Window *window = SDL_CreateWindow("Window", 352, 430,
SDL_WINDOW_RESIZABLE);
if (!window)
{
return SDL_Fail();
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, NULL);
if (!renderer)
{
return SDL_Fail();
}
SDL_ShowWindow(window);
*appstate = new AppContext {
window,
renderer,
};
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
{
auto *app = (AppContext *)appstate;
if (event->type == SDL_EVENT_QUIT)
{
app->app_quit = SDL_APP_SUCCESS;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
auto *app = (AppContext *)appstate;
SDL_SetRenderDrawColor(app->renderer, 128, 255, 128, SDL_ALPHA_OPAQUE);
SDL_RenderClear(app->renderer);
SDL_RenderPresent(app->renderer);
return app->app_quit;
}
void SDL_AppQuit(void *appstate)
{
auto *app = (AppContext *)appstate;
if (app)
{
SDL_DestroyRenderer(app->renderer);
SDL_DestroyWindow(app->window);
delete app;
}
SDL_Quit();
}
mkdir dist\win
cd dist
cmake -G "MinGW Makefiles" --fresh -S .. -B ..\dist\win -DSDL3_DIR=E:\libs\sdl3-desktop-prefix\lib\cmake\SDL3
cd win
mingw32-make
app
When you run the "app.exe" from the example above you see a window and the console. Let's hide the console
add_executable(app WIN32)
target_link_options(app PRIVATE "-mwindows")
cmake_minimum_required(VERSION 3.20)
project(background_color)
add_executable(app) # WIN32
target_include_directories(app PRIVATE E:/libs/glad-2.0.6/include)
target_sources(app
PRIVATE
E:/libs/glad-2.0.6/src/glad.c
main.cpp
)
# This code copies the "SDL3.dll" file to the build directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
)
find_package(SDL3)
target_link_libraries(app PRIVATE SDL3::SDL3)
target_compile_definitions(app PRIVATE SDL_MAIN_USE_CALLBACKS)
target_link_options(app PRIVATE -static-libgcc -static-libstdc++)
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <glad/glad.h>
#include <iostream>
struct AppContext
{
SDL_Window *window;
SDL_GLContext glContext;
SDL_AppResult appQuit = SDL_APP_CONTINUE;
};
SDL_AppResult SDL_Fail()
{
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
// Init the library, here we make a window so we only need the Video capabilities.
if (SDL_Init(SDL_INIT_VIDEO))
{
return SDL_Fail();
}
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable MULTISAMPLE
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); // can be 2, 4, 8 or 16
// Create a window
SDL_Window *window = SDL_CreateWindow("SDL3, OpenGL 2.1, C++", 350, 350,
SDL_WINDOW_OPENGL); // | SDL_WINDOW_RESIZABLE
if (!window)
{
return SDL_Fail();
}
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (!glContext)
{
return SDL_Fail();
}
if (!gladLoadGL())
{
std::cout << "Failed to load OpenGL functions" << std::endl;
return SDL_APP_FAILURE;
}
glClearColor(0.2f, 0.3f, 0.5f, 1.f);
SDL_ShowWindow(window);
// Set up the application data
*appstate = new AppContext {
window,
glContext,
};
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
{
auto *app = (AppContext *)appstate;
switch (event->type)
{
case SDL_EVENT_QUIT:
{
app->appQuit = SDL_APP_SUCCESS;
break;
}
default:
{
break;
}
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
auto *app = (AppContext *)appstate;
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(app->window);
return app->appQuit;
}
void SDL_AppQuit(void *appstate)
{
auto *app = (AppContext *)appstate;
if (app)
{
SDL_GL_DestroyContext(app->glContext);
SDL_DestroyWindow(app->window);
delete app;
}
SDL_Quit();
}
mkdir dist\win
cd dist
cmake -G "MinGW Makefiles" --fresh -S .. -B ../dist/win -DSDL3_DIR=E:/libs/sdl3-desktop-prefix/lib/cmake/SDL3
cd win
mingw32-make
app
upx.exe --best app.exe
You can open and the previous project in the Qt Creator
Key: SDL3_DIR
Value: E:\libs\sdl3-desktop-prefix\lib\cmake\SDL3
project("opengl_window")
cmake_minimum_required(VERSION 3.20)
project(opengl_window)
add_executable(app main.cpp)
target_sources(app
PRIVATE
src/main.cpp
src/math_helper.cpp
src/shader_program.cpp
E:/libs/glad-2.0.6/src/glad.c
)
# This code copies the "SDL3.dll" file to the build directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
)
find_package(SDL3)
target_link_libraries(app PRIVATE SDL3::SDL3)
target_compile_definitions(app PRIVATE SDL_MAIN_USE_CALLBACKS)
Key: SDL3_DIR
Value: E:\libs\sdl3-desktop-prefix\lib\cmake\SDL3
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
struct AppContext
{
SDL_Window *window;
SDL_GLContext glcontext;
SDL_AppResult app_quit = SDL_APP_CONTINUE;
};
SDL_AppResult SDL_Fail()
{
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
// Init the library, here we make a window so we
// only need the Video capabilities
if (SDL_Init(SDL_INIT_VIDEO))
{
return SDL_Fail();
}
// Create a window
SDL_Window *window = SDL_CreateWindow("OpenGL Window", 350, 350,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!window)
{
return SDL_Fail();
}
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
if (!glcontext)
{
return SDL_Fail();
}
SDL_ShowWindow(window);
// Set up the application data
*appstate = new AppContext {
window,
glcontext,
};
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
{
auto *app = (AppContext *)appstate;
switch (event->type)
{
case SDL_EVENT_QUIT:
{
app->app_quit = SDL_APP_SUCCESS;
break;
}
default:
{
break;
}
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
auto *app = (AppContext *)appstate;
SDL_GL_SwapWindow(app->window);
return app->app_quit;
}
void SDL_AppQuit(void *appstate)
{
auto *app = (AppContext *)appstate;
if (app)
{
SDL_GL_DestroyContext(app->glcontext);
SDL_DestroyWindow(app->window);
delete app;
}
SDL_Quit();
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
auto *app = (AppContext *)appstate;
glClearColor(0.f, 0.5f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(app->window);
return app->app_quit;
}
error: 'glClearColor' was not declared in this scope
error: 'GL_COLOR_BUFFER_BIT' was not declared in this scope
error: 'glClear' was not declared in this scope
target_include_directories(app PRIVATE E:/libs/glad-2.0.6/include)
target_sources(app
PRIVATE
main.cpp
E:/libs/glad-2.0.6/src/glad.c
)
#include <glad/glad.h>
if (!gladLoadGL())
{
std::cout << "Failed to load OpenGL functions" << std::endl;
return SDL_APP_FAILURE;
}
#include <iostream>
cmake_minimum_required(VERSION 3.20)
project(opengl_window)
add_executable(app)
target_include_directories(app PRIVATE E:/libs/glad-2.0.6/include)
target_sources(app
PRIVATE
main.cpp
E:/libs/glad-2.0.6/src/glad.c
)
# This code copies the "SDL3.dll" file to the build directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
)
find_package(SDL3)
target_link_libraries(app PRIVATE SDL3::SDL3)
target_compile_definitions(app PRIVATE SDL_MAIN_USE_CALLBACKS)
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <glad/glad.h>
#include <iostream>
struct AppContext
{
SDL_Window *window;
SDL_GLContext glcontext;
SDL_AppResult app_quit = SDL_APP_CONTINUE;
};
SDL_AppResult SDL_Fail()
{
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
// Init the library, here we make a window so we
// only need the Video capabilities
if (SDL_Init(SDL_INIT_VIDEO))
{
return SDL_Fail();
}
// Create a window
SDL_Window *window = SDL_CreateWindow("OpenGL Window", 350, 350,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!window)
{
return SDL_Fail();
}
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
if (!glcontext)
{
return SDL_Fail();
}
if (!gladLoadGL())
{
std::cout << "Failed to load OpenGL functions" << std::endl;
return SDL_APP_FAILURE;
}
SDL_ShowWindow(window);
// Set up the application data
*appstate = new AppContext {
window,
glcontext,
};
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
{
auto *app = (AppContext *)appstate;
switch (event->type)
{
case SDL_EVENT_QUIT:
{
app->app_quit = SDL_APP_SUCCESS;
break;
}
default:
{
break;
}
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
auto *app = (AppContext *)appstate;
glClearColor(0.f, 0.5f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(app->window);
return app->app_quit;
}
void SDL_AppQuit(void *appstate)
{
auto *app = (AppContext *)appstate;
if (app)
{
SDL_GL_DestroyContext(app->glcontext);
SDL_DestroyWindow(app->window);
delete app;
}
SDL_Quit();
}
Let's create a text file and embed it in the EXE. We'll print the contents of the text file to the console
mkdir embeded-text-file
cd embeded-text-file
Hello, World!
cmake_minimum_required(VERSION 3.20)
project(embeded_text_file)
add_executable(app)
target_sources(app
PRIVATE
src/main.cpp
)
# C++ 20 requires for the "battery-embed" library
target_compile_features(app PUBLIC cxx_std_20)
# This code will install the "battery-embed" library
include(FetchContent)
FetchContent_Declare(
battery-embed
GIT_REPOSITORY https://github.com/batterycenter/embed.git
GIT_TAG main
)
FetchContent_MakeAvailable(battery-embed)
# Files to embed
b_embed(app assets/hello-world.txt)
#include <iostream>
#include <battery/embed.hpp>
int main()
{
std::string text = b::embed<"assets/hello-world.txt">();
std::cout << text << std::endl;
return 0;
}
mkdir dist\win
cd dist
cmake -G "MinGW Makefiles" --fresh -S .. -B ..\dist\win
cd win
mingw32-make
app
This example uses the embed library. You don't need to install this library. It will be installed automatically by "CMakeLists.txt"
mkdir dist\win
cd dist
cmake -G "MinGW Makefiles" --fresh -S .. -B ..\dist\win -DSDL3_DIR=E:\libs\sdl3-desktop-prefix\lib\cmake\SDL3
cd win
mingw32-make
app
cmake_minimum_required(VERSION 3.20)
project(imgui_static)
# Set where the ImGui files are stored
set(IMGUI_PATH_INCLUDE "E:/libs/imgui-1.91.1-sdl3-opengl3/include")
set(IMGUI_PATH_SRC "E:/libs/imgui-1.91.1-sdl3-opengl3/src_to_build")
# Compile as static library
file(GLOB IMGUI_SOURCES ${IMGUI_PATH_SRC}/*.cpp)
add_library("ImGui" STATIC ${IMGUI_SOURCES})
target_include_directories("ImGui" PUBLIC ${IMGUI_PATH_INCLUDE})
mkdir dist
cd dist
cmake -G "MinGW Makefiles" ..
mingw32-make
cmake_minimum_required(VERSION 3.20)
project(imgui_and_triangle)
add_executable(app) # WIN32 - add this to hide the console like this: add_executable(app WIN32)
target_include_directories(app PRIVATE E:/libs/glad-2.0.6/include)
target_include_directories(app PRIVATE E:/libs/imgui-1.91.1-sdl3-opengl3/include)
target_sources(app
PRIVATE
E:/libs/glad-2.0.6/src/glad.c
E:/libs/imgui-1.91.1-sdl3-opengl3/src/imgui_impl_opengl3.cpp
E:/libs/imgui-1.91.1-sdl3-opengl3/src/imgui_impl_sdl3.cpp
main.cpp
)
# This code copies the "SDL3.dll" file to the build directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
)
find_package(SDL3)
target_link_directories(app PRIVATE E:/libs/imgui-1.91.1-sdl3-opengl3/lib)
target_link_libraries(app PRIVATE SDL3::SDL3 ImGui opengl32)
target_compile_definitions(app PRIVATE SDL_MAIN_USE_CALLBACKS)
target_link_options(app PRIVATE -static-libgcc -static-libstdc++)
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <glad/glad.h>
#include <iostream>
#include <vector>
#include <imgui_impl_opengl3.h>
#include <imgui_impl_sdl3.h>
struct AppContext
{
SDL_Window *window;
SDL_GLContext glContext;
SDL_AppResult appQuit = SDL_APP_CONTINUE;
};
const char *vertexShaderSource =
"attribute vec2 aPosition;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPosition, 0.0, 1.0);\n"
"}\n";
const char *fragmentShaderSource =
"void main()\n"
"{\n"
" gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);\n"
"}\n";
// Helper function for creating shaders
GLuint createShader(const char *shaderSource, int shaderType)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> errorLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
glDeleteShader(shader); // Don't leak the shader
std::cout << &(errorLog[0]) << std::endl;
std::cout << shaderSource << std::endl;
}
return shader;
}
// Helper function for creating a shader program
GLuint createShaderProgram()
{
GLuint program = glCreateProgram();
GLuint vShader = createShader(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fShader = createShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
glAttachShader(program, vShader);
glAttachShader(program, fShader);
glLinkProgram(program);
glUseProgram(program);
return program;
}
// Load a triangle to the video card
void initVertexBuffers(GLuint program)
{
float vertPositions[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
0.f, 0.5f
};
GLuint vertPosBuffer;
glGenBuffers(1, &vertPosBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer);
int amount = sizeof(vertPositions) / sizeof(vertPositions[0]);
glBufferData(GL_ARRAY_BUFFER, amount * sizeof(GLfloat),
vertPositions, GL_STATIC_DRAW);
GLint aPositionLocation = glGetAttribLocation(program, "aPosition");
glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(aPositionLocation);
}
SDL_AppResult SDL_Fail()
{
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
// init the library, here we make a window so we only need the Video capabilities.
if (SDL_Init(SDL_INIT_VIDEO))
{
return SDL_Fail();
}
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable MULTISAMPLE
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); // can be 2, 4, 8 or 16
// Create a window
SDL_Window *window = SDL_CreateWindow("SDL3, OpenGL 2.1, C++", 400, 400,
SDL_WINDOW_OPENGL); // | SDL_WINDOW_RESIZABLE
if (!window)
{
return SDL_Fail();
}
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (!glContext)
{
return SDL_Fail();
}
if (!gladLoadGL())
{
std::cout << "Failed to load OpenGL functions" << std::endl;
return SDL_APP_FAILURE;
}
glClearColor(0.188f, 0.22f, 0.255f, 1.f);
GLuint program = createShaderProgram();
initVertexBuffers(program);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
(void)io;
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// ImGui::StyleColorsLight();
// Setup Platform/Renderer bindings
ImGui_ImplSDL3_InitForOpenGL(window, glContext);
ImGui_ImplOpenGL3_Init();
SDL_ShowWindow(window);
// set up the application data
*appstate = new AppContext {
window,
glContext,
};
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
{
auto *app = (AppContext *)appstate;
// ImGui_ImplSDL3_ProcessEvent(event);
switch (event->type)
{
case SDL_EVENT_QUIT:
{
app->appQuit = SDL_APP_SUCCESS;
break;
}
default:
{
break;
}
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
auto *app = (AppContext *)appstate;
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Another Window");
ImGui::Text("Hello from another window!");
if (ImGui::Button("Click Me"))
std::cout << "clicked" << std::endl;
ImGui::End();
ImGui::Render();
ImGuiIO &io = ImGui::GetIO();
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
// Clear the canvas
glClear(GL_COLOR_BUFFER_BIT);
// Draw a triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
// Draw GUI
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(app->window);
return app->appQuit;
}
void SDL_AppQuit(void *appstate)
{
auto *app = (AppContext *)appstate;
if (app)
{
SDL_GL_DestroyContext(app->glContext);
SDL_DestroyWindow(app->window);
delete app;
}
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
SDL_Quit();
}
mkdir dist
cd dist
cmake -G "MinGW Makefiles" --fresh -S .. -B ../dist/win -DSDL3_DIR=E:/libs/sdl3-desktop-prefix/lib/cmake/SDL3
cd win
mingw32-make
app
cmake -G "MinGW Makefiles" --fresh -S . -B dist -DCMAKE_INSTALL_PREFIX=E:\libs\box2d-2.4.2-prefix -DBOX2D_BUILD_TESTBED=OFF -DBOX2D_BUILD_UNIT_TESTS=OFF
cmake --build dist -j4
cmake --install dist
E:\libs\box2d-2.4.2-prefix\lib\cmake\box2d
cmake_minimum_required(VERSION 3.20)
project(print_gravity_box2d)
add_executable(app) # WIN32
target_include_directories(app PRIVATE E:/libs/glad-2.0.6/include)
target_sources(app
PRIVATE
E:/libs/glad-2.0.6/src/glad.c
main.cpp
)
# This code copies the "SDL3.dll" file to the build directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
)
find_package(SDL3)
find_package(box2d)
target_link_libraries(app PRIVATE box2d::box2d SDL3::SDL3)
target_compile_definitions(app PRIVATE SDL_MAIN_USE_CALLBACKS)
target_link_options(app PRIVATE -static-libgcc -static-libstdc++)
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <glad/glad.h>
#include <box2d/box2d.h>
#include <iostream>
#include <vector>
b2World *world;
struct AppContext
{
SDL_Window *window;
SDL_GLContext glContext;
SDL_AppResult appQuit = SDL_APP_CONTINUE;
};
const char *vertexShaderSource =
"attribute vec2 aPosition;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPosition, 0.0, 1.0);\n"
"}\n";
const char *fragmentShaderSource =
"void main()\n"
"{\n"
" gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);\n"
"}\n";
// Helper function for creating shaders
GLuint createShader(const char *shaderSource, int shaderType)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> errorLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
glDeleteShader(shader); // Don't leak the shader
std::cout << &(errorLog[0]) << std::endl;
std::cout << shaderSource << std::endl;
}
return shader;
}
// Helper function for creating a shader program
GLuint createShaderProgram()
{
GLuint program = glCreateProgram();
GLuint vShader = createShader(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fShader = createShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
glAttachShader(program, vShader);
glAttachShader(program, fShader);
glLinkProgram(program);
glUseProgram(program);
return program;
}
// Load a triangle to the video card
void initVertexBuffers(GLuint program)
{
float vertPositions[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
0.f, 0.5f
};
GLuint vertPosBuffer;
glGenBuffers(1, &vertPosBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer);
int amount = sizeof(vertPositions) / sizeof(vertPositions[0]);
glBufferData(GL_ARRAY_BUFFER, amount * sizeof(GLfloat),
vertPositions, GL_STATIC_DRAW);
GLint aPositionLocation = glGetAttribLocation(program, "aPosition");
glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(aPositionLocation);
}
SDL_AppResult SDL_Fail()
{
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
// Init the library, here we make a window so we only need the Video capabilities.
if (SDL_Init(SDL_INIT_VIDEO))
{
return SDL_Fail();
}
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable MULTISAMPLE
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); // can be 2, 4, 8 or 16
// Create a window
SDL_Window *window = SDL_CreateWindow("SDL3, OpenGL 2.1, C++", 400, 400,
SDL_WINDOW_OPENGL); // | SDL_WINDOW_RESIZABLE
if (!window)
{
return SDL_Fail();
}
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (!glContext)
{
return SDL_Fail();
}
if (!gladLoadGL())
{
std::cout << "Failed to load OpenGL functions" << std::endl;
return SDL_APP_FAILURE;
}
GLuint program = createShaderProgram();
initVertexBuffers(program);
b2Vec2 gravity(0.f, -9.8f);
world = new b2World(gravity);
float gx = world->GetGravity().x;
float gy = world->GetGravity().y;
std::cout << "gravity = (" << gx << ", " << gy << ")" << std::endl;
SDL_ShowWindow(window);
// Set up the application data
*appstate = new AppContext {
window,
glContext,
};
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
{
auto *app = (AppContext *)appstate;
switch (event->type)
{
case SDL_EVENT_QUIT:
{
app->appQuit = SDL_APP_SUCCESS;
break;
}
default:
{
break;
}
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
auto *app = (AppContext *)appstate;
glClearColor(0.188f, 0.22f, 0.255f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(app->window);
return app->appQuit;
}
void SDL_AppQuit(void *appstate)
{
auto *app = (AppContext *)appstate;
if (app)
{
SDL_GL_DestroyContext(app->glContext);
SDL_DestroyWindow(app->window);
delete app;
}
delete world;
SDL_Quit();
}
mkdir dist\win
cd dist
cmake -G "MinGW Makefiles" --fresh -S .. -B ..\dist\win -DSDL3_DIR=E:\libs\sdl3-desktop-prefix\lib\cmake\SDL3 -Dbox2d_DIR=E:\libs\box2d-2.4.2-prefix\lib\cmake\box2d
cd win
mingw32-make
app
In the future: