292f9317 |
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 "Render.h" |
21 | #include "Timing.h" |
22 | |
23 | void RSP_GBI1_Vtx(Gfx *gfx) |
24 | { |
25 | uint32 addr = RSPSegmentAddr((gfx->gbi1vtx.addr)); |
26 | uint32 v0 = gfx->gbi1vtx.v0; |
27 | uint32 n = gfx->gbi1vtx.n; |
28 | |
29 | LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", addr, v0, n, gfx->gbi1vtx.len); |
30 | |
31 | if (addr > g_dwRamSize) |
32 | { |
33 | TRACE0(" Address out of range - ignoring load"); |
34 | return; |
35 | } |
36 | |
37 | if ((v0 + n) > 80) |
38 | { |
39 | TRACE5("Warning, invalid vertex positions, N=%d, v0=%d, Addr=0x%08X, Cmd=%08X-%08X", |
40 | n, v0, addr, gfx->words.w0, gfx->words.w1); |
41 | return; |
42 | } |
43 | |
44 | ProcessVertexData(addr, v0, n); |
45 | status.dwNumVertices += n; |
46 | DisplayVertexInfo(addr, v0, n); |
47 | } |
48 | |
49 | void RSP_GBI1_ModifyVtx(Gfx *gfx) |
50 | { |
51 | SP_Timing(RSP_GBI1_ModifyVtx); |
52 | |
53 | if( gRSP.ucode == 5 && ((gfx->words.w0)&0x00FFFFFF) == 0 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) |
54 | { |
55 | DLParser_Bomberman2TextRect(gfx); |
56 | } |
57 | else |
58 | { |
59 | uint32 dwWhere = ((gfx->words.w0) >> 16) & 0xFF; |
60 | uint32 dwVert = (((gfx->words.w0) ) & 0xFFFF) / 2; |
61 | uint32 dwValue = (gfx->words.w1); |
62 | |
63 | if( dwVert > 80 ) |
64 | { |
65 | RSP_RDP_NOIMPL("RSP_GBI1_ModifyVtx: Invalid vertex number: %d", dwVert, 0); |
66 | return; |
67 | } |
68 | |
69 | // Data for other commands? |
70 | switch (dwWhere) |
71 | { |
72 | case RSP_MV_WORD_OFFSET_POINT_RGBA: // Modify RGBA |
73 | case RSP_MV_WORD_OFFSET_POINT_XYSCREEN: // Modify X,Y |
74 | case RSP_MV_WORD_OFFSET_POINT_ZSCREEN: // Modify C |
75 | case RSP_MV_WORD_OFFSET_POINT_ST: // Texture |
76 | ModifyVertexInfo(dwWhere, dwVert, dwValue); |
77 | break; |
78 | default: |
79 | RSP_RDP_NOIMPL("RSP_GBI1_ModifyVtx: Setting unk value: 0x%02x, 0x%08x", dwWhere, dwValue); |
80 | break; |
81 | } |
82 | } |
83 | } |
84 | |
85 | void RSP_GBI1_Tri2(Gfx *gfx) |
86 | { |
87 | status.primitiveType = PRIM_TRI2; |
88 | bool bTrisAdded = false; |
89 | bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); |
90 | |
91 | // While the next command pair is Tri2, add vertices |
92 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc; |
93 | |
94 | do { |
95 | // Vertex indices are multiplied by 10 for Mario64, by 2 for MarioKart |
96 | uint32 dwV0 = gfx->gbi1tri2.v0/gRSP.vertexMult; |
97 | uint32 dwV1 = gfx->gbi1tri2.v1/gRSP.vertexMult; |
98 | uint32 dwV2 = gfx->gbi1tri2.v2/gRSP.vertexMult; |
99 | |
100 | uint32 dwV3 = gfx->gbi1tri2.v3/gRSP.vertexMult; |
101 | uint32 dwV4 = gfx->gbi1tri2.v4/gRSP.vertexMult; |
102 | uint32 dwV5 = gfx->gbi1tri2.v5/gRSP.vertexMult; |
103 | |
104 | // Do first tri |
105 | if (IsTriangleVisible(dwV0, dwV1, dwV2)) |
106 | { |
107 | DEBUG_DUMP_VERTEXES("Tri2 1/2", dwV0, dwV1, dwV2); |
108 | if (!bTrisAdded) |
109 | { |
110 | if( bTexturesAreEnabled ) |
111 | { |
112 | PrepareTextures(); |
113 | InitVertexTextureConstants(); |
114 | } |
115 | |
116 | CRender::g_pRender->SetCombinerAndBlender(); |
117 | bTrisAdded = true; |
118 | } |
119 | PrepareTriangle(dwV0, dwV1, dwV2); |
120 | } |
121 | |
122 | // Do second tri |
123 | if (IsTriangleVisible(dwV3, dwV4, dwV5)) |
124 | { |
125 | DEBUG_DUMP_VERTEXES("Tri2 2/2", dwV3, dwV4, dwV5); |
126 | if (!bTrisAdded) |
127 | { |
128 | if( bTexturesAreEnabled ) |
129 | { |
130 | PrepareTextures(); |
131 | InitVertexTextureConstants(); |
132 | } |
133 | |
134 | CRender::g_pRender->SetCombinerAndBlender(); |
135 | bTrisAdded = true; |
136 | } |
137 | PrepareTriangle(dwV3, dwV4, dwV5); |
138 | } |
139 | |
140 | gfx++; |
141 | dwPC += 8; |
142 | #ifdef DEBUGGER |
143 | } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_TRI2); |
144 | #else |
145 | } while( gfx->words.cmd == (uint8)RSP_TRI2); |
146 | #endif |
147 | |
148 | |
149 | gDlistStack[gDlistStackPointer].pc = dwPC-8; |
150 | |
151 | |
152 | if (bTrisAdded) |
153 | { |
154 | CRender::g_pRender->DrawTriangles(); |
155 | } |
156 | |
157 | DEBUG_TRIANGLE(TRACE0("Pause at GBI1 TRI1")); |
158 | } |
159 | |
160 | extern XVECTOR4 g_vtxNonTransformed[MAX_VERTS]; |
161 | |
162 | void RSP_GBI1_BranchZ(Gfx *gfx) |
163 | { |
164 | SP_Timing(RSP_GBI1_BranchZ); |
165 | |
166 | uint32 vtx = ((gfx->words.w0)&0xFFF)>>1; |
167 | float vtxdepth = g_vecProjected[vtx].z/g_vecProjected[vtx].w; |
168 | |
169 | #ifdef DEBUGGER |
170 | if( debuggerEnableZBuffer==FALSE || vtxdepth <= (s32)gfx->words.w1 || g_curRomInfo.bForceDepthBuffer ) |
171 | #else |
172 | if( vtxdepth <= (s32)(gfx->words.w1) || g_curRomInfo.bForceDepthBuffer ) |
173 | #endif |
174 | { |
175 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction |
176 | uint32 dwDL = *(uint32 *)(g_pRDRAMu8 + dwPC-12); |
177 | uint32 dwAddr = RSPSegmentAddr(dwDL); |
178 | |
292f9317 |
179 | LOG_UCODE("BranchZ to DisplayList 0x%08x", dwAddr); |
180 | gDlistStack[gDlistStackPointer].pc = dwAddr; |
181 | gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; |
182 | } |
183 | } |
184 | |
185 | #ifdef DEBUGGER |
186 | void DumpUcodeInfo(UcodeInfo &info) |
187 | { |
188 | DebuggerAppendMsg("Loading Unknown Ucode:\n%08X-%08X-%08X-%08X, Size=0x%X, CRC=0x%08X\nCode:\n", |
189 | info.ucDWORD1, info.ucDWORD2, info.ucDWORD3, info.ucDWORD4, |
190 | info.ucSize, info.ucCRC); |
191 | DumpHex(info.ucStart,20); |
192 | TRACE0("Data:\n"); |
193 | DumpHex(info.ucDStart,20); |
194 | } |
195 | #endif |
196 | |
197 | void RSP_GBI1_LoadUCode(Gfx *gfx) |
198 | { |
199 | SP_Timing(RSP_GBI1_LoadUCode); |
200 | |
201 | //TRACE0("Load ucode"); |
202 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc; |
203 | uint32 dwUcStart = RSPSegmentAddr((gfx->words.w1)); |
204 | uint32 dwSize = ((gfx->words.w0)&0xFFFF)+1; |
205 | uint32 dwUcDStart = RSPSegmentAddr(*(uint32 *)(g_pRDRAMu8 + dwPC-12)); |
206 | |
207 | uint32 ucode = DLParser_CheckUcode(dwUcStart, dwUcDStart, dwSize, 8); |
208 | RSP_SetUcode(ucode, dwUcStart, dwUcDStart, dwSize); |
209 | |
210 | DEBUGGER_PAUSE_AND_DUMP(NEXT_SWITCH_UCODE,{DebuggerAppendMsg("Pause at loading ucode");}); |
211 | } |
212 | |
213 | void RSP_GFX_Force_Matrix(uint32 dwAddr) |
214 | { |
215 | if (dwAddr + 64 > g_dwRamSize) |
216 | { |
217 | DebuggerAppendMsg("ForceMtx: Address invalid (0x%08x)", dwAddr); |
218 | return; |
219 | } |
220 | |
221 | // Load matrix from dwAddr |
222 | LoadMatrix(dwAddr); |
223 | |
224 | CRender::g_pRender->SetWorldProjectMatrix(matToLoad); |
225 | |
226 | DEBUGGER_PAUSE_AND_DUMP(NEXT_MATRIX_CMD,{TRACE0("Paused at ModMatrix Cmd");}); |
227 | } |
228 | |
229 | |
230 | void DisplayVertexInfo(uint32 dwAddr, uint32 dwV0, uint32 dwN) |
231 | { |
232 | #ifdef DEBUGGER |
233 | s8 *pcSrc = (s8 *)(g_pRDRAMu8 + dwAddr); |
234 | short *psSrc = (short *)(g_pRDRAMu8 + dwAddr); |
235 | |
236 | for (uint32 dwV = dwV0; dwV < dwV0 + dwN; dwV++) |
237 | { |
238 | float x = (float)psSrc[0^0x1]; |
239 | float y = (float)psSrc[1^0x1]; |
240 | float z = (float)psSrc[2^0x1]; |
241 | |
242 | //uint32 wFlags = g_dwVtxFlags[dwV]; //(uint16)psSrc[3^0x1]; |
243 | uint32 wFlags = 0; |
244 | |
245 | uint8 a = pcSrc[12^0x3]; |
246 | uint8 b = pcSrc[13^0x3]; |
247 | uint8 c = pcSrc[14^0x3]; |
248 | uint8 d = pcSrc[15^0x3]; |
249 | |
250 | //int nTU = (int)(short)(psSrc[4^0x1]<<4); |
251 | //int nTV = (int)(short)(psSrc[5^0x1]<<4); |
252 | |
253 | //float tu = (float)(nTU>>4); |
254 | //float tv = (float)(nTV>>4); |
255 | float tu = (float)(short)(psSrc[4^0x1]); |
256 | float tv = (float)(short)(psSrc[5^0x1]); |
257 | |
258 | XVECTOR4 & t = g_vecProjected[dwV]; |
259 | |
260 | psSrc += 8; // Increase by 16 bytes |
261 | pcSrc += 16; |
262 | |
263 | LOG_UCODE(" #%02d Flags: 0x%04x Pos: {% 6f,% 6f,% 6f} Tex: {%+7.2f,%+7.2f}, Extra: %02x %02x %02x %02x (transf: {% 6f,% 6f,% 6f})", |
264 | dwV, wFlags, x, y, z, tu, tv, a, b, c, d, t.x, t.y, t.z ); |
265 | } |
266 | #endif |
267 | } |
268 | |
269 | void RSP_MoveMemLight(uint32 dwLight, uint32 dwAddr) |
270 | { |
271 | if( dwLight >= 16 ) |
272 | { |
273 | DebuggerAppendMsg("Warning: invalid light # = %d", dwLight); |
274 | return; |
275 | } |
276 | |
277 | s8 * pcBase = g_pRDRAMs8 + dwAddr; |
278 | uint32 * pdwBase = (uint32 *)pcBase; |
279 | |
280 | |
281 | float range = 0, x, y, z; |
282 | if( options.enableHackForGames == HACK_FOR_ZELDA_MM && (pdwBase[0]&0xFF) == 0x08 && (pdwBase[1]&0xFF) == 0xFF ) |
283 | { |
284 | gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; |
285 | gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; |
286 | short* pdwBase16 = (short*)pcBase; |
287 | x = pdwBase16[5]; |
288 | y = pdwBase16[4]; |
289 | z = pdwBase16[7]; |
290 | range = pdwBase16[6]; |
291 | } |
292 | else |
293 | { |
294 | gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; |
295 | gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; |
296 | x = pcBase[8 ^ 0x3]; |
297 | y = pcBase[9 ^ 0x3]; |
298 | z = pcBase[10 ^ 0x3]; |
299 | } |
300 | |
301 | |
302 | LOG_UCODE(" RGBA: 0x%08x, RGBACopy: 0x%08x, x: %d, y: %d, z: %d", |
303 | gRSPn64lights[dwLight].dwRGBA, |
304 | gRSPn64lights[dwLight].dwRGBACopy, |
305 | x, y, z); |
306 | |
307 | LIGHT_DUMP(TRACE3("Move Light: %08X, %08X, %08X", pdwBase[0], pdwBase[1], pdwBase[2])); |
308 | |
309 | |
310 | if (dwLight == gRSP.ambientLightIndex) |
311 | { |
312 | LOG_UCODE(" (Ambient Light)"); |
313 | |
314 | uint32 dwCol = COLOR_RGBA( (gRSPn64lights[dwLight].dwRGBA >> 24)&0xFF, |
315 | (gRSPn64lights[dwLight].dwRGBA >> 16)&0xFF, |
316 | (gRSPn64lights[dwLight].dwRGBA >> 8)&0xFF, 0xff); |
317 | |
318 | SetAmbientLight( dwCol ); |
319 | } |
320 | else |
321 | { |
322 | LOG_UCODE(" (Normal Light)"); |
323 | |
324 | SetLightCol(dwLight, gRSPn64lights[dwLight].dwRGBA); |
325 | if (pdwBase[2] == 0) // Direction is 0! |
326 | { |
327 | LOG_UCODE(" Light is invalid"); |
328 | } |
329 | SetLightDirection(dwLight, x, y, z, range); |
330 | } |
331 | } |
332 | |
333 | void RSP_MoveMemViewport(uint32 dwAddr) |
334 | { |
335 | if( dwAddr+16 >= g_dwRamSize ) |
336 | { |
337 | TRACE0("MoveMem Viewport, invalid memory"); |
338 | return; |
339 | } |
340 | |
341 | short scale[4]; |
342 | short trans[4]; |
343 | |
344 | // dwAddr is offset into RD_RAM of 8 x 16bits of data... |
345 | scale[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(0*2))^0x2)); |
346 | scale[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(1*2))^0x2)); |
347 | scale[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(2*2))^0x2)); |
348 | scale[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(3*2))^0x2)); |
349 | |
350 | trans[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(4*2))^0x2)); |
351 | trans[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(5*2))^0x2)); |
352 | trans[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(6*2))^0x2)); |
353 | trans[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(7*2))^0x2)); |
354 | |
355 | |
356 | int nCenterX = trans[0]/4; |
357 | int nCenterY = trans[1]/4; |
358 | int nWidth = scale[0]/4; |
359 | int nHeight = scale[1]/4; |
360 | |
361 | // Check for some strange games |
362 | if( nWidth < 0 ) nWidth = -nWidth; |
363 | if( nHeight < 0 ) nHeight = -nHeight; |
364 | |
365 | int nLeft = nCenterX - nWidth; |
366 | int nTop = nCenterY - nHeight; |
367 | int nRight= nCenterX + nWidth; |
368 | int nBottom= nCenterY + nHeight; |
369 | |
370 | //int maxZ = scale[2]; |
371 | int maxZ = 0x3FF; |
372 | |
373 | CRender::g_pRender->SetViewport(nLeft, nTop, nRight, nBottom, maxZ); |
374 | |
375 | LOG_UCODE(" Scale: %d %d %d %d = %d,%d", scale[0], scale[1], scale[2], scale[3], nWidth, nHeight); |
376 | LOG_UCODE(" Trans: %d %d %d %d = %d,%d", trans[0], trans[1], trans[2], trans[3], nCenterX, nCenterY); |
377 | } |
378 | |
379 | |
380 | // S2DEX uses this - 0xc1 |
381 | void RSP_S2DEX_SPObjLoadTxtr_Ucode1(Gfx *gfx) |
382 | { |
383 | SP_Timing(RSP_S2DEX_SPObjLoadTxtr_Ucode1); |
384 | |
385 | // Add S2DEX ucode supporting to F3DEX, see game DT and others |
386 | status.bUseModifiedUcodeMap = true; |
387 | RSP_SetUcode(1); |
388 | memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); |
389 | |
390 | LoadedUcodeMap[S2DEX_OBJ_MOVEMEM] = &RSP_S2DEX_OBJ_MOVEMEM; |
391 | LoadedUcodeMap[S2DEX_OBJ_LOADTXTR] = &RSP_S2DEX_SPObjLoadTxtr; |
392 | LoadedUcodeMap[S2DEX_OBJ_LDTX_SPRITE] = &RSP_S2DEX_SPObjLoadTxSprite; |
393 | LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT] = &RSP_S2DEX_SPObjLoadTxRect; |
394 | LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT_R] = &RSP_S2DEX_SPObjLoadTxRectR; |
395 | |
396 | RSP_S2DEX_SPObjLoadTxtr(gfx); |
397 | } |
398 | |