/[pcsx2_0.9.7]/trunk/plugins/zzogl-pg/opengl/ZZoglFlush.cpp
ViewVC logotype

Contents of /trunk/plugins/zzogl-pg/opengl/ZZoglFlush.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 10 months ago) by william
File size: 76029 byte(s)
committing r3113 initial commit again...
1 /* ZZ Open GL graphics plugin
2 * Copyright (c)2009 zeydlitz@gmail.com
3 * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2006
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 // Realisation of Flush -- drawing function of GS
21
22 #include <stdlib.h>
23
24 #include "GS.h"
25 #include "Mem.h"
26 #include "zerogs.h"
27 #include "targets.h"
28
29 using namespace ZeroGS;
30
31 //------------------ Defines
32 #ifndef DEVBUILD
33
34 #define INC_GENVARS()
35 #define INC_TEXVARS()
36 #define INC_ALPHAVARS()
37 #define INC_RESOLVE()
38
39 #define g_bUpdateEffect 0
40 #define g_bSaveTex 0
41 bool g_bSaveTrans = 0;
42 #define g_bSaveResolved 0
43
44 #else // defined(ZEROGS_DEVBUILD)
45
46 #define INC_GENVARS() ++g_nGenVars
47 #define INC_TEXVARS() ++g_nTexVars
48 #define INC_ALPHAVARS() ++g_nAlphaVars
49 #define INC_RESOLVE() ++g_nResolve
50
51 bool g_bSaveTrans = 0;
52 bool g_bUpdateEffect = 0;
53 bool g_bSaveTex = 0; // saves the curent texture
54 bool g_bSaveResolved = 0;
55 #endif // !defined(ZEROGS_DEVBUILD)
56
57 #define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80
58 #define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush)
59 #define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush)
60 #define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush)
61 //#define STENCIL_PBE 16
62 #define STENCIL_CLEAR (2|4|8|16)
63
64 #define DRAW() glDrawArrays(primtype[curvb.curprim.prim], 0, curvb.nCount)
65
66 #define GL_BLEND_RGB(src, dst) { \
67 s_srcrgb = src; \
68 s_dstrgb = dst; \
69 zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \
70 }
71
72 #define GL_BLEND_ALPHA(src, dst) { \
73 s_srcalpha = src; \
74 s_dstalpha = dst; \
75 zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \
76 }
77
78 #define GL_BLEND_ALL(srcrgb, dstrgb, srcalpha, dstalpha) { \
79 s_srcrgb = srcrgb; \
80 s_dstrgb = dstrgb; \
81 s_srcalpha = srcalpha; \
82 s_dstalpha = dstalpha; \
83 zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \
84 }
85
86 #define GL_ZTEST(enable) { \
87 if (enable) glEnable(GL_DEPTH_TEST); \
88 else glDisable(GL_DEPTH_TEST); \
89 }
90
91 #define GL_ALPHATEST(enable) { \
92 if( enable ) glEnable(GL_ALPHA_TEST); \
93 else glDisable(GL_ALPHA_TEST); \
94 }
95
96 #define GL_BLENDEQ_RGB(eq) { \
97 s_rgbeq = eq; \
98 zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \
99 }
100
101 #define GL_BLENDEQ_ALPHA(eq) { \
102 s_alphaeq = eq; \
103 zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \
104 }
105
106 #define COLORMASK_RED 1
107 #define COLORMASK_GREEN 2
108 #define COLORMASK_BLUE 4
109 #define COLORMASK_ALPHA 8
110 #define GL_COLORMASK(mask) glColorMask(!!((mask)&COLORMASK_RED), !!((mask)&COLORMASK_GREEN), !!((mask)&COLORMASK_BLUE), !!((mask)&COLORMASK_ALPHA))
111
112 // ----------------- Types
113 //------------------ Dummies
114
115 //------------------ variables
116
117 extern bool g_bIsLost;
118 bool g_bUpdateStencil = 1;
119 u32 g_SaveFrameNum = 0; // ZZ
120
121 int GPU_TEXWIDTH = 512;
122 float g_fiGPU_TEXWIDTH = 1 / 512.0f;
123
124 extern CGprogram g_psprog; // 2 -- ZZ
125
126 // local alpha blending settings
127 static GLenum s_rgbeq, s_alphaeq; // set by zgsBlendEquationSeparateEXT // ZZ
128
129
130 static const u32 blendalpha[3] = { GL_SRC_ALPHA, GL_DST_ALPHA, GL_CONSTANT_COLOR_EXT }; // ZZ
131 static const u32 blendinvalpha[3] = { GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR_EXT }; //ZZ
132 static const u32 g_dwAlphaCmp[] = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL }; // ZZ
133
134 // used for afail case
135 static const u32 g_dwReverseAlphaCmp[] = { GL_ALWAYS, GL_NEVER, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL, GL_LESS, GL_LEQUAL, GL_EQUAL };
136 static const u32 g_dwZCmp[] = { GL_NEVER, GL_ALWAYS, GL_GEQUAL, GL_GREATER };
137
138 /////////////////////
139 // graphics resources
140 #define s_bForceTexFlush 1 // ZZ
141 u32 s_ptexCurSet[2] = {0};
142 static u32 s_ptexNextSet[2] = {0}; // ZZ
143
144 vector<u32> s_vecTempTextures; // temporary textures, released at the end of every frame
145
146 extern bool s_bTexFlush;
147 bool s_bWriteDepth = false;
148 bool s_bDestAlphaTest = false;
149 int s_ClutResolve = 0; // ZZ
150 int g_nDepthUsed = 0; // ffx2 pal movies
151 int s_nWriteDepthCount = 0; // ZZ
152 int s_nWriteDestAlphaTest = 0; // ZZ
153
154 ////////////////////
155 // State parameters
156 static Vector vAlphaBlendColor; // used for GPU_COLOR
157
158 static u8 bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80)
159 static u32 s_dwColorWrite = 0xf; // the color write mask of the current target
160
161 union
162 {
163
164 struct
165 {
166 u8 _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set
167 u8 _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values
168 // otherwise alpha testing needs to be done separately.
169 u8 _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1.
170 u8 _bAlphaClamping; // if first bit is set, do min; if second bit, do max
171 };
172
173 u32 _bAlphaState;
174 } g_vars;
175
176 //#define bNeedAlphaColor g_vars._bNeedAlphaColor
177 #define b2XAlphaTest g_vars._b2XAlphaTest
178 #define bDestAlphaColor g_vars._bDestAlphaColor
179 #define bAlphaClamping g_vars._bAlphaClamping
180
181 int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY // ZZ
182
183 static alphaInfo s_alphaInfo; // ZZ
184
185 extern u8* g_pbyGSClut;
186
187 //------------------ Namespace
188
189 namespace ZeroGS
190 {
191
192 VB vb[2];
193 float fiTexWidth[2], fiTexHeight[2]; // current tex width and height
194
195 u8 s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set
196 u8 s_AAz = 0, s_AAw = 0; // if AAy is set, then AAx has to be set
197
198 int icurctx = -1;
199
200 extern CRangeManager s_RangeMngr; // manages overwritten memory // zz
201 void FlushTransferRanges(const tex0Info* ptex); //zz
202
203 RenderFormatType GetRenderFormat() { return g_RenderFormatType; } //zz
204
205 // use to update the state
206 void SetTexVariables(int context, FRAGMENTSHADER* pfragment); // zz
207 void SetTexInt(int context, FRAGMENTSHADER* pfragment, int settexint); // zz
208 void SetAlphaVariables(const alphaInfo& ainfo); // zzz
209 void ResetAlphaVariables();
210
211 inline void SetAlphaTestInt(pixTest curtest);
212
213 inline void RenderAlphaTest(const VB& curvb, CGparameter sOneColor);
214 inline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting);
215 inline void ProcessStencil(const VB& curvb);
216 inline void RenderFBA(const VB& curvb, CGparameter sOneColor);
217 inline void ProcessFBA(const VB& curvb, CGparameter sOneColor); // zz
218
219
220 }
221
222 //------------------ Code
223
224 inline float AlphaReferedValue(int aref)
225 {
226 return b2XAlphaTest ? min(1.0f, (float)aref / 127.5f) : (float)aref / 255.0f ;
227 }
228
229 inline void SetAlphaTest(const pixTest& curtest)
230 {
231 // if s_dwColorWrite is nontrivial, than we should not off alphatest.
232 // This fix GOW and Okami.
233 if (!curtest.ate && USEALPHATESTING && (s_dwColorWrite != 2 && s_dwColorWrite != 14))
234 {
235 glDisable(GL_ALPHA_TEST);
236 }
237 else
238 {
239 glEnable(GL_ALPHA_TEST);
240 glAlphaFunc(g_dwAlphaCmp[curtest.atst], AlphaReferedValue(curtest.aref));
241 }
242 }
243
244 // Switch wireframe rendering off for first flush, so it's draw few solid primitives
245 inline void SwitchWireframeOff()
246 {
247 if (conf.options & GSOPTION_WIREFRAME)
248 {
249 if (s_nWireframeCount > 0)
250 {
251 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
252 }
253 }
254 }
255
256 // Switch wireframe rendering on, look at previous function
257 inline void SwitchWireframeOn()
258 {
259 if (conf.options & GSOPTION_WIREFRAME)
260 {
261 if (s_nWireframeCount > 0)
262 {
263 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
264 --s_nWireframeCount;
265 }
266 }
267 }
268
269 int GetTexFilter(const tex1Info& tex1)
270 {
271 // always force
272 if (conf.bilinear == 2) return 1;
273
274 int texfilter = 0;
275
276 if (conf.bilinear && ptexBilinearBlocks != 0)
277 {
278 if (tex1.mmin <= 1)
279 texfilter = tex1.mmin | tex1.mmag;
280 else
281 texfilter = tex1.mmag ? ((tex1.mmin + 2) & 5) : tex1.mmin;
282
283 texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5;
284 }
285
286 return texfilter;
287 }
288
289 void ZeroGS::ReloadEffects()
290 {
291 #ifdef ZEROGS_DEVBUILD
292
293 for (int i = 0; i < ARRAY_SIZE(ppsTexture); ++i)
294 {
295 SAFE_RELEASE_PROG(ppsTexture[i].prog);
296 }
297
298 memset(ppsTexture, 0, sizeof(ppsTexture));
299
300 LoadExtraEffects();
301 #endif
302 }
303
304 long BufferNumber = 0;
305
306 // This is a debug function. It prints all buffer info and save current texture into the file, then prints the file name.
307 inline void VisualBufferMessage(int context)
308 {
309 #if defined(WRITE_PRIM_LOGS) && defined(_DEBUG)
310 BufferNumber++;
311 ZeroGS::VB& curvb = vb[context];
312 static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"};
313 static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" };
314 static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" };
315 ZZLog::Error_Log("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d", context, vb[context].nCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw);
316 ZZLog::Error_Log("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x",
317 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);
318 ZZLog::Error_Log("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d",
319 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);
320 ZZLog::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]);
321 ZZLog::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",
322 curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw,
323 curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp,
324 curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld);
325 char* Name;
326 // if (g_bSaveTex) {
327 // if (g_bSaveTex == 1)
328 Name = NamedSaveTex(&curvb.tex0, 1);
329 // else
330 // Name = NamedSaveTex(&curvb.tex0, 0);
331 ZZLog::Error_Log("TGA name '%s'.", Name);
332 free(Name);
333 // }
334 ZZLog::Error_Log("frame: %d, buffer %ld.\n", g_SaveFrameNum, BufferNumber);
335 #endif
336 }
337
338 inline void SaveRendererTarget(VB& curvb)
339 {
340 #ifdef _DEBUG
341
342 if (g_bSaveFlushedFrame & 0x80000000)
343 {
344 char str[255];
345 sprintf(str, "rndr.tga", g_SaveFrameNum);
346 SaveRenderTarget(str, curvb.prndr->fbw, curvb.prndr->fbh, 0);
347 }
348
349 #endif
350 }
351
352 // Stop effects in Developers mode
353 inline void FlushUpdateEffect()
354 {
355 #if defined(DEVBUILD)
356
357 if (g_bUpdateEffect)
358 {
359 ReloadEffects();
360 g_bUpdateEffect = 0;
361 }
362
363 #endif
364 }
365
366 // Check, maybe we cold skip flush
367 inline bool IsFlushNoNeed(VB& curvb, const pixTest& curtest)
368 {
369 if (curvb.nCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost)
370 {
371 curvb.nCount = 0;
372 return true;
373 }
374
375 return false;
376 }
377
378 // Transfer targets, that are located in current texture.
379 inline void FlushTransferRangesHelper(VB& curvb)
380 {
381 if (s_RangeMngr.ranges.size() > 0)
382 {
383 // don't want infinite loop, so set nCount to 0.
384 u32 prevcount = curvb.nCount;
385 curvb.nCount = 0;
386
387 FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL);
388
389 curvb.nCount += prevcount;
390 }
391 }
392
393 // If set bit for texture cheking, do it. Maybe it's all.
394 inline bool FushTexDataHelper(VB& curvb)
395 {
396 if (curvb.bNeedFrameCheck || curvb.bNeedZCheck)
397 {
398 curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0);
399 }
400
401 if (curvb.bNeedTexCheck) // Zeydlitz want to try this
402 {
403 curvb.FlushTexData();
404
405 if (curvb.nCount == 0) return true;
406 }
407
408 return false;
409 }
410
411 // Null target mean that we do something really bad.
412 inline bool FlushCheckForNULLTarget(VB& curvb, int context)
413 {
414 if ((curvb.prndr == NULL) || (curvb.pdepth == NULL))
415 {
416 ERROR_LOG_SPAMA("Current render target NULL (ctx: %d)", context);
417 curvb.nCount = 0;
418 return true;
419 }
420
421 return false;
422 }
423
424 // O.k. A set of resolutions, we do before real flush. We do RangeManager, FrameCheck and
425 // ZCheck before this.
426 inline bool FlushInitialTest(VB& curvb, const pixTest& curtest, int context)
427 {
428 GL_REPORT_ERRORD();
429 assert(context >= 0 && context <= 1);
430
431 FlushUpdateEffect();
432
433 if (IsFlushNoNeed(curvb, curtest)) return true;
434
435 FlushTransferRangesHelper(curvb);
436
437 if (FushTexDataHelper(curvb)) return true;
438
439 GL_REPORT_ERRORD();
440
441 if (FlushCheckForNULLTarget(curvb, context)) return true;
442
443 return false;
444 }
445
446 // Try to different approach if texture target was not found
447 inline CRenderTarget* FlushReGetTarget(int& tbw, int& tbp0, int& tpsm, VB& curvb)
448 {
449 // This was incorrect code
450 CRenderTarget* ptextarg = NULL;
451
452 if (ptextarg == NULL && tpsm == PSMT8 && (g_GameSettings & GAME_REGETHACK))
453 {
454 // check for targets with half the width. Break Valkyrie Chronicles
455 ptextarg = s_RTs.GetTarg(tbp0, tbw / 2, curvb);
456
457 if (ptextarg == NULL)
458 {
459 tbp0 &= ~0x7ff;
460 ptextarg = s_RTs.GetTarg(tbp0, tbw / 2, curvb); // mgs3 hack
461
462 if (ptextarg == NULL)
463 {
464 // check the next level (mgs3)
465 tbp0 &= ~0xfff;
466 ptextarg = s_RTs.GetTarg(tbp0, tbw / 2, curvb); // mgs3 hack
467 }
468
469 if (ptextarg != NULL && ptextarg->start > tbp0*256)
470 {
471 // target beyond range, so ignore
472 ptextarg = NULL;
473 }
474 }
475 }
476
477
478 if (PSMT_ISZTEX(tpsm) && (ptextarg == NULL))
479 {
480 // try depth
481 ptextarg = s_DepthRTs.GetTarg(tbp0, tbw, curvb);
482 }
483
484 if ((ptextarg == NULL) && (g_GameSettings & GAME_TEXTURETARGS))
485 {
486 // check if any part of the texture intersects the current target
487 if (!PSMT_ISCLUT(tpsm) && (curvb.tex0.tbp0 >= curvb.frame.fbp) && ((curvb.tex0.tbp0) < curvb.prndr->end))
488 {
489 ptextarg = curvb.prndr;
490 }
491 }
492
493 #ifdef DEBUG
494 if (tbp0 == 0x3600 && tbw == 0x100)
495 {
496 if (ptextarg == NULL)
497 {
498 printf("Miss %x 0x%x %d\n", tbw, tbp0, tpsm);
499
500 typedef map<u32, CRenderTarget*> MAPTARGETS;
501
502 for (MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew)
503 {
504 printf("\tRender %x 0x%x %x\n", itnew->second->fbw, itnew->second->fbp, itnew->second->psm);
505 }
506
507 for (MAPTARGETS::iterator itnew = s_DepthRTs.mapTargets.begin(); itnew != s_DepthRTs.mapTargets.end(); ++itnew)
508 {
509 printf("\tDepth %x 0x%x %x\n", itnew->second->fbw, itnew->second->fbp, itnew->second->psm);
510 }
511
512 printf("\tCurvb 0x%x 0x%x 0x%x %x\n", curvb.frame.fbp, curvb.prndr->end, curvb.prndr->fbp, curvb.prndr->fbw);
513 }
514 else
515 printf("Hit %x 0x%x %x\n", tbw, tbp0, tpsm);
516 }
517
518 #endif
519
520 return ptextarg;
521 }
522
523 // Find target to draw a texture, it's highly p
524 inline CRenderTarget* FlushGetTarget(VB& curvb)
525 {
526 int tbw, tbp0, tpsm;
527
528 CRenderTarget* ptextarg = NULL;
529
530 if (!curvb.curprim.tme) return ptextarg;
531
532 if (curvb.bNeedTexCheck)
533 {
534 printf("How it is possible?\n");
535 // not yet initied, but still need to get correct target! (xeno3 ingame)
536 tbp0 = ZZOglGet_tbp0_TexBits(curvb.uNextTex0Data[0]);
537 tbw = ZZOglGet_tbw_TexBitsMult(curvb.uNextTex0Data[0]);
538 tpsm = ZZOglGet_psm_TexBitsFix(curvb.uNextTex0Data[0]);
539 }
540 else
541 {
542 tbw = curvb.tex0.tbw;
543 tbp0 = curvb.tex0.tbp0;
544 tpsm = curvb.tex0.psm;
545 }
546
547 ptextarg = s_RTs.GetTarg(tbp0, tbw, curvb);
548
549 if (ptextarg == NULL)
550 ptextarg = FlushReGetTarget(tbw, tbp0, tpsm, curvb);
551
552 if ((ptextarg != NULL) && !(ptextarg->status & CRenderTarget::TS_NeedUpdate))
553 {
554 if (PSMT_BITMODE(tpsm) == 4) // handle 8h cluts
555 {
556 // don't support clut targets, read from mem
557 // 4hl - kh2 check - from dx version -- arcum42
558
559 if (tpsm == PSMT4 && s_ClutResolve <= 1)
560 {
561 // xenosaga requires 2 resolves
562 u32 prevcount = curvb.nCount;
563 curvb.nCount = 0;
564 ptextarg->Resolve();
565 s_ClutResolve++;
566 curvb.nCount += prevcount;
567 }
568
569 ptextarg = NULL;
570 }
571 else
572 {
573 if (ptextarg == curvb.prndr)
574 {
575 // need feedback
576 curvb.prndr->CreateFeedback();
577
578 if (s_bWriteDepth && (curvb.pdepth != NULL))
579 curvb.pdepth->SetRenderTarget(1);
580 else
581 ResetRenderTarget(1);
582 }
583 }
584 }
585 else
586 {
587 ptextarg = NULL;
588 }
589
590 return ptextarg;
591 }
592
593 // Set target for current context
594 inline void FlushSetContextTarget(VB& curvb, int context)
595 {
596 if (!curvb.bVarsSetTarg)
597 {
598 SetContextTarget(context);
599 }
600 else
601 {
602 assert(curvb.pdepth != NULL);
603
604 if (curvb.pdepth->status & CRenderTarget::TS_Virtual)
605 {
606 if (!curvb.zbuf.zmsk)
607 {
608 CRenderTarget* ptemp = s_DepthRTs.Promote(GetFrameKey(curvb.pdepth));
609 assert(ptemp == curvb.pdepth);
610 }
611 else
612 {
613 curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate;
614 }
615 }
616
617 if ((curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate))
618 SetContextTarget(context);
619 }
620
621 assert(!(curvb.prndr->status&CRenderTarget::TS_NeedUpdate));
622
623 curvb.prndr->status = 0;
624
625 if (curvb.pdepth != NULL)
626 {
627 assert(!(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate));
628
629 if (!curvb.zbuf.zmsk)
630 {
631 assert(!(curvb.pdepth->status & CRenderTarget::TS_Virtual));
632 curvb.pdepth->status = 0;
633 }
634 }
635 }
636
637 inline void FlushSetStream(VB& curvb)
638 {
639 glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[g_nCurVBOIndex]);
640 g_nCurVBOIndex = (g_nCurVBOIndex + 1) % g_vboBuffers.size();
641 glBufferData(GL_ARRAY_BUFFER, curvb.nCount * sizeof(VertexGPU), curvb.pBufferData, GL_STREAM_DRAW);
642 // void* pdata = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
643 // memcpy_amd(pdata, curvb.pBufferData, curvb.nCount * sizeof(VertexGPU));
644 // glUnmapBuffer(GL_ARRAY_BUFFER);
645 SET_STREAM();
646 #ifdef _DEBUG
647 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
648 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
649 #endif
650
651 }
652
653 int SetMaskR = 0x0;
654 int SetMaskG = 0x0;
655 int SetMaskB = 0x0;
656 // Set color mask. Really, it's not as good as PS2 one.
657 inline void FlushSetColorMask(VB& curvb)
658 {
659 s_dwColorWrite = (PSMT_BITMODE(curvb.prndr->psm) == 1) ? (COLORMASK_BLUE | COLORMASK_GREEN | COLORMASK_RED) : 0xf;
660
661 int maskR = ZZOglGet_fbmRed_FrameBits(curvb.frame.fbm);
662 int maskG = ZZOglGet_fbmGreen_FrameBits(curvb.frame.fbm);
663 int maskB = ZZOglGet_fbmBlue_FrameBits(curvb.frame.fbm);
664 int maskA = ZZOglGet_fbmAlpha_FrameBits(curvb.frame.fbm);
665
666 if (maskR == 0xff) s_dwColorWrite &= ~COLORMASK_RED;
667 if (maskG == 0xff) s_dwColorWrite &= ~COLORMASK_GREEN;
668 if (maskB == 0xff) s_dwColorWrite &= ~COLORMASK_BLUE;
669
670 if ((maskA == 0xff) || (curvb.curprim.abe && (curvb.test.atst == 2 && curvb.test.aref == 128)))
671 s_dwColorWrite &= ~COLORMASK_ALPHA;
672
673 GL_COLORMASK(s_dwColorWrite);
674 }
675
676 // Set Scissors for scissor test.
677 inline void FlushSetScissorRect(VB& curvb)
678 {
679 Rect& scissor = curvb.prndr->scissorrect;
680 glScissor(scissor.x, scissor.y, scissor.w, scissor.h);
681 }
682
683 // Prior really doing something check context
684 inline void FlushDoContextJob(VB& curvb, int context)
685 {
686 SaveRendererTarget(curvb);
687
688 FlushSetContextTarget(curvb, context);
689 icurctx = context;
690
691 FlushSetStream(curvb);
692 FlushSetColorMask(curvb);
693 FlushSetScissorRect(curvb);
694 }
695
696 // Set 1 is Alpha test is EQUAL and alpha should be proceed with care.
697 inline int FlushGetExactcolor(const pixTest curtest)
698 {
699 if (!(g_nPixelShaderVer&SHADER_REDUCED))
700 // ffx2 breaks when ==7
701 return ((curtest.ate && curtest.aref <= 128) && (curtest.atst == 4));//||curtest.atst==7);
702
703 return 0;
704 }
705
706 // fill the buffer by decoding the clut
707 inline void FlushDecodeClut(VB& curvb, GLuint& ptexclut)
708 {
709 glGenTextures(1, &ptexclut);
710 glBindTexture(GL_TEXTURE_2D, ptexclut);
711 vector<char> data(PSMT_ISHALF_STORAGE(curvb.tex0) ? 512 : 1024);
712
713 if (ptexclut != 0)
714 {
715
716 int nClutOffset = 0, clutsize;
717 int entries = PSMT_IS8CLUT(curvb.tex0.psm) ? 256 : 16;
718
719 if (curvb.tex0.csm && curvb.tex0.csa)
720 printf("ERROR, csm1\n");
721
722 if (PSMT_IS32BIT(curvb.tex0.cpsm)) // 32 bit
723 {
724 nClutOffset = 64 * curvb.tex0.csa;
725 clutsize = min(entries, 256 - curvb.tex0.csa * 16) * 4;
726 }
727 else
728 {
729 nClutOffset = 64 * (curvb.tex0.csa & 15) + (curvb.tex0.csa >= 16 ? 2 : 0);
730 clutsize = min(entries, 512 - curvb.tex0.csa * 16) * 2;
731 }
732
733 if (PSMT_IS32BIT(curvb.tex0.cpsm)) // 32 bit
734 {
735 memcpy_amd(&data[0], g_pbyGSClut + nClutOffset, clutsize);
736 }
737 else
738 {
739 u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset);
740 u16* pclut = (u16*) & data[0];
741 int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset & 0x3ff) / 2) + clutsize - 512;
742
743 if (left > 0) clutsize -= left;
744
745 while (clutsize > 0)
746 {
747 pclut[0] = pClutBuffer[0];
748 pclut++;
749 pClutBuffer += 2;
750 clutsize -= 2;
751 }
752
753 if (left > 0)
754 {
755 pClutBuffer = (u16*)(g_pbyGSClut + 2);
756
757 while (left > 0)
758 {
759 pclut[0] = pClutBuffer[0];
760 left -= 2;
761 pClutBuffer += 2;
762 pclut++;
763 }
764 }
765 }
766
767 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]);
768
769 s_vecTempTextures.push_back(ptexclut);
770
771 if (g_bSaveTex) SaveTexture("clut.tga", GL_TEXTURE_2D, ptexclut, 256, 1);
772
773 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
774 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
775 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
776 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
777 }
778 }
779
780 inline int FlushGetShaderType(VB& curvb, CRenderTarget* ptextarg, GLuint& ptexclut)
781 {
782 if (PSMT_ISCLUT(curvb.tex0.psm) && !(g_GameSettings&GAME_NOTARGETCLUT))
783 {
784 FlushDecodeClut(curvb, ptexclut);
785
786 if (!(g_nPixelShaderVer&SHADER_REDUCED) && PSMT_ISHALF(ptextarg->psm))
787 {
788 return 4;
789 }
790 else
791 {
792 // Valkyrie
793 return 2;
794 }
795 }
796
797 if (PSMT_ISHALF_STORAGE(curvb.tex0) != PSMT_ISHALF(ptextarg->psm) && (!(g_nPixelShaderVer&SHADER_REDUCED) || !curvb.curprim.fge))
798 {
799 if (PSMT_ISHALF_STORAGE(curvb.tex0))
800 {
801 // converting from 32->16
802 // Radiata Chronicles
803 return 3;
804 }
805 else
806 {
807 // converting from 16->32
808 // Star Ward: Force
809 return 0;
810 }
811 }
812
813 return 1;
814 }
815
816
817 //Set page offsets depends omn shader type.
818 inline Vector FlushSetPageOffset(FRAGMENTSHADER* pfragment, int shadertype, CRenderTarget* ptextarg)
819 {
820 SetShaderCaller("FlushSetPageOffset");
821
822 Vector vpageoffset;
823 vpageoffset.w = 0;
824
825 switch (shadertype)
826 {
827 case 3:
828 vpageoffset.x = -0.1f / 256.0f;
829 vpageoffset.y = -0.001f / 256.0f;
830 vpageoffset.z = -0.1f / (ptextarg->fbh);
831 vpageoffset.w = 0.0f;
832 break;
833
834 case 4:
835 vpageoffset.x = 2;
836 vpageoffset.y = 1;
837 vpageoffset.z = 0;
838 vpageoffset.w = 0.0001f;
839 break;
840 }
841
842 // zoe2
843 if (PSMT_ISZTEX(ptextarg->psm)) vpageoffset.w = -1.0f;
844
845 ZZcgSetParameter4fv(pfragment->fPageOffset, vpageoffset, "g_fPageOffset");
846
847 return vpageoffset;
848 }
849
850 //Set texture offsets depends omn shader type.
851 inline Vector FlushSetTexOffset(FRAGMENTSHADER* pfragment, int shadertype, VB& curvb, CRenderTarget* ptextarg)
852 {
853 SetShaderCaller("FlushSetTexOffset");
854 Vector v;
855
856 if (shadertype == 3)
857 {
858 Vector v;
859 v.x = 16.0f / (float)curvb.tex0.tw;
860 v.y = 16.0f / (float)curvb.tex0.th;
861 v.z = 0.5f * v.x;
862 v.w = 0.5f * v.y;
863 ZZcgSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset");
864 }
865 else if (shadertype == 4)
866 {
867 Vector v;
868 v.x = 16.0f / (float)ptextarg->fbw;
869 v.y = 16.0f / (float)ptextarg->fbh;
870 v.z = -1;
871 v.w = 8.0f / (float)ptextarg->fbh;
872 ZZcgSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset");
873 }
874
875 return v;
876 }
877
878 // Set dimension (Real!) of texture. z and w
879 inline Vector FlushTextureDims(FRAGMENTSHADER* pfragment, int shadertype, VB& curvb, CRenderTarget* ptextarg)
880 {
881 SetShaderCaller("FlushTextureDims");
882 Vector vTexDims;
883 vTexDims.x = (float)RW(curvb.tex0.tw) ;
884 vTexDims.y = (float)RH(curvb.tex0.th) ;
885
886 // look at the offset of tbp0 from fbp
887
888 if (curvb.tex0.tbp0 <= ptextarg->fbp)
889 {
890 vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw;
891 vTexDims.w = 0;//0.2f/(float)ptextarg->fbh;
892 }
893 else
894 {
895 //u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page
896 int blockheight = PSMT_ISHALF(ptextarg->psm) ? 64 : 32;
897 int ycoord = ((curvb.tex0.tbp0 - ptextarg->fbp) / (32 * (ptextarg->fbw >> 6))) * blockheight;
898 int xcoord = (((curvb.tex0.tbp0 - ptextarg->fbp) % (32 * (ptextarg -> fbw >> 6)))) * 2;
899 vTexDims.z = (float)xcoord;
900 vTexDims.w = (float)ycoord;
901 }
902
903 if (shadertype == 4)
904 vTexDims.z += 8.0f;
905
906 ZZcgSetParameter4fv(pfragment->fTexDims, vTexDims, "g_fTexDims");
907
908 return vTexDims;
909 }
910
911 // Apply TEX1 mmag and mmin -- filter for expanding/reducing texture
912 // We ignore all settings, only NEAREST (0) is used
913 inline void FlushApplyResizeFilter(VB& curvb, u32& dwFilterOpts, CRenderTarget* ptextarg, int context)
914 {
915 u32 ptexset = (ptextarg == curvb.prndr) ? ptextarg->ptexFeedback : ptextarg->ptex;
916 s_ptexCurSet[context] = ptexset;
917
918 if ((!curvb.tex1.mmag) || (!curvb.tex1.mmin))
919 glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset);
920
921 if (!curvb.tex1.mmag)
922 {
923 glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
924 dwFilterOpts |= 1;
925 }
926
927 if (!curvb.tex1.mmin)
928 {
929 glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
930 dwFilterOpts |= 2;
931 }
932 }
933
934
935 // Usage existing targets depends on several tricks, 32-16 conversion and CLUTing, so we need handle it.
936 inline FRAGMENTSHADER* FlushUseExistRenderTaget(VB& curvb, CRenderTarget* ptextarg, u32& dwFilterOpts, int exactcolor, int context)
937 {
938 if (ptextarg->IsDepth())
939 SetWriteDepth();
940
941 GLuint ptexclut = 0;
942
943 //int psm = GetTexCPSM(curvb.tex0);
944 int shadertype = FlushGetShaderType(curvb, ptextarg, ptexclut);
945
946 FRAGMENTSHADER* pfragment = LoadShadeEffect(shadertype, 0, curvb.curprim.fge,
947 IsAlphaTestExpansion(curvb), exactcolor, curvb.clamp, context, NULL);
948
949 Vector vpageoffset = FlushSetPageOffset(pfragment, shadertype, ptextarg);
950
951 Vector v = FlushSetTexOffset(pfragment, shadertype, curvb, ptextarg);
952
953 Vector vTexDims = FlushTextureDims(pfragment, shadertype, curvb, ptextarg);
954
955 if (pfragment->sCLUT != NULL && ptexclut != 0)
956 {
957 cgGLSetTextureParameter(pfragment->sCLUT, ptexclut);
958 cgGLEnableTextureParameter(pfragment->sCLUT);
959 }
960
961 FlushApplyResizeFilter(curvb, dwFilterOpts, ptextarg, context);
962
963 if (g_bSaveTex)
964 SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_NV,
965 ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, RW(ptextarg->fbw), RH(ptextarg->fbh));
966
967 return pfragment;
968 }
969
970 // Usage most major shader.
971 inline FRAGMENTSHADER* FlushMadeNewTarget(VB& curvb, int exactcolor, int context)
972 {
973 // save the texture
974 if (g_bSaveTex)
975 {
976 if (g_bSaveTex == 1)
977 {
978 SaveTex(&curvb.tex0, 1);
979 /*CMemoryTarget* pmemtarg = */
980 g_MemTargs.GetMemoryTarget(curvb.tex0, 0);
981 }
982 else
983 {
984 SaveTex(&curvb.tex0, 0);
985 }
986 }
987
988 FRAGMENTSHADER* pfragment = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge,
989
990 IsAlphaTestExpansion(curvb), exactcolor, curvb.clamp, context, NULL);
991
992 if (pfragment == NULL)
993 ZZLog::Error_Log("Could not find memory target shader.");
994
995 return pfragment;
996 }
997
998 // We made an shader, so now need to put all common variables.
999 inline void FlushSetTexture(VB& curvb, FRAGMENTSHADER* pfragment, CRenderTarget* ptextarg, int context)
1000 {
1001 SetTexVariables(context, pfragment);
1002 SetTexInt(context, pfragment, ptextarg == NULL);
1003
1004 // have to enable the texture parameters(curtest.atst=
1005
1006 if (curvb.ptexClamp[0] != 0)
1007 {
1008 cgGLSetTextureParameter(pfragment->sBitwiseANDX, curvb.ptexClamp[0]);
1009 cgGLEnableTextureParameter(pfragment->sBitwiseANDX);
1010 }
1011
1012 if (curvb.ptexClamp[1] != 0)
1013 {
1014 cgGLSetTextureParameter(pfragment->sBitwiseANDY, curvb.ptexClamp[1]);
1015 cgGLEnableTextureParameter(pfragment->sBitwiseANDY);
1016 }
1017
1018 if (pfragment->sMemory != NULL && s_ptexCurSet[context] != 0)
1019 {
1020 cgGLSetTextureParameter(pfragment->sMemory, s_ptexCurSet[context]);
1021 cgGLEnableTextureParameter(pfragment->sMemory);
1022 }
1023 }
1024
1025 // Reset programm and texture variables;
1026 inline void FlushBindProgramm(FRAGMENTSHADER* pfragment, int context)
1027 {
1028 vb[context].bTexConstsSync = 0;
1029 vb[context].bVarsTexSync = 0;
1030
1031 cgGLBindProgram(pfragment->prog);
1032 g_psprog = pfragment->prog;
1033 }
1034
1035 inline FRAGMENTSHADER* FlushRendererStage(VB& curvb, u32& dwFilterOpts, CRenderTarget* ptextarg, int exactcolor, int context)
1036 {
1037
1038 FRAGMENTSHADER* pfragment = NULL;
1039
1040 // set the correct pixel shaders
1041
1042 if (curvb.curprim.tme)
1043 {
1044 if (ptextarg != NULL)
1045 pfragment = FlushUseExistRenderTaget(curvb, ptextarg, dwFilterOpts, exactcolor, context);
1046 else
1047 pfragment = FlushMadeNewTarget(curvb, exactcolor, context);
1048
1049 if (pfragment == NULL)
1050 {
1051 ZZLog::Error_Log("Shader is not found.");
1052 // return NULL;
1053 }
1054
1055 FlushSetTexture(curvb, pfragment, ptextarg, context);
1056 }
1057 else
1058 {
1059 pfragment = &ppsRegular[curvb.curprim.fge + 2 * s_bWriteDepth];
1060 }
1061
1062 GL_REPORT_ERRORD();
1063
1064 // set the shaders
1065 SetShaderCaller("FlushRendererStage") ;
1066 SETVERTEXSHADER(pvs[2 * ((curvb.curprim._val >> 1) & 3) + 8 * s_bWriteDepth + context]);
1067 FlushBindProgramm(pfragment, context);
1068
1069 GL_REPORT_ERRORD();
1070 return pfragment;
1071 }
1072
1073 inline bool AlphaCanRenderStencil(VB& curvb)
1074 {
1075 return g_bUpdateStencil && (PSMT_BITMODE(curvb.prndr->psm) != 1) &&
1076 !ZZOglGet_fbmHighByte(curvb.frame.fbm) && !(g_GameSettings & GAME_NOSTENCIL);
1077 }
1078
1079 inline void AlphaSetStencil(bool DoIt)
1080 {
1081 if (DoIt)
1082 {
1083 glEnable(GL_STENCIL_TEST);
1084 GL_STENCILFUNC(GL_ALWAYS, 0, 0);
1085 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1086 }
1087 else glDisable(GL_STENCIL_TEST);
1088 }
1089
1090 inline void AlphaSetDepthTest(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pfragment)
1091 {
1092 glDepthMask(!curvb.zbuf.zmsk && curtest.zte);
1093 // && curtest.zte && (curtest.ztst > 1) );
1094
1095 if (curtest.zte)
1096 {
1097 if (curtest.ztst > 1) g_nDepthUsed = 2;
1098 if ((curtest.ztst == 2) ^(g_nDepthBias != 0))
1099 {
1100 g_nDepthBias = (curtest.ztst == 2);
1101 //SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f));
1102 }
1103
1104 glDepthFunc(g_dwZCmp[curtest.ztst]);
1105 }
1106
1107 GL_ZTEST(curtest.zte);
1108
1109 // glEnable (GL_POLYGON_OFFSET_FILL);
1110 // glPolygonOffset (-1., -1.);
1111
1112 if (s_bWriteDepth)
1113 {
1114 if (!curvb.zbuf.zmsk)
1115 curvb.pdepth->SetRenderTarget(1);
1116 else
1117 ResetRenderTarget(1);
1118 }
1119 }
1120
1121 inline u32 AlphaSetupBlendTest(VB& curvb)
1122 {
1123 if (curvb.curprim.abe)
1124 SetAlphaVariables(curvb.alpha);
1125 else
1126 glDisable(GL_BLEND);
1127
1128 u32 oldabe = curvb.curprim.abe;
1129
1130 if (gs.pabe)
1131 {
1132 //ZZLog::Error_Log("PABE!");
1133 curvb.curprim.abe = 1;
1134 glEnable(GL_BLEND);
1135 }
1136
1137 return oldabe;
1138 }
1139
1140 inline void AlphaRenderFBA(VB& curvb, FRAGMENTSHADER* pfragment, bool s_bDestAlphaTest, bool bCanRenderStencil)
1141 {
1142 // needs to be before RenderAlphaTest
1143 if ((gs.pabe) || (curvb.fba.fba && !ZZOglGet_fbmHighByte(curvb.frame.fbm)) || (s_bDestAlphaTest && bCanRenderStencil))
1144 {
1145 RenderFBA(curvb, pfragment->sOneColor);
1146 }
1147
1148 }
1149
1150 inline u32 AlphaRenderAlpha(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pfragment, int exactcolor)
1151 {
1152 SetShaderCaller("AlphaRenderAlpha");
1153 u32 dwUsingSpecialTesting = 0;
1154
1155 if (curvb.curprim.abe)
1156 {
1157 if ((bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst > 1) && (curtest.aref > 0x80))))
1158 {
1159 // need special stencil processing for the alpha
1160 RenderAlphaTest(curvb, pfragment->sOneColor);
1161 dwUsingSpecialTesting = 1;
1162 }
1163
1164 // harvest fishing
1165 Vector v = vAlphaBlendColor;
1166
1167 if (exactcolor)
1168 {
1169 v.y *= 255;
1170 v.w *= 255;
1171 }
1172
1173 ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
1174 }
1175 else
1176 {
1177 // not using blending so set to defaults
1178 Vector v = exactcolor ? Vector(1, 510 * 255.0f / 256.0f, 0, 0) : Vector(1, 2 * 255.0f / 256.0f, 0, 0);
1179 ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
1180
1181 }
1182
1183 return dwUsingSpecialTesting;
1184 }
1185
1186 inline void AlphaRenderStencil(VB& curvb, bool s_bDestAlphaTest, bool bCanRenderStencil, u32 dwUsingSpecialTesting)
1187 {
1188 if (s_bDestAlphaTest && bCanRenderStencil)
1189 {
1190 // if not 24bit and can write to high alpha bit
1191 RenderStencil(curvb, dwUsingSpecialTesting);
1192 }
1193 else
1194 {
1195 s_stencilref = STENCIL_SPECIAL;
1196 s_stencilmask = STENCIL_SPECIAL;
1197
1198 // setup the stencil to only accept the test pixels
1199
1200 if (dwUsingSpecialTesting)
1201 {
1202 glEnable(GL_STENCIL_TEST);
1203 glStencilMask(STENCIL_PIXELWRITE);
1204 GL_STENCILFUNC(GL_EQUAL, STENCIL_SPECIAL | STENCIL_PIXELWRITE, STENCIL_SPECIAL);
1205 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1206 }
1207 }
1208
1209 #ifdef _DEBUG
1210 if (bDestAlphaColor == 1)
1211 {
1212 ZZLog::Debug_Log("Dest alpha blending! Manipulate alpha here.");
1213 }
1214
1215 #endif
1216
1217 if (bCanRenderStencil && gs.pabe)
1218 {
1219 // only render the pixels with alpha values >= 0x80
1220 GL_STENCILFUNC(GL_EQUAL, s_stencilref | STENCIL_FBA, s_stencilmask | STENCIL_FBA);
1221 }
1222
1223 GL_REPORT_ERRORD();
1224 }
1225
1226 inline void AlphaTest(VB& curvb)
1227 {
1228 // printf ("%d %d %d %d %d\n", curvb.test.date, curvb.test.datm, gs.texa.aem, curvb.test.ate, curvb.test.atst );
1229
1230 // return;
1231 // Zeydlitz changed this with a reason! It's an "Alpha more than 1 hack."
1232 if (curvb.test.ate == 1 && curvb.test.atst == 1 && curvb.test.date == 1)
1233 {
1234 if (curvb.test.datm == 1)
1235 {
1236 glAlphaFunc(GL_GREATER, 1.0f);
1237 }
1238 else
1239 {
1240 glAlphaFunc(GL_LESS, 1.0f);
1241 printf("%d %d %d\n", curvb.test.date, curvb.test.datm, gs.texa.aem);
1242 }
1243 }
1244
1245 if (!curvb.test.ate || curvb.test.atst > 0)
1246 {
1247 DRAW();
1248 }
1249
1250 GL_REPORT_ERRORD();
1251 }
1252
1253 inline void AlphaPabe(VB& curvb, FRAGMENTSHADER* pfragment, int exactcolor)
1254 {
1255 if (gs.pabe)
1256 {
1257 SetShaderCaller("AlphaPabe");
1258 // only render the pixels with alpha values < 0x80
1259 glDisable(GL_BLEND);
1260 GL_STENCILFUNC_SET();
1261
1262 Vector v;
1263 v.x = 1;
1264 v.y = 2;
1265 v.z = 0;
1266 v.w = 0;
1267
1268 if (exactcolor) v.y *= 255;
1269
1270 ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
1271
1272 DRAW();
1273
1274 // reset
1275 if (!s_stencilmask) s_stencilfunc = GL_ALWAYS;
1276
1277 GL_STENCILFUNC_SET();
1278 }
1279
1280 GL_REPORT_ERRORD();
1281 }
1282
1283 // Alpha Failure does not work properly on this cases. True means that no failure job should be done.
1284 // First three cases are trivial manual.
1285 inline bool AlphaFailureIgnore(const pixTest curtest)
1286 {
1287 if (!curtest.ate) return true;
1288 if (curtest.atst == 1) return true;
1289 if (curtest.afail == 0) return true;
1290
1291 if (g_GameSettings & GAME_NOALPHAFAIL && ((s_dwColorWrite < 8) || (s_dwColorWrite == 15 && curtest.atst == 5 && (curtest.aref == 64))))
1292 return true;
1293
1294 // old and seemingly incorrect code.
1295 // if ((s_dwColorWrite < 8 && s_dwColorWrite !=8) && curtest.afail == 1)
1296 // return true;
1297 // if ((s_dwColorWrite == 0xf) && curtest.atst == 5 && curtest.afail == 1 && !(g_GameSettings & GAME_REGETHACK))
1298 // return true;
1299 return false;
1300 }
1301
1302 // more work on alpha failure case
1303 inline void AlphaFailureTestJob(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pfragment, int exactcolor, bool bCanRenderStencil, int oldabe)
1304 {
1305 // Note, case when ate == 1, atst == 0 and afail > 0 in documentation wrote as failure case. But it seems that
1306 // either doc's are incorrect or this case has some issues.
1307 if (AlphaFailureIgnore(curtest)) return;
1308
1309 #ifdef NOALFAFAIL
1310 ZZLog::Error_Log("Alpha job here %d %d %d %d %d %d", s_dwColorWrite, curtest.atst, curtest.afail, curtest.aref, gs.pabe, s_bWriteDepth);
1311
1312 // return;
1313 #endif
1314
1315 SetShaderCaller("AlphaFailureTestJob");
1316
1317 // need to reverse the test and disable some targets
1318 glAlphaFunc(g_dwReverseAlphaCmp[curtest.atst], AlphaReferedValue(curtest.aref));
1319
1320 if (curtest.afail & 1) // front buffer update only
1321 {
1322 if (curtest.afail == 3) glColorMask(1, 1, 1, 0);// disable alpha
1323
1324 glDepthMask(0);
1325
1326 if (s_bWriteDepth) ResetRenderTarget(1);
1327 }
1328 else
1329 {
1330 // zbuffer update only
1331 glColorMask(0, 0, 0, 0);
1332 }
1333
1334 if (gs.pabe && bCanRenderStencil)
1335 {
1336 // only render the pixels with alpha values >= 0x80
1337 Vector v = vAlphaBlendColor;
1338
1339 if (exactcolor) { v.y *= 255; v.w *= 255; }
1340
1341 ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
1342
1343 glEnable(GL_BLEND);
1344 GL_STENCILFUNC(GL_EQUAL, s_stencilref | STENCIL_FBA, s_stencilmask | STENCIL_FBA);
1345 }
1346
1347 DRAW();
1348
1349 GL_REPORT_ERRORD();
1350
1351 if (gs.pabe)
1352 {
1353 // only render the pixels with alpha values < 0x80
1354 glDisable(GL_BLEND);
1355 GL_STENCILFUNC_SET();
1356
1357 Vector v;
1358 v.x = 1;
1359 v.y = 2;
1360 v.z = 0;
1361 v.w = 0;
1362
1363 if (exactcolor) v.y *= 255;
1364
1365 ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
1366
1367 DRAW();
1368
1369 // reset
1370 if (oldabe) glEnable(GL_BLEND);
1371
1372 if (!s_stencilmask) s_stencilfunc = GL_ALWAYS;
1373
1374 GL_STENCILFUNC_SET();
1375 }
1376
1377 // restore
1378 if ((curtest.afail & 1) && !curvb.zbuf.zmsk)
1379 {
1380 glDepthMask(1);
1381
1382 if (s_bWriteDepth)
1383 {
1384 assert(curvb.pdepth != NULL);
1385 curvb.pdepth->SetRenderTarget(1);
1386 }
1387 }
1388
1389 GL_COLORMASK(s_dwColorWrite);
1390
1391 // not needed anymore since rest of ops concentrate on image processing
1392
1393 GL_REPORT_ERRORD();
1394 }
1395
1396 inline void AlphaSpecialTesting(VB& curvb, FRAGMENTSHADER* pfragment, u32 dwUsingSpecialTesting, int exactcolor)
1397 {
1398 if (dwUsingSpecialTesting)
1399 {
1400 SetShaderCaller("AlphaSpecialTesting");
1401
1402 // render the real alpha
1403 glDisable(GL_ALPHA_TEST);
1404 glColorMask(0, 0, 0, 1);
1405
1406 if (s_bWriteDepth)
1407 {
1408 ResetRenderTarget(1);
1409 }
1410
1411 glDepthMask(0);
1412
1413 glStencilFunc(GL_EQUAL, STENCIL_SPECIAL | STENCIL_PIXELWRITE, STENCIL_SPECIAL | STENCIL_PIXELWRITE);
1414 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1415
1416 Vector v = Vector(0, exactcolor ? 510.0f : 2.0f, 0, 0);
1417 ZZcgSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor");
1418 DRAW();
1419
1420 // don't need to restore
1421 }
1422
1423 GL_REPORT_ERRORD();
1424 }
1425
1426 inline void AlphaDestinationTest(VB& curvb, FRAGMENTSHADER* pfragment, bool s_bDestAlphaTest, bool bCanRenderStencil)
1427 {
1428 if (s_bDestAlphaTest)
1429 {
1430 if ((s_dwColorWrite & COLORMASK_ALPHA))
1431 {
1432 if (curvb.fba.fba)
1433 ProcessFBA(curvb, pfragment->sOneColor);
1434 else if (bCanRenderStencil)
1435 // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case)
1436 ProcessStencil(curvb);
1437 }
1438 }
1439 else if ((s_dwColorWrite & COLORMASK_ALPHA) && curvb.fba.fba)
1440 ProcessFBA(curvb, pfragment->sOneColor);
1441
1442 if (bDestAlphaColor == 1)
1443 {
1444 // need to reset the dest colors to their original counter parts
1445 //WARN_LOG("Need to reset dest alpha color\n");
1446 }
1447 }
1448
1449 inline void AlphaSaveTarget(VB& curvb)
1450 {
1451 #ifdef _DEBUG
1452 return; // Do nothing
1453
1454 // if( g_bSaveFlushedFrame & 0xf ) {
1455 //#ifdef _WIN32
1456 // CreateDirectory("frames", NULL);
1457 //#else
1458 // char* strdir="";
1459 // sprintf(strdir, "mkdir %s", "frames");
1460 // system(strdir);
1461 //#endif
1462 // char str[255];
1463 // sprintf(str, "frames/frame%.4d.tga", g_SaveFrameNum++);
1464 // if( (g_bSaveFlushedFrame & 2) ) {
1465 // //glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer
1466 // //glFlush();
1467 // //SaveTexture("tex.jpg", GL_TEXTURE_RECTANGLE_NV, curvb.prndr->ptex, RW(curvb.prndr->fbw), RH(curvb.prndr->fbh));
1468 // SaveRenderTarget(str, RW(curvb.prndr->fbw), RH(curvb.prndr->fbh), 0);
1469 // }
1470 // }
1471 #endif
1472 }
1473
1474 inline void AlphaColorClamping(VB& curvb, const pixTest curtest)
1475 {
1476 // clamp the final colors, when enabled ffx2 credits mess up
1477 if (curvb.curprim.abe && bAlphaClamping && GetRenderFormat() != RFT_byte8 && !(g_GameSettings&GAME_NOCOLORCLAMP)) // if !colclamp, skip
1478 {
1479 ResetAlphaVariables();
1480
1481 // if processing the clamping case, make sure can write to the front buffer
1482 glDisable(GL_STENCIL_TEST);
1483 glEnable(GL_BLEND);
1484 glDisable(GL_ALPHA_TEST);
1485 glDisable(GL_DEPTH_TEST);
1486 glDepthMask(0);
1487 glColorMask(1, 1, 1, 0);
1488
1489 if (s_bWriteDepth) ResetRenderTarget(1);
1490
1491 SetShaderCaller("AlphaColorClamping");
1492
1493 SETPIXELSHADER(ppsOne.prog);
1494 GL_BLEND_RGB(GL_ONE, GL_ONE);
1495
1496 float f;
1497
1498 if (bAlphaClamping & 1) // min
1499 {
1500 f = 0;
1501 ZZcgSetParameter4fv(ppsOne.sOneColor, &f, "g_fOneColor");
1502 GL_BLENDEQ_RGB(GL_MAX_EXT);
1503 DRAW();
1504 }
1505
1506 // bios shows white screen
1507 if (bAlphaClamping & 2) // max
1508 {
1509 f = 1;
1510 ZZcgSetParameter4fv(ppsOne.sOneColor, &f, "g_fOneColor");
1511 GL_BLENDEQ_RGB(GL_MIN_EXT);
1512 DRAW();
1513 }
1514
1515 if (!curvb.zbuf.zmsk)
1516 {
1517 glDepthMask(1);
1518
1519 if (s_bWriteDepth)
1520 {
1521 assert(curvb.pdepth != NULL);
1522 curvb.pdepth->SetRenderTarget(1);
1523 }
1524 }
1525
1526 if (curvb.test.ate && USEALPHATESTING) glEnable(GL_ALPHA_TEST);
1527
1528 GL_ZTEST(curtest.zte);
1529 }
1530 }
1531
1532 inline void FlushUndoFiter(u32 dwFilterOpts)
1533 {
1534 if (dwFilterOpts)
1535 {
1536 // undo filter changes (binding didn't change)
1537 if (dwFilterOpts & 1) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1538 if (dwFilterOpts & 2) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1539 }
1540 }
1541
1542 // This is the most important function! It draws all collected info onscreen.
1543 void ZeroGS::Flush(int context)
1544 {
1545 FUNCLOG
1546 VB& curvb = vb[context];
1547 const pixTest curtest = curvb.test;
1548
1549 if (FlushInitialTest(curvb, curtest, context)) return;
1550
1551 VisualBufferMessage(context);
1552
1553 GL_REPORT_ERRORD();
1554
1555 CRenderTarget* ptextarg = FlushGetTarget(curvb);
1556
1557 SwitchWireframeOff();
1558 FlushDoContextJob(curvb, context);
1559
1560 u32 dwUsingSpecialTesting = 0;
1561 u32 dwFilterOpts = 0;
1562 int exactcolor = FlushGetExactcolor(curtest);
1563
1564 FRAGMENTSHADER* pfragment = FlushRendererStage(curvb, dwFilterOpts, ptextarg, exactcolor, context);
1565
1566 bool bCanRenderStencil = AlphaCanRenderStencil(curvb);
1567
1568 if (curtest.date || gs.pabe) SetDestAlphaTest();
1569
1570 AlphaSetStencil(s_bDestAlphaTest && bCanRenderStencil);
1571 AlphaSetDepthTest(curvb, curtest, pfragment); // Error!
1572 SetAlphaTest(curtest);
1573
1574 u32 oldabe = AlphaSetupBlendTest(curvb); // Unavoidable
1575
1576 // needs to be before RenderAlphaTest
1577 AlphaRenderFBA(curvb, pfragment, s_bDestAlphaTest, bCanRenderStencil);
1578
1579 dwUsingSpecialTesting = AlphaRenderAlpha(curvb, curtest, pfragment, exactcolor); // Unavoidable
1580 AlphaRenderStencil(curvb, s_bDestAlphaTest, bCanRenderStencil, dwUsingSpecialTesting);
1581 AlphaTest(curvb); // Unavoidable
1582 AlphaPabe(curvb, pfragment, exactcolor);
1583 AlphaFailureTestJob(curvb, curtest, pfragment, exactcolor, bCanRenderStencil, oldabe);
1584 AlphaSpecialTesting(curvb, pfragment, dwUsingSpecialTesting, exactcolor);
1585 AlphaDestinationTest(curvb, pfragment, s_bDestAlphaTest, bCanRenderStencil);
1586 AlphaSaveTarget(curvb);
1587
1588 GL_REPORT_ERRORD();
1589
1590 AlphaColorClamping(curvb, curtest);
1591 FlushUndoFiter(dwFilterOpts);
1592
1593 ppf += curvb.nCount + 0x100000;
1594
1595 curvb.nCount = 0;
1596 curvb.curprim.abe = oldabe;
1597
1598 SwitchWireframeOn();
1599
1600 GL_REPORT_ERRORD();
1601 }
1602
1603 inline void ZeroGS::RenderFBA(const VB& curvb, CGparameter sOneColor)
1604 {
1605 // add fba to all pixels
1606 GL_STENCILFUNC(GL_ALWAYS, STENCIL_FBA, 0xff);
1607 glStencilMask(STENCIL_CLEAR);
1608 glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE);
1609
1610 glDisable(GL_DEPTH_TEST);
1611 glDepthMask(0);
1612 glColorMask(0, 0, 0, 0);
1613
1614 if (s_bWriteDepth) ResetRenderTarget(1);
1615
1616 SetShaderCaller("RenderFBA");
1617
1618 glEnable(GL_ALPHA_TEST);
1619
1620 glAlphaFunc(GL_GEQUAL, 1);
1621
1622 Vector v(1,2,0,0);
1623
1624 ZZcgSetParameter4fv(sOneColor, v, "g_fOneColor");
1625
1626 DRAW();
1627
1628 SetAlphaTest(curvb.test);
1629
1630 // reset (not necessary)
1631 GL_COLORMASK(s_dwColorWrite);
1632
1633 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1634
1635 if (!curvb.zbuf.zmsk)
1636 {
1637 glDepthMask(1);
1638
1639 assert(curvb.pdepth != NULL);
1640
1641 if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1);
1642 }
1643
1644 GL_ZTEST(curvb.test.zte);
1645 }
1646
1647 __forceinline void ZeroGS::RenderAlphaTest(const VB& curvb, CGparameter sOneColor)
1648 {
1649 if (!g_bUpdateStencil) return;
1650
1651 if ((curvb.test.ate) && (curvb.test.afail == 1)) glDisable(GL_ALPHA_TEST);
1652
1653 glDepthMask(0);
1654
1655 glColorMask(0, 0, 0, 0);
1656
1657 if (s_bWriteDepth) ResetRenderTarget(1);
1658
1659 SetShaderCaller("RenderAlphaTest");
1660
1661 Vector v(1,2,0,0);
1662
1663 ZZcgSetParameter4fv(sOneColor, v, "g_fOneColor");
1664
1665 // or a 1 to the stencil buffer wherever alpha passes
1666 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1667
1668 s_stencilfunc = GL_ALWAYS;
1669
1670 glEnable(GL_STENCIL_TEST);
1671
1672 if (!s_bDestAlphaTest)
1673 {
1674 // clear everything
1675 s_stencilref = 0;
1676 glStencilMask(STENCIL_CLEAR);
1677 glDisable(GL_ALPHA_TEST);
1678 GL_STENCILFUNC_SET();
1679 DRAW();
1680
1681 if (curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING) glEnable(GL_ALPHA_TEST);
1682 }
1683
1684 if (curvb.test.ate && curvb.test.atst > 1 && curvb.test.aref > 0x80)
1685 {
1686 v = Vector(1,1,0,0);
1687 ZZcgSetParameter4fv(sOneColor, v, "g_fOneColor");
1688 glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], AlphaReferedValue(curvb.test.aref));
1689 }
1690
1691 s_stencilref = STENCIL_SPECIAL;
1692
1693 glStencilMask(STENCIL_SPECIAL);
1694 GL_STENCILFUNC_SET();
1695 glDisable(GL_DEPTH_TEST);
1696
1697 DRAW();
1698
1699 if (curvb.test.zte) glEnable(GL_DEPTH_TEST);
1700
1701 GL_ALPHATEST(0);
1702
1703 GL_COLORMASK(s_dwColorWrite);
1704
1705 if (!curvb.zbuf.zmsk)
1706 {
1707 glDepthMask(1);
1708
1709 // set rt next level
1710
1711 if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1);
1712 }
1713 }
1714
1715 inline void ZeroGS::RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting)
1716 {
1717 //NOTE: This stencil hack for dest alpha testing ONLY works when
1718 // the geometry in one DrawPrimitive call does not overlap
1719
1720 // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff)
1721 // mark 4 if a pixel was written (so that the stencil buf can be changed with new values)
1722 glStencilMask(STENCIL_PIXELWRITE);
1723 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1724
1725 s_stencilmask = (curvb.test.date ? STENCIL_ALPHABIT : 0) | (dwUsingSpecialTesting ? STENCIL_SPECIAL : 0);
1726 s_stencilfunc = s_stencilmask ? GL_EQUAL : GL_ALWAYS;
1727
1728 s_stencilref = curvb.test.date * curvb.test.datm | STENCIL_PIXELWRITE | (dwUsingSpecialTesting ? STENCIL_SPECIAL : 0);
1729 GL_STENCILFUNC_SET();
1730 }
1731
1732 inline void ZeroGS::ProcessStencil(const VB& curvb)
1733 {
1734 assert(!curvb.fba.fba);
1735
1736 // set new alpha bit
1737 glStencilMask(STENCIL_ALPHABIT);
1738 GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE, STENCIL_PIXELWRITE | STENCIL_FBA);
1739 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1740
1741 glDisable(GL_DEPTH_TEST);
1742 glDepthMask(0);
1743 glColorMask(0, 0, 0, 0);
1744
1745 if (s_bWriteDepth) ResetRenderTarget(1);
1746
1747 GL_ALPHATEST(0);
1748
1749 SetShaderCaller("ProcessStencil");
1750
1751 SETPIXELSHADER(ppsOne.prog);
1752 DRAW();
1753
1754 // process when alpha >= 0xff
1755 GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE | STENCIL_FBA | STENCIL_ALPHABIT, STENCIL_PIXELWRITE | STENCIL_FBA);
1756 DRAW();
1757
1758 // clear STENCIL_PIXELWRITE bit
1759 glStencilMask(STENCIL_CLEAR);
1760
1761 GL_STENCILFUNC(GL_ALWAYS, 0, STENCIL_PIXELWRITE | STENCIL_FBA);
1762 DRAW();
1763
1764 // restore state
1765 GL_COLORMASK(s_dwColorWrite);
1766
1767 if (curvb.test.ate && USEALPHATESTING) glEnable(GL_ALPHA_TEST);
1768
1769 if (!curvb.zbuf.zmsk)
1770 {
1771 glDepthMask(1);
1772
1773 if (s_bWriteDepth)
1774 {
1775 assert(curvb.pdepth != NULL);
1776 curvb.pdepth->SetRenderTarget(1);
1777 }
1778 }
1779
1780 GL_ZTEST(curvb.test.zte);
1781
1782 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1783 }
1784
1785 __forceinline void ZeroGS::ProcessFBA(const VB& curvb, CGparameter sOneColor)
1786 {
1787 if ((curvb.frame.fbm&0x80000000)) return;
1788
1789 // add fba to all pixels that were written and alpha was less than 0xff
1790 glStencilMask(STENCIL_ALPHABIT);
1791 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1792 GL_STENCILFUNC(GL_EQUAL, STENCIL_FBA | STENCIL_PIXELWRITE | STENCIL_ALPHABIT, STENCIL_PIXELWRITE | STENCIL_FBA);
1793 glDisable(GL_DEPTH_TEST);
1794
1795 glDepthMask(0);
1796 glColorMask(0, 0, 0, 1);
1797
1798 if (s_bWriteDepth) ResetRenderTarget(1);
1799
1800 SetShaderCaller("ProcessFBA");
1801
1802 // processes the pixels with ALPHA < 0x80*2
1803 glEnable(GL_ALPHA_TEST);
1804 glAlphaFunc(GL_LEQUAL, 1);
1805
1806 // add 1 to dest
1807 GL_BLEND_ALPHA(GL_ONE, GL_ONE);
1808 GL_BLENDEQ_ALPHA(GL_FUNC_ADD);
1809
1810 float f = 1;
1811 ZZcgSetParameter4fv(sOneColor, &f, "g_fOneColor");
1812 SETPIXELSHADER(ppsOne.prog);
1813 DRAW();
1814 glDisable(GL_ALPHA_TEST);
1815
1816 // reset bits
1817 glStencilMask(STENCIL_CLEAR);
1818 GL_STENCILFUNC(GL_GREATER, 0, STENCIL_PIXELWRITE | STENCIL_FBA);
1819 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
1820 DRAW();
1821
1822 if (curvb.test.atst && USEALPHATESTING)
1823 {
1824 glEnable(GL_ALPHA_TEST);
1825 glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], AlphaReferedValue(curvb.test.aref));
1826 }
1827
1828 // restore (SetAlphaVariables)
1829 GL_BLEND_ALPHA(GL_ONE, GL_ZERO);
1830
1831 if (vAlphaBlendColor.y < 0) GL_BLENDEQ_ALPHA(GL_FUNC_REVERSE_SUBTRACT);
1832
1833 // reset (not necessary)
1834 GL_COLORMASK(s_dwColorWrite);
1835
1836 if (!curvb.zbuf.zmsk)
1837 {
1838 glDepthMask(1);
1839
1840 if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1);
1841 }
1842
1843 GL_ZTEST(curvb.test.zte);
1844 }
1845
1846 void ZeroGS::SetContextTarget(int context)
1847 {
1848 FUNCLOG
1849 VB& curvb = vb[context];
1850 GL_REPORT_ERRORD();
1851
1852 if (curvb.prndr == NULL)
1853 curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, get_maxheight(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm));
1854
1855 // make sure targets are valid
1856 if (curvb.pdepth == NULL)
1857 {
1858 frameInfo f;
1859 f.fbp = curvb.zbuf.zbp;
1860 f.fbw = curvb.frame.fbw;
1861 f.fbh = curvb.prndr->fbh;
1862 f.psm = curvb.zbuf.psm;
1863 f.fbm = 0;
1864 curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer | CRenderTargetMngr::TO_StrictHeight |
1865 (curvb.zbuf.zmsk ? CRenderTargetMngr::TO_Virtual : 0), get_maxheight(curvb.zbuf.zbp, curvb.gsfb.fbw, 0));
1866 }
1867
1868 assert(curvb.prndr != NULL && curvb.pdepth != NULL);
1869
1870 assert(curvb.pdepth->fbh == curvb.prndr->fbh);
1871
1872 if (curvb.pdepth->status & CRenderTarget::TS_Virtual)
1873 {
1874
1875 if (!curvb.zbuf.zmsk)
1876 {
1877 CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp | (curvb.pdepth->fbw << 16));
1878 assert(ptemp == curvb.pdepth);
1879 }
1880 else
1881 {
1882 curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate;
1883 }
1884 }
1885
1886 bool bSetTarg = 1;
1887
1888 if (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate)
1889 {
1890 assert(!(curvb.pdepth->status & CRenderTarget::TS_Virtual));
1891
1892 // don't update if virtual
1893 curvb.pdepth->Update(context, curvb.prndr);
1894 bSetTarg = 0;
1895 }
1896
1897 GL_REPORT_ERRORD();
1898
1899 if (curvb.prndr->status & CRenderTarget::TS_NeedUpdate)
1900 {
1901 /* if(bSetTarg) {
1902 * printf ( " Here\n ");
1903 * if(s_bWriteDepth) {
1904 * curvb.pdepth->SetRenderTarget(1);
1905 * curvb.pdepth->SetDepthStencilSurface();
1906 * }
1907 * else
1908 * curvb.pdepth->SetDepthStencilSurface();
1909 * }*/
1910 curvb.prndr->Update(context, curvb.pdepth);
1911 }
1912 else
1913 {
1914
1915 //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg )
1916 curvb.prndr->SetRenderTarget(0);
1917 //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) )
1918 curvb.pdepth->SetDepthStencilSurface();
1919
1920 if (conf.mrtdepth && ZeroGS::IsWriteDepth()) curvb.pdepth->SetRenderTarget(1);
1921 if (s_ptexCurSet[0] == curvb.prndr->ptex) s_ptexCurSet[0] = 0;
1922 if (s_ptexCurSet[1] == curvb.prndr->ptex) s_ptexCurSet[1] = 0;
1923
1924 curvb.prndr->SetViewport();
1925 }
1926
1927 curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context);
1928
1929 if ((curvb.zbuf.zbp - curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte)
1930 ZZLog::Warn_Log("Frame and zbuf not aligned.");
1931
1932 curvb.bVarsSetTarg = true;
1933
1934 if (vb[!context].prndr != curvb.prndr) vb[!context].bVarsSetTarg = false;
1935
1936 assert(!(curvb.prndr->status&CRenderTarget::TS_NeedUpdate));
1937 assert(curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate));
1938
1939 GL_REPORT_ERRORD();
1940 }
1941
1942
1943 void ZeroGS::SetTexInt(int context, FRAGMENTSHADER* pfragment, int settexint)
1944 {
1945 FUNCLOG
1946
1947 if (settexint)
1948 {
1949 tex0Info& tex0 = vb[context].tex0;
1950
1951 CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(tex0, 1);
1952
1953 if (vb[context].bVarsTexSync)
1954 {
1955 if (vb[context].pmemtarg != pmemtarg)
1956 {
1957 SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush);
1958 vb[context].bVarsTexSync = true;
1959 }
1960 }
1961 else
1962 {
1963 SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush);
1964 vb[context].bVarsTexSync = true;
1965
1966 INC_TEXVARS();
1967 }
1968 }
1969 else
1970 {
1971 vb[context].bVarsTexSync = false;
1972 }
1973 }
1974
1975 // clamp relies on texture width
1976 void ZeroGS::SetTexClamping(int context, FRAGMENTSHADER* pfragment)
1977 {
1978 FUNCLOG
1979 SetShaderCaller("SetTexClamping");
1980 clampInfo* pclamp = &ZeroGS::vb[context].clamp;
1981 Vector v, v2;
1982 v.x = v.y = 0;
1983 u32* ptex = ZeroGS::vb[context].ptexClamp;
1984 ptex[0] = ptex[1] = 0;
1985
1986 float fw = ZeroGS::vb[context].tex0.tw ;
1987 float fh = ZeroGS::vb[context].tex0.th ;
1988
1989 switch (pclamp->wms)
1990 {
1991 case 0:
1992 v2.x = -1e10;
1993 v2.z = 1e10;
1994 break;
1995
1996 case 1: // pclamp
1997 // suikoden5 movie text
1998 v2.x = 0;
1999 v2.z = 1 - 0.5f / fw;
2000 break;
2001
2002 case 2: // reg pclamp
2003 v2.x = (pclamp->minu + 0.5f) / fw;
2004 v2.z = (pclamp->maxu - 0.5f) / fw;
2005 break;
2006
2007 case 3: // region rep x
2008 v.x = 0.9999f;
2009 v.z = fw;
2010 v2.x = (float)GPU_TEXMASKWIDTH / fw;
2011 v2.z = pclamp->maxu / fw;
2012 int correctMinu = pclamp->minu & (~pclamp->maxu); // (A && B) || C == (A && (B && !C)) + C
2013
2014 if (correctMinu != g_PrevBitwiseTexX)
2015 {
2016 g_PrevBitwiseTexX = correctMinu;
2017 ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(correctMinu, 0);
2018 }
2019
2020 break;
2021 }
2022
2023 switch (pclamp->wmt)
2024 {
2025
2026 case 0:
2027 v2.y = -1e10;
2028 v2.w = 1e10;
2029 break;
2030
2031 case 1: // pclamp
2032 // suikoden5 movie text
2033 v2.y = 0;
2034 v2.w = 1 - 0.5f / fh;
2035 break;
2036
2037 case 2: // reg pclamp
2038 v2.y = (pclamp->minv + 0.5f) / fh;
2039 v2.w = (pclamp->maxv - 0.5f) / fh;
2040 break;
2041
2042 case 3: // region rep y
2043 v.y = 0.9999f;
2044 v.w = fh;
2045 v2.y = (float)GPU_TEXMASKWIDTH / fh;
2046 v2.w = pclamp->maxv / fh;
2047 int correctMinv = pclamp->minv & (~pclamp->maxv); // (A && B) || C == (A && (B && !C)) + C
2048
2049 if (correctMinv != g_PrevBitwiseTexY)
2050 {
2051 g_PrevBitwiseTexY = correctMinv;
2052 ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(correctMinv, ptex[0]);
2053 }
2054 break;
2055 }
2056
2057 if (pfragment->fTexWrapMode != 0)
2058 ZZcgSetParameter4fv(pfragment->fTexWrapMode, v, "g_fTexWrapMode");
2059
2060 if (pfragment->fClampExts != 0)
2061 ZZcgSetParameter4fv(pfragment->fClampExts, v2, "g_fClampExts");
2062
2063
2064 }
2065
2066 // Fixme should be in Vector lib
2067 inline bool equal_vectors(Vector a, Vector b)
2068 {
2069 if (abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w) < 0.01)
2070 return true;
2071 else
2072 return false;
2073 }
2074
2075 int CheckTexArray[4][2][2][2] = {{{{0, }}}};
2076 void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment)
2077 {
2078 FUNCLOG
2079
2080 if (!vb[context].curprim.tme) return;
2081
2082 assert(!vb[context].bNeedTexCheck);
2083
2084 Vector v, v2;
2085
2086 tex0Info& tex0 = vb[context].tex0;
2087
2088 //float fw = (float)tex0.tw;
2089 //float fh = (float)tex0.th;
2090
2091 if (!vb[context].bTexConstsSync)
2092 {
2093 SetShaderCaller("SetTexVariables");
2094
2095 // alpha and texture highlighting
2096 Vector valpha, valpha2 ;
2097
2098 // if clut, use the frame format
2099 int psm = GetTexCPSM(tex0);
2100
2101 // printf ( "A %d psm, is-clut %d. cpsm %d | %d %d\n", psm, PSMT_ISCLUT(psm), tex0.cpsm, tex0.tfx, tex0.tcc );
2102
2103 Vector vblack;
2104 vblack.x = vblack.y = vblack.z = vblack.w = 10;
2105
2106 /* tcc -- Tecture Color Component 0=RGB, 1=RGBA + use Alpha from TEXA reg when not in PSM
2107 * tfx -- Texture Function (0=modulate, 1=decal, 2=hilight, 3=hilight2)
2108 *
2109 * valpha2 = 0 0 2 1 0 0 2 1
2110 * 1 0 0 0 1 1 0 0
2111 * 0 0 2 0 0 1 2 0
2112 * 0 0 2 0 0 1 2 0
2113 *
2114 * 0 1,!nNeed 1, psm=2, 10 1, psm=1
2115 * valpha = 0 0 0 1 0 2 0 0 2ta0 2ta1-2ta0 0 0 2ta0 0 0 0
2116 * 0 0 0 1 0 1 0 0 ta0 ta1-ta0 0 0 ta0 0 0 0
2117 * 0 0 1 1 0 1 1 1 1 1 ta0 0 1 1
2118 * 0 0 1 1 0 1 1 0 1 0 ta0 0 1 0
2119 */
2120
2121 valpha2.x = (tex0.tfx == 1) ;
2122 valpha2.y = (tex0.tcc == 1) && (tex0.tfx != 0) ;
2123 valpha2.z = (tex0.tfx != 1) * 2 ;
2124 valpha2.w = (tex0.tfx == 0) ;
2125
2126 if (tex0.tcc == 0 || !nNeedAlpha(psm))
2127 {
2128 valpha.x = 0 ;
2129 valpha.y = (!!tex0.tcc) * (1 + (tex0.tfx == 0)) ;
2130 }
2131 else
2132 {
2133 valpha.x = (gs.texa.fta[0]) * (1 + (tex0.tfx == 0)) ;
2134 valpha.y = (gs.texa.fta[psm!=1] - gs.texa.fta[0]) * (1 + (tex0.tfx == 0)) ;
2135 }
2136
2137 valpha.z = (tex0.tfx >= 3) ;
2138
2139 valpha.w = (tex0.tcc == 0) || (tex0.tcc == 1 && tex0.tfx == 2) ;
2140
2141 if (tex0.tcc && gs.texa.aem && psm == PSMCT24)
2142 vblack.w = 0;
2143
2144 /*
2145 // Test, old code.
2146 Vector valpha3, valpha4;
2147 switch(tex0.tfx) {
2148 case 0:
2149 valpha3.z = 0; valpha3.w = 0;
2150 valpha4.x = 0; valpha4.y = 0;
2151 valpha4.z = 2; valpha4.w = 1;
2152
2153 break;
2154 case 1:
2155 valpha3.z = 0; valpha3.w = 1;
2156 valpha4.x = 1; valpha4.y = 0;
2157 valpha4.z = 0; valpha4.w = 0;
2158
2159 break;
2160 case 2:
2161 valpha3.z = 1; valpha3.w = 1.0f;
2162 valpha4.x = 0; valpha4.y = tex0.tcc ? 1.0f : 0.0f;
2163 valpha4.z = 2; valpha4.w = 0;
2164
2165 break;
2166
2167 case 3:
2168 valpha3.z = 1; valpha3.w = tex0.tcc ? 0.0f : 1.0f;
2169 valpha4.x = 0; valpha4.y = tex0.tcc ? 1.0f : 0.0f;
2170 valpha4.z = 2; valpha4.w = 0;
2171
2172 break;
2173 }
2174 if( tex0.tcc ) {
2175
2176 if( tex0.tfx == 1 ) {
2177 //mode.x = 10;
2178 valpha3.z = 0; valpha3.w = 0;
2179 valpha4.x = 1; valpha4.y = 1;
2180 valpha4.z = 0; valpha4.w = 0;
2181 }
2182
2183 if( nNeedAlpha(psm) ) {
2184
2185 if( tex0.tfx == 0 ) {
2186 // make sure alpha is mult by two when the output is Cv = Ct*Cf
2187 valpha3.x = 2*gs.texa.fta[0];
2188 // if 24bit, always choose ta[0]
2189 valpha3.y = 2*gs.texa.fta[psm != 1];
2190 valpha3.y -= valpha.x;
2191 }
2192 else {
2193 valpha3.x = gs.texa.fta[0];
2194 // if 24bit, always choose ta[0]
2195 valpha3.y = gs.texa.fta[psm != 1];
2196 valpha3.y -= valpha.x;
2197 }
2198 }
2199 else {
2200 if( tex0.tfx == 0 ) {
2201 valpha3.x = 0;
2202 valpha3.y = 2;
2203 }
2204 else {
2205 valpha3.x = 0;
2206 valpha3.y = 1;
2207 }
2208 }
2209 }
2210 else {
2211
2212 // reset alpha to color
2213 valpha3.x = valpha3.y = 0;
2214 valpha3.w = 1;
2215 }
2216
2217 if ( equal_vectors(valpha, valpha3) && equal_vectors(valpha2, valpha4) ) {
2218 if (CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm)] == 0) {
2219 printf ( "Good issue %d %d %d %d\n", tex0.tfx, tex0.tcc, psm, nNeedAlpha(psm) );
2220 CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm) ] = 1;
2221 }
2222 }
2223 else if (CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm)] == -1) {
2224 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",
2225 tex0.tfx, tex0.tcc, psm, nNeedAlpha(psm),
2226 valpha3.x, valpha3.y, valpha3.z, valpha3.w, valpha4.x, valpha4.y, valpha4.z, valpha4.w,
2227 valpha.x, valpha.y, valpha.z, valpha.w, valpha2.x, valpha2.y, valpha2.z, valpha2.w);
2228 CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][nNeedAlpha(psm)] = -1 ;
2229 }
2230
2231 // Test;*/
2232
2233 ZZcgSetParameter4fv(pfragment->fTexAlpha, valpha, "g_fTexAlpha");
2234 ZZcgSetParameter4fv(pfragment->fTexAlpha2, valpha2, "g_fTexAlpha2");
2235
2236 if (tex0.tcc && gs.texa.aem && nNeedAlpha(psm))
2237 ZZcgSetParameter4fv(pfragment->fTestBlack, vblack, "g_fTestBlack");
2238
2239 SetTexClamping(context, pfragment);
2240
2241 vb[context].bTexConstsSync = true;
2242 }
2243
2244 if (s_bTexFlush)
2245 {
2246 if (PSMT_ISCLUT(tex0.psm))
2247 texClutWrite(context);
2248 else
2249 s_bTexFlush = false;
2250 }
2251 }
2252
2253 void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force)
2254 {
2255 FUNCLOG
2256 Vector v;
2257 assert(pmemtarg != NULL && pfragment != NULL && pmemtarg->ptex != NULL);
2258
2259 if (pmemtarg == NULL || pfragment == NULL || pmemtarg->ptex == NULL)
2260 {
2261 printf("SetTexVariablesInt error\n");
2262 return;
2263 }
2264
2265 SetShaderCaller("SetTexVariablesInt");
2266
2267 float fw = (float)tex0.tw;
2268 float fh = (float)tex0.th;
2269
2270 bool bUseBilinear = bilinear > 1 || (bilinear && conf.bilinear);
2271
2272 if (bUseBilinear)
2273 {
2274 v.x = (float)fw;
2275 v.y = (float)fh;
2276 v.z = 1.0f / (float)fw;
2277 v.w = 1.0f / (float)fh;
2278
2279 if (pfragment->fRealTexDims)
2280 ZZcgSetParameter4fv(pfragment->fRealTexDims, v, "g_fRealTexDims");
2281 else
2282 ZZcgSetParameter4fv(cgGetNamedParameter(pfragment->prog, "g_fRealTexDims"), v, "g_fRealTexDims");
2283 }
2284
2285 if (m_Blocks[tex0.psm].bpp == 0)
2286 {
2287 ZZLog::Error_Log("Undefined tex psm 0x%x!", tex0.psm);
2288 return;
2289 }
2290
2291 const BLOCK& b = m_Blocks[tex0.psm];
2292
2293 float fbw = (float)tex0.tbw;
2294
2295 Vector vTexDims;
2296
2297 vTexDims.x = b.vTexDims.x * (fw);
2298 vTexDims.y = b.vTexDims.y * (fh);
2299 vTexDims.z = (float)BLOCK_TEXWIDTH * (0.002f / 64.0f + 0.01f / 128.0f);
2300 vTexDims.w = (float)BLOCK_TEXHEIGHT * 0.1f / 512.0f;
2301
2302 if (bUseBilinear)
2303 {
2304 vTexDims.x *= 1 / 128.0f;
2305 vTexDims.y *= 1 / 512.0f;
2306 vTexDims.z *= 1 / 128.0f;
2307 vTexDims.w *= 1 / 512.0f;
2308 }
2309
2310 float g_fitexwidth = g_fiGPU_TEXWIDTH / (float)pmemtarg->widthmult;
2311
2312 //float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult;
2313
2314 float fpage = tex0.tbp0 * (64.0f * g_fitexwidth);// + 0.05f * g_fitexwidth;
2315 float fpageint = floorf(fpage);
2316 //int starttbp = (int)fpage;
2317
2318 // 2048 is number of words to span one page
2319 //float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw;
2320
2321 float fblockstride = (2048.0f / (float)(GPU_TEXWIDTH * (float)pmemtarg->widthmult * BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw;
2322
2323 assert(fblockstride >= 1.0f);
2324
2325 v.x = (float)(2048 * g_fitexwidth);
2326 v.y = fblockstride;
2327 v.z = g_fBlockMult / (float)pmemtarg->widthmult;
2328 v.w = fpage - fpageint ;
2329
2330 if (g_fBlockMult > 1)
2331 {
2332 // make sure to divide by mult (since the G16R16 texture loses info)
2333 v.z *= b.bpp * (1 / 32.0f);
2334 }
2335
2336 ZZcgSetParameter4fv(pfragment->fTexDims, vTexDims, "g_fTexDims");
2337
2338 // ZZcgSetParameter4fv(pfragment->fTexBlock, b.vTexBlock, "g_fTexBlock"); // I change it, and it's working. Seems casting from Vector to float[4] is ok.
2339 ZZcgSetParameter4fv(pfragment->fTexBlock, &b.vTexBlock.x, "g_fTexBlock");
2340 ZZcgSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset");
2341
2342 // get hardware texture dims
2343 //int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult;
2344 int texwidth = GPU_TEXWIDTH * pmemtarg->widthmult * pmemtarg->channels;
2345
2346 v.y = 1.0f;
2347 v.x = (fpageint - (float)pmemtarg->realy / (float)pmemtarg->widthmult + 0.5f);//*v.y;
2348 v.z = (float)texwidth;
2349
2350 /* if( !(g_nPixelShaderVer & SHADER_ACCURATE) || bUseBilinear ) {
2351 if (tex0.psm == PSMT4 )
2352 v.w = 0.0f;
2353 else
2354 v.w = 0.25f;
2355 }
2356 else
2357 v.w = 0.5f;*/
2358 v.w = 0.5f;
2359
2360 ZZcgSetParameter4fv(pfragment->fPageOffset, v, "g_fPageOffset");
2361
2362 if (force)
2363 s_ptexCurSet[context] = pmemtarg->ptex->tex;
2364 else
2365 s_ptexNextSet[context] = pmemtarg->ptex->tex;
2366
2367 vb[context].pmemtarg = pmemtarg;
2368
2369 vb[context].bVarsTexSync = false;
2370 }
2371
2372 #define SET_ALPHA_COLOR_FACTOR(sign) \
2373 { \
2374 switch(a.c) \
2375 { \
2376 case 0: \
2377 vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \
2378 s_srcalpha = GL_ONE; \
2379 s_alphaeq = (sign) ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT; \
2380 break; \
2381 \
2382 case 1: \
2383 /* if in 24 bit mode, dest alpha should be one */ \
2384 switch(PSMT_BITMODE(vb[icurctx].prndr->psm)) \
2385 { \
2386 case 0: \
2387 bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \
2388 break; \
2389 \
2390 case 1: \
2391 /* dest alpha should be one */ \
2392 bDestAlphaColor = 2; \
2393 break; \
2394 /* default: 16bit surface, so returned alpha is ok */ \
2395 } \
2396 break; \
2397 \
2398 case 2: \
2399 bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \
2400 vAlphaBlendColor.y = 0; \
2401 vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \
2402 usec = 0; /* change so that alpha comes from source*/ \
2403 break; \
2404 } \
2405 } \
2406
2407 //if( a.fix <= 0x80 ) { \
2408 // dwTemp = (a.fix*2)>255?255:(a.fix*2); \
2409 // dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \
2410 // printf("bfactor: %8.8x\n", dwTemp); \
2411 // glBlendColorEXT(dwTemp); \
2412 // } \
2413 // else { \
2414
2415 void ZeroGS::ResetAlphaVariables() {
2416 FUNCLOG
2417 }
2418
2419 inline void ZeroGS::NeedFactor(int w)
2420 {
2421 if (bDestAlphaColor == 2)
2422 {
2423 bNeedBlendFactorInAlpha = (w + 1) ? 1 : 0;
2424 vAlphaBlendColor.y = 0;
2425 vAlphaBlendColor.w = (float)w;
2426 }
2427 }
2428
2429 //static int CheckArray[48][2] = {{0,}};
2430
2431 void ZeroGS::SetAlphaVariables(const alphaInfo& a)
2432 {
2433 FUNCLOG
2434 bool alphaenable = true;
2435
2436 // TODO: negative color when not clamping turns to positive???
2437 g_vars._bAlphaState = 0; // set all to zero
2438 bNeedBlendFactorInAlpha = 0;
2439 b2XAlphaTest = 1;
2440 //u32 dwTemp = 0xffffffff;
2441 bDestAlphaColor = 0;
2442
2443 // default
2444 s_srcalpha = GL_ONE;
2445 s_dstalpha = GL_ZERO;
2446 s_alphaeq = GL_FUNC_ADD;
2447 s_rgbeq = 1;
2448
2449 s_alphaInfo = a;
2450 vAlphaBlendColor = Vector(1, 2 * 255.0f / 256.0f, 0, 0);
2451 u32 usec = a.c;
2452
2453
2454 /*
2455 * Alpha table
2456 * a + b + d
2457 * S D
2458 * 0 a -a 1 | 0 0 0
2459 * 1 0 0 0 | a -a 1
2460 * 2 0 0 0 | 0 0 0
2461 *
2462 * d = 0 Cs
2463 * a b 0 Cs 1 Cd 2 0
2464 * | |
2465 * 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
2466 * 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
2467 * 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
2468 *
2469 * d = 1 Cd
2470 * 0 | 1 | 2
2471 * 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
2472 * 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)
2473 * 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
2474 *
2475 * d = 2 0
2476 * 0 | 1 | 2
2477 * 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
2478 * 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
2479 * 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
2480 *
2481 * Formulae is: (a-b) * (c /32) + d
2482 * 0 1 2
2483 * a Cs Cd 0
2484 * b Cs Cd 0
2485 * c As Ad ALPHA.FIX
2486 * d Cs Cd 0
2487 *
2488 * We want to emulate Cs * F1(alpha) + Cd * F2(alpha) by OpenGl blending: (Cs * Ss (+,-,R-) Cd * Sd)
2489 * SET_ALPHA_COLOR_FACTOR(sign) set Set A (as As>>7, Ad>>7 or FIX>>7) with sign.
2490 * So we could use 1+a as one_minus_alpha and -a as alpha.
2491 *
2492 */
2493 int code = (a.a * 16) + (a.b * 4) + a.d ;
2494
2495 #define one_minus_alpha (bDestAlphaColor == 2) ? GL_ONE_MINUS_SRC_ALPHA : blendinvalpha[usec]
2496 #define alpha (bDestAlphaColor == 2) ? GL_SRC_ALPHA : blendalpha[usec]
2497 #define one (bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec]
2498 #define zero (bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec]
2499
2500 switch (code)
2501 {
2502
2503 case 0: // 000 // Cs -- nothing changed
2504 case 20: // 110 = 16+4=20 // Cs
2505 case 40: // 220 = 32+8=40 // Cs
2506 {
2507 alphaenable = false;
2508 break;
2509 }
2510
2511 case 2: //002 // 0 -- should be zero
2512 case 22: //112 // 0
2513 case 42: //222 = 32+8+2 =42 // 0
2514 {
2515 s_rgbeq = GL_FUNC_ADD;
2516 s_srcrgb = GL_ZERO;
2517 s_dstrgb = GL_ZERO;
2518 break;
2519 }
2520
2521 case 1: //001 // Cd -- Should be destination alpha
2522 case 21: //111, // Cd -- 0*Source + 1*Desrinarion
2523 case 41: //221 = 32+8+1=41 // Cd --
2524 {
2525 s_rgbeq = GL_FUNC_ADD;
2526 s_srcrgb = GL_ZERO;
2527 s_dstrgb = GL_ONE;
2528 break;
2529 }
2530
2531 case 4: // 010 // (Cs-Cd)*A+Cs = Cs * (A + 1) - Cd * A
2532 {
2533 bAlphaClamping = 3;
2534 SET_ALPHA_COLOR_FACTOR(0); // a = -A
2535
2536 s_rgbeq = GL_FUNC_ADD; // Cs*(1-a)+Cd*a
2537 s_srcrgb = one_minus_alpha ;
2538 s_dstrgb = alpha;
2539
2540 NeedFactor(-1);
2541 break;
2542 }
2543
2544 case 5: // 011 // (Cs-Cd)*A+Cs = Cs * A + Cd * (1-A)
2545 {
2546 bAlphaClamping = 3; // all testing
2547 SET_ALPHA_COLOR_FACTOR(1);
2548
2549 s_rgbeq = GL_FUNC_ADD;
2550 s_srcrgb = alpha;
2551 s_dstrgb = one_minus_alpha;
2552
2553 NeedFactor(1);
2554 break;
2555 }
2556
2557 case 6: //012 // (Cs-Cd)*FIX
2558 {
2559 bAlphaClamping = 3;
2560 SET_ALPHA_COLOR_FACTOR(1);
2561
2562 s_rgbeq = GL_FUNC_SUBTRACT;
2563 s_srcrgb = alpha;
2564 s_dstrgb = alpha;
2565
2566 break;
2567 }
2568
2569 case 8: //020 // Cs*A+Cs = Cs * (1+A)
2570 {
2571 bAlphaClamping = 2; // max testing
2572 SET_ALPHA_COLOR_FACTOR(0); // Zeyflitz change this! a = -A
2573
2574 s_rgbeq = GL_FUNC_ADD;
2575 s_srcrgb = one_minus_alpha; // Cs*(1-a).
2576 s_dstrgb = GL_ZERO;
2577
2578 // NeedFactor(1);
2579 break;
2580 }
2581
2582 case 9: //021 // Cs*A+Cd
2583 {
2584 bAlphaClamping = 2; // max testing
2585 SET_ALPHA_COLOR_FACTOR(1);
2586
2587 s_rgbeq = GL_FUNC_ADD;
2588 s_srcrgb = alpha; // ZZ change it to.
2589 s_dstrgb = GL_ONE;
2590 break;
2591 }
2592
2593 case 10: //022 // Cs*A
2594 {
2595 bAlphaClamping = 2; // max testing
2596 SET_ALPHA_COLOR_FACTOR(1);
2597
2598 s_rgbeq = GL_FUNC_ADD;
2599 s_srcrgb = alpha;
2600 s_dstrgb = GL_ZERO;
2601 break;
2602 }
2603
2604 case 16: //100
2605 {
2606 bAlphaClamping = 3;
2607 SET_ALPHA_COLOR_FACTOR(1);
2608
2609 s_rgbeq = GL_FUNC_ADD;
2610 s_srcrgb = one_minus_alpha;
2611 s_dstrgb = alpha;
2612
2613 NeedFactor(1);
2614 break;
2615 }
2616
2617 case 17: //101
2618 {
2619 bAlphaClamping = 3; // all testing
2620 SET_ALPHA_COLOR_FACTOR(0);
2621
2622 s_rgbeq = GL_FUNC_ADD;
2623 s_srcrgb = alpha;
2624 s_dstrgb = one_minus_alpha;
2625
2626 NeedFactor(-1);
2627 break;
2628 }
2629
2630 case 18: //102
2631 {
2632 bAlphaClamping = 3;
2633 SET_ALPHA_COLOR_FACTOR(1);
2634
2635 s_rgbeq = GL_FUNC_REVERSE_SUBTRACT;
2636 s_srcrgb = alpha;
2637 s_dstrgb = alpha;
2638
2639 break;
2640 }
2641
2642 case 24: //120 = 16+8
2643 {
2644 bAlphaClamping = 2; // max testing
2645 SET_ALPHA_COLOR_FACTOR(1);
2646
2647 s_rgbeq = GL_FUNC_ADD;
2648 s_srcrgb = GL_ONE;
2649 s_dstrgb = alpha;
2650 break;
2651 }
2652
2653 case 25: //121 // Cd*(1+A)
2654 {
2655 bAlphaClamping = 2; // max testing
2656 SET_ALPHA_COLOR_FACTOR(0);
2657
2658 s_rgbeq = GL_FUNC_ADD;
2659 s_srcrgb = GL_ZERO;
2660 s_dstrgb = one_minus_alpha;
2661
2662 // NeedFactor(-1);
2663 break;
2664 }
2665
2666 case 26: //122
2667 {
2668 bAlphaClamping = 2;
2669 SET_ALPHA_COLOR_FACTOR(1);
2670
2671 s_rgbeq = GL_FUNC_ADD;
2672 s_srcrgb = GL_ZERO;
2673 s_dstrgb = alpha;
2674 break;
2675 }
2676
2677 case 32: // 200 = 32
2678 {
2679 bAlphaClamping = 1; // min testing
2680 SET_ALPHA_COLOR_FACTOR(1);
2681
2682 s_rgbeq = GL_FUNC_ADD;
2683 s_srcrgb = one_minus_alpha;
2684 s_dstrgb = GL_ZERO;
2685 break;
2686 }
2687
2688 case 33: //201 // -Cs*A + Cd
2689 {
2690 bAlphaClamping = 1; // min testing
2691 SET_ALPHA_COLOR_FACTOR(1);
2692
2693 s_rgbeq = GL_FUNC_REVERSE_SUBTRACT;
2694 s_srcrgb = alpha;
2695 s_dstrgb = GL_ONE;
2696 break;
2697 }
2698
2699 case 34: //202
2700 case 38: //212
2701 {
2702 bAlphaClamping = 1; // min testing -- negative values
2703
2704 s_rgbeq = GL_FUNC_ADD;
2705 s_srcrgb = GL_ZERO;
2706 s_dstrgb = GL_ZERO;
2707 break;
2708 }
2709
2710 case 36: //210
2711 {
2712 bAlphaClamping = 1; // min testing
2713 SET_ALPHA_COLOR_FACTOR(1);
2714
2715 s_rgbeq = GL_FUNC_SUBTRACT;
2716 s_srcrgb = GL_ONE;
2717 s_dstrgb = alpha;
2718 break;
2719 }
2720
2721 case 37: //211
2722 {
2723 bAlphaClamping = 1; // min testing
2724 SET_ALPHA_COLOR_FACTOR(1);
2725
2726 s_rgbeq = GL_FUNC_ADD;
2727 s_srcrgb = GL_ZERO;
2728 s_dstrgb = one_minus_alpha;
2729 break;
2730 }
2731
2732 default:
2733 {
2734 ZZLog::Error_Log("Bad alpha code %d | %d %d %d", code, a.a, a.b, a.d);
2735 }
2736 }
2737
2738 /*
2739 int t_rgbeq = GL_FUNC_ADD;
2740 int t_srcrgb = GL_ONE;
2741 int t_dstrgb = GL_ZERO;
2742 int tAlphaClamping = 0;
2743
2744 if( a.a == a.b )
2745 { // just d remains
2746 if( a.d == 0 ) {}
2747 else
2748 {
2749 t_dstrgb = a.d == 1 ? GL_ONE : GL_ZERO;
2750 t_srcrgb = GL_ZERO;
2751 t_rgbeq = GL_FUNC_ADD; //a) (001) (111) (221) b) (002) (112) (222)
2752 }
2753 goto EndSetAlpha;
2754 }
2755 else if( a.d == 2 )
2756 { // zero
2757 if( a.a == 2 )
2758 {
2759 // zero all color
2760 t_srcrgb = GL_ZERO;
2761 t_dstrgb = GL_ZERO;
2762 goto EndSetAlpha; // (202) (212)
2763 }
2764 else if( a.b == 2 )
2765 {
2766 //b2XAlphaTest = 1; // a) (022) // b) (122)
2767 SET_ALPHA_COLOR_FACTOR(1);
2768
2769 if( bDestAlphaColor == 2 )
2770 {
2771 t_rgbeq = GL_FUNC_ADD;
2772 t_srcrgb = a.a == 0 ? GL_ONE : GL_ZERO;
2773 t_dstrgb = a.a == 0 ? GL_ZERO : GL_ONE;
2774 }
2775 else
2776 {
2777 tAlphaClamping = 2;
2778 t_rgbeq = GL_FUNC_ADD;
2779 t_srcrgb = a.a == 0 ? blendalpha[usec] : GL_ZERO;
2780 t_dstrgb = a.a == 0 ? GL_ZERO : blendalpha[usec];
2781 }
2782
2783 goto EndSetAlpha;
2784 }
2785
2786 // nothing is zero, so must do some real blending //b2XAlphaTest = 1; //a) (012) //b) (102)
2787 tAlphaClamping = 3;
2788
2789 SET_ALPHA_COLOR_FACTOR(1);
2790
2791 t_rgbeq = a.a == 0 ? GL_FUNC_SUBTRACT : GL_FUNC_REVERSE_SUBTRACT;
2792 t_srcrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec];
2793 t_dstrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec];
2794 }
2795 else if( a.a == 2 )
2796 { // zero
2797
2798 //b2XAlphaTest = 1;
2799 tAlphaClamping = 1; // min testing
2800
2801 SET_ALPHA_COLOR_FACTOR(1);
2802
2803 if( a.b == a.d )
2804 {
2805 // can get away with 1-A
2806 // a.a == a.d == 2!! (200) (211)
2807 t_rgbeq = GL_FUNC_ADD;
2808 t_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : GL_ZERO;
2809 t_dstrgb = (a.b == 0 || bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec];
2810 }
2811 else
2812 {
2813 // a) (201) b)(210)
2814 t_rgbeq = a.b==0 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_SUBTRACT;
2815 t_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE;
2816 t_dstrgb = (a.b == 0 || bDestAlphaColor == 2 ) ? GL_ONE : blendalpha[usec];
2817 }
2818 }
2819 else if( a.b == 2 )
2820 {
2821 tAlphaClamping = 2; // max testing
2822
2823 SET_ALPHA_COLOR_FACTOR(a.a!=a.d);
2824
2825 if( a.a == a.d )
2826 {
2827 // can get away with 1+A, but need to set alpha to negative
2828 // a)(020)
2829 // b)(121)
2830 t_rgbeq = GL_FUNC_ADD;
2831
2832 if( bDestAlphaColor == 2 )
2833 {
2834 t_srcrgb = (a.a == 0) ? GL_ONE_MINUS_SRC_ALPHA : GL_ZERO;
2835 t_dstrgb = (a.a == 0) ? GL_ZERO : GL_ONE_MINUS_SRC_ALPHA;
2836 }
2837 else
2838 {
2839 t_srcrgb = a.a == 0 ? blendinvalpha[usec] : GL_ZERO;
2840 t_dstrgb = a.a == 0 ? GL_ZERO : blendinvalpha[usec];
2841 }
2842 }
2843 else
2844 {
2845 //a)(021) //b)(120) //b2XAlphaTest = 1;
2846 t_rgbeq = GL_FUNC_ADD;
2847 t_srcrgb = (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE;
2848 t_dstrgb = (a.a == 0 || bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec];
2849 }
2850 }
2851 else
2852 {
2853 // all 3 components are valid!
2854 tAlphaClamping = 3; // all testing
2855 SET_ALPHA_COLOR_FACTOR(a.a!=a.d);
2856
2857 if( a.a == a.d )
2858 {
2859 // can get away with 1+A, but need to set alpha to negative // a) 010, // b) 101
2860 t_rgbeq = GL_FUNC_ADD;
2861
2862 if( bDestAlphaColor == 2 )
2863 {
2864 // all ones
2865 t_srcrgb = a.a == 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA;
2866 t_dstrgb = a.a == 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA;
2867 }
2868 else
2869 {
2870 t_srcrgb = a.a == 0 ? blendinvalpha[usec] : blendalpha[usec];
2871 t_dstrgb = a.a == 0 ? blendalpha[usec] : blendinvalpha[usec];
2872 }
2873 }
2874 else
2875 {
2876 t_rgbeq = GL_FUNC_ADD; // a) 011 // b) 100 //
2877 if( bDestAlphaColor == 2 )
2878 {
2879 // all ones
2880 t_srcrgb = a.a != 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA;
2881 t_dstrgb = a.a != 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA;
2882 }
2883 else
2884 {
2885 //b2XAlphaTest = 1;
2886 t_srcrgb = a.a != 0 ? blendinvalpha[usec] : blendalpha[usec];
2887 t_dstrgb = a.a != 0 ? blendalpha[usec] : blendinvalpha[usec];
2888 }
2889 }
2890 }
2891 EndSetAlpha:
2892
2893
2894 if ( alphaenable && (t_rgbeq != s_rgbeq || s_srcrgb != t_srcrgb || t_dstrgb != s_dstrgb || tAlphaClamping != bAlphaClamping)) {
2895 if (CheckArray[code][(bDestAlphaColor==2)] != -1) {
2896 printf ( "A code %d, 0x%x, 0x%x, 0x%x, 0x%x %d\n", code, alpha, one_minus_alpha, one, zero, bDestAlphaColor );
2897 printf ( " Difference %d %d %d %d | 0x%x 0x%x | 0x%x 0x%x | 0x%x 0x%x | %d %d\n",
2898 code, a.a, a.b, a.d,
2899 t_rgbeq, s_rgbeq, t_srcrgb, s_srcrgb, t_dstrgb, s_dstrgb, tAlphaClamping, bAlphaClamping);
2900 CheckArray[code][(bDestAlphaColor==2)] = -1;
2901 }
2902 }
2903 else
2904 if (CheckArray[code][(bDestAlphaColor==2)] == 0){
2905 printf ( "Add good code %d %d, psm %d destA %d\n", code, a.c, vb[icurctx].prndr->psm, bDestAlphaColor);
2906 CheckArray[code][(bDestAlphaColor==2)] = 1;
2907 }*/
2908
2909
2910 if (alphaenable)
2911 {
2912 zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha);
2913 zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq);
2914 glEnable(GL_BLEND); // always set
2915 }
2916 else
2917 {
2918 glDisable(GL_BLEND);
2919 }
2920
2921 INC_ALPHAVARS();
2922 }
2923
2924 void ZeroGS::SetWriteDepth()
2925 {
2926 FUNCLOG
2927
2928 if (conf.mrtdepth)
2929 {
2930 s_bWriteDepth = true;
2931 s_nWriteDepthCount = 4;
2932 }
2933 }
2934
2935 bool ZeroGS::IsWriteDepth()
2936 {
2937 FUNCLOG
2938 return s_bWriteDepth;
2939 }
2940
2941 bool ZeroGS::IsWriteDestAlphaTest()
2942 {
2943 FUNCLOG
2944 return s_bDestAlphaTest;
2945 }
2946
2947 void ZeroGS::SetDestAlphaTest()
2948 {
2949 FUNCLOG
2950 s_bDestAlphaTest = true;
2951 s_nWriteDestAlphaTest = 4;
2952 }
2953
2954 void ZeroGS::SetTexFlush()
2955 {
2956 FUNCLOG
2957 s_bTexFlush = true;
2958
2959 // if( PSMT_ISCLUT(vb[0].tex0.psm) )
2960 // texClutWrite(0);
2961 // if( PSMT_ISCLUT(vb[1].tex0.psm) )
2962 // texClutWrite(1);
2963
2964 if (!s_bForceTexFlush)
2965 {
2966 if (s_ptexCurSet[0] != s_ptexNextSet[0]) s_ptexCurSet[0] = s_ptexNextSet[0];
2967 if (s_ptexCurSet[1] != s_ptexNextSet[1]) s_ptexCurSet[1] = s_ptexNextSet[1];
2968 }
2969 }
2970

  ViewVC Help
Powered by ViewVC 1.1.22