89a4923639b9a39691dd1533b30fb1eb00c7c589
[mupen64plus-pandora.git] / source / mupen64plus-video-arachnoid / src / RSP / RSPMatrixManager.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 "RSPMatrixManager.h"
23 #include "Memory.h"
24 #include <cmath>      //modff
25 #include "GBI.h"      //SHIFT
26 #include "GBIDefs.h"  //_FIXED2FLOAT
27 //-----------------------------------------------------------------------------
28 //! Constructor
29 //-----------------------------------------------------------------------------
30 RSPMatrixManager::RSPMatrixManager()
31 {
32
33 }
34
35 //-----------------------------------------------------------------------------
36 //! Destructor
37 //-----------------------------------------------------------------------------
38 RSPMatrixManager::~RSPMatrixManager()
39 {
40
41 }
42
43 //-----------------------------------------------------------------------------
44 //* Initialize
45 //-----------------------------------------------------------------------------
46 bool RSPMatrixManager::initialize(Memory* memory)
47 {
48     m_memory = memory;
49     m_rdramOffset = 0;
50     return true;
51 }
52
53 //-----------------------------------------------------------------------------
54 //! Add Matrix
55 //! @param segmentAddress Later converted to RDRam address pointing to Matrix to load
56 //! @param projectionMatrix True if matrix is a projection matrix, 
57 //!                         False if matrix is a modelview matrix
58 //! @param push True if adding a new matrix to stack(and saving the old one)
59 //! @param replace True if loading matrix (glLoadMatrix), false if multiplying with the previus matrix (glMultMatrix)
60 //-----------------------------------------------------------------------------
61 void RSPMatrixManager::addMatrix(unsigned int segmentAddress, bool projectionMatrix, bool push, bool replace)
62 {
63     unsigned int rdramAddress = m_memory->getRDRAMAddress(segmentAddress);
64
65     if (rdramAddress + 64 > m_memory->getRDRAMSize() ) {
66         return;
67     }
68
69     Matrix4 temp;
70     _loadMatrix(rdramAddress, temp);
71     
72     if ( projectionMatrix )
73     {
74         _setProjection(temp, push, replace);
75     }
76     else
77     {
78         _setWorldView(temp, push, replace);
79     }
80
81     _updateCombinedMatrix();
82 }
83
84 //-----------------------------------------------------------------------------
85 //! Insert Matrix
86 //-----------------------------------------------------------------------------
87 void RSPMatrixManager::insertMatrix(unsigned int where, unsigned int num) 
88 {
89     float fraction, integer;
90
91     _updateCombinedMatrix();
92
93     if ((where & 0x3) || (where > 0x3C))
94     {
95         return;
96     }
97
98     if (where < 0x20)
99     {
100         fraction = modff( m_worldProject[0][where >> 1], &integer );
101         m_worldProject[0][where >> 1] = (short)_SHIFTR( num, 16, 16 ) + fabs( fraction );
102
103         fraction = modff( m_worldProject[0][(where >> 1) + 1], &integer );
104         m_worldProject[0][(where >> 1) + 1] = (short)_SHIFTR( num, 0, 16 ) + fabs( fraction );
105     }
106     else
107     {
108         float newValue;
109
110         fraction = modff( m_worldProject[0][(where - 0x20) >> 1], &integer );
111         newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 16, 16 ), 16);
112
113         // Make sure the sign isn't lost
114         if ((integer == 0.0f) && (fraction != 0.0f))
115             newValue = newValue * (fraction / fabs( fraction ));
116
117         m_worldProject[0][(where - 0x20) >> 1] = newValue;
118
119         fraction = modff( m_worldProject[0][((where - 0x20) >> 1) + 1], &integer );
120         newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 0, 16 ), 16 );
121
122         // Make sure the sign isn't lost
123         if ((integer == 0.0f) && (fraction != 0.0f))
124             newValue = newValue * (fraction / fabs( fraction ));
125
126         m_worldProject[0][((where - 0x20) >> 1) + 1] = newValue;
127     }
128 }
129 void RSPMatrixManager::ForceMatrix(unsigned int rdramAddress)
130 {
131     _loadMatrix(rdramAddress, m_worldProject);
132 }
133         
134
135
136 //-----------------------------------------------------------------------------
137 // Pop Matrix
138 //-----------------------------------------------------------------------------
139 void RSPMatrixManager::popMatrix()
140 {
141     if ( m_modelViewMatrixTop > 0 )
142     {
143         m_modelViewMatrixTop--;             //Pop Matrix from stack
144     }
145
146     _updateCombinedMatrix();
147 }
148
149 //-----------------------------------------------------------------------------
150 // Pop Matrix N
151 //-----------------------------------------------------------------------------
152 void RSPMatrixManager::popMatrixN(unsigned int num)
153 {
154     if ( m_modelViewMatrixTop > num - 1)
155     {
156         m_modelViewMatrixTop -= num;
157     }
158
159     _updateCombinedMatrix();
160 }
161
162 //-----------------------------------------------------------------------------
163 //! DMA Matrix
164 //-----------------------------------------------------------------------------
165 void RSPMatrixManager::DMAMatrix( unsigned int rdramAddress, unsigned char index, unsigned char multiply )
166 {
167     //Get final address
168     unsigned int address = m_rdramOffset + rdramAddress;
169
170     if (address + 64 > m_memory->getRDRAMSize())
171     {
172         return;
173     }
174
175     //Load Matrix from Memory
176     Matrix4 temp;
177     _loadMatrix(rdramAddress, temp);
178     
179     //Set Modelview index
180     m_modelViewMatrixTop = index;
181
182     //FIXME: Other way around?
183     if (multiply)
184     {
185         m_modelViewMatrices[m_modelViewMatrixTop] = m_modelViewMatrices[0];  
186         m_modelViewMatrices[m_modelViewMatrixTop] = m_modelViewMatrices[m_modelViewMatrixTop] * temp;
187     }
188     else 
189     {
190         m_modelViewMatrices[m_modelViewMatrixTop] = temp;
191     }
192
193     //Set Projection Matrix to Identity
194     m_projectionMatrices[m_projectionMatrixTop] = Matrix4::IDENTITY;
195
196     //Update Matrices
197     _updateCombinedMatrix();
198 }
199
200 //-----------------------------------------------------------------------------
201 //! Reset Matrices
202 //-----------------------------------------------------------------------------
203 void RSPMatrixManager::resetMatrices()
204 {
205     m_modelViewMatrices[0] = Matrix4::IDENTITY;
206     m_projectionMatrices[0] = Matrix4::IDENTITY;
207
208     m_modelViewMatrixTop = 0;
209     m_projectionMatrixTop = 0;
210
211     _updateCombinedMatrix();
212 }
213
214 //-----------------------------------------------------------------------------
215 //! Load Matrix
216 //-----------------------------------------------------------------------------
217 void RSPMatrixManager::_loadMatrix(unsigned int addr, Matrix4& out)
218 {
219     if ( addr + 64 > m_memory->getRDRAMSize() ) {
220         return;
221     }
222
223     unsigned char* RDRAM = m_memory->getRDRAM();
224
225
226     for (int i = 0; i < 4; i++)
227     {
228         for (int j = 0; j < 4; j++) 
229         {
230             int             hi = *(short *)(RDRAM + ((addr+(i<<3)+(j<<1)     )^0x2));
231             unsigned short  lo = *(unsigned short  *)(RDRAM + ((addr+(i<<3)+(j<<1) + 32)^0x2));
232             out[i][j] = (float)((hi<<16) | (lo))/ 65536.0f;
233         }
234     }
235 }
236
237 //-----------------------------------------------------------------------------
238 //! Set Projection Matrix
239 //-----------------------------------------------------------------------------
240 void RSPMatrixManager::_setProjection(const Matrix4& mat, bool push, bool replace) 
241 {
242     Matrix4& oldMatrix = m_projectionMatrices[m_projectionMatrixTop];
243
244     if (push)
245     {
246         m_projectionMatrixTop++;
247     }
248
249     if ( replace )
250     {
251         m_projectionMatrices[m_projectionMatrixTop] = mat;
252     }
253     else
254     {
255         m_projectionMatrices[m_projectionMatrixTop] = mat * oldMatrix;        
256     }
257
258     _updateCombinedMatrix();
259 }
260
261 //-----------------------------------------------------------------------------
262 //! Set World View Matrix
263 //-----------------------------------------------------------------------------
264 void RSPMatrixManager::_setWorldView(const Matrix4 & mat, bool push, bool replace)
265 {
266     Matrix4& oldMatrix = m_modelViewMatrices[m_modelViewMatrixTop];
267
268     if (push)
269     {
270         m_modelViewMatrixTop++;
271     }
272
273     if ( replace )
274     {
275         m_modelViewMatrices[m_modelViewMatrixTop] = mat;
276     }
277     else
278     {
279         m_modelViewMatrices[m_modelViewMatrixTop] = mat * oldMatrix;        
280     }    
281
282     _updateCombinedMatrix();
283 }
284
285 //-----------------------------------------------------------------------------
286 //! Update Combined Matrix
287 //-----------------------------------------------------------------------------
288 void RSPMatrixManager::_updateCombinedMatrix()
289 {
290     m_worldProject = m_modelViewMatrices[m_modelViewMatrixTop] * m_projectionMatrices[m_projectionMatrixTop];
291 }