Dear ImGui, in short, for those who don’t know it yet, it creates immediate mode.
This means that you don’t create graphical interfaces from scratch with Dear ImGui. It uses a library that has graphical windows and overlays its widgets on that window to facilitate changes and configurations without having to leave the screen you are on.
To focus on implementing ImGui in SDL2, let’s reuse that basic code we used in this article from SDL2!
Let’s start!
Clone and copy the necessary files.
mkdir MyProject
cd MyProject
git clone https://github.com/ocornut/imgui
mkdir sdl2gui
.h
and .cpp
from the root of the cloned Dear ImGui repository to your project:cp imgui/*.h sdl2gui/
cp imgui/*.cpp sdl2gui/
impl
to SDL2:cp imgui/backends/imgui_impl_sdl2.* sdl2gui/
cp imgui/backends/imgui_impl_sdlrenderer2.* sdl2gui/
rm -rf imgui/
Let’s use the code made in the previous video: How to Install SDL2 on Windows and Linux to Create C/C++ Games and First Steps.
Note: Download the image available in the other article
vim main.cpp
:
#include <SDL2/SDL.h>
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window* window = SDL_CreateWindow(
"SDL2 It's Works!",
50, 30,
1280, 720,
SDL_WINDOW_SHOWN
);
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Surface * surface = SDL_LoadBMP("./sdl.bmp");
SDL_Texture * logo = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
SDL_Rect rect, rect2;
rect.x = 50;
rect.y = 20;
rect.w = surface->w;
rect.h = surface->h;
rect2.x = 800;
rect2.y = 20;
rect2.w = 300;
rect2.h = 300;
while(true){
SDL_Event event;
while(SDL_PollEvent(&event)){
if( event.type == SDL_QUIT ){
exit(0);
}else if( event.type == SDL_MOUSEBUTTONDOWN ){
rect2.x -= 20;
}
}
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
//SDL_RenderDrawRect(renderer, &rect2);
SDL_RenderFillRect(renderer, &rect2);
SDL_SetRenderDrawColor(renderer, 9, 20, 33, 255);
SDL_RenderCopy(renderer, logo, NULL, &rect);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(logo);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Compile the code: g++ main.cpp $(pkg-config --cflags --libs sdl2)
and run: ./a.out
To be able to move the Dear ImGui window in this specific example, let’s comment out the line that listens to the click event. To do this, comment leaving the lines like this:
while(SDL_PollEvent(&event)){
if( event.type == SDL_QUIT ){
exit(0);
}/*else if( event.type == SDL_MOUSEBUTTONDOWN ){
rect2.x -= 20;
}*/
}
#include "sdl2imgui/imgui.h"
#include "sdl2imgui/imgui_impl_sdl2.h"
#include "sdl2imgui/imgui_impl_sdlrenderer2.h"
After initializing the Window (
window
) and the Renderer (renderer
)
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
ImGui_ImplSDLRenderer2_Init(renderer);
ImGui_ImplSDL2_ProcessEvent(&event);
Inside the loop after the events.
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
Basic example only displays text similar to Hello World
ImGui::Begin("Hello, Dear ImGui with SDL2");
ImGui::Text("This is just a basic Hello World!");
ImGui::End();
ImGui::Render();
SDL_RenderClear
add the ImGui window display:ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData());
After the main loop at the end of the program execution.
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
The files in the sdl2gui/
folder must be compiled separately with the -c
parameter and saving as object: .o
to only generate the Assembly code without being executed by the Linker. Only later link them to the binary that contains our main
function.
Note the Makefile
:
Check
-I
for some headers forImpl
.
TARGET=a.out
CXX=g++ -std=c++11
DEBUG=-g
OPT=-O0
WARN=-Wall
SDL2=`pkg-config --cflags --libs sdl2`
INCSDL2=-I /usr/include/SDL2
CXXFLAGS=$(DEBUG) $(OPT) $(WARN) $(SDL2)
LD=g++
OBJS= main.o imgui.o imgui_draw.o imgui_impl_sdl2.o imgui_impl_sdlrenderer2.o imgui_tables.o imgui_widgets.o
all: $(OBJS)
$(LD) -o $(TARGET) $(OBJS) $(CXXFLAGS)
# @rm *.o
@./$(TARGET)
main.o: main.cpp
$(CXX) -c $(CXXFLAGS) main.cpp -o main.o
imgui.o: sdl2imgui/imgui.cpp
$(CXX) -c $(DEBUG) $(OPT) sdl2imgui/imgui.cpp -o imgui.o
imgui_draw.o: sdl2imgui/imgui_draw.cpp
$(CXX) -c $(DEBUG) $(OPT) sdl2imgui/imgui_draw.cpp -o imgui_draw.o
imgui_impl_sdl2.o: sdl2imgui/imgui_impl_sdl2.cpp
$(CXX) $(INCSDL2) -c $(DEBUG) $(OPT) sdl2imgui/imgui_impl_sdl2.cpp -o imgui_impl_sdl2.o
imgui_impl_sdlrenderer2.o: sdl2imgui/imgui_impl_sdlrenderer2.cpp
$(CXX) $(INCSDL2) -c $(DEBUG) $(OPT) sdl2imgui/imgui_impl_sdlrenderer2.cpp -o imgui_impl_sdlrenderer2.o
imgui_tables.o: sdl2imgui/imgui_tables.cpp
$(CXX) -c $(DEBUG) $(OPT) sdl2imgui/imgui_tables.cpp -o imgui_tables.o
imgui_widgets.o: sdl2imgui/imgui_widgets.cpp
$(CXX) -c $(DEBUG) $(OPT) sdl2imgui/imgui_widgets.cpp -o imgui_widgets.o
Then just run the make
command, in this case the .o
objects will be automatically deleted by the Makefile
in addition to the code also being executed by the Makefile
Outside the main loop.
float imcolor[4] = { (float)0 / 255, (float)255 / 255, (float)64 / 255, (float)64 / 255 };
ImGui::ColorEdit4("Change BG SDL2", imcolor);
SDL_SetRenderDrawColor(renderer, 9, 20, 33, 255);
with the line below:SDL_SetRenderDrawColor(renderer, imcolor[0] * 255, imcolor[1] * 255, imcolor[2] * 255, imcolor[3] * 255);
Multiplying by 255 is essential for the changes made by ImGui to take effect!
Then just recompile and test!