98e75f2d |
1 | /* |
2 | * Glide64 - Glide video plugin for Nintendo 64 emulators. |
3 | * Copyright (c) 2002 Dave2001 |
4 | * Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
20 | |
21 | //**************************************************************** |
22 | // |
23 | // Glide64 - Glide Plugin for Nintendo 64 emulators |
24 | // Project started on December 29th, 2001 |
25 | // |
26 | // Authors: |
27 | // Dave2001, original author, founded the project in 2001, left it in 2002 |
28 | // Gugaman, joined the project in 2002, left it in 2002 |
29 | // Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002 |
30 | // Hiroshi 'KoolSmoky' Morii, joined the project in 2007 |
31 | // |
32 | //**************************************************************** |
33 | // |
34 | // To modify Glide64: |
35 | // * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me. |
36 | // * Do NOT send me the whole project or file that you modified. Take out your modified code sections, and tell me where to put them. If people sent the whole thing, I would have many different versions, but no idea how to combine them all. |
37 | // |
38 | //**************************************************************** |
39 | |
40 | #define ucode_Fast3D 0 |
41 | #define ucode_F3DEX 1 |
42 | #define ucode_F3DEX2 2 |
43 | #define ucode_WaveRace 3 |
44 | #define ucode_StarWars 4 |
45 | #define ucode_DiddyKong 5 |
46 | #define ucode_S2DEX 6 |
47 | #define ucode_PerfectDark 7 |
48 | #define ucode_CBFD 8 |
49 | #define ucode_zSort 9 |
50 | #define ucode_Turbo3d 21 |
51 | |
52 | static void rsp_vertex(int v0, int n) |
53 | { |
54 | Check_FrameSkip; |
55 | |
56 | wxUint32 addr = segoffset(rdp.cmd1) & 0x00FFFFFF; |
57 | int i; |
58 | float x, y, z; |
59 | |
60 | rdp.v0 = v0; // Current vertex |
61 | rdp.vn = n; // Number to copy |
62 | |
63 | // This is special, not handled in update(), but here |
64 | // * Matrix Pre-multiplication idea by Gonetz (Gonetz@ngs.ru) |
65 | if (rdp.update & UPDATE_MULT_MAT) |
66 | { |
67 | rdp.update ^= UPDATE_MULT_MAT; |
68 | MulMatrices(rdp.model, rdp.proj, rdp.combined); |
69 | } |
70 | // * |
71 | |
72 | // This is special, not handled in update() |
73 | if (rdp.update & UPDATE_LIGHTS) |
74 | { |
75 | rdp.update ^= UPDATE_LIGHTS; |
76 | |
77 | // Calculate light vectors |
78 | for (wxUint32 l=0; l<rdp.num_lights; l++) |
79 | { |
80 | InverseTransformVector(&rdp.light[l].dir_x, rdp.light_vector[l], rdp.model); |
81 | NormalizeVector (rdp.light_vector[l]); |
82 | } |
83 | } |
84 | |
85 | FRDP ("rsp:vertex v0:%d, n:%d, from: %08lx\n", v0, n, addr); |
86 | |
87 | for (i=0; i < (n<<4); i+=16) |
88 | { |
89 | VERTEX *v = &rdp.vtx[v0 + (i>>4)]; |
90 | x = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 0)^1]; |
91 | y = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 1)^1]; |
92 | z = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 2)^1]; |
93 | v->flags = ((wxUint16*)gfx.RDRAM)[(((addr+i) >> 1) + 3)^1]; |
94 | v->ou = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 4)^1]; |
95 | v->ov = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 5)^1]; |
96 | v->uv_scaled = 0; |
97 | v->a = ((wxUint8*)gfx.RDRAM)[(addr+i + 15)^3]; |
98 | |
99 | v->x = x*rdp.combined[0][0] + y*rdp.combined[1][0] + z*rdp.combined[2][0] + rdp.combined[3][0]; |
100 | v->y = x*rdp.combined[0][1] + y*rdp.combined[1][1] + z*rdp.combined[2][1] + rdp.combined[3][1]; |
101 | v->z = x*rdp.combined[0][2] + y*rdp.combined[1][2] + z*rdp.combined[2][2] + rdp.combined[3][2]; |
102 | v->w = x*rdp.combined[0][3] + y*rdp.combined[1][3] + z*rdp.combined[2][3] + rdp.combined[3][3]; |
103 | |
104 | |
105 | if (fabs(v->w) < 0.001) v->w = 0.001f; |
106 | v->oow = 1.0f / v->w; |
107 | v->x_w = v->x * v->oow; |
108 | v->y_w = v->y * v->oow; |
109 | v->z_w = v->z * v->oow; |
110 | CalculateFog (v); |
111 | |
112 | v->uv_calculated = 0xFFFFFFFF; |
113 | v->screen_translated = 0; |
114 | v->shade_mod = 0; |
115 | |
116 | v->scr_off = 0; |
117 | if (v->x < -v->w) v->scr_off |= 1; |
118 | if (v->x > v->w) v->scr_off |= 2; |
119 | if (v->y < -v->w) v->scr_off |= 4; |
120 | if (v->y > v->w) v->scr_off |= 8; |
121 | if (v->w < 0.1f) v->scr_off |= 16; |
122 | // if (v->z_w > 1.0f) v->scr_off |= 32; |
123 | |
124 | if (rdp.geom_mode & 0x00020000) |
125 | { |
126 | v->vec[0] = ((char*)gfx.RDRAM)[(addr+i + 12)^3]; |
127 | v->vec[1] = ((char*)gfx.RDRAM)[(addr+i + 13)^3]; |
128 | v->vec[2] = ((char*)gfx.RDRAM)[(addr+i + 14)^3]; |
129 | if (rdp.geom_mode & 0x40000) |
130 | { |
131 | if (rdp.geom_mode & 0x80000) |
132 | calc_linear (v); |
133 | else |
134 | calc_sphere (v); |
135 | } |
136 | NormalizeVector (v->vec); |
137 | |
138 | calc_light (v); |
139 | } |
140 | else |
141 | { |
142 | v->r = ((wxUint8*)gfx.RDRAM)[(addr+i + 12)^3]; |
143 | v->g = ((wxUint8*)gfx.RDRAM)[(addr+i + 13)^3]; |
144 | v->b = ((wxUint8*)gfx.RDRAM)[(addr+i + 14)^3]; |
145 | } |
146 | #ifdef EXTREME_LOGGING |
147 | FRDP ("v%d - x: %f, y: %f, z: %f, w: %f, u: %f, v: %f, f: %f, z_w: %f, r=%d, g=%d, b=%d, a=%d\n", i>>4, v->x, v->y, v->z, v->w, v->ou*rdp.tiles[rdp.cur_tile].s_scale, v->ov*rdp.tiles[rdp.cur_tile].t_scale, v->f, v->z_w, v->r, v->g, v->b, v->a); |
148 | #endif |
149 | |
150 | } |
151 | } |
152 | |
153 | static void rsp_tri1(VERTEX **v, wxUint16 linew = 0) |
154 | { |
155 | Check_FrameSkip; |
156 | |
157 | if (cull_tri(v)) |
158 | rdp.tri_n ++; |
159 | else |
160 | { |
161 | update (); |
162 | draw_tri (v, linew); |
163 | rdp.tri_n ++; |
164 | } |
165 | } |
166 | |
167 | static void rsp_tri2 (VERTEX **v) |
168 | { |
169 | Check_FrameSkip; |
170 | |
171 | int updated = 0; |
172 | |
173 | if (cull_tri(v)) |
174 | rdp.tri_n ++; |
175 | else |
176 | { |
177 | updated = 1; |
178 | update (); |
179 | |
180 | draw_tri (v); |
181 | rdp.tri_n ++; |
182 | } |
183 | |
184 | if (cull_tri(v+3)) |
185 | rdp.tri_n ++; |
186 | else |
187 | { |
188 | if (!updated) |
189 | update (); |
190 | |
191 | draw_tri (v+3); |
192 | rdp.tri_n ++; |
193 | } |
194 | } |
195 | |
196 | // |
197 | // uc0:vertex - loads vertices |
198 | // |
199 | static void uc0_vertex() |
200 | { |
201 | int v0 = (rdp.cmd0 >> 16) & 0xF; // Current vertex |
202 | int n = ((rdp.cmd0 >> 20) & 0xF) + 1; // Number of vertices to copy |
203 | rsp_vertex(v0, n); |
204 | } |
205 | |
206 | // ** Definitions ** |
207 | |
208 | void modelview_load (float m[4][4]) |
209 | { |
210 | memcpy (rdp.model, m, 64); // 4*4*4(float) |
211 | |
212 | rdp.update |= UPDATE_MULT_MAT | UPDATE_LIGHTS; |
213 | } |
214 | |
215 | void modelview_mul (float m[4][4]) |
216 | { |
217 | DECLAREALIGN16VAR(m_src[4][4]); |
218 | memcpy (m_src, rdp.model, 64); |
219 | MulMatrices(m, m_src, rdp.model); |
220 | rdp.update |= UPDATE_MULT_MAT | UPDATE_LIGHTS; |
221 | } |
222 | |
223 | void modelview_push () |
224 | { |
225 | if (rdp.model_i == rdp.model_stack_size) |
226 | { |
227 | RDP_E ("** Model matrix stack overflow ** too many pushes\n"); |
228 | LRDP("** Model matrix stack overflow ** too many pushes\n"); |
229 | return; |
230 | } |
231 | |
232 | memcpy (rdp.model_stack[rdp.model_i], rdp.model, 64); |
233 | rdp.model_i ++; |
234 | } |
235 | |
236 | void modelview_pop (int num = 1) |
237 | { |
238 | if (rdp.model_i > num - 1) |
239 | { |
240 | rdp.model_i -= num; |
241 | } |
242 | else |
243 | { |
244 | RDP_E ("** Model matrix stack error ** too many pops\n"); |
245 | LRDP("** Model matrix stack error ** too many pops\n"); |
246 | return; |
247 | } |
248 | memcpy (rdp.model, rdp.model_stack[rdp.model_i], 64); |
249 | rdp.update |= UPDATE_MULT_MAT | UPDATE_LIGHTS; |
250 | } |
251 | |
252 | void modelview_load_push (float m[4][4]) |
253 | { |
254 | modelview_push (); |
255 | modelview_load (m); |
256 | } |
257 | |
258 | void modelview_mul_push (float m[4][4]) |
259 | { |
260 | modelview_push (); |
261 | modelview_mul (m); |
262 | } |
263 | |
264 | void projection_load (float m[4][4]) |
265 | { |
266 | memcpy (rdp.proj, m, 64); // 4*4*4(float) |
267 | |
268 | rdp.update |= UPDATE_MULT_MAT; |
269 | } |
270 | |
271 | void projection_mul (float m[4][4]) |
272 | { |
273 | DECLAREALIGN16VAR(m_src[4][4]); |
274 | memcpy (m_src, rdp.proj, 64); |
275 | MulMatrices(m, m_src, rdp.proj); |
276 | rdp.update |= UPDATE_MULT_MAT; |
277 | } |
278 | |
279 | void load_matrix (float m[4][4], wxUint32 addr) |
280 | { |
281 | FRDP ("matrix - addr: %08lx\n", addr); |
282 | int x,y; // matrix index |
283 | addr >>= 1; |
284 | wxUint16 * src = (wxUint16*)gfx.RDRAM; |
285 | for (x=0; x<16; x+=4) { // Adding 4 instead of one, just to remove mult. later |
286 | for (y=0; y<4; y++) { |
287 | m[x>>2][y] = (float)( |
288 | (((wxInt32)src[(addr+x+y)^1]) << 16) | |
289 | src[(addr+x+y+16)^1] |
290 | ) / 65536.0f; |
291 | } |
292 | } |
293 | } |
294 | |
295 | // |
296 | // uc0:matrix - performs matrix operations |
297 | // |
298 | static void uc0_matrix() |
299 | { |
300 | LRDP("uc0:matrix "); |
301 | |
302 | // Use segment offset to get the address |
303 | wxUint32 addr = segoffset(rdp.cmd1) & 0x00FFFFFF; |
304 | wxUint8 command = (wxUint8)((rdp.cmd0 >> 16) & 0xFF); |
305 | |
306 | DECLAREALIGN16VAR(m[4][4]); |
307 | load_matrix(m, addr); |
308 | |
309 | switch (command) |
310 | { |
311 | case 0: // modelview mul nopush |
312 | LRDP("modelview mul\n"); |
313 | modelview_mul (m); |
314 | break; |
315 | |
316 | case 1: // projection mul nopush |
317 | case 5: // projection mul push, can't push projection |
318 | LRDP("projection mul\n"); |
319 | projection_mul (m); |
320 | break; |
321 | |
322 | case 2: // modelview load nopush |
323 | LRDP("modelview load\n"); |
324 | modelview_load (m); |
325 | break; |
326 | |
327 | case 3: // projection load nopush |
328 | case 7: // projection load push, can't push projection |
329 | LRDP("projection load\n"); |
330 | projection_load (m); |
331 | |
332 | break; |
333 | |
334 | case 4: // modelview mul push |
335 | LRDP("modelview mul push\n"); |
336 | modelview_mul_push (m); |
337 | break; |
338 | |
339 | case 6: // modelview load push |
340 | LRDP("modelview load push\n"); |
341 | modelview_load_push (m); |
342 | break; |
343 | |
344 | default: |
345 | FRDP_E ("Unknown matrix command, %02lx", command); |
346 | FRDP ("Unknown matrix command, %02lx", command); |
347 | } |
348 | |
349 | #ifdef EXTREME_LOGGING |
350 | FRDP ("{%f,%f,%f,%f}\n", m[0][0], m[0][1], m[0][2], m[0][3]); |
351 | FRDP ("{%f,%f,%f,%f}\n", m[1][0], m[1][1], m[1][2], m[1][3]); |
352 | FRDP ("{%f,%f,%f,%f}\n", m[2][0], m[2][1], m[2][2], m[2][3]); |
353 | FRDP ("{%f,%f,%f,%f}\n", m[3][0], m[3][1], m[3][2], m[3][3]); |
354 | FRDP ("\nmodel\n{%f,%f,%f,%f}\n", rdp.model[0][0], rdp.model[0][1], rdp.model[0][2], rdp.model[0][3]); |
355 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[1][0], rdp.model[1][1], rdp.model[1][2], rdp.model[1][3]); |
356 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[2][0], rdp.model[2][1], rdp.model[2][2], rdp.model[2][3]); |
357 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[3][0], rdp.model[3][1], rdp.model[3][2], rdp.model[3][3]); |
358 | FRDP ("\nproj\n{%f,%f,%f,%f}\n", rdp.proj[0][0], rdp.proj[0][1], rdp.proj[0][2], rdp.proj[0][3]); |
359 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[1][0], rdp.proj[1][1], rdp.proj[1][2], rdp.proj[1][3]); |
360 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[2][0], rdp.proj[2][1], rdp.proj[2][2], rdp.proj[2][3]); |
361 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[3][0], rdp.proj[3][1], rdp.proj[3][2], rdp.proj[3][3]); |
362 | #endif |
363 | } |
364 | |
365 | // |
366 | // uc0:movemem - loads a structure with data |
367 | // |
368 | static void uc0_movemem() |
369 | { |
370 | LRDP("uc0:movemem "); |
371 | |
372 | wxUint32 i,a; |
373 | |
374 | // Check the command |
375 | switch ((rdp.cmd0 >> 16) & 0xFF) |
376 | { |
377 | case 0x80: |
378 | { |
379 | a = (segoffset(rdp.cmd1) & 0xFFFFFF) >> 1; |
380 | |
381 | short scale_x = ((short*)gfx.RDRAM)[(a+0)^1] / 4; |
382 | short scale_y = ((short*)gfx.RDRAM)[(a+1)^1] / 4; |
383 | short scale_z = ((short*)gfx.RDRAM)[(a+2)^1]; |
384 | short trans_x = ((short*)gfx.RDRAM)[(a+4)^1] / 4; |
385 | short trans_y = ((short*)gfx.RDRAM)[(a+5)^1] / 4; |
386 | short trans_z = ((short*)gfx.RDRAM)[(a+6)^1]; |
387 | if (settings.correct_viewport) |
388 | { |
389 | scale_x = abs(scale_x); |
390 | scale_y = abs(scale_y); |
391 | } |
392 | rdp.view_scale[0] = scale_x * rdp.scale_x; |
393 | rdp.view_scale[1] = -scale_y * rdp.scale_y; |
394 | rdp.view_scale[2] = 32.0f * scale_z; |
395 | rdp.view_trans[0] = trans_x * rdp.scale_x; |
396 | rdp.view_trans[1] = trans_y * rdp.scale_y; |
397 | rdp.view_trans[2] = 32.0f * trans_z; |
398 | |
399 | // there are other values than x and y, but I don't know what they do |
400 | |
401 | rdp.update |= UPDATE_VIEWPORT; |
402 | |
403 | FRDP ("viewport scale(%d, %d, %d), trans(%d, %d, %d), from:%08lx\n", scale_x, scale_y, scale_z, |
404 | trans_x, trans_y, trans_z, rdp.cmd1); |
405 | } |
406 | break; |
407 | |
408 | case 0x82: |
409 | { |
410 | a = segoffset(rdp.cmd1) & 0x00ffffff; |
411 | char dir_x = ((char*)gfx.RDRAM)[(a+8)^3]; |
412 | rdp.lookat[1][0] = (float)(dir_x) / 127.0f; |
413 | char dir_y = ((char*)gfx.RDRAM)[(a+9)^3]; |
414 | rdp.lookat[1][1] = (float)(dir_y) / 127.0f; |
415 | char dir_z = ((char*)gfx.RDRAM)[(a+10)^3]; |
416 | rdp.lookat[1][2] = (float)(dir_z) / 127.0f; |
417 | if (!dir_x && !dir_y) |
418 | rdp.use_lookat = FALSE; |
419 | else |
420 | rdp.use_lookat = TRUE; |
421 | FRDP("lookat_y (%f, %f, %f)\n", rdp.lookat[1][0], rdp.lookat[1][1], rdp.lookat[1][2]); |
422 | } |
423 | break; |
424 | |
425 | case 0x84: |
426 | a = segoffset(rdp.cmd1) & 0x00ffffff; |
427 | rdp.lookat[0][0] = (float)(((char*)gfx.RDRAM)[(a+8)^3]) / 127.0f; |
428 | rdp.lookat[0][1] = (float)(((char*)gfx.RDRAM)[(a+9)^3]) / 127.0f; |
429 | rdp.lookat[0][2] = (float)(((char*)gfx.RDRAM)[(a+10)^3]) / 127.0f; |
430 | rdp.use_lookat = TRUE; |
431 | FRDP("lookat_x (%f, %f, %f)\n", rdp.lookat[1][0], rdp.lookat[1][1], rdp.lookat[1][2]); |
432 | break; |
433 | |
434 | case 0x86: |
435 | case 0x88: |
436 | case 0x8a: |
437 | case 0x8c: |
438 | case 0x8e: |
439 | case 0x90: |
440 | case 0x92: |
441 | case 0x94: |
442 | // Get the light # |
443 | i = (((rdp.cmd0 >> 16) & 0xff) - 0x86) >> 1; |
444 | a = segoffset(rdp.cmd1) & 0x00ffffff; |
445 | |
446 | // Get the data |
447 | rdp.light[i].r = (float)(((wxUint8*)gfx.RDRAM)[(a+0)^3]) / 255.0f; |
448 | rdp.light[i].g = (float)(((wxUint8*)gfx.RDRAM)[(a+1)^3]) / 255.0f; |
449 | rdp.light[i].b = (float)(((wxUint8*)gfx.RDRAM)[(a+2)^3]) / 255.0f; |
450 | rdp.light[i].a = 1.0f; |
451 | // ** Thanks to Icepir8 for pointing this out ** |
452 | // Lighting must be signed byte instead of byte |
453 | rdp.light[i].dir_x = (float)(((char*)gfx.RDRAM)[(a+8)^3]) / 127.0f; |
454 | rdp.light[i].dir_y = (float)(((char*)gfx.RDRAM)[(a+9)^3]) / 127.0f; |
455 | rdp.light[i].dir_z = (float)(((char*)gfx.RDRAM)[(a+10)^3]) / 127.0f; |
456 | // ** |
457 | |
458 | //rdp.update |= UPDATE_LIGHTS; |
459 | |
460 | FRDP ("light: n: %d, r: %.3f, g: %.3f, b: %.3f, x: %.3f, y: %.3f, z: %.3f\n", |
461 | i, rdp.light[i].r, rdp.light[i].g, rdp.light[i].b, |
462 | rdp.light_vector[i][0], rdp.light_vector[i][1], rdp.light_vector[i][2]); |
463 | break; |
464 | |
465 | |
466 | case 0x9E: //gSPForceMatrix command. Modification of uc2_movemem:matrix. Gonetz. |
467 | { |
468 | // do not update the combined matrix! |
469 | rdp.update &= ~UPDATE_MULT_MAT; |
470 | |
471 | wxUint32 addr = segoffset(rdp.cmd1) & 0x00FFFFFF; |
472 | load_matrix(rdp.combined, addr); |
473 | |
474 | addr = rdp.pc[rdp.pc_i] & BMASK; |
475 | rdp.pc[rdp.pc_i] = (addr+24) & BMASK; //skip next 3 command, b/c they all are part of gSPForceMatrix |
476 | |
477 | #ifdef EXTREME_LOGGING |
478 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[0][0], rdp.combined[0][1], rdp.combined[0][2], rdp.combined[0][3]); |
479 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[1][0], rdp.combined[1][1], rdp.combined[1][2], rdp.combined[1][3]); |
480 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[2][0], rdp.combined[2][1], rdp.combined[2][2], rdp.combined[2][3]); |
481 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[3][0], rdp.combined[3][1], rdp.combined[3][2], rdp.combined[3][3]); |
482 | #endif |
483 | } |
484 | break; |
485 | |
486 | //next 3 command should never appear since they will be skipped in previous command |
487 | case 0x98: |
488 | RDP_E ("uc0:movemem matrix 0 - ERROR!\n"); |
489 | LRDP("matrix 0 - IGNORED\n"); |
490 | break; |
491 | |
492 | case 0x9A: |
493 | RDP_E ("uc0:movemem matrix 1 - ERROR!\n"); |
494 | LRDP("matrix 1 - IGNORED\n"); |
495 | break; |
496 | |
497 | case 0x9C: |
498 | RDP_E ("uc0:movemem matrix 2 - ERROR!\n"); |
499 | LRDP("matrix 2 - IGNORED\n"); |
500 | break; |
501 | |
502 | default: |
503 | FRDP_E ("uc0:movemem unknown (index: 0x%08lx)\n", (rdp.cmd0 >> 16) & 0xFF); |
504 | FRDP ("unknown (index: 0x%08lx)\n", (rdp.cmd0 >> 16) & 0xFF); |
505 | } |
506 | } |
507 | |
508 | // |
509 | // uc0:displaylist - makes a call to another section of code |
510 | // |
511 | static void uc0_displaylist() |
512 | { |
513 | wxUint32 addr = segoffset(rdp.cmd1) & 0x00FFFFFF; |
514 | |
515 | // This fixes partially Gauntlet: Legends |
516 | if (addr == rdp.pc[rdp.pc_i] - 8) { LRDP("display list not executed!\n"); return; } |
517 | |
518 | wxUint32 push = (rdp.cmd0 >> 16) & 0xFF; // push the old location? |
519 | |
520 | FRDP("uc0:displaylist: %08lx, push:%s", addr, push?"no":"yes"); |
521 | FRDP(" (seg %d, offset %08lx)\n", (rdp.cmd1>>24)&0x0F, rdp.cmd1&0x00FFFFFF); |
522 | |
523 | switch (push) |
524 | { |
525 | case 0: // push |
526 | if (rdp.pc_i >= 9) { |
527 | RDP_E ("** DL stack overflow **"); |
528 | LRDP("** DL stack overflow **\n"); |
529 | return; |
530 | } |
531 | rdp.pc_i ++; // go to the next PC in the stack |
532 | rdp.pc[rdp.pc_i] = addr; // jump to the address |
533 | break; |
534 | |
535 | case 1: // no push |
536 | rdp.pc[rdp.pc_i] = addr; // just jump to the address |
537 | break; |
538 | |
539 | default: |
540 | RDP_E("Unknown displaylist operation\n"); |
541 | LRDP("Unknown displaylist operation\n"); |
542 | } |
543 | } |
544 | |
545 | // |
546 | // tri1 - renders a triangle |
547 | // |
548 | static void uc0_tri1() |
549 | { |
550 | Check_FrameSkip; |
551 | |
552 | FRDP("uc0:tri1 #%d - %d, %d, %d\n", rdp.tri_n, |
553 | ((rdp.cmd1>>16) & 0xFF) / 10, |
554 | ((rdp.cmd1>>8) & 0xFF) / 10, |
555 | (rdp.cmd1 & 0xFF) / 10); |
556 | |
557 | VERTEX *v[3] = { |
558 | &rdp.vtx[((rdp.cmd1 >> 16) & 0xFF) / 10], |
559 | &rdp.vtx[((rdp.cmd1 >> 8) & 0xFF) / 10], |
560 | &rdp.vtx[(rdp.cmd1 & 0xFF) / 10] |
561 | }; |
562 | if (settings.hacks & hack_Makers) |
563 | { |
564 | rdp.force_wrap = FALSE; |
565 | for (int i = 0; i < 3; i++) |
566 | { |
567 | if (v[i]->ou < 0.0f || v[i]->ov < 0.0f) |
568 | { |
569 | rdp.force_wrap = TRUE; |
570 | break; |
571 | } |
572 | } |
573 | } |
574 | rsp_tri1(v); |
575 | } |
576 | |
577 | // |
578 | // uc0:enddl - ends a call made by uc0:displaylist |
579 | // |
580 | static void uc0_enddl() |
581 | { |
582 | LRDP("uc0:enddl\n"); |
583 | |
584 | if (rdp.pc_i == 0) |
585 | { |
586 | LRDP("RDP end\n"); |
587 | |
588 | // Halt execution here |
589 | rdp.halt = 1; |
590 | } |
591 | |
592 | rdp.pc_i --; |
593 | } |
594 | |
595 | static void uc0_culldl() |
596 | { |
597 | wxUint8 vStart = (wxUint8)((rdp.cmd0 & 0x00FFFFFF) / 40) & 0xF; |
598 | wxUint8 vEnd = (wxUint8)(rdp.cmd1 / 40) & 0x0F; |
599 | wxUint32 cond = 0; |
600 | VERTEX *v; |
601 | |
602 | FRDP("uc0:culldl start: %d, end: %d\n", vStart, vEnd); |
603 | |
604 | if (vEnd < vStart) return; |
605 | for (wxUint16 i=vStart; i<=vEnd; i++) |
606 | { |
607 | v = &rdp.vtx[i]; |
608 | // Check if completely off the screen (quick frustrum clipping for 90 FOV) |
609 | if (v->x >= -v->w) |
610 | cond |= 0x01; |
611 | if (v->x <= v->w) |
612 | cond |= 0x02; |
613 | if (v->y >= -v->w) |
614 | cond |= 0x04; |
615 | if (v->y <= v->w) |
616 | cond |= 0x08; |
617 | if (v->w >= 0.1f) |
618 | cond |= 0x10; |
619 | |
620 | if (cond == 0x1F) |
621 | return; |
622 | } |
623 | |
624 | LRDP(" - "); // specify that the enddl is not a real command |
625 | uc0_enddl (); |
626 | } |
627 | |
628 | static void uc0_popmatrix() |
629 | { |
630 | LRDP("uc0:popmatrix\n"); |
631 | |
632 | wxUint32 param = rdp.cmd1; |
633 | |
634 | switch (param) |
635 | { |
636 | case 0: // modelview |
637 | modelview_pop (); |
638 | break; |
639 | |
640 | case 1: // projection, can't |
641 | break; |
642 | |
643 | default: |
644 | FRDP_E ("Unknown uc0:popmatrix command: 0x%08lx\n", param); |
645 | FRDP ("Unknown uc0:popmatrix command: 0x%08lx\n", param); |
646 | } |
647 | } |
648 | |
649 | static void uc6_obj_sprite (); |
650 | |
651 | static void uc0_modifyvtx(wxUint8 where, wxUint16 vtx, wxUint32 val) |
652 | { |
653 | VERTEX *v = &rdp.vtx[vtx]; |
654 | |
655 | switch (where) |
656 | { |
657 | case 0: |
658 | uc6_obj_sprite (); |
659 | break; |
660 | |
661 | case 0x10: // RGBA |
662 | v->r = (wxUint8)(val >> 24); |
663 | v->g = (wxUint8)((val >> 16) & 0xFF); |
664 | v->b = (wxUint8)((val >> 8) & 0xFF); |
665 | v->a = (wxUint8)(val & 0xFF); |
666 | v->shade_mod = 0; |
667 | |
668 | FRDP ("RGBA: %d, %d, %d, %d\n", v->r, v->g, v->b, v->a); |
669 | break; |
670 | |
671 | case 0x14: // ST |
672 | { |
673 | float scale = rdp.Persp_en ? 0.03125f : 0.015625f; |
674 | v->ou = (float)((short)(val>>16)) * scale; |
675 | v->ov = (float)((short)(val&0xFFFF)) * scale; |
676 | v->uv_calculated = 0xFFFFFFFF; |
677 | v->uv_scaled = 1; |
678 | } |
679 | FRDP ("u/v: (%04lx, %04lx), (%f, %f)\n", (short)(val>>16), (short)(val&0xFFFF), |
680 | v->ou, v->ov); |
681 | break; |
682 | |
683 | case 0x18: // XY screen |
684 | { |
685 | float scr_x = (float)((short)(val>>16)) / 4.0f; |
686 | float scr_y = (float)((short)(val&0xFFFF)) / 4.0f; |
687 | v->screen_translated = 2; |
688 | v->sx = scr_x * rdp.scale_x + rdp.offset_x; |
689 | v->sy = scr_y * rdp.scale_y + rdp.offset_y; |
690 | if (v->w < 0.01f) |
691 | { |
692 | v->w = 1.0f; |
693 | v->oow = 1.0f; |
694 | v->z_w = 1.0f; |
695 | } |
696 | v->sz = rdp.view_trans[2] + v->z_w * rdp.view_scale[2]; |
697 | |
698 | v->scr_off = 0; |
699 | if (scr_x < 0) v->scr_off |= 1; |
700 | if (scr_x > rdp.vi_width) v->scr_off |= 2; |
701 | if (scr_y < 0) v->scr_off |= 4; |
702 | if (scr_y > rdp.vi_height) v->scr_off |= 8; |
703 | if (v->w < 0.1f) v->scr_off |= 16; |
704 | |
705 | FRDP ("x/y: (%f, %f)\n", scr_x, scr_y); |
706 | } |
707 | break; |
708 | |
709 | case 0x1C: // Z screen |
710 | { |
711 | float scr_z = (float)((short)(val>>16)); |
712 | v->z_w = (scr_z - rdp.view_trans[2]) / rdp.view_scale[2]; |
713 | v->z = v->z_w * v->w; |
714 | FRDP ("z: %f\n", scr_z); |
715 | } |
716 | break; |
717 | |
718 | default: |
719 | LRDP("UNKNOWN\n"); |
720 | break; |
721 | } |
722 | } |
723 | |
724 | // |
725 | // uc0:moveword - moves a word to someplace, like the segment pointers |
726 | // |
727 | static void uc0_moveword() |
728 | { |
729 | LRDP("uc0:moveword "); |
730 | |
731 | // Find which command this is (lowest byte of cmd0) |
732 | switch (rdp.cmd0 & 0xFF) |
733 | { |
734 | case 0x00: |
735 | RDP_E ("uc0:moveword matrix - IGNORED\n"); |
736 | LRDP("matrix - IGNORED\n"); |
737 | break; |
738 | |
739 | case 0x02: |
740 | rdp.num_lights = ((rdp.cmd1 - 0x80000000) >> 5) - 1; // inverse of equation |
741 | if (rdp.num_lights > 8) rdp.num_lights = 0; |
742 | |
743 | rdp.update |= UPDATE_LIGHTS; |
744 | FRDP ("numlights: %d\n", rdp.num_lights); |
745 | break; |
746 | |
747 | case 0x04: |
748 | if (((rdp.cmd0>>8)&0xFFFF) == 0x04) |
749 | { |
750 | rdp.clip_ratio = sqrt((float)rdp.cmd1); |
751 | rdp.update |= UPDATE_VIEWPORT; |
752 | } |
753 | FRDP ("clip %08lx, %08lx\n", rdp.cmd0, rdp.cmd1); |
754 | break; |
755 | |
756 | case 0x06: // segment |
757 | FRDP ("segment: %08lx -> seg%d\n", rdp.cmd1, (rdp.cmd0 >> 10) & 0x0F); |
758 | if ((rdp.cmd1&BMASK)<BMASK) |
759 | rdp.segment[(rdp.cmd0 >> 10) & 0x0F] = rdp.cmd1; |
760 | break; |
761 | |
762 | case 0x08: |
763 | { |
764 | rdp.fog_multiplier = (short)(rdp.cmd1 >> 16); |
765 | rdp.fog_offset = (short)(rdp.cmd1 & 0x0000FFFF); |
766 | FRDP ("fog: multiplier: %f, offset: %f\n", rdp.fog_multiplier, rdp.fog_offset); |
767 | } |
768 | break; |
769 | |
770 | case 0x0a: // moveword LIGHTCOL |
771 | { |
772 | int n = (rdp.cmd0&0xE000) >> 13; |
773 | FRDP ("lightcol light:%d, %08lx\n", n, rdp.cmd1); |
774 | |
775 | rdp.light[n].r = (float)((rdp.cmd1 >> 24) & 0xFF) / 255.0f; |
776 | rdp.light[n].g = (float)((rdp.cmd1 >> 16) & 0xFF) / 255.0f; |
777 | rdp.light[n].b = (float)((rdp.cmd1 >> 8) & 0xFF) / 255.0f; |
778 | rdp.light[n].a = 255; |
779 | } |
780 | break; |
781 | |
782 | case 0x0c: |
783 | { |
784 | wxUint16 val = (wxUint16)((rdp.cmd0 >> 8) & 0xFFFF); |
785 | wxUint16 vtx = val / 40; |
786 | wxUint8 where = val%40; |
787 | uc0_modifyvtx(where, vtx, rdp.cmd1); |
788 | FRDP ("uc0:modifyvtx: vtx: %d, where: 0x%02lx, val: %08lx - ", vtx, where, rdp.cmd1); |
789 | } |
790 | break; |
791 | |
792 | case 0x0e: |
793 | LRDP("perspnorm - IGNORED\n"); |
794 | break; |
795 | |
796 | default: |
797 | FRDP_E ("uc0:moveword unknown (index: 0x%08lx)\n", rdp.cmd0 & 0xFF); |
798 | FRDP ("unknown (index: 0x%08lx)\n", rdp.cmd0 & 0xFF); |
799 | } |
800 | } |
801 | |
802 | static void uc0_texture() |
803 | { |
804 | int tile = (rdp.cmd0 >> 8) & 0x07; |
805 | if (tile == 7 && (settings.hacks&hack_Supercross)) tile = 0; //fix for supercross 2000 |
806 | rdp.mipmap_level = (rdp.cmd0 >> 11) & 0x07; |
807 | wxUint32 on = (rdp.cmd0 & 0xFF); |
808 | rdp.cur_tile = tile; |
809 | |
810 | if (on) |
811 | { |
812 | wxUint16 s = (wxUint16)((rdp.cmd1 >> 16) & 0xFFFF); |
813 | wxUint16 t = (wxUint16)(rdp.cmd1 & 0xFFFF); |
814 | |
815 | TILE *tmp_tile = &rdp.tiles[tile]; |
816 | tmp_tile->on = 1; |
817 | tmp_tile->org_s_scale = s; |
818 | tmp_tile->org_t_scale = t; |
819 | tmp_tile->s_scale = (float)(s+1)/65536.0f; |
820 | tmp_tile->t_scale = (float)(t+1)/65536.0f; |
821 | tmp_tile->s_scale /= 32.0f; |
822 | tmp_tile->t_scale /= 32.0f; |
823 | |
824 | rdp.update |= UPDATE_TEXTURE; |
825 | |
826 | FRDP("uc0:texture: tile: %d, mipmap_lvl: %d, on: %d, s_scale: %f, t_scale: %f\n", |
827 | tile, rdp.mipmap_level, on, tmp_tile->s_scale, tmp_tile->t_scale); |
828 | } |
829 | else |
830 | { |
831 | LRDP("uc0:texture skipped b/c of off\n"); |
832 | rdp.tiles[tile].on = 0; |
833 | } |
834 | } |
835 | |
836 | |
837 | static void uc0_setothermode_h() |
838 | { |
839 | LRDP("uc0:setothermode_h: "); |
840 | |
841 | int shift, len; |
842 | if ((settings.ucode == ucode_F3DEX2) || (settings.ucode == ucode_CBFD)) |
843 | { |
844 | len = (rdp.cmd0 & 0xFF) + 1; |
845 | shift = 32 - ((rdp.cmd0 >> 8) & 0xFF) - len; |
846 | } |
847 | else |
848 | { |
849 | shift = (rdp.cmd0 >> 8) & 0xFF; |
850 | len = rdp.cmd0 & 0xFF; |
851 | } |
852 | |
853 | wxUint32 mask = 0; |
854 | int i = len; |
855 | for (; i; i--) |
856 | mask = (mask << 1) | 1; |
857 | mask <<= shift; |
858 | |
859 | rdp.cmd1 &= mask; |
860 | rdp.othermode_h &= ~mask; |
861 | rdp.othermode_h |= rdp.cmd1; |
862 | |
863 | if (mask & 0x00000030) // alpha dither mode |
864 | { |
865 | rdp.alpha_dither_mode = (rdp.othermode_h >> 4) & 0x3; |
866 | FRDP ("alpha dither mode: %s\n", str_dither[rdp.alpha_dither_mode]); |
867 | } |
868 | |
869 | if (mask & 0x000000C0) // rgb dither mode |
870 | { |
871 | wxUint32 dither_mode = (rdp.othermode_h >> 6) & 0x3; |
872 | FRDP ("rgb dither mode: %s\n", str_dither[dither_mode]); |
873 | } |
874 | |
875 | if (mask & 0x00003000) // filter mode |
876 | { |
877 | rdp.filter_mode = (int)((rdp.othermode_h & 0x00003000) >> 12); |
878 | rdp.update |= UPDATE_TEXTURE; |
879 | FRDP ("filter mode: %s\n", str_filter[rdp.filter_mode]); |
880 | } |
881 | |
882 | if (mask & 0x0000C000) // tlut mode |
883 | { |
884 | rdp.tlut_mode = (wxUint8)((rdp.othermode_h & 0x0000C000) >> 14); |
885 | FRDP ("tlut mode: %s\n", str_tlut[rdp.tlut_mode]); |
886 | } |
887 | |
888 | if (mask & 0x00300000) // cycle type |
889 | { |
890 | rdp.cycle_mode = (wxUint8)((rdp.othermode_h & 0x00300000) >> 20); |
891 | rdp.update |= UPDATE_ZBUF_ENABLED; |
892 | FRDP ("cycletype: %d\n", rdp.cycle_mode); |
893 | } |
894 | |
895 | if (mask & 0x00010000) // LOD enable |
896 | { |
897 | rdp.LOD_en = (rdp.othermode_h & 0x00010000) ? TRUE : FALSE; |
898 | FRDP ("LOD_en: %d\n", rdp.LOD_en); |
899 | } |
900 | |
901 | if (mask & 0x00080000) // Persp enable |
902 | { |
903 | if (rdp.persp_supported) |
904 | rdp.Persp_en = (rdp.othermode_h & 0x00080000) ? TRUE : FALSE; |
905 | FRDP ("Persp_en: %d\n", rdp.Persp_en); |
906 | } |
907 | |
908 | wxUint32 unk = mask & 0x0FFC60F0F; |
909 | if (unk) // unknown portions, LARGE |
910 | { |
911 | FRDP ("UNKNOWN PORTIONS: shift: %d, len: %d, unknowns: %08lx\n", shift, len, unk); |
912 | } |
913 | } |
914 | |
915 | static void uc0_setothermode_l() |
916 | { |
917 | LRDP("uc0:setothermode_l "); |
918 | |
919 | int shift, len; |
920 | if ((settings.ucode == ucode_F3DEX2) || (settings.ucode == ucode_CBFD)) |
921 | { |
922 | len = (rdp.cmd0 & 0xFF) + 1; |
923 | shift = 32 - ((rdp.cmd0 >> 8) & 0xFF) - len; |
924 | if (shift < 0) shift = 0; |
925 | } |
926 | else |
927 | { |
928 | len = rdp.cmd0 & 0xFF; |
929 | shift = (rdp.cmd0 >> 8) & 0xFF; |
930 | } |
931 | |
932 | wxUint32 mask = 0; |
933 | int i = len; |
934 | for (; i; i--) |
935 | mask = (mask << 1) | 1; |
936 | mask <<= shift; |
937 | |
938 | rdp.cmd1 &= mask; |
939 | rdp.othermode_l &= ~mask; |
940 | rdp.othermode_l |= rdp.cmd1; |
941 | |
942 | if (mask & 0x00000003) // alpha compare |
943 | { |
944 | rdp.acmp = rdp.othermode_l & 0x00000003; |
945 | FRDP ("alpha compare %s\n", ACmp[rdp.acmp]); |
946 | rdp.update |= UPDATE_ALPHA_COMPARE; |
947 | } |
948 | |
949 | if (mask & 0x00000004) // z-src selection |
950 | { |
951 | rdp.zsrc = (rdp.othermode_l & 0x00000004) >> 2; |
952 | FRDP ("z-src sel: %s\n", str_zs[rdp.zsrc]); |
953 | FRDP ("z-src sel: %08lx\n", rdp.zsrc); |
954 | rdp.update |= UPDATE_ZBUF_ENABLED; |
955 | } |
956 | |
957 | if (mask & 0xFFFFFFF8) // rendermode / blender bits |
958 | { |
959 | rdp.update |= UPDATE_FOG_ENABLED; //if blender has no fog bits, fog must be set off |
960 | rdp.render_mode_changed |= rdp.rm ^ rdp.othermode_l; |
961 | rdp.rm = rdp.othermode_l; |
962 | if (settings.flame_corona && (rdp.rm == 0x00504341)) //hack for flame's corona |
963 | rdp.othermode_l |= /*0x00000020 |*/ 0x00000010; |
964 | FRDP ("rendermode: %08lx\n", rdp.othermode_l); // just output whole othermode_l |
965 | } |
966 | |
967 | // there is not one setothermode_l that's not handled :) |
968 | } |
969 | |
970 | static void uc0_setgeometrymode() |
971 | { |
972 | rdp.geom_mode |= rdp.cmd1; |
973 | FRDP("uc0:setgeometrymode %08lx; result: %08lx\n", rdp.cmd1, rdp.geom_mode); |
974 | |
975 | if (rdp.cmd1 & 0x00000001) // Z-Buffer enable |
976 | { |
977 | if (!(rdp.flags & ZBUF_ENABLED)) |
978 | { |
979 | rdp.flags |= ZBUF_ENABLED; |
980 | rdp.update |= UPDATE_ZBUF_ENABLED; |
981 | } |
982 | } |
983 | if (rdp.cmd1 & 0x00001000) // Front culling |
984 | { |
985 | if (!(rdp.flags & CULL_FRONT)) |
986 | { |
987 | rdp.flags |= CULL_FRONT; |
988 | rdp.update |= UPDATE_CULL_MODE; |
989 | } |
990 | } |
991 | if (rdp.cmd1 & 0x00002000) // Back culling |
992 | { |
993 | if (!(rdp.flags & CULL_BACK)) |
994 | { |
995 | rdp.flags |= CULL_BACK; |
996 | rdp.update |= UPDATE_CULL_MODE; |
997 | } |
998 | } |
999 | |
1000 | //Added by Gonetz |
1001 | if (rdp.cmd1 & 0x00010000) // Fog enable |
1002 | { |
1003 | if (!(rdp.flags & FOG_ENABLED)) |
1004 | { |
1005 | rdp.flags |= FOG_ENABLED; |
1006 | rdp.update |= UPDATE_FOG_ENABLED; |
1007 | } |
1008 | } |
1009 | } |
1010 | |
1011 | static void uc0_cleargeometrymode() |
1012 | { |
1013 | FRDP("uc0:cleargeometrymode %08lx\n", rdp.cmd1); |
1014 | |
1015 | rdp.geom_mode &= (~rdp.cmd1); |
1016 | |
1017 | if (rdp.cmd1 & 0x00000001) // Z-Buffer enable |
1018 | { |
1019 | if (rdp.flags & ZBUF_ENABLED) |
1020 | { |
1021 | rdp.flags ^= ZBUF_ENABLED; |
1022 | rdp.update |= UPDATE_ZBUF_ENABLED; |
1023 | } |
1024 | } |
1025 | if (rdp.cmd1 & 0x00001000) // Front culling |
1026 | { |
1027 | if (rdp.flags & CULL_FRONT) |
1028 | { |
1029 | rdp.flags ^= CULL_FRONT; |
1030 | rdp.update |= UPDATE_CULL_MODE; |
1031 | } |
1032 | } |
1033 | if (rdp.cmd1 & 0x00002000) // Back culling |
1034 | { |
1035 | if (rdp.flags & CULL_BACK) |
1036 | { |
1037 | rdp.flags ^= CULL_BACK; |
1038 | rdp.update |= UPDATE_CULL_MODE; |
1039 | } |
1040 | } |
1041 | |
1042 | //Added by Gonetz |
1043 | if (rdp.cmd1 & 0x00010000) // Fog enable |
1044 | { |
1045 | if (rdp.flags & FOG_ENABLED) |
1046 | { |
1047 | rdp.flags ^= FOG_ENABLED; |
1048 | rdp.update |= UPDATE_FOG_ENABLED; |
1049 | } |
1050 | } |
1051 | } |
1052 | |
1053 | static void uc0_line3d() |
1054 | { |
1055 | Check_FrameSkip; |
1056 | |
1057 | wxUint32 v0 = ((rdp.cmd1 >> 16) & 0xff) / 10; |
1058 | wxUint32 v1 = ((rdp.cmd1 >> 8) & 0xff) / 10; |
1059 | wxUint16 width = (wxUint16)(rdp.cmd1 & 0xFF) + 3; |
1060 | |
1061 | VERTEX *v[3] = { |
1062 | &rdp.vtx[v1], |
1063 | &rdp.vtx[v0], |
1064 | &rdp.vtx[v0] |
1065 | }; |
1066 | wxUint32 cull_mode = (rdp.flags & CULLMASK) >> CULLSHIFT; |
1067 | rdp.flags |= CULLMASK; |
1068 | rdp.update |= UPDATE_CULL_MODE; |
1069 | rsp_tri1(v, width); |
1070 | rdp.flags ^= CULLMASK; |
1071 | rdp.flags |= cull_mode << CULLSHIFT; |
1072 | rdp.update |= UPDATE_CULL_MODE; |
1073 | |
1074 | FRDP("uc0:line3d v0:%d, v1:%d, width:%d\n", v0, v1, width); |
1075 | } |
1076 | |
1077 | static void uc0_tri4 () |
1078 | { |
1079 | Check_FrameSkip; |
1080 | |
1081 | // c0: 0000 0123, c1: 456789ab |
1082 | // becomes: 405 617 829 a3b |
1083 | |
1084 | LRDP("uc0:tri4"); |
1085 | FRDP(" #%d, #%d, #%d, #%d - %d, %d, %d - %d, %d, %d - %d, %d, %d - %d, %d, %d\n", rdp.tri_n, rdp.tri_n+1, rdp.tri_n+2, rdp.tri_n+3, |
1086 | (rdp.cmd1 >> 28) & 0xF, |
1087 | (rdp.cmd0 >> 12) & 0xF, |
1088 | (rdp.cmd1 >> 24) & 0xF, |
1089 | (rdp.cmd1 >> 20) & 0xF, |
1090 | (rdp.cmd0 >> 8) & 0xF, |
1091 | (rdp.cmd1 >> 16) & 0xF, |
1092 | (rdp.cmd1 >> 12) & 0xF, |
1093 | (rdp.cmd0 >> 4) & 0xF, |
1094 | (rdp.cmd1 >> 8) & 0xF, |
1095 | (rdp.cmd1 >> 4) & 0xF, |
1096 | (rdp.cmd0 >> 0) & 0xF, |
1097 | (rdp.cmd1 >> 0) & 0xF); |
1098 | |
1099 | VERTEX *v[12] = { |
1100 | &rdp.vtx[(rdp.cmd1 >> 28) & 0xF], |
1101 | &rdp.vtx[(rdp.cmd0 >> 12) & 0xF], |
1102 | &rdp.vtx[(rdp.cmd1 >> 24) & 0xF], |
1103 | &rdp.vtx[(rdp.cmd1 >> 20) & 0xF], |
1104 | &rdp.vtx[(rdp.cmd0 >> 8) & 0xF], |
1105 | &rdp.vtx[(rdp.cmd1 >> 16) & 0xF], |
1106 | &rdp.vtx[(rdp.cmd1 >> 12) & 0xF], |
1107 | &rdp.vtx[(rdp.cmd0 >> 4) & 0xF], |
1108 | &rdp.vtx[(rdp.cmd1 >> 8) & 0xF], |
1109 | &rdp.vtx[(rdp.cmd1 >> 4) & 0xF], |
1110 | &rdp.vtx[(rdp.cmd0 >> 0) & 0xF], |
1111 | &rdp.vtx[(rdp.cmd1 >> 0) & 0xF], |
1112 | }; |
1113 | |
1114 | int updated = 0; |
1115 | |
1116 | if (cull_tri(v)) |
1117 | rdp.tri_n ++; |
1118 | else |
1119 | { |
1120 | updated = 1; |
1121 | update (); |
1122 | |
1123 | draw_tri (v); |
1124 | rdp.tri_n ++; |
1125 | } |
1126 | |
1127 | if (cull_tri(v+3)) |
1128 | rdp.tri_n ++; |
1129 | else |
1130 | { |
1131 | if (!updated) |
1132 | { |
1133 | updated = 1; |
1134 | update (); |
1135 | } |
1136 | |
1137 | draw_tri (v+3); |
1138 | rdp.tri_n ++; |
1139 | } |
1140 | |
1141 | if (cull_tri(v+6)) |
1142 | rdp.tri_n ++; |
1143 | else |
1144 | { |
1145 | if (!updated) |
1146 | { |
1147 | updated = 1; |
1148 | update (); |
1149 | } |
1150 | |
1151 | draw_tri (v+6); |
1152 | rdp.tri_n ++; |
1153 | } |
1154 | |
1155 | if (cull_tri(v+9)) |
1156 | rdp.tri_n ++; |
1157 | else |
1158 | { |
1159 | if (!updated) |
1160 | { |
1161 | updated = 1; |
1162 | update (); |
1163 | } |
1164 | |
1165 | draw_tri (v+9); |
1166 | rdp.tri_n ++; |
1167 | } |
1168 | } |