Skip to content

Commit 6931b9c

Browse files
committed
Add CMake project
Now implemented: - Build ImGui library (CMake's package); - Optionaly build opengl2_example and sdl_opengl2_example (ImGui_BUILD_EXAMPLES option); - Fix opengl2_example to build via Emscripten for web (wasm). CMake's ImGui package contains targets: - ImGui::Library; - ImGui::Demo; - ImGui::ImplGlfwGL2; - ImGui::ImplSdlGL2. Users can easy link ImGui::Impl<Xxx> libraries and use example binding implementation in custom projects. Tested with MinGW-w64, MSVC and Emscripten toolchains.
1 parent 5f4001a commit 6931b9c

File tree

6 files changed

+276
-58
lines changed

6 files changed

+276
-58
lines changed

CMakeLists.txt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
cmake_minimum_required(VERSION 3.3)
2+
3+
project(ImGui
4+
VERSION 1.60
5+
LANGUAGES C CXX)
6+
7+
option(${PROJECT_NAME}_BUILD_EXAMPLES OFF
8+
"Set to \"ON\" to build Dear ImGui examples")
9+
10+
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
11+
12+
if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
13+
set(CMAKE_DEBUG_POSTFIX _d)
14+
endif()
15+
16+
add_library(Library
17+
imgui_internal.h
18+
imgui.cpp
19+
imgui_draw.cpp)
20+
set_target_properties(Library PROPERTIES
21+
FRAMEWORK TRUE
22+
VERSION ${PROJECT_VERSION}
23+
PUBLIC_HEADER "imgui.h;imconfig.h"
24+
OUTPUT_NAME ${PROJECT_NAME_LOWER})
25+
target_include_directories(Library PUBLIC
26+
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
27+
$<INSTALL_INTERFACE:include>)
28+
29+
add_library(Demo
30+
imgui_demo.cpp)
31+
target_link_libraries(Demo PUBLIC Library)
32+
set_target_properties(Demo PROPERTIES
33+
OUTPUT_NAME ${PROJECT_NAME_LOWER}_demo)
34+
35+
include(GNUInstallDirs)
36+
37+
install(TARGETS Library Demo
38+
EXPORT ${PROJECT_NAME}Export
39+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
40+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
41+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
42+
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
43+
)
44+
45+
add_subdirectory(examples)
46+
47+
install(EXPORT ${PROJECT_NAME}Export NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME}Config.cmake DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME_LOWER}/cmake)

