mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
bindAnim() improvements
This commit is contained in:
parent
8c92a5e207
commit
63a948749a
@ -1535,12 +1535,13 @@ class Actor(DirectObject, NodePath):
|
||||
except:
|
||||
return None
|
||||
|
||||
def getAnimControl(self, animName, partName=None, lodName=None):
|
||||
def getAnimControl(self, animName, partName=None, lodName=None,
|
||||
allowAsyncBind = True):
|
||||
"""
|
||||
getAnimControl(self, string, string, string="lodRoot")
|
||||
Search the animControl dictionary indicated by lodName for
|
||||
a given anim and part. If none specified, try the first part and lod.
|
||||
Return the animControl if present, or None otherwise
|
||||
Return the animControl if present, or None otherwise.
|
||||
"""
|
||||
|
||||
if not partName:
|
||||
@ -1571,21 +1572,31 @@ class Actor(DirectObject, NodePath):
|
||||
else:
|
||||
# bind the animation first if we need to
|
||||
if not anim.animControl:
|
||||
self.__bindAnimToPart(animName, partName, lodName)
|
||||
self.__bindAnimToPart(animName, partName, lodName,
|
||||
allowAsyncBind = allowAsyncBind)
|
||||
return anim.animControl
|
||||
|
||||
return None
|
||||
|
||||
def getAnimControls(self, animName=None, partName=None, lodName=None):
|
||||
def getAnimControls(self, animName=None, partName=None, lodName=None,
|
||||
allowAsyncBind = True):
|
||||
"""getAnimControls(self, string, string=None, string=None)
|
||||
|
||||
Returns a list of the AnimControls that represent the given
|
||||
animation for the given part and the given lod. If animName
|
||||
is omitted, the currently-playing animation (or all
|
||||
currently-playing animations) is returned. If partName is
|
||||
omitted, all parts are returned (or possibly the one overall
|
||||
Actor part, according to the subpartsComplete flag). If
|
||||
lodName is omitted, all LOD's are returned.
|
||||
animation for the given part and the given lod.
|
||||
|
||||
If animName is None or omitted, the currently-playing
|
||||
animation (or all currently-playing animations) is returned.
|
||||
If animName is True, all animations are returned. If animName
|
||||
is a single string name, that particular animation is
|
||||
returned. If animName is a list of string names, all of the
|
||||
names animations are returned.
|
||||
|
||||
If partName is None or omitted, all parts are returned (or
|
||||
possibly the one overall Actor part, according to the
|
||||
subpartsComplete flag).
|
||||
|
||||
If lodName is None or omitted, all LOD's are returned.
|
||||
"""
|
||||
|
||||
if partName == None and self.__subpartsComplete:
|
||||
@ -1642,15 +1653,25 @@ class Actor(DirectObject, NodePath):
|
||||
else:
|
||||
animDictItems.append((pName, animDict))
|
||||
|
||||
if animName == None:
|
||||
if animName is None:
|
||||
# get all playing animations
|
||||
for thisPart, animDict in animDictItems:
|
||||
for anim in animDict.values():
|
||||
if anim.animControl and anim.animControl.isPlaying():
|
||||
controls.append(anim.animControl)
|
||||
else:
|
||||
# get the named animation only.
|
||||
# get the named animation(s) only.
|
||||
if isinstance(animName, types.StringType):
|
||||
# A single animName
|
||||
animNameList = [animName]
|
||||
else:
|
||||
# A list of animNames, or True to indicate all anims.
|
||||
animNameList = animName
|
||||
for thisPart, animDict in animDictItems:
|
||||
names = animNameList
|
||||
if animNameList is True:
|
||||
names = animDict.keys()
|
||||
for animName in names:
|
||||
anim = animDict.get(animName)
|
||||
if anim == None and partName != None:
|
||||
for pName in partNameList:
|
||||
@ -1671,7 +1692,9 @@ class Actor(DirectObject, NodePath):
|
||||
# bind the animation first if we need to
|
||||
animControl = anim.animControl
|
||||
if animControl == None:
|
||||
animControl = self.__bindAnimToPart(animName, thisPart, lodName)
|
||||
animControl = self.__bindAnimToPart(
|
||||
animName, thisPart, lodName,
|
||||
allowAsyncBind = allowAsyncBind)
|
||||
if animControl:
|
||||
controls.append(animControl)
|
||||
|
||||
@ -2027,65 +2050,45 @@ class Actor(DirectObject, NodePath):
|
||||
except:
|
||||
return
|
||||
|
||||
def bindAnim(self, animName, partName="modelRoot", lodName="lodRoot"):
|
||||
"""bindAnim(self, string, string='modelRoot', string='lodRoot')
|
||||
Bind the named animation to the named part and lod
|
||||
def bindAnim(self, animName, partName = None, lodName = None,
|
||||
allowAsyncBind = False):
|
||||
"""
|
||||
if lodName == None or self.mergeLODBundles:
|
||||
lodNames = self.__animControlDict.keys()
|
||||
else:
|
||||
lodNames = [lodName]
|
||||
Binds the named animation to the named part and/or lod. If
|
||||
allowAsyncBind is False, this guarantees that the animation is
|
||||
bound immediately--the animation is never bound in a
|
||||
sub-thread; it will be loaded and bound in the main thread, so
|
||||
it will be available by the time this method returns.
|
||||
|
||||
# loop over all lods
|
||||
for thisLod in lodNames:
|
||||
if partName == None:
|
||||
partNames = self.__partBundleDict[thisLod].keys()
|
||||
else:
|
||||
partNames = [partName]
|
||||
# loop over all parts
|
||||
for thisPart in partNames:
|
||||
ac = self.__bindAnimToPart(animName, thisPart, thisLod)
|
||||
The parameters are the same as that for getAnimControls(). In
|
||||
fact, this method is a thin wrapper around that other method.
|
||||
|
||||
Use this method if you need to ensure that an animation is
|
||||
available before you start to play it, and you don't mind
|
||||
holding up the render for a frame or two until the animation
|
||||
is available.
|
||||
"""
|
||||
self.getAnimControls(animName = animName, partName = partName,
|
||||
lodName = lodName,
|
||||
allowAsyncBind = allowAsyncBind)
|
||||
|
||||
def bindAllAnims(self):
|
||||
def bindAllAnims(self, allowAsyncBind = False):
|
||||
"""Loads and binds all animations that have been defined for
|
||||
the Actor. """
|
||||
self.getAnimControls(animName = True, allowAsyncBind = allowAsyncBind)
|
||||
|
||||
for lodName, partDict in self.__animControlDict.items():
|
||||
# Now, build the list of partNames and the corresponding
|
||||
# animDicts.
|
||||
for thisPart, animDict in partDict.items():
|
||||
if animDict == None:
|
||||
# Maybe it's a subpart that hasn't been bound yet.
|
||||
subpartDef = self.__subpartDict.get(pName)
|
||||
if subpartDef:
|
||||
animDict = {}
|
||||
partDict[pName] = animDict
|
||||
|
||||
for animName, anim in animDict.items():
|
||||
if anim == None and partName != None:
|
||||
for pName in partNameList:
|
||||
# Maybe it's a subpart that hasn't been bound yet.
|
||||
subpartDef = self.__subpartDict.get(pName)
|
||||
if subpartDef:
|
||||
truePartName = subpartDef.truePartName
|
||||
anim = partDict[truePartName].get(animName)
|
||||
if anim:
|
||||
anim = anim.makeCopy()
|
||||
animDict[animName] = anim
|
||||
|
||||
if anim.animControl == None:
|
||||
self.__bindAnimToPart(animName, thisPart, lodName)
|
||||
|
||||
def __bindAnimToPart(self, animName, partName, lodName):
|
||||
def __bindAnimToPart(self, animName, partName, lodName,
|
||||
allowAsyncBind = True):
|
||||
"""
|
||||
for internal use only!
|
||||
Binds the named animation to the named part/lod and returns
|
||||
the associated animControl. The animation is loaded and bound
|
||||
in a sub-thread, if allowAsyncBind is True,
|
||||
self.allowAsyncBind is True, threading is enabled, and the
|
||||
animation has a preload table generated for it (e.g. via
|
||||
"egg-optchar -preload"). Even though the animation may or may
|
||||
not be yet bound at the time this function returns, a usable
|
||||
animControl is returned, or None if the animation could not be
|
||||
bound.
|
||||
"""
|
||||
|
||||
# Temporary check for old Pandas.
|
||||
if not hasattr(PartBundle, 'loadBindAnim'):
|
||||
return self.__tempHackDoNotUseBindAnimToPart(animName, partName, lodName)
|
||||
|
||||
# make sure this anim is in the dict
|
||||
subpartDef = self.__subpartDict.get(partName, Actor.SubpartDef(partName))
|
||||
|
||||
@ -2120,7 +2123,7 @@ class Actor(DirectObject, NodePath):
|
||||
# will still return a usable AnimControl.
|
||||
animControl = bundle.loadBindAnim(
|
||||
loader.loader, Filename(anim.filename), -1,
|
||||
subpartDef.subset, self.allowAsyncBind)
|
||||
subpartDef.subset, allowAsyncBind and self.allowAsyncBind)
|
||||
|
||||
if not animControl:
|
||||
# Couldn't bind. (This implies the binding operation was
|
||||
@ -2133,69 +2136,6 @@ class Actor(DirectObject, NodePath):
|
||||
(animName, partName, lodName))
|
||||
return animControl
|
||||
|
||||
def __tempHackDoNotUseBindAnimToPart(self, animName, partName, lodName):
|
||||
""" This method exists only temporarily to support old Pandas
|
||||
that don't yet have PartBundle.loadBindAnim(). This method is
|
||||
the old implementation of __bindAnimToPart(), from before we
|
||||
added asynchronous support. """
|
||||
|
||||
# make sure this anim is in the dict
|
||||
subpartDef = self.__subpartDict.get(partName, Actor.SubpartDef(partName))
|
||||
|
||||
partDict = self.__animControlDict[lodName]
|
||||
animDict = partDict.get(partName)
|
||||
if animDict == None:
|
||||
# It must be a subpart that hasn't been bound yet.
|
||||
animDict = {}
|
||||
partDict[partName] = animDict
|
||||
|
||||
anim = animDict.get(animName)
|
||||
if anim == None:
|
||||
# It must be a subpart that hasn't been bound yet.
|
||||
anim = partDict[subpartDef.truePartName].get(animName)
|
||||
anim = anim.makeCopy()
|
||||
animDict[animName] = anim
|
||||
|
||||
if anim == None:
|
||||
Actor.notify.error("actor has no animation %s", animName)
|
||||
|
||||
# only bind if not already bound!
|
||||
if anim.animControl:
|
||||
return anim.animControl
|
||||
|
||||
if self.mergeLODBundles:
|
||||
bundle = self.__commonBundleHandles[subpartDef.truePartName].getBundle()
|
||||
else:
|
||||
bundle = self.__partBundleDict[lodName][subpartDef.truePartName].getBundle()
|
||||
|
||||
# fetch a copy from the modelPool, or if we weren't careful
|
||||
# enough to preload, fetch from disk
|
||||
animPath = anim.filename
|
||||
loaderOptions = self.animLoaderOptions
|
||||
if not self.__autoCopy:
|
||||
# If copy = 0, then we should always hit the disk.
|
||||
loaderOptions = LoaderOptions(loaderOptions)
|
||||
loaderOptions.setFlags(loaderOptions.getFlags() & ~LoaderOptions.LFNoRamCache)
|
||||
|
||||
animNode = loader.loadModel(animPath, loaderOptions = loaderOptions)
|
||||
if animNode == None:
|
||||
return None
|
||||
animBundle = (animNode.find("**/+AnimBundleNode").node()).getBundle()
|
||||
animModel = animNode.node()
|
||||
|
||||
# bind anim
|
||||
animControl = bundle.bindAnim(animBundle, -1, subpartDef.subset)
|
||||
|
||||
if (animControl == None):
|
||||
Actor.notify.error("Null AnimControl: %s" % (animName))
|
||||
else:
|
||||
# store the animControl
|
||||
anim.animControl = animControl
|
||||
anim.animModel = animModel
|
||||
assert Actor.notify.debug("binding anim: %s to part: %s, lod: %s" %
|
||||
(animName, partName, lodName))
|
||||
return animControl
|
||||
|
||||
def __copyPartBundles(self, other):
|
||||
"""__copyPartBundles(self, Actor)
|
||||
Copy the part bundle dictionary from another actor as this
|
||||
|
Loading…
x
Reference in New Issue
Block a user