123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- //-----------------------------------------------------------------------------
- // 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 "T3D/components/collision/collisionInterfaces.h"
- #include "scene/sceneObject.h"
- #include "T3D/entity.h"
- #include "console/engineAPI.h"
- #include "T3D/trigger.h"
- #include "materials/baseMatInstance.h"
- void CollisionInterface::handleCollisionList( CollisionList &collisionList, VectorF velocity )
- {
- Collision bestCol;
- mCollisionList = collisionList;
- for (U32 i=0; i < collisionList.getCount(); ++i)
- {
- Collision& colCheck = collisionList[i];
- if (colCheck.object)
- {
- if (colCheck.object->getTypeMask() & PlayerObjectType)
- {
- handleCollision( colCheck, velocity );
- }
- else if (colCheck.object->getTypeMask() & TriggerObjectType)
- {
- // We've hit it's bounding box, that's close enough for triggers
- Trigger* pTrigger = static_cast<Trigger*>(colCheck.object);
- Component *comp = dynamic_cast<Component*>(this);
- pTrigger->potentialEnterObject(comp->getOwner());
- }
- else if (colCheck.object->getTypeMask() & DynamicShapeObjectType)
- {
- Con::printf("HIT A GENERICALLY DYNAMIC OBJECT");
- handleCollision(colCheck, velocity);
- }
- else if(colCheck.object->getTypeMask() & EntityObjectType)
- {
- Entity* ent = dynamic_cast<Entity*>(colCheck.object);
- if (ent)
- {
- CollisionInterface *colObjectInterface = ent->getComponent<CollisionInterface>();
- if (colObjectInterface)
- {
- //convert us to our component
- Component *thisComp = dynamic_cast<Component*>(this);
- if (thisComp)
- {
- colObjectInterface->onCollisionSignal.trigger(thisComp->getOwner());
- //TODO: properly do this
- Collision oppositeCol = colCheck;
- oppositeCol.object = thisComp->getOwner();
- colObjectInterface->handleCollision(oppositeCol, velocity);
- }
- }
- }
- }
- else
- {
- handleCollision(colCheck, velocity);
- }
- }
- }
- }
- void CollisionInterface::handleCollision( Collision &col, VectorF velocity )
- {
- if (col.object && (mContactInfo.contactObject == NULL ||
- col.object->getId() != mContactInfo.contactObject->getId()))
- {
- queueCollision(col.object, velocity - col.object->getVelocity());
- //do the callbacks to script for this collision
- Component *comp = dynamic_cast<Component*>(this);
- if (comp->isMethod("onCollision"))
- {
- S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
- Con::executef(comp, "onCollision", col.object, col.normal, col.point, matId, velocity);
- }
- if (comp->getOwner()->isMethod("onCollisionEvent"))
- {
- S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
- Con::executef(comp->getOwner(), "onCollisionEvent", col.object, col.normal, col.point, matId, velocity);
- }
- }
- }
- void CollisionInterface::handleCollisionNotifyList()
- {
- //special handling for any collision components we should notify that a collision happened.
- for (U32 i = 0; i < mCollisionNotifyList.size(); ++i)
- {
- //convert us to our component
- Component *thisComp = dynamic_cast<Component*>(this);
- if (thisComp)
- {
- mCollisionNotifyList[i]->onCollisionSignal.trigger(thisComp->getOwner());
- }
- }
- mCollisionNotifyList.clear();
- }
- Chunker<CollisionInterface::CollisionTimeout> sTimeoutChunker;
- CollisionInterface::CollisionTimeout* CollisionInterface::sFreeTimeoutList = 0;
- void CollisionInterface::queueCollision( SceneObject *obj, const VectorF &vec)
- {
- // Add object to list of collisions.
- SimTime time = Sim::getCurrentTime();
- S32 num = obj->getId();
- CollisionTimeout** adr = &mTimeoutList;
- CollisionTimeout* ptr = mTimeoutList;
- while (ptr)
- {
- if (ptr->objectNumber == num)
- {
- if (ptr->expireTime < time)
- {
- ptr->expireTime = time + CollisionTimeoutValue;
- ptr->object = obj;
- ptr->vector = vec;
- }
- return;
- }
- // Recover expired entries
- if (ptr->expireTime < time)
- {
- CollisionTimeout* cur = ptr;
- *adr = ptr->next;
- ptr = ptr->next;
- cur->next = sFreeTimeoutList;
- sFreeTimeoutList = cur;
- }
- else
- {
- adr = &ptr->next;
- ptr = ptr->next;
- }
- }
- // New entry for the object
- if (sFreeTimeoutList != NULL)
- {
- ptr = sFreeTimeoutList;
- sFreeTimeoutList = ptr->next;
- ptr->next = NULL;
- }
- else
- {
- ptr = sTimeoutChunker.alloc();
- }
- ptr->object = obj;
- ptr->objectNumber = obj->getId();
- ptr->vector = vec;
- ptr->expireTime = time + CollisionTimeoutValue;
- ptr->next = mTimeoutList;
- mTimeoutList = ptr;
- }
- bool CollisionInterface::checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale,
- Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList)
- {
- Point3F end = start + velocity * time;
- Point3F distance = end - start;
- Box3F scaledBox = objectBox;
- scaledBox.minExtents.convolve(objectScale);
- scaledBox.maxExtents.convolve(objectScale);
- if (mFabs(distance.x) < objectBox.len_x() &&
- mFabs(distance.y) < objectBox.len_y() &&
- mFabs(distance.z) < objectBox.len_z())
- {
- // We can potentially early out of this. If there are no polys in the clipped polylist at our
- // end position, then we can bail, and just set start = end;
- Box3F wBox = scaledBox;
- wBox.minExtents += end;
- wBox.maxExtents += end;
- static EarlyOutPolyList eaPolyList;
- eaPolyList.clear();
- eaPolyList.mNormal.set(0.0f, 0.0f, 0.0f);
- eaPolyList.mPlaneList.clear();
- eaPolyList.mPlaneList.setSize(6);
- eaPolyList.mPlaneList[0].set(wBox.minExtents,VectorF(-1.0f, 0.0f, 0.0f));
- eaPolyList.mPlaneList[1].set(wBox.maxExtents,VectorF(0.0f, 1.0f, 0.0f));
- eaPolyList.mPlaneList[2].set(wBox.maxExtents,VectorF(1.0f, 0.0f, 0.0f));
- eaPolyList.mPlaneList[3].set(wBox.minExtents,VectorF(0.0f, -1.0f, 0.0f));
- eaPolyList.mPlaneList[4].set(wBox.minExtents,VectorF(0.0f, 0.0f, -1.0f));
- eaPolyList.mPlaneList[5].set(wBox.maxExtents,VectorF(0.0f, 0.0f, 1.0f));
- // Build list from convex states here...
- CollisionWorkingList& rList = colWorkingList;
- CollisionWorkingList* pList = rList.wLink.mNext;
- while (pList != &rList)
- {
- Convex* pConvex = pList->mConvex;
- if (pConvex->getObject()->getTypeMask() & collisionMask)
- {
- Box3F convexBox = pConvex->getBoundingBox();
- if (wBox.isOverlapped(convexBox))
- {
- // No need to separate out the physical zones here, we want those
- // to cause a fallthrough as well...
- pConvex->getPolyList(&eaPolyList);
- }
- }
- pList = pList->wLink.mNext;
- }
- if (eaPolyList.isEmpty())
- {
- return true;
- }
- }
- return false;
- }
- Collision* CollisionInterface::getCollision(S32 col)
- {
- if(col < mCollisionList.getCount() && col >= 0)
- return &mCollisionList[col];
- else
- return NULL;
- }
|