examples/CMakeLists.txt

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Search depend packages
2+
find_package(SDL2 QUIET)
3+
find_package(glfw3 QUIET)
4+
find_package(OpenGL QUIET)
5+
6+
if((glfw3_FOUND AND OpenGL_FOUND) OR EMSCRIPTEN)
7+
add_library(ImplGlfwGL2 opengl2_example/imgui_impl_glfw_gl2.cpp)
8+
set_target_properties(ImplGlfwGL2 PROPERTIES
9+
FRAMEWORK TRUE
10+
VERSION ${PROJECT_VERSION}
11+
PUBLIC_HEADER opengl2_example/imgui_impl_glfw_gl2.h
12+
OUTPUT_NAME ${PROJECT_NAME_LOWER}_impl_glfw_gl2)
13+
target_include_directories(ImplGlfwGL2 PUBLIC
14+
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/opengl2_example>
15+
$<INSTALL_INTERFACE:include>)
16+
target_link_libraries(ImplGlfwGL2 PUBLIC Library)
17+
if(EMSCRIPTEN)
18+
target_link_libraries(ImplGlfwGL2 PUBLIC glfw GL
19+
"-s LEGACY_GL_EMULATION=1" "-s GL_UNSAFE_OPTS=0" "-s USE_GLFW=3")
20+
else()
21+
target_link_libraries(ImplGlfwGL2 PUBLIC glfw OpenGL::GL)
22+
endif()
23+
install(TARGETS ImplGlfwGL2
24+
EXPORT ${PROJECT_NAME}Export
25+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
26+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
27+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
28+
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
29+
)
30+
endif()
31+
32+
if((SDL2_FOUND AND OpenGL_FOUND))
33+
add_library(ImplSdlGL2 sdl_opengl2_example/imgui_impl_sdl_gl2.cpp)
34+
set_target_properties(ImplSdlGL2 PROPERTIES
35+
FRAMEWORK TRUE
36+
VERSION ${PROJECT_VERSION}
37+
PUBLIC_HEADER sdl_opengl2_example/imgui_impl_sdl_gl2.h
38+
OUTPUT_NAME ${PROJECT_NAME_LOWER}_impl_sdl_gl2)
39+
target_include_directories(ImplSdlGL2 PUBLIC
40+
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/sdl_opengl2_example>
41+
$<INSTALL_INTERFACE:include>)
42+
target_link_libraries(ImplSdlGL2 PUBLIC Library SDL2::SDL2 SDL2::SDL2main OpenGL::GL)
43+
get_target_property(SDL2_INCLUDE_DIR SDL2::SDL2 INTERFACE_INCLUDE_DIRECTORIES)
44+
if(EXISTS ${SDL2_INCLUDE_DIR}/SDL2)
45+
target_include_directories(ImplSdlGL2 PUBLIC
46+
$<BUILD_INTERFACE:${SDL2_INCLUDE_DIR}/SDL2>
47+
$<INSTALL_INTERFACE:include/SDL2>)
48+
endif()
49+
install(TARGETS ImplSdlGL2
50+
EXPORT ${PROJECT_NAME}Export
51+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
52+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
53+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
54+
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
55+
)
56+
endif()
57+
58+
include(CMakePackageConfigHelpers)
59+
write_basic_package_version_file(
60+
${PROJECT_NAME}ConfigVersion.cmake
61+
VERSION ${PROJECT_VERSION}
62+
COMPATIBILITY AnyNewerVersion)
63+
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
64+
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME_LOWER}/cmake)
65+
export(EXPORT ${PROJECT_NAME}Export NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME}Config.cmake)
66+
67+
if(${PROJECT_NAME}_BUILD_EXAMPLES)
68+
set(${PROJECT_NAME}_DIR ${CMAKE_CURRENT_BINARY_DIR})
69+
find_package(${PROJECT_NAME} QUIET CONFIG NO_DEFAULT_PATH)
70+
if(TARGET ImplGlfwGL2 AND ${PROJECT_NAME}_FOUND)
71+
add_subdirectory(opengl2_example)
72+
add_dependencies(opengl2_example ImplGlfwGL2 Demo)
73+
endif()
74+
if(TARGET ImplSdlGL2 AND ${PROJECT_NAME}_FOUND)
75+
add_subdirectory(sdl_opengl2_example)
76+
add_dependencies(sdl_opengl2_example ImplSdlGL2 Demo)
77+
endif()
78+
endif()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
cmake_minimum_required(VERSION 3.3)
2+
3+
project(opengl2_example
4+
VERSION 1.60
5+
LANGUAGES CXX)
6+
7+
find_package(ImGui ${PROJECT_VERSION} REQUIRED CONFIG)
8+
9+
add_executable(${PROJECT_NAME} main.cpp)
10+
11+
target_link_libraries(${PROJECT_NAME} ImGui::ImplGlfwGL2 ImGui::Demo)
12+
13+
include(GNUInstallDirs)
14+
if(EMSCRIPTEN)
15+
set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY LINK_FLAGS "-s WASM=1")
16+
set_property(TARGET ${PROJECT_NAME} PROPERTY SUFFIX .html)
17+
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.html
18+
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.js
19+
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.wasm
20+
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME_LOWER}/examples)
21+
else()
22+
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME imgui_${PROJECT_NAME})
23+
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
24+
endif()

