Commits

Anonymous committed aaba3b4

Refactore baking code\nAdd material animation\nUpdate export of channel to typed channel

Comments (0)

Files changed (11)

blenderExporter/osg/osgconf.py

+# -*- python-indent: 4; coding: iso-8859-1; mode: python -*-
 # Copyright (C) 2008 Cedric Pinson, Jeremy Moles
 #
 # This program is free software; you can redistribute it and/or modify

blenderExporter/osg/osgdata.py

 
 def getImageFilesFromStateSet(stateset):
     list = []
+    if DEBUG: debug("stateset %s" % str(stateset))
     if stateset is not None and len(stateset.texture_attributes) > 0:
         for unit, attributes in stateset.texture_attributes.items():
             for a in attributes:
             return o
     return None
 
+def findMaterialForIpo(ipo):
+    index = ipo.name.rfind('-')
+    if index != -1:
+        objname = ipo.name[index+1:]
+        try:
+            obj = bpy.data.materials[objname]
+            log("bake ipo %s to material %s" % (ipo.name, objname))
+            return obj
+        except:
+            return None
+
+    for o in bpy.data.materials:
+        if o.getIpo() == ipo:
+            log("bake ipo %s to material %s" % (ipo.name, o.name))
+            return o
+    return None
+
+def createAnimationGenericObject(osg_object, blender_object, config, UpdateCallback):
+    if config.export_anim is not True:
+        return None
+
+    ipo = blender_object.getIpo()
+    if ipo:
+        anim = None
+        ipo2animation = BlenderIpoOrActionToAnimation(ipo = ipo, config = config)
+        anim = ipo2animation.createAnimationFromIpo(blender_object.getName())
+
+        update_callback = UpdateCallback()
+        update_callback.setName(osg_object.name)
+        osg_object.update_callbacks.append(update_callback)
+        return anim
+    return None
+
+def createAnimationObjectAndSetCallback(osg_node, obj, config):
+    return createAnimationGenericObject(osg_node, obj, config, UpdateTransform)
+
+def createAnimationMaterialAndSetCallback(osg_node, obj, config):
+    return createAnimationGenericObject(osg_node, obj, config, UpdateMaterial)
+
+
 class Export(object):
     def __init__(self, config = None):
         object.__init__(self)
         self.lights = {}
         self.root = None
         self.uniq_objects = {}
+        self.uniq_stateset = {}
 
     def setArmatureInRestMode(self):
         for arm in bpy.data.objects:
         if item is not None:
             self.items.append(item)
 
-    def createAnimationIpo(self, osg_node, obj):
+    def createAnimationObject(self, osg_node, obj):
         if self.config.export_anim is not True:
             return
 
         item = None
         if self.uniq_objects.has_key(obj):
             log(str("use referenced item for " + obj.getName() + " " + obj.getType()))
-            item = ShadowObject(self.uniq_objects[obj])
+            item = self.uniq_objects[obj] #ShadowObject(self.uniq_objects[obj])
         else:
             if obj.getType() == "Armature":
                 item = self.createSkeletonAndAnimations(obj)
-                self.createAnimationIpo(item, obj)
+                anim = createAnimationObjectAndSetCallback(item, obj, self.config)
+                if anim : 
+                    self.animations[anim.name] = anim
+
             elif obj.getType() == "Mesh":
                 # because it blender can insert inverse matrix, we have to recompute the parent child
                 # matrix for our use. Not if an armature we force it to be in rest position to compute
                 item.setName(obj.getName())
                 item.matrix = matrix
                 objectItem = self.createMesh(obj)
-                self.createAnimationIpo(item, obj)
+
+                anim = createAnimationObjectAndSetCallback(item, obj, self.config)
+                if anim : 
+                    self.animations[anim.name] = anim
+
                 item.children.append(objectItem)
             elif obj.getType() == "Lamp":
                 # because it blender can insert inverse matrix, we have to recompute the parent child
                 item.setName(obj.getName())
                 item.matrix = matrix
                 lightItem = self.createLight(obj)
-                self.createAnimationIpo(item, obj)
+                anim = createAnimationObjectAndSetCallback(item, obj, self.config)
+                if anim : 
+                    self.animations[anim.name] = anim
+
                 item.children.append(lightItem)
             elif obj.getType() == "Empty":
                 # because it blender can insert inverse matrix, we have to recompute the parent child
                 item = MatrixTransform()
                 item.setName(obj.getName())
                 item.matrix = matrix
-                self.createAnimationIpo(item, obj)
+                anim = createAnimationObjectAndSetCallback(item, obj, self.config)
+                if anim : 
+                    self.animations[anim.name] = anim
                 self.evaluateGroup(obj, item, rootItem)
             else:
                 log(str("WARNING " + obj.getName() + " " + obj.getType() + " not exported"))
                 log("WARNING can't create animation from %s" % anim)
                 
     def process(self):
-        initReferenceCount()
+        Object.resetWriter()
         self.scene_name = bpy.data.scenes.active.name
         if self.config.validFilename() is False:
             self.config.filename += self.scene_name
                 key = "GL_LIGHT%s" % light_num
                 st.modes[key] = "ON"
                 light_num += 1
-        
+
+        for key in self.uniq_stateset.iterkeys():
+            if self.uniq_stateset[key] is not None: # register images to unpack them at the end
+                images = getImageFilesFromStateSet(self.uniq_stateset[key])
+                for i in images:
+                    self.images.add(i)
 
     def write(self):
         if len(self.items) == 0:
 
         geometries = []
         if exportInfluence is False or hasVertexGroup is False:
-            converter = BlenderObjectToGeometry(object = mesh)
+            converter = BlenderObjectToGeometry(object = mesh, config = self.config, uniq_stateset = self.uniq_stateset)
             geometries = converter.convert()
         else:
-            converter = BlenderObjectToRigGeometry(object = mesh)
+            converter = BlenderObjectToRigGeometry(object = mesh, config = self.config, uniq_stateset = self.uniq_stateset)
             geometries = converter.convert()
         if len(geometries) > 0:
             for geom in geometries:
-                if geom.stateset is not None: # register images to unpack them at the end
-                    images = getImageFilesFromStateSet(geom.stateset)
-                    for i in images:
-                        self.images.add(i)
                 geode.drawables.append(geom)
+            for name in converter.material_animations.iterkeys():
+                self.animations[name] = converter.material_animations[name]
         return geode
 
     def createLight(self, obj):
 class BlenderObjectToGeometry(object):
     def __init__(self, *args, **kwargs):
         self.object = kwargs["object"]
+        self.config = kwargs.get("config", osgconf.Config())
+        self.uniq_stateset = kwargs.get("uniq_stateset", {})
         self.geom_type = Geometry
         self.mesh = self.object.getData(False, True)
+        self.material_animations = {}
 
     def createTexture2D(self, mtex):
         image_object = mtex.tex.getImage()
         texture.source_image = image_object
         return texture
 
-    def createStateSet(self, index_material, mesh, geom):
-        s = StateSet()
+    def adjustUVLayerFromMaterial(self, geom, material):
         uvs = geom.uvs
         if DEBUG: debug("geometry uvs %s" % (str(uvs)))
         geom.uvs = {}
+
+        texture_list = material.getTextures()
+        if DEBUG: debug("texture list %s" % str(texture_list))
+
+        # find a default channel if exist uv
+        default_uv = None
+        default_uv_key = None
+        if (len(uvs)) == 1:
+            default_uv_key = uvs.keys()[0]
+            default_uv = uvs[default_uv_key]
+
+        for i in range(0, len(texture_list)):
+            if texture_list[i] is not None:
+                uv_layer =  texture_list[i].uvlayer
+
+                if len(uv_layer) > 0 and not uvs.has_key(uv_layer):
+                    log("WARNING your material '%s' with texture '%s' use an uv layer '%s' that does not exist on the mesh '%s', use the first uv channel as fallback" % (mat_source.getName(), texture_list[i], uv_layer, geom.name))
+                if len(uv_layer) > 0 and uvs.has_key(uv_layer):
+                    if DEBUG: debug("texture %s use uv layer %s" % (i, uv_layer))
+                    geom.uvs[i] = TexCoordArray()
+                    geom.uvs[i].array = uvs[uv_layer].array
+                    geom.uvs[i].index = i
+                elif default_uv:
+                    if DEBUG: debug("texture %s use default uv layer %s" % (i, default_uv_key))
+                    geom.uvs[i] = TexCoordArray()
+                    geom.uvs[i].index = i
+                    geom.uvs[i].array = default_uv.array
+
+        # adjust uvs channels if no textures assigned
+        if len(geom.uvs.keys()) == 0:
+            if DEBUG: debug("no texture set, adjust uvs channels, in arbitrary order")
+            index = 0
+            for k in uvs.keys():
+                uvs[k].index = index
+                index += 1
+            geom.uvs = uvs
+        return
+
+    def createStateSet(self, index_material, mesh, geom):
+        s = StateSet()
         if len(mesh.materials) > 0:
             mat_source = mesh.materials[index_material]
