1 /******************************************************************************
2 * Arachnoid Graphics Plugin for Mupen64Plus
3 * http://bitbucket.org/wahrhaft/mupen64plus-video-arachnoid/
5 * Copyright (C) 2007 Kristofer Karlsson, Rickard Niklasson
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.
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.
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 *****************************************************************************/
22 #include "RSPMatrixManager.h"
24 #include <cmath> //modff
25 #include "GBI.h" //SHIFT
26 #include "GBIDefs.h" //_FIXED2FLOAT
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
30 RSPMatrixManager::RSPMatrixManager()
35 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
38 RSPMatrixManager::~RSPMatrixManager()
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
46 bool RSPMatrixManager::initialize(Memory* memory)
53 //-----------------------------------------------------------------------------
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)
63 unsigned int rdramAddress = m_memory->getRDRAMAddress(segmentAddress);
65 if (rdramAddress + 64 > m_memory->getRDRAMSize() ) {
70 _loadMatrix(rdramAddress, temp);
72 if ( projectionMatrix )
74 _setProjection(temp, push, replace);
78 _setWorldView(temp, push, replace);
81 _updateCombinedMatrix();
84 //-----------------------------------------------------------------------------
86 //-----------------------------------------------------------------------------
87 void RSPMatrixManager::insertMatrix(unsigned int where, unsigned int num)
89 float fraction, integer;
91 _updateCombinedMatrix();
93 if ((where & 0x3) || (where > 0x3C))
100 fraction = modff( m_worldProject[0][where >> 1], &integer );
101 m_worldProject[0][where >> 1] = (short)_SHIFTR( num, 16, 16 ) + fabs( fraction );
103 fraction = modff( m_worldProject[0][(where >> 1) + 1], &integer );
104 m_worldProject[0][(where >> 1) + 1] = (short)_SHIFTR( num, 0, 16 ) + fabs( fraction );
110 fraction = modff( m_worldProject[0][(where - 0x20) >> 1], &integer );
111 newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 16, 16 ), 16);
113 // Make sure the sign isn't lost
114 if ((integer == 0.0f) && (fraction != 0.0f))
115 newValue = newValue * (fraction / fabs( fraction ));
117 m_worldProject[0][(where - 0x20) >> 1] = newValue;
119 fraction = modff( m_worldProject[0][((where - 0x20) >> 1) + 1], &integer );
120 newValue = integer + _FIXED2FLOAT( _SHIFTR( num, 0, 16 ), 16 );
122 // Make sure the sign isn't lost
123 if ((integer == 0.0f) && (fraction != 0.0f))
124 newValue = newValue * (fraction / fabs( fraction ));
126 m_worldProject[0][((where - 0x20) >> 1) + 1] = newValue;
129 void RSPMatrixManager::ForceMatrix(unsigned int rdramAddress)
131 _loadMatrix(rdramAddress, m_worldProject);
136 //-----------------------------------------------------------------------------
138 //-----------------------------------------------------------------------------
139 void RSPMatrixManager::popMatrix()
141 if ( m_modelViewMatrixTop > 0 )
143 m_modelViewMatrixTop--; //Pop Matrix from stack
146 _updateCombinedMatrix();
149 //-----------------------------------------------------------------------------
151 //-----------------------------------------------------------------------------
152 void RSPMatrixManager::popMatrixN(unsigned int num)
154 if ( m_modelViewMatrixTop > num - 1)
156 m_modelViewMatrixTop -= num;
159 _updateCombinedMatrix();
162 //-----------------------------------------------------------------------------
164 //-----------------------------------------------------------------------------
165 void RSPMatrixManager::DMAMatrix( unsigned int rdramAddress, unsigned char index, unsigned char multiply )
168 unsigned int address = m_rdramOffset + rdramAddress;
170 if (address + 64 > m_memory->getRDRAMSize())
175 //Load Matrix from Memory
177 _loadMatrix(rdramAddress, temp);
179 //Set Modelview index
180 m_modelViewMatrixTop = index;
182 //FIXME: Other way around?
185 m_modelViewMatrices[m_modelViewMatrixTop] = m_modelViewMatrices[0];
186 m_modelViewMatrices[m_modelViewMatrixTop] = m_modelViewMatrices[m_modelViewMatrixTop] * temp;
190 m_modelViewMatrices[m_modelViewMatrixTop] = temp;
193 //Set Projection Matrix to Identity
194 m_projectionMatrices[m_projectionMatrixTop] = Matrix4::IDENTITY;
197 _updateCombinedMatrix();
200 //-----------------------------------------------------------------------------
202 //-----------------------------------------------------------------------------
203 void RSPMatrixManager::resetMatrices()
205 m_modelViewMatrices[0] = Matrix4::IDENTITY;
206 m_projectionMatrices[0] = Matrix4::IDENTITY;
208 m_modelViewMatrixTop = 0;
209 m_projectionMatrixTop = 0;
211 _updateCombinedMatrix();
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
217 void RSPMatrixManager::_loadMatrix(unsigned int addr, Matrix4& out)
219 if ( addr + 64 > m_memory->getRDRAMSize() ) {
223 unsigned char* RDRAM = m_memory->getRDRAM();
226 for (int i = 0; i < 4; i++)
228 for (int j = 0; j < 4; j++)
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;
237 //-----------------------------------------------------------------------------
238 //! Set Projection Matrix
239 //-----------------------------------------------------------------------------
240 void RSPMatrixManager::_setProjection(const Matrix4& mat, bool push, bool replace)
242 Matrix4& oldMatrix = m_projectionMatrices[m_projectionMatrixTop];
246 m_projectionMatrixTop++;
251 m_projectionMatrices[m_projectionMatrixTop] = mat;
255 m_projectionMatrices[m_projectionMatrixTop] = mat * oldMatrix;
258 _updateCombinedMatrix();
261 //-----------------------------------------------------------------------------
262 //! Set World View Matrix
263 //-----------------------------------------------------------------------------
264 void RSPMatrixManager::_setWorldView(const Matrix4 & mat, bool push, bool replace)
266 Matrix4& oldMatrix = m_modelViewMatrices[m_modelViewMatrixTop];
270 m_modelViewMatrixTop++;
275 m_modelViewMatrices[m_modelViewMatrixTop] = mat;
279 m_modelViewMatrices[m_modelViewMatrixTop] = mat * oldMatrix;
282 _updateCombinedMatrix();
285 //-----------------------------------------------------------------------------
286 //! Update Combined Matrix
287 //-----------------------------------------------------------------------------
288 void RSPMatrixManager::_updateCombinedMatrix()
290 m_worldProject = m_modelViewMatrices[m_modelViewMatrixTop] * m_projectionMatrices[m_projectionMatrixTop];