2009-02-09 21:15:56 +00:00
/*
* Copyright ( C ) 2007 - 2009 Gabest
* http : //www.gabest.org
*
* This Program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This Program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# pragma once
# include "GSWnd.h"
# include "GSState.h"
# include "GSVertexList.h"
# include "GSSettingsDlg.h"
# include "GSCapture.h"
struct GSRendererSettings
{
int m_interlace ;
int m_aspectratio ;
int m_filter ;
bool m_vsync ;
bool m_nativeres ;
2009-03-09 01:42:56 +00:00
bool m_aa1 ;
2009-02-09 21:15:56 +00:00
} ;
class GSRendererBase : public GSState , protected GSRendererSettings
{
protected :
bool m_osd ;
void ProcessWindowMessages ( )
{
MSG msg ;
memset ( & msg , 0 , sizeof ( msg ) ) ;
while ( msg . message ! = WM_QUIT & & PeekMessage ( & msg , NULL , 0 , 0 , PM_REMOVE ) )
{
if ( OnMessage ( msg ) )
{
continue ;
}
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
}
virtual bool OnMessage ( const MSG & msg )
{
if ( msg . message = = WM_KEYDOWN )
{
int step = ( : : GetAsyncKeyState ( VK_SHIFT ) & 0x8000 ) ? - 1 : 1 ;
if ( msg . wParam = = VK_F5 )
{
m_interlace = ( m_interlace + 7 + step ) % 7 ;
return true ;
}
if ( msg . wParam = = VK_F6 )
{
m_aspectratio = ( m_aspectratio + 3 + step ) % 3 ;
return true ;
}
if ( msg . wParam = = VK_F7 )
{
m_wnd . SetWindowText ( _T ( " PCSX2 " ) ) ;
m_osd = ! m_osd ;
return true ;
}
2009-03-09 01:42:56 +00:00
if ( msg . wParam = = VK_DELETE )
{
m_aa1 = ! m_aa1 ;
return true ;
}
2009-02-09 21:15:56 +00:00
}
return false ;
}
public :
GSWnd m_wnd ;
public :
GSRendererBase ( BYTE * base , bool mt , void ( * irq ) ( ) , int nloophack , const GSRendererSettings & rs )
: GSState ( base , mt , irq , nloophack )
, m_osd ( true )
{
m_interlace = rs . m_interlace ;
m_aspectratio = rs . m_aspectratio ;
m_filter = rs . m_filter ;
m_vsync = rs . m_vsync ;
m_nativeres = rs . m_nativeres ;
2009-03-09 01:42:56 +00:00
m_aa1 = rs . m_aa1 ;
2009-02-09 21:15:56 +00:00
} ;
virtual bool Create ( LPCTSTR title ) = 0 ;
virtual void VSync ( int field ) = 0 ;
virtual bool MakeSnapshot ( LPCTSTR path ) = 0 ;
} ;
template < class Device > class GSRenderer : public GSRendererBase
{
protected :
typedef typename Device : : Texture Texture ;
virtual void ResetDevice ( ) { }
virtual bool GetOutput ( int i , Texture & t ) = 0 ;
2009-03-22 13:10:31 +00:00
bool Merge ( int field )
2009-02-09 21:15:56 +00:00
{
2009-03-20 09:10:37 +00:00
bool en [ 2 ] ;
CRect fr [ 2 ] ;
CRect dr [ 2 ] ;
2009-02-09 21:15:56 +00:00
int baseline = INT_MAX ;
for ( int i = 0 ; i < 2 ; i + + )
{
2009-03-20 09:10:37 +00:00
en [ i ] = IsEnabled ( i ) ;
if ( en [ i ] )
2009-02-09 21:15:56 +00:00
{
2009-03-20 09:10:37 +00:00
fr [ i ] = GetFrameRect ( i ) ;
dr [ i ] = GetDisplayRect ( i ) ;
baseline = min ( dr [ i ] . top , baseline ) ;
2009-03-22 13:10:31 +00:00
// printf("[%d]: %d %d %d %d, %d %d %d %d\n", i, fr[i], dr[i]);
2009-03-20 09:10:37 +00:00
}
}
// try to avoid fullscreen blur, could be nice on tv but on a monitor it's like double vision, hurts my eyes (persona 4, guitar hero)
//
// NOTE: probably the technique explained in graphtip.pdf (Antialiasing by Supersampling / 4. Reading Odd/Even Scan Lines Separately with the PCRTC then Blending)
if ( en [ 0 ] & & en [ 1 ] & & PMODE - > SLBG = = 0 & & PMODE - > MMOD = = 1 & & PMODE - > ALP = = 0x80 )
{
if ( DISPFB [ 0 ] - > FBP = = DISPFB [ 1 ] - > FBP
& & DISPFB [ 0 ] - > FBW = = DISPFB [ 1 ] - > FBW
& & DISPFB [ 0 ] - > PSM = = DISPFB [ 1 ] - > PSM )
{
2009-03-22 13:10:31 +00:00
if ( fr [ 0 ] = = fr [ 1 ] + CRect ( 0 , 1 , 0 , 0 ) & & dr [ 0 ] = = dr [ 1 ] + CRect ( 0 , 0 , 0 , 1 )
| | fr [ 1 ] = = fr [ 0 ] + CRect ( 0 , 1 , 0 , 0 ) & & dr [ 1 ] = = dr [ 0 ] + CRect ( 0 , 0 , 0 , 1 ) )
2009-03-20 09:10:37 +00:00
{
2009-03-22 13:10:31 +00:00
// persona 4:
2009-03-20 09:10:37 +00:00
//
// fr[0] = 0, 0, 640, 448 (y = 0, height = 448)
// fr[1] = 0, 1, 640, 448 (y = 1, height = 447)
// dr[0] = 159, 50, 779, 498 (y = 50, height = 448)
// dr[1] = 159, 50, 779, 497 (y = 50, height = 447)
//
// second image shifted up by 1 pixel and blended over itself
2009-03-22 13:10:31 +00:00
//
// god of war:
//
// fr[0] = 0 1 512 448
// fr[1] = 0 0 512 448
// dr[0] = 127 50 639 497
// dr[1] = 127 50 639 498
//
// same just the first image shifted
2009-03-20 09:10:37 +00:00
2009-03-22 13:10:31 +00:00
int top = min ( fr [ 0 ] . top , fr [ 1 ] . top ) ;
int bottom = max ( dr [ 0 ] . bottom , dr [ 1 ] . bottom ) ;
fr [ 0 ] . top = top ;
fr [ 1 ] . top = top ;
dr [ 0 ] . bottom = bottom ;
dr [ 1 ] . bottom = bottom ;
}
else if ( dr [ 0 ] = = dr [ 1 ] & & ( fr [ 0 ] = = fr [ 1 ] + CPoint ( 0 , 1 ) | | fr [ 1 ] = = fr [ 0 ] + CPoint ( 0 , 1 ) ) )
{
// dq5:
//
// fr[0] = 0 1 512 445
// fr[1] = 0 0 512 444
// dr[0] = 127 50 639 494
// dr[1] = 127 50 639 494
int top = min ( fr [ 0 ] . top , fr [ 1 ] . top ) ;
int bottom = min ( fr [ 0 ] . bottom , fr [ 1 ] . bottom ) ;
fr [ 0 ] . top = fr [ 1 ] . top = top ;
fr [ 0 ] . bottom = fr [ 1 ] . bottom = bottom ;
2009-03-20 09:10:37 +00:00
}
2009-02-09 21:15:56 +00:00
}
}
CSize fs ( 0 , 0 ) ;
CSize ds ( 0 , 0 ) ;
2009-03-20 09:10:37 +00:00
Texture tex [ 2 ] ;
GSVector4 src [ 2 ] ;
GSVector4 dst [ 2 ] ;
2009-02-09 21:15:56 +00:00
for ( int i = 0 ; i < 2 ; i + + )
{
2009-03-20 09:10:37 +00:00
if ( ! en [ i ] | | ! GetOutput ( i , tex [ i ] ) )
2009-02-09 21:15:56 +00:00
{
2009-03-20 09:10:37 +00:00
continue ;
}
2009-02-09 21:15:56 +00:00
2009-03-20 09:10:37 +00:00
CRect r = fr [ i ] ;
2009-02-09 21:15:56 +00:00
2009-03-20 09:10:37 +00:00
// overscan hack
2009-02-09 21:15:56 +00:00
2009-03-20 09:10:37 +00:00
if ( dr [ i ] . Height ( ) > 512 ) // hmm
{
int y = GetDeviceSize ( i ) . cy ;
if ( SMODE2 - > INT & & SMODE2 - > FFMD ) y / = 2 ;
r . bottom = r . top + y ;
}
2009-02-09 21:15:56 +00:00
2009-03-20 09:10:37 +00:00
//
2009-02-09 21:15:56 +00:00
2009-03-20 09:10:37 +00:00
src [ i ] . x = tex [ i ] . m_scale . x * r . left / tex [ i ] . GetWidth ( ) ;
src [ i ] . y = tex [ i ] . m_scale . y * r . top / tex [ i ] . GetHeight ( ) ;
src [ i ] . z = tex [ i ] . m_scale . x * r . right / tex [ i ] . GetWidth ( ) ;
src [ i ] . w = tex [ i ] . m_scale . y * r . bottom / tex [ i ] . GetHeight ( ) ;
2009-02-09 21:15:56 +00:00
2009-03-20 09:10:37 +00:00
GSVector2 o ;
2009-02-09 21:15:56 +00:00
2009-03-20 09:10:37 +00:00
o . x = 0 ;
o . y = 0 ;
if ( dr [ i ] . top - baseline > = 4 ) // 2?
{
o . y = tex [ i ] . m_scale . y * ( dr [ i ] . top - baseline ) ;
2009-02-09 21:15:56 +00:00
}
2009-03-20 09:10:37 +00:00
if ( SMODE2 - > INT & & SMODE2 - > FFMD ) o . y / = 2 ;
dst [ i ] . x = o . x ;
dst [ i ] . y = o . y ;
dst [ i ] . z = o . x + tex [ i ] . m_scale . x * r . Width ( ) ;
dst [ i ] . w = o . y + tex [ i ] . m_scale . y * r . Height ( ) ;
fs . cx = max ( fs . cx , ( int ) ( dst [ i ] . z + 0.5f ) ) ;
fs . cy = max ( fs . cy , ( int ) ( dst [ i ] . w + 0.5f ) ) ;
2009-02-09 21:15:56 +00:00
}
ds . cx = fs . cx ;
ds . cy = fs . cy ;
if ( SMODE2 - > INT & & SMODE2 - > FFMD ) ds . cy * = 2 ;
bool slbg = PMODE - > SLBG ;
bool mmod = PMODE - > MMOD ;
2009-03-20 09:10:37 +00:00
if ( tex [ 0 ] | | tex [ 1 ] )
2009-02-09 21:15:56 +00:00
{
GSVector4 c ;
c . r = ( float ) BGCOLOR - > R / 255 ;
c . g = ( float ) BGCOLOR - > G / 255 ;
c . b = ( float ) BGCOLOR - > B / 255 ;
c . a = ( float ) PMODE - > ALP / 255 ;
2009-03-20 09:10:37 +00:00
m_dev . Merge ( tex , src , dst , fs , slbg , mmod , c ) ;
2009-02-09 21:15:56 +00:00
if ( SMODE2 - > INT & & m_interlace > 0 )
{
2009-03-22 13:10:31 +00:00
int field2 = 1 - ( ( m_interlace - 1 ) & 1 ) ;
2009-02-09 21:15:56 +00:00
int mode = ( m_interlace - 1 ) > > 1 ;
2009-03-22 13:10:31 +00:00
if ( ! m_dev . Interlace ( ds , field ^ field2 , mode , tex [ 1 ] . m_scale . y ) )
2009-02-09 21:15:56 +00:00
{
return false ;
}
}
}
return true ;
}
2009-03-22 13:10:31 +00:00
void DoSnapshot ( int field )
{
if ( ! m_snapshot . IsEmpty ( ) )
{
if ( ! m_dump & & ( : : GetAsyncKeyState ( VK_SHIFT ) & 0x8000 ) )
{
GSFreezeData fd ;
fd . size = 0 ;
fd . data = NULL ;
Freeze ( & fd , true ) ;
fd . data = new BYTE [ fd . size ] ;
Freeze ( & fd , false ) ;
m_dump . Open ( m_snapshot , m_crc , fd , PMODE ) ;
delete [ ] fd . data ;
}
m_dev . SaveCurrent ( m_snapshot + _T ( " .bmp " ) ) ;
m_snapshot . Empty ( ) ;
}
else
{
if ( m_dump )
{
m_dump . VSync ( field , ! ( : : GetAsyncKeyState ( VK_CONTROL ) & 0x8000 ) , PMODE ) ;
}
}
}
2009-02-09 21:15:56 +00:00
void DoCapture ( )
{
if ( ! m_capture . IsCapturing ( ) )
{
return ;
}
CSize size = m_capture . GetSize ( ) ;
Texture current ;
m_dev . GetCurrent ( current ) ;
Texture offscreen ;
if ( m_dev . CopyOffscreen ( current , GSVector4 ( 0 , 0 , 1 , 1 ) , offscreen , size . cx , size . cy ) )
{
BYTE * bits = NULL ;
int pitch = 0 ;
if ( offscreen . Map ( & bits , pitch ) )
{
m_capture . DeliverFrame ( bits , pitch , m_dev . IsCurrentRGBA ( ) ) ;
offscreen . Unmap ( ) ;
}
m_dev . Recycle ( offscreen ) ;
}
}
virtual bool OnMessage ( const MSG & msg )
{
if ( msg . message = = WM_KEYDOWN )
{
if ( msg . wParam = = VK_F12 )
{
if ( m_capture . IsCapturing ( ) )
{
m_capture . EndCapture ( ) ;
}
else
{
m_capture . BeginCapture ( GetFPS ( ) ) ;
}
return true ;
}
}
return __super : : OnMessage ( msg ) ;
}
public :
Device m_dev ;
bool m_psrr ;
int s_n ;
bool s_dump ;
bool s_save ;
bool s_savez ;
2009-03-22 13:10:31 +00:00
CString m_snapshot ;
2009-02-09 21:15:56 +00:00
GSCapture m_capture ;
public :
GSRenderer ( BYTE * base , bool mt , void ( * irq ) ( ) , int nloophack , const GSRendererSettings & rs , bool psrr )
: GSRendererBase ( base , mt , irq , nloophack , rs )
, m_psrr ( psrr )
{
s_n = 0 ;
s_dump = ! ! AfxGetApp ( ) - > GetProfileInt ( _T ( " Debug " ) , _T ( " dump " ) , 0 ) ;
s_save = ! ! AfxGetApp ( ) - > GetProfileInt ( _T ( " Debug " ) , _T ( " save " ) , 0 ) ;
s_savez = ! ! AfxGetApp ( ) - > GetProfileInt ( _T ( " Debug " ) , _T ( " savez " ) , 0 ) ;
}
bool Create ( LPCTSTR title )
{
if ( ! m_wnd . Create ( title ) )
{
return false ;
}
if ( ! m_dev . Create ( m_wnd , m_vsync ) )
{
return false ;
}
Reset ( ) ;
return true ;
}
void VSync ( int field )
{
GSPerfMonAutoTimer pmat ( m_perfmon ) ;
Flush ( ) ;
m_perfmon . Put ( GSPerfMon : : Frame ) ;
ProcessWindowMessages ( ) ;
2009-03-22 13:10:31 +00:00
field = field ? 1 : 0 ;
2009-02-09 21:15:56 +00:00
2009-03-22 13:10:31 +00:00
if ( ! Merge ( field ) ) return ;
2009-02-09 21:15:56 +00:00
// osd
static UINT64 s_frame = 0 ;
static CString s_stats ;
if ( m_perfmon . GetFrame ( ) - s_frame > = 30 )
{
m_perfmon . Update ( ) ;
s_frame = m_perfmon . GetFrame ( ) ;
double fps = 1000.0f / m_perfmon . Get ( GSPerfMon : : Frame ) ;
s_stats . Format (
_T ( " %I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f " ) ,
m_perfmon . GetFrame ( ) , GetDisplaySize ( ) . cx , GetDisplaySize ( ) . cy , fps , ( int ) ( 100.0 * fps / GetFPS ( ) ) ,
SMODE2 - > INT ? ( CString ( _T ( " Interlaced " ) ) + ( SMODE2 - > FFMD ? _T ( " (frame) " ) : _T ( " (field) " ) ) ) : _T ( " Progressive " ) ,
GSSettingsDlg : : g_interlace [ m_interlace ] . name ,
GSSettingsDlg : : g_aspectratio [ m_aspectratio ] . name ,
( int ) m_perfmon . Get ( GSPerfMon : : Quad ) ,
( int ) m_perfmon . Get ( GSPerfMon : : Prim ) ,
( int ) m_perfmon . Get ( GSPerfMon : : Draw ) ,
m_perfmon . CPU ( ) ,
m_perfmon . Get ( GSPerfMon : : Swizzle ) / 1024 ,
m_perfmon . Get ( GSPerfMon : : Unswizzle ) / 1024
) ;
double fillrate = m_perfmon . Get ( GSPerfMon : : Fillrate ) ;
if ( fillrate > 0 )
{
s_stats . Format ( _T ( " %s | %.2f mpps " ) , CString ( s_stats ) , fps * fillrate / ( 1024 * 1024 ) ) ;
}
if ( m_capture . IsCapturing ( ) )
{
s_stats + = _T ( " | Recording... " ) ;
}
if ( m_perfmon . Get ( GSPerfMon : : COLCLAMP ) ) _tprintf ( _T ( " *** NOT SUPPORTED: color wrap *** \n " ) ) ;
if ( m_perfmon . Get ( GSPerfMon : : PABE ) ) _tprintf ( _T ( " *** NOT SUPPORTED: per pixel alpha blend *** \n " ) ) ;
if ( m_perfmon . Get ( GSPerfMon : : DATE ) ) _tprintf ( _T ( " *** PERFORMANCE WARNING: destination alpha test used *** \n " ) ) ;
if ( m_perfmon . Get ( GSPerfMon : : ABE ) ) _tprintf ( _T ( " *** NOT SUPPORTED: alpha blending mode *** \n " ) ) ;
if ( m_perfmon . Get ( GSPerfMon : : DepthTexture ) ) _tprintf ( _T ( " *** NOT SUPPORTED: depth texture *** \n " ) ) ;
m_wnd . SetWindowText ( s_stats ) ;
}
if ( m_osd )
{
m_dev . Draw ( s_stats + _T ( " \n \n F5: interlace mode \n F6: aspect ratio \n F7: OSD " ) ) ;
}
if ( m_frameskip )
{
return ;
}
//
if ( m_dev . IsLost ( ) )
{
ResetDevice ( ) ;
}
//
CRect r ;
m_wnd . GetClientRect ( & r ) ;
GSUtil : : FitRect ( r , m_aspectratio ) ;
m_dev . Present ( r ) ;
2009-03-22 13:10:31 +00:00
//
DoSnapshot ( field ) ;
2009-02-09 21:15:56 +00:00
DoCapture ( ) ;
}
bool MakeSnapshot ( LPCTSTR path )
{
2009-03-22 13:10:31 +00:00
if ( m_snapshot . IsEmpty ( ) )
2009-02-09 21:15:56 +00:00
{
2009-03-22 13:10:31 +00:00
m_snapshot . Format ( _T ( " %s_%s " ) , path , CTime : : GetCurrentTime ( ) . Format ( _T ( " %Y%m%d%H%M%S " ) ) ) ;
2009-02-09 21:15:56 +00:00
}
2009-03-22 13:10:31 +00:00
return true ;
2009-02-09 21:15:56 +00:00
}
virtual void MinMaxUV ( int w , int h , CRect & r ) { r = CRect ( 0 , 0 , w , h ) ; }
virtual bool CanUpscale ( ) { return ! m_nativeres ; }
} ;
template < class Device , class Vertex > class GSRendererT : public GSRenderer < Device >
{
protected :
Vertex * m_vertices ;
int m_count ;
int m_maxcount ;
GSVertexList < Vertex > m_vl ;
void Reset ( )
{
m_count = 0 ;
m_vl . RemoveAll ( ) ;
__super : : Reset ( ) ;
}
void ResetPrim ( )
{
m_vl . RemoveAll ( ) ;
}
void FlushPrim ( )
{
if ( m_count > 0 )
{
/*
TRACE ( _T ( " [%d] Draw f %05x (%d) z %05x (%d %d %d %d) t %05x %05x (%d) \n " ) ,
( int ) m_perfmon . GetFrame ( ) ,
( int ) m_context - > FRAME . Block ( ) ,
( int ) m_context - > FRAME . PSM ,
( int ) m_context - > ZBUF . Block ( ) ,
( int ) m_context - > ZBUF . PSM ,
m_context - > TEST . ZTE ,
m_context - > TEST . ZTST ,
m_context - > ZBUF . ZMSK ,
PRIM - > TME ? ( int ) m_context - > TEX0 . TBP0 : 0xfffff ,
PRIM - > TME & & m_context - > TEX0 . PSM > PSM_PSMCT16S ? ( int ) m_context - > TEX0 . CBP : 0xfffff ,
PRIM - > TME ? ( int ) m_context - > TEX0 . PSM : 0xff ) ;
*/
if ( GSUtil : : EncodePSM ( m_context - > FRAME . PSM ) ! = 3 & & GSUtil : : EncodePSM ( m_context - > ZBUF . PSM ) ! = 3 )
{
// FIXME: berserk fpsm = 27 (8H)
Draw ( ) ;
}
m_count = 0 ;
}
}
void GrowVertexBuffer ( )
{
m_maxcount = max ( 10000 , m_maxcount * 3 / 2 ) ;
m_vertices = ( Vertex * ) _aligned_realloc ( m_vertices , sizeof ( Vertex ) * m_maxcount , 16 ) ;
m_maxcount - = 100 ;
}
template < DWORD prim > __forceinline Vertex * DrawingKick ( bool skip , DWORD & count )
{
switch ( prim )
{
case GS_POINTLIST : count = 1 ; break ;
case GS_LINELIST : count = 2 ; break ;
case GS_LINESTRIP : count = 2 ; break ;
case GS_TRIANGLELIST : count = 3 ; break ;
case GS_TRIANGLESTRIP : count = 3 ; break ;
case GS_TRIANGLEFAN : count = 3 ; break ;
case GS_SPRITE : count = 2 ; break ;
case GS_INVALID : count = 1 ; break ;
default : __assume ( 0 ) ;
}
if ( m_vl . GetCount ( ) < count )
{
return NULL ;
}
if ( m_count > = m_maxcount )
{
GrowVertexBuffer ( ) ;
}
Vertex * v = & m_vertices [ m_count ] ;
switch ( prim )
{
case GS_POINTLIST :
m_vl . GetAt ( 0 , v [ 0 ] ) ;
m_vl . RemoveAll ( ) ;
break ;
case GS_LINELIST :
m_vl . GetAt ( 0 , v [ 0 ] ) ;
m_vl . GetAt ( 1 , v [ 1 ] ) ;
m_vl . RemoveAll ( ) ;
break ;
case GS_LINESTRIP :
m_vl . GetAt ( 0 , v [ 0 ] ) ;
m_vl . GetAt ( 1 , v [ 1 ] ) ;
m_vl . RemoveAt ( 0 , 1 ) ;
break ;
case GS_TRIANGLELIST :
m_vl . GetAt ( 0 , v [ 0 ] ) ;
m_vl . GetAt ( 1 , v [ 1 ] ) ;
m_vl . GetAt ( 2 , v [ 2 ] ) ;
m_vl . RemoveAll ( ) ;
break ;
case GS_TRIANGLESTRIP :
m_vl . GetAt ( 0 , v [ 0 ] ) ;
m_vl . GetAt ( 1 , v [ 1 ] ) ;
m_vl . GetAt ( 2 , v [ 2 ] ) ;
m_vl . RemoveAt ( 0 , 2 ) ;
break ;
case GS_TRIANGLEFAN :
m_vl . GetAt ( 0 , v [ 0 ] ) ;
m_vl . GetAt ( 1 , v [ 1 ] ) ;
m_vl . GetAt ( 2 , v [ 2 ] ) ;
m_vl . RemoveAt ( 1 , 1 ) ;
break ;
case GS_SPRITE :
m_vl . GetAt ( 0 , v [ 0 ] ) ;
m_vl . GetAt ( 1 , v [ 1 ] ) ;
m_vl . RemoveAll ( ) ;
break ;
case GS_INVALID :
ASSERT ( 0 ) ;
m_vl . RemoveAll ( ) ;
return NULL ;
default :
__assume ( 0 ) ;
}
return ! skip ? v : NULL ;
}
virtual void Draw ( ) = 0 ;
public :
GSRendererT ( BYTE * base , bool mt , void ( * irq ) ( ) , int nloophack , const GSRendererSettings & rs , bool psrr = true )
: GSRenderer < Device > ( base , mt , irq , nloophack , rs , psrr )
, m_count ( 0 )
, m_maxcount ( 0 )
, m_vertices ( NULL )
{
}
~ GSRendererT ( )
{
if ( m_vertices ) _aligned_free ( m_vertices ) ;
}
} ;