MercuryMesh.cpp

Go to the documentation of this file.
00001 #include "MercuryMesh.h"
00002 #include "MercuryUtil.h"
00003 #include "MercuryDisplay.h"
00004 #include "MercuryPoly.h"
00005 #include "MercuryMath.h"
00006 #include "MercuryLog.h"
00007 
00008 MercuryMeshManager MESHMAN;
00009 
00010 MercuryMeshCore::MercuryMeshCore()
00011 {
00012     m_iMeshCount = 0;
00013     m_drawType = MGL_INVALID;
00014 
00015     m_useVBOs = false;
00016     m_verticesVBO = MVPtr(NULL);
00017     m_tangentVBO = MVPtr(NULL);
00018     m_binormalVBO = MVPtr(NULL);
00019     m_indicesVBO = MVPtr(NULL);
00020     m_extrasVBO = MVPtr(NULL);
00021     m_VBOinited = false;
00022 }
00023 
00024 bool MercuryMeshManager::RegMesh( MercuryMesh * pOut, const MString & sName, bool bCanCache )
00025 {
00026     if( !bCanCache )
00027     {
00028         pOut->SetName( sName );
00029         pOut->core = new MercuryMeshCore;
00030         pOut->Init();
00031         pOut->core->m_iMeshCount = 1;
00032         return false;
00033     }
00034 
00035     MercuryMeshCore ** m = m_hAllMeshes.get(sName);
00036 
00037     //We already have one sitting aroudn
00038     if( m )
00039     {
00040         pOut->SetName( sName );
00041         pOut->Init();
00042         pOut->core = (*m);
00043         pOut->core->m_iMeshCount++;
00044         return true;
00045     }
00046 
00047     //Otherwise, we have to make it
00048     pOut->SetName( sName );
00049     m_hAllMeshes[sName] = pOut->core = new MercuryMeshCore;
00050     pOut->Init();
00051     pOut->core->m_iMeshCount = 1;
00052     return false;
00053 }
00054 
00055 void MercuryMeshManager::UnregMesh( MercuryMesh * pIn )
00056 {
00057     pIn->core->m_iMeshCount--;
00058     if( pIn->core->m_iMeshCount <= 0 )
00059     {
00060         DISPLAY->DestroyVBO(*pIn);
00061 
00062         if( m_hAllMeshes.get( pIn->GetName() ) )
00063             m_hAllMeshes.remove( pIn->GetName() );
00064         SAFE_DELETE( pIn->core );
00065         return;
00066     }
00067 }
00068 
00069 
00070 MercuryMesh::MercuryMesh()
00071 :MercuryObject()
00072 {
00073     m_glState.Disable(MGLS_ALL);
00074     m_glState.Enable(MGLS_DEPTHWRITE | MGLS_DEPTHTEST | MGLS_COLORWRITE | MGLS_VERTEXARRAY |
00075                     MGLS_NORMALARRAY | MGLS_UVARRAY | MGLS_TEXTURING | MGLS_LIGHTING | MGLS_BLEND |
00076                     MGLS_SHADER | MGLS_OPAQUE );
00077 }
00078 
00079 MercuryMesh::~MercuryMesh()
00080 {
00081     MESHMAN.UnregMesh(this);
00082 }
00083 
00084 void MercuryMesh::Init()
00085 {
00086     MercuryObject::Init();
00087     m_drawable = true;
00088 }
00089 
00090 void MercuryMesh::Draw() 
00091 {
00092     if (core->m_drawType == MGL_INVALID)
00093         return;
00094 
00095     ASSERT(!GetName().empty());
00096   
00097     DISPLAY->SendMatrixData(GetFinalMatrix());
00098 
00099 //  if (core->m_VBOinited)
00100 //      DISPLAY->DrawMeshVBO(*this);
00101 //  else
00102         DISPLAY->DrawMesh(*this);
00103 }
00104 
00105 void MercuryMesh::BuildVBO()
00106 {
00107     if (core->m_useVBOs && !core->m_VBOinited)
00108     {
00109         DISPLAY->GenerateVBO(*this);
00110         core->m_VBOinited = true;
00111     }
00112 }
00113 
00114 void MercuryMeshCore::CalculateVertexNormals()
00115 {
00116     unsigned i;
00117     MVector <float> numFacePerVert;
00118     numFacePerVert.resize(m_vertices.size());
00119 
00120     for( i = 0; i < m_vertices.size(); ++i )
00121     {
00122         numFacePerVert[i] = 0;
00123         m_vertices[i].m_normal.Clear();
00124     }
00125 
00126     if (m_drawType == MGL_TRIANGLE)
00127         for( i = 0; i < m_indices.size(); i+=3 )
00128         {
00129             MercuryPoint pThisNormal = ( m_vertices[m_indices[i]].GetPointHandle() -
00130                     m_vertices[m_indices[i+1]].GetPointHandle() ).CrossProduct(
00131                     m_vertices[m_indices[i]].GetPointHandle() -
00132                     m_vertices[m_indices[i+2]].GetPointHandle());
00133 
00134             m_vertices[m_indices[i]].m_normal += pThisNormal;
00135             m_vertices[m_indices[i+1]].m_normal += pThisNormal;
00136             m_vertices[m_indices[i+2]].m_normal += pThisNormal;
00137 
00138             ++numFacePerVert[m_indices[i]];
00139             ++numFacePerVert[m_indices[i+1]];
00140             ++numFacePerVert[m_indices[i+2]];
00141         }
00142 
00143     for( i = 0; i < m_vertices.size(); ++i )
00144     {
00145         m_vertices[i].m_normal /= numFacePerVert[i];
00146         m_vertices[i].m_normal.NormalizeSelf();
00147     }
00148 
00149     ComputeBinormalsAndTangents();
00150 }
00151 
00153 
00154 //This function takes a 3-high, 3-wide, matrix, in the form:
00155 // [0] [1] [2] [3]
00156 // [4] [5] [6] [7]
00157 // [8] [9][10][11]
00158 //
00159 // and solves it so it has the form:
00160 //  1   0   0   A
00161 //  0   1   0   B
00162 //  0   0   1   C
00163 //
00164 // This can be used in more general cases, but isn't ready for MercuryMathing
00165 
00166 inline void RowAddEqualScalar( float * r1s, float * r2, float scalar )
00167 { r1s[0] += r2[0] * scalar; r1s[1] += r2[1] * scalar; r1s[2] += r2[2] * scalar; r1s[3] += r2[3] * scalar; }
00168 
00169 inline void RowScale( float * r1s, float scalar )
00170 { r1s[0] *= scalar; r1s[1] *= scalar; r1s[2] *= scalar; r1s[3] *= scalar; }
00171 
00172 void SolveThreeByFour( float * mat )
00173 {
00174     //Step 1, prevent inaccuracies by adding various rows to each other to make the matrix
00175     //  have bigger numbers to start with
00176     if( ABS( mat[0] ) < 0.001f )
00177         if( ABS( mat[4] ) > ABS( mat[8] ) )
00178             RowAddEqualScalar( &mat[0], &mat[4], 1 );
00179         else
00180             RowAddEqualScalar( &mat[0], &mat[8], 1 );
00181 
00182     //Now that our matrix has nice values, we can solve it.
00183     RowScale( &mat[0], 1.f/mat[0] );
00184     RowAddEqualScalar( &mat[4], &mat[0], -mat[4]/mat[0] );
00185     RowAddEqualScalar( &mat[8], &mat[0], -mat[8]/mat[0] );
00186 
00187     if( ABS( mat[5] ) < 0.001f )
00188         if( ABS( mat[1] ) > ABS( mat[9] ) )
00189             RowAddEqualScalar( &mat[4], &mat[0], 1 );
00190         else
00191             RowAddEqualScalar( &mat[4], &mat[8], 1 );
00192 
00193     RowScale( &mat[4], 1.f/mat[5] );
00194     RowAddEqualScalar( &mat[0], &mat[4], -mat[1]/mat[5] );
00195     RowAddEqualScalar( &mat[8], &mat[4], -mat[9]/mat[5] );
00196 
00197     if( ABS( mat[10] ) < 0.001f )
00198         if( ABS( mat[2] ) > ABS( mat[6] ) )
00199             RowAddEqualScalar( &mat[8], &mat[0], 1 );
00200         else
00201             RowAddEqualScalar( &mat[8], &mat[4], 1 );
00202 
00203     RowScale( &mat[8], 1.f/mat[10] );
00204     RowAddEqualScalar( &mat[0], &mat[8], -mat[2]/mat[10] );
00205     RowAddEqualScalar( &mat[4], &mat[8], -mat[6]/mat[10] );
00206 
00207     //verify here that we're solved
00208     return;
00209 }
00210 
00211 void MercuryMeshCore::ComputeBinormalsAndTangents()
00212 {
00213     if (m_indices.size() <= 0)
00214         return;
00215 
00216     unsigned int * ints = &m_indices[0];
00217 
00218     m_tangents.resize( m_vertices.size() );
00219     m_binormals.resize( m_vertices.size() );
00220 
00221     unsigned i;
00222 
00223     for( i = 0; i < m_indices.size(); i+=3 )
00224     {
00225         unsigned int ind[3];
00226         ind[0] = ints[i+0];
00227         ind[1] = ints[i+1];
00228         ind[2] = ints[i+2];
00229 
00230         float uv[3][2];
00231         MercuryPoint p[3];
00232         p[0] = m_vertices[ind[0]].GetPointHandle();
00233         p[1] = m_vertices[ind[1]].GetPointHandle();
00234         p[2] = m_vertices[ind[2]].GetPointHandle();
00235         m_vertices[ind[0]].GetUV( uv[0] );
00236         m_vertices[ind[1]].GetUV( uv[1] );
00237         m_vertices[ind[2]].GetUV( uv[2] );
00238 
00239         MercuryPoint pLocalNormal;
00240         pLocalNormal = (p[0] - p[1]).CrossProduct( p[2] - p[1] );
00241         pLocalNormal.NormalizeSelf();
00242 
00243         bool bSubZForX = false;
00244         bool bSubZForY = false;
00245 
00246         if( ABS( pLocalNormal.z ) < 0.001f )
00247         {
00248             if( ABS( pLocalNormal.y ) < 0.001f )
00249                 bSubZForX = true;
00250             else
00251                 bSubZForY = true;
00252         }
00253 
00254         float fMatToSolve[12];
00255         fMatToSolve[ 0] = (!bSubZForX)?p[0].x:p[0].z;
00256         fMatToSolve[ 1] = (!bSubZForY)?p[0].y:p[0].z;
00257         fMatToSolve[ 2] = uv[0][1];
00258         fMatToSolve[ 3] = 1;
00259         fMatToSolve[ 4] = (!bSubZForX)?p[1].x:p[1].z;
00260         fMatToSolve[ 5] = (!bSubZForY)?p[1].y:p[1].z;
00261         fMatToSolve[ 6] = uv[1][1];
00262         fMatToSolve[ 7] = 1;
00263         fMatToSolve[ 8] = (!bSubZForX)?p[2].x:p[2].z;
00264         fMatToSolve[ 9] = (!bSubZForY)?p[2].y:p[2].z;
00265         fMatToSolve[10] = uv[2][1];
00266         fMatToSolve[11] = 1;
00267 
00268         SolveThreeByFour( fMatToSolve );
00269         
00270         float xComp = fMatToSolve[3];
00271         float yComp = fMatToSolve[7];
00272         float cComp = fMatToSolve[11];
00273 
00274         MercuryPoint pBiNormal;
00275         if( bSubZForX )
00276         {
00277             pBiNormal.x = 0;
00278             pBiNormal.y = yComp;
00279             pBiNormal.z = xComp;
00280         } else if( bSubZForY )
00281         {
00282             pBiNormal.x = xComp;
00283             pBiNormal.y = 0;
00284             pBiNormal.z = yComp;
00285         }
00286         else
00287         {
00288             pBiNormal.x = xComp;
00289             pBiNormal.y = yComp;
00290             pBiNormal.z = 0;
00291         }
00292 
00293         MercuryPoint pTangent = (pBiNormal.CrossProduct( pLocalNormal )).Normalize();
00294 
00295         pBiNormal = (pTangent.CrossProduct( pLocalNormal)).Normalize();
00296 
00297         m_tangents[ind[0]] += pTangent;
00298         m_tangents[ind[1]] += pTangent;
00299         m_tangents[ind[2]] += pTangent;
00300 
00301         m_binormals[ind[0]] += pBiNormal;
00302         m_binormals[ind[1]] += pBiNormal;
00303         m_binormals[ind[2]] += pBiNormal;
00304     }
00305 
00306     //Now, we have all local BiNormals and Tangents.  Let's weight and set them all
00307     for( i = 0; i < m_tangents.size(); ++i )
00308     {
00309         m_tangents[i].NormalizeSelf();
00310         m_binormals[i].NormalizeSelf();
00311     //  m_vertices[i].m_normal = -1 * m_binormals[i];
00312     }
00313 
00314 }
00315 
00316 /* 
00317  * Copyright (c) 2006 Joshua Allen
00318  * All rights reserved.
00319  *
00320  * Redistribution and use in source and binary forms, with or
00321  * without modification, are permitted provided that the following
00322  * conditions are met:
00323  *  -   Redistributions of source code must retain the above
00324  *      copyright notice, this list of conditions and the following disclaimer.
00325  *  -   Redistributions in binary form must reproduce the above copyright
00326  *      notice, this list of conditions and the following disclaimer in
00327  *      the documentation and/or other materials provided with the distribution.
00328  *  -   Neither the name of the Mercury Engine nor the names of its
00329  *      contributors may be used to endorse or promote products derived from
00330  *      this software without specific prior written permission.
00331  *
00332  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00333  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00334  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00335  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00336  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00337  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00338  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00339  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00340  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00341  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00342  */

Hosted by SourceForge.net Logo