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
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
00061
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
00130
00131
00132
00133
00134
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 )
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 )
00200 {
00201 v.SetV( 0 );
00202 v.z = - 0.5f;
00203 } else if ( y == Stacks + 1 )
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
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
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
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411