feat(Client): Added ImGui implementation.

Source:
`https://github.com/JJL772/source-2013-imgui`
This commit is contained in:
tupoy-ya 2023-10-08 11:02:36 +05:00
parent da0a943bcb
commit 39ab429ca7
No known key found for this signature in database
GPG Key ID: 3541E2B1B448A2DB
10 changed files with 1337 additions and 9 deletions

View File

@ -87,6 +87,7 @@
#include "ihudlcd.h"
#include "toolframework_client.h"
#include "hltvcamera.h"
#include "imgui/imgui_system.h"
#if defined( REPLAY_ENABLED )
#include "replay/replaycamera.h"
#include "replay/replay_ragdoll.h"
@ -1101,6 +1102,8 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi
HookHapticMessages(); // Always hook the messages
#endif
g_pImguiSystem->Init();
return true;
}
@ -1180,6 +1183,8 @@ void CHLClient::Shutdown( void )
g_pAchievementsAndStatsInterface->ReleasePanel();
}
g_pImguiSystem->Shutdown();
#ifdef SIXENSE
g_pSixenseInput->Shutdown();
delete g_pSixenseInput;

View File

@ -14,6 +14,7 @@ $Macro GENERATED_PROTO_DIR "$SRCDIR\game\client\generated_proto_$GAMENAME"
$MacroRequired "GAMENAME"
$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
$Include "$SRCDIR\game\client\imgui\imgui_system.vpc"
$include "$SRCDIR\vpc_scripts\protobuf_builder.vpc"
$Include "$SRCDIR\vpc_scripts\source_replay.vpc" [$TF]
@ -51,7 +52,7 @@ $Configuration
$Compiler
{
$AdditionalIncludeDirectories ".\;$BASE;$SRCDIR\vgui2\include;$SRCDIR\vgui2\controls;$SRCDIR\game\shared;.\game_controls;$SRCDIR\thirdparty\sixensesdk\include"
$PreprocessorDefinitions "$BASE;GLOWS_ENABLE;MAPBASE_VSCRIPT;NO_STRING_T;CLIENT_DLL;VECTOR;VERSION_SAFE_STEAM_API_INTERFACES;PROTECTED_THINGS_ENABLE;strncpy=use_Q_strncpy_instead;_snprintf=use_Q_snprintf_instead"
$PreprocessorDefinitions "$BASE;GLOWS_ENABLE;MAPBASE_VSCRIPT;NO_STRING_T;CLIENT_DLL;VECTOR;VERSION_SAFE_STEAM_API_INTERFACES;PROTECTED_THINGS_ENABLE;"
$PreprocessorDefinitions "$BASE;ENABLE_CHROMEHTMLWINDOW;fopen=dont_use_fopen" [$WIN32]
$PreprocessorDefinitions "$BASE;ENABLE_CHROMEHTMLWINDOW;" [$OSXALL]
$PreprocessorDefinitions "$BASE;ENABLE_CHROMEHTMLWINDOW;USE_WEBM_FOR_REPLAY;" [$LINUXALL]

View File

@ -0,0 +1,60 @@
#pragma once
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
// Use tier0's asserts
#include "tier0/dbg.h"
#undef IM_ASSERT
#define IM_ASSERT Assert
// We provide our own allocators.
#define IMGUI_DISABLE_DEFAULT_ALLOCATORS
// We do not define Dear ImGui's api to cross dll boundaries.
// Instead, everything that wants to use Dear ImGui can link devui_static.lib.
#define IMGUI_API
// Disable obsolete APIs. No need to make more work for ourselves.
#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
#define IMGUI_DISABLE_OBSOLETE_KEYIO
// Let's not link win32 for everything we include Dear ImGui with...
#define IMGUI_DISABLE_WIN32_FUNCTIONS
// 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
#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
using ImFileHandle = void*;
IMGUI_API ImFileHandle ImFileOpen( const char *filename, const char *mode );
IMGUI_API bool ImFileClose( ImFileHandle file );
IMGUI_API uint64 ImFileGetSize( ImFileHandle file );
IMGUI_API uint64 ImFileRead( void *data, uint64 size, uint64 count, ImFileHandle file );
IMGUI_API uint64 ImFileWrite( const void *data, uint64 size, uint64 count, ImFileHandle file );
// Source's colors are stored as BGRA. Setting this allows us to avoid per vertex swizzles in mesh builder.
// On Linux and Mac, mesh builder already does these swizzles regardless
#if !defined( OPENGL_COLOR_SWAP )
#define IMGUI_USE_BGRA_PACKED_COLOR
#endif
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// 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.
//#define IMGUI_USE_STB_SPRINTF
#include "mathlib/vector2d.h"
#include "mathlib/vector4d.h"
#define IM_VEC2_CLASS_EXTRA \
ImVec2( const Vector2D& f ) : x( f.x ), y( f.y ) {} \
operator Vector2D() const { return Vector2D( x, y ); }
#define IM_VEC4_CLASS_EXTRA \
ImVec4( const Vector4D& f ) : x( f.x ), y( f.y ), z( f.z ), w( f.w ) {} \
operator Vector4D() const { return Vector4D( x, y, z, w ); }
class IMaterial;
#define ImTextureID IMaterial*

View File

@ -0,0 +1,275 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2023 Strata Source Contributors
*
* 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:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* 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.
*********************************************************************************/
#include "imgui_impl_source.h"
#include "KeyValues.h"
#include "materialsystem/imesh.h"
#include "materialsystem/itexture.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"
#include "pixelwriter.h"
#include "filesystem.h"
#include "vgui/ISystem.h"
#include "vgui_controls/Controls.h"
#include "tier0/memdbgon.h"
static IMaterial *g_pFontMat = nullptr;
class CDearImGuiFontTextureRegenerator : public ITextureRegenerator
{
public:
CDearImGuiFontTextureRegenerator() = default;
// Inherited from ITextureRegenerator
void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) override
{
ImGuiIO &io = ImGui::GetIO();
unsigned char *pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32( &pixels, &width, &height );
Assert( pVTFTexture->Width() == width );
Assert( pVTFTexture->Height() == height );
// if we ever use freetype for font loading, this should do format conversion instead
memcpy( pVTFTexture->ImageData(), pixels, 4ULL * width * height );
}
void Release() override
{
delete this;
}
};
void ImGui_ImplSource_SetupRenderState( IMatRenderContext *ctx, ImDrawData *draw_data )
{
// Apply imgui's display dimensions
ctx->Viewport( draw_data->DisplayPos.x, draw_data->DisplayPos.y, draw_data->DisplaySize.x, draw_data->DisplaySize.y );
// Setup orthographic projection matrix
// 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.
ctx->MatrixMode( MATERIAL_PROJECTION );
ctx->LoadIdentity();
ctx->Scale( 1, -1, 1 );
float L = draw_data->DisplayPos.x + 0.5f;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
float T = draw_data->DisplayPos.y + 0.5f;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
ctx->Ortho( L, T, R, B, 0.f, 1.f );
ctx->MatrixMode( MATERIAL_VIEW );
ctx->LoadIdentity();
}
void ImGui_ImplSource_RenderDrawData( ImDrawData *draw_data )
{
// Avoid rendering when minimized
if ( draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f )
return;
CMatRenderContextPtr ctx( materials );
ctx->MatrixMode( MATERIAL_VIEW );
ctx->PushMatrix();
ctx->MatrixMode( MATERIAL_PROJECTION );
ctx->PushMatrix();
ImGui_ImplSource_SetupRenderState( ctx, draw_data );
// Render command lists
ImVec2 clip_off = draw_data->DisplayPos;
for ( int n = 0; n < draw_data->CmdListsCount; n++ )
{
const ImDrawList *cmd_list = draw_data->CmdLists[n];
const ImDrawIdx *idx_buffer = cmd_list->IdxBuffer.Data;
// Draw the mesh
for ( int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++ )
{
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
if ( pcmd->UserCallback != nullptr )
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if ( pcmd->UserCallback == ImDrawCallback_ResetRenderState )
ImGui_ImplSource_SetupRenderState( ctx, draw_data );
else
pcmd->UserCallback( cmd_list, pcmd );
}
else
{
if ( pcmd->GetTexID() )
{
Vector2D clipmin = { pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y };
Vector2D clipmax = { pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y };
// Avoid rendering completely clipped draws
if ( clipmax.x <= clipmin.x || clipmax.y <= clipmin.y )
continue;
ctx->SetScissorRect( clipmin.x, clipmin.y, clipmax.x, clipmax.y, true );
IMesh *mesh = ctx->GetDynamicMesh( false, nullptr, nullptr, static_cast<IMaterial*>( pcmd->GetTexID() ) );
CMeshBuilder mb;
mb.Begin( mesh, MATERIAL_TRIANGLES, cmd_list->VtxBuffer.Size, pcmd->ElemCount );
const ImDrawVert *vtx_src = cmd_list->VtxBuffer.Data;
for ( int i = 0; i < cmd_list->VtxBuffer.Size; i++ )
{
mb.Position3f( Vector2DExpand( vtx_src->pos ), 0 );
mb.Color4ubv( reinterpret_cast<const unsigned char*>( &vtx_src->col ) );
mb.TexCoord2fv( 0, &vtx_src->uv.x );
mb.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
vtx_src++;
}
static_cast<CIndexBuilder &>( mb ).FastIndexList( idx_buffer + pcmd->IdxOffset, 0, pcmd->ElemCount );
mb.End( false, true );
ctx->SetScissorRect( clipmin.x, clipmin.y, clipmax.x, clipmax.y, false );
}
}
}
}
ctx->MatrixMode( MATERIAL_PROJECTION );
ctx->PopMatrix();
ctx->MatrixMode( MATERIAL_VIEW );
ctx->PopMatrix();
}
bool ImGui_ImplSource_Init()
{
// Setup backend capabilities flags
ImGuiIO &io = ImGui::GetIO();
io.BackendPlatformName = "source";
io.BackendRendererName = "imgui_impl_source";
io.BackendFlags = ImGuiBackendFlags_None;
io.SetClipboardTextFn = []( void *, const char *c )
{
vgui::system()->SetClipboardText( c, V_strlen( c ) );
};
io.GetClipboardTextFn = []( void *ctx ) -> const char *
{
auto &g = *static_cast<ImGuiContext *>( ctx );
g.ClipboardHandlerData.clear();
auto len = vgui::system()->GetClipboardTextCount();
if ( !len )
return nullptr;
g.ClipboardHandlerData.resize( len );
vgui::system()->GetClipboardText( 0, g.ClipboardHandlerData.Data, g.ClipboardHandlerData.Size );
return g.ClipboardHandlerData.Data;
};
ImGui_ImplSource_CreateDeviceObjects();
return true;
}
void ImGui_ImplSource_Shutdown()
{
ImGui_ImplSource_InvalidateDeviceObjects();
}
static bool ImGui_ImplSource_CreateFontsTexture()
{
if ( g_pFontMat )
return true;
// Build texture atlas
ImGuiIO &io = ImGui::GetIO();
int width, height;
unsigned char* pixels;
io.Fonts->GetTexDataAsRGBA32( &pixels, &width, &height );
// Create a material for the texture
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 );
fonttex->SetTextureRegenerator( new CDearImGuiFontTextureRegenerator );
KeyValues *vmt = new KeyValues( "UnlitGeneric" );
vmt->SetString( "$basetexture", "imgui_font" );
vmt->SetInt( "$nocull", 1 );
vmt->SetInt( "$vertexcolor", 1 );
vmt->SetInt( "$vertexalpha", 1 );
vmt->SetInt( "$translucent", 1 );
g_pFontMat = materials->CreateMaterial( "imgui_font_mat", vmt );
g_pFontMat->AddRef();
// Store our identifier
io.Fonts->SetTexID( g_pFontMat );
return true;
}
bool ImGui_ImplSource_CreateDeviceObjects()
{
return ImGui_ImplSource_CreateFontsTexture();
}
void ImGui_ImplSource_InvalidateDeviceObjects()
{
if ( g_pFontMat )
{
g_pFontMat->DecrementReferenceCount();
g_pFontMat = nullptr;
}
}
// The following functions are declared in imconfig_source.h and must not be renamed
ImFileHandle ImFileOpen( const char *filename, const char *mode )
{
Assert( g_pFullFileSystem );
return g_pFullFileSystem->Open( filename, mode );
}
bool ImFileClose( ImFileHandle f )
{
if ( f == nullptr )
return false;
Assert( g_pFullFileSystem );
g_pFullFileSystem->Close( f );
return true;
}
uint64 ImFileGetSize( ImFileHandle f )
{
Assert( g_pFullFileSystem && f );
return g_pFullFileSystem->Size( f );
}
uint64 ImFileRead( void *data, uint64 sz, uint64 count, ImFileHandle f )
{
Assert( g_pFullFileSystem && f );
return g_pFullFileSystem->Read( data, sz * count, f );
}
uint64 ImFileWrite( const void *data, uint64 sz, uint64 count, ImFileHandle f )
{
Assert( g_pFullFileSystem && f );
return g_pFullFileSystem->Write( data, sz * count, f );
}

