/* Copyright (c) 2015 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __CollisionResolver_H__ #define __CollisionResolver_H__ #ifdef __cplusplus extern "C" { #endif typedef struct CollisionResolver CollisionResolver; #define CollisionResolver_superclass StemObject #include "collision/CollisionObject.h" #include "collision/CollisionObjectIO.h" #include "collision/IntersectionManager.h" #include "gamemath/Vector3x.h" #include "stemobject/StemObject.h" #include typedef struct CollisionRecord { // Target colliding object CollisionObject * object1; // Object with which target collided CollisionObject * object2; // Temporal position within the timeslice being evaluated at which the intersection first occurs, from 0x00000 (beginning // of timeslice) to 0x10000 (end of timeslice). fixed16_16 time; // Amount of contact between the two objects. This is used internally by CollisionResolver to sort simultaneous collisions. fixed16_16 contactArea; // Normal vector of the surface of object2 at the first point of intersection by object1 Vector3x normal; // Calculated vector of motion of the point on object1 that contacted object2. Relative to timeslice size. Vector3x object1Vector; // Calculated vector of motion of the point on object2 that contacted object1. Relative to timeslice size. Vector3x object2Vector; } CollisionRecord; typedef struct CollisionRaycastResult { // Object intersecting ray CollisionObject * object; // Normalized distance from rayStart to rayEnd where intersection occurred. Always between 0x00000 and 0x10000. fixed16_16 distance; } CollisionRaycastResult; #define CollisionResolver_ivars \ StemObject_ivars \ \ IntersectionManager * intersectionManager; \ void (* listObjectsCallback)(CollisionObjectIO * objectIO, void * context); \ void * callbackContext; \ CollisionObjectIO * objectIO; \ \ /* If normal resolution fails to prevent object penetration, this function (if not NULL, which is the default) is called, */ \ /* and object1 will no longer be able to collide with object2 for the rest of the timeslice being processed. */ \ /* This a debugging facility to indicate a faulty collisionCallback implementation, and should not be used for normal logic. */ \ void (* resolutionFailureCallback)(CollisionObject * object1, CollisionObject * object2); \ \ bool private_ivar(intersectionManagerOwned); \ bool private_ivar(inResolveAll); \ compat_type(CollisionPairQueue *) private_ivar(pairQueue); \ CollisionRecord * private_ivar(simultaneousCollisionBuffer); \ CollisionObject ** private_ivar(cycleDetectionBuffer); \ size_t private_ivar(cycleDetectionBufferSize); \ size_t private_ivar(cycleDetectionBufferCount); \ unsigned int private_ivar(objectListDirtyValue); \ unsigned int private_ivar(lastObjectListDirtyValue); #define CollisionResolver_vtable(self_type) \ StemObject_vtable(self_type) stemobject_declare(CollisionResolver) // Creates and initializes a CollisionResolver. // intersectionManager will be used for all intersection tests in querySingle, findEarliest, and resolveAll. // If takeOwnership is true, intersectionManager will be freed when this CollisionResolver is freed. // If takeOwnership is false, the caller retains ownership of intersectionManager and is responsible for freeing it. CollisionResolver * CollisionResolver_create(IntersectionManager * intersectionManager, bool takeOwnership, void (* listObjectsCallback)(CollisionObjectIO * objectIO, void * context), void * callbackContext); bool CollisionResolver_init(CollisionResolver * self, IntersectionManager * intersectionManager, bool takeOwnership, void (* listObjectsCallback)(CollisionObjectIO * objectIO, void * context), void * callbackContext); // Disposes the CollisionResolver and all objects owned by it. Objects added with addObject are not owned by CollisionResolver. void CollisionResolver_dispose(CollisionResolver * self); // Adds/removes objects to/from the list of collidable objects tracked by CollisionResolver. // Objects in this list are used by querySingle, findEarliest, and resolveAll. // If addObject is called in a collision callback during resolveAll, it will be included immediately and tested against // in the next iteration. // If removeObject is called in a collision callback during resolveAll, the removed object will immediately be ignored // for the rest of resolveAll, but will not actually be removed from the list until resolveAll has completed. void CollisionResolver_addObject(CollisionResolver * self, compat_type(CollisionObject *) object); void CollisionResolver_removeObject(CollisionResolver * self, compat_type(CollisionObject *) object); // Performs an intersection test between object and all other collidable objects in list, returning true on intersection. // Works regardless of whether object has been added to CollisionResolver's list. // Does not call CollisionCallback; only returns the information of a potential collision if one exists. bool CollisionResolver_querySingle(CollisionResolver * self, compat_type(CollisionObject *) object, CollisionRecord * outCollision); // Performs intersection tests on all pairs of objects in list, and returns information about the earliest available // collisions, if any. If multiple collisions occur at the same time, this function will write all of them to // outCollisions (up to collisionCountMax), and return the number of CollisionRecords written. // Does not call CollisionCallback; only returns the information of potential collisions if any exist. size_t CollisionResolver_findEarliest(CollisionResolver * self, CollisionRecord * outCollisions, size_t collisionCountMax); // Collision tests all objects in list against all other objects in list, calling the CollisionCallback for each. // Fully resolves one frame. Not reentrant (but should never need to be). void CollisionResolver_resolveAll(CollisionResolver * self); // Tests all objects (at the current latest instant in time) against a line from rayStart to rayEnd, returning // the number of objects intersected by the ray, and writing records of the intersected objects in outResults, // sorted from nearest to farthest intersection from rayStart toward rayEnd. At most resultCountMax results will // be written to outResults. The return value is the number of intersections detected, which may be greater than // resultCountMax. No more than the number of objects added to this CollisionResolver's CollisionObjectIO (both // static and moving) will be returned. // objectMask determines which objects will be included in the query. If the result of a bitwise and between // an object's ownMask field and objectMask is 0, the object will be ignored. unsigned int CollisionResolver_listRaycastHits(CollisionResolver * self, Vector3x rayStart, Vector3x rayEnd, uint32_t objectMask, unsigned int resultCountMax, CollisionRaycastResult * outResults); // When listObjectsCallback is non-NULL, call dirtyObjectList() to mark that the list of objects needs to be rebuilt. // Otherwise, the previously fetched list of objects will be used. If listObjectsCallback is known to always add // the same objects to CollisionObjectIO, this function does not need to be called. If multiple queries are being // performed with querySingle(), findEarliest(), listRaycastHits(), etc., call this function only between cycles // or frames where listed objects may change in order to avoid the extra work of rebuilding the list on every call. // In usages where listObjectsCallback is NULL and objects are manually managed with addObject() and removeObject(), // this function has no effect. void CollisionResolver_dirtyObjectList(CollisionResolver * self); #ifdef __cplusplus } #endif #endif