+            if self.uniq_stateset.has_key(mat_source):
+                #s = ShadowObject(self.uniq_stateset[mat_source])
+                s = self.uniq_stateset[mat_source]
+                return s
+
             if mat_source is not None:
+                self.uniq_stateset[mat_source] = s
                 m = Material()
+                m.setName(mat_source.getName())
                 s.setName(mat_source.getName())
 
+                anim = createAnimationMaterialAndSetCallback(m, mat_source, self.config)
+                if anim :
+                    self.material_animations[anim.name] = anim
+
                 mode = mat_source.getMode()
                 if mode & Blender.Material.Modes['SHADELESS']:
                     s.modes["GL_LIGHTING"] = "OFF"
                 texture_list = mat_source.getTextures()
                 if DEBUG: debug("texture list %s" % str(texture_list))
 
-                # find a default channel if exist uv
-                default_uv = None
-                default_uv_key = None
-                if (len(uvs)) == 1:
-                    default_uv_key = uvs.keys()[0]
-                    default_uv = uvs[default_uv_key]
-                
                 for i in range(0, len(texture_list)):
                     if texture_list[i] is not None:
                         t = self.createTexture2D(texture_list[i])
                         if t is not None:
                             if not s.texture_attributes.has_key(i):
                                 s.texture_attributes[i] = []
-                            uv_layer =  texture_list[i].uvlayer
-                            if len(uv_layer) > 0 and not uvs.has_key(uv_layer):
-                                log("WARNING your material '%s' with texture '%s' use an uv layer '%s' that does not exist on the mesh '%s', use the first uv channel as fallback" % (mat_source.getName(), t.name, uv_layer, geom.name))
-                            if len(uv_layer) > 0 and uvs.has_key(uv_layer):
-                                if DEBUG: debug("texture %s use uv layer %s" % (i, uv_layer))
-                                geom.uvs[i] = TexCoordArray()
-                                geom.uvs[i].array = uvs[uv_layer].array
-                                geom.uvs[i].index = i
-                            elif default_uv:
-                                if DEBUG: debug("texture %s use default uv layer %s" % (i, default_uv_key))
-                                geom.uvs[i] = TexCoordArray()
-                                geom.uvs[i].index = i
-                                geom.uvs[i].array = default_uv.array
-                                
                             s.texture_attributes[i].append(t)
                             try:
                                 if t.source_image.getDepth() > 24: # there is an alpha
                             except:
                                 log("can't read the source image file for texture %s" % t)
                 if DEBUG: debug("state set %s" % str(s))
-
-        # adjust uvs channels if no textures assigned
-        if len(geom.uvs.keys()) == 0:
-            if DEBUG: debug("no texture set, adjust uvs channels, in arbitrary order")
-            index = 0
-            for k in uvs.keys():
-                uvs[k].index = index
-                index += 1
-            geom.uvs = uvs
         return s
 
     def equalVertices(self, vert1, vert2, vertexes, normals, colors, uvs):
         geom.setName(self.object.getName())
         geom.stateset = self.createStateSet(material_index, mesh, geom)
 
+        if len(mesh.materials) > 0 and mesh.materials[material_index] is not None:
+            self.adjustUVLayerFromMaterial(geom, mesh.materials[material_index])
+
         end_title = '-' * len(title)
         log(end_title)
         return geom
         self.ipos = kwargs.get("ipo", None)
         self.action = kwargs.get("action", None)
         self.config = kwargs["config"]
+        self.object = kwargs.get("object", None)
         self.animation = None
 
     def getTypeOfIpo(self, ipo):
         try:
-            ipo.curveConsts['MAT_R']
+            ipo.curveConsts['MA_R']
             return "Material"
         except:
             pass
         self.animation = animation
         return animation
 
-    def convertIpoToAnimation(self, name, ani, ipo):
+    def convertIpoToAnimation(self, name, anim, ipo):
         if not ipo:
             ipo = []
         # Or we could call the other "type" here.
         channels = self.exportKeyframeSplitRotationTranslationScale(ipo, self.config.anim_fps)
         for i in channels:
             i.target = name
-            ani.channels.append(i)
+            anim.channels.append(i)
 
     def exportKeyframeSplitRotationTranslationScale(self, ipo, fps):
         SUPPORTED_IPOS = (
             'RotX', 'RotY', 'RotZ',
             'QuatW', 'QuatX', 'QuatY', 'QuatZ',
             'LocX', 'LocY', 'LocZ',
-            'ScaleX', 'ScaleY', 'ScaleZ'
+            'ScaleX', 'ScaleY', 'ScaleZ',
             'R', 'G', 'B', 'Alpha'
             )
 
         duration = 0
 
         for curve in ipo:
+            if DEBUG: debug("ipo %s curve %s with %s keys" % (ipo.getName(), curve.name, len(curve.bezierPoints)))
             if curve.name not in SUPPORTED_IPOS:
+                if DEBUG: debug("ipo %s curve %s not supported" % (ipo.getName(), curve.name))
                 continue
 
-            elif curve.name[ : 3] == "Rot" or curve.name[ : 4] == "Quat":
+            elif curve.name == "RotX" or curve.name == "RotY" or curve.name == "RotZ" or curve.name == "QuatX" or curve.name == "QuatY" or curve.name == "QuatZ" or curve.name == "QuatW":
                 times = channel_times['Rotation']
                 channel_ipos['Rotation'].append(curve)
 
-            elif curve.name[ : 3] == "Loc":
+            elif curve.name == "LocX" or curve.name == "LocY" or curve.name == "LocZ":
                 times = channel_times['Translation']
                 channel_ipos['Translation'].append(curve)
 
-            elif curve.name[ : 5] == "Scale":
+            elif curve.name == "ScaleX" or curve.name == "ScaleY" or curve.name == "ScaleZ":
                 times = channel_times['Scale']
                 channel_ipos['Scale'].append(curve)
 
+            elif curve.name == "R" or curve.name == "G" or curve.name == "B" or curve.name == "Alpha":
+                times = channel_times['Color']
+                channel_ipos['Color'].append(curve)
+
             for p in curve.bezierPoints:
                 times.add(p.pt[0])
 
+        if DEBUG: debug("ipo %s sort time for curves" % (ipo.getName()))
         for key in channel_times.iterkeys():
             time = list(channel_times[key])
             time.sort()
 
             if len(time) > 0:
                 channel_samplers[key] = Channel()
+            if DEBUG: debug("ipo %s time sorted %s %s" % (ipo.getName(), key, len(time)))
 
+
+        if DEBUG: debug("ipo %s fill channels" % (ipo.getName()))
         for key in channel_times.iterkeys():
             if channel_samplers[key] is None:
+                if DEBUG: debug("ipo %s nothing to fill for channel %s" % (ipo.getName(), key))
                 continue
+            if DEBUG: debug("ipo %s fill channel %s" % (ipo.getName(), key))
 
+            #if DEBUG: debug("ipo %s process %s " % (ipo.getName(), key))
             times = channel_times[key]
 
             for time in times:
                 quat  = Quaternion()
                 scale = Vector()
                 rot   = Euler()
+                color   = [1,1,1,1]
                 rtype = None
 
-                            # I know this can be cleaned up...
+                # I know this can be cleaned up...
                 for curve in channel_ipos[key]:
                     val       = curve[time]
+                    if DEBUG: debug("ipo %s process curve %s at %s value is %s" % (ipo.getName(), curve.name, time, val))
                     bezPoints = curve.bezierPoints
 
                     if curve.name == 'LocX':
                     elif curve.name == 'RotZ':
                         rot.z = val * 10
                         rtype = "Euler"
