Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Thompson <quornian@googlemail.com>2008-07-19 03:35:34 +0400
committerIan Thompson <quornian@googlemail.com>2008-07-19 03:35:34 +0400
commitf042a468fdd0f06ca41c022c9ed6ac59d35ff143 (patch)
tree634b6082233a7d8eaa520ddd760e72b1fd48131d /release
parent123407e0b4ec616aef40216ab76e559e0dee5711 (diff)
Merged 15170:15635 from trunk (no conflicts or even merges)
Diffstat (limited to 'release')
-rw-r--r--release/datafiles/blenderbuttonsbin69070 -> 69599 bytes
-rw-r--r--release/scripts/DirectX8Exporter.py34
-rw-r--r--release/scripts/animation_bake_constraints.py792
-rw-r--r--release/scripts/bpymodules/BPyArmature.py75
-rw-r--r--release/scripts/c3d_import.py1243
-rw-r--r--release/scripts/ms3d_import.py132
-rw-r--r--release/scripts/vrml97_export.py80
-rw-r--r--release/windows/installer/00.sconsblender.nsi25
8 files changed, 2301 insertions, 80 deletions
diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons
index ebd0ec82ebd..a4834091692 100644
--- a/release/datafiles/blenderbuttons
+++ b/release/datafiles/blenderbuttons
Binary files differ
diff --git a/release/scripts/DirectX8Exporter.py b/release/scripts/DirectX8Exporter.py
index 2ec42057039..01212545f77 100644
--- a/release/scripts/DirectX8Exporter.py
+++ b/release/scripts/DirectX8Exporter.py
@@ -6,9 +6,9 @@
# Group: 'Export'
# Tooltip: 'Export to DirectX text file format format for XNA Animation Component Library.'
"""
-__author__ = "minahito (original:Arben (Ben) Omari)"
-__url__ = ("blender", "blenderartists.org", "Adjuster's site http://sunday-lab.blogspot.com/, Author's site http://www.omariben.too.it")
-__version__ = "3.0"
+__author__ = "vertex color exporting feature is added by mnemoto (original:minahito (original:Arben (Ben) Omari))"
+__url__ = ("blender", "elysiun", "Adjuster's site http://sunday-lab.blogspot.com/, Author's site http://www.omariben.too.it","Adjuster's site http://ex.homeunix.net/")
+__version__ = "3.1"
__bpydoc__ = """\
This script exports a Blender mesh with armature to DirectX 8's text file
@@ -444,6 +444,7 @@ class xExport:
self.writeMeshMaterialList(obj, mesh, tex)
self.writeMeshNormals(obj, mesh)
self.writeMeshTextureCoords(obj, mesh)
+ self.writeMeshVertexColors(obj, mesh)
self.file.write(" } // End of the Mesh %s \n" % (obj.name))
@@ -464,6 +465,7 @@ class xExport:
self.writeMeshMaterialList(obj, mesh, tex)
self.writeMeshNormals(obj, mesh)
self.writeMeshTextureCoords(obj, mesh)
+ self.writeMeshVertexColors(obj, mesh)
self.file.write(" }\n")
self.file.write("}\n")
ind = objs.index(obj)
@@ -1047,6 +1049,32 @@ template SkinWeights {\n\
self.file.write(",\n")
self.file.write("} //End of MeshTextureCoords\n")
+
+ #***********************************************
+ #MESH VORTEX COLORS
+ #***********************************************
+ def writeMeshVertexColors(self, name, mesh):
+ if mesh.hasVertexColours():
+ self.file.write("MeshVertexColors {\n")
+ #VERTICES NUMBER
+ numvert = reduce( lambda i,f: len(f)+i, mesh.faces, 0)
+ self.file.write("%d;\n" % (numvert))
+ #VERTEX COLORS
+
+ vcounter =0
+ for f in mesh.faces:
+ col = f.col
+ for i,c in enumerate(col):
+ # Note vcol alpha has no meaning
+ self.file.write("%d;%f;%f;%f;%f;" % (vcounter,c.r/255.0, c.g/255.0, c.b/255.0, 1.0)) # c.a/255.0))
+ vcounter+=1
+ if vcounter == numvert :
+ self.file.write(";\n")
+ else :
+ self.file.write(",\n")
+
+ self.file.write("} //End of MeshVertexColors\n")
+
#***********************************************#***********************************************#***********************************************
#***********************************************
#FRAMES
diff --git a/release/scripts/animation_bake_constraints.py b/release/scripts/animation_bake_constraints.py
new file mode 100644
index 00000000000..8a416c3c488
--- /dev/null
+++ b/release/scripts/animation_bake_constraints.py
@@ -0,0 +1,792 @@
+#!BPY
+
+"""
+Name: 'Bake Constraints'
+Blender: 246
+Group: 'Animation'
+Tooltip: 'Bake a Constrained object/rig to IPOs'
+Fillename: 'Bake_Constraint.py'
+"""
+
+__author__ = "Roger Wickes (rogerwickes(at)yahoo.com)"
+__script__ = "Animation Bake Constraints"
+__version__ = "0.7"
+__url__ = ["Communicate problems and errors, http://www.blenderartists.com/forum/private.php?do=newpm to PapaSmurf"]
+__email__= ["Roger Wickes, rogerwickes@yahoo.com", "scripts"]
+__bpydoc__ = """\
+
+bake_constraints
+
+This script bakes the real-world LocRot of an object (the net effect of any constraints -
+(Copy, Limit, Track, Follow, - that affect Location, Rotation)
+(usually one constrained to match another's location and/or Tracked to another)
+and creates a clone with a set of Ipo Curves named Ipo<objname>
+These curves control a non-constrained object and thus make it mimic the constrained object
+Actions can be then be edited without the need for the drivers/constraining objects
+
+Developed for use with MoCap data, where a bone is constrained to point at an empty
+moving through space and time. This records the actual locrot of the armature
+so that the motion can be edited, reoriented, scaled, and used as NLA Actions
+
+see also wiki Scripts/Manual/ Tutorial/Motion Capture <br>
+
+Usage: <br>
+ - Select the reference Object(s) you want to bake <br>
+ - Set the frame range to bake in the Anim Panel <br>
+ - Set the test code (if you want a self-test) in the RT field in the Anim Panel <br>
+ -- Set RT:1 to create a test armature <br>
+ -- Set RT: up to 100 for more debug messages and status updates <br>
+<br>
+ - Run the script <br>
+ - The clone copy of the object is created and it has an IPO curve assigned to it. <br>
+ - The clone shadows the object by an offset locrot (see usrDelta) <br>
+ - That Object has Ipo Location and Rotation curves that make the clone mimic the movement <br>
+ of the selected object, but without using constraints. <br>
+ - If the object was an Armature, the clone's bones move identically in relation to the <br>
+ original armature, and an Action is created that drives the bone movements. <br>
+
+Version History:
+ 0.1: bakes Loc Rot for a constrained object
+ 0.2: bakes Loc and Rot for the bones within Armature object
+ 0.3: UI for setting options
+ 0.3.1 add manual to script library
+ 0.4: bake multiple objects
+ 0.5: root bone worldspace rotation
+ 0.6: re-integration with BPyArmature
+ 0.7: bakes parents and leaves clones selected
+
+License, Copyright, and Attribution:
+ by Roger WICKES May 2008, released under Blender Artistic Licence to Public Domain
+ feel free to add to any Blender Python Scripts Bundle.
+ Thanks to Jean-Baptiste PERIN, IdeasMan42 (Campbell Barton), Basil_Fawlty/Cage_drei (Andrew Cruse)
+ much lifted/learned from blender.org/documentation/245PytonDoc and wiki
+ some modules based on c3D_Import.py, PoseLib16.py and IPO/Armature code examples e.g. camera jitter
+
+Pseudocode:
+ Initialize
+ If at least one object is selected
+ For each selected object,
+ create a cloned object
+ remove any constraints on the clone
+ create or reset an ipo curve named like the object
+ for each frame
+ set the clone's locrot key based on the reference object
+ if it's an armature,
+ create an action (which is an Ipo for each bone)
+ for each frame of the animation
+ for each bone in the armature
+ set the key
+ Else you're a smurf
+
+Test Conditions and Regressions:
+ 1. (v0.1) Non-armatures (the cube), with ipo curve and constraints at the object level
+ 2. armatures, with ipo curve and constraints at the object level
+ 3. armatures, with bones that have ipo curves and constraints
+ 4. objects without parents, children with unselected parents, select children first.
+
+Naming conventions:
+ arm = a specific objec type armature
+ bone = bones that make up the skeleton of an armature
+
+ ob = object, an instance of an object type
+ ebone = edit bone, a bone in edit mode
+ pbone = pose bone, a posed bone in an object
+ tst = testing, self-test routines
+ usr = user-entered or designated stuff
+"""
+########################################
+
+import Blender
+from Blender import *
+from Blender.Mathutils import *
+import struct
+import string
+import bpy
+import BPyMessages
+import BPyArmature
+# reload(BPyArmature)
+from BPyArmature import getBakedPoseData
+
+Vector= Blender.Mathutils.Vector
+Euler= Blender.Mathutils.Euler
+Matrix= Blender.Mathutils.Matrix #invert() function at least
+RotationMatrix = Blender.Mathutils.RotationMatrix
+TranslationMatrix= Blender.Mathutils.TranslationMatrix
+Quaternion = Blender.Mathutils.Quaternion
+Vector = Blender.Mathutils.Vector
+POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT]
+
+#=================
+# Global Variables
+#=================
+
+# set senstitivity for displaying debug/console messages. 0=none, 100=max
+# then call debug(num,string) to conditionally display status/info in console window
+MODE=Blender.Get('rt') #execution mode: 0=run normal, 1=make test armature
+DEBUG=Blender.Get('rt') #how much detail on internal processing for user to see. range 0-100
+BATCH=False #called from command line? is someone there? Would you like some cake?
+
+#there are two coordinate systems, the real, or absolute 3D space,
+# and the local relative to a parent.
+COORDINATE_SYSTEMS = ['local','real']
+COORD_LOCAL = 0
+COORD_REAL = 1
+
+# User Settings - Change these options manually or via GUI (future TODO)
+usrCoord = COORD_REAL # what the user wants
+usrParent = False # True=clone keeps original parent, False = clone's parent is the clone of the original parent (if cloned)
+usrFreeze = 2 #2=yes, 0=no. Freezes shadow object in place at current frame as origin
+# delta is amount to offset/change from the reference object. future set in a ui, so technically not a constant
+usrDelta = [10,10,0,0,0,0] #order specific - Loc xyz Rot xyz
+usrACTION = True # Offset baked Action frames to start at frame 1
+
+CURFRAME = 'curframe' #keyword to use when getting the frame number that the scene is presently on
+ARMATURE = 'Armature' #en anglais
+BONE_SPACES = ['ARMATURESPACE','BONESPACE']
+ # 'ARMATURESPACE' - this matrix of the bone in relation to the armature
+ # 'BONESPACE' - the matrix of the bone in relation to itself
+
+#Ipo curves created are prefixed with a name, like Ipo_ or Bake_ followed by the object/bone name
+#bakedArmName = "b." #used for both the armature class and object instance
+usrObjectNamePrefix= ""
+#ipoBoneNamePrefix = ""
+# for example, if on entry an armature named Man was selected, and the object prefix was "a."
+# on exit an armature and an IPO curve named a.Man exists for the object as a whole
+# if that armature had bones (spine, neck, arm) and the bone prefix was "a."
+# the bones and IPO curves will be (a.spine, a.neck, a.arm)
+
+R2D = 18/3.1415 # radian to grad
+BLENDER_VERSION = Blender.Get('version')
+
+# Gets the current scene, there can be many scenes in 1 blend file.
+scn = Blender.Scene.GetCurrent()
+
+#=================
+# Methods
+#=================
+########################################
+def debug(num,msg): #use log4j or just console here.
+ if DEBUG >= num:
+ if BATCH == False:
+ print 'debug: '[:num/10+7]+msg
+ #TODO: else write out to file (runs faster if it doesnt have to display details)
+ return
+
+########################################
+def error(str):
+ debug(0,'ERROR: '+str)
+ if BATCH == False:
+ Draw.PupMenu('ERROR%t|'+str)
+ return
+
+########################################
+def getRenderInfo():
+ context=scn.getRenderingContext()
+ staframe = context.startFrame()
+ endframe = context.endFrame()
+ if endframe<staframe: endframe=staframe
+ curframe = Blender.Get(CURFRAME)
+ debug(90,'Scene is on frame %i and frame range is %i to %i' % (curframe,staframe,endframe))
+ return (staframe,endframe,curframe)
+
+########################################
+def sortObjects(obs): #returns a list of objects sorted based on parent dependency
+ obClones= []
+ while len(obClones) < len(obs):
+ for ob in obs:
+ if not ob in obClones:
+ par= ob.getParent()
+ #if no parent, or the parent is not scheduled to be cloned
+ if par==None:
+ obClones.append(ob) # add the independent
+ elif par not in obs: # parent will not be cloned
+ obClones.append(ob) # add the child
+ elif par in obClones: # is it on the list?
+ obClones.append(ob) # add the child
+ # parent may be a child, so it will be caught next time thru
+ debug(100,'clone object order: \n%s' % obClones)
+ return obClones # ordered list of (ob, par) tuples
+
+########################################
+def sortBones(xbones): #returns a sorted list of bones that should be added,sorted based on parent dependency
+# while there are bones to add,
+# look thru the list of bones we need to add
+# if we have not already added this bone
+# if it does not have a parent
+# add it
+# else, it has a parent
+# if we already added it's parent
+# add it now.
+# else #we need to keep cycling and catch its parent
+# else it is a root bone
+# add it
+# else skip it, it's already in there
+# endfor
+# endwhile
+ xboneNames=[]
+ for xbone in xbones: xboneNames.append(xbone.name)
+ debug (80,'reference bone order: \n%s' % xboneNames)
+ eboneNames=[]
+ while len(eboneNames) < len(xboneNames):
+ for xbone in xbones:
+ if not xbone.name in eboneNames:
+ if not xbone.parent:
+ eboneNames.append(xbone.name)
+ else:
+ if xbone.parent.name in eboneNames:
+ eboneNames.append(xbone.name)
+ #else skip it
+ #endif
+ #else prego
+ #endfor
+ #endwhile
+ debug (80,'clone bone order: \n%s' % eboneNames)
+ return eboneNames
+
+########################################
+def dupliArmature(ob): #makes a copy in current scn of the armature used by ob and its bones
+ ob_mat = ob.matrixWorld
+ ob_data = ob.getData()
+ debug(49,'Reference object uses %s' % ob_data)
+ arm_ob = Armature.Get(ob_data.name) #the armature used by the passed object
+
+ arm = Blender.Armature.New()
+ debug(20,'Cloning Armature %s to create %s' % (arm_ob.name, arm.name))
+ arm.drawType = Armature.STICK #set the draw type
+
+ arm.makeEditable() #enter editmode
+
+ # for each bone in the object's armature,
+ xbones=ob.data.bones.values()
+ usrSpace = 0 #0=armature, 1=local
+ space=[BONE_SPACES[usrSpace]][0]
+
+ #we have to make a list of bones, then figure out our parents, then add to the arm
+ #when creating a child, we cannot link to a parent if it does not yet exist in our armature
+ ebones = [] #list of the bones I want to create for my arm
+
+ eboneNames = sortBones(xbones)
+
+ i=0
+ # error('bones sorted. continue?')
+ for abone in eboneNames: #set all editable attributes to fully define the bone.
+ for bone in xbones:
+ if bone.name == abone: break # get the reference bone
+ ebone = Armature.Editbone() #throw me a bone, bone-man!
+ ebones.append(ebone) #you're on my list, buddy
+
+ ebone.name = bone.name
+ ebone.headRadius = bone.headRadius
+ ebone.tailRadius = bone.tailRadius
+ ebone.weight = bone.weight
+ ebone.options = bone.options
+
+ ebone.head = bone.head[space] #dictionary lookups
+ ebone.tail = bone.tail[space]
+ ebone.matrix = bone.matrix[space]
+ ebone.roll = bone.roll[space]
+
+ debug(30,'Generating new %s as child of %s' % (bone,bone.parent))
+ if bone.hasParent():
+# parent=bone.parent.name
+# debug(100,'looking for %s' % parent)
+# for parbone in xbones: if parbone.name == parent: break # get the parent bone
+# ebone.parent = arm.bones[ebones[j].name]
+ ebone.parent = arm.bones[bone.parent.name]
+# else:
+# ebone.parent = None
+ debug(30,'Generating new editbone %s as child of %s' % (ebone,ebone.parent))
+ arm.bones[ebone.name] = ebone # i would have expected an append or add function, but this works
+
+ debug (100,'arm.bones: \n%s' % arm.bones)
+ debug (20,'Cloned %i bones now in armature %s' %(len(arm.bones),arm.name))
+
+ myob = scn.objects.new(arm) #interestingly, object must be created before
+ arm.update() #armature can be saved
+ debug(40,'dupArm finished %s instanced as object %s' % (arm.name,myob.getName()))
+ print ob.matrix
+ print myob.matrix
+
+ return myob
+########################################
+def scrub(): # scrubs to startframe
+ staFrame,endFrame,curFrame = getRenderInfo()
+
+ # eye-candy, go from current to start, fwd or back
+ if not BATCH:
+ debug(100, "Positioning to start...")
+ frameinc=(staFrame-curFrame)/10
+ if abs(frameinc) >= 1:
+ for i in range(10):
+ curFrame+=frameinc
+ Blender.Set(CURFRAME,curFrame) # computes the constrained location of the 'real' objects
+ Blender.Redraw()
+ Blender.Set(CURFRAME, staFrame)
+ return
+
+########################################
+def bakeBones(ref_ob,arm_ob): #copy pose from ref_ob to arm_ob
+ scrub()
+ staFrame,endFrame,curFrame = getRenderInfo()
+ act = getBakedPoseData(ref_ob, staFrame, endFrame, ACTION_BAKE = True, ACTION_BAKE_FIRST_FRAME = usrACTION) # bake the pose positions of the reference ob to the armature ob
+ arm_ob.action = act
+ scrub()
+
+ # user comprehension feature - change action name and channel ipo names to match the names of the bone they drive
+ debug (80,'Renaming each action ipo to match the bone they pose')
+ act.name = arm_ob.name
+ arm_channels = act.getAllChannelIpos()
+ pose= arm_ob.getPose()
+ pbones= pose.bones.values() #we want the bones themselves, not the dictionary lookup
+ for pbone in pbones:
+ debug (100,'Channel listing for %s: %s' % (pbone.name,arm_channels[pbone.name] ))
+ ipo=arm_channels[pbone.name]
+ ipo.name = pbone.name # since bone names are unique within an armature, the pose names can be the same since they are within an Action
+
+ return
+
+########################################
+def getOrCreateCurve(ipo, curvename):
+ """
+ Retrieve or create a Blender Ipo Curve named C{curvename} in the C{ipo} Ipo
+ Either an ipo curve named C{curvename} exists before the call then this curve is returned,
+ Or such a curve doesn't exist before the call .. then it is created into the c{ipo} Ipo and returned
+ """
+ try:
+ mycurve = ipo.getCurve(curvename)
+ if mycurve != None:
+ pass
+ else:
+ mycurve = ipo.addCurve(curvename)
+ except:
+ mycurve = ipo.addCurve(curvename)
+ return mycurve
+
+########################################
+def eraseCurve(ipo,numCurves):
+ debug(90,'Erasing %i curves for %' % (numCurves,ipo.GetName()))
+ for i in range(numCurves):
+ nbBezPoints= ipo.getNBezPoints(i)
+ for j in range(nbBezPoints):
+ ipo.delBezPoint(i)
+ return
+
+########################################
+def resetIPO(ipo):
+ debug(60,'Resetting ipo curve named %s' %ipo.name)
+ numCurves = ipo.getNcurves() #like LocX, LocY, etc
+ if numCurves > 0:
+ eraseCurve(ipo, numCurves) #erase data if one exists
+ return
+
+########################################
+def resetIPOs(ob): #resets all IPO curvess assocated with an object and its bones
+ debug(30,'Resetting any ipo curves linked to %s' %ob.getName())
+ ipo = ob.getIpo() #may be None
+ ipoName = ipo.getName() #name of the IPO that guides/controls this object
+ debug(70,'Object IPO is %s' %ipoName)
+ try:
+ ipo = Ipo.Get(ipoName)
+ except:
+ ipo = Ipo.New('Object', ipoName)
+ resetIPO(ipo)
+ if ob.getType() == ARMATURE:
+ arm_data=ob.getData()
+ bones=arm_data.bones.values()
+ for bone in bones:
+ #for each bone: get the name and check for a Pose IPO
+ debug(10,'Processing '+ bone.name)
+ return
+
+########################################
+def parse(string,delim):
+ index = string.find(delim) # -1 if not found, else pointer to delim
+ if index+1: return string[:index]
+ return string
+
+########################################
+def newIpo(ipoName): #add a new Ipo object to the Blender scene
+ ipo=Blender.Ipo.New('Object',ipoName)
+
+ ipo.addCurve('LocX')
+ ipo.addCurve('LocY')
+ ipo.addCurve('LocZ')
+ ipo.addCurve('RotX')
+ ipo.addCurve('RotY')
+ ipo.addCurve('RotZ')
+ return ipo
+
+########################################
+def makeUpaName(type,name): #i know this exists in Blender somewhere...
+ debug(90,'Making up a new %s name using %s as a basis.' % (type,name))
+ name = (parse(name,'.'))
+ if type == 'Ipo':
+ ipoName = name # maybe we get lucky today
+ ext = 0
+ extlen = 3 # 3 digit extensions, like hello.002
+ success = False
+ while not(success):
+ try:
+ debug(100,'Trying %s' % ipoName)
+ ipo = Ipo.Get(ipoName)
+ #that one exists if we get here. add on extension and keep trying
+ ext +=1
+ if ext>=10**extlen: extlen +=1 # go to more digits if 999 not found
+ ipoName = '%s.%s' % (name, str(ext).zfill(extlen))
+ except: # could not find it
+ success = True
+ name=ipoName
+ else:
+ debug (0,'FATAL ERROR: I dont know how to make up a new %s name based on %s' % (type,ob))
+ return None
+ return name
+
+########################################
+def createIpo(ob): #create an Ipo and curves and link them to this object
+ #first, we have to create a unique name
+ #try first with just the name of the object to keep things simple.
+ ipoName = makeUpaName('Ipo',ob.getName()) # make up a name for a new Ipo based on the object name
+ debug(20,'Ipo and LocRot curves called %s' % ipoName)
+ ipo=newIpo(ipoName)
+ ob.setIpo(ipo) #link them
+ return ipo
+
+########################################
+def getLocLocal(ob):
+ key = [
+ ob.LocX,
+ ob.LocY,
+ ob.LocZ,
+ ob.RotX*R2D, #get the curves in this order
+ ob.RotY*R2D,
+ ob.RotZ*R2D
+ ]
+ return key
+
+########################################
+def getLocReal(ob):
+ obMatrix = ob.matrixWorld #Thank you IdeasMan42
+ loc = obMatrix.translationPart()
+ rot = obMatrix.toEuler()
+ key = [
+ loc.x,
+ loc.y,
+ loc.z,
+ rot.x/10,
+ rot.y/10,
+ rot.z/10
+ ]
+ return key
+
+########################################
+def getLocRot(ob,space):
+ if space in xrange(len(COORDINATE_SYSTEMS)):
+ if space == COORD_LOCAL:
+ key = getLocLocal(ob)
+ return key
+ elif space == COORD_REAL:
+ key = getLocReal(ob)
+ return key
+ else: #hey, programmers make mistakes too.
+ debug(0,'Fatal Error: getLoc called with %i' % space)
+ return
+
+########################################
+def getCurves(ipo):
+ ipos = [
+ ipo[Ipo.OB_LOCX],
+ ipo[Ipo.OB_LOCY],
+ ipo[Ipo.OB_LOCZ],
+ ipo[Ipo.OB_ROTX], #get the curves in this order
+ ipo[Ipo.OB_ROTY],
+ ipo[Ipo.OB_ROTZ]
+ ]
+ return ipos
+
+########################################
+def addPoint(time,keyLocRot,ipos):
+ if BLENDER_VERSION < 245:
+ debug(0,'WARNING: addPoint uses BezTriple')
+ for i in range(len(ipos)):
+ point = BezTriple.New() #this was new with Blender 2.45 API
+ point.pt = (time, keyLocRot[i])
+ point.handleTypes = [1,1]
+
+ ipos[i].append(point)
+ return ipos
+
+########################################
+def bakeFrames(ob,myipo): #bakes an object in a scene, returning the IPO containing the curves
+ myipoName = myipo.getName()
+ debug(20,'Baking frames for scene %s object %s to ipo %s' % (scn.getName(),ob.getName(),myipoName))
+ ipos = getCurves(myipo)
+ #TODO: Gui setup idea: myOffset
+ # reset action to start at frame 1 or at location
+ myOffset=0 #=1-staframe
+ #loop through frames in the animation. Often, there is rollup and the mocap starts late
+ staframe,endframe,curframe = getRenderInfo()
+ for frame in range(staframe, endframe+1):
+ debug(80,'Baking Frame %i' % frame)
+ #tell Blender to advace to frame
+ Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects
+ if not BATCH: Blender.Redraw() # no secrets, let user see what we are doing
+
+ #using the constrained Loc Rot of the object, set the location of the unconstrained clone. Yea! Clones are FreeMen
+ key = getLocRot(ob,usrCoord) #a key is a set of specifed exact channel values (LocRotScale) for a certain frame
+ key = [a+b for a,b in zip(key, usrDelta)] #offset to the new location
+
+ myframe= frame+myOffset
+ Blender.Set(CURFRAME,myframe)
+
+ time = Blender.Get('curtime') #for BezTriple
+ ipos = addPoint(time,key,ipos) #add this data at this time to the ipos
+ debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (myipoName, myframe, time, key[0], key[1], key[2], key[3], key[4], key[5]))
+ # eye-candy - smoothly rewind the animation, showing now how the clone match moves
+ if endframe-staframe <400 and not BATCH:
+ for frame in range (endframe,staframe,-1): #rewind
+ Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects
+ Blender.Redraw()
+ Blender.Set(CURFRAME,staframe)
+ Blender.Redraw()
+
+ return ipos
+
+########################################
+def duplicateLinked(ob):
+ obType = ob.type
+ debug(10,'Duplicating %s Object named %s' % (obType,ob.getName()))
+ scn.objects.selected = [ob]
+## rdw: simplified by just duplicating armature. kept code as reference for creating armatures
+## disadvantage is that you cant have clone as stick and original as octahedron
+## since they share the same Armature. User can click Make Single User button.
+## if obType == ARMATURE: #build a copy from scratch
+## myob= dupliArmature(ob)
+## else:
+ Blender.Object.Duplicate() # Duplicate linked, including pose constraints.
+ myobs = Object.GetSelected() #duplicate is top on the list
+ myob = myobs[0]
+ if usrParent == False:
+ myob.clrParent(usrFreeze)
+ debug(20,'=myob= was created as %s' % myob.getName())
+ return myob
+
+########################################
+def removeConstraints(ob):
+ for const in ob.constraints:
+ debug(90,'removed %s => %s' % (ob.name, const))
+ ob.constraints.remove(const)
+ return
+
+########################################
+def removeConstraintsOb(ob): # from object or armature
+ debug(40,'Removing constraints from '+ob.getName())
+ if BLENDER_VERSION > 241: #constraints module not available before 242
+ removeConstraints(ob)
+ if ob.getType() == ARMATURE:
+ pose = ob.getPose()
+ for pbone in pose.bones.values():
+ #bone = pose.bones[bonename]
+ removeConstraints(pbone)
+ #should also check if it is a deflector?
+ return
+
+########################################
+def deLinkOb(type,ob): #remove linkages
+ if type == 'Ipo':
+ success = ob.clearIpo() #true=there was one
+ if success: debug(80,'deLinked Ipo curve to %s' % ob.getName())
+ return
+
+########################################
+def bakeObject(ob): #bakes the core object locrot and assigns the Ipo to a Clone
+ if ob != None:
+ # Clone the object - duplicate it, clean the clone, and create an ipo curve for the clone
+ myob = duplicateLinked(ob) #clone it
+ myob.name= usrObjectNamePrefix + ob.getName()
+ removeConstraintsOb(myob) #my object is a free man
+ deLinkOb('Ipo',myob) #kids, it's not nice to share. you've been lied to
+ if ob.getType() != ARMATURE: # baking armatures is based on bones, not object
+ myipo = createIpo(myob) #create own IPO and curves for the clone object
+ ipos = bakeFrames(ob,myipo) #bake the locrot for this obj for the scene frames
+ return myob
+
+########################################
+def bake(ob,par): #bakes an object of any type, linking it to parent
+ debug(0,'Baking %s object %s' % (ob.getType(), ob))
+ clone = bakeObject(ob) #creates and bakes the object motion
+ if par!= None:
+ par.makeParent([clone])
+ debug(20,"assigned object to parent %s" % par)
+ if ob.getType() == ARMATURE:
+## error('Object baked. Continue with bones?')
+ bakeBones(ob,clone) #go into the bones and copy from -> to in frame range
+ #future idea: bakeMesh (net result of Shapekeys, Softbody, Cloth, Fluidsim,...)
+ return clone
+
+########################################
+def tstCreateArm(): #create a test armature in scene
+ # rip-off from http://www.blender.org/documentation/245PythonDoc/Pose-module.html - thank you!
+
+ debug(0,'Making Test Armature')
+ # New Armature
+ arm_data= Armature.New('myArmature')
+ print arm_data
+ arm_ob = scn.objects.new(arm_data)
+ arm_data.makeEditable()
+
+ # Add 4 bones
+ ebones = [Armature.Editbone(), Armature.Editbone(), Armature.Editbone(), Armature.Editbone()]
+
+ # Name the editbones
+ ebones[0].name = 'Bone.001'
+ ebones[1].name = 'Bone.002'
+ ebones[2].name = 'Bone.003'
+ ebones[3].name = 'Bone.004'
+
+ # Assign the editbones to the armature
+ for eb in ebones:
+ arm_data.bones[eb.name]= eb
+
+ # Set the locations of the bones
+ ebones[0].head= Mathutils.Vector(0,0,0)
+ ebones[0].tail= Mathutils.Vector(0,0,1) #tip
+ ebones[1].head= Mathutils.Vector(0,0,1)
+ ebones[1].tail= Mathutils.Vector(0,0,2)
+ ebones[2].head= Mathutils.Vector(0,0,2)
+ ebones[2].tail= Mathutils.Vector(0,0,3)
+ ebones[3].head= Mathutils.Vector(0,0,3)
+ ebones[3].tail= Mathutils.Vector(0,0,4)
+
+ ebones[1].parent= ebones[0]
+ ebones[2].parent= ebones[1]
+ ebones[3].parent= ebones[2]
+
+ arm_data.update()
+ # Done with editing the armature
+
+ # Assign the pose animation
+ arm_pose = arm_ob.getPose()
+
+ act = arm_ob.getAction()
+ if not act: # Add a pose action if we dont have one
+ act = Armature.NLA.NewAction()
+ act.setActive(arm_ob)
+
+ xbones=arm_ob.data.bones.values()
+ pbones = arm_pose.bones.values()
+
+ frame = 1
+ for pbone in pbones: # set bones to no rotation
+ pbone.quat[:] = 1.000,0.000,0.000,0.0000
+ pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
+
+ # Set a different rotation at frame 25
+ pbones[0].quat[:] = 1.000,0.1000,0.2000,0.20000
+ pbones[1].quat[:] = 1.000,0.6000,0.5000,0.40000
+ pbones[2].quat[:] = 1.000,0.1000,0.3000,0.40000
+ pbones[3].quat[:] = 1.000,-0.2000,-0.3000,0.30000
+
+ frame = 25
+ for i in xrange(4):
+ pbones[i].insertKey(arm_ob, frame, Object.Pose.ROT)
+
+ pbones[0].quat[:] = 1.000,0.000,0.000,0.0000
+ pbones[1].quat[:] = 1.000,0.000,0.000,0.0000
+ pbones[2].quat[:] = 1.000,0.000,0.000,0.0000
+ pbones[3].quat[:] = 1.000,0.000,0.000,0.0000
+
+ frame = 50
+ for pbone in pbones: # set bones to no rotation
+ pbone.quat[:] = 1.000,0.000,0.000,0.0000
+ pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
+
+ return arm_ob
+
+########################################
+def tstMoveOb(ob): # makes a simple LocRot animation of object in the scene
+ anim = [
+ #Loc Rot/10
+ #
+ ( 0,0,0, 0, 0, 0), #frame 1 origin
+ ( 1,0,0, 0, 0, 0), #frame 2
+ ( 1,1,0, 0, 0, 0),
+ ( 1,1,1, 0, 0, 0),
+ ( 1,1,1,4.5, 0, 0),
+ ( 1,1,1,4.5,4.5, 0),
+ ( 1,1,1,4.5,4.5,4.5)
+ ]
+ space = COORD_LOCAL
+ ipo = createIpo(ob) #create an Ipo and curves for this object
+ ipos = getCurves(ipo)
+
+ # span this motion over the currently set anim range
+ # to set points, i need time but do not know how it is computed, so will have to advance the animation
+ staframe,endframe,curframe = getRenderInfo()
+
+ frame = staframe #x position of new ipo datapoint. set to staframe if you want a match
+ frameDelta=(endframe-staframe)/(len(anim)) #accomplish the animation in frame range
+ for key in anim: #effectively does a getLocRot()
+ #tell Blender to advace to frame
+ Blender.Set('curframe',frame) # computes the constrained location of the 'real' objects
+ time = Blender.Get('curtime')
+
+ ipos = addPoint(time,key,ipos) #add this data at this time to the ipos
+
+ debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (ipo.name, frame, time, key[0], key[1], key[2], key[3], key[4], key[5]))
+ frame += frameDelta
+ Blender.Set(CURFRAME,curframe) # reset back to where we started
+ return
+#=================
+# Program Template
+#=================
+########################################
+def main():
+ # return code set via rt button in Blender Buttons Scene Context Anim panel
+ if MODE == 1: #create test armature #1
+ ob = tstCreateArm() # make test arm and select it
+ tstMoveOb(ob)
+ scn.objects.selected = [ob]
+
+ obs= Blender.Object.GetSelected() #scn.objects.selected
+ obs= sortObjects(obs)
+ debug(0,'Baking %i objects' % len(obs))
+
+ if len(obs) >= 1: # user might have multiple objects selected
+ i= 0
+ clones=[] # my clone army
+ for ob in obs:
+ par= ob.getParent()
+ if not usrParent:
+ if par in obs:
+ par= clones[obs.index(par)]
+ clones.append(bake(ob,par))
+ scn.objects.selected = clones
+ else:
+ error('Please select at least one object')
+ return
+
+########################################
+def benchmark(): # This lets you benchmark (time) the script's running duration
+ Window.WaitCursor(1)
+ t = sys.time()
+ debug(60,'%s began at %.0f' %(__script__,sys.time()))
+
+ # Run the function on the active scene
+ in_editmode = Window.EditMode()
+ if in_editmode: Window.EditMode(0)
+
+ main()
+
+ if in_editmode: Window.EditMode(1)
+
+ # Timing the script is a good way to be aware on any speed hits when scripting
+ debug(0,'%s Script finished in %.2f seconds' % (__script__,sys.time()-t) )
+ Window.WaitCursor(0)
+ return
+
+########################################
+# This lets you can import the script without running it
+if __name__ == '__main__':
+ debug(0, "------------------------------------")
+ debug(0, "%s %s Script begins with mode=%i debug=%i batch=%s" % (__script__,__version__,MODE,DEBUG,BATCH))
+ benchmark()
diff --git a/release/scripts/bpymodules/BPyArmature.py b/release/scripts/bpymodules/BPyArmature.py
index d0b41dc35c5..63df02d080c 100644
--- a/release/scripts/bpymodules/BPyArmature.py
+++ b/release/scripts/bpymodules/BPyArmature.py
@@ -11,13 +11,19 @@
# 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
+# Version History:
+# 1.0 original release bakes an armature into a matrix
+# 1.1 optional params (ACTION_BAKE, ACTION_BAKE_FIRST_FRAME, direct function to key and return the Action
import Blender
+from Blender import sys
import bpy
-def getBakedPoseData(ob_arm, start_frame, end_frame):
+def getBakedPoseData(ob_arm, start_frame, end_frame, ACTION_BAKE = False, ACTION_BAKE_FIRST_FRAME = True):
'''
If you are currently getting IPO's this function can be used to
- return a list of frame aligned bone dictionary's
+ ACTION_BAKE==False: return a list of frame aligned bone dictionary's
+ ACTION_BAKE==True: return an action with keys aligned to bone constrained movement
+ if ACTION_BAKE_FIRST_FRAME is not supplied or is true: keys begin at frame 1
The data in these can be swaped in for the IPO loc and quat
@@ -77,7 +83,13 @@ def getBakedPoseData(ob_arm, start_frame, end_frame):
# --------------------------------- Main loop to collect IPO data
frame_index = 0
+ NvideoFrames= end_frame-start_frame
for current_frame in xrange(start_frame, end_frame+1):
+ if frame_index==0: start=sys.time()
+ elif frame_index==15: print NvideoFrames*(sys.time()-start),"seconds estimated..." #slows as it grows *3
+ elif frame_index >15:
+ percom= frame_index*100/NvideoFrames
+ print "Frame %i Overall %i percent complete\r" % (current_frame, percom),
ob_arm.action = backup_action
#pose.update() # not needed
Blender.Set('curframe', current_frame)
@@ -88,9 +100,7 @@ def getBakedPoseData(ob_arm, start_frame, end_frame):
for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data:
matrix= pose_bone.poseMatrix
-
parent_bone= rest_bone.parent
-
if parent_index != -1:
parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix
parent_bone_matrix_inv = armature_bone_data[parent_index][5]
@@ -98,40 +108,45 @@ def getBakedPoseData(ob_arm, start_frame, end_frame):
rest_matrix= rest_matrix * parent_bone_matrix_inv
matrix=matrix * rest_matrix.copy().invert()
-
pose_bone.quat= matrix.toQuat()
pose_bone.loc= matrix.translationPart()
- pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1
-
- # THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE
- # - use a temp action and bake into that, always at the same frame
- # so as not to make big IPO's, then collect the result from the IPOs
+ if ACTION_BAKE==False:
+ pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1
+
+ # THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE
+ # - use a temp action and bake into that, always at the same frame
+ # so as not to make big IPO's, then collect the result from the IPOs
- # Now get the data from the IPOs
- if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name)
+ # Now get the data from the IPOs
+ if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name)
- loc = Vector()
- quat = Quaternion()
+ loc = Vector()
+ quat = Quaternion()
- for curve in ipo:
- val = curve.evaluate(1)
- curve_name= curve.name
- if curve_name == 'LocX': loc[0] = val
- elif curve_name == 'LocY': loc[1] = val
- elif curve_name == 'LocZ': loc[2] = val
- elif curve_name == 'QuatW': quat[3] = val
- elif curve_name == 'QuatX': quat[0] = val
- elif curve_name == 'QuatY': quat[1] = val
- elif curve_name == 'QuatZ': quat[2] = val
+ for curve in ipo:
+ val = curve.evaluate(1)
+ curve_name= curve.name
+ if curve_name == 'LocX': loc[0] = val
+ elif curve_name == 'LocY': loc[1] = val
+ elif curve_name == 'LocZ': loc[2] = val
+ elif curve_name == 'QuatW': quat[3] = val
+ elif curve_name == 'QuatX': quat[0] = val
+ elif curve_name == 'QuatY': quat[1] = val
+ elif curve_name == 'QuatZ': quat[2] = val
- bake_data[frame_index][bone_name] = loc, quat
-
-
+ bake_data[frame_index][bone_name] = loc, quat
+ else:
+ if ACTION_BAKE_FIRST_FRAME: pose_bone.insertKey(ob_arm, frame_index+1, POSE_XFORM)
+ else: pose_bone.insertKey(ob_arm, current_frame , POSE_XFORM)
frame_index+=1
-
+ print "\nBaking Complete."
ob_arm.action = backup_action
- Blender.Set('curframe', backup_frame)
- return bake_data
+ if ACTION_BAKE==False:
+ Blender.Set('curframe', backup_frame)
+ return bake_data
+ elif ACTION_BAKE==True:
+ return new_action
+ else: print "ERROR: Invalid ACTION_BAKE %i sent to BPyArmature" % ACTION_BAKE
diff --git a/release/scripts/c3d_import.py b/release/scripts/c3d_import.py
new file mode 100644
index 00000000000..ca4f8cd79e9
--- /dev/null
+++ b/release/scripts/c3d_import.py
@@ -0,0 +1,1243 @@
+#!BPY
+
+"""
+Name: 'Motion Capture (.c3d)...'
+Blender: 246
+Group: 'Import'
+Tooltip: 'Import a C3D Motion Capture file'
+"""
+__script__ = "C3D Motion Capture file import"
+__author__ = " Jean-Baptiste PERIN, Roger D. Wickes (rogerwickes@yahoo.com)"
+__version__ = "0.9"
+__url__ = ["Communicate problems and errors, BlenderArtists.org, Python forum"]
+__email__= ["rogerwickes@yahoo.com", "c3d script"]
+__bpydoc__ = """\
+c3d_import.py v0.8
+
+Script loading Graphics Lab Motion Capture file,
+Usage:<br>
+ - Run the script <br>
+ - Choose the file to open<br>
+ - Press Import C3D button<br>
+
+Version History:
+ 0.4: PERIN Released under Blender Artistic Licence
+ 0.5: WICKES used marker names, fixed 2.45 depricated call
+ 0.6: WICKES creates armature for each subject
+ 0.7: WICKES constrains armature to follow the empties (markers). Verified for shake hands s
+ 0.8: WICKES resolved DEC support issue
+ 0.9: BARTON removed scene name change, whitespace edits. WICKES added IK layers
+"""
+
+#----------------------------------------------
+# (c) Jean-Baptiste PERIN december 2005, released under Blender Artistic Licence
+# for the Blender 2.40 Python Scripts Bundle.
+#----------------------------------------------
+
+######################################################
+# This script imports a C3D file into blender.
+# Loader is based on MATLAB C3D loader from
+# Alan Morris, Toronto, October 1998
+# Jaap Harlaar, Amsterdam, april 2002
+######################################################
+
+import string
+import Blender
+from Blender import *
+import bpy
+import struct
+import BPyMessages
+Vector= Blender.Mathutils.Vector
+Euler= Blender.Mathutils.Euler
+Matrix= Blender.Mathutils.Matrix
+RotationMatrix = Blender.Mathutils.RotationMatrix
+TranslationMatrix= Blender.Mathutils.TranslationMatrix
+
+#=================
+# Global Variables, Constants, Defaults, and Shorthand References
+#=================
+# set senstitivity for displaying debug/console messages. 0=few, 100=max, including clicks at major steps
+# debug(num,string) to conditionally display status/info in console window
+DEBUG=Blender.Get('rt')
+
+# marker sets known in the world
+HUMAN_CMU= "HumanRTKm.mkr" # The Human Real-Time capture marker set used by CMU
+HUMAN_CMU2="HumanRT.mkr" # found in another file, seems same as others in that series
+MARKER_SETS = [ HUMAN_CMU, HUMAN_CMU2 ] # marker sets that this program supports (can make an armature for)
+XYZ_LIMIT= 10000 #max value for coordinates if in integer format
+
+# what layers to put stuff on in scene. 1 is selected, so everything goes there
+# selecting only layer 2 shows only the armature moving, 12 shows only the empties
+LAYERS_ARMOB= [1,2]
+LAYERS_MARKER=[1,12]
+LAYERS_IK=[1,11]
+IK_PREFIX="ik_" # prefix in empty name: ik_prefix+subject prefix+bone name
+
+CLEAN=True # Should program ignore markers at (0,0,0) and beyond the outer limits?
+
+scn = Blender.Scene.GetCurrent()
+
+BCS=Blender.Constraint.Settings # shorthand dictionary - define with brace, reference with bracket
+trackto={"+x":BCS.TRACKX, "+y":BCS.TRACKY, "+z":BCS.TRACKZ, "-x":BCS.TRACKNEGX, "-y":BCS.TRACKNEGY, "-z":BCS.TRACKNEGZ}
+trackup={"x":BCS.UPX, "y":BCS.UPY, "z":BCS.UPZ}
+
+#=============================#
+# Classes
+#=============================#
+class Marker:
+ def __init__(self, x, y, z):
+ self.x=0.0
+ self.y=0.0
+ self.z=0.0
+
+ def __repr__(self): #report on self, as in if just printed
+ return str("[x = "+str(self.x) +" y = " + str(self.y)+" z = "+ str(self.z)+"]")
+
+class ParameterGroup:
+ def __init__(self, nom, description, parameter):
+ self.name = nom
+ self.description = description
+ self.parameter = parameter
+
+ def __repr__(self):
+ return self.name, " ", self.description, " ", self.parameter
+
+class Parameter:
+ def __init__(self, name, datatype, dim, data, description):
+ self.name = name
+ self.datatype = datatype
+ self.dim = dim
+ self.data = data
+ self.description = description
+
+ def __repr__(self):
+ return self.name, " ", self.description, " ", self.dim
+
+class MyVector:
+ def __init__(self, fx,fy,fz):
+ self.x=fx
+ self.y=fy
+ self.z=fz
+
+class Mybone:
+ "information structure for bone generation and posing"
+ def __init__(self, name,vec,par,head,tail,const):
+ self.name=name # name of this bone. must be unique within armature
+ self.vec=vec # edit bone vector it points
+ self.parent=par # name of parent bone to locate head and form a chain
+ self.headMark=head # list of 0+ markers where the head of this non-parented bone should be placed
+ self.tailMark=tail # list of 0+ markers where the tip should be placed
+ self.const=const # list of 0+ constraint tuples to control posing
+ self.head=MyVector(0,0,0) #T-pose location
+ self.tail=MyVector(0,0,0)
+ def __repr__(self):
+ return '[Mybone "%s"]' % self.name
+
+
+#=============================#
+# functions/modules
+#=============================#
+def error(str):
+ Draw.PupMenu('ERROR%t|'+str)
+ return
+def status(str):
+ Draw.PupMenu('STATUS%t|'+str+"|Continue?")
+ return
+def debug(num,msg): #use log4j or just console here.
+ if DEBUG >= num:
+ print 'debug:', (' '*num), msg
+ #TODO: if level 0, make a text file in Blender file to record major stuff
+ return
+
+def names(ob): return ob.name
+
+
+#########
+# Cette fonction renvoie la liste des empties
+# in :
+# out : emp_list (List of Object) la liste des objets de type "Empty"
+#########
+def getEmpty(name):
+ obs = [ob for ob in scn.objects if ob.type=="Empty" and ob.name==name]
+ if len(obs)==0:
+ return None
+ elif len(obs)==1:
+ return obs[0]
+ else:
+ error("FATAL ERROR: %i empties %s in file" % (len(obs),ob[0]))
+#########
+# Cette fonction renvoie un empty
+# in : objname : le nom de l'empty recherche
+# out : myobj : l'empty cree ou retrouve
+#########
+def getOrCreateEmpty(objname):
+ myobj= getEmpty(objname)
+ if myobj==None:
+ myobj = scn.objects.new("Empty",objname)
+ debug(50,'Marker/Empty created %s' % myobj)
+ return myobj
+
+def getOrCreateCurve(ipo, curvename):
+ """
+ Retrieve or create a Blender Ipo Curve named C{curvename} in the C{ipo} Ipo
+
+ >>> import mylib
+
+ >>> lIpo = GetOrCreateIPO("Une IPO")
+ >>> laCurve = getOrCreateCurve(lIpo, "RotX")
+
+ Either an ipo curve named C{curvename} exists before the call then this curve is returned,
+ Or such a curve doesn't exist before the call .. then it is created into the c{ipo} Ipo and returned
+
+ @type ipo: Blender Ipo
+ @param ipo: the Ipo in which the curve must be retrieved or created.
+ @type curvename: string
+ @param curvename: name of the IPO.
+ @rtype: Blender Curve
+ @return: a Blender Curve named C{curvename} in the C{ipo} Ipo
+ """
+ try:
+ mycurve = ipo.getCurve(curvename)
+ if mycurve != None:
+ pass
+ else:
+ mycurve = ipo.addCurve(curvename)
+ except:
+ mycurve = ipo.addCurve(curvename)
+ return mycurve
+
+def eraseIPO (objectname):
+ object = Blender.Object.Get(objectname)
+ lIpo = object.getIpo()
+ if lIpo != None:
+ nbCurves = lIpo.getNcurves()
+ for i in range(nbCurves):
+ nbBezPoints = lIpo.getNBezPoints(i)
+ for j in range(nbBezPoints):
+ lIpo.delBezPoint(i)
+
+def comp_loc(emptyNameList):
+ myloc=Vector(0,0,0)
+ for emName in emptyNameList:
+ myobj = Blender.Object.Get(emName)
+ for i in range(3):
+ myloc[i]= myloc[i]+(myobj.loc[i]/len(emptyNameList)) #take the average loc of all marks
+ return myloc
+
+def comp_len(head, tail): # computes the length of a bone
+ headvec=comp_loc(head)
+ tailvec=comp_loc(tail)
+ netvec=headvec-tailvec
+ return netvec.length
+
+def createHumanCMU(): # human bone structure, makes a node set for CMU MoCap Lab
+ # order of bones: "spine","chest","neck","head",...face toward you in front view
+ # pose constraints are tuples of (type,target,influence,other-as-needed)
+ # constraint stack order is important. for proper bone pointing and orinetation:
+ # IK, then TT +YZ in world space. then LR XZ to 0 in world space, this points the bone, twists it, but then
+ # limits the rotation to the sidebar enpty with the Z facing it, and Y pointing along the bone.
+ nodes=[] # bonename, vector, parent, head targets, tail targets, constraint list
+ for i in range(23): nodes.append(Mybone("name","vec","par",[],[],[]))
+ nodes[0]= Mybone("root", "-Y","",["RBWT", "LBWT"],["RFWT", "LFWT", "RBWT", "LBWT"],[("LOC","RBWT",1.0),("LOC","LBWT",0.5),("IK","RFWT",1.0),("IK","LFWT",0.5),("TT","RBWT",1,"+YZ"),("LR","XZ",1)])
+ nodes[1]= Mybone("spine","+Z","root",[],["STRN","T10"],[("IK","STRN",1.0),("IK","T10",0.5),("TT","STRN",1,"+YZ"),("LR","XZ",1)])
+ nodes[2]= Mybone("chest","+Z","spine",[],["CLAV","C7"],[("IK","CLAV",1.0),("IK","C7",0.5),("TT","CLAV",1,"+YZ"),("LR","XZ",1)])
+ nodes[3]= Mybone("neck", "+Z","chest",[],["RBHD","LBHD"],[("IK","RBHD",1.0),("IK","LBHD",0.5),("TT","LBHD",1,"+YZ"),("LR","XZ",1)])
+ nodes[4]= Mybone("head" ,"-Y","neck",[],["RFHD","LFHD"],[("IK","RFHD",1.0),("IK","LFHD",0.5),("TT","LFHD",1,"+YZ"),("LR","XZ",1)])
+
+ nodes[5]= Mybone("shoulder.R","-X","chest",[],["RSHO"],[("IK","RSHO",1.0)])
+ nodes[6]= Mybone("toparm.R", "-X","shoulder.R",[],["RELB"],[("IK","RELB",1.0),("TT","RUPA",1,"+YZ"),("LR","XZ",1)])
+ nodes[7]= Mybone("lowarm.R", "-X","toparm.R",[],["RWRA","RWRB"],[("IK","RWRA",1.0),("IK","RWRB",0.5),("TT","RFRM",1,"+YZ"),("LR","XZ",1)])
+ nodes[8]= Mybone("hand.R", "-X","lowarm.R",[],["RFIN"],[("IK","RFIN",1.0),("TT","RWRA",1,"+YZ"),("LR","XZ",1)]) #missing ,"RTHM"
+
+ nodes[9]= Mybone("hip.R", "-X","root",[],["RFWT","RBWT"],[("IK","RFWT",1.0),("IK","RBWT",0.5)])
+ nodes[10]=Mybone("topleg.R","-Z","hip.R",[],["RKNE"],[("IK","RKNE",1),("TT","RTHI",1,"+YZ"),("LR","XZ",1)])
+ nodes[11]=Mybone("lowleg.R","-Z","topleg.R",[],["RANK","RHEE"],[("IK","RHEE",1.0),("TT","RSHN",1,"+YZ"),("LR","XZ",1)])
+ nodes[12]=Mybone("foot.R", "-Y","lowleg.R",[],["RTOE","RMT5"],[("IK","RTOE",1.0),("IK","RMT5",0.2),("TT","RMT5",1,"+YZ")])
+ nodes[13]=Mybone("toes.R", "-Y","foot.R",[],["RTOE"],[("IK","RTOE",1.0)])
+
+ nodes[14]=Mybone("shoulder.L","+X","chest",[],["LSHO"],[("IK","LSHO",1.0)])
+ nodes[15]=Mybone("toparm.L", "+X","shoulder.L",[],["LELB"],[("IK","LELB",1.0),("TT","LUPA",1,"+YZ"),("LR","XZ",1)])
+ nodes[16]=Mybone("lowarm.L", "+X","toparm.L",[],["LWRA","LWRB"],[("IK","LWRA",1.0),("IK","LWRB",0.5),("TT","LFRM",1,"+YZ"),("LR","XZ",1)])
+ nodes[17]=Mybone("hand.L", "+X","lowarm.L",[],["LFIN"],[("IK","LFIN",1.0),("TT","RWRA",1,"+YZ"),("LR","XZ",1)]) #missing ,"LTHM"
+
+ nodes[18]=Mybone("hip.L", "+X","root",[],["LFWT","LBWT"],[("IK","LFWT",1.0),("IK","LBWT",0.5)])
+ nodes[19]=Mybone("topleg.L","-Z","hip.L",[],["LKNE"],[("IK","LKNE",1),("TT","LTHI",1,"+YZ"),("LR","XZ",1)])
+ nodes[20]=Mybone("lowleg.L","-Z","topleg.L",[],["LANK","LHEE"],[("IK","LHEE",1.0),("TT","LSHN",1,"+YZ"),("LR","XZ",1)])
+ nodes[21]=Mybone("foot.L", "-Y","lowleg.L",[],["LTOE","LMT5"],[("IK","LTOE",1.0),("IK","LMT5",0.2),("TT","LMT5",1,"+YZ"),("LR","XZ",1)])
+ nodes[22]=Mybone("toes.L", "-Y","foot.L",[],["LTOE"],[("IK","LTOE",1.0)])
+ return nodes
+
+def createNodes(marker_set): # make a list of bone name, parent, edit head loc, edit tail loc, pose constraints
+ #ultimately, I want to read in an XML file here that specifies the node trees for various marker sets
+ if marker_set==HUMAN_CMU: nodes= createHumanCMU() #load up and verify the file has the CMU marker set
+ elif marker_set==HUMAN_CMU2: nodes= createHumanCMU()
+ else: nodes=[]
+ return nodes
+def findEntry(item,list):
+ for i in range(len(list)):
+ if item==list[i]: break
+ debug(100,"findEtnry %s is %i in list of %i items" % (item,i,len(list)))
+ return i
+def makeNodes(prefix, markerList, empties, marker_set): #make sure the file has the nodes selected
+ nodes= createNodes(marker_set) # list has generic marker names; replace them with the actual object names created
+ #each entry in markerlist has a corresponding entry in empties in the same order
+ errList=[]
+ for i in range(len(nodes)):
+ node= nodes[i]
+ debug(60,"Adapting node %s to prefix %s" % (node,prefix))
+
+ #replace generic head markers with actual empty names
+ for im in range(len(node.headMark)):
+ marker= node.headMark[im]
+ mark= prefix+marker
+ imn= findEntry(mark,markerList)
+ if imn < len(markerList):
+ debug(90,"Adapating head marker %s to %s" % (marker,empties[imn].name))
+ nodes[i].headMark[im]= empties[imn].name
+ else: errList.append([node.name,"head location",mark,node,2])
+
+ #replace generic tail markers with actual empty names
+ for im in range(len(node.tailMark)):
+ marker= node.tailMark[im]
+ mark= prefix+marker
+ imn= findEntry(mark,markerList)
+ if imn < len(markerList):
+ debug(90,"Adapating marker %s to %s" % (marker,empties[imn].name))
+ nodes[i].tailMark[im]= empties[imn].name
+ else: errList.append([node.name,"tail location",mark,node,2])
+
+ #replace generic constraint markers (if the constraint references a marker) with empty name
+ for im in range(len(node.const)):
+ const=node.const[im]
+ if const[0] in ("LOC","IK","TT"):
+ marker=const[1]
+ mark= prefix+marker
+ imn= findEntry(mark,markerList)
+ if imn < len(markerList):
+ debug(90,"Adapating %s constraint marker %s to %s" % (const[0],marker,empties[imn].name))
+ if const[0] in ("IK","LR","LOC"):
+ nodes[i].const[im]=(const[0], empties[imn].name, const[2])
+ else: nodes[i].const[im]=(const[0], empties[imn].name, const[2], const[3])
+ else: errList.append([node.name,const[0]+" constraint",mark,node,4])
+
+ if errList!=[]: #we have issues.
+ for err in errList:
+ debug(0,"Bone "+err[0]+" specifies "+err[2]+" as "+err[1]+"which was not specified in file.")
+ #need a popup here to ignore/cleanup node tree, or add the marker(?) or abort
+ usrOption= 1
+ if usrOption==0: #ignore this marker (remove it)
+ for node in nodes: #find the bone in error
+ if node.name==err[0]:
+ print "Before",node
+ if err[3] in range(2,3):
+ node[err[3]].remove(err[2]) #find the marker in error and remove it
+ elif err[3]==4: #find the constraint and remove it
+ for const in node.const:
+ if const[1]==err[2]: node.const.remove(const)
+ print "After",node
+ elif usrOption==1: #add these markers as static empties, and user will automate them later
+ #and the bones will be keyed to them, so it will all be good.
+ #file may have just mis-named the empty, or the location can be derived based on other markers
+ em= getOrCreateEmpty(err[2])
+ em.layers= LAYERS_MARKER
+ else: abort() #abend
+ if DEBUG==100: status("Nodes Updated")
+ return nodes #nodes may be updated
+
+def makeBones(arm,nodes):
+ debug(20,"Making %i edit bones" % len(nodes))
+ for node in nodes:
+ bone= Blender.Armature.Editbone()
+ bone.name= node.name
+ arm.bones[bone.name]= bone #add it to the armature
+ debug(50,"Bone added: %s" % bone)
+ if bone.name <> node.name:
+ debug(0,"ERROR: duplicate node % name specified" % node.name)
+ node.name= bone.name #you may not get what you asked for
+ if node.parent!="": #parent
+ debug(60,"Bone parent: %s"%node.parent)
+ bone.parent= arm.bones[node.parent]
+ bone.options = [Armature.CONNECTED]
+ #compute head = average of the reference empties
+ if node.headMark==[]: # no head explicitly stated, must be tail of parent
+ for parnode in nodes:
+ if node.parent==parnode.name: break
+ node.headMark= parnode.tailMark
+ node.head= parnode.tail
+ else: node.head= comp_loc(node.headMark) #node head is specified, probably only for root.
+
+ bone.head= node.head
+ debug(60,"%s bone head: (%0.2f, %0.2f, %0.2f)" % (bone.name,bone.head.x, bone.head.y, bone.head.z))
+ mylen=comp_len(node.headMark,node.tailMark) # length of the bone as it was recorded for that person
+ # for our T position, compute the bone length, add it to the head vector component to get the tail
+ if node.vec[0]=="-": mylen=-mylen
+ debug(80,"Bone vector %s length %0.2f" %(node.vec,mylen))
+ node.tail= Vector(node.head)
+ myvec=node.vec[1].lower()
+ if myvec=="x": node.tail.x+=mylen
+ elif myvec=="y": node.tail.y+=mylen
+ elif myvec=="z": node.tail.z+=mylen
+ else:
+ debug(0,"%s %s %s %s" % (node.vec,myvec,node.vec[0],node.vec[1]))
+ error("ERROR IN BONE SPEC ")
+ bone.tail= node.tail
+ debug(60,"Bone tail: (%i,%i,%i)" %(bone.tail.x, bone.tail.y, bone.tail.z))
+ #Armature created in the T postion, but with bone lengths to match the marker set and subject
+ #when this is constrained to the markers, the recorded action will be relative to a know Rotation
+ #so that all recorded actions should be interchangeable. wooot!
+ #Only have to adjust starting object loc when matching up actions.
+ return #arm #updated
+
+def makeConstLoc(pbone,const):
+ const_new= pbone.constraints.append(Constraint.Type.COPYLOC)
+ const_new.name = const[0]+"-"+const[1]
+ const_target=Blender.Object.Get(const[1])
+ const_new[BCS.TARGET]= const_target
+ const_new.influence = const[2]
+ return
+
+def makeConstLimRot(pbone,const):
+ const_new= pbone.constraints.append(Constraint.Type.LIMITROT)
+ const_new.name = const[0]+"-"+const[1]
+ for axis in const[1]:
+ if axis.lower()=="x": const_new[BCS.LIMIT] |= BCS.LIMIT_XROT #set
+ if axis.lower()=="y": const_new[BCS.LIMIT] |= BCS.LIMIT_YROT #set
+ if axis.lower()=="z": const_new[BCS.LIMIT] |= BCS.LIMIT_ZROT #set
+ const_new[BCS.OWNERSPACE]= BCS.SPACE_LOCAL
+ const_new.influence = const[2]
+ # fyi, const[Constraint.Settings.LIMIT] &= ~Constraint.Settings.LIMIT_XROT #reset
+ return
+
+def makeConstIK(prefix,pbone,const):
+ #Blender 246 only supports one IK Solver per bone, but we might want many,
+ # so we need to create a reference empty named after the bone
+ # that floats between the markers, so the bone can point to it as a singularity
+ myob= getOrCreateEmpty(IK_PREFIX+prefix+pbone.name)
+ myob.layers= LAYERS_IK
+ # note that this empty gets all the IK constraints added on as location constraints
+ myconst= myob.constraints.append(Constraint.Type.COPYLOC)
+ myconst.name=const[0]+"-"+const[1]
+ myconst[Constraint.Settings.TARGET]= Blender.Object.Get(const[1])
+ myconst.influence = const[2]
+
+ #point the bone once to the empty via IK
+ success=False
+ for myconst in pbone.constraints:
+ if myconst.type == Constraint.Type.IKSOLVER: success=True
+ if not(success): #add an IK constraint to the bone to point to the empty
+ #print pbone
+ myconst= pbone.constraints.append(Constraint.Type.IKSOLVER)
+ myconst.name = const[1]
+ myconst[BCS.TARGET]= myob
+ myconst.influence = const[2]
+ #const_new[Constraint.Settings.BONE]= ?
+ myconst[BCS.CHAINLEN]= 1
+ myconst[BCS.USETIP]= True
+ myconst[BCS.STRETCH]= False
+ return
+
+def makeConstTT(pbone,const):
+ myconst= pbone.constraints.append(Constraint.Type.TRACKTO)
+ myconst.name=const[0]+"-"+const[1]
+ debug(70,"%s %s" % (myconst,const[3]))
+ myob= getEmpty(const[1])
+ if myob!= None:
+ myconst[BCS.TARGET]= myob
+ myconst.influence = const[2]
+ #const[3] is the Track and the thrird char is the Up indicator
+ myconst[BCS.TRACK]= trackto[const[3][0:2].lower()]
+ myconst[BCS.UP]=trackup[const[3][2].lower()]#up direction
+ myconst[BCS.OWNERSPACE]= BCS.SPACE_LOCAL
+ myconst[BCS.TARGETSPACE]= [BCS.SPACE_LOCAL]
+ if const[3][1]==const[3][2]: debug(0,"WARNING: Track To axis and up axis should not be the same. Constraint is INACTIVE")
+ else: #marker not found. could be missing from this file, or an error in node spec
+ error("TrackTo Constraint for %s |specifies unknown marker %s" % (pbone.name,const[1]))
+ return
+
+def makePoses(prefix,arm_ob,nodes): # pose this armature object based on node requirements
+ #this is constraint-based posing, not hard-keyed posing.
+ #we do constraint-based first so that user can adjust the constraints, possibly smooth/tweak motion
+ # add additional bones or referneces/constraints, before baking to hard keyframes
+
+ pose= arm_ob.getPose()
+ debug(0,"Posing %s %s" % (arm_ob, pose))
+ for node in nodes:
+ debug(30, "examining %s" %node)
+ if len(node.const)>0: #constraints for this bone are desired
+ pbone = pose.bones[node.name]
+ debug(40,"Posing bone %s" %pbone)
+ for const in node.const:
+ debug(50,"Constraining %s by %s" %(pbone,const))
+ if const[0]=="LOC":makeConstLoc(pbone,const)
+ elif const[0]=="IK": makeConstIK(prefix,pbone,const)
+ elif const[0]=="LR": makeConstLimRot(pbone,const)
+ elif const[0]=="TT": makeConstTT(pbone,const)
+ else:
+ error("FATAL: constraint %s not supported" %const[0])
+ break
+ debug(10, "Posing complete. Cycling pose and edit mode")
+ pose.update()
+ return
+
+def make_arm(subject,prefix,markerList, emptyList,marker_set):
+ debug(10,"**************************")
+ debug(00, "**** Making Armature for %s..." % subject)
+ debug(10, "**************************")
+ # copied from bvh import bvh_node_dict2armature; trying to use similar process for further integtration down the road
+ # Add the new armature,
+
+ nodes= makeNodes(prefix, markerList, emptyList, marker_set) #assume everyone in file uses the same mocap suit
+ # each person in the file may be different height, so each needs their own new armature to match marker location
+
+## obs= Blender.Object.Get()
+## success=False
+## for ob in obs:
+## if ob.name==subject:
+## success=True
+## if success:
+## menu="Human Armature already exists for this subject."
+## menu+="%t|Create another in this scene"
+## menu+="%l|Start a new scene"
+## menu+="%l|Use this armature"
+## menusel= Draw.PupMenu(menu)
+
+ arm= Blender.Armature.New(subject) #make an armature.
+ debug(10,"Created Armature %s" % arm)
+ # Put us into editmode
+ arm.makeEditable()
+ arm.drawType = Armature.OCTAHEDRON
+ makeBones(arm,nodes)
+ scn = Blender.Scene.GetCurrent() #add it to the current scene. could create new scenes here as yaf
+ arm_ob= scn.objects.new(arm) #instance it in the scene. this is the new way for 2.46 to instance objects
+ arm_ob.name= subject #name it something like the person it represents
+ arm_ob.layers= LAYERS_ARMOB
+ debug(20,"Instanced Armature %s" % arm_ob)
+ arm.update() #exit editmode. Arm must be instanced as an object before you can save changes or pose it
+ Blender.Redraw() # show the world
+ if DEBUG==100: status("T-Bones made.")
+
+ makePoses(prefix,arm_ob,nodes) #constrain arm_ob with these markers
+
+ scn.update(1) #make everyone behave themselves in the scene, and respect the new constraints
+ return arm_ob
+
+def setupAnim(StartFrame, EndFrame, VideoFrameRate):
+ debug(100, 'VideoFrameRate is %i' %VideoFrameRate)
+ if VideoFrameRate<1: VideoFrameRate=1
+ if VideoFrameRate>120: VideoFrameRate=120
+ # set up anim panel for them
+ context=scn.getRenderingContext()
+ context.startFrame(StartFrame)
+ context.endFrame(EndFrame)
+ context.framesPerSec(int(VideoFrameRate))
+ Blender.Set("curframe",StartFrame)
+ Blender.Redraw()
+ return
+
+def makeCloud(Nmarkers,markerList,StartFrame,EndFrame,Markers):
+ debug(10, "**************************")
+ debug(00, "*** Making Cloud Formation")
+ debug(10, "**************************")
+ empties=[]
+ ipos=[]
+ curvesX=[]
+ curvesY=[]
+ curvesZ=[]
+ debug(0, "%i Markers (empty cloud) will be put on layers %s" % (Nmarkers,LAYERS_MARKER))
+ # Empty Cloud formation
+ for i in range(Nmarkers):
+ debug(100,"%i marker %s"%(i, markerList[i]))
+ emptyname = markerList[i] # rdw: to use meaningful names from Points parameter
+ em= getOrCreateEmpty(emptyname) #in this scene
+ em.layers= LAYERS_MARKER
+ #make a list of the actual empty
+ empties.append(em)
+ #assign it an ipo with the loc xyz curves
+ lipo = Ipo.New("Object",em.name)
+ ipos.append(lipo)
+ curvesX.append(getOrCreateCurve(ipos[i],'LocX'))
+ curvesY.append(getOrCreateCurve(ipos[i],'LocY'))
+ curvesZ.append(getOrCreateCurve(ipos[i],'LocZ'))
+ empties[i].setIpo(ipos[i])
+ debug(30,"Cloud of %i empties created." % len(empties))
+ NvideoFrames= EndFrame-StartFrame+1
+ debug(10, "**************************")
+ debug(00, "**** Calculating Marker Ipo Curves over %i Frames ..." % NvideoFrames)
+ debug(10, "**************************")
+ err= index=0 #number of errors, logical frame
+ for frame in range(StartFrame,EndFrame+1):
+ if index==0: start=sys.time()
+ elif index==100:
+ tmp=(NvideoFrames-100)*(sys.time()-start)/6000
+ debug(0,"%i minutes process time estimated" % tmp)
+ elif index >100: print index*100/(NvideoFrames-1),"% complete\r",
+ for i in range(Nmarkers):
+ if Markers[index][i].z < 0: Markers[index][i].z= -Markers[index][i].z
+ success=True
+ if CLEAN: #check for good data
+ # C3D marker decoding may have coordinates negative (improper sign bit decoding?)
+ myX= abs(Markers[index][i].x)
+ myY= abs(Markers[index][i].y)
+ myZ= Markers[index][i].z
+ if myX > 10000 or myY > 10000 or myZ > 10000: success=False
+ if myX <.01 and myY <.01 and myZ <.01: success=False # discontinuity in marker tracking (lost marker)
+
+ if success:
+ curvesX[i].append((frame, Markers[index][i].x)) #2.46 knot method
+ curvesY[i].append((frame, Markers[index][i].y))
+ curvesZ[i].append((frame, Markers[index][i].z))
+ if frame==StartFrame: debug(40, "%s loc frame %i: (%0.2f, %0.2f, %0.2f)" % (markerList[i],frame,Markers[index][i].x,Markers[index][i].y,Markers[index][i].z))
+ else:
+ err+=1 # some files have thousands...
+ #debug(30,"Point ignored for marker:%s frame %i: (%i, %i, %i)" % (markerList[i],frame,Markers[index][i].x,Markers[index][i].y,Markers[index][i].z))
+ index += 1
+ debug(70, "%i points ignored across all markers and frames. Recalculating..." % err)
+
+ for i in range(Nmarkers):
+ curvesX[i].Recalc()
+ curvesY[i].Recalc()
+ curvesZ[i].Recalc()
+ Blender.Set('curframe', StartFrame)
+ Blender.Redraw()
+ if DEBUG==100: status("Clound formed")
+ return empties
+
+def getNumber(str, length):
+ if length==2: # unsigned short
+ return struct.unpack('H',str[0:2])[0], str[2:]
+ sum = 0
+ for i in range(length):
+ #sum = (sum << 8) + ord(str[i]) for big endian
+ sum = sum + ord(str[i])*(2**(8*i))
+ return sum, str[length:]
+def unpackFloat(chunk,proctype):
+ #print proctype
+ myvar=chunk[0:4]
+ if proctype==2: #DEC-VAX
+ myvar=chunk[2:4]+chunk[0:2] #swap lo=hi word order pair
+ return struct.unpack('f',myvar[0:4])[0]
+
+def getFloat(chunk,proctype):
+ return unpackFloat(chunk, proctype), chunk[4:]
+def parseFloat(chunk,ptr,proctype):
+ return unpackFloat(chunk[ptr:ptr+4], proctype), ptr+4
+
+
+def load_c3d(FullFileName):
+# Input: FullFileName - file (including path) to be read
+#
+# Variable:
+# Markers 3D-marker data [Nmarkers x NvideoFrames x Ndim(=3)]
+# VideoFrameRate Frames/sec
+# AnalogSignals Analog signals [Nsignals x NanalogSamples ]
+# AnalogFrameRate Samples/sec
+# Event Event(Nevents).time ..value ..name
+# ParameterGroup ParameterGroup(Ngroups).Parameters(Nparameters).data ..etc.
+# CameraInfo MarkerRelated CameraInfo [Nmarkers x NvideoFrames]
+# ResidualError MarkerRelated ErrorInfo [Nmarkers x NvideoFrames]
+
+ Markers=[];
+ VideoFrameRate=120;
+ AnalogSignals=[];
+ AnalogFrameRate=0;
+ Event=[];
+ ParameterGroups=[];
+ CameraInfo=[];
+ ResidualError=[];
+
+ debug(10, "*********************")
+ debug(10, "**** Opening File ***")
+ debug(10, "*********************")
+
+ #ind=findstr(FullFileName,'\');
+ #if ind>0, FileName=FullFileName(ind(length(ind))+1:length(FullFileName)); else FileName=FullFileName; end
+ debug(0, "FileName = " + FullFileName)
+ fid=open(FullFileName,'rb'); # native format (PC-intel). ideasman says maybe rU
+ content = fid.read();
+ content_memory = content
+ #Header section
+ NrecordFirstParameterblock, content = getNumber(content,1) # Reading record number of parameter section
+
+ key, content = getNumber(content,1)
+ if key!=80:
+ error('File: does not comply to the C3D format')
+ fid.close()
+ return
+ #Paramter section
+ content = content[512*(NrecordFirstParameterblock-1)+1:] # first word ignored
+ #file format spec says that 3rd byte=NumberofParmaterRecords... but is ignored here.
+ proctype,content =getNumber(content,1)
+ proctype = proctype-83
+ proctypes= ["unknown","(INTEL-PC)","(DEC-VAX)","(MIPS-SUN/SGI)"]
+
+ if proctype in (1,2): debug(0, "Processor coding %s"%proctypes[proctype])
+ elif proctype==3: debug(0,"Program untested with %s"%proctypes[proctype])
+ else:
+ debug(0, "INVALID processor type %i"%proctype)
+ proctype=1
+ debug(0,"OVERRIDE processor type %i"%proctype)
+
+ #if proctype==2,
+ # fclose(fid);
+ # fid=fopen(FullFileName,'r','d'); % DEC VAX D floating point and VAX ordering
+ #end
+ debug(10, "***********************")
+ debug(00, "**** Reading Header ***")
+ debug(10, "***********************")
+
+ # ###############################################
+ # ## ##
+ # ## read header ##
+ # ## ##
+ # ###############################################
+
+ #%NrecordFirstParameterblock=fread(fid,1,'int8'); % Reading record number of parameter section
+ #%key1=fread(fid,1,'int8'); % key = 80;
+
+ content = content_memory
+ #fseek(fid,2,'bof');
+ content = content[2:]
+
+ #
+ Nmarkers, content=getNumber(content, 2)
+ NanalogSamplesPerVideoFrame, content = getNumber(content, 2)
+ StartFrame, content = getNumber(content, 2)
+ EndFrame, content = getNumber(content, 2)
+ MaxInterpolationGap, content = getNumber(content, 2)
+
+ Scale, content = getFloat(content,proctype)
+
+ NrecordDataBlock, content = getNumber(content, 2)
+ NanalogFramesPerVideoFrame, content = getNumber(content, 2)
+
+ if NanalogFramesPerVideoFrame > 0:
+ NanalogChannels=NanalogSamplesPerVideoFrame/NanalogFramesPerVideoFrame
+ else:
+ NanalogChannels=0
+
+ VideoFrameRate, content = getFloat(content,proctype)
+
+ AnalogFrameRate=VideoFrameRate*NanalogFramesPerVideoFrame
+ NvideoFrames = EndFrame - StartFrame + 1
+
+ debug(0, "Scale= %0.2f" %Scale)
+ debug(0, "NanalogFramesPerVideoFrame= %i" %NanalogFramesPerVideoFrame)
+ debug(0, "Video Frame Rate= %i" %VideoFrameRate)
+ debug(0, "AnalogFrame Rate= %i"%AnalogFrameRate)
+ debug(0, "# markers= %i" %Nmarkers)
+ debug(0, "StartFrame= %i" %StartFrame)
+ debug(0, "EndFrame= %i" %EndFrame)
+ debug(0, "# Video Frames= %i" %NvideoFrames)
+
+ if Scale>0:
+ debug(0, "Marker data is in integer format")
+ if Scale>(XYZ_LIMIT/32767):
+ Scale=XYZ_LIMIT/32767.0
+ debug(0, "OVERRIDE: Max coordinate is %i, Scale changed to %0.2f" % (XYZ_LIMIT,Scale))
+ else: debug(0, "Marker data is in floating point format")
+ if VideoFrameRate<1 or VideoFrameRate>120:
+ VideoFrameRate= 120
+ debug(0, "OVERRIDE Video Frame Rate= %i" %VideoFrameRate)
+ if proctype not in (1,2): # Intel, DEC are known good
+ debug(0, "OVERRIDE|Program not tested with this encoding. Set to Intel")
+ proctype= 1
+
+ debug(10, "***********************")
+ debug(10, "**** Reading Events ...")
+ debug(10, "***********************")
+
+ content = content_memory
+ content = content[298:] #bizarre .. ce devrait être 150 selon la doc rdw skips first 299 bytes?
+
+ EventIndicator, content = getNumber(content, 2)
+ EventTime=[]
+ EventValue=[]
+ EventName=[]
+
+ debug(0, "Event Indicator = %i" %EventIndicator)
+ if EventIndicator==12345: #rdw: somehow, this original code seems fishy, but I cannot deny it.
+ Nevents, content = getNumber(content, 2)
+ debug(0, "Nevents= %i" %Nevents)
+ content = content[2:]
+ if Nevents>0:
+ for i in range(Nevents):
+ letime, content = getFloat(content,proctype)
+ EventTime.append(letime)
+ content = content_memory
+ content = content[188*2:]
+ for i in range(Nevents):
+ lavalue, content = getNumber(content, 1)
+ EventValue.append(lavalue)
+ content = content_memory
+ content = content[198*2:]
+ for i in range(Nevents):
+ lenom = content[0:4]
+ content = content[4:]
+ EventName.append(lenom)
+
+ debug(00, "***************************")
+ debug(00, "**** Reading Parameters ...")
+ debug(10, "***************************")
+ subjects=[] # a name would be nice, but human will do
+ prefixes=[] # added on to mocap marker names, one for each subject
+ marker_subjects = [] # hopefully will be specified in the file and known to this program
+ markerList=[]
+ ParameterGroups = []
+ ParameterNumberIndex = []
+
+ content = content_memory
+ content = content[512*(NrecordFirstParameterblock-1):]
+
+ dat1, content = getNumber(content, 1)
+ key2, content = getNumber(content, 1)
+
+ NparameterRecords, content = getNumber(content, 1)
+ debug(100, "NparameterRecords=%i"%NparameterRecords)
+ proctype,content =getNumber(content,1)
+ proctype = proctype-83 # proctype: 1(INTEL-PC); 2(DEC-VAX); 3(MIPS-SUN/SGI)
+
+ for i in range(NparameterRecords):
+ leparam = ParameterGroup(None, None, [])
+ ParameterGroups.append(leparam)
+ ParameterNumberIndex.append(0)
+ #
+ Ncharacters, content = getNumber(content, 1)
+ if Ncharacters>=128:
+ Ncharacters = -(2**8)+(Ncharacters)
+ GroupNumber, content = getNumber(content, 1)
+ if GroupNumber>=128:
+ GroupNumber = -(2**8)+(GroupNumber)
+ debug(80,"GroupNumber = %i, Nchar=%i" %(GroupNumber,Ncharacters))
+
+ while Ncharacters > 0:
+ if GroupNumber<0:
+ GroupNumber=abs(GroupNumber)
+ GroupName = content[0:Ncharacters]
+ content = content[Ncharacters:]
+ #print "Group Number = ", GroupNumber
+ ParameterGroups[GroupNumber].name = GroupName
+ #print "ParameterGroupName =", GroupName
+ offset, content = getNumber(content, 2)
+ deschars, content = getNumber(content, 1)
+ GroupDescription = content[0:deschars]
+ content = content[deschars:]
+ ParameterGroups[GroupNumber].description = GroupDescription
+ #
+ ParameterNumberIndex[GroupNumber]=0
+ content = content[offset-3-deschars:]
+ else:
+
+ ParameterNumberIndex[GroupNumber]=ParameterNumberIndex[GroupNumber]+1
+ ParameterNumber=ParameterNumberIndex[GroupNumber]
+ #print "ParameterNumber=", ParameterNumber
+ ParameterGroups[GroupNumber].parameter.append(Parameter(None, None, [], [], None))
+ ParameterName = content[0:Ncharacters]
+ content = content[Ncharacters:]
+ #print "ParameterName = ",ParameterName
+ if len(ParameterName)>0:
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].name=ParameterName
+ offset, content = getNumber(content, 2)
+ filepos = len(content_memory)-len(content)
+ nextrec = filepos+offset-2
+
+ type, content=getNumber(content, 1)
+ if type>=128:
+ type = -(2**8)+type
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].type=type
+
+ dimnum, content=getNumber(content, 1)
+ if dimnum == 0:
+ datalength = abs(type)
+ else:
+ mult=1
+ dimension=[]
+ for j in range (dimnum):
+ ladim, content = getNumber(content, 1)
+ dimension.append(ladim)
+ mult=mult*dimension[j]
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].dim.append(dimension[j])
+ datalength = abs(type)*mult
+
+ #print "ParameterNumber = ", ParameterNumber, " Group Number = ", GroupNumber
+
+ if type==-1:
+ data = ""
+ wordlength=dimension[0]
+ if dimnum==2 and datalength>0:
+ for j in range(dimension[1]):
+ data=string.rstrip(content[0:wordlength])
+ content = content[wordlength:]
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data.append(data)
+ elif dimnum==1 and datalength>0:
+ data=content[0:wordlength]
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data.append(data) # ???
+
+ myParam=string.rstrip(ParameterName)
+ myGroup=string.rstrip(GroupName)
+ msg= "-%s-%s-" % (myGroup,myParam)
+ if myGroup == "POINT":
+ if myParam== "LABELS":
+ # named in form of subject:marker.
+ # the list "empties" is a corresponding list of actual empty object names that make up the cloud
+ markerList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ debug(0, "%sLABELS = %i %s" %(msg, len(markerList),markerList)) #list of logical markers from 0 to n corresponding to points
+ elif myParam== "LABELS2": #more labels
+ # named in form of subject:marker.
+ # the list "empties" is a corresponding list of actual empty object names that make up the cloud
+ momarkList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ markerList+=momarkList
+ debug(0, "%sLABELS2 = %i %s" %(msg, len(momarkList),momarkList)) #list of logical markers from 0 to n corresponding to points
+ else: debug(70, "%s UNUSED = %s" %(msg,ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data))
+ elif myGroup in ["SUBJECT", "SUBJECTS"]: #info about the actor
+ if myParam in ["NAME", "NAMES"]:
+ subjects= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ debug(0, "%sNames of Subjects = %s" %(msg, subjects)) # might be useful in naming armatures
+ for i in range(len(subjects)):
+ subjects[i]=subjects[i].rstrip()
+ if subjects[i]=="": subjects[i]="Human"
+ elif myParam == "LABEL_PREFIXES":
+ prefixes = ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ debug(0, "%sMarker Prefixes = %s" %(msg, prefixes)) # to xlate marker name to that in file
+ for i in range(len(prefixes)):
+ prefixes[i]=prefixes[i].rstrip()
+ elif myParam== "MARKER_SETS":
+ marker_subjects= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ debug(0, "%sMarker Set = %s"%(msg, marker_subjects)) # marker set that each subject was wearing
+ elif myParam== "MODEL_PARAM":
+ action= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ debug(0, "%sModel Paramter = %s"%(msg,action)) # might be a good name for the blender scene
+ elif myParam== "LABELS":
+ # named in form of subject:marker.
+ # the list "empties" is a corresponding list of actual empty object names that make up the cloud
+ markerList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ debug(0, "%sLABELS = %i %s"%(msg, len(markerList),markerList)) #list of logical markers from 0 to n corresponding to points
+ else: debug(70, "%sUNUSED = %s"%(msg, ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data))
+ else:
+ debug(70, "%sUNUSED = %s"%(msg, ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data))
+ elif type == 1:
+ debug(100,"Block type %i is largely unsupported and untested."%type)
+ data = []
+ Nparameters=datalength/abs(type)
+ debug(100, "Nparameters=%i"%Nparameters)
+ for i in range(Nparameters):
+ ladata,content = getNumber(content, 1)
+ data.append(ladata)
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data
+ #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+
+ #print "type boolean"
+ elif type == 2 and datalength>0:
+ debug(100,"Block type %i is largely unsupported and untested."%type)
+ data = []
+ Nparameters=datalength/abs(type)
+ debug(100, "Nparameters=%i"%Nparameters)
+ for i in range(Nparameters):
+ ladata,content = getNumber(content, 2)
+ data.append(ladata)
+ #ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data
+ if dimnum>1:
+ #???? print "arg je comprends pas"
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data
+ #???ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=reshape(data,dimension)
+ else:
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data
+ #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ #pass
+ #print "type integer"
+ elif type == 4 and datalength>0:
+ debug(100,"Block type %i is largely unsupported and untested."%type)
+ data = []
+ Nparameters=datalength/abs(type)
+ debug(100, "Nparameters=%i"%Nparameters)
+ for i in range(Nparameters):
+ ladata,content = getFloat(content,proctype)
+ data.append(ladata)
+ if dimnum>1:
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data
+ #print "arg je comprends pas"
+ #???ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=reshape(data,dimension)
+ else:
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data
+ #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data
+ else:
+ debug(100,"Block type %i is largely unsupported and untested."%type)
+ #print "error"
+ pass
+ deschars, content= getNumber(content, 1)
+ if deschars>0:
+ description = content[0:deschars]
+ content = content[deschars:]
+ ParameterGroups[GroupNumber].parameter[ParameterNumber-1].description=description
+
+ content = content_memory
+ content = content[nextrec:]
+
+ Ncharacters,content = getNumber(content, 1)
+ if Ncharacters>=128:
+ Ncharacters = -(2**8)+(Ncharacters)
+ GroupNumber,content = getNumber(content, 1)
+ if GroupNumber>=128:
+ GroupNumber = -(2**8)+(GroupNumber)
+ debug(80,"GroupNumber = %i, Nchar=%i" %(GroupNumber,Ncharacters))
+
+ debug(00, "***************************")
+ debug(00, "**** Examining Parameters ...")
+ debug(10, "***************************")
+
+ if len(subjects)==0: subjects=["Test"] #well, somebody got mocapped!
+ for i in range(0, len(subjects)-len(prefixes)): prefixes.append("")
+ for i in range(0, len(subjects)-len(marker_subjects)): marker_subjects.append(subjects[i])
+
+ #make a markerlist if they didn't
+ debug(0, "%i Markers specified, %i marker names supplied" %(Nmarkers,len(markerList)))
+ if len(markerList)==0:
+ debug(0, "File missing any POINT LABELS marker list. Making defaults")
+ #I guess just make cloud of empty.xxx
+ if len(markerList)<Nmarkers:
+ for i in range(len(markerList),Nmarkers): markerList.append("mark."+str(i))
+ #note that they may supply more markers than Nmarkers, extras are usually null or ignored
+ #an idea here to winnow down the marker List is to go through the nodes and see if there are markers
+ # in the list that are not used in constraining the armature, and discard them or set them debug(0,
+ # so that later on in processing we don't bother saving their location, possibly speeding up processing
+ # because we can just skip over their data block.
+ # put this on TODO list since it gets pretty complicated going throuch each marker set and all constraints etc.
+
+ ## ###############################################
+ ## ## ##
+ ## ## Initalize Arrays and Allocate Memory
+ ## ## ##
+ ## ###############################################
+ ## Get the coordinate and analog data
+ #
+
+ content = content_memory
+ content = content[(NrecordDataBlock-1)*512:]
+ debug(20,"Allocating memory for %i floats" %NvideoFrames*(Nmarkers*3+2))
+ for i in range (NvideoFrames):
+ Markers.append([])
+ ResidualError.append([])
+ CameraInfo.append([])
+ for j in range (Nmarkers):
+ Markers[i].append(Marker(0.0,0.0,0.0))
+ ResidualError[i].append(0)
+ CameraInfo[i].append(0)
+
+ #print Markers
+ #
+ #if Scale < 0
+ # for i=1:NvideoFrames
+ # for j=1:Nmarkers
+ # Markers(i,j,1:3)=fread(fid,3,'float32')';
+ # a=fix(fread(fid,1,'float32'));
+ # highbyte=fix(a/256);
+ # lowbyte=a-highbyte*256;
+ # CameraInfo(i,j)=highbyte;
+ # ResidualError(i,j)=lowbyte*abs(Scale);
+ # end
+ # waitbar(i/NvideoFrames)
+ # for j=1:NanalogFramesPerVideoFrame,
+ # AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=...
+ # fread(fid,NanalogChannels,'int16')';
+ # end
+ # end
+
+ debug(10, "***************************")
+ debug(00, "**** Reading DataBlock of %i Frames...." % NvideoFrames)
+ debug(10, "***************************")
+ residuals= NanalogFramesPerVideoFrame*NanalogChannels*2
+ err=0 #keep track of errors or serious data issues
+ ptr_read = 0
+
+ if Scale < 0.0: # 3D Data - 4-byte Floating-point Format
+ for i in range (NvideoFrames):
+ if i==0: start=sys.time()
+ elif i==10:
+ tmp=(sys.time()-start)*NvideoFrames/600
+ debug(0,"%i minutes remaining..." % tmp)
+ else: print "%i percent complete. On Frame %i Points procesed: %i\r" % (i*100/NvideoFrames,i,i*Nmarkers),
+ for j in range (Nmarkers):
+
+ x,ptr_read = parseFloat(content, ptr_read, proctype)
+ y,ptr_read = parseFloat(content, ptr_read, proctype)
+ z,ptr_read = parseFloat(content, ptr_read, proctype)
+ myx= x * -Scale
+ myy= y * -Scale
+ myz= z * -Scale
+
+ if abs(myx)>XYZ_LIMIT or abs(myy)>XYZ_LIMIT or abs(myz)>XYZ_LIMIT:
+ err+=1
+ if err>100:
+ debug(0, "Warning: 100 data points for markers seem way out there")
+ debug(0, "data read: (%i, %i, %i)" %(x,y,z))
+ debug(0, "Consider revising Scale %0.2f" % Scale)
+ debug(0, "which now givs coordinates: (%i, %i, %i)" %(x*Scale,y*Scale,z*Scale))
+ err=-0
+ if abs(myx)>XYZ_LIMIT: myx= XYZ_LIMIT*myx/abs(myx) #preserve sign
+ if abs(myy)>XYZ_LIMIT: myy= XYZ_LIMIT*myy/abs(myy) #preserve sign
+ if abs(myz)>XYZ_LIMIT: myz= XYZ_LIMIT*myz/abs(myz) #preserve sign
+ Markers[i][j].x = myx
+ Markers[i][j].y = myy
+ Markers[i][j].z = myz
+
+ a,ptr_read = parseFloat(content, ptr_read, proctype)
+ a = int(a)
+ highbyte = int(a/256)
+ lowbyte=a-highbyte*256
+ CameraInfo[i][j] = highbyte
+ ResidualError[i][j] = lowbyte*abs(Scale)
+ #Monitor marker location to ensure data block is being parsed properly
+ if j==0: debug(90,"Frame %i loc of %s: (%i, %i, %i)" % (i,markerList[j],myx,myy,myz))
+ if i==0: debug(50, "Initial loc of %s: (%i, %i, %i)" % (markerList[j],myx,myy,myz))
+
+ ptr_read+=residuals #skip over the following
+ #for j in range (NanalogFramesPerVideoFrame):
+ # for k in range(NanalogChannels):
+ # val, content = getNumber(content, 2)
+ # AnalogSignals[j+NanalogFramesPerVideoFrame*(i)][k]=val #??? i-1
+ #else
+ # for i=1:NvideoFrames
+ # for j=1:Nmarkers
+ # Markers(i,j,1:3)=fread(fid,3,'int16')'.*Scale;
+ # ResidualError(i,j)=fread(fid,1,'int8');
+ # CameraInfo(i,j)=fread(fid,1,'int8');
+ # end
+ # waitbar(i/NvideoFrames)
+ # for j=1:NanalogFramesPerVideoFrame,
+ # AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=...
+ # fread(fid,NanalogChannels,'int16')';
+ # end
+ # end
+ #end
+
+ else: #Scale is positive, but should be <1 to scale down, like 0.05
+ two16= -2**16
+ if len(content) < NvideoFrames*(Nmarkers*(6+2)+residuals):
+ error("%i bytes is not enough data for |%i frames|%i markers|%i residual" %(len(content),NvideoFrames,Nmarkers,residuals))
+ #Note: I really tried to optimize this loop, since it was taking hours to process
+ for i in range(NvideoFrames):
+ if i==0: start=sys.time()
+ elif i==10:
+ tmp=(sys.time()-start)*NvideoFrames/600
+ debug(0,"%i minutes remaining..." % tmp)
+ else: print "%i percent complete. On Frame %i Points procesed: %i\r" % (i*100/NvideoFrames,i,i*Nmarkers),
+
+ for j in range(Nmarkers):
+ #x, content = getNumber(content,2)
+ # this is old skool signed int, not but not a short.
+ x = ord(content[ptr_read+0]) + (ord(content[ptr_read+1])<<8)
+ if x>32768: x+=two16
+ y = ord(content[ptr_read+2]) + (ord(content[ptr_read+3])<<8)
+ if y>32768: y+=two16
+ z = ord(content[ptr_read+4]) + (ord(content[ptr_read+5])<<8)
+ if z>32768: z+=two16
+
+##
+## x = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8)
+## ptr_read+=2
+## if x > 32768:
+## x=-(2**16)+(x)
+## #y, content = getNumber(content,2)
+## y = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8)
+## ptr_read+=2
+## if y > 32768:
+## y=-(2**16)+(y)
+## #z, content = getNumber(content,2)
+## z = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8)
+## ptr_read+=2
+## if z > 32768:
+## z=-(2**16)+(z)
+##
+## print "(%i=%i, %i=%i, %i=%i)" %(x,myx,y,myy,z,myz)
+
+ # for integers, I changed Scale above to avoid getting impossible numbers
+ Markers[i][j].x = x*Scale
+ Markers[i][j].y = y*Scale
+ Markers[i][j].z = z*Scale
+
+## ResidualError[i][j], content = getNumber(content, 1)
+## CameraInfo[i][j], content = getNumber(content, 1)
+ #try to improve performance by:
+ ResidualError[i][j]= ord(content[ptr_read+6])
+ CameraInfo[i][j]= ord(content[ptr_read+7])
+
+ content= content[ptr_read+8:]
+ ptr_read=0
+
+ if j==0: debug(100,"Frame %i loc of %s: %s" % (i,markerList[j],Markers[i][j]))
+ if i==0: debug(50, "Initial loc of %s: (%s)" % (markerList[j],Markers[i][j]))
+
+ #for j in range (NanalogFramesPerVideoFrame):
+ # for k in range(NanalogChannels):
+ # val, content = getNumber(content, 2)
+ #AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=val
+ ptr_read= residuals # skip over the above
+ print "\ndone with file."
+ fid.close()
+
+ cloud= makeCloud(Nmarkers,markerList,StartFrame,EndFrame,Markers)
+
+ setupAnim(StartFrame, EndFrame,VideoFrameRate)
+
+ debug(10, "**************************")
+ debug(00, "**** Making %i Armatures" % len(subjects))
+ debug(10, "**************************")
+ for i in range(len(subjects)):
+ marker_set= marker_subjects[i]
+ success=False
+ if len(marker_set)>0:
+ for trymark in MARKER_SETS:
+ if trymark[0:len(marker_set)]==marker_set:
+ marker_set=trymark
+ success=True
+ if success:
+ debug(0, "Armature for %s will be put on layers %s" % (subjects[i],LAYERS_ARMOB))
+ debug(0, " based on an markers beginning with %s" % prefixes[i])
+ ob= make_arm(subjects[i],prefixes[i],markerList,cloud,marker_set)
+ else:
+ debug(00, "Presently, this program can automatically create a constrained armature for marker sets %s" % MARKER_SETS)
+ debug(00, "%s uses an unknown marker set %s" % (subjects[i],marker_set))
+ debug(10, "Have a nice day! If you figure out an armature node system for this cloud, please add it to the program.")
+
+ debug(10, "**************************")
+ debug(00, "**** Conclusion")
+ minmax=[0,0,0,0,0,0]
+ for i in range(NvideoFrames):
+ for j in range(Nmarkers):
+ if minmax[0]>Markers[i][j].x: minmax[0]=Markers[i][j].x
+ if minmax[1]>Markers[i][j].y: minmax[1]=Markers[i][j].y
+ if minmax[2]>Markers[i][j].z: minmax[2]=Markers[i][j].z
+ if minmax[3]<Markers[i][j].x: minmax[3]=Markers[i][j].x
+ if minmax[4]<Markers[i][j].y: minmax[4]=Markers[i][j].y
+ if minmax[5]<Markers[i][j].z: minmax[5]=Markers[i][j].z
+ debug(0,"Markers move in 3D space from (%i,%i,%i) to (%i,%i,%i). "%(minmax[0],minmax[1],minmax[2],minmax[3],minmax[4],minmax[5]))
+ debug(0,"Set your 3D View Properties Clip End and zoom out your display.")
+def my_callback(filename):
+ # processing options UI goes here, eventually
+ Window.WaitCursor(1)
+ t = sys.time()
+ load_c3d(filename)
+ # Timing the script is a good way to be aware on any speed hits when scripting
+ debug(0, '%s file processed in %.2f sec.' % (filename,sys.time()-t))
+ Window.WaitCursor(0)
+
+def processFile():
+ # select file and pass a handle to the processor
+ Blender.Window.FileSelector(my_callback, "Import C3D") # makes a window a file selector and processes it
+ #processing contiues while file is being worked
+
+def main():
+ # Display the GUI
+
+ # Run the function
+ processFile()
+
+ #Close files, display stats, cleanup, advice on next steps
+
+# This lets you import the script without running it
+if __name__ == '__main__':
+ debug(00, "------------------------------------")
+ debug(00, '%s %s script began at %.0f' % (__script__,__version__,sys.time()))
+ main()
+
+
+
diff --git a/release/scripts/ms3d_import.py b/release/scripts/ms3d_import.py
index 78ffbb92847..c1438cbfc97 100644
--- a/release/scripts/ms3d_import.py
+++ b/release/scripts/ms3d_import.py
@@ -50,7 +50,7 @@ def RM(a):
cp = cos(a[1])
sr = sin(a[0])
cr = cos(a[0])
- return Matrix([cp*cy, sr*sp*cy+cr*-sy, cr*sp*cy+-sr*-sy],[cp*sy, sr*sp*sy+cr*cy, cr*sp*sy+-sr*cy], [-sp, sr*cp, cr*cp])
+ return Matrix([cp*cy, cp*sy, -sp], [sr*sp*cy+cr*-sy, sr*sp*sy+cr*cy, sr*cp],[cr*sp*cy+-sr*-sy, cr*sp*sy+-sr*cy, cr*cp])
# Converts ms3d euler angles to a quaternion
@@ -94,7 +94,12 @@ def import_ms3d(path):
except IOError:
return "Failed to open the file!"
- # read id
+ # get the file size
+ file.seek(0, os.SEEK_END);
+ fileSize = file.tell();
+ file.seek(0, os.SEEK_SET);
+
+ # read id to check if the file is a MilkShape3D file
id = file.read(10)
if id!="MS3D000000":
return "The file is not a MS3D file!"
@@ -123,7 +128,7 @@ def import_ms3d(path):
coords.append(struct.unpack("fff", file.read(3*4)))
# read bone ids
- boneIds.append(struct.unpack("B", file.read(1))[0])
+ boneIds.append(struct.unpack("b", file.read(1))[0])
# skip refcount
file.read(1)
@@ -190,9 +195,10 @@ def import_ms3d(path):
triangleIndices = struct.unpack(str(numGroupTriangles) + "H", file.read(2*numGroupTriangles));
# read material
- material = struct.unpack("B", file.read(1))[0]
- for j in xrange(numGroupTriangles):
- mesh.faces[triangleIndices[j]].mat = material
+ material = struct.unpack("b", file.read(1))[0]
+ if material>=0:
+ for j in xrange(numGroupTriangles):
+ mesh.faces[triangleIndices[j]].mat = material
# read the number of materials
numMaterials = struct.unpack("H", file.read(2))[0]
@@ -224,7 +230,6 @@ def import_ms3d(path):
# read shininess
shininess = struct.unpack("f", file.read(4))[0]
- print "Shininess: " + str(shininess)
# read transparency
transparency = struct.unpack("f", file.read(4))[0]
@@ -272,6 +277,7 @@ def import_ms3d(path):
armature.makeEditable()
# read joints
+ joints = []
rotKeys = {}
posKeys = {}
for i in xrange(numJoints):
@@ -280,6 +286,7 @@ def import_ms3d(path):
# read name
name = uku(file.read(32))
+ joints.append(name)
# create the bone
bone = Blender.Armature.Editbone()
@@ -295,11 +302,13 @@ def import_ms3d(path):
# read position
pos = struct.unpack("fff", file.read(3*4))
-
+
# set head
if bone.hasParent():
- bone.head = bone.parent.matrix * Vector(pos) + bone.parent.head
- bone.matrix = bone.parent.matrix * RM(rot)
+ bone.head = Vector(pos) * bone.parent.matrix + bone.parent.head
+ tempM = RM(rot) * bone.parent.matrix
+ tempM.transpose;
+ bone.matrix = tempM
else:
bone.head = Vector(pos)
bone.matrix = RM(rot)
@@ -355,13 +364,111 @@ def import_ms3d(path):
# create position keys
for key in posKeys[name]:
pbone.loc = Vector(key[1])
- pbone.insertKey(armOb, int(key[0]), Blender.Object.Pose.LOC, True)
+ pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.LOC, True)
# create rotation keys
for key in rotKeys[name]:
pbone.quat = RQ(key[1])
- pbone.insertKey(armOb, int(key[0]), Blender.Object.Pose.ROT, True)
+ pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.ROT, True)
+
+ # The old format ends here. If there is more data then the file is newer version
+
+ # check to see if there are any comments
+ if file.tell()<fileSize:
+
+ # read sub version
+ subVersion = struct.unpack("i", file.read(4))[0]
+
+ # Is the sub version a supported one
+ if subVersion==1:
+
+ # Group comments
+ numComments = struct.unpack("i", file.read(4))[0]
+ for i in range(numComments):
+ file.read(4) # index
+ size = struct.unpack("i", file.read(4))[0] # comment size
+ if size>0:
+ print "Group comment: " + file.read(size)
+
+ # Material comments
+ numComments = struct.unpack("i", file.read(4))[0]
+ for i in range(numComments):
+ file.read(4) # index
+ size = struct.unpack("i", file.read(4))[0] # comment size
+ if size>0:
+ print "Material comment: " + file.read(size)
+
+ # Joint comments
+ numComments = struct.unpack("i", file.read(4))[0]
+ for i in range(numComments):
+ file.read(4) # index
+ size = struct.unpack("i", file.read(4))[0] # comment size
+ if size>0:
+ print "Joint comment: " + file.read(size)
+
+ # Model comments
+ numComments = struct.unpack("i", file.read(4))[0]
+ for i in range(numComments):
+ file.read(4) # index
+ size = struct.unpack("i", file.read(4))[0] # comment size
+ if size>0:
+ print "Model comment: " + file.read(size)
+
+ # Unknown version give a warning
+ else:
+ print "Warning: Unknown version!"
+
+
+ # check to see if there is any extra vertex data
+ if file.tell()<fileSize:
+
+ # read the subversion
+ subVersion = struct.unpack("i", file.read(4))[0]
+
+ # is the version supported
+ if subVersion==2:
+ # read the extra data for each vertex
+ for i in xrange(numVertices):
+ # bone ids
+ ids = struct.unpack("bbb", file.read(3))
+ # weights
+ weights = struct.unpack("BBB", file.read(3))
+ # extra
+ extra = struct.unpack("I", file.read(4))
+ # add extra vertices with weights to deform groups
+ if ids[0]>=0 or ids[1]>=0 or ids[2]>=0:
+ mesh.assignVertsToGroup(joints[boneIds[i]], [i], 0.01*weights[0], 1)
+ if ids[0]>=0:
+ mesh.assignVertsToGroup(joints[ids[0]], [i], 0.01*weights[1], 1)
+ if ids[1]>=0:
+ mesh.assignVertsToGroup(joints[ids[1]], [i], 0.01*weights[2], 1)
+ if ids[2]>=0:
+ mesh.assignVertsToGroup(joints[ids[2]], [i], 0.01*(100-(weights[0]+weights[1]+weights[2])), 1)
+
+ elif subVersion==1:
+ # read extra data for each vertex
+ for i in xrange(numVertices):
+ # bone ids
+ ids = struct.unpack("bbb", file.read(3))
+ # weights
+ weights = struct.unpack("BBB", file.read(3))
+ # add extra vertices with weights to deform groups
+ if ids[0]>=0 or ids[1]>=0 or ids[2]>=0:
+ mesh.assignVertsToGroup(joints[boneIds[i]], [i], 0.01*weights[0], 1)
+ if ids[0]>=0:
+ mesh.assignVertsToGroup(joints[ids[0]], [i], 0.01*weights[1], 1)
+ if ids[1]>=0:
+ mesh.assignVertsToGroup(joints[ids[1]], [i], 0.01*weights[2], 1)
+ if ids[2]>=0:
+ mesh.assignVertsToGroup(joints[ids[2]], [i], 0.01*(100-(weights[0]+weights[1]+weights[2])), 1)
+
+ # non supported subversion give a warning
+ else:
+ print "Warning: Unknown subversion!"
+ # rest of the extra data in the file is not imported/used
+
+ # refresh the view
Blender.Redraw()
# close the file
@@ -378,4 +485,3 @@ def fileCallback(filename):
Blender.Draw.PupMenu("An error occured during import: " + error + "|Not all data might have been imported succesfully.", 2)
Blender.Window.FileSelector(fileCallback, 'Import')
-
diff --git a/release/scripts/vrml97_export.py b/release/scripts/vrml97_export.py
index eb3be80c99c..b28c7f5bbdc 100644
--- a/release/scripts/vrml97_export.py
+++ b/release/scripts/vrml97_export.py
@@ -3,9 +3,6 @@
Name: 'VRML97 (.wrl)...'
Blender: 241
Group: 'Export'
-Submenu: 'All Objects...' all
-Submenu: 'All Objects compressed...' comp
-Submenu: 'Selected Objects...' selected
Tooltip: 'Export to VRML97 file (.wrl)'
"""
@@ -55,7 +52,7 @@ want to export only selected or all relevant objects.
import Blender
from Blender import Object, Mesh, Lamp, Draw, BGL, \
- Image, Text, sys, Mathutils
+ Image, Text, sys, Mathutils, Registry
from Blender.Scene import Render
import math
@@ -70,8 +67,9 @@ worldmat = Blender.Texture.Get()
filename = Blender.Get('filename')
_safeOverwrite = True
extension = ''
-ARG=''
+# Matrices below are used only when export_rotate_z_to_y.val:
+#
# Blender is Z up, VRML is Y up, both are right hand coordinate
# systems, so to go from Blender coords to VRML coords we rotate
# by 90 degrees around the X axis. In matrix notation, we have a
@@ -456,6 +454,8 @@ class VRML2Export:
if mat:
if (mat.mode & Blender.Material.Modes['VCOL_PAINT']):
self.vcolors = 1
+ else:
+ self.vcolors = 0
# check if object is wireframe only
if ob.drawType == Blender.Object.DrawTypes.WIRE:
@@ -633,8 +633,9 @@ class VRML2Export:
meshVertexList = me.verts
for vertex in meshVertexList:
- blenvert = Mathutils.Vector(vertex.co)
- vrmlvert = M_blen2vrml * blenvert
+ vrmlvert = blenvert = Mathutils.Vector(vertex.co)
+ if export_rotate_z_to_y.val:
+ vrmlvert = M_blen2vrml * vrmlvert
self.writeUnindented("%s %s %s\n " % \
(vrmlvert[0], \
vrmlvert[1], \
@@ -730,8 +731,8 @@ class VRML2Export:
round(uv[1], self.tp))
j=j+1
indexStr += "-1"
- texIndexList.append(indexStr)
- texCoordList.append(coordStr)
+ texIndexList.append(indexStr)
+ texCoordList.append(coordStr)
self.writeIndented("texCoord TextureCoordinate {\n", 1)
self.writeIndented("point [\n", 1)
@@ -1016,7 +1017,10 @@ class VRML2Export:
return
ob_matrix = Mathutils.Matrix(ob.getMatrix('worldspace'))
- matrix = M_blen2vrml * ob_matrix * M_vrml2blen
+ if export_rotate_z_to_y.val:
+ matrix = M_blen2vrml * ob_matrix * M_vrml2blen
+ else:
+ matrix = ob_matrix
e = matrix.rotationPart().toEuler()
v = matrix.translationPart()
@@ -1089,7 +1093,7 @@ class VRML2Export:
self.writeFog()
self.proto = 0
allObj = []
- if ARG == 'selected':
+ if export_selection_only.val:
allObj = list(scene.objects.context)
else:
allObj = list(scene.objects)
@@ -1098,7 +1102,7 @@ class VRML2Export:
for thisObj in allObj:
self.writeObject(thisObj)
- if ARG != 'selected':
+ if not export_selection_only.val:
self.writeScript()
self.cleanup()
@@ -1213,26 +1217,54 @@ def select_file(filename):
wrlexport=VRML2Export(filename)
wrlexport.export(scene, world, worldmat)
+#########################################################
+# UI and Registry utilities
+#########################################################
+
+export_selection_only = Draw.Create(0)
+export_rotate_z_to_y = Draw.Create(1)
+export_compressed = Draw.Create(0)
+
+def save_to_registry():
+ d = {}
+ d['selection_only'] = export_selection_only.val
+ d['rotate_z_to_y'] = export_rotate_z_to_y.val
+ d['compressed'] = export_compressed.val
+ Registry.SetKey('vrml97_export', d, True)
+
+def load_from_registry():
+ d = Registry.GetKey('vrml97_export', True)
+ if d:
+ try:
+ export_selection_only.val = d['selection_only']
+ export_rotate_z_to_y.val = d['rotate_z_to_y']
+ export_compressed.val = d['compressed']
+ except: save_to_registry() # If data is not valid, rewrite it.
+
+def show_popup():
+ pup_block = [
+ ('Selection Only', export_selection_only, 'Only export objects in visible selection. Else export whole scene.'),
+ ('Rotate +Z to +Y', export_rotate_z_to_y, 'Rotate such that +Z axis (Blender up) becomes +Y (VRML up).'),
+ ('Compress', export_compressed, 'Generate a .wrz file (normal VRML compressed by gzip).')
+ ]
+ return Draw.PupBlock('Export VRML 97...', pup_block)
#########################################################
# main routine
#########################################################
-try:
- ARG = __script__['arg'] # user selected argument
-except:
- print "older version"
-
-if Blender.Get('version') < 235:
- print "Warning: VRML97 export failed, wrong blender version!"
- print " You aren't running blender version 2.35 or greater"
- print " download a newer version from http://blender3d.org/"
-else:
- if ARG == 'comp':
+load_from_registry()
+
+# Note that show_popup must be done before Blender.Window.FileSelector,
+# because export_compressed affects the suggested extension of resulting
+# file.
+
+if show_popup():
+ save_to_registry()
+ if export_compressed.val:
extension=".wrz"
from gzip import *
else:
extension=".wrl"
Blender.Window.FileSelector(select_file, "Export VRML97", \
sys.makename(ext=extension))
-
diff --git a/release/windows/installer/00.sconsblender.nsi b/release/windows/installer/00.sconsblender.nsi
index 338075c1b18..c96b188fb02 100644
--- a/release/windows/installer/00.sconsblender.nsi
+++ b/release/windows/installer/00.sconsblender.nsi
@@ -353,6 +353,7 @@ Section "Blender-VERSION (required)" SecCopyUI
SetOutPath $INSTDIR
; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\BlenderFoundation "Install_Dir" "$INSTDIR"
+ WriteRegStr HKLM SOFTWARE\BlenderFoundation "Home_Dir" "$BLENDERHOME"
; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" "DisplayName" "Blender (remove only)"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" "UninstallString" '"$INSTDIR\uninstall.exe"'
@@ -406,28 +407,32 @@ SectionEnd
UninstallText "This will uninstall Blender VERSION. Hit next to continue."
Section "Uninstall"
+ Delete $INSTDIR\uninstall.exe
+
+ ReadRegStr $BLENDERHOME HKLM "SOFTWARE\BlenderFoundation" "Home_Dir"
+
; remove registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender"
DeleteRegKey HKLM SOFTWARE\BlenderFoundation
; remove files
[DELROOTDIRCONTS]
- Delete $INSTDIR\.blender\.bfont.ttf
- Delete $INSTDIR\.blender\.Blanguages
+ Delete $BLENDERHOME\.blender\.bfont.ttf
+ Delete $BLENDERHOME\.blender\.Blanguages
; remove shortcuts, if any.
Delete "$SMPROGRAMS\Blender Foundation\Blender\*.*"
Delete "$DESKTOP\Blender.lnk"
; remove directories used.
- RMDir /r $INSTDIR\.blender\locale
+ RMDir /r $BLENDERHOME\.blender\locale
MessageBox MB_YESNO "Erase .blender\scripts folder? (ALL contents will be erased!)" IDNO Next
- RMDir /r $INSTDIR\.blender\scripts
- RMDir /r $INSTDIR\.blender\scripts\bpymodules
- RMDir /r $INSTDIR\.blender\scripts\bpydata
- RMDir /r $INSTDIR\.blender\scripts\bpydata\config
+ RMDir /r $BLENDERHOME\.blender\scripts
+ RMDir /r $BLENDERHOME\.blender\scripts\bpymodules
+ RMDir /r $BLENDERHOME\.blender\scripts\bpydata
+ RMDir /r $BLENDERHOME\.blender\scripts\bpydata\config
Next:
- RMDir /r $INSTDIR\plugins\include
- RMDir /r $INSTDIR\plugins
- RMDir $INSTDIR\.blender
+ RMDir /r $BLENDERHOME\plugins\include
+ RMDir /r $BLENDERHOME\plugins
+ RMDir $BLENDERHOME\.blender
RMDir "$SMPROGRAMS\Blender Foundation\Blender"
RMDir "$SMPROGRAMS\Blender Foundation"
RMDir "$INSTDIR"