1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "T3D/convexShape.h"
- #include "math/mathIO.h"
- #include "math/mathUtils.h"
- #include "scene/sceneRenderState.h"
- #include "console/consoleTypes.h"
- #include "core/stream/bitStream.h"
- #include "materials/materialManager.h"
- #include "lighting/lightQuery.h"
- #include "renderInstance/renderPassManager.h"
- #include "gfx/gfxTransformSaver.h"
- #include "gfx/primBuilder.h"
- #include "gfx/gfxDrawUtil.h"
- #include "core/bitVector.h"
- #include "materials/materialFeatureTypes.h"
- #include "materials/baseMatInstance.h"
- #include "collision/optimizedPolyList.h"
- #include "T3D/physics/physicsPlugin.h"
- #include "T3D/physics/physicsBody.h"
- #include "T3D/physics/physicsCollision.h"
- #include "console/engineAPI.h"
- IMPLEMENT_CO_NETOBJECT_V1( ConvexShape );
- ConsoleDocClass( ConvexShape,
- "@brief A renderable, collidable convex shape defined by a collection of surface planes.\n\n"
-
- "%ConvexShape is intended to be used as a temporary asset for quickly "
- "blocking out a scene or filling in approximate shapes to be later replaced "
- "with final assets. This is most easily done by using the WorldEditor's "
- "Sketch Tool.\n\n"
-
- "@ingroup enviroMisc"
- );
- Point3F ConvexShapeCollisionConvex::support( const VectorF &vec ) const
- {
- const Vector< Point3F > &pointList = pShape->mGeometry.points;
- if ( pointList.empty() )
- return pShape->getObjBox().getCenter();
-
- // This doesn't deal with the case that the farthest plane along vec is also
- // perpendicular to it, but in that case maybe it doesn't matter which point we return
- // anyway.
- F32 bestDot = mDot( pointList[0], vec );
- const Point3F *bestP = &pointList[0];
- for ( S32 i = 1; i < pointList.size(); i++ )
- {
- F32 newD = mDot( pointList[i], vec );
- if ( newD > bestDot )
- {
- bestDot = newD;
- bestP = &pointList[i];
- }
- }
- return *bestP;
- }
- void ConvexShapeCollisionConvex::getFeatures( const MatrixF &mat, const VectorF &n, ConvexFeature *cf )
- {
- if ( pShape->mGeometry.points.empty() )
- {
- cf->material = 0;
- cf->object = NULL;
- return;
- }
- cf->material = 0;
- cf->object = mObject;
- // Simple implementation... Add all Points, Edges and Faces.
- // Points...
- S32 firstVert = cf->mVertexList.size();
-
- const Vector< Point3F > &pointList = pShape->mGeometry.points;
- const U32 pointListCount = pointList.size();
- cf->mVertexList.increment( pointListCount );
- for ( S32 i = 0; i < pointListCount; i++ )
- mat.mulP( pointList[i], &(cf->mVertexList[ firstVert + i ]) );
-
- // Edges and Triangles for each face...
- const Vector< ConvexShape::Face > &faceList = pShape->mGeometry.faces;
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- // Add this Face's Edges.
- const Vector< ConvexShape::Edge > &edgeList = faceList[i].edges;
- const U32 edgeCount = edgeList.size();
- const S32 firstEdge = cf->mEdgeList.size();
- cf->mEdgeList.increment( edgeCount );
- for ( S32 j = 0; j < edgeCount; j++ )
- {
- cf->mEdgeList[ firstEdge + j ].vertex[0] = faceList[i].points[ edgeList[j].p0 ];
- cf->mEdgeList[ firstEdge + j ].vertex[1] = faceList[i].points[ edgeList[j].p1 ];
- }
- // Add this face's Triangles.
- // Note that ConvexFeature calls triangles 'faces' but a ConvexShape 'Face' is not
- // necessarily a single triangle.
-
- const Vector< ConvexShape::Triangle > &triangleList = faceList[i].triangles;
- const U32 triangleCount = triangleList.size();
- S32 firstTriangle = cf->mFaceList.size();
- cf->mFaceList.increment( triangleCount );
- for ( S32 j = 0; j < triangleCount; j++ )
- {
- ConvexFeature::Face &cft = cf->mFaceList[ firstTriangle + j ];
- cft.normal = faceList[i].normal;
- cft.vertex[0] = triangleList[j].p0;
- cft.vertex[1] = triangleList[j].p1;
- cft.vertex[2] = triangleList[j].p2;
- }
- }
- }
- void ConvexShapeCollisionConvex::getPolyList( AbstractPolyList* list )
- {
- SphereF sphere( Point3F::Zero, 0.0f );
-
- pShape->buildPolyList( PLC_Collision, list, Box3F::Invalid, sphere );
- }
- GFXImplementVertexFormat( ConvexVert )
- {
- addElement( "POSITION", GFXDeclType_Float3 );
- addElement( "COLOR", GFXDeclType_Color );
- addElement( "NORMAL", GFXDeclType_Float3 );
- addElement( "TANGENT", GFXDeclType_Float3 );
- addElement( "TEXCOORD", GFXDeclType_Float2, 0 );
- };
- static const U32 sgConvexFaceColorCount = 16;
- static const ColorI sgConvexFaceColors[ sgConvexFaceColorCount ] =
- {
- ColorI( 239, 131, 201 ),
- ColorI( 124, 255, 69 ),
- ColorI( 255, 65, 77 ),
- ColorI( 33, 118, 235 ),
- ColorI( 114, 227, 110 ),
- ColorI( 197, 50, 237 ),
- ColorI( 236, 255, 255 ),
- ColorI( 139, 225, 192 ),
- ColorI( 215, 9, 65 ),
- ColorI( 249, 114, 93 ),
- ColorI( 255, 255, 90 ),
- ColorI( 93, 104, 97 ),
- ColorI( 255, 214, 192 ),
- ColorI( 122, 44, 198 ),
- ColorI( 137, 141, 194 ),
- ColorI( 164, 114, 43 )
- };
- bool ConvexShape::smRenderEdges = false;
- bool ConvexShape::protectedSetSurface( void *object, const char *index, const char *data )
- {
- ConvexShape *shape = static_cast< ConvexShape* >( object );
- QuatF quat;
- Point3F pos;
- //MatrixF mat;
- /*
- dSscanf( data, "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g",
- &mat[0], &mat[1], &mat[2], &mat[3],
- &mat[4], &mat[5], &mat[6], &mat[7],
- &mat[8], &mat[9], &mat[10], &mat[11],
- &mat[12], &mat[13], &mat[14], &mat[15] );
- */
- dSscanf( data, "%g %g %g %g %g %g %g", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z );
- MatrixF surface;
- quat.setMatrix( &surface );
- surface.setPosition( pos );
- shape->mSurfaces.push_back( surface );
- return false;
- }
- ConvexShape::ConvexShape()
- : mMaterialName( "Grid512_OrangeLines_Mat" ),
- mMaterialInst( NULL ),
- mVertCount( 0 ),
- mPrimCount( 0 ),
- mPhysicsRep( NULL ),
- mNormalLength( 0.3f )
- {
- mNetFlags.set( Ghostable | ScopeAlways );
-
- mTypeMask |= StaticObjectType |
- StaticShapeObjectType;
- mConvexList = new Convex;
- }
- ConvexShape::~ConvexShape()
- {
- if ( mMaterialInst )
- SAFE_DELETE( mMaterialInst );
- delete mConvexList;
- mConvexList = NULL;
- }
- void ConvexShape::initPersistFields()
- {
- addGroup( "Rendering" );
- addField( "material", TypeMaterialName, Offset( mMaterialName, ConvexShape ), "Material used to render the ConvexShape surface." );
- endGroup( "Rendering" );
- addGroup( "Internal" );
- addProtectedField( "surface", TypeRealString, NULL, &protectedSetSurface, &defaultProtectedGetFn,
- "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
- endGroup( "Internal" );
- Parent::initPersistFields();
- }
- void ConvexShape::inspectPostApply()
- {
- Parent::inspectPostApply();
- _updateGeometry( true );
- setMaskBits( UpdateMask );
- }
- bool ConvexShape::onAdd()
- {
- if ( !Parent::onAdd() )
- return false;
-
- //mObjBox.set( -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f );
- //resetWorldBox();
- // Face Order:
- // Top, Bottom, Front, Back, Left, Right
- // X Axis
- static const Point3F cubeTangents[6] =
- {
- Point3F( 1, 0, 0 ),
- Point3F(-1, 0, 0 ),
- Point3F( 1, 0, 0 ),
- Point3F(-1, 0, 0 ),
- Point3F( 0, 1, 0 ),
- Point3F( 0, -1, 0 )
- };
- // Y Axis
- static const Point3F cubeBinormals[6] =
- {
- Point3F( 0, 1, 0 ),
- Point3F( 0, 1, 0 ),
- Point3F( 0, 0, -1 ),
- Point3F( 0, 0, -1 ),
- Point3F( 0, 0, -1 ),
- Point3F( 0, 0, -1 )
- };
- // Z Axis
- static const Point3F cubeNormals[6] =
- {
- Point3F( 0, 0, 1),
- Point3F( 0, 0, -1),
- Point3F( 0, 1, 0),
- Point3F( 0, -1, 0),
- Point3F(-1, 0, 0),
- Point3F( 1, 0, 0),
- };
- if ( mSurfaces.empty() )
- {
- for ( S32 i = 0; i < 6; i++ )
- {
- mSurfaces.increment();
- MatrixF &surf = mSurfaces.last();
- surf.identity();
-
- surf.setColumn( 0, cubeTangents[i] );
- surf.setColumn( 1, cubeBinormals[i] );
- surf.setColumn( 2, cubeNormals[i] );
- surf.setPosition( cubeNormals[i] * 0.5f );
- }
- }
- if ( isClientObject() )
- _updateMaterial();
-
- _updateGeometry( true );
- addToScene();
- return true;
- }
- void ConvexShape::onRemove()
- {
- removeFromScene();
- mConvexList->nukeList();
- SAFE_DELETE( mPhysicsRep );
- Parent::onRemove();
- }
- void ConvexShape::writeFields( Stream &stream, U32 tabStop )
- {
- Parent::writeFields( stream, tabStop );
- // Now write all planes.
- stream.write(2, "\r\n");
- S32 count = mSurfaces.size();
- if ( count > smMaxSurfaces )
- {
- Con::errorf( "ConvexShape has too many surfaces to save! Truncated value %d to maximum value of %d", count, smMaxSurfaces );
- count = smMaxSurfaces;
- }
- for ( U32 i = 0; i < count; i++ )
- {
- const MatrixF &mat = mSurfaces[i];
- QuatF quat( mat );
- Point3F pos( mat.getPosition() );
- stream.writeTabs(tabStop);
- char buffer[1024];
- dMemset( buffer, 0, 1024 );
-
- dSprintf( buffer, 1024, "surface = \"%g %g %g %g %g %g %g\";",
- quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z );
- stream.writeLine( (const U8*)buffer );
- }
- }
- bool ConvexShape::writeField( StringTableEntry fieldname, const char *value )
- {
- if ( fieldname == StringTable->insert("surface") )
- return false;
- return Parent::writeField( fieldname, value );
- }
- void ConvexShape::onScaleChanged()
- {
- if ( isProperlyAdded() )
- _updateCollision();
- }
- void ConvexShape::setTransform( const MatrixF &mat )
- {
- Parent::setTransform( mat );
- if ( mPhysicsRep )
- mPhysicsRep->setTransform( mat );
-
- setMaskBits( TransformMask );
- }
- U32 ConvexShape::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
- {
- U32 retMask = Parent::packUpdate( conn, mask, stream );
-
- if ( stream->writeFlag( mask & TransformMask ) )
- {
- mathWrite(*stream, getTransform());
- mathWrite(*stream, getScale());
- }
- if ( stream->writeFlag( mask & UpdateMask ) )
- {
- stream->write( mMaterialName );
-
- U32 surfCount = mSurfaces.size();
- stream->writeInt( surfCount, 32 );
- for ( S32 i = 0; i < surfCount; i++ )
- {
- QuatF quat( mSurfaces[i] );
- Point3F pos( mSurfaces[i].getPosition() );
- mathWrite( *stream, quat );
- mathWrite( *stream, pos );
- }
- }
- return retMask;
- }
- void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream )
- {
- Parent::unpackUpdate( conn, stream );
- if ( stream->readFlag() ) // TransformMask
- {
- mathRead(*stream, &mObjToWorld);
- mathRead(*stream, &mObjScale);
- setTransform( mObjToWorld );
- setScale( mObjScale );
- }
- if ( stream->readFlag() ) // UpdateMask
- {
- stream->read( &mMaterialName );
- if ( isProperlyAdded() )
- _updateMaterial();
- mSurfaces.clear();
- const U32 surfCount = stream->readInt( 32 );
- for ( S32 i = 0; i < surfCount; i++ )
- {
- mSurfaces.increment();
- MatrixF &mat = mSurfaces.last();
- QuatF quat;
- Point3F pos;
- mathRead( *stream, &quat );
- mathRead( *stream, &pos );
- quat.setMatrix( &mat );
- mat.setPosition( pos );
- }
- if ( isProperlyAdded() )
- _updateGeometry( true );
- }
- }
- void ConvexShape::prepRenderImage( SceneRenderState *state )
- {
- if ( state->isDiffusePass() )
- {
- ObjectRenderInst *ri2 = state->getRenderPass()->allocInst<ObjectRenderInst>();
- ri2->renderDelegate.bind( this, &ConvexShape::_renderDebug );
- ri2->type = RenderPassManager::RIT_Editor;
- state->getRenderPass()->addInst( ri2 );
- }
-
- if ( mVertexBuffer.isNull() || !state)
- return;
- // If we don't have a material instance after the override then
- // we can skip rendering all together.
- BaseMatInstance *matInst = state->getOverrideMaterial( mMaterialInst ? mMaterialInst : MATMGR->getWarningMatInstance() );
- if ( !matInst )
- return;
- // Get a handy pointer to our RenderPassmanager
- RenderPassManager *renderPass = state->getRenderPass();
- // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager
- MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
- // Set our RenderInst as a standard mesh render
- ri->type = RenderPassManager::RIT_Mesh;
- // Calculate our sorting point
- if ( state )
- {
- // Calculate our sort point manually.
- const Box3F& rBox = getRenderWorldBox();
- ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() );
- }
- else
- ri->sortDistSq = 0.0f;
- // Set up our transforms
- MatrixF objectToWorld = getRenderTransform();
- objectToWorld.scale( getScale() );
- ri->objectToWorld = renderPass->allocUniqueXform( objectToWorld );
- ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
- ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection);
- // If we need lights then set them up.
- if ( matInst->isForwardLit() )
- {
- LightQuery query;
- query.init( getWorldSphere() );
- query.getLights( ri->lights, 8 );
- }
- // Make sure we have an up-to-date backbuffer in case
- // our Material would like to make use of it
- // NOTICE: SFXBB is removed and refraction is disabled!
- //ri->backBuffTex = GFX->getSfxBackBuffer();
- // Set our Material
- ri->matInst = matInst;
- if ( matInst->getMaterial()->isTranslucent() )
- {
- ri->translucentSort = true;
- ri->type = RenderPassManager::RIT_Translucent;
- }
- // Set up our vertex buffer and primitive buffer
- ri->vertBuff = &mVertexBuffer;
- ri->primBuff = &mPrimitiveBuffer;
- ri->prim = renderPass->allocPrim();
- ri->prim->type = GFXTriangleList;
- ri->prim->minIndex = 0;
- ri->prim->startIndex = 0;
- ri->prim->numPrimitives = mPrimCount;
- ri->prim->startVertex = 0;
- ri->prim->numVertices = mVertCount;
- // We sort by the material then vertex buffer.
- ri->defaultKey = matInst->getStateHint();
- ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
- // Submit our RenderInst to the RenderPassManager
- state->getRenderPass()->addInst( ri );
- }
- void ConvexShape::buildConvex( const Box3F &box, Convex *convex )
- {
- if ( mGeometry.faces.empty() )
- return;
- mConvexList->collectGarbage();
- Box3F realBox = box;
- mWorldToObj.mul( realBox );
- realBox.minExtents.convolveInverse( mObjScale );
- realBox.maxExtents.convolveInverse( mObjScale );
- if ( realBox.isOverlapped( getObjBox() ) == false )
- return;
- // See if this convex exists in the working set already...
- Convex *cc = 0;
- CollisionWorkingList &wl = convex->getWorkingList();
- for ( CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext )
- {
- if ( itr->mConvex->getType() == ConvexShapeCollisionConvexType )
- {
- ConvexShapeCollisionConvex *pConvex = static_cast<ConvexShapeCollisionConvex*>(itr->mConvex);
- if ( pConvex->pShape == this )
- {
- cc = itr->mConvex;
- return;
- }
- }
- }
- // Set up the convex...
- ConvexShapeCollisionConvex *cp = new ConvexShapeCollisionConvex();
- mConvexList->registerObject( cp );
- convex->addToWorkingList( cp );
- cp->mObject = this;
- cp->pShape = this;
- }
- bool ConvexShape::buildPolyList( PolyListContext context, AbstractPolyList *plist, const Box3F &box, const SphereF &sphere )
- {
- if ( mGeometry.points.empty() )
- return false;
- // If we're exporting deal with that first.
- if ( context == PLC_Export )
- {
- AssertFatal( dynamic_cast<OptimizedPolyList*>( plist ), "ConvexShape::buildPolyList - Bad polylist for export!" );
- _export( (OptimizedPolyList*)plist, box, sphere );
- return true;
- }
- plist->setTransform( &mObjToWorld, mObjScale );
- plist->setObject( this );
- // Add points...
- const Vector< Point3F > pointList = mGeometry.points;
- S32 base = plist->addPoint( pointList[0] );
- for ( S32 i = 1; i < pointList.size(); i++ )
- plist->addPoint( pointList[i] );
- // Add Surfaces...
- const Vector< ConvexShape::Face > faceList = mGeometry.faces;
- if(context == PLC_Navigation)
- {
- for(S32 i = 0; i < faceList.size(); i++)
- {
- const ConvexShape::Face &face = faceList[i];
- S32 s = face.triangles.size();
- for(S32 j = 0; j < s; j++)
- {
- plist->begin(0, s*i + j);
- plist->plane(PlaneF(face.centroid, face.normal));
- plist->vertex(base + face.points[face.triangles[j].p0]);
- plist->vertex(base + face.points[face.triangles[j].p1]);
- plist->vertex(base + face.points[face.triangles[j].p2]);
- plist->end();
- }
- }
- return true;
- }
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- const ConvexShape::Face &face = faceList[i];
- plist->begin( 0, i );
- plist->plane( PlaneF( face.centroid, face.normal ) );
- for ( S32 j = 0; j < face.triangles.size(); j++ )
- {
- plist->vertex( base + face.points[ face.triangles[j].p0 ] );
- plist->vertex( base + face.points[ face.triangles[j].p1 ] );
- plist->vertex( base + face.points[ face.triangles[j].p2 ] );
- }
- plist->end();
- }
- return true;
- }
- bool ConvexShape::buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F &box, const SphereF &)
- {
- if (mGeometry.points.empty())
- return false;
- //Get the collision mesh geometry
- {
- ColladaUtils::ExportData::colMesh* colMesh;
- exportData->colMeshes.increment();
- colMesh = &exportData->colMeshes.last();
- colMesh->mesh.setTransform(&mObjToWorld, mObjScale);
- colMesh->mesh.setObject(this);
- //Just get the visible
- buildPolyList(PLC_Export, &colMesh->mesh, getWorldBox(), getWorldSphere());
- colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size());
- }
- //Next, process the geometry and materials.
- //Convex shapes only have the one 'level', so we'll just rely on the export post-process to back-fill
- if (isServerObject() && getClientObject())
- {
- exportData->meshData.increment();
- //Prep a meshData for this shape in particular
- ColladaUtils::ExportData::meshLODData* meshData = &exportData->meshData.last();
- //Fill out the info we'll need later to actually append our mesh data for the detail levels during the processing phase
- meshData->shapeInst = nullptr;
- meshData->originatingObject = this;
- meshData->meshTransform = mObjToWorld;
- meshData->scale = mObjScale;
- meshData->meshDetailLevels.increment();
- ColladaUtils::ExportData::detailLevel* curDetail = &meshData->meshDetailLevels.last();
- //Make sure we denote the size this detail level has
- curDetail->size = 512;
- }
- return true;
- }
- void ConvexShape::_export( OptimizedPolyList *plist, const Box3F &box, const SphereF &sphere )
- {
- BaseMatInstance *matInst = mMaterialInst;
- if ( isServerObject() && getClientObject() )
- matInst = dynamic_cast<ConvexShape*>(getClientObject())->mMaterialInst;
-
- MatrixF saveMat;
- Point3F saveScale;
- plist->getTransform( &saveMat, &saveScale );
- plist->setTransform( &mObjToWorld, mObjScale );
- plist->setObject( this );
- const Vector< ConvexShape::Face > faceList = mGeometry.faces;
- const Vector< Point3F > &pointList = mGeometry.points;
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- const ConvexShape::Face &face = faceList[i];
- plist->begin( matInst, i, OptimizedPolyList::TriangleList );
- plist->plane( PlaneF( face.centroid, face.normal ) );
- for ( S32 j = 0; j < face.triangles.size(); j++ )
- {
- for ( S32 k = 0; k < 3; k++ )
- {
- U32 vertId = face.triangles[j][k];
- plist->vertex( pointList[ face.points[ vertId ] ], face.normal, face.texcoords[ vertId ] );
- }
- }
- plist->end();
- }
- plist->setTransform( &saveMat, saveScale );
- }
- bool ConvexShape::castRay( const Point3F &start, const Point3F &end, RayInfo *info )
- {
- if ( mPlanes.empty() )
- return false;
- const Vector< PlaneF > &planeList = mPlanes;
- const U32 planeCount = planeList.size();
- F32 t;
- F32 tmin = F32_MAX;
- S32 hitFace = -1;
- Point3F pnt;
- VectorF rayDir( end - start );
- rayDir.normalizeSafe();
-
- for ( S32 i = 0; i < planeCount; i++ )
- {
- // Don't hit the back-side of planes.
- if ( mDot( rayDir, planeList[i] ) >= 0.0f )
- continue;
- t = planeList[i].intersect( start, end );
- if ( t >= 0.0f && t <= 1.0f && t < tmin )
- {
- pnt.interpolate( start, end, t );
- S32 j = 0;
- for ( ; j < planeCount; j++ )
- {
- if ( i == j )
- continue;
- F32 dist = planeList[j].distToPlane( pnt );
- if ( dist > 1.0e-004f )
- break;
- }
- if ( j == planeCount )
- {
- tmin = t;
- hitFace = i;
- }
- }
- }
- if ( hitFace == -1 )
- return false;
- info->face = hitFace;
- info->material = mMaterialInst;
- info->normal = planeList[ hitFace ];
- info->object = this;
- info->t = tmin;
- //mObjToWorld.mulV( info->normal );
- return true;
- }
- bool ConvexShape::collideBox( const Point3F &start, const Point3F &end, RayInfo *info )
- {
- return Parent::collideBox( start, end, info );
- }
- void ConvexShape::updateBounds( bool recenter )
- {
- if ( mGeometry.points.size() == 0 )
- return;
- Vector<Point3F> &pointListOS = mGeometry.points;
- U32 pointCount = pointListOS.size();
- Point3F volumnCenter( 0,0,0 );
- F32 areaSum = 0.0f;
- F32 faceCount = mGeometry.faces.size();
- for ( S32 i = 0; i < faceCount; i++ )
- {
- volumnCenter += mGeometry.faces[i].centroid * mGeometry.faces[i].area;
- areaSum += mGeometry.faces[i].area;
- }
- if ( areaSum == 0.0f )
- return;
- volumnCenter /= areaSum;
-
- mObjBox.minExtents = mObjBox.maxExtents = Point3F::Zero;
- mObjBox.setCenter( volumnCenter );
- for ( S32 i = 0; i < pointCount; i++ )
- mObjBox.extend( pointListOS[i] );
- resetWorldBox();
- }
- void ConvexShape::recenter()
- {
- if ( mGeometry.points.size() == 0 )
- return;
-
- Point3F volCenterOS( 0,0,0 );
- F32 areaSum = 0.0f;
- F32 faceCount = mGeometry.faces.size();
- for ( S32 i = 0; i < faceCount; i++ )
- {
- volCenterOS += mGeometry.faces[i].centroid * mGeometry.faces[i].area;
- areaSum += mGeometry.faces[i].area;
- }
- volCenterOS /= areaSum;
- for ( S32 i = 0; i < mSurfaces.size(); i++ )
- mSurfaces[i].setPosition( mSurfaces[i].getPosition() - volCenterOS );
-
- Point3F volCenterWS;
- MatrixF objToWorld( mObjToWorld );
- objToWorld.scale( mObjScale );
- objToWorld.mulP( volCenterOS, &volCenterWS );
- setPosition( volCenterWS );
- _updateGeometry(true);
- }
- MatrixF ConvexShape::getSurfaceWorldMat( S32 surfId, bool scaled ) const
- {
- if ( surfId < 0 || surfId >= mSurfaces.size() )
- return MatrixF::Identity;
- MatrixF objToWorld( mObjToWorld );
- if ( scaled )
- objToWorld.scale( mObjScale );
- MatrixF surfMat;
- surfMat.mul( objToWorld, mSurfaces[surfId] );
- return surfMat;
- }
- // Used in cullEmptyPlanes.
- S32 QSORT_CALLBACK sortDescendingU32( const void *a, const void *b )
- {
- U32 *aa = (U32*)(a);
- U32 *bb = (U32*)(b);
- return (S32)(*bb) - (S32)(*aa);
- }
- void ConvexShape::cullEmptyPlanes( Vector< U32 > *removedPlanes )
- {
- //if ( mPlanes.size() == mGeometry.faces.size() )
- // return;
- removedPlanes->clear();
- const U32 startPlaneCount = mPlanes.size();
- const Vector< ConvexShape::Face > &faceList = mGeometry.faces;
- const U32 faceCount = faceList.size();
- S32 *used = new S32[ startPlaneCount ];
- for ( S32 i = 0; i < startPlaneCount; i++ )
- used[i] = i;
- for ( S32 i = 0; i < faceCount; i++ )
- {
- if ( faceList[i].area > 0.001f )
- used[ faceList[i].id ] = -1;
- }
- for ( S32 i = 0; i < startPlaneCount; i++ )
- {
- if ( used[i] != -1 )
- removedPlanes->push_back( used[i] );
- }
-
- dQsort( removedPlanes->address(), removedPlanes->size(), sizeof( U32 ), sortDescendingU32 );
- for ( S32 i = 0; i < removedPlanes->size(); i++ )
- {
- mPlanes.erase( (*removedPlanes)[i] );
- mSurfaces.erase( (*removedPlanes)[i] );
- }
- delete [] used;
- }
- void ConvexShape::exportToCollada()
- {
- if ( mSurfaces.size() == 0 )
- {
- Con::errorf( "ConvexShape::exportToCollada() - has no surfaces to export!" );
- return;
- }
- }
- void ConvexShape::resizePlanes( const Point3F &size )
- {
- //Point3F nSize;
- //mWorldToObj.mulV( nSize );
- for ( S32 i = 0; i < mSurfaces.size(); i++ )
- {
- MatrixF objToPlane( mSurfaces[i] );
- objToPlane.inverse();
- Point3F lim;
- objToPlane.mulV( size, &lim );
- F32 sign = ( mPlanes[i].d > 0.0f ) ? 1.0f : -1.0f;
- mPlanes[i].d = mFabs(lim.z) * 0.5f * sign;
-
- //mPlanes[i].d = -lim.z * 0.5f;
- mSurfaces[i].setPosition( mPlanes[i].getPosition() );
- }
- }
- void ConvexShape::getSurfaceLineList( S32 surfId, Vector< Point3F > &lineList )
- {
- if ( surfId < 0 || surfId > mSurfaces.size() - 1 )
- return;
- S32 faceId = -1;
- for ( S32 i = 0; i < mGeometry.faces.size(); i++ )
- {
- if ( mGeometry.faces[i].id == surfId )
- {
- faceId = i;
- break;
- }
- }
- if ( faceId == -1 )
- return;
- ConvexShape::Face &face = mGeometry.faces[faceId];
- const Vector< Point3F > &pointList = mGeometry.points;
- if ( pointList.size() == 0 )
- return;
- for ( S32 i = 0; i < face.winding.size(); i++ )
- lineList.push_back( pointList[ face.points[ face.winding[i] ] ] );
-
- lineList.push_back( pointList[ face.points[ face.winding.first() ] ] );
- }
- void ConvexShape::_updateMaterial()
- {
- // If the material name matches then don't bother updating it.
- if ( mMaterialInst && mMaterialName.equal( mMaterialInst->getMaterial()->getName(), String::NoCase ) )
- return;
- SAFE_DELETE( mMaterialInst );
- Material *material;
-
- if ( !Sim::findObject( mMaterialName, material ) )
- Sim::findObject( "WarningMaterial", material );
- mMaterialInst = material->createMatInstance();
- //GFXStateBlockDesc desc;
- //desc.setCullMode( GFXCullNone );
- //desc.setBlend( false );
- //mMaterialInst->addStateBlockDesc( desc );
- FeatureSet features = MATMGR->getDefaultFeatures();
- //features.addFeature( MFT_DiffuseVertColor );
- mMaterialInst->init( features, getGFXVertexFormat<VertexType>() );
- if ( !mMaterialInst->isValid() )
- {
- SAFE_DELETE( mMaterialInst );
- }
- }
- void ConvexShape::_updateGeometry( bool updateCollision )
- {
- mPlanes.clear();
- for ( S32 i = 0; i < mSurfaces.size(); i++ )
- mPlanes.push_back( PlaneF( mSurfaces[i].getPosition(), mSurfaces[i].getUpVector() ) );
- Vector< Point3F > tangents;
- for ( S32 i = 0; i < mSurfaces.size(); i++ )
- tangents.push_back( mSurfaces[i].getRightVector() );
-
- mGeometry.generate( mPlanes, tangents );
- AssertFatal( mGeometry.faces.size() <= mSurfaces.size(), "Got more faces than planes?" );
- const Vector< ConvexShape::Face > &faceList = mGeometry.faces;
- const Vector< Point3F > &pointList = mGeometry.points;
- // Reset our surface center points.
- for ( S32 i = 0; i < faceList.size(); i++ )
- mSurfaces[ faceList[i].id ].setPosition( faceList[i].centroid );
- mPlanes.clear();
- for ( S32 i = 0; i < mSurfaces.size(); i++ )
- mPlanes.push_back( PlaneF( mSurfaces[i].getPosition(), mSurfaces[i].getUpVector() ) );
- // Update bounding box.
- updateBounds( false );
- mVertexBuffer = NULL;
- mPrimitiveBuffer = NULL;
- mVertCount = 0;
- mPrimCount = 0;
- if ( updateCollision )
- _updateCollision();
- // Server does not need to generate vertex/prim buffers.
- if ( isServerObject() )
- return;
- if ( faceList.empty() )
- return;
- // Get total vert and prim count.
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- U32 count = faceList[i].triangles.size();
- mPrimCount += count;
- mVertCount += count * 3;
- }
- // Allocate VB and copy in data.
- mVertexBuffer.set( GFX, mVertCount, GFXBufferTypeStatic );
- VertexType *pVert = mVertexBuffer.lock();
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- const ConvexShape::Face &face = faceList[i];
- const Vector< U32 > &facePntMap = face.points;
- const Vector< ConvexShape::Triangle > &triangles = face.triangles;
- const ColorI &faceColor = sgConvexFaceColors[ i % sgConvexFaceColorCount ];
- for ( S32 j = 0; j < triangles.size(); j++ )
- {
- for ( S32 k = 0; k < 3; k++ )
- {
- pVert->normal = face.normal;
- pVert->tangent = face.tangent;
- pVert->color = faceColor;
- pVert->point = pointList[ facePntMap[ triangles[j][k] ] ];
- pVert->texCoord = face.texcoords[ triangles[j][k] ];
- pVert++;
- }
- }
- }
- mVertexBuffer.unlock();
- // Allocate PB
- mPrimitiveBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic );
- U16 *pIndex;
- mPrimitiveBuffer.lock( &pIndex );
- for ( U16 i = 0; i < mPrimCount * 3; i++ )
- {
- *pIndex = i;
- pIndex++;
- }
- mPrimitiveBuffer.unlock();
- }
- void ConvexShape::_updateCollision()
- {
- SAFE_DELETE( mPhysicsRep );
- if ( !PHYSICSMGR )
- return;
- PhysicsCollision *colShape = PHYSICSMGR->createCollision();
- // We need the points untransformed!
- Vector<Point3F> rawPoints;
- MatrixF xfm( getWorldTransform() );
- xfm.setPosition( Point3F::Zero );
- for ( U32 i=0; i < mGeometry.points.size(); i++ )
- {
- Point3F p = mGeometry.points[i];
- xfm.mulP( p );
- rawPoints.push_back( p );
- }
- // The convex generation from a point cloud
- // can fail at times... give up in that case.
- if ( !colShape->addConvex( mGeometry.points.address(),
- mGeometry.points.size(),
- MatrixF::Identity ) )
- {
- delete colShape;
- return;
- }
- PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
- mPhysicsRep = PHYSICSMGR->createBody();
- mPhysicsRep->init( colShape, 0, 0, this, world );
- mPhysicsRep->setTransform( getTransform() );
- }
- void ConvexShape::_renderDebug( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mat )
- {
- GFXDrawUtil *drawer = GFX->getDrawUtil();
- GFX->setTexture( 0, NULL );
- // Render world box.
- if (Con::getBoolVariable("$pref::convexDBG::ShowWorldBox", false))
- {
- Box3F wbox( mWorldBox );
- if ( getServerObject() )
- wbox = static_cast<ConvexShape*>( getServerObject() )->mWorldBox;
- GFXStateBlockDesc desc;
- desc.setCullMode( GFXCullNone );
- desc.setFillModeWireframe();
- drawer->drawCube( desc, wbox, ColorI::RED );
- }
- const Vector< Point3F > &pointList = mGeometry.points;
- const Vector< ConvexShape::Face > &faceList = mGeometry.faces;
- // Render Edges.
- if (Con::getBoolVariable("$pref::convexDBG::ShowEdges", false))
- {
- GFXTransformSaver saver;
- //GFXFrustumSaver fsaver;
- MatrixF xfm( getRenderTransform() );
- xfm.scale( getScale() );
- GFX->multWorld( xfm );
- GFXStateBlockDesc desc;
- desc.setZReadWrite( true, false );
- desc.setBlend( true );
- GFX->setStateBlockByDesc( desc );
- //MathUtils::getZBiasProjectionMatrix( 0.01f, state->getFrustum(), )
- const Point3F &camFvec = state->getCameraTransform().getForwardVector();
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- const ConvexShape::Face &face = faceList[i];
-
- const Vector< ConvexShape::Edge > &edgeList = face.edges;
- const Vector< U32 > &facePntList = face.points;
- PrimBuild::begin( GFXLineList, edgeList.size() * 2 );
-
- PrimBuild::color( LinearColorF(ColorI::WHITE) * 0.8f );
- for ( S32 j = 0; j < edgeList.size(); j++ )
- {
- PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p0 ] ] - camFvec * 0.001f );
- PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p1 ] ] - camFvec * 0.001f );
- }
-
- PrimBuild::end();
- }
- }
- ColorI faceColorsx[4] =
- {
- ColorI( 255, 0, 0 ),
- ColorI( 0, 255, 0 ),
- ColorI( 0, 0, 255 ),
- ColorI( 255, 0, 255 )
- };
- MatrixF objToWorld( mObjToWorld );
- objToWorld.scale( mObjScale );
- // Render faces centers/colors.
- if (Con::getBoolVariable("$pref::convexDBG::ShowFaceColors", false))
- {
- GFXStateBlockDesc desc;
- desc.setCullMode( GFXCullNone );
-
- Point3F size( 0.1f );
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- ColorI color = faceColorsx[ i % 4 ];
- LinearColorF tCol = LinearColorF(color);
- S32 div = ( i / 4 ) * 4;
- if ( div > 0 )
- tCol /= div;
- tCol.alpha = 1;
- color = tCol.toColorI();
- Point3F pnt;
- objToWorld.mulP( faceList[i].centroid, &pnt );
- drawer->drawCube( desc, size, pnt, color, NULL );
- }
- }
- // Render winding order.
- if (Con::getBoolVariable("$pref::convexDBG::ShowWinding", false))
- {
- GFXStateBlockDesc desc;
- desc.setCullMode( GFXCullNone );
- desc.setZReadWrite( true, false );
- GFX->setStateBlockByDesc( desc );
- U32 pointCount = 0;
- for ( S32 i = 0; i < faceList.size(); i++ )
- pointCount += faceList[i].winding.size();
- PrimBuild::begin( GFXLineList, pointCount * 2 );
-
- for ( S32 i = 0; i < faceList.size(); i++ )
- {
- for ( S32 j = 0; j < faceList[i].winding.size(); j++ )
- {
- Point3F p0 = pointList[ faceList[i].points[ faceList[i].winding[j] ] ];
- Point3F p1 = p0 + mSurfaces[ faceList[i].id ].getUpVector() * 0.75f * ( Point3F::One / mObjScale );
- objToWorld.mulP( p0 );
- objToWorld.mulP( p1 );
- ColorI color = faceColorsx[j % 4];
- LinearColorF tCol = LinearColorF(color);
- S32 div = (j / 4) * 4;
- if (div > 0)
- tCol /= div;
- tCol.alpha = 1;
- color = tCol.toColorI();
-
- PrimBuild::color( color );
- PrimBuild::vertex3fv( p0 );
- PrimBuild::color( color );
- PrimBuild::vertex3fv( p1 );
- }
- }
- PrimBuild::end();
- }
- // Render Points.
- if ( false )
- {
- /*
- GFXTransformSaver saver;
- MatrixF xfm( getRenderTransform() );
- xfm.scale( getScale() );
- GFX->multWorld( xfm );
- GFXStateBlockDesc desc;
- Point3F size( 0.05f );
- */
- }
- // Render surface transforms.
- if (Con::getBoolVariable("$pref::convexDBG::ShowSurfaceTransforms", false))
- {
- GFXStateBlockDesc desc;
- desc.setBlend( false );
- desc.setZReadWrite( true, true );
- Point3F scale(mNormalLength);
- for ( S32 i = 0; i < mSurfaces.size(); i++ )
- {
- objToWorld = mObjToWorld;
- objToWorld.scale( mObjScale );
- MatrixF renderMat;
- renderMat.mul( objToWorld, mSurfaces[i] );
- renderMat.setPosition( renderMat.getPosition() + renderMat.getUpVector() * 0.001f );
-
- drawer->drawTransform( desc, renderMat, &scale, NULL );
- }
- }
- }
- void ConvexShape::renderFaceEdges( S32 faceid, const ColorI &color /*= ColorI::WHITE*/, F32 lineWidth /*= 1.0f */ )
- {
- const Vector< ConvexShape::Face > &faceList = mGeometry.faces;
- if ( faceid >= faceList.size() )
- return;
- GFXTransformSaver saver;
- MatrixF xfm( mObjToWorld );
- xfm.scale( mObjScale );
- GFX->multWorld( xfm );
- GFXStateBlockDesc desc;
- desc.setBlend( true );
- GFX->setStateBlockByDesc( desc );
- MatrixF projBias(true);
- const Frustum& frustum = GFX->getFrustum();
- MathUtils::getZBiasProjectionMatrix( 0.001f, frustum, &projBias );
- GFX->setProjectionMatrix( projBias );
- S32 s = faceid;
- S32 e = faceid + 1;
- if ( faceid == -1 )
- {
- s = 0;
- e = faceList.size();
- }
- for ( S32 i = s; i < e; i++ )
- {
- const ConvexShape::Face &face = faceList[i];
- const Vector< ConvexShape::Edge > &edgeList = face.edges;
- const Vector< U32 > &facePntList = face.points;
- const Vector< Point3F > &pointList = mGeometry.points;
- PrimBuild::begin( GFXLineList, edgeList.size() * 2 );
- PrimBuild::color( color );
- for ( S32 j = 0; j < edgeList.size(); j++ )
- {
- PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p0 ] ] );
- PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p1 ] ] );
- }
- PrimBuild::end();
- }
- }
- void ConvexShape::getSurfaceTriangles( S32 surfId, Vector< Point3F > *outPoints, Vector< Point2F > *outCoords, bool worldSpace )
- {
- S32 faceId = -1;
- for ( S32 i = 0; i < mGeometry.faces.size(); i++ )
- {
- if ( mGeometry.faces[i].id == surfId )
- {
- faceId = i;
- break;
- }
- }
- if ( faceId == -1 )
- return;
- const ConvexShape::Face &face = mGeometry.faces[ faceId ];
- const Vector< Point3F > &pointList = mGeometry.points;
- const MatrixF &surfToObj = mSurfaces[ faceId ];
- MatrixF objToSurf( surfToObj );
- objToSurf.inverse();
- Point3F surfScale( 1.5f, 1.5f, 1.0f );
- for ( S32 i = 0; i < face.triangles.size(); i++ )
- {
- for ( S32 j = 0; j < 3; j++ )
- {
- Point3F pnt( pointList[ face.points[ face.triangles[i][j] ] ] );
-
- objToSurf.mulP( pnt );
- pnt *= surfScale;
- surfToObj.mulP( pnt );
- outPoints->push_back( pnt );
- if ( outCoords )
- outCoords->push_back( face.texcoords[ face.triangles[i][j] ] );
- }
- }
- if ( worldSpace )
- {
- MatrixF objToWorld( mObjToWorld );
- objToWorld.scale( mObjScale );
- for ( S32 i = 0; i < outPoints->size(); i++ )
- objToWorld.mulP( (*outPoints)[i] );
- }
- }
- void ConvexShape::Geometry::generate( const Vector< PlaneF > &planes, const Vector< Point3F > &tangents )
- {
- PROFILE_SCOPE( Geometry_generate );
- points.clear();
- faces.clear();
- AssertFatal( planes.size() == tangents.size(), "ConvexShape - incorrect plane/tangent count." );
- #ifdef TORQUE_ENABLE_ASSERTS
- for ( S32 i = 0; i < planes.size(); i++ )
- {
- F32 dt = mDot( planes[i], tangents[i] );
- AssertFatal( mIsZero( dt, 0.0001f ), "ConvexShape - non perpendicular input vectors." );
- AssertFatal( planes[i].isUnitLength() && tangents[i].isUnitLength(), "ConvexShape - non unit length input vector." );
- }
- #endif
- const U32 planeCount = planes.size();
- Point3F linePt, lineDir;
- for ( S32 i = 0; i < planeCount; i++ )
- {
- Vector< MathUtils::Line > collideLines;
- // Find the lines defined by the intersection of this plane with all others.
- for ( S32 j = 0; j < planeCount; j++ )
- {
- if ( i == j )
- continue;
- if ( planes[i].intersect( planes[j], linePt, lineDir ) )
- {
- collideLines.increment();
- MathUtils::Line &line = collideLines.last();
- line.origin = linePt;
- line.direction = lineDir;
- }
- }
- if ( collideLines.empty() )
- continue;
- // Find edges and points defined by the intersection of these lines.
- // As we find them we fill them into our working ConvexShape::Face
- // structure.
-
- Face newFace;
- for ( S32 j = 0; j < collideLines.size(); j++ )
- {
- Vector< Point3F > collidePoints;
- for ( S32 k = 0; k < collideLines.size(); k++ )
- {
- if ( j == k )
- continue;
- MathUtils::LineSegment segment;
- MathUtils::mShortestSegmentBetweenLines( collideLines[j], collideLines[k], &segment );
- F32 dist = ( segment.p0 - segment.p1 ).len();
- if ( dist < 0.0005f )
- {
- S32 l = 0;
- for ( ; l < planeCount; l++ )
- {
- if ( planes[l].whichSide( segment.p0 ) == PlaneF::Front )
- break;
- }
- if ( l == planeCount )
- collidePoints.push_back( segment.p0 );
- }
- }
- //AssertFatal( collidePoints.size() <= 2, "A line can't collide with more than 2 other lines in a convex shape..." );
- if ( collidePoints.size() != 2 )
- continue;
- // Push back collision points into our points vector
- // if they are not duplicates and determine the id
- // index for those points to be used by Edge(s).
- const Point3F &pnt0 = collidePoints[0];
- const Point3F &pnt1 = collidePoints[1];
- S32 idx0 = -1;
- S32 idx1 = -1;
- for ( S32 k = 0; k < points.size(); k++ )
- {
- if ( pnt0.equal( points[k] ) )
- {
- idx0 = k;
- break;
- }
- }
- for ( S32 k = 0; k < points.size(); k++ )
- {
- if ( pnt1.equal( points[k] ) )
- {
- idx1 = k;
- break;
- }
- }
- if ( idx0 == -1 )
- {
- points.push_back( pnt0 );
- idx0 = points.size() - 1;
- }
- if ( idx1 == -1 )
- {
- points.push_back( pnt1 );
- idx1 = points.size() - 1;
- }
- // Construct the Face::Edge defined by this collision.
- S32 localIdx0 = newFace.points.push_back_unique( idx0 );
- S32 localIdx1 = newFace.points.push_back_unique( idx1 );
- newFace.edges.increment();
- ConvexShape::Edge &newEdge = newFace.edges.last();
- newEdge.p0 = localIdx0;
- newEdge.p1 = localIdx1;
- }
- if ( newFace.points.size() < 3 )
- continue;
- //AssertFatal( newFace.points.size() == newFace.edges.size(), "ConvexShape - face point count does not equal edge count." );
- // Fill in some basic Face information.
- newFace.id = i;
- newFace.normal = planes[i];
- newFace.tangent = tangents[i];
- // Make a working array of Point3Fs on this face.
- U32 pntCount = newFace.points.size();
- Point3F *workPoints = new Point3F[ pntCount ];
- for ( S32 j = 0; j < pntCount; j++ )
- workPoints[j] = points[ newFace.points[j] ];
- // Calculate the average point for calculating winding order.
- Point3F averagePnt = Point3F::Zero;
- for ( S32 j = 0; j < pntCount; j++ )
- averagePnt += workPoints[j];
- averagePnt /= pntCount;
- // Sort points in correct winding order.
- U32 *vertMap = new U32[pntCount];
- MatrixF quadMat( true );
- quadMat.setPosition( averagePnt );
- quadMat.setColumn( 0, newFace.tangent );
- quadMat.setColumn( 1, mCross( newFace.normal, newFace.tangent ) );
- quadMat.setColumn( 2, newFace.normal );
- quadMat.inverse();
- // Transform working points into quad space
- // so we can work with them as 2D points.
- for ( S32 j = 0; j < pntCount; j++ )
- quadMat.mulP( workPoints[j] );
- MathUtils::sortQuadWindingOrder( true, workPoints, vertMap, pntCount );
- // Save points in winding order.
- for ( S32 j = 0; j < pntCount; j++ )
- newFace.winding.push_back( vertMap[j] );
- // Calculate the area and centroid of the face.
- newFace.area = 0.0f;
- for ( S32 j = 0; j < pntCount; j++ )
- {
- S32 k = ( j + 1 ) % pntCount;
- const Point3F &p0 = workPoints[ vertMap[j] ];
- const Point3F &p1 = workPoints[ vertMap[k] ];
-
- // Note that this calculation returns positive area for clockwise winding
- // and negative area for counterclockwise winding.
- newFace.area += p0.y * p1.x;
- newFace.area -= p0.x * p1.y;
- }
- //AssertFatal( newFace.area > 0.0f, "ConvexShape - face area was not positive." );
- if ( newFace.area > 0.0f )
- newFace.area /= 2.0f;
- F32 factor;
- F32 cx = 0.0f, cy = 0.0f;
-
- for ( S32 j = 0; j < pntCount; j++ )
- {
- S32 k = ( j + 1 ) % pntCount;
- const Point3F &p0 = workPoints[ vertMap[j] ];
- const Point3F &p1 = workPoints[ vertMap[k] ];
- factor = p0.x * p1.y - p1.x * p0.y;
- cx += ( p0.x + p1.x ) * factor;
- cy += ( p0.y + p1.y ) * factor;
- }
-
- factor = 1.0f / ( newFace.area * 6.0f );
- newFace.centroid.set( cx * factor, cy * factor, 0.0f );
- quadMat.inverse();
- quadMat.mulP( newFace.centroid );
- delete [] workPoints;
- workPoints = NULL;
- // Make polygons / triangles for this face.
- const U32 polyCount = pntCount - 2;
- newFace.triangles.setSize( polyCount );
- for ( S32 j = 0; j < polyCount; j++ )
- {
- ConvexShape::Triangle &poly = newFace.triangles[j];
- poly.p0 = vertMap[0];
- if ( j == 0 )
- {
- poly.p1 = vertMap[ 1 ];
- poly.p2 = vertMap[ 2 ];
- }
- else
- {
- poly.p1 = vertMap[ 1 + j ];
- poly.p2 = vertMap[ 2 + j ];
- }
- }
- delete [] vertMap;
- // Calculate texture coordinates for each point in this face.
- const Point3F binormal = mCross( newFace.normal, newFace.tangent );
- PlaneF planey( newFace.centroid - 0.5f * binormal, binormal );
- PlaneF planex( newFace.centroid - 0.5f * newFace.tangent, newFace.tangent );
- newFace.texcoords.setSize( newFace.points.size() );
- for ( S32 j = 0; j < newFace.points.size(); j++ )
- {
- F32 x = planex.distToPlane( points[ newFace.points[ j ] ] );
- F32 y = planey.distToPlane( points[ newFace.points[ j ] ] );
- newFace.texcoords[j].set( -x, -y );
- }
- // Data verification tests.
- #ifdef TORQUE_ENABLE_ASSERTS
- //S32 triCount = newFace.triangles.size();
- //S32 edgeCount = newFace.edges.size();
- //AssertFatal( triCount == edgeCount - 2, "ConvexShape - triangle/edge count do not match." );
- /*
- for ( S32 j = 0; j < triCount; j++ )
- {
- F32 area = MathUtils::mTriangleArea( points[ newFace.points[ newFace.triangles[j][0] ] ],
- points[ newFace.points[ newFace.triangles[j][1] ] ],
- points[ newFace.points[ newFace.triangles[j][2] ] ] );
- AssertFatal( area > 0.0f, "ConvexShape - triangle winding bad." );
- }*/
- #endif
- // Done with this Face.
-
- faces.push_back( newFace );
- }
- }
|