Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / ucode00.h
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 }