examples/opengl2_example/imgui_impl_glfw_gl2.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,14 @@ void ImGui_ImplGlfwGL2_RenderDrawData(ImDrawData* draw_data)
7575
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
7676
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
7777
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
78+
#ifndef __EMSCRIPTEN__
7879
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
80+
#else
81+
// Methods gl[Push/Pop]Attrib now not implemented in emscripten's library_gl.js
82+
GLboolean imgui_GL_ENABLE_BIT_was_enabled = glIsEnabled(GL_ENABLE_BIT);
83+
GLboolean imgui_GL_COLOR_BUFFER_BIT_was_enabled = glIsEnabled(GL_COLOR_BUFFER_BIT);
84+
GLboolean imgui_GL_TRANSFORM_BIT_was_enabled = glIsEnabled(GL_TRANSFORM_BIT);
85+
#endif
7986
glEnable(GL_BLEND);
8087
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
8188
glDisable(GL_CULL_FACE);
@@ -129,12 +136,30 @@ void ImGui_ImplGlfwGL2_RenderDrawData(ImDrawData* draw_data)
129136
glDisableClientState(GL_COLOR_ARRAY);
130137
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
131138
glDisableClientState(GL_VERTEX_ARRAY);
139+
#ifdef __EMSCRIPTEN__
140+
if(last_texture)
141+
#endif
132142
glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
133143
glMatrixMode(GL_MODELVIEW);
134144
glPopMatrix();
135145
glMatrixMode(GL_PROJECTION);
136146
glPopMatrix();
147+
#ifndef __EMSCRIPTEN__
137148
glPopAttrib();
149+
#else
150+
if(imgui_GL_ENABLE_BIT_was_enabled)
151+
glEnable(GL_ENABLE_BIT);
152+
else
153+
glDisable(GL_ENABLE_BIT);
154+
if(imgui_GL_COLOR_BUFFER_BIT_was_enabled)
155+
glEnable(GL_COLOR_BUFFER_BIT);
156+
else
157+
glDisable(GL_COLOR_BUFFER_BIT);
158+
if(imgui_GL_TRANSFORM_BIT_was_enabled)
159+
glEnable(GL_TRANSFORM_BIT);
160+
else
161+
glDisable(GL_TRANSFORM_BIT);
162+
#endif
138163
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
139164
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
140165
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
@@ -318,7 +343,9 @@ void ImGui_ImplGlfwGL2_NewFrame()
318343

319344
// Setup inputs
320345
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
346+
#ifndef __EMSCRIPTEN__ // Bug in emscripten library_glfw.js: GLFW_FOCUSED allways 0
321347
if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED))
348+
#endif
322349
{
323350
// Set OS mouse position if requested (only used when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
324351
if (io.WantSetMousePos)
@@ -332,10 +359,12 @@ void ImGui_ImplGlfwGL2_NewFrame()
332359
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
333360
}
334361
}
362+
#ifndef __EMSCRIPTEN__
335363
else
336364
{
337365
io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX);
338366
}
367+
#endif
339368