+                    elif curve.name == 'R':
+                        color[0] = val
+                    elif curve.name == 'G':
+                        color[1] = val
+                    elif curve.name == 'B':
+                        color[2] = val
+                    elif curve.name == 'Alpha':
+                        color[3] = val
                     else:
                         continue
 
                 if key == 'Scale':
+#                    if DEBUG: debug("ipo %s process %s %s %s %s %s" % (ipo.getName(), key, realtime, scale[0], scale[1], scale[2]))
                     channel_samplers[key].keys.append((realtime, scale[0], scale[1], scale[2]))
-                    channel_samplers[key].type = "Vec3"
+                    channel_samplers[key].type = "Vec3LinearChannel"
                     channel_samplers[key].setName("scale")
 
                 elif key == 'Rotation':
                     if rtype == "Quat":
                         quat.normalize()
                         channel_samplers[key].keys.append((realtime, quat.x, quat.y, quat.z, quat.w))
-                        channel_samplers[key].type = "Quat"
+                        channel_samplers[key].type = "QuatSphericalLinearChannel"
                         channel_samplers[key].setName("quaternion")
 
                     elif rtype == "Euler":
                         channel_samplers[key].keys.append((realtime, math.radians(rot.x)  , math.radians(rot.y), math.radians(rot.z) ))
-                        channel_samplers[key].type = "Vec3"
+                        channel_samplers[key].type = "Vec3LinearChannel"
                         channel_samplers[key].setName("euler")
 
                 elif key == 'Translation':
                     channel_samplers[key].keys.append((realtime, trans[0], trans[1], trans[2]))
-                    channel_samplers[key].type = "Vec3"
+                    channel_samplers[key].type = "Vec3LinearChannel"
                     channel_samplers[key].setName("position")
 
+                elif key == 'Color':
+                    channel_samplers[key].keys.append((realtime, color[0], color[1], color[2], color[3]))
+                    channel_samplers[key].type = "Vec4LinearChannel"
+                    channel_samplers[key].setName("diffuse")
+
             channels.append(channel_samplers[key])
             #print channel_samplers[key]
         return channels

blenderExporter/osg/osggui.py

+# -*- python-indent: 4; coding: iso-8859-1; mode: python -*-
+# Copyright (C) 2008 Cedric Pinson, Jeremy Moles
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Authors:
+#  Cedric Pinson <cedric.pinson@plopbyte.net>
+#  Jeremy Moles <jeremy@emperorlinux.com>
+
+
 import os
 import Blender
 import osg
 import osgconf
 
 HELPINFO = (
-	"Tip 1. Make sure that....",
-	"Tip 2. Make sure that....",
-	"Tip 3. Make sure that....",
-	"Tip 4. Make sure that....",
-	"Tip 5. Make sure that....",
-	"Tip 6. Make sure that...."
+    "Tip 1. Make sure that....",
+    "Tip 2. Make sure that....",
+    "Tip 3. Make sure that....",
+    "Tip 4. Make sure that....",
+    "Tip 5. Make sure that....",
+    "Tip 6. Make sure that...."
 )
 
-class AnimTKGUIObject(object):
-	def __init__(self, val, eventID):
-		object.__init__(self);
+class OSGGUIObject(object):
+    def __init__(self, val, eventID):
+        object.__init__(self);
 
-		self.eventID  = eventID
-		self.val      = val
-		self.gui      = None
-		self.callback = lambda *a, **k: None
+        self.eventID  = eventID
+        self.val      = val
+        self.gui      = None
+        self.callback = lambda *a, **k: None
 
-	def matchAndUpdate(self, eventID):
-		if self.eventID == eventID:
-			try:
-				self.val = self.gui.val
+    def matchAndUpdate(self, eventID):
+        if self.eventID == eventID:
+            try:
+                self.val = self.gui.val
 
-			except:
-				pass
-	
-			self.callback()
+            except:
+                pass
 
-class AnimTKGUI(object):
-	def __init__(self, callback=lambda *a, **k: None):
-		object.__init__(self)
+            self.callback()
 
-		self.lastCoords  = [0] * 4
-		self.nextEventID = 0
-		self.callback    = callback
-		self.objects     = {}
+class OSGGUI(object):
+    def __init__(self, callback=lambda *a, **k: None):
+        object.__init__(self)
 
-	def getNextCoords(self, width, height, stayHoriz=False):
-		coords = self.lastCoords
+        self.lastCoords  = [0] * 4
+        self.nextEventID = 0
+        self.callback    = callback
+        self.objects     = {}
 
-		# If the user wants to stay on the same row.
-		if stayHoriz:
-			coords[0] += coords[2] + 2
+    def getNextCoords(self, width, height, stayHoriz=False):
+        coords = self.lastCoords
 
-		# Otherwise, increment Y so that we're on a new row.
-		else:
-			coords[0] = 2
-			coords[1] += coords[3] + 2
+	# If the user wants to stay on the same row.
+        if stayHoriz:
+            coords[0] += coords[2] + 2
 
-		# Set the new width/height, and copy it back into the member.
-		coords[2 : 1] = [width + 2, height + 2]
+	# Otherwise, increment Y so that we're on a new row.
+	else:
+            coords[0] = 2
+            coords[1] += coords[3] + 2
 
-		self.lastCoords = coords
+	# Set the new width/height, and copy it back into the member.
+        coords[2 : 1] = [width + 2, height + 2]
+        self.lastCoords = coords
+        return coords
 
-		return coords
+    def addGUIObject(self, val, initial=None):
+        if not self.objects.has_key(val):
+            self.objects[val] = OSGGUIObject(initial, self.nextEventID)
+            self.nextEventID += 1
+        return self.objects[val]
 
-	def addGUIObject(self, val, initial=None):
-		if not self.objects.has_key(val):
-			self.objects[val] = AnimTKGUIObject(initial, self.nextEventID)
-			
-			self.nextEventID += 1
+    def addString(self, val, label, hint="", initial="", stayHoriz=False, w=300, h=24):
+        c = self.getNextCoords(w, h, stayHoriz)
+        o = self.addGUIObject(val, initial)
 
-		return self.objects[val]
+        o.gui = Blender.Draw.String(
+            "%s: " % label,
+            o.eventID,
+            c[0], c[1], c[2], c[3],
+            o.val,
+            255,
+            hint
+            )
 
-	def addString(self, val, label, hint="", initial="", stayHoriz=False, w=300, h=24):
-		c = self.getNextCoords(w, h, stayHoriz)
-		o = self.addGUIObject(val, initial)
+    def addToggle(self, val, label, hint="", initial=False, stayHoriz=False, w=200, h=24):
+        c = self.getNextCoords(w, h, stayHoriz)
+        o = self.addGUIObject(val, initial)
 
-		o.gui = Blender.Draw.String(
-			"%s: " % label,
-			o.eventID,
-			c[0], c[1], c[2], c[3],
-			o.val,
-			255,
-			hint
-		)
+        o.gui = Blender.Draw.Toggle(
+            label,
+            o.eventID,
+            c[0], c[1], c[2], c[3],
+            o.val,
+            hint
+            )
 
-	def addToggle(self, val, label, hint="", initial=False, stayHoriz=False, w=200, h=24):
-		c = self.getNextCoords(w, h, stayHoriz)
-		o = self.addGUIObject(val, initial)
+    def addNumber(self, val, label, minv, maxv, hint="", initial=0, stayHoriz=False, w=300, h=24):
+        c = self.getNextCoords(w, h, stayHoriz)
+        o = self.addGUIObject(val, initial)
 
-		o.gui = Blender.Draw.Toggle(
-			label,
-			o.eventID,
-			c[0], c[1], c[2], c[3],
-			o.val,
-			hint
-		)
+        if initial < minv:
+            initial = minv
 
-	def addNumber(self, val, label, minv, maxv, hint="", initial=0, stayHoriz=False, w=300, h=24):
-		c = self.getNextCoords(w, h, stayHoriz)
-		o = self.addGUIObject(val, initial)
+        o.gui = Blender.Draw.Number(
+            "%s: " % label,
+            o.eventID,
+            c[0], c[1], c[2], c[3],
+            o.val,
+            minv,
+            maxv,
+            hint
+            )
 
-		if initial < minv:
-			initial = minv
+    def addPushButton(self, val, label, hint="", stayHoriz=False, w=175, h=24):
+        c = self.getNextCoords(w, h, stayHoriz)
+        o = self.addGUIObject(val, None)
 
