/* Copyright (c) 2018 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __ArmaturePose_H__ #define __ArmaturePose_H__ #ifdef __cplusplus extern "C" { #endif typedef struct ArmaturePose ArmaturePose; #define ArmaturePose_superclass StemObject #include "gamemath/Matrix4x4f.h" #include "gamemath/Quaternionf.h" #include "gamemath/Vector3f.h" #include "gamemath/Armature.h" #include "stemobject/StemObject.h" typedef struct ArmaturePoseBone { ArmatureBoneID boneID; Vector3f offset; Vector3f scale; Quaternionf rotation; unsigned int armatureBoneIndex; // Runtime only; set by resolveArmatureBoneIndexes() unsigned int parentPoseBoneIndex; // Runtime only; set by resolveArmatureBoneIndexes() } ArmaturePoseBone; #define ArmaturePose_ivars \ StemObject_ivars \ \ unsigned int poseBoneCount; \ ArmaturePoseBone * poseBones; \ unsigned int poseTransformDirtyValue; \ unsigned int poseBoneTransformCount; \ Matrix4x4f * poseBoneTransforms; #define ArmaturePose_vtable(self_type) \ StemObject_vtable(self_type) stemobject_declare(ArmaturePose) // create/initWithArmature() creates one ArmaturePoseBone per ArmatureBone. Use for ArmaturePoses destined for // rendering rather than data storage. When initialized this way, if the provided Armature has already had // resolveParentBoneIndexes() called on it, it's not necessary to call resolveArmatureBoneIndexes() on the // resulting ArmaturePose. ArmaturePose * ArmaturePose_create(unsigned int poseBoneCount, ArmaturePoseBone * poseBones); ArmaturePose * ArmaturePose_createWithArmature(Armature * armature); bool ArmaturePose_init(ArmaturePose * self, unsigned int poseBoneCount, ArmaturePoseBone * poseBones); bool ArmaturePose_initWithArmature(ArmaturePose * self, Armature * armature); void ArmaturePose_initCopy(ArmaturePose * self, ArmaturePose * original); void ArmaturePose_dispose(ArmaturePose * self); ArmaturePose * ArmaturePose_copy(ArmaturePose * self); // Resets the offset, scale, and rotation of all pose bones to the identity. Does not affect poseBoneTransforms. void ArmaturePose_resetAllPoseBones(ArmaturePose * self); // Computes a matrix for each bone and stores it in poseBoneTransforms. This is not done automatically. // resolveArmatureBoneIndexes() must be called at least once with the same armature before calling this function. // poseBoneTransforms is stored separately from poseBones and packed tightly for convenient shader buffering. // If the number of pose bones in this pose has been mutated since the last call to computePoseBoneTransforms, // poseBoneTransformCount will be adjusted accordingly and poseBoneTransforms will be reallocated. // Each call increases poseTransformDirtyValue by 1. void ArmaturePose_computePoseBoneTransforms(ArmaturePose * self, Armature * armature); // Returns the base position of the specified pose bone after being transformed by its parent chain. // ArmaturePose_computePoseBoneTransforms() must be called before using this function. Vector3f ArmaturePose_getPoseBonePosition(ArmaturePose * self, unsigned int poseBoneIndex, Armature * armature); // Same as above, but for the endpoint of the pose bone rather than the base position. Vector3f ArmaturePose_getPoseBoneEndpoint(ArmaturePose * self, unsigned int poseBoneIndex, Armature * armature); // Adds the offsets, scales, and rotations in pose to the pose bones in self. Does not affect poseBoneTransforms. // The two poses can describe different sets of bones. Only the pose bones that are present in self will be // added from pose. void ArmaturePose_combinePoses(ArmaturePose * self, ArmaturePose * pose); // Similar to combinePoses(), with the difference that any ArmaturePoseBones present in pose will be copied // into self rather than ignored. If pose bones in self are added as a result of this function, it may be // necessary to call resolveArmatureBoneIndexes() afterward. Returns true if pose bones were added. bool ArmaturePose_combinePoseBones(ArmaturePose * self, ArmaturePose * pose); // Sets armatureBoneIndex to a valid value for the provided armature for all bones that can be resolved, and // sets it to BONE_INDEX_NOT_FOUND for unresolvable bones void ArmaturePose_resolveArmatureBoneIndexes(ArmaturePose * self, Armature * armature); // After mutating the pose bone list, it may be necessary to call resolveArmatureBoneIndexes() to adjust parentPoseBoneIndex void ArmaturePose_addPoseBone(ArmaturePose * self, ArmaturePoseBone poseBone); void ArmaturePose_insertPoseBone(ArmaturePose * self, unsigned int poseBoneIndex, ArmaturePoseBone poseBone); ArmaturePoseBone * ArmaturePose_getPoseBone(ArmaturePose * self, ArmatureBoneID boneID); unsigned int ArmaturePose_getPoseBoneIndex(ArmaturePose * self, ArmatureBoneID boneID); void ArmaturePose_removePoseBoneAtIndex(ArmaturePose * self, unsigned int poseBoneIndex); void ArmaturePose_reorderPoseBone(ArmaturePose * self, unsigned int fromPoseBoneIndex, unsigned int toPoseBoneIndex); // Modifies this pose's list of poseBones to be as if it was newly created using ArmaturePose_createWithArmature(), // without having to dispose and recreate the object. void ArmaturePose_copyBonesFromArmature(ArmaturePose * self, Armature * armature); #ifdef __cplusplus } #endif #endif