View File

@ -0,0 +1,147 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2023 Strata Source Contributors
*
* 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:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* 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.
*********************************************************************************/
#pragma once
#include "imgui/imgui.h"
struct ImDrawData;
bool ImGui_ImplSource_Init();
void ImGui_ImplSource_Shutdown();
void ImGui_ImplSource_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.
bool ImGui_ImplSource_CreateDeviceObjects();
void ImGui_ImplSource_InvalidateDeviceObjects();
// Translation table for imgui keys
constexpr ImGuiKey IMGUI_KEY_TABLE[] = {
/*KEY_NONE*/ ImGuiKey_None,
/*KEY_0*/ ImGuiKey_0,
/*KEY_1*/ ImGuiKey_1,
/*KEY_2*/ ImGuiKey_2,
/*KEY_3*/ ImGuiKey_3,
/*KEY_4*/ ImGuiKey_4,
/*KEY_5*/ ImGuiKey_5,
/*KEY_6*/ ImGuiKey_6,
/*KEY_7*/ ImGuiKey_7,
/*KEY_8*/ ImGuiKey_8,
/*KEY_9*/ ImGuiKey_9,
/*KEY_A*/ ImGuiKey_A,
/*KEY_B*/ ImGuiKey_B,
/*KEY_C*/ ImGuiKey_C,
/*KEY_D*/ ImGuiKey_D,
/*KEY_E*/ ImGuiKey_E,
/*KEY_F*/ ImGuiKey_F,
/*KEY_G*/ ImGuiKey_G,
/*KEY_H*/ ImGuiKey_H,
/*KEY_I*/ ImGuiKey_I,
/*KEY_J*/ ImGuiKey_J,
/*KEY_K*/ ImGuiKey_K,
/*KEY_L*/ ImGuiKey_L,
/*KEY_M*/ ImGuiKey_M,
/*KEY_N*/ ImGuiKey_N,
/*KEY_O*/ ImGuiKey_O,
/*KEY_P*/ ImGuiKey_P,
/*KEY_Q*/ ImGuiKey_Q,
/*KEY_R*/ ImGuiKey_R,
/*KEY_S*/ ImGuiKey_S,
/*KEY_T*/ ImGuiKey_T,
/*KEY_U*/ ImGuiKey_U,
/*KEY_V*/ ImGuiKey_V,
/*KEY_W*/ ImGuiKey_W,
/*KEY_X*/ ImGuiKey_X,
/*KEY_Y*/ ImGuiKey_Y,
/*KEY_Z*/ ImGuiKey_Z,
/*KEY_PAD_0*/ ImGuiKey_Keypad0,
/*KEY_PAD_1*/ ImGuiKey_Keypad1,
/*KEY_PAD_2*/ ImGuiKey_Keypad2,
/*KEY_PAD_3*/ ImGuiKey_Keypad3,
/*KEY_PAD_4*/ ImGuiKey_Keypad4,
/*KEY_PAD_5*/ ImGuiKey_Keypad5,
/*KEY_PAD_6*/ ImGuiKey_Keypad6,
/*KEY_PAD_7*/ ImGuiKey_Keypad7,
/*KEY_PAD_8*/ ImGuiKey_Keypad8,
/*KEY_PAD_9*/ ImGuiKey_Keypad9,
/*KEY_PAD_DIVIDE*/ ImGuiKey_KeypadDivide,
/*KEY_PAD_MULTIPLY*/ ImGuiKey_KeypadMultiply,
/*KEY_PAD_MINUS*/ ImGuiKey_KeypadSubtract,
/*KEY_PAD_PLUS*/ ImGuiKey_KeypadAdd,
/*KEY_PAD_ENTER*/ ImGuiKey_KeypadEnter,
/*KEY_PAD_DECIMAL*/ ImGuiKey_KeypadDecimal,
/*KEY_LBRACKET*/ ImGuiKey_LeftBracket,
/*KEY_RBRACKET*/ ImGuiKey_RightBracket,
/*KEY_SEMICOLON*/ ImGuiKey_Semicolon,
/*KEY_APOSTROPHE*/ ImGuiKey_Apostrophe,
/*KEY_BACKQUOTE*/ ImGuiKey_None, // ?
/*KEY_COMMA*/ ImGuiKey_Comma,
/*KEY_PERIOD*/ ImGuiKey_Period,
/*KEY_SLASH*/ ImGuiKey_Slash,
/*KEY_BACKSLASH*/ ImGuiKey_Backslash,
/*KEY_MINUS*/ ImGuiKey_Minus,
/*KEY_EQUAL*/ ImGuiKey_Equal,
/*KEY_ENTER*/ ImGuiKey_Enter,
/*KEY_SPACE*/ ImGuiKey_Space,
/*KEY_BACKSPACE*/ ImGuiKey_Backspace,
/*KEY_TAB*/ ImGuiKey_Tab,
/*KEY_CAPSLOCK*/ ImGuiKey_CapsLock,
/*KEY_NUMLOCK*/ ImGuiKey_NumLock,
/*KEY_ESCAPE*/ ImGuiKey_Escape,
/*KEY_SCROLLLOCK*/ ImGuiKey_ScrollLock,
/*KEY_INSERT*/ ImGuiKey_Insert,
/*KEY_DELETE*/ ImGuiKey_Delete,
/*KEY_HOME*/ ImGuiKey_Home,
/*KEY_END*/ ImGuiKey_End,
/*KEY_PAGEUP*/ ImGuiKey_PageUp,
/*KEY_PAGEDOWN*/ ImGuiKey_PageDown,
/*KEY_BREAK*/ ImGuiKey_None, // ?
/*KEY_LSHIFT*/ ImGuiKey_LeftShift,
/*KEY_RSHIFT*/ ImGuiKey_RightShift,
/*KEY_LALT*/ ImGuiKey_LeftAlt,
/*KEY_RALT*/ ImGuiKey_RightAlt,
/*KEY_LCONTROL*/ ImGuiKey_LeftCtrl,
/*KEY_RCONTROL*/ ImGuiKey_RightCtrl,
/*KEY_LWIN*/ ImGuiKey_LeftSuper,
/*KEY_RWIN*/ ImGuiKey_RightSuper,
/*KEY_APP*/ ImGuiKey_None, // ?
/*KEY_UP*/ ImGuiKey_UpArrow,
/*KEY_LEFT*/ ImGuiKey_LeftArrow,
/*KEY_DOWN*/ ImGuiKey_DownArrow,
/*KEY_RIGHT*/ ImGuiKey_RightArrow,
/*KEY_F1*/ ImGuiKey_F1,
/*KEY_F2*/ ImGuiKey_F2,
/*KEY_F3*/ ImGuiKey_F3,
/*KEY_F4*/ ImGuiKey_F4,
/*KEY_F5*/ ImGuiKey_F5,
/*KEY_F6*/ ImGuiKey_F6,
/*KEY_F7*/ ImGuiKey_F7,
/*KEY_F8*/ ImGuiKey_F8,
/*KEY_F9*/ ImGuiKey_F9,
/*KEY_F10*/ ImGuiKey_F10,
/*KEY_F11*/ ImGuiKey_F11,
/*KEY_F12*/ ImGuiKey_F12,
/*KEY_CAPSLOCKTOGGLE*/ ImGuiKey_None, // ?
/*KEY_NUMLOCKTOGGLE*/ ImGuiKey_None, // ?
/*KEY_SCROLLLOCKTOGGLE*/ImGuiKey_None, // ?
};

