2013-03-15 20:22:17 +00:00
// Copyright (c) 2012- PPSSPP Project.
// 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, version 2.0 or later versions.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2012-11-24 14:19:29 +00:00
# include "StateMapping.h"
2013-02-04 22:39:09 +00:00
# include "native/gfx_es2/gl_state.h"
2012-12-21 15:49:42 +00:00
2013-02-04 22:39:09 +00:00
# include "GPU/Math3D.h"
# include "GPU/GPUState.h"
# include "GPU/ge_constants.h"
# include "Core/System.h"
# include "Core/Config.h"
2013-04-30 07:04:00 +00:00
# include "Core/Reporting.h"
2012-12-21 15:49:42 +00:00
# include "DisplayListInterpreter.h"
# include "ShaderManager.h"
2013-01-19 16:05:08 +00:00
# include "TextureCache.h"
2013-03-15 22:24:13 +00:00
# include "Framebuffer.h"
2012-11-24 14:19:29 +00:00
2013-03-15 20:22:17 +00:00
static const GLushort aLookup [ 11 ] = {
2012-11-24 14:19:29 +00:00
GL_DST_COLOR ,
GL_ONE_MINUS_DST_COLOR ,
GL_SRC_ALPHA ,
GL_ONE_MINUS_SRC_ALPHA ,
GL_DST_ALPHA ,
GL_ONE_MINUS_DST_ALPHA ,
GL_SRC_ALPHA , // should be 2x
GL_ONE_MINUS_SRC_ALPHA , // should be 2x
GL_DST_ALPHA , // should be 2x
2012-11-25 14:49:37 +00:00
GL_ONE_MINUS_DST_ALPHA , // should be 2x - and COLOR?
GL_CONSTANT_COLOR , // FIXA
2012-11-24 14:19:29 +00:00
} ;
2013-03-15 20:22:17 +00:00
static const GLushort bLookup [ 11 ] = {
2012-11-24 14:19:29 +00:00
GL_SRC_COLOR ,
GL_ONE_MINUS_SRC_COLOR ,
GL_SRC_ALPHA ,
GL_ONE_MINUS_SRC_ALPHA ,
GL_DST_ALPHA ,
GL_ONE_MINUS_DST_ALPHA ,
GL_SRC_ALPHA , // should be 2x
GL_ONE_MINUS_SRC_ALPHA , // should be 2x
GL_DST_ALPHA , // should be 2x
GL_ONE_MINUS_DST_ALPHA , // should be 2x
2012-11-25 14:49:37 +00:00
GL_CONSTANT_COLOR , // FIXB
2012-11-24 14:19:29 +00:00
} ;
2013-01-20 12:15:46 +00:00
2013-03-15 20:22:17 +00:00
static const GLushort eqLookup [ ] = {
2012-11-24 14:19:29 +00:00
GL_FUNC_ADD ,
GL_FUNC_SUBTRACT ,
GL_FUNC_REVERSE_SUBTRACT ,
2012-11-26 03:25:14 +00:00
# if defined(USING_GLES2)
2012-11-24 14:19:29 +00:00
GL_FUNC_ADD ,
GL_FUNC_ADD ,
# else
GL_MIN ,
GL_MAX ,
# endif
GL_FUNC_ADD , // should be abs(diff)
} ;
2013-03-15 20:22:17 +00:00
static const GLushort cullingMode [ ] = {
2012-11-24 14:19:29 +00:00
GL_BACK ,
GL_FRONT ,
} ;
2013-03-15 20:22:17 +00:00
static const GLushort ztests [ ] = {
2012-11-24 14:19:29 +00:00
GL_NEVER , GL_ALWAYS , GL_EQUAL , GL_NOTEQUAL ,
GL_LESS , GL_LEQUAL , GL_GREATER , GL_GEQUAL ,
2012-11-26 03:25:14 +00:00
} ;
2012-12-21 15:49:42 +00:00
2013-03-15 20:22:17 +00:00
static const GLushort stencilOps [ ] = {
2013-01-12 16:20:00 +00:00
GL_KEEP ,
GL_ZERO ,
GL_REPLACE ,
GL_INVERT ,
GL_INCR_WRAP ,
GL_DECR_WRAP , // don't know if these should be wrap or not
GL_KEEP , // reserved
GL_KEEP , // reserved
} ;
2012-12-21 15:49:42 +00:00
2013-05-01 15:00:52 +00:00
static GLenum blendColor2Func ( u32 fix ) {
if ( fix = = 0xFFFFFF )
return GL_ONE ;
if ( fix = = 0 )
return GL_ZERO ;
2013-07-13 09:46:44 +00:00
Vec3 fix3 = Vec3 : : FromRGB ( fix ) ;
2013-05-01 15:00:52 +00:00
if ( fix3 . x > = 0.99 & & fix3 . y > = 0.99 & & fix3 . z > = 0.99 )
return GL_ONE ;
else if ( fix3 . x < = 0.01 & & fix3 . y < = 0.01 & & fix3 . z < = 0.01 )
return GL_ZERO ;
return GL_INVALID_ENUM ;
}
static bool blendColorSimilar ( Vec3 a , Vec3 b , float margin = 0.1f ) {
Vec3 diff = a - b ;
if ( fabsf ( diff . x ) < = margin & & fabsf ( diff . y ) < = margin & & fabsf ( diff . z ) < = margin )
return true ;
return false ;
}
2013-01-30 19:40:26 +00:00
void TransformDrawEngine : : ApplyDrawState ( int prim ) {
2012-12-21 15:49:42 +00:00
// TODO: All this setup is soon so expensive that we'll need dirty flags, or simply do it in the command writes where we detect dirty by xoring. Silly to do all this work on every drawcall.
2013-01-19 16:05:08 +00:00
if ( gstate_c . textureChanged ) {
2013-07-22 01:13:55 +00:00
if ( gstate . isTextureMapEnabled ( ) ) {
2013-01-30 19:40:26 +00:00
textureCache_ - > SetTexture ( ) ;
2013-01-19 16:05:08 +00:00
}
gstate_c . textureChanged = false ;
}
2012-12-21 15:49:42 +00:00
// TODO: The top bit of the alpha channel should be written to the stencil bit somehow. This appears to require very expensive multipass rendering :( Alternatively, one could do a
// single fullscreen pass that converts alpha to stencil (or 2 passes, to set both the 0 and 1 values) very easily.
// Set blend
2013-02-27 14:36:09 +00:00
bool wantBlend = ! gstate . isModeClear ( ) & & gstate . isAlphaBlendEnabled ( ) ;
2012-12-21 15:49:42 +00:00
glstate . blend . set ( wantBlend ) ;
2013-02-21 20:52:12 +00:00
if ( wantBlend ) {
2012-12-21 15:49:42 +00:00
// This can't be done exactly as there are several PSP blend modes that are impossible to do on OpenGL ES 2.0, and some even on regular OpenGL for desktop.
// HOWEVER - we should be able to approximate the 2x modes in the shader, although they will clip wrongly.
// Examples of seen unimplementable blend states:
// Mortal Kombat Unchained: FixA=0000ff FixB=000080 FuncA=10 FuncB=10
int blendFuncA = gstate . getBlendFuncA ( ) ;
int blendFuncB = gstate . getBlendFuncB ( ) ;
int blendFuncEq = gstate . getBlendEq ( ) ;
2013-01-20 12:15:46 +00:00
if ( blendFuncA > GE_SRCBLEND_FIXA ) blendFuncA = GE_SRCBLEND_FIXA ;
if ( blendFuncB > GE_DSTBLEND_FIXB ) blendFuncB = GE_DSTBLEND_FIXB ;
2012-12-21 15:49:42 +00:00
2013-05-01 15:00:52 +00:00
// Shortcut by using GL_ONE where possible, no need to set blendcolor
GLuint glBlendFuncA = blendFuncA = = GE_SRCBLEND_FIXA ? blendColor2Func ( gstate . getFixA ( ) ) : aLookup [ blendFuncA ] ;
GLuint glBlendFuncB = blendFuncB = = GE_DSTBLEND_FIXB ? blendColor2Func ( gstate . getFixB ( ) ) : bLookup [ blendFuncB ] ;
if ( blendFuncA = = GE_SRCBLEND_FIXA | | blendFuncB = = GE_DSTBLEND_FIXB ) {
2013-07-13 09:46:44 +00:00
Vec3 fixA = Vec3 : : FromRGB ( gstate . getFixA ( ) ) ;
Vec3 fixB = Vec3 : : FromRGB ( gstate . getFixB ( ) ) ;
2012-12-21 15:49:42 +00:00
if ( glBlendFuncA = = GL_INVALID_ENUM & & glBlendFuncB ! = GL_INVALID_ENUM ) {
// Can use blendcolor trivially.
2013-05-01 15:00:52 +00:00
const float blendColor [ 4 ] = { fixA . x , fixA . y , fixA . z , 1.0f } ;
2012-12-21 15:49:42 +00:00
glstate . blendColor . set ( blendColor ) ;
glBlendFuncA = GL_CONSTANT_COLOR ;
} else if ( glBlendFuncA ! = GL_INVALID_ENUM & & glBlendFuncB = = GL_INVALID_ENUM ) {
// Can use blendcolor trivially.
2013-05-01 15:00:52 +00:00
const float blendColor [ 4 ] = { fixB . x , fixB . y , fixB . z , 1.0f } ;
2012-12-21 15:49:42 +00:00
glstate . blendColor . set ( blendColor ) ;
glBlendFuncB = GL_CONSTANT_COLOR ;
2013-05-01 15:00:52 +00:00
} else if ( glBlendFuncA = = GL_INVALID_ENUM & & glBlendFuncB = = GL_INVALID_ENUM ) {
2013-07-13 09:46:44 +00:00
if ( blendColorSimilar ( fixA , Vec3 : : AssignToAll ( 1.0f ) - fixB ) ) {
2012-12-21 15:49:42 +00:00
glBlendFuncA = GL_CONSTANT_COLOR ;
glBlendFuncB = GL_ONE_MINUS_CONSTANT_COLOR ;
2013-05-01 15:00:52 +00:00
const float blendColor [ 4 ] = { fixA . x , fixA . y , fixA . z , 1.0f } ;
2012-12-21 15:49:42 +00:00
glstate . blendColor . set ( blendColor ) ;
2013-05-01 15:00:52 +00:00
} else if ( blendColorSimilar ( fixA , fixB ) ) {
2012-12-21 15:49:42 +00:00
glBlendFuncA = GL_CONSTANT_COLOR ;
glBlendFuncB = GL_CONSTANT_COLOR ;
2013-05-01 15:00:52 +00:00
const float blendColor [ 4 ] = { fixA . x , fixA . y , fixA . z , 1.0f } ;
2012-12-21 15:49:42 +00:00
glstate . blendColor . set ( blendColor ) ;
} else {
2013-04-30 07:04:00 +00:00
static bool didReportBlend = false ;
if ( ! didReportBlend )
Reporting : : ReportMessage ( " ERROR INVALID blendcolorstate: FixA=%06x FixB=%06x FuncA=%i FuncB=%i " , gstate . getFixA ( ) , gstate . getFixB ( ) , gstate . getBlendFuncA ( ) , gstate . getBlendFuncB ( ) ) ;
didReportBlend = true ;
2012-12-21 15:49:42 +00:00
DEBUG_LOG ( HLE , " ERROR INVALID blendcolorstate: FixA=%06x FixB=%06x FuncA=%i FuncB=%i " , gstate . getFixA ( ) , gstate . getFixB ( ) , gstate . getBlendFuncA ( ) , gstate . getBlendFuncB ( ) ) ;
2013-05-01 15:00:52 +00:00
// Let's approximate, at least. Close is better than totally off.
2013-07-13 09:46:44 +00:00
const bool nearZeroA = blendColorSimilar ( fixA , Vec3 : : AssignToAll ( 0.0f ) , 0.25f ) ;
const bool nearZeroB = blendColorSimilar ( fixB , Vec3 : : AssignToAll ( 0.0f ) , 0.25f ) ;
if ( nearZeroA | | blendColorSimilar ( fixA , Vec3 : : AssignToAll ( 1.0f ) , 0.25f ) ) {
2013-05-01 15:00:52 +00:00
glBlendFuncA = nearZeroA ? GL_ZERO : GL_ONE ;
glBlendFuncB = GL_CONSTANT_COLOR ;
const float blendColor [ 4 ] = { fixB . x , fixB . y , fixB . z , 1.0f } ;
glstate . blendColor . set ( blendColor ) ;
// We need to pick something. Let's go with A as the fixed color.
2013-05-01 07:55:30 +00:00
} else {
2013-05-01 15:00:52 +00:00
glBlendFuncA = GL_CONSTANT_COLOR ;
glBlendFuncB = nearZeroB ? GL_ZERO : GL_ONE ;
const float blendColor [ 4 ] = { fixA . x , fixA . y , fixA . z , 1.0f } ;
glstate . blendColor . set ( blendColor ) ;
2013-05-01 07:55:30 +00:00
}
2012-12-21 15:49:42 +00:00
}
}
}
2013-05-01 15:00:52 +00:00
// At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow.
glstate . blendFunc . set ( glBlendFuncA , glBlendFuncB ) ;
glstate . blendEquation . set ( eqLookup [ blendFuncEq ] ) ;
2012-12-21 15:49:42 +00:00
}
2013-02-25 16:41:37 +00:00
// Set Dither
2013-03-26 06:50:37 +00:00
if ( gstate . isDitherEnabled ( ) ) {
glstate . dither . enable ( ) ;
glstate . dither . set ( GL_TRUE ) ;
2013-03-26 07:36:13 +00:00
} else
glstate . dither . disable ( ) ;
2013-03-15 21:24:16 +00:00
2013-02-25 16:41:37 +00:00
// Set ColorMask/Stencil/Depth
2013-02-21 20:52:12 +00:00
if ( gstate . isModeClear ( ) ) {
2013-07-01 15:03:34 +00:00
2013-07-14 16:10:43 +00:00
// Set Cull
glstate . cullFace . set ( GL_FALSE ) ;
2013-07-01 15:03:34 +00:00
// Depth Test
bool depthMask = ( gstate . clearmode > > 10 ) & 1 ;
2013-07-24 16:01:00 +00:00
glstate . depthTest . enable ( ) ;
glstate . depthFunc . set ( GL_ALWAYS ) ;
glstate . depthWrite . set ( depthMask ? GL_TRUE : GL_FALSE ) ;
2013-07-01 15:03:34 +00:00
// Color Test
2013-02-23 15:26:58 +00:00
bool colorMask = ( gstate . clearmode > > 8 ) & 1 ;
2013-02-21 20:52:12 +00:00
bool alphaMask = ( gstate . clearmode > > 9 ) & 1 ;
2013-02-23 15:26:58 +00:00
glstate . colorMask . set ( colorMask , colorMask , colorMask , alphaMask ) ;
2013-01-12 11:51:09 +00:00
2013-07-01 15:03:34 +00:00
// Stencil Test
2013-07-03 15:57:33 +00:00
if ( alphaMask ) {
glstate . stencilTest . enable ( ) ;
glstate . stencilOp . set ( GL_REPLACE , GL_REPLACE , GL_REPLACE ) ;
glstate . stencilFunc . set ( GL_ALWAYS , 0 , 0xFF ) ;
} else {
glstate . stencilTest . disable ( ) ;
}
2013-01-12 16:20:00 +00:00
2013-05-08 09:28:53 +00:00
} else {
2013-07-14 16:10:43 +00:00
// Set cull
bool wantCull = ! gstate . isModeThrough ( ) & & prim ! = GE_PRIM_RECTANGLES & & gstate . isCullEnabled ( ) ;
glstate . cullFace . set ( wantCull ) ;
if ( wantCull )
glstate . cullFaceMode . set ( cullingMode [ gstate . getCullMode ( ) ] ) ;
2013-07-01 15:03:34 +00:00
// Depth Test
2013-02-23 18:18:18 +00:00
if ( gstate . isDepthTestEnabled ( ) ) {
glstate . depthTest . enable ( ) ;
glstate . depthFunc . set ( ztests [ gstate . getDepthTestFunc ( ) ] ) ;
2013-07-01 15:03:34 +00:00
glstate . depthWrite . set ( gstate . isDepthWriteEnabled ( ) ? GL_TRUE : GL_FALSE ) ;
} else
2013-02-23 18:18:18 +00:00
glstate . depthTest . disable ( ) ;
2013-07-01 15:03:34 +00:00
2013-02-21 20:52:12 +00:00
// PSP color/alpha mask is per bit but we can only support per byte.
// But let's do that, at least. And let's try a threshold.
bool rmask = ( gstate . pmskc & 0xFF ) < 128 ;
bool gmask = ( ( gstate . pmskc > > 8 ) & 0xFF ) < 128 ;
bool bmask = ( ( gstate . pmskc > > 16 ) & 0xFF ) < 128 ;
bool amask = ( gstate . pmska & 0xFF ) < 128 ;
glstate . colorMask . set ( rmask , gmask , bmask , amask ) ;
2013-03-27 10:21:02 +00:00
2013-07-01 15:03:34 +00:00
// Stencil Test
2013-02-21 20:52:12 +00:00
if ( gstate . isStencilTestEnabled ( ) ) {
glstate . stencilTest . enable ( ) ;
2013-07-22 01:54:17 +00:00
glstate . stencilFunc . set ( ztests [ gstate . getStencilTestFunction ( ) ] ,
gstate . getStencilTestRef ( ) ,
gstate . getStencilTestMask ( ) ) ;
glstate . stencilOp . set ( stencilOps [ gstate . getStencilOpSFail ( ) ] , // stencil fail
stencilOps [ gstate . getStencilOpZFail ( ) ] , // depth fail
stencilOps [ gstate . getStencilOpZPass ( ) ] ) ; // depth pass
2013-07-01 15:03:34 +00:00
} else
2013-02-21 20:52:12 +00:00
glstate . stencilTest . disable ( ) ;
2013-07-01 15:03:34 +00:00
2013-02-21 20:52:12 +00:00
}
2012-12-21 15:49:42 +00:00
2013-03-15 20:22:17 +00:00
float renderWidthFactor , renderHeightFactor ;
float renderWidth , renderHeight ;
float renderX , renderY ;
2013-07-21 20:15:18 +00:00
bool useBufferedRendering = g_Config . iRenderingMode ! = 0 ? 1 : 0 ;
if ( useBufferedRendering ) {
2013-07-29 09:12:02 +00:00
renderX = 0.0f ;
renderY = 0.0f ;
2013-06-20 20:18:44 +00:00
renderWidth = framebufferManager_ - > GetRenderWidth ( ) ;
renderHeight = framebufferManager_ - > GetRenderHeight ( ) ;
2013-03-15 20:22:17 +00:00
renderWidthFactor = ( float ) renderWidth / framebufferManager_ - > GetTargetWidth ( ) ;
renderHeightFactor = ( float ) renderHeight / framebufferManager_ - > GetTargetHeight ( ) ;
2013-02-04 22:39:09 +00:00
} else {
// TODO: Aspect-ratio aware and centered
2013-03-15 20:22:17 +00:00
float pixelW = PSP_CoreParameter ( ) . pixelWidth ;
float pixelH = PSP_CoreParameter ( ) . pixelHeight ;
CenterRect ( & renderX , & renderY , & renderWidth , & renderHeight , 480 , 272 , pixelW , pixelH ) ;
2013-07-29 09:12:02 +00:00
renderWidthFactor = renderWidth / 480.0f ;
renderHeightFactor = renderHeight / 272.0f ;
2013-02-04 22:39:09 +00:00
}
2013-03-15 20:22:17 +00:00
2012-12-21 15:49:42 +00:00
bool throughmode = ( gstate . vertType & GE_VTYPE_THROUGH_MASK ) ! = 0 ;
2013-03-15 21:24:16 +00:00
// Scissor
2013-07-17 21:12:46 +00:00
int scissorX1 = ( gstate . getScissorX1 ( ) ) ;
int scissorY1 = ( gstate . getScissorY1 ( ) ) ;
int scissorX2 = ( gstate . getScissorX2 ( ) ) ;
int scissorY2 = ( gstate . getScissorY2 ( ) ) ;
2013-03-15 21:24:16 +00:00
// This is a bit of a hack as the render buffer isn't always that size
2013-03-24 13:25:38 +00:00
if ( scissorX1 = = 0 & & scissorY1 = = 0
& & scissorX2 > = ( int ) ( gstate_c . curRTWidth - 1 )
& & scissorY2 > = ( int ) ( gstate_c . curRTHeight - 1 ) ) {
2013-03-15 21:24:16 +00:00
glstate . scissorTest . disable ( ) ;
} else {
glstate . scissorTest . enable ( ) ;
glstate . scissorRect . set (
renderX + scissorX1 * renderWidthFactor ,
renderY + renderHeight - ( scissorY2 * renderHeightFactor ) ,
2013-07-17 21:12:46 +00:00
( scissorX2 - scissorX1 + 1 ) * renderWidthFactor ,
( scissorY2 - scissorY1 + 1 ) * renderHeightFactor ) ;
2013-03-15 21:24:16 +00:00
}
2013-03-15 20:22:17 +00:00
/*
2012-12-21 15:49:42 +00:00
int regionX1 = gstate . region1 & 0x3FF ;
int regionY1 = ( gstate . region1 > > 10 ) & 0x3FF ;
int regionX2 = ( gstate . region2 & 0x3FF ) + 1 ;
int regionY2 = ( ( gstate . region2 > > 10 ) & 0x3FF ) + 1 ;
2013-03-15 20:22:17 +00:00
*/
int regionX1 = 0 ;
int regionY1 = 0 ;
2013-03-15 23:40:37 +00:00
int regionX2 = gstate_c . curRTWidth ;
int regionY2 = gstate_c . curRTHeight ;
2012-12-21 15:49:42 +00:00
float offsetX = ( float ) ( gstate . offsetx & 0xFFFF ) / 16.0f ;
float offsetY = ( float ) ( gstate . offsety & 0xFFFF ) / 16.0f ;
if ( throughmode ) {
// No viewport transform here. Let's experiment with using region.
2013-03-15 21:24:16 +00:00
glstate . viewport . set (
renderX + ( 0 + regionX1 ) * renderWidthFactor ,
renderY + ( 0 - regionY1 ) * renderHeightFactor ,
( regionX2 - regionX1 ) * renderWidthFactor ,
( regionY2 - regionY1 ) * renderHeightFactor ) ;
2013-02-23 15:26:58 +00:00
glstate . depthRange . set ( 0.0f , 1.0f ) ;
2012-12-21 15:49:42 +00:00
} else {
// These we can turn into a glViewport call, offset by offsetX and offsetY. Math after.
float vpXa = getFloat24 ( gstate . viewportx1 ) ;
float vpXb = getFloat24 ( gstate . viewportx2 ) ;
float vpYa = getFloat24 ( gstate . viewporty1 ) ;
float vpYb = getFloat24 ( gstate . viewporty2 ) ;
// The viewport transform appears to go like this:
// Xscreen = -offsetX + vpXb + vpXa * Xview
// Yscreen = -offsetY + vpYb + vpYa * Yview
// Zscreen = vpZb + vpZa * Zview
// This means that to get the analogue glViewport we must:
float vpX0 = vpXb - offsetX - vpXa ;
float vpY0 = vpYb - offsetY + vpYa ; // Need to account for sign of Y
2013-07-29 09:12:02 +00:00
gstate_c . vpWidth = vpXa * 2.0f ;
gstate_c . vpHeight = - vpYa * 2.0f ;
2012-12-21 15:49:42 +00:00
float vpWidth = fabsf ( gstate_c . vpWidth ) ;
float vpHeight = fabsf ( gstate_c . vpHeight ) ;
2012-12-25 12:47:59 +00:00
vpX0 * = renderWidthFactor ;
vpY0 * = renderHeightFactor ;
vpWidth * = renderWidthFactor ;
vpHeight * = renderHeightFactor ;
2012-12-21 15:49:42 +00:00
2013-07-27 10:45:48 +00:00
vpX0 = ( vpXb - offsetX - fabsf ( vpXa ) ) * renderWidthFactor ;
2012-12-21 15:49:42 +00:00
// Flip vpY0 to match the OpenGL coordinate system.
2013-07-27 10:45:48 +00:00
vpY0 = renderHeight - ( vpYb - offsetY + fabsf ( vpYa ) ) * renderHeightFactor ;
2013-07-26 22:24:59 +00:00
2013-03-15 20:22:17 +00:00
glstate . viewport . set ( vpX0 + renderX , vpY0 + renderY , vpWidth , vpHeight ) ;
2012-12-21 15:49:42 +00:00
// Sadly, as glViewport takes integers, we will not be able to support sub pixel offsets this way. But meh.
2012-12-25 12:47:59 +00:00
// shaderManager_->DirtyUniform(DIRTY_PROJMATRIX);
2013-02-09 19:53:32 +00:00
2013-02-23 15:26:58 +00:00
float zScale = getFloat24 ( gstate . viewportz1 ) / 65535.0f ;
float zOff = getFloat24 ( gstate . viewportz2 ) / 65535.0f ;
2013-02-09 19:53:32 +00:00
float depthRangeMin = zOff - zScale ;
float depthRangeMax = zOff + zScale ;
glstate . depthRange . set ( depthRangeMin , depthRangeMax ) ;
2012-12-21 15:49:42 +00:00
}
}