MercuryShapes.cpp

Go to the documentation of this file.
00001 #include "MercuryShapes.h"
00002 #include "MercuryINI.h"
00003 #include "MercuryMath.h"
00004 #include "MercuryLog.h"
00005 #include "MercuryUtil.h"
00006 #include "MercuryPoly.h"
00007 #include "MercuryTexture.h"
00008 #include "MercuryObjectFactory.h"
00009 
00010 MercuryShape::MercuryShape() : MercuryModel()
00011 {
00012     AddMaterial( new MercuryMaterial );
00013 }
00014 
00015 MercuryShape::~MercuryShape()
00016 {
00017 }
00018 
00019 bool MercuryShape::LoadImage( const MString & Filename )
00020 {
00021     //Assume 1st material for shapes
00022     MercuryMaterial* m = m_materials[0];
00023 
00024     m->LoadMaterial( Filename );
00025 
00026     m->m_diffuse.SetA( 1 );
00027     m->m_diffuse.SetB( 1 );
00028     m->m_diffuse.SetG( 1 );
00029     m->m_diffuse.SetR( 1 );
00030 
00031     m->m_specular.SetA( .4f );
00032     m->m_specular.SetB( .4f );
00033     m->m_specular.SetG( .4f );
00034     m->m_specular.SetR( .4f );
00035         
00036     m->m_ambient.SetA( .1f );
00037     m->m_ambient.SetB( .1f );
00038     m->m_ambient.SetG( .1f );
00039     m->m_ambient.SetR( .1f );
00040 
00041     if (m->NumTextures() > 0)
00042     {
00043         SetScaleX((m->GetTexture(0)->GetWidth() / m->GetTexture(0)->GetDpiX()) * 12);
00044         SetScaleY((m->GetTexture(0)->GetHeight() / m->GetTexture(0)->GetDpiY()) * 12);
00045     }
00046 
00047     return true;
00048 }
00049 
00050 void MercuryShape::MakeSphere( int Stacks, int Slices )
00051 {
00052     int x,y;
00053     CleanupMeshes();
00054 
00055     MercuryMesh* m = new MercuryMesh;
00056     if( !MESHMAN.RegMesh( m, ssprintf( "BASE:Sphere%d,%d", Stacks, Slices ), true ) )
00057     {
00058         m->SetDrawType(MGL_TRIANGLE);
00059 
00060         //stacks*slices*2 = number of polys
00061         //3 verts per poly
00062         m->SetNumVertices( (Stacks+1)*(Slices+1) );
00063 
00064         float dY = 6.2831853072f / float(Stacks)/2;
00065         float dX = 6.2831853072f / float(Slices);
00066 
00067         for ( y = 0; y < Stacks+1; y++ )
00068             for ( x = 0; x < Slices+1; x++ )
00069             {
00070                 int p = (x)+(y*Slices);
00071                 MercuryVertex& v = (*m)[p];
00072                 v.x = COS( dX * x ) * SIN( dY * y );
00073                 v.y = SIN( dX * x ) * SIN( dY * y );
00074                 v.z = COS( dY * y );
00075                 v.SetV( float( y ) / Stacks );
00076                 v.SetU( float( x ) / Slices );
00077             }
00078 
00079         m->SetNumIndices(Stacks*Slices*3*2);
00080         unsigned int kjg = 0;
00081         for ( y = 0; y < Stacks; y++ )
00082             for ( x = 0; x < Slices; x++ )
00083             {
00084                 int p = (x)+(y*Slices);
00085                 m->SetIndice(kjg++, p+1);
00086                 m->SetIndice(kjg++, p);
00087                 m->SetIndice(kjg++, p+Slices);
00088 
00089                 m->SetIndice(kjg++, p+Slices);
00090                 m->SetIndice(kjg++, p+Slices+1);
00091                 m->SetIndice(kjg++, p+1);
00092 
00093             }
00094         m->CalculateVertexNormals();
00095         m->ToggleUseVBOs(true);
00096         m->BuildVBO();
00097 
00098     }
00099     m->SetMaterial( m_materials[0] );
00100     AddMesh(m);
00101     m_hidden = false;
00102     m_fVisRadius = 1;
00103 }
00104 
00105 void MercuryShape::MakeSprite( int Rows, int Cols )
00106 {
00107     CleanupMeshes();
00108     MercuryMesh* m = new MercuryMesh;
00109     if( !MESHMAN.RegMesh( m, ssprintf("BASE:Sprite%dx%d", Rows, Cols ), true ) )
00110     {
00111         m->SetDrawType(MGL_TRIANGLE);
00112         m->SetNumIndices( Rows * Cols * 6 );
00113         unsigned int * i = m->GetIndicesPtr();
00114         unsigned l;
00115 
00116         for( l = 0; l < Rows*Cols; l++ )
00117         {
00118             int c1 = l + l/Cols;
00119             int c2 = l + l/Cols+1;
00120             int c3 = c1 + Cols+1;
00121             int c4 = c2 + Cols+1;
00122             i[l*6+0] = c2;
00123             i[l*6+1] = c1;
00124             i[l*6+2] = c3;
00125             i[l*6+3] = c2;
00126             i[l*6+4] = c3;
00127             i[l*6+5] = c4;
00128                             
00129             /*i[l*6+0] = 1+l*6;
00130             i[l*6+1] = 0+l*6;
00131             i[l*6+2] = 2+l*6;
00132             i[l*6+3] = 1+l*6;
00133             i[l*6+4] = 2+l*6;
00134             i[l*6+5] = 3+l*6;*/
00135 
00136         }
00137 
00138         m->SetNumVertices(4 * Rows * Cols);
00139 
00140         l=0;
00141         for( unsigned r = 0; r<=Rows; r++ )
00142         {
00143             for( unsigned c = 0; c<=Cols; c++ )
00144             {
00145                 float rc = (float)r, rt = (float)Rows;
00146                 float cc = (float)c, ct = (float)Cols;
00147 
00148                 (*m)[l].x = rc/rt-0.5f;
00149                 (*m)[l].y = cc/ct-0.5f;
00150                 (*m)[l].z = 0;
00151                 (*m)[l].SetU( rc/rt );
00152                 (*m)[l].SetV( cc/ct );
00153                 ++l;
00154             }
00155         }
00156     }
00157     
00158     m->ToggleUseVBOs(true);
00159 
00160     AddMesh(m);
00161     m_hidden = false;
00162     m->SetMaterial( m_materials[0] );
00163 
00164     m->CalculateVertexNormals();
00165     m->BuildVBO();
00166 
00167     m_fVisRadius = 1;
00168 }
00169 
00170 void MercuryShape::MakeCylinder( int Stacks, int Slices )
00171 {
00172     int y,x;
00173     CleanupMeshes();
00174     MercuryMesh* m = new MercuryMesh;
00175     if( !MESHMAN.RegMesh( m, ssprintf( "BASE:Cylinder%d,%d", Stacks, Slices ), true ) )
00176     {
00177         int p;
00178         float dX = 6.2831853072f / float(Slices);
00179 
00180         m->SetDrawType(MGL_TRIANGLE);
00181         m->SetNumVertices( (Stacks+3)*(Slices+1) );
00182 
00183 
00184         for ( y = 0; y < Stacks+3; y++ )
00185             for ( x = 0; x < Slices+1; x++ )
00186             {
00187                 p = (x)+(y*Slices);
00188 
00189                 MercuryVertex& v = (*m)[p];
00190 
00191                 if ( y == Stacks + 1 || y == Stacks + 2 )       //We're at a pole
00192                 {
00193                     v.x = 0;
00194                     v.y = 0; 
00195                 } else {
00196                     v.x = COS( dX * x );
00197                     v.y = SIN( dX * x );
00198                 }
00199                 if ( y == Stacks + 2 )  //North Pole
00200                 {
00201                     v.SetV( 0 );
00202                     v.z = - 0.5f;
00203                 } else if ( y == Stacks + 1 ) //South Pole
00204                 {
00205                     v.SetV( 1 );
00206                     v.z = 0.5f;
00207                 } else 
00208                 {
00209                     v.SetV( float( y ) / Stacks/3+0.333333f );
00210                     v.z = ( float( y ) / Stacks ) - 0.5f;
00211                 }
00212                 v.SetU( float( x ) / Slices );
00213             }
00214         m->CalculateVertexNormals();
00215         m->ToggleUseVBOs(true);
00216         m->BuildVBO();
00217 
00218     }
00219     
00220     m->SetMaterial( m_materials[0] );
00221     AddMesh(m);
00222     m_hidden = false;
00223     m_fVisRadius = 1;
00224 }
00225 
00226 void MercuryShape::MakeBox( bool bWholeMap )
00227 {
00228     int i;
00229     CleanupMeshes();
00230 
00231     MercuryMesh* m = new MercuryMesh;
00232     if( !MESHMAN.RegMesh( m, "BASE:Box", true ) )
00233     {
00234         m->SetDrawType(MGL_TRIANGLE);
00235         m->SetNumIndices( 36 );
00236         m->SetNumVertices( 24 );
00237 
00238         for( i = 0; i < 6; i++ )
00239         {
00240             //order: 0 1 2    2 1 3 
00241             
00242             m->SetIndice( i*6 + 0, 0 + 4*i );
00243             m->SetIndice( i*6 + 1, 1 + 4*i );
00244             m->SetIndice( i*6 + 2, 2 + 4*i );
00245             m->SetIndice( i*6 + 3, 2 + 4*i );
00246             m->SetIndice( i*6 + 4, 1 + 4*i );
00247             m->SetIndice( i*6 + 5, 3 + 4*i );
00248         }
00249         MercuryPoint CoreF[8];
00250         static int CoreI[36] = {    1,0,3,2,
00251                                     0,1,4,5,
00252                                     3,2,7,6,
00253                                     2,0,6,4,
00254                                     4,5,6,7,
00255                                     1,3,5,7 };
00256 
00257         for( i = 0; i < 8; i++ )
00258             CoreF[i] = MercuryPoint( (i%2)-.5f,((i/2)%2)-.5f,((i/4)%2)-.5f );
00259 
00260         //Now that we have the cores set up, we can generate general verticies
00261         for( i = 0; i < 24; i++ )
00262         {
00263             m->GetVerticePtr()[i].GetPointHandle() = CoreF[CoreI[i]];
00264             m->GetVerticePtr()[i].SetU( float((i)%2) );
00265             m->GetVerticePtr()[i].SetV( float((i/2)%2) );
00266         }
00267         m->ToggleUseVBOs(true);
00268     }
00269     m->SetMaterial( m_materials[0] );
00270     AddMesh(m);
00271     m->CalculateVertexNormals();
00272             m->BuildVBO();
00273 
00274     m_hidden = false;
00275     m_fVisRadius = 1.1f;
00276 }
00277 
00278 bool MercuryShape::SetFromINI( MercuryINI & InINI, const MString & section )
00279 {
00280     MString Texture = InINI.GetValueS( section, "Texture", "" );
00281     LoadImage( Texture );
00282 
00283     int ShapeType = InINI.GetValueI( section, "Type", 0 );
00284     switch ( ShapeType )
00285     {
00286     case 0:
00287         MakeBox( true );
00288         break;
00289     case 1:
00290         MakeCylinder(   InINI.GetValueI( section, "Stacks", 6 ),
00291                         InINI.GetValueI( section, "Slices", 12 ) );
00292         break;
00293     case 2:
00294         MakeSphere(     InINI.GetValueI( section, "Stacks", 6 ),
00295                         InINI.GetValueI( section, "Slices", 12 ) );
00296         break;
00297     case 3:
00298         MakeSprite( );
00299         break;
00300     default:
00301         LOG.Warn( ssprintf("Could not find shape type '%s'.", section.c_str() ) );
00302     }
00303 
00304     SetScaleX( InINI.GetValueF( section, "ScaleX", 1 ) );
00305     SetScaleY( InINI.GetValueF( section, "ScaleY", 1 ) );
00306     SetScaleZ( InINI.GetValueF( section, "ScaleZ", 1 ) );
00307 
00308     SetRotX( InINI.GetValueF( section, "RotationX", 0 ) );
00309     SetRotY( InINI.GetValueF( section, "RotationY", 0 ) );
00310     SetRotZ( InINI.GetValueF( section, "RotationZ", 0 ) );
00311 
00312     SetPosition( MercuryPoint( 
00313         InINI.GetValueF( section, "PositionX", 0 ),
00314         InINI.GetValueF( section, "PositionY", 0 ),
00315         InINI.GetValueF( section, "PositionZ", 0 ) ) );
00316 
00317     return true;
00318 }
00319 
00320 bool MercuryShape::Command( PStack & ret, const char * command, PStack & args )
00321 {
00322     if ( strcmp( command, "LoadImage" ) == 0 )
00323     {
00324         MString Parameter = args.PopItem().GetValueS();
00325         while( args.GetSize() )
00326             Parameter = args.PopItem().GetValueS() + "," + Parameter;
00327         LoadImage( Parameter );
00328         return true;
00329     }
00330 
00331     if ( strcmp( command, "SetShape" ) == 0 )
00332     {
00333         PSElement type = args.PopItem();
00334         if ( type.GetValueS() == "Sphere" )
00335         {
00336             long Stacks, Slices;
00337             if ( !args.PopItem().GetValueI( Stacks ) )
00338                 Stacks = 6;
00339             if ( !args.PopItem().GetValueI( Slices ) )
00340                 Slices = 12;
00341             MakeSphere( Stacks, Slices );
00342             return true;
00343         }
00344         else if ( type.GetValueS() == "Cylinder" )
00345         {
00346             long Stacks, Slices;
00347             if ( !args.PopItem().GetValueI( Stacks ) )
00348                 Stacks = 6;
00349             if ( !args.PopItem().GetValueI( Slices ) )
00350                 Slices = 12;
00351             MakeCylinder( Stacks, Slices );
00352             return true;
00353         } else if ( type.GetValueS() == "Box" )
00354         {
00355             MakeBox();
00356             return true;
00357         } else if ( type.GetValueS() == "Sprite" )
00358         {
00359             MakeSprite();
00360             return true;
00361         }
00362         return false;
00363     }
00364     return MercuryObject::Command( ret, command, args );
00365 }
00366 
00367 void MercuryShape::EnumerateCommands( MVector< MString > & toAdd )
00368 {
00369     toAdd.push_back( "SetShape" );
00370     toAdd.push_back( "LoadImage" );
00371     MercuryObject::EnumerateCommands( toAdd );
00372 }
00373 
00374 void MercuryShape::CleanupMeshes()
00375 {
00376     for ( int i = 0; (unsigned)i < m_meshes.size(); i++ )
00377     {
00378         RemoveObject(m_meshes[i]);
00379         SAFE_DELETE(m_meshes[i]);
00380     }
00381 }
00382 
00383 REGISTER_OBJECT_TYPE( MercuryShape );
00384 
00385 /* 
00386  * Copyright (c) 2005-2006, Charles Lohr
00387  * All rights reserved.
00388  *
00389  * Redistribution and use in source and binary forms, with or
00390  * without modification, are permitted provided that the following
00391  * conditions are met:
00392  *  -   Redistributions of source code must retain the above
00393  *      copyright notice, this list of conditions and the following disclaimer.
00394  *  -   Redistributions in binary form must reproduce the above copyright
00395  *      notice, this list of conditions and the following disclaimer in
00396  *      the documentation and/or other materials provided with the distribution.
00397  *  -   Neither the name of the Mercury Engine nor the names of its
00398  *      contributors may be used to endorse or promote products derived from
00399  *      this software without specific prior written permission.
00400  *
00401  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00402  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00403  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00404  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00405  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00406  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00407  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00408  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00409  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00410  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00411  */

Hosted by SourceForge.net Logo