d07c171f |
1 | /* |
2 | Copyright (C) 2002 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 | #include <cmath> |
21 | #include "Render.h" |
22 | #include "Timing.h" |
23 | |
24 | void RSP_GBI1_SpNoop(Gfx *gfx) |
25 | { |
26 | SP_Timing(RSP_GBI1_SpNoop); |
27 | |
28 | if( (gfx+1)->words.cmd == 0x00 && gRSP.ucode >= 17 ) |
29 | { |
30 | RSP_RDP_NOIMPL("Double SPNOOP, Skip remain ucodes, PC=%08X, Cmd1=%08X", gDlistStack[gDlistStackPointer].pc, gfx->words.w1); |
31 | RDP_GFX_PopDL(); |
32 | //if( gRSP.ucode < 17 ) TriggerDPInterrupt(); |
33 | } |
34 | } |
35 | |
36 | void RSP_GBI0_Mtx(Gfx *gfx) |
37 | { |
38 | SP_Timing(RSP_GBI0_Mtx); |
39 | |
40 | uint32 addr = RSPSegmentAddr((gfx->gbi0matrix.addr)); |
41 | |
42 | LOG_UCODE(" Command: %s %s %s Length %d Address 0x%08x", |
43 | gfx->gbi0matrix.projection == 1 ? "Projection" : "ModelView", |
44 | gfx->gbi0matrix.load == 1 ? "Load" : "Mul", |
45 | gfx->gbi0matrix.push == 1 ? "Push" : "NoPush", |
46 | gfx->gbi0matrix.len, addr); |
47 | |
48 | if (addr + 64 > g_dwRamSize) |
49 | { |
50 | TRACE1("Mtx: Address invalid (0x%08x)", addr); |
51 | return; |
52 | } |
53 | |
54 | LoadMatrix(addr); |
55 | |
56 | if (gfx->gbi0matrix.projection) |
57 | { |
58 | CRender::g_pRender->SetProjection(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load); |
59 | } |
60 | else |
61 | { |
62 | CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load); |
63 | } |
64 | |
65 | #ifdef DEBUGGER |
66 | const char *loadstr = gfx->gbi0matrix.load == 1 ? "Load" : "Mul"; |
67 | const char *pushstr = gfx->gbi0matrix.push == 1 ? "Push" : "Nopush"; |
68 | int projlevel = CRender::g_pRender->GetProjectMatrixLevel(); |
69 | int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel(); |
70 | if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) |
71 | { |
72 | pauseAtNext = false; |
73 | debuggerPause = true; |
74 | if (gfx->gbi0matrix.projection) |
75 | { |
76 | TRACE3("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel ); |
77 | } |
78 | else |
79 | { |
80 | TRACE3("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel); |
81 | } |
82 | } |
83 | else |
84 | { |
85 | if( pauseAtNext && logMatrix ) |
86 | { |
87 | if (gfx->gbi0matrix.projection) |
88 | { |
89 | TRACE3("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel); |
90 | } |
91 | else |
92 | { |
93 | TRACE3("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel); |
94 | } |
95 | } |
96 | } |
97 | #endif |
98 | } |
99 | |
100 | |
101 | void RSP_GBI1_Reserved(Gfx *gfx) |
102 | { |
103 | SP_Timing(RSP_GBI1_Reserved); |
104 | RSP_RDP_NOIMPL("RDP: Reserved (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); |
105 | } |
106 | |
107 | |
108 | void RSP_GBI1_MoveMem(Gfx *gfx) |
109 | { |
110 | SP_Timing(RSP_GBI1_MoveMem); |
111 | |
112 | uint32 type = ((gfx->words.w0)>>16)&0xFF; |
113 | uint32 dwLength = ((gfx->words.w0))&0xFFFF; |
114 | uint32 addr = RSPSegmentAddr((gfx->words.w1)); |
115 | |
116 | switch (type) |
117 | { |
118 | case RSP_GBI1_MV_MEM_VIEWPORT: |
119 | { |
120 | LOG_UCODE(" RSP_GBI1_MV_MEM_VIEWPORT. Address: 0x%08x, Length: 0x%04x", addr, dwLength); |
121 | RSP_MoveMemViewport(addr); |
122 | } |
123 | break; |
124 | case RSP_GBI1_MV_MEM_LOOKATY: |
125 | LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATY"); |
126 | break; |
127 | case RSP_GBI1_MV_MEM_LOOKATX: |
128 | LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATX"); |
129 | break; |
130 | case RSP_GBI1_MV_MEM_L0: |
131 | case RSP_GBI1_MV_MEM_L1: |
132 | case RSP_GBI1_MV_MEM_L2: |
133 | case RSP_GBI1_MV_MEM_L3: |
134 | case RSP_GBI1_MV_MEM_L4: |
135 | case RSP_GBI1_MV_MEM_L5: |
136 | case RSP_GBI1_MV_MEM_L6: |
137 | case RSP_GBI1_MV_MEM_L7: |
138 | { |
139 | uint32 dwLight = (type-RSP_GBI1_MV_MEM_L0)/2; |
140 | LOG_UCODE(" RSP_GBI1_MV_MEM_L%d", dwLight); |
141 | LOG_UCODE(" Light%d: Length:0x%04x, Address: 0x%08x", dwLight, dwLength, addr); |
142 | |
143 | RSP_MoveMemLight(dwLight, addr); |
144 | } |
145 | break; |
146 | case RSP_GBI1_MV_MEM_TXTATT: |
147 | LOG_UCODE(" RSP_GBI1_MV_MEM_TXTATT"); |
148 | break; |
149 | case RSP_GBI1_MV_MEM_MATRIX_1: |
150 | RSP_GFX_Force_Matrix(addr); |
151 | break; |
152 | case RSP_GBI1_MV_MEM_MATRIX_2: |
153 | break; |
154 | case RSP_GBI1_MV_MEM_MATRIX_3: |
155 | break; |
156 | case RSP_GBI1_MV_MEM_MATRIX_4: |
157 | break; |
158 | default: |
159 | RSP_RDP_NOIMPL("MoveMem: Unknown Move Type, cmd=%08X, %08X", gfx->words.w0, gfx->words.w1); |
160 | break; |
161 | } |
162 | } |
163 | |
164 | |
165 | void RSP_GBI0_Vtx(Gfx *gfx) |
166 | { |
167 | SP_Timing(RSP_GBI0_Vtx); |
168 | |
169 | int n = gfx->gbi0vtx.n + 1; |
170 | int v0 = gfx->gbi0vtx.v0; |
171 | uint32 addr = RSPSegmentAddr((gfx->gbi0vtx.addr)); |
172 | |
173 | LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", addr, v0, n, gfx->gbi0vtx.len); |
174 | |
175 | if ((v0 + n) > 80) |
176 | { |
177 | TRACE3("Warning, invalid vertex positions, N=%d, v0=%d, Addr=0x%08X", n, v0, addr); |
178 | n = 32 - v0; |
179 | } |
180 | |
181 | // Check that address is valid... |
182 | if ((addr + n*16) > g_dwRamSize) |
183 | { |
184 | TRACE1("Vertex Data: Address out of range (0x%08x)", addr); |
185 | } |
186 | else |
187 | { |
188 | ProcessVertexData(addr, v0, n); |
189 | status.dwNumVertices += n; |
190 | DisplayVertexInfo(addr, v0, n); |
191 | } |
192 | } |
193 | |
194 | |
195 | void RSP_GBI0_DL(Gfx *gfx) |
196 | { |
197 | SP_Timing(RSP_GBI0_DL); |
198 | |
199 | uint32 addr = RSPSegmentAddr((gfx->gbi0dlist.addr)) & (g_dwRamSize-1); |
200 | |
201 | LOG_UCODE(" Address=0x%08x Push: 0x%02x", addr, gfx->gbi0dlist.param); |
202 | if( addr > g_dwRamSize ) |
203 | { |
204 | RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", addr, gDlistStack[gDlistStackPointer].pc ); |
205 | addr &= (g_dwRamSize-1); |
206 | DebuggerPauseCountN( NEXT_DLIST ); |
207 | } |
208 | |
209 | if( gfx->gbi0dlist.param == RSP_DLIST_PUSH ) |
210 | gDlistStackPointer++; |
211 | |
212 | gDlistStack[gDlistStackPointer].pc = addr; |
213 | gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; |
214 | |
215 | LOG_UCODE("Level=%d", gDlistStackPointer+1); |
216 | LOG_UCODE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); |
217 | } |
218 | |
219 | |
220 | void RSP_GBI1_RDPHalf_Cont(Gfx *gfx) |
221 | { |
222 | SP_Timing(RSP_GBI1_RDPHalf_Cont); |
223 | |
224 | LOG_UCODE("RDPHalf_Cont: (Ignored)"); |
225 | } |
226 | void RSP_GBI1_RDPHalf_2(Gfx *gfx) |
227 | { |
228 | SP_Timing(RSP_GBI1_RDPHalf_2); |
229 | |
230 | LOG_UCODE("RDPHalf_2: (Ignored)"); |
231 | } |
232 | |
233 | void RSP_GBI1_RDPHalf_1(Gfx *gfx) |
234 | { |
235 | SP_Timing(RSP_GBI1_RDPHalf_1); |
236 | |
237 | LOG_UCODE("RDPHalf_1: (Ignored)"); |
238 | } |
239 | |
240 | void RSP_GBI1_Line3D(Gfx *gfx) |
241 | { |
242 | status.primitiveType = PRIM_LINE3D; |
243 | |
244 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc; |
245 | |
246 | BOOL bTrisAdded = FALSE; |
247 | |
248 | if( gfx->ln3dtri2.v3 == 0 ) |
249 | { |
250 | // Flying Dragon |
251 | uint32 dwV0 = gfx->ln3dtri2.v0/gRSP.vertexMult; |
252 | uint32 dwV1 = gfx->ln3dtri2.v1/gRSP.vertexMult; |
253 | uint32 dwWidth = gfx->ln3dtri2.v2; |
254 | //uint32 dwFlag = gfx->ln3dtri2.v3/gRSP.vertexMult; |
255 | |
256 | CRender::g_pRender->SetCombinerAndBlender(); |
257 | |
258 | status.dwNumTrisRendered++; |
259 | |
260 | CRender::g_pRender->Line3D(dwV0, dwV1, dwWidth); |
261 | SP_Timing(RSP_GBI1_Line3D); |
262 | DP_Timing(RSP_GBI1_Line3D); |
263 | } |
264 | else |
265 | { |
266 | do { |
267 | uint32 dwV3 = gfx->ln3dtri2.v3/gRSP.vertexMult; |
268 | uint32 dwV0 = gfx->ln3dtri2.v0/gRSP.vertexMult; |
269 | uint32 dwV1 = gfx->ln3dtri2.v1/gRSP.vertexMult; |
270 | uint32 dwV2 = gfx->ln3dtri2.v2/gRSP.vertexMult; |
271 | |
272 | LOG_UCODE(" Line3D: V0: %d, V1: %d, V2: %d, V3: %d", dwV0, dwV1, dwV2, dwV3); |
273 | |
274 | // Do first tri |
275 | if (IsTriangleVisible(dwV0, dwV1, dwV2)) |
276 | { |
277 | DEBUG_DUMP_VERTEXES("Line3D 1/2", dwV0, dwV1, dwV2); |
278 | if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) |
279 | { |
280 | PrepareTextures(); |
281 | InitVertexTextureConstants(); |
282 | } |
283 | |
284 | if( !bTrisAdded ) |
285 | { |
286 | CRender::g_pRender->SetCombinerAndBlender(); |
287 | } |
288 | |
289 | bTrisAdded = true; |
290 | PrepareTriangle(dwV0, dwV1, dwV2); |
291 | } |
292 | |
293 | // Do second tri |
294 | if (IsTriangleVisible(dwV2, dwV3, dwV0)) |
295 | { |
296 | DEBUG_DUMP_VERTEXES("Line3D 2/2", dwV0, dwV1, dwV2); |
297 | if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) |
298 | { |
299 | PrepareTextures(); |
300 | InitVertexTextureConstants(); |
301 | } |
302 | |
303 | if( !bTrisAdded ) |
304 | { |
305 | CRender::g_pRender->SetCombinerAndBlender(); |
306 | } |
307 | |
308 | bTrisAdded = true; |
309 | PrepareTriangle(dwV2, dwV3, dwV0); |
310 | } |
311 | |
312 | gfx++; |
313 | dwPC += 8; |
314 | #ifdef DEBUGGER |
315 | } while (gfx->words.cmd == (uint8)RSP_LINE3D && !(pauseAtNext && eventToPause==NEXT_FLUSH_TRI)); |
316 | #else |
317 | } while (gfx->words.cmd == (uint8)RSP_LINE3D); |
318 | #endif |
319 | |
320 | gDlistStack[gDlistStackPointer].pc = dwPC-8; |
321 | |
322 | if (bTrisAdded) |
323 | { |
324 | CRender::g_pRender->DrawTriangles(); |
325 | } |
326 | } |
327 | } |
328 | |
329 | |
330 | void RSP_GBI1_ClearGeometryMode(Gfx *gfx) |
331 | { |
332 | SP_Timing(RSP_GBI1_ClearGeometryMode); |
333 | uint32 dwMask = ((gfx->words.w1)); |
334 | |
335 | #ifdef DEBUGGER |
336 | LOG_UCODE(" Mask=0x%08x", dwMask); |
337 | if (dwMask & G_ZBUFFER) LOG_UCODE(" Disabling ZBuffer"); |
338 | if (dwMask & G_TEXTURE_ENABLE) LOG_UCODE(" Disabling Texture"); |
339 | if (dwMask & G_SHADE) LOG_UCODE(" Disabling Shade"); |
340 | if (dwMask & G_SHADING_SMOOTH) LOG_UCODE(" Disabling Smooth Shading"); |
341 | if (dwMask & G_CULL_FRONT) LOG_UCODE(" Disabling Front Culling"); |
342 | if (dwMask & G_CULL_BACK) LOG_UCODE(" Disabling Back Culling"); |
343 | if (dwMask & G_FOG) LOG_UCODE(" Disabling Fog"); |
344 | if (dwMask & G_LIGHTING) LOG_UCODE(" Disabling Lighting"); |
345 | if (dwMask & G_TEXTURE_GEN) LOG_UCODE(" Disabling Texture Gen"); |
346 | if (dwMask & G_TEXTURE_GEN_LINEAR) LOG_UCODE(" Disabling Texture Gen Linear"); |
347 | if (dwMask & G_LOD) LOG_UCODE(" Disabling LOD (no impl)"); |
348 | #endif |
349 | |
350 | gRDP.geometryMode &= ~dwMask; |
351 | RSP_GFX_InitGeometryMode(); |
352 | } |
353 | |
354 | |
355 | |
356 | void RSP_GBI1_SetGeometryMode(Gfx *gfx) |
357 | { |
358 | SP_Timing(RSP_GBI1_SetGeometryMode); |
359 | uint32 dwMask = ((gfx->words.w1)); |
360 | |
361 | #ifdef DEBUGGER |
362 | LOG_UCODE(" Mask=0x%08x", dwMask); |
363 | if (dwMask & G_ZBUFFER) LOG_UCODE(" Enabling ZBuffer"); |
364 | if (dwMask & G_TEXTURE_ENABLE) LOG_UCODE(" Enabling Texture"); |
365 | if (dwMask & G_SHADE) LOG_UCODE(" Enabling Shade"); |
366 | if (dwMask & G_SHADING_SMOOTH) LOG_UCODE(" Enabling Smooth Shading"); |
367 | if (dwMask & G_CULL_FRONT) LOG_UCODE(" Enabling Front Culling"); |
368 | if (dwMask & G_CULL_BACK) LOG_UCODE(" Enabling Back Culling"); |
369 | if (dwMask & G_FOG) LOG_UCODE(" Enabling Fog"); |
370 | if (dwMask & G_LIGHTING) LOG_UCODE(" Enabling Lighting"); |
371 | if (dwMask & G_TEXTURE_GEN) LOG_UCODE(" Enabling Texture Gen"); |
372 | if (dwMask & G_TEXTURE_GEN_LINEAR) LOG_UCODE(" Enabling Texture Gen Linear"); |
373 | if (dwMask & G_LOD) LOG_UCODE(" Enabling LOD (no impl)"); |
374 | #endif // DEBUGGER |
375 | gRDP.geometryMode |= dwMask; |
376 | RSP_GFX_InitGeometryMode(); |
377 | } |
378 | |
379 | |
380 | void RSP_GBI1_EndDL(Gfx *gfx) |
381 | { |
382 | SP_Timing(RSP_GBI1_EndDL); |
383 | RDP_GFX_PopDL(); |
384 | } |
385 | |
386 | |
387 | //static const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" }; |
388 | //static const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" }; |
389 | //static const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "?" }; |
390 | |
391 | void RSP_GBI1_SetOtherModeL(Gfx *gfx) |
392 | { |
393 | SP_Timing(RSP_GBI1_SetOtherModeL); |
394 | |
395 | uint32 dwShift = ((gfx->words.w0)>>8)&0xFF; |
396 | uint32 dwLength= ((gfx->words.w0) )&0xFF; |
397 | uint32 dwData = (gfx->words.w1); |
398 | |
399 | uint32 dwMask = ((1<<dwLength)-1)<<dwShift; |
400 | |
401 | uint32 modeL = gRDP.otherModeL; |
402 | modeL = (modeL&(~dwMask)) | dwData; |
403 | |
404 | Gfx tempgfx; |
405 | tempgfx.words.w0 = gRDP.otherModeH; |
406 | tempgfx.words.w1 = modeL; |
407 | DLParser_RDPSetOtherMode(&tempgfx); |
408 | } |
409 | |
410 | |
411 | void RSP_GBI1_SetOtherModeH(Gfx *gfx) |
412 | { |
413 | SP_Timing(RSP_GBI1_SetOtherModeH); |
414 | |
415 | uint32 dwShift = ((gfx->words.w0)>>8)&0xFF; |
416 | uint32 dwLength= ((gfx->words.w0) )&0xFF; |
417 | uint32 dwData = (gfx->words.w1); |
418 | |
419 | uint32 dwMask = ((1<<dwLength)-1)<<dwShift; |
420 | uint32 dwModeH = gRDP.otherModeH; |
421 | |
422 | dwModeH = (dwModeH&(~dwMask)) | dwData; |
423 | Gfx tempgfx; |
424 | tempgfx.words.w0 = dwModeH; |
425 | tempgfx.words.w1 = gRDP.otherModeL; |
426 | DLParser_RDPSetOtherMode(&tempgfx ); |
427 | } |
428 | |
429 | |
430 | void RSP_GBI1_Texture(Gfx *gfx) |
431 | { |
432 | SP_Timing(RSP_GBI1_Texture); |
433 | |
434 | float fTextureScaleS = (float)(gfx->texture.scaleS) / (65536.0f * 32.0f); |
435 | float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f); |
436 | |
437 | if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF ) |
438 | { |
439 | fTextureScaleS = 1/32.0f; |
440 | } |
441 | else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 ) |
442 | { |
443 | fTextureScaleS = 1/64.0f; |
444 | } |
445 | #ifdef DEBUGGER |
446 | else if( ((gfx->words.w1>>16)&0xFFFF) != 0 ) |
447 | { |
448 | //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1>>16)&0xFFFF); |
449 | } |
450 | #endif |
451 | |
452 | if( (((gfx->words.w1) )&0xFFFF) == 0xFFFF ) |
453 | { |
454 | fTextureScaleT = 1/32.0f; |
455 | } |
456 | else if( (((gfx->words.w1) )&0xFFFF) == 0x8000 ) |
457 | { |
458 | fTextureScaleT = 1/64.0f; |
459 | } |
460 | #ifdef DEBUGGER |
461 | else if( (gfx->words.w1&0xFFFF) != 0 ) |
462 | { |
463 | //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1)&0xFFFF); |
464 | } |
465 | #endif |
466 | |
467 | if( gRSP.ucode == 6 ) |
468 | { |
469 | if( fTextureScaleS == 0 ) fTextureScaleS = 1.0f/32.0f; |
470 | if( fTextureScaleT == 0 ) fTextureScaleT = 1.0f/32.0f; |
471 | } |
472 | |
473 | CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi0, fTextureScaleS, fTextureScaleT); |
474 | |
475 | // What happens if these are 0? Interpret as 1.0f? |
476 | |
477 | LOG_TEXTURE( |
478 | { |
479 | DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled"); |
480 | DebuggerAppendMsg(" ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f); |
481 | }); |
482 | |
483 | DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE); |
484 | LOG_UCODE(" Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled"); |
485 | LOG_UCODE(" ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f); |
486 | } |
487 | |
488 | extern void RSP_RDP_InsertMatrix(uint32 word0, uint32 word1); |
489 | void RSP_GBI1_MoveWord(Gfx *gfx) |
490 | { |
491 | SP_Timing(RSP_GBI1_MoveWord); |
492 | |
493 | switch (gfx->gbi0moveword.type) |
494 | { |
495 | case RSP_MOVE_WORD_MATRIX: |
496 | RSP_RDP_InsertMatrix(gfx); |
497 | break; |
498 | case RSP_MOVE_WORD_NUMLIGHT: |
499 | { |
500 | uint32 dwNumLights = (((gfx->gbi0moveword.value)-0x80000000)/32)-1; |
501 | LOG_UCODE(" RSP_MOVE_WORD_NUMLIGHT: Val:%d", dwNumLights); |
502 | |
503 | gRSP.ambientLightIndex = dwNumLights; |
504 | SetNumLights(dwNumLights); |
505 | } |
506 | break; |
507 | case RSP_MOVE_WORD_CLIP: |
508 | { |
509 | switch (gfx->gbi0moveword.offset) |
510 | { |
511 | case RSP_MV_WORD_OFFSET_CLIP_RNX: |
512 | case RSP_MV_WORD_OFFSET_CLIP_RNY: |
513 | case RSP_MV_WORD_OFFSET_CLIP_RPX: |
514 | case RSP_MV_WORD_OFFSET_CLIP_RPY: |
515 | CRender::g_pRender->SetClipRatio(gfx->gbi0moveword.offset, gfx->gbi0moveword.value); |
516 | break; |
517 | default: |
518 | LOG_UCODE(" RSP_MOVE_WORD_CLIP ? : 0x%08x", gfx->words.w1); |
519 | break; |
520 | } |
521 | } |
522 | break; |
523 | case RSP_MOVE_WORD_SEGMENT: |
524 | { |
525 | uint32 dwSegment = (gfx->gbi0moveword.offset >> 2) & 0xF; |
526 | uint32 dwBase = (gfx->gbi0moveword.value)&0x00FFFFFF; |
527 | LOG_UCODE(" RSP_MOVE_WORD_SEGMENT Seg[%d] = 0x%08x", dwSegment, dwBase); |
528 | if( dwBase > g_dwRamSize ) |
529 | { |
530 | gRSP.segments[dwSegment] = dwBase; |
531 | #ifdef DEBUGGER |
532 | if( pauseAtNext ) |
533 | DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSegment, dwBase); |
534 | #endif |
535 | } |
536 | else |
537 | { |
538 | gRSP.segments[dwSegment] = dwBase; |
539 | } |
540 | } |
541 | break; |
542 | case RSP_MOVE_WORD_FOG: |
543 | { |
544 | uint16 wMult = (uint16)(((gfx->gbi0moveword.value) >> 16) & 0xFFFF); |
545 | uint16 wOff = (uint16)(((gfx->gbi0moveword.value) ) & 0xFFFF); |
546 | |
547 | float fMult = (float)(short)wMult; |
548 | float fOff = (float)(short)wOff; |
549 | |
550 | float rng = 128000.0f / fMult; |
551 | float fMin = 500.0f - (fOff*rng/256.0f); |
552 | float fMax = rng + fMin; |
553 | |
554 | FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff)); |
555 | //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 ) |
556 | if( fMult <= 0 || fMax < 0 ) |
557 | { |
558 | // Hack |
559 | fMin = 996; |
560 | fMax = 1000; |
561 | fMult = 0; |
562 | fOff = 1; |
563 | } |
564 | |
565 | LOG_UCODE(" RSP_MOVE_WORD_FOG/Mul=%d: Off=%d", wMult, wOff); |
566 | FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=%08X", fMin, fMax, gfx->gbi0moveword.value)); |
567 | SetFogMinMax(fMin, fMax, fMult, fOff); |
568 | } |
569 | break; |
570 | case RSP_MOVE_WORD_LIGHTCOL: |
571 | { |
572 | uint32 dwLight = gfx->gbi0moveword.offset / 0x20; |
573 | uint32 dwField = (gfx->gbi0moveword.offset & 0x7); |
574 | |
575 | LOG_UCODE(" RSP_MOVE_WORD_LIGHTCOL/0x%08x: 0x%08x", gfx->gbi0moveword.offset, gfx->words.w1); |
576 | |
577 | switch (dwField) |
578 | { |
579 | case 0: |
580 | if (dwLight == gRSP.ambientLightIndex) |
581 | { |
582 | SetAmbientLight( ((gfx->gbi0moveword.value)>>8) ); |
583 | } |
584 | else |
585 | { |
586 | SetLightCol(dwLight, gfx->gbi0moveword.value); |
587 | } |
588 | break; |
589 | |
590 | case 4: |
591 | break; |
592 | |
593 | default: |
594 | TRACE1("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField); |
595 | break; |
596 | } |
597 | } |
598 | break; |
599 | case RSP_MOVE_WORD_POINTS: |
600 | { |
601 | uint32 vtx = gfx->gbi0moveword.offset/40; |
602 | uint32 where = gfx->gbi0moveword.offset - vtx*40; |
603 | ModifyVertexInfo(where, vtx, gfx->gbi0moveword.value); |
604 | } |
605 | break; |
606 | case RSP_MOVE_WORD_PERSPNORM: |
607 | LOG_UCODE(" RSP_MOVE_WORD_PERSPNORM"); |
608 | //if( word1 != 0x1A ) DebuggerAppendMsg("PerspNorm: 0x%04x", (short)word1); |
609 | break; |
610 | default: |
611 | RSP_RDP_NOIMPL("Unknown MoveWord, %08X, %08X", gfx->words.w0, gfx->words.w1); |
612 | break; |
613 | } |
614 | |
615 | } |
616 | |
617 | |
618 | void RSP_GBI1_PopMtx(Gfx *gfx) |
619 | { |
620 | SP_Timing(RSP_GBI1_PopMtx); |
621 | |
622 | LOG_UCODE(" Command: (%s)", gfx->gbi0popmatrix.projection ? "Projection" : "ModelView"); |
623 | |
624 | // Do any of the other bits do anything? |
625 | // So far only Extreme-G seems to Push/Pop projection matrices |
626 | |
627 | if (gfx->gbi0popmatrix.projection) |
628 | { |
629 | CRender::g_pRender->PopProjection(); |
630 | } |
631 | else |
632 | { |
633 | CRender::g_pRender->PopWorldView(); |
634 | } |
635 | #ifdef DEBUGGER |
636 | if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) |
637 | { |
638 | pauseAtNext = false; |
639 | debuggerPause = true; |
640 | DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World"); |
641 | } |
642 | else |
643 | { |
644 | if( pauseAtNext && logMatrix ) |
645 | { |
646 | DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World"); |
647 | } |
648 | } |
649 | #endif |
650 | } |
651 | |
652 | |
653 | void RSP_GBI1_CullDL(Gfx *gfx) |
654 | { |
655 | SP_Timing(RSP_GBI1_CullDL); |
656 | |
657 | #ifdef DEBUGGER |
658 | if( !debuggerEnableCullFace ) |
659 | { |
660 | return; //Disable Culling |
661 | } |
662 | #endif |
663 | if( g_curRomInfo.bDisableCulling ) |
664 | { |
665 | return; //Disable Culling |
666 | } |
667 | |
668 | uint32 dwVFirst = ((gfx->words.w0) & 0xFFF) / gRSP.vertexMult; |
669 | uint32 dwVLast = (((gfx->words.w1)) & 0xFFF) / gRSP.vertexMult; |
670 | |
671 | LOG_UCODE(" Culling using verts %d to %d", dwVFirst, dwVLast); |
672 | |
673 | // Mask into range |
674 | dwVFirst &= 0x1f; |
675 | dwVLast &= 0x1f; |
676 | |
677 | if( dwVLast < dwVFirst ) return; |
678 | if( !gRSP.bRejectVtx ) return; |
679 | |
680 | for (uint32 i = dwVFirst; i <= dwVLast; i++) |
681 | { |
682 | if (g_clipFlag[i] == 0) |
683 | { |
684 | LOG_UCODE(" Vertex %d is visible, continuing with display list processing", i); |
685 | return; |
686 | } |
687 | } |
688 | |
689 | status.dwNumDListsCulled++; |
690 | |
691 | LOG_UCODE(" No vertices were visible, culling rest of display list"); |
692 | |
693 | RDP_GFX_PopDL(); |
694 | } |
695 | |
696 | |
697 | |
698 | void RSP_GBI1_Tri1(Gfx *gfx) |
699 | { |
700 | status.primitiveType = PRIM_TRI1; |
701 | bool bTrisAdded = false; |
702 | bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); |
703 | |
704 | // While the next command pair is Tri1, add vertices |
705 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc; |
706 | //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC); |
707 | |
708 | do |
709 | { |
710 | uint32 dwV0 = gfx->tri1.v0/gRSP.vertexMult; |
711 | uint32 dwV1 = gfx->tri1.v1/gRSP.vertexMult; |
712 | uint32 dwV2 = gfx->tri1.v2/gRSP.vertexMult; |
713 | |
714 | if (IsTriangleVisible(dwV0, dwV1, dwV2)) |
715 | { |
716 | DEBUG_DUMP_VERTEXES("Tri1", dwV0, dwV1, dwV2); |
717 | LOG_UCODE(" Tri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2); |
718 | |
719 | if (!bTrisAdded) |
720 | { |
721 | if( bTexturesAreEnabled ) |
722 | { |
723 | PrepareTextures(); |
724 | InitVertexTextureConstants(); |
725 | } |
726 | CRender::g_pRender->SetCombinerAndBlender(); |
727 | bTrisAdded = true; |
728 | } |
729 | PrepareTriangle(dwV0, dwV1, dwV2); |
730 | } |
731 | |
732 | gfx++; |
733 | dwPC += 8; |
734 | |
735 | #ifdef DEBUGGER |
736 | } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_TRI1); |
737 | #else |
738 | } while (gfx->words.cmd == (uint8)RSP_TRI1); |
739 | #endif |
740 | |
741 | gDlistStack[gDlistStackPointer].pc = dwPC-8; |
742 | |
743 | if (bTrisAdded) |
744 | { |
745 | CRender::g_pRender->DrawTriangles(); |
746 | } |
747 | |
748 | DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI1")); |
749 | } |
750 | |
751 | |
752 | void RSP_GBI0_Tri4(Gfx *gfx) |
753 | { |
754 | uint32 w0 = gfx->words.w0; |
755 | uint32 w1 = gfx->words.w1; |
756 | |
757 | status.primitiveType = PRIM_TRI2; |
758 | |
759 | // While the next command pair is Tri2, add vertices |
760 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc; |
761 | |
762 | BOOL bTrisAdded = FALSE; |
763 | |
764 | do { |
765 | uint32 dwFlag = (w0>>16)&0xFF; |
766 | LOG_UCODE(" PD Tri4: 0x%08x 0x%08x Flag: 0x%02x", gfx->words.w0, gfx->words.w1, dwFlag); |
767 | |
768 | BOOL bVisible; |
769 | for( int i=0; i<4; i++) |
770 | { |
771 | uint32 v0 = (w1>>(4+(i<<3))) & 0xF; |
772 | uint32 v1 = (w1>>( (i<<3))) & 0xF; |
773 | uint32 v2 = (w0>>( (i<<2))) & 0xF; |
774 | bVisible = IsTriangleVisible(v0, v2, v1); |
775 | LOG_UCODE(" (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)"); |
776 | if (bVisible) |
777 | { |
778 | DEBUG_DUMP_VERTEXES("Tri4_PerfectDark 1/2", v0, v1, v2); |
779 | if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) |
780 | { |
781 | PrepareTextures(); |
782 | InitVertexTextureConstants(); |
783 | } |
784 | |
785 | if( !bTrisAdded ) |
786 | { |
787 | CRender::g_pRender->SetCombinerAndBlender(); |
788 | } |
789 | |
790 | bTrisAdded = true; |
791 | PrepareTriangle(v0, v2, v1); |
792 | } |
793 | } |
794 | |
795 | w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0); |
796 | w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); |
797 | dwPC += 8; |
798 | |
799 | #ifdef DEBUGGER |
800 | } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>24) == (uint8)RSP_TRI2); |
801 | #else |
802 | } while (((w0)>>24) == (uint8)RSP_TRI2); |
803 | #endif |
804 | |
805 | |
806 | gDlistStack[gDlistStackPointer].pc = dwPC-8; |
807 | |
808 | if (bTrisAdded) |
809 | { |
810 | CRender::g_pRender->DrawTriangles(); |
811 | } |
812 | |
813 | DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI4")); |
814 | |
815 | gRSP.DKRVtxCount=0; |
816 | } |
817 | |
818 | //Nintro64 uses Sprite2d |
819 | |
820 | |
821 | void RSP_RDP_Nothing(Gfx *gfx) |
822 | { |
823 | SP_Timing(RSP_RDP_Nothing); |
824 | |
825 | #ifdef DEBUGGER |
826 | if( logWarning ) |
827 | { |
828 | TRACE0("Stack Trace"); |
829 | for( int i=0; i<gDlistStackPointer; i++ ) |
830 | { |
831 | DebuggerAppendMsg(" %08X", gDlistStack[i].pc); |
832 | } |
833 | |
834 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; |
835 | DebuggerAppendMsg("PC=%08X",dwPC); |
836 | DebuggerAppendMsg("Warning, unknown ucode PC=%08X: 0x%08x 0x%08x\n", dwPC, gfx->words.w0, gfx->words.w1); |
837 | } |
838 | DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_UNKNOWN_OP, {TRACE0("Paused at unknown ucode\n");}) |
839 | if( debuggerContinueWithUnknown ) |
840 | { |
841 | return; |
842 | } |
843 | #endif |
844 | |
845 | if( options.bEnableHacks ) |
846 | return; |
847 | |
848 | gDlistStackPointer=-1; |
849 | } |
850 | |
851 | |
852 | void RSP_RDP_InsertMatrix(Gfx *gfx) |
853 | { |
854 | float fraction; |
855 | |
856 | UpdateCombinedMatrix(); |
857 | |
858 | if ((gfx->words.w0) & 0x20) |
859 | { |
860 | int x = ((gfx->words.w0) & 0x1F) >> 1; |
861 | int y = x >> 2; |
862 | x &= 3; |
863 | |
864 | fraction = ((gfx->words.w1)>>16)/65536.0f; |
865 | gRSPworldProject.m[y][x] = (float)(int)gRSPworldProject.m[y][x]; |
866 | gRSPworldProject.m[y][x] += fraction; |
867 | |
868 | fraction = ((gfx->words.w1)&0xFFFF)/65536.0f; |
869 | gRSPworldProject.m[y][x+1] = (float)(int)gRSPworldProject.m[y][x+1]; |
870 | gRSPworldProject.m[y][x+1] += fraction; |
871 | } |
872 | else |
873 | { |
874 | int x = ((gfx->words.w0) & 0x1F) >> 1; |
875 | int y = x >> 2; |
876 | x &= 3; |
877 | |
878 | fraction = (float)fabs(gRSPworldProject.m[y][x] - (int)gRSPworldProject.m[y][x]); |
879 | gRSPworldProject.m[y][x] = (short)((gfx->words.w1)>>16) + fraction; |
880 | |
881 | fraction = (float)fabs(gRSPworldProject.m[y][x+1] - (int)gRSPworldProject.m[y][x+1]); |
882 | gRSPworldProject.m[y][x+1] = (short)((gfx->words.w1)&0xFFFF) + fraction; |
883 | } |
884 | |
885 | gRSP.bMatrixIsUpdated = false; |
886 | gRSP.bCombinedMatrixIsUpdated = true; |
887 | |
888 | #ifdef DEBUGGER |
889 | if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) |
890 | { |
891 | pauseAtNext = false; |
892 | debuggerPause = true; |
893 | DebuggerAppendMsg("Pause after insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1); |
894 | } |
895 | else |
896 | { |
897 | if( pauseAtNext && logMatrix ) |
898 | { |
899 | DebuggerAppendMsg("insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1); |
900 | } |
901 | } |
902 | #endif |
903 | } |
904 | |