reorganize Actor dictionaries a bit; keep around ModelRoot node for proper ModelPool reference counting

This commit is contained in:
David Rose 2006-10-24 17:11:22 +00:00
parent 79d14e2fc8
commit 1373705582

View File

@ -22,6 +22,66 @@ class Actor(DirectObject, NodePath):
LoaderOptions.LFReportErrors | LoaderOptions.LFReportErrors |
LoaderOptions.LFConvertAnim) LoaderOptions.LFConvertAnim)
class PartDef:
"""Instances of this class are stored within the
PartBundleDict to track all of the individual PartBundles
associated with the Actor. In general, each separately loaded
model file is a different PartBundle. This can include the
multiple different LOD's, as well as the multiple different
pieces of a multipart Actor. """
def __init__(self, partBundle, partModel):
# We also save the ModelRoot node along with the
# PartBundle, so that the reference count in the ModelPool
# will be accurate.
self.partBundle = partBundle
self.partModel = partModel
def __repr__(self):
return 'Actor.PartDef(%s, %s)' % (repr(self.partBundle), repr(self.partModel))
class AnimDef:
"""Instances of this class are stored within the
AnimControlDict to track all of the animations associated with
the Actor. This includes animations that have already been
bound (these have a valid AnimControl) as well as those that
have not yet been bound (for these, self.animControl is None).
There is a different AnimDef for each different part or
sub-part, times each different animation in the AnimDict. """
def __init__(self, filename):
self.filename = filename
self.animModel = None
self.animControl = None
def makeCopy(self):
return Actor.AnimDef(self.filename)
def __repr__(self):
return 'Actor.AnimDef(%s)' % (repr(self.filename))
class SubpartDef:
"""Instances of this class are stored within the SubpartDict
to track the existance of arbitrary sub-parts. These are
designed to appear to the user to be identical to true "part"
of a multi-part Actor, but in fact each subpart represents a
subset of the joints of an existing part (which is accessible
via a different name). """
def __init__(self, truePartName, subset = PartSubset()):
self.truePartName = truePartName
self.subset = subset
def makeCopy(self):
return Actor.SubpartDef(self.truePartName, PartSubset(self.subset))
def __repr__(self):
return 'Actor.SubpartDef(%s, %s)' % (repr(self.truePartName), repr(self.subset))
def __init__(self, models=None, anims=None, other=None, copy=1, def __init__(self, models=None, anims=None, other=None, copy=1,
lodNode = None): lodNode = None):
"""__init__(self, string | string:string{}, string:string{} | """__init__(self, string | string:string{}, string:string{} |
@ -226,7 +286,7 @@ class Actor(DirectObject, NodePath):
# copy the scene graph elements of other # copy the scene graph elements of other
if (overwrite): if (overwrite):
otherCopy = other.copyTo(hidden) otherCopy = other.copyTo(NodePath())
otherCopy.detachNode() otherCopy.detachNode()
# assign these elements to ourselve (overwrite) # assign these elements to ourselve (overwrite)
self.assign(otherCopy) self.assign(otherCopy)
@ -266,8 +326,8 @@ class Actor(DirectObject, NodePath):
""" """
Actor print function Actor print function
""" """
return "Actor: partBundleDict = %s,\n animControlDict = %s" % \ return "Actor %s, parts = %s, LODs = %s, anims = %s" % \
(self.__partBundleDict, self.__animControlDict) (self.getName(), self.getPartNames(), self.getLODNames(), self.getAnimNames())
def listJoints(self, partName="modelRoot", lodName="lodRoot"): def listJoints(self, partName="modelRoot", lodName="lodRoot"):
"""Handy utility function to list the joint hierarchy of the """Handy utility function to list the joint hierarchy of the
@ -277,18 +337,14 @@ class Actor(DirectObject, NodePath):
if not partBundleDict: if not partBundleDict:
Actor.notify.error("no lod named: %s" % (lodName)) Actor.notify.error("no lod named: %s" % (lodName))
truePartName = partName subpartDef = self.__subpartDict.get(partName, Actor.SubpartDef(partName))
subset = PartSubset()
subpartDef = self.__subpartDict.get(partName)
if subpartDef:
truePartName, subset = subpartDef
bundle = partBundleDict.get(truePartName) partDef = partBundleDict.get(subpartDef.truePartName)
if bundle == None: if partDef == None:
Actor.notify.error("no part named: %s" % (partName)) Actor.notify.error("no part named: %s" % (partName))
self.__doListJoints(0, bundle.node().getBundle(), self.__doListJoints(0, partDef.partBundle.node().getBundle(),
subset.isIncludeEmpty(), subset) subset.isIncludeEmpty(), subpartDef.subset)
def __doListJoints(self, indentLevel, part, isIncluded, subset): def __doListJoints(self, indentLevel, part, isIncluded, subset):
name = part.getName() name = part.getName()
@ -322,12 +378,12 @@ class Actor(DirectObject, NodePath):
partInfo = [] partInfo = []
for partName in partDict.keys(): for partName in partDict.keys():
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
partBundle = self.__partBundleDict[lodName][truePartName] partBundle = self.__partBundleDict[lodName][truePartName].partBundle
animDict = partDict[partName] animDict = partDict[partName]
animInfo = [] animInfo = []
for animName in animDict.keys(): for animName in animDict.keys():
file = animDict[animName][0] file = animDict[animName].filename
animControl = animDict[animName][1] animControl = animDict[animName].animControl
animInfo.append([animName, file, animControl]) animInfo.append([animName, file, animControl])
partInfo.append([partName, partBundle, animInfo]) partInfo.append([partName, partBundle, animInfo])
lodInfo.append([lodName, partInfo]) lodInfo.append([lodName, partInfo])
@ -563,10 +619,10 @@ class Actor(DirectObject, NodePath):
def update(self, lod=0): def update(self, lod=0):
lodnames = self.getLODNames() lodnames = self.getLODNames()
if (lod < len(lodnames)): if (lod < len(lodnames)):
partBundles = self.__partBundleDict[lodnames[lod]].values() partDefs = self.__partBundleDict[lodnames[lod]].values()
for partBundle in partBundles: for partDef in partDefs:
# print "updating: %s" % (partBundle.node()) # print "updating: %s" % (partBundle.node())
partBundle.node().updateToNow() partDef.partBundle.node().updateToNow()
else: else:
self.notify.warning('update() - no lod: %d' % lod) self.notify.warning('update() - no lod: %d' % lod)
@ -675,7 +731,7 @@ class Actor(DirectObject, NodePath):
# loop through all anims for named part and find if any are playing # loop through all anims for named part and find if any are playing
for animName, anim in animDict.items(): for animName, anim in animDict.items():
if isinstance(anim[1], AnimControl) and anim[1].isPlaying(): if isinstance(anim.animControl, AnimControl) and anim.animControl.isPlaying():
return animName return animName
# we must have found none, or gotten an error # we must have found none, or gotten an error
@ -700,8 +756,8 @@ class Actor(DirectObject, NodePath):
# loop through all anims for named part and find if any are playing # loop through all anims for named part and find if any are playing
for animName, anim in animDict.items(): for animName, anim in animDict.items():
if isinstance(anim[1], AnimControl) and anim[1].isPlaying(): if isinstance(anim.animControl, AnimControl) and anim.animControl.isPlaying():
return anim[1].getFrame() return anim.animControl.getFrame()
# we must have found none, or gotten an error # we must have found none, or gotten an error
return None return None
@ -719,7 +775,10 @@ class Actor(DirectObject, NodePath):
Actor.notify.warning("no lod named: %s" % (lodName)) Actor.notify.warning("no lod named: %s" % (lodName))
return None return None
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
return partBundleDict.get(truePartName) partDef = partBundleDict.get(truePartName)
if partDef != None:
return partDef.partBundle
return None
def removePart(self, partName, lodName="lodRoot"): def removePart(self, partName, lodName="lodRoot"):
""" """
@ -735,7 +794,7 @@ class Actor(DirectObject, NodePath):
# remove the part # remove the part
if (partBundleDict.has_key(partName)): if (partBundleDict.has_key(partName)):
partBundleDict[partName].removeNode() partBundleDict[partName].partBundle.removeNode()
del(partBundleDict[partName]) del(partBundleDict[partName])
# find the corresponding anim control dict # find the corresponding anim control dict
@ -758,9 +817,9 @@ class Actor(DirectObject, NodePath):
if not partBundleDict: if not partBundleDict:
Actor.notify.warning("no lod named: %s" % (lodName)) Actor.notify.warning("no lod named: %s" % (lodName))
return return
part = partBundleDict.get(partName) partDef = partBundleDict.get(partName)
if part: if partDef:
part.hide() partDef.partBundle.hide()
else: else:
Actor.notify.warning("no part named %s!" % (partName)) Actor.notify.warning("no part named %s!" % (partName))
@ -773,9 +832,9 @@ class Actor(DirectObject, NodePath):
if not partBundleDict: if not partBundleDict:
Actor.notify.warning("no lod named: %s" % (lodName)) Actor.notify.warning("no lod named: %s" % (lodName))
return return
part = partBundleDict.get(partName) partDef = partBundleDict.get(partName)
if part: if partDef:
part.show() partDef.partBundle.show()
else: else:
Actor.notify.warning("no part named %s!" % (partName)) Actor.notify.warning("no part named %s!" % (partName))
@ -788,10 +847,10 @@ class Actor(DirectObject, NodePath):
if not partBundleDict: if not partBundleDict:
Actor.notify.warning("no lod named: %s" % (lodName)) Actor.notify.warning("no lod named: %s" % (lodName))
return return
part = partBundleDict.get(partName) partDef = partBundleDict.get(partName)
if part: if partDef:
part.show() partDef.partBundle.show()
part.getChildren().show() partDef.partBundle.getChildren().show()
else: else:
Actor.notify.warning("no part named %s!" % (partName)) Actor.notify.warning("no part named %s!" % (partName))
@ -810,9 +869,9 @@ class Actor(DirectObject, NodePath):
return None return None
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
part = partBundleDict.get(truePartName) partDef = partBundleDict.get(truePartName)
if part: if partDef:
bundle = part.node().getBundle() bundle = partDef.partBundle.node().getBundle()
else: else:
Actor.notify.warning("no part named %s!" % (partName)) Actor.notify.warning("no part named %s!" % (partName))
return None return None
@ -844,9 +903,9 @@ class Actor(DirectObject, NodePath):
return None return None
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
part = partBundleDict.get(truePartName) partDef = partBundleDict.get(truePartName)
if part: if partDef:
bundle = part.node().getBundle() bundle = partDef.partBundle.node().getBundle()
else: else:
Actor.notify.warning("no part named %s!" % (partName)) Actor.notify.warning("no part named %s!" % (partName))
return None return None
@ -878,9 +937,9 @@ class Actor(DirectObject, NodePath):
return None return None
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
part = partBundleDict.get(truePartName) partDef = partBundleDict.get(truePartName)
if part: if part:
bundle = part.node().getBundle() bundle = partDef.partBundle.node().getBundle()
else: else:
Actor.notify.warning("no part named %s!" % (partName)) Actor.notify.warning("no part named %s!" % (partName))
return None return None
@ -911,9 +970,9 @@ class Actor(DirectObject, NodePath):
partBundleDict = self.__partBundleDict.get(lodName) partBundleDict = self.__partBundleDict.get(lodName)
if partBundleDict: if partBundleDict:
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
part = partBundleDict.get(truePartName) partDef = partBundleDict.get(truePartName)
if part: if partDef:
joint = part.find("**/" + jointName) joint = partDef.partBundle.find("**/" + jointName)
if (joint.isEmpty()): if (joint.isEmpty()):
Actor.notify.warning("%s not found!" % (jointName)) Actor.notify.warning("%s not found!" % (jointName))
else: else:
@ -929,15 +988,15 @@ class Actor(DirectObject, NodePath):
partBundleDict = self.__partBundleDict.get(lodName) partBundleDict = self.__partBundleDict.get(lodName)
if partBundleDict: if partBundleDict:
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
part = partBundleDict.get(truePartName) partDef = partBundleDict.get(truePartName)
if part: if partDef:
anotherPart = partBundleDict.get(anotherPartName) anotherPartDef = partBundleDict.get(anotherPartName)
if anotherPart: if anotherPartDef:
joint = anotherPart.find("**/" + jointName) joint = anotherPartDef.partBundle.find("**/" + jointName)
if (joint.isEmpty()): if (joint.isEmpty()):
Actor.notify.warning("%s not found!" % (jointName)) Actor.notify.warning("%s not found!" % (jointName))
else: else:
part.reparentTo(joint) partDef.partBundle.reparentTo(joint)
else: else:
Actor.notify.warning("no part named %s!" % (anotherPartName)) Actor.notify.warning("no part named %s!" % (anotherPartName))
else: else:
@ -1191,14 +1250,14 @@ class Actor(DirectObject, NodePath):
for lodName, bundleDict in self.__partBundleDict.items(): for lodName, bundleDict in self.__partBundleDict.items():
if partName == None: if partName == None:
for partBundle in bundleDict.values(): for partDef in bundleDict.values():
bundles.append(partBundle.node().getBundle()) bundles.append(partDef.partBundle.node().getBundle())
else: else:
truePartName = self.__subpartDict.get(partName, [partName])[0] truePartName = self.__subpartDict.get(partName, [partName])[0]
partBundle = bundleDict.get(truePartName) partDef = bundleDict.get(truePartName)
if partBundle != None: if partDef != None:
bundles.append(partBundle.node().getBundle()) bundles.append(partDef.partBundle.node().getBundle())
else: else:
Actor.notify.warning("Couldn't find part: %s" % (partName)) Actor.notify.warning("Couldn't find part: %s" % (partName))
@ -1269,9 +1328,9 @@ class Actor(DirectObject, NodePath):
pass pass
else: else:
# bind the animation first if we need to # bind the animation first if we need to
if not isinstance(anim[1], AnimControl): if not isinstance(anim.animControl, AnimControl):
self.__bindAnimToPart(animName, partName, lodName) self.__bindAnimToPart(animName, partName, lodName)
return anim[1] return anim.animControl
return None return None
@ -1345,8 +1404,8 @@ class Actor(DirectObject, NodePath):
# get all playing animations # get all playing animations
for thisPart, animDict in animDictItems: for thisPart, animDict in animDictItems:
for anim in animDict.values(): for anim in animDict.values():
if isinstance(anim[1], AnimControl) and anim[1].isPlaying(): if isinstance(anim.animControl, AnimControl) and anim.animControl.isPlaying():
controls.append(anim[1]) controls.append(anim.animControl)
else: else:
# get the named animation only. # get the named animation only.
for thisPart, animDict in animDictItems: for thisPart, animDict in animDictItems:
@ -1356,10 +1415,10 @@ class Actor(DirectObject, NodePath):
# Maybe it's a subpart that hasn't been bound yet. # Maybe it's a subpart that hasn't been bound yet.
subpartDef = self.__subpartDict.get(pName) subpartDef = self.__subpartDict.get(pName)
if subpartDef: if subpartDef:
truePartName = subpartDef[0] truePartName = subpartDef.truePartName
anim = partDict[truePartName].get(animName) anim = partDict[truePartName].get(animName)
if anim: if anim:
anim = [anim[0], None] anim = anim.makeCopy()
animDict[animName] = anim animDict[animName] = anim
if anim == None: if anim == None:
@ -1368,7 +1427,7 @@ class Actor(DirectObject, NodePath):
pass pass
else: else:
# bind the animation first if we need to # bind the animation first if we need to
animControl = anim[1] animControl = anim.animControl
if animControl == None: if animControl == None:
animControl = self.__bindAnimToPart(animName, thisPart, lodName) animControl = self.__bindAnimToPart(animName, thisPart, lodName)
if animControl: if animControl:
@ -1392,27 +1451,31 @@ class Actor(DirectObject, NodePath):
# If we got a NodePath instead of a string, use *that* as # If we got a NodePath instead of a string, use *that* as
# the model directly. # the model directly.
if (copy): if (copy):
model = modelPath.copyTo(hidden) model = modelPath.copyTo(NodePath())
else: else:
model = modelPath model = modelPath
else: else:
# otherwise, we got the name of the model to load. # otherwise, we got the name of the model to load.
if (copy): loaderOptions = self.modelLoaderOptions
# We can't pass loaderOptions to loadModelCopy. if not copy:
model = loader.loadModelCopy(modelPath) # If copy = 0, then we should always hit the disk.
else: loaderOptions = LoaderOptions(loaderOptions)
# But if we're loading our own copy of the model, we loaderOptions.setFlags(loaderOptions.getFlags() & ~LoaderOptions.LFNoRamCache)
# can pass loaderOptions to specify that we want to
# Pass loaderOptions to specify that we want to
# get the skeleton model. This only matters to model # get the skeleton model. This only matters to model
# files (like .mb) for which we can choose to extract # files (like .mb) for which we can choose to extract
# either the skeleton or animation, or neither. # either the skeleton or animation, or neither.
model = loader.loadModel(modelPath, model = loader.loadModel(modelPath, loaderOptions = loaderOptions)
loaderOptions = self.modelLoaderOptions)
if (model == None): if (model == None):
raise StandardError, "Could not load Actor model %s" % (modelPath) raise StandardError, "Could not load Actor model %s" % (modelPath)
if (model.node().isOfType(PartBundleNode.getClassType())):
bundle = model
else:
bundle = model.find("**/+PartBundleNode") bundle = model.find("**/+PartBundleNode")
if (bundle.isEmpty()): if (bundle.isEmpty()):
Actor.notify.warning("%s is not a character!" % (modelPath)) Actor.notify.warning("%s is not a character!" % (modelPath))
model.reparentTo(self.__geomNode) model.reparentTo(self.__geomNode)
@ -1426,7 +1489,7 @@ class Actor(DirectObject, NodePath):
# Now extract out the PartBundleNode and integrate it with # Now extract out the PartBundleNode and integrate it with
# the Actor. # the Actor.
self.prepareBundle(bundle, partName, lodName) self.__prepareBundle(bundle, model, partName, lodName)
if numAnims != 0: if numAnims != 0:
# If the model had some animations, store them in the # If the model had some animations, store them in the
@ -1446,9 +1509,8 @@ class Actor(DirectObject, NodePath):
# animControl, but put None in for the filename. # animControl, but put None in for the filename.
self.__animControlDict[lodName][partName][animName] = [None, animControl] self.__animControlDict[lodName][partName][animName] = [None, animControl]
model.removeNode() def __prepareBundle(self, bundle, model,
partName="modelRoot", lodName="lodRoot"):
def prepareBundle(self, bundle, partName="modelRoot", lodName="lodRoot"):
assert partName not in self.__subpartDict assert partName not in self.__subpartDict
# Rename the node at the top of the hierarchy, if we # Rename the node at the top of the hierarchy, if we
@ -1469,20 +1531,17 @@ class Actor(DirectObject, NodePath):
needsDict = 0 needsDict = 0
if (lodName!="lodRoot"): if (lodName!="lodRoot"):
# instance to appropriate node under LOD switch # parent to appropriate node under LOD switch
#bundle = bundle.instanceTo(
# self.__LODNode.find("**/" + str(lodName)))
bundle.reparentTo(self.__LODNode.find("**/" + str(lodName))) bundle.reparentTo(self.__LODNode.find("**/" + str(lodName)))
else: else:
#bundle = bundle.instanceTo(self.__geomNode)
bundle.reparentTo(self.__geomNode) bundle.reparentTo(self.__geomNode)
if (needsDict): if (needsDict):
bundleDict[partName] = bundle bundleDict[partName] = Actor.PartDef(bundle, model.node())
self.__partBundleDict[lodName] = bundleDict self.__partBundleDict[lodName] = bundleDict
self.__updateSortedLODNames() self.__updateSortedLODNames()
else: else:
self.__partBundleDict[lodName][partName] = bundle self.__partBundleDict[lodName][partName] = Actor.PartDef(bundle, model.node())
def makeSubpart(self, partName, includeJoints, excludeJoints = [], def makeSubpart(self, partName, includeJoints, excludeJoints = [],
parent="modelRoot"): parent="modelRoot"):
@ -1513,19 +1572,15 @@ class Actor(DirectObject, NodePath):
assert partName not in self.__subpartDict assert partName not in self.__subpartDict
truePartName = partName subpartDef = self.__subpartDict.get(parent, Actor.SubpartDef(''))
prevSubset = PartSubset()
subpartDef = self.__subpartDict.get(partName)
if subpartDef:
truePartName, subset = subpartDef
subset = PartSubset(prevSubset) subset = PartSubset(subpartDef.subset)
for name in includeJoints: for name in includeJoints:
subset.addIncludeJoint(GlobPattern(name)) subset.addIncludeJoint(GlobPattern(name))
for name in excludeJoints: for name in excludeJoints:
subset.addExcludeJoint(GlobPattern(name)) subset.addExcludeJoint(GlobPattern(name))
self.__subpartDict[partName] = (parent, subset) self.__subpartDict[partName] = Actor.SubpartDef(parent, subset)
def setSubpartsComplete(self, flag): def setSubpartsComplete(self, flag):
@ -1567,13 +1622,14 @@ class Actor(DirectObject, NodePath):
assert Actor.notify.debug("in loadAnims: %s, part: %s, lod: %s" % assert Actor.notify.debug("in loadAnims: %s, part: %s, lod: %s" %
(anims, partName, lodName)) (anims, partName, lodName))
for animName in anims.keys(): for animName, filename in anims.items():
# make sure this lod is in anim control dict # make sure this lod is in anim control dict
self.__animControlDict.setdefault(lodName, {}) self.__animControlDict.setdefault(lodName, {})
self.__animControlDict[lodName].setdefault(partName, {}) self.__animControlDict[lodName].setdefault(partName, {})
# store the file path and None in place of the animControl.
# we will bind it only when played # store the file path only; we will bind it (and produce
self.__animControlDict[lodName][partName][animName] = [anims[animName], None] # an AnimControl) when it is played
self.__animControlDict[lodName][partName][animName] = Actor.AnimDef(filename)
def unloadAnims(self, anims, partName="modelRoot", lodName="lodRoot"): def unloadAnims(self, anims, partName="modelRoot", lodName="lodRoot"):
@ -1612,15 +1668,14 @@ class Actor(DirectObject, NodePath):
for animName in anims: for animName in anims:
# delete the anim control # delete the anim control
try: try:
animControlPair = self.__animControlDict[lodName][partName][animName] animDef = self.__animControlDict[lodName][partName][animName]
if animControlPair[1] != None: if animDef.animControl != None:
# Try to clear any control effects before we let # Try to clear any control effects before we let
# our handle on them go. This is especially # our handle on them go. This is especially
# important if the anim control was blending # important if the anim control was blending
# animations. # animations.
animControlPair[1].getPart().clearControlEffects() animDef.animControl.getPart().clearControlEffects()
del(animControlPair[1]) animDef.animControl = None
animControlPair.append(None)
except: except:
return return
@ -1649,12 +1704,7 @@ class Actor(DirectObject, NodePath):
for internal use only! for internal use only!
""" """
# make sure this anim is in the dict # make sure this anim is in the dict
subpartDef = self.__subpartDict.get(partName) subpartDef = self.__subpartDict.get(partName, Actor.SubpartDef(partName))
truePartName = partName
subset = PartSubset()
if subpartDef:
truePartName, subset = subpartDef
partDict = self.__animControlDict[lodName] partDict = self.__animControlDict[lodName]
animDict = partDict.get(partName) animDict = partDict.get(partName)
@ -1666,31 +1716,32 @@ class Actor(DirectObject, NodePath):
anim = animDict.get(animName) anim = animDict.get(animName)
if anim == None: if anim == None:
# It must be a subpart that hasn't been bound yet. # It must be a subpart that hasn't been bound yet.
if subpartDef != None: anim = partDict[subpartDef.truePartName].get(animName)
anim = partDict[truePartName].get(animName) anim = anim.makeCopy()
anim = [anim[0], None]
animDict[animName] = anim animDict[animName] = anim
if anim == None: if anim == None:
Actor.notify.error("actor has no animation %s", animName) Actor.notify.error("actor has no animation %s", animName)
# only bind if not already bound! # only bind if not already bound!
if anim[1]: if anim.animControl:
return anim[1] return anim.animControl
# fetch a copy from the modelPool, or if we weren't careful # fetch a copy from the modelPool, or if we weren't careful
# enough to preload, fetch from disk # enough to preload, fetch from disk
animPath = anim[0] animPath = anim.filename
if self.__autoCopy: loaderOptions = self.animLoaderOptions
animNode = loader.loadModelOnce(animPath) if not self.__autoCopy:
else: # If copy = 0, then we should always hit the disk.
animNode = loader.loadModel(animPath, loaderOptions = LoaderOptions(loaderOptions)
loaderOptions = self.animLoaderOptions) loaderOptions.setFlags(loaderOptions.getFlags() & ~LoaderOptions.LFNoRamCache)
animNode = loader.loadModel(animPath, loaderOptions = loaderOptions)
if animNode == None: if animNode == None:
return None return None
animBundle = (animNode.find("**/+AnimBundleNode").node()).getBundle() animBundle = (animNode.find("**/+AnimBundleNode").node()).getBundle()
bundle = self.__partBundleDict[lodName][truePartName].node().getBundle() bundle = self.__partBundleDict[lodName][subpartDef.truePartName].partBundle.node().getBundle()
# Are there any controls requested for joints in this bundle? # Are there any controls requested for joints in this bundle?
# If so, apply them. # If so, apply them.
@ -1706,13 +1757,13 @@ class Actor(DirectObject, NodePath):
Actor.notify.error("controlled joint %s is not present" % jointName) Actor.notify.error("controlled joint %s is not present" % jointName)
# bind anim # bind anim
animControl = bundle.bindAnim(animBundle, -1, subset) animControl = bundle.bindAnim(animBundle, -1, subpartDef.subset)
if (animControl == None): if (animControl == None):
Actor.notify.error("Null AnimControl: %s" % (animName)) Actor.notify.error("Null AnimControl: %s" % (animName))
else: else:
# store the animControl # store the animControl
anim[1] = animControl anim.animControl = animControl
assert Actor.notify.debug("binding anim: %s to part: %s, lod: %s" % assert Actor.notify.debug("binding anim: %s to part: %s, lod: %s" %
(animName, partName, lodName)) (animName, partName, lodName))
return animControl return animControl
@ -1733,14 +1784,14 @@ class Actor(DirectObject, NodePath):
if partLod.isEmpty(): if partLod.isEmpty():
Actor.notify.warning("no lod named: %s" % (lodName)) Actor.notify.warning("no lod named: %s" % (lodName))
return None return None
for partName in other.__partBundleDict[lodName].keys(): for partName, partDef in other.__partBundleDict[lodName].items():
model = partDef.partModel.copySubgraph()
# find the part in our tree # find the part in our tree
#partBundle = self.find("**/" + Actor.partPrefix + partName)
# Asad: changed above line to below
partBundle = partLod.find("**/" + Actor.partPrefix + partName) partBundle = partLod.find("**/" + Actor.partPrefix + partName)
if (partBundle != None): if (partBundle != None):
# store the part bundle # store the part bundle
self.__partBundleDict[lodName][partName] = partBundle self.__partBundleDict[lodName][partName] = Actor.PartDef(partBundle, model)
else: else:
Actor.notify.error("lod: %s has no matching part: %s" % Actor.notify.error("lod: %s has no matching part: %s" %
(lodName, partName)) (lodName, partName))
@ -1755,8 +1806,7 @@ class Actor(DirectObject, NodePath):
for partName, subpartDef in other.__subpartDict.items(): for partName, subpartDef in other.__subpartDict.items():
subpartDefCopy = subpartDef subpartDefCopy = subpartDef
if subpartDef: if subpartDef:
truePartName, subset = subpartDef subpartDef = subpartDef.makeCopy()
subpartDefCopy = (truePartName, PartSubset(subset))
self.__subpartDict[partName] = subpartDef self.__subpartDict[partName] = subpartDef
def __copyAnimControls(self, other): def __copyAnimControls(self, other):
@ -1770,9 +1820,10 @@ class Actor(DirectObject, NodePath):
for partName in other.__animControlDict[lodName].keys(): for partName in other.__animControlDict[lodName].keys():
self.__animControlDict[lodName][partName] = {} self.__animControlDict[lodName][partName] = {}
for animName in other.__animControlDict[lodName][partName].keys(): for animName in other.__animControlDict[lodName][partName].keys():
# else just copy what's there anim = other.__animControlDict[lodName][partName][animName]
self.__animControlDict[lodName][partName][animName] = \ anim = anim.makeCopy()
[other.__animControlDict[lodName][partName][animName][0], None] self.__animControlDict[lodName][partName][animName] = anim
def actorInterval(self, *args, **kw): def actorInterval(self, *args, **kw):
from direct.interval import ActorInterval from direct.interval import ActorInterval