import animation import mesh import matrixmath import skeleton # enum Type { STATIC, DEFORMABLE }; (STATIC,DEFORMABLE) = range(2) class Model(object): ''' type: enum Type { STATIC, DEFORMABLE } ''' def __init__(self, type, texture_loader = None): self.__meshCacher = mesh.MeshCacher() self.__animCacher = animation.AnimCacher() self.__anims = [] # vector<AnimPlayer *> self.__blends= [] # vector<BlendBase *> self.__masks = [] # vector<HiBoneMask *> self.meshes = []# vector<Mesh *> self.originSubtraction = False # bool self.fp = texture_loader self.type = -1 # enum Type self.arbitraryAnim = None self.renderPose = None self.worldBones = matrixmath.Matrix() self.worldBonesTEMP = matrixmath.Matrix() def AllocateRenderPose(self): if (self.arbitraryAnim == None): raise(Exception.new("ERROR: Load an animation before allocating render pose.")) return else: self.renderPose = skeleton.Pose(self.arbitraryAnim.bones.numBones) self.worldBones = [matrixmath.Matrix() \ for i in range(self.arbitraryAnim.bones.numBones)] self.worldBonesTEMP = [matrixmath.Matrix() \ for i in range(self.arbitraryAnim.bones.numBones)] def AddMesh(self,filename): #returns unsigned int self.meshes.append( self.__meshCacher.GetMesh(filename, self.fp) ) return len(self.meshes) - 1 def SwapMesh(self,index, filename): self.meshes[index] = self.__meshCacher.GetMesh(filename, self.fp) def AddAnim(self, filename, startFrame = 0): handle = animation.AnimPlayer(self.__animCacher.GetAnim(filename), startFrame) if (self.arbitraryAnim == None): self.arbitraryAnim = handle.anim self.__blends.append(handle) self.__anims.append(handle) return handle def CreateBlend( self, source, dest ): if (self.arbitraryAnim == None): raise(Exception("ERROR: Load an animation before creating a blend.")) return None handle = skeleton.Blend(self.arbitraryAnim.bones.numBones, source, dest ) self.__blends.append(handle) return handle def CreateMask( self, selections ): if (self.arbitraryAnim == None): raise(Exception("ERROR: Load an animation before creating a mask.")) return None handle = skeleton.HiBoneMask(self.arbitraryAnim.bones, selections) self.__masks.append(handle) return handle def GenerateRenderPoseMatrices(self): for i in range(self.arbitraryAnim.bones.numBones): if (i==0): self.worldBones[i].Set(self.renderPose.bones[i].q, \ self.renderPose.bones[i].x,\ self.renderPose.bones[i].y,\ self.renderPose.bones[i].z) else: self.worldBones[i].Set(self.renderPose.bones[i].q, \ self.arbitraryAnim.frames[0].pose.bones[i].x,\ self.arbitraryAnim.frames[0].pose.bones[i].y,\ self.arbitraryAnim.frames[0].pose.bones[i].z) parent = self.arbitraryAnim.bones.nodes[i].parent if (parent >= 0): self.worldBones[i] = self.worldBones[parent] * self.worldBones[i] # Careful! # A mesh can be bound to a subset of the skeleton. Therefore two # different meshes could be bound to the same bones, but at different # poses. This means we have to multiply the inverse when we know which # mesh we're dealing with. Which means when different meshes do have # the same bind pose (usually) we calculate the same value twice. If # there is only one mesh, this is all very unecessary. # OPTIMIZE: to solve this problem, when a mesh is loaded, a record # could be kept of common bind poses, and then, at this point, we # could store the common-bind-pose to render-pose transformations for # all bones. If a mesh's bind pose differs from an already loaded bind # pose, the bones that differ can cause an extra transform when the mesh # is drawn that account for the difference. # for (i=0; i < arbitraryAnim->bones->numBones; i++) # worldbones[i] = worldbones[i] * meshes[0]->inverseBindPose[i]; def Update(self, timestep): for it in self.__anims: it.Update(timestep * it.anim.fps)