hkpWorldCinfo.h
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:27k
- /*
- *
- * Confidential Information of Telekinesys Research Limited (t/a Havok). Not for disclosure or distribution without Havok's
- * prior written consent. This software contains code, techniques and know-how which is confidential and proprietary to Havok.
- * Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2009 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
- *
- */
- #ifndef HKDYNAMICS_WORLD_HKWORLDCINFO_XML_H
- #define HKDYNAMICS_WORLD_HKWORLDCINFO_XML_H
- #include <Common/Base/Types/Geometry/Aabb/hkAabb.h>
- #include <Physics/Dynamics/World/Memory/hkpWorldMemoryAvailableWatchDog.h>
- #include <Physics/Collide/Filter/hkpConvexListFilter.h>
- #include <Physics/Collide/Filter/List/hkpCollisionFilterList.h>
- /// hkpWorldCinfo meta information
- extern const class hkClass hkpWorldCinfoClass;
- /// This structure contains all the information needed to construct a hkpWorld
- /// object.
- class hkpWorldCinfo : public hkReferencedObject
- {
- public:
- // +version(2)
- HK_DECLARE_REFLECTION();
- /// Used to specify the speed/stiffness balance of the core solver.
- /// Havok's solver is an iterative solver and similar to a 'successive
- /// over relaxation' (SOR) method. That means that each constraint will not
- /// be solved perfectly, but rather solved like a very stiff spring,
- /// which gives the solver a 'soft' feeling. So the goal of the solver
- /// is to make the constraint to appear hard.
- /// There are 3 parameters to control the behavior of the solver:
- /// - m_solverIterations: defines how often the solver iterates over
- /// all constraints. The higher the number, the stiffer the constraints,
- /// however you need to spend more CPU. Values between 2 and 16 are
- /// reasonable, higher values could lead to instable behavior (in this
- /// case you can achieve the same results by decreasing the physics delta time).
- /// - m_tau: defines how much of the current constraint error is solved every
- /// solver iteration. High values (0.8 .. 1.2 ) make the constraints harder,
- /// however they get more unstable as well. Smaller numbers (0.3 .. 0.6) give
- /// much softer and smoother behavior, however you have to set the number of iterations
- /// pretty high to achieve a stiff behavior.
- /// - m_damping: defines how the current bodies velocity is taken into account.
- /// If you set damping to 0, you get an explicit solver, setting it to m_tau
- /// makes the solver semi-implicit. A good choice is to set it to tau.
- /// This enum list allows to define some reasonable defaults: NITERS refers
- /// to the number of iterations, SOFT/MEDIUM/HARD refers to the value of tau and
- /// damp.
- /// Note: there is a new experimental parameter: m_solverNumMicroSteps. This allows for
- /// further increasing (multiply) the m_solverIterations without adding extra instability
- enum SolverType
- {
- ///
- SOLVER_TYPE_INVALID,
- /// 'Softest' solver type.
- SOLVER_TYPE_2ITERS_SOFT,
- /// .
- SOLVER_TYPE_2ITERS_MEDIUM,
- /// .
- SOLVER_TYPE_2ITERS_HARD,
- /// .
- SOLVER_TYPE_4ITERS_SOFT,
- /// .
- SOLVER_TYPE_4ITERS_MEDIUM,
- /// .
- SOLVER_TYPE_4ITERS_HARD,
- /// .
- SOLVER_TYPE_8ITERS_SOFT,
- /// .
- SOLVER_TYPE_8ITERS_MEDIUM,
- /// 'Hardest' solver type.
- SOLVER_TYPE_8ITERS_HARD,
- ///
- SOLVER_TYPE_MAX_ID
- };
- /// Specifies simulation with discrete or continuous collision detection.
- // Note: all simulation types with enumeration values >= SIMULATION_TYPE_CONTINUOUS set m_wantContinuousAgents = true in hkpWorld's constructor.
- enum SimulationType
- {
- ///
- SIMULATION_TYPE_INVALID,
- /// No continuous simulation is performed
- SIMULATION_TYPE_DISCRETE,
- /// Use this simulation if you want any continuous simulation.
- /// Depending on the hkpEntity->getQualityType(), collisions
- /// are not only performed at 'normal' physical timesteps (called PSI), but
- /// at any time when two objects collide (TOI)
- SIMULATION_TYPE_CONTINUOUS,
- /// Multithreaded continuous simulation.
- /// You must have read the multi threading user guide.<br>
- /// To use this you should call hkpWorld::stepMultithreaded(), see
- /// the hkDefaultPhysicsDemo::stepDemo for an example.
- /// Notes:
- /// - The internal overhead for multi threaded is small and you can expect
- /// good speedups, except:
- /// - solving multiple TOI events can not be done on different threads,
- /// so TOI are solved on a single thread. However the collision detection
- /// for each TOI event can be solver multithreaded (see m_processToisMultithreaded)
- SIMULATION_TYPE_MULTITHREADED,
- };
- /// Specifies how aggressively the engine accepts new contact points
- enum ContactPointGeneration
- {
- /// Try to gather as many contact points as possible. This
- /// gives you the highest quality at the cost of some (up to 25%)
- /// extra CPU. You should use this setting if you want to stack
- /// very small objects in your game
- CONTACT_POINT_ACCEPT_ALWAYS,
- /// Accept good contact points immediately and try to
- /// to reject the rest. This is a compromise
- CONTACT_POINT_REJECT_DUBIOUS,
- /// Uses some optimistic algorithms to speed up contact point generation.
- /// This can seriously increase the performance of the engine.
- /// Note: Stacking small objects becomes very difficult with this option enabled
- CONTACT_POINT_REJECT_MANY,
- };
- /// Tell the system what should happen if an objects leaves the
- /// extents of the broadphase.
- /// If you want to do your own implementation,
- /// just derive from hkpBroadPhaseBorder, implement your own
- /// maxPositionExceededCallback and call
- /// hkpWorld::setBroadPhaseBorder( new myBroadPhaseBorder() );
- enum BroadPhaseBorderBehaviour
- {
- /// Cause an assert and set the motion type to be fixed (default).
- BROADPHASE_BORDER_ASSERT,
- /// Set the motion type to be fixed and raise a warning.
- BROADPHASE_BORDER_FIX_ENTITY,
- /// Remove the entity from the hkpWorld and raise a warning.
- BROADPHASE_BORDER_REMOVE_ENTITY,
- /// Do not do anything, just continue to work.
- /// If many (>20) objects leave the broadphase,
- /// serious memory and CPU can be wasted.
- BROADPHASE_BORDER_DO_NOTHING,
- };
- /// Default constructor
- hkpWorldCinfo();
- //
- // Methods
- //
- /// Set the parameters of the world's solver. Each solver type provides a different
- /// speed/stiffness balance for the simulation. The default solver type is
- /// SOLVER_TYPE_4ITERS_MEDIUM, which is fast and moderately soft.
- void setupSolverInfo(enum SolverType st);
- /// Sets the broadphase size to be a cube centered on the origin of side
- /// sideLength. See also m_broadPhaseWorldSize.
- void setBroadPhaseWorldSize(hkReal size);
- //
- // Members
- //
- public:
- //
- // Basic setup
- //
- /// The gravity for the world. The default is (0, -9.8, 0).
- hkVector4 m_gravity; //+default(0,-9.8f,0)
- /// This variable is used to guess at the maximum number of overlaps you will get
- /// when you add or remove an entity or phantom. It determines the size of the local
- /// array used to query the broadphase. The local array uses the hkMemory stack,
- /// The default value is 1024, which requires a local array stack area of 8K.
- hkInt32 m_broadPhaseQuerySize; //+default(1024)
- /// The velocity which defines when two objects are assumed to be
- /// in resting contact. If the approaching velocity of the two objects
- /// at a point of contact is higher than this value, a special more accurate collision
- /// restitution algorithm is called. By default this value is HK_REAL_MAX
- /// which thus disables this algorithm (though more accurate, this algorithm can, as a side-effect,
- /// cause instabilites for long thin bodies). If you want to enable this algorithm
- /// and are aware of the possible artifacts mentioned above, you can set this value to 0.2f
- /// (the value used in Havok 3.1.0 and 3.1.1).
- hkReal m_contactRestingVelocity;
- /// Tell the system what should happen if an objects leaves the
- /// extents of the broadphase. Read BroadPhaseBorderBehaviour for more details.
- /// This value defaults to BROADPHASE_BORDER_ASSERT
- hkEnum<BroadPhaseBorderBehaviour,hkInt8> m_broadPhaseBorderBehaviour;
- /// Defines the area dealt with by the collision detection broadphase. The size
- /// specified is a cuboid in world units - this cuboid defines the broadphase
- /// limits. There is a significant performance cost for objects that leave this
- /// area. The default size is a cube of side 1000, centred at the origin.
- class hkAabb m_broadPhaseWorldAabb;
- /// Enables/disables use of KD-trees. KD-trees speed up raycasting and linear casting
- /// queries performed on the world. When this is disabled the hkpWorld uses the standard broadphase.
- hkBool m_useKdTree; //+default(false)
- /// Enables/disables automatic updating of the world's kd-tree after the world step.
- /// The kd-tree must be in sync with the world state in order to avoid missed raycasts.
- /// Thus this should be set to false if you intend to add, move, or remove objects
- /// after the world has been stepped but before starting raycasts.
- /// If this is the case, you must call hkpWorld::updateKdTree() manually;
- hkBool m_autoUpdateKdTree; //+default(true)
- /// The collision tolerance. This is used to create and keep contact points even for
- /// non penetrating objects. This dramatically increases the stability of the
- /// system. The default collision tolerance is 0.1f.
- /// It is safe to decrease this value slightly when continuous simulation is enabled. This allows
- /// for more precise creation of contact points and better quality at the cost of generating
- /// more TOI events.
- hkReal m_collisionTolerance; //+default(.1f)
- /// The collision filter used by the hkpWorld. By default this is HK_NULL.
- /// If left as HK_NULL, a hkpNullCollisionFilter is set as the default filter in the
- /// world. This disables no collisions.
-
- hkRefPtr<class hkpCollisionFilter> m_collisionFilter;
- /// The filter used to decide how convex list shape collisions should be treated.
- /// By default this pointer is set to HK_NULL, in which case the default convex list filter
- /// will be created when the hkpWorld is constructed.
- /// It is not possible to change this collision filter after the world has been created.
- hkRefPtr<class hkpConvexListFilter> m_convexListFilter;
- /// The max linear velocity you expect the continuous physics to work correctly.
- /// This value is used to set internal tolerances. It defaults to 200 [meters per second]
- /// Note: This value does not limit the maximum linear velocities of rigid bodies.
- /// You have to set hkpRigidBody::m_maxLinearVelocity for each body yourself.
- hkReal m_expectedMaxLinearVelocity; //+default(200)
- /// For continuous physics this is the size of the toi queue as used by the collision detector.
- ///
- /// The collision detector exports tois into the hkMultithreadedSimulation::m_toiEvents array, which
- /// will have the initial size of m_sizeOfToiEventQueue. If more tois are generated, they will simply be
- /// dropped.
- int m_sizeOfToiEventQueue; //+default(250)
- /// The min delta time you expect between two PSI.
- /// This value is only used to set internal tolerances. It defaults to 1/30.0f second
- /// Note: This value does not limit the delta time.
- hkReal m_expectedMinPsiDeltaTime; //+default(1.0f/30.0f)
- /// The memory "watchdog" used by the world. By default this is HK_NULL, i.e. the memory
- /// for the world is not checked. If this is set, hkpWorldMemoryWatchDog::watchMemory will be
- /// called every step, which gives the hkpWorldMemoryWatchDog a chance to prevent the memory
- /// exceeding a desired threshold.
- hkRefPtr<class hkWorldMemoryAvailableWatchDog> m_memoryWatchDog;
- //
- // Optimizations
- //
- /// NOTE: There is currently a known issue HVK-2553 associated with markers which
- /// can cause a possible crash during simulation. You should leave this value at 0 in the meantime.
- /// This variable is used to subdivide the x-axis in the 3-axisSweepAndPrune space
- /// into regular intervals. Setting this value slows down the normal operations by a
- /// very small amount, but can speed up asynchronous broadphase queries by up to 10
- /// times. Values have to be of power of 2. A typical good value would be 64.
- /// The default is 0, i.e. markers are not enabled by default.
- hkInt32 m_broadPhaseNumMarkers;
- /// Specifies how aggressively the engine accepts new contact points
- /// Defaults to CONTACT_POINT_REJECT_MANY
- hkEnum<ContactPointGeneration, hkInt8> m_contactPointGeneration;
- /// On PLAYSTATION(R)3 contact point confirmed callbacks can be omitted when bodies have zero restitution.
- /// The default false value ensures all callbacks are triggered properly.
- hkBool m_allowToSkipConfirmedCallbacks; //+default(false)
- //
- // Solver settings
- //
- /// Parameter of the world's constraint solver. Default sets of values can be
- /// automatically set using the setupSolverInfo() method by passing the required
- /// hkSolverType. See SolverType or documentation for details on customizing these values.
- hkReal m_solverTau;
- /// Parameter of the world's constraint solver. Default sets of values can be
- /// automatically set using the setupSolverInfo() method by passing the required
- /// hkSolverType. See SolverType or documentation for details on customizing these values.
- /// The default is 0.6f
- hkReal m_solverDamp; //+default(.6f)
- /// Parameter of the world's constraint solver. Default sets of values can be
- /// automatically set using the setupSolverInfo() method by passing the required
- /// hkSolverType. See SolverType or documentation for details on customizing these values.
- /// The default is 4.
- hkInt32 m_solverIterations; //+default(4)
- /// This is the number of gauss seidel steps the solver performs during each Havok step.
- /// Basically this allows for virtually increasing the number of solver steps without
- /// adding extra instability. However the microsteps are not as powerful as the main
- /// solver steps.
- /// So by default this value should be 1. Only if you wish to increase the number
- /// of solver steps to be higher than 8 and you experience stability problems,
- /// you can increase this value and leave the number of solver steps to 4 or 8.
- hkInt32 m_solverMicrosteps; //+default(1)
- /// When using multithreading, this forces the solver to process the constraints in the same
- /// order as it is done in single-treaded mode. As the result, a big part of solving is performed
- /// by a single processing unit. This will cause a noticable/significant slowdown when
- /// processing a single large island.
- ///
- /// Leaving this option off (default) may cause some random jitter.
- hkBool m_forceCoherentConstraintOrderingInSolver; //+default(false)
- //
- // Internal algorithm settings
- //
- /// This value determines when collision normals will be welded. See the user guide for details.
- /// By default this is 30 degrees. This value is only used for two sided welding, if you build
- /// one sided welding information this value is not used.
- hkReal m_snapCollisionToConvexEdgeThreshold; //+default(.524f)
- /// This value determines when collision normals will be welded. See the user guide for details.
- /// This value is only used for two sided welding, if you build one sided welding information this value is not used.
- /// By default this is 40 degrees.
- hkReal m_snapCollisionToConcaveEdgeThreshold; //+default(0.698f)
- /// This flag determines whether tois will be rejected by welding. See the user guide for details.
- /// By default this is set to false, meaning that tois will always be accepted, even if
- /// they will cause a welding artefact. If you set this to true, Tois will never produce welding artefacts,
- /// however it means that objects will be able to penetrate landscapes more easily even in continuous mode.
- /// Note that this is not an issue if you have build one sided welding information for your landscapes; in
- /// this case Tois are never rejected by setting this variable.
- hkBool m_enableToiWeldRejection; //+default(false)
- /// The recommended welding solution of versions 4.5 and later involves building welding info and storing
- /// additional data with the mesh. However, if you have not built this info, or wish to weld non-triangle
- /// based meshes, you may wish to enable the old, deprecated welding. To do so, set this flag to true.
- hkBool m_enableDeprecatedWelding; //+default(false)
- /// (Collision config) The early out distance default for Linear casts. Defaults to
- /// 0.01 units, usually about a 10th of collision tolerance so change this if you
- /// change the collision tolerance value.
- hkReal m_iterativeLinearCastEarlyOutDistance; //+default(.01f)
- /// (Collision config) The max number of iterations the Linear casts will make.
- /// Defaults to 20.
- hkInt32 m_iterativeLinearCastMaxIterations; //+default(20)
- /// Internal deactivation flag, leave at default.
- hkUint8 m_deactivationNumInactiveFramesSelectFlag0; //+default(0)
- /// Internal deactivation flag, leave at default.
- hkUint8 m_deactivationNumInactiveFramesSelectFlag1; //+default(0)
- /// Internal deactivation counter, leave at default.
- hkUint8 m_deactivationIntegrateCounter; //+default(0)
- /// This says whether bodies are to be activated when they get moved around with any
- /// of the setPositon/setRotation/setTransform calls. By default this is true.
- hkBool m_shouldActivateOnRigidBodyTransformChange; //+default(true)
- /// This is the base distance used for the deactivation check.
- /// The basic idea is that we deactivate an object if its position stays
- /// within a sphere (radius=m_deactivationReferenceDistance) for about 20 frames (high frequency deactivation).
- /// Or within a sphere (radius = 4*m_deactivationReferenceDistance) for about 80 frames (low frequency deactivation).
- /// If the object breaches this deactivation sphere, the center of the sphere is set to the current position
- /// of the object. Also the same rules apply to angular movement.
- /// Some details:
- /// - Every object is only checked every 4th frame for high frequency deactivation
- /// - Every object is only checked every 16th frame for low frequency deactivation
- /// - Just before deactivating we check the velocity again. If the velocity has significantly increased
- /// (is significantly (0.1f) bigger than 2 times the maximum velocity measured over the last 20/80 frames)
- /// we do not deactivate this object.
- /// You can set some of those values in the hkpSolverInfo (hkpWorld::getSolverInfo()) for each deactivation class after the world is constructed.
- hkReal m_deactivationReferenceDistance; //+default(0.02f)
- /// Advanced Parameter:
- /// Rotates the normal of the contact point for TOI contact point resolution.
- /// The range of this parameter should be between 0 and 1 (0.2f by default).
- /// Setting this parameter bigger than 0 simulates an extra surface roughness,
- /// thereby allowing sliding objects to get an extra separating velocity and
- /// therefore reducing the frequency of subsequent TOI.
- /// In short: Setting this parameter to >0 adds extra bounce and can greatly
- /// reduce CPU.
- hkReal m_toiCollisionResponseRotateNormal; //+default(0.2f)
- /// The maximum number of hkpAgentSector elements that will be processed by each task split-off from an hkAgentSectorJob.
- int m_maxSectorsPerCollideTask; //+default(4)
- /// If set to true (default), the continuous TOI solver will run collision detection multithreaded (used in hkMultithreadedSimulation only)
- /// If set to false, the old-style single threaded variant will be used.
- /// TOIs in general have to be solved sequentially and therefore cannot be solved multithreaded.
- /// However the collision detection part of each TOI can be parallelized and solved by different threads.
- /// As a result you should see a TOI solving speedup if a fast complicated object (e.g. listshape) hits a pile of other complicated objects.
- /// However you will not get any speedup (but rather a slow-down) if a simple object (e.g. ragdoll bone) hits another single object (e.g. landscape).
- /// You should try to experiment with that parameter to see which value suits your scenario best.
- /// Note: if you enable this flag the Havok worker threads will not be released until the stepDeltaTime() call is finished,
- /// i.e. you cannot use them for different purposes even if they are idle.
- hkBool m_processToisMultithreaded; //+default(true)
- /// The maximum number of hkpAgentNnEntry elements that will be processed by each task split-off from an hkAgentNnEntryJob.
- /// This value is only used when m_processToisMultithreaded is enabled.
- int m_maxEntriesPerToiCollideTask; //+default(1)
- /// When checking for the allowed penetration depth, Havok's collision detection will initially allow for a fixed
- /// percentage of that depth during the first TOI. The remaining penetration depth will then be subdivided into a
- /// customizable number of TOIs. This allows for tweaking 'competing' collision agents to be resolved in a way the
- /// user prefers, e.g. if the player is standing beneath a downward bound elevator platform he should preferrably
- /// tunnel through the platform than through the floor (and by this possibly getting pushed out of the world).
- /// This value defines the number of TOIs to be triggered for collisions between fast-moving, non critical objects
- /// and the landscape (COLLISION_QUALITY_SIMPLIFIED_TOI) and has to be > 1.0.
- /// The default is 3.0.
- hkReal m_numToisTillAllowedPenetrationSimplifiedToi; //+default(3.0f)
- /// This value defines the number of TOIs to be triggered for collisions between two moving objects (COLLISION_QUALITY_TOI)
- /// and has to be > 1.0.
- /// For details see m_numToisTillAllowedPenetrationSimplifiedToi.
- /// The default is 3.0.
- hkReal m_numToisTillAllowedPenetrationToi; //+default(3.0f)
- /// This value defines the number of TOIs to be triggered for collisions between a (non-critical) moving object and
- /// the landscape (COLLISION_QUALITY_TOI_HIGHER) and has to be > 1.0.
- /// For details see m_numToisTillAllowedPenetrationSimplifiedToi.
- /// The default is 4.0.
- hkReal m_numToisTillAllowedPenetrationToiHigher; //+default(4.0f)
- /// This value defines the number of TOIs to be triggered for collisions between a (critical) moving object and the
- /// landscape (COLLISION_QUALITY_TOI_FORCED) and has to be > 1.0.
- /// For details see m_numToisTillAllowedPenetrationSimplifiedToi.
- /// The default is 20.0.
- hkReal m_numToisTillAllowedPenetrationToiForced; //+default(20.0f)
- //
- // Debugging flags
- //
- /// Set to false if you want deactivation to be disabled. See the frequency settings
- /// for deactivation too.
- hkBool m_enableDeactivation; //+default(true)
- /// Simulation type. By default this is SIMULATION_TYPE_CONTINUOUS. See hkpWorld::SimulationType for more details.
- hkEnum<SimulationType, hkInt8> m_simulationType;
- /// Sets whether the world is automatically segmented into separate islands each step.
- /// This should always be enabled. The default is enabled.
- hkBool m_enableSimulationIslands; //+default(true)
- /// This parameter allows to keep the islands size reasonable large to avoid performance overhead in multi threaded simulations.
- ///
- /// Having lots of very small islands can cause some unnecessary overhead in the multithreaded simulation.
- /// (Its like rendering single triangles using a modern graphics card).
- /// Therefore we have the concept of sparse islands.
- /// These islands could in theory be split into smaller islands,
- /// however its not done and those islands are flagged with hkpSimulationIsland::m_sparseEnabled = true.
- /// But whenever an island is deactivated, it will be checked for split and only that sub island will be deactivated
- /// which is actually inactive.
- ///
- /// This parameter only works in multithreading mode, otherwise it will not be used and will be set to 0.
- hkUint32 m_minDesiredIslandSize; //+default(64)
- /// Forces actions to be processed in a single thread. If you have a multi threaded simulation and
- /// you are using actions which influence objects other then the action's entities (listed in hkpAction::getEntities(), this flag must
- /// be set to true (e.g. hkpVehicleInstance applies forces on objects laying on the ground and uses a phantom).
- hkBool m_processActionsInSingleThread; //+default(true)
- /// Snaps the frameTimeMarker to the currentPsiTime when those times are close together.
- /// By default they must be less than .0001 seconds apart to be snapped together.
- /// This synchronization of frameTime and physicsTime is performed by default, and is useful to control numerical drift when e.g.
- /// running simulation at half the frequency of the frame rate. A side effect is such that the total time of simulation may
- /// slightly vary from the sum of frameDeltaTime parameters passed to world->setFrameTimeMarker(frameDeltaTime).
- /// If you use your hkpWorld for testing and precise measurements you may prefer to disable synchronization.
- /// To do this set this variable to 0.
- hkReal m_frameMarkerPsiSnap; //+default(.0001f)
- virtual ~hkpWorldCinfo() {}
- explicit hkpWorldCinfo( hkFinishLoadedObjectFlag flag );
- };
- #endif // HKDYNAMICS_WORLD_HKWORLDCINFO_XML_H
- /*
- * Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20090216)
- *
- * Confidential Information of Havok. (C) Copyright 1999-2009
- * Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
- * Logo, and the Havok buzzsaw logo are trademarks of Havok. Title, ownership
- * rights, and intellectual property rights in the Havok software remain in
- * Havok and/or its suppliers.
- *
- * Use of this software for evaluation purposes is subject to and indicates
- * acceptance of the End User licence Agreement for this product. A copy of
- * the license is included with this software and is also available at www.havok.com/tryhavok.
- *
- */