diff options
| author | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
| commit | e1bf674c16e3c8472b29574159c789cd3f0c64e0 (patch) | |
| tree | 9f0cfce09c71a2c27ff19589fcad6cd83504477c /docs/_source/api_hl_users_guide.txt | |
| parent | first commit (diff) | |
| download | blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.tar.xz blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.zip | |
Updating to [email protected] and [email protected] with a new directory structure.
NvBlast folder is gone, files have been moved to top level directory. README is changed to reflect this.
Diffstat (limited to 'docs/_source/api_hl_users_guide.txt')
| -rw-r--r-- | docs/_source/api_hl_users_guide.txt | 706 |
1 files changed, 706 insertions, 0 deletions
diff --git a/docs/_source/api_hl_users_guide.txt b/docs/_source/api_hl_users_guide.txt new file mode 100644 index 0000000..99b2aa3 --- /dev/null +++ b/docs/_source/api_hl_users_guide.txt @@ -0,0 +1,706 @@ +/*! \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 holds an allocator and error message callback, 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. +- Task management and processing groups (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, only joint descriptions are managed, since physical objects are not handled by BlastTk. +- Various damage and material options for actors (<b>TkActor</b>). + +<br> +\section tk_class_hierarchy NvBlastTk Class Hierarchy + +- There are three abstract interfaces, in an inheritance chain: <b>TkObject <- TkIdentifiable <- TkSerializable</b>. + - Lightweight objects are derived from <b>TkObject</b>. + - Objects which use a GUID and class identification are derieved from <b>TkIdentifiable</b>. + - Objects which support serialization are derived from <b>TkSerializable</b>. +- <b>TkAsset</b> derives from <b>TkSerializable</b>. This is mostly a wrapper for NvBlastAsset, however it also stores +extra data associated with the asset such as a chunk map and internal joint descriptors. +- <b>TkFamily</b> derives from <b>TkSerializable</b>. One and only 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 will process damage applied to its actors, and split the actors into new actors when +the actors fracture. Groups use a user-defined task manager and can process actors in multiple threads simultaneously. +- <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>. Based upon <b>TkAsset</b> and <b>TkComposite</b> descriptors, a <b>TkJoint</b> may be internal +to an actor (joining chunks within the same actor) or external (joining chunks between two 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. + +<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 Nv::Blast; +\endcode + +In order to use NvBlastTk, one first has to create a TkFramework singleton. This requires a descriptor which +holds two callback classes defined by the user. These classes are derived from the physx::PxErrorCallback and +physx::PxAllocatorCallback interfaces, and define message handling and allocation/deallocation functions, +respectively. Assuming the user has already defined these objects with names gErrorCallback and gAllocatorCallback, +the TkFramework descriptor is built as follows: + +\code +TkFrameworkDesc desc; +desc.errorCallback = &gErrorCallback; // physx::PxErrorCallback-derived callback object +desc.allocatorCallback = &gAllocatorCallback; // physx::PxAllocatorCallback-derived callback object +\endcode + +One then creates the framework: + +\code +TkFramework* framework = NvBlastTkFrameworkCreate( desc ); +\endcode + +The framework is a global singleton, and 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. + +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, nullptr); +\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: + +asset->release(); + +<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 <em>not</em> +released automatically when all actors within it have been released. The user must use the TkObject::release() method 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 roll in NvBlastTk, holding user-supplied event listeners (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 (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; + +myFunctionToFillInLowLevelActorFields(desc); // Fill in the low-level (NvBlastActorDesc) fields as usual + +desc.asset = asset; + +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 feature of NvBlastTk is multithreading of 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 they like. 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. + +When processing, a group spawns tasks to calculate the effects of all damage taken by the group's actors. The group's sync function waits for all tasks to finish, +and then has each family associated with its actors broadcast events to its listeners. + +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. + +Because a group spawns tasks, for flexibility it requires a user-defined task manager. This manager needs to implement the type physx::PxTaskManager interface. + +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.pxTaskManager = &gTaskManager; // physx::PxTaskManager-derived object + +// 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 spawn tasks to process damage taken to the contained actors. +group1->process(); +group2->process(); + +// The user may insert code to be run asynchronously with group processing... + +// Call the groups' sync functions (with default block = true argument) to wait for processing to finish and fire off events. +group1->sync(); +group2->sync(); + +// When the groups are no longer needed, they may be released with the usual release method. +group1->release(); +group2->release(); +\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::sync 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.singleChunkThreshold = 1.0f; +material.graphChunkThreshold = 1.0f; +material.bondTangentialThreshold = 0.5f; +material.bondNormalThreshold = 0.25f; +material.damageAttenuation = 0.75f + +// Set the damage params struct +NvBlastProgramParams params = { damageDescs, 2, &material }; + +// Apply damage +actor->damage(program, ¶ms); // params must be kept around until TkGroup::sync 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.singleChunkThreshold = 1.0f; +material.graphChunkThreshold = 1.0f; +material.bondTangentialThreshold = 0.5f; +material.bondNormalThreshold = 0.25f; +material.damageAttenuation = 0.75f + +// 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::sync 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::sync 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.f, 2.f; 3.f); // 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.f, 5.f; 6.f); // 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.f, 0.f; 0.f); // 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.f, 0.f, 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::sync 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 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> +*/ |