-		o.gui = Blender.Draw.Number(
-			"%s: " % label,
-			o.eventID,
-			c[0], c[1], c[2], c[3],
-			o.val,
-			minv,
-			maxv,
-			hint
-		)
+        o.gui = Blender.Draw.PushButton(
+            label,
+            o.eventID,
+            c[0], c[1], c[2], c[3],
+            hint
+            )
 
-	def addPushButton(self, val, label, hint="", stayHoriz=False, w=175, h=24):
-		c = self.getNextCoords(w, h, stayHoriz)
-		o = self.addGUIObject(val, None)
+    def InterfaceDraw(self):
+        Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
+        Blender.BGL.glEnable(Blender.BGL.GL_BLEND)
+        Blender.BGL.glBlendFunc(
+            Blender.BGL.GL_SRC_ALPHA,
+            Blender.BGL.GL_ONE_MINUS_SRC_ALPHA
+            )
 
-		o.gui = Blender.Draw.PushButton(
-			label,
-			o.eventID,
-			c[0], c[1], c[2], c[3],
-			hint
-		)
+        self.lastCoords = [0] * 4
 
-	def InterfaceDraw(self):
-		Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
-		Blender.BGL.glEnable(Blender.BGL.GL_BLEND)
-		Blender.BGL.glBlendFunc(
-			Blender.BGL.GL_SRC_ALPHA,
-			Blender.BGL.GL_ONE_MINUS_SRC_ALPHA
-		)
+        self.addPushButton("help", "Help", w=96)
+        self.addPushButton("cancel", "Cancel", w=98, stayHoriz=True)
+        self.addPushButton("write", "Write", w=98, stayHoriz=True)
+        self.addString("AUTHOR", "Author's Name")
+        #self.addToggle("LOG", "Create Logfile")
+        self.addToggle("SELECTED", "Only Exported Selected")
+        self.addToggle("VIEWERFILE", "...", w=150)
+        self.addToggle("RELATIVE", "Relative", w=46, stayHoriz=True)
+        self.addNumber("INDENT", "Indentation Size", 1, 8, initial=3)
+        self.addNumber("FLOATPRE", "Float Precsion", 1, 8, initial=4)
+        self.addNumber("ANIMFPS", "Animation FPS", 1, 60, initial=25)
 
-		# Reset out coordiate "counter."
-		self.lastCoords = [0] * 4
+        # Set our callbacks...
+        self.objects["help"].callback   = lambda: self.RegisterHelp()
+        self.objects["cancel"].callback = lambda: Blender.Draw.Exit()
+        self.objects["write"].callback  = lambda: self.Write()
 
-		self.addPushButton("help", "Help", w=96)
-		self.addPushButton("cancel", "Cancel", w=98, stayHoriz=True)
-		self.addPushButton("write", "Write", w=98, stayHoriz=True)
-		self.addString("AUTHOR", "Author's Name")
-#		self.addToggle("LOG", "Create Logfile")
-		self.addToggle("SELECTED", "Only Exported Selected")
-		self.addToggle("VIEWERFILE", "...", w=150)
-		self.addToggle("RELATIVE", "Relative", w=46, stayHoriz=True)
-		self.addNumber("INDENT", "Indentation Size", 1, 8, initial=3)
-		self.addNumber("FLOATPRE", "Float Precsion", 1, 8, initial=4)
-		self.addNumber("ANIMFPS", "Animation FPS", 1, 60, initial=25)
+        # It does not work for me because Blender.Get("scriptsdir") returns
+        # /usr/share/blender/scripts, so first try in user script dir, and if not found
+        # try in scriptdir
+        try:
+            img = Blender.Image.Load(
+                os.path.join(Blender.Get("uscriptsdir"), "osg", "logo.png")
+                )
+            Blender.Draw.Image(img, 210, 54)
+        except:
+            pass
 
-		# Set our callbacks...
-		self.objects["help"].callback   = lambda: self.RegisterHelp()
-		self.objects["cancel"].callback = lambda: Blender.Draw.Exit()
-		self.objects["write"].callback  = lambda: self.Write()
+        Blender.BGL.glDisable(Blender.BGL.GL_BLEND)
 
-		# It does not work for me because Blender.Get("scriptsdir") returns
-		# /usr/share/blender/scripts, so first try in user script dir, and if not found
-		# try in scriptdir
-		try:
-			img = Blender.Image.Load(
-				os.path.join(Blender.Get("uscriptsdir"), "animtk", "logo.png")
-			)
-	
-                        Blender.Draw.Image(img, 210, 54)
+    def HelpInfoDraw(self):
+        Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
 
-		except:
-                        pass
+        self.lastCoords = [0] * 4
 
-		Blender.BGL.glDisable(Blender.BGL.GL_BLEND)
+        self.addPushButton("helpback", "Return To Exporter")
 
-	def HelpInfoDraw(self):
-		Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
+        for i, hi in enumerate(HELPINFO[::-1]):
+            Blender.Draw.Label(hi, 5, 30 + (i * 22), 500, 20)
 
-		self.lastCoords = [0] * 4
+        self.objects["helpback"].callback = lambda: self.Register()
 
-		self.addPushButton("helpback", "Return To Exporter")
+    def InterfaceEvent(self, event, value):
+        if event == Blender.Draw.ESCKEY:
+            Blender.Draw.Exit()
 
-		for i, hi in enumerate(HELPINFO[::-1]):
-			Blender.Draw.Label(hi, 5, 30 + (i * 22), 500, 20)
+    def InterfaceButton(self, event):
+        for k, v in self.objects.iteritems():
+            v.matchAndUpdate(event)
 
-		self.objects["helpback"].callback = lambda: self.Register()
+    def Register(self):
+        Blender.Draw.Register(
+            self.InterfaceDraw,
+            self.InterfaceEvent,
+            self.InterfaceButton
+        )
 
-	def InterfaceEvent(self, event, value):
-		if event == Blender.Draw.ESCKEY:
-			Blender.Draw.Exit()
+    def RegisterHelp(self):
+        Blender.Draw.Register(
+            self.HelpInfoDraw,
+            self.InterfaceEvent,
+            self.InterfaceButton
+        )
 
-	def InterfaceButton(self, event):
-		for k, v in self.objects.iteritems():
-			v.matchAndUpdate(event)
+    def Write(self):
+        def CallCallback(path):
+                if self.objects["SELECTED"].val:
+                        self.objects["SELECTED"].val = "SELECTED_ONLY_WITH_CHILDREN"
+                config = osg.parseArgs(["""--osg=
+                        AUTHOR     = %s;
+                        LOG        = %s;
+                        SELECTED   = %s;
+                        INDENT  = %s;
+                        FLOATPRE   = %g;
+                        ANIMFPS    = %s;
+                        FILENAME   = %s;
+                """ % (
+                        self.objects["AUTHOR"].val,
+                        True, #self.objects["LOG"].val,
+                        self.objects["SELECTED"].val,
+                        self.objects["INDENT"].val,
+                        self.objects["FLOATPRE"].val,
+                        self.objects["ANIMFPS"].val,
+                        path
+                )])
 
-	def Register(self):
-		Blender.Draw.Register(
-			self.InterfaceDraw,
-			self.InterfaceEvent,
-			self.InterfaceButton
-		)
-
-	def RegisterHelp(self):
-		Blender.Draw.Register(
-			self.HelpInfoDraw,
-			self.InterfaceEvent,
-			self.InterfaceButton
-		)
-
-	def Write(self):
-		def CallCallback(path):
-			config = osg.parseArgs(["""--osg=
-				AUTHOR     = %s;
-				LOG        = %s;
-				SELECTED   = %s;
-				INDENT  = %s;
-				FLOATPRE   = %g;
-				ANIMFPS    = %s;
-				FILENAME   = %s;
-			""" % (
-				self.objects["AUTHOR"].val,
-				True, #self.objects["LOG"].val,
-				self.objects["SELECTED"].val,
-				self.objects["INDENT"].val,
-				self.objects["FLOATPRE"].val,
-				self.objects["ANIMFPS"].val,
-				path
-			)])
-
-			self.callback(config)
-	
-		Blender.Window.FileSelector(CallCallback, "Export AnimTK", "")
-		Blender.Draw.Exit()
+                self.callback(config)
+        Blender.Window.FileSelector(CallCallback, "Export OpenSceneGraph", "")
+        Blender.Draw.Exit()

