mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
mergeLODBundles
This commit is contained in:
parent
f7cc947329
commit
516b5a8baf
@ -21,7 +21,6 @@ class Actor(DirectObject, NodePath):
|
|||||||
animLoaderOptions = LoaderOptions(LoaderOptions.LFSearch |
|
animLoaderOptions = LoaderOptions(LoaderOptions.LFSearch |
|
||||||
LoaderOptions.LFReportErrors |
|
LoaderOptions.LFReportErrors |
|
||||||
LoaderOptions.LFConvertAnim)
|
LoaderOptions.LFConvertAnim)
|
||||||
|
|
||||||
class PartDef:
|
class PartDef:
|
||||||
|
|
||||||
"""Instances of this class are stored within the
|
"""Instances of this class are stored within the
|
||||||
@ -85,7 +84,8 @@ class Actor(DirectObject, NodePath):
|
|||||||
return 'Actor.SubpartDef(%s, %s)' % (repr(self.truePartName), repr(self.subset))
|
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, flattenable = 1, setFinal = 0):
|
lodNode = None, flattenable = 1, setFinal = 0,
|
||||||
|
mergeLODBundles = None):
|
||||||
"""__init__(self, string | string:string{}, string:string{} |
|
"""__init__(self, string | string:string{}, string:string{} |
|
||||||
string:(string:string{}){}, Actor=None)
|
string:(string:string{}){}, Actor=None)
|
||||||
Actor constructor: can be used to create single or multipart
|
Actor constructor: can be used to create single or multipart
|
||||||
@ -153,7 +153,27 @@ class Actor(DirectObject, NodePath):
|
|||||||
|
|
||||||
self.__autoCopy = copy
|
self.__autoCopy = copy
|
||||||
|
|
||||||
|
# Set the mergeLODBundles flag. If this is true, all
|
||||||
|
# different LOD's will be merged into a single common bundle
|
||||||
|
# (joint hierarchy). All LOD's will thereafter share the same
|
||||||
|
# skeleton, even though they may have been loaded from
|
||||||
|
# different egg files. If this is false, LOD's will be kept
|
||||||
|
# completely isolated, and each LOD will have its own
|
||||||
|
# skeleton.
|
||||||
|
|
||||||
|
# When this flag is true, __animControlDict has only one key,
|
||||||
|
# ['common']; when it is false, __animControlDict has one key
|
||||||
|
# per each LOD name.
|
||||||
|
|
||||||
|
if mergeLODBundles == None:
|
||||||
|
# If this isn't specified, it comes from the Config.prc
|
||||||
|
# file.
|
||||||
|
self.mergeLODBundles = base.config.GetBool('merge-lod-bundles', 0)
|
||||||
|
else:
|
||||||
|
self.mergeLODBundles = mergeLODBundles
|
||||||
|
|
||||||
# create data structures
|
# create data structures
|
||||||
|
self.__commonBundles = {}
|
||||||
self.__partBundleDict = {}
|
self.__partBundleDict = {}
|
||||||
self.__subpartDict = {}
|
self.__subpartDict = {}
|
||||||
self.__sortedLODNames = []
|
self.__sortedLODNames = []
|
||||||
@ -391,8 +411,7 @@ class Actor(DirectObject, NodePath):
|
|||||||
Useful for iterating over details of an actor.
|
Useful for iterating over details of an actor.
|
||||||
"""
|
"""
|
||||||
lodInfo = []
|
lodInfo = []
|
||||||
for lodName in self.__animControlDict.keys():
|
for lodName, partDict in self.__animControlDict.items():
|
||||||
partDict = self.__animControlDict[lodName]
|
|
||||||
partInfo = []
|
partInfo = []
|
||||||
for partName in partDict.keys():
|
for partName in partDict.keys():
|
||||||
subpartDef = self.__subpartDict.get(partName, Actor.SubpartDef(partName))
|
subpartDef = self.__subpartDict.get(partName, Actor.SubpartDef(partName))
|
||||||
@ -456,6 +475,7 @@ class Actor(DirectObject, NodePath):
|
|||||||
NodePath.removeNode(self)
|
NodePath.removeNode(self)
|
||||||
|
|
||||||
def clearPythonData(self):
|
def clearPythonData(self):
|
||||||
|
self.__commonBundles = {}
|
||||||
self.__partBundleDict = {}
|
self.__partBundleDict = {}
|
||||||
self.__subpartDict = {}
|
self.__subpartDict = {}
|
||||||
self.__sortedLODNames = []
|
self.__sortedLODNames = []
|
||||||
@ -878,6 +898,8 @@ class Actor(DirectObject, NodePath):
|
|||||||
del(partBundleDict[partName])
|
del(partBundleDict[partName])
|
||||||
|
|
||||||
# find the corresponding anim control dict
|
# find the corresponding anim control dict
|
||||||
|
if self.mergeLODBundles:
|
||||||
|
lodName = 'common'
|
||||||
partDict = self.__animControlDict.get(lodName)
|
partDict = self.__animControlDict.get(lodName)
|
||||||
if not partDict:
|
if not partDict:
|
||||||
Actor.notify.warning("no lod named: %s" % (lodName))
|
Actor.notify.warning("no lod named: %s" % (lodName))
|
||||||
@ -1455,7 +1477,9 @@ class Actor(DirectObject, NodePath):
|
|||||||
getAnimFilename(self, animName)
|
getAnimFilename(self, animName)
|
||||||
return the animFilename given the animName
|
return the animFilename given the animName
|
||||||
"""
|
"""
|
||||||
if self.switches:
|
if self.mergeLODBundles:
|
||||||
|
lodName = 'common'
|
||||||
|
elif self.switches:
|
||||||
lodName = str(self.switches.keys()[0])
|
lodName = str(self.switches.keys()[0])
|
||||||
else:
|
else:
|
||||||
lodName = 'lodRoot'
|
lodName = 'lodRoot'
|
||||||
@ -1476,7 +1500,9 @@ class Actor(DirectObject, NodePath):
|
|||||||
if not partName:
|
if not partName:
|
||||||
partName = 'modelRoot'
|
partName = 'modelRoot'
|
||||||
|
|
||||||
if not lodName:
|
if self.mergeLODBundles:
|
||||||
|
lodName = 'common'
|
||||||
|
elif not lodName:
|
||||||
if self.switches:
|
if self.switches:
|
||||||
lodName = str(self.switches.keys()[0])
|
lodName = str(self.switches.keys()[0])
|
||||||
else:
|
else:
|
||||||
@ -1525,7 +1551,7 @@ class Actor(DirectObject, NodePath):
|
|||||||
controls = []
|
controls = []
|
||||||
# build list of lodNames and corresponding animControlDicts
|
# build list of lodNames and corresponding animControlDicts
|
||||||
# requested.
|
# requested.
|
||||||
if lodName == None:
|
if lodName == None or self.mergeLODBundles:
|
||||||
# Get all LOD's
|
# Get all LOD's
|
||||||
animControlDictItems = self.__animControlDict.items()
|
animControlDictItems = self.__animControlDict.items()
|
||||||
else:
|
else:
|
||||||
@ -1641,10 +1667,10 @@ class Actor(DirectObject, NodePath):
|
|||||||
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())):
|
if (model.node().isOfType(Character.getClassType())):
|
||||||
bundleNP = model
|
bundleNP = model
|
||||||
else:
|
else:
|
||||||
bundleNP = model.find("**/+PartBundleNode")
|
bundleNP = model.find("**/+Character")
|
||||||
|
|
||||||
if (bundleNP.isEmpty()):
|
if (bundleNP.isEmpty()):
|
||||||
Actor.notify.warning("%s is not a character!" % (modelPath))
|
Actor.notify.warning("%s is not a character!" % (modelPath))
|
||||||
@ -1657,7 +1683,7 @@ class Actor(DirectObject, NodePath):
|
|||||||
autoBind(model.node(), acc, ~0)
|
autoBind(model.node(), acc, ~0)
|
||||||
numAnims = acc.getNumAnims()
|
numAnims = acc.getNumAnims()
|
||||||
|
|
||||||
# Now extract out the PartBundleNode and integrate it with
|
# Now extract out the Character and integrate it with
|
||||||
# the Actor.
|
# the Actor.
|
||||||
self.__prepareBundle(bundleNP, model, partName, lodName)
|
self.__prepareBundle(bundleNP, model, partName, lodName)
|
||||||
|
|
||||||
@ -1667,6 +1693,8 @@ class Actor(DirectObject, NodePath):
|
|||||||
Actor.notify.info("model contains %s animations." % (numAnims))
|
Actor.notify.info("model contains %s animations." % (numAnims))
|
||||||
|
|
||||||
# make sure this lod is in anim control dict
|
# make sure this lod is in anim control dict
|
||||||
|
if self.mergeLODBundles:
|
||||||
|
lodName = 'common'
|
||||||
self.__animControlDict.setdefault(lodName, {})
|
self.__animControlDict.setdefault(lodName, {})
|
||||||
self.__animControlDict[lodName].setdefault(partName, {})
|
self.__animControlDict[lodName].setdefault(partName, {})
|
||||||
|
|
||||||
@ -1695,12 +1723,12 @@ class Actor(DirectObject, NodePath):
|
|||||||
# we rename this node to make Actor copying easier
|
# we rename this node to make Actor copying easier
|
||||||
bundleNP.node().setName("%s%s"%(Actor.partPrefix,partName))
|
bundleNP.node().setName("%s%s"%(Actor.partPrefix,partName))
|
||||||
|
|
||||||
if (self.__partBundleDict.has_key(lodName) == 0):
|
bundleDict = self.__partBundleDict.get(lodName, None)
|
||||||
|
if bundleDict == None:
|
||||||
# make a dictionary to store these parts in
|
# make a dictionary to store these parts in
|
||||||
needsDict = 1
|
|
||||||
bundleDict = {}
|
bundleDict = {}
|
||||||
else:
|
self.__partBundleDict[lodName] = bundleDict
|
||||||
needsDict = 0
|
self.__updateSortedLODNames()
|
||||||
|
|
||||||
if (lodName!="lodRoot"):
|
if (lodName!="lodRoot"):
|
||||||
# parent to appropriate node under LOD switch
|
# parent to appropriate node under LOD switch
|
||||||
@ -1712,12 +1740,19 @@ class Actor(DirectObject, NodePath):
|
|||||||
# A model loaded from disk will always have just one bundle.
|
# A model loaded from disk will always have just one bundle.
|
||||||
assert(node.getNumBundles() == 1)
|
assert(node.getNumBundles() == 1)
|
||||||
bundle = node.getBundle(0)
|
bundle = node.getBundle(0)
|
||||||
if (needsDict):
|
|
||||||
bundleDict[partName] = Actor.PartDef(bundleNP, bundle, model.node())
|
if self.mergeLODBundles:
|
||||||
self.__partBundleDict[lodName] = bundleDict
|
loadedBundle = self.__commonBundles.get(partName, None)
|
||||||
self.__updateSortedLODNames()
|
if loadedBundle:
|
||||||
|
# We've already got a bundle for this part; merge it.
|
||||||
|
node.mergeBundles(bundle, loadedBundle)
|
||||||
|
bundle = loadedBundle
|
||||||
else:
|
else:
|
||||||
self.__partBundleDict[lodName][partName] = Actor.PartDef(bundleNP, bundle, model.node())
|
# We haven't already got a bundle for this part; store it.
|
||||||
|
self.__commonBundles[partName] = bundle
|
||||||
|
|
||||||
|
bundleDict[partName] = Actor.PartDef(bundleNP, bundle, model.node())
|
||||||
|
|
||||||
|
|
||||||
def makeSubpart(self, partName, includeJoints, excludeJoints = [],
|
def makeSubpart(self, partName, includeJoints, excludeJoints = [],
|
||||||
parent="modelRoot"):
|
parent="modelRoot"):
|
||||||
@ -1796,7 +1831,9 @@ class Actor(DirectObject, NodePath):
|
|||||||
anims in the form animName:animPath{}
|
anims in the form animName:animPath{}
|
||||||
"""
|
"""
|
||||||
reload = True
|
reload = True
|
||||||
if (lodName == 'all'):
|
if self.mergeLODBundles:
|
||||||
|
lodNames = ['common']
|
||||||
|
elif lodName == 'all':
|
||||||
reload = False
|
reload = False
|
||||||
lodNames = self.switches.keys()
|
lodNames = self.switches.keys()
|
||||||
lodNames.sort()
|
lodNames.sort()
|
||||||
@ -1831,8 +1868,12 @@ class Actor(DirectObject, NodePath):
|
|||||||
self.__animControlDict[lName][partName][animName] = Actor.AnimDef(filename)
|
self.__animControlDict[lName][partName][animName] = Actor.AnimDef(filename)
|
||||||
|
|
||||||
def initAnimsOnAllLODs(self,partNames):
|
def initAnimsOnAllLODs(self,partNames):
|
||||||
|
if self.mergeLODBundles:
|
||||||
|
lodNames = ['common']
|
||||||
|
else:
|
||||||
|
lodNames = self.__partBundleDict.keys()
|
||||||
|
|
||||||
for lod in self.__partBundleDict.keys():
|
for lod in lodNames:
|
||||||
for part in partNames:
|
for part in partNames:
|
||||||
self.__animControlDict.setdefault(lod,{})
|
self.__animControlDict.setdefault(lod,{})
|
||||||
self.__animControlDict[lod].setdefault(part, {})
|
self.__animControlDict[lod].setdefault(part, {})
|
||||||
@ -1853,10 +1894,14 @@ class Actor(DirectObject, NodePath):
|
|||||||
to 'lodRoot' for non-LOD actors) and dict of corresponding
|
to 'lodRoot' for non-LOD actors) and dict of corresponding
|
||||||
anims in the form animName:animPath{}
|
anims in the form animName:animPath{}
|
||||||
"""
|
"""
|
||||||
|
if self.mergeLODBundles:
|
||||||
|
lodNames = ['common']
|
||||||
|
else:
|
||||||
|
lodNames = self.__partBundleDict.keys()
|
||||||
|
|
||||||
for animName, filename in anims.items():
|
for animName, filename in anims.items():
|
||||||
# make sure this lod is in anim control dict
|
# make sure this lod is in anim control dict
|
||||||
for lod in self.__partBundleDict.keys():
|
for lod in lodNames:
|
||||||
# store the file path only; we will bind it (and produce
|
# store the file path only; we will bind it (and produce
|
||||||
# an AnimControl) when it is played
|
# an AnimControl) when it is played
|
||||||
|
|
||||||
@ -1875,7 +1920,7 @@ class Actor(DirectObject, NodePath):
|
|||||||
assert Actor.notify.debug("in unloadAnims: %s, part: %s, lod: %s" %
|
assert Actor.notify.debug("in unloadAnims: %s, part: %s, lod: %s" %
|
||||||
(anims, partName, lodName))
|
(anims, partName, lodName))
|
||||||
|
|
||||||
if (lodName == None):
|
if lodName == None or self.mergeLODBundles:
|
||||||
lodNames = self.__animControlDict.keys()
|
lodNames = self.__animControlDict.keys()
|
||||||
else:
|
else:
|
||||||
lodNames = [lodName]
|
lodNames = [lodName]
|
||||||
@ -1915,7 +1960,7 @@ class Actor(DirectObject, NodePath):
|
|||||||
"""bindAnim(self, string, string='modelRoot', string='lodRoot')
|
"""bindAnim(self, string, string='modelRoot', string='lodRoot')
|
||||||
Bind the named animation to the named part and lod
|
Bind the named animation to the named part and lod
|
||||||
"""
|
"""
|
||||||
if lodName == None:
|
if lodName == None or self.mergeLODBundles:
|
||||||
lodNames = self.__animControlDict.keys()
|
lodNames = self.__animControlDict.keys()
|
||||||
else:
|
else:
|
||||||
lodNames = [lodName]
|
lodNames = [lodName]
|
||||||
@ -1989,6 +2034,9 @@ class Actor(DirectObject, NodePath):
|
|||||||
if anim.animControl:
|
if anim.animControl:
|
||||||
return anim.animControl
|
return anim.animControl
|
||||||
|
|
||||||
|
if self.mergeLODBundles:
|
||||||
|
bundle = self.__commonBundles[subpartDef.truePartName]
|
||||||
|
else:
|
||||||
bundle = self.__partBundleDict[lodName][subpartDef.truePartName].partBundle
|
bundle = self.__partBundleDict[lodName][subpartDef.truePartName].partBundle
|
||||||
|
|
||||||
# fetch a copy from the modelPool, or if we weren't careful
|
# fetch a copy from the modelPool, or if we weren't careful
|
||||||
@ -2071,6 +2119,9 @@ class Actor(DirectObject, NodePath):
|
|||||||
dictionary of another actor. Bind these anim's to the part
|
dictionary of another actor. Bind these anim's to the part
|
||||||
bundles in our part bundle dict that have matching names, and
|
bundles in our part bundle dict that have matching names, and
|
||||||
store the resulting anim controls in our own part bundle dict"""
|
store the resulting anim controls in our own part bundle dict"""
|
||||||
|
|
||||||
|
assert(other.mergeLODBundles == self.mergeLODBundles)
|
||||||
|
|
||||||
for lodName in other.__animControlDict.keys():
|
for lodName in other.__animControlDict.keys():
|
||||||
self.__animControlDict[lodName] = {}
|
self.__animControlDict[lodName] = {}
|
||||||
for partName in other.__animControlDict[lodName].keys():
|
for partName in other.__animControlDict[lodName].keys():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user