├── example ├── test.png ├── CMakeLists.txt ├── test.cpp └── test_advanced.cpp ├── .gitmodules ├── .gitignore ├── LICENSE ├── src ├── imgui_app.h └── imgui_app.cpp ├── README.md └── Makefile /example/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pplux/imgui-app/HEAD/example/test.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "imgui"] 2 | path = imgui 3 | url = https://github.com/ocornut/imgui.git 4 | [submodule "sokol"] 5 | path = sokol 6 | url = https://github.com/pplux/sokol.git 7 | branch = opengl-version-select 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated 2 | header.txt 3 | *.tgz 4 | *.zip 5 | 6 | # Prerequisites 7 | *.d 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | *.smod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | *.lib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 PpluX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(imgui-app) 3 | include_directories(..) 4 | 5 | set(CMAKE_C_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD 11) 7 | 8 | add_executable(test ../imgui_app.cpp test.cpp) 9 | add_executable(test_advanced ../imgui_app.cpp test_advanced.cpp) 10 | 11 | if (APPLE) 12 | add_compile_definitions(SOKOL_METAL) 13 | target_compile_options(test PRIVATE -x objective-c++) 14 | target_link_libraries(test PUBLIC 15 | "-framework QuartzCore" 16 | "-framework Cocoa" 17 | "-framework MetalKit" 18 | "-framework Metal") 19 | target_compile_options(test_advanced PRIVATE -x objective-c++) 20 | target_link_libraries(test_advanced PUBLIC 21 | "-framework QuartzCore" 22 | "-framework Cocoa" 23 | "-framework MetalKit" 24 | "-framework Metal") 25 | elseif (CMAKE_SYSTEM_NAME STREQUAL Linux) 26 | target_link_libraries(test PRIVATE X11 Xi Xcursor dl m GL) 27 | target_compile_definitions(test PRIVATE SOKOL_GLCORE33) 28 | 29 | target_link_libraries(test_advanced PRIVATE X11 Xi Xcursor dl m GL) 30 | target_compile_definitions(test_advanced PRIVATE SOKOL_GLCORE33) 31 | else() 32 | add_compile_definitions(SOKOL_GLCORE33) 33 | endif() 34 | 35 | -------------------------------------------------------------------------------- /src/imgui_app.h: -------------------------------------------------------------------------------- 1 | // Amalgamated version of : 2 | // - imgui 3 | // - sokol_[app, gfx, time, imgui, ...] for multiplatform rendering 4 | // 5 | // ---------------------------------------------------------------------------- 6 | 7 | #include 8 | 9 | // Starts the graphical context, and runs the UI. This function will not return 10 | // until the app finishes. 11 | void imgui_app( 12 | std::function &&frame_func, 13 | const char *window_title = "IMGUI APP", 14 | int width = 800, 15 | int height = 600, 16 | int ImGuiConfigFlags = 0 17 | ); 18 | 19 | 20 | typedef void* ImTextureID; 21 | ImTextureID imgui_app_loadImageRGBA8(const void *data, int width, int height); 22 | void imgui_app_destroyImage(ImTextureID id); 23 | 24 | // Allows to configure sokol manually/ 25 | // - Remember to call previous event function if you decide to override the event callback 26 | // - The passed function must return the Imgui config flags (default 0) 27 | extern "C" { 28 | struct sapp_desc; 29 | } 30 | void imgui_app(std::function &&frame_func, void (*config_sokol)(sapp_desc *), int ImGuiConfigFlags = 0); 31 | 32 | // 33 | // ---------------------------------------------------------------------------- 34 | -------------------------------------------------------------------------------- /example/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../imgui.h" // > imgui headers (+imgui_app definitions) 3 | 4 | char buf[128]; 5 | float f; 6 | ImTextureID tex = 0; 7 | 8 | void frame() { 9 | ImGui::Text("Hello, world %d", 123); 10 | if (ImGui::Button("Button")) { 11 | buf[0] = 0; 12 | f = 1.0f; 13 | } 14 | ImGui::InputText("string", buf, IM_ARRAYSIZE(buf)); 15 | ImGui::SliderFloat("float", &f, 0.0f, 1.0f); 16 | if (tex == 0) { 17 | unsigned char buffer[32*32*4]; 18 | for(int i = 0; i < 32*32; ++i) { 19 | buffer[i*4+0] = std::rand()%255; 20 | buffer[i*4+1] = std::rand()%255; 21 | buffer[i*4+2] = std::rand()%255; 22 | buffer[i*4+3] = 255; 23 | } 24 | tex = imgui_app_loadImageRGBA8(buffer, 32, 32); 25 | } 26 | ImGui::Image(tex, {256, 256}); 27 | ImGui::ShowDemoWindow(); 28 | } 29 | 30 | 31 | int main(int, char **) { 32 | // do any initialization 33 | buf[0] = 0; 34 | f = 0.0f; 35 | // when ready start the UI (this will not return until the app finishes) 36 | int imguiConfigFlags = 0; 37 | #ifdef IMGUI_HAS_DOCK 38 | imguiConfigFlags |= ImGuiConfigFlags_DockingEnable; 39 | #endif 40 | imgui_app(frame, "IMGUI_APP", 800, 600, imguiConfigFlags); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /example/test_advanced.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../imgui.h" // > imgui headers (+imgui_app definitions) 3 | #include "../sokol.h" // > for advanced sokol handling (advanced) 4 | 5 | char buf[128]; 6 | float f; 7 | ImTextureID tex = 0; 8 | 9 | void frame() { 10 | ImGui::Text("Hello, world %d", 123); 11 | if (ImGui::Button("Button")) { 12 | buf[0] = 0; 13 | f = 1.0f; 14 | } 15 | ImGui::InputText("string", buf, IM_ARRAYSIZE(buf)); 16 | ImGui::SliderFloat("float", &f, 0.0f, 1.0f); 17 | if (tex == 0) { 18 | unsigned char buffer[32*32*4]; 19 | for(int i = 0; i < 32*32; ++i) { 20 | buffer[i*4+0] = std::rand()%255; 21 | buffer[i*4+1] = std::rand()%255; 22 | buffer[i*4+2] = std::rand()%255; 23 | buffer[i*4+3] = 255; 24 | } 25 | tex = imgui_app_loadImageRGBA8(buffer, 32, 32); 26 | } 27 | ImGui::Image(tex, {256, 256}); 28 | ImGui::ShowDemoWindow(); 29 | } 30 | 31 | 32 | int main(int, char **) { 33 | // do any initialization 34 | buf[0] = 0; 35 | f = 0.0f; 36 | 37 | // when ready start the UI (this will not return until the app finishes) 38 | int imgui_flags = 0; 39 | #ifdef IMGUI_HAS_DOCK 40 | imgui_flags = ImGuiConfigFlags_DockingEnable; 41 | #endif 42 | 43 | imgui_app(frame, [](sapp_desc *desc) { 44 | desc->gl_major_version = 4; 45 | desc->gl_minor_version = 6; 46 | desc->high_dpi = true; 47 | desc->width = 800; 48 | desc->height = 600; 49 | desc->window_title = "IMGUI_APP(advanced)"; 50 | desc->high_dpi = false; 51 | }, imgui_flags ); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imgui-app 2 | 3 | Imgui-app is an amalgamation of two amazing projects [Dear Imgui](https://github.com/ocornut/imgui) and [Sokol libraries](https://github.com/floooh/sokol) into **two** files to make it very easy to start working with imgui. It might be useful when you need to do some UI quickly for a project but do not want to care that much how to get imgui up and running (imgui compilation, backend rendering, window handling, ...). 4 | 5 | ![test.png](https://github.com/pplux/imgui-app/blob/main/example/test.png?raw=true) 6 | 7 | # Howto 8 | 9 | To start using imgui-app you need to add these two files to your project: 10 | * [imgui.h](https://github.com/pplux/imgui-app/blob/main/imgui.h) 11 | * [imgui_app.cpp](https://github.com/pplux/imgui-app/blob/main/imgui_app.cpp) 12 | 13 | Once you are ready to display the UI, just call `imgui_app`, see the [example](https://github.com/pplux/imgui-app/blob/main/example/test.cpp). 14 | 15 | ```cpp 16 | #include "imgui.h" 17 | 18 | void frame() { 19 | ImGui::Text("Hello, world %d", 123); 20 | ImGui::ShowDemoWindow(); 21 | } 22 | 23 | int main(int, char **) { 24 | // when ready, call the UI: 25 | imgui_app(frame, "IMGUI_APP", 800, 600); 26 | // execution continues when window is closed 27 | return 0; 28 | } 29 | ``` 30 | 31 | Finally, make sure to select the proper sokol render backend, by compiling your project with `-DSOKOL_GLCORE33` or any of the [available backends](https://github.com/floooh/sokol/blob/master/sokol_gfx.h#L18-L24). 32 | 33 | # Optional files: 34 | This files are **not required** to use imgui-app, but if you need access to more advanced components from imgui or sokol here they are: 35 | * [imgui_internal.h](https://github.com/pplux/imgui-app/blob/main/imgui_internal.h). Might be needed if you need access to advanced rendering, or you us a 3rd party widget that requires it. 36 | * [sokol.h](https://github.com/pplux/imgui-app/blob/main/sokol.h), amalgamation of sokol_app and sokol_time. You might require this if you want to initialize the window manually and provide callbacks for sokol events (input, drag and drop, etc...). 37 | 38 | # Notes: 39 | * Try not to modify the files `imgui.h`, `imgui_app.cpp`, or `imgui_internal.h` they are generated from the original sources by the `Makefile` of this project 40 | * We chose to use imgui.h for the headers to make the project compatible with other exisiting imgui code. 41 | * imgui_app.cpp is **BIG**, it is the result of including in one file imgui, sokol, and all the dependencies. Try not to compile every time on your project :) 42 | * The *amalgamation* idea comes from [Sqlite amalgamation](https://www.sqlite.org/amalgamation.html) 43 | 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CPP = sokol/sokol_app.h 2 | CPP += sokol/sokol_gfx.h 3 | CPP += sokol/sokol_time.h 4 | CPP += sokol/sokol_glue.h 5 | CPP += imgui/imgui_draw.cpp 6 | CPP += imgui/imgui_tables.cpp 7 | CPP += imgui/imgui_widgets.cpp 8 | CPP += imgui/imgui_demo.cpp 9 | CPP += imgui/imgui.cpp 10 | CPP += sokol/util/sokol_imgui.h 11 | 12 | VERSION=$(shell cd imgui; git describe --tags) 13 | TGZ=imgui_app_$(VERSION).tgz 14 | ZIP=imgui_app_$(VERSION).zip 15 | 16 | all: $(TGZ) $(ZIP) 17 | 18 | $(TGZ): imgui.h imgui_app.cpp imgui_internal.h sokol.h README.md 19 | @echo "Creating $(TGZ)" 20 | @tar -cvzf $@ $^ 21 | 22 | $(ZIP): imgui.h imgui_app.cpp imgui_internal.h sokol.h README.md 23 | @echo "Creating $(TGZ)" 24 | @zip $@ $^ 25 | 26 | .PHONY: header.txt clean 27 | 28 | header.txt: imgui sokol 29 | @echo "// ----------------------------------------------------------------------------" > $@ 30 | @echo "// File generated by imgui-app. By Jose L. Hidalgo (PpluX) @ 2021" >> $@ 31 | @echo "// ----------------------------------------------------------------------------" >> $@ 32 | @(cd imgui; git log --pretty="// imgui:%n// %H(%ad)" -1 >> ../header.txt ) 33 | @(cd sokol; git log --pretty="// sokol:%n// %H(%ad)" -1 >> ../header.txt ) 34 | @echo "// ----------------------------------------------------------------------------" >> $@ 35 | 36 | imgui.h: src/imgui_app.h imgui/imgui.h header.txt 37 | @cat header.txt > $@ 38 | @cat src/imgui_app.h >> $@ 39 | @cat imgui/imgui.h >> $@ 40 | @sed -e 's/\(#include "imconfig.h"\)/\/\/\1/' -i $@ 41 | 42 | imgui_app.cpp: header.txt $(CPP) src/imgui_app.cpp 43 | @cat header.txt > $@ 44 | @echo "#define SOKOL_IMPL\n#define SOKOL_NO_ENTRY\n\n" >> $@ 45 | @echo "#define SOKOL_IMPL\n#define SOKOL_WIN32_FORCE_MAIN\n\n" >> $@ 46 | @cat $(CPP) >> $@ 47 | # imgui_internal, only replace the first time, remove the other includes 48 | @sed -e '0,/#include "imgui_internal.h"/{ /#include "imgui_internal.h"/{' -e 'r imgui/imgui_internal.h' -e 'd' -e '}}' -i $@ 49 | @sed -e 's/#include "imgui_internal.h"//' -i $@ 50 | # Other dependencies: 51 | @sed -e '/#include "imstb_textedit.h"/ {' -e 'r imgui/imstb_textedit.h' -e 'd' -e '}' -i $@ 52 | @sed -e '/#include "imstb_rectpack.h"/ {' -e 'r imgui/imstb_rectpack.h' -e 'd' -e '}' -i $@ 53 | @sed -e '/#include "imstb_truetype.h"/ {' -e 'r imgui/imstb_truetype.h' -e 'd' -e '}' -i $@ 54 | @cat src/imgui_app.cpp >> $@ 55 | 56 | imgui_internal.h: header.txt imgui/imgui_internal.h 57 | @cat $+ > $@ 58 | @sed -e '/#include "imstb_textedit.h"/ {' -e 'r imgui/imstb_textedit.h' -e 'd' -e '}' -i $@ 59 | @sed -e '/#include "imstb_rectpack.h"/ {' -e 'r imgui/imstb_rectpack.h' -e 'd' -e '}' -i $@ 60 | @sed -e '/#include "imstb_truetype.h"/ {' -e 'r imgui/imstb_truetype.h' -e 'd' -e '}' -i $@ 61 | 62 | sokol.h: header.txt sokol/sokol_app.h sokol/sokol_time.h 63 | @cat $+ > $@ 64 | 65 | clean: 66 | @rm -f imgui_app.cpp imgui.h imgui_app.tgz header.txt 67 | -------------------------------------------------------------------------------- /src/imgui_app.cpp: -------------------------------------------------------------------------------- 1 | // imgui_app by PpluX (Jose L. Hidalgo) 2021 2 | 3 | static struct { 4 | uint64_t laptime; 5 | sg_pass_action pass_action; 6 | std::function frame_fn; 7 | ImGuiConfigFlags config_flags; 8 | } state = {}; 9 | 10 | static void init(void) { 11 | sg_desc desc = {}; 12 | desc.context = sapp_sgcontext(); 13 | sg_setup(&desc); 14 | stm_setup(); 15 | simgui_desc_t desc_imgui = {}; 16 | simgui_setup(&desc_imgui); 17 | 18 | ImGui::GetIO().ConfigFlags = state.config_flags; 19 | 20 | state.pass_action.colors[0].action = SG_ACTION_CLEAR; 21 | state.pass_action.colors[0].value.r = 0.12f; 22 | state.pass_action.colors[0].value.g = 0.12f; 23 | state.pass_action.colors[0].value.b = 0.12f; 24 | state.pass_action.colors[0].value.a = 1.0f; 25 | } 26 | 27 | static void frame(void) { 28 | const simgui_frame_desc_t new_frame = { 29 | sapp_width(), 30 | sapp_height(), 31 | stm_sec(stm_round_to_common_refresh_rate(stm_laptime(&state.laptime))), 32 | sapp_dpi_scale() 33 | }; 34 | simgui_new_frame(new_frame); 35 | state.frame_fn(); 36 | sg_begin_default_pass(&state.pass_action, new_frame.width, new_frame.height); 37 | simgui_render(); 38 | sg_end_pass(); 39 | sg_commit(); 40 | } 41 | 42 | static void cleanup(void) { 43 | simgui_shutdown(); 44 | sg_shutdown(); 45 | } 46 | 47 | static void event(const sapp_event* ev) { 48 | simgui_handle_event(ev); 49 | } 50 | 51 | void imgui_app(std::function &&frame_func, void (*config_sokol)(sapp_desc *), int config) { 52 | state.frame_fn = std::move(frame_func); 53 | state.config_flags = config; 54 | sapp_desc desc = {}; 55 | desc.init_cb = init; 56 | desc.frame_cb = frame; 57 | desc.cleanup_cb = cleanup; 58 | desc.event_cb = event; 59 | desc.window_title = "IMGUI APP"; 60 | desc.width = 800; 61 | desc.height = 600; 62 | config_sokol(&desc); 63 | sapp_run(&desc); 64 | } 65 | 66 | void imgui_app(std::function &&frame_func, const char *window_title, int width, int height, int config) { 67 | state.frame_fn = std::move(frame_func); 68 | state.config_flags = config; 69 | sapp_desc desc = {}; 70 | desc.init_cb = init; 71 | desc.frame_cb = frame; 72 | desc.cleanup_cb = cleanup; 73 | desc.event_cb = event; 74 | desc.window_title = window_title; 75 | desc.width = width; 76 | desc.height = height; 77 | sapp_run(&desc); 78 | } 79 | 80 | ImTextureID imgui_app_loadImageRGBA8(const void *data, int width, int height) { 81 | sg_image_desc img_desc; 82 | memset(&img_desc, 0, sizeof(img_desc)); 83 | img_desc.width = width; 84 | img_desc.height = height; 85 | img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; 86 | img_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; 87 | img_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; 88 | img_desc.min_filter = SG_FILTER_LINEAR; 89 | img_desc.mag_filter = SG_FILTER_LINEAR; 90 | img_desc.data.subimage[0][0].ptr = data; 91 | img_desc.data.subimage[0][0].size = (size_t)(width * height) * 4; 92 | sg_image img = sg_make_image(&img_desc); 93 | return (ImTextureID)(size_t)img.id; 94 | } 95 | 96 | void imgui_app_destroyImage(ImTextureID id) { 97 | sg_image img = {(uint32_t)(size_t)id}; 98 | sg_destroy_image(img); 99 | } 100 | --------------------------------------------------------------------------------