2011-12-31 00:06:04 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
# include <base/detect.h>
# include <base/math.h>
2012-02-05 12:22:39 +00:00
# include <base/tl/threading.h>
2011-12-31 00:06:04 +00:00
2014-01-19 03:02:01 +00:00
# if defined(CONF_FAMILY_UNIX)
# include <pthread.h>
# endif
2011-12-31 00:06:04 +00:00
# include <base/system.h>
2018-02-12 22:14:14 +00:00
# include <pnglite.h>
2011-12-31 00:06:04 +00:00
# include <engine/shared/config.h>
# include <engine/graphics.h>
# include <engine/storage.h>
# include <engine/keys.h>
# include <engine/console.h>
2020-08-31 11:07:42 +00:00
# include <game/localization.h>
2011-12-31 00:06:04 +00:00
2017-10-09 16:58:44 +00:00
# include <math.h> // cosf, sinf, log2f
2011-12-31 00:06:04 +00:00
2020-06-19 06:19:40 +00:00
# if defined(CONF_VIDEORECORDER)
# include "video.h"
# endif
2011-12-31 00:11:24 +00:00
# include "graphics_threaded.h"
2011-12-31 00:06:04 +00:00
static CVideoMode g_aFakeModes [ ] = {
{ 320 , 240 , 8 , 8 , 8 } , { 400 , 300 , 8 , 8 , 8 } , { 640 , 480 , 8 , 8 , 8 } ,
{ 720 , 400 , 8 , 8 , 8 } , { 768 , 576 , 8 , 8 , 8 } , { 800 , 600 , 8 , 8 , 8 } ,
{ 1024 , 600 , 8 , 8 , 8 } , { 1024 , 768 , 8 , 8 , 8 } , { 1152 , 864 , 8 , 8 , 8 } ,
{ 1280 , 768 , 8 , 8 , 8 } , { 1280 , 800 , 8 , 8 , 8 } , { 1280 , 960 , 8 , 8 , 8 } ,
{ 1280 , 1024 , 8 , 8 , 8 } , { 1368 , 768 , 8 , 8 , 8 } , { 1400 , 1050 , 8 , 8 , 8 } ,
{ 1440 , 900 , 8 , 8 , 8 } , { 1440 , 1050 , 8 , 8 , 8 } , { 1600 , 1000 , 8 , 8 , 8 } ,
{ 1600 , 1200 , 8 , 8 , 8 } , { 1680 , 1050 , 8 , 8 , 8 } , { 1792 , 1344 , 8 , 8 , 8 } ,
{ 1800 , 1440 , 8 , 8 , 8 } , { 1856 , 1392 , 8 , 8 , 8 } , { 1920 , 1080 , 8 , 8 , 8 } ,
{ 1920 , 1200 , 8 , 8 , 8 } , { 1920 , 1440 , 8 , 8 , 8 } , { 1920 , 2400 , 8 , 8 , 8 } ,
{ 2048 , 1536 , 8 , 8 , 8 } ,
{ 320 , 240 , 5 , 6 , 5 } , { 400 , 300 , 5 , 6 , 5 } , { 640 , 480 , 5 , 6 , 5 } ,
{ 720 , 400 , 5 , 6 , 5 } , { 768 , 576 , 5 , 6 , 5 } , { 800 , 600 , 5 , 6 , 5 } ,
{ 1024 , 600 , 5 , 6 , 5 } , { 1024 , 768 , 5 , 6 , 5 } , { 1152 , 864 , 5 , 6 , 5 } ,
{ 1280 , 768 , 5 , 6 , 5 } , { 1280 , 800 , 5 , 6 , 5 } , { 1280 , 960 , 5 , 6 , 5 } ,
{ 1280 , 1024 , 5 , 6 , 5 } , { 1368 , 768 , 5 , 6 , 5 } , { 1400 , 1050 , 5 , 6 , 5 } ,
{ 1440 , 900 , 5 , 6 , 5 } , { 1440 , 1050 , 5 , 6 , 5 } , { 1600 , 1000 , 5 , 6 , 5 } ,
{ 1600 , 1200 , 5 , 6 , 5 } , { 1680 , 1050 , 5 , 6 , 5 } , { 1792 , 1344 , 5 , 6 , 5 } ,
{ 1800 , 1440 , 5 , 6 , 5 } , { 1856 , 1392 , 5 , 6 , 5 } , { 1920 , 1080 , 5 , 6 , 5 } ,
{ 1920 , 1200 , 5 , 6 , 5 } , { 1920 , 1440 , 5 , 6 , 5 } , { 1920 , 2400 , 5 , 6 , 5 } ,
{ 2048 , 1536 , 5 , 6 , 5 }
} ;
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : FlushVertices ( bool KeepVertices )
2011-12-31 00:06:04 +00:00
{
if ( m_NumVertices = = 0 )
return ;
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
size_t VertSize = sizeof ( CCommandBuffer : : SVertex ) ;
2011-12-31 00:06:04 +00:00
int NumVerts = m_NumVertices ;
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
if ( ! KeepVertices )
m_NumVertices = 0 ;
2011-12-31 00:06:04 +00:00
CCommandBuffer : : SCommand_Render Cmd ;
Cmd . m_State = m_State ;
if ( m_Drawing = = DRAWING_QUADS )
{
2020-08-18 18:26:35 +00:00
if ( g_Config . m_GfxQuadAsTriangle & & ! m_IsNewOpenGL )
2015-03-31 11:35:18 +00:00
{
Cmd . m_PrimType = CCommandBuffer : : PRIMTYPE_TRIANGLES ;
Cmd . m_PrimCount = NumVerts / 3 ;
}
else
{
Cmd . m_PrimType = CCommandBuffer : : PRIMTYPE_QUADS ;
Cmd . m_PrimCount = NumVerts / 4 ;
2015-07-09 00:08:14 +00:00
}
2011-12-31 00:06:04 +00:00
}
else if ( m_Drawing = = DRAWING_LINES )
{
Cmd . m_PrimType = CCommandBuffer : : PRIMTYPE_LINES ;
Cmd . m_PrimCount = NumVerts / 2 ;
}
else
return ;
2018-03-13 20:47:07 +00:00
Cmd . m_pVertices = ( CCommandBuffer : : SVertex * ) m_pCommandBuffer - > AllocData ( VertSize * NumVerts ) ;
2011-12-31 00:06:04 +00:00
if ( Cmd . m_pVertices = = 0x0 )
2012-01-03 21:01:37 +00:00
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2018-03-13 20:47:07 +00:00
Cmd . m_pVertices = ( CCommandBuffer : : SVertex * ) m_pCommandBuffer - > AllocData ( VertSize * NumVerts ) ;
2012-01-03 21:01:37 +00:00
if ( Cmd . m_pVertices = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for vertices " ) ;
return ;
}
}
2011-12-31 00:06:04 +00:00
2012-11-13 14:39:23 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2015-07-09 00:08:14 +00:00
2018-03-13 20:47:07 +00:00
Cmd . m_pVertices = ( CCommandBuffer : : SVertex * ) m_pCommandBuffer - > AllocData ( VertSize * NumVerts ) ;
2012-11-13 20:37:46 +00:00
if ( Cmd . m_pVertices = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for vertices " ) ;
return ;
}
2012-11-13 14:39:23 +00:00
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render command " ) ;
return ;
}
}
2012-11-13 20:37:46 +00:00
2018-03-13 20:47:07 +00:00
mem_copy ( Cmd . m_pVertices , m_aVertices , VertSize * NumVerts ) ;
}
void CGraphics_Threaded : : FlushTextVertices ( int TextureSize , int TextTextureIndex , int TextOutlineTextureIndex , float * pOutlineTextColor )
{
if ( m_NumVertices = = 0 )
return ;
size_t VertSize = 0 ;
VertSize = sizeof ( CCommandBuffer : : SVertex ) ;
int NumVerts = m_NumVertices ;
m_NumVertices = 0 ;
CCommandBuffer : : SCommand_RenderTextStream Cmd ;
Cmd . m_State = m_State ;
Cmd . m_TextureSize = TextureSize ;
Cmd . m_TextTextureIndex = TextTextureIndex ;
Cmd . m_TextOutlineTextureIndex = TextOutlineTextureIndex ;
mem_copy ( Cmd . m_aTextOutlineColor , pOutlineTextColor , sizeof ( Cmd . m_aTextOutlineColor ) ) ;
Cmd . m_QuadNum = NumVerts / 4 ;
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
Cmd . m_pVertices = ( CCommandBuffer : : SVertex * ) m_pCommandBuffer - > AllocData ( VertSize * NumVerts ) ;
if ( Cmd . m_pVertices = = 0x0 )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
Cmd . m_pVertices = ( CCommandBuffer : : SVertex * ) m_pCommandBuffer - > AllocData ( VertSize * NumVerts ) ;
if ( Cmd . m_pVertices = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for vertices " ) ;
return ;
}
}
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
Cmd . m_pVertices = ( CCommandBuffer : : SVertex * ) m_pCommandBuffer - > AllocData ( VertSize * NumVerts ) ;
if ( Cmd . m_pVertices = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for vertices " ) ;
return ;
}
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render command " ) ;
return ;
}
}
mem_copy ( Cmd . m_pVertices , m_aVertices , VertSize * NumVerts ) ;
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : AddVertices ( int Count )
{
m_NumVertices + = Count ;
if ( ( m_NumVertices + Count ) > = MAX_VERTICES )
2012-01-01 13:15:35 +00:00
FlushVertices ( ) ;
2011-12-31 00:06:04 +00:00
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : Rotate ( const CCommandBuffer : : SPoint & rCenter , CCommandBuffer : : SVertex * pPoints , int NumPoints )
2011-12-31 00:06:04 +00:00
{
float c = cosf ( m_Rotation ) ;
float s = sinf ( m_Rotation ) ;
float x , y ;
int i ;
2019-04-26 22:11:15 +00:00
2019-04-11 10:21:42 +00:00
CCommandBuffer : : SVertex * pVertices = pPoints ;
2018-03-13 20:47:07 +00:00
for ( i = 0 ; i < NumPoints ; i + + )
2011-12-31 00:06:04 +00:00
{
2018-03-13 20:47:07 +00:00
x = pVertices [ i ] . m_Pos . x - rCenter . x ;
y = pVertices [ i ] . m_Pos . y - rCenter . y ;
pVertices [ i ] . m_Pos . x = x * c - y * s + rCenter . x ;
pVertices [ i ] . m_Pos . y = x * s + y * c + rCenter . y ;
2011-12-31 00:06:04 +00:00
}
}
CGraphics_Threaded : : CGraphics_Threaded ( )
{
m_State . m_ScreenTL . x = 0 ;
m_State . m_ScreenTL . y = 0 ;
m_State . m_ScreenBR . x = 0 ;
m_State . m_ScreenBR . y = 0 ;
m_State . m_ClipEnable = false ;
m_State . m_ClipX = 0 ;
m_State . m_ClipY = 0 ;
m_State . m_ClipW = 0 ;
m_State . m_ClipH = 0 ;
m_State . m_Texture = - 1 ;
m_State . m_BlendMode = CCommandBuffer : : BLEND_NONE ;
2012-01-08 00:47:53 +00:00
m_State . m_WrapMode = CCommandBuffer : : WRAP_REPEAT ;
2011-12-31 00:06:04 +00:00
2011-12-31 09:04:46 +00:00
m_CurrentCommandBuffer = 0 ;
m_pCommandBuffer = 0x0 ;
m_apCommandBuffers [ 0 ] = 0x0 ;
m_apCommandBuffers [ 1 ] = 0x0 ;
2011-12-31 00:06:04 +00:00
m_NumVertices = 0 ;
m_ScreenWidth = - 1 ;
m_ScreenHeight = - 1 ;
m_Rotation = 0 ;
m_Drawing = 0 ;
m_TextureMemoryUsage = 0 ;
m_RenderEnable = true ;
m_DoScreenshot = false ;
}
void CGraphics_Threaded : : ClipEnable ( int x , int y , int w , int h )
{
if ( x < 0 )
w + = x ;
if ( y < 0 )
h + = y ;
x = clamp ( x , 0 , ScreenWidth ( ) ) ;
y = clamp ( y , 0 , ScreenHeight ( ) ) ;
w = clamp ( w , 0 , ScreenWidth ( ) - x ) ;
h = clamp ( h , 0 , ScreenHeight ( ) - y ) ;
m_State . m_ClipEnable = true ;
m_State . m_ClipX = x ;
m_State . m_ClipY = ScreenHeight ( ) - ( y + h ) ;
m_State . m_ClipW = w ;
m_State . m_ClipH = h ;
}
void CGraphics_Threaded : : ClipDisable ( )
{
m_State . m_ClipEnable = false ;
}
void CGraphics_Threaded : : BlendNone ( )
{
m_State . m_BlendMode = CCommandBuffer : : BLEND_NONE ;
}
void CGraphics_Threaded : : BlendNormal ( )
{
m_State . m_BlendMode = CCommandBuffer : : BLEND_ALPHA ;
}
void CGraphics_Threaded : : BlendAdditive ( )
{
m_State . m_BlendMode = CCommandBuffer : : BLEND_ADDITIVE ;
}
2012-01-08 00:47:53 +00:00
void CGraphics_Threaded : : WrapNormal ( )
{
m_State . m_WrapMode = CCommandBuffer : : WRAP_REPEAT ;
}
void CGraphics_Threaded : : WrapClamp ( )
{
m_State . m_WrapMode = CCommandBuffer : : WRAP_CLAMP ;
}
2011-12-31 00:06:04 +00:00
int CGraphics_Threaded : : MemoryUsage ( ) const
{
2012-10-06 21:31:02 +00:00
return m_pBackend - > MemoryUsage ( ) ;
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : MapScreen ( float TopLeftX , float TopLeftY , float BottomRightX , float BottomRightY )
{
m_State . m_ScreenTL . x = TopLeftX ;
m_State . m_ScreenTL . y = TopLeftY ;
m_State . m_ScreenBR . x = BottomRightX ;
m_State . m_ScreenBR . y = BottomRightY ;
}
void CGraphics_Threaded : : GetScreen ( float * pTopLeftX , float * pTopLeftY , float * pBottomRightX , float * pBottomRightY )
{
* pTopLeftX = m_State . m_ScreenTL . x ;
* pTopLeftY = m_State . m_ScreenTL . y ;
* pBottomRightX = m_State . m_ScreenBR . x ;
* pBottomRightY = m_State . m_ScreenBR . y ;
}
void CGraphics_Threaded : : LinesBegin ( )
{
dbg_assert ( m_Drawing = = 0 , " called Graphics()->LinesBegin twice " ) ;
m_Drawing = DRAWING_LINES ;
SetColor ( 1 , 1 , 1 , 1 ) ;
}
void CGraphics_Threaded : : LinesEnd ( )
{
dbg_assert ( m_Drawing = = DRAWING_LINES , " called Graphics()->LinesEnd without begin " ) ;
2012-01-01 13:15:35 +00:00
FlushVertices ( ) ;
2011-12-31 00:06:04 +00:00
m_Drawing = 0 ;
}
void CGraphics_Threaded : : LinesDraw ( const CLineItem * pArray , int Num )
{
dbg_assert ( m_Drawing = = DRAWING_LINES , " called Graphics()->LinesDraw without begin " ) ;
for ( int i = 0 ; i < Num ; + + i )
{
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 2 * i ] . m_Pos . x = pArray [ i ] . m_X0 ;
m_aVertices [ m_NumVertices + 2 * i ] . m_Pos . y = pArray [ i ] . m_Y0 ;
m_aVertices [ m_NumVertices + 2 * i ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 2 * i ] , 0 ) ;
m_aVertices [ m_NumVertices + 2 * i + 1 ] . m_Pos . x = pArray [ i ] . m_X1 ;
m_aVertices [ m_NumVertices + 2 * i + 1 ] . m_Pos . y = pArray [ i ] . m_Y1 ;
m_aVertices [ m_NumVertices + 2 * i + 1 ] . m_Tex = m_aTexture [ 1 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 2 * i + 1 ] , 1 ) ;
2011-12-31 00:06:04 +00:00
}
AddVertices ( 2 * Num ) ;
}
2012-08-12 10:41:50 +00:00
int CGraphics_Threaded : : UnloadTexture ( CTextureHandle Index )
2011-12-31 00:06:04 +00:00
{
if ( Index = = m_InvalidTexture )
return 0 ;
if ( Index < 0 )
return 0 ;
2011-12-31 08:40:11 +00:00
CCommandBuffer : : SCommand_Texture_Destroy Cmd ;
Cmd . m_Slot = Index ;
m_pCommandBuffer - > AddCommand ( Cmd ) ;
2013-02-24 17:55:55 +00:00
m_aTextureIndices [ Index ] = m_FirstFreeTexture ;
2011-12-31 00:06:04 +00:00
m_FirstFreeTexture = Index ;
return 0 ;
}
2011-12-31 08:40:11 +00:00
static int ImageFormatToTexFormat ( int Format )
{
if ( Format = = CImageInfo : : FORMAT_RGB ) return CCommandBuffer : : TEXFORMAT_RGB ;
if ( Format = = CImageInfo : : FORMAT_RGBA ) return CCommandBuffer : : TEXFORMAT_RGBA ;
if ( Format = = CImageInfo : : FORMAT_ALPHA ) return CCommandBuffer : : TEXFORMAT_ALPHA ;
return CCommandBuffer : : TEXFORMAT_RGBA ;
}
2011-12-31 00:06:04 +00:00
2012-10-06 21:31:02 +00:00
static int ImageFormatToPixelSize ( int Format )
{
switch ( Format )
{
case CImageInfo : : FORMAT_RGB : return 3 ;
case CImageInfo : : FORMAT_ALPHA : return 1 ;
default : return 4 ;
}
}
2011-12-31 08:40:11 +00:00
2012-08-12 10:41:50 +00:00
int CGraphics_Threaded : : LoadTextureRawSub ( CTextureHandle TextureID , int x , int y , int Width , int Height , int Format , const void * pData )
2011-12-31 00:06:04 +00:00
{
2011-12-31 08:40:11 +00:00
CCommandBuffer : : SCommand_Texture_Update Cmd ;
Cmd . m_Slot = TextureID ;
Cmd . m_X = x ;
Cmd . m_Y = y ;
Cmd . m_Width = Width ;
Cmd . m_Height = Height ;
Cmd . m_Format = ImageFormatToTexFormat ( Format ) ;
// calculate memory usage
2012-10-06 21:31:02 +00:00
int MemSize = Width * Height * ImageFormatToPixelSize ( Format ) ;
2011-12-31 08:40:11 +00:00
// copy texture data
2018-04-09 09:56:39 +00:00
void * pTmpData = malloc ( MemSize ) ;
2011-12-31 08:40:11 +00:00
mem_copy ( pTmpData , pData , MemSize ) ;
Cmd . m_pData = pTmpData ;
2019-04-26 22:11:15 +00:00
2017-09-15 01:50:06 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
m_pCommandBuffer - > AddCommand ( Cmd ) ;
2019-04-26 22:11:15 +00:00
}
2011-12-31 08:40:11 +00:00
return 0 ;
}
2011-12-31 00:06:04 +00:00
2020-08-29 10:49:45 +00:00
IGraphics : : CTextureHandle CGraphics_Threaded : : LoadTextureRaw ( int Width , int Height , int Format , const void * pData , int StoreFormat , int Flags , const char * pTexName )
2011-12-31 08:40:11 +00:00
{
2011-12-31 00:06:04 +00:00
// don't waste memory on texture if we are stress testing
2017-06-02 18:45:09 +00:00
# ifdef CONF_DEBUG
2011-12-31 00:06:04 +00:00
if ( g_Config . m_DbgStress )
2011-12-31 08:40:11 +00:00
return m_InvalidTexture ;
2017-06-02 18:45:09 +00:00
# endif
2011-12-31 00:06:04 +00:00
// grab texture
2011-12-31 08:40:11 +00:00
int Tex = m_FirstFreeTexture ;
2012-10-06 21:31:02 +00:00
m_FirstFreeTexture = m_aTextureIndices [ Tex ] ;
m_aTextureIndices [ Tex ] = - 1 ;
2011-12-31 00:06:04 +00:00
2011-12-31 08:40:11 +00:00
CCommandBuffer : : SCommand_Texture_Create Cmd ;
Cmd . m_Slot = Tex ;
Cmd . m_Width = Width ;
Cmd . m_Height = Height ;
2012-10-06 21:31:02 +00:00
Cmd . m_PixelSize = ImageFormatToPixelSize ( Format ) ;
2011-12-31 08:40:11 +00:00
Cmd . m_Format = ImageFormatToTexFormat ( Format ) ;
Cmd . m_StoreFormat = ImageFormatToTexFormat ( StoreFormat ) ;
2011-12-31 00:06:04 +00:00
2011-12-31 10:18:55 +00:00
// flags
Cmd . m_Flags = 0 ;
if ( Flags & IGraphics : : TEXLOAD_NOMIPMAPS )
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_NOMIPMAPS ;
2019-01-20 13:28:59 +00:00
if ( g_Config . m_GfxTextureCompression & & ( ( Flags & IGraphics : : TEXLOAD_NO_COMPRESSION ) = = 0 ) )
2012-09-03 09:39:12 +00:00
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_COMPRESSED ;
2012-10-07 09:22:49 +00:00
if ( g_Config . m_GfxTextureQuality | | Flags & TEXLOAD_NORESAMPLE )
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_QUALITY ;
2020-08-19 05:05:51 +00:00
if ( ( Flags & IGraphics : : TEXLOAD_TO_2D_ARRAY_TEXTURE ) ! = 0 )
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_TO_2D_ARRAY_TEXTURE ;
if ( ( Flags & IGraphics : : TEXLOAD_TO_3D_TEXTURE ) ! = 0 )
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_TO_3D_TEXTURE ;
if ( ( Flags & IGraphics : : TEXLOAD_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER ) ! = 0 )
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER ;
if ( ( Flags & IGraphics : : TEXLOAD_TO_3D_TEXTURE_SINGLE_LAYER ) ! = 0 )
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER ;
2020-08-23 06:25:21 +00:00
if ( ( Flags & IGraphics : : TEXLOAD_NO_2D_TEXTURE ) ! = 0 )
Cmd . m_Flags | = CCommandBuffer : : TEXFLAG_NO_2D_TEXTURE ;
2011-12-31 10:18:55 +00:00
2020-08-29 10:49:45 +00:00
if ( ( Flags & IGraphics : : TEXLOAD_TO_2D_ARRAY_TEXTURE ) ! = 0 | | ( Flags & IGraphics : : TEXLOAD_TO_3D_TEXTURE ) ! = 0 )
{
if ( Width = = 0 | | ( Width % 16 ) ! = 0 | | Height = = 0 | | ( Height % 16 ) ! = 0 )
{
SGraphicsWarning NewWarning ;
char aText [ 128 ] ;
2020-08-31 11:07:42 +00:00
aText [ 0 ] = ' \0 ' ;
if ( pTexName )
2020-08-29 10:49:45 +00:00
{
2020-08-31 11:07:42 +00:00
str_format ( aText , sizeof ( aText ) , " \" %s \" " , pTexName ) ;
2020-08-29 10:49:45 +00:00
}
2020-08-31 11:07:42 +00:00
str_format ( NewWarning . m_aWarningMsg , sizeof ( NewWarning . m_aWarningMsg ) , Localize ( " The width or height of texture %s is not divisible by 16, which might cause visual bugs. " ) , aText ) ;
2020-08-29 10:49:45 +00:00
m_Warnings . emplace_back ( NewWarning ) ;
}
}
2011-12-31 08:40:11 +00:00
// copy texture data
2012-10-06 21:31:02 +00:00
int MemSize = Width * Height * Cmd . m_PixelSize ;
2018-04-09 09:56:39 +00:00
void * pTmpData = malloc ( MemSize ) ;
2011-12-31 08:40:11 +00:00
mem_copy ( pTmpData , pData , MemSize ) ;
Cmd . m_pData = pTmpData ;
2011-12-31 00:06:04 +00:00
2017-09-15 01:50:06 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
m_pCommandBuffer - > AddCommand ( Cmd ) ;
}
2011-12-31 09:04:46 +00:00
2012-08-12 10:41:50 +00:00
return CreateTextureHandle ( Tex ) ;
2011-12-31 00:06:04 +00:00
}
// simple uncompressed RGBA loaders
2012-08-12 10:41:50 +00:00
IGraphics : : CTextureHandle CGraphics_Threaded : : LoadTexture ( const char * pFilename , int StorageType , int StoreFormat , int Flags )
2011-12-31 00:06:04 +00:00
{
int l = str_length ( pFilename ) ;
int ID ;
CImageInfo Img ;
if ( l < 3 )
2012-08-12 10:41:50 +00:00
return CTextureHandle ( ) ;
2011-12-31 00:06:04 +00:00
if ( LoadPNG ( & Img , pFilename , StorageType ) )
{
2018-03-13 20:47:07 +00:00
if ( StoreFormat = = CImageInfo : : FORMAT_AUTO )
2011-12-31 00:06:04 +00:00
StoreFormat = Img . m_Format ;
2020-08-29 10:49:45 +00:00
ID = LoadTextureRaw ( Img . m_Width , Img . m_Height , Img . m_Format , Img . m_pData , StoreFormat , Flags , pFilename ) ;
2018-04-09 09:56:39 +00:00
free ( Img . m_pData ) ;
2011-12-31 00:06:04 +00:00
if ( ID ! = m_InvalidTexture & & g_Config . m_Debug )
dbg_msg ( " graphics/texture " , " loaded %s " , pFilename ) ;
2012-08-12 10:41:50 +00:00
return CreateTextureHandle ( ID ) ;
2011-12-31 00:06:04 +00:00
}
return m_InvalidTexture ;
}
int CGraphics_Threaded : : LoadPNG ( CImageInfo * pImg , const char * pFilename , int StorageType )
{
char aCompleteFilename [ 512 ] ;
unsigned char * pBuffer ;
png_t Png ; // ignore_convention
// open file for reading
png_init ( 0 , 0 ) ; // ignore_convention
IOHANDLE File = m_pStorage - > OpenFile ( pFilename , IOFLAG_READ , StorageType , aCompleteFilename , sizeof ( aCompleteFilename ) ) ;
if ( File )
io_close ( File ) ;
else
{
dbg_msg ( " game/png " , " failed to open file. filename='%s' " , pFilename ) ;
return 0 ;
}
int Error = png_open_file ( & Png , aCompleteFilename ) ; // ignore_convention
if ( Error ! = PNG_NO_ERROR )
{
dbg_msg ( " game/png " , " failed to open file. filename='%s' " , aCompleteFilename ) ;
if ( Error ! = PNG_FILE_ERROR )
png_close_file ( & Png ) ; // ignore_convention
return 0 ;
}
if ( Png . depth ! = 8 | | ( Png . color_type ! = PNG_TRUECOLOR & & Png . color_type ! = PNG_TRUECOLOR_ALPHA ) ) // ignore_convention
{
dbg_msg ( " game/png " , " invalid format. filename='%s' " , aCompleteFilename ) ;
png_close_file ( & Png ) ; // ignore_convention
return 0 ;
}
2018-04-09 09:56:39 +00:00
pBuffer = ( unsigned char * ) malloc ( Png . width * Png . height * Png . bpp ) ; // ignore_convention
2011-12-31 00:06:04 +00:00
png_get_data ( & Png , pBuffer ) ; // ignore_convention
png_close_file ( & Png ) ; // ignore_convention
pImg - > m_Width = Png . width ; // ignore_convention
pImg - > m_Height = Png . height ; // ignore_convention
if ( Png . color_type = = PNG_TRUECOLOR ) // ignore_convention
pImg - > m_Format = CImageInfo : : FORMAT_RGB ;
else if ( Png . color_type = = PNG_TRUECOLOR_ALPHA ) // ignore_convention
pImg - > m_Format = CImageInfo : : FORMAT_RGBA ;
pImg - > m_pData = pBuffer ;
return 1 ;
}
2020-09-08 13:11:32 +00:00
void CGraphics_Threaded : : CopyTextureBufferSub ( uint8_t * pDestBuffer , uint8_t * pSourceBuffer , size_t FullWidth , size_t FullHeight , size_t ColorChannelCount , size_t SubOffsetX , size_t SubOffsetY , size_t SubCopyWidth , size_t SubCopyHeight )
{
for ( size_t Y = 0 ; Y < SubCopyHeight ; + + Y )
{
size_t ImgOffset = ( ( SubOffsetY + Y ) * FullWidth * ColorChannelCount ) + ( SubOffsetX * ColorChannelCount ) ;
size_t CopySize = SubCopyWidth * ColorChannelCount ;
mem_copy ( & pDestBuffer [ ImgOffset ] , & pSourceBuffer [ ImgOffset ] , CopySize ) ;
}
}
2012-01-01 13:15:35 +00:00
void CGraphics_Threaded : : KickCommandBuffer ( )
{
2012-01-03 20:39:10 +00:00
m_pBackend - > RunBuffer ( m_pCommandBuffer ) ;
2012-01-01 13:15:35 +00:00
// swap buffer
m_CurrentCommandBuffer ^ = 1 ;
m_pCommandBuffer = m_apCommandBuffers [ m_CurrentCommandBuffer ] ;
m_pCommandBuffer - > Reset ( ) ;
}
2014-01-19 03:02:01 +00:00
void CGraphics_Threaded : : ScreenshotDirect ( )
{
2012-01-01 13:15:35 +00:00
// add swap command
CImageInfo Image ;
mem_zero ( & Image , sizeof ( Image ) ) ;
CCommandBuffer : : SCommand_Screenshot Cmd ;
Cmd . m_pImage = & Image ;
2014-03-29 16:04:06 +00:00
m_pCommandBuffer - > AddCommand ( Cmd ) ;
2011-12-31 00:06:04 +00:00
2012-01-01 13:15:35 +00:00
// kick the buffer and wait for the result
2014-03-29 16:04:06 +00:00
KickCommandBuffer ( ) ;
WaitForIdle ( ) ;
2012-01-01 13:15:35 +00:00
if ( Image . m_pData )
2011-12-31 00:06:04 +00:00
{
2012-01-01 13:15:35 +00:00
// find filename
2011-12-31 00:06:04 +00:00
char aWholePath [ 1024 ] ;
png_t Png ; // ignore_convention
2014-03-29 16:04:06 +00:00
IOHANDLE File = m_pStorage - > OpenFile ( m_aScreenshotName , IOFLAG_WRITE , IStorage : : TYPE_SAVE , aWholePath , sizeof ( aWholePath ) ) ;
2011-12-31 00:06:04 +00:00
if ( File )
io_close ( File ) ;
// save png
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " saved screenshot to '%s' " , aWholePath ) ;
2014-03-29 16:04:06 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , aBuf ) ;
2011-12-31 00:06:04 +00:00
png_open_file_write ( & Png , aWholePath ) ; // ignore_convention
2012-01-01 13:15:35 +00:00
png_set_data ( & Png , Image . m_Width , Image . m_Height , 8 , PNG_TRUECOLOR , ( unsigned char * ) Image . m_pData ) ; // ignore_convention
2011-12-31 00:06:04 +00:00
png_close_file ( & Png ) ; // ignore_convention
2018-04-09 09:56:39 +00:00
free ( Image . m_pData ) ;
2012-01-01 13:15:35 +00:00
}
2011-12-31 00:06:04 +00:00
}
2012-08-12 10:41:50 +00:00
void CGraphics_Threaded : : TextureSet ( CTextureHandle TextureID )
2011-12-31 00:06:04 +00:00
{
dbg_assert ( m_Drawing = = 0 , " called Graphics()->TextureSet within begin " ) ;
2011-12-31 08:40:11 +00:00
m_State . m_Texture = TextureID ;
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : Clear ( float r , float g , float b )
{
CCommandBuffer : : SCommand_Clear Cmd ;
Cmd . m_Color . r = r ;
Cmd . m_Color . g = g ;
Cmd . m_Color . b = b ;
Cmd . m_Color . a = 0 ;
m_pCommandBuffer - > AddCommand ( Cmd ) ;
}
void CGraphics_Threaded : : QuadsBegin ( )
{
dbg_assert ( m_Drawing = = 0 , " called Graphics()->QuadsBegin twice " ) ;
m_Drawing = DRAWING_QUADS ;
2018-03-13 20:47:07 +00:00
QuadsSetSubset ( 0 , 0 , 1 , 1 ) ;
2011-12-31 00:06:04 +00:00
QuadsSetRotation ( 0 ) ;
2018-03-13 20:47:07 +00:00
SetColor ( 1 , 1 , 1 , 1 ) ;
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : QuadsEnd ( )
{
dbg_assert ( m_Drawing = = DRAWING_QUADS , " called Graphics()->QuadsEnd without begin " ) ;
2012-01-01 13:15:35 +00:00
FlushVertices ( ) ;
2011-12-31 00:06:04 +00:00
m_Drawing = 0 ;
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : TextQuadsBegin ( )
{
QuadsBegin ( ) ;
}
void CGraphics_Threaded : : TextQuadsEnd ( int TextureSize , int TextTextureIndex , int TextOutlineTextureIndex , float * pOutlineTextColor )
{
dbg_assert ( m_Drawing = = DRAWING_QUADS , " called Graphics()->TextQuadsEnd without begin " ) ;
FlushTextVertices ( TextureSize , TextTextureIndex , TextOutlineTextureIndex , pOutlineTextColor ) ;
m_Drawing = 0 ;
}
void CGraphics_Threaded : : QuadsEndKeepVertices ( )
{
dbg_assert ( m_Drawing = = DRAWING_QUADS , " called Graphics()->QuadsEndKeepVertices without begin " ) ;
FlushVertices ( true ) ;
m_Drawing = 0 ;
}
void CGraphics_Threaded : : QuadsDrawCurrentVertices ( bool KeepVertices )
{
m_Drawing = DRAWING_QUADS ;
FlushVertices ( KeepVertices ) ;
m_Drawing = 0 ;
}
2011-12-31 00:06:04 +00:00
void CGraphics_Threaded : : QuadsSetRotation ( float Angle )
{
m_Rotation = Angle ;
}
2017-09-27 12:52:06 +00:00
inline void clampf ( float & Value , float Min , float Max )
{
2017-09-27 10:16:34 +00:00
if ( Value > Max ) Value = Max ;
else if ( Value < Min ) Value = Min ;
}
2011-12-31 00:06:04 +00:00
void CGraphics_Threaded : : SetColorVertex ( const CColorVertex * pArray , int Num )
{
dbg_assert ( m_Drawing ! = 0 , " called Graphics()->SetColorVertex without begin " ) ;
for ( int i = 0 ; i < Num ; + + i )
{
2018-03-13 20:47:07 +00:00
float r = pArray [ i ] . m_R , g = pArray [ i ] . m_G , b = pArray [ i ] . m_B , a = pArray [ i ] . m_A ;
clampf ( r , 0.f , 1.f ) ;
clampf ( g , 0.f , 1.f ) ;
clampf ( b , 0.f , 1.f ) ;
clampf ( a , 0.f , 1.f ) ;
m_aColor [ pArray [ i ] . m_Index ] . r = ( unsigned char ) ( r * 255.f ) ;
m_aColor [ pArray [ i ] . m_Index ] . g = ( unsigned char ) ( g * 255.f ) ;
m_aColor [ pArray [ i ] . m_Index ] . b = ( unsigned char ) ( b * 255.f ) ;
m_aColor [ pArray [ i ] . m_Index ] . a = ( unsigned char ) ( a * 255.f ) ;
2011-12-31 00:06:04 +00:00
}
}
void CGraphics_Threaded : : SetColor ( float r , float g , float b , float a )
{
2018-03-13 20:47:07 +00:00
clampf ( r , 0.f , 1.f ) ;
clampf ( g , 0.f , 1.f ) ;
clampf ( b , 0.f , 1.f ) ;
clampf ( a , 0.f , 1.f ) ;
r * = 255.f ;
g * = 255.f ;
b * = 255.f ;
a * = 255.f ;
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
for ( int i = 0 ; i < 4 ; + + i )
{
m_aColor [ i ] . r = ( unsigned char ) ( r ) ;
m_aColor [ i ] . g = ( unsigned char ) ( g ) ;
m_aColor [ i ] . b = ( unsigned char ) ( b ) ;
m_aColor [ i ] . a = ( unsigned char ) ( a ) ;
}
2011-12-31 00:06:04 +00:00
}
2019-04-26 22:11:15 +00:00
void CGraphics_Threaded : : SetColor ( ColorRGBA rgb )
{
SetColor ( rgb . r , rgb . g , rgb . b , rgb . a ) ;
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : ChangeColorOfCurrentQuadVertices ( float r , float g , float b , float a )
2017-09-27 10:16:34 +00:00
{
2018-03-13 20:47:07 +00:00
clampf ( r , 0.f , 1.f ) ;
clampf ( g , 0.f , 1.f ) ;
clampf ( b , 0.f , 1.f ) ;
clampf ( a , 0.f , 1.f ) ;
m_aColor [ 0 ] . r = ( unsigned char ) ( r * 255.f ) ;
m_aColor [ 0 ] . g = ( unsigned char ) ( g * 255.f ) ;
m_aColor [ 0 ] . b = ( unsigned char ) ( b * 255.f ) ;
m_aColor [ 0 ] . a = ( unsigned char ) ( a * 255.f ) ;
for ( int i = 0 ; i < m_NumVertices ; + + i )
2017-09-27 10:16:34 +00:00
{
2018-03-13 20:47:07 +00:00
SetColor ( & m_aVertices [ i ] , 0 ) ;
2017-09-27 10:16:34 +00:00
}
}
2019-04-06 15:06:12 +00:00
void CGraphics_Threaded : : ChangeColorOfQuadVertices ( int QuadOffset , unsigned char r , unsigned char g , unsigned char b , unsigned char a )
{
2020-08-18 18:26:35 +00:00
if ( g_Config . m_GfxQuadAsTriangle & & ! m_IsNewOpenGL )
2018-04-03 15:40:21 +00:00
{
m_aVertices [ QuadOffset * 6 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 6 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 6 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 6 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 6 + 1 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 6 + 1 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 6 + 1 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 6 + 1 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 6 + 2 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 6 + 2 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 6 + 2 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 6 + 2 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 6 + 3 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 6 + 3 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 6 + 3 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 6 + 3 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 6 + 4 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 6 + 4 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 6 + 4 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 6 + 4 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 6 + 5 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 6 + 5 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 6 + 5 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 6 + 5 ] . m_Color . a = a ;
}
else
{
m_aVertices [ QuadOffset * 4 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 4 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 4 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 4 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 4 + 1 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 4 + 1 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 4 + 1 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 4 + 1 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 4 + 2 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 4 + 2 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 4 + 2 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 4 + 2 ] . m_Color . a = a ;
m_aVertices [ QuadOffset * 4 + 3 ] . m_Color . r = r ;
m_aVertices [ QuadOffset * 4 + 3 ] . m_Color . g = g ;
m_aVertices [ QuadOffset * 4 + 3 ] . m_Color . b = b ;
m_aVertices [ QuadOffset * 4 + 3 ] . m_Color . a = a ;
}
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : SetColor ( CCommandBuffer : : SVertex * pVertex , int ColorIndex )
2017-09-27 10:16:34 +00:00
{
2019-04-11 10:21:42 +00:00
CCommandBuffer : : SVertex * pVert = pVertex ;
2018-03-13 20:47:07 +00:00
pVert - > m_Color . r = m_aColor [ ColorIndex ] . r ;
pVert - > m_Color . g = m_aColor [ ColorIndex ] . g ;
pVert - > m_Color . b = m_aColor [ ColorIndex ] . b ;
pVert - > m_Color . a = m_aColor [ ColorIndex ] . a ;
2017-09-27 10:16:34 +00:00
}
2011-12-31 00:06:04 +00:00
void CGraphics_Threaded : : QuadsSetSubset ( float TlU , float TlV , float BrU , float BrV )
{
m_aTexture [ 0 ] . u = TlU ; m_aTexture [ 1 ] . u = BrU ;
m_aTexture [ 0 ] . v = TlV ; m_aTexture [ 1 ] . v = TlV ;
m_aTexture [ 3 ] . u = TlU ; m_aTexture [ 2 ] . u = BrU ;
m_aTexture [ 3 ] . v = BrV ; m_aTexture [ 2 ] . v = BrV ;
}
void CGraphics_Threaded : : QuadsSetSubsetFree (
float x0 , float y0 , float x1 , float y1 ,
float x2 , float y2 , float x3 , float y3 )
{
m_aTexture [ 0 ] . u = x0 ; m_aTexture [ 0 ] . v = y0 ;
m_aTexture [ 1 ] . u = x1 ; m_aTexture [ 1 ] . v = y1 ;
m_aTexture [ 2 ] . u = x2 ; m_aTexture [ 2 ] . v = y2 ;
m_aTexture [ 3 ] . u = x3 ; m_aTexture [ 3 ] . v = y3 ;
}
void CGraphics_Threaded : : QuadsDraw ( CQuadItem * pArray , int Num )
{
for ( int i = 0 ; i < Num ; + + i )
{
pArray [ i ] . m_X - = pArray [ i ] . m_Width / 2 ;
pArray [ i ] . m_Y - = pArray [ i ] . m_Height / 2 ;
}
QuadsDrawTL ( pArray , Num ) ;
}
void CGraphics_Threaded : : QuadsDrawTL ( const CQuadItem * pArray , int Num )
{
CCommandBuffer : : SPoint Center ;
dbg_assert ( m_Drawing = = DRAWING_QUADS , " called Graphics()->QuadsDrawTL without begin " ) ;
2020-08-18 18:26:35 +00:00
if ( g_Config . m_GfxQuadAsTriangle & & ! m_IsNewOpenGL )
2011-12-31 00:06:04 +00:00
{
2015-03-31 11:35:18 +00:00
for ( int i = 0 ; i < Num ; + + i )
2011-12-31 00:06:04 +00:00
{
2015-03-31 11:35:18 +00:00
// first triangle
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 6 * i ] . m_Pos . x = pArray [ i ] . m_X ;
m_aVertices [ m_NumVertices + 6 * i ] . m_Pos . y = pArray [ i ] . m_Y ;
m_aVertices [ m_NumVertices + 6 * i ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i ] , 0 ) ;
2015-03-31 11:35:18 +00:00
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 6 * i + 1 ] . m_Pos . x = pArray [ i ] . m_X + pArray [ i ] . m_Width ;
m_aVertices [ m_NumVertices + 6 * i + 1 ] . m_Pos . y = pArray [ i ] . m_Y ;
m_aVertices [ m_NumVertices + 6 * i + 1 ] . m_Tex = m_aTexture [ 1 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 1 ] , 1 ) ;
2015-03-31 11:35:18 +00:00
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 6 * i + 2 ] . m_Pos . x = pArray [ i ] . m_X + pArray [ i ] . m_Width ;
m_aVertices [ m_NumVertices + 6 * i + 2 ] . m_Pos . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height ;
m_aVertices [ m_NumVertices + 6 * i + 2 ] . m_Tex = m_aTexture [ 2 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 2 ] , 2 ) ;
2015-03-31 11:35:18 +00:00
// second triangle
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 6 * i + 3 ] . m_Pos . x = pArray [ i ] . m_X ;
m_aVertices [ m_NumVertices + 6 * i + 3 ] . m_Pos . y = pArray [ i ] . m_Y ;
m_aVertices [ m_NumVertices + 6 * i + 3 ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 3 ] , 0 ) ;
2015-03-31 11:35:18 +00:00
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 6 * i + 4 ] . m_Pos . x = pArray [ i ] . m_X + pArray [ i ] . m_Width ;
m_aVertices [ m_NumVertices + 6 * i + 4 ] . m_Pos . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height ;
m_aVertices [ m_NumVertices + 6 * i + 4 ] . m_Tex = m_aTexture [ 2 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 4 ] , 2 ) ;
2015-03-31 11:35:18 +00:00
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 6 * i + 5 ] . m_Pos . x = pArray [ i ] . m_X ;
m_aVertices [ m_NumVertices + 6 * i + 5 ] . m_Pos . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height ;
m_aVertices [ m_NumVertices + 6 * i + 5 ] . m_Tex = m_aTexture [ 3 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 5 ] , 3 ) ;
2015-03-31 11:35:18 +00:00
if ( m_Rotation ! = 0 )
{
Center . x = pArray [ i ] . m_X + pArray [ i ] . m_Width / 2 ;
Center . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height / 2 ;
2018-03-13 20:47:07 +00:00
Rotate ( Center , & m_aVertices [ m_NumVertices + 6 * i ] , 6 ) ;
2015-03-31 11:35:18 +00:00
}
2011-12-31 00:06:04 +00:00
}
2015-03-31 11:35:18 +00:00
AddVertices ( 3 * 2 * Num ) ;
2011-12-31 00:06:04 +00:00
}
2015-03-31 11:35:18 +00:00
else
{
for ( int i = 0 ; i < Num ; + + i )
{
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 4 * i ] . m_Pos . x = pArray [ i ] . m_X ;
m_aVertices [ m_NumVertices + 4 * i ] . m_Pos . y = pArray [ i ] . m_Y ;
m_aVertices [ m_NumVertices + 4 * i ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i ] , 0 ) ;
m_aVertices [ m_NumVertices + 4 * i + 1 ] . m_Pos . x = pArray [ i ] . m_X + pArray [ i ] . m_Width ;
m_aVertices [ m_NumVertices + 4 * i + 1 ] . m_Pos . y = pArray [ i ] . m_Y ;
m_aVertices [ m_NumVertices + 4 * i + 1 ] . m_Tex = m_aTexture [ 1 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i + 1 ] , 1 ) ;
m_aVertices [ m_NumVertices + 4 * i + 2 ] . m_Pos . x = pArray [ i ] . m_X + pArray [ i ] . m_Width ;
m_aVertices [ m_NumVertices + 4 * i + 2 ] . m_Pos . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height ;
m_aVertices [ m_NumVertices + 4 * i + 2 ] . m_Tex = m_aTexture [ 2 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i + 2 ] , 2 ) ;
m_aVertices [ m_NumVertices + 4 * i + 3 ] . m_Pos . x = pArray [ i ] . m_X ;
m_aVertices [ m_NumVertices + 4 * i + 3 ] . m_Pos . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height ;
m_aVertices [ m_NumVertices + 4 * i + 3 ] . m_Tex = m_aTexture [ 3 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i + 3 ] , 3 ) ;
2015-03-31 11:35:18 +00:00
if ( m_Rotation ! = 0 )
{
Center . x = pArray [ i ] . m_X + pArray [ i ] . m_Width / 2 ;
Center . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height / 2 ;
2018-03-13 20:47:07 +00:00
Rotate ( Center , & m_aVertices [ m_NumVertices + 4 * i ] , 4 ) ;
2015-03-31 11:35:18 +00:00
}
}
2011-12-31 00:06:04 +00:00
2015-03-31 11:35:18 +00:00
AddVertices ( 4 * Num ) ;
}
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : QuadsDrawFreeform ( const CFreeformItem * pArray , int Num )
{
dbg_assert ( m_Drawing = = DRAWING_QUADS , " called Graphics()->QuadsDrawFreeform without begin " ) ;
2020-08-18 18:26:35 +00:00
if ( g_Config . m_GfxQuadAsTriangle & & ! m_IsNewOpenGL )
2011-12-31 00:06:04 +00:00
{
2015-03-31 11:35:18 +00:00
for ( int i = 0 ; i < Num ; + + i )
{
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 6 * i ] . m_Pos . x = pArray [ i ] . m_X0 ;
m_aVertices [ m_NumVertices + 6 * i ] . m_Pos . y = pArray [ i ] . m_Y0 ;
m_aVertices [ m_NumVertices + 6 * i ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i ] , 0 ) ;
m_aVertices [ m_NumVertices + 6 * i + 1 ] . m_Pos . x = pArray [ i ] . m_X1 ;
m_aVertices [ m_NumVertices + 6 * i + 1 ] . m_Pos . y = pArray [ i ] . m_Y1 ;
m_aVertices [ m_NumVertices + 6 * i + 1 ] . m_Tex = m_aTexture [ 1 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 1 ] , 1 ) ;
m_aVertices [ m_NumVertices + 6 * i + 2 ] . m_Pos . x = pArray [ i ] . m_X3 ;
m_aVertices [ m_NumVertices + 6 * i + 2 ] . m_Pos . y = pArray [ i ] . m_Y3 ;
m_aVertices [ m_NumVertices + 6 * i + 2 ] . m_Tex = m_aTexture [ 3 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 2 ] , 3 ) ;
m_aVertices [ m_NumVertices + 6 * i + 3 ] . m_Pos . x = pArray [ i ] . m_X0 ;
m_aVertices [ m_NumVertices + 6 * i + 3 ] . m_Pos . y = pArray [ i ] . m_Y0 ;
m_aVertices [ m_NumVertices + 6 * i + 3 ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 3 ] , 0 ) ;
m_aVertices [ m_NumVertices + 6 * i + 4 ] . m_Pos . x = pArray [ i ] . m_X3 ;
m_aVertices [ m_NumVertices + 6 * i + 4 ] . m_Pos . y = pArray [ i ] . m_Y3 ;
m_aVertices [ m_NumVertices + 6 * i + 4 ] . m_Tex = m_aTexture [ 3 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 4 ] , 3 ) ;
m_aVertices [ m_NumVertices + 6 * i + 5 ] . m_Pos . x = pArray [ i ] . m_X2 ;
m_aVertices [ m_NumVertices + 6 * i + 5 ] . m_Pos . y = pArray [ i ] . m_Y2 ;
m_aVertices [ m_NumVertices + 6 * i + 5 ] . m_Tex = m_aTexture [ 2 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 6 * i + 5 ] , 2 ) ;
2015-03-31 11:35:18 +00:00
}
AddVertices ( 3 * 2 * Num ) ;
2011-12-31 00:06:04 +00:00
}
2015-03-31 11:35:18 +00:00
else
{
for ( int i = 0 ; i < Num ; + + i )
{
2018-03-13 20:47:07 +00:00
m_aVertices [ m_NumVertices + 4 * i ] . m_Pos . x = pArray [ i ] . m_X0 ;
m_aVertices [ m_NumVertices + 4 * i ] . m_Pos . y = pArray [ i ] . m_Y0 ;
m_aVertices [ m_NumVertices + 4 * i ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i ] , 0 ) ;
m_aVertices [ m_NumVertices + 4 * i + 1 ] . m_Pos . x = pArray [ i ] . m_X1 ;
m_aVertices [ m_NumVertices + 4 * i + 1 ] . m_Pos . y = pArray [ i ] . m_Y1 ;
m_aVertices [ m_NumVertices + 4 * i + 1 ] . m_Tex = m_aTexture [ 1 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i + 1 ] , 1 ) ;
m_aVertices [ m_NumVertices + 4 * i + 2 ] . m_Pos . x = pArray [ i ] . m_X3 ;
m_aVertices [ m_NumVertices + 4 * i + 2 ] . m_Pos . y = pArray [ i ] . m_Y3 ;
m_aVertices [ m_NumVertices + 4 * i + 2 ] . m_Tex = m_aTexture [ 3 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i + 2 ] , 3 ) ;
m_aVertices [ m_NumVertices + 4 * i + 3 ] . m_Pos . x = pArray [ i ] . m_X2 ;
m_aVertices [ m_NumVertices + 4 * i + 3 ] . m_Pos . y = pArray [ i ] . m_Y2 ;
m_aVertices [ m_NumVertices + 4 * i + 3 ] . m_Tex = m_aTexture [ 2 ] ;
SetColor ( & m_aVertices [ m_NumVertices + 4 * i + 3 ] , 2 ) ;
2015-03-31 11:35:18 +00:00
}
2011-12-31 00:06:04 +00:00
2015-03-31 11:35:18 +00:00
AddVertices ( 4 * Num ) ;
}
2011-12-31 00:06:04 +00:00
}
2012-10-14 12:04:48 +00:00
void CGraphics_Threaded : : QuadsText ( float x , float y , float Size , const char * pText )
2011-12-31 00:06:04 +00:00
{
float StartX = x ;
while ( * pText )
{
char c = * pText ;
pText + + ;
if ( c = = ' \n ' )
{
x = StartX ;
y + = Size ;
}
else
{
QuadsSetSubset (
( c % 16 ) / 16.0f ,
( c / 16 ) / 16.0f ,
( c % 16 ) / 16.0f + 1.0f / 16.0f ,
( c / 16 ) / 16.0f + 1.0f / 16.0f ) ;
CQuadItem QuadItem ( x , y , Size , Size ) ;
QuadsDrawTL ( & QuadItem , 1 ) ;
x + = Size / 2 ;
}
}
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : RenderTileLayer ( int BufferContainerIndex , float * pColor , char * * pOffsets , unsigned int * IndicedVertexDrawNum , size_t NumIndicesOffet )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
if ( NumIndicesOffet = = 0 )
return ;
2019-04-26 22:11:15 +00:00
2017-09-12 18:08:45 +00:00
//add the VertexArrays and draw
2018-03-13 20:47:07 +00:00
CCommandBuffer : : SCommand_RenderTileLayer Cmd ;
2017-09-12 18:08:45 +00:00
Cmd . m_State = m_State ;
Cmd . m_IndicesDrawNum = NumIndicesOffet ;
2018-03-13 20:47:07 +00:00
Cmd . m_BufferContainerIndex = BufferContainerIndex ;
2017-09-12 18:08:45 +00:00
mem_copy ( & Cmd . m_Color , pColor , sizeof ( Cmd . m_Color ) ) ;
2017-12-02 21:19:57 +00:00
void * Data = m_pCommandBuffer - > AllocData ( ( sizeof ( char * ) + sizeof ( unsigned int ) ) * NumIndicesOffet ) ;
2017-09-27 10:16:34 +00:00
if ( Data = = 0x0 )
2017-09-12 18:08:45 +00:00
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2019-04-26 22:11:15 +00:00
2017-12-02 21:19:57 +00:00
void * Data = m_pCommandBuffer - > AllocData ( ( sizeof ( char * ) + sizeof ( unsigned int ) ) * NumIndicesOffet ) ;
2017-09-27 10:16:34 +00:00
if ( Data = = 0x0 )
2017-09-12 18:08:45 +00:00
{
dbg_msg ( " graphics " , " failed to allocate data for vertices " ) ;
return ;
}
}
2017-09-27 10:16:34 +00:00
Cmd . m_pIndicesOffsets = ( char * * ) Data ;
Cmd . m_pDrawCount = ( unsigned int * ) ( ( ( char * ) Data ) + ( sizeof ( char * ) * NumIndicesOffet ) ) ;
2019-04-26 22:11:15 +00:00
2017-09-12 18:08:45 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2017-09-27 10:16:34 +00:00
Data = m_pCommandBuffer - > AllocData ( ( sizeof ( char * ) + sizeof ( unsigned int ) ) * NumIndicesOffet ) ;
if ( Data = = 0x0 )
2017-09-12 18:08:45 +00:00
{
dbg_msg ( " graphics " , " failed to allocate data for vertices " ) ;
return ;
}
2017-09-27 10:16:34 +00:00
Cmd . m_pIndicesOffsets = ( char * * ) Data ;
Cmd . m_pDrawCount = ( unsigned int * ) ( ( ( char * ) Data ) + ( sizeof ( char * ) * NumIndicesOffet ) ) ;
2017-09-12 18:08:45 +00:00
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render command " ) ;
return ;
}
}
2019-04-26 22:11:15 +00:00
2017-09-27 10:16:34 +00:00
mem_copy ( Cmd . m_pIndicesOffsets , pOffsets , sizeof ( char * ) * NumIndicesOffet ) ;
mem_copy ( Cmd . m_pDrawCount , IndicedVertexDrawNum , sizeof ( unsigned int ) * NumIndicesOffet ) ;
2019-04-26 22:11:15 +00:00
2017-09-12 18:08:45 +00:00
//todo max indices group check!!
}
2018-08-02 16:26:12 +00:00
void CGraphics_Threaded : : RenderBorderTiles ( int BufferContainerIndex , float * pColor , char * pIndexBufferOffset , float * pOffset , float * pDir , int JumpIndex , unsigned int DrawNum )
2017-09-13 18:33:58 +00:00
{
2018-08-02 16:26:12 +00:00
if ( DrawNum = = 0 )
return ;
2018-02-04 15:00:47 +00:00
// Draw a border tile a lot of times
2017-09-12 18:08:45 +00:00
CCommandBuffer : : SCommand_RenderBorderTile Cmd ;
Cmd . m_State = m_State ;
Cmd . m_DrawNum = DrawNum ;
2018-03-13 20:47:07 +00:00
Cmd . m_BufferContainerIndex = BufferContainerIndex ;
2017-09-12 18:08:45 +00:00
mem_copy ( & Cmd . m_Color , pColor , sizeof ( Cmd . m_Color ) ) ;
2018-08-02 16:26:12 +00:00
Cmd . m_pIndicesOffset = pIndexBufferOffset ;
2017-09-12 18:08:45 +00:00
Cmd . m_JumpIndex = JumpIndex ;
2019-04-26 22:11:15 +00:00
2018-08-02 16:26:12 +00:00
Cmd . m_Offset [ 0 ] = pOffset [ 0 ] ;
Cmd . m_Offset [ 1 ] = pOffset [ 1 ] ;
Cmd . m_Dir [ 0 ] = pDir [ 0 ] ;
Cmd . m_Dir [ 1 ] = pDir [ 1 ] ;
2017-09-12 18:08:45 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render command " ) ;
return ;
}
}
}
2018-08-02 16:26:12 +00:00
void CGraphics_Threaded : : RenderBorderTileLines ( int BufferContainerIndex , float * pColor , char * pIndexBufferOffset , float * pOffset , float * pDir , unsigned int IndexDrawNum , unsigned int RedrawNum )
2017-09-13 18:33:58 +00:00
{
2018-08-02 16:26:12 +00:00
if ( IndexDrawNum = = 0 | | RedrawNum = = 0 )
return ;
2018-02-04 15:00:47 +00:00
// Draw a border tile a lot of times
2017-09-12 18:08:45 +00:00
CCommandBuffer : : SCommand_RenderBorderTileLine Cmd ;
Cmd . m_State = m_State ;
Cmd . m_IndexDrawNum = IndexDrawNum ;
Cmd . m_DrawNum = RedrawNum ;
2018-03-13 20:47:07 +00:00
Cmd . m_BufferContainerIndex = BufferContainerIndex ;
2017-09-12 18:08:45 +00:00
mem_copy ( & Cmd . m_Color , pColor , sizeof ( Cmd . m_Color ) ) ;
2018-08-02 16:26:12 +00:00
Cmd . m_pIndicesOffset = pIndexBufferOffset ;
Cmd . m_Offset [ 0 ] = pOffset [ 0 ] ;
Cmd . m_Offset [ 1 ] = pOffset [ 1 ] ;
Cmd . m_Dir [ 0 ] = pDir [ 0 ] ;
Cmd . m_Dir [ 1 ] = pDir [ 1 ] ;
2017-09-12 18:08:45 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render command " ) ;
return ;
}
}
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : RenderQuadLayer ( int BufferContainerIndex , SQuadRenderInfo * pQuadInfo , int QuadNum )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
if ( QuadNum = = 0 )
return ;
//add the VertexArrays and draw
CCommandBuffer : : SCommand_RenderQuadLayer Cmd ;
Cmd . m_State = m_State ;
Cmd . m_QuadNum = QuadNum ;
Cmd . m_BufferContainerIndex = BufferContainerIndex ;
Cmd . m_pQuadInfo = ( SQuadRenderInfo * ) AllocCommandBufferData ( QuadNum * sizeof ( SQuadRenderInfo ) ) ;
if ( Cmd . m_pQuadInfo = = 0x0 )
return ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
Cmd . m_pQuadInfo = ( SQuadRenderInfo * ) m_pCommandBuffer - > AllocData ( QuadNum * sizeof ( SQuadRenderInfo ) ) ;
if ( Cmd . m_pQuadInfo = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for the quad info " ) ;
return ;
}
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render quad command " ) ;
return ;
}
}
mem_copy ( Cmd . m_pQuadInfo , pQuadInfo , sizeof ( SQuadRenderInfo ) * QuadNum ) ;
}
void CGraphics_Threaded : : RenderText ( int BufferContainerIndex , int TextQuadNum , int TextureSize , int TextureTextIndex , int TextureTextOutlineIndex , float * pTextColor , float * pTextoutlineColor )
{
if ( BufferContainerIndex = = - 1 )
return ;
CCommandBuffer : : SCommand_RenderText Cmd ;
Cmd . m_State = m_State ;
Cmd . m_BufferContainerIndex = BufferContainerIndex ;
Cmd . m_DrawNum = TextQuadNum * 6 ;
Cmd . m_TextureSize = TextureSize ;
Cmd . m_TextTextureIndex = TextureTextIndex ;
Cmd . m_TextOutlineTextureIndex = TextureTextOutlineIndex ;
mem_copy ( Cmd . m_aTextColor , pTextColor , sizeof ( Cmd . m_aTextColor ) ) ;
mem_copy ( Cmd . m_aTextOutlineColor , pTextoutlineColor , sizeof ( Cmd . m_aTextOutlineColor ) ) ;
2017-09-12 18:08:45 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate memory for render text command " ) ;
2017-09-12 18:08:45 +00:00
return ;
}
}
}
2018-03-13 20:47:07 +00:00
int CGraphics_Threaded : : CreateQuadContainer ( )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
int Index = - 1 ;
if ( m_FirstFreeQuadContainer = = - 1 )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
Index = m_QuadContainers . size ( ) ;
m_QuadContainers . push_back ( SQuadContainer ( ) ) ;
2017-09-27 12:52:06 +00:00
}
else
{
2018-03-13 20:47:07 +00:00
Index = m_FirstFreeQuadContainer ;
m_FirstFreeQuadContainer = m_QuadContainers [ Index ] . m_FreeIndex ;
m_QuadContainers [ Index ] . m_FreeIndex = Index ;
2017-09-12 18:08:45 +00:00
}
2018-03-13 20:47:07 +00:00
return Index ;
}
2018-04-15 17:34:56 +00:00
void CGraphics_Threaded : : QuadContainerUpload ( int ContainerIndex )
{
2020-08-22 06:09:10 +00:00
if ( IsQuadContainerBufferingEnabled ( ) )
2018-04-15 17:34:56 +00:00
{
SQuadContainer & Container = m_QuadContainers [ ContainerIndex ] ;
if ( Container . m_Quads . size ( ) > 0 )
{
if ( Container . m_QuadBufferObjectIndex = = - 1 )
{
size_t UploadDataSize = Container . m_Quads . size ( ) * sizeof ( SQuadContainer : : SQuad ) ;
Container . m_QuadBufferObjectIndex = CreateBufferObject ( UploadDataSize , & Container . m_Quads [ 0 ] ) ;
}
else
{
size_t UploadDataSize = Container . m_Quads . size ( ) * sizeof ( SQuadContainer : : SQuad ) ;
RecreateBufferObject ( Container . m_QuadBufferObjectIndex , UploadDataSize , & Container . m_Quads [ 0 ] ) ;
}
if ( Container . m_QuadBufferContainerIndex = = - 1 )
{
SBufferContainerInfo Info ;
Info . m_Stride = sizeof ( CCommandBuffer : : SVertex ) ;
Info . m_Attributes . push_back ( SBufferContainerInfo : : SAttribute ( ) ) ;
SBufferContainerInfo : : SAttribute * pAttr = & Info . m_Attributes . back ( ) ;
pAttr - > m_DataTypeCount = 2 ;
pAttr - > m_FuncType = 0 ;
pAttr - > m_Normalized = false ;
pAttr - > m_pOffset = 0 ;
pAttr - > m_Type = GRAPHICS_TYPE_FLOAT ;
pAttr - > m_VertBufferBindingIndex = Container . m_QuadBufferObjectIndex ;
Info . m_Attributes . push_back ( SBufferContainerInfo : : SAttribute ( ) ) ;
pAttr = & Info . m_Attributes . back ( ) ;
pAttr - > m_DataTypeCount = 2 ;
pAttr - > m_FuncType = 0 ;
pAttr - > m_Normalized = false ;
pAttr - > m_pOffset = ( void * ) ( sizeof ( float ) * 2 ) ;
pAttr - > m_Type = GRAPHICS_TYPE_FLOAT ;
pAttr - > m_VertBufferBindingIndex = Container . m_QuadBufferObjectIndex ;
Info . m_Attributes . push_back ( SBufferContainerInfo : : SAttribute ( ) ) ;
pAttr = & Info . m_Attributes . back ( ) ;
pAttr - > m_DataTypeCount = 4 ;
pAttr - > m_FuncType = 0 ;
pAttr - > m_Normalized = true ;
pAttr - > m_pOffset = ( void * ) ( sizeof ( float ) * 2 + sizeof ( float ) * 2 ) ;
pAttr - > m_Type = GRAPHICS_TYPE_UNSIGNED_BYTE ;
pAttr - > m_VertBufferBindingIndex = Container . m_QuadBufferObjectIndex ;
Container . m_QuadBufferContainerIndex = CreateBufferContainer ( & Info ) ;
}
}
}
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : QuadContainerAddQuads ( int ContainerIndex , CQuadItem * pArray , int Num )
{
SQuadContainer & Container = m_QuadContainers [ ContainerIndex ] ;
if ( ( int ) Container . m_Quads . size ( ) > Num + CCommandBuffer : : MAX_VERTICES )
return ;
for ( int i = 0 ; i < Num ; + + i )
{
Container . m_Quads . push_back ( SQuadContainer : : SQuad ( ) ) ;
SQuadContainer : : SQuad & Quad = Container . m_Quads . back ( ) ;
Quad . m_aVertices [ 0 ] . m_Pos . x = pArray [ i ] . m_X ;
Quad . m_aVertices [ 0 ] . m_Pos . y = pArray [ i ] . m_Y ;
Quad . m_aVertices [ 0 ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & Quad . m_aVertices [ 0 ] , 0 ) ;
Quad . m_aVertices [ 1 ] . m_Pos . x = pArray [ i ] . m_X + pArray [ i ] . m_Width ;
Quad . m_aVertices [ 1 ] . m_Pos . y = pArray [ i ] . m_Y ;
Quad . m_aVertices [ 1 ] . m_Tex = m_aTexture [ 1 ] ;
SetColor ( & Quad . m_aVertices [ 1 ] , 1 ) ;
Quad . m_aVertices [ 2 ] . m_Pos . x = pArray [ i ] . m_X + pArray [ i ] . m_Width ;
Quad . m_aVertices [ 2 ] . m_Pos . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height ;
Quad . m_aVertices [ 2 ] . m_Tex = m_aTexture [ 2 ] ;
SetColor ( & Quad . m_aVertices [ 2 ] , 2 ) ;
Quad . m_aVertices [ 3 ] . m_Pos . x = pArray [ i ] . m_X ;
Quad . m_aVertices [ 3 ] . m_Pos . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height ;
Quad . m_aVertices [ 3 ] . m_Tex = m_aTexture [ 3 ] ;
SetColor ( & Quad . m_aVertices [ 3 ] , 3 ) ;
if ( m_Rotation ! = 0 )
{
CCommandBuffer : : SPoint Center ;
Center . x = pArray [ i ] . m_X + pArray [ i ] . m_Width / 2 ;
Center . y = pArray [ i ] . m_Y + pArray [ i ] . m_Height / 2 ;
Rotate ( Center , Quad . m_aVertices , 4 ) ;
}
}
2018-04-15 17:34:56 +00:00
QuadContainerUpload ( ContainerIndex ) ;
2018-03-13 20:47:07 +00:00
}
void CGraphics_Threaded : : QuadContainerAddQuads ( int ContainerIndex , CFreeformItem * pArray , int Num )
{
SQuadContainer & Container = m_QuadContainers [ ContainerIndex ] ;
if ( ( int ) Container . m_Quads . size ( ) > Num + CCommandBuffer : : MAX_VERTICES )
return ;
for ( int i = 0 ; i < Num ; + + i )
{
Container . m_Quads . push_back ( SQuadContainer : : SQuad ( ) ) ;
SQuadContainer : : SQuad & Quad = Container . m_Quads . back ( ) ;
Quad . m_aVertices [ 0 ] . m_Pos . x = pArray [ i ] . m_X0 ;
Quad . m_aVertices [ 0 ] . m_Pos . y = pArray [ i ] . m_Y0 ;
Quad . m_aVertices [ 0 ] . m_Tex = m_aTexture [ 0 ] ;
SetColor ( & Quad . m_aVertices [ 0 ] , 0 ) ;
Quad . m_aVertices [ 1 ] . m_Pos . x = pArray [ i ] . m_X1 ;
Quad . m_aVertices [ 1 ] . m_Pos . y = pArray [ i ] . m_Y1 ;
Quad . m_aVertices [ 1 ] . m_Tex = m_aTexture [ 1 ] ;
SetColor ( & Quad . m_aVertices [ 1 ] , 1 ) ;
Quad . m_aVertices [ 2 ] . m_Pos . x = pArray [ i ] . m_X3 ;
Quad . m_aVertices [ 2 ] . m_Pos . y = pArray [ i ] . m_Y3 ;
Quad . m_aVertices [ 2 ] . m_Tex = m_aTexture [ 3 ] ;
SetColor ( & Quad . m_aVertices [ 2 ] , 3 ) ;
Quad . m_aVertices [ 3 ] . m_Pos . x = pArray [ i ] . m_X2 ;
Quad . m_aVertices [ 3 ] . m_Pos . y = pArray [ i ] . m_Y2 ;
Quad . m_aVertices [ 3 ] . m_Tex = m_aTexture [ 2 ] ;
SetColor ( & Quad . m_aVertices [ 3 ] , 2 ) ;
}
2018-04-15 17:34:56 +00:00
QuadContainerUpload ( ContainerIndex ) ;
2018-03-13 20:47:07 +00:00
}
void CGraphics_Threaded : : QuadContainerReset ( int ContainerIndex )
{
SQuadContainer & Container = m_QuadContainers [ ContainerIndex ] ;
2020-08-22 06:09:10 +00:00
if ( IsQuadContainerBufferingEnabled ( ) )
2018-04-15 17:34:56 +00:00
{
if ( Container . m_QuadBufferContainerIndex ! = - 1 )
DeleteBufferContainer ( Container . m_QuadBufferContainerIndex , true ) ;
}
2018-03-13 20:47:07 +00:00
Container . m_Quads . clear ( ) ;
Container . m_QuadBufferContainerIndex = Container . m_QuadBufferObjectIndex = - 1 ;
}
void CGraphics_Threaded : : DeleteQuadContainer ( int ContainerIndex )
{
QuadContainerReset ( ContainerIndex ) ;
// also clear the container index
m_QuadContainers [ ContainerIndex ] . m_FreeIndex = m_FirstFreeQuadContainer ;
m_FirstFreeQuadContainer = ContainerIndex ;
}
void CGraphics_Threaded : : RenderQuadContainer ( int ContainerIndex , int QuadDrawNum )
{
RenderQuadContainer ( ContainerIndex , 0 , QuadDrawNum ) ;
}
void CGraphics_Threaded : : RenderQuadContainer ( int ContainerIndex , int QuadOffset , int QuadDrawNum )
{
SQuadContainer & Container = m_QuadContainers [ ContainerIndex ] ;
if ( QuadDrawNum = = - 1 )
QuadDrawNum = ( int ) Container . m_Quads . size ( ) - QuadOffset ;
if ( ( int ) Container . m_Quads . size ( ) < QuadOffset + QuadDrawNum | | QuadDrawNum = = 0 )
return ;
2019-04-26 22:11:15 +00:00
2020-08-22 06:09:10 +00:00
if ( IsQuadContainerBufferingEnabled ( ) )
2018-03-13 20:47:07 +00:00
{
2018-04-15 17:34:56 +00:00
if ( Container . m_QuadBufferContainerIndex = = - 1 )
return ;
2018-03-13 20:47:07 +00:00
CCommandBuffer : : SCommand_RenderQuadContainer Cmd ;
Cmd . m_State = m_State ;
Cmd . m_DrawNum = ( unsigned int ) QuadDrawNum * 6 ;
Cmd . m_pOffset = ( void * ) ( QuadOffset * 6 * sizeof ( unsigned int ) ) ;
Cmd . m_BufferContainerIndex = Container . m_QuadBufferContainerIndex ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render quad container " ) ;
return ;
}
}
}
else
{
if ( g_Config . m_GfxQuadAsTriangle )
{
for ( int i = 0 ; i < QuadDrawNum ; + + i )
{
SQuadContainer : : SQuad & Quad = Container . m_Quads [ QuadOffset + i ] ;
m_aVertices [ i * 6 ] = Quad . m_aVertices [ 0 ] ;
m_aVertices [ i * 6 + 1 ] = Quad . m_aVertices [ 1 ] ;
m_aVertices [ i * 6 + 2 ] = Quad . m_aVertices [ 2 ] ;
m_aVertices [ i * 6 + 3 ] = Quad . m_aVertices [ 0 ] ;
m_aVertices [ i * 6 + 4 ] = Quad . m_aVertices [ 2 ] ;
m_aVertices [ i * 6 + 5 ] = Quad . m_aVertices [ 3 ] ;
m_NumVertices + = 6 ;
}
}
else
{
mem_copy ( m_aVertices , & Container . m_Quads [ QuadOffset ] , sizeof ( CCommandBuffer : : SVertex ) * 4 * QuadDrawNum ) ;
m_NumVertices + = 4 * QuadDrawNum ;
}
m_Drawing = DRAWING_QUADS ;
FlushVertices ( false ) ;
m_Drawing = 0 ;
}
}
void CGraphics_Threaded : : RenderQuadContainerAsSprite ( int ContainerIndex , int QuadOffset , float X , float Y , float ScaleX , float ScaleY )
{
SQuadContainer & Container = m_QuadContainers [ ContainerIndex ] ;
if ( ( int ) Container . m_Quads . size ( ) < QuadOffset + 1 )
return ;
2020-08-22 06:09:10 +00:00
if ( IsQuadContainerBufferingEnabled ( ) )
2018-03-13 20:47:07 +00:00
{
2018-04-15 17:34:56 +00:00
if ( Container . m_QuadBufferContainerIndex = = - 1 )
return ;
2018-03-13 20:47:07 +00:00
SQuadContainer : : SQuad & Quad = Container . m_Quads [ QuadOffset ] ;
CCommandBuffer : : SCommand_RenderQuadContainerAsSprite Cmd ;
float ScreenX0 , ScreenY0 , ScreenX1 , ScreenY1 ;
GetScreen ( & ScreenX0 , & ScreenY0 , & ScreenX1 , & ScreenY1 ) ;
MapScreen ( ( ScreenX0 - X ) / ScaleX , ( ScreenY0 - Y ) / ScaleY , ( ScreenX1 - X ) / ScaleX , ( ScreenY1 - Y ) / ScaleY ) ;
Cmd . m_State = m_State ;
MapScreen ( ScreenX0 , ScreenY0 , ScreenX1 , ScreenY1 ) ;
Cmd . m_DrawNum = 1 * 6 ;
Cmd . m_pOffset = ( void * ) ( QuadOffset * 6 * sizeof ( unsigned int ) ) ;
Cmd . m_BufferContainerIndex = Container . m_QuadBufferContainerIndex ;
Cmd . m_VertexColor . r = ( float ) m_aColor [ 0 ] . r / 255.f ;
Cmd . m_VertexColor . g = ( float ) m_aColor [ 0 ] . g / 255.f ;
Cmd . m_VertexColor . b = ( float ) m_aColor [ 0 ] . b / 255.f ;
Cmd . m_VertexColor . a = ( float ) m_aColor [ 0 ] . a / 255.f ;
Cmd . m_Rotation = m_Rotation ;
// rotate before positioning
Cmd . m_Center . x = Quad . m_aVertices [ 0 ] . m_Pos . x + ( Quad . m_aVertices [ 1 ] . m_Pos . x - Quad . m_aVertices [ 0 ] . m_Pos . x ) / 2.f ;
Cmd . m_Center . y = Quad . m_aVertices [ 0 ] . m_Pos . y + ( Quad . m_aVertices [ 2 ] . m_Pos . y - Quad . m_aVertices [ 0 ] . m_Pos . y ) / 2.f ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render quad container sprite " ) ;
return ;
}
}
}
else
{
if ( g_Config . m_GfxQuadAsTriangle )
{
SQuadContainer : : SQuad & Quad = Container . m_Quads [ QuadOffset ] ;
m_aVertices [ 0 ] = Quad . m_aVertices [ 0 ] ;
m_aVertices [ 1 ] = Quad . m_aVertices [ 1 ] ;
m_aVertices [ 2 ] = Quad . m_aVertices [ 2 ] ;
m_aVertices [ 3 ] = Quad . m_aVertices [ 0 ] ;
m_aVertices [ 4 ] = Quad . m_aVertices [ 2 ] ;
m_aVertices [ 5 ] = Quad . m_aVertices [ 3 ] ;
for ( int i = 0 ; i < 6 ; + + i )
{
m_aVertices [ i ] . m_Pos . x * = ScaleX ;
m_aVertices [ i ] . m_Pos . y * = ScaleY ;
}
SetColor ( & m_aVertices [ 0 ] , 0 ) ;
SetColor ( & m_aVertices [ 1 ] , 0 ) ;
SetColor ( & m_aVertices [ 2 ] , 0 ) ;
SetColor ( & m_aVertices [ 3 ] , 0 ) ;
SetColor ( & m_aVertices [ 4 ] , 0 ) ;
SetColor ( & m_aVertices [ 5 ] , 0 ) ;
if ( m_Rotation ! = 0 )
{
CCommandBuffer : : SPoint Center ;
Center . x = m_aVertices [ 0 ] . m_Pos . x + ( m_aVertices [ 1 ] . m_Pos . x - m_aVertices [ 0 ] . m_Pos . x ) / 2.f ;
Center . y = m_aVertices [ 0 ] . m_Pos . y + ( m_aVertices [ 2 ] . m_Pos . y - m_aVertices [ 0 ] . m_Pos . y ) / 2.f ;
Rotate ( Center , & m_aVertices [ 0 ] , 6 ) ;
}
for ( int i = 0 ; i < 6 ; + + i )
{
m_aVertices [ i ] . m_Pos . x + = X ;
m_aVertices [ i ] . m_Pos . y + = Y ;
}
m_NumVertices + = 6 ;
}
else
{
mem_copy ( m_aVertices , & Container . m_Quads [ QuadOffset ] , sizeof ( CCommandBuffer : : SVertex ) * 4 * 1 ) ;
SetColor ( & m_aVertices [ 0 ] , 0 ) ;
SetColor ( & m_aVertices [ 1 ] , 0 ) ;
SetColor ( & m_aVertices [ 2 ] , 0 ) ;
SetColor ( & m_aVertices [ 3 ] , 0 ) ;
for ( int i = 0 ; i < 4 ; + + i )
{
m_aVertices [ i ] . m_Pos . x * = ScaleX ;
m_aVertices [ i ] . m_Pos . y * = ScaleY ;
}
if ( m_Rotation ! = 0 )
{
CCommandBuffer : : SPoint Center ;
Center . x = m_aVertices [ 0 ] . m_Pos . x + ( m_aVertices [ 1 ] . m_Pos . x - m_aVertices [ 0 ] . m_Pos . x ) / 2.f ;
Center . y = m_aVertices [ 0 ] . m_Pos . y + ( m_aVertices [ 2 ] . m_Pos . y - m_aVertices [ 0 ] . m_Pos . y ) / 2.f ;
Rotate ( Center , & m_aVertices [ 0 ] , 4 ) ;
}
for ( int i = 0 ; i < 4 ; + + i )
{
m_aVertices [ i ] . m_Pos . x + = X ;
m_aVertices [ i ] . m_Pos . y + = Y ;
}
m_NumVertices + = 4 ;
}
m_Drawing = DRAWING_QUADS ;
FlushVertices ( false ) ;
m_Drawing = 0 ;
}
}
void CGraphics_Threaded : : RenderQuadContainerAsSpriteMultiple ( int ContainerIndex , int QuadOffset , int DrawCount , SRenderSpriteInfo * pRenderInfo )
{
SQuadContainer & Container = m_QuadContainers [ ContainerIndex ] ;
if ( DrawCount = = 0 )
return ;
2020-08-22 06:09:10 +00:00
if ( IsQuadContainerBufferingEnabled ( ) )
2018-03-13 20:47:07 +00:00
{
2018-04-15 17:34:56 +00:00
if ( Container . m_QuadBufferContainerIndex = = - 1 )
return ;
2018-03-13 20:47:07 +00:00
SQuadContainer : : SQuad & Quad = Container . m_Quads [ 0 ] ;
CCommandBuffer : : SCommand_RenderQuadContainerAsSpriteMultiple Cmd ;
Cmd . m_State = m_State ;
Cmd . m_DrawNum = 1 * 6 ;
Cmd . m_DrawCount = DrawCount ;
Cmd . m_pOffset = ( void * ) ( QuadOffset * 6 * sizeof ( unsigned int ) ) ;
Cmd . m_BufferContainerIndex = Container . m_QuadBufferContainerIndex ;
Cmd . m_VertexColor . r = ( float ) m_aColor [ 0 ] . r / 255.f ;
Cmd . m_VertexColor . g = ( float ) m_aColor [ 0 ] . g / 255.f ;
Cmd . m_VertexColor . b = ( float ) m_aColor [ 0 ] . b / 255.f ;
Cmd . m_VertexColor . a = ( float ) m_aColor [ 0 ] . a / 255.f ;
// rotate before positioning
Cmd . m_Center . x = Quad . m_aVertices [ 0 ] . m_Pos . x + ( Quad . m_aVertices [ 1 ] . m_Pos . x - Quad . m_aVertices [ 0 ] . m_Pos . x ) / 2.f ;
Cmd . m_Center . y = Quad . m_aVertices [ 0 ] . m_Pos . y + ( Quad . m_aVertices [ 2 ] . m_Pos . y - Quad . m_aVertices [ 0 ] . m_Pos . y ) / 2.f ;
Cmd . m_pRenderInfo = ( IGraphics : : SRenderSpriteInfo * ) m_pCommandBuffer - > AllocData ( sizeof ( IGraphics : : SRenderSpriteInfo ) * DrawCount ) ;
if ( Cmd . m_pRenderInfo = = 0x0 )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
Cmd . m_pRenderInfo = ( IGraphics : : SRenderSpriteInfo * ) m_pCommandBuffer - > AllocData ( sizeof ( IGraphics : : SRenderSpriteInfo ) * DrawCount ) ;
if ( Cmd . m_pRenderInfo = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for render info " ) ;
return ;
}
}
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
Cmd . m_pRenderInfo = ( IGraphics : : SRenderSpriteInfo * ) m_pCommandBuffer - > AllocData ( sizeof ( IGraphics : : SRenderSpriteInfo ) * DrawCount ) ;
if ( Cmd . m_pRenderInfo = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for render info " ) ;
return ;
}
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for render quad container sprite " ) ;
return ;
}
}
mem_copy ( Cmd . m_pRenderInfo , pRenderInfo , sizeof ( IGraphics : : SRenderSpriteInfo ) * DrawCount ) ;
}
else
{
for ( int i = 0 ; i < DrawCount ; + + i )
{
QuadsSetRotation ( pRenderInfo [ i ] . m_Rotation ) ;
RenderQuadContainerAsSprite ( ContainerIndex , QuadOffset , pRenderInfo [ i ] . m_Pos [ 0 ] , pRenderInfo [ i ] . m_Pos [ 1 ] , pRenderInfo [ i ] . m_Scale , pRenderInfo [ i ] . m_Scale ) ;
}
}
}
2019-12-21 13:35:09 +00:00
void * CGraphics_Threaded : : AllocCommandBufferData ( unsigned AllocSize )
{
2019-04-26 22:11:15 +00:00
void * pData = m_pCommandBuffer - > AllocData ( AllocSize ) ;
2018-03-13 20:47:07 +00:00
if ( pData = = 0x0 )
2017-09-12 18:08:45 +00:00
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2018-03-13 20:47:07 +00:00
pData = m_pCommandBuffer - > AllocData ( AllocSize ) ;
if ( pData = = 0x0 )
2017-09-12 18:08:45 +00:00
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate data for command buffer " ) ;
return NULL ;
}
}
return pData ;
}
int CGraphics_Threaded : : CreateBufferObject ( size_t UploadDataSize , void * pUploadData )
{
int Index = - 1 ;
if ( m_FirstFreeBufferObjectIndex = = - 1 )
{
Index = m_BufferObjectIndices . size ( ) ;
m_BufferObjectIndices . push_back ( Index ) ;
}
else
{
Index = m_FirstFreeBufferObjectIndex ;
m_FirstFreeBufferObjectIndex = m_BufferObjectIndices [ Index ] ;
m_BufferObjectIndices [ Index ] = Index ;
}
CCommandBuffer : : SCommand_CreateBufferObject Cmd ;
Cmd . m_BufferIndex = Index ;
Cmd . m_DataSize = UploadDataSize ;
if ( UploadDataSize < = CMD_BUFFER_DATA_BUFFER_SIZE )
{
Cmd . m_pUploadData = AllocCommandBufferData ( UploadDataSize ) ;
if ( Cmd . m_pUploadData = = NULL )
2017-09-12 18:08:45 +00:00
return - 1 ;
2018-03-13 20:47:07 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
Cmd . m_pUploadData = m_pCommandBuffer - > AllocData ( UploadDataSize ) ;
if ( Cmd . m_pUploadData = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for upload data " ) ;
return - 1 ;
}
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for create buffer object command " ) ;
return - 1 ;
}
}
mem_copy ( Cmd . m_pUploadData , pUploadData , UploadDataSize ) ;
}
else {
Cmd . m_pUploadData = NULL ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for create buffer object command " ) ;
return - 1 ;
}
}
// update the buffer instead
size_t UploadDataOffset = 0 ;
while ( UploadDataSize > 0 ) {
size_t UpdateSize = ( UploadDataSize > CMD_BUFFER_DATA_BUFFER_SIZE ? CMD_BUFFER_DATA_BUFFER_SIZE : UploadDataSize ) ;
UpdateBufferObject ( Index , UpdateSize , ( ( ( char * ) pUploadData ) + UploadDataOffset ) , ( void * ) UploadDataOffset ) ;
UploadDataOffset + = UpdateSize ;
UploadDataSize - = UpdateSize ;
}
}
return Index ;
}
void CGraphics_Threaded : : RecreateBufferObject ( int BufferIndex , size_t UploadDataSize , void * pUploadData )
{
CCommandBuffer : : SCommand_RecreateBufferObject Cmd ;
Cmd . m_BufferIndex = BufferIndex ;
Cmd . m_DataSize = UploadDataSize ;
if ( UploadDataSize < = CMD_BUFFER_DATA_BUFFER_SIZE )
{
Cmd . m_pUploadData = AllocCommandBufferData ( UploadDataSize ) ;
if ( Cmd . m_pUploadData = = NULL )
return ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
Cmd . m_pUploadData = m_pCommandBuffer - > AllocData ( UploadDataSize ) ;
if ( Cmd . m_pUploadData = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for upload data " ) ;
return ;
}
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for recreate buffer object command " ) ;
return ;
}
2017-09-12 18:08:45 +00:00
}
2018-03-13 20:47:07 +00:00
mem_copy ( Cmd . m_pUploadData , pUploadData , UploadDataSize ) ;
2017-09-12 18:08:45 +00:00
}
2018-03-13 20:47:07 +00:00
else {
Cmd . m_pUploadData = NULL ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for update buffer object command " ) ;
return ;
}
}
// update the buffer instead
size_t UploadDataOffset = 0 ;
while ( UploadDataSize > 0 ) {
size_t UpdateSize = ( UploadDataSize > CMD_BUFFER_DATA_BUFFER_SIZE ? CMD_BUFFER_DATA_BUFFER_SIZE : UploadDataSize ) ;
UpdateBufferObject ( BufferIndex , UpdateSize , ( ( ( char * ) pUploadData ) + UploadDataOffset ) , ( void * ) UploadDataOffset ) ;
UploadDataOffset + = UpdateSize ;
UploadDataSize - = UpdateSize ;
}
}
}
void CGraphics_Threaded : : UpdateBufferObject ( int BufferIndex , size_t UploadDataSize , void * pUploadData , void * pOffset )
{
CCommandBuffer : : SCommand_UpdateBufferObject Cmd ;
Cmd . m_BufferIndex = BufferIndex ;
Cmd . m_DataSize = UploadDataSize ;
Cmd . m_pOffset = pOffset ;
Cmd . m_pUploadData = AllocCommandBufferData ( UploadDataSize ) ;
if ( Cmd . m_pUploadData = = NULL )
return ;
2017-09-12 18:08:45 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2018-03-13 20:47:07 +00:00
Cmd . m_pUploadData = m_pCommandBuffer - > AllocData ( UploadDataSize ) ;
if ( Cmd . m_pUploadData = = 0x0 )
2017-09-12 18:08:45 +00:00
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate data for upload data " ) ;
return ;
2017-09-12 18:08:45 +00:00
}
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate memory for update buffer object command " ) ;
return ;
2017-09-12 18:08:45 +00:00
}
}
2018-03-13 20:47:07 +00:00
mem_copy ( Cmd . m_pUploadData , pUploadData , UploadDataSize ) ;
}
void CGraphics_Threaded : : CopyBufferObject ( int WriteBufferIndex , int ReadBufferIndex , size_t WriteOffset , size_t ReadOffset , size_t CopyDataSize )
{
CCommandBuffer : : SCommand_CopyBufferObject Cmd ;
Cmd . m_WriteBufferIndex = WriteBufferIndex ;
Cmd . m_ReadBufferIndex = ReadBufferIndex ;
Cmd . m_pWriteOffset = WriteOffset ;
Cmd . m_pReadOffset = ReadOffset ;
Cmd . m_CopySize = CopyDataSize ;
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for copy buffer object command " ) ;
return ;
}
2017-09-12 18:08:45 +00:00
}
2018-03-13 20:47:07 +00:00
}
void CGraphics_Threaded : : DeleteBufferObject ( int BufferIndex )
{
if ( BufferIndex = = - 1 )
return ;
CCommandBuffer : : SCommand_DeleteBufferObject Cmd ;
Cmd . m_BufferIndex = BufferIndex ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
// kick command buffer and try again
KickCommandBuffer ( ) ;
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for delete buffer object command " ) ;
return ;
}
2017-09-12 18:08:45 +00:00
}
2018-03-13 20:47:07 +00:00
// also clear the buffer object index
m_BufferObjectIndices [ BufferIndex ] = m_FirstFreeBufferObjectIndex ;
m_FirstFreeBufferObjectIndex = BufferIndex ;
}
int CGraphics_Threaded : : CreateBufferContainer ( SBufferContainerInfo * pContainerInfo )
{
int Index = - 1 ;
if ( m_FirstFreeVertexArrayInfo = = - 1 )
{
Index = m_VertexArrayInfo . size ( ) ;
m_VertexArrayInfo . push_back ( SVertexArrayInfo ( ) ) ;
}
else
{
Index = m_FirstFreeVertexArrayInfo ;
m_FirstFreeVertexArrayInfo = m_VertexArrayInfo [ Index ] . m_FreeIndex ;
m_VertexArrayInfo [ Index ] . m_FreeIndex = Index ;
}
CCommandBuffer : : SCommand_CreateBufferContainer Cmd ;
Cmd . m_BufferContainerIndex = Index ;
Cmd . m_AttrCount = ( int ) pContainerInfo - > m_Attributes . size ( ) ;
Cmd . m_Stride = pContainerInfo - > m_Stride ;
Cmd . m_Attributes = ( SBufferContainerInfo : : SAttribute * ) AllocCommandBufferData ( Cmd . m_AttrCount * sizeof ( SBufferContainerInfo : : SAttribute ) ) ;
if ( Cmd . m_Attributes = = NULL )
return - 1 ;
2017-09-12 18:08:45 +00:00
// check if we have enough free memory in the commandbuffer
2018-03-13 20:47:07 +00:00
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
2017-09-12 18:08:45 +00:00
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2018-03-13 20:47:07 +00:00
Cmd . m_Attributes = ( SBufferContainerInfo : : SAttribute * ) m_pCommandBuffer - > AllocData ( Cmd . m_AttrCount * sizeof ( SBufferContainerInfo : : SAttribute ) ) ;
if ( Cmd . m_Attributes = = 0x0 )
{
dbg_msg ( " graphics " , " failed to allocate data for upload data " ) ;
return - 1 ;
}
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
2017-09-12 18:08:45 +00:00
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate memory for create buffer container command " ) ;
2017-09-12 18:08:45 +00:00
return - 1 ;
}
}
2018-03-13 20:47:07 +00:00
mem_copy ( Cmd . m_Attributes , & pContainerInfo - > m_Attributes [ 0 ] , Cmd . m_AttrCount * sizeof ( SBufferContainerInfo : : SAttribute ) ) ;
for ( size_t i = 0 ; i < pContainerInfo - > m_Attributes . size ( ) ; + + i )
m_VertexArrayInfo [ Index ] . m_AssociatedBufferObjectIndices . push_back ( pContainerInfo - > m_Attributes [ i ] . m_VertBufferBindingIndex ) ;
return Index ;
2017-09-12 18:08:45 +00:00
}
2018-03-13 20:47:07 +00:00
void CGraphics_Threaded : : DeleteBufferContainer ( int ContainerIndex , bool DestroyAllBO )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
if ( ContainerIndex = = - 1 )
return ;
CCommandBuffer : : SCommand_DeleteBufferContainer Cmd ;
Cmd . m_BufferContainerIndex = ContainerIndex ;
Cmd . m_DestroyAllBO = DestroyAllBO ;
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
2017-09-12 18:08:45 +00:00
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2018-03-13 20:47:07 +00:00
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
2017-09-12 18:08:45 +00:00
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate memory for delete buffer container command " ) ;
2017-09-12 18:08:45 +00:00
return ;
}
}
2018-03-13 20:47:07 +00:00
if ( DestroyAllBO )
{
// delete all associated references
for ( size_t i = 0 ; i < m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices . size ( ) ; + + i )
{
int BufferObjectIndex = m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices [ i ] ;
if ( BufferObjectIndex ! = - 1 )
{
// don't delete double entries
for ( size_t n = 0 ; n < m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices . size ( ) ; + + n )
{
if ( BufferObjectIndex = = m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices [ n ] )
m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices [ n ] = - 1 ;
}
// clear the buffer object index
m_BufferObjectIndices [ BufferObjectIndex ] = m_FirstFreeBufferObjectIndex ;
m_FirstFreeBufferObjectIndex = BufferObjectIndex ;
}
}
}
m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices . clear ( ) ;
// also clear the buffer object index
m_VertexArrayInfo [ ContainerIndex ] . m_FreeIndex = m_FirstFreeVertexArrayInfo ;
m_FirstFreeVertexArrayInfo = ContainerIndex ;
}
void CGraphics_Threaded : : UpdateBufferContainer ( int ContainerIndex , SBufferContainerInfo * pContainerInfo )
{
CCommandBuffer : : SCommand_UpdateBufferContainer Cmd ;
Cmd . m_BufferContainerIndex = ContainerIndex ;
Cmd . m_AttrCount = ( int ) pContainerInfo - > m_Attributes . size ( ) ;
Cmd . m_Stride = pContainerInfo - > m_Stride ;
Cmd . m_Attributes = ( SBufferContainerInfo : : SAttribute * ) AllocCommandBufferData ( Cmd . m_AttrCount * sizeof ( SBufferContainerInfo : : SAttribute ) ) ;
if ( Cmd . m_Attributes = = NULL )
return ;
2017-09-12 18:08:45 +00:00
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
// kick command buffer and try again
KickCommandBuffer ( ) ;
2018-03-13 20:47:07 +00:00
Cmd . m_Attributes = ( SBufferContainerInfo : : SAttribute * ) m_pCommandBuffer - > AllocData ( Cmd . m_AttrCount * sizeof ( SBufferContainerInfo : : SAttribute ) ) ;
if ( Cmd . m_Attributes = = 0x0 )
2017-09-12 18:08:45 +00:00
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate data for upload data " ) ;
2017-09-12 18:08:45 +00:00
return ;
}
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
2018-03-13 20:47:07 +00:00
dbg_msg ( " graphics " , " failed to allocate memory for update buffer container command " ) ;
2017-09-12 18:08:45 +00:00
return ;
}
}
2018-03-13 20:47:07 +00:00
mem_copy ( Cmd . m_Attributes , & pContainerInfo - > m_Attributes [ 0 ] , Cmd . m_AttrCount * sizeof ( SBufferContainerInfo : : SAttribute ) ) ;
m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices . clear ( ) ;
for ( size_t i = 0 ; i < pContainerInfo - > m_Attributes . size ( ) ; + + i )
m_VertexArrayInfo [ ContainerIndex ] . m_AssociatedBufferObjectIndices . push_back ( pContainerInfo - > m_Attributes [ i ] . m_VertBufferBindingIndex ) ;
}
void CGraphics_Threaded : : IndicesNumRequiredNotify ( unsigned int RequiredIndicesCount )
{
CCommandBuffer : : SCommand_IndicesRequiredNumNotify Cmd ;
Cmd . m_RequiredIndicesNum = RequiredIndicesCount ;
// check if we have enough free memory in the commandbuffer
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
2017-09-13 18:33:58 +00:00
{
2018-03-13 20:47:07 +00:00
// kick command buffer and try again
KickCommandBuffer ( ) ;
2019-04-26 22:11:15 +00:00
2018-03-13 20:47:07 +00:00
if ( ! m_pCommandBuffer - > AddCommand ( Cmd ) )
{
dbg_msg ( " graphics " , " failed to allocate memory for indcies required count notify command " ) ;
return ;
}
2017-09-12 18:08:45 +00:00
}
}
2011-12-31 13:00:49 +00:00
int CGraphics_Threaded : : IssueInit ( )
{
2012-01-03 20:39:10 +00:00
int Flags = 0 ;
2012-06-27 09:46:11 +00:00
if ( g_Config . m_GfxBorderless ) Flags | = IGraphicsBackend : : INITFLAG_BORDERLESS ;
2016-04-29 22:34:12 +00:00
if ( g_Config . m_GfxFullscreen ) Flags | = IGraphicsBackend : : INITFLAG_FULLSCREEN ;
2012-01-03 20:39:10 +00:00
if ( g_Config . m_GfxVsync ) Flags | = IGraphicsBackend : : INITFLAG_VSYNC ;
2020-04-07 20:37:46 +00:00
if ( g_Config . m_GfxHighdpi ) Flags | = IGraphicsBackend : : INITFLAG_HIGHDPI ;
2016-04-30 15:59:58 +00:00
if ( g_Config . m_GfxResizable ) Flags | = IGraphicsBackend : : INITFLAG_RESIZABLE ;
2011-12-31 13:00:49 +00:00
2017-12-02 21:19:57 +00:00
int r = m_pBackend - > Init ( " DDNet Client " , & g_Config . m_GfxScreen , & g_Config . m_GfxScreenWidth , & g_Config . m_GfxScreenHeight , g_Config . m_GfxFsaaSamples , Flags , & m_DesktopScreenWidth , & m_DesktopScreenHeight , & m_ScreenWidth , & m_ScreenHeight , m_pStorage ) ;
2020-08-18 18:26:35 +00:00
m_IsNewOpenGL = m_pBackend - > IsNewOpenGL ( ) ;
2020-08-22 06:09:10 +00:00
m_OpenGLTileBufferingEnabled = m_IsNewOpenGL | | m_pBackend - > HasTileBuffering ( ) ;
m_OpenGLQuadBufferingEnabled = m_IsNewOpenGL | | m_pBackend - > HasQuadBuffering ( ) ;
m_OpenGLQuadContainerBufferingEnabled = m_IsNewOpenGL | | m_pBackend - > HasQuadContainerBuffering ( ) ;
m_OpenGLTextBufferingEnabled = m_IsNewOpenGL | | ( m_OpenGLQuadContainerBufferingEnabled & & m_pBackend - > HasTextBuffering ( ) ) ;
m_OpenGLHasTextureArrays = m_IsNewOpenGL | | m_pBackend - > Has2DTextureArrays ( ) ;
2017-09-12 18:08:45 +00:00
return r ;
2011-12-31 13:00:49 +00:00
}
int CGraphics_Threaded : : InitWindow ( )
{
2020-08-22 06:09:10 +00:00
int ErrorCode = IssueInit ( ) ;
if ( ErrorCode = = 0 )
2011-12-31 13:00:49 +00:00
return 0 ;
// try disabling fsaa
while ( g_Config . m_GfxFsaaSamples )
{
g_Config . m_GfxFsaaSamples - - ;
if ( g_Config . m_GfxFsaaSamples )
dbg_msg ( " gfx " , " lowering FSAA to %d and trying again " , g_Config . m_GfxFsaaSamples ) ;
else
dbg_msg ( " gfx " , " disabling FSAA and trying again " ) ;
2020-08-22 06:09:10 +00:00
ErrorCode = IssueInit ( ) ;
if ( ErrorCode = = 0 )
2011-12-31 13:00:49 +00:00
return 0 ;
}
2019-04-26 22:11:15 +00:00
2020-08-22 06:09:10 +00:00
size_t OpenGLInitTryCount = 0 ;
while ( ErrorCode = = EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED | | ErrorCode = = EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED )
2017-09-27 10:16:34 +00:00
{
2020-08-22 06:09:10 +00:00
if ( ErrorCode = = EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED )
{
// try next smaller major/minor or patch version
if ( g_Config . m_GfxOpenGLMajor > = 4 )
{
g_Config . m_GfxOpenGLMajor = 3 ;
g_Config . m_GfxOpenGLMinor = 3 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 3 & & g_Config . m_GfxOpenGLMinor > = 1 )
{
g_Config . m_GfxOpenGLMajor = 3 ;
g_Config . m_GfxOpenGLMinor = 0 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 3 & & g_Config . m_GfxOpenGLMinor = = 0 )
{
g_Config . m_GfxOpenGLMajor = 2 ;
g_Config . m_GfxOpenGLMinor = 1 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 2 & & g_Config . m_GfxOpenGLMinor > = 1 )
{
g_Config . m_GfxOpenGLMajor = 2 ;
g_Config . m_GfxOpenGLMinor = 0 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 2 & & g_Config . m_GfxOpenGLMinor = = 0 )
{
g_Config . m_GfxOpenGLMajor = 1 ;
g_Config . m_GfxOpenGLMinor = 5 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 1 & & g_Config . m_GfxOpenGLMinor = = 5 )
{
g_Config . m_GfxOpenGLMajor = 1 ;
g_Config . m_GfxOpenGLMinor = 4 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 1 & & g_Config . m_GfxOpenGLMinor = = 4 )
{
g_Config . m_GfxOpenGLMajor = 1 ;
g_Config . m_GfxOpenGLMinor = 3 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 1 & & g_Config . m_GfxOpenGLMinor = = 3 )
{
g_Config . m_GfxOpenGLMajor = 1 ;
g_Config . m_GfxOpenGLMinor = 2 ;
g_Config . m_GfxOpenGLPatch = 1 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 1 & & g_Config . m_GfxOpenGLMinor = = 2 )
{
g_Config . m_GfxOpenGLMajor = 1 ;
g_Config . m_GfxOpenGLMinor = 1 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
}
// new opengl version was set by backend, try again
ErrorCode = IssueInit ( ) ;
if ( ErrorCode = = 0 )
2017-10-20 20:52:38 +00:00
{
2017-09-27 10:16:34 +00:00
return 0 ;
2017-10-20 20:52:38 +00:00
}
2020-08-22 06:09:10 +00:00
if ( + + OpenGLInitTryCount > = 9 )
{
// try something else
break ;
}
2017-09-27 10:16:34 +00:00
}
2011-12-31 13:00:49 +00:00
// try lowering the resolution
if ( g_Config . m_GfxScreenWidth ! = 640 | | g_Config . m_GfxScreenHeight ! = 480 )
{
dbg_msg ( " gfx " , " setting resolution to 640x480 and trying again " ) ;
g_Config . m_GfxScreenWidth = 640 ;
g_Config . m_GfxScreenHeight = 480 ;
if ( IssueInit ( ) = = 0 )
return 0 ;
}
dbg_msg ( " gfx " , " out of ideas. failed to init graphics " ) ;
return - 1 ;
}
2012-01-03 20:39:10 +00:00
int CGraphics_Threaded : : Init ( )
2011-12-31 00:06:04 +00:00
{
// fetch pointers
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
// init textures
m_FirstFreeTexture = 0 ;
2012-10-06 21:31:02 +00:00
for ( int i = 0 ; i < MAX_TEXTURES - 1 ; i + + )
m_aTextureIndices [ i ] = i + 1 ;
m_aTextureIndices [ MAX_TEXTURES - 1 ] = - 1 ;
2018-03-13 20:47:07 +00:00
m_FirstFreeVertexArrayInfo = - 1 ;
m_FirstFreeBufferObjectIndex = - 1 ;
m_FirstFreeQuadContainer = - 1 ;
2011-12-31 00:06:04 +00:00
2012-01-03 20:39:10 +00:00
m_pBackend = CreateGraphicsBackend ( ) ;
if ( InitWindow ( ) ! = 0 )
return - 1 ;
2011-12-31 00:06:04 +00:00
// create command buffers
2012-01-03 21:01:37 +00:00
for ( int i = 0 ; i < NUM_CMDBUFFERS ; i + + )
2018-03-13 20:47:07 +00:00
m_apCommandBuffers [ i ] = new CCommandBuffer ( CMD_BUFFER_CMD_BUFFER_SIZE , CMD_BUFFER_DATA_BUFFER_SIZE ) ;
2011-12-31 00:06:04 +00:00
m_pCommandBuffer = m_apCommandBuffers [ 0 ] ;
2011-12-31 13:00:49 +00:00
// create null texture, will get id=0
2017-03-21 10:24:44 +00:00
static const unsigned char s_aNullTextureData [ ] = {
2011-12-31 13:00:49 +00:00
0xff , 0x00 , 0x00 , 0xff , 0xff , 0x00 , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff ,
0xff , 0x00 , 0x00 , 0xff , 0xff , 0x00 , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff ,
0x00 , 0x00 , 0xff , 0xff , 0x00 , 0x00 , 0xff , 0xff , 0xff , 0xff , 0x00 , 0xff , 0xff , 0xff , 0x00 , 0xff ,
0x00 , 0x00 , 0xff , 0xff , 0x00 , 0x00 , 0xff , 0xff , 0xff , 0xff , 0x00 , 0xff , 0xff , 0xff , 0x00 , 0xff ,
} ;
2017-03-21 10:24:44 +00:00
m_InvalidTexture = LoadTextureRaw ( 4 , 4 , CImageInfo : : FORMAT_RGBA , s_aNullTextureData , CImageInfo : : FORMAT_RGBA , TEXLOAD_NORESAMPLE ) ;
2011-12-31 13:00:49 +00:00
return 0 ;
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : Shutdown ( )
{
2012-01-03 20:39:10 +00:00
// shutdown the backend
m_pBackend - > Shutdown ( ) ;
delete m_pBackend ;
m_pBackend = 0x0 ;
2012-01-03 21:01:37 +00:00
// delete the command buffers
for ( int i = 0 ; i < NUM_CMDBUFFERS ; i + + )
delete m_apCommandBuffers [ i ] ;
2011-12-31 00:06:04 +00:00
}
2016-04-29 22:34:12 +00:00
int CGraphics_Threaded : : GetNumScreens ( ) const
{
return m_pBackend - > GetNumScreens ( ) ;
}
2011-12-31 00:06:04 +00:00
void CGraphics_Threaded : : Minimize ( )
{
2012-01-03 20:39:10 +00:00
m_pBackend - > Minimize ( ) ;
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : Maximize ( )
{
// TODO: SDL
2012-01-03 20:39:10 +00:00
m_pBackend - > Maximize ( ) ;
2011-12-31 00:06:04 +00:00
}
2016-04-29 19:07:10 +00:00
bool CGraphics_Threaded : : Fullscreen ( bool State )
{
return m_pBackend - > Fullscreen ( State ) ;
}
2016-04-29 22:34:12 +00:00
void CGraphics_Threaded : : SetWindowBordered ( bool State )
{
m_pBackend - > SetWindowBordered ( State ) ;
}
bool CGraphics_Threaded : : SetWindowScreen ( int Index )
{
return m_pBackend - > SetWindowScreen ( Index ) ;
}
2016-04-30 15:59:58 +00:00
void CGraphics_Threaded : : Resize ( int w , int h )
{
2020-06-19 06:19:40 +00:00
# if defined(CONF_VIDEORECORDER)
2020-06-22 21:59:37 +00:00
if ( IVideo : : Current ( ) & & IVideo : : Current ( ) - > IsRecording ( ) )
2020-06-19 06:19:40 +00:00
return ;
# endif
2016-04-30 15:59:58 +00:00
if ( m_ScreenWidth = = w & & m_ScreenHeight = = h )
return ;
if ( h > 4 * w / 5 )
h = 4 * w / 5 ;
if ( w > 21 * h / 9 )
w = 21 * h / 9 ;
m_ScreenWidth = w ;
m_ScreenHeight = h ;
CCommandBuffer : : SCommand_Resize Cmd ;
Cmd . m_Width = w ;
Cmd . m_Height = h ;
m_pCommandBuffer - > AddCommand ( Cmd ) ;
// kick the command buffer
KickCommandBuffer ( ) ;
WaitForIdle ( ) ;
2018-03-21 14:48:48 +00:00
for ( size_t i = 0 ; i < m_ResizeListeners . size ( ) ; + + i )
m_ResizeListeners [ i ] . m_pFunc ( m_ResizeListeners [ i ] . m_pUser ) ;
}
void CGraphics_Threaded : : AddWindowResizeListener ( WINDOW_RESIZE_FUNC pFunc , void * pUser )
{
m_ResizeListeners . push_back ( SWindowResizeListener ( pFunc , pUser ) ) ;
2016-04-30 15:59:58 +00:00
}
2016-04-29 22:34:12 +00:00
int CGraphics_Threaded : : GetWindowScreen ( )
{
return m_pBackend - > GetWindowScreen ( ) ;
}
2011-12-31 00:06:04 +00:00
int CGraphics_Threaded : : WindowActive ( )
{
2012-01-03 20:39:10 +00:00
return m_pBackend - > WindowActive ( ) ;
2011-12-31 00:06:04 +00:00
}
int CGraphics_Threaded : : WindowOpen ( )
{
2012-01-03 20:39:10 +00:00
return m_pBackend - > WindowOpen ( ) ;
2014-10-18 14:17:36 +00:00
}
2011-12-31 00:06:04 +00:00
2015-08-24 23:01:38 +00:00
void CGraphics_Threaded : : SetWindowGrab ( bool Grab )
{
return m_pBackend - > SetWindowGrab ( Grab ) ;
}
2014-10-18 14:17:36 +00:00
void CGraphics_Threaded : : NotifyWindow ( )
{
return m_pBackend - > NotifyWindow ( ) ;
2011-12-31 00:06:04 +00:00
}
void CGraphics_Threaded : : TakeScreenshot ( const char * pFilename )
{
// TODO: screenshot support
char aDate [ 20 ] ;
str_timestamp ( aDate , sizeof ( aDate ) ) ;
str_format ( m_aScreenshotName , sizeof ( m_aScreenshotName ) , " screenshots/%s_%s.png " , pFilename ? pFilename : " screenshot " , aDate ) ;
m_DoScreenshot = true ;
}
2014-01-19 03:02:01 +00:00
void CGraphics_Threaded : : TakeCustomScreenshot ( const char * pFilename )
{
str_copy ( m_aScreenshotName , pFilename , sizeof ( m_aScreenshotName ) ) ;
m_DoScreenshot = true ;
}
2011-12-31 00:06:04 +00:00
void CGraphics_Threaded : : Swap ( )
{
2020-08-29 10:49:45 +00:00
if ( ! m_Warnings . empty ( ) )
{
SGraphicsWarning * pCurWarning = GetCurWarning ( ) ;
if ( pCurWarning - > m_WasShown )
{
m_Warnings . erase ( m_Warnings . begin ( ) ) ;
}
}
2011-12-31 00:06:04 +00:00
// TODO: screenshot support
if ( m_DoScreenshot )
{
2012-03-04 11:46:46 +00:00
if ( WindowActive ( ) )
2014-01-19 03:02:01 +00:00
ScreenshotDirect ( ) ;
2011-12-31 00:06:04 +00:00
m_DoScreenshot = false ;
2012-01-01 13:15:35 +00:00
}
2011-12-31 00:06:04 +00:00
2011-12-31 09:04:46 +00:00
// add swap command
2011-12-31 08:40:11 +00:00
CCommandBuffer : : SCommand_Swap Cmd ;
2012-01-06 13:12:49 +00:00
Cmd . m_Finish = g_Config . m_GfxFinish ;
2011-12-31 08:40:11 +00:00
m_pCommandBuffer - > AddCommand ( Cmd ) ;
2011-12-31 09:04:46 +00:00
2012-01-01 13:15:35 +00:00
// kick the command buffer
KickCommandBuffer ( ) ;
2011-12-31 00:06:04 +00:00
}
2016-04-29 22:34:12 +00:00
bool CGraphics_Threaded : : SetVSync ( bool State )
{
2017-08-31 21:42:21 +00:00
if ( ! m_pCommandBuffer )
return true ;
2016-04-29 22:34:12 +00:00
// add vsnc command
2017-08-31 21:42:21 +00:00
bool RetOk = false ;
2016-04-29 22:34:12 +00:00
CCommandBuffer : : SCommand_VSync Cmd ;
Cmd . m_VSync = State ? 1 : 0 ;
Cmd . m_pRetOk = & RetOk ;
m_pCommandBuffer - > AddCommand ( Cmd ) ;
// kick the command buffer
KickCommandBuffer ( ) ;
WaitForIdle ( ) ;
return RetOk ;
}
2018-02-04 15:00:47 +00:00
// synchronization
2011-12-31 09:04:46 +00:00
void CGraphics_Threaded : : InsertSignal ( semaphore * pSemaphore )
{
CCommandBuffer : : SCommand_Signal Cmd ;
Cmd . m_pSemaphore = pSemaphore ;
m_pCommandBuffer - > AddCommand ( Cmd ) ;
}
bool CGraphics_Threaded : : IsIdle ( )
{
2012-01-03 20:39:10 +00:00
return m_pBackend - > IsIdle ( ) ;
2011-12-31 09:04:46 +00:00
}
void CGraphics_Threaded : : WaitForIdle ( )
{
2012-01-03 20:39:10 +00:00
m_pBackend - > WaitForIdle ( ) ;
2011-12-31 09:04:46 +00:00
}
2011-12-31 00:06:04 +00:00
2020-08-29 10:49:45 +00:00
SGraphicsWarning * CGraphics_Threaded : : GetCurWarning ( )
{
if ( m_Warnings . empty ( ) )
return NULL ;
else
{
SGraphicsWarning * pCurWarning = & m_Warnings [ 0 ] ;
return pCurWarning ;
}
}
2015-08-24 20:46:28 +00:00
int CGraphics_Threaded : : GetVideoModes ( CVideoMode * pModes , int MaxModes , int Screen )
2011-12-31 00:06:04 +00:00
{
2012-01-01 13:30:45 +00:00
if ( g_Config . m_GfxDisplayAllModes )
2011-12-31 00:06:04 +00:00
{
int Count = sizeof ( g_aFakeModes ) / sizeof ( CVideoMode ) ;
mem_copy ( pModes , g_aFakeModes , sizeof ( g_aFakeModes ) ) ;
if ( MaxModes < Count )
Count = MaxModes ;
return Count ;
}
2012-01-01 13:30:45 +00:00
// add videomodes command
CImageInfo Image ;
mem_zero ( & Image , sizeof ( Image ) ) ;
2011-12-31 00:06:04 +00:00
2012-01-01 13:30:45 +00:00
int NumModes = 0 ;
2016-04-29 22:34:12 +00:00
CCommandBuffer : : SCommand_VideoModes Cmd ;
2012-01-01 13:30:45 +00:00
Cmd . m_pModes = pModes ;
Cmd . m_MaxModes = MaxModes ;
Cmd . m_pNumModes = & NumModes ;
2016-04-29 22:34:12 +00:00
Cmd . m_Screen = Screen ;
2012-01-01 13:30:45 +00:00
m_pCommandBuffer - > AddCommand ( Cmd ) ;
2011-12-31 00:06:04 +00:00
2012-01-01 13:30:45 +00:00
// kick the buffer and wait for the result and return it
KickCommandBuffer ( ) ;
WaitForIdle ( ) ;
return NumModes ;
2011-12-31 00:06:04 +00:00
}
2011-12-31 09:29:25 +00:00
extern IEngineGraphics * CreateEngineGraphicsThreaded ( ) { return new CGraphics_Threaded ( ) ; }