convexShape.cpp
Engine/source/T3D/convexShape.cpp
Public Variables
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 )
sortDescendingU32(const void * a, const void * b)
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