diff options
Diffstat (limited to 'docs/_source/api_hl_users_guide.txt')
| -rwxr-xr-x[-rw-r--r--] | docs/_source/api_hl_users_guide.txt | 1410 |
1 files changed, 705 insertions, 705 deletions
diff --git a/docs/_source/api_hl_users_guide.txt b/docs/_source/api_hl_users_guide.txt index ae8dd4a..34d843e 100644..100755 --- a/docs/_source/api_hl_users_guide.txt +++ b/docs/_source/api_hl_users_guide.txt @@ -1,705 +1,705 @@ -/*! \page pagehlapi High Level (Toolkit) API (NvBlastTk) - -<b>Table of Contents</b> - -\subpage tkintroduction - -\subpage tk_class_hierarchy - -\subpage tk_include_and_library - -\subpage framework_init - -\subpage tkasset_creation - -\subpage tkasset_instancing - -\subpage tkgroups - -\subpage damage_in_tk - -\subpage tkjoints - -\subpage tkevents - -\subpage tktypes - -<br> -\section tkintroduction Introduction to NvBlastTk - -The high-level API, NvBlastTk (Tk stands for "toolkit"), is intended to be a more powerful library and a much more convenient entry point -into the use of Blast&tm;. Like the low-level library, Tk is physics and graphics-agnostic. Whereas the low-level API is C-style, Tk uses -a C++ API. Everything in Tk is in the namespace: - -\code -Nv::Blast -\endcode - -(the only exceptions are global-scope functions to create and access a framework singleton, see below). -Every object in Tk is prefixed with 'Tk'. For example, the Tk framework interface is: - -\code -Nv::Blast::TkFramework -\endcode - -<b> -For the remainder of this page we will be in the Nv::Blast namespace, and will drop the explicit scope Nv::Blast:: from our names. -</b> -<br> -<br> - - -BlastTk adds: - -- An object class hierarchy (see \ref tk_class_hierarchy, below). -- A global framework, <b>TkFramework</b> (a singleton). This keeps track of <b>TkIdentifiable</b> objects and allows -the user to query them based upon either GUID or <b>TkIdentifiable</b> subclass type, and also provides a number of functions to create the various objects in BlastTk. -- Processing groups with a task interface (see <b>TkGroup</b>). -- Event dispatching for actor families (see <b>TkFamily</b>). -- Intra-actor and inter-actor joint management (see <b>TkJoint</b>). Note, these "joints" only hold descriptor data, since physical objects are not handled by BlastTk. - -<br> -\section tk_class_hierarchy NvBlastTk Class Hierarchy - -- There are two abstract interfaces, one of which deriving from the other: <b>TkObject <- TkIdentifiable</b>. - - Lightweight objects are derived from <b>TkObject</b>. - - Objects which use a GUID and class identification are derieved from <b>TkIdentifiable</b>. -- <b>TkAsset</b> derives from <b>TkIdentifiable</b>. This is mostly a wrapper for NvBlastAsset, however it also stores -extra data associated with the asset such as internal joint descriptors. -- <b>TkFamily</b> derives from <b>TkIdentifiable</b>. One of these objects is made when a <b>TkActor</b> is instanced -from a <b>TkAsset</b>. All actors that are created by splitting the family's original actor remain within the same family. Actor and joint -events are dispatched from the <b>TkFamily</b>. -- <b>TkGroup</b> derives from <b>TkIdentifiable</b>. Groups are processing units. The user may create as many groups as they please, and add -or remove actors as they please from groups. The group provides a worker (TkGroupWorker) interface which allows the user to process multiple -jobs in the group asynchoronously. These jobs, along with a call to TkGroup::endProcess(), perform the tasks of generating fracture commands, -applying fracture commands, and actor splitting at the low-level. The user is informed of splitting through listeners given to TkFamily objects. -- <b>TkActor</b> derives from <b>TkObject</b>. It is mostly a wrapper for NvBlastActor, but it also provides a number of damage functions -to the user. -- <b>TkJoint</b> derives from <b>TkObject</b>. <b>TkAsset</b> descriptors, cause internal <b>TkJoint</b> obejcts to be created within an actor -(joining chunks within the same actor). Alternatively, the TkFramework provides a function which allows the user to create an external joint -between any two different actors. As actors split, internal joints may become external. The user gets notification whenever joints become -external, or when actors joined by joints change or are deleted, through listeners attached to the associated TkFamily objects. - -<br> -\section tk_include_and_library Linking and Header Files - -To use the BlastTk library, the application need only inlclude the header NvBlastTk.h, found in the <b>include/toolkit</b> folder, and link -against the appropriate version of the NvBlastTk library. Depending on the platform and configuration, various suffixes will be added to the library -name. The general naming scheme is - -NvBlastTk(config)(arch).(ext) - -(config) is DEBUG, CHECKED, OR PROFILE for the corresponding configurations. For a release configuration there is no (config) suffix. - -(arch) is _x86 or _x64 for Windows 32- and 64-bit builds, respectively, and empty for non-Windows platforms. - -(ext) is .lib for static linking and .dll for dynamic linking on Windows. On XBoxOne it is .lib, and on PS4 it is .a. - - -<br> -\section framework_init Creating the TkFramework - -As a reminder, in this document we assume we are in the Nv::Blast namespace: - -\code -using namespace Nv::Blast; -\endcode - -In order to use NvBlastTk, one first has to create a TkFramework singleton. This simply requires a call -to the global function NvBlastTkFrameworkCreate: - -\code -TkFramework* framework = NvBlastTkFrameworkCreate(); -\endcode - -The framework may be accessed via: - -\code -TkFramework* framework = NvBlastTkFrameworkGet(); -\endcode - -In the sections that follow, it is assumed that a framework has been created, and we have a pointer to it named 'framework' within scope. - -Finally, to release the framework, use - -\code -framework->release(); -\endcode - -This will release all assets, families, actors, joints, and groups. - -<br> -\section tkasset_creation Creating a TkAsset - -The TkAsset object is a high-level wrapper for the low-level NvBlastAsset (see \ref assets). The descriptor used to create a TkAsset, a TkAssetDesc, is derived from -NvBlastAssetDesc. The base fields should be filled in as described in (\ref assets). The new field is an optional array of flags to be associated with each bond in -the base descriptor. Currently the only flag is "BondJointed," and if set will cause an "internal joint" to be created in actors (TkActor type) created from the asset. -See (\ref tkjoints) for more on joints in BlastTk. - -\code -TkAssetDesc desc; - -myFunctionToFillInLowLevelAssetFields(desc); // Fill in the low-level (NvBlastAssetDesc) fields as usual - -std::vector<uint8_t*> bondFlags(desc.bondCount, 0); // Clear all flags - -// Set BondJointed flags corresponding to joints selected by the user (assumes a myBondIsJointedFunction to make this selection) -for (uint32_t i = 0; i < desc.bondCount; ++i) -{ - if (myBondIsJointedFunction(i)) // User-authored - { - bondFlags[i] |= TkAssetDesc::BondJointed; - } -} - -TkAsset* asset = framework->createAsset(desc); // Create a new TkAsset -\endcode - -The createAsset function used above creates a low-level NvBlastAsset from the base fields of the descriptor, and then adds internal joint descriptors based -upon the bonds' centroids and attached chunks. An alternative method to create a TkAsset allows the user to pass in a pre-existing NvBlastAsset, and a list -of joint descriptors. If the TkAsset is to have no internal joints, then the joint descriptors are not necessary and with an NvBlastAsset -pointer <b>llAsset</b>, a TkAsset may be created simply by using - -\code -TkAsset* asset = framework->createAsset(llAsset); -\endcode - -By default, such a TkAsset will not "own" the llAsset. When the TkAsset is released, the llAsset memory will be untouched. You can pass ownership to the -TkAsset using all of the default parameters of the createAsset function: - -\code -TkAsset* asset = framework->createAsset(llAsset, nullptr, 0, true); -\endcode - -The last parameter sets ownership. N.B.: in order for the TkAsset to own the underlying llAsset, and therefore release it when the TkAsset is released, -the memory for the llAsset must be allocated using the allocator accessed through NvBlastGlobals (see \ref pageglobalsapi). - -If one wants to author internal joints in a TkAsset using this second createAsset method, one must pass in a valid array of joint descriptors of type -TkAssetJointDesc. Each joint descriptor takes two positions and two node indices. The positions are the joint's attachment positions in asset space, and -the nodes indices are those of the graph nodes that correspond to support chunks. These indices are not, in general, the same as the chunk indices. -An example of initialization of the joint descriptors is given below. - -\code -std::vector<TkAssetJointDesc> jointDescs(jointCount); // Assume jointCount = the number of joints to add -jointDescs[0].nodeIndices[0] = 0; // Attach node 0 to node 1 -jointDescs[0].nodeIndices[1] = 1; -jointDescs[0].attachPoistions[0] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); // Attachment positions are often the same within an asset, but they don't have to be -jointDescs[0].attachPoistions[1] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); -// ... etc. - -TkAsset* asset = framework->createAsset(llAsset, jointDescs.data(), jointDescs.size()); -\endcode - -The code above assumes you know the support graph nodes to which you'd like to attach joints. Often, the user only knows the corresponding chunk indices. -Fortunately it's easy to map chunk indices to graph node indices. In order to get the map, use the low-level function - -\code -const uint32_t map = NvBlastAssetGetChunkToGraphNodeMap(llAsset, logFn); -\endcode - -This map is an array with an entry for every chunk index. To get the graph node index for a chunk indexed <b>chunkIndex</b>, use - -\code -uint32_t nodeIndex = map[chunkIndex]; -\endcode - -If the chunk indexed by <b>chunkIndex</b> does <em>not</em> correspond to a support chunk, then the mapped value will be UINT32_MAX, the invalid index. -Otherwise, the mapped value will be a valid graph node index. - -Finally, to release a TkAsset, as with any TkObject-derived object, use the release() method: - -\code -asset->release(); -\endcode - -<br> -\section tkasset_instancing Instancing a TkAsset: Creation of a TkActor and a TkFamily - -Whereas with the Blast&tm; low-level (\ref pagellapi), one must explicitly create a family (NvBlastFamily) from an asset (NvBlastAsset) before creating -the first actor (NvBlastActor) in the family, NvBlastTk creates a TkFamily automatically when an unfractured TkActor is instanced from a TkAsset using -the framework's createActor function. This family is accessible through the actor and any actor that is created from splitting it. The family is -<em>not</em> released automatically when all actors within it have been released. The user must use the TkFamily's release() method (see TkObject base -API) to do so. (Or wait until the framework is released.) If a family is released that contains actors, the actors within will be released as well. - -The TkFamily has a special role in NvBlastTk, holding user-supplied event listeners (\ref TkEventListener). All <em>internal</em> actor creation and destruction -events are broadcast to listeners through split events (TkSplitEvent). These signal when a fracturing operation has destroyed an actor and created -child actors from it. TkActor creation or release that occurs from an explicit API call do not produce events. For example when creating a first unfractured -instance of an asset using createAsset, or when calling the release() method on a TkActor. TkJoint events are similarly broadcast to -receivers (TkJointEvent). These signal when the actors which are joined by the joints change, so that the user may update a corresponding physical joint. -They also signal when a joint no longer attaches actors and is therefore unreferenced. The user may invalidate or release the joint using the TkObject -release() method when this occurs (more on joint ownership in \ref tkjoints). - -To create an unfractured TkActor instance from a TkAsset, one first fills in a descriptor (\ref TkActorDesc) and passes it to the framework's createActor function. -As with the TkAssetDesc, the TkActorDesc is derived from its low-level counterpart, the NvBlastActorDesc. In addition the TkActorDesc holds a pointer to -the TkAsset being instanced. An example of TkActor creation is given below, given a TkAsset pointer <b>asset</b>. - -\code -TkActorDesc desc; // The TkActorDesc constructor sets sane default values for the base (NvBlastActorDesc) fields, giving uniform chunk and bond healths of 1.0. -desc.asset = asset; // This field of TkActorDesc must be set to a valid asset pointer. - -TkActor* actor = framework->createActor(desc); -\endcode - -The TkFamily created with the actor above may be accessed through the actor's getFamily field: - -\code -TkFamily& family = actor->getFamily(); -\endcode - -The returned value is a reference since a TkActor's family can never be NULL. Actors resulting from the split of a "parent" actor will always belong to the -parent's family. - -For most applications, the user will need to create a listener object to pass to every family created, in order to keep their physics and graphics representations -in sync with the splitting of the TkActor. For more on this, see \ref tkevents. - -<br> -\section tkgroups Groups - -One important feature of NvBlastTk is the ability to multitask damage processing. The mechanism by which the toolkit does this is the group object, TkGroup. -Groups are created at the request of the user; the user may create as many groups as he or she likes. Actors may be added or removed from groups in any way the -user wishes, with the only constraint being that a given actor may belong to no more than one group. A group is a processing object, much like a scene in a physics -simulation. Indeed, a natural pattern would be to associate one group per physics scene, and synchronize the group processing with scene simulation. Another -pattern would be to subdivide the world into neighborhoods, and associate each neighborhood with a group. A distributed game could take advantage of this structure -to similarly distribute computation. - -Group processing is performed by <em>workers</em>, which have a TkGroupWorker API exposed to the user. The number of workers may be set by the user, with the idea being -that this should correspond to the number of threads available for group processing. Processing starts with a call to TkGroup::startProcess(). This creates a number -of jobs which the user may assign to workers as they like, each worker potentially on its own thread. The jobs calculate the effects of all damage taken -by the group's actors. After all jobs have been run, the user must call TkGroup::endProcess(). This will result in all events being fired off to listeners associated -with families with actors in the group. - -A convenience function, TkGroup::process(), is provided which uses one worker to perform all jobs sequentially on the calling thread. This is useful shortcut to -get BlastTk up and running quickly. A multithreaded group processing implementation is given by Nv::Blast::ExtGroupTaskManager (in NvBlastExtPxTask.h). -This resides in \ref pageextphysx, because it uses physx::PxTask. - -Actors resulting from the split of a "parent" actor will be placed automatically into the group that the parent belonged to. This is similar to the assigment of -families from a split, except that unlike families, the user then has the option to move the new actors to other groups, or no group at all. - -Also similar to families, groups are not automatically released when the last actor is removed from it. Unlike families, when a group is released, the actors which -belong to the group are <em>not</em> released. They will, however, be removed from the group before the release is complete. - -A typical usage is outlined below. See \ref damage_in_tk for methods of applying damage to actors. - -\code -// Create actors from descriptors desc1, desc2, ... etc., and attach a listener to each new family created -TkActor* actor1 = framework->createActor(desc1); -actor1->getFamily().addListener(gMyReceiver); // gMyReceiver is a TkEventListener-derived object. More on events in a subsequent section. -TkActor* actor2 = framework->createActor(desc2); -actor2->getFamily().addListener(gMyReceiver); -TkActor* actor3 = framework->createActor(desc3); -actor3->getFamily().addListener(gMyReceiver); -// etc... - -// Let's create two groups. First, create a group descriptor. This may be used to create both groups. -TkGroupDesc groupDesc; -groupDesc.workerCount = 1; // this example processes groups on the calling thread only - -// Now create the groups -TkGroup* group1 = framework->createGroup(groupDesc); -TkGroup* group2 = framework->createGroup(groupDesc); - -// Add actor1 and actor2 to group1, and actor2 to group3... -group1->addActor(actor1); -group1->addActor(actor2); -group2->addActor(actor3); -// etc... - -// Now apply damage to all actors - *NOTE* damage is described in detail in the next section. -// For now we will just assume a "myDamageFunction" to apply the damage. -myDamageFunction(actor1); -myDamageFunction(actor2); -myDamageFunction(actor3); -// etc... - -// Calling the groups' process functions will (synchronously) run all jobs to process damage taken by the contained actors. -group1->process(); -group2->process(); - -// When the groups are no longer needed, they may be released with the usual release method. -group1->release(); -group2->release(); -\endcode - -<br> -<b>Multithreaded processing</b> - -When distributing the jobs as mentioned above, every job must be processed exactly once (over all user tasks). - -The number of jobs processed per worker can range from a single job (resulting in a user task per job) to all jobs (like Nv::Blast::TkGroup::process() does). - -At any point in time, no more than the set workerCount amount of workers may have been acquired. Return the worker at the end of each task. - -\code -Nv::Blast::TkGroupWorker* worker = group->acquireWorker(); -// process some jobs -group->returnWorker(worker); -\endcode - -<br> -\section damage_in_tk Applying Damage to Actors and Families - -Damage in NvBlastTk uses the same damage program scheme as the low-level SDK (see \ref splitting). One passes the program -(NvBlastDamageProgram), damage descriptor (program-dependent), and material (also program-dependent) to a TkActor::damage -function. Ultimately, the damage descriptor and material data are all parameters used by the damage program. The distinction -is that the damage descriptor should describe properties of the thing doing the damage, while the material should -describe properties of the actor (the thing being damaged). The interpretation of this data is entirely up to the program's -functions, however. - -For convenience, the user may set a default material in the actor's family. This assumes, of course, that the material parameters -for this default are compatible with the program being used to damage the family's actors. - -Examples of the three TkActor damage methods are given below. - -<br> -\subsection multiple_damage Multiple Damage Descriptors using NvBlastProgramParams - -<b>N.B. - with this method of damage, the lifetime of the NvBlastProgramParams <em>must</em> extend at -least until the TkGroup::endProcess call for the actor.</b> - -\code -NvBlastDamageProgram program = -{ - myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature - mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature -}; - -// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension -RadialDamageDesc damageDescs[2]; - -damageDescs[0].compressive = 10.0f; -damageDescs[0].position[0] = 1.0f; -damageDescs[0].position[1] = 2.0f; -damageDescs[0].position[2] = 3.0f; -damageDescs[0].minRadius = 0.0f; -damageDescs[0].maxRadius = 1.0f; - -damageDescs[1].compressive = 100.0f; -damageDescs[1].position[0] = 3.0f; -damageDescs[1].position[1] = 4.0f; -damageDescs[1].position[2] = 5.0f; -damageDescs[1].minRadius = 0.0f; -damageDescs[1].maxRadius = 5.0f; - -// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension -Material material; - -material.health = 10.0f; -material.minDamageThreshold = 0.1f; -material.maxDamageThreshold = 0.8f; - -// Set the damage params struct -NvBlastProgramParams params = { damageDescs, 2, &material }; - -// Apply damage -actor->damage(program, ¶ms); // params must be kept around until TkGroup::endProcess is called! -\endcode - -<br> -\subsection single_damage_desc_default_material Single Damage Descriptor with Default TkFamily Material - -This method of damage copies the damage descriptor into a buffer, so the user need <em>not</em> hold onto -a copy after the damage function call. Only one damage descriptor may be passed in at once. - -To use this method, the user must first set a default material in the actor's family. For example: - -\code -// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension -Material material; - -material.health = 10.0f; -material.minDamageThreshold = 0.1f; -material.maxDamageThreshold = 0.8f; - -// Set the default material used by the material-less TkActor::damage call -actor->getFamily().setMaterial(&material); -\endcode - -<b>N.B. the lifetime of the material set <em>must</em> extend at least until the TkGroup::endProcess call for the actor.</b> - -Then to apply damage, use: - -\code -NvBlastDamageProgram program = -{ - myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature - mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature -}; - -// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension -RadialDamageDesc damageDesc; - -damageDesc.compressive = 10.0f; -damageDesc.position[0] = 1.0f; -damageDesc.position[1] = 2.0f; -damageDesc.position[2] = 3.0f; -damageDesc.minRadius = 0.0f; -damageDesc.maxRadius = 1.0f; - -// Apply damage -actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc)); -\endcode - -<br> -\subsection single_damage_desc_with_material Single Damage Descriptor with Specified Material - -This method is just like the one above, except that the user has the opportunity to override the material used during damage. - -<b>N.B. - the lifetime of the material passed in <em>must</em> extend at least until the TkGroup::endProcess call for the actor.</b> - -This call is just like the one above with an extra material parameter: - -\code -actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc), &material); -\endcode - -<br> -\section tkjoints Joints - -Joints in NvBlastTk are abstract representations of physical joints. When joints become active, change the actors they join, -or become unreferenced (the actors they join disappear), the user will receive notification via a TkJointUpdateEvent -(see \ref tkevents). - -Joints may be defined as a part of a TkAsset, in which case they are consisdered "internal" joints. (See \ref tkasset_creation.) -Since the first instance of a TkAsset is a single TkActor, internal joints are defined between chunks within the same actor. -Therefore they are not active (there is no point in joining two locations in a single rigid body). Upon splitting into multiple -actors, however, an internal joint's chunks may now belong to two different TkActors. When this happens, the user will receive a -TkJointUpdateEvent of subtype TkJointUpdateEvent::External. The event contains a pointer to the TkJoint, and from that the user -has access to the information needed to create a physical joint between the rigid bodies that correspond to the joined TkActors. - -Joints may also be created externally at runtime, using the TkFramework::createJoint function. A joint created this way must -be between two different TkActors. Because of this, the joint is immediately considered active, and so no TkJointUpdateEvent -is generated from its creation. The user should create a physical joint to correspond to the joint returned by createJoint. -An externally created joint of this type has another distinguishing characteristic: it may join an actor to "the world," or -"Newtonial Reference Frame" (NRF). To do this, one TkFamily pointer in the joint descriptor is set to NULL. Examples are -given below. - -\code -TkJointDesc desc; -desc.families[0] = &actor0->getFamily(); // Assume we have a valid actor0 pointer -desc.chunkIndices[0] = 1; // This chunk *must* be a support chunk in the asset that created desc.families[0] -desc.attachPositions[0] = physx::PxVec3(1.0f, 2.0f; 3.0f); // The attach position is in asset space -desc.families[1] = &actor1->getFamily(); // Assume we have a valid actor1 pointer... note, actor0 and actor1 could have the same family -desc.chunkIndices[1] = 10; // This chunk *must* be a support chunk in the asset that created desc.families[1] -desc.attachPositions[1] = physx::PxVec3(4.0f, 5.0f; 6.0f); // The attach position is in asset space - -// Create the external joint from the descriptor, which joins actor0 and actor1 -TkJoint* joint = framework->createJoint(desc); - -// Now join actor0 to the NRF -// desc.families[0] already contains actor0's family -desc.chunkIndices[0] = 2; // Again, this chunk must be a support chunk in the asset that created desc.families[0] -desc.attachPositions[0] = physx::PxVec3(0.0f, 0.0f; 0.0f); // The attach position is in asset space -desc.families[1] = nullptr; // Setting the family to NULL designates the world (NRF) -// The value of desc.chunkIndices[1] is not used, since desc.families[1] is NULL -desc.attachPositions[1] = physx::PxVec3(0.0f, 0.0f, 10.0f); // Attach position in the world - -// Create the external joint which joins actor0 to the world -TkJoint* jointNRF = framework->createJoint(desc); -\endcode - -<br> -\subsection releasing_joints Releasing Joints - -TkJoints are not released by Blast&tm;, except when the TkFramework is released. Otherwise, the user is responsible for -releasing TkJoints after they become unreferenced. This is facilitated by the Unreferenced subtype of the TkJointUpdateEvent. After -receiving this event for joint, the user may choose to release, using the typical TkObject::release() method. - -\code -joint->release(); -\endcode - -Note, this method can be called <em>at any time</em>, even before the joint is unreferenced. When called, it will remove its -references to its attached actors first, causing the joint to then become unreferenced. For example, if the user wishes to break -a physical joint in their simulation, they can then release the corresponding TkJoint. - -It should be mentioned, however, that joints created with an asset are allocated differently from external joints created using -TkFramework::createJoint. Internal joints created from the joint descriptors in a TkAsset are <em>block allocated</em> with every -TkFamily that instances the asset. Calling the release() method on those joints will remove any remaining references to them -(as mentioned above), but will not perform any deallocation. Only when the TkFamily itself is released will the internal joint -memory for that family be released. <b>This is true even if the internal joints become "external" from actor splitting.</b> Joints -that <em>become</em> external are still associated with a single family and their memory still resides with that family. - -On the other hand, joints that start out life external by way of the TkFramework::createJoint function have a separate allocation, -and do not have memory tied to any TkFamily (even if both actors joined are in the same family). Releasing a family holding one -of the actors in such a "purely external" joint will trigger a TkJointUpdateEvent of subtype Unreferenced, however, signalling that -the joint is ready for user release. - -<br> -\section tkevents Events - -NvBlastTk uses events to communicate the results of actor splitting, joint updates from actor splitting, and fracture event buffers -that can be used to synchronize fracturing between multiple clients. - -Events are broadcast to listeners which implement the TkEventListener interface. Listeners are held by TkFamily objects. During -a TkGroup::endProcess call (see \ref tkgroups), relevant events are broadcast to the listeners in the families associated with the actors -in the group. - -A typical user's receiver implementation might take on the form shown below. - -\code -class MyActorAndJointListener : public TkEventListener -{ - // TkEventListener interface - void receive(const TkEvent* events, uint32_t eventCount) override - { - // Events are batched into an event buffer. Loop over all events: - for (uint32_t i = 0; i < eventCount; ++i) - { - const TkEvent& event = events[i]; - - // See TkEvent documentation for event types - switch (event.type) - { - case TkSplitEvent::EVENT_TYPE: // A TkActor has split into smaller actors - { - const TkSplitEvent* splitEvent = event.getPayload<TkSplitEvent>(); // Split event payload - - // The parent actor may no longer be valid. Instead, we receive the information it held - // which we need to update our app's representation (e.g. removal of the corresponding physics actor) - myRemoveActorFunction(splitEvent->parentData.family, splitEvent->parentData.index, splitEvent->parentData.userData); - - // The split event contains an array of "child" actors that came from the parent. These are valid - // TkActor pointers and may be used to create physics and graphics representations in our application - for (uint32_t j = 0; j < splitEvent->numChildren; ++j) - { - myCreateActorFunction(splitEvent->children[j]); - } - } - break; - - case TkJointUpdateEvent::EVENT_TYPE: - { - const TkJointUpdateEvent* jointEvent = event.getPayload<TkJointUpdateEvent>(); // Joint update event payload - - // Joint events have three subtypes, see which one we have - switch (jointEvent->subtype) - { - case TkJointUpdateEvent::External: - myCreateJointFunction(jointEvent->joint); // An internal joint has been "exposed" (now joins two different actors). Create a physics joint. - break; - case TkJointUpdateEvent::Changed: - myUpdatejointFunction(jointEvent->joint); // A joint's actors have changed, so we need to update its corresponding physics joint. - break; - case TkJointUpdateEvent::Unreferenced: - myDestroyJointFunction(jointEvent->joint); // This joint is no longer referenced, so we may delete the corresponding physics joint. - break; - } - } - - // Unhandled: - case TkFractureCommands::EVENT_TYPE: - case TkFractureEvents::EVENT_TYPE: - default: - break; - } - } - } -}; -\endcode - -Whenever a new TkActor is created by the user (via TkFramework::createActor, see \ref tkasset_instancing), its newly-made family should -be given whatever listeners the user wishes to attach. For example, - -\code -TkActor* actor = framework->createActor(actorDesc); - -actor->getFamily().addListener(myListener); // myListener is an object which implements TkEventListener (see MyActorAndJointListener above, for example) -\endcode - -Listeners may also be removed from families at any time. - -<br> -\section tktypes Object and Type Identification - -NvBlastTk objects that are derived from TkIdentifiable (TkAsset, TkFamily, and TkGroup) support an object and class (type) identification -system. The TkIdentifiable interfaces setID and getID allow the user to set and access an NvBlastID for each object. The NvBlastID -is a 128-bit identifier. TkIdentifiable objects are tracked by the TkFramework, which may be used to look up an object by its NvBlastID. - -Upon creation, TkIdentifiable objects are given a GUID, a unique NvBlastID. The user is welcome to change the object's guid at any time, with -the restriction that the GUID cannot be all zero bytes. - -With an object's GUID, one may look up the object using the TkFramework function findObjectByID: - -\code -TkIdentifiable* object = framework->findObjectByID(id); // id = an NvBlastID GUID -\endcode - -If the object is found, a non-NULL pointer will be returned. - -TkIdentifiable-derived classes also have a class identification system, the TkType interface. From an individual object one may use the -TkIdentifiable interface getType to access the class's TkType interface. Alternatively, one may use the TkFramework getType function -with TkTypeIndex::Enum argument. For example, to get the TkType interface for the TkAsset class, use - -\code -const TkType* assetType = framework->getType(TkTypeIndex::Asset); -\endcode - -The type interface may be used: - - - to access class-specific object lists in the framework, - - identify the class of a TkIdentifiable obtained through ID lookup or deserialization, or - - to obtain the class's name and format version number. - -For example, to access a list of all families: - -\code -// Get the TkFamily type interface -const TkType* familyType = framework->getType(TkTypeIndex::Family); - -// Get the family count to allocate a buffer -const uint32_t familyCount = framework->getObjectCount(familyType); -std::vector<TkIdentifiable*> families(familyCount); - -// Write the families to the buffer -const uint32_t familiesFound = framework->getObjects(families.data(), familyCount, familyType); -\endcode - -In the above code, the values of familyCount and familiesFound should be equal. An alternative usage of TkFramework::getObjects allows the -user to write to a (potentially) smaller buffer, iteratively. For example: - -\code -uint32_t familiesFound; -uint32_t totalFamilyCount = 0; -do -{ - // Write to a fixed-size buffer - TkIdentifiable* familyBuffer[16]; - familiesFound = framework->getObjects(familyBuffer, 16, familyType, totalFamilyCount); - totalFamilyCount += familiesFound; - - // Process the families found so far - myProcessFamiliesFunction(familyBuffer, familiesFound); -} while (familiesFound == 16); -\endcode - -To use the type interface to identify a class, perhaps after serialization or lookup by ID, one may do something like: - -\code -\\ Assume we have a TkIdentifiable pointer called "object" - -// Get the type interfaces of interest -const TkType* assetType = framework->getType(TkTypeIndex::Asset); -const TkType* familyType = framework->getType(TkTypeIndex::Family); - -if (object->getType() == *assetType) -{ - TkAsset* asset = static_cast<TkAsset*>(object); - - // Process the object as a TkAsset -} -if (object->getType() == *familyType) -else -{ - TkFamily* family = static_cast<TkFamily*>(object); - - // Process the object as a TkFamily -} -\endcode - -A TkIdentifiable-derived class may be queried for its name using the TkType interface, using TkType::getName(). -This function returns a const char pointer to a string. - -Finally, one may query the class for its current format version number using TkType::getVersion(). - -<br> -*/ +/*! \page pagehlapi High Level (Toolkit) API (NvBlastTk)
+
+<b>Table of Contents</b>
+
+\subpage tkintroduction
+
+\subpage tk_class_hierarchy
+
+\subpage tk_include_and_library
+
+\subpage framework_init
+
+\subpage tkasset_creation
+
+\subpage tkasset_instancing
+
+\subpage tkgroups
+
+\subpage damage_in_tk
+
+\subpage tkjoints
+
+\subpage tkevents
+
+\subpage tktypes
+
+<br>
+\section tkintroduction Introduction to NvBlastTk
+
+The high-level API, NvBlastTk (Tk stands for "toolkit"), is intended to be a more powerful library and a much more convenient entry point
+into the use of Blast&tm;. Like the low-level library, Tk is physics and graphics-agnostic. Whereas the low-level API is C-style, Tk uses
+a C++ API. Everything in Tk is in the namespace:
+
+\code
+Nv::Blast
+\endcode
+
+(the only exceptions are global-scope functions to create and access a framework singleton, see below).
+Every object in Tk is prefixed with 'Tk'. For example, the Tk framework interface is:
+
+\code
+Nv::Blast::TkFramework
+\endcode
+
+<b>
+For the remainder of this page we will be in the Nv::Blast namespace, and will drop the explicit scope Nv::Blast:: from our names.
+</b>
+<br>
+<br>
+
+
+BlastTk adds:
+
+- An object class hierarchy (see \ref tk_class_hierarchy, below).
+- A global framework, <b>TkFramework</b> (a singleton). This keeps track of <b>TkIdentifiable</b> objects and allows
+the user to query them based upon either GUID or <b>TkIdentifiable</b> subclass type, and also provides a number of functions to create the various objects in BlastTk.
+- Processing groups with a task interface (see <b>TkGroup</b>).
+- Event dispatching for actor families (see <b>TkFamily</b>).
+- Intra-actor and inter-actor joint management (see <b>TkJoint</b>). Note, these "joints" only hold descriptor data, since physical objects are not handled by BlastTk.
+
+<br>
+\section tk_class_hierarchy NvBlastTk Class Hierarchy
+
+- There are two abstract interfaces, one of which deriving from the other: <b>TkObject <- TkIdentifiable</b>.
+ - Lightweight objects are derived from <b>TkObject</b>.
+ - Objects which use a GUID and class identification are derieved from <b>TkIdentifiable</b>.
+- <b>TkAsset</b> derives from <b>TkIdentifiable</b>. This is mostly a wrapper for NvBlastAsset, however it also stores
+extra data associated with the asset such as internal joint descriptors.
+- <b>TkFamily</b> derives from <b>TkIdentifiable</b>. One of these objects is made when a <b>TkActor</b> is instanced
+from a <b>TkAsset</b>. All actors that are created by splitting the family's original actor remain within the same family. Actor and joint
+events are dispatched from the <b>TkFamily</b>.
+- <b>TkGroup</b> derives from <b>TkIdentifiable</b>. Groups are processing units. The user may create as many groups as they please, and add
+or remove actors as they please from groups. The group provides a worker (TkGroupWorker) interface which allows the user to process multiple
+jobs in the group asynchoronously. These jobs, along with a call to TkGroup::endProcess(), perform the tasks of generating fracture commands,
+applying fracture commands, and actor splitting at the low-level. The user is informed of splitting through listeners given to TkFamily objects.
+- <b>TkActor</b> derives from <b>TkObject</b>. It is mostly a wrapper for NvBlastActor, but it also provides a number of damage functions
+to the user.
+- <b>TkJoint</b> derives from <b>TkObject</b>. <b>TkAsset</b> descriptors, cause internal <b>TkJoint</b> obejcts to be created within an actor
+(joining chunks within the same actor). Alternatively, the TkFramework provides a function which allows the user to create an external joint
+between any two different actors. As actors split, internal joints may become external. The user gets notification whenever joints become
+external, or when actors joined by joints change or are deleted, through listeners attached to the associated TkFamily objects.
+
+<br>
+\section tk_include_and_library Linking and Header Files
+
+To use the BlastTk library, the application need only inlclude the header NvBlastTk.h, found in the <b>include/toolkit</b> folder, and link
+against the appropriate version of the NvBlastTk library. Depending on the platform and configuration, various suffixes will be added to the library
+name. The general naming scheme is
+
+NvBlastTk(config)(arch).(ext)
+
+(config) is DEBUG, CHECKED, OR PROFILE for the corresponding configurations. For a release configuration there is no (config) suffix.
+
+(arch) is _x86 or _x64 for Windows 32- and 64-bit builds, respectively, and empty for non-Windows platforms.
+
+(ext) is .lib for static linking and .dll for dynamic linking on Windows. On XBoxOne it is .lib, and on PS4 it is .a.
+
+
+<br>
+\section framework_init Creating the TkFramework
+
+As a reminder, in this document we assume we are in the Nv::Blast namespace:
+
+\code
+using namespace Nv::Blast;
+\endcode
+
+In order to use NvBlastTk, one first has to create a TkFramework singleton. This simply requires a call
+to the global function NvBlastTkFrameworkCreate:
+
+\code
+TkFramework* framework = NvBlastTkFrameworkCreate();
+\endcode
+
+The framework may be accessed via:
+
+\code
+TkFramework* framework = NvBlastTkFrameworkGet();
+\endcode
+
+In the sections that follow, it is assumed that a framework has been created, and we have a pointer to it named 'framework' within scope.
+
+Finally, to release the framework, use
+
+\code
+framework->release();
+\endcode
+
+This will release all assets, families, actors, joints, and groups.
+
+<br>
+\section tkasset_creation Creating a TkAsset
+
+The TkAsset object is a high-level wrapper for the low-level NvBlastAsset (see \ref assets). The descriptor used to create a TkAsset, a TkAssetDesc, is derived from
+NvBlastAssetDesc. The base fields should be filled in as described in (\ref assets). The new field is an optional array of flags to be associated with each bond in
+the base descriptor. Currently the only flag is "BondJointed," and if set will cause an "internal joint" to be created in actors (TkActor type) created from the asset.
+See (\ref tkjoints) for more on joints in BlastTk.
+
+\code
+TkAssetDesc desc;
+
+myFunctionToFillInLowLevelAssetFields(desc); // Fill in the low-level (NvBlastAssetDesc) fields as usual
+
+std::vector<uint8_t*> bondFlags(desc.bondCount, 0); // Clear all flags
+
+// Set BondJointed flags corresponding to joints selected by the user (assumes a myBondIsJointedFunction to make this selection)
+for (uint32_t i = 0; i < desc.bondCount; ++i)
+{
+ if (myBondIsJointedFunction(i)) // User-authored
+ {
+ bondFlags[i] |= TkAssetDesc::BondJointed;
+ }
+}
+
+TkAsset* asset = framework->createAsset(desc); // Create a new TkAsset
+\endcode
+
+The createAsset function used above creates a low-level NvBlastAsset from the base fields of the descriptor, and then adds internal joint descriptors based
+upon the bonds' centroids and attached chunks. An alternative method to create a TkAsset allows the user to pass in a pre-existing NvBlastAsset, and a list
+of joint descriptors. If the TkAsset is to have no internal joints, then the joint descriptors are not necessary and with an NvBlastAsset
+pointer <b>llAsset</b>, a TkAsset may be created simply by using
+
+\code
+TkAsset* asset = framework->createAsset(llAsset);
+\endcode
+
+By default, such a TkAsset will not "own" the llAsset. When the TkAsset is released, the llAsset memory will be untouched. You can pass ownership to the
+TkAsset using all of the default parameters of the createAsset function:
+
+\code
+TkAsset* asset = framework->createAsset(llAsset, nullptr, 0, true);
+\endcode
+
+The last parameter sets ownership. N.B.: in order for the TkAsset to own the underlying llAsset, and therefore release it when the TkAsset is released,
+the memory for the llAsset must be allocated using the allocator accessed through NvBlastGlobals (see \ref pageglobalsapi).
+
+If one wants to author internal joints in a TkAsset using this second createAsset method, one must pass in a valid array of joint descriptors of type
+TkAssetJointDesc. Each joint descriptor takes two positions and two node indices. The positions are the joint's attachment positions in asset space, and
+the nodes indices are those of the graph nodes that correspond to support chunks. These indices are not, in general, the same as the chunk indices.
+An example of initialization of the joint descriptors is given below.
+
+\code
+std::vector<TkAssetJointDesc> jointDescs(jointCount); // Assume jointCount = the number of joints to add
+jointDescs[0].nodeIndices[0] = 0; // Attach node 0 to node 1
+jointDescs[0].nodeIndices[1] = 1;
+jointDescs[0].attachPoistions[0] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); // Attachment positions are often the same within an asset, but they don't have to be
+jointDescs[0].attachPoistions[1] = physx::PxVec3( 1.0f, 2.0f, 3.0f );
+// ... etc.
+
+TkAsset* asset = framework->createAsset(llAsset, jointDescs.data(), jointDescs.size());
+\endcode
+
+The code above assumes you know the support graph nodes to which you'd like to attach joints. Often, the user only knows the corresponding chunk indices.
+Fortunately it's easy to map chunk indices to graph node indices. In order to get the map, use the low-level function
+
+\code
+const uint32_t map = NvBlastAssetGetChunkToGraphNodeMap(llAsset, logFn);
+\endcode
+
+This map is an array with an entry for every chunk index. To get the graph node index for a chunk indexed <b>chunkIndex</b>, use
+
+\code
+uint32_t nodeIndex = map[chunkIndex];
+\endcode
+
+If the chunk indexed by <b>chunkIndex</b> does <em>not</em> correspond to a support chunk, then the mapped value will be UINT32_MAX, the invalid index.
+Otherwise, the mapped value will be a valid graph node index.
+
+Finally, to release a TkAsset, as with any TkObject-derived object, use the release() method:
+
+\code
+asset->release();
+\endcode
+
+<br>
+\section tkasset_instancing Instancing a TkAsset: Creation of a TkActor and a TkFamily
+
+Whereas with the Blast&tm; low-level (\ref pagellapi), one must explicitly create a family (NvBlastFamily) from an asset (NvBlastAsset) before creating
+the first actor (NvBlastActor) in the family, NvBlastTk creates a TkFamily automatically when an unfractured TkActor is instanced from a TkAsset using
+the framework's createActor function. This family is accessible through the actor and any actor that is created from splitting it. The family is
+<em>not</em> released automatically when all actors within it have been released. The user must use the TkFamily's release() method (see TkObject base
+API) to do so. (Or wait until the framework is released.) If a family is released that contains actors, the actors within will be released as well.
+
+The TkFamily has a special role in NvBlastTk, holding user-supplied event listeners (\ref TkEventListener). All <em>internal</em> actor creation and destruction
+events are broadcast to listeners through split events (TkSplitEvent). These signal when a fracturing operation has destroyed an actor and created
+child actors from it. TkActor creation or release that occurs from an explicit API call do not produce events. For example when creating a first unfractured
+instance of an asset using createAsset, or when calling the release() method on a TkActor. TkJoint events are similarly broadcast to
+receivers (TkJointEvent). These signal when the actors which are joined by the joints change, so that the user may update a corresponding physical joint.
+They also signal when a joint no longer attaches actors and is therefore unreferenced. The user may invalidate or release the joint using the TkObject
+release() method when this occurs (more on joint ownership in \ref tkjoints).
+
+To create an unfractured TkActor instance from a TkAsset, one first fills in a descriptor (\ref TkActorDesc) and passes it to the framework's createActor function.
+As with the TkAssetDesc, the TkActorDesc is derived from its low-level counterpart, the NvBlastActorDesc. In addition the TkActorDesc holds a pointer to
+the TkAsset being instanced. An example of TkActor creation is given below, given a TkAsset pointer <b>asset</b>.
+
+\code
+TkActorDesc desc; // The TkActorDesc constructor sets sane default values for the base (NvBlastActorDesc) fields, giving uniform chunk and bond healths of 1.0.
+desc.asset = asset; // This field of TkActorDesc must be set to a valid asset pointer.
+
+TkActor* actor = framework->createActor(desc);
+\endcode
+
+The TkFamily created with the actor above may be accessed through the actor's getFamily field:
+
+\code
+TkFamily& family = actor->getFamily();
+\endcode
+
+The returned value is a reference since a TkActor's family can never be NULL. Actors resulting from the split of a "parent" actor will always belong to the
+parent's family.
+
+For most applications, the user will need to create a listener object to pass to every family created, in order to keep their physics and graphics representations
+in sync with the splitting of the TkActor. For more on this, see \ref tkevents.
+
+<br>
+\section tkgroups Groups
+
+One important feature of NvBlastTk is the ability to multitask damage processing. The mechanism by which the toolkit does this is the group object, TkGroup.
+Groups are created at the request of the user; the user may create as many groups as he or she likes. Actors may be added or removed from groups in any way the
+user wishes, with the only constraint being that a given actor may belong to no more than one group. A group is a processing object, much like a scene in a physics
+simulation. Indeed, a natural pattern would be to associate one group per physics scene, and synchronize the group processing with scene simulation. Another
+pattern would be to subdivide the world into neighborhoods, and associate each neighborhood with a group. A distributed game could take advantage of this structure
+to similarly distribute computation.
+
+Group processing is performed by <em>workers</em>, which have a TkGroupWorker API exposed to the user. The number of workers may be set by the user, with the idea being
+that this should correspond to the number of threads available for group processing. Processing starts with a call to TkGroup::startProcess(). This creates a number
+of jobs which the user may assign to workers as they like, each worker potentially on its own thread. The jobs calculate the effects of all damage taken
+by the group's actors. After all jobs have been run, the user must call TkGroup::endProcess(). This will result in all events being fired off to listeners associated
+with families with actors in the group.
+
+A convenience function, TkGroup::process(), is provided which uses one worker to perform all jobs sequentially on the calling thread. This is useful shortcut to
+get BlastTk up and running quickly. A multithreaded group processing implementation is given by Nv::Blast::ExtGroupTaskManager (in NvBlastExtPxTask.h).
+This resides in \ref pageextphysx, because it uses physx::PxTask.
+
+Actors resulting from the split of a "parent" actor will be placed automatically into the group that the parent belonged to. This is similar to the assigment of
+families from a split, except that unlike families, the user then has the option to move the new actors to other groups, or no group at all.
+
+Also similar to families, groups are not automatically released when the last actor is removed from it. Unlike families, when a group is released, the actors which
+belong to the group are <em>not</em> released. They will, however, be removed from the group before the release is complete.
+
+A typical usage is outlined below. See \ref damage_in_tk for methods of applying damage to actors.
+
+\code
+// Create actors from descriptors desc1, desc2, ... etc., and attach a listener to each new family created
+TkActor* actor1 = framework->createActor(desc1);
+actor1->getFamily().addListener(gMyReceiver); // gMyReceiver is a TkEventListener-derived object. More on events in a subsequent section.
+TkActor* actor2 = framework->createActor(desc2);
+actor2->getFamily().addListener(gMyReceiver);
+TkActor* actor3 = framework->createActor(desc3);
+actor3->getFamily().addListener(gMyReceiver);
+// etc...
+
+// Let's create two groups. First, create a group descriptor. This may be used to create both groups.
+TkGroupDesc groupDesc;
+groupDesc.workerCount = 1; // this example processes groups on the calling thread only
+
+// Now create the groups
+TkGroup* group1 = framework->createGroup(groupDesc);
+TkGroup* group2 = framework->createGroup(groupDesc);
+
+// Add actor1 and actor2 to group1, and actor2 to group3...
+group1->addActor(actor1);
+group1->addActor(actor2);
+group2->addActor(actor3);
+// etc...
+
+// Now apply damage to all actors - *NOTE* damage is described in detail in the next section.
+// For now we will just assume a "myDamageFunction" to apply the damage.
+myDamageFunction(actor1);
+myDamageFunction(actor2);
+myDamageFunction(actor3);
+// etc...
+
+// Calling the groups' process functions will (synchronously) run all jobs to process damage taken by the contained actors.
+group1->process();
+group2->process();
+
+// When the groups are no longer needed, they may be released with the usual release method.
+group1->release();
+group2->release();
+\endcode
+
+<br>
+<b>Multithreaded processing</b>
+
+When distributing the jobs as mentioned above, every job must be processed exactly once (over all user tasks).
+
+The number of jobs processed per worker can range from a single job (resulting in a user task per job) to all jobs (like Nv::Blast::TkGroup::process() does).
+
+At any point in time, no more than the set workerCount amount of workers may have been acquired. Return the worker at the end of each task.
+
+\code
+Nv::Blast::TkGroupWorker* worker = group->acquireWorker();
+// process some jobs
+group->returnWorker(worker);
+\endcode
+
+<br>
+\section damage_in_tk Applying Damage to Actors and Families
+
+Damage in NvBlastTk uses the same damage program scheme as the low-level SDK (see \ref splitting). One passes the program
+(NvBlastDamageProgram), damage descriptor (program-dependent), and material (also program-dependent) to a TkActor::damage
+function. Ultimately, the damage descriptor and material data are all parameters used by the damage program. The distinction
+is that the damage descriptor should describe properties of the thing doing the damage, while the material should
+describe properties of the actor (the thing being damaged). The interpretation of this data is entirely up to the program's
+functions, however.
+
+For convenience, the user may set a default material in the actor's family. This assumes, of course, that the material parameters
+for this default are compatible with the program being used to damage the family's actors.
+
+Examples of the three TkActor damage methods are given below.
+
+<br>
+\subsection multiple_damage Multiple Damage Descriptors using NvBlastProgramParams
+
+<b>N.B. - with this method of damage, the lifetime of the NvBlastProgramParams <em>must</em> extend at
+least until the TkGroup::endProcess call for the actor.</b>
+
+\code
+NvBlastDamageProgram program =
+{
+ myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature
+ mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature
+};
+
+// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension
+RadialDamageDesc damageDescs[2];
+
+damageDescs[0].compressive = 10.0f;
+damageDescs[0].position[0] = 1.0f;
+damageDescs[0].position[1] = 2.0f;
+damageDescs[0].position[2] = 3.0f;
+damageDescs[0].minRadius = 0.0f;
+damageDescs[0].maxRadius = 1.0f;
+
+damageDescs[1].compressive = 100.0f;
+damageDescs[1].position[0] = 3.0f;
+damageDescs[1].position[1] = 4.0f;
+damageDescs[1].position[2] = 5.0f;
+damageDescs[1].minRadius = 0.0f;
+damageDescs[1].maxRadius = 5.0f;
+
+// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension
+Material material;
+
+material.health = 10.0f;
+material.minDamageThreshold = 0.1f;
+material.maxDamageThreshold = 0.8f;
+
+// Set the damage params struct
+NvBlastProgramParams params = { damageDescs, 2, &material };
+
+// Apply damage
+actor->damage(program, ¶ms); // params must be kept around until TkGroup::endProcess is called!
+\endcode
+
+<br>
+\subsection single_damage_desc_default_material Single Damage Descriptor with Default TkFamily Material
+
+This method of damage copies the damage descriptor into a buffer, so the user need <em>not</em> hold onto
+a copy after the damage function call. Only one damage descriptor may be passed in at once.
+
+To use this method, the user must first set a default material in the actor's family. For example:
+
+\code
+// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension
+Material material;
+
+material.health = 10.0f;
+material.minDamageThreshold = 0.1f;
+material.maxDamageThreshold = 0.8f;
+
+// Set the default material used by the material-less TkActor::damage call
+actor->getFamily().setMaterial(&material);
+\endcode
+
+<b>N.B. the lifetime of the material set <em>must</em> extend at least until the TkGroup::endProcess call for the actor.</b>
+
+Then to apply damage, use:
+
+\code
+NvBlastDamageProgram program =
+{
+ myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature
+ mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature
+};
+
+// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension
+RadialDamageDesc damageDesc;
+
+damageDesc.compressive = 10.0f;
+damageDesc.position[0] = 1.0f;
+damageDesc.position[1] = 2.0f;
+damageDesc.position[2] = 3.0f;
+damageDesc.minRadius = 0.0f;
+damageDesc.maxRadius = 1.0f;
+
+// Apply damage
+actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc));
+\endcode
+
+<br>
+\subsection single_damage_desc_with_material Single Damage Descriptor with Specified Material
+
+This method is just like the one above, except that the user has the opportunity to override the material used during damage.
+
+<b>N.B. - the lifetime of the material passed in <em>must</em> extend at least until the TkGroup::endProcess call for the actor.</b>
+
+This call is just like the one above with an extra material parameter:
+
+\code
+actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc), &material);
+\endcode
+
+<br>
+\section tkjoints Joints
+
+Joints in NvBlastTk are abstract representations of physical joints. When joints become active, change the actors they join,
+or become unreferenced (the actors they join disappear), the user will receive notification via a TkJointUpdateEvent
+(see \ref tkevents).
+
+Joints may be defined as a part of a TkAsset, in which case they are consisdered "internal" joints. (See \ref tkasset_creation.)
+Since the first instance of a TkAsset is a single TkActor, internal joints are defined between chunks within the same actor.
+Therefore they are not active (there is no point in joining two locations in a single rigid body). Upon splitting into multiple
+actors, however, an internal joint's chunks may now belong to two different TkActors. When this happens, the user will receive a
+TkJointUpdateEvent of subtype TkJointUpdateEvent::External. The event contains a pointer to the TkJoint, and from that the user
+has access to the information needed to create a physical joint between the rigid bodies that correspond to the joined TkActors.
+
+Joints may also be created externally at runtime, using the TkFramework::createJoint function. A joint created this way must
+be between two different TkActors. Because of this, the joint is immediately considered active, and so no TkJointUpdateEvent
+is generated from its creation. The user should create a physical joint to correspond to the joint returned by createJoint.
+An externally created joint of this type has another distinguishing characteristic: it may join an actor to "the world," or
+"Newtonial Reference Frame" (NRF). To do this, one TkFamily pointer in the joint descriptor is set to NULL. Examples are
+given below.
+
+\code
+TkJointDesc desc;
+desc.families[0] = &actor0->getFamily(); // Assume we have a valid actor0 pointer
+desc.chunkIndices[0] = 1; // This chunk *must* be a support chunk in the asset that created desc.families[0]
+desc.attachPositions[0] = physx::PxVec3(1.0f, 2.0f; 3.0f); // The attach position is in asset space
+desc.families[1] = &actor1->getFamily(); // Assume we have a valid actor1 pointer... note, actor0 and actor1 could have the same family
+desc.chunkIndices[1] = 10; // This chunk *must* be a support chunk in the asset that created desc.families[1]
+desc.attachPositions[1] = physx::PxVec3(4.0f, 5.0f; 6.0f); // The attach position is in asset space
+
+// Create the external joint from the descriptor, which joins actor0 and actor1
+TkJoint* joint = framework->createJoint(desc);
+
+// Now join actor0 to the NRF
+// desc.families[0] already contains actor0's family
+desc.chunkIndices[0] = 2; // Again, this chunk must be a support chunk in the asset that created desc.families[0]
+desc.attachPositions[0] = physx::PxVec3(0.0f, 0.0f; 0.0f); // The attach position is in asset space
+desc.families[1] = nullptr; // Setting the family to NULL designates the world (NRF)
+// The value of desc.chunkIndices[1] is not used, since desc.families[1] is NULL
+desc.attachPositions[1] = physx::PxVec3(0.0f, 0.0f, 10.0f); // Attach position in the world
+
+// Create the external joint which joins actor0 to the world
+TkJoint* jointNRF = framework->createJoint(desc);
+\endcode
+
+<br>
+\subsection releasing_joints Releasing Joints
+
+TkJoints are not released by Blast&tm;, except when the TkFramework is released. Otherwise, the user is responsible for
+releasing TkJoints after they become unreferenced. This is facilitated by the Unreferenced subtype of the TkJointUpdateEvent. After
+receiving this event for joint, the user may choose to release, using the typical TkObject::release() method.
+
+\code
+joint->release();
+\endcode
+
+Note, this method can be called <em>at any time</em>, even before the joint is unreferenced. When called, it will remove its
+references to its attached actors first, causing the joint to then become unreferenced. For example, if the user wishes to break
+a physical joint in their simulation, they can then release the corresponding TkJoint.
+
+It should be mentioned, however, that joints created with an asset are allocated differently from external joints created using
+TkFramework::createJoint. Internal joints created from the joint descriptors in a TkAsset are <em>block allocated</em> with every
+TkFamily that instances the asset. Calling the release() method on those joints will remove any remaining references to them
+(as mentioned above), but will not perform any deallocation. Only when the TkFamily itself is released will the internal joint
+memory for that family be released. <b>This is true even if the internal joints become "external" from actor splitting.</b> Joints
+that <em>become</em> external are still associated with a single family and their memory still resides with that family.
+
+On the other hand, joints that start out life external by way of the TkFramework::createJoint function have a separate allocation,
+and do not have memory tied to any TkFamily (even if both actors joined are in the same family). Releasing a family holding one
+of the actors in such a "purely external" joint will trigger a TkJointUpdateEvent of subtype Unreferenced, however, signalling that
+the joint is ready for user release.
+
+<br>
+\section tkevents Events
+
+NvBlastTk uses events to communicate the results of actor splitting, joint updates from actor splitting, and fracture event buffers
+that can be used to synchronize fracturing between multiple clients.
+
+Events are broadcast to listeners which implement the TkEventListener interface. Listeners are held by TkFamily objects. During
+a TkGroup::endProcess call (see \ref tkgroups), relevant events are broadcast to the listeners in the families associated with the actors
+in the group.
+
+A typical user's receiver implementation might take on the form shown below.
+
+\code
+class MyActorAndJointListener : public TkEventListener
+{
+ // TkEventListener interface
+ void receive(const TkEvent* events, uint32_t eventCount) override
+ {
+ // Events are batched into an event buffer. Loop over all events:
+ for (uint32_t i = 0; i < eventCount; ++i)
+ {
+ const TkEvent& event = events[i];
+
+ // See TkEvent documentation for event types
+ switch (event.type)
+ {
+ case TkSplitEvent::EVENT_TYPE: // A TkActor has split into smaller actors
+ {
+ const TkSplitEvent* splitEvent = event.getPayload<TkSplitEvent>(); // Split event payload
+
+ // The parent actor may no longer be valid. Instead, we receive the information it held
+ // which we need to update our app's representation (e.g. removal of the corresponding physics actor)
+ myRemoveActorFunction(splitEvent->parentData.family, splitEvent->parentData.index, splitEvent->parentData.userData);
+
+ // The split event contains an array of "child" actors that came from the parent. These are valid
+ // TkActor pointers and may be used to create physics and graphics representations in our application
+ for (uint32_t j = 0; j < splitEvent->numChildren; ++j)
+ {
+ myCreateActorFunction(splitEvent->children[j]);
+ }
+ }
+ break;
+
+ case TkJointUpdateEvent::EVENT_TYPE:
+ {
+ const TkJointUpdateEvent* jointEvent = event.getPayload<TkJointUpdateEvent>(); // Joint update event payload
+
+ // Joint events have three subtypes, see which one we have
+ switch (jointEvent->subtype)
+ {
+ case TkJointUpdateEvent::External:
+ myCreateJointFunction(jointEvent->joint); // An internal joint has been "exposed" (now joins two different actors). Create a physics joint.
+ break;
+ case TkJointUpdateEvent::Changed:
+ myUpdatejointFunction(jointEvent->joint); // A joint's actors have changed, so we need to update its corresponding physics joint.
+ break;
+ case TkJointUpdateEvent::Unreferenced:
+ myDestroyJointFunction(jointEvent->joint); // This joint is no longer referenced, so we may delete the corresponding physics joint.
+ break;
+ }
+ }
+
+ // Unhandled:
+ case TkFractureCommands::EVENT_TYPE:
+ case TkFractureEvents::EVENT_TYPE:
+ default:
+ break;
+ }
+ }
+ }
+};
+\endcode
+
+Whenever a new TkActor is created by the user (via TkFramework::createActor, see \ref tkasset_instancing), its newly-made family should
+be given whatever listeners the user wishes to attach. For example,
+
+\code
+TkActor* actor = framework->createActor(actorDesc);
+
+actor->getFamily().addListener(myListener); // myListener is an object which implements TkEventListener (see MyActorAndJointListener above, for example)
+\endcode
+
+Listeners may also be removed from families at any time.
+
+<br>
+\section tktypes Object and Type Identification
+
+NvBlastTk objects that are derived from TkIdentifiable (TkAsset, TkFamily, and TkGroup) support an object and class (type) identification
+system. The TkIdentifiable interfaces setID and getID allow the user to set and access an NvBlastID for each object. The NvBlastID
+is a 128-bit identifier. TkIdentifiable objects are tracked by the TkFramework, which may be used to look up an object by its NvBlastID.
+
+Upon creation, TkIdentifiable objects are given a GUID, a unique NvBlastID. The user is welcome to change the object's guid at any time, with
+the restriction that the GUID cannot be all zero bytes.
+
+With an object's GUID, one may look up the object using the TkFramework function findObjectByID:
+
+\code
+TkIdentifiable* object = framework->findObjectByID(id); // id = an NvBlastID GUID
+\endcode
+
+If the object is found, a non-NULL pointer will be returned.
+
+TkIdentifiable-derived classes also have a class identification system, the TkType interface. From an individual object one may use the
+TkIdentifiable interface getType to access the class's TkType interface. Alternatively, one may use the TkFramework getType function
+with TkTypeIndex::Enum argument. For example, to get the TkType interface for the TkAsset class, use
+
+\code
+const TkType* assetType = framework->getType(TkTypeIndex::Asset);
+\endcode
+
+The type interface may be used:
+
+ - to access class-specific object lists in the framework,
+ - identify the class of a TkIdentifiable obtained through ID lookup or deserialization, or
+ - to obtain the class's name and format version number.
+
+For example, to access a list of all families:
+
+\code
+// Get the TkFamily type interface
+const TkType* familyType = framework->getType(TkTypeIndex::Family);
+
+// Get the family count to allocate a buffer
+const uint32_t familyCount = framework->getObjectCount(familyType);
+std::vector<TkIdentifiable*> families(familyCount);
+
+// Write the families to the buffer
+const uint32_t familiesFound = framework->getObjects(families.data(), familyCount, familyType);
+\endcode
+
+In the above code, the values of familyCount and familiesFound should be equal. An alternative usage of TkFramework::getObjects allows the
+user to write to a (potentially) smaller buffer, iteratively. For example:
+
+\code
+uint32_t familiesFound;
+uint32_t totalFamilyCount = 0;
+do
+{
+ // Write to a fixed-size buffer
+ TkIdentifiable* familyBuffer[16];
+ familiesFound = framework->getObjects(familyBuffer, 16, familyType, totalFamilyCount);
+ totalFamilyCount += familiesFound;
+
+ // Process the families found so far
+ myProcessFamiliesFunction(familyBuffer, familiesFound);
+} while (familiesFound == 16);
+\endcode
+
+To use the type interface to identify a class, perhaps after serialization or lookup by ID, one may do something like:
+
+\code
+\\ Assume we have a TkIdentifiable pointer called "object"
+
+// Get the type interfaces of interest
+const TkType* assetType = framework->getType(TkTypeIndex::Asset);
+const TkType* familyType = framework->getType(TkTypeIndex::Family);
+
+if (object->getType() == *assetType)
+{
+ TkAsset* asset = static_cast<TkAsset*>(object);
+
+ // Process the object as a TkAsset
+}
+if (object->getType() == *familyType)
+else
+{
+ TkFamily* family = static_cast<TkFamily*>(object);
+
+ // Process the object as a TkFamily
+}
+\endcode
+
+A TkIdentifiable-derived class may be queried for its name using the TkType interface, using TkType::getName().
+This function returns a const char pointer to a string.
+
+Finally, one may query the class for its current format version number using TkType::getVersion().
+
+<br>
+*/
|