Pārlūkot izejas kodu

mergeLODBundles

David Rose 18 gadi atpakaļ
vecāks
revīzija
516b5a8baf
1 mainītis faili ar 78 papildinājumiem un 27 dzēšanām
  1. 78 27
      direct/src/actor/Actor.py

+ 78 - 27
direct/src/actor/Actor.py

@@ -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():
-            partDict = self.__animControlDict[lodName]
+        for lodName, partDict in self.__animControlDict.items():
             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:
-            needsDict = 0
+            self.__partBundleDict[lodName] = bundleDict
+            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())
-            self.__partBundleDict[lodName] = bundleDict
-            self.__updateSortedLODNames()
-        else:
-            self.__partBundleDict[lodName][partName] = Actor.PartDef(bundleNP, bundle, model.node())
+
+        if self.mergeLODBundles:
+            loadedBundle = self.__commonBundles.get(partName, None)
+            if loadedBundle:
+                # We've already got a bundle for this part; merge it.
+                node.mergeBundles(bundle, loadedBundle)
+                bundle = loadedBundle
+            else:
+                # 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,7 +2034,10 @@ class Actor(DirectObject, NodePath):
         if anim.animControl:
         if anim.animControl:
             return anim.animControl
             return anim.animControl
 
 
-        bundle = self.__partBundleDict[lodName][subpartDef.truePartName].partBundle
+        if self.mergeLODBundles:
+            bundle = self.__commonBundles[subpartDef.truePartName]
+        else:
+            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
         # enough to preload, fetch from disk
         # enough to preload, fetch from disk
@@ -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():