improved font rendering
This commit is contained in:
@@ -57,23 +57,27 @@ extern "C" void FunnyMain( int argc, char **argv )
|
||||
|
||||
EngineConsts_t stConstants = {};
|
||||
#ifdef STEAM
|
||||
V_printf("Steam :)\n");
|
||||
if(SteamAPI_RestartAppIfNecessary(480))
|
||||
{
|
||||
V_printf("Mshallah we are doing reboot\n");
|
||||
Plat_Exit(0);
|
||||
}
|
||||
|
||||
stConstants.m_bIsSteam = true;
|
||||
if (!SteamAPI_Init())
|
||||
if (SteamAPI_Init())
|
||||
{
|
||||
V_printf("Steam :)\n");
|
||||
stConstants.m_bIsSteam = true;
|
||||
stConstants.LaunchServer = LaunchServerAtSteamRelay;
|
||||
stConstants.ConnectSteamServer = ConnectBySteamID;
|
||||
SteamNetworkingUtils()->SetDebugOutputFunction(k_ESteamNetworkingSocketsDebugOutputType_Msg, SteamAPIDebug);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_printf("Steam :()\n");
|
||||
stConstants.m_bIsSteam = false;
|
||||
}
|
||||
stConstants.LaunchServer = LaunchServerAtSteamRelay;
|
||||
stConstants.ConnectSteamServer = ConnectBySteamID;
|
||||
|
||||
SteamNetworkingUtils()->SetDebugOutputFunction(k_ESteamNetworkingSocketsDebugOutputType_Msg, SteamAPIDebug);
|
||||
}
|
||||
|
||||
#endif
|
||||
stConstants.m_bIsDedicated = CommandLine()->CheckParam("-dedicated");
|
||||
stConstants.LaunchLocalBridge = LaunchLocalBridge;
|
||||
|
||||
@@ -32,6 +32,10 @@ public:
|
||||
GlyphData_t *m_glyphs;
|
||||
uint32_t m_uGlyphCount;
|
||||
IImage *m_pAtlas;
|
||||
|
||||
bool m_bIsMono = false;
|
||||
uint32_t m_uMonoWidth = 0;
|
||||
uint32_t m_uMonoHeight = 0;
|
||||
};
|
||||
|
||||
class CKotUIBuffer: public IKotUIBuffer
|
||||
@@ -41,8 +45,11 @@ public:
|
||||
|
||||
virtual void Move( int iY, int iX ) override;
|
||||
|
||||
virtual void SetColor( char c ) override;
|
||||
virtual void Clear( char c ) override;
|
||||
|
||||
virtual void SetColor( float fX, float fY, float fZ, float fA ) override;
|
||||
virtual void SetBackgroundColor( float fX, float fY, float fZ, float fA ) override;
|
||||
virtual void Clear( float fX, float fY, float fZ, float fA ) override;
|
||||
|
||||
|
||||
virtual void PutChar( char c ) override;
|
||||
virtual void Printf(const char *szFormat, ...) override;
|
||||
@@ -64,6 +71,12 @@ public:
|
||||
IKotRenderFont *m_pFont;
|
||||
|
||||
uint32_t m_uCursor = 0;
|
||||
|
||||
uint32_t m_uTextWidth = 16;
|
||||
uint32_t m_uTextHeight = 16;
|
||||
|
||||
ColorAlpha m_fgColor = {1,1,1,1};
|
||||
ColorAlpha m_bgColor = {0,0,0,0};
|
||||
};
|
||||
|
||||
class CKotUIManager: public IKotUIManager
|
||||
@@ -155,6 +168,24 @@ float CKotRenderFont::GetHeight( uint32_t letter )
|
||||
|
||||
|
||||
|
||||
bool CKotRenderFont::IsMono()
|
||||
{
|
||||
return m_bIsMono;
|
||||
|
||||
}
|
||||
|
||||
uint32_t CKotRenderFont::GetLetterWidth()
|
||||
{
|
||||
return m_uMonoWidth;
|
||||
|
||||
}
|
||||
|
||||
uint32_t CKotRenderFont::GetLetterHeight()
|
||||
{
|
||||
return m_uMonoHeight;
|
||||
}
|
||||
|
||||
|
||||
void CKotUIBuffer::SetPosition( int iY, int iX )
|
||||
{
|
||||
|
||||
@@ -166,19 +197,30 @@ void CKotUIBuffer::Move( int iY, int iX )
|
||||
m_uCursor = m_uCursor % (m_iWidth * m_iHeight);
|
||||
}
|
||||
|
||||
void CKotUIBuffer::SetColor( char c )
|
||||
|
||||
void CKotUIBuffer::SetColor( float fX, float fY, float fZ, float fA )
|
||||
{
|
||||
m_fgColor = {fX, fY, fZ, fA};
|
||||
}
|
||||
|
||||
void CKotUIBuffer::SetBackgroundColor( float fX, float fY, float fZ, float fA )
|
||||
{
|
||||
m_bgColor = {fX, fY, fZ, fA};
|
||||
|
||||
}
|
||||
|
||||
void CKotUIBuffer::Clear( float fX, float fY, float fZ, float fA )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CKotUIBuffer::Clear( char c )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CKotUIBuffer::PutChar( char c )
|
||||
{
|
||||
m_buffer[m_uCursor] = c;
|
||||
m_primaryColor[m_uCursor] = m_fgColor;
|
||||
m_secondaryColor[m_uCursor] = m_bgColor;
|
||||
Move(0, m_uCursor+1);
|
||||
|
||||
}
|
||||
@@ -199,6 +241,8 @@ void CKotUIBuffer::Printf(const char *szFormat, ...)
|
||||
for ( size_t u = 0, i = m_uCursor; u < nSize; u++, i = (i + 1 % (m_iWidth * m_iHeight)) )
|
||||
{
|
||||
m_buffer[i] = psz[u];
|
||||
m_primaryColor[i] = m_fgColor;
|
||||
m_secondaryColor[i] = m_bgColor;
|
||||
}
|
||||
va_end(vlArgs2);
|
||||
V_free(psz);
|
||||
@@ -217,8 +261,8 @@ struct TextDrawData_t
|
||||
float m_fPosY;
|
||||
float m_fSizeX;
|
||||
float m_fSizeY;
|
||||
float m_fColor[4];
|
||||
float m_fColor2[4];
|
||||
ColorAlpha m_fColor1;
|
||||
ColorAlpha m_fColor2;
|
||||
};
|
||||
|
||||
struct ScreenData_t
|
||||
@@ -240,16 +284,16 @@ void CKotUIBuffer::Draw( IImage *pImage )
|
||||
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;
|
||||
pData[uRealGlyphCount].m_fSizeX = m_uTextWidth;
|
||||
pData[uRealGlyphCount].m_fSizeY = m_uTextHeight;
|
||||
pData[uRealGlyphCount].m_fPosX = i%m_iWidth*m_uTextWidth;
|
||||
pData[uRealGlyphCount].m_fPosY = i/m_iWidth*m_uTextHeight;
|
||||
pData[uRealGlyphCount].m_fColor1 = m_primaryColor[i];
|
||||
pData[uRealGlyphCount].m_fColor2 = m_secondaryColor[i];
|
||||
uRealGlyphCount++;
|
||||
}
|
||||
m_pDataBuffer->Unmap();
|
||||
@@ -274,17 +318,24 @@ void CKotUIBuffer::Draw( IImage *pImage )
|
||||
pList->SetLoadStoreModes(0, LOAD_MODE_LOAD, STORE_MODE_STORE);
|
||||
pList->SetRenderResolution(pImage->GetImageWidth(), pImage->GetImageHeight());
|
||||
|
||||
pList->Barrier(m_pDataBuffer, true, false);
|
||||
pList->Barrier(pScreenBuffer, true, false);
|
||||
pList->Barrier(m_pFont->GetAtlas(), true, false);
|
||||
|
||||
pList->SetMaterial(m_pMaterial);
|
||||
pList->SetVertexBuffer(0, s_pGlyphBuffer);
|
||||
pList->DrawPrimitives(6, 0, uRealGlyphCount, 0);
|
||||
|
||||
pList->EndRecording();
|
||||
m_pRenderContext->SubmitCommandList(pList);
|
||||
m_pRenderContext->DestroyBuffer(pScreenBuffer);
|
||||
|
||||
}
|
||||
|
||||
void CKotUIBuffer::SetTextSize( int iY, int iX )
|
||||
{
|
||||
m_uTextHeight = iY;
|
||||
m_uTextWidth = iX;
|
||||
|
||||
|
||||
}
|
||||
@@ -301,7 +352,7 @@ 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->AddOutputImage(0, IMAGE_FORMAT_RGBA8_UNORM, true);
|
||||
s_pShader->Build();
|
||||
s_pGlyphBuffer = m_pRenderContext->CreateVertexBuffer(sizeof(float)*12);
|
||||
void *pBuffer = s_pGlyphBuffer->Map();
|
||||
@@ -349,9 +400,16 @@ IKotRenderFont *CKotUIManager::LoadFont( const char *szPath )
|
||||
uint32_t uAtlas = m_pFonts->LoadTexture(szAtlas);
|
||||
|
||||
CKotRenderFont *pFont = new CKotRenderFont;
|
||||
IJSONObject *pAtlas = pValue->GetObject()->GetValue("atlas")->GetObject();
|
||||
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();
|
||||
uint32_t atlasWidth = pAtlas->GetValue("width")->GetNumberValue();
|
||||
uint32_t atlasHeight = pAtlas->GetValue("height")->GetNumberValue();
|
||||
pFont->m_bIsMono = pAtlas->GetValue("grid") != NULL;
|
||||
if (pFont->m_bIsMono)
|
||||
{
|
||||
pFont->m_uMonoWidth = pAtlas->GetValue("grid")->GetObject()->GetValue("cellWidth")->GetNumberValue();
|
||||
pFont->m_uMonoHeight = pAtlas->GetValue("grid")->GetObject()->GetValue("cellHeight")->GetNumberValue();
|
||||
}
|
||||
|
||||
pFont->m_uGlyphCount = 0;
|
||||
pFont->m_glyphs = (GlyphData_t*)V_malloc(sizeof(GlyphData_t)*pGlyphs->GetCount());
|
||||
@@ -385,6 +443,10 @@ IKotUIBuffer *CKotUIManager::CreateBuffer( int iWidth, int iHeight )
|
||||
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_primaryColor = (ColorAlpha*)V_malloc(sizeof(ColorAlpha)*iWidth*iHeight);
|
||||
V_memset(pBuffer->m_primaryColor, 0, sizeof(ColorAlpha)*iWidth*iHeight);
|
||||
pBuffer->m_secondaryColor = (ColorAlpha*)V_malloc(sizeof(ColorAlpha)*iWidth*iHeight);
|
||||
V_memset(pBuffer->m_secondaryColor, 0, sizeof(ColorAlpha)*iWidth*iHeight);
|
||||
pBuffer->m_iWidth = iWidth;
|
||||
pBuffer->m_iHeight = iHeight;
|
||||
|
||||
|
||||
@@ -5,13 +5,12 @@ COMMON {
|
||||
{
|
||||
float4 m_vPosition: SV_POSITION;
|
||||
float2 m_vUV: TEXCOORD0;
|
||||
uint m_uFont;
|
||||
uint m_uFont: SV_InstanceID;
|
||||
}
|
||||
struct TextDrawData_t
|
||||
{
|
||||
float2 m_vTexcoordOffset;
|
||||
float2 m_vTexcoordSize;
|
||||
|
||||
float2 m_vPos;
|
||||
float2 m_vSize;
|
||||
float4 m_vFGColor;
|
||||
@@ -51,6 +50,7 @@ VS
|
||||
PS_INPUT output = {};
|
||||
output.m_vPosition = float4(position, 0, 1);
|
||||
output.m_vUV = uv;
|
||||
output.m_uFont = uInstance;
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,11 @@ PS
|
||||
float fSd = median3(vMsd.x, vMsd.y, vMsd.z);
|
||||
float fScreenPixelDistance = ScreenPixelRange(input.m_vUV)*(fSd-0.5);
|
||||
float fOpacity = clamp(fScreenPixelDistance+0.5, 0.0, 1.0);
|
||||
output.m_vAlbedo = fOpacity;
|
||||
float4 vColor1 = g_textData[input.m_uFont].m_vFGColor;
|
||||
float4 vColor2 = g_textData[input.m_uFont].m_vBGColor;
|
||||
vColor1.xyz*=vColor1.w;
|
||||
vColor2.xyz*=vColor2.w;
|
||||
output.m_vAlbedo = lerp(vColor2, vColor1, fOpacity);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@ IEngineBridge *EngineBridge()
|
||||
|
||||
EXPOSE_INTERFACE_FN(EngineBridge, IEngineBridge, ENGINE_BRIDGE_INTERFACE_VERSION)
|
||||
|
||||
static IKotUIBuffer *s_pUIBuffer;
|
||||
|
||||
void CFunnyGameBridge::Init()
|
||||
{
|
||||
Console()->AddCommand("exec game/core/default.cfg\n");
|
||||
@@ -77,16 +75,6 @@ void CFunnyGameBridge::Init()
|
||||
|
||||
g_pKotUI->ConnectInterface(g_pRenderContext, RENDER_CONTEXT_INTERFACE_VERSION);
|
||||
g_pKotUI->Init();
|
||||
IKotRenderFont *pFont = g_pKotUI->LoadFont("game/core/fonts/IBMPlexMono-Regular");
|
||||
s_pUIBuffer = g_pKotUI->CreateBuffer(40, 30);
|
||||
s_pUIBuffer->SetTextFont(pFont);
|
||||
s_pUIBuffer->SetTextSize(, int iX)
|
||||
s_pUIBuffer->Move(0, 0);
|
||||
s_pUIBuffer->Printf("hello %f", 20.0);
|
||||
s_pUIBuffer->Move(1, 0);
|
||||
s_pUIBuffer->Printf("hello %f", 40.0);
|
||||
s_pUIBuffer->Move(2, 0);
|
||||
s_pUIBuffer->Printf("hello %f", 40.0);
|
||||
}
|
||||
|
||||
void CFunnyGameBridge::Tick( float fDelta )
|
||||
@@ -183,7 +171,6 @@ void CFunnyGameBridge::Frame( float fDelta )
|
||||
EntitySystem()->NetSendThink(pCurrentServer);
|
||||
}
|
||||
g_pWorldRenderer->Frame(fDelta);
|
||||
s_pUIBuffer->Draw(g_pMainWindow->GetOutputImage());
|
||||
}
|
||||
|
||||
void CFunnyGameBridge::Shutdown()
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
#include "mainmenu.h"
|
||||
#include "fgui/label.h"
|
||||
#include "fgui/rect.h"
|
||||
#include "fgui/widget.h"
|
||||
#include "tier1/interface.h"
|
||||
|
||||
class CMOBAMainMenuGUI: public CFGUI_Widget
|
||||
{
|
||||
public:
|
||||
CMOBAMainMenuGUI();
|
||||
virtual void Event( FGUI_Event_t event ) override;
|
||||
virtual void Draw() override;
|
||||
virtual void Frame() override;
|
||||
private:
|
||||
CFGUI_Rect *m_pBackground;
|
||||
CFGUI_Label *m_pGameName;
|
||||
};
|
||||
|
||||
CMOBAMainMenuGUI::CMOBAMainMenuGUI()
|
||||
{
|
||||
SetPosition(0, 0);
|
||||
|
||||
|
||||
m_pBackground = new CFGUI_Rect;
|
||||
m_pBackground->SetParent(this);
|
||||
m_pBackground->SetPosition(90,90);
|
||||
m_pBackground->SetSize(300, 400);
|
||||
m_pBackground->SetBoxColor(0.1, 0.1, 0.1, 1);
|
||||
|
||||
m_pGameName = new CFGUI_Label;
|
||||
m_pGameName->SetParent(this);
|
||||
m_pGameName->SetFont("fonts/IBMPlexMono-Regular");
|
||||
m_pGameName->SetLabel("funnygame");
|
||||
m_pGameName->SetGlyphSize(24);
|
||||
m_pGameName->SetPosition(100, 100);
|
||||
};
|
||||
|
||||
void CMOBAMainMenuGUI::Event( FGUI_Event_t event )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CMOBAMainMenuGUI::Draw()
|
||||
{
|
||||
}
|
||||
|
||||
void CMOBAMainMenuGUI::Frame()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class CMOBAMainMenu: public IMainMenu
|
||||
{
|
||||
public:
|
||||
virtual void Init() override;
|
||||
virtual void Frame() override;
|
||||
virtual void Deinit() override;
|
||||
|
||||
virtual void SetVisibility( bool bIsVisible ) override;
|
||||
private:
|
||||
CMOBAMainMenuGUI *m_pMainMenu;
|
||||
};
|
||||
|
||||
|
||||
void CMOBAMainMenu::Init()
|
||||
{
|
||||
m_pMainMenu = new CMOBAMainMenuGUI;
|
||||
m_pMainMenu->SetVisibility(true);
|
||||
}
|
||||
|
||||
void CMOBAMainMenu::Frame()
|
||||
{
|
||||
}
|
||||
|
||||
void CMOBAMainMenu::SetVisibility( bool bIsVisible )
|
||||
{
|
||||
m_pMainMenu->SetVisibility(bIsVisible);
|
||||
}
|
||||
|
||||
void CMOBAMainMenu::Deinit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DECLARE_ENGINE_INTERFACE(MainMenu, CMOBAMainMenu);
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ void C_MOBAPlayer::Think( float fDelta )
|
||||
g_pWorldRenderer->SetCameraPosition(vCameraPos);
|
||||
Quat vCameraRot;
|
||||
glm_euler_yxz_quat((vec3){m_fPitch, m_fYaw, 0}, *(versor*)&vCameraRot);
|
||||
//g_pWorldRenderer->SetCameraRotation(vCameraRot);
|
||||
g_pWorldRenderer->SetCameraRotation(vCameraRot);
|
||||
}
|
||||
BaseClass::Think(fDelta);
|
||||
};
|
||||
|
||||
0
game/client/milmoba/ui/gameplay.cpp
Normal file
0
game/client/milmoba/ui/gameplay.cpp
Normal file
0
game/client/milmoba/ui/gameplay.h
Normal file
0
game/client/milmoba/ui/gameplay.h
Normal file
0
game/client/milmoba/ui/mainmenu.cpp
Normal file
0
game/client/milmoba/ui/mainmenu.cpp
Normal file
0
game/client/milmoba/ui/mainmenu.h
Normal file
0
game/client/milmoba/ui/mainmenu.h
Normal file
@@ -208,7 +208,6 @@ void CVkCommandBuffer::SortDependencies()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
for (auto &pCommand: m_commands)
|
||||
{
|
||||
for ( auto dependency: pCommand->m_dependencies)
|
||||
@@ -263,7 +262,6 @@ void CVkCommandBuffer::SortDependencies()
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +309,6 @@ void CVkCommandBuffer::TryBarrier( int iCurrent, int iCurrentBuffer )
|
||||
|
||||
if (dynamic_cast<CVkImage*>(pObject))
|
||||
{
|
||||
|
||||
VkImageMemoryBarrier2 imageMemoryBarrier = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||
imageMemoryBarrier.image = pImage->m_image;
|
||||
|
||||
@@ -48,7 +48,7 @@ CVkMaterial::~CVkMaterial()
|
||||
|
||||
void CVkMaterial::Frame()
|
||||
{
|
||||
vkUpdateDescriptorSets(m_pVkShader->m_hDevice, m_writes.GetSize(), m_writes.GetData(), 0, 0);
|
||||
//vkUpdateDescriptorSets(m_pVkShader->m_hDevice, m_writes.GetSize(), m_writes.GetData(), 0, 0);
|
||||
};
|
||||
|
||||
void CVkMaterial::VSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource )
|
||||
@@ -185,7 +185,6 @@ void CVkMaterial::SetShaderResource( uint32_t uRegister, uint32_t uSet, IRenderi
|
||||
writes[1].descriptorCount = 128;
|
||||
writes[1].pImageInfo = stWrites;
|
||||
vkUpdateDescriptorSets(m_pVkShader->m_hDevice, 2, writes, 0, 0);
|
||||
m_pTextureArray = pArray;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ void CVkRenderCommandList::SetMaterial( IMaterial *pMaterial )
|
||||
pBeginCommand->nResolutionY = m_uHeight;
|
||||
for ( auto &i: pBeginCommand->images)
|
||||
{
|
||||
pBeginCommand->AddDependency(i.m_stImage.m_pSingle, DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE);
|
||||
pBeginCommand->AddDependency(i.m_stImage.m_pSingle, DEPENDENCY_MODE_DRAWCALL_MIXED_IMAGE);
|
||||
}
|
||||
if ( m_bDepthEnabled )
|
||||
{
|
||||
@@ -118,10 +118,6 @@ void CVkRenderCommandList::SetMaterial( IMaterial *pMaterial )
|
||||
|
||||
CVkSetShaderDataCommand *pSetShaderData = CREATE_COMMAND(m_pCommandBufferManager, SetShaderData);
|
||||
pSetShaderData->pShaderData = pMaterial;
|
||||
{
|
||||
CVkTextureArray *pArray = (CVkTextureArray*)((CVkMaterial*)pMaterial)->m_pTextureArray;
|
||||
|
||||
}
|
||||
m_pCurrentMaterialBuffer->AddCommand(pSetShaderData);
|
||||
|
||||
CVkSetScissorsCommand *pScissorsCommand = CREATE_COMMAND(m_pCommandBufferManager, SetScissors);
|
||||
@@ -146,6 +142,7 @@ void CVkRenderCommandList::SetVertexBuffer( uint32_t uBinding, IVertexBuffer *pB
|
||||
CVkSetVertexBufferCommand *pCmd = CREATE_COMMAND(m_pCommandBufferManager, SetVertexBuffer);
|
||||
pCmd->uBinding = uBinding;
|
||||
pCmd->pBuffer = pBuffer;
|
||||
pCmd->AddDependency(pBuffer, DEPENDENCY_MODE_BUFFER_SOURCE);
|
||||
m_pCurrentMaterialBuffer->AddCommand(pCmd);
|
||||
}
|
||||
|
||||
@@ -163,6 +160,34 @@ void CVkRenderCommandList::DrawPrimitives( uint32_t nVertexCount, uint32_t nFirs
|
||||
pCmd->nFirstVertex = nFirstVertex;
|
||||
pCmd->nInstanceCount = nInstanceCount;
|
||||
pCmd->nFirstInstance = nFirstInstance;
|
||||
for ( auto &b: m_barriers )
|
||||
{
|
||||
if (dynamic_cast<CVkBuffer*>(b.pObject))
|
||||
{
|
||||
if (b.m_bIsRead)
|
||||
if (b.m_bIsWrite)
|
||||
pCmd->AddDependency(b.pObject, DEPENDENCY_MODE_SHADER_BUFFER_READ_WRITE);
|
||||
else
|
||||
pCmd->AddDependency(b.pObject, DEPENDENCY_MODE_SHADER_BUFFER_READ);
|
||||
else
|
||||
if (b.m_bIsWrite)
|
||||
pCmd->AddDependency(b.pObject, DEPENDENCY_MODE_SHADER_BUFFER_WRITE);
|
||||
|
||||
}
|
||||
if (dynamic_cast<CVkImage*>(b.pObject))
|
||||
{
|
||||
if (b.m_bIsRead)
|
||||
if (b.m_bIsWrite)
|
||||
pCmd->AddDependency(b.pObject, DEPENDENCY_MODE_SHADER_IMAGE_READ_WRITE);
|
||||
else
|
||||
pCmd->AddDependency(b.pObject, DEPENDENCY_MODE_SHADER_IMAGE_READ);
|
||||
else
|
||||
if (b.m_bIsWrite)
|
||||
pCmd->AddDependency(b.pObject, DEPENDENCY_MODE_SHADER_IMAGE_WRITE);
|
||||
|
||||
}
|
||||
}
|
||||
m_barriers = {};
|
||||
m_pCurrentMaterialBuffer->AddCommand(pCmd);
|
||||
}
|
||||
|
||||
@@ -182,8 +207,8 @@ void CVkRenderCommandList::ResolveImage( IImage *pOriginal, IImage *pResolved )
|
||||
pCmd->stInputImage.m_pSingle = pOriginal;
|
||||
pCmd->stOutputImage.m_eObjectType = FRAME_OBJECT_TYPE_SINGLE;
|
||||
pCmd->stOutputImage.m_pSingle = pResolved;
|
||||
pCmd->AddDependency(pOriginal, DEPENDENCY_MODE_IMAGE_SOURCE);
|
||||
pCmd->AddDependency(pResolved, DEPENDENCY_MODE_IMAGE_DESTINATION);
|
||||
pCmd->AddDependency(pOriginal, DEPENDENCY_MODE_IMAGE_RESOLVE_SOURCE);
|
||||
pCmd->AddDependency(pResolved, DEPENDENCY_MODE_IMAGE_RESOLVE_DESTINATION);
|
||||
m_pPostRaster->AddCommand(pCmd);
|
||||
}
|
||||
|
||||
@@ -198,6 +223,11 @@ void CVkRenderCommandList::EndRecording()
|
||||
SwitchRenderingStage(RENDERING_STAGE_FINISHED);
|
||||
}
|
||||
|
||||
void CVkRenderCommandList::Barrier( IRenderingObject *pObject, bool bIsRead, bool bIsWrite )
|
||||
{
|
||||
m_barriers.AppendTail({pObject, bIsRead, bIsWrite});
|
||||
}
|
||||
|
||||
void CVkRenderCommandList::Submit()
|
||||
{
|
||||
for ( auto m: m_pCommandBuffers)
|
||||
|
||||
@@ -932,6 +932,7 @@ void CVkRenderContext::Frame( float fDeltaTime )
|
||||
|
||||
double a = Plat_GetTime();
|
||||
i = 0;
|
||||
CVkEmptyCommand *pEmptyCommand = CREATE_COMMAND(m_pCommandBufferManager, Empty);
|
||||
for ( auto &s: m_renderWindows )
|
||||
{
|
||||
|
||||
@@ -952,11 +953,14 @@ void CVkRenderContext::Frame( float fDeltaTime )
|
||||
pBlitCommand->iDstMax[0] = s.m_pWindow->GetRenderWidth();
|
||||
pBlitCommand->iDstMax[1] = s.m_pWindow->GetRenderHeight();
|
||||
pBlitCommand->iDstMax[2] = 1;
|
||||
|
||||
pEmptyCommand->AddDependency((IRenderingObject*)s.m_images[uSwapchainImageIndexes[i]], DEPENDENCY_MODE_IMAGE_PRESENT);
|
||||
}
|
||||
if (pBlitCommand != NULL)
|
||||
s_pPresentCommandBuffer->AddCommand(pBlitCommand);
|
||||
i++;
|
||||
}
|
||||
s_pPresentCommandBuffer->AddCommand(pEmptyCommand);
|
||||
|
||||
s_pPresentCommandBuffer->Render();
|
||||
s_pPresentCommandBuffer->Submit(0);
|
||||
|
||||
@@ -27,9 +27,9 @@ void CVkShader::SetTopology( ETopologyMode eTopology )
|
||||
|
||||
}
|
||||
|
||||
void CVkShader::AddOutputImage( int iImageIndex, EImageFormat eFormat )
|
||||
void CVkShader::AddOutputImage( int iImageIndex, EImageFormat eFormat, bool bBlendingEnabled )
|
||||
{
|
||||
m_eFormats.AppendTail(CVkImage::GetImageFormat(eFormat));
|
||||
m_formats.AppendTail({CVkImage::GetImageFormat(eFormat), bBlendingEnabled});
|
||||
}
|
||||
|
||||
void CVkShader::SetDepthImage( EImageFormat eFormat )
|
||||
@@ -68,6 +68,7 @@ void CVkShader::Build()
|
||||
};
|
||||
VkPipelineLayoutCreateInfo stPipelineLayout = {};
|
||||
CUtlVector<CUtlVector<VkDescriptorSetLayoutBinding>> bindings = {};
|
||||
CUtlVector<VkFormat> formats = {};
|
||||
|
||||
// TODO: Filter by vulkan shaders at some points
|
||||
stages.Resize(m_shader.m_objects.GetSize());
|
||||
@@ -163,10 +164,13 @@ void CVkShader::Build()
|
||||
msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
msaa.rasterizationSamples = CVkImage::GetMultisampling(m_eMultiSampling);
|
||||
|
||||
formats.Resize(m_formats.GetSize());
|
||||
for ( uint32_t i = 0; i < m_formats.GetSize(); i++ )
|
||||
formats[i] = m_formats[i].m_eFormat;
|
||||
|
||||
render.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
||||
render.colorAttachmentCount = m_eFormats.GetSize();
|
||||
render.pColorAttachmentFormats = m_eFormats.GetData();
|
||||
render.colorAttachmentCount = formats.GetSize();
|
||||
render.pColorAttachmentFormats = formats.GetData();
|
||||
|
||||
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
if (m_eDepthFormat == VK_FORMAT_D32_SFLOAT)
|
||||
@@ -177,11 +181,23 @@ void CVkShader::Build()
|
||||
render.depthAttachmentFormat = m_eDepthFormat;
|
||||
}
|
||||
|
||||
for ( auto e: m_eFormats )
|
||||
for ( auto e: m_formats )
|
||||
{
|
||||
VkPipelineColorBlendAttachmentState a = {};
|
||||
a.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
a.blendEnable = VK_FALSE;
|
||||
if (e.m_bIsBlendingEnabled)
|
||||
{
|
||||
a.blendEnable = VK_TRUE;
|
||||
a.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
a.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
a.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
a.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
a.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
a.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
}
|
||||
else
|
||||
a.blendEnable = VK_FALSE;
|
||||
attachments.AppendTail(a);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,17 +21,26 @@ VkAccessFlags2 VulkanGetAccessFlags( EDependencyMode eMode )
|
||||
case DEPENDENCY_MODE_JUST_CREATED: return VK_ACCESS_2_NONE;
|
||||
case DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE: return VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR;
|
||||
case DEPENDENCY_MODE_DRAWCALL_OUTPUT_DEPTH_IMAGE: return VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
case DEPENDENCY_MODE_DRAWCALL_MIXED_IMAGE: return VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR;
|
||||
case DEPENDENCY_MODE_COLOR_CLEAR_DESTINATION: return VK_ACCESS_2_TRANSFER_WRITE_BIT;
|
||||
case DEPENDENCY_MODE_IMAGE_PRESENT: return VK_ACCESS_2_NONE;
|
||||
case DEPENDENCY_MODE_SHADER_BUFFER_READ: return VK_ACCESS_2_SHADER_READ_BIT;
|
||||
case DEPENDENCY_MODE_SHADER_BUFFER_WRITE: return VK_ACCESS_2_SHADER_READ_BIT;
|
||||
case DEPENDENCY_MODE_SHADER_BUFFER_READ_WRITE: return VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT;
|
||||
case DEPENDENCY_MODE_SHADER_IMAGE_READ: return VK_ACCESS_2_SHADER_READ_BIT;
|
||||
case DEPENDENCY_MODE_SHADER_IMAGE_WRITE: return VK_ACCESS_2_SHADER_READ_BIT;
|
||||
case DEPENDENCY_MODE_SHADER_IMAGE_READ_WRITE: return VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT;
|
||||
|
||||
case DEPENDENCY_MODE_BLIT_IMAGE_SOURCE:
|
||||
case DEPENDENCY_MODE_IMAGE_SOURCE:
|
||||
case DEPENDENCY_MODE_BUFFER_SOURCE:
|
||||
case DEPENDENCY_MODE_IMAGE_RESOLVE_SOURCE:
|
||||
return VK_ACCESS_2_TRANSFER_READ_BIT;
|
||||
|
||||
case DEPENDENCY_MODE_IMAGE_DESTINATION:
|
||||
case DEPENDENCY_MODE_BLIT_IMAGE_DESTINATION:
|
||||
case DEPENDENCY_MODE_BUFFER_DESTINATION:
|
||||
case DEPENDENCY_MODE_IMAGE_RESOLVE_DESTINATION:
|
||||
return VK_ACCESS_2_TRANSFER_WRITE_BIT;
|
||||
|
||||
default:
|
||||
@@ -46,19 +55,24 @@ VkPipelineStageFlags2 VulkanGetStageFlags( EDependencyMode eMode )
|
||||
case DEPENDENCY_MODE_JUST_CREATED: return VK_PIPELINE_STAGE_2_NONE;
|
||||
case DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE: return VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
case DEPENDENCY_MODE_DRAWCALL_OUTPUT_DEPTH_IMAGE: return VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT;
|
||||
case DEPENDENCY_MODE_DRAWCALL_MIXED_IMAGE: return VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
case DEPENDENCY_MODE_COLOR_CLEAR_DESTINATION: return VK_PIPELINE_STAGE_2_TRANSFER_BIT;
|
||||
case DEPENDENCY_MODE_IMAGE_PRESENT: return VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
||||
case DEPENDENCY_MODE_BLIT_IMAGE_DESTINATION:
|
||||
case DEPENDENCY_MODE_BLIT_IMAGE_SOURCE:
|
||||
case DEPENDENCY_MODE_BLIT_IMAGE_DESTINATION:
|
||||
return VK_PIPELINE_STAGE_2_BLIT_BIT;
|
||||
|
||||
case DEPENDENCY_MODE_BUFFER_SOURCE:
|
||||
case DEPENDENCY_MODE_BUFFER_DESTINATION:
|
||||
case DEPENDENCY_MODE_IMAGE_SOURCE:
|
||||
case DEPENDENCY_MODE_BUFFER_DESTINATION:
|
||||
case DEPENDENCY_MODE_IMAGE_DESTINATION:
|
||||
return VK_PIPELINE_STAGE_2_COPY_BIT;
|
||||
|
||||
case DEPENDENCY_MODE_IMAGE_RESOLVE_SOURCE:
|
||||
case DEPENDENCY_MODE_IMAGE_RESOLVE_DESTINATION:
|
||||
return VK_PIPELINE_STAGE_2_RESOLVE_BIT;
|
||||
|
||||
default:
|
||||
return VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
||||
}
|
||||
@@ -71,16 +85,25 @@ VkImageLayout VulkanGetImageLayout( EDependencyMode eMode )
|
||||
case DEPENDENCY_MODE_JUST_CREATED: return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
case DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
case DEPENDENCY_MODE_DRAWCALL_OUTPUT_DEPTH_IMAGE: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
|
||||
case DEPENDENCY_MODE_DRAWCALL_MIXED_IMAGE: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
case DEPENDENCY_MODE_COLOR_CLEAR_DESTINATION: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
case DEPENDENCY_MODE_IMAGE_PRESENT: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
case DEPENDENCY_MODE_BLIT_IMAGE_SOURCE:
|
||||
case DEPENDENCY_MODE_IMAGE_SOURCE:
|
||||
case DEPENDENCY_MODE_BUFFER_SOURCE:
|
||||
case DEPENDENCY_MODE_IMAGE_RESOLVE_SOURCE:
|
||||
return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
case DEPENDENCY_MODE_BLIT_IMAGE_DESTINATION:
|
||||
case DEPENDENCY_MODE_IMAGE_DESTINATION:
|
||||
case DEPENDENCY_MODE_BUFFER_DESTINATION:
|
||||
case DEPENDENCY_MODE_IMAGE_RESOLVE_DESTINATION:
|
||||
return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
|
||||
case DEPENDENCY_MODE_SHADER_IMAGE_READ:
|
||||
case DEPENDENCY_MODE_SHADER_IMAGE_WRITE:
|
||||
case DEPENDENCY_MODE_SHADER_IMAGE_READ_WRITE:
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
default:
|
||||
return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ enum EDependencyMode
|
||||
DEPENDENCY_MODE_SHADER_BUFFER_READ,
|
||||
DEPENDENCY_MODE_SHADER_IMAGE_WRITE,
|
||||
DEPENDENCY_MODE_SHADER_BUFFER_WRITE,
|
||||
DEPENDENCY_MODE_SHADER_BUFFER_READ_WRITE,
|
||||
DEPENDENCY_MODE_SHADER_IMAGE_READ_WRITE,
|
||||
DEPENDENCY_MODE_SHADER_ACCELERATION_STRUCTURE,
|
||||
|
||||
DEPENDENCY_MODE_DRAWCALL_VERTEX_BUFFER,
|
||||
@@ -63,6 +65,9 @@ enum EDependencyMode
|
||||
DEPENDENCY_MODE_IMAGE_DESTINATION,
|
||||
DEPENDENCY_MODE_BUFFER_DESTINATION,
|
||||
|
||||
DEPENDENCY_MODE_IMAGE_RESOLVE_SOURCE,
|
||||
DEPENDENCY_MODE_IMAGE_RESOLVE_DESTINATION,
|
||||
|
||||
DEPENDENCY_MODE_BLIT_IMAGE_SOURCE,
|
||||
DEPENDENCY_MODE_BLIT_IMAGE_DESTINATION,
|
||||
|
||||
@@ -97,7 +102,7 @@ struct VulkanCommandParameter_t
|
||||
};
|
||||
};
|
||||
|
||||
abstract_class CVkCommand
|
||||
class CVkCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute( VkCommandBuffer hCommandBuffer, int iCurrentFrame ) = 0;
|
||||
@@ -266,6 +271,12 @@ void CVk##name##PipelineLibrary::Build() \
|
||||
vkCreateGraphicsPipelines(m_hDevice, NULL, 1, &pipeline, NULL, &m_hPipeline); \
|
||||
}
|
||||
|
||||
struct VkOutputImageConfig_t
|
||||
{
|
||||
VkFormat m_eFormat;
|
||||
bool m_bIsBlendingEnabled;
|
||||
};
|
||||
|
||||
class CVkShader : public IShader
|
||||
{
|
||||
public:
|
||||
@@ -273,7 +284,7 @@ public:
|
||||
virtual void AddLayout( int iIndex, int iStride ) override;
|
||||
virtual void AddAttribute( int iBufferIndex, int iLocation, EVertexFormat eFormat, int iOffset ) override;
|
||||
virtual void SetTopology( ETopologyMode eTopology ) override;
|
||||
virtual void AddOutputImage( int iImageIndex, EImageFormat eFormat ) override;
|
||||
virtual void AddOutputImage( int iImageIndex, EImageFormat eFormat, bool bBlendingEnabled ) override;
|
||||
virtual void SetDepthImage( EImageFormat eFormat ) override;
|
||||
virtual void SetMultisampling( EMultisampleType eFormat ) override;
|
||||
virtual void DisablePixelShader( bool bDisable ) override;
|
||||
@@ -289,7 +300,7 @@ public:
|
||||
private:
|
||||
CUtlVector<VkVertexInputBindingDescription> m_layouts;
|
||||
CUtlVector<VkVertexInputAttributeDescription> m_attributes;
|
||||
CUtlVector<VkFormat> m_eFormats;
|
||||
CUtlVector<VkOutputImageConfig_t> m_formats;
|
||||
EMultisampleType m_eMultiSampling;
|
||||
VkFormat m_eDepthFormat;
|
||||
bool m_bIsFragmentEnabled;
|
||||
@@ -389,7 +400,6 @@ public:
|
||||
|
||||
CVkShader *m_pVkShader;
|
||||
CUtlVector<VkDescriptorSet> m_hSets;
|
||||
ITextureArray *m_pTextureArray;
|
||||
private:
|
||||
VkDescriptorPool m_hPool;
|
||||
CUtlVector<VkWriteDescriptorSet> m_writes = {};
|
||||
@@ -442,6 +452,13 @@ struct VulkanRenderOutput_t {
|
||||
EStoreMode m_eStoreMode;
|
||||
};
|
||||
|
||||
struct VkRenderBarrier_t
|
||||
{
|
||||
IRenderingObject *pObject;
|
||||
bool m_bIsRead;
|
||||
bool m_bIsWrite;
|
||||
};
|
||||
|
||||
class CVkRenderCommandList: public IRenderCommandList
|
||||
{
|
||||
public:
|
||||
@@ -472,6 +489,8 @@ public:
|
||||
virtual void StartRecording() override;
|
||||
virtual void EndRecording() override;
|
||||
|
||||
virtual void Barrier( IRenderingObject *pObject, bool bIsRead, bool bIsWrite ) override;
|
||||
|
||||
void Submit();
|
||||
|
||||
IVkCommandBufferManager *m_pCommandBufferManager;
|
||||
@@ -494,6 +513,7 @@ private:
|
||||
uint32_t m_uHeight;
|
||||
CUtlVector<IVkCommandBuffer*> m_pCommandBuffers = {};
|
||||
CUtlVector<IVkCommandBuffer*> m_pScheduledDestroyPostRaster = {};
|
||||
CUtlVector<VkRenderBarrier_t> m_barriers = {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -27,8 +27,9 @@ public:
|
||||
|
||||
virtual void Move( int iY, int iX ) = 0;
|
||||
|
||||
virtual void SetColor( char c ) = 0;
|
||||
virtual void Clear( char c ) = 0;
|
||||
virtual void SetColor( float fX, float fY, float fZ, float fA ) = 0;
|
||||
virtual void SetBackgroundColor( float fX, float fY, float fZ, float fA ) = 0;
|
||||
virtual void Clear( float fX, float fY, float fZ, float fA ) = 0;
|
||||
|
||||
virtual void PutChar( char c ) = 0;
|
||||
virtual void Printf(const char *szFormat, ...) = 0;
|
||||
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
virtual void AddLayout( int iIndex, int iStride ) = 0;
|
||||
virtual void AddAttribute( int iBufferIndex, int iLocation, EVertexFormat eFormat, int iOffset ) = 0;
|
||||
virtual void SetTopology( ETopologyMode eTopology ) = 0;
|
||||
virtual void AddOutputImage( int iImageIndex, EImageFormat eFormat ) = 0;
|
||||
virtual void AddOutputImage( int iImageIndex, EImageFormat eFormat, bool bBlendingEnabled = false ) = 0;
|
||||
virtual void SetDepthImage( EImageFormat eFormat ) = 0;
|
||||
virtual void SetMultisampling( EMultisampleType eFormat ) = 0;
|
||||
virtual void DisablePixelShader( bool bDisable) = 0;
|
||||
@@ -287,6 +287,8 @@ public:
|
||||
|
||||
virtual void StartRecording() = 0;
|
||||
virtual void EndRecording() = 0;
|
||||
|
||||
virtual void Barrier( IRenderingObject *pObject, bool bIsRead, bool bIsWrite ) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user