From 859959b49c8122b1e37027cf5009fecd23f5d8c8 Mon Sep 17 00:00:00 2001 From: Willian Padovani Germano Date: Tue, 17 May 2005 07:17:52 +0000 Subject: BPython: - fixing bug reported by Paolo Colombo: space handler slinks set for a 3d view were not set when the area got maximized; - Blender.Object: added object.isSB() method to know if an object is a soft body (has ob->soft != NULL). Used in fixfromarmature.py. Scripts: - updates: batch_name_edit (Campbell), fixfromarmature (JMS); - additions: X3D exporter by Bart; Envelope Suite by Jonas Petersen; BVH 2 Armature by Jean-Baptiste Perin; Camera Changer by Regis Montoya (3R); Interactive Console by Campbell (ideasman). - tiny updates in other scripts. --- release/scripts/armature_symetry.py | 197 ++++++ release/scripts/batch_name_edit.py | 134 ++-- release/scripts/bpymodules/BPyNMesh.py | 48 ++ release/scripts/bvh2arm.py | 693 +++++++++++++++++++++ release/scripts/bvh_import.py | 5 +- release/scripts/camera_changer.py | 95 +++ release/scripts/console.py | 517 ++++++++++++++++ release/scripts/envelope_assignment.py | 234 +++++++ release/scripts/envelope_symmetry.py | 176 ++++++ release/scripts/fixfromarmature.py | 74 ++- release/scripts/knife.py | 2 +- release/scripts/save_theme.py | 6 +- release/scripts/vrml97_export.py | 2 +- release/scripts/x3d_export.py | 1045 ++++++++++++++++++++++++++++++++ 14 files changed, 3128 insertions(+), 100 deletions(-) create mode 100644 release/scripts/armature_symetry.py create mode 100644 release/scripts/bpymodules/BPyNMesh.py create mode 100644 release/scripts/bvh2arm.py create mode 100644 release/scripts/camera_changer.py create mode 100644 release/scripts/console.py create mode 100644 release/scripts/envelope_assignment.py create mode 100644 release/scripts/envelope_symmetry.py create mode 100644 release/scripts/x3d_export.py (limited to 'release') diff --git a/release/scripts/armature_symetry.py b/release/scripts/armature_symetry.py new file mode 100644 index 00000000000..be4f109ccce --- /dev/null +++ b/release/scripts/armature_symetry.py @@ -0,0 +1,197 @@ +#!BPY + +""" +Name: 'Armature Symmetry' +Blender: 234 +Group: 'Animation' +Tooltip: 'Make an armature symetrical' +""" + +__author__ = "Jonas Petersen" +__url__ = ("blender", "elysiun", "Script's homepage, http://www.mindfloaters.de/blender/", "thread at blender.org, http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4858") +__version__ = "0.9 2004-11-10" + +__doc__ = """\ +This script creates perfectly symmetrical armatures. + +With default configuration it will:
+ - Look for bones that have the reference suffix (".L") and +adjust/create the according opposite bone (suffix ".R");
+ - Center align all bones that _don't_ have the suffix ".X". + +Please check the script's homepage and the thread at blender.org (last link button above) for more info. + +For this version users need to edit the script code to change default options. +""" + +# -------------------------------------------------------------------------- +# "Armature Symmetry" by Jonas Petersen +# Version 0.9 - 10th November 2004 - first public release +# -------------------------------------------------------------------------- +# +# A script for creating perfectly symmetrical armatures. +# +# It is available in Object Mode via the menu item: +# +# Object -> Scripts -> Armature Symmetry +# +# With default configuration it will: +# +# - Look for bones that have the reference suffix (".L") and +# adjust/create the according opposite bone (suffix ".R"). +# +# - Center align all bones that _don't_ have the suffix ".X" +# +# Find the latest version at: http://www.mindfloaters.de/blender/ +# +# -------------------------------------------------------------------------- +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Jonas Petersen, jonas at mindfloaters dot de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +# -------------------------------------------------------------------------- +# CONFIGURATION +# -------------------------------------------------------------------------- + +# Note: Theses values will later be editable via a gui interface +# within Blender. + +# CENTER_SUFFIX is the suffix for bones that should (or shouldn't) get +# center aligned. The default is '.X'. +CENTER_SUFFIX = '.X' + +# CENTER_SUFFIX_MODE: +# +# 'include' only bones with the CENTER_SUFFIX appended +# get center aligned. +# +# 'exclude' (default) +# all bones except those with the CENTER_SUFFIX +# appended get center aligned. +# +# +# 'off' bones will not get center aligned at all. +# +CENTER_SUFFIX_MODE = 'exclude' + +# The suffix for the reference and opposite side of the +# armature. Bone positions of the opposite side will be overwritten by +# the mirrored values of the reference side. +# The default is REF_SUFFIX = '.L' and OPP_SUFFIX = '.R'. +REF_SUFFIX = '.L' +OPP_SUFFIX = '.R' + +# MIRROR_AXIS defines the axis in which bones are mirrored/aligned. +# Values: +# 0 for X (default) +# 1 for Y +# 2 for Z +MIRROR_AXIS = 0 + +# -------------------------------------------------------------------------- +# END OF CONFIGURATION +# -------------------------------------------------------------------------- + +import Blender + +def splitName(bone): + name = bone.getName() + base = name[0:len(name)-ref_suffix_len] + rsuff = name[-ref_suffix_len:len(name)] + csuff = name[-center_suffix_len:len(name)] + return name, base, rsuff, csuff + +ref_suffix_len = len(REF_SUFFIX); +center_suffix_len = len(CENTER_SUFFIX); +armature_selected = False + +obj_list = Blender.Object.GetSelected() +for obj in obj_list: + if obj.getType() == "Armature": + armature_selected = True + arm = obj.getData() + bones = arm.getBones() + bonehash = {} + + for bone in bones: + bonehash[bone.getName()] = bone + + for bone in bones: + name, base, rsuff, csuff = splitName(bone) + + # reference bone? + if (rsuff == REF_SUFFIX): + oppname = base + OPP_SUFFIX + + # create opposite bone if necessary + if not bonehash.has_key(oppname): + bonehash[oppname]=Blender.Armature.Bone.New(oppname) + parent = bone.getParent() + if parent: + pname, pbase, prsuff, pcsuff = splitName(parent) + if prsuff == REF_SUFFIX: + poppname = pbase + OPP_SUFFIX + if bonehash.has_key(poppname): + bonehash[oppname].setParent(bonehash[poppname]) + else: + bonehash[oppname].setParent(parent) + arm.addBone(bonehash[oppname]) + + # mirror bone coords + + tail = bone.getTail() + tail[MIRROR_AXIS] *= -1; + bonehash[oppname].setTail(tail) + + head = bone.getHead() + head[MIRROR_AXIS] *= -1; + bonehash[oppname].setHead(head) + + roll = -bone.getRoll() + bonehash[oppname].setRoll(roll) + + # Write access to ik flag not (yet?) supported in Blender (2.34) + #if bone.hasParent(): + # bonehash[oppname].setIK(not bone.getIK()) + + # center bone? + elif (rsuff != OPP_SUFFIX) and \ + (CENTER_SUFFIX_MODE != 'off') and \ + ((CENTER_SUFFIX_MODE == 'exclude' and csuff != CENTER_SUFFIX) or \ + (CENTER_SUFFIX_MODE == 'include' and csuff == CENTER_SUFFIX)): + + # center bone coords + + tail = bone.getTail() + tail[MIRROR_AXIS] = 0.0; + bone.setTail(tail) + + head = bone.getHead() + head[MIRROR_AXIS] = 0.0; + bone.setHead(head) + + # Setting set roll in python rotates all child bones. + # Not so if set via the Transform Properties in Blender. + # Bug? + bone.setRoll(0.0) + +if not armature_selected: + Blender.Draw.PupMenu("Armature Symmetry%t|Please select an Armature object!") diff --git a/release/scripts/batch_name_edit.py b/release/scripts/batch_name_edit.py index 175d33cb973..75d2294aa68 100644 --- a/release/scripts/batch_name_edit.py +++ b/release/scripts/batch_name_edit.py @@ -50,74 +50,82 @@ menu of the 3d View. from Blender import * -def new(): - newname = Draw.PupStrInput('Name: ', '', 32) - if newname == None: return - for ob in Object.GetSelected(): - ob.name = newname - -def replace(): - replace = Draw.PupStrInput('Replace: ', '', 32) - if replace == None: return - - with = Draw.PupStrInput('With: ', '', 32) - if with == None: return - - for ob in Object.GetSelected(): +def main(): + def new(): + newname = Draw.PupStrInput('Name: ', '', 32) + if newname == None: return + Window.WaitCursor(1) + for ob in Object.GetSelected(): + ob.name = newname - if replace in ob.name: - chIdx = ob.name.index(replace) + def replace(): + replace = Draw.PupStrInput('Replace: ', '', 32) + if replace == None: return + with = Draw.PupStrInput('With: ', '', 32) + if with == None: return + Window.WaitCursor(1) + for ob in Object.GetSelected(): + ob.name = ob.name.replace(replace, with) - # Remove the offending word and replace it with - 'with' - ob.name = ob.name[ :chIdx] + with + ob.name[chIdx + len(replace):] + # Use pythons replace, its better. + ''' + if replace in ob.name: + chIdx = ob.name.index(replace) + + # Remove the offending word and replace it with - 'with' + ob.name = ob.name[ :chIdx] + with + ob.name[chIdx + len(replace):] + ''' - -def prefix(): - prefix = Draw.PupStrInput('prefix: ', '', 32) - if prefix == None: return - for ob in Object.GetSelected(): - ob.name = prefix + ob.name - - -def suffix(): - suffix = Draw.PupStrInput('Suffix: ', '', 32) - if suffix == None: return + def prefix(): + prefix = Draw.PupStrInput('prefix: ', '', 32) + + if prefix == None: return + Window.WaitCursor(1) + for ob in Object.GetSelected(): + ob.name = prefix + ob.name - for ob in Object.GetSelected(): - ob.name = ob.name + suffix - -def truncate_start(): - truncate = Draw.PupIntInput('Truncate Start: ', 0, 0, 31) - if truncate != None: + + def suffix(): + suffix = Draw.PupStrInput('Suffix: ', '', 32) + if suffix == None: return + Window.WaitCursor(1) for ob in Object.GetSelected(): - ob.name = ob.name[truncate: ] - -def truncate_end(): - truncate = Draw.PupIntInput('Truncate End: ', 0, 0, 31) - if truncate == None: return + ob.name = ob.name + suffix - for ob in Object.GetSelected(): - ob.name = ob.name[ :-truncate] - - - - -name = "Selected Object Names%t|New Name|Replace Text|Add Prefix|Add Suffix|Truncate Start|Truncate End" -result = Draw.PupMenu(name) - -if result == -1: - pass -elif result == 1: - new() -elif result == 2: - replace() -elif result == 3: - prefix() -elif result == 4: - suffix() -elif result == 5: - truncate_start() -elif result == 6: - truncate_end() + def truncate_start(): + truncate = Draw.PupIntInput('Truncate Start: ', 0, 0, 31) + if truncate != None: + Window.WaitCursor(1) + for ob in Object.GetSelected(): + ob.name = ob.name[truncate: ] + + def truncate_end(): + truncate = Draw.PupIntInput('Truncate End: ', 0, 0, 31) + if truncate == None: return + Window.WaitCursor(1) + for ob in Object.GetSelected(): + ob.name = ob.name[ :-truncate] + + + name = "Selected Object Names%t|New Name|Replace Text|Add Prefix|Add Suffix|Truncate Start|Truncate End" + result = Draw.PupMenu(name) + + if result == -1: + pass + elif result == 1: + new() + elif result == 2: + replace() + elif result == 3: + prefix() + elif result == 4: + suffix() + elif result == 5: + truncate_start() + elif result == 6: + truncate_end() + + Window.WaitCursor(0) +main() diff --git a/release/scripts/bpymodules/BPyNMesh.py b/release/scripts/bpymodules/BPyNMesh.py new file mode 100644 index 00000000000..043d8514db9 --- /dev/null +++ b/release/scripts/bpymodules/BPyNMesh.py @@ -0,0 +1,48 @@ +# $Id$ +# +# -------------------------------------------------------------------------- +# BPyNMesh.py version 0.1 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +# -------------------------------------------------------------------------- +# "Apply size and rotation" function by Jonas Petersen +# -------------------------------------------------------------------------- +# This function does (hopefully) exactly what the +# "Apply size and rotation" command does (CTRL-A in Object Mode). +def ApplySizeAndRotation(obj): + if obj.getType() != "Mesh": return + if obj.SizeX==1.0 and obj.SizeY==1.0 and obj.SizeZ==1.0 and obj.RotX == 0.0 and obj.RotY == 0.0 and obj.RotZ == 0.0: return + mesh = obj.getData() + matrix = obj.matrix + v = [0,0,0] + for vert in mesh.verts: + co = vert.co + v[0] = co[0]*matrix[0][0] + co[1]*matrix[1][0] + co[2]*matrix[2][0] + v[1] = co[0]*matrix[0][1] + co[1]*matrix[1][1] + co[2]*matrix[2][1] + v[2] = co[0]*matrix[0][2] + co[1]*matrix[1][2] + co[2]*matrix[2][2] + co[0], co[1], co[2] = v + obj.SizeX = obj.SizeY = obj.SizeZ = 1.0 + obj.RotX = obj.RotY = obj.RotZ = 0.0 + mesh.update() + diff --git a/release/scripts/bvh2arm.py b/release/scripts/bvh2arm.py new file mode 100644 index 00000000000..c8cac3d90cf --- /dev/null +++ b/release/scripts/bvh2arm.py @@ -0,0 +1,693 @@ +#!BPY +""" +Name: 'BVH Empties to Armature' +Blender: 234 +Group: 'Animation' +Tooltip: 'Create Armature from Empties created by the BVH import script' +""" +__author__ = " Jean-Baptiste PERIN (jb_perin(at)yahoo.fr)" +__url__ = ("blender", "elysiun", +"BVH 2 ARMATURE, http://www.zoo-logique.org/3D.Blender/index.php3?zoo=dld&rep=zip ", +"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") + +__version__ = "2.0" + +__bpydoc__ = """ BVH2ARM.py v2.0 + +Script for generating armature from BVH empties. + +This script generates an armature and makes bones +follow empties created by the BVH import script. + +Usage:
+ - Import a bvh in Blender (File->Import->BVH);
+ - Launch this script (Alt-P);
+ - Set up variables:
+ "hipbonename": the name of the main bone;
+ "startframe": the first frame of your anim;
+ "endframe": the last frame of your anim;
+ "decimation": the frequency (in number of frames) to which the armature is updated;
+ "scale": to size the created armature. + - Press "Create Armature". +""" + +#---------------------------------------------- +# (c) Jean-Baptiste PERIN octobre 2004, released under Blender Artistic Licence +# for the Blender 2.34-2.36 Python Scripts Bundle. +#---------------------------------------------- + + + +import Blender +from Blender import Mathutils +import math + +dicEmptiesRestMatrix= {} +dicEmptiesInvRestMatrix= {} +dicBoneRestMatrix= {} +dicBone={} +dicEmptyChild={} +dicBoneRestInvEmpRest={} +dicEmpRestInvBoneRest={} +restFrame = 1 + +######################################################################## +# +# UTILITY FUNCTIONS FOR HANDLING BONES AND EMPTIES +# +######################################################################## + +def names(ob): return ob.getName() + +######### +# Cette fonction renvoie la liste des empties attaches a root +# in : +# out : emp_list (List of Object) la liste des objets de type "Empty" +######### +def getTree(emp_list, root): + empties=getAllEmpties() + chlds = getChildren(root, empties) + dicEmptyChild[root.getName()]=chlds + for ch in chlds: + emp_list.append(ch) + getTree(emp_list,ch) + +######### +# Cette fonction renvoie la liste des empties attaches a root +# in : +# out : emp_list (List of Object) la liste des objets de type "Empty" +######### +def getEmpties(): + global hipbonename + emp_list = [] + root = Blender.Object.Get(hipbonename) + emp_list.append(root) + getTree(emp_list, root) + return emp_list + +######### +# Cette fonction renvoie la liste des empties +# in : +# out : emp_list (List of Object) la liste des objets de type "Empty" +######### +def getAllEmpties(): + emp_list = [] + objs = Blender.Object.Get() + for o in objs: + if o.getType()=="Empty": + emp_list.append(o) + return emp_list + +######### +# Cette fonction renvoie la liste des empties +# in : +# out : emp_list (List of Object) la liste des objets de type "Empty" +######### +def getEmpty(name): + p = None + objs = Blender.Object.Get() + for o in objs: + if o.getType()=="Empty" and o.getName()==name: + p = o + return p + +def getChild(emp, emp_list): + return dicEmptyChild[emp.getName()] + + +######### +# Cette fonction fournit la liste des enfants d'un empty +# in : emp (Object) un empty +# emp_list (List of Object) la liste des empties +# out : children (List of Object) la liste des empties enfants de 'empty' +######### +def getChildren(emp, emp_list): + children = [] + root_emp = getRootEmpties(emp_list) + for em in emp_list: + if (em.getName() != emp.getName()) and (em not in root_emp): + if (em.getParent().getName() == emp.getName()): + children.append(em) + return children + + + +######### +# Cette fonction renvoie la liste des empties n'ayant pas de parent +# in : emp_list (List) une liste d'empties +# out : root (List) le (ou les) empty n'ayant pas de parent +######### +def getRootEmpties(emp_list): + root = [] + for em in emp_list: + if em.getParent() == None: + root.append(em) + return root + + +######### +# Cette fonction renvoie le bone de nom 'name' dans l'armature 'armature' +# in : armature (Armature) l'armature dans laquelle cherchait le bone +# name (String) le nom de l'os a chercher +# out : p (Bone) +######### +#def getBone(armature, name): +# return (dicBone[name]) + #p = None + #bones = armature.getBones() + #for i in bones: + # if i.getName() == name: + # p = i + # break + #return p + + +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 GetOrCreateIPO(name): + + ipos = Blender.Ipo.Get() + if name in map(names,ipos): + myipo = Blender.Ipo.Get(name) + print name+' exists' + else: + myipo = Blender.Ipo.New('Object',name) + print name+' was created' + return myipo + + +def GetOrCreateCurve(ipo, curvename): + curves = ipo.getCurves() + if curvename in map(names,curves): + mycurve = ipo.getCurve(curvename) + print curvename+' exists' + else: + mycurve = ipo.addCurve(curvename) + print curvename+' was created' + return mycurve + + + + +######################################################################## +# +# FUNCTIONS FOR COMPUTING POSITION AND ROTATION OF BONES +# +######################################################################## + +def computeRootQuat2(empty, bone): + + M1=dicBoneRestInvEmpRest[bone.getName()].rotationPart() + M2=dicEmpRestInvBoneRest[bone.getName()].rotationPart() + emprot = empty.getMatrix('worldspace').rotationPart() + emprot.transpose() + mat = M1*emprot*M2 + mat.transpose() + return (mat.toQuat()) + + #emprest = dicEmptiesRestMatrix[empty.getName()].rotationPart() + #invemprest= dicEmptiesRestMatrix[empty.getName()].rotationPart() + ##invemprest= emprest + ##invemprest.invert() + ##invemprest= dicEmptiesInvRestMatrix[empty.getName()].rotationPart() + #emprot = empty.getMatrix('worldspace').rotationPart() + #bonerest = dicBoneRestMatrix[bone.getName()].rotationPart() + #invbonerest = dicBoneRestMatrix[bone.getName()].rotationPart() + #invbonerest.invert() + #T2=emprot*invemprest + #T2.transpose() + #mat = bonerest*invemprest*T2*emprest*invbonerest + #mat.transpose() + #return (mat.toQuat()) + + + + +######### +# Cette fonction +# in : +# out : +######### +def computeRootPos(empty, bone): + vec = computeScaledPos(empty.getMatrix('worldspace').translationPart()) - dicBoneRestMatrix[bone.getName()].translationPart() + mat = dicBoneRestMatrix[bone.getName()].rotationPart() + vec2 = Mathutils.MatMultVec (mat, vec) + return vec2 + + +def computeRelativePos(empty,bone): + vec = computeScaledPos(empty.getMatrix('worldspace').translationPart()) - dicBoneRestMatrix[bone.getName()].translationPart() + rootempty = getEmpty(hipbonename) + vec3 = computeScaledPos(rootempty.getMatrix('worldspace').translationPart()) + mat = dicBoneRestMatrix[bone.getName()].rotationPart() + vec2 = Mathutils.MatMultVec (mat, vec-vec3) + return vec2 + + + ######### +# Cette fonction +# in : +# out : +######### +def computeScaledPos(vec): + global scalef + vec2 = Mathutils.Vector([vec[0]*scalef, vec[1]*scalef, vec[2]*scalef]) + return vec2 + +######################################################################## +# +# FUNCTIONS FOR CREATING AND MOVING ARMATURES +# +######################################################################## + +######### +# Cette fonction +# in : +# out : +######### +def createBone (armature, empty, bone, empties): + children = getChildren(empty, empties) + for ch in children: + if len(children) >= 2: + bonename = empty.getName()[1:len(empty.getName())]+'_'+ch.getName()[1:len(ch.getName())] + else : + bonename = empty.getName()[1:len(empty.getName())] + b=Blender.Armature.Bone.New(bonename) + b.setHead(computeScaledPos(empty.getMatrix('worldspace').translationPart())) + b.setTail(computeScaledPos(ch.getMatrix('worldspace').translationPart())) + #b.setParent(bone) + matrice = empty.getMatrix('worldspace') + invmatrice = empty.getMatrix('worldspace') + invmatrice.invert() + invmatricet=empty.getMatrix('worldspace') + invmatricet.invert() + invmatricet.transpose() + dicEmptiesRestMatrix[empty.getName()] = matrice + dicEmptiesInvRestMatrix[empty.getName()] = invmatrice + armature.addBone(b) + invbonerest=b.getRestMatrix() + invbonerest.invert() + dicBoneRestMatrix[b.getName()] = b.getRestMatrix() + dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet + dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest + dicBone[b.getName()]=b + createBone(armature, ch, b, empties) + +######### +# Cette fonction +# in : +# out : +######### +def f_createBone (armData, empty, bone, empties): + bones = armData.getBones() + + def getBone(bonename): + bone = None + for b in bones: + #print b.getName() + if b.getName() == bonename: + bone = b + return bone + + children = getChildren(empty, empties) + for ch in children: + if len(children) >= 2: + bonename = empty.getName()[1:len(empty.getName())]+'_'+ch.getName()[1:len(ch.getName())] + else : + bonename = empty.getName()[1:len(empty.getName())] + #b=Blender.Armature.Bone.New(bonename) + b=getBone(bonename) + #b.setHead(empty.getMatrix('worldspace').translationPart()) + #b.setTail(ch.getMatrix('worldspace').translationPart()) + #b.setParent(bone) + matrice = empty.getMatrix('worldspace') + invmatrice = empty.getMatrix('worldspace') + invmatrice.invert() + invmatricet=empty.getMatrix('worldspace') + invmatricet.invert() + invmatricet.transpose() + dicEmptiesRestMatrix[empty.getName()] = matrice + dicEmptiesInvRestMatrix[empty.getName()] = invmatrice + #armature.addBone(b) + invbonerest=b.getRestMatrix() + invbonerest.invert() + dicBoneRestMatrix[b.getName()] = b.getRestMatrix() + dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet + dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest + dicBone[b.getName()]=b + print "Ajout de ", b.getName()," au dictionnaire" + f_createBone(armData, ch, b, empties) + + +######### +# Cette fonction fabrique une arma +# in : +# out : +######### +def createArmature (rootEmpty, empties): + armData=Blender.Armature.New('monArmature') + children = getChildren(rootEmpty, empties) + for ch in children: + b=Blender.Armature.Bone.New(rootEmpty.getName()[1:len(rootEmpty.getName())] + ch.getName()[1:len(ch.getName())]) + b.setHead(computeScaledPos(rootEmpty.getMatrix('worldspace').translationPart())) + b.setTail(computeScaledPos(ch.getMatrix('worldspace').translationPart())) + armData.addBone(b) + matrice = ch.getMatrix('worldspace') + invmatrice = ch.getMatrix('worldspace') + invmatrice.invert() + invmatricet=ch.getMatrix('worldspace') + invmatricet.invert() + invmatricet.transpose() + dicEmptiesRestMatrix[rootEmpty.getName()] = matrice + dicEmptiesInvRestMatrix[rootEmpty.getName()] = invmatrice + invbonerest=b.getRestMatrix() + invbonerest.invert() + dicBoneRestMatrix[b.getName()] = b.getRestMatrix() + dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet + dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest + dicBone[b.getName()]=b + createBone(armData, ch, b, empties) + return armData + + + +######### +# Cette fonction fabrique une arma +# in : +# out : +######### +def f_createArmature (rootEmpty, empties, armData): + bones = armData.getBones() + + def getBone(bonename): + bone = None + for b in bones: + #print b.getName() + if b.getName() == bonename: + bone = b + return bone + + children = getChildren(rootEmpty, empties) + for ch in children: + b=getBone(rootEmpty.getName()[1:len(rootEmpty.getName())] + ch.getName()[1:len(ch.getName())]) + matrice = ch.getMatrix('worldspace') + invmatrice = ch.getMatrix('worldspace') + invmatrice.invert() + invmatricet=ch.getMatrix('worldspace') + invmatricet.invert() + invmatricet.transpose() + dicEmptiesRestMatrix[rootEmpty.getName()] = matrice + dicEmptiesInvRestMatrix[rootEmpty.getName()] = invmatrice + invbonerest=b.getRestMatrix() + invbonerest.invert() + dicBoneRestMatrix[b.getName()] = b.getRestMatrix() + dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet + dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest + dicBone[b.getName()]=b + print "Ajout de ", b.getName()," au dictionnaire" + + f_createBone(armData, ch, b, empties) + + + +######### +# Cette fonction +# in : +# out : +######### +def moveBones(armature, empty, empties): + children = dicEmptyChild[empty.getName()] + for ch in children: + if len(children) >= 2: + bonename = empty.getName()[1:len(empty.getName())]+'_'+ch.getName()[1:len(ch.getName())] + else : + bonename = empty.getName()[1:len(empty.getName())] + bone = dicBone[bonename] + #bone.setLoc(computeRootPos(empty,bone)) + bone.setLoc(computeRelativePos(empty,bone)) + bone.setQuat(computeRootQuat2(empty,bone)) + chch = dicEmptyChild[ch.getName()] + if len(chch) >= 1: + moveBones(armature, ch, empties) + + +######### +# Cette fonction +# in : +# out : +######### +def moveArmature (armature, empties): + root = Blender.Object.Get(hipbonename) + children = dicEmptyChild[hipbonename] + for ch in children: + b=dicBone[hipbonename[1:len(hipbonename)] + ch.getName()[1:len(ch.getName())]] + #b.setLoc(computeRootPos(root, b)) + b.setLoc([0.0, 0.0, 0.0]) + b.setQuat(computeRootQuat2(root, b)) + moveBones(armature, ch, empties) + + +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) + + +######################################################################## +# +# MAIN PROGRAM +# +######################################################################## + +def RemoveEmpties(): + + global endframe, startframe,hipbonename + + lesEmpties = getEmpties() + scn = Blender.Scene.getCurrent() + #scn.link (armObj) + for em in lesEmpties: + eraseIPO (em.getName()) + scn.unlink(em) + Blender.Redraw() + + +def Main(): + + global endframe, startframe,hipbonename, framedecimation + + + print "*****START*****" + + Blender.Set("curframe",restFrame) + + ##----------- + ## Positionnement des empties + ##----------- + em0 = Blender.Object.Get(hipbonename) + + Blender.Redraw() + + + + ##----------- + ## Creation de l'armature et des os + ##----------- + + lesEmpties = getEmpties() + #print dicEmptyChild + + #armData = createArmature(em0, lesEmpties) + objects = Blender.Object.Get() + if 'OBArmature' in map(names,objects): + armObj = Blender.Object.Get('OBArmature') + armData = armObj.getData() + print 'OBArmature'+' exists' + eraseIPO ('OBArmature') + #print armData.getBones() + f_createArmature(em0, lesEmpties, armData) + else: + armData= createArmature(em0, lesEmpties) + armObj=Blender.Object.New('Armature', 'OBArmature') + armObj.link(armData) + scn = Blender.Scene.getCurrent() + scn.link (armObj) + + print 'OBArmature'+' was created' + #return myobj + + ##----------- + ## Creation de l'ipo de l'armature + ##----------- + lipo = GetOrCreateIPO('BVHIpo') + armObj.setIpo(lipo) + curvX = GetOrCreateCurve(lipo, 'LocX') + curvY = GetOrCreateCurve(lipo, 'LocY') + curvZ = GetOrCreateCurve(lipo, 'LocZ') + + + #armData.drawAxes(1) + #armData.drawNames(1) + + + + Blender.Redraw() + + ##----------- + ## Enregistrement de la position de l'armature + ##----------- + + bones = armData.getBones() + for bo in bones: + bo.setPose([Blender.Armature.Bone.ROT, Blender.Armature.Bone.LOC]) + + curvX.addBezier((Blender.Get("curframe"), getEmpty(hipbonename).getMatrix('worldspace').translationPart()[0]*scalef)) + curvY.addBezier((Blender.Get("curframe"), getEmpty(hipbonename).getMatrix('worldspace').translationPart()[1]*scalef)) + curvZ.addBezier((Blender.Get("curframe"), getEmpty(hipbonename).getMatrix('worldspace').translationPart()[2]*scalef)) + curvX.setInterpolation('Linear') + curvX.setExtrapolation('Constant') + curvY.setInterpolation('Linear') + curvY.setExtrapolation('Constant') + curvZ.setInterpolation('Linear') + curvZ.setExtrapolation('Constant') + + Blender.Redraw() + + Blender.Set("curframe",startframe) + while endframe >= Blender.Get("curframe"): + + ##----------- + ## Positionnement des os + ##----------- + + moveArmature(armData, lesEmpties) + + + ##----------- + ## Enregistrement de la position de l'armature + ##----------- + + for bo in bones: + bo.setPose([Blender.Armature.Bone.ROT, Blender.Armature.Bone.LOC]) + curvX.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').translationPart()[0])*scalef)) + curvY.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').translationPart()[1])*scalef)) + curvZ.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').translationPart()[2])*scalef)) + + ##----------- + ## Passage a la frame suivante + ##----------- + num_frame = Blender.Get("curframe")+framedecimation + print num_frame + Blender.Set("curframe", num_frame) + + Blender.Set("curframe",startframe) + Blender.Redraw() + + print "*****END*****" + + +######################################################################## +# +# GUI FUNCTIONS AND VARIABLES +# +######################################################################## + +EFrame = Blender.Draw.Create(5) +IFrame = Blender.Draw.Create(6) +SFrame2 = Blender.Draw.Create(5) +HBName = Blender.Draw.Create(0) +FrameDecimation = Blender.Draw.Create(5) +ScaleF = Blender.Draw.Create(0) + +Msg = ' ' + +def event (evt, val): + if evt == Blender.Draw.ESCKEY: + Blender.Draw.Exit() + return + +def button_event(evt): + global EFrame, IFrame, SFrame2, HBName, Msg , FrameDecimation, ScaleF + global endframe, startframe, insertionframe, hipbonename, framedecimation , scalef + if evt==1: + startframe = SFrame2.val + insertionframe = IFrame.val + endframe = EFrame.val + hipbonename = HBName.val + framedecimation = FrameDecimation.val + scalef= eval(str(ScaleF.val)) + print "scalef = ", scalef + if startframe>=endframe: + Msg = 'Start frame must be lower than End frame' + Blender.Draw.PupMenu("ERROR: %s" % Msg) + else: + ob = getEmpty(hipbonename) + if (ob!=None): + if ob.getParent()!=None: + Msg = 'Empty '+hipbonename+ ' is not a root bone.' + Blender.Draw.PupMenu("ERROR: %s" % Msg) + else: + if (0.0 > scalef): + Msg = 'Scale factor must be greater than 0' + Blender.Draw.PupMenu("ERROR: %s" % Msg) + else: + #Blender.Draw.Exit() + Main() + else: + Msg = 'Empty '+ hipbonename+ ' not found' + Blender.Draw.PupMenu("ERROR: %s" % Msg) + + #Blender.Draw.Redraw(1) + elif evt==2: + hipbonename = HBName.val + ob = getEmpty(hipbonename) + if (ob!=None): + if ob.getParent()!=None: + Msg = 'Empty '+hipbonename+ ' is not a root bone.' + Blender.Draw.PupMenu("ERROR: %s" % Msg) + else: + #Blender.Draw.Exit() + RemoveEmpties() + else: + Msg = 'Empty '+ hipbonename+ ' not found' + Blender.Draw.PupMenu("ERROR: %s" % Msg) + + #else: + # print "evt = ",evt + +def GUI(): + global EFrame, SFrame2, HBName, Msg , ScaleF, FrameDecimation + Blender.BGL.glClearColor(0,0,1,1) + Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT) + Blender.BGL.glColor3f(1,1,1) + Blender.BGL.glRasterPos2i(20,200) + Blender.Draw.Text ("BVH 2 ARMATURE v2.0 by Jean-Baptiste PERIN", 'normal') + HBName = Blender.Draw.String("HipBoneName: ", -1, 20, 175, 250, 20, '_Hips', 100) + SFrame2 = Blender.Draw.Number("Startframe: ", -1, 20, 150, 250, 20, 1, 1,3000,"") + EFrame = Blender.Draw.Number("Endframe: ", -1, 20, 125, 250, 20, Blender.Get("endframe"), 1,3000,"") + #IFrame = Blender.Draw.Number("Insertionframe: ", -1, 20, 100, 250, 20, Blender.Get("staframe"), 1,3000,"") + FrameDecimation = Blender.Draw.Number("FrameDecimation: ", -1, 20, 75, 250, 20,5, 1,10,'') + ScaleF = Blender.Draw.Number("Scale: ", -1, 20, 50, 250, 20, 0.03, 0.0, 10.0, 'Scale Factor') + Blender.Draw.Toggle("Create Armature", 1, 20, 10, 100, 20, 0, "Create Armature") + #Blender.Draw.Toggle("Remove Empties", 2, 200, 10, 100, 20, 0, "Remove Empties") + Blender.BGL.glRasterPos2i(20,40) + Blender.Draw.Text (Msg, 'normal') + + +Blender.Draw.Register(GUI, event, button_event) diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py index 8c39d32eb8f..103c0df9969 100644 --- a/release/scripts/bvh_import.py +++ b/release/scripts/bvh_import.py @@ -21,8 +21,9 @@ Missing:
Known issues:
Notes:
- Jean-Michel Soler improved importer to support Poser 3.01 files. - + Jean-Michel Soler improved importer to support Poser 3.01 files;
+ Jean-Baptiste Perin wrote a script to create an armature out of the +Empties created by this importer, it's in the Scripts window -> Scripts -> Animation menu. """ # $Id$ diff --git a/release/scripts/camera_changer.py b/release/scripts/camera_changer.py new file mode 100644 index 00000000000..fe08c6d6338 --- /dev/null +++ b/release/scripts/camera_changer.py @@ -0,0 +1,95 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Camera Changer' +Blender: 234 +Group: 'Animation' +Tip: 'Create script link to change cameras (based on their names) during an animation' +""" + +__author__ = '3R - R3gis' +__version__ = '1.2' +__url__ = ["Author's site , http://cybercreator.free.fr", "French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender"] +__email__=["3R, r3gis@free.fr"] + + +__bpydoc__ = """\ +This script creates an script link to change cameras during an animation. + +The created script link (a Blender Text) is linked to Scene Frame Changed events. +Usage: + +Run the script, then name the camera Object with the number of the frame(s) where you +want this camera to become active. + +For example:
+ - a camera called "10" will become active at frame 10.
+ - a camera called "10,25,185" will become active at frames 10, 25 and 185. + +Notes:
+ - This script creates another script named camera.py, which is linked to the current scene.
+ - If there is already a text called "camera.py", but it's from an old version or is not recognized, +you can choose if you want to rename or overwrite it. +""" + + +# $Id$ +# +#Script in the same idea that this one : +#http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm +# +#---------------------------------------------- +# R3gis Montoya (3R) +# +# Pout tout probleme a: +# cybercreator@free.fr +# --------------------------------------------- + +import Blender +from Blender import * +import string + +sc=Scene.GetCurrent() + +#import du texte +lestext=Blender.Text.Get() +Ntexts=[] +for txt in lestext: + Ntexts.append(txt.getName()) +ecrire=0 + +if 'camera.py' not in Ntexts: + ecrire=1 +else : + if lestext[Ntexts.index('camera.py')].asLines()[0] != "# camera.py 1.2 link python #": + reecrire=Blender.Draw.PupMenu("WARNING: Text camera.py already exists but is outdated%t|Overwrite|Rename old version text") + if reecrire == 1: + Text.unlink(lestext[Ntexts.index('camera.py')]) + ecrire=1 + if reecrire == 2: + lestext[Ntexts.index('camera.py')].name="old_camera.txt" + ecrire=1 + + + +if ecrire == 1: + scripting=Blender.Text.New('camera.py') + scripting.write("# camera.py 1.2 link python #\nimport Blender\nfrom Blender import *\nfrom math import *\nimport string\n") + scripting.write("sc=Scene.GetCurrent()\n#Changement camera\nlescam=[]\nobjets=Blender.Object.Get()\n") + scripting.write("for ob in objets:\n if type(ob.getData())==Blender.Types.CameraType:\n try:") + scripting.write("\n lesfram=string.split(ob.name,',')\n for fr in lesfram:\n lescam.append(ob.name)\n lescam.append(int(fr))\n except:\n pass") + scripting.write("\nframe = Blender.Get('curframe')\nif frame in lescam:\n nom=lescam.index(frame)\n sc.setCurrentCamera(Blender.Object.Get(lescam[nom-1]))\n") + + +#Linkage +list=[] +try: + for script in sc.getScriptLinks('FrameChanged'): + list.append(script) +except: + pass +if 'camera.py' not in list: + sc.addScriptLink('camera.py','FrameChanged') + Blender.Draw.PupMenu("Done! Remember:%t|Name cameras as (a comma separated list of) their activation frame number(s)") + Blender.Redraw(-1) + diff --git a/release/scripts/console.py b/release/scripts/console.py new file mode 100644 index 00000000000..1fbf7908c7a --- /dev/null +++ b/release/scripts/console.py @@ -0,0 +1,517 @@ +#!BPY + +""" +Name: 'Interactive Console' +Blender: 236 +Group: 'System' +Tooltip: 'Interactive Python Console' +""" +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun", "Official Python site, http://www.python.org"] +__bpydoc__ = """\ +This is an interactive console, similar to Python's own command line interpreter. Since it is embedded in Blender, it has access to all Blender Python modules. + +Those completely new to Python can check the link button above that points to +its official homepage, with news, downloads and documentation. + +Usage:
+ Type your code and hit "Enter" to get it executed.
+ - Right mouse click: Save output;
+ - Arrow keys: command history and cursor;
+ - Ctrl + Tab: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;
+ - Ctrl + Enter: multiline functions -- delays executing code until only Enter is pressed. +""" + +import Blender +from Blender import * +import sys as python_sys +import StringIO +import types + +# Constants +__DELIMETERS__ = '. ,=+-*/%<>&~][{}():' +__LINE_HISTORY__ = 200 +__LINE_HEIGHT__ = 14 +__FONT_SIZE__ = "normal" + +''' +# Generic Blender functions +def getActScriptWinRect(): + area = Window.GetAreaSize() + area = (area[0]-1, area[1]-1) + for scrInfo in Window.GetScreenInfo(Window.Types['SCRIPT'], 'win', ''): + if scrInfo['vertices'][2]-scrInfo['vertices'][0] == area[0]: + if scrInfo['vertices'][3]-scrInfo['vertices'][1] == area[1]: + return scrInfo['vertices'] + return None +''' + +class cmdLine: + # cmd: is the command string, or any other message + # type: 0:user input 1:program feedback 2:error message. 3:option feedback + # exe; 0- not yet executed 1:executed + def __init__(self, cmd, type, exe): + self.cmd = cmd + self.type = type + self.exe = exe + +# Include external file with internal namespace +def include(filename): + file = open(filename, 'r') + filedata = file.read() + file.close() + return compile(filedata, filename, 'exec') + +# Writes command line data to a blender text file. +def writeCmdData(cmdLineList, type): + if type == 3: + typeList = [0,1,2, 3, None] # all + else: + typeList = [type] # so we can use athe lists 'in' methiod + + newText = Text.New('command_output.py', 1) + for myCmd in cmdLineList: + if myCmd.type in typeList: # user input + newText.write('%s\n' % myCmd.cmd) + Draw.PupMenu('%s written' % newText.name) + +def insertCmdData(cmdBuffer): + textNames = [tex.name for tex in Text.Get()] + if textNames: + choice = Draw.PupMenu('|'.join(textNames)) + if choice != -1: + text = Text.Get()[choice-1] + + # Add the text! + for l in text.asLines(): + cmdBuffer.append(cmdLine('%s ' % l, 0, 0)) + Draw.Redraw() + + +COLLECTED_VAR_NAMES = {} # a list of keys, each key has a list of absolute paths + +# Pain and simple recursice dir(), accepts a string +def rdir(dirString): + global COLLECTED_VAR_NAMES + dirStringSplit = dirString.split('.') + + exec('dirList = dir(%s)' % dirString) + for dirItem in dirList: + if not dirItem.startswith('_'): + if dirItem not in COLLECTED_VAR_NAMES.keys(): + COLLECTED_VAR_NAMES[dirItem] = [] + + # Add the string + splitD = dirString.split('"')[-2] + if splitD not in COLLECTED_VAR_NAMES[dirItem]: + COLLECTED_VAR_NAMES[dirItem].append(splitD) + + + + # Stops recursice stuff, overlooping + if type(dirItem) == types.ClassType or \ + type(dirItem) == types.ModuleType: + + print dirString, splitD, dirItem + + # Dont loop up dirs for strings ints etc. + if d not in dirStringSplit: + rdir( '%s.%s' % (dirString, d)) + +def recursive_dir(): + global COLLECTED_VAR_NAMES + + for name in __CONSOLE_VAR_DICT__.keys(): + if not name.startswith('_'): # Dont pick names like __name__ + rdir('__CONSOLE_VAR_DICT__["%s"]' % name) + #print COLLECTED_VAR_NAMES + COLLECTED_VAR_NAMES[name] = [''] + return COLLECTED_VAR_NAMES + +# Runs the code line(s) the user has entered and handle errors +# As well as feeding back the output into the blender window. +def runUserCode(__USER_CODE_STRING__): + global __CONSOLE_VAR_DICT__ # We manipulate the variables here. loading and saving from localspace to this global var. + + # Open A File like object to write all output to, that would useually be printed. + python_sys.stdout.flush() # Get rid of whatever came before + __FILE_LIKE_STRING__ = StringIO.StringIO() # make a new file like string, this saves up from making a file. + __STD_OUTPUT__ = python_sys.stdout # we need to store the normal output. + python_sys.stdout=__FILE_LIKE_STRING__ # Now anything printed will be written to the file like string. + + # Try and run the user entered line(s) + try: + # Load all variabls from global dict to local space. + for __TMP_VAR_NAME__ in __CONSOLE_VAR_DICT__.keys(): + exec('%s%s%s%s' % (__TMP_VAR_NAME__,'=__CONSOLE_VAR_DICT__["', __TMP_VAR_NAME__, '"]')) + del __TMP_VAR_NAME__ + + # Now all the vars are loaded, execute the code. # Newline thanks to phillip, + exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'single')) #exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'exec')) + + # Write local veriables to global __CONSOLE_VAR_DICT__ + for __TMP_VAR_NAME__ in dir(): + if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\ + __TMP_VAR_NAME__ != '__STD_OUTPUT__' and\ + __TMP_VAR_NAME__ != '__TMP_VAR_NAME__' and\ + __TMP_VAR_NAME__ != '__USER_CODE_STRING__': + + # Execute the local > global coversion. + exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) + del __TMP_VAR_NAME__ + + except: # Prints the REAL exception. + error = str(python_sys.exc_value) + for errorLine in error.split('\n'): + cmdBuffer.append(cmdLine(errorLine, 2, None)) # new line to type into + + python_sys.stdout = __STD_OUTPUT__ # Go back to output to the normal blender console + + # Copy all new output to cmdBuffer + __FILE_LIKE_STRING__.seek(0) # the readline function requires that we go back to the start of the file. + for line in __FILE_LIKE_STRING__.readlines(): + cmdBuffer.append(cmdLine(line, 1, None)) + + cmdBuffer.append(cmdLine(' ', 0, 0)) # new line to type into + python_sys.stdout=__STD_OUTPUT__ + __FILE_LIKE_STRING__.close() + + + + + +#------------------------------------------------------------------------------# +# event handling code # +#------------------------------------------------------------------------------# +def handle_event(evt, val): + + # Insert Char into the cammand line + def insCh(ch): # Instert a char + global cmdBuffer + global cursor + # Later account for a cursor variable + cmdBuffer[-1].cmd = ('%s%s%s' % ( cmdBuffer[-1].cmd[:cursor], ch, cmdBuffer[-1].cmd[cursor:])) + + #------------------------------------------------------------------------------# + # Define Complex Key Actions # + #------------------------------------------------------------------------------# + def actionEnterKey(): + global histIndex, cursor, cmdBuffer + # Check for the neter kay hit + if Window.GetKeyQualifiers() & Window.Qual.CTRL: # HOLDING DOWN SHIFT, GO TO NEXT LINE. + cmdBuffer.append(cmdLine(' ', 0, 0)) + else: + # Multiline code will still run with 1 line, + multiLineCode = ['if 1:'] + if cmdBuffer[-1].cmd != ' ': + multiLineCode = ['%s%s' % (' ', cmdBuffer[-1].cmd)] # added space for fake if. + else: + cmdBuffer[-1].type = 1 + multiLineCode = [] + cmdBuffer[-1].exe = 1 + i = 2 + while cmdBuffer[-i].exe == 0: + if cmdBuffer[-i].cmd == ' ':# Tag as an output type so its not used in the key history + cmdBuffer[-i].type = 1 + else: # space added at the start for added if 1: statement + multiLineCode.append('%s%s' % (' ', cmdBuffer[-i].cmd) ) + + # Mark as executed + cmdBuffer[-i].exe = 1 + i+=1 + + # add if to the end, reverse will make it the start. + multiLineCode.append('if 1:') + multiLineCode.reverse() + multiLineCode.append(' pass') # Now this is the end + + + runUserCode('\n'.join(multiLineCode)) + + # Clear the output based on __LINE_HISTORY__ + if len(cmdBuffer) > __LINE_HISTORY__: + cmdBuffer = cmdBuffer[-__LINE_HISTORY__:] + + histIndex = cursor = -1 # Reset cursor and history + + def actionUpKey(): + global histIndex, cmdBuffer + if abs(histIndex)+1 >= len(cmdBuffer): + histIndex = -1 + histIndex -= 1 + while cmdBuffer[histIndex].type != 0 and abs(histIndex) < len(cmdBuffer): + histIndex -= 1 + if cmdBuffer[histIndex].type == 0: # we found one + cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd + + def actionDownKey(): + global histIndex, cmdBuffer + if histIndex >= -2: + histIndex = -len(cmdBuffer) + histIndex += 1 + while cmdBuffer[histIndex].type != 0 and histIndex != -2: + histIndex += 1 + if cmdBuffer[histIndex].type == 0: # we found one + cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd + + def actionRightMouse(): + choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Quit') + print choice + if choice == 1: + writeCmdData(cmdBuffer, 0) # type 0 user + elif choice == 2: + writeCmdData(cmdBuffer, 1) # type 1 user output + elif choice == 3: + writeCmdData(cmdBuffer, 2) # type 2 errors + elif choice == 4: + writeCmdData(cmdBuffer, 3) # All + elif choice == 6: + insertCmdData(cmdBuffer) # All + elif choice == 8: # Exit + Draw.Exit() + + + # Auto compleating, quite complex- use recutsice dir for the moment. + def actionAutoCompleate(): # Ctrl + Tab + RECURSIVE_DIR = recursive_dir() + + # get last name of user input + editVar = cmdBuffer[-1].cmd[:cursor] + + # Split off spaces operators etc from the staryt of the command so we can use the startswith function. + for splitChar in __DELIMETERS__: + editVar = editVar.split(splitChar)[-1] + + # Now we should have the var by its self + if editVar: + + possibilities = [] + + print editVar, 'editVar' + for __TMP_VAR_NAME__ in RECURSIVE_DIR.keys(): + if __TMP_VAR_NAME__ == editVar: + # print 'ADITVAR IS A VAR' + continue + elif __TMP_VAR_NAME__.startswith( editVar ): + possibilities.append( __TMP_VAR_NAME__ ) + + + if len(possibilities) == 1: + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], possibilities[0], cmdBuffer[-1].cmd[cursor:])) + + elif possibilities: # If its not just [] + # -1 with insert is the second last. + + # Text choice + #cmdBuffer.insert(-1, cmdLine('options: %s' % ' '.join(possibilities), 3, None)) + + menuText = 'Choices (hold shift for whole name)%t|' + menuList = [] + menuListAbs = [] + possibilities.sort() # make nice :) + for __TMP_VAR_NAME__ in possibilities: + for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]: + # Account for non absolute (variables for eg.) + if usage: # not '' + menuListAbs.append('%s.%s' % (usage, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift. + else: + menuListAbs.append(__TMP_VAR_NAME__) # Used for names and can be entered when pressing shift. + + menuList.append(__TMP_VAR_NAME__) # Used for non Shift + + + #choice = Draw.PupMenu('Select Variabe name%t|' + '|'.join(possibilities) ) + choice = Draw.PupMenu(menuText + '|'.join(menuListAbs)) + if choice != -1: + + if not Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Only paste in the Short name + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1], cmdBuffer[-1].cmd[cursor:])) + else: # Put in the long name + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuListAbs[choice-1], cmdBuffer[-1].cmd[cursor:])) + else: + # print 'NO EDITVAR' + return + + # ------------------end------------------# + + + #if (evt == Draw.ESCKEY and not val): + # Draw.Exit() + if evt == Draw.MOUSEX: # AVOID TOO MANY REDRAWS. + return + elif evt == Draw.MOUSEY: + return + + + global cursor + global histIndex + + ascii = Blender.event + + #------------------------------------------------------------------------------# + # key codes and key handling # + #------------------------------------------------------------------------------# + + # UP DOWN ARROW KEYS, TO TRAVERSE HISTORY + if (evt == Draw.UPARROWKEY and val): actionUpKey() + elif (evt == Draw.DOWNARROWKEY and val): actionDownKey() + + elif (evt == Draw.RIGHTARROWKEY and val): + cursor +=1 + if cursor > -1: + cursor = -1 + elif (evt == Draw.LEFTARROWKEY and val): + cursor -=1 + + elif (evt == Draw.TABKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.CTRL: + actionAutoCompleate() + else: + insCh('\t') + + elif (evt == Draw.BACKSPACEKEY and val): cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:cursor-1] , cmdBuffer[-1].cmd[cursor:])) + elif (evt == Draw.DELKEY and val) and cursor < -1: + cmdBuffer[-1].cmd = cmdBuffer[-1].cmd[:cursor] + cmdBuffer[-1].cmd[cursor+1:] + cursor +=1 + + elif ((evt == Draw.RETKEY or evt == Draw.PADENTER) and val): actionEnterKey() + elif (evt == Draw.RIGHTMOUSE and not val):actionRightMouse(); return + + elif ascii: + insCh(chr(ascii)) + else: + return # dont redraw. + Draw.Redraw() + + +def draw_gui(): + + # Get the bounds from ObleGL directly + __CONSOLE_RECT__ = BGL.Buffer(BGL.GL_FLOAT, 4) + BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, __CONSOLE_RECT__) + __CONSOLE_RECT__= __CONSOLE_RECT__.list + + + # Clear the screen + BGL.glClearColor(0.0, 0.0, 0.0, 1.0) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) # use it to clear the color buffer + + # Draw cursor location colour + cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], __FONT_SIZE__) + BGL.glColor3f(0.8, 0.2, 0.2) + BGL.glRecti(cmd2curWidth-1,4,cmd2curWidth+1, 20) + + BGL.glColor3f(1,1,1) + # Draw the set of cammands to the buffer + + consoleLineIdx = 1 + wrapLineIndex = 0 + while consoleLineIdx < len(cmdBuffer) and __CONSOLE_RECT__[3] > consoleLineIdx*__LINE_HEIGHT__ : + if cmdBuffer[-consoleLineIdx].type == 0: + BGL.glColor3f(1, 1, 1) + elif cmdBuffer[-consoleLineIdx].type == 1: + BGL.glColor3f(.3, .3, 1) + elif cmdBuffer[-consoleLineIdx].type == 2: + BGL.glColor3f(1.0, 0, 0) + elif cmdBuffer[-consoleLineIdx].type == 3: + BGL.glColor3f(0, 0.8, 0) + else: + BGL.glColor3f(1, 1, 0) + + if consoleLineIdx == 1: # NEVER WRAP THE USER INPUT + BGL.glRasterPos2i(0, (__LINE_HEIGHT__*consoleLineIdx) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__) + + + else: # WRAP? + # LINE WRAP + if Draw.GetStringWidth(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__) > __CONSOLE_RECT__[2]: + wrapLineList = [] + copyCmd = [cmdBuffer[-consoleLineIdx].cmd, ''] + while copyCmd != ['','']: + while Draw.GetStringWidth(copyCmd[0], __FONT_SIZE__) > __CONSOLE_RECT__[2]: + #print copyCmd + copyCmd[1] = '%s%s'% (copyCmd[0][-1], copyCmd[1]) # Add the char on the end + copyCmd[0] = copyCmd[0][:-1]# remove last chat + + # Now we have copyCmd[0] at a good length we can print it. + if copyCmd[0] != '': + wrapLineList.append(copyCmd[0]) + + copyCmd[0]='' + copyCmd = [copyCmd[1], copyCmd[0]] + + # Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change) + wrapLineList.reverse() + for wline in wrapLineList: + BGL.glRasterPos2i(0, (__LINE_HEIGHT__*(consoleLineIdx + wrapLineIndex)) - 8) + Draw.Text(wline, __FONT_SIZE__) + wrapLineIndex += 1 + wrapLineIndex-=1 # otherwise we get a silly extra line. + + else: # no wrapping. + + BGL.glRasterPos2i(0, (__LINE_HEIGHT__*(consoleLineIdx+wrapLineIndex)) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__) + + + consoleLineIdx += 1 + + +# This recieves the event index, call a function from here depending on the event. +def handle_button_event(evt): + pass + + +# Run the console +__CONSOLE_VAR_DICT__ = {} # Initialize var dict + + +# Print Startup lines +cmdBuffer = [cmdLine("Welcome to Ideasman's Blender Console", 1, None),\ + cmdLine(' * Right Click: Save output', 1, None),\ + cmdLine(' * Arrow Keys: Command history and cursor', 1, None),\ + cmdLine(' * Ctrl + Tab: Auto compleate based on variable names and modules loaded, multiple choices popup a menu', 1, None),\ + cmdLine(' * Ctrl + Enter: Multiline functions, delays executing code until only Enter is pressed.', 1, None)] + +histIndex = cursor = -1 # How far back from the first letter are we? - in current CMD line, history if for moving up and down lines. + +# Autoexec, startup code. +console_autoexec = '%s%s' % (Get('datadir'), '/console_autoexec.py') +if not sys.exists(console_autoexec): + # touch the file + open(console_autoexec, 'w').close() + cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts data dir', 1, None)) +else: + cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts data dir', 1, None)) + + + +#-Autoexec---------------------------------------------------------------------# +# Just use the function to jump into local naming mode. +# This is so we can loop through all of the autoexec functions / vars and add them to the __CONSOLE_VAR_DICT__ +def autoexecToVarList(): + global __CONSOLE_VAR_DICT__ # write autoexec vars to this. + + # Execute an external py file as if local + exec(include(console_autoexec)) + + # Write local to global __CONSOLE_VAR_DICT__ for reuse, + for __TMP_VAR_NAME__ in dir() + dir(Blender): + # Execute the local > global coversion. + exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) + +autoexecToVarList() # pass the blender module +#-end autoexec-----------------------------------------------------------------# + + +# Append new line to write to +cmdBuffer.append(cmdLine(' ', 0, 0)) + +#------------------------------------------------------------------------------# +# register the event handling code, GUI # +#------------------------------------------------------------------------------# +def main(): + Draw.Register(draw_gui, handle_event, handle_button_event) + +main() diff --git a/release/scripts/envelope_assignment.py b/release/scripts/envelope_assignment.py new file mode 100644 index 00000000000..9bc4b5a8494 --- /dev/null +++ b/release/scripts/envelope_assignment.py @@ -0,0 +1,234 @@ +#!BPY + +""" +Name: 'Envelope Assignment' +Blender: 234 +Group: 'Animation' +Tooltip: 'Assigns weights to vertices via envelopes' +""" + +__author__ = "Jonas Petersen" +__url__ = ("blender", "elysiun", "Script's homepage, http://www.mindfloaters.de/blender/", "thread at blender.org, http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4858") +__version__ = "0.9 2004-11-10" +__doc__ = """\ +This script creates vertex groups from a set of envelopes. + +"Envelopes" are Mesh objects with names following this naming convention: + +: + +Notes:
+ - All existing vertex groups of the target Mesh will be deleted. + +Please check the script's homepage and the thread at blender.org (last link button above) for more info. +""" + +# -------------------------------------------------------------------------- +# "Armature Symmetry" by Jonas Petersen +# Version 0.9 - 10th November 2004 - first public release +# -------------------------------------------------------------------------- +# +# A script that creates vertex groups from a set of envelopes. +# +# Envelopes are Mesh objects with names that follow the following +# naming convention (syntax): +# +# : +# +# All existing vertex groups of the target Mesh will be deleted. +# +# Find the latest version at: http://www.mindfloaters.de/blender/ +# +# -------------------------------------------------------------------------- +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Jonas Petersen, jonas at mindfloaters dot de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +# -------------------------------------------------------------------------- +# CONFIGURATION +# -------------------------------------------------------------------------- + +# Note: Theses values will later be editable via a gui interface +# within Blender. + +# SEPARATOR is the character used to delimit the bone name and the weight +# in the envelope name. +SEPARATOR = ":" + +# -------------------------------------------------------------------------- +# END OF CONFIGURATION +# -------------------------------------------------------------------------- + +import Blender, math, sys, string +from Blender import Mathutils +from Blender.Mathutils import * + +def run(target_obj): + target_mesh = target_obj.getData() + + num_verts = len(target_mesh.verts) + warn_count = 0 + main_obj_loc = Vector(list(target_obj.getLocation())) + + Blender.Window.EditMode(0) + + def vertGroupExist(group): + global vert_group_names; + for name in target_mesh.getVertGroupNames(): + if group == name: + return True + return False + + def isInside(point, envl_data): + for i in range(len(envl_data['normals'])): + vec = point - envl_data['points'][i] + if DotVecs(envl_data['normals'][i], vec) > 0.0: + return False + return True + + envls = {} + + Blender.Window.DrawProgressBar(0.0, "Parsing Zones") + + # go through all envelopes and fill the 'envls' dict with points, normals + # and weights of the box faces + for obj in Blender.Object.Get(): + if obj.getType() == "Mesh": + name = obj.getName() + pos = name.find(SEPARATOR) + if (pos > -1): + mesh = obj.getData() + loc = Vector(list(obj.getLocation())) + + bone_name = name[0:pos] + try: + weight = float(name[pos+1:len(name)]) + except ValueError: + print "WARNING: invalid syntax in envelope name \"%s\" - syntax: \":\""%(obj.getName()) + warn_count += 1 + weight = 0.0 + + envl_data = {'points': [], 'normals': [], 'weight': weight} + for face in mesh.faces: + envl_data['normals'].append(Vector(list(face.normal))) + envl_data['points'].append(Vector(list(face.v[0].co)) + loc) + + if not envls.has_key(bone_name): + # add as first data set + envls[bone_name] = [envl_data] + else: + # add insert in sorted list of data sets + inserted = False + for i in range(len(envls[bone_name])): + if envl_data['weight'] > envls[bone_name][i]['weight']: + envls[bone_name].insert(i, envl_data) + inserted = True + if not inserted: + envls[bone_name].append(envl_data) + + Blender.Window.DrawProgressBar(0.33, "Parsing Vertices") + + assign_count = 0 + vert_groups = {} + + # go throug all vertices of the target mesh + for vert in target_mesh.verts: + point = Vector(list(vert.co)) + main_obj_loc + + vert.sel = 1 + counted = False + + for bone_name in envls.keys(): + for envl_data in envls[bone_name]: + + if (isInside(point, envl_data)): + + if (not vert_groups.has_key(bone_name)): + vert_groups[bone_name] = {} + + if (not vert_groups[bone_name].has_key(envl_data['weight'])): + vert_groups[bone_name][envl_data['weight']] = [] + + vert_groups[bone_name][envl_data['weight']].append(vert.index) + + vert.sel = 0 + + if not counted: + assign_count += 1 + counted = True + + break + + + Blender.Window.DrawProgressBar(0.66, "Writing Groups") + + vert_group_names = target_mesh.getVertGroupNames() + + # delete all vertices in vertex groups + for group in vert_group_names: + try: + v = target_mesh.getVertsFromGroup(group) + except: + pass + else: + # target_mesh.removeVertsFromGroup(group) without second argument doesn't work + #print "removing", len(v), "vertices from group \"",group,"\"" + target_mesh.removeVertsFromGroup(group, v) + + # delete all vertex groups + for group in vert_group_names: + target_mesh.removeVertGroup(group) + + # create new vertex groups and fill them + if 1: + for bone_name in vert_groups.keys(): + # add vertex group + target_mesh.addVertGroup(bone_name) + + for weight in vert_groups[bone_name]: + print "name: ", bone_name, ": ", weight, "len: ", len(vert_groups[bone_name][weight]) + index_list = vert_groups[bone_name][weight] + target_mesh.assignVertsToGroup(bone_name, index_list, weight, 'replace') + + target_mesh.update(0) + + Blender.Window.DrawProgressBar(1.0, "") + + if assign_count < num_verts: + Blender.Window.EditMode(1) + print '\a' + if warn_count: warn_msg = " There is also %d warning(s) in the console."%(warn_count) + else: warn_msg = "" + Blender.Draw.PupMenu("Envelope Assignment%%t|%d vertices were not assigned.%s"%(num_verts-assign_count, warn_msg)) + elif warn_count: + print '\a' + Blender.Draw.PupMenu("Envelope Assignment%%t|There is %d warning(s) in the console."%(warn_count)) + +sel_objs = Blender.Object.GetSelected() +if len(sel_objs) != 1 or sel_objs[0].getType() != "Mesh": + print '\a' + Blender.Draw.PupMenu("Envelope Assignment%t|Please select 1 Mesh object to assign vertex groups to!") +else: + if string.find(sel_objs[0].getName(), SEPARATOR) > -1: + print '\a' + Blender.Draw.PupMenu("Envelope Assignment%t|Don't use the command on the envelopes themselves!") + else: + run(sel_objs[0]) diff --git a/release/scripts/envelope_symmetry.py b/release/scripts/envelope_symmetry.py new file mode 100644 index 00000000000..5a4f7a31b3b --- /dev/null +++ b/release/scripts/envelope_symmetry.py @@ -0,0 +1,176 @@ +#!BPY + +""" +Name: 'Envelope Symmetry' +Blender: 234 +Group: 'Animation' +Tooltip: 'Make envelope symetrical' +""" + +__author__ = "Jonas Petersen" +__url__ = ("blender", "elysiun", "Script's homepage, http://www.mindfloaters.de/blender/", "thread at blender.org, http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4858 ") +__version__ = "0.9 2004-11-10" +__doc__ = """\ +This script creates perfectly symmetrical envelope sets. It is part of the +envelop assignment tools. + +"Envelopes" are Mesh objects with names following this naming convention: + +: + +Please check the script's homepage and the thread at blender.org (last link button above) for more info. + +For this version users need to edit the script code to change default options. +""" + +# -------------------------------------------------------------------------- +# "Envelope Symmetry" by Jonas Petersen +# Version 0.9 - 10th November 2004 - first public release +# -------------------------------------------------------------------------- +# +# A script for creating perfectly symmetrical envelope sets. It is +# part of the envelope assignment tool. +# +# It is available in Object Mode via the menu item: +# +# Object -> Scripts -> Envelope Symmetry +# +# With default settings it will: +# +# - Look for bones +# +# Find the latest version at: http://www.mindfloaters.de/blender/ +# +# -------------------------------------------------------------------------- +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Jonas Petersen, jonas at mindfloaters dot de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +# -------------------------------------------------------------------------- +# CONFIGURATION +# -------------------------------------------------------------------------- + +# Note: Theses values will later be editable via a gui interface +# within Blender. + +# The suffix for the reference and opposite envelope. +# The configuration of of the opposite envelope will be overwritten by +# the configuration of the reference envelope (shape, position, bone, weight). +# The default is REF_SUFFIX = '.L' and OPP_SUFFIX = '.R'. +REF_SUFFIX = '.R' +OPP_SUFFIX = '.L' + +# MIRROR_AXIS defines the axis in which bones are mirrored/aligned. +# Values: +# 0 for X (default) +# 1 for Y +# 2 for Z +MIRROR_AXIS = 0 + +# SEPARATOR is the character used to delimit the bone name and the weight +# in the envelope name. +SEPARATOR = ":" + +# -------------------------------------------------------------------------- +# END OF CONFIGURATION +# -------------------------------------------------------------------------- + +import Blender, math, sys +from Blender import Mathutils +from BPyNMesh import * + +def flipFace(v): + if len(v) == 3: v[0], v[1], v[2] = v[2], v[1], v[0] + elif len(v) == 4: v[0], v[1], v[2], v[3] = v[3], v[2], v[1], v[0] + +# return object with given object name (with variable parts) and mesh name +def getObjectByName(obj_name, mesh_name): + objs = Blender.Object.Get() + for obj in objs: + if obj.getType() == "Mesh": +# if obj.getName()[0:len(obj_name)] == obj_name and obj.getData().name == mesh_name: + # use only mesh_name so bone name and weight (in the envelope name) + # can be changed by the user and mirrored by the script. + if obj.getData().name == mesh_name: + return obj + return False + +SUFFIX_LEN = len(REF_SUFFIX); + +Blender.Window.EditMode(0) + +count = 0 +objs = Blender.Object.Get() +for obj in objs: + if obj.getType() != 'Mesh': + continue + + count += 1 + name = obj.getName() + pos = name.find(SEPARATOR) + if (pos > -1): + ApplySizeAndRotation(obj) + + base_name = name[0:pos-SUFFIX_LEN] + suffix = name[pos-SUFFIX_LEN:pos] + weight = name[pos:len(name)] # the SEPARATOR following a float value + + if suffix == REF_SUFFIX: + mesh = obj.getData() + mirror_name = base_name + OPP_SUFFIX + weight + mirror_mesh_name = mesh.name + ".mirror" + + mirror_obj = getObjectByName(base_name + OPP_SUFFIX, mirror_mesh_name) + + if mirror_obj: + + # update vertices + + mirror_mesh = mirror_obj.getData() + for i in range(len(mesh.verts)): + org = mesh.verts[i] + mir = mirror_mesh.verts[i] + mir.co[0], mir.co[1], mir.co[2] = org.co[0], org.co[1], org.co[2] + mir.co[MIRROR_AXIS] *= -1 + + mirror_mesh.update() + else: + + # create mirror object + + mirror_mesh = Blender.NMesh.GetRaw(obj.getData().name) + for face in mirror_mesh.faces: + flipFace(face.v) + for vert in mirror_mesh.verts: + vert.co[MIRROR_AXIS] *= -1 + + mirror_obj = Blender.NMesh.PutRaw(mirror_mesh, mirror_mesh_name) + + # update name, drawType and location + + mirror_obj.setName(mirror_name) + mirror_obj.drawType = obj.drawType + + loc = [obj.LocX, obj.LocY, obj.LocZ] + loc[MIRROR_AXIS] *= -1 + mirror_obj.setLocation(loc) + +Blender.Window.EditMode(0) diff --git a/release/scripts/fixfromarmature.py b/release/scripts/fixfromarmature.py index 9e11702c0be..a9fea501b87 100644 --- a/release/scripts/fixfromarmature.py +++ b/release/scripts/fixfromarmature.py @@ -1,20 +1,20 @@ #!BPY """ Registration info for Blender menus: <- these words are ignored -Name: 'Fix From Armature' -Blender: 232 +Name: 'Fix From Everything' +Blender: 236 Group: 'Mesh' -Tip: 'Fix armature deformation' +Tip: 'Fix armature/lattice/RVK/curve deform and taper/soft body deformation (without bake)' """ __author__ = "Jean-Michel Soler (jms)" __url__ = ("blender", "elysiun", "Script's homepage, http://jmsoler.free.fr/util/blenderfile/py/fixfromarmature.py", "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") -__version__ = "10/2004" +__version__ = "05/2005" __bpydoc__ = """\ -This script creates a copy of the active mesh with armature deformation fixed. +This script creates a copy of the active mesh with deformations fixed. Usage: @@ -24,7 +24,7 @@ Select the mesh and run this script. A fixed copy of it will be created. # $Id$ # #---------------------------------------------- -# jm soler 05/2004 : 'FixfromArmature' +# jm soler 05/2004-->04/2005 : 'FixfromArmature' #---------------------------------------------- # Official Page : # http://jmsoler.free.fr/util/blenderfile/py/fixfromarmature.py @@ -65,36 +65,50 @@ Select the mesh and run this script. A fixed copy of it will be created. import Blender +def fix_mesh(nomdelobjet): + Mesh=Blender.NMesh.GetRawFromObject(nomdelobjet) + Obis = Blender.Object.New ('Mesh') + Obis.link(Mesh) + Obis.setMatrix(Ozero.getMatrix()) + scene = Blender.Scene.getCurrent() + scene.link (Obis) + + Mesh2=Obis.getData() + Mesh1=Ozero.getData() + + if len(Mesh2.verts)==len(Mesh1.verts): + for VertGroupName in Mesh1.getVertGroupNames(): + VertexList = Mesh1.getVertsFromGroup(VertGroupName, True) + Mesh2.addVertGroup(VertGroupName) + for Vertex in VertexList: + Mesh2.assignVertsToGroup(VertGroupName, [Vertex[0]], Vertex[1], 'add') + else: + for vgroupname in Mesh1.getVertGroupNames(): + Mesh2.addVertGroup(vgroupname) + Mesh2.update() + + Ozero=Blender.Object.GetSelected()[0] errormsg = '' + if not Ozero: - errormsg = "no mesh object selected" + errormsg = "no mesh object selected" elif Ozero.getType() != "Mesh": - errormsg = "selected (active) object must be a mesh" + errormsg = "selected (active) object must be a mesh" if errormsg: - Blender.Draw.PupMenu("ERROR: %s" % errormsg) + Blender.Draw.PupMenu("ERROR: %s" % errormsg) else: - nomdelobjet=Ozero.getName() - Mesh=Blender.NMesh.GetRawFromObject(nomdelobjet) - Obis = Blender.Object.New ('Mesh') - Obis.link(Mesh) - Obis.setMatrix(Ozero.getMatrix()) - scene = Blender.Scene.getCurrent() - scene.link (Obis) - - Mesh2=Obis.getData() - Mesh1=Ozero.getData() - - if len(Mesh2.verts)==len(Mesh1.verts): - for VertGroupName in Mesh1.getVertGroupNames(): - VertexList = Mesh1.getVertsFromGroup(VertGroupName, True) - Mesh2.addVertGroup(VertGroupName) - for Vertex in VertexList: - Mesh2.assignVertsToGroup(VertGroupName, [Vertex[0]], Vertex[1], 'add') - else: - for vgroupname in Ozero.getVertGroupNames(): - Mesh2.addVertGroup(vgroupname) - Mesh2.update() + fix = 1 + curframe = Blender.Get('curframe') + if Ozero.isSB() and curframe != 1: + softbodies=Blender.Draw.PupMenu("Soft Body: play anim up to the current frame to fix it?%t|Yes%x1|No %x2|Cancel %x3") + if softbodies==3: + fix = 0 + elif softbodies==1: + for f in range(1, curframe + 1): + Blender.Set('curframe',f) + if fix: fix_mesh(Ozero.getName()) + diff --git a/release/scripts/knife.py b/release/scripts/knife.py index c58c8b4dada..017b81de393 100644 --- a/release/scripts/knife.py +++ b/release/scripts/knife.py @@ -1,7 +1,7 @@ #!BPY """ -Name: 'Blender Knife Tool' +Name: 'Knife Tool' Blender: 232 Group: 'Object' Tooltip: 'Cut selected mesh(es) along an active plane w/o creating doubles' diff --git a/release/scripts/save_theme.py b/release/scripts/save_theme.py index a79de94f4ea..ba0b9bbcf8f 100644 --- a/release/scripts/save_theme.py +++ b/release/scripts/save_theme.py @@ -9,7 +9,7 @@ Tooltip: 'Save current theme as a bpython script' __author__ = "Willian P. Germano" __url__ = ("blender", "elysiun") -__version__ = "1.1 2005/13/01" +__version__ = "1.2 2005/05/17" __bpydoc__ = """\ This script saves the current Theme in Blender as a Blender Python script. @@ -63,7 +63,7 @@ default_fname = default_fname.replace(' ','_') def write_theme(filename): "Write the current theme as a bpython script" - if filename.find('.py', -3) <= 0: filename += '.py' + if not filename.endswith('.py'): filename += '.py' fout = file(filename, "w") @@ -77,7 +77,7 @@ def write_theme(filename): # \"\"\" __%s__ = "????" -__%s__ = "1.0" +__%s__ = "1.2" __%s__ = ["blender"] __%s__ = \"\"\"\\ You can edit this section to write something about your script that can diff --git a/release/scripts/vrml97_export.py b/release/scripts/vrml97_export.py index 7fb036f9997..478fbf901ad 100644 --- a/release/scripts/vrml97_export.py +++ b/release/scripts/vrml97_export.py @@ -5,7 +5,7 @@ Blender: 235 Group: 'Export' Submenu: 'All Objects...' all Submenu: 'Selected Objects...' selected -Tooltip: 'Export to VRML97 file format (.wrl)' +Tooltip: 'Export to VRML97 (VRML2) file format (.wrl)' """ __author__ = ("Rick Kimball", "Ken Miller", "Steve Matthews", "Bart") diff --git a/release/scripts/x3d_export.py b/release/scripts/x3d_export.py new file mode 100644 index 00000000000..1f869d08464 --- /dev/null +++ b/release/scripts/x3d_export.py @@ -0,0 +1,1045 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'X3D Extensible 3D (.x3d)...' +Blender: 235 +Group: 'Export' +Submenu: 'All Objects...' all +Submenu: 'Selected Objects...' selected +Tooltip: 'Export to Extensible 3D file format (.x3d)' +""" + +__author__ = ("Bart") +__url__ = ["Author's (Bart) homepage, http://www.neeneenee.de/vrml", +"Complete online documentation, http://www.neeneenee.de/blender/x3d/exporting_web3d.html"] +__version__ = "2005/05/10" + + + +__bpydoc__ = """\ +This script exports to X3D file format. + +Usage: + +Run this script from "File->Export" menu. A pop-up will ask whether you +want to export only selected or all relevant objects. + +Known issues:
+ Doesn't handle multiple materials (don't use material indices);
+ Doesn't handle multiple UV textures on a single mesh (create a mesh +for each texture);
+ Can't get the texture array associated with material * not the UV ones; +""" + + +# $Id$ +# +#------------------------------------------------------------------------ +# X3D exporter for blender 2.36 or above +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003,2004: Bart bart@neeneenee.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# + +#################################### +# Library dependancies +#################################### + +import Blender +from Blender import Object, NMesh, Lamp, Draw, BGL, Image, Text +from Blender.Scene import Render +from os.path import exists, join +pytinst = 1 +import math, sys, datetime + +#################################### +# Global Variables +#################################### + +scene = Blender.Scene.getCurrent() +world = Blender.World.Get() +worldmat = Blender.Texture.Get() +filename = Blender.Get('filename') +_safeOverwrite = True +radD=math.pi/180.0 +ARG='' + +def rad2deg(v): + return round(v*180.0/math.pi,4) + +def deg2rad(v): + return (v*math.pi)/180.0; + +class DrawTypes: + """Object DrawTypes enum values + BOUNDS - draw only the bounding box of the object + WIRE - draw object as a wire frame + SOLID - draw object with flat shading + SHADED - draw object with OpenGL shading +""" + BOUNDBOX = 1 + WIRE = 2 + SOLID = 3 + SHADED = 4 + TEXTURE = 5 + +if not hasattr(Blender.Object,'DrawTypes'): + Blender.Object.DrawTypes = DrawTypes() + +########################################################## +# Functions for writing output file +########################################################## + +class VRML2Export: + + def __init__(self, filename): + #--- public you can change these --- + self.writingcolor = 0 + self.writingtexture = 0 + self.writingcoords = 0 + self.wire = 0 + self.proto = 1 + self.matonly = 0 + self.share = 0 + self.billnode = 0 + self.halonode = 0 + self.collnode = 0 + self.tilenode = 0 + self.verbose=2 # level of verbosity in console 0-none, 1-some, 2-most + self.cp=3 # decimals for material color values 0.000 - 1.000 + self.vp=3 # decimals for vertex coordinate values 0.000 - n.000 + self.tp=3 # decimals for texture coordinate values 0.000 - 1.000 + self.it=3 + + #--- class private don't touch --- + self.texNames={} # dictionary of textureNames + self.matNames={} # dictionary of materiaNames + self.meshNames={} # dictionary of meshNames + self.indentLevel=0 # keeps track of current indenting + self.filename=filename + self.file = open(filename, "w") + self.bNav=0 + self.nodeID=0 + self.namesReserved=[ "Anchor","Appearance","Arc2D","ArcClose2D","AudioClip","Background","Billboard", + "BooleanFilter","BooleanSequencer","BooleanToggle","BooleanTrigger","Box","Circle2D", + "Collision","Color","ColorInterpolator","ColorRGBA","component","Cone","connect", + "Contour2D","ContourPolyline2D","Coordinate","CoordinateDouble","CoordinateInterpolator", + "CoordinateInterpolator2D","Cylinder","CylinderSensor","DirectionalLight","Disk2D", + "ElevationGrid","EspduTransform","EXPORT","ExternProtoDeclare","Extrusion","field", + "fieldValue","FillProperties","Fog","FontStyle","GeoCoordinate","GeoElevationGrid", + "GeoLocation","GeoLOD","GeoMetadata","GeoOrigin","GeoPositionInterpolator", + "GeoTouchSensor","GeoViewpoint","Group","HAnimDisplacer","HAnimHumanoid","HAnimJoint", + "HAnimSegment","HAnimSite","head","ImageTexture","IMPORT","IndexedFaceSet", + "IndexedLineSet","IndexedTriangleFanSet","IndexedTriangleSet","IndexedTriangleStripSet", + "Inline","IntegerSequencer","IntegerTrigger","IS","KeySensor","LineProperties","LineSet", + "LoadSensor","LOD","Material","meta","MetadataDouble","MetadataFloat","MetadataInteger", + "MetadataSet","MetadataString","MovieTexture","MultiTexture","MultiTextureCoordinate", + "MultiTextureTransform","NavigationInfo","Normal","NormalInterpolator","NurbsCurve", + "NurbsCurve2D","NurbsOrientationInterpolator","NurbsPatchSurface", + "NurbsPositionInterpolator","NurbsSet","NurbsSurfaceInterpolator","NurbsSweptSurface", + "NurbsSwungSurface","NurbsTextureCoordinate","NurbsTrimmedSurface","OrientationInterpolator", + "PixelTexture","PlaneSensor","PointLight","PointSet","Polyline2D","Polypoint2D", + "PositionInterpolator","PositionInterpolator2D","ProtoBody","ProtoDeclare","ProtoInstance", + "ProtoInterface","ProximitySensor","ReceiverPdu","Rectangle2D","ROUTE","ScalarInterpolator", + "Scene","Script","Shape","SignalPdu","Sound","Sphere","SphereSensor","SpotLight","StaticGroup", + "StringSensor","Switch","Text","TextureBackground","TextureCoordinate","TextureCoordinateGenerator", + "TextureTransform","TimeSensor","TimeTrigger","TouchSensor","Transform","TransmitterPdu", + "TriangleFanSet","TriangleSet","TriangleSet2D","TriangleStripSet","Viewpoint","VisibilitySensor", + "WorldInfo","X3D","XvlShell","VertexShader","FragmentShader","MultiShaderAppearance","ShaderAppearance" ] + self.namesStandard=[ "Empty","Empty.000","Empty.001","Empty.002","Empty.003","Empty.004","Empty.005", + "Empty.006","Empty.007","Empty.008","Empty.009","Empty.010","Empty.011","Empty.012", + "Scene.001","Scene.002","Scene.003","Scene.004","Scene.005","Scene.06","Scene.013", + "Scene.006","Scene.007","Scene.008","Scene.009","Scene.010","Scene.011","Scene.012", + "World","World.000","World.001","World.002","World.003","World.004","World.005" ] + self.namesFog=[ "","LINEAR","EXPONENTIAL","" ] + +########################################################## +# Writing nodes routines +########################################################## + + def writeHeader(self): + self.file.write("\n") + self.file.write("\n") + self.file.write("\n") + self.file.write("\n") + self.file.write("\t\n" % filename) + self.file.write("\t\n" % Blender.Get('version')) + self.file.write("\t\n") + self.file.write("\n") + self.file.write("\n") + + def writeInline(self): + inlines = Blender.Scene.Get() + allinlines = len(inlines) + if scene != inlines[0]: + return + else: + for i in range(allinlines): + nameinline=inlines[i].getName() + if (nameinline not in self.namesStandard) and (i > 0): + self.file.write("" % nameinline) + self.file.write("\n\n") + + def writeScript(self): + textEditor = Blender.Text.Get() + alltext = len(textEditor) + for i in range(alltext): + nametext = textEditor[i].getName() + nlines = textEditor[i].getNLines() + if (self.proto == 1): + if (nametext == "proto" or nametext == "proto.js" or nametext == "proto.txt") and (nlines != None): + nalllines = len(textEditor[i].asLines()) + alllines = textEditor[i].asLines() + for j in range(nalllines): + self.writeIndented(alllines[j] + "\n") + elif (self.proto == 0): + if (nametext == "route" or nametext == "route.js" or nametext == "route.txt") and (nlines != None): + nalllines = len(textEditor[i].asLines()) + alllines = textEditor[i].asLines() + for j in range(nalllines): + self.writeIndented(alllines[j] + "\n") + self.writeIndented("\n") + + def writeViewpoint(self, thisObj): + context = scene.getRenderingContext() + ratio = float(context.imageSizeY())/float(context.imageSizeX()) + lens = (360* (math.atan(ratio *16 / thisObj.data.getLens()) / 3.141593))*(3.141593/180) + if lens > 3.14: + lens = 3.14 + # get the camera location, subtract 90 degress from X to orient like X3D does + loc = self.rotatePointForVRML(thisObj.loc) + rot = [thisObj.RotX - 1.57, thisObj.RotY, thisObj.RotZ] + nRot = self.rotatePointForVRML(rot) + # convert to Quaternion and to Angle Axis + Q = self.eulerToQuaternions(nRot[0], nRot[1], nRot[2]) + Q1 = self.multiplyQuaternions(Q[0], Q[1]) + Qf = self.multiplyQuaternions(Q1, Q[2]) + angleAxis = self.quaternionToAngleAxis(Qf) + self.file.write("\n\n" % (lens)) + + def writeFog(self): + if len(world) > 0: + mtype = world[0].getMistype() + mparam = world[0].getMist() + grd = world[0].getHor() + grd0, grd1, grd2 = grd[0], grd[1], grd[2] + else: + return + if (mtype == 1 or mtype == 2): + self.file.write("\n\n" % round(mparam[2],self.cp)) + else: + return + + def writeNavigationInfo(self, scene): + allObj = [] + allObj = scene.getChildren() + headlight = "TRUE" + vislimit = 0.0 + for thisObj in allObj: + objType=thisObj.getType() + if objType == "Camera": + vislimit = thisObj.data.getClipEnd() + elif objType == "Lamp": + headlight = "FALSE" + self.file.write("\n\n") + + def writeSpotLight(self, object, lamp): + safeName = self.cleanStr(object.name) + if len(world) > 0: + ambi = world[0].getAmb() + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + # compute cutoff and beamwidth + intensity=min(lamp.energy/1.5,1.0) + beamWidth=deg2rad(lamp.spotSize)*.37; + cutOffAngle=beamWidth*1.3 + + (dx,dy,dz)=self.computeDirection(object) + # note -dx seems to equal om[3][0] + # note -dz seems to equal om[3][1] + # note dy seems to equal om[3][2] + om = object.getMatrix() + + location=self.rotVertex(om, (0,0,0)); + radius = lamp.dist*math.cos(beamWidth) + self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + + def writeDirectionalLight(self, object, lamp): + safeName = self.cleanStr(object.name) + if len(world) > 0: + ambi = world[0].getAmb() + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + intensity=min(lamp.energy/1.5, 1.0) + (dx,dy,dz)=self.computeDirection(object) + self.file.write("\n\n" % (round(dx,4),round(dy,4),round(dz,4))) + + def writePointLight(self, object, lamp): + safeName = self.cleanStr(object.name) + if len(world) > 0: + ambi = world[0].getAmb() + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + om = object.getMatrix() + location=self.rotVertex(om, (0,0,0)); + intensity=min(lamp.energy/1.5,1.0) + radius = lamp.dist + self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + + def writeNode(self, thisObj): + objectname=str(thisObj.getName()) + if objectname in self.namesStandard: + return + else: + (dx,dy,dz)=self.computeDirection(thisObj) + om = thisObj.getMatrix() + location=self.rotVertex(om, (0,0,0)); + self.writeIndented("<%s\n" % objectname,1) + self.writeIndented("# direction %s %s %s\n" % (round(dx,3),round(dy,3),round(dz,3))) + self.writeIndented("# location %s %s %s\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + self.writeIndented("/>\n",-1) + self.writeIndented("\n") + def createDef(self, name): + name = name + str(self.nodeID) + self.nodeID=self.nodeID+1 + if len(name) <= 3: + newname = "_" + str(self.nodeID) + return "%s" % (newname) + else: + for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']: + name=name.replace(bad,'_') + if name in self.namesReserved: + newname = name[0:3] + "_" + str(self.nodeID) + return "%s" % (newname) + elif name[0].isdigit(): + newname = "_" + name + str(self.nodeID) + return "%s" % (newname) + else: + newname = name + return "%s" % (newname) + + def secureName(self, name): + name = name + str(self.nodeID) + self.nodeID=self.nodeID+1 + if len(name) <= 3: + newname = "_" + str(self.nodeID) + return "%s" % (newname) + else: + for bad in ['"','#',"'",',','.','[','\\',']','{','}']: + name=name.replace(bad,'_') + if name in self.namesReserved: + newname = name[0:3] + "_" + str(self.nodeID) + return "%s" % (newname) + elif name[0].isdigit(): + newname = "_" + name + str(self.nodeID) + return "%s" % (newname) + else: + newname = name + return "%s" % (newname) + + def writeIndexedFaceSet(self, object, normals = 0): + + imageMap={} # set of used images + sided={} # 'one':cnt , 'two':cnt + vColors={} # 'multi':1 + meshName = self.cleanStr(object.name) + mesh=object.getData() + meshME = self.cleanStr(mesh.name) + for face in mesh.faces: + if face.mode & Blender.NMesh.FaceModes['HALO'] and self.halonode == 0: + self.writeIndented("\n",1) + self.halonode = 1 + elif face.mode & Blender.NMesh.FaceModes['BILLBOARD'] and self.billnode == 0: + self.writeIndented("\n",1) + self.billnode = 1 + elif face.mode & Blender.NMesh.FaceModes['OBCOL'] and self.matonly == 0: + self.matonly = 1 + elif face.mode & Blender.NMesh.FaceModes['SHAREDCOL'] and self.share == 0: + self.share = 1 + elif face.mode & Blender.NMesh.FaceModes['TILES'] and self.tilenode == 0: + self.tilenode = 1 + elif not face.mode & Blender.NMesh.FaceModes['DYNAMIC'] and self.collnode == 0: + self.writeIndented("\n",1) + self.collnode = 1 + + nIFSCnt=self.countIFSSetsNeeded(mesh, imageMap, sided, vColors) + + if nIFSCnt > 1: + self.writeIndented("\n" % ("G_", meshName),1) + + if sided.has_key('two') and sided['two'] > 0: + bTwoSided=1 + else: + bTwoSided=0 + om = object.getMatrix(); + location=self.rotVertex(om, (0,0,0)); + self.writeIndented("\n" % (round(location[0],3), round(location[1],3), round(location[2],3)),1) + self.writeIndented("\n" % meshName,1) + + maters=mesh.materials + hasImageTexture=0 + issmooth=0 + + if len(maters) > 0 or mesh.hasFaceUV(): + self.writeIndented("\n", 1) + + # right now this script can only handle a single material per mesh. + if len(maters) >= 1: + mat=Blender.Material.Get(maters[0].name) + self.writeMaterial(mat, self.cleanStr(maters[0].name,'')) + if len(maters) > 1: + print "Warning: mesh named %s has multiple materials" % meshName + print "Warning: only one material per object handled" + else: + self.writeIndented("\n") + + #-- textures + if mesh.hasFaceUV(): + for face in mesh.faces: + if (hasImageTexture == 0) and (face.image): + self.writeImageTexture(face.image.name) + hasImageTexture=1 # keep track of face texture + if self.tilenode == 1: + self.writeIndented("\n" % (face.image.xrep, face.image.yrep)) + self.tilenode = 0 + self.writeIndented("\n", -1) + + #-- IndexedFaceSet or IndexedLineSet + + # check if object is wireframe only + if object.drawType == Blender.Object.DrawTypes.WIRE: + # user selected WIRE=2 on the Drawtype=Wire on (F9) Edit page + ifStyle="IndexedLineSet" + self.wire = 1 + else: + # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5 + ifStyle="IndexedFaceSet" + # look up mesh name, use it if available + if self.meshNames.has_key(meshME): + self.writeIndented("<%s USE=\"ME_%s\">" % (ifStyle, meshME), 1) + self.meshNames[meshME]+=1 + else: + if int(mesh.users) > 1: + self.writeIndented("<%s DEF=\"ME_%s\" " % (ifStyle, meshME), 1) + self.meshNames[meshME]=1 + else: + self.writeIndented("<%s " % ifStyle, 1) + if object.drawType != Blender.Object.DrawTypes.WIRE: + if bTwoSided == 1: + self.file.write("solid=\"false\" ") + else: + self.file.write("solid=\"true\" ") + + for face in mesh.faces: + if face.smooth: + issmooth=1 + if issmooth==1 and self.wire == 0: + creaseAngle=(mesh.getMaxSmoothAngle())*radD + self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp))) + + #--- output vertexColors + if self.share == 1 and self.matonly == 0: + self.writeVertexColors(mesh) + if object.drawType != Blender.Object.DrawTypes.WIRE: + #--- output textureCoordinates if UV texture used + if mesh.hasFaceUV(): + if self.matonly == 1 and self.share == 1: + self.writeFaceColors(mesh) + elif hasImageTexture == 1: + self.writeTextureCoordinates(mesh) + #--- output coordinates + self.writeCoordinates(object, mesh, meshName) + + self.writingcoords = 1 + self.writingtexture = 1 + self.writingcolor = 1 + self.writeCoordinates(object, mesh, meshName) + + if object.drawType != Blender.Object.DrawTypes.WIRE: + #--- output textureCoordinates if UV texture used + if mesh.hasFaceUV(): + if hasImageTexture == 1: + self.writeTextureCoordinates(mesh) + elif self.matonly == 1 and self.share == 1: + self.writeFaceColors(mesh) + #--- output vertexColors + if self.share == 1 and self.matonly == 0: + self.writeVertexColors(mesh) + self.matonly = 0 + self.share = 0 + self.wire = 0 + self.writingcoords = 0 + self.writingtexture = 0 + self.writingcolor = 0 + #--- output closing braces + self.writeIndented("\n" % ifStyle, -1) + self.writeIndented("\n", -1) + self.writeIndented("\n", -1) + + if self.halonode == 1: + self.writeIndented("\n", -1) + self.halonode = 0 + + if self.billnode == 1: + self.writeIndented("\n", -1) + self.billnode = 0 + + if self.collnode == 1: + self.writeIndented("\n", -1) + self.collnode = 0 + + if nIFSCnt > 1: + self.writeIndented("\n", -1) + + self.file.write("\n") + + def writeCoordinates(self, object, mesh, meshName): + meshVertexList = mesh.verts + + # create vertex list and pre rotate -90 degrees X for VRML + mm=object.getMatrix() + location=self.rotVertex(mm, (0,0,0)); + if self.writingcoords == 0: + self.file.write("coordIndex=\"") + coordIndexList=[] + for face in mesh.faces: + cordStr="" + for i in range(len(face)): + indx=meshVertexList.index(face[i]) + cordStr = cordStr + "%s " % indx + self.file.write(cordStr + "-1, ") + self.file.write("\">\n") + else: + #-- vertices + self.writeIndented("") + self.writeIndented("\n", -1) + + def writeTextureCoordinates(self, mesh): + texCoordList=[] + texIndexList=[] + j=0 + + for face in mesh.faces: + for i in range(len(face)): + texIndexList.append(j) + texCoordList.append(face.uv[i]) + j=j+1 + texIndexList.append(-1) + if self.writingtexture == 0: + self.file.write("\n\t\t\ttexCoordIndex=\"") + texIndxStr="" + for i in range(len(texIndexList)): + texIndxStr = texIndxStr + "%d, " % texIndexList[i] + if texIndexList[i]==-1: + self.file.write(texIndxStr) + texIndxStr="" + self.file.write("\"\n\t\t\t") + else: + self.writeIndented("") + self.writeIndented("\n", -1) + + def writeFaceColors(self, mesh): + if self.writingcolor == 0: + self.file.write("colorPerVertex=\"false\" ") + else: + self.writeIndented(" 2: + print "Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b) + aColor = self.rgbToFS(c) + self.file.write("%s, " % aColor) + self.file.write("\" />") + self.writeIndented("\n",-1) + + def writeVertexColors(self, mesh): + if self.writingcolor == 0: + self.file.write("colorPerVertex=\"false\" ") + else: + self.writeIndented(" 2: + print "Debug: vertex[%d].col r=%d g=%d b=%d" % (i, c.r, c.g, c.b) + + aColor = self.rgbToFS(c) + self.file.write("%s, " % aColor) + self.file.write("\" />") + self.writeIndented("\n",-1) + + def writeMaterial(self, mat, matName): + # look up material name, use it if available + if self.matNames.has_key(matName): + self.writeIndented("\n" % matName) + self.matNames[matName]+=1 + return; + + self.matNames[matName]=1 + + ambient = mat.amb/2 + diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2] + if len(world) > 0: + ambi = world[0].getAmb() + ambi0, ambi1, ambi2 = ambi[0], ambi[1], ambi[2] + else: + ambi = 0 + ambi0, ambi1, ambi2 = 0, 0, 0 + emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/4, (diffuseG*mat.emit+ambi1)/4, (diffuseB*mat.emit+ambi2)/4 + + shininess = mat.hard/255.0 + specR = (mat.specCol[0]+0.001)/(1.05/(mat.getSpec()+0.001)) + specG = (mat.specCol[1]+0.001)/(1.05/(mat.getSpec()+0.001)) + specB = (mat.specCol[2]+0.001)/(1.05/(mat.getSpec()+0.001)) + transp = 1-mat.alpha + + self.writeIndented("" % (round(transp,self.cp))) + self.writeIndented("\n",-1) + + def writeImageTexture(self, name): + if self.texNames.has_key(name): + self.writeIndented("\n" % self.cleanStr(name)) + self.texNames[name] += 1 + return + else: + self.writeIndented("" % name) + self.writeIndented("\n",-1) + self.texNames[name] = 1 + + def writeBackground(self): + if len(world) > 0: + worldname = world[0].getName() + else: + return + blending = world[0].getSkytype() + grd = world[0].getHor() + grd0, grd1, grd2 = grd[0], grd[1], grd[2] + sky = world[0].getZen() + sky0, sky1, sky2 = sky[0], sky[1], sky[2] + mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2] + mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2 + self.file.write("\n\n") + +########################################################## +# export routine +########################################################## + + def export(self, scene, world, worldmat): + print "Info: starting X3D export to " + self.filename + "..." + self.writeHeader() + self.writeScript() + self.writeNavigationInfo(scene) + self.writeBackground() + self.writeFog() + self.proto = 0 + allObj = [] + if ARG == 'selected': + allObj = Blender.Object.GetSelected() + else: + allObj = scene.getChildren() + self.writeInline() + for thisObj in allObj: + try: + objType=thisObj.getType() + objName=thisObj.getName() + self.matonly = 0 + if objType == "Camera": + self.writeViewpoint(thisObj) + elif objType == "Mesh": + self.writeIndexedFaceSet(thisObj, normals = 0) + elif objType == "Lamp": + lmpName=Lamp.Get(thisObj.data.getName()) + lmpType=lmpName.getType() + if lmpType == Lamp.Types.Lamp: + self.writePointLight(thisObj, lmpName) + elif lmpType == Lamp.Types.Spot: + self.writeSpotLight(thisObj, lmpName) + elif lmpType == Lamp.Types.Sun: + self.writeDirectionalLight(thisObj, lmpName) + else: + self.writeDirectionalLight(thisObj, lmpName) + elif objType == "Empty" and objName != "Empty": + self.writeNode(thisObj) + else: + #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType()) + print "" + except AttributeError: + print "Error: Unable to get type info for %s" % thisObj.getName() + if ARG != 'selected': + self.writeScript() + self.file.write("\n\n") + self.cleanup() + +########################################################## +# Utility methods +########################################################## + + def cleanup(self): + self.file.close() + self.texNames={} + self.matNames={} + self.indentLevel=0 + print "Info: finished X3D export to %s\n" % self.filename + + def cleanStr(self, name, prefix='rsvd_'): + """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name""" + + newName=name[:] + if len(newName) == 0: + self.nNodeID+=1 + return "%s%d" % (prefix, self.nNodeID) + + if newName in self.namesReserved: + newName='%s%s' % (prefix,newName) + + if newName[0].isdigit(): + newName='%s%s' % ('_',newName) + + for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']: + newName=newName.replace(bad,'_') + return newName + + def countIFSSetsNeeded(self, mesh, imageMap, sided, vColors): + """ + countIFFSetsNeeded() - should look at a blender mesh to determine + how many VRML IndexFaceSets or IndexLineSets are needed. A + new mesh created under the following conditions: + + o - split by UV Textures / one per mesh + o - split by face, one sided and two sided + o - split by smooth and flat faces + o - split when faces only have 2 vertices * needs to be an IndexLineSet + """ + + imageNameMap={} + faceMap={} + nFaceIndx=0 + + for face in mesh.faces: + sidename=''; + if (face.mode & NMesh.FaceModes.TWOSIDE) == NMesh.FaceModes.TWOSIDE: + sidename='two' + else: + sidename='one' + + if not vColors.has_key('multi'): + for face in mesh.faces: + if face.col: + c=face.col[0] + if c.r != 255 and c.g != 255 and c.b !=255: + vColors['multi']=1 + + if sided.has_key(sidename): + sided[sidename]+=1 + else: + sided[sidename]=1 + + if face.image: + faceName="%s_%s" % (face.image.name, sidename); + + if imageMap.has_key(faceName): + imageMap[faceName].append(face) + else: + imageMap[faceName]=[face.image.name,sidename,face] + + if self.verbose > 2: + for faceName in imageMap.keys(): + ifs=imageMap[faceName] + print "Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \ + (faceName, ifs[0], ifs[1], len(ifs)-2) + + return len(imageMap.keys()) + + def faceToString(self,face): + + print "Debug: face.flag=0x%x (bitflags)" % face.flag + if face.flag & NMesh.FaceFlags.SELECT == NMesh.FaceFlags.SELECT: + print "Debug: face.flag.SELECT=true" + + print "Debug: face.mode=0x%x (bitflags)" % face.mode + if (face.mode & NMesh.FaceModes.TWOSIDE) == NMesh.FaceModes.TWOSIDE: + print "Debug: face.mode twosided" + + print "Debug: face.transp=0x%x (enum)" % face.transp + if face.transp == NMesh.FaceTranspModes.SOLID: + print "Debug: face.transp.SOLID" + + if face.image: + print "Debug: face.image=%s" % face.image.name + print "Debug: face.materialIndex=%d" % face.materialIndex + + def getVertexColorByIndx(self, mesh, indx): + for face in mesh.faces: + j=0 + for vertex in face.v: + if vertex.index == indx: + c=face.col[j] + j=j+1 + return c + + def meshToString(self,mesh): + print "Debug: mesh.hasVertexUV=%d" % mesh.hasVertexUV() + print "Debug: mesh.hasFaceUV=%d" % mesh.hasFaceUV() + print "Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours() + print "Debug: mesh.verts=%d" % len(mesh.verts) + print "Debug: mesh.faces=%d" % len(mesh.faces) + print "Debug: mesh.materials=%d" % len(mesh.materials) + + def rgbToFS(self, c): + s="%s %s %s" % ( + round(c.r/255.0,self.cp), + round(c.g/255.0,self.cp), + round(c.b/255.0,self.cp)) + return s + + def computeDirection(self, object): + x,y,z=(0,-1.0,0) # point down + ax,ay,az = (object.RotX,object.RotZ,object.RotY) + + # rot X + x1=x + y1=y*math.cos(ax)-z*math.sin(ax) + z1=y*math.sin(ax)+z*math.cos(ax) + + # rot Y + x2=x1*math.cos(ay)+z1*math.sin(ay) + y2=y1 + z2=z1*math.cos(ay)-x1*math.sin(ay) + + # rot Z + x3=x2*math.cos(az)-y2*math.sin(az) + y3=x2*math.sin(az)+y2*math.cos(az) + z3=z2 + + return [x3,y3,z3] + + + # swap Y and Z to handle axis difference between Blender and VRML + #------------------------------------------------------------------------ + def rotatePointForVRML(self, v): + x = v[0] + y = v[2] + z = -v[1] + + vrmlPoint=[x, y, z] + return vrmlPoint + + def rotVertex(self, mm, v): + lx,ly,lz=v[0],v[1],v[2] + gx=(mm[0][0]*lx + mm[1][0]*ly + mm[2][0]*lz) + mm[3][0] + gy=((mm[0][2]*lx + mm[1][2]*ly+ mm[2][2]*lz) + mm[3][2]) + gz=-((mm[0][1]*lx + mm[1][1]*ly + mm[2][1]*lz) + mm[3][1]) + rotatedv=[gx,gy,gz] + return rotatedv + + # For writing well formed VRML code + #------------------------------------------------------------------------ + def writeIndented(self, s, inc=0): + if inc < 1: + self.indentLevel = self.indentLevel + inc + + spaces="" + for x in xrange(self.indentLevel): + spaces = spaces + "\t" + self.file.write(spaces + s) + + if inc > 0: + self.indentLevel = self.indentLevel + inc + + # Converts a Euler to three new Quaternions + # Angles of Euler are passed in as radians + #------------------------------------------------------------------------ + def eulerToQuaternions(self, x, y, z): + Qx = [math.cos(x/2), math.sin(x/2), 0, 0] + Qy = [math.cos(y/2), 0, math.sin(y/2), 0] + Qz = [math.cos(z/2), 0, 0, math.sin(z/2)] + + quaternionVec=[Qx,Qy,Qz] + return quaternionVec + + # Multiply two Quaternions together to get a new Quaternion + #------------------------------------------------------------------------ + def multiplyQuaternions(self, Q1, Q2): + result = [((Q1[0] * Q2[0]) - (Q1[1] * Q2[1]) - (Q1[2] * Q2[2]) - (Q1[3] * Q2[3])), + ((Q1[0] * Q2[1]) + (Q1[1] * Q2[0]) + (Q1[2] * Q2[3]) - (Q1[3] * Q2[2])), + ((Q1[0] * Q2[2]) + (Q1[2] * Q2[0]) + (Q1[3] * Q2[1]) - (Q1[1] * Q2[3])), + ((Q1[0] * Q2[3]) + (Q1[3] * Q2[0]) + (Q1[1] * Q2[2]) - (Q1[2] * Q2[1]))] + + return result + + # Convert a Quaternion to an Angle Axis (ax, ay, az, angle) + # angle is in radians + #------------------------------------------------------------------------ + def quaternionToAngleAxis(self, Qf): + scale = math.pow(Qf[1],2) + math.pow(Qf[2],2) + math.pow(Qf[3],2) + ax = Qf[1] + ay = Qf[2] + az = Qf[3] + + if scale > .0001: + ax/=scale + ay/=scale + az/=scale + + angle = 2 * math.acos(Qf[0]) + + result = [ax, ay, az, angle] + return result + +########################################################## +# Callbacks, needed before Main +########################################################## + +def select_file(filename): + if pytinst == 1: + if exists(filename) and _safeOverwrite: + result = Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0") + if(result != 1): + return + + if not filename.endswith('.x3d'): filename += '.x3d' + wrlexport=VRML2Export(filename) + wrlexport.export(scene, world, worldmat) + +def createWRLPath(): + filename = Blender.Get('filename') + #print filename + + if filename.find('.') != -1: + filename = filename.split('.')[0] + filename += ".x3d" + #print filename + + return filename + +######################################################### +# main routine +######################################################### + +try: + ARG = __script__['arg'] # user selected argument +except: + print "older version" + +if Blender.Get('version') < 235: + print "Warning: X3D 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: + Blender.Window.FileSelector(select_file,"Export X3D",createWRLPath()) -- cgit v1.2.3