View File

@ -0,0 +1,631 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2023 Strata Source Contributors
*
* 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:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* 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.
*********************************************************************************/
#include "imgui_system.h"
#include "imgui_window.h"
#include "filesystem.h"
#include "fmtstr.h"
#include "imgui_impl_source.h"
#include "inputsystem/iinputsystem.h"
#include "materialsystem/imaterialsystem.h"
#include "strtools.h"
#include "tier2/tier2.h"
#include "tier3/tier3.h"
#include "utldict.h"
#include "imgui/imgui.h"
#include <vgui/IInput.h>
#include <vgui/ISurface.h>
#include <vgui/IPanel.h>
#include <vgui_controls/Frame.h>
#include <vgui/ISystem.h>
#include <vgui_controls/Panel.h>
#include <vgui_controls/Controls.h>
#include <vgui/IVGui.h>
#include "ienginevgui.h"
#include "tier0/memdbgon.h"
class CDummyOverlayPanel;
CUtlVector<IImguiWindow *> &ImGuiWindows();
static ConVar imgui_font_scale( "imgui_font_scale", "1", FCVAR_ARCHIVE, "Global scale applied to Imgui fonts" );
static ConVar imgui_display_scale( "imgui_display_scale", "1", FCVAR_ARCHIVE, "Global imgui scale, usually used for Hi-DPI displays" );
void *ImGui_MemAlloc( size_t sz, void *user_data )
{
return MemAlloc_Alloc( sz, "Dear ImGui", 0 );
}
static void ImGui_MemFree( void *ptr, void *user_data )
{
MemAlloc_Free( ptr );
}
//---------------------------------------------------------------------------------------//
// Global helpers
//---------------------------------------------------------------------------------------//
CUtlVector<IImguiWindow *> &ImGuiWindows()
{
static CUtlVector<IImguiWindow *> s_DearImGuiWindows;
return s_DearImGuiWindows;
}
void RegisterImGuiWindowFactory( IImguiWindow *pWindow )
{
ImGuiWindows().AddToTail( pWindow );
}
//---------------------------------------------------------------------------------------//
// Purpose: Implementation of the imgui system
//---------------------------------------------------------------------------------------//
class CDearImGuiSystem : public IImguiSystem
{
using BaseClass = IImguiSystem;
public:
// IAppSystem
bool Init() override;
void Shutdown() override;
// IDearImGuiSystem
DearImGuiSysData_t GetData() override;
void Render() override;
void RegisterWindowFactories( IImguiWindow **arrpWindows, int nCount ) override;
IImguiWindow *FindWindow( const char *szName ) override;
void UnregisterWindowFactories( IImguiWindow **ppWindows, int nCount ) override;
void GetAllWindows( CUtlVector<IImguiWindow *> &windows ) override;
void SetWindowVisible( IImguiWindow* pWindow, bool bVisible, bool bEnableInput ) override;
bool DrawWindow( IImguiWindow *pWindow );
void PushInputContext();
void PopInputContext();
// True if our input context is enabled in any capacity
bool IsInputContextEnabled() const { return m_bInputEnabled; }
void SetStyle();
void DrawMenuBar();
void SetDrawMenuBar( bool bEnable ) { m_bDrawMenuBar = bEnable; }
bool IsDrawingMenuBar() const { return m_bDrawMenuBar; }
void ToggleMenuBar() { m_bDrawMenuBar = !m_bDrawMenuBar; }
public:
CUtlDict<IImguiWindow *> m_ImGuiWindows;
double m_flLastFrameTime;
bool m_bInputEnabled = false;
bool m_bDrawMenuBar = false;
bool m_bDrawMetrics = false;
bool m_bDrawDemo = false;
CDummyOverlayPanel* m_pInputOverlay = nullptr;
};
static CDearImGuiSystem g_ImguiSystem;
IImguiSystem* g_pImguiSystem = &g_ImguiSystem;
//---------------------------------------------------------------------------------------//
// Purpose: Dummy overlay panel for capturing input
//---------------------------------------------------------------------------------------//
class CDummyOverlayPanel : public vgui::Panel
{
public:
CDummyOverlayPanel()
{
SetVisible( false );
SetParent( enginevgui->GetPanel( PANEL_GAMEUIDLL ) );
SetPaintEnabled( true );
SetCursor( vgui::dc_arrow );
SetPaintBorderEnabled( false );
SetPaintBackgroundEnabled( false );
MakePopup();
}
void OnMousePressed( ButtonCode_t code ) override
{
auto& io = ImGui::GetIO();
if ( io.WantCaptureMouse )
io.AddMouseButtonEvent( code - MOUSE_FIRST, true );
}
void OnMouseReleased( ButtonCode_t code ) override
{
auto& io = ImGui::GetIO();
if ( io.WantCaptureMouse )
{
io.AddMouseButtonEvent( code - MOUSE_FIRST, false );
}
}
void OnMouseWheeled( int delta ) override
{
auto& io = ImGui::GetIO();
io.AddMouseWheelEvent( 0, delta );
}
void OnCursorMoved( int x, int y ) override
{
vgui::Panel::OnCursorMoved( x, y );
ImGui::GetIO().AddMousePosEvent( x, y );
}
void OnMouseDoublePressed( ButtonCode_t code ) override
{
}
void OnKeyTyped( wchar_t code ) override
{
auto& io = ImGui::GetIO();
if ( io.WantCaptureKeyboard )
io.AddInputCharacter( code );
}
void OnKeyCodePressed( vgui::KeyCode code ) override
{
auto& io = ImGui::GetIO();
if ( io.WantCaptureKeyboard )
io.AddKeyEvent( IMGUI_KEY_TABLE[code], true );
}
void OnKeyCodeReleased( vgui::KeyCode code ) override
{
auto& io = ImGui::GetIO();
if ( io.WantCaptureKeyboard )
io.AddKeyEvent( IMGUI_KEY_TABLE[code], false );
}
void Paint() override
{
g_pImguiSystem->Render();
}
void Activate( bool bActive )
{
SetVisible( bActive );
SetEnabled( bActive );
SetKeyBoardInputEnabled( bActive );
SetMouseInputEnabled( bActive );
if ( bActive )
{
MoveToFront();
RequestFocus();
vgui::input()->SetMouseCapture( NULL );
}
}
};
//---------------------------------------------------------------------------------------//
// Purpose: Init our dear friend
//---------------------------------------------------------------------------------------//
bool CDearImGuiSystem::Init()
{
ImGui::SetAllocatorFunctions( ImGui_MemAlloc, ImGui_MemFree, nullptr );
ImFontAtlas *atlas = new ImFontAtlas();
ImGui::CreateContext( atlas );
ImGui_ImplSource_Init();
SetStyle();
m_flLastFrameTime = Plat_FloatTime();
DearImGuiSysData_t data = g_pImguiSystem->GetData();
ImGui::SetAllocatorFunctions( (ImGuiMemAllocFunc)data.memallocfn, (ImGuiMemFreeFunc)data.memfreefn, nullptr );
ImGui::SetCurrentContext( (ImGuiContext *)data.context );
g_pImguiSystem->RegisterWindowFactories( ImGuiWindows().Base(), ImGuiWindows().Count() );
return true;
}
void CDearImGuiSystem::Shutdown()
{
g_pImguiSystem->UnregisterWindowFactories( ImGuiWindows().Base(), ImGuiWindows().Count() );
ImGui_ImplSource_Shutdown();
ImGui::DestroyContext();
}
DearImGuiSysData_t CDearImGuiSystem::GetData()
{
DearImGuiSysData_t data;
data.context = ImGui::GetCurrentContext();
data.memallocfn = ImGui_MemAlloc;
data.memfreefn = ImGui_MemFree;
return data;
}
//---------------------------------------------------------------------------------------//
// Purpose: Render all imgui windows
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::Render()
{
// Update the IO
auto &io = ImGui::GetIO();
// Create input overlay helper if it doesn't yet exist
if ( !m_pInputOverlay )
{
m_pInputOverlay = new CDummyOverlayPanel();
}
// Update the screen size before drawing
CMatRenderContextPtr pRenderContext( materials );
int w, h;
pRenderContext->GetWindowSize( w, h );
if ( !w || !h )
return;
m_pInputOverlay->SetSize( w, h );
io.DisplaySize.x = static_cast<float>( w );
io.DisplaySize.y = static_cast<float>( h );
io.DisplayFramebufferScale.x = io.DisplayFramebufferScale.y = imgui_display_scale.GetFloat();
io.FontGlobalScale = imgui_font_scale.GetFloat();
// Create new frame
ImGui::NewFrame();
// Draw menubar first
if ( m_bDrawMenuBar )
DrawMenuBar();
// Draw imgui-specific debug menus
if ( m_bDrawDemo )
ImGui::ShowDemoWindow( &m_bDrawDemo );
if ( m_bDrawMetrics )
ImGui::ShowMetricsWindow( &m_bDrawMetrics );
// Draw everything else
bool bDrawn = false;
FOR_EACH_DICT( m_ImGuiWindows, i )
{
auto *pWindow = m_ImGuiWindows[i];
if ( pWindow->ShouldDraw() )
{
DrawWindow( pWindow );
bDrawn = true;
}
}
ImGui::Render();
ImDrawData *drawdata = ImGui::GetDrawData();
if ( drawdata )
ImGui_ImplSource_RenderDrawData( drawdata );
// Post render, update deltas
auto curtime = Plat_FloatTime();
auto dt = curtime - m_flLastFrameTime;
m_flLastFrameTime = curtime;
io.DeltaTime = static_cast<float>( dt );
// Deactivate our overlay if nothing is being drawn anymore
if ( !bDrawn && !m_bDrawDemo && !m_bDrawMetrics && !m_bDrawMenuBar )
{
PopInputContext();
}
}
//---------------------------------------------------------------------------------------//
// Purpose: Draws a window
//---------------------------------------------------------------------------------------//
bool CDearImGuiSystem::DrawWindow( IImguiWindow *pWindow )
{
bool closeButton = pWindow->ShouldDraw();
ImGui::Begin( pWindow->GetWindowTitle(), &closeButton, pWindow->GetFlags() );
pWindow->SetDraw( closeButton );
bool stayOpen = pWindow->Draw();
ImGui::End();
return stayOpen;
}
//---------------------------------------------------------------------------------------//
// Purpose: Register all window factories from another DLL
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::RegisterWindowFactories( IImguiWindow **arrpWindows, int nCount )
{
for ( int i = 0; i < nCount; i++ )
{
auto *pWindow = arrpWindows[i];
m_ImGuiWindows.Insert( pWindow->GetName(), pWindow );
}
}
//---------------------------------------------------------------------------------------//
// Purpose: Unregister window factories, usually called on DLL shutdown
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::UnregisterWindowFactories( IImguiWindow **ppWindows, int nCount )
{
for ( int i = 0; i < nCount; ++i )
{
m_ImGuiWindows.Remove( ppWindows[i]->GetName() );
}
}
//---------------------------------------------------------------------------------------//
// Purpose: find window by name
//---------------------------------------------------------------------------------------//
IImguiWindow *CDearImGuiSystem::FindWindow( const char *szName )
{
if ( auto it = m_ImGuiWindows.Find( szName ); it != m_ImGuiWindows.InvalidIndex() )
return m_ImGuiWindows[it];
return nullptr;
}
//---------------------------------------------------------------------------------------//
// Purpose: Returns a list of all windows into `windows`
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::GetAllWindows( CUtlVector<IImguiWindow *> &windows )
{
windows.Purge();
FOR_EACH_DICT( m_ImGuiWindows, i )
windows.AddToTail( m_ImGuiWindows[i] );
}
//---------------------------------------------------------------------------------------//
// Purpose: Make a window visible
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::SetWindowVisible( IImguiWindow* pWindow, bool bVisible, bool bEnableInput )
{
Assert( pWindow );
pWindow->SetDraw( bVisible );
if ( bVisible && bEnableInput )
PushInputContext();
else if ( !bVisible && bEnableInput )
PopInputContext();
}
//---------------------------------------------------------------------------------------//
// Purpose: Push a new input context so we can show the mouse cursor
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::PushInputContext()
{
if ( m_bInputEnabled )
return;
if ( !m_pInputOverlay )
m_pInputOverlay = new CDummyOverlayPanel();
m_pInputOverlay->Activate( true );
m_bInputEnabled = true;
}
//---------------------------------------------------------------------------------------//
// Purpose: Pop input context, returning mouse control to whatever needed it last
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::PopInputContext()
{
m_pInputOverlay->Activate( false );
m_bInputEnabled = false;
}
//---------------------------------------------------------------------------------------//
// Purpose: Update Imgui style
// TODO: User-configurable styles
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::SetStyle()
{
ImGuiStyle& style = ImGui::GetStyle();
style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f);
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.08f, 0.50f, 0.72f, 1.00f);
style.Colors[ImGuiCol_Button] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f);
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
style.Colors[ImGuiCol_Header] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f);
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
style.Colors[ImGuiCol_Separator] = style.Colors[ImGuiCol_Border];
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.41f, 0.42f, 0.44f, 1.00f);
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.29f, 0.30f, 0.31f, 0.67f);
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
style.Colors[ImGuiCol_Tab] = ImVec4(0.08f, 0.08f, 0.09f, 0.83f);
style.Colors[ImGuiCol_TabHovered] = ImVec4(0.33f, 0.34f, 0.36f, 0.83f);
style.Colors[ImGuiCol_TabActive] = ImVec4(0.23f, 0.23f, 0.24f, 1.00f);
style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
style.Colors[ImGuiCol_DragDropTarget] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
style.GrabRounding = style.FrameRounding = 2.3f;
}
//---------------------------------------------------------------------------------------//
// Purpose: Draws the menu bar as a top-level window
//---------------------------------------------------------------------------------------//
void CDearImGuiSystem::DrawMenuBar()
{
if ( ImGui::BeginMainMenuBar() )
{
if ( ImGui::BeginMenu( "File" ) )
{
if ( ImGui::MenuItem( "Close Menu" ) )
{
this->m_bDrawMenuBar = false;
this->PopInputContext();
}
ImGui::EndMenu();
}
if ( ImGui::BeginMenu( "Windows" ) )
{
CUtlVector<IImguiWindow *> windows;
g_pImguiSystem->GetAllWindows( windows );
for ( auto &window : windows )
{
bool bToggle = window->ShouldDraw();
if ( ImGui::MenuItem( window->GetWindowTitle(), "", &bToggle ) )
window->SetDraw( bToggle );
}
ImGui::EndMenu();
}
if ( ImGui::BeginMenu( "Debug" ) )
{
ImGui::MenuItem( "Show Demo Window", "", &m_bDrawDemo );
ImGui::MenuItem( "Show Metrics Window", "", &m_bDrawMetrics );
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
}
//---------------------------------------------------------------------------------------//
// Purpose: Implementation of imgui_show command
//---------------------------------------------------------------------------------------//
class CImGuiShowAutoCompletionFunctor : public ICommandCallback,
public ICommandCompletionCallback
{
public:
void CommandCallback( const CCommand &command ) override
{
if ( command.ArgC() < 2 )
{
Msg( "Format: imgui_show <window name>\n" );
return;
}
// Get our window
const char *pKey = command.Arg( 1 );
auto *pWindow = g_ImguiSystem.FindWindow( pKey );
if ( !pWindow )
{
Warning( "Failed to find ImGUI window called %s\n", pKey );
return;
}
pWindow->ToggleDraw();
}
int CommandCompletionCallback( const char *partial, CUtlVector<CUtlString> &commands ) override
{
auto &windows = g_ImguiSystem.m_ImGuiWindows;
FOR_EACH_DICT( windows, i )
{
commands.AddToTail( CFmtStr( "%s %s", "imgui_show", windows[i]->GetName() ).Get() );
}
return commands.Count();
}
};
static CImGuiShowAutoCompletionFunctor g_ImGuiShowAutoComplete;
static ConCommand imgui_show( "imgui_show", &g_ImGuiShowAutoComplete, "Toggles the specified imgui window", FCVAR_CLIENTDLL, &g_ImGuiShowAutoComplete );
//---------------------------------------------------------------------------------------//
// Purpose: Toggle input for imgui windows
//---------------------------------------------------------------------------------------//
CON_COMMAND_F( imgui_toggle_input, "Toggles the mouse cursor for imgui windows", FCVAR_CLIENTDLL )
{
if ( g_ImguiSystem.IsInputContextEnabled() )
g_ImguiSystem.PopInputContext();
else
g_ImguiSystem.PushInputContext();
}
static ConCommand imgui_input_start(
"+imgui_input", []( const CCommand &args )
{
g_ImguiSystem.PushInputContext();
},
"Toggles the mouse cursor for imgui windows, same as imgui_toggle_input", FCVAR_CLIENTDLL );
static ConCommand imgui_input_end(
"-imgui_input", []( const CCommand &args )
{
g_ImguiSystem.PopInputContext();
},
"Toggles the mouse cursor for imgui windows, same as imgui_toggle_input", FCVAR_CLIENTDLL );
//---------------------------------------------------------------------------------------//
// Purpose: Toggles the built-in menu bar (and input)
//---------------------------------------------------------------------------------------//
CON_COMMAND_F( imgui_toggle_menu, "Toggles the imgui menu bar", FCVAR_CLIENTDLL )
{
g_ImguiSystem.ToggleMenuBar();
if ( g_ImguiSystem.IsDrawingMenuBar() )
g_ImguiSystem.PushInputContext();
else
g_ImguiSystem.PopInputContext();
}
template <bool ON>
void CC_ToggleMenu( const CCommand &args )
{
g_ImguiSystem.SetDrawMenuBar( ON );
if constexpr ( ON )
g_ImguiSystem.PushInputContext();
else
g_ImguiSystem.PopInputContext();
}
static ConCommand imgui_menu_start( "+imgui_menu", CC_ToggleMenu<true>, "Toggles the menu bar and input", FCVAR_CLIENTDLL );
static ConCommand imgui_menu_end( "-imgui_menu", CC_ToggleMenu<false>, "Toggles the menu bar and input", FCVAR_CLIENTDLL );
CON_COMMAND_F( imgui_show_demo, "Shows the imgui demo", FCVAR_CLIENTDLL )
{
g_ImguiSystem.m_bDrawDemo = true;
}

View File

@ -0,0 +1,61 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2023 Strata Source Contributors
*
* 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:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* 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.
*********************************************************************************/
#pragma once
#include "appframework/IAppSystem.h"
#include "inputsystem/InputEnums.h"
#include "utlvector.h"
struct DearImGuiSysData_t
{
void *context;
void *( *memallocfn )( size_t sz, void *user_data );
void ( *memfreefn )( void *ptr, void *user_data );
};
class IImguiWindow;
abstract_class IImguiSystem
{
public:
virtual bool Init() = 0;
virtual void Shutdown() = 0;
virtual DearImGuiSysData_t GetData() = 0;
virtual void Render() = 0;
virtual void RegisterWindowFactories( IImguiWindow * *arrpWindows, int nCount ) = 0;
virtual void UnregisterWindowFactories( IImguiWindow * *ppWindows, int nCount ) = 0;
virtual IImguiWindow *FindWindow( const char *szName ) = 0;
virtual void GetAllWindows( CUtlVector<IImguiWindow *> & windows ) = 0;
virtual void SetWindowVisible( IImguiWindow* pWindow, bool bVisible, bool bEnableInput = true ) = 0;
};
extern IImguiSystem *g_pImguiSystem;

View File

@ -0,0 +1,39 @@
$Macro IMGUI_DIR "$SRCDIR\game\client\imgui"
$Configuration
{
$Compiler
{
$PreprocessorDefinitions "$BASE;IMGUI_DISABLE_INCLUDE_IMCONFIG_H;IMGUI_USER_CONFIG=<imgui/imconfig_source.h>"
$AdditionalIncludeDirectories "$BASE;$IMGUI_DIR;$SRCDIR/thirdparty;"
}
}
$Project
{
$Folder "Source Files"
{
$File "$SRCDIR\game\client\imgui\imgui_impl_source.cpp"
$File "$SRCDIR\game\client\imgui\imgui_system.cpp"
$Folder "ImGUI"
{
$File "$SRCDIR/thirdparty/imgui/imgui.cpp" \
"$SRCDIR/thirdparty/imgui/imgui_demo.cpp" \
"$SRCDIR/thirdparty/imgui/imgui_draw.cpp" \
"$SRCDIR/thirdparty/imgui/imgui_tables.cpp" \
"$SRCDIR/thirdparty/imgui/imgui_widgets.cpp"
{
$Configuration
{
$Compiler
{
$Create/UsePrecompiledHeader "Not Using Precompiled Headers"
}
}
}
}
}
}

View File

@ -0,0 +1,109 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2023 Strata Source Contributors
*
* 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:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* 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.
*********************************************************************************/
#pragma once
#include "imgui/imgui.h"
#include "imgui_system.h"
#include "utlmap.h"
// Implemented by devui_static
extern void RegisterImGuiWindowFactory( IImguiWindow *pWindow );
//--------------------------------------------------------------------------------//
// Purpose: Interface implemented by each window. Use with DEFINE_DEVUI_WINDOW.
//--------------------------------------------------------------------------------//
class IImguiWindow
{
public:
IImguiWindow() = delete;
IImguiWindow( const char *pszName, const char* pszTitle ) :
m_pName( pszName ),
m_pTitle( pszTitle )
{
RegisterImGuiWindowFactory( this );
}
virtual ~IImguiWindow() = default;
// Must be implemented by subclasses
// Returns true to indicate if this window should continue to stay open
virtual bool Draw() = 0;
// Default implementations provided
virtual bool ShouldDraw() { return m_bEnabled; }
virtual void ToggleDraw()
{
m_bEnabled = !m_bEnabled;
OnChangeVisibility();
}
virtual void SetDraw( bool bState )
{
bool old = m_bEnabled;
m_bEnabled = bState;
if ( old != m_bEnabled )
OnChangeVisibility();
}
// Returns window flags for this window, override this if you want (Or use DECLARE_DEVUI_WINDOW_F)
virtual ImGuiWindowFlags GetFlags() const { return ImGuiWindowFlags_None; }
// Returns the internal reference name of the window
const char *GetName() const { return m_pName; }
// Returns the window title. This will be passed to ImGui::Begin and displayed in the menu
virtual const char *GetWindowTitle() const { return m_pTitle; }
virtual void OnChangeVisibility() {}
protected:
bool m_bEnabled = false;
const char *m_pName;
const char* m_pTitle;
};
// Defines an imgui window
#define DEFINE_IMGUI_WINDOW( _className ) \
static _className __s_##_className##_registrar;
// Helper macro for simpler windows
#define DECLARE_IMGUI_WINDOW_F( name, _title, _flags ) \
class CDearImGuiWindow##name : public IImguiWindow \
{ \
public: \
CDearImGuiWindow##name() : IImguiWindow( #name, _title ) \
{ \
} \
bool Draw() override; \
ImGuiWindowFlags GetFlags() const override { return _flags; } \
}; \
static CDearImGuiWindow##name _s_dearimguiwindow##name; \
bool CDearImGuiWindow##name::Draw()
#define DECLARE_IMGUI_WINDOW( _name, _title ) DECLARE_IMGUI_WINDOW_F( _name, _title, ImGuiWindowFlags_None )

View File

@ -12,14 +12,14 @@ def options(opt):
return
games = {
'hl2': ['client_base.vpc', 'client_hl2.vpc'],
'hl2mp': ['client_base.vpc', 'client_hl2mp.vpc'],
'hl1': ['client_base.vpc', 'client_hl1.vpc'],
'episodic': ['client_base.vpc', 'client_episodic.vpc'],
'portal': ['client_base.vpc', 'client_portal.vpc'],
'hl1mp': ['client_base.vpc', 'client_hl1mp.vpc'],
'cstrike': ['client_base.vpc', 'client_cstrike.vpc'],
'dod': ['client_base.vpc', 'client_dod.vpc']
'hl2': ['client_base.vpc', 'client_hl2.vpc', 'imgui/imgui_system.vpc'],
'hl2mp': ['client_base.vpc', 'client_hl2mp.vpc', 'imgui/imgui_system.vpc'],
'hl1': ['client_base.vpc', 'client_hl1.vpc', 'imgui/imgui_system.vpc'],
'episodic': ['client_base.vpc', 'client_episodic.vpc', 'imgui/imgui_system.vpc'],
'portal': ['client_base.vpc', 'client_portal.vpc', 'imgui/imgui_system.vpc'],
'hl1mp': ['client_base.vpc', 'client_hl1mp.vpc', 'imgui/imgui_system.vpc'],
'cstrike': ['client_base.vpc', 'client_cstrike.vpc', 'imgui/imgui_system.vpc'],
'dod': ['client_base.vpc', 'client_dod.vpc', 'imgui/imgui_system.vpc']
}
def configure(conf):