├── .clang-format ├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── compile_flags.txt ├── lib ├── imgui │ ├── .gitignore │ ├── LICENSE.txt │ ├── backends │ │ ├── imgui_impl_opengl3.cpp │ │ ├── imgui_impl_opengl3.h │ │ ├── imgui_impl_opengl3_loader.h │ │ ├── imgui_impl_sdl2.cpp │ │ └── imgui_impl_sdl2.h │ ├── docs │ │ ├── BACKENDS.md │ │ ├── CHANGELOG.txt │ │ ├── CONTRIBUTING.md │ │ ├── EXAMPLES.md │ │ ├── FAQ.md │ │ ├── FONTS.md │ │ ├── README.md │ │ └── TODO.txt │ ├── examples │ │ ├── README.txt │ │ └── example_sdl2_opengl3 │ │ │ ├── Makefile │ │ │ ├── Makefile.emscripten │ │ │ ├── README.md │ │ │ ├── build_win32.bat │ │ │ ├── example_sdl2_opengl3.vcxproj │ │ │ ├── example_sdl2_opengl3.vcxproj.filters │ │ │ └── main.cpp │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_internal.h │ ├── imgui_tables.cpp │ ├── imgui_widgets.cpp │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ ├── imstb_truetype.h │ └── misc │ │ ├── README.txt │ │ ├── debuggers │ │ ├── README.txt │ │ ├── imgui.gdb │ │ ├── imgui.natstepfilter │ │ └── imgui.natvis │ │ ├── fonts │ │ └── binary_to_compressed_c.cpp │ │ └── freetype │ │ ├── README.md │ │ ├── imgui_freetype.cpp │ │ └── imgui_freetype.h ├── portable-file-dialogs │ ├── COPYING │ ├── portable-file-dialogs-impl.h │ ├── portable-file-dialogs.cpp │ └── portable-file-dialogs.hpp └── stb │ ├── LICENSE │ ├── stb_image.h │ └── stb_image_write.h ├── misc ├── fonts │ ├── MaterialIcons-Regular.ttf │ └── OpenSans-Regular.ttf ├── icon │ ├── icon.ico │ ├── icon.png │ └── icon.rc └── readme │ ├── ayin.png │ └── honest-work.jpg └── src ├── Application.cpp ├── Application.hpp ├── Commands.cpp ├── Commands.hpp ├── Image.cpp ├── Image.hpp ├── ImageFilter.cpp ├── ImageFilter.hpp ├── Main.cpp ├── Photo.cpp ├── Photo.hpp ├── fonts ├── MaterialIcons.hpp ├── MaterialIconsFont.hpp └── OpenSansFont.hpp └── utils └── win32.hpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | TabWidth: 4 4 | IndentWidth: 4 5 | UseTab: Always 6 | LineEnding: LF 7 | ColumnLimit: 120 8 | IndentAccessModifiers: false 9 | AccessModifierOffset: -4 10 | ... 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = 4 9 | indent_style = tab 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build files 2 | target/ 3 | 4 | # Visual Studio Code 5 | .vscode/ 6 | 7 | # JetBrains IDE 8 | .idea/ 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | mode = debug 2 | 3 | CXXFLAGS = -Ilib/imgui -Ilib/imgui/backends -Ilib/imgui/misc/freetype -Ilib/portable-file-dialogs -Ilib/stb 4 | CXXFLAGS += -std=c++17 -Wall -Wextra -Wno-missing-field-initializers -Wno-missing-braces 5 | 6 | ifeq ($(mode),debug) 7 | BUILDDIR = target/debug 8 | CXXFLAGS += -O1 9 | else 10 | ifeq ($(mode),release) 11 | BUILDDIR = target/release 12 | CXXFLAGS += -O3 -DNDEBUG 13 | else 14 | ifeq ($(mode),dev-release) 15 | BUILDDIR = target/dev-release 16 | CXXFLAGS += -g -O2 17 | else 18 | $(error unknown mode: $(mode)) 19 | endif 20 | endif 21 | endif 22 | 23 | exe := $(BUILDDIR)/ayin 24 | 25 | INTERNAL_SOURCES = src/Application.cpp src/Commands.cpp src/Image.cpp src/ImageFilter.cpp src/Photo.cpp src/Main.cpp 26 | # for `make format` 27 | INTERNAL_HEADERS = src/Application.hpp src/Commands.hpp src/Image.hpp src/ImageFilter.hpp src/Photo.hpp src/utils/win32.hpp 28 | 29 | EXTERNAL_SOURCES = lib/imgui/imgui.cpp lib/imgui/imgui_draw.cpp lib/imgui/imgui_tables.cpp lib/imgui/imgui_widgets.cpp # ImGui 30 | EXTERNAL_SOURCES += lib/imgui/misc/freetype/imgui_freetype.cpp # ImGui FreeType 31 | EXTERNAL_SOURCES += lib/imgui/backends/imgui_impl_sdl2.cpp lib/imgui/backends/imgui_impl_opengl3.cpp # ImGui (SDL2 + OpenGL3) Backend 32 | EXTERNAL_SOURCES += lib/portable-file-dialogs/portable-file-dialogs.cpp # Portable File Dialogs 33 | 34 | INTERNAL_OBJECTS = $(addprefix $(BUILDDIR)/internal/, $(addsuffix .o, $(basename $(notdir $(INTERNAL_SOURCES))))) 35 | EXTERNAL_OBJECTS = $(addprefix $(BUILDDIR)/external/, $(addsuffix .o, $(basename $(notdir $(EXTERNAL_SOURCES))))) 36 | 37 | ifeq ($(OS),Windows_NT) 38 | exe := $(exe).exe 39 | LDFLAGS += -mwindows -lopengl32 -luuid -ldwmapi 40 | ifeq ($(mode),debug) 41 | LDFLAGS += -mconsole `pkg-config --libs sdl2 freetype2` 42 | else 43 | LDFLAGS += -static `pkg-config --static --libs sdl2 freetype2` 44 | endif 45 | CXXFLAGS += `pkg-config --cflags sdl2 freetype2` 46 | INTERNAL_OBJECTS += $(BUILDDIR)/internal/icon.o 47 | else 48 | ifeq ($(shell uname),Linux) 49 | LDFLAGS += -lGL `pkg-config --libs sdl2 freetype2` 50 | CXXFLAGS += `pkg-config --cflags sdl2 freetype2` 51 | else 52 | $(error unsupported platform: $(mode)) 53 | endif 54 | endif 55 | 56 | $(exe): $(INTERNAL_OBJECTS) $(EXTERNAL_OBJECTS) 57 | $(CXX) -o $@ $^ $(LDFLAGS) 58 | 59 | $(BUILDDIR): 60 | mkdir -p $(BUILDDIR)/internal $(BUILDDIR)/external 61 | 62 | $(BUILDDIR)/internal/%.o:src/%.cpp|$(BUILDDIR) 63 | $(CXX) -c -o $@ $< $(CXXFLAGS) 64 | 65 | ifeq ($(OS),Windows_NT) 66 | $(BUILDDIR)/internal/icon.o:misc/icon/icon.rc 67 | windres $^ $@ 68 | endif 69 | 70 | $(BUILDDIR)/external/%.o:lib/portable-file-dialogs/%.cpp 71 | $(CXX) -c -o $@ $< $(CXXFLAGS) 72 | 73 | $(BUILDDIR)/external/%.o:lib/imgui/%.cpp 74 | $(CXX) -c -o $@ $< $(CXXFLAGS) 75 | 76 | $(BUILDDIR)/external/%.o:lib/imgui/backends/%.cpp 77 | $(CXX) -c -o $@ $< $(CXXFLAGS) 78 | 79 | $(BUILDDIR)/external/%.o:lib/imgui/misc/freetype/%.cpp 80 | $(CXX) -c -o $@ $< $(CXXFLAGS) 81 | 82 | .PHONY: all format clean clean-ayin clean-extern 83 | 84 | all: $(BUILDDIR) $(exe) 85 | 86 | format: 87 | clang-format -i $(INTERNAL_SOURCES) $(INTERNAL_HEADERS) 88 | 89 | clean: clean-ayin clean-extern 90 | 91 | clean-ayin: 92 | $(RM) $(exe) $(INTERNAL_OBJECTS) 93 | 94 | clean-extern: 95 | $(RM) $(exe) $(EXTERNAL_OBJECTS) 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ayin – Photo Editing Software 2 | 3 | ![Ayin interface showcase](./misc/readme/ayin.png) 4 | 5 | Ayin (عَيْن, [\[ʕajn\]](https://en.wikipedia.org/wiki/Help:IPA/Arabic)), Arabic for "eye", is a free and open-source photo editing software I developed in part of a contest in my first year at FCAI-CU and got 1st place in the solo competition. Ayin is very simplistic compared to big corporate software™ but it has some cool [features](#features) and gets the job done in terms of functionality implemented. A pre-compiled version for Windows is available in the [releases](https://github.com/faresbakhit/ayin/releases/) page, but I urge you to compile it yourself and hack your own version of Ayin with your own patches. 6 | 7 | ![Photo of a framer with the text 'it ain't much' on top, and the text 'but it's honest work' on the bottom.](./misc/readme/honest-work.jpg) 8 | 9 | ## Features 10 | 11 | - [x] 21+ Filters 12 | - [x] Multiple image tabs 13 | - [x] Undo and redo stack 14 | - [x] Follow device theme 15 | 16 | ## Build on Windows/MinGW-w64 17 | 18 | 1. Install [MSYS2](https://www.msys2.org/) 19 | 2. Open `MSYS2 UCRT64` 20 | 3. Install dependencies: 21 | ``` 22 | $ pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-freetype 23 | ``` 24 | 5. Build 25 | ``` 26 | $ cd /path/to/ayin/ 27 | $ make mode=release 28 | $ ./target/release/ayin.exe 29 | ``` 30 | 31 | ### Configure MSYS2 UCRT64 for VSCode 32 | 33 | 1. Ctrl+Shift+P 34 | 2. Preferences: Open User Settings (JSON) 35 | 3. Copy this to of your `settings.json` 36 | ```jsonc 37 | { 38 | // ... 39 | "terminal.integrated.profiles.windows": { 40 | "MSYS2 UCRT": { 41 | "path": "cmd.exe", 42 | "args": [ 43 | "/c", 44 | "C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64" 45 | ] 46 | } 47 | } 48 | // ... 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /compile_flags.txt: -------------------------------------------------------------------------------- 1 | -Ilib/imgui 2 | -Ilib/imgui/backends 3 | -Ilib/imgui/misc/freetype 4 | -Ilib/portable-file-dialogs 5 | -Ilib/stb 6 | -------------------------------------------------------------------------------- /lib/imgui/.gitignore: -------------------------------------------------------------------------------- 1 | ## OSX artifacts 2 | .DS_Store 3 | 4 | ## Dear ImGui artifacts 5 | imgui.ini 6 | 7 | ## General build artifacts 8 | *.o 9 | *.obj 10 | *.exe 11 | examples/*/Debug/* 12 | examples/*/Release/* 13 | examples/*/x64/* 14 | 15 | ## Visual Studio artifacts 16 | .vs 17 | ipch 18 | *.opensdf 19 | *.log 20 | *.pdb 21 | *.ilk 22 | *.user 23 | *.sdf 24 | *.suo 25 | *.VC.db 26 | *.VC.VC.opendb 27 | 28 | ## Getting files created in JSON/Schemas/Catalog/ from a VS2022 update 29 | JSON/ 30 | 31 | ## Commonly used CMake directories 32 | build*/ 33 | 34 | ## Xcode artifacts 35 | project.xcworkspace 36 | xcuserdata 37 | 38 | ## Emscripten artifacts 39 | examples/*.o.tmp 40 | examples/*.out.js 41 | examples/*.out.wasm 42 | examples/example_glfw_opengl3/web/* 43 | examples/example_sdl2_opengl3/web/* 44 | examples/example_emscripten_wgpu/web/* 45 | 46 | ## JetBrains IDE artifacts 47 | .idea 48 | cmake-build-* 49 | 50 | ## Unix executables from our example Makefiles 51 | examples/example_glfw_metal/example_glfw_metal 52 | examples/example_glfw_opengl2/example_glfw_opengl2 53 | examples/example_glfw_opengl3/example_glfw_opengl3 54 | examples/example_glut_opengl2/example_glut_opengl2 55 | examples/example_null/example_null 56 | examples/example_sdl2_metal/example_sdl2_metal 57 | examples/example_sdl2_opengl2/example_sdl2_opengl2 58 | examples/example_sdl2_opengl3/example_sdl2_opengl3 59 | examples/example_sdl2_sdlrenderer/example_sdl2_sdlrenderer 60 | -------------------------------------------------------------------------------- /lib/imgui/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2024 Omar Cornut 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 | -------------------------------------------------------------------------------- /lib/imgui/backends/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline 2 | // - Desktop GL: 2.x 3.x 4.x 3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) 4 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) 5 | 6 | // Implemented features: 7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! 8 | // [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). 9 | 10 | // About WebGL/ES: 11 | // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. 12 | // - This is done automatically on iOS, Android and Emscripten targets. 13 | // - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h. 14 | 15 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 16 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 17 | // Learn about Dear ImGui: 18 | // - FAQ https://dearimgui.com/faq 19 | // - Getting Started https://dearimgui.com/getting-started 20 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). 21 | // - Introduction, links and more at the top of imgui.cpp 22 | 23 | // About GLSL version: 24 | // The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string. 25 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" 26 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. 27 | 28 | #pragma once 29 | #include "imgui.h" // IMGUI_IMPL_API 30 | #ifndef IMGUI_DISABLE 31 | 32 | // Backend API 33 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr); 34 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 35 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 36 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 37 | 38 | // (Optional) Called by Init/NewFrame/Shutdown 39 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 40 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 41 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 42 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 43 | 44 | // Specific OpenGL ES versions 45 | //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten 46 | //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android 47 | 48 | // You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. 49 | #if !defined(IMGUI_IMPL_OPENGL_ES2) \ 50 | && !defined(IMGUI_IMPL_OPENGL_ES3) 51 | 52 | // Try to detect GLES on matching platforms 53 | #if defined(__APPLE__) 54 | #include 55 | #endif 56 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) 57 | #define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" 58 | #elif defined(__EMSCRIPTEN__) || defined(__amigaos4__) 59 | #define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" 60 | #else 61 | // Otherwise imgui_impl_opengl3_loader.h will be used. 62 | #endif 63 | 64 | #endif 65 | 66 | #endif // #ifndef IMGUI_DISABLE 67 | -------------------------------------------------------------------------------- /lib/imgui/backends/imgui_impl_sdl2.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for SDL2 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | // (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Clipboard support. 7 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. 8 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] 9 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 10 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 11 | // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. 12 | 13 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 14 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 15 | // Learn about Dear ImGui: 16 | // - FAQ https://dearimgui.com/faq 17 | // - Getting Started https://dearimgui.com/getting-started 18 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). 19 | // - Introduction, links and more at the top of imgui.cpp 20 | 21 | #pragma once 22 | #include "imgui.h" // IMGUI_IMPL_API 23 | #ifndef IMGUI_DISABLE 24 | 25 | struct SDL_Window; 26 | struct SDL_Renderer; 27 | struct _SDL_GameController; 28 | typedef union SDL_Event SDL_Event; 29 | 30 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); 31 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); 32 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); 33 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window); 34 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); 35 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window); 36 | IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); 37 | IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); 38 | IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); 39 | 40 | // Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. 41 | // When using manual mode, caller is responsible for opening/closing gamepad. 42 | enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; 43 | IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = NULL, int manual_gamepads_count = -1); 44 | 45 | #endif // #ifndef IMGUI_DISABLE 46 | -------------------------------------------------------------------------------- /lib/imgui/docs/BACKENDS.md: -------------------------------------------------------------------------------- 1 | _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md or view this file with any Markdown viewer)_ 2 | 3 | ## Dear ImGui: Backends 4 | 5 | **The backends/ folder contains backends for popular platforms/graphics API, which you can use in 6 | your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. 7 | 8 | - The 'Platform' backends are in charge of: mouse/keyboard/gamepad inputs, cursor shape, timing, and windowing.
9 | e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl2.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl2.cpp)), etc. 10 | 11 | - The 'Renderer' backends are in charge of: creating atlas texture, and rendering imgui draw data.
12 | e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc. 13 | 14 | - For some high-level frameworks, a single backend usually handles both 'Platform' and 'Renderer' parts.
15 | e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)). If you end up creating a custom backend for your engine, you may want to do the same. 16 | 17 | An application usually combines one Platform backend + one Renderer backend + main Dear ImGui sources. 18 | For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree/master/examples/example_win32_directx11) application combines imgui_impl_win32.cpp + imgui_impl_dx11.cpp. There are 20+ examples in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder. See [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for details. 19 | 20 | **Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** 21 | 22 | 23 | ### What are backends? 24 | 25 | Dear ImGui is highly portable and only requires a few things to run and render, typically: 26 | 27 | - Required: providing mouse/keyboard inputs (fed into the `ImGuiIO` structure). 28 | - Required: uploading the font atlas texture into graphics memory. 29 | - Required: rendering indexed textured triangles with a clipping rectangle. 30 | 31 | Extra features are opt-in, our backends try to support as many as possible: 32 | 33 | - Optional: custom texture binding support. 34 | - Optional: clipboard support. 35 | - Optional: gamepad support. 36 | - Optional: mouse cursor shape support. 37 | - Optional: IME support. 38 | - Optional: multi-viewports support. 39 | etc. 40 | 41 | This is essentially what each backend is doing + obligatory portability cruft. Using default backends ensure you can get all those features including the ones that would be harder to implement on your side (e.g. multi-viewports support). 42 | 43 | It is important to understand the difference between the core Dear ImGui library (files in the root folder) 44 | and the backends which we are describing here (backends/ folder). 45 | 46 | - Some issues may only be backend or platform specific. 47 | - You should be able to write backends for pretty much any platform and any 3D graphics API. 48 | e.g. you can get creative and use software rendering or render remotely on a different machine. 49 | 50 | 51 | ### Integrating a backend 52 | 53 | See "Getting Started" section of [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for more details. 54 | 55 | 56 | ### List of backends 57 | 58 | In the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder: 59 | 60 | List of Platforms Backends: 61 | 62 | imgui_impl_android.cpp ; Android native app API 63 | imgui_impl_glfw.cpp ; GLFW (Windows, macOS, Linux, etc.) http://www.glfw.org/ 64 | imgui_impl_osx.mm ; macOS native API (not as feature complete as glfw/sdl backends) 65 | imgui_impl_sdl2.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org 66 | imgui_impl_sdl3.cpp ; SDL3 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org (*EXPERIMENTAL UNTIL SDL3 IS RELEASED*) 67 | imgui_impl_win32.cpp ; Win32 native API (Windows) 68 | imgui_impl_glut.cpp ; GLUT/FreeGLUT (this is prehistoric software and absolutely not recommended today!) 69 | 70 | List of Renderer Backends: 71 | 72 | imgui_impl_dx9.cpp ; DirectX9 73 | imgui_impl_dx10.cpp ; DirectX10 74 | imgui_impl_dx11.cpp ; DirectX11 75 | imgui_impl_dx12.cpp ; DirectX12 76 | imgui_impl_metal.mm ; Metal (with ObjC) 77 | imgui_impl_opengl2.cpp ; OpenGL 2 (legacy, fixed pipeline <- don't use with modern OpenGL context) 78 | imgui_impl_opengl3.cpp ; OpenGL 3/4, OpenGL ES 2, OpenGL ES 3 (modern programmable pipeline) 79 | imgui_impl_sdlrenderer2.cpp ; SDL_Renderer (optional component of SDL2 available from SDL 2.0.18+) 80 | imgui_impl_sdlrenderer3.cpp ; SDL_Renderer (optional component of SDL3 available from SDL 3.0.0+) 81 | imgui_impl_vulkan.cpp ; Vulkan 82 | imgui_impl_wgpu.cpp ; WebGPU 83 | 84 | List of high-level Frameworks Backends (combining Platform + Renderer): 85 | 86 | imgui_impl_allegro5.cpp 87 | 88 | Emscripten is also supported! 89 | The SDL+GL, GLFW+GL and SDL+WebGPU examples are all ready to build and run with Emscripten. 90 | 91 | ### Backends for third-party frameworks, graphics API or other languages 92 | 93 | See https://github.com/ocornut/imgui/wiki/Bindings for the full list (e.g. Adventure Game Studio, Cinder, Cocos2d-x, Game Maker Studio2, Godot, LÖVE+LUA, Magnum, Monogame, Ogre, openFrameworks, OpenSceneGraph, SFML, Sokol, Unity, Unreal Engine and many others). 94 | 95 | ### Recommended Backends 96 | 97 | If you are not sure which backend to use, the recommended platform/frameworks for portable applications: 98 | 99 | |Library |Website |Backend |Note | 100 | |--------|--------|--------|-----| 101 | | GLFW | https://github.com/glfw/glfw | imgui_impl_glfw.cpp | | 102 | | SDL2 | https://www.libsdl.org | imgui_impl_sdl2.cpp | | 103 | | Sokol | https://github.com/floooh/sokol | [util/sokol_imgui.h](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h) | Lower-level than GLFW/SDL | 104 | 105 | 106 | ### Using a custom engine? 107 | 108 | You will likely be tempted to start by rewrite your own backend using your own custom/high-level facilities...
109 | Think twice! 110 | 111 | If you are new to Dear ImGui, first try using the existing backends as-is. 112 | You will save lots of time integrating the library. 113 | You can LATER decide to rewrite yourself a custom backend if you really need to. 114 | In most situations, custom backends have fewer features and more bugs than the standard backends we provide. 115 | If you want portability, you can use multiple backends and choose between them either at compile time 116 | or at runtime. 117 | 118 | **Example A**: your engine is built over Windows + DirectX11 but you have your own high-level rendering 119 | system layered over DirectX11.
120 | Suggestion: try using imgui_impl_win32.cpp + imgui_impl_dx11.cpp first. 121 | Once it works, if you really need it, you can replace the imgui_impl_dx11.cpp code with a 122 | custom renderer using your own rendering functions, and keep using the standard Win32 code etc. 123 | 124 | **Example B**: your engine runs on Windows, Mac, Linux and uses DirectX11, Metal, and Vulkan respectively.
125 | Suggestion: use multiple generic backends! 126 | Once it works, if you really need it, you can replace parts of backends with your own abstractions. 127 | 128 | **Example C**: your engine runs on platforms we can't provide public backends for (e.g. PS4/PS5, Switch), 129 | and you have high-level systems everywhere.
130 | Suggestion: try using a non-portable backend first (e.g. win32 + underlying graphics API) to get 131 | your desktop builds working first. This will get you running faster and get your acquainted with 132 | how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API... 133 | 134 | Generally: 135 | It is unlikely you will add value to your project by creating your own backend. 136 | 137 | Also: 138 | The [multi-viewports feature](https://github.com/ocornut/imgui/issues/1542) of the 'docking' branch allows 139 | Dear ImGui windows to be seamlessly detached from the main application window. This is achieved using an 140 | extra layer to the Platform and Renderer backends, which allows Dear ImGui to communicate platform-specific 141 | requests such as: "create an additional OS window", "create a render context", "get the OS position of this 142 | window" etc. See 'ImGuiPlatformIO' for details. 143 | Supporting the multi-viewports feature correctly using 100% of your own abstractions is more difficult 144 | than supporting single-viewport. 145 | If you decide to use unmodified imgui_impl_XXXX.cpp files, you can automatically benefit from 146 | improvements and fixes related to viewports and platform windows without extra work on your side. 147 | -------------------------------------------------------------------------------- /lib/imgui/docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Index 4 | 5 | - [Getting Started & General Advice](#getting-started--general-advice) 6 | - [Issues vs Discussions](#issues-vs-discussions) 7 | - [How to open an Issue](#how-to-open-an-issue) 8 | - [How to open a Pull Request](#how-to-open-a-pull-request) 9 | - [Copyright / Contributor License Agreement](#copyright--contributor-license-agreement) 10 | 11 | ## Getting Started & General Advice 12 | 13 | - Article: [How To Ask Good Questions](https://bit.ly/3nwRnx1). 14 | - Please browse the [Wiki](https://github.com/ocornut/imgui/wiki) to find code snippets, links and other resources (e.g. [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started), [Useful extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions)). 15 | - Please read [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) if your question relates to setting up Dear ImGui. 16 | - Please read [docs/FAQ.md](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md). 17 | - Please read [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) if your question relates to fonts or text. 18 | - Please run `ImGui::ShowDemoWindow()` to explore the demo and its sources. 19 | - Please use the search function of your IDE to search for symbols and comments related to your situation. 20 | - Please use the search function of GitHub to look for similar topics (always include 'Closed' issues/pr in your search). 21 | - You may [browse issues by Labels](https://github.com/ocornut/imgui/labels). 22 | - Please use a web search engine to look for similar issues. 23 | - If you get a crash or assert, use a debugger to locate the line triggering it and read the comments around. 24 | - Please don't be a [Help Vampire](https://slash7.com/2006/12/22/vampires/). 25 | 26 | ## 'Issues' vs 'Discussions' 27 | 28 | We are happy to use 'Issues' for many type of open-ended questions. We are encouraging 'Issues' becoming an enormous, centralized and cross-referenced database of Dear ImGui contents. 29 | 30 | Only if you: 31 | - Cannot BUILD or LINK examples. 32 | - Cannot BUILD, or LINK, or RUN Dear ImGui in your application or custom engine. 33 | - Cannot LOAD a font. 34 | 35 | Then please [use the Discussions forums](https://github.com/ocornut/imgui/discussions) instead of opening an issue. 36 | 37 | If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new issue. 38 | 39 | ## How to open an issue 40 | 41 | You may use the Issue Tracker to submit bug reports, feature requests or suggestions. You may ask for help or advice as well. But **PLEASE CAREFULLY READ THIS WALL OF TEXT. ISSUES IGNORING THOSE GUIDELINES MAY BE CLOSED. USERS IGNORING THOSE GUIDELINES MIGHT BE BLOCKED.** 42 | 43 | Please do your best to clarify your request. The amount of incomplete or ambiguous requests due to people not following those guidelines is often overwhelming. Issues created without the requested information may be closed prematurely. Exceptionally entitled, impolite, or lazy requests may lead to bans. 44 | 45 | **PLEASE UNDERSTAND THAT OPEN-SOURCE SOFTWARE LIVES OR DIES BY THE AMOUNT OF ENERGY MAINTAINERS CAN SPARE. WE HAVE LOTS OF STUFF TO DO. THIS IS AN ATTENTION ECONOMY AND MANY LAZY OR MINOR ISSUES ARE HOGGING OUR ATTENTION AND DRAINING ENERGY, TAKING US AWAY FROM MORE IMPORTANT WORK.** 46 | 47 | Steps: 48 | 49 | - Article: [How To Ask Good Questions](https://bit.ly/3nwRnx1). 50 | - **PLEASE DO FILL THE REQUESTED NEW ISSUE TEMPLATE.** Including Dear ImGui version number, branch name, platform/renderer back-ends (imgui_impl_XXX files), operating system. 51 | - **Try to be explicit with your GOALS, your EXPECTATIONS and what you have tried**. Be mindful of [The XY Problem](http://xyproblem.info/). What you have in mind or in your code is not obvious to other people. People frequently discuss problems and suggest incorrect solutions without first clarifying their goals. When requesting a new feature, please describe the usage context (how you intend to use it, why you need it, etc.). If you tried something and it failed, show us what you tried. 52 | - **Please INCLUDE CODE. Provide a Minimal, Complete, and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem**. An ideal submission includes a small piece of code that anyone can paste into one of the examples applications (examples/../main.cpp) or demo (imgui_demo.cpp) to understand and reproduce it. **Narrowing your problem to its shortest and purest form is the easiest way to understand it, explain it and fix it**. Please test your shortened code to ensure it exhibits the problem. **Often while creating the MCVE you will solve the problem!** Many questions that are missing a standalone verifiable example are missing the actual cause of their issue in the description, which ends up wasting everyone's time. 53 | - **Attach screenshots (or GIF/video) to clarify the context**. They often convey useful information that is omitted by the description. You can drag pictures/files in the message edit box. Avoid using 3rd party image hosting services, prefer the long-term longevity of GitHub attachments (you can drag pictures into your post). On Windows, you can use [ScreenToGif](https://www.screentogif.com/) to easily capture .gif files. 54 | - **If you are discussing an assert or a crash, please provide a debugger callstack**. Never state "it crashes" without additional information. If you don't know how to use a debugger and retrieve a callstack, learning about it will be useful. 55 | - **Please make sure that your project has asserts enabled.** Calls to IM_ASSERT() are scattered in the code to help catch common issues. When an assert is triggered read the comments around it. By default IM_ASSERT() calls the standard assert() function. To verify that your asserts are enabled, add the line `IM_ASSERT(false);` in your main() function. Your application should display an error message and abort. If your application doesn't report an error, your asserts are disabled. 56 | - Please state if you have made substantial modifications to your copy of Dear ImGui or the back-end. 57 | - If you are not calling Dear ImGui directly from C++, please provide information about your Language and the wrapper/binding you are using. 58 | - Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proofread your messages before sending them. Edits are not seen by those users unless they browse the site. 59 | 60 | **Some unfortunate words of warning** 61 | - If you are involved in cheating schemes (e.g. DLL injection) for competitive online multiplayer games, please don't post here. We won't answer and you will be blocked. It doesn't matter if your question relates to said project. We've had too many of you and need to protect our time and sanity. 62 | - Due to frequent abuse of this service from the aforementioned users, if your GitHub account is anonymous and was created five minutes ago please understand that your post will receive more scrutiny and incomplete questions will be harshly dismissed. 63 | 64 | If you have been using Dear ImGui for a while or have been using C/C++ for several years or have demonstrated good behavior here, it is ok to not fulfill every item to the letter. Those are guidelines and experienced users or members of the community will know which information is useful in a given context. 65 | 66 | ## How to open a Pull Request 67 | 68 | - **Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance.** PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it. 69 | - Many PRs are useful to demonstrate a need and a possible solution but aren't adequate for merging (causing other issues, not seeing other aspects of the big picture, etc.). In doubt, don't hesitate to push a PR because that is always the first step toward pointing toward a problem, and finding the mergeable solution! Even if a PR stays unmerged for a long time, its presence can be useful for other users and helps toward finding a general solution. 70 | - **When adding a feature,** please describe the usage context (how you intend to use it, why you need it, etc.). Be mindful of [The XY Problem](http://xyproblem.info/). 71 | - **When fixing a warning or compilation problem,** please post the compiler log and specify the compiler version and platform you are using. 72 | - **Attach screenshots (or GIF/video) to clarify the context and demonstrate the feature at a glance.** You can drag pictures/files in the message edit box. Prefer the long-term longevity of GitHub attachments over 3rd party hosting (you can drag pictures into your post). 73 | - **Make sure your code follows the coding style already used in the codebase:** 4 spaces indentations (no tabs), `local_variable`, `FunctionName()`, `MemberName`, `// Text Comment`, `//CodeComment();`, C-style casts, etc.. We don't use modern C++ idioms and tend to use only a minimum of C++11 features. The applications under examples/ are generally less consistent because they sometimes try to mimic the coding style often adopted by a certain ecosystem (e.g. DirectX-related code tend to use the style of their sample). 74 | - **Make sure you create a branch dedicated to the pull request**. In Git, 1 PR is associated to 1 branch. If you keep pushing to the same branch after you submitted the PR, your new commits will appear in the PR (we can still cherry-pick individual commits). 75 | 76 | ## Copyright / Contributor License Agreement 77 | 78 | Any code you submit will become part of the repository and be distributed under the [Dear ImGui license](https://github.com/ocornut/imgui/blob/master/LICENSE.txt). By submitting code to the project you agree that the code is your work and that you can give it to the project. 79 | 80 | You also agree by submitting your code that you grant all transferrable rights to the code to the project maintainer, including for example re-licensing the code, modifying the code, and distributing it in source or binary forms. Specifically, this includes a requirement that you assign copyright to the project maintainer. For this reason, do not modify any copyright statements in files in any PRs. 81 | 82 | -------------------------------------------------------------------------------- /lib/imgui/docs/EXAMPLES.md: -------------------------------------------------------------------------------- 1 | _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md or view this file with any Markdown viewer)_ 2 | 3 | ## Dear ImGui: Examples 4 | 5 | **The [examples/](https://github.com/ocornut/imgui/blob/master/examples) folder example applications (standalone, ready-to-build) for variety of 6 | platforms and graphics APIs.** They all use standard backends from the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder (see [BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md)). 7 | 8 | The purpose of Examples is to showcase integration with backends, let you try Dear ImGui, and guide you toward 9 | integrating Dear ImGui in your own application/game/engine. 10 | **Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** 11 | 12 | You can find Windows binaries for some of those example applications at: 13 | https://www.dearimgui.com/binaries 14 | 15 | 16 | ### Getting Started 17 | 18 | Integration in a typical existing application, should take <20 lines when using standard backends. 19 | 20 | ```cpp 21 | At initialization: 22 | call ImGui::CreateContext() 23 | call ImGui_ImplXXXX_Init() for each backend. 24 | 25 | At the beginning of your frame: 26 | call ImGui_ImplXXXX_NewFrame() for each backend. 27 | call ImGui::NewFrame() 28 | 29 | At the end of your frame: 30 | call ImGui::Render() 31 | call ImGui_ImplXXXX_RenderDrawData() for your Renderer backend. 32 | 33 | At shutdown: 34 | call ImGui_ImplXXXX_Shutdown() for each backend. 35 | call ImGui::DestroyContext() 36 | ``` 37 | 38 | Example (using [backends/imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp) + [backends/imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)): 39 | 40 | ```cpp 41 | // Create a Dear ImGui context, setup some options 42 | ImGui::CreateContext(); 43 | ImGuiIO& io = ImGui::GetIO(); 44 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable some options 45 | 46 | // Initialize Platform + Renderer backends (here: using imgui_impl_win32.cpp + imgui_impl_dx11.cpp) 47 | ImGui_ImplWin32_Init(my_hwnd); 48 | ImGui_ImplDX11_Init(my_d3d_device, my_d3d_device_context); 49 | 50 | // Application main loop 51 | while (true) 52 | { 53 | // Beginning of frame: update Renderer + Platform backend, start Dear ImGui frame 54 | ImGui_ImplDX11_NewFrame(); 55 | ImGui_ImplWin32_NewFrame(); 56 | ImGui::NewFrame(); 57 | 58 | // Any application code here 59 | ImGui::Text("Hello, world!"); 60 | 61 | // End of frame: render Dear ImGui 62 | ImGui::Render(); 63 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 64 | 65 | // Swap 66 | g_pSwapChain->Present(1, 0); 67 | } 68 | 69 | // Shutdown 70 | ImGui_ImplDX11_Shutdown(); 71 | ImGui_ImplWin32_Shutdown(); 72 | ImGui::DestroyContext(); 73 | ``` 74 | 75 | Please read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. 76 | Please read the comments and instruction at the top of each file. 77 | Please read FAQ at https://www.dearimgui.com/faq 78 | 79 | If you are using any of the backends provided here, you can add the backends/imgui_impl_xxxx(.cpp,.h) 80 | files to your project and use as-in. Each imgui_impl_xxxx.cpp file comes with its own individual 81 | Changelog, so if you want to update them later it will be easier to catch up with what changed. 82 | 83 | 84 | ### Examples Applications 85 | 86 | [example_allegro5/](https://github.com/ocornut/imgui/blob/master/examples/example_allegro5/)
87 | Allegro 5 example.
88 | = main.cpp + imgui_impl_allegro5.cpp 89 | 90 | [example_android_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_android_opengl3/)
91 | Android + OpenGL3 (ES) example.
92 | = main.cpp + imgui_impl_android.cpp + imgui_impl_opengl3.cpp 93 | 94 | [example_apple_metal/](https://github.com/ocornut/imgui/blob/master/examples/example_metal/)
95 | OSX & iOS + Metal example.
96 | = main.m + imgui_impl_osx.mm + imgui_impl_metal.mm
97 | It is based on the "cross-platform" game template provided with Xcode as of Xcode 9. 98 | (NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends. 99 | You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.) 100 | 101 | [example_apple_opengl2/](https://github.com/ocornut/imgui/blob/master/examples/example_apple_opengl2/)
102 | OSX + OpenGL2 example.
103 | = main.mm + imgui_impl_osx.mm + imgui_impl_opengl2.cpp
104 | (NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends. 105 | You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.) 106 | 107 | [example_emscripten_wgpu/](https://github.com/ocornut/imgui/blob/master/examples/example_emscripten_wgpu/)
108 | Emcripten + GLFW + WebGPU example.
109 | = main.cpp + imgui_impl_glfw.cpp + imgui_impl_wgpu.cpp 110 | Note that the 'example_glfw_opengl3' and 'example_sdl2_opengl3' examples also supports Emscripten! 111 | 112 | [example_glfw_metal/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_metal/)
113 | GLFW (Mac) + Metal example.
114 | = main.mm + imgui_impl_glfw.cpp + imgui_impl_metal.mm 115 | 116 | [example_glfw_opengl2/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_opengl2/)
117 | GLFW + OpenGL2 example (legacy, fixed pipeline).
118 | = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp
119 | **DO NOT USE THIS IF YOUR CODE/ENGINE IS USING MODERN GL or WEBGL (SHADERS, VBO, VAO, etc.)**
120 | This code is mostly provided as a reference to learn about Dear ImGui integration, because it is shorter. 121 | If your code is using GL3+ context or any semi modern GL calls, using this renderer is likely to 122 | make things more complicated, will require your code to reset many GL attributes to their initial 123 | state, and might confuse your GPU driver. One star, not recommended. 124 | 125 | [example_glfw_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_opengl3/)
126 | GLFW (Win32, Mac, Linux) + OpenGL3+/ES2/ES3 example (modern, programmable pipeline).
127 | = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp
128 | This uses more modern GL calls and custom shaders.
129 | This support building with Emscripten and targetting WebGL.
130 | Prefer using that if you are using modern GL or WebGL in your application. 131 | 132 | [example_glfw_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_vulkan/)
133 | GLFW (Win32, Mac, Linux) + Vulkan example.
134 | = main.cpp + imgui_impl_glfw.cpp + imgui_impl_vulkan.cpp
135 | This is quite long and tedious, because: Vulkan. 136 | For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp. 137 | 138 | [example_glut_opengl2/](https://github.com/ocornut/imgui/blob/master/examples/example_glut_opengl2/)
139 | GLUT (e.g., FreeGLUT on Linux/Windows, GLUT framework on OSX) + OpenGL2 example.
140 | = main.cpp + imgui_impl_glut.cpp + imgui_impl_opengl2.cpp
141 | Note that GLUT/FreeGLUT is largely obsolete software, prefer using GLFW or SDL. 142 | 143 | [example_null/](https://github.com/ocornut/imgui/blob/master/examples/example_null/)
144 | Null example, compile and link imgui, create context, run headless with no inputs and no graphics output.
145 | = main.cpp
146 | This is used to quickly test compilation of core imgui files in as many setups as possible. 147 | Because this application doesn't create a window nor a graphic context, there's no graphics output. 148 | 149 | [example_sdl2_directx11/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_directx11/)
150 | SDL2 + DirectX11 example, Windows only.
151 | = main.cpp + imgui_impl_sdl2.cpp + imgui_impl_dx11.cpp
152 | This to demonstrate usage of DirectX with SDL2. 153 | 154 | [example_sdl2_metal/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_metal/)
155 | SDL2 + Metal example, Mac only.
156 | = main.mm + imgui_impl_sdl2.cpp + imgui_impl_metal.mm 157 | 158 | [example_sdl2_opengl2/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_opengl2/)
159 | SDL2 (Win32, Mac, Linux etc.) + OpenGL example (legacy, fixed pipeline).
160 | = main.cpp + imgui_impl_sdl2.cpp + imgui_impl_opengl2.cpp
161 | **DO NOT USE OPENGL2 CODE IF YOUR CODE/ENGINE IS USING GL OR WEBGL (SHADERS, VBO, VAO, etc.)**
162 | This code is mostly provided as a reference to learn about Dear ImGui integration, because it is shorter. 163 | If your code is using GL3+ context or any semi modern GL calls, using this renderer is likely to 164 | make things more complicated, will require your code to reset many GL attributes to their initial 165 | state, and might confuse your GPU driver. One star, not recommended. 166 | 167 | [example_sdl2_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_opengl3/)
168 | SDL2 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example.
169 | = main.cpp + imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp
170 | This uses more modern GL calls and custom shaders.
171 | This support building with Emscripten and targetting WebGL.
172 | Prefer using that if you are using modern GL or WebGL in your application. 173 | 174 | [example_sdl2_sdlrenderer2/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_sdlrenderer2/)
175 | SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL2 (most graphics backends are supported underneath)
176 | = main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlrenderer.cpp
177 | This requires SDL 2.0.18+ (released November 2021)
178 | 179 | [example_sdl2_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_vulkan/)
180 | SDL2 (Win32, Mac, Linux, etc.) + Vulkan example.
181 | = main.cpp + imgui_impl_sdl2.cpp + imgui_impl_vulkan.cpp
182 | This is quite long and tedious, because: Vulkan.
183 | For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp. 184 | 185 | [example_win32_directx9/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx9/)
186 | DirectX9 example, Windows only.
187 | = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx9.cpp 188 | 189 | [example_win32_directx10/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx10/)
190 | DirectX10 example, Windows only.
191 | = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx10.cpp 192 | 193 | [example_win32_directx11/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx11/)
194 | DirectX11 example, Windows only.
195 | = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx11.cpp 196 | 197 | [example_win32_directx12/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx12/)
198 | DirectX12 example, Windows only.
199 | = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx12.cpp
200 | This is quite long and tedious, because: DirectX12. 201 | 202 | [example_win32_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_opengl3/)
203 | Raw Windows + OpenGL3 + example (modern, programmable pipeline)
204 | = main.cpp + imgui_impl_win32.cpp + imgui_impl_opengl3.cpp
205 | 206 | 207 | ### Miscellaneous 208 | 209 | **Building** 210 | 211 | Unfortunately nowadays it is still tedious to create and maintain portable build files using external 212 | libraries (the kind we're using here to create a window and render 3D triangles) without relying on 213 | third party software and build systems. For most examples here we choose to provide: 214 | - Makefiles for Linux/OSX 215 | - Batch files for Visual Studio 2008+ 216 | - A .sln project file for Visual Studio 2012+ 217 | - Xcode project files for the Apple examples 218 | Please let us know if they don't work with your setup! 219 | You can probably just import the imgui_impl_xxx.cpp/.h files into your own codebase or compile those 220 | directly with a command-line compiler. 221 | 222 | If you are interested in using Cmake to build and links examples, see: 223 | https://github.com/ocornut/imgui/pull/1713 and https://github.com/ocornut/imgui/pull/3027 224 | 225 | **About mouse cursor latency** 226 | 227 | Dear ImGui has no particular extra lag for most behaviors, 228 | e.g. the last value passed to 'io.AddMousePosEvent()' before NewFrame() will result in windows being moved 229 | to the right spot at the time of EndFrame()/Render(). At 60 FPS your experience should be pleasant. 230 | 231 | However, consider that OS mouse cursors are typically drawn through a very specific hardware accelerated 232 | path and will feel smoother than the majority of contents rendered via regular graphics API (including, 233 | but not limited to Dear ImGui windows). Because UI rendering and interaction happens on the same plane 234 | as the mouse, that disconnect may be jarring to particularly sensitive users. 235 | You may experiment with enabling the io.MouseDrawCursor flag to request Dear ImGui to draw a mouse cursor 236 | using the regular graphics API, to help you visualize the difference between a "hardware" cursor and a 237 | regularly rendered software cursor. 238 | However, rendering a mouse cursor at 60 FPS will feel sluggish so you likely won't want to enable that at 239 | all times. It might be beneficial for the user experience to switch to a software rendered cursor _only_ 240 | when an interactive drag is in progress. 241 | 242 | Note that some setup or GPU drivers are likely to be causing extra display lag depending on their settings. 243 | If you feel that dragging windows feels laggy and you are not sure what the cause is: try to build a simple 244 | drawing a flat 2D shape directly under the mouse cursor! 245 | 246 | -------------------------------------------------------------------------------- /lib/imgui/docs/README.md: -------------------------------------------------------------------------------- 1 | Dear ImGui 2 | ===== 3 | 4 |
"Give someone state and they'll have a bug one day, but teach them how to represent state in two separate locations that have to be kept in sync and they'll have bugs for a lifetime."
-ryg 5 | 6 | ---- 7 | 8 | [![Build Status](https://github.com/ocornut/imgui/workflows/build/badge.svg)](https://github.com/ocornut/imgui/actions?workflow=build) [![Static Analysis Status](https://github.com/ocornut/imgui/workflows/static-analysis/badge.svg)](https://github.com/ocornut/imgui/actions?workflow=static-analysis) [![Tests Status](https://github.com/ocornut/imgui_test_engine/workflows/tests/badge.svg)](https://github.com/ocornut/imgui_test_engine/actions?workflow=tests) 9 | 10 | (This library is available under a free and permissive license, but needs financial support to sustain its continued improvements. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using Dear ImGui, please consider reaching out.) 11 | 12 | Businesses: support continued development and maintenance via invoiced sponsoring/support contracts: 13 |
  _E-mail: contact @ dearimgui dot com_ 14 |
Individuals: support continued development and maintenance [here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S). Also see [Funding](https://github.com/ocornut/imgui/wiki/Funding) page. 15 | 16 | | [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Integration](#integration) | 17 | :----------------------------------------------------------: | 18 | | [Gallery](#gallery) - [Support, FAQ](#support-frequently-asked-questions-faq) - [How to help](#how-to-help) - **[Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding)** - [Credits](#credits) - [License](#license) | 19 | | [Wiki](https://github.com/ocornut/imgui/wiki) - [Extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions) - [Languages bindings & frameworks backends](https://github.com/ocornut/imgui/wiki/Bindings) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [User quotes](https://github.com/ocornut/imgui/wiki/Quotes) | 20 | 21 | ### The Pitch 22 | 23 | Dear ImGui is a **bloat-free graphical user interface library for C++**. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline-enabled application. It is fast, portable, renderer agnostic, and self-contained (no external dependencies). 24 | 25 | Dear ImGui is designed to **enable fast iterations** and to **empower programmers** to create **content creation tools and visualization / debug tools** (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal and lacks certain features commonly found in more high-level libraries. 26 | 27 | Dear ImGui is particularly suited to integration in game engines (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on console platforms where operating system features are non-standard. 28 | 29 | - Minimize state synchronization. 30 | - Minimize UI-related state storage on user side. 31 | - Minimize setup and maintenance. 32 | - Easy to use to create dynamic UI which are the reflection of a dynamic data set. 33 | - Easy to use to create code-driven and data-driven tools. 34 | - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. 35 | - Easy to hack and improve. 36 | - Portable, minimize dependencies, run on target (consoles, phones, etc.). 37 | - Efficient runtime and memory consumption. 38 | - Battle-tested, used by [many major actors in the game industry](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui). 39 | 40 | ### Usage 41 | 42 | **The core of Dear ImGui is self-contained within a few platform-agnostic files** which you can easily compile in your application/engine. They are all the files in the root folder of the repository (imgui*.cpp, imgui*.h). **No specific build process is required**. You can add the .cpp files into your existing project. 43 | 44 | **Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui. 45 | 46 | See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide and [Integration](#integration) section of this document for more details. 47 | 48 | After Dear ImGui is set up in your application, you can use it from \_anywhere\_ in your program loop: 49 | ```cpp 50 | ImGui::Text("Hello, world %d", 123); 51 | if (ImGui::Button("Save")) 52 | MySaveFunction(); 53 | ImGui::InputText("string", buf, IM_ARRAYSIZE(buf)); 54 | ImGui::SliderFloat("float", &f, 0.0f, 1.0f); 55 | ``` 56 | ![sample code output (dark, segoeui font, freetype)](https://user-images.githubusercontent.com/8225057/191050833-b7ecf528-bfae-4a9f-ac1b-f3d83437a2f4.png) 57 | ![sample code output (light, segoeui font, freetype)](https://user-images.githubusercontent.com/8225057/191050838-8742efd4-504d-4334-a9a2-e756d15bc2ab.png) 58 | 59 | ```cpp 60 | // Create a window called "My First Tool", with a menu bar. 61 | ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar); 62 | if (ImGui::BeginMenuBar()) 63 | { 64 | if (ImGui::BeginMenu("File")) 65 | { 66 | if (ImGui::MenuItem("Open..", "Ctrl+O")) { /* Do stuff */ } 67 | if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Do stuff */ } 68 | if (ImGui::MenuItem("Close", "Ctrl+W")) { my_tool_active = false; } 69 | ImGui::EndMenu(); 70 | } 71 | ImGui::EndMenuBar(); 72 | } 73 | 74 | // Edit a color stored as 4 floats 75 | ImGui::ColorEdit4("Color", my_color); 76 | 77 | // Generate samples and plot them 78 | float samples[100]; 79 | for (int n = 0; n < 100; n++) 80 | samples[n] = sinf(n * 0.2f + ImGui::GetTime() * 1.5f); 81 | ImGui::PlotLines("Samples", samples, 100); 82 | 83 | // Display contents in a scrolling region 84 | ImGui::TextColored(ImVec4(1,1,0,1), "Important Stuff"); 85 | ImGui::BeginChild("Scrolling"); 86 | for (int n = 0; n < 50; n++) 87 | ImGui::Text("%04d: Some text", n); 88 | ImGui::EndChild(); 89 | ImGui::End(); 90 | ``` 91 | ![my_first_tool_v188](https://user-images.githubusercontent.com/8225057/191055698-690a5651-458f-4856-b5a9-e8cc95c543e2.gif) 92 | 93 | Dear ImGui allows you to **create elaborate tools** as well as very short-lived ones. On the extreme side of short-livedness: using the Edit&Continue (hot code reload) feature of modern compilers you can add a few widgets to tweak variables while your application is running, and remove the code a minute later! Dear ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, an entire game-making editor/framework, etc. 94 | 95 | ### How it works 96 | 97 | The IMGUI paradigm through its API tries to minimize superfluous state duplication, state synchronization, and state retention from the user's point of view. It is less error-prone (less code and fewer bugs) than traditional retained-mode interfaces, and lends itself to creating dynamic user interfaces. Check out the Wiki's [About the IMGUI paradigm](https://github.com/ocornut/imgui/wiki#about-the-imgui-paradigm) section for more details. 98 | 99 | Dear ImGui outputs vertex buffers and command lists that you can easily render in your application. The number of draw calls and state changes required to render them is fairly small. Because Dear ImGui doesn't know or touch graphics state directly, you can call its functions anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate Dear ImGui with your existing codebase. 100 | 101 | _A common misunderstanding is to mistake immediate mode GUI for immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes as the GUI functions are called. This is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batches. It never touches your GPU directly. The draw call batches are decently optimal and you can render them later, in your app or even remotely._ 102 | 103 | ### Releases & Changelogs 104 | 105 | See [Releases](https://github.com/ocornut/imgui/releases) page for decorated Changelogs. 106 | Reading the changelogs is a good way to keep up to date with the things Dear ImGui has to offer, and maybe will give you ideas of some features that you've been ignoring until now! 107 | 108 | ### Demo 109 | 110 | Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. [Here's how the demo looks](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). 111 | 112 | You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: 113 | - [imgui-demo-binaries-20240105.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20240105.zip) (Windows, 1.90.1 WIP, built 2024/01/05, master) or [older binaries](https://www.dearimgui.com/binaries). 114 | 115 | The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at a different scale and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.com/faq)). 116 | 117 | ### Integration 118 | 119 | See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide for details. 120 | 121 | On most platforms and when using C++, **you should be able to use a combination of the [imgui_impl_xxxx](https://github.com/ocornut/imgui/tree/master/backends) backends without modification** (e.g. `imgui_impl_win32.cpp` + `imgui_impl_dx11.cpp`). If your engine supports multiple platforms, consider using more imgui_impl_xxxx files instead of rewriting them: this will be less work for you, and you can get Dear ImGui running immediately. You can _later_ decide to rewrite a custom backend using your custom engine functions if you wish so. 122 | 123 | Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading a texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles, which is essentially what Backends are doing. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that: setting up a window and using backends. If you follow the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide it should in theory takes you less than an hour to integrate Dear ImGui. **Make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!** 124 | 125 | Officially maintained backends/bindings (in repository): 126 | - Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_Renderer, Vulkan, WebGPU. 127 | - Platforms: GLFW, SDL2/SDL3, Win32, Glut, OSX, Android. 128 | - Frameworks: Allegro5, Emscripten. 129 | 130 | [Third-party backends/bindings](https://github.com/ocornut/imgui/wiki/Bindings) wiki page: 131 | - Languages: C, C# and: Beef, ChaiScript, CovScript, Crystal, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lobster, Lua, Nim, Odin, Pascal, PureBasic, Python, ReaScript, Ruby, Rust, Swift, Zig... 132 | - Frameworks: AGS/Adventure Game Studio, Amethyst, Blender, bsf, Cinder, Cocos2d-x, Defold, Diligent Engine, Ebiten, Flexium, GML/Game Maker Studio, GLEQ, Godot, GTK3, Irrlicht Engine, JUCE, LÖVE+LUA, Mach Engine, Magnum, Marmalade, Monogame, NanoRT, nCine, Nim Game Lib, Nintendo 3DS/Switch/WiiU (homebrew), Ogre, openFrameworks, OSG/OpenSceneGraph, Orx, Photoshop, px_render, Qt/QtDirect3D, raylib, SFML, Sokol, Unity, Unreal Engine 4/5, UWP, vtk, VulkanHpp, VulkanSceneGraph, Win32 GDI, WxWidgets. 133 | - Many bindings are auto-generated (by good old [cimgui](https://github.com/cimgui/cimgui) or newer/experimental [dear_bindings](https://github.com/dearimgui/dear_bindings)), you can use their metadata output to generate bindings for other languages. 134 | 135 | [Useful Extensions/Widgets](https://github.com/ocornut/imgui/wiki/Useful-Extensions) wiki page: 136 | - Automation/testing, Text editors, node editors, timeline editors, plotting, software renderers, remote network access, memory editors, gizmos, etc. Notable and well supported extensions include [ImPlot](https://github.com/epezent/implot) and [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine). 137 | 138 | Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas. 139 | 140 | ### Gallery 141 | 142 | Examples projects using Dear ImGui: [Tracy](https://github.com/wolfpld/tracy) (profiler), [ImHex](https://github.com/WerWolv/ImHex) (hex editor/data analysis), [RemedyBG](https://remedybg.itch.io/remedybg) (debugger) and [hundreds of others](https://github.com/ocornut/imgui/wiki/Software-using-Dear-ImGui). 143 | 144 | For more user-submitted screenshots of projects using Dear ImGui, check out the [Gallery Threads](https://github.com/ocornut/imgui/issues/6897)! 145 | 146 | For a list of third-party widgets and extensions, check out the [Useful Extensions/Widgets](https://github.com/ocornut/imgui/wiki/Useful-Extensions) wiki page. 147 | 148 | | | | 149 | |--|--| 150 | | Custom engine [erhe](https://github.com/tksuoran/erhe) (docking branch)
[![erhe](https://user-images.githubusercontent.com/8225057/190203358-6988b846-0686-480e-8663-1311fbd18abd.jpg)](https://user-images.githubusercontent.com/994606/147875067-a848991e-2ad2-4fd3-bf71-4aeb8a547bcf.png) | Custom engine for [Wonder Boy: The Dragon's Trap](http://www.TheDragonsTrap.com) (2017)
[![the dragon's trap](https://user-images.githubusercontent.com/8225057/190203379-57fcb80e-4aec-4fec-959e-17ddd3cd71e5.jpg)](https://cloud.githubusercontent.com/assets/8225057/20628927/33e14cac-b329-11e6-80f6-9524e93b048a.png) | 151 | | Custom engine (untitled)
[![editor white](https://user-images.githubusercontent.com/8225057/190203393-c5ac9f22-b900-4d1e-bfeb-6027c63e3d92.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/editor_white.png) | Tracy Profiler ([github](https://github.com/wolfpld/tracy))
[![tracy profiler](https://user-images.githubusercontent.com/8225057/190203401-7b595f6e-607c-44d3-97ea-4c2673244dfb.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v176/tracy_profiler.png) | 152 | 153 | ### Support, Frequently Asked Questions (FAQ) 154 | 155 | See: [Frequently Asked Questions (FAQ)](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md) where common questions are answered. 156 | 157 | See: [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) and [Wiki](https://github.com/ocornut/imgui/wiki) for many links, references, articles. 158 | 159 | See: [Articles about the IMGUI paradigm](https://github.com/ocornut/imgui/wiki#about-the-imgui-paradigm) to read/learn about the Immediate Mode GUI paradigm. 160 | 161 | See: [Upcoming Changes](https://github.com/ocornut/imgui/wiki/Upcoming-Changes). 162 | 163 | See: [Dear ImGui Test Engine + Test Suite](https://github.com/ocornut/imgui_test_engine) for Automation & Testing. 164 | 165 | For the purposes of getting search engines to crawl the wiki, here's a link to the [Crawable Wiki](https://github-wiki-see.page/m/ocornut/imgui/wiki) (not for humans, [here's why](https://github-wiki-see.page/)). 166 | 167 | Getting started? For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions). For ANY other questions, bug reports, requests, feedback, please post on [GitHub Issues](https://github.com/ocornut/imgui/issues). Please read and fill the New Issue template carefully. 168 | 169 | Private support is available for paying business customers (E-mail: _contact @ dearimgui dot com_). 170 | 171 | **Which version should I get?** 172 | 173 | We occasionally tag [Releases](https://github.com/ocornut/imgui/releases) (with nice releases notes) but it is generally safe and recommended to sync to latest `master` or `docking` branch. The library is fairly stable and regressions tend to be fixed fast when reported. Advanced users may want to use the `docking` branch with [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features. This branch is kept in sync with master regularly. 174 | 175 | **Who uses Dear ImGui?** 176 | 177 | See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes), [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding), and [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for an idea of who is using Dear ImGui. Please add your game/software if you can! Also, see the [Gallery Threads](https://github.com/ocornut/imgui/issues/6897)! 178 | 179 | How to help 180 | ----------- 181 | 182 | **How can I help?** 183 | 184 | - See [GitHub Forum/Issues](https://github.com/ocornut/imgui/issues). 185 | - You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it. 186 | - See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the [Wiki](https://github.com/ocornut/imgui/wiki/) for some more ideas. 187 | - Be a [Funding Supporter](https://github.com/ocornut/imgui/wiki/Funding)! Have your company financially support this project via invoiced sponsors/maintenance or by buying a license for [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine) (please reach out: omar AT dearimgui DOT com). 188 | 189 | Sponsors 190 | -------- 191 | 192 | Ongoing Dear ImGui development is and has been financially supported by users and private sponsors. 193 |
Please see the **[detailed list of current and past Dear ImGui funding supporters and sponsors](https://github.com/ocornut/imgui/wiki/Funding)** for details. 194 |
From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations. 195 | 196 | **THANK YOU to all past and present supporters for helping to keep this project alive and thriving!** 197 | 198 | Dear ImGui is using software and services provided free of charge for open source projects: 199 | - [PVS-Studio](https://www.viva64.com/en/b/0570/) for static analysis. 200 | - [GitHub actions](https://github.com/features/actions) for continuous integration systems. 201 | - [OpenCppCoverage](https://github.com/OpenCppCoverage/OpenCppCoverage) for code coverage analysis. 202 | 203 | Credits 204 | ------- 205 | 206 | Developed by [Omar Cornut](https://www.miracleworld.net) and every direct or indirect [contributors](https://github.com/ocornut/imgui/graphs/contributors) to the GitHub. The early version of this library was developed with the support of [Media Molecule](https://www.mediamolecule.com) and first used internally on the game [Tearaway](https://tearaway.mediamolecule.com) (PS Vita). 207 | 208 | Recurring contributors include Rokas Kupstys [@rokups](https://github.com/rokups) (2020-2022): a good portion of work on automation system and regression tests now available in [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine). 209 | 210 | Maintenance/support contracts, sponsoring invoices and other B2B transactions are hosted and handled by [Disco Hello](https://www.discohello.com). 211 | 212 | Omar: "I first discovered the IMGUI paradigm at [Q-Games](https://www.q-games.com) where Atman Binstock had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating and improving it." 213 | 214 | Embeds [ProggyClean.ttf](https://www.proggyfonts.net) font by Tristan Grimmer (MIT license). 215 |
Embeds [stb_textedit.h, stb_truetype.h, stb_rect_pack.h](https://github.com/nothings/stb/) by Sean Barrett (public domain). 216 | 217 | Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Also thank you to everyone posting feedback, questions and patches on GitHub. 218 | 219 | License 220 | ------- 221 | 222 | Dear ImGui is licensed under the MIT License, see [LICENSE.txt](https://github.com/ocornut/imgui/blob/master/LICENSE.txt) for more information. 223 | -------------------------------------------------------------------------------- /lib/imgui/examples/README.txt: -------------------------------------------------------------------------------- 1 | See BACKENDS and EXAMPLES files in the docs/ folder, or on the web at: https://github.com/ocornut/imgui/tree/master/docs 2 | 3 | Backends = Helper code to facilitate integration with platforms/graphics api (used by Examples + should be used by your app). 4 | Examples = Standalone applications showcasing integration with platforms/graphics api. 5 | 6 | Some Examples have extra README files in their respective directory, please check them too! 7 | 8 | Once Dear ImGui is running (in either examples or your own application/game/engine), 9 | run and refer to ImGui::ShowDemoWindow() in imgui_demo.cpp for the end-user API. 10 | -------------------------------------------------------------------------------- /lib/imgui/examples/example_sdl2_opengl3/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Cross Platform Makefile 3 | # Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X 4 | # 5 | # You will need SDL2 (http://www.libsdl.org): 6 | # Linux: 7 | # apt-get install libsdl2-dev 8 | # Mac OS X: 9 | # brew install sdl2 10 | # MSYS2: 11 | # pacman -S mingw-w64-i686-SDL2 12 | # 13 | 14 | #CXX = g++ 15 | #CXX = clang++ 16 | 17 | EXE = example_sdl2_opengl3 18 | IMGUI_DIR = ../.. 19 | SOURCES = main.cpp 20 | SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp 21 | SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp 22 | OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) 23 | UNAME_S := $(shell uname -s) 24 | LINUX_GL_LIBS = -lGL 25 | 26 | CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends 27 | CXXFLAGS += -g -Wall -Wformat 28 | LIBS = 29 | 30 | ##--------------------------------------------------------------------- 31 | ## OPENGL ES 32 | ##--------------------------------------------------------------------- 33 | 34 | ## This assumes a GL ES library available in the system, e.g. libGLESv2.so 35 | # CXXFLAGS += -DIMGUI_IMPL_OPENGL_ES2 36 | # LINUX_GL_LIBS = -lGLESv2 37 | ## If you're on a Raspberry Pi and want to use the legacy drivers, 38 | ## use the following instead: 39 | # LINUX_GL_LIBS = -L/opt/vc/lib -lbrcmGLESv2 40 | 41 | ##--------------------------------------------------------------------- 42 | ## BUILD FLAGS PER PLATFORM 43 | ##--------------------------------------------------------------------- 44 | 45 | ifeq ($(UNAME_S), Linux) #LINUX 46 | ECHO_MESSAGE = "Linux" 47 | LIBS += $(LINUX_GL_LIBS) -ldl `sdl2-config --libs` 48 | 49 | CXXFLAGS += `sdl2-config --cflags` 50 | CFLAGS = $(CXXFLAGS) 51 | endif 52 | 53 | ifeq ($(UNAME_S), Darwin) #APPLE 54 | ECHO_MESSAGE = "Mac OS X" 55 | LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs` 56 | LIBS += -L/usr/local/lib -L/opt/local/lib 57 | 58 | CXXFLAGS += `sdl2-config --cflags` 59 | CXXFLAGS += -I/usr/local/include -I/opt/local/include 60 | CFLAGS = $(CXXFLAGS) 61 | endif 62 | 63 | ifeq ($(OS), Windows_NT) 64 | ECHO_MESSAGE = "MinGW" 65 | LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2` 66 | 67 | CXXFLAGS += `pkg-config --cflags sdl2` 68 | CFLAGS = $(CXXFLAGS) 69 | endif 70 | 71 | ##--------------------------------------------------------------------- 72 | ## BUILD RULES 73 | ##--------------------------------------------------------------------- 74 | 75 | %.o:%.cpp 76 | $(CXX) $(CXXFLAGS) -c -o $@ $< 77 | 78 | %.o:$(IMGUI_DIR)/%.cpp 79 | $(CXX) $(CXXFLAGS) -c -o $@ $< 80 | 81 | %.o:$(IMGUI_DIR)/backends/%.cpp 82 | $(CXX) $(CXXFLAGS) -c -o $@ $< 83 | 84 | all: $(EXE) 85 | @echo Build complete for $(ECHO_MESSAGE) 86 | 87 | $(EXE): $(OBJS) 88 | $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) 89 | 90 | clean: 91 | rm -f $(EXE) $(OBJS) 92 | -------------------------------------------------------------------------------- /lib/imgui/examples/example_sdl2_opengl3/Makefile.emscripten: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile to use with SDL+emscripten 3 | # See https://emscripten.org/docs/getting_started/downloads.html 4 | # for installation instructions. 5 | # 6 | # This Makefile assumes you have loaded emscripten's environment. 7 | # (On Windows, you may need to execute emsdk_env.bat or encmdprompt.bat ahead) 8 | # 9 | # Running `make -f Makefile.emscripten` will produce three files: 10 | # - web/index.html 11 | # - web/index.js 12 | # - web/index.wasm 13 | # 14 | # All three are needed to run the demo. 15 | 16 | CC = emcc 17 | CXX = em++ 18 | WEB_DIR = web 19 | EXE = $(WEB_DIR)/index.html 20 | IMGUI_DIR = ../.. 21 | SOURCES = main.cpp 22 | SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp 23 | SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp 24 | OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) 25 | UNAME_S := $(shell uname -s) 26 | CPPFLAGS = 27 | LDFLAGS = 28 | EMS = 29 | 30 | ##--------------------------------------------------------------------- 31 | ## EMSCRIPTEN OPTIONS 32 | ##--------------------------------------------------------------------- 33 | 34 | # ("EMS" options gets added to both CPPFLAGS and LDFLAGS, whereas some options are for linker only) 35 | EMS += -s USE_SDL=2 36 | EMS += -s DISABLE_EXCEPTION_CATCHING=1 37 | LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 38 | 39 | # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) 40 | #EMS += -s BINARYEN_TRAP_MODE=clamp 41 | #EMS += -s SAFE_HEAP=1 ## Adds overhead 42 | 43 | # Emscripten allows preloading a file or folder to be accessible at runtime. 44 | # The Makefile for this example project suggests embedding the misc/fonts/ folder into our application, it will then be accessible as "/fonts" 45 | # See documentation for more details: https://emscripten.org/docs/porting/files/packaging_files.html 46 | # (Default value is 0. Set to 1 to enable file-system and include the misc/fonts/ folder as part of the build.) 47 | USE_FILE_SYSTEM ?= 0 48 | ifeq ($(USE_FILE_SYSTEM), 0) 49 | LDFLAGS += -s NO_FILESYSTEM=1 50 | CPPFLAGS += -DIMGUI_DISABLE_FILE_FUNCTIONS 51 | endif 52 | ifeq ($(USE_FILE_SYSTEM), 1) 53 | LDFLAGS += --no-heap-copy --preload-file ../../misc/fonts@/fonts 54 | endif 55 | 56 | ##--------------------------------------------------------------------- 57 | ## FINAL BUILD FLAGS 58 | ##--------------------------------------------------------------------- 59 | 60 | CPPFLAGS += -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends 61 | #CPPFLAGS += -g 62 | CPPFLAGS += -Wall -Wformat -Os $(EMS) 63 | LDFLAGS += --shell-file ../libs/emscripten/shell_minimal.html 64 | LDFLAGS += $(EMS) 65 | 66 | ##--------------------------------------------------------------------- 67 | ## BUILD RULES 68 | ##--------------------------------------------------------------------- 69 | 70 | %.o:%.cpp 71 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< 72 | 73 | %.o:$(IMGUI_DIR)/%.cpp 74 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< 75 | 76 | %.o:$(IMGUI_DIR)/backends/%.cpp 77 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< 78 | 79 | all: $(EXE) 80 | @echo Build complete for $(EXE) 81 | 82 | $(WEB_DIR): 83 | mkdir $@ 84 | 85 | serve: all 86 | python3 -m http.server -d $(WEB_DIR) 87 | 88 | $(EXE): $(OBJS) $(WEB_DIR) 89 | $(CXX) -o $@ $(OBJS) $(LDFLAGS) 90 | 91 | clean: 92 | rm -rf $(OBJS) $(WEB_DIR) 93 | -------------------------------------------------------------------------------- /lib/imgui/examples/example_sdl2_opengl3/README.md: -------------------------------------------------------------------------------- 1 | 2 | # How to Build 3 | 4 | ## Windows with Visual Studio's IDE 5 | 6 | Use the provided project file (.vcxproj). Add to solution (imgui_examples.sln) if necessary. 7 | 8 | ## Windows with Visual Studio's CLI 9 | 10 | Use build_win32.bat or directly: 11 | ``` 12 | set SDL2_DIR=path_to_your_sdl2_folder 13 | cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl2_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console 14 | # ^^ include paths ^^ source files ^^ output exe ^^ output dir ^^ libraries 15 | # or for 64-bit: 16 | cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl2_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x64 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console 17 | ``` 18 | 19 | ## Linux and similar Unixes 20 | 21 | Use our Makefile or directly: 22 | ``` 23 | c++ `sdl2-config --cflags` -I .. -I ../.. -I ../../backends 24 | main.cpp ../../backends/imgui_impl_sdl2.cpp ../../backends/imgui_impl_opengl3.cpp ../../imgui*.cpp 25 | `sdl2-config --libs` -lGL -ldl 26 | ``` 27 | 28 | ## macOS 29 | 30 | Use our Makefile or directly: 31 | ``` 32 | brew install sdl2 33 | c++ `sdl2-config --cflags` -I .. -I ../.. -I ../../backends 34 | main.cpp ../../backends/imgui_impl_sdl2.cpp ../../backends/imgui_impl_opengl3.cpp ../../imgui*.cpp 35 | `sdl2-config --libs` -framework OpenGl -framework CoreFoundation 36 | ``` 37 | 38 | ## Emscripten 39 | 40 | **Building** 41 | 42 | You need to install Emscripten from https://emscripten.org/docs/getting_started/downloads.html, and have the environment variables set, as described in https://emscripten.org/docs/getting_started/downloads.html#installation-instructions 43 | 44 | - Depending on your configuration, in Windows you may need to run `emsdk/emsdk_env.bat` in your console to access the Emscripten command-line tools. 45 | - You may also refer to our [Continuous Integration setup](https://github.com/ocornut/imgui/tree/master/.github/workflows) for Emscripten setup. 46 | - Then build using `make -f Makefile.emscripten` while in the current directory. 47 | 48 | **Running an Emscripten project** 49 | 50 | To run on a local machine: 51 | - `make -f Makefile.emscripten serve` will use Python3 to spawn a local webserver, you can then browse http://localhost:8000 to access your build. 52 | - Otherwise, generally you will need a local webserver. Quoting [https://emscripten.org/docs/getting_started](https://emscripten.org/docs/getting_started/Tutorial.html#generating-html):
53 | _"Unfortunately several browsers (including Chrome, Safari, and Internet Explorer) do not support file:// [XHR](https://emscripten.org/docs/site/glossary.html#term-xhr) requests, and can’t load extra files needed by the HTML (like a .wasm file, or packaged file data as mentioned lower down). For these browsers you’ll need to serve the files using a [local webserver](https://emscripten.org/docs/getting_started/FAQ.html#faq-local-webserver) and then open http://localhost:8000/hello.html."_ 54 | - Emscripten SDK has a handy `emrun` command: `emrun web/index.html --browser firefox` which will spawn a temporary local webserver (in Firefox). See https://emscripten.org/docs/compiling/Running-html-files-with-emrun.html for details. 55 | - You may use Python 3 builtin webserver: `python -m http.server -d web` (this is what `make serve` uses). 56 | - You may use Python 2 builtin webserver: `cd web && python -m SimpleHTTPServer`. 57 | - If you are accessing the files over a network, certain browsers, such as Firefox, will restrict Gamepad API access to secure contexts only (e.g. https only). 58 | -------------------------------------------------------------------------------- /lib/imgui/examples/example_sdl2_opengl3/build_win32.bat: -------------------------------------------------------------------------------- 1 | @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. 2 | @set OUT_DIR=Debug 3 | @set OUT_EXE=example_sdl2_opengl3 4 | @set INCLUDES=/I..\.. /I..\..\backends /I%SDL2_DIR%\include 5 | @set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp 6 | @set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib shell32.lib 7 | mkdir %OUT_DIR% 8 | cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console 9 | -------------------------------------------------------------------------------- /lib/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {BBAEB705-1669-40F3-8567-04CF6A991F4C} 23 | example_sdl2_opengl3 24 | 8.1 25 | 26 | 27 | 28 | Application 29 | true 30 | MultiByte 31 | v140 32 | 33 | 34 | Application 35 | true 36 | MultiByte 37 | v140 38 | 39 | 40 | Application 41 | false 42 | true 43 | MultiByte 44 | v140 45 | 46 | 47 | Application 48 | false 49 | true 50 | MultiByte 51 | v140 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | $(ProjectDir)$(Configuration)\ 71 | $(ProjectDir)$(Configuration)\ 72 | $(IncludePath) 73 | 74 | 75 | $(ProjectDir)$(Configuration)\ 76 | $(ProjectDir)$(Configuration)\ 77 | $(IncludePath) 78 | 79 | 80 | $(ProjectDir)$(Configuration)\ 81 | $(ProjectDir)$(Configuration)\ 82 | $(IncludePath) 83 | 84 | 85 | $(ProjectDir)$(Configuration)\ 86 | $(ProjectDir)$(Configuration)\ 87 | $(IncludePath) 88 | 89 | 90 | 91 | Level4 92 | Disabled 93 | ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) 94 | /utf-8 %(AdditionalOptions) 95 | 96 | 97 | true 98 | %SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories) 99 | opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies) 100 | Console 101 | msvcrt.lib 102 | 103 | 104 | 105 | 106 | Level4 107 | Disabled 108 | ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) 109 | /utf-8 %(AdditionalOptions) 110 | 111 | 112 | true 113 | %SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories) 114 | opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies) 115 | Console 116 | msvcrt.lib 117 | 118 | 119 | 120 | 121 | Level4 122 | MaxSpeed 123 | true 124 | true 125 | ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) 126 | false 127 | /utf-8 %(AdditionalOptions) 128 | 129 | 130 | true 131 | true 132 | true 133 | %SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories) 134 | opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies) 135 | Console 136 | 137 | 138 | 139 | 140 | 141 | 142 | Level4 143 | MaxSpeed 144 | true 145 | true 146 | ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) 147 | false 148 | /utf-8 %(AdditionalOptions) 149 | 150 | 151 | true 152 | true 153 | true 154 | %SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories) 155 | opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies) 156 | Console 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /lib/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {20b90ce4-7fcb-4731-b9a0-075f875de82d} 6 | 7 | 8 | {f18ab499-84e1-499f-8eff-9754361e0e52} 9 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 10 | 11 | 12 | 13 | 14 | imgui 15 | 16 | 17 | imgui 18 | 19 | 20 | imgui 21 | 22 | 23 | sources 24 | 25 | 26 | sources 27 | 28 | 29 | sources 30 | 31 | 32 | imgui 33 | 34 | 35 | imgui 36 | 37 | 38 | 39 | 40 | imgui 41 | 42 | 43 | imgui 44 | 45 | 46 | imgui 47 | 48 | 49 | sources 50 | 51 | 52 | sources 53 | 54 | 55 | sources 56 | 57 | 58 | 59 | 60 | 61 | imgui 62 | 63 | 64 | imgui 65 | 66 | 67 | -------------------------------------------------------------------------------- /lib/imgui/examples/example_sdl2_opengl3/main.cpp: -------------------------------------------------------------------------------- 1 | // Dear ImGui: standalone example application for SDL2 + OpenGL 2 | // (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) 3 | 4 | // Learn about Dear ImGui: 5 | // - FAQ https://dearimgui.com/faq 6 | // - Getting Started https://dearimgui.com/getting-started 7 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). 8 | // - Introduction, links and more at the top of imgui.cpp 9 | 10 | #include "imgui.h" 11 | #include "imgui_impl_sdl2.h" 12 | #include "imgui_impl_opengl3.h" 13 | #include 14 | #include 15 | #if defined(IMGUI_IMPL_OPENGL_ES2) 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | // This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details. 22 | #ifdef __EMSCRIPTEN__ 23 | #include "../libs/emscripten/emscripten_mainloop_stub.h" 24 | #endif 25 | 26 | // Main code 27 | int main(int, char**) 28 | { 29 | // Setup SDL 30 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) 31 | { 32 | printf("Error: %s\n", SDL_GetError()); 33 | return -1; 34 | } 35 | 36 | // Decide GL+GLSL versions 37 | #if defined(IMGUI_IMPL_OPENGL_ES2) 38 | // GL ES 2.0 + GLSL 100 39 | const char* glsl_version = "#version 100"; 40 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 41 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 42 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); 43 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 44 | #elif defined(__APPLE__) 45 | // GL 3.2 Core + GLSL 150 46 | const char* glsl_version = "#version 150"; 47 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac 48 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 49 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 50 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 51 | #else 52 | // GL 3.0 + GLSL 130 53 | const char* glsl_version = "#version 130"; 54 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 55 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 56 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 57 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 58 | #endif 59 | 60 | // From 2.0.18: Enable native IME. 61 | #ifdef SDL_HINT_IME_SHOW_UI 62 | SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); 63 | #endif 64 | 65 | // Create window with graphics context 66 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 67 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 68 | SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); 69 | SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); 70 | SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); 71 | if (window == nullptr) 72 | { 73 | printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); 74 | return -1; 75 | } 76 | 77 | SDL_GLContext gl_context = SDL_GL_CreateContext(window); 78 | SDL_GL_MakeCurrent(window, gl_context); 79 | SDL_GL_SetSwapInterval(1); // Enable vsync 80 | 81 | // Setup Dear ImGui context 82 | IMGUI_CHECKVERSION(); 83 | ImGui::CreateContext(); 84 | ImGuiIO& io = ImGui::GetIO(); (void)io; 85 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 86 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 87 | 88 | // Setup Dear ImGui style 89 | ImGui::StyleColorsDark(); 90 | //ImGui::StyleColorsLight(); 91 | 92 | // Setup Platform/Renderer backends 93 | ImGui_ImplSDL2_InitForOpenGL(window, gl_context); 94 | ImGui_ImplOpenGL3_Init(glsl_version); 95 | 96 | // Load Fonts 97 | // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. 98 | // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. 99 | // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). 100 | // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. 101 | // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. 102 | // - Read 'docs/FONTS.md' for more instructions and details. 103 | // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! 104 | // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. 105 | //io.Fonts->AddFontDefault(); 106 | //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); 107 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); 108 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); 109 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); 110 | //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); 111 | //IM_ASSERT(font != nullptr); 112 | 113 | // Our state 114 | bool show_demo_window = true; 115 | bool show_another_window = false; 116 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 117 | 118 | // Main loop 119 | bool done = false; 120 | #ifdef __EMSCRIPTEN__ 121 | // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. 122 | // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. 123 | io.IniFilename = nullptr; 124 | EMSCRIPTEN_MAINLOOP_BEGIN 125 | #else 126 | while (!done) 127 | #endif 128 | { 129 | // Poll and handle events (inputs, window resize, etc.) 130 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 131 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. 132 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. 133 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 134 | SDL_Event event; 135 | while (SDL_PollEvent(&event)) 136 | { 137 | ImGui_ImplSDL2_ProcessEvent(&event); 138 | if (event.type == SDL_QUIT) 139 | done = true; 140 | if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) 141 | done = true; 142 | } 143 | 144 | // Start the Dear ImGui frame 145 | ImGui_ImplOpenGL3_NewFrame(); 146 | ImGui_ImplSDL2_NewFrame(); 147 | ImGui::NewFrame(); 148 | 149 | // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). 150 | if (show_demo_window) 151 | ImGui::ShowDemoWindow(&show_demo_window); 152 | 153 | // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. 154 | { 155 | static float f = 0.0f; 156 | static int counter = 0; 157 | 158 | ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. 159 | 160 | ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) 161 | ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state 162 | ImGui::Checkbox("Another Window", &show_another_window); 163 | 164 | ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f 165 | ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color 166 | 167 | if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) 168 | counter++; 169 | ImGui::SameLine(); 170 | ImGui::Text("counter = %d", counter); 171 | 172 | ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); 173 | ImGui::End(); 174 | } 175 | 176 | // 3. Show another simple window. 177 | if (show_another_window) 178 | { 179 | ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) 180 | ImGui::Text("Hello from another window!"); 181 | if (ImGui::Button("Close Me")) 182 | show_another_window = false; 183 | ImGui::End(); 184 | } 185 | 186 | // Rendering 187 | ImGui::Render(); 188 | glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); 189 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); 190 | glClear(GL_COLOR_BUFFER_BIT); 191 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 192 | SDL_GL_SwapWindow(window); 193 | } 194 | #ifdef __EMSCRIPTEN__ 195 | EMSCRIPTEN_MAINLOOP_END; 196 | #endif 197 | 198 | // Cleanup 199 | ImGui_ImplOpenGL3_Shutdown(); 200 | ImGui_ImplSDL2_Shutdown(); 201 | ImGui::DestroyContext(); 202 | 203 | SDL_GL_DeleteContext(gl_context); 204 | SDL_DestroyWindow(window); 205 | SDL_Quit(); 206 | 207 | return 0; 208 | } 209 | -------------------------------------------------------------------------------- /lib/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // DEAR IMGUI COMPILE-TIME OPTIONS 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS. 32 | 33 | //---- Disable all of Dear ImGui or don't implement standard windows/tools. 34 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. 35 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 36 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. 37 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty. 38 | 39 | //---- Don't implement some functions to reduce linkage requirements. 40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 41 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 42 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 43 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). 44 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 45 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 46 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 47 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 48 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 49 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 50 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 51 | 52 | //---- Include imgui_user.h at the end of imgui.h as a convenience 53 | // May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included. 54 | //#define IMGUI_INCLUDE_IMGUI_USER_H 55 | //#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h" 56 | 57 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 58 | //#define IMGUI_USE_BGRA_PACKED_COLOR 59 | 60 | //---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 61 | //#define IMGUI_USE_WCHAR32 62 | 63 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 64 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 65 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 66 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 67 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined. 68 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 69 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 70 | //#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. 71 | 72 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 73 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. 74 | //#define IMGUI_USE_STB_SPRINTF 75 | 76 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 77 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 78 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 79 | #define IMGUI_ENABLE_FREETYPE 80 | 81 | //---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) 82 | // Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). 83 | // Only works in combination with IMGUI_ENABLE_FREETYPE. 84 | // (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) 85 | //#define IMGUI_ENABLE_FREETYPE_LUNASVG 86 | 87 | //---- Use stb_truetype to build and rasterize the font atlas (default) 88 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 89 | //#define IMGUI_ENABLE_STB_TRUETYPE 90 | 91 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 92 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 93 | /* 94 | #define IM_VEC2_CLASS_EXTRA \ 95 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ 96 | operator MyVec2() const { return MyVec2(x,y); } 97 | 98 | #define IM_VEC4_CLASS_EXTRA \ 99 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ 100 | operator MyVec4() const { return MyVec4(x,y,z,w); } 101 | */ 102 | //---- ...Or use Dear ImGui's own very basic math operators. 103 | //#define IMGUI_DEFINE_MATH_OPERATORS 104 | 105 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 106 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 107 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 108 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 109 | //#define ImDrawIdx unsigned int 110 | 111 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 112 | //struct ImDrawList; 113 | //struct ImDrawCmd; 114 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 115 | //#define ImDrawCallback MyImDrawCallback 116 | 117 | //---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) 118 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 119 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 120 | //#define IM_DEBUG_BREAK __debugbreak() 121 | 122 | //---- Debug Tools: Enable slower asserts 123 | //#define IMGUI_DEBUG_PARANOID 124 | 125 | //---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) 126 | /* 127 | namespace ImGui 128 | { 129 | void MyFunction(const char* name, MyMatrix44* mtx); 130 | } 131 | */ 132 | -------------------------------------------------------------------------------- /lib/imgui/misc/README.txt: -------------------------------------------------------------------------------- 1 | 2 | misc/cpp/ 3 | InputText() wrappers for C++ standard library (STL) type: std::string. 4 | This is also an example of how you may wrap your own similar types. 5 | 6 | misc/debuggers/ 7 | Helper files for popular debuggers. 8 | With the .natvis file, types like ImVector<> will be displayed nicely in Visual Studio debugger. 9 | 10 | misc/fonts/ 11 | Fonts loading/merging instructions (e.g. How to handle glyph ranges, how to merge icons fonts). 12 | Command line tool "binary_to_compressed_c" to create compressed arrays to embed data in source code. 13 | Suggested fonts and links. 14 | 15 | misc/freetype/ 16 | Font atlas builder/rasterizer using FreeType instead of stb_truetype. 17 | Benefit from better FreeType rasterization, in particular for small fonts. 18 | 19 | misc/single_file/ 20 | Single-file header stub. 21 | We use this to validate compiling all *.cpp files in a same compilation unit. 22 | Users of that technique (also called "Unity builds") can generally provide this themselves, 23 | so we don't really recommend you use this in your projects. 24 | -------------------------------------------------------------------------------- /lib/imgui/misc/debuggers/README.txt: -------------------------------------------------------------------------------- 1 | 2 | HELPER FILES FOR POPULAR DEBUGGERS 3 | 4 | imgui.gdb 5 | GDB: disable stepping into trivial functions. 6 | (read comments inside file for details) 7 | 8 | imgui.natstepfilter 9 | Visual Studio Debugger: disable stepping into trivial functions. 10 | (read comments inside file for details) 11 | 12 | imgui.natvis 13 | Visual Studio Debugger: describe Dear ImGui types for better display. 14 | With this, types like ImVector<> will be displayed nicely in the debugger. 15 | (read comments inside file for details) 16 | 17 | -------------------------------------------------------------------------------- /lib/imgui/misc/debuggers/imgui.gdb: -------------------------------------------------------------------------------- 1 | # GDB configuration to aid debugging experience 2 | 3 | # To enable these customizations edit $HOME/.gdbinit (or ./.gdbinit if local gdbinit is enabled) and add: 4 | # add-auto-load-safe-path /path/to/imgui.gdb 5 | # source /path/to/imgui.gdb 6 | # 7 | # More Information at: 8 | # * https://sourceware.org/gdb/current/onlinedocs/gdb/gdbinit-man.html 9 | # * https://sourceware.org/gdb/current/onlinedocs/gdb/Init-File-in-the-Current-Directory.html#Init-File-in-the-Current-Directory 10 | 11 | # Disable stepping into trivial functions 12 | skip -rfunction Im(Vec2|Vec4|Strv|Vector|Span)::.+ 13 | -------------------------------------------------------------------------------- /lib/imgui/misc/debuggers/imgui.natstepfilter: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | (ImVec2|ImVec4|ImStrv)::.+ 24 | NoStepInto 25 | 26 | 27 | (ImVector|ImSpan).*::operator.+ 28 | NoStepInto 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /lib/imgui/misc/debuggers/imgui.natvis: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | {{Size={Size} Capacity={Capacity}}} 18 | 19 | 20 | Size 21 | Data 22 | 23 | 24 | 25 | 26 | 27 | {{Size={DataEnd-Data} }} 28 | 29 | 30 | DataEnd-Data 31 | Data 32 | 33 | 34 | 35 | 36 | 37 | {{x={x,g} y={y,g}}} 38 | 39 | 40 | 41 | {{x={x,g} y={y,g} z={z,g} w={w,g}}} 42 | 43 | 44 | 45 | {{Min=({Min.x,g} {Min.y,g}) Max=({Max.x,g} {Max.y,g}) Size=({Max.x-Min.x,g} {Max.y-Min.y,g})}} 46 | 47 | Min 48 | Max 49 | Max.x - Min.x 50 | Max.y - Min.y 51 | 52 | 53 | 54 | 55 | {{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /lib/imgui/misc/fonts/binary_to_compressed_c.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui 2 | // (binary_to_compressed_c.cpp) 3 | // Helper tool to turn a file into a C array, if you want to embed font data in your source code. 4 | 5 | // The data is first compressed with stb_compress() to reduce source code size, 6 | // then encoded in Base85 to fit in a string so we can fit roughly 4 bytes of compressed data into 5 bytes of source code (suggested by @mmalex) 7 | // (If we used 32-bit constants it would require take 11 bytes of source code to encode 4 bytes, and be endianness dependent) 8 | // Note that even with compression, the output array is likely to be bigger than the binary file.. 9 | // Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF() 10 | 11 | // Build with, e.g: 12 | // # cl.exe binary_to_compressed_c.cpp 13 | // # g++ binary_to_compressed_c.cpp 14 | // # clang++ binary_to_compressed_c.cpp 15 | // You can also find a precompiled Windows binary in the binary/demo package available from https://github.com/ocornut/imgui 16 | 17 | // Usage: 18 | // binary_to_compressed_c.exe [-base85] [-nocompress] [-nostatic] 19 | // Usage example: 20 | // # binary_to_compressed_c.exe myfont.ttf MyFont > myfont.cpp 21 | // # binary_to_compressed_c.exe -base85 myfont.ttf MyFont > myfont.cpp 22 | 23 | #define _CRT_SECURE_NO_WARNINGS 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | // stb_compress* from stb.h - declaration 30 | typedef unsigned int stb_uint; 31 | typedef unsigned char stb_uchar; 32 | stb_uint stb_compress(stb_uchar* out, stb_uchar* in, stb_uint len); 33 | 34 | static bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression, bool use_static); 35 | 36 | int main(int argc, char** argv) 37 | { 38 | if (argc < 3) 39 | { 40 | printf("Syntax: %s [-base85] [-nocompress] [-nostatic] \n", argv[0]); 41 | return 0; 42 | } 43 | 44 | int argn = 1; 45 | bool use_base85_encoding = false; 46 | bool use_compression = true; 47 | bool use_static = true; 48 | while (argn < (argc - 2) && argv[argn][0] == '-') 49 | { 50 | if (strcmp(argv[argn], "-base85") == 0) { use_base85_encoding = true; argn++; } 51 | else if (strcmp(argv[argn], "-nocompress") == 0) { use_compression = false; argn++; } 52 | else if (strcmp(argv[argn], "-nostatic") == 0) { use_static = false; argn++; } 53 | else 54 | { 55 | fprintf(stderr, "Unknown argument: '%s'\n", argv[argn]); 56 | return 1; 57 | } 58 | } 59 | 60 | bool ret = binary_to_compressed_c(argv[argn], argv[argn + 1], use_base85_encoding, use_compression, use_static); 61 | if (!ret) 62 | fprintf(stderr, "Error opening or reading file: '%s'\n", argv[argn]); 63 | return ret ? 0 : 1; 64 | } 65 | 66 | char Encode85Byte(unsigned int x) 67 | { 68 | x = (x % 85) + 35; 69 | return (char)((x >= '\\') ? x + 1 : x); 70 | } 71 | 72 | bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression, bool use_static) 73 | { 74 | // Read file 75 | FILE* f = fopen(filename, "rb"); 76 | if (!f) return false; 77 | int data_sz; 78 | if (fseek(f, 0, SEEK_END) || (data_sz = (int)ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) { fclose(f); return false; } 79 | char* data = new char[data_sz + 4]; 80 | if (fread(data, 1, data_sz, f) != (size_t)data_sz) { fclose(f); delete[] data; return false; } 81 | memset((void*)(((char*)data) + data_sz), 0, 4); 82 | fclose(f); 83 | 84 | // Compress 85 | int maxlen = data_sz + 512 + (data_sz >> 2) + sizeof(int); // total guess 86 | char* compressed = use_compression ? new char[maxlen] : data; 87 | int compressed_sz = use_compression ? stb_compress((stb_uchar*)compressed, (stb_uchar*)data, data_sz) : data_sz; 88 | if (use_compression) 89 | memset(compressed + compressed_sz, 0, maxlen - compressed_sz); 90 | 91 | // Output as Base85 encoded 92 | FILE* out = stdout; 93 | fprintf(out, "// File: '%s' (%d bytes)\n", filename, (int)data_sz); 94 | fprintf(out, "// Exported using binary_to_compressed_c.cpp\n"); 95 | const char* static_str = use_static ? "static " : ""; 96 | const char* compressed_str = use_compression ? "compressed_" : ""; 97 | if (use_base85_encoding) 98 | { 99 | fprintf(out, "%sconst char %s_%sdata_base85[%d+1] =\n \"", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*5); 100 | char prev_c = 0; 101 | for (int src_i = 0; src_i < compressed_sz; src_i += 4) 102 | { 103 | // This is made a little more complicated by the fact that ??X sequences are interpreted as trigraphs by old C/C++ compilers. So we need to escape pairs of ??. 104 | unsigned int d = *(unsigned int*)(compressed + src_i); 105 | for (unsigned int n5 = 0; n5 < 5; n5++, d /= 85) 106 | { 107 | char c = Encode85Byte(d); 108 | fprintf(out, (c == '?' && prev_c == '?') ? "\\%c" : "%c", c); 109 | prev_c = c; 110 | } 111 | if ((src_i % 112) == 112 - 4) 112 | fprintf(out, "\"\n \""); 113 | } 114 | fprintf(out, "\";\n\n"); 115 | } 116 | else 117 | { 118 | fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz); 119 | fprintf(out, "%sconst unsigned int %s_%sdata[%d/4] =\n{", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*4); 120 | int column = 0; 121 | for (int i = 0; i < compressed_sz; i += 4) 122 | { 123 | unsigned int d = *(unsigned int*)(compressed + i); 124 | if ((column++ % 12) == 0) 125 | fprintf(out, "\n 0x%08x, ", d); 126 | else 127 | fprintf(out, "0x%08x, ", d); 128 | } 129 | fprintf(out, "\n};\n\n"); 130 | } 131 | 132 | // Cleanup 133 | delete[] data; 134 | if (use_compression) 135 | delete[] compressed; 136 | return true; 137 | } 138 | 139 | // stb_compress* from stb.h - definition 140 | 141 | //////////////////// compressor /////////////////////// 142 | 143 | static stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen) 144 | { 145 | const unsigned long ADLER_MOD = 65521; 146 | unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; 147 | unsigned long blocklen, i; 148 | 149 | blocklen = buflen % 5552; 150 | while (buflen) { 151 | for (i=0; i + 7 < blocklen; i += 8) { 152 | s1 += buffer[0], s2 += s1; 153 | s1 += buffer[1], s2 += s1; 154 | s1 += buffer[2], s2 += s1; 155 | s1 += buffer[3], s2 += s1; 156 | s1 += buffer[4], s2 += s1; 157 | s1 += buffer[5], s2 += s1; 158 | s1 += buffer[6], s2 += s1; 159 | s1 += buffer[7], s2 += s1; 160 | 161 | buffer += 8; 162 | } 163 | 164 | for (; i < blocklen; ++i) 165 | s1 += *buffer++, s2 += s1; 166 | 167 | s1 %= ADLER_MOD, s2 %= ADLER_MOD; 168 | buflen -= blocklen; 169 | blocklen = 5552; 170 | } 171 | return (s2 << 16) + s1; 172 | } 173 | 174 | static unsigned int stb_matchlen(stb_uchar *m1, stb_uchar *m2, stb_uint maxlen) 175 | { 176 | stb_uint i; 177 | for (i=0; i < maxlen; ++i) 178 | if (m1[i] != m2[i]) return i; 179 | return i; 180 | } 181 | 182 | // simple implementation that just takes the source data in a big block 183 | 184 | static stb_uchar *stb__out; 185 | static FILE *stb__outfile; 186 | static stb_uint stb__outbytes; 187 | 188 | static void stb__write(unsigned char v) 189 | { 190 | fputc(v, stb__outfile); 191 | ++stb__outbytes; 192 | } 193 | 194 | //#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v))) 195 | #define stb_out(v) do { if (stb__out) *stb__out++ = (stb_uchar) (v); else stb__write((stb_uchar) (v)); } while (0) 196 | 197 | static void stb_out2(stb_uint v) { stb_out(v >> 8); stb_out(v); } 198 | static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); } 199 | static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16); stb_out(v >> 8 ); stb_out(v); } 200 | 201 | static void outliterals(stb_uchar *in, int numlit) 202 | { 203 | while (numlit > 65536) { 204 | outliterals(in,65536); 205 | in += 65536; 206 | numlit -= 65536; 207 | } 208 | 209 | if (numlit == 0) ; 210 | else if (numlit <= 32) stb_out (0x000020 + numlit-1); 211 | else if (numlit <= 2048) stb_out2(0x000800 + numlit-1); 212 | else /* numlit <= 65536) */ stb_out3(0x070000 + numlit-1); 213 | 214 | if (stb__out) { 215 | memcpy(stb__out,in,numlit); 216 | stb__out += numlit; 217 | } else 218 | fwrite(in, 1, numlit, stb__outfile); 219 | } 220 | 221 | static int stb__window = 0x40000; // 256K 222 | 223 | static int stb_not_crap(int best, int dist) 224 | { 225 | return ((best > 2 && dist <= 0x00100) 226 | || (best > 5 && dist <= 0x04000) 227 | || (best > 7 && dist <= 0x80000)); 228 | } 229 | 230 | static stb_uint stb__hashsize = 32768; 231 | 232 | // note that you can play with the hashing functions all you 233 | // want without needing to change the decompressor 234 | #define stb__hc(q,h,c) (((h) << 7) + ((h) >> 25) + q[c]) 235 | #define stb__hc2(q,h,c,d) (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d]) 236 | #define stb__hc3(q,c,d,e) ((q[c] << 14) + (q[d] << 7) + q[e]) 237 | 238 | static unsigned int stb__running_adler; 239 | 240 | static int stb_compress_chunk(stb_uchar *history, 241 | stb_uchar *start, 242 | stb_uchar *end, 243 | int length, 244 | int *pending_literals, 245 | stb_uchar **chash, 246 | stb_uint mask) 247 | { 248 | (void)history; 249 | int window = stb__window; 250 | stb_uint match_max; 251 | stb_uchar *lit_start = start - *pending_literals; 252 | stb_uchar *q = start; 253 | 254 | #define STB__SCRAMBLE(h) (((h) + ((h) >> 16)) & mask) 255 | 256 | // stop short of the end so we don't scan off the end doing 257 | // the hashing; this means we won't compress the last few bytes 258 | // unless they were part of something longer 259 | while (q < start+length && q+12 < end) { 260 | int m; 261 | stb_uint h1,h2,h3,h4, h; 262 | stb_uchar *t; 263 | int best = 2, dist=0; 264 | 265 | if (q+65536 > end) 266 | match_max = (stb_uint)(end-q); 267 | else 268 | match_max = 65536; 269 | 270 | #define stb__nc(b,d) ((d) <= window && ((b) > 9 || stb_not_crap((int)(b),(int)(d)))) 271 | 272 | #define STB__TRY(t,p) /* avoid retrying a match we already tried */ \ 273 | if (p ? dist != (int)(q-t) : 1) \ 274 | if ((m = stb_matchlen(t, q, match_max)) > best) \ 275 | if (stb__nc(m,q-(t))) \ 276 | best = m, dist = (int)(q - (t)) 277 | 278 | // rather than search for all matches, only try 4 candidate locations, 279 | // chosen based on 4 different hash functions of different lengths. 280 | // this strategy is inspired by LZO; hashing is unrolled here using the 281 | // 'hc' macro 282 | h = stb__hc3(q,0, 1, 2); h1 = STB__SCRAMBLE(h); 283 | t = chash[h1]; if (t) STB__TRY(t,0); 284 | h = stb__hc2(q,h, 3, 4); h2 = STB__SCRAMBLE(h); 285 | h = stb__hc2(q,h, 5, 6); t = chash[h2]; if (t) STB__TRY(t,1); 286 | h = stb__hc2(q,h, 7, 8); h3 = STB__SCRAMBLE(h); 287 | h = stb__hc2(q,h, 9,10); t = chash[h3]; if (t) STB__TRY(t,1); 288 | h = stb__hc2(q,h,11,12); h4 = STB__SCRAMBLE(h); 289 | t = chash[h4]; if (t) STB__TRY(t,1); 290 | 291 | // because we use a shared hash table, can only update it 292 | // _after_ we've probed all of them 293 | chash[h1] = chash[h2] = chash[h3] = chash[h4] = q; 294 | 295 | if (best > 2) 296 | assert(dist > 0); 297 | 298 | // see if our best match qualifies 299 | if (best < 3) { // fast path literals 300 | ++q; 301 | } else if (best > 2 && best <= 0x80 && dist <= 0x100) { 302 | outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best); 303 | stb_out(0x80 + best-1); 304 | stb_out(dist-1); 305 | } else if (best > 5 && best <= 0x100 && dist <= 0x4000) { 306 | outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best); 307 | stb_out2(0x4000 + dist-1); 308 | stb_out(best-1); 309 | } else if (best > 7 && best <= 0x100 && dist <= 0x80000) { 310 | outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best); 311 | stb_out3(0x180000 + dist-1); 312 | stb_out(best-1); 313 | } else if (best > 8 && best <= 0x10000 && dist <= 0x80000) { 314 | outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best); 315 | stb_out3(0x100000 + dist-1); 316 | stb_out2(best-1); 317 | } else if (best > 9 && dist <= 0x1000000) { 318 | if (best > 65536) best = 65536; 319 | outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best); 320 | if (best <= 0x100) { 321 | stb_out(0x06); 322 | stb_out3(dist-1); 323 | stb_out(best-1); 324 | } else { 325 | stb_out(0x04); 326 | stb_out3(dist-1); 327 | stb_out2(best-1); 328 | } 329 | } else { // fallback literals if no match was a balanced tradeoff 330 | ++q; 331 | } 332 | } 333 | 334 | // if we didn't get all the way, add the rest to literals 335 | if (q-start < length) 336 | q = start+length; 337 | 338 | // the literals are everything from lit_start to q 339 | *pending_literals = (int)(q - lit_start); 340 | 341 | stb__running_adler = stb_adler32(stb__running_adler, start, (stb_uint)(q - start)); 342 | return (int)(q - start); 343 | } 344 | 345 | static int stb_compress_inner(stb_uchar *input, stb_uint length) 346 | { 347 | int literals = 0; 348 | stb_uint len,i; 349 | 350 | stb_uchar **chash; 351 | chash = (stb_uchar**) malloc(stb__hashsize * sizeof(stb_uchar*)); 352 | if (chash == nullptr) return 0; // failure 353 | for (i=0; i < stb__hashsize; ++i) 354 | chash[i] = nullptr; 355 | 356 | // stream signature 357 | stb_out(0x57); stb_out(0xbc); 358 | stb_out2(0); 359 | 360 | stb_out4(0); // 64-bit length requires 32-bit leading 0 361 | stb_out4(length); 362 | stb_out4(stb__window); 363 | 364 | stb__running_adler = 1; 365 | 366 | len = stb_compress_chunk(input, input, input+length, length, &literals, chash, stb__hashsize-1); 367 | assert(len == length); 368 | 369 | outliterals(input+length - literals, literals); 370 | 371 | free(chash); 372 | 373 | stb_out2(0x05fa); // end opcode 374 | 375 | stb_out4(stb__running_adler); 376 | 377 | return 1; // success 378 | } 379 | 380 | stb_uint stb_compress(stb_uchar *out, stb_uchar *input, stb_uint length) 381 | { 382 | stb__out = out; 383 | stb__outfile = nullptr; 384 | 385 | stb_compress_inner(input, length); 386 | 387 | return (stb_uint)(stb__out - out); 388 | } 389 | -------------------------------------------------------------------------------- /lib/imgui/misc/freetype/README.md: -------------------------------------------------------------------------------- 1 | # imgui_freetype 2 | 3 | Build font atlases using FreeType instead of stb_truetype (which is the default font rasterizer). 4 |
by @vuhdo, @mikesart, @ocornut. 5 | 6 | ### Usage 7 | 8 | 1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype --triplet=x64-windows`, `vcpkg integrate install`). 9 | 2. Add imgui_freetype.h/cpp alongside your project files. 10 | 3. Add `#define IMGUI_ENABLE_FREETYPE` in your [imconfig.h](https://github.com/ocornut/imgui/blob/master/imconfig.h) file 11 | 12 | ### About Gamma Correct Blending 13 | 14 | FreeType assumes blending in linear space rather than gamma space. 15 | See FreeType note for [FT_Render_Glyph](https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_render_glyph). 16 | For correct results you need to be using sRGB and convert to linear space in the pixel shader output. 17 | The default Dear ImGui styles will be impacted by this change (alpha values will need tweaking). 18 | 19 | ### Testbed for toying with settings (for developers) 20 | 21 | See https://gist.github.com/ocornut/b3a9ecf13502fd818799a452969649ad 22 | 23 | ### Known issues 24 | 25 | - Oversampling settings are ignored but also not so much necessary with the higher quality rendering. 26 | 27 | ### Comparison 28 | 29 | Small, thin anti-aliased fonts typically benefit a lot from FreeType's hinting: 30 | ![comparing_font_rasterizers](https://user-images.githubusercontent.com/8225057/107550178-fef87f00-6bd0-11eb-8d09-e2edb2f0ccfc.gif) 31 | 32 | ### Colorful glyphs/emojis 33 | 34 | You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain colorful glyphs. See the 35 | ["Using Colorful Glyphs/Emojis"](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#using-colorful-glyphsemojis) section of FONTS.md. 36 | 37 | ![colored glyphs](https://user-images.githubusercontent.com/8225057/106171241-9dc4ba80-6191-11eb-8a69-ca1467b206d1.png) 38 | 39 | ### Using OpenType SVG fonts (SVGinOT) 40 | - *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations. 41 | - Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT 42 | - Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above 43 | 1. Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`. 44 | 2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. 45 | -------------------------------------------------------------------------------- /lib/imgui/misc/freetype/imgui_freetype.h: -------------------------------------------------------------------------------- 1 | // dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder) 2 | // (headers) 3 | 4 | #pragma once 5 | #include "imgui.h" // IMGUI_API 6 | #ifndef IMGUI_DISABLE 7 | 8 | // Forward declarations 9 | struct ImFontAtlas; 10 | struct ImFontBuilderIO; 11 | 12 | // Hinting greatly impacts visuals (and glyph sizes). 13 | // - By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter. 14 | // - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h 15 | // - The Default hinting mode usually looks good, but may distort glyphs in an unusual way. 16 | // - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. 17 | // You can set those flags globaly in ImFontAtlas::FontBuilderFlags 18 | // You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags 19 | enum ImGuiFreeTypeBuilderFlags 20 | { 21 | ImGuiFreeTypeBuilderFlags_NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. 22 | ImGuiFreeTypeBuilderFlags_NoAutoHint = 1 << 1, // Disable auto-hinter. 23 | ImGuiFreeTypeBuilderFlags_ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter. 24 | ImGuiFreeTypeBuilderFlags_LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. 25 | ImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. 26 | ImGuiFreeTypeBuilderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font? 27 | ImGuiFreeTypeBuilderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style? 28 | ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results! 29 | ImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8, // Enable FreeType color-layered glyphs 30 | ImGuiFreeTypeBuilderFlags_Bitmap = 1 << 9 // Enable FreeType bitmap glyphs 31 | }; 32 | 33 | namespace ImGuiFreeType 34 | { 35 | // This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'. 36 | // If you need to dynamically select between multiple builders: 37 | // - you can manually assign this builder with 'atlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()' 38 | // - prefer deep-copying this into your own ImFontBuilderIO instance if you use hot-reloading that messes up static data. 39 | IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType(); 40 | 41 | // Override allocators. By default ImGuiFreeType will use IM_ALLOC()/IM_FREE() 42 | // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired. 43 | IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = nullptr); 44 | 45 | // Obsolete names (will be removed soon) 46 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 47 | //static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE' 48 | #endif 49 | } 50 | 51 | #endif // #ifndef IMGUI_DISABLE 52 | -------------------------------------------------------------------------------- /lib/portable-file-dialogs/COPYING: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /lib/portable-file-dialogs/portable-file-dialogs.cpp: -------------------------------------------------------------------------------- 1 | #include "portable-file-dialogs.hpp" 2 | #include "portable-file-dialogs-impl.h" 3 | 4 | #include 5 | #include 6 | 7 | bool pfd::Settings::available() { return settings::available(); } 8 | void pfd::Settings::verbose(bool value) { settings::verbose(value); } 9 | void pfd::Settings::rescan() { settings::rescan(); } 10 | 11 | 12 | pfd::Notify::Notify( 13 | std::string const &title, 14 | std::string const &message, 15 | Icon t_icon) 16 | : impl{new pfd::notify{title, message, icon(int(t_icon))}} {} 17 | 18 | pfd::Notify::~Notify() { delete impl; } 19 | 20 | bool pfd::Notify::ready(int timeout) const { return impl->ready(timeout); } 21 | bool pfd::Notify::kill() const { return impl->kill(); } 22 | 23 | 24 | pfd::Message::Message( 25 | std::string const &title, 26 | std::string const &text, 27 | Choice t_choice, 28 | Icon t_icon) 29 | : impl{new pfd::message{title, text, choice(int(t_choice)), icon(int(t_icon))}} {} 30 | 31 | pfd::Message::~Message() { delete impl; } 32 | 33 | bool pfd::Message::ready(int timeout) const { return impl->ready(timeout); } 34 | bool pfd::Message::kill() const { return impl->kill(); } 35 | pfd::Button pfd::Message::result() const { return Button(int(impl->result())); } 36 | 37 | 38 | pfd::OpenFile::OpenFile(std::string const &title, 39 | std::string const &default_path, 40 | std::vector const &filters, 41 | Option options) 42 | : impl{new open_file{title, default_path, filters, opt(uint8_t(options))}} {} 43 | 44 | pfd::OpenFile::~OpenFile() { delete impl; } 45 | 46 | bool pfd::OpenFile::ready(int timeout) const { return impl->ready(timeout); } 47 | bool pfd::OpenFile::kill() const { return impl->kill(); } 48 | std::vector pfd::OpenFile::result() const { return impl->result(); } 49 | 50 | 51 | pfd::SaveFile::SaveFile( 52 | std::string const &title, 53 | std::string const &default_path, 54 | std::vector const &filters, 55 | Option options) 56 | : impl{new save_file{title, default_path, filters, opt(uint8_t(options))}} {} 57 | 58 | pfd::SaveFile::~SaveFile() { delete impl; } 59 | 60 | bool pfd::SaveFile::ready(int timeout) const { return impl->ready(timeout); } 61 | bool pfd::SaveFile::kill() const { return impl->kill(); } 62 | std::string pfd::SaveFile::result() const { return impl->result(); } 63 | 64 | 65 | pfd::SelectFolder::SelectFolder( 66 | std::string const &title, 67 | std::string const &default_path, 68 | Option options) 69 | : impl{new select_folder{title, default_path, opt(uint8_t(options))}} {} 70 | 71 | pfd::SelectFolder::~SelectFolder() { delete impl; } 72 | 73 | bool pfd::SelectFolder::ready(int timeout) const { return impl->ready(timeout); } 74 | bool pfd::SelectFolder::kill() const { return impl->kill(); } 75 | std::string pfd::SelectFolder::result() const { return impl->result(); } 76 | -------------------------------------------------------------------------------- /lib/portable-file-dialogs/portable-file-dialogs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace pfd 8 | { 9 | class notify; 10 | class message; 11 | class open_file; 12 | class save_file; 13 | class select_folder; 14 | 15 | enum class Button 16 | { 17 | cancel = -1, 18 | ok, 19 | yes, 20 | no, 21 | abort, 22 | retry, 23 | ignore, 24 | }; 25 | 26 | enum class Choice 27 | { 28 | ok = 0, 29 | ok_cancel, 30 | yes_no, 31 | yes_no_cancel, 32 | retry_cancel, 33 | abort_retry_ignore, 34 | }; 35 | 36 | enum class Icon 37 | { 38 | info = 0, 39 | warning, 40 | error, 41 | question, 42 | }; 43 | 44 | enum class Option : uint8_t 45 | { 46 | none = 0, 47 | // For file open, allow multiselect. 48 | multiselect = 0x1, 49 | // For file save, force overwrite and disable the confirmation dialog. 50 | force_overwrite = 0x2, 51 | // For folder select, force path to be the provided argument instead 52 | // of the last opened directory, which is the Microsoft-recommended, 53 | // user-friendly behaviour. 54 | force_path = 0x4, 55 | }; 56 | 57 | inline Option operator |(Option a, Option b) { return Option(uint8_t(a) | uint8_t(b)); } 58 | inline bool operator &(Option a, Option b) { return bool(uint8_t(a) & uint8_t(b)); } 59 | 60 | 61 | class Settings 62 | { 63 | public: 64 | static int const default_wait_timeout = 20; 65 | static bool available(); 66 | static void verbose(bool value); 67 | static void rescan(); 68 | }; 69 | 70 | class Notify 71 | { 72 | public: 73 | Notify(std::string const &title, std::string const &message, Icon icon = Icon::info); 74 | ~Notify(); 75 | bool ready(int timeout = Settings::default_wait_timeout) const; 76 | bool kill() const; 77 | private: 78 | notify* impl; 79 | }; 80 | 81 | class Message 82 | { 83 | public: 84 | Message(std::string const &title, std::string const &text, Choice choice = Choice::ok_cancel, Icon icon = Icon::info); 85 | ~Message(); 86 | bool ready(int timeout = Settings::default_wait_timeout) const; 87 | bool kill() const; 88 | Button result() const; 89 | private: 90 | message* impl; 91 | }; 92 | 93 | class OpenFile 94 | { 95 | public: 96 | OpenFile(std::string const &title, 97 | std::string const &default_path = "", 98 | std::vector const &filters = { "All Files", "*" }, 99 | Option options = Option::none); 100 | ~OpenFile(); 101 | bool ready(int timeout = Settings::default_wait_timeout) const; 102 | bool kill() const; 103 | std::vector result() const; 104 | private: 105 | open_file* impl; 106 | }; 107 | 108 | class SaveFile 109 | { 110 | public: 111 | SaveFile(std::string const &title, 112 | std::string const &default_path = "", 113 | std::vector const &filters = { "All Files", "*" }, 114 | Option options = Option::none); 115 | ~SaveFile(); 116 | bool ready(int timeout = Settings::default_wait_timeout) const; 117 | bool kill() const; 118 | std::string result() const; 119 | private: 120 | save_file* impl; 121 | }; 122 | 123 | class SelectFolder 124 | { 125 | public: 126 | SelectFolder(std::string const &title, 127 | std::string const &default_path = "", 128 | Option options = Option::none); 129 | ~SelectFolder(); 130 | bool ready(int timeout = Settings::default_wait_timeout) const; 131 | bool kill() const; 132 | std::string result() const; 133 | private: 134 | select_folder* impl; 135 | }; 136 | } -------------------------------------------------------------------------------- /lib/stb/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Sean Barrett 2 | Permission is hereby granted, free of charge, to any person obtaining a copy of 3 | this software and associated documentation files (the "Software"), to deal in 4 | the Software without restriction, including without limitation the rights to 5 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 6 | of the Software, and to permit persons to whom the Software is furnished to do 7 | so, subject to the following conditions: 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 16 | SOFTWARE. 17 | -------------------------------------------------------------------------------- /misc/fonts/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faresbakhit/ayin/d4a03e5060f20891895dd168d05e964505b5fc4d/misc/fonts/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /misc/fonts/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faresbakhit/ayin/d4a03e5060f20891895dd168d05e964505b5fc4d/misc/fonts/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /misc/icon/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faresbakhit/ayin/d4a03e5060f20891895dd168d05e964505b5fc4d/misc/icon/icon.ico -------------------------------------------------------------------------------- /misc/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faresbakhit/ayin/d4a03e5060f20891895dd168d05e964505b5fc4d/misc/icon/icon.png -------------------------------------------------------------------------------- /misc/icon/icon.rc: -------------------------------------------------------------------------------- 1 | ID_BPS_ICON ICON "icon.ico" 2 | -------------------------------------------------------------------------------- /misc/readme/ayin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faresbakhit/ayin/d4a03e5060f20891895dd168d05e964505b5fc4d/misc/readme/ayin.png -------------------------------------------------------------------------------- /misc/readme/honest-work.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faresbakhit/ayin/d4a03e5060f20891895dd168d05e964505b5fc4d/misc/readme/honest-work.jpg -------------------------------------------------------------------------------- /src/Application.cpp: -------------------------------------------------------------------------------- 1 | #include "Application.hpp" 2 | #include "fonts/MaterialIcons.hpp" 3 | #include "fonts/MaterialIconsFont.hpp" 4 | #include "fonts/OpenSansFont.hpp" 5 | #ifdef _WIN32 6 | #include "utils/win32.hpp" 7 | #endif 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace ayin; 16 | 17 | Application::Application(const std::string &title) { 18 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { 19 | throw std::runtime_error(SDL_GetError()); 20 | } 21 | 22 | // Decide GL+GLSL versions 23 | #if defined(IMGUI_IMPL_OPENGL_ES2) 24 | // GL ES 2.0 + GLSL 100 25 | const char *glsl_version = "#version 100"; 26 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 27 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 28 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); 29 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 30 | #elif defined(__APPLE__) 31 | // GL 3.2 Core + GLSL 150 32 | const char *glsl_version = "#version 150"; 33 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 34 | SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac 35 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 36 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 37 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 38 | #else 39 | // GL 3.0 + GLSL 130 40 | const char *glsl_version = "#version 130"; 41 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 42 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 43 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 44 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 45 | #endif 46 | 47 | // From 2.0.18: Enable native IME. 48 | #ifdef SDL_HINT_IME_SHOW_UI 49 | SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); 50 | #endif 51 | 52 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 53 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 54 | SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); 55 | sdl_window = 56 | SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, 57 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED | SDL_WINDOW_ALLOW_HIGHDPI); 58 | 59 | if (sdl_window == nullptr) { 60 | throw std::runtime_error(SDL_GetError()); 61 | } 62 | 63 | gl_context = SDL_GL_CreateContext(sdl_window); 64 | if (gl_context == NULL) { 65 | throw std::runtime_error(SDL_GetError()); 66 | } 67 | if (SDL_GL_MakeCurrent(sdl_window, gl_context) < 0) { 68 | throw std::runtime_error(SDL_GetError()); 69 | }; 70 | SDL_GL_SetSwapInterval(1); 71 | 72 | IMGUI_CHECKVERSION(); 73 | ImGui::CreateContext(); 74 | io = &ImGui::GetIO(); 75 | io->IniFilename = nullptr; 76 | io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; 77 | 78 | ImGui_ImplSDL2_InitForOpenGL(sdl_window, gl_context); 79 | ImGui_ImplOpenGL3_Init(glsl_version); 80 | 81 | const float font_size = 18.0f; 82 | io->Fonts->AddFontFromMemoryCompressedTTF(OpenSansFont_compressed_data, OpenSansFont_compressed_size, font_size); 83 | static const ImWchar icons_ranges[] = {ICON_MIN_MD, ICON_MAX_16_MD, 0}; 84 | ImFontConfig icons_config; 85 | icons_config.MergeMode = true; 86 | icons_config.PixelSnapH = true; 87 | icons_config.GlyphMinAdvanceX = font_size * 2.0f / 3.0f; // font size (px) 88 | io->Fonts->AddFontFromMemoryCompressedTTF(MaterialIconsFont_compressed_data, MaterialIconsFont_compressed_size, 89 | icons_config.GlyphMinAdvanceX, // font size (px) 90 | &icons_config, icons_ranges); 91 | 92 | #ifdef _WIN32 93 | SDL_AddTimer(0, utils::win32::AutoImGuiStyleColorsSDLTimerCallback, sdl_window); 94 | #else 95 | ImGui::StyleColorsDark(); 96 | #endif 97 | } 98 | 99 | Application::~Application() { 100 | ImGui_ImplOpenGL3_Shutdown(); 101 | ImGui_ImplSDL2_Shutdown(); 102 | ImGui::DestroyContext(NULL); 103 | 104 | SDL_GL_DeleteContext(gl_context); 105 | SDL_DestroyWindow(sdl_window); 106 | SDL_Quit(); 107 | } 108 | 109 | void Application::new_frame() { 110 | ImGui_ImplOpenGL3_NewFrame(); 111 | ImGui_ImplSDL2_NewFrame(); 112 | ImGui::NewFrame(); 113 | } 114 | 115 | void Application::add_photo(const std::string &filepath) { 116 | Image *image = new Image(); 117 | std::string name = std::filesystem::path(filepath).filename().string(); 118 | std::ostringstream name_suffix; 119 | 120 | auto pred = [&](std::unique_ptr &photo) { return photo->name == name + name_suffix.str(); }; 121 | int name_suffix_i = 1; 122 | while (std::find_if(photos.begin(), photos.end(), pred) != photos.end()) { 123 | name_suffix.str(""); 124 | name_suffix << " (" << name_suffix_i++ << ")"; 125 | } 126 | 127 | image->load(filepath.c_str()); 128 | image->load_texture(); 129 | 130 | std::unique_ptr photo = std::make_unique(); 131 | photo->image = image; 132 | photo->origImage = new Image(*image); 133 | photo->name = name + name_suffix.str(); 134 | photo->filepath = filepath; 135 | 136 | photos.push_back(std::move(photo)); 137 | } 138 | 139 | Photo *Application::get_selected_photo() { return photos[m_selectedPhotoIndex].get(); } 140 | 141 | void Application::set_selected_photo(size_t index) { 142 | m_selectedPhotoIndex = std::clamp(index, (size_t)0, (size_t)(photos.size() - 1)); 143 | } 144 | 145 | void Application::open_file_dialog() { 146 | auto selection = pfd::OpenFile("Open", "", pfdImageFile, pfd::Option::multiselect).result(); 147 | for (auto it = selection.begin(); it != selection.end(); ++it) { 148 | std::string filepath = *it; 149 | add_photo(filepath); 150 | } 151 | } 152 | 153 | void Application::save_file_dialog(Photo &photo) { 154 | auto selection = pfd::SaveFile("Save As...", "", pfdImageFile, pfd::Option::none).result(); 155 | if (selection.empty()) { 156 | return; 157 | } 158 | if (photo.image->save(selection.c_str())) { 159 | pfd::Notify("Error: Save", "An error happened", pfd::Icon::error); 160 | } 161 | } 162 | 163 | InputRequest Application::handle_input() { 164 | static bool zoomin = false; 165 | static bool zoomout = false; 166 | SDL_Event event; 167 | Uint32 window_flags = SDL_GetWindowFlags(sdl_window); 168 | while (SDL_PollEvent(&event)) { 169 | ImGui_ImplSDL2_ProcessEvent(&event); 170 | switch (event.type) { 171 | case SDL_QUIT: 172 | done = true; 173 | break; 174 | case SDL_KEYDOWN: 175 | if (event.key.keysym.sym == SDLK_F11) { 176 | if ((window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { 177 | SDL_SetWindowFullscreen(sdl_window, 0); 178 | } else { 179 | SDL_SetWindowFullscreen(sdl_window, SDL_WINDOW_FULLSCREEN_DESKTOP); 180 | } 181 | } else if (event.key.keysym.mod & KMOD_CTRL) { 182 | if (event.key.keysym.sym == SDLK_o) { 183 | open_file_dialog(); 184 | } else if (event.key.keysym.sym == SDLK_w) { 185 | photos.erase(photos.begin() + m_selectedPhotoIndex); 186 | if (m_selectedPhotoIndex > 0) 187 | m_selectedPhotoIndex -= 1; 188 | } else if (event.key.keysym.mod & KMOD_SHIFT && (event.key.keysym.sym == SDLK_s)) { 189 | return InputRequest(InputRequest_SaveAs); 190 | } else if (event.key.keysym.sym == SDLK_s) { 191 | return InputRequest(InputRequest_Save); 192 | } else if (event.key.keysym.sym == SDLK_q) { 193 | done = true; 194 | } else if (event.key.keysym.sym == SDLK_z) { 195 | return InputRequest(InputRequest_Undo); 196 | } else if (event.key.keysym.sym == SDLK_y) { 197 | return InputRequest(InputRequest_Redo); 198 | } else if (event.key.keysym.sym == SDLK_EQUALS) { 199 | zoomin = true; 200 | } else if (event.key.keysym.sym == SDLK_MINUS) { 201 | zoomout = true; 202 | } 203 | } 204 | break; 205 | case SDL_KEYUP: 206 | if (event.key.keysym.mod & SDLK_LCTRL) { 207 | if (event.key.keysym.sym == SDLK_EQUALS) { 208 | zoomin = false; 209 | } else if (event.key.keysym.sym == SDLK_MINUS) { 210 | zoomout = false; 211 | } 212 | } 213 | break; 214 | default: 215 | break; 216 | } 217 | } 218 | 219 | if (zoomin) { 220 | return InputRequest(InputRequest_ZoomIn); 221 | } 222 | 223 | if (zoomout) { 224 | return InputRequest(InputRequest_ZoomOut); 225 | } 226 | 227 | return InputRequest(InputRequest_None); 228 | } 229 | 230 | void Application::render() { 231 | ImGui::Render(); 232 | glViewport(0, 0, (int)io->DisplaySize.x, (int)io->DisplaySize.y); 233 | ImVec4 clear_color = ImGui::GetStyleColorVec4(ImGuiCol_PopupBg); 234 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, 235 | clear_color.w); 236 | glClear(GL_COLOR_BUFFER_BIT); 237 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 238 | SDL_GL_SwapWindow(sdl_window); 239 | } 240 | -------------------------------------------------------------------------------- /src/Application.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Photo.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #if defined(IMGUI_IMPL_OPENGL_ES2) 15 | #include 16 | #else 17 | #include 18 | #endif 19 | #include 20 | 21 | namespace ayin { 22 | 23 | const std::vector pfdImageFile = {"All Picture Files (*.bmp;*.jpg;*.jpeg;*.png;*.psd)", 24 | "*.bmp *.dib *.jpg *.jpeg *.jpe *.jfif *.gif *.png *.psd"}; 25 | 26 | enum InputRequest_ { 27 | InputRequest_ZoomIn, 28 | InputRequest_ZoomOut, 29 | InputRequest_Save, 30 | InputRequest_SaveAs, 31 | InputRequest_Undo, 32 | InputRequest_Redo, 33 | InputRequest_None, 34 | }; 35 | 36 | struct InputRequest { 37 | InputRequest_ ty; 38 | union { 39 | int tab_number; 40 | }; 41 | InputRequest(InputRequest_ ty) : ty(ty) {} 42 | InputRequest(InputRequest_ ty, int tab_number) : ty(ty), tab_number(tab_number) {} 43 | }; 44 | 45 | class Application { 46 | public: 47 | std::vector> photos; 48 | ImGuiIO *io = nullptr; 49 | bool done = false; 50 | 51 | Application(const std::string &title); 52 | ~Application(); 53 | void new_frame(); 54 | void add_photo(const std::string &filepath); 55 | Photo *get_selected_photo(); 56 | void set_selected_photo(size_t index); 57 | void open_file_dialog(); 58 | void save_file_dialog(Photo &photo); 59 | void render(); 60 | InputRequest handle_input(); 61 | 62 | private: 63 | SDL_GLContext gl_context = nullptr; 64 | SDL_Window *sdl_window = nullptr; 65 | size_t m_selectedPhotoIndex = 0; 66 | }; 67 | } // namespace ayin 68 | -------------------------------------------------------------------------------- /src/Commands.cpp: -------------------------------------------------------------------------------- 1 | #include "Commands.hpp" 2 | #include "Application.hpp" 3 | #include "ImageFilter.hpp" 4 | 5 | #include 6 | #include 7 | 8 | using namespace ayin::Commands; 9 | 10 | Info::Info(Type ty) : ty(ty) {} 11 | 12 | Info::Info(Type ty, int darkenlighten_factor) : ty(ty), darkenlighten_factor(darkenlighten_factor) {} 13 | 14 | Info::Info(Type ty, int frame_fanciness, unsigned int frame_color) 15 | : ty(ty), frame_fanciness(frame_fanciness), frame_color(frame_color) {} 16 | 17 | Info::Info(Type ty, const char *merge_image) : ty(ty), merge_image(merge_image) {} 18 | 19 | Info::Info(Type ty, int crop_x, int crop_y, int crop_width, int crop_height) 20 | : ty(ty), crop_x(crop_x), crop_y(crop_y), crop_width(crop_width), crop_height(crop_height) {} 21 | 22 | Info::Info(Type ty, int resize_width, int resize_height) 23 | : ty(ty), resize_width(resize_width), resize_height(resize_height) {} 24 | 25 | Base::~Base() { delete tmpImage; } 26 | 27 | void Grayscale::setImage(Image &image) { 28 | ImageFilter::Grayscale(image); 29 | image.update_texture(); 30 | done = true; 31 | } 32 | 33 | Info Grayscale::getInfo() { return Info(Type_Grayscale); } 34 | 35 | void BlackAndWhite::setImage(Image &image) { 36 | ImageFilter::BlackAndWhite(image); 37 | image.update_texture(); 38 | done = true; 39 | } 40 | 41 | Info BlackAndWhite::getInfo() { return Info(Type_BlackAndWhite); } 42 | 43 | void Invert::setImage(Image &image) { 44 | ImageFilter::Invert(image); 45 | image.update_texture(); 46 | done = true; 47 | } 48 | 49 | Info Invert::getInfo() { return Info(Type_Invert); } 50 | 51 | void Merge::setImage(Image &image) { 52 | auto selection = pfd::OpenFile("Open", "", pfdImageFile, pfd::Option::multiselect).result(); 53 | 54 | if (selection.empty()) { 55 | done = true; 56 | return; 57 | } 58 | 59 | m_mergeImageFilename = selection[0].c_str(); 60 | Image *image2 = new Image(); 61 | image2->load(m_mergeImageFilename); 62 | ImageFilter::Merge(image, *image2); 63 | image.update_texture(); 64 | delete image2; 65 | done = true; 66 | } 67 | 68 | Info Merge::getInfo() { return Info(Type_Merge, m_mergeImageFilename); } 69 | 70 | void FlipHorizontally::setImage(Image &image) { 71 | ImageFilter::FlipHorizontally(image); 72 | image.update_texture(); 73 | done = true; 74 | } 75 | 76 | Info FlipHorizontally::getInfo() { return Info(Type_FlipHorizontally); } 77 | 78 | void FlipVertically::setImage(Image &image) { 79 | ImageFilter::FlipVertically(image); 80 | image.update_texture(); 81 | done = true; 82 | } 83 | 84 | Info FlipVertically::getInfo() { return Info(Type_FlipVertically); } 85 | 86 | void Rotate::setImage(Image &image) { 87 | ImageFilter::Rotate(image); 88 | if (image.width == image.height) { 89 | image.update_texture(); 90 | } else { 91 | image.load_texture(); 92 | } 93 | } 94 | 95 | Info Rotate::getInfo() { return Info(Type_Rotate); } 96 | 97 | void DarkenAndLighten::setImage(Image &image) { 98 | tmpImage = new Image(image.width, image.height, image.channels); 99 | memcpy(tmpImage->data, image.data, image.width * image.height * image.channels); 100 | tmpImage->load_texture(); 101 | this->image = ℑ 102 | } 103 | 104 | bool DarkenAndLighten::hasOptionsMenu() { return true; } 105 | 106 | void DarkenAndLighten::showOptionsMenu() { 107 | if (ImGui::SliderInt("Brightness", &factor, 0, 200)) { 108 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 109 | ImageFilter::ChangeBrightness(*tmpImage, factor); 110 | tmpImage->update_texture(); 111 | } 112 | if (ImGui::Button("Apply brightness")) { 113 | std::swap(image->data, tmpImage->data); 114 | image->update_texture(); 115 | done = true; 116 | } 117 | } 118 | 119 | Info DarkenAndLighten::getInfo() { return Info(Type_DarkenAndLighten, factor); } 120 | 121 | void Crop::setImage(Image &image) { 122 | tmpImage = new Image(image.width, image.height, image.channels); 123 | memcpy(tmpImage->data, image.data, image.width * image.height * image.channels); 124 | tmpImage->load_texture(); 125 | this->image = ℑ 126 | m_width = image.width; 127 | m_height = image.height; 128 | } 129 | 130 | bool Crop::hasOptionsMenu() { return true; } 131 | 132 | void Crop::showOptionsMenu() { 133 | bool update_frame = false; 134 | if (ImGui::SliderInt("Width", &m_width, 0, image->width - m_x)) { 135 | update_frame = true; 136 | } 137 | if (ImGui::SliderInt("Height", &m_height, 0, image->height - m_y)) { 138 | update_frame = true; 139 | } 140 | if (ImGui::SliderInt("X", &m_x, 0, image->width - m_width)) { 141 | update_frame = true; 142 | } 143 | if (ImGui::SliderInt("Y", &m_y, 0, image->height - m_height)) { 144 | update_frame = true; 145 | } 146 | if (update_frame) { 147 | unsigned char color[3] = {255, 0, 0}; 148 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 149 | ImageFilter::DrawRectangle(*tmpImage, m_x, m_y, m_width, m_height, 10, color); 150 | tmpImage->update_texture(); 151 | } 152 | if (ImGui::Button("Apply crop")) { 153 | ImageFilter::Crop(*image, m_x, m_y, m_width, m_height); 154 | image->load_texture(); 155 | done = true; 156 | } 157 | } 158 | 159 | Info Crop::getInfo() { return Info(Type_Crop, m_x, m_y, m_width, m_height); } 160 | 161 | void Frame::setImage(Image &image) { 162 | tmpImage = new Image(image.width, image.height, image.channels); 163 | memcpy(tmpImage->data, image.data, image.width * image.height * image.channels); 164 | ImU32 pcolor = ImGui::ColorConvertFloat4ToU32(color); 165 | ImageFilter::Frame(*tmpImage, fanciness, pcolor); 166 | tmpImage->load_texture(); 167 | this->image = ℑ 168 | } 169 | 170 | bool Frame::hasOptionsMenu() { return true; } 171 | 172 | void Frame::showOptionsMenu() { 173 | bool update_frame = false; 174 | if (ImGui::RadioButton("Simple", &fanciness, 1)) { 175 | update_frame = true; 176 | } 177 | ImGui::SameLine(); 178 | if (ImGui::RadioButton("Fancy", &fanciness, 2)) { 179 | update_frame = true; 180 | } 181 | ImGui::SameLine(); 182 | if (ImGui::RadioButton("Very Fancy", &fanciness, 3)) { 183 | update_frame = true; 184 | } 185 | if (ImGui::ColorPicker3("Frame Color", (float *)&color, ImGuiColorEditFlags_DisplayRGB)) { 186 | update_frame = true; 187 | } 188 | if (ImGui::Button("Apply frame")) { 189 | std::swap(image->data, tmpImage->data); 190 | image->update_texture(); 191 | done = true; 192 | } 193 | if (update_frame) { 194 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 195 | ImU32 pcolor = ImGui::ColorConvertFloat4ToU32(color); 196 | ImageFilter::Frame(*tmpImage, fanciness, pcolor); 197 | tmpImage->load_texture(); 198 | } 199 | } 200 | 201 | Info Frame::getInfo() { 202 | ImU32 pcolor = ImGui::ColorConvertFloat4ToU32(color); 203 | return Info(Type_Frame, fanciness, pcolor); 204 | } 205 | 206 | void DetectEdges::setImage(Image &image) { 207 | ImageFilter::DetectEdges(image); 208 | image.update_texture(); 209 | done = true; 210 | } 211 | 212 | Info DetectEdges::getInfo() { return Info(Type_DetectEdges); } 213 | 214 | void Resize::setImage(Image &image) { 215 | this->image = ℑ 216 | m_width = image.width; 217 | m_height = image.height; 218 | } 219 | 220 | bool Resize::hasOptionsMenu() { return true; } 221 | 222 | void Resize::showOptionsMenu() { 223 | bool update_frame = false; 224 | if (ImGui::SliderInt("Width", &m_width, 1, image->width * 2, "%d", ImGuiSliderFlags_AlwaysClamp)) { 225 | update_frame = true; 226 | } 227 | if (ImGui::SliderInt("Height", &m_height, 1, image->height * 2, "%d", ImGuiSliderFlags_AlwaysClamp)) { 228 | update_frame = true; 229 | } 230 | if (update_frame) { 231 | delete tmpImage; 232 | tmpImage = new Image(image->width, image->height, image->channels); 233 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 234 | ImageFilter::Resize(*tmpImage, m_width, m_height); 235 | tmpImage->load_texture(); 236 | } 237 | if (ImGui::Button("Apply resize")) { 238 | image->width = tmpImage->width; 239 | image->height = tmpImage->height; 240 | std::swap(image->data, tmpImage->data); 241 | std::swap(image->texture, tmpImage->texture); 242 | done = true; 243 | } 244 | } 245 | 246 | Info Resize::getInfo() { return Info(Type_Resize, m_width, m_height); } 247 | 248 | void Blur::setImage(Image &image) { 249 | tmpImage = new Image(image.width, image.height, image.channels); 250 | memcpy(tmpImage->data, image.data, image.width * image.height * image.channels); 251 | ImageFilter::Blur(*tmpImage, m_blurLevel); 252 | tmpImage->load_texture(); 253 | this->image = ℑ 254 | } 255 | 256 | bool Blur::hasOptionsMenu() { return true; } 257 | 258 | void Blur::showOptionsMenu() { 259 | if (ImGui::SliderInt("Blur Level", &m_blurLevel, 1, 10)) { 260 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 261 | ImageFilter::Blur(*tmpImage, m_blurLevel); 262 | tmpImage->update_texture(); 263 | } 264 | if (ImGui::Button("Apply blur")) { 265 | std::swap(image->data, tmpImage->data); 266 | image->update_texture(); 267 | done = true; 268 | } 269 | } 270 | 271 | Info Blur::getInfo() { return Info(Type_Blur, m_blurLevel); } 272 | 273 | void Sunlight::setImage(Image &image) { 274 | ImageFilter::Sunlight(image); 275 | image.update_texture(); 276 | done = true; 277 | } 278 | 279 | Info Sunlight::getInfo() { return Info(Type_Sunlight); } 280 | 281 | void OilPaint::setImage(Image &image) { 282 | ImageFilter::OilPaint(image); 283 | image.update_texture(); 284 | done = true; 285 | } 286 | 287 | Info OilPaint::getInfo() { return Info(Type_OilPaint); } 288 | 289 | void Purple::setImage(Image &image) { 290 | ImageFilter::Purple(image); 291 | image.update_texture(); 292 | done = true; 293 | } 294 | 295 | Info Purple::getInfo() { return Info(Type_Purple); } 296 | 297 | void Infrared::setImage(Image &image) { 298 | ImageFilter::Infrared(image); 299 | image.update_texture(); 300 | done = true; 301 | } 302 | 303 | Info Infrared::getInfo() { return Info(Type_Infrared); } 304 | 305 | void Skew::setImage(Image &image) { 306 | tmpImage = new Image(image.width, image.height, image.channels); 307 | memcpy(tmpImage->data, image.data, image.width * image.height * image.channels); 308 | ImageFilter::Skew(*tmpImage, m_skewAngle); 309 | tmpImage->load_texture(); 310 | this->image = ℑ 311 | } 312 | 313 | bool Skew::hasOptionsMenu() { return true; } 314 | 315 | void Skew::showOptionsMenu() { 316 | if (ImGui::SliderInt("Angle", &m_skewAngle, -89, 89, "%d", ImGuiSliderFlags_AlwaysClamp)) { 317 | delete tmpImage; 318 | tmpImage = new Image(image->width, image->height, image->channels); 319 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 320 | if (m_skewAngle != 0) { 321 | ImageFilter::Skew(*tmpImage, m_skewAngle); 322 | } 323 | tmpImage->load_texture(); 324 | } 325 | if (ImGui::Button("Apply skew")) { 326 | std::swap(image->data, tmpImage->data); 327 | image->width = tmpImage->width; 328 | image->load_texture(); 329 | done = true; 330 | } 331 | } 332 | 333 | Info Skew::getInfo() { return Info(Type_Skew, m_skewAngle); } 334 | 335 | void Glasses3D::setImage(Image &image) { 336 | tmpImage = new Image(image.width, image.height, image.channels); 337 | memcpy(tmpImage->data, image.data, image.width * image.height * image.channels); 338 | intensity = 10; 339 | ImageFilter::Glasses3D(*tmpImage, intensity); 340 | tmpImage->load_texture(); 341 | this->image = ℑ 342 | } 343 | 344 | bool Glasses3D::hasOptionsMenu() { return true; } 345 | 346 | void Glasses3D::showOptionsMenu() { 347 | if (ImGui::SliderInt("Intensity", &intensity, 0, 50)) { 348 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 349 | ImageFilter::Glasses3D(*tmpImage, intensity); 350 | tmpImage->update_texture(); 351 | } 352 | if (ImGui::Button("Apply effect")) { 353 | std::swap(image->data, tmpImage->data); 354 | image->update_texture(); 355 | done = true; 356 | } 357 | } 358 | 359 | Info Glasses3D::getInfo() { return Info(Type_Glasses3D, intensity); } 360 | 361 | void MotionBlur::setImage(Image &image) { 362 | tmpImage = new Image(image.width, image.height, image.channels); 363 | memcpy(tmpImage->data, image.data, image.width * image.height * image.channels); 364 | m_blurLevel = 9; 365 | ImageFilter::MotionBlur(*tmpImage, m_blurLevel); 366 | tmpImage->load_texture(); 367 | this->image = ℑ 368 | } 369 | 370 | bool MotionBlur::hasOptionsMenu() { return true; } 371 | 372 | void MotionBlur::showOptionsMenu() { 373 | if (ImGui::SliderInt("Blur Level", &m_blurLevel, 1, 21)) { 374 | memcpy(tmpImage->data, image->data, image->width * image->height * image->channels); 375 | ImageFilter::MotionBlur(*tmpImage, m_blurLevel); 376 | tmpImage->update_texture(); 377 | } 378 | if (ImGui::Button("Apply blur")) { 379 | std::swap(image->data, tmpImage->data); 380 | image->update_texture(); 381 | done = true; 382 | } 383 | } 384 | 385 | Info MotionBlur::getInfo() { return Info(Type_MotionBlur, m_blurLevel); } 386 | 387 | void Emboss::setImage(Image &image) { 388 | ImageFilter::Emboss(image); 389 | image.update_texture(); 390 | done = true; 391 | } 392 | 393 | Info Emboss::getInfo() { return Info(Type_Emboss); } 394 | -------------------------------------------------------------------------------- /src/Commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Image.hpp" 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace ayin::Commands { 10 | enum Type { 11 | Type_Grayscale, 12 | Type_BlackAndWhite, 13 | Type_Invert, 14 | Type_Merge, 15 | Type_FlipHorizontally, 16 | Type_FlipVertically, 17 | Type_Rotate, 18 | Type_DarkenAndLighten, 19 | Type_Crop, 20 | Type_Frame, 21 | Type_DetectEdges, 22 | Type_Resize, 23 | Type_Blur, 24 | Type_Sunlight, 25 | Type_OilPaint, 26 | Type_Purple, 27 | Type_Infrared, 28 | Type_Skew, 29 | Type_Glasses3D, 30 | Type_MotionBlur, 31 | Type_Emboss, 32 | }; 33 | 34 | struct Info { 35 | Type ty; 36 | union { 37 | int darkenlighten_factor; 38 | struct { 39 | int crop_x, crop_y, crop_width, crop_height; 40 | }; 41 | struct { 42 | int frame_fanciness; 43 | unsigned int frame_color; 44 | }; 45 | struct { 46 | int resize_width, resize_height; 47 | }; 48 | int blur_level; 49 | const char *merge_image; 50 | int skew_angle; 51 | }; 52 | Info() = default; 53 | Info(Type ty); 54 | Info(Type ty, int); 55 | Info(Type ty, int frame_fanciness, unsigned int frame_color); 56 | Info(Type ty, int resize_width, int resize_height); 57 | Info(Type ty, const char *merge_image); 58 | Info(Type ty, int crop_x, int crop_y, int crop_width, int crop_height); 59 | }; 60 | 61 | class Base { 62 | public: 63 | bool done = false; 64 | Image *image = nullptr; 65 | Image *tmpImage = nullptr; 66 | 67 | virtual ~Base(); 68 | virtual void setImage(Image &image) = 0; 69 | virtual bool hasOptionsMenu() { return false; }; 70 | virtual void showOptionsMenu(){}; 71 | virtual Info getInfo() = 0; 72 | }; 73 | 74 | class Grayscale : public Base { 75 | public: 76 | void setImage(Image &) override; 77 | Info getInfo() override; 78 | }; 79 | 80 | class BlackAndWhite : public Base { 81 | public: 82 | void setImage(Image &) override; 83 | Info getInfo() override; 84 | }; 85 | 86 | class Invert : public Base { 87 | public: 88 | void setImage(Image &) override; 89 | Info getInfo() override; 90 | }; 91 | 92 | class Merge : public Base { 93 | public: 94 | void setImage(Image &) override; 95 | Info getInfo() override; 96 | 97 | private: 98 | const char *m_mergeImageFilename; 99 | }; 100 | 101 | class FlipHorizontally : public Base { 102 | public: 103 | void setImage(Image &) override; 104 | Info getInfo() override; 105 | }; 106 | 107 | class FlipVertically : public Base { 108 | public: 109 | void setImage(Image &) override; 110 | Info getInfo() override; 111 | }; 112 | 113 | class Rotate : public Base { 114 | public: 115 | void setImage(Image &) override; 116 | Info getInfo() override; 117 | }; 118 | 119 | class DarkenAndLighten : public Base { 120 | public: 121 | void setImage(Image &) override; 122 | bool hasOptionsMenu() override; 123 | void showOptionsMenu() override; 124 | Info getInfo() override; 125 | 126 | private: 127 | int factor = 100; 128 | }; 129 | 130 | class Crop : public Base { 131 | public: 132 | void setImage(Image &) override; 133 | bool hasOptionsMenu() override; 134 | void showOptionsMenu() override; 135 | Info getInfo() override; 136 | 137 | private: 138 | int m_x, m_y, m_width, m_height; 139 | }; 140 | 141 | class Frame : public Base { 142 | public: 143 | void setImage(Image &) override; 144 | bool hasOptionsMenu() override; 145 | void showOptionsMenu() override; 146 | Info getInfo() override; 147 | 148 | private: 149 | int fanciness = 1; 150 | ImVec4 color{1.0f, 1.0f, 1.0f, 1.0f}; 151 | }; 152 | 153 | class DetectEdges : public Base { 154 | public: 155 | void setImage(Image &) override; 156 | Info getInfo() override; 157 | }; 158 | 159 | class Resize : public Base { 160 | public: 161 | void setImage(Image &) override; 162 | bool hasOptionsMenu() override; 163 | void showOptionsMenu() override; 164 | Info getInfo() override; 165 | 166 | private: 167 | int m_width, m_height; 168 | }; 169 | 170 | class Blur : public Base { 171 | public: 172 | void setImage(Image &) override; 173 | bool hasOptionsMenu() override; 174 | void showOptionsMenu() override; 175 | Info getInfo() override; 176 | 177 | private: 178 | int m_blurLevel = 5; 179 | }; 180 | 181 | class Sunlight : public Base { 182 | public: 183 | void setImage(Image &) override; 184 | Info getInfo() override; 185 | }; 186 | 187 | class OilPaint : public Base { 188 | public: 189 | void setImage(Image &) override; 190 | Info getInfo() override; 191 | }; 192 | 193 | // class CrtTV : public Base { 194 | // public: 195 | // }; 196 | 197 | class Purple : public Base { 198 | public: 199 | void setImage(Image &) override; 200 | Info getInfo() override; 201 | }; 202 | 203 | class Infrared : public Base { 204 | public: 205 | void setImage(Image &) override; 206 | Info getInfo() override; 207 | }; 208 | 209 | class Skew : public Base { 210 | public: 211 | void setImage(Image &) override; 212 | bool hasOptionsMenu() override; 213 | void showOptionsMenu() override; 214 | Info getInfo() override; 215 | 216 | private: 217 | int m_skewAngle = 45; 218 | }; 219 | 220 | class Glasses3D : public Base { 221 | public: 222 | void setImage(Image &) override; 223 | bool hasOptionsMenu() override; 224 | void showOptionsMenu() override; 225 | Info getInfo() override; 226 | 227 | private: 228 | int intensity; 229 | }; 230 | 231 | class MotionBlur : public Base { 232 | public: 233 | void setImage(Image &) override; 234 | bool hasOptionsMenu() override; 235 | void showOptionsMenu() override; 236 | Info getInfo() override; 237 | 238 | private: 239 | int m_blurLevel; 240 | }; 241 | 242 | class Emboss : public Base { 243 | public: 244 | void setImage(Image &) override; 245 | Info getInfo() override; 246 | }; 247 | 248 | inline extern const char *const names[]{ 249 | "Grayscale", "Black and White", "Invert", "Merge", "Flip Horizontally", "Flip Vertically", 250 | "Rotate", "Darken and Lighten", "Crop", "Frame", "Detect Edges", "Resize", 251 | "Blur", "Sunlight", "Oil Paint", "Purple", "Infrared", "Skew", 252 | "3D Glasses", "Motion Blur", "Emboss", 253 | }; 254 | 255 | inline extern const std::function factory[]{ 256 | []() { return new Grayscale(); }, []() { return new BlackAndWhite(); }, []() { return new Invert(); }, 257 | []() { return new Merge(); }, []() { return new FlipHorizontally(); }, []() { return new FlipVertically(); }, 258 | []() { return new Rotate(); }, []() { return new DarkenAndLighten(); }, []() { return new Crop(); }, 259 | []() { return new Frame(); }, []() { return new DetectEdges(); }, []() { return new Resize(); }, 260 | []() { return new Blur(); }, []() { return new Sunlight(); }, []() { return new OilPaint(); }, 261 | []() { return new Purple(); }, []() { return new Infrared(); }, []() { return new Skew(); }, 262 | []() { return new Glasses3D(); }, []() { return new MotionBlur(); }, []() { return new Emboss(); }, 263 | }; 264 | 265 | inline extern const int number = std::size(names); 266 | static_assert(std::size(factory) == number); 267 | } // namespace ayin::Commands 268 | -------------------------------------------------------------------------------- /src/Image.cpp: -------------------------------------------------------------------------------- 1 | #include "Image.hpp" 2 | 3 | #include 4 | 5 | #define STB_IMAGE_IMPLEMENTATION 6 | #include 7 | #define STB_IMAGE_WRITE_IMPLEMENTATION 8 | #include 9 | #include 10 | 11 | using namespace ayin; 12 | 13 | Image::Image(int width, int height, int channels) : width(width), height(height), channels(channels) { 14 | data = (unsigned char *)malloc(width * height * channels); 15 | } 16 | 17 | Image::Image(const Image &image) : Image(image.width, image.height, image.channels) { 18 | memcpy(data, image.data, width * height * channels); 19 | } 20 | 21 | Image::~Image() { 22 | #ifndef NDEBUG 23 | static int i = 0; 24 | printf("[DEBUG] %d Image::~Image()\n", ++i); 25 | #endif 26 | stbi_image_free(data); 27 | glDeleteTextures(1, &texture); 28 | } 29 | 30 | bool Image::load(const char *filename) { 31 | if (data != nullptr) { 32 | stbi_image_free(data); 33 | } 34 | if (texture) { 35 | glDeleteTextures(1, &texture); 36 | } 37 | data = stbi_load(filename, &width, &height, &channels, 0); 38 | return data != nullptr; 39 | } 40 | 41 | void Image::clear() { 42 | std::memset(data, 0, width * height * channels); 43 | } 44 | 45 | bool Image::save(const char *filename) { 46 | const char *extension = strrchr(filename, '.'); 47 | 48 | if (!extension) { 49 | return false; 50 | } 51 | 52 | if (strcmp(extension, ".png") == 0) { 53 | return stbi_write_png(filename, width, height, STBI_rgb, data, 0); 54 | } else if (strcmp(extension, ".bmp") == 0) { 55 | return stbi_write_bmp(filename, width, height, STBI_rgb, data); 56 | } else if (strcmp(extension, ".tga") == 0) { 57 | return stbi_write_tga(filename, width, height, STBI_rgb, data); 58 | } else if (strcmp(extension, ".jpg") == 0 || strcmp(extension, ".jpeg") == 0) { 59 | return stbi_write_jpg(filename, width, height, STBI_rgb, data, 90); 60 | } 61 | 62 | return false; 63 | } 64 | 65 | void Image::load_texture() { 66 | glDeleteTextures(1, &texture); 67 | 68 | GLint format = channels == 3 ? GL_RGB : GL_RGBA; 69 | glGenTextures(1, &texture); 70 | glBindTexture(GL_TEXTURE_2D, texture); 71 | 72 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 73 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 74 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 75 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 76 | 77 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 78 | glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); 79 | } 80 | 81 | void Image::update_texture() const { 82 | GLint format = channels == 3 ? GL_RGB : GL_RGBA; 83 | glBindTexture(GL_TEXTURE_2D, texture); 84 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 85 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE, data); 86 | } 87 | 88 | unsigned char &Image::operator()(int x, int y, int c) { return data[(y * width + x) * channels + c]; } 89 | 90 | const unsigned char &Image::operator()(int x, int y, int c) const { return data[(y * width + x) * channels + c]; } 91 | -------------------------------------------------------------------------------- /src/Image.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace ayin { 4 | struct Image { 5 | int width = 0; 6 | int height = 0; 7 | int channels = 0; 8 | unsigned char *data = nullptr; 9 | unsigned int texture = 0; 10 | 11 | Image() = default; 12 | Image(const Image &); 13 | Image(int width, int height, int channels); 14 | ~Image(); 15 | 16 | void clear(); 17 | bool load(const char *filename); 18 | bool save(const char *filename); 19 | 20 | void load_texture(); 21 | void update_texture() const; 22 | 23 | unsigned char &operator()(int x, int y, int c); 24 | const unsigned char &operator()(int x, int y, int c) const; 25 | }; 26 | } // namespace ayin 27 | -------------------------------------------------------------------------------- /src/ImageFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | #include "ImageFilter.hpp" 7 | 8 | using namespace ayin; 9 | 10 | void ImageFilter::Grayscale(Image &image) { 11 | for (int i = 0; i < image.width; i++) { 12 | for (int j = 0; j < image.height; j++) { 13 | int avg = (image(i, j, 0) + image(i, j, 1) + image(i, j, 2)) / 3; 14 | for (int k = 0; k < 3; k++) { 15 | image(i, j, k) = avg; 16 | } 17 | } 18 | } 19 | } 20 | 21 | void ImageFilter::BlackAndWhite(Image &image) { 22 | for (int i = 0; i < image.width; ++i) { 23 | for (int j = 0; j < image.height; ++j) { 24 | int r = image(i, j, 0); 25 | int g = image(i, j, 1); 26 | int b = image(i, j, 2); 27 | int grayScale = (r + g + b) / 3; 28 | if (grayScale > 128) { 29 | image(i, j, 0) = 255; 30 | image(i, j, 1) = 255; 31 | image(i, j, 2) = 255; 32 | } else { 33 | image(i, j, 0) = 0; 34 | image(i, j, 1) = 0; 35 | image(i, j, 2) = 0; 36 | } 37 | } 38 | } 39 | } 40 | 41 | void ImageFilter::Invert(Image &image) { 42 | for (int i = 0; i < image.width; ++i) { 43 | for (int j = 0; j < image.height; ++j) { 44 | for (int k = 0; k < 3; ++k) { 45 | image(i, j, k) = 0xFF - image(i, j, k); 46 | } 47 | } 48 | } 49 | } 50 | 51 | void ImageFilter::Rotate(Image &image) { 52 | Image flipped_image(image.height, image.width, image.channels); 53 | for (int i = 0; i < image.width; ++i) { 54 | for (int j = 0; j < image.height; ++j) { 55 | for (int k = 0; k < image.channels; ++k) { 56 | flipped_image(image.height - j, i, k) = image(i, j, k); 57 | } 58 | } 59 | } 60 | std::swap(image.data, flipped_image.data); 61 | std::swap(image.width, image.height); 62 | } 63 | 64 | void ImageFilter::DrawRectangle(Image &image, int x, int y, int width, int height, int thickness, 65 | unsigned char *color) { 66 | for (int i = 0; i < width; ++i) { 67 | for (int j = 0; j < thickness; ++j) { 68 | for (int k = 0; k < 3; ++k) { 69 | image(x + i, y + j, k) = color[k]; 70 | image(x + i, y + j + height - thickness, k) = color[k]; 71 | } 72 | } 73 | } 74 | for (int i = 0; i < thickness; ++i) { 75 | for (int j = thickness; j < (height - thickness); ++j) { 76 | for (int k = 0; k < 3; ++k) { 77 | image(x + i, y + j, k) = color[k]; 78 | image(x + i + width - thickness, y + j, k) = color[k]; 79 | } 80 | } 81 | } 82 | } 83 | 84 | static void DrawFilledRectangle(Image &image, int x, int y, int width, int height, unsigned char *color) { 85 | for (int i = 0; i < width; ++i) { 86 | for (int j = 0; j < height; ++j) { 87 | for (int k = 0; k < 3; ++k) { 88 | image(x + i, y + j, k) = color[k]; 89 | } 90 | } 91 | } 92 | } 93 | 94 | void ImageFilter::Frame(Image &image, int fanciness, unsigned int pcolor) { 95 | unsigned char color[3] = { 96 | (unsigned char)((pcolor >> 0) & 0xFF), 97 | (unsigned char)((pcolor >> 8) & 0xFF), 98 | (unsigned char)((pcolor >> 16) & 0xFF), 99 | }; 100 | unsigned char white[3] = {255, 255, 255}; 101 | int outer_frame_box_width = image.height / 32; // px 102 | int outer_frame_thickness = image.height / 64; // px 103 | int inner_frame_thickness = image.height / 96; // px 104 | int inner_inner_frame_thickness = image.height / 128; // px 105 | 106 | DrawRectangle(image, 0, 0, // x, y 107 | image.width, image.height, // width, height 108 | outer_frame_thickness, // thickness 109 | color); 110 | 111 | if (fanciness <= 1) { 112 | return; 113 | } 114 | 115 | DrawRectangle(image, outer_frame_thickness, outer_frame_thickness, // x, y 116 | image.width - 2 * outer_frame_thickness, // width 117 | image.height - 2 * outer_frame_thickness, // height 118 | inner_frame_thickness, // thickness 119 | white); 120 | 121 | DrawRectangle(image, outer_frame_thickness + 2 * inner_frame_thickness, 122 | outer_frame_thickness + 2 * inner_frame_thickness, // x, y 123 | image.width - 2 * outer_frame_thickness - 4 * inner_frame_thickness, // width 124 | image.height - 2 * outer_frame_thickness - 4 * inner_frame_thickness, // height 125 | inner_inner_frame_thickness, // thickness 126 | white); 127 | 128 | if (fanciness <= 2) { 129 | return; 130 | } 131 | 132 | for (int i = 0; i < 2; ++i) { 133 | for (int j = 0; j < 2; ++j) { 134 | DrawFilledRectangle(image, 135 | (1 - 2 * i) * (outer_frame_thickness + 2 * inner_frame_thickness) + 136 | i * (image.width - outer_frame_box_width), // x 137 | (1 - 2 * j) * (outer_frame_thickness + 2 * inner_frame_thickness) + 138 | j * (image.height - outer_frame_box_width), // y 139 | outer_frame_box_width, 140 | outer_frame_box_width, // width, height 141 | white); 142 | DrawRectangle(image, 143 | (1 - 2 * i) * (outer_frame_thickness + 2 * inner_frame_thickness) + 144 | i * (image.width - 2.4 * outer_frame_box_width), // x 145 | (1 - 2 * j) * (outer_frame_thickness + 2 * inner_frame_thickness) + 146 | j * (image.height - 2.4 * outer_frame_box_width), // y 147 | 2.4 * outer_frame_box_width, // width 148 | 2.4 * outer_frame_box_width, // height 149 | inner_frame_thickness, // thickness 150 | white); 151 | DrawRectangle(image, 152 | (1 - 2 * i) * (outer_frame_thickness + 2 * inner_frame_thickness) + 153 | i * (image.width - 1.7 * outer_frame_box_width), // x 154 | (1 - 2 * j) * (outer_frame_thickness + 2 * inner_frame_thickness) + 155 | j * (image.height - 1.7 * outer_frame_box_width), // y 156 | 1.7 * outer_frame_box_width, // width 157 | 1.7 * outer_frame_box_width, // height 158 | inner_inner_frame_thickness / 2, // thickness 159 | white); 160 | DrawFilledRectangle( 161 | image, 162 | i * ((1 - 2 * j) * outer_frame_thickness + j * (image.width - inner_frame_thickness)), // x 163 | !i * ((1 - 2 * j) * (outer_frame_thickness) + j * (image.height - inner_frame_thickness)), // y 164 | i * inner_frame_thickness + !i * image.width, // width 165 | i * image.height + !i * inner_frame_thickness, // height 166 | white); 167 | } 168 | } 169 | } 170 | 171 | void ImageFilter::FlipHorizontally(Image &image) { 172 | int width = image.width; 173 | int middle = width / 2; 174 | bool isEven = width % 2 == 0; 175 | int end = isEven ? middle - 2 : middle - 1; 176 | for (int i = 0; i < end; i++) { 177 | for (int j = 0; j < image.height; j++) { 178 | for (int c = 0; c < 3; c++) { 179 | int temp = image(i, j, c); 180 | image(i, j, c) = image(width - i - 1, j, c); 181 | image(width - i - 1, j, c) = temp; 182 | } 183 | } 184 | } 185 | if (isEven) { 186 | for (int j = 0; j < image.height; j++) { 187 | for (int c = 0; c < 3; c++) { 188 | int temp = image(middle, j, c); 189 | image(middle, j, c) = image(middle - 1, j, c); 190 | image(middle - 1, j, c) = temp; 191 | } 192 | } 193 | } 194 | } 195 | 196 | void ImageFilter::FlipVertically(Image &image) { 197 | int height = image.height; 198 | int middle = height / 2; 199 | bool isEven = height % 2 == 0; 200 | int end = isEven ? middle - 2 : middle - 1; 201 | for (int j = 0; j < end; j++) { 202 | for (int i = 0; i < image.width; ++i) { 203 | for (int c = 0; c < 3; c++) { 204 | int temp = image(i, j, c); 205 | image(i, j, c) = image(i, height - j - 1, c); 206 | image(i, height - j - 1, c) = temp; 207 | } 208 | } 209 | } 210 | if (isEven) { 211 | for (int i = 0; i < image.width; ++i) { 212 | for (int c = 0; c < 3; c++) { 213 | int temp = image(i, middle, c); 214 | image(i, middle, c) = image(i, middle - 1, c); 215 | image(i, middle - 1, c) = temp; 216 | } 217 | } 218 | } 219 | } 220 | 221 | void ImageFilter::Crop(Image &image, int x, int y, int width, int height) { 222 | Image cropped_image(width, height, image.channels); 223 | for (int i = x; i < x + width; i++) { 224 | for (int j = y; j < y + height; j++) { 225 | for (int k = 0; k < image.channels; k++) { 226 | cropped_image(i - x, j - y, k) = image(i, j, k); 227 | } 228 | } 229 | } 230 | std::swap(image.data, cropped_image.data); 231 | image.width = width; 232 | image.height = height; 233 | } 234 | 235 | void ImageFilter::Resize(Image &image, int w, int h) { 236 | Image result(w, h, image.channels); 237 | bool w_bigger = w > image.width; 238 | bool h_bigger = h > image.height; 239 | float ratio_w = w_bigger ? (float)image.width / (float)w : (float)w / (float)image.width; 240 | float ratio_h = h_bigger ? (float)image.height / (float)h : (float)h / (float)image.height; 241 | float end_w = w_bigger ? w : image.width; 242 | float end_h = h_bigger ? h : image.height; 243 | for (int i = 0; i < end_w; i++) { 244 | for (int j = 0; j < end_h; j++) { 245 | for (int c = 0; c < 3; c++) { 246 | result(w_bigger ? i : (int)floor(i * ratio_w), h_bigger ? j : (int)floor(j * ratio_h), c) = 247 | image(w_bigger ? (int)floor(i * ratio_w) : i, h_bigger ? (int)floor(j * ratio_h) : j, c); 248 | } 249 | } 250 | } 251 | std::swap(image.data, result.data); 252 | image.width = w; 253 | image.height = h; 254 | } 255 | 256 | void ImageFilter::Merge(Image &image1, Image &image2) { 257 | int minWidth = std::min(image1.width, image2.width); 258 | int minHeight = std::min(image1.height, image2.height); 259 | for (int i = 0; i < minWidth; i++) { 260 | for (int j = 0; j < minHeight; j++) { 261 | image1(i, j, 0) = (image1(i, j, 0) + image2(i, j, 0)) / 2; 262 | image1(i, j, 1) = (image1(i, j, 1) + image2(i, j, 1)) / 2; 263 | image1(i, j, 2) = (image1(i, j, 2) + image2(i, j, 2)) / 2; 264 | } 265 | } 266 | } 267 | 268 | void ImageFilter::ChangeBrightness(Image &image, int factor) { 269 | float m = factor / 100.0f; 270 | for (int i = 0; i < image.width; i++) { 271 | for (int j = 0; j < image.height; j++) { 272 | for (int k = 0; k < 3; k++) { 273 | image(i, j, k) = std::clamp((int)(image(i, j, k) * m), 0, 255); 274 | } 275 | } 276 | } 277 | } 278 | 279 | void ImageFilter::DetectEdges(Image &image) { 280 | int sobel_x[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; 281 | int sobel_y[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; 282 | Image edges(image.width, image.height, image.channels); 283 | for (int y = 1; y < image.height - 1; y++) { 284 | for (int x = 1; x < image.width - 1; x++) { 285 | int x_gradient = 0, y_gradient = 0; 286 | for (int j = -1; j <= 1; j++) { 287 | for (int i = -1; i <= 1; i++) { 288 | x_gradient += sobel_x[j + 1][i + 1] * image(x + i, y + j, 0); 289 | y_gradient += sobel_y[j + 1][i + 1] * image(x + i, y + j, 0); 290 | } 291 | } 292 | int magnitude = static_cast(sqrt(x_gradient * x_gradient + y_gradient * y_gradient)); 293 | magnitude = std::max(0, std::min(255, magnitude)); 294 | for (int c = 0; c < 3; ++c) { 295 | edges(x, y, c) = magnitude; 296 | } 297 | } 298 | } 299 | for (int y = 0; y < image.height; y++) { 300 | for (int x = 0; x < image.width; x++) { 301 | for (int c = 0; c < 3; c++) { 302 | image(x, y, c) = edges(x, y, c); 303 | } 304 | } 305 | } 306 | } 307 | 308 | void ImageFilter::Blur(Image &image, int level) { 309 | Image blurred_image(image.width, image.height, image.channels); 310 | int n = pow(2 * level + 1, 2); 311 | int sum = 0; 312 | for (int i = level; i < image.width - level; ++i) { 313 | for (int j = level; j < image.height - level; ++j) { 314 | for (int k = 0; k < image.channels; ++k) { 315 | for (int m = -level; m <= level; ++m) { 316 | for (int n = -level; n <= level; ++n) { 317 | sum += image(i + m, j + n, k); 318 | } 319 | } 320 | blurred_image(i, j, k) = sum / n; 321 | sum = 0; 322 | } 323 | } 324 | } 325 | std::swap(image.data, blurred_image.data); 326 | } 327 | 328 | void ImageFilter::Sunlight(Image &image) { 329 | for (int i = 0; i < image.width; i++) { 330 | for (int j = 0; j < image.height; j++) { 331 | image(i, j, 2) /= 2; 332 | } 333 | } 334 | } 335 | 336 | void ImageFilter::OilPaint(Image &image) { 337 | int intensityCount[AYIN_IMAGEFILTER_OILPAINT_INTENSITY]{}, averageR[AYIN_IMAGEFILTER_OILPAINT_INTENSITY]{}, 338 | averageG[AYIN_IMAGEFILTER_OILPAINT_INTENSITY]{}, averageB[AYIN_IMAGEFILTER_OILPAINT_INTENSITY]{}; 339 | Image oil_image(image.width, image.height, image.channels); 340 | for (int i = AYIN_IMAGEFILTER_OILPAINT_RADIUS; i < image.width - AYIN_IMAGEFILTER_OILPAINT_RADIUS; ++i) { 341 | for (int j = AYIN_IMAGEFILTER_OILPAINT_RADIUS; j < image.height - AYIN_IMAGEFILTER_OILPAINT_RADIUS; ++j) { 342 | for (int m = -AYIN_IMAGEFILTER_OILPAINT_RADIUS; m <= AYIN_IMAGEFILTER_OILPAINT_RADIUS; ++m) { 343 | for (int n = -AYIN_IMAGEFILTER_OILPAINT_RADIUS; n <= AYIN_IMAGEFILTER_OILPAINT_RADIUS; ++n) { 344 | int r = image(i + m, j + n, 0), g = image(i + m, j + n, 1), b = image(i + m, j + n, 2); 345 | int curIntensity = (int)((((double)(r + g + b) / 3) * AYIN_IMAGEFILTER_OILPAINT_INTENSITY) / 255.0); 346 | intensityCount[curIntensity]++; 347 | averageR[curIntensity] += r; 348 | averageG[curIntensity] += g; 349 | averageB[curIntensity] += b; 350 | } 351 | } 352 | int curMax = 0; 353 | int maxIndex = 0; 354 | for (int t = 0; t < AYIN_IMAGEFILTER_OILPAINT_INTENSITY; t++) { 355 | if (intensityCount[t] > curMax) { 356 | curMax = intensityCount[t]; 357 | maxIndex = t; 358 | } 359 | } 360 | oil_image(i, j, 0) = averageR[maxIndex] / curMax; 361 | oil_image(i, j, 1) = averageG[maxIndex] / curMax; 362 | oil_image(i, j, 2) = averageB[maxIndex] / curMax; 363 | std::memset(intensityCount, 0, sizeof(intensityCount)); 364 | std::memset(averageR, 0, sizeof(averageR)); 365 | std::memset(averageG, 0, sizeof(averageG)); 366 | std::memset(averageB, 0, sizeof(averageB)); 367 | } 368 | } 369 | std::swap(image.data, oil_image.data); 370 | } 371 | 372 | void ImageFilter::Purple(Image &image) { 373 | for (int i = 0; i < image.width; ++i) { 374 | for (int j = 0; j < image.height; ++j) { 375 | image(i, j, 0) = std::clamp((int)((float)image(i, j, 0) * 1.25f), 0, 255); 376 | image(i, j, 1) = (int)((float)image(i, j, 1) * 0.5f); 377 | image(i, j, 2) = std::clamp((int)((float)image(i, j, 2) * 1.25f), 0, 255); 378 | } 379 | } 380 | } 381 | 382 | void ImageFilter::Infrared(Image &image) { 383 | for (int i = 0; i < image.width; ++i) { 384 | for (int j = 0; j < image.height; ++j) { 385 | int r = image(i, j, 0); 386 | image(i, j, 0) = 255; 387 | image(i, j, 1) = 255 - r; 388 | image(i, j, 2) = 255 - r; 389 | } 390 | } 391 | } 392 | 393 | void ImageFilter::Skew(Image &image, int angle) { 394 | bool neg = angle < 0; 395 | double tangent = std::tan(std::abs(angle) * M_PI / 180.0); 396 | Image skew_image(image.width + image.height * tangent, image.height, image.channels); 397 | 398 | skew_image.clear(); 399 | for (int i = 0; i < image.width; i++) { 400 | for (int j = 0; j < image.height; j++) { 401 | for (int k = 0; k < 3; k++) { 402 | skew_image(i + (neg * image.height + (1 - 2 * neg) * j) * tangent, j, k) = image(i, j, k); 403 | } 404 | } 405 | } 406 | 407 | std::swap(image.data, skew_image.data); 408 | image.width = skew_image.width; 409 | } 410 | 411 | void ImageFilter::Glasses3D(Image &image, int intensity) { 412 | Image helper_image(image.width, image.height, image.channels); 413 | for (int i = intensity; i < image.width - intensity - 1; i++) { 414 | for (int j = 0; j < image.height; j++) { 415 | helper_image(i - intensity, j, 0) = image(i, j, 0); 416 | helper_image(i + intensity, j, 2) = image(i, j, 2); 417 | } 418 | } 419 | for (int i = intensity; i < image.width - intensity - 1; i++) { 420 | for (int j = 0; j < image.height; j++) { 421 | image(i, j, 0) = (image(i, j, 0) + helper_image(i, j, 0)) / 2; 422 | image(i, j, 2) = (image(i, j, 2) + helper_image(i, j, 2)) / 2; 423 | } 424 | } 425 | } 426 | 427 | void ImageFilter::MotionBlur(Image &image, int level) { 428 | Image blurred_image(image.width, image.height, image.channels); 429 | int n = 2 * level + 1; 430 | int sum = 0; 431 | for (int i = level; i < image.width - level; ++i) { 432 | for (int j = level; j < image.height - level; ++j) { 433 | for (int k = 0; k < image.channels; ++k) { 434 | for (int m = -level; m <= level; ++m) { 435 | sum += image(i + m, j + m, k); 436 | } 437 | blurred_image(i, j, k) = sum / n; 438 | sum = 0; 439 | } 440 | } 441 | } 442 | std::swap(image.data, blurred_image.data); 443 | } 444 | 445 | void ImageFilter::Emboss(Image &image) { 446 | Image emboss_image(image.width, image.height, image.channels); 447 | int sum = 0; 448 | for (int i = 3; i < image.width - 3; ++i) { 449 | for (int j = 3; j < image.height - 3; ++j) { 450 | for (int k = 0; k < image.channels; ++k) { 451 | sum = image(i, j - 1, k) * -1 + 128 + image(i - 1, j - 1, k) * -1 + 128 + image(i - 1, j, k) * -1 + 452 | 128 + image(i, j + 1, k) + 128 + image(i + 1, j + 1, k) + 128 + image(i + 1, j, k) + 128; 453 | emboss_image(i, j, k) = std::clamp(sum / 6, 0, 255); 454 | } 455 | } 456 | } 457 | std::swap(image.data, emboss_image.data); 458 | } 459 | -------------------------------------------------------------------------------- /src/ImageFilter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Image.hpp" 4 | 5 | #ifndef AYIN_IMAGEFILTER_OILPAINT_RADIUS 6 | #define AYIN_IMAGEFILTER_OILPAINT_RADIUS 5 7 | #endif 8 | 9 | #ifndef AYIN_IMAGEFILTER_OILPAINT_INTENSITY 10 | #define AYIN_IMAGEFILTER_OILPAINT_INTENSITY 20 11 | #endif 12 | 13 | namespace ayin::ImageFilter { 14 | void Grayscale(Image &image); 15 | void BlackAndWhite(Image &image); 16 | void Invert(Image &image); 17 | void Merge(Image &image1, Image &image2); 18 | void FlipHorizontally(Image &image); 19 | void FlipVertically(Image &image); 20 | void Rotate(Image &image); 21 | void DrawRectangle(Image &image, int x, int y, int width, int height, int thickness, unsigned char *color); 22 | void Frame(Image &image, int fanciness, unsigned int color); 23 | void Crop(Image &image, int x, int y, int w, int h); 24 | void Resize(Image &image, int w, int h); 25 | void ChangeBrightness(Image &image, int factor); 26 | void DetectEdges(Image &image); 27 | void Blur(Image &image, int level); 28 | void Sunlight(Image &image); 29 | void OilPaint(Image &image); 30 | void Purple(Image &image); 31 | void Infrared(Image &image); 32 | void Skew(Image &image, int degree); 33 | void Glasses3D(Image &image, int intensity); 34 | void MotionBlur(Image &image, int level); 35 | void Emboss(Image &image); 36 | } // namespace ayin::ImageFilter 37 | -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "Application.hpp" 2 | #include "Commands.hpp" 3 | #include "Image.hpp" 4 | #include "fonts/MaterialIcons.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace ayin; 12 | 13 | const ImGuiWindowFlags window_flags = 14 | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse; 15 | 16 | const ImGuiTabBarFlags tabbar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_FittingPolicyScroll; 17 | 18 | int main(int argc, char *argv[]) try { 19 | Commands::Base *cmd = nullptr; 20 | Application app("Ayin"); 21 | 22 | for (int i = 1; i < argc; i++) { 23 | app.add_photo(argv[i]); 24 | } 25 | 26 | while (!app.done) { 27 | InputRequest input_req = app.handle_input(); 28 | app.new_frame(); 29 | 30 | if (ImGui::BeginMainMenuBar()) { 31 | if (ImGui::BeginMenu("File")) { 32 | if (ImGui::MenuItem("Open", "Ctrl+O")) { 33 | app.open_file_dialog(); 34 | } 35 | if (ImGui::MenuItem("Save", "Ctrl+S")) { 36 | input_req.ty = InputRequest_Save; 37 | }; 38 | if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) { 39 | input_req.ty = InputRequest_SaveAs; 40 | }; 41 | ImGui::Separator(); 42 | ImGui::MenuItem("Quit", "Ctrl-Q", &app.done); 43 | ImGui::EndMenu(); 44 | } 45 | if (ImGui::BeginMenu("Edit")) { 46 | if (ImGui::MenuItem("Undo", "Ctrl+Z")) { 47 | input_req.ty = InputRequest_Undo; 48 | } 49 | if (ImGui::MenuItem("Redo", "Ctrl+Y")) { 50 | input_req.ty = InputRequest_Redo; 51 | } 52 | ImGui::EndMenu(); 53 | } 54 | ImGui::EndMainMenuBar(); 55 | } 56 | 57 | if (app.photos.empty()) { 58 | app.render(); 59 | continue; 60 | } 61 | 62 | Photo *photo = app.get_selected_photo(); 63 | ImGui::SetNextWindowSize(ImVec2(app.io->DisplaySize.x * 4.0f / 5.0f, (app.io->DisplaySize.y - 23.0f))); 64 | ImGui::SetNextWindowPos(ImVec2(app.io->DisplaySize.x - app.io->DisplaySize.x * 4.0f / 5.0f, 23.0f)); 65 | if (ImGui::Begin("Display", NULL, window_flags)) { 66 | if (ImGui::BeginTabBar("PhotosTabBar", tabbar_flags)) { 67 | size_t i = 0; 68 | for (auto it = app.photos.begin(); it != app.photos.end(); ++it, ++i) { 69 | int flags = (photo->can_undo_change() && (photo->name) == (*it)->name) 70 | ? ImGuiTabItemFlags_UnsavedDocument 71 | : ImGuiTabItemFlags_None; 72 | if (ImGui::BeginTabItem((*it)->name.c_str(), NULL, flags)) { 73 | if ((photo->name) != (*it)->name) { 74 | app.set_selected_photo(i); 75 | photo = app.get_selected_photo(); 76 | } 77 | if (ImGui::BeginChild("PhotoPreview")) { 78 | ImVec2 cursor_pos = ImGui::GetCursorPos(); 79 | ImVec2 content_region = ImGui::GetContentRegionAvail(); 80 | ImVec2 content_pos = ImGui::GetWindowPos(); 81 | if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && app.io->MousePos.x >= content_pos.x && 82 | app.io->MousePos.y >= content_pos.y) { 83 | photo->x += app.io->MouseDelta.x; 84 | photo->y += app.io->MouseDelta.y; 85 | } 86 | if ((app.io->KeyCtrl && app.io->MouseWheel > 0) || input_req.ty == InputRequest_ZoomIn) { 87 | photo->zoom = std::min(photo->zoom * 1.03f, 10.0f); 88 | } else if ((app.io->KeyCtrl && app.io->MouseWheel < 0) || 89 | input_req.ty == InputRequest_ZoomOut) { 90 | photo->zoom = std::max(photo->zoom / 1.03f, 0.1f); 91 | } 92 | ImGui::SetCursorPos(ImVec2( 93 | photo->x + cursor_pos.x + (content_region.x - photo->image->width * photo->zoom) * 0.5f, 94 | photo->y + cursor_pos.y + 95 | (content_region.y - photo->image->height * photo->zoom) * 0.5f)); 96 | if (cmd && cmd->tmpImage) { 97 | ImGui::Image( 98 | (void *)(intptr_t)cmd->tmpImage->texture, 99 | ImVec2(cmd->tmpImage->width * photo->zoom, cmd->tmpImage->height * photo->zoom)); 100 | } else { 101 | ImGui::Image( 102 | (void *)(intptr_t)photo->image->texture, 103 | ImVec2(photo->image->width * photo->zoom, photo->image->height * photo->zoom)); 104 | } 105 | } 106 | ImGui::EndChild(); 107 | ImGui::EndTabItem(); 108 | } 109 | } 110 | ImGui::EndTabBar(); 111 | } 112 | ImGui::End(); 113 | } 114 | 115 | ImVec2 button_size(app.io->DisplaySize.x * 1.0f / 5.0f - 15, 0); 116 | ImGui::SetNextWindowSize(ImVec2(button_size.x + 15, (app.io->DisplaySize.y - 23.0f))); 117 | ImGui::SetNextWindowPos(ImVec2(0, app.io->DisplaySize.y - (app.io->DisplaySize.y - 23.0f))); 118 | if (ImGui::Begin("Filters", NULL, window_flags)) { 119 | if (cmd && cmd->done) { 120 | photo->push_change(cmd->getInfo()); 121 | delete cmd; 122 | cmd = nullptr; 123 | } else if (cmd) { 124 | cmd->showOptionsMenu(); 125 | } else { 126 | ImGui::BeginDisabled(!photo->can_undo_change()); 127 | if (ImGui::Button(ICON_MD_UNDO " Undo")) { 128 | input_req.ty = InputRequest_Undo; 129 | } 130 | ImGui::EndDisabled(); 131 | ImGui::SameLine(); 132 | ImGui::BeginDisabled(!photo->can_redo_change()); 133 | if (ImGui::Button(ICON_MD_REDO " Redo")) { 134 | input_req.ty = InputRequest_Redo; 135 | }; 136 | ImGui::EndDisabled(); 137 | ImGui::SameLine(); 138 | ImGui::BeginDisabled(!photo->can_undo_change()); 139 | if (ImGui::Button(ICON_MD_HISTORY " Reset")) { 140 | photo->reset(); 141 | } 142 | ImGui::EndDisabled(); 143 | ImGui::Text("Filters"); 144 | for (size_t i = 0; i < Commands::number; i++) { 145 | if (ImGui::Button(Commands::names[i], button_size)) { 146 | cmd = Commands::factory[i](); 147 | cmd->setImage(*photo->image); 148 | if (!cmd->hasOptionsMenu()) { 149 | photo->push_change(cmd->getInfo()); 150 | delete cmd; 151 | cmd = nullptr; 152 | } 153 | } 154 | } 155 | } 156 | } 157 | ImGui::End(); 158 | 159 | if (input_req.ty == InputRequest_SaveAs) { 160 | app.save_file_dialog(*photo); 161 | } else if (input_req.ty == InputRequest_Save) { 162 | photo->image->save(photo->filepath.c_str()); 163 | delete photo->origImage; 164 | photo->origImage = new Image(photo->image->width, photo->image->height, photo->image->channels); 165 | memcpy(photo->origImage->data, photo->image->data, 166 | photo->image->width * photo->image->height * photo->image->channels); 167 | photo->soft_reset(); 168 | } else if (input_req.ty == InputRequest_Undo && photo->can_undo_change()) { 169 | photo->undo_change(); 170 | } else if (input_req.ty == InputRequest_Redo && photo->can_redo_change()) { 171 | photo->redo_change(); 172 | } 173 | 174 | app.render(); 175 | } 176 | 177 | if (cmd != nullptr) { 178 | delete cmd; 179 | } 180 | return EXIT_SUCCESS; 181 | } catch (const std::exception& exc) { 182 | fprintf(stderr, "[ERROR] %s", exc.what()); 183 | return EXIT_FAILURE; 184 | } 185 | -------------------------------------------------------------------------------- /src/Photo.cpp: -------------------------------------------------------------------------------- 1 | #include "Photo.hpp" 2 | #include "ImageFilter.hpp" 3 | 4 | using namespace ayin; 5 | 6 | static void doCommand(Image &image, Commands::Info cmd) { 7 | switch (cmd.ty) { 8 | case Commands::Type_Grayscale: 9 | ImageFilter::Grayscale(image); 10 | break; 11 | case Commands::Type_BlackAndWhite: 12 | ImageFilter::BlackAndWhite(image); 13 | break; 14 | case Commands::Type_Invert: 15 | ImageFilter::Invert(image); 16 | break; 17 | case Commands::Type_Merge: { 18 | Image *image2 = new Image(); 19 | image2->load(cmd.merge_image); 20 | ImageFilter::Merge(image, *image2); 21 | delete image2; 22 | break; 23 | } 24 | case Commands::Type_FlipHorizontally: 25 | ImageFilter::FlipHorizontally(image); 26 | break; 27 | case Commands::Type_FlipVertically: 28 | ImageFilter::FlipVertically(image); 29 | break; 30 | case Commands::Type_Rotate: 31 | ImageFilter::Rotate(image); 32 | break; 33 | case Commands::Type_DarkenAndLighten: 34 | ImageFilter::ChangeBrightness(image, cmd.darkenlighten_factor); 35 | break; 36 | case Commands::Type_Crop: 37 | ImageFilter::Crop(image, cmd.crop_x, cmd.crop_y, cmd.crop_width, cmd.crop_height); 38 | break; 39 | case Commands::Type_Frame: 40 | ImageFilter::Frame(image, cmd.frame_fanciness, cmd.frame_color); 41 | break; 42 | case Commands::Type_DetectEdges: 43 | ImageFilter::DetectEdges(image); 44 | break; 45 | case Commands::Type_Resize: 46 | ImageFilter::Resize(image, cmd.resize_width, cmd.resize_height); 47 | break; 48 | case Commands::Type_Blur: 49 | ImageFilter::Blur(image, cmd.blur_level); 50 | break; 51 | case Commands::Type_Sunlight: 52 | ImageFilter::Sunlight(image); 53 | break; 54 | case Commands::Type_OilPaint: 55 | ImageFilter::OilPaint(image); 56 | break; 57 | case Commands::Type_Purple: 58 | ImageFilter::Purple(image); 59 | break; 60 | case Commands::Type_Infrared: 61 | ImageFilter::Infrared(image); 62 | break; 63 | case Commands::Type_Skew: 64 | ImageFilter::Skew(image, cmd.skew_angle); 65 | break; 66 | case Commands::Type_Glasses3D: 67 | ImageFilter::Glasses3D(image, cmd.darkenlighten_factor); 68 | break; 69 | case Commands::Type_MotionBlur: 70 | ImageFilter::MotionBlur(image, cmd.blur_level); 71 | break; 72 | case Commands::Type_Emboss: 73 | ImageFilter::Emboss(image); 74 | break; 75 | } 76 | } 77 | 78 | void Photo::reset() { 79 | bool newDataSize = image->width != origImage->width || image->height != origImage->height; 80 | if (newDataSize) { 81 | newDataSize = true; 82 | delete image; 83 | image = new Image(origImage->width, origImage->height, origImage->channels); 84 | } 85 | memcpy(image->data, origImage->data, origImage->width * origImage->height * origImage->channels); 86 | if (newDataSize) { 87 | image->load_texture(); 88 | } else { 89 | image->update_texture(); 90 | } 91 | m_undoPos = 0; 92 | m_undoStack.clear(); 93 | } 94 | 95 | void Photo::soft_reset() { 96 | m_undoPos = 0; 97 | m_undoStack.clear(); 98 | } 99 | 100 | void Photo::push_change(Commands::Info info) { 101 | if (m_undoPos != 0) { 102 | m_undoStack.resize(m_undoStack.size() - m_undoPos); 103 | m_undoPos = 0; 104 | } 105 | m_undoStack.push_back(info); 106 | } 107 | 108 | void Photo::undo_change() { 109 | ++m_undoPos; 110 | 111 | bool newDataSize = image->width != origImage->width || image->height != origImage->height; 112 | if (newDataSize) { 113 | newDataSize = true; 114 | delete image; 115 | image = new Image(origImage->width, origImage->height, origImage->channels); 116 | } 117 | 118 | memcpy(image->data, origImage->data, origImage->width * origImage->height * origImage->channels); 119 | 120 | for (size_t i = 0; i < m_undoStack.size() - m_undoPos; ++i) { 121 | doCommand(*image, m_undoStack[i]); 122 | } 123 | 124 | if (newDataSize) { 125 | image->load_texture(); 126 | } else { 127 | image->update_texture(); 128 | } 129 | } 130 | 131 | bool Photo::can_undo_change() { return m_undoPos <= (int)m_undoStack.size() - 1; } 132 | 133 | void Photo::redo_change() { 134 | --m_undoPos; 135 | int width = image->width, height = image->height; 136 | doCommand(*image, m_undoStack[m_undoStack.size() - m_undoPos - 1]); 137 | if (width == image->width && height == image->height) { 138 | image->update_texture(); 139 | } else { 140 | image->load_texture(); 141 | } 142 | } 143 | 144 | bool Photo::can_redo_change() { return m_undoPos != 0; } 145 | -------------------------------------------------------------------------------- /src/Photo.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Commands.hpp" 4 | #include "Image.hpp" 5 | 6 | #include 7 | 8 | namespace ayin { 9 | class Photo { 10 | public: 11 | Image *image = nullptr; 12 | Image *origImage = nullptr; 13 | std::string name{}; 14 | std::string filepath{}; 15 | float x = 0.0f, y = 0.0f, zoom = 1.0f; 16 | 17 | Photo() = default; 18 | void reset(); 19 | void soft_reset(); 20 | void push_change(Commands::Info info); 21 | void undo_change(); 22 | bool can_undo_change(); 23 | void redo_change(); 24 | bool can_redo_change(); 25 | 26 | private: 27 | std::vector m_undoStack{}; 28 | int m_undoPos = 0; 29 | }; 30 | } // namespace ayin 31 | -------------------------------------------------------------------------------- /src/utils/win32.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #ifndef __MINGW32__ 5 | #include 6 | #else 7 | #include 8 | #endif // __MINGW32_ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #ifndef AYIN_UTILS_WIN32_AUTO_IMGUI_STYLE_COLORS_SDL_TIMER_CALLBACK_TIMEOUT 16 | #define AYIN_UTILS_WIN32_AUTO_IMGUI_STYLE_COLORS_SDL_TIMER_CALLBACK_TIMEOUT 5000 17 | #endif 18 | 19 | namespace ayin::utils::win32 { 20 | 21 | static bool AppsUseLightTheme() { 22 | auto buffer = std::vector(4); 23 | auto cbData = static_cast(buffer.size() * sizeof(char)); 24 | auto res = RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 25 | L"AppsUseLightTheme", RRF_RT_REG_DWORD, nullptr, buffer.data(), &cbData); 26 | if (res != ERROR_SUCCESS) 27 | return -1; 28 | auto i = int(buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0]); 29 | return i == 1; 30 | } 31 | 32 | static Uint32 AutoImGuiStyleColorsSDLTimerCallback(Uint32, void *sdl_window) { 33 | static int is_light = -1; 34 | switch (is_light) { 35 | case -1: // init 36 | is_light = AppsUseLightTheme(); 37 | goto change; 38 | case 0: // false 39 | if (AppsUseLightTheme()) { 40 | is_light = true; 41 | goto change; 42 | } 43 | break; 44 | case 1: // true 45 | if (!AppsUseLightTheme()) { 46 | is_light = false; 47 | goto change; 48 | } 49 | break; 50 | } 51 | return AYIN_UTILS_WIN32_AUTO_IMGUI_STYLE_COLORS_SDL_TIMER_CALLBACK_TIMEOUT; 52 | change: 53 | is_light ? ImGui::StyleColorsLight() : ImGui::StyleColorsDark(); 54 | SDL_SysWMinfo wmInfo; 55 | SDL_VERSION(&wmInfo.version); 56 | SDL_GetWindowWMInfo((SDL_Window *)sdl_window, &wmInfo); 57 | BOOL USE_DARK_MODE = !is_light; 58 | DwmSetWindowAttribute((HWND)wmInfo.info.win.window, DWMWINDOWATTRIBUTE::DWMWA_USE_IMMERSIVE_DARK_MODE, 59 | &USE_DARK_MODE, sizeof(USE_DARK_MODE)); 60 | return AYIN_UTILS_WIN32_AUTO_IMGUI_STYLE_COLORS_SDL_TIMER_CALLBACK_TIMEOUT; 61 | } 62 | } // namespace ayin::utils::win32 63 | --------------------------------------------------------------------------------