Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / turbo3D.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 // Created by Gonetz, 2008
41 //
42 //****************************************************************
43
44 /******************Turbo3D microcode*************************/
45
46 struct t3dGlobState {
47   wxUint16              pad0;
48   wxUint16              perspNorm;
49   wxUint32              flag;
50   wxUint32              othermode0;
51   wxUint32              othermode1;
52   wxUint32              segBases[16];
53   /* the viewport to use */
54   short     vsacle1;
55   short     vsacle0;
56   short     vsacle3;
57   short     vsacle2;
58   short     vtrans1;
59   short     vtrans0;
60   short     vtrans3;
61   short     vtrans2;
62   wxUint32  rdpCmds;
63 };
64
65 struct t3dState {
66     wxUint32    renderState;    /* render state */
67     wxUint32    textureState;   /* texture state */
68     wxUint8     flag;
69     wxUint8     triCount;       /* how many tris? */
70     wxUint8     vtxV0;          /* where to load verts? */
71     wxUint8     vtxCount;       /* how many verts? */
72     wxUint32    rdpCmds;        /* ptr (segment address) to RDP DL */
73     wxUint32    othermode0;
74     wxUint32    othermode1;
75 };
76
77
78 struct t3dTriN{
79    wxUint8      flag, v2, v1, v0;       /* flag is which one for flat shade */
80 };
81
82
83 static void t3dProcessRDP(wxUint32 a)
84 {
85   if (a)
86   {
87     rdp.LLE = 1;
88     rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a++];
89     rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[a++];
90     while (rdp.cmd0 + rdp.cmd1) {
91       gfx_instruction[0][rdp.cmd0>>24] ();
92       rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a++];
93       rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[a++];
94       wxUint32 cmd = rdp.cmd0>>24;
95       if (cmd == 0xE4 || cmd == 0xE5)
96       {
97         rdp.cmd2 = ((wxUint32*)gfx.RDRAM)[a++];
98         rdp.cmd3 = ((wxUint32*)gfx.RDRAM)[a++];
99       }
100     }
101     rdp.LLE = 0;
102   }
103 }
104
105 static void t3dLoadGlobState(wxUint32 pgstate)
106 {
107   t3dGlobState *gstate = (t3dGlobState*)&gfx.RDRAM[segoffset(pgstate)];
108   FRDP ("Global state. pad0: %04lx, perspNorm: %04lx, flag: %08lx\n", gstate->pad0, gstate->perspNorm, gstate->flag);
109   rdp.cmd0 = gstate->othermode0;
110   rdp.cmd1 = gstate->othermode1;
111   rdp_setothermode();
112
113   for (int s = 0; s < 16; s++)
114   {
115     rdp.segment[s] = gstate->segBases[s];
116     FRDP ("segment: %08lx -> seg%d\n", rdp.segment[s], s);
117   }
118
119   short scale_x = gstate->vsacle0 / 4;
120   short scale_y = gstate->vsacle1 / 4;;
121   short scale_z = gstate->vsacle2;
122   short trans_x = gstate->vtrans0 / 4;
123   short trans_y = gstate->vtrans1 / 4;
124   short trans_z = gstate->vtrans2;
125   rdp.view_scale[0] = scale_x * rdp.scale_x;
126   rdp.view_scale[1] = -scale_y * rdp.scale_y;
127   rdp.view_scale[2] = 32.0f * scale_z;
128   rdp.view_trans[0] = trans_x * rdp.scale_x;
129   rdp.view_trans[1] = trans_y * rdp.scale_y;
130   rdp.view_trans[2] = 32.0f * trans_z;
131   rdp.update |= UPDATE_VIEWPORT;
132   FRDP ("viewport scale(%d, %d, %d), trans(%d, %d, %d)\n", scale_x, scale_y, scale_z,
133     trans_x, trans_y, trans_z);
134
135   t3dProcessRDP(segoffset(gstate->rdpCmds) >> 2);
136 }
137
138 static void t3d_vertex(wxUint32 addr, wxUint32 v0, wxUint32 n)
139 {
140     float x, y, z;
141
142     rdp.v0 = v0; // Current vertex
143     rdp.vn = n; // Number of vertices to copy
144     n <<= 4;
145
146     for (wxUint32 i=0; i < n; i+=16)
147     {
148       VERTEX *v = &rdp.vtx[v0 + (i>>4)];
149       x   = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 0)^1];
150       y   = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 1)^1];
151       z   = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 2)^1];
152       v->flags  = ((wxUint16*)gfx.RDRAM)[(((addr+i) >> 1) + 3)^1];
153       v->ou   = 2.0f * (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 4)^1];
154       v->ov   = 2.0f * (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 5)^1];
155       v->uv_scaled = 0;
156       v->r = ((wxUint8*)gfx.RDRAM)[(addr+i + 12)^3];
157       v->g = ((wxUint8*)gfx.RDRAM)[(addr+i + 13)^3];
158       v->b = ((wxUint8*)gfx.RDRAM)[(addr+i + 14)^3];
159       v->a    = ((wxUint8*)gfx.RDRAM)[(addr+i + 15)^3];
160
161       v->x = x*rdp.combined[0][0] + y*rdp.combined[1][0] + z*rdp.combined[2][0] + rdp.combined[3][0];
162       v->y = x*rdp.combined[0][1] + y*rdp.combined[1][1] + z*rdp.combined[2][1] + rdp.combined[3][1];
163       v->z = x*rdp.combined[0][2] + y*rdp.combined[1][2] + z*rdp.combined[2][2] + rdp.combined[3][2];
164       v->w = x*rdp.combined[0][3] + y*rdp.combined[1][3] + z*rdp.combined[2][3] + rdp.combined[3][3];
165
166       if (fabs(v->w) < 0.001) v->w = 0.001f;
167       v->oow = 1.0f / v->w;
168       v->x_w = v->x * v->oow;
169       v->y_w = v->y * v->oow;
170       v->z_w = v->z * v->oow;
171
172       v->uv_calculated = 0xFFFFFFFF;
173       v->screen_translated = 0;
174       v->shade_mod = 0;
175
176       v->scr_off = 0;
177       if (v->x < -v->w) v->scr_off |= 1;
178       if (v->x > v->w) v->scr_off |= 2;
179       if (v->y < -v->w) v->scr_off |= 4;
180       if (v->y > v->w) v->scr_off |= 8;
181       if (v->w < 0.1f) v->scr_off |= 16;
182 #ifdef EXTREME_LOGGING
183     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);
184 #endif
185     }
186 }
187
188 static void t3dLoadObject(wxUint32 pstate, wxUint32 pvtx, wxUint32 ptri)
189 {
190   LRDP("Loading Turbo3D object\n");
191   t3dState *ostate = (t3dState*)&gfx.RDRAM[segoffset(pstate)];
192   rdp.cur_tile = (ostate->textureState)&7;
193   FRDP("tile: %d\n", rdp.cur_tile);
194   if (rdp.tiles[rdp.cur_tile].s_scale < 0.001f)
195     rdp.tiles[rdp.cur_tile].s_scale = 0.015625;
196   if (rdp.tiles[rdp.cur_tile].t_scale < 0.001f)
197     rdp.tiles[rdp.cur_tile].t_scale = 0.015625;
198
199 #ifdef EXTREME_LOGGING
200   FRDP("renderState: %08lx, textureState: %08lx, othermode0: %08lx, othermode1: %08lx, rdpCmds: %08lx, triCount : %d, v0: %d, vn: %d\n", ostate->renderState, ostate->textureState,
201      ostate->othermode0, ostate->othermode1, ostate->rdpCmds, ostate->triCount, ostate->vtxV0, ostate->vtxCount);
202 #endif
203
204   rdp.cmd0 = ostate->othermode0;
205   rdp.cmd1 = ostate->othermode1;
206   rdp_setothermode();
207
208   rdp.cmd1 = ostate->renderState;
209   uc0_setgeometrymode();
210
211   if (!(ostate->flag&1)) //load matrix
212   {
213     wxUint32 addr = segoffset(pstate+sizeof(t3dState)) & BMASK;
214     load_matrix(rdp.combined, addr);
215 #ifdef EXTREME_LOGGING
216       FRDP ("{%f,%f,%f,%f}\n", rdp.combined[0][0], rdp.combined[0][1], rdp.combined[0][2], rdp.combined[0][3]);
217       FRDP ("{%f,%f,%f,%f}\n", rdp.combined[1][0], rdp.combined[1][1], rdp.combined[1][2], rdp.combined[1][3]);
218       FRDP ("{%f,%f,%f,%f}\n", rdp.combined[2][0], rdp.combined[2][1], rdp.combined[2][2], rdp.combined[2][3]);
219       FRDP ("{%f,%f,%f,%f}\n", rdp.combined[3][0], rdp.combined[3][1], rdp.combined[3][2], rdp.combined[3][3]);
220 #endif
221   }
222
223   rdp.geom_mode &= ~0x00020000;
224   rdp.geom_mode |= 0x00000200;
225   if (pvtx) //load vtx
226     t3d_vertex(segoffset(pvtx) & BMASK, ostate->vtxV0, ostate->vtxCount);
227
228   t3dProcessRDP(segoffset(ostate->rdpCmds) >> 2);
229
230   if (ptri)
231   {
232     update ();
233     wxUint32 a = segoffset(ptri);
234     for (int t=0; t < ostate->triCount; t++)
235     {
236       t3dTriN * tri = (t3dTriN*)&gfx.RDRAM[a];
237       a += 4;
238       FRDP("tri #%d - %d, %d, %d\n", t, tri->v0, tri->v1, tri->v2);
239       VERTEX *v[3] = { &rdp.vtx[tri->v0], &rdp.vtx[tri->v1], &rdp.vtx[tri->v2] };
240       if (cull_tri(v))
241         rdp.tri_n ++;
242       else
243       {
244         draw_tri (v);
245         rdp.tri_n ++;
246       }
247     }
248   }
249 }
250
251 static void Turbo3D()
252 {
253   LRDP("Start Turbo3D microcode\n");
254   settings.ucode = ucode_Fast3D;
255   wxUint32 a = 0, pgstate = 0, pstate = 0, pvtx = 0, ptri = 0;
256   do {
257     a = rdp.pc[rdp.pc_i] & BMASK;
258     pgstate = ((wxUint32*)gfx.RDRAM)[a>>2];
259     pstate = ((wxUint32*)gfx.RDRAM)[(a>>2)+1];
260     pvtx = ((wxUint32*)gfx.RDRAM)[(a>>2)+2];
261     ptri = ((wxUint32*)gfx.RDRAM)[(a>>2)+3];
262     FRDP("GlobalState: %08lx, Object: %08lx, Vertices: %08lx, Triangles: %08lx\n", pgstate, pstate, pvtx, ptri);
263     if (!pstate)
264     {
265       rdp.halt = 1;
266       break;
267     }
268     if (pgstate)
269       t3dLoadGlobState(pgstate);
270     t3dLoadObject(pstate, pvtx, ptri);
271    // Go to the next instruction
272     rdp.pc[rdp.pc_i] += 16;
273  } while (pstate);
274 // rdp_fullsync();
275  settings.ucode = ucode_Turbo3d;
276 }