├── .gitattributes ├── .gitignore ├── .gitmodules ├── LICENSE.md ├── README.md ├── src ├── LiveMemTracer.hpp └── LiveMemTracer_Windows.hpp └── test ├── External ├── GL │ ├── gl3w.cpp │ ├── gl3w.h │ └── glcorearb.h ├── GLFW │ ├── glfw3.h │ └── glfw3native.h ├── glfw3.lib ├── glfw3_x64.lib ├── glfw3_x86.lib └── imgui │ ├── .travis.yml │ ├── LICENSE │ ├── README.md │ ├── extra_fonts │ ├── Cousine-Regular.ttf │ ├── DroidSans.ttf │ ├── Karla-Regular.ttf │ ├── ProggyClean.ttf │ ├── ProggyTiny.ttf │ └── README.txt │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_impl_glfw_gl3.cpp │ ├── imgui_impl_glfw_gl3.h │ ├── imgui_internal.h │ ├── stb_rect_pack.h │ ├── stb_textedit.h │ └── stb_truetype.h ├── Main.cpp ├── Test.sln ├── Test.vcxproj ├── Test.vcxproj.filters └── imgui.ini /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Windows Azure Emulator 159 | efc/ 160 | rfc/ 161 | 162 | # Windows Store app package directory 163 | AppPackages/ 164 | 165 | # Visual Studio cache files 166 | # files ending in .cache can be ignored 167 | *.[Cc]ache 168 | # but keep track of directories ending in .cache 169 | !*.[Cc]ache/ 170 | 171 | # Others 172 | ClientBin/ 173 | [Ss]tyle[Cc]op.* 174 | ~$* 175 | *~ 176 | *.dbmdl 177 | *.dbproj.schemaview 178 | *.pfx 179 | *.publishsettings 180 | node_modules/ 181 | orleans.codegen.cs 182 | 183 | # RIA/Silverlight projects 184 | Generated_Code/ 185 | 186 | # Backup & report files from converting an old project file 187 | # to a newer Visual Studio version. Backup files are not needed, 188 | # because we have git ;-) 189 | _UpgradeReport_Files/ 190 | Backup*/ 191 | UpgradeLog*.XML 192 | UpgradeLog*.htm 193 | 194 | # SQL Server files 195 | *.mdf 196 | *.ldf 197 | 198 | # Business Intelligence projects 199 | *.rdl.data 200 | *.bim.layout 201 | *.bim_*.settings 202 | 203 | # Microsoft Fakes 204 | FakesAssemblies/ 205 | 206 | # GhostDoc plugin setting file 207 | *.GhostDoc.xml 208 | 209 | # Node.js Tools for Visual Studio 210 | .ntvs_analysis.dat 211 | 212 | # Visual Studio 6 build log 213 | *.plg 214 | 215 | # Visual Studio 6 workspace options file 216 | *.opt 217 | 218 | # Visual Studio LightSwitch build output 219 | **/*.HTMLClient/GeneratedArtifacts 220 | **/*.DesktopClient/GeneratedArtifacts 221 | **/*.DesktopClient/ModelManifest.xml 222 | **/*.Server/GeneratedArtifacts 223 | **/*.Server/ModelManifest.xml 224 | _Pvt_Extensions 225 | 226 | # Paket dependency manager 227 | .paket/paket.exe 228 | 229 | # FAKE - F# Make 230 | .fake/ 231 | 232 | # ========================= 233 | # Operating System Files 234 | # ========================= 235 | 236 | # OSX 237 | # ========================= 238 | 239 | .DS_Store 240 | .AppleDouble 241 | .LSOverride 242 | 243 | # Thumbnails 244 | ._* 245 | 246 | # Files that might appear in the root of a volume 247 | .DocumentRevisions-V100 248 | .fseventsd 249 | .Spotlight-V100 250 | .TemporaryItems 251 | .Trashes 252 | .VolumeIcon.icns 253 | 254 | # Directories potentially created on remote AFP share 255 | .AppleDB 256 | .AppleDesktop 257 | Network Trash Folder 258 | Temporary Items 259 | .apdisk 260 | 261 | # Windows 262 | # ========================= 263 | 264 | # Windows image file caches 265 | Thumbs.db 266 | ehthumbs.db 267 | 268 | # Folder config file 269 | Desktop.ini 270 | 271 | # Recycle Bin used on file shares 272 | $RECYCLE.BIN/ 273 | 274 | # Windows Installer files 275 | *.cab 276 | *.msi 277 | *.msm 278 | *.msp 279 | 280 | # Windows shortcuts 281 | *.lnk 282 | *.ini 283 | *.ini 284 | *.ini 285 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/LiveMemTracer_Orbis"] 2 | path = src/LiveMemTracer_Orbis 3 | url = https://github.com/cesarl/LiveMemTracer_Orbis/ 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LiveMemTracer 2 | ============= 3 | 4 | LiveMemTracer trace and display allocation stacks in real time. 5 | 6 | It's header only and use ImGui for display ( https://github.com/ocornut/imgui ) 7 | 8 | __/!\__ In a very early development stage __/!\__ 9 | 10 | Features 11 | -------- 12 | 13 | - Inspect stack 14 | - Search for callee 15 | - Trace functions or stacked calls 16 | - Detailed function view 17 | - Header only, easy to setup 18 | - Orbis version (contact me) 19 | 20 | Inspect stack 21 | 22 | ![Stack](http://i.imgur.com/pi8HJnj.png "Stack") 23 | 24 | Search for callee 25 | 26 | ![Callee](http://i.imgur.com/IqpkcGS.png "Callee") 27 | 28 | Trace functions and stacked calls 29 | 30 | ![Histograms](http://i.imgur.com/8gUFZER.png "Histograms") 31 | 32 | Detailed function view 33 | 34 | ![Detailed](http://i.imgur.com/QEgvGsy.png "Detailed") 35 | 36 | Using it 37 | -------- 38 | 39 | Define LiveMemTracer settings : 40 | ```cpp 41 | 42 | // Will enable "capture" feature : 43 | // Capture all stack infos and display diff between capture state 44 | // and current state. 45 | // (use more memory) 46 | #define LMT_CAPTURE_ACTIVATED 1 47 | 48 | // Will enable "instance count" feature : 49 | // Display the number of time functions allocate 50 | // Increment at allocation, decrement at free 51 | // (use more memory) 52 | #define LMT_INSTANCE_COUNT_ACTIVATED 1 53 | 54 | // Add more stats to "(?)" menu tooltip 55 | // Made it easy to setup dictionary size 56 | #define LMT_STATS 1 57 | 58 | // Define platform 59 | #define LMT_x64 60 | // Or 61 | #define LMT_x86 62 | 63 | // Number of allocs register per chunks 64 | // Adapt it to the number of allocations your program do 65 | // ( default : 1024 * 8 ) 66 | #define LMT_ALLOC_NUMBER_PER_CHUNK 1024 67 | 68 | // Max depth of the stack 69 | // ( default : 50 ) 70 | #define LMT_STACK_SIZE_PER_ALLOC 50 71 | 72 | // Pre allocated chunks per thread 73 | // ( default : 8 ) 74 | #define LMT_CHUNK_NUMBER_PER_THREAD 4 75 | 76 | // Cache size (per thread cache) 77 | // ( default : 16 ) 78 | #define LMT_CACHE_SIZE 8 79 | 80 | // Will assert one errors, example if Dictionnary is full 81 | #define LMT_DEBUG_DEV 1 82 | 83 | // ImGui header path 84 | #define LMT_IMGUI_INCLUDE_PATH "External/imgui/imgui.h" 85 | 86 | // Disable imgui 87 | #define LMT_IMGUI 0 88 | 89 | // Allocation dictionnary max entry 90 | // ( default : 1024 * 16 ) 91 | #define LMT_ALLOC_DICTIONARY_SIZE 1024 * 16 92 | 93 | // Stack dictionnary max entry 94 | // ( default : 1024 * 16 ) 95 | #define LMT_STACK_DICTIONARY_SIZE 1024 * 16 96 | 97 | // Leaf dictionnary max entry 98 | // Depend of the size of your program 99 | // ( default : 1024 * 16 * 16 ) 100 | #define LMT_TREE_DICTIONARY_SIZE 1024 * 16 * 16 101 | 102 | // Allocation functions used by LiveMemTracer 103 | #define LMT_USE_MALLOC ::malloc 104 | #define LMT_USE_REALLOC ::realloc 105 | #define LMT_USE_FREE ::free 106 | 107 | // Your assert function 108 | #define LMT_ASSERT(condition, message, ...) assert(condition) 109 | 110 | // Important if you want that LiveMemTracer treat allocation chunks asynchronously : 111 | // You can override it and ask to LMT to do the job differently. 112 | // Example : 113 | #define LMT_TREAT_CHUNK(chunk) MyTaskScheduler::getInstancer().pushTask([=](){LiveMemTracer::treatChunk(chunk);}) 114 | ``` 115 | 116 | In one `.cpp`, declare IMPL and include "LiveMemTracer.hpp" : 117 | 118 | ```cpp 119 | #define LMT_IMPL 1 120 | #include "../Src/LiveMemTracer.hpp" 121 | ``` 122 | 123 | In your main function : 124 | 125 | ```cpp 126 | int main(int ac, char **av) 127 | { 128 | LMT_INIT_SYMBOLS(); 129 | LMT_INIT(); 130 | // Your code 131 | LMT_EXIT(); 132 | return EXIT_SUCCESS; 133 | } 134 | ``` 135 | 136 | If you want to enable LiveMemTracer, add `LMT_ENABLED` to your pre-processor variables. If not, it'll be totally deactivated. 137 | 138 | Finally, used LMT macros for your allocations : 139 | 140 | ```cpp 141 | #define MY_MALLOC(size) LMT_ALLOC(size) 142 | #define MY_FREE(ptr) LMT_DEALLOC(ptr) 143 | #define MY_REALLOC(ptr, size) LMT_REALLOC(ptr, size) 144 | #define MY_MALLOC_ALIGNED(size, alignment) LMT_ALLOC_ALIGNED(size, alignment) 145 | #define MY_FREE_ALIGNED(ptr) LMT_DEALLOC_ALIGNED(ptr) 146 | #define MY_REALLOC_ALIGNED(ptr, size, alignment) LMT_REALLOC_ALIGNED(ptr, size, alignment) 147 | 148 | // Override new/delete operators 149 | void* operator new(size_t count) throw(std::bad_alloc) 150 | { 151 | return MY_MALLOC(count); 152 | } 153 | ... 154 | ... 155 | ... 156 | ``` 157 | 158 | Note : 159 | 160 | If some of your threads do the same allocations / deallocations so that the cache is hit everytime and so the chunk is never full and so never treated, you can force the current thread to treat chunk, with `LMT_FLUSH()`. 161 | -------------------------------------------------------------------------------- /src/LiveMemTracer_Windows.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef LMT_IMPLEMENTED 4 | 5 | #ifndef LMT_PLATFORM_WINDOWS 6 | static_assert(false, "LMT_PLATFORM_WINDOWS should be defined. Do not include this file in your code, only include LiveMemTracer.hpp"); 7 | #endif 8 | 9 | #include 10 | #include "imagehlp.h" 11 | #include "Shlwapi.h" //StrStrI 12 | #pragma comment(lib, "imagehlp.lib") 13 | #pragma comment(lib, "Shlwapi.lib") 14 | 15 | #define LMT_TLS __declspec(thread) 16 | 17 | namespace LiveMemTracer 18 | { 19 | typedef void* StackInfo; 20 | 21 | static inline uint32_t getCallstack(uint32_t maxStackSize, void **stack, Hash *hash) 22 | { 23 | uint32_t count = CaptureStackBackTrace(INTERNAL_FRAME_TO_SKIP, maxStackSize, stack, (PDWORD)hash); 24 | 25 | if (count == maxStackSize) 26 | { 27 | void* tmpStack[INTERNAL_MAX_STACK_DEPTH]; 28 | uint32_t tmpSize = CaptureStackBackTrace(INTERNAL_FRAME_TO_SKIP, INTERNAL_MAX_STACK_DEPTH, tmpStack, (PDWORD)hash); 29 | 30 | for (uint32_t i = 0; i < maxStackSize - 1; i++) 31 | stack[maxStackSize - 1 - i] = tmpStack[tmpSize - 1 - i]; 32 | stack[0] = (void*)~0; 33 | } 34 | return count; 35 | } 36 | 37 | namespace SymbolGetter 38 | { 39 | static inline const char *getSymbol(void *ptr, void *& absoluteAddress) 40 | { 41 | DWORD64 dwDisplacement = 0; 42 | DWORD64 dwAddress = DWORD64(ptr); 43 | HANDLE hProcess = GetCurrentProcess(); 44 | 45 | char pSymbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; 46 | PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)pSymbolBuffer; 47 | 48 | pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); 49 | pSymbol->MaxNameLen = MAX_SYM_NAME; 50 | 51 | if (size_t(ptr) == size_t(-1) || !SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol)) 52 | { 53 | return TRUNCATED_STACK_NAME; 54 | } 55 | absoluteAddress = (void*)(DWORD64(ptr) - dwDisplacement); 56 | return _strdup(pSymbol->Name); 57 | } 58 | } 59 | } 60 | 61 | void LiveMemTracer::SymbolGetter::init() 62 | { 63 | HANDLE hProcess; 64 | 65 | SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); 66 | 67 | hProcess = GetCurrentProcess(); 68 | if (!SymInitialize(hProcess, NULL, TRUE)) 69 | { 70 | LMT_ASSERT(false, "SymInitialize failed."); 71 | } 72 | } 73 | 74 | #endif -------------------------------------------------------------------------------- /test/External/GLFW/glfw3native.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * GLFW 3.1 - 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 | /*! @defgroup native Native access 42 | * 43 | * **By using the native access functions you assert that you know what you're 44 | * doing and how to fix problems caused by using them. If you don't, you 45 | * shouldn't be using them.** 46 | * 47 | * Before the inclusion of @ref glfw3native.h, you must define exactly one 48 | * window system API macro and exactly one context creation API macro. Failure 49 | * to do this will cause a compile-time error. 50 | * 51 | * The available window API macros are: 52 | * * `GLFW_EXPOSE_NATIVE_WIN32` 53 | * * `GLFW_EXPOSE_NATIVE_COCOA` 54 | * * `GLFW_EXPOSE_NATIVE_X11` 55 | * 56 | * The available context API macros are: 57 | * * `GLFW_EXPOSE_NATIVE_WGL` 58 | * * `GLFW_EXPOSE_NATIVE_NSGL` 59 | * * `GLFW_EXPOSE_NATIVE_GLX` 60 | * * `GLFW_EXPOSE_NATIVE_EGL` 61 | * 62 | * These macros select which of the native access functions that are declared 63 | * and which platform-specific headers to include. It is then up your (by 64 | * definition platform-specific) code to handle which of these should be 65 | * defined. 66 | */ 67 | 68 | 69 | /************************************************************************* 70 | * System headers and types 71 | *************************************************************************/ 72 | 73 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 74 | // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for 75 | // example to allow applications to correctly declare a GL_ARB_debug_output 76 | // callback) but windows.h assumes no one will define APIENTRY before it does 77 | #undef APIENTRY 78 | #include 79 | #elif defined(GLFW_EXPOSE_NATIVE_COCOA) 80 | #include 81 | #if defined(__OBJC__) 82 | #import 83 | #else 84 | typedef void* id; 85 | #endif 86 | #elif defined(GLFW_EXPOSE_NATIVE_X11) 87 | #include 88 | #include 89 | #else 90 | #error "No window API selected" 91 | #endif 92 | 93 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 94 | /* WGL is declared by windows.h */ 95 | #elif defined(GLFW_EXPOSE_NATIVE_NSGL) 96 | /* NSGL is declared by Cocoa.h */ 97 | #elif defined(GLFW_EXPOSE_NATIVE_GLX) 98 | #include 99 | #elif defined(GLFW_EXPOSE_NATIVE_EGL) 100 | #include 101 | #else 102 | #error "No context API selected" 103 | #endif 104 | 105 | 106 | /************************************************************************* 107 | * Functions 108 | *************************************************************************/ 109 | 110 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 111 | /*! @brief Returns the adapter device name of the specified monitor. 112 | * 113 | * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) 114 | * of the specified monitor, or `NULL` if an [error](@ref error_handling) 115 | * occurred. 116 | * 117 | * @par Thread Safety 118 | * This function may be called from any thread. Access is not synchronized. 119 | * 120 | * @par History 121 | * Added in GLFW 3.1. 122 | * 123 | * @ingroup native 124 | */ 125 | GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); 126 | 127 | /*! @brief Returns the display device name of the specified monitor. 128 | * 129 | * @return The UTF-8 encoded display device name (for example 130 | * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an 131 | * [error](@ref error_handling) occurred. 132 | * 133 | * @par Thread Safety 134 | * This function may be called from any thread. Access is not synchronized. 135 | * 136 | * @par History 137 | * Added in GLFW 3.1. 138 | * 139 | * @ingroup native 140 | */ 141 | GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); 142 | 143 | /*! @brief Returns the `HWND` of the specified window. 144 | * 145 | * @return The `HWND` of the specified window, or `NULL` if an 146 | * [error](@ref error_handling) occurred. 147 | * 148 | * @par Thread Safety 149 | * This function may be called from any thread. Access is not synchronized. 150 | * 151 | * @par History 152 | * Added in GLFW 3.0. 153 | * 154 | * @ingroup native 155 | */ 156 | GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); 157 | #endif 158 | 159 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 160 | /*! @brief Returns the `HGLRC` of the specified window. 161 | * 162 | * @return The `HGLRC` of the specified window, or `NULL` if an 163 | * [error](@ref error_handling) occurred. 164 | * 165 | * @par Thread Safety 166 | * This function may be called from any thread. Access is not synchronized. 167 | * 168 | * @par History 169 | * Added in GLFW 3.0. 170 | * 171 | * @ingroup native 172 | */ 173 | GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); 174 | #endif 175 | 176 | #if defined(GLFW_EXPOSE_NATIVE_COCOA) 177 | /*! @brief Returns the `CGDirectDisplayID` of the specified monitor. 178 | * 179 | * @return The `CGDirectDisplayID` of the specified monitor, or 180 | * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. 181 | * 182 | * @par Thread Safety 183 | * This function may be called from any thread. Access is not synchronized. 184 | * 185 | * @par History 186 | * Added in GLFW 3.1. 187 | * 188 | * @ingroup native 189 | */ 190 | GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); 191 | 192 | /*! @brief Returns the `NSWindow` of the specified window. 193 | * 194 | * @return The `NSWindow` of the specified window, or `nil` if an 195 | * [error](@ref error_handling) occurred. 196 | * 197 | * @par Thread Safety 198 | * This function may be called from any thread. Access is not synchronized. 199 | * 200 | * @par History 201 | * Added in GLFW 3.0. 202 | * 203 | * @ingroup native 204 | */ 205 | GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); 206 | #endif 207 | 208 | #if defined(GLFW_EXPOSE_NATIVE_NSGL) 209 | /*! @brief Returns the `NSOpenGLContext` of the specified window. 210 | * 211 | * @return The `NSOpenGLContext` of the specified window, or `nil` if an 212 | * [error](@ref error_handling) occurred. 213 | * 214 | * @par Thread Safety 215 | * This function may be called from any thread. Access is not synchronized. 216 | * 217 | * @par History 218 | * Added in GLFW 3.0. 219 | * 220 | * @ingroup native 221 | */ 222 | GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); 223 | #endif 224 | 225 | #if defined(GLFW_EXPOSE_NATIVE_X11) 226 | /*! @brief Returns the `Display` used by GLFW. 227 | * 228 | * @return The `Display` used by GLFW, or `NULL` if an 229 | * [error](@ref error_handling) occurred. 230 | * 231 | * @par Thread Safety 232 | * This function may be called from any thread. Access is not synchronized. 233 | * 234 | * @par History 235 | * Added in GLFW 3.0. 236 | * 237 | * @ingroup native 238 | */ 239 | GLFWAPI Display* glfwGetX11Display(void); 240 | 241 | /*! @brief Returns the `RRCrtc` of the specified monitor. 242 | * 243 | * @return The `RRCrtc` of the specified monitor, or `None` if an 244 | * [error](@ref error_handling) occurred. 245 | * 246 | * @par Thread Safety 247 | * This function may be called from any thread. Access is not synchronized. 248 | * 249 | * @par History 250 | * Added in GLFW 3.1. 251 | * 252 | * @ingroup native 253 | */ 254 | GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); 255 | 256 | /*! @brief Returns the `RROutput` of the specified monitor. 257 | * 258 | * @return The `RROutput` of the specified monitor, or `None` if an 259 | * [error](@ref error_handling) occurred. 260 | * 261 | * @par Thread Safety 262 | * This function may be called from any thread. Access is not synchronized. 263 | * 264 | * @par History 265 | * Added in GLFW 3.1. 266 | * 267 | * @ingroup native 268 | */ 269 | GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); 270 | 271 | /*! @brief Returns the `Window` of the specified window. 272 | * 273 | * @return The `Window` of the specified window, or `None` if an 274 | * [error](@ref error_handling) occurred. 275 | * 276 | * @par Thread Safety 277 | * This function may be called from any thread. Access is not synchronized. 278 | * 279 | * @par History 280 | * Added in GLFW 3.0. 281 | * 282 | * @ingroup native 283 | */ 284 | GLFWAPI Window glfwGetX11Window(GLFWwindow* window); 285 | #endif 286 | 287 | #if defined(GLFW_EXPOSE_NATIVE_GLX) 288 | /*! @brief Returns the `GLXContext` of the specified window. 289 | * 290 | * @return The `GLXContext` of the specified window, or `NULL` if an 291 | * [error](@ref error_handling) occurred. 292 | * 293 | * @par Thread Safety 294 | * This function may be called from any thread. Access is not synchronized. 295 | * 296 | * @par History 297 | * Added in GLFW 3.0. 298 | * 299 | * @ingroup native 300 | */ 301 | GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); 302 | #endif 303 | 304 | #if defined(GLFW_EXPOSE_NATIVE_EGL) 305 | /*! @brief Returns the `EGLDisplay` used by GLFW. 306 | * 307 | * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an 308 | * [error](@ref error_handling) occurred. 309 | * 310 | * @par Thread Safety 311 | * This function may be called from any thread. Access is not synchronized. 312 | * 313 | * @par History 314 | * Added in GLFW 3.0. 315 | * 316 | * @ingroup native 317 | */ 318 | GLFWAPI EGLDisplay glfwGetEGLDisplay(void); 319 | 320 | /*! @brief Returns the `EGLContext` of the specified window. 321 | * 322 | * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an 323 | * [error](@ref error_handling) occurred. 324 | * 325 | * @par Thread Safety 326 | * This function may be called from any thread. Access is not synchronized. 327 | * 328 | * @par History 329 | * Added in GLFW 3.0. 330 | * 331 | * @ingroup native 332 | */ 333 | GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); 334 | 335 | /*! @brief Returns the `EGLSurface` of the specified window. 336 | * 337 | * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an 338 | * [error](@ref error_handling) occurred. 339 | * 340 | * @par Thread Safety 341 | * This function may be called from any thread. Access is not synchronized. 342 | * 343 | * @par History 344 | * Added in GLFW 3.0. 345 | * 346 | * @ingroup native 347 | */ 348 | GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); 349 | #endif 350 | 351 | #ifdef __cplusplus 352 | } 353 | #endif 354 | 355 | #endif /* _glfw3_native_h_ */ 356 | 357 | -------------------------------------------------------------------------------- /test/External/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/glfw3.lib -------------------------------------------------------------------------------- /test/External/glfw3_x64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/glfw3_x64.lib -------------------------------------------------------------------------------- /test/External/glfw3_x86.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/glfw3_x86.lib -------------------------------------------------------------------------------- /test/External/imgui/.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | os: 4 | - linux 5 | 6 | compiler: 7 | - gcc 8 | - clang 9 | 10 | before_install: 11 | - if [ $TRAVIS_OS_NAME == linux ]; then sudo add-apt-repository -y ppa:pyglfw/pyglfw && sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libglfw3-dev libxrandr-dev libxi-dev libxxf86vm-dev; fi 12 | - if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install glfw3; fi 13 | 14 | script: 15 | - make -C examples/opengl_example 16 | - make -C examples/opengl3_example 17 | 18 | -------------------------------------------------------------------------------- /test/External/imgui/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Omar Cornut and ImGui contributors 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 | -------------------------------------------------------------------------------- /test/External/imgui/README.md: -------------------------------------------------------------------------------- 1 | ImGui 2 | ===== 3 | [![Build Status](https://travis-ci.org/ocornut/imgui.svg?branch=master)](https://travis-ci.org/ocornut/imgui) 4 | [![Coverity Status](https://scan.coverity.com/projects/4720/badge.svg)](https://scan.coverity.com/projects/4720) 5 | 6 | (This library is free but I need your support to sustain its development - there's lots of desirable new features and maintenance to do. If you work for a company using ImGui or have the means to do so, please consider financial support) 7 | 8 | [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) 9 | 10 | ImGui is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is portable, renderer agnostic and self-contained (no external dependencies). It is based on an "immediate mode" graphical user interface paradigm which enables you to build user interfaces with ease. 11 | 12 | ImGui is designed to enable fast iteration and empower programmers to create content creation tools and visualization/debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and thus lacks certain features normally found in more high-level libraries. 13 | 14 | ImGui is particularly suited to integration in realtime 3D applications, fullscreen applications, embedded applications, games, or any applications on consoles platforms where operating system features are non-standard. 15 | 16 | ImGui is self-contained within a few files that you can easily copy and compile into your application/engine: 17 | 18 | - imgui.cpp 19 | - imgui.h 20 | - imgui_demo.cpp 21 | - imgui_draw.cpp 22 | - imgui_internal.h 23 | - imconfig.h (empty by default, user-editable) 24 | - stb_rect_pack.h 25 | - stb_textedit.h 26 | - stb_truetype.h 27 | 28 | No specific build process is required. You can add the .cpp files to your project or #include them from an existing file. 29 | 30 | Your code passes mouse/keyboard inputs and settings to ImGui (see example applications for more details). After ImGui is setup, you can use it like in this example: 31 | 32 | ![screenshot of sample code alongside its output with ImGui](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/code_sample_01.png) 33 | 34 | ImGui outputs vertex buffers and simple command-lists that you can render in your application. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase. 35 | 36 | ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. 37 | 38 | Some of the features supported in some way by ImGui: window management (ordering, moving, resizing, collapsing, persistent settings), button, slider, dragging value, checkbox, radio button, text input (with selection, clipboard support, and standard keyboard controls), multiline text input, filtering text input, tree nodes, collapsing header, word-wrapping, utf-8 text, images, selectable items, vertical and horizontal scrolling, sub-window with independant scrolling/clipping, ttf font loading, basic styling, logging any ui output into text data (clipboard/tty/file), hovering, tooltips, popup windows, modal windows, menu bars, menu items, context menus, combo boxes, list box, plotting lines and histograms, resizable columns, keyboard tabbing, dragging, simple drawing api (anti-aliased, with stroking, convex fill), and low-level primitives to create custom widgets. 39 | 40 | Demo 41 | ---- 42 | 43 | You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download Windows binaries of the demo app here. 44 | - [imgui-demo-binaries-20150909.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20150909.zip) (Windows binaries, ImGui 1.46 WIP 2015/09/09, 4 executables, 505 KB) 45 | 46 | 47 | Gallery 48 | ------- 49 | 50 | ![screenshot 1](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/examples_04.png) 51 | ![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_01.png) 52 | ![screenshot 3](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_02.png) 53 | ![screenshot 4](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_03.png) 54 | ![screenshot 5](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v140/test_window_05_menus.png) 55 | ![screenshot 6](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/skinning_sample_02.png) 56 | ![screenshot 7](https://cloud.githubusercontent.com/assets/8225057/7903336/96f0fb7c-07d0-11e5-95d6-41c6a1595e5a.png) 57 | 58 | ImGui can load TTF fonts. UTF-8 is supported for text display and input. Here using Arial Unicode font to display Japanese. Initialize custom font with: 59 | ``` 60 | ImGuiIO& io = ImGui::GetIO(); 61 | io.Fonts->AddFontFromFileTTF("ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); 62 | 63 | // For Microsoft IME, pass your HWND to enable IME positioning: 64 | io.ImeWindowHandle = my_hwnd; 65 | ``` 66 | ![Japanese screenshot](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/code_sample_01_jp.png) 67 | 68 | References 69 | ---------- 70 | 71 | The Immediate Mode GUI paradigm may at first appear unusual to some users. This is mainly because "Retained Mode" GUIs have been so widespread and predominant. The following links can give you a better understanding about how Immediate Mode GUIs works. 72 | - [Johannes 'johno' Norneby's article](http://www.johno.se/book/imgui.html). 73 | - [A presentation by Rickard Gustafsson and Johannes Algelind](http://www.cse.chalmers.se/edu/year/2011/course/TDA361/Advanced%20Computer%20Graphics/IMGUI.pdf). 74 | - [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/). 75 | - [Casey Muratori's original video that popularized the concept](https://mollyrocket.com/861). 76 | 77 | See the [Links page](https://github.com/ocornut/imgui/wiki/Links) for third-party bindings to different languages and frameworks. 78 | 79 | Frequently Asked Question (FAQ) 80 | ------------------------------- 81 | 82 | Where is the documentation? 83 | 84 | - The documentation is at the top of imgui.cpp + effectively imgui.h. 85 | - Example code is in imgui_demo.cpp and particularly the ImGui::ShowTestWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output. 86 | - Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder. 87 | - It obviously needs better documentation! Consider helping or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort. 88 | 89 | How do you use ImGui on a platform that may not have a mouse or keyboard? 90 | 91 | I recommend using [Synergy](http://synergy-project.org) ([sources](https://github.com/synergy/synergy)). In particular, the _src/micro/uSynergy.c_ file contains a small client that you can use on any platform to connect to your host PC. You can seamlessly use your PC input devices from a video game console or a tablet. ImGui allows to increase the hit box of widgets (via the _TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse to allow optimising for screen real-estate. 92 | 93 | I integrated ImGui in my engine and the text or lines are blurry.. 94 | 95 | In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. 96 | 97 | I integrated ImGui in my engine and some elements are disappearing when I move windows around.. 98 | 99 | Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height). 100 | 101 | Can you create elaborate/serious tools with ImGui? 102 | 103 | Yes. I have written data browsers, debuggers, profilers and all sort of non-trivial tools with the library. In my experience the simplicity of the API is very empowering. Your UI runs close to your live data. Make the tools always-on and everybody in the team will be inclined to create new tools (as opposed to more "offline" UI toolkits where only a fraction of your team effectively creates tools). 104 | 105 | ImGui is very programmer centric and the immediate-mode GUI paradigm might requires a bit of adaptation before you can realize its full potential. Many programmers have unfortunately been taught by their environment to make unnecessarily complicated things. ImGui is about making things that are simple, efficient and powerful. 106 | 107 | Is ImGui fast? 108 | 109 | Probably fast enough for most uses. Down to the fundation of its visual design, ImGui is engineered to be fairly performant both in term of CPU and GPU usage. Running elaborate code and creating elaborate UI will of course have a cost but ImGui aims to minimize it. 110 | 111 | Mileage may vary but the following screenshot can give you a rough idea of the cost of running and rendering UI code (In the case of a trivial demo application like this one, your driver/os setup are likely to be the bottleneck. Testing performance as part of a real application is recommended). 112 | 113 | ![performance screenshot](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v138/performance_01.png) 114 | 115 | This is showing framerate for the full application loop on my 2011 iMac running Windows 7, OpenGL, AMD Radeon HD 6700M with an optimized executable. In contrast, librairies featuring higher-quality rendering and layouting techniques may have a higher resources footprint. 116 | 117 | If you intend to display large lists of items (say, 1000+) it can be beneficial for your code to perform clipping manually - one way is using helpers such as ImGuiListClipper - in order to avoid submitting them to ImGui in the first place. Even though ImGui will discard your clipped items it still needs to calculate their size and that overhead will add up if you have thousands of items. If you can handle clipping and height positionning yourself then browsing a list with millions of items isn't a problem. 118 | 119 | Can you reskin the look of ImGui? 120 | 121 | You can alter the look of the interface to some degree: changing colors, sizes, padding, rounding, fonts. However, as ImGui is designed and optimised to create debug tools, the amount of skinning you can apply is limited. There is only so much you can stray away from the default look and feel of the interface. 122 | 123 | Why using C++ (as opposed to C)? 124 | 125 | ImGui takes advantage of a few C++ features for convenience but nothing anywhere Boost-insanity/quagmire. In particular, function overloading and default parameters are used to make the API easier to use and code more terse. Doing so I believe the API is sitting on a sweet spot and giving up on those features would make the API more cumbersome. Other features such as namespace, constructors and templates (in the case of the ImVector<> class) are also relied on as a convenience but could be removed. 126 | 127 | There is an unofficial but reasonably maintained [c-api for ImGui](https://github.com/Extrawurst/cimgui) by Stephan Dilly. I would suggest using your target language functionality to try replicating the function overloading and default parameters used in C++ else the API may be harder to use. It was really designed with C++ in mind and may not make the same amount of sense with another language. Also see [Links](https://github.com/ocornut/imgui/wiki/Links) for third-party bindings to other languages. 128 | 129 | Donate 130 | ------ 131 | 132 | Can I donate to support the development of ImGui? 133 | 134 | [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) 135 | 136 | I'm currently an independant developer and your contributions are very meaningful to me. I have setup an [**ImGui Patreon page**](http://www.patreon.com/imgui) if you want to donate and enable me to spend more time improving the library. If your company uses ImGui please consider making a contribution. One-off donations are also greatly appreciated (PayPal link above). I am also available for hire to work on or with ImGui. Thanks! 137 | 138 | Credits 139 | ------- 140 | 141 | Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com). 142 | 143 | I first discovered imgui principles at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple imgui implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it. 144 | 145 | Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT license). 146 | 147 | Embeds [stb_textedit.h, stb_truetype.h, stb_rectpack.h](https://github.com/nothings/stb/) by Sean Barrett (public domain). 148 | 149 | Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. And everybody posting feedback, questions and patches on the GitHub. 150 | 151 | ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). 152 | 153 | Special supporters: 154 | - Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano. 155 | 156 | And: 157 | - Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner. 158 | 159 | And other supporters; thanks! 160 | 161 | License 162 | ------- 163 | 164 | ImGui is licensed under the MIT License, see LICENSE for more information. 165 | -------------------------------------------------------------------------------- /test/External/imgui/extra_fonts/Cousine-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/imgui/extra_fonts/Cousine-Regular.ttf -------------------------------------------------------------------------------- /test/External/imgui/extra_fonts/DroidSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/imgui/extra_fonts/DroidSans.ttf -------------------------------------------------------------------------------- /test/External/imgui/extra_fonts/Karla-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/imgui/extra_fonts/Karla-Regular.ttf -------------------------------------------------------------------------------- /test/External/imgui/extra_fonts/ProggyClean.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/imgui/extra_fonts/ProggyClean.ttf -------------------------------------------------------------------------------- /test/External/imgui/extra_fonts/ProggyTiny.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesarl/LiveMemTracer/d3c5ad91fd061de83572dba061a287635c751b4c/test/External/imgui/extra_fonts/ProggyTiny.ttf -------------------------------------------------------------------------------- /test/External/imgui/extra_fonts/README.txt: -------------------------------------------------------------------------------- 1 | 2 | The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' that you can use without any external files. 3 | Those are only provided as a convenience, you can load your own .TTF files. 4 | 5 | --------------------------------- 6 | LOADING INSTRUCTIONS 7 | --------------------------------- 8 | 9 | Load default font with: 10 | 11 | ImGuiIO& io = ImGui::GetIO(); 12 | io.Fonts->AddFontDefault(); 13 | 14 | Load .TTF file with: 15 | 16 | ImGuiIO& io = ImGui::GetIO(); 17 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); 18 | 19 | Detailed options: 20 | 21 | ImFontConfig config; 22 | config.OversampleH = 3; 23 | config.OversampleV = 3; 24 | config.GlyphExtraSpacing.x = 1.0f; 25 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); 26 | 27 | Combine two fonts into one: 28 | 29 | // Load main font 30 | io.Fonts->AddFontDefault(); 31 | 32 | // Add character ranges and merge into main font 33 | // The ranges array is not copied by the AddFont* functions and is used lazily 34 | // so ensure it is available for duration of font usage 35 | static const ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; 36 | ImFontConfig config; 37 | config.MergeMode = true; 38 | io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); 39 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config, io.Fonts->GetGlyphRangesJapanese()); 40 | 41 | Add a fourth parameter to bake specific font ranges only: 42 | 43 | // Basic Latin, Extended Latin 44 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault()); 45 | 46 | // Include full set of about 21000 CJK Unified Ideographs 47 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); 48 | 49 | // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs 50 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesChinese()); 51 | 52 | Offset font vertically by altering the io.Font->DisplayOffset value: 53 | 54 | ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); 55 | font->DisplayOffset.y += 1; // Render 1 pixel down 56 | 57 | --------------------------------- 58 | EMBED A FONT IN SOURCE CODE 59 | --------------------------------- 60 | 61 | Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array. Then load the font with: 62 | 63 | ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); 64 | 65 | Or 66 | 67 | ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); 68 | 69 | --------------------------------- 70 | INCLUDED FONT FILES 71 | --------------------------------- 72 | 73 | Cousine-Regular.ttf 74 | Digitized data copyright (c) 2010 Google Corporation. 75 | Licensed under the SIL Open Font License, Version 1.1 76 | 77 | DroidSans.ttf 78 | Copyright (c) Steve Matteson 79 | Apache License, version 2.0 80 | http://www.google.com/fonts/specimen/Droid+Sans 81 | 82 | ProggyClean.ttf 83 | Copyright (c) 2004, 2005 Tristan Grimmer 84 | MIT License 85 | recommended loading setting in ImGui: Size = 13.0, DisplayOffset.Y = +1 86 | 87 | ProggyTiny.ttf 88 | Copyright (c) 2004, 2005 Tristan Grimmer 89 | MIT License 90 | recommended loading setting in ImGui: Size = 10.0, DisplayOffset.Y = +1 91 | 92 | Karla-Regular 93 | Copyright (c) 2012, Jonathan Pinhorn 94 | SIL OPEN FONT LICENSE Version 1.1 95 | 96 | --------------------------------- 97 | LINKS 98 | --------------------------------- 99 | 100 | Typefaces for source code beautification 101 | https://github.com/chrissimpkins/codeface 102 | 103 | Programmation fonts 104 | http://s9w.github.io/font_compare/ 105 | 106 | Proggy Programming Fonts 107 | http://upperbounds.net 108 | 109 | Inconsolata 110 | http://www.levien.com/type/myfonts/inconsolata.html 111 | 112 | Adobe Source Code Pro: Monospaced font family for user interface and coding environments 113 | https://github.com/adobe-fonts/source-code-pro 114 | 115 | Monospace/Fixed Width Programmer's Fonts 116 | http://www.lowing.org/fonts/ 117 | 118 | (Japanese) M+ fonts by Coji Morishita are free and include most useful Kanjis you would need. 119 | http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html 120 | 121 | Or use Arial Unicode or other Unicode fonts provided with Windows for full characters coverage (not sure of their licensing). 122 | -------------------------------------------------------------------------------- /test/External/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // USER IMPLEMENTATION 3 | // This file contains compile-time options for ImGui. 4 | // Other options (memory allocation overrides, callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO(). 5 | //----------------------------------------------------------------------------- 6 | 7 | #pragma once 8 | 9 | //---- Define assertion handler. Defaults to calling assert(). 10 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 11 | 12 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. 13 | //#define IMGUI_API __declspec( dllexport ) 14 | //#define IMGUI_API __declspec( dllimport ) 15 | 16 | //---- Include imgui_user.inl at the end of imgui.cpp so you can include code that extends ImGui using its private data/functions. 17 | //#define IMGUI_INCLUDE_IMGUI_USER_INL 18 | 19 | //---- Include imgui_user.h at the end of imgui.h 20 | //#define IMGUI_INCLUDE_IMGUI_USER_H 21 | 22 | //---- Don't implement default handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions) 23 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS 24 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS 25 | 26 | //---- Don't implement help and test window functionality (ShowUserGuide()/ShowStyleEditor()/ShowTestWindow() methods will be empty) 27 | //#define IMGUI_DISABLE_TEST_WINDOWS 28 | 29 | //---- Don't define obsolete functions names 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | 32 | //---- Implement STB libraries in a namespace to avoid conflicts 33 | //#define IMGUI_STB_NAMESPACE ImGuiStb 34 | 35 | //---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. 36 | /* 37 | #define IM_VEC2_CLASS_EXTRA \ 38 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 39 | operator MyVec2() const { return MyVec2(x,y); } 40 | 41 | #define IM_VEC4_CLASS_EXTRA \ 42 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 43 | operator MyVec4() const { return MyVec4(x,y,z,w); } 44 | */ 45 | 46 | //---- Freely implement extra functions within the ImGui:: namespace. 47 | //---- Declare helpers or widgets implemented in imgui_user.inl or elsewhere, so end-user doesn't need to include multiple files. 48 | //---- e.g. you can create variants of the ImGui::Value() helper for your low-level math types, or your own widgets/helpers. 49 | /* 50 | namespace ImGui 51 | { 52 | void Value(const char* prefix, const MyVec2& v, const char* float_format = NULL); 53 | void Value(const char* prefix, const MyVec4& v, const char* float_format = NULL); 54 | } 55 | */ 56 | 57 | #define ImDrawIdx unsigned int 58 | -------------------------------------------------------------------------------- /test/External/imgui/imgui_impl_glfw_gl3.cpp: -------------------------------------------------------------------------------- 1 | // ImGui GLFW binding with OpenGL3 + shaders 2 | // You can copy and use unmodified imgui_impl_* files in your project. 3 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). 4 | // See main.cpp for an example of using this. 5 | // https://github.com/ocornut/imgui 6 | 7 | #include "imgui.h" 8 | #include "imgui_impl_glfw_gl3.h" 9 | 10 | // GL3W/GLFW 11 | #include 12 | #include 13 | #ifdef _WIN32 14 | #undef APIENTRY 15 | #define GLFW_EXPOSE_NATIVE_WIN32 16 | #define GLFW_EXPOSE_NATIVE_WGL 17 | #include 18 | #endif 19 | 20 | // Data 21 | static GLFWwindow* g_Window = NULL; 22 | static double g_Time = 0.0f; 23 | static bool g_MousePressed[3] = { false, false, false }; 24 | static float g_MouseWheel = 0.0f; 25 | static GLuint g_FontTexture = 0; 26 | static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; 27 | static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; 28 | static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; 29 | static unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0; 30 | 31 | // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) 32 | // If text or lines are blurry when integrating ImGui in your engine: 33 | // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) 34 | void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) 35 | { 36 | // Backup GL state 37 | GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); 38 | GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 39 | GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 40 | GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); 41 | GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 42 | GLint last_blend_src; glGetIntegerv(GL_BLEND_SRC, &last_blend_src); 43 | GLint last_blend_dst; glGetIntegerv(GL_BLEND_DST, &last_blend_dst); 44 | GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); 45 | GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); 46 | GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); 47 | GLboolean last_enable_blend = glIsEnabled(GL_BLEND); 48 | GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); 49 | GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); 50 | GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); 51 | 52 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled 53 | glEnable(GL_BLEND); 54 | glBlendEquation(GL_FUNC_ADD); 55 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 56 | glDisable(GL_CULL_FACE); 57 | glDisable(GL_DEPTH_TEST); 58 | glEnable(GL_SCISSOR_TEST); 59 | glActiveTexture(GL_TEXTURE0); 60 | 61 | // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) 62 | ImGuiIO& io = ImGui::GetIO(); 63 | float fb_height = io.DisplaySize.y * io.DisplayFramebufferScale.y; 64 | draw_data->ScaleClipRects(io.DisplayFramebufferScale); 65 | 66 | // Setup viewport, orthographic projection matrix 67 | glViewport(0, 0, (GLsizei)io.DisplaySize.x, (GLsizei)io.DisplaySize.y); 68 | const float ortho_projection[4][4] = 69 | { 70 | { 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f }, 71 | { 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f }, 72 | { 0.0f, 0.0f, -1.0f, 0.0f }, 73 | {-1.0f, 1.0f, 0.0f, 1.0f }, 74 | }; 75 | glUseProgram(g_ShaderHandle); 76 | glUniform1i(g_AttribLocationTex, 0); 77 | glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); 78 | glBindVertexArray(g_VaoHandle); 79 | 80 | for (int n = 0; n < draw_data->CmdListsCount; n++) 81 | { 82 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 83 | const ImDrawIdx* idx_buffer_offset = 0; 84 | 85 | glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); 86 | glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.size() * sizeof(ImDrawVert), (GLvoid*)&cmd_list->VtxBuffer.front(), GL_STREAM_DRAW); 87 | 88 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); 89 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx), (GLvoid*)&cmd_list->IdxBuffer.front(), GL_STREAM_DRAW); 90 | 91 | for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++) 92 | { 93 | if (pcmd->UserCallback) 94 | { 95 | pcmd->UserCallback(cmd_list, pcmd); 96 | } 97 | else 98 | { 99 | glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); 100 | glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); 101 | glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, GL_UNSIGNED_INT, idx_buffer_offset); 102 | } 103 | idx_buffer_offset += pcmd->ElemCount; 104 | } 105 | } 106 | 107 | // Restore modified GL state 108 | glUseProgram(last_program); 109 | glBindTexture(GL_TEXTURE_2D, last_texture); 110 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 111 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer); 112 | glBindVertexArray(last_vertex_array); 113 | glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); 114 | glBlendFunc(last_blend_src, last_blend_dst); 115 | if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); 116 | if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); 117 | if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); 118 | if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); 119 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); 120 | } 121 | 122 | static const char* ImGui_ImplGlfwGL3_GetClipboardText() 123 | { 124 | return glfwGetClipboardString(g_Window); 125 | } 126 | 127 | static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text) 128 | { 129 | glfwSetClipboardString(g_Window, text); 130 | } 131 | 132 | void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) 133 | { 134 | if (action == GLFW_PRESS && button >= 0 && button < 3) 135 | g_MousePressed[button] = true; 136 | } 137 | 138 | void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset) 139 | { 140 | g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. 141 | } 142 | 143 | void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow*, int key, int, int action, int mods) 144 | { 145 | ImGuiIO& io = ImGui::GetIO(); 146 | if (action == GLFW_PRESS) 147 | io.KeysDown[key] = true; 148 | if (action == GLFW_RELEASE) 149 | io.KeysDown[key] = false; 150 | 151 | (void)mods; // Modifiers are not reliable across systems 152 | io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; 153 | io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; 154 | io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; 155 | } 156 | 157 | void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow*, unsigned int c) 158 | { 159 | ImGuiIO& io = ImGui::GetIO(); 160 | if (c > 0 && c < 0x10000) 161 | io.AddInputCharacter((unsigned short)c); 162 | } 163 | 164 | void ImGui_ImplGlfwGL3_CreateFontsTexture() 165 | { 166 | ImGuiIO& io = ImGui::GetIO(); 167 | 168 | // Build texture atlas 169 | unsigned char* pixels; 170 | int width, height; 171 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. 172 | 173 | // Create OpenGL texture 174 | glGenTextures(1, &g_FontTexture); 175 | glBindTexture(GL_TEXTURE_2D, g_FontTexture); 176 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 177 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 178 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 179 | 180 | // Store our identifier 181 | io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; 182 | 183 | // Cleanup (don't clear the input data if you want to append new fonts later) 184 | io.Fonts->ClearInputData(); 185 | io.Fonts->ClearTexData(); 186 | } 187 | 188 | bool ImGui_ImplGlfwGL3_CreateDeviceObjects() 189 | { 190 | // Backup GL state 191 | GLint last_texture, last_array_buffer, last_vertex_array; 192 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 193 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 194 | glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 195 | 196 | const GLchar *vertex_shader = 197 | "#version 330\n" 198 | "uniform mat4 ProjMtx;\n" 199 | "in vec2 Position;\n" 200 | "in vec2 UV;\n" 201 | "in vec4 Color;\n" 202 | "out vec2 Frag_UV;\n" 203 | "out vec4 Frag_Color;\n" 204 | "void main()\n" 205 | "{\n" 206 | " Frag_UV = UV;\n" 207 | " Frag_Color = Color;\n" 208 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 209 | "}\n"; 210 | 211 | const GLchar* fragment_shader = 212 | "#version 330\n" 213 | "uniform sampler2D Texture;\n" 214 | "in vec2 Frag_UV;\n" 215 | "in vec4 Frag_Color;\n" 216 | "out vec4 Out_Color;\n" 217 | "void main()\n" 218 | "{\n" 219 | " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" 220 | "}\n"; 221 | 222 | g_ShaderHandle = glCreateProgram(); 223 | g_VertHandle = glCreateShader(GL_VERTEX_SHADER); 224 | g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); 225 | glShaderSource(g_VertHandle, 1, &vertex_shader, 0); 226 | glShaderSource(g_FragHandle, 1, &fragment_shader, 0); 227 | glCompileShader(g_VertHandle); 228 | glCompileShader(g_FragHandle); 229 | glAttachShader(g_ShaderHandle, g_VertHandle); 230 | glAttachShader(g_ShaderHandle, g_FragHandle); 231 | glLinkProgram(g_ShaderHandle); 232 | 233 | g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); 234 | g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); 235 | g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position"); 236 | g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV"); 237 | g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color"); 238 | 239 | glGenBuffers(1, &g_VboHandle); 240 | glGenBuffers(1, &g_ElementsHandle); 241 | 242 | glGenVertexArrays(1, &g_VaoHandle); 243 | glBindVertexArray(g_VaoHandle); 244 | glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); 245 | glEnableVertexAttribArray(g_AttribLocationPosition); 246 | glEnableVertexAttribArray(g_AttribLocationUV); 247 | glEnableVertexAttribArray(g_AttribLocationColor); 248 | 249 | #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) 250 | glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); 251 | glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); 252 | glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); 253 | #undef OFFSETOF 254 | 255 | ImGui_ImplGlfwGL3_CreateFontsTexture(); 256 | 257 | // Restore modified GL state 258 | glBindTexture(GL_TEXTURE_2D, last_texture); 259 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 260 | glBindVertexArray(last_vertex_array); 261 | 262 | return true; 263 | } 264 | 265 | bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) 266 | { 267 | g_Window = window; 268 | 269 | ImGuiIO& io = ImGui::GetIO(); 270 | io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. 271 | io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; 272 | io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; 273 | io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; 274 | io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; 275 | io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; 276 | io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; 277 | io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; 278 | io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; 279 | io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; 280 | io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; 281 | io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; 282 | io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; 283 | io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; 284 | io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; 285 | io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; 286 | io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; 287 | io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; 288 | io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; 289 | 290 | io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. 291 | io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText; 292 | io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText; 293 | #ifdef _WIN32 294 | io.ImeWindowHandle = glfwGetWin32Window(g_Window); 295 | #endif 296 | 297 | if (install_callbacks) 298 | { 299 | glfwSetMouseButtonCallback(window, ImGui_ImplGlfwGL3_MouseButtonCallback); 300 | glfwSetScrollCallback(window, ImGui_ImplGlfwGL3_ScrollCallback); 301 | glfwSetKeyCallback(window, ImGui_ImplGlfwGL3_KeyCallback); 302 | glfwSetCharCallback(window, ImGui_ImplGlfwGL3_CharCallback); 303 | } 304 | 305 | return true; 306 | } 307 | 308 | void ImGui_ImplGlfwGL3_Shutdown() 309 | { 310 | if (g_VaoHandle) glDeleteVertexArrays(1, &g_VaoHandle); 311 | if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle); 312 | if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); 313 | g_VaoHandle = g_VboHandle = g_ElementsHandle = 0; 314 | 315 | glDetachShader(g_ShaderHandle, g_VertHandle); 316 | glDeleteShader(g_VertHandle); 317 | g_VertHandle = 0; 318 | 319 | glDetachShader(g_ShaderHandle, g_FragHandle); 320 | glDeleteShader(g_FragHandle); 321 | g_FragHandle = 0; 322 | 323 | glDeleteProgram(g_ShaderHandle); 324 | g_ShaderHandle = 0; 325 | 326 | if (g_FontTexture) 327 | { 328 | glDeleteTextures(1, &g_FontTexture); 329 | ImGui::GetIO().Fonts->TexID = 0; 330 | g_FontTexture = 0; 331 | } 332 | ImGui::Shutdown(); 333 | } 334 | 335 | void ImGui_ImplGlfwGL3_NewFrame() 336 | { 337 | if (!g_FontTexture) 338 | ImGui_ImplGlfwGL3_CreateDeviceObjects(); 339 | 340 | ImGuiIO& io = ImGui::GetIO(); 341 | 342 | // Setup display size (every frame to accommodate for window resizing) 343 | int w, h; 344 | int display_w, display_h; 345 | glfwGetWindowSize(g_Window, &w, &h); 346 | glfwGetFramebufferSize(g_Window, &display_w, &display_h); 347 | io.DisplaySize = ImVec2((float)w, (float)h); 348 | io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); 349 | 350 | // Setup time step 351 | double current_time = glfwGetTime(); 352 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); 353 | g_Time = current_time; 354 | 355 | // Setup inputs 356 | // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) 357 | if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED)) 358 | { 359 | double mouse_x, mouse_y; 360 | glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); 361 | io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.) 362 | } 363 | else 364 | { 365 | io.MousePos = ImVec2(-1,-1); 366 | } 367 | 368 | for (int i = 0; i < 3; i++) 369 | { 370 | io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. 371 | g_MousePressed[i] = false; 372 | } 373 | 374 | io.MouseWheel = g_MouseWheel; 375 | g_MouseWheel = 0.0f; 376 | 377 | // Hide OS mouse cursor if ImGui is drawing it 378 | glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); 379 | 380 | // Start the frame 381 | ImGui::NewFrame(); 382 | } 383 | -------------------------------------------------------------------------------- /test/External/imgui/imgui_impl_glfw_gl3.h: -------------------------------------------------------------------------------- 1 | // ImGui GLFW binding with OpenGL3 + shaders 2 | // You can copy and use unmodified imgui_impl_* files in your project. 3 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). 4 | // See main.cpp for an example of using this. 5 | // https://github.com/ocornut/imgui 6 | 7 | struct GLFWwindow; 8 | 9 | IMGUI_API bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks); 10 | IMGUI_API void ImGui_ImplGlfwGL3_Shutdown(); 11 | IMGUI_API void ImGui_ImplGlfwGL3_NewFrame(); 12 | 13 | // Use if you want to reset your rendering device without losing ImGui state. 14 | IMGUI_API void ImGui_ImplGlfwGL3_InvalidateDeviceObjects(); 15 | IMGUI_API bool ImGui_ImplGlfwGL3_CreateDeviceObjects(); 16 | 17 | // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) 18 | // Provided here if you want to chain callbacks. 19 | // You can also handle inputs yourself and use those as a reference. 20 | IMGUI_API void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); 21 | IMGUI_API void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); 22 | IMGUI_API void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); 23 | IMGUI_API void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c); 24 | -------------------------------------------------------------------------------- /test/External/imgui/imgui_internal.h: -------------------------------------------------------------------------------- 1 | // ImGui library v1.47 WIP 2 | // Internals 3 | // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! 4 | 5 | // Implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) 6 | // #define IMGUI_DEFINE_MATH_OPERATORS 7 | 8 | #pragma once 9 | 10 | #ifndef IMGUI_VERSION 11 | #error Must include imgui.h before imgui_internal.h 12 | #endif 13 | 14 | #include // FILE* 15 | #include // sqrtf() 16 | 17 | #ifdef _MSC_VER 18 | #pragma warning (push) 19 | #pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) 20 | #endif 21 | 22 | //----------------------------------------------------------------------------- 23 | // Forward Declarations 24 | //----------------------------------------------------------------------------- 25 | 26 | struct ImRect; 27 | struct ImGuiColMod; 28 | struct ImGuiStyleMod; 29 | struct ImGuiGroupData; 30 | struct ImGuiSimpleColumns; 31 | struct ImGuiDrawContext; 32 | struct ImGuiTextEditState; 33 | struct ImGuiIniData; 34 | struct ImGuiMouseCursorData; 35 | struct ImGuiPopupRef; 36 | struct ImGuiState; 37 | struct ImGuiWindow; 38 | 39 | typedef int ImGuiLayoutType; // enum ImGuiLayoutType_ 40 | typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_ 41 | typedef int ImGuiTreeNodeFlags; // enum ImGuiTreeNodeFlags_ 42 | typedef int ImGuiSliderFlags; // enum ImGuiSliderFlags_ 43 | 44 | //------------------------------------------------------------------------- 45 | // STB libraries 46 | //------------------------------------------------------------------------- 47 | 48 | namespace ImGuiStb 49 | { 50 | 51 | #ifdef __clang__ 52 | #pragma clang diagnostic push 53 | #pragma clang diagnostic ignored "-Wunused-function" 54 | #pragma clang diagnostic ignored "-Wmissing-prototypes" 55 | #endif 56 | 57 | #undef STB_TEXTEDIT_STRING 58 | #undef STB_TEXTEDIT_CHARTYPE 59 | #define STB_TEXTEDIT_STRING ImGuiTextEditState 60 | #define STB_TEXTEDIT_CHARTYPE ImWchar 61 | #define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f 62 | #include "stb_textedit.h" 63 | 64 | #ifdef __clang__ 65 | #pragma clang diagnostic pop 66 | #endif 67 | 68 | } // namespace ImGuiStb 69 | 70 | //----------------------------------------------------------------------------- 71 | // Context 72 | //----------------------------------------------------------------------------- 73 | 74 | extern IMGUI_API ImGuiState* GImGui; 75 | 76 | //----------------------------------------------------------------------------- 77 | // Helpers 78 | //----------------------------------------------------------------------------- 79 | 80 | #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) 81 | #define IM_PI 3.14159265358979323846f 82 | 83 | // Helpers: UTF-8 <> wchar 84 | IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count 85 | IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count 86 | IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count 87 | IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) 88 | IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points 89 | 90 | // Helpers: Misc 91 | IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings 92 | IMGUI_API void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0); 93 | IMGUI_API bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c); 94 | static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; } 95 | static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } 96 | 97 | // Helpers: String 98 | IMGUI_API int ImStricmp(const char* str1, const char* str2); 99 | IMGUI_API int ImStrnicmp(const char* str1, const char* str2, int count); 100 | IMGUI_API char* ImStrdup(const char* str); 101 | IMGUI_API int ImStrlenW(const ImWchar* str); 102 | IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line 103 | IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); 104 | IMGUI_API int ImFormatString(char* buf, int buf_size, const char* fmt, ...) IM_PRINTFARGS(3); 105 | IMGUI_API int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args); 106 | 107 | // Helpers: Math 108 | // We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined) 109 | #ifdef IMGUI_DEFINE_MATH_OPERATORS 110 | static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } 111 | static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); } 112 | static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y); } 113 | static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y); } 114 | static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); } 115 | static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x/rhs.x, lhs.y/rhs.y); } 116 | static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } 117 | static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } 118 | static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } 119 | static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } 120 | static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-lhs.w); } 121 | #endif 122 | 123 | static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; } 124 | static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; } 125 | static inline float ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; } 126 | static inline float ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; } 127 | static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(ImMin(lhs.x,rhs.x), ImMin(lhs.y,rhs.y)); } 128 | static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(ImMax(lhs.x,rhs.x), ImMax(lhs.y,rhs.y)); } 129 | static inline int ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } 130 | static inline float ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } 131 | static inline ImVec2 ImClamp(const ImVec2& f, const ImVec2& mn, ImVec2 mx) { return ImVec2(ImClamp(f.x,mn.x,mx.x), ImClamp(f.y,mn.y,mx.y)); } 132 | static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } 133 | static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; } 134 | static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } 135 | static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } 136 | static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } 137 | static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; } 138 | static inline ImVec2 ImRound(ImVec2 v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } 139 | 140 | //----------------------------------------------------------------------------- 141 | // Types 142 | //----------------------------------------------------------------------------- 143 | 144 | enum ImGuiButtonFlags_ 145 | { 146 | ImGuiButtonFlags_Repeat = 1 << 0, 147 | ImGuiButtonFlags_PressedOnClick = 1 << 1, // return pressed on click only (default requires click+release) 148 | ImGuiButtonFlags_PressedOnRelease = 1 << 2, // return pressed on release only (default requires click+release) 149 | ImGuiButtonFlags_FlattenChilds = 1 << 3, 150 | ImGuiButtonFlags_DontClosePopups = 1 << 4, 151 | ImGuiButtonFlags_Disabled = 1 << 5, 152 | ImGuiButtonFlags_AlignTextBaseLine = 1 << 6, 153 | ImGuiButtonFlags_NoKeyModifiers = 1 << 7 154 | }; 155 | 156 | enum ImGuiTreeNodeFlags_ 157 | { 158 | ImGuiTreeNodeFlags_DefaultOpen = 1 << 0, 159 | ImGuiTreeNodeFlags_NoAutoExpandOnLog = 1 << 1 160 | }; 161 | 162 | enum ImGuiSliderFlags_ 163 | { 164 | ImGuiSliderFlags_Vertical = 1 << 0, 165 | }; 166 | 167 | enum ImGuiSelectableFlagsPrivate_ 168 | { 169 | // NB: need to be in sync with last value of ImGuiSelectableFlags_ 170 | ImGuiSelectableFlags_Menu = 1 << 2, 171 | ImGuiSelectableFlags_MenuItem = 1 << 3, 172 | ImGuiSelectableFlags_Disabled = 1 << 4, 173 | ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 5 174 | }; 175 | 176 | // FIXME: this is in development, not exposed/functional as a generic feature yet. 177 | enum ImGuiLayoutType_ 178 | { 179 | ImGuiLayoutType_Vertical, 180 | ImGuiLayoutType_Horizontal 181 | }; 182 | 183 | enum ImGuiPlotType 184 | { 185 | ImGuiPlotType_Lines, 186 | ImGuiPlotType_Histogram 187 | }; 188 | 189 | enum ImGuiDataType 190 | { 191 | ImGuiDataType_Int, 192 | ImGuiDataType_Float 193 | }; 194 | 195 | // 2D axis aligned bounding-box 196 | // NB: we can't rely on ImVec2 math operators being available here 197 | struct IMGUI_API ImRect 198 | { 199 | ImVec2 Min; // Upper-left 200 | ImVec2 Max; // Lower-right 201 | 202 | ImRect() : Min(FLT_MAX,FLT_MAX), Max(-FLT_MAX,-FLT_MAX) {} 203 | ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} 204 | ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} 205 | ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} 206 | 207 | ImVec2 GetCenter() const { return ImVec2((Min.x+Max.x)*0.5f, (Min.y+Max.y)*0.5f); } 208 | ImVec2 GetSize() const { return ImVec2(Max.x-Min.x, Max.y-Min.y); } 209 | float GetWidth() const { return Max.x-Min.x; } 210 | float GetHeight() const { return Max.y-Min.y; } 211 | ImVec2 GetTL() const { return Min; } 212 | ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } 213 | ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } 214 | ImVec2 GetBR() const { return Max; } 215 | bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } 216 | bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y; } 217 | bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } 218 | void Add(const ImVec2& rhs) { if (Min.x > rhs.x) Min.x = rhs.x; if (Min.y > rhs.y) Min.y = rhs.y; if (Max.x < rhs.x) Max.x = rhs.x; if (Max.y < rhs.y) Max.y = rhs.y; } 219 | void Add(const ImRect& rhs) { if (Min.x > rhs.Min.x) Min.x = rhs.Min.x; if (Min.y > rhs.Min.y) Min.y = rhs.Min.y; if (Max.x < rhs.Max.x) Max.x = rhs.Max.x; if (Max.y < rhs.Max.y) Max.y = rhs.Max.y; } 220 | void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } 221 | void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } 222 | void Reduce(const ImVec2& amount) { Min.x += amount.x; Min.y += amount.y; Max.x -= amount.x; Max.y -= amount.y; } 223 | void Clip(const ImRect& clip) { if (Min.x < clip.Min.x) Min.x = clip.Min.x; if (Min.y < clip.Min.y) Min.y = clip.Min.y; if (Max.x > clip.Max.x) Max.x = clip.Max.x; if (Max.y > clip.Max.y) Max.y = clip.Max.y; } 224 | void Round() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } 225 | ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const 226 | { 227 | if (!on_edge && Contains(p)) 228 | return p; 229 | if (p.x > Max.x) p.x = Max.x; 230 | else if (p.x < Min.x) p.x = Min.x; 231 | if (p.y > Max.y) p.y = Max.y; 232 | else if (p.y < Min.y) p.y = Min.y; 233 | return p; 234 | } 235 | }; 236 | 237 | // Stacked color modifier, backup of modified data so we can restore it 238 | struct ImGuiColMod 239 | { 240 | ImGuiCol Col; 241 | ImVec4 PreviousValue; 242 | }; 243 | 244 | // Stacked style modifier, backup of modified data so we can restore it 245 | struct ImGuiStyleMod 246 | { 247 | ImGuiStyleVar Var; 248 | ImVec2 PreviousValue; 249 | }; 250 | 251 | // Stacked data for BeginGroup()/EndGroup() 252 | struct ImGuiGroupData 253 | { 254 | ImVec2 BackupCursorPos; 255 | ImVec2 BackupCursorMaxPos; 256 | float BackupColumnsStartX; 257 | float BackupCurrentLineHeight; 258 | float BackupCurrentLineTextBaseOffset; 259 | float BackupLogLinePosY; 260 | bool AdvanceCursor; 261 | }; 262 | 263 | // Simple column measurement currently used for MenuItem() only. This is very short-sighted for now and not a generic helper. 264 | struct IMGUI_API ImGuiSimpleColumns 265 | { 266 | int Count; 267 | float Spacing; 268 | float Width, NextWidth; 269 | float Pos[8], NextWidths[8]; 270 | 271 | ImGuiSimpleColumns(); 272 | void Update(int count, float spacing, bool clear); 273 | float DeclColumns(float w0, float w1, float w2); 274 | float CalcExtraSpace(float avail_w); 275 | }; 276 | 277 | // Internal state of the currently focused/edited text input box 278 | struct IMGUI_API ImGuiTextEditState 279 | { 280 | ImGuiID Id; // widget id owning the text state 281 | ImVector Text; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. 282 | ImVector InitialText; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) 283 | ImVector TempTextBuffer; 284 | int CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format. 285 | int BufSizeA; // end-user buffer size 286 | float ScrollX; 287 | ImGuiStb::STB_TexteditState StbState; 288 | float CursorAnim; 289 | bool CursorFollow; 290 | ImVec2 InputCursorScreenPos; // Cursor position in screen space to be used by IME callback. 291 | bool SelectedAllMouseLock; 292 | 293 | ImGuiTextEditState() { memset(this, 0, sizeof(*this)); } 294 | void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking 295 | void CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); } 296 | bool HasSelection() const { return StbState.select_start != StbState.select_end; } 297 | void ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; } 298 | void SelectAll() { StbState.select_start = 0; StbState.select_end = CurLenW; StbState.cursor = StbState.select_end; StbState.has_preferred_x = false; } 299 | void OnKeyPressed(int key); 300 | }; 301 | 302 | // Data saved in imgui.ini file 303 | struct ImGuiIniData 304 | { 305 | char* Name; 306 | ImGuiID ID; 307 | ImVec2 Pos; 308 | ImVec2 Size; 309 | bool Collapsed; 310 | }; 311 | 312 | // Mouse cursor data (used when io.MouseDrawCursor is set) 313 | struct ImGuiMouseCursorData 314 | { 315 | ImGuiMouseCursor Type; 316 | ImVec2 HotOffset; 317 | ImVec2 Size; 318 | ImVec2 TexUvMin[2]; 319 | ImVec2 TexUvMax[2]; 320 | }; 321 | 322 | // Storage for current popup stack 323 | struct ImGuiPopupRef 324 | { 325 | ImGuiID PopupID; // Set on OpenPopup() 326 | ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() 327 | ImGuiWindow* ParentWindow; // Set on OpenPopup() 328 | ImGuiID ParentMenuSet; // Set on OpenPopup() 329 | ImVec2 MousePosOnOpen; // Copy of mouse position at the time of opening popup 330 | 331 | ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupID = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; } 332 | }; 333 | 334 | // Main state for ImGui 335 | struct ImGuiState 336 | { 337 | bool Initialized; 338 | ImGuiIO IO; 339 | ImGuiStyle Style; 340 | ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() 341 | float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize() 342 | float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Size of characters. 343 | ImVec2 FontTexUvWhitePixel; // (Shortcut) == Font->TexUvForWhite 344 | 345 | float Time; 346 | int FrameCount; 347 | int FrameCountEnded; 348 | int FrameCountRendered; 349 | ImVector Windows; 350 | ImVector WindowsSortBuffer; 351 | ImGuiWindow* CurrentWindow; // Being drawn into 352 | ImVector CurrentWindowStack; 353 | ImGuiWindow* FocusedWindow; // Will catch keyboard inputs 354 | ImGuiWindow* HoveredWindow; // Will catch mouse inputs 355 | ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) 356 | ImGuiID HoveredId; // Hovered widget 357 | bool HoveredIdAllowHoveringOthers; 358 | ImGuiID HoveredIdPreviousFrame; 359 | ImGuiID ActiveId; // Active widget 360 | ImGuiID ActiveIdPreviousFrame; 361 | bool ActiveIdIsAlive; 362 | bool ActiveIdIsJustActivated; // Set at the time of activation for one frame 363 | bool ActiveIdAllowHoveringOthers; // Set only by active widget 364 | ImGuiWindow* ActiveIdWindow; 365 | ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Pointer is only valid if ActiveID is the "#MOVE" identifier of a window. 366 | ImVector Settings; // .ini Settings 367 | float SettingsDirtyTimer; // Save .ini settinngs on disk when time reaches zero 368 | int DisableHideTextAfterDoubleHash; 369 | ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() 370 | ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() 371 | ImVector FontStack; // Stack for PushFont()/PopFont() 372 | ImVector OpenedPopupStack; // Which popups are open (persistent) 373 | ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) 374 | 375 | // Storage for SetNexWindow** and SetNextTreeNode*** functions 376 | ImVec2 SetNextWindowPosVal; 377 | ImVec2 SetNextWindowSizeVal; 378 | ImVec2 SetNextWindowContentSizeVal; 379 | bool SetNextWindowCollapsedVal; 380 | ImGuiSetCond SetNextWindowPosCond; 381 | ImGuiSetCond SetNextWindowSizeCond; 382 | ImGuiSetCond SetNextWindowContentSizeCond; 383 | ImGuiSetCond SetNextWindowCollapsedCond; 384 | bool SetNextWindowFocus; 385 | bool SetNextTreeNodeOpenedVal; 386 | ImGuiSetCond SetNextTreeNodeOpenedCond; 387 | 388 | // Render 389 | ImDrawData RenderDrawData; // Main ImDrawData instance to pass render information to the user 390 | ImVector RenderDrawLists[3]; 391 | float ModalWindowDarkeningRatio; 392 | ImDrawList OverlayDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays 393 | ImGuiMouseCursor MouseCursor; 394 | ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_]; 395 | 396 | // Widget state 397 | ImGuiTextEditState InputTextState; 398 | ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. 399 | ImGuiStorage ColorEditModeStorage; // Store user selection of color edit mode 400 | ImVec2 ActiveClickDeltaToCenter; 401 | float DragCurrentValue; // Currently dragged value, always float, not rounded by end-user precision settings 402 | ImVec2 DragLastMouseDelta; 403 | float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio 404 | float DragSpeedScaleSlow; 405 | float DragSpeedScaleFast; 406 | ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? 407 | char Tooltip[1024]; 408 | char* PrivateClipboard; // If no custom clipboard handler is defined 409 | 410 | // Logging 411 | bool LogEnabled; 412 | FILE* LogFile; // If != NULL log to stdout/ file 413 | ImGuiTextBuffer* LogClipboard; // Else log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. 414 | int LogStartDepth; 415 | int LogAutoExpandMaxDepth; 416 | 417 | // Misc 418 | float FramerateSecPerFrame[120]; // calculate estimate of framerate for user 419 | int FramerateSecPerFrameIdx; 420 | float FramerateSecPerFrameAccum; 421 | bool CaptureMouseNextFrame; // explicit capture via CaptureInputs() sets those flags 422 | bool CaptureKeyboardNextFrame; 423 | char TempBuffer[1024*3+1]; // temporary text buffer 424 | 425 | ImGuiState() 426 | { 427 | Initialized = false; 428 | Font = NULL; 429 | FontSize = FontBaseSize = 0.0f; 430 | FontTexUvWhitePixel = ImVec2(0.0f, 0.0f); 431 | 432 | Time = 0.0f; 433 | FrameCount = 0; 434 | FrameCountEnded = FrameCountRendered = -1; 435 | CurrentWindow = NULL; 436 | FocusedWindow = NULL; 437 | HoveredWindow = NULL; 438 | HoveredRootWindow = NULL; 439 | HoveredId = 0; 440 | HoveredIdAllowHoveringOthers = false; 441 | HoveredIdPreviousFrame = 0; 442 | ActiveId = 0; 443 | ActiveIdPreviousFrame = 0; 444 | ActiveIdIsAlive = false; 445 | ActiveIdIsJustActivated = false; 446 | ActiveIdAllowHoveringOthers = false; 447 | ActiveIdWindow = NULL; 448 | MovedWindow = NULL; 449 | SettingsDirtyTimer = 0.0f; 450 | DisableHideTextAfterDoubleHash = 0; 451 | 452 | SetNextWindowPosVal = ImVec2(0.0f, 0.0f); 453 | SetNextWindowSizeVal = ImVec2(0.0f, 0.0f); 454 | SetNextWindowCollapsedVal = false; 455 | SetNextWindowPosCond = 0; 456 | SetNextWindowSizeCond = 0; 457 | SetNextWindowCollapsedCond = 0; 458 | SetNextWindowFocus = false; 459 | SetNextTreeNodeOpenedVal = false; 460 | SetNextTreeNodeOpenedCond = 0; 461 | 462 | ScalarAsInputTextId = 0; 463 | ActiveClickDeltaToCenter = ImVec2(0.0f, 0.0f); 464 | DragCurrentValue = 0.0f; 465 | DragLastMouseDelta = ImVec2(0.0f, 0.0f); 466 | DragSpeedDefaultRatio = 0.01f; 467 | DragSpeedScaleSlow = 0.01f; 468 | DragSpeedScaleFast = 10.0f; 469 | ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); 470 | memset(Tooltip, 0, sizeof(Tooltip)); 471 | PrivateClipboard = NULL; 472 | 473 | ModalWindowDarkeningRatio = 0.0f; 474 | OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging 475 | MouseCursor = ImGuiMouseCursor_Arrow; 476 | 477 | LogEnabled = false; 478 | LogFile = NULL; 479 | LogClipboard = NULL; 480 | LogStartDepth = 0; 481 | LogAutoExpandMaxDepth = 2; 482 | 483 | memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); 484 | FramerateSecPerFrameIdx = 0; 485 | FramerateSecPerFrameAccum = 0.0f; 486 | CaptureMouseNextFrame = CaptureKeyboardNextFrame = false; 487 | } 488 | }; 489 | 490 | // Transient per-window data, reset at the beginning of the frame 491 | // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiDrawContext is quite tenuous and could be reconsidered. 492 | struct IMGUI_API ImGuiDrawContext 493 | { 494 | ImVec2 CursorPos; 495 | ImVec2 CursorPosPrevLine; 496 | ImVec2 CursorStartPos; 497 | ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame 498 | float CurrentLineHeight; 499 | float CurrentLineTextBaseOffset; 500 | float PrevLineHeight; 501 | float PrevLineTextBaseOffset; 502 | float LogLinePosY; 503 | int TreeDepth; 504 | ImGuiID LastItemID; 505 | ImRect LastItemRect; 506 | bool LastItemHoveredAndUsable; 507 | bool LastItemHoveredRect; 508 | bool MenuBarAppending; 509 | float MenuBarOffsetX; 510 | ImVector ChildWindows; 511 | ImGuiStorage* StateStorage; 512 | ImGuiLayoutType LayoutType; 513 | 514 | // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. 515 | float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window 516 | float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] 517 | bool AllowKeyboardFocus; // == AllowKeyboardFocusStack.back() [empty == true] 518 | bool ButtonRepeat; // == ButtonRepeatStack.back() [empty == false] 519 | ImVector ItemWidthStack; 520 | ImVector TextWrapPosStack; 521 | ImVector AllowKeyboardFocusStack; 522 | ImVector ButtonRepeatStack; 523 | ImVectorGroupStack; 524 | ImGuiColorEditMode ColorEditMode; 525 | int StackSizesBackup[6]; // Store size of various stacks for asserting 526 | 527 | float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) 528 | float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. 529 | int ColumnsCurrent; 530 | int ColumnsCount; 531 | ImVec2 ColumnsStartPos; 532 | float ColumnsCellMinY; 533 | float ColumnsCellMaxY; 534 | bool ColumnsShowBorders; 535 | ImGuiID ColumnsSetID; 536 | ImVector ColumnsOffsetsT; // Columns offset normalized 0.0 (far left) -> 1.0 (far right) 537 | 538 | ImGuiDrawContext() 539 | { 540 | CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); 541 | CurrentLineHeight = PrevLineHeight = 0.0f; 542 | CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; 543 | LogLinePosY = -1.0f; 544 | TreeDepth = 0; 545 | LastItemID = 0; 546 | LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f); 547 | LastItemHoveredAndUsable = LastItemHoveredRect = false; 548 | MenuBarAppending = false; 549 | MenuBarOffsetX = 0.0f; 550 | StateStorage = NULL; 551 | LayoutType = ImGuiLayoutType_Vertical; 552 | ItemWidth = 0.0f; 553 | ButtonRepeat = false; 554 | AllowKeyboardFocus = true; 555 | TextWrapPos = -1.0f; 556 | ColorEditMode = ImGuiColorEditMode_RGB; 557 | memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); 558 | 559 | ColumnsStartX = 0.0f; 560 | ColumnsOffsetX = 0.0f; 561 | ColumnsCurrent = 0; 562 | ColumnsCount = 1; 563 | ColumnsStartPos = ImVec2(0.0f, 0.0f); 564 | ColumnsCellMinY = ColumnsCellMaxY = 0.0f; 565 | ColumnsShowBorders = true; 566 | ColumnsSetID = 0; 567 | } 568 | }; 569 | 570 | // Windows data 571 | struct IMGUI_API ImGuiWindow 572 | { 573 | char* Name; 574 | ImGuiID ID; 575 | ImGuiWindowFlags Flags; 576 | ImVec2 PosFloat; 577 | ImVec2 Pos; // Position rounded-up to nearest pixel 578 | ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) 579 | ImVec2 SizeFull; // Size when non collapsed 580 | ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame 581 | ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize() 582 | ImVec2 WindowPadding; // Window padding at the time of begin. We need to lock it, in particular manipulation of the ShowBorder would have an effect 583 | ImGuiID MoveID; // == window->GetID("#MOVE") 584 | ImVec2 Scroll; 585 | ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) 586 | ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered 587 | bool ScrollbarX, ScrollbarY; 588 | ImVec2 ScrollbarSizes; // 589 | bool Active; // Set to true on Begin() 590 | bool WasActive; 591 | bool Accessed; // Set to true when any widget access the current window 592 | bool Collapsed; // Set when collapsing window to become only title-bar 593 | bool SkipItems; // == Visible && !Collapsed 594 | int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) 595 | ImGuiID PopupID; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) 596 | int AutoFitFramesX, AutoFitFramesY; 597 | bool AutoFitOnlyGrows; 598 | int AutoPosLastDirection; 599 | int HiddenFrames; 600 | int SetWindowPosAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowPos() call will succeed with this particular flag. 601 | int SetWindowSizeAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowSize() call will succeed with this particular flag. 602 | int SetWindowCollapsedAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowCollapsed() call will succeed with this particular flag. 603 | bool SetWindowPosCenterWanted; 604 | 605 | ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame 606 | ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack 607 | ImRect ClipRect; // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. 608 | ImRect ClippedWindowRect; // = ClipRect just after setup in Begin() 609 | int LastFrameActive; 610 | float ItemWidthDefault; 611 | ImGuiSimpleColumns MenuColumns; // Simplified columns storage for menu items 612 | ImGuiStorage StateStorage; 613 | float FontWindowScale; // Scale multiplier per-window 614 | ImDrawList* DrawList; 615 | ImGuiWindow* RootWindow; 616 | ImGuiWindow* RootNonPopupWindow; 617 | 618 | // Focus 619 | int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() 620 | int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through) 621 | int FocusIdxAllRequestCurrent; // Item being requested for focus 622 | int FocusIdxTabRequestCurrent; // Tab-able item being requested for focus 623 | int FocusIdxAllRequestNext; // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame) 624 | int FocusIdxTabRequestNext; // " 625 | 626 | public: 627 | ImGuiWindow(const char* name); 628 | ~ImGuiWindow(); 629 | 630 | ImGuiID GetID(const char* str, const char* str_end = NULL); 631 | ImGuiID GetID(const void* ptr); 632 | 633 | ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } 634 | float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } 635 | float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } 636 | ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } 637 | float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } 638 | ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } 639 | ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); } 640 | ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } 641 | }; 642 | 643 | //----------------------------------------------------------------------------- 644 | // Internal API 645 | // No guarantee of forward compatibility here. 646 | //----------------------------------------------------------------------------- 647 | 648 | namespace ImGui 649 | { 650 | // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) 651 | // If this ever crash because g.CurrentWindow is NULL it means that either 652 | // - ImGui::NewFrame() has never been called, which is illegal. 653 | // - You are calling ImGui functions after ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. 654 | inline ImGuiWindow* GetCurrentWindowRead() { ImGuiState& g = *GImGui; return g.CurrentWindow; } 655 | inline ImGuiWindow* GetCurrentWindow() { ImGuiState& g = *GImGui; g.CurrentWindow->Accessed = true; return g.CurrentWindow; } 656 | IMGUI_API ImGuiWindow* GetParentWindow(); 657 | IMGUI_API void FocusWindow(ImGuiWindow* window); 658 | 659 | IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); 660 | IMGUI_API void SetHoveredID(ImGuiID id); 661 | IMGUI_API void KeepAliveID(ImGuiID id); 662 | 663 | IMGUI_API void EndFrame(); // This automatically called by Render() 664 | 665 | IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); 666 | IMGUI_API void ItemSize(const ImRect& bb, float text_offset_y = 0.0f); 667 | IMGUI_API bool ItemAdd(const ImRect& bb, const ImGuiID* id); 668 | IMGUI_API bool IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when_logged); 669 | IMGUI_API bool IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs = false); 670 | IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, bool is_active, bool tab_stop = true); // Return true if focus is requested 671 | IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); 672 | IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); 673 | IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); 674 | 675 | // NB: All position are in absolute pixels coordinates (not window coordinates) 676 | IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); 677 | IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); 678 | IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); 679 | IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); 680 | IMGUI_API void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); 681 | IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); 682 | 683 | IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); 684 | IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); 685 | 686 | IMGUI_API bool SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags = 0); 687 | IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power); 688 | IMGUI_API bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* display_format); 689 | 690 | IMGUI_API bool DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power); 691 | IMGUI_API bool DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* display_format, float power); 692 | IMGUI_API bool DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* display_format); 693 | 694 | IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); 695 | IMGUI_API bool InputFloatN(const char* label, float* v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags); 696 | IMGUI_API bool InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags); 697 | IMGUI_API bool InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags); 698 | IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision); 699 | 700 | IMGUI_API bool TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging 701 | 702 | IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size); 703 | 704 | IMGUI_API int ParseFormatPrecision(const char* fmt, int default_value); 705 | IMGUI_API float RoundScalar(float value, int decimal_precision); 706 | 707 | } // namespace ImGuiP 708 | 709 | #ifdef _MSC_VER 710 | #pragma warning (pop) 711 | #endif 712 | -------------------------------------------------------------------------------- /test/External/imgui/stb_rect_pack.h: -------------------------------------------------------------------------------- 1 | // stb_rect_pack.h - v0.05 - public domain - rectangle packing 2 | // Sean Barrett 2014 3 | // 4 | // Useful for e.g. packing rectangular textures into an atlas. 5 | // Does not do rotation. 6 | // 7 | // Not necessarily the awesomest packing method, but better than 8 | // the totally naive one in stb_truetype (which is primarily what 9 | // this is meant to replace). 10 | // 11 | // Has only had a few tests run, may have issues. 12 | // 13 | // More docs to come. 14 | // 15 | // No memory allocations; uses qsort() and assert() from stdlib. 16 | // 17 | // This library currently uses the Skyline Bottom-Left algorithm. 18 | // 19 | // Please note: better rectangle packers are welcome! Please 20 | // implement them to the same API, but with a different init 21 | // function. 22 | // 23 | // Version history: 24 | // 25 | // 0.05: added STBRP_ASSERT to allow replacing assert 26 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 27 | // 0.01: initial release 28 | 29 | ////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // INCLUDE SECTION 32 | // 33 | 34 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 35 | #define STB_INCLUDE_STB_RECT_PACK_H 36 | 37 | #define STB_RECT_PACK_VERSION 1 38 | 39 | #ifdef STBRP_STATIC 40 | #define STBRP_DEF static 41 | #else 42 | #define STBRP_DEF extern 43 | #endif 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | typedef struct stbrp_context stbrp_context; 50 | typedef struct stbrp_node stbrp_node; 51 | typedef struct stbrp_rect stbrp_rect; 52 | 53 | #ifdef STBRP_LARGE_RECTS 54 | typedef int stbrp_coord; 55 | #else 56 | typedef unsigned short stbrp_coord; 57 | #endif 58 | 59 | STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 60 | // Assign packed locations to rectangles. The rectangles are of type 61 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 62 | // are 'num_rects' many of them. 63 | // 64 | // Rectangles which are successfully packed have the 'was_packed' flag 65 | // set to a non-zero value and 'x' and 'y' store the minimum location 66 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 67 | // if you imagine y increasing downwards). Rectangles which do not fit 68 | // have the 'was_packed' flag set to 0. 69 | // 70 | // You should not try to access the 'rects' array from another thread 71 | // while this function is running, as the function temporarily reorders 72 | // the array while it executes. 73 | // 74 | // To pack into another rectangle, you need to call stbrp_init_target 75 | // again. To continue packing into the same rectangle, you can call 76 | // this function again. Calling this multiple times with multiple rect 77 | // arrays will probably produce worse packing results than calling it 78 | // a single time with the full rectangle array, but the option is 79 | // available. 80 | 81 | struct stbrp_rect 82 | { 83 | // reserved for your use: 84 | int id; 85 | 86 | // input: 87 | stbrp_coord w, h; 88 | 89 | // output: 90 | stbrp_coord x, y; 91 | int was_packed; // non-zero if valid packing 92 | 93 | }; // 16 bytes, nominally 94 | 95 | 96 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 97 | // Initialize a rectangle packer to: 98 | // pack a rectangle that is 'width' by 'height' in dimensions 99 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 100 | // 101 | // You must call this function every time you start packing into a new target. 102 | // 103 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 104 | // the following stbrp_pack_rects() call (or calls), but can be freed after 105 | // the call (or calls) finish. 106 | // 107 | // Note: to guarantee best results, either: 108 | // 1. make sure 'num_nodes' >= 'width' 109 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 110 | // 111 | // If you don't do either of the above things, widths will be quantized to multiples 112 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 113 | // 114 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 115 | // may run out of temporary storage and be unable to pack some rectangles. 116 | 117 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 118 | // Optionally call this function after init but before doing any packing to 119 | // change the handling of the out-of-temp-memory scenario, described above. 120 | // If you call init again, this will be reset to the default (false). 121 | 122 | 123 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 124 | // Optionally select which packing heuristic the library should use. Different 125 | // heuristics will produce better/worse results for different data sets. 126 | // If you call init again, this will be reset to the default. 127 | 128 | enum 129 | { 130 | STBRP_HEURISTIC_Skyline_default=0, 131 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 132 | STBRP_HEURISTIC_Skyline_BF_sortHeight 133 | }; 134 | 135 | 136 | ////////////////////////////////////////////////////////////////////////////// 137 | // 138 | // the details of the following structures don't matter to you, but they must 139 | // be visible so you can handle the memory allocations for them 140 | 141 | struct stbrp_node 142 | { 143 | stbrp_coord x,y; 144 | stbrp_node *next; 145 | }; 146 | 147 | struct stbrp_context 148 | { 149 | int width; 150 | int height; 151 | int align; 152 | int init_mode; 153 | int heuristic; 154 | int num_nodes; 155 | stbrp_node *active_head; 156 | stbrp_node *free_head; 157 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 158 | }; 159 | 160 | #ifdef __cplusplus 161 | } 162 | #endif 163 | 164 | #endif 165 | 166 | ////////////////////////////////////////////////////////////////////////////// 167 | // 168 | // IMPLEMENTATION SECTION 169 | // 170 | 171 | #ifdef STB_RECT_PACK_IMPLEMENTATION 172 | #include 173 | 174 | #ifndef STBRP_ASSERT 175 | #include 176 | #define STBRP_ASSERT assert 177 | #endif 178 | 179 | enum 180 | { 181 | STBRP__INIT_skyline = 1 182 | }; 183 | 184 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 185 | { 186 | switch (context->init_mode) { 187 | case STBRP__INIT_skyline: 188 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 189 | context->heuristic = heuristic; 190 | break; 191 | default: 192 | STBRP_ASSERT(0); 193 | } 194 | } 195 | 196 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 197 | { 198 | if (allow_out_of_mem) 199 | // if it's ok to run out of memory, then don't bother aligning them; 200 | // this gives better packing, but may fail due to OOM (even though 201 | // the rectangles easily fit). @TODO a smarter approach would be to only 202 | // quantize once we've hit OOM, then we could get rid of this parameter. 203 | context->align = 1; 204 | else { 205 | // if it's not ok to run out of memory, then quantize the widths 206 | // so that num_nodes is always enough nodes. 207 | // 208 | // I.e. num_nodes * align >= width 209 | // align >= width / num_nodes 210 | // align = ceil(width/num_nodes) 211 | 212 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 213 | } 214 | } 215 | 216 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 217 | { 218 | int i; 219 | #ifndef STBRP_LARGE_RECTS 220 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 221 | #endif 222 | 223 | for (i=0; i < num_nodes-1; ++i) 224 | nodes[i].next = &nodes[i+1]; 225 | nodes[i].next = NULL; 226 | context->init_mode = STBRP__INIT_skyline; 227 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 228 | context->free_head = &nodes[0]; 229 | context->active_head = &context->extra[0]; 230 | context->width = width; 231 | context->height = height; 232 | context->num_nodes = num_nodes; 233 | stbrp_setup_allow_out_of_mem(context, 0); 234 | 235 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 236 | context->extra[0].x = 0; 237 | context->extra[0].y = 0; 238 | context->extra[0].next = &context->extra[1]; 239 | context->extra[1].x = (stbrp_coord) width; 240 | #ifdef STBRP_LARGE_RECTS 241 | context->extra[1].y = (1<<30); 242 | #else 243 | context->extra[1].y = 65535; 244 | #endif 245 | context->extra[1].next = NULL; 246 | } 247 | 248 | // find minimum y position if it starts at x1 249 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 250 | { 251 | (void)c; 252 | stbrp_node *node = first; 253 | int x1 = x0 + width; 254 | int min_y, visited_width, waste_area; 255 | STBRP_ASSERT(first->x <= x0); 256 | 257 | #if 0 258 | // skip in case we're past the node 259 | while (node->next->x <= x0) 260 | ++node; 261 | #else 262 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 263 | #endif 264 | 265 | STBRP_ASSERT(node->x <= x0); 266 | 267 | min_y = 0; 268 | waste_area = 0; 269 | visited_width = 0; 270 | while (node->x < x1) { 271 | if (node->y > min_y) { 272 | // raise min_y higher. 273 | // we've accounted for all waste up to min_y, 274 | // but we'll now add more waste for everything we've visted 275 | waste_area += visited_width * (node->y - min_y); 276 | min_y = node->y; 277 | // the first time through, visited_width might be reduced 278 | if (node->x < x0) 279 | visited_width += node->next->x - x0; 280 | else 281 | visited_width += node->next->x - node->x; 282 | } else { 283 | // add waste area 284 | int under_width = node->next->x - node->x; 285 | if (under_width + visited_width > width) 286 | under_width = width - visited_width; 287 | waste_area += under_width * (min_y - node->y); 288 | visited_width += under_width; 289 | } 290 | node = node->next; 291 | } 292 | 293 | *pwaste = waste_area; 294 | return min_y; 295 | } 296 | 297 | typedef struct 298 | { 299 | int x,y; 300 | stbrp_node **prev_link; 301 | } stbrp__findresult; 302 | 303 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 304 | { 305 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 306 | stbrp__findresult fr; 307 | stbrp_node **prev, *node, *tail, **best = NULL; 308 | 309 | // align to multiple of c->align 310 | width = (width + c->align - 1); 311 | width -= width % c->align; 312 | STBRP_ASSERT(width % c->align == 0); 313 | 314 | node = c->active_head; 315 | prev = &c->active_head; 316 | while (node->x + width <= c->width) { 317 | int y,waste; 318 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 319 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 320 | // bottom left 321 | if (y < best_y) { 322 | best_y = y; 323 | best = prev; 324 | } 325 | } else { 326 | // best-fit 327 | if (y + height <= c->height) { 328 | // can only use it if it first vertically 329 | if (y < best_y || (y == best_y && waste < best_waste)) { 330 | best_y = y; 331 | best_waste = waste; 332 | best = prev; 333 | } 334 | } 335 | } 336 | prev = &node->next; 337 | node = node->next; 338 | } 339 | 340 | best_x = (best == NULL) ? 0 : (*best)->x; 341 | 342 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 343 | // 344 | // e.g, if fitting 345 | // 346 | // ____________________ 347 | // |____________________| 348 | // 349 | // into 350 | // 351 | // | | 352 | // | ____________| 353 | // |____________| 354 | // 355 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 356 | // 357 | // This makes BF take about 2x the time 358 | 359 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 360 | tail = c->active_head; 361 | node = c->active_head; 362 | prev = &c->active_head; 363 | // find first node that's admissible 364 | while (tail->x < width) 365 | tail = tail->next; 366 | while (tail) { 367 | int xpos = tail->x - width; 368 | int y,waste; 369 | STBRP_ASSERT(xpos >= 0); 370 | // find the left position that matches this 371 | while (node->next->x <= xpos) { 372 | prev = &node->next; 373 | node = node->next; 374 | } 375 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 376 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 377 | if (y + height < c->height) { 378 | if (y <= best_y) { 379 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 380 | best_x = xpos; 381 | STBRP_ASSERT(y <= best_y); 382 | best_y = y; 383 | best_waste = waste; 384 | best = prev; 385 | } 386 | } 387 | } 388 | tail = tail->next; 389 | } 390 | } 391 | 392 | fr.prev_link = best; 393 | fr.x = best_x; 394 | fr.y = best_y; 395 | return fr; 396 | } 397 | 398 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 399 | { 400 | // find best position according to heuristic 401 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 402 | stbrp_node *node, *cur; 403 | 404 | // bail if: 405 | // 1. it failed 406 | // 2. the best node doesn't fit (we don't always check this) 407 | // 3. we're out of memory 408 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 409 | res.prev_link = NULL; 410 | return res; 411 | } 412 | 413 | // on success, create new node 414 | node = context->free_head; 415 | node->x = (stbrp_coord) res.x; 416 | node->y = (stbrp_coord) (res.y + height); 417 | 418 | context->free_head = node->next; 419 | 420 | // insert the new node into the right starting point, and 421 | // let 'cur' point to the remaining nodes needing to be 422 | // stiched back in 423 | 424 | cur = *res.prev_link; 425 | if (cur->x < res.x) { 426 | // preserve the existing one, so start testing with the next one 427 | stbrp_node *next = cur->next; 428 | cur->next = node; 429 | cur = next; 430 | } else { 431 | *res.prev_link = node; 432 | } 433 | 434 | // from here, traverse cur and free the nodes, until we get to one 435 | // that shouldn't be freed 436 | while (cur->next && cur->next->x <= res.x + width) { 437 | stbrp_node *next = cur->next; 438 | // move the current node to the free list 439 | cur->next = context->free_head; 440 | context->free_head = cur; 441 | cur = next; 442 | } 443 | 444 | // stitch the list back in 445 | node->next = cur; 446 | 447 | if (cur->x < res.x + width) 448 | cur->x = (stbrp_coord) (res.x + width); 449 | 450 | #ifdef _DEBUG 451 | cur = context->active_head; 452 | while (cur->x < context->width) { 453 | STBRP_ASSERT(cur->x < cur->next->x); 454 | cur = cur->next; 455 | } 456 | STBRP_ASSERT(cur->next == NULL); 457 | 458 | { 459 | stbrp_node *L1 = NULL, *L2 = NULL; 460 | int count=0; 461 | cur = context->active_head; 462 | while (cur) { 463 | L1 = cur; 464 | cur = cur->next; 465 | ++count; 466 | } 467 | cur = context->free_head; 468 | while (cur) { 469 | L2 = cur; 470 | cur = cur->next; 471 | ++count; 472 | } 473 | STBRP_ASSERT(count == context->num_nodes+2); 474 | } 475 | #endif 476 | 477 | return res; 478 | } 479 | 480 | static int rect_height_compare(const void *a, const void *b) 481 | { 482 | stbrp_rect *p = (stbrp_rect *) a; 483 | stbrp_rect *q = (stbrp_rect *) b; 484 | if (p->h > q->h) 485 | return -1; 486 | if (p->h < q->h) 487 | return 1; 488 | return (p->w > q->w) ? -1 : (p->w < q->w); 489 | } 490 | 491 | static int rect_width_compare(const void *a, const void *b) 492 | { 493 | stbrp_rect *p = (stbrp_rect *) a; 494 | stbrp_rect *q = (stbrp_rect *) b; 495 | if (p->w > q->w) 496 | return -1; 497 | if (p->w < q->w) 498 | return 1; 499 | return (p->h > q->h) ? -1 : (p->h < q->h); 500 | } 501 | 502 | static int rect_original_order(const void *a, const void *b) 503 | { 504 | stbrp_rect *p = (stbrp_rect *) a; 505 | stbrp_rect *q = (stbrp_rect *) b; 506 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 507 | } 508 | 509 | #ifdef STBRP_LARGE_RECTS 510 | #define STBRP__MAXVAL 0xffffffff 511 | #else 512 | #define STBRP__MAXVAL 0xffff 513 | #endif 514 | 515 | STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 516 | { 517 | int i; 518 | 519 | // we use the 'was_packed' field internally to allow sorting/unsorting 520 | for (i=0; i < num_rects; ++i) { 521 | rects[i].was_packed = i; 522 | #ifndef STBRP_LARGE_RECTS 523 | STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff); 524 | #endif 525 | } 526 | 527 | // sort according to heuristic 528 | qsort(rects, num_rects, sizeof(rects[0]), rect_height_compare); 529 | 530 | for (i=0; i < num_rects; ++i) { 531 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 532 | if (fr.prev_link) { 533 | rects[i].x = (stbrp_coord) fr.x; 534 | rects[i].y = (stbrp_coord) fr.y; 535 | } else { 536 | rects[i].x = rects[i].y = STBRP__MAXVAL; 537 | } 538 | } 539 | 540 | // unsort 541 | qsort(rects, num_rects, sizeof(rects[0]), rect_original_order); 542 | 543 | // set was_packed flags 544 | for (i=0; i < num_rects; ++i) 545 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 546 | } 547 | #endif 548 | -------------------------------------------------------------------------------- /test/External/imgui/stb_textedit.h: -------------------------------------------------------------------------------- 1 | // [ImGui] this is a slightly modified version of stb_truetype.h 1.4 2 | // [ImGui] we made a fix for using the END key on multi-line text edit, see https://github.com/ocornut/imgui/issues/275 3 | 4 | // stb_textedit.h - v1.4 - public domain - Sean Barrett 5 | // Development of this library was sponsored by RAD Game Tools 6 | // 7 | // This C header file implements the guts of a multi-line text-editing 8 | // widget; you implement display, word-wrapping, and low-level string 9 | // insertion/deletion, and stb_textedit will map user inputs into 10 | // insertions & deletions, plus updates to the cursor position, 11 | // selection state, and undo state. 12 | // 13 | // It is intended for use in games and other systems that need to build 14 | // their own custom widgets and which do not have heavy text-editing 15 | // requirements (this library is not recommended for use for editing large 16 | // texts, as its performance does not scale and it has limited undo). 17 | // 18 | // Non-trivial behaviors are modelled after Windows text controls. 19 | // 20 | // 21 | // LICENSE 22 | // 23 | // This software has been placed in the public domain by its author. 24 | // Where that dedication is not recognized, you are granted a perpetual, 25 | // irrevocable license to copy and modify this file as you see fit. 26 | // 27 | // 28 | // DEPENDENCIES 29 | // 30 | // Uses the C runtime function 'memmove'. Uses no other functions. 31 | // Performs no runtime allocations. 32 | // 33 | // 34 | // VERSION HISTORY 35 | // 36 | // 1.4 (2014-08-17) fix signed/unsigned warnings 37 | // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary 38 | // 1.2 (2014-05-27) fix some RAD types that had crept into the new code 39 | // 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) 40 | // 1.0 (2012-07-26) improve documentation, initial public release 41 | // 0.3 (2012-02-24) bugfixes, single-line mode; insert mode 42 | // 0.2 (2011-11-28) fixes to undo/redo 43 | // 0.1 (2010-07-08) initial version 44 | // 45 | // ADDITIONAL CONTRIBUTORS 46 | // 47 | // Ulf Winklemann: move-by-word in 1.1 48 | // Scott Graham: mouse selection bugfix in 1.3 49 | // 50 | // USAGE 51 | // 52 | // This file behaves differently depending on what symbols you define 53 | // before including it. 54 | // 55 | // 56 | // Header-file mode: 57 | // 58 | // If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, 59 | // it will operate in "header file" mode. In this mode, it declares a 60 | // single public symbol, STB_TexteditState, which encapsulates the current 61 | // state of a text widget (except for the string, which you will store 62 | // separately). 63 | // 64 | // To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a 65 | // primitive type that defines a single character (e.g. char, wchar_t, etc). 66 | // 67 | // To save space or increase undo-ability, you can optionally define the 68 | // following things that are used by the undo system: 69 | // 70 | // STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position 71 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 72 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 73 | // 74 | // If you don't define these, they are set to permissive types and 75 | // moderate sizes. The undo system does no memory allocations, so 76 | // it grows STB_TexteditState by the worst-case storage which is (in bytes): 77 | // 78 | // [4 + sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT 79 | // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT 80 | // 81 | // 82 | // Implementation mode: 83 | // 84 | // If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it 85 | // will compile the implementation of the text edit widget, depending 86 | // on a large number of symbols which must be defined before the include. 87 | // 88 | // The implementation is defined only as static functions. You will then 89 | // need to provide your own APIs in the same file which will access the 90 | // static functions. 91 | // 92 | // The basic concept is that you provide a "string" object which 93 | // behaves like an array of characters. stb_textedit uses indices to 94 | // refer to positions in the string, implicitly representing positions 95 | // in the displayed textedit. This is true for both plain text and 96 | // rich text; even with rich text stb_truetype interacts with your 97 | // code as if there was an array of all the displayed characters. 98 | // 99 | // Symbols that must be the same in header-file and implementation mode: 100 | // 101 | // STB_TEXTEDIT_CHARTYPE the character type 102 | // STB_TEXTEDIT_POSITIONTYPE small type that a valid cursor position 103 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 104 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 105 | // 106 | // Symbols you must define for implementation mode: 107 | // 108 | // STB_TEXTEDIT_STRING the type of object representing a string being edited, 109 | // typically this is a wrapper object with other data you need 110 | // 111 | // STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) 112 | // STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters 113 | // starting from character #n (see discussion below) 114 | // STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character 115 | // to the xpos of the i+1'th char for a line of characters 116 | // starting at character #n (i.e. accounts for kerning 117 | // with previous char) 118 | // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character 119 | // (return type is int, -1 means not valid to insert) 120 | // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based 121 | // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize 122 | // as manually wordwrapping for end-of-line positioning 123 | // 124 | // STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i 125 | // STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) 126 | // 127 | // STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key 128 | // 129 | // STB_TEXTEDIT_K_LEFT keyboard input to move cursor left 130 | // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right 131 | // STB_TEXTEDIT_K_UP keyboard input to move cursor up 132 | // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 133 | // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 134 | // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END 135 | // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME 136 | // STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END 137 | // STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor 138 | // STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor 139 | // STB_TEXTEDIT_K_UNDO keyboard input to perform undo 140 | // STB_TEXTEDIT_K_REDO keyboard input to perform redo 141 | // 142 | // Optional: 143 | // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode 144 | // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), 145 | // required for WORDLEFT/WORDRIGHT 146 | // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT 147 | // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT 148 | // 149 | // Todo: 150 | // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 151 | // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 152 | // 153 | // Keyboard input must be encoded as a single integer value; e.g. a character code 154 | // and some bitflags that represent shift states. to simplify the interface, SHIFT must 155 | // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 156 | // i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 157 | // 158 | // You can encode other things, such as CONTROL or ALT, in additional bits, and 159 | // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, 160 | // my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN 161 | // bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, 162 | // and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the 163 | // API below. The control keys will only match WM_KEYDOWN events because of the 164 | // keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN 165 | // bit so it only decodes WM_CHAR events. 166 | // 167 | // STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed 168 | // row of characters assuming they start on the i'th character--the width and 169 | // the height and the number of characters consumed. This allows this library 170 | // to traverse the entire layout incrementally. You need to compute word-wrapping 171 | // here. 172 | // 173 | // Each textfield keeps its own insert mode state, which is not how normal 174 | // applications work. To keep an app-wide insert mode, update/copy the 175 | // "insert_mode" field of STB_TexteditState before/after calling API functions. 176 | // 177 | // API 178 | // 179 | // void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 180 | // 181 | // void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 182 | // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 183 | // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 184 | // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 185 | // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) 186 | // 187 | // Each of these functions potentially updates the string and updates the 188 | // state. 189 | // 190 | // initialize_state: 191 | // set the textedit state to a known good default state when initially 192 | // constructing the textedit. 193 | // 194 | // click: 195 | // call this with the mouse x,y on a mouse down; it will update the cursor 196 | // and reset the selection start/end to the cursor point. the x,y must 197 | // be relative to the text widget, with (0,0) being the top left. 198 | // 199 | // drag: 200 | // call this with the mouse x,y on a mouse drag/up; it will update the 201 | // cursor and the selection end point 202 | // 203 | // cut: 204 | // call this to delete the current selection; returns true if there was 205 | // one. you should FIRST copy the current selection to the system paste buffer. 206 | // (To copy, just copy the current selection out of the string yourself.) 207 | // 208 | // paste: 209 | // call this to paste text at the current cursor point or over the current 210 | // selection if there is one. 211 | // 212 | // key: 213 | // call this for keyboard inputs sent to the textfield. you can use it 214 | // for "key down" events or for "translated" key events. if you need to 215 | // do both (as in Win32), or distinguish Unicode characters from control 216 | // inputs, set a high bit to distinguish the two; then you can define the 217 | // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 218 | // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 219 | // clear. 220 | // 221 | // When rendering, you can read the cursor position and selection state from 222 | // the STB_TexteditState. 223 | // 224 | // 225 | // Notes: 226 | // 227 | // This is designed to be usable in IMGUI, so it allows for the possibility of 228 | // running in an IMGUI that has NOT cached the multi-line layout. For this 229 | // reason, it provides an interface that is compatible with computing the 230 | // layout incrementally--we try to make sure we make as few passes through 231 | // as possible. (For example, to locate the mouse pointer in the text, we 232 | // could define functions that return the X and Y positions of characters 233 | // and binary search Y and then X, but if we're doing dynamic layout this 234 | // will run the layout algorithm many times, so instead we manually search 235 | // forward in one pass. Similar logic applies to e.g. up-arrow and 236 | // down-arrow movement.) 237 | // 238 | // If it's run in a widget that *has* cached the layout, then this is less 239 | // efficient, but it's not horrible on modern computers. But you wouldn't 240 | // want to edit million-line files with it. 241 | 242 | 243 | //////////////////////////////////////////////////////////////////////////// 244 | //////////////////////////////////////////////////////////////////////////// 245 | //// 246 | //// Header-file mode 247 | //// 248 | //// 249 | 250 | #ifndef INCLUDE_STB_TEXTEDIT_H 251 | #define INCLUDE_STB_TEXTEDIT_H 252 | 253 | //////////////////////////////////////////////////////////////////////// 254 | // 255 | // STB_TexteditState 256 | // 257 | // Definition of STB_TexteditState which you should store 258 | // per-textfield; it includes cursor position, selection state, 259 | // and undo state. 260 | // 261 | 262 | #ifndef STB_TEXTEDIT_UNDOSTATECOUNT 263 | #define STB_TEXTEDIT_UNDOSTATECOUNT 99 264 | #endif 265 | #ifndef STB_TEXTEDIT_UNDOCHARCOUNT 266 | #define STB_TEXTEDIT_UNDOCHARCOUNT 999 267 | #endif 268 | #ifndef STB_TEXTEDIT_CHARTYPE 269 | #define STB_TEXTEDIT_CHARTYPE int 270 | #endif 271 | #ifndef STB_TEXTEDIT_POSITIONTYPE 272 | #define STB_TEXTEDIT_POSITIONTYPE int 273 | #endif 274 | 275 | typedef struct 276 | { 277 | // private data 278 | STB_TEXTEDIT_POSITIONTYPE where; 279 | short insert_length; 280 | short delete_length; 281 | short char_storage; 282 | } StbUndoRecord; 283 | 284 | typedef struct 285 | { 286 | // private data 287 | StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 288 | STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 289 | short undo_point, redo_point; 290 | short undo_char_point, redo_char_point; 291 | } StbUndoState; 292 | 293 | typedef struct 294 | { 295 | ///////////////////// 296 | // 297 | // public data 298 | // 299 | 300 | int cursor; 301 | // position of the text cursor within the string 302 | 303 | int select_start; // selection start point 304 | int select_end; 305 | // selection start and end point in characters; if equal, no selection. 306 | // note that start may be less than or greater than end (e.g. when 307 | // dragging the mouse, start is where the initial click was, and you 308 | // can drag in either direction) 309 | 310 | unsigned char insert_mode; 311 | // each textfield keeps its own insert mode state. to keep an app-wide 312 | // insert mode, copy this value in/out of the app state 313 | 314 | ///////////////////// 315 | // 316 | // private data 317 | // 318 | unsigned char cursor_at_end_of_line; // not implemented yet 319 | unsigned char initialized; 320 | unsigned char has_preferred_x; 321 | unsigned char single_line; 322 | unsigned char padding1, padding2, padding3; 323 | float preferred_x; // this determines where the cursor up/down tries to seek to along x 324 | StbUndoState undostate; 325 | } STB_TexteditState; 326 | 327 | 328 | //////////////////////////////////////////////////////////////////////// 329 | // 330 | // StbTexteditRow 331 | // 332 | // Result of layout query, used by stb_textedit to determine where 333 | // the text in each row is. 334 | 335 | // result of layout query 336 | typedef struct 337 | { 338 | float x0,x1; // starting x location, end x location (allows for align=right, etc) 339 | float baseline_y_delta; // position of baseline relative to previous row's baseline 340 | float ymin,ymax; // height of row above and below baseline 341 | int num_chars; 342 | } StbTexteditRow; 343 | #endif //INCLUDE_STB_TEXTEDIT_H 344 | 345 | 346 | //////////////////////////////////////////////////////////////////////////// 347 | //////////////////////////////////////////////////////////////////////////// 348 | //// 349 | //// Implementation mode 350 | //// 351 | //// 352 | 353 | 354 | // implementation isn't include-guarded, since it might have indirectly 355 | // included just the "header" portion 356 | #ifdef STB_TEXTEDIT_IMPLEMENTATION 357 | 358 | #include // memmove 359 | 360 | 361 | ///////////////////////////////////////////////////////////////////////////// 362 | // 363 | // Mouse input handling 364 | // 365 | 366 | // traverse the layout to locate the nearest character to a display position 367 | static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) 368 | { 369 | StbTexteditRow r; 370 | int n = STB_TEXTEDIT_STRINGLEN(str); 371 | float base_y = 0, prev_x; 372 | int i=0, k; 373 | 374 | if (y < 0) 375 | return 0; 376 | 377 | r.x0 = r.x1 = 0; 378 | r.ymin = r.ymax = 0; 379 | r.num_chars = 0; 380 | 381 | // search rows to find one that straddles 'y' 382 | while (i < n) { 383 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 384 | if (r.num_chars <= 0) 385 | return n; 386 | 387 | if (y < base_y + r.ymax) 388 | break; 389 | 390 | i += r.num_chars; 391 | base_y += r.baseline_y_delta; 392 | } 393 | 394 | // below all text, return 'after' last character 395 | if (i >= n) 396 | return n; 397 | 398 | // check if it's before the beginning of the line 399 | if (x < r.x0) 400 | return i; 401 | 402 | // check if it's before the end of the line 403 | if (x < r.x1) { 404 | // search characters in row for one that straddles 'x' 405 | k = i; 406 | prev_x = r.x0; 407 | for (i=0; i < r.num_chars; ++i) { 408 | float w = STB_TEXTEDIT_GETWIDTH(str, k, i); 409 | if (x < prev_x+w) { 410 | if (x < prev_x+w/2) 411 | return k+i; 412 | else 413 | return k+i+1; 414 | } 415 | prev_x += w; 416 | } 417 | // shouldn't happen, but if it does, fall through to end-of-line case 418 | } 419 | 420 | // if the last character is a newline, return that. otherwise return 'after' the last character 421 | if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 422 | return i+r.num_chars-1; 423 | else 424 | return i+r.num_chars; 425 | } 426 | 427 | // API click: on mouse down, move the cursor to the clicked location, and reset the selection 428 | static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 429 | { 430 | state->cursor = stb_text_locate_coord(str, x, y); 431 | state->select_start = state->cursor; 432 | state->select_end = state->cursor; 433 | state->has_preferred_x = 0; 434 | } 435 | 436 | // API drag: on mouse drag, move the cursor and selection endpoint to the clicked location 437 | static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 438 | { 439 | int p = stb_text_locate_coord(str, x, y); 440 | state->cursor = state->select_end = p; 441 | } 442 | 443 | ///////////////////////////////////////////////////////////////////////////// 444 | // 445 | // Keyboard input handling 446 | // 447 | 448 | // forward declarations 449 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 450 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 451 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); 452 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); 453 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); 454 | 455 | typedef struct 456 | { 457 | float x,y; // position of n'th character 458 | float height; // height of line 459 | int first_char, length; // first char of row, and length 460 | int prev_first; // first char of previous row 461 | } StbFindState; 462 | 463 | // find the x/y location of a character, and remember info about the previous row in 464 | // case we get a move-up event (for page up, we'll have to rescan) 465 | static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) 466 | { 467 | StbTexteditRow r; 468 | int prev_start = 0; 469 | int z = STB_TEXTEDIT_STRINGLEN(str); 470 | int i=0, first; 471 | 472 | if (n == z) { 473 | // if it's at the end, then find the last line -- simpler than trying to 474 | // explicitly handle this case in the regular code 475 | if (single_line) { 476 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 477 | find->y = 0; 478 | find->first_char = 0; 479 | find->length = z; 480 | find->height = r.ymax - r.ymin; 481 | find->x = r.x1; 482 | } else { 483 | find->y = 0; 484 | find->x = 0; 485 | find->height = 1; 486 | while (i < z) { 487 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 488 | prev_start = i; 489 | i += r.num_chars; 490 | } 491 | find->first_char = i; 492 | find->length = 0; 493 | find->prev_first = prev_start; 494 | } 495 | return; 496 | } 497 | 498 | // search rows to find the one that straddles character n 499 | find->y = 0; 500 | 501 | for(;;) { 502 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 503 | if (n < i + r.num_chars) 504 | break; 505 | prev_start = i; 506 | i += r.num_chars; 507 | find->y += r.baseline_y_delta; 508 | } 509 | 510 | find->first_char = first = i; 511 | find->length = r.num_chars; 512 | find->height = r.ymax - r.ymin; 513 | find->prev_first = prev_start; 514 | 515 | // now scan to find xpos 516 | find->x = r.x0; 517 | i = 0; 518 | for (i=0; first+i < n; ++i) 519 | find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 520 | } 521 | 522 | #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 523 | 524 | // make the selection/cursor state valid if client altered the string 525 | static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 526 | { 527 | int n = STB_TEXTEDIT_STRINGLEN(str); 528 | if (STB_TEXT_HAS_SELECTION(state)) { 529 | if (state->select_start > n) state->select_start = n; 530 | if (state->select_end > n) state->select_end = n; 531 | // if clamping forced them to be equal, move the cursor to match 532 | if (state->select_start == state->select_end) 533 | state->cursor = state->select_start; 534 | } 535 | if (state->cursor > n) state->cursor = n; 536 | } 537 | 538 | // delete characters while updating undo 539 | static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) 540 | { 541 | stb_text_makeundo_delete(str, state, where, len); 542 | STB_TEXTEDIT_DELETECHARS(str, where, len); 543 | state->has_preferred_x = 0; 544 | } 545 | 546 | // delete the section 547 | static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 548 | { 549 | stb_textedit_clamp(str, state); 550 | if (STB_TEXT_HAS_SELECTION(state)) { 551 | if (state->select_start < state->select_end) { 552 | stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 553 | state->select_end = state->cursor = state->select_start; 554 | } else { 555 | stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 556 | state->select_start = state->cursor = state->select_end; 557 | } 558 | state->has_preferred_x = 0; 559 | } 560 | } 561 | 562 | // canoncialize the selection so start <= end 563 | static void stb_textedit_sortselection(STB_TexteditState *state) 564 | { 565 | if (state->select_end < state->select_start) { 566 | int temp = state->select_end; 567 | state->select_end = state->select_start; 568 | state->select_start = temp; 569 | } 570 | } 571 | 572 | // move cursor to first character of selection 573 | static void stb_textedit_move_to_first(STB_TexteditState *state) 574 | { 575 | if (STB_TEXT_HAS_SELECTION(state)) { 576 | stb_textedit_sortselection(state); 577 | state->cursor = state->select_start; 578 | state->select_end = state->select_start; 579 | state->has_preferred_x = 0; 580 | } 581 | } 582 | 583 | // move cursor to last character of selection 584 | static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 585 | { 586 | if (STB_TEXT_HAS_SELECTION(state)) { 587 | stb_textedit_sortselection(state); 588 | stb_textedit_clamp(str, state); 589 | state->cursor = state->select_end; 590 | state->select_start = state->select_end; 591 | state->has_preferred_x = 0; 592 | } 593 | } 594 | 595 | #ifdef STB_TEXTEDIT_IS_SPACE 596 | static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx ) 597 | { 598 | return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1; 599 | } 600 | 601 | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state ) 602 | { 603 | int c = _state->cursor - 1; 604 | while( c >= 0 && !is_word_boundary( _str, c ) ) 605 | --c; 606 | 607 | if( c < 0 ) 608 | c = 0; 609 | 610 | return c; 611 | } 612 | 613 | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state ) 614 | { 615 | const int len = STB_TEXTEDIT_STRINGLEN(_str); 616 | int c = _state->cursor+1; 617 | while( c < len && !is_word_boundary( _str, c ) ) 618 | ++c; 619 | 620 | if( c > len ) 621 | c = len; 622 | 623 | return c; 624 | } 625 | #endif 626 | 627 | // update selection and cursor to match each other 628 | static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) 629 | { 630 | if (!STB_TEXT_HAS_SELECTION(state)) 631 | state->select_start = state->select_end = state->cursor; 632 | else 633 | state->cursor = state->select_end; 634 | } 635 | 636 | // API cut: delete selection 637 | static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 638 | { 639 | if (STB_TEXT_HAS_SELECTION(state)) { 640 | stb_textedit_delete_selection(str,state); // implicity clamps 641 | state->has_preferred_x = 0; 642 | return 1; 643 | } 644 | return 0; 645 | } 646 | 647 | // API paste: replace existing selection with passed-in text 648 | static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 649 | { 650 | STB_TEXTEDIT_CHARTYPE *text = (STB_TEXTEDIT_CHARTYPE *) ctext; 651 | // if there's a selection, the paste should delete it 652 | stb_textedit_clamp(str, state); 653 | stb_textedit_delete_selection(str,state); 654 | // try to insert the characters 655 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { 656 | stb_text_makeundo_insert(state, state->cursor, len); 657 | state->cursor += len; 658 | state->has_preferred_x = 0; 659 | return 1; 660 | } 661 | // remove the undo since we didn't actually insert the characters 662 | if (state->undostate.undo_point) 663 | --state->undostate.undo_point; 664 | return 0; 665 | } 666 | 667 | // API key: process a keyboard input 668 | static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) 669 | { 670 | retry: 671 | switch (key) { 672 | default: { 673 | int c = STB_TEXTEDIT_KEYTOTEXT(key); 674 | if (c > 0) { 675 | STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 676 | 677 | // can't add newline in single-line mode 678 | if (c == '\n' && state->single_line) 679 | break; 680 | 681 | if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 682 | stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 683 | STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 684 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 685 | ++state->cursor; 686 | state->has_preferred_x = 0; 687 | } 688 | } else { 689 | stb_textedit_delete_selection(str,state); // implicity clamps 690 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 691 | stb_text_makeundo_insert(state, state->cursor, 1); 692 | ++state->cursor; 693 | state->has_preferred_x = 0; 694 | } 695 | } 696 | } 697 | break; 698 | } 699 | 700 | #ifdef STB_TEXTEDIT_K_INSERT 701 | case STB_TEXTEDIT_K_INSERT: 702 | state->insert_mode = !state->insert_mode; 703 | break; 704 | #endif 705 | 706 | case STB_TEXTEDIT_K_UNDO: 707 | stb_text_undo(str, state); 708 | state->has_preferred_x = 0; 709 | break; 710 | 711 | case STB_TEXTEDIT_K_REDO: 712 | stb_text_redo(str, state); 713 | state->has_preferred_x = 0; 714 | break; 715 | 716 | case STB_TEXTEDIT_K_LEFT: 717 | // if currently there's a selection, move cursor to start of selection 718 | if (STB_TEXT_HAS_SELECTION(state)) 719 | stb_textedit_move_to_first(state); 720 | else 721 | if (state->cursor > 0) 722 | --state->cursor; 723 | state->has_preferred_x = 0; 724 | break; 725 | 726 | case STB_TEXTEDIT_K_RIGHT: 727 | // if currently there's a selection, move cursor to end of selection 728 | if (STB_TEXT_HAS_SELECTION(state)) 729 | stb_textedit_move_to_last(str, state); 730 | else 731 | ++state->cursor; 732 | stb_textedit_clamp(str, state); 733 | state->has_preferred_x = 0; 734 | break; 735 | 736 | case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 737 | stb_textedit_clamp(str, state); 738 | stb_textedit_prep_selection_at_cursor(state); 739 | // move selection left 740 | if (state->select_end > 0) 741 | --state->select_end; 742 | state->cursor = state->select_end; 743 | state->has_preferred_x = 0; 744 | break; 745 | 746 | #ifdef STB_TEXTEDIT_IS_SPACE 747 | case STB_TEXTEDIT_K_WORDLEFT: 748 | if (STB_TEXT_HAS_SELECTION(state)) 749 | stb_textedit_move_to_first(state); 750 | else { 751 | state->cursor = stb_textedit_move_to_word_previous(str, state); 752 | stb_textedit_clamp( str, state ); 753 | } 754 | break; 755 | 756 | case STB_TEXTEDIT_K_WORDRIGHT: 757 | if (STB_TEXT_HAS_SELECTION(state)) 758 | stb_textedit_move_to_last(str, state); 759 | else { 760 | state->cursor = stb_textedit_move_to_word_next(str, state); 761 | stb_textedit_clamp( str, state ); 762 | } 763 | break; 764 | 765 | case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: 766 | if( !STB_TEXT_HAS_SELECTION( state ) ) 767 | stb_textedit_prep_selection_at_cursor(state); 768 | 769 | state->cursor = stb_textedit_move_to_word_previous(str, state); 770 | state->select_end = state->cursor; 771 | 772 | stb_textedit_clamp( str, state ); 773 | break; 774 | 775 | case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: 776 | if( !STB_TEXT_HAS_SELECTION( state ) ) 777 | stb_textedit_prep_selection_at_cursor(state); 778 | 779 | state->cursor = stb_textedit_move_to_word_next(str, state); 780 | state->select_end = state->cursor; 781 | 782 | stb_textedit_clamp( str, state ); 783 | break; 784 | #endif 785 | 786 | case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 787 | stb_textedit_prep_selection_at_cursor(state); 788 | // move selection right 789 | ++state->select_end; 790 | stb_textedit_clamp(str, state); 791 | state->cursor = state->select_end; 792 | state->has_preferred_x = 0; 793 | break; 794 | 795 | case STB_TEXTEDIT_K_DOWN: 796 | case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { 797 | StbFindState find; 798 | StbTexteditRow row; 799 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 800 | 801 | if (state->single_line) { 802 | // on windows, up&down in single-line behave like left&right 803 | key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 804 | goto retry; 805 | } 806 | 807 | if (sel) 808 | stb_textedit_prep_selection_at_cursor(state); 809 | else if (STB_TEXT_HAS_SELECTION(state)) 810 | stb_textedit_move_to_last(str,state); 811 | 812 | // compute current position of cursor point 813 | stb_textedit_clamp(str, state); 814 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 815 | 816 | // now find character position down a row 817 | if (find.length) { 818 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x; 819 | float x; 820 | int start = find.first_char + find.length; 821 | state->cursor = start; 822 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 823 | x = row.x0; 824 | for (i=0; i < row.num_chars; ++i) { 825 | float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); 826 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 827 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 828 | break; 829 | #endif 830 | x += dx; 831 | if (x > goal_x) 832 | break; 833 | ++state->cursor; 834 | } 835 | stb_textedit_clamp(str, state); 836 | 837 | state->has_preferred_x = 1; 838 | state->preferred_x = goal_x; 839 | 840 | if (sel) 841 | state->select_end = state->cursor; 842 | } 843 | break; 844 | } 845 | 846 | case STB_TEXTEDIT_K_UP: 847 | case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { 848 | StbFindState find; 849 | StbTexteditRow row; 850 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 851 | 852 | if (state->single_line) { 853 | // on windows, up&down become left&right 854 | key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 855 | goto retry; 856 | } 857 | 858 | if (sel) 859 | stb_textedit_prep_selection_at_cursor(state); 860 | else if (STB_TEXT_HAS_SELECTION(state)) 861 | stb_textedit_move_to_first(state); 862 | 863 | // compute current position of cursor point 864 | stb_textedit_clamp(str, state); 865 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 866 | 867 | // can only go up if there's a previous row 868 | if (find.prev_first != find.first_char) { 869 | // now find character position up a row 870 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x; 871 | float x; 872 | state->cursor = find.prev_first; 873 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 874 | x = row.x0; 875 | for (i=0; i < row.num_chars; ++i) { 876 | float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); 877 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 878 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 879 | break; 880 | #endif 881 | x += dx; 882 | if (x > goal_x) 883 | break; 884 | ++state->cursor; 885 | } 886 | stb_textedit_clamp(str, state); 887 | 888 | state->has_preferred_x = 1; 889 | state->preferred_x = goal_x; 890 | 891 | if (sel) 892 | state->select_end = state->cursor; 893 | } 894 | break; 895 | } 896 | 897 | case STB_TEXTEDIT_K_DELETE: 898 | case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: 899 | if (STB_TEXT_HAS_SELECTION(state)) 900 | stb_textedit_delete_selection(str, state); 901 | else { 902 | int n = STB_TEXTEDIT_STRINGLEN(str); 903 | if (state->cursor < n) 904 | stb_textedit_delete(str, state, state->cursor, 1); 905 | } 906 | state->has_preferred_x = 0; 907 | break; 908 | 909 | case STB_TEXTEDIT_K_BACKSPACE: 910 | case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: 911 | if (STB_TEXT_HAS_SELECTION(state)) 912 | stb_textedit_delete_selection(str, state); 913 | else { 914 | stb_textedit_clamp(str, state); 915 | if (state->cursor > 0) { 916 | stb_textedit_delete(str, state, state->cursor-1, 1); 917 | --state->cursor; 918 | } 919 | } 920 | state->has_preferred_x = 0; 921 | break; 922 | 923 | case STB_TEXTEDIT_K_TEXTSTART: 924 | state->cursor = state->select_start = state->select_end = 0; 925 | state->has_preferred_x = 0; 926 | break; 927 | 928 | case STB_TEXTEDIT_K_TEXTEND: 929 | state->cursor = STB_TEXTEDIT_STRINGLEN(str); 930 | state->select_start = state->select_end = 0; 931 | state->has_preferred_x = 0; 932 | break; 933 | 934 | case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: 935 | stb_textedit_prep_selection_at_cursor(state); 936 | state->cursor = state->select_end = 0; 937 | state->has_preferred_x = 0; 938 | break; 939 | 940 | case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: 941 | stb_textedit_prep_selection_at_cursor(state); 942 | state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); 943 | state->has_preferred_x = 0; 944 | break; 945 | 946 | 947 | case STB_TEXTEDIT_K_LINESTART: { 948 | StbFindState find; 949 | stb_textedit_clamp(str, state); 950 | stb_textedit_move_to_first(state); 951 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 952 | state->cursor = find.first_char; 953 | state->has_preferred_x = 0; 954 | break; 955 | } 956 | 957 | case STB_TEXTEDIT_K_LINEEND: { 958 | StbFindState find; 959 | stb_textedit_clamp(str, state); 960 | stb_textedit_move_to_first(state); 961 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 962 | state->cursor = find.first_char + find.length; 963 | if (find.length > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) == STB_TEXTEDIT_NEWLINE) 964 | state->cursor--; 965 | state->has_preferred_x = 0; 966 | break; 967 | } 968 | 969 | case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: { 970 | StbFindState find; 971 | stb_textedit_clamp(str, state); 972 | stb_textedit_prep_selection_at_cursor(state); 973 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 974 | state->cursor = state->select_end = find.first_char; 975 | state->has_preferred_x = 0; 976 | break; 977 | } 978 | 979 | case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 980 | StbFindState find; 981 | stb_textedit_clamp(str, state); 982 | stb_textedit_prep_selection_at_cursor(state); 983 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 984 | state->cursor = state->select_end = find.first_char + find.length; 985 | if (find.length > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) == STB_TEXTEDIT_NEWLINE) 986 | state->cursor = state->select_end = state->cursor - 1; 987 | state->has_preferred_x = 0; 988 | break; 989 | } 990 | 991 | // @TODO: 992 | // STB_TEXTEDIT_K_PGUP - move cursor up a page 993 | // STB_TEXTEDIT_K_PGDOWN - move cursor down a page 994 | } 995 | } 996 | 997 | ///////////////////////////////////////////////////////////////////////////// 998 | // 999 | // Undo processing 1000 | // 1001 | // @OPTIMIZE: the undo/redo buffer should be circular 1002 | 1003 | static void stb_textedit_flush_redo(StbUndoState *state) 1004 | { 1005 | state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1006 | state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1007 | } 1008 | 1009 | // discard the oldest entry in the undo list 1010 | static void stb_textedit_discard_undo(StbUndoState *state) 1011 | { 1012 | if (state->undo_point > 0) { 1013 | // if the 0th undo state has characters, clean those up 1014 | if (state->undo_rec[0].char_storage >= 0) { 1015 | int n = state->undo_rec[0].insert_length, i; 1016 | // delete n characters from all other records 1017 | state->undo_char_point = state->undo_char_point - (short) n; // vsnet05 1018 | memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1019 | for (i=0; i < state->undo_point; ++i) 1020 | if (state->undo_rec[i].char_storage >= 0) 1021 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it 1022 | } 1023 | --state->undo_point; 1024 | memmove(state->undo_rec, state->undo_rec+1, (size_t) ((size_t)state->undo_point*sizeof(state->undo_rec[0]))); 1025 | } 1026 | } 1027 | 1028 | // discard the oldest entry in the redo list--it's bad if this 1029 | // ever happens, but because undo & redo have to store the actual 1030 | // characters in different cases, the redo character buffer can 1031 | // fill up even though the undo buffer didn't 1032 | static void stb_textedit_discard_redo(StbUndoState *state) 1033 | { 1034 | int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1035 | 1036 | if (state->redo_point <= k) { 1037 | // if the k'th undo state has characters, clean those up 1038 | if (state->undo_rec[k].char_storage >= 0) { 1039 | int n = state->undo_rec[k].insert_length, i; 1040 | // delete n characters from all other records 1041 | state->redo_char_point = state->redo_char_point + (short) n; // vsnet05 1042 | memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); 1043 | for (i=state->redo_point; i < k; ++i) 1044 | if (state->undo_rec[i].char_storage >= 0) 1045 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 1046 | } 1047 | ++state->redo_point; 1048 | memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); 1049 | } 1050 | } 1051 | 1052 | static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) 1053 | { 1054 | // any time we create a new undo record, we discard redo 1055 | stb_textedit_flush_redo(state); 1056 | 1057 | // if we have no free records, we have to make room, by sliding the 1058 | // existing records down 1059 | if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1060 | stb_textedit_discard_undo(state); 1061 | 1062 | // if the characters to store won't possibly fit in the buffer, we can't undo 1063 | if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { 1064 | state->undo_point = 0; 1065 | state->undo_char_point = 0; 1066 | return NULL; 1067 | } 1068 | 1069 | // if we don't have enough free characters in the buffer, we have to make room 1070 | while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) 1071 | stb_textedit_discard_undo(state); 1072 | 1073 | return &state->undo_rec[state->undo_point++]; 1074 | } 1075 | 1076 | static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) 1077 | { 1078 | StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); 1079 | if (r == NULL) 1080 | return NULL; 1081 | 1082 | r->where = pos; 1083 | r->insert_length = (short) insert_len; 1084 | r->delete_length = (short) delete_len; 1085 | 1086 | if (insert_len == 0) { 1087 | r->char_storage = -1; 1088 | return NULL; 1089 | } else { 1090 | r->char_storage = state->undo_char_point; 1091 | state->undo_char_point = state->undo_char_point + (short) insert_len; 1092 | return &state->undo_char[r->char_storage]; 1093 | } 1094 | } 1095 | 1096 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1097 | { 1098 | StbUndoState *s = &state->undostate; 1099 | StbUndoRecord u, *r; 1100 | if (s->undo_point == 0) 1101 | return; 1102 | 1103 | // we need to do two things: apply the undo record, and create a redo record 1104 | u = s->undo_rec[s->undo_point-1]; 1105 | r = &s->undo_rec[s->redo_point-1]; 1106 | r->char_storage = -1; 1107 | 1108 | r->insert_length = u.delete_length; 1109 | r->delete_length = u.insert_length; 1110 | r->where = u.where; 1111 | 1112 | if (u.delete_length) { 1113 | // if the undo record says to delete characters, then the redo record will 1114 | // need to re-insert the characters that get deleted, so we need to store 1115 | // them. 1116 | 1117 | // there are three cases: 1118 | // there's enough room to store the characters 1119 | // characters stored for *redoing* don't leave room for redo 1120 | // characters stored for *undoing* don't leave room for redo 1121 | // if the last is true, we have to bail 1122 | 1123 | if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { 1124 | // the undo records take up too much character space; there's no space to store the redo characters 1125 | r->insert_length = 0; 1126 | } else { 1127 | int i; 1128 | 1129 | // there's definitely room to store the characters eventually 1130 | while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1131 | // there's currently not enough room, so discard a redo record 1132 | stb_textedit_discard_redo(s); 1133 | // should never happen: 1134 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1135 | return; 1136 | } 1137 | r = &s->undo_rec[s->redo_point-1]; 1138 | 1139 | r->char_storage = s->redo_char_point - u.delete_length; 1140 | s->redo_char_point = s->redo_char_point - (short) u.delete_length; 1141 | 1142 | // now save the characters 1143 | for (i=0; i < u.delete_length; ++i) 1144 | s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1145 | } 1146 | 1147 | // now we can carry out the deletion 1148 | STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); 1149 | } 1150 | 1151 | // check type of recorded action: 1152 | if (u.insert_length) { 1153 | // easy case: was a deletion, so we need to insert n characters 1154 | STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); 1155 | s->undo_char_point -= u.insert_length; 1156 | } 1157 | 1158 | state->cursor = u.where + u.insert_length; 1159 | 1160 | s->undo_point--; 1161 | s->redo_point--; 1162 | } 1163 | 1164 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1165 | { 1166 | StbUndoState *s = &state->undostate; 1167 | StbUndoRecord *u, r; 1168 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1169 | return; 1170 | 1171 | // we need to do two things: apply the redo record, and create an undo record 1172 | u = &s->undo_rec[s->undo_point]; 1173 | r = s->undo_rec[s->redo_point]; 1174 | 1175 | // we KNOW there must be room for the undo record, because the redo record 1176 | // was derived from an undo record 1177 | 1178 | u->delete_length = r.insert_length; 1179 | u->insert_length = r.delete_length; 1180 | u->where = r.where; 1181 | u->char_storage = -1; 1182 | 1183 | if (r.delete_length) { 1184 | // the redo record requires us to delete characters, so the undo record 1185 | // needs to store the characters 1186 | 1187 | if (s->undo_char_point + u->insert_length > s->redo_char_point) { 1188 | u->insert_length = 0; 1189 | u->delete_length = 0; 1190 | } else { 1191 | int i; 1192 | u->char_storage = s->undo_char_point; 1193 | s->undo_char_point = s->undo_char_point + u->insert_length; 1194 | 1195 | // now save the characters 1196 | for (i=0; i < u->insert_length; ++i) 1197 | s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1198 | } 1199 | 1200 | STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); 1201 | } 1202 | 1203 | if (r.insert_length) { 1204 | // easy case: need to insert n characters 1205 | STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); 1206 | } 1207 | 1208 | state->cursor = r.where + r.insert_length; 1209 | 1210 | s->undo_point++; 1211 | s->redo_point++; 1212 | } 1213 | 1214 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) 1215 | { 1216 | stb_text_createundo(&state->undostate, where, 0, length); 1217 | } 1218 | 1219 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) 1220 | { 1221 | int i; 1222 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1223 | if (p) { 1224 | for (i=0; i < length; ++i) 1225 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1226 | } 1227 | } 1228 | 1229 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) 1230 | { 1231 | int i; 1232 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1233 | if (p) { 1234 | for (i=0; i < old_length; ++i) 1235 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1236 | } 1237 | } 1238 | 1239 | // reset the state to default 1240 | static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) 1241 | { 1242 | state->undostate.undo_point = 0; 1243 | state->undostate.undo_char_point = 0; 1244 | state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1245 | state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1246 | state->select_end = state->select_start = 0; 1247 | state->cursor = 0; 1248 | state->has_preferred_x = 0; 1249 | state->preferred_x = 0; 1250 | state->cursor_at_end_of_line = 0; 1251 | state->initialized = 1; 1252 | state->single_line = (unsigned char) is_single_line; 1253 | state->insert_mode = 0; 1254 | } 1255 | 1256 | // API initialize 1257 | static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 1258 | { 1259 | stb_textedit_clear_state(state, is_single_line); 1260 | } 1261 | #endif//STB_TEXTEDIT_IMPLEMENTATION 1262 | -------------------------------------------------------------------------------- /test/Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class WorkerThread 7 | { 8 | public: 9 | WorkerThread() 10 | { 11 | for (int i = 0; i < 4; ++i) 12 | { 13 | _threads[i] = std::thread([this](){ 14 | while (_exit == false) 15 | { 16 | std::function fn; 17 | { 18 | std::unique_lock lock(_mutex); 19 | _cond.wait(lock); 20 | if (_exit) 21 | return; 22 | fn = _queue.back(); 23 | _queue.pop(); 24 | } 25 | fn(); 26 | } 27 | }); 28 | } 29 | } 30 | 31 | void push(std::function fn) 32 | { 33 | std::lock_guard lock(_mutex); 34 | _queue.push(fn); 35 | _cond.notify_one(); 36 | } 37 | 38 | void exit() 39 | { 40 | _exit = true; 41 | push([](){}); 42 | _cond.notify_all(); 43 | for (int i = 0; i < 4; ++i) 44 | { 45 | _threads[i].join(); 46 | } 47 | } 48 | private: 49 | std::mutex _mutex; 50 | std::queue> _queue; 51 | std::condition_variable _cond; 52 | std::thread _threads[4]; 53 | bool _exit = false; 54 | }; 55 | 56 | static WorkerThread g_workerThread; 57 | 58 | #define LMT_ENABLED 1 59 | #define LMT_ALLOC_NUMBER_PER_CHUNK 1024 * 16 60 | #define LMT_ALLOC_DICTIONARY_SIZE 1024 * 16 * 16 61 | #define LMT_STACK_DICTIONARY_SIZE 1024 * 16 * 8 62 | #define LMT_STACK_SIZE_PER_ALLOC 50 63 | #define LMT_CHUNK_NUMBER_PER_THREAD 4 64 | #define LMT_CACHE_SIZE 16 65 | #define LMT_DEBUG_DEV 1 66 | #define LMT_IMGUI_INCLUDE_PATH "External/imgui/imgui.h" 67 | #define LMT_USE_MALLOC ::malloc 68 | #define LMT_USE_REALLOC ::realloc 69 | #define LMT_USE_FREE ::free 70 | #define LMT_DEBUG_DEV 1 71 | 72 | // Activate snapping option (use more memory !) 73 | #define LMT_CAPTURE_ACTIVATED 1 74 | 75 | #define LMT_INSTANCE_COUNT_ACTIVATED 1 76 | 77 | #ifdef WIN64 78 | #define LMT_x64 79 | #else 80 | #define LMT_x86 81 | #endif 82 | 83 | #define LMT_STATS 1 84 | 85 | #define LMT_IMPL 1 86 | //#define SINGLE_THREADED 1 87 | 88 | #if defined(SINGLE_THREADED) 89 | #define LMT_TREAT_CHUNK(chunk) LiveMemTracer::treatChunk(chunk) 90 | #else 91 | #define LMT_TREAT_CHUNK(chunk) g_workerThread.push([=](){LiveMemTracer::treatChunk(chunk);}) 92 | #endif 93 | 94 | #include "../Src/LiveMemTracer.hpp" 95 | 96 | #include 97 | 98 | #include LMT_IMGUI_INCLUDE_PATH 99 | #include "External/GL/gl3w.h" 100 | #include "External/GLFW/glfw3.h" 101 | #include "External/imgui/imgui_impl_glfw_gl3.h" 102 | 103 | #include 104 | 105 | static void error_callback(int error, const char* description) 106 | { 107 | fprintf(stderr, "Error %d: %s\n", error, description); 108 | } 109 | 110 | #define OVERRIDE_NEW 1 111 | 112 | #if defined(OVERRIDE_NEW) 113 | ////////////////////////////////////////////////////////////////////////// 114 | inline void *myMalloc(size_t size) 115 | { 116 | return LMT_ALLOC(size); 117 | } 118 | 119 | inline void myFree(void *ptr) 120 | { 121 | LMT_DEALLOC(ptr); 122 | } 123 | 124 | void *myRealloc(void *ptr, size_t size) 125 | { 126 | return LMT_REALLOC(ptr, size); 127 | } 128 | 129 | void* operator new(size_t count) throw(std::bad_alloc) 130 | { 131 | return LMT_ALLOC(count); 132 | } 133 | 134 | void* operator new(size_t count, const std::nothrow_t&) throw() 135 | { 136 | return LMT_ALLOC(count); 137 | } 138 | 139 | void* operator new(size_t count, size_t alignment) throw(std::bad_alloc) 140 | { 141 | return LMT_ALLOC_ALIGNED(count, alignment); 142 | } 143 | 144 | void* operator new(size_t count, size_t alignment, const std::nothrow_t&) throw() 145 | { 146 | return LMT_ALLOC_ALIGNED(count, alignment); 147 | } 148 | 149 | void* operator new[](size_t count) throw(std::bad_alloc) 150 | { 151 | return LMT_ALLOC(count); 152 | } 153 | 154 | void* operator new[](size_t count, const std::nothrow_t&) throw() 155 | { 156 | return LMT_ALLOC(count); 157 | } 158 | 159 | void* operator new[](size_t count, size_t alignment) throw(std::bad_alloc) 160 | { 161 | return LMT_ALLOC_ALIGNED(count, alignment); 162 | } 163 | 164 | void* operator new[](size_t count, size_t alignment, const std::nothrow_t&) throw() 165 | { 166 | return LMT_ALLOC_ALIGNED(count, alignment); 167 | } 168 | 169 | void operator delete(void* ptr) throw() 170 | { 171 | return LMT_DEALLOC(ptr); 172 | } 173 | 174 | void operator delete(void *ptr, const std::nothrow_t&) throw() 175 | { 176 | return LMT_DEALLOC(ptr); 177 | } 178 | 179 | void operator delete(void *ptr, size_t alignment) throw() 180 | { 181 | return LMT_DEALLOC_ALIGNED(ptr); 182 | } 183 | 184 | void operator delete(void *ptr, size_t alignment, const std::nothrow_t&) throw() 185 | { 186 | return LMT_DEALLOC_ALIGNED(ptr); 187 | } 188 | 189 | void operator delete[](void* ptr) throw() 190 | { 191 | return LMT_DEALLOC(ptr); 192 | } 193 | 194 | void operator delete[](void *ptr, const std::nothrow_t&) throw() 195 | { 196 | return LMT_DEALLOC(ptr); 197 | } 198 | 199 | void operator delete[](void *ptr, size_t alignment) throw() 200 | { 201 | return LMT_DEALLOC_ALIGNED(ptr); 202 | } 203 | 204 | void operator delete[](void *ptr, size_t alignment, const std::nothrow_t&) throw() 205 | { 206 | return LMT_DEALLOC_ALIGNED(ptr); 207 | } 208 | ////////////////////////////////////////////////////////////////////////// 209 | #else 210 | inline void *myMalloc(size_t size) { return ::malloc(size); } 211 | inline void myFree(void *ptr) { ::free(ptr); } 212 | inline void *myRealloc(void *ptr, size_t size) { return ::realloc(ptr, size); } 213 | #endif 214 | 215 | struct Bar 216 | { 217 | Bar(){} 218 | char empty[8]; 219 | }; 220 | 221 | struct Foo 222 | { 223 | size_t index; 224 | std::string indexStr; 225 | Bar* ptr; 226 | Foo* next; 227 | Foo() : 228 | next(nullptr) 229 | {} 230 | }; 231 | 232 | template 233 | struct FooBarFunctor 234 | { 235 | static void call(Foo *prev) 236 | { 237 | if (size == 0) 238 | return; 239 | Foo *tmpFoo = new Foo; 240 | tmpFoo->index = size; 241 | tmpFoo->indexStr = std::to_string(size); 242 | tmpFoo->ptr = new Bar[size](); 243 | for (int i = 0; i < size; ++i) 244 | tmpFoo->indexStr += "|coucou|"; 245 | prev->next = tmpFoo; 246 | FooBarFunctor<(size > 0 ? size - 1 : 0)>::call(tmpFoo); 247 | } 248 | }; 249 | 250 | struct Titi 251 | { 252 | char titi[256]; 253 | }; 254 | 255 | Titi *leftTiti() { return new Titi; } 256 | Titi *rightTiti() { return new Titi; } 257 | 258 | Titi *conditionalTiti(bool left) 259 | { 260 | if (left) 261 | return leftTiti(); 262 | else 263 | return rightTiti(); 264 | } 265 | 266 | void *tataAlloc(size_t size) 267 | { 268 | return LMT_ALLOC(size); 269 | } 270 | 271 | struct Tata 272 | { 273 | char tata[1024]; 274 | Titi *a; 275 | Titi *b; 276 | void *v; 277 | Tata() 278 | { 279 | a = conditionalTiti(true); 280 | b = conditionalTiti(false); 281 | v = tataAlloc(128); 282 | } 283 | ~Tata() 284 | { 285 | LMT_DEALLOC(v); 286 | delete a; 287 | delete b; 288 | } 289 | }; 290 | 291 | struct Toto 292 | { 293 | char toto[128]; 294 | Tata *one; 295 | Tata *two; 296 | Toto() 297 | { 298 | one = new Tata(); 299 | two = new Tata(); 300 | } 301 | ~Toto() 302 | { 303 | delete one; 304 | delete two; 305 | } 306 | }; 307 | 308 | void smallLeak() 309 | { 310 | auto t = new Titi(); 311 | } 312 | 313 | #include 314 | #include 315 | 316 | int main(int ac, char **av) 317 | { 318 | LMT_INIT(); 319 | 320 | // Setup window 321 | glfwSetErrorCallback(error_callback); 322 | if (!glfwInit()) 323 | exit(1); 324 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 325 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 326 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 327 | GLFWwindow* window = glfwCreateWindow(1280, 720, "LiveMemTracer", NULL, NULL); 328 | glfwMakeContextCurrent(window); 329 | gl3wInit(); 330 | 331 | // Setup ImGui binding 332 | ImGui_ImplGlfwGL3_Init(window, true); 333 | ImGui::GetIO().MemAllocFn = &myMalloc; 334 | ImGui::GetIO().MemFreeFn = &myFree; 335 | 336 | ImVec4 clear_color = ImColor(114, 144, 154); 337 | 338 | smallLeak(); 339 | 340 | // Main loop 341 | float dt = 0.0f; 342 | std::vector totoVector; 343 | int clearCounter = 0; 344 | int test = 10; 345 | while (!glfwWindowShouldClose(window)) 346 | { 347 | auto start = std::chrono::high_resolution_clock::now(); 348 | 349 | glfwPollEvents(); 350 | ImGui_ImplGlfwGL3_NewFrame(); 351 | 352 | // Rendering 353 | int display_w, display_h; 354 | glfwGetFramebufferSize(window, &display_w, &display_h); 355 | glViewport(0, 0, display_w, display_h); 356 | glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); 357 | glClear(GL_COLOR_BUFFER_BIT); 358 | 359 | //Foo foo; 360 | //FooBarFunctor<1>::call(&foo); 361 | // 362 | //FooBarFunctor<200>::call(foo.next); 363 | // 364 | //Foo *p = foo.next; 365 | //while (p != nullptr) 366 | //{ 367 | // auto *next = p->next; 368 | // delete[]p->ptr; 369 | // delete p; 370 | // p = next; 371 | //} 372 | 373 | for (int i = 0; i < 100; ++i) 374 | { 375 | auto lambda = [&](){ 376 | totoVector.push_back(new Toto()); 377 | }; 378 | lambda(); 379 | } 380 | if (++clearCounter == 100) 381 | { 382 | for (auto &e : totoVector) 383 | { 384 | delete e; 385 | } 386 | totoVector.clear(); 387 | clearCounter = 0; 388 | } 389 | 390 | LMT_DISPLAY(dt); 391 | ImGui::ShowTestWindow(); 392 | ImGui::Render(); 393 | glfwSwapBuffers(window); 394 | 395 | 396 | auto end = std::chrono::high_resolution_clock::now(); 397 | int64_t elapsedTime = std::chrono::duration_cast(end - start).count(); 398 | dt = float(elapsedTime) / 1000.f; 399 | } 400 | 401 | ImGui_ImplGlfwGL3_Shutdown(); 402 | glfwTerminate(); 403 | LMT_EXIT(); 404 | g_workerThread.exit(); 405 | return 0; 406 | } -------------------------------------------------------------------------------- /test/Test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test.vcxproj", "{83942588-15DD-4FB0-8A05-CF906CD67EE1}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A9AA7383-110E-4775-82C4-3E0358FFD723}" 9 | ProjectSection(SolutionItems) = preProject 10 | Performance1.psess = Performance1.psess 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Debug|x64 = Debug|x64 17 | Release|Win32 = Release|Win32 18 | Release|x64 = Release|x64 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Debug|Win32.Build.0 = Debug|Win32 23 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Debug|x64.ActiveCfg = Debug|x64 24 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Debug|x64.Build.0 = Debug|x64 25 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Release|Win32.ActiveCfg = Release|Win32 26 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Release|Win32.Build.0 = Release|Win32 27 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Release|x64.ActiveCfg = Release|x64 28 | {83942588-15DD-4FB0-8A05-CF906CD67EE1}.Release|x64.Build.0 = Release|x64 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(Performance) = preSolution 34 | HasPerformanceSessions = true 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /test/Test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {83942588-15DD-4FB0-8A05-CF906CD67EE1} 37 | Test 38 | 39 | 40 | 41 | Application 42 | true 43 | v120 44 | MultiByte 45 | 46 | 47 | Application 48 | true 49 | v120 50 | MultiByte 51 | 52 | 53 | Application 54 | false 55 | v120 56 | true 57 | MultiByte 58 | 59 | 60 | Application 61 | false 62 | v120 63 | true 64 | MultiByte 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | $(SolutionDir)External;$(IncludePath) 84 | $(SolutionDir)External/Imgui;$(SourcePath) 85 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(SolutionDir)External; 86 | 87 | 88 | $(SolutionDir)External;$(IncludePath) 89 | $(SolutionDir)External/Imgui;$(SourcePath) 90 | $(SolutionDir)External;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) 91 | 92 | 93 | $(SolutionDir)External;$(IncludePath) 94 | $(SolutionDir)External/Imgui;$(SourcePath) 95 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(SolutionDir)External; 96 | 97 | 98 | $(SolutionDir)External;$(IncludePath) 99 | $(SolutionDir)External/Imgui;$(SourcePath) 100 | $(SolutionDir)External;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) 101 | 102 | 103 | 104 | Level3 105 | Disabled 106 | true 107 | _MBCS;%(PreprocessorDefinitions);_WIN32;WIN32_LEAN_AND_MEAN 108 | 109 | 110 | true 111 | opengl32.lib;glfw3_x86.lib;glu32.lib;%(AdditionalDependencies) 112 | 113 | 114 | 115 | 116 | Level3 117 | Disabled 118 | true 119 | _MBCS;%(PreprocessorDefinitions);_WIN32;WIN32_LEAN_AND_MEAN;WIN64 120 | 121 | 122 | true 123 | opengl32.lib;glfw3_x64.lib;glu32.lib;%(AdditionalDependencies) 124 | Console 125 | false 126 | 127 | 128 | 129 | 130 | Level3 131 | MaxSpeed 132 | true 133 | true 134 | true 135 | _MBCS;%(PreprocessorDefinitions);_WIN32;WIN32_LEAN_AND_MEAN 136 | 137 | 138 | true 139 | true 140 | true 141 | opengl32.lib;glfw3_x86.lib;glu32.lib;%(AdditionalDependencies) 142 | 143 | 144 | 145 | 146 | Level3 147 | MaxSpeed 148 | true 149 | true 150 | true 151 | _MBCS;%(PreprocessorDefinitions);_WIN32;WIN32_LEAN_AND_MEAN;WIN64 152 | 153 | 154 | true 155 | true 156 | true 157 | opengl32.lib;glfw3_x64.lib;%(AdditionalDependencies) 158 | Console 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /test/Test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | -------------------------------------------------------------------------------- /test/imgui.ini: -------------------------------------------------------------------------------- 1 | [Debug] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | [LiveMemoryProfiler] 7 | Pos=15,14 8 | Size=1238,680 9 | Collapsed=0 10 | 11 | [ImGui Demo] 12 | Pos=465,91 13 | Size=550,680 14 | Collapsed=1 15 | 16 | [Example: Custom rendering] 17 | Pos=60,60 18 | Size=300,350 19 | Collapsed=0 20 | 21 | --------------------------------------------------------------------------------