12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730 |
- //-----------------------------------------------------------------------------
- // 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 "ts/tsShapeInstance.h"
- #include "ts/tsMaterialList.h"
- #include "scene/sceneObject.h"
- #include "collision/convex.h"
- #include "collision/collision.h"
- #include "T3D/tsStatic.h" // TODO: We shouldn't have this dependancy!
- #include "T3D/physics/physicsPlugin.h"
- #include "T3D/physics/physicsCollision.h"
- #include "collision/concretePolyList.h"
- #include "collision/vertexPolyList.h"
- #include "platform/profiler.h"
- #include "opcode/Opcode.h"
- #include "opcode/Ice/IceAABB.h"
- #include "opcode/Ice/IcePoint.h"
- #include "opcode/OPC_AABBTree.h"
- #include "opcode/OPC_AABBCollider.h"
- static bool gOpcodeInitialized = false;
- //-------------------------------------------------------------------------------------
- // Collision methods
- //-------------------------------------------------------------------------------------
- bool TSShapeInstance::buildPolyList(AbstractPolyList * polyList, S32 dl)
- {
- // if dl==-1, nothing to do
- if (dl==-1)
- return false;
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyList");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- S32 od = detail->objectDetailNum;
- // This detail does not have any geometry.
- if ( ss < 0 )
- return false;
- // nothing emitted yet...
- bool emitted = false;
- U32 surfaceKey = 0;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- if (start<end)
- {
- MatrixF initialMat;
- Point3F initialScale;
- polyList->getTransform(&initialMat,&initialScale);
- // set up for first object's node
- MatrixF mat;
- MatrixF scaleMat(true);
- F32* p = scaleMat;
- p[0] = initialScale.x;
- p[5] = initialScale.y;
- p[10] = initialScale.z;
- const MatrixF *previousMat = &mMeshObjects[start].getTransform();
- mat.mul(initialMat,scaleMat);
- mat.mul(*previousMat);
- polyList->setTransform(&mat,Point3F(1, 1, 1));
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (&mesh->getTransform() != previousMat)
- {
- // different node from before, set up for this node
- previousMat = &mesh->getTransform();
- if (previousMat != NULL)
- {
- mat.mul(initialMat,scaleMat);
- mat.mul(*previousMat);
- polyList->setTransform(&mat,Point3F(1, 1, 1));
- }
- }
- // collide...
- emitted |= mesh->buildPolyList(od,polyList,surfaceKey,mMaterialList);
- }
- // restore original transform...
- polyList->setTransform(&initialMat,initialScale);
- }
- return emitted;
- }
- bool TSShapeInstance::getFeatures(const MatrixF& mat, const Point3F& n, ConvexFeature* cf, S32 dl)
- {
- // if dl==-1, nothing to do
- if (dl==-1)
- return false;
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyList");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- S32 od = detail->objectDetailNum;
- // nothing emitted yet...
- bool emitted = false;
- U32 surfaceKey = 0;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- if (start<end)
- {
- MatrixF final;
- const MatrixF* previousMat = &mMeshObjects[start].getTransform();
- final.mul(mat, *previousMat);
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (&mesh->getTransform() != previousMat)
- {
- previousMat = &mesh->getTransform();
- final.mul(mat, *previousMat);
- }
- emitted |= mesh->getFeatures(od, final, n, cf, surfaceKey);
- }
- }
- return emitted;
- }
- bool TSShapeInstance::castRay(const Point3F & a, const Point3F & b, RayInfo * rayInfo, S32 dl)
- {
- // if dl==-1, nothing to do
- if (dl==-1)
- return false;
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::castRay");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- S32 od = detail->objectDetailNum;
- // This detail has no geometry to hit.
- if ( ss < 0 )
- return false;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- RayInfo saveRay;
- saveRay.t = 1.0f;
- const MatrixF * saveMat = NULL;
- bool found = false;
- if (start<end)
- {
- Point3F ta, tb;
- // set up for first object's node
- MatrixF mat;
- const MatrixF * previousMat = &mMeshObjects[start].getTransform();
- mat = *previousMat;
- mat.inverse();
- mat.mulP(a,&ta);
- mat.mulP(b,&tb);
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (&mesh->getTransform() != previousMat)
- {
- // different node from before, set up for this node
- previousMat = &mesh->getTransform();
- if (previousMat != NULL)
- {
- mat = *previousMat;
- mat.inverse();
- mat.mulP(a,&ta);
- mat.mulP(b,&tb);
- }
- }
- // collide...
- if (mesh->castRay(od,ta,tb,rayInfo, mMaterialList))
- {
- if (!rayInfo)
- return true;
- if (rayInfo->t <= saveRay.t)
- {
- saveRay = *rayInfo;
- saveMat = previousMat;
- }
- found = true;
- }
- }
- }
- // collide with any skins for this detail level...
- // TODO: if ever...
- // finalize the deal...
- if (found)
- {
- *rayInfo = saveRay;
- saveMat->mulV(rayInfo->normal);
- rayInfo->point = b-a;
- rayInfo->point *= rayInfo->t;
- rayInfo->point += a;
- }
- return found;
- }
- bool TSShapeInstance::castRayRendered(const Point3F & a, const Point3F & b, RayInfo * rayInfo, S32 dl)
- {
- // if dl==-1, nothing to do
- if (dl==-1)
- return false;
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::castRayRendered");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- S32 od = detail->objectDetailNum;
- if ( ss == -1 )
- return false;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- RayInfo saveRay;
- saveRay.t = 1.0f;
- const MatrixF * saveMat = NULL;
- bool found = false;
- if (start<end)
- {
- Point3F ta, tb;
- // set up for first object's node
- MatrixF mat;
- const MatrixF * previousMat = &mMeshObjects[start].getTransform();
- mat = *previousMat;
- mat.inverse();
- mat.mulP(a,&ta);
- mat.mulP(b,&tb);
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (&mesh->getTransform() != previousMat)
- {
- // different node from before, set up for this node
- previousMat = &mesh->getTransform();
- if (previousMat != NULL)
- {
- mat = *previousMat;
- mat.inverse();
- mat.mulP(a,&ta);
- mat.mulP(b,&tb);
- }
- }
- // collide...
- if (mesh->castRayRendered(od,ta,tb,rayInfo, mMaterialList))
- {
- if (!rayInfo)
- return true;
- if (rayInfo->t <= saveRay.t)
- {
- saveRay = *rayInfo;
- saveMat = previousMat;
- }
- found = true;
- }
- }
- }
- // collide with any skins for this detail level...
- // TODO: if ever...
- // finalize the deal...
- if (found)
- {
- *rayInfo = saveRay;
- saveMat->mulV(rayInfo->normal);
- rayInfo->point = b-a;
- rayInfo->point *= rayInfo->t;
- rayInfo->point += a;
- }
- return found;
- }
- Point3F TSShapeInstance::support(const Point3F & v, S32 dl)
- {
- // if dl==-1, nothing to do
- AssertFatal(dl != -1, "Error, should never try to collide with a non-existant detail level!");
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::support");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- S32 od = detail->objectDetailNum;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- F32 currMaxDP = -1e9f;
- Point3F currSupport = Point3F(0, 0, 0);
- const MatrixF * previousMat = NULL;
- MatrixF mat;
- if (start<end)
- {
- Point3F va;
- // set up for first object's node
- previousMat = &mMeshObjects[start].getTransform();
- mat = *previousMat;
- mat.inverse();
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- TSMesh* physMesh = mesh->getMesh(od);
- if (physMesh && !mesh->forceHidden && mesh->visible > 0.01f)
- {
- // collide...
- if (&mesh->getTransform() != previousMat)
- {
- // different node from before, set up for this node
- previousMat = &mesh->getTransform();
- mat = *previousMat;
- mat.inverse();
- }
- mat.mulV(v, &va);
- physMesh->support(mesh->frame, va, &currMaxDP, &currSupport);
- }
- }
- }
- if (currMaxDP != -1e9f)
- {
- previousMat->mulP(currSupport);
- return currSupport;
- }
- else
- {
- return Point3F(0, 0, 0);
- }
- }
- void TSShapeInstance::computeBounds(S32 dl, Box3F & bounds)
- {
- // if dl==-1, nothing to do
- if (dl==-1)
- return;
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::computeBounds");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- S32 od = detail->objectDetailNum;
- // use shape bounds for imposter details
- if (ss < 0)
- {
- bounds = mShape->mBounds;
- return;
- }
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- // run through objects and updating bounds as we go
- bounds.minExtents.set( 10E30f, 10E30f, 10E30f);
- bounds.maxExtents.set(-10E30f,-10E30f,-10E30f);
- Box3F box;
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (mesh->getMesh(od))
- {
- mesh->getMesh(od)->computeBounds(mesh->getTransform(),box, 0); // use frame 0 so TSSkinMesh uses skinned verts to compute bounds
- bounds.minExtents.setMin(box.minExtents);
- bounds.maxExtents.setMax(box.maxExtents);
- }
- }
- }
- //-------------------------------------------------------------------------------------
- // Object (MeshObjectInstance & PluginObjectInstance) collision methods
- //-------------------------------------------------------------------------------------
- bool TSShapeInstance::ObjectInstance::buildPolyList(S32 objectDetail, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials )
- {
- TORQUE_UNUSED( objectDetail );
- TORQUE_UNUSED( polyList );
- TORQUE_UNUSED( surfaceKey );
- TORQUE_UNUSED( materials );
- AssertFatal(0,"TSShapeInstance::ObjectInstance::buildPolyList: no default method.");
- return false;
- }
- bool TSShapeInstance::ObjectInstance::getFeatures(S32 objectDetail, const MatrixF& mat, const Point3F& n, ConvexFeature* cf, U32& surfaceKey)
- {
- TORQUE_UNUSED( objectDetail );
- TORQUE_UNUSED( mat );
- TORQUE_UNUSED( n );
- TORQUE_UNUSED( cf );
- TORQUE_UNUSED( surfaceKey );
- AssertFatal(0,"TSShapeInstance::ObjectInstance::buildPolyList: no default method.");
- return false;
- }
- void TSShapeInstance::ObjectInstance::support(S32, const Point3F&, F32*, Point3F*)
- {
- AssertFatal(0,"TSShapeInstance::ObjectInstance::supprt: no default method.");
- }
- bool TSShapeInstance::ObjectInstance::castRay( S32 objectDetail, const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials )
- {
- TORQUE_UNUSED( objectDetail );
- TORQUE_UNUSED( start );
- TORQUE_UNUSED( end );
- TORQUE_UNUSED( rayInfo );
- AssertFatal(0,"TSShapeInstance::ObjectInstance::castRay: no default method.");
- return false;
- }
- bool TSShapeInstance::MeshObjectInstance::buildPolyList( S32 objectDetail, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials )
- {
- TSMesh * mesh = getMesh(objectDetail);
- if (mesh && !forceHidden && visible>0.01f)
- return mesh->buildPolyList(frame,polyList,surfaceKey,materials);
- return false;
- }
- bool TSShapeInstance::MeshObjectInstance::getFeatures(S32 objectDetail, const MatrixF& mat, const Point3F& n, ConvexFeature* cf, U32& surfaceKey)
- {
- TSMesh* mesh = getMesh(objectDetail);
- if (mesh && !forceHidden && visible > 0.01f)
- return mesh->getFeatures(frame, mat, n, cf, surfaceKey);
- return false;
- }
- void TSShapeInstance::MeshObjectInstance::support(S32 objectDetail, const Point3F& v, F32* currMaxDP, Point3F* currSupport)
- {
- TSMesh* mesh = getMesh(objectDetail);
- if (mesh && !forceHidden && visible > 0.01f)
- mesh->support(frame, v, currMaxDP, currSupport);
- }
- bool TSShapeInstance::MeshObjectInstance::castRay( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials )
- {
- TSMesh* mesh = getMesh( objectDetail );
- if( mesh && !forceHidden && visible > 0.01f )
- return mesh->castRay( frame, start, end, rayInfo, materials );
- return false;
- }
- bool TSShapeInstance::MeshObjectInstance::castRayRendered( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials )
- {
- TSMesh* mesh = getMesh( objectDetail );
- if( mesh && !forceHidden && visible > 0.01f )
- return mesh->castRayRendered( frame, start, end, rayInfo, materials );
- return false;
- }
- bool TSShapeInstance::ObjectInstance::castRayOpcode( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo *rayInfo, TSMaterialList* materials )
- {
- TORQUE_UNUSED( objectDetail );
- TORQUE_UNUSED( start );
- TORQUE_UNUSED( end );
- TORQUE_UNUSED( rayInfo );
- TORQUE_UNUSED( materials );
- return false;
- }
- bool TSShapeInstance::ObjectInstance::buildPolyListOpcode( S32 objectDetail, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials )
- {
- TORQUE_UNUSED( objectDetail );
- TORQUE_UNUSED( polyList );
- TORQUE_UNUSED( surfaceKey );
- TORQUE_UNUSED( materials );
- return false;
- }
- bool TSShapeInstance::ObjectInstance::buildConvexOpcode( const MatrixF &mat, S32 objectDetail, const Box3F &bounds, Convex *c, Convex *list )
- {
- TORQUE_UNUSED( mat );
- TORQUE_UNUSED( objectDetail );
- TORQUE_UNUSED( bounds );
- TORQUE_UNUSED( c );
- TORQUE_UNUSED( list );
- return false;
- }
- bool TSShapeInstance::MeshObjectInstance::castRayOpcode( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo *info, TSMaterialList* materials )
- {
- TSMesh * mesh = getMesh(objectDetail);
- if (mesh && !forceHidden && visible>0.01f)
- return mesh->castRayOpcode(start, end, info, materials);
- return false;
- }
- bool TSShapeInstance::MeshObjectInstance::buildPolyListOpcode( S32 objectDetail, AbstractPolyList *polyList, const Box3F &box, TSMaterialList *materials )
- {
- TSMesh * mesh = getMesh(objectDetail);
- if ( mesh && !forceHidden && visible > 0.01f && box.isOverlapped( mesh->getBounds() ) )
- return mesh->buildPolyListOpcode(frame,polyList,box,materials);
- return false;
- }
- bool TSShapeInstance::MeshObjectInstance::buildConvexOpcode( const MatrixF &mat, S32 objectDetail, const Box3F &bounds, Convex *c, Convex *list)
- {
- TSMesh * mesh = getMesh(objectDetail);
- if ( mesh && !forceHidden && visible > 0.01f && bounds.isOverlapped( mesh->getBounds() ) )
- return mesh->buildConvexOpcode(mat, bounds, c, list);
- return false;
- }
- bool TSShapeInstance::buildPolyListOpcode( S32 dl, AbstractPolyList *polyList, const Box3F &box )
- {
- PROFILE_SCOPE( TSShapeInstance_buildPolyListOpcode_MeshObjInst );
- if (dl==-1)
- return false;
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyListOpcode");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- if ( ss < 0 )
- return false;
- S32 od = detail->objectDetailNum;
- // nothing emitted yet...
- bool emitted = false;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- if (start<end)
- {
- MatrixF initialMat;
- Point3F initialScale;
- polyList->getTransform(&initialMat,&initialScale);
- // set up for first object's node
- MatrixF mat;
- MatrixF scaleMat(true);
- F32* p = scaleMat;
- p[0] = initialScale.x;
- p[5] = initialScale.y;
- p[10] = initialScale.z;
- const MatrixF * previousMat = &mMeshObjects[start].getTransform();
- mat.mul(initialMat,scaleMat);
- mat.mul(*previousMat);
- polyList->setTransform(&mat,Point3F(1, 1, 1));
- // Update our bounding box...
- Box3F localBox = box;
- MatrixF otherMat = mat;
- otherMat.inverse();
- otherMat.mul(localBox);
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (&mesh->getTransform() != previousMat)
- {
- // different node from before, set up for this node
- previousMat = &mesh->getTransform();
- if (previousMat != NULL)
- {
- mat.mul(initialMat,scaleMat);
- mat.mul(*previousMat);
- polyList->setTransform(&mat,Point3F(1, 1, 1));
- // Update our bounding box...
- otherMat = mat;
- otherMat.inverse();
- localBox = box;
- otherMat.mul(localBox);
- }
- }
- // collide...
- emitted |= mesh->buildPolyListOpcode(od,polyList,localBox,mMaterialList);
- }
- // restore original transform...
- polyList->setTransform(&initialMat,initialScale);
- }
- return emitted;
- }
- bool TSShapeInstance::castRayOpcode( S32 dl, const Point3F & startPos, const Point3F & endPos, RayInfo *info)
- {
- // if dl==-1, nothing to do
- if (dl==-1)
- return false;
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::castRayOpcode");
- info->t = 100.f;
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- if ( ss < 0 )
- return false;
- S32 od = detail->objectDetailNum;
- // nothing emitted yet...
- bool emitted = false;
- const MatrixF* saveMat = NULL;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- if (start<end)
- {
- MatrixF mat;
- const MatrixF * previousMat = &mMeshObjects[start].getTransform();
- mat = *previousMat;
- mat.inverse();
- Point3F localStart, localEnd;
- mat.mulP(startPos, &localStart);
- mat.mulP(endPos, &localEnd);
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (&mesh->getTransform() != previousMat)
- {
- // different node from before, set up for this node
- previousMat = &mesh->getTransform();
- if (previousMat != NULL)
- {
- mat = *previousMat;
- mat.inverse();
- mat.mulP(startPos, &localStart);
- mat.mulP(endPos, &localEnd);
- }
- }
- // collide...
- if ( mesh->castRayOpcode(od,localStart, localEnd, info, mMaterialList) )
- {
- saveMat = previousMat;
- emitted = true;
- }
- }
- }
- if ( emitted )
- {
- saveMat->mulV(info->normal);
- info->point = endPos - startPos;
- info->point *= info->t;
- info->point += startPos;
- }
- return emitted;
- }
- bool TSShapeInstance::buildConvexOpcode( const MatrixF &objMat, const Point3F &objScale, S32 dl, const Box3F &bounds, Convex *c, Convex *list )
- {
- AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildConvexOpcode");
- // get subshape and object detail
- const TSDetail * detail = &mShape->details[dl];
- S32 ss = detail->subShapeNum;
- S32 od = detail->objectDetailNum;
- // nothing emitted yet...
- bool emitted = false;
- S32 start = mShape->subShapeFirstObject[ss];
- S32 end = mShape->subShapeNumObjects[ss] + start;
- if (start<end)
- {
- MatrixF initialMat = objMat;
- Point3F initialScale = objScale;
- // set up for first object's node
- MatrixF mat;
- MatrixF scaleMat(true);
- F32* p = scaleMat;
- p[0] = initialScale.x;
- p[5] = initialScale.y;
- p[10] = initialScale.z;
- const MatrixF * previousMat = &mMeshObjects[start].getTransform();
- mat.mul(initialMat,scaleMat);
- mat.mul(*previousMat);
- // Update our bounding box...
- Box3F localBox = bounds;
- MatrixF otherMat = mat;
- otherMat.inverse();
- otherMat.mul(localBox);
- // run through objects and collide
- for (S32 i=start; i<end; i++)
- {
- MeshObjectInstance * mesh = &mMeshObjects[i];
- if (od >= mesh->object->numMeshes)
- continue;
- if (&mesh->getTransform() != previousMat)
- {
- // different node from before, set up for this node
- previousMat = &mesh->getTransform();
- if (previousMat != NULL)
- {
- mat.mul(initialMat,scaleMat);
- mat.mul(*previousMat);
- // Update our bounding box...
- otherMat = mat;
- otherMat.inverse();
- localBox = bounds;
- otherMat.mul(localBox);
- }
- }
- // collide... note we pass the original mech transform
- // here so that the convex data returned is in mesh space.
- emitted |= mesh->buildConvexOpcode(*previousMat,od,localBox,c, list);
- }
- }
- return emitted;
- }
- void TSShape::findColDetails( bool useVisibleMesh, Vector<S32> *outDetails, Vector<S32> *outLOSDetails, S32 specifiedLOD) const
- {
- PROFILE_SCOPE( TSShape_findColDetails );
- if ( useVisibleMesh || (specifiedLOD !=0))
- {
- // If we're using the visible mesh for collision then
- // find the highest detail and use that.
- U32 highestDetail = -1;
- F32 highestSize = -F32_MAX;
- for ( U32 i = 0; i < details.size(); i++ )
- {
- // Make sure we skip any details that shouldn't be rendered
- if ( details[i].size < 0 )
- continue;
- /*
- // Also make sure we skip any collision details with a size.
- const String &name = names[details[i].nameIndex];
- if ( dStrStartsWith( name, "Collision" ) ||
- dStrStartsWith( name, "LOS" ) )
- continue;
- */
- if (specifiedLOD != 0)
- {
- if (details[i].size == specifiedLOD)
- {
- highestDetail = i;
- highestSize = details[i].size;
- }
- }
- else
- {
- // Otherwise test against the current highest size
- if (details[i].size > highestSize)
- {
- highestDetail = i;
- highestSize = details[i].size;
- }
- }
- }
- // We use the same detail for both raycast and collisions.
- if ( highestDetail != -1 )
- {
- outDetails->push_back( highestDetail );
- if ( outLOSDetails )
- outLOSDetails->push_back( highestDetail );
- }
- return;
- }
- // Detail meshes starting with COL or LOS is considered
- // to be a collision mesh.
- //
- // The LOS (light of sight) details are used for raycasts.
- for ( U32 i = 0; i < details.size(); i++ )
- {
- const String &name = names[ details[i].nameIndex ];
- if ( !dStrStartsWith( name, "Collision" ) )
- continue;
- outDetails->push_back(i);
- // If we're not returning LOS details then skip out.
- if ( !outLOSDetails )
- continue;
- // The way LOS works is that it will check to see if there is a LOS detail that matches
- // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in
- // the future). If it can't find a matching LOS it will simply use the collision instead.
- // We check for any "unmatched" LOS's further down.
- // Extract the detail number from the name.
- S32 number = 0;
- String::GetTrailingNumber( name, number );
-
- // Look for a matching LOS collision detail.
- //
- // TODO: Fix the old 9 detail offset which is there
- // because you cannot have two detail markers with
- // the same detail number.
- //
- const S32 LOSOverrideOffset = 9;
- String buff = String::ToString( "LOS-%d", mAbs( number ) + LOSOverrideOffset );
- S32 los = findDetail( buff );
-
- // If we didn't find the lod detail then use the
- // normal collision detail for LOS tests.
- if ( los == -1 )
- los = i;
- outLOSDetails->push_back( los );
- }
- // If we're not returning LOS details then skip out.
- if ( !outLOSDetails )
- return;
- // Snag any "unmatched" LOS details and put
- // them at the end of the list.
- for ( U32 i = 0; i < details.size(); i++ )
- {
- const String &name = names[ details[i].nameIndex ];
- if ( !dStrStartsWith( name, "LOS" ) )
- continue;
- // See if we already have this LOS
- bool found = false;
- for (U32 j = 0; j < outLOSDetails->size(); j++)
- {
- if ( (*outLOSDetails)[j] == i )
- {
- found = true;
- break;
- }
- }
- if ( !found )
- outLOSDetails->push_back(i);
- }
- }
- PhysicsCollision* TSShape::buildColShape( bool useVisibleMesh, const Point3F &scale )
- {
- return _buildColShapes( useVisibleMesh, scale, NULL, false );
- }
- void TSShape::buildColShapes( bool useVisibleMesh, const Point3F &scale, Vector< CollisionShapeInfo > *list )
- {
- _buildColShapes( useVisibleMesh, scale, list, true );
- }
- PhysicsCollision* TSShape::_buildColShapes( bool useVisibleMesh, const Point3F &scale, Vector< CollisionShapeInfo > *list, bool perMesh )
- {
- PROFILE_SCOPE( TSShape_buildColShapes );
- if ( !PHYSICSMGR )
- return NULL;
- PhysicsCollision *colShape = NULL;
- U32 surfaceKey = 0;
- if ( useVisibleMesh )
- {
- // Here we build triangle collision meshes from the
- // visible detail levels.
- // A negative subshape on the detail means we don't have geometry.
- const TSShape::Detail &detail = details[0];
- if ( detail.subShapeNum < 0 )
- return NULL;
- // We don't try to optimize the triangles we're given
- // and assume the art was created properly for collision.
- ConcretePolyList polyList;
- polyList.setTransform( &MatrixF::Identity, scale );
- // Create the collision meshes.
- S32 start = subShapeFirstObject[ detail.subShapeNum ];
- S32 end = start + subShapeNumObjects[ detail.subShapeNum ];
- for ( S32 o=start; o < end; o++ )
- {
- const TSShape::Object &object = objects[o];
- if ( detail.objectDetailNum >= object.numMeshes )
- continue;
- // No mesh or no verts.... nothing to do.
- TSMesh *mesh = meshes[ object.startMeshIndex + detail.objectDetailNum ];
- if ( !mesh || mesh->mNumVerts == 0 )
- continue;
- // Gather the mesh triangles.
- polyList.clear();
- mesh->buildPolyList( 0, &polyList, surfaceKey, NULL );
- // Create the collision shape if we haven't already.
- if ( !colShape )
- colShape = PHYSICSMGR->createCollision();
- // Get the object space mesh transform.
- MatrixF localXfm;
- getNodeWorldTransform( object.nodeIndex, &localXfm );
- colShape->addTriangleMesh( polyList.mVertexList.address(),
- polyList.mVertexList.size(),
- polyList.mIndexList.address(),
- polyList.mIndexList.size() / 3,
- localXfm );
- if ( perMesh )
- {
- list->increment();
- list->last().colNode = -1;
- list->last().colShape = colShape;
- colShape = NULL;
- }
- }
- // Return what we built... if anything.
- return colShape;
- }
- // Scan out the collision hulls...
- //
- // TODO: We need to support LOS collision for physics.
- //
- for ( U32 i = 0; i < details.size(); i++ )
- {
- const TSShape::Detail &detail = details[i];
- const String &name = names[detail.nameIndex];
- // Is this a valid collision detail.
- if ( !dStrStartsWith( name, "Collision" ) || detail.subShapeNum < 0 )
- continue;
- // Now go thru the meshes for this detail.
- S32 start = subShapeFirstObject[ detail.subShapeNum ];
- S32 end = start + subShapeNumObjects[ detail.subShapeNum ];
- if ( start >= end )
- continue;
- for ( S32 o=start; o < end; o++ )
- {
- const TSShape::Object &object = objects[o];
- const String &meshName = names[ object.nameIndex ];
- if ( object.numMeshes <= detail.objectDetailNum )
- continue;
- // No mesh, a flat bounds, or no verts.... nothing to do.
- TSMesh *mesh = meshes[ object.startMeshIndex + detail.objectDetailNum ];
- if ( !mesh || mesh->getBounds().isEmpty() || mesh->mNumVerts == 0 )
- continue;
- // We need the default mesh transform.
- MatrixF localXfm;
- getNodeWorldTransform( object.nodeIndex, &localXfm );
- Point3F nodeWorldPosition = localXfm.getPosition();
- nodeWorldPosition.convolve(scale);
- localXfm.setPosition(nodeWorldPosition);
- // We have some sort of collision shape... so allocate it.
- if ( !colShape )
- colShape = PHYSICSMGR->createCollision();
- // We have geometry... what is it?
- if ( dStrStartsWith( meshName, "Colbox" ) )
- {
- // The bounds define the box extents directly.
- Point3F halfWidth = mesh->getBounds().getExtents() * scale * 0.5f;
- // Add the offset to the center of the bounds
- // into the local space transform.
- MatrixF centerXfm( true );
- Point3F meshBoundsCenter = mesh->getBounds().getCenter();
- meshBoundsCenter.convolve(scale);
- centerXfm.setPosition(meshBoundsCenter);
- localXfm.mul( centerXfm );
- colShape->addBox( halfWidth, localXfm );
- }
- else if ( dStrStartsWith( meshName, "Colsphere" ) )
- {
- // Get a sphere inscribed to the bounds.
- Point3F extents = mesh->getBounds().getExtents() * scale;
- F32 radius = extents.least() * 0.5f;
- // Add the offset to the center of the bounds
- // into the local space transform.
- MatrixF primXfm( true );
- Point3F meshBoundsCenter = mesh->getBounds().getCenter();
- meshBoundsCenter.convolve(scale);
- primXfm.setPosition(meshBoundsCenter);
- localXfm.mul( primXfm );
- colShape->addSphere( radius, localXfm );
- }
- else if ( dStrStartsWith( meshName, "Colcapsule" ) )
- {
- // Use the smallest extent as the radius for the capsule.
- Point3F extents = mesh->getBounds().getExtents() * scale;
- F32 radius = extents.least() * 0.5f;
- // We need to center the capsule and align it to the Y axis.
- MatrixF primXfm( true );
- Point3F meshBoundsCenter = mesh->getBounds().getCenter();
- meshBoundsCenter.convolve(scale);
- primXfm.setPosition(meshBoundsCenter);
- // Use the longest axis as the capsule height.
- F32 height = -radius * 2.0f;
- if ( extents.x > extents.y && extents.x > extents.z )
- {
- primXfm.setColumn( 0, Point3F( 0, 0, 1 ) );
- primXfm.setColumn( 1, Point3F( 1, 0, 0 ) );
- primXfm.setColumn( 2, Point3F( 0, 1, 0 ) );
- height += extents.x;
- }
- else if ( extents.z > extents.x && extents.z > extents.y )
- {
- primXfm.setColumn( 0, Point3F( 0, 1, 0 ) );
- primXfm.setColumn( 1, Point3F( 0, 0, 1 ) );
- primXfm.setColumn( 2, Point3F( 1, 0, 0 ) );
- height += extents.z;
- }
- else
- height += extents.y;
- // Add the primitive transform into the local transform.
- localXfm.mul( primXfm );
- // If we didn't find a positive height then fallback to
- // creating a sphere which is better than nothing.
- if ( height > 0.0f )
- colShape->addCapsule( radius, height, localXfm );
- else
- colShape->addSphere( radius, localXfm );
- }
- else if ( dStrStartsWith( meshName, "Colmesh" ) )
- {
- // For a triangle mesh we gather the triangles raw from the
- // mesh and don't do any optimizations or cleanup.
- ConcretePolyList polyList;
- polyList.setTransform( &MatrixF::Identity, scale );
- mesh->buildPolyList( 0, &polyList, surfaceKey, NULL );
- colShape->addTriangleMesh( polyList.mVertexList.address(),
- polyList.mVertexList.size(),
- polyList.mIndexList.address(),
- polyList.mIndexList.size() / 3,
- localXfm );
- }
- else
- {
- // Any other mesh name we assume as a generic convex hull.
- //
- // Collect the verts using the vertex polylist which will
- // filter out duplicates. This is importaint as the convex
- // generators can sometimes fail with duplicate verts.
- //
- VertexPolyList polyList;
- MatrixF meshMat( localXfm );
- polyList.setTransform( &MatrixF::Identity, scale );
- mesh->buildPolyList( 0, &polyList, surfaceKey, NULL );
- colShape->addConvex( polyList.getVertexList().address(),
- polyList.getVertexList().size(),
- meshMat );
- }
- if ( perMesh )
- {
- list->increment();
-
- S32 detailNum;
- String::GetTrailingNumber( name, detailNum );
-
- String str = String::ToString( "%s%i", meshName.c_str(), detailNum );
- S32 found = findNode( str );
- if ( found == -1 )
- {
- str = str.replace('-','_');
- found = findNode( str );
- }
- list->last().colNode = found;
- list->last().colShape = colShape;
- colShape = NULL;
- }
- } // objects
- } // details
- return colShape;
- }
- bool TSMesh::buildPolyListOpcode( const S32 od, AbstractPolyList *polyList, const Box3F &nodeBox, TSMaterialList *materials )
- {
- PROFILE_SCOPE( TSMesh_buildPolyListOpcode );
- // This is small... there is no win for preallocating it.
- Opcode::AABBCollider opCollider;
- opCollider.SetPrimitiveTests( true );
- // This isn't really needed within the AABBCollider as
- // we don't use temporal coherance... use a static to
- // remove the allocation overhead.
- static Opcode::AABBCache opCache;
- IceMaths::AABB opBox;
- opBox.SetMinMax( Point( nodeBox.minExtents.x, nodeBox.minExtents.y, nodeBox.minExtents.z ),
- Point( nodeBox.maxExtents.x, nodeBox.maxExtents.y, nodeBox.maxExtents.z ) );
- Opcode::CollisionAABB opCBox(opBox);
- if ( !opCollider.Collide( opCache, opCBox, *mOptTree ) )
- return false;
- U32 count = opCollider.GetNbTouchedPrimitives();
- const udword *idx = opCollider.GetTouchedPrimitives();
- Opcode::VertexPointers vp;
- U32 plIdx[3];
- S32 j;
- Point3F tmp;
- const IceMaths::Point **verts;
- const Opcode::MeshInterface *mi = mOptTree->GetMeshInterface();
- for ( S32 i=0; i < count; i++ )
- {
- // Get the triangle...
- mi->GetTriangle( vp, idx[i] );
- verts = vp.Vertex;
- // And register it in the polylist...
- polyList->begin( NULL, i );
- for( j = 2; j > -1; j-- )
- {
- tmp.set( verts[j]->x, verts[j]->y, verts[j]->z );
- plIdx[j] = polyList->addPoint( tmp );
- polyList->vertex( plIdx[j] );
- }
- polyList->plane( plIdx[0], plIdx[2], plIdx[1] );
- polyList->end();
- }
- // TODO: Add a polyList->getCount() so we can see if we
- // got clipped polys and didn't really emit anything.
- return count > 0;
- }
- bool TSMesh::buildConvexOpcode( const MatrixF &meshToObjectMat, const Box3F &nodeBox, Convex *convex, Convex *list )
- {
- PROFILE_SCOPE( TSMesh_buildConvexOpcode );
- // This is small... there is no win for preallocating it.
- Opcode::AABBCollider opCollider;
- opCollider.SetPrimitiveTests( true );
- // This isn't really needed within the AABBCollider as
- // we don't use temporal coherance... use a static to
- // remove the allocation overhead.
- static Opcode::AABBCache opCache;
- IceMaths::AABB opBox;
- opBox.SetMinMax( Point( nodeBox.minExtents.x, nodeBox.minExtents.y, nodeBox.minExtents.z ),
- Point( nodeBox.maxExtents.x, nodeBox.maxExtents.y, nodeBox.maxExtents.z ) );
- Opcode::CollisionAABB opCBox(opBox);
- if( !opCollider.Collide( opCache, opCBox, *mOptTree ) )
- return false;
- U32 cnt = opCollider.GetNbTouchedPrimitives();
- const udword *idx = opCollider.GetTouchedPrimitives();
- Opcode::VertexPointers vp;
- for ( S32 i = 0; i < cnt; i++ )
- {
- // First, check our active convexes for a potential match (and clean things
- // up, too.)
- const U32 curIdx = idx[i];
- // See if the square already exists as part of the working set.
- bool gotMatch = false;
- CollisionWorkingList& wl = convex->getWorkingList();
- for ( CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext )
- {
- if( itr->mConvex->getType() != TSPolysoupConvexType )
- continue;
- const TSStaticPolysoupConvex *chunkc = static_cast<TSStaticPolysoupConvex*>( itr->mConvex );
- if( chunkc->getObject() != TSStaticPolysoupConvex::smCurObject )
- continue;
-
- if( chunkc->mesh != this )
- continue;
- if( chunkc->idx != curIdx )
- continue;
- // A match! Don't need to add it.
- gotMatch = true;
- break;
- }
- if( gotMatch )
- continue;
- // Get the triangle...
- mOptTree->GetMeshInterface()->GetTriangle( vp, idx[i] );
- Point3F a( vp.Vertex[0]->x, vp.Vertex[0]->y, vp.Vertex[0]->z );
- Point3F b( vp.Vertex[1]->x, vp.Vertex[1]->y, vp.Vertex[1]->z );
- Point3F c( vp.Vertex[2]->x, vp.Vertex[2]->y, vp.Vertex[2]->z );
- // Transform the result into object space!
- meshToObjectMat.mulP( a );
- meshToObjectMat.mulP( b );
- meshToObjectMat.mulP( c );
- PlaneF p( c, b, a );
- Point3F peak = ((a + b + c) / 3.0f) - (p * 0.15f);
- // Set up the convex...
- TSStaticPolysoupConvex *cp = new TSStaticPolysoupConvex();
- list->registerObject( cp );
- convex->addToWorkingList( cp );
- cp->mesh = this;
- cp->idx = curIdx;
- cp->mObject = TSStaticPolysoupConvex::smCurObject;
- cp->normal = p;
- cp->verts[0] = a;
- cp->verts[1] = b;
- cp->verts[2] = c;
- cp->verts[3] = peak;
- // Update the bounding box.
- Box3F &bounds = cp->box;
- bounds.minExtents.set( F32_MAX, F32_MAX, F32_MAX );
- bounds.maxExtents.set( -F32_MAX, -F32_MAX, -F32_MAX );
- bounds.minExtents.setMin( a );
- bounds.minExtents.setMin( b );
- bounds.minExtents.setMin( c );
- bounds.minExtents.setMin( peak );
- bounds.maxExtents.setMax( a );
- bounds.maxExtents.setMax( b );
- bounds.maxExtents.setMax( c );
- bounds.maxExtents.setMax( peak );
- }
- return true;
- }
- void TSMesh::prepOpcodeCollision()
- {
- // Make sure opcode is loaded!
- if( !gOpcodeInitialized )
- {
- Opcode::InitOpcode();
- gOpcodeInitialized = true;
- }
- // Don't re init if we already have something...
- if ( mOptTree )
- return;
- // Ok, first set up a MeshInterface
- Opcode::MeshInterface *mi = new Opcode::MeshInterface();
- mOpMeshInterface = mi;
- // Figure out how many triangles we have...
- U32 triCount = 0;
- const U32 base = 0;
- for ( U32 i = 0; i < mPrimitives.size(); i++ )
- {
- TSDrawPrimitive & draw = mPrimitives[i];
- const U32 start = draw.start;
- AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" );
- // gonna depend on what kind of primitive it is...
- if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )
- triCount += draw.numElements / 3;
- else
- {
- // Have to walk the tristrip to get a count... may have degenerates
- U32 idx0 = base + mIndices[start + 0];
- U32 idx1;
- U32 idx2 = base + mIndices[start + 1];
- U32 * nextIdx = &idx1;
- for ( S32 j = 2; j < draw.numElements; j++ )
- {
- *nextIdx = idx2;
- // nextIdx = (j%2)==0 ? &idx0 : &idx1;
- nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
- idx2 = base + mIndices[start + j];
- if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 )
- continue;
- triCount++;
- }
- }
- }
- // Just do the first trilist for now.
- mi->SetNbVertices( mVertexData.isReady() ? mNumVerts : mVerts.size() );
- mi->SetNbTriangles( triCount );
- // Stuff everything into appropriate arrays.
- IceMaths::IndexedTriangle *its = new IceMaths::IndexedTriangle[ mi->GetNbTriangles() ], *curIts = its;
- IceMaths::Point *pts = new IceMaths::Point[ mi->GetNbVertices() ];
- mOpTris = its;
- mOpPoints = pts;
- // add the polys...
- for ( U32 i = 0; i < mPrimitives.size(); i++ )
- {
- TSDrawPrimitive & draw = mPrimitives[i];
- const U32 start = draw.start;
- AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" );
- const U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask;
- // gonna depend on what kind of primitive it is...
- if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )
- {
- for ( S32 j = 0; j < draw.numElements; )
- {
- curIts->mVRef[2] = base + mIndices[start + j + 0];
- curIts->mVRef[1] = base + mIndices[start + j + 1];
- curIts->mVRef[0] = base + mIndices[start + j + 2];
- curIts->mMatIdx = matIndex;
- curIts++;
- j += 3;
- }
- }
- else
- {
- AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::buildPolyList (2)" );
- U32 idx0 = base + mIndices[start + 0];
- U32 idx1;
- U32 idx2 = base + mIndices[start + 1];
- U32 * nextIdx = &idx1;
- for ( S32 j = 2; j < draw.numElements; j++ )
- {
- *nextIdx = idx2;
- // nextIdx = (j%2)==0 ? &idx0 : &idx1;
- nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
- idx2 = base + mIndices[start + j];
- if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 )
- continue;
- curIts->mVRef[2] = idx0;
- curIts->mVRef[1] = idx1;
- curIts->mVRef[0] = idx2;
- curIts->mMatIdx = matIndex;
- curIts++;
- }
- }
- }
- AssertFatal( (curIts - its) == mi->GetNbTriangles(), "Triangle count mismatch!" );
- for( S32 i = 0; i < mi->GetNbVertices(); i++ )
- {
- if( mVertexData.isReady() )
- {
- const __TSMeshVertexBase &vertData = mVertexData.getBase(i);
- pts[i].Set( vertData.vert().x, vertData.vert().y, vertData.vert().z );
- }
- else
- {
- pts[i].Set( mVerts[i].x, mVerts[i].y, mVerts[i].z );
- }
- }
- mi->SetPointers( its, pts );
- // Ok, we've got a mesh interface populated, now let's build a thingy to collide against.
- mOptTree = new Opcode::Model();
- Opcode::OPCODECREATE opcc;
- opcc.mCanRemap = true;
- opcc.mIMesh = mi;
- opcc.mKeepOriginal = false;
- opcc.mNoLeaf = false;
- opcc.mQuantized = false;
- opcc.mSettings.mLimit = 1;
- mOptTree->Build( opcc );
- }
- static Point3F texGenAxis[18] =
- {
- Point3F(0,0,1), Point3F(1,0,0), Point3F(0,-1,0),
- Point3F(0,0,-1), Point3F(1,0,0), Point3F(0,1,0),
- Point3F(1,0,0), Point3F(0,1,0), Point3F(0,0,1),
- Point3F(-1,0,0), Point3F(0,1,0), Point3F(0,0,-1),
- Point3F(0,1,0), Point3F(1,0,0), Point3F(0,0,1),
- Point3F(0,-1,0), Point3F(-1,0,0), Point3F(0,0,-1)
- };
- bool TSMesh::castRayOpcode( const Point3F &start, const Point3F &end, RayInfo *info, TSMaterialList *materials )
- {
- Opcode::RayCollider ray;
- Opcode::CollisionFaces cfs;
- IceMaths::Point dir(end.x - start.x, end.y - start.y, end.z - start.z );
- const F32 rayLen = dir.Magnitude();
- IceMaths::Ray vec( Point(start.x, start.y, start.z), dir.Normalize() );
- ray.SetDestination( &cfs);
- ray.SetFirstContact( false );
- ray.SetClosestHit( true );
- ray.SetPrimitiveTests( true );
- ray.SetCulling( true );
- ray.SetMaxDist( rayLen );
- AssertFatal( ray.ValidateSettings() == NULL, "invalid ray settings" );
- // Do collision.
- bool safety = ray.Collide( vec, *mOptTree );
- AssertFatal( safety, "TSMesh::castRayOpcode - no good ray collide!" );
- // If no hit, just skip out.
- if( cfs.GetNbFaces() == 0 )
- return false;
- // Got a hit!
- AssertFatal( cfs.GetNbFaces() == 1, "bad" );
- const Opcode::CollisionFace &face = cfs.GetFaces()[0];
- // If the cast was successful let's check if the t value is less than what we had
- // and toggle the collision boolean
- // Stupid t... i prefer coffee
- const F32 t = face.mDistance / rayLen;
- if( t < 0.0f || t > 1.0f )
- return false;
- if( t <= info->t )
- {
- info->t = t;
- // Calculate the normal.
- Opcode::VertexPointers vp;
- mOptTree->GetMeshInterface()->GetTriangle( vp, face.mFaceID );
- if ( materials && vp.MatIdx >= 0 && vp.MatIdx < materials->size() )
- info->material = materials->getMaterialInst( vp.MatIdx );
- // Get the two edges.
- IceMaths::Point baseVert = *vp.Vertex[0];
- IceMaths::Point a = *vp.Vertex[1] - baseVert;
- IceMaths::Point b = *vp.Vertex[2] - baseVert;
- IceMaths::Point n;
- n.Cross( a, b );
- n.Normalize();
- info->normal.set( n.x, n.y, n.z );
- // generate UV coordinate across mesh based on
- // matching normals, this isn't done by default and is
- // primarily of interest in matching a collision point to
- // either a GUI control coordinate or finding a hit pixel in texture space
- if (info->generateTexCoord)
- {
- baseVert = *vp.Vertex[0];
- a = *vp.Vertex[1];
- b = *vp.Vertex[2];
- Point3F facePoint = (1.0f - face.mU - face.mV) * Point3F(baseVert.x, baseVert.y, baseVert.z)
- + face.mU * Point3F(a.x, a.y, a.z) + face.mV * Point3F(b.x, b.y, b.z);
- U32 faces[1024];
- U32 numFaces = 0;
- for (U32 i = 0; i < mOptTree->GetMeshInterface()->GetNbTriangles(); i++)
- {
- if ( i == face.mFaceID )
- {
- faces[numFaces++] = i;
- }
- else
- {
- IceMaths::Point n2;
- mOptTree->GetMeshInterface()->GetTriangle( vp, i );
- baseVert = *vp.Vertex[0];
- a = *vp.Vertex[1] - baseVert;
- b = *vp.Vertex[2] - baseVert;
- n2.Cross( a, b );
- n2.Normalize();
- F32 eps = .01f;
- if ( mFabs(n.x - n2.x) < eps && mFabs(n.y - n2.y) < eps && mFabs(n.z - n2.z) < eps)
- {
- faces[numFaces++] = i;
- }
- }
- if (numFaces == 1024)
- {
- // too many faces in this collision mesh for UV generation
- return true;
- }
- }
- Point3F min(F32_MAX, F32_MAX, F32_MAX);
- Point3F max(-F32_MAX, -F32_MAX, -F32_MAX);
- for (U32 i = 0; i < numFaces; i++)
- {
- mOptTree->GetMeshInterface()->GetTriangle( vp, faces[i] );
- for ( U32 j =0; j < 3; j++)
- {
- a = *vp.Vertex[j];
- if (a.x < min.x)
- min.x = a.x;
- if (a.y < min.y)
- min.y = a.y;
- if (a.z < min.z)
- min.z = a.z;
- if (a.x > max.x)
- max.x = a.x;
- if (a.y > max.y)
- max.y = a.y;
- if (a.z > max.z)
- max.z = a.z;
- }
- }
- // slerp
- Point3F divSafe = (max - min);
- if (divSafe.x == 0.0f) divSafe.x = POINT_EPSILON;
- if (divSafe.y == 0.0f) divSafe.y = POINT_EPSILON;
- if (divSafe.z == 0.0f) divSafe.z = POINT_EPSILON;
- Point3F s = ( (max - min) - (facePoint - min) ) / divSafe;
- // compute axis
- S32 bestAxis = 0;
- F32 best = 0.f;
- for (U32 i = 0 ; i < 6 ; i++)
- {
- F32 dot = mDot (info->normal, texGenAxis[i*3]);
- if (dot > best)
- {
- best = dot;
- bestAxis = i;
- }
- }
- Point3F xv = texGenAxis[bestAxis*3+1];
- Point3F yv = texGenAxis[bestAxis*3+2];
- S32 sv, tv;
- if (xv.x)
- sv = 0;
- else if (xv.y)
- sv = 1;
- else
- sv = 2;
- if (yv.x)
- tv = 0;
- else if (yv.y)
- tv = 1;
- else
- tv = 2;
- // handle coord translation
- if (bestAxis == 2 || bestAxis == 3)
- {
- S32 x = sv;
- sv = tv;
- tv = x;
- if (yv.z < 0)
- s[sv] = 1.f - s[sv];
- }
- if (bestAxis < 2)
- {
- if (yv.y < 0)
- s[sv] = 1.f - s[sv];
- }
- if (bestAxis > 3)
- {
- s[sv] = 1.f - s[sv];
- if (yv.z > 0)
- s[tv] = 1.f - s[tv];
- }
- // done!
- info->texCoord.set(s[sv], s[tv]);
- }
- return true;
- }
- return false;
- }
|