blenderExporter/osg/osgobject.py

 STRFLT    = lambda f: "%%.%df" % FLOATPRE % float(f)
 INDENT    = 2
 
-OBJECT_COUNTER = 0
-
-def initReferenceCount():
-    global OBJECT_COUNTER
-    OBJECT_COUNTER = 0
-
 
 def findObject(name, root):
     if root.name == name:
 
     def __repr__(self):
         ret = ""
-        text = self.ascii().replace("\t", "").replace("#", (" " * INDENT)).replace("$", (" " * (INDENT*self.indent_level) ))
+#        text = self.ascii().replace("\t", "").replace("#", (" " * INDENT)).replace("$", (" " * (INDENT*self.indent_level) ))
+        text = Object.writeInstanceOrUseIt(self).replace("\t", "").replace("#", (" " * INDENT)).replace("$", (" " * (INDENT*self.indent_level) ))
         return ret + text
 
     def __str__(self):
         return text
 
 class Object(Writer):
+    instances = {}
+    wrote_elements = {}
+    
     def __init__(self, *args, **kwargs):
         Writer.__init__(self, *args, **kwargs)
         self.dataVariance = "UNKNOWN"
         self.name = "None"
-        global OBJECT_COUNTER
-        self.counter = OBJECT_COUNTER
-        OBJECT_COUNTER += 1
+        self.counter = len(Object.instances)
+        Object.instances[self] = True
+
+    @staticmethod
+    def resetWriter():
+        Object.instances = {}
+        wrote_elements = {}
+
+    @staticmethod
+    def writeInstanceOrUseIt(obj):
+        if Object.wrote_elements.has_key(obj):
+            shadow_object = ShadowObject(obj)
+            return shadow_object.ascii()
+        Object.wrote_elements[obj] = True
+        return obj.ascii()
 
     def generateID(self):
         return "uniqid_" + self.className() + "_" + str(self.counter)
         text += "$}\n"
         return text
 
+class UpdateMaterial(Object):
+    def __init__(self, *args, **kwargs):
+        Object.__init__(self, *args, **kwargs)
+
+    def className(self):
+        return "UpdateMaterial"
+
+    def ascii(self):
+        text = "$osgAnimation::%s {\n" % self.className()
+        text += Object.printContent(self)
+        text += "$}\n"
+        return text
+
 class UpdateBone(Object):
     def __init__(self, *args, **kwargs):
         Object.__init__(self, *args, **kwargs)
 class StateAttribute(Object):
     def __init__(self, *args, **kwargs):
         Object.__init__(self, *args, **kwargs)
+        self.update_callbacks = []
 
     def className(self):
         return "StateAttribute"
 
     def printContent(self):
         text = Object.printContent(self)
+        if len(self.update_callbacks) > 0:
+            text += "$#UpdateCallbacks {\n"
+            for i in self.update_callbacks:
+                i.indent_level = self.indent_level + 2
+                text += str(i)
+            text += "$#}\n"
         return text
 
 class StateTextureAttribute(StateAttribute):
         return "Channel"
 
     def ascii(self):
-        text = "$Channel {\n"
+        text = "$%s {\n" % self.type
         text += self.printContent()
         text += "$}\n"
         return text
     def printContent(self):
         text = "$#name \"%s\"\n" % self.name
         text += "$#target \"%s\"\n" % self.target
-        text += "$#Keyframes \"%s\" %s {\n" % (self.type, len(self.keys))
+        text += "$#Keyframes %s {\n" % (len(self.keys))
         for i in self.keys:
             text += "$##key"
             for a in range(0, len(i)):

blenderExporter/osgExport.py

 #!BPY
+# -*- python-indent: 4; coding: iso-8859-1; mode: python -*-
 # Copyright (C) 2008 Cedric Pinson
 #
 # This program is free software; you can redistribute it and/or modify
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #
 # Authors:
