2009-02-09 21:15:56 +00:00
/* ZeroGS KOSMOS
* Copyright ( C ) 2005 - 2006 zerofrog @ gmail . com
*
* 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 of the License , 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 this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# if defined(_WIN32)
# include <windows.h>
# include <aviUtil.h>
# include "resource.h"
# endif
# include <stdio.h>
# include <malloc.h>
# include <assert.h>
# include <stdlib.h>
# include <string.h>
# include "GS.h"
# include "Mem.h"
# include "x86.h"
# include "zerogs.h"
# include "zpipe.h"
# include "ZeroGSShaders/zerogsshaders.h"
# include "targets.h"
# include "rasterfont.h" // simple font
# define VB_BUFFERSIZE 0x400
# define VB_NUMBUFFERS 512
# define SIZEOF_VB sizeof(ZeroGS::VB) //((u32)((u8*)&vb[0].buffers-(u8*)&vb[0]))
# define MINMAX_SHIFT 3
# define MAX_ACTIVECLUTS 16
# define ZEROGS_SAVEVER 0xaa000005
# define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80
# define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush)
# define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush)
# define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush)
//#define STENCIL_PBE 16
# define STENCIL_CLEAR (2|4|8|16)
# define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0]))
using namespace ZeroGS ;
extern u32 g_nGenVars , g_nTexVars , g_nAlphaVars , g_nResolve ;
extern char * libraryName ;
extern int g_nFrame , g_nRealFrame ;
extern float fFPS ;
extern unsigned char zgsrevision , zgsbuild , zgsminor ;
BOOL g_bDisplayMsg = 1 ;
# ifdef _WIN32
HDC hDC = NULL ; // Private GDI Device Context
HGLRC hRC = NULL ; // Permanent Rendering Context
# endif
BOOL g_bCRTCBilinear = TRUE ;
BOOL g_bSaveFlushedFrame = 0 ;
BOOL g_bIsLost = 0 ;
int g_nFrameRender = 10 ;
int g_nFramesSkipped = 0 ;
# ifdef RELEASE_TO_PUBLIC
# define INC_GENVARS()
# define INC_TEXVARS()
# define INC_ALPHAVARS()
# define INC_RESOLVE()
# define g_bUpdateEffect 0
# define g_bSaveTex 0
# define g_bSaveTrans 0
# define g_bSaveFrame 0
# define g_bSaveFinalFrame 0
# define g_bSaveResolved 0
# else
# define INC_GENVARS() ++g_nGenVars
# define INC_TEXVARS() ++g_nTexVars
# define INC_ALPHAVARS() ++g_nAlphaVars
# define INC_RESOLVE() ++g_nResolve
BOOL g_bSaveTrans = 0 ;
BOOL g_bUpdateEffect = 0 ;
BOOL g_bSaveTex = 0 ; // saves the curent texture
BOOL g_bSaveFrame = 0 ; // saves the current psurfTarget
BOOL g_bSaveFinalFrame = 0 ; // saves the input to the CRTC
BOOL g_bSaveResolved = 0 ;
# ifdef _WIN32
//#define EFFECT_NAME "f:\\ps2dev\\svn\\pcsx2\\ZeroGS\\opengl\\"
char * EFFECT_DIR = " C: \\ programming \\ ps2dev \\ zerogs \\ opengl \\ " ;
char * EFFECT_NAME = " C: \\ programming \\ ps2dev \\ zerogs \\ opengl \\ ps2hw.fx " ;
# else
char EFFECT_DIR [ 255 ] = " ~/pcsx2/plugins/gs/zerogs/opengl/ " ;
char EFFECT_NAME [ 255 ] = " ~/pcsx2/plugins/gs/zerogs/opengl/ps2hw.fx " ;
# endif
# endif
BOOL g_bUpdateStencil = 1 ; // only needed for dest alpha test (unfortunately, it has to be on all the time)
# define DRAW() glDrawArrays(primtype[curvb.curprim.prim], 0, curvb.nCount)
# define GL_BLEND_RGB(src, dst) { \
s_srcrgb = src ; \
s_dstrgb = dst ; \
zgsBlendFuncSeparateEXT ( s_srcrgb , s_dstrgb , s_srcalpha , s_dstalpha ) ; \
}
# define GL_BLEND_ALPHA(src, dst) { \
s_srcalpha = src ; \
s_dstalpha = dst ; \
zgsBlendFuncSeparateEXT ( s_srcrgb , s_dstrgb , s_srcalpha , s_dstalpha ) ; \
}
# define GL_BLEND_ALL(srcrgb, dstrgb, srcalpha, dstalpha) { \
s_srcrgb = srcrgb ; \
s_dstrgb = dstrgb ; \
s_srcalpha = srcalpha ; \
s_dstalpha = dstalpha ; \
zgsBlendFuncSeparateEXT ( s_srcrgb , s_dstrgb , s_srcalpha , s_dstalpha ) ; \
}
# define GL_BLEND_SET() zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha)
# define GL_ZTEST(enable) { \
if ( enable ) glEnable ( GL_DEPTH_TEST ) ; \
else glDisable ( GL_DEPTH_TEST ) ; \
}
# define GL_ALPHATEST(enable) { \
if ( enable ) glEnable ( GL_ALPHA_TEST ) ; \
else glDisable ( GL_ALPHA_TEST ) ; \
}
# define GL_BLENDEQ_RGB(eq) { \
s_rgbeq = eq ; \
zgsBlendEquationSeparateEXT ( s_rgbeq , s_alphaeq ) ; \
}
# define GL_BLENDEQ_ALPHA(eq) { \
s_alphaeq = eq ; \
zgsBlendEquationSeparateEXT ( s_rgbeq , s_alphaeq ) ; \
}
# define GL_STENCILFUNC(func, ref, mask) { \
s_stencilfunc = func ; \
s_stencilref = ref ; \
s_stencilmask = mask ; \
glStencilFunc ( func , ref , mask ) ; \
}
# define GL_STENCILFUNC_SET() glStencilFunc(s_stencilfunc, s_stencilref, s_stencilmask)
# define COLORMASK_RED 1
# define COLORMASK_GREEN 2
# define COLORMASK_BLUE 4
# define COLORMASK_ALPHA 8
# define GL_COLORMASK(mask) glColorMask(!!((mask)&COLORMASK_RED), !!((mask)&COLORMASK_GREEN), !!((mask)&COLORMASK_BLUE), !!((mask)&COLORMASK_ALPHA))
typedef void ( APIENTRYP _PFNSWAPINTERVAL ) ( int ) ;
extern int s_frameskipping ;
static u32 g_SaveFrameNum = 0 ;
BOOL g_bMakeSnapshot = 0 ;
string strSnapshot ;
int GPU_TEXWIDTH = 512 ;
float g_fiGPU_TEXWIDTH = 1 / 512.0f ;
int g_MaxTexWidth = 4096 , g_MaxTexHeight = 4096 ;
CGprogram g_vsprog = 0 , g_psprog = 0 ;
// AVI Capture
static int s_aviinit = 0 ;
static int s_avicapturing = 0 ;
inline u32 FtoDW ( float f ) { return ( * ( ( u32 * ) & f ) ) ; }
float g_fBlockMult = 1 ;
static int s_nFullscreen = 0 ;
int g_nDepthUpdateCount = 0 ;
int g_nDepthBias = 0 ;
// local alpha blending settings
static GLenum s_srcrgb , s_dstrgb , s_srcalpha , s_dstalpha ; // set by zgsBlendFuncSeparateEXT
static GLenum s_rgbeq , s_alphaeq ; // set by zgsBlendEquationSeparateEXT
static u32 s_stencilfunc , s_stencilref , s_stencilmask ;
static GLenum s_drawbuffers [ ] = { GL_COLOR_ATTACHMENT0_EXT , GL_COLOR_ATTACHMENT1_EXT } ;
# ifdef _WIN32
extern HINSTANCE hInst ;
void ( __stdcall * zgsBlendEquationSeparateEXT ) ( GLenum , GLenum ) = NULL ;
void ( __stdcall * zgsBlendFuncSeparateEXT ) ( GLenum , GLenum , GLenum , GLenum ) = NULL ;
# else
void ( APIENTRY * zgsBlendEquationSeparateEXT ) ( GLenum , GLenum ) = NULL ;
void ( APIENTRY * zgsBlendFuncSeparateEXT ) ( GLenum , GLenum , GLenum , GLenum ) = NULL ;
# endif
GLenum g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI ;
GLenum g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI ;
GLenum g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI ;
// Consts
static const GLenum primtype [ 8 ] = { GL_POINTS , GL_LINES , GL_LINES , GL_TRIANGLES , GL_TRIANGLES , GL_TRIANGLES , GL_TRIANGLES , 0xffffffff } ;
static const u32 blendalpha [ 3 ] = { GL_SRC_ALPHA , GL_DST_ALPHA , GL_CONSTANT_COLOR_EXT } ;
static const u32 blendinvalpha [ 3 ] = { GL_ONE_MINUS_SRC_ALPHA , GL_ONE_MINUS_DST_ALPHA , GL_ONE_MINUS_CONSTANT_COLOR_EXT } ;
static const int PRIMMASK = 0x0e ; // for now ignore 0x10 (AA)
static const u32 g_dwAlphaCmp [ ] = { GL_NEVER , GL_ALWAYS , GL_LESS , GL_LEQUAL , GL_EQUAL , GL_GEQUAL , GL_GREATER , GL_NOTEQUAL } ;
// used for afail case
static const u32 g_dwReverseAlphaCmp [ ] = { GL_ALWAYS , GL_NEVER , GL_GEQUAL , GL_GREATER , GL_NOTEQUAL , GL_LESS , GL_LEQUAL , GL_EQUAL } ;
static const u32 g_dwZCmp [ ] = { GL_NEVER , GL_ALWAYS , GL_GEQUAL , GL_GREATER } ;
PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL ;
PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL ;
PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL ;
PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL ;
PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL ;
PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL ;
PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL ;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL ;
PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL ;
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL ;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL ;
PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL ;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL ;
PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL ;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL ;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL ;
PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL ;
PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL ;
/////////////////////
// graphics resources
static map < string , GLbyte > mapGLExtensions ;
RasterFont * font_p = NULL ;
CGprofile cgvProf , cgfProf ;
static CGprogram pvs [ 16 ] = { NULL } ;
static FRAGMENTSHADER ppsRegular [ 4 ] , ppsTexture [ NUM_SHADERS ] ;
static FRAGMENTSHADER ppsCRTC [ 2 ] , ppsCRTC24 [ 2 ] , ppsCRTCTarg [ 2 ] ;
CGparameter g_vparamPosXY [ 2 ] = { 0 } , g_fparamFogColor = 0 ;
int g_nPixelShaderVer = 0 ; // default
static u8 * s_lpShaderResources = NULL ;
static map < int , SHADERHEADER * > mapShaderResources ;
u32 s_uFramebuffer = 0 ;
u32 s_ptexCurSet [ 2 ] = { 0 } ;
# define s_bForceTexFlush 1
static u32 s_ptexNextSet [ 2 ] = { 0 } ;
u32 ptexBlocks = 0 , ptexConv16to32 = 0 ; // holds information on block tiling
u32 ptexBilinearBlocks = 0 ;
u32 ptexConv32to16 = 0 ;
static u32 s_ptexInterlace = 0 ; // holds interlace fields
static int s_nInterlaceTexWidth = 0 ; // width of texture
static vector < u32 > s_vecTempTextures ; // temporary textures, released at the end of every frame
static BOOL s_bTexFlush = FALSE ;
static u32 ptexLogo = 0 ;
static int nLogoWidth , nLogoHeight ;
static BOOL s_bWriteDepth = FALSE ;
static BOOL s_bDestAlphaTest = FALSE ;
static int s_nLastResolveReset = 0 ;
static int s_nResolveCounts [ 30 ] = { 0 } ; // resolve counts for last 30 frames
static int s_nCurResolveIndex = 0 ;
int s_nResolved = 0 ; // number of targets resolved this frame
int g_nDepthUsed = 0 ; // ffx2 pal movies
static int s_nWriteDepthCount = 0 ;
static int s_nWireframeCount = 0 ;
static int s_nWriteDestAlphaTest = 0 ;
////////////////////
// State parameters
static float fiRendWidth , fiRendHeight ;
static Vector vAlphaBlendColor ; // used for GPU_COLOR
static u8 bNeedBlendFactorInAlpha ; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80)
static u32 s_dwColorWrite = 0xf ; // the color write mask of the current target
BOOL g_bDisplayFPS = FALSE ;
union {
struct {
u8 _bNeedAlphaColor ; // set if vAlphaBlendColor needs to be set
u8 _b2XAlphaTest ; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values
// otherwise alpha testing needs to be done separately.
u8 _bDestAlphaColor ; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1.
u8 _bAlphaClamping ; // if first bit is set, do min; if second bit, do max
} ;
u32 _bAlphaState ;
} g_vars ;
//#define bNeedAlphaColor g_vars._bNeedAlphaColor
# define b2XAlphaTest g_vars._b2XAlphaTest
# define bDestAlphaColor g_vars._bDestAlphaColor
# define bAlphaClamping g_vars._bAlphaClamping
int g_PrevBitwiseTexX = - 1 , g_PrevBitwiseTexY = - 1 ; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY
// stores the buffers for the last RenderCRTC
const float g_filog32 = 0.999f / ( 32.0f * logf ( 2.0f ) ) ;
static alphaInfo s_alphaInfo ;
CGcontext g_cgcontext ;
static int nBackbufferWidth , nBackbufferHeight ;
u8 * g_pbyGSMemory = NULL ; // 4Mb GS system mem
u8 * g_pbyGSClut = NULL ;
namespace ZeroGS
{
VB vb [ 2 ] ;
float fiTexWidth [ 2 ] , fiTexHeight [ 2 ] ; // current tex width and height
GLuint vboRect = 0 ;
vector < GLuint > g_vboBuffers ; // VBOs for all drawing commands
int g_nCurVBOIndex = 0 ;
u8 s_AAx = 0 , s_AAy = 0 ; // if AAy is set, then AAx has to be set
RenderFormatType g_RenderFormatType = RFT_float16 ;
int icurctx = - 1 ;
Vector g_vdepth = Vector ( 256.0f * 65536.0f , 65536.0f , 256.0f , 65536.0f * 65536.0f ) ;
VERTEXSHADER pvsBitBlt ;
FRAGMENTSHADER ppsBitBlt [ 2 ] , ppsBitBltDepth , ppsOne ;
FRAGMENTSHADER ppsBaseTexture , ppsConvert16to32 , ppsConvert32to16 ;
extern CRangeManager s_RangeMngr ; // manages overwritten memory
void FlushTransferRanges ( const tex0Info * ptex ) ;
RenderFormatType GetRenderFormat ( ) { return g_RenderFormatType ; }
GLenum GetRenderTargetFormat ( ) { return GetRenderFormat ( ) = = RFT_byte8 ? 4 : g_internalRGBAFloat16Fmt ; }
// returns the first and last addresses aligned to a page that cover
void GetRectMemAddress ( int & start , int & end , int psm , int x , int y , int w , int h , int bp , int bw ) ;
bool LoadEffects ( ) ;
bool LoadExtraEffects ( ) ;
FRAGMENTSHADER * LoadShadeEffect ( int type , int texfilter , int fog , int testaem , int exactcolor , const clampInfo & clamp , int context , bool * pbFailed ) ;
static int s_nNewWidth = - 1 , s_nNewHeight = - 1 ;
void ChangeDeviceSize ( int nNewWidth , int nNewHeight ) ;
void ProcessMessages ( ) ;
void RenderCustom ( float fAlpha ) ; // intro anim
struct MESSAGE
{
MESSAGE ( ) { }
MESSAGE ( const char * p , u32 dw ) { strcpy ( str , p ) ; dwTimeStamp = dw ; }
char str [ 255 ] ;
u32 dwTimeStamp ;
} ;
static list < MESSAGE > listMsgs ;
///////////////////////
// Method Prototypes //
///////////////////////
void AdjustTransToAspect ( Vector & v , int dispwidth , int dispheight ) ;
void KickPoint ( ) ;
void KickLine ( ) ;
void KickTriangle ( ) ;
void KickTriangleFan ( ) ;
void KickSprite ( ) ;
void KickDummy ( ) ;
__forceinline void SetContextTarget ( int context ) ;
// use to update the state
void SetTexVariables ( int context , FRAGMENTSHADER * pfragment , int settexint ) ;
void SetAlphaVariables ( const alphaInfo & ainfo ) ;
void ResetAlphaVariables ( ) ;
__forceinline void SetAlphaTestInt ( pixTest curtest ) ;
__forceinline void RenderAlphaTest ( const VB & curvb , CGparameter sOneColor ) ;
__forceinline void RenderStencil ( const VB & curvb , u32 dwUsingSpecialTesting ) ;
__forceinline void ProcessStencil ( const VB & curvb ) ;
__forceinline void RenderFBA ( const VB & curvb , CGparameter sOneColor ) ;
__forceinline void ProcessFBA ( const VB & curvb , CGparameter sOneColor ) ;
void ResolveInRange ( int start , int end ) ;
void ExtWrite ( ) ;
__forceinline u32 CreateInterlaceTex ( int width ) {
if ( width = = s_nInterlaceTexWidth & & s_ptexInterlace ! = 0 ) return s_ptexInterlace ;
SAFE_RELEASE_TEX ( s_ptexInterlace ) ;
s_nInterlaceTexWidth = width ;
vector < u32 > data ( width ) ;
for ( int i = 0 ; i < width ; + + i ) data [ i ] = ( i & 1 ) ? 0xffffffff : 0 ;
glGenTextures ( 1 , & s_ptexInterlace ) ;
glBindTexture ( GL_TEXTURE_RECTANGLE_NV , s_ptexInterlace ) ;
glTexImage2D ( GL_TEXTURE_RECTANGLE_NV , 0 , 4 , width , 1 , 0 , GL_RGBA , GL_UNSIGNED_BYTE , & data [ 0 ] ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
GL_REPORT_ERRORD ( ) ;
return s_ptexInterlace ;
}
void ResetRenderTarget ( int index ) {
glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT + index , GL_TEXTURE_RECTANGLE_NV , 0 , 0 ) ;
}
DrawFn drawfn [ 8 ] = { KickDummy , KickDummy , KickDummy , KickDummy ,
KickDummy , KickDummy , KickDummy , KickDummy } ;
} ; // end namespace
///////////////////
// Context State //
///////////////////
ZeroGS : : VB : : VB ( )
{
memset ( this , 0 , SIZEOF_VB ) ;
tex0 . tw = 1 ;
tex0 . th = 1 ;
}
ZeroGS : : VB : : ~ VB ( )
{
Destroy ( ) ;
}
void ZeroGS : : VB : : Destroy ( )
{
_aligned_free ( pBufferData ) ; pBufferData = NULL ; nNumVertices = 0 ;
prndr = NULL ;
pdepth = NULL ;
}
bool ZeroGS : : VB : : CheckPrim ( )
{
if ( ( PRIMMASK & prim - > _val ) ! = ( PRIMMASK & curprim . _val ) | | primtype [ prim - > prim ] ! = primtype [ curprim . prim ] )
return nCount > 0 ;
return false ;
}
// upper bound on max possible height
# define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp)) / (fbw))&~0x1f)<<((psm&2)?1:0))
# include <set>
static int maxmin = 608 ;
//static set<int> s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames
//static int s_nCurFBPSet = 0;
//static map<int, int> s_mapFrameHeights[2];
//static int s_nCurFrameMap = 0;
// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound
void ZeroGS : : VB : : CheckFrame ( int tbp )
{
static int bChanged ;
if ( bNeedZCheck ) {
PRIM_LOG ( " zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d \n " , ictx , zbuf . zbp , zbuf . psm , zbuf . zmsk ) ;
//zbuf = *zb;
}
bChanged = 0 ;
if ( bNeedFrameCheck ) {
int maxpos = 0x00100000 ;
// important to set before calling GetTarg
bNeedFrameCheck = 0 ;
bNeedZCheck = 0 ;
// add constraints of other targets
if ( gsfb . fbw > 0 ) {
maxpos = 0x00100000 - 64 * gsfb . fbp ;
// make sure texture is far away from tbp
if ( gsfb . fbp < tbp & & gsfb . fbp + 0x2000 < tbp ) {
maxpos = min ( 64 * ( tbp - gsfb . fbp ) , maxpos ) ;
}
if ( prndr ! = NULL ) {
// offroad uses 0x80 fbp which messes up targets
if ( gsfb . fbp + 0x80 < frame . fbp ) {
// special case when double buffering (hamsterball)
maxpos = min ( 64 * ( frame . fbp - gsfb . fbp ) , maxpos ) ;
}
}
if ( zbuf . zbp < tbp & & ! zbuf . zmsk ) {
maxpos = min ( ( tbp - zbuf . zbp ) * ( ( zbuf . psm & 2 ) ? 128 : 64 ) , maxpos ) ;
}
// old caching method
if ( gsfb . fbp < zbuf . zbp & & ! zbuf . zmsk ) { // zmsk necessary for KH movie
int temp = 64 * ( zbuf . zbp - gsfb . fbp ) ; //min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) );
maxpos = min ( temp , maxpos ) ;
}
maxpos / = gsfb . fbw ;
if ( gsfb . psm & 2 ) maxpos * = 2 ; ;
maxpos = min ( gsfb . fbh , maxpos ) ;
maxpos = min ( maxmin , maxpos ) ;
//? atelier iris crashes without it
if ( maxpos > 256 ) maxpos & = ~ 0x1f ;
}
else {
ERROR_LOG ( " render target null, ignoring \n " ) ;
//prndr = NULL;
//pdepth = NULL;
return ;
}
gsfb . psm & = 0xf ; // shadow tower
if ( prndr ! = NULL ) {
// render target
if ( prndr - > psm ! = gsfb . psm ) {
// behavior for dest alpha varies
ResetAlphaVariables ( ) ;
}
}
int fbh = ( scissor . y1 > > MINMAX_SHIFT ) + 1 ;
if ( fbh > 2 & & ( fbh & 1 ) ) fbh - = 1 ;
if ( ! ( gsfb . psm & 2 ) | | ! ( g_GameSettings & GAME_FULL16BITRES ) ) {
fbh = min ( fbh , maxpos ) ;
}
frame = gsfb ;
// if (frame.fbw > 1024) frame.fbw = 1024;
// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) {
// // dragon ball z
// fbh -= fbh%m_Blocks[gsfb.psm].height;
// }
if ( ! ( frame . psm & 2 ) | | ! ( g_GameSettings & GAME_FULL16BITRES ) )
frame . fbh = fbh ;
if ( ! ( frame . psm & 2 ) ) { //|| !(g_GameSettings&GAME_FULL16BITRES) ) {
if ( frame . fbh > = 512 ) {
// neopets hack
maxmin = min ( maxmin , frame . fbh ) ;
frame . fbh = maxmin ;
}
}
// mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback
/*if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) {
int considerheight = ( g_MaxRenderedHeight / 8 + 31 ) & ~ 31 ;
if ( frame . fbh > considerheight )
frame . fbh = considerheight ;
else if ( frame . fbh < = 32 )
frame . fbh = considerheight ;
if ( frame . fbh = = considerheight ) {
// stops bad resolves (mgs3)
if ( ! curprim . abe & & ( ! test . ate | | test . atst = = 0 ) )
s_nResolved | = 0x100 ;
}
} */
// ffxii hack to stop resolving
if ( ! ( frame . psm & 2 ) | | ! ( g_GameSettings & GAME_FULL16BITRES ) ) {
if ( frame . fbp > = 0x3000 & & fbh > = 0x1a0 ) {
int endfbp = frame . fbp + frame . fbw * fbh / ( ( gsfb . psm & 2 ) ? 128 : 64 ) ;
// see if there is a previous render target in the way, reduce
for ( CRenderTargetMngr : : MAPTARGETS : : iterator itnew = s_RTs . mapTargets . begin ( ) ; itnew ! = s_RTs . mapTargets . end ( ) ; + + itnew ) {
if ( itnew - > second - > fbp > frame . fbp & & endfbp > itnew - > second - > fbp ) {
endfbp = itnew - > second - > fbp ;
}
}
frame . fbh = ( endfbp - frame . fbp ) * ( ( gsfb . psm & 2 ) ? 128 : 64 ) / frame . fbw ;
}
}
CRenderTarget * pprevrndr = prndr ;
CDepthTarget * pprevdepth = pdepth ;
// reset so that Resolve doesn't call Flush
prndr = NULL ;
pdepth = NULL ;
CRenderTarget * pnewtarg = s_RTs . GetTarg ( frame , 0 , maxmin ) ;
assert ( pnewtarg ! = NULL ) ;
// pnewtarg->fbh >= 0x1c0 needed for ffx
if ( pnewtarg - > fbh > = 0x1c0 & & pnewtarg - > fbh > frame . fbh & & zbuf . zbp < tbp & & ! zbuf . zmsk ) {
// check if zbuf is in the way of the texture (suikoden5)
int maxallowedfbh = ( tbp - zbuf . zbp ) * ( ( zbuf . psm & 2 ) ? 128 : 64 ) / gsfb . fbw ;
if ( gsfb . psm & 2 )
maxallowedfbh * = 2 ;
if ( pnewtarg - > fbh > maxallowedfbh + 32 ) { // +32 needed for ffx2
// destroy and recreate
s_RTs . DestroyAllTargs ( 0 , 0x100 , pnewtarg - > fbw ) ;
pnewtarg = s_RTs . GetTarg ( frame , 0 , maxmin ) ;
assert ( pnewtarg ! = NULL ) ;
}
}
PRIM_LOG ( " frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x \n " , ictx , gsfb . fbp , gsfb . fbw , gsfb . fbh , pnewtarg - > fbh , gsfb . psm , gsfb . fbm ) ;
if ( ( pprevrndr ! = pnewtarg ) | | ( prndr ! = NULL & & ( prndr - > status & CRenderTarget : : TS_NeedUpdate ) ) )
bChanged = 1 ;
prndr = pnewtarg ;
// update z
frameInfo tempfb ;
tempfb . fbw = prndr - > fbw ;
tempfb . fbp = zbuf . zbp ;
tempfb . psm = zbuf . psm ;
tempfb . fbh = prndr - > fbh ;
if ( zbuf . psm = = 0x31 )
tempfb . fbm = 0xff000000 ;
else
tempfb . fbm = 0 ;
// check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2)
//u32 key = zbuf.zbp|(frame.fbw<<16);
//CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key);
// if( it != s_RTs.mapTargets.end() ) {
//#ifdef _DEBUG
// DEBUG_LOG("zbuf resolve\n");
//#endif
// if( it->second->status & CRenderTarget::TS_Resolved )
// it->second->Resolve();
// }
GL_REPORT_ERRORD ( ) ;
CDepthTarget * pnewdepth = ( CDepthTarget * ) s_DepthRTs . GetTarg ( tempfb , CRenderTargetMngr : : TO_DepthBuffer |
CRenderTargetMngr : : TO_StrictHeight | ( zbuf . zmsk ? CRenderTargetMngr : : TO_Virtual : 0 ) ,
GET_MAXHEIGHT ( zbuf . zbp , gsfb . fbw , 0 ) ) ;
assert ( pnewdepth ! = NULL & & prndr ! = NULL ) ;
assert ( pnewdepth - > fbh = = prndr - > fbh ) ;
if ( ( pprevdepth ! = pnewdepth ) | | ( pdepth ! = NULL & & ( pdepth - > status & CRenderTarget : : TS_NeedUpdate ) ) )
bChanged | = 2 ;
pdepth = pnewdepth ;
if ( prndr - > status & CRenderTarget : : TS_NeedConvert32 ) {
if ( pdepth - > pdepth ! = 0 )
pdepth - > SetDepthStencilSurface ( ) ;
prndr - > fbh * = 2 ;
prndr - > ConvertTo32 ( ) ;
prndr - > status & = ~ CRenderTarget : : TS_NeedConvert32 ;
}
else if ( prndr - > status & CRenderTarget : : TS_NeedConvert16 ) {
if ( pdepth - > pdepth ! = 0 )
pdepth - > SetDepthStencilSurface ( ) ;
prndr - > fbh / = 2 ;
prndr - > ConvertTo16 ( ) ;
prndr - > status & = ~ CRenderTarget : : TS_NeedConvert16 ;
}
}
else if ( bNeedZCheck ) {
bNeedZCheck = 0 ;
CDepthTarget * pprevdepth = pdepth ;
pdepth = NULL ;
if ( prndr ! = NULL & & gsfb . fbw > 0 ) {
// just z changed
frameInfo f ;
f . fbp = zbuf . zbp ;
f . fbw = prndr - > fbw ;
f . fbh = prndr - > fbh ;
f . psm = zbuf . psm ;
if ( zbuf . psm = = 0x31 ) f . fbm = 0xff000000 ;
else f . fbm = 0 ;
CDepthTarget * pnewdepth = ( CDepthTarget * ) s_DepthRTs . GetTarg ( f , CRenderTargetMngr : : TO_DepthBuffer | CRenderTargetMngr : : TO_StrictHeight |
( zbuf . zmsk ? CRenderTargetMngr : : TO_Virtual : 0 ) , GET_MAXHEIGHT ( zbuf . zbp , gsfb . fbw , 0 ) ) ;
assert ( pnewdepth ! = NULL & & prndr ! = NULL ) ;
assert ( pnewdepth - > fbh = = prndr - > fbh ) ;
if ( ( pprevdepth ! = pnewdepth ) | | ( pdepth ! = NULL & & ( pdepth - > status & CRenderTarget : : TS_NeedUpdate ) ) )
bChanged = 2 ;
pdepth = pnewdepth ;
}
}
if ( prndr ! = NULL ) SetContextTarget ( ictx ) ;
}
void ZeroGS : : VB : : FlushTexData ( )
{
assert ( bNeedTexCheck ) ;
bNeedTexCheck = 0 ;
u32 psm = ( uNextTex0Data [ 0 ] > > 20 ) & 0x3f ;
if ( psm = = 9 ) psm = 1 ; // hmm..., ffx intro menu
// don't update unless necessary
if ( uCurTex0Data [ 0 ] = = uNextTex0Data [ 0 ] & & ( uCurTex0Data [ 1 ] & 0x1f ) = = ( uNextTex0Data [ 1 ] & 0x1f ) ) {
if ( PSMT_ISCLUT ( psm ) ) {
// have to write the CLUT again if changed
if ( ( uCurTex0Data [ 1 ] & 0x1fffffe0 ) = = ( uNextTex0Data [ 1 ] & 0x1fffffe0 ) ) {
if ( uNextTex0Data [ 1 ] & 0xe0000000 ) {
//ZeroGS::Flush(ictx);
ZeroGS : : texClutWrite ( ictx ) ;
// invalidate to make sure target didn't change!
bVarsTexSync = FALSE ;
}
return ;
}
if ( ( uNextTex0Data [ 1 ] & 0xe0000000 ) = = 0 ) {
if ( ( uCurTex0Data [ 1 ] & 0x1ff10000 ) ! = ( uNextTex0Data [ 1 ] & 0x1ff10000 ) )
ZeroGS : : Flush ( ictx ) ;
// clut isn't going to be loaded so can ignore, but at least update CSA and CPSM!
uCurTex0Data [ 1 ] = ( uCurTex0Data [ 1 ] & 0xe087ffff ) | ( uNextTex0Data [ 1 ] & 0x1f780000 ) ;
if ( tex0 . cpsm < = 1 ) tex0 . csa = ( uNextTex0Data [ 1 ] > > 24 ) & 0xf ;
else tex0 . csa = ( uNextTex0Data [ 1 ] > > 24 ) & 0x1f ;
tex0 . cpsm = ( uNextTex0Data [ 1 ] > > 19 ) & 0xe ;
ZeroGS : : texClutWrite ( ictx ) ;
bVarsTexSync = FALSE ;
return ;
}
// fall through
}
else {
//bVarsTexSync = FALSE;
return ;
}
}
ZeroGS : : Flush ( ictx ) ;
bVarsTexSync = FALSE ;
bTexConstsSync = FALSE ;
uCurTex0Data [ 0 ] = uNextTex0Data [ 0 ] ;
uCurTex0Data [ 1 ] = uNextTex0Data [ 1 ] ;
tex0 . tbp0 = ( uNextTex0Data [ 0 ] & 0x3fff ) ;
tex0 . tbw = ( ( uNextTex0Data [ 0 ] > > 14 ) & 0x3f ) * 64 ;
tex0 . psm = psm ;
tex0 . tw = ( uNextTex0Data [ 0 ] > > 26 ) & 0xf ;
if ( tex0 . tw > 10 ) tex0 . tw = 10 ;
tex0 . tw = 1 < < tex0 . tw ;
tex0 . th = ( ( uNextTex0Data [ 0 ] > > 30 ) & 0x3 ) | ( ( uNextTex0Data [ 1 ] & 0x3 ) < < 2 ) ;
if ( tex0 . th > 10 ) tex0 . th = 10 ;
tex0 . th = 1 < < tex0 . th ;
tex0 . tcc = ( uNextTex0Data [ 1 ] > > 2 ) & 0x1 ;
tex0 . tfx = ( uNextTex0Data [ 1 ] > > 3 ) & 0x3 ;
ZeroGS : : fiTexWidth [ ictx ] = ( 1 / 16.0f ) / tex0 . tw ;
ZeroGS : : fiTexHeight [ ictx ] = ( 1 / 16.0f ) / tex0 . th ;
if ( tex0 . tbw = = 0 ) tex0 . tbw = 64 ;
if ( PSMT_ISCLUT ( psm ) ) {
tex0 . cbp = ( ( uNextTex0Data [ 1 ] > > 5 ) & 0x3fff ) ;
tex0 . cpsm = ( uNextTex0Data [ 1 ] > > 19 ) & 0xe ;
tex0 . csm = ( uNextTex0Data [ 1 ] > > 23 ) & 0x1 ;
if ( tex0 . cpsm < = 1 ) tex0 . csa = ( uNextTex0Data [ 1 ] > > 24 ) & 0xf ;
else tex0 . csa = ( uNextTex0Data [ 1 ] > > 24 ) & 0x1f ;
tex0 . cld = ( uNextTex0Data [ 1 ] > > 29 ) & 0x7 ;
ZeroGS : : texClutWrite ( ictx ) ;
}
}
// does one time only initializing/destruction
class ZeroGSInit
{
public :
ZeroGSInit ( ) {
// clear
g_pbyGSMemory = ( u8 * ) _aligned_malloc ( 0x00410000 , 1024 ) ; // leave some room for out of range accesses (saves on the checks)
memset ( g_pbyGSMemory , 0 , 0x00410000 ) ;
g_pbyGSClut = ( u8 * ) _aligned_malloc ( 256 * 8 , 1024 ) ; // need 512 alignment!
memset ( g_pbyGSClut , 0 , 256 * 8 ) ;
# ifndef _WIN32
memset ( & GLWin , 0 , sizeof ( GLWin ) ) ;
# endif
}
~ ZeroGSInit ( ) {
_aligned_free ( g_pbyGSMemory ) ; g_pbyGSMemory = NULL ;
_aligned_free ( g_pbyGSClut ) ; g_pbyGSClut = NULL ;
}
} ;
static ZeroGSInit s_ZeroGSInit ;
# ifdef _WIN32
void __stdcall glBlendFuncSeparateDummy ( GLenum e1 , GLenum e2 , GLenum e3 , GLenum e4 )
# else
void APIENTRY glBlendFuncSeparateDummy ( GLenum e1 , GLenum e2 , GLenum e3 , GLenum e4 )
# endif
{
glBlendFunc ( e1 , e2 ) ;
}
# ifdef _WIN32
void __stdcall glBlendEquationSeparateDummy ( GLenum e1 , GLenum e2 )
# else
void APIENTRY glBlendEquationSeparateDummy ( GLenum e1 , GLenum e2 )
# endif
{
glBlendEquation ( e1 ) ;
}
void HandleCgError ( CGcontext ctx , CGerror err , void * appdata )
{
ERROR_LOG ( " Cg error: %s \n " , cgGetErrorString ( err ) ) ;
const char * listing = cgGetLastListing ( g_cgcontext ) ;
if ( listing ! = NULL ) DEBUG_LOG ( " last listing: %s \n " , listing ) ;
// int loc;
// const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
// if( pstr != NULL ) printf("error at: %s\n");
// glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc);
// DEBUG_LOG("pos: %d\n", loc);
}
# ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
# define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8
# endif
void ZeroGS : : HandleGLError ( )
{
// check the error status of this framebuffer */
GLenum error = glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) ;
// if error != GL_FRAMEBUFFER_COMPLETE_EXT, there's an error of some sort
if ( error ! = 0 ) {
int w , h ;
GLint fmt ;
glGetRenderbufferParameterivEXT ( GL_COLOR_ATTACHMENT0_EXT , GL_RENDERBUFFER_INTERNAL_FORMAT_EXT , & fmt ) ;
glGetRenderbufferParameterivEXT ( GL_COLOR_ATTACHMENT0_EXT , GL_RENDERBUFFER_WIDTH_EXT , & w ) ;
glGetRenderbufferParameterivEXT ( GL_COLOR_ATTACHMENT0_EXT , GL_RENDERBUFFER_HEIGHT_EXT , & h ) ;
switch ( error )
{
case GL_FRAMEBUFFER_COMPLETE_EXT :
break ;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT :
ERROR_LOG ( " Error! missing a required image/buffer attachment! \n " ) ;
break ;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT :
ERROR_LOG ( " Error! has no images/buffers attached! \n " ) ;
break ;
// case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
// ERROR_LOG("Error! has an image/buffer attached in multiple locations!\n");
// break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT :
ERROR_LOG ( " Error! has mismatched image/buffer dimensions! \n " ) ;
break ;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT :
ERROR_LOG ( " Error! colorbuffer attachments have different types! \n " ) ;
break ;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT :
ERROR_LOG ( " Error! trying to draw to non-attached color buffer! \n " ) ;
break ;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT :
ERROR_LOG ( " Error! trying to read from a non-attached color buffer! \n " ) ;
break ;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT :
ERROR_LOG ( " Error! format is not supported by current graphics card/driver! \n " ) ;
break ;
default :
ERROR_LOG ( " *UNKNOWN ERROR* reported from glCheckFramebufferStatusEXT() for %s! \n " ) ;
break ;
}
}
}
# ifdef _WIN32
# define GL_LOADFN(name) { \
if ( ( * ( void * * ) & name = ( void * ) wglGetProcAddress ( # name ) ) = = NULL ) { \
ERROR_LOG ( " Failed to find %s, exiting \n " , # name ) ; \
} \
}
# else
// let GLEW take care of it
# define GL_LOADFN(name)
# endif
bool ZeroGS : : IsGLExt ( const char * szTargetExtension )
{
return mapGLExtensions . find ( string ( szTargetExtension ) ) ! = mapGLExtensions . end ( ) ;
}
bool ZeroGS : : Create ( int _width , int _height )
{
GLenum err = GL_NO_ERROR ;
bool bSuccess = true ;
int i ;
Destroy ( 1 ) ;
GSStateReset ( ) ;
cgSetErrorHandler ( HandleCgError , NULL ) ;
g_RenderFormatType = RFT_float16 ;
nBackbufferWidth = _width ;
nBackbufferHeight = _height ;
fiRendWidth = 1.0f / nBackbufferWidth ;
fiRendHeight = 1.0f / nBackbufferHeight ;
# ifdef _WIN32
GLuint PixelFormat ; // Holds The Results After Searching For A Match
DWORD dwExStyle ; // Window Extended Style
DWORD dwStyle ; // Window Style
RECT rcdesktop ;
GetWindowRect ( GetDesktopWindow ( ) , & rcdesktop ) ;
if ( conf . options & GSOPTION_FULLSCREEN ) {
nBackbufferWidth = rcdesktop . right - rcdesktop . left ;
nBackbufferHeight = rcdesktop . bottom - rcdesktop . top ;
DEVMODE dmScreenSettings ;
memset ( & dmScreenSettings , 0 , sizeof ( dmScreenSettings ) ) ;
dmScreenSettings . dmSize = sizeof ( dmScreenSettings ) ;
dmScreenSettings . dmPelsWidth = nBackbufferWidth ;
dmScreenSettings . dmPelsHeight = nBackbufferHeight ;
dmScreenSettings . dmBitsPerPel = 32 ;
dmScreenSettings . dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT ;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if ( ChangeDisplaySettings ( & dmScreenSettings , CDS_FULLSCREEN ) ! = DISP_CHANGE_SUCCESSFUL )
{
if ( MessageBox ( NULL , " The Requested Fullscreen Mode Is Not Supported By \n Your Video Card. Use Windowed Mode Instead? " , " NeHe GL " , MB_YESNO | MB_ICONEXCLAMATION ) = = IDYES )
conf . options & = ~ GSOPTION_FULLSCREEN ;
else
return false ;
}
}
else {
// change to default resolution
ChangeDisplaySettings ( NULL , 0 ) ;
}
if ( conf . options & GSOPTION_FULLSCREEN ) {
dwExStyle = WS_EX_APPWINDOW ;
dwStyle = WS_POPUP ;
ShowCursor ( FALSE ) ;
}
else {
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE ;
dwStyle = WS_OVERLAPPEDWINDOW ;
}
RECT rc ;
rc . left = 0 ; rc . top = 0 ;
rc . right = nBackbufferWidth ; rc . bottom = nBackbufferHeight ;
AdjustWindowRectEx ( & rc , dwStyle , FALSE , dwExStyle ) ;
int X = ( rcdesktop . right - rcdesktop . left ) / 2 - ( rc . right - rc . left ) / 2 ;
int Y = ( rcdesktop . bottom - rcdesktop . top ) / 2 - ( rc . bottom - rc . top ) / 2 ;
SetWindowPos ( GShwnd , NULL , X , Y , rc . right - rc . left , rc . bottom - rc . top , SWP_NOREPOSITION | SWP_NOZORDER ) ;
PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
{
sizeof ( PIXELFORMATDESCRIPTOR ) , // Size Of This Pixel Format Descriptor
1 , // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER , // Must Support Double Buffering
PFD_TYPE_RGBA , // Request An RGBA Format
32 , // Select Our Color Depth
0 , 0 , 0 , 0 , 0 , 0 , // Color Bits Ignored
0 , // 8bit Alpha Buffer
0 , // Shift Bit Ignored
0 , // No Accumulation Buffer
0 , 0 , 0 , 0 , // Accumulation Bits Ignored
24 , // 24Bit Z-Buffer (Depth Buffer)
8 , // 8bit Stencil Buffer
0 , // No Auxiliary Buffer
PFD_MAIN_PLANE , // Main Drawing Layer
0 , // Reserved
0 , 0 , 0 // Layer Masks Ignored
} ;
if ( ! ( hDC = GetDC ( GShwnd ) ) ) {
MessageBox ( NULL , " (1) Can't Create A GL Device Context. " , " ERROR " , MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
if ( ! ( PixelFormat = ChoosePixelFormat ( hDC , & pfd ) ) ) {
MessageBox ( NULL , " (2) Can't Find A Suitable PixelFormat. " , " ERROR " , MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
if ( ! SetPixelFormat ( hDC , PixelFormat , & pfd ) ) {
MessageBox ( NULL , " (3) Can't Set The PixelFormat. " , " ERROR " , MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
if ( ! ( hRC = wglCreateContext ( hDC ) ) ) {
MessageBox ( NULL , " (4) Can't Create A GL Rendering Context. " , " ERROR " , MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
if ( ! wglMakeCurrent ( hDC , hRC ) ) {
MessageBox ( NULL , " (5) Can't Activate The GL Rendering Context. " , " ERROR " , MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
# else
XVisualInfo * vi ;
Colormap cmap ;
int dpyWidth , dpyHeight ;
int glxMajorVersion , glxMinorVersion ;
int vidModeMajorVersion , vidModeMinorVersion ;
Atom wmDelete ;
Window winDummy ;
unsigned int borderDummy ;
// attributes for a single buffered visual in RGBA format with at least
// 8 bits per color and a 24 bit depth buffer
int attrListSgl [ ] = { GLX_RGBA , GLX_RED_SIZE , 8 ,
GLX_GREEN_SIZE , 8 ,
GLX_BLUE_SIZE , 8 ,
GLX_DEPTH_SIZE , 24 ,
None } ;
// attributes for a double buffered visual in RGBA format with at least
// 8 bits per color and a 24 bit depth buffer
int attrListDbl [ ] = { GLX_RGBA , GLX_DOUBLEBUFFER ,
GLX_RED_SIZE , 8 ,
GLX_GREEN_SIZE , 8 ,
GLX_BLUE_SIZE , 8 ,
GLX_DEPTH_SIZE , 24 ,
None } ;
GLWin . fs = ! ! ( conf . options & GSOPTION_FULLSCREEN ) ;
/* get an appropriate visual */
vi = glXChooseVisual ( GLWin . dpy , GLWin . screen , attrListDbl ) ;
if ( vi = = NULL ) {
vi = glXChooseVisual ( GLWin . dpy , GLWin . screen , attrListSgl ) ;
GLWin . doubleBuffered = False ;
ERROR_LOG ( " Only Singlebuffered Visual! \n " ) ;
}
else {
GLWin . doubleBuffered = True ;
ERROR_LOG ( " Got Doublebuffered Visual! \n " ) ;
}
glXQueryVersion ( GLWin . dpy , & glxMajorVersion , & glxMinorVersion ) ;
ERROR_LOG ( " glX-Version %d.%d \n " , glxMajorVersion , glxMinorVersion ) ;
/* create a GLX context */
GLWin . ctx = glXCreateContext ( GLWin . dpy , vi , 0 , GL_TRUE ) ;
/* create a color map */
cmap = XCreateColormap ( GLWin . dpy , RootWindow ( GLWin . dpy , vi - > screen ) ,
vi - > visual , AllocNone ) ;
GLWin . attr . colormap = cmap ;
GLWin . attr . border_pixel = 0 ;
// get a connection
XF86VidModeQueryVersion ( GLWin . dpy , & vidModeMajorVersion , & vidModeMinorVersion ) ;
if ( GLWin . fs ) {
XF86VidModeModeInfo * * modes = NULL ;
int modeNum = 0 ;
int bestMode = 0 ;
// set best mode to current
bestMode = 0 ;
ERROR_LOG ( " XF86VidModeExtension-Version %d.%d \n " , vidModeMajorVersion , vidModeMinorVersion ) ;
XF86VidModeGetAllModeLines ( GLWin . dpy , GLWin . screen , & modeNum , & modes ) ;
if ( modeNum > 0 & & modes ! = NULL ) {
/* save desktop-resolution before switching modes */
GLWin . deskMode = * modes [ 0 ] ;
/* look for mode with requested resolution */
for ( i = 0 ; i < modeNum ; i + + ) {
if ( ( modes [ i ] - > hdisplay = = _width ) & & ( modes [ i ] - > vdisplay = = _height ) ) {
bestMode = i ;
}
}
XF86VidModeSwitchToMode ( GLWin . dpy , GLWin . screen , modes [ bestMode ] ) ;
XF86VidModeSetViewPort ( GLWin . dpy , GLWin . screen , 0 , 0 ) ;
dpyWidth = modes [ bestMode ] - > hdisplay ;
dpyHeight = modes [ bestMode ] - > vdisplay ;
ERROR_LOG ( " Resolution %dx%d \n " , dpyWidth , dpyHeight ) ;
XFree ( modes ) ;
/* create a fullscreen window */
GLWin . attr . override_redirect = True ;
GLWin . attr . event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
StructureNotifyMask ;
GLWin . win = XCreateWindow ( GLWin . dpy , RootWindow ( GLWin . dpy , vi - > screen ) ,
0 , 0 , dpyWidth , dpyHeight , 0 , vi - > depth , InputOutput , vi - > visual ,
CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect ,
& GLWin . attr ) ;
XWarpPointer ( GLWin . dpy , None , GLWin . win , 0 , 0 , 0 , 0 , 0 , 0 ) ;
XMapRaised ( GLWin . dpy , GLWin . win ) ;
XGrabKeyboard ( GLWin . dpy , GLWin . win , True , GrabModeAsync ,
GrabModeAsync , CurrentTime ) ;
XGrabPointer ( GLWin . dpy , GLWin . win , True , ButtonPressMask ,
GrabModeAsync , GrabModeAsync , GLWin . win , None , CurrentTime ) ;
}
else {
ERROR_LOG ( " Failed to start fullscreen. If you received the \n "
" \" XFree86-VidModeExtension \" extension is missing, add \n "
" Load \" extmod \" \n "
" to your X configuration file (under the Module Section) \n " ) ;
GLWin . fs = 0 ;
}
}
if ( ! GLWin . fs ) {
//XRootWindow(dpy,screen)
//int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
//int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
// create a window in window mode
GLWin . attr . event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
StructureNotifyMask ;
GLWin . win = XCreateWindow ( GLWin . dpy , RootWindow ( GLWin . dpy , vi - > screen ) ,
0 , 0 , _width , _height , 0 , vi - > depth , InputOutput , vi - > visual ,
CWBorderPixel | CWColormap | CWEventMask , & GLWin . attr ) ;
// only set window title and handle wm_delete_events if in windowed mode
wmDelete = XInternAtom ( GLWin . dpy , " WM_DELETE_WINDOW " , True ) ;
XSetWMProtocols ( GLWin . dpy , GLWin . win , & wmDelete , 1 ) ;
XSetStandardProperties ( GLWin . dpy , GLWin . win , " ZeroGS " ,
" ZeroGS " , None , NULL , 0 , NULL ) ;
XMapRaised ( GLWin . dpy , GLWin . win ) ;
}
// connect the glx-context to the window
glXMakeCurrent ( GLWin . dpy , GLWin . win , GLWin . ctx ) ;
XGetGeometry ( GLWin . dpy , GLWin . win , & winDummy , & GLWin . x , & GLWin . y ,
& GLWin . width , & GLWin . height , & borderDummy , & GLWin . depth ) ;
ERROR_LOG ( " Depth %d \n " , GLWin . depth ) ;
if ( glXIsDirect ( GLWin . dpy , GLWin . ctx ) )
ERROR_LOG ( " you have Direct Rendering! \n " ) ;
else
ERROR_LOG ( " no Direct Rendering possible! \n " ) ;
// better for pad plugin key input (thc)
XSelectInput ( GLWin . dpy , GLWin . win , ExposureMask | KeyPressMask | KeyReleaseMask |
ButtonPressMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask |
FocusChangeMask ) ;
# endif
// fill the opengl extension map
const char * ptoken = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
if ( ptoken = = NULL ) return false ;
int prevlog = conf . log ;
conf . log = 1 ;
GS_LOG ( " Supported OpenGL Extensions: \n %s \n " , ptoken ) ; // write to the log file
conf . log = prevlog ;
// insert all exts into mapGLExtensions
const char * pend = NULL ;
while ( ptoken ! = NULL ) {
pend = strchr ( ptoken , ' ' ) ;
if ( pend ! = NULL ) {
mapGLExtensions [ string ( ptoken , pend - ptoken ) ] ;
}
else {
mapGLExtensions [ string ( ptoken ) ] ;
break ;
}
ptoken = pend ;
while ( * ptoken = = ' ' ) + + ptoken ;
}
s_nFullscreen = ( conf . options & GSOPTION_FULLSCREEN ) ? 1 : 0 ;
conf . mrtdepth = 0 ; // for now
# ifndef _WIN32
int const glew_ok = glewInit ( ) ;
if ( glew_ok ! = GLEW_OK ) {
ERROR_LOG ( " glewInit() is not ok! \n " ) ;
return false ;
}
# endif
if ( ! IsGLExt ( " GL_EXT_framebuffer_object " ) ) {
ERROR_LOG ( " ********* \n ZeroGS: ERROR: Need GL_EXT_framebufer_object for multiple render targets \n ZeroGS: ********* \n " ) ;
bSuccess = false ;
}
if ( ! IsGLExt ( " GL_EXT_blend_equation_separate " ) | | glBlendEquationSeparateEXT = = NULL ) {
ERROR_LOG ( " ********* \n ZeroGS: OGL WARNING: Need GL_EXT_blend_equation_separate \n ZeroGS: ********* \n " ) ;
zgsBlendEquationSeparateEXT = glBlendEquationSeparateDummy ;
}
else {
zgsBlendEquationSeparateEXT = glBlendEquationSeparateEXT ;
}
if ( ! IsGLExt ( " GL_EXT_blend_func_separate " ) | | glBlendFuncSeparateEXT = = NULL ) {
ERROR_LOG ( " ********* \n ZeroGS: OGL WARNING: Need GL_EXT_blend_func_separate \n ZeroGS: ********* \n " ) ;
zgsBlendFuncSeparateEXT = glBlendFuncSeparateDummy ;
}
else {
zgsBlendFuncSeparateEXT = glBlendFuncSeparateEXT ;
}
if ( ! IsGLExt ( " GL_EXT_secondary_color " ) ) {
ERROR_LOG ( " ********* \n ZeroGS: OGL WARNING: Need GL_EXT_secondary_color \n ZeroGS: ********* \n " ) ;
bSuccess = false ;
}
if ( ! IsGLExt ( " GL_ARB_draw_buffers " ) & & ! IsGLExt ( " GL_ATI_draw_buffers " ) ) {
ERROR_LOG ( " ********* \n ZeroGS: OGL WARNING: multiple render targets not supported, some effects might look bad \n ZeroGS: ********* \n " ) ;
conf . mrtdepth = 0 ;
}
if ( ! bSuccess )
return false ;
if ( g_GameSettings & GAME_32BITTARGS ) {
g_RenderFormatType = RFT_byte8 ;
ERROR_LOG ( " Setting 32 bit render target \n " ) ;
}
else {
if ( ! IsGLExt ( " GL_NV_float_buffer " ) & & ! IsGLExt ( " GL_ARB_color_buffer_float " ) & & ! IsGLExt ( " ATI_pixel_format_float " ) ) {
ERROR_LOG ( " ****** \n ZeroGS: GS WARNING: Floating point render targets not supported, switching to 32bit \n ZeroGS: ********* \n " ) ;
g_RenderFormatType = RFT_byte8 ;
}
}
g_RenderFormatType = RFT_byte8 ;
# ifdef _WIN32
if ( IsGLExt ( " WGL_EXT_swap_control " ) | | IsGLExt ( " EXT_swap_control " ) )
wglSwapIntervalEXT ( 0 ) ;
# else
if ( IsGLExt ( " GLX_SGI_swap_control " ) ) {
_PFNSWAPINTERVAL swapinterval = ( _PFNSWAPINTERVAL ) wglGetProcAddress ( " glXSwapInterval " ) ;
if ( ! swapinterval )
swapinterval = ( _PFNSWAPINTERVAL ) wglGetProcAddress ( " glXSwapIntervalSGI " ) ;
if ( ! swapinterval )
swapinterval = ( _PFNSWAPINTERVAL ) wglGetProcAddress ( " glXSwapIntervalEXT " ) ;
if ( swapinterval )
swapinterval ( 0 ) ;
else
ERROR_LOG ( " no support for SwapInterval (framerate clamped to monitor refresh rate) \n " ) ;
}
# endif
// check the max texture width and height
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & g_MaxTexWidth ) ;
g_MaxTexHeight = g_MaxTexWidth ;
GPU_TEXWIDTH = g_MaxTexWidth / 8 ;
g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH ;
# ifdef RELEASE_TO_PUBLIC
# ifdef _WIN32
HRSRC hShaderSrc = FindResource ( hInst , MAKEINTRESOURCE ( IDR_SHADERS ) , RT_RCDATA ) ;
assert ( hShaderSrc ! = NULL ) ;
HGLOBAL hShaderGlob = LoadResource ( hInst , hShaderSrc ) ;
assert ( hShaderGlob ! = NULL ) ;
s_lpShaderResources = ( u8 * ) LockResource ( hShaderGlob ) ;
# else
FILE * fres = fopen ( " ps2hw.dat " , " rb " ) ;
if ( fres = = NULL ) {
fres = fopen ( " plugins/ps2hw.dat " , " rb " ) ;
if ( fres = = NULL ) {
ERROR_LOG ( " Cannot find ps2hw.dat in working directory. Exiting \n " ) ;
return false ;
}
}
fseek ( fres , 0 , SEEK_END ) ;
size_t s = ftell ( fres ) ;
s_lpShaderResources = new u8 [ s + 1 ] ;
fseek ( fres , 0 , SEEK_SET ) ;
fread ( s_lpShaderResources , s , 1 , fres ) ;
s_lpShaderResources [ s ] = 0 ;
# endif
# else
# ifndef _WIN32
// test if ps2hw.fx exists
char tempstr [ 255 ] ;
char curwd [ 255 ] ;
getcwd ( curwd , ARRAY_SIZE ( curwd ) ) ;
2009-02-14 13:48:02 +00:00
strcpy ( tempstr , " ../plugins/zerogs/opengl/ " ) ;
2009-02-09 21:15:56 +00:00
sprintf ( EFFECT_NAME , " %sps2hw.fx " , tempstr ) ;
FILE * f = fopen ( EFFECT_NAME , " r " ) ;
if ( f = = NULL ) {
2009-02-14 13:48:02 +00:00
strcpy ( tempstr , " ../../plugins/zerogs/opengl/ " ) ;
2009-02-09 21:15:56 +00:00
sprintf ( EFFECT_NAME , " %sps2hw.fx " , tempstr ) ;
f = fopen ( EFFECT_NAME , " r " ) ;
if ( f = = NULL ) {
ERROR_LOG ( " Failed to find %s, try compiling a non-devbuild \n " , EFFECT_NAME ) ;
return false ;
}
}
fclose ( f ) ;
sprintf ( EFFECT_DIR , " %s/%s " , curwd , tempstr ) ;
sprintf ( EFFECT_NAME , " %sps2hw.fx " , EFFECT_DIR ) ;
# endif
# endif // RELEASE_TO_PUBLIC
// load the effect, find the best profiles (if any)
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBVP1 ) ! = CG_TRUE ) {
ERROR_LOG ( " arbvp1 not supported \n " ) ;
return false ;
}
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBFP1 ) ! = CG_TRUE ) {
ERROR_LOG ( " arbfp1 not supported \n " ) ;
return false ;
}
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
s_srcrgb = s_dstrgb = s_srcalpha = s_dstalpha = GL_ONE ;
GL_LOADFN ( glIsRenderbufferEXT ) ;
GL_LOADFN ( glBindRenderbufferEXT ) ;
GL_LOADFN ( glDeleteRenderbuffersEXT ) ;
GL_LOADFN ( glGenRenderbuffersEXT ) ;
GL_LOADFN ( glRenderbufferStorageEXT ) ;
GL_LOADFN ( glGetRenderbufferParameterivEXT ) ;
GL_LOADFN ( glIsFramebufferEXT ) ;
GL_LOADFN ( glBindFramebufferEXT ) ;
GL_LOADFN ( glDeleteFramebuffersEXT ) ;
GL_LOADFN ( glGenFramebuffersEXT ) ;
GL_LOADFN ( glCheckFramebufferStatusEXT ) ;
GL_LOADFN ( glFramebufferTexture1DEXT ) ;
GL_LOADFN ( glFramebufferTexture2DEXT ) ;
GL_LOADFN ( glFramebufferTexture3DEXT ) ;
GL_LOADFN ( glFramebufferRenderbufferEXT ) ;
GL_LOADFN ( glGetFramebufferAttachmentParameterivEXT ) ;
GL_LOADFN ( glGenerateMipmapEXT ) ;
if ( IsGLExt ( " GL_ARB_draw_buffers " ) )
glDrawBuffers = ( PFNGLDRAWBUFFERSPROC ) wglGetProcAddress ( " glDrawBuffers " ) ;
else if ( IsGLExt ( " GL_ATI_draw_buffers " ) )
glDrawBuffers = ( PFNGLDRAWBUFFERSPROC ) wglGetProcAddress ( " glDrawBuffersATI " ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
glGenFramebuffersEXT ( 1 , & s_uFramebuffer ) ;
if ( s_uFramebuffer = = 0 ) {
ERROR_LOG ( " failed to create the renderbuffer \n " ) ;
}
assert ( glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) = = GL_FRAMEBUFFER_COMPLETE_EXT ) ;
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , s_uFramebuffer ) ;
if ( glDrawBuffers ! = NULL )
glDrawBuffers ( 1 , s_drawbuffers ) ;
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
font_p = new RasterFont ( ) ;
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
// init draw fns
drawfn [ 0 ] = KickPoint ;
drawfn [ 1 ] = KickLine ;
drawfn [ 2 ] = KickLine ;
drawfn [ 3 ] = KickTriangle ;
drawfn [ 4 ] = KickTriangle ;
drawfn [ 5 ] = KickTriangleFan ;
drawfn [ 6 ] = KickSprite ;
drawfn [ 7 ] = KickDummy ;
SetAA ( conf . aa ) ;
GSsetGameCRC ( g_LastCRC , g_GameSettings ) ;
GL_STENCILFUNC ( GL_ALWAYS , 0 , 0 ) ;
//g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE;
//s_bWriteDepth = TRUE;
GL_BLEND_ALL ( GL_ONE , GL_ONE , GL_ONE , GL_ONE ) ;
glViewport ( 0 , 0 , nBackbufferWidth , nBackbufferHeight ) ; // Reset The Current Viewport
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
glShadeModel ( GL_SMOOTH ) ;
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
glClearDepth ( 1.0f ) ;
glEnable ( GL_DEPTH_TEST ) ;
glDisable ( GL_LIGHTING ) ;
glDepthFunc ( GL_LEQUAL ) ;
glHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST ) ; // Really Nice Perspective Calculations
glGenTextures ( 1 , & ptexLogo ) ;
glBindTexture ( GL_TEXTURE_RECTANGLE_NV , ptexLogo ) ;
# ifdef _WIN32
HRSRC hBitmapSrc = FindResource ( hInst , MAKEINTRESOURCE ( IDB_ZEROGSLOGO ) , RT_BITMAP ) ;
assert ( hBitmapSrc ! = NULL ) ;
HGLOBAL hBitmapGlob = LoadResource ( hInst , hBitmapSrc ) ;
assert ( hBitmapGlob ! = NULL ) ;
PBITMAPINFO pinfo = ( PBITMAPINFO ) LockResource ( hBitmapGlob ) ;
glTexImage2D ( GL_TEXTURE_RECTANGLE_NV , 0 , 4 , pinfo - > bmiHeader . biWidth , pinfo - > bmiHeader . biHeight , 0 , pinfo - > bmiHeader . biBitCount = = 32 ? GL_RGBA : GL_RGB , GL_UNSIGNED_BYTE , ( u8 * ) pinfo + pinfo - > bmiHeader . biSize ) ;
nLogoWidth = pinfo - > bmiHeader . biWidth ;
nLogoHeight = pinfo - > bmiHeader . biHeight ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
# else
# endif
GL_REPORT_ERROR ( ) ;
g_nCurVBOIndex = 0 ;
g_vboBuffers . resize ( VB_NUMBUFFERS ) ;
glGenBuffers ( ( GLsizei ) g_vboBuffers . size ( ) , & g_vboBuffers [ 0 ] ) ;
for ( i = 0 ; i < ( int ) g_vboBuffers . size ( ) ; + + i ) {
glBindBuffer ( GL_ARRAY_BUFFER , g_vboBuffers [ i ] ) ;
glBufferData ( GL_ARRAY_BUFFER , 0x100 * sizeof ( VertexGPU ) , NULL , GL_STREAM_DRAW ) ;
}
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
// create the blocks texture
g_fBlockMult = 1 ;
vector < char > vBlockData , vBilinearData ;
BLOCK : : FillBlocks ( vBlockData , vBilinearData , 1 ) ;
glGenTextures ( 1 , & ptexBlocks ) ;
glBindTexture ( GL_TEXTURE_2D , ptexBlocks ) ;
g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI ;
g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI ;
g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI ;
glTexImage2D ( GL_TEXTURE_2D , 0 , g_internalFloatFmt , BLOCK_TEXWIDTH , BLOCK_TEXHEIGHT , 0 , GL_ALPHA , GL_FLOAT , & vBlockData [ 0 ] ) ;
if ( glGetError ( ) ! = GL_NO_ERROR ) {
// try different internal format
g_internalFloatFmt = GL_FLOAT_R32_NV ;
glTexImage2D ( GL_TEXTURE_2D , 0 , g_internalFloatFmt , BLOCK_TEXWIDTH , BLOCK_TEXHEIGHT , 0 , GL_RED , GL_FLOAT , & vBlockData [ 0 ] ) ;
}
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ;
if ( glGetError ( ) ! = GL_NO_ERROR ) {
// error, resort to 16bit
g_fBlockMult = 65535.0f * ( float ) g_fiGPU_TEXWIDTH ;
BLOCK : : FillBlocks ( vBlockData , vBilinearData , 0 ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , 2 , BLOCK_TEXWIDTH , BLOCK_TEXHEIGHT , 0 , GL_R , GL_UNSIGNED_SHORT , & vBlockData [ 0 ] ) ;
if ( glGetError ( ) ! = GL_NO_ERROR )
return false ;
}
else {
// fill in the bilinear blocks
glGenTextures ( 1 , & ptexBilinearBlocks ) ;
glBindTexture ( GL_TEXTURE_2D , ptexBilinearBlocks ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , g_internalRGBAFloatFmt , BLOCK_TEXWIDTH , BLOCK_TEXHEIGHT , 0 , GL_RGBA , GL_FLOAT , & vBilinearData [ 0 ] ) ;
if ( glGetError ( ) ! = GL_NO_ERROR ) {
g_internalRGBAFloatFmt = GL_FLOAT_RGBA32_NV ;
g_internalRGBAFloat16Fmt = GL_FLOAT_RGBA16_NV ;
glTexImage2D ( GL_TEXTURE_2D , 0 , g_internalRGBAFloatFmt , BLOCK_TEXWIDTH , BLOCK_TEXHEIGHT , 0 , GL_RGBA , GL_FLOAT , & vBilinearData [ 0 ] ) ;
B_G ( glGetError ( ) = = GL_NO_ERROR , return false ) ;
}
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ;
}
float fpri = 1 ;
glPrioritizeTextures ( 1 , & ptexBlocks , & fpri ) ;
if ( ptexBilinearBlocks ! = 0 )
glPrioritizeTextures ( 1 , & ptexBilinearBlocks , & fpri ) ;
GL_REPORT_ERROR ( ) ;
// fill a simple rect
glGenBuffers ( 1 , & vboRect ) ;
glBindBuffer ( GL_ARRAY_BUFFER , vboRect ) ;
vector < VertexGPU > verts ( 4 ) ;
VertexGPU * pvert = & verts [ 0 ] ;
pvert - > x = - 0x7fff ; pvert - > y = 0x7fff ; pvert - > z = 0 ; pvert - > s = 0 ; pvert - > t = 0 ; pvert + + ;
pvert - > x = 0x7fff ; pvert - > y = 0x7fff ; pvert - > z = 0 ; pvert - > s = 1 ; pvert - > t = 0 ; pvert + + ;
pvert - > x = - 0x7fff ; pvert - > y = - 0x7fff ; pvert - > z = 0 ; pvert - > s = 0 ; pvert - > t = 1 ; pvert + + ;
pvert - > x = 0x7fff ; pvert - > y = - 0x7fff ; pvert - > z = 0 ; pvert - > s = 1 ; pvert - > t = 1 ; pvert + + ;
glBufferDataARB ( GL_ARRAY_BUFFER , 4 * sizeof ( VertexGPU ) , & verts [ 0 ] , GL_STATIC_DRAW ) ;
// setup the default vertex declaration
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glClientActiveTexture ( GL_TEXTURE0 ) ;
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glEnableClientState ( GL_SECONDARY_COLOR_ARRAY ) ;
glEnableClientState ( GL_COLOR_ARRAY ) ;
GL_REPORT_ERROR ( ) ;
// some cards don't support this
// glClientActiveTexture(GL_TEXTURE0);
// glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// glTexCoordPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12);
// create the conversion textures
glGenTextures ( 1 , & ptexConv16to32 ) ;
glBindTexture ( GL_TEXTURE_2D , ptexConv16to32 ) ;
vector < u32 > conv16to32data ( 256 * 256 ) ;
for ( i = 0 ; i < 256 * 256 ; + + i ) {
u32 tempcol = RGBA16to32 ( i ) ;
// have to flip r and b
conv16to32data [ i ] = ( tempcol & 0xff00ff00 ) | ( ( tempcol & 0xff ) < < 16 ) | ( ( tempcol & 0xff0000 ) > > 16 ) ;
}
glTexImage2D ( GL_TEXTURE_2D , 0 , 4 , 256 , 256 , 0 , GL_RGBA , GL_UNSIGNED_BYTE , & conv16to32data [ 0 ] ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP ) ;
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
vector < u32 > conv32to16data ( 32 * 32 * 32 ) ;
glGenTextures ( 1 , & ptexConv32to16 ) ;
glBindTexture ( GL_TEXTURE_3D , ptexConv32to16 ) ;
u32 * dst = & conv32to16data [ 0 ] ;
for ( i = 0 ; i < 32 ; + + i ) {
for ( int j = 0 ; j < 32 ; + + j ) {
for ( int k = 0 ; k < 32 ; + + k ) {
u32 col = ( i < < 10 ) | ( j < < 5 ) | k ;
* dst + + = ( ( col & 0xff ) < < 16 ) | ( col & 0xff00 ) ;
}
}
}
glTexImage3D ( GL_TEXTURE_3D , 0 , 4 , 32 , 32 , 32 , 0 , GL_RGBA , GL_UNSIGNED_BYTE , & conv32to16data [ 0 ] ) ;
glTexParameteri ( GL_TEXTURE_3D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_3D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_3D , GL_TEXTURE_WRAP_S , GL_CLAMP ) ;
glTexParameteri ( GL_TEXTURE_3D , GL_TEXTURE_WRAP_T , GL_CLAMP ) ;
glTexParameteri ( GL_TEXTURE_3D , GL_TEXTURE_WRAP_R , GL_CLAMP ) ;
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
g_cgcontext = cgCreateContext ( ) ;
cgvProf = CG_PROFILE_ARBVP1 ;
cgfProf = CG_PROFILE_ARBFP1 ;
cgGLEnableProfile ( cgvProf ) ;
cgGLEnableProfile ( cgfProf ) ;
cgGLSetOptimalOptions ( cgvProf ) ;
cgGLSetOptimalOptions ( cgfProf ) ;
cgGLSetManageTextureParameters ( g_cgcontext , CG_FALSE ) ;
//cgSetAutoCompile(g_cgcontext, CG_COMPILE_IMMEDIATE);
g_fparamFogColor = cgCreateParameter ( g_cgcontext , CG_FLOAT4 ) ;
g_vparamPosXY [ 0 ] = cgCreateParameter ( g_cgcontext , CG_FLOAT4 ) ;
g_vparamPosXY [ 1 ] = cgCreateParameter ( g_cgcontext , CG_FLOAT4 ) ;
ERROR_LOG ( " Creating effects \n " ) ;
B_G ( LoadEffects ( ) , return false ) ;
g_bDisplayMsg = 0 ;
// create a sample shader
clampInfo temp ;
memset ( & temp , 0 , sizeof ( temp ) ) ;
temp . wms = 3 ; temp . wmt = 3 ;
g_nPixelShaderVer = SHADER_ACCURATE ;
// test
bool bFailed ;
FRAGMENTSHADER * pfrag = LoadShadeEffect ( 0 , 1 , 1 , 1 , 1 , temp , 0 , & bFailed ) ;
if ( bFailed | | pfrag = = NULL ) {
g_nPixelShaderVer = SHADER_ACCURATE | SHADER_REDUCED ;
pfrag = LoadShadeEffect ( 0 , 0 , 1 , 1 , 0 , temp , 0 , & bFailed ) ;
if ( pfrag ! = NULL )
cgGLLoadProgram ( pfrag - > prog ) ;
if ( bFailed | | pfrag = = NULL | | cgGetError ( ) ! = CG_NO_ERROR ) {
g_nPixelShaderVer = SHADER_REDUCED ;
ERROR_LOG ( " Basic shader test failed \n " ) ;
}
}
g_bDisplayMsg = 1 ;
if ( g_nPixelShaderVer & SHADER_REDUCED )
conf . bilinear = 0 ;
ERROR_LOG ( " Creating extra effects \n " ) ;
B_G ( LoadExtraEffects ( ) , return false ) ;
ERROR_LOG ( " using %s shaders \n " , g_pShaders [ g_nPixelShaderVer ] ) ;
GL_REPORT_ERROR ( ) ;
if ( err ! = GL_NO_ERROR ) bSuccess = false ;
glDisable ( GL_STENCIL_TEST ) ;
glEnable ( GL_SCISSOR_TEST ) ;
GL_BLEND_ALPHA ( GL_ONE , GL_ZERO ) ;
glBlendColorEXT ( 0 , 0 , 0 , 0.5f ) ;
glDisable ( GL_CULL_FACE ) ;
// points
// This was changed in SetAA - should we be changing it back?
glPointSize ( 1.0f ) ;
g_nDepthBias = 0 ;
glEnable ( GL_POLYGON_OFFSET_FILL ) ;
glEnable ( GL_POLYGON_OFFSET_LINE ) ;
glPolygonOffset ( 0 , 1 ) ;
vb [ 0 ] . Init ( VB_BUFFERSIZE ) ;
vb [ 1 ] . Init ( VB_BUFFERSIZE ) ;
g_bSaveFlushedFrame = 1 ;
g_vsprog = g_psprog = 0 ;
return glGetError ( ) = = GL_NO_ERROR & & bSuccess ;
}
void ZeroGS : : Destroy ( BOOL bD3D )
{
if ( s_aviinit ) {
StopCapture ( ) ;
# ifdef _WIN32
STOP_AVI ( ) ;
# else // linux
//TODO
# endif
ERROR_LOG ( " zerogs.avi stopped " ) ;
s_aviinit = 0 ;
}
g_MemTargs . Destroy ( ) ;
s_RTs . Destroy ( ) ;
s_DepthRTs . Destroy ( ) ;
s_BitwiseTextures . Destroy ( ) ;
SAFE_RELEASE_TEX ( s_ptexInterlace ) ;
SAFE_RELEASE_TEX ( ptexBlocks ) ;
SAFE_RELEASE_TEX ( ptexBilinearBlocks ) ;
SAFE_RELEASE_TEX ( ptexConv16to32 ) ;
SAFE_RELEASE_TEX ( ptexConv32to16 ) ;
vb [ 0 ] . Destroy ( ) ;
vb [ 1 ] . Destroy ( ) ;
if ( g_vboBuffers . size ( ) > 0 ) {
glDeleteBuffers ( ( GLsizei ) g_vboBuffers . size ( ) , & g_vboBuffers [ 0 ] ) ;
g_vboBuffers . clear ( ) ;
}
g_nCurVBOIndex = 0 ;
for ( int i = 0 ; i < ARRAY_SIZE ( pvs ) ; + + i ) {
SAFE_RELEASE_PROG ( pvs [ i ] ) ;
}
for ( int i = 0 ; i < ARRAY_SIZE ( ppsRegular ) ; + + i ) {
SAFE_RELEASE_PROG ( ppsRegular [ i ] . prog ) ;
}
for ( int i = 0 ; i < ARRAY_SIZE ( ppsTexture ) ; + + i ) {
SAFE_RELEASE_PROG ( ppsTexture [ i ] . prog ) ;
}
SAFE_RELEASE_PROG ( pvsBitBlt . prog ) ;
SAFE_RELEASE_PROG ( ppsBitBlt [ 0 ] . prog ) ; SAFE_RELEASE_PROG ( ppsBitBlt [ 1 ] . prog ) ;
SAFE_RELEASE_PROG ( ppsBitBltDepth . prog ) ;
SAFE_RELEASE_PROG ( ppsCRTCTarg [ 0 ] . prog ) ; SAFE_RELEASE_PROG ( ppsCRTCTarg [ 1 ] . prog ) ;
SAFE_RELEASE_PROG ( ppsCRTC [ 0 ] . prog ) ; SAFE_RELEASE_PROG ( ppsCRTC [ 1 ] . prog ) ;
SAFE_RELEASE_PROG ( ppsCRTC24 [ 0 ] . prog ) ; SAFE_RELEASE_PROG ( ppsCRTC24 [ 1 ] . prog ) ;
SAFE_RELEASE_PROG ( ppsOne . prog ) ;
SAFE_DELETE ( font_p ) ;
# ifdef _WIN32
if ( hRC ) // Do We Have A Rendering Context?
{
if ( ! wglMakeCurrent ( NULL , NULL ) ) // Are We Able To Release The DC And RC Contexts?
{
MessageBox ( NULL , " Release Of DC And RC Failed. " , " SHUTDOWN ERROR " , MB_OK | MB_ICONINFORMATION ) ;
}
if ( ! wglDeleteContext ( hRC ) ) // Are We Able To Delete The RC?
{
MessageBox ( NULL , " Release Rendering Context Failed. " , " SHUTDOWN ERROR " , MB_OK | MB_ICONINFORMATION ) ;
}
hRC = NULL ; // Set RC To NULL
}
if ( hDC & & ! ReleaseDC ( GShwnd , hDC ) ) // Are We Able To Release The DC
{
MessageBox ( NULL , " Release Device Context Failed. " , " SHUTDOWN ERROR " , MB_OK | MB_ICONINFORMATION ) ;
hDC = NULL ; // Set DC To NULL
}
# else // linux
if ( GLWin . ctx )
{
if ( ! glXMakeCurrent ( GLWin . dpy , None , NULL ) )
{
ERROR_LOG ( " Could not release drawing context. \n " ) ;
}
glXDestroyContext ( GLWin . dpy , GLWin . ctx ) ;
GLWin . ctx = NULL ;
}
/* switch back to original desktop resolution if we were in fs */
if ( GLWin . dpy ! = NULL ) {
if ( GLWin . fs ) {
XF86VidModeSwitchToMode ( GLWin . dpy , GLWin . screen , & GLWin . deskMode ) ;
XF86VidModeSetViewPort ( GLWin . dpy , GLWin . screen , 0 , 0 ) ;
}
}
# endif
mapGLExtensions . clear ( ) ;
}
void ZeroGS : : GSStateReset ( )
{
icurctx = - 1 ;
for ( int i = 0 ; i < 2 ; + + i ) {
vb [ i ] . Destroy ( ) ;
memset ( & vb [ i ] , 0 , SIZEOF_VB ) ;
vb [ i ] . tex0 . tw = 1 ;
vb [ i ] . tex0 . th = 1 ;
vb [ i ] . scissor . x1 = 639 ;
vb [ i ] . scissor . y1 = 479 ;
vb [ i ] . tex0 . tbw = 64 ;
vb [ i ] . Init ( VB_BUFFERSIZE ) ;
}
s_RangeMngr . Clear ( ) ;
g_MemTargs . Destroy ( ) ;
s_RTs . Destroy ( ) ;
s_DepthRTs . Destroy ( ) ;
s_BitwiseTextures . Destroy ( ) ;
vb [ 0 ] . ictx = 0 ;
vb [ 1 ] . ictx = 1 ;
}
void ZeroGS : : AddMessage ( const char * pstr , u32 ms )
{
listMsgs . push_back ( MESSAGE ( pstr , timeGetTime ( ) + ms ) ) ;
}
void ZeroGS : : DrawText ( const char * pstr , int left , int top , u32 color )
{
cgGLDisableProfile ( cgvProf ) ;
cgGLDisableProfile ( cgfProf ) ;
glColor3f ( ( ( color > > 16 ) & 0xff ) / 255.0f , ( ( color > > 8 ) & 0xff ) / 255.0f , ( color & 0xff ) / 255.0f ) ;
font_p - > printString ( pstr , left * 2.0f / ( float ) nBackbufferWidth - 1 , 1 - top * 2.0f / ( float ) nBackbufferHeight , 0 ) ;
cgGLEnableProfile ( cgvProf ) ;
cgGLEnableProfile ( cgfProf ) ;
}
void ZeroGS : : ChangeWindowSize ( int nNewWidth , int nNewHeight )
{
nBackbufferWidth = nNewWidth > 16 ? nNewWidth : 16 ;
nBackbufferHeight = nNewHeight > 16 ? nNewHeight : 16 ;
if ( ! ( conf . options & GSOPTION_FULLSCREEN ) ) {
conf . width = nNewWidth ;
conf . height = nNewHeight ;
//SaveConfig();
}
}
void ZeroGS : : SetChangeDeviceSize ( int nNewWidth , int nNewHeight )
{
s_nNewWidth = nNewWidth ;
s_nNewHeight = nNewHeight ;
if ( ! ( conf . options & GSOPTION_FULLSCREEN ) ) {
conf . width = nNewWidth ;
conf . height = nNewHeight ;
//SaveConfig();
}
}
void ZeroGS : : Reset ( )
{
s_RTs . ResolveAll ( ) ;
s_DepthRTs . ResolveAll ( ) ;
vb [ 0 ] . nCount = 0 ;
vb [ 1 ] . nCount = 0 ;
memset ( s_nResolveCounts , 0 , sizeof ( s_nResolveCounts ) ) ;
s_nLastResolveReset = 0 ;
icurctx = - 1 ;
g_vsprog = g_psprog = 0 ;
GSStateReset ( ) ;
Destroy ( 0 ) ;
drawfn [ 0 ] = KickDummy ;
drawfn [ 1 ] = KickDummy ;
drawfn [ 2 ] = KickDummy ;
drawfn [ 3 ] = KickDummy ;
drawfn [ 4 ] = KickDummy ;
drawfn [ 5 ] = KickDummy ;
drawfn [ 6 ] = KickDummy ;
drawfn [ 7 ] = KickDummy ;
}
void ZeroGS : : ChangeDeviceSize ( int nNewWidth , int nNewHeight )
{
int oldscreen = s_nFullscreen ;
int oldwidth = nBackbufferWidth , oldheight = nBackbufferHeight ;
if ( ! Create ( nNewWidth & ~ 7 , nNewHeight & ~ 7 ) ) {
ERROR_LOG ( " Failed to recreate, changing to old \n " ) ;
if ( ! Create ( oldwidth , oldheight ) ) {
SysMessage ( " failed to create dev, exiting... \n " ) ;
exit ( 0 ) ;
}
}
for ( int i = 0 ; i < 2 ; + + i ) {
vb [ i ] . bNeedFrameCheck = vb [ i ] . bNeedZCheck = 1 ;
vb [ i ] . CheckFrame ( 0 ) ;
}
if ( oldscreen & & ! ( conf . options & GSOPTION_FULLSCREEN ) ) { // if transitioning from full screen
RECT rc ;
rc . left = 0 ; rc . top = 0 ;
rc . right = conf . width ; rc . bottom = conf . height ;
# ifdef _WIN32
AdjustWindowRect ( & rc , conf . winstyle , FALSE ) ;
RECT rcdesktop ;
GetWindowRect ( GetDesktopWindow ( ) , & rcdesktop ) ;
SetWindowLong ( GShwnd , GWL_STYLE , conf . winstyle ) ;
SetWindowPos ( GShwnd , HWND_TOP , ( ( rcdesktop . right - rcdesktop . left ) - ( rc . right - rc . left ) ) / 2 ,
( ( rcdesktop . bottom - rcdesktop . top ) - ( rc . bottom - rc . top ) ) / 2 ,
rc . right - rc . left , rc . bottom - rc . top , SWP_SHOWWINDOW ) ;
UpdateWindow ( GShwnd ) ;
# else // linux
# endif
}
assert ( vb [ 0 ] . pBufferData ! = NULL & & vb [ 1 ] . pBufferData ! = NULL ) ;
}
void ZeroGS : : SetAA ( int mode )
{
float f ;
// need to flush all targets
s_RTs . ResolveAll ( ) ;
s_RTs . Destroy ( ) ;
s_DepthRTs . ResolveAll ( ) ;
s_DepthRTs . Destroy ( ) ;
s_AAx = s_AAy = 0 ; // This is code for x0, x2, x4, x8 and x16 anti-aliasing.
if ( mode > 0 )
{
s_AAx = ( mode + 1 ) / 2 ; // ( 1, 0 ) ; ( 1, 1 ) ; ( 2, 1 ) ; ( 2, 2 ) -- it's used as binary shift, so x >> s_AAx, y >> s_AAy
s_AAy = mode / 2 ;
}
memset ( s_nResolveCounts , 0 , sizeof ( s_nResolveCounts ) ) ;
s_nLastResolveReset = 0 ;
vb [ 0 ] . prndr = NULL ; vb [ 0 ] . pdepth = NULL ; vb [ 0 ] . bNeedFrameCheck = 1 ; vb [ 0 ] . bNeedZCheck = 1 ;
vb [ 1 ] . prndr = NULL ; vb [ 1 ] . pdepth = NULL ; vb [ 1 ] . bNeedFrameCheck = 1 ; vb [ 1 ] . bNeedZCheck = 1 ;
f = mode > 0 ? 2.0f : 1.0f ;
glPointSize ( f ) ;
}
# define SET_UNIFORMPARAM(var, name) { \
p = cgGetNamedParameter ( pf - > prog , name ) ; \
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) \
pf - > var = p ; \
} \
void SetupFragmentProgramParameters ( FRAGMENTSHADER * pf , int context , int type )
{
// uniform parameters
CGparameter p ;
p = cgGetNamedParameter ( pf - > prog , " g_fFogColor " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
cgConnectParameter ( g_fparamFogColor , p ) ;
}
SET_UNIFORMPARAM ( sOneColor , " g_fOneColor " ) ;
SET_UNIFORMPARAM ( sBitBltZ , " g_fBitBltZ " ) ;
SET_UNIFORMPARAM ( sInvTexDims , " g_fInvTexDims " ) ;
SET_UNIFORMPARAM ( fTexAlpha2 , " fTexAlpha2 " ) ;
SET_UNIFORMPARAM ( fTexOffset , " g_fTexOffset " ) ;
SET_UNIFORMPARAM ( fTexDims , " g_fTexDims " ) ;
SET_UNIFORMPARAM ( fTexBlock , " g_fTexBlock " ) ;
SET_UNIFORMPARAM ( fClampExts , " g_fClampExts " ) ;
SET_UNIFORMPARAM ( fTexWrapMode , " TexWrapMode " ) ;
SET_UNIFORMPARAM ( fRealTexDims , " g_fRealTexDims " ) ;
SET_UNIFORMPARAM ( fTestBlack , " g_fTestBlack " ) ;
SET_UNIFORMPARAM ( fPageOffset , " g_fPageOffset " ) ;
SET_UNIFORMPARAM ( fTexAlpha , " fTexAlpha " ) ;
// textures
p = cgGetNamedParameter ( pf - > prog , " g_sBlocks " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
cgGLSetTextureParameter ( p , ptexBlocks ) ;
cgGLEnableTextureParameter ( p ) ;
}
// cg parameter usage is wrong, so do it manually
if ( type = = 3 ) {
p = cgGetNamedParameter ( pf - > prog , " g_sConv16to32 " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
cgGLSetTextureParameter ( p , ptexConv16to32 ) ;
cgGLEnableTextureParameter ( p ) ;
}
}
else if ( type = = 4 ) {
p = cgGetNamedParameter ( pf - > prog , " g_sConv32to16 " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
cgGLSetTextureParameter ( p , ptexConv32to16 ) ;
cgGLEnableTextureParameter ( p ) ;
}
}
else {
p = cgGetNamedParameter ( pf - > prog , " g_sBilinearBlocks " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
cgGLSetTextureParameter ( p , ptexBilinearBlocks ) ;
cgGLEnableTextureParameter ( p ) ;
}
}
p = cgGetNamedParameter ( pf - > prog , " g_sMemory " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
//cgGLEnableTextureParameter(p);
pf - > sMemory = p ;
}
p = cgGetNamedParameter ( pf - > prog , " g_sSrcFinal " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
//cgGLEnableTextureParameter(p);
pf - > sFinal = p ;
}
p = cgGetNamedParameter ( pf - > prog , " g_sBitwiseANDX " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
//cgGLEnableTextureParameter(p);
pf - > sBitwiseANDX = p ;
}
p = cgGetNamedParameter ( pf - > prog , " g_sBitwiseANDY " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
//cgGLEnableTextureParameter(p);
pf - > sBitwiseANDY = p ;
}
p = cgGetNamedParameter ( pf - > prog , " g_sCLUT " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
//cgGLEnableTextureParameter(p);
pf - > sCLUT = p ;
}
p = cgGetNamedParameter ( pf - > prog , " g_sInterlace " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
//cgGLEnableTextureParameter(p);
pf - > sInterlace = p ;
}
// set global shader constants
p = cgGetNamedParameter ( pf - > prog , " g_fExactColor " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE ) {
cgGLSetParameter4fv ( p , Vector ( 0.5f , ( g_GameSettings & GAME_EXACTCOLOR ) ? 0.9f / 256.0f : 0.5f / 256.0f , 0 , 1 / 255.0f ) ) ;
}
p = cgGetNamedParameter ( pf - > prog , " g_fBilinear " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , Vector ( - 0.2f , - 0.65f , 0.9f , 1.0f / 32767.0f ) ) ;
p = cgGetNamedParameter ( pf - > prog , " g_fZBias " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , Vector ( 1.0f / 256.0f , 1.0004f , 1 , 0.5f ) ) ;
p = cgGetNamedParameter ( pf - > prog , " g_fc0 " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , Vector ( 0 , 1 , 0.001f , 0.5f ) ) ;
p = cgGetNamedParameter ( pf - > prog , " g_fMult " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , pf - > prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , Vector ( 1 / 1024.0f , 0.2f / 1024.0f , 1 / 128.0f , 1 / 512.0f ) ) ;
}
void SetupVertexProgramParameters ( CGprogram prog , int context )
{
CGparameter p ;
p = cgGetNamedParameter ( prog , " g_fPosXY " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , prog ) = = CG_TRUE )
cgConnectParameter ( g_vparamPosXY [ context ] , p ) ;
p = cgGetNamedParameter ( prog , " g_fZ " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , g_vdepth ) ;
Vector vnorm = Vector ( g_filog32 , 0 , 0 , 0 ) ;
p = cgGetNamedParameter ( prog , " g_fZNorm " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , vnorm ) ;
p = cgGetNamedParameter ( prog , " g_fBilinear " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , Vector ( - 0.2f , - 0.65f , 0.9f , 1.0f / 32767.0f ) ) ;
p = cgGetNamedParameter ( prog , " g_fZBias " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , Vector ( 1.0f / 256.0f , 1.0004f , 1 , 0.5f ) ) ;
p = cgGetNamedParameter ( prog , " g_fc0 " ) ;
if ( p ! = NULL & & cgIsParameterUsed ( p , prog ) = = CG_TRUE )
cgGLSetParameter4fv ( p , Vector ( 0 , 1 , 0.001f , 0.5f ) ) ;
}
# ifdef RELEASE_TO_PUBLIC
# define LOAD_VS(Index, prog) { \
assert ( mapShaderResources . find ( Index ) ! = mapShaderResources . end ( ) ) ; \
header = mapShaderResources [ Index ] ; \
assert ( ( header ) ! = NULL & & ( header ) - > index = = ( Index ) ) ; \
prog = cgCreateProgram ( g_cgcontext , CG_OBJECT , ( char * ) ( s_lpShaderResources + ( header ) - > offset ) , cgvProf , NULL , NULL ) ; \
if ( ! cgIsProgram ( prog ) ) { \
ERROR_LOG ( " Failed to load vs %d: \n %s \n " , Index , cgGetLastListing ( g_cgcontext ) ) ; \
return false ; \
} \
cgGLLoadProgram ( prog ) ; \
if ( cgGetError ( ) ! = CG_NO_ERROR ) ERROR_LOG ( " failed to load program %d \n " , Index ) ; \
SetupVertexProgramParameters ( prog , ! ! ( Index & SH_CONTEXT1 ) ) ; \
} \
# define LOAD_PS(Index, fragment) { \
bLoadSuccess = true ; \
assert ( mapShaderResources . find ( Index ) ! = mapShaderResources . end ( ) ) ; \
header = mapShaderResources [ Index ] ; \
fragment . prog = cgCreateProgram ( g_cgcontext , CG_OBJECT , ( char * ) ( s_lpShaderResources + ( header ) - > offset ) , cgfProf , NULL , NULL ) ; \
if ( ! cgIsProgram ( fragment . prog ) ) { \
ERROR_LOG ( " Failed to load ps %d: \n %s \n " , Index , cgGetLastListing ( g_cgcontext ) ) ; \
return false ; \
} \
cgGLLoadProgram ( fragment . prog ) ; \
if ( cgGetError ( ) ! = CG_NO_ERROR ) { \
ERROR_LOG ( " failed to load program %d \n " , Index ) ; \
bLoadSuccess = false ; \
} \
SetupFragmentProgramParameters ( & fragment , ! ! ( Index & SH_CONTEXT1 ) , 0 ) ; \
} \
bool ZeroGS : : LoadEffects ( )
{
assert ( s_lpShaderResources ! = NULL ) ;
// process the header
u32 num = * ( u32 * ) s_lpShaderResources ;
int compressed_size = * ( int * ) ( s_lpShaderResources + 4 ) ;
int real_size = * ( int * ) ( s_lpShaderResources + 8 ) ;
int out ;
char * pbuffer = ( char * ) malloc ( real_size ) ;
inf ( ( char * ) s_lpShaderResources + 12 , & pbuffer [ 0 ] , compressed_size , real_size , & out ) ;
assert ( out = = real_size ) ;
s_lpShaderResources = ( u8 * ) pbuffer ;
SHADERHEADER * header = ( SHADERHEADER * ) s_lpShaderResources ;
mapShaderResources . clear ( ) ;
while ( num - - > 0 ) {
mapShaderResources [ header - > index ] = header ;
+ + header ;
}
// clear the textures
for ( int i = 0 ; i < ARRAY_SIZE ( ppsTexture ) ; + + i ) {
SAFE_RELEASE_PROG ( ppsTexture [ i ] . prog ) ;
ppsTexture [ i ] . prog = NULL ;
}
# ifndef _DEBUG
memset ( ppsTexture , 0 , sizeof ( ppsTexture ) ) ;
# endif
return true ;
}
// called
bool ZeroGS : : LoadExtraEffects ( )
{
SHADERHEADER * header ;
bool bLoadSuccess = true ;
const int vsshaders [ 4 ] = { SH_REGULARVS , SH_TEXTUREVS , SH_REGULARFOGVS , SH_TEXTUREFOGVS } ;
for ( int i = 0 ; i < 4 ; + + i ) {
LOAD_VS ( vsshaders [ i ] , pvs [ 2 * i ] ) ;
LOAD_VS ( vsshaders [ i ] | SH_CONTEXT1 , pvs [ 2 * i + 1 ] ) ;
//if( conf.mrtdepth ) {
LOAD_VS ( vsshaders [ i ] | SH_WRITEDEPTH , pvs [ 2 * i + 8 ] ) ;
LOAD_VS ( vsshaders [ i ] | SH_WRITEDEPTH | SH_CONTEXT1 , pvs [ 2 * i + 8 + 1 ] ) ;
// }
// else {
// pvs[2*i+8] = pvs[2*i+8+1] = NULL;
// }
}
LOAD_VS ( SH_BITBLTVS , pvsBitBlt . prog ) ;
pvsBitBlt . sBitBltPos = cgGetNamedParameter ( pvsBitBlt . prog , " g_fBitBltPos " ) ;
pvsBitBlt . sBitBltTex = cgGetNamedParameter ( pvsBitBlt . prog , " g_fBitBltTex " ) ;
pvsBitBlt . fBitBltTrans = cgGetNamedParameter ( pvsBitBlt . prog , " g_fBitBltTrans " ) ;
LOAD_PS ( SH_REGULARPS , ppsRegular [ 0 ] ) ;
LOAD_PS ( SH_REGULARFOGPS , ppsRegular [ 1 ] ) ;
if ( conf . mrtdepth ) {
LOAD_PS ( SH_REGULARPS , ppsRegular [ 2 ] ) ;
if ( ! bLoadSuccess )
conf . mrtdepth = 0 ;
LOAD_PS ( SH_REGULARFOGPS , ppsRegular [ 3 ] ) ;
if ( ! bLoadSuccess )
conf . mrtdepth = 0 ;
}
LOAD_PS ( SH_BITBLTPS , ppsBitBlt [ 0 ] ) ;
LOAD_PS ( SH_BITBLTAAPS , ppsBitBlt [ 1 ] ) ;
if ( ! bLoadSuccess ) {
ERROR_LOG ( " Failed to load BitBltAAPS, using BitBltPS \n " ) ;
LOAD_PS ( SH_BITBLTPS , ppsBitBlt [ 1 ] ) ;
}
LOAD_PS ( SH_BITBLTDEPTHPS , ppsBitBltDepth ) ;
LOAD_PS ( SH_CRTCTARGPS , ppsCRTCTarg [ 0 ] ) ;
LOAD_PS ( SH_CRTCTARGINTERPS , ppsCRTCTarg [ 1 ] ) ;
g_bCRTCBilinear = TRUE ;
LOAD_PS ( SH_CRTCPS , ppsCRTC [ 0 ] ) ;
if ( ! bLoadSuccess ) {
// switch to simpler
g_bCRTCBilinear = FALSE ;
LOAD_PS ( SH_CRTC_NEARESTPS , ppsCRTC [ 0 ] ) ;
LOAD_PS ( SH_CRTCINTER_NEARESTPS , ppsCRTC [ 0 ] ) ;
}
else {
LOAD_PS ( SH_CRTCINTERPS , ppsCRTC [ 1 ] ) ;
}
if ( ! bLoadSuccess )
ERROR_LOG ( " Failed to create CRTC shaders \n " ) ;
LOAD_PS ( SH_CRTC24PS , ppsCRTC24 [ 0 ] ) ;
LOAD_PS ( SH_CRTC24INTERPS , ppsCRTC24 [ 1 ] ) ;
LOAD_PS ( SH_ZEROPS , ppsOne ) ;
LOAD_PS ( SH_BASETEXTUREPS , ppsBaseTexture ) ;
LOAD_PS ( SH_CONVERT16TO32PS , ppsConvert16to32 ) ;
LOAD_PS ( SH_CONVERT32TO16PS , ppsConvert32to16 ) ;
return true ;
}
FRAGMENTSHADER * ZeroGS : : LoadShadeEffect ( int type , int texfilter , int fog , int testaem , int exactcolor , const clampInfo & clamp , int context , bool * pbFailed )
{
int texwrap ;
assert ( texfilter < NUM_FILTERS ) ;
if ( g_nPixelShaderVer & SHADER_REDUCED )
texfilter = 0 ;
assert ( ! ( g_nPixelShaderVer & SHADER_REDUCED ) | | ! exactcolor ) ;
if ( clamp . wms = = clamp . wmt ) {
switch ( clamp . wms ) {
case 0 : texwrap = TEXWRAP_REPEAT ; break ;
case 1 : texwrap = TEXWRAP_CLAMP ; break ;
case 2 : texwrap = TEXWRAP_CLAMP ; break ;
default : texwrap = TEXWRAP_REGION_REPEAT ; break ;
}
}
else if ( clamp . wms = = 3 | | clamp . wmt = = 3 )
texwrap = TEXWRAP_REGION_REPEAT ;
else
texwrap = TEXWRAP_REPEAT_CLAMP ;
int index = GET_SHADER_INDEX ( type , texfilter , texwrap , fog , s_bWriteDepth , testaem , exactcolor , context , 0 ) ;
assert ( index < ARRAY_SIZE ( ppsTexture ) ) ;
FRAGMENTSHADER * pf = ppsTexture + index ;
if ( pbFailed ! = NULL ) * pbFailed = false ;
if ( pf - > prog ! = NULL )
return pf ;
if ( ( g_nPixelShaderVer & SHADER_ACCURATE ) & & mapShaderResources . find ( index + NUM_SHADERS * SHADER_ACCURATE ) ! = mapShaderResources . end ( ) )
index + = NUM_SHADERS * SHADER_ACCURATE ;
assert ( mapShaderResources . find ( index ) ! = mapShaderResources . end ( ) ) ;
SHADERHEADER * header = mapShaderResources [ index ] ;
if ( header = = NULL )
ERROR_LOG ( " %d %d \n " , index , g_nPixelShaderVer ) ;
assert ( header ! = NULL ) ;
//DEBUG_LOG("shader:\n%s\n", (char*)(s_lpShaderResources + (header)->offset));
pf - > prog = cgCreateProgram ( g_cgcontext , CG_OBJECT , ( char * ) ( s_lpShaderResources + ( header ) - > offset ) , cgfProf , NULL , NULL ) ;
if ( pf - > prog ! = NULL & & cgIsProgram ( pf - > prog ) & & cgGetError ( ) = = CG_NO_ERROR ) {
SetupFragmentProgramParameters ( pf , context , type ) ;
cgGLLoadProgram ( pf - > prog ) ;
if ( cgGetError ( ) ! = CG_NO_ERROR ) {
// cgGLLoadProgram(pf->prog);
// if( cgGetError() != CG_NO_ERROR ) {
ERROR_LOG ( " Failed to load shader %d,%d,%d,%d \n " , type , fog , texfilter , 4 * clamp . wms + clamp . wmt ) ;
if ( pbFailed ! = NULL ) * pbFailed = true ;
return pf ;
// }
}
return pf ;
}
ERROR_LOG ( " Failed to create shader %d,%d,%d,%d \n " , type , fog , texfilter , 4 * clamp . wms + clamp . wmt ) ;
if ( pbFailed ! = NULL ) * pbFailed = true ;
return NULL ;
}
# else // not RELEASE_TO_PUBLIC
# define LOAD_VS(name, prog, shaderver) { \
prog = cgCreateProgramFromFile ( g_cgcontext , CG_SOURCE , EFFECT_NAME , shaderver , name , args ) ; \
if ( ! cgIsProgram ( prog ) ) { \
ERROR_LOG ( " Failed to load vs %s: \n %s \n " , name , cgGetLastListing ( g_cgcontext ) ) ; \
return false ; \
} \
cgGLLoadProgram ( prog ) ; \
if ( cgGetError ( ) ! = CG_NO_ERROR ) ERROR_LOG ( " failed to load program %s \n " , name ) ; \
SetupVertexProgramParameters ( prog , args [ 0 ] = = context1 ) ; \
} \
# ifdef _DEBUG
# define SET_PSFILENAME(frag, name) frag.filename = name
# else
# define SET_PSFILENAME(frag, name)
# endif
# define LOAD_PS(name, fragment, shaderver) { \
bLoadSuccess = true ; \
fragment . prog = cgCreateProgramFromFile ( g_cgcontext , CG_SOURCE , EFFECT_NAME , shaderver , name , args ) ; \
if ( ! cgIsProgram ( fragment . prog ) ) { \
ERROR_LOG ( " Failed to load ps %s: \n %s \n " , name , cgGetLastListing ( g_cgcontext ) ) ; \
return false ; \
} \
cgGLLoadProgram ( fragment . prog ) ; \
if ( cgGetError ( ) ! = CG_NO_ERROR ) { \
ERROR_LOG ( " failed to load program %s \n " , name ) ; \
bLoadSuccess = false ; \
} \
SetupFragmentProgramParameters ( & fragment , args [ 0 ] = = context1 , 0 ) ; \
SET_PSFILENAME ( fragment , name ) ; \
} \
bool ZeroGS : : LoadEffects ( )
{
// clear the textures
for ( int i = 0 ; i < ARRAY_SIZE ( ppsTexture ) ; + + i ) {
SAFE_RELEASE_PROG ( ppsTexture [ i ] . prog ) ;
}
# ifndef _DEBUG
memset ( ppsTexture , 0 , sizeof ( ppsTexture ) ) ;
# endif
return true ;
}
bool ZeroGS : : LoadExtraEffects ( )
{
const char * args [ ] = { NULL , NULL , NULL , NULL } ;
char context0 [ 255 ] , context1 [ 255 ] ;
sprintf ( context0 , " -I%sctx0 " , EFFECT_DIR ) ;
sprintf ( context1 , " -I%sctx1 " , EFFECT_DIR ) ;
char * write_depth = " -DWRITE_DEPTH " ;
bool bLoadSuccess = true ;
const char * pvsshaders [ 4 ] = { " RegularVS " , " TextureVS " , " RegularFogVS " , " TextureFogVS " } ;
for ( int i = 0 ; i < 4 ; + + i ) {
args [ 0 ] = context0 ;
args [ 1 ] = NULL ;
LOAD_VS ( pvsshaders [ i ] , pvs [ 2 * i ] , cgvProf ) ;
args [ 0 ] = context1 ;
LOAD_VS ( pvsshaders [ i ] , pvs [ 2 * i + 1 ] , cgvProf ) ;
//if( conf.mrtdepth ) {
args [ 0 ] = context0 ;
args [ 1 ] = write_depth ;
LOAD_VS ( pvsshaders [ i ] , pvs [ 2 * i + 8 ] , cgvProf ) ;
args [ 0 ] = context1 ;
LOAD_VS ( pvsshaders [ i ] , pvs [ 2 * i + 8 + 1 ] , cgvProf ) ;
// }
// else {
// pvs[2*i+8] = pvs[2*i+8+1] = NULL;
// }
}
args [ 0 ] = context0 ;
args [ 1 ] = NULL ;
LOAD_VS ( " BitBltVS " , pvsBitBlt . prog , cgvProf ) ;
pvsBitBlt . sBitBltPos = cgGetNamedParameter ( pvsBitBlt . prog , " g_fBitBltPos " ) ;
pvsBitBlt . sBitBltTex = cgGetNamedParameter ( pvsBitBlt . prog , " g_fBitBltTex " ) ;
pvsBitBlt . fBitBltTrans = cgGetNamedParameter ( pvsBitBlt . prog , " g_fBitBltTrans " ) ;
LOAD_PS ( " RegularPS " , ppsRegular [ 0 ] , cgfProf ) ;
LOAD_PS ( " RegularFogPS " , ppsRegular [ 1 ] , cgfProf ) ;
if ( conf . mrtdepth ) {
args [ 0 ] = context0 ;
args [ 1 ] = write_depth ;
LOAD_PS ( " RegularPS " , ppsRegular [ 2 ] , cgfProf ) ;
if ( ! bLoadSuccess )
conf . mrtdepth = 0 ;
LOAD_PS ( " RegularFogPS " , ppsRegular [ 3 ] , cgfProf ) ;
if ( ! bLoadSuccess )
conf . mrtdepth = 0 ;
}
LOAD_PS ( " BitBltPS " , ppsBitBlt [ 0 ] , cgfProf ) ;
LOAD_PS ( " BitBltAAPS " , ppsBitBlt [ 1 ] , cgfProf ) ;
if ( ! bLoadSuccess ) {
ERROR_LOG ( " Failed to load BitBltAAPS, using BitBltPS \n " ) ;
LOAD_PS ( " BitBltPS " , ppsBitBlt [ 1 ] , cgfProf ) ;
}
LOAD_PS ( " BitBltDepthPS " , ppsBitBltDepth , cgfProf ) ;
LOAD_PS ( " CRTCTargPS " , ppsCRTCTarg [ 0 ] , cgfProf ) ; LOAD_PS ( " CRTCTargInterPS " , ppsCRTCTarg [ 1 ] , cgfProf ) ;
g_bCRTCBilinear = TRUE ;
LOAD_PS ( " CRTCPS " , ppsCRTC [ 0 ] , cgfProf ) ;
if ( ! bLoadSuccess ) {
// switch to simpler
g_bCRTCBilinear = FALSE ;
LOAD_PS ( " CRTCPS_Nearest " , ppsCRTC [ 0 ] , cgfProf ) ;
LOAD_PS ( " CRTCInterPS_Nearest " , ppsCRTC [ 0 ] , cgfProf ) ;
}
else {
LOAD_PS ( " CRTCInterPS " , ppsCRTC [ 1 ] , cgfProf ) ;
}
if ( ! bLoadSuccess )
ERROR_LOG ( " Failed to create CRTC shaders \n " ) ;
LOAD_PS ( " CRTC24PS " , ppsCRTC24 [ 0 ] , cgfProf ) ; LOAD_PS ( " CRTC24InterPS " , ppsCRTC24 [ 1 ] , cgfProf ) ;
LOAD_PS ( " ZeroPS " , ppsOne , cgfProf ) ;
LOAD_PS ( " BaseTexturePS " , ppsBaseTexture , cgfProf ) ;
LOAD_PS ( " Convert16to32PS " , ppsConvert16to32 , cgfProf ) ;
LOAD_PS ( " Convert32to16PS " , ppsConvert32to16 , cgfProf ) ;
// if( !conf.mrtdepth ) {
// ERROR_LOG("Disabling MRT depth writing\n");
// s_bWriteDepth = FALSE;
// }
return true ;
}
FRAGMENTSHADER * ZeroGS : : LoadShadeEffect ( int type , int texfilter , int fog , int testaem , int exactcolor , const clampInfo & clamp , int context , bool * pbFailed )
{
int texwrap ;
assert ( texfilter < NUM_FILTERS ) ;
//assert( g_nPixelShaderVer == SHADER_30 );
if ( clamp . wms = = clamp . wmt ) {
switch ( clamp . wms ) {
case 0 : texwrap = TEXWRAP_REPEAT ; break ;
case 1 : texwrap = TEXWRAP_CLAMP ; break ;
case 2 : texwrap = TEXWRAP_CLAMP ; break ;
default :
texwrap = TEXWRAP_REGION_REPEAT ; break ;
}
}
else if ( clamp . wms = = 3 | | clamp . wmt = = 3 )
texwrap = TEXWRAP_REGION_REPEAT ;
else
texwrap = TEXWRAP_REPEAT_CLAMP ;
int index = GET_SHADER_INDEX ( type , texfilter , texwrap , fog , s_bWriteDepth , testaem , exactcolor , context , 0 ) ;
if ( pbFailed ! = NULL ) * pbFailed = false ;
FRAGMENTSHADER * pf = ppsTexture + index ;
if ( pf - > prog ! = NULL )
return pf ;
pf - > prog = LoadShaderFromType ( EFFECT_DIR , EFFECT_NAME , type , texfilter , texwrap , fog , s_bWriteDepth , testaem , exactcolor , g_nPixelShaderVer , context ) ;
if ( pf - > prog ! = NULL ) {
# ifdef _DEBUG
char str [ 255 ] ;
sprintf ( str , " Texture%s%d_%sPS " , fog ? " Fog " : " " , texfilter , g_pTexTypes [ type ] ) ;
pf - > filename = str ;
# endif
SetupFragmentProgramParameters ( pf , context , type ) ;
cgGLLoadProgram ( pf - > prog ) ;
if ( cgGetError ( ) ! = CG_NO_ERROR ) {
// try again
// cgGLLoadProgram(pf->prog);
// if( cgGetError() != CG_NO_ERROR ) {
ERROR_LOG ( " Failed to load shader %d,%d,%d,%d \n " , type , fog , texfilter , 4 * clamp . wms + clamp . wmt ) ;
if ( pbFailed ! = NULL ) * pbFailed = true ;
//assert(0);
// NULL makes things crash
return pf ;
// }
}
return pf ;
}
ERROR_LOG ( " Failed to create shader %d,%d,%d,%d \n " , type , fog , texfilter , 4 * clamp . wms + clamp . wmt ) ;
if ( pbFailed ! = NULL ) * pbFailed = true ;
return NULL ;
}
# endif // RELEASE_TO_PUBLIC
void ZeroGS : : Prim ( )
{
if ( g_bIsLost )
return ;
VB & curvb = vb [ prim - > ctxt ] ;
if ( curvb . CheckPrim ( ) )
Flush ( prim - > ctxt ) ;
curvb . curprim . _val = prim - > _val ;
// flush the other pipe if sharing the same buffer
// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].nCount > 0 )
// {
// assert( vb[prim->ctxt].nCount == 0 );
// Flush(!prim->ctxt);
// }
curvb . curprim . prim = prim - > prim ;
}
int GetTexFilter ( const tex1Info & tex1 )
{
// always force
if ( conf . bilinear = = 2 )
return 1 ;
int texfilter = 0 ;
if ( conf . bilinear & & ptexBilinearBlocks ! = 0 ) {
if ( tex1 . mmin < = 1 )
texfilter = tex1 . mmin | tex1 . mmag ;
else
texfilter = tex1 . mmag ? ( ( tex1 . mmin + 2 ) & 5 ) : tex1 . mmin ;
texfilter = texfilter = = 1 | | texfilter = = 4 | | texfilter = = 5 ;
}
return texfilter ;
}
void ZeroGS : : ReloadEffects ( )
{
# ifndef RELEASE_TO_PUBLIC
for ( int i = 0 ; i < ARRAY_SIZE ( ppsTexture ) ; + + i ) {
SAFE_RELEASE_PROG ( ppsTexture [ i ] . prog ) ;
}
memset ( ppsTexture , 0 , sizeof ( ppsTexture ) ) ;
LoadExtraEffects ( ) ;
# endif
}
static int s_ClutResolve = 0 ;
void ZeroGS : : Flush ( int context )
{
GL_REPORT_ERRORD ( ) ;
assert ( context > = 0 & & context < = 1 ) ;
# ifndef RELEASE_TO_PUBLIC
if ( g_bUpdateEffect ) {
ReloadEffects ( ) ;
g_bUpdateEffect = 0 ;
}
# endif
VB & curvb = vb [ context ] ;
const pixTest curtest = curvb . test ;
if ( curvb . nCount = = 0 | | ( curtest . zte & & curtest . ztst = = 0 ) | | g_bIsLost ) {
curvb . nCount = 0 ;
return ;
}
if ( s_RangeMngr . ranges . size ( ) > 0 ) {
// don't want infinite loop
u32 prevcount = curvb . nCount ;
curvb . nCount = 0 ;
FlushTransferRanges ( curvb . curprim . tme ? & curvb . tex0 : NULL ) ;
curvb . nCount = prevcount ;
//if( curvb.nCount == 0 )
// return;
}
if ( curvb . bNeedTexCheck ) {
curvb . FlushTexData ( ) ;
if ( curvb . nCount = = 0 )
return ;
}
DVProfileFunc _pf ( " Flush " ) ;
GL_REPORT_ERRORD ( ) ;
if ( curvb . bNeedFrameCheck | | curvb . bNeedZCheck ) {
curvb . CheckFrame ( curvb . curprim . tme ? curvb . tex0 . tbp0 : 0 ) ;
}
if ( curvb . prndr = = NULL | | curvb . pdepth = = NULL ) {
WARN_LOG ( " Current render target NULL (ctx: %d) " , context ) ;
curvb . nCount = 0 ;
return ;
}
# if defined(PRIM_LOG) && defined(_DEBUG)
static const char * patst [ 8 ] = { " NEVER " , " ALWAYS " , " LESS " , " LEQUAL " , " EQUAL " , " GEQUAL " , " GREATER " , " NOTEQUAL " } ;
static const char * pztst [ 4 ] = { " NEVER " , " ALWAYS " , " GEQUAL " , " GREATER " } ;
static const char * pafail [ 4 ] = { " KEEP " , " FB_ONLY " , " ZB_ONLY " , " RGB_ONLY " } ;
PRIM_LOG ( " **Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d \n " , context , vb [ context ] . nCount , curvb . prndr - > fbp , curvb . zbuf . zbp , curvb . prndr - > psm , curvb . zbuf . psm , curvb . prndr - > fbw ) ;
PRIM_LOG ( " prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x \n " ,
curvb . curprim . prim , curvb . curprim . iip , curvb . curprim . tme , curvb . curprim . fge , curvb . curprim . abe , curvb . curprim . aa1 , curvb . curprim . fst , curvb . curprim . ctxt , curvb . curprim . fix ) ;
PRIM_LOG ( " test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d \n " ,
curvb . test . ate , patst [ curvb . test . atst ] , curvb . test . aref , pafail [ curvb . test . afail ] , curvb . test . date , curvb . test . datm , curvb . test . zte , pztst [ curvb . test . ztst ] , curvb . fba . fba ) ;
PRIM_LOG ( " alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d \n " , curvb . alpha . a , curvb . alpha . b , curvb . alpha . c , curvb . alpha . d , curvb . alpha . fix , gs . pabe , gs . texa . aem , gs . texa . ta [ 0 ] , gs . texa . ta [ 1 ] ) ;
PRIM_LOG ( " tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d \n " ,
curvb . tex0 . tbp0 , curvb . tex0 . tbw , curvb . tex0 . psm , curvb . tex0 . tw ,
curvb . tex0 . th , curvb . tex0 . tcc , curvb . tex0 . tfx , curvb . tex0 . cbp ,
curvb . tex0 . cpsm , curvb . tex0 . csm , curvb . tex0 . csa , curvb . tex0 . cld ) ;
PRIM_LOG ( " frame: %d \n \n " , g_SaveFrameNum ) ;
# endif
GL_REPORT_ERRORD ( ) ;
CRenderTarget * ptextarg = NULL ;
if ( curtest . date | | gs . pabe )
SetDestAlphaTest ( ) ;
// set the correct pixel shaders
if ( curvb . curprim . tme ) {
// if texture is part of a previous target, use that instead
int tbw = curvb . tex0 . tbw ;
int tbp0 = curvb . tex0 . tbp0 ;
int tpsm = curvb . tex0 . psm ;
if ( curvb . bNeedTexCheck ) {
// not yet initied, but still need to get correct target! (xeno3 ingame)
tbp0 = ( curvb . uNextTex0Data [ 0 ] & 0x3fff ) ;
tbw = ( ( curvb . uNextTex0Data [ 0 ] > > 14 ) & 0x3f ) * 64 ;
tpsm = ( curvb . uNextTex0Data [ 0 ] > > 20 ) & 0x3f ;
}
ptextarg = s_RTs . GetTarg ( tbp0 , tbw ) ;
if ( ( tpsm & 0x30 ) = = 0x30 & & ptextarg = = NULL ) {
// try depth
ptextarg = s_DepthRTs . GetTarg ( tbp0 , tbw ) ;
}
if ( ptextarg = = NULL & & ( g_GameSettings & GAME_TEXTURETARGS ) ) {
// check if any part of the texture intersects the current target
if ( ! PSMT_ISCLUT ( tpsm ) & & curvb . tex0 . tbp0 > = curvb . frame . fbp & & ( curvb . tex0 . tbp0 < < 8 ) < curvb . prndr - > end ) {
ptextarg = curvb . prndr ;
}
}
if ( ptextarg ! = NULL & & ! ( ptextarg - > status & CRenderTarget : : TS_NeedUpdate ) ) {
if ( PSMT_ISCLUT ( tpsm ) & & tpsm ! = PSMT8H ) { // handle 8h cluts
// don't support clut targets, read from mem
// 4hl - kh2 check - from dx version -- arcum42
if ( tpsm ! = PSMT4HL & & tpsm ! = PSMT4HH & & s_ClutResolve < = 1 )
{ // xenosaga requires 2 resolves
u32 prevcount = curvb . nCount ;
curvb . nCount = 0 ;
ptextarg - > Resolve ( ) ;
s_ClutResolve + + ;
curvb . nCount = prevcount ;
}
ptextarg = NULL ;
}
else {
if ( ptextarg = = curvb . prndr ) {
// need feedback
curvb . prndr - > CreateFeedback ( ) ;
if ( s_bWriteDepth & & curvb . pdepth ! = NULL )
curvb . pdepth - > SetRenderTarget ( 1 ) ;
else
ResetRenderTarget ( 1 ) ;
}
}
}
else ptextarg = NULL ;
}
# ifdef _DEBUG
if ( g_bSaveFlushedFrame & 0x80000000 ) {
char str [ 255 ] ;
sprintf ( str , " rndr.tga " , g_SaveFrameNum ) ;
SaveRenderTarget ( str , curvb . prndr - > fbw , curvb . prndr - > fbh , 0 ) ;
}
# endif
if ( conf . options & GSOPTION_WIREFRAME ) {
// always render first few geometry as solid
if ( s_nWireframeCount > 0 ) {
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
}
}
if ( ! curvb . bVarsSetTarg )
SetContextTarget ( context ) ;
else {
assert ( curvb . pdepth ! = NULL ) ;
if ( curvb . pdepth - > status & CRenderTarget : : TS_Virtual ) {
if ( ! curvb . zbuf . zmsk ) {
CRenderTarget * ptemp = s_DepthRTs . Promote ( curvb . pdepth - > fbp | ( curvb . pdepth - > fbw < < 16 ) ) ;
assert ( ptemp = = curvb . pdepth ) ;
}
else
curvb . pdepth - > status & = ~ CRenderTarget : : TS_NeedUpdate ;
}
if ( ( curvb . pdepth - > status & CRenderTarget : : TS_NeedUpdate ) | | ( curvb . prndr - > status & CRenderTarget : : TS_NeedUpdate ) )
SetContextTarget ( context ) ;
}
icurctx = context ;
DVProfileFunc _pf5 ( " Flush:after texvars " ) ;
glBindBuffer ( GL_ARRAY_BUFFER , g_vboBuffers [ g_nCurVBOIndex ] ) ;
g_nCurVBOIndex = ( g_nCurVBOIndex + 1 ) % g_vboBuffers . size ( ) ;
glBufferData ( GL_ARRAY_BUFFER , curvb . nCount * sizeof ( VertexGPU ) , curvb . pBufferData , GL_STREAM_DRAW ) ;
// void* pdata = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// memcpy_amd(pdata, curvb.pBufferData, curvb.nCount * sizeof(VertexGPU));
// glUnmapBuffer(GL_ARRAY_BUFFER);
SET_STREAM ( ) ;
assert ( ! ( curvb . prndr - > status & CRenderTarget : : TS_NeedUpdate ) ) ;
curvb . prndr - > status = 0 ;
if ( curvb . pdepth ! = NULL ) {
assert ( ! ( curvb . pdepth - > status & CRenderTarget : : TS_NeedUpdate ) ) ;
if ( ! curvb . zbuf . zmsk ) {
assert ( ! ( curvb . pdepth - > status & CRenderTarget : : TS_Virtual ) ) ;
curvb . pdepth - > status = 0 ;
}
}
# ifdef _DEBUG
//curvb.prndr->SetRenderTarget(0);
//curvb.pdepth->SetDepthStencilSurface();
//glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 );
GLenum status = glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) ;
assert ( glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) = = GL_FRAMEBUFFER_COMPLETE_EXT ) ;
# endif
s_dwColorWrite = ( curvb . prndr - > psm & 0xf ) = = 1 ? ( COLORMASK_BLUE | COLORMASK_GREEN | COLORMASK_RED ) : 0xf ;
if ( ( ( curvb . frame . fbm ) & 0xff ) = = 0xff ) s_dwColorWrite & = ~ COLORMASK_RED ;
if ( ( ( curvb . frame . fbm > > 8 ) & 0xff ) = = 0xff ) s_dwColorWrite & = ~ COLORMASK_GREEN ;
if ( ( ( curvb . frame . fbm > > 16 ) & 0xff ) = = 0xff ) s_dwColorWrite & = ~ COLORMASK_BLUE ;
if ( ( ( curvb . frame . fbm > > 24 ) & 0xff ) = = 0xff ) s_dwColorWrite & = ~ COLORMASK_ALPHA ;
GL_COLORMASK ( s_dwColorWrite ) ;
Rect & scissor = curvb . prndr - > scissorrect ;
glScissor ( scissor . x , scissor . y , scissor . w , scissor . h ) ;
u32 dwUsingSpecialTesting = 0 ;
u32 dwFilterOpts = 0 ;
FRAGMENTSHADER * pfragment = NULL ;
// need exact if equal or notequal
int exactcolor = 0 ;
if ( ! ( g_nPixelShaderVer & SHADER_REDUCED ) )
// ffx2 breaks when ==7
exactcolor = ( curtest . ate & & curtest . aref < = 128 ) & & ( curtest . atst = = 4 ) ; //||curtest.atst==7);
int shadertype = 0 ;
// set the correct pixel shaders
u32 ptexclut = 0 ;
if ( curvb . curprim . tme ) {
if ( ptextarg ! = NULL ) {
if ( ptextarg - > IsDepth ( ) )
SetWriteDepth ( ) ;
Vector vpageoffset ;
vpageoffset . w = 0 ;
int psm = curvb . tex0 . psm ;
if ( PSMT_ISCLUT ( curvb . tex0 . psm ) ) psm = curvb . tex0 . cpsm ;
shadertype = 1 ;
if ( curvb . tex0 . psm = = PSMT8H & & ! ( g_GameSettings & GAME_NOTARGETCLUT ) ) {
// load the clut to memory
glGenTextures ( 1 , & ptexclut ) ;
glBindTexture ( GL_TEXTURE_2D , ptexclut ) ;
vector < char > data ( ( curvb . tex0 . cpsm & 2 ) ? 512 : 1024 ) ;
if ( ptexclut ! = 0 ) {
// fill the buffer by decoding the clut
int nClutOffset = 0 , clutsize ;
int entries = ( curvb . tex0 . psm & 3 ) = = 3 ? 256 : 16 ;
if ( curvb . tex0 . cpsm < = 1 ) { // 32 bit
nClutOffset = 64 * curvb . tex0 . csa ;
clutsize = min ( entries , 256 - curvb . tex0 . csa * 16 ) * 4 ;
}
else {
nClutOffset = 64 * ( curvb . tex0 . csa & 15 ) + ( curvb . tex0 . csa > = 16 ? 2 : 0 ) ;
clutsize = min ( entries , 512 - curvb . tex0 . csa * 16 ) * 2 ;
}
if ( curvb . tex0 . cpsm < = 1 ) { // 32 bit
memcpy_amd ( & data [ 0 ] , g_pbyGSClut + nClutOffset , clutsize ) ;
}
else {
u16 * pClutBuffer = ( u16 * ) ( g_pbyGSClut + nClutOffset ) ;
u16 * pclut = ( u16 * ) & data [ 0 ] ;
int left = ( ( u32 ) nClutOffset & 2 ) ? 0 : ( ( nClutOffset & 0x3ff ) / 2 ) + clutsize - 512 ;
if ( left > 0 ) clutsize - = left ;
while ( clutsize > 0 ) {
pclut [ 0 ] = pClutBuffer [ 0 ] ;
pclut + + ;
pClutBuffer + = 2 ;
clutsize - = 2 ;
}
if ( left > 0 ) {
pClutBuffer = ( u16 * ) ( g_pbyGSClut + 2 ) ;
while ( left > 0 ) {
pclut [ 0 ] = pClutBuffer [ 0 ] ;
left - = 2 ;
pClutBuffer + = 2 ;
pclut + + ;
}
}
}
glTexImage2D ( GL_TEXTURE_2D , 0 , 4 , 256 , 1 , 0 , GL_RGBA , ( curvb . tex0 . cpsm & 2 ) ? GL_UNSIGNED_SHORT_5_5_5_1 : GL_UNSIGNED_BYTE , & data [ 0 ] ) ;
s_vecTempTextures . push_back ( ptexclut ) ;
if ( g_bSaveTex )
SaveTexture ( " clut.tga " , GL_TEXTURE_2D , ptexclut , 256 , 1 ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
}
if ( ! ( g_nPixelShaderVer & SHADER_REDUCED ) & & ( ptextarg - > psm & 2 ) ) {
shadertype = 4 ;
}
else
shadertype = 2 ;
}
else {
if ( PSMT_ISCLUT ( curvb . tex0 . psm ) )
WARN_LOG ( " Using render target with CLUTs %d! \n " , curvb . tex0 . psm ) ;
else {
if ( ( curvb . tex0 . psm & 2 ) ! = ( ptextarg - > psm & 2 ) & & ( ! ( g_nPixelShaderVer & SHADER_REDUCED ) | | ! curvb . curprim . fge ) ) {
if ( curvb . tex0 . psm & 2 ) {
// converting from 32->16
shadertype = 3 ;
}
else {
// converting from 16->32
WARN_LOG ( " ZeroGS: converting from 16 to 32bit RTs \n " ) ;
//shadetype = 4;
}
}
}
}
pfragment = LoadShadeEffect ( shadertype , 0 , curvb . curprim . fge , curvb . tex0 . tcc & & gs . texa . aem & & ( psm = = PSMCT24 | | psm = = PSMCT16 | | psm = = PSMCT16S ) ,
exactcolor , curvb . clamp , context , NULL ) ;
if ( shadertype = = 3 ) {
Vector v ;
v . x = 16.0f / ( float ) curvb . tex0 . tw ;
v . y = 16.0f / ( float ) curvb . tex0 . th ;
v . z = 0.5f * v . x ;
v . w = 0.5f * v . y ;
cgGLSetParameter4fv ( pfragment - > fTexOffset , v ) ;
vpageoffset . x = - 0.1f / 256.0f ;
vpageoffset . y = - 0.001f / 256.0f ;
vpageoffset . z = - 0.1f / ptextarg - > fbh ;
vpageoffset . w = ( ( ptextarg - > psm & 0x30 ) = = 0x30 ) ? - 1.0f : 0.0f ;
}
else if ( shadertype = = 4 ) {
Vector v ;
v . x = 16.0f / ( float ) ptextarg - > fbw ;
v . y = 16.0f / ( float ) ptextarg - > fbh ;
v . z = - 1 ;
v . w = 8.0f / ( float ) ptextarg - > fbh ;
cgGLSetParameter4fv ( pfragment - > fTexOffset , v ) ;
vpageoffset . x = 2 ;
vpageoffset . y = 1 ;
vpageoffset . z = 0 ;
vpageoffset . w = 0.0001f ;
}
u32 ptexset = ptextarg = = curvb . prndr ? ptextarg - > ptexFeedback : ptextarg - > ptex ;
s_ptexCurSet [ context ] = ptexset ;
if ( ! curvb . tex1 . mmag ) {
glBindTexture ( GL_TEXTURE_RECTANGLE_NV , ptexset ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
dwFilterOpts | = 1 ;
}
if ( ! curvb . tex1 . mmin ) {
if ( curvb . tex1 . mmag )
glBindTexture ( GL_TEXTURE_RECTANGLE_NV , ptexset ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
dwFilterOpts | = 2 ;
}
2009-02-14 23:47:09 +00:00
2009-02-09 21:15:56 +00:00
Vector vTexDims ;
2009-02-14 23:47:09 +00:00
vTexDims . x = curvb . tex0 . tw < < s_AAx ;
vTexDims . y = curvb . tex0 . th < < s_AAy ;
2009-02-09 21:15:56 +00:00
// look at the offset of tbp0 from fbp
if ( curvb . tex0 . tbp0 < = ptextarg - > fbp ) {
vTexDims . z = 0 ; //-0.5f/(float)ptextarg->fbw;
vTexDims . w = 0 ; //0.2f/(float)ptextarg->fbh;
}
else {
u32 tbp0 = curvb . tex0 . tbp0 > > 5 ; // align to a page
int blockheight = ( ptextarg - > psm & 2 ) ? 64 : 32 ;
int ycoord = ( ( curvb . tex0 . tbp0 - ptextarg - > fbp ) / ( 32 * ( ptextarg - > fbw > > 6 ) ) ) * blockheight ;
int xcoord = ( ( ( curvb . tex0 . tbp0 - ptextarg - > fbp ) % ( 32 * ( ptextarg - > fbw > > 6 ) ) ) ) * 2 ;
vTexDims . z = ( float ) xcoord ;
vTexDims . w = ( float ) ycoord ;
}
2009-02-14 23:47:09 +00:00
if ( shadertype = = 4 ) vTexDims . z + = 8.0f ;
2009-02-09 21:15:56 +00:00
cgGLSetParameter4fv ( pfragment - > fTexDims , vTexDims ) ;
// zoe2
if ( ( ptextarg - > psm & 0x30 ) = = 0x30 ) { //&& (psm&2) == (ptextarg->psm&2) ) {
// target of zbuf has +1 added to it, don't do 16bit
vpageoffset . w = - 1 ;
// Vector valpha2;
// valpha2.x = 1; valpha2.y = 0;
// valpha2.z = -1; valpha2.w = 0;
// SETCONSTF(GPU_TEXALPHA20+context, &valpha2);
}
cgGLSetParameter4fv ( pfragment - > fPageOffset , vpageoffset ) ;
if ( g_bSaveTex )
SaveTexture ( " tex.tga " , GL_TEXTURE_RECTANGLE_NV ,
ptextarg = = curvb . prndr ? ptextarg - > ptexFeedback : ptextarg - > ptex , ptextarg - > fbw < < s_AAx , ptextarg - > fbh < < s_AAy ) ;
}
else {
// save the texture
# ifdef _DEBUG
// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0);
// assert( curvb.pmemtarg == pmemtarg );
// if( PSMT_ISCLUT(curvb.tex0.psm) )
// assert( curvb.pmemtarg->ValidateClut(curvb.tex0) );
# endif
//#ifdef ZEROGS_CACHEDCLEAR
// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) {
// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1);
// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush);
// vb[context].bVarsTexSync = TRUE;
// }
//#endif
if ( g_bSaveTex ) {
if ( g_bSaveTex = = 1 ) {
SaveTex ( & curvb . tex0 , 1 ) ;
// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0);
// int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult;
// int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels;
// SaveTexture("real.tga", GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex, texwidth, texheight);
}
else SaveTex ( & curvb . tex0 , 0 ) ;
}
int psm = curvb . tex0 . psm ;
if ( PSMT_ISCLUT ( curvb . tex0 . psm ) ) psm = curvb . tex0 . cpsm ;
pfragment = LoadShadeEffect ( 0 , GetTexFilter ( curvb . tex1 ) , curvb . curprim . fge ,
curvb . tex0 . tcc & & gs . texa . aem & & ( psm = = PSMCT24 | | psm = = PSMCT16 | | psm = = PSMCT16S ) ,
exactcolor , curvb . clamp , context , NULL ) ;
}
if ( pfragment - > prog ! = g_psprog ) {
// programs changed, so reset the texture variables
vb [ context ] . bTexConstsSync = 0 ;
vb [ context ] . bVarsTexSync = 0 ;
}
SetTexVariables ( context , pfragment , ptextarg = = NULL ) ;
}
else {
pfragment = & ppsRegular [ curvb . curprim . fge + 2 * s_bWriteDepth ] ;
}
assert ( pfragment ! = 0 ) ;
if ( curvb . curprim . tme ) {
// have to enable the texture parameters
if ( curvb . ptexClamp [ 0 ] ! = 0 ) {
cgGLSetTextureParameter ( pfragment - > sBitwiseANDX , curvb . ptexClamp [ 0 ] ) ;
cgGLEnableTextureParameter ( pfragment - > sBitwiseANDX ) ;
}
if ( curvb . ptexClamp [ 1 ] ! = 0 ) {
cgGLSetTextureParameter ( pfragment - > sBitwiseANDY , curvb . ptexClamp [ 1 ] ) ;
cgGLEnableTextureParameter ( pfragment - > sBitwiseANDY ) ;
}
if ( pfragment - > sMemory ! = NULL & & s_ptexCurSet [ context ] ! = 0 ) {
cgGLSetTextureParameter ( pfragment - > sMemory , s_ptexCurSet [ context ] ) ;
cgGLEnableTextureParameter ( pfragment - > sMemory ) ;
}
if ( pfragment - > sCLUT ! = NULL & & ptexclut ! = 0 ) {
cgGLSetTextureParameter ( pfragment - > sCLUT , ptexclut ) ;
cgGLEnableTextureParameter ( pfragment - > sCLUT ) ;
}
}
DVProfileFunc _pf4 ( " Flush:before bind " ) ;
GL_REPORT_ERRORD ( ) ;
// set the shaders
SETVERTEXSHADER ( pvs [ 2 * ( ( curvb . curprim . _val > > 1 ) & 3 ) + 8 * s_bWriteDepth + context ] ) ;
if ( pfragment - > prog ! = g_psprog ) {
cgGLBindProgram ( pfragment - > prog ) ;
g_psprog = pfragment - > prog ;
}
GL_REPORT_ERRORD ( ) ;
DVProfileFunc _pf1 ( " Flush:after bind " ) ;
BOOL bCanRenderStencil = g_bUpdateStencil & & ( curvb . prndr - > psm & 0xf ) ! = 1 & & ! ( curvb . frame . fbm & 0x80000000 ) ;
if ( g_GameSettings & GAME_NOSTENCIL )
bCanRenderStencil = 0 ;
if ( s_bDestAlphaTest & & bCanRenderStencil ) {
glEnable ( GL_STENCIL_TEST ) ;
GL_STENCILFUNC ( GL_ALWAYS , 0 , 0 ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_KEEP ) ;
}
else glDisable ( GL_STENCIL_TEST ) ;
glDepthMask ( ! curvb . zbuf . zmsk ) ;
GL_ZTEST ( curtest . zte ) ;
if ( curtest . zte ) {
if ( curtest . ztst > 1 ) g_nDepthUsed = 2 ;
if ( ( curtest . ztst = = 2 ) ^ ( g_nDepthBias ! = 0 ) ) {
g_nDepthBias = curtest . ztst = = 2 ;
//SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f));
}
glDepthFunc ( g_dwZCmp [ curtest . ztst ] ) ;
// if( curtest.ztst == 3 ) {
// // gequal
// if( s_vznorm.y == 0 ) {
// s_vznorm.y = 0.00001f;
// SETCONSTF(GPU_ZNORM, s_vznorm);
// }
// }
// else {
// if( s_vznorm.y > 0 ) {
// s_vznorm.y = 0;
// SETCONSTF(GPU_ZNORM, s_vznorm);
// }
// }
}
GL_ALPHATEST ( curtest . ate & & USEALPHATESTING ) ;
if ( curtest . ate ) {
glAlphaFunc ( g_dwAlphaCmp [ curtest . atst ] , b2XAlphaTest ? min ( 1.0f , ( float ) curtest . aref * ( 1 / 127.5f ) ) : curtest . aref * ( 1 / 255.0f ) ) ;
}
if ( s_bWriteDepth ) {
if ( ! curvb . zbuf . zmsk )
curvb . pdepth - > SetRenderTarget ( 1 ) ;
else
ResetRenderTarget ( 1 ) ;
}
if ( curvb . curprim . abe )
SetAlphaVariables ( curvb . alpha ) ;
else
glDisable ( GL_BLEND ) ;
// needs to be before RenderAlphaTest
if ( curvb . fba . fba | | s_bDestAlphaTest ) {
if ( gs . pabe | | ( curvb . fba . fba | | bCanRenderStencil ) & & ! ( curvb . frame . fbm & 0x80000000 ) ) {
RenderFBA ( curvb , pfragment - > sOneColor ) ;
}
}
u32 oldabe = curvb . curprim . abe ;
if ( gs . pabe ) {
//WARN_LOG("PBE!\n");
curvb . curprim . abe = 1 ;
glEnable ( GL_BLEND ) ;
}
if ( curvb . curprim . abe ) {
if ( //bCanRenderStencil &&
( bNeedBlendFactorInAlpha | | ( ( curtest . ate & & curtest . atst > 1 ) & & ( curtest . aref > 0x80 ) ) ) ) {
// need special stencil processing for the alpha
RenderAlphaTest ( curvb , pfragment - > sOneColor ) ;
dwUsingSpecialTesting = 1 ;
}
// harvest fishing
Vector v = vAlphaBlendColor ; // + Vector(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0);
if ( exactcolor ) { v . y * = 255 ; v . w * = 255 ; }
cgGLSetParameter4fv ( pfragment - > sOneColor , v ) ;
}
else {
// not using blending so set to defaults
Vector v = exactcolor ? Vector ( 1 , 510 * 255.0f / 256.0f , 0 , 0 ) : Vector ( 1 , 2 * 255.0f / 256.0f , 0 , 0 ) ;
cgGLSetParameter4fv ( pfragment - > sOneColor , v ) ;
}
if ( s_bDestAlphaTest & & bCanRenderStencil ) {
// if not 24bit and can write to high alpha bit
RenderStencil ( curvb , dwUsingSpecialTesting ) ;
}
else {
s_stencilref = STENCIL_SPECIAL ;
s_stencilmask = STENCIL_SPECIAL ;
// setup the stencil to only accept the test pixels
if ( dwUsingSpecialTesting ) {
glEnable ( GL_STENCIL_TEST ) ;
glStencilMask ( STENCIL_PIXELWRITE ) ;
GL_STENCILFUNC ( GL_EQUAL , STENCIL_SPECIAL | STENCIL_PIXELWRITE , STENCIL_SPECIAL ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
}
}
# ifdef _DEBUG
if ( bDestAlphaColor = = 1 ) {
WARN_LOG ( " dest alpha blending! manipulate alpha here \n " ) ;
}
# endif
if ( bCanRenderStencil & & gs . pabe ) {
// only render the pixels with alpha values >= 0x80
GL_STENCILFUNC ( GL_EQUAL , s_stencilref | STENCIL_FBA , s_stencilmask | STENCIL_FBA ) ;
}
// curvb.prndr->SetViewport();
// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect);
// glEnable(GL_SCISSOR_TEST);
GL_REPORT_ERRORD ( ) ;
if ( ! curvb . test . ate | | curvb . test . atst > 0 ) {
DRAW ( ) ;
}
GL_REPORT_ERRORD ( ) ;
if ( gs . pabe ) {
// only render the pixels with alpha values < 0x80
glDisable ( GL_BLEND ) ;
GL_STENCILFUNC_SET ( ) ;
Vector v ;
v . x = 1 ; v . y = 2 ; v . z = 0 ; v . w = 0 ;
if ( exactcolor ) v . y * = 255 ;
cgGLSetParameter4fv ( pfragment - > sOneColor , v ) ;
DRAW ( ) ;
// reset
if ( ! s_stencilmask ) s_stencilfunc = GL_ALWAYS ;
GL_STENCILFUNC_SET ( ) ;
}
GL_REPORT_ERRORD ( ) ;
// more work on alpha failure case
if ( curtest . ate & & curtest . atst ! = 1 & & curtest . afail > 0 ) {
// need to reverse the test and disable some targets
glAlphaFunc ( g_dwReverseAlphaCmp [ curtest . atst ] , b2XAlphaTest ? min ( 1.0f , ( float ) curtest . aref * ( 1 / 127.5f ) ) : curtest . aref * ( 1 / 255.0f ) ) ;
if ( curtest . afail & 1 ) { // front buffer update only
if ( curtest . afail = = 3 ) // disable alpha
glColorMask ( 1 , 1 , 1 , 0 ) ;
glDepthMask ( 0 ) ;
if ( s_bWriteDepth )
ResetRenderTarget ( 1 ) ;
}
else {
// zbuffer update only
glColorMask ( 0 , 0 , 0 , 0 ) ;
}
if ( gs . pabe & & bCanRenderStencil ) {
// only render the pixels with alpha values >= 0x80
Vector v = vAlphaBlendColor ;
if ( exactcolor ) { v . y * = 255 ; v . w * = 255 ; }
cgGLSetParameter4fv ( pfragment - > sOneColor , v ) ;
glEnable ( GL_BLEND ) ;
GL_STENCILFUNC ( GL_EQUAL , s_stencilref | STENCIL_FBA , s_stencilmask | STENCIL_FBA ) ;
}
// IDirect3DQuery9* pOcclusionQuery;
// u32 numberOfPixelsDrawn;
//
// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery);
//
// // Add an end marker to the command buffer queue.
// pOcclusionQuery->Issue(D3DISSUE_BEGIN);
DRAW ( ) ;
GL_REPORT_ERRORD ( ) ;
// pOcclusionQuery->Issue(D3DISSUE_END);
// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(u32), D3DGETDATA_FLUSH ));
// SAFE_RELEASE(pOcclusionQuery);
if ( gs . pabe ) {
// only render the pixels with alpha values < 0x80
glDisable ( GL_BLEND ) ;
GL_STENCILFUNC_SET ( ) ;
Vector v ;
v . x = 1 ; v . y = 2 ; v . z = 0 ; v . w = 0 ;
if ( exactcolor ) v . y * = 255 ;
cgGLSetParameter4fv ( pfragment - > sOneColor , v ) ;
DRAW ( ) ;
// reset
if ( oldabe ) glEnable ( GL_BLEND ) ;
if ( ! s_stencilmask ) s_stencilfunc = GL_ALWAYS ;
GL_STENCILFUNC_SET ( ) ;
}
// restore
if ( ( curtest . afail & 1 ) & & ! curvb . zbuf . zmsk ) {
glDepthMask ( 1 ) ;
if ( s_bWriteDepth ) {
assert ( curvb . pdepth ! = NULL ) ;
curvb . pdepth - > SetRenderTarget ( 1 ) ;
}
}
GL_COLORMASK ( s_dwColorWrite ) ;
// not needed anymore since rest of ops concentrate on image processing
}
GL_REPORT_ERRORD ( ) ;
if ( dwUsingSpecialTesting ) {
// render the real alpha
glDisable ( GL_ALPHA_TEST ) ;
glColorMask ( 0 , 0 , 0 , 1 ) ;
if ( s_bWriteDepth ) {
ResetRenderTarget ( 1 ) ;
}
glDepthMask ( 0 ) ;
glStencilFunc ( GL_EQUAL , STENCIL_SPECIAL | STENCIL_PIXELWRITE , STENCIL_SPECIAL | STENCIL_PIXELWRITE ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_KEEP ) ;
Vector v = Vector ( 0 , exactcolor ? 510.0f : 2.0f , 0 , 0 ) ;
cgGLSetParameter4fv ( pfragment - > sOneColor , v ) ;
DRAW ( ) ;
// don't need to restore
}
GL_REPORT_ERRORD ( ) ;
if ( s_bDestAlphaTest ) {
if ( ( s_dwColorWrite & COLORMASK_ALPHA ) ) {
if ( curvb . fba . fba )
ProcessFBA ( curvb , pfragment - > sOneColor ) ;
else if ( bCanRenderStencil )
// finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case)
ProcessStencil ( curvb ) ;
}
}
else if ( ( s_dwColorWrite & COLORMASK_ALPHA ) & & curvb . fba . fba )
ProcessFBA ( curvb , pfragment - > sOneColor ) ;
if ( bDestAlphaColor = = 1 ) {
// need to reset the dest colors to their original counter parts
//WARN_LOG("Need to reset dest alpha color\n");
}
# ifdef _DEBUG
if ( g_bSaveFlushedFrame & 0xf ) {
# ifdef _WIN32
CreateDirectory ( " frames " , NULL ) ;
# else
mkdir ( " frames " , 0755 ) ;
# endif
char str [ 255 ] ;
sprintf ( str , " frames/frame%.4d.tga " , g_SaveFrameNum + + ) ;
if ( ( g_bSaveFlushedFrame & 2 ) ) {
//glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer
//glFlush();
//SaveTexture("tex.jpg", GL_TEXTURE_RECTANGLE_NV, curvb.prndr->ptex, curvb.prndr->fbw<<s_AAx, curvb.prndr->fbh<<s_AAx);
SaveRenderTarget ( str , curvb . prndr - > fbw < < s_AAx , curvb . prndr - > fbh < < s_AAx , 0 ) ;
}
}
# endif
GL_REPORT_ERRORD ( ) ;
// clamp the final colors, when enabled ffx2 credits mess up
if ( curvb . curprim . abe & & bAlphaClamping & & GetRenderFormat ( ) ! = RFT_byte8 & & ! ( g_GameSettings & GAME_NOCOLORCLAMP ) ) { // if !colclamp, skip
ResetAlphaVariables ( ) ;
// if processing the clamping case, make sure can write to the front buffer
glDisable ( GL_STENCIL_TEST ) ;
glEnable ( GL_BLEND ) ;
glDisable ( GL_ALPHA_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( 0 ) ;
glColorMask ( 1 , 1 , 1 , 0 ) ;
if ( s_bWriteDepth ) {
ResetRenderTarget ( 1 ) ;
}
SETPIXELSHADER ( ppsOne . prog ) ;
// (dest&0x7f)+0x80, blend factor for alpha is always 0x80
GL_BLEND_RGB ( GL_ONE , GL_ONE ) ;
float f ;
if ( bAlphaClamping & 1 ) { // min
f = 0 ;
cgGLSetParameter4fv ( ppsOne . sOneColor , & f ) ;
GL_BLENDEQ_RGB ( GL_MAX_EXT ) ;
DRAW ( ) ;
}
// bios shows white screen
if ( bAlphaClamping & 2 ) { // max
f = 1 ;
cgGLSetParameter4fv ( ppsOne . sOneColor , & f ) ;
GL_BLENDEQ_RGB ( GL_MIN_EXT ) ;
DRAW ( ) ;
}
if ( ! curvb . zbuf . zmsk ) {
glDepthMask ( 1 ) ;
if ( s_bWriteDepth ) {
assert ( curvb . pdepth ! = NULL ) ;
curvb . pdepth - > SetRenderTarget ( 1 ) ;
}
}
if ( curvb . test . ate & & USEALPHATESTING )
glEnable ( GL_ALPHA_TEST ) ;
GL_ZTEST ( curtest . zte ) ;
}
if ( dwFilterOpts ) {
// undo filter changes (binding didn't change)
if ( dwFilterOpts & 1 ) glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
if ( dwFilterOpts & 2 ) glTexParameteri ( GL_TEXTURE_RECTANGLE_NV , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
}
//#ifndef RELEASE_TO_PUBLIC
ppf + = curvb . nCount + 0x100000 ;
//#endif
curvb . nCount = 0 ;
curvb . curprim . abe = oldabe ;
//if( oldabe ) glEnable(GL_BLEND);
if ( conf . options & GSOPTION_WIREFRAME ) {
// always render first few geometry as solid
if ( s_nWireframeCount > 0 ) {
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
- - s_nWireframeCount ;
}
}
GL_REPORT_ERRORD ( ) ;
}
void ZeroGS : : ProcessMessages ( )
{
if ( listMsgs . size ( ) > 0 ) {
int left = 25 , top = 15 ;
list < MESSAGE > : : iterator it = listMsgs . begin ( ) ;
while ( it ! = listMsgs . end ( ) ) {
DrawText ( it - > str , left + 1 , top + 1 , 0xff000000 ) ;
DrawText ( it - > str , left , top , 0xffffff30 ) ;
top + = 15 ;
if ( ( int ) ( it - > dwTimeStamp - timeGetTime ( ) ) < 0 )
it = listMsgs . erase ( it ) ;
else + + it ;
}
}
}
void ZeroGS : : RenderCustom ( float fAlpha )
{
GLenum err = GL_NO_ERROR ;
GL_REPORT_ERROR ( ) ;
fAlpha = 1 ;
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ) ; // switch to the backbuffer
glDisable ( GL_STENCIL_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( 0 ) ;
glColorMask ( 1 , 1 , 1 , 1 ) ;
glDisable ( GL_BLEND ) ;
glDisable ( GL_ALPHA_TEST ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glViewport ( 0 , 0 , nBackbufferWidth , nBackbufferHeight ) ;
// play custom animation
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
// tex coords
Vector v = Vector ( 1 / 32767.0f , 1 / 32767.0f , 0 , 0 ) ;
cgGLSetParameter4fv ( pvsBitBlt . sBitBltPos , v ) ;
v . x = ( float ) nLogoWidth ;
v . y = ( float ) nLogoHeight ;
cgGLSetParameter4fv ( pvsBitBlt . sBitBltPos , v ) ;
v . x = v . y = v . z = v . w = fAlpha ;
cgGLSetParameter4fv ( ppsBaseTexture . sOneColor , v ) ;
if ( conf . options & GSOPTION_WIREFRAME ) glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
// inside vb[0]'s target area, so render that region only
cgGLSetTextureParameter ( ppsBaseTexture . sFinal , ptexLogo ) ;
cgGLEnableTextureParameter ( ppsBaseTexture . sFinal ) ;
glBindBuffer ( GL_ARRAY_BUFFER , vboRect ) ;
SET_STREAM ( ) ;
SETVERTEXSHADER ( pvsBitBlt . prog ) ;
SETPIXELSHADER ( ppsBaseTexture . prog ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
// restore
if ( conf . options & GSOPTION_WIREFRAME ) glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
ProcessMessages ( ) ;
# ifdef _WIN32
SwapBuffers ( hDC ) ;
# else
glXSwapBuffers ( GLWin . dpy , GLWin . win ) ;
# endif
glEnable ( GL_SCISSOR_TEST ) ;
glEnable ( GL_STENCIL_TEST ) ;
vb [ 0 ] . bSyncVars = 0 ;
vb [ 1 ] . bSyncVars = 0 ;
GL_REPORT_ERROR ( ) ;
GLint status = glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) ;
assert ( status = = GL_FRAMEBUFFER_COMPLETE_EXT | | status = = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT ) ;
}
// adjusts trans to preserve aspect ratio
void ZeroGS : : AdjustTransToAspect ( Vector & v , int dispwidth , int dispheight )
{
double temp ;
float f ;
if ( dispwidth * nBackbufferHeight > dispheight * nBackbufferWidth ) {
// limited by width
// change in ratio
f = ( ( float ) nBackbufferWidth / ( float ) dispwidth ) / ( ( float ) nBackbufferHeight / ( float ) dispheight ) ;
v . y * = f ;
v . w * = f ;
// scanlines mess up when not aligned right
v . y + = ( 1 - ( float ) modf ( v . y * ( float ) nBackbufferHeight * 0.5f + 0.05f , & temp ) ) * 2.0f / ( float ) nBackbufferHeight ;
v . w + = ( 1 - ( float ) modf ( v . w * ( float ) nBackbufferHeight * 0.5f + 0.05f , & temp ) ) * 2.0f / ( float ) nBackbufferHeight ;
}
else {
// limited by height
f = ( ( float ) nBackbufferHeight / ( float ) dispheight ) / ( ( float ) nBackbufferWidth / ( float ) dispwidth ) ;
f - = ( float ) modf ( f * nBackbufferWidth , & temp ) / ( float ) nBackbufferWidth ;
v . x * = f ;
v . z * = f ;
}
// v.y *= -1;
// v.w *= -1;
v * = 1 / 32767.0f ;
}
void ZeroGS : : Restore ( )
{
if ( ! g_bIsLost )
return ;
//if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) {
g_bIsLost = 0 ;
// handle lost states
ZeroGS : : ChangeDeviceSize ( nBackbufferWidth , nBackbufferHeight ) ;
//}
}
void ZeroGS : : RenderCRTC ( int interlace )
{
if ( g_bIsLost ) return ;
// Crashes Final Fantasy X at startup if uncommented. --arcum42
//#ifdef RELEASE_TO_PUBLIC
// if(g_nRealFrame < 80 ) {
// RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) );
//
// if( g_nRealFrame == 79 )
// SAFE_RELEASE_TEX(ptexLogo);
// return;
// }
//#endif
if ( conf . mrtdepth & & pvs [ 8 ] = = NULL ) {
conf . mrtdepth = 0 ;
s_bWriteDepth = FALSE ;
ERROR_LOG ( " Disabling MRT depth writing \n " ) ;
}
Flush ( 0 ) ;
Flush ( 1 ) ;
GL_REPORT_ERRORD ( ) ;
DVProfileFunc _pf ( " RenderCRTC " ) ;
// frame skipping
if ( g_nFrameRender > 0 ) {
if ( g_nFrameRender < 8 ) {
g_nFrameRender + + ;
if ( g_nFrameRender < = 3 ) {
g_nFramesSkipped + + ;
return ;
}
}
}
else {
if ( g_nFrameRender < - 1 ) {
g_nFramesSkipped + + ;
return ;
}
g_nFrameRender - - ;
}
if ( g_bSaveFrame ) {
if ( vb [ 0 ] . prndr ! = NULL ) {
SaveTexture ( " frame1.tga " , GL_TEXTURE_RECTANGLE_NV , vb [ 0 ] . prndr - > ptex , vb [ 0 ] . prndr - > fbw < < s_AAx , vb [ 0 ] . prndr - > fbh < < s_AAy ) ;
}
if ( vb [ 1 ] . prndr ! = NULL & & vb [ 0 ] . prndr ! = vb [ 1 ] . prndr ) {
SaveTexture ( " frame2.tga " , GL_TEXTURE_RECTANGLE_NV , vb [ 1 ] . prndr - > ptex , vb [ 1 ] . prndr - > fbw < < s_AAx , vb [ 1 ] . prndr - > fbh < < s_AAy ) ;
}
# ifdef _WIN32
else DeleteFile ( " frame2.tga " ) ;
# endif
}
if ( s_RangeMngr . ranges . size ( ) > 0 )
FlushTransferRanges ( NULL ) ;
//g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE;
//s_bWriteDepth = TRUE;
g_SaveFrameNum = 0 ;
g_bSaveFlushedFrame = 1 ;
// reset fba after every frame
vb [ 0 ] . fba . fba = 0 ;
vb [ 1 ] . fba . fba = 0 ;
// static int counter = 0;
// counter++;
u32 bInterlace = SMODE2 - > INT & & SMODE2 - > FFMD & & ( conf . interlace < 2 ) ;
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ) ; // switch to the backbuffer
glViewport ( 0 , 0 , nBackbufferWidth , nBackbufferHeight ) ;
// if interlace, only clear every other vsync
if ( ! bInterlace ) {
u32 color = COLOR_ARGB ( 0 , BGCOLOR - > R , BGCOLOR - > G , BGCOLOR - > B ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
}
SETVERTEXSHADER ( pvsBitBlt . prog ) ;
glBindBuffer ( GL_ARRAY_BUFFER , vboRect ) ;
SET_STREAM ( ) ;
GL_REPORT_ERRORD ( ) ;
if ( conf . options & GSOPTION_WIREFRAME ) glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( 0 ) ;
glColorMask ( 1 , 1 , 1 , 1 ) ;
glDisable ( GL_BLEND ) ;
glDisable ( GL_ALPHA_TEST ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glDisable ( GL_STENCIL_TEST ) ;
GL_REPORT_ERRORD ( ) ;
BOOL bUsingStencil = 0 ;
if ( bInterlace ) g_PrevBitwiseTexX = - 1 ; // reset since will be using
tex0Info dispinfo [ 2 ] ;
for ( int i = 0 ; i < 2 ; + + i ) {
if ( ! ( * ( u32 * ) ( PMODE ) & ( 1 < < i ) ) ) {
dispinfo [ i ] . tw = 0 ;
dispinfo [ i ] . th = 0 ;
continue ;
}
GSRegDISPFB * pfb = i ? DISPFB2 : DISPFB1 ;
GSRegDISPLAY * pd = i ? DISPLAY2 : DISPLAY1 ;
int magh = pd - > MAGH + 1 ;
int magv = pd - > MAGV + 1 ;
dispinfo [ i ] . tbp0 = pfb - > FBP < < 5 ;
dispinfo [ i ] . tbw = pfb - > FBW < < 6 ;
dispinfo [ i ] . tw = ( pd - > DW + 1 ) / magh ;
dispinfo [ i ] . th = ( pd - > DH + 1 ) / magv ;
dispinfo [ i ] . psm = pfb - > PSM ;
// hack!!
// 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4
if ( bInterlace & & 2 * dispinfo [ i ] . tw / dispinfo [ i ] . th < = 1 & & ! ( g_GameSettings & GAME_INTERLACE2X ) ) {
dispinfo [ i ] . th > > = 1 ;
}
}
//int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th);
// hack!, CMOD != 3, gradius
// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320)
// dispwidth *= 2;
// hack! makai
//if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2;
// start from the last circuit
for ( int i = ! PMODE - > SLBG ; i > = 0 ; - - i ) {
tex0Info & texframe = dispinfo [ i ] ;
if ( texframe . th < = 1 )
continue ;
GSRegDISPFB * pfb = i ? DISPFB2 : DISPFB1 ;
GSRegDISPLAY * pd = i ? DISPLAY2 : DISPLAY1 ;
Vector v , valpha ;
u32 interlacetex = 0 ;
if ( bInterlace ) {
texframe . th > > = 1 ;
// interlace mode
interlacetex = CreateInterlaceTex ( 2 * texframe . th ) ;
if ( interlace = = ( conf . interlace & 1 ) ) {
// pass if odd
valpha . z = 1.0f ;
valpha . w = - 0.4999f ;
}
else {
// pass if even
valpha . z = - 1.0f ;
valpha . w = 0.5001f ;
}
}
else {
if ( SMODE2 - > INT & & SMODE2 - > FFMD ) {
texframe . th > > = 1 ;
}
// always pass interlace test
valpha . z = 0 ;
valpha . w = 1 ;
}
int bpp = 4 ;
if ( texframe . psm = = 0x12 ) bpp = 3 ;
else if ( texframe . psm & 2 ) bpp = 2 ;
// get the start and end addresses of the buffer
int start , end ;
GetRectMemAddress ( start , end , texframe . psm , 0 , 0 , texframe . tw , texframe . th , texframe . tbp0 , texframe . tbw ) ;
if ( i = = 0 ) {
// setup right blending
glEnable ( GL_BLEND ) ;
zgsBlendEquationSeparateEXT ( GL_FUNC_ADD , GL_FUNC_ADD ) ;
if ( PMODE - > MMOD ) {
glBlendColorEXT ( PMODE - > ALP * ( 1 / 255.0f ) , PMODE - > ALP * ( 1 / 255.0f ) , PMODE - > ALP * ( 1 / 255.0f ) , 0.5f ) ;
s_srcrgb = GL_CONSTANT_COLOR_EXT ;
s_dstrgb = GL_ONE_MINUS_CONSTANT_COLOR_EXT ;
}
else {
s_srcrgb = GL_SRC_ALPHA ;
s_dstrgb = GL_ONE_MINUS_SRC_ALPHA ;
}
s_srcalpha = PMODE - > AMOD ? GL_ZERO : GL_ONE ;
s_dstalpha = PMODE - > AMOD ? GL_ONE : GL_ZERO ;
zgsBlendFuncSeparateEXT ( s_srcrgb , s_dstrgb , s_srcalpha , s_dstalpha ) ;
}
if ( bUsingStencil ) {
glStencilMask ( 1 < < i ) ;
s_stencilmask = 1 < < i ;
GL_STENCILFUNC_SET ( ) ;
}
if ( texframe . psm = = 0x12 ) {
ERROR_LOG ( " CRTC24!!! \n " ) ;
// assume that data is already in ptexMem (do Resolve?)
SETPIXELSHADER ( ppsCRTC24 [ bInterlace ] . prog ) ;
valpha . x = 0 ;
valpha . y = 1 ;
cgGLSetParameter4fv ( ppsCRTC24 [ bInterlace ] . sOneColor , valpha ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
continue ;
}
// first render the current render targets, then from ptexMem
if ( texframe . psm = = 1 ) {
valpha . x = 0 ;
valpha . y = 1 ;
}
else {
valpha . x = 1 ;
valpha . y = 0 ;
}
BOOL bSkip = 0 ;
BOOL bResolveTargs = 1 ;
//s_mapFrameHeights[s_nCurFrameMap][texframe.tbp0] = texframe.th;
list < CRenderTarget * > listTargs ;
s_RTs . GetTargs ( start , end , listTargs ) ;
for ( list < CRenderTarget * > : : iterator it = listTargs . begin ( ) ; it ! = listTargs . end ( ) ; ) {
CRenderTarget * ptarg = * it ;
if ( ptarg - > fbw = = texframe . tbw & & ! ( ptarg - > status & CRenderTarget : : TS_NeedUpdate ) & & ( ( 256 / bpp ) * ( texframe . tbp0 - ptarg - > fbp ) ) % texframe . tbw = = 0 ) {
if ( ptarg - > fbp ! = texframe . tbp0 ) {
// look for a better target (metal slug 5)
list < CRenderTarget * > : : iterator itbetter ;
for ( itbetter = listTargs . begin ( ) ; itbetter ! = listTargs . end ( ) ; + + itbetter ) {
if ( ( * itbetter ) - > fbp = = texframe . tbp0 )
break ;
}
if ( itbetter ! = listTargs . end ( ) ) {
it = listTargs . erase ( it ) ;
continue ;
}
}
if ( g_bSaveFinalFrame )
SaveTexture ( " frame1.tga " , GL_TEXTURE_RECTANGLE_NV , ptarg - > ptex , ptarg - > fbw < < s_AAx , ptarg - > fbh < < s_AAy ) ;
int dby = pfb - > DBY ;
int movy = 0 ;
// determine the rectangle to render
if ( ptarg - > fbp < texframe . tbp0 ) {
dby + = ( 256 / bpp ) * ( texframe . tbp0 - ptarg - > fbp ) / texframe . tbw ;
}
else if ( ptarg - > fbp > texframe . tbp0 ) {
dby - = ( 256 / bpp ) * ( ptarg - > fbp - texframe . tbp0 ) / texframe . tbw ;
if ( dby < 0 ) {
movy = - dby ;
dby = 0 ;
}
}
int dh = min ( ptarg - > fbh - dby , texframe . th - movy ) ;
if ( dh > = 64 ) {
if ( ptarg - > fbh - dby < texframe . th - movy & & ! bUsingStencil ) {
if ( ! bUsingStencil ) {
glClear ( GL_STENCIL_BUFFER_BIT ) ;
}
bUsingStencil = 1 ;
glEnable ( GL_STENCIL_TEST ) ;
GL_STENCILFUNC ( GL_NOTEQUAL , 3 , 1 < < i ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
glStencilMask ( 1 < < i ) ;
}
float fiw = 1.0f / texframe . tbw ;
float fih = 1.0f / ptarg - > fbh ;
// tex coords
v = Vector ( ( float ) ( texframe . tw < < s_AAx ) , ( float ) ( dh < < s_AAy ) , ( float ) ( pfb - > DBX < < s_AAx ) , ( float ) ( dby < < s_AAy ) - 0.5f ) ;
cgGLSetParameter4fv ( pvsBitBlt . sBitBltTex , v ) ;
// dest rect
v . x = 1 ;
v . y = dh / ( float ) texframe . th ;
v . z = 0 ;
v . w = 1 - v . y ;
if ( movy > 0 )
v . w - = movy / ( float ) texframe . th ;
if ( bInterlace & & interlace = = ( conf . interlace & 1 ) ) {
// move down by 1 pixel
v . w + = 1.0f / ( float ) dh ;
}
AdjustTransToAspect ( v , 640 , 480 ) ;
cgGLSetParameter4fv ( pvsBitBlt . sBitBltPos , v ) ;
cgGLSetParameter4fv ( pvsBitBlt . fBitBltTrans , Vector ( fih * 0.5f , fih * - 0.5f , fih * 0.5f , fih * 0.5f ) ) ;
// use g_fInvTexDims to store inverse texture dims
if ( ppsCRTCTarg [ bInterlace ] . sInvTexDims ) {
v . x = fiw ;
v . y = fih ;
v . z = 0 ;
cgGLSetParameter4fv ( ppsCRTCTarg [ bInterlace ] . sInvTexDims , v ) ;
}
cgGLSetParameter4fv ( ppsCRTCTarg [ bInterlace ] . sOneColor , valpha ) ;
// inside vb[0]'s target area, so render that region only
cgGLSetTextureParameter ( ppsCRTCTarg [ bInterlace ] . sFinal , ptarg - > ptex ) ;
cgGLEnableTextureParameter ( ppsCRTCTarg [ bInterlace ] . sFinal ) ;
if ( interlacetex ! = 0 ) {
cgGLSetTextureParameter ( ppsCRTCTarg [ bInterlace ] . sInterlace , interlacetex ) ;
cgGLEnableTextureParameter ( ppsCRTCTarg [ bInterlace ] . sInterlace ) ;
}
SETPIXELSHADER ( ppsCRTCTarg [ bInterlace ] . prog ) ;
GL_REPORT_ERRORD ( ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
//SaveRenderTarget("temp.tga", nBackbufferWidth, nBackbufferHeight, 0);
if ( abs ( dh - ( int ) texframe . th ) < = 1 ) {
bSkip = 1 ;
break ;
}
if ( abs ( dh - ( int ) ptarg - > fbh ) < = 1 ) {
it = listTargs . erase ( it ) ;
continue ;
}
}
}
+ + it ;
}
if ( ! bSkip ) {
for ( list < CRenderTarget * > : : iterator it = listTargs . begin ( ) ; it ! = listTargs . end ( ) ; + + it )
( * it ) - > Resolve ( ) ;
// context has to be 0
CMemoryTarget * pmemtarg = g_MemTargs . GetMemoryTarget ( texframe , 1 ) ;
SetTexVariablesInt ( 0 , g_bCRTCBilinear ? 2 : 0 , texframe , pmemtarg , & ppsCRTC [ bInterlace ] , 1 ) ;
cgGLSetTextureParameter ( ppsCRTC [ bInterlace ] . sMemory , pmemtarg - > ptex - > tex ) ;
cgGLEnableTextureParameter ( ppsCRTC [ bInterlace ] . sMemory ) ;
if ( g_bSaveFinalFrame )
SaveTex ( & texframe , g_bSaveFinalFrame - 1 > 0 ) ;
// finally render from the memory (note that the stencil buffer will keep previous regions)
v = Vector ( 1 , 1 , 0 , 0 ) ;
if ( bInterlace & & interlace = = ( conf . interlace ) ) {
// move down by 1 pixel
v . w + = 1.0f / ( float ) texframe . th ;
}
cgGLSetParameter4fv ( ppsCRTC [ bInterlace ] . sOneColor , valpha ) ;
AdjustTransToAspect ( v , 640 , 480 ) ;
cgGLSetParameter4fv ( pvsBitBlt . sBitBltPos , v ) ;
float fih = 1.0f / ( float ) texframe . th ;
if ( g_bCRTCBilinear )
cgGLSetParameter4fv ( pvsBitBlt . sBitBltTex , Vector ( texframe . tw , texframe . th , - 0.5f , - 0.5f ) ) ;
else
cgGLSetParameter4fv ( pvsBitBlt . sBitBltTex , Vector ( 1 , 1 , - 0.5f / ( float ) texframe . tw , - 0.5f / ( float ) texframe . th ) ) ;
cgGLSetParameter4fv ( pvsBitBlt . fBitBltTrans , Vector ( fih * 0.5f , fih * - 0.5f , fih * 0.5f , fih * 0.5f ) ) ;
// use g_fInvTexDims to store inverse texture dims
if ( ppsCRTC [ bInterlace ] . sInvTexDims ) {
v . x = 1.0f / ( float ) texframe . tw ;
v . y = fih ;
v . z = 0 ; //-0.5f * v.x;
v . w = - 0.5f * fih ;
cgGLSetParameter4fv ( ppsCRTC [ bInterlace ] . sInvTexDims , v ) ;
}
if ( interlacetex ! = 0 ) {
cgGLSetTextureParameter ( ppsCRTC [ bInterlace ] . sInterlace , interlacetex ) ;
cgGLEnableTextureParameter ( ppsCRTC [ bInterlace ] . sInterlace ) ;
}
SETPIXELSHADER ( ppsCRTC [ bInterlace ] . prog ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
GL_REPORT_ERRORD ( ) ;
if ( 1 ) { // || !bInterlace) {
glDisable ( GL_BLEND ) ;
ProcessMessages ( ) ;
if ( g_bMakeSnapshot ) {
char str [ 64 ] ;
int left = 200 , top = 15 ;
sprintf ( str , " ZeroGS %d.%d.%d - %.1f fps %s " , zgsrevision , zgsbuild , zgsminor , fFPS , s_frameskipping ? " - frameskipping " : " " ) ;
DrawText ( str , left + 1 , top + 1 , 0xff000000 ) ;
DrawText ( str , left , top , 0xffc0ffff ) ;
}
if ( g_bDisplayFPS ) {
char str [ 64 ] ;
int left = 10 , top = 15 ;
sprintf ( str , " %.1f fps " , fFPS ) ;
DrawText ( str , left + 1 , top + 1 , 0xff000000 ) ;
DrawText ( str , left , top , 0xffc0ffff ) ;
}
if ( glGetError ( ) ! = GL_NO_ERROR ) DEBUG_LOG ( " glerror before swap! \n " ) ;
# ifdef _WIN32
static u32 lastswaptime = 0 ;
//if( timeGetTime() - lastswaptime > 14 ) {
SwapBuffers ( hDC ) ;
lastswaptime = timeGetTime ( ) ;
//}
# else
glXSwapBuffers ( GLWin . dpy , GLWin . win ) ;
# endif
// if( glGetError() != GL_NO_ERROR) {
// // device is lost, need to recreate
// ERROR_LOG("device lost\n");
// g_bIsLost = TRUE;
// Reset();
// return;
// }
if ( conf . options & GSOPTION_WIREFRAME ) {
// clear all targets
s_nWireframeCount = 1 ;
}
if ( g_bMakeSnapshot ) {
if ( SaveRenderTarget ( strSnapshot ! = " " ? strSnapshot . c_str ( ) : " temp.jpg " , nBackbufferWidth , - nBackbufferHeight , 0 ) ) { //(conf.options&GSOPTION_TGASNAP)?0:1) ) {
char str [ 255 ] ;
sprintf ( str , " saved %s \n " , strSnapshot . c_str ( ) ) ;
AddMessage ( str , 500 ) ;
}
g_bMakeSnapshot = 0 ;
}
if ( s_avicapturing ) {
CaptureFrame ( ) ;
}
if ( s_nNewWidth > = 0 & & s_nNewHeight > = 0 & & ! g_bIsLost ) {
Reset ( ) ;
ChangeDeviceSize ( s_nNewWidth , s_nNewHeight ) ;
s_nNewWidth = s_nNewHeight = - 1 ;
}
// switch the fbp lists
// s_nCurFBPSet ^= 1;
// s_setFBP[s_nCurFBPSet].clear();
//s_nCurFrameMap ^= 1;
//s_mapFrameHeights[s_nCurFrameMap].clear();
}
// switch back to rendering to textures
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , s_uFramebuffer ) ;
g_MemTargs . DestroyCleared ( ) ;
if ( s_vecTempTextures . size ( ) > 0 )
glDeleteTextures ( ( GLsizei ) s_vecTempTextures . size ( ) , & s_vecTempTextures [ 0 ] ) ;
s_vecTempTextures . clear ( ) ;
if ( EXTWRITE - > WRITE & 1 ) {
WARN_LOG ( " EXTWRITE \n " ) ;
ExtWrite ( ) ;
EXTWRITE - > WRITE = 0 ;
}
if ( conf . options & GSOPTION_WIREFRAME ) glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
glEnable ( GL_SCISSOR_TEST ) ;
if ( icurctx > = 0 ) {
vb [ icurctx ] . bVarsSetTarg = FALSE ;
vb [ icurctx ] . bVarsTexSync = FALSE ;
vb [ 0 ] . bVarsTexSync = FALSE ;
}
// statistics
if ( s_nWriteDepthCount > 0 ) {
assert ( conf . mrtdepth ) ;
if ( - - s_nWriteDepthCount < = 0 ) {
s_bWriteDepth = FALSE ;
}
}
if ( s_nWriteDestAlphaTest > 0 ) {
if ( - - s_nWriteDestAlphaTest < = 0 ) {
s_bDestAlphaTest = FALSE ;
}
}
if ( g_GameSettings & GAME_AUTORESET ) {
s_nResolveCounts [ s_nCurResolveIndex ] = s_nResolved ;
s_nCurResolveIndex = ( s_nCurResolveIndex + 1 ) % ARRAY_SIZE ( s_nResolveCounts ) ;
int total = 0 ;
for ( int i = 0 ; i < ARRAY_SIZE ( s_nResolveCounts ) ; + + i ) total + = s_nResolveCounts [ i ] ;
if ( total / ARRAY_SIZE ( s_nResolveCounts ) > 3 ) {
if ( s_nLastResolveReset > ( int ) ( fFPS * 8 ) ) {
// reset
ERROR_LOG ( " video mem reset \n " ) ;
s_nLastResolveReset = 0 ;
memset ( s_nResolveCounts , 0 , sizeof ( s_nResolveCounts ) ) ;
s_RTs . ResolveAll ( ) ;
s_RTs . Destroy ( ) ;
s_DepthRTs . ResolveAll ( ) ;
s_DepthRTs . Destroy ( ) ;
vb [ 0 ] . prndr = NULL ; vb [ 0 ] . pdepth = NULL ; vb [ 0 ] . bNeedFrameCheck = 1 ; vb [ 0 ] . bNeedZCheck = 1 ;
vb [ 1 ] . prndr = NULL ; vb [ 1 ] . pdepth = NULL ; vb [ 1 ] . bNeedFrameCheck = 1 ; vb [ 1 ] . bNeedZCheck = 1 ;
}
}
s_nLastResolveReset + + ;
}
if ( s_nResolved > 8 ) s_nResolved = 2 ;
else if ( s_nResolved > 0 ) - - s_nResolved ;
if ( g_nDepthUsed > 0 ) - - g_nDepthUsed ;
s_ClutResolve = 0 ;
g_nDepthUpdateCount = 0 ;
maxmin = 608 ;
}
//////////////////////////
// Internal Definitions //
//////////////////////////
__forceinline void MOVZ ( VertexGPU * p , u32 gsz , const VB & curvb )
{
p - > z = curvb . zprimmask = = 0xffff ? min ( ( u32 ) 0xffff , gsz ) : gsz ;
}
__forceinline void MOVFOG ( VertexGPU * p , Vertex gsf )
{
p - > f = ( ( s16 ) ( gsf ) . f < < 7 ) | 0x7f ;
}
__forceinline void SET_VERTEX ( VertexGPU * p , int Index , const VB & curvb )
{
int index = Index ;
p - > x = ( ( ( int ) gs . gsvertex [ index ] . x - curvb . offset . x ) > > 1 ) & 0xffff ;
p - > y = ( ( ( int ) gs . gsvertex [ index ] . y - curvb . offset . y ) > > 1 ) & 0xffff ;
/*x = ((int)gs.gsvertex[index].x - curvb.offset.x);
y = ( ( int ) gs . gsvertex [ index ] . y - curvb . offset . y ) ;
p . x = ( x & 0x7fff ) | ( x < 0 ? 0x8000 : 0 ) ;
p . y = ( y & 0x7fff ) | ( y < 0 ? 0x8000 : 0 ) ; */
p - > f = ( ( s16 ) gs . gsvertex [ index ] . f < < 7 ) | 0x7f ;
MOVZ ( p , gs . gsvertex [ index ] . z , curvb ) ;
p - > rgba = prim - > iip ? gs . gsvertex [ index ] . rgba : gs . rgba ;
if ( ( g_GameSettings & GAME_TEXAHACK ) & & ! ( p - > rgba & 0xffffff ) )
p - > rgba = 0 ;
if ( prim - > tme )
{
if ( prim - > fst )
{
p - > s = ( float ) gs . gsvertex [ index ] . u * fiTexWidth [ prim - > ctxt ] ;
p - > t = ( float ) gs . gsvertex [ index ] . v * fiTexHeight [ prim - > ctxt ] ;
p - > q = 1 ;
}
else
{
p - > s = gs . gsvertex [ index ] . s ;
p - > t = gs . gsvertex [ index ] . t ;
p - > q = gs . gsvertex [ index ] . q ;
}
}
}
# define OUTPUT_VERT(fn, vert, id) { \
fn ( " %c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f) \n " , id = = 0 ? ' * ' : ' ' , id , prim - > prim , vert . x / 8 , vert . y / 8 , vert . z , vert . f / 128 , \
vert . rgba , Clamp ( vert . s , - 10 , 10 ) , Clamp ( vert . t , - 10 , 10 ) , Clamp ( vert . q , - 10 , 10 ) ) ; \
} \
void ZeroGS : : KickPoint ( )
{
assert ( gs . primC > = 1 ) ;
VB & curvb = vb [ prim - > ctxt ] ;
if ( curvb . bNeedTexCheck ) curvb . FlushTexData ( ) ;
if ( ( vb [ ! prim - > ctxt ] . nCount > 0 ) & & ( vb [ prim - > ctxt ] . gsfb . fbp = = vb [ ! prim - > ctxt ] . gsfb . fbp ) )
{
assert ( vb [ prim - > ctxt ] . nCount = = 0 ) ;
Flush ( ! prim - > ctxt ) ;
}
curvb . NotifyWrite ( 1 ) ;
int last = ( gs . primIndex + 2 ) % ARRAY_SIZE ( gs . gsvertex ) ;
VertexGPU * p = curvb . pBufferData + curvb . nCount ;
SET_VERTEX ( & p [ 0 ] , last , curvb ) ;
curvb . nCount + + ;
# ifdef PRIM_LOG
OUTPUT_VERT ( PRIM_LOG , p [ 0 ] , 0 ) ;
# endif
}
void ZeroGS : : KickLine ( )
{
assert ( gs . primC > = 2 ) ;
VB & curvb = vb [ prim - > ctxt ] ;
if ( curvb . bNeedTexCheck )
curvb . FlushTexData ( ) ;
if ( vb [ ! prim - > ctxt ] . nCount > 0 & & vb [ prim - > ctxt ] . gsfb . fbp = = vb [ ! prim - > ctxt ] . gsfb . fbp )
{
assert ( vb [ prim - > ctxt ] . nCount = = 0 ) ;
Flush ( ! prim - > ctxt ) ;
}
curvb . NotifyWrite ( 2 ) ;
int next = ( gs . primIndex + 1 ) % ARRAY_SIZE ( gs . gsvertex ) ;
int last = ( gs . primIndex + 2 ) % ARRAY_SIZE ( gs . gsvertex ) ;
VertexGPU * p = curvb . pBufferData + curvb . nCount ;
SET_VERTEX ( & p [ 0 ] , next , curvb ) ;
SET_VERTEX ( & p [ 1 ] , last , curvb ) ;
curvb . nCount + = 2 ;
# ifdef PRIM_LOG
OUTPUT_VERT ( PRIM_LOG , p [ 0 ] , 0 ) ;
OUTPUT_VERT ( PRIM_LOG , p [ 1 ] , 1 ) ;
# endif
}
void ZeroGS : : KickTriangle ( )
{
assert ( gs . primC > = 3 ) ;
VB & curvb = vb [ prim - > ctxt ] ;
if ( curvb . bNeedTexCheck ) curvb . FlushTexData ( ) ;
if ( ( vb [ ! prim - > ctxt ] . nCount > 0 ) & & ( vb [ prim - > ctxt ] . gsfb . fbp = = vb [ ! prim - > ctxt ] . gsfb . fbp ) )
{
assert ( vb [ prim - > ctxt ] . nCount = = 0 ) ;
Flush ( ! prim - > ctxt ) ;
}
curvb . NotifyWrite ( 3 ) ;
VertexGPU * p = curvb . pBufferData + curvb . nCount ;
SET_VERTEX ( & p [ 0 ] , 0 , curvb ) ;
SET_VERTEX ( & p [ 1 ] , 1 , curvb ) ;
SET_VERTEX ( & p [ 2 ] , 2 , curvb ) ;
curvb . nCount + = 3 ;
# ifdef PRIM_LOG
OUTPUT_VERT ( PRIM_LOG , p [ 0 ] , 0 ) ;
OUTPUT_VERT ( PRIM_LOG , p [ 1 ] , 1 ) ;
OUTPUT_VERT ( PRIM_LOG , p [ 2 ] , 2 ) ;
# endif
}
void ZeroGS : : KickTriangleFan ( )
{
assert ( gs . primC > = 3 ) ;
VB & curvb = vb [ prim - > ctxt ] ;
if ( curvb . bNeedTexCheck ) curvb . FlushTexData ( ) ;
if ( ( vb [ ! prim - > ctxt ] . nCount > 0 ) & & ( vb [ prim - > ctxt ] . gsfb . fbp = = vb [ ! prim - > ctxt ] . gsfb . fbp ) )
{
assert ( vb [ prim - > ctxt ] . nCount = = 0 ) ;
Flush ( ! prim - > ctxt ) ;
}
curvb . NotifyWrite ( 3 ) ;
VertexGPU * p = curvb . pBufferData + curvb . nCount ;
SET_VERTEX ( & p [ 0 ] , 0 , curvb ) ;
SET_VERTEX ( & p [ 1 ] , 1 , curvb ) ;
SET_VERTEX ( & p [ 2 ] , 2 , curvb ) ;
curvb . nCount + = 3 ;
// add 1 to skip the first vertex
if ( gs . primIndex = = gs . nTriFanVert )
gs . primIndex = ( gs . primIndex + 1 ) % ARRAY_SIZE ( gs . gsvertex ) ;
# ifdef PRIM_LOG
OUTPUT_VERT ( PRIM_LOG , p [ 0 ] , 0 ) ;
OUTPUT_VERT ( PRIM_LOG , p [ 1 ] , 1 ) ;
OUTPUT_VERT ( PRIM_LOG , p [ 2 ] , 2 ) ;
# endif
}
__forceinline void SetKickVertex ( VertexGPU * p , Vertex v , int next , const VB & curvb )
{
SET_VERTEX ( p , next , curvb ) ;
MOVZ ( p , v . z , curvb ) ;
MOVFOG ( p , v ) ;
}
void ZeroGS : : KickSprite ( )
{
assert ( gs . primC > = 2 ) ;
VB & curvb = vb [ prim - > ctxt ] ;
if ( curvb . bNeedTexCheck ) curvb . FlushTexData ( ) ;
if ( ( vb [ ! prim - > ctxt ] . nCount > 0 ) & & ( vb [ prim - > ctxt ] . gsfb . fbp = = vb [ ! prim - > ctxt ] . gsfb . fbp ) )
{
assert ( vb [ prim - > ctxt ] . nCount = = 0 ) ;
Flush ( ! prim - > ctxt ) ;
}
curvb . NotifyWrite ( 6 ) ;
int next = ( gs . primIndex + 1 ) % ARRAY_SIZE ( gs . gsvertex ) ;
int last = ( gs . primIndex + 2 ) % ARRAY_SIZE ( gs . gsvertex ) ;
// sprite is too small and AA shows lines (tek4)
if ( s_AAx )
{
gs . gsvertex [ last ] . x + = 4 ;
if ( s_AAy ) gs . gsvertex [ last ] . y + = 4 ;
}
// might be bad sprite (KH dialog text)
//if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y )
//return;
VertexGPU * p = curvb . pBufferData + curvb . nCount ;
SetKickVertex ( & p [ 0 ] , gs . gsvertex [ last ] , next , curvb ) ;
SetKickVertex ( & p [ 3 ] , gs . gsvertex [ last ] , next , curvb ) ;
SetKickVertex ( & p [ 1 ] , gs . gsvertex [ last ] , last , curvb ) ;
SetKickVertex ( & p [ 4 ] , gs . gsvertex [ last ] , last , curvb ) ;
SetKickVertex ( & p [ 2 ] , gs . gsvertex [ last ] , next , curvb ) ;
p [ 2 ] . s = p [ 1 ] . s ;
p [ 2 ] . x = p [ 1 ] . x ;
SetKickVertex ( & p [ 5 ] , gs . gsvertex [ last ] , last , curvb ) ;
p [ 5 ] . s = p [ 0 ] . s ;
p [ 5 ] . x = p [ 0 ] . x ;
curvb . nCount + = 6 ;
# ifdef PRIM_LOG
OUTPUT_VERT ( PRIM_LOG , p [ 0 ] , 0 ) ;
OUTPUT_VERT ( PRIM_LOG , p [ 1 ] , 1 ) ;
# endif
}
void ZeroGS : : KickDummy ( )
{
//GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim);
}
__forceinline void ZeroGS : : RenderFBA ( const VB & curvb , CGparameter sOneColor )
{
// add fba to all pixels
GL_STENCILFUNC ( GL_ALWAYS , STENCIL_FBA , 0xff ) ;
glStencilMask ( STENCIL_CLEAR ) ;
glStencilOp ( GL_ZERO , GL_KEEP , GL_REPLACE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( 0 ) ;
glColorMask ( 0 , 0 , 0 , 0 ) ;
if ( s_bWriteDepth ) ResetRenderTarget ( 1 ) ;
glEnable ( GL_ALPHA_TEST ) ;
glAlphaFunc ( GL_GEQUAL , 1 ) ;
Vector v ;
v . x = 1 ; v . y = 2 ; v . z = 0 ; v . w = 0 ;
cgGLSetParameter4fv ( sOneColor , v ) ;
DRAW ( ) ;
if ( ! curvb . test . ate )
glDisable ( GL_ALPHA_TEST ) ;
else
glAlphaFunc ( g_dwAlphaCmp [ curvb . test . atst ] , b2XAlphaTest ? min ( 1.0f , curvb . test . aref * ( 1 / 127.5f ) ) : curvb . test . aref * ( 1 / 255.0f ) ) ;
// reset (not necessary)
GL_COLORMASK ( s_dwColorWrite ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
if ( ! curvb . zbuf . zmsk )
{
glDepthMask ( 1 ) ;
assert ( curvb . pdepth ! = NULL ) ;
if ( s_bWriteDepth ) curvb . pdepth - > SetRenderTarget ( 1 ) ;
}
GL_ZTEST ( curvb . test . zte ) ;
}
__forceinline void ZeroGS : : RenderAlphaTest ( const VB & curvb , CGparameter sOneColor )
{
if ( ! g_bUpdateStencil ) return ;
if ( curvb . test . ate )
if ( curvb . test . afail = = 1 ) glDisable ( GL_ALPHA_TEST ) ;
glDepthMask ( 0 ) ;
glColorMask ( 0 , 0 , 0 , 0 ) ;
Vector v ;
v . x = 1 ; v . y = 2 ; v . z = 0 ; v . w = 0 ;
cgGLSetParameter4fv ( sOneColor , v ) ;
if ( s_bWriteDepth ) ResetRenderTarget ( 1 ) ;
// or a 1 to the stencil buffer wherever alpha passes
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
s_stencilfunc = GL_ALWAYS ;
glEnable ( GL_STENCIL_TEST ) ;
if ( ! s_bDestAlphaTest )
{
// clear everything
s_stencilref = 0 ;
glStencilMask ( STENCIL_CLEAR ) ;
glDisable ( GL_ALPHA_TEST ) ;
GL_STENCILFUNC_SET ( ) ;
DRAW ( ) ;
if ( curvb . test . ate & & curvb . test . afail ! = 1 & & USEALPHATESTING )
glEnable ( GL_ALPHA_TEST ) ;
}
if ( curvb . test . ate & & curvb . test . atst > 1 & & curvb . test . aref > 0x80 )
{
v . x = 1 ; v . y = 1 ; v . z = 0 ; v . w = 0 ;
cgGLSetParameter4fv ( sOneColor , v ) ;
glAlphaFunc ( g_dwAlphaCmp [ curvb . test . atst ] , curvb . test . aref * ( 1 / 255.0f ) ) ;
}
s_stencilref = STENCIL_SPECIAL ;
glStencilMask ( STENCIL_SPECIAL ) ;
GL_STENCILFUNC_SET ( ) ;
glDisable ( GL_DEPTH_TEST ) ;
DRAW ( ) ;
if ( curvb . test . zte )
glEnable ( GL_DEPTH_TEST ) ;
GL_ALPHATEST ( 0 ) ;
GL_COLORMASK ( s_dwColorWrite ) ;
if ( ! curvb . zbuf . zmsk )
{
glDepthMask ( 1 ) ;
// set rt next level
if ( s_bWriteDepth ) curvb . pdepth - > SetRenderTarget ( 1 ) ;
}
}
__forceinline void ZeroGS : : RenderStencil ( const VB & curvb , u32 dwUsingSpecialTesting )
{
//NOTE: This stencil hack for dest alpha testing ONLY works when
// the geometry in one DrawPrimitive call does not overlap
// mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff)
// mark 4 if a pixel was written (so that the stencil buf can be changed with new values)
glStencilMask ( STENCIL_PIXELWRITE ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
s_stencilmask = ( curvb . test . date ? STENCIL_ALPHABIT : 0 ) | ( dwUsingSpecialTesting ? STENCIL_SPECIAL : 0 ) ;
s_stencilfunc = s_stencilmask ? GL_EQUAL : GL_ALWAYS ;
s_stencilref = curvb . test . date * curvb . test . datm | STENCIL_PIXELWRITE | ( dwUsingSpecialTesting ? STENCIL_SPECIAL : 0 ) ;
GL_STENCILFUNC_SET ( ) ;
}
__forceinline void ZeroGS : : ProcessStencil ( const VB & curvb )
{
assert ( ! curvb . fba . fba ) ;
// set new alpha bit
glStencilMask ( STENCIL_ALPHABIT ) ;
GL_STENCILFUNC ( GL_EQUAL , STENCIL_PIXELWRITE , STENCIL_PIXELWRITE | STENCIL_FBA ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( 0 ) ;
glColorMask ( 0 , 0 , 0 , 0 ) ;
if ( s_bWriteDepth ) ResetRenderTarget ( 1 ) ;
GL_ALPHATEST ( 0 ) ;
SETPIXELSHADER ( ppsOne . prog ) ;
DRAW ( ) ;
// process when alpha >= 0xff
GL_STENCILFUNC ( GL_EQUAL , STENCIL_PIXELWRITE | STENCIL_FBA | STENCIL_ALPHABIT , STENCIL_PIXELWRITE | STENCIL_FBA ) ;
DRAW ( ) ;
// clear STENCIL_PIXELWRITE bit
glStencilMask ( STENCIL_CLEAR ) ;
GL_STENCILFUNC ( GL_ALWAYS , 0 , STENCIL_PIXELWRITE | STENCIL_FBA ) ;
DRAW ( ) ;
// restore state
GL_COLORMASK ( s_dwColorWrite ) ;
if ( curvb . test . ate & & USEALPHATESTING )
glEnable ( GL_ALPHA_TEST ) ;
if ( ! curvb . zbuf . zmsk ) {
glDepthMask ( 1 ) ;
if ( s_bWriteDepth ) {
assert ( curvb . pdepth ! = NULL ) ;
curvb . pdepth - > SetRenderTarget ( 1 ) ;
}
}
GL_ZTEST ( curvb . test . zte ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_KEEP ) ;
}
__forceinline void ZeroGS : : ProcessFBA ( const VB & curvb , CGparameter sOneColor )
{
if ( ( curvb . frame . fbm & 0x80000000 ) ) return ;
// add fba to all pixels that were written and alpha was less than 0xff
glStencilMask ( STENCIL_ALPHABIT ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
GL_STENCILFUNC ( GL_EQUAL , STENCIL_FBA | STENCIL_PIXELWRITE | STENCIL_ALPHABIT , STENCIL_PIXELWRITE | STENCIL_FBA ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( 0 ) ;
glColorMask ( 0 , 0 , 0 , 1 ) ;
if ( s_bWriteDepth ) {
ResetRenderTarget ( 1 ) ;
}
// processes the pixels with ALPHA < 0x80*2
glEnable ( GL_ALPHA_TEST ) ;
glAlphaFunc ( GL_LEQUAL , 1 ) ;
// add 1 to dest
GL_BLEND_ALPHA ( GL_ONE , GL_ONE ) ;
GL_BLENDEQ_ALPHA ( GL_FUNC_ADD ) ;
float f = 1 ;
cgGLSetParameter4fv ( sOneColor , & f ) ;
SETPIXELSHADER ( ppsOne . prog ) ;
DRAW ( ) ;
glDisable ( GL_ALPHA_TEST ) ;
// reset bits
glStencilMask ( STENCIL_CLEAR ) ;
GL_STENCILFUNC ( GL_GREATER , 0 , STENCIL_PIXELWRITE | STENCIL_FBA ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_ZERO ) ;
DRAW ( ) ;
if ( curvb . test . atst & & USEALPHATESTING ) {
glEnable ( GL_ALPHA_TEST ) ;
glAlphaFunc ( g_dwAlphaCmp [ curvb . test . atst ] , b2XAlphaTest ? min ( 1.0f , curvb . test . aref * ( 1 / 127.5f ) ) : curvb . test . aref * ( 1 / 255.0f ) ) ;
}
// restore (SetAlphaVariables)
GL_BLEND_ALPHA ( GL_ONE , GL_ZERO ) ;
if ( vAlphaBlendColor . y < 0 ) GL_BLENDEQ_ALPHA ( GL_FUNC_REVERSE_SUBTRACT ) ;
// reset (not necessary)
GL_COLORMASK ( s_dwColorWrite ) ;
if ( ! curvb . zbuf . zmsk ) {
glDepthMask ( 1 ) ;
if ( s_bWriteDepth ) curvb . pdepth - > SetRenderTarget ( 1 ) ;
}
GL_ZTEST ( curvb . test . zte ) ;
}
inline void ZeroGS : : SetContextTarget ( int context )
{
VB & curvb = vb [ context ] ;
GL_REPORT_ERRORD ( ) ;
if ( curvb . prndr = = NULL )
curvb . prndr = s_RTs . GetTarg ( curvb . frame , 0 , GET_MAXHEIGHT ( curvb . gsfb . fbp , curvb . gsfb . fbw , curvb . gsfb . psm ) ) ;
// make sure targets are valid
if ( curvb . pdepth = = NULL ) {
frameInfo f ;
f . fbp = curvb . zbuf . zbp ;
f . fbw = curvb . frame . fbw ;
f . fbh = curvb . prndr - > fbh ;
f . psm = curvb . zbuf . psm ;
f . fbm = 0 ;
curvb . pdepth = ( CDepthTarget * ) s_DepthRTs . GetTarg ( f , CRenderTargetMngr : : TO_DepthBuffer | CRenderTargetMngr : : TO_StrictHeight |
( curvb . zbuf . zmsk ? CRenderTargetMngr : : TO_Virtual : 0 ) , GET_MAXHEIGHT ( curvb . zbuf . zbp , curvb . gsfb . fbw , 0 ) ) ;
}
assert ( curvb . prndr ! = NULL & & curvb . pdepth ! = NULL ) ;
assert ( curvb . pdepth - > fbh = = curvb . prndr - > fbh ) ;
if ( curvb . pdepth - > status & CRenderTarget : : TS_Virtual ) {
if ( ! curvb . zbuf . zmsk ) {
CRenderTarget * ptemp = s_DepthRTs . Promote ( curvb . pdepth - > fbp | ( curvb . pdepth - > fbw < < 16 ) ) ;
assert ( ptemp = = curvb . pdepth ) ;
}
else
curvb . pdepth - > status & = ~ CRenderTarget : : TS_NeedUpdate ;
}
BOOL bSetTarg = 1 ;
if ( curvb . pdepth - > status & CRenderTarget : : TS_NeedUpdate ) {
assert ( ! ( curvb . pdepth - > status & CRenderTarget : : TS_Virtual ) ) ;
// don't update if virtual
curvb . pdepth - > Update ( context , curvb . prndr ) ;
bSetTarg = 0 ;
}
GL_REPORT_ERRORD ( ) ;
if ( curvb . prndr - > status & CRenderTarget : : TS_NeedUpdate ) {
// if(bSetTarg s_bWriteDepth ) {
// if( s_bWriteDepth ) {
// curvb.pdepth->SetRenderTarget(1);
// curvb.pdepth->SetDepthStencilSurface();
// }
// else curvb.pdepth->SetDepthStencilSurface();
// }
curvb . prndr - > Update ( context , curvb . pdepth ) ;
}
else {
//if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg )
curvb . prndr - > SetRenderTarget ( 0 ) ;
//if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) )
curvb . pdepth - > SetDepthStencilSurface ( ) ;
if ( conf . mrtdepth & & ZeroGS : : IsWriteDepth ( ) ) curvb . pdepth - > SetRenderTarget ( 1 ) ;
if ( s_ptexCurSet [ 0 ] = = curvb . prndr - > ptex ) s_ptexCurSet [ 0 ] = 0 ;
if ( s_ptexCurSet [ 1 ] = = curvb . prndr - > ptex ) s_ptexCurSet [ 1 ] = 0 ;
curvb . prndr - > SetViewport ( ) ;
}
curvb . prndr - > SetTarget ( curvb . frame . fbp , curvb . scissor , context ) ;
if ( ( curvb . zbuf . zbp - curvb . pdepth - > fbp ) ! = ( curvb . frame . fbp - curvb . prndr - > fbp ) & & curvb . test . zte )
WARN_LOG ( " frame and zbuf not aligned \n " ) ;
curvb . bVarsSetTarg = TRUE ;
if ( vb [ ! context ] . prndr ! = curvb . prndr ) vb [ ! context ] . bVarsSetTarg = FALSE ;
assert ( ! ( curvb . prndr - > status & CRenderTarget : : TS_NeedUpdate ) ) ;
assert ( curvb . pdepth = = NULL | | ! ( curvb . pdepth - > status & CRenderTarget : : TS_NeedUpdate ) ) ;
GL_REPORT_ERRORD ( ) ;
}
void ZeroGS : : SetTexVariables ( int context , FRAGMENTSHADER * pfragment , int settexint )
{
if ( ! vb [ context ] . curprim . tme ) return ;
DVProfileFunc _pf ( " SetTexVariables " ) ;
assert ( ! vb [ context ] . bNeedTexCheck ) ;
Vector v , v2 ;
tex0Info & tex0 = vb [ context ] . tex0 ;
float fw = ( float ) tex0 . tw ;
float fh = ( float ) tex0 . th ;
if ( ! vb [ context ] . bTexConstsSync ) {
// alpha and texture highlighting
Vector valpha , valpha2 ;
// if clut, use the frame format
int psm = tex0 . psm ;
if ( PSMT_ISCLUT ( tex0 . psm ) ) psm = tex0 . cpsm ;
int nNeedAlpha = ( psm = = 1 | | psm = = 2 | | psm = = 10 ) ;
Vector vblack ;
vblack . x = vblack . y = vblack . z = vblack . w = 10 ;
switch ( tex0 . tfx ) {
case 0 :
valpha . z = 0 ; valpha . w = 0 ;
valpha2 . x = 0 ; valpha2 . y = 0 ;
valpha2 . z = 2 ; valpha2 . w = 1 ;
break ;
case 1 :
valpha . z = 0 ; valpha . w = 1 ;
valpha2 . x = 1 ; valpha2 . y = 0 ;
valpha2 . z = 0 ; valpha2 . w = 0 ;
break ;
case 2 :
valpha . z = 1 ; valpha . w = 1.0f ;
valpha2 . x = 0 ; valpha2 . y = tex0 . tcc ? 1.0f : 0.0f ;
valpha2 . z = 2 ; valpha2 . w = 0 ;
break ;
case 3 :
valpha . z = 1 ; valpha . w = tex0 . tcc ? 0.0f : 1.0f ;
valpha2 . x = 0 ; valpha2 . y = tex0 . tcc ? 1.0f : 0.0f ;
valpha2 . z = 2 ; valpha2 . w = 0 ;
break ;
}
if ( tex0 . tcc ) {
if ( tex0 . tfx = = 1 ) {
//mode.x = 10;
valpha . z = 0 ; valpha . w = 0 ;
valpha2 . x = 1 ; valpha2 . y = 1 ;
valpha2 . z = 0 ; valpha2 . w = 0 ;
}
if ( nNeedAlpha ) {
if ( tex0 . tfx = = 0 ) {
// make sure alpha is mult by two when the output is Cv = Ct*Cf
valpha . x = 2 * gs . texa . fta [ 0 ] ;
// if 24bit, always choose ta[0]
valpha . y = 2 * gs . texa . fta [ psm ! = 1 ] ;
valpha . y - = valpha . x ;
}
else {
valpha . x = gs . texa . fta [ 0 ] ;
// if 24bit, always choose ta[0]
valpha . y = gs . texa . fta [ psm ! = 1 ] ;
valpha . y - = valpha . x ;
}
// need black detection
if ( gs . texa . aem & & psm = = PSMCT24 )
vblack . w = 0 ;
}
else {
if ( tex0 . tfx = = 0 ) {
valpha . x = 0 ;
valpha . y = 2 ;
}
else {
valpha . x = 0 ;
valpha . y = 1 ;
}
}
}
else {
// reset alpha to color
valpha . x = valpha . y = 0 ;
valpha . w = 1 ;
}
cgGLSetParameter4fv ( pfragment - > fTexAlpha , valpha ) ;
cgGLSetParameter4fv ( pfragment - > fTexAlpha2 , valpha2 ) ;
if ( tex0 . tcc & & gs . texa . aem & & ( psm = = PSMCT24 | | psm = = PSMCT16 | | psm = = PSMCT16S ) )
cgGLSetParameter4fv ( pfragment - > fTestBlack , vblack ) ;
// clamp relies on texture width
{
clampInfo * pclamp = & ZeroGS : : vb [ context ] . clamp ;
Vector v , v2 ;
v . x = v . y = 0 ;
u32 * ptex = ZeroGS : : vb [ context ] . ptexClamp ;
ptex [ 0 ] = ptex [ 1 ] = 0 ;
float fw = ZeroGS : : vb [ context ] . tex0 . tw ;
float fh = ZeroGS : : vb [ context ] . tex0 . th ;
switch ( pclamp - > wms ) {
case 0 :
v2 . x = - 1e10 ; v2 . z = 1e10 ;
break ;
case 1 : // pclamp
// suikoden5 movie text
v2 . x = 0 ; v2 . z = 1 - 0.5f / fw ;
break ;
case 2 : // reg pclamp
v2 . x = ( pclamp - > minu + 0.5f ) / fw ; v2 . z = ( pclamp - > maxu - 0.5f ) / fw ;
break ;
case 3 : // region rep x
v . x = 0.9999f ;
v . z = fw / ( float ) GPU_TEXMASKWIDTH ;
v2 . x = ( float ) GPU_TEXMASKWIDTH / fw ;
v2 . z = pclamp - > maxu / fw ;
if ( pclamp - > minu ! = g_PrevBitwiseTexX ) {
g_PrevBitwiseTexX = pclamp - > minu ;
ptex [ 0 ] = ZeroGS : : s_BitwiseTextures . GetTex ( pclamp - > minu , 0 ) ;
}
break ;
}
switch ( pclamp - > wmt ) {
case 0 :
v2 . y = - 1e10 ; v2 . w = 1e10 ;
break ;
case 1 : // pclamp
// suikoden5 movie text
v2 . y = 0 ; v2 . w = 1 - 0.5f / fh ;
break ;
case 2 : // reg pclamp
v2 . y = ( pclamp - > minv + 0.5f ) / fh ; v2 . w = ( pclamp - > maxv - 0.5f ) / fh ;
break ;
case 3 : // region rep y
v . y = 0.9999f ;
v . w = fh / ( float ) GPU_TEXMASKWIDTH ;
v2 . y = ( float ) GPU_TEXMASKWIDTH / fh ;
v2 . w = pclamp - > maxv / fh ;
if ( pclamp - > minv ! = g_PrevBitwiseTexY ) {
g_PrevBitwiseTexY = pclamp - > minv ;
ptex [ 1 ] = ZeroGS : : s_BitwiseTextures . GetTex ( pclamp - > minv , ptex [ 0 ] ) ;
}
break ;
}
if ( pfragment - > fTexWrapMode ! = 0 )
cgGLSetParameter4fv ( pfragment - > fTexWrapMode , v ) ;
if ( pfragment - > fClampExts ! = 0 )
cgGLSetParameter4fv ( pfragment - > fClampExts , v2 ) ;
}
vb [ context ] . bTexConstsSync = TRUE ;
}
if ( s_bTexFlush ) {
if ( PSMT_ISCLUT ( tex0 . psm ) )
texClutWrite ( context ) ;
else
s_bTexFlush = FALSE ;
}
if ( settexint ) {
CMemoryTarget * pmemtarg = g_MemTargs . GetMemoryTarget ( tex0 , 1 ) ;
if ( vb [ context ] . bVarsTexSync ) {
if ( vb [ context ] . pmemtarg ! = pmemtarg ) {
SetTexVariablesInt ( context , GetTexFilter ( vb [ context ] . tex1 ) , tex0 , pmemtarg , pfragment , s_bForceTexFlush ) ;
vb [ context ] . bVarsTexSync = TRUE ;
}
}
else {
SetTexVariablesInt ( context , GetTexFilter ( vb [ context ] . tex1 ) , tex0 , pmemtarg , pfragment , s_bForceTexFlush ) ;
vb [ context ] . bVarsTexSync = TRUE ;
INC_TEXVARS ( ) ;
}
}
else {
vb [ context ] . bVarsTexSync = FALSE ;
}
}
void ZeroGS : : SetTexVariablesInt ( int context , int bilinear , const tex0Info & tex0 , CMemoryTarget * pmemtarg , FRAGMENTSHADER * pfragment , int force )
{
DVProfileFunc _pf ( " SetTexVariablesInt " ) ;
Vector v ;
assert ( pmemtarg ! = NULL & & pfragment ! = NULL ) ;
float fw = ( float ) tex0 . tw ;
float fh = ( float ) tex0 . th ;
bool bUseBilinear = bilinear > 1 | | ( bilinear & & conf . bilinear ) ;
if ( bUseBilinear ) {
v . x = ( float ) fw ;
v . y = ( float ) fh ;
v . z = 1.0f / ( float ) fw ;
v . w = 1.0f / ( float ) fh ;
if ( pfragment - > fRealTexDims )
cgGLSetParameter4fv ( pfragment - > fRealTexDims , v ) ;
else
cgGLSetParameter4fv ( cgGetNamedParameter ( pfragment - > prog , " g_fRealTexDims " ) , v ) ;
}
if ( m_Blocks [ tex0 . psm ] . bpp = = 0 ) {
ERROR_LOG ( " Undefined tex psm 0x%x! \n " , tex0 . psm ) ;
return ;
}
const BLOCK & b = m_Blocks [ tex0 . psm ] ;
float fbw = ( float ) tex0 . tbw ;
Vector vTexDims ;
vTexDims . x = b . vTexDims . x * fw ;
vTexDims . y = b . vTexDims . y * fh ;
vTexDims . z = ( float ) BLOCK_TEXWIDTH * ( 0.002f / 64.0f + 0.01f / 128.0f ) ;
vTexDims . w = ( float ) BLOCK_TEXHEIGHT * 0.2f / 512.0f ;
if ( bUseBilinear ) {
vTexDims . x * = 1 / 128.0f ;
vTexDims . y * = 1 / 512.0f ;
vTexDims . z * = 1 / 128.0f ;
vTexDims . w * = 1 / 512.0f ;
}
float g_fitexwidth = g_fiGPU_TEXWIDTH / ( float ) pmemtarg - > widthmult ;
float g_texwidth = GPU_TEXWIDTH * ( float ) pmemtarg - > widthmult ;
float fpage = tex0 . tbp0 * ( 64.0f * g_fitexwidth ) + 0.05f * g_fitexwidth ;
float fpageint = floorf ( fpage ) ;
int starttbp = ( int ) fpage ;
// 2048 is number of words to span one page
float fblockstride = ( 2048.0f / ( float ) ( g_texwidth * BLOCK_TEXWIDTH ) ) * b . vTexDims . x * fbw ;
assert ( fblockstride > = 1.0f ) ;
v . x = ( float ) ( 2048 * g_fitexwidth ) ;
v . y = fblockstride ;
v . z = g_fBlockMult / ( float ) pmemtarg - > widthmult ;
v . w = fpage - fpageint ;
if ( g_fBlockMult > 1 ) {
// make sure to divide by mult (since the G16R16 texture loses info)
v . z * = b . bpp * ( 1 / 32.0f ) ;
}
cgGLSetParameter4fv ( pfragment - > fTexDims , vTexDims ) ;
cgGLSetParameter4fv ( pfragment - > fTexBlock , & b . vTexBlock . x ) ;
cgGLSetParameter4fv ( pfragment - > fTexOffset , v ) ;
// get hardware texture dims
int texheight = ( pmemtarg - > realheight + pmemtarg - > widthmult - 1 ) / pmemtarg - > widthmult ;
int texwidth = GPU_TEXWIDTH * pmemtarg - > widthmult * pmemtarg - > channels ;
v . y = 1 ; //(float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult);
v . x = ( fpageint - ( float ) pmemtarg - > realy / ( float ) pmemtarg - > widthmult + 0.5f ) ; //*v.y;
// v.x *= (float)texheight;
// v.y *= (float)texheight;
v . z = ( float ) texwidth ;
if ( ! ( g_nPixelShaderVer & SHADER_ACCURATE ) | | bUseBilinear )
v . w = 0.25f ;
else
v . w = 0.5f ;
cgGLSetParameter4fv ( pfragment - > fPageOffset , v ) ;
if ( force ) s_ptexCurSet [ context ] = pmemtarg - > ptex - > tex ;
else s_ptexNextSet [ context ] = pmemtarg - > ptex - > tex ;
vb [ context ] . pmemtarg = pmemtarg ;
vb [ context ] . bVarsTexSync = FALSE ;
}
# define SET_ALPHA_COLOR_FACTOR(sign) \
{ \
switch ( a . c ) \
{ \
case 0 : \
vAlphaBlendColor . y = ( sign ) ? 2.0f * 255.0f / 256.0f : - 2.0f * 255.0f / 256.0f ; \
s_srcalpha = GL_ONE ; \
s_alphaeq = ( sign ) ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT ; \
break ; \
\
case 1 : \
/* if in 24 bit mode, dest alpha should be one */ \
switch ( vb [ icurctx ] . prndr - > psm & 0xf ) \
{ \
case 0 : \
bDestAlphaColor = ( a . d ! = 2 ) & & ( ( a . a = = a . d ) | | ( a . b = = a . d ) ) ; \
break ; \
\
case 1 : \
/* dest alpha should be one */ \
bDestAlphaColor = 2 ; \
break ; \
/* default: 16bit surface, so returned alpha is ok */ \
} \
break ; \
\
case 2 : \
bNeedBlendFactorInAlpha = 1 ; /* should disable alpha channel writing */ \
vAlphaBlendColor . y = 0 ; \
vAlphaBlendColor . w = ( sign ) ? ( float ) a . fix * ( 2.0f / 255.0f ) : ( float ) a . fix * ( - 2.0f / 255.0f ) ; \
usec = 0 ; /* change so that alpha comes from source*/ \
break ; \
} \
} \
/ / if ( a . fix < = 0x80 ) { \
/ / dwTemp = ( a . fix * 2 ) > 255 ? 255 : ( a . fix * 2 ) ; \
/ / dwTemp = dwTemp | ( dwTemp < < 8 ) | ( dwTemp < < 16 ) | 0x80000000 ; \
/ / printf ( " bfactor: %8.8x \n " , dwTemp ) ; \
/ / glBlendColorEXT ( dwTemp ) ; \
/ / } \
/ / else { \
void ZeroGS : : ResetAlphaVariables ( )
{
}
void ZeroGS : : SetAlphaVariables ( const alphaInfo & a )
{
bool alphaenable = true ;
// TODO: negative color when not clamping turns to positive???
g_vars . _bAlphaState = 0 ; // set all to zero
bNeedBlendFactorInAlpha = 0 ;
b2XAlphaTest = 1 ;
u32 dwTemp = 0xffffffff ;
// default
s_srcalpha = GL_ONE ;
s_dstalpha = GL_ZERO ;
s_alphaeq = GL_FUNC_ADD ;
s_alphaInfo = a ;
vAlphaBlendColor = Vector ( 1 , 2 * 255.0f / 256.0f , 0 , 0 ) ;
u32 usec = a . c ;
if ( a . a = = a . b )
{ // just d remains
if ( a . d = = 0 )
{
alphaenable = false ;
}
else
{
s_dstrgb = a . d = = 1 ? GL_ONE : GL_ZERO ;
s_srcrgb = GL_ZERO ;
s_rgbeq = GL_FUNC_ADD ;
}
goto EndSetAlpha ;
}
else if ( a . d = = 2 )
{ // zero
if ( a . a = = 2 )
{
// zero all color
s_srcrgb = GL_ZERO ;
s_dstrgb = GL_ZERO ;
goto EndSetAlpha ;
}
else if ( a . b = = 2 )
{
//b2XAlphaTest = 1;
SET_ALPHA_COLOR_FACTOR ( 1 ) ;
if ( bDestAlphaColor = = 2 )
{
s_rgbeq = GL_FUNC_ADD ;
s_srcrgb = a . a = = 0 ? GL_ONE : GL_ZERO ;
s_dstrgb = a . a = = 0 ? GL_ZERO : GL_ONE ;
}
else
{
bAlphaClamping = 2 ;
s_rgbeq = GL_FUNC_ADD ;
s_srcrgb = a . a = = 0 ? blendalpha [ usec ] : GL_ZERO ;
s_dstrgb = a . a = = 0 ? GL_ZERO : blendalpha [ usec ] ;
}
goto EndSetAlpha ;
}
// nothing is zero, so must do some real blending
//b2XAlphaTest = 1;
bAlphaClamping = 3 ;
SET_ALPHA_COLOR_FACTOR ( 1 ) ;
s_rgbeq = a . a = = 0 ? GL_FUNC_SUBTRACT : GL_FUNC_REVERSE_SUBTRACT ;
s_srcrgb = bDestAlphaColor = = 2 ? GL_ONE : blendalpha [ usec ] ;
s_dstrgb = bDestAlphaColor = = 2 ? GL_ONE : blendalpha [ usec ] ;
}
else if ( a . a = = 2 )
{ // zero
//b2XAlphaTest = 1;
bAlphaClamping = 1 ; // min testing
SET_ALPHA_COLOR_FACTOR ( 1 ) ;
if ( a . b = = a . d )
{
// can get away with 1-A
s_rgbeq = GL_FUNC_ADD ;
s_srcrgb = ( a . b = = 0 & & bDestAlphaColor ! = 2 ) ? blendinvalpha [ usec ] : GL_ZERO ;
s_dstrgb = ( a . b = = 0 | | bDestAlphaColor = = 2 ) ? GL_ZERO : blendinvalpha [ usec ] ;
}
else
{
s_rgbeq = a . b = = 0 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_SUBTRACT ;
s_srcrgb = ( a . b = = 0 & & bDestAlphaColor ! = 2 ) ? blendalpha [ usec ] : GL_ONE ;
s_dstrgb = ( a . b = = 0 | | bDestAlphaColor = = 2 ) ? GL_ONE : blendalpha [ usec ] ;
}
}
else if ( a . b = = 2 )
{
bAlphaClamping = 2 ; // max testing
SET_ALPHA_COLOR_FACTOR ( a . a ! = a . d ) ;
if ( a . a = = a . d )
{
// can get away with 1+A, but need to set alpha to negative
s_rgbeq = GL_FUNC_ADD ;
if ( bDestAlphaColor = = 2 )
{
assert ( usec = = 1 ) ;
// all ones
bNeedBlendFactorInAlpha = 1 ;
vAlphaBlendColor . y = 0 ;
vAlphaBlendColor . w = - 1 ;
s_srcrgb = ( a . a = = 0 ) ? GL_ONE_MINUS_SRC_ALPHA : GL_ZERO ;
s_dstrgb = ( a . a = = 0 ) ? GL_ZERO : GL_ONE_MINUS_SRC_ALPHA ;
}
else
{
s_srcrgb = a . a = = 0 ? blendinvalpha [ usec ] : GL_ZERO ;
s_dstrgb = a . a = = 0 ? GL_ZERO : blendinvalpha [ usec ] ;
}
}
else
{
//b2XAlphaTest = 1;
s_rgbeq = GL_FUNC_ADD ;
s_srcrgb = ( a . a = = 0 & & bDestAlphaColor ! = 2 ) ? blendalpha [ usec ] : GL_ONE ;
s_dstrgb = ( a . a = = 0 | | bDestAlphaColor = = 2 ) ? GL_ONE : blendalpha [ usec ] ;
}
}
else
{
// all 3 components are valid!
bAlphaClamping = 3 ; // all testing
SET_ALPHA_COLOR_FACTOR ( a . a ! = a . d ) ;
if ( a . a = = a . d )
{
// can get away with 1+A, but need to set alpha to negative
s_rgbeq = GL_FUNC_ADD ;
if ( bDestAlphaColor = = 2 )
{
assert ( usec = = 1 ) ;
// all ones
bNeedBlendFactorInAlpha = 1 ;
vAlphaBlendColor . y = 0 ;
vAlphaBlendColor . w = - 1 ;
s_srcrgb = a . a = = 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA ;
s_dstrgb = a . a = = 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA ;
}
else
{
s_srcrgb = a . a = = 0 ? blendinvalpha [ usec ] : blendalpha [ usec ] ;
s_dstrgb = a . a = = 0 ? blendalpha [ usec ] : blendinvalpha [ usec ] ;
}
}
else
{
assert ( a . b = = a . d ) ;
s_rgbeq = GL_FUNC_ADD ;
if ( bDestAlphaColor = = 2 )
{
assert ( usec = = 1 ) ;
// all ones
bNeedBlendFactorInAlpha = 1 ;
vAlphaBlendColor . y = 0 ;
vAlphaBlendColor . w = 1 ;
s_srcrgb = a . a ! = 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA ;
s_dstrgb = a . a ! = 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA ;
}
else
{
//b2XAlphaTest = 1;
s_srcrgb = a . a ! = 0 ? blendinvalpha [ usec ] : blendalpha [ usec ] ;
s_dstrgb = a . a ! = 0 ? blendalpha [ usec ] : blendinvalpha [ usec ] ;
}
}
}
EndSetAlpha :
GL_BLEND_SET ( ) ;
zgsBlendEquationSeparateEXT ( s_rgbeq , s_alphaeq ) ;
if ( alphaenable )
glEnable ( GL_BLEND ) ; // always set
else
glDisable ( GL_BLEND ) ;
INC_ALPHAVARS ( ) ;
}
void ZeroGS : : SetWriteDepth ( )
{
if ( conf . mrtdepth ) {
s_bWriteDepth = TRUE ;
s_nWriteDepthCount = 4 ;
}
}
BOOL ZeroGS : : IsWriteDepth ( )
{
return s_bWriteDepth ;
}
BOOL ZeroGS : : IsWriteDestAlphaTest ( )
{
return s_bWriteDepth ;
}
void ZeroGS : : SetDestAlphaTest ( )
{
s_bDestAlphaTest = TRUE ;
s_nWriteDestAlphaTest = 4 ;
}
void ZeroGS : : SetFogColor ( u32 fog )
{
if ( 1 | | gs . fogcol ! = fog ) {
gs . fogcol = fog ;
ZeroGS : : Flush ( 0 ) ;
ZeroGS : : Flush ( 1 ) ;
if ( ! g_bIsLost ) {
Vector v ;
// set it immediately
v . x = ( gs . fogcol & 0xff ) / 255.0f ;
v . y = ( ( gs . fogcol > > 8 ) & 0xff ) / 255.0f ;
v . z = ( ( gs . fogcol > > 16 ) & 0xff ) / 255.0f ;
cgGLSetParameter4fv ( g_fparamFogColor , v ) ;
}
}
}
void ZeroGS : : ExtWrite ( )
{
WARN_LOG ( " ExtWrite \n " ) ;
// use local DISPFB, EXTDATA, EXTBUF, and PMODE
// int bpp, start, end;
// tex0Info texframe;
// bpp = 4;
// if( texframe.psm == 0x12 ) bpp = 3;
// else if( texframe.psm & 2 ) bpp = 2;
//
// // get the start and end addresses of the buffer
// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw);
}
////////////
// Caches //
////////////
# ifdef __x86_64__
extern " C " void TestClutChangeMMX ( void * src , void * dst , int entries , void * pret ) ;
# endif
bool ZeroGS : : CheckChangeInClut ( u32 highdword , u32 psm )
{
int cld = ( highdword > > 29 ) & 0x7 ;
int cbp = ( ( highdword > > 5 ) & 0x3fff ) ;
// processing the CLUT after tex0/2 are written
switch ( cld ) {
case 0 : return false ;
case 1 : break ; // Seems to rarely not be 1.
// note sure about changing cbp[0,1]
case 4 : return gs . cbp [ 0 ] ! = cbp ;
case 5 : return gs . cbp [ 1 ] ! = cbp ;
// default: load
default : break ;
}
int cpsm = ( highdword > > 19 ) & 0xe ;
int csm = ( highdword > > 23 ) & 0x1 ;
if ( cpsm > 1 | | csm )
// don't support 16bit for now
return true ;
int csa = ( highdword > > 24 ) & 0x1f ;
int entries = ( psm & 3 ) = = 3 ? 256 : 16 ;
u64 * src = ( u64 * ) ( g_pbyGSMemory + cbp * 256 ) ;
u64 * dst = ( u64 * ) ( g_pbyGSClut + 64 * csa ) ;
bool bRet = false ;
// do a fast test with MMX
# ifdef _MSC_VER
# ifdef __x86_64__
TestClutChangeMMX ( dst , src , entries , & bRet ) ;
# else
int storeebx ;
__asm {
mov storeebx , ebx
mov edx , dst
mov ecx , src
mov ebx , entries
Start :
movq mm0 , [ edx ]
movq mm1 , [ edx + 8 ]
pcmpeqd mm0 , [ ecx ]
pcmpeqd mm1 , [ ecx + 16 ]
movq mm2 , [ edx + 16 ]
movq mm3 , [ edx + 24 ]
pcmpeqd mm2 , [ ecx + 32 ]
pcmpeqd mm3 , [ ecx + 48 ]
pand mm0 , mm1
pand mm2 , mm3
movq mm4 , [ edx + 32 ]
movq mm5 , [ edx + 40 ]
pcmpeqd mm4 , [ ecx + 8 ]
pcmpeqd mm5 , [ ecx + 24 ]
pand mm0 , mm2
pand mm4 , mm5
movq mm6 , [ edx + 48 ]
movq mm7 , [ edx + 56 ]
pcmpeqd mm6 , [ ecx + 40 ]
pcmpeqd mm7 , [ ecx + 56 ]
pand mm0 , mm4
pand mm6 , mm7
pand mm0 , mm6
pmovmskb eax , mm0
cmp eax , 0xff
je Continue
mov bRet , 1
jmp Return
Continue :
cmp ebx , 16
jle Return
test ebx , 0x10
jz AddEcx
sub ecx , 448 // go back and down one column,
AddEcx :
add ecx , 256 // go to the right block
jne Continue1
add ecx , 256 // skip whole block
Continue1 :
add edx , 64
sub ebx , 16
jmp Start
Return :
emms
mov ebx , storeebx
}
# endif // __x86_64__
# else // linux
# ifdef __x86_64__
__asm__ (
" .intel_syntax \n "
" Start: \n "
" movq %%mm0, [%%rcx] \n "
" movq %%mm1, [%%rcx+8] \n "
" pcmpeqd %%mm0, [%%rdx] \n "
" pcmpeqd %%mm1, [%%rdx+16] \n "
" movq %%mm2, [%%rcx+16] \n "
" movq %%mm3, [%%rcx+24] \n "
" pcmpeqd %%mm2, [%%rdx+32] \n "
" pcmpeqd %%mm3, [%%rdx+48] \n "
" pand %%mm0, %%mm1 \n "
" pand %%mm2, %%mm3 \n "
" movq %%mm4, [%%rcx+32] \n "
" movq %%mm5, [%%rcx+40] \n "
" pcmpeqd %%mm4, [%%rdx+8] \n "
" pcmpeqd %%mm5, [%%rdx+24] \n "
" pand %%mm0, %%mm2 \n "
" pand %%mm4, %%mm5 \n "
" movq %%mm6, [%%rcx+48] \n "
" movq %%mm7, [%%rcx+56] \n "
" pcmpeqd %%mm6, [%%rdx+40] \n "
" pcmpeqd %%mm7, [%%rdx+56] \n "
" pand %%mm0, %%mm4 \n "
" pand %%mm6, %%mm7 \n "
" pand %%mm0, %%mm6 \n "
" pmovmskb %%eax, %%mm0 \n "
" cmp %%eax, 0xff \n "
" je Continue \n "
" .att_syntax \n "
" movb $1, %0 \n "
" .intel_syntax \n "
" jmp Return \n "
" Continue: \n "
" cmp %%rbx, 16 \n "
" jle Return \n "
" test %%rbx, 0x10 \n "
" jz AddRcx \n "
" sub %%rdx, 448 \n " // go back and down one column
" AddRcx: \n "
" add %%rdx, 256 \n " // go to the right block
" cmp %%rbx, 0x90 \n "
" jne Continue1 \n "
" add %%rdx, 256 \n " // skip whole block
" Continue1: \n "
" add %%rcx, 64 \n "
" sub %%rbx, 16 \n "
" jmp Start \n "
" Return: \n "
" emms \n "
" .att_syntax \n " : " =m " ( bRet ) : " c " ( dst ) , " d " ( src ) , " b " ( entries ) : " rax " , " memory " ) ;
# else
// do a fast test with MMX
__asm__ (
" .intel_syntax \n "
" Start: \n "
" movq %%mm0, [%%ecx] \n "
" movq %%mm1, [%%ecx+8] \n "
" pcmpeqd %%mm0, [%%edx] \n "
" pcmpeqd %%mm1, [%%edx+16] \n "
" movq %%mm2, [%%ecx+16] \n "
" movq %%mm3, [%%ecx+24] \n "
" pcmpeqd %%mm2, [%%edx+32] \n "
" pcmpeqd %%mm3, [%%edx+48] \n "
" pand %%mm0, %%mm1 \n "
" pand %%mm2, %%mm3 \n "
" movq %%mm4, [%%ecx+32] \n "
" movq %%mm5, [%%ecx+40] \n "
" pcmpeqd %%mm4, [%%edx+8] \n "
" pcmpeqd %%mm5, [%%edx+24] \n "
" pand %%mm0, %%mm2 \n "
" pand %%mm4, %%mm5 \n "
" movq %%mm6, [%%ecx+48] \n "
" movq %%mm7, [%%ecx+56] \n "
" pcmpeqd %%mm6, [%%edx+40] \n "
" pcmpeqd %%mm7, [%%edx+56] \n "
" pand %%mm0, %%mm4 \n "
" pand %%mm6, %%mm7 \n "
" pand %%mm0, %%mm6 \n "
" pmovmskb %%eax, %%mm0 \n "
" cmp %%eax, 0xff \n "
" je Continue \n "
" .att_syntax \n "
" movb $1, %0 \n "
" .intel_syntax \n "
" jmp Return \n "
" Continue: \n "
" cmp %%ebx, 16 \n "
" jle Return \n "
" test %%ebx, 0x10 \n "
" jz AddEcx \n "
" sub %%edx, 448 \n " // go back and down one column
" AddEcx: \n "
" add %%edx, 256 \n " // go to the right block
" cmp %%ebx, 0x90 \n "
" jne Continue1 \n "
" add %%edx, 256 \n " // skip whole block
" Continue1: \n "
" add %%ecx, 64 \n "
" sub %%ebx, 16 \n "
" jmp Start \n "
" Return: \n "
" emms \n "
" .att_syntax \n " : " =m " ( bRet ) : " c " ( dst ) , " d " ( src ) , " b " ( entries ) : " eax " , " memory " ) ;
# endif // __x86_64__
# endif // _WIN32
return bRet ;
}
void ZeroGS : : texClutWrite ( int ctx )
{
s_bTexFlush = 0 ;
if ( g_bIsLost )
return ;
tex0Info & tex0 = vb [ ctx ] . tex0 ;
assert ( PSMT_ISCLUT ( tex0 . psm ) ) ;
// processing the CLUT after tex0/2 are written
switch ( tex0 . cld ) {
case 0 : return ;
case 1 : break ; // tex0.cld is usually 1.
case 2 : gs . cbp [ 0 ] = tex0 . cbp ; break ;
case 3 : gs . cbp [ 1 ] = tex0 . cbp ; break ;
// not sure about changing cbp[0,1]
case 4 :
if ( gs . cbp [ 0 ] = = tex0 . cbp )
return ;
gs . cbp [ 0 ] = tex0 . cbp ;
break ;
case 5 :
if ( gs . cbp [ 1 ] = = tex0 . cbp )
return ;
gs . cbp [ 1 ] = tex0 . cbp ;
break ;
default : //DEBUG_LOG("cld isn't 0-5!");
break ;
}
Flush ( ! ctx ) ;
int entries = ( tex0 . psm & 3 ) = = 3 ? 256 : 16 ;
if ( tex0 . csm )
{
switch ( tex0 . cpsm )
{
// 16bit psm
// eggomania uses non16bit textures for csm2
case PSMCT16 :
{
u16 * src = ( u16 * ) g_pbyGSMemory + tex0 . cbp * 128 ;
u16 * dst = ( u16 * ) ( g_pbyGSClut + 32 * ( tex0 . csa & 15 ) + ( tex0 . csa > = 16 ? 2 : 0 ) ) ;
for ( int i = 0 ; i < entries ; + + i )
{
* dst = src [ getPixelAddress16_0 ( gs . clut . cou + i , gs . clut . cov , gs . clut . cbw ) ] ;
dst + = 2 ;
// check for wrapping
if ( ( ( u32 ) ( uptr ) dst & 0x3ff ) = = 0 ) dst = ( u16 * ) ( g_pbyGSClut + 2 ) ;
}
break ;
}
case PSMCT16S :
{
u16 * src = ( u16 * ) g_pbyGSMemory + tex0 . cbp * 128 ;
u16 * dst = ( u16 * ) ( g_pbyGSClut + 32 * ( tex0 . csa & 15 ) + ( tex0 . csa > = 16 ? 2 : 0 ) ) ;
for ( int i = 0 ; i < entries ; + + i )
{
* dst = src [ getPixelAddress16S_0 ( gs . clut . cou + i , gs . clut . cov , gs . clut . cbw ) ] ;
dst + = 2 ;
// check for wrapping
if ( ( ( u32 ) ( uptr ) dst & 0x3ff ) = = 0 ) dst = ( u16 * ) ( g_pbyGSClut + 2 ) ;
}
break ;
}
case PSMCT32 :
case PSMCT24 :
{
u32 * src = ( u32 * ) g_pbyGSMemory + tex0 . cbp * 64 ;
u32 * dst = ( u32 * ) ( g_pbyGSClut + 64 * tex0 . csa ) ;
// check if address exceeds src
if ( src + getPixelAddress32_0 ( gs . clut . cou + entries - 1 , gs . clut . cov , gs . clut . cbw ) > = ( u32 * ) g_pbyGSMemory + 0x00100000 )
ERROR_LOG ( " texClutWrite out of bounds \n " ) ;
else
for ( int i = 0 ; i < entries ; + + i )
{
* dst = src [ getPixelAddress32_0 ( gs . clut . cou + i , gs . clut . cov , gs . clut . cbw ) ] ;
dst + + ;
}
break ;
}
default :
{
# ifndef RELEASE_TO_PUBLIC
//DEBUG_LOG("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm);
# endif
break ;
}
}
}
else
{
switch ( tex0 . cpsm )
{
case PSMCT24 :
case PSMCT32 :
if ( entries = = 16 )
WriteCLUT_T32_I4_CSM1 ( ( u32 * ) ( g_pbyGSMemory + tex0 . cbp * 256 ) , ( u32 * ) ( g_pbyGSClut + 64 * tex0 . csa ) ) ;
else
WriteCLUT_T32_I8_CSM1 ( ( u32 * ) ( g_pbyGSMemory + tex0 . cbp * 256 ) , ( u32 * ) ( g_pbyGSClut + 64 * tex0 . csa ) ) ;
break ;
default :
if ( entries = = 16 )
WriteCLUT_T16_I4_CSM1 ( ( u32 * ) ( g_pbyGSMemory + 256 * tex0 . cbp ) , ( u32 * ) ( g_pbyGSClut + 32 * ( tex0 . csa & 15 ) + ( tex0 . csa > = 16 ? 2 : 0 ) ) ) ;
else // sse2 for 256 is more complicated, so use regular
WriteCLUT_T16_I8_CSM1_c ( ( u32 * ) ( g_pbyGSMemory + 256 * tex0 . cbp ) , ( u32 * ) ( g_pbyGSClut + 32 * ( tex0 . csa & 15 ) + ( tex0 . csa > = 16 ? 2 : 0 ) ) ) ;
break ;
}
}
}
void ZeroGS : : SetTexFlush ( )
{
s_bTexFlush = TRUE ;
// if( PSMT_ISCLUT(vb[0].tex0.psm) )
// texClutWrite(0);
// if( PSMT_ISCLUT(vb[1].tex0.psm) )
// texClutWrite(1);
if ( ! s_bForceTexFlush )
{
if ( s_ptexCurSet [ 0 ] ! = s_ptexNextSet [ 0 ] ) s_ptexCurSet [ 0 ] = s_ptexNextSet [ 0 ] ;
if ( s_ptexCurSet [ 1 ] ! = s_ptexNextSet [ 1 ] ) s_ptexCurSet [ 1 ] = s_ptexNextSet [ 1 ] ;
}
}
int ZeroGS : : Save ( char * pbydata )
{
if ( pbydata = = NULL )
return 40 + 0x00400000 + sizeof ( gs ) + 2 * VBSAVELIMIT + 2 * sizeof ( frameInfo ) + 4 + 256 * 4 ;
s_RTs . ResolveAll ( ) ;
s_DepthRTs . ResolveAll ( ) ;
strcpy ( pbydata , libraryName ) ;
* ( u32 * ) ( pbydata + 16 ) = ZEROGS_SAVEVER ;
pbydata + = 32 ;
* ( int * ) pbydata = icurctx ; pbydata + = 4 ;
* ( int * ) pbydata = VBSAVELIMIT ; pbydata + = 4 ;
memcpy ( pbydata , g_pbyGSMemory , 0x00400000 ) ;
pbydata + = 0x00400000 ;
memcpy ( pbydata , g_pbyGSClut , 256 * 4 ) ;
pbydata + = 256 * 4 ;
* ( int * ) pbydata = sizeof ( gs ) ;
pbydata + = 4 ;
memcpy ( pbydata , & gs , sizeof ( gs ) ) ;
pbydata + = sizeof ( gs ) ;
for ( int i = 0 ; i < 2 ; + + i ) {
memcpy ( pbydata , & vb [ i ] , VBSAVELIMIT ) ;
pbydata + = VBSAVELIMIT ;
}
return 0 ;
}
extern u32 s_uTex1Data [ 2 ] [ 2 ] , s_uClampData [ 2 ] ;
extern char * libraryName ;
bool ZeroGS : : Load ( char * pbydata )
{
memset ( s_uTex1Data , 0 , sizeof ( s_uTex1Data ) ) ;
memset ( s_uClampData , 0 , sizeof ( s_uClampData ) ) ;
g_nCurVBOIndex = 0 ;
// first 32 bytes are the id
u32 savever = * ( u32 * ) ( pbydata + 16 ) ;
if ( strncmp ( pbydata , libraryName , 6 ) = = 0 & & ( savever = = ZEROGS_SAVEVER | | savever = = 0xaa000004 ) ) {
g_MemTargs . Destroy ( ) ;
GSStateReset ( ) ;
pbydata + = 32 ;
int context = * ( int * ) pbydata ; pbydata + = 4 ;
u32 savelimit = VBSAVELIMIT ;
savelimit = * ( u32 * ) pbydata ; pbydata + = 4 ;
memcpy ( g_pbyGSMemory , pbydata , 0x00400000 ) ;
pbydata + = 0x00400000 ;
memcpy ( g_pbyGSClut , pbydata , 256 * 4 ) ;
pbydata + = 256 * 4 ;
memset ( & gs , 0 , sizeof ( gs ) ) ;
int savedgssize ;
if ( savever = = 0xaa000004 )
savedgssize = 0x1d0 ;
else {
savedgssize = * ( int * ) pbydata ;
pbydata + = 4 ;
}
memcpy ( & gs , pbydata , savedgssize ) ;
pbydata + = savedgssize ;
prim = & gs . _prim [ gs . prac ] ;
vb [ 0 ] . Destroy ( ) ;
memcpy ( & vb [ 0 ] , pbydata , min ( savelimit , VBSAVELIMIT ) ) ;
pbydata + = savelimit ;
vb [ 0 ] . pBufferData = NULL ;
vb [ 1 ] . Destroy ( ) ;
memcpy ( & vb [ 1 ] , pbydata , min ( savelimit , VBSAVELIMIT ) ) ;
pbydata + = savelimit ;
vb [ 1 ] . pBufferData = NULL ;
for ( int i = 0 ; i < 2 ; + + i ) {
vb [ i ] . Init ( VB_BUFFERSIZE ) ;
vb [ i ] . bNeedZCheck = vb [ i ] . bNeedFrameCheck = 1 ;
vb [ i ] . bSyncVars = 0 ; vb [ i ] . bNeedTexCheck = 1 ;
memset ( vb [ i ] . uCurTex0Data , 0 , sizeof ( vb [ i ] . uCurTex0Data ) ) ;
}
icurctx = - 1 ;
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , s_uFramebuffer ) ; // switch to the backbuffer
SetFogColor ( gs . fogcol ) ;
GL_REPORT_ERRORD ( ) ;
return true ;
}
return false ;
}
void ZeroGS : : SaveSnapshot ( const char * filename )
{
g_bMakeSnapshot = 1 ;
strSnapshot = filename ;
}
bool ZeroGS : : SaveRenderTarget ( const char * filename , int width , int height , int jpeg )
{
bool bflip = height < 0 ;
height = abs ( height ) ;
vector < u32 > data ( width * height ) ;
glReadPixels ( 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_BYTE , & data [ 0 ] ) ;
if ( glGetError ( ) ! = GL_NO_ERROR )
return false ;
if ( bflip ) {
// swap scanlines
vector < u32 > scanline ( width ) ;
for ( int i = 0 ; i < height / 2 ; + + i ) {
memcpy ( & scanline [ 0 ] , & data [ i * width ] , width * 4 ) ;
memcpy ( & data [ i * width ] , & data [ ( height - i - 1 ) * width ] , width * 4 ) ;
memcpy ( & data [ ( height - i - 1 ) * width ] , & scanline [ 0 ] , width * 4 ) ;
}
}
if ( jpeg ) return SaveJPEG ( filename , width , height , & data [ 0 ] , 70 ) ;
return SaveTGA ( filename , width , height , & data [ 0 ] ) ;
}
bool ZeroGS : : SaveTexture ( const char * filename , u32 textarget , u32 tex , int width , int height )
{
vector < u32 > data ( width * height ) ;
glBindTexture ( textarget , tex ) ;
glGetTexImage ( textarget , 0 , GL_RGBA , GL_UNSIGNED_BYTE , & data [ 0 ] ) ;
if ( glGetError ( ) ! = GL_NO_ERROR ) {
return false ;
}
return SaveTGA ( filename , width , height , & data [ 0 ] ) ; //SaveJPEG(filename, width, height, &data[0], 70);
}
extern " C " {
# ifdef _WIN32
# define XMD_H
# undef FAR
# define HAVE_BOOLEAN
# endif
# include "jpeglib.h"
}
bool ZeroGS : : SaveJPEG ( const char * filename , int image_width , int image_height , const void * pdata , int quality )
{
u8 * image_buffer = new u8 [ image_width * image_height * 3 ] ;
u8 * psrc = ( u8 * ) pdata ;
// input data is rgba format, so convert to rgb
u8 * p = image_buffer ;
for ( int i = 0 ; i < image_height ; + + i ) {
for ( int j = 0 ; j < image_width ; + + j ) {
p [ 0 ] = psrc [ 0 ] ;
p [ 1 ] = psrc [ 1 ] ;
p [ 2 ] = psrc [ 2 ] ;
p + = 3 ;
psrc + = 4 ;
}
}
/* This struct contains the JPEG compression parameters and pointers to
* working space ( which is allocated as needed by the JPEG library ) .
* It is possible to have several such structures , representing multiple
* compression / decompression processes , in existence at once . We refer
* to any one struct ( and its associated working data ) as a " JPEG object " .
*/
struct jpeg_compress_struct cinfo ;
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* ( see the second half of this file for an example ) . But here we just
* take the easy way out and use the standard error handler , which will
* print a message on stderr and call exit ( ) if compression fails .
* Note that this struct must live as long as the main JPEG parameter
* struct , to avoid dangling - pointer problems .
*/
struct jpeg_error_mgr jerr ;
/* More stuff */
FILE * outfile ; /* target file */
JSAMPROW row_pointer [ 1 ] ; /* pointer to JSAMPLE row[s] */
int row_stride ; /* physical row width in image buffer */
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
* step fails . ( Unlikely , but it could happen if you are out of memory . )
* This routine fills in the contents of struct jerr , and returns jerr ' s
* address which we place into the link field in cinfo .
*/
cinfo . err = jpeg_std_error ( & jerr ) ;
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress ( & cinfo ) ;
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
/* Here we use the library-supplied code to send compressed data to a
* stdio stream . You can also write your own code to do something else .
* VERY IMPORTANT : use " b " option to fopen ( ) if you are on a machine that
* requires it in order to write binary files .
*/
if ( ( outfile = fopen ( filename , " wb " ) ) = = NULL ) {
fprintf ( stderr , " can't open %s \n " , filename ) ;
exit ( 1 ) ;
}
jpeg_stdio_dest ( & cinfo , outfile ) ;
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in :
*/
cinfo . image_width = image_width ; /* image width and height, in pixels */
cinfo . image_height = image_height ;
cinfo . input_components = 3 ; /* # of color components per pixel */
cinfo . in_color_space = JCS_RGB ; /* colorspace of input image */
/* Now use the library's routine to set default compression parameters.
* ( You must set at least cinfo . in_color_space before calling this ,
* since the defaults depend on the source color space . )
*/
jpeg_set_defaults ( & cinfo ) ;
/* Now you can set any non-default parameters you wish to.
* Here we just illustrate the use of quality ( quantization table ) scaling :
*/
jpeg_set_quality ( & cinfo , quality , TRUE /* limit to baseline-JPEG values */ ) ;
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you ' re doing .
*/
jpeg_start_compress ( & cinfo , TRUE ) ;
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter , so that we don ' t have to keep track ourselves .
* To keep things simple , we pass one scanline per call ; you can pass
* more if you wish , though .
*/
row_stride = image_width * 3 ; /* JSAMPLEs per row in image_buffer */
while ( cinfo . next_scanline < cinfo . image_height ) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long , but you could pass
* more than one scanline at a time if that ' s more convenient .
*/
row_pointer [ 0 ] = & image_buffer [ cinfo . next_scanline * row_stride ] ;
( void ) jpeg_write_scanlines ( & cinfo , row_pointer , 1 ) ;
}
/* Step 6: Finish compression */
jpeg_finish_compress ( & cinfo ) ;
/* After finish_compress, we can close the output file. */
fclose ( outfile ) ;
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress ( & cinfo ) ;
delete image_buffer ;
/* And we're done! */
return true ;
}
# if defined(_MSC_VER)
# pragma pack(push, 1)
# endif
struct TGA_HEADER
{
u8 identsize ; // size of ID field that follows 18 u8 header (0 usually)
u8 colourmaptype ; // type of colour map 0=none, 1=has palette
u8 imagetype ; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed
s16 colourmapstart ; // first colour map entry in palette
s16 colourmaplength ; // number of colours in palette
u8 colourmapbits ; // number of bits per palette entry 15,16,24,32
s16 xstart ; // image x origin
s16 ystart ; // image y origin
s16 width ; // image width in pixels
s16 height ; // image height in pixels
u8 bits ; // image bits per pixel 8,16,24,32
u8 descriptor ; // image descriptor bits (vh flip bits)
// pixel data follows header
# if defined(_MSC_VER)
} ;
# pragma pack(pop)
# else
} __attribute__ ( ( packed ) ) ;
# endif
bool ZeroGS : : SaveTGA ( const char * filename , int width , int height , void * pdata )
{
TGA_HEADER hdr ;
FILE * f = fopen ( filename , " wb " ) ;
if ( f = = NULL )
return false ;
assert ( sizeof ( TGA_HEADER ) = = 18 & & sizeof ( hdr ) = = 18 ) ;
memset ( & hdr , 0 , sizeof ( hdr ) ) ;
hdr . imagetype = 2 ;
hdr . bits = 32 ;
hdr . width = width ;
hdr . height = height ;
hdr . descriptor | = 8 | ( 1 < < 5 ) ; // 8bit alpha, flip vertical
fwrite ( & hdr , sizeof ( hdr ) , 1 , f ) ;
fwrite ( pdata , width * height * 4 , 1 , f ) ;
fclose ( f ) ;
return true ;
}
// AVI capture stuff
void ZeroGS : : StartCapture ( )
{
if ( ! s_aviinit ) {
# ifdef _WIN32
START_AVI ( " zerogs.avi " ) ;
# else // linux
//TODO
# endif
s_aviinit = 1 ;
}
else {
ERROR_LOG ( " Continuing from previous capture " ) ;
}
s_avicapturing = 1 ;
}
void ZeroGS : : StopCapture ( )
{
s_avicapturing = 0 ;
}
void ZeroGS : : CaptureFrame ( )
{
assert ( s_avicapturing & & s_aviinit ) ;
//vector<u8> mem(nBackbufferWidth*nBackbufferHeight);
vector < u32 > data ( nBackbufferWidth * nBackbufferHeight ) ;
glReadPixels ( 0 , 0 , nBackbufferWidth , nBackbufferHeight , GL_RGBA , GL_UNSIGNED_BYTE , & data [ 0 ] ) ;
if ( glGetError ( ) ! = GL_NO_ERROR )
return ;
// u8* pend = (u8*)&data[0] + (nBackbufferHeight-1)*nBackbufferWidth*4;
// for(int i = 0; i < conf.height; ++i) {
// memcpy_amd(&mem[nBackbufferWidth*4*i], pend - nBackbufferWidth*4*i, nBackbufferWidth * 4);
// }
int fps = SMODE1 - > CMOD = = 3 ? 50 : 60 ;
# ifdef _WIN32
bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI ( " AAAA " , fps , nBackbufferWidth , nBackbufferHeight , 32 , & data [ 0 ] ) ;
if ( ! bSuccess ) {
s_avicapturing = 0 ;
STOP_AVI ( ) ;
ZeroGS : : AddMessage ( " Failed to create avi " ) ;
return ;
}
# else // linux
//TODO
# endif
}