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 | |
179 | dwAddr = RSPSegmentAddr(dwDL);; |
180 | |
181 | LOG_UCODE("BranchZ to DisplayList 0x%08x", dwAddr); |
182 | gDlistStack[gDlistStackPointer].pc = dwAddr; |
183 | gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; |
184 | } |
185 | } |
186 | |
187 | #ifdef DEBUGGER |
188 | void DumpUcodeInfo(UcodeInfo &info) |
189 | { |
190 | DebuggerAppendMsg("Loading Unknown Ucode:\n%08X-%08X-%08X-%08X, Size=0x%X, CRC=0x%08X\nCode:\n", |
191 | info.ucDWORD1, info.ucDWORD2, info.ucDWORD3, info.ucDWORD4, |
192 | info.ucSize, info.ucCRC); |
193 | DumpHex(info.ucStart,20); |
194 | TRACE0("Data:\n"); |
195 | DumpHex(info.ucDStart,20); |
196 | } |
197 | #endif |
198 | |
199 | void RSP_GBI1_LoadUCode(Gfx *gfx) |
200 | { |
201 | SP_Timing(RSP_GBI1_LoadUCode); |
202 | |
203 | //TRACE0("Load ucode"); |
204 | uint32 dwPC = gDlistStack[gDlistStackPointer].pc; |
205 | uint32 dwUcStart = RSPSegmentAddr((gfx->words.w1)); |
206 | uint32 dwSize = ((gfx->words.w0)&0xFFFF)+1; |
207 | uint32 dwUcDStart = RSPSegmentAddr(*(uint32 *)(g_pRDRAMu8 + dwPC-12)); |
208 | |
209 | uint32 ucode = DLParser_CheckUcode(dwUcStart, dwUcDStart, dwSize, 8); |
210 | RSP_SetUcode(ucode, dwUcStart, dwUcDStart, dwSize); |
211 | |
212 | DEBUGGER_PAUSE_AND_DUMP(NEXT_SWITCH_UCODE,{DebuggerAppendMsg("Pause at loading ucode");}); |
213 | } |
214 | |
215 | void RSP_GFX_Force_Matrix(uint32 dwAddr) |
216 | { |
217 | if (dwAddr + 64 > g_dwRamSize) |
218 | { |
219 | DebuggerAppendMsg("ForceMtx: Address invalid (0x%08x)", dwAddr); |
220 | return; |
221 | } |
222 | |
223 | // Load matrix from dwAddr |
224 | LoadMatrix(dwAddr); |
225 | |
226 | CRender::g_pRender->SetWorldProjectMatrix(matToLoad); |
227 | |
228 | DEBUGGER_PAUSE_AND_DUMP(NEXT_MATRIX_CMD,{TRACE0("Paused at ModMatrix Cmd");}); |
229 | } |
230 | |
231 | |
232 | void DisplayVertexInfo(uint32 dwAddr, uint32 dwV0, uint32 dwN) |
233 | { |
234 | #ifdef DEBUGGER |
235 | s8 *pcSrc = (s8 *)(g_pRDRAMu8 + dwAddr); |
236 | short *psSrc = (short *)(g_pRDRAMu8 + dwAddr); |
237 | |
238 | for (uint32 dwV = dwV0; dwV < dwV0 + dwN; dwV++) |
239 | { |
240 | float x = (float)psSrc[0^0x1]; |
241 | float y = (float)psSrc[1^0x1]; |
242 | float z = (float)psSrc[2^0x1]; |
243 | |
244 | //uint32 wFlags = g_dwVtxFlags[dwV]; //(uint16)psSrc[3^0x1]; |
245 | uint32 wFlags = 0; |
246 | |
247 | uint8 a = pcSrc[12^0x3]; |
248 | uint8 b = pcSrc[13^0x3]; |
249 | uint8 c = pcSrc[14^0x3]; |
250 | uint8 d = pcSrc[15^0x3]; |
251 | |
252 | //int nTU = (int)(short)(psSrc[4^0x1]<<4); |
253 | //int nTV = (int)(short)(psSrc[5^0x1]<<4); |
254 | |
255 | //float tu = (float)(nTU>>4); |
256 | //float tv = (float)(nTV>>4); |
257 | float tu = (float)(short)(psSrc[4^0x1]); |
258 | float tv = (float)(short)(psSrc[5^0x1]); |
259 | |
260 | XVECTOR4 & t = g_vecProjected[dwV]; |
261 | |
262 | psSrc += 8; // Increase by 16 bytes |
263 | pcSrc += 16; |
264 | |
265 | LOG_UCODE(" #%02d Flags: 0x%04x Pos: {% 6f,% 6f,% 6f} Tex: {%+7.2f,%+7.2f}, Extra: %02x %02x %02x %02x (transf: {% 6f,% 6f,% 6f})", |
266 | dwV, wFlags, x, y, z, tu, tv, a, b, c, d, t.x, t.y, t.z ); |
267 | } |
268 | #endif |
269 | } |
270 | |
271 | void RSP_MoveMemLight(uint32 dwLight, uint32 dwAddr) |
272 | { |
273 | if( dwLight >= 16 ) |
274 | { |
275 | DebuggerAppendMsg("Warning: invalid light # = %d", dwLight); |
276 | return; |
277 | } |
278 | |
279 | s8 * pcBase = g_pRDRAMs8 + dwAddr; |
280 | uint32 * pdwBase = (uint32 *)pcBase; |
281 | |
282 | |
283 | float range = 0, x, y, z; |
284 | if( options.enableHackForGames == HACK_FOR_ZELDA_MM && (pdwBase[0]&0xFF) == 0x08 && (pdwBase[1]&0xFF) == 0xFF ) |
285 | { |
286 | gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; |
287 | gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; |
288 | short* pdwBase16 = (short*)pcBase; |
289 | x = pdwBase16[5]; |
290 | y = pdwBase16[4]; |
291 | z = pdwBase16[7]; |
292 | range = pdwBase16[6]; |
293 | } |
294 | else |
295 | { |
296 | gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; |
297 | gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; |
298 | x = pcBase[8 ^ 0x3]; |
299 | y = pcBase[9 ^ 0x3]; |
300 | z = pcBase[10 ^ 0x3]; |
301 | } |
302 | |
303 | |
304 | LOG_UCODE(" RGBA: 0x%08x, RGBACopy: 0x%08x, x: %d, y: %d, z: %d", |
305 | gRSPn64lights[dwLight].dwRGBA, |
306 | gRSPn64lights[dwLight].dwRGBACopy, |
307 | x, y, z); |
308 | |
309 | LIGHT_DUMP(TRACE3("Move Light: %08X, %08X, %08X", pdwBase[0], pdwBase[1], pdwBase[2])); |
310 | |
311 | |
312 | if (dwLight == gRSP.ambientLightIndex) |
313 | { |
314 | LOG_UCODE(" (Ambient Light)"); |
315 | |
316 | uint32 dwCol = COLOR_RGBA( (gRSPn64lights[dwLight].dwRGBA >> 24)&0xFF, |
317 | (gRSPn64lights[dwLight].dwRGBA >> 16)&0xFF, |
318 | (gRSPn64lights[dwLight].dwRGBA >> 8)&0xFF, 0xff); |
319 | |
320 | SetAmbientLight( dwCol ); |
321 | } |
322 | else |
323 | { |
324 | LOG_UCODE(" (Normal Light)"); |
325 | |
326 | SetLightCol(dwLight, gRSPn64lights[dwLight].dwRGBA); |
327 | if (pdwBase[2] == 0) // Direction is 0! |
328 | { |
329 | LOG_UCODE(" Light is invalid"); |
330 | } |
331 | SetLightDirection(dwLight, x, y, z, range); |
332 | } |
333 | } |
334 | |
335 | void RSP_MoveMemViewport(uint32 dwAddr) |
336 | { |
337 | if( dwAddr+16 >= g_dwRamSize ) |
338 | { |
339 | TRACE0("MoveMem Viewport, invalid memory"); |
340 | return; |
341 | } |
342 | |
343 | short scale[4]; |
344 | short trans[4]; |
345 | |
346 | // dwAddr is offset into RD_RAM of 8 x 16bits of data... |
347 | scale[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(0*2))^0x2)); |
348 | scale[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(1*2))^0x2)); |
349 | scale[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(2*2))^0x2)); |
350 | scale[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(3*2))^0x2)); |
351 | |
352 | trans[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(4*2))^0x2)); |
353 | trans[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(5*2))^0x2)); |
354 | trans[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(6*2))^0x2)); |
355 | trans[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(7*2))^0x2)); |
356 | |
357 | |
358 | int nCenterX = trans[0]/4; |
359 | int nCenterY = trans[1]/4; |
360 | int nWidth = scale[0]/4; |
361 | int nHeight = scale[1]/4; |
362 | |
363 | // Check for some strange games |
364 | if( nWidth < 0 ) nWidth = -nWidth; |
365 | if( nHeight < 0 ) nHeight = -nHeight; |
366 | |
367 | int nLeft = nCenterX - nWidth; |
368 | int nTop = nCenterY - nHeight; |
369 | int nRight= nCenterX + nWidth; |
370 | int nBottom= nCenterY + nHeight; |
371 | |
372 | //int maxZ = scale[2]; |
373 | int maxZ = 0x3FF; |
374 | |
375 | CRender::g_pRender->SetViewport(nLeft, nTop, nRight, nBottom, maxZ); |
376 | |
377 | LOG_UCODE(" Scale: %d %d %d %d = %d,%d", scale[0], scale[1], scale[2], scale[3], nWidth, nHeight); |
378 | LOG_UCODE(" Trans: %d %d %d %d = %d,%d", trans[0], trans[1], trans[2], trans[3], nCenterX, nCenterY); |
379 | } |
380 | |
381 | |
382 | // S2DEX uses this - 0xc1 |
383 | void RSP_S2DEX_SPObjLoadTxtr_Ucode1(Gfx *gfx) |
384 | { |
385 | SP_Timing(RSP_S2DEX_SPObjLoadTxtr_Ucode1); |
386 | |
387 | // Add S2DEX ucode supporting to F3DEX, see game DT and others |
388 | status.bUseModifiedUcodeMap = true; |
389 | RSP_SetUcode(1); |
390 | memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); |
391 | |
392 | LoadedUcodeMap[S2DEX_OBJ_MOVEMEM] = &RSP_S2DEX_OBJ_MOVEMEM; |
393 | LoadedUcodeMap[S2DEX_OBJ_LOADTXTR] = &RSP_S2DEX_SPObjLoadTxtr; |
394 | LoadedUcodeMap[S2DEX_OBJ_LDTX_SPRITE] = &RSP_S2DEX_SPObjLoadTxSprite; |
395 | LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT] = &RSP_S2DEX_SPObjLoadTxRect; |
396 | LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT_R] = &RSP_S2DEX_SPObjLoadTxRectR; |
397 | |
398 | RSP_S2DEX_SPObjLoadTxtr(gfx); |
399 | } |
400 | |