2017-01-10 15:22:32 +00:00
# include <algorithm>
# include <assert.h>
# include "Graphics/Context.h"
# include "Graphics/Parameters.h"
# include "DisplayWindow.h"
# include "SoftwareRender.h"
2017-01-11 06:08:05 +00:00
# include "GraphicsDrawer.h"
2017-01-11 10:07:20 +00:00
# include "Performance.h"
2017-01-14 15:11:19 +00:00
# include "TextureFilterHandler.h"
# include "PostProcessor.h"
# include "NoiseTexture.h"
# include "ZlutTexture.h"
# include "PaletteTexture.h"
# include "FrameBuffer.h"
# include "DepthBuffer.h"
# include "FrameBufferInfo.h"
# include "Config.h"
# include "RSP.h"
# include "RDP.h"
# include "VI.h"
2017-01-10 15:22:32 +00:00
using namespace graphics ;
2017-01-11 06:08:05 +00:00
GraphicsDrawer : : GraphicsDrawer ( )
2017-01-10 14:58:09 +00:00
: m_modifyVertices ( 0 )
, m_bImageTexture ( false )
, m_bFlatColors ( false )
{
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : addTriangle ( int _v0 , int _v1 , int _v2 )
2017-01-10 15:22:32 +00:00
{
const u32 firstIndex = triangles . num ;
triangles . elements [ triangles . num + + ] = _v0 ;
triangles . elements [ triangles . num + + ] = _v1 ;
triangles . elements [ triangles . num + + ] = _v2 ;
triangles . maxElement = std : : max ( triangles . maxElement , _v0 ) ;
triangles . maxElement = std : : max ( triangles . maxElement , _v1 ) ;
triangles . maxElement = std : : max ( triangles . maxElement , _v2 ) ;
m_modifyVertices | = triangles . vertices [ _v0 ] . modify |
triangles . vertices [ _v1 ] . modify |
triangles . vertices [ _v2 ] . modify ;
if ( ( gSP . geometryMode & G_LIGHTING ) = = 0 ) {
if ( ( gSP . geometryMode & G_SHADE ) = = 0 ) {
// Prim shading
for ( u32 i = firstIndex ; i < triangles . num ; + + i ) {
SPVertex & vtx = triangles . vertices [ triangles . elements [ i ] ] ;
vtx . flat_r = gDP . primColor . r ;
vtx . flat_g = gDP . primColor . g ;
vtx . flat_b = gDP . primColor . b ;
vtx . flat_a = gDP . primColor . a ;
}
}
else if ( ( gSP . geometryMode & G_SHADING_SMOOTH ) = = 0 ) {
// Flat shading
SPVertex & vtx0 = triangles . vertices [ triangles . elements [ firstIndex + ( ( RSP . w1 > > 24 ) & 3 ) ] ] ;
for ( u32 i = firstIndex ; i < triangles . num ; + + i ) {
SPVertex & vtx = triangles . vertices [ triangles . elements [ i ] ] ;
vtx . r = vtx . flat_r = vtx0 . r ;
vtx . g = vtx . flat_g = vtx0 . g ;
vtx . b = vtx . flat_b = vtx0 . b ;
vtx . a = vtx . flat_a = vtx0 . a ;
}
}
}
if ( gDP . otherMode . depthSource = = G_ZS_PRIM ) {
for ( u32 i = firstIndex ; i < triangles . num ; + + i ) {
SPVertex & vtx = triangles . vertices [ triangles . elements [ i ] ] ;
vtx . z = gDP . primDepth . z * vtx . w ;
}
}
if ( ! gfxContext . isSupported ( SpecialFeatures : : NearPlaneClipping ) ) {
if ( GBI . isNoN ( ) & & gDP . otherMode . depthCompare = = 0 & & gDP . otherMode . depthUpdate = = 0 ) {
for ( u32 i = firstIndex ; i < triangles . num ; + + i ) {
SPVertex & vtx = triangles . vertices [ triangles . elements [ i ] ] ;
vtx . z = 0.0f ;
}
}
}
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _updateCullFace ( ) const
2017-01-10 15:22:32 +00:00
{
if ( gSP . geometryMode & G_CULL_BOTH ) {
gfxContext . enable ( enable : : CULL_FACE , true ) ;
if ( gSP . geometryMode & G_CULL_BACK )
gfxContext . cullFace ( cullMode : : BACK ) ;
else
gfxContext . cullFace ( cullMode : : FRONT ) ;
} else
gfxContext . enable ( enable : : CULL_FACE , false ) ;
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _updateDepthUpdate ( ) const
2017-01-10 15:22:32 +00:00
{
gfxContext . enableDepthWrite ( gDP . otherMode . depthUpdate ! = 0 ) ;
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _updateDepthCompare ( ) const
2017-01-10 15:22:32 +00:00
{
if ( config . frameBufferEmulation . N64DepthCompare ! = 0 ) {
gfxContext . enable ( enable : : DEPTH_TEST , false ) ;
gfxContext . enableDepthWrite ( false ) ;
}
else if ( ( gDP . changed & ( CHANGED_RENDERMODE | CHANGED_CYCLETYPE ) ) ! = 0 ) {
if ( ( ( gSP . geometryMode & G_ZBUFFER ) | | gDP . otherMode . depthSource = = G_ZS_PRIM ) & & gDP . otherMode . cycleType < = G_CYC_2CYCLE ) {
if ( gDP . otherMode . depthCompare ! = 0 ) {
switch ( gDP . otherMode . depthMode ) {
case ZMODE_INTER :
gfxContext . enable ( enable : : POLYGON_OFFSET_FILL , false ) ;
gfxContext . setDepthCompare ( compare : : LEQUAL ) ;
break ;
case ZMODE_OPA :
case ZMODE_XLU :
// Max || Infront;
gfxContext . enable ( enable : : POLYGON_OFFSET_FILL , false ) ;
if ( gDP . otherMode . depthSource = = G_ZS_PRIM & & gDP . primDepth . z = = 1.0f )
// Max
gfxContext . setDepthCompare ( compare : : LEQUAL ) ;
else
// Infront
gfxContext . setDepthCompare ( compare : : LESS ) ;
break ;
case ZMODE_DEC :
gfxContext . enable ( enable : : POLYGON_OFFSET_FILL , true ) ;
gfxContext . setDepthCompare ( compare : : LEQUAL ) ;
break ;
}
} else {
gfxContext . enable ( enable : : POLYGON_OFFSET_FILL , false ) ;
gfxContext . setDepthCompare ( compare : : ALWAYS ) ;
}
_updateDepthUpdate ( ) ;
gfxContext . enable ( enable : : DEPTH_TEST , true ) ;
if ( ! GBI . isNoN ( ) )
gfxContext . enable ( enable : : DEPTH_CLAMP , false ) ;
} else {
gfxContext . enable ( enable : : DEPTH_TEST , false ) ;
if ( ! GBI . isNoN ( ) )
gfxContext . enable ( enable : : DEPTH_CLAMP , true ) ;
}
}
}
inline
bool _needAdjustCoordinate ( DisplayWindow & _wnd )
{
return _wnd . isAdjustScreen ( ) & &
gSP . viewport . width < gDP . colorImage . width & &
u32 ( gSP . viewport . width + gSP . viewport . x * 2.0f ) ! = gDP . colorImage . width & &
gDP . colorImage . width > VI . width * 98 / 100 ;
}
inline
void _adjustScissorX ( f32 & _X0 , f32 & _X1 , float _scale )
{
const float halfX = gDP . colorImage . width / 2.0f ;
_X0 = ( _X0 - halfX ) * _scale + halfX ;
_X1 = ( _X1 - halfX ) * _scale + halfX ;
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : updateScissor ( FrameBuffer * _pBuffer ) const
2017-01-10 15:22:32 +00:00
{
DisplayWindow & wnd = DisplayWindow : : get ( ) ;
f32 scaleX , scaleY ;
u32 heightOffset , screenHeight ;
if ( _pBuffer = = nullptr ) {
scaleX = wnd . getScaleX ( ) ;
scaleY = wnd . getScaleY ( ) ;
heightOffset = wnd . getHeightOffset ( ) ;
screenHeight = VI . height ;
} else {
scaleX = _pBuffer - > m_scaleX ;
scaleY = _pBuffer - > m_scaleY ;
heightOffset = 0 ;
screenHeight = ( _pBuffer - > m_height = = 0 ) ? VI . height : _pBuffer - > m_height ;
}
f32 SX0 = gDP . scissor . ulx ;
f32 SX1 = gDP . scissor . lrx ;
if ( _needAdjustCoordinate ( wnd ) )
_adjustScissorX ( SX0 , SX1 , wnd . getAdjustScale ( ) ) ;
gfxContext . setScissor ( ( s32 ) ( SX0 * scaleX ) , ( s32 ) ( ( screenHeight - gDP . scissor . lry ) * scaleY + heightOffset ) ,
std : : max ( ( s32 ) ( ( SX1 - SX0 ) * scaleX ) , 0 ) , std : : max ( ( s32 ) ( ( gDP . scissor . lry - gDP . scissor . uly ) * scaleY ) , 0 ) ) ;
gDP . changed & = ~ CHANGED_SCISSOR ;
}
inline
float _adjustViewportX ( f32 _X0 )
{
const f32 halfX = gDP . colorImage . width / 2.0f ;
const f32 halfVP = gSP . viewport . width / 2.0f ;
2017-01-15 07:57:25 +00:00
return ( _X0 + halfVP - halfX ) * dwnd ( ) . getAdjustScale ( ) + halfX - halfVP ;
2017-01-10 15:22:32 +00:00
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _updateViewport ( ) const
2017-01-10 15:22:32 +00:00
{
DisplayWindow & wnd = DisplayWindow : : get ( ) ;
FrameBuffer * pCurrentBuffer = frameBufferList ( ) . getCurrent ( ) ;
if ( pCurrentBuffer = = nullptr ) {
const f32 scaleX = wnd . getScaleX ( ) ;
const f32 scaleY = wnd . getScaleY ( ) ;
float Xf = gSP . viewport . vscale [ 0 ] < 0 ? ( gSP . viewport . x + gSP . viewport . vscale [ 0 ] * 2.0f ) : gSP . viewport . x ;
if ( _needAdjustCoordinate ( wnd ) )
Xf = _adjustViewportX ( Xf ) ;
const s32 X = ( s32 ) ( Xf * scaleX ) ;
const s32 Y = gSP . viewport . vscale [ 1 ] < 0 ? ( s32 ) ( ( gSP . viewport . y + gSP . viewport . vscale [ 1 ] * 2.0f ) * scaleY ) : ( s32 ) ( ( VI . height - ( gSP . viewport . y + gSP . viewport . height ) ) * scaleY ) ;
gfxContext . setViewport ( X , Y + wnd . getHeightOffset ( ) ,
std : : max ( ( s32 ) ( gSP . viewport . width * scaleX ) , 0 ) , std : : max ( ( s32 ) ( gSP . viewport . height * scaleY ) , 0 ) ) ;
} else {
const f32 scaleX = pCurrentBuffer - > m_scaleX ;
const f32 scaleY = pCurrentBuffer - > m_scaleY ;
float Xf = gSP . viewport . vscale [ 0 ] < 0 ? ( gSP . viewport . x + gSP . viewport . vscale [ 0 ] * 2.0f ) : gSP . viewport . x ;
if ( _needAdjustCoordinate ( wnd ) )
Xf = _adjustViewportX ( Xf ) ;
const s32 X = ( s32 ) ( Xf * scaleX ) ;
const s32 Y = gSP . viewport . vscale [ 1 ] < 0 ? ( s32 ) ( ( gSP . viewport . y + gSP . viewport . vscale [ 1 ] * 2.0f ) * scaleY ) : ( s32 ) ( ( pCurrentBuffer - > m_height - ( gSP . viewport . y + gSP . viewport . height ) ) * scaleY ) ;
gfxContext . setViewport ( X , Y ,
std : : max ( ( s32 ) ( gSP . viewport . width * scaleX ) , 0 ) , std : : max ( ( s32 ) ( gSP . viewport . height * scaleY ) , 0 ) ) ;
}
gSP . changed & = ~ CHANGED_VIEWPORT ;
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _updateScreenCoordsViewport ( ) const
2017-01-10 15:22:32 +00:00
{
DisplayWindow & wnd = DisplayWindow : : get ( ) ;
FrameBuffer * pCurrentBuffer = frameBufferList ( ) . getCurrent ( ) ;
if ( pCurrentBuffer = = nullptr )
gfxContext . setViewport ( 0 , wnd . getHeightOffset ( ) , wnd . getScreenWidth ( ) , wnd . getScreenHeight ( ) ) ;
else
gfxContext . setViewport ( 0 , 0 , s32 ( pCurrentBuffer - > m_width * pCurrentBuffer - > m_scaleX ) , s32 ( pCurrentBuffer - > m_height * pCurrentBuffer - > m_scaleY ) ) ;
gSP . changed | = CHANGED_VIEWPORT ;
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _legacySetBlendMode ( ) const
2017-01-10 15:22:32 +00:00
{
const u32 blendmode = gDP . otherMode . l > > 16 ;
// 0x7000 = CVG_X_ALPHA|ALPHA_CVG_SEL|FORCE_BL
if ( gDP . otherMode . alphaCvgSel ! = 0 & & ( gDP . otherMode . l & 0x7000 ) ! = 0x7000 ) {
switch ( blendmode ) {
case 0x4055 : // Mario Golf
case 0x5055 : // Paper Mario intro clr_mem * a_in + clr_mem * a_mem
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
break ;
default :
gfxContext . enable ( enable : : BLEND , false ) ;
}
return ;
}
if ( gDP . otherMode . forceBlender ! = 0 & & gDP . otherMode . cycleType < G_CYC_COPY ) {
Parameter sfactor , dfactor ;
switch ( blendmode )
{
// Mace objects
case 0x0382 :
// Mace special blend mode, see GLSLCombiner.cpp
case 0x0091 :
// 1080 Sky
case 0x0C08 :
// Used LOTS of places
case 0x0F0A :
//DK64 blue prints
case 0x0302 :
// Bomberman 2 special blend mode, see GLSLCombiner.cpp
case 0xA500 :
//Sin and Punishment
case 0xCB02 :
// Battlezone
// clr_in * a + clr_in * (1-a)
case 0xC800 :
// Conker BFD
// clr_in * a_fog + clr_fog * (1-a)
// clr_in * 0 + clr_in * 1
case 0x07C2 :
case 0x00C0 :
//ISS64
case 0xC302 :
// Donald Duck
case 0xC702 :
sfactor = blend : : ONE ;
dfactor = blend : : ZERO ;
break ;
case 0x55f0 :
// Bust-A-Move 3 DX
// CLR_MEM * A_FOG + CLR_FOG * 1MA
sfactor = blend : : ONE ;
dfactor = blend : : SRC_ALPHA ;
break ;
case 0x0F1A :
if ( gDP . otherMode . cycleType = = G_CYC_1CYCLE ) {
sfactor = blend : : ONE ;
dfactor = blend : : ZERO ;
}
else {
sfactor = blend : : ZERO ;
dfactor = blend : : ONE ;
}
break ;
//Space Invaders
case 0x0448 : // Add
case 0x055A :
sfactor = blend : : ONE ;
dfactor = blend : : ONE ;
break ;
case 0xc712 : // Pokemon Stadium?
case 0xAF50 : // LOT in Zelda: MM
case 0x0F5A : // LOT in Zelda: MM
case 0x0FA5 : // Seems to be doing just blend color - maybe combiner can be used for this?
case 0x5055 : // Used in Paper Mario intro, I'm not sure if this is right...
//clr_in * 0 + clr_mem * 1
sfactor = blend : : ZERO ;
dfactor = blend : : ONE ;
break ;
case 0x5F50 : //clr_mem * 0 + clr_mem * (1-a)
sfactor = blend : : ZERO ;
dfactor = blend : : ONE_MINUS_SRC_ALPHA ;
break ;
case 0xF550 : //clr_fog * a_fog + clr_mem * (1-a)
case 0x0150 : // spiderman
case 0x0550 : // bomberman 64
case 0x0D18 : //clr_in * a_fog + clr_mem * (1-a)
sfactor = blend : : SRC_ALPHA ;
dfactor = blend : : ONE_MINUS_SRC_ALPHA ;
break ;
case 0xC912 : //40 winks, clr_in * a_fog + clr_mem * 1
sfactor = blend : : SRC_ALPHA ;
dfactor = blend : : ONE ;
break ;
case 0x0040 : // Fzero
case 0xC810 : // Blends fog
case 0x0C18 : // Standard interpolated blend
case 0x0050 : // Standard interpolated blend
case 0x0051 : // Standard interpolated blend
case 0x0055 : // Used for antialiasing
sfactor = blend : : SRC_ALPHA ;
dfactor = blend : : ONE_MINUS_SRC_ALPHA ;
break ;
case 0x0C19 : // Used for antialiasing
case 0xC811 : // Blends fog
sfactor = blend : : SRC_ALPHA ;
dfactor = blend : : DST_ALPHA ;
break ;
case 0x5000 : // V8 explosions
sfactor = blend : : ONE_MINUS_SRC_ALPHA ;
dfactor = blend : : SRC_ALPHA ;
break ;
case 0xFA00 : // Bomberman second attack
sfactor = blend : : ONE ;
dfactor = blend : : ZERO ;
break ;
default :
//LOG(LOG_VERBOSE, "Unhandled blend mode=%x", gDP.otherMode.l >> 16);
sfactor = blend : : SRC_ALPHA ;
dfactor = blend : : ONE_MINUS_SRC_ALPHA ;
break ;
}
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( sfactor , dfactor ) ;
} else if ( ( config . generalEmulation . hacks & hack_pilotWings ) ! = 0 & & ( gDP . otherMode . l & 0x80 ) ! = 0 ) { //CLR_ON_CVG without FORCE_BL
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
} else if ( ( config . generalEmulation . hacks & hack_blastCorps ) ! = 0 & & gDP . otherMode . cycleType < G_CYC_COPY & & gSP . texture . on = = 0 & & currentCombiner ( ) - > usesTexture ( ) ) { // Blast Corps
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
} else {
gfxContext . enable ( enable : : BLEND , false ) ;
}
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _setBlendMode ( ) const
2017-01-10 15:22:32 +00:00
{
if ( config . generalEmulation . enableLegacyBlending ! = 0 ) {
_legacySetBlendMode ( ) ;
return ;
}
if ( gDP . otherMode . forceBlender ! = 0 & & gDP . otherMode . cycleType < G_CYC_COPY ) {
Parameter srcFactor = blend : : ONE ;
Parameter dstFactor = blend : : ZERO ;
u32 memFactorSource = 2 , muxA , muxB ;
if ( gDP . otherMode . cycleType = = G_CYC_2CYCLE ) {
muxA = gDP . otherMode . c2_m1b ;
muxB = gDP . otherMode . c2_m2b ;
if ( gDP . otherMode . c2_m1a = = 1 ) {
if ( gDP . otherMode . c2_m2a = = 1 ) {
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
return ;
}
memFactorSource = 0 ;
} else if ( gDP . otherMode . c2_m2a = = 1 ) {
memFactorSource = 1 ;
}
if ( gDP . otherMode . c2_m2a = = 0 & & gDP . otherMode . c2_m2b = = 1 ) {
// c_in * a_mem
srcFactor = blend : : DST_ALPHA ;
}
} else {
muxA = gDP . otherMode . c1_m1b ;
muxB = gDP . otherMode . c1_m2b ;
if ( gDP . otherMode . c1_m1a = = 1 ) {
if ( gDP . otherMode . c1_m2a = = 1 ) {
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
return ;
}
memFactorSource = 0 ;
}
else if ( gDP . otherMode . c1_m2a = = 1 ) {
memFactorSource = 1 ;
}
if ( gDP . otherMode . c1_m2a = = 0 & & gDP . otherMode . c1_m2b = = 1 ) {
// c_pixel * a_mem
srcFactor = blend : : DST_ALPHA ;
}
}
switch ( memFactorSource ) {
case 0 :
switch ( muxA ) {
case 0 :
dstFactor = blend : : SRC_ALPHA ;
break ;
case 1 :
gfxContext . setBlendColor ( gDP . fogColor . r , gDP . fogColor . g , gDP . fogColor . b , gDP . fogColor . a ) ;
dstFactor = blend : : CONSTANT_ALPHA ;
break ;
case 2 :
assert ( false ) ; // shade alpha
dstFactor = blend : : SRC_ALPHA ;
break ;
case 3 :
dstFactor = blend : : ZERO ;
break ;
}
break ;
case 1 :
switch ( muxB ) {
case 0 :
// 1.0 - muxA
switch ( muxA ) {
case 0 :
dstFactor = blend : : ONE_MINUS_SRC_ALPHA ;
break ;
case 1 :
gfxContext . setBlendColor ( gDP . fogColor . r , gDP . fogColor . g , gDP . fogColor . b , gDP . fogColor . a ) ;
dstFactor = blend : : ONE_MINUS_CONSTANT_ALPHA ;
break ;
case 2 :
assert ( false ) ; // shade alpha
dstFactor = blend : : ONE_MINUS_SRC_ALPHA ;
break ;
case 3 :
dstFactor = blend : : ONE ;
break ;
}
break ;
case 1 :
dstFactor = blend : : DST_ALPHA ;
break ;
case 2 :
dstFactor = blend : : ONE ;
break ;
case 3 :
dstFactor = blend : : ZERO ;
break ;
}
break ;
default :
dstFactor = blend : : ZERO ;
}
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( srcFactor , dstFactor ) ;
}
else if ( ( config . generalEmulation . hacks & hack_pilotWings ) ! = 0 & & gDP . otherMode . clearOnCvg ! = 0 ) { //CLR_ON_CVG without FORCE_BL
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
}
else if ( ( config . generalEmulation . hacks & hack_blastCorps ) ! = 0 & & gDP . otherMode . cycleType < G_CYC_COPY & & gSP . texture . on = = 0 & & currentCombiner ( ) - > usesTexture ( ) ) { // Blast Corps
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
} else if ( ( gDP . otherMode . forceBlender = = 0 & & gDP . otherMode . cycleType < G_CYC_COPY ) ) {
if ( gDP . otherMode . c1_m1a = = 1 & & gDP . otherMode . c1_m2a = = 1 ) {
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
} else {
gfxContext . enable ( enable : : BLEND , false ) ;
}
}
else {
gfxContext . enable ( enable : : BLEND , false ) ;
}
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _updateTextures ( ) const
2017-01-10 15:22:32 +00:00
{
//For some reason updating the texture cache on the first frame of LOZ:OOT causes a nullptr Pointer exception...
CombinerInfo & cmbInfo = CombinerInfo : : get ( ) ;
CombinerProgram * pCurrentCombiner = cmbInfo . getCurrent ( ) ;
if ( pCurrentCombiner ! = nullptr ) {
for ( u32 t = 0 ; t < 2 ; + + t ) {
if ( pCurrentCombiner - > usesTile ( t ) )
textureCache ( ) . update ( t ) ;
else
textureCache ( ) . activateDummy ( t ) ;
}
}
gDP . changed & = ~ ( CHANGED_TILE | CHANGED_TMEM ) ;
gSP . changed & = ~ ( CHANGED_TEXTURE ) ;
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : _updateStates ( DrawingState _drawingState ) const
2017-01-10 15:22:32 +00:00
{
CombinerInfo & cmbInfo = CombinerInfo : : get ( ) ;
cmbInfo . setPolygonMode ( _drawingState ) ;
cmbInfo . update ( ) ;
if ( gSP . changed & CHANGED_GEOMETRYMODE ) {
_updateCullFace ( ) ;
gSP . changed & = ~ CHANGED_GEOMETRYMODE ;
}
_updateDepthCompare ( ) ;
if ( gDP . changed & CHANGED_SCISSOR )
updateScissor ( frameBufferList ( ) . getCurrent ( ) ) ;
if ( gSP . changed & CHANGED_VIEWPORT )
_updateViewport ( ) ;
if ( ( gSP . changed & CHANGED_TEXTURE ) | |
( gDP . changed & ( CHANGED_TILE | CHANGED_TMEM ) ) | |
cmbInfo . isChanged ( ) | |
_drawingState = = DrawingState : : TexRect ) {
_updateTextures ( ) ;
}
if ( ( gDP . changed & ( CHANGED_RENDERMODE | CHANGED_CYCLETYPE ) ) ) {
_setBlendMode ( ) ;
gDP . changed & = ~ ( CHANGED_RENDERMODE | CHANGED_CYCLETYPE ) ;
}
cmbInfo . updateParameters ( ) ;
if ( ! gfxContext . isSupported ( SpecialFeatures : : FragmentDepthWrite ) )
return ;
if ( gDP . colorImage . address = = gDP . depthImageAddress & &
config . generalEmulation . enableFragmentDepthWrite ! = 0 & &
config . frameBufferEmulation . N64DepthCompare = = 0 & &
( config . generalEmulation . hacks & hack_ZeldaMM ) = = 0
) {
// Current render target is depth buffer.
// Shader will set gl_FragDepth to shader color, see ShaderCombiner ctor
// Here we enable depth buffer write.
if ( gDP . otherMode . depthCompare ! = 0 ) {
// Render to depth buffer with depth compare. Need to get copy of current depth buffer.
FrameBuffer * pCurBuf = frameBufferList ( ) . getCurrent ( ) ;
if ( pCurBuf ! = nullptr & & pCurBuf - > m_pDepthBuffer ! = nullptr ) {
CachedTexture * pDepthTexture = pCurBuf - > m_pDepthBuffer - > copyDepthBufferTexture ( pCurBuf ) ;
if ( pDepthTexture = = nullptr )
return ;
Context : : TexParameters params ;
params . handle = graphics : : ObjectHandle ( pDepthTexture - > glName ) ;
params . target = graphics : : target : : TEXTURE_2D ;
params . textureUnitIndex = graphics : : textureIndices : : DepthTex ;
params . maxMipmapLevel = 0 ;
params . minFilter = graphics : : textureParameters : : FILTER_NEAREST ;
params . magFilter = graphics : : textureParameters : : FILTER_NEAREST ;
gfxContext . setTextureParameters ( params ) ;
}
}
else if ( frameBufferList ( ) . getCurrent ( ) = = nullptr ) {
gfxContext . enable ( enable : : BLEND , true ) ;
gfxContext . setBlending ( blend : : ZERO , blend : : ONE ) ;
}
gfxContext . enable ( enable : : DEPTH_TEST , true ) ;
gfxContext . setDepthCompare ( compare : : ALWAYS ) ;
gfxContext . enableDepthWrite ( true ) ;
gDP . changed | = CHANGED_RENDERMODE ;
}
}
2017-01-11 10:07:20 +00:00
void GraphicsDrawer : : _prepareDrawTriangle ( )
2017-01-10 15:22:32 +00:00
{
2017-01-11 10:07:20 +00:00
m_texrectDrawer . draw ( ) ;
2017-01-10 15:22:32 +00:00
if ( ( m_modifyVertices & MODIFY_XY ) ! = 0 )
gSP . changed & = ~ CHANGED_VIEWPORT ;
if ( gSP . changed | | gDP . changed )
_updateStates ( DrawingState : : Triangle ) ;
m_drawingState = DrawingState : : Triangle ;
bool bFlatColors = false ;
if ( ! RSP . bLLE & & ( gSP . geometryMode & G_LIGHTING ) = = 0 ) {
bFlatColors = ( gSP . geometryMode & G_SHADE ) = = 0 ;
bFlatColors | = ( gSP . geometryMode & G_SHADING_SMOOTH ) = = 0 ;
}
m_bFlatColors = bFlatColors ;
if ( ( m_modifyVertices & MODIFY_XY ) ! = 0 )
_updateScreenCoordsViewport ( ) ;
m_modifyVertices = 0 ;
}
2017-01-11 06:08:05 +00:00
bool GraphicsDrawer : : _canDraw ( ) const
2017-01-10 15:22:32 +00:00
{
return config . frameBufferEmulation . enable = = 0 | | frameBufferList ( ) . getCurrent ( ) ! = nullptr ;
}
2017-01-11 06:08:05 +00:00
void GraphicsDrawer : : drawTriangles ( )
2017-01-10 15:22:32 +00:00
{
if ( triangles . num = = 0 | | ! _canDraw ( ) ) {
triangles . num = 0 ;
triangles . maxElement = 0 ;
return ;
}
2017-01-11 10:07:20 +00:00
_prepareDrawTriangle ( ) ;
2017-01-10 15:22:32 +00:00
2017-01-12 15:22:53 +00:00
Context : : DrawTriangleParameters triParams ;
2017-01-11 10:07:20 +00:00
triParams . mode = drawmode : : TRIANGLES ;
triParams . flatColors = m_bFlatColors ;
triParams . elementsType = datatype : : UNSIGNED_BYTE ;
triParams . verticesCount = static_cast < u32 > ( triangles . maxElement ) + 1 ;
triParams . elementsCount = triangles . num ;
triParams . vertices = triangles . vertices . data ( ) ;
triParams . elements = triangles . elements . data ( ) ;
triParams . combiner = currentCombiner ( ) ;
2017-01-12 15:22:53 +00:00
gfxContext . drawTriangles ( triParams ) ;
2017-01-10 15:22:32 +00:00
if ( config . frameBufferEmulation . enable ! = 0 & &
config . frameBufferEmulation . copyDepthToRDRAM = = Config : : cdSoftwareRender & &
gDP . otherMode . depthUpdate ! = 0 ) {
renderTriangles ( triangles . vertices . data ( ) , triangles . elements . data ( ) , triangles . num ) ;
FrameBuffer * pCurrentDepthBuffer = frameBufferList ( ) . findBuffer ( gDP . depthImageAddress ) ;
if ( pCurrentDepthBuffer ! = nullptr )
pCurrentDepthBuffer - > m_cleared = false ;
}
2017-01-10 14:58:09 +00:00
2017-01-10 15:22:32 +00:00
triangles . num = 0 ;
triangles . maxElement = 0 ;
}
2017-01-11 10:07:20 +00:00
void GraphicsDrawer : : drawScreenSpaceTriangle ( u32 _numVtx )
{
if ( _numVtx = = 0 | | ! _canDraw ( ) )
return ;
for ( u32 i = 0 ; i < _numVtx ; + + i ) {
SPVertex & vtx = m_dmaVertices [ i ] ;
vtx . modify = MODIFY_ALL ;
}
m_modifyVertices = MODIFY_ALL ;
gSP . changed & = ~ CHANGED_GEOMETRYMODE ; // Don't update cull mode
_prepareDrawTriangle ( ) ;
gfxContext . enable ( enable : : CULL_FACE , false ) ;
2017-01-12 15:22:53 +00:00
Context : : DrawTriangleParameters triParams ;
2017-01-11 10:07:20 +00:00
triParams . mode = drawmode : : TRIANGLE_STRIP ;
triParams . flatColors = m_bFlatColors ;
triParams . verticesCount = _numVtx ;
triParams . vertices = m_dmaVertices . data ( ) ;
triParams . combiner = currentCombiner ( ) ;
2017-01-12 15:22:53 +00:00
gfxContext . drawTriangles ( triParams ) ;
2017-01-11 10:07:20 +00:00
frameBufferList ( ) . setBufferChanged ( ) ;
gSP . changed | = CHANGED_GEOMETRYMODE ;
}
void GraphicsDrawer : : drawDMATriangles ( u32 _numVtx )
{
if ( _numVtx = = 0 | | ! _canDraw ( ) )
return ;
_prepareDrawTriangle ( ) ;
2017-01-12 15:22:53 +00:00
Context : : DrawTriangleParameters triParams ;
2017-01-11 10:07:20 +00:00
triParams . mode = drawmode : : TRIANGLES ;
triParams . flatColors = m_bFlatColors ;
triParams . verticesCount = _numVtx ;
triParams . vertices = m_dmaVertices . data ( ) ;
triParams . combiner = currentCombiner ( ) ;
2017-01-12 15:22:53 +00:00
gfxContext . drawTriangles ( triParams ) ;
2017-01-11 10:07:20 +00:00
if ( config . frameBufferEmulation . enable ! = 0 & &
config . frameBufferEmulation . copyDepthToRDRAM = = Config : : cdSoftwareRender & &
gDP . otherMode . depthUpdate ! = 0 ) {
renderTriangles ( m_dmaVertices . data ( ) , nullptr , _numVtx ) ;
FrameBuffer * pCurrentDepthBuffer = frameBufferList ( ) . findBuffer ( gDP . depthImageAddress ) ;
if ( pCurrentDepthBuffer ! = nullptr )
pCurrentDepthBuffer - > m_cleared = false ;
}
}
void GraphicsDrawer : : _drawThickLine ( int _v0 , int _v1 , float _width )
{
if ( ( gSP . geometryMode & G_LIGHTING ) = = 0 ) {
if ( ( gSP . geometryMode & G_SHADE ) = = 0 ) {
SPVertex & vtx1 = triangles . vertices [ _v0 ] ;
vtx1 . flat_r = gDP . primColor . r ;
vtx1 . flat_g = gDP . primColor . g ;
vtx1 . flat_b = gDP . primColor . b ;
vtx1 . flat_a = gDP . primColor . a ;
SPVertex & vtx2 = triangles . vertices [ _v1 ] ;
vtx2 . flat_r = gDP . primColor . r ;
vtx2 . flat_g = gDP . primColor . g ;
vtx2 . flat_b = gDP . primColor . b ;
vtx2 . flat_a = gDP . primColor . a ;
}
else if ( ( gSP . geometryMode & G_SHADING_SMOOTH ) = = 0 ) {
// Flat shading
SPVertex & vtx0 = triangles . vertices [ _v0 + ( ( RSP . w1 > > 24 ) & 3 ) ] ;
SPVertex & vtx1 = triangles . vertices [ _v0 ] ;
vtx1 . r = vtx1 . flat_r = vtx0 . r ;
vtx1 . g = vtx1 . flat_g = vtx0 . g ;
vtx1 . b = vtx1 . flat_b = vtx0 . b ;
vtx1 . a = vtx1 . flat_a = vtx0 . a ;
SPVertex & vtx2 = triangles . vertices [ _v1 ] ;
vtx2 . r = vtx2 . flat_r = vtx0 . r ;
vtx2 . g = vtx2 . flat_g = vtx0 . g ;
vtx2 . b = vtx2 . flat_b = vtx0 . b ;
vtx2 . a = vtx2 . flat_a = vtx0 . a ;
}
}
setDMAVerticesSize ( 4 ) ;
SPVertex * pVtx = getDMAVerticesData ( ) ;
pVtx [ 0 ] = triangles . vertices [ _v0 ] ;
pVtx [ 0 ] . x = pVtx [ 0 ] . x / pVtx [ 0 ] . w * gSP . viewport . vscale [ 0 ] + gSP . viewport . vtrans [ 0 ] ;
pVtx [ 0 ] . y = pVtx [ 0 ] . y / pVtx [ 0 ] . w * gSP . viewport . vscale [ 1 ] + gSP . viewport . vtrans [ 1 ] ;
pVtx [ 0 ] . z = pVtx [ 0 ] . z / pVtx [ 0 ] . w * gSP . viewport . vscale [ 2 ] + gSP . viewport . vtrans [ 2 ] ;
pVtx [ 1 ] = pVtx [ 0 ] ;
pVtx [ 2 ] = triangles . vertices [ _v1 ] ;
pVtx [ 2 ] . x = pVtx [ 2 ] . x / pVtx [ 2 ] . w * gSP . viewport . vscale [ 0 ] + gSP . viewport . vtrans [ 0 ] ;
pVtx [ 2 ] . y = pVtx [ 2 ] . y / pVtx [ 2 ] . w * gSP . viewport . vscale [ 1 ] + gSP . viewport . vtrans [ 1 ] ;
pVtx [ 2 ] . z = pVtx [ 2 ] . z / pVtx [ 2 ] . w * gSP . viewport . vscale [ 2 ] + gSP . viewport . vtrans [ 2 ] ;
pVtx [ 3 ] = pVtx [ 2 ] ;
if ( fabs ( pVtx [ 0 ] . y - pVtx [ 2 ] . y ) < 0.0001 ) {
const f32 Y = pVtx [ 0 ] . y ;
pVtx [ 0 ] . y = pVtx [ 2 ] . y = Y - _width ;
pVtx [ 1 ] . y = pVtx [ 3 ] . y = Y + _width ;
}
else if ( fabs ( pVtx [ 0 ] . x - pVtx [ 2 ] . x ) < 0.0001 ) {
const f32 X = pVtx [ 0 ] . x ;
pVtx [ 0 ] . x = pVtx [ 2 ] . x = X - _width ;
pVtx [ 1 ] . x = pVtx [ 3 ] . x = X + _width ;
}
else {
const f32 X0 = pVtx [ 0 ] . x ;
const f32 Y0 = pVtx [ 0 ] . y ;
const f32 X1 = pVtx [ 2 ] . x ;
const f32 Y1 = pVtx [ 2 ] . y ;
const f32 dx = X1 - X0 ;
const f32 dy = Y1 - Y0 ;
const f32 len = sqrtf ( dx * dx + dy * dy ) ;
const f32 wx = dy * _width / len ;
const f32 wy = dx * _width / len ;
pVtx [ 0 ] . x = X0 + wx ;
pVtx [ 0 ] . y = Y0 - wy ;
pVtx [ 1 ] . x = X0 - wx ;
pVtx [ 1 ] . y = Y0 + wy ;
pVtx [ 2 ] . x = X1 + wx ;
pVtx [ 2 ] . y = Y1 - wy ;
pVtx [ 3 ] . x = X1 - wx ;
pVtx [ 3 ] . y = Y1 + wy ;
}
drawScreenSpaceTriangle ( 4 ) ;
}
void GraphicsDrawer : : drawLine ( int _v0 , int _v1 , float _width )
{
m_texrectDrawer . draw ( ) ;
if ( ! _canDraw ( ) )
return ;
GLfloat lineWidth = _width ;
if ( config . frameBufferEmulation . nativeResFactor = = 0 )
2017-01-15 07:57:25 +00:00
lineWidth * = dwnd ( ) . getScaleX ( ) ;
2017-01-11 10:07:20 +00:00
else
lineWidth * = config . frameBufferEmulation . nativeResFactor ;
if ( lineWidth > m_maxLineWidth ) {
_drawThickLine ( _v0 , _v1 , _width * 0.5f ) ;
return ;
}
if ( ( triangles . vertices [ _v0 ] . modify & MODIFY_XY ) ! = 0 )
gSP . changed & = ~ CHANGED_VIEWPORT ;
if ( gSP . changed | | gDP . changed )
_updateStates ( DrawingState : : Line ) ;
m_drawingState = DrawingState : : Line ;
if ( ( triangles . vertices [ _v0 ] . modify & MODIFY_XY ) ! = 0 )
_updateScreenCoordsViewport ( ) ;
SPVertex vertexBuf [ 2 ] = { triangles . vertices [ triangles . elements [ _v0 ] ] , triangles . vertices [ triangles . elements [ _v1 ] ] } ;
2017-01-12 15:22:53 +00:00
gfxContext . drawLine ( lineWidth , vertexBuf ) ;
2017-01-11 10:07:20 +00:00
}
void GraphicsDrawer : : drawRect ( int _ulx , int _uly , int _lrx , int _lry , float * _pColor )
{
m_texrectDrawer . draw ( ) ;
if ( ! _canDraw ( ) )
return ;
gSP . changed & = ~ CHANGED_GEOMETRYMODE ; // Don't update cull mode
if ( gSP . changed | | gDP . changed )
_updateStates ( DrawingState : : Rect ) ;
m_drawingState = DrawingState : : Rect ;
FrameBuffer * pCurrentBuffer = frameBufferList ( ) . getCurrent ( ) ;
2017-01-15 07:57:25 +00:00
DisplayWindow & wnd = dwnd ( ) ;
2017-01-11 10:07:20 +00:00
if ( pCurrentBuffer = = nullptr )
2017-01-15 07:57:25 +00:00
gfxContext . setViewport ( 0 , wnd . getHeightOffset ( ) , wnd . getScreenWidth ( ) , wnd . getScreenHeight ( ) ) ;
2017-01-11 10:07:20 +00:00
else
gfxContext . setViewport ( 0 , 0 , pCurrentBuffer - > m_width * pCurrentBuffer - > m_scaleX , pCurrentBuffer - > m_height * pCurrentBuffer - > m_scaleY ) ;
gfxContext . enable ( enable : : CULL_FACE , false ) ;
const float scaleX = pCurrentBuffer ! = nullptr ? 1.0f / pCurrentBuffer - > m_width : VI . rwidth ;
const float scaleY = pCurrentBuffer ! = nullptr ? 1.0f / pCurrentBuffer - > m_height : VI . rheight ;
const float Z = ( gDP . otherMode . depthSource = = G_ZS_PRIM ) ? gDP . primDepth . z : 0.0f ;
const float W = 1.0f ;
m_rect [ 0 ] . x = ( float ) _ulx * ( 2.0f * scaleX ) - 1.0 ;
m_rect [ 0 ] . y = ( float ) _uly * ( - 2.0f * scaleY ) + 1.0 ;
m_rect [ 0 ] . z = Z ;
m_rect [ 0 ] . w = W ;
m_rect [ 1 ] . x = ( float ) _lrx * ( 2.0f * scaleX ) - 1.0 ;
m_rect [ 1 ] . y = m_rect [ 0 ] . y ;
m_rect [ 1 ] . z = Z ;
m_rect [ 1 ] . w = W ;
m_rect [ 2 ] . x = m_rect [ 0 ] . x ;
m_rect [ 2 ] . y = ( float ) _lry * ( - 2.0f * scaleY ) + 1.0 ;
m_rect [ 2 ] . z = Z ;
m_rect [ 2 ] . w = W ;
m_rect [ 3 ] . x = m_rect [ 1 ] . x ;
m_rect [ 3 ] . y = m_rect [ 2 ] . y ;
m_rect [ 3 ] . z = Z ;
m_rect [ 3 ] . w = W ;
2017-01-15 07:57:25 +00:00
if ( wnd . isAdjustScreen ( ) & & ( gDP . colorImage . width > VI . width * 98 / 100 ) & & ( _lrx - _ulx < VI . width * 9 / 10 ) ) {
const float scale = wnd . getAdjustScale ( ) ;
2017-01-11 10:07:20 +00:00
for ( u32 i = 0 ; i < 4 ; + + i )
m_rect [ i ] . x * = scale ;
}
2017-01-12 15:22:53 +00:00
Context : : DrawRectParameters rectParams ;
2017-01-11 10:07:20 +00:00
rectParams . mode = drawmode : : TRIANGLE_STRIP ;
if ( gDP . otherMode . cycleType = = G_CYC_FILL )
2017-01-15 11:46:04 +00:00
std : : copy_n ( _pColor , 4 , rectParams . rectColor . begin ( ) ) ;
2017-01-11 10:07:20 +00:00
else
rectParams . rectColor . fill ( 0.0f ) ;
rectParams . verticesCount = 4 ;
rectParams . vertices = m_rect ;
rectParams . combiner = currentCombiner ( ) ;
2017-01-12 15:22:53 +00:00
gfxContext . drawRects ( rectParams ) ;
2017-01-11 10:07:20 +00:00
gSP . changed | = CHANGED_GEOMETRYMODE | CHANGED_VIEWPORT ;
}
static
bool texturedRectShadowMap ( const GraphicsDrawer : : TexturedRectParams & )
{
FrameBuffer * pCurrentBuffer = frameBufferList ( ) . getCurrent ( ) ;
if ( pCurrentBuffer ! = nullptr ) {
2017-01-17 14:52:28 +00:00
if ( gDP . textureImage . size = = 2 & & gDP . textureImage . address > = gDP . depthImageAddress & &
gDP . textureImage . address < ( gDP . depthImageAddress + gDP . colorImage . width * gDP . colorImage . width * 6 / 4 ) ) {
if ( ! Context : : imageTextures )
2017-01-11 10:07:20 +00:00
return true ;
2017-01-17 14:52:28 +00:00
pCurrentBuffer - > m_pDepthBuffer - > activateDepthBufferTexture ( pCurrentBuffer ) ;
CombinerInfo : : get ( ) . setDepthFogCombiner ( ) ;
return false ;
2017-01-11 10:07:20 +00:00
}
}
return false ;
}
//u32 rectDepthBufferCopyFrame = 0xFFFFFFFF;
static
bool texturedRectDepthBufferCopy ( const GraphicsDrawer : : TexturedRectParams & _params )
{
// Copy one line from depth buffer into auxiliary color buffer with height = 1.
// Data from depth buffer loaded into TMEM and then rendered to RDRAM by texrect.
// Works only with depth buffer emulation enabled.
// Load of arbitrary data to that area causes weird camera rotation in CBFD.
const gDPTile * pTile = gSP . textureTile [ 0 ] ;
if ( pTile - > loadType = = LOADTYPE_BLOCK & & gDP . textureImage . size = = 2 & & gDP . textureImage . address > = gDP . depthImageAddress & & gDP . textureImage . address < ( gDP . depthImageAddress + gDP . colorImage . width * gDP . colorImage . width * 6 / 4 ) ) {
if ( config . frameBufferEmulation . copyDepthToRDRAM = = Config : : cdDisable )
return true ;
FrameBuffer * pBuffer = frameBufferList ( ) . getCurrent ( ) ;
if ( pBuffer = = nullptr )
return true ;
pBuffer - > m_cleared = true ;
if ( config . frameBufferEmulation . copyDepthToRDRAM = = Config : : cdCopyFromVRam ) {
2017-01-15 07:57:25 +00:00
if ( rectDepthBufferCopyFrame ! = dwnd ( ) . getBuffersSwapCount ( ) ) {
rectDepthBufferCopyFrame = dwnd ( ) . getBuffersSwapCount ( ) ;
2017-01-11 10:07:20 +00:00
if ( ! FrameBuffer_CopyDepthBuffer ( gDP . colorImage . address ) )
return true ;
}
RDP_RepeatLastLoadBlock ( ) ;
}
const u32 width = ( u32 ) ( _params . lrx - _params . ulx ) ;
const u32 ulx = ( u32 ) _params . ulx ;
u16 * pSrc = ( ( u16 * ) TMEM ) + ( u32 ) floorf ( _params . uls + 0.5f ) ;
u16 * pDst = ( u16 * ) ( RDRAM + gDP . colorImage . address ) ;
for ( u32 x = 0 ; x < width ; + + x )
pDst [ ( ulx + x ) ^ 1 ] = swapword ( pSrc [ x ] ) ;
return true ;
}
return false ;
}
static
bool texturedRectCopyToItself ( const GraphicsDrawer : : TexturedRectParams & _params )
{
FrameBuffer * pCurrent = frameBufferList ( ) . getCurrent ( ) ;
if ( pCurrent ! = nullptr & & pCurrent - > m_size = = G_IM_SIZ_8b & & gSP . textureTile [ 0 ] - > frameBuffer = = pCurrent )
return true ;
return texturedRectDepthBufferCopy ( _params ) ;
}
static
bool texturedRectBGCopy ( const GraphicsDrawer : : TexturedRectParams & _params )
{
if ( GBI . getMicrocodeType ( ) ! = S2DEX )
return false ;
float flry = _params . lry ;
if ( flry > gDP . scissor . lry )
flry = gDP . scissor . lry ;
const u32 width = ( u32 ) ( _params . lrx - _params . ulx ) ;
const u32 tex_width = gSP . textureTile [ 0 ] - > line < < 3 ;
const u32 uly = ( u32 ) _params . uly ;
const u32 lry = flry ;
u8 * texaddr = RDRAM + gDP . loadInfo [ gSP . textureTile [ 0 ] - > tmem ] . texAddress + tex_width * ( u32 ) _params . ult + ( u32 ) _params . uls ;
u8 * fbaddr = RDRAM + gDP . colorImage . address + ( u32 ) _params . ulx ;
// LOG(LOG_VERBOSE, "memrect (%d, %d, %d, %d), ci_width: %d texaddr: 0x%08lx fbaddr: 0x%08lx\n", (u32)_params.ulx, uly, (u32)_params.lrx, lry, gDP.colorImage.width, gSP.textureTile[0]->imageAddress + tex_width*(u32)_params.ult + (u32)_params.uls, gDP.colorImage.address + (u32)_params.ulx);
for ( u32 y = uly ; y < lry ; + + y ) {
u8 * src = texaddr + ( y - uly ) * tex_width ;
u8 * dst = fbaddr + y * gDP . colorImage . width ;
memcpy ( dst , src , width ) ;
}
frameBufferList ( ) . removeBuffer ( gDP . colorImage . address ) ;
return true ;
}
static
bool texturedRectPaletteMod ( const GraphicsDrawer : : TexturedRectParams & _params )
{
if ( gDP . textureImage . address = = 0x400 ) {
// Paper Mario uses complex set of actions to prepare darkness texture.
// It includes manipulations with texture formats and drawing buffer into itsels.
// All that stuff is hardly possible to reproduce with GL, so I just use dirty hacks to emualte it.
if ( gDP . colorImage . address = = 0x400 & & gDP . colorImage . width = = 64 ) {
memcpy ( RDRAM + 0x400 , RDRAM + 0x14d500 , 4096 ) ;
return true ;
}
if ( gDP . textureImage . width = = 64 ) {
gDPTile & curTile = gDP . tiles [ 0 ] ;
curTile . frameBuffer = nullptr ;
curTile . textureMode = TEXTUREMODE_NORMAL ;
textureCache ( ) . update ( 0 ) ;
currentCombiner ( ) - > update ( false ) ;
}
return false ;
}
// Modify palette for Paper Mario "2D lighting" effect
if ( gDP . scissor . lrx ! = 16 | | gDP . scissor . lry ! = 1 | | _params . lrx ! = 16 | | _params . lry ! = 1 )
return false ;
u8 envr = ( u8 ) ( gDP . envColor . r * 31.0f ) ;
u8 envg = ( u8 ) ( gDP . envColor . g * 31.0f ) ;
u8 envb = ( u8 ) ( gDP . envColor . b * 31.0f ) ;
u16 env16 = ( u16 ) ( ( envr < < 11 ) | ( envg < < 6 ) | ( envb < < 1 ) | 1 ) ;
u8 prmr = ( u8 ) ( gDP . primColor . r * 31.0f ) ;
u8 prmg = ( u8 ) ( gDP . primColor . g * 31.0f ) ;
u8 prmb = ( u8 ) ( gDP . primColor . b * 31.0f ) ;
u16 prim16 = ( u16 ) ( ( prmr < < 11 ) | ( prmg < < 6 ) | ( prmb < < 1 ) | 1 ) ;
u16 * src = ( u16 * ) & TMEM [ 256 ] ;
u16 * dst = ( u16 * ) ( RDRAM + gDP . colorImage . address ) ;
for ( u32 i = 0 ; i < 16 ; + + i )
dst [ i ^ 1 ] = ( src [ i < < 2 ] & 0x100 ) ? prim16 : env16 ;
return true ;
}
static
bool texturedRectMonochromeBackground ( const GraphicsDrawer : : TexturedRectParams & _params )
{
2017-01-17 14:52:28 +00:00
if ( gDP . textureImage . address > = gDP . colorImage . address & &
gDP . textureImage . address < = ( gDP . colorImage . address + gDP . colorImage . width * gDP . colorImage . height * 2 ) ) {
2017-01-11 10:07:20 +00:00
FrameBuffer * pCurrentBuffer = frameBufferList ( ) . getCurrent ( ) ;
if ( pCurrentBuffer ! = nullptr ) {
FrameBuffer_ActivateBufferTexture ( 0 , pCurrentBuffer ) ;
CombinerInfo : : get ( ) . setMonochromeCombiner ( ) ;
return false ;
2017-01-17 14:52:28 +00:00
} else
2017-01-11 10:07:20 +00:00
return true ;
2017-01-17 14:52:28 +00:00
2017-01-11 10:07:20 +00:00
}
2017-01-17 14:52:28 +00:00
2017-01-11 10:07:20 +00:00
return false ;
}
// Special processing of textured rect.
// Return true if actuial rendering is not necessary
bool ( * texturedRectSpecial ) ( const GraphicsDrawer : : TexturedRectParams & _params ) = nullptr ;
void GraphicsDrawer : : drawTexturedRect ( const TexturedRectParams & _params )
{
gSP . changed & = ~ CHANGED_GEOMETRYMODE ; // Don't update cull mode
m_drawingState = DrawingState : : TexRect ;
f32 alpha = 0.0f ;
if ( ! m_texrectDrawer . isEmpty ( ) ) {
CombinerInfo & cmbInfo = CombinerInfo : : get ( ) ;
cmbInfo . setPolygonMode ( DrawingState : : TexRect ) ;
cmbInfo . update ( ) ;
_updateTextures ( ) ;
cmbInfo . updateParameters ( ) ;
}
else {
if ( _params . texrectCmd & & ( gSP . changed | gDP . changed ) ! = 0 )
_updateStates ( DrawingState : : TexRect ) ;
glDisable ( GL_CULL_FACE ) ;
if ( CombinerInfo : : get ( ) . isChanged ( ) ) {
if ( currentCombiner ( ) - > usesShade ( ) ) {
gDPCombine combine ;
combine . mux = currentCombiner ( ) - > getKey ( ) . getMux ( ) ;
if ( combine . mA0 = = G_ACMUX_0 & & combine . aA0 = = G_ACMUX_SHADE )
alpha = 1.0f ;
}
}
if ( _params . texrectCmd & & texturedRectSpecial ! = nullptr & & texturedRectSpecial ( _params ) ) {
gSP . changed | = CHANGED_GEOMETRYMODE ;
return ;
}
if ( ! _canDraw ( ) )
return ;
}
CombinerProgram * pCurrentCombiner = currentCombiner ( ) ;
const FrameBuffer * pCurrentBuffer = _params . pBuffer ;
2017-01-15 07:57:25 +00:00
DisplayWindow & wnd = dwnd ( ) ;
2017-01-11 10:07:20 +00:00
TextureCache & cache = textureCache ( ) ;
const bool bUseBilinear = ( gDP . otherMode . textureFilter | ( gSP . objRendermode & G_OBJRM_BILERP ) ) ! = 0 ;
const bool bUseTexrectDrawer = config . generalEmulation . enableNativeResTexrects ! = 0
& & bUseBilinear
& & pCurrentCombiner - > usesTexture ( )
& & ( pCurrentBuffer = = nullptr | | ! pCurrentBuffer - > m_cfb )
& & ( cache . current [ 0 ] ! = nullptr )
// && (cache.current[0] == nullptr || cache.current[0]->format == G_IM_FMT_RGBA || cache.current[0]->format == G_IM_FMT_CI)
& & ( ( cache . current [ 0 ] - > frameBufferTexture = = CachedTexture : : fbNone & & ! cache . current [ 0 ] - > bHDTexture ) )
& & ( cache . current [ 1 ] = = nullptr | | ( cache . current [ 1 ] - > frameBufferTexture = = CachedTexture : : fbNone & & ! cache . current [ 1 ] - > bHDTexture ) ) ;
const float scaleX = pCurrentBuffer ! = nullptr ? 1.0f / pCurrentBuffer - > m_width : VI . rwidth ;
const float scaleY = pCurrentBuffer ! = nullptr ? 1.0f / pCurrentBuffer - > m_height : VI . rheight ;
const float Z = ( gDP . otherMode . depthSource = = G_ZS_PRIM ) ? gDP . primDepth . z : 0.0f ;
const float W = 1.0f ;
f32 uly , lry ;
if ( bUseTexrectDrawer ) {
uly = ( float ) _params . uly * ( 2.0f * scaleY ) - 1.0f ;
lry = ( float ) _params . lry * ( 2.0f * scaleY ) - 1.0f ;
}
else {
uly = ( float ) _params . uly * ( - 2.0f * scaleY ) + 1.0f ;
lry = ( float ) ( _params . lry ) * ( - 2.0f * scaleY ) + 1.0f ;
// Flush text drawer
if ( m_texrectDrawer . draw ( ) )
_updateStates ( DrawingState : : TexRect ) ;
}
m_rect [ 0 ] . x = ( float ) _params . ulx * ( 2.0f * scaleX ) - 1.0f ;
m_rect [ 0 ] . y = uly ;
m_rect [ 0 ] . z = Z ;
m_rect [ 0 ] . w = W ;
m_rect [ 1 ] . x = ( float ) ( _params . lrx ) * ( 2.0f * scaleX ) - 1.0f ;
m_rect [ 1 ] . y = m_rect [ 0 ] . y ;
m_rect [ 1 ] . z = Z ;
m_rect [ 1 ] . w = W ;
m_rect [ 2 ] . x = m_rect [ 0 ] . x ;
m_rect [ 2 ] . y = lry ;
m_rect [ 2 ] . z = Z ;
m_rect [ 2 ] . w = W ;
m_rect [ 3 ] . x = m_rect [ 1 ] . x ;
m_rect [ 3 ] . y = m_rect [ 2 ] . y ;
m_rect [ 3 ] . z = Z ;
m_rect [ 3 ] . w = W ;
struct
{
float s0 , t0 , s1 , t1 ;
} texST [ 2 ] = { { 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 } } ; //struct for texture coordinates
for ( u32 t = 0 ; t < 2 ; + + t ) {
if ( pCurrentCombiner - > usesTile ( t ) & & cache . current [ t ] & & gSP . textureTile [ t ] ) {
f32 shiftScaleS = 1.0f ;
f32 shiftScaleT = 1.0f ;
getTextureShiftScale ( t , cache , shiftScaleS , shiftScaleT ) ;
if ( _params . uls > _params . lrs ) {
texST [ t ] . s0 = ( _params . uls + _params . dsdx ) * shiftScaleS - gSP . textureTile [ t ] - > fuls ;
texST [ t ] . s1 = _params . lrs * shiftScaleS - gSP . textureTile [ t ] - > fuls ;
}
else {
texST [ t ] . s0 = _params . uls * shiftScaleS - gSP . textureTile [ t ] - > fuls ;
texST [ t ] . s1 = ( _params . lrs + _params . dsdx ) * shiftScaleS - gSP . textureTile [ t ] - > fuls ;
}
if ( _params . ult > _params . lrt ) {
texST [ t ] . t0 = ( _params . ult + _params . dtdy ) * shiftScaleT - gSP . textureTile [ t ] - > fult ;
texST [ t ] . t1 = _params . lrt * shiftScaleT - gSP . textureTile [ t ] - > fult ;
}
else {
texST [ t ] . t0 = _params . ult * shiftScaleT - gSP . textureTile [ t ] - > fult ;
texST [ t ] . t1 = ( _params . lrt + _params . dtdy ) * shiftScaleT - gSP . textureTile [ t ] - > fult ;
}
if ( cache . current [ t ] - > frameBufferTexture ! = CachedTexture : : fbNone ) {
texST [ t ] . s0 = cache . current [ t ] - > offsetS + texST [ t ] . s0 ;
texST [ t ] . t0 = cache . current [ t ] - > offsetT - texST [ t ] . t0 ;
texST [ t ] . s1 = cache . current [ t ] - > offsetS + texST [ t ] . s1 ;
texST [ t ] . t1 = cache . current [ t ] - > offsetT - texST [ t ] . t1 ;
}
Context : : TexParameters texParams ;
if ( ( cache . current [ t ] - > mirrorS = = 0 & & cache . current [ t ] - > maskS = = 0 & &
( texST [ t ] . s0 < texST [ t ] . s1 ?
texST [ t ] . s0 > = 0.0 & & texST [ t ] . s1 < = ( float ) cache . current [ t ] - > width :
texST [ t ] . s1 > = 0.0 & & texST [ t ] . s0 < = ( float ) cache . current [ t ] - > width ) )
| | ( cache . current [ t ] - > maskS = = 0 & & ( texST [ t ] . s0 < - 1024.0f | | texST [ t ] . s1 > 1023.99f ) ) )
texParams . wrapS = textureParameters : : WRAP_CLAMP_TO_EDGE ;
if ( cache . current [ t ] - > mirrorT = = 0 & &
( texST [ t ] . t0 < texST [ t ] . t1 ?
texST [ t ] . t0 > = 0.0f & & texST [ t ] . t1 < = ( float ) cache . current [ t ] - > height :
texST [ t ] . t1 > = 0.0f & & texST [ t ] . t0 < = ( float ) cache . current [ t ] - > height ) )
texParams . wrapT = textureParameters : : WRAP_CLAMP_TO_EDGE ;
if ( texParams . wrapS . isValid ( ) | | texParams . wrapT . isValid ( ) ) {
texParams . handle = ObjectHandle ( cache . current [ t ] - > glName ) ;
2017-01-15 11:46:04 +00:00
texParams . target = cache . current [ t ] - > frameBufferTexture = = CachedTexture : : fbMultiSample ?
target : : TEXTURE_2D_MULTISAMPLE : target : : TEXTURE_2D ;
2017-01-11 10:07:20 +00:00
texParams . textureUnitIndex = textureIndices : : Tex [ t ] ;
gfxContext . setTextureParameters ( texParams ) ;
}
texST [ t ] . s0 * = cache . current [ t ] - > scaleS ;
texST [ t ] . t0 * = cache . current [ t ] - > scaleT ;
texST [ t ] . s1 * = cache . current [ t ] - > scaleS ;
texST [ t ] . t1 * = cache . current [ t ] - > scaleT ;
}
}
if ( gDP . otherMode . cycleType = = G_CYC_COPY ) {
Context : : TexParameters texParams ;
texParams . handle = ObjectHandle ( cache . current [ 0 ] - > glName ) ;
2017-01-15 11:46:04 +00:00
texParams . target = cache . current [ 0 ] - > frameBufferTexture = = CachedTexture : : fbMultiSample ?
target : : TEXTURE_2D_MULTISAMPLE : target : : TEXTURE_2D ;
2017-01-11 10:07:20 +00:00
texParams . textureUnitIndex = textureIndices : : Tex [ 0 ] ;
texParams . minFilter = textureParameters : : FILTER_NEAREST ;
texParams . magFilter = textureParameters : : FILTER_NEAREST ;
gfxContext . setTextureParameters ( texParams ) ;
}
m_rect [ 0 ] . s0 = texST [ 0 ] . s0 ;
m_rect [ 0 ] . t0 = texST [ 0 ] . t0 ;
m_rect [ 0 ] . s1 = texST [ 1 ] . s0 ;
m_rect [ 0 ] . t1 = texST [ 1 ] . t0 ;
m_rect [ 3 ] . s0 = texST [ 0 ] . s1 ;
m_rect [ 3 ] . t0 = texST [ 0 ] . t1 ;
m_rect [ 3 ] . s1 = texST [ 1 ] . s1 ;
m_rect [ 3 ] . t1 = texST [ 1 ] . t1 ;
if ( _params . flip ) {
m_rect [ 1 ] . s0 = texST [ 0 ] . s0 ;
m_rect [ 1 ] . t0 = texST [ 0 ] . t1 ;
m_rect [ 1 ] . s1 = texST [ 1 ] . s0 ;
m_rect [ 1 ] . t1 = texST [ 1 ] . t1 ;
m_rect [ 2 ] . s0 = texST [ 0 ] . s1 ;
m_rect [ 2 ] . t0 = texST [ 0 ] . t0 ;
m_rect [ 2 ] . s1 = texST [ 1 ] . s1 ;
m_rect [ 2 ] . t1 = texST [ 1 ] . t0 ;
}
else {
m_rect [ 1 ] . s0 = texST [ 0 ] . s1 ;
m_rect [ 1 ] . t0 = texST [ 0 ] . t0 ;
m_rect [ 1 ] . s1 = texST [ 1 ] . s1 ;
m_rect [ 1 ] . t1 = texST [ 1 ] . t0 ;
m_rect [ 2 ] . s0 = texST [ 0 ] . s0 ;
m_rect [ 2 ] . t0 = texST [ 0 ] . t1 ;
m_rect [ 2 ] . s1 = texST [ 1 ] . s0 ;
m_rect [ 2 ] . t1 = texST [ 1 ] . t1 ;
}
2017-01-15 07:57:25 +00:00
if ( wnd . isAdjustScreen ( ) & &
2017-01-11 10:07:20 +00:00
( _params . forceAjustScale | |
( ( gDP . colorImage . width > VI . width * 98 / 100 ) & & ( _params . lrx - _params . ulx < VI . width * 9 / 10 ) ) ) )
{
2017-01-15 07:57:25 +00:00
const float scale = wnd . getAdjustScale ( ) ;
2017-01-11 10:07:20 +00:00
for ( u32 i = 0 ; i < 4 ; + + i )
m_rect [ i ] . x * = scale ;
}
if ( bUseTexrectDrawer )
m_texrectDrawer . add ( ) ;
else {
if ( pCurrentBuffer = = nullptr )
2017-01-15 07:57:25 +00:00
gfxContext . setViewport ( 0 , wnd . getHeightOffset ( ) , wnd . getScreenWidth ( ) , wnd . getScreenHeight ( ) ) ;
2017-01-11 10:07:20 +00:00
else
gfxContext . setViewport ( 0 , 0 , pCurrentBuffer - > m_width * pCurrentBuffer - > m_scaleX , pCurrentBuffer - > m_height * pCurrentBuffer - > m_scaleY ) ;
2017-01-12 15:22:53 +00:00
Context : : DrawRectParameters rectParams ;
2017-01-11 10:07:20 +00:00
rectParams . mode = drawmode : : TRIANGLE_STRIP ;
rectParams . rectColor . fill ( 0.0f ) ;
rectParams . rectColor [ 3 ] = alpha ;
rectParams . verticesCount = 4 ;
rectParams . vertices = m_rect ;
rectParams . combiner = currentCombiner ( ) ;
2017-01-12 15:22:53 +00:00
gfxContext . drawRects ( rectParams ) ;
2017-01-11 10:07:20 +00:00
gSP . changed | = CHANGED_GEOMETRYMODE | CHANGED_VIEWPORT ;
}
}
void GraphicsDrawer : : correctTexturedRectParams ( TexturedRectParams & _params )
{
if ( config . generalEmulation . correctTexrectCoords = = Config : : tcSmart ) {
if ( _params . ulx = = m_texrectParams . ulx & & _params . lrx = = m_texrectParams . lrx ) {
if ( fabsf ( _params . uly - m_texrectParams . lry ) < 0.51f )
_params . uly = m_texrectParams . lry ;
else if ( fabsf ( _params . lry - m_texrectParams . uly ) < 0.51f )
_params . lry = m_texrectParams . uly ;
}
else if ( _params . uly = = m_texrectParams . uly & & _params . lry = = m_texrectParams . lry ) {
if ( fabsf ( _params . ulx - m_texrectParams . lrx ) < 0.51f )
_params . ulx = m_texrectParams . lrx ;
else if ( fabsf ( _params . lrx - m_texrectParams . ulx ) < 0.51f )
_params . lrx = m_texrectParams . ulx ;
}
}
else if ( config . generalEmulation . correctTexrectCoords = = Config : : tcForce ) {
_params . lrx + = 0.25f ;
_params . lry + = 0.25f ;
}
m_texrectParams = _params ;
}
void GraphicsDrawer : : drawText ( const char * _pText , float x , float y )
{
m_drawingState = DrawingState : : None ;
2017-01-12 15:22:53 +00:00
gfxContext . drawText ( _pText , x , y ) ;
2017-01-11 10:07:20 +00:00
}
void GraphicsDrawer : : _drawOSD ( const char * _pText , float _x , float & _y )
{
float tW , tH ;
2017-01-14 15:24:17 +00:00
gfxContext . getTextSize ( _pText , tW , tH ) ;
2017-01-11 10:07:20 +00:00
const bool top = ( config . posTop & config . onScreenDisplay . pos ) ! = 0 ;
const bool right = ( config . onScreenDisplay . pos = = Config : : posTopRight ) | | ( config . onScreenDisplay . pos = = Config : : posBottomRight ) ;
const bool center = ( config . onScreenDisplay . pos = = Config : : posTopCenter ) | | ( config . onScreenDisplay . pos = = Config : : posBottomCenter ) ;
if ( center )
_x = - tW * 0.5f ;
else if ( right )
_x - = tW ;
if ( top )
_y - = tH ;
drawText ( _pText , _x , _y ) ;
if ( top )
_y - = tH * 0.5f ;
else
_y + = tH * 1.5f ;
}
void GraphicsDrawer : : drawOSD ( )
{
if ( ( config . onScreenDisplay . fps | config . onScreenDisplay . vis | config . onScreenDisplay . percent ) = = 0 )
return ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
DisplayWindow & wnd = DisplayWindow : : get ( ) ;
const GLint X = ( wnd . getScreenWidth ( ) - wnd . getWidth ( ) ) / 2 ;
const GLint Y = wnd . getHeightOffset ( ) ;
const GLint W = wnd . getWidth ( ) ;
const GLint H = wnd . getHeight ( ) ;
glViewport ( X , Y , W , H ) ;
glScissor ( X , Y , W , H ) ;
gSP . changed | = CHANGED_VIEWPORT ;
gDP . changed | = CHANGED_SCISSOR ;
const bool bottom = ( config . posBottom & config . onScreenDisplay . pos ) ! = 0 ;
const bool left = ( config . onScreenDisplay . pos = = Config : : posTopLeft ) | | ( config . onScreenDisplay . pos = = Config : : posBottomLeft ) ;
const float hp = left ? - 1 : 1 ;
const float vp = bottom ? - 1 : 1 ;
float hShift , vShift ;
2017-01-14 15:24:17 +00:00
gfxContext . getTextSize ( " 0 " , hShift , vShift ) ;
2017-01-11 10:07:20 +00:00
hShift * = 0.5f ;
vShift * = 0.5f ;
const float x = hp - hShift * hp ;
float y = vp - vShift * vp ;
char buf [ 16 ] ;
if ( config . onScreenDisplay . fps ) {
sprintf ( buf , " %d FPS " , int ( perf . getFps ( ) ) ) ;
_drawOSD ( buf , x , y ) ;
}
if ( config . onScreenDisplay . vis ) {
sprintf ( buf , " %d VI/S " , int ( perf . getVIs ( ) ) ) ;
_drawOSD ( buf , x , y ) ;
}
if ( config . onScreenDisplay . percent ) {
sprintf ( buf , " %d %% " , int ( perf . getPercent ( ) ) ) ;
_drawOSD ( buf , x , y ) ;
}
frameBufferList ( ) . setCurrentDrawBuffer ( ) ;
}
void GraphicsDrawer : : clearDepthBuffer ( u32 _ulx , u32 _uly , u32 _lrx , u32 _lry )
{
if ( ! _canDraw ( ) )
return ;
depthBufferList ( ) . clearBuffer ( _ulx , _uly , _lrx , _lry ) ;
gfxContext . clearDepthBuffer ( ) ;
_updateDepthUpdate ( ) ;
}
void GraphicsDrawer : : clearColorBuffer ( float * _pColor )
{
if ( _pColor ! = nullptr )
gfxContext . clearColorBuffer ( _pColor [ 0 ] , _pColor [ 1 ] , _pColor [ 2 ] , _pColor [ 3 ] ) ;
else
gfxContext . clearColorBuffer ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
}
2017-01-14 08:58:14 +00:00
void GraphicsDrawer : : copyTexturedRect ( const CopyRectParams & _params )
{
m_drawingState = DrawingState : : TexRect ;
const float scaleX = 1.0f / _params . dstWidth ;
const float scaleY = 1.0f / _params . dstHeight ;
const float X0 = _params . dstX0 * ( 2.0f * scaleX ) - 1.0f ;
const float Y0 = _params . dstY0 * ( 2.0f * scaleY ) - 1.0f ;
const float X1 = _params . dstX1 * ( 2.0f * scaleX ) - 1.0f ;
const float Y1 = _params . dstY1 * ( 2.0f * scaleY ) - 1.0f ;
2017-01-18 15:39:10 +00:00
const float Z = 0.0f ;
2017-01-14 08:58:14 +00:00
const float W = 1.0f ;
m_rect [ 0 ] . x = X0 ;
m_rect [ 0 ] . y = Y0 ;
m_rect [ 0 ] . z = Z ;
m_rect [ 0 ] . w = W ;
m_rect [ 1 ] . x = X1 ;
m_rect [ 1 ] . y = Y0 ;
m_rect [ 1 ] . z = Z ;
m_rect [ 1 ] . w = W ;
m_rect [ 2 ] . x = X0 ;
m_rect [ 2 ] . y = Y1 ;
m_rect [ 2 ] . z = Z ;
m_rect [ 2 ] . w = W ;
m_rect [ 3 ] . x = X1 ;
m_rect [ 3 ] . y = Y1 ;
m_rect [ 3 ] . z = Z ;
m_rect [ 3 ] . w = W ;
const float scaleS = 1.0f / _params . srcWidth ;
const float scaleT = 1.0f / _params . srcHeight ;
const float S0 = _params . srcX0 * scaleS ;
const float S1 = _params . srcX1 * scaleS ;
const float T0 = _params . srcY0 * scaleT ;
const float T1 = _params . srcY1 * scaleT ;
m_rect [ 0 ] . s0 = S0 ;
m_rect [ 0 ] . t0 = T0 ;
m_rect [ 1 ] . s0 = S1 ;
m_rect [ 1 ] . t0 = T0 ;
m_rect [ 2 ] . s0 = S0 ;
m_rect [ 2 ] . t0 = T1 ;
m_rect [ 3 ] . s0 = S1 ;
m_rect [ 3 ] . t0 = T1 ;
for ( u32 i = 0 ; i < 2 ; + + i ) {
CachedTexture * tex = _params . tex [ i ] ;
if ( tex = = nullptr )
continue ;
Context : : TexParameters texParams ;
texParams . handle = graphics : : ObjectHandle ( tex - > glName ) ;
texParams . textureUnitIndex = graphics : : textureIndices : : Tex [ i ] ;
texParams . target = tex - > frameBufferTexture = = CachedTexture : : fbMultiSample ?
graphics : : target : : TEXTURE_2D_MULTISAMPLE : graphics : : target : : TEXTURE_2D ;
texParams . minFilter = _params . filter ;
texParams . magFilter = _params . filter ;
texParams . wrapS = graphics : : textureParameters : : WRAP_CLAMP_TO_EDGE ;
texParams . wrapT = graphics : : textureParameters : : WRAP_CLAMP_TO_EDGE ;
gfxContext . setTextureParameters ( texParams ) ;
}
gfxContext . setViewport ( 0 , 0 , _params . dstWidth , _params . dstHeight ) ;
gfxContext . enable ( graphics : : enable : : CULL_FACE , false ) ;
gfxContext . enable ( graphics : : enable : : BLEND , false ) ;
gfxContext . enable ( graphics : : enable : : DEPTH_TEST , false ) ;
gfxContext . enable ( graphics : : enable : : SCISSOR_TEST , false ) ;
gfxContext . enableDepthWrite ( false ) ;
Context : : DrawRectParameters rectParams ;
rectParams . mode = drawmode : : TRIANGLE_STRIP ;
rectParams . rectColor . fill ( 0.0f ) ;
rectParams . verticesCount = 4 ;
rectParams . vertices = m_rect ;
rectParams . combiner = _params . combiner ;
2017-01-18 15:39:10 +00:00
_params . combiner - > activate ( ) ;
2017-01-14 08:58:14 +00:00
gfxContext . drawRects ( rectParams ) ;
gSP . changed | = CHANGED_GEOMETRYMODE | CHANGED_VIEWPORT ;
gDP . changed | = CHANGED_RENDERMODE | CHANGED_TILE | CHANGED_COMBINE | CHANGED_SCISSOR ;
2017-01-14 10:08:02 +00:00
}
void GraphicsDrawer : : blitOrCopyTexturedRect ( const BlitOrCopyRectParams & _params )
{
Context : : BlitFramebuffersParams blitParams ;
blitParams . readBuffer = _params . readBuffer ;
blitParams . drawBuffer = _params . drawBuffer ;
blitParams . srcX0 = _params . srcX0 ;
blitParams . srcX1 = _params . srcX1 ;
blitParams . dstX0 = _params . dstX0 ;
blitParams . dstX1 = _params . dstX1 ;
blitParams . srcY0 = _params . srcY0 ;
blitParams . srcY1 = _params . srcY1 ;
blitParams . dstY0 = _params . dstY0 ;
blitParams . dstY1 = _params . dstY1 ;
blitParams . mask = _params . mask ;
blitParams . filter = _params . filter ;
if ( gfxContext . blitFramebuffers ( blitParams ) )
return ;
2017-01-15 07:57:25 +00:00
gfxContext . bindFramebuffer ( bufferTarget : : READ_FRAMEBUFFER , _params . readBuffer ) ;
gfxContext . bindFramebuffer ( bufferTarget : : DRAW_FRAMEBUFFER , _params . drawBuffer ) ;
2017-01-14 10:08:02 +00:00
copyTexturedRect ( _params ) ;
}
2017-01-14 14:24:48 +00:00
void GraphicsDrawer : : _initStates ( )
{
gfxContext . enable ( enable : : CULL_FACE , false ) ;
gfxContext . enable ( enable : : SCISSOR_TEST , true ) ;
gfxContext . enableDepthWrite ( false ) ;
gfxContext . setDepthCompare ( compare : : ALWAYS ) ;
if ( config . frameBufferEmulation . N64DepthCompare ! = 0 ) {
gfxContext . enable ( enable : : DEPTH_TEST , false ) ;
gfxContext . enable ( enable : : POLYGON_OFFSET_FILL , false ) ;
}
else {
gfxContext . enable ( enable : : DEPTH_TEST , true ) ;
# ifdef ANDROID
if ( config . generalEmulation . forcePolygonOffset ! = 0 )
gfxContext . setPolygonOffset ( config . generalEmulation . polygonOffsetFactor , config . generalEmulation . polygonOffsetUnits ) ;
else
# endif
gfxContext . setPolygonOffset ( - 3.0f , - 3.0f ) ;
}
DisplayWindow & wnd = DisplayWindow : : get ( ) ;
glViewport ( 0 , wnd . getHeightOffset ( ) , wnd . getScreenWidth ( ) , wnd . getScreenHeight ( ) ) ;
gfxContext . clearColorBuffer ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
srand ( time ( nullptr ) ) ;
wnd . swapBuffers ( ) ;
}
2017-01-14 15:11:19 +00:00
void GraphicsDrawer : : _setSpecialTexrect ( ) const
{
const char * name = RSP . romname ;
if ( strstr ( name , ( const char * ) " Beetle " ) | | strstr ( name , ( const char * ) " BEETLE " ) | | strstr ( name , ( const char * ) " HSV " )
| | strstr ( name , ( const char * ) " DUCK DODGERS " ) | | strstr ( name , ( const char * ) " DAFFY DUCK " ) )
texturedRectSpecial = texturedRectShadowMap ;
else if ( strstr ( name , ( const char * ) " Perfect Dark " ) | | strstr ( name , ( const char * ) " PERFECT DARK " ) )
texturedRectSpecial = texturedRectDepthBufferCopy ; // See comments to that function!
else if ( strstr ( name , ( const char * ) " CONKER BFD " ) )
texturedRectSpecial = texturedRectCopyToItself ;
else if ( strstr ( name , ( const char * ) " YOSHI STORY " ) )
texturedRectSpecial = texturedRectBGCopy ;
else if ( strstr ( name , ( const char * ) " PAPER MARIO " ) | | strstr ( name , ( const char * ) " MARIO STORY " ) )
texturedRectSpecial = texturedRectPaletteMod ;
else if ( strstr ( name , ( const char * ) " ZELDA " ) )
texturedRectSpecial = texturedRectMonochromeBackground ;
else
texturedRectSpecial = nullptr ;
}
void GraphicsDrawer : : _initData ( )
{
_setSpecialTexrect ( ) ;
textureCache ( ) . init ( ) ;
DepthBuffer_Init ( ) ;
FrameBuffer_Init ( ) ;
Combiner_Init ( ) ;
TFH . init ( ) ;
PostProcessor : : get ( ) . init ( ) ;
g_zlutTexture . init ( ) ;
g_noiseTexture . init ( ) ;
g_paletteTexture . init ( ) ;
perf . reset ( ) ;
FBInfo : : fbInfo . reset ( ) ;
m_texrectDrawer . init ( ) ;
m_drawingState = DrawingState : : None ;
2017-01-15 07:57:25 +00:00
m_bImageTexture = gfxContext . isSupported ( SpecialFeatures : : ImageTextures ) ;
2017-01-14 15:11:19 +00:00
gSP . changed = gDP . changed = 0xFFFFFFFF ;
memset ( triangles . vertices . data ( ) , 0 , triangles . vertices . size ( ) * sizeof ( SPVertex ) ) ;
triangles . elements . fill ( 0 ) ;
for ( auto vtx : triangles . vertices )
vtx . w = 1.0f ;
triangles . num = 0 ;
}
void GraphicsDrawer : : _destroyData ( )
{
m_drawingState = DrawingState : : None ;
m_texrectDrawer . destroy ( ) ;
g_paletteTexture . destroy ( ) ;
g_zlutTexture . destroy ( ) ;
g_noiseTexture . destroy ( ) ;
PostProcessor : : get ( ) . destroy ( ) ;
if ( TFH . optionsChanged ( ) )
TFH . shutdown ( ) ;
Combiner_Destroy ( ) ;
FrameBuffer_Destroy ( ) ;
DepthBuffer_Destroy ( ) ;
textureCache ( ) . destroy ( ) ;
}