1 /*
2 Copyright (C) 2003 Rice1964
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 */
19
20 #define M64P_PLUGIN_PROTOTYPES 1
21 #include <stdint.h>
22
23 #include <retro_miscellaneous.h>
24
25 #include "osal_preproc.h"
26 #include "m64p_plugin.h"
27
28 #include "ConvertImage.h"
29 #include "DeviceBuilder.h"
30 #include "FrameBuffer.h"
31 #include "Render.h"
32
33 #include <algorithm>
34
35 extern FiddledVtx * g_pVtxBase;
36 CRender * CRender::g_pRender=NULL;
37 int CRender::gRenderReferenceCount=0;
38
39 XMATRIX reverseXY(-1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1);
40 XMATRIX reverseY(1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1);
41 extern char* right (const char * src, int nchars);
42
43 #if defined(WIN32)
44 #define strcasecmp _stricmp
45 #endif
46
47 //========================================================================
GetRender(void)48 CRender * CRender::GetRender(void)
49 {
50 return CRender::g_pRender;
51 }
IsAvailable()52 bool CRender::IsAvailable()
53 {
54 return CRender::g_pRender != NULL;
55 }
56
CRender()57 CRender::CRender() :
58 m_fScreenViewportMultX(2.0f),
59 m_fScreenViewportMultY(2.0f),
60
61 m_dwTexturePerspective(false),
62 m_bAlphaTestEnable(false),
63
64 m_bZUpdate(false),
65 m_bZCompare(false),
66 m_dwZBias(0),
67
68 m_dwMinFilter(FILTER_POINT),
69 m_dwMagFilter(FILTER_POINT),
70 m_dwAlpha(0xFF),
71 m_Mux(0),
72 m_bBlendModeValid(false)
73 {
74 InitRenderBase();
75
76 for( int i=0; i<MAX_TEXTURES; i++ )
77 {
78 g_textures[i].m_lpsTexturePtr = NULL;
79 g_textures[i].m_pCTexture = NULL;
80
81 g_textures[i].m_dwTileWidth = 64; // Value doesn't really matter, as tex not set
82 g_textures[i].m_dwTileHeight = 64;
83 g_textures[i].m_fTexWidth = 64.0f; // Value doesn't really matter, as tex not set
84 g_textures[i].m_fTexHeight = 64.0f;
85 g_textures[i].pTextureEntry = NULL;
86
87 TileUFlags[i] = TileVFlags[i] = TEXTURE_UV_FLAG_CLAMP;
88 }
89
90
91 //for( int i=0; i<MAX_VERTS; i++)
92 //{
93 // g_dwVtxFlags[i] = 0;
94 //}
95
96 m_pColorCombiner = CDeviceBuilder::GetBuilder()->CreateColorCombiner(this);
97 m_pColorCombiner->Initialize();
98
99 m_pAlphaBlender = CDeviceBuilder::GetBuilder()->CreateAlphaBlender(this);
100
101 }
102
~CRender()103 CRender::~CRender()
104 {
105 if( m_pColorCombiner != NULL )
106 {
107 CDeviceBuilder::GetBuilder()->DeleteColorCombiner();
108 m_pColorCombiner = NULL;
109 }
110
111 if( m_pAlphaBlender != NULL )
112 {
113 CDeviceBuilder::GetBuilder()->DeleteAlphaBlender();
114 m_pAlphaBlender = NULL;
115 }
116 }
117
ResetMatrices()118 void CRender::ResetMatrices()
119 {
120 Matrix mat;
121
122 mat.m[0][1] = mat.m[0][2] = mat.m[0][3] =
123 mat.m[1][0] = mat.m[1][2] = mat.m[1][3] =
124 mat.m[2][0] = mat.m[2][1] = mat.m[2][3] =
125 mat.m[3][0] = mat.m[3][1] = mat.m[3][2] = 0.0f;
126
127 mat.m[0][0] = mat.m[1][1] = mat.m[2][2] = mat.m[3][3] = 1.0f;
128
129 gRSP.projectionMtxTop = 0;
130 gRSP.modelViewMtxTop = 0;
131 gRSP.projectionMtxs[0] = mat;
132 gRSP.modelviewMtxs[0] = mat;
133
134 gRSP.bMatrixIsUpdated = true;
135 gRSP.bWorldMatrixIsUpdated = true;
136 UpdateCombinedMatrix();
137 }
138
SetProjection(const Matrix & mat,bool bPush,bool bReplace)139 void CRender::SetProjection(const Matrix & mat, bool bPush, bool bReplace)
140 {
141 if (bPush)
142 {
143 if (gRSP.projectionMtxTop < (RICE_MATRIX_STACK-1))
144 gRSP.projectionMtxTop++;
145
146 if (bReplace) // Load projection matrix
147 gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat;
148 else
149 gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat * gRSP.projectionMtxs[gRSP.projectionMtxTop-1];
150
151 }
152 else
153 {
154 if (bReplace) // Load projection matrix
155 gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat;
156 else
157 gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat * gRSP.projectionMtxs[gRSP.projectionMtxTop];
158 }
159
160 gRSP.bMatrixIsUpdated = true;
161 }
162
163 bool mtxPopUpError = false;
SetWorldView(const Matrix & mat,bool bPush,bool bReplace)164 void CRender::SetWorldView(const Matrix & mat, bool bPush, bool bReplace)
165 {
166 if (bPush)
167 {
168 if (gRSP.modelViewMtxTop < (RICE_MATRIX_STACK-1))
169 gRSP.modelViewMtxTop++;
170
171 // We should store the current projection matrix...
172 if (bReplace)
173 {
174 // Load projection matrix
175 gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat;
176
177 //GSI: Hack needed to show heart in OOT & MM
178 //it renders at Z coordinate = 0.0f that gets clipped away.
179 //so we translate them a bit along Z to make them stick
180
181 if( options.enableHackForGames == HACK_FOR_ZELDA || options.enableHackForGames == HACK_FOR_ZELDA_MM)
182 {
183 if(gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._43 == 0.0f
184 && gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._42 != 0.0f
185 && gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._42 <= 94.5f
186 && gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._42 >= -94.5f)
187 gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._43 -= 10.1f;
188 }
189 }
190 else // Multiply projection matrix
191 gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat * gRSP.modelviewMtxs[gRSP.modelViewMtxTop-1];
192 }
193 else // NoPush
194 {
195 if (bReplace) // Load projection matrix
196 gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat;
197 else // Multiply projection matrix
198 gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat * gRSP.modelviewMtxs[gRSP.modelViewMtxTop];
199 }
200
201 gRSPmodelViewTop = gRSP.modelviewMtxs[gRSP.modelViewMtxTop];
202 if( options.enableHackForGames == HACK_REVERSE_XY_COOR )
203 gRSPmodelViewTop = gRSPmodelViewTop * reverseXY;
204 if( options.enableHackForGames == HACK_REVERSE_Y_COOR )
205 gRSPmodelViewTop = gRSPmodelViewTop * reverseY;
206 MatrixTranspose(&gRSPmodelViewTopTranspose, &gRSPmodelViewTop);
207
208 gRSP.bMatrixIsUpdated = true;
209 gRSP.bWorldMatrixIsUpdated = true;
210 }
211
212
PopWorldView()213 void CRender::PopWorldView()
214 {
215 if (gRSP.modelViewMtxTop > 0)
216 {
217 gRSP.modelViewMtxTop--;
218 gRSPmodelViewTop = gRSP.modelviewMtxs[gRSP.modelViewMtxTop];
219 if( options.enableHackForGames == HACK_REVERSE_XY_COOR )
220 gRSPmodelViewTop = gRSPmodelViewTop * reverseXY;
221 if( options.enableHackForGames == HACK_REVERSE_Y_COOR )
222 gRSPmodelViewTop = gRSPmodelViewTop * reverseY;
223 MatrixTranspose(&gRSPmodelViewTopTranspose, &gRSPmodelViewTop);
224 gRSP.bMatrixIsUpdated = true;
225 gRSP.bWorldMatrixIsUpdated = true;
226 }
227 else
228 {
229 mtxPopUpError = true;
230 }
231 }
232
233
GetWorldProjectMatrix(void)234 Matrix & CRender::GetWorldProjectMatrix(void)
235 {
236 return gRSPworldProject;
237 }
238
SetWorldProjectMatrix(Matrix & mtx)239 void CRender::SetWorldProjectMatrix(Matrix &mtx)
240 {
241 gRSPworldProject = mtx;
242
243 gRSP.bMatrixIsUpdated = false;
244 gRSP.bCombinedMatrixIsUpdated = true;
245 }
246
SetMux(uint32_t dwMux0,uint32_t dwMux1)247 void CRender::SetMux(uint32_t dwMux0, uint32_t dwMux1)
248 {
249 uint64_t tempmux = (((uint64_t)dwMux0) << 32) | (uint64_t)dwMux1;
250 if( m_Mux != tempmux )
251 {
252 m_Mux = tempmux;
253 m_bBlendModeValid = false;
254 m_pColorCombiner->UpdateCombiner(dwMux0, dwMux1);
255 }
256 }
257
258
SetCombinerAndBlender()259 void CRender::SetCombinerAndBlender()
260 {
261 InitOtherModes();
262
263 if( g_curRomInfo.bDisableBlender )
264 m_pAlphaBlender->DisableAlphaBlender();
265 else if( currentRomOptions.bNormalBlender )
266 m_pAlphaBlender->NormalAlphaBlender();
267 else
268 m_pAlphaBlender->InitBlenderMode();
269
270 m_pColorCombiner->InitCombinerMode();
271 }
272
RenderReset()273 void CRender::RenderReset()
274 {
275 UpdateClipRectangle();
276 ResetMatrices();
277 SetZBias(0);
278 gRSP.numVertices = 0;
279 gRSP.maxVertexID = 0;
280 gRSP.curTile = 0;
281 gRSP.fTexScaleX = 1/32.0f;;
282 gRSP.fTexScaleY = 1/32.0f;
283 }
284
FillRect(int nX0,int nY0,int nX1,int nY1,uint32_t dwColor)285 bool CRender::FillRect(int nX0, int nY0, int nX1, int nY1, uint32_t dwColor)
286 {
287 if (g_CI.dwSize != G_IM_SIZ_16b && frameBufferOptions.bIgnore)
288 return true;
289
290 if (status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM)
291 status.bFrameBufferIsDrawn = true;
292
293 if(status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE)
294 {
295 status.bVIOriginIsUpdated=false;
296 CGraphicsContext::Get()->UpdateFrame(false);
297 }
298
299 if (status.bCIBufferIsRendered && status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_BEFORE_SCREEN_CLEAR )
300 {
301 if ((nX0==0 && nY0 == 0 && (nX1 == (int) g_CI.dwWidth || nX1 == (int) g_CI.dwWidth-1)) ||
302 (nX0==gRDP.scissor.left && nY0 == gRDP.scissor.top && (nX1 == gRDP.scissor.right || nX1 == gRDP.scissor.right-1)) ||
303 ((nX0+nX1 == (int)g_CI.dwWidth || nX0+nX1 == (int)g_CI.dwWidth-1 || nX0+nX1 == gRDP.scissor.left+gRDP.scissor.right || nX0+nX1 == gRDP.scissor.left+gRDP.scissor.right-1) && (nY0 == gRDP.scissor.top || nY0 == 0 || nY0+nY1 == gRDP.scissor.top+gRDP.scissor.bottom || nY0+nY1 == gRDP.scissor.top+gRDP.scissor.bottom-1)))
304 {
305 status.bVIOriginIsUpdated=false;
306 CGraphicsContext::Get()->UpdateFrame(false);
307 }
308 }
309
310
311 SetFillMode(RICE_FILLMODE_SOLID);
312
313 bool res=true;
314
315 /*
316 // I don't know why this does not work for OpenGL
317 if( gRDP.otherMode.cycle_type == G_CYC_FILL && nX0 == 0 && nY0 == 0 && ((nX1==windowSetting.uViWidth && nY1==windowSetting.uViHeight)||(nX1==windowSetting.uViWidth-1 && nY1==windowSetting.uViHeight-1)) )
318 {
319 CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,dwColor, 0xFF000000, 1.0f);
320 }
321 else
322 */
323 {
324 //bool m_savedZBufferFlag = gRSP.bZBufferEnabled; // Save ZBuffer state
325 ZBufferEnable( false );
326
327 m_fillRectVtx[0].x = ViewPortTranslatei_x(nX0);
328 m_fillRectVtx[0].y = ViewPortTranslatei_y(nY0);
329 m_fillRectVtx[1].x = ViewPortTranslatei_x(nX1);
330 m_fillRectVtx[1].y = ViewPortTranslatei_y(nY1);
331
332 SetCombinerAndBlender();
333
334 if( gRDP.otherMode.cycle_type >= G_CYC_COPY )
335 {
336 ZBufferEnable(false);
337 }
338 else
339 {
340 //dwColor = PostProcessDiffuseColor(0);
341 dwColor = PostProcessDiffuseColor(gRDP.primitiveColor);
342 }
343
344 float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 );
345
346 ApplyRDPScissor(false);
347 TurnFogOnOff(false);
348 res = RenderFillRect(dwColor, depth);
349 TurnFogOnOff(gRSP.bFogEnabled);
350
351 if( gRDP.otherMode.cycle_type >= G_CYC_COPY )
352 {
353 ZBufferEnable(gRSP.bZBufferEnabled);
354 }
355 }
356
357 if( options.bWinFrameMode )
358 SetFillMode(RICE_FILLMODE_WINFRAME);
359
360 return res;
361 }
362
363
Line3D(uint32_t dwV0,uint32_t dwV1,uint32_t dwWidth)364 bool CRender::Line3D(uint32_t dwV0, uint32_t dwV1, uint32_t dwWidth)
365 {
366 if( !status.bCIBufferIsRendered )
367 g_pFrameBufferManager->ActiveTextureBuffer();
368
369 m_line3DVtx[0].z = (g_vecProjected[dwV0].z + 1.0f) * 0.5f;
370 m_line3DVtx[1].z = (g_vecProjected[dwV1].z + 1.0f) * 0.5f;
371
372 if( m_line3DVtx[0].z != m_line3DVtx[1].z )
373 return false;
374
375 if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM )
376 status.bFrameBufferIsDrawn = true;
377
378 if( status.bHandleN64RenderTexture )
379 {
380 g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height;
381 if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM )
382 {
383 status.bFrameBufferIsDrawn = true;
384 status.bFrameBufferDrawnByTriangles = true;
385 }
386 }
387
388 m_line3DVtx[0].x = ViewPortTranslatef_x(g_vecProjected[dwV0].x);
389 m_line3DVtx[0].y = ViewPortTranslatef_y(g_vecProjected[dwV0].y);
390 m_line3DVtx[0].rhw = g_vecProjected[dwV0].w;
391 m_line3DVtx[0].dcDiffuse = PostProcessDiffuseColor(g_dwVtxDifColor[dwV0]);
392 m_line3DVtx[0].dcSpecular = PostProcessSpecularColor();
393
394 m_line3DVtx[1].x = ViewPortTranslatef_x(g_vecProjected[dwV1].x);
395 m_line3DVtx[1].y = ViewPortTranslatef_y(g_vecProjected[dwV1].y);
396 m_line3DVtx[1].rhw = g_vecProjected[dwV1].w;
397 m_line3DVtx[1].dcDiffuse = PostProcessDiffuseColor(g_dwVtxDifColor[dwV1]);
398 m_line3DVtx[1].dcSpecular = m_line3DVtx[0].dcSpecular;
399
400 float width = dwWidth*0.5f+1.5f;
401
402 if( m_line3DVtx[0].y == m_line3DVtx[1].y )
403 {
404 m_line3DVector[0].x = m_line3DVector[1].x = m_line3DVtx[0].x;
405 m_line3DVector[2].x = m_line3DVector[3].x = m_line3DVtx[1].x;
406
407 m_line3DVector[0].y = m_line3DVector[2].y = m_line3DVtx[0].y-width/2*windowSetting.fMultY;
408 m_line3DVector[1].y = m_line3DVector[3].y = m_line3DVtx[0].y+width/2*windowSetting.fMultY;
409 }
410 else
411 {
412 m_line3DVector[0].y = m_line3DVector[1].y = m_line3DVtx[0].y;
413 m_line3DVector[2].y = m_line3DVector[3].y = m_line3DVtx[1].y;
414
415 m_line3DVector[0].x = m_line3DVector[2].x = m_line3DVtx[0].x-width/2*windowSetting.fMultX;
416 m_line3DVector[1].x = m_line3DVector[3].x = m_line3DVtx[0].x+width/2*windowSetting.fMultX;
417 }
418
419 SetCombinerAndBlender();
420
421 return RenderLine3D();
422 }
423
RemapTextureCoordinate(float t0,float t1,uint32_t tileWidth,uint32_t mask,float textureWidth,float & u0,float & u1)424 bool CRender::RemapTextureCoordinate
425 (float t0, float t1, uint32_t tileWidth, uint32_t mask, float textureWidth, float &u0, float &u1)
426 {
427 int s0 = (int)t0;
428 int s1 = (int)t1;
429 int width = mask>0 ? (1<<mask) : tileWidth;
430 if( width == 0 ) return false;
431
432 int divs0 = s0/width; if( divs0*width > s0 ) divs0--;
433 int divs1 = s1/width; if( divs1*width > s1 ) divs1--;
434
435 if( divs0 == divs1 )
436 {
437 s0 -= divs0*width;
438 s1 -= divs1*width;
439 //if( s0 > s1 )
440 // s0++;
441 //else if( s1 > s0 )
442 // s1++;
443 u0 = s0/textureWidth;
444 u1 = s1/textureWidth;
445
446 return true;
447 }
448 else if( divs0+1 == divs1 && s0%width==0 && s1%width == 0 )
449 {
450 u0 = 0;
451 u1 = tileWidth/textureWidth;
452 return true;
453 }
454 else if( divs0 == divs1+1 && s0%width==0 && s1%width == 0 )
455 {
456 u1 = 0;
457 u0 = tileWidth/textureWidth;
458 return true;
459 }
460 else
461 {
462 //if( s0 > s1 )
463 //{
464 //s0++;
465 // u0 = s0/textureWidth;
466 //}
467 //else if( s1 > s0 )
468 //{
469 //s1++;
470 // u1 = s1/textureWidth;
471 //}
472
473 return false;
474 }
475 }
476
TexRect(int nX0,int nY0,int nX1,int nY1,float fS0,float fT0,float fScaleS,float fScaleT,bool colorFlag,uint32_t diffuseColor)477 bool CRender::TexRect(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fScaleS, float fScaleT, bool colorFlag, uint32_t diffuseColor)
478 {
479 if( options.enableHackForGames == HACK_FOR_DUKE_NUKEM )
480 {
481 colorFlag = true;
482 diffuseColor = 0;
483 }
484
485 if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE )
486 {
487 status.bVIOriginIsUpdated=false;
488 CGraphicsContext::Get()->UpdateFrame(false);
489 }
490
491 if( options.enableHackForGames == HACK_FOR_BANJO_TOOIE )
492 {
493 // Hack for Banjo shadow in Banjo Tooie
494 if( g_TI.dwWidth == g_CI.dwWidth && g_TI.dwFormat == G_IM_FMT_CI && g_TI.dwSize == G_IM_SIZ_8b )
495 {
496 // Skip the text rect
497 if( nX0 == fS0 && nY0 == fT0 )//&& nX0 > 90 && nY0 > 130 && nX1-nX0 > 80 && nY1-nY0 > 20 )
498 return true;
499 }
500 }
501
502 if( status.bN64IsDrawingTextureBuffer )
503 {
504 if( frameBufferOptions.bIgnore || ( frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown && newRenderTextureInfo.knownHeight == 0 ) )
505 return true;
506 }
507
508 PrepareTextures();
509
510 if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == G_IM_SIZ_8b )
511 return true;
512
513 if( !IsTextureEnabled() && gRDP.otherMode.cycle_type != G_CYC_COPY )
514 {
515 FillRect(nX0, nY0, nX1, nY1, gRDP.primitiveColor);
516 return true;
517 }
518
519
520 if( IsUsedAsDI(g_CI.dwAddr) && !status.bHandleN64RenderTexture )
521 status.bFrameBufferIsDrawn = true;
522
523 if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) status.bFrameBufferIsDrawn = true;
524
525 if( options.bEnableHacks )
526 {
527 // Goldeneye HACK
528 if( nY1 - nY0 < 2 )
529 nY1 = nY1+2;
530
531 //// Text edge hack
532 else if( gRDP.otherMode.cycle_type == G_CYC_1CYCLE && fScaleS == 1 && fScaleT == 1 &&
533 (int)g_textures[gRSP.curTile].m_dwTileWidth == nX1-nX0+1 && (int)g_textures[gRSP.curTile].m_dwTileHeight == nY1-nY0+1 &&
534 g_textures[gRSP.curTile].m_dwTileWidth%2 == 0 && g_textures[gRSP.curTile].m_dwTileHeight%2 == 0 )
535 {
536 nY1++;
537 nX1++;
538 }
539 else if( g_curRomInfo.bIncTexRectEdge )
540 {
541 nX1++;
542 nY1++;
543 }
544 }
545
546
547 // Scale to Actual texture coords
548 // The two cases are to handle the oversized textures hack on voodoos
549
550 SetCombinerAndBlender();
551
552
553 if( gRDP.otherMode.cycle_type >= G_CYC_COPY || !gRDP.otherMode.z_cmp )
554 ZBufferEnable(false);
555
556 bool accurate = currentRomOptions.bAccurateTextureMapping;
557
558 RenderTexture &tex0 = g_textures[gRSP.curTile];
559 TileAdditionalInfo *tile0 = &gRDP.tilesinfo[gRSP.curTile];
560 gDPTile *tile0info = &gDP.tiles[gRSP.curTile];
561
562 float widthDiv = tex0.m_fTexWidth;
563 float heightDiv = tex0.m_fTexHeight;
564 float t0u0;
565 if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB )
566 t0u0 = (fS0 -tile0->fhilite_sl);
567 else
568 t0u0 = (fS0 * tile0->fShiftScaleS -tile0->fhilite_sl);
569
570 float t0u1;
571 if( accurate && gRDP.otherMode.cycle_type >= G_CYC_COPY )
572 t0u1 = t0u0 + (fScaleS * (nX1 - nX0 - 1))*tile0->fShiftScaleS;
573 else
574 t0u1 = t0u0 + (fScaleS * (nX1 - nX0))*tile0->fShiftScaleS;
575
576
577 if( status.UseLargerTile[0] )
578 {
579 m_texRectTex1UV[0].u = (t0u0+status.LargerTileRealLeft[0])/widthDiv;
580 m_texRectTex1UV[1].u = (t0u1+status.LargerTileRealLeft[0])/widthDiv;
581 }
582 else
583 {
584 m_texRectTex1UV[0].u = t0u0/widthDiv;
585 m_texRectTex1UV[1].u = t0u1/widthDiv;
586 if( accurate && !tile0info->mirrors && RemapTextureCoordinate(t0u0, t0u1, tex0.m_dwTileWidth, tile0info->masks, widthDiv, m_texRectTex1UV[0].u, m_texRectTex1UV[1].u) )
587 SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile);
588 }
589
590 float t0v0;
591 if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB )
592 t0v0 = (fT0 -tile0->fhilite_tl);
593 else
594 t0v0 = (fT0 * tile0->fShiftScaleT -tile0->fhilite_tl);
595
596 float t0v1;
597 if ( accurate && gRDP.otherMode.cycle_type >= G_CYC_COPY)
598 t0v1 = t0v0 + (fScaleT * (nY1 - nY0-1))*tile0->fShiftScaleT;
599 else
600 t0v1 = t0v0 + (fScaleT * (nY1 - nY0))*tile0->fShiftScaleT;
601
602 m_texRectTex1UV[0].v = t0v0/heightDiv;
603 m_texRectTex1UV[1].v = t0v1/heightDiv;
604 if( accurate && !tile0info->mirrort && RemapTextureCoordinate(t0v0, t0v1, tex0.m_dwTileHeight, tile0info->maskt, heightDiv, m_texRectTex1UV[0].v, m_texRectTex1UV[1].v) )
605 SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile);
606
607 COLOR speColor = PostProcessSpecularColor();
608 COLOR difColor;
609 if( colorFlag )
610 difColor = PostProcessDiffuseColor(diffuseColor);
611 else
612 //difColor = PostProcessDiffuseColor(0);
613 difColor = PostProcessDiffuseColor(gRDP.primitiveColor);
614
615 g_texRectTVtx[0].x = ViewPortTranslatei_x(nX0);
616 g_texRectTVtx[0].y = ViewPortTranslatei_y(nY0);
617 g_texRectTVtx[0].dcDiffuse = difColor;
618 g_texRectTVtx[0].dcSpecular = speColor;
619
620 g_texRectTVtx[1].x = ViewPortTranslatei_x(nX1);
621 g_texRectTVtx[1].y = ViewPortTranslatei_y(nY0);
622 g_texRectTVtx[1].dcDiffuse = difColor;
623 g_texRectTVtx[1].dcSpecular = speColor;
624
625 g_texRectTVtx[2].x = ViewPortTranslatei_x(nX1);
626 g_texRectTVtx[2].y = ViewPortTranslatei_y(nY1);
627 g_texRectTVtx[2].dcDiffuse = difColor;
628 g_texRectTVtx[2].dcSpecular = speColor;
629
630 g_texRectTVtx[3].x = ViewPortTranslatei_x(nX0);
631 g_texRectTVtx[3].y = ViewPortTranslatei_y(nY1);
632 g_texRectTVtx[3].dcDiffuse = difColor;
633 g_texRectTVtx[3].dcSpecular = speColor;
634
635 float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 );
636
637 g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = depth;
638 g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = 1;
639
640 if( IsTexel1Enable() )
641 {
642 RenderTexture &tex1 = g_textures[(gRSP.curTile+1)&7];
643 TileAdditionalInfo *tile1 = &gRDP.tilesinfo[(gRSP.curTile+1)&7];
644 gDPTile *tile1info = &gDP.tiles[(gRSP.curTile+1)&7];
645
646 widthDiv = tex1.m_fTexWidth;
647 heightDiv = tex1.m_fTexHeight;
648
649 float t0u0 = fS0 * tile1->fShiftScaleS -tile1->fhilite_sl;
650 float t0v0 = fT0 * tile1->fShiftScaleT -tile1->fhilite_tl;
651 float t0u1;
652 float t0v1;
653 if ( accurate && gRDP.otherMode.cycle_type >= G_CYC_COPY)
654 {
655 t0u1 = t0u0 + (fScaleS * (nX1 - nX0 - 1))*tile1->fShiftScaleS;
656 t0v1 = t0v0 + (fScaleT * (nY1 - nY0 - 1))*tile1->fShiftScaleT;
657 }
658 else
659 {
660 t0u1 = t0u0 + (fScaleS * (nX1 - nX0))*tile1->fShiftScaleS;
661 t0v1 = t0v0 + (fScaleT * (nY1 - nY0))*tile1->fShiftScaleT;
662 }
663
664 if( status.UseLargerTile[1] )
665 {
666 m_texRectTex2UV[0].u = (t0u0+status.LargerTileRealLeft[1])/widthDiv;
667 m_texRectTex2UV[1].u = (t0u1+status.LargerTileRealLeft[1])/widthDiv;
668 }
669 else
670 {
671 m_texRectTex2UV[0].u = t0u0/widthDiv;
672 m_texRectTex2UV[1].u = t0u1/widthDiv;
673 if( accurate && !tile1info->mirrors && RemapTextureCoordinate(t0u0, t0u1, tex1.m_dwTileWidth, tile1info->masks, widthDiv, m_texRectTex2UV[0].u, m_texRectTex2UV[1].u) )
674 SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, (gRSP.curTile+1)&7);
675 }
676
677 m_texRectTex2UV[0].v = t0v0/heightDiv;
678 m_texRectTex2UV[1].v = t0v1/heightDiv;
679
680 if( accurate && !tile1info->mirrort && RemapTextureCoordinate(t0v0, t0v1, tex1.m_dwTileHeight, tile1info->maskt, heightDiv, m_texRectTex2UV[0].v, m_texRectTex2UV[1].v) )
681 SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, (gRSP.curTile+1)&7);
682
683 SetVertexTextureUVCoord(g_texRectTVtx[0], m_texRectTex1UV[0].u, m_texRectTex1UV[0].v, m_texRectTex2UV[0].u, m_texRectTex2UV[0].v);
684 SetVertexTextureUVCoord(g_texRectTVtx[1], m_texRectTex1UV[1].u, m_texRectTex1UV[0].v, m_texRectTex2UV[1].u, m_texRectTex2UV[0].v);
685 SetVertexTextureUVCoord(g_texRectTVtx[2], m_texRectTex1UV[1].u, m_texRectTex1UV[1].v, m_texRectTex2UV[1].u, m_texRectTex2UV[1].v);
686 SetVertexTextureUVCoord(g_texRectTVtx[3], m_texRectTex1UV[0].u, m_texRectTex1UV[1].v, m_texRectTex2UV[0].u, m_texRectTex2UV[1].v);
687 }
688 else
689 {
690 SetVertexTextureUVCoord(g_texRectTVtx[0], m_texRectTex1UV[0].u, m_texRectTex1UV[0].v);
691 SetVertexTextureUVCoord(g_texRectTVtx[1], m_texRectTex1UV[1].u, m_texRectTex1UV[0].v);
692 SetVertexTextureUVCoord(g_texRectTVtx[2], m_texRectTex1UV[1].u, m_texRectTex1UV[1].v);
693 SetVertexTextureUVCoord(g_texRectTVtx[3], m_texRectTex1UV[0].u, m_texRectTex1UV[1].v);
694 }
695
696
697 bool res;
698 TurnFogOnOff(false);
699 if( TileUFlags[gRSP.curTile]==TEXTURE_UV_FLAG_CLAMP && TileVFlags[gRSP.curTile]==TEXTURE_UV_FLAG_CLAMP && options.forceTextureFilter == FORCE_DEFAULT_FILTER )
700 {
701 TextureFilter dwFilter = m_dwMagFilter;
702 m_dwMagFilter = m_dwMinFilter = FILTER_LINEAR;
703 ApplyTextureFilter();
704 ApplyRDPScissor(false);
705 res = RenderTexRect();
706 m_dwMagFilter = m_dwMinFilter = dwFilter;
707 ApplyTextureFilter();
708 }
709 else if( fScaleS >= 1 && fScaleT >= 1 && options.forceTextureFilter == FORCE_DEFAULT_FILTER )
710 {
711 TextureFilter dwFilter = m_dwMagFilter;
712 m_dwMagFilter = m_dwMinFilter = FILTER_POINT;
713 ApplyTextureFilter();
714 ApplyRDPScissor(false);
715 res = RenderTexRect();
716 m_dwMagFilter = m_dwMinFilter = dwFilter;
717 ApplyTextureFilter();
718 }
719 else
720 {
721 ApplyRDPScissor(false);
722 res = RenderTexRect();
723 }
724 TurnFogOnOff(gRSP.bFogEnabled);
725
726 if( gRDP.otherMode.cycle_type >= G_CYC_COPY || !gRDP.otherMode.z_cmp )
727 ZBufferEnable(gRSP.bZBufferEnabled);
728
729 return res;
730 }
731
732
TexRectFlip(int nX0,int nY0,int nX1,int nY1,float fS0,float fT0,float fS1,float fT1)733 bool CRender::TexRectFlip(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fS1, float fT1)
734 {
735 if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM )
736 {
737 status.bFrameBufferIsDrawn = true;
738 status.bFrameBufferDrawnByTriangles = true;
739 }
740
741 PrepareTextures();
742
743 // Save ZBuffer state
744 m_savedZBufferFlag = gRSP.bZBufferEnabled;
745 if( gRDP.otherMode.depth_source == 0 )
746 ZBufferEnable( false );
747
748 float widthDiv = g_textures[gRSP.curTile].m_fTexWidth;
749 float heightDiv = g_textures[gRSP.curTile].m_fTexHeight;
750
751 //Tile &tile0 = gRDP.tiles[gRSP.curTile];
752
753 float t0u0 = fS0 / widthDiv;
754 float t0v0 = fT0 / heightDiv;
755
756 float t0u1 = (fS1 - fS0)/ widthDiv + t0u0;
757 float t0v1 = (fT1 - fT0)/ heightDiv + t0v0;
758
759 float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 );
760
761 if( t0u0 >= 0 && t0u1 <= 1 && t0u1 >= t0u0 ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile);
762 if( t0v0 >= 0 && t0v1 <= 1 && t0v1 >= t0v0 ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile);
763
764 SetCombinerAndBlender();
765
766 COLOR speColor = PostProcessSpecularColor();
767 COLOR difColor = PostProcessDiffuseColor(gRDP.primitiveColor);
768
769 // Same as TexRect, but with texcoords 0,2 swapped
770 g_texRectTVtx[0].x = ViewPortTranslatei_x(nX0);
771 g_texRectTVtx[0].y = ViewPortTranslatei_y(nY0);
772 g_texRectTVtx[0].dcDiffuse = difColor;
773 g_texRectTVtx[0].dcSpecular = speColor;
774
775 g_texRectTVtx[1].x = ViewPortTranslatei_x(nX1);
776 g_texRectTVtx[1].y = ViewPortTranslatei_y(nY0);
777 g_texRectTVtx[1].dcDiffuse = difColor;
778 g_texRectTVtx[1].dcSpecular = speColor;
779
780 g_texRectTVtx[2].x = ViewPortTranslatei_x(nX1);
781 g_texRectTVtx[2].y = ViewPortTranslatei_y(nY1);
782 g_texRectTVtx[2].dcDiffuse = difColor;
783 g_texRectTVtx[2].dcSpecular = speColor;
784
785 g_texRectTVtx[3].x = ViewPortTranslatei_x(nX0);
786 g_texRectTVtx[3].y = ViewPortTranslatei_y(nY1);
787 g_texRectTVtx[3].dcDiffuse = difColor;
788 g_texRectTVtx[3].dcSpecular = speColor;
789
790 g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = depth;
791 g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = 1.0f;
792
793 SetVertexTextureUVCoord(g_texRectTVtx[0], t0u0, t0v0);
794 SetVertexTextureUVCoord(g_texRectTVtx[1], t0u0, t0v1);
795 SetVertexTextureUVCoord(g_texRectTVtx[2], t0u1, t0v1);
796 SetVertexTextureUVCoord(g_texRectTVtx[3], t0u1, t0v0);
797
798 TurnFogOnOff(false);
799 ApplyRDPScissor(false);
800 bool res = RenderTexRect();
801
802 TurnFogOnOff(gRSP.bFogEnabled);
803
804 // Restore state
805 ZBufferEnable( m_savedZBufferFlag );
806
807 return res;
808 }
809
810
StartDrawSimple2DTexture(float x0,float y0,float x1,float y1,float u0,float v0,float u1,float v1,COLOR dif,COLOR spe,float z,float rhw)811 void CRender::StartDrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, COLOR spe, float z, float rhw)
812 {
813 g_texRectTVtx[0].x = ViewPortTranslatei_x(x0); // << Error here, shouldn't divid by 4
814 g_texRectTVtx[0].y = ViewPortTranslatei_y(y0);
815 g_texRectTVtx[0].dcDiffuse = dif;
816 g_texRectTVtx[0].dcSpecular = spe;
817 g_texRectTVtx[0].tcord[0].u = u0;
818 g_texRectTVtx[0].tcord[0].v = v0;
819
820
821 g_texRectTVtx[1].x = ViewPortTranslatei_x(x1);
822 g_texRectTVtx[1].y = ViewPortTranslatei_y(y0);
823 g_texRectTVtx[1].dcDiffuse = dif;
824 g_texRectTVtx[1].dcSpecular = spe;
825 g_texRectTVtx[1].tcord[0].u = u1;
826 g_texRectTVtx[1].tcord[0].v = v0;
827
828 g_texRectTVtx[2].x = ViewPortTranslatei_x(x1);
829 g_texRectTVtx[2].y = ViewPortTranslatei_y(y1);
830 g_texRectTVtx[2].dcDiffuse = dif;
831 g_texRectTVtx[2].dcSpecular = spe;
832 g_texRectTVtx[2].tcord[0].u = u1;
833 g_texRectTVtx[2].tcord[0].v = v1;
834
835 g_texRectTVtx[3].x = ViewPortTranslatei_x(x0);
836 g_texRectTVtx[3].y = ViewPortTranslatei_y(y1);
837 g_texRectTVtx[3].dcDiffuse = dif;
838 g_texRectTVtx[3].dcSpecular = spe;
839 g_texRectTVtx[3].tcord[0].u = u0;
840 g_texRectTVtx[3].tcord[0].v = v1;
841
842 RenderTexture &txtr = g_textures[0];
843 if( txtr.pTextureEntry && txtr.pTextureEntry->txtrBufIdx > 0 )
844 {
845 RenderTextureInfo &info = gRenderTextureInfos[txtr.pTextureEntry->txtrBufIdx-1];
846 g_texRectTVtx[0].tcord[0].u *= info.scaleX;
847 g_texRectTVtx[0].tcord[0].v *= info.scaleY;
848 g_texRectTVtx[1].tcord[0].u *= info.scaleX;
849 g_texRectTVtx[1].tcord[0].v *= info.scaleY;
850 g_texRectTVtx[2].tcord[0].u *= info.scaleX;
851 g_texRectTVtx[2].tcord[0].v *= info.scaleY;
852 g_texRectTVtx[3].tcord[0].u *= info.scaleX;
853 g_texRectTVtx[3].tcord[0].v *= info.scaleY;
854 }
855
856 g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = z;
857 g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = rhw;
858 }
859
StartDrawSimpleRect(int nX0,int nY0,int nX1,int nY1,uint32_t dwColor,float depth,float rhw)860 void CRender::StartDrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32_t dwColor, float depth, float rhw)
861 {
862 m_simpleRectVtx[0].x = ViewPortTranslatei_x(nX0);
863 m_simpleRectVtx[1].x = ViewPortTranslatei_x(nX1);
864 m_simpleRectVtx[0].y = ViewPortTranslatei_y(nY0);
865 m_simpleRectVtx[1].y = ViewPortTranslatei_y(nY1);
866 }
867
SetAddressUAllStages(uint32_t dwTile,TextureUVFlag dwFlag)868 void CRender::SetAddressUAllStages(uint32_t dwTile, TextureUVFlag dwFlag)
869 {
870 }
871
SetAddressVAllStages(uint32_t dwTile,TextureUVFlag dwFlag)872 void CRender::SetAddressVAllStages(uint32_t dwTile, TextureUVFlag dwFlag)
873 {
874 }
875
SetAllTexelRepeatFlag()876 void CRender::SetAllTexelRepeatFlag()
877 {
878 if( IsTextureEnabled() )
879 {
880 if( IsTexel0Enable() || gRDP.otherMode.cycle_type == G_CYC_COPY )
881 SetTexelRepeatFlags(gRSP.curTile);
882 if( IsTexel1Enable() )
883 SetTexelRepeatFlags((gRSP.curTile+1)&7);
884 }
885 }
886
887
SetTexelRepeatFlags(uint32_t dwTile)888 void CRender::SetTexelRepeatFlags(uint32_t dwTile)
889 {
890 TileAdditionalInfo *tile = &gRDP.tilesinfo[dwTile];
891 gDPTile *tileinfo = &gDP.tiles[dwTile];
892
893 if( tile->bForceClampS )
894 SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, dwTile);
895 else if( tile->bForceWrapS )
896 SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile);
897 else if( tileinfo->masks == 0 || tileinfo->clamps )
898 {
899 if( gRDP.otherMode.cycle_type >= G_CYC_COPY )
900 SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile); // Can not clamp in COPY/FILL mode
901 else
902 SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, dwTile);
903 }
904 else if (tileinfo->mirrors )
905 SetTextureUFlag(TEXTURE_UV_FLAG_MIRROR, dwTile);
906 else
907 SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile);
908
909 if( tile->bForceClampT )
910 SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, dwTile);
911 else if( tile->bForceWrapT )
912 SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile);
913 else if( tileinfo->maskt == 0 || tileinfo->clampt)
914 {
915 if( gRDP.otherMode.cycle_type >= G_CYC_COPY )
916 SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile); // Can not clamp in COPY/FILL mode
917 else
918 SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, dwTile);
919 }
920 else if (tileinfo->mirrort )
921 SetTextureVFlag(TEXTURE_UV_FLAG_MIRROR, dwTile);
922 else
923 SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile);
924 }
925
Initialize(void)926 void CRender::Initialize(void)
927 {
928 ClearDeviceObjects();
929 InitDeviceObjects();
930 }
931
CleanUp(void)932 void CRender::CleanUp(void)
933 {
934 m_pColorCombiner->CleanUp();
935 ClearDeviceObjects();
936 }
937
myVec3Transform(float * vecout,float * vecin,float * m)938 void myVec3Transform(float *vecout, float *vecin, float* m)
939 {
940 float w = m[3]*vecin[0]+m[7]*vecin[1]+m[11]*vecin[2]+m[15];
941 vecout[0] = (m[0]*vecin[0]+m[4]*vecin[1]+m[8]*vecin[2]+m[12])/w;
942 vecout[1] = (m[1]*vecin[0]+m[5]*vecin[1]+m[9]*vecin[2]+m[13])/w;
943 vecout[2] = (m[2]*vecin[0]+m[6]*vecin[1]+m[10]*vecin[2]+m[14])/w;
944 }
945
SetTextureEnableAndScale(int dwTile,bool bEnable,float fScaleX,float fScaleY)946 void CRender::SetTextureEnableAndScale(int dwTile, bool bEnable, float fScaleX, float fScaleY)
947 {
948 gRSP.bTextureEnabled = bEnable;
949
950 if( bEnable )
951 {
952 if( gRSP.curTile != (unsigned int)dwTile )
953 gRDP.textureIsChanged = true;
954
955 gRSP.curTile = dwTile;
956 gRSP.fTexScaleX = fScaleX;
957 gRSP.fTexScaleY = fScaleY;
958
959 if( fScaleX == 0 || fScaleY == 0 )
960 {
961 gRSP.fTexScaleX = 1/32.0f;
962 gRSP.fTexScaleY = 1/32.0f;
963 }
964 }
965 }
966
SetViewport(int nLeft,int nTop,int nRight,int nBottom,int maxZ)967 void CRender::SetViewport(int nLeft, int nTop, int nRight, int nBottom, int maxZ)
968 {
969 if( status.bHandleN64RenderTexture )
970 return;
971
972 static float MultX=0, MultY=0;
973
974 if( gRSP.nVPLeftN == nLeft && gRSP.nVPTopN == nTop &&
975 gRSP.nVPRightN == nRight && gRSP.nVPBottomN == nBottom &&
976 MultX==windowSetting.fMultX && MultY==windowSetting.fMultY)
977 {
978 // no changes
979 return;
980 }
981
982 MultX=windowSetting.fMultX;
983 MultY=windowSetting.fMultY;
984
985 gRSP.maxZ = maxZ;
986 gRSP.nVPLeftN = nLeft;
987 gRSP.nVPTopN = nTop;
988 gRSP.nVPRightN = nRight;
989 gRSP.nVPBottomN = nBottom;
990 gRSP.nVPWidthN = nRight - nLeft + 1;
991 gRSP.nVPHeightN = nBottom - nTop + 1;
992
993 UpdateClipRectangle();
994 SetViewportRender();
995 }
996
997 extern bool bHalfTxtScale;
998
DrawTriangles()999 bool CRender::DrawTriangles()
1000 {
1001 if( !status.bCIBufferIsRendered )
1002 g_pFrameBufferManager->ActiveTextureBuffer();
1003
1004 if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE )
1005 {
1006 status.bVIOriginIsUpdated=false;
1007 CGraphicsContext::Get()->UpdateFrame(false);
1008 }
1009
1010 // Hack for Pilotwings 64 (U) [!].v64
1011 static bool skipNext=false;
1012 if( options.enableHackForGames == HACK_FOR_PILOT_WINGS )
1013 {
1014 if( IsUsedAsDI(g_CI.dwAddr) && gRDP.otherMode.z_cmp+gRDP.otherMode.z_upd > 0 )
1015 {
1016 TRACE0("Warning: using Flushtris to write Z-Buffer" );
1017 gRSP.numVertices = 0;
1018 gRSP.maxVertexID = 0;
1019 skipNext = true;
1020 return true;
1021 }
1022 else if( skipNext )
1023 {
1024 skipNext = false;
1025 gRSP.numVertices = 0;
1026 gRSP.maxVertexID = 0;
1027 return true;
1028 }
1029 }
1030
1031 if( status.bN64IsDrawingTextureBuffer && frameBufferOptions.bIgnore )
1032 {
1033 gRSP.numVertices = 0;
1034 gRSP.maxVertexID = 0;
1035 return true;
1036 }
1037
1038 extern bool bConkerHideShadow;
1039 if( options.enableHackForGames == HACK_FOR_CONKER && bConkerHideShadow )
1040 {
1041 gRSP.numVertices = 0;
1042 gRSP.maxVertexID = 0;
1043 return true;
1044 }
1045
1046 if( IsUsedAsDI(g_CI.dwAddr) && !status.bHandleN64RenderTexture )
1047 {
1048 status.bFrameBufferIsDrawn = true;
1049 }
1050
1051 /*
1052 if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == G_IM_SIZ_8b )
1053 {
1054 gRSP.numVertices = 0;
1055 gRSP.maxVertexID = 0;
1056 return true;
1057 }
1058 */
1059
1060 if (gRSP.numVertices == 0)
1061 return true;
1062
1063 if( status.bHandleN64RenderTexture )
1064 {
1065 g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height;
1066 if( !status.bDirectWriteIntoRDRAM )
1067 {
1068 status.bFrameBufferIsDrawn = true;
1069 status.bFrameBufferDrawnByTriangles = true;
1070 }
1071 }
1072
1073 if( !gRDP.bFogEnableInBlender && gRSP.bFogEnabled )
1074 {
1075 TurnFogOnOff(false);
1076 }
1077
1078 for( int t=0; t<2; t++ )
1079 {
1080 float halfscaleS = 1;
1081
1082 // This will get rid of the thin black lines
1083 if( t==0 && !(m_pColorCombiner->m_bTex0Enabled) )
1084 {
1085 continue;
1086 }
1087 else
1088 {
1089 if( ( gDP.tiles[gRSP.curTile].size == G_IM_SIZ_32b &&
1090 options.enableHackForGames == HACK_FOR_RUMBLE ) ||
1091 (bHalfTxtScale && g_curRomInfo.bTextureScaleHack ) ||
1092 (
1093 options.enableHackForGames == HACK_FOR_POLARISSNOCROSS &&
1094 gDP.tiles[7].format == G_IM_FMT_CI &&
1095 gDP.tiles[7].size == G_IM_SIZ_8b &&
1096 gDP.tiles[0].format == G_IM_FMT_CI &&
1097 gDP.tiles[0].size == G_IM_SIZ_8b &&
1098 gRSP.curTile == 0 )
1099 )
1100 {
1101 halfscaleS = 0.5;
1102 }
1103 }
1104
1105 if( t==1 && !(m_pColorCombiner->m_bTex1Enabled) )
1106 break;
1107
1108 if( halfscaleS < 1 )
1109 {
1110 for( uint32_t i=0; i<gRSP.numVertices; i++ )
1111 {
1112 if( t == 0 )
1113 {
1114 g_vtxBuffer[i].tcord[t].u += gRSP.tex0OffsetX;
1115 g_vtxBuffer[i].tcord[t].u /= 2;
1116 g_vtxBuffer[i].tcord[t].u -= gRSP.tex0OffsetX;
1117 g_vtxBuffer[i].tcord[t].v += gRSP.tex0OffsetY;
1118 g_vtxBuffer[i].tcord[t].v /= 2;
1119 g_vtxBuffer[i].tcord[t].v -= gRSP.tex0OffsetY;
1120 }
1121 else
1122 {
1123 g_vtxBuffer[i].tcord[t].u += gRSP.tex1OffsetX;
1124 g_vtxBuffer[i].tcord[t].u /= 2;
1125 g_vtxBuffer[i].tcord[t].u -= gRSP.tex1OffsetX;
1126 g_vtxBuffer[i].tcord[t].v += gRSP.tex1OffsetY;
1127 g_vtxBuffer[i].tcord[t].v /= 2;
1128 g_vtxBuffer[i].tcord[t].v -= gRSP.tex1OffsetY;
1129 }
1130 }
1131 }
1132
1133 /*
1134 // The code here is disabled because it could cause incorrect texture repeating flag
1135 // for later DrawTriangles
1136 bool clampS=true;
1137 bool clampT=true;
1138
1139 for( uint32_t i=0; i<gRSP.numVertices; i++ )
1140 {
1141 float w = g_vtxProjected5[i][3];
1142 if( w < 0 || g_vtxBuffer[i].tcord[t].u > 1.0 || g_vtxBuffer[i].tcord[t].u < 0.0 )
1143 {
1144 clampS = false;
1145 break;
1146 }
1147 }
1148
1149 for( uint32_t i=0; i<gRSP.numVertices; i++ )
1150 {
1151 float w = g_vtxProjected5[i][3];
1152 if( w < 0 || g_vtxBuffer[i].tcord[t].v > 1.0 || g_vtxBuffer[i].tcord[t].v < 0.0 )
1153 {
1154 clampT = false;
1155 break;
1156 }
1157 }
1158
1159 if( clampS )
1160 {
1161 SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile+t);
1162 }
1163 if( clampT )
1164 {
1165 SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile+t);
1166 }
1167 */
1168 }
1169
1170 if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == G_IM_SIZ_8b )
1171 {
1172 ZBufferEnable(false);
1173 }
1174
1175 ApplyScissorWithClipRatio(false);
1176
1177 if( g_curRomInfo.bZHack )
1178 {
1179 extern void HackZAll();
1180 HackZAll();
1181 }
1182
1183 bool res = RenderFlushTris();
1184 g_clippedVtxCount = 0;
1185
1186 gRSP.numVertices = 0; // Reset index
1187 gRSP.maxVertexID = 0;
1188
1189 if( !gRDP.bFogEnableInBlender && gRSP.bFogEnabled )
1190 TurnFogOnOff(true);
1191
1192 return res;
1193 }
1194
ReverseCITableLookup(uint32_t * pTable,int size,uint32_t val)1195 inline int ReverseCITableLookup(uint32_t *pTable, int size, uint32_t val)
1196 {
1197 for( int i=0; i<size; i++)
1198 {
1199 if( pTable[i] == val )
1200 return i;
1201 }
1202
1203 TRACE0("Cannot find value in CI table");
1204 return 0;
1205 }
1206
1207 extern RenderTextureInfo gRenderTextureInfos[];
SetVertexTextureUVCoord(TexCord & dst,const TexCord & src,int tile,TxtrCacheEntry * pEntry)1208 void SetVertexTextureUVCoord(TexCord &dst, const TexCord &src, int tile, TxtrCacheEntry *pEntry)
1209 {
1210 RenderTexture &txtr = g_textures[tile];
1211 RenderTextureInfo &info = gRenderTextureInfos[pEntry->txtrBufIdx-1];
1212 float s = src.u;
1213 float t = src.v;
1214
1215 uint32_t addrOffset = g_TI.dwAddr-info.CI_Info.dwAddr;
1216 uint32_t extraTop = (addrOffset>>(info.CI_Info.dwSize-1)) /info.CI_Info.dwWidth;
1217 uint32_t extraLeft = (addrOffset>>(info.CI_Info.dwSize-1))%info.CI_Info.dwWidth;
1218
1219 if( pEntry->txtrBufIdx > 0 )
1220 {
1221 // Loading from render_texture or back buffer
1222 s += (extraLeft+pEntry->ti.LeftToLoad)/txtr.m_fTexWidth;
1223 t += (extraTop+pEntry->ti.TopToLoad)/txtr.m_fTexHeight;
1224
1225 s *= info.scaleX;
1226 t *= info.scaleY;
1227 }
1228
1229 dst.u = s;
1230 dst.v = t;
1231 }
1232
SetVertexTextureUVCoord(TLITVERTEX & v,const TexCord & fTex0)1233 void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, const TexCord &fTex0)
1234 {
1235 RenderTexture &txtr = g_textures[0];
1236 if( txtr.pTextureEntry && txtr.pTextureEntry->txtrBufIdx > 0 )
1237 {
1238 ::SetVertexTextureUVCoord(v.tcord[0], fTex0, 0, txtr.pTextureEntry);
1239 }
1240 else
1241 {
1242 v.tcord[0] = fTex0;
1243 }
1244 }
1245
SetVertexTextureUVCoord(TLITVERTEX & v,float fTex0S,float fTex0T)1246 void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T)
1247 {
1248 TexCord t = { fTex0S, fTex0T };
1249 SetVertexTextureUVCoord(v, t);
1250 }
1251
SetVertexTextureUVCoord(TLITVERTEX & v,const TexCord & fTex0_,const TexCord & fTex1_)1252 void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, const TexCord &fTex0_, const TexCord &fTex1_)
1253 {
1254 TexCord fTex0 = fTex0_;
1255 TexCord fTex1 = fTex1_;
1256
1257 if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && m_Mux == 0x00262a60150c937fLL && gRSP.curTile == 0 )
1258 {
1259 // Hack for Zelda Sun
1260 gDPTile *t0 = &gDP.tiles[0];
1261 gDPTile *t1 = &gDP.tiles[1];
1262 if( t0->format == G_IM_FMT_I && t0->size == G_IM_SIZ_8b && t0->width == 64 &&
1263 t1->format == G_IM_FMT_I && t1->size == G_IM_SIZ_8b && t1->width == 64 &&
1264 t0->height == t1->height )
1265 {
1266 fTex0.u /= 2;
1267 fTex0.v /= 2;
1268 fTex1.u /= 2;
1269 fTex1.v /= 2;
1270 }
1271 }
1272
1273 RenderTexture &txtr0 = g_textures[0];
1274 if( txtr0.pTextureEntry && txtr0.pTextureEntry->txtrBufIdx > 0 )
1275 ::SetVertexTextureUVCoord(v.tcord[0], fTex0, 0, txtr0.pTextureEntry);
1276 else
1277 v.tcord[0] = fTex0;
1278
1279 RenderTexture &txtr1 = g_textures[1];
1280 if( txtr1.pTextureEntry && txtr1.pTextureEntry->txtrBufIdx > 0 )
1281 ::SetVertexTextureUVCoord(v.tcord[1], fTex1, 1, txtr1.pTextureEntry);
1282 else
1283 v.tcord[1] = fTex1;
1284 }
1285
SetVertexTextureUVCoord(TLITVERTEX & v,float fTex0S,float fTex0T,float fTex1S,float fTex1T)1286 void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T, float fTex1S, float fTex1T)
1287 {
1288 TexCord t0 = { fTex0S, fTex0T };
1289 TexCord t1 = { fTex1S, fTex1T };
1290 SetVertexTextureUVCoord(v, t0, t1);
1291 }
1292
SetClipRatio(uint32_t type,uint32_t w1)1293 void CRender::SetClipRatio(uint32_t type, uint32_t w1)
1294 {
1295 bool modified = false;
1296 switch(type)
1297 {
1298 case G_MWO_CLIP_RNX:
1299 if( gRSP.clip_ratio_negx != (short)w1 )
1300 {
1301 gRSP.clip_ratio_negx = (short)w1;
1302 modified = true;
1303 }
1304 break;
1305 case G_MWO_CLIP_RNY:
1306 if( gRSP.clip_ratio_negy != (short)w1 )
1307 {
1308 gRSP.clip_ratio_negy = (short)w1;
1309 modified = true;
1310 }
1311 break;
1312 case G_MWO_CLIP_RPX:
1313 if( gRSP.clip_ratio_posx != -(short)w1 )
1314 {
1315 gRSP.clip_ratio_posx = -(short)w1;
1316 modified = true;
1317 }
1318 break;
1319 case G_MWO_CLIP_RPY:
1320 if( gRSP.clip_ratio_posy != -(short)w1 )
1321 {
1322 gRSP.clip_ratio_posy = -(short)w1;
1323 modified = true;
1324 }
1325 break;
1326 }
1327
1328 if( modified )
1329 UpdateClipRectangle();
1330 }
1331
UpdateClipRectangle()1332 void CRender::UpdateClipRectangle()
1333 {
1334 if( status.bHandleN64RenderTexture )
1335 {
1336 //windowSetting.fMultX = windowSetting.fMultY = 1;
1337 windowSetting.vpLeftW = 0;
1338 windowSetting.vpTopW = 0;
1339 windowSetting.vpRightW = newRenderTextureInfo.bufferWidth;
1340 windowSetting.vpBottomW = newRenderTextureInfo.bufferHeight;
1341 windowSetting.vpWidthW = newRenderTextureInfo.bufferWidth;
1342 windowSetting.vpHeightW = newRenderTextureInfo.bufferHeight;
1343
1344 gRSP.vtxXMul = windowSetting.vpWidthW/2.0f;
1345 gRSP.vtxXAdd = gRSP.vtxXMul + windowSetting.vpLeftW;
1346 gRSP.vtxYMul = -windowSetting.vpHeightW/2.0f;
1347 gRSP.vtxYAdd = windowSetting.vpHeightW/2.0f + windowSetting.vpTopW;
1348
1349 // Update clip rectangle by setting scissor
1350
1351 int halfx = newRenderTextureInfo.bufferWidth/2;
1352 int halfy = newRenderTextureInfo.bufferHeight/2;
1353 int centerx = halfx;
1354 int centery = halfy;
1355
1356 gRSP.clip_ratio_left = centerx - halfx * gRSP.clip_ratio_negx;
1357 gRSP.clip_ratio_top = centery - halfy * gRSP.clip_ratio_negy;
1358 gRSP.clip_ratio_right = centerx + halfx * gRSP.clip_ratio_posx;
1359 gRSP.clip_ratio_bottom = centery + halfy * gRSP.clip_ratio_posy;
1360 }
1361 else
1362 {
1363 windowSetting.vpLeftW = int(gRSP.nVPLeftN * windowSetting.fMultX);
1364 windowSetting.vpTopW = int(gRSP.nVPTopN * windowSetting.fMultY);
1365 windowSetting.vpRightW = int(gRSP.nVPRightN* windowSetting.fMultX);
1366 windowSetting.vpBottomW = int(gRSP.nVPBottomN* windowSetting.fMultY);
1367 windowSetting.vpWidthW = int((gRSP.nVPRightN - gRSP.nVPLeftN + 1) * windowSetting.fMultX);
1368 windowSetting.vpHeightW = int((gRSP.nVPBottomN - gRSP.nVPTopN + 1) * windowSetting.fMultY);
1369
1370 gRSP.vtxXMul = windowSetting.vpWidthW/2.0f;
1371 gRSP.vtxXAdd = gRSP.vtxXMul + windowSetting.vpLeftW;
1372 gRSP.vtxYMul = -windowSetting.vpHeightW/2.0f;
1373 gRSP.vtxYAdd = windowSetting.vpHeightW/2.0f + windowSetting.vpTopW;
1374
1375 // Update clip rectangle by setting scissor
1376
1377 int halfx = gRSP.nVPWidthN/2;
1378 int halfy = gRSP.nVPHeightN/2;
1379 int centerx = gRSP.nVPLeftN+halfx;
1380 int centery = gRSP.nVPTopN+halfy;
1381
1382 gRSP.clip_ratio_left = centerx - halfx * gRSP.clip_ratio_negx;
1383 gRSP.clip_ratio_top = centery - halfy * gRSP.clip_ratio_negy;
1384 gRSP.clip_ratio_right = centerx + halfx * gRSP.clip_ratio_posx;
1385 gRSP.clip_ratio_bottom = centery + halfy * gRSP.clip_ratio_posy;
1386 }
1387
1388 UpdateScissorWithClipRatio();
1389 }
1390
UpdateScissorWithClipRatio()1391 void CRender::UpdateScissorWithClipRatio()
1392 {
1393 gRSP.real_clip_scissor_left = MAX(gRDP.scissor.left, gRSP.clip_ratio_left);
1394 gRSP.real_clip_scissor_top = MAX(gRDP.scissor.top, gRSP.clip_ratio_top);
1395 gRSP.real_clip_scissor_right = MIN(gRDP.scissor.right,gRSP.clip_ratio_right);
1396 gRSP.real_clip_scissor_bottom = MIN(gRDP.scissor.bottom, gRSP.clip_ratio_bottom);
1397
1398 gRSP.real_clip_scissor_left = MAX(gRSP.real_clip_scissor_left, 0);
1399 gRSP.real_clip_scissor_top = MAX(gRSP.real_clip_scissor_top, 0);
1400 gRSP.real_clip_scissor_right = MIN(gRSP.real_clip_scissor_right,windowSetting.uViWidth-1);
1401 gRSP.real_clip_scissor_bottom = MIN(gRSP.real_clip_scissor_bottom, windowSetting.uViHeight-1);
1402
1403 WindowSettingStruct &w = windowSetting;
1404 w.clipping.left = (uint32_t)(gRSP.real_clip_scissor_left*windowSetting.fMultX);
1405 w.clipping.top = (uint32_t)(gRSP.real_clip_scissor_top*windowSetting.fMultY);
1406 w.clipping.bottom = (uint32_t)(gRSP.real_clip_scissor_bottom*windowSetting.fMultY);
1407 w.clipping.right = (uint32_t)(gRSP.real_clip_scissor_right*windowSetting.fMultX);
1408
1409 if( w.clipping.left > 0 || w.clipping.top > 0 || w.clipping.right < (uint32_t)windowSetting.uDisplayWidth-1 ||
1410 w.clipping.bottom < (uint32_t)windowSetting.uDisplayHeight-1 )
1411 w.clipping.needToClip = true;
1412 else
1413 w.clipping.needToClip = false;
1414
1415 w.clipping.width = (uint32_t)((gRSP.real_clip_scissor_right-gRSP.real_clip_scissor_left+1)*windowSetting.fMultX);
1416 w.clipping.height = (uint32_t)((gRSP.real_clip_scissor_bottom-gRSP.real_clip_scissor_top+1)*windowSetting.fMultY);
1417
1418 float halfx = gRSP.nVPWidthN/2.0f;
1419 float halfy = gRSP.nVPHeightN/2.0f;
1420 float centerx = gRSP.nVPLeftN+halfx;
1421 float centery = gRSP.nVPTopN+halfy;
1422
1423 gRSP.real_clip_ratio_negx = (gRSP.real_clip_scissor_left - centerx)/halfx;
1424 gRSP.real_clip_ratio_negy = (gRSP.real_clip_scissor_top - centery)/halfy;
1425 gRSP.real_clip_ratio_posx = (gRSP.real_clip_scissor_right - centerx)/halfx;
1426 gRSP.real_clip_ratio_posy = (gRSP.real_clip_scissor_bottom - centery)/halfy;
1427
1428 ApplyScissorWithClipRatio(true);
1429 }
1430
1431
1432 // Set other modes not covered by color combiner or alpha blender
InitOtherModes(void)1433 void CRender::InitOtherModes(void)
1434 {
1435 ApplyTextureFilter();
1436
1437 //
1438 // I can't think why the hand in Mario's menu screen is rendered with an opaque rendermode,
1439 // and no alpha threshold. We set the alpha reference to 1 to ensure that the transparent pixels
1440 // don't get rendered. I hope this doesn't fuck anything else up.
1441 //
1442 if ( gRDP.otherMode.alpha_compare == 0 )
1443 {
1444 if ( gRDP.otherMode.cvg_x_alpha && (gRDP.otherMode.alpha_cvg_sel || gRDP.otherMode.aa_en ) )
1445 {
1446 ForceAlphaRef(128); // Strange, I have to use value=2 for pixel shader combiner for Nvidia FX5200
1447 // for other video cards, value=1 is good enough.
1448 SetAlphaTestEnable(true);
1449 }
1450 else
1451 SetAlphaTestEnable(false);
1452 }
1453 else if ( gRDP.otherMode.alpha_compare == 3 )
1454 {
1455 //RDP_ALPHA_COMPARE_DITHER
1456 SetAlphaTestEnable(false);
1457 }
1458 else
1459 {
1460 // Use CVG for pixel alpha
1461 if( (gRDP.otherMode.alpha_cvg_sel ) && !gRDP.otherMode.cvg_x_alpha )
1462 SetAlphaTestEnable(false);
1463 else
1464 {
1465 // RDP_ALPHA_COMPARE_THRESHOLD || RDP_ALPHA_COMPARE_DITHER
1466 if( m_dwAlpha==0 )
1467 ForceAlphaRef(1);
1468 else
1469 ForceAlphaRef(m_dwAlpha);
1470 SetAlphaTestEnable(true);
1471 }
1472 }
1473
1474 if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY && m_Mux == 0x00121824ff33ffffLL &&
1475 gRSP.bCullFront && gRDP.otherMode.aa_en && gRDP.otherMode.z_cmp && gRDP.otherMode.z_upd )
1476 {
1477 SetZCompare(false);
1478 }
1479
1480
1481 if( gRDP.otherMode.cycle_type >= G_CYC_COPY )
1482 {
1483 // Disable zbuffer for COPY and FILL mode
1484 SetZCompare(false);
1485 }
1486 else
1487 {
1488 SetZCompare(gRDP.otherMode.z_cmp);
1489 SetZUpdate(gRDP.otherMode.z_upd);
1490 }
1491
1492 /*
1493 if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY && m_Mux == 0x00121824ff33ffff &&
1494 gRSP.bCullFront && gRDP.otherMode.z_cmp && gRDP.otherMode.z_upd )//&& gRDP.otherMode.aa_en )
1495 {
1496 SetZCompare(false);
1497 SetZUpdate(false);
1498 }
1499 */
1500 }
1501
1502
SetTextureFilter(uint32_t dwFilter)1503 void CRender::SetTextureFilter(uint32_t dwFilter)
1504 {
1505 if( options.forceTextureFilter == FORCE_DEFAULT_FILTER )
1506 {
1507 switch(dwFilter)
1508 {
1509 case RDP_TFILTER_AVERAGE: //?
1510 case RDP_TFILTER_BILERP:
1511 m_dwMinFilter = m_dwMagFilter = FILTER_LINEAR;
1512 break;
1513 default:
1514 m_dwMinFilter = m_dwMagFilter = FILTER_POINT;
1515 break;
1516 }
1517 }
1518 else
1519 {
1520 switch( options.forceTextureFilter )
1521 {
1522 case FORCE_POINT_FILTER:
1523 m_dwMinFilter = m_dwMagFilter = FILTER_POINT;
1524 break;
1525 case FORCE_LINEAR_FILTER:
1526 m_dwMinFilter = m_dwMagFilter = FILTER_LINEAR;
1527 break;
1528 }
1529 }
1530
1531 ApplyTextureFilter();
1532 }
1533