22726e4d |
1 | /****************************************************************************** |
2 | * Arachnoid Graphics Plugin for Mupen64Plus |
3 | * http://bitbucket.org/wahrhaft/mupen64plus-video-arachnoid/ |
4 | * |
5 | * Copyright (C) 2007 Kristofer Karlsson, Rickard Niklasson |
6 | * |
7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2 |
10 | * of the License, or (at your option) any later version. |
11 | * |
12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU General Public License |
18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | *****************************************************************************/ |
21 | |
22 | #include "RDP.h" |
23 | #include "GBIDefs.h" |
24 | #include "GBI.h" |
25 | #include "RSP.h" |
26 | #include "DisplayListParser.h" |
27 | #include "assembler.h" |
28 | #include "OpenGLRenderer.h" |
29 | #include "TextureCache.h" |
30 | #include "VI.h" |
31 | #include "Memory.h" |
32 | #include "OpenGLManager.h" |
33 | #include "OpenGL2DRenderer.h" |
34 | #include "AdvancedCombinerManager.h" |
35 | #include "FogManager.h" |
36 | #include "Logger.h" |
37 | #include "MathLib.h" |
38 | #include "RomDetector.h" |
39 | #include "m64p.h" |
40 | #include "OpenGL.h" |
41 | #include <algorithm> |
42 | using std::max; |
43 | |
44 | //----------------------------------------------------------------------------- |
45 | //! Defines |
46 | //----------------------------------------------------------------------------- |
47 | #define MI_INTR_DP 0x00000020 //!< RDP Interrupt signal |
48 | |
49 | //----------------------------------------------------------------------------- |
50 | //! Static Variables |
51 | //----------------------------------------------------------------------------- |
52 | Memory* RDP::m_memory = 0; |
53 | |
54 | //----------------------------------------------------------------------------- |
55 | //! Constructor |
56 | //----------------------------------------------------------------------------- |
57 | RDP::RDP() |
58 | { |
59 | m_graphicsInfo = 0; |
60 | m_changedTiles = false; |
61 | m_textureMode = TM_NORMAL; |
62 | m_loadType = LOADTYPE_BLOCK; |
63 | m_tmemChanged = false; |
64 | m_textureLUT = 0; |
65 | m_texRectWidth = 1; |
66 | m_texRectHeight = 1; |
67 | m_displayListParser = 0; |
68 | m_primitiveZ = 0; |
69 | m_combinerMgr = 0; |
70 | m_textureLoader = 0; |
71 | m_openGL2DRenderer = 0; |
72 | m_screenUpdatePending= false; |
73 | } |
74 | |
75 | //----------------------------------------------------------------------------- |
76 | //! Destructor |
77 | //----------------------------------------------------------------------------- |
78 | RDP::~RDP() |
79 | { |
80 | } |
81 | |
82 | //----------------------------------------------------------------------------- |
83 | //* Initialize |
84 | //! Sets pointers to managers and initializes objects |
85 | //----------------------------------------------------------------------------- |
86 | bool RDP::initialize(GFX_INFO* graphicsInfo, RSP* rsp, Memory* memory, GBI* gbi, TextureCache* textureCache, VI* vi, DisplayListParser* displayListParser, FogManager* fogMgr) |
87 | { |
88 | //Set pointers |
89 | m_graphicsInfo = graphicsInfo; |
90 | m_rsp = rsp; |
91 | m_vi = vi; |
92 | m_memory = memory; |
93 | m_displayListParser = displayListParser; |
94 | m_textureCache = textureCache; |
95 | m_fogMgr = fogMgr; |
96 | |
97 | //Create combiner manager |
98 | m_combinerMgr = new AdvancedCombinerManager(); |
99 | m_combinerMgr->initialize(); |
100 | |
101 | //Create texture loader |
102 | m_textureLoader = new TextureLoader(); |
103 | m_textureLoader->initialize(this, m_memory); |
104 | |
105 | //Create OpenGL 2D Renderer |
106 | m_openGL2DRenderer = new OpenGL2DRenderer(); |
107 | m_openGL2DRenderer->initialize(vi); |
108 | |
109 | return true; |
110 | } |
111 | |
112 | //----------------------------------------------------------------------------- |
113 | //* Dispose |
114 | //! Delets all allocated memory |
115 | //----------------------------------------------------------------------------- |
116 | void RDP::dispose() |
117 | { |
118 | if ( m_combinerMgr ) { delete m_combinerMgr; m_combinerMgr = 0; } |
119 | if ( m_textureLoader ) { delete m_textureLoader; m_textureLoader = 0; } |
120 | if ( m_openGL2DRenderer ) { delete m_openGL2DRenderer; m_openGL2DRenderer = 0; } |
121 | } |
122 | |
123 | //----------------------------------------------------------------------------- |
124 | //* Update States |
125 | //! Sets OpenGL states, updates combiner, activates textures, sets blender |
126 | //----------------------------------------------------------------------------- |
127 | void RDP::updateStates() |
128 | { |
129 | //Depth Compare |
130 | if (m_otherMode.depthCompare) |
131 | glDepthFunc( GL_LEQUAL ); |
132 | else |
133 | glDepthFunc( GL_ALWAYS ); |
134 | |
135 | //Depth Update |
136 | if (m_otherMode.depthUpdate) |
137 | glDepthMask( true ); |
138 | else |
139 | glDepthMask( false ); |
140 | |
141 | // Depth Mode |
142 | if (m_otherMode.depthMode == ZMODE_DEC) |
143 | { |
144 | glEnable( GL_POLYGON_OFFSET_FILL ); |
145 | glPolygonOffset( -3.0f, -3.0f ); |
146 | } |
147 | else |
148 | { |
149 | glDisable( GL_POLYGON_OFFSET_FILL ); |
150 | } |
151 | |
152 | // Alpha Compare |
153 | if ((m_otherMode.alphaCompare == G_AC_THRESHOLD) && !(m_otherMode.alphaCvgSel)) |
154 | { |
155 | glEnable( GL_ALPHA_TEST ); |
156 | glAlphaFunc( (m_combinerMgr->getBlendColor()[3] > 0.0f) ? GL_GEQUAL : GL_GREATER, m_combinerMgr->getBlendColor()[3] ); |
157 | } |
158 | // Used in TEX_EDGE and similar render modes |
159 | else if (m_otherMode.cvgXAlpha) |
160 | { |
161 | glEnable( GL_ALPHA_TEST ); |
162 | glAlphaFunc( GL_GEQUAL, 0.5f ); // Arbitrary number -- gives nice results though |
163 | } |
164 | else |
165 | glDisable( GL_ALPHA_TEST ); |
166 | |
167 | //Combiner |
168 | if ( m_updateCombiner ) |
169 | { |
170 | if ( m_otherMode.cycleType == G_CYC_COPY) |
171 | { |
172 | m_combinerMgr->setMux(72057594037727865LL, m_otherMode.cycleType); //Only normal texturing |
173 | m_combinerMgr->selectCombine(m_otherMode.cycleType); |
174 | } |
175 | else if ( m_otherMode.cycleType == G_CYC_FILL ) |
176 | { |
177 | m_combinerMgr->setMux( 72057594037828926LL, m_otherMode.cycleType ); |
178 | m_combinerMgr->selectCombine(m_otherMode.cycleType); |
179 | } |
180 | else |
181 | { |
182 | m_combinerMgr->selectCombine(m_otherMode.cycleType); |
183 | } |
184 | m_updateCombiner = false; |
185 | m_updateCombineColors = true; |
186 | } |
187 | |
188 | if ( m_updateCombineColors ) |
189 | { |
190 | m_combinerMgr->updateCombineColors(); |
191 | m_updateCombineColors = false; |
192 | } |
193 | |
194 | //Texturing |
195 | if ( m_changedTiles || m_tmemChanged || m_rsp->getTexturesChanged() ) |
196 | { |
197 | m_combinerMgr->beginTextureUpdate(); |
198 | |
199 | //Update Texture channel 0 |
200 | if ( m_combinerMgr->getUsesTexture0() ) |
201 | { |
202 | //Enable texture 0 |
203 | m_textureCache->update(0); |
204 | m_rsp->setTexturesChanged(false); |
205 | m_changedTiles = false; |
206 | m_tmemChanged = false; |
207 | } |
208 | else |
209 | { |
210 | //Disable texture 0 |
211 | glActiveTextureARB( GL_TEXTURE0_ARB + 0 ); |
212 | glDisable(GL_TEXTURE_2D); |
213 | } |
214 | |
215 | //Update Texture channel 1 |
216 | if ( m_combinerMgr->getUsesTexture1() ) |
217 | { |
218 | //Enable texture 1 |
219 | m_textureCache->update(1); |
220 | m_rsp->setTexturesChanged(false); |
221 | m_changedTiles = false; |
222 | m_tmemChanged = false; |
223 | } |
224 | else |
225 | { |
226 | //Disable textureing 1 |
227 | glActiveTextureARB( GL_TEXTURE0_ARB + 1 ); |
228 | glDisable(GL_TEXTURE_2D); |
229 | } |
230 | |
231 | m_combinerMgr->endTextureUpdate(); |
232 | } |
233 | |
234 | // Blending |
235 | if ( (m_otherMode.forceBlender) && |
236 | (m_otherMode.cycleType != G_CYC_COPY) && |
237 | (m_otherMode.cycleType != G_CYC_FILL) && |
238 | !(m_otherMode.alphaCvgSel)) |
239 | { |
240 | glEnable( GL_BLEND ); |
241 | switch (m_otherMode.l >> 16) |
242 | { |
243 | case 0x0448: // Add |
244 | case 0x055A: |
245 | glBlendFunc( GL_ONE, GL_ONE ); |
246 | break; |
247 | case 0x0C08: // 1080 Sky |
248 | case 0x0F0A: // Used LOTS of places |
249 | glBlendFunc( GL_ONE, GL_ZERO ); |
250 | break; |
251 | case 0xC810: // Blends fog |
252 | case 0xC811: // Blends fog |
253 | case 0x0C18: // Standard interpolated blend |
254 | case 0x0C19: // Used for antialiasing |
255 | case 0x0050: // Standard interpolated blend |
256 | case 0x0055: // Used for antialiasing |
257 | glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); |
258 | break; |
259 | case 0x0FA5: // Seems to be doing just blend color - maybe combiner can be used for this? |
260 | case 0x5055: // Used in Paper Mario intro, I'm not sure if this is right... |
261 | glBlendFunc( GL_ZERO, GL_ONE ); |
262 | break; |
263 | default: |
264 | glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); |
265 | break; |
266 | } |
267 | } |
268 | else |
269 | glDisable( GL_BLEND ); |
270 | |
271 | if (m_otherMode.cycleType == G_CYC_FILL) |
272 | { |
273 | glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); |
274 | glEnable( GL_BLEND ); |
275 | } |
276 | } |
277 | |
278 | //----------------------------------------------------------------------------- |
279 | //* Reset |
280 | //! Resets all states on RDP |
281 | //----------------------------------------------------------------------------- |
282 | void RDP::reset() |
283 | { |
284 | setTextureFiltering( G_TF_POINT ); |
285 | setRenderMode(0); |
286 | } |
287 | |
288 | //----------------------------------------------------------------------------- |
289 | //* Trigger Interrupt |
290 | //! Tell emulator that the RDP is idle |
291 | //----------------------------------------------------------------------------- |
292 | void RDP::triggerInterrupt() |
293 | { |
294 | *(m_graphicsInfo->MI_INTR_REG) |= MI_INTR_DP; |
295 | m_graphicsInfo->CheckInterrupts(); |
296 | } |
297 | |
298 | //----------------------------------------------------------------------------- |
299 | //* Set Alpha Compare Mode |
300 | //----------------------------------------------------------------------------- |
301 | void RDP::setAlphaCompareMode(unsigned int mode) |
302 | { |
303 | m_otherMode.alphaCompare = mode; |
304 | OpenGLManager::getSingleton().setAlphaTest( m_otherMode.alphaCompare != 0 ); |
305 | } |
306 | |
307 | //----------------------------------------------------------------------------- |
308 | //* Set Render Mode |
309 | //----------------------------------------------------------------------------- |
310 | void RDP::setRenderMode(unsigned int w1) |
311 | { |
312 | unsigned int mode1 = (w1 & 0xCCCCFFFF); |
313 | unsigned int mode2 = (w1 & 0x3333FFFF); |
314 | |
315 | m_otherMode.l &= 0x00000007; |
316 | m_otherMode.l |= mode1 | mode2; |
317 | } |
318 | |
319 | //############################################################################# |
320 | // UCODE FUNCTIONS: |
321 | //############################################################################# |
322 | |
323 | //***************************************************************************** |
324 | // Combiner Mode |
325 | //***************************************************************************** |
326 | |
327 | //----------------------------------------------------------------------------- |
328 | //* Set Combine |
329 | //! Sets all combiner variables on combiner that tells it how to combine |
330 | //! the diffrent colors and textures. |
331 | //----------------------------------------------------------------------------- |
332 | void RDP::RDP_SetCombine(MicrocodeArgument* ucode) |
333 | { |
334 | int mux0 = _SHIFTR( ucode->w0, 0, 24 ); |
335 | int mux1 = ucode->w1; |
336 | m_combinerMgr->setMux(mux0, mux1, (G_CYCLE_TYPE)m_otherMode.cycleType); |
337 | |
338 | m_updateCombiner = true; |
339 | } |
340 | |
341 | //***************************************************************************** |
342 | // Colors |
343 | //***************************************************************************** |
344 | |
345 | //----------------------------------------------------------------------------- |
346 | //* Set Environment Color |
347 | //! Sets Environment Color on combiner |
348 | //! @param r Red component of color (0.0 - 1.0) |
349 | //! @param g Green component of color (0.0 - 1.0) |
350 | //! @param b Blue component of color (0.0 - 1.0) |
351 | //! @param a Alpha component of color (0.0 - 1.0) |
352 | //----------------------------------------------------------------------------- |
353 | void RDP::RDP_SetEnvColor(float r, float g, float b, float a) |
354 | { |
355 | m_combinerMgr->setEnvColor(r, g, b, a); |
356 | m_updateCombineColors = true; |
357 | } |
358 | |
359 | //----------------------------------------------------------------------------- |
360 | //* Set Prim Color |
361 | //! Sets Prim Color on combiner |
362 | //! @param r Red component of color (0.0 - 1.0) |
363 | //! @param g Green component of color (0.0 - 1.0) |
364 | //! @param b Blue component of color (0.0 - 1.0) |
365 | //! @param a Alpha component of color (0.0 - 1.0) |
366 | //! @param primLodMin |
367 | //! @param primLevel |
368 | //----------------------------------------------------------------------------- |
369 | void RDP::RDP_SetPrimColor(float r, float g, float b, float a, unsigned int primLodMin, unsigned int primLevel) |
370 | { |
371 | int primLodFrac = max(primLevel, primLodMin); |
372 | m_combinerMgr->setPrimLodMin(primLodMin); |
373 | m_combinerMgr->setPrimLodFrac(primLodFrac / 255.0f); |
374 | m_combinerMgr->setPrimColor(r, g, b, a); |
375 | m_updateCombineColors = true; |
376 | } |
377 | |
378 | //----------------------------------------------------------------------------- |
379 | //* Set Blend Color |
380 | //! Sets Blend Color on combiner |
381 | //! @param r Red component of color (0.0 - 1.0) |
382 | //! @param g Green component of color (0.0 - 1.0) |
383 | //! @param b Blue component of color (0.0 - 1.0) |
384 | //! @param a Alpha component of color (0.0 - 1.0) |
385 | //----------------------------------------------------------------------------- |
386 | void RDP::RDP_SetBlendColor(float r, float g, float b, float a) |
387 | { |
388 | m_combinerMgr->setBlendColor(r, g, b, a); |
389 | m_updateCombineColors = true; |
390 | } |
391 | |
392 | //----------------------------------------------------------------------------- |
393 | //* Set Fill Color |
394 | //! Sets Fill Color on combiner |
395 | //! @param r Red component of color (0.0 - 1.0) |
396 | //! @param g Green component of color (0.0 - 1.0) |
397 | //! @param b Blue component of color (0.0 - 1.0) |
398 | //! @param a Alpha component of color (0.0 - 1.0) |
399 | //----------------------------------------------------------------------------- |
400 | void RDP::RDP_SetFillColor(float r, float g, float b, float a) |
401 | { |
402 | m_combinerMgr->setFillColor(r, g, b, a); |
403 | m_updateCombineColors = true; |
404 | } |
405 | |
406 | //----------------------------------------------------------------------------- |
407 | //* Set Fog Color |
408 | //! Sets fog color used when rendering fog |
409 | //! @param r Red component of color (0.0 - 1.0) |
410 | //! @param g Green component of color (0.0 - 1.0) |
411 | //! @param b Blue component of color (0.0 - 1.0) |
412 | //! @param a Alpha component of color (0.0 - 1.0) |
413 | //----------------------------------------------------------------------------- |
414 | void RDP::RDP_SetFogColor(float r, float g, float b, float a) |
415 | { |
416 | m_fogMgr->setFogColor(r, g, b, a); |
417 | } |
418 | |
419 | //***************************************************************************** |
420 | // Misc |
421 | //***************************************************************************** |
422 | |
423 | //----------------------------------------------------------------------------- |
424 | //! Set Other Mode |
425 | //----------------------------------------------------------------------------- |
426 | void RDP::RDP_SetOtherMode(MicrocodeArgument* ucode) |
427 | { |
428 | unsigned int mode0 = _SHIFTR( ucode->w0, 0, 24 ); |
429 | unsigned int mode1 = ucode->w1; |
430 | |
431 | m_otherMode.h = mode0; |
432 | m_otherMode.l = mode1; |
433 | } |
434 | |
435 | //----------------------------------------------------------------------------- |
436 | //! Set Prim Depth |
437 | //----------------------------------------------------------------------------- |
438 | void RDP::RDP_SetPrimDepth(unsigned int dwZ, unsigned int dwDZ) |
439 | { |
440 | unsigned int primitiveDepth = dwZ & 0x7FFF; |
441 | |
442 | //Convert to float |
443 | m_primitiveZ = (float)(primitiveDepth)/(float)0x8000; |
444 | } |
445 | |
446 | //----------------------------------------------------------------------------- |
447 | //! Set Scissor |
448 | //----------------------------------------------------------------------------- |
449 | void RDP::RDP_SetScissor(int x0, int y0, int x1, int y1, int mode) |
450 | { |
451 | //Get Scale |
452 | float vsx = OpenGLManager::getSingleton().getViewScaleX(); |
453 | float vsy = OpenGLManager::getSingleton().getViewScaleY(); |
454 | |
455 | //Get Offset |
456 | int offset = 0; //TODO: height offset? |
457 | |
458 | //Set Scissor |
459 | OpenGLManager::getSingleton().setScissor( |
460 | x0 * vsx, |
461 | (m_vi->getHeight() - y1) * vsy + offset, |
462 | (x1 - x0) * vsx, |
463 | (y1 - y0) * vsy |
464 | ); |
465 | } |
466 | |
467 | //----------------------------------------------------------------------------- |
468 | //* Set Full Sync |
469 | //! Called when RDP is finished |
470 | //----------------------------------------------------------------------------- |
471 | void RDP::RDP_FullSync() |
472 | { |
473 | this->triggerInterrupt(); |
474 | } |
475 | |
476 | //***************************************************************************** |
477 | // Rendering |
478 | //***************************************************************************** |
479 | |
480 | //----------------------------------------------------------------------------- |
481 | //* Fill Rect |
482 | //! Renders a rectangle |
483 | //----------------------------------------------------------------------------- |
484 | void RDP::RDP_FillRect(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1) |
485 | { |
486 | //Logger::getSingleton() << "RDP_FillRect: " << (int)x0 << " " << (int)y0 << " " << (int)x1 << " " << (int)y1 << "\n"; |
487 | |
488 | //Increase rectangle size? |
489 | if( m_otherMode.cycleType >= G_CYC_COPY ) |
490 | { |
491 | x1++; |
492 | y1++; |
493 | } |
494 | |
495 | //Clear Depth Buffer? |
496 | if ( m_depthImageInfo.rdramAddress == m_colorImageInfo.rdramAddress ) |
497 | { |
498 | //Clear the Z Buffer |
499 | updateStates(); |
500 | glDepthMask( true ); |
501 | glClear(GL_DEPTH_BUFFER_BIT); |
502 | |
503 | // Depth update |
504 | if (m_otherMode.depthUpdate) |
505 | { |
506 | glDepthMask(GL_TRUE); |
507 | } |
508 | else |
509 | { |
510 | glDepthMask(GL_FALSE); |
511 | } |
512 | |
513 | return; |
514 | } |
515 | |
516 | //Clear Color Buffer? |
517 | if ( m_otherMode.cycleType == G_CYC_FILL) |
518 | { |
519 | if ( x0 == 0 && y0 == 0 && x1 == m_vi->getWidth() && y1 == m_vi->getHeight() ) |
520 | { |
521 | const float* fillColor = m_combinerMgr->getFillColor(); |
522 | glClearColor(fillColor[0], fillColor[1], fillColor[2], fillColor[3]); |
523 | bool scissor = OpenGLManager::getSingleton().getScissorEnabled(); |
524 | OpenGLManager::getSingleton().setScissorEnabled(false); |
525 | glClear(GL_COLOR_BUFFER_BIT); |
526 | OpenGLManager::getSingleton().setScissorEnabled(scissor); |
527 | return; |
528 | } |
529 | } |
530 | |
531 | //Update States |
532 | this->updateStates(); |
533 | |
534 | //Ignore fill rects? |
535 | if ( ROMDetector::getSingleton().getIgnoreFillRects() ) |
536 | { |
537 | return; |
538 | } |
539 | |
540 | //Disable Scissor |
541 | glDisable( GL_SCISSOR_TEST ); |
542 | |
543 | //Set Viewport |
544 | //int oldViewport[4]; |
545 | //glGetIntegerv(GL_VIEWPORT, oldViewport); |
546 | //glViewport(0, 0, OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() ); |
547 | glDepthRange(0.0f, 1.0f); |
548 | |
549 | //Get depth and color |
550 | float depth = m_otherMode.depthSource == 1 ? m_primitiveZ : 0; //TODO: Use RSP viewport nearz? |
551 | float* color = m_otherMode.cycleType == G_CYC_FILL ? m_combinerMgr->getFillColor() : m_combinerMgr->getPrimColor(); |
552 | |
553 | //Render rectangle |
554 | m_openGL2DRenderer->renderQuad(color, x0, y0, x1, y1, depth); |
555 | |
556 | //Reset viewport |
557 | //glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); |
558 | |
559 | //Reset Scissor |
560 | glEnable( GL_SCISSOR_TEST ); |
561 | } |
562 | |
563 | //----------------------------------------------------------------------------- |
564 | // Texture Rectangle Flip |
565 | //----------------------------------------------------------------------------- |
566 | void RDP::RDP_TexRectFlip(unsigned int dwXH, unsigned int dwYH, unsigned int dwXL, unsigned int dwYL, |
567 | unsigned int tileno, unsigned int dwS, unsigned int dwT, int nDSDX, int nDTDY) |
568 | { |
569 | Logger::getSingleton().printMsg("RDP_TexRect"); |
570 | |
571 | float fS0 = (float)dwS / 32.0f; |
572 | float fT0 = (float)dwT / 32.0f; |
573 | |
574 | float fDSDX = (float)nDSDX / 1024.0f; |
575 | float fDTDY = (float)nDTDY / 1024.0f; |
576 | |
577 | if (m_otherMode.cycleType == G_CYC_COPY) |
578 | { |
579 | fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once. |
580 | dwXH++; |
581 | dwYH++; |
582 | } |
583 | else if (m_otherMode.cycleType == G_CYC_FILL ) |
584 | { |
585 | dwXH++; |
586 | dwYH++; |
587 | } |
588 | |
589 | float fS1 = fS0 + (fDSDX * (dwYH - dwYL)); |
590 | float fT1 = fT0 + (fDTDY * (dwXH - dwXL)); |
591 | |
592 | //Set Current Texture tiles |
593 | m_rsp->setTile( m_textureLoader->getTile(tileno), 0); |
594 | if ( tileno < 7 ) |
595 | { |
596 | m_rsp->setTile( m_textureLoader->getTile(tileno + 1), 1); |
597 | } |
598 | else { |
599 | m_rsp->setTile( m_textureLoader->getTile(tileno), 1); |
600 | } |
601 | |
602 | m_texRectWidth = (unsigned int)fS1; |
603 | m_texRectHeight = (unsigned int)fT1; |
604 | |
605 | //Update States |
606 | this->updateStates(); |
607 | |
608 | float t0u0 = 0, t0v0 = 0, t0u1 =0, t0v1 = 0; |
609 | if ( m_textureCache->getCurrentTexture(0) ) |
610 | { |
611 | t0u0 = (fS0) * m_textureCache->getCurrentTexture(0)->shiftScaleS - m_textureLoader->getTile(tileno)->uls; |
612 | t0v0 = (fT0) * m_textureCache->getCurrentTexture(0)->shiftScaleT - m_textureLoader->getTile(tileno)->ult; |
613 | t0u1 = t0u0 + (fDSDX * (dwYH - dwYL))*m_textureCache->getCurrentTexture(0)->shiftScaleS; |
614 | t0v1 = t0v0 + (fDTDY * (dwXH - dwXL))*m_textureCache->getCurrentTexture(0)->shiftScaleT; |
615 | } |
616 | |
617 | _textureRectangleFlip(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); |
618 | |
619 | //Restore RSP Tile |
620 | int rspTile = m_rsp->getTexture().tile; |
621 | m_rsp->setTile( m_textureLoader->getTile(tileno), 0); |
622 | m_rsp->setTile( m_textureLoader->getTile(rspTile < 7 ? rspTile + 1 : rspTile), 1); |
623 | } |
624 | |
625 | //----------------------------------------------------------------------------- |
626 | //* Texture Rect |
627 | //! Not this command use 128bits and not 64 bits wich could cause some |
628 | //! problems with the program counter. |
629 | //----------------------------------------------------------------------------- |
630 | void RDP::RDP_TexRect(unsigned int dwXH, unsigned int dwYH, unsigned int dwXL, unsigned int dwYL, |
631 | unsigned int tileno, unsigned short dwS, unsigned short dwT, unsigned short nDSDX, unsigned short nDTDY) |
632 | { |
633 | Logger::getSingleton().printMsg("RDP_TexRect"); |
634 | |
635 | glEnable(GL_TEXTURE_2D); |
636 | |
637 | //Convert to signed |
638 | short s16S = *(short*)(&dwS); |
639 | short s16T = *(short*)(&dwT); |
640 | short s16DSDX = *(short*)(&nDSDX); |
641 | short s16DTDY = *(short*)(&nDTDY); |
642 | |
643 | //Convert to float |
644 | float s = s16S / 32.0f; |
645 | float t = s16T / 32.0f; |
646 | float dsdx = s16DSDX / 1024.0f; |
647 | float dtdy = s16DTDY / 1024.0f; |
648 | |
649 | |
650 | float ulx = (float)dwXH; |
651 | float uly = (float)dwYH; |
652 | float lrx = (float)dwXL; |
653 | float lry = (float)dwYL; |
654 | |
655 | int tile = tileno; |
656 | |
657 | _textureRectangle(ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy, false); |
658 | } |
659 | |
660 | //***************************************************************************** |
661 | // Texturing |
662 | //***************************************************************************** |
663 | |
664 | //----------------------------------------------------------------------------- |
665 | //* Set Color Image |
666 | //! Sets information about color image |
667 | //----------------------------------------------------------------------------- |
668 | void RDP::RDP_SetCImg(unsigned int format, unsigned int size, unsigned int width, unsigned int segmentAddress) |
669 | { |
670 | m_colorImageInfo.rdramAddress = m_memory->getRDRAMAddress( segmentAddress ); |
671 | m_colorImageInfo.format = format; |
672 | m_colorImageInfo.size = size; |
673 | m_colorImageInfo.width = width + 1; //Note: add plus one |
674 | m_colorImageInfo.bpl = m_colorImageInfo.width << m_colorImageInfo.size >> 1; |
675 | |
676 | if (m_screenUpdatePending) |
677 | { |
678 | OpenGLManager::getSingleton().endRendering(); |
679 | m_screenUpdatePending = false; |
680 | } |
681 | } |
682 | |
683 | //----------------------------------------------------------------------------- |
684 | //* Set Z Image |
685 | //! Sets information about depth image |
686 | //----------------------------------------------------------------------------- |
687 | void RDP::RDP_SetZImg(unsigned int format, unsigned int size, unsigned int width, unsigned int segmentAddress) |
688 | { |
689 | m_depthImageInfo.rdramAddress = m_memory->getRDRAMAddress( segmentAddress ); |
690 | m_depthImageInfo.format = format; |
691 | m_depthImageInfo.size = size; |
692 | m_depthImageInfo.width = width + 1; //Note: add plus one |
693 | m_depthImageInfo.bpl = m_colorImageInfo.width << m_colorImageInfo.size >> 1; |
694 | } |
695 | |
696 | //----------------------------------------------------------------------------- |
697 | //* Set Texture Image |
698 | //! Sets information about texture image |
699 | //----------------------------------------------------------------------------- |
700 | void RDP::RDP_SetTImg(unsigned int format, unsigned int size, unsigned int width, unsigned int segmentAddress) |
701 | { |
702 | m_textureLoader->setTextureImage(format, size, width, segmentAddress); |
703 | } |
704 | |
705 | //----------------------------------------------------------------------------- |
706 | // Set Tile |
707 | //----------------------------------------------------------------------------- |
708 | void RDP::RDP_SetTile(int format, int size, int line, int tmem, int tile, |
709 | int palette, int clampS, int clampT, int mirrorS, |
710 | int mirrorT, int maskS, int maskT, int shiftS, int shiftT ) |
711 | { |
712 | //Set Tile |
713 | m_textureLoader->setTile( format, size, line, tmem, tile, palette, |
714 | clampS, clampT, mirrorS, mirrorT, maskS, maskT, |
715 | shiftS, shiftT ); |
716 | |
717 | //m_changedTiles = true; ??? Not needed? |
718 | } |
719 | |
720 | //----------------------------------------------------------------------------- |
721 | //* Load Tile |
722 | //----------------------------------------------------------------------------- |
723 | void RDP::RDP_LoadTile(int tile, int s0, int t0, int s1, int t1) |
724 | { |
725 | //Load Tile |
726 | m_textureLoader->loadTile(tile, s0, t0, s1, t1); |
727 | |
728 | m_textureMode = TM_NORMAL; |
729 | m_loadType = LOADTYPE_TILE; |
730 | m_tmemChanged = true; |
731 | } |
732 | |
733 | //----------------------------------------------------------------------------- |
734 | // Load Block |
735 | //----------------------------------------------------------------------------- |
736 | void RDP::RDP_LoadBlock(int tile, int s0, int t0, int s1, int t1) |
737 | { |
738 | //Load Block |
739 | m_textureLoader->loadBlock(tile, s0, t0, s1, t1); |
740 | |
741 | m_textureMode = TM_NORMAL; |
742 | m_loadType = LOADTYPE_BLOCK; |
743 | m_tmemChanged = true; |
744 | } |
745 | |
746 | //----------------------------------------------------------------------------- |
747 | //! Sets the size of tile |
748 | //! @Param tile Index of the tile to set size on |
749 | //! @param s0 Texture Coordinats for first vertex coordinate |
750 | //! @param t0 Texture Coordinats for first vertex coordinate |
751 | //! @param s1 Texture Coordinats for second vertex coordinate |
752 | //! @param t1 Texture Coordinats for second vertex coordinate |
753 | //----------------------------------------------------------------------------- |
754 | void RDP::RDP_SetTileSize(int tile, unsigned int s0, unsigned int t0, unsigned int s1, unsigned int t1) |
755 | { |
756 | m_textureLoader->setTileSize( tile, s0, t0, s1, t1); |
757 | |
758 | m_changedTiles = true; |
759 | } |
760 | |
761 | //----------------------------------------------------------------------------- |
762 | // Load Texture Look Up Table |
763 | //----------------------------------------------------------------------------- |
764 | void RDP::RDP_LoadTLUT(int tile, int s0, int t0, int s1, int t1) |
765 | { |
766 | m_textureLoader->loadTLUT(tile, s0, t0, s1, t1); |
767 | |
768 | m_tmemChanged = true; |
769 | } |
770 | |
771 | //***************************************************************************** |
772 | // Private Functions |
773 | //***************************************************************************** |
774 | |
775 | //----------------------------------------------------------------------------- |
776 | // Texture Rectangle |
777 | //----------------------------------------------------------------------------- |
778 | void RDP::_textureRectangle(float ulx, float uly, float lrx, float lry, int tile, float s, float t, float dsdx, float dtdy,bool flip) |
779 | { |
780 | bool zEnabled = OpenGLManager::getSingleton().getZBufferEnabled(); |
781 | OpenGLManager::getSingleton().setZBufferEnabled(false); |
782 | |
783 | //Copy Mode |
784 | if ( m_otherMode.cycleType == G_CYC_COPY ) |
785 | { |
786 | dsdx = 1.0; |
787 | lrx += 1.0f; |
788 | lry += 1.0f; |
789 | } |
790 | else if (m_otherMode.cycleType == G_CYC_FILL ) |
791 | { |
792 | lrx++; |
793 | lry++; |
794 | } |
795 | |
796 | //Set Current Texture tiles |
797 | m_rsp->setTile( m_textureLoader->getTile(tile), 0); |
798 | m_rsp->setTile( m_textureLoader->getTile(tile < 7 ? tile + 1 : tile), 1); |
799 | |
800 | |
801 | float lrs = s + (lrx - ulx - 1) * dsdx; |
802 | float lrt = t + (lry - uly - 1) * dtdy; |
803 | |
804 | //Change mode to texture rectangle |
805 | if ( m_textureMode == TM_NORMAL ) |
806 | m_textureMode = TM_TEXRECT; |
807 | |
808 | m_texRectWidth = (unsigned int)(max( lrs, s ) + dsdx); |
809 | m_texRectHeight = (unsigned int)(max( lrt, t ) + dtdy); |
810 | |
811 | //Update States |
812 | this->updateStates(); |
813 | |
814 | //glViewport( 0, 0, OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() ); |
815 | |
816 | glDisable(GL_SCISSOR_TEST); |
817 | |
818 | if (lrs > s) |
819 | { |
820 | if (lrt > t) |
821 | OpenGLRenderer::getSingleton().renderTexRect( ulx, uly, lrx, lry, s, t, lrs, lrt, flip ); |
822 | else |
823 | OpenGLRenderer::getSingleton().renderTexRect( ulx, lry, lrx, uly, s, lrt, lrs, t, flip ); |
824 | } |
825 | else |
826 | { |
827 | if (lrt > t) |
828 | OpenGLRenderer::getSingleton().renderTexRect( lrx, uly, ulx, lry, lrs, t, s, lrt, flip ); |
829 | else |
830 | OpenGLRenderer::getSingleton().renderTexRect( lrx, lry, ulx, uly, lrs, lrt, s, t, flip ); |
831 | } |
832 | |
833 | //Restore RSP Tile |
834 | int rspTile = m_rsp->getTexture().tile; |
835 | m_rsp->setTile( m_textureLoader->getTile( rspTile ), 0); |
836 | m_rsp->setTile( m_textureLoader->getTile(rspTile < 7 ? rspTile + 1 : rspTile), 1); |
837 | |
838 | //glViewport( 0, m_windowMgr->getHeightOffset(), OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() ); |
839 | |
840 | glEnable(GL_SCISSOR_TEST); |
841 | OpenGLManager::getSingleton().setZBufferEnabled(zEnabled); |
842 | } |
843 | |
844 | //----------------------------------------------------------------------------- |
845 | //* Texture Rectangle Flip |
846 | //! @todo: Clamp Tile |
847 | //----------------------------------------------------------------------------- |
848 | void RDP::_textureRectangleFlip(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fS1, float fT1, int tile) |
849 | { |
850 | //Disable z buffer |
851 | bool zEnabled = OpenGLManager::getSingleton().getZBufferEnabled(); |
852 | OpenGLManager::getSingleton().setZBufferEnabled(false); |
853 | |
854 | float widthDiv = (float)m_textureLoader->getTile( m_rsp->getTexture().tile )->getWidth(); |
855 | float heightDiv = (float)m_textureLoader->getTile( m_rsp->getTexture().tile )->getHeight(); |
856 | |
857 | float t0u0 = fS0 / widthDiv; |
858 | float t0v0 = fT0 / heightDiv; |
859 | float t0u1 = (fS1 - fS0)/ widthDiv + t0u0; |
860 | float t0v1 = (fT1 - fT0)/ heightDiv + t0v0; |
861 | |
862 | float depth = m_otherMode.depthSource == 1 ? m_primitiveZ : 0; //TODO: Use RSP viewport nearz? |
863 | |
864 | static bool warned = false; |
865 | if( t0u0 >= 0 && t0u1 <= 1 && t0u1 >= t0u0 ) |
866 | { |
867 | //TODO: Clamp Tile |
868 | if (!warned) |
869 | { |
870 | warned = true; |
871 | Logger::getSingleton().printMsg("_textureRectangleFlip - unimplemented", M64MSG_WARNING); |
872 | } |
873 | } |
874 | if( t0v0 >= 0 && t0v1 <= 1 && t0v1 >= t0v0 ) |
875 | { |
876 | //TODO: Clamp tile |
877 | if (!warned) |
878 | { |
879 | warned = true; |
880 | Logger::getSingleton().printMsg("_textureRectangleFlip - unimplemented", M64MSG_WARNING); |
881 | } |
882 | } |
883 | |
884 | //HACK |
885 | if ( ROMDetector::getSingleton().getRomID() == SUPER_MARIO_64 ) |
886 | { |
887 | t0u0 *= 0.5f; |
888 | t0v0 *= 0.5f; |
889 | t0u1 *= 0.5f; |
890 | t0v1 *= 0.5f; |
891 | } |
892 | |
893 | //glViewport( 0, m_windowMgr->getHeightOffset(), OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() ); |
894 | |
895 | //Get Color |
896 | float color[4] = { 1,1,1,0 }; |
897 | this->getCombinerMgr()->getCombinerColor( &color[0] ); |
898 | float secondaryColor[4] = { 1,1,1,1 }; |
899 | |
900 | if ( m_otherMode.cycleType == G_CYC_COPY ) |
901 | { |
902 | glActiveTextureARB( GL_TEXTURE0_ARB ); |
903 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); |
904 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); |
905 | } |
906 | |
907 | //Disable Scissor |
908 | glDisable( GL_SCISSOR_TEST ); |
909 | |
910 | //Render Quad |
911 | m_openGL2DRenderer->renderFlippedTexturedQuad( color, secondaryColor, |
912 | (float)nX0, (float)nY0, |
913 | (float)nX1, (float)nY1, |
914 | depth, |
915 | t0u0, t0v0, |
916 | t0u1, t0v1, |
917 | t0u0, t0v0, |
918 | t0u1, t0v1 ); |
919 | |
920 | //Restore states |
921 | glEnable(GL_SCISSOR_TEST); |
922 | OpenGLManager::getSingleton().setZBufferEnabled(zEnabled); |
923 | } |