Files
funnygame/fgui/fgui.cpp
2025-07-20 00:45:31 +03:00

331 lines
8.3 KiB
C++

#include "fgui/fgui.h"
#include "filesystem.h"
#include "rendering.h"
#include "tier1/utlvector.h"
#include "fgui/widget.h"
#include "ctype.h"
float fgui_fRectColor[4];
float fgui_fTextColor[4];
float fgui_fTextPosition[2];
float fgui_fGlyphScale[2];
CFont *fgui_pTextFont;
float fgui_fOffset[2];
IGraphicsPipeline *fgui_RectPipeline;
IGraphicsPipeline *fgui_TextPipeline;
IVertexBuffer *fgui_pRectangleBuffer;
IVertexBuffer *fgui_pUVRectangleBuffer;
CUtlVector<CFGUI_Widget*> fgui_widgets;
void IFGUI::Init( void )
{
}
void IFGUI::Frame( void )
{
for (auto &widget: fgui_widgets)
{
widget->Frame();
}
}
//----------------------------------------------------------------------------
// Sets offset of the drawn widget
//----------------------------------------------------------------------------
void IFGUI::AddOffset( float x, float y)
{
fgui_fOffset[0] += x;
fgui_fOffset[1] += y;
}
//----------------------------------------------------------------------------
// Reset offset of the drawn widget
//----------------------------------------------------------------------------
void IFGUI::ResetOffset()
{
fgui_fOffset[0] = 0;
fgui_fOffset[1] = 0;
}
//----------------------------------------------------------------------------
// Creates new widget in the world
//----------------------------------------------------------------------------
void IFGUI::AppendWidget( CFGUI_Widget *pWidget )
{
fgui_widgets.AppendTail(pWidget);
}
//----------------------------------------------------------------------------
// Destroys widget
//----------------------------------------------------------------------------
void IFGUI::DestroyWidget( CFGUI_Widget *pWidget )
{
size_t i = 0;
for (auto &widget: fgui_widgets)
{
if (widget == pWidget)
{
fgui_widgets.RemoveAt(i);
return;
}
i++;
}
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
void IFGUI::SetRectColor( float r, float g, float b, float a )
{
fgui_fRectColor[0] = r;
fgui_fRectColor[1] = g;
fgui_fRectColor[2] = b;
fgui_fRectColor[3] = a;
}
//----------------------------------------------------------------------------
// Draws rectangle on the screen
//----------------------------------------------------------------------------
void IFGUI::DrawRect( int32_t iPosX, int32_t iPosY, uint32_t uSizeX, uint32_t uSizeY )
{
Renderer()->BindPipeline(fgui_RectPipeline);
struct RectConstants_t
{
uint32_t nResolution[2];
uint32_t nSize[2];
int32_t nPosition[2];
float offest0[2];
float fColor[4];
} constants;
constants.nResolution[0] = g_nWindowWidth;
constants.nResolution[1] = g_nWindowHeight;
constants.nPosition[0] = fgui_fOffset[0] + iPosX;
constants.nPosition[1] = fgui_fOffset[1] + iPosY;
constants.nSize[0] = uSizeX;
constants.nSize[1] = uSizeY;
for ( int i = 0; i < 4; i++ )
constants.fColor[i] = fgui_fRectColor[i];
Renderer()->SetConstants(sizeof(RectConstants_t), &constants);
Renderer()->Draw(fgui_pRectangleBuffer, NULL);
}
CUtlVector<CFont*> fgui_fonts;
CFont *fgui_pCurrentFont;
//----------------------------------------------------------------------------
// Loads new font
//----------------------------------------------------------------------------
CFont *IFGUI::LoadFont( CUtlString szFontPath )
{
for (auto &font: fgui_fonts)
{
if (font->szName == szFontPath)
return font;
};
CFont *pFont = new CFont;
pFont->szName = szFontPath;
pFont->pTexture = ITextureManager::LoadTexture(CUtlString("%s.png", szFontPath.GetString()));
FileHandle_t f = FileSystem()->Open(CUtlString("%s.fontdata", szFontPath.GetString()), IFILE_READ);
CUtlBuffer<char> b = FileSystem()->Size(f)+1;
FileSystem()->Read(f, b.GetMemory(), FileSystem()->Size(f));
FileSystem()->Close(f);
char cCharacterSet[256] = {};
V_memset(cCharacterSet, 0, 256);
uint32_t nElementsWidth;
uint32_t nElementsHeight;
V_sscanf(b, "%u %u %255s", &nElementsWidth, &nElementsHeight, cCharacterSet);
uint32_t nGlyphWidth = pFont->pTexture->x / nElementsWidth;
uint32_t nGlyphHeight = pFont->pTexture->y / nElementsHeight;
for ( int i = 0; i < 255; i++ )
{
if (isprint(cCharacterSet[i]) && !isspace(cCharacterSet[i]))
pFont->cCharacterSet[cCharacterSet[i]] = i;
else
pFont->cCharacterSet[cCharacterSet[i]] = -1;
}
pFont->glyphWidth = nGlyphWidth;
pFont->glyphHeight = nGlyphHeight;
pFont->nGlyphsPerRow = nElementsWidth;
pFont->nGlyphsPerColumn = nElementsHeight;
return pFont;
}
void IFGUI::SetGlyphScale( float x, float y )
{
fgui_fGlyphScale[0] = x;
fgui_fGlyphScale[1] = y;
};
void IFGUI::SetTextFont( CFont *pFont )
{
fgui_pTextFont = pFont;
}
void IFGUI::SetTextPos( float x, float y )
{
fgui_fTextPosition[0] = x;
fgui_fTextPosition[1] = y;
}
void IFGUI::SetTextColor( float r, float g, float b, float a )
{
fgui_fRectColor[0] = r;
fgui_fRectColor[1] = g;
fgui_fRectColor[2] = b;
fgui_fRectColor[3] = a;
}
void IFGUI::DrawText( CUtlString psz )
{
if (fgui_pTextFont == NULL)
{
V_printf("Forgot to call IFGUI::SetTextFont()?\n");
return;
}
Renderer()->BindPipeline(fgui_TextPipeline);
struct RectConstants_t
{
uint32_t nResolution[2];
uint32_t nSize[2];
int32_t nPosition[2];
float offest0[2];
float fColor[4];
float fGlyphPos[2];
float fGlyphSize[2];
uint32_t nFont;
} constants;
constants.nResolution[0] = g_nWindowWidth;
constants.nResolution[1] = g_nWindowHeight;
constants.nPosition[0] = fgui_fOffset[0] + fgui_fTextPosition[0];
constants.nPosition[1] = fgui_fOffset[1] + fgui_fTextPosition[1];
constants.nSize[0] = fgui_pTextFont->glyphWidth * fgui_fGlyphScale[0];
constants.nSize[1] = fgui_pTextFont->glyphHeight * fgui_fGlyphScale[1];
constants.fGlyphSize[0] = 1.0 / fgui_pTextFont->nGlyphsPerRow;
constants.fGlyphSize[1] = 1.0 / fgui_pTextFont->nGlyphsPerColumn;
constants.nFont = ITextureManager::GetTextureID(fgui_pTextFont->pTexture);
for ( int i = 0; i < 4; i++ )
constants.fColor[i] = fgui_fRectColor[i];
for ( int i = 0; psz[i]; i++)
{
constants.fGlyphPos[0] = fgui_pTextFont->cCharacterSet[psz[i]] % fgui_pTextFont->nGlyphsPerRow;
constants.fGlyphPos[1] = fgui_pTextFont->cCharacterSet[psz[i]] / fgui_pTextFont->nGlyphsPerRow;
if (isprint(psz[i]) && !isspace(psz[i]))
{
Renderer()->SetConstants(sizeof(RectConstants_t), &constants);
Renderer()->Draw(fgui_pUVRectangleBuffer, NULL);
}
constants.nPosition[0] += constants.nSize[0];
}
}
class CFGUI_Rendering: public IRenderingPipelineStep
{
public:
virtual void Init() override;
virtual void Frame( float fDelta ) override;
virtual void Deinit() override;
};
DECLARE_UI_RENDERING_STAGE(CFGUI_Rendering, fgui_rendering);
void CFGUI_Rendering::Init()
{
fgui_RectPipeline = Renderer()->CreateGraphicsPipeline(
{
{"gfx/fgui_rect_vert.shader", SHADER_TYPE_VERTEX},
{"gfx/fgui_rect_frag.shader", SHADER_TYPE_FRAGMENT},
},
{},
48,
8,
{{0,0,VERTEX_FORMAT_X32Y32}},
{IMAGE_FORMAT_WINDOW},
true
);
fgui_TextPipeline = Renderer()->CreateGraphicsPipeline(
{
{"gfx/fgui_text_vert.shader", SHADER_TYPE_VERTEX},
{"gfx/fgui_text_frag.shader", SHADER_TYPE_FRAGMENT},
},
{
{SHADER_INPUT_TYPE_TEXTURES, 29},
},
80,
16,
{{0,0, VERTEX_FORMAT_X32Y32},{8,1, VERTEX_FORMAT_X32Y32}},
{IMAGE_FORMAT_WINDOW},
true
);
{
float vertices[6*2] = {
0,0,
0,1,
1,0,
1,0,
0,1,
1,1,
};
fgui_pRectangleBuffer = Renderer()->CreateVertexBuffer(sizeof(vertices));
void *pMapping = fgui_pRectangleBuffer->Map();
V_memcpy(pMapping, vertices, sizeof(vertices));
fgui_pRectangleBuffer->Unmap();
}
{
float vertices[6*4] = {
0,0, 0,0,
0,1, 0,1,
1,0, 1,0,
1,0, 1,0,
0,1, 0,1,
1,1, 1,1,
};
fgui_pUVRectangleBuffer = Renderer()->CreateVertexBuffer(sizeof(vertices));
void *pMapping = fgui_pUVRectangleBuffer->Map();
V_memcpy(pMapping, vertices, sizeof(vertices));
fgui_pUVRectangleBuffer->Unmap();
}
};
void CFGUI_Rendering::Frame( float fDelta )
{
fgui_TextPipeline->PushBindings();
Renderer()->Begin(g_nWindowWidth, g_nWindowHeight, {
{
Renderer()->GetOutputImage(),
NULL,
ATTACHMENT_LOAD_MODE_LOAD,
ATTACHMENT_STORE_MODE_STORE,
}
}, {});
Renderer()->ResetState();
Renderer()->SetDepthMode(DEPTH_MODE_LESS);
for (auto &widget: fgui_widgets)
{
if (!widget->IsVisible())
{
continue;
}
IFGUI::ResetOffset();
widget->ComputeOffset();
widget->Draw();
}
Renderer()->End();
};
void CFGUI_Rendering::Deinit()
{
};