Torque3D Documentation / _generateds / convexShape.cpp

convexShape.cpp

Engine/source/T3D/convexShape.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(ConvexShape , "@brief A renderable, collidable convex shape defined by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> collection of surface <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">planes.\n\n</a>" "%<a href="/coding/class/classconvexshape/">ConvexShape</a> is intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> temporary asset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> quickly " "blocking out <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene or filling in approximate shapes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be later replaced " "with final assets. This is most easily done by using the <a href="/coding/class/classworldeditor/">WorldEditor</a> 's " "Sketch <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Tool.\n\n</a>" " @ingroup enviroMisc" )

Detailed Description

Public Variables

const U32 sgConvexFaceColorCount 
const ColorI sgConvexFaceColors [sgConvexFaceColorCount]

Public Functions

ConsoleDocClass(ConvexShape , "@brief A renderable, collidable convex shape defined by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> collection of surface <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">planes.\n\n</a>" "%<a href="/coding/class/classconvexshape/">ConvexShape</a> is intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> temporary asset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> quickly " "blocking out <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene or filling in approximate shapes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be later replaced " "with final assets. This is most easily done by using the <a href="/coding/class/classworldeditor/">WorldEditor</a> 's " "Sketch <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Tool.\n\n</a>" " @ingroup enviroMisc" )

GFXImplementVertexFormat(ConvexVert )

IMPLEMENT_CO_NETOBJECT_V1(ConvexShape )

sortDescendingU32(const void * a, const void * b)

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "platform/platform.h"
  25#include "T3D/convexShape.h"
  26
  27#include "math/mathIO.h"
  28#include "math/mathUtils.h"
  29#include "scene/sceneRenderState.h"
  30#include "console/consoleTypes.h"
  31#include "core/stream/bitStream.h"
  32#include "materials/materialManager.h"
  33#include "lighting/lightQuery.h"
  34#include "renderInstance/renderPassManager.h"
  35#include "gfx/gfxTransformSaver.h"
  36#include "gfx/primBuilder.h"
  37#include "gfx/gfxDrawUtil.h"
  38#include "core/bitVector.h"
  39#include "materials/materialFeatureTypes.h"
  40#include "materials/baseMatInstance.h"
  41#include "collision/optimizedPolyList.h"
  42#include "T3D/physics/physicsPlugin.h"
  43#include "T3D/physics/physicsBody.h"
  44#include "T3D/physics/physicsCollision.h"
  45#include "console/engineAPI.h"
  46#include "core/strings/stringUnit.h"
  47
  48IMPLEMENT_CO_NETOBJECT_V1( ConvexShape );
  49
  50ConsoleDocClass( ConvexShape,
  51   "@brief A renderable, collidable convex shape defined by a collection of surface planes.\n\n"
  52   
  53   "%ConvexShape is intended to be used as a temporary asset for quickly "
  54   "blocking out a scene or filling in approximate shapes to be later replaced "
  55   "with final assets. This is most easily done by using the WorldEditor's "
  56   "Sketch Tool.\n\n"
  57   
  58   "@ingroup enviroMisc"   
  59);
  60
  61
  62Point3F ConvexShapeCollisionConvex::support( const VectorF &vec ) const
  63{
  64   const Vector< Point3F> &pointList = pShape->mGeometry.points;
  65
  66   if ( pointList.empty() )
  67      return pShape->getObjBox().getCenter();
  68   
  69   // This doesn't deal with the case that the farthest plane along vec is also
  70   // perpendicular to it, but in that case maybe it doesn't matter which point we return
  71   // anyway.
  72
  73   F32 bestDot = mDot( pointList[0], vec );
  74
  75   const Point3F *bestP = &pointList[0];
  76
  77   for ( S32 i = 1; i < pointList.size(); i++ )
  78   {
  79      F32 newD = mDot( pointList[i], vec );
  80
  81      if ( newD > bestDot )
  82      {
  83         bestDot = newD;
  84         bestP = &pointList[i];
  85      }
  86   }
  87
  88   return *bestP;
  89}
  90
  91void ConvexShapeCollisionConvex::getFeatures( const MatrixF &mat, const VectorF &n, ConvexFeature *cf )
  92{
  93   if ( pShape->mGeometry.points.empty() )
  94   {
  95      cf->material = 0;
  96      cf->mObject = NULL;
  97      return;
  98   }
  99
 100   cf->material = 0;
 101   cf->mObject = mObject;
 102
 103   // Simple implementation... Add all Points, Edges and Faces.
 104
 105
 106   // Points...
 107
 108   S32 firstVert = cf->mVertexList.size();
 109   
 110   const Vector< Point3F> &pointList = pShape->mGeometry.points;
 111   const U32 pointListCount = pointList.size();
 112
 113   cf->mVertexList.increment( pointListCount );
 114
 115   for ( S32 i = 0; i < pointListCount; i++ )   
 116      mat.mulP( pointList[i], &(cf->mVertexList[ firstVert + i ]) ); 
 117   
 118
 119   // Edges and Triangles for each face...
 120
 121   const Vector< ConvexShape::Face> &faceList = pShape->mGeometry.faces;
 122
 123   for ( S32 i = 0; i < faceList.size(); i++ )
 124   {
 125      // Add this Face's Edges.
 126
 127      const Vector< ConvexShape::Edge> &edgeList = faceList[i].edges;     
 128      const U32 edgeCount = edgeList.size();
 129      const S32 firstEdge = cf->mEdgeList.size();
 130
 131      cf->mEdgeList.increment( edgeCount );
 132
 133      for ( S32 j = 0; j < edgeCount; j++ )
 134      {
 135         cf->mEdgeList[ firstEdge + j ].vertex[0] = faceList[i].points[ edgeList[j].p0 ];
 136         cf->mEdgeList[ firstEdge + j ].vertex[1] = faceList[i].points[ edgeList[j].p1 ];
 137      }
 138
 139      // Add this face's Triangles. 
 140
 141      // Note that ConvexFeature calls triangles 'faces' but a ConvexShape 'Face' is not
 142      // necessarily a single triangle.
 143            
 144      const Vector< ConvexShape::Triangle> &triangleList = faceList[i].triangles;
 145      const U32 triangleCount = triangleList.size();
 146      S32 firstTriangle = cf->mFaceList.size();
 147
 148      cf->mFaceList.increment( triangleCount );
 149
 150      for ( S32 j = 0; j < triangleCount; j++ )
 151      {        
 152         ConvexFeature::Face &cft = cf->mFaceList[ firstTriangle + j ];
 153
 154         cft.normal = faceList[i].normal;
 155         cft.vertex[0] = triangleList[j].p0;
 156         cft.vertex[1] = triangleList[j].p1;
 157         cft.vertex[2] = triangleList[j].p2;
 158      }
 159   }  
 160}
 161
 162
 163void ConvexShapeCollisionConvex::getPolyList( AbstractPolyList* list )
 164{
 165   SphereF sphere( Point3F::Zero, 0.0f );
 166   
 167   pShape->buildPolyList( PLC_Collision, list, Box3F::Invalid, sphere );   
 168}
 169
 170
 171GFXImplementVertexFormat( ConvexVert )
 172{
 173   addElement( "POSITION", GFXDeclType_Float3 );
 174   addElement( "COLOR", GFXDeclType_Color );
 175   addElement( "NORMAL", GFXDeclType_Float3 );
 176   addElement( "TANGENT", GFXDeclType_Float3 );
 177   addElement( "TEXCOORD", GFXDeclType_Float2, 0 );
 178};
 179
 180static const U32 sgConvexFaceColorCount = 16;
 181static const ColorI sgConvexFaceColors[ sgConvexFaceColorCount ] = 
 182{
 183   ColorI( 239, 131, 201 ),
 184   ColorI( 124, 255, 69 ),
 185   ColorI( 255, 65, 77 ),
 186   ColorI( 33, 118, 235 ),
 187   ColorI( 114, 227, 110 ),
 188   ColorI( 197, 50, 237 ),
 189   ColorI( 236, 255, 255 ),
 190   ColorI( 139, 225, 192 ),
 191   ColorI( 215, 9, 65 ),
 192   ColorI( 249, 114, 93 ),
 193   ColorI( 255, 255, 90 ),
 194   ColorI( 93, 104, 97 ),
 195   ColorI( 255, 214, 192 ),
 196   ColorI( 122, 44, 198 ),
 197   ColorI( 137, 141, 194 ),
 198   ColorI( 164, 114, 43 )
 199};
 200
 201bool ConvexShape::smRenderEdges = false;
 202
 203bool ConvexShape::protectedSetSurface( void *object, const char *index, const char *data )
 204{
 205   ConvexShape *shape = static_cast< ConvexShape* >( object );
 206
 207   QuatF quat;
 208   Point3F pos;
 209   //MatrixF mat;
 210
 211   U32 matID;
 212   Point2F offset;
 213   Point2F scale;
 214   F32 rot = 0;
 215   bool horz = true, vert = true;
 216
 217   /*
 218   dSscanf( data, "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
 219      &mat[0], &mat[1], &mat[2], &mat[3], 
 220      &mat[4], &mat[5], &mat[6], &mat[7], 
 221      &mat[8], &mat[9], &mat[10], &mat[11],
 222      &mat[12], &mat[13], &mat[14], &mat[15] );
 223   */
 224
 225   String t = data;
 226   S32 len = t.length();
 227
 228   dSscanf( data, "%g %g %g %g %g %g %g %i %g %g %g %g %f", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z,
 229      &matID, &offset.x, &offset.y, &scale.x, &scale.y, &rot);
 230
 231   MatrixF surface;
 232   quat.setMatrix( &surface );
 233   surface.setPosition( pos );
 234
 235   shape->mSurfaces.push_back( surface );  
 236
 237   surfaceUV surfUV;
 238   if (StringUnit::getUnitCount(data, " ") > 7)
 239   {
 240      surfUV.matID = matID;
 241      surfUV.offset = offset;
 242      surfUV.scale = scale;
 243      surfUV.zRot = rot;
 244      surfUV.horzFlip = horz;
 245      surfUV.vertFlip = vert;
 246   }
 247   else
 248   {
 249      surfUV.matID = 0;
 250      surfUV.offset = Point2F(0,0);
 251      surfUV.scale = Point2F(1, 1);
 252      surfUV.zRot = 0;
 253      surfUV.horzFlip = false;
 254      surfUV.vertFlip = false;
 255   }
 256
 257   shape->mSurfaceUVs.push_back(surfUV);
 258
 259   return false;
 260}
 261
 262bool ConvexShape::protectedSetSurfaceTexture(void *object, const char *index, const char *data)
 263{
 264   ConvexShape *shape = static_cast< ConvexShape* >(object);
 265
 266   surfaceMaterial surface;
 267
 268   surface.materialName = data;
 269
 270   shape->mSurfaceTextures.push_back(surface);
 271
 272   return false;
 273}
 274
 275ConvexShape::ConvexShape()
 276 : mMaterialName( "Grid512_OrangeLines_Mat" ),
 277   mMaterialInst( NULL ),
 278   //mVertCount( 0 ),
 279   //mPrimCount( 0 ),
 280   mPhysicsRep( NULL ),
 281   mNormalLength( 0.3f )
 282{   
 283   mNetFlags.set( Ghostable | ScopeAlways );
 284   
 285   mTypeMask |= StaticObjectType | 
 286                StaticShapeObjectType;    
 287
 288   mConvexList = new Convex;
 289
 290   mSurfaceBuffers.clear();
 291   mSurfaceUVs.clear();
 292   mSurfaceTextures.clear();
 293}
 294
 295ConvexShape::~ConvexShape()
 296{
 297   if ( mMaterialInst )
 298      SAFE_DELETE( mMaterialInst );
 299
 300   for(U32 i=0; i<mSurfaceTextures.size(); i++)
 301   {
 302      if (mSurfaceTextures[i].materialInst)
 303         SAFE_DELETE(mSurfaceTextures[i].materialInst);
 304   }
 305
 306   delete mConvexList;
 307   mConvexList = NULL;
 308}
 309
 310void ConvexShape::initPersistFields()
 311{
 312   addGroup( "Rendering" );
 313
 314      addField( "material", TypeMaterialName, Offset( mMaterialName, ConvexShape ), "Material used to render the ConvexShape surface." );
 315
 316   endGroup( "Rendering" );
 317
 318   addGroup( "Internal" );
 319
 320      addProtectedField( "surface", TypeRealString, NULL, &protectedSetSurface, &defaultProtectedGetFn, 
 321         "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
 322
 323     addProtectedField( "surfaceTexture", TypeRealString, NULL, &protectedSetSurfaceTexture, &defaultProtectedGetFn, 
 324         "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
 325
 326   endGroup( "Internal" );
 327
 328   Parent::initPersistFields();
 329}
 330
 331void ConvexShape::inspectPostApply()
 332{
 333   Parent::inspectPostApply();
 334
 335   _updateGeometry( true );
 336
 337   setMaskBits( UpdateMask );
 338}
 339
 340bool ConvexShape::onAdd()
 341{
 342   if ( !Parent::onAdd() )
 343      return false;
 344   
 345   //mObjBox.set( -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f );
 346   //resetWorldBox();   
 347
 348   // Face Order:
 349   // Top, Bottom, Front, Back, Left, Right
 350
 351   // X Axis
 352   static const Point3F cubeTangents[6] =
 353   {
 354      Point3F( 1,  0,  0 ),
 355      Point3F(-1,  0,  0 ),
 356      Point3F( 1,  0,  0 ),
 357      Point3F(-1,  0,  0 ),
 358      Point3F( 0,  1,  0 ),
 359      Point3F( 0, -1,  0 )      
 360   };
 361
 362   // Y Axis
 363   static const Point3F cubeBinormals[6] =
 364   {
 365      Point3F( 0,  1,  0 ),
 366      Point3F( 0,  1,  0 ),
 367      Point3F( 0,  0, -1 ),
 368      Point3F( 0,  0, -1 ),
 369      Point3F( 0,  0, -1 ),
 370      Point3F( 0,  0, -1 )
 371   };
 372
 373   // Z Axis
 374   static const Point3F cubeNormals[6] = 
 375   {
 376      Point3F( 0,  0,  1),
 377      Point3F( 0,  0, -1),
 378      Point3F( 0,  1,  0),
 379      Point3F( 0, -1,  0),
 380      Point3F(-1,  0,  0),
 381      Point3F( 1,  0,  0),      
 382   };
 383
 384   if ( mSurfaces.empty() )
 385   {      
 386      for ( S32 i = 0; i < 6; i++ )
 387      {
 388         mSurfaces.increment();
 389         MatrixF &surf = mSurfaces.last();
 390
 391         surf.identity();
 392         
 393         surf.setColumn( 0, cubeTangents[i] );
 394         surf.setColumn( 1, cubeBinormals[i] );
 395         surf.setColumn( 2, cubeNormals[i] );
 396         surf.setPosition( cubeNormals[i] * 0.5f );   
 397
 398         mSurfaceUVs.increment();
 399         mSurfaceUVs[i].offset = Point2F(0, 0);
 400         mSurfaceUVs[i].scale = Point2F(1, 1);
 401         mSurfaceUVs[i].zRot = 0;
 402         mSurfaceUVs[i].horzFlip = false;
 403         mSurfaceUVs[i].vertFlip = false;
 404         mSurfaceUVs[i].matID = 0;
 405      }
 406   }
 407
 408   if ( isClientObject() )   
 409      _updateMaterial();      
 410   
 411   _updateGeometry( true );
 412
 413   addToScene();
 414
 415   PlaneF p = PlaneF(Point3F(0, 0, 0), Point3F(0, 0, 1));
 416
 417   Point3F a = Point3F(0, 0, 1);
 418   Point3F b = Point3F(1, 0, -1);
 419   Point3F c = Point3F(-1, 0, -1);
 420
 421   Vector<Point3F> points;
 422   points.push_back(a);
 423   points.push_back(b);
 424   points.push_back(c);
 425
 426   Point3F vertices[64];
 427   p.clipPolygon(points.address(), points.size(), vertices);
 428
 429   return true;
 430}
 431
 432void ConvexShape::onRemove()
 433{
 434   removeFromScene();
 435
 436   mConvexList->nukeList();
 437
 438   SAFE_DELETE( mPhysicsRep );
 439
 440   Parent::onRemove();
 441}
 442
 443void ConvexShape::writeFields( Stream &stream, U32 tabStop )
 444{
 445   Parent::writeFields( stream, tabStop );
 446
 447   // Now write all planes.
 448
 449   stream.write(2, "\r\n");   
 450
 451   S32 count = mSurfaces.size();
 452   if ( count > smMaxSurfaces )
 453   {
 454       Con::errorf( "ConvexShape has too many surfaces to save! Truncated value %d to maximum value of %d", count, smMaxSurfaces );
 455       count = smMaxSurfaces;
 456   }
 457
 458   for (U32 i = 0; i < mSurfaceTextures.size(); i++)
 459   {
 460      stream.writeTabs(tabStop);
 461
 462      char buffer[1024];
 463      dMemset(buffer, 0, 1024);
 464
 465      const char* tex = mSurfaceTextures[i].materialName.c_str();
 466
 467      dSprintf(buffer, 1024, "surfaceTexture = \"%s\";", mSurfaceTextures[i].materialName.c_str());
 468
 469      stream.writeLine((const U8*)buffer);
 470   }
 471
 472   for ( U32 i = 0; i < count; i++ )
 473   {      
 474      const MatrixF &mat = mSurfaces[i];
 475
 476      QuatF quat( mat );
 477      Point3F pos( mat.getPosition() );
 478
 479      stream.writeTabs(tabStop);
 480
 481      char buffer[1024];
 482      dMemset( buffer, 0, 1024 );      
 483      
 484      dSprintf( buffer, 1024, "surface = \"%g %g %g %g %g %g %g %i %g %g %g %g %g %i %i\";", 
 485         quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z, mSurfaceUVs[i].matID,
 486         mSurfaceUVs[i].offset.x, mSurfaceUVs[i].offset.y, mSurfaceUVs[i].scale.x, 
 487         mSurfaceUVs[i].scale.y, mSurfaceUVs[i].zRot, mSurfaceUVs[i].horzFlip, mSurfaceUVs[i].vertFlip);
 488
 489      stream.writeLine( (const U8*)buffer );
 490   }
 491}
 492
 493bool ConvexShape::writeField( StringTableEntry fieldname, const char *value )
 494{   
 495   if ( fieldname == StringTable->insert("surface") )
 496      return false;
 497
 498   if ( fieldname == StringTable->insert("surfaceTexture") )
 499      return false;
 500
 501   return Parent::writeField( fieldname, value );
 502}
 503
 504void ConvexShape::onScaleChanged()
 505{
 506   if ( isProperlyAdded() )
 507      _updateCollision();
 508}
 509
 510void ConvexShape::setTransform( const MatrixF &mat )
 511{   
 512   Parent::setTransform( mat );
 513
 514   if ( mPhysicsRep )
 515      mPhysicsRep->setTransform( mat );
 516 
 517   setMaskBits( TransformMask );
 518}
 519
 520U32 ConvexShape::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
 521{
 522   U32 retMask = Parent::packUpdate( conn, mask, stream );
 523   
 524   if ( stream->writeFlag( mask & TransformMask ) )
 525   {
 526      mathWrite(*stream, getTransform());
 527      mathWrite(*stream, getScale());
 528   }
 529
 530   if ( stream->writeFlag( mask & UpdateMask ) )
 531   {
 532      stream->write( mMaterialName );
 533      
 534      U32 surfCount = mSurfaces.size();
 535      stream->writeInt( surfCount, 32 );
 536
 537      for ( S32 i = 0; i < surfCount; i++ )    
 538      {
 539         QuatF quat( mSurfaces[i] );
 540       Point3F pos( mSurfaces[i].getPosition() );
 541
 542         mathWrite( *stream, quat );
 543         mathWrite( *stream, pos );   
 544
 545         mathWrite(*stream, mSurfaceUVs[i].offset);
 546         mathWrite(*stream, mSurfaceUVs[i].scale);
 547
 548         stream->writeFlag(mSurfaceUVs[i].horzFlip);
 549         stream->writeFlag(mSurfaceUVs[i].vertFlip);
 550
 551         stream->writeInt(mSurfaceUVs[i].matID, 16);
 552      }
 553
 554     const U32 surfaceTex = mSurfaceTextures.size();
 555
 556     stream->writeInt( surfaceTex, 32 );
 557     //next check for any texture coord or scale mods
 558     for(U32 i=0; i < surfaceTex; i++)
 559     {
 560        String a = mSurfaceTextures[i].materialName;
 561         stream->write( mSurfaceTextures[i].materialName );
 562     }
 563   }
 564
 565   return retMask;
 566}
 567
 568void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream )
 569{
 570   Parent::unpackUpdate( conn, stream );
 571
 572   if ( stream->readFlag() )  // TransformMask
 573   {
 574      mathRead(*stream, &mObjToWorld);
 575      mathRead(*stream, &mObjScale);
 576
 577      setTransform( mObjToWorld );
 578      setScale( mObjScale );
 579   }
 580
 581   if ( stream->readFlag() ) // UpdateMask
 582   {
 583      stream->read( &mMaterialName );      
 584
 585      mSurfaces.clear();
 586      mSurfaceUVs.clear();
 587
 588      const U32 surfCount = stream->readInt( 32 );
 589      for ( S32 i = 0; i < surfCount; i++ )
 590      {
 591         mSurfaces.increment();
 592         MatrixF &mat = mSurfaces.last();
 593
 594         QuatF quat;
 595         Point3F pos;
 596
 597         mathRead( *stream, &quat );
 598         mathRead( *stream, &pos ); 
 599
 600         quat.setMatrix( &mat );
 601         mat.setPosition( pos );
 602
 603         mSurfaceUVs.increment();
 604
 605         mathRead(*stream, &mSurfaceUVs[i].offset);
 606         mathRead(*stream, &mSurfaceUVs[i].scale);
 607
 608         mSurfaceUVs[i].horzFlip = stream->readFlag();
 609         mSurfaceUVs[i].vertFlip = stream->readFlag();
 610
 611         mSurfaceUVs[i].matID = stream->readInt(16);
 612      }
 613
 614     //now fetch our text coord mods to store into the geometry data
 615      mSurfaceTextures.clear();
 616     const U32 surfaceTex = stream->readInt( 32 );
 617
 618     //next check for any texture coord or scale mods
 619     for(U32 i=0; i < surfaceTex; i++)
 620     {
 621        mSurfaceTextures.increment();
 622
 623        stream->read( &mSurfaceTextures[i].materialName );
 624     }
 625
 626     if (isProperlyAdded())
 627        _updateMaterial();
 628
 629      if ( isProperlyAdded() )
 630         _updateGeometry( true );
 631   }
 632}
 633
 634void ConvexShape::prepRenderImage( SceneRenderState *state )
 635{   
 636   /*
 637   if ( state->isDiffusePass() )
 638   {
 639      ObjectRenderInst *ri2 = state->getRenderPass()->allocInst<ObjectRenderInst>();
 640      ri2->renderDelegate.bind( this, &ConvexShape::_renderDebug );
 641      ri2->type = RenderPassManager::RIT_Editor;
 642      state->getRenderPass()->addInst( ri2 );
 643   }
 644   */
 645
 646   for (U32 i = 0; i < mSurfaceBuffers.size(); i++)
 647   {
 648      if (mSurfaceBuffers[i].mPrimitiveBuffer.isNull())
 649         continue;
 650
 651      // If we don't have a material instance after the override then 
 652      // we can skip rendering all together.
 653      BaseMatInstance *matInst;
 654      if (i == 0)
 655      {
 656         matInst = state->getOverrideMaterial(mMaterialInst ? mMaterialInst : MATMGR->getWarningMatInstance());
 657      }
 658      else
 659      {
 660         matInst = state->getOverrideMaterial(mSurfaceTextures[i - 1].materialInst ? mSurfaceTextures[i - 1].materialInst : MATMGR->getWarningMatInstance());
 661      }
 662
 663      if (!matInst)
 664         continue;
 665
 666      // Get a handy pointer to our RenderPassmanager
 667      RenderPassManager *renderPass = state->getRenderPass();
 668
 669      // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager
 670      MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
 671
 672      // Set our RenderInst as a standard mesh render
 673      ri->type = RenderPassManager::RIT_Mesh;
 674
 675      // Calculate our sorting point
 676      if (state)
 677      {
 678         // Calculate our sort point manually.
 679         const Box3F& rBox = getRenderWorldBox();
 680         ri->sortDistSq = rBox.getSqDistanceToPoint(state->getCameraPosition());
 681      }
 682      else
 683         ri->sortDistSq = 0.0f;
 684
 685      // Set up our transforms
 686      MatrixF objectToWorld = getRenderTransform();
 687      objectToWorld.scale(getScale());
 688
 689      ri->objectToWorld = renderPass->allocUniqueXform(objectToWorld);
 690      ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
 691      ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection);
 692
 693      // If we need lights then set them up.
 694      if (matInst->isForwardLit())
 695      {
 696         LightQuery query;
 697         query.init(getWorldSphere());
 698         query.getLights(ri->lights, 8);
 699      }
 700
 701      // Make sure we have an up-to-date backbuffer in case
 702      // our Material would like to make use of it
 703      // NOTICE: SFXBB is removed and refraction is disabled!
 704      //ri->backBuffTex = GFX->getSfxBackBuffer();
 705
 706      // Set our Material
 707      ri->matInst = matInst;
 708      if (matInst->getMaterial()->isTranslucent() && (!(matInst->getMaterial()->isAlphatest() && state->isShadowPass())))
 709      {
 710         ri->translucentSort = true;
 711         ri->type = RenderPassManager::RIT_Translucent;
 712      }
 713
 714      // Set up our vertex buffer and primitive buffer
 715      ri->vertBuff = &mSurfaceBuffers[i].mVertexBuffer;
 716      ri->primBuff = &mSurfaceBuffers[i].mPrimitiveBuffer;
 717
 718      ri->prim = renderPass->allocPrim();
 719      ri->prim->type = GFXTriangleList;
 720      ri->prim->minIndex = 0;
 721      ri->prim->startIndex = 0;
 722      ri->prim->numPrimitives = mSurfaceBuffers[i].mPrimCount;
 723      ri->prim->startVertex = 0;
 724      ri->prim->numVertices = mSurfaceBuffers[i].mVertCount;
 725
 726      // We sort by the material then vertex buffer.
 727      ri->defaultKey = matInst->getStateHint();
 728      ri->defaultKey2 = (U32)(uintptr_t)ri->vertBuff; // Not 64bit safe!
 729
 730      // Submit our RenderInst to the RenderPassManager
 731      state->getRenderPass()->addInst(ri);
 732   }
 733}
 734
 735void ConvexShape::buildConvex( const Box3F &box, Convex *convex )
 736{
 737   if ( mGeometry.faces.empty() )
 738      return;
 739
 740   mConvexList->collectGarbage();
 741
 742   Box3F realBox = box;
 743   mWorldToObj.mul( realBox );
 744   realBox.minExtents.convolveInverse( mObjScale );
 745   realBox.maxExtents.convolveInverse( mObjScale );
 746
 747   if ( realBox.isOverlapped( getObjBox() ) == false )
 748      return;
 749
 750   // See if this convex exists in the working set already...
 751   Convex *cc = 0;
 752   CollisionWorkingList &wl = convex->getWorkingList();
 753   for ( CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext ) 
 754   {
 755      if ( itr->mConvex->getType() == ConvexShapeCollisionConvexType )
 756      {
 757         ConvexShapeCollisionConvex *pConvex = static_cast<ConvexShapeCollisionConvex*>(itr->mConvex);
 758
 759         if ( pConvex->pShape == this )              
 760         {
 761            cc = itr->mConvex;
 762            return;
 763         }
 764      }
 765   }
 766
 767   // Set up the convex...
 768
 769   ConvexShapeCollisionConvex *cp = new ConvexShapeCollisionConvex();
 770
 771   mConvexList->registerObject( cp );
 772   convex->addToWorkingList( cp );
 773
 774   cp->mObject = this;
 775   cp->pShape  = this;   
 776}
 777
 778bool ConvexShape::buildPolyList( PolyListContext context, AbstractPolyList *plist, const Box3F &box, const SphereF &sphere )
 779{
 780   if ( mGeometry.points.empty() )
 781      return false;
 782
 783   // If we're exporting deal with that first.
 784   if ( context == PLC_Export )
 785   {
 786      AssertFatal( dynamic_cast<OptimizedPolyList*>( plist ), "ConvexShape::buildPolyList - Bad polylist for export!" );
 787      _export( (OptimizedPolyList*)plist, box, sphere );
 788      return true;
 789   }
 790
 791   plist->setTransform( &mObjToWorld, mObjScale );
 792   plist->setObject( this );
 793
 794
 795   // Add points...
 796
 797   const Vector< Point3F> pointList = mGeometry.points;
 798
 799   S32 base = plist->addPoint( pointList[0] );
 800
 801   for ( S32 i = 1; i < pointList.size(); i++ ) 
 802      plist->addPoint( pointList[i] );
 803
 804
 805   // Add Surfaces...
 806
 807   const Vector< ConvexShape::Face> faceList = mGeometry.faces;
 808
 809   if(context == PLC_Navigation)
 810   {
 811      for(S32 i = 0; i < faceList.size(); i++)
 812      {
 813         const ConvexShape::Face &face = faceList[i];
 814
 815         S32 s = face.triangles.size();
 816         for(S32 j = 0; j < s; j++)
 817         {
 818            plist->begin(0, s*i + j);
 819
 820            plist->plane(PlaneF(face.centroid, face.normal));
 821
 822            plist->vertex(base + face.points[face.triangles[j].p0]);
 823            plist->vertex(base + face.points[face.triangles[j].p1]);
 824            plist->vertex(base + face.points[face.triangles[j].p2]);
 825
 826            plist->end();
 827         }
 828      }
 829      return true;
 830   }
 831
 832   for ( S32 i = 0; i < faceList.size(); i++ )
 833   {
 834      const ConvexShape::Face &face = faceList[i];    
 835
 836      plist->begin( 0, i );
 837
 838      plist->plane( PlaneF( face.centroid, face.normal ) );
 839
 840      for ( S32 j = 0; j < face.triangles.size(); j++ )
 841      {
 842         plist->vertex( base + face.points[ face.triangles[j].p0 ] );
 843         plist->vertex( base + face.points[ face.triangles[j].p1 ] );
 844         plist->vertex( base + face.points[ face.triangles[j].p2 ] );
 845      }      
 846
 847      plist->end();
 848   }
 849
 850   return true;
 851}
 852
 853bool ConvexShape::buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F &box, const SphereF &)
 854{
 855   if (mGeometry.points.empty())
 856      return false;
 857
 858   //Get the collision mesh geometry
 859   {
 860      ColladaUtils::ExportData::colMesh* colMesh;
 861      exportData->colMeshes.increment();
 862      colMesh = &exportData->colMeshes.last();
 863
 864      colMesh->mesh.setTransform(&mObjToWorld, mObjScale);
 865      colMesh->mesh.setObject(this);
 866
 867      //Just get the visible
 868      buildPolyList(PLC_Export, &colMesh->mesh, getWorldBox(), getWorldSphere());
 869
 870      colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size());
 871   }
 872
 873   //Next, process the geometry and materials.
 874   //Convex shapes only have the one 'level', so we'll just rely on the export post-process to back-fill
 875   if (isServerObject() && getClientObject())
 876   {
 877      exportData->meshData.increment();
 878
 879      //Prep a meshData for this shape in particular
 880      ColladaUtils::ExportData::meshLODData* meshData = &exportData->meshData.last();
 881
 882      //Fill out the info we'll need later to actually append our mesh data for the detail levels during the processing phase
 883      meshData->shapeInst = nullptr;
 884      meshData->originatingObject = this;
 885      meshData->meshTransform = mObjToWorld;
 886      meshData->scale = mObjScale;
 887
 888      meshData->meshDetailLevels.increment();
 889
 890      ColladaUtils::ExportData::detailLevel* curDetail = &meshData->meshDetailLevels.last();
 891
 892      //Make sure we denote the size this detail level has
 893      curDetail->size = getNextPow2(getObjBox().len());
 894
 895   }
 896
 897   return true;
 898}
 899
 900void ConvexShape::_export( OptimizedPolyList *plist, const Box3F &box, const SphereF &sphere )
 901{
 902   BaseMatInstance *matInst = mMaterialInst;
 903   if ( isServerObject() && getClientObject() )
 904      matInst = dynamic_cast<ConvexShape*>(getClientObject())->mMaterialInst;
 905   
 906   MatrixF saveMat;
 907   Point3F saveScale;
 908   plist->getTransform( &saveMat, &saveScale );
 909
 910   plist->setTransform( &mObjToWorld, mObjScale );
 911   plist->setObject( this );   
 912
 913   const Vector< ConvexShape::Face> faceList = mGeometry.faces;
 914   const Vector< Point3F> &pointList = mGeometry.points;
 915
 916   for ( S32 i = 0; i < faceList.size(); i++ )
 917   {
 918      const ConvexShape::Face &face = faceList[i];    
 919
 920      plist->begin( matInst, i, OptimizedPolyList::TriangleList );
 921
 922      plist->plane( PlaneF( face.centroid, face.normal ) );
 923
 924      for ( S32 j = 0; j < face.triangles.size(); j++ )
 925      {                  
 926         for ( S32 k = 0; k < 3; k++ )         
 927         {
 928            U32 vertId = face.triangles[j][k];
 929            plist->vertex( pointList[ face.points[ vertId ] ], face.normal, face.texcoords[ vertId ] );         
 930         }
 931      }      
 932
 933      plist->end();
 934   }
 935
 936   plist->setTransform( &saveMat, saveScale );
 937}
 938
 939bool ConvexShape::castRay( const Point3F &start, const Point3F &end, RayInfo *info )
 940{
 941   if ( mPlanes.empty() )
 942      return false;   
 943
 944   const Vector< PlaneF> &planeList = mPlanes;
 945   const U32 planeCount = planeList.size();  
 946
 947   F32 t;
 948   F32 tmin = F32_MAX;
 949   S32 hitFace = -1;
 950   Point3F hitPnt, pnt;
 951   VectorF rayDir( end - start );
 952   rayDir.normalizeSafe();
 953
 954   if ( false )
 955   {
 956      PlaneF plane( Point3F(0,0,0), Point3F(0,0,1) );
 957      Point3F sp( 0,0,-1 );
 958      Point3F ep( 0,0,1 );
 959
 960      F32 t = plane.intersect( sp, ep );
 961      Point3F hitPnt;
 962      hitPnt.interpolate( sp, ep, t );
 963   }
 964
 965   for ( S32 i = 0; i < planeCount; i++ )
 966   {
 967      // Don't hit the back-side of planes.
 968      if ( mDot( rayDir, planeList[i] ) >= 0.0f )
 969         continue;
 970
 971      t = planeList[i].intersect( start, end );
 972
 973      if ( t >= 0.0f && t <= 1.0f && t < tmin )
 974      {
 975         pnt.interpolate( start, end, t );
 976
 977         S32 j = 0;
 978         for ( ; j < planeCount; j++ )
 979         {
 980            if ( i == j )
 981               continue;
 982
 983            F32 dist = planeList[j].distToPlane( pnt );
 984            if ( dist > 1.0e-004f )
 985               break;
 986         }
 987
 988         if ( j == planeCount )
 989         {
 990            tmin = t;
 991            hitFace = i;
 992         }
 993      }
 994   }
 995
 996   if ( hitFace == -1 )
 997      return false;
 998
 999   info->face = hitFace;            
1000   info->material = mMaterialInst;
1001   info->normal = planeList[ hitFace ];
1002   info->object = this;
1003   info->t = tmin;
1004
1005   //mObjToWorld.mulV( info->normal );
1006
1007   return true;
1008}
1009
1010bool ConvexShape::collideBox( const Point3F &start, const Point3F &end, RayInfo *info )
1011{
1012   return Parent::collideBox( start, end, info );
1013}
1014
1015void ConvexShape::updateBounds( bool recenter )
1016{
1017   if ( mGeometry.points.size() == 0 )
1018      return;
1019
1020   Vector<Point3F> &pointListOS = mGeometry.points;
1021   U32 pointCount = pointListOS.size();
1022
1023   Point3F volumnCenter( 0,0,0 );
1024   F32 areaSum = 0.0f;
1025
1026   F32 faceCount = mGeometry.faces.size();
1027
1028   for ( S32 i = 0; i < faceCount; i++ )   
1029   {
1030      volumnCenter += mGeometry.faces[i].centroid * mGeometry.faces[i].area;         
1031      areaSum += mGeometry.faces[i].area;
1032   }
1033
1034   if ( areaSum == 0.0f )
1035      return;
1036
1037   volumnCenter /= areaSum;
1038   
1039   mObjBox.minExtents = mObjBox.maxExtents = Point3F::Zero;
1040   mObjBox.setCenter( volumnCenter );
1041
1042   for ( S32 i = 0; i < pointCount; i++ )      
1043      mObjBox.extend( pointListOS[i] );
1044
1045   resetWorldBox();
1046}
1047
1048void ConvexShape::recenter()
1049{
1050   if ( mGeometry.points.size() == 0 )
1051      return;
1052  
1053   Point3F volCenterOS( 0,0,0 );
1054   F32 areaSum = 0.0f;
1055
1056   F32 faceCount = mGeometry.faces.size();
1057
1058   for ( S32 i = 0; i < faceCount; i++ )   
1059   {
1060      volCenterOS += mGeometry.faces[i].centroid * mGeometry.faces[i].area;         
1061      areaSum += mGeometry.faces[i].area;
1062   }
1063
1064   volCenterOS /= areaSum;
1065
1066   for ( S32 i = 0; i < mSurfaces.size(); i++ )   
1067      mSurfaces[i].setPosition( mSurfaces[i].getPosition() - volCenterOS );
1068   
1069   Point3F volCenterWS;
1070   MatrixF objToWorld( mObjToWorld );
1071   objToWorld.scale( mObjScale );
1072   objToWorld.mulP( volCenterOS, &volCenterWS );
1073
1074   setPosition( volCenterWS );
1075
1076   _updateGeometry(true);   
1077}
1078
1079MatrixF ConvexShape::getSurfaceWorldMat( S32 surfId, bool scaled ) const
1080{
1081   if ( surfId < 0 || surfId >= mSurfaces.size() )
1082      return MatrixF::Identity;      
1083
1084   MatrixF objToWorld( mObjToWorld );
1085
1086   if ( scaled )
1087      objToWorld.scale( mObjScale );
1088
1089   MatrixF surfMat;
1090   surfMat.mul( objToWorld, mSurfaces[surfId] );   
1091
1092   return surfMat;
1093}
1094
1095// Used in cullEmptyPlanes.
1096S32 QSORT_CALLBACK sortDescendingU32( const void *a, const void *b )
1097{
1098   U32 *aa = (U32*)(a);
1099   U32 *bb = (U32*)(b);
1100
1101   return (S32)(*bb) - (S32)(*aa);
1102}
1103
1104void ConvexShape::cullEmptyPlanes( Vector< U32> *removedPlanes )
1105{
1106   //if ( mPlanes.size() == mGeometry.faces.size() )
1107   //   return;
1108
1109   removedPlanes->clear();
1110   const U32 startPlaneCount = mPlanes.size();
1111
1112   const Vector< ConvexShape::Face> &faceList = mGeometry.faces;
1113   const U32 faceCount = faceList.size();
1114
1115   S32 *used = new S32[ startPlaneCount ];
1116
1117   for ( S32 i = 0; i < startPlaneCount; i++ )   
1118      used[i] = i;
1119
1120   for ( S32 i = 0; i < faceCount; i++ )
1121   {
1122      if ( faceList[i].area > 0.001f )
1123         used[ faceList[i].id ] = -1;
1124   }
1125
1126   for ( S32 i = 0; i < startPlaneCount; i++ )
1127   {
1128      if ( used[i] != -1 )      
1129         removedPlanes->push_back( used[i] );
1130   }
1131   
1132   dQsort( removedPlanes->address(), removedPlanes->size(), sizeof( U32 ), sortDescendingU32 );
1133
1134   for ( S32 i = 0; i < removedPlanes->size(); i++ )
1135   {
1136      mPlanes.erase( (*removedPlanes)[i] );
1137      mSurfaces.erase( (*removedPlanes)[i] );      
1138   }
1139
1140   delete [] used;
1141}
1142
1143void ConvexShape::exportToCollada()
1144{
1145   if ( mSurfaces.size() == 0 )
1146   {
1147      Con::errorf( "ConvexShape::exportToCollada() - has no surfaces to export!" );
1148      return;
1149   }
1150}
1151
1152void ConvexShape::resizePlanes( const Point3F &size )
1153{
1154   //Point3F nSize;
1155   //mWorldToObj.mulV( nSize );
1156
1157   for ( S32 i = 0; i < mSurfaces.size(); i++ )
1158   {
1159      MatrixF objToPlane( mSurfaces[i] );
1160      objToPlane.inverse();
1161
1162      Point3F lim;
1163      objToPlane.mulV( size, &lim );
1164
1165      F32 sign = ( mPlanes[i].d > 0.0f ) ? 1.0f : -1.0f;
1166      mPlanes[i].d = mFabs(lim.z) * 0.5f * sign;
1167      
1168      //mPlanes[i].d = -lim.z * 0.5f;      
1169
1170      mSurfaces[i].setPosition( mPlanes[i].getPosition() );
1171   }   
1172}
1173
1174void ConvexShape::getSurfaceLineList( S32 surfId, Vector< Point3F> &lineList )
1175{
1176   if ( surfId < 0 || surfId > mSurfaces.size() - 1 )
1177      return;
1178
1179   S32 faceId = -1;
1180
1181   for ( S32 i = 0; i < mGeometry.faces.size(); i++ )
1182   {
1183      if ( mGeometry.faces[i].id == surfId )
1184      {
1185         faceId = i;
1186         break;
1187      }
1188   }
1189
1190   if ( faceId == -1 )
1191      return;
1192
1193   ConvexShape::Face &face = mGeometry.faces[faceId];
1194   const Vector< Point3F> &pointList = mGeometry.points;
1195
1196   if ( pointList.size() == 0 )
1197      return;
1198
1199   for ( S32 i = 0; i < face.winding.size(); i++ )   
1200      lineList.push_back( pointList[ face.points[ face.winding[i] ] ] );
1201   
1202   lineList.push_back( pointList[ face.points[ face.winding.first() ] ] );
1203}
1204
1205void ConvexShape::_updateMaterial()
1206{   
1207   //update our custom surface materials
1208   for (U32 i = 0; i<mSurfaceTextures.size(); i++)
1209   {
1210      //If we already have the material inst and it hasn't changed, skip
1211      if (mSurfaceTextures[i].materialInst && mSurfaceTextures[i].materialName.equal(mSurfaceTextures[i].materialInst->getMaterial()->getName(), String::NoCase))
1212         continue;
1213
1214      Material *material;
1215
1216      if (!Sim::findObject(mSurfaceTextures[i].materialName, material))
1217         //bail
1218         continue;
1219
1220      mSurfaceTextures[i].materialInst = material->createMatInstance();
1221
1222      FeatureSet features = MATMGR->getDefaultFeatures();
1223
1224      mSurfaceTextures[i].materialInst->init(features, getGFXVertexFormat<VertexType>());
1225
1226      if (!mSurfaceTextures[i].materialInst->isValid())
1227      {
1228         SAFE_DELETE(mSurfaceTextures[i].materialInst);
1229      }
1230   }
1231
1232   // If the material name matches then don't bother updating it.
1233   if (mMaterialInst && mMaterialName.equal(mMaterialInst->getMaterial()->getName(), String::NoCase))
1234      return;
1235
1236   SAFE_DELETE( mMaterialInst );
1237
1238   Material *material;
1239   
1240   if ( !Sim::findObject( mMaterialName, material ) )
1241      Sim::findObject( "WarningMaterial", material );
1242
1243   mMaterialInst = material->createMatInstance();
1244
1245   //GFXStateBlockDesc desc;
1246   //desc.setCullMode( GFXCullNone );
1247   //desc.setBlend( false );
1248
1249   //mMaterialInst->addStateBlockDesc( desc );
1250
1251   FeatureSet features = MATMGR->getDefaultFeatures();
1252   //features.addFeature( MFT_DiffuseVertColor );
1253
1254   mMaterialInst->init( features, getGFXVertexFormat<VertexType>() );
1255
1256   if ( !mMaterialInst->isValid() )
1257   {
1258      SAFE_DELETE( mMaterialInst );
1259   }
1260}
1261
1262void ConvexShape::_updateGeometry( bool updateCollision )
1263{
1264   mPlanes.clear();
1265
1266   for ( S32 i = 0; i < mSurfaces.size(); i++ )   
1267      mPlanes.push_back( PlaneF( mSurfaces[i].getPosition(), mSurfaces[i].getUpVector() ) );
1268
1269   Vector< Point3F> tangents;
1270   for (S32 i = 0; i < mSurfaces.size(); i++)
1271      tangents.push_back(mSurfaces[i].getRightVector());
1272
1273   //prepping the texture info
1274   Vector<Point2F> texOffset;
1275   Vector<Point2F> texScale;
1276   Vector<bool> horzFlip;
1277   Vector<bool> vertFlip;
1278   //step in here, and add new surfaceTextures if we don't match the count of surfaces, we use
1279   //msurfaces as the counter, because we need to match it.
1280   if (mSurfaceUVs.size() > mSurfaces.size())
1281   {
1282      for (U32 x = mSurfaceUVs.size(); x > mSurfaces.size(); x--)
1283         mSurfaceUVs.pop_front();
1284   }
1285   else if (mSurfaceUVs.size() < mSurfaces.size())
1286   {
1287      for (U32 x = mSurfaceUVs.size(); x <= mSurfaces.size(); x++)
1288      {
1289         mSurfaceUVs.increment();
1290         mSurfaceUVs[x].offset = Point2F(0, 0);
1291         mSurfaceUVs[x].scale = Point2F(1, 1);
1292         mSurfaceUVs[x].zRot = 0;
1293         mSurfaceUVs[x].horzFlip = false;
1294         mSurfaceUVs[x].vertFlip = false;
1295         mSurfaceUVs[x].matID = 0;
1296      }
1297   }
1298
1299   for (S32 i = 0; i < mSurfaceUVs.size(); i++)
1300   {
1301      //add our offsets/scales for passing to the geometry now
1302      texOffset.push_back(mSurfaceUVs[i].offset);
1303      texScale.push_back(mSurfaceUVs[i].scale);
1304      horzFlip.push_back(mSurfaceUVs[i].horzFlip);
1305      vertFlip.push_back(mSurfaceUVs[i].vertFlip);
1306   }
1307
1308   mGeometry.generate(mPlanes, tangents, mSurfaceTextures, texOffset, texScale, horzFlip, vertFlip);
1309
1310   AssertFatal(mGeometry.faces.size() <= mSurfaces.size(), "Got more faces than planes?");
1311
1312   const Vector< ConvexShape::Face> &faceList = mGeometry.faces;
1313   const Vector< Point3F> &pointList = mGeometry.points;
1314
1315   // Reset our surface center points.
1316
1317   for (S32 i = 0; i < faceList.size(); i++)
1318      mSurfaces[faceList[i].id].setPosition(faceList[i].centroid);
1319
1320   mPlanes.clear();
1321
1322   for (S32 i = 0; i < mSurfaces.size(); i++)
1323      mPlanes.push_back(PlaneF(mSurfaces[i].getPosition(), mSurfaces[i].getUpVector()));
1324
1325   // Update bounding box.   
1326   updateBounds( false );
1327
1328   /*mVertexBuffer = NULL;
1329   mPrimitiveBuffer = NULL;
1330   mVertCount = 0;
1331   mPrimCount = 0;*/
1332
1333   mSurfaceBuffers.clear();
1334
1335   //set up buffers based on how many materials we have, but we always have at least one for our default mat
1336   mSurfaceBuffers.increment();
1337   mSurfaceBuffers[0].mVertexBuffer = NULL;
1338   mSurfaceBuffers[0].mVertCount = 0;
1339   mSurfaceBuffers[0].mPrimCount = 0;
1340
1341   for (U32 i = 0; i < mSurfaceTextures.size(); i++)
1342   {
1343      mSurfaceBuffers.increment();
1344      mSurfaceBuffers[i+1].mVertexBuffer = NULL;
1345      mSurfaceBuffers[i + 1].mVertCount = 0;
1346      mSurfaceBuffers[i + 1].mPrimCount = 0;
1347   }
1348
1349   if ( updateCollision )
1350      _updateCollision();
1351
1352   // Server does not need to generate vertex/prim buffers.
1353   if ( isServerObject() )
1354      return;
1355
1356   if ( faceList.empty() )   
1357      return;
1358
1359   //We do this in 2 parts. First, going through and building the buffers for all faces with the default material(matID -1)
1360   //After that, we then through and build buffers for all faces sharing materials. This means we can have a single buffer,
1361   //or one for each face of the brush, depending on how it's textured
1362
1363   // Get total vert and prim count.
1364
1365   for ( S32 i = 0; i < faceList.size(); i++ )  
1366   {
1367      U32 count = faceList[i].triangles.size();
1368
1369      S32 matID = mSurfaceUVs[i].matID;
1370
1371      mSurfaceBuffers[mSurfaceUVs[i].matID].mPrimCount += count;
1372      mSurfaceBuffers[mSurfaceUVs[i].matID].mVertCount += count * 3;
1373   }
1374
1375   //Build the buffer for our default material
1376   /*if (mVertCount > 0)
1377   {
1378      mVertexBuffer.set(GFX, mVertCount, GFXBufferTypeStatic);
1379      VertexType *pVert = mVertexBuffer.lock();
1380
1381      for (S32 i = 0; i < faceList.size(); i++)
1382      {
1383         if (mSurfaceUVs[i].matID == -1)
1384         {
1385            const ConvexShape::Face &face = faceList[i];
1386            const Vector< U32 > &facePntMap = face.points;
1387            const Vector< ConvexShape::Triangle > &triangles = face.triangles;
1388            const ColorI &faceColor = sgConvexFaceColors[i % sgConvexFaceColorCount];
1389
1390            const Point3F binormal = mCross(face.normal, face.tangent);
1391
1392                  pVert++;
1393               }
1394            }
1395         }
1396      }
1397
1398      mVertexBuffer.unlock();
1399
1400      // Allocate PB
1401
1402      mPrimitiveBuffer.set(GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic);
1403
1404      U16 *pIndex;
1405      mPrimitiveBuffer.lock(&pIndex);
1406
1407      for (U16 i = 0; i < mPrimCount * 3; i++)
1408      {
1409         *pIndex = i;
1410         pIndex++;
1411      }
1412
1413      mPrimitiveBuffer.unlock();
1414   }*/
1415
1416   //
1417   //
1418   for (U32 i = 0; i < mSurfaceBuffers.size(); i++)
1419   {
1420      if (mSurfaceBuffers[i].mVertCount > 0)
1421      {
1422         U32 primCount = mSurfaceBuffers[i].mPrimCount;
1423         U32 vertCount = mSurfaceBuffers[i].mVertCount;
1424
1425         mSurfaceBuffers[i].mVertexBuffer.set(GFX, mSurfaceBuffers[i].mVertCount, GFXBufferTypeStatic);
1426         VertexType *pVert = mSurfaceBuffers[i].mVertexBuffer.lock();
1427
1428         U32 vc = 0;
1429
1430         for (S32 f = 0; f < faceList.size(); f++)
1431         {
1432            if (mSurfaceUVs[f].matID == i)
1433            {
1434               const ConvexShape::Face &face = faceList[f];
1435               const Vector< U32> &facePntMap = face.points;
1436               const Vector< ConvexShape::Triangle> &triangles = face.triangles;
1437               const ColorI &faceColor = sgConvexFaceColors[f % sgConvexFaceColorCount];
1438
1439               const Point3F binormal = mCross(face.normal, face.tangent);
1440
1441               for (S32 j = 0; j < triangles.size(); j++)
1442               {
1443                  for (S32 k = 0; k < 3; k++)
1444                  {
1445                     pVert->normal = face.normal;
1446                     pVert->tangent = face.tangent;
1447                     pVert->color = faceColor;
1448                     pVert->point = pointList[facePntMap[triangles[j][k]]];
1449                     pVert->texCoord = face.texcoords[triangles[j][k]];
1450
1451                     pVert++;
1452                     vc++;
1453                  }
1454               }
1455            }
1456         }
1457
1458         mSurfaceBuffers[i].mVertexBuffer.unlock();
1459
1460         // Allocate PB
1461
1462         mSurfaceBuffers[i].mPrimitiveBuffer.set(GFX, mSurfaceBuffers[i].mPrimCount * 3, mSurfaceBuffers[i].mPrimCount, GFXBufferTypeStatic);
1463
1464         U16 *pIndex;
1465         mSurfaceBuffers[i].mPrimitiveBuffer.lock(&pIndex);
1466
1467         for (U16 p = 0; p < mSurfaceBuffers[i].mPrimCount * 3; p++)
1468         {
1469            *pIndex = p;
1470            pIndex++;
1471         }
1472
1473         mSurfaceBuffers[i].mPrimitiveBuffer.unlock();
1474      }
1475   }
1476   //
1477   //
1478
1479   /*// Allocate VB and copy in data.
1480   for (S32 i = 0; i < faceList.size(); i++)
1481   {
1482      mVertexBuffer.set(GFX, mVertCount, GFXBufferTypeStatic);
1483      VertexType *pVert = mVertexBuffer.lock();
1484
1485      for (S32 i = 0; i < faceList.size(); i++)
1486      {
1487         const ConvexShape::Face &face = faceList[i];
1488         const Vector< U32 > &facePntMap = face.points;
1489         const Vector< ConvexShape::Triangle > &triangles = face.triangles;
1490         const ColorI &faceColor = sgConvexFaceColors[i % sgConvexFaceColorCount];
1491
1492         const Point3F binormal = mCross(face.normal, face.tangent);
1493
1494         for (S32 j = 0; j < triangles.size(); j++)
1495         {
1496            for (S32 k = 0; k < 3; k++)
1497            {
1498               pVert->normal = face.normal;
1499               pVert->tangent = face.tangent;
1500               pVert->color = faceColor;
1501               pVert->point = pointList[facePntMap[triangles[j][k]]];
1502               pVert->texCoord = face.texcoords[triangles[j][k]];
1503
1504               pVert++;
1505            }
1506         }
1507      }
1508
1509      mVertexBuffer.unlock();
1510
1511      // Allocate PB
1512
1513      mPrimitiveBuffer.set(GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic);
1514
1515      U16 *pIndex;
1516      mPrimitiveBuffer.lock(&pIndex);
1517
1518      for (U16 i = 0; i < mPrimCount * 3; i++)
1519      {
1520         *pIndex = i;
1521         pIndex++;
1522      }
1523
1524      mPrimitiveBuffer.unlock();
1525   }*/
1526}
1527
1528void ConvexShape::_updateCollision()
1529{
1530   SAFE_DELETE( mPhysicsRep );
1531
1532   if ( !PHYSICSMGR )
1533      return;
1534
1535   PhysicsCollision *colShape = PHYSICSMGR->createCollision();
1536
1537   // We need the points untransformed!
1538   Vector<Point3F> rawPoints;
1539   MatrixF xfm( getWorldTransform() );
1540   xfm.setPosition( Point3F::Zero );
1541   for ( U32 i=0; i < mGeometry.points.size(); i++ )
1542   {
1543      Point3F p = mGeometry.points[i];
1544      xfm.mulP( p );
1545      rawPoints.push_back( p );
1546   }
1547
1548   // The convex generation from a point cloud 
1549   // can fail at times... give up in that case.
1550   if ( !colShape->addConvex(    mGeometry.points.address(), 
1551                                 mGeometry.points.size(), 
1552                                 MatrixF::Identity ) )
1553   {
1554      delete colShape;
1555      return;
1556   }
1557
1558   PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
1559
1560   mPhysicsRep = PHYSICSMGR->createBody();
1561   mPhysicsRep->init( colShape, 0, 0, this, world );
1562
1563   mPhysicsRep->setTransform( getTransform() );
1564}
1565
1566void ConvexShape::_renderDebug( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mat )
1567{   
1568   GFXDrawUtil *drawer = GFX->getDrawUtil();
1569
1570   GFX->setTexture( 0, NULL );
1571
1572   // Render world box.
1573   if (Con::getBoolVariable("$pref::convexDBG::ShowWorldBox", false))
1574   {
1575      Box3F wbox( mWorldBox );
1576      if ( getServerObject() )      
1577         wbox = static_cast<ConvexShape*>( getServerObject() )->mWorldBox;      
1578      GFXStateBlockDesc desc;
1579      desc.setCullMode( GFXCullNone );
1580      desc.setFillModeWireframe();
1581      drawer->drawCube( desc, wbox, ColorI::RED );
1582   }
1583
1584
1585   const Vector< Point3F> &pointList = mGeometry.points;
1586   const Vector< ConvexShape::Face> &faceList = mGeometry.faces;
1587
1588   // Render Edges.
1589   if (Con::getBoolVariable("$pref::convexDBG::ShowEdges", false))
1590   {
1591      GFXTransformSaver saver;
1592      //GFXFrustumSaver fsaver;
1593
1594      MatrixF xfm( getRenderTransform() );
1595      xfm.scale( getScale() );
1596      GFX->multWorld( xfm );
1597
1598      GFXStateBlockDesc desc;
1599      desc.setZReadWrite( true, false );
1600      desc.setBlend( true );
1601      GFX->setStateBlockByDesc( desc );
1602
1603      //MathUtils::getZBiasProjectionMatrix( 0.01f, state->getFrustum(), )
1604
1605      const Point3F &camFvec = state->getCameraTransform().getForwardVector();
1606
1607
1608
1609      for ( S32 i = 0; i < faceList.size(); i++ )
1610      {         
1611         const ConvexShape::Face &face = faceList[i];
1612         
1613         const Vector< ConvexShape::Edge> &edgeList = face.edges;
1614
1615         const Vector< U32> &facePntList = face.points;
1616
1617         PrimBuild::begin( GFXLineList, edgeList.size() * 2 );
1618         
1619         PrimBuild::color( LinearColorF(ColorI::WHITE) * 0.8f );
1620
1621         for ( S32 j = 0; j < edgeList.size(); j++ )         
1622         {
1623            PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p0 ] ] - camFvec * 0.001f );
1624            PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p1 ] ] - camFvec * 0.001f );
1625         }
1626         
1627         PrimBuild::end();
1628      }
1629   }
1630
1631   ColorI faceColorsx[4] = 
1632   {
1633      ColorI( 255, 0, 0 ),
1634      ColorI( 0, 255, 0 ),
1635      ColorI( 0, 0, 255 ),
1636      ColorI( 255, 0, 255 )
1637   };
1638
1639   MatrixF objToWorld( mObjToWorld );
1640   objToWorld.scale( mObjScale );
1641
1642   // Render faces centers/colors.
1643   if (Con::getBoolVariable("$pref::convexDBG::ShowFaceColors", false))
1644   {
1645      GFXStateBlockDesc desc;
1646      desc.setCullMode( GFXCullNone );
1647      
1648      Point3F size( 0.1f );
1649
1650      for ( S32 i = 0; i < faceList.size(); i++ )
1651      {
1652         ColorI color = faceColorsx[ i % 4 ];
1653         LinearColorF tCol = LinearColorF(color);
1654         S32 div = ( i / 4 ) * 4;
1655         if ( div > 0 )
1656            tCol /= div;
1657         tCol.alpha = 1;
1658         color = tCol.toColorI();
1659
1660         Point3F pnt;
1661         objToWorld.mulP( faceList[i].centroid, &pnt );
1662         drawer->drawCube( desc, size, pnt, color, NULL );
1663      }
1664   }
1665
1666   // Render winding order.
1667   if (Con::getBoolVariable("$pref::convexDBG::ShowWinding", false))
1668   {
1669      GFXStateBlockDesc desc;
1670      desc.setCullMode( GFXCullNone );
1671      desc.setZReadWrite( true, false );
1672      GFX->setStateBlockByDesc( desc );  
1673
1674      U32 pointCount = 0;
1675      for ( S32 i = 0; i < faceList.size(); i++ )      
1676         pointCount += faceList[i].winding.size();      
1677
1678      PrimBuild::begin( GFXLineList, pointCount * 2 );
1679      
1680      for ( S32 i = 0; i < faceList.size(); i++ )
1681      {
1682         for ( S32 j = 0; j < faceList[i].winding.size(); j++ )
1683         {
1684            Point3F p0 = pointList[ faceList[i].points[ faceList[i].winding[j] ] ];
1685            Point3F p1 = p0 + mSurfaces[ faceList[i].id ].getUpVector() * 0.75f * ( Point3F::One / mObjScale );
1686
1687            objToWorld.mulP( p0 );
1688            objToWorld.mulP( p1 );
1689
1690            ColorI color = faceColorsx[j % 4];
1691            LinearColorF tCol = LinearColorF(color);
1692            S32 div = (j / 4) * 4;
1693            if (div > 0)
1694               tCol /= div;
1695            tCol.alpha = 1;
1696            color = tCol.toColorI();
1697            
1698            PrimBuild::color( color );
1699            PrimBuild::vertex3fv( p0 );            
1700            PrimBuild::color( color );
1701            PrimBuild::vertex3fv( p1 );                        
1702         }
1703      }
1704
1705      PrimBuild::end();
1706   }
1707
1708   // Render Points.
1709   if ( false )
1710   {      
1711      /*
1712      GFXTransformSaver saver;
1713
1714      MatrixF xfm( getRenderTransform() );
1715      xfm.scale( getScale() );
1716      GFX->multWorld( xfm );
1717
1718      GFXStateBlockDesc desc;
1719      Point3F size( 0.05f );
1720      */
1721   }
1722
1723   // Render surface transforms.
1724   if (Con::getBoolVariable("$pref::convexDBG::ShowSurfaceTransforms", false))
1725   {
1726      GFXStateBlockDesc desc;
1727      desc.setBlend( false );
1728      desc.setZReadWrite( true, true );
1729
1730      Point3F scale(mNormalLength);
1731
1732      for ( S32 i = 0; i < mSurfaces.size(); i++ )
1733      {
1734         objToWorld = mObjToWorld;
1735         objToWorld.scale( mObjScale );
1736
1737         MatrixF renderMat;
1738         renderMat.mul( objToWorld, mSurfaces[i] );
1739
1740         renderMat.setPosition( renderMat.getPosition() + renderMat.getUpVector() * 0.001f );
1741              
1742         drawer->drawTransform( desc, renderMat, &scale, NULL );
1743      }
1744   }
1745}
1746
1747void ConvexShape::renderFaceEdges( S32 faceid, const ColorI &color /*= ColorI::WHITE*/, F32 lineWidth /*= 1.0f */ )
1748{
1749   const Vector< ConvexShape::Face> &faceList = mGeometry.faces;
1750
1751   if ( faceid >= faceList.size() )
1752      return;
1753
1754   GFXTransformSaver saver;
1755   MatrixF xfm( mObjToWorld );
1756   xfm.scale( mObjScale );
1757   GFX->multWorld( xfm );
1758
1759   GFXStateBlockDesc desc;
1760   desc.setBlend( true );
1761   GFX->setStateBlockByDesc( desc );
1762
1763   MatrixF projBias(true);
1764   const Frustum& frustum = GFX->getFrustum();
1765   MathUtils::getZBiasProjectionMatrix( 0.001f, frustum, &projBias );
1766   GFX->setProjectionMatrix( projBias );
1767
1768   S32 s = faceid;
1769   S32 e = faceid + 1;
1770
1771   if ( faceid == -1 )
1772   {
1773      s = 0;
1774      e = faceList.size();
1775   }
1776
1777   for ( S32 i = s; i < e; i++ )
1778   {
1779      const ConvexShape::Face &face = faceList[i];
1780      const Vector< ConvexShape::Edge> &edgeList = face.edges;
1781      const Vector< U32> &facePntList = face.points;
1782      const Vector< Point3F> &pointList = mGeometry.points;
1783
1784      PrimBuild::begin( GFXLineList, edgeList.size() * 2 );
1785
1786      PrimBuild::color( color );
1787
1788      for ( S32 j = 0; j < edgeList.size(); j++ )         
1789      {
1790         PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p0 ] ] );
1791         PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p1 ] ] );
1792      }
1793
1794      PrimBuild::end();
1795   }
1796}
1797
1798void ConvexShape::getSurfaceTriangles( S32 surfId, Vector< Point3F> *outPoints, Vector< Point2F> *outCoords, bool worldSpace )
1799{
1800   S32 faceId = -1;
1801   for ( S32 i = 0; i < mGeometry.faces.size(); i++ )
1802   {
1803      if ( mGeometry.faces[i].id == surfId )
1804      {
1805         faceId = i;
1806         break;
1807      }
1808   }
1809
1810   if ( faceId == -1 )
1811      return;
1812
1813   const ConvexShape::Face &face = mGeometry.faces[ faceId ];
1814   const Vector< Point3F> &pointList = mGeometry.points;
1815
1816   const MatrixF &surfToObj = mSurfaces[ faceId ];
1817   MatrixF objToSurf( surfToObj );
1818   objToSurf.inverse();
1819
1820   Point3F surfScale( 1.5f, 1.5f, 1.0f );
1821
1822   for ( S32 i = 0; i < face.triangles.size(); i++ )
1823   {
1824      for ( S32 j = 0; j < 3; j++ )
1825      {
1826         Point3F pnt( pointList[ face.points[ face.triangles[i][j] ] ] );
1827         
1828         objToSurf.mulP( pnt );
1829         pnt *= surfScale;
1830         surfToObj.mulP( pnt );
1831
1832         outPoints->push_back( pnt );
1833
1834         if ( outCoords )
1835            outCoords->push_back( face.texcoords[ face.triangles[i][j] ] );
1836      }
1837   }
1838
1839   if ( worldSpace )
1840   {
1841      MatrixF objToWorld( mObjToWorld );
1842      objToWorld.scale( mObjScale );
1843
1844      for ( S32 i = 0; i < outPoints->size(); i++ )      
1845         objToWorld.mulP( (*outPoints)[i] );      
1846   }
1847}
1848void ConvexShape::Geometry::generate(const Vector< PlaneF> &planes, const Vector< Point3F> &tangents, const Vector< surfaceMaterial> surfaceTextures, const Vector< Point2F> texOffset, const Vector< Point2F> texScale, const Vector< bool> horzFlip, const Vector< bool> vertFlip)
1849{
1850   PROFILE_SCOPE( Geometry_generate );
1851
1852   points.clear();
1853   faces.clear(); 
1854
1855   AssertFatal( planes.size() == tangents.size(), "ConvexShape - incorrect plane/tangent count." );
1856
1857#ifdef TORQUE_ENABLE_ASSERTS
1858   for ( S32 i = 0; i < planes.size(); i++ )
1859   {
1860      F32 dt = mDot( planes[i], tangents[i] );
1861      AssertFatal( mIsZero( dt, 0.0001f ), "ConvexShape - non perpendicular input vectors." );
1862      AssertFatal( planes[i].isUnitLength() && tangents[i].isUnitLength(), "ConvexShape - non unit length input vector." );
1863   }
1864#endif
1865
1866   const U32 planeCount = planes.size();
1867
1868   Point3F linePt, lineDir;   
1869
1870   for ( S32 i = 0; i < planeCount; i++ )
1871   {      
1872      Vector< MathUtils::Line> collideLines;
1873
1874      // Find the lines defined by the intersection of this plane with all others.
1875
1876      for ( S32 j = 0; j < planeCount; j++ )
1877      {         
1878         if ( i == j )
1879            continue;
1880
1881         if ( planes[i].intersect( planes[j], linePt, lineDir ) )
1882         {
1883            collideLines.increment();
1884            MathUtils::Line &line = collideLines.last();
1885            line.origin = linePt;
1886            line.direction = lineDir;   
1887         }         
1888      }
1889
1890      if ( collideLines.empty() )
1891         continue;
1892
1893      // Find edges and points defined by the intersection of these lines.
1894      // As we find them we fill them into our working ConvexShape::Face
1895      // structure.
1896      
1897      Face newFace;
1898
1899      for ( S32 j = 0; j < collideLines.size(); j++ )
1900      {
1901         Vector< Point3F> collidePoints;
1902
1903         for ( S32 k = 0; k < collideLines.size(); k++ )
1904         {
1905            if ( j == k )
1906               continue;
1907
1908            MathUtils::LineSegment segment;
1909            MathUtils::mShortestSegmentBetweenLines( collideLines[j], collideLines[k], &segment );
1910
1911            F32 dist = ( segment.p0 - segment.p1 ).len();
1912
1913            if ( dist < 0.0005f )
1914            {
1915               S32 l = 0;
1916               for ( ; l < planeCount; l++ )
1917               {
1918                  if ( planes[l].whichSide( segment.p0 ) == PlaneF::Front )
1919                     break;
1920               }
1921
1922               if ( l == planeCount )
1923                  collidePoints.push_back( segment.p0 );
1924            }
1925         }
1926
1927         //AssertFatal( collidePoints.size() <= 2, "A line can't collide with more than 2 other lines in a convex shape..." );
1928
1929         if ( collidePoints.size() != 2 )
1930            continue;
1931
1932         // Push back collision points into our points vector
1933         // if they are not duplicates and determine the id
1934         // index for those points to be used by Edge(s).    
1935
1936         const Point3F &pnt0 = collidePoints[0];
1937         const Point3F &pnt1 = collidePoints[1];
1938         S32 idx0 = -1;
1939         S32 idx1 = -1;
1940
1941         for ( S32 k = 0; k < points.size(); k++ )
1942         {
1943            if ( pnt0.equal( points[k] ) )
1944            {
1945               idx0 = k;
1946               break;
1947            }
1948         }
1949
1950         for ( S32 k = 0; k < points.size(); k++ )
1951         {
1952            if ( pnt1.equal( points[k] ) )
1953            {
1954               idx1 = k;
1955               break;
1956            }
1957         }
1958
1959         if ( idx0 == -1 )
1960         {
1961            points.push_back( pnt0 );               
1962            idx0 = points.size() - 1;
1963         }
1964
1965         if ( idx1 == -1 )
1966         {
1967            points.push_back( pnt1 );
1968            idx1 = points.size() - 1;
1969         }
1970
1971         // Construct the Face::Edge defined by this collision.
1972
1973         S32 localIdx0 = newFace.points.push_back_unique( idx0 );
1974         S32 localIdx1 = newFace.points.push_back_unique( idx1 );
1975
1976         newFace.edges.increment();
1977         ConvexShape::Edge &newEdge = newFace.edges.last();
1978         newEdge.p0 = localIdx0;
1979         newEdge.p1 = localIdx1;
1980      }    
1981
1982      if ( newFace.points.size() < 3 )
1983         continue;
1984
1985      //AssertFatal( newFace.points.size() == newFace.edges.size(), "ConvexShape - face point count does not equal edge count." );
1986
1987
1988      // Fill in some basic Face information.
1989
1990      newFace.id = i;
1991      newFace.normal = planes[i];
1992      newFace.tangent = tangents[i];
1993
1994
1995      // Make a working array of Point3Fs on this face.
1996
1997      U32 pntCount = newFace.points.size();     
1998      Point3F *workPoints = new Point3F[ pntCount ];
1999
2000      for ( S32 j = 0; j < pntCount; j++ )
2001         workPoints[j] = points[ newFace.points[j] ];
2002
2003
2004      // Calculate the average point for calculating winding order.
2005
2006      Point3F averagePnt = Point3F::Zero;
2007
2008      for ( S32 j = 0; j < pntCount; j++ )
2009         averagePnt += workPoints[j];
2010
2011      averagePnt /= pntCount;    
2012
2013
2014      // Sort points in correct winding order.
2015
2016      U32 *vertMap = new U32[pntCount];
2017
2018      MatrixF quadMat( true );
2019      quadMat.setPosition( averagePnt );
2020      quadMat.setColumn( 0, newFace.tangent );
2021      quadMat.setColumn( 1, mCross( newFace.normal, newFace.tangent ) );
2022      quadMat.setColumn( 2, newFace.normal );
2023      quadMat.inverse();
2024
2025      // Transform working points into quad space 
2026      // so we can work with them as 2D points.
2027
2028      for ( S32 j = 0; j < pntCount; j++ )
2029         quadMat.mulP( workPoints[j] );
2030
2031      MathUtils::sortQuadWindingOrder( true, workPoints, vertMap, pntCount );
2032
2033      // Save points in winding order.
2034
2035      for ( S32 j = 0; j < pntCount; j++ )
2036         newFace.winding.push_back( vertMap[j] );
2037
2038      // Calculate the area and centroid of the face.
2039
2040      newFace.area = 0.0f;
2041      for ( S32 j = 0; j < pntCount; j++ )
2042      {
2043         S32 k = ( j + 1 ) % pntCount;
2044         const Point3F &p0 = workPoints[ vertMap[j] ];
2045         const Point3F &p1 = workPoints[ vertMap[k] ];
2046         
2047         // Note that this calculation returns positive area for clockwise winding
2048         // and negative area for counterclockwise winding.
2049         newFace.area += p0.y * p1.x;
2050         newFace.area -= p0.x * p1.y;                  
2051      }
2052
2053      //AssertFatal( newFace.area > 0.0f, "ConvexShape - face area was not positive." );
2054      if ( newFace.area > 0.0f )
2055         newFace.area /= 2.0f;      
2056
2057      F32 factor;
2058      F32 cx = 0.0f, cy = 0.0f;
2059      
2060      for ( S32 j = 0; j < pntCount; j++ )
2061      {
2062         S32 k = ( j + 1 ) % pntCount;
2063         const Point3F &p0 = workPoints[ vertMap[j] ];
2064         const Point3F &p1 = workPoints[ vertMap[k] ];
2065
2066         factor = p0.x * p1.y - p1.x * p0.y;
2067         cx += ( p0.x + p1.x ) * factor;
2068         cy += ( p0.y + p1.y ) * factor;
2069      }
2070      
2071      factor = 1.0f / ( newFace.area * 6.0f );
2072      newFace.centroid.set( cx * factor, cy * factor, 0.0f );
2073      quadMat.inverse();
2074      quadMat.mulP( newFace.centroid );
2075
2076      delete [] workPoints;
2077      workPoints = NULL;
2078
2079      // Make polygons / triangles for this face.
2080
2081      const U32 polyCount = pntCount - 2;
2082
2083      newFace.triangles.setSize( polyCount );
2084
2085      for ( S32 j = 0; j < polyCount; j++ )
2086      {
2087         ConvexShape::Triangle &poly = newFace.triangles[j];
2088
2089         poly.p0 = vertMap[0];
2090
2091         if ( j == 0 )
2092         {
2093            poly.p1 = vertMap[ 1 ];
2094            poly.p2 = vertMap[ 2 ];
2095         }
2096         else
2097         {
2098            poly.p1 = vertMap[ 1 + j ];
2099            poly.p2 = vertMap[ 2 + j ];
2100         }
2101      }
2102
2103      delete [] vertMap;
2104
2105
2106      // Calculate texture coordinates for each point in this face.
2107
2108      const Point3F binormal = mCross( newFace.normal, newFace.tangent );
2109      PlaneF planey( newFace.centroid - 0.5f * binormal, binormal );
2110      PlaneF planex( newFace.centroid - 0.5f * newFace.tangent, newFace.tangent );
2111
2112      newFace.texcoords.setSize( newFace.points.size() );
2113
2114      for ( S32 j = 0; j < newFace.points.size(); j++ )
2115      {
2116         F32 x = planex.distToPlane( points[ newFace.points[ j ] ] );
2117         F32 y = planey.distToPlane( points[ newFace.points[ j ] ] );
2118
2119         if (!texOffset.empty())
2120            {
2121               x += texOffset[i].x;
2122               y += texOffset[i].y;
2123            }
2124   
2125            //now scale
2126            if (!texScale.empty() && !texScale[i].isZero())
2127            {
2128               x *= (texScale[i].x);
2129               y *= (texScale[i].y);
2130            }
2131   
2132            if (horzFlip.size() > 0 && horzFlip[i])
2133               x *= -1;
2134   
2135            if (vertFlip.size() > 0 && vertFlip[i])
2136               y *= -1;
2137   
2138            newFace.texcoords[j].set(-x, -y);
2139      }
2140
2141      // Data verification tests.
2142#ifdef TORQUE_ENABLE_ASSERTS
2143      //S32 triCount = newFace.triangles.size();
2144      //S32 edgeCount = newFace.edges.size();
2145      //AssertFatal( triCount == edgeCount - 2, "ConvexShape - triangle/edge count do not match." );
2146
2147      /*
2148      for ( S32 j = 0; j < triCount; j++ )
2149      {
2150         F32 area = MathUtils::mTriangleArea( points[ newFace.points[ newFace.triangles[j][0] ] ], 
2151                                              points[ newFace.points[ newFace.triangles[j][1] ] ],
2152                                              points[ newFace.points[ newFace.triangles[j][2] ] ] );
2153         AssertFatal( area > 0.0f, "ConvexShape - triangle winding bad." );
2154      }*/
2155#endif
2156
2157
2158      // Done with this Face.
2159      
2160      faces.push_back( newFace );
2161   }
2162}
2163