340369
for (int i = 0; i < 3; i++)
341370
{

examples/opengl2_example/main.cpp

Lines changed: 82 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,34 @@
1111
#include <stdio.h>
1212
#include <GLFW/glfw3.h>
1313

14+
#ifdef __EMSCRIPTEN__
15+
#include <emscripten.h>
16+
#endif
17+
1418
static void glfw_error_callback(int error, const char* description)
1519
{
1620
fprintf(stderr, "Error %d: %s\n", error, description);
1721
}
1822

23+
// Global variables nedded for step() method implementation
24+
static GLFWwindow* window;
25+
static bool show_demo_window;
26+
static bool show_another_window;
27+
static ImVec4 clear_color;
28+
29+
void step();
30+
1931
int main(int, char**)
2032
{
2133
// Setup window
2234
glfwSetErrorCallback(glfw_error_callback);
2335
if (!glfwInit())
2436
return 1;
25-
GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui GLFW+OpenGL2 example", NULL, NULL);
37+
window = glfwCreateWindow(1280, 720, "ImGui GLFW+OpenGL2 example", NULL, NULL);
2638
glfwMakeContextCurrent(window);
39+
#ifndef __EMSCRIPTEN__
2740
glfwSwapInterval(1); // Enable vsync
41+
#endif
2842

2943
// Setup ImGui binding
3044
ImGui::CreateContext();
@@ -51,68 +65,20 @@ int main(int, char**)
5165
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
5266
//IM_ASSERT(font != NULL);
5367

54-
bool show_demo_window = true;
55-
bool show_another_window = false;
56-
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
68+
// Default values
69+
show_demo_window = true;
70+
show_another_window = false;
71+
clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
5772

5873
// Main loop
74+
#ifdef __EMSCRIPTEN__
75+
emscripten_set_main_loop(step, 0, 1);
76+
#else
5977
while (!glfwWindowShouldClose(window))
6078
{
61-
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
62-
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
63-
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
64-
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
65-
glfwPollEvents();
66-
ImGui_ImplGlfwGL2_NewFrame();
67-
68-
// 1. Show a simple window.
69-
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
70-
{
71-
static float f = 0.0f;
72-
static int counter = 0;
73-
ImGui::Text("Hello, world!"); // Display some text (you can use a format string too)
74-
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
75-
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
76-
77-
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our windows open/close state
78-
ImGui::Checkbox("Another Window", &show_another_window);
79-
80-
if (ImGui::Button("Button")) // Buttons return true when clicked (NB: most widgets return true when edited/activated)
81-
counter++;
82-
ImGui::SameLine();
83-
ImGui::Text("counter = %d", counter);
84-
85-
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
86-
}
87-
88-
// 2. Show another simple window. In most cases you will use an explicit Begin/End pair to name your windows.
89-
if (show_another_window)
90-
{
91-
ImGui::Begin("Another Window", &show_another_window);
92-
ImGui::Text("Hello from another window!");
93-
if (ImGui::Button("Close Me"))
94-
show_another_window = false;
95-
ImGui::End();
96-
}
97-
98-
// 3. Show the ImGui demo window. Most of the sample code is in ImGui::ShowDemoWindow(). Read its code to learn more about Dear ImGui!
99-
if (show_demo_window)
100-
{
101-
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); // Normally user code doesn't need/want to call this because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
102-
ImGui::ShowDemoWindow(&show_demo_window);
103-
}
104-
105-
// Rendering
106-
int display_w, display_h;
107-
glfwGetFramebufferSize(window, &display_w, &display_h);
108-
glViewport(0, 0, display_w, display_h);
109-
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
110-
glClear(GL_COLOR_BUFFER_BIT);
111-
//glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound, but prefer using the GL3+ code.
112-
ImGui::Render();
113-
ImGui_ImplGlfwGL2_RenderDrawData(ImGui::GetDrawData());
114-
glfwSwapBuffers(window);
79+
step();
11580
}
81+
#endif
11682

11783
// Cleanup
11884
ImGui_ImplGlfwGL2_Shutdown();
@@ -121,3 +87,61 @@ int main(int, char**)
12187

12288
return 0;
12389
}
90+
91+
void step()
92+
{
93+
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
94+
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
95+
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
96+
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
97+
glfwPollEvents();
98+
ImGui_ImplGlfwGL2_NewFrame();
99+
100+
// 1. Show a simple window.
101+
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
102+
{
103+
static float f = 0.0f;
104+
static int counter = 0;
105+
ImGui::Text("Hello, world!"); // Display some text (you can use a format string too)
106+
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
107+
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
108+
109+
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our windows open/close state
110+
ImGui::Checkbox("Another Window", &show_another_window);
111+
112+
if (ImGui::Button("Button")) // Buttons return true when clicked (NB: most widgets return true when edited/activated)
113+
counter++;
114+
ImGui::SameLine();
115+
ImGui::Text("counter = %d", counter);
116+
117+
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
118+
}
119+
120+
// 2. Show another simple window. In most cases you will use an explicit Begin/End pair to name your windows.
121+
if (show_another_window)
122+
{
123+
ImGui::Begin("Another Window", &show_another_window);
124+
ImGui::Text("Hello from another window!");
125+
if (ImGui::Button("Close Me"))
126+
show_another_window = false;
127+
ImGui::End();
128+
}
129+
130+
// 3. Show the ImGui demo window. Most of the sample code is in ImGui::ShowDemoWindow(). Read its code to learn more about Dear ImGui!
131+
if (show_demo_window)
132+
{
133+
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); // Normally user code doesn't need/want to call this because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
134+
ImGui::ShowDemoWindow(&show_demo_window);
135+
}
136+
137+
// Rendering
138+
int display_w, display_h;
139+
glfwGetFramebufferSize(window, &display_w, &display_h);
140+
glViewport(0, 0, display_w, display_h);
141+
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
142+
glClear(GL_COLOR_BUFFER_BIT);
143+
//glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound, but prefer using the GL3+ code.
144+
ImGui::Render();
145+
ImGui_ImplGlfwGL2_RenderDrawData(ImGui::GetDrawData());
146+
glfwSwapBuffers(window);
147+
}

0 commit comments

Comments
 (0)