├── .gitignore ├── .gitmodules ├── LICENSE.md ├── README.md └── imgui ├── imconfig_source.h ├── imgui_impl_source.cpp ├── imgui_impl_source.h ├── imgui_system.cpp ├── imgui_system.h ├── imgui_system.vpc └── imgui_window.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.a 4 | *.dll 5 | *.lib 6 | *.exe 7 | build/ 8 | 9 | .ccls-cache 10 | .clangd/ 11 | 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/imgui"] 2 | path = thirdparty/imgui 3 | url = https://github.com/StrataSource/imgui.git 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2023 Strata Source Contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Source 2013 imgui 2 | 3 | This repo contains an imgui implementation for Source 2013 based on the one we developed for Strata Source (Portal 2: Community Edition, Momentum Mod, etc.) 4 | 5 | ## Integrating 6 | 7 | 1. Add this repo as a submodule to your Source mod 8 | 2. Include the VPC file in your client\_base.vpc 9 | 3. Add the following code to cdll\_client\_int.cpp 10 | 11 | At the top of the file: 12 | ```cpp 13 | #include "imgui/imgui_system.h" 14 | ``` 15 | 16 | Towards the end of `CHLClient::Init`: 17 | ```cpp 18 | g_pImguiSystem->Init(); 19 | ``` 20 | 21 | At the start of `CHLClient::Shutdown`: 22 | ```cpp 23 | g_pImguiSystem->Shutdown(); 24 | ``` 25 | 26 | 4. That's it! 27 | 28 | ## Limitations 29 | 30 | * Interop with vgui isn't the greatest, as we need to intercept input from vgui itself and redirect it to imgui. An invisible popup panel is used for this purpose. 31 | 32 | ## See Also 33 | 34 | For an example of a standalone app in Source with imgui, [see this](https://github.com/ozxybox/Source-2013-Example-ImGui-App) 35 | 36 | -------------------------------------------------------------------------------- /imgui/imconfig_source.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 4 | 5 | // Use tier0's asserts 6 | #include "tier0/dbg.h" 7 | 8 | #undef IM_ASSERT 9 | #define IM_ASSERT Assert 10 | 11 | // We provide our own allocators. 12 | #define IMGUI_DISABLE_DEFAULT_ALLOCATORS 13 | 14 | 15 | // We do not define Dear ImGui's api to cross dll boundaries. 16 | // Instead, everything that wants to use Dear ImGui can link devui_static.lib. 17 | #define IMGUI_API 18 | 19 | // Disable obsolete APIs. No need to make more work for ourselves. 20 | #define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 21 | #define IMGUI_DISABLE_OBSOLETE_KEYIO 22 | 23 | // Let's not link win32 for everything we include Dear ImGui with... 24 | #define IMGUI_DISABLE_WIN32_FUNCTIONS 25 | 26 | // We need to disable Dear ImGui's file functions, so we can pass them to Source's filesystem. Otherwise, we won't be able to access VPKs 27 | #define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 28 | using ImFileHandle = void*; 29 | IMGUI_API ImFileHandle ImFileOpen( const char *filename, const char *mode ); 30 | IMGUI_API bool ImFileClose( ImFileHandle file ); 31 | IMGUI_API uint64 ImFileGetSize( ImFileHandle file ); 32 | IMGUI_API uint64 ImFileRead( void *data, uint64 size, uint64 count, ImFileHandle file ); 33 | IMGUI_API uint64 ImFileWrite( const void *data, uint64 size, uint64 count, ImFileHandle file ); 34 | 35 | 36 | // Source's colors are stored as BGRA. Setting this allows us to avoid per vertex swizzles in mesh builder. 37 | // On Linux and Mac, mesh builder already does these swizzles regardless 38 | #if !defined( OPENGL_COLOR_SWAP ) 39 | #define IMGUI_USE_BGRA_PACKED_COLOR 40 | #endif 41 | 42 | 43 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 44 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. 45 | //#define IMGUI_USE_STB_SPRINTF 46 | 47 | 48 | #include "mathlib/vector2d.h" 49 | #include "mathlib/vector4d.h" 50 | #define IM_VEC2_CLASS_EXTRA \ 51 | ImVec2( const Vector2D& f ) : x( f.x ), y( f.y ) {} \ 52 | operator Vector2D() const { return Vector2D( x, y ); } 53 | 54 | #define IM_VEC4_CLASS_EXTRA \ 55 | ImVec4( const Vector4D& f ) : x( f.x ), y( f.y ), z( f.z ), w( f.w ) {} \ 56 | operator Vector4D() const { return Vector4D( x, y, z, w ); } 57 | 58 | 59 | class IMaterial; 60 | #define ImTextureID IMaterial* 61 | -------------------------------------------------------------------------------- /imgui/imgui_impl_source.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | * MIT License 3 | * 4 | * Copyright (c) 2023 Strata Source Contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | *********************************************************************************/ 24 | #include "imgui_impl_source.h" 25 | 26 | #include "KeyValues.h" 27 | #include "materialsystem/imesh.h" 28 | #include "materialsystem/itexture.h" 29 | #include "imgui/imgui.h" 30 | #include "imgui/imgui_internal.h" 31 | #include "pixelwriter.h" 32 | #include "filesystem.h" 33 | 34 | #include "vgui/ISystem.h" 35 | #include "vgui_controls/Controls.h" 36 | 37 | #include "tier0/memdbgon.h" 38 | 39 | static IMaterial *g_pFontMat = nullptr; 40 | 41 | class CDearImGuiFontTextureRegenerator : public ITextureRegenerator 42 | { 43 | public: 44 | CDearImGuiFontTextureRegenerator() = default; 45 | 46 | // Inherited from ITextureRegenerator 47 | void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) override 48 | { 49 | ImGuiIO &io = ImGui::GetIO(); 50 | unsigned char *pixels; 51 | int width, height; 52 | io.Fonts->GetTexDataAsRGBA32( &pixels, &width, &height ); 53 | 54 | Assert( pVTFTexture->Width() == width ); 55 | Assert( pVTFTexture->Height() == height ); 56 | // if we ever use freetype for font loading, this should do format conversion instead 57 | memcpy( pVTFTexture->ImageData(), pixels, 4ULL * width * height ); 58 | } 59 | 60 | void Release() override 61 | { 62 | delete this; 63 | } 64 | }; 65 | 66 | void ImGui_ImplSource_SetupRenderState( IMatRenderContext *ctx, ImDrawData *draw_data ) 67 | { 68 | // Apply imgui's display dimensions 69 | ctx->Viewport( draw_data->DisplayPos.x, draw_data->DisplayPos.y, draw_data->DisplaySize.x, draw_data->DisplaySize.y ); 70 | 71 | // Setup orthographic projection matrix 72 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. 73 | ctx->MatrixMode( MATERIAL_PROJECTION ); 74 | ctx->LoadIdentity(); 75 | ctx->Scale( 1, -1, 1 ); 76 | 77 | float L = draw_data->DisplayPos.x + 0.5f; 78 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f; 79 | float T = draw_data->DisplayPos.y + 0.5f; 80 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f; 81 | ctx->Ortho( L, T, R, B, 0.f, 1.f ); 82 | 83 | ctx->MatrixMode( MATERIAL_VIEW ); 84 | ctx->LoadIdentity(); 85 | } 86 | 87 | void ImGui_ImplSource_RenderDrawData( ImDrawData *draw_data ) 88 | { 89 | // Avoid rendering when minimized 90 | if ( draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f ) 91 | return; 92 | 93 | CMatRenderContextPtr ctx( materials ); 94 | 95 | ctx->MatrixMode( MATERIAL_VIEW ); 96 | ctx->PushMatrix(); 97 | ctx->MatrixMode( MATERIAL_PROJECTION ); 98 | ctx->PushMatrix(); 99 | 100 | ImGui_ImplSource_SetupRenderState( ctx, draw_data ); 101 | 102 | // Render command lists 103 | ImVec2 clip_off = draw_data->DisplayPos; 104 | for ( int n = 0; n < draw_data->CmdListsCount; n++ ) 105 | { 106 | const ImDrawList *cmd_list = draw_data->CmdLists[n]; 107 | const ImDrawIdx *idx_buffer = cmd_list->IdxBuffer.Data; 108 | 109 | // Draw the mesh 110 | for ( int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++ ) 111 | { 112 | const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i]; 113 | if ( pcmd->UserCallback != nullptr ) 114 | { 115 | // User callback, registered via ImDrawList::AddCallback() 116 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) 117 | if ( pcmd->UserCallback == ImDrawCallback_ResetRenderState ) 118 | ImGui_ImplSource_SetupRenderState( ctx, draw_data ); 119 | else 120 | pcmd->UserCallback( cmd_list, pcmd ); 121 | } 122 | else 123 | { 124 | if ( pcmd->GetTexID() ) 125 | { 126 | Vector2D clipmin = { pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y }; 127 | Vector2D clipmax = { pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y }; 128 | 129 | // Avoid rendering completely clipped draws 130 | if ( clipmax.x <= clipmin.x || clipmax.y <= clipmin.y ) 131 | continue; 132 | 133 | ctx->SetScissorRect( clipmin.x, clipmin.y, clipmax.x, clipmax.y, true ); 134 | IMesh *mesh = ctx->GetDynamicMesh( false, nullptr, nullptr, static_cast( pcmd->GetTexID() ) ); 135 | CMeshBuilder mb; 136 | mb.Begin( mesh, MATERIAL_TRIANGLES, cmd_list->VtxBuffer.Size, pcmd->ElemCount ); 137 | 138 | const ImDrawVert *vtx_src = cmd_list->VtxBuffer.Data; 139 | for ( int i = 0; i < cmd_list->VtxBuffer.Size; i++ ) 140 | { 141 | mb.Position3f( Vector2DExpand( vtx_src->pos ), 0 ); 142 | mb.Color4ubv( reinterpret_cast( &vtx_src->col ) ); 143 | mb.TexCoord2fv( 0, &vtx_src->uv.x ); 144 | mb.AdvanceVertexF(); 145 | vtx_src++; 146 | } 147 | 148 | static_cast( mb ).FastIndexList( idx_buffer + pcmd->IdxOffset, 0, pcmd->ElemCount ); 149 | mb.End( false, true ); 150 | ctx->SetScissorRect( clipmin.x, clipmin.y, clipmax.x, clipmax.y, false ); 151 | } 152 | } 153 | } 154 | } 155 | 156 | ctx->MatrixMode( MATERIAL_PROJECTION ); 157 | ctx->PopMatrix(); 158 | ctx->MatrixMode( MATERIAL_VIEW ); 159 | ctx->PopMatrix(); 160 | } 161 | 162 | bool ImGui_ImplSource_Init() 163 | { 164 | // Setup backend capabilities flags 165 | ImGuiIO &io = ImGui::GetIO(); 166 | io.BackendPlatformName = "source"; 167 | io.BackendRendererName = "imgui_impl_source"; 168 | io.BackendFlags = ImGuiBackendFlags_None; 169 | io.SetClipboardTextFn = []( void *, const char *c ) 170 | { 171 | vgui::system()->SetClipboardText( c, V_strlen( c ) ); 172 | }; 173 | io.GetClipboardTextFn = []( void *ctx ) -> const char * 174 | { 175 | auto &g = *static_cast( ctx ); 176 | g.ClipboardHandlerData.clear(); 177 | auto len = vgui::system()->GetClipboardTextCount(); 178 | if ( !len ) 179 | return nullptr; 180 | g.ClipboardHandlerData.resize( len ); 181 | vgui::system()->GetClipboardText( 0, g.ClipboardHandlerData.Data, g.ClipboardHandlerData.Size ); 182 | return g.ClipboardHandlerData.Data; 183 | }; 184 | 185 | ImGui_ImplSource_CreateDeviceObjects(); 186 | return true; 187 | } 188 | 189 | void ImGui_ImplSource_Shutdown() 190 | { 191 | ImGui_ImplSource_InvalidateDeviceObjects(); 192 | } 193 | 194 | static bool ImGui_ImplSource_CreateFontsTexture() 195 | { 196 | if ( g_pFontMat ) 197 | return true; 198 | 199 | // Build texture atlas 200 | ImGuiIO &io = ImGui::GetIO(); 201 | int width, height; 202 | unsigned char* pixels; 203 | io.Fonts->GetTexDataAsRGBA32( &pixels, &width, &height ); 204 | 205 | // Create a material for the texture 206 | ITexture *fonttex = g_pMaterialSystem->CreateProceduralTexture( "imgui_font", TEXTURE_GROUP_OTHER, width, height, IMAGE_FORMAT_RGBA8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_NOLOD ); 207 | fonttex->SetTextureRegenerator( new CDearImGuiFontTextureRegenerator ); 208 | fonttex->Download(); 209 | 210 | KeyValues *vmt = new KeyValues( "UnlitGeneric" ); 211 | vmt->SetString( "$basetexture", "imgui_font" ); 212 | vmt->SetInt( "$nocull", 1 ); 213 | vmt->SetInt( "$vertexcolor", 1 ); 214 | vmt->SetInt( "$vertexalpha", 1 ); 215 | vmt->SetInt( "$translucent", 1 ); 216 | g_pFontMat = materials->CreateMaterial( "imgui_font_mat", vmt ); 217 | g_pFontMat->AddRef(); 218 | 219 | // Store our identifier 220 | io.Fonts->SetTexID( g_pFontMat ); 221 | 222 | return true; 223 | } 224 | 225 | bool ImGui_ImplSource_CreateDeviceObjects() 226 | { 227 | return ImGui_ImplSource_CreateFontsTexture(); 228 | } 229 | 230 | void ImGui_ImplSource_InvalidateDeviceObjects() 231 | { 232 | if ( g_pFontMat ) 233 | { 234 | g_pFontMat->DecrementReferenceCount(); 235 | g_pFontMat = nullptr; 236 | } 237 | } 238 | 239 | // The following functions are declared in imconfig_source.h and must not be renamed 240 | 241 | ImFileHandle ImFileOpen( const char *filename, const char *mode ) 242 | { 243 | Assert( g_pFullFileSystem ); 244 | return g_pFullFileSystem->Open( filename, mode ); 245 | } 246 | 247 | bool ImFileClose( ImFileHandle f ) 248 | { 249 | if ( f == nullptr ) 250 | return false; 251 | 252 | Assert( g_pFullFileSystem ); 253 | g_pFullFileSystem->Close( f ); 254 | return true; 255 | } 256 | 257 | uint64 ImFileGetSize( ImFileHandle f ) 258 | { 259 | Assert( g_pFullFileSystem && f ); 260 | 261 | return g_pFullFileSystem->Size( f ); 262 | } 263 | 264 | uint64 ImFileRead( void *data, uint64 sz, uint64 count, ImFileHandle f ) 265 | { 266 | Assert( g_pFullFileSystem && f ); 267 | 268 | return g_pFullFileSystem->Read( data, sz * count, f ); 269 | } 270 | 271 | uint64 ImFileWrite( const void *data, uint64 sz, uint64 count, ImFileHandle f ) 272 | { 273 | Assert( g_pFullFileSystem && f ); 274 | 275 | return g_pFullFileSystem->Write( data, sz * count, f ); 276 | } 277 | -------------------------------------------------------------------------------- /imgui/imgui_impl_source.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | * MIT License 3 | * 4 | * Copyright (c) 2023 Strata Source Contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | *********************************************************************************/ 24 | #pragma once 25 | 26 | #include "imgui/imgui.h" 27 | 28 | struct ImDrawData; 29 | bool ImGui_ImplSource_Init(); 30 | void ImGui_ImplSource_Shutdown(); 31 | void ImGui_ImplSource_RenderDrawData(ImDrawData* draw_data); 32 | 33 | // Use if you want to reset your rendering device without losing Dear ImGui state. 34 | bool ImGui_ImplSource_CreateDeviceObjects(); 35 | void ImGui_ImplSource_InvalidateDeviceObjects(); 36 | 37 | // Translation table for imgui keys 38 | constexpr ImGuiKey IMGUI_KEY_TABLE[] = { 39 | 40 | /*KEY_NONE*/ ImGuiKey_None, 41 | /*KEY_0*/ ImGuiKey_0, 42 | /*KEY_1*/ ImGuiKey_1, 43 | /*KEY_2*/ ImGuiKey_2, 44 | /*KEY_3*/ ImGuiKey_3, 45 | /*KEY_4*/ ImGuiKey_4, 46 | /*KEY_5*/ ImGuiKey_5, 47 | /*KEY_6*/ ImGuiKey_6, 48 | /*KEY_7*/ ImGuiKey_7, 49 | /*KEY_8*/ ImGuiKey_8, 50 | /*KEY_9*/ ImGuiKey_9, 51 | /*KEY_A*/ ImGuiKey_A, 52 | /*KEY_B*/ ImGuiKey_B, 53 | /*KEY_C*/ ImGuiKey_C, 54 | /*KEY_D*/ ImGuiKey_D, 55 | /*KEY_E*/ ImGuiKey_E, 56 | /*KEY_F*/ ImGuiKey_F, 57 | /*KEY_G*/ ImGuiKey_G, 58 | /*KEY_H*/ ImGuiKey_H, 59 | /*KEY_I*/ ImGuiKey_I, 60 | /*KEY_J*/ ImGuiKey_J, 61 | /*KEY_K*/ ImGuiKey_K, 62 | /*KEY_L*/ ImGuiKey_L, 63 | /*KEY_M*/ ImGuiKey_M, 64 | /*KEY_N*/ ImGuiKey_N, 65 | /*KEY_O*/ ImGuiKey_O, 66 | /*KEY_P*/ ImGuiKey_P, 67 | /*KEY_Q*/ ImGuiKey_Q, 68 | /*KEY_R*/ ImGuiKey_R, 69 | /*KEY_S*/ ImGuiKey_S, 70 | /*KEY_T*/ ImGuiKey_T, 71 | /*KEY_U*/ ImGuiKey_U, 72 | /*KEY_V*/ ImGuiKey_V, 73 | /*KEY_W*/ ImGuiKey_W, 74 | /*KEY_X*/ ImGuiKey_X, 75 | /*KEY_Y*/ ImGuiKey_Y, 76 | /*KEY_Z*/ ImGuiKey_Z, 77 | /*KEY_PAD_0*/ ImGuiKey_Keypad0, 78 | /*KEY_PAD_1*/ ImGuiKey_Keypad1, 79 | /*KEY_PAD_2*/ ImGuiKey_Keypad2, 80 | /*KEY_PAD_3*/ ImGuiKey_Keypad3, 81 | /*KEY_PAD_4*/ ImGuiKey_Keypad4, 82 | /*KEY_PAD_5*/ ImGuiKey_Keypad5, 83 | /*KEY_PAD_6*/ ImGuiKey_Keypad6, 84 | /*KEY_PAD_7*/ ImGuiKey_Keypad7, 85 | /*KEY_PAD_8*/ ImGuiKey_Keypad8, 86 | /*KEY_PAD_9*/ ImGuiKey_Keypad9, 87 | /*KEY_PAD_DIVIDE*/ ImGuiKey_KeypadDivide, 88 | /*KEY_PAD_MULTIPLY*/ ImGuiKey_KeypadMultiply, 89 | /*KEY_PAD_MINUS*/ ImGuiKey_KeypadSubtract, 90 | /*KEY_PAD_PLUS*/ ImGuiKey_KeypadAdd, 91 | /*KEY_PAD_ENTER*/ ImGuiKey_KeypadEnter, 92 | /*KEY_PAD_DECIMAL*/ ImGuiKey_KeypadDecimal, 93 | /*KEY_LBRACKET*/ ImGuiKey_LeftBracket, 94 | /*KEY_RBRACKET*/ ImGuiKey_RightBracket, 95 | /*KEY_SEMICOLON*/ ImGuiKey_Semicolon, 96 | /*KEY_APOSTROPHE*/ ImGuiKey_Apostrophe, 97 | /*KEY_BACKQUOTE*/ ImGuiKey_None, // ? 98 | /*KEY_COMMA*/ ImGuiKey_Comma, 99 | /*KEY_PERIOD*/ ImGuiKey_Period, 100 | /*KEY_SLASH*/ ImGuiKey_Slash, 101 | /*KEY_BACKSLASH*/ ImGuiKey_Backslash, 102 | /*KEY_MINUS*/ ImGuiKey_Minus, 103 | /*KEY_EQUAL*/ ImGuiKey_Equal, 104 | /*KEY_ENTER*/ ImGuiKey_Enter, 105 | /*KEY_SPACE*/ ImGuiKey_Space, 106 | /*KEY_BACKSPACE*/ ImGuiKey_Backspace, 107 | /*KEY_TAB*/ ImGuiKey_Tab, 108 | /*KEY_CAPSLOCK*/ ImGuiKey_CapsLock, 109 | /*KEY_NUMLOCK*/ ImGuiKey_NumLock, 110 | /*KEY_ESCAPE*/ ImGuiKey_Escape, 111 | /*KEY_SCROLLLOCK*/ ImGuiKey_ScrollLock, 112 | /*KEY_INSERT*/ ImGuiKey_Insert, 113 | /*KEY_DELETE*/ ImGuiKey_Delete, 114 | /*KEY_HOME*/ ImGuiKey_Home, 115 | /*KEY_END*/ ImGuiKey_End, 116 | /*KEY_PAGEUP*/ ImGuiKey_PageUp, 117 | /*KEY_PAGEDOWN*/ ImGuiKey_PageDown, 118 | /*KEY_BREAK*/ ImGuiKey_None, // ? 119 | /*KEY_LSHIFT*/ ImGuiKey_LeftShift, 120 | /*KEY_RSHIFT*/ ImGuiKey_RightShift, 121 | /*KEY_LALT*/ ImGuiKey_LeftAlt, 122 | /*KEY_RALT*/ ImGuiKey_RightAlt, 123 | /*KEY_LCONTROL*/ ImGuiKey_LeftCtrl, 124 | /*KEY_RCONTROL*/ ImGuiKey_RightCtrl, 125 | /*KEY_LWIN*/ ImGuiKey_LeftSuper, 126 | /*KEY_RWIN*/ ImGuiKey_RightSuper, 127 | /*KEY_APP*/ ImGuiKey_None, // ? 128 | /*KEY_UP*/ ImGuiKey_UpArrow, 129 | /*KEY_LEFT*/ ImGuiKey_LeftArrow, 130 | /*KEY_DOWN*/ ImGuiKey_DownArrow, 131 | /*KEY_RIGHT*/ ImGuiKey_RightArrow, 132 | /*KEY_F1*/ ImGuiKey_F1, 133 | /*KEY_F2*/ ImGuiKey_F2, 134 | /*KEY_F3*/ ImGuiKey_F3, 135 | /*KEY_F4*/ ImGuiKey_F4, 136 | /*KEY_F5*/ ImGuiKey_F5, 137 | /*KEY_F6*/ ImGuiKey_F6, 138 | /*KEY_F7*/ ImGuiKey_F7, 139 | /*KEY_F8*/ ImGuiKey_F8, 140 | /*KEY_F9*/ ImGuiKey_F9, 141 | /*KEY_F10*/ ImGuiKey_F10, 142 | /*KEY_F11*/ ImGuiKey_F11, 143 | /*KEY_F12*/ ImGuiKey_F12, 144 | /*KEY_CAPSLOCKTOGGLE*/ ImGuiKey_None, // ? 145 | /*KEY_NUMLOCKTOGGLE*/ ImGuiKey_None, // ? 146 | /*KEY_SCROLLLOCKTOGGLE*/ImGuiKey_None, // ? 147 | }; 148 | -------------------------------------------------------------------------------- /imgui/imgui_system.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | * MIT License 3 | * 4 | * Copyright (c) 2023 Strata Source Contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | *********************************************************************************/ 24 | #include "imgui_system.h" 25 | #include "imgui_window.h" 26 | 27 | #include "filesystem.h" 28 | #include "fmtstr.h" 29 | #include "imgui_impl_source.h" 30 | #include "inputsystem/iinputsystem.h" 31 | #include "materialsystem/imaterialsystem.h" 32 | #include "strtools.h" 33 | #include "tier2/tier2.h" 34 | #include "tier3/tier3.h" 35 | #include "utldict.h" 36 | #include "imgui/imgui.h" 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include "ienginevgui.h" 47 | 48 | #include "tier0/memdbgon.h" 49 | 50 | class CDummyOverlayPanel; 51 | 52 | CUtlVector &ImGuiWindows(); 53 | 54 | static ConVar imgui_font_scale( "imgui_font_scale", "1", FCVAR_ARCHIVE, "Global scale applied to Imgui fonts" ); 55 | static ConVar imgui_display_scale( "imgui_display_scale", "1", FCVAR_ARCHIVE, "Global imgui scale, usually used for Hi-DPI displays" ); 56 | 57 | void *ImGui_MemAlloc( size_t sz, void *user_data ) 58 | { 59 | return MemAlloc_Alloc( sz, "Dear ImGui", 0 ); 60 | } 61 | 62 | static void ImGui_MemFree( void *ptr, void *user_data ) 63 | { 64 | MemAlloc_Free( ptr ); 65 | } 66 | 67 | //---------------------------------------------------------------------------------------// 68 | // Global helpers 69 | //---------------------------------------------------------------------------------------// 70 | 71 | CUtlVector &ImGuiWindows() 72 | { 73 | static CUtlVector s_DearImGuiWindows; 74 | return s_DearImGuiWindows; 75 | } 76 | 77 | void RegisterImGuiWindowFactory( IImguiWindow *pWindow ) 78 | { 79 | ImGuiWindows().AddToTail( pWindow ); 80 | } 81 | 82 | 83 | //---------------------------------------------------------------------------------------// 84 | // Purpose: Implementation of the imgui system 85 | //---------------------------------------------------------------------------------------// 86 | class CDearImGuiSystem : public IImguiSystem 87 | { 88 | using BaseClass = IImguiSystem; 89 | 90 | public: 91 | // IAppSystem 92 | bool Init() override; 93 | void Shutdown() override; 94 | 95 | // IDearImGuiSystem 96 | DearImGuiSysData_t GetData() override; 97 | void Render() override; 98 | void RegisterWindowFactories( IImguiWindow **arrpWindows, int nCount ) override; 99 | IImguiWindow *FindWindow( const char *szName ) override; 100 | void UnregisterWindowFactories( IImguiWindow **ppWindows, int nCount ) override; 101 | void GetAllWindows( CUtlVector &windows ) override; 102 | void SetWindowVisible( IImguiWindow* pWindow, bool bVisible, bool bEnableInput ) override; 103 | 104 | bool DrawWindow( IImguiWindow *pWindow ); 105 | 106 | void PushInputContext(); 107 | void PopInputContext(); 108 | 109 | // True if our input context is enabled in any capacity 110 | bool IsInputContextEnabled() const { return m_bInputEnabled; } 111 | 112 | void SetStyle(); 113 | void DrawMenuBar(); 114 | 115 | void SetDrawMenuBar( bool bEnable ) { m_bDrawMenuBar = bEnable; } 116 | bool IsDrawingMenuBar() const { return m_bDrawMenuBar; } 117 | void ToggleMenuBar() { m_bDrawMenuBar = !m_bDrawMenuBar; } 118 | 119 | public: 120 | CUtlDict m_ImGuiWindows; 121 | 122 | double m_flLastFrameTime; 123 | bool m_bInputEnabled = false; 124 | 125 | bool m_bDrawMenuBar = false; 126 | bool m_bDrawMetrics = false; 127 | bool m_bDrawDemo = false; 128 | CDummyOverlayPanel* m_pInputOverlay = nullptr; 129 | }; 130 | 131 | static CDearImGuiSystem g_ImguiSystem; 132 | IImguiSystem* g_pImguiSystem = &g_ImguiSystem; 133 | 134 | //---------------------------------------------------------------------------------------// 135 | // Purpose: Dummy overlay panel for capturing input 136 | //---------------------------------------------------------------------------------------// 137 | class CDummyOverlayPanel : public vgui::Panel 138 | { 139 | public: 140 | CDummyOverlayPanel() 141 | { 142 | SetVisible( false ); 143 | SetParent( enginevgui->GetPanel( PANEL_GAMEUIDLL ) ); 144 | SetPaintEnabled( true ); 145 | SetCursor( vgui::dc_arrow ); 146 | 147 | SetPaintBorderEnabled( false ); 148 | SetPaintBackgroundEnabled( false ); 149 | MakePopup(); 150 | } 151 | 152 | void OnMousePressed( ButtonCode_t code ) override 153 | { 154 | auto& io = ImGui::GetIO(); 155 | if ( io.WantCaptureMouse ) 156 | io.AddMouseButtonEvent( code - MOUSE_FIRST, true ); 157 | } 158 | 159 | void OnMouseReleased( ButtonCode_t code ) override 160 | { 161 | auto& io = ImGui::GetIO(); 162 | if ( io.WantCaptureMouse ) 163 | { 164 | io.AddMouseButtonEvent( code - MOUSE_FIRST, false ); 165 | } 166 | } 167 | 168 | void OnMouseWheeled( int delta ) override 169 | { 170 | auto& io = ImGui::GetIO(); 171 | io.AddMouseWheelEvent( 0, delta ); 172 | } 173 | 174 | void OnCursorMoved( int x, int y ) override 175 | { 176 | vgui::Panel::OnCursorMoved( x, y ); 177 | ImGui::GetIO().AddMousePosEvent( x, y ); 178 | } 179 | 180 | void OnMouseDoublePressed( ButtonCode_t code ) override 181 | { 182 | } 183 | 184 | void OnKeyTyped( wchar_t code ) override 185 | { 186 | auto& io = ImGui::GetIO(); 187 | if ( io.WantCaptureKeyboard ) 188 | io.AddInputCharacter( code ); 189 | } 190 | 191 | // always pass keycodes to imgui, WantCaptureKeyboard should NOT affect whether or not we do this 192 | void OnKeyCodePressed( vgui::KeyCode code ) override 193 | { 194 | auto& io = ImGui::GetIO(); 195 | io.AddKeyEvent( IMGUI_KEY_TABLE[code], true ); 196 | } 197 | 198 | void OnKeyCodeReleased( vgui::KeyCode code ) override 199 | { 200 | auto& io = ImGui::GetIO(); 201 | io.AddKeyEvent( IMGUI_KEY_TABLE[code], false ); 202 | } 203 | 204 | void Paint() override 205 | { 206 | g_pImguiSystem->Render(); 207 | } 208 | 209 | void Activate( bool bActive ) 210 | { 211 | SetVisible( bActive ); 212 | SetEnabled( bActive ); 213 | SetKeyBoardInputEnabled( bActive ); 214 | SetMouseInputEnabled( bActive ); 215 | 216 | if ( bActive ) 217 | { 218 | MoveToFront(); 219 | RequestFocus(); 220 | vgui::input()->SetMouseCapture( NULL ); 221 | } 222 | } 223 | }; 224 | 225 | //---------------------------------------------------------------------------------------// 226 | // Purpose: Init our dear friend 227 | //---------------------------------------------------------------------------------------// 228 | bool CDearImGuiSystem::Init() 229 | { 230 | ImGui::SetAllocatorFunctions( ImGui_MemAlloc, ImGui_MemFree, nullptr ); 231 | ImFontAtlas *atlas = new ImFontAtlas(); 232 | ImGui::CreateContext( atlas ); 233 | ImGui_ImplSource_Init(); 234 | 235 | SetStyle(); 236 | 237 | m_flLastFrameTime = Plat_FloatTime(); 238 | 239 | DearImGuiSysData_t data = g_pImguiSystem->GetData(); 240 | 241 | ImGui::SetAllocatorFunctions( (ImGuiMemAllocFunc)data.memallocfn, (ImGuiMemFreeFunc)data.memfreefn, nullptr ); 242 | ImGui::SetCurrentContext( (ImGuiContext *)data.context ); 243 | 244 | g_pImguiSystem->RegisterWindowFactories( ImGuiWindows().Base(), ImGuiWindows().Count() ); 245 | 246 | return true; 247 | } 248 | 249 | void CDearImGuiSystem::Shutdown() 250 | { 251 | g_pImguiSystem->UnregisterWindowFactories( ImGuiWindows().Base(), ImGuiWindows().Count() ); 252 | ImGui_ImplSource_Shutdown(); 253 | 254 | ImGui::DestroyContext(); 255 | } 256 | 257 | DearImGuiSysData_t CDearImGuiSystem::GetData() 258 | { 259 | DearImGuiSysData_t data; 260 | data.context = ImGui::GetCurrentContext(); 261 | data.memallocfn = ImGui_MemAlloc; 262 | data.memfreefn = ImGui_MemFree; 263 | return data; 264 | } 265 | 266 | //---------------------------------------------------------------------------------------// 267 | // Purpose: Render all imgui windows 268 | //---------------------------------------------------------------------------------------// 269 | void CDearImGuiSystem::Render() 270 | { 271 | // Update the IO 272 | auto &io = ImGui::GetIO(); 273 | 274 | // Create input overlay helper if it doesn't yet exist 275 | if ( !m_pInputOverlay ) 276 | { 277 | m_pInputOverlay = new CDummyOverlayPanel(); 278 | } 279 | 280 | // Update the screen size before drawing 281 | CMatRenderContextPtr pRenderContext( materials ); 282 | int w, h; 283 | pRenderContext->GetWindowSize( w, h ); 284 | if ( !w || !h ) 285 | return; 286 | 287 | m_pInputOverlay->SetSize( w, h ); 288 | 289 | io.DisplaySize.x = static_cast( w ); 290 | io.DisplaySize.y = static_cast( h ); 291 | io.DisplayFramebufferScale.x = io.DisplayFramebufferScale.y = imgui_display_scale.GetFloat(); 292 | io.FontGlobalScale = imgui_font_scale.GetFloat(); 293 | 294 | // Create new frame 295 | ImGui::NewFrame(); 296 | 297 | // Draw menubar first 298 | if ( m_bDrawMenuBar ) 299 | DrawMenuBar(); 300 | 301 | // Draw imgui-specific debug menus 302 | if ( m_bDrawDemo ) 303 | ImGui::ShowDemoWindow( &m_bDrawDemo ); 304 | 305 | if ( m_bDrawMetrics ) 306 | ImGui::ShowMetricsWindow( &m_bDrawMetrics ); 307 | 308 | // Draw everything else 309 | bool bDrawn = false; 310 | FOR_EACH_DICT( m_ImGuiWindows, i ) 311 | { 312 | auto *pWindow = m_ImGuiWindows[i]; 313 | if ( pWindow->ShouldDraw() ) 314 | { 315 | DrawWindow( pWindow ); 316 | bDrawn = true; 317 | } 318 | } 319 | 320 | ImGui::Render(); 321 | ImDrawData *drawdata = ImGui::GetDrawData(); 322 | if ( drawdata ) 323 | ImGui_ImplSource_RenderDrawData( drawdata ); 324 | 325 | // Post render, update deltas 326 | auto curtime = Plat_FloatTime(); 327 | auto dt = curtime - m_flLastFrameTime; 328 | m_flLastFrameTime = curtime; 329 | 330 | io.DeltaTime = static_cast( dt ); 331 | 332 | // Deactivate our overlay if nothing is being drawn anymore 333 | if ( !bDrawn && !m_bDrawDemo && !m_bDrawMetrics && !m_bDrawMenuBar ) 334 | { 335 | PopInputContext(); 336 | } 337 | } 338 | 339 | //---------------------------------------------------------------------------------------// 340 | // Purpose: Draws a window 341 | //---------------------------------------------------------------------------------------// 342 | bool CDearImGuiSystem::DrawWindow( IImguiWindow *pWindow ) 343 | { 344 | bool closeButton = pWindow->ShouldDraw(); 345 | ImGui::Begin( pWindow->GetWindowTitle(), &closeButton, pWindow->GetFlags() ); 346 | pWindow->SetDraw( closeButton ); 347 | 348 | bool stayOpen = pWindow->Draw(); 349 | ImGui::End(); 350 | return stayOpen; 351 | } 352 | 353 | //---------------------------------------------------------------------------------------// 354 | // Purpose: Register all window factories from another DLL 355 | //---------------------------------------------------------------------------------------// 356 | void CDearImGuiSystem::RegisterWindowFactories( IImguiWindow **arrpWindows, int nCount ) 357 | { 358 | for ( int i = 0; i < nCount; i++ ) 359 | { 360 | auto *pWindow = arrpWindows[i]; 361 | m_ImGuiWindows.Insert( pWindow->GetName(), pWindow ); 362 | } 363 | } 364 | 365 | //---------------------------------------------------------------------------------------// 366 | // Purpose: Unregister window factories, usually called on DLL shutdown 367 | //---------------------------------------------------------------------------------------// 368 | void CDearImGuiSystem::UnregisterWindowFactories( IImguiWindow **ppWindows, int nCount ) 369 | { 370 | for ( int i = 0; i < nCount; ++i ) 371 | { 372 | m_ImGuiWindows.Remove( ppWindows[i]->GetName() ); 373 | } 374 | } 375 | 376 | //---------------------------------------------------------------------------------------// 377 | // Purpose: find window by name 378 | //---------------------------------------------------------------------------------------// 379 | IImguiWindow *CDearImGuiSystem::FindWindow( const char *szName ) 380 | { 381 | if ( auto it = m_ImGuiWindows.Find( szName ); it != m_ImGuiWindows.InvalidIndex() ) 382 | return m_ImGuiWindows[it]; 383 | return nullptr; 384 | } 385 | 386 | //---------------------------------------------------------------------------------------// 387 | // Purpose: Returns a list of all windows into `windows` 388 | //---------------------------------------------------------------------------------------// 389 | void CDearImGuiSystem::GetAllWindows( CUtlVector &windows ) 390 | { 391 | windows.Purge(); 392 | FOR_EACH_DICT( m_ImGuiWindows, i ) 393 | windows.AddToTail( m_ImGuiWindows[i] ); 394 | } 395 | 396 | //---------------------------------------------------------------------------------------// 397 | // Purpose: Make a window visible 398 | //---------------------------------------------------------------------------------------// 399 | void CDearImGuiSystem::SetWindowVisible( IImguiWindow* pWindow, bool bVisible, bool bEnableInput ) 400 | { 401 | Assert( pWindow ); 402 | pWindow->SetDraw( bVisible ); 403 | if ( bVisible && bEnableInput ) 404 | PushInputContext(); 405 | else if ( !bVisible && bEnableInput ) 406 | PopInputContext(); 407 | } 408 | 409 | //---------------------------------------------------------------------------------------// 410 | // Purpose: Push a new input context so we can show the mouse cursor 411 | //---------------------------------------------------------------------------------------// 412 | void CDearImGuiSystem::PushInputContext() 413 | { 414 | if ( m_bInputEnabled ) 415 | return; 416 | 417 | if ( !m_pInputOverlay ) 418 | m_pInputOverlay = new CDummyOverlayPanel(); 419 | 420 | m_pInputOverlay->Activate( true ); 421 | m_bInputEnabled = true; 422 | } 423 | 424 | //---------------------------------------------------------------------------------------// 425 | // Purpose: Pop input context, returning mouse control to whatever needed it last 426 | //---------------------------------------------------------------------------------------// 427 | void CDearImGuiSystem::PopInputContext() 428 | { 429 | m_pInputOverlay->Activate( false ); 430 | m_bInputEnabled = false; 431 | } 432 | 433 | //---------------------------------------------------------------------------------------// 434 | // Purpose: Update Imgui style 435 | // TODO: User-configurable styles 436 | //---------------------------------------------------------------------------------------// 437 | void CDearImGuiSystem::SetStyle() 438 | { 439 | ImGuiStyle& style = ImGui::GetStyle(); 440 | style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 441 | style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 442 | style.Colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f); 443 | style.Colors[ImGuiCol_ChildBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f); 444 | style.Colors[ImGuiCol_PopupBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f); 445 | style.Colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); 446 | style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 447 | style.Colors[ImGuiCol_FrameBg] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); 448 | style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f); 449 | style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f); 450 | style.Colors[ImGuiCol_TitleBg] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f); 451 | style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f); 452 | style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); 453 | style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); 454 | style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); 455 | style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 456 | style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); 457 | style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); 458 | style.Colors[ImGuiCol_CheckMark] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f); 459 | style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f); 460 | style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.08f, 0.50f, 0.72f, 1.00f); 461 | style.Colors[ImGuiCol_Button] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); 462 | style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f); 463 | style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f); 464 | style.Colors[ImGuiCol_Header] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f); 465 | style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); 466 | style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f); 467 | style.Colors[ImGuiCol_Separator] = style.Colors[ImGuiCol_Border]; 468 | style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.41f, 0.42f, 0.44f, 1.00f); 469 | style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 470 | style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 471 | style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.29f, 0.30f, 0.31f, 0.67f); 472 | style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 473 | style.Colors[ImGuiCol_Tab] = ImVec4(0.08f, 0.08f, 0.09f, 0.83f); 474 | style.Colors[ImGuiCol_TabHovered] = ImVec4(0.33f, 0.34f, 0.36f, 0.83f); 475 | style.Colors[ImGuiCol_TabActive] = ImVec4(0.23f, 0.23f, 0.24f, 1.00f); 476 | style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f); 477 | style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f); 478 | style.Colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); 479 | style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); 480 | style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 481 | style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); 482 | style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); 483 | style.Colors[ImGuiCol_DragDropTarget] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f); 484 | style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 485 | style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 486 | style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); 487 | style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); 488 | style.GrabRounding = style.FrameRounding = 2.3f; 489 | } 490 | 491 | //---------------------------------------------------------------------------------------// 492 | // Purpose: Draws the menu bar as a top-level window 493 | //---------------------------------------------------------------------------------------// 494 | void CDearImGuiSystem::DrawMenuBar() 495 | { 496 | if ( ImGui::BeginMainMenuBar() ) 497 | { 498 | if ( ImGui::BeginMenu( "File" ) ) 499 | { 500 | if ( ImGui::MenuItem( "Close Menu" ) ) 501 | { 502 | this->m_bDrawMenuBar = false; 503 | this->PopInputContext(); 504 | } 505 | ImGui::EndMenu(); 506 | } 507 | if ( ImGui::BeginMenu( "Windows" ) ) 508 | { 509 | CUtlVector windows; 510 | g_pImguiSystem->GetAllWindows( windows ); 511 | 512 | for ( auto &window : windows ) 513 | { 514 | bool bToggle = window->ShouldDraw(); 515 | if ( ImGui::MenuItem( window->GetWindowTitle(), "", &bToggle ) ) 516 | window->SetDraw( bToggle ); 517 | } 518 | 519 | ImGui::EndMenu(); 520 | } 521 | 522 | if ( ImGui::BeginMenu( "Debug" ) ) 523 | { 524 | ImGui::MenuItem( "Show Demo Window", "", &m_bDrawDemo ); 525 | ImGui::MenuItem( "Show Metrics Window", "", &m_bDrawMetrics ); 526 | 527 | ImGui::EndMenu(); 528 | } 529 | ImGui::EndMainMenuBar(); 530 | } 531 | } 532 | 533 | //---------------------------------------------------------------------------------------// 534 | // Purpose: Implementation of imgui_show command 535 | //---------------------------------------------------------------------------------------// 536 | class CImGuiShowAutoCompletionFunctor : public ICommandCallback, 537 | public ICommandCompletionCallback 538 | { 539 | public: 540 | void CommandCallback( const CCommand &command ) override 541 | { 542 | if ( command.ArgC() < 2 ) 543 | { 544 | Msg( "Format: imgui_show \n" ); 545 | return; 546 | } 547 | 548 | // Get our window 549 | const char *pKey = command.Arg( 1 ); 550 | auto *pWindow = g_ImguiSystem.FindWindow( pKey ); 551 | 552 | if ( !pWindow ) 553 | { 554 | Warning( "Failed to find ImGUI window called %s\n", pKey ); 555 | return; 556 | } 557 | 558 | pWindow->ToggleDraw(); 559 | } 560 | 561 | int CommandCompletionCallback( const char *partial, CUtlVector &commands ) override 562 | { 563 | auto &windows = g_ImguiSystem.m_ImGuiWindows; 564 | FOR_EACH_DICT( windows, i ) 565 | { 566 | commands.AddToTail( CFmtStr( "%s %s", "imgui_show", windows[i]->GetName() ).Get() ); 567 | } 568 | 569 | return commands.Count(); 570 | } 571 | }; 572 | 573 | static CImGuiShowAutoCompletionFunctor g_ImGuiShowAutoComplete; 574 | static ConCommand imgui_show( "imgui_show", &g_ImGuiShowAutoComplete, "Toggles the specified imgui window", FCVAR_CLIENTDLL, &g_ImGuiShowAutoComplete ); 575 | 576 | //---------------------------------------------------------------------------------------// 577 | // Purpose: Toggle input for imgui windows 578 | //---------------------------------------------------------------------------------------// 579 | CON_COMMAND_F( imgui_toggle_input, "Toggles the mouse cursor for imgui windows", FCVAR_CLIENTDLL ) 580 | { 581 | if ( g_ImguiSystem.IsInputContextEnabled() ) 582 | g_ImguiSystem.PopInputContext(); 583 | else 584 | g_ImguiSystem.PushInputContext(); 585 | } 586 | 587 | static ConCommand imgui_input_start( 588 | "+imgui_input", []( const CCommand &args ) 589 | { 590 | g_ImguiSystem.PushInputContext(); 591 | }, 592 | "Toggles the mouse cursor for imgui windows, same as imgui_toggle_input", FCVAR_CLIENTDLL ); 593 | 594 | static ConCommand imgui_input_end( 595 | "-imgui_input", []( const CCommand &args ) 596 | { 597 | g_ImguiSystem.PopInputContext(); 598 | }, 599 | "Toggles the mouse cursor for imgui windows, same as imgui_toggle_input", FCVAR_CLIENTDLL ); 600 | 601 | //---------------------------------------------------------------------------------------// 602 | // Purpose: Toggles the built-in menu bar (and input) 603 | //---------------------------------------------------------------------------------------// 604 | 605 | CON_COMMAND_F( imgui_toggle_menu, "Toggles the imgui menu bar", FCVAR_CLIENTDLL ) 606 | { 607 | g_ImguiSystem.ToggleMenuBar(); 608 | if ( g_ImguiSystem.IsDrawingMenuBar() ) 609 | g_ImguiSystem.PushInputContext(); 610 | else 611 | g_ImguiSystem.PopInputContext(); 612 | } 613 | 614 | template 615 | void CC_ToggleMenu( const CCommand &args ) 616 | { 617 | g_ImguiSystem.SetDrawMenuBar( ON ); 618 | if constexpr ( ON ) 619 | g_ImguiSystem.PushInputContext(); 620 | else 621 | g_ImguiSystem.PopInputContext(); 622 | } 623 | 624 | static ConCommand imgui_menu_start( "+imgui_menu", CC_ToggleMenu, "Toggles the menu bar and input", FCVAR_CLIENTDLL ); 625 | static ConCommand imgui_menu_end( "-imgui_menu", CC_ToggleMenu, "Toggles the menu bar and input", FCVAR_CLIENTDLL ); 626 | 627 | CON_COMMAND_F( imgui_show_demo, "Shows the imgui demo", FCVAR_CLIENTDLL ) 628 | { 629 | g_ImguiSystem.m_bDrawDemo = true; 630 | } 631 | -------------------------------------------------------------------------------- /imgui/imgui_system.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | * MIT License 3 | * 4 | * Copyright (c) 2023 Strata Source Contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | *********************************************************************************/ 24 | #pragma once 25 | 26 | #include "appframework/IAppSystem.h" 27 | #include "inputsystem/InputEnums.h" 28 | #include "utlvector.h" 29 | 30 | struct DearImGuiSysData_t 31 | { 32 | void *context; 33 | void *( *memallocfn )( size_t sz, void *user_data ); 34 | void ( *memfreefn )( void *ptr, void *user_data ); 35 | }; 36 | 37 | class IImguiWindow; 38 | 39 | abstract_class IImguiSystem 40 | { 41 | public: 42 | virtual bool Init() = 0; 43 | 44 | virtual void Shutdown() = 0; 45 | 46 | virtual DearImGuiSysData_t GetData() = 0; 47 | 48 | virtual void Render() = 0; 49 | 50 | virtual void RegisterWindowFactories( IImguiWindow * *arrpWindows, int nCount ) = 0; 51 | 52 | virtual void UnregisterWindowFactories( IImguiWindow * *ppWindows, int nCount ) = 0; 53 | 54 | virtual IImguiWindow *FindWindow( const char *szName ) = 0; 55 | 56 | virtual void GetAllWindows( CUtlVector & windows ) = 0; 57 | 58 | virtual void SetWindowVisible( IImguiWindow* pWindow, bool bVisible, bool bEnableInput = true ) = 0; 59 | }; 60 | 61 | extern IImguiSystem *g_pImguiSystem; 62 | -------------------------------------------------------------------------------- /imgui/imgui_system.vpc: -------------------------------------------------------------------------------- 1 | 2 | $Macro IMGUI_DIR "$SRCDIR\imgui" 3 | 4 | $Configuration 5 | { 6 | $Compiler 7 | { 8 | $PreprocessorDefinitions "$BASE;IMGUI_DISABLE_INCLUDE_IMCONFIG_H;IMGUI_USER_CONFIG=\$QUOTEimgui/imconfig_source.h\$QUOTE" 9 | $AdditionalIncludeDirectories "$BASE;$IMGUI_DIR;$IMGUI_DIR/thirdparty" 10 | } 11 | } 12 | 13 | $Project 14 | { 15 | $Folder "Source Files" 16 | { 17 | $File "$IMGUI_DIR/imgui/imgui_impl_source.cpp" 18 | $File "$IMGUI_DIR/imgui/imgui_system.cpp" 19 | 20 | $Folder "ImGUI" 21 | { 22 | $File "$IMGUI_DIR/thirdparty/imgui/imgui.cpp" \ 23 | "$IMGUI_DIR/thirdparty/imgui/imgui_demo.cpp" \ 24 | "$IMGUI_DIR/thirdparty/imgui/imgui_draw.cpp" \ 25 | "$IMGUI_DIR/thirdparty/imgui/imgui_tables.cpp" \ 26 | "$IMGUI_DIR/thirdparty/imgui/imgui_widgets.cpp" 27 | { 28 | $Configuration 29 | { 30 | $Compiler 31 | { 32 | $Create/UsePrecompiledHeader "Not Using Precompiled Headers" 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | $Folder "Header Files" 40 | { 41 | $File "$IMGUI_DIR/imgui/imconfig_source.h" 42 | $File "$IMGUI_DIR/imgui/imgui_impl_source.h" 43 | $File "$IMGUI_DIR/imgui/imgui_system.h" 44 | $File "$IMGUI_DIR/imgui/imgui_window.h" 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /imgui/imgui_window.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | * MIT License 3 | * 4 | * Copyright (c) 2023 Strata Source Contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | *********************************************************************************/ 24 | #pragma once 25 | 26 | #include "imgui/imgui.h" 27 | 28 | #include "imgui_system.h" 29 | #include "utlmap.h" 30 | 31 | // Implemented by devui_static 32 | extern void RegisterImGuiWindowFactory( IImguiWindow *pWindow ); 33 | 34 | //--------------------------------------------------------------------------------// 35 | // Purpose: Interface implemented by each window. Use with DEFINE_DEVUI_WINDOW. 36 | //--------------------------------------------------------------------------------// 37 | class IImguiWindow 38 | { 39 | public: 40 | IImguiWindow() = delete; 41 | 42 | IImguiWindow( const char *pszName, const char* pszTitle ) : 43 | m_pName( pszName ), 44 | m_pTitle( pszTitle ) 45 | { 46 | RegisterImGuiWindowFactory( this ); 47 | } 48 | 49 | virtual ~IImguiWindow() = default; 50 | 51 | // Must be implemented by subclasses 52 | // Returns true to indicate if this window should continue to stay open 53 | virtual bool Draw() = 0; 54 | 55 | // Default implementations provided 56 | virtual bool ShouldDraw() { return m_bEnabled; } 57 | 58 | virtual void ToggleDraw() 59 | { 60 | m_bEnabled = !m_bEnabled; 61 | OnChangeVisibility(); 62 | } 63 | 64 | virtual void SetDraw( bool bState ) 65 | { 66 | bool old = m_bEnabled; 67 | m_bEnabled = bState; 68 | if ( old != m_bEnabled ) 69 | OnChangeVisibility(); 70 | } 71 | 72 | // Returns window flags for this window, override this if you want (Or use DECLARE_DEVUI_WINDOW_F) 73 | virtual ImGuiWindowFlags GetFlags() const { return ImGuiWindowFlags_None; } 74 | 75 | // Returns the internal reference name of the window 76 | const char *GetName() const { return m_pName; } 77 | 78 | // Returns the window title. This will be passed to ImGui::Begin and displayed in the menu 79 | virtual const char *GetWindowTitle() const { return m_pTitle; } 80 | 81 | virtual void OnChangeVisibility() {} 82 | 83 | protected: 84 | bool m_bEnabled = false; 85 | const char *m_pName; 86 | const char* m_pTitle; 87 | }; 88 | 89 | // Defines an imgui window 90 | #define DEFINE_IMGUI_WINDOW( _className ) \ 91 | static _className __s_##_className##_registrar; 92 | 93 | 94 | // Helper macro for simpler windows 95 | #define DECLARE_IMGUI_WINDOW_F( name, _title, _flags ) \ 96 | class CDearImGuiWindow##name : public IImguiWindow \ 97 | { \ 98 | public: \ 99 | CDearImGuiWindow##name() : IImguiWindow( #name, _title ) \ 100 | { \ 101 | } \ 102 | bool Draw() override; \ 103 | ImGuiWindowFlags GetFlags() const override { return _flags; } \ 104 | }; \ 105 | static CDearImGuiWindow##name _s_dearimguiwindow##name; \ 106 | bool CDearImGuiWindow##name::Draw() 107 | 108 | 109 | #define DECLARE_IMGUI_WINDOW( _name, _title ) DECLARE_IMGUI_WINDOW_F( _name, _title, ImGuiWindowFlags_None ) 110 | --------------------------------------------------------------------------------