mirror of https://github.com/PCSX2/pcsx2.git
2628 lines
74 KiB
C++
2628 lines
74 KiB
C++
|
/* ZZ Open GL graphics plugin
|
||
|
* Copyright (c)2009 zeydlitz@gmail.com
|
||
|
* Based on Zerofrog's ZeroGS KOSMOS (c)2005-2006
|
||
|
*
|
||
|
* 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
|
||
|
*/
|
||
|
|
||
|
// Realisation of Flush -- drawing function of GS
|
||
|
|
||
|
//------------------ Includes
|
||
|
//#if defined(_WIN32)
|
||
|
//# include <windows.h>
|
||
|
//# include "resource.h"
|
||
|
//#endif
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "GS.h"
|
||
|
#include "Mem.h"
|
||
|
#include "zerogs.h"
|
||
|
#include "targets.h"
|
||
|
|
||
|
using namespace ZeroGS;
|
||
|
|
||
|
//------------------ Defines
|
||
|
#ifndef DEVBUILD
|
||
|
|
||
|
#define INC_GENVARS()
|
||
|
#define INC_TEXVARS()
|
||
|
#define INC_ALPHAVARS()
|
||
|
#define INC_RESOLVE()
|
||
|
|
||
|
#define g_bUpdateEffect 0
|
||
|
#define g_bSaveTex 0
|
||
|
bool g_bSaveTrans = 0;
|
||
|
#define g_bSaveResolved 0
|
||
|
|
||
|
#else // NOT RELEASE_TO_PUBLIC
|
||
|
|
||
|
#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_bSaveResolved = 0;
|
||
|
#endif // RELEASE_TO_PUBLIC
|
||
|
|
||
|
#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 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_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 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))
|
||
|
|
||
|
// ----------------- Types
|
||
|
//------------------ Dummies
|
||
|
|
||
|
//------------------ variables
|
||
|
|
||
|
extern bool g_bIsLost;
|
||
|
bool g_bUpdateStencil = 1;
|
||
|
u32 g_SaveFrameNum = 0; // ZZ
|
||
|
|
||
|
int GPU_TEXWIDTH = 512;
|
||
|
float g_fiGPU_TEXWIDTH = 1/512.0f;
|
||
|
|
||
|
extern CGprogram g_psprog; // 2 -- ZZ
|
||
|
|
||
|
// local alpha blending settings
|
||
|
static GLenum s_rgbeq, s_alphaeq; // set by zgsBlendEquationSeparateEXT // ZZ
|
||
|
|
||
|
|
||
|
static const u32 blendalpha[3] = { GL_SRC_ALPHA, GL_DST_ALPHA, GL_CONSTANT_COLOR_EXT }; // ZZ
|
||
|
static const u32 blendinvalpha[3] = { GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR_EXT }; //ZZ
|
||
|
static const u32 g_dwAlphaCmp[] = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL }; // ZZ
|
||
|
|
||
|
// 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 };
|
||
|
|
||
|
/////////////////////
|
||
|
// graphics resources
|
||
|
#define s_bForceTexFlush 1 // ZZ
|
||
|
u32 s_ptexCurSet[2] = {0};
|
||
|
static u32 s_ptexNextSet[2] = {0}; // ZZ
|
||
|
|
||
|
vector<u32> s_vecTempTextures; // temporary textures, released at the end of every frame
|
||
|
|
||
|
extern bool s_bTexFlush;
|
||
|
bool s_bWriteDepth = FALSE;
|
||
|
bool s_bDestAlphaTest = FALSE;
|
||
|
int s_ClutResolve = 0; // ZZ
|
||
|
int g_nDepthUsed = 0; // ffx2 pal movies
|
||
|
int s_nWriteDepthCount = 0; // ZZ
|
||
|
int s_nWriteDestAlphaTest = 0; // ZZ
|
||
|
|
||
|
////////////////////
|
||
|
// State parameters
|
||
|
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
|
||
|
|
||
|
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 // ZZ
|
||
|
|
||
|
static alphaInfo s_alphaInfo; // ZZ
|
||
|
|
||
|
extern u8* g_pbyGSClut;
|
||
|
|
||
|
//------------------ Namespace
|
||
|
|
||
|
namespace ZeroGS {
|
||
|
|
||
|
VB vb[2];
|
||
|
float fiTexWidth[2], fiTexHeight[2]; // current tex width and height
|
||
|
|
||
|
u8 s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set
|
||
|
u8 s_AAz = 0, s_AAw = 0; // if AAy is set, then AAx has to be set
|
||
|
|
||
|
int icurctx = -1;
|
||
|
|
||
|
extern CRangeManager s_RangeMngr; // manages overwritten memory // zz
|
||
|
void FlushTransferRanges(const tex0Info* ptex); //zz
|
||
|
|
||
|
RenderFormatType GetRenderFormat() { return g_RenderFormatType; } //zz
|
||
|
|
||
|
// use to update the state
|
||
|
void SetTexVariables(int context, FRAGMENTSHADER* pfragment); // zz
|
||
|
void SetTexInt(int context, FRAGMENTSHADER* pfragment, int settexint); // zz
|
||
|
void SetAlphaVariables(const alphaInfo& ainfo); // zzz
|
||
|
void ResetAlphaVariables();
|
||
|
|
||
|
inline void SetAlphaTestInt(pixTest curtest);
|
||
|
|
||
|
inline void RenderAlphaTest(const VB& curvb, CGparameter sOneColor);
|
||
|
inline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting);
|
||
|
inline void ProcessStencil(const VB& curvb);
|
||
|
inline void RenderFBA(const VB& curvb, CGparameter sOneColor);
|
||
|
inline void ProcessFBA(const VB& curvb, CGparameter sOneColor); // zz
|
||
|
|
||
|
|
||
|
}
|
||
|
//------------------ Code
|
||
|
|
||
|
inline float AlphaReferedValue(int aref) {
|
||
|
return b2XAlphaTest ? min (1.0f, (float)aref / 127.5f) : (float)aref /255.0f ;
|
||
|
}
|
||
|
|
||
|
inline void SetAlphaTest(const pixTest& curtest) {
|
||
|
// if s_dwColorWrite is nontrivial, than we should not off alphatest.
|
||
|
// This fix GOW and Okami.
|
||
|
if( !curtest.ate && USEALPHATESTING && (s_dwColorWrite != 2 && s_dwColorWrite != 14 )) {
|
||
|
glDisable(GL_ALPHA_TEST);
|
||
|
}
|
||
|
else {
|
||
|
glEnable(GL_ALPHA_TEST);
|
||
|
glAlphaFunc(g_dwAlphaCmp[curtest.atst], AlphaReferedValue(curtest.aref));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Switch wireframe rendering off for first flush, so it's draw few solid primitives
|
||
|
inline void SwitchWireframeOff() {
|
||
|
if( conf.options & GSOPTION_WIREFRAME ) {
|
||
|
if( s_nWireframeCount > 0 ) {
|
||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Switch wireframe rendering on, look at previous function
|
||
|
inline void SwitchWireframeOn() {
|
||
|
if( conf.options & GSOPTION_WIREFRAME ) {
|
||
|
if( s_nWireframeCount > 0 ) {
|
||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||
|
--s_nWireframeCount;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
long BufferNumber = 0;
|
||
|
|
||
|
// This is debug function. It's print all buffer info and save current texture into the file, than printf file name.
|
||
|
inline void
|
||
|
VisualBufferMessage(int context) {
|
||
|
#if defined(PRIM_LOG) && defined(_DEBUG)
|
||
|
BufferNumber++;
|
||
|
ZeroGS::VB& curvb = vb[context];
|
||
|
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" };
|
||
|
ERROR_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);
|
||
|
ERROR_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);
|
||
|
ERROR_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);
|
||
|
ERROR_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]);
|
||
|
ERROR_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);
|
||
|
char* Name;
|
||
|
// if (g_bSaveTex) {
|
||
|
// if (g_bSaveTex == 1)
|
||
|
Name = NamedSaveTex(&curvb.tex0, 1);
|
||
|
// else
|
||
|
// Name = NamedSaveTex(&curvb.tex0, 0);
|
||
|
ERROR_LOG("TGA name %s\n", Name);
|
||
|
free(Name);
|
||
|
// }
|
||
|
ERROR_LOG("frame: %d, buffer %ld\n\n", g_SaveFrameNum, BufferNumber);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
inline void SaveRendererTarget(VB& curvb) {
|
||
|
#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
|
||
|
}
|
||
|
|
||
|
// Stop effects in Developers mode
|
||
|
inline void FlushUpdateEffect() {
|
||
|
#ifdef DEVBUID
|
||
|
if( g_bUpdateEffect ) {
|
||
|
ReloadEffects();
|
||
|
g_bUpdateEffect = 0;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Check, maybe we cold skip flush
|
||
|
inline bool IsFlushNoNeed(VB& curvb, const pixTest& curtest ) {
|
||
|
if (curvb.nCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost) {
|
||
|
curvb.nCount = 0;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Transfer targets, that are located in current texture.
|
||
|
inline void FlushTransferRangesHelper(VB& curvb) {
|
||
|
if( s_RangeMngr.ranges.size() > 0 ) {
|
||
|
// don't want infinite loop, so set nCount to 0.
|
||
|
u32 prevcount = curvb.nCount;
|
||
|
curvb.nCount = 0;
|
||
|
|
||
|
FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL);
|
||
|
|
||
|
curvb.nCount += prevcount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If set bit for texture cheking, do it. Maybe it's all.
|
||
|
inline bool FushTexDataHelper(VB& curvb){
|
||
|
if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) {
|
||
|
curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0);
|
||
|
}
|
||
|
|
||
|
if( curvb.bNeedTexCheck ) { // Zeydlitz want to try this
|
||
|
curvb.FlushTexData();
|
||
|
|
||
|
if (curvb.nCount == 0)
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Null target mean that we do something really bad.
|
||
|
inline bool FlushCheckForNULLTarget(VB& curvb, int context){
|
||
|
if ((curvb.prndr == NULL) || (curvb.pdepth == NULL)) {
|
||
|
ERROR_LOG_SPAMA("Current render target NULL (ctx: %d)", context);
|
||
|
curvb.nCount = 0;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// O.k. A set of resolutions, we do before real flush. We do RangeManager, FrameCheck and
|
||
|
// ZCheck before this.
|
||
|
inline bool FlushInitialTest(VB& curvb, const pixTest& curtest, int context) {
|
||
|
GL_REPORT_ERRORD();
|
||
|
assert( context >= 0 && context <= 1 );
|
||
|
|
||
|
FlushUpdateEffect();
|
||
|
|
||
|
if (IsFlushNoNeed(curvb, curtest))
|
||
|
return true;
|
||
|
|
||
|
FlushTransferRangesHelper(curvb);
|
||
|
|
||
|
if (FushTexDataHelper(curvb))
|
||
|
return true;
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
|
||
|
if (FlushCheckForNULLTarget(curvb, context))
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Try to different approach if texture target was not found
|
||
|
inline CRenderTarget* FlushReGetTarget(int& tbw, int& tbp0, int& tpsm, VB& curvb) {
|
||
|
// This was incorrect code
|
||
|
CRenderTarget* ptextarg = NULL;
|
||
|
|
||
|
if (ptextarg == NULL && tpsm == PSMT8 && (g_GameSettings & GAME_REGETHACK) ) {
|
||
|
// check for targets with half the width. Break Valkyrie Chronicles
|
||
|
ptextarg = s_RTs.GetTarg(tbp0, tbw/2, curvb);
|
||
|
if( ptextarg == NULL ) {
|
||
|
tbp0 &= ~0x7ff;
|
||
|
ptextarg = s_RTs.GetTarg(tbp0, tbw/2, curvb); // mgs3 hack
|
||
|
|
||
|
if( ptextarg == NULL ) {
|
||
|
// check the next level (mgs3)
|
||
|
tbp0 &= ~0xfff;
|
||
|
ptextarg = s_RTs.GetTarg(tbp0, tbw/2, curvb); // mgs3 hack
|
||
|
}
|
||
|
|
||
|
if( ptextarg != NULL && ptextarg->start > tbp0*256 ) {
|
||
|
// target beyond range, so ignore
|
||
|
ptextarg = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if( PSMT_ISZTEX(tpsm) && (ptextarg == NULL) ) {
|
||
|
// try depth
|
||
|
ptextarg = s_DepthRTs.GetTarg(tbp0, tbw, curvb);
|
||
|
}
|
||
|
|
||
|
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 ) < curvb.prndr->end)) {
|
||
|
ptextarg = curvb.prndr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (tbp0 == 0x3600 && tbw == 0x100) {
|
||
|
if (ptextarg == NULL) {
|
||
|
printf ("Miss %x 0x%x %d\n", tbw, tbp0, tpsm);
|
||
|
|
||
|
typedef map<u32, CRenderTarget*> MAPTARGETS;
|
||
|
for(MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) {
|
||
|
printf("\tRender %x 0x%x %x\n", itnew->second->fbw, itnew->second->fbp, itnew->second->psm);
|
||
|
}
|
||
|
for(MAPTARGETS::iterator itnew = s_DepthRTs.mapTargets.begin(); itnew != s_DepthRTs.mapTargets.end(); ++itnew) {
|
||
|
printf("\tDepth %x 0x%x %x\n", itnew->second->fbw, itnew->second->fbp, itnew->second->psm);
|
||
|
}
|
||
|
|
||
|
printf ("\tCurvb 0x%x 0x%x 0x%x %x\n", curvb.frame.fbp, curvb.prndr->end, curvb.prndr->fbp, curvb.prndr->fbw);
|
||
|
}
|
||
|
else
|
||
|
printf ("Hit %x 0x%x %x\n", tbw, tbp0, tpsm);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return ptextarg;
|
||
|
}
|
||
|
|
||
|
// Find target to draw a texture, it's highly p
|
||
|
inline CRenderTarget* FlushGetTarget(VB& curvb) {
|
||
|
int tbw, tbp0, tpsm;
|
||
|
|
||
|
CRenderTarget* ptextarg = NULL;
|
||
|
if (!curvb.curprim.tme)
|
||
|
return ptextarg;
|
||
|
|
||
|
if (curvb.bNeedTexCheck) {
|
||
|
printf ("How it is possible?\n");
|
||
|
// not yet initied, but still need to get correct target! (xeno3 ingame)
|
||
|
tbp0 = ZZOglGet_tbp0_TexBits(curvb.uNextTex0Data[0]);
|
||
|
tbw = ZZOglGet_tbw_TexBitsMult(curvb.uNextTex0Data[0]);
|
||
|
tpsm = ZZOglGet_psm_TexBitsFix(curvb.uNextTex0Data[0]);
|
||
|
}
|
||
|
else{
|
||
|
tbw = curvb.tex0.tbw;
|
||
|
tbp0 = curvb.tex0.tbp0;
|
||
|
tpsm = curvb.tex0.psm;
|
||
|
}
|
||
|
|
||
|
ptextarg = s_RTs.GetTarg(tbp0, tbw, curvb);
|
||
|
if (ptextarg == NULL)
|
||
|
ptextarg = FlushReGetTarget(tbw, tbp0, tpsm, curvb);
|
||
|
|
||
|
if ((ptextarg != NULL) && !(ptextarg->status & CRenderTarget::TS_NeedUpdate)) {
|
||
|
if (PSMT_BITMODE(tpsm) == 4) { // handle 8h cluts
|
||
|
// don't support clut targets, read from mem
|
||
|
// 4hl - kh2 check - from dx version -- arcum42
|
||
|
if ( tpsm == PSMT4 && 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;
|
||
|
|
||
|
return ptextarg;
|
||
|
}
|
||
|
|
||
|
// Set target for current context
|
||
|
inline void FlushSetContextTarget(VB& curvb, int context) {
|
||
|
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(GetFrameKey(curvb.pdepth));
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void FlushSetStream(VB& curvb) {
|
||
|
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();
|
||
|
#ifdef _DEBUG
|
||
|
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||
|
assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT );
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
int SetMaskR = 0x0; int SetMaskG = 0x0; int SetMaskB = 0x0;
|
||
|
// Set color mask. Really it's not as good as PS2 one.
|
||
|
inline void FlushSetColorMask(VB& curvb) {
|
||
|
s_dwColorWrite = (PSMT_BITMODE(curvb.prndr->psm) == 1) ? (COLORMASK_BLUE|COLORMASK_GREEN|COLORMASK_RED) : 0xf;
|
||
|
|
||
|
int maskR = ZZOglGet_fbmRed_FrameBits(curvb.frame.fbm);
|
||
|
int maskG = ZZOglGet_fbmGreen_FrameBits(curvb.frame.fbm);
|
||
|
int maskB = ZZOglGet_fbmBlue_FrameBits(curvb.frame.fbm);
|
||
|
int maskA = ZZOglGet_fbmAlpha_FrameBits(curvb.frame.fbm);
|
||
|
|
||
|
if (maskR == 0xff)
|
||
|
s_dwColorWrite &= ~COLORMASK_RED;
|
||
|
if (maskG == 0xff)
|
||
|
s_dwColorWrite &= ~COLORMASK_GREEN;
|
||
|
if (maskB == 0xff)
|
||
|
s_dwColorWrite &= ~COLORMASK_BLUE;
|
||
|
if ((maskA == 0xff) || (curvb.curprim.abe && (curvb.test.atst == 2 && curvb.test.aref == 128)))
|
||
|
s_dwColorWrite &= ~COLORMASK_ALPHA;
|
||
|
|
||
|
GL_COLORMASK(s_dwColorWrite);
|
||
|
}
|
||
|
|
||
|
// Set Scissors for scissor test.
|
||
|
inline void FlushSetScissorRect(VB& curvb) {
|
||
|
Rect& scissor = curvb.prndr->scissorrect;
|
||
|
glScissor(scissor.x, scissor.y, scissor.w, scissor.h);
|
||
|
}
|
||
|
|
||
|
// Prior really doing something check context
|
||
|
inline void FlushDoContextJob(VB& curvb, int context) {
|
||
|
SaveRendererTarget(curvb);
|
||
|
|
||
|
FlushSetContextTarget(curvb, context);
|
||
|
icurctx = context;
|
||
|
|
||
|
FlushSetStream(curvb);
|
||
|
FlushSetColorMask(curvb);
|
||
|
FlushSetScissorRect(curvb);
|
||
|
}
|
||
|
|
||
|
// Set 1 is Alpha test is EQUAL and alpha should be proceed with care.
|
||
|
inline int FlushGetExactcolor(const pixTest curtest) {
|
||
|
if (!(g_nPixelShaderVer&SHADER_REDUCED))
|
||
|
// ffx2 breaks when ==7
|
||
|
return ((curtest.ate && curtest.aref <= 128) && (curtest.atst==4));//||curtest.atst==7);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// fill the buffer by decoding the clut
|
||
|
inline void FlushDecodeClut(VB& curvb, GLuint& ptexclut) {
|
||
|
glGenTextures(1, &ptexclut);
|
||
|
glBindTexture(GL_TEXTURE_2D, ptexclut);
|
||
|
vector<char> data(PSMT_ISHALF_STORAGE(curvb.tex0) ? 512 : 1024);
|
||
|
|
||
|
if( ptexclut != 0 ) {
|
||
|
|
||
|
int nClutOffset = 0, clutsize;
|
||
|
int entries = PSMT_IS8CLUT(curvb.tex0.psm) ? 256 : 16;
|
||
|
|
||
|
if (curvb.tex0.csm && curvb.tex0.csa )
|
||
|
printf ("ERROR, csm1\n");
|
||
|
|
||
|
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, PSMT_ISHALF_STORAGE(curvb.tex0)?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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline int FlushGetShaderType(VB& curvb, CRenderTarget* ptextarg, GLuint& ptexclut) {
|
||
|
if( PSMT_ISCLUT(curvb.tex0.psm) && !(g_GameSettings&GAME_NOTARGETCLUT) ) {
|
||
|
FlushDecodeClut(curvb, ptexclut);
|
||
|
if( !(g_nPixelShaderVer&SHADER_REDUCED) && PSMT_ISHALF(ptextarg->psm) ) {
|
||
|
return 4;
|
||
|
}
|
||
|
else {
|
||
|
// Valkyrie
|
||
|
return 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (PSMT_ISHALF_STORAGE(curvb.tex0) != PSMT_ISHALF(ptextarg->psm) && (!(g_nPixelShaderVer&SHADER_REDUCED) || !curvb.curprim.fge) ) {
|
||
|
if (PSMT_ISHALF_STORAGE(curvb.tex0)) {
|
||
|
// converting from 32->16
|
||
|
// Radiata Chronicles
|
||
|
return 3;
|
||
|
}
|
||
|
else {
|
||
|
// converting from 16->32
|
||
|
// Star Ward: Force
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//Set page offsets depends omn shader type.
|
||
|
inline Vector FlushSetPageOffset(FRAGMENTSHADER* pfragment, int shadertype, CRenderTarget* ptextarg) {
|
||
|
SetShaderCaller("FlushSetPageOffset");
|
||
|
|
||
|
Vector vpageoffset;
|
||
|
vpageoffset.w = 0;
|
||
|
|
||
|
switch (shadertype) {
|
||
|
case 3:
|
||
|
vpageoffset.x = -0.1f / 256.0f;
|
||
|
vpageoffset.y = -0.001f / 256.0f;
|
||
|
vpageoffset.z = -0.1f / (ptextarg->fbh);
|
||
|
vpageoffset.w = 0.0f;
|
||
|
break;
|
||
|
case 4:
|
||
|
vpageoffset.x = 2;
|
||
|
vpageoffset.y = 1;
|
||
|
vpageoffset.z = 0;
|
||
|
vpageoffset.w = 0.0001f;
|
||
|
break;
|
||
|
}
|
||
|
// zoe2
|
||
|
if (PSMT_ISZTEX(ptextarg->psm))
|
||
|
vpageoffset.w = -1.0f;
|
||
|
|
||
|
ZZcgSetParameter4fv(pfragment->fPageOffset, vpageoffset, "g_fPageOffset");
|
||
|
return vpageoffset;
|
||
|
}
|
||
|
|
||
|
//Set texture offsets depends omn shader type.
|
||
|
inline Vector FlushSetTexOffset(FRAGMENTSHADER* pfragment, int shadertype, VB& curvb, CRenderTarget* ptextarg) {
|
||
|
SetShaderCaller("FlushSetTexOffset");
|
||
|
Vector v;
|
||
|
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;
|
||
|
ZZcgSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset");
|
||
|
}
|
||
|
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;
|
||
|
ZZcgSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset");
|
||
|
}
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
// Set dimension (Real!) of texture. z and w
|
||
|
inline Vector FlushTextureDims(FRAGMENTSHADER* pfragment, int shadertype, VB& curvb, CRenderTarget* ptextarg) {
|
||
|
SetShaderCaller("FlushTextureDims");
|
||
|
Vector vTexDims;
|
||
|
vTexDims.x = (float)RW(curvb.tex0.tw) ;
|
||
|
vTexDims.y = (float)RH(curvb.tex0.th) ;
|
||
|
|
||
|
// 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 = PSMT_ISHALF(ptextarg->psm) ? 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;
|
||
|
}
|
||
|
|
||
|
if (shadertype == 4)
|
||
|
vTexDims.z += 8.0f;
|
||
|
|
||
|
ZZcgSetParameter4fv(pfragment->fTexDims, vTexDims, "g_fTexDims");
|
||
|
return vTexDims;
|
||
|
}
|
||
|
|
||
|
// Apply TEX1 mmag and mmin -- filter for expanding/reducing texture
|
||
|
// We ignore all settings, only NEAREST (0) is used
|
||
|
inline void FlushApplyResizeFilter(VB& curvb, u32& dwFilterOpts, CRenderTarget* ptextarg, int context) {
|
||
|
u32 ptexset = (ptextarg == curvb.prndr) ? ptextarg->ptexFeedback : ptextarg->ptex;
|
||
|
s_ptexCurSet[context] = ptexset;
|
||
|
|
||
|
if ((!curvb.tex1.mmag) || (!curvb.tex1.mmin))
|
||
|
glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset);
|
||
|
|
||
|
if( !curvb.tex1.mmag ) {
|
||
|
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
dwFilterOpts |= 1;
|
||
|
}
|
||
|
|
||
|
if( !curvb.tex1.mmin ) {
|
||
|
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
dwFilterOpts |= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Usage existing targets depends on several tricks, 32-16 conversion and CLUTing, so we need handle it.
|
||
|
inline FRAGMENTSHADER* FlushUseExistRenderTaget(VB& curvb, CRenderTarget* ptextarg, u32& dwFilterOpts, int exactcolor, int context) {
|
||
|
if (ptextarg->IsDepth())
|
||
|
SetWriteDepth();
|
||
|
|
||
|
GLuint ptexclut = 0;
|
||
|
int psm = GetTexCPSM(curvb.tex0);
|
||
|
int shadertype = FlushGetShaderType(curvb, ptextarg, ptexclut);
|
||
|
|
||
|
FRAGMENTSHADER* pfragment = LoadShadeEffect(shadertype, 0, curvb.curprim.fge,
|
||
|
IsAlphaTestExpansion(curvb), exactcolor, curvb.clamp, context, NULL);
|
||
|
|
||
|
Vector vpageoffset = FlushSetPageOffset(pfragment, shadertype, ptextarg);
|
||
|
Vector v = FlushSetTexOffset(pfragment, shadertype, curvb, ptextarg);
|
||
|
Vector vTexDims = FlushTextureDims(pfragment, shadertype, curvb, ptextarg);
|
||
|
|
||
|
if( pfragment->sCLUT != NULL && ptexclut != 0 ) {
|
||
|
cgGLSetTextureParameter(pfragment->sCLUT, ptexclut);
|
||
|
cgGLEnableTextureParameter(pfragment->sCLUT);
|
||
|
}
|
||
|
|
||
|
FlushApplyResizeFilter(curvb, dwFilterOpts, ptextarg, context);
|
||
|
|
||
|
if( g_bSaveTex )
|
||
|
SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_NV,
|
||
|
ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, RW(ptextarg->fbw), RH(ptextarg->fbh));
|
||
|
|
||
|
return pfragment;
|
||
|
}
|
||
|
|
||
|
// Usage most major shader.
|
||
|
inline FRAGMENTSHADER* FlushMadeNewTarget(VB& curvb, int exactcolor, int context) {
|
||
|
// save the texture
|
||
|
if( g_bSaveTex ) {
|
||
|
if( g_bSaveTex == 1 ) {
|
||
|
SaveTex(&curvb.tex0, 1);
|
||
|
CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0);
|
||
|
}
|
||
|
else SaveTex(&curvb.tex0, 0);
|
||
|
}
|
||
|
|
||
|
FRAGMENTSHADER* pfragment = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge,
|
||
|
IsAlphaTestExpansion(curvb), exactcolor, curvb.clamp, context, NULL);
|
||
|
|
||
|
if (pfragment == NULL)
|
||
|
ERROR_LOG("Could not find memory target shader\n");
|
||
|
|
||
|
return pfragment;
|
||
|
}
|
||
|
|
||
|
// We made an shader, so now need to put all common variables.
|
||
|
inline void FlushSetTexture(VB& curvb, FRAGMENTSHADER* pfragment, CRenderTarget* ptextarg, int context) {
|
||
|
SetTexVariables(context, pfragment);
|
||
|
SetTexInt(context, pfragment, ptextarg == NULL);
|
||
|
|
||
|
// have to enable the texture parameters(curtest.atst=
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Reset programm and texture variables;
|
||
|
inline void FlushBindProgramm( FRAGMENTSHADER* pfragment, int context) {
|
||
|
vb[context].bTexConstsSync = 0;
|
||
|
vb[context].bVarsTexSync = 0;
|
||
|
|
||
|
cgGLBindProgram(pfragment->prog);
|
||
|
g_psprog = pfragment->prog;
|
||
|
}
|
||
|
|
||
|
inline FRAGMENTSHADER* FlushRendererStage(VB& curvb, u32& dwFilterOpts, CRenderTarget* ptextarg, int exactcolor, int context) {
|
||
|
|
||
|
FRAGMENTSHADER* pfragment = NULL;
|
||
|
|
||
|
// set the correct pixel shaders
|
||
|
if (curvb.curprim.tme) {
|
||
|
if (ptextarg != NULL)
|
||
|
pfragment = FlushUseExistRenderTaget(curvb, ptextarg, dwFilterOpts, exactcolor, context);
|
||
|
else
|
||
|
pfragment = FlushMadeNewTarget(curvb, exactcolor, context);
|
||
|
|
||
|
if (pfragment == NULL) {
|
||
|
ERROR_LOG("Shader does not found\n");
|
||
|
// return NULL;
|
||
|
}
|
||
|
FlushSetTexture(curvb, pfragment, ptextarg, context);
|
||
|
}
|
||
|
else {
|
||
|
pfragment = &ppsRegular[curvb.curprim.fge + 2 * s_bWriteDepth];
|
||
|
}
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
|
||
|
// set the shaders
|
||
|
SetShaderCaller("FlushRendererStage") ;
|
||
|
SETVERTEXSHADER(pvs[2 * ((curvb.curprim._val >> 1) & 3) + 8 * s_bWriteDepth + context] );
|
||
|
FlushBindProgramm(pfragment, context);
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
return pfragment;
|
||
|
}
|
||
|
|
||
|
inline bool AlphaCanRenderStencil(VB& curvb) {
|
||
|
return g_bUpdateStencil && (PSMT_BITMODE(curvb.prndr->psm) != 1) &&
|
||
|
!ZZOglGet_fbmHighByte(curvb.frame.fbm) && !(g_GameSettings & GAME_NOSTENCIL);
|
||
|
}
|
||
|
|
||
|
inline void AlphaSetStencil (bool DoIt) {
|
||
|
if (DoIt) {
|
||
|
glEnable(GL_STENCIL_TEST);
|
||
|
GL_STENCILFUNC(GL_ALWAYS, 0, 0);
|
||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||
|
}
|
||
|
else glDisable(GL_STENCIL_TEST);
|
||
|
}
|
||
|
|
||
|
inline void AlphaSetDepthTest(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pfragment) {
|
||
|
glDepthMask(!curvb.zbuf.zmsk && curtest.zte);
|
||
|
// && curtest.zte && (curtest.ztst > 1) );
|
||
|
|
||
|
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]);
|
||
|
}
|
||
|
GL_ZTEST(curtest.zte);
|
||
|
|
||
|
// glEnable (GL_POLYGON_OFFSET_FILL);
|
||
|
// glPolygonOffset (-1., -1.);
|
||
|
|
||
|
if (s_bWriteDepth) {
|
||
|
if(!curvb.zbuf.zmsk)
|
||
|
curvb.pdepth->SetRenderTarget(1);
|
||
|
else
|
||
|
ResetRenderTarget(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline u32 AlphaSetupBlendTest(VB& curvb) {
|
||
|
if (curvb.curprim.abe)
|
||
|
SetAlphaVariables(curvb.alpha);
|
||
|
else
|
||
|
glDisable(GL_BLEND);
|
||
|
|
||
|
u32 oldabe = curvb.curprim.abe;
|
||
|
if (gs.pabe) {
|
||
|
//ERROR_LOG("PBE!\n");
|
||
|
curvb.curprim.abe = 1;
|
||
|
glEnable(GL_BLEND);
|
||
|
}
|
||
|
return oldabe;
|
||
|
}
|
||
|
|
||
|
inline void AlphaRenderFBA(VB& curvb, FRAGMENTSHADER* pfragment, bool s_bDestAlphaTest, bool bCanRenderStencil) {
|
||
|
// needs to be before RenderAlphaTest
|
||
|
if ((gs.pabe) || (curvb.fba.fba && !ZZOglGet_fbmHighByte(curvb.frame.fbm)) || (s_bDestAlphaTest && bCanRenderStencil)) {
|
||
|
RenderFBA(curvb, pfragment->sOneColor);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
inline u32 AlphaRenderAlpha(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pfragment, int exactcolor) {
|
||
|
SetShaderCaller("AlphaRenderAlpha");
|
||
|
u32 dwUsingSpecialTesting = 0;
|
||
|
if (curvb.curprim.abe) {
|
||
|
if ((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;
|
||
|
if (exactcolor) {
|
||
|
v.y *= 255;
|
||
|
v.w *= 255;
|
||
|
}
|
||
|
ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
|
||
|
}
|
||
|
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);
|
||
|
ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
|
||
|
|
||
|
}
|
||
|
return dwUsingSpecialTesting;
|
||
|
}
|
||
|
|
||
|
inline void AlphaRenderStencil(VB& curvb, bool s_bDestAlphaTest, bool bCanRenderStencil, u32 dwUsingSpecialTesting) {
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
}
|
||
|
|
||
|
inline void AlphaTest(VB& curvb) {
|
||
|
// printf ("%d %d %d %d %d\n", curvb.test.date, curvb.test.datm, gs.texa.aem, curvb.test.ate, curvb.test.atst );
|
||
|
|
||
|
// return;
|
||
|
// Zeydlitz change this with a reason! It's "Alpha more than 1 hack."
|
||
|
if (curvb.test.ate == 1 && curvb.test.atst == 1 && curvb.test.date == 1) {
|
||
|
if (curvb.test.datm == 1)
|
||
|
glAlphaFunc(GL_GREATER, 1.0f);
|
||
|
else {
|
||
|
glAlphaFunc(GL_LESS, 1.0f);
|
||
|
printf ("%d %d %d\n", curvb.test.date, curvb.test.datm, gs.texa.aem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!curvb.test.ate || curvb.test.atst > 0) {
|
||
|
DRAW();
|
||
|
}
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
}
|
||
|
|
||
|
inline void AlphaPabe(VB& curvb, FRAGMENTSHADER* pfragment, int exactcolor) {
|
||
|
if( gs.pabe ) {
|
||
|
SetShaderCaller("AlphaPabe");
|
||
|
// 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;
|
||
|
ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
|
||
|
|
||
|
DRAW();
|
||
|
|
||
|
// reset
|
||
|
if (!s_stencilmask)
|
||
|
s_stencilfunc = GL_ALWAYS;
|
||
|
GL_STENCILFUNC_SET();
|
||
|
}
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
}
|
||
|
|
||
|
// Alfa Failure does not work properly on this cases. True means that no failure job should be done
|
||
|
// First three cases are trivail manual
|
||
|
inline bool AlphaFailureIgnore(const pixTest curtest) {
|
||
|
if (!curtest.ate)
|
||
|
return true;
|
||
|
if (curtest.atst == 1)
|
||
|
return true;
|
||
|
if (curtest.afail == 0)
|
||
|
return true;
|
||
|
if (g_GameSettings & GAME_NOALPHAFAIL && ((s_dwColorWrite < 8) || (s_dwColorWrite == 15 && curtest.atst == 5 && (curtest.aref == 64))))
|
||
|
return true;
|
||
|
|
||
|
// old and seemingly incorrect code.
|
||
|
// if ((s_dwColorWrite < 8 && s_dwColorWrite !=8) && curtest.afail == 1)
|
||
|
// return true;
|
||
|
// if ((s_dwColorWrite == 0xf) && curtest.atst == 5 && curtest.afail == 1 && !(g_GameSettings & GAME_REGETHACK))
|
||
|
// return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// more work on alpha failure case
|
||
|
inline void AlphaFailureTestJob(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pfragment, int exactcolor, bool bCanRenderStencil, int oldabe) {
|
||
|
// Note, case when ate == 1, atst == 0 and afail > 0 in documentation wrote as failure case. But it seems that
|
||
|
// either doc's are incorrect nor this case have some issues.
|
||
|
if (AlphaFailureIgnore(curtest)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#ifdef NOALFAFAIL
|
||
|
ERROR_LOG("Alpha job here %d %d %d %d %d %d\n", s_dwColorWrite, curtest.atst, curtest.afail, curtest.aref, gs.pabe, s_bWriteDepth);
|
||
|
// return;
|
||
|
#endif
|
||
|
|
||
|
SetShaderCaller("AlphaFailureTestJob");
|
||
|
|
||
|
// need to reverse the test and disable some targets
|
||
|
glAlphaFunc(g_dwReverseAlphaCmp[curtest.atst], AlphaReferedValue(curtest.aref));
|
||
|
|
||
|
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; }
|
||
|
ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
|
||
|
glEnable(GL_BLEND);
|
||
|
GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
inline void AlphaSpecialTesting(VB& curvb, FRAGMENTSHADER* pfragment, u32 dwUsingSpecialTesting, int exactcolor) {
|
||
|
if (dwUsingSpecialTesting) {
|
||
|
SetShaderCaller("AlphaSpecialTesting");
|
||
|
|
||
|
// 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);
|
||
|
ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
|
||
|
DRAW();
|
||
|
|
||
|
// don't need to restore
|
||
|
}
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
}
|
||
|
|
||
|
inline void AlphaDestinationTest(VB& curvb, FRAGMENTSHADER* pfragment, bool s_bDestAlphaTest, bool bCanRenderStencil) {
|
||
|
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");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void AlphaSaveTarget(VB& curvb) {
|
||
|
#ifdef _DEBUG
|
||
|
return; // Do nothing
|
||
|
|
||
|
if( g_bSaveFlushedFrame & 0xf ) {
|
||
|
#ifdef _WIN32
|
||
|
CreateDirectory("frames", NULL);
|
||
|
#else
|
||
|
char* strdir="";
|
||
|
sprintf(strdir, "mkdir %s", "frames");
|
||
|
system(strdir);
|
||
|
#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, RW(curvb.prndr->fbw), RH(curvb.prndr->fbh));
|
||
|
SaveRenderTarget(str, RW(curvb.prndr->fbw), RH(curvb.prndr->fbh), 0);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
inline void AlphaColorClamping (VB& curvb, const pixTest curtest) {
|
||
|
// 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);
|
||
|
}
|
||
|
SetShaderCaller("AlphaColorClamping");
|
||
|
|
||
|
SETPIXELSHADER(ppsOne.prog);
|
||
|
GL_BLEND_RGB(GL_ONE, GL_ONE);
|
||
|
|
||
|
float f;
|
||
|
if( bAlphaClamping & 1 ) { // min
|
||
|
f = 0;
|
||
|
ZZcgSetParameter4fv(ppsOne.sOneColor, &f, "g_fOneColor");
|
||
|
GL_BLENDEQ_RGB(GL_MAX_EXT);
|
||
|
DRAW();
|
||
|
}
|
||
|
|
||
|
// bios shows white screen
|
||
|
if( bAlphaClamping & 2 ) { // max
|
||
|
f = 1;
|
||
|
ZZcgSetParameter4fv(ppsOne.sOneColor, &f, "g_fOneColor");
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void FlushUndoFiter(u32 dwFilterOpts) {
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This is the most important function! it's draw all collected info oncscreen.
|
||
|
void
|
||
|
ZeroGS::Flush(int context)
|
||
|
{
|
||
|
FUNCLOG
|
||
|
VB& curvb = vb[context];
|
||
|
const pixTest curtest = curvb.test;
|
||
|
|
||
|
if (FlushInitialTest(curvb, curtest, context))
|
||
|
return;
|
||
|
|
||
|
VisualBufferMessage(context);
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
CRenderTarget* ptextarg = FlushGetTarget(curvb);
|
||
|
|
||
|
SwitchWireframeOff();
|
||
|
FlushDoContextJob(curvb, context);
|
||
|
|
||
|
u32 dwUsingSpecialTesting = 0;
|
||
|
u32 dwFilterOpts = 0;
|
||
|
int exactcolor = FlushGetExactcolor(curtest);
|
||
|
FRAGMENTSHADER* pfragment = FlushRendererStage(curvb, dwFilterOpts, ptextarg, exactcolor, context);
|
||
|
|
||
|
bool bCanRenderStencil = AlphaCanRenderStencil(curvb);
|
||
|
if (curtest.date || gs.pabe)
|
||
|
SetDestAlphaTest();
|
||
|
|
||
|
AlphaSetStencil(s_bDestAlphaTest && bCanRenderStencil);
|
||
|
AlphaSetDepthTest(curvb, curtest, pfragment); // Error!
|
||
|
SetAlphaTest(curtest);
|
||
|
u32 oldabe = AlphaSetupBlendTest(curvb); // Unavoidable
|
||
|
|
||
|
// needs to be before RenderAlphaTest
|
||
|
AlphaRenderFBA(curvb, pfragment, s_bDestAlphaTest, bCanRenderStencil);
|
||
|
dwUsingSpecialTesting = AlphaRenderAlpha(curvb, curtest, pfragment, exactcolor); // Unavoidable
|
||
|
AlphaRenderStencil(curvb, s_bDestAlphaTest, bCanRenderStencil, dwUsingSpecialTesting);
|
||
|
AlphaTest(curvb); // Unavoidable
|
||
|
AlphaPabe(curvb, pfragment, exactcolor);
|
||
|
AlphaFailureTestJob(curvb, curtest, pfragment, exactcolor, bCanRenderStencil, oldabe);
|
||
|
AlphaSpecialTesting(curvb, pfragment, dwUsingSpecialTesting, exactcolor);
|
||
|
AlphaDestinationTest(curvb, pfragment, s_bDestAlphaTest, bCanRenderStencil);
|
||
|
AlphaSaveTarget(curvb);
|
||
|
|
||
|
GL_REPORT_ERRORD();
|
||
|
|
||
|
AlphaColorClamping (curvb, curtest);
|
||
|
FlushUndoFiter(dwFilterOpts);
|
||
|
ppf += curvb.nCount+0x100000;
|
||
|
|
||
|
curvb.nCount = 0;
|
||
|
curvb.curprim.abe = oldabe;
|
||
|
SwitchWireframeOn();
|
||
|
GL_REPORT_ERRORD();
|
||
|
}
|
||
|
|
||
|
inline 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);
|
||
|
|
||
|
SetShaderCaller("RenderFBA");
|
||
|
glEnable(GL_ALPHA_TEST);
|
||
|
glAlphaFunc(GL_GEQUAL, 1);
|
||
|
|
||
|
Vector v;
|
||
|
v.x = 1; v.y = 2; v.z = 0; v.w = 0;
|
||
|
ZZcgSetParameter4fv(sOneColor, v, "g_fOneColor");
|
||
|
|
||
|
DRAW();
|
||
|
|
||
|
SetAlphaTest(curvb.test);
|
||
|
|
||
|
// 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) && (curvb.test.afail == 1))
|
||
|
glDisable(GL_ALPHA_TEST);
|
||
|
|
||
|
glDepthMask(0);
|
||
|
glColorMask(0,0,0,0);
|
||
|
|
||
|
if (s_bWriteDepth)
|
||
|
ResetRenderTarget(1);
|
||
|
|
||
|
SetShaderCaller("RenderAlphaTest");
|
||
|
|
||
|
Vector v;
|
||
|
v.x = 1; v.y = 2; v.z = 0; v.w = 0;
|
||
|
ZZcgSetParameter4fv(sOneColor, v, "g_fOneColor");
|
||
|
|
||
|
// 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;
|
||
|
ZZcgSetParameter4fv(sOneColor, v, "g_fOneColor");
|
||
|
glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], AlphaReferedValue(curvb.test.aref));
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline 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();
|
||
|
}
|
||
|
|
||
|
inline 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);
|
||
|
SetShaderCaller("ProcessStencil");
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
SetShaderCaller("ProcessFBA");
|
||
|
|
||
|
// 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;
|
||
|
ZZcgSetParameter4fv(sOneColor, &f, "g_fOneColor");
|
||
|
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], AlphaReferedValue(curvb.test.aref));
|
||
|
}
|
||
|
|
||
|
// 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);
|
||
|
}
|
||
|
|
||
|
void ZeroGS::SetContextTarget(int context)
|
||
|
{
|
||
|
FUNCLOG
|
||
|
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) {
|
||
|
* printf ( " Here\n ");
|
||
|
* 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::SetTexInt (int context, FRAGMENTSHADER* pfragment, int settexint ) {
|
||
|
FUNCLOG
|
||
|
if (settexint) {
|
||
|
tex0Info& tex0 = vb[context].tex0;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// clamp relies on texture width
|
||
|
void ZeroGS::SetTexClamping(int context, FRAGMENTSHADER* pfragment ) {
|
||
|
FUNCLOG
|
||
|
SetShaderCaller("SetTexClamping");
|
||
|
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;
|
||
|
v2.x = (float)GPU_TEXMASKWIDTH / fw;
|
||
|
v2.z = pclamp->maxu / fw;
|
||
|
int correctMinu = pclamp->minu & (~pclamp->maxu); // (A && B) || C == (A && (B && !C)) + C
|
||
|
|
||
|
if( correctMinu != g_PrevBitwiseTexX ) {
|
||
|
g_PrevBitwiseTexX = correctMinu;
|
||
|
ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(correctMinu, 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;
|
||
|
v2.y = (float)GPU_TEXMASKWIDTH / fh;
|
||
|
v2.w = pclamp->maxv / fh;
|
||
|
int correctMinv = pclamp->minv & (~pclamp->maxv); // (A && B) || C == (A && (B && !C)) + C
|
||
|
|
||
|
if( correctMinv != g_PrevBitwiseTexY ) {
|
||
|
g_PrevBitwiseTexY = correctMinv;
|
||
|
ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(correctMinv, ptex[0]);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( pfragment->fTexWrapMode != 0 )
|
||
|
ZZcgSetParameter4fv(pfragment->fTexWrapMode, v, "g_fTexWrapMode");
|
||
|
if( pfragment->fClampExts != 0 )
|
||
|
ZZcgSetParameter4fv(pfragment->fClampExts, v2, "g_fClampExts");
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
// Fixme should be in Vector lib
|
||
|
inline bool equal_vectors( Vector a, Vector b){
|
||
|
if ( abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w) < 0.01 )
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int CheckTexArray[4][2][2][2] = {{{{0,}}}};
|
||
|
void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment ) {
|
||
|
FUNCLOG
|
||
|
if (!vb[context].curprim.tme) return;
|
||
|
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 ) {
|
||
|
SetShaderCaller("SetTexVariables");
|
||
|
|
||
|
// alpha and texture highlighting
|
||
|
Vector valpha, valpha2 ;
|
||
|
|
||
|
// if clut, use the frame format
|
||
|
int psm = GetTexCPSM(tex0);
|
||
|
|
||
|
// printf ( "A %d psm, is-clut %d. cpsm %d | %d %d\n", psm, PSMT_ISCLUT(psm), tex0.cpsm, tex0.tfx, tex0.tcc );
|
||
|
|
||
|
Vector vblack;
|
||
|
vblack.x = vblack.y = vblack.z = vblack.w = 10;
|
||
|
|
||
|
/* tcc -- Tecture Color Component 0=RGB, 1=RGBA + use Alpha from TEXA reg when not in PSM
|
||
|
* tfx -- Texture Function (0=modulate, 1=decal, 2=hilight, 3=hilight2)
|
||
|
*
|
||
|
* valpha2 = 0 0 2 1 0 0 2 1
|
||
|
* 1 0 0 0 1 1 0 0
|
||
|
* 0 0 2 0 0 1 2 0
|
||
|
* 0 0 2 0 0 1 2 0
|
||
|
*
|
||
|
* 0 1,!nNeed 1, psm=2, 10 1, psm=1
|
||
|
* valpha = 0 0 0 1 0 2 0 0 2ta0 2ta1-2ta0 0 0 2ta0 0 0 0
|
||
|
* 0 0 0 1 0 1 0 0 ta0 ta1-ta0 0 0 ta0 0 0 0
|
||
|
* 0 0 1 1 0 1 1 1 1 1 ta0 0 1 1
|
||
|
* 0 0 1 1 0 1 1 0 1 0 ta0 0 1 0
|
||
|
*/
|
||
|
|
||
|
valpha2.x = ( tex0.tfx == 1 ) ;
|
||
|
valpha2.y = ( tex0.tcc == 1 ) && ( tex0.tfx != 0 ) ;
|
||
|
valpha2.z = ( tex0.tfx != 1 ) * 2 ;
|
||
|
valpha2.w = ( tex0.tfx == 0 ) ;
|
||
|
|
||
|
if ( tex0.tcc == 0 || !nNeedAlpha(psm) ) {
|
||
|
valpha.x = 0 ;
|
||
|
valpha.y = ( !!tex0.tcc ) * ( 1 + ( tex0.tfx == 0) ) ; }
|
||
|
else {
|
||
|
valpha.x = ( gs.texa.fta[0] ) * ( 1 + ( tex0.tfx == 0) ) ;
|
||
|
valpha.y = ( gs.texa.fta[psm!=1] - gs.texa.fta[0] ) * ( 1 + ( tex0.tfx == 0) ) ;
|
||
|
}
|
||
|
|
||
|
valpha.z = ( tex0.tfx >= 3 ) ;
|
||
|
valpha.w = ( tex0.tcc == 0 ) || ( tex0.tcc == 1 && tex0.tfx == 2 ) ;
|
||
|
|
||
|
if( tex0.tcc && gs.texa.aem && psm == PSMCT24 )
|
||
|
vblack.w = 0;
|
||
|
/*
|
||
|
// Test, old code.
|
||
|
Vector valpha3, valpha4;
|
||
|
switch(tex0.tfx) {
|
||
|
case 0:
|
||
|
valpha3.z = 0; valpha3.w = 0;
|
||
|
valpha4.x = 0; valpha4.y = 0;
|
||
|
valpha4.z = 2; valpha4.w = 1;
|
||
|
|
||
|
break;
|
||
|
case 1:
|
||
|
valpha3.z = 0; valpha3.w = 1;
|
||
|
valpha4.x = 1; valpha4.y = 0;
|
||
|
valpha4.z = 0; valpha4.w = 0;
|
||
|
|
||
|
break;
|
||
|
case 2:
|
||
|
valpha3.z = 1; valpha3.w = 1.0f;
|
||
|
valpha4.x = 0; valpha4.y = tex0.tcc ? 1.0f : 0.0f;
|
||
|
valpha4.z = 2; valpha4.w = 0;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
valpha3.z = 1; valpha3.w = tex0.tcc ? 0.0f : 1.0f;
|
||
|
valpha4.x = 0; valpha4.y = tex0.tcc ? 1.0f : 0.0f;
|
||
|
valpha4.z = 2; valpha4.w = 0;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
if( tex0.tcc ) {
|
||
|
|
||
|
if( tex0.tfx == 1 ) {
|
||
|
//mode.x = 10;
|
||
|
valpha3.z = 0; valpha3.w = 0;
|
||
|
valpha4.x = 1; valpha4.y = 1;
|
||
|
valpha4.z = 0; valpha4.w = 0;
|
||
|
}
|
||
|
|
||
|
if( nNeedAlpha(psm) ) {
|
||
|
|
||
|
if( tex0.tfx == 0 ) {
|
||
|
// make sure alpha is mult by two when the output is Cv = Ct*Cf
|
||
|
valpha3.x = 2*gs.texa.fta[0];
|
||
|
// if 24bit, always choose ta[0]
|
||
|
valpha3.y = 2*gs.texa.fta[psm != 1];
|
||
|
valpha3.y -= valpha.x;
|
||
|
}
|
||
|
else {
|
||
|
valpha3.x = gs.texa.fta[0];
|
||
|
// if 24bit, always choose ta[0]
|
||
|
valpha3.y = gs.texa.fta[psm != 1];
|
||
|
valpha3.y -= valpha.x;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if( tex0.tfx == 0 ) {
|
||
|
valpha3.x = 0;
|
||
|
valpha3.y = 2;
|
||
|
}
|
||
|
else {
|
||
|
valpha3.x = 0;
|
||
|
valpha3.y = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
// reset alpha to color
|
||
|
valpha3.x = valpha3.y = 0;
|
||
|
valpha3.w = 1;
|
||
|
}
|
||
|
|
||
|
if ( equal_vectors(valpha, valpha3) && equal_vectors(valpha2, valpha4) ) {
|
||
|
if (CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm)] == 0) {
|
||
|
printf ( "Good issue %d %d %d %d\n", tex0.tfx, tex0.tcc, psm, nNeedAlpha(psm) );
|
||
|
CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm) ] = 1;
|
||
|
}
|
||
|
}
|
||
|
else if (CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm)] == -1) {
|
||
|
printf ("Bad array, %d %d %d %d\n\tolf valpha %f, %f, %f, %f : valpha2 %f %f %f %f\n\tnew valpha %f, %f, %f, %f : valpha2 %f %f %f %f\n",
|
||
|
tex0.tfx, tex0.tcc, psm, nNeedAlpha(psm),
|
||
|
valpha3.x, valpha3.y, valpha3.z, valpha3.w, valpha4.x, valpha4.y, valpha4.z, valpha4.w,
|
||
|
valpha.x, valpha.y, valpha.z, valpha.w, valpha2.x, valpha2.y, valpha2.z, valpha2.w);
|
||
|
CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm)] = -1 ;
|
||
|
}
|
||
|
|
||
|
// Test;*/
|
||
|
|
||
|
ZZcgSetParameter4fv(pfragment->fTexAlpha, valpha, "g_fTexAlpha");
|
||
|
ZZcgSetParameter4fv(pfragment->fTexAlpha2, valpha2, "g_fTexAlpha2");
|
||
|
if(tex0.tcc && gs.texa.aem && nNeedAlpha(psm))
|
||
|
ZZcgSetParameter4fv(pfragment->fTestBlack, vblack, "g_fTestBlack");
|
||
|
|
||
|
SetTexClamping(context, pfragment);
|
||
|
vb[context].bTexConstsSync = TRUE;
|
||
|
}
|
||
|
|
||
|
if(s_bTexFlush ) {
|
||
|
if( PSMT_ISCLUT(tex0.psm) )
|
||
|
texClutWrite(context);
|
||
|
else
|
||
|
s_bTexFlush = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force) {
|
||
|
FUNCLOG
|
||
|
Vector v;
|
||
|
assert( pmemtarg != NULL && pfragment != NULL && pmemtarg->ptex != NULL);
|
||
|
|
||
|
if (pmemtarg == NULL || pfragment == NULL || pmemtarg->ptex == NULL )
|
||
|
{
|
||
|
printf ("SetTexVariablesInt error\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SetShaderCaller("SetTexVariablesInt");
|
||
|
|
||
|
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)
|
||
|
ZZcgSetParameter4fv(pfragment->fRealTexDims, v, "g_fRealTexDims");
|
||
|
else
|
||
|
ZZcgSetParameter4fv(cgGetNamedParameter(pfragment->prog,"g_fRealTexDims"),v, "g_fRealTexDims");
|
||
|
}
|
||
|
|
||
|
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.1f / 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;
|
||
|
|
||
|
float fblockstride = (2048.0f /(float)(GPU_TEXWIDTH*(float)pmemtarg->widthmult*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);
|
||
|
}
|
||
|
|
||
|
ZZcgSetParameter4fv(pfragment->fTexDims, vTexDims, "g_fTexDims");
|
||
|
// ZZcgSetParameter4fv(pfragment->fTexBlock, b.vTexBlock, "g_fTexBlock"); // I change it, and it's working. Seems casting from Vector to float[4] is ok.
|
||
|
ZZcgSetParameter4fv(pfragment->fTexBlock, &b.vTexBlock.x, "g_fTexBlock");
|
||
|
ZZcgSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset");
|
||
|
|
||
|
// get hardware texture dims
|
||
|
int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult;
|
||
|
int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels;
|
||
|
|
||
|
v.y = 1.0f;
|
||
|
v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f);//*v.y;
|
||
|
v.z = (float)texwidth;
|
||
|
|
||
|
/* if( !(g_nPixelShaderVer & SHADER_ACCURATE) || bUseBilinear ) {
|
||
|
if (tex0.psm == PSMT4 )
|
||
|
v.w = 0.0f;
|
||
|
else
|
||
|
v.w = 0.25f;
|
||
|
}
|
||
|
else
|
||
|
v.w = 0.5f;*/
|
||
|
v.w = 0.5f;
|
||
|
|
||
|
ZZcgSetParameter4fv(pfragment->fPageOffset, v, "g_fPageOffset");
|
||
|
|
||
|
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(PSMT_BITMODE(vb[icurctx].prndr->psm)) \
|
||
|
{ \
|
||
|
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() {
|
||
|
FUNCLOG
|
||
|
}
|
||
|
|
||
|
inline void ZeroGS::NeedFactor( int w ) {
|
||
|
if (bDestAlphaColor == 2){
|
||
|
bNeedBlendFactorInAlpha = (w+1) ? 1 : 0;
|
||
|
vAlphaBlendColor.y = 0;
|
||
|
vAlphaBlendColor.w = (float)w;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int CheckArray[48][2] = {{0,}};
|
||
|
|
||
|
void ZeroGS::SetAlphaVariables(const alphaInfo& a)
|
||
|
{
|
||
|
FUNCLOG
|
||
|
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;
|
||
|
bDestAlphaColor = 0;
|
||
|
|
||
|
// default
|
||
|
s_srcalpha = GL_ONE;
|
||
|
s_dstalpha = GL_ZERO;
|
||
|
s_alphaeq = GL_FUNC_ADD;
|
||
|
s_rgbeq = 1;
|
||
|
|
||
|
s_alphaInfo = a;
|
||
|
vAlphaBlendColor = Vector(1,2*255.0f/256.0f,0,0);
|
||
|
u32 usec = a.c;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Alpha table
|
||
|
* a + b + d
|
||
|
* S D
|
||
|
* 0 a -a 1 | 0 0 0
|
||
|
* 1 0 0 0 | a -a 1
|
||
|
* 2 0 0 0 | 0 0 0
|
||
|
*
|
||
|
* d = 0 Cs
|
||
|
* a b 0 Cs 1 Cd 2 0
|
||
|
* | |
|
||
|
* 0 000: a+-a+ 1 | 0+ 0+ 0 = 1 | 010: a+ 0+ 1 | 0+-a+ 0 = 1-(-a)(+)(-a) | 020: a+ 0+ 1 | 0+ 0+ 0 = 1-(-a) (+) 0
|
||
|
* 1 100: 0+-a+ 1 | a+ 0+ 0 = 1-a (+) a | 110: 0+ 0+ 1 | a+-a+ 0 = 1 | 120: 0+ 0+ 1 | a+ 0+ 0 = 1 (+) a
|
||
|
* 2 200: 0+-a+ 1 | 0+ 0+ 0 = 1-a (+) 0 | 210: 0+ 0+ 1 | 0+-a+ 0 = 1 (-) a | 220: 0+ 0+ 1 | 0+ 0+ 0 = 1
|
||
|
*
|
||
|
* d = 1 Cd
|
||
|
* 0 | 1 | 2
|
||
|
* 0 001: a+-a+ 0 | 0+ 0+ 1 = 0 (+) 1 | 011: a+ 0+ 0 | 0+-a+ 1 = a (+) 1-a | 021: a+ 0+ 0 | 0+ 0+ 1 = a (+) 1
|
||
|
* 1 101: 0+-a+ 0 | a+ 0+ 1 = (-a)(+) 1-(-a) | 111: 0+ 0+ 0 | a+-a+ 1 = 0 (+) 1 | 121: 0+ 0+ 0 | a+ 0+ 1 = 0 (+) 1-(-a)
|
||
|
* 2 201: 0+-a+ 0 | 0+ 0+ 1 = a (R-)1 | 211: 0+ 0+ 0 | 0+-a+ 1 = 0 (+) 1-a | 221: 0+ 0+ 0 | 0+ 0+ 1 = 0 (+) 1
|
||
|
*
|
||
|
* d = 2 0
|
||
|
* 0 | 1 | 2
|
||
|
* 0 002: a+-a+ 0 | 0+ 0+ 0 = 0 | 012: a+ 0+ 0 | 0+-a+ 0 = a (-) a | 022: a+ 0+ 0 | 0+ 0+ 0 = a (+) 0
|
||
|
* 1 102: 0+-a+ 0 | a+ 0+ 0 = a (R-) a | 112: 0+ 0+ 0 | a+-a+ 0 = 0 | 122: 0+ 0+ 0 | a+ 0+ 0 = 0 (+) a
|
||
|
* 2 202: 0+-a+ 0 | 0+ 0+ 0 = a (R-) 0 | 212: 0+ 0+ 0 | 0+-a+ 0 = 0 (-) a | 222: 0+ 0+ 0 | 0+ 0+ 0 = 0
|
||
|
*
|
||
|
* Formulae is: (a-b) * (c /32) + d
|
||
|
* 0 1 2
|
||
|
* a Cs Cd 0
|
||
|
* b Cs Cd 0
|
||
|
* c As Ad ALPHA.FIX
|
||
|
* d Cs Cd 0
|
||
|
*
|
||
|
* We want to emulate Cs * F1(alpha) + Cd * F2(alpha) by OpenGl blending: (Cs * Ss (+,-,R-) Cd * Sd)
|
||
|
* SET_ALPHA_COLOR_FACTOR(sign) set Set A (as As>>7, Ad>>7 or FIX>>7) with sign.
|
||
|
* So we could use 1+a as one_minus_alpha and -a as alpha.
|
||
|
*
|
||
|
*/
|
||
|
int code = ( a.a * 16 ) + ( a.b * 4 ) + a.d ;
|
||
|
|
||
|
#define one_minus_alpha (bDestAlphaColor == 2) ? GL_ONE_MINUS_SRC_ALPHA : blendinvalpha[usec]
|
||
|
#define alpha (bDestAlphaColor == 2) ? GL_SRC_ALPHA : blendalpha[usec]
|
||
|
#define one (bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec]
|
||
|
#define zero (bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec]
|
||
|
|
||
|
switch (code)
|
||
|
{
|
||
|
case 0: // 000 // Cs -- nothing changed
|
||
|
case 20: // 110 = 16+4=20 // Cs
|
||
|
case 40: { // 220 = 32+8=40 // Cs
|
||
|
alphaenable = false;
|
||
|
break;
|
||
|
}
|
||
|
case 2: //002 // 0 -- should be zero
|
||
|
case 22: //112 // 0
|
||
|
case 42: { //222 = 32+8+2 =42 // 0
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = GL_ZERO;
|
||
|
s_dstrgb = GL_ZERO;
|
||
|
break;
|
||
|
}
|
||
|
case 1: //001 // Cd -- Should be destination alpha
|
||
|
case 21: //111, // Cd -- 0*Source + 1*Desrinarion
|
||
|
case 41: { //221 = 32+8+1=41 // Cd --
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = GL_ZERO;
|
||
|
s_dstrgb = GL_ONE;
|
||
|
break;
|
||
|
}
|
||
|
case 4: { // 010 // (Cs-Cd)*A+Cs = Cs * (A + 1) - Cd * A
|
||
|
bAlphaClamping = 3;
|
||
|
SET_ALPHA_COLOR_FACTOR(0); // a = -A
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD; // Cs*(1-a)+Cd*a
|
||
|
s_srcrgb = one_minus_alpha ;
|
||
|
s_dstrgb = alpha;
|
||
|
|
||
|
NeedFactor(-1);
|
||
|
break;
|
||
|
}
|
||
|
case 5: { // 011 // (Cs-Cd)*A+Cs = Cs * A + Cd * (1-A)
|
||
|
bAlphaClamping = 3; // all testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = alpha;
|
||
|
s_dstrgb = one_minus_alpha;
|
||
|
|
||
|
NeedFactor(1);
|
||
|
break;
|
||
|
}
|
||
|
case 6: { //012 // (Cs-Cd)*FIX
|
||
|
bAlphaClamping = 3;
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_SUBTRACT;
|
||
|
s_srcrgb = alpha;
|
||
|
s_dstrgb = alpha;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case 8: { //020 // Cs*A+Cs = Cs * (1+A)
|
||
|
bAlphaClamping = 2; // max testing
|
||
|
SET_ALPHA_COLOR_FACTOR(0); // Zeyflitz change this! a = -A
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = one_minus_alpha; // Cs*(1-a).
|
||
|
s_dstrgb = GL_ZERO;
|
||
|
|
||
|
// NeedFactor(1);
|
||
|
break;
|
||
|
}
|
||
|
case 9: { //021 // Cs*A+Cd
|
||
|
bAlphaClamping = 2; // max testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = alpha; // ZZ change it to.
|
||
|
s_dstrgb = GL_ONE;
|
||
|
break;
|
||
|
}
|
||
|
case 10: { //022 // Cs*A
|
||
|
bAlphaClamping = 2; // max testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = alpha;
|
||
|
s_dstrgb = GL_ZERO;
|
||
|
break;
|
||
|
}
|
||
|
case 16: { //100
|
||
|
bAlphaClamping = 3;
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = one_minus_alpha;
|
||
|
s_dstrgb = alpha;
|
||
|
|
||
|
NeedFactor(1);
|
||
|
break;
|
||
|
}
|
||
|
case 17: { //101
|
||
|
bAlphaClamping = 3; // all testing
|
||
|
SET_ALPHA_COLOR_FACTOR(0);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = alpha;
|
||
|
s_dstrgb = one_minus_alpha;
|
||
|
|
||
|
NeedFactor(-1);
|
||
|
break;
|
||
|
}
|
||
|
case 18: { //102
|
||
|
bAlphaClamping = 3;
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_REVERSE_SUBTRACT;
|
||
|
s_srcrgb = alpha;
|
||
|
s_dstrgb = alpha;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case 24: { //120 = 16+8
|
||
|
bAlphaClamping = 2; // max testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = GL_ONE;
|
||
|
s_dstrgb = alpha;
|
||
|
break;
|
||
|
}
|
||
|
case 25: { //121 // Cd*(1+A)
|
||
|
bAlphaClamping = 2; // max testing
|
||
|
SET_ALPHA_COLOR_FACTOR(0);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = GL_ZERO;
|
||
|
s_dstrgb = one_minus_alpha;
|
||
|
|
||
|
// NeedFactor(-1);
|
||
|
break;
|
||
|
}
|
||
|
case 26: { //122
|
||
|
bAlphaClamping = 2;
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = GL_ZERO;
|
||
|
s_dstrgb = alpha;
|
||
|
break;
|
||
|
}
|
||
|
case 32: {// 200 = 32
|
||
|
bAlphaClamping = 1; // min testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = one_minus_alpha;
|
||
|
s_dstrgb = GL_ZERO;
|
||
|
break;
|
||
|
}
|
||
|
case 33: {//201 // -Cs*A + Cd
|
||
|
bAlphaClamping = 1; // min testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_REVERSE_SUBTRACT;
|
||
|
s_srcrgb = alpha;
|
||
|
s_dstrgb = GL_ONE;
|
||
|
break;
|
||
|
}
|
||
|
case 34: //202
|
||
|
case 38: {//212
|
||
|
bAlphaClamping = 1; // min testing -- negative values
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = GL_ZERO;
|
||
|
s_dstrgb = GL_ZERO;
|
||
|
break;
|
||
|
}
|
||
|
case 36: {//210
|
||
|
bAlphaClamping = 1; // min testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_SUBTRACT;
|
||
|
s_srcrgb = GL_ONE;
|
||
|
s_dstrgb = alpha;
|
||
|
break;
|
||
|
}
|
||
|
case 37: {//211
|
||
|
bAlphaClamping = 1; // min testing
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
s_rgbeq = GL_FUNC_ADD;
|
||
|
s_srcrgb = GL_ZERO;
|
||
|
s_dstrgb = one_minus_alpha;
|
||
|
break;
|
||
|
}
|
||
|
default: {
|
||
|
ERROR_LOG ( "Bad alpha code %d | %d %d %d\n", code, a.a, a.b, a.d );
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
int t_rgbeq = GL_FUNC_ADD;
|
||
|
int t_srcrgb = GL_ONE;
|
||
|
int t_dstrgb = GL_ZERO;
|
||
|
int tAlphaClamping = 0;
|
||
|
|
||
|
if( a.a == a.b )
|
||
|
{ // just d remains
|
||
|
if( a.d == 0 ) {}
|
||
|
else
|
||
|
{
|
||
|
t_dstrgb = a.d == 1 ? GL_ONE : GL_ZERO;
|
||
|
t_srcrgb = GL_ZERO;
|
||
|
t_rgbeq = GL_FUNC_ADD; //a) (001) (111) (221) b) (002) (112) (222)
|
||
|
}
|
||
|
goto EndSetAlpha;
|
||
|
}
|
||
|
else if( a.d == 2 )
|
||
|
{ // zero
|
||
|
if( a.a == 2 )
|
||
|
{
|
||
|
// zero all color
|
||
|
t_srcrgb = GL_ZERO;
|
||
|
t_dstrgb = GL_ZERO;
|
||
|
goto EndSetAlpha; // (202) (212)
|
||
|
}
|
||
|
else if( a.b == 2 )
|
||
|
{
|
||
|
//b2XAlphaTest = 1; // a) (022) // b) (122)
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
if( bDestAlphaColor == 2 )
|
||
|
{
|
||
|
t_rgbeq = GL_FUNC_ADD;
|
||
|
t_srcrgb = a.a == 0 ? GL_ONE : GL_ZERO;
|
||
|
t_dstrgb = a.a == 0 ? GL_ZERO : GL_ONE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tAlphaClamping = 2;
|
||
|
t_rgbeq = GL_FUNC_ADD;
|
||
|
t_srcrgb = a.a == 0 ? blendalpha[usec] : GL_ZERO;
|
||
|
t_dstrgb = a.a == 0 ? GL_ZERO : blendalpha[usec];
|
||
|
}
|
||
|
|
||
|
goto EndSetAlpha;
|
||
|
}
|
||
|
|
||
|
// nothing is zero, so must do some real blending //b2XAlphaTest = 1; //a) (012) //b) (102)
|
||
|
tAlphaClamping = 3;
|
||
|
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
t_rgbeq = a.a == 0 ? GL_FUNC_SUBTRACT : GL_FUNC_REVERSE_SUBTRACT;
|
||
|
t_srcrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec];
|
||
|
t_dstrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec];
|
||
|
}
|
||
|
else if( a.a == 2 )
|
||
|
{ // zero
|
||
|
|
||
|
//b2XAlphaTest = 1;
|
||
|
tAlphaClamping = 1; // min testing
|
||
|
|
||
|
SET_ALPHA_COLOR_FACTOR(1);
|
||
|
|
||
|
if( a.b == a.d )
|
||
|
{
|
||
|
// can get away with 1-A
|
||
|
// a.a == a.d == 2!! (200) (211)
|
||
|
t_rgbeq = GL_FUNC_ADD;
|
||
|
t_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : GL_ZERO;
|
||
|
t_dstrgb = (a.b == 0 || bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// a) (201) b)(210)
|
||
|
t_rgbeq = a.b==0 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_SUBTRACT;
|
||
|
t_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE;
|
||
|
t_dstrgb = (a.b == 0 || bDestAlphaColor == 2 ) ? GL_ONE : blendalpha[usec];
|
||
|
}
|
||
|
}
|
||
|
else if( a.b == 2 )
|
||
|
{
|
||
|
tAlphaClamping = 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
|
||
|
// a)(020)
|
||
|
// b)(121)
|
||
|
t_rgbeq = GL_FUNC_ADD;
|
||
|
|
||
|
if( bDestAlphaColor == 2 )
|
||
|
{
|
||
|
t_srcrgb = (a.a == 0) ? GL_ONE_MINUS_SRC_ALPHA : GL_ZERO;
|
||
|
t_dstrgb = (a.a == 0) ? GL_ZERO : GL_ONE_MINUS_SRC_ALPHA;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
t_srcrgb = a.a == 0 ? blendinvalpha[usec] : GL_ZERO;
|
||
|
t_dstrgb = a.a == 0 ? GL_ZERO : blendinvalpha[usec];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//a)(021) //b)(120) //b2XAlphaTest = 1;
|
||
|
t_rgbeq = GL_FUNC_ADD;
|
||
|
t_srcrgb = (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE;
|
||
|
t_dstrgb = (a.a == 0 || bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// all 3 components are valid!
|
||
|
tAlphaClamping = 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 // a) 010, // b) 101
|
||
|
t_rgbeq = GL_FUNC_ADD;
|
||
|
|
||
|
if( bDestAlphaColor == 2 )
|
||
|
{
|
||
|
// all ones
|
||
|
t_srcrgb = a.a == 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA;
|
||
|
t_dstrgb = a.a == 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
t_srcrgb = a.a == 0 ? blendinvalpha[usec] : blendalpha[usec];
|
||
|
t_dstrgb = a.a == 0 ? blendalpha[usec] : blendinvalpha[usec];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
t_rgbeq = GL_FUNC_ADD; // a) 011 // b) 100 //
|
||
|
if( bDestAlphaColor == 2 )
|
||
|
{
|
||
|
// all ones
|
||
|
t_srcrgb = a.a != 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA;
|
||
|
t_dstrgb = a.a != 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//b2XAlphaTest = 1;
|
||
|
t_srcrgb = a.a != 0 ? blendinvalpha[usec] : blendalpha[usec];
|
||
|
t_dstrgb = a.a != 0 ? blendalpha[usec] : blendinvalpha[usec];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
EndSetAlpha:
|
||
|
|
||
|
|
||
|
if ( alphaenable && (t_rgbeq != s_rgbeq || s_srcrgb != t_srcrgb || t_dstrgb != s_dstrgb || tAlphaClamping != bAlphaClamping)) {
|
||
|
if (CheckArray[code][(bDestAlphaColor==2)] != -1) {
|
||
|
printf ( "A code %d, 0x%x, 0x%x, 0x%x, 0x%x %d\n", code, alpha, one_minus_alpha, one, zero, bDestAlphaColor );
|
||
|
printf ( " Difference %d %d %d %d | 0x%x 0x%x | 0x%x 0x%x | 0x%x 0x%x | %d %d\n",
|
||
|
code, a.a, a.b, a.d,
|
||
|
t_rgbeq, s_rgbeq, t_srcrgb, s_srcrgb, t_dstrgb, s_dstrgb, tAlphaClamping, bAlphaClamping);
|
||
|
CheckArray[code][(bDestAlphaColor==2)] = -1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (CheckArray[code][(bDestAlphaColor==2)] == 0){
|
||
|
printf ( "Add good code %d %d, psm %d destA %d\n", code, a.c, vb[icurctx].prndr->psm, bDestAlphaColor);
|
||
|
CheckArray[code][(bDestAlphaColor==2)] = 1;
|
||
|
}*/
|
||
|
|
||
|
|
||
|
if( alphaenable ) {
|
||
|
zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha);
|
||
|
zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq);
|
||
|
glEnable(GL_BLEND); // always set
|
||
|
}
|
||
|
else
|
||
|
glDisable(GL_BLEND);
|
||
|
|
||
|
INC_ALPHAVARS();
|
||
|
}
|
||
|
|
||
|
void ZeroGS::SetWriteDepth() {
|
||
|
FUNCLOG
|
||
|
if( conf.mrtdepth ) {
|
||
|
s_bWriteDepth = TRUE;
|
||
|
s_nWriteDepthCount = 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ZeroGS::IsWriteDepth() {
|
||
|
FUNCLOG
|
||
|
return s_bWriteDepth;
|
||
|
}
|
||
|
|
||
|
bool ZeroGS::IsWriteDestAlphaTest() {
|
||
|
FUNCLOG
|
||
|
return s_bDestAlphaTest;
|
||
|
}
|
||
|
|
||
|
void ZeroGS::SetDestAlphaTest() {
|
||
|
FUNCLOG
|
||
|
s_bDestAlphaTest = TRUE;
|
||
|
s_nWriteDestAlphaTest = 4;
|
||
|
}
|
||
|
|
||
|
void ZeroGS::SetTexFlush() {
|
||
|
FUNCLOG
|
||
|
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];
|
||
|
}
|
||
|
}
|
||
|
|