GLES2N64: Some fixes from mupen64plus-ae team
[mupen64plus-pandora.git] / source / gles2n64 / src / gSP.cpp
1 #include <math.h>
2 #include <stdlib.h>
3
4 #include "Common.h"
5 #include "gles2N64.h"
6 #include "Debug.h"
7 #include "Types.h"
8 #include "RSP.h"
9 #include "GBI.h"
10 #include "gSP.h"
11 #include "gDP.h"
12 #include "3DMath.h"
13 #include "OpenGL.h"
14 #include "CRC.h"
15 #include <string.h>
16 #include "convert.h"
17 #include "S2DEX.h"
18 #include "VI.h"
19 #include "DepthBuffer.h"
20 #include "Config.h"
21
22 //Note: 0xC0 is used by 1080 alot, its an unknown command.
23
24 #ifdef DEBUG
25 extern u32 uc_crc, uc_dcrc;
26 extern char uc_str[256];
27 #endif
28
29 void gSPCombineMatrices();
30
31 //#ifdef __TRIBUFFER_OPT
32 void __indexmap_init()
33 {
34     memset(OGL.triangles.indexmapinv, 0xFF, VERTBUFF_SIZE*sizeof(u32));
35     for(int i=0;i<INDEXMAP_SIZE;i++)
36     {
37         OGL.triangles.indexmap[i] = i;
38         //OGL.triangles.indexmapinv[i] = i;
39     }
40
41     OGL.triangles.indexmap_prev = -1;
42     OGL.triangles.indexmap_nomap = 0;
43 }
44
45 void __indexmap_clear()
46 {
47     memset(OGL.triangles.indexmapinv, 0xFF, VERTBUFF_SIZE * sizeof(u32));
48     for(int i=0;i<INDEXMAP_SIZE;i++)
49         OGL.triangles.indexmapinv[OGL.triangles.indexmap[i]] = i;
50 }
51
52 u32 __indexmap_findunused(u32 num)
53 {
54     u32 c = 0;
55     u32 i = min(OGL.triangles.indexmap_prev+1, VERTBUFF_SIZE-1);
56     u32 n = 0;
57     while(n < VERTBUFF_SIZE)
58     {
59         c = (OGL.triangles.indexmapinv[i] == 0xFFFFFFFF) ? (c+1) : 0;
60         if ((c == num) && (i < (VERTBUFF_SIZE - num)))
61         {
62             break;
63         }
64         i=i+1;
65         if (i >= VERTBUFF_SIZE) {i=0; c=0;}
66         n++;
67     }
68     return (c == num) ? (i-num+1) : (0xFFFFFFFF);
69 }
70
71 void __indexmap_undomap()
72 {
73     SPVertex tmp[INDEXMAP_SIZE];
74     memset(OGL.triangles.indexmapinv, 0xFF, VERTBUFF_SIZE * sizeof(u32));
75
76     for(int i=0;i<INDEXMAP_SIZE;i++)
77     {
78         u32 ind = OGL.triangles.indexmap[i];
79         tmp[i] = OGL.triangles.vertices[ind];
80         OGL.triangles.indexmap[i] = i;
81         OGL.triangles.indexmapinv[i] = i;
82     }
83
84     memcpy(OGL.triangles.vertices, tmp, INDEXMAP_SIZE * sizeof(SPVertex));
85     OGL.triangles.indexmap_nomap = 1;
86 }
87
88 u32 __indexmap_getnew(u32 index, u32 num)
89 {
90     u32 ind;
91
92     //test to see if unmapped
93     u32 unmapped = 1;
94     for(int i=0;i<num;i++)
95     {
96         if (OGL.triangles.indexmap[i]!=0xFFFFFFFF)
97         {
98             unmapped = 0;
99             break;
100         }
101
102     }
103
104     if (unmapped)
105     {
106         ind = index;
107     }
108     else
109     {
110         ind = __indexmap_findunused(num);
111
112         //no more room in buffer....
113         if (ind > VERTBUFF_SIZE)
114         {
115             OGL_DrawTriangles();
116             ind = __indexmap_findunused(num);
117
118             //OK the indices are spread so sparsely, we cannot find a num element block.
119             if (ind > VERTBUFF_SIZE)
120             {
121                 __indexmap_undomap();
122                 ind = __indexmap_findunused(num);
123                 if (ind > VERTBUFF_SIZE)
124                 {
125                     LOG(LOG_ERROR, "Could not allocate %i indices\n", num);
126
127                     LOG(LOG_VERBOSE, "indexmap=[");
128                     for(int i=0;i<INDEXMAP_SIZE;i++)
129                         LOG(LOG_VERBOSE, "%i,", OGL.triangles.indexmap[i]);
130                     LOG(LOG_VERBOSE, "]\n");
131
132                     LOG(LOG_VERBOSE, "indexmapinv=[");
133                     for(int i=0;i<VERTBUFF_SIZE;i++)
134                         LOG(LOG_VERBOSE, "%i,", OGL.triangles.indexmapinv[i]);
135                     LOG(LOG_VERBOSE, "]\n");
136                 }
137                 return ind;
138             }
139         }
140     }
141
142     for(int i=0;i<num;i++)
143     {
144         OGL.triangles.indexmap[index+i] = ind+i;
145         OGL.triangles.indexmapinv[ind+i] = index+i;
146     }
147
148     OGL.triangles.indexmap_prev = ind+num-1;
149     OGL.triangles.indexmap_nomap = 0;
150
151     return ind;
152 }
153 //#endif
154
155 void gSPTriangle(s32 v0, s32 v1, s32 v2)
156 {
157     if ((v0 < INDEXMAP_SIZE) && (v1 < INDEXMAP_SIZE) && (v2 < INDEXMAP_SIZE))
158     {
159
160 #ifdef __TRIBUFFER_OPT
161         v0 = OGL.triangles.indexmap[v0];
162         v1 = OGL.triangles.indexmap[v1];
163         v2 = OGL.triangles.indexmap[v2];
164 #endif
165
166 #if 0
167         // Don't bother with triangles completely outside clipping frustrum
168         if (config.enableClipping)
169         {
170             if (OGL.triangles.vertices[v0].clip & OGL.triangles.vertices[v1].clip & OGL.triangles.vertices[v2].clip)
171             {
172                 return;
173             }
174         }
175 #endif
176
177         OGL_AddTriangle(v0, v1, v2);
178
179     }
180
181     if (depthBuffer.current) depthBuffer.current->cleared = FALSE;
182     gDP.colorImage.changed = TRUE;
183     gDP.colorImage.height = (unsigned int)(max( gDP.colorImage.height, gDP.scissor.lry ));
184 }
185
186 void gSP1Triangle( const s32 v0, const s32 v1, const s32 v2)
187 {
188     gSPTriangle( v0, v1, v2);
189     gSPFlushTriangles();
190 }
191
192 void gSP2Triangles(const s32 v00, const s32 v01, const s32 v02, const s32 flag0,
193                     const s32 v10, const s32 v11, const s32 v12, const s32 flag1 )
194 {
195     gSPTriangle( v00, v01, v02);
196     gSPTriangle( v10, v11, v12);
197     gSPFlushTriangles();
198 }
199
200 void gSP4Triangles(const s32 v00, const s32 v01, const s32 v02,
201                     const s32 v10, const s32 v11, const s32 v12,
202                     const s32 v20, const s32 v21, const s32 v22,
203                     const s32 v30, const s32 v31, const s32 v32 )
204 {
205     gSPTriangle(v00, v01, v02);
206     gSPTriangle(v10, v11, v12);
207     gSPTriangle(v20, v21, v22);
208     gSPTriangle(v30, v31, v32);
209     gSPFlushTriangles();
210 }
211
212
213 gSPInfo gSP;
214
215 f32 identityMatrix[4][4] =
216 {
217     { 1.0f, 0.0f, 0.0f, 0.0f },
218     { 0.0f, 1.0f, 0.0f, 0.0f },
219     { 0.0f, 0.0f, 1.0f, 0.0f },
220     { 0.0f, 0.0f, 0.0f, 1.0f }
221 };
222
223 #ifdef __VEC4_OPT
224 static void gSPTransformVertex4_default(u32 v, float mtx[4][4])
225 {
226     float x, y, z, w;
227     int i;
228     for(i = 0; i < 4; i++)
229     {
230         x = OGL.triangles.vertices[v+i].x;
231         y = OGL.triangles.vertices[v+i].y;
232         z = OGL.triangles.vertices[v+i].z;
233         w = OGL.triangles.vertices[v+i].w;
234         OGL.triangles.vertices[v+i].x = x * mtx[0][0] + y * mtx[1][0] + z * mtx[2][0] + mtx[3][0];
235         OGL.triangles.vertices[v+i].y = x * mtx[0][1] + y * mtx[1][1] + z * mtx[2][1] + mtx[3][1];
236         OGL.triangles.vertices[v+i].z = x * mtx[0][2] + y * mtx[1][2] + z * mtx[2][2] + mtx[3][2];
237         OGL.triangles.vertices[v+i].w = x * mtx[0][3] + y * mtx[1][3] + z * mtx[2][3] + mtx[3][3];
238     }
239 }
240
241 void gSPClipVertex4(u32 v)
242 {
243     int i;
244     for(i = 0; i < 4; i++){
245         SPVertex *vtx = &OGL.triangles.vertices[v+i];
246         vtx->clip = 0;
247         if (vtx->x > +vtx->w)   vtx->clip |= CLIP_POSX;
248         if (vtx->x < -vtx->w)   vtx->clip |= CLIP_NEGX;
249         if (vtx->y > +vtx->w)   vtx->clip |= CLIP_POSY;
250         if (vtx->y < -vtx->w)   vtx->clip |= CLIP_NEGY;
251     }
252 }
253
254 static void gSPTransformNormal4_default(u32 v, float mtx[4][4])
255 {
256     float len, x, y, z;
257     int i;
258     for(i = 0; i < 4; i++){
259         x = OGL.triangles.vertices[v+i].nx;
260         y = OGL.triangles.vertices[v+i].ny;
261         z = OGL.triangles.vertices[v+i].nz;
262
263         OGL.triangles.vertices[v+i].nx = mtx[0][0]*x + mtx[1][0]*y + mtx[2][0]*z;
264         OGL.triangles.vertices[v+i].ny = mtx[0][1]*x + mtx[1][1]*y + mtx[2][1]*z;
265         OGL.triangles.vertices[v+i].nz = mtx[0][2]*x + mtx[1][2]*y + mtx[2][2]*z;
266         len =   OGL.triangles.vertices[v+i].nx*OGL.triangles.vertices[v+i].nx +
267                 OGL.triangles.vertices[v+i].ny*OGL.triangles.vertices[v+i].ny +
268                 OGL.triangles.vertices[v+i].nz*OGL.triangles.vertices[v+i].nz;
269         if (len != 0.0)
270         {
271             len = sqrtf(len);
272             OGL.triangles.vertices[v+i].nx /= len;
273             OGL.triangles.vertices[v+i].ny /= len;
274             OGL.triangles.vertices[v+i].nz /= len;
275         }
276     }
277 }
278
279 static void gSPLightVertex4_default(u32 v)
280 {
281     gSPTransformNormal4(v, gSP.matrix.modelView[gSP.matrix.modelViewi]);
282     for(int j = 0; j < 4; j++)
283     {
284         f32 r,g,b;
285         r = gSP.lights[gSP.numLights].r;
286         g = gSP.lights[gSP.numLights].g;
287         b = gSP.lights[gSP.numLights].b;
288
289         for (int i = 0; i < gSP.numLights; i++)
290         {
291             f32 intensity = DotProduct( &OGL.triangles.vertices[v+j].nx, &gSP.lights[i].x );
292             if (intensity < 0.0f) intensity = 0.0f;
293 /*
294 // paulscode, cause of the shader bug (not applying intensity to correct varriables)
295             OGL.triangles.vertices[v+j].r += gSP.lights[i].r * intensity;
296             OGL.triangles.vertices[v+j].g += gSP.lights[i].g * intensity;
297             OGL.triangles.vertices[v+j].b += gSP.lights[i].b * intensity;
298 */
299 //// paulscode, shader bug-fix:
300             r += gSP.lights[i].r * intensity;
301             g += gSP.lights[i].g * intensity;
302             b += gSP.lights[i].b * intensity;
303 ////
304         }
305         OGL.triangles.vertices[v+j].r = min(1.0f, r);
306         OGL.triangles.vertices[v+j].g = min(1.0f, g);
307         OGL.triangles.vertices[v+j].b = min(1.0f, b);
308     }
309 }
310
311 static void gSPBillboardVertex4_default(u32 v)
312 {
313
314     int i = 0;
315 #ifdef __TRIBUFFER_OPT
316     i = OGL.triangles.indexmap[0];
317 #endif
318
319     OGL.triangles.vertices[v].x += OGL.triangles.vertices[i].x;
320     OGL.triangles.vertices[v].y += OGL.triangles.vertices[i].y;
321     OGL.triangles.vertices[v].z += OGL.triangles.vertices[i].z;
322     OGL.triangles.vertices[v].w += OGL.triangles.vertices[i].w;
323     OGL.triangles.vertices[v+1].x += OGL.triangles.vertices[i].x;
324     OGL.triangles.vertices[v+1].y += OGL.triangles.vertices[i].y;
325     OGL.triangles.vertices[v+1].z += OGL.triangles.vertices[i].z;
326     OGL.triangles.vertices[v+1].w += OGL.triangles.vertices[i].w;
327     OGL.triangles.vertices[v+2].x += OGL.triangles.vertices[i].x;
328     OGL.triangles.vertices[v+2].y += OGL.triangles.vertices[i].y;
329     OGL.triangles.vertices[v+2].z += OGL.triangles.vertices[i].z;
330     OGL.triangles.vertices[v+2].w += OGL.triangles.vertices[i].w;
331     OGL.triangles.vertices[v+3].x += OGL.triangles.vertices[i].x;
332     OGL.triangles.vertices[v+3].y += OGL.triangles.vertices[i].y;
333     OGL.triangles.vertices[v+3].z += OGL.triangles.vertices[i].z;
334     OGL.triangles.vertices[v+3].w += OGL.triangles.vertices[i].w;
335 }
336
337 void gSPProcessVertex4(u32 v)
338 {
339     if (gSP.changed & CHANGED_MATRIX)
340         gSPCombineMatrices();
341
342     gSPTransformVertex4(v, gSP.matrix.combined );
343
344     if (config.screen.flipVertical)
345     {
346         OGL.triangles.vertices[v+0].y = -OGL.triangles.vertices[v+0].y;
347         OGL.triangles.vertices[v+1].y = -OGL.triangles.vertices[v+1].y;
348         OGL.triangles.vertices[v+2].y = -OGL.triangles.vertices[v+2].y;
349         OGL.triangles.vertices[v+3].y = -OGL.triangles.vertices[v+3].y;
350     }
351
352     if (gDP.otherMode.depthSource)
353     {
354         OGL.triangles.vertices[v+0].z = gDP.primDepth.z * OGL.triangles.vertices[v+0].w;
355         OGL.triangles.vertices[v+1].z = gDP.primDepth.z * OGL.triangles.vertices[v+1].w;
356         OGL.triangles.vertices[v+2].z = gDP.primDepth.z * OGL.triangles.vertices[v+2].w;
357         OGL.triangles.vertices[v+3].z = gDP.primDepth.z * OGL.triangles.vertices[v+3].w;
358     }
359
360     if (gSP.matrix.billboard)
361         gSPBillboardVertex4(v);
362
363     if (!(gSP.geometryMode & G_ZBUFFER))
364     {
365         OGL.triangles.vertices[v].z = -OGL.triangles.vertices[v].w;
366         OGL.triangles.vertices[v+1].z = -OGL.triangles.vertices[v+1].w;
367         OGL.triangles.vertices[v+2].z = -OGL.triangles.vertices[v+2].w;
368         OGL.triangles.vertices[v+3].z = -OGL.triangles.vertices[v+3].w;
369     }
370
371     if (gSP.geometryMode & G_LIGHTING)
372     {
373         if (config.enableLighting)
374         {
375             gSPLightVertex4(v);
376         }
377         else
378         {
379             OGL.triangles.vertices[v].r = 1.0f;
380             OGL.triangles.vertices[v].g = 1.0f;
381             OGL.triangles.vertices[v].b = 1.0f;
382             OGL.triangles.vertices[v+1].r = 1.0f;
383             OGL.triangles.vertices[v+1].g = 1.0f;
384             OGL.triangles.vertices[v+1].b = 1.0f;
385             OGL.triangles.vertices[v+2].r = 1.0f;
386             OGL.triangles.vertices[v+2].g = 1.0f;
387             OGL.triangles.vertices[v+2].b = 1.0f;
388             OGL.triangles.vertices[v+3].r = 1.0f;
389             OGL.triangles.vertices[v+3].g = 1.0f;
390             OGL.triangles.vertices[v+3].b = 1.0f;
391         }
392
393         if (gSP.geometryMode & G_TEXTURE_GEN)
394         {
395             gSPTransformNormal4(v, gSP.matrix.projection);
396
397             if (gSP.geometryMode & G_TEXTURE_GEN_LINEAR)
398             {
399                 OGL.triangles.vertices[v].s = acosf(OGL.triangles.vertices[v].nx) * 325.94931f;
400                 OGL.triangles.vertices[v].t = acosf(OGL.triangles.vertices[v].ny) * 325.94931f;
401                 OGL.triangles.vertices[v+1].s = acosf(OGL.triangles.vertices[v+1].nx) * 325.94931f;
402                 OGL.triangles.vertices[v+1].t = acosf(OGL.triangles.vertices[v+1].ny) * 325.94931f;
403                 OGL.triangles.vertices[v+2].s = acosf(OGL.triangles.vertices[v+2].nx) * 325.94931f;
404                 OGL.triangles.vertices[v+2].t = acosf(OGL.triangles.vertices[v+2].ny) * 325.94931f;
405                 OGL.triangles.vertices[v+3].s = acosf(OGL.triangles.vertices[v+3].nx) * 325.94931f;
406                 OGL.triangles.vertices[v+3].t = acosf(OGL.triangles.vertices[v+3].ny) * 325.94931f;
407             }
408             else // G_TEXTURE_GEN
409             {
410                 OGL.triangles.vertices[v].s = (OGL.triangles.vertices[v].nx + 1.0f) * 512.0f;
411                 OGL.triangles.vertices[v].t = (OGL.triangles.vertices[v].ny + 1.0f) * 512.0f;
412                 OGL.triangles.vertices[v+1].s = (OGL.triangles.vertices[v+1].nx + 1.0f) * 512.0f;
413                 OGL.triangles.vertices[v+1].t = (OGL.triangles.vertices[v+1].ny + 1.0f) * 512.0f;
414                 OGL.triangles.vertices[v+2].s = (OGL.triangles.vertices[v+2].nx + 1.0f) * 512.0f;
415                 OGL.triangles.vertices[v+2].t = (OGL.triangles.vertices[v+2].ny + 1.0f) * 512.0f;
416                 OGL.triangles.vertices[v+3].s = (OGL.triangles.vertices[v+3].nx + 1.0f) * 512.0f;
417                 OGL.triangles.vertices[v+3].t = (OGL.triangles.vertices[v+3].ny + 1.0f) * 512.0f;
418             }
419         }
420     }
421
422     if (config.enableClipping) gSPClipVertex4(v);
423 }
424 #endif
425
426 void gSPClipVertex(u32 v)
427 {
428     SPVertex *vtx = &OGL.triangles.vertices[v];
429     vtx->clip = 0;
430     if (vtx->x > +vtx->w)   vtx->clip |= CLIP_POSX;
431     if (vtx->x < -vtx->w)   vtx->clip |= CLIP_NEGX;
432     if (vtx->y > +vtx->w)   vtx->clip |= CLIP_POSY;
433     if (vtx->y < -vtx->w)   vtx->clip |= CLIP_NEGY;
434     //if (vtx->w < 0.1f)      vtx->clip |= CLIP_NEGW;
435 }
436
437 static void gSPTransformVertex_default(float vtx[4], float mtx[4][4])
438 {
439     float x, y, z, w;
440     x = vtx[0];
441     y = vtx[1];
442     z = vtx[2];
443     w = vtx[3];
444
445     vtx[0] = x * mtx[0][0] + y * mtx[1][0] + z * mtx[2][0] + mtx[3][0];
446     vtx[1] = x * mtx[0][1] + y * mtx[1][1] + z * mtx[2][1] + mtx[3][1];
447     vtx[2] = x * mtx[0][2] + y * mtx[1][2] + z * mtx[2][2] + mtx[3][2];
448     vtx[3] = x * mtx[0][3] + y * mtx[1][3] + z * mtx[2][3] + mtx[3][3];
449 }
450
451 static void gSPLightVertex_default(u32 v)
452 {
453     TransformVectorNormalize( &OGL.triangles.vertices[v].nx, gSP.matrix.modelView[gSP.matrix.modelViewi] );
454
455     f32 r, g, b;
456     r = gSP.lights[gSP.numLights].r;
457     g = gSP.lights[gSP.numLights].g;
458     b = gSP.lights[gSP.numLights].b;
459     for (int i = 0; i < gSP.numLights; i++)
460     {
461         f32 intensity = DotProduct( &OGL.triangles.vertices[v].nx, &gSP.lights[i].x );
462         if (intensity < 0.0f) intensity = 0.0f;
463         r += gSP.lights[i].r * intensity;
464         g += gSP.lights[i].g * intensity;
465         b += gSP.lights[i].b * intensity;
466     }
467     OGL.triangles.vertices[v].r = min(1.0, r);
468     OGL.triangles.vertices[v].g = min(1.0, g);
469     OGL.triangles.vertices[v].b = min(1.0, b);
470 }
471
472 static void gSPBillboardVertex_default(u32 v, u32 i)
473 {
474     OGL.triangles.vertices[v].x += OGL.triangles.vertices[i].x;
475     OGL.triangles.vertices[v].y += OGL.triangles.vertices[i].y;
476     OGL.triangles.vertices[v].z += OGL.triangles.vertices[i].z;
477     OGL.triangles.vertices[v].w += OGL.triangles.vertices[i].w;
478 }
479
480 void gSPCombineMatrices()
481 {
482     MultMatrix(gSP.matrix.projection, gSP.matrix.modelView[gSP.matrix.modelViewi], gSP.matrix.combined);
483     gSP.changed &= ~CHANGED_MATRIX;
484 }
485
486 void gSPProcessVertex( u32 v )
487 {
488     f32 intensity;
489     f32 r, g, b;
490
491     if (gSP.changed & CHANGED_MATRIX)
492         gSPCombineMatrices();
493
494     gSPTransformVertex( &OGL.triangles.vertices[v].x, gSP.matrix.combined );
495
496     if (config.screen.flipVertical)
497     {
498         OGL.triangles.vertices[v].y = -OGL.triangles.vertices[v].y;
499     }
500
501     if (gDP.otherMode.depthSource)
502     {
503         OGL.triangles.vertices[v].z = gDP.primDepth.z * OGL.triangles.vertices[v].w;
504     }
505
506     if (gSP.matrix.billboard)
507     {
508         int i = 0;
509 #ifdef __TRIBUFFER_OPT
510         i = OGL.triangles.indexmap[0];
511 #endif
512
513         gSPBillboardVertex(v, i);
514     }
515
516     if (!(gSP.geometryMode & G_ZBUFFER))
517     {
518         OGL.triangles.vertices[v].z = -OGL.triangles.vertices[v].w;
519     }
520
521     if (config.enableClipping)
522         gSPClipVertex(v);
523
524     if (gSP.geometryMode & G_LIGHTING)
525     {
526         if (config.enableLighting)
527         {
528             gSPLightVertex(v);
529         }
530         else
531         {
532             OGL.triangles.vertices[v].r = 1.0f;
533             OGL.triangles.vertices[v].g = 1.0f;
534             OGL.triangles.vertices[v].b = 1.0f;
535         }
536
537         if (gSP.geometryMode & G_TEXTURE_GEN)
538         {
539             TransformVectorNormalize(&OGL.triangles.vertices[v].nx, gSP.matrix.projection);
540
541             if (gSP.geometryMode & G_TEXTURE_GEN_LINEAR)
542             {
543                 OGL.triangles.vertices[v].s = acosf(OGL.triangles.vertices[v].nx) * 325.94931f;
544                 OGL.triangles.vertices[v].t = acosf(OGL.triangles.vertices[v].ny) * 325.94931f;
545             }
546             else // G_TEXTURE_GEN
547             {
548                 OGL.triangles.vertices[v].s = (OGL.triangles.vertices[v].nx + 1.0f) * 512.0f;
549                 OGL.triangles.vertices[v].t = (OGL.triangles.vertices[v].ny + 1.0f) * 512.0f;
550             }
551         }
552     }
553 }
554
555
556 void gSPLoadUcodeEx( u32 uc_start, u32 uc_dstart, u16 uc_dsize )
557 {
558     RSP.PCi = 0;
559     gSP.matrix.modelViewi = 0;
560     gSP.changed |= CHANGED_MATRIX;
561     gSP.status[0] = gSP.status[1] = gSP.status[2] = gSP.status[3] = 0;
562
563     if ((((uc_start & 0x1FFFFFFF) + 4096) > RDRAMSize) || (((uc_dstart & 0x1FFFFFFF) + uc_dsize) > RDRAMSize))
564     {
565         return;
566     }
567
568     MicrocodeInfo *ucode = GBI_DetectMicrocode( uc_start, uc_dstart, uc_dsize );
569
570     if (ucode->type != 0xFFFFFFFF)
571         last_good_ucode = ucode->type;
572
573     if (ucode->type != NONE)
574     {
575         GBI_MakeCurrent( ucode );
576     }
577     else
578     {
579         LOG(LOG_WARNING, "Unknown Ucode\n");
580     }
581 }
582
583 void gSPNoOp()
584 {
585     gSPFlushTriangles();
586 }
587
588 void gSPTriangleUnknown()
589 {
590 #ifdef __TRIBUFFER_OPT
591     gSPFlushTriangles();
592 #endif
593 }
594
595 void gSPMatrix( u32 matrix, u8 param )
596 {
597 #ifdef __TRIBUFFER_OPT
598     gSPFlushTriangles();
599 #endif
600
601     f32 mtx[4][4];
602     u32 address = RSP_SegmentToPhysical( matrix );
603
604     if (address + 64 > RDRAMSize)
605     {
606         return;
607     }
608
609     RSP_LoadMatrix( mtx, address );
610
611     if (param & G_MTX_PROJECTION)
612     {
613         if (param & G_MTX_LOAD)
614             CopyMatrix( gSP.matrix.projection, mtx );
615         else
616             MultMatrix2( gSP.matrix.projection, mtx );
617     }
618     else
619     {
620         if ((param & G_MTX_PUSH) && (gSP.matrix.modelViewi < (gSP.matrix.stackSize - 1)))
621         {
622             CopyMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi + 1], gSP.matrix.modelView[gSP.matrix.modelViewi] );
623             gSP.matrix.modelViewi++;
624         }
625         if (param & G_MTX_LOAD)
626             CopyMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi], mtx );
627         else
628             MultMatrix2( gSP.matrix.modelView[gSP.matrix.modelViewi], mtx );
629     }
630
631     gSP.changed |= CHANGED_MATRIX;
632 }
633
634 void gSPDMAMatrix( u32 matrix, u8 index, u8 multiply )
635 {
636     f32 mtx[4][4];
637     u32 address = gSP.DMAOffsets.mtx + RSP_SegmentToPhysical( matrix );
638
639     if (address + 64 > RDRAMSize)
640     {
641         return;
642     }
643
644     RSP_LoadMatrix( mtx, address );
645
646     gSP.matrix.modelViewi = index;
647
648     if (multiply)
649     {
650         //CopyMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi], gSP.matrix.modelView[0] );
651         //MultMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi], mtx );
652         MultMatrix(gSP.matrix.modelView[0], mtx, gSP.matrix.modelView[gSP.matrix.modelViewi]);
653     }
654     else
655         CopyMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi], mtx );
656
657     CopyMatrix( gSP.matrix.projection, identityMatrix );
658     gSP.changed |= CHANGED_MATRIX;
659 }
660
661 void gSPViewport( u32 v )
662 {
663     u32 address = RSP_SegmentToPhysical( v );
664
665     if ((address + 16) > RDRAMSize)
666     {
667 #ifdef DEBUG
668         DebugMsg( DEBUG_HIGH | DEBUG_ERROR, "// Attempting to load viewport from invalid address\n" );
669         DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gSPViewport( 0x%08X );\n", v );
670 #endif
671         return;
672     }
673
674     gSP.viewport.vscale[0] = _FIXED2FLOAT( *(s16*)&RDRAM[address +  2], 2 );
675     gSP.viewport.vscale[1] = _FIXED2FLOAT( *(s16*)&RDRAM[address     ], 2 );
676     gSP.viewport.vscale[2] = _FIXED2FLOAT( *(s16*)&RDRAM[address +  6], 10 );// * 0.00097847357f;
677     gSP.viewport.vscale[3] = *(s16*)&RDRAM[address +  4];
678     gSP.viewport.vtrans[0] = _FIXED2FLOAT( *(s16*)&RDRAM[address + 10], 2 );
679     gSP.viewport.vtrans[1] = _FIXED2FLOAT( *(s16*)&RDRAM[address +  8], 2 );
680     gSP.viewport.vtrans[2] = _FIXED2FLOAT( *(s16*)&RDRAM[address + 14], 10 );// * 0.00097847357f;
681     gSP.viewport.vtrans[3] = *(s16*)&RDRAM[address + 12];
682
683     gSP.viewport.x      = gSP.viewport.vtrans[0] - gSP.viewport.vscale[0];
684     gSP.viewport.y      = gSP.viewport.vtrans[1] - gSP.viewport.vscale[1];
685     gSP.viewport.width  = gSP.viewport.vscale[0] * 2;
686     gSP.viewport.height = gSP.viewport.vscale[1] * 2;
687     gSP.viewport.nearz  = gSP.viewport.vtrans[2] - gSP.viewport.vscale[2];
688     gSP.viewport.farz   = (gSP.viewport.vtrans[2] + gSP.viewport.vscale[2]) ;
689
690     gSP.changed |= CHANGED_VIEWPORT;
691 }
692
693 void gSPForceMatrix( u32 mptr )
694 {
695     u32 address = RSP_SegmentToPhysical( mptr );
696
697     if (address + 64 > RDRAMSize)
698     {
699         return;
700     }
701
702     RSP_LoadMatrix( gSP.matrix.combined, RSP_SegmentToPhysical( mptr ) );
703
704     gSP.changed &= ~CHANGED_MATRIX;
705 }
706
707 void gSPLight( u32 l, s32 n )
708 {
709     n--;
710     if (n >= 8)
711         return;
712
713     u32 address = RSP_SegmentToPhysical( l );
714
715     if ((address + sizeof( Light )) > RDRAMSize)
716     {
717         return;
718     }
719
720     u8 *addr = &RDRAM[address];
721
722     if (config.hackZelda && (addr[0] == 0x08) && (addr[4] == 0xFF))
723     {
724         LightMM *light = (LightMM*)addr;
725         gSP.lights[n].r = light->r * 0.0039215689f;
726         gSP.lights[n].g = light->g * 0.0039215689f;
727         gSP.lights[n].b = light->b * 0.0039215689f;
728         gSP.lights[n].x = light->x;
729         gSP.lights[n].y = light->y;
730         gSP.lights[n].z = light->z;
731     }
732     else
733     {
734         Light *light = (Light*)addr;
735         gSP.lights[n].r = light->r * 0.0039215689f;
736         gSP.lights[n].g = light->g * 0.0039215689f;
737         gSP.lights[n].b = light->b * 0.0039215689f;
738         gSP.lights[n].x = light->x;
739         gSP.lights[n].y = light->y;
740         gSP.lights[n].z = light->z;
741     }
742     Normalize(&gSP.lights[n].x);
743 }
744
745 void gSPLookAt( u32 l )
746 {
747 }
748
749 void gSPVertex( u32 v, u32 n, u32 v0 )
750 {
751     //flush batched triangles:
752 #ifdef __TRIBUFFER_OPT
753     gSPFlushTriangles();
754 #endif
755
756     u32 address = RSP_SegmentToPhysical( v );
757
758     if ((address + sizeof( Vertex ) * n) > RDRAMSize)
759     {
760         return;
761     }
762
763     Vertex *vertex = (Vertex*)&RDRAM[address];
764
765     if ((n + v0) <= INDEXMAP_SIZE)
766     {
767         unsigned int i = v0;
768 #ifdef __VEC4_OPT
769         for (; i < n - (n%4) + v0; i += 4)
770         {
771             u32 v = i;
772 #ifdef __TRIBUFFER_OPT
773             v = __indexmap_getnew(v, 4);
774 #endif
775             for(int j = 0; j < 4; j++)
776             {
777                 OGL.triangles.vertices[v+j].x = vertex->x;
778                 OGL.triangles.vertices[v+j].y = vertex->y;
779                 OGL.triangles.vertices[v+j].z = vertex->z;
780                 //OGL.triangles.vertices[i+j].flag = vertex->flag;
781                 OGL.triangles.vertices[v+j].s = _FIXED2FLOAT( vertex->s, 5 );
782                 OGL.triangles.vertices[v+j].t = _FIXED2FLOAT( vertex->t, 5 );
783                 if (gSP.geometryMode & G_LIGHTING)
784                 {
785                     OGL.triangles.vertices[v+j].nx = vertex->normal.x;
786                     OGL.triangles.vertices[v+j].ny = vertex->normal.y;
787                     OGL.triangles.vertices[v+j].nz = vertex->normal.z;
788                     OGL.triangles.vertices[v+j].a = vertex->color.a * 0.0039215689f;
789                 }
790                 else
791                 {
792                     OGL.triangles.vertices[v+j].r = vertex->color.r * 0.0039215689f;
793                     OGL.triangles.vertices[v+j].g = vertex->color.g * 0.0039215689f;
794                     OGL.triangles.vertices[v+j].b = vertex->color.b * 0.0039215689f;
795                     OGL.triangles.vertices[v+j].a = vertex->color.a * 0.0039215689f;
796                 }
797                 vertex++;
798             }
799             gSPProcessVertex4(v);
800         }
801 #endif
802         for (; i < n + v0; i++)
803         {
804             u32 v = i;
805 #ifdef __TRIBUFFER_OPT
806             v = __indexmap_getnew(v, 1);
807 #endif
808             OGL.triangles.vertices[v].x = vertex->x;
809             OGL.triangles.vertices[v].y = vertex->y;
810             OGL.triangles.vertices[v].z = vertex->z;
811             OGL.triangles.vertices[v].s = _FIXED2FLOAT( vertex->s, 5 );
812             OGL.triangles.vertices[v].t = _FIXED2FLOAT( vertex->t, 5 );
813             if (gSP.geometryMode & G_LIGHTING)
814             {
815                 OGL.triangles.vertices[v].nx = vertex->normal.x;
816                 OGL.triangles.vertices[v].ny = vertex->normal.y;
817                 OGL.triangles.vertices[v].nz = vertex->normal.z;
818                 OGL.triangles.vertices[v].a = vertex->color.a * 0.0039215689f;
819             }
820             else
821             {
822                 OGL.triangles.vertices[v].r = vertex->color.r * 0.0039215689f;
823                 OGL.triangles.vertices[v].g = vertex->color.g * 0.0039215689f;
824                 OGL.triangles.vertices[v].b = vertex->color.b * 0.0039215689f;
825                 OGL.triangles.vertices[v].a = vertex->color.a * 0.0039215689f;
826             }
827             gSPProcessVertex(v);
828             vertex++;
829         }
830     }
831     else
832     {
833         LOG(LOG_ERROR, "Using Vertex outside buffer v0=%i, n=%i\n", v0, n);
834     }
835
836 }
837
838 void gSPCIVertex( u32 v, u32 n, u32 v0 )
839 {
840
841 #ifdef __TRIBUFFER_OPT
842     gSPFlushTriangles();
843 #endif
844
845     u32 address = RSP_SegmentToPhysical( v );
846
847     if ((address + sizeof( PDVertex ) * n) > RDRAMSize)
848     {
849         return;
850     }
851
852     PDVertex *vertex = (PDVertex*)&RDRAM[address];
853
854     if ((n + v0) <= INDEXMAP_SIZE)
855     {
856         unsigned int i = v0;
857 #ifdef __VEC4_OPT
858         for (; i < n - (n%4) + v0; i += 4)
859         {
860             u32 v = i;
861 #ifdef __TRIBUFFER_OPT
862             v = __indexmap_getnew(v, 4);
863 #endif
864             for(unsigned int j = 0; j < 4; j++)
865             {
866                 OGL.triangles.vertices[v+j].x = vertex->x;
867                 OGL.triangles.vertices[v+j].y = vertex->y;
868                 OGL.triangles.vertices[v+j].z = vertex->z;
869                 OGL.triangles.vertices[v+j].s = _FIXED2FLOAT( vertex->s, 5 );
870                 OGL.triangles.vertices[v+j].t = _FIXED2FLOAT( vertex->t, 5 );
871                 u8 *color = &RDRAM[gSP.vertexColorBase + (vertex->ci & 0xff)];
872
873                 if (gSP.geometryMode & G_LIGHTING)
874                 {
875                     OGL.triangles.vertices[v+j].nx = (s8)color[3];
876                     OGL.triangles.vertices[v+j].ny = (s8)color[2];
877                     OGL.triangles.vertices[v+j].nz = (s8)color[1];
878                     OGL.triangles.vertices[v+j].a = color[0] * 0.0039215689f;
879                 }
880                 else
881                 {
882                     OGL.triangles.vertices[v+j].r = color[3] * 0.0039215689f;
883                     OGL.triangles.vertices[v+j].g = color[2] * 0.0039215689f;
884                     OGL.triangles.vertices[v+j].b = color[1] * 0.0039215689f;
885                     OGL.triangles.vertices[v+j].a = color[0] * 0.0039215689f;
886                 }
887                 vertex++;
888             }
889             gSPProcessVertex4(v);
890         }
891 #endif
892         for(; i < n + v0; i++)
893         {
894             u32 v = i;
895 #ifdef __TRIBUFFER_OPT
896             v = __indexmap_getnew(v, 1);
897 #endif
898             OGL.triangles.vertices[v].x = vertex->x;
899             OGL.triangles.vertices[v].y = vertex->y;
900             OGL.triangles.vertices[v].z = vertex->z;
901             OGL.triangles.vertices[v].s = _FIXED2FLOAT( vertex->s, 5 );
902             OGL.triangles.vertices[v].t = _FIXED2FLOAT( vertex->t, 5 );
903             u8 *color = &RDRAM[gSP.vertexColorBase + (vertex->ci & 0xff)];
904
905             if (gSP.geometryMode & G_LIGHTING)
906             {
907                 OGL.triangles.vertices[v].nx = (s8)color[3];
908                 OGL.triangles.vertices[v].ny = (s8)color[2];
909                 OGL.triangles.vertices[v].nz = (s8)color[1];
910                 OGL.triangles.vertices[v].a = color[0] * 0.0039215689f;
911             }
912             else
913             {
914                 OGL.triangles.vertices[v].r = color[3] * 0.0039215689f;
915                 OGL.triangles.vertices[v].g = color[2] * 0.0039215689f;
916                 OGL.triangles.vertices[v].b = color[1] * 0.0039215689f;
917                 OGL.triangles.vertices[v].a = color[0] * 0.0039215689f;
918             }
919
920             gSPProcessVertex(v);
921             vertex++;
922         }
923     }
924     else
925     {
926         LOG(LOG_ERROR, "Using Vertex outside buffer v0=%i, n=%i\n", v0, n);
927     }
928
929 }
930
931 void gSPDMAVertex( u32 v, u32 n, u32 v0 )
932 {
933
934     u32 address = gSP.DMAOffsets.vtx + RSP_SegmentToPhysical( v );
935
936     if ((address + 10 * n) > RDRAMSize)
937     {
938         return;
939     }
940
941     if ((n + v0) <= INDEXMAP_SIZE)
942     {
943         u32 i = v0;
944 #ifdef __VEC4_OPT
945         for (; i < n - (n%4) + v0; i += 4)
946         {
947             u32 v = i;
948 #ifdef __TRIBUFFER_OPT
949             v = __indexmap_getnew(v, 4);
950 #endif
951             for(int j = 0; j < 4; j++)
952             {
953                 OGL.triangles.vertices[v+j].x = *(s16*)&RDRAM[address ^ 2];
954                 OGL.triangles.vertices[v+j].y = *(s16*)&RDRAM[(address + 2) ^ 2];
955                 OGL.triangles.vertices[v+j].z = *(s16*)&RDRAM[(address + 4) ^ 2];
956
957                 if (gSP.geometryMode & G_LIGHTING)
958                 {
959                     OGL.triangles.vertices[v+j].nx = *(s8*)&RDRAM[(address + 6) ^ 3];
960                     OGL.triangles.vertices[v+j].ny = *(s8*)&RDRAM[(address + 7) ^ 3];
961                     OGL.triangles.vertices[v+j].nz = *(s8*)&RDRAM[(address + 8) ^ 3];
962                     OGL.triangles.vertices[v+j].a = *(u8*)&RDRAM[(address + 9) ^ 3] * 0.0039215689f;
963                 }
964                 else
965                 {
966                     OGL.triangles.vertices[v+j].r = *(u8*)&RDRAM[(address + 6) ^ 3] * 0.0039215689f;
967                     OGL.triangles.vertices[v+j].g = *(u8*)&RDRAM[(address + 7) ^ 3] * 0.0039215689f;
968                     OGL.triangles.vertices[v+j].b = *(u8*)&RDRAM[(address + 8) ^ 3] * 0.0039215689f;
969                     OGL.triangles.vertices[v+j].a = *(u8*)&RDRAM[(address + 9) ^ 3] * 0.0039215689f;
970                 }
971                 address += 10;
972             }
973             gSPProcessVertex4(v);
974         }
975 #endif
976         for (; i < n + v0; i++)
977         {
978             u32 v = i;
979 #ifdef __TRIBUFFER_OPT
980             //int ind = OGL.triangles.indexmap[i];
981             v = __indexmap_getnew(v, 1);
982
983             //if previously mapped copy across s/t.
984             //if (ind != -1)
985             //{
986             //    SPVertex *vtx = &OGL.triangles.vertices[ind];
987             //    OGL.triangles.vertices[v].s = vtx->s;
988             //    OGL.triangles.vertices[v].t = vtx->s;
989             //}
990 #else
991             v = i;
992 #endif
993             OGL.triangles.vertices[v].x = *(s16*)&RDRAM[address ^ 2];
994             OGL.triangles.vertices[v].y = *(s16*)&RDRAM[(address + 2) ^ 2];
995             OGL.triangles.vertices[v].z = *(s16*)&RDRAM[(address + 4) ^ 2];
996
997             if (gSP.geometryMode & G_LIGHTING)
998             {
999                 OGL.triangles.vertices[v].nx = *(s8*)&RDRAM[(address + 6) ^ 3];
1000                 OGL.triangles.vertices[v].ny = *(s8*)&RDRAM[(address + 7) ^ 3];
1001                 OGL.triangles.vertices[v].nz = *(s8*)&RDRAM[(address + 8) ^ 3];
1002                 OGL.triangles.vertices[v].a = *(u8*)&RDRAM[(address + 9) ^ 3] * 0.0039215689f;
1003             }
1004             else
1005             {
1006                 OGL.triangles.vertices[v].r = *(u8*)&RDRAM[(address + 6) ^ 3] * 0.0039215689f;
1007                 OGL.triangles.vertices[v].g = *(u8*)&RDRAM[(address + 7) ^ 3] * 0.0039215689f;
1008                 OGL.triangles.vertices[v].b = *(u8*)&RDRAM[(address + 8) ^ 3] * 0.0039215689f;
1009                 OGL.triangles.vertices[v].a = *(u8*)&RDRAM[(address + 9) ^ 3] * 0.0039215689f;
1010             }
1011
1012             gSPProcessVertex(v);
1013             address += 10;
1014         }
1015     }
1016     else
1017     {
1018         LOG(LOG_ERROR, "Using Vertex outside buffer v0=%i, n=%i\n", v0, n);
1019     }
1020
1021 }
1022
1023 void gSPDisplayList( u32 dl )
1024 {
1025     u32 address = RSP_SegmentToPhysical( dl );
1026
1027     if ((address + 8) > RDRAMSize)
1028     {
1029         return;
1030     }
1031
1032     if (RSP.PCi < (GBI.PCStackSize - 1))
1033     {
1034 #ifdef DEBUG
1035     DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "\n" );
1036     DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gSPDisplayList( 0x%08X );\n",
1037         dl );
1038 #endif
1039         RSP.PCi++;
1040         RSP.PC[RSP.PCi] = address;
1041         RSP.nextCmd = _SHIFTR( *(u32*)&RDRAM[address], 24, 8 );
1042     }
1043
1044
1045 }
1046
1047 void gSPDMADisplayList( u32 dl, u32 n )
1048 {
1049     if ((dl + (n << 3)) > RDRAMSize)
1050     {
1051         return;
1052     }
1053
1054     u32 curDL = RSP.PC[RSP.PCi];
1055
1056     RSP.PC[RSP.PCi] = RSP_SegmentToPhysical( dl );
1057
1058     while ((RSP.PC[RSP.PCi] - dl) < (n << 3))
1059     {
1060         if ((RSP.PC[RSP.PCi] + 8) > RDRAMSize)
1061         {
1062             break;
1063         }
1064
1065         u32 w0 = *(u32*)&RDRAM[RSP.PC[RSP.PCi]];
1066         u32 w1 = *(u32*)&RDRAM[RSP.PC[RSP.PCi] + 4];
1067
1068         RSP.PC[RSP.PCi] += 8;
1069         RSP.nextCmd = _SHIFTR( *(u32*)&RDRAM[RSP.PC[RSP.PCi]], 24, 8 );
1070
1071         GBI.cmd[_SHIFTR( w0, 24, 8 )]( w0, w1 );
1072     }
1073
1074     RSP.PC[RSP.PCi] = curDL;
1075 }
1076
1077 void gSPBranchList( u32 dl )
1078 {
1079     u32 address = RSP_SegmentToPhysical( dl );
1080
1081     if ((address + 8) > RDRAMSize)
1082     {
1083         return;
1084     }
1085
1086     RSP.PC[RSP.PCi] = address;
1087     RSP.nextCmd = _SHIFTR( *(u32*)&RDRAM[address], 24, 8 );
1088 }
1089
1090 void gSPBranchLessZ( u32 branchdl, u32 vtx, f32 zval )
1091 {
1092     u32 address = RSP_SegmentToPhysical( branchdl );
1093
1094     if ((address + 8) > RDRAMSize)
1095     {
1096         return;
1097     }
1098
1099     if (OGL.triangles.vertices[vtx].z <= zval)
1100         RSP.PC[RSP.PCi] = address;
1101 }
1102
1103 void gSPSetDMAOffsets( u32 mtxoffset, u32 vtxoffset )
1104 {
1105     gSP.DMAOffsets.mtx = mtxoffset;
1106     gSP.DMAOffsets.vtx = vtxoffset;
1107 }
1108
1109 void gSPSetVertexColorBase( u32 base )
1110 {
1111     gSP.vertexColorBase = RSP_SegmentToPhysical( base );
1112
1113 #ifdef __TRIBUFFER_OPT
1114     gSPFlushTriangles();
1115 #endif
1116 }
1117
1118 void gSPSprite2DBase( u32 base )
1119 {
1120 }
1121
1122 void gSPCopyVertex( SPVertex *dest, SPVertex *src )
1123 {
1124     dest->x = src->x;
1125     dest->y = src->y;
1126     dest->z = src->z;
1127     dest->w = src->w;
1128     dest->r = src->r;
1129     dest->g = src->g;
1130     dest->b = src->b;
1131     dest->a = src->a;
1132     dest->s = src->s;
1133     dest->t = src->t;
1134 }
1135
1136 void gSPInterpolateVertex( SPVertex *dest, f32 percent, SPVertex *first, SPVertex *second )
1137 {
1138     dest->x = first->x + percent * (second->x - first->x);
1139     dest->y = first->y + percent * (second->y - first->y);
1140     dest->z = first->z + percent * (second->z - first->z);
1141     dest->w = first->w + percent * (second->w - first->w);
1142     dest->r = first->r + percent * (second->r - first->r);
1143     dest->g = first->g + percent * (second->g - first->g);
1144     dest->b = first->b + percent * (second->b - first->b);
1145     dest->a = first->a + percent * (second->a - first->a);
1146     dest->s = first->s + percent * (second->s - first->s);
1147     dest->t = first->t + percent * (second->t - first->t);
1148 }
1149
1150 void gSPDMATriangles( u32 tris, u32 n )
1151 {
1152     u32 address = RSP_SegmentToPhysical( tris );
1153
1154     if (address + sizeof( DKRTriangle ) * n > RDRAMSize)
1155     {
1156         return;
1157     }
1158
1159 #ifdef __TRIBUFFER_OPT
1160     __indexmap_undomap();
1161 #endif
1162
1163     DKRTriangle *triangles = (DKRTriangle*)&RDRAM[address];
1164
1165     for (u32 i = 0; i < n; i++)
1166     {
1167         int mode = 0;
1168         if (!(triangles->flag & 0x40))
1169         {
1170             if (gSP.viewport.vscale[0] > 0)
1171                 mode |= G_CULL_BACK;
1172             else
1173                 mode |= G_CULL_FRONT;
1174         }
1175
1176         if ((gSP.geometryMode&G_CULL_BOTH) != mode)
1177         {
1178 //            OGL_DrawTriangles();
1179             gSP.geometryMode &= ~G_CULL_BOTH;
1180             gSP.geometryMode |= mode;
1181             gSP.changed |= CHANGED_GEOMETRYMODE;
1182         }
1183
1184
1185         s32 v0 = triangles->v0;
1186         s32 v1 = triangles->v1;
1187         s32 v2 = triangles->v2;
1188         OGL.triangles.vertices[v0].s = _FIXED2FLOAT( triangles->s0, 5 );
1189         OGL.triangles.vertices[v0].t = _FIXED2FLOAT( triangles->t0, 5 );
1190         OGL.triangles.vertices[v1].s = _FIXED2FLOAT( triangles->s1, 5 );
1191         OGL.triangles.vertices[v1].t = _FIXED2FLOAT( triangles->t1, 5 );
1192         OGL.triangles.vertices[v2].s = _FIXED2FLOAT( triangles->s2, 5 );
1193         OGL.triangles.vertices[v2].t = _FIXED2FLOAT( triangles->t2, 5 );
1194         gSPTriangle(triangles->v0, triangles->v1, triangles->v2);
1195         triangles++;
1196     }
1197
1198 //#ifdef __TRIBUFFER_OPT
1199     OGL_DrawTriangles();
1200 //#endif
1201 }
1202
1203 void gSP1Quadrangle( s32 v0, s32 v1, s32 v2, s32 v3)
1204 {
1205     gSPTriangle( v0, v1, v2);
1206     gSPTriangle( v0, v2, v3);
1207     gSPFlushTriangles();
1208 }
1209
1210 bool gSPCullVertices( u32 v0, u32 vn )
1211 {
1212     if (!config.enableClipping)
1213         return FALSE;
1214
1215     s32 v = v0;
1216 #ifdef __TRIBUFFER_OPT
1217     v = OGL.triangles.indexmap[v0];
1218 #endif
1219
1220     u32 clip = OGL.triangles.vertices[v].clip;
1221     if (clip == 0)
1222         return FALSE;
1223
1224     for (unsigned int i = (v0+1); i <= vn; i++)
1225     {
1226         v = i;
1227 #ifdef __TRIBUFFER_OPT
1228         v = OGL.triangles.indexmap[i];
1229 #endif
1230         if (OGL.triangles.vertices[v].clip != clip) return FALSE;
1231     }
1232     return TRUE;
1233 }
1234
1235 void gSPCullDisplayList( u32 v0, u32 vn )
1236 {
1237     if (gSPCullVertices( v0, vn ))
1238     {
1239         if (RSP.PCi > 0)
1240             RSP.PCi--;
1241         else
1242         {
1243             RSP.halt = TRUE;
1244         }
1245     }
1246 }
1247
1248 void gSPPopMatrixN( u32 param, u32 num )
1249 {
1250     if (gSP.matrix.modelViewi > num - 1)
1251     {
1252         gSP.matrix.modelViewi -= num;
1253
1254         gSP.changed |= CHANGED_MATRIX;
1255     }
1256 }
1257
1258 void gSPPopMatrix( u32 param )
1259 {
1260     if (gSP.matrix.modelViewi > 0)
1261     {
1262         gSP.matrix.modelViewi--;
1263
1264         gSP.changed |= CHANGED_MATRIX;
1265     }
1266 }
1267
1268 void gSPSegment( s32 seg, s32 base )
1269 {
1270     if (seg > 0xF)
1271     {
1272         return;
1273     }
1274
1275     if ((unsigned int)base > RDRAMSize - 1)
1276     {
1277         return;
1278     }
1279
1280     gSP.segment[seg] = base;
1281 }
1282
1283 void gSPClipRatio( u32 r )
1284 {
1285 }
1286
1287 void gSPInsertMatrix( u32 where, u32 num )
1288 {
1289     f32 fraction, integer;
1290
1291     if (gSP.changed & CHANGED_MATRIX)
1292         gSPCombineMatrices();
1293
1294     if ((where & 0x3) || (where > 0x3C))
1295     {
1296         return;
1297     }
1298
1299     if (where < 0x20)
1300     {
1301         fraction = modff( gSP.matrix.combined[0][where >> 1], &integer );
1302         gSP.matrix.combined[0][where >> 1] = (s16)_SHIFTR( num, 16, 16 ) + abs( (int)fraction );
1303
1304         fraction = modff( gSP.matrix.combined[0][(where >> 1) + 1], &integer );
1305         gSP.matrix.combined[0][(where >> 1) + 1] = (s16)_SHIFTR( num, 0, 16 ) + abs( (int)fraction );
1306     }
1307     else
1308     {
1309         f32 newValue;
1310
1311         fraction = modff( gSP.matrix.combined[0][(where - 0x20) >> 1], &integer );
1312         newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 16, 16 ), 16);
1313
1314         // Make sure the sign isn't lost
1315         if ((integer == 0.0f) && (fraction != 0.0f))
1316             newValue = newValue * (fraction / abs( (int)fraction ));
1317
1318         gSP.matrix.combined[0][(where - 0x20) >> 1] = newValue;
1319
1320         fraction = modff( gSP.matrix.combined[0][((where - 0x20) >> 1) + 1], &integer );
1321         newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 0, 16 ), 16 );
1322
1323         // Make sure the sign isn't lost
1324         if ((integer == 0.0f) && (fraction != 0.0f))
1325             newValue = newValue * (fraction / abs( (int)fraction ));
1326
1327         gSP.matrix.combined[0][((where - 0x20) >> 1) + 1] = newValue;
1328     }
1329 }
1330
1331 void gSPModifyVertex( u32 vtx, u32 where, u32 val )
1332 {
1333     s32 v = vtx;
1334
1335 #ifdef __TRIBUFFER_OPT
1336     v = OGL.triangles.indexmap[v];
1337 #endif
1338
1339     switch (where)
1340     {
1341         case G_MWO_POINT_RGBA:
1342             OGL.triangles.vertices[v].r = _SHIFTR( val, 24, 8 ) * 0.0039215689f;
1343             OGL.triangles.vertices[v].g = _SHIFTR( val, 16, 8 ) * 0.0039215689f;
1344             OGL.triangles.vertices[v].b = _SHIFTR( val, 8, 8 ) * 0.0039215689f;
1345             OGL.triangles.vertices[v].a = _SHIFTR( val, 0, 8 ) * 0.0039215689f;
1346             break;
1347         case G_MWO_POINT_ST:
1348             OGL.triangles.vertices[v].s = _FIXED2FLOAT( (s16)_SHIFTR( val, 16, 16 ), 5 );
1349             OGL.triangles.vertices[v].t = _FIXED2FLOAT( (s16)_SHIFTR( val, 0, 16 ), 5 );
1350             break;
1351         case G_MWO_POINT_XYSCREEN:
1352             break;
1353         case G_MWO_POINT_ZSCREEN:
1354             break;
1355     }
1356 }
1357
1358 void gSPNumLights( s32 n )
1359 {
1360     gSP.numLights = (n <= 8) ? n : 0;
1361 }
1362
1363
1364 void gSPLightColor( u32 lightNum, u32 packedColor )
1365 {
1366     lightNum--;
1367
1368     if (lightNum < 8)
1369     {
1370         gSP.lights[lightNum].r = _SHIFTR( packedColor, 24, 8 ) * 0.0039215689f;
1371         gSP.lights[lightNum].g = _SHIFTR( packedColor, 16, 8 ) * 0.0039215689f;
1372         gSP.lights[lightNum].b = _SHIFTR( packedColor, 8, 8 ) * 0.0039215689f;
1373     }
1374 }
1375
1376 void gSPFogFactor( s16 fm, s16 fo )
1377 {
1378     gSP.fog.multiplier = fm;
1379     gSP.fog.offset = fo;
1380
1381     gSP.changed |= CHANGED_FOGPOSITION;
1382 }
1383
1384 void gSPPerspNormalize( u16 scale )
1385 {
1386 }
1387
1388 void gSPTexture( f32 sc, f32 tc, s32 level, s32 tile, s32 on )
1389 {
1390     gSP.texture.scales = sc;
1391     gSP.texture.scalet = tc;
1392
1393     if (gSP.texture.scales == 0.0f) gSP.texture.scales = 1.0f;
1394     if (gSP.texture.scalet == 0.0f) gSP.texture.scalet = 1.0f;
1395
1396     gSP.texture.level = level;
1397     gSP.texture.on = on;
1398
1399     if (gSP.texture.tile != tile)
1400     {
1401         gSP.texture.tile = tile;
1402         gSP.textureTile[0] = &gDP.tiles[tile];
1403         gSP.textureTile[1] = &gDP.tiles[(tile < 7) ? (tile + 1) : tile];
1404         gSP.changed |= CHANGED_TEXTURE;
1405     }
1406
1407     gSP.changed |= CHANGED_TEXTURESCALE;
1408 }
1409
1410 void gSPEndDisplayList()
1411 {
1412     if (RSP.PCi > 0)
1413         RSP.PCi--;
1414     else
1415     {
1416         RSP.halt = TRUE;
1417     }
1418
1419 #ifdef __TRIBUFFER_OPT
1420     RSP.nextCmd = _SHIFTR( *(u32*)&RDRAM[RSP.PC[RSP.PCi]], 24, 8 );
1421     gSPFlushTriangles();
1422 #endif
1423 }
1424
1425 void gSPGeometryMode( u32 clear, u32 set )
1426 {
1427     gSP.geometryMode = (gSP.geometryMode & ~clear) | set;
1428     gSP.changed |= CHANGED_GEOMETRYMODE;
1429 }
1430
1431 void gSPSetGeometryMode( u32 mode )
1432 {
1433     gSP.geometryMode |= mode;
1434     gSP.changed |= CHANGED_GEOMETRYMODE;
1435 }
1436
1437 void gSPClearGeometryMode( u32 mode )
1438 {
1439     gSP.geometryMode &= ~mode;
1440     gSP.changed |= CHANGED_GEOMETRYMODE;
1441 }
1442
1443 void gSPLine3D( s32 v0, s32 v1, s32 flag )
1444 {
1445     OGL_DrawLine(v0, v1, 1.5f );
1446 }
1447
1448 void gSPLineW3D( s32 v0, s32 v1, s32 wd, s32 flag )
1449 {
1450     OGL_DrawLine(v0, v1, 1.5f + wd * 0.5f );
1451 }
1452
1453 void gSPBgRect1Cyc( u32 bg )
1454 {
1455
1456 #if 1
1457
1458     u32 addr = RSP_SegmentToPhysical(bg) >> 1;
1459
1460     f32 imageX  = (((u16*)RDRAM)[(addr+0)^1] >> 5);     // 0
1461     f32 imageY  = (((u16*)RDRAM)[(addr+4)^1] >> 5);     // 4
1462     f32 imageW  = (((u16*)RDRAM)[(addr+1)^1] >> 2);     // 1
1463     f32 imageH  = (((u16*)RDRAM)[(addr+5)^1] >> 2);     // 5
1464
1465     f32 frameX  = ((s16*)RDRAM)[(addr+2)^1] / 4.0f;     // 2
1466     f32 frameY  = ((s16*)RDRAM)[(addr+6)^1] / 4.0f;     // 6
1467     f32 frameW  = ((u16*)RDRAM)[(addr+3)^1] >> 2;               // 3
1468     f32 frameH  = ((u16*)RDRAM)[(addr+7)^1] >> 2;               // 7
1469
1470
1471     //wxUint16 imageFlip = ((u16*)gfx.RDRAM)[(addr+13)^1];      // 13;
1472     //d.flipX   = (u8)imageFlip&0x01;
1473
1474     gSP.bgImage.address = RSP_SegmentToPhysical(((u32*)RDRAM)[(addr+8)>>1]);    // 8,9
1475     gSP.bgImage.width = imageW;
1476     gSP.bgImage.height = imageH;
1477     gSP.bgImage.format = ((u8*)RDRAM)[(((addr+11)<<1)+0)^3];
1478     gSP.bgImage.size = ((u8*)RDRAM)[(((addr+11)<<1)+1)^3];
1479     gSP.bgImage.palette = ((u16*)RDRAM)[(addr+12)^1];
1480
1481     f32 scaleW  = ((s16*)RDRAM)[(addr+14)^1] / 1024.0f; // 14
1482     f32 scaleH  = ((s16*)RDRAM)[(addr+15)^1] / 1024.0f; // 15
1483     gDP.textureMode = TEXTUREMODE_BGIMAGE;
1484
1485 #else
1486     u32 address = RSP_SegmentToPhysical( bg );
1487     uObjScaleBg *objScaleBg = (uObjScaleBg*)&RDRAM[address];
1488
1489     gSP.bgImage.address = RSP_SegmentToPhysical( objScaleBg->imagePtr );
1490     gSP.bgImage.width = objScaleBg->imageW >> 2;
1491     gSP.bgImage.height = objScaleBg->imageH >> 2;
1492     gSP.bgImage.format = objScaleBg->imageFmt;
1493     gSP.bgImage.size = objScaleBg->imageSiz;
1494     gSP.bgImage.palette = objScaleBg->imagePal;
1495     gDP.textureMode = TEXTUREMODE_BGIMAGE;
1496
1497     f32 imageX = _FIXED2FLOAT( objScaleBg->imageX, 5 );
1498     f32 imageY = _FIXED2FLOAT( objScaleBg->imageY, 5 );
1499     f32 imageW = objScaleBg->imageW >> 2;
1500     f32 imageH = objScaleBg->imageH >> 2;
1501
1502     f32 frameX = _FIXED2FLOAT( objScaleBg->frameX, 2 );
1503     f32 frameY = _FIXED2FLOAT( objScaleBg->frameY, 2 );
1504     f32 frameW = _FIXED2FLOAT( objScaleBg->frameW, 2 );
1505     f32 frameH = _FIXED2FLOAT( objScaleBg->frameH, 2 );
1506     f32 scaleW = _FIXED2FLOAT( objScaleBg->scaleW, 10 );
1507     f32 scaleH = _FIXED2FLOAT( objScaleBg->scaleH, 10 );
1508 #endif
1509
1510     f32 frameX0 = frameX;
1511     f32 frameY0 = frameY;
1512     f32 frameS0 = imageX;
1513     f32 frameT0 = imageY;
1514
1515     f32 frameX1 = frameX + min( (imageW - imageX) / scaleW, frameW );
1516     f32 frameY1 = frameY + min( (imageH - imageY) / scaleH, frameH );
1517     //f32 frameS1 = imageX + min( (imageW - imageX) * scaleW, frameW * scaleW );
1518     //f32 frameT1 = imageY + min( (imageH - imageY) * scaleH, frameH * scaleH );
1519
1520     gDP.otherMode.cycleType = G_CYC_1CYCLE;
1521     gDP.changed |= CHANGED_CYCLETYPE;
1522     gSPTexture( 1.0f, 1.0f, 0, 0, TRUE );
1523     gDPTextureRectangle( frameX0, frameY0, frameX1 - 1, frameY1 - 1, 0, frameS0 - 1, frameT0 - 1, scaleW, scaleH );
1524
1525     if ((frameX1 - frameX0) < frameW)
1526     {
1527         f32 frameX2 = frameW - (frameX1 - frameX0) + frameX1;
1528         gDPTextureRectangle( frameX1, frameY0, frameX2 - 1, frameY1 - 1, 0, 0, frameT0, scaleW, scaleH );
1529     }
1530
1531     if ((frameY1 - frameY0) < frameH)
1532     {
1533         f32 frameY2 = frameH - (frameY1 - frameY0) + frameY1;
1534         gDPTextureRectangle( frameX0, frameY1, frameX1 - 1, frameY2 - 1, 0, frameS0, 0, scaleW, scaleH );
1535     }
1536
1537     gDPTextureRectangle( 0, 0, 319, 239, 0, 0, 0, scaleW, scaleH );
1538 }
1539
1540 void gSPBgRectCopy( u32 bg )
1541 {
1542
1543     u32 address = RSP_SegmentToPhysical( bg );
1544     uObjBg *objBg = (uObjBg*)&RDRAM[address];
1545
1546     gSP.bgImage.address = RSP_SegmentToPhysical( objBg->imagePtr );
1547     gSP.bgImage.width = objBg->imageW >> 2;
1548     gSP.bgImage.height = objBg->imageH >> 2;
1549     gSP.bgImage.format = objBg->imageFmt;
1550     gSP.bgImage.size = objBg->imageSiz;
1551     gSP.bgImage.palette = objBg->imagePal;
1552     gDP.textureMode = TEXTUREMODE_BGIMAGE;
1553
1554     u16 imageX = objBg->imageX >> 5;
1555     u16 imageY = objBg->imageY >> 5;
1556
1557     s16 frameX = objBg->frameX / 4;
1558     s16 frameY = objBg->frameY / 4;
1559     u16 frameW = objBg->frameW >> 2;
1560     u16 frameH = objBg->frameH >> 2;
1561
1562     gSPTexture( 1.0f, 1.0f, 0, 0, TRUE );
1563
1564     gDPTextureRectangle( frameX, frameY, frameX + frameW - 1, frameY + frameH - 1, 0, imageX, imageY, 4, 1 );
1565 }
1566
1567 void gSPObjRectangle( u32 sp )
1568 {
1569     u32 address = RSP_SegmentToPhysical( sp );
1570     uObjSprite *objSprite = (uObjSprite*)&RDRAM[address];
1571
1572     f32 scaleW = _FIXED2FLOAT( objSprite->scaleW, 10 );
1573     f32 scaleH = _FIXED2FLOAT( objSprite->scaleH, 10 );
1574     f32 objX = _FIXED2FLOAT( objSprite->objX, 2 );
1575     f32 objY = _FIXED2FLOAT( objSprite->objY, 2 );
1576     u32 imageW = objSprite->imageW >> 2;
1577     u32 imageH = objSprite->imageH >> 2;
1578
1579     gDPTextureRectangle( objX, objY, objX + imageW / scaleW - 1, objY + imageH / scaleH - 1, 0, 0.0f, 0.0f, scaleW * (gDP.otherMode.cycleType == G_CYC_COPY ? 4.0f : 1.0f), scaleH );
1580 }
1581
1582 void gSPObjLoadTxtr( u32 tx )
1583 {
1584     u32 address = RSP_SegmentToPhysical( tx );
1585     uObjTxtr *objTxtr = (uObjTxtr*)&RDRAM[address];
1586
1587     if ((gSP.status[objTxtr->block.sid >> 2] & objTxtr->block.mask) != objTxtr->block.flag)
1588     {
1589         switch (objTxtr->block.type)
1590         {
1591             case G_OBJLT_TXTRBLOCK:
1592                 gDPSetTextureImage( 0, 1, 0, objTxtr->block.image );
1593                 gDPSetTile( 0, 1, 0, objTxtr->block.tmem, 7, 0, 0, 0, 0, 0, 0, 0 );
1594                 gDPLoadBlock( 7, 0, 0, ((objTxtr->block.tsize + 1) << 3) - 1, objTxtr->block.tline );
1595                 break;
1596             case G_OBJLT_TXTRTILE:
1597                 gDPSetTextureImage( 0, 1, (objTxtr->tile.twidth + 1) << 1, objTxtr->tile.image );
1598                 gDPSetTile( 0, 1, (objTxtr->tile.twidth + 1) >> 2, objTxtr->tile.tmem, 7, 0, 0, 0, 0, 0, 0, 0 );
1599                 gDPLoadTile( 7, 0, 0, (((objTxtr->tile.twidth + 1) << 1) - 1) << 2, (((objTxtr->tile.theight + 1) >> 2) - 1) << 2 );
1600                 break;
1601             case G_OBJLT_TLUT:
1602                 gDPSetTextureImage( 0, 2, 1, objTxtr->tlut.image );
1603                 gDPSetTile( 0, 2, 0, objTxtr->tlut.phead, 7, 0, 0, 0, 0, 0, 0, 0 );
1604                 gDPLoadTLUT( 7, 0, 0, objTxtr->tlut.pnum << 2, 0 );
1605                 break;
1606         }
1607         gSP.status[objTxtr->block.sid >> 2] = (gSP.status[objTxtr->block.sid >> 2] & ~objTxtr->block.mask) | (objTxtr->block.flag & objTxtr->block.mask);
1608     }
1609 }
1610
1611 void gSPObjSprite( u32 sp )
1612 {
1613     u32 address = RSP_SegmentToPhysical( sp );
1614     uObjSprite *objSprite = (uObjSprite*)&RDRAM[address];
1615
1616     f32 scaleW = _FIXED2FLOAT( objSprite->scaleW, 10 );
1617     f32 scaleH = _FIXED2FLOAT( objSprite->scaleH, 10 );
1618     f32 objX = _FIXED2FLOAT( objSprite->objX, 2 );
1619     f32 objY = _FIXED2FLOAT( objSprite->objY, 2 );
1620     u32 imageW = objSprite->imageW >> 5;
1621     u32 imageH = objSprite->imageH >> 5;
1622
1623     f32 x0 = objX;
1624     f32 y0 = objY;
1625     f32 x1 = objX + imageW / scaleW - 1;
1626     f32 y1 = objY + imageH / scaleH - 1;
1627
1628     s32 v0=0,v1=1,v2=2,v3=3;
1629
1630 #ifdef __TRIBUFFER_OPT
1631     v0 = OGL.triangles.indexmap[v0];
1632     v1 = OGL.triangles.indexmap[v1];
1633     v2 = OGL.triangles.indexmap[v2];
1634     v3 = OGL.triangles.indexmap[v3];
1635 #endif
1636
1637     OGL.triangles.vertices[v0].x = gSP.objMatrix.A * x0 + gSP.objMatrix.B * y0 + gSP.objMatrix.X;
1638     OGL.triangles.vertices[v0].y = gSP.objMatrix.C * x0 + gSP.objMatrix.D * y0 + gSP.objMatrix.Y;
1639     OGL.triangles.vertices[v0].z = 0.0f;
1640     OGL.triangles.vertices[v0].w = 1.0f;
1641     OGL.triangles.vertices[v0].s = 0.0f;
1642     OGL.triangles.vertices[v0].t = 0.0f;
1643     OGL.triangles.vertices[v1].x = gSP.objMatrix.A * x1 + gSP.objMatrix.B * y0 + gSP.objMatrix.X;
1644     OGL.triangles.vertices[v1].y = gSP.objMatrix.C * x1 + gSP.objMatrix.D * y0 + gSP.objMatrix.Y;
1645     OGL.triangles.vertices[v1].z = 0.0f;
1646     OGL.triangles.vertices[v1].w = 1.0f;
1647     OGL.triangles.vertices[v1].s = imageW - 1;
1648     OGL.triangles.vertices[v1].t = 0.0f;
1649     OGL.triangles.vertices[v2].x = gSP.objMatrix.A * x1 + gSP.objMatrix.B * y1 + gSP.objMatrix.X;
1650     OGL.triangles.vertices[v2].y = gSP.objMatrix.C * x1 + gSP.objMatrix.D * y1 + gSP.objMatrix.Y;
1651     OGL.triangles.vertices[v2].z = 0.0f;
1652     OGL.triangles.vertices[v2].w = 1.0f;
1653     OGL.triangles.vertices[v2].s = imageW - 1;
1654     OGL.triangles.vertices[v2].t = imageH - 1;
1655     OGL.triangles.vertices[v3].x = gSP.objMatrix.A * x0 + gSP.objMatrix.B * y1 + gSP.objMatrix.X;
1656     OGL.triangles.vertices[v3].y = gSP.objMatrix.C * x0 + gSP.objMatrix.D * y1 + gSP.objMatrix.Y;
1657     OGL.triangles.vertices[v3].z = 0.0f;
1658     OGL.triangles.vertices[v3].w = 1.0f;
1659     OGL.triangles.vertices[v3].s = 0;
1660     OGL.triangles.vertices[v3].t = imageH - 1;
1661
1662     gDPSetTile( objSprite->imageFmt, objSprite->imageSiz, objSprite->imageStride, objSprite->imageAdrs, 0, objSprite->imagePal, G_TX_CLAMP, G_TX_CLAMP, 0, 0, 0, 0 );
1663     gDPSetTileSize( 0, 0, 0, (imageW - 1) << 2, (imageH - 1) << 2 );
1664     gSPTexture( 1.0f, 1.0f, 0, 0, TRUE );
1665
1666     //glOrtho( 0, VI.width, VI.height, 0, 0.0f, 32767.0f );
1667     OGL.triangles.vertices[v0].x = 2.0f * VI.rwidth * OGL.triangles.vertices[v0].x - 1.0f;
1668     OGL.triangles.vertices[v0].y = -2.0f * VI.rheight * OGL.triangles.vertices[v0].y + 1.0f;
1669     OGL.triangles.vertices[v0].z = -1.0f;
1670     OGL.triangles.vertices[v0].w = 1.0f;
1671     OGL.triangles.vertices[v1].x = 2.0f * VI.rwidth * OGL.triangles.vertices[v0].x - 1.0f;
1672     OGL.triangles.vertices[v1].y = -2.0f * VI.rheight * OGL.triangles.vertices[v0].y + 1.0f;
1673     OGL.triangles.vertices[v1].z = -1.0f;
1674     OGL.triangles.vertices[v1].w = 1.0f;
1675     OGL.triangles.vertices[v2].x = 2.0f * VI.rwidth * OGL.triangles.vertices[v0].x - 1.0f;
1676     OGL.triangles.vertices[v2].y = -2.0f * VI.rheight * OGL.triangles.vertices[v0].y + 1.0f;
1677     OGL.triangles.vertices[v2].z = -1.0f;
1678     OGL.triangles.vertices[v2].w = 1.0f;
1679     OGL.triangles.vertices[v3].x = 2.0f * VI.rwidth * OGL.triangles.vertices[v0].x - 1.0f;
1680     OGL.triangles.vertices[v3].y = -2.0f * VI.rheight * OGL.triangles.vertices[v0].y + 1.0f;
1681     OGL.triangles.vertices[v3].z = -1.0f;
1682     OGL.triangles.vertices[v3].w = 1.0f;
1683
1684     OGL_AddTriangle(v0, v1, v2);
1685     OGL_AddTriangle(v0, v2, v3);
1686     OGL_DrawTriangles();
1687
1688     if (depthBuffer.current) depthBuffer.current->cleared = FALSE;
1689     gDP.colorImage.changed = TRUE;
1690     gDP.colorImage.height = (unsigned int)(max( gDP.colorImage.height, gDP.scissor.lry ));
1691 }
1692
1693 void gSPObjLoadTxSprite( u32 txsp )
1694 {
1695     gSPObjLoadTxtr( txsp );
1696     gSPObjSprite( txsp + sizeof( uObjTxtr ) );
1697 }
1698
1699 void gSPObjLoadTxRectR( u32 txsp )
1700 {
1701     gSPObjLoadTxtr( txsp );
1702 //  gSPObjRectangleR( txsp + sizeof( uObjTxtr ) );
1703 }
1704
1705 void gSPObjMatrix( u32 mtx )
1706 {
1707     u32 address = RSP_SegmentToPhysical( mtx );
1708     uObjMtx *objMtx = (uObjMtx*)&RDRAM[address];
1709
1710     gSP.objMatrix.A = _FIXED2FLOAT( objMtx->A, 16 );
1711     gSP.objMatrix.B = _FIXED2FLOAT( objMtx->B, 16 );
1712     gSP.objMatrix.C = _FIXED2FLOAT( objMtx->C, 16 );
1713     gSP.objMatrix.D = _FIXED2FLOAT( objMtx->D, 16 );
1714     gSP.objMatrix.X = _FIXED2FLOAT( objMtx->X, 2 );
1715     gSP.objMatrix.Y = _FIXED2FLOAT( objMtx->Y, 2 );
1716     gSP.objMatrix.baseScaleX = _FIXED2FLOAT( objMtx->BaseScaleX, 10 );
1717     gSP.objMatrix.baseScaleY = _FIXED2FLOAT( objMtx->BaseScaleY, 10 );
1718 }
1719
1720 void gSPObjSubMatrix( u32 mtx )
1721 {
1722 }
1723
1724
1725 #ifdef __VEC4_OPT
1726 void (*gSPTransformVertex4)(u32 v, float mtx[4][4]) =
1727         gSPTransformVertex4_default;
1728 void (*gSPTransformNormal4)(u32 v, float mtx[4][4]) =
1729         gSPTransformNormal4_default;
1730 void (*gSPLightVertex4)(u32 v) = gSPLightVertex4_default;
1731 void (*gSPBillboardVertex4)(u32 v) = gSPBillboardVertex4_default;
1732 #endif
1733 void (*gSPTransformVertex)(float vtx[4], float mtx[4][4]) =
1734         gSPTransformVertex_default;
1735 void (*gSPLightVertex)(u32 v) = gSPLightVertex_default;
1736 void (*gSPBillboardVertex)(u32 v, u32 i) = gSPBillboardVertex_default;
1737