-#  Cedric Pinson <mornifle@plopbyte.net>
+#  Cedric Pinson <cedric.pinson@plopbyte.net>
 #
 
 """
 __url__     = osg.URL
 __bpydoc__  = osg.DOC
 
-def AnimTKExport(config=None):
-	export = osg.osgdata.Export(config)
-
-	print "....................", config.filename
-
-	export.process()
-	export.write()
+def OpenSceneGraphExport(config=None):
+    export = osg.osgdata.Export(config)
+    print "....................", config.filename
+    export.process()
+    export.write()
 
 if __name__ == "__main__":
-	# If the user wants to run in "batch" mode, assume that ParseArgs
-	# will correctly set atkconf data and go.
-        config = osg.parseArgs(sys.argv)
-	
-	if config:
-		AnimTKExport(config)
-		Blender.Quit()
+    # If the user wants to run in "batch" mode, assume that ParseArgs
+    # will correctly set atkconf data and go.
+    config = osg.parseArgs(sys.argv)
+    
+    if config:
+        OpenSceneGraphExport(config)
+        Blender.Quit()
 
 	# Otherwise, let the atkcgui module take over.
-	else:
-		gui = osg.osggui.AnimTKGUI(AnimTKExport)
-		gui.Register()
+    else:
+        gui = osg.osggui.OSGGUI(OpenSceneGraphExport)
+        gui.Register()

data/nathan/character.blend

Binary file modified.

test/test-armature.py.in

 class Exporter(unittest.TestCase):
     # ------------------------------------------------------
     def setUp(self):
-        osg.osgobject.initReferenceCount()
+        osg.osgobject.Object.resetWriter()
 
     def tearDown(self):
         pass
         exporter.write()
 
     def testArmatureSimple(self):
-        initReferenceCount()
+        osg.osgobject.Object.resetWriter()
         sc = bpy.data.scenes["ArmatureSimple"]
         bpy.data.scenes.active = sc
         exporter = Export()
         print v0, " ", v1
         self.assertEquals(True, v0 != v1)
         text = exporter.root.update_callbacks[0].ascii()
-        result = '$osgAnimation::BasicAnimationManager {\n$#UniqueID uniqid_BasicAnimationManager_38\n$#num_animations 1\n  osgAnimation::Animation {\n    UniqueID uniqid_Animation_11\n    name "Action"\n    num_channels 9\n    Channel {\n      name "quaternion"\n      target "Bone.001"\n      Keyframes "Quat" 20 {\n        key 0.00000 0.00000 0.00000 0.00000 1.00000\n        key 0.04000 0.01962 -0.00000 -0.00000 0.99981\n        key 0.08000 0.08011 -0.00000 -0.00000 0.99679\n        key 0.12000 0.18125 -0.00000 -0.00000 0.98344\n        key 0.16000 0.31294 0.00000 0.00000 0.94977\n        key 0.20000 0.45100 0.00000 -0.00000 0.89252\n        key 0.24000 0.56771 -0.00000 0.00000 0.82323\n        key 0.28000 0.64843 0.00000 -0.00000 0.76128\n        key 0.32000 0.69316 0.00000 -0.00000 0.72078\n        key 0.36000 0.70711 -0.00000 0.00000 0.70711\n        key 0.40000 0.70711 -0.00000 0.00000 0.70711\n        key 0.44000 0.70711 -0.00000 0.00000 0.70711\n        key 0.48000 0.70711 -0.00000 0.00000 0.70711\n        key 0.52000 0.70711 -0.00000 0.00000 0.70711\n        key 0.56000 0.70711 -0.00000 0.00000 0.70711\n        key 0.60000 0.70711 -0.00000 0.00000 0.70711\n        key 0.64000 0.70711 -0.00000 0.00000 0.70711\n        key 0.68000 0.70711 -0.00000 0.00000 0.70711\n        key 0.72000 0.70711 -0.00000 0.00000 0.70711\n        key 0.76000 0.70711 -0.00000 0.00000 0.70711\n      }\n    }\n    Channel {\n      name "scale"\n      target "Bone.001"\n      Keyframes "Vec3" 20 {\n        key 0.00000 1.00000 1.00000 0.00000\n        key 0.04000 1.00000 1.00000 0.00000\n        key 0.08000 1.00000 1.00000 0.00000\n        key 0.12000 1.00000 1.00000 0.00000\n        key 0.16000 1.00000 1.00000 0.00000\n        key 0.20000 1.00000 1.00000 0.00000\n        key 0.24000 1.00000 1.00000 0.00000\n        key 0.28000 1.00000 1.00000 0.00000\n        key 0.32000 1.00000 1.00000 0.00000\n        key 0.36000 1.00000 1.00000 0.00000\n        key 0.40000 1.00000 1.00000 0.00000\n        key 0.44000 1.00000 1.00000 0.00000\n        key 0.48000 1.00000 1.00000 0.00000\n        key 0.52000 1.00000 1.00000 0.00000\n        key 0.56000 1.00000 1.00000 0.00000\n        key 0.60000 1.00000 1.00000 0.00000\n        key 0.64000 1.00000 1.00000 0.00000\n        key 0.68000 1.00000 1.00000 0.00000\n        key 0.72000 1.00000 1.00000 0.00000\n        key 0.76000 1.00000 1.00000 0.00000\n      }\n    }\n    Channel {\n      name "position"\n      target "Bone.001"\n      Keyframes "Vec3" 20 {\n        key 0.00000 0.00000 0.00000 0.00000\n        key 0.04000 0.00000 0.00000 0.00000\n        key 0.08000 0.00000 0.00000 0.00000\n        key 0.12000 0.00000 0.00000 0.00000\n        key 0.16000 0.00000 0.00000 0.00000\n        key 0.20000 0.00000 0.00000 0.00000\n        key 0.24000 0.00000 0.00000 0.00000\n        key 0.28000 0.00000 0.00000 0.00000\n        key 0.32000 0.00000 0.00000 0.00000\n        key 0.36000 0.00000 0.00000 0.00000\n        key 0.40000 0.00000 0.00000 0.00000\n        key 0.44000 0.00000 0.00000 0.00000\n        key 0.48000 0.00000 0.00000 0.00000\n        key 0.52000 0.00000 0.00000 0.00000\n        key 0.56000 0.00000 0.00000 0.00000\n        key 0.60000 0.00000 0.00000 0.00000\n        key 0.64000 0.00000 0.00000 0.00000\n        key 0.68000 0.00000 0.00000 0.00000\n        key 0.72000 0.00000 0.00000 0.00000\n        key 0.76000 0.00000 0.00000 0.00000\n      }\n    }\n    Channel {\n      name "quaternion"\n      target "Bone.002"\n      Keyframes "Quat" 20 {\n        key 0.00000 0.00000 0.00000 0.00000 1.00000\n        key 0.04000 0.00000 0.00000 0.00000 1.00000\n        key 0.08000 -0.00000 0.00000 -0.00000 1.00000\n        key 0.12000 0.00000 0.00000 0.00000 1.00000\n        key 0.16000 -0.00000 0.00000 0.00000 1.00000\n        key 0.20000 0.00000 0.00000 0.00000 1.00000\n        key 0.24000 0.00000 0.00000 0.00000 1.00000\n        key 0.28000 0.00000 -0.00000 -0.00000 1.00000\n        key 0.32000 0.00000 0.00000 -0.00000 1.00000\n        key 0.36000 -0.00000 0.00000 -0.00000 1.00000\n        key 0.40000 0.01579 0.00000 -0.00000 0.99988\n        key 0.44000 0.06441 0.00000 -0.00000 0.99792\n        key 0.48000 0.14647 0.00000 -0.00000 0.98922\n        key 0.52000 0.25720 0.00000 -0.00000 0.96636\n        key 0.56000 0.38238 0.00000 -0.00000 0.92400\n        key 0.60000 0.50096 0.00000 -0.00000 0.86547\n        key 0.64000 0.59562 0.00000 -0.00000 0.80327\n        key 0.68000 0.65997 0.00000 -0.00000 0.75129\n        key 0.72000 0.69583 0.00000 0.00000 0.71821\n        key 0.76000 0.70711 0.00000 0.00000 0.70711\n      }\n    }\n    Channel {\n      name "scale"\n      target "Bone.002"\n      Keyframes "Vec3" 20 {\n        key 0.00000 1.00000 1.00000 0.00000\n        key 0.04000 1.00000 1.00000 0.00000\n        key 0.08000 1.00000 1.00000 0.00000\n        key 0.12000 1.00000 1.00000 0.00000\n        key 0.16000 1.00000 1.00000 0.00000\n        key 0.20000 1.00000 1.00000 0.00000\n        key 0.24000 1.00000 1.00000 0.00000\n        key 0.28000 1.00000 1.00000 0.00000\n        key 0.32000 1.00000 1.00000 0.00000\n        key 0.36000 1.00000 1.00000 0.00000\n        key 0.40000 1.00000 1.00000 0.00000\n        key 0.44000 1.00000 1.00000 0.00000\n        key 0.48000 1.00000 1.00000 0.00000\n        key 0.52000 1.00000 1.00000 0.00000\n        key 0.56000 1.00000 1.00000 0.00000\n        key 0.60000 1.00000 1.00000 0.00000\n        key 0.64000 1.00000 1.00000 0.00000\n        key 0.68000 1.00000 1.00000 0.00000\n        key 0.72000 1.00000 1.00000 0.00000\n        key 0.76000 1.00000 1.00000 0.00000\n      }\n    }\n    Channel {\n      name "position"\n      target "Bone.002"\n      Keyframes "Vec3" 20 {\n        key 0.00000 0.00000 0.00000 -0.00000\n        key 0.04000 0.00000 0.00000 -0.00000\n        key 0.08000 -0.00000 -0.00000 0.00000\n        key 0.12000 0.00000 0.00000 -0.00000\n        key 0.16000 0.00000 0.00000 -0.00000\n        key 0.20000 -0.00000 0.00000 0.00000\n        key 0.24000 -0.00000 0.00000 0.00000\n        key 0.28000 0.00000 0.00000 -0.00000\n        key 0.32000 0.00000 0.00000 -0.00000\n        key 0.36000 0.00000 0.00000 -0.00000\n        key 0.40000 0.00000 0.00000 -0.00000\n        key 0.44000 0.00000 0.00000 -0.00000\n        key 0.48000 0.00000 0.00000 -0.00000\n        key 0.52000 0.00000 0.00000 -0.00000\n        key 0.56000 0.00000 0.00000 -0.00000\n        key 0.60000 0.00000 0.00000 -0.00000\n        key 0.64000 0.00000 0.00000 -0.00000\n        key 0.68000 0.00000 0.00000 -0.00000\n        key 0.72000 0.00000 0.00000 -0.00000\n        key 0.76000 0.00000 0.00000 -0.00000\n      }\n    }\n    Channel {\n      name "quaternion"\n      target "Bone"\n      Keyframes "Quat" 20 {\n        key 0.00000 0.00000 0.00000 0.00000 1.00000\n        key 0.04000 0.00000 0.00000 0.00000 1.00000\n        key 0.08000 0.00000 0.00000 0.00000 1.00000\n        key 0.12000 0.00000 0.00000 0.00000 1.00000\n        key 0.16000 0.00000 0.00000 0.00000 1.00000\n        key 0.20000 0.00000 0.00000 0.00000 1.00000\n        key 0.24000 0.00000 0.00000 0.00000 1.00000\n        key 0.28000 0.00000 0.00000 0.00000 1.00000\n        key 0.32000 0.00000 0.00000 0.00000 1.00000\n        key 0.36000 0.00000 0.00000 0.00000 1.00000\n        key 0.40000 0.00000 0.00000 0.00000 1.00000\n        key 0.44000 0.00000 0.00000 0.00000 1.00000\n        key 0.48000 0.00000 0.00000 0.00000 1.00000\n        key 0.52000 0.00000 0.00000 0.00000 1.00000\n        key 0.56000 0.00000 0.00000 0.00000 1.00000\n        key 0.60000 0.00000 0.00000 0.00000 1.00000\n        key 0.64000 0.00000 0.00000 0.00000 1.00000\n        key 0.68000 0.00000 0.00000 0.00000 1.00000\n        key 0.72000 0.00000 0.00000 0.00000 1.00000\n        key 0.76000 0.00000 0.00000 0.00000 1.00000\n      }\n    }\n    Channel {\n      name "scale"\n      target "Bone"\n      Keyframes "Vec3" 20 {\n        key 0.00000 1.00000 1.00000 0.00000\n        key 0.04000 1.00000 1.00000 0.00000\n        key 0.08000 1.00000 1.00000 0.00000\n        key 0.12000 1.00000 1.00000 0.00000\n        key 0.16000 1.00000 1.00000 0.00000\n        key 0.20000 1.00000 1.00000 0.00000\n        key 0.24000 1.00000 1.00000 0.00000\n        key 0.28000 1.00000 1.00000 0.00000\n        key 0.32000 1.00000 1.00000 0.00000\n        key 0.36000 1.00000 1.00000 0.00000\n        key 0.40000 1.00000 1.00000 0.00000\n        key 0.44000 1.00000 1.00000 0.00000\n        key 0.48000 1.00000 1.00000 0.00000\n        key 0.52000 1.00000 1.00000 0.00000\n        key 0.56000 1.00000 1.00000 0.00000\n        key 0.60000 1.00000 1.00000 0.00000\n        key 0.64000 1.00000 1.00000 0.00000\n        key 0.68000 1.00000 1.00000 0.00000\n        key 0.72000 1.00000 1.00000 0.00000\n        key 0.76000 1.00000 1.00000 0.00000\n      }\n    }\n    Channel {\n      name "position"\n      target "Bone"\n      Keyframes "Vec3" 20 {\n        key 0.00000 -0.00000 0.00000 0.00000\n        key 0.04000 -0.00000 0.00000 0.00000\n        key 0.08000 -0.00000 0.00000 0.00000\n        key 0.12000 -0.00000 0.00000 0.00000\n        key 0.16000 -0.00000 0.00000 0.00000\n        key 0.20000 -0.00000 0.00000 0.00000\n        key 0.24000 -0.00000 0.00000 0.00000\n        key 0.28000 -0.00000 0.00000 0.00000\n        key 0.32000 -0.00000 0.00000 0.00000\n        key 0.36000 -0.00000 0.00000 0.00000\n        key 0.40000 -0.00000 0.00000 0.00000\n        key 0.44000 -0.00000 0.00000 0.00000\n        key 0.48000 -0.00000 0.00000 0.00000\n        key 0.52000 -0.00000 0.00000 0.00000\n        key 0.56000 -0.00000 0.00000 0.00000\n        key 0.60000 -0.00000 0.00000 0.00000\n        key 0.64000 -0.00000 0.00000 0.00000\n        key 0.68000 -0.00000 0.00000 0.00000\n        key 0.72000 -0.00000 0.00000 0.00000\n        key 0.76000 -0.00000 0.00000 0.00000\n      }\n    }\n  }\n$}\n'
+        result = '$osgAnimation::BasicAnimationManager {\n$#UniqueID uniqid_BasicAnimationManager_38\n$#num_animations 1\n  osgAnimation::Animation {\n    UniqueID uniqid_Animation_11\n    name "Action"\n    num_channels 9\n    QuatSphericalLinearChannel {\n      name "quaternion"\n      target "Bone.001"\n      Keyframes 20 {\n        key 0.00000 0.00000 0.00000 0.00000 1.00000\n        key 0.04000 0.01962 -0.00000 -0.00000 0.99981\n        key 0.08000 0.08011 -0.00000 -0.00000 0.99679\n        key 0.12000 0.18125 -0.00000 -0.00000 0.98344\n        key 0.16000 0.31294 0.00000 0.00000 0.94977\n        key 0.20000 0.45100 0.00000 -0.00000 0.89252\n        key 0.24000 0.56771 -0.00000 0.00000 0.82323\n        key 0.28000 0.64843 0.00000 -0.00000 0.76128\n        key 0.32000 0.69316 0.00000 -0.00000 0.72078\n        key 0.36000 0.70711 -0.00000 0.00000 0.70711\n        key 0.40000 0.70711 -0.00000 0.00000 0.70711\n        key 0.44000 0.70711 -0.00000 0.00000 0.70711\n        key 0.48000 0.70711 -0.00000 0.00000 0.70711\n        key 0.52000 0.70711 -0.00000 0.00000 0.70711\n        key 0.56000 0.70711 -0.00000 0.00000 0.70711\n        key 0.60000 0.70711 -0.00000 0.00000 0.70711\n        key 0.64000 0.70711 -0.00000 0.00000 0.70711\n        key 0.68000 0.70711 -0.00000 0.00000 0.70711\n        key 0.72000 0.70711 -0.00000 0.00000 0.70711\n        key 0.76000 0.70711 -0.00000 0.00000 0.70711\n      }\n    }\n    Vec3LinearChannel {\n      name "scale"\n      target "Bone.001"\n      Keyframes 20 {\n        key 0.00000 1.00000 1.00000 1.00000\n        key 0.04000 1.00000 1.00000 1.00000\n        key 0.08000 1.00000 1.00000 1.00000\n        key 0.12000 1.00000 1.00000 1.00000\n        key 0.16000 1.00000 1.00000 1.00000\n        key 0.20000 1.00000 1.00000 1.00000\n        key 0.24000 1.00000 1.00000 1.00000\n        key 0.28000 1.00000 1.00000 1.00000\n        key 0.32000 1.00000 1.00000 1.00000\n        key 0.36000 1.00000 1.00000 1.00000\n        key 0.40000 1.00000 1.00000 1.00000\n        key 0.44000 1.00000 1.00000 1.00000\n        key 0.48000 1.00000 1.00000 1.00000\n        key 0.52000 1.00000 1.00000 1.00000\n        key 0.56000 1.00000 1.00000 1.00000\n        key 0.60000 1.00000 1.00000 1.00000\n        key 0.64000 1.00000 1.00000 1.00000\n        key 0.68000 1.00000 1.00000 1.00000\n        key 0.72000 1.00000 1.00000 1.00000\n        key 0.76000 1.00000 1.00000 1.00000\n      }\n    }\n    Vec3LinearChannel {\n      name "position"\n      target "Bone.001"\n      Keyframes 20 {\n        key 0.00000 0.00000 0.00000 0.00000\n        key 0.04000 0.00000 0.00000 0.00000\n        key 0.08000 0.00000 0.00000 0.00000\n        key 0.12000 0.00000 0.00000 0.00000\n        key 0.16000 0.00000 0.00000 0.00000\n        key 0.20000 0.00000 0.00000 0.00000\n        key 0.24000 0.00000 0.00000 0.00000\n        key 0.28000 0.00000 0.00000 0.00000\n        key 0.32000 0.00000 0.00000 0.00000\n        key 0.36000 0.00000 0.00000 0.00000\n        key 0.40000 0.00000 0.00000 0.00000\n        key 0.44000 0.00000 0.00000 0.00000\n        key 0.48000 0.00000 0.00000 0.00000\n        key 0.52000 0.00000 0.00000 0.00000\n        key 0.56000 0.00000 0.00000 0.00000\n        key 0.60000 0.00000 0.00000 0.00000\n        key 0.64000 0.00000 0.00000 0.00000\n        key 0.68000 0.00000 0.00000 0.00000\n        key 0.72000 0.00000 0.00000 0.00000\n        key 0.76000 0.00000 0.00000 0.00000\n      }\n    }\n    QuatSphericalLinearChannel {\n      name "quaternion"\n      target "Bone.002"\n      Keyframes 20 {\n        key 0.00000 0.00000 0.00000 0.00000 1.00000\n        key 0.04000 0.00000 0.00000 0.00000 1.00000\n        key 0.08000 -0.00000 0.00000 -0.00000 1.00000\n        key 0.12000 0.00000 0.00000 0.00000 1.00000\n        key 0.16000 -0.00000 0.00000 0.00000 1.00000\n        key 0.20000 0.00000 0.00000 0.00000 1.00000\n        key 0.24000 0.00000 0.00000 0.00000 1.00000\n        key 0.28000 0.00000 -0.00000 -0.00000 1.00000\n        key 0.32000 0.00000 0.00000 -0.00000 1.00000\n        key 0.36000 -0.00000 0.00000 -0.00000 1.00000\n        key 0.40000 0.01579 0.00000 -0.00000 0.99988\n        key 0.44000 0.06441 0.00000 -0.00000 0.99792\n        key 0.48000 0.14647 0.00000 -0.00000 0.98922\n        key 0.52000 0.25720 0.00000 -0.00000 0.96636\n        key 0.56000 0.38238 0.00000 -0.00000 0.92400\n        key 0.60000 0.50096 0.00000 -0.00000 0.86547\n        key 0.64000 0.59562 0.00000 -0.00000 0.80327\n        key 0.68000 0.65997 0.00000 -0.00000 0.75129\n        key 0.72000 0.69583 0.00000 0.00000 0.71821\n        key 0.76000 0.70711 0.00000 0.00000 0.70711\n      }\n    }\n    Vec3LinearChannel {\n      name "scale"\n      target "Bone.002"\n      Keyframes 20 {\n        key 0.00000 1.00000 1.00000 1.00000\n        key 0.04000 1.00000 1.00000 1.00000\n        key 0.08000 1.00000 1.00000 1.00000\n        key 0.12000 1.00000 1.00000 1.00000\n        key 0.16000 1.00000 1.00000 1.00000\n        key 0.20000 1.00000 1.00000 1.00000\n        key 0.24000 1.00000 1.00000 1.00000\n        key 0.28000 1.00000 1.00000 1.00000\n        key 0.32000 1.00000 1.00000 1.00000\n        key 0.36000 1.00000 1.00000 1.00000\n        key 0.40000 1.00000 1.00000 1.00000\n        key 0.44000 1.00000 1.00000 1.00000\n        key 0.48000 1.00000 1.00000 1.00000\n        key 0.52000 1.00000 1.00000 1.00000\n        key 0.56000 1.00000 1.00000 1.00000\n        key 0.60000 1.00000 1.00000 1.00000\n        key 0.64000 1.00000 1.00000 1.00000\n        key 0.68000 1.00000 1.00000 1.00000\n        key 0.72000 1.00000 1.00000 1.00000\n        key 0.76000 1.00000 1.00000 1.00000\n      }\n    }\n    Vec3LinearChannel {\n      name "position"\n      target "Bone.002"\n      Keyframes 20 {\n        key 0.00000 0.00000 0.00000 -0.00000\n        key 0.04000 0.00000 0.00000 -0.00000\n        key 0.08000 -0.00000 -0.00000 0.00000\n        key 0.12000 0.00000 0.00000 -0.00000\n        key 0.16000 0.00000 0.00000 -0.00000\n        key 0.20000 -0.00000 0.00000 0.00000\n        key 0.24000 -0.00000 0.00000 0.00000\n        key 0.28000 0.00000 0.00000 -0.00000\n        key 0.32000 0.00000 0.00000 -0.00000\n        key 0.36000 0.00000 0.00000 -0.00000\n        key 0.40000 0.00000 0.00000 -0.00000\n        key 0.44000 0.00000 0.00000 -0.00000\n        key 0.48000 0.00000 0.00000 -0.00000\n        key 0.52000 0.00000 0.00000 -0.00000\n        key 0.56000 0.00000 0.00000 -0.00000\n        key 0.60000 0.00000 0.00000 -0.00000\n        key 0.64000 0.00000 0.00000 -0.00000\n        key 0.68000 0.00000 0.00000 -0.00000\n        key 0.72000 0.00000 0.00000 -0.00000\n        key 0.76000 0.00000 0.00000 -0.00000\n      }\n    }\n    QuatSphericalLinearChannel {\n      name "quaternion"\n      target "Bone"\n      Keyframes 20 {\n        key 0.00000 0.00000 0.00000 0.00000 1.00000\n        key 0.04000 0.00000 0.00000 0.00000 1.00000\n        key 0.08000 0.00000 0.00000 0.00000 1.00000\n        key 0.12000 0.00000 0.00000 0.00000 1.00000\n        key 0.16000 0.00000 0.00000 0.00000 1.00000\n        key 0.20000 0.00000 0.00000 0.00000 1.00000\n        key 0.24000 0.00000 0.00000 0.00000 1.00000\n        key 0.28000 0.00000 0.00000 0.00000 1.00000\n        key 0.32000 0.00000 0.00000 0.00000 1.00000\n        key 0.36000 0.00000 0.00000 0.00000 1.00000\n        key 0.40000 0.00000 0.00000 0.00000 1.00000\n        key 0.44000 0.00000 0.00000 0.00000 1.00000\n        key 0.48000 0.00000 0.00000 0.00000 1.00000\n        key 0.52000 0.00000 0.00000 0.00000 1.00000\n        key 0.56000 0.00000 0.00000 0.00000 1.00000\n        key 0.60000 0.00000 0.00000 0.00000 1.00000\n        key 0.64000 0.00000 0.00000 0.00000 1.00000\n        key 0.68000 0.00000 0.00000 0.00000 1.00000\n        key 0.72000 0.00000 0.00000 0.00000 1.00000\n        key 0.76000 0.00000 0.00000 0.00000 1.00000\n      }\n    }\n    Vec3LinearChannel {\n      name "scale"\n      target "Bone"\n      Keyframes 20 {\n        key 0.00000 1.00000 1.00000 1.00000\n        key 0.04000 1.00000 1.00000 1.00000\n        key 0.08000 1.00000 1.00000 1.00000\n        key 0.12000 1.00000 1.00000 1.00000\n        key 0.16000 1.00000 1.00000 1.00000\n        key 0.20000 1.00000 1.00000 1.00000\n        key 0.24000 1.00000 1.00000 1.00000\n        key 0.28000 1.00000 1.00000 1.00000\n        key 0.32000 1.00000 1.00000 1.00000\n        key 0.36000 1.00000 1.00000 1.00000\n        key 0.40000 1.00000 1.00000 1.00000\n        key 0.44000 1.00000 1.00000 1.00000\n        key 0.48000 1.00000 1.00000 1.00000\n        key 0.52000 1.00000 1.00000 1.00000\n        key 0.56000 1.00000 1.00000 1.00000\n        key 0.60000 1.00000 1.00000 1.00000\n        key 0.64000 1.00000 1.00000 1.00000\n        key 0.68000 1.00000 1.00000 1.00000\n        key 0.72000 1.00000 1.00000 1.00000\n        key 0.76000 1.00000 1.00000 1.00000\n      }\n    }\n    Vec3LinearChannel {\n      name "position"\n      target "Bone"\n      Keyframes 20 {\n        key 0.00000 -0.00000 0.00000 0.00000\n        key 0.04000 -0.00000 0.00000 0.00000\n        key 0.08000 -0.00000 0.00000 0.00000\n        key 0.12000 -0.00000 0.00000 0.00000\n        key 0.16000 -0.00000 0.00000 0.00000\n        key 0.20000 -0.00000 0.00000 0.00000\n        key 0.24000 -0.00000 0.00000 0.00000\n        key 0.28000 -0.00000 0.00000 0.00000\n        key 0.32000 -0.00000 0.00000 0.00000\n        key 0.36000 -0.00000 0.00000 0.00000\n        key 0.40000 -0.00000 0.00000 0.00000\n        key 0.44000 -0.00000 0.00000 0.00000\n        key 0.48000 -0.00000 0.00000 0.00000\n        key 0.52000 -0.00000 0.00000 0.00000\n        key 0.56000 -0.00000 0.00000 0.00000\n        key 0.60000 -0.00000 0.00000 0.00000\n        key 0.64000 -0.00000 0.00000 0.00000\n        key 0.68000 -0.00000 0.00000 0.00000\n        key 0.72000 -0.00000 0.00000 0.00000\n        key 0.76000 -0.00000 0.00000 0.00000\n      }\n    }\n  }\n$}\n'
         self.assertEquals(result, text)
         exporter.write()
 

test/test-baked_ipo.py.in

 class Exporter(unittest.TestCase):
     # ------------------------------------------------------
     def setUp(self):
-        osg.osgobject.initReferenceCount()
+        osg.osgobject.Object.resetWriter()
 
     def tearDown(self):
         pass

test/test-bug_multimaterial.py.in

 class Exporter(unittest.TestCase):
     # ------------------------------------------------------
     def setUp(self):
-        osg.osgobject.initReferenceCount()
+        osg.osgobject.Object.resetWriter()
 
     def tearDown(self):
         pass

test/test-exporter.py.in

 class Exporter(unittest.TestCase):
     # ------------------------------------------------------
     def setUp(self):
-        osg.osgobject.initReferenceCount()
+        osg.osgobject.Object.resetWriter()
 
     def tearDown(self):
         pass

test/test-geometry_and_material.py.in

 class Exporter(unittest.TestCase):
     # ------------------------------------------------------
     def setUp(self):
-        osg.osgobject.initReferenceCount()
+        osg.osgobject.Object.resetWriter()
 
     def tearDown(self):
         pass