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