├── examples ├── demo_1.png ├── libs │ ├── glfw │ │ ├── lib-vc2010-32 │ │ │ └── glfw3.lib │ │ ├── lib-vc2010-64 │ │ │ └── glfw3.lib │ │ ├── COPYING.txt │ │ └── include │ │ │ └── GLFW │ │ │ └── glfw3native.h │ └── usynergy │ │ ├── README.txt │ │ ├── uSynergy.h │ │ └── uSynergy.c ├── example_win32_directx11 │ ├── build_win32.bat │ └── main.cpp ├── example_sdl_opengl3 │ ├── build_win32.bat │ ├── Makefile │ └── main.cpp └── example_emscripten_opengl3 │ ├── shell_minimal.html │ ├── Makefile │ └── main.cpp ├── backends ├── tex_inspect_opengl.h ├── tex_inspect_directx11.h ├── tex_inspect_directx11.cpp └── tex_inspect_opengl.cpp ├── .gitignore ├── imgui_tex_inspect_demo.h ├── LICENSE.txt ├── README.md ├── imgui_tex_inspect_internal.h ├── imgui_tex_inspect.h └── imgui_tex_inspect_demo.cpp /examples/demo_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyborrell/imgui_tex_inspect/HEAD/examples/demo_1.png -------------------------------------------------------------------------------- /examples/libs/glfw/lib-vc2010-32/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyborrell/imgui_tex_inspect/HEAD/examples/libs/glfw/lib-vc2010-32/glfw3.lib -------------------------------------------------------------------------------- /examples/libs/glfw/lib-vc2010-64/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyborrell/imgui_tex_inspect/HEAD/examples/libs/glfw/lib-vc2010-64/glfw3.lib -------------------------------------------------------------------------------- /backends/tex_inspect_opengl.h: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | #pragma once 3 | 4 | #include 5 | namespace ImGuiTexInspect 6 | { 7 | bool ImplOpenGL3_Init(const char *glsl_version = NULL); 8 | void ImplOpenGl3_Shutdown(); 9 | } // namespace ImGuiTexInspect 10 | -------------------------------------------------------------------------------- /examples/libs/usynergy/README.txt: -------------------------------------------------------------------------------- 1 | 2 | uSynergy client -- Implementation for the embedded Synergy client library 3 | version 1.0.0, July 7th, 2012 4 | Copyright (c) 2012 Alex Evans 5 | 6 | This is a copy of the files once found at: 7 | https://github.com/symless/synergy-core/tree/790d108a56ada9caad8e56ff777d444485a69da9/src/micro 8 | 9 | -------------------------------------------------------------------------------- /.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 | *.dll 12 | *.pdb 13 | examples/build/* 14 | examples/*/Debug/* 15 | examples/*/Release/* 16 | examples/*/x64/* 17 | 18 | ## Editor files 19 | compile_commands.json 20 | *.bak 21 | -------------------------------------------------------------------------------- /imgui_tex_inspect_demo.h: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | 3 | #pragma once 4 | #include "imgui.h" 5 | 6 | namespace ImGuiTexInspect 7 | { 8 | struct Texture 9 | { 10 | ImTextureID texture; 11 | ImVec2 size; 12 | }; 13 | 14 | Texture LoadTexture(const char *path); 15 | 16 | void ShowDemoWindow(); 17 | } //namespace ImGuiTexInspect 18 | -------------------------------------------------------------------------------- /backends/tex_inspect_directx11.h: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | 3 | #pragma once 4 | struct ID3D11Device; 5 | struct ID3D11DeviceContext; 6 | namespace ImGuiTexInspect 7 | { 8 | bool ImplDX11_Init(ID3D11Device *device, ID3D11DeviceContext *device_context); // Will add references 9 | void ImplDX11_Shutdown(); // Will release references 10 | } // namespace ImGuiTexInspect 11 | -------------------------------------------------------------------------------- /examples/example_win32_directx11/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_win32_directx11 4 | @REM TEX_INSPECT_CHANGE... 5 | @set IMGUI_DIR=..\..\..\imgui 6 | @set TEX_INSPECT_DIR=..\.. 7 | @set INCLUDES=/I%IMGUI_DIR% /I%IMGUI_DIR%\backends /I%TEX_INSPECT_DIR% /I%TEX_INSPECT_DIR%/backends /I%TEX_INSPECT_DIR%/examples/loaders /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" 8 | @set SOURCES=main.cpp %IMGUI_DIR%\backends\imgui_impl_dx11.cpp %IMGUI_DIR%\backends\imgui_impl_win32.cpp %IMGUI_DIR%\imgui*.cpp %TEX_INSPECT_DIR%/imgui_tex_*.cpp %TEX_INSPECT_DIR%/backends/tex_inspect_directx11.cpp 9 | @REM ...TEX_INSPECT_CHANGE 10 | @set LIBS=/LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d11.lib d3dcompiler.lib 11 | mkdir %OUT_DIR% 12 | cl /nologo /Zi /MD %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% 13 | 14 | -------------------------------------------------------------------------------- /examples/libs/glfw/COPYING.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002-2006 Marcus Geelnard 2 | Copyright (c) 2006-2010 Camilla Berglund 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would 15 | be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and must not 18 | be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | 23 | -------------------------------------------------------------------------------- /examples/example_sdl_opengl3/build_win32.bat: -------------------------------------------------------------------------------- 1 | @REM TODO 2 | @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. 3 | @set OUT_DIR=Debug 4 | @set OUT_EXE=example_sdl_opengl3 5 | @REM TEX_INSPECT_CHANGE... 6 | @set IMGUI_DIR=..\..\..\imgui 7 | @set TEX_INSPECT_DIR=..\.. 8 | @set INCLUDES=/I%IMGUI_DIR% /I%IMGUI_DIR%\backends /I%SDL2_DIR%\include /I..\libs\gl3w /I%TEX_INSPECT_DIR% /I%TEX_INSPECT_DIR%/backends /I%TEX_INSPECT_DIR%/examples/loaders 9 | @set SOURCES=main.cpp %IMGUI_DIR%\backends\imgui_impl_sdl.cpp %IMGUI_DIR%\backends\imgui_impl_opengl3.cpp %IMGUI_DIR%\imgui*.cpp %IMGUI_DIR%\examples\libs\gl3w\GL\gl3w.c %TEX_INSPECT_DIR%/imgui_tex_inspect.cpp %TEX_INSPECT_DIR%/imgui_tex_inspect_demo.cpp %TEX_INSPECT_DIR%/backends/tex_inspect_opengl.cpp 10 | @REM ...TEX_INSPECT_CHANGE 11 | @set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib shell32.lib 12 | mkdir %OUT_DIR% 13 | cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console 14 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2021 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 | -------------------------------------------------------------------------------- /examples/example_emscripten_opengl3/shell_minimal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dear ImGui Emscripten example 7 | 29 | 30 | 31 | 32 | 62 | {{{ SCRIPT }}} 63 | 64 | 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ImGuiTexInspect 2 | ===== 3 | 4 | ImGuiTexInspect is a texture inspector library for Dear ImGui. It's a debug tool that allows you to easily inspect the data in any texture. It provides the following features: 5 | - Zoom and Pan 6 | - Hover to see exact RGBA values 7 | - Annotation system at high zoom which annotates texel cells with: 8 | - Numerical RGBA values 9 | - Arrow representation of vector data encoded in color channels (e.g. normal maps) 10 | - Custom annotations, which can be added easily 11 | - Customizable alpha handling 12 | - Filters to select a combination of red, green, blue & alpha channels 13 | - Per texel matrix-transformation to allow versatile channel swizzling, blending, etc 14 | 15 | Screenshot 16 | ===== 17 | [![screenshot1](https://andyborrell.github.io/imgui_tex_inspect/Screenshot_1.png)](https://andyborrell.github.io/imgui_tex_inspect/Screenshot_1.png) 18 | 19 | Demo 20 | ===== 21 | 22 | The ```examples``` directory contains example projects for the supported platforms. Note that the example projects expect the `imgui` directory to be in the same parent directory as `imgui_tex_inspect`. 23 | 24 | [You can also see a WebGL build of the demo project here](https://andyborrell.github.io/imgui_tex_inspect) 25 | 26 | 27 | [![screenshot2](https://andyborrell.github.io/imgui_tex_inspect/Screenshot_2.png)](https://andyborrell.github.io/imgui_tex_inspect/Screenshot_2.png) 28 | 29 | 30 | Usage 31 | ===== 32 | Add an inspector instance to a Dear ImGui window like so: 33 | 34 | ```cpp 35 | ImGui::Begin("Simple Texture Inspector"); 36 | ImGuiTexInspect::BeginInspectorPanel("Inspector", textureHandle, textureSize); 37 | ImGuiTexInspect::EndInspectorPanel(); 38 | ImGui::End(); 39 | ``` 40 | 41 | Adding annotations to a texture is done by inserting a call to `ImGuiTexInspect::DrawAnnotations` between the calls to `ImGuiTexInspect::BeginInspectorPanel` and `ImGuiTexInspect::EndInspectorPanel`. The following shows how to add text to the inspector showing the RGBA components for each texel. Of course, this per-texel annotation is only visible when sufficiently zoomed in. 42 | 43 | ```cpp 44 | ImGui::Begin("Example Texture##screenshot2"); 45 | ImGuiTexInspect::BeginInspectorPanel("Inspector", textureHandle, textureSize); 46 | ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::Floats)); 47 | ImGuiTexInspect::EndInspectorPanel(); 48 | ImGui::End(); 49 | ``` 50 | 51 | For more advanced usage take a look at `imgui_tex_inspect_demo.cpp`. 52 | 53 | 54 | Integration 55 | ===== 56 | To integrate ImGuiTexInspect to your project you must: 57 | - Add the `imgui_tex_inspect.cpp`source file 58 | - Add the appropriate renderer source file from `imgui_tex_inspect_test\backends` 59 | - Add `imgui_tex_inspect` and `imgui_tex_inspect\backends` as include directories 60 | 61 | The following calls are required to initialize ImGuiTexInspect: 62 | ```cpp 63 | ImGuiTexInspect::ImplOpenGL3_Init(); // Or DirectX 11 equivalent (check your chosen backend header file) 64 | ImGuiTexInspect::Init(); 65 | ImGuiTexInspect::CreateContext(); 66 | ``` 67 | 68 | The main API is in `imgui_tex_inspect.h` 69 | 70 | In order to initialize the backend you will also need to include the appropriate backend header file, e.g. `tex_inspect_opengl.h` 71 | 72 | 73 | Supported Renderers 74 | ===== 75 | ImGuiTexInspect relies on a renderer specific backend, much like Dear ImGui does. In fact the backend code for ImGuiTexInspect is very closely based on Dear ImGui's own backend code. Currently the following backend source files are available: 76 | 77 | - `tex_inspect_opengl.cpp` 78 | - Desktop GL: 2.x 3.x 4.x 79 | - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) 80 | - `tex_inspect_directx11.cpp` 81 | - DirectX 11 82 | 83 | To avoid linker errors be sure to only include one backend source file. 84 | 85 | Dependencies 86 | ===== 87 | The only external dependency is Dear ImGui itself. Dear ImGui version 1.80 onwards is supported. Older versions of Dear ImGui have not been tested, but could probably be made to work without too much effort. 88 | 89 | 90 | -------------------------------------------------------------------------------- /examples/example_emscripten_opengl3/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile to use with 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` 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 | #TEX_INSPECT_CHANGE... 21 | IMGUI_DIR = ../../../imgui 22 | TEX_INSPECT_DIR = ../.. 23 | #...TEX_INSPECT_CHANGE 24 | SOURCES = main.cpp 25 | 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 26 | SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp 27 | #TEX_INSPECT_CHANGE... 28 | SOURCES += $(TEX_INSPECT_DIR)/imgui_tex_inspect.cpp $(TEX_INSPECT_DIR)/imgui_tex_inspect_demo.cpp 29 | SOURCES += $(TEX_INSPECT_DIR)/backends/tex_inspect_opengl.cpp 30 | #...TEX_INSPECT_CHANGE 31 | OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) 32 | UNAME_S := $(shell uname -s) 33 | 34 | ##--------------------------------------------------------------------- 35 | ## EMSCRIPTEN OPTIONS 36 | ##--------------------------------------------------------------------- 37 | 38 | EMS += -s USE_SDL=2 -s WASM=1 39 | EMS += -s ALLOW_MEMORY_GROWTH=1 40 | EMS += -s DISABLE_EXCEPTION_CATCHING=1 -s NO_EXIT_RUNTIME=0 41 | EMS += -s ASSERTIONS=1 42 | 43 | # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) 44 | #EMS += -s BINARYEN_TRAP_MODE=clamp 45 | #EMS += -s SAFE_HEAP=1 ## Adds overhead 46 | 47 | # Emscripten allows preloading a file or folder to be accessible at runtime. 48 | # The Makefile for this example project suggests embedding the misc/fonts/ folder into our application, it will then be accessible as "/fonts" 49 | # See documentation for more details: https://emscripten.org/docs/porting/files/packaging_files.html 50 | # (Default value is 0. Set to 1 to enable file-system and include the misc/fonts/ folder as part of the build.) 51 | #TEX_INSPECT_CHANGE... 52 | USE_FILE_SYSTEM ?= 1 53 | #...TEX_INSPECT_CHANGE 54 | ifeq ($(USE_FILE_SYSTEM), 0) 55 | EMS += -s NO_FILESYSTEM=1 -DIMGUI_DISABLE_FILE_FUNCTIONS 56 | endif 57 | ifeq ($(USE_FILE_SYSTEM), 1) 58 | #TEX_INSPECT_CHANGE... 59 | LDFLAGS += --no-heap-copy --preload-file $(IMGUI_DIR)/misc/fonts@/fonts 60 | LDFLAGS += --preload-file ../demo_1.png@/demo_1.png 61 | #...TEX_INSPECT_CHANGE 62 | endif 63 | 64 | ##--------------------------------------------------------------------- 65 | ## FINAL BUILD FLAGS 66 | ##--------------------------------------------------------------------- 67 | 68 | #TEX_INSPECT_CHANGE... 69 | CXXFLAGS = -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I$(TEX_INSPECT_DIR) -I$(TEX_INSPECT_DIR)/backends -I$(TEX_INSPECT_DIR)/examples/loaders 70 | #...TEX_INSPECT_CHANGE 71 | #CPPFLAGS += -g 72 | CPPFLAGS += -Wall -Wformat -Os 73 | CPPFLAGS += $(EMS) 74 | LIBS += $(EMS) 75 | LDFLAGS += --shell-file shell_minimal.html 76 | 77 | ##--------------------------------------------------------------------- 78 | ## BUILD RULES 79 | ##--------------------------------------------------------------------- 80 | 81 | %.o:%.cpp 82 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< 83 | 84 | %.o:$(IMGUI_DIR)/%.cpp 85 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< 86 | 87 | %.o:$(IMGUI_DIR)/backends/%.cpp 88 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< 89 | 90 | #TEX_INSPECT_CHANGE... 91 | %.o:$(TEX_INSPECT_DIR)/backends/%.cpp 92 | $(CXX) $(CXXFLAGS) -c -o $@ $< 93 | 94 | %.o:$(TEX_INSPECT_DIR)/examples/loaders/%.cpp 95 | $(CXX) $(CXXFLAGS) -c -o $@ $< 96 | 97 | %.o:$(TEX_INSPECT_DIR)/%.cpp 98 | $(CXX) $(CXXFLAGS) -c -o $@ $< 99 | #...TEX_INSPECT_CHANGE 100 | 101 | %.o:../libs/gl3w/GL/%.c 102 | $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< 103 | 104 | all: $(EXE) 105 | @echo Build complete for $(EXE) 106 | 107 | $(WEB_DIR): 108 | mkdir $@ 109 | 110 | serve: all 111 | python3 -m http.server -d $(WEB_DIR) 112 | 113 | $(EXE): $(OBJS) $(WEB_DIR) 114 | $(CXX) -o $@ $(OBJS) $(LIBS) $(LDFLAGS) 115 | 116 | clean: 117 | rm -rf $(OBJS) $(WEB_DIR) 118 | -------------------------------------------------------------------------------- /examples/example_sdl_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_sdl_opengl3 18 | #TEX_INSPECT_CHANGE... 19 | IMGUI_DIR = ../../../imgui 20 | TEX_INSPECT_DIR = ../.. 21 | #...TEX_INSPECT_CHANGE 22 | SOURCES = main.cpp 23 | 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 24 | SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp 25 | #TEX_INSPECT_CHANGE... 26 | SOURCES += $(TEX_INSPECT_DIR)/imgui_tex_inspect.cpp $(TEX_INSPECT_DIR)/imgui_tex_inspect_demo.cpp 27 | SOURCES += $(TEX_INSPECT_DIR)/backends/tex_inspect_opengl.cpp 28 | #...TEX_INSPECT_CHANGE 29 | OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) 30 | UNAME_S := $(shell uname -s) 31 | LINUX_GL_LIBS = -lGL 32 | 33 | #TEX_INSPECT_CHANGE... 34 | CXXFLAGS = -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I$(TEX_INSPECT_DIR) -I$(TEX_INSPECT_DIR)/backends -I$(TEX_INSPECT_DIR)/examples/loaders 35 | #...TEX_INSPECT_CHANGE 36 | CXXFLAGS += -g -Wall -Wformat 37 | LIBS = 38 | 39 | ##--------------------------------------------------------------------- 40 | ## OPENGL LOADER / OPENGL ES 41 | ##--------------------------------------------------------------------- 42 | 43 | ## See below for OpenGL ES option (no loader required) - comment out 44 | ## the following if you want to use OpenGL ES instead of Desktop GL. 45 | 46 | ## Using OpenGL loader: gl3w [default] 47 | SOURCES += ../libs/gl3w/GL/gl3w.c 48 | CXXFLAGS += -I../libs/gl3w -DIMGUI_IMPL_OPENGL_LOADER_GL3W 49 | 50 | ## Using OpenGL loader: glew 51 | ## (This assumes a system-wide installation) 52 | # CXXFLAGS += -DIMGUI_IMPL_OPENGL_LOADER_GLEW 53 | # LIBS += -lGLEW 54 | 55 | ## Using OpenGL loader: glad 56 | # SOURCES += ../libs/glad/src/glad.c 57 | # CXXFLAGS += -I../libs/glad/include -DIMGUI_IMPL_OPENGL_LOADER_GLAD 58 | 59 | ## Using OpenGL loader: glad2 60 | # SOURCES += ../libs/glad/src/gl.c 61 | # CXXFLAGS += -I../libs/glad/include -DIMGUI_IMPL_OPENGL_LOADER_GLAD2 62 | 63 | ## Using OpenGL loader: glbinding 64 | ## This assumes a system-wide installation 65 | ## of either version 3.0.0 (or newer) 66 | # CXXFLAGS += -DIMGUI_IMPL_OPENGL_LOADER_GLBINDING3 67 | # LIBS += -lglbinding 68 | ## or the older version 2.x 69 | # CXXFLAGS += -DIMGUI_IMPL_OPENGL_LOADER_GLBINDING2 70 | # LIBS += -lglbinding 71 | 72 | ## Using OpenGL ES, no loader required 73 | ## This assumes a GL ES library available in the system, e.g. libGLESv2.so 74 | # CXXFLAGS += -DIMGUI_IMPL_OPENGL_ES2 75 | # LINUX_GL_LIBS = -lGLESv2 76 | ## If you're on a Raspberry Pi and want to use the legacy drivers, 77 | ## use the following instead: 78 | # LINUX_GL_LIBS = -L/opt/vc/lib -lbrcmGLESv2 79 | 80 | ##--------------------------------------------------------------------- 81 | ## BUILD FLAGS PER PLATFORM 82 | ##--------------------------------------------------------------------- 83 | 84 | ifeq ($(UNAME_S), Linux) #LINUX 85 | ECHO_MESSAGE = "Linux" 86 | LIBS += $(LINUX_GL_LIBS) -ldl `sdl2-config --libs` 87 | 88 | CXXFLAGS += `sdl2-config --cflags` 89 | CFLAGS = $(CXXFLAGS) 90 | endif 91 | 92 | ifeq ($(UNAME_S), Darwin) #APPLE 93 | ECHO_MESSAGE = "Mac OS X" 94 | LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs` 95 | LIBS += -L/usr/local/lib -L/opt/local/lib 96 | 97 | CXXFLAGS += `sdl2-config --cflags` 98 | CXXFLAGS += -I/usr/local/include -I/opt/local/include 99 | CFLAGS = $(CXXFLAGS) 100 | endif 101 | 102 | ifeq ($(OS), Windows_NT) 103 | ECHO_MESSAGE = "MinGW" 104 | LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2` 105 | 106 | CXXFLAGS += `pkg-config --cflags sdl2` 107 | CFLAGS = $(CXXFLAGS) 108 | endif 109 | 110 | ##--------------------------------------------------------------------- 111 | ## BUILD RULES 112 | ##--------------------------------------------------------------------- 113 | 114 | %.o:%.cpp 115 | $(CXX) $(CXXFLAGS) -c -o $@ $< 116 | 117 | %.o:$(IMGUI_DIR)/%.cpp 118 | $(CXX) $(CXXFLAGS) -c -o $@ $< 119 | 120 | %.o:$(IMGUI_DIR)/backends/%.cpp 121 | $(CXX) $(CXXFLAGS) -c -o $@ $< 122 | 123 | #TEX_INSPECT_CHANGE... 124 | %.o:$(TEX_INSPECT_DIR)/backends/%.cpp 125 | $(CXX) $(CXXFLAGS) -c -o $@ $< 126 | 127 | %.o:$(TEX_INSPECT_DIR)/examples/loaders/%.cpp 128 | $(CXX) $(CXXFLAGS) -c -o $@ $< 129 | 130 | %.o:$(TEX_INSPECT_DIR)/%.cpp 131 | $(CXX) $(CXXFLAGS) -c -o $@ $< 132 | #...TEX_INSPECT_CHANGE 133 | 134 | %.o:../libs/gl3w/GL/%.c 135 | $(CC) $(CFLAGS) -c -o $@ $< 136 | 137 | %.o:../libs/glad/src/%.c 138 | $(CC) $(CFLAGS) -c -o $@ $< 139 | 140 | all: $(EXE) 141 | @echo Build complete for $(ECHO_MESSAGE) 142 | 143 | $(EXE): $(OBJS) 144 | $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) 145 | 146 | clean: 147 | rm -f $(EXE) $(OBJS) 148 | -------------------------------------------------------------------------------- /imgui_tex_inspect_internal.h: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | 3 | #pragma once 4 | #include "imgui.h" 5 | #include "imgui_internal.h" 6 | #include "imgui_tex_inspect.h" 7 | 8 | namespace ImGuiTexInspect 9 | { 10 | //------------------------------------------------------------------------- 11 | // [SECTION] UTILITIES 12 | //------------------------------------------------------------------------- 13 | // Returns true if a flag is set 14 | template 15 | static inline bool HasFlag(TSet set, TFlag flag) 16 | { 17 | return (set & flag) == flag; 18 | } 19 | 20 | // Set flag or flags in set 21 | template 22 | static inline void SetFlag(TSet &set, TFlag flags) 23 | { 24 | set = static_cast(set | flags); 25 | } 26 | 27 | // Clear flag or flags in set 28 | template 29 | static inline void ClearFlag(TSet &set, TFlag flag) 30 | { 31 | set = static_cast(set & ~flag); 32 | } 33 | 34 | // Proper modulus operator, as opposed to remainder as calculated by % 35 | template 36 | static inline T Modulus(T a, T b) 37 | { 38 | return a - b * ImFloorSigned(a / b); 39 | } 40 | 41 | // Defined in recent versions of imgui_internal.h. Included here in case user is on older 42 | // imgui version. 43 | static inline float ImFloorSigned(float f) 44 | { 45 | return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1); 46 | } 47 | 48 | static inline float Round(float f) 49 | { 50 | return ImFloorSigned(f + 0.5f); 51 | } 52 | 53 | static inline ImVec2 Abs(ImVec2 v) 54 | { 55 | return ImVec2(ImAbs(v.x), ImAbs(v.y)); 56 | } 57 | 58 | //------------------------------------------------------------------------- 59 | // [SECTION] STRUCTURES 60 | //------------------------------------------------------------------------- 61 | struct ShaderOptions 62 | { 63 | float ColorTransform[16] = {}; // See CurrentInspector_SetColorMatrix for details 64 | float ColorOffset[4] = {}; 65 | 66 | ImVec4 BackgroundColor = {0,0,0,0}; // Color used for alpha blending 67 | float PremultiplyAlpha = 0; // If 1 then color will be multiplied by alpha in shader, before blend stage 68 | float DisableFinalAlpha = 0; // If 1 then fragment shader will always output alpha = 1 69 | 70 | bool ForceNearestSampling = false; // If true fragment shader will always sample from texel centers 71 | 72 | ImVec2 GridWidth = {0,0}; // Width in UV coords of grid line 73 | ImVec4 GridColor = {0,0,0,0}; 74 | 75 | void ResetColorTransform(); 76 | ShaderOptions(); 77 | }; 78 | 79 | struct Inspector 80 | { 81 | ImGuiID ID; 82 | bool Initialized = false; 83 | 84 | // Texture 85 | ImTextureID Texture = ImTextureID{}; 86 | ImVec2 TextureSize = {0, 0}; // Size in texels of texture 87 | float PixelAspectRatio = 1; // Values other than 1 not supported yet 88 | 89 | // View State 90 | bool IsDragging = false; // Is user currently dragging to pan view 91 | ImVec2 PanPos = {0.5f, 0.5f}; // The UV value at the center of the current view 92 | ImVec2 Scale = {1, 1}; // 1 pixel is 1 texel 93 | 94 | ImVec2 PanelTopLeftPixel = {0, 0}; // Top left of view in ImGui pixel coordinates 95 | ImVec2 PanelSize = {0, 0}; // Size of area allocated to drawing the image in pixels. 96 | 97 | ImVec2 ViewTopLeftPixel = {0, 0}; // Position in ImGui pixel coordinates 98 | ImVec2 ViewSize = {0, 0}; // Rendered size of current image. This could be smaller than panel size if user has zoomed out. 99 | ImVec2 ViewSizeUV = {0, 0}; // Visible region of the texture in UV coordinates 100 | 101 | /* Conversion transforms to go back and forth between screen pixels (what ImGui considers screen pixels) and texels*/ 102 | Transform2D TexelsToPixels; 103 | Transform2D PixelsToTexels; 104 | 105 | // Cached pixel data 106 | bool HaveCurrentTexelData = false; 107 | BufferDesc Buffer; 108 | 109 | /* We don't actually access texel data through this pointer. We just 110 | * manage its lifetime. The backend might have asked us to allocated a 111 | * buffer, or it might not. The pointer we actually use to access texel 112 | * data is in the Buffer object above (which depending on what the backend 113 | * did might point to the same memory as this pointer) 114 | */ 115 | ImU8 *DataBuffer = nullptr; 116 | size_t DataBufferSize = 0; 117 | 118 | // Configuration 119 | InspectorFlags Flags = 0; 120 | 121 | // Background mode 122 | InspectorAlphaMode AlphaMode = InspectorAlphaMode_ImGui; 123 | ImVec4 CustomBackgroundColor = {0, 0, 0, 1}; 124 | 125 | // Scaling limits 126 | ImVec2 ScaleMin = {0.02f, 0.02f}; 127 | ImVec2 ScaleMax = {500, 500}; 128 | 129 | // Grid 130 | float MinimumGridSize = 4; // Don't draw the grid if lines would be closer than MinimumGridSize pixels 131 | 132 | // Annotations 133 | ImU32 MaxAnnotatedTexels = 0; 134 | 135 | // Color transformation 136 | ShaderOptions ActiveShaderOptions; 137 | ShaderOptions CachedShaderOptions; 138 | 139 | ~Inspector(); 140 | }; 141 | 142 | //------------------------------------------------------------------------- 143 | // [SECTION] INTERNAL FUNCTIONS 144 | //------------------------------------------------------------------------- 145 | 146 | Inspector *GetByKey(const Context *ctx, ImGuiID key); 147 | Inspector *GetOrAddByKey(Context *ctx, ImGuiID key); 148 | 149 | void SetPanPos(Inspector *inspector, ImVec2 pos); 150 | void SetScale(Inspector *inspector, ImVec2 scale); 151 | void SetScale(Inspector *inspector, float scaleY); 152 | void RoundPanPos(Inspector *inspector); 153 | 154 | ImU8 *GetBuffer(Inspector *inspector, size_t bytes); 155 | 156 | /* GetTexelsToPixels 157 | * Calculate a transform to convert from texel coordinates to screen pixel coordinates 158 | * */ 159 | Transform2D GetTexelsToPixels(ImVec2 screenTopLeft, ImVec2 screenViewSize, ImVec2 uvTopLeft, ImVec2 uvViewSize, ImVec2 textureSize); 160 | 161 | //------------------------------------------------------------------------- 162 | // [SECTION] IMGUI UTILS 163 | //------------------------------------------------------------------------- 164 | /* TextVector 165 | * Draws a single-column ImGui table with one row for each provided string 166 | */ 167 | void TextVector(const char *title, const char *const *strings, int n); 168 | 169 | /* PushDisabled & PopDisabled 170 | * Push and Pop and ImGui styles that disable and "grey out" ImGui elements 171 | * by making them non interactive and transparent*/ 172 | void PushDisabled(); 173 | void PopDisabled(); 174 | 175 | //------------------------------------------------------------------------- 176 | // [SECTION] BACKEND FUNCTIONS 177 | //------------------------------------------------------------------------- 178 | void BackEnd_SetShader(const ImDrawList *drawList, const ImDrawCmd *cmd, const Inspector *inspector); 179 | bool BackEnd_GetData(Inspector *inspector, ImTextureID texture, int x, int y, int width, int height, BufferDesc *buffer); 180 | 181 | } // namespace ImGuiTexInspect 182 | -------------------------------------------------------------------------------- /examples/example_emscripten_opengl3/main.cpp: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // The ImGuiTexInspect version of this file is very based on the 3 | // ImGui version. All changes have been labelled with TEX_INSPECT_CHANGE 4 | //========================================================================== 5 | 6 | // Dear ImGui: standalone example application for Emscripten, using SDL2 + OpenGL3 7 | // (Emscripten is a C++-to-javascript compiler, used to publish executables for the web. See https://emscripten.org/) 8 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 9 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 10 | 11 | // This is mostly the same code as the SDL2 + OpenGL3 example, simply with the modifications needed to run on Emscripten. 12 | // It is possible to combine both code into a single source file that will compile properly on Desktop and using Emscripten. 13 | // See https://github.com/ocornut/imgui/pull/2492 as an example on how to do just that. 14 | 15 | #include "imgui.h" 16 | #include "imgui_impl_sdl.h" 17 | #include "imgui_impl_opengl3.h" 18 | #include "imgui_tex_inspect.h" //TEX_INSPECT_CHANGE 19 | #include "tex_inspect_opengl.h" //TEX_INSPECT_CHANGE 20 | #include "imgui_tex_inspect_demo.h" //TEX_INSPECT_CHANGE 21 | #define STB_IMAGE_IMPLEMENTATION//TEX_INSPECT_CHANGE 22 | #include "stb_image.h" //TEX_INSPECT_CHANGE 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | // Emscripten requires to have full control over the main loop. We're going to store our SDL book-keeping variables globally. 29 | // Having a single function that acts as a loop prevents us to store state in the stack of said function. So we need some location for this. 30 | SDL_Window* g_Window = NULL; 31 | SDL_GLContext g_GLContext = NULL; 32 | 33 | // For clarity, our main loop code is declared at the end. 34 | static void main_loop(void*); 35 | 36 | int main(int, char**) 37 | { 38 | // Setup SDL 39 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) 40 | { 41 | printf("Error: %s\n", SDL_GetError()); 42 | return -1; 43 | } 44 | 45 | // For the browser using Emscripten, we are going to use WebGL1 with GL ES2. See the Makefile. for requirement details. 46 | // It is very likely the generated file won't work in many browsers. Firefox is the only sure bet, but I have successfully 47 | // run this code on Chrome for Android for example. 48 | const char* glsl_version = "#version 100"; 49 | //const char* glsl_version = "#version 300 es"; 50 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 51 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 52 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); 53 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 54 | 55 | // Create window with graphics context 56 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 57 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 58 | SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); 59 | SDL_DisplayMode current; 60 | SDL_GetCurrentDisplayMode(0, ¤t); 61 | SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); 62 | g_Window = SDL_CreateWindow("Dear ImGui Emscripten example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); 63 | g_GLContext = SDL_GL_CreateContext(g_Window); 64 | if (!g_GLContext) 65 | { 66 | fprintf(stderr, "Failed to initialize WebGL context!\n"); 67 | return 1; 68 | } 69 | SDL_GL_SetSwapInterval(1); // Enable vsync 70 | 71 | // Setup Dear ImGui context 72 | IMGUI_CHECKVERSION(); 73 | ImGui::CreateContext(); 74 | ImGuiIO& io = ImGui::GetIO(); (void)io; 75 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 76 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 77 | 78 | // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. 79 | // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. 80 | io.IniFilename = NULL; 81 | 82 | // Setup Dear ImGui style 83 | ImGui::StyleColorsDark(); 84 | //ImGui::StyleColorsClassic(); 85 | 86 | // Setup Platform/Renderer backends 87 | ImGui_ImplSDL2_InitForOpenGL(g_Window, g_GLContext); 88 | ImGui_ImplOpenGL3_Init(glsl_version); 89 | ImGuiTexInspect::ImplOpenGL3_Init(glsl_version); //TEX_INSPECT_CHANGE 90 | 91 | // Load Fonts 92 | // - 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. 93 | // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. 94 | // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). 95 | // - 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. 96 | // - Read 'docs/FONTS.md' for more instructions and details. 97 | // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! 98 | // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. 99 | //io.Fonts->AddFontDefault(); 100 | #ifndef IMGUI_DISABLE_FILE_FUNCTIONS 101 | io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); 102 | //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); 103 | //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f); 104 | //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); 105 | //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); 106 | //IM_ASSERT(font != NULL); 107 | #endif 108 | 109 | // This function call won't return, and will engage in an infinite loop, processing events from the browser, and dispatching them. 110 | emscripten_set_main_loop_arg(main_loop, NULL, 0, true); 111 | } 112 | 113 | static void main_loop(void* arg) 114 | { 115 | ImGuiIO& io = ImGui::GetIO(); 116 | IM_UNUSED(arg); // We can pass this argument as the second parameter of emscripten_set_main_loop_arg(), but we don't use that. 117 | 118 | // Our state (make them static = more or less global) as a convenience to keep the example terse. 119 | static bool show_demo_window = false; //TEX_INSPECT_CHANGE 120 | static bool show_another_window = false; 121 | static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 122 | 123 | // Poll and handle events (inputs, window resize, etc.) 124 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 125 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. 126 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. 127 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 128 | SDL_Event event; 129 | while (SDL_PollEvent(&event)) 130 | { 131 | ImGui_ImplSDL2_ProcessEvent(&event); 132 | // Capture events here, based on io.WantCaptureMouse and io.WantCaptureKeyboard 133 | } 134 | 135 | // Start the Dear ImGui frame 136 | ImGui_ImplOpenGL3_NewFrame(); 137 | ImGui_ImplSDL2_NewFrame(g_Window); 138 | ImGui::NewFrame(); 139 | 140 | // 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!). 141 | if (show_demo_window) 142 | ImGui::ShowDemoWindow(&show_demo_window); 143 | 144 | ImGuiTexInspect::ShowDemoWindow();//TEX_INSPECT_CHANGE 145 | 146 | 147 | // 3. Show another simple window. 148 | if (show_another_window) 149 | { 150 | 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) 151 | ImGui::Text("Hello from another window!"); 152 | if (ImGui::Button("Close Me")) 153 | show_another_window = false; 154 | ImGui::End(); 155 | } 156 | 157 | // Rendering 158 | ImGui::Render(); 159 | SDL_GL_MakeCurrent(g_Window, g_GLContext); 160 | glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); 161 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); 162 | glClear(GL_COLOR_BUFFER_BIT); 163 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 164 | SDL_GL_SwapWindow(g_Window); 165 | } 166 | 167 | namespace ImGuiTexInspect // TEX_INSPECT_CHANGE 168 | { 169 | Texture LoadTexture(const char * path) 170 | { 171 | const int channelCount = 4; 172 | int imageFileChannelCount; 173 | int width, height; 174 | uint8_t *image = (uint8_t *)stbi_load(path, &width, &height, &imageFileChannelCount, channelCount); 175 | if (image == NULL) 176 | { 177 | fprintf(stderr, "%s\nFailed to open %s\n", stbi_failure_reason(), path); 178 | return {nullptr,{0,0}}; 179 | } 180 | 181 | GLenum dataFormat = GL_RGBA; 182 | GLuint textureHandle; 183 | glGenTextures(1, &textureHandle); 184 | glBindTexture(GL_TEXTURE_2D, textureHandle); 185 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 186 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 187 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, dataFormat, GL_UNSIGNED_BYTE, image); 188 | 189 | Texture t; 190 | t.texture = (void*)(uintptr_t)(textureHandle); 191 | t.size = ImVec2((float)width,(float)height); 192 | 193 | stbi_image_free(image); 194 | return t; 195 | } 196 | } // namespace ImGuiTexInspect 197 | -------------------------------------------------------------------------------- /examples/example_sdl_opengl3/main.cpp: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // The ImGuiTexInspect version of this file is very based on the 3 | // ImGui version. All changes have been labelled with TEX_INSPECT_CHANGE 4 | //========================================================================== 5 | 6 | // Dear ImGui: standalone example application for SDL2 + OpenGL 7 | // (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) 8 | // (GL3W is a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc.) 9 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 10 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 11 | 12 | #include "imgui.h" 13 | #include "imgui_impl_sdl.h" 14 | #include "imgui_impl_opengl3.h" 15 | #include "imgui_tex_inspect.h" //TEX_INSPECT_CHANGE 16 | #include "tex_inspect_opengl.h" //TEX_INSPECT_CHANGE 17 | #include "imgui_tex_inspect_demo.h" //TEX_INSPECT_CHANGE 18 | #define STB_IMAGE_IMPLEMENTATION//TEX_INSPECT_CHANGE 19 | #include "stb_image.h" //TEX_INSPECT_CHANGE 20 | #include 21 | #include 22 | 23 | #if defined(IMGUI_IMPL_OPENGL_ES2) 24 | #include 25 | // About Desktop OpenGL function loaders: 26 | // Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. 27 | // Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). 28 | // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. 29 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 30 | #include // Initialize with gl3wInit() 31 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 32 | #include // Initialize with glewInit() 33 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 34 | #include // Initialize with gladLoadGL() 35 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) 36 | #include // Initialize with gladLoadGL(...) or gladLoaderLoadGL() 37 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) 38 | #define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. 39 | #include // Initialize with glbinding::Binding::initialize() 40 | #include 41 | using namespace gl; 42 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) 43 | #define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. 44 | #include // Initialize with glbinding::initialize() 45 | #include 46 | using namespace gl; 47 | #else 48 | #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM 49 | #endif 50 | 51 | // Main code 52 | int main(int, char**) 53 | { 54 | // Setup SDL 55 | // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems, 56 | // depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!) 57 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) 58 | { 59 | printf("Error: %s\n", SDL_GetError()); 60 | return -1; 61 | } 62 | 63 | // Decide GL+GLSL versions 64 | #if defined(IMGUI_IMPL_OPENGL_ES2) 65 | // GL ES 2.0 + GLSL 100 66 | const char* glsl_version = "#version 100"; 67 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 68 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 69 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); 70 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 71 | #elif defined(__APPLE__) 72 | // GL 3.2 Core + GLSL 150 73 | const char* glsl_version = "#version 150"; 74 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac 75 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 76 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 77 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 78 | #else 79 | // GL 3.0 + GLSL 130 80 | const char* glsl_version = "#version 130"; 81 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 82 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 83 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 84 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 85 | #endif 86 | 87 | // Create window with graphics context 88 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 89 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 90 | SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); 91 | SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); 92 | SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); 93 | SDL_GLContext gl_context = SDL_GL_CreateContext(window); 94 | SDL_GL_MakeCurrent(window, gl_context); 95 | SDL_GL_SetSwapInterval(1); // Enable vsync 96 | 97 | // Initialize OpenGL loader 98 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 99 | bool err = gl3wInit() != 0; 100 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 101 | bool err = glewInit() != GLEW_OK; 102 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 103 | bool err = gladLoadGL() == 0; 104 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) 105 | bool err = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one. 106 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) 107 | bool err = false; 108 | glbinding::Binding::initialize(); 109 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) 110 | bool err = false; 111 | glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)SDL_GL_GetProcAddress(name); }); 112 | #else 113 | bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization. 114 | #endif 115 | if (err) 116 | { 117 | fprintf(stderr, "Failed to initialize OpenGL loader!\n"); 118 | return 1; 119 | } 120 | 121 | // Setup Dear ImGui context 122 | IMGUI_CHECKVERSION(); 123 | ImGui::CreateContext(); 124 | ImGuiIO& io = ImGui::GetIO(); (void)io; 125 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 126 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 127 | 128 | // Setup Dear ImGui style 129 | ImGui::StyleColorsDark(); 130 | //ImGui::StyleColorsClassic(); 131 | 132 | // Setup Platform/Renderer backends 133 | ImGui_ImplSDL2_InitForOpenGL(window, gl_context); 134 | ImGui_ImplOpenGL3_Init(glsl_version); 135 | ImGuiTexInspect::ImplOpenGL3_Init(glsl_version); //TEX_INSPECT_CHANGE 136 | 137 | // Load Fonts 138 | // - 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. 139 | // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. 140 | // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). 141 | // - 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. 142 | // - Read 'docs/FONTS.md' for more instructions and details. 143 | // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! 144 | //io.Fonts->AddFontDefault(); 145 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); 146 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); 147 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); 148 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); 149 | //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); 150 | //IM_ASSERT(font != NULL); 151 | 152 | // Our state 153 | bool show_demo_window = false; //TEX_INSPECT_CHANGE 154 | //bool show_another_window = false //TEX_INSPECT_CHANGE; 155 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 156 | 157 | // Main loop 158 | bool done = false; 159 | while (!done) 160 | { 161 | // Poll and handle events (inputs, window resize, etc.) 162 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 163 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. 164 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. 165 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 166 | SDL_Event event; 167 | while (SDL_PollEvent(&event)) 168 | { 169 | ImGui_ImplSDL2_ProcessEvent(&event); 170 | if (event.type == SDL_QUIT) 171 | done = true; 172 | if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) 173 | done = true; 174 | } 175 | 176 | // Start the Dear ImGui frame 177 | ImGui_ImplOpenGL3_NewFrame(); 178 | ImGui_ImplSDL2_NewFrame(window); 179 | ImGui::NewFrame(); 180 | 181 | // 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!). 182 | if (show_demo_window) 183 | ImGui::ShowDemoWindow(&show_demo_window); 184 | 185 | ImGuiTexInspect::ShowDemoWindow(); //TEX_INSPECT_CHANGE 186 | 187 | // Rendering 188 | ImGui::Render(); 189 | glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); 190 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); 191 | glClear(GL_COLOR_BUFFER_BIT); 192 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 193 | SDL_GL_SwapWindow(window); 194 | } 195 | 196 | // Cleanup 197 | ImGuiTexInspect::ImplOpenGl3_Shutdown();//TEX_INSPECT_CHANGE 198 | ImGui_ImplOpenGL3_Shutdown(); 199 | ImGui_ImplSDL2_Shutdown(); 200 | ImGui::DestroyContext(); 201 | 202 | SDL_GL_DeleteContext(gl_context); 203 | SDL_DestroyWindow(window); 204 | SDL_Quit(); 205 | 206 | return 0; 207 | } 208 | 209 | namespace ImGuiTexInspect // TEX_INSPECT_CHANGE 210 | { 211 | Texture LoadTexture(const char * path) 212 | { 213 | const int channelCount = 4; 214 | int imageFileChannelCount; 215 | int width, height; 216 | uint8_t *image = (uint8_t *)stbi_load(path, &width, &height, &imageFileChannelCount, channelCount); 217 | if (image == NULL) 218 | { 219 | fprintf(stderr, "%s\nFailed to open %s\n", stbi_failure_reason(), path); 220 | 221 | return {nullptr,{0,0}}; 222 | } 223 | 224 | GLenum dataFormat = GL_RGBA; 225 | GLuint textureHandle; 226 | glGenTextures(1, &textureHandle); 227 | glBindTexture(GL_TEXTURE_2D, textureHandle); 228 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 229 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 230 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, dataFormat, GL_UNSIGNED_BYTE, image); 231 | 232 | Texture t; 233 | t.texture = (void*)(uintptr_t)(textureHandle); 234 | t.size = ImVec2((float)width,(float)height); 235 | 236 | stbi_image_free(image); 237 | return t; 238 | } 239 | } // namespace ImGuiTexInspect 240 | -------------------------------------------------------------------------------- /examples/example_win32_directx11/main.cpp: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // The ImGuiTexInspect version of this file is very based on the 3 | // ImGui version. All changes have been labelled with TEX_INSPECT_CHANGE 4 | //========================================================================== 5 | 6 | // Dear ImGui: standalone example application for DirectX 11 7 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 8 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 9 | 10 | #include "imgui_tex_inspect.h" //TEX_INSPECT_CHANGE 11 | #include "tex_inspect_directx11.h" //TEX_INSPECT_CHANGE 12 | #include "imgui_tex_inspect_demo.h" //TEX_INSPECT_CHANGE 13 | #define STB_IMAGE_IMPLEMENTATION//TEX_INSPECT_CHANGE 14 | #include "stb_image.h" //TEX_INSPECT_CHANGE 15 | #include "imgui.h" 16 | #include "imgui_impl_win32.h" 17 | #include "imgui_impl_dx11.h" 18 | #include 19 | #include 20 | 21 | // Data 22 | static ID3D11Device* g_pd3dDevice = NULL; 23 | static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; 24 | static IDXGISwapChain* g_pSwapChain = NULL; 25 | static ID3D11RenderTargetView* g_mainRenderTargetView = NULL; 26 | 27 | // Forward declarations of helper functions 28 | bool CreateDeviceD3D(HWND hWnd); 29 | void CleanupDeviceD3D(); 30 | void CreateRenderTarget(); 31 | void CleanupRenderTarget(); 32 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 33 | 34 | // Main code 35 | int main(int, char**) 36 | { 37 | // Create application window 38 | //ImGui_ImplWin32_EnableDpiAwareness(); 39 | WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; 40 | ::RegisterClassEx(&wc); 41 | HWND hwnd = ::CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX11 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); 42 | 43 | // Initialize Direct3D 44 | if (!CreateDeviceD3D(hwnd)) 45 | { 46 | CleanupDeviceD3D(); 47 | ::UnregisterClass(wc.lpszClassName, wc.hInstance); 48 | return 1; 49 | } 50 | 51 | // Show the window 52 | ::ShowWindow(hwnd, SW_SHOWDEFAULT); 53 | ::UpdateWindow(hwnd); 54 | 55 | // Setup Dear ImGui context 56 | IMGUI_CHECKVERSION(); 57 | ImGui::CreateContext(); 58 | ImGuiIO& io = ImGui::GetIO(); (void)io; 59 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 60 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 61 | 62 | // Setup Dear ImGui style 63 | ImGui::StyleColorsDark(); 64 | //ImGui::StyleColorsClassic(); 65 | 66 | // Setup Platform/Renderer backends 67 | ImGui_ImplWin32_Init(hwnd); 68 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); 69 | ImGuiTexInspect::ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); //TEX_INSPECT_CHANGE 70 | // Load Fonts 71 | // - 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. 72 | // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. 73 | // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). 74 | // - 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. 75 | // - Read 'docs/FONTS.md' for more instructions and details. 76 | // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! 77 | //io.Fonts->AddFontDefault(); 78 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); 79 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); 80 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); 81 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); 82 | //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); 83 | //IM_ASSERT(font != NULL); 84 | 85 | // Our state 86 | bool show_demo_window = false; //TEX_INSPECT_CHANGE 87 | //bool show_another_window = false; //TEX_INSPECT_CHANGE 88 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 89 | 90 | // Main loop 91 | bool done = false; 92 | while (!done) 93 | { 94 | // Poll and handle messages (inputs, window resize, etc.) 95 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 96 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. 97 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. 98 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 99 | MSG msg; 100 | while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) 101 | { 102 | ::TranslateMessage(&msg); 103 | ::DispatchMessage(&msg); 104 | if (msg.message == WM_QUIT) 105 | done = true; 106 | } 107 | if (done) 108 | break; 109 | 110 | // Start the Dear ImGui frame 111 | ImGui_ImplDX11_NewFrame(); 112 | ImGui_ImplWin32_NewFrame(); 113 | ImGui::NewFrame(); 114 | 115 | // 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!). 116 | if (show_demo_window) 117 | ImGui::ShowDemoWindow(&show_demo_window); 118 | 119 | ImGuiTexInspect::ShowDemoWindow(); //TEX_INSPECT_CHANGE 120 | 121 | // Rendering 122 | ImGui::Render(); 123 | const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; 124 | g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); 125 | g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); 126 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 127 | 128 | g_pSwapChain->Present(1, 0); // Present with vsync 129 | //g_pSwapChain->Present(0, 0); // Present without vsync 130 | } 131 | 132 | // Cleanup 133 | ImGuiTexInspect::ImplDX11_Shutdown(); //TEX_INSPECT_CHANGE 134 | ImGui_ImplDX11_Shutdown(); 135 | ImGui_ImplWin32_Shutdown(); 136 | ImGui::DestroyContext(); 137 | 138 | CleanupDeviceD3D(); 139 | ::DestroyWindow(hwnd); 140 | ::UnregisterClass(wc.lpszClassName, wc.hInstance); 141 | 142 | return 0; 143 | } 144 | 145 | // Helper functions 146 | 147 | bool CreateDeviceD3D(HWND hWnd) 148 | { 149 | // Setup swap chain 150 | DXGI_SWAP_CHAIN_DESC sd; 151 | ZeroMemory(&sd, sizeof(sd)); 152 | sd.BufferCount = 2; 153 | sd.BufferDesc.Width = 0; 154 | sd.BufferDesc.Height = 0; 155 | sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 156 | sd.BufferDesc.RefreshRate.Numerator = 60; 157 | sd.BufferDesc.RefreshRate.Denominator = 1; 158 | sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 159 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 160 | sd.OutputWindow = hWnd; 161 | sd.SampleDesc.Count = 1; 162 | sd.SampleDesc.Quality = 0; 163 | sd.Windowed = TRUE; 164 | sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 165 | 166 | UINT createDeviceFlags = 0; 167 | //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 168 | D3D_FEATURE_LEVEL featureLevel; 169 | const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; 170 | if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK) 171 | return false; 172 | 173 | CreateRenderTarget(); 174 | return true; 175 | } 176 | 177 | void CleanupDeviceD3D() 178 | { 179 | CleanupRenderTarget(); 180 | if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; } 181 | if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; } 182 | if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } 183 | } 184 | 185 | void CreateRenderTarget() 186 | { 187 | ID3D11Texture2D* pBackBuffer; 188 | g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); 189 | g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView); 190 | pBackBuffer->Release(); 191 | } 192 | 193 | void CleanupRenderTarget() 194 | { 195 | if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = NULL; } 196 | } 197 | 198 | // Forward declare message handler from imgui_impl_win32.cpp 199 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 200 | 201 | // Win32 message handler 202 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 203 | { 204 | if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) 205 | return true; 206 | 207 | switch (msg) 208 | { 209 | case WM_SIZE: 210 | if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) 211 | { 212 | CleanupRenderTarget(); 213 | g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); 214 | CreateRenderTarget(); 215 | } 216 | return 0; 217 | case WM_SYSCOMMAND: 218 | if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu 219 | return 0; 220 | break; 221 | case WM_DESTROY: 222 | ::PostQuitMessage(0); 223 | return 0; 224 | } 225 | return ::DefWindowProc(hWnd, msg, wParam, lParam); 226 | } 227 | 228 | 229 | namespace ImGuiTexInspect // TEX_INSPECT_CHANGE 230 | { 231 | Texture LoadTexture(const char * path) 232 | { 233 | const int channelCount = 4; 234 | int imageFileChannelCount; 235 | 236 | int width, height; 237 | ImU8 *image = (ImU8 *)stbi_load(path, &width, &height, &imageFileChannelCount, channelCount); 238 | 239 | if (image == NULL) 240 | { 241 | fprintf(stderr, "%s\n", stbi_failure_reason()); 242 | fprintf(stderr, "Failed to open\n"); 243 | return {nullptr,{0,0}}; 244 | } 245 | 246 | D3D11_TEXTURE2D_DESC desc; 247 | ZeroMemory(&desc, sizeof(desc)); 248 | desc.Width = (UINT)width; 249 | desc.Height = (UINT)height; 250 | desc.MipLevels = 1; 251 | desc.ArraySize = 1; 252 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 253 | desc.SampleDesc.Count = 1; 254 | desc.Usage = D3D11_USAGE_DEFAULT; 255 | desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 256 | desc.CPUAccessFlags = 0; 257 | 258 | ID3D11Texture2D* pTexture = NULL; 259 | 260 | D3D11_SUBRESOURCE_DATA subResource; 261 | subResource.pSysMem = image; 262 | subResource.SysMemPitch = desc.Width * channelCount; 263 | subResource.SysMemSlicePitch = 0; 264 | g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); 265 | IM_ASSERT(pTexture != NULL); 266 | 267 | // Create texture view 268 | D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; 269 | ZeroMemory(&srvDesc, sizeof(srvDesc)); 270 | srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 271 | srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 272 | srvDesc.Texture2D.MipLevels = desc.MipLevels; 273 | srvDesc.Texture2D.MostDetailedMip = 0; 274 | 275 | ID3D11ShaderResourceView* textureView; 276 | g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &textureView); 277 | 278 | pTexture->Release(); 279 | 280 | Texture t; 281 | t.texture = (void*)textureView; 282 | t.size = ImVec2((float)width, (float)height); 283 | 284 | stbi_image_free(image); 285 | 286 | return t; 287 | } 288 | } // namespace ImGuiTexInspect 289 | -------------------------------------------------------------------------------- /imgui_tex_inspect.h: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | 3 | #pragma once 4 | #include "imgui.h" 5 | 6 | namespace ImGuiTexInspect 7 | { 8 | struct Context; 9 | struct Transform2D; 10 | //------------------------------------------------------------------------- 11 | // [SECTION] INIT & SHUTDOWN 12 | //------------------------------------------------------------------------- 13 | void Init(); 14 | void Shutdown(); 15 | 16 | Context *CreateContext(); 17 | void DestroyContext(Context *); 18 | void SetCurrentContext(Context *); 19 | 20 | //------------------------------------------------------------------------- 21 | // [SECTION] BASIC USAGE 22 | //------------------------------------------------------------------------- 23 | 24 | enum InspectorAlphaMode 25 | { 26 | InspectorAlphaMode_ImGui, // Alpha is transparency so you see the ImGui panel background behind image 27 | InspectorAlphaMode_Black, // Alpha is used to blend over a black background 28 | InspectorAlphaMode_White, // Alpha is used to blend over a white background 29 | InspectorAlphaMode_CustomColor // Alpha is used to blend over a custom colour. 30 | }; 31 | 32 | typedef ImU64 InspectorFlags; 33 | enum InspectorFlags_ 34 | { 35 | InspectorFlags_ShowWrap = 1 << 0, // Draw beyong the [0,1] uv range. What you see will depend on API 36 | InspectorFlags_NoForceFilterNearest = 1 << 1, // Normally we force nearest neighbour sampling when zoomed in. Set to disable this. 37 | InspectorFlags_NoGrid = 1 << 2, // By default a grid is shown at high zoom levels 38 | InspectorFlags_NoTooltip = 1 << 3, // Disable tooltip on hover 39 | InspectorFlags_FillHorizontal = 1 << 4, // Scale to fill available space horizontally 40 | InspectorFlags_FillVertical = 1 << 5, // Scale to fill available space vertically 41 | InspectorFlags_NoAutoReadTexture = 1 << 6, // By default texture data is read to CPU every frame for tooltip and annotations 42 | InspectorFlags_FlipX = 1 << 7, // Horizontally flip the way the texture is displayed 43 | InspectorFlags_FlipY = 1 << 8, // Vertically flip the way the texture is displayed 44 | }; 45 | 46 | /* Use one of these Size structs if you want to specify an exact size for the inspector panel. 47 | * E.g. 48 | * BeginInspectorPanel("MyPanel", texture_1K, ImVec2(1024,1024), 0, SizeExcludingBorder(ImVec2(1024,1024))); 49 | * 50 | * However, most of the time the default size will be fine. E.g. 51 | * 52 | * BeginInspectorPanel("MyPanel", texture_1K, ImVec2(1024,1024)); 53 | */ 54 | struct SizeIncludingBorder {ImVec2 Size; SizeIncludingBorder(ImVec2 size):Size(size){}}; 55 | struct SizeExcludingBorder {ImVec2 size; SizeExcludingBorder(ImVec2 size):size(size){}}; 56 | /* BeginInspectorPanel 57 | * Returns true if panel is drawn. Note that flags will only be considered on the first call */ 58 | bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags = 0); 59 | bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags, SizeIncludingBorder size); 60 | bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags, SizeExcludingBorder size); 61 | 62 | /* EndInspectorPanel 63 | * Always call after BeginInspectorPanel and after you have drawn any required annotations*/ 64 | void EndInspectorPanel(); 65 | 66 | /* ReleaseInspectorData 67 | * ImGuiTexInspect keeps texture data cached in memory. If you know you won't 68 | * be displaying a particular panel for a while you can call this to release 69 | * the memory. It won't be allocated again until next time you call 70 | * BeginInspectorPanel. If id is NULL then the current (most recent) inspector 71 | * will be affected. Unless you have a lot of different Inspector instances 72 | * you can probably not worry about this. Call CurrentInspector_GetID to get 73 | * the ID of an inspector. 74 | */ 75 | void ReleaseInspectorData(ImGuiID id); 76 | 77 | //------------------------------------------------------------------------- 78 | // [SECTION] CURRENT INSPECTOR MANIPULATORS 79 | //------------------------------------------------------------------------- 80 | /* All the functions starting with CurrentInspector_ can be used after calling 81 | * BeginInspector until the end of the frame. It is not necessary to call them 82 | * before the matching EndInspectorPanel 83 | */ 84 | 85 | /* CurrentInspector_SetColorMatrix 86 | * colorMatrix and colorOffset describe the transform which happens to the 87 | * color of each texel. 88 | * The calculation is finalColor = colorMatrix * originalColor + colorOffset. 89 | * Where finalColor, originalColor and colorOffset are column vectors with 90 | * components (r,g,b,a) and colorMatrix is a column-major matrix. 91 | */ 92 | void CurrentInspector_SetColorMatrix(const float (&colorMatrix)[16], const float (&colorOffset)[4]); 93 | void CurrentInspector_ResetColorMatrix(); 94 | 95 | /* CurrentInspector_SetAlphaMode - see enum comments for details*/ 96 | void CurrentInspector_SetAlphaMode(InspectorAlphaMode); 97 | void CurrentInspector_SetFlags(InspectorFlags toSet, InspectorFlags toClear = 0); 98 | inline void CurrentInspector_ClearFlags(InspectorFlags toClear) {CurrentInspector_SetFlags(0, toClear);} 99 | void CurrentInspector_SetGridColor(ImU32 color); 100 | void CurrentInspector_SetMaxAnnotations(int maxAnnotations); 101 | 102 | /* CurrentInspector_InvalidateTextureCache 103 | * If using the InspectorFlags_NoAutoReadTexture flag then call this to 104 | * indicate your texture has changed context. 105 | */ 106 | void CurrentInspector_InvalidateTextureCache(); 107 | 108 | /* CurrentInspector_SetCustomBackgroundColor 109 | * If using InspectorAlphaMode_CustomColor then this is the color that will be 110 | * blended as the background where alpha is less than one. 111 | */ 112 | void CurrentInspector_SetCustomBackgroundColor(ImVec4 color); 113 | void CurrentInspector_SetCustomBackgroundColor(ImU32 color); 114 | 115 | /* CurrentInspector_GetID 116 | * Get the ID of the current inspector. Currently only used for calling 117 | * ReleaseInspectorData. 118 | */ 119 | ImGuiID CurrentInspector_GetID(); 120 | 121 | /* Some convenience functions for drawing ImGui controls for the current Inspector */ 122 | void DrawColorMatrixEditor(); // ColorMatrix editor. See comments on ColorMatrix below. 123 | void DrawGridEditor(); // Grid editor. Enable/Disable grid. Set Grid Color. 124 | void DrawColorChannelSelector(); // For toggling R,G,B channels 125 | void DrawAlphaModeSelector(); // A combo box for selecting the alpha mode 126 | 127 | //------------------------------------------------------------------------- 128 | // [SECTION] CONTEXT-WIDE SETTINGS 129 | //------------------------------------------------------------------------- 130 | /* SetZoomRate 131 | * factor should be greater than 1. A value of 1.5 means one mouse wheel 132 | * scroll will increase zoom level by 50%. The factor used for zooming out is 133 | * 1/factor. */ 134 | void SetZoomRate(float factor); 135 | 136 | //------------------------------------------------------------------------- 137 | // [SECTION] ANNOTATION TOOLS 138 | //------------------------------------------------------------------------- 139 | 140 | /* DrawAnnotationLine 141 | * Convenience function to add a line to draw list using texel coordinates. 142 | */ 143 | void DrawAnnotationLine(ImDrawList *drawList, ImVec2 fromTexel, ImVec2 toTexel, Transform2D texelsToPixels, ImU32 color); 144 | 145 | //------------------------------------------------------------------------- 146 | // [SECTION] Annotation Classes 147 | //------------------------------------------------------------------------- 148 | 149 | /* To draw annotations call DrawAnnotions in between BeginInspectorPanel and 150 | * EndInspectorPanel. Example usage: 151 | * DrawAnnotations(ValueText(ValueText::HexString)); 152 | * 153 | * To provide your own Annotation drawing class just define a class that 154 | * implements the DrawAnnotation method. See imgui_tex_inspect_demo.cpp 155 | * for an example. 156 | */ 157 | template 158 | void DrawAnnotations(T drawer, ImU64 maxAnnotatedTexels = 0); 159 | 160 | /* ValueText 161 | * An annoation class that draws text inside each texel when zoom level is high enough for it to fit. 162 | * The text shows the value of the texel. E.g. "R:255, G: 128, B:0, A:255" 163 | */ 164 | class ValueText 165 | { 166 | protected: 167 | int TextRowCount; 168 | int TextColumnCount; 169 | const char *TextFormatString; 170 | bool FormatAsFloats; 171 | 172 | public: 173 | enum Format 174 | { 175 | HexString, // E.g. #EF97B9FF 176 | BytesHex, // E.g. R:#EF G:#97 B:#B9 A:#FF (split over 4 lines) 177 | BytesDec, // E.g. R:239 G: 151 B:185 A:255 (split over 4 lines) 178 | Floats // E.g. 0.937 0.592 0.725 1.000 (split over 4 lines) 179 | }; 180 | ValueText(Format format = HexString); 181 | void DrawAnnotation(ImDrawList *drawList, ImVec2 texel, Transform2D texelsToPixels, ImVec4 value); 182 | }; 183 | 184 | /* Arrow 185 | * An annotation class that draws an arrow inside each texel when zoom level is 186 | * high enough. The direction and length of the arrow are determined by texel 187 | * values. 188 | * The X and Y components of the arrow is determined by the VectorIndex_x, and 189 | * VectorIndex_y channels of the texel value. Examples: 190 | 191 | * VectorIndex_x = 0, VectorIndex_y = 1 means X component is red and Y component is green 192 | * VectorIndex_x = 1, VectorIndex_y = 2 means X component is green and Y component is blue 193 | * VectorIndex_x = 0, VectorIndex_y = 3 means X component is red and Y component is alpha 194 | * 195 | * ZeroPoint is the texel value which corresponds to a zero length vector. E.g. 196 | * ZeroPoint = (0.5, 0.5) means (0.5, 0.5) will be drawn as a zero length arrow 197 | * 198 | * All public properties can be directly manipulated. There are also presets that can be set 199 | * by calling UsePreset. 200 | 201 | */ 202 | class Arrow 203 | { 204 | public: 205 | int VectorIndex_x; 206 | int VectorIndex_y; 207 | ImVec2 LineScale; 208 | ImVec2 ZeroPoint = {0, 0}; 209 | 210 | enum Preset 211 | { 212 | NormalMap, // For normal maps. I.e. Arrow is in (R,G) channels. 128, 128 is zero point 213 | NormalizedFloat // Arrow in (R,G) channels. 0,0 is zero point, (1,0) will draw an arrow exactly to 214 | // right edge of texture. (0,-1) will draw exactly to the bottom etc. 215 | }; 216 | Arrow(int xVectorIndex = 0, int yVectorIndex = 1, ImVec2 lineScale = ImVec2(1, 1)); 217 | Arrow &UsePreset(Preset); 218 | void DrawAnnotation(ImDrawList *drawList, ImVec2 texel, Transform2D texelsToPixels, ImVec4 value); 219 | }; 220 | 221 | //------------------------------------------------------------------------- 222 | // [SECTION] INTERNAL 223 | //------------------------------------------------------------------------- 224 | 225 | struct Transform2D 226 | { 227 | ImVec2 Scale; 228 | ImVec2 Translate; 229 | 230 | /* Transform a vector by this transform. Scale is applied first */ 231 | ImVec2 operator*(const ImVec2 &rhs) const 232 | { 233 | return ImVec2(Scale.x * rhs.x + Translate.x, Scale.y * rhs.y + Translate.y); 234 | } 235 | 236 | /* Return an inverse transform such that transform.Inverse() * transform * vector == vector*/ 237 | Transform2D Inverse() const 238 | { 239 | ImVec2 inverseScale(1 / Scale.x, 1 / Scale.y); 240 | return {inverseScale, ImVec2(-inverseScale.x * Translate.x, -inverseScale.y * Translate.y)}; 241 | } 242 | }; 243 | 244 | struct BufferDesc 245 | { 246 | float *Data_float = nullptr; // Only one of these 247 | ImU8 *Data_uint8_t = nullptr; // two pointers should be non NULL 248 | size_t BufferByteSize = 0; // Size of buffer pointed to by one of above pointers 249 | int Stride = 0; // Measured in size of data type, not bytes! 250 | int LineStride = 0; // Measured in size of data type, not bytes! 251 | int StartX = 0; // Texel coordinates of data start 252 | int StartY = 0; 253 | int Width = 0; // Size of block of texels which are in data 254 | int Height = 0; 255 | 256 | unsigned char ChannelCount = 0; // Number of color channels in data. E.g. 2 means just red and green 257 | 258 | /* These 4 values describe where each color is stored relative to the beginning of the texel in memory 259 | * E.g. the float containing the red value would be at: 260 | * Data_float[texelIndex + bufferDesc.Red] 261 | */ 262 | unsigned char Red = 0; 263 | unsigned char Green = 0; 264 | unsigned char Blue = 0; 265 | unsigned char Alpha = 0; 266 | }; 267 | 268 | /* We use this struct for annotations rather than the Inspector struct so that 269 | * the whole Inspector struct doesn't have to be exposed in this header. 270 | */ 271 | struct AnnotationsDesc 272 | { 273 | ImDrawList *DrawList; 274 | ImVec2 TexelViewSize; // How many texels are visible for annotating 275 | ImVec2 TexelTopLeft; // Coordinated in texture space of top left visible texel 276 | BufferDesc Buffer; // Description of cache texel data 277 | Transform2D TexelsToPixels; // Transform to go from texel space to screen pixel space 278 | }; 279 | 280 | //------------------------------------------------------------------------- 281 | // [SECTION] FORWARD DECLARATIONS FOR TEMPLATE IMPLEMENTATION - Do not call directly 282 | //------------------------------------------------------------------------- 283 | 284 | ImVec4 GetTexel(const BufferDesc *bd, int x, int y); 285 | bool GetAnnotationDesc(AnnotationsDesc *, ImU64 maxAnnotatedTexels); 286 | 287 | //------------------------------------------------------------------------- 288 | // [SECTION] TEMPLATE IMPLEMENTATION 289 | //------------------------------------------------------------------------- 290 | template 291 | void DrawAnnotations(T drawer, ImU64 maxAnnotatedTexels) 292 | { 293 | AnnotationsDesc ad; 294 | if (GetAnnotationDesc(&ad, maxAnnotatedTexels)) 295 | { 296 | ImVec2 texelBottomRight = ImVec2(ad.TexelTopLeft.x + ad.TexelViewSize.x, ad.TexelTopLeft.y + ad.TexelViewSize.y); 297 | for (int ty = (int)ad.TexelTopLeft.y; ty < (int)texelBottomRight.y; ++ty) 298 | { 299 | for (int tx = (int)ad.TexelTopLeft.x; tx < (int)texelBottomRight.x; ++tx) 300 | { 301 | ImVec4 color = GetTexel(&ad.Buffer, tx, ty); 302 | ImVec2 center = {(float)tx + 0.5f, (float)ty + 0.5f}; 303 | drawer.DrawAnnotation(ad.DrawList, center, ad.TexelsToPixels, color); 304 | } 305 | } 306 | } 307 | } 308 | } // namespace ImGuiTexInspect 309 | -------------------------------------------------------------------------------- /backends/tex_inspect_directx11.cpp: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | 3 | #include "imgui.h" 4 | #include "imgui_tex_inspect_internal.h" 5 | #include 6 | #include 7 | 8 | namespace ImGuiTexInspect 9 | { 10 | 11 | /* Constant buffer used in pixel shader. Size must be multiple of 16 bytes. 12 | * Layout must match the layout in the pixel shader. */ 13 | struct PIXEL_CONSTANT_BUFFER 14 | { 15 | float ColorTransform[16]; 16 | float ColorOffset[4]; 17 | float Grid[4]; 18 | float GridWidth[2]; 19 | float PremultiplyAlpha; 20 | float DisableFinalAlpha; 21 | float BackgroundColor[3]; 22 | bool forceNearestSampling; 23 | float TextureSize[2]; 24 | float padding[2]; 25 | }; 26 | 27 | struct ImGuiTexInspect_ImplDX11_Data 28 | { 29 | ID3D11Device *pd3dDevice = NULL; 30 | ID3D11DeviceContext *pd3dDeviceContext = NULL; 31 | ID3D11PixelShader *pPixelShader = NULL; 32 | ID3D11Buffer *pPixelConstantBuffer = NULL; 33 | }; 34 | 35 | static ImGuiTexInspect_ImplDX11_Data GImplData; 36 | 37 | 38 | bool ImplDX11_Init(ID3D11Device *device, ID3D11DeviceContext *device_context) 39 | { 40 | // Check we're not initializing more than once 41 | assert(GImplData.pd3dDevice == NULL); 42 | 43 | // Save pointers to DirectX device and context 44 | GImplData.pd3dDevice = device; 45 | GImplData.pd3dDevice->AddRef(); 46 | 47 | GImplData.pd3dDeviceContext = device_context; 48 | GImplData.pd3dDeviceContext->AddRef(); 49 | 50 | // Create our pixel shader 51 | { 52 | static const char *pixelShader = 53 | "cbuffer pixelBuffer :register(b0)\n\ 54 | {\n\ 55 | float4x4 ColorTransform;\n\ 56 | float4 ColorOffset;\n\ 57 | float4 Grid;\n\ 58 | float2 GridWidth;\n\ 59 | float PremultiplyAlpha;\n\ 60 | float DisableFinalAlpha;\n\ 61 | float3 BackgroundColor;\n\ 62 | bool ForceNearestSampling;\n\ 63 | float2 TextureSize;\n\ 64 | };\n\ 65 | struct PS_INPUT\n\ 66 | {\n\ 67 | float4 pos : SV_POSITION;\n\ 68 | float4 col : COLOR0;\n\ 69 | float2 uv : TEXCOORD0;\n\ 70 | };\n\ 71 | sampler sampler0;\n\ 72 | Texture2D texture0;\n\ 73 | \n\ 74 | float4 main(PS_INPUT input) : SV_Target\n\ 75 | {\n\ 76 | float2 uv;\n\ 77 | float2 texel = input.uv * TextureSize;\n\ 78 | if (ForceNearestSampling)\n\ 79 | uv = (floor(texel) + float2(0.5, 0.5)) / TextureSize;\n\ 80 | else\n\ 81 | uv = input.uv;\n\ 82 | float2 texelEdge = step(texel - floor(texel), GridWidth);\n\ 83 | float isGrid = max(texelEdge.x, texelEdge.y);\n\ 84 | float4 ct = mul(ColorTransform, texture0.Sample(sampler0, uv)) + ColorOffset;\n\ 85 | ct.rgb = ct.rgb * lerp(1.0, ct.a, PremultiplyAlpha);\n\ 86 | ct.rgb += BackgroundColor * (1.0 - ct.a);\n\ 87 | ct.a = lerp(ct.a, 1.0, DisableFinalAlpha);\n\ 88 | ct = lerp(ct, float4(Grid.rgb, 1), Grid.a * isGrid);\n\ 89 | return ct;\n\ 90 | }"; 91 | 92 | ID3DBlob *pixelShaderBlob; 93 | ID3DBlob *errorBlob; 94 | if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, &errorBlob))) 95 | { 96 | fprintf(stderr, "ImGuiTexInspect pixel shader failed. Diagnostic:\n%s\n", (const char *)errorBlob->GetBufferPointer()); 97 | errorBlob->Release(); 98 | return false; 99 | } 100 | 101 | if (GImplData.pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, 102 | &GImplData.pPixelShader) != S_OK) 103 | { 104 | pixelShaderBlob->Release(); 105 | return false; 106 | } 107 | pixelShaderBlob->Release(); 108 | } 109 | 110 | // Create pixel shader constant buffer 111 | { 112 | D3D11_BUFFER_DESC desc; 113 | desc.ByteWidth = sizeof(PIXEL_CONSTANT_BUFFER); 114 | desc.Usage = D3D11_USAGE_DYNAMIC; 115 | desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 116 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 117 | desc.MiscFlags = 0; 118 | GImplData.pd3dDevice->CreateBuffer(&desc, NULL, &GImplData.pPixelConstantBuffer); 119 | } 120 | 121 | return true; 122 | } 123 | 124 | void ImplDX11_Shutdown() 125 | { 126 | if (GImplData.pd3dDevice) 127 | GImplData.pd3dDevice->Release(); 128 | 129 | if (GImplData.pd3dDeviceContext) 130 | GImplData.pd3dDeviceContext->Release(); 131 | 132 | if (GImplData.pPixelConstantBuffer) 133 | GImplData.pPixelConstantBuffer->Release(); 134 | 135 | if (GImplData.pPixelShader) 136 | GImplData.pPixelShader->Release(); 137 | 138 | GImplData.pd3dDevice = NULL; 139 | } 140 | 141 | void GiveNotInitializedWarning() 142 | { 143 | static bool warningGiven = false; 144 | if (!warningGiven) 145 | { 146 | fprintf(stderr, "ERROR: ImGuiTexInspect backend not initialized\n"); 147 | warningGiven = true; 148 | } 149 | } 150 | 151 | struct DX11FormatDesc 152 | { 153 | ImGuiDataType_ type; 154 | int channelCount; 155 | 156 | int GetComponentSize() 157 | { 158 | switch (type) 159 | { 160 | case ImGuiDataType_S8: return 1; 161 | case ImGuiDataType_U8: return 1; 162 | case ImGuiDataType_S16: return 2; 163 | case ImGuiDataType_U16: return 2; 164 | case ImGuiDataType_S32: return 4; 165 | case ImGuiDataType_U32: return 4; 166 | case ImGuiDataType_S64: return 8; 167 | case ImGuiDataType_U64: return 8; 168 | case ImGuiDataType_Float: return 4; 169 | case ImGuiDataType_Double: return 8; 170 | default: 171 | // Shouldn't get here 172 | assert(false); 173 | return 0; 174 | } 175 | } 176 | }; 177 | 178 | bool DecodeDXGIFormat(DXGI_FORMAT format, DX11FormatDesc *desc) 179 | { 180 | switch (format) 181 | { 182 | case DXGI_FORMAT_R8G8B8A8_UNORM: 183 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: 184 | case DXGI_FORMAT_R8G8B8A8_UINT: 185 | desc->type = ImGuiDataType_U8; 186 | desc->channelCount = 4; 187 | return true; 188 | 189 | case DXGI_FORMAT_R8G8_UNORM: 190 | case DXGI_FORMAT_R8G8_UINT: 191 | desc->type = ImGuiDataType_U8; 192 | desc->channelCount = 2; 193 | return true; 194 | 195 | case DXGI_FORMAT_R8_UNORM: 196 | case DXGI_FORMAT_R8_UINT: 197 | desc->type = ImGuiDataType_U8; 198 | desc->channelCount = 1; 199 | return true; 200 | 201 | case DXGI_FORMAT_R32G32B32A32_FLOAT: 202 | desc->type = ImGuiDataType_Float; 203 | desc->channelCount = 4; 204 | return true; 205 | 206 | case DXGI_FORMAT_R32G32B32_FLOAT: 207 | desc->type = ImGuiDataType_Float; 208 | desc->channelCount = 3; 209 | return true; 210 | 211 | case DXGI_FORMAT_R32G32_FLOAT: 212 | desc->type = ImGuiDataType_Float; 213 | desc->channelCount = 2; 214 | return true; 215 | 216 | case DXGI_FORMAT_R32_FLOAT: 217 | desc->type = ImGuiDataType_Float; 218 | desc->channelCount = 1; 219 | return true; 220 | 221 | default: 222 | return false; 223 | } 224 | } 225 | 226 | //------------------------------------------------------------------------- 227 | // [SECTION] BackEnd functions declared in imgui_tex_inspect_internal.h 228 | //------------------------------------------------------------------------- 229 | 230 | void BackEnd_SetShader(const ImDrawList *, const ImDrawCmd *, const Inspector *inspector) 231 | { 232 | if (GImplData.pPixelShader == NULL) 233 | { 234 | GiveNotInitializedWarning(); 235 | return; 236 | } 237 | 238 | const ShaderOptions *shaderOptions = &inspector->CachedShaderOptions; 239 | 240 | // Map the pixel shader constant buffer and fill values 241 | { 242 | D3D11_MAPPED_SUBRESOURCE mapped_resource; 243 | if (GImplData.pd3dDeviceContext->Map(GImplData.pPixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) 244 | return; 245 | 246 | 247 | // Transfer shader options from shaderOptions to our backend specific pixel shader constant buffer 248 | PIXEL_CONSTANT_BUFFER *constant_buffer = (PIXEL_CONSTANT_BUFFER *)mapped_resource.pData; 249 | 250 | memcpy(constant_buffer->ColorTransform, shaderOptions->ColorTransform, sizeof(shaderOptions->ColorTransform)); 251 | memcpy(constant_buffer->ColorOffset, shaderOptions->ColorOffset, sizeof(shaderOptions->ColorOffset)); 252 | memcpy(constant_buffer->Grid, &shaderOptions->GridColor, sizeof(shaderOptions->GridColor)); 253 | memcpy(constant_buffer->GridWidth, &shaderOptions->GridWidth, sizeof(shaderOptions->GridWidth)); 254 | memcpy(constant_buffer->BackgroundColor, &shaderOptions->BackgroundColor, sizeof(shaderOptions->BackgroundColor)); 255 | memcpy(constant_buffer->TextureSize, &inspector->TextureSize, sizeof(inspector->TextureSize)); 256 | 257 | constant_buffer->PremultiplyAlpha = shaderOptions->PremultiplyAlpha; 258 | constant_buffer->DisableFinalAlpha = shaderOptions->DisableFinalAlpha; 259 | constant_buffer->forceNearestSampling = shaderOptions->ForceNearestSampling; 260 | 261 | GImplData.pd3dDeviceContext->Unmap(GImplData.pPixelConstantBuffer, 0); 262 | } 263 | 264 | // Activate shader and buffer 265 | GImplData.pd3dDeviceContext->PSSetShader(GImplData.pPixelShader, NULL, 0); 266 | GImplData.pd3dDeviceContext->PSSetConstantBuffers(0, 1, &GImplData.pPixelConstantBuffer); 267 | } 268 | 269 | bool BackEnd_GetData(Inspector *inspector, ImTextureID texture, int /*x*/, int /*y*/, int /*width*/, int /*height*/, BufferDesc *bufferDesc) 270 | { 271 | if (GImplData.pd3dDevice == NULL) 272 | { 273 | GiveNotInitializedWarning(); 274 | return false; 275 | } 276 | ID3D11Texture2D *pTexture = NULL; 277 | 278 | // Get a pointer to the texture 279 | { 280 | ID3D11ShaderResourceView *pTextureView = (ID3D11ShaderResourceView *)texture; 281 | ID3D11Resource *pResource; 282 | pTextureView->GetResource(&pResource); 283 | 284 | if (pResource == NULL) 285 | return false; 286 | 287 | pResource->QueryInterface(&pTexture); 288 | 289 | if (pTexture == NULL) 290 | { 291 | pResource->Release(); 292 | return false; 293 | } 294 | pResource->Release(); 295 | } 296 | 297 | int texWidth = (int)inspector->TextureSize.x; 298 | int texHeight = (int)inspector->TextureSize.y; 299 | 300 | ID3D11Texture2D *pStagingTexture = nullptr; 301 | DX11FormatDesc formatDesc; 302 | 303 | // Create a CPU accessible texture to copy src texture into 304 | { 305 | D3D11_TEXTURE2D_DESC texDesc; 306 | pTexture->GetDesc(&texDesc); 307 | 308 | if (!DecodeDXGIFormat(texDesc.Format, &formatDesc)) 309 | { 310 | // Not a supoorted format 311 | pTexture->Release(); 312 | return false; 313 | } 314 | 315 | // We'll keep all settings as is except for these: 316 | texDesc.Usage = D3D11_USAGE_STAGING; 317 | texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 318 | texDesc.BindFlags = 0; 319 | texDesc.MiscFlags = 0; 320 | 321 | /* Yes we could be keeping this staging texture around rather than creating it 322 | * every time. But in profiling it was apparent that the cost of creating the 323 | * texture is not significant compared to copying the data. So it's not worth the 324 | * complexity of tracking and releasing a texture for each Inspector. 325 | */ 326 | HRESULT hr = GImplData.pd3dDevice->CreateTexture2D(&texDesc, NULL, &pStagingTexture); 327 | 328 | if (FAILED(hr)) 329 | { 330 | pTexture->Release(); 331 | return false; 332 | } 333 | } 334 | 335 | // Oopy texture data to CPU accessible texture 336 | GImplData.pd3dDeviceContext->CopyResource(pStagingTexture, pTexture); 337 | 338 | D3D11_MAPPED_SUBRESOURCE resourceDesc = {}; 339 | HRESULT hr = GImplData.pd3dDeviceContext->Map(pStagingTexture, 0, D3D11_MAP_READ, 0, &resourceDesc); 340 | bool success = false; 341 | if (SUCCEEDED(hr)) 342 | { 343 | int componentSize = formatDesc.GetComponentSize(); 344 | int channelCount = formatDesc.channelCount; 345 | 346 | void *copyDst = NULL; 347 | if (formatDesc.type == ImGuiDataType_Float) 348 | { 349 | bufferDesc->Data_float = 350 | (float *)ImGuiTexInspect::GetBuffer(inspector, (size_t)texWidth * texHeight * channelCount * componentSize); 351 | bufferDesc->Data_uint8_t = NULL; 352 | copyDst = bufferDesc->Data_float; 353 | } 354 | else // ImGuiDataType_U8 is only other supported type at the moment 355 | { 356 | bufferDesc->Data_uint8_t = ImGuiTexInspect::GetBuffer(inspector, (size_t)texWidth * texHeight * channelCount * componentSize); 357 | bufferDesc->Data_float = NULL; 358 | copyDst = bufferDesc->Data_uint8_t; 359 | } 360 | 361 | if (copyDst) 362 | { 363 | int const bytesPerPixel = componentSize * channelCount; 364 | for (int i = 0; i < texHeight; ++i) 365 | { 366 | /* TODO : An obvious optimization would be to return a pointer 367 | * directly into the DirectX ResourceDesc data. We would need 368 | * another callback to know when to unmap it. 369 | */ 370 | memcpy((byte *)copyDst + texWidth * bytesPerPixel * i, (byte *)resourceDesc.pData + resourceDesc.RowPitch * i, 371 | (size_t)texWidth * bytesPerPixel); 372 | } 373 | bufferDesc->BufferByteSize = (size_t)texWidth * texHeight * bytesPerPixel; 374 | bufferDesc->Red = 0; 375 | bufferDesc->Green = (ImU8)ImMin(1, channelCount - 1); 376 | bufferDesc->Blue = (ImU8)ImMin(2, channelCount - 1); 377 | bufferDesc->Alpha = (ImU8)ImMin(3, channelCount - 1); 378 | bufferDesc->ChannelCount = (ImU8)channelCount; 379 | 380 | bufferDesc->LineStride = (int)inspector->TextureSize.x * channelCount; 381 | bufferDesc->Stride = channelCount; 382 | bufferDesc->StartX = 0; 383 | bufferDesc->StartY = 0; 384 | bufferDesc->Width = texWidth; 385 | bufferDesc->Height = texHeight; 386 | 387 | success = true; 388 | } 389 | GImplData.pd3dDeviceContext->Unmap(pStagingTexture, 0); 390 | } 391 | 392 | pTexture->Release(); 393 | 394 | pStagingTexture->Release(); 395 | 396 | return success; 397 | } 398 | } // namespace ImGuiTexInspect 399 | -------------------------------------------------------------------------------- /examples/libs/glfw/include/GLFW/glfw3native.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * GLFW 3.2 - www.glfw.org 3 | * A library for OpenGL, window and input 4 | *------------------------------------------------------------------------ 5 | * Copyright (c) 2002-2006 Marcus Geelnard 6 | * Copyright (c) 2006-2010 Camilla Berglund 7 | * 8 | * This software is provided 'as-is', without any express or implied 9 | * warranty. In no event will the authors be held liable for any damages 10 | * arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, 13 | * including commercial applications, and to alter it and redistribute it 14 | * freely, subject to the following restrictions: 15 | * 16 | * 1. The origin of this software must not be misrepresented; you must not 17 | * claim that you wrote the original software. If you use this software 18 | * in a product, an acknowledgment in the product documentation would 19 | * be appreciated but is not required. 20 | * 21 | * 2. Altered source versions must be plainly marked as such, and must not 22 | * be misrepresented as being the original software. 23 | * 24 | * 3. This notice may not be removed or altered from any source 25 | * distribution. 26 | * 27 | *************************************************************************/ 28 | 29 | #ifndef _glfw3_native_h_ 30 | #define _glfw3_native_h_ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | 37 | /************************************************************************* 38 | * Doxygen documentation 39 | *************************************************************************/ 40 | 41 | /*! @file glfw3native.h 42 | * @brief The header of the native access functions. 43 | * 44 | * This is the header file of the native access functions. See @ref native for 45 | * more information. 46 | */ 47 | /*! @defgroup native Native access 48 | * 49 | * **By using the native access functions you assert that you know what you're 50 | * doing and how to fix problems caused by using them. If you don't, you 51 | * shouldn't be using them.** 52 | * 53 | * Before the inclusion of @ref glfw3native.h, you may define exactly one 54 | * window system API macro and zero or more context creation API macros. 55 | * 56 | * The chosen backends must match those the library was compiled for. Failure 57 | * to do this will cause a link-time error. 58 | * 59 | * The available window API macros are: 60 | * * `GLFW_EXPOSE_NATIVE_WIN32` 61 | * * `GLFW_EXPOSE_NATIVE_COCOA` 62 | * * `GLFW_EXPOSE_NATIVE_X11` 63 | * * `GLFW_EXPOSE_NATIVE_WAYLAND` 64 | * * `GLFW_EXPOSE_NATIVE_MIR` 65 | * 66 | * The available context API macros are: 67 | * * `GLFW_EXPOSE_NATIVE_WGL` 68 | * * `GLFW_EXPOSE_NATIVE_NSGL` 69 | * * `GLFW_EXPOSE_NATIVE_GLX` 70 | * * `GLFW_EXPOSE_NATIVE_EGL` 71 | * 72 | * These macros select which of the native access functions that are declared 73 | * and which platform-specific headers to include. It is then up your (by 74 | * definition platform-specific) code to handle which of these should be 75 | * defined. 76 | */ 77 | 78 | 79 | /************************************************************************* 80 | * System headers and types 81 | *************************************************************************/ 82 | 83 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 84 | // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for 85 | // example to allow applications to correctly declare a GL_ARB_debug_output 86 | // callback) but windows.h assumes no one will define APIENTRY before it does 87 | #undef APIENTRY 88 | #include 89 | #elif defined(GLFW_EXPOSE_NATIVE_COCOA) 90 | #include 91 | #if defined(__OBJC__) 92 | #import 93 | #else 94 | typedef void* id; 95 | #endif 96 | #elif defined(GLFW_EXPOSE_NATIVE_X11) 97 | #include 98 | #include 99 | #elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) 100 | #include 101 | #elif defined(GLFW_EXPOSE_NATIVE_MIR) 102 | #include 103 | #endif 104 | 105 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 106 | /* WGL is declared by windows.h */ 107 | #endif 108 | #if defined(GLFW_EXPOSE_NATIVE_NSGL) 109 | /* NSGL is declared by Cocoa.h */ 110 | #endif 111 | #if defined(GLFW_EXPOSE_NATIVE_GLX) 112 | #include 113 | #endif 114 | #if defined(GLFW_EXPOSE_NATIVE_EGL) 115 | #include 116 | #endif 117 | 118 | 119 | /************************************************************************* 120 | * Functions 121 | *************************************************************************/ 122 | 123 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 124 | /*! @brief Returns the adapter device name of the specified monitor. 125 | * 126 | * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) 127 | * of the specified monitor, or `NULL` if an [error](@ref error_handling) 128 | * occurred. 129 | * 130 | * @thread_safety This function may be called from any thread. Access is not 131 | * synchronized. 132 | * 133 | * @since Added in version 3.1. 134 | * 135 | * @ingroup native 136 | */ 137 | GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); 138 | 139 | /*! @brief Returns the display device name of the specified monitor. 140 | * 141 | * @return The UTF-8 encoded display device name (for example 142 | * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an 143 | * [error](@ref error_handling) occurred. 144 | * 145 | * @thread_safety This function may be called from any thread. Access is not 146 | * synchronized. 147 | * 148 | * @since Added in version 3.1. 149 | * 150 | * @ingroup native 151 | */ 152 | GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); 153 | 154 | /*! @brief Returns the `HWND` of the specified window. 155 | * 156 | * @return The `HWND` of the specified window, or `NULL` if an 157 | * [error](@ref error_handling) occurred. 158 | * 159 | * @thread_safety This function may be called from any thread. Access is not 160 | * synchronized. 161 | * 162 | * @since Added in version 3.0. 163 | * 164 | * @ingroup native 165 | */ 166 | GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); 167 | #endif 168 | 169 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 170 | /*! @brief Returns the `HGLRC` of the specified window. 171 | * 172 | * @return The `HGLRC` of the specified window, or `NULL` if an 173 | * [error](@ref error_handling) occurred. 174 | * 175 | * @thread_safety This function may be called from any thread. Access is not 176 | * synchronized. 177 | * 178 | * @since Added in version 3.0. 179 | * 180 | * @ingroup native 181 | */ 182 | GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); 183 | #endif 184 | 185 | #if defined(GLFW_EXPOSE_NATIVE_COCOA) 186 | /*! @brief Returns the `CGDirectDisplayID` of the specified monitor. 187 | * 188 | * @return The `CGDirectDisplayID` of the specified monitor, or 189 | * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. 190 | * 191 | * @thread_safety This function may be called from any thread. Access is not 192 | * synchronized. 193 | * 194 | * @since Added in version 3.1. 195 | * 196 | * @ingroup native 197 | */ 198 | GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); 199 | 200 | /*! @brief Returns the `NSWindow` of the specified window. 201 | * 202 | * @return The `NSWindow` of the specified window, or `nil` if an 203 | * [error](@ref error_handling) occurred. 204 | * 205 | * @thread_safety This function may be called from any thread. Access is not 206 | * synchronized. 207 | * 208 | * @since Added in version 3.0. 209 | * 210 | * @ingroup native 211 | */ 212 | GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); 213 | #endif 214 | 215 | #if defined(GLFW_EXPOSE_NATIVE_NSGL) 216 | /*! @brief Returns the `NSOpenGLContext` of the specified window. 217 | * 218 | * @return The `NSOpenGLContext` of the specified window, or `nil` if an 219 | * [error](@ref error_handling) occurred. 220 | * 221 | * @thread_safety This function may be called from any thread. Access is not 222 | * synchronized. 223 | * 224 | * @since Added in version 3.0. 225 | * 226 | * @ingroup native 227 | */ 228 | GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); 229 | #endif 230 | 231 | #if defined(GLFW_EXPOSE_NATIVE_X11) 232 | /*! @brief Returns the `Display` used by GLFW. 233 | * 234 | * @return The `Display` used by GLFW, or `NULL` if an 235 | * [error](@ref error_handling) occurred. 236 | * 237 | * @thread_safety This function may be called from any thread. Access is not 238 | * synchronized. 239 | * 240 | * @since Added in version 3.0. 241 | * 242 | * @ingroup native 243 | */ 244 | GLFWAPI Display* glfwGetX11Display(void); 245 | 246 | /*! @brief Returns the `RRCrtc` of the specified monitor. 247 | * 248 | * @return The `RRCrtc` of the specified monitor, or `None` if an 249 | * [error](@ref error_handling) occurred. 250 | * 251 | * @thread_safety This function may be called from any thread. Access is not 252 | * synchronized. 253 | * 254 | * @since Added in version 3.1. 255 | * 256 | * @ingroup native 257 | */ 258 | GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); 259 | 260 | /*! @brief Returns the `RROutput` of the specified monitor. 261 | * 262 | * @return The `RROutput` of the specified monitor, or `None` if an 263 | * [error](@ref error_handling) occurred. 264 | * 265 | * @thread_safety This function may be called from any thread. Access is not 266 | * synchronized. 267 | * 268 | * @since Added in version 3.1. 269 | * 270 | * @ingroup native 271 | */ 272 | GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); 273 | 274 | /*! @brief Returns the `Window` of the specified window. 275 | * 276 | * @return The `Window` of the specified window, or `None` if an 277 | * [error](@ref error_handling) occurred. 278 | * 279 | * @thread_safety This function may be called from any thread. Access is not 280 | * synchronized. 281 | * 282 | * @since Added in version 3.0. 283 | * 284 | * @ingroup native 285 | */ 286 | GLFWAPI Window glfwGetX11Window(GLFWwindow* window); 287 | #endif 288 | 289 | #if defined(GLFW_EXPOSE_NATIVE_GLX) 290 | /*! @brief Returns the `GLXContext` of the specified window. 291 | * 292 | * @return The `GLXContext` of the specified window, or `NULL` if an 293 | * [error](@ref error_handling) occurred. 294 | * 295 | * @thread_safety This function may be called from any thread. Access is not 296 | * synchronized. 297 | * 298 | * @since Added in version 3.0. 299 | * 300 | * @ingroup native 301 | */ 302 | GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); 303 | 304 | /*! @brief Returns the `GLXWindow` of the specified window. 305 | * 306 | * @return The `GLXWindow` of the specified window, or `None` if an 307 | * [error](@ref error_handling) occurred. 308 | * 309 | * @thread_safety This function may be called from any thread. Access is not 310 | * synchronized. 311 | * 312 | * @since Added in version 3.2. 313 | * 314 | * @ingroup native 315 | */ 316 | GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); 317 | #endif 318 | 319 | #if defined(GLFW_EXPOSE_NATIVE_WAYLAND) 320 | /*! @brief Returns the `struct wl_display*` used by GLFW. 321 | * 322 | * @return The `struct wl_display*` used by GLFW, or `NULL` if an 323 | * [error](@ref error_handling) occurred. 324 | * 325 | * @thread_safety This function may be called from any thread. Access is not 326 | * synchronized. 327 | * 328 | * @since Added in version 3.2. 329 | * 330 | * @ingroup native 331 | */ 332 | GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); 333 | 334 | /*! @brief Returns the `struct wl_output*` of the specified monitor. 335 | * 336 | * @return The `struct wl_output*` of the specified monitor, or `NULL` if an 337 | * [error](@ref error_handling) occurred. 338 | * 339 | * @thread_safety This function may be called from any thread. Access is not 340 | * synchronized. 341 | * 342 | * @since Added in version 3.2. 343 | * 344 | * @ingroup native 345 | */ 346 | GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); 347 | 348 | /*! @brief Returns the main `struct wl_surface*` of the specified window. 349 | * 350 | * @return The main `struct wl_surface*` of the specified window, or `NULL` if 351 | * an [error](@ref error_handling) occurred. 352 | * 353 | * @thread_safety This function may be called from any thread. Access is not 354 | * synchronized. 355 | * 356 | * @since Added in version 3.2. 357 | * 358 | * @ingroup native 359 | */ 360 | GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); 361 | #endif 362 | 363 | #if defined(GLFW_EXPOSE_NATIVE_MIR) 364 | /*! @brief Returns the `MirConnection*` used by GLFW. 365 | * 366 | * @return The `MirConnection*` used by GLFW, or `NULL` if an 367 | * [error](@ref error_handling) occurred. 368 | * 369 | * @thread_safety This function may be called from any thread. Access is not 370 | * synchronized. 371 | * 372 | * @since Added in version 3.2. 373 | * 374 | * @ingroup native 375 | */ 376 | GLFWAPI MirConnection* glfwGetMirDisplay(void); 377 | 378 | /*! @brief Returns the Mir output ID of the specified monitor. 379 | * 380 | * @return The Mir output ID of the specified monitor, or zero if an 381 | * [error](@ref error_handling) occurred. 382 | * 383 | * @thread_safety This function may be called from any thread. Access is not 384 | * synchronized. 385 | * 386 | * @since Added in version 3.2. 387 | * 388 | * @ingroup native 389 | */ 390 | GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); 391 | 392 | /*! @brief Returns the `MirSurface*` of the specified window. 393 | * 394 | * @return The `MirSurface*` of the specified window, or `NULL` if an 395 | * [error](@ref error_handling) occurred. 396 | * 397 | * @thread_safety This function may be called from any thread. Access is not 398 | * synchronized. 399 | * 400 | * @since Added in version 3.2. 401 | * 402 | * @ingroup native 403 | */ 404 | GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); 405 | #endif 406 | 407 | #if defined(GLFW_EXPOSE_NATIVE_EGL) 408 | /*! @brief Returns the `EGLDisplay` used by GLFW. 409 | * 410 | * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an 411 | * [error](@ref error_handling) occurred. 412 | * 413 | * @thread_safety This function may be called from any thread. Access is not 414 | * synchronized. 415 | * 416 | * @since Added in version 3.0. 417 | * 418 | * @ingroup native 419 | */ 420 | GLFWAPI EGLDisplay glfwGetEGLDisplay(void); 421 | 422 | /*! @brief Returns the `EGLContext` of the specified window. 423 | * 424 | * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an 425 | * [error](@ref error_handling) occurred. 426 | * 427 | * @thread_safety This function may be called from any thread. Access is not 428 | * synchronized. 429 | * 430 | * @since Added in version 3.0. 431 | * 432 | * @ingroup native 433 | */ 434 | GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); 435 | 436 | /*! @brief Returns the `EGLSurface` of the specified window. 437 | * 438 | * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an 439 | * [error](@ref error_handling) occurred. 440 | * 441 | * @thread_safety This function may be called from any thread. Access is not 442 | * synchronized. 443 | * 444 | * @since Added in version 3.0. 445 | * 446 | * @ingroup native 447 | */ 448 | GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); 449 | #endif 450 | 451 | #ifdef __cplusplus 452 | } 453 | #endif 454 | 455 | #endif /* _glfw3_native_h_ */ 456 | 457 | -------------------------------------------------------------------------------- /examples/libs/usynergy/uSynergy.h: -------------------------------------------------------------------------------- 1 | /* 2 | uSynergy client -- Interface for the embedded Synergy client library 3 | version 1.0.0, July 7th, 2012 4 | 5 | Copyright (C) 2012 Synergy Si Ltd. 6 | Copyright (c) 2012 Alex Evans 7 | 8 | This software is provided 'as-is', without any express or implied 9 | warranty. In no event will the authors be held liable for any damages 10 | arising from the use of this software. 11 | 12 | Permission is granted to anyone to use this software for any purpose, 13 | including commercial applications, and to alter it and redistribute it 14 | freely, subject to the following restrictions: 15 | 16 | 1. The origin of this software must not be misrepresented; you must not 17 | claim that you wrote the original software. If you use this software 18 | in a product, an acknowledgment in the product documentation would be 19 | appreciated but is not required. 20 | 21 | 2. Altered source versions must be plainly marked as such, and must not be 22 | misrepresented as being the original software. 23 | 24 | 3. This notice may not be removed or altered from any source 25 | distribution. 26 | */ 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | 34 | 35 | //--------------------------------------------------------------------------------------------------------------------- 36 | // Configuration 37 | //--------------------------------------------------------------------------------------------------------------------- 38 | 39 | 40 | 41 | /** 42 | @brief Determine endianness 43 | **/ 44 | #if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN) 45 | /* Ambiguous: both endians specified */ 46 | #error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN" 47 | #elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN) 48 | /* Attempt to auto detect */ 49 | #if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN) 50 | #define USYNERGY_LITTLE_ENDIAN 51 | #elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN) 52 | #define USYNERGY_BIG_ENDIAN 53 | #else 54 | #error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN"; 55 | #endif 56 | #else 57 | /* User-specified endian-nes, nothing to do for us */ 58 | #endif 59 | 60 | 61 | 62 | //--------------------------------------------------------------------------------------------------------------------- 63 | // Types and Constants 64 | //--------------------------------------------------------------------------------------------------------------------- 65 | 66 | 67 | 68 | /** 69 | @brief Boolean type 70 | **/ 71 | typedef int uSynergyBool; 72 | #define USYNERGY_FALSE 0 /* False value */ 73 | #define USYNERGY_TRUE 1 /* True value */ 74 | 75 | 76 | /** 77 | @brief User context type 78 | 79 | The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to 80 | callback functions as context. 81 | **/ 82 | typedef struct { int ignored; } * uSynergyCookie; 83 | 84 | 85 | 86 | /** 87 | @brief Clipboard types 88 | **/ 89 | enum uSynergyClipboardFormat 90 | { 91 | USYNERGY_CLIPBOARD_FORMAT_TEXT = 0, /* Text format, UTF-8, newline is LF */ 92 | USYNERGY_CLIPBOARD_FORMAT_BITMAP = 1, /* Bitmap format, BMP 24/32bpp, BI_RGB */ 93 | USYNERGY_CLIPBOARD_FORMAT_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */ 94 | }; 95 | 96 | 97 | 98 | /** 99 | @brief Constants and limits 100 | **/ 101 | #define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */ 102 | 103 | #define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */ 104 | #define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */ 105 | 106 | #define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */ 107 | 108 | #define USYNERGY_TRACE_BUFFER_SIZE 1024 /* Maximum length of traced message */ 109 | #define USYNERGY_REPLY_BUFFER_SIZE 1024 /* Maximum size of a reply packet */ 110 | #define USYNERGY_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */ 111 | 112 | 113 | 114 | /** 115 | @brief Keyboard constants 116 | **/ 117 | #define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */ 118 | #define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */ 119 | #define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */ 120 | #define USYNERGY_MODIFIER_META 0x0008 /* Meta key modifier */ 121 | #define USYNERGY_MODIFIER_WIN 0x0010 /* Windows key modifier */ 122 | #define USYNERGY_MODIFIER_ALT_GR 0x0020 /* AltGr key modifier */ 123 | #define USYNERGY_MODIFIER_LEVEL5LOCK 0x0040 /* Level5Lock key modifier */ 124 | #define USYNERGY_MODIFIER_CAPSLOCK 0x1000 /* CapsLock key modifier */ 125 | #define USYNERGY_MODIFIER_NUMLOCK 0x2000 /* NumLock key modifier */ 126 | #define USYNERGY_MODIFIER_SCROLLOCK 0x4000 /* ScrollLock key modifier */ 127 | 128 | 129 | 130 | 131 | //--------------------------------------------------------------------------------------------------------------------- 132 | // Functions and Callbacks 133 | //--------------------------------------------------------------------------------------------------------------------- 134 | 135 | 136 | 137 | /** 138 | @brief Connect function 139 | 140 | This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or 141 | destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a 142 | connection was established or USYNERGY_FALSE if it could not connect. 143 | 144 | When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again 145 | so the implementation of the function must close any old connections and clean up resources before retrying. 146 | 147 | @param cookie Cookie supplied in the Synergy context 148 | **/ 149 | typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie); 150 | 151 | 152 | 153 | /** 154 | @brief Send function 155 | 156 | This function is called when uSynergy needs to send something over the default connection. It should return 157 | USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send 158 | operation is completed. 159 | 160 | @param cookie Cookie supplied in the Synergy context 161 | @param buffer Address of buffer to send 162 | @param length Length of buffer to send 163 | **/ 164 | typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length); 165 | 166 | 167 | 168 | /** 169 | @brief Receive function 170 | 171 | This function is called when uSynergy needs to receive data from the default connection. It should return 172 | USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data 173 | has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is 174 | assumed that the connection is alive, but still in a connecting state and needs time to settle. 175 | 176 | @param cookie Cookie supplied in the Synergy context 177 | @param buffer Address of buffer to receive data into 178 | @param maxLength Maximum amount of bytes to write into the receive buffer 179 | @param outLength Address of integer that receives the actual amount of bytes written into @a buffer 180 | **/ 181 | typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength); 182 | 183 | 184 | 185 | /** 186 | @brief Thread sleep function 187 | 188 | This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It 189 | is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a 190 | network connection in case the network is down. 191 | 192 | @param cookie Cookie supplied in the Synergy context 193 | @param timeMs Time to sleep the current thread (in milliseconds) 194 | **/ 195 | typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs); 196 | 197 | 198 | 199 | /** 200 | @brief Get time function 201 | 202 | This function is called when uSynergy needs to know the current time. This is used to determine when timeouts 203 | have occured. The time base should be a cyclic millisecond time value. 204 | 205 | @returns Time value in milliseconds 206 | **/ 207 | typedef uint32_t (*uSynergyGetTimeFunc)(); 208 | 209 | 210 | 211 | /** 212 | @brief Trace function 213 | 214 | This function is called when uSynergy wants to trace something. It is optional to show these messages, but they 215 | are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually 216 | only a single trace is shown when the connection is established and no more trace are called. 217 | 218 | @param cookie Cookie supplied in the Synergy context 219 | @param text Text to be traced 220 | **/ 221 | typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text); 222 | 223 | 224 | 225 | /** 226 | @brief Screen active callback 227 | 228 | This callback is called when Synergy makes the screen active or inactive. This 229 | callback is usually sent when the mouse enters or leaves the screen. 230 | 231 | @param cookie Cookie supplied in the Synergy context 232 | @param active Activation flag, 1 if the screen has become active, 0 if the screen has become inactive 233 | **/ 234 | typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active); 235 | 236 | 237 | 238 | /** 239 | @brief Mouse callback 240 | 241 | This callback is called when a mouse events happens. The mouse X and Y position, 242 | wheel and button state is communicated in the message. It's up to the user to 243 | interpret if this is a mouse up, down, double-click or other message. 244 | 245 | @param cookie Cookie supplied in the Synergy context 246 | @param x Mouse X position 247 | @param y Mouse Y position 248 | @param wheelX Mouse wheel X position 249 | @param wheelY Mouse wheel Y position 250 | @param buttonLeft Left button pressed status, 0 for released, 1 for pressed 251 | @param buttonMiddle Middle button pressed status, 0 for released, 1 for pressed 252 | @param buttonRight Right button pressed status, 0 for released, 1 for pressed 253 | **/ 254 | typedef void (*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle); 255 | 256 | 257 | 258 | /** 259 | @brief Key event callback 260 | 261 | This callback is called when a key is pressed or released. 262 | 263 | @param cookie Cookie supplied in the Synergy context 264 | @param key Key code of key that was pressed or released 265 | @param modifiers Status of modifier keys (alt, shift, etc.) 266 | @param down Down or up status, 1 is key is pressed down, 0 if key is released (up) 267 | @param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user 268 | **/ 269 | typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat); 270 | 271 | 272 | 273 | /** 274 | @brief Joystick event callback 275 | 276 | This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are 277 | fired when different sticks or buttons change as these are individual messages in the packet stream. Each 278 | callback will contain all the valid state for the different axes and buttons. The last callback received will 279 | represent the most current joystick state. 280 | 281 | @param cookie Cookie supplied in the Synergy context 282 | @param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS> 283 | @param buttons Button pressed mask 284 | @param leftStickX Left stick X position, in range [-127 ... 127] 285 | @param leftStickY Left stick Y position, in range [-127 ... 127] 286 | @param rightStickX Right stick X position, in range [-127 ... 127] 287 | @param rightStickY Right stick Y position, in range [-127 ... 127] 288 | **/ 289 | typedef void (*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); 290 | 291 | 292 | 293 | /** 294 | @brief Clipboard event callback 295 | 296 | This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for 297 | multiple clipboard formats if they are supported. The data provided is read-only and may not be modified 298 | by the application. 299 | 300 | @param cookie Cookie supplied in the Synergy context 301 | @param format Clipboard format 302 | @param data Memory area containing the clipboard raw data 303 | @param size Size of clipboard data 304 | **/ 305 | typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size); 306 | 307 | 308 | 309 | //--------------------------------------------------------------------------------------------------------------------- 310 | // Context 311 | //--------------------------------------------------------------------------------------------------------------------- 312 | 313 | 314 | 315 | /** 316 | @brief uSynergy context 317 | **/ 318 | typedef struct 319 | { 320 | /* Mandatory configuration data, filled in by client */ 321 | uSynergyConnectFunc m_connectFunc; /* Connect function */ 322 | uSynergySendFunc m_sendFunc; /* Send data function */ 323 | uSynergyReceiveFunc m_receiveFunc; /* Receive data function */ 324 | uSynergySleepFunc m_sleepFunc; /* Thread sleep function */ 325 | uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */ 326 | const char* m_clientName; /* Name of Synergy Screen / Client */ 327 | uint16_t m_clientWidth; /* Width of screen */ 328 | uint16_t m_clientHeight; /* Height of screen */ 329 | 330 | /* Optional configuration data, filled in by client */ 331 | uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */ 332 | uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */ 333 | uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */ 334 | uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */ 335 | uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */ 336 | uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */ 337 | uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */ 338 | 339 | /* State data, used internall by client, initialized by uSynergyInit() */ 340 | uSynergyBool m_connected; /* Is our socket connected? */ 341 | uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */ 342 | uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */ 343 | uint32_t m_lastMessageTime; /* Time at which last message was received */ 344 | uint32_t m_sequenceNumber; /* Packet sequence number */ 345 | uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */ 346 | int m_receiveOfs; /* Receive buffer offset */ 347 | uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */ 348 | uint8_t* m_replyCur; /* Write offset into reply buffer */ 349 | uint16_t m_mouseX; /* Mouse X position */ 350 | uint16_t m_mouseY; /* Mouse Y position */ 351 | int16_t m_mouseWheelX; /* Mouse wheel X position */ 352 | int16_t m_mouseWheelY; /* Mouse wheel Y position */ 353 | uSynergyBool m_mouseButtonLeft; /* Mouse left button */ 354 | uSynergyBool m_mouseButtonRight; /* Mouse right button */ 355 | uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */ 356 | int8_t m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4]; /* Joystick stick position in 2 axes for 2 sticks */ 357 | uint16_t m_joystickButtons[USYNERGY_NUM_JOYSTICKS]; /* Joystick button state */ 358 | } uSynergyContext; 359 | 360 | 361 | 362 | //--------------------------------------------------------------------------------------------------------------------- 363 | // Interface 364 | //--------------------------------------------------------------------------------------------------------------------- 365 | 366 | 367 | 368 | /** 369 | @brief Initialize uSynergy context 370 | 371 | This function initializes @a context for use. Call this function directly after 372 | creating the context, before filling in any configuration data in it. Not calling 373 | this function will cause undefined behavior. 374 | 375 | @param context Context to be initialized 376 | **/ 377 | extern void uSynergyInit(uSynergyContext *context); 378 | 379 | 380 | 381 | /** 382 | @brief Update uSynergy 383 | 384 | This function updates uSynergy and does the bulk of the work. It does connection management, 385 | receiving data, reconnecting after errors or timeouts and so on. It assumes that networking 386 | operations are blocking and it can suspend the current thread if it needs to wait. It is 387 | best practice to call uSynergyUpdate from a background thread so it is responsive. 388 | 389 | Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state 390 | waiting for system mutexes and won't eat much memory. 391 | 392 | uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of 393 | the callbacks it calls. 394 | 395 | @param context Context to be updated 396 | **/ 397 | extern void uSynergyUpdate(uSynergyContext *context); 398 | 399 | 400 | 401 | /** 402 | @brief Send clipboard data 403 | 404 | This function sets new clipboard data and sends it to the server. Use this function if 405 | your client cuts or copies data onto the clipboard that it needs to share with the 406 | server. 407 | 408 | Currently there is only support for plaintext, but HTML and image data could be 409 | supported with some effort. 410 | 411 | @param context Context to send clipboard data to 412 | @param text Text to set to the clipboard 413 | **/ 414 | extern void uSynergySendClipboard(uSynergyContext *context, const char *text); 415 | 416 | 417 | 418 | #ifdef __cplusplus 419 | }; 420 | #endif 421 | -------------------------------------------------------------------------------- /imgui_tex_inspect_demo.cpp: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | 3 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 4 | #define _CRT_SECURE_NO_WARNINGS 5 | #endif 6 | #include "imgui_tex_inspect_internal.h" 7 | #include "imgui_tex_inspect_demo.h" 8 | #include "imgui.h" 9 | #include "imgui_tex_inspect.h" 10 | 11 | #include 12 | 13 | namespace ImGuiTexInspect 14 | { 15 | 16 | Texture testTex; 17 | Texture fontTexture; 18 | bool testInitted = false; 19 | 20 | //------------------------------------------------------------------------- 21 | // [SECTION] FORWARD DECLARATIONS 22 | //------------------------------------------------------------------------- 23 | void Demo_ColorFilters(); 24 | void Demo_ColorMatrix(); 25 | void Demo_TextureAnnotations(); 26 | void Demo_AlphaMode(); 27 | void Demo_WrapAndFilter(); 28 | void ShowDemoWindow(); 29 | Texture LoadDemoTexture(); 30 | void DemoInit(); 31 | 32 | 33 | //------------------------------------------------------------------------- 34 | // [SECTION] EXAMPLE USAGES 35 | //------------------------------------------------------------------------- 36 | 37 | /* Each of the following Demo_* functions is a standalone demo showing an example 38 | * usage of ImGuiTexInspect. You'll notice the structure is essentially the same in 39 | * all the examples, i.e. a call to BeginInspectorPanel & a call to 40 | * EndInspectorPanel, possibly with some annotation functions in between, 41 | * followed by some controls to manipulate the inspector. 42 | * 43 | * Each Demo_* function corresponds to one of the large buttons at the top of 44 | * the demo window. 45 | */ 46 | 47 | /* Demo_ColorFilters 48 | * An example showing controls to filter red, green and blue channels 49 | * independently. These controls are provided by the DrawColorChannelSelector 50 | * funtions. The example also uses the DrawGridEditor function to allow the 51 | * user to control grid appearance. 52 | * 53 | * The Draw_* functions are provided for convenience, it is of course possible 54 | * to control these aspects programmatically. 55 | */ 56 | void Demo_ColorFilters() 57 | { 58 | /* BeginInspectorPanel & EndInspectorPanel is all you need to draw an 59 | * inspector (assuming you are already in between an ImGui::Begin and 60 | * ImGui::End pair) 61 | * */ 62 | static bool flipX = false; 63 | static bool flipY = false; 64 | 65 | ImGuiTexInspect::InspectorFlags flags = 0; 66 | if (flipX) SetFlag(flags, ImGuiTexInspect::InspectorFlags_FlipX); 67 | if (flipY) SetFlag(flags, ImGuiTexInspect::InspectorFlags_FlipY); 68 | 69 | if (ImGuiTexInspect::BeginInspectorPanel("##ColorFilters", testTex.texture, testTex.size, flags)) 70 | { 71 | // Draw some text showing color value of each texel (you must be zoomed in to see this) 72 | ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::BytesDec)); 73 | } 74 | ImGuiTexInspect::EndInspectorPanel(); 75 | 76 | // Now some ordinary ImGui elements to provide some explanation 77 | ImGui::BeginChild("Controls", ImVec2(600, 100)); 78 | ImGui::TextWrapped("Basics:"); 79 | ImGui::BulletText("Use mouse wheel to zoom in and out. Click and drag to pan."); 80 | ImGui::BulletText("Use the demo select buttons at the top of the window to explore"); 81 | ImGui::BulletText("Use the controls below to change basic color filtering options"); 82 | ImGui::EndChild(); 83 | 84 | 85 | /* DrawColorChannelSelector & DrawGridEditor are convenience functions that 86 | * draw ImGui controls to manipulate config of the most recently drawn 87 | * texture inspector 88 | **/ 89 | ImGuiTexInspect::DrawColorChannelSelector(); 90 | ImGui::SameLine(200); 91 | ImGuiTexInspect::DrawGridEditor(); 92 | 93 | ImGui::Separator(); 94 | 95 | ImGui::Checkbox("Flip X", &flipX); 96 | ImGui::Checkbox("Flip Y", &flipY); 97 | } 98 | 99 | //------------------------------------------------------------------------- 100 | 101 | /* Demo_ColorMatrix 102 | * An example showing usage of the ColorMatrix. See comments at the 103 | * declaration of CurrentInspector_SetColorMatrix for details. This example 104 | * shows how to set the matrix directly, as well as how to use the 105 | * DrawColorMatrixEditor convenience function to draw ImGui controls to 106 | * manipulate it. 107 | */ 108 | void Demo_ColorMatrix() 109 | { 110 | if (ImGuiTexInspect::BeginInspectorPanel("##ColorMatrix", testTex.texture, testTex.size)) 111 | { 112 | // Draw some text showing color value of each texel (you must be zoomed in to see this) 113 | ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::BytesDec)); 114 | } 115 | ImGuiTexInspect::EndInspectorPanel(); 116 | 117 | ImGui::BeginGroup(); 118 | ImGui::Text("Colour Matrix Editor:"); 119 | // Draw Matrix editor to allow user to manipulate the ColorMatrix 120 | ImGuiTexInspect::DrawColorMatrixEditor(); 121 | ImGui::EndGroup(); 122 | 123 | ImGui::SameLine(); 124 | 125 | // Provide some presets that can be used to set the ColorMatrix for example purposes 126 | ImGui::BeginGroup(); 127 | ImGui::PushItemWidth(200); 128 | ImGui::Indent(50); 129 | const ImVec2 buttonSize = ImVec2(160, 0); 130 | ImGui::Text("Example Presets:"); 131 | // clang-format off 132 | if (ImGui::Button("Negative", buttonSize)) 133 | { 134 | // Matrix which inverts each of the red, green, blue channels and leaves Alpha untouched 135 | float matrix[] = {-1.000f, 0.000f, 0.000f, 0.000f, 136 | 0.000f, -1.000f, 0.000f, 0.000f, 137 | 0.000f, 0.000f, -1.000f, 0.000f, 138 | 0.000f, 0.000f, 0.000f, 1.000f}; 139 | 140 | float colorOffset[] = {1, 1, 1, 0}; 141 | ImGuiTexInspect::CurrentInspector_SetColorMatrix(matrix, colorOffset); 142 | } 143 | if (ImGui::Button("Swap Red & Blue", buttonSize)) 144 | { 145 | // Matrix which swaps red and blue channels but leaves green and alpha untouched 146 | float matrix[] = { 0.000f, 0.000f, 1.000f, 0.000f, 147 | 0.000f, 1.000f, 0.000f, 0.000f, 148 | 1.000f, 0.000f, 0.000f, 0.000f, 149 | 0.000f, 0.000f, 0.000f, 1.000f}; 150 | float colorOffset[] = {0, 0, 0, 0}; 151 | ImGuiTexInspect::CurrentInspector_SetColorMatrix(matrix, colorOffset); 152 | } 153 | if (ImGui::Button("Alpha", buttonSize)) 154 | { 155 | // Red, green and blue channels are set based on alpha value so that alpha = 1 shows as white. 156 | // output alpha is set to 1 157 | float highlightTransparencyMatrix[] = {0.000f, 0.000f, 0.000f, 0.000f, 158 | 0.000f, 0.000f, 0.000f, 0.000f, 159 | 0.000f, 0.000f, 0.000f, 0.000f, 160 | 1.000, 1.000, 1.000, 1.000f}; 161 | float highlightTransparencyOffset[] = {0, 0, 0, 1}; 162 | ImGuiTexInspect::CurrentInspector_SetColorMatrix(highlightTransparencyMatrix, highlightTransparencyOffset); 163 | } 164 | if (ImGui::Button("Transparency", buttonSize)) 165 | { 166 | // Red, green and blue channels are scaled by 0.1f. Low alpha values are shown as magenta 167 | float highlightTransparencyMatrix[] = {0.100f, 0.100f, 0.100f, 0.000f, 168 | 0.100f, 0.100f, 0.100f, 0.000f, 169 | 0.100f, 0.100f, 0.100f, 0.000f, 170 | -1.000f, 0.000f, -1.000f, 0.000f}; 171 | float highlightTransparencyOffset[] = {1, 0, 1, 1}; 172 | ImGuiTexInspect::CurrentInspector_SetColorMatrix(highlightTransparencyMatrix, highlightTransparencyOffset); 173 | } 174 | if (ImGui::Button("Default", buttonSize)) 175 | { 176 | // Default "identity" matrix that doesn't modify colors at all 177 | float matrix[] = {1.000f, 0.000f, 0.000f, 0.000f, 178 | 0.000f, 1.000f, 0.000f, 0.000f, 179 | 0.000f, 0.000f, 1.000f, 0.000f, 180 | 0.000f, 0.000f, 0.000f, 1.000f}; 181 | 182 | float colorOffset[] = {0, 0, 0, 0}; 183 | ImGuiTexInspect::CurrentInspector_SetColorMatrix(matrix, colorOffset); 184 | } 185 | // clang-format on 186 | ImGui::PopItemWidth(); 187 | ImGui::EndGroup(); 188 | } 189 | 190 | /* Demo_AlphaMode 191 | * Very simple example that calls DrawAlphaModeSelector to draw controls to 192 | * allow user to select alpha mode for the inpsector. See InspectorAlphaMode 193 | * enum for details on what the different modes are. */ 194 | void Demo_AlphaMode() 195 | { 196 | if (ImGuiTexInspect::BeginInspectorPanel("##AlphaModeDemo", testTex.texture, testTex.size)) 197 | { 198 | // Add annotations here 199 | } 200 | ImGuiTexInspect::EndInspectorPanel(); 201 | ImGuiTexInspect::DrawAlphaModeSelector(); 202 | } 203 | 204 | /* Demo_WrapAndFilter 205 | * Demo showing the effect of the InspectorFlags_ShowWrap & InspectorFlags_NoForceFilterNearest flags. 206 | * See InspectorFlags_ enum for details on these flags. 207 | */ 208 | void Demo_WrapAndFilter() 209 | { 210 | static bool showWrap = false; 211 | static bool forceNearestTexel = true; 212 | 213 | if (ImGuiTexInspect::BeginInspectorPanel("##WrapAndFilter", testTex.texture, testTex.size)) 214 | { 215 | } 216 | ImGuiTexInspect::InspectorFlags flags = 0; 217 | 218 | if (showWrap) 219 | flags |= ImGuiTexInspect::InspectorFlags_ShowWrap; 220 | if (!forceNearestTexel) 221 | flags |= ImGuiTexInspect::InspectorFlags_NoForceFilterNearest; 222 | 223 | ImGuiTexInspect::CurrentInspector_SetFlags(flags, ~flags); 224 | ImGuiTexInspect::EndInspectorPanel(); 225 | 226 | ImGui::BeginChild("Controls", ImVec2(600, 0)); 227 | ImGui::TextWrapped("The following option can be enabled to render texture outside of the [0,1] UV range, what you actually " 228 | "see outside of this range will depend on the mode of the texture. For example you may see the texture repeat, or " 229 | "it might be clamped to the colour of the edge pixels.\nIn this demo the texture is set to wrap."); 230 | ImGui::Checkbox("Show Wrapping Mode", &showWrap); 231 | 232 | ImGui::TextWrapped("The following option is enabled by default and forces a nearest texel filter, implemented at the shader level. " 233 | "By disabling this you can the currently set mode for this texture."); 234 | ImGui::Checkbox("Force Nearest Texel", &forceNearestTexel); 235 | ImGui::EndChild(); 236 | } 237 | 238 | // This class is used in Demo_TextureAnnotations to show the process of creating a new texture annotation. 239 | class CustomAnnotationExample 240 | { 241 | public: 242 | void DrawAnnotation(ImDrawList *drawList, ImVec2 texel, ImGuiTexInspect::Transform2D texelsToPixels, ImVec4 value) 243 | { 244 | /* A silly example to show the process of creating a new annotation 245 | * We'll see which primary colour is the dominant colour in the texel 246 | * then draw a different shape for each primary colour. The radius 247 | * will be based on the overall brightness. 248 | */ 249 | int numSegments; 250 | 251 | if (value.x > value.y && value.x > value.z) 252 | { 253 | // Red pixel - draw a triangle! 254 | numSegments = 3; 255 | } 256 | else 257 | { 258 | if (value.y > value.z) 259 | { 260 | // Green pixel - draw a diamond! 261 | numSegments = 4; 262 | } 263 | else 264 | { 265 | // Blue pixel - draw a hexagon! 266 | numSegments = 6; 267 | } 268 | } 269 | 270 | // Don't go larger than whole texel 271 | const float maxRadius = texelsToPixels.Scale.x * 0.5f; 272 | 273 | // Scale radius based on texel brightness 274 | const float radius = maxRadius * (value.x + value.y + value.z) / 3; 275 | drawList->AddNgon(texelsToPixels * texel, radius, 0xFFFFFFFF, numSegments); 276 | } 277 | }; 278 | 279 | void Demo_TextureAnnotations() 280 | { 281 | static bool annotationEnabled_arrow = true; 282 | static bool annotationEnabled_valueText = false; 283 | static bool annotationEnabled_customExample = false; 284 | 285 | static ImGuiTexInspect::ValueText::Format textFormat = ImGuiTexInspect::ValueText::BytesHex; 286 | 287 | const int maxAnnotatedTexels = 1000; 288 | 289 | if (ImGuiTexInspect::BeginInspectorPanel("##TextureAnnotations", testTex.texture, testTex.size)) 290 | { 291 | // Draw the currently enabled annotations... 292 | if (annotationEnabled_arrow) 293 | { 294 | ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::Arrow().UsePreset(ImGuiTexInspect::Arrow::NormalMap), maxAnnotatedTexels); 295 | } 296 | 297 | if (annotationEnabled_valueText) 298 | { 299 | ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(textFormat), maxAnnotatedTexels); 300 | } 301 | 302 | if (annotationEnabled_customExample) 303 | { 304 | ImGuiTexInspect::DrawAnnotations(CustomAnnotationExample(), maxAnnotatedTexels); 305 | } 306 | } 307 | ImGuiTexInspect::EndInspectorPanel(); 308 | 309 | // Checkboxes to toggle each type of annotation on and off 310 | ImGui::BeginChild("Controls", ImVec2(600, 0)); 311 | ImGui::Checkbox("Arrow (Hint: zoom in on the normal-map part of the texture)", &annotationEnabled_arrow); 312 | ImGui::Checkbox("Value Text", &annotationEnabled_valueText); 313 | ImGui::Checkbox("Custom Annotation Example", &annotationEnabled_customExample); 314 | ImGui::EndChild(); 315 | 316 | if (annotationEnabled_valueText) 317 | { 318 | // Show a combo to select the text formatting mode 319 | ImGui::SameLine(); 320 | ImGui::BeginGroup(); 321 | const char *textOptions[] = {"Hex String", "Bytes in Hex", "Bytes in Decimal", "Floats"}; 322 | ImGui::SetNextItemWidth(200); 323 | int textFormatInt = (int)(textFormat); 324 | ImGui::Combo("Text Mode", &textFormatInt, textOptions, IM_ARRAYSIZE(textOptions)); 325 | textFormat = (ImGuiTexInspect::ValueText::Format)textFormatInt; 326 | ImGui::EndGroup(); 327 | } 328 | } 329 | 330 | //------------------------------------------------------------------------- 331 | // [SECTION] MAIN DEMO WINDOW FUNCTION 332 | //------------------------------------------------------------------------- 333 | 334 | void ShowDemoWindow() 335 | { 336 | if (!testInitted) 337 | { 338 | DemoInit(); 339 | } 340 | 341 | ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver); 342 | ImGui::SetNextWindowSize(ImVec2(1000, 1000), ImGuiCond_FirstUseEver); 343 | 344 | struct DemoConfig 345 | { 346 | const char *buttonName; // Button text to display to user for a demo 347 | void (*DrawDemoFn)(); // Function which implements the demo 348 | }; 349 | const DemoConfig demos[] = { 350 | {"Basics", Demo_ColorFilters}, 351 | {"Color Matrix", Demo_ColorMatrix}, 352 | {"Annotations", Demo_TextureAnnotations}, 353 | {"Alpha Mode", Demo_AlphaMode}, 354 | {"Wrap & Filter", Demo_WrapAndFilter}, 355 | }; 356 | 357 | if (ImGui::Begin("ImGuiTexInspect Demo")) 358 | { 359 | ImGui::Text("Select Demo:"); 360 | ImGui::Spacing(); 361 | 362 | //Custom color values to example-select buttons to make them stand out 363 | ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0.59f, 0.7f, 0.8f)); 364 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0.59f, 0.8f, 0.8f)); 365 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0.59f, 0.9f, 1.0f)); 366 | 367 | // Draw row of buttons, one for each demo scene 368 | static int selectedDemo = 0; 369 | for (int i = 0; i < IM_ARRAYSIZE(demos); i++) 370 | { 371 | if (i != 0) 372 | { 373 | ImGui::SameLine(); 374 | } 375 | if (ImGui::Button(demos[i].buttonName, ImVec2(140, 60))) 376 | { 377 | selectedDemo = i; 378 | } 379 | } 380 | ImGui::PopStyleColor(); 381 | ImGui::PopStyleColor(); 382 | ImGui::PopStyleColor(); 383 | 384 | ImGui::Spacing(); 385 | 386 | // Call function to render currently example scene 387 | demos[selectedDemo].DrawDemoFn(); 388 | } 389 | ImGui::End(); 390 | } 391 | 392 | //------------------------------------------------------------------------- 393 | // [SECTION] INIT & TEXTURE LOAD 394 | //------------------------------------------------------------------------- 395 | 396 | void DemoInit() 397 | { 398 | ImGuiTexInspect::Init(); 399 | ImGuiTexInspect::CreateContext(); 400 | 401 | ImGuiIO &io = ImGui::GetIO(); 402 | fontTexture.texture = io.Fonts->TexID; 403 | fontTexture.size = ImVec2((float)io.Fonts->TexWidth, (float)io.Fonts->TexHeight); 404 | 405 | testTex = LoadDemoTexture(); 406 | testInitted = true; 407 | } 408 | 409 | // Check if file at path is accessible 410 | bool CanAccessFile(const char *path) 411 | { 412 | if (FILE *file = fopen(path, "r")) 413 | { 414 | fclose(file); 415 | return true; 416 | } 417 | else 418 | { 419 | return false; 420 | } 421 | } 422 | 423 | Texture LoadDemoTexture() 424 | { 425 | /* To be a bit forgiving to build different build & test processes we check 426 | * a few different paths to find the demo texture. 427 | */ 428 | const char *pathsToTry[] = {"demo_1.png", "../demo_1.png", "examples/demo_1.png"}; 429 | 430 | for (int i = 0; i < IM_ARRAYSIZE(pathsToTry); ++i) 431 | { 432 | if (CanAccessFile(pathsToTry[i])) 433 | { 434 | return LoadTexture(pathsToTry[i]); 435 | } 436 | } 437 | fprintf(stderr, "Unable to find demo_1.png\n"); 438 | exit(-1); 439 | } 440 | } //namespace 441 | -------------------------------------------------------------------------------- /examples/libs/usynergy/uSynergy.c: -------------------------------------------------------------------------------- 1 | /* 2 | uSynergy client -- Implementation for the embedded Synergy client library 3 | version 1.0.0, July 7th, 2012 4 | 5 | Copyright (c) 2012 Alex Evans 6 | 7 | This software is provided 'as-is', without any express or implied 8 | warranty. In no event will the authors be held liable for any damages 9 | arising from the use of this software. 10 | 11 | Permission is granted to anyone to use this software for any purpose, 12 | including commercial applications, and to alter it and redistribute it 13 | freely, subject to the following restrictions: 14 | 15 | 1. The origin of this software must not be misrepresented; you must not 16 | claim that you wrote the original software. If you use this software 17 | in a product, an acknowledgment in the product documentation would be 18 | appreciated but is not required. 19 | 20 | 2. Altered source versions must be plainly marked as such, and must not be 21 | misrepresented as being the original software. 22 | 23 | 3. This notice may not be removed or altered from any source 24 | distribution. 25 | */ 26 | #include "uSynergy.h" 27 | #include 28 | #include 29 | 30 | 31 | 32 | //--------------------------------------------------------------------------------------------------------------------- 33 | // Internal helpers 34 | //--------------------------------------------------------------------------------------------------------------------- 35 | 36 | 37 | 38 | /** 39 | @brief Read 16 bit integer in network byte order and convert to native byte order 40 | **/ 41 | static int16_t sNetToNative16(const unsigned char *value) 42 | { 43 | #ifdef USYNERGY_LITTLE_ENDIAN 44 | return value[1] | (value[0] << 8); 45 | #else 46 | return value[0] | (value[1] << 8); 47 | #endif 48 | } 49 | 50 | 51 | 52 | /** 53 | @brief Read 32 bit integer in network byte order and convert to native byte order 54 | **/ 55 | static int32_t sNetToNative32(const unsigned char *value) 56 | { 57 | #ifdef USYNERGY_LITTLE_ENDIAN 58 | return value[3] | (value[2] << 8) | (value[1] << 16) | (value[0] << 24); 59 | #else 60 | return value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); 61 | #endif 62 | } 63 | 64 | 65 | 66 | /** 67 | @brief Trace text to client 68 | **/ 69 | static void sTrace(uSynergyContext *context, const char* text) 70 | { 71 | // Don't trace if we don't have a trace function 72 | if (context->m_traceFunc != 0L) 73 | context->m_traceFunc(context->m_cookie, text); 74 | } 75 | 76 | 77 | 78 | /** 79 | @brief Add string to reply packet 80 | **/ 81 | static void sAddString(uSynergyContext *context, const char *string) 82 | { 83 | size_t len = strlen(string); 84 | memcpy(context->m_replyCur, string, len); 85 | context->m_replyCur += len; 86 | } 87 | 88 | 89 | 90 | /** 91 | @brief Add uint8 to reply packet 92 | **/ 93 | static void sAddUInt8(uSynergyContext *context, uint8_t value) 94 | { 95 | *context->m_replyCur++ = value; 96 | } 97 | 98 | 99 | 100 | /** 101 | @brief Add uint16 to reply packet 102 | **/ 103 | static void sAddUInt16(uSynergyContext *context, uint16_t value) 104 | { 105 | uint8_t *reply = context->m_replyCur; 106 | *reply++ = (uint8_t)(value >> 8); 107 | *reply++ = (uint8_t)value; 108 | context->m_replyCur = reply; 109 | } 110 | 111 | 112 | 113 | /** 114 | @brief Add uint32 to reply packet 115 | **/ 116 | static void sAddUInt32(uSynergyContext *context, uint32_t value) 117 | { 118 | uint8_t *reply = context->m_replyCur; 119 | *reply++ = (uint8_t)(value >> 24); 120 | *reply++ = (uint8_t)(value >> 16); 121 | *reply++ = (uint8_t)(value >> 8); 122 | *reply++ = (uint8_t)value; 123 | context->m_replyCur = reply; 124 | } 125 | 126 | 127 | 128 | /** 129 | @brief Send reply packet 130 | **/ 131 | static uSynergyBool sSendReply(uSynergyContext *context) 132 | { 133 | // Set header size 134 | uint8_t *reply_buf = context->m_replyBuffer; 135 | uint32_t reply_len = (uint32_t)(context->m_replyCur - reply_buf); /* Total size of reply */ 136 | uint32_t body_len = reply_len - 4; /* Size of body */ 137 | uSynergyBool ret; 138 | reply_buf[0] = (uint8_t)(body_len >> 24); 139 | reply_buf[1] = (uint8_t)(body_len >> 16); 140 | reply_buf[2] = (uint8_t)(body_len >> 8); 141 | reply_buf[3] = (uint8_t)body_len; 142 | 143 | // Send reply 144 | ret = context->m_sendFunc(context->m_cookie, context->m_replyBuffer, reply_len); 145 | 146 | // Reset reply buffer write pointer 147 | context->m_replyCur = context->m_replyBuffer+4; 148 | return ret; 149 | } 150 | 151 | 152 | 153 | /** 154 | @brief Call mouse callback after a mouse event 155 | **/ 156 | static void sSendMouseCallback(uSynergyContext *context) 157 | { 158 | // Skip if no callback is installed 159 | if (context->m_mouseCallback == 0L) 160 | return; 161 | 162 | // Send callback 163 | context->m_mouseCallback(context->m_cookie, context->m_mouseX, context->m_mouseY, context->m_mouseWheelX, 164 | context->m_mouseWheelY, context->m_mouseButtonLeft, context->m_mouseButtonRight, context->m_mouseButtonMiddle); 165 | } 166 | 167 | 168 | 169 | /** 170 | @brief Send keyboard callback when a key has been pressed or released 171 | **/ 172 | static void sSendKeyboardCallback(uSynergyContext *context, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat) 173 | { 174 | // Skip if no callback is installed 175 | if (context->m_keyboardCallback == 0L) 176 | return; 177 | 178 | // Send callback 179 | context->m_keyboardCallback(context->m_cookie, key, modifiers, down, repeat); 180 | } 181 | 182 | 183 | 184 | /** 185 | @brief Send joystick callback 186 | **/ 187 | static void sSendJoystickCallback(uSynergyContext *context, uint8_t joyNum) 188 | { 189 | int8_t *sticks; 190 | 191 | // Skip if no callback is installed 192 | if (context->m_joystickCallback == 0L) 193 | return; 194 | 195 | // Send callback 196 | sticks = context->m_joystickSticks[joyNum]; 197 | context->m_joystickCallback(context->m_cookie, joyNum, context->m_joystickButtons[joyNum], sticks[0], sticks[1], sticks[2], sticks[3]); 198 | } 199 | 200 | 201 | 202 | /** 203 | @brief Parse a single client message, update state, send callbacks and send replies 204 | **/ 205 | #define USYNERGY_IS_PACKET(pkt_id) memcmp(message+4, pkt_id, 4)==0 206 | static void sProcessMessage(uSynergyContext *context, const uint8_t *message) 207 | { 208 | // We have a packet! 209 | if (memcmp(message+4, "Synergy", 7)==0) 210 | { 211 | // Welcome message 212 | // kMsgHello = "Synergy%2i%2i" 213 | // kMsgHelloBack = "Synergy%2i%2i%s" 214 | sAddString(context, "Synergy"); 215 | sAddUInt16(context, USYNERGY_PROTOCOL_MAJOR); 216 | sAddUInt16(context, USYNERGY_PROTOCOL_MINOR); 217 | sAddUInt32(context, (uint32_t)strlen(context->m_clientName)); 218 | sAddString(context, context->m_clientName); 219 | if (!sSendReply(context)) 220 | { 221 | // Send reply failed, let's try to reconnect 222 | sTrace(context, "SendReply failed, trying to reconnect in a second"); 223 | context->m_connected = USYNERGY_FALSE; 224 | context->m_sleepFunc(context->m_cookie, 1000); 225 | } 226 | else 227 | { 228 | // Let's assume we're connected 229 | char buffer[256+1]; 230 | sprintf(buffer, "Connected as client \"%s\"", context->m_clientName); 231 | sTrace(context, buffer); 232 | context->m_hasReceivedHello = USYNERGY_TRUE; 233 | } 234 | return; 235 | } 236 | else if (USYNERGY_IS_PACKET("QINF")) 237 | { 238 | // Screen info. Reply with DINF 239 | // kMsgQInfo = "QINF" 240 | // kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i" 241 | uint16_t x = 0, y = 0, warp = 0; 242 | sAddString(context, "DINF"); 243 | sAddUInt16(context, x); 244 | sAddUInt16(context, y); 245 | sAddUInt16(context, context->m_clientWidth); 246 | sAddUInt16(context, context->m_clientHeight); 247 | sAddUInt16(context, warp); 248 | sAddUInt16(context, 0); // mx? 249 | sAddUInt16(context, 0); // my? 250 | sSendReply(context); 251 | return; 252 | } 253 | else if (USYNERGY_IS_PACKET("CIAK")) 254 | { 255 | // Do nothing? 256 | // kMsgCInfoAck = "CIAK" 257 | return; 258 | } 259 | else if (USYNERGY_IS_PACKET("CROP")) 260 | { 261 | // Do nothing? 262 | // kMsgCResetOptions = "CROP" 263 | return; 264 | } 265 | else if (USYNERGY_IS_PACKET("CINN")) 266 | { 267 | // Screen enter. Reply with CNOP 268 | // kMsgCEnter = "CINN%2i%2i%4i%2i" 269 | 270 | // Obtain the Synergy sequence number 271 | context->m_sequenceNumber = sNetToNative32(message + 12); 272 | context->m_isCaptured = USYNERGY_TRUE; 273 | 274 | // Call callback 275 | if (context->m_screenActiveCallback != 0L) 276 | context->m_screenActiveCallback(context->m_cookie, USYNERGY_TRUE); 277 | } 278 | else if (USYNERGY_IS_PACKET("COUT")) 279 | { 280 | // Screen leave 281 | // kMsgCLeave = "COUT" 282 | context->m_isCaptured = USYNERGY_FALSE; 283 | 284 | // Call callback 285 | if (context->m_screenActiveCallback != 0L) 286 | context->m_screenActiveCallback(context->m_cookie, USYNERGY_FALSE); 287 | } 288 | else if (USYNERGY_IS_PACKET("DMDN")) 289 | { 290 | // Mouse down 291 | // kMsgDMouseDown = "DMDN%1i" 292 | char btn = message[8]-1; 293 | if (btn==2) 294 | context->m_mouseButtonRight = USYNERGY_TRUE; 295 | else if (btn==1) 296 | context->m_mouseButtonMiddle = USYNERGY_TRUE; 297 | else 298 | context->m_mouseButtonLeft = USYNERGY_TRUE; 299 | sSendMouseCallback(context); 300 | } 301 | else if (USYNERGY_IS_PACKET("DMUP")) 302 | { 303 | // Mouse up 304 | // kMsgDMouseUp = "DMUP%1i" 305 | char btn = message[8]-1; 306 | if (btn==2) 307 | context->m_mouseButtonRight = USYNERGY_FALSE; 308 | else if (btn==1) 309 | context->m_mouseButtonMiddle = USYNERGY_FALSE; 310 | else 311 | context->m_mouseButtonLeft = USYNERGY_FALSE; 312 | sSendMouseCallback(context); 313 | } 314 | else if (USYNERGY_IS_PACKET("DMMV")) 315 | { 316 | // Mouse move. Reply with CNOP 317 | // kMsgDMouseMove = "DMMV%2i%2i" 318 | context->m_mouseX = sNetToNative16(message+8); 319 | context->m_mouseY = sNetToNative16(message+10); 320 | sSendMouseCallback(context); 321 | } 322 | else if (USYNERGY_IS_PACKET("DMWM")) 323 | { 324 | // Mouse wheel 325 | // kMsgDMouseWheel = "DMWM%2i%2i" 326 | // kMsgDMouseWheel1_0 = "DMWM%2i" 327 | context->m_mouseWheelX += sNetToNative16(message+8); 328 | context->m_mouseWheelY += sNetToNative16(message+10); 329 | sSendMouseCallback(context); 330 | } 331 | else if (USYNERGY_IS_PACKET("DKDN")) 332 | { 333 | // Key down 334 | // kMsgDKeyDown = "DKDN%2i%2i%2i" 335 | // kMsgDKeyDown1_0 = "DKDN%2i%2i" 336 | //uint16_t id = sNetToNative16(message+8); 337 | uint16_t mod = sNetToNative16(message+10); 338 | uint16_t key = sNetToNative16(message+12); 339 | sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_FALSE); 340 | } 341 | else if (USYNERGY_IS_PACKET("DKRP")) 342 | { 343 | // Key repeat 344 | // kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i" 345 | // kMsgDKeyRepeat1_0 = "DKRP%2i%2i%2i" 346 | uint16_t mod = sNetToNative16(message+10); 347 | // uint16_t count = sNetToNative16(message+12); 348 | uint16_t key = sNetToNative16(message+14); 349 | sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_TRUE); 350 | } 351 | else if (USYNERGY_IS_PACKET("DKUP")) 352 | { 353 | // Key up 354 | // kMsgDKeyUp = "DKUP%2i%2i%2i" 355 | // kMsgDKeyUp1_0 = "DKUP%2i%2i" 356 | //uint16 id=Endian::sNetToNative(sbuf[4]); 357 | uint16_t mod = sNetToNative16(message+10); 358 | uint16_t key = sNetToNative16(message+12); 359 | sSendKeyboardCallback(context, key, mod, USYNERGY_FALSE, USYNERGY_FALSE); 360 | } 361 | else if (USYNERGY_IS_PACKET("DGBT")) 362 | { 363 | // Joystick buttons 364 | // kMsgDGameButtons = "DGBT%1i%2i"; 365 | uint8_t joy_num = message[8]; 366 | if (joy_numm_joystickButtons[joy_num] = (message[9] << 8) | message[10]; 370 | sSendJoystickCallback(context, joy_num); 371 | } 372 | } 373 | else if (USYNERGY_IS_PACKET("DGST")) 374 | { 375 | // Joystick sticks 376 | // kMsgDGameSticks = "DGST%1i%1i%1i%1i%1i"; 377 | uint8_t joy_num = message[8]; 378 | if (joy_numm_joystickSticks[joy_num], message+9, 4); 382 | sSendJoystickCallback(context, joy_num); 383 | } 384 | } 385 | else if (USYNERGY_IS_PACKET("DSOP")) 386 | { 387 | // Set options 388 | // kMsgDSetOptions = "DSOP%4I" 389 | } 390 | else if (USYNERGY_IS_PACKET("CALV")) 391 | { 392 | // Keepalive, reply with CALV and then CNOP 393 | // kMsgCKeepAlive = "CALV" 394 | sAddString(context, "CALV"); 395 | sSendReply(context); 396 | // now reply with CNOP 397 | } 398 | else if (USYNERGY_IS_PACKET("DCLP")) 399 | { 400 | // Clipboard message 401 | // kMsgDClipboard = "DCLP%1i%4i%s" 402 | // 403 | // The clipboard message contains: 404 | // 1 uint32: The size of the message 405 | // 4 chars: The identifier ("DCLP") 406 | // 1 uint8: The clipboard index 407 | // 1 uint32: The sequence number. It's zero, because this message is always coming from the server? 408 | // 1 uint32: The total size of the remaining 'string' (as per the Synergy %s string format (which is 1 uint32 for size followed by a char buffer (not necessarily null terminated)). 409 | // 1 uint32: The number of formats present in the message 410 | // And then 'number of formats' times the following: 411 | // 1 uint32: The format of the clipboard data 412 | // 1 uint32: The size n of the clipboard data 413 | // n uint8: The clipboard data 414 | const uint8_t * parse_msg = message+17; 415 | uint32_t num_formats = sNetToNative32(parse_msg); 416 | parse_msg += 4; 417 | for (; num_formats; num_formats--) 418 | { 419 | // Parse clipboard format header 420 | uint32_t format = sNetToNative32(parse_msg); 421 | uint32_t size = sNetToNative32(parse_msg+4); 422 | parse_msg += 8; 423 | 424 | // Call callback 425 | if (context->m_clipboardCallback) 426 | context->m_clipboardCallback(context->m_cookie, format, parse_msg, size); 427 | 428 | parse_msg += size; 429 | } 430 | } 431 | else 432 | { 433 | // Unknown packet, could be any of these 434 | // kMsgCNoop = "CNOP" 435 | // kMsgCClose = "CBYE" 436 | // kMsgCClipboard = "CCLP%1i%4i" 437 | // kMsgCScreenSaver = "CSEC%1i" 438 | // kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i" 439 | // kMsgDKeyRepeat1_0 = "DKRP%2i%2i%2i" 440 | // kMsgDMouseRelMove = "DMRM%2i%2i" 441 | // kMsgEIncompatible = "EICV%2i%2i" 442 | // kMsgEBusy = "EBSY" 443 | // kMsgEUnknown = "EUNK" 444 | // kMsgEBad = "EBAD" 445 | char buffer[64]; 446 | sprintf(buffer, "Unknown packet '%c%c%c%c'", message[4], message[5], message[6], message[7]); 447 | sTrace(context, buffer); 448 | return; 449 | } 450 | 451 | // Reply with CNOP maybe? 452 | sAddString(context, "CNOP"); 453 | sSendReply(context); 454 | } 455 | #undef USYNERGY_IS_PACKET 456 | 457 | 458 | 459 | /** 460 | @brief Mark context as being disconnected 461 | **/ 462 | static void sSetDisconnected(uSynergyContext *context) 463 | { 464 | context->m_connected = USYNERGY_FALSE; 465 | context->m_hasReceivedHello = USYNERGY_FALSE; 466 | context->m_isCaptured = USYNERGY_FALSE; 467 | context->m_replyCur = context->m_replyBuffer + 4; 468 | context->m_sequenceNumber = 0; 469 | } 470 | 471 | 472 | 473 | /** 474 | @brief Update a connected context 475 | **/ 476 | static void sUpdateContext(uSynergyContext *context) 477 | { 478 | /* Receive data (blocking) */ 479 | int receive_size = USYNERGY_RECEIVE_BUFFER_SIZE - context->m_receiveOfs; 480 | int num_received = 0; 481 | int packlen = 0; 482 | if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer + context->m_receiveOfs, receive_size, &num_received) == USYNERGY_FALSE) 483 | { 484 | /* Receive failed, let's try to reconnect */ 485 | char buffer[128]; 486 | sprintf(buffer, "Receive failed (%d bytes asked, %d bytes received), trying to reconnect in a second", receive_size, num_received); 487 | sTrace(context, buffer); 488 | sSetDisconnected(context); 489 | context->m_sleepFunc(context->m_cookie, 1000); 490 | return; 491 | } 492 | context->m_receiveOfs += num_received; 493 | 494 | /* If we didn't receive any data then we're probably still polling to get connected and 495 | therefore not getting any data back. To avoid overloading the system with a Synergy 496 | thread that would hammer on polling, we let it rest for a bit if there's no data. */ 497 | if (num_received == 0) 498 | context->m_sleepFunc(context->m_cookie, 500); 499 | 500 | /* Check for timeouts */ 501 | if (context->m_hasReceivedHello) 502 | { 503 | uint32_t cur_time = context->m_getTimeFunc(); 504 | if (num_received == 0) 505 | { 506 | /* Timeout after 2 secs of inactivity (we received no CALV) */ 507 | if ((cur_time - context->m_lastMessageTime) > USYNERGY_IDLE_TIMEOUT) 508 | sSetDisconnected(context); 509 | } 510 | else 511 | context->m_lastMessageTime = cur_time; 512 | } 513 | 514 | /* Eat packets */ 515 | for (;;) 516 | { 517 | /* Grab packet length and bail out if the packet goes beyond the end of the buffer */ 518 | packlen = sNetToNative32(context->m_receiveBuffer); 519 | if (packlen+4 > context->m_receiveOfs) 520 | break; 521 | 522 | /* Process message */ 523 | sProcessMessage(context, context->m_receiveBuffer); 524 | 525 | /* Move packet to front of buffer */ 526 | memmove(context->m_receiveBuffer, context->m_receiveBuffer+packlen+4, context->m_receiveOfs-packlen-4); 527 | context->m_receiveOfs -= packlen+4; 528 | } 529 | 530 | /* Throw away over-sized packets */ 531 | if (packlen > USYNERGY_RECEIVE_BUFFER_SIZE) 532 | { 533 | /* Oversized packet, ditch tail end */ 534 | char buffer[128]; 535 | sprintf(buffer, "Oversized packet: '%c%c%c%c' (length %d)", context->m_receiveBuffer[4], context->m_receiveBuffer[5], context->m_receiveBuffer[6], context->m_receiveBuffer[7], packlen); 536 | sTrace(context, buffer); 537 | num_received = context->m_receiveOfs-4; // 4 bytes for the size field 538 | while (num_received != packlen) 539 | { 540 | int buffer_left = packlen - num_received; 541 | int to_receive = buffer_left < USYNERGY_RECEIVE_BUFFER_SIZE ? buffer_left : USYNERGY_RECEIVE_BUFFER_SIZE; 542 | int ditch_received = 0; 543 | if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer, to_receive, &ditch_received) == USYNERGY_FALSE) 544 | { 545 | /* Receive failed, let's try to reconnect */ 546 | sTrace(context, "Receive failed, trying to reconnect in a second"); 547 | sSetDisconnected(context); 548 | context->m_sleepFunc(context->m_cookie, 1000); 549 | break; 550 | } 551 | else 552 | { 553 | num_received += ditch_received; 554 | } 555 | } 556 | context->m_receiveOfs = 0; 557 | } 558 | } 559 | 560 | 561 | //--------------------------------------------------------------------------------------------------------------------- 562 | // Public interface 563 | //--------------------------------------------------------------------------------------------------------------------- 564 | 565 | 566 | 567 | /** 568 | @brief Initialize uSynergy context 569 | **/ 570 | void uSynergyInit(uSynergyContext *context) 571 | { 572 | /* Zero memory */ 573 | memset(context, 0, sizeof(uSynergyContext)); 574 | 575 | /* Initialize to default state */ 576 | sSetDisconnected(context); 577 | } 578 | 579 | 580 | /** 581 | @brief Update uSynergy 582 | **/ 583 | void uSynergyUpdate(uSynergyContext *context) 584 | { 585 | if (context->m_connected) 586 | { 587 | /* Update context, receive data, call callbacks */ 588 | sUpdateContext(context); 589 | } 590 | else 591 | { 592 | /* Try to connect */ 593 | if (context->m_connectFunc(context->m_cookie)) 594 | context->m_connected = USYNERGY_TRUE; 595 | } 596 | } 597 | 598 | 599 | 600 | /** 601 | @brief Send clipboard data 602 | **/ 603 | void uSynergySendClipboard(uSynergyContext *context, const char *text) 604 | { 605 | // Calculate maximum size that will fit in a reply packet 606 | uint32_t overhead_size = 4 + /* Message size */ 607 | 4 + /* Message ID */ 608 | 1 + /* Clipboard index */ 609 | 4 + /* Sequence number */ 610 | 4 + /* Rest of message size (because it's a Synergy string from here on) */ 611 | 4 + /* Number of clipboard formats */ 612 | 4 + /* Clipboard format */ 613 | 4; /* Clipboard data length */ 614 | uint32_t max_length = USYNERGY_REPLY_BUFFER_SIZE - overhead_size; 615 | 616 | // Clip text to max length 617 | uint32_t text_length = (uint32_t)strlen(text); 618 | if (text_length > max_length) 619 | { 620 | char buffer[128]; 621 | sprintf(buffer, "Clipboard buffer too small, clipboard truncated at %d characters", max_length); 622 | sTrace(context, buffer); 623 | text_length = max_length; 624 | } 625 | 626 | // Assemble packet 627 | sAddString(context, "DCLP"); 628 | sAddUInt8(context, 0); /* Clipboard index */ 629 | sAddUInt32(context, context->m_sequenceNumber); 630 | sAddUInt32(context, 4+4+4+text_length); /* Rest of message size: numFormats, format, length, data */ 631 | sAddUInt32(context, 1); /* Number of formats (only text for now) */ 632 | sAddUInt32(context, USYNERGY_CLIPBOARD_FORMAT_TEXT); 633 | sAddUInt32(context, text_length); 634 | sAddString(context, text); 635 | sSendReply(context); 636 | } 637 | -------------------------------------------------------------------------------- /backends/tex_inspect_opengl.cpp: -------------------------------------------------------------------------------- 1 | // ImGuiTexInspect, a texture inspector widget for dear imgui 2 | 3 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 4 | #define _CRT_SECURE_NO_WARNINGS 5 | #endif 6 | #if defined EMSCRIPTEN && defined IMGUI_TEX_INSPECT_FLOAT_READ_ENABLED 7 | #warning "Float texture read back is disabled on Emscripten" 8 | #undef IMGUI_TEX_INSPECT_FLOAT_READ_ENABLED 9 | #endif 10 | #include "imgui_tex_inspect_internal.h" 11 | 12 | // ========================================================================== 13 | // This file is largely based on: 14 | // https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp 15 | // 16 | // In the following section the ImGui_ImplOpenGL3_Init function has been 17 | // changed to not rewrite global ImGui state. It has also been wrapped in a 18 | // namespace to not clash with the main ImGui version. Aside from that this 19 | // section is identical to the imgui original. 20 | // 21 | // It's reproduced here because none of this code is exposed in the ImGui API 22 | // in a way that be reused (nor should it be). 23 | // 24 | // Search for "END COPIED" to find the end of the copied segment. 25 | // =========================================================================== 26 | 27 | // COPIED FROM imgui_impl_opengl3.cp //////////////////////////////////////// 28 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 29 | #define _CRT_SECURE_NO_WARNINGS 30 | #endif 31 | 32 | #include "imgui.h" 33 | #include "imgui_impl_opengl3.h" 34 | #include 35 | #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier 36 | #include // intptr_t 37 | #else 38 | #include // intptr_t 39 | #endif 40 | 41 | // GL includes 42 | #if defined(IMGUI_IMPL_OPENGL_ES2) 43 | #include 44 | #elif defined(IMGUI_IMPL_OPENGL_ES3) 45 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) 46 | #include // Use GL ES 3 47 | #else 48 | #include // Use GL ES 3 49 | #endif 50 | #else 51 | // About Desktop OpenGL function loaders: 52 | // Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. 53 | // Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). 54 | // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. 55 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 56 | #include // Needs to be initialized with gl3wInit() in user's code 57 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 58 | #include // Needs to be initialized with glewInit() in user's code. 59 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 60 | #include // Needs to be initialized with gladLoadGL() in user's code. 61 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) 62 | #include // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code. 63 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) 64 | #ifndef GLFW_INCLUDE_NONE 65 | #define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. 66 | #endif 67 | #include // Needs to be initialized with glbinding::Binding::initialize() in user's code. 68 | #include 69 | using namespace gl; 70 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) 71 | #ifndef GLFW_INCLUDE_NONE 72 | #define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. 73 | #endif 74 | #include // Needs to be initialized with glbinding::initialize() in user's code. 75 | #include 76 | using namespace gl; 77 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_EPOXY) 78 | #include 79 | #else 80 | #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM 81 | #endif 82 | #endif 83 | 84 | // Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have. 85 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2) 86 | #define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 87 | #endif 88 | 89 | // Desktop GL 3.3+ has glBindSampler() 90 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3) 91 | #define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER 92 | #endif 93 | 94 | // Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state 95 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1) 96 | #define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART 97 | #endif 98 | 99 | namespace imgui_impl_opengl 100 | { 101 | // OpenGL Data 102 | static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) 103 | static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings. 104 | static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; 105 | static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location 106 | static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0; // Vertex attributes location 107 | static GLint g_UniformLocationForceNearestSampling = 0; 108 | static GLint g_UniformLocationGridWidth = 0; 109 | 110 | // Functions 111 | static bool ImGui_ImplOpenGL3_Init(const char* glsl_version) 112 | { 113 | // Query for GL version (e.g. 320 for GL 3.2) 114 | #if !defined(IMGUI_IMPL_OPENGL_ES2) 115 | GLint major = 0; 116 | GLint minor = 0; 117 | glGetIntegerv(GL_MAJOR_VERSION, &major); 118 | glGetIntegerv(GL_MINOR_VERSION, &minor); 119 | if (major == 0 && minor == 0) 120 | { 121 | // Query GL_VERSION in desktop GL 2.x, the string will start with "." 122 | const char* gl_version = (const char*)glGetString(GL_VERSION); 123 | sscanf(gl_version, "%d.%d", &major, &minor); 124 | } 125 | g_GlVersion = (GLuint)(major * 100 + minor * 10); 126 | #else 127 | g_GlVersion = 200; // GLES 2 128 | #endif 129 | 130 | 131 | // Store GLSL version string so we can refer to it later in case we recreate shaders. 132 | // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. 133 | #if defined(IMGUI_IMPL_OPENGL_ES2) 134 | if (glsl_version == NULL) 135 | glsl_version = "#version 100"; 136 | #elif defined(IMGUI_IMPL_OPENGL_ES3) 137 | if (glsl_version == NULL) 138 | glsl_version = "#version 300 es"; 139 | #elif defined(__APPLE__) 140 | if (glsl_version == NULL) 141 | glsl_version = "#version 150"; 142 | #else 143 | if (glsl_version == NULL) 144 | glsl_version = "#version 130"; 145 | #endif 146 | IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString)); 147 | strcpy(g_GlslVersionString, glsl_version); 148 | strcat(g_GlslVersionString, "\n"); 149 | 150 | // Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected. 151 | // The code actually never uses the 'gl_loader' variable! It is only here so you can read it! 152 | // If auto-detection fails or doesn't select the same GL loader file as used by your application, 153 | // you are likely to get a crash below. 154 | // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. 155 | const char* gl_loader = "Unknown"; 156 | IM_UNUSED(gl_loader); 157 | #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 158 | gl_loader = "GL3W"; 159 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 160 | gl_loader = "GLEW"; 161 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 162 | gl_loader = "GLAD"; 163 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) 164 | gl_loader = "GLAD2"; 165 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) 166 | gl_loader = "glbinding2"; 167 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) 168 | gl_loader = "glbinding3"; 169 | #elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) 170 | gl_loader = "custom"; 171 | #else 172 | gl_loader = "none"; 173 | #endif 174 | 175 | // Make an arbitrary GL call (we don't actually need the result) 176 | // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. 177 | // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. 178 | GLint current_texture; 179 | glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); 180 | 181 | return true; 182 | } 183 | 184 | // =========================================================================== 185 | // COPIED FROM A DIFFERENT PART OF imgui_impl_opengl3.cpp 186 | // =========================================================================== 187 | 188 | // If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. 189 | static bool CheckShader(GLuint handle, const char* desc) 190 | { 191 | GLint status = 0, log_length = 0; 192 | glGetShaderiv(handle, GL_COMPILE_STATUS, &status); 193 | glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); 194 | if ((GLboolean)status == GL_FALSE) 195 | fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); 196 | if (log_length > 1) 197 | { 198 | ImVector buf; 199 | buf.resize((int)(log_length + 1)); 200 | glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); 201 | fprintf(stderr, "%s\n", buf.begin()); 202 | } 203 | return (GLboolean)status == GL_TRUE; 204 | } 205 | 206 | // If you get an error please report on GitHub. You may try different GL context version or GLSL version. 207 | static bool CheckProgram(GLuint handle, const char* desc) 208 | { 209 | GLint status = 0, log_length = 0; 210 | glGetProgramiv(handle, GL_LINK_STATUS, &status); 211 | glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); 212 | if ((GLboolean)status == GL_FALSE) 213 | fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); 214 | if (log_length > 1) 215 | { 216 | ImVector buf; 217 | buf.resize((int)(log_length + 1)); 218 | glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); 219 | fprintf(stderr, "%s\n", buf.begin()); 220 | } 221 | return (GLboolean)status == GL_TRUE; 222 | } 223 | 224 | static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) 225 | { 226 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill 227 | glEnable(GL_BLEND); 228 | glBlendEquation(GL_FUNC_ADD); 229 | glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 230 | glDisable(GL_CULL_FACE); 231 | glDisable(GL_DEPTH_TEST); 232 | glDisable(GL_STENCIL_TEST); 233 | glEnable(GL_SCISSOR_TEST); 234 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART 235 | if (g_GlVersion >= 310) 236 | glDisable(GL_PRIMITIVE_RESTART); 237 | #endif 238 | #ifdef GL_POLYGON_MODE 239 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 240 | #endif 241 | 242 | // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) 243 | #if defined(GL_CLIP_ORIGIN) 244 | bool clip_origin_lower_left = true; 245 | if (g_GlVersion >= 450) 246 | { 247 | GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); 248 | if (current_clip_origin == GL_UPPER_LEFT) 249 | clip_origin_lower_left = false; 250 | } 251 | #endif 252 | // Setup viewport, orthographic projection matrix 253 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. 254 | glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); 255 | float L = draw_data->DisplayPos.x; 256 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; 257 | float T = draw_data->DisplayPos.y; 258 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; 259 | #if defined(GL_CLIP_ORIGIN) 260 | if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left 261 | #endif 262 | const float ortho_projection[4][4] = 263 | { 264 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, 265 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, 266 | { 0.0f, 0.0f, -1.0f, 0.0f }, 267 | { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, 268 | }; 269 | glUseProgram(g_ShaderHandle); 270 | glUniform1i(g_AttribLocationTex, 0); 271 | glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); 272 | 273 | 274 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER 275 | if (g_GlVersion >= 330) 276 | glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. 277 | #endif 278 | 279 | glEnableVertexAttribArray(g_AttribLocationVtxPos); 280 | glEnableVertexAttribArray(g_AttribLocationVtxUV); 281 | //glEnableVertexAttribArray(g_AttribLocationVtxColor); //Our shader doesn't use vertex color 282 | glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); 283 | glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); 284 | //glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); 285 | } 286 | 287 | // =========================================================================== 288 | // END COPIED FROM imgui_impl_opengl3.cpp 289 | // --------------------------------------------------------------------------- 290 | // Note that a lot of the following code still orginated in 291 | // imgui_impl_opengl3.cpp but there are more changes from here on. 292 | // =========================================================================== 293 | 294 | // New uniforms for ImGuiTexInspect fragment shader 295 | static GLint g_UniformLocationTextureSize; 296 | static GLint g_UniformLocationColorTransform; 297 | static GLint g_UniformLocationColorOffset; 298 | static GLint g_UniformLocationBackgroundColor; 299 | static GLint g_UniformLocationPremultiplyAlpha; 300 | static GLint g_UniformLocationDisableFinalAlpha; 301 | static GLint g_UniformLocationGrid; 302 | 303 | 304 | // Vertex shaders are directly from imgui_impl_opengl3.cpp 305 | const GLchar* vertex_shader_glsl_120 = 306 | "uniform mat4 ProjMtx;\n" 307 | "attribute vec2 Position;\n" 308 | "attribute vec2 UV;\n" 309 | "attribute vec4 Color;\n" 310 | "varying vec2 Frag_UV;\n" 311 | "varying vec4 Frag_Color;\n" 312 | "void main()\n" 313 | "{\n" 314 | " Frag_UV = UV;\n" 315 | " Frag_Color = Color;\n" 316 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 317 | "}\n"; 318 | 319 | const GLchar* vertex_shader_glsl_130 = 320 | "uniform mat4 ProjMtx;\n" 321 | "in vec2 Position;\n" 322 | "in vec2 UV;\n" 323 | "in vec4 Color;\n" 324 | "out vec2 Frag_UV;\n" 325 | "out vec4 Frag_Color;\n" 326 | "void main()\n" 327 | "{\n" 328 | " Frag_UV = UV;\n" 329 | " Frag_Color = Color;\n" 330 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 331 | "}\n"; 332 | 333 | const GLchar* vertex_shader_glsl_300_es = 334 | "precision mediump float;\n" 335 | "layout (location = 0) in vec2 Position;\n" 336 | "layout (location = 1) in vec2 UV;\n" 337 | "layout (location = 2) in vec4 Color;\n" 338 | "uniform mat4 ProjMtx;\n" 339 | "out vec2 Frag_UV;\n" 340 | "out vec4 Frag_Color;\n" 341 | "void main()\n" 342 | "{\n" 343 | " Frag_UV = UV;\n" 344 | " Frag_Color = Color;\n" 345 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 346 | "}\n"; 347 | 348 | const GLchar* vertex_shader_glsl_410_core = 349 | "layout (location = 0) in vec2 Position;\n" 350 | "layout (location = 1) in vec2 UV;\n" 351 | "layout (location = 2) in vec4 Color;\n" 352 | "uniform mat4 ProjMtx;\n" 353 | "out vec2 Frag_UV;\n" 354 | "out vec4 Frag_Color;\n" 355 | "void main()\n" 356 | "{\n" 357 | " Frag_UV = UV;\n" 358 | " Frag_Color = Color;\n" 359 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 360 | "}\n"; 361 | 362 | 363 | //------------------------------------------------------------------------- 364 | // [SECTION] IMGUI_TEX_INSPECT FRAGMENT SHADERS 365 | //------------------------------------------------------------------------- 366 | const GLchar *fragment_shader_glsl_120 = "#ifdef GL_ES\n" 367 | " precision mediump float;\n" 368 | "#endif\n" 369 | "uniform sampler2D Texture;\n" 370 | "uniform vec2 TextureSize;\n" 371 | "uniform mat4 ColorTransform;\n" 372 | "uniform vec4 ColorOffset;\n" 373 | "uniform vec3 BackgroundColor;\n" 374 | "uniform float PremultiplyAlpha;\n" 375 | "uniform float DisableFinalAlpha;\n" 376 | "uniform bool ForceNearestSampling;\n" 377 | "uniform vec4 Grid;\n" 378 | "uniform vec2 GridWidth;\n" 379 | "varying vec2 Frag_UV;\n" 380 | "void main()\n" 381 | "{\n" 382 | " vec2 uv;\n" 383 | " vec2 texel = Frag_UV * TextureSize;\n" 384 | " if (ForceNearestSampling)\n" 385 | " uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n" 386 | " else\n" 387 | " uv = Frag_UV;\n" 388 | " vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n" 389 | " float isGrid = max(texelEdge.x, texelEdge.y);\n" 390 | " vec4 ct = ColorTransform * texture2D(Texture, uv) + ColorOffset;\n" 391 | " ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n" 392 | " ct.rgb += BackgroundColor * (1.0-ct.a);\n" 393 | " ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n" 394 | " ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n" 395 | " gl_FragColor = ct;\n" 396 | "}\n"; 397 | 398 | const GLchar *fragment_shader_glsl_130 = "uniform sampler2D Texture;\n" 399 | "uniform vec2 TextureSize;\n" 400 | "uniform mat4 ColorTransform;\n" 401 | "uniform vec4 ColorOffset;\n" 402 | "uniform vec3 BackgroundColor;\n" 403 | "uniform float PremultiplyAlpha;\n" 404 | "uniform float DisableFinalAlpha;\n" 405 | "uniform bool ForceNearestSampling;\n" 406 | "uniform vec4 Grid;\n" 407 | "uniform vec2 GridWidth;\n" 408 | "in vec2 Frag_UV;\n" 409 | "out vec4 Out_Color;\n" 410 | "void main()\n" 411 | "{\n" 412 | " vec2 uv;\n" 413 | " vec2 texel = Frag_UV * TextureSize;\n" 414 | " if (ForceNearestSampling)\n" 415 | " uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n" 416 | " else\n" 417 | " uv = Frag_UV;\n" 418 | " vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n" 419 | " float isGrid = max(texelEdge.x, texelEdge.y);\n" 420 | " vec4 ct = ColorTransform * texture(Texture, uv) + ColorOffset;\n" 421 | " ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n" 422 | " ct.rgb += BackgroundColor * (1.0-ct.a);\n" 423 | " ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n" 424 | " ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n" 425 | " Out_Color = ct;\n" 426 | "}\n"; 427 | 428 | const GLchar *fragment_shader_glsl_300_es = "precision mediump float;\n" 429 | "uniform sampler2D Texture;\n" 430 | "uniform vec2 TextureSize;\n" 431 | "uniform mat4 ColorTransform;\n" 432 | "uniform vec4 ColorOffset;\n" 433 | "uniform vec3 BackgroundColor;\n" 434 | "uniform float PremultiplyAlpha;\n" 435 | "uniform float DisableFinalAlpha;\n" 436 | "uniform bool ForceNearestSampling;\n" 437 | "uniform vec4 Grid;\n" 438 | "uniform vec2 GridWidth;\n" 439 | "in vec2 Frag_UV;\n" 440 | "layout (location = 0) out vec4 Out_Color;\n" 441 | "void main()\n" 442 | "{\n" 443 | " vec2 uv;\n" 444 | " vec2 texel = Frag_UV * TextureSize;\n" 445 | " if (ForceNearestSampling)\n" 446 | " uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n" 447 | " else\n" 448 | " uv = Frag_UV;\n" 449 | " vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n" 450 | " float isGrid = max(texelEdge.x, texelEdge.y);\n" 451 | " vec4 ct = ColorTransform * texture(Texture, uv) + ColorOffset;\n" 452 | " ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n" 453 | " ct.rgb += BackgroundColor * (1.0-ct.a);\n" 454 | " ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n" 455 | " ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n" 456 | " Out_Color = ct;\n" 457 | "}\n"; 458 | 459 | const GLchar *fragment_shader_glsl_410_core = "uniform sampler2D Texture;\n" 460 | "uniform vec2 TextureSize;\n" 461 | "uniform mat4 ColorTransform;\n" 462 | "uniform vec4 ColorOffset;\n" 463 | "uniform vec3 BackgroundColor;\n" 464 | "uniform float PremultiplyAlpha;\n" 465 | "uniform float DisableFinalAlpha;\n" 466 | "uniform bool ForceNearestSampling;\n" 467 | "uniform vec4 Grid;\n" 468 | "uniform vec2 GridWidth;\n" 469 | "in vec2 Frag_UV;\n" 470 | "layout (location = 0) out vec4 Out_Color;\n" 471 | "void main()\n" 472 | "{\n" 473 | " vec2 uv;\n" 474 | " vec2 texel = Frag_UV * TextureSize;\n" 475 | " if (ForceNearestSampling)\n" 476 | " uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n" 477 | " else\n" 478 | " uv = Frag_UV;\n" 479 | " vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n" 480 | " float isGrid = max(texelEdge.x, texelEdge.y);\n" 481 | " vec4 ct = ColorTransform * texture(Texture, uv) + ColorOffset;\n" 482 | " ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n" 483 | " ct.rgb += BackgroundColor * (1.0-ct.a);\n" 484 | " ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n" 485 | " ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n" 486 | " Out_Color = ct;\n" 487 | "}\n"; 488 | 489 | /* BuildShader is from imgui_impl_opengl3.cpp. Only change is to query the 490 | * additional uniform locations for the new fragment shader*/ 491 | void BuildShader() 492 | { 493 | // Shader selection code based on imgui_impl_opengl3.cpp 494 | 495 | // Parse GLSL version string 496 | int glsl_version = 130; 497 | sscanf(g_GlslVersionString, "#version %d", &glsl_version); 498 | 499 | // Select shaders matching our GLSL versions 500 | const GLchar *vertex_shader = NULL; 501 | const GLchar *fragment_shader = NULL; 502 | if (glsl_version < 130) 503 | { 504 | vertex_shader = vertex_shader_glsl_120; 505 | fragment_shader = fragment_shader_glsl_120; 506 | } 507 | else if (glsl_version >= 410) 508 | { 509 | vertex_shader = vertex_shader_glsl_410_core; 510 | fragment_shader = fragment_shader_glsl_410_core; 511 | } 512 | else if (glsl_version == 300) 513 | { 514 | vertex_shader = vertex_shader_glsl_300_es; 515 | fragment_shader = fragment_shader_glsl_300_es; 516 | } 517 | else 518 | { 519 | vertex_shader = vertex_shader_glsl_130; 520 | fragment_shader = fragment_shader_glsl_130; 521 | } 522 | 523 | if (fragment_shader == NULL) 524 | { 525 | fprintf(stderr, "ERROR: imgui_tex_inspect fragment shader for %s not implemented yet", g_GlslVersionString); 526 | } 527 | else 528 | { 529 | // Create shaders 530 | const GLchar *vertex_shader_with_version[2] = {g_GlslVersionString, vertex_shader}; 531 | g_VertHandle = glCreateShader(GL_VERTEX_SHADER); 532 | glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); 533 | glCompileShader(g_VertHandle); 534 | CheckShader(g_VertHandle, "vertex shader"); 535 | 536 | const GLchar *fragment_shader_with_version[2] = {g_GlslVersionString, fragment_shader}; 537 | g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); 538 | glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); 539 | glCompileShader(g_FragHandle); 540 | CheckShader(g_FragHandle, "fragment shader"); 541 | 542 | g_ShaderHandle = glCreateProgram(); 543 | glAttachShader(g_ShaderHandle, g_VertHandle); 544 | glAttachShader(g_ShaderHandle, g_FragHandle); 545 | glLinkProgram(g_ShaderHandle); 546 | CheckProgram(g_ShaderHandle, "shader program"); 547 | 548 | g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); 549 | g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); 550 | g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position"); 551 | g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV"); 552 | 553 | // Change from imgui_impl_opengl3.cpp (Our shader doesn't use vertex color) 554 | //g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color"); 555 | 556 | // New uniforms used by imgui_tex_inspect 557 | g_UniformLocationTextureSize = glGetUniformLocation(g_ShaderHandle, "TextureSize"); 558 | g_UniformLocationColorTransform = glGetUniformLocation(g_ShaderHandle, "ColorTransform"); 559 | g_UniformLocationColorOffset = glGetUniformLocation(g_ShaderHandle, "ColorOffset"); 560 | g_UniformLocationBackgroundColor = glGetUniformLocation(g_ShaderHandle, "BackgroundColor"); 561 | g_UniformLocationPremultiplyAlpha = glGetUniformLocation(g_ShaderHandle, "PremultiplyAlpha"); 562 | g_UniformLocationDisableFinalAlpha = glGetUniformLocation(g_ShaderHandle, "DisableFinalAlpha"); 563 | g_UniformLocationGrid = glGetUniformLocation(g_ShaderHandle, "Grid"); 564 | g_UniformLocationForceNearestSampling = glGetUniformLocation(g_ShaderHandle, "ForceNearestSampling"); 565 | g_UniformLocationGridWidth = glGetUniformLocation(g_ShaderHandle, "GridWidth"); 566 | } 567 | } 568 | 569 | } // namespace imgui_impl_opengl 570 | 571 | 572 | namespace ImGuiTexInspect 573 | { 574 | using namespace imgui_impl_opengl; 575 | 576 | static GLuint readbackFramebuffer = 0; 577 | 578 | //------------------------------------------------------------------------- 579 | // [SECTION] Init and Shutdown 580 | //------------------------------------------------------------------------- 581 | 582 | bool ImplOpenGL3_Init(const char *glsl_version) 583 | { 584 | imgui_impl_opengl::ImGui_ImplOpenGL3_Init(glsl_version); 585 | BuildShader(); 586 | glGenFramebuffers(1, &readbackFramebuffer); 587 | return true; 588 | } 589 | void ImplOpenGl3_Shutdown() 590 | { 591 | // No need to call ImGui_ImplOpenGL3_Shutdown, it doesn't even 592 | // exist in the imgui_impl_opengl namespace. Our version of 593 | // ImGui_ImplOpenGL3_Init doesn't affect OpenGL state. 594 | 595 | glDeleteShader(g_VertHandle); 596 | glDeleteShader(g_FragHandle); 597 | glDeleteProgram(g_ShaderHandle); 598 | 599 | g_VertHandle = 0; 600 | g_FragHandle = 0; 601 | g_ShaderHandle = 0; 602 | 603 | glDeleteFramebuffers(1, &readbackFramebuffer); 604 | readbackFramebuffer = 0; 605 | } 606 | 607 | void GiveNotInitializedWarning() 608 | { 609 | static bool warningGiven = false; 610 | if (!warningGiven) 611 | { 612 | fprintf(stderr, "ERROR: ImGuiTexInspect backend not initialized\n"); 613 | warningGiven = true; 614 | } 615 | } 616 | 617 | //------------------------------------------------------------------------- 618 | // [SECTION] BackEnd functions declared in imgui_tex_inspect_internal.h 619 | //------------------------------------------------------------------------- 620 | 621 | void BackEnd_SetShader(const ImDrawList *, const ImDrawCmd *, const Inspector *inspector) 622 | { 623 | const ShaderOptions *texConversion = &inspector->CachedShaderOptions; 624 | if (g_ShaderHandle) 625 | { 626 | ImDrawData *draw_data = ImGui::GetDrawData(); 627 | int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); 628 | int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); 629 | 630 | if (fb_width <= 0 || fb_height <= 0) 631 | return; 632 | 633 | // Setup normal ImGui GL state 634 | ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height); 635 | 636 | // Setup imgui_tex_inspect specific shader uniforms 637 | glUniformMatrix4fv(g_UniformLocationColorTransform, 1, GL_FALSE, texConversion->ColorTransform); 638 | glUniform2fv(g_UniformLocationTextureSize, 1, &inspector->TextureSize.x); 639 | glUniform4fv(g_UniformLocationColorOffset, 1, texConversion->ColorOffset); 640 | glUniform3fv(g_UniformLocationBackgroundColor, 1, &texConversion->BackgroundColor.x); 641 | glUniform1f(g_UniformLocationPremultiplyAlpha, texConversion->PremultiplyAlpha); 642 | glUniform1f(g_UniformLocationDisableFinalAlpha, texConversion->DisableFinalAlpha); 643 | glUniform1i(g_UniformLocationForceNearestSampling, texConversion->ForceNearestSampling); 644 | glUniform2fv(g_UniformLocationGridWidth, 1, &texConversion->GridWidth.x); 645 | glUniform4fv(g_UniformLocationGrid, 1, &texConversion->GridColor.x); 646 | } 647 | else 648 | { 649 | GiveNotInitializedWarning(); 650 | } 651 | } 652 | bool BackEnd_GetData(Inspector *inspector, ImTextureID texture, int /*x*/, int /*y*/, int /*width*/, int /*height*/, BufferDesc *bufferDesc) 653 | { 654 | // Current simple implementation just gets data for whole texture 655 | 656 | if (readbackFramebuffer == 0) 657 | { 658 | GiveNotInitializedWarning(); 659 | return false; 660 | } 661 | const int numChannels = 4; 662 | glGetError(); // Discard any current error so that check at end of function is useful 663 | void * data; 664 | int texWidth = (int)inspector->TextureSize.x; 665 | int texHeight = (int)inspector->TextureSize.y; 666 | GLuint glTexture = (GLuint)(uintptr_t)texture; //Double cast to avoid warning 667 | 668 | #ifdef IMGUI_TEX_INSPECT_FLOAT_READ_ENABLED 669 | size_t bufferSize = sizeof(float) * texWidth * texHeight * numChannels; 670 | bufferDesc->Data_float = (float *)GetBuffer(inspector, bufferSize); 671 | GLuint type = GL_FLOAT; 672 | data = (void *)bufferDesc->Data_float; 673 | #else 674 | size_t bufferSize = sizeof(uint8_t) * texWidth * texHeight * numChannels; 675 | bufferDesc->Data_uint8_t = (uint8_t *)GetBuffer(inspector, bufferSize); 676 | GLuint type = GL_UNSIGNED_BYTE; 677 | data = (void *)bufferDesc->Data_uint8_t; 678 | #endif 679 | 680 | if (data == NULL) 681 | return false; 682 | 683 | bufferDesc->BufferByteSize = bufferSize; 684 | bufferDesc->Red = 0; // Data is packed such that red channel is first 685 | bufferDesc->Green = 1; // then green, then blue, the alpha. Hence, 0,1,2,3 686 | bufferDesc->Blue = 2; // for these channel order values. 687 | bufferDesc->Alpha = 3; 688 | bufferDesc->ChannelCount = 4; // RGBA 689 | bufferDesc->LineStride = (int)inspector->TextureSize.x * numChannels; 690 | bufferDesc->Stride = 4; // No padding between each RGBA texel 691 | bufferDesc->StartX = 0; // We queried the whole texture 692 | bufferDesc->StartY = 0; 693 | bufferDesc->Width = texWidth; 694 | bufferDesc->Height = texHeight; 695 | 696 | // Save current frame buffer so we can restore it 697 | GLuint currentFramebuffer; 698 | glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)¤tFramebuffer); 699 | 700 | // Read texture data 701 | glBindFramebuffer(GL_FRAMEBUFFER, readbackFramebuffer); 702 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture, 0); 703 | glReadPixels(0, 0, texWidth, texHeight, GL_RGBA, type, data); 704 | 705 | // Restore previous framebuffer 706 | glBindFramebuffer(GL_FRAMEBUFFER, currentFramebuffer); 707 | 708 | return glGetError() == GL_NO_ERROR; 709 | } 710 | } // namespace ImGuiTexInspect 711 | --------------------------------------------------------------------------------