1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <math.h>
5 
6 #include <retro_miscellaneous.h>
7 
8 #include "Common.h"
9 #include "gles2N64.h"
10 #include "Debug.h"
11 #include "RSP.h"
12 #include "GBI.h"
13 #include "gSP.h"
14 #include "gDP.h"
15 #include "3DMath.h"
16 #include "OpenGL.h"
17 #include "CRC.h"
18 #include <string.h>
19 #include "convert.h"
20 #include "S2DEX.h"
21 #include "VI.h"
22 #include "FrameBuffer.h"
23 #include "DepthBuffer.h"
24 #include "Config.h"
25 
26 #include "../../Graphics/3dmath.h"
27 #include "../../Graphics/RDP/gDP_state.h"
28 #include "../../Graphics/RSP/gSP_state.h"
29 #include "../../Graphics/image_convert.h"
30 
31 //Note: 0xC0 is used by 1080 alot, its an unknown command.
32 
33 float identityMatrix[4][4] =
34 {
35     { 1.0f, 0.0f, 0.0f, 0.0f },
36     { 0.0f, 1.0f, 0.0f, 0.0f },
37     { 0.0f, 0.0f, 1.0f, 0.0f },
38     { 0.0f, 0.0f, 0.0f, 1.0f }
39 };
40 
41 
gln64gSPFlushTriangles(void)42 static INLINE void gln64gSPFlushTriangles(void)
43 {
44    if ((gSP.geometryMode & G_SHADING_SMOOTH) == 0)
45    {
46       OGL_DrawTriangles();
47       return;
48    }
49 
50    if (
51          (__RSP.nextCmd != G_TRI1) &&
52          (__RSP.nextCmd != G_TRI2) &&
53          (__RSP.nextCmd != G_TRI4) &&
54          (__RSP.nextCmd != G_QUAD)
55       )
56          OGL_DrawTriangles();
57 }
58 
59 
gln64gSPCopyVertex(struct SPVertex * dest,struct SPVertex * src)60 void gln64gSPCopyVertex( struct SPVertex *dest, struct SPVertex *src )
61 {
62 	dest->x = src->x;
63 	dest->y = src->y;
64 	dest->z = src->z;
65 	dest->w = src->w;
66 	dest->r = src->r;
67 	dest->g = src->g;
68 	dest->b = src->b;
69 	dest->a = src->a;
70 	dest->s = src->s;
71 	dest->t = src->t;
72 }
73 
gln64gSPInterpolateVertex(struct SPVertex * dest,float percent,struct SPVertex * first,struct SPVertex * second)74 void gln64gSPInterpolateVertex( struct SPVertex *dest, float percent, struct SPVertex *first, struct SPVertex *second )
75 {
76 	dest->x = first->x + percent * (second->x - first->x);
77 	dest->y = first->y + percent * (second->y - first->y);
78 	dest->z = first->z + percent * (second->z - first->z);
79 	dest->w = first->w + percent * (second->w - first->w);
80 	dest->r = first->r + percent * (second->r - first->r);
81 	dest->g = first->g + percent * (second->g - first->g);
82 	dest->b = first->b + percent * (second->b - first->b);
83 	dest->a = first->a + percent * (second->a - first->a);
84 	dest->s = first->s + percent * (second->s - first->s);
85 	dest->t = first->t + percent * (second->t - first->t);
86 }
87 
gln64gSPTriangle(int32_t v0,int32_t v1,int32_t v2)88 void gln64gSPTriangle(int32_t v0, int32_t v1, int32_t v2)
89 {
90    /* TODO/FIXME - update with gliden64 code */
91    if ((v0 < INDEXMAP_SIZE) && (v1 < INDEXMAP_SIZE) && (v2 < INDEXMAP_SIZE))
92    {
93       OGL_AddTriangle(v0, v1, v2);
94    }
95 
96    if (depthBuffer.current) depthBuffer.current->cleared = false;
97    gDP.colorImage.height = (uint32_t)(MAX( gDP.colorImage.height, (uint32_t)gDP.scissor.lry ));
98 }
99 
gln64gSP1Triangle(int32_t v0,int32_t v1,int32_t v2,int flags)100 void gln64gSP1Triangle( int32_t v0, int32_t v1, int32_t v2, int flags)
101 {
102    gln64gSPTriangle( v0, v1, v2);
103    gln64gSPFlushTriangles();
104 }
105 
gln64gSP2Triangles(const int32_t v00,const int32_t v01,const int32_t v02,const int32_t flag0,const int32_t v10,const int32_t v11,const int32_t v12,const int32_t flag1)106 void gln64gSP2Triangles(const int32_t v00, const int32_t v01, const int32_t v02, const int32_t flag0,
107                     const int32_t v10, const int32_t v11, const int32_t v12, const int32_t flag1 )
108 {
109    gln64gSPTriangle( v00, v01, v02);
110    gln64gSPTriangle( v10, v11, v12);
111    gln64gSPFlushTriangles();
112 }
113 
gln64gSP4Triangles(const int32_t v00,const int32_t v01,const int32_t v02,const int32_t v10,const int32_t v11,const int32_t v12,const int32_t v20,const int32_t v21,const int32_t v22,const int32_t v30,const int32_t v31,const int32_t v32)114 void gln64gSP4Triangles(const int32_t v00, const int32_t v01, const int32_t v02,
115                     const int32_t v10, const int32_t v11, const int32_t v12,
116                     const int32_t v20, const int32_t v21, const int32_t v22,
117                     const int32_t v30, const int32_t v31, const int32_t v32 )
118 {
119    gln64gSPTriangle(v00, v01, v02);
120    gln64gSPTriangle(v10, v11, v12);
121    gln64gSPTriangle(v20, v21, v22);
122    gln64gSPTriangle(v30, v31, v32);
123    gln64gSPFlushTriangles();
124 }
125 
gln64gSPTransformVertex_default(float vtx[4],float mtx[4][4])126 static void gln64gSPTransformVertex_default(float vtx[4], float mtx[4][4])
127 {
128    float x, y, z, w;
129    x = vtx[0];
130    y = vtx[1];
131    z = vtx[2];
132    w = vtx[3];
133 
134    vtx[0] = x * mtx[0][0] + y * mtx[1][0] + z * mtx[2][0] + mtx[3][0];
135    vtx[1] = x * mtx[0][1] + y * mtx[1][1] + z * mtx[2][1] + mtx[3][1];
136    vtx[2] = x * mtx[0][2] + y * mtx[1][2] + z * mtx[2][2] + mtx[3][2];
137    vtx[3] = x * mtx[0][3] + y * mtx[1][3] + z * mtx[2][3] + mtx[3][3];
138 }
139 
gln64gSPLightVertex_default(void * data)140 static void gln64gSPLightVertex_default(void *data)
141 {
142    struct SPVertex * _vtx = (struct SPVertex*)data;
143 	if (!config.generalEmulation.enableHWLighting)
144    {
145       unsigned i;
146 
147       _vtx->HWLight = 0;
148       _vtx->r = gSP.lights[gSP.numLights].r;
149       _vtx->g = gSP.lights[gSP.numLights].g;
150       _vtx->b = gSP.lights[gSP.numLights].b;
151 
152       for (i = 0; i < gSP.numLights; i++)
153       {
154          float intensity = DotProduct( &_vtx->nx, &gSP.lights[i].x );
155          if (intensity < 0.0f)
156             intensity = 0.0f;
157          _vtx->r += gSP.lights[i].r * intensity;
158          _vtx->g += gSP.lights[i].g * intensity;
159          _vtx->b += gSP.lights[i].b * intensity;
160       }
161 
162       _vtx->r = MIN(1.0f, _vtx->r);
163       _vtx->g = MIN(1.0f, _vtx->g);
164       _vtx->b = MIN(1.0f, _vtx->b);
165    }
166    else
167    {
168       /* TODO/FIXME - update with gliden64 code */
169    }
170 
171 }
172 
gln64gSPPointLightVertex_default(void * data,float * _vPos)173 static void gln64gSPPointLightVertex_default(void *data, float * _vPos)
174 {
175    uint32_t l;
176    float light_intensity = 0.0f;
177    struct SPVertex *_vtx = (struct SPVertex*)data;
178 
179    assert(_vPos != NULL);
180    _vtx->HWLight = 0;
181    _vtx->r = gSP.lights[gSP.numLights].r;
182    _vtx->g = gSP.lights[gSP.numLights].g;
183    _vtx->b = gSP.lights[gSP.numLights].b;
184 
185    for (l = 0; l < gSP.numLights; ++l)
186    {
187       float light_len2, light_len, at;
188       float lvec[3] = {gSP.lights[l].posx, gSP.lights[l].posy, gSP.lights[l].posz};
189       lvec[0] -= _vPos[0];
190       lvec[1] -= _vPos[1];
191       lvec[2] -= _vPos[2];
192       light_len2 = lvec[0]*lvec[0] + lvec[1]*lvec[1] + lvec[2]*lvec[2];
193       light_len = sqrtf(light_len2);
194       at = gSP.lights[l].ca + light_len/65535.0f*gSP.lights[l].la + light_len2/65535.0f*gSP.lights[l].qa;
195 
196       if (at > 0.0f)
197          light_intensity = 1/at;//DotProduct (lvec, nvec) / (light_len * normal_len * at);
198       else
199          light_intensity = 0.0f;
200 
201       if (light_intensity > 0.0f)
202       {
203          _vtx->r += gSP.lights[l].r * light_intensity;
204          _vtx->g += gSP.lights[l].g * light_intensity;
205          _vtx->b += gSP.lights[l].b * light_intensity;
206       }
207    }
208    if (_vtx->r > 1.0f)  _vtx->r = 1.0f;
209    if (_vtx->g > 1.0f)  _vtx->g = 1.0f;
210    if (_vtx->b > 1.0f)  _vtx->b = 1.0f;
211 }
212 
gln64gSPLightVertex_CBFD(void * data)213 static void gln64gSPLightVertex_CBFD(void *data)
214 {
215    struct SPVertex *_vtx = (struct SPVertex*)data;
216    uint32_t l;
217 	float r = gSP.lights[gSP.numLights].r;
218 	float g = gSP.lights[gSP.numLights].g;
219 	float b = gSP.lights[gSP.numLights].b;
220 
221 	for (l = 0; l < gSP.numLights; ++l)
222    {
223       const struct SPLight *light = (const struct SPLight*)&gSP.lights[l];
224       const float vx = (_vtx->x + gSP.vertexCoordMod[ 8])*gSP.vertexCoordMod[12] - light->posx;
225       const float vy = (_vtx->y + gSP.vertexCoordMod[ 9])*gSP.vertexCoordMod[13] - light->posy;
226       const float vz = (_vtx->z + gSP.vertexCoordMod[10])*gSP.vertexCoordMod[14] - light->posz;
227       const float vw = (_vtx->w + gSP.vertexCoordMod[11])*gSP.vertexCoordMod[15] - light->posw;
228       const float len = (vx*vx+vy*vy+vz*vz+vw*vw)/65536.0f;
229       float intensity = light->ca / len;
230       if (intensity > 1.0f)
231          intensity = 1.0f;
232       r += light->r * intensity;
233       g += light->g * intensity;
234       b += light->b * intensity;
235    }
236 
237 	r = MIN(1.0f, r);
238 	g = MIN(1.0f, g);
239 	b = MIN(1.0f, b);
240 
241 	_vtx->r *= r;
242 	_vtx->g *= g;
243 	_vtx->b *= b;
244 	_vtx->HWLight = 0;
245 }
246 
gln64gSPPointLightVertex_CBFD(void * data,float * _vPos)247 static void gln64gSPPointLightVertex_CBFD(void *data, float * _vPos)
248 {
249    uint32_t l;
250    const struct SPLight *light = NULL;
251    struct SPVertex *_vtx = (struct SPVertex*)data;
252 	float r = gSP.lights[gSP.numLights].r;
253 	float g = gSP.lights[gSP.numLights].g;
254 	float b = gSP.lights[gSP.numLights].b;
255 
256 	float intensity = 0.0f;
257 
258 	for (l = 0; l < gSP.numLights-1; ++l)
259    {
260 		light = (struct SPLight*)&gSP.lights[l];
261 		intensity = DotProduct( &_vtx->nx, &light->x );
262 
263 		if (intensity < 0.0f)
264 			continue;
265 
266 		if (light->ca > 0.0f)
267       {
268 			const float vx = (_vtx->x + gSP.vertexCoordMod[ 8])*gSP.vertexCoordMod[12] - light->posx;
269 			const float vy = (_vtx->y + gSP.vertexCoordMod[ 9])*gSP.vertexCoordMod[13] - light->posy;
270 			const float vz = (_vtx->z + gSP.vertexCoordMod[10])*gSP.vertexCoordMod[14] - light->posz;
271 			const float vw = (_vtx->w + gSP.vertexCoordMod[11])*gSP.vertexCoordMod[15] - light->posw;
272 			const float len = (vx*vx+vy*vy+vz*vz+vw*vw)/65536.0f;
273 			float p_i = light->ca / len;
274 			if (p_i > 1.0f) p_i = 1.0f;
275 			intensity *= p_i;
276 		}
277 		r += light->r * intensity;
278 		g += light->g * intensity;
279 		b += light->b * intensity;
280 	}
281 
282 	light = (struct SPLight*)&gSP.lights[gSP.numLights-1];
283 
284 	intensity = DotProduct( &_vtx->nx, &light->x );
285 
286 	if (intensity > 0.0f)
287    {
288 		r += light->r * intensity;
289 		g += light->g * intensity;
290 		b += light->b * intensity;
291 	}
292 
293 	r = MIN(1.0f, r);
294 	g = MIN(1.0f, g);
295 	b = MIN(1.0f, b);
296 
297 	_vtx->r *= r;
298 	_vtx->g *= g;
299 	_vtx->b *= b;
300 	_vtx->HWLight = 0;
301 }
302 
gln64gSPBillboardVertex_default(uint32_t v,uint32_t i)303 static void gln64gSPBillboardVertex_default(uint32_t v, uint32_t i)
304 {
305    struct SPVertex *vtx0 = (struct SPVertex*)&OGL.triangles.vertices[i];
306    struct SPVertex *vtx  = (struct SPVertex*)&OGL.triangles.vertices[v];
307 
308    vtx->x += vtx0->x;
309    vtx->y += vtx0->y;
310    vtx->z += vtx0->z;
311    vtx->w += vtx0->w;
312 }
313 
gln64gSPClipVertex(uint32_t v)314 void gln64gSPClipVertex(uint32_t v)
315 {
316    struct SPVertex *vtx = &OGL.triangles.vertices[v];
317    vtx->clip = 0;
318    if (vtx->x > +vtx->w)   vtx->clip |= CLIP_POSX;
319    if (vtx->x < -vtx->w)   vtx->clip |= CLIP_NEGX;
320    if (vtx->y > +vtx->w)   vtx->clip |= CLIP_POSY;
321    if (vtx->y < -vtx->w)   vtx->clip |= CLIP_NEGY;
322    if (vtx->w < 0.01f)      vtx->clip |= CLIP_Z;
323 }
324 
gln64gSPProcessVertex(uint32_t v)325 void gln64gSPProcessVertex(uint32_t v)
326 {
327 
328    float intensity, r, g, b;
329    struct SPVertex *vtx = (struct SPVertex*)&OGL.triangles.vertices[v];
330 
331    if (gSP.changed & CHANGED_MATRIX)
332       gln64gSPCombineMatrices();
333 
334    gln64gSPTransformVertex( &vtx->x, gSP.matrix.combined );
335 
336    if (gSP.viewport.vscale[0] < 0)
337 		vtx->x = -vtx->x;
338 
339    if (gSP.matrix.billboard)
340    {
341       int i = 0;
342 
343       gln64gSPBillboardVertex(v, i);
344    }
345 
346    gln64gSPClipVertex(v);
347 
348    if (gSP.geometryMode & G_LIGHTING)
349    {
350       float vPos[3];
351       vPos[0] = (float)vtx->x;
352       vPos[1] = (float)vtx->y;
353       vPos[2] = (float)vtx->z;
354 
355       TransformVectorNormalize( &vtx->nx, gSP.matrix.modelView[gSP.matrix.modelViewi] );
356 		if (gSP.geometryMode & G_POINT_LIGHTING)
357 			gln64gSPPointLightVertex(vtx, vPos);
358       else
359 			gln64gSPLightVertex(vtx);
360 
361       if (/* GBI.isTextureGen() && */ gSP.geometryMode & G_TEXTURE_GEN)
362       {
363 			float fLightDir[3] = {vtx->nx, vtx->ny, vtx->nz};
364 			float x, y;
365 
366 			if (gSP.lookatEnable)
367          {
368 				x = DotProduct(&gSP.lookat[0].x, fLightDir);
369 				y = DotProduct(&gSP.lookat[1].x, fLightDir);
370 			}
371          else
372          {
373 				x = fLightDir[0];
374 				y = fLightDir[1];
375 			}
376 
377          if (gSP.geometryMode & G_TEXTURE_GEN_LINEAR)
378          {
379             vtx->s = acosf(x) * 325.94931f;
380             vtx->t = acosf(y) * 325.94931f;
381          }
382          else /* G_TEXTURE_GEN */
383          {
384             vtx->s = (x + 1.0f) * 512.0f;
385             vtx->t = (y + 1.0f) * 512.0f;
386          }
387       }
388    }
389    else
390 		vtx->HWLight = 0;
391 }
392 
gln64gSPLoadUcodeEx(uint32_t uc_start,uint32_t uc_dstart,uint16_t uc_dsize)393 void gln64gSPLoadUcodeEx( uint32_t uc_start, uint32_t uc_dstart, uint16_t uc_dsize )
394 {
395    MicrocodeInfo *ucode;
396    __RSP.PCi = 0;
397    gSP.matrix.modelViewi = 0;
398    gSP.changed |= CHANGED_MATRIX;
399    gSP.status[0] = gSP.status[1] = gSP.status[2] = gSP.status[3] = 0;
400 
401    if ((((uc_start & 0x1FFFFFFF) + 4096) > RDRAMSize) || (((uc_dstart & 0x1FFFFFFF) + uc_dsize) > RDRAMSize))
402       return;
403 
404    ucode = (MicrocodeInfo*)GBI_DetectMicrocode( uc_start, uc_dstart, uc_dsize );
405 
406    __RSP.uc_start  = uc_start;
407    __RSP.uc_dstart = uc_dstart;
408 
409    /* TODO/FIXME - remove this maybe? for gliden64 */
410    if (ucode->type != 0xFFFFFFFF)
411       last_good_ucode = ucode->type;
412 
413    if (ucode->type != NONE)
414       GBI_MakeCurrent( ucode );
415    else
416    {
417       LOG(LOG_WARNING, "Unknown Ucode\n");
418    }
419 }
420 
gln64gSPCombineMatrices(void)421 void gln64gSPCombineMatrices(void)
422 {
423    MultMatrix(gSP.matrix.projection, gSP.matrix.modelView[gSP.matrix.modelViewi], gSP.matrix.combined);
424    gSP.changed &= ~CHANGED_MATRIX;
425 }
426 
gln64gSPNoOp(void)427 void gln64gSPNoOp(void)
428 {
429    gln64gSPFlushTriangles();
430 }
431 
gln64gSPMatrix(uint32_t matrix,uint8_t param)432 void gln64gSPMatrix( uint32_t matrix, uint8_t param )
433 {
434    float mtx[4][4];
435    uint32_t address = RSP_SegmentToPhysical( matrix );
436 
437    if (address + 64 > RDRAMSize)
438       return;
439 
440    RSP_LoadMatrix( mtx, address );
441 
442    if (param & G_MTX_PROJECTION)
443    {
444       if (param & G_MTX_LOAD)
445          CopyMatrix( gSP.matrix.projection, mtx );
446       else
447          MultMatrix2( gSP.matrix.projection, mtx );
448    }
449    else
450    {
451       if ((param & G_MTX_PUSH) && (gSP.matrix.modelViewi < (gSP.matrix.stackSize - 1)))
452       {
453          CopyMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi + 1], gSP.matrix.modelView[gSP.matrix.modelViewi] );
454          gSP.matrix.modelViewi++;
455       }
456       if (param & G_MTX_LOAD)
457          CopyMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi], mtx );
458       else
459          MultMatrix2( gSP.matrix.modelView[gSP.matrix.modelViewi], mtx );
460    }
461 
462    gSP.changed |= CHANGED_MATRIX;
463 }
464 
gln64gSPDMAMatrix(uint32_t matrix,uint8_t index,uint8_t multiply)465 void gln64gSPDMAMatrix( uint32_t matrix, uint8_t index, uint8_t multiply )
466 {
467    float mtx[4][4];
468    uint32_t address = gSP.DMAOffsets.mtx + RSP_SegmentToPhysical( matrix );
469 
470    if (address + 64 > RDRAMSize)
471       return;
472 
473    RSP_LoadMatrix( mtx, address );
474 
475    gSP.matrix.modelViewi = index;
476 
477    if (multiply)
478       MultMatrix(gSP.matrix.modelView[0], mtx, gSP.matrix.modelView[gSP.matrix.modelViewi]);
479    else
480       CopyMatrix( gSP.matrix.modelView[gSP.matrix.modelViewi], mtx );
481 
482    CopyMatrix( gSP.matrix.projection, identityMatrix );
483 
484    gSP.changed |= CHANGED_MATRIX;
485 }
486 
gln64gSPViewport(uint32_t v)487 void gln64gSPViewport(uint32_t v)
488 {
489    uint32_t address = RSP_SegmentToPhysical( v );
490 
491    if ((address + 16) > RDRAMSize)
492       return;
493 
494    gSP.viewport.vscale[0] = _FIXED2FLOAT( *(int16_t*)&gfx_info.RDRAM[address +  2], 2 );
495    gSP.viewport.vscale[1] = _FIXED2FLOAT( *(int16_t*)&gfx_info.RDRAM[address     ], 2 );
496    gSP.viewport.vscale[2] = _FIXED2FLOAT( *(int16_t*)&gfx_info.RDRAM[address +  6], 10 ); /* * 0.00097847357f; */
497    gSP.viewport.vscale[3] = *(int16_t*)&gfx_info.RDRAM[address +  4];
498    gSP.viewport.vtrans[0] = _FIXED2FLOAT( *(int16_t*)&gfx_info.RDRAM[address + 10], 2 );
499    gSP.viewport.vtrans[1] = _FIXED2FLOAT( *(int16_t*)&gfx_info.RDRAM[address +  8], 2 );
500    gSP.viewport.vtrans[2] = _FIXED2FLOAT( *(int16_t*)&gfx_info.RDRAM[address + 14], 10 ); /* * 0.00097847357f; */
501    gSP.viewport.vtrans[3] = *(int16_t*)&gfx_info.RDRAM[address + 12];
502 
503    gSP.viewport.x      = gSP.viewport.vtrans[0] - gSP.viewport.vscale[0];
504    gSP.viewport.y      = gSP.viewport.vtrans[1] - gSP.viewport.vscale[1];
505    gSP.viewport.width  = fabs(gSP.viewport.vscale[0]) * 2;
506    gSP.viewport.height = fabs(gSP.viewport.vscale[1]) * 2;
507    gSP.viewport.nearz  = gSP.viewport.vtrans[2] - gSP.viewport.vscale[2];
508    gSP.viewport.farz   = (gSP.viewport.vtrans[2] + gSP.viewport.vscale[2]) ;
509 
510    gSP.changed |= CHANGED_VIEWPORT;
511 }
512 
gln64gSPForceMatrix(uint32_t mptr)513 void gln64gSPForceMatrix( uint32_t mptr )
514 {
515    uint32_t address = RSP_SegmentToPhysical( mptr );
516 
517    if (address + 64 > RDRAMSize)
518       return;
519 
520    RSP_LoadMatrix( gSP.matrix.combined, address);
521 
522    gSP.changed &= ~CHANGED_MATRIX;
523 }
524 
gln64gSPLight(uint32_t l,int32_t n)525 void gln64gSPLight( uint32_t l, int32_t n )
526 {
527    uint32_t addrByte;
528    Light *light = NULL;
529 
530 	--n;
531 	addrByte = RSP_SegmentToPhysical( l );
532 
533 	if ((addrByte + sizeof( Light )) > RDRAMSize)
534 		return;
535 
536 	light = (Light*)&gfx_info.RDRAM[addrByte];
537 
538 	if (n < 8)
539    {
540       uint32_t addrShort;
541 
542 		gSP.lights[n].r = light->r * 0.0039215689f;
543 		gSP.lights[n].g = light->g * 0.0039215689f;
544 		gSP.lights[n].b = light->b * 0.0039215689f;
545 
546 		gSP.lights[n].x = light->x;
547 		gSP.lights[n].y = light->y;
548 		gSP.lights[n].z = light->z;
549 
550 		NormalizeVector( &gSP.lights[n].x );
551 		addrShort = addrByte >> 1;
552 		gSP.lights[n].posx = (float)(((short*)gfx_info.RDRAM)[(addrShort+4)^1]);
553 		gSP.lights[n].posy = (float)(((short*)gfx_info.RDRAM)[(addrShort+5)^1]);
554 		gSP.lights[n].posz = (float)(((short*)gfx_info.RDRAM)[(addrShort+6)^1]);
555 		gSP.lights[n].ca = (float)(gfx_info.RDRAM[(addrByte + 3) ^ 3]) / 16.0f;
556 		gSP.lights[n].la = (float)(gfx_info.RDRAM[(addrByte + 7) ^ 3]);
557 		gSP.lights[n].qa = (float)(gfx_info.RDRAM[(addrByte + 14) ^ 3]) / 8.0f;
558 	}
559 
560 	if (config.generalEmulation.enableHWLighting != 0)
561 		gSP.changed |= CHANGED_LIGHT;
562 }
563 
gln64gSPLightCBFD(uint32_t l,int32_t n)564 void gln64gSPLightCBFD( uint32_t l, int32_t n )
565 {
566    Light *light = NULL;
567 	uint32_t addrByte = RSP_SegmentToPhysical( l );
568 
569 	if ((addrByte + sizeof( Light )) > RDRAMSize)
570 		return;
571 
572 	light = (Light*)&gfx_info.RDRAM[addrByte];
573 
574 	if (n < 12)
575    {
576 	   uint32_t addrShort;
577 
578 		gSP.lights[n].r = light->r * 0.0039215689f;
579 		gSP.lights[n].g = light->g * 0.0039215689f;
580 		gSP.lights[n].b = light->b * 0.0039215689f;
581 
582 		gSP.lights[n].x = light->x;
583 		gSP.lights[n].y = light->y;
584 		gSP.lights[n].z = light->z;
585 
586 		NormalizeVector( &gSP.lights[n].x );
587 		addrShort = addrByte >> 1;
588 		gSP.lights[n].posx = (float)(((int16_t*)gfx_info.RDRAM)[(addrShort+16)^1]);
589 		gSP.lights[n].posy = (float)(((int16_t*)gfx_info.RDRAM)[(addrShort+17)^1]);
590 		gSP.lights[n].posz = (float)(((int16_t*)gfx_info.RDRAM)[(addrShort+18)^1]);
591 		gSP.lights[n].posw = (float)(((int16_t*)gfx_info.RDRAM)[(addrShort+19)^1]);
592 		gSP.lights[n].ca = (float)(gfx_info.RDRAM[(addrByte + 12) ^ 3]) / 16.0f;
593 	}
594 
595 	if (config.generalEmulation.enableHWLighting != 0)
596 		gSP.changed |= CHANGED_LIGHT;
597 }
598 
gln64gSPLookAt(uint32_t _l,uint32_t _n)599 void gln64gSPLookAt( uint32_t _l, uint32_t _n )
600 {
601 	Light *light;
602    uint32_t address = RSP_SegmentToPhysical(_l);
603 
604    if ((address + sizeof(Light)) > RDRAMSize)
605       return;
606 
607    assert(_n < 2);
608 
609    light = (Light*)&gfx_info.RDRAM[address];
610 
611    gSP.lookat[_n].x = light->x;
612    gSP.lookat[_n].y = light->y;
613    gSP.lookat[_n].z = light->z;
614 
615    gSP.lookatEnable = (_n == 0) || (_n == 1 && (light->x != 0 || light->y != 0));
616 
617    NormalizeVector(&gSP.lookat[_n].x);
618 }
619 
gln64gSPVertex(uint32_t v,uint32_t n,uint32_t v0)620 void gln64gSPVertex( uint32_t v, uint32_t n, uint32_t v0 )
621 {
622    unsigned int i;
623    Vertex *vertex;
624    uint32_t address = RSP_SegmentToPhysical( v );
625 
626    if ((address + sizeof( Vertex ) * n) > RDRAMSize)
627       return;
628 
629    vertex = (Vertex*)&gfx_info.RDRAM[address];
630 
631    if ((n + v0) <= INDEXMAP_SIZE)
632    {
633       for (i = v0; i < n + v0; i++)
634       {
635          uint32_t v = i;
636          struct SPVertex *vtx = (struct SPVertex*)&OGL.triangles.vertices[v];
637 
638          vtx->x = vertex->x;
639          vtx->y = vertex->y;
640          vtx->z = vertex->z;
641          vtx->s = _FIXED2FLOAT( vertex->s, 5 );
642          vtx->t = _FIXED2FLOAT( vertex->t, 5 );
643 
644          if (gSP.geometryMode & G_LIGHTING)
645          {
646             vtx->nx = vertex->normal.x;
647             vtx->ny = vertex->normal.y;
648             vtx->nz = vertex->normal.z;
649             vtx->a = vertex->color.a * 0.0039215689f;
650          }
651          else
652          {
653             vtx->r = vertex->color.r * 0.0039215689f;
654             vtx->g = vertex->color.g * 0.0039215689f;
655             vtx->b = vertex->color.b * 0.0039215689f;
656             vtx->a = vertex->color.a * 0.0039215689f;
657          }
658 
659          gln64gSPProcessVertex(v);
660          vertex++;
661       }
662    }
663 }
664 
gln64gSPCIVertex(uint32_t v,uint32_t n,uint32_t v0)665 void gln64gSPCIVertex( uint32_t v, uint32_t n, uint32_t v0 )
666 {
667    unsigned int i;
668    PDVertex *vertex;
669 
670    uint32_t address = RSP_SegmentToPhysical( v );
671 
672    if ((address + sizeof( PDVertex ) * n) > RDRAMSize)
673       return;
674 
675    vertex = (PDVertex*)&gfx_info.RDRAM[address];
676 
677    if ((n + v0) <= INDEXMAP_SIZE)
678    {
679       for(i = v0; i < n + v0; i++)
680       {
681          uint8_t *color;
682          uint32_t v = i;
683          struct SPVertex *vtx = (struct SPVertex*)&OGL.triangles.vertices[v];
684          vtx->x = vertex->x;
685          vtx->y = vertex->y;
686          vtx->z = vertex->z;
687          vtx->s = _FIXED2FLOAT( vertex->s, 5 );
688          vtx->t = _FIXED2FLOAT( vertex->t, 5 );
689 
690          color = (uint8_t*)&gfx_info.RDRAM[gSP.vertexColorBase + (vertex->ci & 0xff)];
691 
692          if (gSP.geometryMode & G_LIGHTING)
693          {
694             vtx->nx = (int8_t)color[3];
695             vtx->ny = (int8_t)color[2];
696             vtx->nz = (int8_t)color[1];
697             vtx->a = color[0] * 0.0039215689f;
698          }
699          else
700          {
701             vtx->r = color[3] * 0.0039215689f;
702             vtx->g = color[2] * 0.0039215689f;
703             vtx->b = color[1] * 0.0039215689f;
704             vtx->a = color[0] * 0.0039215689f;
705          }
706 
707          gln64gSPProcessVertex(v);
708          vertex++;
709       }
710    }
711 }
712 
gln64gSPDMAVertex(uint32_t v,uint32_t n,uint32_t v0)713 void gln64gSPDMAVertex( uint32_t v, uint32_t n, uint32_t v0 )
714 {
715    unsigned int i;
716    uint32_t address = gSP.DMAOffsets.vtx + RSP_SegmentToPhysical( v );
717 
718    if ((address + 10 * n) > RDRAMSize)
719       return;
720 
721    if ((n + v0) <= INDEXMAP_SIZE)
722    {
723       for (i = v0; i < n + v0; i++)
724       {
725          uint32_t v = i;
726          struct SPVertex *vtx = (struct SPVertex*)&OGL.triangles.vertices[v];
727 
728          vtx->x = *(int16_t*)&gfx_info.RDRAM[address ^ 2];
729          vtx->y = *(int16_t*)&gfx_info.RDRAM[(address + 2) ^ 2];
730          vtx->z = *(int16_t*)&gfx_info.RDRAM[(address + 4) ^ 2];
731 
732          if (gSP.geometryMode & G_LIGHTING)
733          {
734             vtx->nx = *(int8_t*)&gfx_info.RDRAM[(address + 6) ^ 3];
735             vtx->ny = *(int8_t*)&gfx_info.RDRAM[(address + 7) ^ 3];
736             vtx->nz = *(int8_t*)&gfx_info.RDRAM[(address + 8) ^ 3];
737             vtx->a = *(uint8_t*)&gfx_info.RDRAM[(address + 9) ^ 3] * 0.0039215689f;
738          }
739          else
740          {
741             vtx->r = *(uint8_t*)&gfx_info.RDRAM[(address + 6) ^ 3] * 0.0039215689f;
742             vtx->g = *(uint8_t*)&gfx_info.RDRAM[(address + 7) ^ 3] * 0.0039215689f;
743             vtx->b = *(uint8_t*)&gfx_info.RDRAM[(address + 8) ^ 3] * 0.0039215689f;
744             vtx->a = *(uint8_t*)&gfx_info.RDRAM[(address + 9) ^ 3] * 0.0039215689f;
745          }
746 
747          gln64gSPProcessVertex(v);
748          address += 10;
749       }
750    }
751 }
752 
gln64gSPCBFDVertex(uint32_t a,uint32_t n,uint32_t v0)753 void gln64gSPCBFDVertex( uint32_t a, uint32_t n, uint32_t v0 )
754 {
755 	Vertex *vertex;
756 	uint32_t address = RSP_SegmentToPhysical(a);
757 
758 	if ((address + sizeof( Vertex ) * n) > RDRAMSize)
759 		return;
760 
761 	vertex = (Vertex*)&gfx_info.RDRAM[address];
762 
763 	if ((n + v0) <= INDEXMAP_SIZE)
764    {
765 		unsigned int i = v0;
766 		for (; i < n + v0; ++i)
767       {
768 			uint32_t v = i;
769          struct SPVertex *vtx = (struct SPVertex*)&OGL.triangles.vertices[v];
770 
771 			vtx->x = vertex->x;
772 			vtx->y = vertex->y;
773 			vtx->z = vertex->z;
774 			vtx->s = _FIXED2FLOAT( vertex->s, 5 );
775 			vtx->t = _FIXED2FLOAT( vertex->t, 5 );
776 			if (gSP.geometryMode & G_LIGHTING)
777          {
778 				const uint32_t normaleAddrOffset = (v<<1);
779 				vtx->nx = (float)(((int8_t*)gfx_info.RDRAM)[(gSP.vertexNormalBase + normaleAddrOffset + 0)^3]);
780 				vtx->ny = (float)(((int8_t*)gfx_info.RDRAM)[(gSP.vertexNormalBase + normaleAddrOffset + 1)^3]);
781 				vtx->nz = (float)((int8_t)(vertex->flag&0xFF));
782 			}
783 			vtx->r = vertex->color.r * 0.0039215689f;
784 			vtx->g = vertex->color.g * 0.0039215689f;
785 			vtx->b = vertex->color.b * 0.0039215689f;
786 			vtx->a = vertex->color.a * 0.0039215689f;
787 			gln64gSPProcessVertex(v);
788 			vertex++;
789 		}
790 	} else {
791 		LOG(LOG_ERROR, "Using Vertex outside buffer v0=%i, n=%i\n", v0, n);
792 	}
793 }
794 
gln64gSPDisplayList(uint32_t dl)795 void gln64gSPDisplayList( uint32_t dl )
796 {
797    uint32_t address = RSP_SegmentToPhysical( dl );
798 
799    if ((address + 8) > RDRAMSize)
800       return;
801 
802    if (__RSP.PCi < (GBI.PCStackSize - 1))
803    {
804       __RSP.PCi++;
805       __RSP.PC[__RSP.PCi] = address;
806       __RSP.nextCmd = _SHIFTR( *(uint32_t*)&gfx_info.RDRAM[address], 24, 8 );
807    }
808 }
809 
gln64gSPBranchList(uint32_t dl)810 void gln64gSPBranchList( uint32_t dl )
811 {
812    uint32_t address = RSP_SegmentToPhysical( dl );
813 
814    if ((address + 8) > RDRAMSize)
815       return;
816 
817    __RSP.PC[__RSP.PCi] = address;
818    __RSP.nextCmd = _SHIFTR( *(uint32_t*)&gfx_info.RDRAM[address], 24, 8 );
819 }
820 
gln64gSPBranchLessZ(uint32_t branchdl,uint32_t vtx,float zval)821 void gln64gSPBranchLessZ( uint32_t branchdl, uint32_t vtx, float zval )
822 {
823    float zTest;
824    struct SPVertex      *v = NULL;
825    uint32_t address = RSP_SegmentToPhysical( branchdl );
826 
827    if ((address + 8) > RDRAMSize)
828       return;
829 
830    v = (struct SPVertex*)&OGL.triangles.vertices[vtx];
831    zTest = v->z / v->w;
832 
833    if (zTest > 1.0f || zTest <= zval)
834       __RSP.PC[__RSP.PCi] = address;
835 }
836 
gln64gSPDlistCount(uint32_t count,uint32_t v)837 void gln64gSPDlistCount(uint32_t count, uint32_t v)
838 {
839 	uint32_t address = RSP_SegmentToPhysical( v );
840 	if (address == 0 || (address + 8) > RDRAMSize)
841 		return;
842 
843 	if (__RSP.PCi >= 9)
844 		return;
845 
846 	++__RSP.PCi;  /* go to the next PC in the stack */
847 	__RSP.PC[__RSP.PCi] = address;  /* jump to the address */
848 	__RSP.nextCmd = _SHIFTR( *(uint32_t*)&gfx_info.RDRAM[address], 24, 8 );
849 	__RSP.count = count + 1;
850 }
851 
gln64gSPSetDMAOffsets(uint32_t mtxoffset,uint32_t vtxoffset)852 void gln64gSPSetDMAOffsets( uint32_t mtxoffset, uint32_t vtxoffset )
853 {
854    gSP.DMAOffsets.mtx = mtxoffset;
855    gSP.DMAOffsets.vtx = vtxoffset;
856 }
857 
gln64gSPSetDMATexOffset(uint32_t _addr)858 void gln64gSPSetDMATexOffset(uint32_t _addr)
859 {
860 	gSP.DMAOffsets.tex_offset = RSP_SegmentToPhysical(_addr);
861 	gSP.DMAOffsets.tex_shift = 0;
862 	gSP.DMAOffsets.tex_count = 0;
863 }
864 
gln64gSPSetVertexColorBase(uint32_t base)865 void gln64gSPSetVertexColorBase( uint32_t base )
866 {
867    gSP.vertexColorBase = RSP_SegmentToPhysical( base );
868 }
869 
gln64gSPSetVertexNormaleBase(uint32_t base)870 void gln64gSPSetVertexNormaleBase( uint32_t base )
871 {
872 	gSP.vertexNormalBase = RSP_SegmentToPhysical( base );
873 }
874 
gln64gSPDMATriangles(uint32_t tris,uint32_t n)875 void gln64gSPDMATriangles( uint32_t tris, uint32_t n )
876 {
877    unsigned int i;
878    int32_t v0, v1, v2;
879    struct SPVertex *pVtx;
880    DKRTriangle *triangles;
881    uint32_t address = RSP_SegmentToPhysical( tris );
882 
883    if (address + sizeof( DKRTriangle ) * n > RDRAMSize)
884       return;
885 
886    triangles = (DKRTriangle*)&gfx_info.RDRAM[address];
887 
888    for (i = 0; i < n; i++)
889    {
890       int mode = 0;
891       if (!(triangles->flag & 0x40))
892       {
893          if (gSP.viewport.vscale[0] > 0)
894             mode |= G_CULL_BACK;
895          else
896             mode |= G_CULL_FRONT;
897       }
898 
899       if ((gSP.geometryMode&G_CULL_BOTH) != mode)
900       {
901          gSP.geometryMode &= ~G_CULL_BOTH;
902          gSP.geometryMode |= mode;
903          gSP.changed |= CHANGED_GEOMETRYMODE;
904       }
905 
906       v0 = triangles->v0;
907       v1 = triangles->v1;
908       v2 = triangles->v2;
909       OGL.triangles.vertices[v0].s = _FIXED2FLOAT( triangles->s0, 5 );
910       OGL.triangles.vertices[v0].t = _FIXED2FLOAT( triangles->t0, 5 );
911       OGL.triangles.vertices[v1].s = _FIXED2FLOAT( triangles->s1, 5 );
912       OGL.triangles.vertices[v1].t = _FIXED2FLOAT( triangles->t1, 5 );
913       OGL.triangles.vertices[v2].s = _FIXED2FLOAT( triangles->s2, 5 );
914       OGL.triangles.vertices[v2].t = _FIXED2FLOAT( triangles->t2, 5 );
915       triangles++;
916    }
917 
918    OGL_DrawTriangles();
919 }
920 
gln64gSP1Quadrangle(int32_t v0,int32_t v1,int32_t v2,int32_t v3)921 void gln64gSP1Quadrangle( int32_t v0, int32_t v1, int32_t v2, int32_t v3)
922 {
923    gln64gSPTriangle( v0, v1, v2);
924    gln64gSPTriangle( v0, v2, v3);
925    gln64gSPFlushTriangles();
926 }
927 
gln64gSPCullVertices(uint32_t v0,uint32_t vn)928 bool gln64gSPCullVertices( uint32_t v0, uint32_t vn )
929 {
930    unsigned int i;
931    uint32_t clip = 0;
932 	if (vn < v0)
933    {
934       // Aidyn Chronicles - The First Mage seems to pass parameters in reverse order.
935       const uint32_t v = v0;
936       v0 = vn;
937       vn = v;
938    }
939 
940    for (i = v0 + 1; i <= vn; i++)
941    {
942       clip |= (~OGL.triangles.vertices[i].clip) & CLIP_ALL;
943       if (clip == CLIP_ALL)
944          return false;
945    }
946    return true;
947 }
948 
_loadSpriteImage(const struct uSprite * _pSprite)949 static void _loadSpriteImage(const struct uSprite *_pSprite)
950 {
951 	gSP.bgImage.address = RSP_SegmentToPhysical( _pSprite->imagePtr );
952 
953 	gSP.bgImage.width = _pSprite->stride;
954 	gSP.bgImage.height = _pSprite->imageY + _pSprite->imageH;
955 	gSP.bgImage.format = _pSprite->imageFmt;
956 	gSP.bgImage.size = _pSprite->imageSiz;
957 	gSP.bgImage.palette = 0;
958 	gDP.tiles[0].textureMode = TEXTUREMODE_BGIMAGE;
959 	gSP.bgImage.imageX = _pSprite->imageX;
960 	gSP.bgImage.imageY = _pSprite->imageY;
961 	gSP.bgImage.scaleW = gSP.bgImage.scaleH = 1.0f;
962 
963 	if (config.frameBufferEmulation.enable != 0)
964 	{
965 		struct FrameBuffer *pBuffer = FrameBuffer_FindBuffer(gSP.bgImage.address);
966 		if (pBuffer != NULL)
967       {
968 			gDP.tiles[0].frameBuffer = pBuffer;
969 			gDP.tiles[0].textureMode = TEXTUREMODE_FRAMEBUFFER_BG;
970 			gDP.tiles[0].loadType = LOADTYPE_TILE;
971 			gDP.changed |= CHANGED_TMEM;
972 		}
973 	}
974 }
975 
gln64gSPSprite2DBase(uint32_t _base)976 void gln64gSPSprite2DBase( uint32_t _base )
977 {
978 	float z, w, scaleX, scaleY;
979 	uint32_t flipX, flipY;
980    //assert(RSP.nextCmd == 0xBE);
981    const uint32_t address = RSP_SegmentToPhysical( _base );
982    struct uSprite *pSprite = (struct uSprite*)&gfx_info.RDRAM[address];
983 
984    if (pSprite->tlutPtr != 0)
985    {
986       gln64gDPSetTextureImage( 0, 2, 1, pSprite->tlutPtr );
987       gln64gDPSetTile( 0, 2, 0, 256, 7, 0, 0, 0, 0, 0, 0, 0 );
988       gln64gDPLoadTLUT( 7, 0, 0, 1020, 0 );
989 
990       if (pSprite->imageFmt != G_IM_FMT_RGBA)
991          gDP.otherMode.textureLUT = G_TT_RGBA16;
992       else
993          gDP.otherMode.textureLUT = G_TT_NONE;
994    } else
995       gDP.otherMode.textureLUT = G_TT_NONE;
996 
997    _loadSpriteImage(pSprite);
998    gln64gSPTexture( 1.0f, 1.0f, 0, 0, true );
999    gDP.otherMode.texturePersp = 1;
1000 
1001    z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : gSP.viewport.nearz;
1002    w = 1.0f;
1003 
1004    scaleX = 1.0f;
1005    scaleY = 1.0f;
1006    flipX = 0;
1007    flipY = 0;
1008 
1009    do
1010    {
1011 	  float uls, ult, lrs, lrt;
1012       float ulx, uly, lrx, lry;
1013       float frameX, frameY, frameW, frameH;
1014       int32_t v0 = 0, v1 = 1, v2 = 2, v3 = 3;
1015       struct SPVertex *vtx0, *vtx1, *vtx2, *vtx3;
1016       uint32_t w0 = *(uint32_t*)&gfx_info.RDRAM[__RSP.PC[__RSP.PCi]];
1017       uint32_t w1 = *(uint32_t*)&gfx_info.RDRAM[__RSP.PC[__RSP.PCi] + 4];
1018       __RSP.cmd = _SHIFTR( w0, 24, 8 );
1019 
1020       __RSP.PC[__RSP.PCi] += 8;
1021       __RSP.nextCmd = _SHIFTR( *(uint32_t*)&gfx_info.RDRAM[__RSP.PC[__RSP.PCi]], 24, 8 );
1022 
1023       if (__RSP.cmd == 0xBE )
1024       {
1025          /* gSPSprite2DScaleFlip */
1026          scaleX  = _FIXED2FLOAT( _SHIFTR(w1, 16, 16), 10 );
1027          scaleY  = _FIXED2FLOAT( _SHIFTR(w1,  0, 16), 10 );
1028          flipX = _SHIFTR(w0, 8, 8);
1029          flipY = _SHIFTR(w0, 0, 8);
1030          continue;
1031       }
1032 
1033       /* gSPSprite2DDraw */
1034       frameX = _FIXED2FLOAT(((int16_t)_SHIFTR(w1, 16, 16)), 2);
1035       frameY = _FIXED2FLOAT(((int16_t)_SHIFTR(w1,  0, 16)), 2);
1036       frameW = pSprite->imageW / scaleX;
1037       frameH = pSprite->imageH / scaleY;
1038 
1039       if (flipX != 0)
1040       {
1041          ulx = frameX + frameW;
1042          lrx = frameX;
1043       }
1044       else
1045       {
1046          ulx = frameX;
1047          lrx = frameX + frameW;
1048       }
1049 
1050       if (flipY != 0)
1051       {
1052          uly = frameY + frameH;
1053          lry = frameY;
1054       }
1055       else
1056       {
1057          uly = frameY;
1058          lry = frameY + frameH;
1059       }
1060 
1061       uls = pSprite->imageX;
1062       ult = pSprite->imageY;
1063       lrs = uls + pSprite->imageW - 1;
1064       lrt = ult + pSprite->imageH - 1;
1065 
1066       /* Hack for WCW Nitro. TODO : activate it later.
1067          if (WCW_NITRO) {
1068          gSP.bgImage.height /= scaleY;
1069          gSP.bgImage.imageY /= scaleY;
1070          ult /= scaleY;
1071          lrt /= scaleY;
1072          gSP.bgImage.width *= scaleY;
1073          }
1074          */
1075 
1076 
1077       vtx0 = (struct SPVertex*)&OGL.triangles.vertices[v0];
1078       vtx0->x = ulx;
1079       vtx0->y = uly;
1080       vtx0->z = z;
1081       vtx0->w = w;
1082       vtx0->s = uls;
1083       vtx0->t = ult;
1084       vtx1 = (struct SPVertex*)&OGL.triangles.vertices[v1];
1085       vtx1->x = lrx;
1086       vtx1->y = uly;
1087       vtx1->z = z;
1088       vtx1->w = w;
1089       vtx1->s = lrs;
1090       vtx1->t = ult;
1091       vtx2 = (struct SPVertex*)&OGL.triangles.vertices[v2];
1092       vtx2->x = ulx;
1093       vtx2->y = lry;
1094       vtx2->z = z;
1095       vtx2->w = w;
1096       vtx2->s = uls;
1097       vtx2->t = lrt;
1098       vtx3 = (struct SPVertex*)&OGL.triangles.vertices[v3];
1099       vtx3->x = lrx;
1100       vtx3->y = lry;
1101       vtx3->z = z;
1102       vtx3->w = w;
1103       vtx3->s = lrs;
1104       vtx3->t = lrt;
1105 
1106       OGL_DrawLLETriangle(4);
1107    } while (__RSP.nextCmd == 0xBD || __RSP.nextCmd == 0xBE);
1108 }
1109 
gln64gSPCullDisplayList(uint32_t v0,uint32_t vn)1110 void gln64gSPCullDisplayList( uint32_t v0, uint32_t vn )
1111 {
1112    if (gln64gSPCullVertices( v0, vn ))
1113       gSPEndDisplayList();
1114 }
1115 
gln64gSPPopMatrixN(uint32_t param,uint32_t num)1116 void gln64gSPPopMatrixN( uint32_t param, uint32_t num )
1117 {
1118    if (gSP.matrix.modelViewi > num - 1)
1119    {
1120       gSP.matrix.modelViewi -= num;
1121 
1122       gSP.changed |= CHANGED_MATRIX;
1123    }
1124 }
1125 
gln64gSPPopMatrix(uint32_t param)1126 void gln64gSPPopMatrix( uint32_t param )
1127 {
1128    switch (param)
1129    {
1130       case 0: // modelview
1131          if (gSP.matrix.modelViewi > 0)
1132          {
1133             gSP.matrix.modelViewi--;
1134 
1135             gSP.changed |= CHANGED_MATRIX;
1136          }
1137          break;
1138       case 1: // projection, can't
1139          break;
1140       default:
1141          break;
1142    }
1143 }
1144 
gln64gSPSegment(int32_t seg,int32_t base)1145 void gln64gSPSegment( int32_t seg, int32_t base )
1146 {
1147     gSP.segment[seg] = base;
1148 }
1149 
gln64gSPClipRatio(uint32_t r)1150 void gln64gSPClipRatio( uint32_t r )
1151 {
1152 }
1153 
gln64gSPInsertMatrix(uint32_t where,uint32_t num)1154 void gln64gSPInsertMatrix( uint32_t where, uint32_t num )
1155 {
1156    float fraction, integer;
1157 
1158    if (gSP.changed & CHANGED_MATRIX)
1159       gln64gSPCombineMatrices();
1160 
1161    if ((where & 0x3) || (where > 0x3C))
1162       return;
1163 
1164    if (where < 0x20)
1165    {
1166       fraction = modff( gSP.matrix.combined[0][where >> 1], &integer );
1167       gSP.matrix.combined[0][where >> 1]
1168        = (float)_SHIFTR( num, 16, 16 ) + abs( (int)fraction );
1169 
1170       fraction = modff( gSP.matrix.combined[0][(where >> 1) + 1], &integer );
1171       gSP.matrix.combined[0][(where >> 1) + 1]
1172        = (float)_SHIFTR( num, 0, 16 ) + abs( (int)fraction );
1173    }
1174    else
1175    {
1176       float newValue;
1177 
1178       fraction = modff( gSP.matrix.combined[0][(where - 0x20) >> 1], &integer );
1179       newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 16, 16 ), 16);
1180 
1181       // Make sure the sign isn't lost
1182       if ((integer == 0.0f) && (fraction != 0.0f))
1183          newValue = newValue * (fraction / abs( (int)fraction ));
1184 
1185       gSP.matrix.combined[0][(where - 0x20) >> 1] = newValue;
1186 
1187       fraction = modff( gSP.matrix.combined[0][((where - 0x20) >> 1) + 1], &integer );
1188       newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 0, 16 ), 16 );
1189 
1190       // Make sure the sign isn't lost
1191       if ((integer == 0.0f) && (fraction != 0.0f))
1192          newValue = newValue * (fraction / abs( (int)fraction ));
1193 
1194       gSP.matrix.combined[0][((where - 0x20) >> 1) + 1] = newValue;
1195    }
1196 }
1197 
gln64gSPModifyVertex(uint32_t vtx,uint32_t where,uint32_t val)1198 void gln64gSPModifyVertex( uint32_t vtx, uint32_t where, uint32_t val )
1199 {
1200    int32_t v = vtx;
1201    struct SPVertex *vtx0 = (struct SPVertex*)&OGL.triangles.vertices[v];
1202 
1203    switch (where)
1204    {
1205       case G_MWO_POINT_RGBA:
1206          vtx0->r = _SHIFTR( val, 24, 8 ) * 0.0039215689f;
1207          vtx0->g = _SHIFTR( val, 16, 8 ) * 0.0039215689f;
1208          vtx0->b = _SHIFTR( val, 8, 8 ) * 0.0039215689f;
1209          vtx0->a = _SHIFTR( val, 0, 8 ) * 0.0039215689f;
1210          break;
1211       case G_MWO_POINT_ST:
1212          vtx0->s = _FIXED2FLOAT( (int16_t)_SHIFTR( val, 16, 16 ), 5 ) / gSP.texture.scales;
1213          vtx0->t = _FIXED2FLOAT( (int16_t)_SHIFTR( val, 0, 16 ), 5 ) / gSP.texture.scalet;
1214          break;
1215       case G_MWO_POINT_XYSCREEN:
1216          {
1217             float scrX = _FIXED2FLOAT( (int16_t)_SHIFTR( val, 16, 16 ), 2 );
1218             float scrY = _FIXED2FLOAT( (int16_t)_SHIFTR( val, 0, 16 ), 2 );
1219             vtx0->x = (scrX - gSP.viewport.vtrans[0]) / gSP.viewport.vscale[0];
1220             vtx0->x *= vtx0->w;
1221             vtx0->y = -(scrY - gSP.viewport.vtrans[1]) / gSP.viewport.vscale[1];
1222             vtx0->y *= vtx0->w;
1223             vtx0->clip &= ~(CLIP_POSX | CLIP_NEGX | CLIP_POSY | CLIP_NEGY);
1224          }
1225          break;
1226       case G_MWO_POINT_ZSCREEN:
1227          {
1228             float scrZ = _FIXED2FLOAT((int16_t)_SHIFTR(val, 16, 16), 15);
1229             vtx0->z = (scrZ - gSP.viewport.vtrans[2]) / (gSP.viewport.vscale[2]);
1230             vtx0->z *= vtx0->w;
1231             vtx0->clip &= ~CLIP_Z;
1232          }
1233          break;
1234    }
1235 }
1236 
gln64gSPNumLights(int32_t n)1237 void gln64gSPNumLights( int32_t n )
1238 {
1239    if (n <= 12)
1240    {
1241       gSP.numLights = n;
1242       if (config.generalEmulation.enableHWLighting != 0)
1243          gSP.changed |= CHANGED_LIGHT;
1244    }
1245 }
1246 
gln64gSPLightColor(uint32_t lightNum,uint32_t packedColor)1247 void gln64gSPLightColor( uint32_t lightNum, uint32_t packedColor )
1248 {
1249    lightNum--;
1250 
1251    if (lightNum < 8)
1252    {
1253       gSP.lights[lightNum].r = _SHIFTR( packedColor, 24, 8 ) * 0.0039215689f;
1254       gSP.lights[lightNum].g = _SHIFTR( packedColor, 16, 8 ) * 0.0039215689f;
1255       gSP.lights[lightNum].b = _SHIFTR( packedColor, 8, 8 ) * 0.0039215689f;
1256 		if (config.generalEmulation.enableHWLighting != 0)
1257 			gSP.changed |= CHANGED_LIGHT;
1258    }
1259 }
1260 
gln64gSPFogFactor(int16_t fm,int16_t fo)1261 void gln64gSPFogFactor( int16_t fm, int16_t fo )
1262 {
1263    gSP.fog.multiplier = fm;
1264    gSP.fog.offset     = fo;
1265 
1266    gSP.changed |= CHANGED_FOGPOSITION;
1267 }
1268 
gln64gSPPerspNormalize(uint16_t scale)1269 void gln64gSPPerspNormalize( uint16_t scale )
1270 {
1271 }
1272 
gln64gSPCoordMod(uint32_t _w0,uint32_t _w1)1273 void gln64gSPCoordMod(uint32_t _w0, uint32_t _w1)
1274 {
1275    uint32_t idx, pos;
1276 
1277 	if ((_w0&8) != 0)
1278 		return;
1279 	idx = _SHIFTR(_w0, 1, 2);
1280 	pos = _w0&0x30;
1281 	if (pos == 0)
1282    {
1283 		gSP.vertexCoordMod[0+idx] = (float)(int16_t)_SHIFTR(_w1, 16, 16);
1284 		gSP.vertexCoordMod[1+idx] = (float)(int16_t)_SHIFTR(_w1, 0, 16);
1285 	}
1286    else if (pos == 0x10)
1287    {
1288 		assert(idx < 3);
1289 		gSP.vertexCoordMod[4+idx] = _SHIFTR(_w1, 16, 16)/65536.0f;
1290 		gSP.vertexCoordMod[5+idx] = _SHIFTR(_w1, 0, 16)/65536.0f;
1291 		gSP.vertexCoordMod[12+idx] = gSP.vertexCoordMod[0+idx] + gSP.vertexCoordMod[4+idx];
1292 		gSP.vertexCoordMod[13+idx] = gSP.vertexCoordMod[1+idx] + gSP.vertexCoordMod[5+idx];
1293 	} else if (pos == 0x20) {
1294 		gSP.vertexCoordMod[8+idx] = (float)(int16_t)_SHIFTR(_w1, 16, 16);
1295 		gSP.vertexCoordMod[9+idx] = (float)(int16_t)_SHIFTR(_w1, 0, 16);
1296 	}
1297 }
1298 
gln64gSPTexture(float sc,float tc,int32_t level,int32_t tile,int32_t on)1299 void gln64gSPTexture( float sc, float tc, int32_t level, int32_t tile, int32_t on )
1300 {
1301    gSP.texture.on = on;
1302    if (on == 0)
1303       return;
1304 
1305    gSP.texture.scales = sc;
1306    gSP.texture.scalet = tc;
1307 
1308    if (gSP.texture.scales == 0.0f)
1309       gSP.texture.scales = 1.0f;
1310    if (gSP.texture.scalet == 0.0f)
1311       gSP.texture.scalet = 1.0f;
1312 
1313    gSP.texture.level = level;
1314 
1315    gSP.texture.tile = tile;
1316    gSP.textureTile[0] = &gDP.tiles[tile];
1317    gSP.textureTile[1] = &gDP.tiles[(tile + 1) & 7];
1318 
1319    gSP.changed |= CHANGED_TEXTURE;
1320 }
1321 
gln64gSPGeometryMode(uint32_t clear,uint32_t set)1322 void gln64gSPGeometryMode( uint32_t clear, uint32_t set )
1323 {
1324    gSP.geometryMode = (gSP.geometryMode & ~clear) | set;
1325    gSP.changed |= CHANGED_GEOMETRYMODE;
1326 }
1327 
gln64gSPSetGeometryMode(uint32_t mode)1328 void gln64gSPSetGeometryMode( uint32_t mode )
1329 {
1330    gSP.geometryMode |= mode;
1331    gSP.changed |= CHANGED_GEOMETRYMODE;
1332 }
1333 
gln64gSPClearGeometryMode(uint32_t mode)1334 void gln64gSPClearGeometryMode( uint32_t mode )
1335 {
1336    gSP.geometryMode &= ~mode;
1337    gSP.changed |= CHANGED_GEOMETRYMODE;
1338 }
1339 
gln64gSPSetOtherMode_H(uint32_t _length,uint32_t _shift,uint32_t _data)1340 void gln64gSPSetOtherMode_H(uint32_t _length, uint32_t _shift, uint32_t _data)
1341 {
1342 	const uint32_t mask = (((uint64_t)1 << _length) - 1) << _shift;
1343 	gDP.otherMode.h = (gDP.otherMode.h&(~mask)) | _data;
1344 
1345 	if (mask & 0x00300000)  // cycle type
1346 		gDP.changed |= CHANGED_CYCLETYPE;
1347 }
1348 
gln64gSPSetOtherMode_L(uint32_t _length,uint32_t _shift,uint32_t _data)1349 void gln64gSPSetOtherMode_L(uint32_t _length, uint32_t _shift, uint32_t _data)
1350 {
1351 	const uint32_t mask = (((uint64_t)1 << _length) - 1) << _shift;
1352 	gDP.otherMode.l = (gDP.otherMode.l&(~mask)) | _data;
1353 
1354 	if (mask & 0xFFFFFFF8)  // rendermode / blender bits
1355 		gDP.changed |= CHANGED_RENDERMODE;
1356 }
1357 
gln64gSPLine3D(int32_t v0,int32_t v1,int32_t flag)1358 void gln64gSPLine3D( int32_t v0, int32_t v1, int32_t flag )
1359 {
1360    OGL_DrawLine(v0, v1, 1.5f );
1361 }
1362 
gln64gSPLineW3D(int32_t v0,int32_t v1,int32_t wd,int32_t flag)1363 void gln64gSPLineW3D( int32_t v0, int32_t v1, int32_t wd, int32_t flag )
1364 {
1365    OGL_DrawLine(v0, v1, 1.5f + wd * 0.5f );
1366 }
1367 
1368 static
_loadBGImage(const struct uObjScaleBg * _bgInfo,bool _loadScale)1369 void _loadBGImage(const struct uObjScaleBg * _bgInfo, bool _loadScale)
1370 {
1371 	uint32_t imageW, imageH;
1372 	gSP.bgImage.address = RSP_SegmentToPhysical( _bgInfo->imagePtr );
1373 
1374 	imageW = _bgInfo->imageW >> 2;
1375 	gSP.bgImage.width = imageW - imageW%2;
1376 	imageH = _bgInfo->imageH >> 2;
1377 	gSP.bgImage.height = imageH - imageH%2;
1378 	gSP.bgImage.format = _bgInfo->imageFmt;
1379 	gSP.bgImage.size = _bgInfo->imageSiz;
1380 	gSP.bgImage.palette = _bgInfo->imagePal;
1381 	gDP.tiles[0].textureMode = TEXTUREMODE_BGIMAGE;
1382 	gSP.bgImage.imageX = _FIXED2FLOAT( _bgInfo->imageX, 5 );
1383 	gSP.bgImage.imageY = _FIXED2FLOAT( _bgInfo->imageY, 5 );
1384 	if (_loadScale) {
1385 		gSP.bgImage.scaleW = _FIXED2FLOAT( _bgInfo->scaleW, 10 );
1386 		gSP.bgImage.scaleH = _FIXED2FLOAT( _bgInfo->scaleH, 10 );
1387 	} else
1388 		gSP.bgImage.scaleW = gSP.bgImage.scaleH = 1.0f;
1389 
1390 	if (config.frameBufferEmulation.enable)
1391    {
1392 		struct FrameBuffer *pBuffer = FrameBuffer_FindBuffer(gSP.bgImage.address);
1393       /* TODO/FIXME */
1394 		if ((pBuffer != NULL) && pBuffer->m_size == gSP.bgImage.size && (/* !pBuffer->m_isDepthBuffer || */ pBuffer->m_changed))
1395       {
1396 			gDP.tiles[0].frameBuffer = pBuffer;
1397 			gDP.tiles[0].textureMode = TEXTUREMODE_FRAMEBUFFER_BG;
1398 			gDP.tiles[0].loadType = LOADTYPE_TILE;
1399 			gDP.changed |= CHANGED_TMEM;
1400 		}
1401 	}
1402 }
1403 
1404 struct ObjCoordinates
1405 {
1406 	float ulx, uly, lrx, lry;
1407 	float uls, ult, lrs, lrt;
1408 	float z, w;
1409 };
1410 
1411 struct ObjData
1412 {
1413 	float scaleW;
1414 	float scaleH;
1415 	uint32_t imageW;
1416 	uint32_t imageH;
1417 	float X0;
1418 	float X1;
1419 	float Y0;
1420 	float Y1;
1421 	bool flipS, flipT;
1422 };
1423 
ObjData_new(struct ObjData * obj,const struct uObjSprite * _pObjSprite)1424 void ObjData_new(struct ObjData *obj, const struct uObjSprite *_pObjSprite)
1425 {
1426    obj->scaleW = _FIXED2FLOAT(_pObjSprite->scaleW, 10);
1427    obj->scaleH = _FIXED2FLOAT(_pObjSprite->scaleH, 10);
1428    obj->imageW = _pObjSprite->imageW >> 5;
1429    obj->imageH = _pObjSprite->imageH >> 5;
1430    obj->X0     = _FIXED2FLOAT(_pObjSprite->objX, 2);
1431    obj->X1     = obj->X0 + obj->imageW / obj->scaleW;
1432    obj->Y0     = _FIXED2FLOAT(_pObjSprite->objY, 2);
1433    obj->Y1     = obj->Y0 + obj->imageH / obj->scaleH;
1434    obj->flipS  = (_pObjSprite->imageFlags & 0x01) != 0;
1435    obj->flipT  = (_pObjSprite->imageFlags & 0x10) != 0;
1436 }
1437 
ObjCoordinates_new(struct ObjCoordinates * obj,const struct uObjSprite * _pObjSprite,bool _useMatrix)1438 void ObjCoordinates_new(struct ObjCoordinates *obj, const struct uObjSprite *_pObjSprite, bool _useMatrix)
1439 {
1440    struct ObjData data;
1441 
1442    ObjData_new(&data, _pObjSprite);
1443 
1444    obj->ulx = data.X0;
1445    obj->lrx = data.X1;
1446    obj->uly = data.Y0;
1447    obj->lry = data.Y1;
1448 
1449    if (_useMatrix)
1450    {
1451       obj->ulx = obj->ulx / gSP.objMatrix.baseScaleX + gSP.objMatrix.X;
1452       obj->lrx = obj->lrx / gSP.objMatrix.baseScaleX + gSP.objMatrix.X;
1453       obj->uly = obj->uly / gSP.objMatrix.baseScaleY + gSP.objMatrix.Y;
1454       obj->lry = obj->lry / gSP.objMatrix.baseScaleY + gSP.objMatrix.Y;
1455    }
1456 
1457    obj->uls = obj->ult = 0;
1458    obj->lrs = data.imageW - 1;
1459    obj->lrt = data.imageH - 1;
1460    if (data.flipS)
1461    {
1462       obj->uls = obj->lrs;
1463       obj->lrs = 0;
1464    }
1465    if (data.flipT)
1466    {
1467       obj->ult = obj->lrt;
1468       obj->lrt = 0;
1469    }
1470 
1471    obj->z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : gSP.viewport.nearz;
1472    obj->w = 1.0f;
1473 }
1474 
ObjCoordinates2_new(struct ObjCoordinates * obj,const struct uObjScaleBg * _pObjScaleBg)1475 void ObjCoordinates2_new(struct ObjCoordinates *obj, const struct uObjScaleBg * _pObjScaleBg)
1476 {
1477    const float frameX = _FIXED2FLOAT(_pObjScaleBg->frameX, 2);
1478    const float frameY = _FIXED2FLOAT(_pObjScaleBg->frameY, 2);
1479    const float frameW = _FIXED2FLOAT(_pObjScaleBg->frameW, 2);
1480    const float frameH = _FIXED2FLOAT(_pObjScaleBg->frameH, 2);
1481    const float imageX = gSP.bgImage.imageX;
1482    const float imageY = gSP.bgImage.imageY;
1483    const float imageW = (float)(_pObjScaleBg->imageW>>2);
1484    const float imageH = (float)(_pObjScaleBg->imageH >> 2);
1485    //		const float imageW = (float)gSP.bgImage.width;
1486    //		const float imageH = (float)gSP.bgImage.height;
1487    const float scaleW = gSP.bgImage.scaleW;
1488    const float scaleH = gSP.bgImage.scaleH;
1489 
1490    obj->ulx = frameX;
1491    obj->uly = frameY;
1492    obj->lrx = frameX + MIN(imageW/scaleW, frameW) - 1.0f;
1493    obj->lry = frameY + MIN(imageH/scaleH, frameH) - 1.0f;
1494    if (gDP.otherMode.cycleType == G_CYC_COPY)
1495    {
1496       obj->lrx += 1.0f;
1497       obj->lry += 1.0f;;
1498    }
1499 
1500    obj->uls = imageX;
1501    obj->ult = imageY;
1502    obj->lrs = obj->uls + (obj->lrx - obj->ulx) * scaleW;
1503    obj->lrt = obj->ult + (obj->lry - obj->uly) * scaleH;
1504    if (gDP.otherMode.cycleType != G_CYC_COPY)
1505    {
1506       if ((gSP.objRendermode&G_OBJRM_SHRINKSIZE_1) != 0)
1507       {
1508          obj->lrs -= 1.0f / scaleW;
1509          obj->lrt -= 1.0f / scaleH;
1510       }
1511       else if ((gSP.objRendermode&G_OBJRM_SHRINKSIZE_2) != 0)
1512       {
1513          obj->lrs -= 1.0f;
1514          obj->lrt -= 1.0f;
1515       }
1516    }
1517 
1518    if ((_pObjScaleBg->imageFlip & 0x01) != 0)
1519    {
1520       obj->ulx = obj->lrx;
1521       obj->lrx = frameX;
1522    }
1523 
1524    obj->z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : gSP.viewport.nearz;
1525    obj->w = 1.0f;
1526 }
1527 
gln64gSPDrawObjRect(const struct ObjCoordinates * _coords)1528 static void gln64gSPDrawObjRect(const struct ObjCoordinates *_coords)
1529 {
1530    struct SPVertex *vtx0, *vtx1, *vtx2, *vtx3;
1531 	uint32_t v0 = 0, v1 = 1, v2 = 2, v3 = 3;
1532    vtx0 = (struct SPVertex*)&OGL.triangles.vertices[v0];
1533 	vtx0->x = _coords->ulx;
1534 	vtx0->y = _coords->uly;
1535 	vtx0->z = _coords->z;
1536 	vtx0->w = _coords->w;
1537 	vtx0->s = _coords->uls;
1538 	vtx0->t = _coords->ult;
1539 	vtx1 = (struct SPVertex*)&OGL.triangles.vertices[v1];
1540 	vtx1->x = _coords->lrx;
1541 	vtx1->y = _coords->uly;
1542 	vtx1->z = _coords->z;
1543 	vtx1->w = _coords->w;
1544 	vtx1->s = _coords->lrs;
1545 	vtx1->t = _coords->ult;
1546 	vtx2 = (struct SPVertex*)&OGL.triangles.vertices[v2];
1547 	vtx2->x = _coords->ulx;
1548 	vtx2->y = _coords->lry;
1549 	vtx2->z = _coords->z;
1550 	vtx2->w = _coords->w;
1551 	vtx2->s = _coords->uls;
1552 	vtx2->t = _coords->lrt;
1553 	vtx3 = (struct SPVertex*)&OGL.triangles.vertices[v3];
1554 	vtx3->x = _coords->lrx;
1555 	vtx3->y = _coords->lry;
1556 	vtx3->z = _coords->z;
1557 	vtx3->w = _coords->w;
1558 	vtx3->s = _coords->lrs;
1559 	vtx3->t = _coords->lrt;
1560 
1561    OGL_DrawLLETriangle(4);
1562 	gDP.colorImage.height = (uint32_t)(MAX(gDP.colorImage.height, (uint32_t)gDP.scissor.lry));
1563 }
1564 
gln64gSPBgRect1Cyc(uint32_t _bg)1565 void gln64gSPBgRect1Cyc( uint32_t _bg )
1566 {
1567    struct ObjCoordinates objCoords;
1568 	const uint32_t address = RSP_SegmentToPhysical( _bg );
1569 	struct uObjScaleBg *objScaleBg = (struct uObjScaleBg*)&gfx_info.RDRAM[address];
1570 	_loadBGImage(objScaleBg, true);
1571 
1572 #ifdef GL_IMAGE_TEXTURES_SUPPORT
1573 	if (gSP.bgImage.address == gDP.depthImageAddress || depthBufferList().findBuffer(gSP.bgImage.address) != NULL)
1574 		_copyDepthBuffer();
1575 	// Zelda MM uses depth buffer copy in LoT and in pause screen.
1576 	// In later case depth buffer is used as temporal color buffer, and usual rendering must be used.
1577 	// Since both situations are hard to distinguish, do the both depth buffer copy and bg rendering.
1578 #endif // GL_IMAGE_TEXTURES_SUPPORT
1579 
1580 	gDP.otherMode.cycleType = G_CYC_1CYCLE;
1581 	gDP.changed |= CHANGED_CYCLETYPE;
1582 	gln64gSPTexture(1.0f, 1.0f, 0, 0, true);
1583 	gDP.otherMode.texturePersp = 1;
1584 
1585 	ObjCoordinates2_new(&objCoords, objScaleBg);
1586 	gln64gSPDrawObjRect(&objCoords);
1587 }
1588 
gln64gSPBgRectCopy(uint32_t _bg)1589 void gln64gSPBgRectCopy( uint32_t _bg )
1590 {
1591    struct ObjCoordinates objCoords;
1592 	const uint32_t address = RSP_SegmentToPhysical( _bg );
1593 	struct uObjScaleBg *objBg = (struct uObjScaleBg*)&gfx_info.RDRAM[address];
1594 	_loadBGImage(objBg, false);
1595 
1596 #ifdef GL_IMAGE_TEXTURES_SUPPORT
1597 	if (gSP.bgImage.address == gDP.depthImageAddress || depthBufferList().findBuffer(gSP.bgImage.address) != NULL)
1598 		_copyDepthBuffer();
1599 	// See comment to gSPBgRect1Cyc
1600 #endif // GL_IMAGE_TEXTURES_SUPPORT
1601 
1602 	gln64gSPTexture( 1.0f, 1.0f, 0, 0, true );
1603 	gDP.otherMode.texturePersp = 1;
1604 
1605    ObjCoordinates2_new(&objCoords, objBg);
1606 	gln64gSPDrawObjRect(&objCoords);
1607 }
1608 
gln64gSPObjLoadTxtr(uint32_t tx)1609 void gln64gSPObjLoadTxtr( uint32_t tx )
1610 {
1611    uint32_t address = RSP_SegmentToPhysical( tx );
1612    uObjTxtr *objTxtr = (uObjTxtr*)&gfx_info.RDRAM[address];
1613 
1614    if ((gSP.status[objTxtr->block.sid >> 2] & objTxtr->block.mask) != objTxtr->block.flag)
1615    {
1616       switch (objTxtr->block.type)
1617       {
1618          case G_OBJLT_TXTRBLOCK:
1619             gln64gDPSetTextureImage( 0, 1, 0, objTxtr->block.image );
1620             gln64gDPSetTile( 0, 1, 0, objTxtr->block.tmem, 7, 0, 0, 0, 0, 0, 0, 0 );
1621             gln64gDPLoadBlock( 7, 0, 0, ((objTxtr->block.tsize + 1) << 3) - 1, objTxtr->block.tline );
1622             break;
1623          case G_OBJLT_TXTRTILE:
1624             gln64gDPSetTextureImage( 0, 1, (objTxtr->tile.twidth + 1) << 1, objTxtr->tile.image );
1625             gln64gDPSetTile( 0, 1, (objTxtr->tile.twidth + 1) >> 2, objTxtr->tile.tmem, 7, 0, 0, 0, 0, 0, 0, 0 );
1626             gln64gDPLoadTile( 7, 0, 0, (((objTxtr->tile.twidth + 1) << 1) - 1) << 2, (((objTxtr->tile.theight + 1) >> 2) - 1) << 2 );
1627             break;
1628          case G_OBJLT_TLUT:
1629             gln64gDPSetTextureImage( 0, 2, 1, objTxtr->tlut.image );
1630             gln64gDPSetTile( 0, 2, 0, objTxtr->tlut.phead, 7, 0, 0, 0, 0, 0, 0, 0 );
1631             gln64gDPLoadTLUT( 7, 0, 0, objTxtr->tlut.pnum << 2, 0 );
1632             break;
1633       }
1634       gSP.status[objTxtr->block.sid >> 2] = (gSP.status[objTxtr->block.sid >> 2] & ~objTxtr->block.mask) | (objTxtr->block.flag & objTxtr->block.mask);
1635    }
1636 }
1637 
gln64gSPSetSpriteTile(const struct uObjSprite * _pObjSprite)1638 static void gln64gSPSetSpriteTile(const struct uObjSprite *_pObjSprite)
1639 {
1640 	const uint32_t w = MAX(_pObjSprite->imageW >> 5, 1);
1641 	const uint32_t h = MAX(_pObjSprite->imageH >> 5, 1);
1642 
1643 	gln64gDPSetTile( _pObjSprite->imageFmt, _pObjSprite->imageSiz, _pObjSprite->imageStride, _pObjSprite->imageAdrs, 0, _pObjSprite->imagePal, G_TX_CLAMP, G_TX_CLAMP, 0, 0, 0, 0 );
1644 	gln64gDPSetTileSize( 0, 0, 0, (w - 1) << 2, (h - 1) << 2 );
1645 	gln64gSPTexture( 1.0f, 1.0f, 0, 0, true );
1646 	gDP.otherMode.texturePersp = 1;
1647 }
1648 
_drawYUVImageToFrameBuffer(const struct ObjCoordinates * _objCoords)1649 static void _drawYUVImageToFrameBuffer(const struct ObjCoordinates *_objCoords)
1650 {
1651    uint16_t h, w;
1652    uint32_t width, height, *mb, *dst;
1653    struct FrameBuffer *pBuffer;
1654 	const uint32_t ulx = (uint32_t)_objCoords->ulx;
1655 	const uint32_t uly = (uint32_t)_objCoords->uly;
1656 	const uint32_t lrx = (uint32_t)_objCoords->lrx;
1657 	const uint32_t lry = (uint32_t)_objCoords->lry;
1658 	const uint32_t ci_width = gDP.colorImage.width;
1659 	const uint32_t ci_height = gDP.colorImage.height;
1660 	if (ulx >= ci_width)
1661 		return;
1662 	if (uly >= ci_height)
1663 		return;
1664 	width = 16;
1665 	height = 16;
1666 	if (lrx > ci_width)
1667 		width = ci_width - ulx;
1668 	if (lry > ci_height)
1669 		height = ci_height - uly;
1670 	mb = (uint32_t*)(gfx_info.RDRAM + gDP.textureImage.address); //pointer to the first macro block
1671 	dst = (uint32_t*)(gfx_info.RDRAM + gDP.colorImage.address);
1672 	dst += ulx + uly * ci_width;
1673 
1674 	/* YUV macro block contains 16x16 texture.
1675     * we need to put it in the proper place inside cimg */
1676 	for (h = 0; h < 16; h++)
1677    {
1678 		for (w = 0; w < 16; w += 2)
1679       {
1680          uint32_t t = *(mb++); //each uint32_t contains 2 pixels
1681          if ((h < height) && (w < width)) //clipping. texture image may be larger than color image
1682          {
1683             uint8_t y0 = (uint8_t)t & 0xFF;
1684             uint8_t v = (uint8_t)(t >> 8) & 0xFF;
1685             uint8_t y1 = (uint8_t)(t >> 16) & 0xFF;
1686             uint8_t u = (uint8_t)(t >> 24) & 0xFF;
1687             *(dst++) = YUVtoRGBA16(y0, u, v);
1688             *(dst++) = YUVtoRGBA16(y1, u, v);
1689          }
1690       }
1691 		dst += ci_width - 16;
1692 	}
1693 
1694 	pBuffer = FrameBuffer_GetCurrent();
1695 	if (pBuffer != NULL)
1696    {
1697 #if 0
1698 		pBuffer->m_isOBScreen = true;
1699 #endif
1700    }
1701 }
1702 
gln64gSPObjRectangle(uint32_t _sp)1703 void gln64gSPObjRectangle(uint32_t _sp)
1704 {
1705    struct ObjCoordinates objCoords;
1706 	const uint32_t address = RSP_SegmentToPhysical(_sp);
1707 	struct uObjSprite *objSprite = (struct uObjSprite*)&gfx_info.RDRAM[address];
1708 
1709 	gln64gSPSetSpriteTile(objSprite);
1710    ObjCoordinates_new(&objCoords, objSprite, false);
1711 	gln64gSPDrawObjRect(&objCoords);
1712 }
1713 
gln64gSPObjRectangleR(uint32_t _sp)1714 void gln64gSPObjRectangleR(uint32_t _sp)
1715 {
1716    struct ObjCoordinates objCoords;
1717    const uint32_t address = RSP_SegmentToPhysical(_sp);
1718    const struct uObjSprite *objSprite = (struct uObjSprite*)&gfx_info.RDRAM[address];
1719 
1720    gln64gSPSetSpriteTile(objSprite);
1721    ObjCoordinates_new(&objCoords, objSprite, true);
1722 
1723    if (objSprite->imageFmt == G_IM_FMT_YUV && (config.generalEmulation.hacks & hack_Ogre64)) //Ogre Battle needs to copy YUV texture to frame buffer
1724       _drawYUVImageToFrameBuffer(&objCoords);
1725    gln64gSPDrawObjRect(&objCoords);
1726 }
1727 
gln64gSPObjSprite(uint32_t _sp)1728 void gln64gSPObjSprite( uint32_t _sp )
1729 {
1730    struct SPVertex *vtx0, *vtx1, *vtx2, *vtx3;
1731    float uls, lrs, ult, lrt;
1732 	float z;
1733 	int32_t v0, v1, v2, v3;
1734    float ulx, uly, lrx, lry;
1735    struct ObjData data;
1736 	const uint32_t address = RSP_SegmentToPhysical( _sp );
1737 	struct uObjSprite *objSprite = (struct uObjSprite*)&gfx_info.RDRAM[address];
1738 
1739 	gln64gSPSetSpriteTile(objSprite);
1740 	ObjData_new(&data, objSprite);
1741 
1742 	ulx = data.X0;
1743 	uly = data.Y0;
1744 	lrx = data.X1;
1745 	lry = data.Y1;
1746 
1747 	uls = 0;
1748    lrs =  data.imageW - 1;
1749    ult = 0;
1750    lrt = data.imageH - 1;
1751 
1752 	if (objSprite->imageFlags & 0x01) { // flipS
1753 		uls = lrs;
1754 		lrs = 0;
1755 	}
1756 	if (objSprite->imageFlags & 0x10) { // flipT
1757 		ult = lrt;
1758 		lrt = 0;
1759 	}
1760 	z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : gSP.viewport.nearz;
1761 
1762 	v0 = 0;
1763 	v1 = 1;
1764 	v2 = 2;
1765 	v3 = 3;
1766 
1767    vtx0 = (struct SPVertex*)&OGL.triangles.vertices[v0];
1768 	vtx0->x = gSP.objMatrix.A * ulx + gSP.objMatrix.B * uly + gSP.objMatrix.X;
1769 	vtx0->y = gSP.objMatrix.C * ulx + gSP.objMatrix.D * uly + gSP.objMatrix.Y;
1770 	vtx0->z = z;
1771 	vtx0->w = 1.0f;
1772 	vtx0->s = uls;
1773 	vtx0->t = ult;
1774    vtx1 = (struct SPVertex*)&OGL.triangles.vertices[v1];
1775 	vtx1->x = gSP.objMatrix.A * lrx + gSP.objMatrix.B * uly + gSP.objMatrix.X;
1776 	vtx1->y = gSP.objMatrix.C * lrx + gSP.objMatrix.D * uly + gSP.objMatrix.Y;
1777 	vtx1->z = z;
1778 	vtx1->w = 1.0f;
1779 	vtx1->s = lrs;
1780 	vtx1->t = ult;
1781    vtx2 = (struct SPVertex*)&OGL.triangles.vertices[v2];
1782 	vtx2->x = gSP.objMatrix.A * ulx + gSP.objMatrix.B * lry + gSP.objMatrix.X;
1783 	vtx2->y = gSP.objMatrix.C * ulx + gSP.objMatrix.D * lry + gSP.objMatrix.Y;
1784 	vtx2->z = z;
1785 	vtx2->w = 1.0f;
1786 	vtx2->s = uls;
1787 	vtx2->t = lrt;
1788    vtx3 = (struct SPVertex*)&OGL.triangles.vertices[v3];
1789 	vtx3->x = gSP.objMatrix.A * lrx + gSP.objMatrix.B * lry + gSP.objMatrix.X;
1790 	vtx3->y = gSP.objMatrix.C * lrx + gSP.objMatrix.D * lry + gSP.objMatrix.Y;
1791 	vtx3->z = z;
1792 	vtx3->w = 1.0f;
1793 	vtx3->s = lrs;
1794 	vtx3->t = lrt;
1795 
1796    OGL_DrawLLETriangle(4);
1797 
1798 #ifdef NEW
1799    /* TODO/FIXME */
1800 	frameBufferList().setBufferChanged();
1801 #endif
1802 	gDP.colorImage.height = (uint32_t)(MAX( gDP.colorImage.height, (uint32_t)gDP.scissor.lry ));
1803 }
1804 
gln64gSPObjLoadTxSprite(uint32_t txsp)1805 void gln64gSPObjLoadTxSprite( uint32_t txsp )
1806 {
1807    gln64gSPObjLoadTxtr( txsp );
1808    gln64gSPObjSprite( txsp + sizeof( uObjTxtr ) );
1809 }
1810 
gln64gSPObjLoadTxRect(uint32_t txsp)1811 void gln64gSPObjLoadTxRect(uint32_t txsp)
1812 {
1813 	gln64gSPObjLoadTxtr(txsp);
1814 	gln64gSPObjRectangle(txsp + sizeof(uObjTxtr));
1815 }
1816 
gln64gSPObjLoadTxRectR(uint32_t txsp)1817 void gln64gSPObjLoadTxRectR( uint32_t txsp )
1818 {
1819 	gln64gSPObjLoadTxtr( txsp );
1820 	gln64gSPObjRectangleR( txsp + sizeof( uObjTxtr ) );
1821 }
1822 
gln64gSPObjMatrix(uint32_t mtx)1823 void gln64gSPObjMatrix( uint32_t mtx )
1824 {
1825    uint32_t address = RSP_SegmentToPhysical( mtx );
1826    uObjMtx *objMtx = (uObjMtx*)&gfx_info.RDRAM[address];
1827 
1828    gSP.objMatrix.A = _FIXED2FLOAT( objMtx->A, 16 );
1829    gSP.objMatrix.B = _FIXED2FLOAT( objMtx->B, 16 );
1830    gSP.objMatrix.C = _FIXED2FLOAT( objMtx->C, 16 );
1831    gSP.objMatrix.D = _FIXED2FLOAT( objMtx->D, 16 );
1832    gSP.objMatrix.X = _FIXED2FLOAT( objMtx->X, 2 );
1833    gSP.objMatrix.Y = _FIXED2FLOAT( objMtx->Y, 2 );
1834    gSP.objMatrix.baseScaleX = _FIXED2FLOAT( objMtx->BaseScaleX, 10 );
1835    gSP.objMatrix.baseScaleY = _FIXED2FLOAT( objMtx->BaseScaleY, 10 );
1836 }
1837 
gln64gSPObjSubMatrix(uint32_t mtx)1838 void gln64gSPObjSubMatrix( uint32_t mtx )
1839 {
1840 	uint32_t address = RSP_SegmentToPhysical(mtx);
1841 	uObjSubMtx *objMtx = (uObjSubMtx*)&gfx_info.RDRAM[address];
1842 	gSP.objMatrix.X = _FIXED2FLOAT(objMtx->X, 2);
1843 	gSP.objMatrix.Y = _FIXED2FLOAT(objMtx->Y, 2);
1844 	gSP.objMatrix.baseScaleX = _FIXED2FLOAT(objMtx->BaseScaleX, 10);
1845 	gSP.objMatrix.baseScaleY = _FIXED2FLOAT(objMtx->BaseScaleY, 10);
1846 }
1847 
gln64gSPObjRendermode(uint32_t _mode)1848 void gln64gSPObjRendermode(uint32_t _mode)
1849 {
1850 	gSP.objRendermode = _mode;
1851 }
1852 
1853 void (*gln64gSPTransformVertex)(float vtx[4], float mtx[4][4])  = gln64gSPTransformVertex_default;
1854 void (*gln64gSPLightVertex)(void *data)                         = gln64gSPLightVertex_default;
1855 void (*gln64gSPPointLightVertex)(void *data, float * _vPos)     = gln64gSPPointLightVertex_default;
1856 void (*gln64gSPBillboardVertex)(uint32_t v, uint32_t i)         = gln64gSPBillboardVertex_default;
1857 
gSPSetupFunctions(void)1858 void gSPSetupFunctions(void)
1859 {
1860    if (GBI_GetCurrentMicrocodeType() != F3DEX2CBFD)
1861    {
1862       gln64gSPLightVertex      = gln64gSPLightVertex_default;
1863       gln64gSPPointLightVertex = gln64gSPPointLightVertex_default;
1864       return;
1865    }
1866 
1867    gln64gSPLightVertex      = gln64gSPLightVertex_CBFD;
1868    gln64gSPPointLightVertex = gln64gSPPointLightVertex_CBFD;
1869 }
1870