400 lines
9.8 KiB
C++
400 lines
9.8 KiB
C++
#include "kottui/kottui.h"
|
|
#include "tier0/lib.h"
|
|
#include "tier0/mem.h"
|
|
#include "tier1/utlstring.h"
|
|
#include "tier2/ifilesystem.h"
|
|
#include "tier2/fileformats/json.h"
|
|
#include "trig.h"
|
|
|
|
struct GlyphData_t
|
|
{
|
|
uint32_t m_uCharacter;
|
|
float m_fX;
|
|
float m_fY;
|
|
float m_fWidth;
|
|
float m_fHeight;
|
|
};
|
|
|
|
class CKotRenderFont: public IKotRenderFont
|
|
{
|
|
public:
|
|
virtual IImage *GetAtlas() override;
|
|
virtual bool IsLetterPresent( uint32_t letter ) override;
|
|
virtual float GetLetterX( uint32_t letter ) override;
|
|
virtual float GetLetterY( uint32_t letter ) override;
|
|
virtual float GetWidth( uint32_t letter ) override;
|
|
virtual float GetHeight( uint32_t letter ) override;
|
|
|
|
virtual bool IsMono() override;
|
|
virtual uint32_t GetLetterWidth() override;
|
|
virtual uint32_t GetLetterHeight() override;
|
|
|
|
GlyphData_t *m_glyphs;
|
|
uint32_t m_uGlyphCount;
|
|
IImage *m_pAtlas;
|
|
};
|
|
|
|
class CKotUIBuffer: public IKotUIBuffer
|
|
{
|
|
public:
|
|
virtual void SetPosition( int iY, int iX ) override;
|
|
|
|
virtual void Move( int iY, int iX ) override;
|
|
|
|
virtual void SetColor( char c ) override;
|
|
virtual void Clear( char c ) override;
|
|
|
|
virtual void PutChar( char c ) override;
|
|
virtual void Printf(const char *szFormat, ...) override;
|
|
|
|
virtual void Draw( IImage *pImage ) override;
|
|
|
|
virtual void SetTextSize( int iY, int iX ) override;
|
|
virtual void SetTextFont( IKotRenderFont *pFont ) override;
|
|
|
|
uint32_t *m_buffer;
|
|
ColorAlpha *m_primaryColor;
|
|
ColorAlpha *m_secondaryColor;
|
|
int m_iWidth = 0;
|
|
int m_iHeight = 0;
|
|
IBuffer *m_pDataBuffer;
|
|
|
|
IMaterial *m_pMaterial;
|
|
IRenderContext *m_pRenderContext;
|
|
IKotRenderFont *m_pFont;
|
|
|
|
uint32_t m_uCursor = 0;
|
|
};
|
|
|
|
class CKotUIManager: public IKotUIManager
|
|
{
|
|
public:
|
|
virtual void Init() override;
|
|
virtual void Shutdown() override;
|
|
virtual void ConnectInterface( void *pIface, const char *szName ) override;
|
|
|
|
virtual IKotRenderFont *LoadFont( const char *szPath ) override;
|
|
|
|
virtual IKotUIBuffer *CreateBuffer( int iWidth, int iHeight ) override;
|
|
virtual void DeleteBuffer( IKotUIBuffer *pBuffer ) override;
|
|
|
|
|
|
IRenderContext *m_pRenderContext;
|
|
ITextureArray *m_pFonts;
|
|
};
|
|
|
|
static IShader *s_pShader;
|
|
static CKotUIManager s_kotUIManager;
|
|
static IVertexBuffer *s_pGlyphBuffer;
|
|
|
|
IKotUIManager *KotUIManager()
|
|
{
|
|
return &s_kotUIManager;
|
|
}
|
|
EXPOSE_INTERFACE_FN(KotUIManager, IKotUIManager, KOT_UI_INTEFACE_VERSION);
|
|
|
|
IImage *CKotRenderFont::GetAtlas()
|
|
{
|
|
return m_pAtlas;
|
|
}
|
|
|
|
bool CKotRenderFont::IsLetterPresent( uint32_t letter )
|
|
{
|
|
for ( int i = 0; i < m_uGlyphCount; i++ )
|
|
{
|
|
GlyphData_t g = m_glyphs[i];
|
|
if (g.m_uCharacter == letter)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
float CKotRenderFont::GetLetterX( uint32_t letter )
|
|
{
|
|
for ( int i = 0; i < m_uGlyphCount; i++ )
|
|
{
|
|
GlyphData_t g = m_glyphs[i];
|
|
if (g.m_uCharacter == letter)
|
|
return g.m_fX;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
float CKotRenderFont::GetLetterY( uint32_t letter )
|
|
{
|
|
for ( int i = 0; i < m_uGlyphCount; i++ )
|
|
{
|
|
GlyphData_t g = m_glyphs[i];
|
|
if (g.m_uCharacter == letter)
|
|
return g.m_fY;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
float CKotRenderFont::GetWidth( uint32_t letter )
|
|
{
|
|
for ( int i = 0; i < m_uGlyphCount; i++ )
|
|
{
|
|
GlyphData_t g = m_glyphs[i];
|
|
if (g.m_uCharacter == letter)
|
|
return g.m_fWidth;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
float CKotRenderFont::GetHeight( uint32_t letter )
|
|
{
|
|
for ( int i = 0; i < m_uGlyphCount; i++ )
|
|
{
|
|
GlyphData_t g = m_glyphs[i];
|
|
if (g.m_uCharacter == letter)
|
|
return g.m_fHeight;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void CKotUIBuffer::SetPosition( int iY, int iX )
|
|
{
|
|
|
|
}
|
|
|
|
void CKotUIBuffer::Move( int iY, int iX )
|
|
{
|
|
m_uCursor = iY*m_iWidth+iX;
|
|
m_uCursor = m_uCursor % (m_iWidth * m_iHeight);
|
|
}
|
|
|
|
void CKotUIBuffer::SetColor( char c )
|
|
{
|
|
|
|
}
|
|
|
|
void CKotUIBuffer::Clear( char c )
|
|
{
|
|
|
|
}
|
|
|
|
void CKotUIBuffer::PutChar( char c )
|
|
{
|
|
m_buffer[m_uCursor] = c;
|
|
Move(0, m_uCursor+1);
|
|
|
|
}
|
|
|
|
void CKotUIBuffer::Printf(const char *szFormat, ...)
|
|
{
|
|
|
|
va_list vlArgs;
|
|
va_start(vlArgs, szFormat);
|
|
va_list vlArgs2;
|
|
va_copy(vlArgs2, vlArgs);
|
|
|
|
size_t nSize = V_vsnprintf(NULL, 0, szFormat, vlArgs2);
|
|
va_end(vlArgs2);
|
|
char *psz = (char*)V_malloc(nSize+1);
|
|
va_copy(vlArgs2, vlArgs);
|
|
V_vsnprintf(psz, nSize+1, szFormat, vlArgs2);
|
|
for ( size_t u = 0, i = m_uCursor; u < nSize; u++, i = (i + 1 % (m_iWidth * m_iHeight)) )
|
|
{
|
|
m_buffer[i] = psz[u];
|
|
}
|
|
va_end(vlArgs2);
|
|
V_free(psz);
|
|
va_end(vlArgs);
|
|
Move(0, m_uCursor+1);
|
|
|
|
}
|
|
|
|
struct TextDrawData_t
|
|
{
|
|
float m_vTexcoordOffsetX;
|
|
float m_vTexcoordOffsetY;
|
|
float m_vTexcoordSizeX;
|
|
float m_vTexcoordSizeY;
|
|
float m_fPosX;
|
|
float m_fPosY;
|
|
float m_fSizeX;
|
|
float m_fSizeY;
|
|
float m_fColor[4];
|
|
float m_fColor2[4];
|
|
};
|
|
|
|
struct ScreenData_t
|
|
{
|
|
float m_fScreenSizeX;
|
|
float m_fScreenSizeY;
|
|
};
|
|
|
|
void CKotUIBuffer::Draw( IImage *pImage )
|
|
{
|
|
uint32_t uGlyphCount = m_iWidth*m_iHeight;
|
|
uint32_t uRealGlyphCount = 0;
|
|
|
|
IRenderCommandList *pList = m_pRenderContext->CreateCommandList();
|
|
pList->StartRecording();
|
|
|
|
m_pDataBuffer->Lock();
|
|
TextDrawData_t *pData = (TextDrawData_t*)m_pDataBuffer->Map();
|
|
for ( uint32_t i = 0; i < uGlyphCount; i++ )
|
|
{
|
|
uint32_t l = m_buffer[i];
|
|
if ( !m_pFont->IsLetterPresent(l) )
|
|
continue;
|
|
pData[uRealGlyphCount].m_vTexcoordOffsetX = m_pFont->GetLetterX(l);
|
|
pData[uRealGlyphCount].m_vTexcoordOffsetY = m_pFont->GetLetterY(l);
|
|
pData[uRealGlyphCount].m_vTexcoordSizeX = m_pFont->GetWidth(l);
|
|
pData[uRealGlyphCount].m_vTexcoordSizeY = m_pFont->GetHeight(l);
|
|
pData[uRealGlyphCount].m_fSizeX = 16;
|
|
pData[uRealGlyphCount].m_fSizeY = 16;
|
|
pData[uRealGlyphCount].m_fPosX = i%m_iWidth*16;
|
|
pData[uRealGlyphCount].m_fPosY = i/m_iWidth*16;
|
|
uRealGlyphCount++;
|
|
}
|
|
m_pDataBuffer->Unmap();
|
|
m_pDataBuffer->Unlock();
|
|
|
|
IBuffer *pScreenBuffer = m_pRenderContext->CreateConstantBuffer(sizeof(ScreenData_t));
|
|
pScreenBuffer->Lock();
|
|
ScreenData_t *pScreenData = (ScreenData_t*)pScreenBuffer->Map();
|
|
pScreenData->m_fScreenSizeX = pImage->GetImageWidth();
|
|
pScreenData->m_fScreenSizeY = pImage->GetImageHeight();
|
|
pScreenBuffer->Unmap();
|
|
pScreenBuffer->Unlock();
|
|
|
|
m_pMaterial = m_pRenderContext->CreateMaterial(s_pShader);
|
|
m_pMaterial->PSSetShaderResource(0, m_pDataBuffer);
|
|
m_pMaterial->PSSetShaderResource(1, pScreenBuffer);
|
|
m_pMaterial->PSSetTexture(2, m_pFont->GetAtlas());
|
|
m_pMaterial->PSSetSampler(3, m_pRenderContext->GetDefaultSampler());
|
|
|
|
|
|
pList->SetRenderTarget(0, pImage);
|
|
pList->SetLoadStoreModes(0, LOAD_MODE_LOAD, STORE_MODE_STORE);
|
|
pList->SetRenderResolution(pImage->GetImageWidth(), pImage->GetImageHeight());
|
|
|
|
pList->SetMaterial(m_pMaterial);
|
|
pList->SetVertexBuffer(0, s_pGlyphBuffer);
|
|
pList->DrawPrimitives(6, 0, uRealGlyphCount, 0);
|
|
|
|
pList->EndRecording();
|
|
m_pRenderContext->SubmitCommandList(pList);
|
|
|
|
}
|
|
|
|
void CKotUIBuffer::SetTextSize( int iY, int iX )
|
|
{
|
|
|
|
|
|
}
|
|
|
|
void CKotUIBuffer::SetTextFont( IKotRenderFont *pFont )
|
|
{
|
|
m_pFont = pFont;
|
|
|
|
}
|
|
|
|
|
|
void CKotUIManager::Init()
|
|
{
|
|
s_pShader = m_pRenderContext->CreateShader("game/core/shaders/kottui.shader_c");
|
|
s_pShader->AddLayout(0, 8);
|
|
s_pShader->AddAttribute(0, 0, VERTEX_FORMAT_XY32_SFLOAT, 0);
|
|
s_pShader->AddOutputImage(0, IMAGE_FORMAT_RGBA8_UNORM);
|
|
s_pShader->Build();
|
|
s_pGlyphBuffer = m_pRenderContext->CreateVertexBuffer(sizeof(float)*12);
|
|
void *pBuffer = s_pGlyphBuffer->Map();
|
|
float vertices[12] = {
|
|
0, 0,
|
|
0, 1,
|
|
1, 0,
|
|
1, 0,
|
|
0, 1,
|
|
1, 1,
|
|
};
|
|
V_memcpy(pBuffer, vertices, sizeof(vertices));
|
|
s_pGlyphBuffer->Unmap();
|
|
|
|
m_pFonts = m_pRenderContext->CreateTextureArray();
|
|
|
|
|
|
}
|
|
|
|
void CKotUIManager::Shutdown()
|
|
{
|
|
|
|
}
|
|
|
|
void CKotUIManager::ConnectInterface( void *pFace, const char *psz )
|
|
{
|
|
if (!V_strcmp(psz, RENDER_CONTEXT_INTERFACE_VERSION))
|
|
m_pRenderContext = (IRenderContext*)pFace;
|
|
}
|
|
|
|
IKotRenderFont *CKotUIManager::LoadFont( const char *szPath )
|
|
{
|
|
CUtlString szAtlas = CUtlString("%s.png", szPath);
|
|
CUtlString szMeta = CUtlString("%s.fmd", szPath);
|
|
|
|
IFileHandle *pMetadataFile = filesystem->Open(szMeta, FILEMODE_READ);
|
|
if (!pMetadataFile)
|
|
return NULL;
|
|
const char *szMetadata = filesystem->ReadString(pMetadataFile);
|
|
filesystem->Close(pMetadataFile);
|
|
|
|
|
|
IJSONValue *pValue = JSONManager()->ReadString(szMetadata);
|
|
IJSONArray *pGlyphs = pValue->GetObject()->GetValue("glyphs")->GetArray();
|
|
uint32_t uAtlas = m_pFonts->LoadTexture(szAtlas);
|
|
|
|
CKotRenderFont *pFont = new CKotRenderFont;
|
|
pFont->m_pAtlas = pFont->m_pAtlas = m_pFonts->GetTexture(uAtlas);
|
|
uint32_t atlasWidth = pValue->GetObject()->GetValue("atlas")->GetObject()->GetValue("width")->GetNumberValue();
|
|
uint32_t atlasHeight = pValue->GetObject()->GetValue("atlas")->GetObject()->GetValue("height")->GetNumberValue();
|
|
|
|
pFont->m_uGlyphCount = 0;
|
|
pFont->m_glyphs = (GlyphData_t*)V_malloc(sizeof(GlyphData_t)*pGlyphs->GetCount());
|
|
for ( uint32_t i = 0; i < pGlyphs->GetCount(); i++ )
|
|
{
|
|
GlyphData_t glyph = {};
|
|
IJSONObject *pGlyph = pGlyphs->GetParameter(i)->GetObject();
|
|
if (pGlyph->GetValue("atlasBounds") == NULL)
|
|
continue;
|
|
IJSONObject *pAtlasBounds = pGlyph->GetValue("atlasBounds")->GetObject();
|
|
glyph.m_uCharacter = pGlyph->GetValue("unicode")->GetNumberValue();
|
|
glyph.m_fX = pAtlasBounds->GetValue("left")->GetNumberValue()/atlasWidth;
|
|
glyph.m_fY = 1-(pAtlasBounds->GetValue("bottom")->GetNumberValue()/atlasHeight);
|
|
glyph.m_fWidth = (
|
|
pAtlasBounds->GetValue("right")->GetNumberValue()
|
|
- pAtlasBounds->GetValue("left")->GetNumberValue()
|
|
) / atlasWidth;
|
|
glyph.m_fHeight = (
|
|
pAtlasBounds->GetValue("bottom")->GetNumberValue()
|
|
- pAtlasBounds->GetValue("top")->GetNumberValue()
|
|
) / atlasHeight;
|
|
pFont->m_glyphs[pFont->m_uGlyphCount++] = glyph;
|
|
}
|
|
return pFont;
|
|
|
|
}
|
|
|
|
IKotUIBuffer *CKotUIManager::CreateBuffer( int iWidth, int iHeight )
|
|
{
|
|
CKotUIBuffer *pBuffer = new CKotUIBuffer;
|
|
pBuffer->m_pRenderContext = m_pRenderContext;
|
|
pBuffer->m_buffer = (uint32_t*)V_malloc(sizeof(uint32_t)*iWidth*iHeight);
|
|
V_memset(pBuffer->m_buffer, 0, sizeof(uint32_t)*iWidth*iHeight);
|
|
pBuffer->m_iWidth = iWidth;
|
|
pBuffer->m_iHeight = iHeight;
|
|
|
|
pBuffer->m_pDataBuffer = m_pRenderContext->CreateStorageBuffer(sizeof(TextDrawData_t)*iWidth*iHeight);
|
|
return pBuffer;
|
|
}
|
|
|
|
void CKotUIManager::DeleteBuffer( IKotUIBuffer *pBuffer )
|
|
{
|
|
|
|
}
|
|
|