327 lines
11 KiB
C
327 lines
11 KiB
C
|
// Redistribution and use in source and binary forms, with or without
|
||
|
// modification, are permitted provided that the following conditions
|
||
|
// are met:
|
||
|
// * Redistributions of source code must retain the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer.
|
||
|
// * Redistributions in binary form must reproduce the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer in the
|
||
|
// documentation and/or other materials provided with the distribution.
|
||
|
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||
|
// contributors may be used to endorse or promote products derived
|
||
|
// from this software without specific prior written permission.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||
|
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
//
|
||
|
// Copyright (c) 2008-2023 NVIDIA Corporation. All rights reserved.
|
||
|
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||
|
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||
|
|
||
|
#pragma once
|
||
|
/** \addtogroup vehicle2
|
||
|
@{
|
||
|
*/
|
||
|
#include "foundation/PxAssert.h"
|
||
|
#include "foundation/PxErrors.h"
|
||
|
#include "foundation/PxFoundation.h"
|
||
|
#include "PxVehicleComponent.h"
|
||
|
|
||
|
#if !PX_DOXYGEN
|
||
|
namespace physx
|
||
|
{
|
||
|
namespace vehicle2
|
||
|
{
|
||
|
#endif
|
||
|
|
||
|
|
||
|
struct PxVehicleComponentSequenceLimits
|
||
|
{
|
||
|
enum Enum
|
||
|
{
|
||
|
eMAX_NB_SUBGROUPS = 16,
|
||
|
eMAX_NB_COMPONENTS = 64,
|
||
|
eMAX_NB_SUBGROUPELEMENTS = eMAX_NB_SUBGROUPS + eMAX_NB_COMPONENTS
|
||
|
};
|
||
|
};
|
||
|
|
||
|
struct PxVehicleComponentSequence
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
eINVALID_SUBSTEP_GROUP = 0xff
|
||
|
};
|
||
|
|
||
|
PxVehicleComponentSequence()
|
||
|
: mNbComponents(0), mNbSubgroups(1), mNbSubGroupElements(0), mActiveSubgroup(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief Add a component to the sequence.
|
||
|
|
||
|
\param[in] component The component to add to the sequence.
|
||
|
\return True on success, else false (for example due to component count limit being reached).
|
||
|
*/
|
||
|
PX_FORCE_INLINE bool add(PxVehicleComponent* component);
|
||
|
|
||
|
/**
|
||
|
\brief Start a substepping group.
|
||
|
\note All components added using #add() will be added to the new substepping group until either the group
|
||
|
is marked as complete with a call to #endSubstepGroup() or a subsequent substepping group is started with
|
||
|
a call to #beginSubstepGroup().
|
||
|
\note Groups can be nested with stacked calls to #beginSubstepGroup().
|
||
|
\note Each group opened by #beginSubstepGroup() must be closed with a complementary #endSubstepGroup() prior to calling #update().
|
||
|
\param[in] nbSubSteps is the number of substeps for the group's sequence. This can be changed with a call to #setSubsteps().
|
||
|
\return Handle for the substepping group on success, else eINVALID_SUBSTEP_GROUP
|
||
|
@see setSubsteps()
|
||
|
@see endSubstepGroup()
|
||
|
*/
|
||
|
PX_FORCE_INLINE PxU8 beginSubstepGroup(const PxU8 nbSubSteps = 1);
|
||
|
|
||
|
/**
|
||
|
\brief End a substepping group
|
||
|
\note The group most recently opened with #beginSubstepGroup() will be closed by this call.
|
||
|
@see setSubsteps()
|
||
|
@see beginSubstepGroup()
|
||
|
*/
|
||
|
PX_FORCE_INLINE void endSubstepGroup()
|
||
|
{
|
||
|
mActiveSubgroup = mSubGroups[mActiveSubgroup].parentGroup;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief Set the number of substeps to perform for a specific substepping group.
|
||
|
\param[in] subGroupHandle specifies the substepping group
|
||
|
\param[in] nbSteps is the number of times to invoke the sequence of components and groups in the specified substepping group.
|
||
|
@see beginSubstepGroup()
|
||
|
@see endSubstepGroup()
|
||
|
*/
|
||
|
void setSubsteps(const PxU8 subGroupHandle, const PxU8 nbSteps)
|
||
|
{
|
||
|
PX_ASSERT(subGroupHandle < mNbSubgroups);
|
||
|
mSubGroups[subGroupHandle].nbSteps = nbSteps;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
\brief Update each component in the sequence.
|
||
|
|
||
|
\note If the update method of a component in the sequence returns false, the update process gets aborted.
|
||
|
|
||
|
\param[in] dt is the timestep of the update. The provided value has to be positive.
|
||
|
\param[in] context specifies global quantities of the simulation such as gravitational acceleration.
|
||
|
*/
|
||
|
void update(const PxReal dt, const PxVehicleSimulationContext& context)
|
||
|
{
|
||
|
PX_ASSERT(0 == mActiveSubgroup);
|
||
|
|
||
|
if (dt > 0.0f)
|
||
|
{
|
||
|
updateSubGroup(dt, context, 0, 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PxGetFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
|
||
|
"PxVehicleComponentSequence::update: The timestep must be positive!");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
enum
|
||
|
{
|
||
|
eINVALID_COMPONENT = 0xff,
|
||
|
eINVALID_SUB_GROUP_ELEMENT = 0xff
|
||
|
};
|
||
|
|
||
|
//Elements have the form of a linked list to allow traversal over a list of elements.
|
||
|
//Each element is either a single component or a subgroup.
|
||
|
struct SubGroupElement
|
||
|
{
|
||
|
SubGroupElement()
|
||
|
: childGroup(eINVALID_SUBSTEP_GROUP),
|
||
|
component(eINVALID_COMPONENT),
|
||
|
nextElement(eINVALID_SUB_GROUP_ELEMENT)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
PxU8 childGroup;
|
||
|
PxU8 component;
|
||
|
PxU8 nextElement;
|
||
|
};
|
||
|
|
||
|
//A group is a linked list of elements to be processed in sequence.
|
||
|
//Each group stores the first element in the sequence.
|
||
|
//Each element in the sequence stores the next element in the sequence
|
||
|
//to allow traversal over the list of elements in the group.
|
||
|
struct Group
|
||
|
{
|
||
|
Group()
|
||
|
: parentGroup(eINVALID_SUBSTEP_GROUP),
|
||
|
firstElement(eINVALID_SUB_GROUP_ELEMENT),
|
||
|
nbSteps(1)
|
||
|
{
|
||
|
}
|
||
|
PxU8 parentGroup;
|
||
|
PxU8 firstElement;
|
||
|
PxU8 nbSteps;
|
||
|
};
|
||
|
|
||
|
PxVehicleComponent* mComponents[PxVehicleComponentSequenceLimits::eMAX_NB_COMPONENTS];
|
||
|
PxU8 mNbComponents;
|
||
|
|
||
|
Group mSubGroups[PxVehicleComponentSequenceLimits::eMAX_NB_SUBGROUPS];
|
||
|
PxU8 mNbSubgroups;
|
||
|
|
||
|
SubGroupElement mSubGroupElements[PxVehicleComponentSequenceLimits::eMAX_NB_SUBGROUPELEMENTS];
|
||
|
PxU8 mNbSubGroupElements;
|
||
|
|
||
|
PxU8 mActiveSubgroup;
|
||
|
|
||
|
bool updateSubGroup(const PxReal dt, const PxVehicleSimulationContext& context, const PxU8 groupId, const PxU8 parentSepMultiplier)
|
||
|
{
|
||
|
const PxU8 nbSteps = mSubGroups[groupId].nbSteps;
|
||
|
const PxU8 stepMultiplier = parentSepMultiplier * nbSteps;
|
||
|
const PxReal timestepForGroup = dt / PxReal(stepMultiplier);
|
||
|
for (PxU8 k = 0; k < nbSteps; k++)
|
||
|
{
|
||
|
PxU8 nextElement = mSubGroups[groupId].firstElement;
|
||
|
while (eINVALID_SUB_GROUP_ELEMENT != nextElement)
|
||
|
{
|
||
|
const SubGroupElement& e = mSubGroupElements[nextElement];
|
||
|
PX_ASSERT(e.component != eINVALID_COMPONENT || e.childGroup != eINVALID_SUBSTEP_GROUP);
|
||
|
if (eINVALID_COMPONENT != e.component)
|
||
|
{
|
||
|
PxVehicleComponent* c = mComponents[e.component];
|
||
|
if (!c->update(timestepForGroup, context))
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PX_ASSERT(eINVALID_SUBSTEP_GROUP != e.childGroup);
|
||
|
if (!updateSubGroup(dt, context, e.childGroup, stepMultiplier))
|
||
|
return false;
|
||
|
}
|
||
|
nextElement = e.nextElement;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
PxU8 getLastKnownElementInGroup(const PxU8 groupId) const
|
||
|
{
|
||
|
PxU8 currElement = mSubGroups[groupId].firstElement;
|
||
|
PxU8 nextElement = mSubGroups[groupId].firstElement;
|
||
|
while (nextElement != eINVALID_SUB_GROUP_ELEMENT)
|
||
|
{
|
||
|
currElement = nextElement;
|
||
|
nextElement = mSubGroupElements[nextElement].nextElement;
|
||
|
}
|
||
|
return currElement;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
bool PxVehicleComponentSequence::add(PxVehicleComponent* c)
|
||
|
{
|
||
|
if (PxVehicleComponentSequenceLimits::eMAX_NB_COMPONENTS == mNbComponents)
|
||
|
return false;
|
||
|
if (PxVehicleComponentSequenceLimits::eMAX_NB_SUBGROUPELEMENTS == mNbSubGroupElements)
|
||
|
return false;
|
||
|
|
||
|
//Create a new element and point it at the component.
|
||
|
SubGroupElement& nextElementInGroup = mSubGroupElements[mNbSubGroupElements];
|
||
|
nextElementInGroup.childGroup = eINVALID_SUBSTEP_GROUP;
|
||
|
nextElementInGroup.component = mNbComponents;
|
||
|
nextElementInGroup.nextElement = eINVALID_SUB_GROUP_ELEMENT;
|
||
|
|
||
|
if (eINVALID_SUB_GROUP_ELEMENT == mSubGroups[mActiveSubgroup].firstElement)
|
||
|
{
|
||
|
//The group is empty so add the first element to it.
|
||
|
//Point the group at the new element because this will
|
||
|
//be the first element in the group.
|
||
|
mSubGroups[mActiveSubgroup].firstElement = mNbSubGroupElements;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//We are extending the sequence of element of the group.
|
||
|
//Add the new element to the end of the group's sequence.
|
||
|
mSubGroupElements[getLastKnownElementInGroup(mActiveSubgroup)].nextElement = mNbSubGroupElements;
|
||
|
}
|
||
|
|
||
|
//Increment the number of elements.
|
||
|
mNbSubGroupElements++;
|
||
|
|
||
|
//Record the component and increment the number of components.
|
||
|
mComponents[mNbComponents] = c;
|
||
|
mNbComponents++;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
PxU8 PxVehicleComponentSequence::beginSubstepGroup(const PxU8 nbSubSteps)
|
||
|
{
|
||
|
if (mNbSubgroups == PxVehicleComponentSequenceLimits::eMAX_NB_SUBGROUPS)
|
||
|
return eINVALID_SUBSTEP_GROUP;
|
||
|
if (mNbSubGroupElements == PxVehicleComponentSequenceLimits::eMAX_NB_SUBGROUPELEMENTS)
|
||
|
return eINVALID_SUBSTEP_GROUP;
|
||
|
|
||
|
//We have a parent and child group relationship.
|
||
|
const PxU8 parentGroup = mActiveSubgroup;
|
||
|
const PxU8 childGroup = mNbSubgroups;
|
||
|
|
||
|
//Set up the child group.
|
||
|
mSubGroups[childGroup].parentGroup = parentGroup;
|
||
|
mSubGroups[childGroup].firstElement = eINVALID_SUB_GROUP_ELEMENT;
|
||
|
mSubGroups[childGroup].nbSteps = nbSubSteps;
|
||
|
|
||
|
//Create a new element to add to the parent group and point it at the child group.
|
||
|
SubGroupElement& nextElementIInGroup = mSubGroupElements[mNbSubGroupElements];
|
||
|
nextElementIInGroup.childGroup = childGroup;
|
||
|
nextElementIInGroup.nextElement = eINVALID_SUB_GROUP_ELEMENT;
|
||
|
nextElementIInGroup.component = eINVALID_COMPONENT;
|
||
|
|
||
|
//Add the new element to the parent group.
|
||
|
if (eINVALID_SUB_GROUP_ELEMENT == mSubGroups[parentGroup].firstElement)
|
||
|
{
|
||
|
//The parent group is empty so add the first element to it.
|
||
|
//Point the parent group at the new element because this will
|
||
|
//be the first element in the group.
|
||
|
mSubGroups[parentGroup].firstElement = mNbSubGroupElements;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//We are extending the sequence of elements of the parent group.
|
||
|
//Add the new element to the end of the group's sequence.
|
||
|
mSubGroupElements[getLastKnownElementInGroup(parentGroup)].nextElement = mNbSubGroupElements;
|
||
|
}
|
||
|
|
||
|
//Push the active group.
|
||
|
//All subsequent operations will now address the child group and we push or pop the group.
|
||
|
mActiveSubgroup = childGroup;
|
||
|
|
||
|
//Increment the number of elements.
|
||
|
mNbSubGroupElements++;
|
||
|
|
||
|
//Increment the number of groups.
|
||
|
mNbSubgroups++;
|
||
|
|
||
|
//Return the group id.
|
||
|
return mActiveSubgroup;
|
||
|
}
|
||
|
|
||
|
#if !PX_DOXYGEN
|
||
|
} // namespace vehicle2
|
||
|
} // namespace physx
|
||
|
#endif
|
||
|
|
||
|
/** @} */
|