Arachnoid GLESv1.1 plugin. Compile and run (a bit glitchy and no frameskip) on the...
[mupen64plus-pandora.git] / source / mupen64plus-video-arachnoid / src / RSP / RSPVertexManager.cpp
1 /******************************************************************************
2  * Arachnoid Graphics Plugin for Mupen64Plus
3  * http://bitbucket.org/wahrhaft/mupen64plus-video-arachnoid/
4  *
5  * Copyright (C) 2007 Kristofer Karlsson, Rickard Niklasson
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  *****************************************************************************/
21
22 #include "RSPVertexManager.h"
23 #include "OpenGLManager.h"
24 #include "Memory.h"
25 #include "RSPMatrixManager.h"
26 #include "RSPLightManager.h"
27 #include "OpenGLRenderer.h"
28 #include "GBIDefs.h"   //hmm
29 #include "MathLib.h"   //Transform, Vec3Normalize
30 #include <cmath> //sqrt
31 #include "Logger.h"
32
33 //Vertex
34 struct Vertex
35 {
36     //Position (x,y,z)
37     short y;
38     short x;
39     unsigned short flag;  //Special Flags
40     short z;
41
42     //TexCoords
43     short t;
44     short s;
45
46     //Color or Normal
47     union 
48     {
49         struct { unsigned char a; unsigned char b; unsigned char g; unsigned char r; } color;
50         struct { signed char a;   signed char z;   signed char y;   signed char x; } normal;
51     };
52 };
53
54 //Perfect Dark Vertex
55 struct PerfectDarkVertex
56 {
57     short y;
58     short x;
59     unsigned short ci;  //Color Index
60     short z;
61     short t;
62     short s;
63 };
64
65 struct DKRTriangle 
66 {
67     unsigned char v2, v1, v0, flag;
68     short        t0, s0;
69     short        t1, s1;
70     short        t2, s2;
71 };
72
73 //-----------------------------------------------------------------------------
74 //! Constructor
75 //-----------------------------------------------------------------------------
76 RSPVertexManager::RSPVertexManager() 
77 {
78     m_openGLMgr = 0;
79     m_memory    = 0;
80     m_matrixMgr = 0;
81 }
82
83 //-----------------------------------------------------------------------------
84 //! Destructor
85 //-----------------------------------------------------------------------------
86 RSPVertexManager::~RSPVertexManager()
87 {
88
89 }
90
91 //-----------------------------------------------------------------------------
92 //* Initialize
93 //-----------------------------------------------------------------------------
94 bool RSPVertexManager::initialize(OpenGLManager* openGLMgr, Memory* memory, RSPMatrixManager* matrixMgr, RSPLightManager* lightMgr)
95 {
96     m_openGLMgr = openGLMgr;
97     m_memory    = memory;
98     m_matrixMgr = matrixMgr;    
99     m_lightMgr  = lightMgr;
100     m_texCoordGenType = TCGT_NONE;
101     m_rdramOffset = 0;
102     m_billboard = false;
103     return true;
104 }
105
106 //-----------------------------------------------------------------------------
107 // Set Vertices
108 //-----------------------------------------------------------------------------
109 void RSPVertexManager::setVertices( unsigned int address, unsigned int numVertices, unsigned int firstVertexIndex)
110 {
111     //Make sure address is valid
112     if ((address + sizeof( Vertex ) * numVertices) > m_memory->getRDRAMSize()) {
113         return;
114     }
115
116     //Get vertex from rdram
117     Vertex *vertex = (Vertex*) m_memory->getRDRAM(address);
118
119     //Avoid overflow. There can only be MAX_VERTICES in size.
120     if ( numVertices+firstVertexIndex >= MAX_VERTICES)
121     {
122         return;
123     }
124
125     //For each vertex
126     for (unsigned int i=firstVertexIndex; i <numVertices+firstVertexIndex; ++i)
127     {
128         m_vertices[i].x = vertex->x;
129         m_vertices[i].y = vertex->y;
130         m_vertices[i].z = vertex->z;
131         m_vertices[i].flag = vertex->flag;
132         m_vertices[i].s = _FIXED2FLOAT( vertex->s, 5 );
133         m_vertices[i].t = _FIXED2FLOAT( vertex->t, 5 );
134
135         if ( m_lightMgr->getLightEnabled() )
136         {
137             m_vertices[i].nx = vertex->normal.x;
138             m_vertices[i].ny = vertex->normal.y;
139             m_vertices[i].nz = vertex->normal.z;
140             m_vertices[i].a = vertex->color.a * 0.0039215689f;
141         }
142         else
143         {
144             m_vertices[i].r = vertex->color.r * 0.0039215689f;
145             m_vertices[i].g = vertex->color.g * 0.0039215689f;
146             m_vertices[i].b = vertex->color.b * 0.0039215689f;
147             m_vertices[i].a = vertex->color.a * 0.0039215689f;
148         }
149
150         _processVertex(i);
151         vertex++;
152     }
153 }
154
155 //-----------------------------------------------------------------------------
156 // Modify Vertex
157 //-----------------------------------------------------------------------------
158 void RSPVertexManager::modifyVertex( unsigned int vtx, unsigned int where, unsigned int val )
159 {
160     switch (where)
161     {
162         case G_MWO_POINT_RGBA:
163             m_vertices[vtx].r = _SHIFTR( val, 24, 8 ) * 0.0039215689f;
164             m_vertices[vtx].g = _SHIFTR( val, 16, 8 ) * 0.0039215689f;
165             m_vertices[vtx].b = _SHIFTR( val, 8, 8 ) * 0.0039215689f;
166             m_vertices[vtx].a = _SHIFTR( val, 0, 8 ) * 0.0039215689f;
167             break;
168         case G_MWO_POINT_ST:
169             m_vertices[vtx].s = _FIXED2FLOAT( (short)_SHIFTR( val, 16, 16 ), 5 );
170             m_vertices[vtx].t = _FIXED2FLOAT( (short)_SHIFTR( val, 0, 16 ), 5 );
171             break;
172         case G_MWO_POINT_XYSCREEN:
173             break;
174         case G_MWO_POINT_ZSCREEN:
175             break;
176     }
177 }
178
179 void RSPVertexManager::setVertexColor(unsigned int vertexIndex, float r, float g, float b, float a)
180 {
181     m_vertices[vertexIndex].r = r;
182     m_vertices[vertexIndex].g = g;
183     m_vertices[vertexIndex].b = b;
184     m_vertices[vertexIndex].a = a;
185 }
186
187 void RSPVertexManager::setVertexTextureCoord(unsigned int vertexIndex, float s, float t)
188 {
189     m_vertices[vertexIndex].s = s;
190     m_vertices[vertexIndex].t = t;
191 }
192
193
194 //-----------------------------------------------------------------------------
195 // ?
196 //-----------------------------------------------------------------------------
197 void RSPVertexManager::ciVertex(unsigned int segmentAddress, unsigned int numVertices, unsigned int firstVertexIndex)
198 {
199     unsigned int rdramAddress = m_memory->getRDRAMAddress(segmentAddress);
200
201     if ((rdramAddress + sizeof(PerfectDarkVertex) * numVertices) > m_memory->getRDRAMSize())
202     {
203         return;
204     }
205
206     PerfectDarkVertex* vertex = (PerfectDarkVertex*)m_memory->getRDRAM(rdramAddress);
207
208     //Avoid overflow. There can only be MAX_VERTICES in size.
209     if ( numVertices+firstVertexIndex >= MAX_VERTICES)
210     {
211         return;    
212     }
213
214     //For each vertex
215     for (unsigned int i=firstVertexIndex; i <numVertices+firstVertexIndex; ++i)
216     {
217         m_vertices[i].x    = vertex->x;
218         m_vertices[i].y    = vertex->y;
219         m_vertices[i].z    = vertex->z;
220         m_vertices[i].flag = 0;
221         m_vertices[i].s    = _FIXED2FLOAT( vertex->s, 5 );
222         m_vertices[i].t    = _FIXED2FLOAT( vertex->t, 5 );
223
224         //Get color
225         unsigned char* color = m_memory->getRDRAM(m_colorBaseRDRAMAddress + (vertex->ci & 0xff));
226
227         //Assign color
228         if ( m_lightMgr->getLightEnabled() )
229         {
230             m_vertices[i].nx = (short)color[3];
231             m_vertices[i].ny = (short)color[2];
232             m_vertices[i].nz = (short)color[1];
233             m_vertices[i].a = color[0] * 0.0039215689f;
234         }
235         else
236         {
237             m_vertices[i].r = color[3] * 0.0039215689f;
238             m_vertices[i].g = color[2] * 0.0039215689f;
239             m_vertices[i].b = color[1] * 0.0039215689f;
240             m_vertices[i].a = color[0] * 0.0039215689f;
241         }
242
243         _processVertex( i );
244         vertex++;
245     }
246 }
247
248 //-----------------------------------------------------------------------------
249 // ?
250 //-----------------------------------------------------------------------------
251 void RSPVertexManager::DMAVertex( unsigned int v, unsigned int numVertices, unsigned int firstVertexIndex)
252 {
253     unsigned int address = m_rdramOffset + m_memory->getRDRAMAddress( v );
254
255     if ((address + 10 * numVertices) > m_memory->getRDRAMSize())
256     {
257         return;
258     }
259
260     unsigned char* RDRAM = m_memory->getRDRAM();
261
262     if ((numVertices + firstVertexIndex) < (80))
263     {
264         for (unsigned int i = firstVertexIndex; i < numVertices + firstVertexIndex; i++)
265         {
266             m_vertices[i].x = *(short*)&RDRAM[address ^ 2];
267             m_vertices[i].y = *(short*)&RDRAM[(address + 2) ^ 2];
268             m_vertices[i].z = *(short*)&RDRAM[(address + 4) ^ 2];
269
270             if ( m_lightMgr->getLightEnabled() )
271             {
272                 m_vertices[i].nx = *(char*)&RDRAM[(address + 6) ^ 3];
273                 m_vertices[i].ny = *(char*)&RDRAM[(address + 7) ^ 3];
274                 m_vertices[i].nz = *(char*)&RDRAM[(address + 8) ^ 3];
275                 m_vertices[i].a = *(unsigned char*)&RDRAM[(address + 9) ^ 3] * 0.0039215689f;
276             }
277             else
278             {
279                 m_vertices[i].r = *(unsigned char*)&RDRAM[(address + 6) ^ 3] * 0.0039215689f;
280                 m_vertices[i].g = *(unsigned char*)&RDRAM[(address + 7) ^ 3] * 0.0039215689f;
281                 m_vertices[i].b = *(unsigned char*)&RDRAM[(address + 8) ^ 3] * 0.0039215689f;
282                 m_vertices[i].a = *(unsigned char*)&RDRAM[(address + 9) ^ 3] * 0.0039215689f;
283             }
284
285             _processVertex( i );
286
287             address += 10;
288         }
289     }
290 }
291
292 //-----------------------------------------------------------------------------
293 // ?
294 //-----------------------------------------------------------------------------
295 void RSPVertexManager::DMAOffsets( unsigned int mtxoffset, unsigned int vtxoffset )
296 {
297     static bool warned = false;
298     if ( !warned ) {
299         Logger::getSingleton().printMsg("VertexManager - DMAOffsets - Unimplemented", M64MSG_WARNING);
300         warned = true;
301     }
302 }
303
304 //-----------------------------------------------------------------------------
305 //! @param v0 Index of first vertex in triangle
306 //! @param v1 Index of second vertex in triangle
307 //! @param v2 Index of third vertex in triangle
308 //-----------------------------------------------------------------------------
309 bool RSPVertexManager::add1Triangle(unsigned int v0, unsigned int v1, unsigned int v2 )
310 {
311     bool triangleAdded = false;
312
313     if (true)//IsTriangleVisible(dwV0, dwV1, dwV2))
314     {
315         if ( !((v0 < MAX_VERTICES) && (v1 < MAX_VERTICES) && (v2 < MAX_VERTICES)) )
316         {
317             return false;
318         }
319
320         // Don't bother with triangles completely outside clipping frustrum
321         if (((m_vertices[v0].xClip <  0.0f) && (m_vertices[v1].xClip <  0.0f) && (m_vertices[v2].xClip <  0.0f)) ||
322             ((m_vertices[v0].xClip >  0.0f) && (m_vertices[v1].xClip >  0.0f) && (m_vertices[v2].xClip >  0.0f)) ||
323             ((m_vertices[v0].yClip <  0.0f) && (m_vertices[v1].yClip <  0.0f) && (m_vertices[v2].yClip <  0.0f)) ||
324             ((m_vertices[v0].yClip >  0.0f) && (m_vertices[v1].yClip >  0.0f) && (m_vertices[v2].yClip >  0.0f)) ||
325             ((m_vertices[v0].zClip >  0.1f) && (m_vertices[v1].zClip >  0.1f) && (m_vertices[v2].zClip >  0.1f)) ||
326             ((m_vertices[v0].zClip < -0.1f) && (m_vertices[v1].zClip < -0.1f) && (m_vertices[v2].zClip < -0.1f))    )
327         {
328             return false;
329         }
330         triangleAdded = true;
331
332         //Add vertex to vertex buffer
333         OpenGLRenderer::getSingleton().addTriangle( m_vertices, v0, v1, v2 );
334     }
335
336     return triangleAdded;
337 }
338
339 void RSPVertexManager::add2Triangles( int v00, int v01, int v02, int flag0,
340                                       int v10, int v11, int v12, int flag1 )
341 {
342     //implemented by calling add1Triangle multiple times
343
344     static bool warned = false;
345     if ( !warned ) {
346         Logger::getSingleton().printMsg("VertexManager - add2Triangles - Unimplemented", M64MSG_WARNING);
347         warned = true;
348     }
349 }
350
351 void RSPVertexManager::add4Triangles( int v00, int v01, int v02,
352                     int v10, int v11, int v12,
353                     int v20, int v21, int v22,
354                     int v30, int v31, int v32 )
355 {
356     //implemented by calling add1Triangle multiple times
357
358
359     static bool warned = false;
360     if ( !warned ) {
361         Logger::getSingleton().printMsg("VertexManager - add4Triangles - Unimplemented", M64MSG_WARNING);
362         warned = true;
363     }
364 }
365
366 //! @todo Set culling
367 void RSPVertexManager::addDMATriangles( unsigned int tris, unsigned int n )
368 {
369     unsigned int address = m_memory->getRDRAMAddress(tris);
370
371     if (address + sizeof( DKRTriangle ) * n > m_memory->getRDRAMSize() )
372     {
373         return;
374     }
375
376     DKRTriangle *triangles = (DKRTriangle*)m_memory->getRDRAM(address);
377
378     for (unsigned int i = 0; i < n; i++)
379     {
380         //TODO Set culling
381         //gSP.geometryMode &= ~G_CULL_BOTH;
382         //if (!(triangles->flag & 0x40))
383         //{
384         //    if (gSP.viewport.vscale[0] > 0)
385         //        gSP.geometryMode |= G_CULL_BACK;
386         //    else
387         //        gSP.geometryMode |= G_CULL_FRONT;
388         //}
389         //gSP.changed |= CHANGED_GEOMETRYMODE;
390         glDisable(GL_CULL_FACE);
391         
392         m_vertices[triangles->v0].s = _FIXED2FLOAT( triangles->s0, 5 );
393         m_vertices[triangles->v0].t = _FIXED2FLOAT( triangles->t0, 5 );
394         m_vertices[triangles->v1].s = _FIXED2FLOAT( triangles->s1, 5 );
395         m_vertices[triangles->v1].t = _FIXED2FLOAT( triangles->t1, 5 );
396         m_vertices[triangles->v2].s = _FIXED2FLOAT( triangles->s2, 5 );
397         m_vertices[triangles->v2].t = _FIXED2FLOAT( triangles->t2, 5 );
398
399         add1Triangle( triangles->v0, triangles->v1, triangles->v2 /*, 0 */ );
400
401         triangles++;
402     }
403 }
404
405
406 void RSPVertexManager::setConkerAddress(unsigned int segmentAddress)
407 {
408     m_conkerRDRAMAddress = m_memory->getRDRAMAddress(segmentAddress);
409 }
410     
411
412 void RSPVertexManager::add1Quadrangle( int v0, int v1, int v2, int v4 )
413 {
414     //implemented by calling add1Triangle multiple times
415
416     static bool warned = false;
417     if ( !warned ) {
418         Logger::getSingleton().printMsg("VertexManager - add1Quadrangle - Unimplemented", M64MSG_WARNING);
419         warned = true;
420     }
421 }
422
423
424 inline float DotProduct( float* v0, float* v1 )
425 {
426     float    dot;
427     dot = v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2];
428     return dot;
429 }
430
431
432 void RSPVertexManager::_processVertex( unsigned int v )
433 {
434 //    float intensity;
435 //    float r, g, b;
436
437     transformVertex( m_matrixMgr->getViewProjectionMatrix(), &m_vertices[v].x, &m_vertices[v].x);
438     //TransformVertex( &m_vertices[v].x, m_worldProject );
439
440
441     if ( m_billboard )
442     {
443         m_vertices[v].x += m_vertices[0].x;
444         m_vertices[v].y += m_vertices[0].y;
445         m_vertices[v].z += m_vertices[0].z;
446         m_vertices[v].w += m_vertices[0].w;
447     }
448
449
450     if ( !OpenGLManager::getSingleton().getZBufferEnabled() )
451     {
452         m_vertices[v].z = -m_vertices[v].w;
453     }
454
455     //Temporary variables
456     float intensity;
457     float r, g, b;
458
459     if ( m_lightMgr->getLightEnabled() )
460     {
461         //Transform normal
462         transformVector( m_matrixMgr->getModelViewMatrix(), &m_vertices[v].nx, &m_vertices[v].nx );
463         Vec3Normalize( &m_vertices[v].nx );
464
465         //Get Ambient Color
466         const float* ambientColor = m_lightMgr->getAmbientLight();
467         r = ambientColor[0];
468         g = ambientColor[1];
469         b = ambientColor[2];
470
471         for (int i=0; i<m_lightMgr->getNumLights(); ++i)
472         {
473             intensity = DotProduct( (float*)&m_vertices[v].nx, (float*)m_lightMgr->getLightDirection(i) );
474
475             if (intensity < 0.0f) intensity = 0.0f;
476
477             const float* lightColor = m_lightMgr->getLightColor(i);
478             r += lightColor[0] * intensity;
479             g += lightColor[1] * intensity;
480             b += lightColor[2] * intensity;
481         }
482
483         //Set Color
484         m_vertices[v].r = r;
485         m_vertices[v].g = g;
486         m_vertices[v].b = b;    
487     }
488
489     //Texture Generation
490     if ( m_texCoordGenType != TCGT_NONE )
491     {
492         transformVector( m_matrixMgr->getProjectionMatrix(), &m_vertices[v].nx, &m_vertices[v].nx );
493
494         Vec3Normalize( &m_vertices[v].nx );
495
496         if ( m_texCoordGenType == TCGT_LINEAR )
497         {   
498             m_vertices[v].s = acosf(m_vertices[v].nx) * 325.94931f;
499             m_vertices[v].t = acosf(m_vertices[v].ny) * 325.94931f;
500         }
501         else // TGT_GEN
502         {
503             m_vertices[v].s = (m_vertices[v].nx + 1.0f) * 512.0f;
504             m_vertices[v].t = (m_vertices[v].ny + 1.0f) * 512.0f;
505         }
506     }
507
508     //Clipping
509     if (m_vertices[v].x < -m_vertices[v].w)  
510         m_vertices[v].xClip = -1.0f;
511     else if (m_vertices[v].x > m_vertices[v].w)
512         m_vertices[v].xClip = 1.0f;
513     else
514         m_vertices[v].xClip = 0.0f;
515
516     if (m_vertices[v].y < -m_vertices[v].w)
517         m_vertices[v].yClip = -1.0f;
518     else if (m_vertices[v].y > m_vertices[v].w)
519         m_vertices[v].yClip = 1.0f;
520     else
521         m_vertices[v].yClip = 0.0f;
522
523     if (m_vertices[v].w <= 0.0f)
524         m_vertices[v].zClip = -1.0f;
525     else if (m_vertices[v].z < -m_vertices[v].w)
526         m_vertices[v].zClip = -0.1f;
527     else if (m_vertices[v].z > m_vertices[v].w)
528         m_vertices[v].zClip = 1.0f;
529     else
530         m_vertices[v].zClip = 0.0f;
531
532 }
533
534
535 void RSPVertexManager::addConkerVertices(unsigned int segmentAddress, unsigned int n, unsigned int v0 )
536 {
537     unsigned int numVertices = n;
538     unsigned int firstVertexIndex = v0;
539     unsigned int address = m_memory->getRDRAMAddress( segmentAddress );
540
541     //Make sure address is valid
542     if ((address + sizeof( Vertex ) * numVertices) > m_memory->getRDRAMSize()) {
543         return;
544     }
545
546     //Get vertex from rdram
547     Vertex *vertex = (Vertex*) m_memory->getRDRAM(address);
548
549
550     //For each vertex
551     for (unsigned int i=firstVertexIndex; i <numVertices+firstVertexIndex; ++i)
552     {
553         m_vertices[i].x = vertex->x;
554         m_vertices[i].y = vertex->y;
555         m_vertices[i].z = vertex->z;
556         m_vertices[i].flag = vertex->flag;
557         m_vertices[i].s = _FIXED2FLOAT( vertex->s, 5 );
558         m_vertices[i].t = _FIXED2FLOAT( vertex->t, 5 );
559
560         if ( m_lightMgr->getLightEnabled() )
561         {
562             m_vertices[i].nx = vertex->normal.x;
563             m_vertices[i].ny = vertex->normal.y;
564             m_vertices[i].nz = vertex->normal.z;
565             m_vertices[i].a = vertex->color.a * 0.0039215689f;
566         }
567         else
568         {
569             m_vertices[i].r = vertex->color.r * 0.0039215689f;
570             m_vertices[i].g = vertex->color.g * 0.0039215689f;
571             m_vertices[i].b = vertex->color.b * 0.0039215689f;
572             m_vertices[i].a = vertex->color.a * 0.0039215689f;
573         }
574
575         _processVertex(i);
576         vertex++;
577     }
578 }