- removed 2.4x release/scripts
- moved release/io and release/ui into release/scripts/io, ui - updated scons, cmake, make When porting 2.4x scripts back, use a command like this so as not to loose the commit history... svn cp https://svn.blender.org/svnroot/bf-blender/branches/blender2.4/release/scripts/raw_import.py release/scripts/io/import_raw.py
This commit is contained in:
@@ -476,8 +476,8 @@ if env['OURPLATFORM']!='darwin':
|
||||
dotblenderinstall.append(env.Install(dir=td, source=srcfile))
|
||||
|
||||
if env['WITH_BF_PYTHON']:
|
||||
#-- .blender/scripts, .blender/ui, .blender/io
|
||||
scriptpaths=['release/scripts', 'release/ui', 'release/io']
|
||||
#-- .blender/scripts
|
||||
scriptpaths=['release/scripts']
|
||||
for scriptpath in scriptpaths:
|
||||
for dp, dn, df in os.walk(scriptpath):
|
||||
if '.svn' in dn:
|
||||
|
||||
@@ -153,9 +153,6 @@ endif
|
||||
|
||||
@echo "----> Copy python infrastructure"
|
||||
@[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts
|
||||
|
||||
@echo "----> Copy python UI files"
|
||||
@[ ! -d ui ] || cp -r ui $(CONFDIR)/ui
|
||||
|
||||
ifeq ($(OS),darwin)
|
||||
@echo "----> Copy python modules"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,125 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus: <- these words are ignored
|
||||
Name: 'Axis Orientation Copy'
|
||||
Blender: 242
|
||||
Group: 'Object'
|
||||
Tip: 'Copy local axis orientation of active object to all selected meshes (changes mesh data)'
|
||||
"""
|
||||
|
||||
__author__ = "A Vanpoucke (xand)"
|
||||
__url__ = ("blenderartists.org", "www.blender.org",
|
||||
"French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
||||
__version__ = "2 17/12/05"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script copies the axis orientation -- X, Y and Z rotations -- of the
|
||||
active object to all selected meshes.
|
||||
|
||||
It's useful to align the orientations of all meshes of a structure, a human
|
||||
skeleton, for example.
|
||||
|
||||
Usage:
|
||||
|
||||
Select all mesh objects that need to have their orientations changed
|
||||
(reminder: keep SHIFT pressed after the first, to add each new one to the
|
||||
selection), then select the object whose orientation will be copied from and
|
||||
finally run this script to update the angles.
|
||||
|
||||
Notes:<br>
|
||||
This script changes mesh data: the vertices are transformed.<br>
|
||||
Before copying the orientation to each object, the script stores its
|
||||
transformation matrix. Then the angles are copied and after that the object's
|
||||
vertices are transformed "back" so that they still have the same positions as
|
||||
before. In other words, the rotations are updated, but you won't notice that
|
||||
just from looking at the objects.<br>
|
||||
Checking their X, Y and Z rotation values with "Transform Properties" in
|
||||
the 3D View's Object menu shows the angles are now the same of the active
|
||||
object. Or simply look at the transform manipulator handles in local transform
|
||||
orientation.
|
||||
"""
|
||||
|
||||
|
||||
# $Id$
|
||||
#
|
||||
#----------------------------------------------
|
||||
# A Vanpoucke (xand)
|
||||
#from the previous script realignaxis
|
||||
#----------------------------------------------
|
||||
# Communiquer les problemes et erreurs sur:
|
||||
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2003, 2004: A Vanpoucke
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
from Blender import *
|
||||
from Blender import Mathutils
|
||||
from Blender.Mathutils import *
|
||||
import BPyMessages
|
||||
|
||||
def realusers(data):
|
||||
users = data.users
|
||||
if data.fakeUser: users -= 1
|
||||
return users
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
scn_obs= Scene.GetCurrent().objects
|
||||
ob_act = scn_obs.active
|
||||
scn_obs = scn_obs.context
|
||||
|
||||
if not ob_act:
|
||||
BPyMessages.Error_NoActive()
|
||||
|
||||
obs = [(ob, ob.getData(mesh=1)) for ob in scn_obs if ob != ob_act]
|
||||
|
||||
for ob, me in obs:
|
||||
|
||||
if ob.type != 'Mesh':
|
||||
Draw.PupMenu("Error%t|Selection must be made up of mesh objects only")
|
||||
return
|
||||
|
||||
if realusers(me) != 1:
|
||||
Draw.PupMenu("Error%t|Meshes must be single user")
|
||||
return
|
||||
|
||||
if len(obs) < 1:
|
||||
Draw.PupMenu("Error: you must select at least 2 objects")
|
||||
return
|
||||
|
||||
result = Draw.PupMenu("Copy axis orientation from: " + ob_act.name + " ?%t|OK")
|
||||
if result == -1:
|
||||
return
|
||||
|
||||
for ob_target, me_target in obs:
|
||||
if ob_act.rot != ob_target.rot:
|
||||
rot_target = ob_target.matrixWorld.rotationPart().toEuler().toMatrix()
|
||||
rot_source = ob_act.matrixWorld.rotationPart().toEuler().toMatrix()
|
||||
rot_source_inv = rot_source.copy().invert()
|
||||
tx_mat = rot_target * rot_source_inv
|
||||
tx_mat.resize4x4()
|
||||
me_target.transform(tx_mat)
|
||||
ob_target.rot=ob_act.rot
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus:
|
||||
Name: 'DirectX(.x)...'
|
||||
Blender: 244
|
||||
Group: 'Import'
|
||||
|
||||
Tip: 'Import from DirectX text file format format.'
|
||||
"""
|
||||
# DirectXImporter.py version 1.2
|
||||
# Copyright (C) 2005 Arben OMARI -- omariarben@everyday.com
|
||||
#
|
||||
# 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.
|
||||
|
||||
# This script import meshes from DirectX text file format
|
||||
|
||||
# Grab the latest version here :www.omariben.too.it
|
||||
import bpy
|
||||
import Blender
|
||||
from Blender import Mesh,Object,Material,Texture,Image,Draw
|
||||
|
||||
|
||||
class xImport:
|
||||
def __init__(self, filename):
|
||||
global my_path
|
||||
self.file = open(filename, "r")
|
||||
my_path = Blender.sys.dirname(filename)
|
||||
|
||||
#
|
||||
self.lines = [l_split for l in self.file.readlines() for l_split in (' '.join(l.split()),) if l_split]
|
||||
|
||||
def Import(self):
|
||||
lines = self.lines
|
||||
print "importing into Blender ..."
|
||||
scene = bpy.data.scenes.active
|
||||
|
||||
mesh_indicies = {} # the index of each 'Mesh' is used as the key for those meshes indicies
|
||||
context_indicies = None # will raise an error if used!
|
||||
|
||||
|
||||
#Get the line of Texture Coords
|
||||
nr_uv_ind = 0
|
||||
|
||||
#Get Materials
|
||||
nr_fac_mat = 0
|
||||
i = -1
|
||||
mat_list = []
|
||||
tex_list = []
|
||||
mesh_line_indicies = []
|
||||
for j, line in enumerate(lines):
|
||||
l = line.strip()
|
||||
words = line.split()
|
||||
if words[0] == "Material" :
|
||||
#context_indicies["Material"] = j
|
||||
self.loadMaterials(j, mat_list, tex_list)
|
||||
elif words[0] == "MeshTextureCoords" :
|
||||
context_indicies["MeshTextureCoords"] = j
|
||||
#nr_uv_ind = j
|
||||
elif words[0] == "MeshMaterialList" :
|
||||
context_indicies["MeshMaterialList"] = j+2
|
||||
#nr_fac_mat = j + 2
|
||||
elif words[0] == "Mesh": # Avoid a second loop
|
||||
context_indicies = mesh_indicies[j] = {'MeshTextureCoords':0, 'MeshMaterialList':0}
|
||||
|
||||
for mesh_index, value in mesh_indicies.iteritems():
|
||||
mesh = Mesh.New()
|
||||
self.loadVertices(mesh_index, mesh, value['MeshTextureCoords'], value['MeshMaterialList'], tex_list)
|
||||
|
||||
mesh.materials = mat_list[:16]
|
||||
if value['MeshMaterialList']:
|
||||
self.loadMeshMaterials(value['MeshMaterialList'], mesh)
|
||||
scene.objects.new(mesh)
|
||||
|
||||
self.file.close()
|
||||
print "... finished"
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# CREATE THE MESH
|
||||
#------------------------------------------------------------------------------
|
||||
def loadVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list):
|
||||
v_ind = nr_vr_ind + 1
|
||||
lin = self.lines[v_ind]
|
||||
if lin :
|
||||
lin_c = self.CleanLine(lin)
|
||||
nr_vert = int((lin_c.split()[0]))
|
||||
else :
|
||||
v_ind = nr_vr_ind + 2
|
||||
lin = self.lines[v_ind]
|
||||
lin_c = self.CleanLine(lin)
|
||||
nr_vert = int((lin_c.split()[0]))
|
||||
|
||||
#--------------------------------------------------
|
||||
nr_fac_li = v_ind + nr_vert +1
|
||||
lin_f = self.lines[nr_fac_li]
|
||||
if lin_f :
|
||||
lin_fc = self.CleanLine(lin_f)
|
||||
nr_face = int((lin_fc.split()[0]))
|
||||
else :
|
||||
nr_fac_li = v_ind + nr_vert +1
|
||||
lin_f = self.lines[nr_fac_li]
|
||||
lin_fc = self.CleanLine(lin_f)
|
||||
nr_face = int((lin_fc.split()[0]))
|
||||
|
||||
#Get Coordinates
|
||||
verts_list = [(0,0,0)] # WARNING - DUMMY VERT - solves EEKADOODLE ERROR
|
||||
for l in xrange(v_ind + 1, (v_ind + nr_vert +1)):
|
||||
line_v = self.lines[l]
|
||||
lin_v = self.CleanLine(line_v)
|
||||
words = lin_v.split()
|
||||
if len(words)==3:
|
||||
verts_list.append((float(words[0]),float(words[1]),float(words[2])))
|
||||
|
||||
mesh.verts.extend(verts_list)
|
||||
del verts_list
|
||||
|
||||
face_list = []
|
||||
#Make Faces
|
||||
i = 0
|
||||
mesh_verts = mesh.verts
|
||||
for f in xrange(nr_fac_li + 1, (nr_fac_li + nr_face + 1)):
|
||||
i += 1
|
||||
line_f = self.lines[f]
|
||||
lin_f = self.CleanLine(line_f)
|
||||
|
||||
# +1 for dummy vert only!
|
||||
words = lin_f.split()
|
||||
if len(words) == 5:
|
||||
face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]), 1+int(words[4])))
|
||||
elif len(words) == 4:
|
||||
face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3])))
|
||||
|
||||
mesh.faces.extend(face_list)
|
||||
del face_list
|
||||
|
||||
if nr_uv :
|
||||
mesh.faceUV = True
|
||||
for f in mesh.faces:
|
||||
fuv = f.uv
|
||||
for ii, v in enumerate(f):
|
||||
# _u, _v = self.CleanLine(self.lines[nr_uv + 2 + v.index]).split()
|
||||
|
||||
# Use a dummy vert
|
||||
_u, _v = self.CleanLine(self.lines[nr_uv + 1 + v.index]).split()
|
||||
|
||||
fuv[ii].x = float(_u)
|
||||
fuv[ii].y = float(_v)
|
||||
|
||||
if nr_fac_mat :
|
||||
fac_line = self.lines[nr_fac_mat + i]
|
||||
fixed_fac = self.CleanLine(fac_line)
|
||||
w_tex = int(fixed_fac.split()[0])
|
||||
f.image = tex_list[w_tex]
|
||||
|
||||
# remove dummy vert
|
||||
mesh.verts.delete([0,])
|
||||
|
||||
def CleanLine(self,line):
|
||||
return line.replace(\
|
||||
";", " ").replace(\
|
||||
'"', ' ').replace(\
|
||||
"{", " ").replace(\
|
||||
"}", " ").replace(\
|
||||
",", " ").replace(\
|
||||
"'", " ")
|
||||
|
||||
#------------------------------------------------------------------
|
||||
# CREATE MATERIALS
|
||||
#------------------------------------------------------------------
|
||||
def loadMaterials(self, nr_mat, mat_list, tex_list):
|
||||
|
||||
def load_image(name):
|
||||
try:
|
||||
return Image.Load(Blender.sys.join(my_path,name))
|
||||
except:
|
||||
return None
|
||||
|
||||
mat = bpy.data.materials.new()
|
||||
line = self.lines[nr_mat + 1]
|
||||
fixed_line = self.CleanLine(line)
|
||||
words = fixed_line.split()
|
||||
mat.rgbCol = [float(words[0]),float(words[1]),float(words[2])]
|
||||
mat.setAlpha(float(words[3]))
|
||||
mat_list.append(mat)
|
||||
l = self.lines[nr_mat + 5]
|
||||
fix_3_line = self.CleanLine(l)
|
||||
tex_n = fix_3_line.split()
|
||||
|
||||
if tex_n and tex_n[0] == "TextureFilename" :
|
||||
|
||||
if len(tex_n) > 1:
|
||||
tex_list.append(load_image(tex_n[1]))
|
||||
|
||||
if len(tex_n) <= 1 :
|
||||
|
||||
l_succ = self.lines[nr_mat + 6]
|
||||
fix_3_succ = self.CleanLine(l_succ)
|
||||
tex_n_succ = fix_3_succ.split()
|
||||
tex_list.append(load_image(tex_n_succ[0]))
|
||||
else :
|
||||
tex_list.append(None) # no texture for this index
|
||||
|
||||
return mat_list, tex_list
|
||||
#------------------------------------------------------------------
|
||||
# SET MATERIALS
|
||||
#------------------------------------------------------------------
|
||||
def loadMeshMaterials(self, nr_fc_mat, mesh):
|
||||
for face in mesh.faces:
|
||||
nr_fc_mat += 1
|
||||
line = self.lines[nr_fc_mat]
|
||||
fixed_line = self.CleanLine(line)
|
||||
wrd = fixed_line.split()
|
||||
mat_idx = int(wrd[0])
|
||||
face.mat = mat_idx
|
||||
|
||||
#------------------------------------------------------------------
|
||||
# MAIN
|
||||
#------------------------------------------------------------------
|
||||
def my_callback(filename):
|
||||
if not filename.lower().endswith('.x'): print "Not an .x file"
|
||||
ximport = xImport(filename)
|
||||
ximport.Import()
|
||||
|
||||
arg = __script__['arg']
|
||||
|
||||
if __name__ == '__main__':
|
||||
Blender.Window.FileSelector(my_callback, "Import DirectX", "*.x")
|
||||
|
||||
#my_callback('/fe/x/directxterrain.x')
|
||||
#my_callback('/fe/x/Male_Normal_MAX.X')
|
||||
#my_callback('/fe/x/male_ms3d.x')
|
||||
@@ -1,523 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'ID Property Browser'
|
||||
Blender: 242
|
||||
Group: 'Help'
|
||||
Tooltip: 'Browse ID properties'
|
||||
"""
|
||||
|
||||
__author__ = "Joe Eagar"
|
||||
__version__ = "0.3.108"
|
||||
__email__ = "joeedh@gmail.com"
|
||||
__bpydoc__ = """\
|
||||
|
||||
Allows browsing, creating and editing of ID Properties
|
||||
for various ID block types such as mesh, scene, object,
|
||||
etc.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# ID Property Browser.
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
from Blender import *
|
||||
from Blender.BGL import *
|
||||
from Blender.Types import IDGroupType, IDArrayType
|
||||
import Blender
|
||||
|
||||
def IsInRectWH(mx, my, x, y, wid, hgt):
|
||||
if mx >= x and mx <= x + wid:
|
||||
if my >= y and my <= y + hgt:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
Button_Back = 1
|
||||
Button_New = 2
|
||||
Button_MatMenu = 3
|
||||
Button_TypeMenu = 4
|
||||
|
||||
ButStart = 55
|
||||
|
||||
IDP_String = 0
|
||||
IDP_Int = 1
|
||||
IDP_Float = 2
|
||||
IDP_Array = 5
|
||||
IDP_Group = 6
|
||||
|
||||
ButDelStart = 255
|
||||
#max limit for string input button
|
||||
strmax = 100
|
||||
|
||||
State_Normal = 0
|
||||
State_InArray = 1
|
||||
|
||||
#IDTypeModules entries are of form [module, active_object_index, module_name]
|
||||
IDTypeModules = [[Scene, 0, "Scenes"], [Object, 0, "Objects"], [Mesh, 0, "Meshes"]]
|
||||
IDTypeModules += [[Material, 0, "Materials"], [Texture, 0, "Textures"]]
|
||||
IDTypeModules += [[Image, 0, "Images"]]
|
||||
|
||||
class IDArrayBrowser:
|
||||
array = 0
|
||||
parentbrowser = 0
|
||||
buts = 0
|
||||
|
||||
def __init__(self):
|
||||
self.buts = []
|
||||
|
||||
def Draw(self):
|
||||
pb = self.parentbrowser
|
||||
x = pb.x
|
||||
y = pb.y
|
||||
width = pb.width
|
||||
height = pb.height
|
||||
pad = pb.pad
|
||||
itemhgt = pb.itemhgt
|
||||
cellwid = 65
|
||||
y = y + height - itemhgt - pad
|
||||
|
||||
Draw.PushButton("Back", Button_Back, x, y, 40, 20)
|
||||
y -= itemhgt + pad
|
||||
|
||||
self.buts = []
|
||||
Draw.BeginAlign()
|
||||
for i in xrange(len(self.array)):
|
||||
st = ""
|
||||
if type(self.array[0]) == float:
|
||||
st = "%.5f" % self.array[i]
|
||||
else: st = str(self.array[i])
|
||||
|
||||
b = Draw.String("", ButStart+i, x, y, cellwid, itemhgt, st, 30)
|
||||
self.buts.append(b)
|
||||
x += cellwid + pad
|
||||
if x + cellwid + pad > width:
|
||||
x = 0
|
||||
y -= itemhgt + pad
|
||||
Draw.EndAlign()
|
||||
def Button(self, bval):
|
||||
if bval == Button_Back:
|
||||
self.parentbrowser.state = State_Normal
|
||||
self.parentbrowser.array = 0
|
||||
self.buts = []
|
||||
Draw.Draw()
|
||||
self.array = 0
|
||||
elif bval >= ButStart:
|
||||
i = bval - ButStart
|
||||
st = self.buts[i].val
|
||||
n = 0
|
||||
if type(self.array[0]) == float:
|
||||
try:
|
||||
n = int(st)
|
||||
except:
|
||||
return
|
||||
elif type(self.array[0]) == int:
|
||||
try:
|
||||
n = float(st)
|
||||
except:
|
||||
return
|
||||
|
||||
self.array[i] = n
|
||||
Draw.Draw()
|
||||
|
||||
def Evt(self, evt, val):
|
||||
if evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
|
||||
class IDPropertyBrowser:
|
||||
width = 0
|
||||
height = 0
|
||||
x = 0
|
||||
y = 0
|
||||
scrollx = 0
|
||||
scrolly = 0
|
||||
itemhgt = 22
|
||||
pad = 2
|
||||
|
||||
group = 0
|
||||
parents = 0 #list stack of parent groups
|
||||
active_item = -1
|
||||
mousecursor = 0
|
||||
_i = 0
|
||||
buts = []
|
||||
|
||||
state = 0
|
||||
array = 0
|
||||
prop = 0
|
||||
|
||||
IDList = 0
|
||||
idindex = 0
|
||||
idblock = 0
|
||||
|
||||
type = 0 # attach buildin type() method to class
|
||||
# since oddly it's not available to button
|
||||
# callbacks! EEK! :(
|
||||
|
||||
def __init__(self, idgroup, mat, x, y, wid, hgt):
|
||||
self.group = idgroup
|
||||
self.prop = idgroup
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = wid
|
||||
self.height = hgt
|
||||
self.mousecursor = [0, 0]
|
||||
self.parents = []
|
||||
self.idblock = mat
|
||||
self.type = type
|
||||
|
||||
def DrawBox(self, glmode, x, y, width, height):
|
||||
glBegin(glmode)
|
||||
glVertex2f(x, y)
|
||||
glVertex2f(x+width, y)
|
||||
glVertex2f(x+width, y+height)
|
||||
glVertex2f(x, y+height)
|
||||
glEnd()
|
||||
|
||||
def Draw(self):
|
||||
global IDTypeModules
|
||||
|
||||
#first draw outlining box :)
|
||||
glColor3f(0, 0, 0)
|
||||
self.DrawBox(GL_LINE_LOOP, self.x, self.y, self.width, self.height)
|
||||
|
||||
itemhgt = self.itemhgt
|
||||
pad = self.pad
|
||||
x = self.x
|
||||
y = self.y + self.height - itemhgt - pad
|
||||
|
||||
if self.state == State_InArray:
|
||||
self.array.Draw()
|
||||
return
|
||||
|
||||
plist = []
|
||||
self.buts = []
|
||||
for p in self.group.iteritems():
|
||||
plist.append(p)
|
||||
|
||||
#-------do top buttons----------#
|
||||
Draw.BeginAlign()
|
||||
Draw.PushButton("New", Button_New, x, y, 40, 20)
|
||||
x += 40 + pad
|
||||
#do the menu button for all materials
|
||||
st = ""
|
||||
|
||||
blocks = IDTypeModules[self.IDList][0].Get()
|
||||
i = 1
|
||||
mi = 0
|
||||
for m in blocks:
|
||||
if m.name == self.idblock.name:
|
||||
mi = i
|
||||
st += m.name + " %x" + str(i) + "|"
|
||||
i += 1
|
||||
|
||||
self.menubut = Draw.Menu(st, Button_MatMenu, x, y, 100, 20, mi)
|
||||
|
||||
x += 100 + pad
|
||||
|
||||
st = ""
|
||||
i = 0
|
||||
for e in IDTypeModules:
|
||||
st += e[2] + " %x" + str(i+1) + "|"
|
||||
i += 1
|
||||
|
||||
cur = self.IDList + 1
|
||||
self.idmenu = Draw.Menu(st, Button_TypeMenu, x, y, 100, 20, cur)
|
||||
x = self.x
|
||||
y -= self.itemhgt + self.pad
|
||||
Draw.EndAlign()
|
||||
|
||||
|
||||
#-----------do property items---------#
|
||||
i = 0
|
||||
while y > self.y - 20 - pad and i < len(plist):
|
||||
k = plist[i][0]
|
||||
p = plist[i][1]
|
||||
if i == self.active_item:
|
||||
glColor3f(0.5, 0.4, 0.3)
|
||||
self.DrawBox(GL_POLYGON, x+pad, y, self.width-pad*2, itemhgt)
|
||||
|
||||
glColor3f(0, 0, 0)
|
||||
self.DrawBox(GL_LINE_LOOP, x+pad, y, self.width-pad*2, itemhgt)
|
||||
|
||||
glRasterPos2f(x+pad*2, y+5)
|
||||
Draw.Text(str(k)) #str(self.mousecursor) + " " + str(self.active_item)) #p.name)
|
||||
tlen = Draw.GetStringWidth(str(k))
|
||||
|
||||
type_p = type(p)
|
||||
if type_p == str:
|
||||
b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 200, itemhgt, p, strmax)
|
||||
self.buts.append(b)
|
||||
elif type_p in [int, float]:
|
||||
#only do precision to 5 points on floats
|
||||
st = ""
|
||||
if type_p == float:
|
||||
st = "%.5f" % p
|
||||
else: st = str(p)
|
||||
b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 75, itemhgt, st, strmax)
|
||||
self.buts.append(b)
|
||||
else:
|
||||
glRasterPos2f(x+pad*2 +tlen+10, y+5)
|
||||
if type_p == Types.IDArrayType:
|
||||
Draw.Text('(array, click to edit)')
|
||||
elif type_p == Types.IDGroupType:
|
||||
Draw.Text('(group, click to edit)')
|
||||
|
||||
|
||||
self.buts.append(None)
|
||||
|
||||
Draw.PushButton("Del", ButDelStart+i, x+self.width-35, y, 30, 20)
|
||||
|
||||
i += 1
|
||||
y -= self.itemhgt + self.pad
|
||||
|
||||
if len(self.parents) != 0:
|
||||
Draw.PushButton("Back", Button_Back, x, y, 40, 20)
|
||||
x = x + 40 + pad
|
||||
|
||||
def SetActive(self):
|
||||
m = self.mousecursor
|
||||
itemhgt = self.itemhgt
|
||||
pad = self.pad
|
||||
|
||||
x = self.x + pad
|
||||
y = self.y + self.height - itemhgt - pad - itemhgt
|
||||
|
||||
plist = []
|
||||
for p in self.group.iteritems():
|
||||
plist.append(p)
|
||||
|
||||
self.active_item = -1
|
||||
i = 0
|
||||
while y > self.y and i < len(plist):
|
||||
p = plist[i]
|
||||
if IsInRectWH(m[0], m[1], x, y, self.width-pad, itemhgt):
|
||||
self.active_item = i
|
||||
|
||||
i += 1
|
||||
y -= self.itemhgt + self.pad
|
||||
|
||||
def EventIn(self, evt, val):
|
||||
if self.state == State_InArray:
|
||||
self.array.Evt(evt, val)
|
||||
|
||||
if evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
if evt == Draw.MOUSEX or evt == Draw.MOUSEY:
|
||||
size = Buffer(GL_FLOAT, 4)
|
||||
glGetFloatv(GL_SCISSOR_BOX, size)
|
||||
if evt == Draw.MOUSEX:
|
||||
self.mousecursor[0] = val - size[0]
|
||||
else:
|
||||
self.mousecursor[1] = val - size[1]
|
||||
del size
|
||||
|
||||
self.SetActive()
|
||||
self._i += 1
|
||||
if self._i == 5:
|
||||
Draw.Draw()
|
||||
self._i = 0
|
||||
|
||||
|
||||
if evt == Draw.LEFTMOUSE and val == 1:
|
||||
plist = list(self.group.iteritems())
|
||||
a = self.active_item
|
||||
if a >= 0 and a < len(plist):
|
||||
p = plist[a]
|
||||
|
||||
basictypes = [IDGroupType, float, str, int]
|
||||
if type(p[1]) == IDGroupType:
|
||||
self.parents.append(self.group)
|
||||
self.group = p[1]
|
||||
self.active_item = -1
|
||||
Draw.Draw()
|
||||
elif type(p[1]) == IDArrayType:
|
||||
self.array = IDArrayBrowser()
|
||||
self.array.array = p[1]
|
||||
self.array.parentbrowser = self
|
||||
self.state = State_InArray
|
||||
Draw.Draw()
|
||||
|
||||
if evt == Draw.TKEY and val == 1:
|
||||
try:
|
||||
self.prop['float'] = 0.0
|
||||
self.prop['int'] = 1
|
||||
self.prop['string'] = "hi!"
|
||||
self.prop['float array'] = [0, 0, 1.0, 0]
|
||||
self.prop['int array'] = [0, 0, 0, 0]
|
||||
self.prop.data['a subgroup'] = {"int": 0, "float": 0.0, "anothergroup": {"a": 0.0, "intarr": [0, 0, 0, 0]}}
|
||||
Draw.Draw()
|
||||
except:
|
||||
Draw.PupMenu("Can only do T once per block, the test names are already taken!")
|
||||
|
||||
|
||||
def Button(self, bval):
|
||||
global IDTypeModules
|
||||
if self.state == State_InArray:
|
||||
self.array.Button(bval)
|
||||
return
|
||||
|
||||
if bval == Button_MatMenu:
|
||||
global IDTypeModules
|
||||
|
||||
val = self.idindex = self.menubut.val - 1
|
||||
i = self.IDList
|
||||
block = IDTypeModules[i][0].Get()[val]
|
||||
self.idblock = block
|
||||
self.prop = block.properties
|
||||
self.group = self.prop
|
||||
self.active_item = -1
|
||||
self.parents = []
|
||||
Draw.Draw()
|
||||
|
||||
if bval == Button_TypeMenu:
|
||||
i = IDTypeModules[self.idmenu.val-1]
|
||||
if len(i[0].Get()) == 0:
|
||||
Draw.PupMenu("Error%t|There are no " + i[2] + "!")
|
||||
return
|
||||
|
||||
IDTypeModules[self.IDList][1] = self.idindex
|
||||
self.IDList = self.idmenu.val-1
|
||||
val = self.idindex = IDTypeModules[self.IDList][1]
|
||||
i = self.IDList
|
||||
block = IDTypeModules[i][0].Get()[val]
|
||||
self.idblock = block
|
||||
self.prop = block.properties
|
||||
self.group = self.prop
|
||||
self.active_item = -1
|
||||
self.parents = []
|
||||
Draw.Draw()
|
||||
|
||||
if bval >= ButDelStart:
|
||||
plist = [p for p in self.group]
|
||||
prop = plist[bval - ButDelStart]
|
||||
del self.group[prop]
|
||||
Draw.Draw()
|
||||
|
||||
elif bval >= ButStart:
|
||||
plist = list(self.group.iteritems())
|
||||
|
||||
prop = plist[bval - ButStart]
|
||||
print prop
|
||||
|
||||
if self.type(prop[1]) == str:
|
||||
self.group[prop[0]] = self.buts[bval - ButStart].val
|
||||
elif self.type(prop[1]) == int:
|
||||
i = self.buts[bval - ButStart].val
|
||||
try:
|
||||
i = int(i)
|
||||
self.group[prop[0]] = i
|
||||
except:
|
||||
Draw.Draw()
|
||||
return
|
||||
Draw.Draw()
|
||||
elif self.type(prop[1]) == float:
|
||||
f = self.buts[bval - ButStart].val
|
||||
try:
|
||||
f = float(f)
|
||||
self.group[prop[0]] = f
|
||||
except:
|
||||
Draw.Draw()
|
||||
return
|
||||
Draw.Draw()
|
||||
|
||||
elif bval == Button_Back:
|
||||
self.group = self.parents[len(self.parents)-1]
|
||||
self.parents.pop(len(self.parents)-1)
|
||||
Draw.Draw()
|
||||
|
||||
elif bval == Button_New:
|
||||
name = Draw.Create("untitled")
|
||||
stype = Draw.Create(0)
|
||||
gtype = Draw.Create(0)
|
||||
ftype = Draw.Create(0)
|
||||
itype = Draw.Create(0)
|
||||
atype = Draw.Create(0)
|
||||
|
||||
block = []
|
||||
block.append(("Name: ", name, 0, 30, "Click to type in the name of the new ID property"))
|
||||
block.append("Type")
|
||||
block.append(("String", stype))
|
||||
block.append(("Subgroup", gtype))
|
||||
block.append(("Float", ftype))
|
||||
block.append(("Int", itype))
|
||||
block.append(("Array", atype))
|
||||
|
||||
retval = Blender.Draw.PupBlock("New IDProperty", block)
|
||||
if retval == 0: return
|
||||
|
||||
name = name.val
|
||||
i = 1
|
||||
stop = 0
|
||||
while stop == 0:
|
||||
stop = 1
|
||||
for p in self.group:
|
||||
if p == name:
|
||||
d = name.rfind(".")
|
||||
if d != -1:
|
||||
name = name[:d]
|
||||
name = name + "." + str(i).zfill(3)
|
||||
i += 1
|
||||
stop = 0
|
||||
|
||||
type = "String"
|
||||
if stype.val:
|
||||
self.group[name] = ""
|
||||
elif gtype.val:
|
||||
self.group[name] = {}
|
||||
elif ftype.val:
|
||||
self.group[name] = 0.0
|
||||
elif itype.val:
|
||||
self.group[name] = 0 #newProperty("Int", name, 0)
|
||||
elif atype.val:
|
||||
arrfloat = Draw.Create(1)
|
||||
arrint = Draw.Create(0)
|
||||
arrlen = Draw.Create(3)
|
||||
block = []
|
||||
block.append("Type")
|
||||
block.append(("Float", arrfloat, "Make a float array"))
|
||||
block.append(("Int", arrint, "Make an integer array"))
|
||||
block.append(("Len", arrlen, 2, 200))
|
||||
|
||||
if Blender.Draw.PupBlock("Array Properties", block):
|
||||
if arrfloat.val:
|
||||
tmpl = 0.0
|
||||
elif arrint.val:
|
||||
tmpl = 0
|
||||
else:
|
||||
return
|
||||
|
||||
self.group[name] = [tmpl] * arrlen.val
|
||||
|
||||
|
||||
def Go(self):
|
||||
Draw.Register(self.Draw, self.EventIn, self.Button)
|
||||
|
||||
scenes = Scene.Get()
|
||||
|
||||
size = Window.GetAreaSize()
|
||||
browser = IDPropertyBrowser(scenes[0].properties, scenes[0], 2, 2, size[0], size[1])
|
||||
browser.Go()
|
||||
|
||||
#a = prop.newProperty("String", "hwello!", "bleh")
|
||||
#b = prop.newProperty("Group", "subgroup")
|
||||
|
||||
#for p in prop:
|
||||
#print p.name
|
||||
@@ -1,828 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus:
|
||||
Name: 'AC3D (.ac)...'
|
||||
Blender: 243
|
||||
Group: 'Export'
|
||||
Tip: 'Export selected meshes to AC3D (.ac) format'
|
||||
"""
|
||||
|
||||
__author__ = "Willian P. Germano"
|
||||
__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org",
|
||||
"PLib 3d gaming lib, http://plib.sf.net")
|
||||
__version__ = "2.44 2007-05-05"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script exports selected Blender meshes to AC3D's .ac file format.
|
||||
|
||||
AC3D is a simple commercial 3d modeller also built with OpenGL.
|
||||
The .ac file format is an easy to parse text format well supported,
|
||||
for example, by the PLib 3d gaming library (AC3D 3.x).
|
||||
|
||||
Supported:<br>
|
||||
UV-textured meshes with hierarchy (grouping) information.
|
||||
|
||||
Missing:<br>
|
||||
The 'url' tag, specific to AC3D. It is easy to add by hand to the exported
|
||||
file, if needed.
|
||||
|
||||
Known issues:<br>
|
||||
The ambient and emit data we can retrieve from Blender are single values,
|
||||
that this script copies to R, G, B, giving shades of gray.<br>
|
||||
Loose edges (lines) receive the first material found in the mesh, if any, or a default white material.<br>
|
||||
In AC3D 4 "compatibility mode":<br>
|
||||
- shininess of materials is taken from the shader specularity value in Blender, mapped from [0.0, 2.0] to [0, 128];<br>
|
||||
- crease angle is exported, but in Blender it is limited to [1, 80], since there are other more powerful ways to control surface smoothing. In AC3D 4.0 crease's range is [0.0, 180.0];
|
||||
|
||||
Config Options:<br>
|
||||
toggle:<br>
|
||||
- AC3D 4 mode: unset it to export without the 'crease' tag that was
|
||||
introduced with AC3D 4.0 and with the old material handling;<br>
|
||||
- global coords: transform all vertices of all meshes to global coordinates;<br>
|
||||
- skip data: set it if you don't want mesh names (ME:, not OB: field)
|
||||
to be exported as strings for AC's "data" tags (19 chars max);<br>
|
||||
- rgb mirror color can be exported as ambient and/or emissive if needed,
|
||||
since Blender handles these differently;<br>
|
||||
- default mat: a default (white) material is added if some mesh was
|
||||
left without mats -- it's better to always add your own materials;<br>
|
||||
- no split: don't split meshes (see above);<br>
|
||||
- set texture dir: override the actual textures path with a given default
|
||||
path (or simply export the texture names, without dir info, if the path is
|
||||
empty);<br>
|
||||
- per face 1 or 2 sided: override the "Double Sided" button that defines this behavior per whole mesh in favor of the UV Face Select mode "twosided" per face atribute;<br>
|
||||
- only selected: only consider selected objects when looking for meshes
|
||||
to export (read notes below about tokens, too);<br>
|
||||
strings:<br>
|
||||
- export dir: default dir to export to;<br>
|
||||
- texture dir: override textures path with this path if 'set texture dir'
|
||||
toggle is "on".
|
||||
|
||||
Notes:<br>
|
||||
This version updates:<br>
|
||||
- modified meshes are correctly exported, no need to apply the modifiers in Blender;<br>
|
||||
- correctly export each used material, be it assigned to the object or to its mesh data;<br>
|
||||
- exporting lines (edges) is again supported; color comes from first material found in the mesh, if any, or a default white one.<br>
|
||||
- there's a new option to choose between exporting meshes with transformed (global) coordinates or local ones;<br>
|
||||
Multiple textures per mesh are supported (mesh gets split);<br>
|
||||
Parents are exported as a group containing both the parent and its children;<br>
|
||||
Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;<br>
|
||||
Start mesh object names (OB: field) with "=" or "$" to prevent them from being split (meshes with multiple textures or both textured and non textured faces are split unless this trick is used or the "no split" option is set.
|
||||
"""
|
||||
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# AC3DExport version 2.44
|
||||
# Program versions: Blender 2.42+ and AC3Db files (means version 0xb)
|
||||
# new: updated for new Blender version and Mesh module; supports lines (edges) again;
|
||||
# option to export vertices transformed to global coordinates or not; now the modified
|
||||
# (by existing mesh modifiers) mesh is exported; materials are properly exported, no
|
||||
# matter if each of them is linked to the mesh or to the object. New (2.43.1): loose
|
||||
# edges use color of first material found in the mesh, if any.
|
||||
# --------------------------------------------------------------------------
|
||||
# Thanks: Steve Baker for discussions and inspiration; for testing, bug
|
||||
# reports, suggestions, patches: David Megginson, Filippo di Natale,
|
||||
# Franz Melchior, Campbell Barton, Josh Babcock, Ralf Gerlich, Stewart Andreason.
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br
|
||||
#
|
||||
# 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,
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender import Object, Mesh, Material, Image, Mathutils, Registry
|
||||
from Blender import sys as bsys
|
||||
|
||||
# Globals
|
||||
REPORT_DATA = {
|
||||
'main': [],
|
||||
'errors': [],
|
||||
'warns': [],
|
||||
'nosplit': [],
|
||||
'noexport': []
|
||||
}
|
||||
TOKENS_DONT_EXPORT = ['!', '#']
|
||||
TOKENS_DONT_SPLIT = ['=', '$']
|
||||
|
||||
MATIDX_ERROR = 0
|
||||
|
||||
# flags:
|
||||
LOOSE = Mesh.EdgeFlags['LOOSE']
|
||||
FACE_TWOSIDED = Mesh.FaceModes['TWOSIDE']
|
||||
MESH_TWOSIDED = Mesh.Modes['TWOSIDED']
|
||||
|
||||
REG_KEY = 'ac3d_export'
|
||||
|
||||
# config options:
|
||||
GLOBAL_COORDS = True
|
||||
SKIP_DATA = False
|
||||
MIRCOL_AS_AMB = False
|
||||
MIRCOL_AS_EMIS = False
|
||||
ADD_DEFAULT_MAT = True
|
||||
SET_TEX_DIR = True
|
||||
TEX_DIR = ''
|
||||
AC3D_4 = True # export crease value, compatible with AC3D 4 loaders
|
||||
NO_SPLIT = False
|
||||
ONLY_SELECTED = True
|
||||
EXPORT_DIR = ''
|
||||
PER_FACE_1_OR_2_SIDED = True
|
||||
|
||||
tooltips = {
|
||||
'GLOBAL_COORDS': "transform all vertices of all meshes to global coordinates",
|
||||
'SKIP_DATA': "don't export mesh names as data fields",
|
||||
'MIRCOL_AS_AMB': "export mirror color as ambient color",
|
||||
'MIRCOL_AS_EMIS': "export mirror color as emissive color",
|
||||
'ADD_DEFAULT_MAT': "always add a default white material",
|
||||
'SET_TEX_DIR': "don't export default texture paths (edit also \"tex dir\")",
|
||||
'EXPORT_DIR': "default / last folder used to export .ac files to",
|
||||
'TEX_DIR': "(see \"set tex dir\") dir to prepend to all exported texture names (leave empty for no dir)",
|
||||
'AC3D_4': "compatibility mode, adds 'crease' tag and slightly better material support",
|
||||
'NO_SPLIT': "don't split meshes with multiple textures (or both textured and non textured polygons)",
|
||||
'ONLY_SELECTED': "export only selected objects",
|
||||
'PER_FACE_1_OR_2_SIDED': "override \"Double Sided\" button in favor of per face \"twosided\" attribute (UV Face Select mode)"
|
||||
}
|
||||
|
||||
def update_RegistryInfo():
|
||||
d = {}
|
||||
d['SKIP_DATA'] = SKIP_DATA
|
||||
d['MIRCOL_AS_AMB'] = MIRCOL_AS_AMB
|
||||
d['MIRCOL_AS_EMIS'] = MIRCOL_AS_EMIS
|
||||
d['ADD_DEFAULT_MAT'] = ADD_DEFAULT_MAT
|
||||
d['SET_TEX_DIR'] = SET_TEX_DIR
|
||||
d['TEX_DIR'] = TEX_DIR
|
||||
d['AC3D_4'] = AC3D_4
|
||||
d['NO_SPLIT'] = NO_SPLIT
|
||||
d['EXPORT_DIR'] = EXPORT_DIR
|
||||
d['ONLY_SELECTED'] = ONLY_SELECTED
|
||||
d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED
|
||||
d['tooltips'] = tooltips
|
||||
d['GLOBAL_COORDS'] = GLOBAL_COORDS
|
||||
Registry.SetKey(REG_KEY, d, True)
|
||||
|
||||
# Looking for a saved key in Blender.Registry dict:
|
||||
rd = Registry.GetKey(REG_KEY, True)
|
||||
|
||||
if rd:
|
||||
try:
|
||||
AC3D_4 = rd['AC3D_4']
|
||||
SKIP_DATA = rd['SKIP_DATA']
|
||||
MIRCOL_AS_AMB = rd['MIRCOL_AS_AMB']
|
||||
MIRCOL_AS_EMIS = rd['MIRCOL_AS_EMIS']
|
||||
ADD_DEFAULT_MAT = rd['ADD_DEFAULT_MAT']
|
||||
SET_TEX_DIR = rd['SET_TEX_DIR']
|
||||
TEX_DIR = rd['TEX_DIR']
|
||||
EXPORT_DIR = rd['EXPORT_DIR']
|
||||
ONLY_SELECTED = rd['ONLY_SELECTED']
|
||||
NO_SPLIT = rd['NO_SPLIT']
|
||||
PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED']
|
||||
GLOBAL_COORDS = rd['GLOBAL_COORDS']
|
||||
except KeyError: update_RegistryInfo()
|
||||
|
||||
else:
|
||||
update_RegistryInfo()
|
||||
|
||||
VERBOSE = True
|
||||
CONFIRM_OVERWRITE = True
|
||||
|
||||
# check General scripts config key for default behaviors
|
||||
rd = Registry.GetKey('General', True)
|
||||
if rd:
|
||||
try:
|
||||
VERBOSE = rd['verbose']
|
||||
CONFIRM_OVERWRITE = rd['confirm_overwrite']
|
||||
except: pass
|
||||
|
||||
|
||||
# The default material to be used when necessary (see ADD_DEFAULT_MAT)
|
||||
DEFAULT_MAT = \
|
||||
'MATERIAL "DefaultWhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 \
|
||||
spec 0.5 0.5 0.5 shi 64 trans 0'
|
||||
|
||||
# This transformation aligns Blender and AC3D coordinate systems:
|
||||
BLEND_TO_AC3D_MATRIX = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1])
|
||||
|
||||
def Round_s(f):
|
||||
"Round to default precision and turn value to a string"
|
||||
r = round(f,6) # precision set to 10e-06
|
||||
if r == int(r):
|
||||
return str(int(r))
|
||||
else:
|
||||
return str(r)
|
||||
|
||||
def transform_verts(verts, m):
|
||||
vecs = []
|
||||
for v in verts:
|
||||
x, y, z = v.co
|
||||
vec = Mathutils.Vector([x, y, z, 1])
|
||||
vecs.append(vec*m)
|
||||
return vecs
|
||||
|
||||
def get_loose_edges(mesh):
|
||||
loose = LOOSE
|
||||
return [e for e in mesh.edges if e.flag & loose]
|
||||
|
||||
# ---
|
||||
|
||||
# meshes with more than one texture assigned
|
||||
# are split and saved as these foomeshes
|
||||
class FooMesh:
|
||||
|
||||
class FooVert:
|
||||
def __init__(self, v):
|
||||
self.v = v
|
||||
self.index = 0
|
||||
|
||||
class FooFace:
|
||||
def __init__(self, foomesh, f):
|
||||
self.f = f
|
||||
foov = foomesh.FooVert
|
||||
self.v = [foov(f.v[0]), foov(f.v[1])]
|
||||
len_fv = len(f.v)
|
||||
if len_fv > 2 and f.v[2]:
|
||||
self.v.append(foov(f.v[2]))
|
||||
if len_fv > 3 and f.v[3]: self.v.append(foov(f.v[3]))
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'v': return self.v
|
||||
return getattr(self.f, attr)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.f)
|
||||
|
||||
def __init__(self, tex, faces, mesh):
|
||||
self.name = mesh.name
|
||||
self.mesh = mesh
|
||||
self.looseEdges = []
|
||||
self.faceUV = mesh.faceUV
|
||||
self.degr = mesh.degr
|
||||
vidxs = [0]*len(mesh.verts)
|
||||
foofaces = []
|
||||
for f in faces:
|
||||
foofaces.append(self.FooFace(self, f))
|
||||
for v in f.v:
|
||||
if v: vidxs[v.index] = 1
|
||||
i = 0
|
||||
fooverts = []
|
||||
for v in mesh.verts:
|
||||
if vidxs[v.index]:
|
||||
fooverts.append(v)
|
||||
vidxs[v.index] = i
|
||||
i += 1
|
||||
for f in foofaces:
|
||||
for v in f.v:
|
||||
if v: v.index = vidxs[v.v.index]
|
||||
self.faces = foofaces
|
||||
self.verts = fooverts
|
||||
|
||||
|
||||
class AC3DExport: # the ac3d exporter part
|
||||
|
||||
def __init__(self, scene_objects, file):
|
||||
|
||||
global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT
|
||||
|
||||
header = 'AC3Db'
|
||||
self.file = file
|
||||
self.buf = ''
|
||||
self.mbuf = []
|
||||
self.mlist = []
|
||||
world_kids = 0
|
||||
parents_list = self.parents_list = []
|
||||
kids_dict = self.kids_dict = {}
|
||||
objs = []
|
||||
exp_objs = self.exp_objs = []
|
||||
tree = {}
|
||||
|
||||
file.write(header+'\n')
|
||||
|
||||
objs = \
|
||||
[o for o in scene_objects if o.type in ['Mesh', 'Empty']]
|
||||
|
||||
# create a tree from parents to children objects
|
||||
|
||||
for obj in objs[:]:
|
||||
parent = obj.parent
|
||||
lineage = [obj]
|
||||
|
||||
while parent:
|
||||
parents_list.append(parent.name)
|
||||
obj = parent
|
||||
parent = parent.getParent()
|
||||
lineage.insert(0, obj)
|
||||
|
||||
d = tree
|
||||
for i in xrange(len(lineage)):
|
||||
lname = lineage[i].getType()[:2] + lineage[i].name
|
||||
if lname not in d.keys():
|
||||
d[lname] = {}
|
||||
d = d[lname]
|
||||
|
||||
# traverse the tree to get an ordered list of names of objects to export
|
||||
self.traverse_dict(tree)
|
||||
|
||||
world_kids = len(tree.keys())
|
||||
|
||||
# get list of objects to export, start writing the .ac file
|
||||
|
||||
objlist = [Object.Get(name) for name in exp_objs]
|
||||
|
||||
meshlist = [o for o in objlist if o.type == 'Mesh']
|
||||
|
||||
# create a temporary mesh to hold actual (modified) mesh data
|
||||
TMP_mesh = Mesh.New('tmp_for_ac_export')
|
||||
|
||||
# write materials
|
||||
|
||||
self.MATERIALS(meshlist, TMP_mesh)
|
||||
mbuf = self.mbuf
|
||||
if not mbuf or ADD_DEFAULT_MAT:
|
||||
mbuf.insert(0, "%s\n" % DEFAULT_MAT)
|
||||
mbuf = "".join(mbuf)
|
||||
file.write(mbuf)
|
||||
|
||||
file.write('OBJECT world\nkids %s\n' % world_kids)
|
||||
|
||||
# write the objects
|
||||
|
||||
for obj in objlist:
|
||||
self.obj = obj
|
||||
|
||||
objtype = obj.type
|
||||
objname = obj.name
|
||||
kidsnum = kids_dict[objname]
|
||||
|
||||
# A parent plus its children are exported as a group.
|
||||
# If the parent is a mesh, its rot and loc are exported as the
|
||||
# group rot and loc and the mesh (w/o rot and loc) is added to the group.
|
||||
if kidsnum:
|
||||
self.OBJECT('group')
|
||||
self.name(objname)
|
||||
if objtype == 'Mesh':
|
||||
kidsnum += 1
|
||||
if not GLOBAL_COORDS:
|
||||
localmatrix = obj.getMatrix('localspace')
|
||||
if not obj.getParent():
|
||||
localmatrix *= BLEND_TO_AC3D_MATRIX
|
||||
self.rot(localmatrix.rotationPart())
|
||||
self.loc(localmatrix.translationPart())
|
||||
self.kids(kidsnum)
|
||||
|
||||
if objtype == 'Mesh':
|
||||
mesh = TMP_mesh # temporary mesh to hold actual (modified) mesh data
|
||||
mesh.getFromObject(objname)
|
||||
self.mesh = mesh
|
||||
if mesh.faceUV:
|
||||
meshes = self.split_mesh(mesh)
|
||||
else:
|
||||
meshes = [mesh]
|
||||
if len(meshes) > 1:
|
||||
if NO_SPLIT or self.dont_split(objname):
|
||||
self.export_mesh(mesh, ob)
|
||||
REPORT_DATA['nosplit'].append(objname)
|
||||
else:
|
||||
self.OBJECT('group')
|
||||
self.name(objname)
|
||||
self.kids(len(meshes))
|
||||
counter = 0
|
||||
for me in meshes:
|
||||
self.export_mesh(me, obj,
|
||||
name = '%s_%s' % (obj.name, counter), foomesh = True)
|
||||
self.kids()
|
||||
counter += 1
|
||||
else:
|
||||
self.export_mesh(mesh, obj)
|
||||
self.kids()
|
||||
|
||||
|
||||
def traverse_dict(self, d):
|
||||
kids_dict = self.kids_dict
|
||||
exp_objs = self.exp_objs
|
||||
keys = d.keys()
|
||||
keys.sort() # sort for predictable output
|
||||
keys.reverse()
|
||||
for k in keys:
|
||||
objname = k[2:]
|
||||
klen = len(d[k])
|
||||
kids_dict[objname] = klen
|
||||
if self.dont_export(objname):
|
||||
d.pop(k)
|
||||
parent = Object.Get(objname).getParent()
|
||||
if parent: kids_dict[parent.name] -= 1
|
||||
REPORT_DATA['noexport'].append(objname)
|
||||
continue
|
||||
if klen:
|
||||
self.traverse_dict(d[k])
|
||||
exp_objs.insert(0, objname)
|
||||
else:
|
||||
if k.find('Em', 0) == 0: # Empty w/o children
|
||||
d.pop(k)
|
||||
parent = Object.Get(objname).getParent()
|
||||
if parent: kids_dict[parent.name] -= 1
|
||||
else:
|
||||
exp_objs.insert(0, objname)
|
||||
|
||||
def dont_export(self, name): # if name starts with '!' or '#'
|
||||
length = len(name)
|
||||
if length >= 1:
|
||||
if name[0] in TOKENS_DONT_EXPORT: # '!' or '#' doubled (escaped): export
|
||||
if length > 1 and name[1] == name[0]:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def dont_split(self, name): # if name starts with '=' or '$'
|
||||
length = len(name)
|
||||
if length >= 1:
|
||||
if name[0] in TOKENS_DONT_SPLIT: # '=' or '$' doubled (escaped): split
|
||||
if length > 1 and name[1] == name[0]:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def split_mesh(self, mesh):
|
||||
tex_dict = {0:[]}
|
||||
for f in mesh.faces:
|
||||
if f.image:
|
||||
if not f.image.name in tex_dict: tex_dict[f.image.name] = []
|
||||
tex_dict[f.image.name].append(f)
|
||||
else: tex_dict[0].append(f)
|
||||
keys = tex_dict.keys()
|
||||
len_keys = len(keys)
|
||||
if not tex_dict[0]:
|
||||
len_keys -= 1
|
||||
tex_dict.pop(0)
|
||||
keys.remove(0)
|
||||
elif len_keys > 1:
|
||||
lines = []
|
||||
anyimgkey = [k for k in keys if k != 0][0]
|
||||
for f in tex_dict[0]:
|
||||
if len(f.v) < 3:
|
||||
lines.append(f)
|
||||
if len(tex_dict[0]) == len(lines):
|
||||
for l in lines:
|
||||
tex_dict[anyimgkey].append(l)
|
||||
len_keys -= 1
|
||||
tex_dict.pop(0)
|
||||
if len_keys > 1:
|
||||
foo_meshes = []
|
||||
for k in keys:
|
||||
faces = tex_dict[k]
|
||||
foo_meshes.append(FooMesh(k, faces, mesh))
|
||||
foo_meshes[0].edges = get_loose_edges(mesh)
|
||||
return foo_meshes
|
||||
return [mesh]
|
||||
|
||||
def export_mesh(self, mesh, obj, name = None, foomesh = False):
|
||||
file = self.file
|
||||
self.OBJECT('poly')
|
||||
if not name: name = obj.name
|
||||
self.name(name)
|
||||
if not SKIP_DATA:
|
||||
meshname = obj.getData(name_only = True)
|
||||
self.data(len(meshname), meshname)
|
||||
if mesh.faceUV:
|
||||
texline = self.texture(mesh.faces)
|
||||
if texline: file.write(texline)
|
||||
if AC3D_4:
|
||||
self.crease(mesh.degr)
|
||||
|
||||
# If exporting using local coordinates, children object coordinates should not be
|
||||
# transformed to ac3d's coordinate system, since that will be accounted for in
|
||||
# their topmost parents (the parents w/o parents) transformations.
|
||||
if not GLOBAL_COORDS:
|
||||
# We hold parents in a list, so they also don't get transformed,
|
||||
# because for each parent we create an ac3d group to hold both the
|
||||
# parent and its children.
|
||||
if obj.name not in self.parents_list:
|
||||
localmatrix = obj.getMatrix('localspace')
|
||||
if not obj.getParent():
|
||||
localmatrix *= BLEND_TO_AC3D_MATRIX
|
||||
self.rot(localmatrix.rotationPart())
|
||||
self.loc(localmatrix.translationPart())
|
||||
matrix = None
|
||||
else:
|
||||
matrix = obj.getMatrix() * BLEND_TO_AC3D_MATRIX
|
||||
|
||||
self.numvert(mesh.verts, matrix)
|
||||
self.numsurf(mesh, foomesh)
|
||||
|
||||
def MATERIALS(self, meshlist, me):
|
||||
for meobj in meshlist:
|
||||
me.getFromObject(meobj)
|
||||
mats = me.materials
|
||||
mbuf = []
|
||||
mlist = self.mlist
|
||||
for m in mats:
|
||||
if not m: continue
|
||||
name = m.name
|
||||
if name not in mlist:
|
||||
mlist.append(name)
|
||||
M = Material.Get(name)
|
||||
material = 'MATERIAL "%s"' % name
|
||||
mirCol = "%s %s %s" % (Round_s(M.mirCol[0]), Round_s(M.mirCol[1]),
|
||||
Round_s(M.mirCol[2]))
|
||||
rgb = "rgb %s %s %s" % (Round_s(M.R), Round_s(M.G), Round_s(M.B))
|
||||
ambval = Round_s(M.amb)
|
||||
amb = "amb %s %s %s" % (ambval, ambval, ambval)
|
||||
spec = "spec %s %s %s" % (Round_s(M.specCol[0]),
|
||||
Round_s(M.specCol[1]), Round_s(M.specCol[2]))
|
||||
if AC3D_4:
|
||||
emit = Round_s(M.emit)
|
||||
emis = "emis %s %s %s" % (emit, emit, emit)
|
||||
shival = int(M.spec * 64)
|
||||
else:
|
||||
emis = "emis 0 0 0"
|
||||
shival = 72
|
||||
shi = "shi %s" % shival
|
||||
trans = "trans %s" % (Round_s(1 - M.alpha))
|
||||
if MIRCOL_AS_AMB:
|
||||
amb = "amb %s" % mirCol
|
||||
if MIRCOL_AS_EMIS:
|
||||
emis = "emis %s" % mirCol
|
||||
mbuf.append("%s %s %s %s %s %s %s\n" \
|
||||
% (material, rgb, amb, emis, spec, shi, trans))
|
||||
self.mlist = mlist
|
||||
self.mbuf.append("".join(mbuf))
|
||||
|
||||
def OBJECT(self, type):
|
||||
self.file.write('OBJECT %s\n' % type)
|
||||
|
||||
def name(self, name):
|
||||
if name[0] in TOKENS_DONT_EXPORT or name[0] in TOKENS_DONT_SPLIT:
|
||||
if len(name) > 1: name = name[1:]
|
||||
self.file.write('name "%s"\n' % name)
|
||||
|
||||
def kids(self, num = 0):
|
||||
self.file.write('kids %s\n' % num)
|
||||
|
||||
def data(self, num, str):
|
||||
self.file.write('data %s\n%s\n' % (num, str))
|
||||
|
||||
def texture(self, faces):
|
||||
tex = ""
|
||||
for f in faces:
|
||||
if f.image:
|
||||
tex = f.image.name
|
||||
break
|
||||
if tex:
|
||||
image = Image.Get(tex)
|
||||
texfname = image.filename
|
||||
if SET_TEX_DIR:
|
||||
texfname = bsys.basename(texfname)
|
||||
if TEX_DIR:
|
||||
texfname = bsys.join(TEX_DIR, texfname)
|
||||
buf = 'texture "%s"\n' % texfname
|
||||
xrep = image.xrep
|
||||
yrep = image.yrep
|
||||
buf += 'texrep %s %s\n' % (xrep, yrep)
|
||||
self.file.write(buf)
|
||||
|
||||
def rot(self, matrix):
|
||||
rot = ''
|
||||
not_I = 0 # not identity
|
||||
matstr = []
|
||||
for i in [0, 1, 2]:
|
||||
r = map(Round_s, matrix[i])
|
||||
not_I += (r[0] != '0')+(r[1] != '0')+(r[2] != '0')
|
||||
not_I -= (r[i] == '1')
|
||||
for j in [0, 1, 2]:
|
||||
matstr.append(' %s' % r[j])
|
||||
if not_I: # no need to write identity
|
||||
self.file.write('rot%s\n' % "".join(matstr))
|
||||
|
||||
def loc(self, loc):
|
||||
loc = map(Round_s, loc)
|
||||
if loc != ['0', '0', '0']: # no need to write default
|
||||
self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2]))
|
||||
|
||||
def crease(self, crease):
|
||||
self.file.write('crease %f\n' % crease)
|
||||
|
||||
def numvert(self, verts, matrix):
|
||||
file = self.file
|
||||
nvstr = []
|
||||
nvstr.append("numvert %s\n" % len(verts))
|
||||
|
||||
if matrix:
|
||||
verts = transform_verts(verts, matrix)
|
||||
for v in verts:
|
||||
v = map (Round_s, v)
|
||||
nvstr.append("%s %s %s\n" % (v[0], v[1], v[2]))
|
||||
else:
|
||||
for v in verts:
|
||||
v = map(Round_s, v.co)
|
||||
nvstr.append("%s %s %s\n" % (v[0], v[1], v[2]))
|
||||
|
||||
file.write("".join(nvstr))
|
||||
|
||||
def numsurf(self, mesh, foomesh = False):
|
||||
|
||||
global MATIDX_ERROR
|
||||
|
||||
# local vars are faster and so better in tight loops
|
||||
lc_ADD_DEFAULT_MAT = ADD_DEFAULT_MAT
|
||||
lc_MATIDX_ERROR = MATIDX_ERROR
|
||||
lc_PER_FACE_1_OR_2_SIDED = PER_FACE_1_OR_2_SIDED
|
||||
lc_FACE_TWOSIDED = FACE_TWOSIDED
|
||||
lc_MESH_TWOSIDED = MESH_TWOSIDED
|
||||
|
||||
faces = mesh.faces
|
||||
hasFaceUV = mesh.faceUV
|
||||
if foomesh:
|
||||
looseEdges = mesh.looseEdges
|
||||
else:
|
||||
looseEdges = get_loose_edges(mesh)
|
||||
|
||||
file = self.file
|
||||
|
||||
file.write("numsurf %s\n" % (len(faces) + len(looseEdges)))
|
||||
|
||||
if not foomesh: verts = list(self.mesh.verts)
|
||||
|
||||
materials = self.mesh.materials
|
||||
mlist = self.mlist
|
||||
matidx_error_reported = False
|
||||
objmats = []
|
||||
for omat in materials:
|
||||
if omat: objmats.append(omat.name)
|
||||
else: objmats.append(None)
|
||||
for f in faces:
|
||||
if not objmats:
|
||||
m_idx = 0
|
||||
elif objmats[f.mat] in mlist:
|
||||
m_idx = mlist.index(objmats[f.mat])
|
||||
else:
|
||||
if not lc_MATIDX_ERROR:
|
||||
rdat = REPORT_DATA['warns']
|
||||
rdat.append("Object %s" % self.obj.name)
|
||||
rdat.append("has at least one material *index* assigned but not")
|
||||
rdat.append("defined (not linked to an existing material).")
|
||||
rdat.append("Result: some faces may be exported with a wrong color.")
|
||||
rdat.append("You can assign materials in the Edit Buttons window (F9).")
|
||||
elif not matidx_error_reported:
|
||||
midxmsg = "- Same for object %s." % self.obj.name
|
||||
REPORT_DATA['warns'].append(midxmsg)
|
||||
lc_MATIDX_ERROR += 1
|
||||
matidx_error_reported = True
|
||||
m_idx = 0
|
||||
if lc_ADD_DEFAULT_MAT: m_idx -= 1
|
||||
refs = len(f)
|
||||
flaglow = 0 # polygon
|
||||
if lc_PER_FACE_1_OR_2_SIDED and hasFaceUV: # per face attribute
|
||||
two_side = f.mode & lc_FACE_TWOSIDED
|
||||
else: # global, for the whole mesh
|
||||
two_side = self.mesh.mode & lc_MESH_TWOSIDED
|
||||
two_side = (two_side > 0) << 1
|
||||
flaghigh = f.smooth | two_side
|
||||
surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
|
||||
if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1
|
||||
matstr = "mat %s\n" % m_idx
|
||||
refstr = "refs %s\n" % refs
|
||||
u, v, vi = 0, 0, 0
|
||||
fvstr = []
|
||||
if foomesh:
|
||||
for vert in f.v:
|
||||
fvstr.append(str(vert.index))
|
||||
if hasFaceUV:
|
||||
u = f.uv[vi][0]
|
||||
v = f.uv[vi][1]
|
||||
vi += 1
|
||||
fvstr.append(" %s %s\n" % (u, v))
|
||||
else:
|
||||
for vert in f.v:
|
||||
fvstr.append(str(verts.index(vert)))
|
||||
if hasFaceUV:
|
||||
u = f.uv[vi][0]
|
||||
v = f.uv[vi][1]
|
||||
vi += 1
|
||||
fvstr.append(" %s %s\n" % (u, v))
|
||||
|
||||
fvstr = "".join(fvstr)
|
||||
|
||||
file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr))
|
||||
|
||||
# material for loose edges
|
||||
edges_mat = 0 # default to first material
|
||||
for omat in objmats: # but look for a material from this mesh
|
||||
if omat in mlist:
|
||||
edges_mat = mlist.index(omat)
|
||||
if lc_ADD_DEFAULT_MAT: edges_mat += 1
|
||||
break
|
||||
|
||||
for e in looseEdges:
|
||||
fvstr = []
|
||||
#flaglow = 2 # 1 = closed line, 2 = line
|
||||
#flaghigh = 0
|
||||
#surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
|
||||
surfstr = "SURF 0x02\n"
|
||||
|
||||
fvstr.append("%d 0 0\n" % verts.index(e.v1))
|
||||
fvstr.append("%d 0 0\n" % verts.index(e.v2))
|
||||
fvstr = "".join(fvstr)
|
||||
|
||||
matstr = "mat %d\n" % edges_mat # for now, use first material
|
||||
refstr = "refs 2\n" # 2 verts
|
||||
|
||||
file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr))
|
||||
|
||||
MATIDX_ERROR = lc_MATIDX_ERROR
|
||||
|
||||
# End of Class AC3DExport
|
||||
|
||||
from Blender.Window import FileSelector
|
||||
|
||||
def report_data():
|
||||
global VERBOSE
|
||||
|
||||
if not VERBOSE: return
|
||||
|
||||
d = REPORT_DATA
|
||||
msgs = {
|
||||
'0main': '%s\nExporting meshes to AC3D format' % str(19*'-'),
|
||||
'1warns': 'Warnings',
|
||||
'2errors': 'Errors',
|
||||
'3nosplit': 'Not split (because name starts with "=" or "$")',
|
||||
'4noexport': 'Not exported (because name starts with "!" or "#")'
|
||||
}
|
||||
if NO_SPLIT:
|
||||
l = msgs['3nosplit']
|
||||
l = "%s (because OPTION NO_SPLIT is set)" % l.split('(')[0]
|
||||
msgs['3nosplit'] = l
|
||||
keys = msgs.keys()
|
||||
keys.sort()
|
||||
for k in keys:
|
||||
msgk = msgs[k]
|
||||
msg = '\n'.join(d[k[1:]])
|
||||
if msg:
|
||||
print '\n-%s:' % msgk
|
||||
print msg
|
||||
|
||||
# File Selector callback:
|
||||
def fs_callback(filename):
|
||||
global EXPORT_DIR, OBJS, CONFIRM_OVERWRITE, VERBOSE
|
||||
|
||||
if not filename.endswith('.ac'): filename = '%s.ac' % filename
|
||||
|
||||
if bsys.exists(filename) and CONFIRM_OVERWRITE:
|
||||
if Blender.Draw.PupMenu('OVERWRITE?%t|File exists') != 1:
|
||||
return
|
||||
|
||||
Blender.Window.WaitCursor(1)
|
||||
starttime = bsys.time()
|
||||
|
||||
export_dir = bsys.dirname(filename)
|
||||
if export_dir != EXPORT_DIR:
|
||||
EXPORT_DIR = export_dir
|
||||
update_RegistryInfo()
|
||||
|
||||
try:
|
||||
file = open(filename, 'w')
|
||||
except IOError, (errno, strerror):
|
||||
error = "IOError #%s: %s" % (errno, strerror)
|
||||
REPORT_DATA['errors'].append("Saving failed - %s." % error)
|
||||
error_msg = "Couldn't save file!%%t|%s" % error
|
||||
Blender.Draw.PupMenu(error_msg)
|
||||
return
|
||||
|
||||
try:
|
||||
test = AC3DExport(OBJS, file)
|
||||
except:
|
||||
file.close()
|
||||
raise
|
||||
else:
|
||||
file.close()
|
||||
endtime = bsys.time() - starttime
|
||||
REPORT_DATA['main'].append("Done. Saved to: %s" % filename)
|
||||
REPORT_DATA['main'].append("Data exported in %.3f seconds." % endtime)
|
||||
|
||||
if VERBOSE: report_data()
|
||||
Blender.Window.WaitCursor(0)
|
||||
|
||||
|
||||
# -- End of definitions
|
||||
|
||||
scn = Blender.Scene.GetCurrent()
|
||||
|
||||
if ONLY_SELECTED:
|
||||
OBJS = list(scn.objects.context)
|
||||
else:
|
||||
OBJS = list(scn.objects)
|
||||
|
||||
if not OBJS:
|
||||
Blender.Draw.PupMenu('ERROR: no objects selected')
|
||||
else:
|
||||
fname = bsys.makename(ext=".ac")
|
||||
if EXPORT_DIR:
|
||||
fname = bsys.join(EXPORT_DIR, bsys.basename(fname))
|
||||
FileSelector(fs_callback, "Export AC3D", fname)
|
||||
@@ -1,783 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus:
|
||||
Name: 'AC3D (.ac)...'
|
||||
Blender: 243
|
||||
Group: 'Import'
|
||||
Tip: 'Import an AC3D (.ac) file.'
|
||||
"""
|
||||
|
||||
__author__ = "Willian P. Germano"
|
||||
__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org",
|
||||
"PLib 3d gaming lib, http://plib.sf.net")
|
||||
__version__ = "2.48.1 2009-01-11"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script imports AC3D models into Blender.
|
||||
|
||||
AC3D is a simple and affordable commercial 3d modeller also built with OpenGL.
|
||||
The .ac file format is an easy to parse text format well supported,
|
||||
for example, by the PLib 3d gaming library.
|
||||
|
||||
Supported:<br>
|
||||
UV-textured meshes with hierarchy (grouping) information.
|
||||
|
||||
Missing:<br>
|
||||
The url tag is irrelevant for Blender.
|
||||
|
||||
Known issues:<br>
|
||||
- Some objects may be imported with wrong normals due to wrong information in the model itself. This can be noticed by strange shading, like darker than expected parts in the model. To fix this, select the mesh with wrong normals, enter edit mode and tell Blender to recalculate the normals, either to make them point outside (the usual case) or inside.<br>
|
||||
|
||||
Config Options:<br>
|
||||
- display transp (toggle): if "on", objects that have materials with alpha < 1.0 are shown with translucency (transparency) in the 3D View.<br>
|
||||
- subdiv (toggle): if "on", ac3d objects meant to be subdivided receive a SUBSURF modifier in Blender.<br>
|
||||
- emis as mircol: store the emissive rgb color from AC3D as mirror color in Blender -- this is a hack to preserve the values and be able to export them using the equivalent option in the exporter.<br>
|
||||
- textures dir (string): if non blank, when imported texture paths are
|
||||
wrong in the .ac file, Blender will also look for them at this dir.
|
||||
|
||||
Notes:<br>
|
||||
- When looking for assigned textures, Blender tries in order: the actual
|
||||
paths from the .ac file, the .ac file's dir and the default textures dir path
|
||||
users can configure (see config options above).
|
||||
"""
|
||||
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# AC3DImport version 2.43.1 Feb 21, 2007
|
||||
# Program versions: Blender 2.43 and AC3Db files (means version 0xb)
|
||||
# changed: better triangulation of ngons, more fixes to support bad .ac files,
|
||||
# option to display transp mats in 3d view, support "subdiv" tag (via SUBSURF modifier)
|
||||
# --------------------------------------------------------------------------
|
||||
# Thanks: Melchior Franz for extensive bug testing and reporting, making this
|
||||
# version cope much better with old or bad .ac files, among other improvements;
|
||||
# Stewart Andreason for reporting a serious crash; Francesco Brisa for the
|
||||
# emis as mircol functionality (w/ patch).
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004-2009: Willian P. Germano, wgermano _at_ ig.com.br
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
from math import radians
|
||||
|
||||
import Blender
|
||||
from Blender import Scene, Object, Mesh, Lamp, Registry, sys as bsys, Window, Image, Material, Modifier
|
||||
from Blender.sys import dirsep
|
||||
from Blender.Mathutils import Vector, Matrix, Euler
|
||||
from Blender.Geometry import PolyFill
|
||||
|
||||
# Default folder for AC3D textures, to override wrong paths, change to your
|
||||
# liking or leave as "":
|
||||
TEXTURES_DIR = ""
|
||||
|
||||
DISPLAY_TRANSP = True
|
||||
|
||||
SUBDIV = True
|
||||
|
||||
EMIS_AS_MIRCOL = False
|
||||
|
||||
|
||||
tooltips = {
|
||||
'DISPLAY_TRANSP': 'Turn transparency on in the 3d View for objects using materials with alpha < 1.0.',
|
||||
'SUBDIV': 'Apply a SUBSURF modifier to objects meant to appear subdivided.',
|
||||
'TEXTURES_DIR': 'Additional folder to look for missing textures.',
|
||||
'EMIS_AS_MIRCOL': 'Store emis color as mirror color in Blender.'
|
||||
}
|
||||
|
||||
def update_registry():
|
||||
global TEXTURES_DIR, DISPLAY_TRANSP, EMIS_AS_MIRCOL
|
||||
rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV), ('EMIS_AS_MIRCOL', EMIS_AS_MIRCOL)])
|
||||
Registry.SetKey('ac3d_import', rd, True)
|
||||
|
||||
rd = Registry.GetKey('ac3d_import', True)
|
||||
|
||||
if rd:
|
||||
if 'GROUP' in rd:
|
||||
update_registry()
|
||||
try:
|
||||
TEXTURES_DIR = rd['TEXTURES_DIR']
|
||||
DISPLAY_TRANSP = rd['DISPLAY_TRANSP']
|
||||
SUBDIV = rd['SUBDIV']
|
||||
EMIS_AS_MIRCOL = rd['EMIS_AS_MIRCOL']
|
||||
except:
|
||||
update_registry()
|
||||
else: update_registry()
|
||||
|
||||
if TEXTURES_DIR:
|
||||
oldtexdir = TEXTURES_DIR
|
||||
if dirsep == '/': TEXTURES_DIR = TEXTURES_DIR.replace('\\', '/')
|
||||
if TEXTURES_DIR[-1] != dirsep: TEXTURES_DIR = "%s%s" % (TEXTURES_DIR, dirsep)
|
||||
if oldtexdir != TEXTURES_DIR: update_registry()
|
||||
|
||||
|
||||
VERBOSE = True
|
||||
rd = Registry.GetKey('General', True)
|
||||
if rd:
|
||||
if rd.has_key('verbose'):
|
||||
VERBOSE = rd['verbose']
|
||||
|
||||
|
||||
errmsg = ""
|
||||
|
||||
# Matrix to align ac3d's coordinate system with Blender's one,
|
||||
# it's a -90 degrees rotation around the x axis:
|
||||
AC_TO_BLEND_MATRIX = Matrix([1, 0, 0], [0, 0, 1], [0, -1, 0])
|
||||
|
||||
AC_WORLD = 0
|
||||
AC_GROUP = 1
|
||||
AC_POLY = 2
|
||||
AC_LIGHT = 3
|
||||
AC_OB_TYPES = {
|
||||
'world': AC_WORLD,
|
||||
'group': AC_GROUP,
|
||||
'poly': AC_POLY,
|
||||
'light': AC_LIGHT
|
||||
}
|
||||
|
||||
AC_OB_BAD_TYPES_LIST = [] # to hold references to unknown (wrong) ob types
|
||||
|
||||
def inform(msg):
|
||||
global VERBOSE
|
||||
if VERBOSE: print msg
|
||||
|
||||
def euler_in_radians(eul):
|
||||
"Used while there's a bug in the BPY API"
|
||||
eul.x = radians(eul.x)
|
||||
eul.y = radians(eul.y)
|
||||
eul.z = radians(eul.z)
|
||||
return eul
|
||||
|
||||
class Obj:
|
||||
|
||||
def __init__(self, type):
|
||||
self.type = type
|
||||
self.dad = None
|
||||
self.name = ''
|
||||
self.data = ''
|
||||
self.tex = ''
|
||||
self.texrep = [1,1]
|
||||
self.texoff = None
|
||||
self.loc = []
|
||||
self.rot = []
|
||||
self.size = []
|
||||
self.crease = 30
|
||||
self.subdiv = 0
|
||||
self.vlist = []
|
||||
self.flist_cfg = []
|
||||
self.flist_v = []
|
||||
self.flist_uv = []
|
||||
self.elist = []
|
||||
self.matlist = []
|
||||
self.kids = 0
|
||||
|
||||
self.bl_obj = None # the actual Blender object created from this data
|
||||
|
||||
class AC3DImport:
|
||||
|
||||
def __init__(self, filename):
|
||||
|
||||
global errmsg
|
||||
|
||||
self.scene = Scene.GetCurrent()
|
||||
|
||||
self.i = 0
|
||||
errmsg = ''
|
||||
self.importdir = bsys.dirname(filename)
|
||||
try:
|
||||
file = open(filename, 'r')
|
||||
except IOError, (errno, strerror):
|
||||
errmsg = "IOError #%s: %s" % (errno, strerror)
|
||||
Blender.Draw.PupMenu('ERROR: %s' % errmsg)
|
||||
inform(errmsg)
|
||||
return None
|
||||
header = file.read(5)
|
||||
header, version = header[:4], header[-1]
|
||||
if header != 'AC3D':
|
||||
file.close()
|
||||
errmsg = 'AC3D header not found (invalid file)'
|
||||
Blender.Draw.PupMenu('ERROR: %s' % errmsg)
|
||||
inform(errmsg)
|
||||
return None
|
||||
elif version != 'b':
|
||||
inform('AC3D file version 0x%s.' % version)
|
||||
inform('This importer is for version 0xb, so it may fail.')
|
||||
|
||||
self.token = {'OBJECT': self.parse_obj,
|
||||
'numvert': self.parse_vert,
|
||||
'numsurf': self.parse_surf,
|
||||
'name': self.parse_name,
|
||||
'data': self.parse_data,
|
||||
'kids': self.parse_kids,
|
||||
'loc': self.parse_loc,
|
||||
'rot': self.parse_rot,
|
||||
'MATERIAL': self.parse_mat,
|
||||
'texture': self.parse_tex,
|
||||
'texrep': self.parse_texrep,
|
||||
'texoff': self.parse_texoff,
|
||||
'subdiv': self.parse_subdiv,
|
||||
'crease': self.parse_crease}
|
||||
|
||||
self.objlist = []
|
||||
self.mlist = []
|
||||
self.kidsnumlist = []
|
||||
self.dad = None
|
||||
|
||||
self.lines = file.readlines()
|
||||
self.lines.append('')
|
||||
self.parse_file()
|
||||
file.close()
|
||||
|
||||
self.testAC3DImport()
|
||||
|
||||
def parse_obj(self, value):
|
||||
kidsnumlist = self.kidsnumlist
|
||||
if kidsnumlist:
|
||||
while not kidsnumlist[-1]:
|
||||
kidsnumlist.pop()
|
||||
if kidsnumlist:
|
||||
self.dad = self.dad.dad
|
||||
else:
|
||||
inform('Ignoring unexpected data at end of file.')
|
||||
return -1 # bad file with more objects than reported
|
||||
kidsnumlist[-1] -= 1
|
||||
if value in AC_OB_TYPES:
|
||||
new = Obj(AC_OB_TYPES[value])
|
||||
else:
|
||||
if value not in AC_OB_BAD_TYPES_LIST:
|
||||
AC_OB_BAD_TYPES_LIST.append(value)
|
||||
inform('Unexpected object type keyword: "%s". Assuming it is of type: "poly".' % value)
|
||||
new = Obj(AC_OB_TYPES['poly'])
|
||||
new.dad = self.dad
|
||||
new.name = value
|
||||
self.objlist.append(new)
|
||||
|
||||
def parse_kids(self, value):
|
||||
kids = int(value)
|
||||
if kids:
|
||||
self.kidsnumlist.append(kids)
|
||||
self.dad = self.objlist[-1]
|
||||
self.objlist[-1].kids = kids
|
||||
|
||||
def parse_name(self, value):
|
||||
name = value.split('"')[1]
|
||||
self.objlist[-1].name = name
|
||||
|
||||
def parse_data(self, value):
|
||||
data = self.lines[self.i].strip()
|
||||
self.objlist[-1].data = data
|
||||
|
||||
def parse_tex(self, value):
|
||||
line = self.lines[self.i - 1] # parse again to properly get paths with spaces
|
||||
texture = line.split('"')[1]
|
||||
self.objlist[-1].tex = texture
|
||||
|
||||
def parse_texrep(self, trash):
|
||||
trep = self.lines[self.i - 1]
|
||||
trep = trep.split()
|
||||
trep = [float(trep[1]), float(trep[2])]
|
||||
self.objlist[-1].texrep = trep
|
||||
self.objlist[-1].texoff = [0, 0]
|
||||
|
||||
def parse_texoff(self, trash):
|
||||
toff = self.lines[self.i - 1]
|
||||
toff = toff.split()
|
||||
toff = [float(toff[1]), float(toff[2])]
|
||||
self.objlist[-1].texoff = toff
|
||||
|
||||
def parse_mat(self, value):
|
||||
i = self.i - 1
|
||||
lines = self.lines
|
||||
line = lines[i].split()
|
||||
mat_name = ''
|
||||
mat_col = mat_amb = mat_emit = mat_spec_col = mat_mir_col = [0,0,0]
|
||||
mat_alpha = 1
|
||||
mat_spec = 1.0
|
||||
|
||||
while line[0] == 'MATERIAL':
|
||||
mat_name = line[1].split('"')[1]
|
||||
mat_col = map(float,[line[3],line[4],line[5]])
|
||||
v = map(float,[line[7],line[8],line[9]])
|
||||
mat_amb = (v[0]+v[1]+v[2]) / 3.0
|
||||
v = map(float,[line[11],line[12],line[13]])
|
||||
mat_emit = (v[0]+v[1]+v[2]) / 3.0
|
||||
if EMIS_AS_MIRCOL:
|
||||
mat_emit = 0
|
||||
mat_mir_col = map(float,[line[11],line[12],line[13]])
|
||||
|
||||
mat_spec_col = map(float,[line[15],line[16],line[17]])
|
||||
mat_spec = float(line[19]) / 64.0
|
||||
mat_alpha = float(line[-1])
|
||||
mat_alpha = 1 - mat_alpha
|
||||
self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_mir_col, mat_alpha])
|
||||
i += 1
|
||||
line = lines[i].split()
|
||||
|
||||
self.i = i
|
||||
|
||||
def parse_rot(self, trash):
|
||||
i = self.i - 1
|
||||
ob = self.objlist[-1]
|
||||
rot = self.lines[i].split(' ', 1)[1]
|
||||
rot = map(float, rot.split())
|
||||
matrix = Matrix(rot[:3], rot[3:6], rot[6:])
|
||||
ob.rot = matrix
|
||||
size = matrix.scalePart() # vector
|
||||
ob.size = size
|
||||
|
||||
def parse_loc(self, trash):
|
||||
i = self.i - 1
|
||||
loc = self.lines[i].split(' ', 1)[1]
|
||||
loc = map(float, loc.split())
|
||||
self.objlist[-1].loc = Vector(loc)
|
||||
|
||||
def parse_crease(self, value):
|
||||
# AC3D: range is [0.0, 180.0]; Blender: [1, 80]
|
||||
value = float(value)
|
||||
self.objlist[-1].crease = int(value)
|
||||
|
||||
def parse_subdiv(self, value):
|
||||
self.objlist[-1].subdiv = int(value)
|
||||
|
||||
def parse_vert(self, value):
|
||||
i = self.i
|
||||
lines = self.lines
|
||||
obj = self.objlist[-1]
|
||||
vlist = obj.vlist
|
||||
n = int(value)
|
||||
|
||||
while n:
|
||||
line = lines[i].split()
|
||||
line = map(float, line)
|
||||
vlist.append(line)
|
||||
n -= 1
|
||||
i += 1
|
||||
|
||||
if vlist: # prepend a vertex at 1st position to deal with vindex 0 issues
|
||||
vlist.insert(0, line)
|
||||
|
||||
self.i = i
|
||||
|
||||
def parse_surf(self, value):
|
||||
i = self.i
|
||||
is_smooth = 0
|
||||
double_sided = 0
|
||||
lines = self.lines
|
||||
obj = self.objlist[-1]
|
||||
vlist = obj.vlist
|
||||
matlist = obj.matlist
|
||||
numsurf = int(value)
|
||||
NUMSURF = numsurf
|
||||
|
||||
badface_notpoly = badface_multirefs = 0
|
||||
|
||||
while numsurf:
|
||||
flags = lines[i].split()[1][2:]
|
||||
if len(flags) > 1:
|
||||
flaghigh = int(flags[0])
|
||||
flaglow = int(flags[1])
|
||||
else:
|
||||
flaghigh = 0
|
||||
flaglow = int(flags[0])
|
||||
|
||||
is_smooth = flaghigh & 1
|
||||
twoside = flaghigh & 2
|
||||
nextline = lines[i+1].split()
|
||||
if nextline[0] != 'mat': # the "mat" line may be missing (found in one buggy .ac file)
|
||||
matid = 0
|
||||
if not matid in matlist: matlist.append(matid)
|
||||
i += 2
|
||||
else:
|
||||
matid = int(nextline[1])
|
||||
if not matid in matlist: matlist.append(matid)
|
||||
nextline = lines[i+2].split()
|
||||
i += 3
|
||||
refs = int(nextline[1])
|
||||
face = []
|
||||
faces = []
|
||||
edges = []
|
||||
fuv = []
|
||||
fuvs = []
|
||||
rfs = refs
|
||||
|
||||
while rfs:
|
||||
line = lines[i].split()
|
||||
v = int(line[0]) + 1 # + 1 to avoid vindex == 0
|
||||
uv = [float(line[1]), float(line[2])]
|
||||
face.append(v)
|
||||
fuv.append(Vector(uv))
|
||||
rfs -= 1
|
||||
i += 1
|
||||
|
||||
if flaglow: # it's a line or closed line, not a polygon
|
||||
while len(face) >= 2:
|
||||
cut = face[:2]
|
||||
edges.append(cut)
|
||||
face = face[1:]
|
||||
|
||||
if flaglow == 1 and edges: # closed line
|
||||
face = [edges[-1][-1], edges[0][0]]
|
||||
edges.append(face)
|
||||
|
||||
else: # polygon
|
||||
|
||||
# check for bad face, that references same vertex more than once
|
||||
lenface = len(face)
|
||||
if lenface < 3:
|
||||
# less than 3 vertices, not a face
|
||||
badface_notpoly += 1
|
||||
elif sum(map(face.count, face)) != lenface:
|
||||
# multiple references to the same vertex
|
||||
badface_multirefs += 1
|
||||
else: # ok, seems fine
|
||||
if len(face) > 4: # ngon, triangulate it
|
||||
polyline = []
|
||||
for vi in face:
|
||||
polyline.append(Vector(vlist[vi]))
|
||||
tris = PolyFill([polyline])
|
||||
for t in tris:
|
||||
tri = [face[t[0]], face[t[1]], face[t[2]]]
|
||||
triuvs = [fuv[t[0]], fuv[t[1]], fuv[t[2]]]
|
||||
faces.append(tri)
|
||||
fuvs.append(triuvs)
|
||||
else: # tri or quad
|
||||
faces.append(face)
|
||||
fuvs.append(fuv)
|
||||
|
||||
obj.flist_cfg.extend([[matid, is_smooth, twoside]] * len(faces))
|
||||
obj.flist_v.extend(faces)
|
||||
obj.flist_uv.extend(fuvs)
|
||||
obj.elist.extend(edges) # loose edges
|
||||
|
||||
numsurf -= 1
|
||||
|
||||
if badface_notpoly or badface_multirefs:
|
||||
inform('Object "%s" - ignoring bad faces:' % obj.name)
|
||||
if badface_notpoly:
|
||||
inform('\t%d face(s) with less than 3 vertices.' % badface_notpoly)
|
||||
if badface_multirefs:
|
||||
inform('\t%d face(s) with multiple references to a same vertex.' % badface_multirefs)
|
||||
|
||||
self.i = i
|
||||
|
||||
def parse_file(self):
|
||||
i = 1
|
||||
lines = self.lines
|
||||
line = lines[i].split()
|
||||
|
||||
while line:
|
||||
kw = ''
|
||||
for k in self.token.keys():
|
||||
if line[0] == k:
|
||||
kw = k
|
||||
break
|
||||
i += 1
|
||||
if kw:
|
||||
self.i = i
|
||||
result = self.token[kw](line[1])
|
||||
if result:
|
||||
break # bad .ac file, stop parsing
|
||||
i = self.i
|
||||
line = lines[i].split()
|
||||
|
||||
# for each group of meshes we try to find one that can be used as
|
||||
# parent of the group in Blender.
|
||||
# If not found, we can use an Empty as parent.
|
||||
def found_parent(self, groupname, olist):
|
||||
l = [o for o in olist if o.type == AC_POLY \
|
||||
and not o.kids and not o.rot and not o.loc]
|
||||
if l:
|
||||
for o in l:
|
||||
if o.name == groupname:
|
||||
return o
|
||||
#return l[0]
|
||||
return None
|
||||
|
||||
def build_hierarchy(self):
|
||||
blmatrix = AC_TO_BLEND_MATRIX
|
||||
|
||||
olist = self.objlist[1:]
|
||||
olist.reverse()
|
||||
|
||||
scene = self.scene
|
||||
|
||||
newlist = []
|
||||
|
||||
for o in olist:
|
||||
kids = o.kids
|
||||
if kids:
|
||||
children = newlist[-kids:]
|
||||
newlist = newlist[:-kids]
|
||||
if o.type == AC_GROUP:
|
||||
parent = self.found_parent(o.name, children)
|
||||
if parent:
|
||||
children.remove(parent)
|
||||
o.bl_obj = parent.bl_obj
|
||||
else: # not found, use an empty
|
||||
empty = scene.objects.new('Empty', o.name)
|
||||
o.bl_obj = empty
|
||||
|
||||
bl_children = [c.bl_obj for c in children if c.bl_obj != None]
|
||||
|
||||
o.bl_obj.makeParent(bl_children, 0, 1)
|
||||
for child in children:
|
||||
blob = child.bl_obj
|
||||
if not blob: continue
|
||||
if child.rot:
|
||||
eul = euler_in_radians(child.rot.toEuler())
|
||||
blob.setEuler(eul)
|
||||
if child.size:
|
||||
blob.size = child.size
|
||||
if not child.loc:
|
||||
child.loc = Vector(0.0, 0.0, 0.0)
|
||||
blob.setLocation(child.loc)
|
||||
|
||||
newlist.append(o)
|
||||
|
||||
for o in newlist: # newlist now only has objs w/o parents
|
||||
blob = o.bl_obj
|
||||
if not blob:
|
||||
continue
|
||||
if o.size:
|
||||
o.bl_obj.size = o.size
|
||||
if not o.rot:
|
||||
blob.setEuler([1.5707963267948966, 0, 0])
|
||||
else:
|
||||
matrix = o.rot * blmatrix
|
||||
eul = euler_in_radians(matrix.toEuler())
|
||||
blob.setEuler(eul)
|
||||
if o.loc:
|
||||
o.loc *= blmatrix
|
||||
else:
|
||||
o.loc = Vector(0.0, 0.0, 0.0)
|
||||
blob.setLocation(o.loc) # forces DAG update, so we do it even for 0, 0, 0
|
||||
|
||||
# XXX important: until we fix the BPy API so it doesn't increase user count
|
||||
# when wrapping a Blender object, this piece of code is needed for proper
|
||||
# object (+ obdata) deletion in Blender:
|
||||
for o in self.objlist:
|
||||
if o.bl_obj:
|
||||
o.bl_obj = None
|
||||
|
||||
def testAC3DImport(self):
|
||||
|
||||
FACE_TWOSIDE = Mesh.FaceModes['TWOSIDE']
|
||||
FACE_TEX = Mesh.FaceModes['TEX']
|
||||
MESH_AUTOSMOOTH = Mesh.Modes['AUTOSMOOTH']
|
||||
|
||||
MAT_MODE_ZTRANSP = Material.Modes['ZTRANSP']
|
||||
MAT_MODE_TRANSPSHADOW = Material.Modes['TRANSPSHADOW']
|
||||
|
||||
scene = self.scene
|
||||
|
||||
bl_images = {} # loaded texture images
|
||||
missing_textures = [] # textures we couldn't find
|
||||
|
||||
objlist = self.objlist[1:] # skip 'world'
|
||||
|
||||
bmat = []
|
||||
has_transp_mats = False
|
||||
for mat in self.mlist:
|
||||
name = mat[0]
|
||||
m = Material.New(name)
|
||||
m.rgbCol = (mat[1][0], mat[1][1], mat[1][2])
|
||||
m.amb = mat[2]
|
||||
m.emit = mat[3]
|
||||
m.specCol = (mat[4][0], mat[4][1], mat[4][2])
|
||||
m.spec = mat[5]
|
||||
m.mirCol = (mat[6][0], mat[6][1], mat[6][2])
|
||||
m.alpha = mat[7]
|
||||
if m.alpha < 1.0:
|
||||
m.mode |= MAT_MODE_ZTRANSP
|
||||
has_transp_mats = True
|
||||
bmat.append(m)
|
||||
|
||||
if has_transp_mats:
|
||||
for mat in bmat:
|
||||
mat.mode |= MAT_MODE_TRANSPSHADOW
|
||||
|
||||
obj_idx = 0 # index of current obj in loop
|
||||
for obj in objlist:
|
||||
if obj.type == AC_GROUP:
|
||||
continue
|
||||
elif obj.type == AC_LIGHT:
|
||||
light = Lamp.New('Lamp')
|
||||
object = scene.objects.new(light, obj.name)
|
||||
#object.select(True)
|
||||
obj.bl_obj = object
|
||||
if obj.data:
|
||||
light.name = obj.data
|
||||
continue
|
||||
|
||||
# type AC_POLY:
|
||||
|
||||
# old .ac files used empty meshes as groups, convert to a real ac group
|
||||
if not obj.vlist and obj.kids:
|
||||
obj.type = AC_GROUP
|
||||
continue
|
||||
|
||||
mesh = Mesh.New()
|
||||
object = scene.objects.new(mesh, obj.name)
|
||||
#object.select(True)
|
||||
obj.bl_obj = object
|
||||
if obj.data: mesh.name = obj.data
|
||||
mesh.degr = obj.crease # will auto clamp to [1, 80]
|
||||
|
||||
if not obj.vlist: # no vertices? nothing more to do
|
||||
continue
|
||||
|
||||
mesh.verts.extend(obj.vlist)
|
||||
|
||||
objmat_indices = []
|
||||
for mat in bmat:
|
||||
if bmat.index(mat) in obj.matlist:
|
||||
objmat_indices.append(bmat.index(mat))
|
||||
mesh.materials += [mat]
|
||||
if DISPLAY_TRANSP and mat.alpha < 1.0:
|
||||
object.transp = True
|
||||
|
||||
for e in obj.elist:
|
||||
mesh.edges.extend(e)
|
||||
|
||||
if obj.flist_v:
|
||||
mesh.faces.extend(obj.flist_v)
|
||||
|
||||
facesnum = len(mesh.faces)
|
||||
|
||||
if facesnum == 0: # shouldn't happen, of course
|
||||
continue
|
||||
|
||||
mesh.faceUV = True
|
||||
|
||||
# checking if the .ac file had duplicate faces (Blender ignores them)
|
||||
if facesnum != len(obj.flist_v):
|
||||
# it has, ugh. Let's clean the uv list:
|
||||
lenfl = len(obj.flist_v)
|
||||
flist = obj.flist_v
|
||||
uvlist = obj.flist_uv
|
||||
cfglist = obj.flist_cfg
|
||||
for f in flist:
|
||||
f.sort()
|
||||
fi = lenfl
|
||||
while fi > 0: # remove data related to duplicates
|
||||
fi -= 1
|
||||
if flist[fi] in flist[:fi]:
|
||||
uvlist.pop(fi)
|
||||
cfglist.pop(fi)
|
||||
|
||||
img = None
|
||||
if obj.tex != '':
|
||||
if obj.tex in bl_images.keys():
|
||||
img = bl_images[obj.tex]
|
||||
elif obj.tex not in missing_textures:
|
||||
texfname = None
|
||||
objtex = obj.tex
|
||||
baseimgname = bsys.basename(objtex)
|
||||
if bsys.exists(objtex) == 1:
|
||||
texfname = objtex
|
||||
elif bsys.exists(bsys.join(self.importdir, objtex)):
|
||||
texfname = bsys.join(self.importdir, objtex)
|
||||
else:
|
||||
if baseimgname.find('\\') > 0:
|
||||
baseimgname = bsys.basename(objtex.replace('\\','/'))
|
||||
objtex = bsys.join(self.importdir, baseimgname)
|
||||
if bsys.exists(objtex) == 1:
|
||||
texfname = objtex
|
||||
else:
|
||||
objtex = bsys.join(TEXTURES_DIR, baseimgname)
|
||||
if bsys.exists(objtex):
|
||||
texfname = objtex
|
||||
if texfname:
|
||||
try:
|
||||
img = Image.Load(texfname)
|
||||
# Commented because it's unnecessary:
|
||||
#img.xrep = int(obj.texrep[0])
|
||||
#img.yrep = int(obj.texrep[1])
|
||||
if img:
|
||||
bl_images[obj.tex] = img
|
||||
except:
|
||||
inform("Couldn't load texture: %s" % baseimgname)
|
||||
else:
|
||||
missing_textures.append(obj.tex)
|
||||
inform("Couldn't find texture: %s" % baseimgname)
|
||||
|
||||
for i in range(facesnum):
|
||||
f = obj.flist_cfg[i]
|
||||
fmat = f[0]
|
||||
is_smooth = f[1]
|
||||
twoside = f[2]
|
||||
bface = mesh.faces[i]
|
||||
bface.smooth = is_smooth
|
||||
if twoside: bface.mode |= FACE_TWOSIDE
|
||||
if img:
|
||||
bface.mode |= FACE_TEX
|
||||
bface.image = img
|
||||
bface.mat = objmat_indices.index(fmat)
|
||||
fuv = obj.flist_uv[i]
|
||||
if obj.texoff:
|
||||
uoff = obj.texoff[0]
|
||||
voff = obj.texoff[1]
|
||||
urep = obj.texrep[0]
|
||||
vrep = obj.texrep[1]
|
||||
for uv in fuv:
|
||||
uv[0] *= urep
|
||||
uv[1] *= vrep
|
||||
uv[0] += uoff
|
||||
uv[1] += voff
|
||||
|
||||
mesh.faces[i].uv = fuv
|
||||
|
||||
# finally, delete the 1st vertex we added to prevent vindices == 0
|
||||
mesh.verts.delete(0)
|
||||
|
||||
mesh.calcNormals()
|
||||
|
||||
mesh.mode = MESH_AUTOSMOOTH
|
||||
|
||||
# subdiv: create SUBSURF modifier in Blender
|
||||
if SUBDIV and obj.subdiv > 0:
|
||||
subdiv = obj.subdiv
|
||||
subdiv_render = subdiv
|
||||
# just to be safe:
|
||||
if subdiv_render > 6: subdiv_render = 6
|
||||
if subdiv > 3: subdiv = 3
|
||||
modif = object.modifiers.append(Modifier.Types.SUBSURF)
|
||||
modif[Modifier.Settings.LEVELS] = subdiv
|
||||
modif[Modifier.Settings.RENDLEVELS] = subdiv_render
|
||||
|
||||
obj_idx += 1
|
||||
|
||||
self.build_hierarchy()
|
||||
scene.update()
|
||||
|
||||
# End of class AC3DImport
|
||||
|
||||
def filesel_callback(filename):
|
||||
|
||||
inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename)
|
||||
Window.WaitCursor(1)
|
||||
starttime = bsys.time()
|
||||
test = AC3DImport(filename)
|
||||
Window.WaitCursor(0)
|
||||
endtime = bsys.time() - starttime
|
||||
inform('Done! Data imported in %.3f seconds.\n' % endtime)
|
||||
|
||||
Window.EditMode(0)
|
||||
|
||||
Window.FileSelector(filesel_callback, "Import AC3D", "*.ac")
|
||||
@@ -1,13 +0,0 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Empty mesh'
|
||||
Blender: 243
|
||||
Group: 'AddMesh'
|
||||
"""
|
||||
import BPyAddMesh
|
||||
import Blender
|
||||
|
||||
def main():
|
||||
BPyAddMesh.add_mesh_simple('EmptyMesh', [], [], [])
|
||||
|
||||
main()
|
||||
@@ -1,69 +0,0 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Torus'
|
||||
Blender: 243
|
||||
Group: 'AddMesh'
|
||||
"""
|
||||
import BPyAddMesh
|
||||
import Blender
|
||||
try: from math import cos, sin, pi
|
||||
except: math = None
|
||||
|
||||
def add_torus(PREF_MAJOR_RAD, PREF_MINOR_RAD, PREF_MAJOR_SEG, PREF_MINOR_SEG):
|
||||
Vector = Blender.Mathutils.Vector
|
||||
RotationMatrix = Blender.Mathutils.RotationMatrix
|
||||
verts = []
|
||||
faces = []
|
||||
i1 = 0
|
||||
tot_verts = PREF_MAJOR_SEG * PREF_MINOR_SEG
|
||||
for major_index in xrange(PREF_MAJOR_SEG):
|
||||
verts_tmp = []
|
||||
mtx = RotationMatrix( 360 * float(major_index)/PREF_MAJOR_SEG, 3, 'z' )
|
||||
|
||||
for minor_index in xrange(PREF_MINOR_SEG):
|
||||
angle = 2*pi*minor_index/PREF_MINOR_SEG
|
||||
|
||||
verts.append( Vector(PREF_MAJOR_RAD+(cos(angle)*PREF_MINOR_RAD), 0, (sin(angle)*PREF_MINOR_RAD)) * mtx )
|
||||
if minor_index+1==PREF_MINOR_SEG:
|
||||
i2 = (major_index)*PREF_MINOR_SEG
|
||||
i3 = i1 + PREF_MINOR_SEG
|
||||
i4 = i2 + PREF_MINOR_SEG
|
||||
|
||||
else:
|
||||
i2 = i1 + 1
|
||||
i3 = i1 + PREF_MINOR_SEG
|
||||
i4 = i3 + 1
|
||||
|
||||
if i2>=tot_verts: i2 = i2-tot_verts
|
||||
if i3>=tot_verts: i3 = i3-tot_verts
|
||||
if i4>=tot_verts: i4 = i4-tot_verts
|
||||
|
||||
faces.append( (i3,i4,i2,i1) )
|
||||
i1+=1
|
||||
|
||||
return verts, faces
|
||||
|
||||
def main():
|
||||
Draw = Blender.Draw
|
||||
PREF_MAJOR_RAD = Draw.Create(1.0)
|
||||
PREF_MINOR_RAD = Draw.Create(0.25)
|
||||
PREF_MAJOR_SEG = Draw.Create(48)
|
||||
PREF_MINOR_SEG = Draw.Create(16)
|
||||
|
||||
if not Draw.PupBlock('Add Torus', [\
|
||||
('Major Radius:', PREF_MAJOR_RAD, 0.01, 100, 'Radius for the main ring of the torus'),\
|
||||
('Minor Radius:', PREF_MINOR_RAD, 0.01, 100, 'Radius for the minor ring of the torus setting the thickness of the ring'),\
|
||||
('Major Segments:', PREF_MAJOR_SEG, 3, 256, 'Number of segments for the main ring of the torus'),\
|
||||
('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Number of segments for the minor ring of the torus'),\
|
||||
]):
|
||||
return
|
||||
|
||||
verts, faces = add_torus(PREF_MAJOR_RAD.val, PREF_MINOR_RAD.val, PREF_MAJOR_SEG.val, PREF_MINOR_SEG.val)
|
||||
|
||||
BPyAddMesh.add_mesh_simple('Torus', verts, [], faces)
|
||||
|
||||
if cos and sin and pi:
|
||||
main()
|
||||
else:
|
||||
Blender.Draw.PupMenu("Error%t|This script requires a full python installation")
|
||||
|
||||
@@ -1,792 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Bake Constraints'
|
||||
Blender: 246
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Bake a Constrained object/rig to IPOs'
|
||||
Fillename: 'Bake_Constraint.py'
|
||||
"""
|
||||
|
||||
__author__ = "Roger Wickes (rogerwickes(at)yahoo.com)"
|
||||
__script__ = "Animation Bake Constraints"
|
||||
__version__ = "0.7"
|
||||
__url__ = ["Communicate problems and errors, http://www.blenderartists.com/forum/private.php?do=newpm to PapaSmurf"]
|
||||
__email__= ["Roger Wickes, rogerwickes@yahoo.com", "scripts"]
|
||||
__bpydoc__ = """\
|
||||
|
||||
bake_constraints
|
||||
|
||||
This script bakes the real-world LocRot of an object (the net effect of any constraints -
|
||||
(Copy, Limit, Track, Follow, - that affect Location, Rotation)
|
||||
(usually one constrained to match another's location and/or Tracked to another)
|
||||
and creates a clone with a set of Ipo Curves named Ipo<objname>
|
||||
These curves control a non-constrained object and thus make it mimic the constrained object
|
||||
Actions can be then be edited without the need for the drivers/constraining objects
|
||||
|
||||
Developed for use with MoCap data, where a bone is constrained to point at an empty
|
||||
moving through space and time. This records the actual locrot of the armature
|
||||
so that the motion can be edited, reoriented, scaled, and used as NLA Actions
|
||||
|
||||
see also wiki Scripts/Manual/ Tutorial/Motion Capture <br>
|
||||
|
||||
Usage: <br>
|
||||
- Select the reference Object(s) you want to bake <br>
|
||||
- Set the frame range to bake in the Anim Panel <br>
|
||||
- Set the test code (if you want a self-test) in the RT field in the Anim Panel <br>
|
||||
-- Set RT:1 to create a test armature <br>
|
||||
-- Set RT: up to 100 for more debug messages and status updates <br>
|
||||
<br>
|
||||
- Run the script <br>
|
||||
- The clone copy of the object is created and it has an IPO curve assigned to it. <br>
|
||||
- The clone shadows the object by an offset locrot (see usrDelta) <br>
|
||||
- That Object has Ipo Location and Rotation curves that make the clone mimic the movement <br>
|
||||
of the selected object, but without using constraints. <br>
|
||||
- If the object was an Armature, the clone's bones move identically in relation to the <br>
|
||||
original armature, and an Action is created that drives the bone movements. <br>
|
||||
|
||||
Version History:
|
||||
0.1: bakes Loc Rot for a constrained object
|
||||
0.2: bakes Loc and Rot for the bones within Armature object
|
||||
0.3: UI for setting options
|
||||
0.3.1 add manual to script library
|
||||
0.4: bake multiple objects
|
||||
0.5: root bone worldspace rotation
|
||||
0.6: re-integration with BPyArmature
|
||||
0.7: bakes parents and leaves clones selected
|
||||
|
||||
License, Copyright, and Attribution:
|
||||
by Roger WICKES May 2008, released under Blender Artistic Licence to Public Domain
|
||||
feel free to add to any Blender Python Scripts Bundle.
|
||||
Thanks to Jean-Baptiste PERIN, IdeasMan42 (Campbell Barton), Basil_Fawlty/Cage_drei (Andrew Cruse)
|
||||
much lifted/learned from blender.org/documentation/245PytonDoc and wiki
|
||||
some modules based on c3D_Import.py, PoseLib16.py and IPO/Armature code examples e.g. camera jitter
|
||||
|
||||
Pseudocode:
|
||||
Initialize
|
||||
If at least one object is selected
|
||||
For each selected object,
|
||||
create a cloned object
|
||||
remove any constraints on the clone
|
||||
create or reset an ipo curve named like the object
|
||||
for each frame
|
||||
set the clone's locrot key based on the reference object
|
||||
if it's an armature,
|
||||
create an action (which is an Ipo for each bone)
|
||||
for each frame of the animation
|
||||
for each bone in the armature
|
||||
set the key
|
||||
Else you're a smurf
|
||||
|
||||
Test Conditions and Regressions:
|
||||
1. (v0.1) Non-armatures (the cube), with ipo curve and constraints at the object level
|
||||
2. armatures, with ipo curve and constraints at the object level
|
||||
3. armatures, with bones that have ipo curves and constraints
|
||||
4. objects without parents, children with unselected parents, select children first.
|
||||
|
||||
Naming conventions:
|
||||
arm = a specific objec type armature
|
||||
bone = bones that make up the skeleton of an armature
|
||||
|
||||
ob = object, an instance of an object type
|
||||
ebone = edit bone, a bone in edit mode
|
||||
pbone = pose bone, a posed bone in an object
|
||||
tst = testing, self-test routines
|
||||
usr = user-entered or designated stuff
|
||||
"""
|
||||
########################################
|
||||
|
||||
import Blender
|
||||
from Blender import *
|
||||
from Blender.Mathutils import *
|
||||
import struct
|
||||
import string
|
||||
import bpy
|
||||
import BPyMessages
|
||||
import BPyArmature
|
||||
# reload(BPyArmature)
|
||||
from BPyArmature import getBakedPoseData
|
||||
|
||||
Vector= Blender.Mathutils.Vector
|
||||
Euler= Blender.Mathutils.Euler
|
||||
Matrix= Blender.Mathutils.Matrix #invert() function at least
|
||||
RotationMatrix = Blender.Mathutils.RotationMatrix
|
||||
TranslationMatrix= Blender.Mathutils.TranslationMatrix
|
||||
Quaternion = Blender.Mathutils.Quaternion
|
||||
Vector = Blender.Mathutils.Vector
|
||||
POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT]
|
||||
|
||||
#=================
|
||||
# Global Variables
|
||||
#=================
|
||||
|
||||
# set senstitivity for displaying debug/console messages. 0=none, 100=max
|
||||
# then call debug(num,string) to conditionally display status/info in console window
|
||||
MODE=Blender.Get('rt') #execution mode: 0=run normal, 1=make test armature
|
||||
DEBUG=Blender.Get('rt') #how much detail on internal processing for user to see. range 0-100
|
||||
BATCH=False #called from command line? is someone there? Would you like some cake?
|
||||
|
||||
#there are two coordinate systems, the real, or absolute 3D space,
|
||||
# and the local relative to a parent.
|
||||
COORDINATE_SYSTEMS = ['local','real']
|
||||
COORD_LOCAL = 0
|
||||
COORD_REAL = 1
|
||||
|
||||
# User Settings - Change these options manually or via GUI (future TODO)
|
||||
usrCoord = COORD_REAL # what the user wants
|
||||
usrParent = False # True=clone keeps original parent, False = clone's parent is the clone of the original parent (if cloned)
|
||||
usrFreeze = 2 #2=yes, 0=no. Freezes shadow object in place at current frame as origin
|
||||
# delta is amount to offset/change from the reference object. future set in a ui, so technically not a constant
|
||||
usrDelta = [10,10,0,0,0,0] #order specific - Loc xyz Rot xyz
|
||||
usrACTION = True # Offset baked Action frames to start at frame 1
|
||||
|
||||
CURFRAME = 'curframe' #keyword to use when getting the frame number that the scene is presently on
|
||||
ARMATURE = 'Armature' #en anglais
|
||||
BONE_SPACES = ['ARMATURESPACE','BONESPACE']
|
||||
# 'ARMATURESPACE' - this matrix of the bone in relation to the armature
|
||||
# 'BONESPACE' - the matrix of the bone in relation to itself
|
||||
|
||||
#Ipo curves created are prefixed with a name, like Ipo_ or Bake_ followed by the object/bone name
|
||||
#bakedArmName = "b." #used for both the armature class and object instance
|
||||
usrObjectNamePrefix= ""
|
||||
#ipoBoneNamePrefix = ""
|
||||
# for example, if on entry an armature named Man was selected, and the object prefix was "a."
|
||||
# on exit an armature and an IPO curve named a.Man exists for the object as a whole
|
||||
# if that armature had bones (spine, neck, arm) and the bone prefix was "a."
|
||||
# the bones and IPO curves will be (a.spine, a.neck, a.arm)
|
||||
|
||||
R2D = 18/3.141592653589793 # radian to grad
|
||||
BLENDER_VERSION = Blender.Get('version')
|
||||
|
||||
# Gets the current scene, there can be many scenes in 1 blend file.
|
||||
scn = Blender.Scene.GetCurrent()
|
||||
|
||||
#=================
|
||||
# Methods
|
||||
#=================
|
||||
########################################
|
||||
def debug(num,msg): #use log4j or just console here.
|
||||
if DEBUG >= num:
|
||||
if BATCH == False:
|
||||
print 'debug: '[:num/10+7]+msg
|
||||
#TODO: else write out to file (runs faster if it doesnt have to display details)
|
||||
return
|
||||
|
||||
########################################
|
||||
def error(str):
|
||||
debug(0,'ERROR: '+str)
|
||||
if BATCH == False:
|
||||
Draw.PupMenu('ERROR%t|'+str)
|
||||
return
|
||||
|
||||
########################################
|
||||
def getRenderInfo():
|
||||
context=scn.getRenderingContext()
|
||||
staframe = context.startFrame()
|
||||
endframe = context.endFrame()
|
||||
if endframe<staframe: endframe=staframe
|
||||
curframe = Blender.Get(CURFRAME)
|
||||
debug(90,'Scene is on frame %i and frame range is %i to %i' % (curframe,staframe,endframe))
|
||||
return (staframe,endframe,curframe)
|
||||
|
||||
########################################
|
||||
def sortObjects(obs): #returns a list of objects sorted based on parent dependency
|
||||
obClones= []
|
||||
while len(obClones) < len(obs):
|
||||
for ob in obs:
|
||||
if not ob in obClones:
|
||||
par= ob.getParent()
|
||||
#if no parent, or the parent is not scheduled to be cloned
|
||||
if par==None:
|
||||
obClones.append(ob) # add the independent
|
||||
elif par not in obs: # parent will not be cloned
|
||||
obClones.append(ob) # add the child
|
||||
elif par in obClones: # is it on the list?
|
||||
obClones.append(ob) # add the child
|
||||
# parent may be a child, so it will be caught next time thru
|
||||
debug(100,'clone object order: \n%s' % obClones)
|
||||
return obClones # ordered list of (ob, par) tuples
|
||||
|
||||
########################################
|
||||
def sortBones(xbones): #returns a sorted list of bones that should be added,sorted based on parent dependency
|
||||
# while there are bones to add,
|
||||
# look thru the list of bones we need to add
|
||||
# if we have not already added this bone
|
||||
# if it does not have a parent
|
||||
# add it
|
||||
# else, it has a parent
|
||||
# if we already added it's parent
|
||||
# add it now.
|
||||
# else #we need to keep cycling and catch its parent
|
||||
# else it is a root bone
|
||||
# add it
|
||||
# else skip it, it's already in there
|
||||
# endfor
|
||||
# endwhile
|
||||
xboneNames=[]
|
||||
for xbone in xbones: xboneNames.append(xbone.name)
|
||||
debug (80,'reference bone order: \n%s' % xboneNames)
|
||||
eboneNames=[]
|
||||
while len(eboneNames) < len(xboneNames):
|
||||
for xbone in xbones:
|
||||
if not xbone.name in eboneNames:
|
||||
if not xbone.parent:
|
||||
eboneNames.append(xbone.name)
|
||||
else:
|
||||
if xbone.parent.name in eboneNames:
|
||||
eboneNames.append(xbone.name)
|
||||
#else skip it
|
||||
#endif
|
||||
#else prego
|
||||
#endfor
|
||||
#endwhile
|
||||
debug (80,'clone bone order: \n%s' % eboneNames)
|
||||
return eboneNames
|
||||
|
||||
########################################
|
||||
def dupliArmature(ob): #makes a copy in current scn of the armature used by ob and its bones
|
||||
ob_mat = ob.matrixWorld
|
||||
ob_data = ob.getData()
|
||||
debug(49,'Reference object uses %s' % ob_data)
|
||||
arm_ob = Armature.Get(ob_data.name) #the armature used by the passed object
|
||||
|
||||
arm = Blender.Armature.New()
|
||||
debug(20,'Cloning Armature %s to create %s' % (arm_ob.name, arm.name))
|
||||
arm.drawType = Armature.STICK #set the draw type
|
||||
|
||||
arm.makeEditable() #enter editmode
|
||||
|
||||
# for each bone in the object's armature,
|
||||
xbones=ob.data.bones.values()
|
||||
usrSpace = 0 #0=armature, 1=local
|
||||
space=[BONE_SPACES[usrSpace]][0]
|
||||
|
||||
#we have to make a list of bones, then figure out our parents, then add to the arm
|
||||
#when creating a child, we cannot link to a parent if it does not yet exist in our armature
|
||||
ebones = [] #list of the bones I want to create for my arm
|
||||
|
||||
eboneNames = sortBones(xbones)
|
||||
|
||||
i=0
|
||||
# error('bones sorted. continue?')
|
||||
for abone in eboneNames: #set all editable attributes to fully define the bone.
|
||||
for bone in xbones:
|
||||
if bone.name == abone: break # get the reference bone
|
||||
ebone = Armature.Editbone() #throw me a bone, bone-man!
|
||||
ebones.append(ebone) #you're on my list, buddy
|
||||
|
||||
ebone.name = bone.name
|
||||
ebone.headRadius = bone.headRadius
|
||||
ebone.tailRadius = bone.tailRadius
|
||||
ebone.weight = bone.weight
|
||||
ebone.options = bone.options
|
||||
|
||||
ebone.head = bone.head[space] #dictionary lookups
|
||||
ebone.tail = bone.tail[space]
|
||||
ebone.matrix = bone.matrix[space]
|
||||
ebone.roll = bone.roll[space]
|
||||
|
||||
debug(30,'Generating new %s as child of %s' % (bone,bone.parent))
|
||||
if bone.hasParent():
|
||||
# parent=bone.parent.name
|
||||
# debug(100,'looking for %s' % parent)
|
||||
# for parbone in xbones: if parbone.name == parent: break # get the parent bone
|
||||
# ebone.parent = arm.bones[ebones[j].name]
|
||||
ebone.parent = arm.bones[bone.parent.name]
|
||||
# else:
|
||||
# ebone.parent = None
|
||||
debug(30,'Generating new editbone %s as child of %s' % (ebone,ebone.parent))
|
||||
arm.bones[ebone.name] = ebone # i would have expected an append or add function, but this works
|
||||
|
||||
debug (100,'arm.bones: \n%s' % arm.bones)
|
||||
debug (20,'Cloned %i bones now in armature %s' %(len(arm.bones),arm.name))
|
||||
|
||||
myob = scn.objects.new(arm) #interestingly, object must be created before
|
||||
arm.update() #armature can be saved
|
||||
debug(40,'dupArm finished %s instanced as object %s' % (arm.name,myob.getName()))
|
||||
print ob.matrix
|
||||
print myob.matrix
|
||||
|
||||
return myob
|
||||
########################################
|
||||
def scrub(): # scrubs to startframe
|
||||
staFrame,endFrame,curFrame = getRenderInfo()
|
||||
|
||||
# eye-candy, go from current to start, fwd or back
|
||||
if not BATCH:
|
||||
debug(100, "Positioning to start...")
|
||||
frameinc=(staFrame-curFrame)/10
|
||||
if abs(frameinc) >= 1:
|
||||
for i in range(10):
|
||||
curFrame+=frameinc
|
||||
Blender.Set(CURFRAME,curFrame) # computes the constrained location of the 'real' objects
|
||||
Blender.Redraw()
|
||||
Blender.Set(CURFRAME, staFrame)
|
||||
return
|
||||
|
||||
########################################
|
||||
def bakeBones(ref_ob,arm_ob): #copy pose from ref_ob to arm_ob
|
||||
scrub()
|
||||
staFrame,endFrame,curFrame = getRenderInfo()
|
||||
act = getBakedPoseData(ref_ob, staFrame, endFrame, ACTION_BAKE = True, ACTION_BAKE_FIRST_FRAME = usrACTION) # bake the pose positions of the reference ob to the armature ob
|
||||
arm_ob.action = act
|
||||
scrub()
|
||||
|
||||
# user comprehension feature - change action name and channel ipo names to match the names of the bone they drive
|
||||
debug (80,'Renaming each action ipo to match the bone they pose')
|
||||
act.name = arm_ob.name
|
||||
arm_channels = act.getAllChannelIpos()
|
||||
pose= arm_ob.getPose()
|
||||
pbones= pose.bones.values() #we want the bones themselves, not the dictionary lookup
|
||||
for pbone in pbones:
|
||||
debug (100,'Channel listing for %s: %s' % (pbone.name,arm_channels[pbone.name] ))
|
||||
ipo=arm_channels[pbone.name]
|
||||
ipo.name = pbone.name # since bone names are unique within an armature, the pose names can be the same since they are within an Action
|
||||
|
||||
return
|
||||
|
||||
########################################
|
||||
def getOrCreateCurve(ipo, curvename):
|
||||
"""
|
||||
Retrieve or create a Blender Ipo Curve named C{curvename} in the C{ipo} Ipo
|
||||
Either an ipo curve named C{curvename} exists before the call then this curve is returned,
|
||||
Or such a curve doesn't exist before the call .. then it is created into the c{ipo} Ipo and returned
|
||||
"""
|
||||
try:
|
||||
mycurve = ipo.getCurve(curvename)
|
||||
if mycurve != None:
|
||||
pass
|
||||
else:
|
||||
mycurve = ipo.addCurve(curvename)
|
||||
except:
|
||||
mycurve = ipo.addCurve(curvename)
|
||||
return mycurve
|
||||
|
||||
########################################
|
||||
def eraseCurve(ipo,numCurves):
|
||||
debug(90,'Erasing %i curves for %' % (numCurves,ipo.GetName()))
|
||||
for i in range(numCurves):
|
||||
nbBezPoints= ipo.getNBezPoints(i)
|
||||
for j in range(nbBezPoints):
|
||||
ipo.delBezPoint(i)
|
||||
return
|
||||
|
||||
########################################
|
||||
def resetIPO(ipo):
|
||||
debug(60,'Resetting ipo curve named %s' %ipo.name)
|
||||
numCurves = ipo.getNcurves() #like LocX, LocY, etc
|
||||
if numCurves > 0:
|
||||
eraseCurve(ipo, numCurves) #erase data if one exists
|
||||
return
|
||||
|
||||
########################################
|
||||
def resetIPOs(ob): #resets all IPO curvess assocated with an object and its bones
|
||||
debug(30,'Resetting any ipo curves linked to %s' %ob.getName())
|
||||
ipo = ob.getIpo() #may be None
|
||||
ipoName = ipo.getName() #name of the IPO that guides/controls this object
|
||||
debug(70,'Object IPO is %s' %ipoName)
|
||||
try:
|
||||
ipo = Ipo.Get(ipoName)
|
||||
except:
|
||||
ipo = Ipo.New('Object', ipoName)
|
||||
resetIPO(ipo)
|
||||
if ob.getType() == ARMATURE:
|
||||
arm_data=ob.getData()
|
||||
bones=arm_data.bones.values()
|
||||
for bone in bones:
|
||||
#for each bone: get the name and check for a Pose IPO
|
||||
debug(10,'Processing '+ bone.name)
|
||||
return
|
||||
|
||||
########################################
|
||||
def parse(string,delim):
|
||||
index = string.find(delim) # -1 if not found, else pointer to delim
|
||||
if index+1: return string[:index]
|
||||
return string
|
||||
|
||||
########################################
|
||||
def newIpo(ipoName): #add a new Ipo object to the Blender scene
|
||||
ipo=Blender.Ipo.New('Object',ipoName)
|
||||
|
||||
ipo.addCurve('LocX')
|
||||
ipo.addCurve('LocY')
|
||||
ipo.addCurve('LocZ')
|
||||
ipo.addCurve('RotX')
|
||||
ipo.addCurve('RotY')
|
||||
ipo.addCurve('RotZ')
|
||||
return ipo
|
||||
|
||||
########################################
|
||||
def makeUpaName(type,name): #i know this exists in Blender somewhere...
|
||||
debug(90,'Making up a new %s name using %s as a basis.' % (type,name))
|
||||
name = (parse(name,'.'))
|
||||
if type == 'Ipo':
|
||||
ipoName = name # maybe we get lucky today
|
||||
ext = 0
|
||||
extlen = 3 # 3 digit extensions, like hello.002
|
||||
success = False
|
||||
while not(success):
|
||||
try:
|
||||
debug(100,'Trying %s' % ipoName)
|
||||
ipo = Ipo.Get(ipoName)
|
||||
#that one exists if we get here. add on extension and keep trying
|
||||
ext +=1
|
||||
if ext>=10**extlen: extlen +=1 # go to more digits if 999 not found
|
||||
ipoName = '%s.%s' % (name, str(ext).zfill(extlen))
|
||||
except: # could not find it
|
||||
success = True
|
||||
name=ipoName
|
||||
else:
|
||||
debug (0,'FATAL ERROR: I dont know how to make up a new %s name based on %s' % (type,ob))
|
||||
return None
|
||||
return name
|
||||
|
||||
########################################
|
||||
def createIpo(ob): #create an Ipo and curves and link them to this object
|
||||
#first, we have to create a unique name
|
||||
#try first with just the name of the object to keep things simple.
|
||||
ipoName = makeUpaName('Ipo',ob.getName()) # make up a name for a new Ipo based on the object name
|
||||
debug(20,'Ipo and LocRot curves called %s' % ipoName)
|
||||
ipo=newIpo(ipoName)
|
||||
ob.setIpo(ipo) #link them
|
||||
return ipo
|
||||
|
||||
########################################
|
||||
def getLocLocal(ob):
|
||||
key = [
|
||||
ob.LocX,
|
||||
ob.LocY,
|
||||
ob.LocZ,
|
||||
ob.RotX*R2D, #get the curves in this order
|
||||
ob.RotY*R2D,
|
||||
ob.RotZ*R2D
|
||||
]
|
||||
return key
|
||||
|
||||
########################################
|
||||
def getLocReal(ob):
|
||||
obMatrix = ob.matrixWorld #Thank you IdeasMan42
|
||||
loc = obMatrix.translationPart()
|
||||
rot = obMatrix.toEuler()
|
||||
key = [
|
||||
loc.x,
|
||||
loc.y,
|
||||
loc.z,
|
||||
rot.x/10,
|
||||
rot.y/10,
|
||||
rot.z/10
|
||||
]
|
||||
return key
|
||||
|
||||
########################################
|
||||
def getLocRot(ob,space):
|
||||
if space in xrange(len(COORDINATE_SYSTEMS)):
|
||||
if space == COORD_LOCAL:
|
||||
key = getLocLocal(ob)
|
||||
return key
|
||||
elif space == COORD_REAL:
|
||||
key = getLocReal(ob)
|
||||
return key
|
||||
else: #hey, programmers make mistakes too.
|
||||
debug(0,'Fatal Error: getLoc called with %i' % space)
|
||||
return
|
||||
|
||||
########################################
|
||||
def getCurves(ipo):
|
||||
ipos = [
|
||||
ipo[Ipo.OB_LOCX],
|
||||
ipo[Ipo.OB_LOCY],
|
||||
ipo[Ipo.OB_LOCZ],
|
||||
ipo[Ipo.OB_ROTX], #get the curves in this order
|
||||
ipo[Ipo.OB_ROTY],
|
||||
ipo[Ipo.OB_ROTZ]
|
||||
]
|
||||
return ipos
|
||||
|
||||
########################################
|
||||
def addPoint(time,keyLocRot,ipos):
|
||||
if BLENDER_VERSION < 245:
|
||||
debug(0,'WARNING: addPoint uses BezTriple')
|
||||
for i in range(len(ipos)):
|
||||
point = BezTriple.New() #this was new with Blender 2.45 API
|
||||
point.pt = (time, keyLocRot[i])
|
||||
point.handleTypes = [1,1]
|
||||
|
||||
ipos[i].append(point)
|
||||
return ipos
|
||||
|
||||
########################################
|
||||
def bakeFrames(ob,myipo): #bakes an object in a scene, returning the IPO containing the curves
|
||||
myipoName = myipo.getName()
|
||||
debug(20,'Baking frames for scene %s object %s to ipo %s' % (scn.getName(),ob.getName(),myipoName))
|
||||
ipos = getCurves(myipo)
|
||||
#TODO: Gui setup idea: myOffset
|
||||
# reset action to start at frame 1 or at location
|
||||
myOffset=0 #=1-staframe
|
||||
#loop through frames in the animation. Often, there is rollup and the mocap starts late
|
||||
staframe,endframe,curframe = getRenderInfo()
|
||||
for frame in range(staframe, endframe+1):
|
||||
debug(80,'Baking Frame %i' % frame)
|
||||
#tell Blender to advace to frame
|
||||
Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects
|
||||
if not BATCH: Blender.Redraw() # no secrets, let user see what we are doing
|
||||
|
||||
#using the constrained Loc Rot of the object, set the location of the unconstrained clone. Yea! Clones are FreeMen
|
||||
key = getLocRot(ob,usrCoord) #a key is a set of specifed exact channel values (LocRotScale) for a certain frame
|
||||
key = [a+b for a,b in zip(key, usrDelta)] #offset to the new location
|
||||
|
||||
myframe= frame+myOffset
|
||||
Blender.Set(CURFRAME,myframe)
|
||||
|
||||
time = Blender.Get('curtime') #for BezTriple
|
||||
ipos = addPoint(time,key,ipos) #add this data at this time to the ipos
|
||||
debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (myipoName, myframe, time, key[0], key[1], key[2], key[3], key[4], key[5]))
|
||||
# eye-candy - smoothly rewind the animation, showing now how the clone match moves
|
||||
if endframe-staframe <400 and not BATCH:
|
||||
for frame in range (endframe,staframe,-1): #rewind
|
||||
Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects
|
||||
Blender.Redraw()
|
||||
Blender.Set(CURFRAME,staframe)
|
||||
Blender.Redraw()
|
||||
|
||||
return ipos
|
||||
|
||||
########################################
|
||||
def duplicateLinked(ob):
|
||||
obType = ob.type
|
||||
debug(10,'Duplicating %s Object named %s' % (obType,ob.getName()))
|
||||
scn.objects.selected = [ob]
|
||||
## rdw: simplified by just duplicating armature. kept code as reference for creating armatures
|
||||
## disadvantage is that you cant have clone as stick and original as octahedron
|
||||
## since they share the same Armature. User can click Make Single User button.
|
||||
## if obType == ARMATURE: #build a copy from scratch
|
||||
## myob= dupliArmature(ob)
|
||||
## else:
|
||||
Blender.Object.Duplicate() # Duplicate linked, including pose constraints.
|
||||
myobs = Object.GetSelected() #duplicate is top on the list
|
||||
myob = myobs[0]
|
||||
if usrParent == False:
|
||||
myob.clrParent(usrFreeze)
|
||||
debug(20,'=myob= was created as %s' % myob.getName())
|
||||
return myob
|
||||
|
||||
########################################
|
||||
def removeConstraints(ob):
|
||||
for const in ob.constraints:
|
||||
debug(90,'removed %s => %s' % (ob.name, const))
|
||||
ob.constraints.remove(const)
|
||||
return
|
||||
|
||||
########################################
|
||||
def removeConstraintsOb(ob): # from object or armature
|
||||
debug(40,'Removing constraints from '+ob.getName())
|
||||
if BLENDER_VERSION > 241: #constraints module not available before 242
|
||||
removeConstraints(ob)
|
||||
if ob.getType() == ARMATURE:
|
||||
pose = ob.getPose()
|
||||
for pbone in pose.bones.values():
|
||||
#bone = pose.bones[bonename]
|
||||
removeConstraints(pbone)
|
||||
#should also check if it is a deflector?
|
||||
return
|
||||
|
||||
########################################
|
||||
def deLinkOb(type,ob): #remove linkages
|
||||
if type == 'Ipo':
|
||||
success = ob.clearIpo() #true=there was one
|
||||
if success: debug(80,'deLinked Ipo curve to %s' % ob.getName())
|
||||
return
|
||||
|
||||
########################################
|
||||
def bakeObject(ob): #bakes the core object locrot and assigns the Ipo to a Clone
|
||||
if ob != None:
|
||||
# Clone the object - duplicate it, clean the clone, and create an ipo curve for the clone
|
||||
myob = duplicateLinked(ob) #clone it
|
||||
myob.setName(usrObjectNamePrefix + ob.getName())
|
||||
removeConstraintsOb(myob) #my object is a free man
|
||||
deLinkOb('Ipo',myob) #kids, it's not nice to share. you've been lied to
|
||||
if ob.getType() != ARMATURE: # baking armatures is based on bones, not object
|
||||
myipo = createIpo(myob) #create own IPO and curves for the clone object
|
||||
ipos = bakeFrames(ob,myipo) #bake the locrot for this obj for the scene frames
|
||||
return myob
|
||||
|
||||
########################################
|
||||
def bake(ob,par): #bakes an object of any type, linking it to parent
|
||||
debug(0,'Baking %s object %s' % (ob.getType(), ob))
|
||||
clone = bakeObject(ob) #creates and bakes the object motion
|
||||
if par!= None:
|
||||
par.makeParent([clone])
|
||||
debug(20,"assigned object to parent %s" % par)
|
||||
if ob.getType() == ARMATURE:
|
||||
## error('Object baked. Continue with bones?')
|
||||
bakeBones(ob,clone) #go into the bones and copy from -> to in frame range
|
||||
#future idea: bakeMesh (net result of Shapekeys, Softbody, Cloth, Fluidsim,...)
|
||||
return clone
|
||||
|
||||
########################################
|
||||
def tstCreateArm(): #create a test armature in scene
|
||||
# rip-off from http://www.blender.org/documentation/245PythonDoc/Pose-module.html - thank you!
|
||||
|
||||
debug(0,'Making Test Armature')
|
||||
# New Armature
|
||||
arm_data= Armature.New('myArmature')
|
||||
print arm_data
|
||||
arm_ob = scn.objects.new(arm_data)
|
||||
arm_data.makeEditable()
|
||||
|
||||
# Add 4 bones
|
||||
ebones = [Armature.Editbone(), Armature.Editbone(), Armature.Editbone(), Armature.Editbone()]
|
||||
|
||||
# Name the editbones
|
||||
ebones[0].name = 'Bone.001'
|
||||
ebones[1].name = 'Bone.002'
|
||||
ebones[2].name = 'Bone.003'
|
||||
ebones[3].name = 'Bone.004'
|
||||
|
||||
# Assign the editbones to the armature
|
||||
for eb in ebones:
|
||||
arm_data.bones[eb.name]= eb
|
||||
|
||||
# Set the locations of the bones
|
||||
ebones[0].head= Mathutils.Vector(0,0,0)
|
||||
ebones[0].tail= Mathutils.Vector(0,0,1) #tip
|
||||
ebones[1].head= Mathutils.Vector(0,0,1)
|
||||
ebones[1].tail= Mathutils.Vector(0,0,2)
|
||||
ebones[2].head= Mathutils.Vector(0,0,2)
|
||||
ebones[2].tail= Mathutils.Vector(0,0,3)
|
||||
ebones[3].head= Mathutils.Vector(0,0,3)
|
||||
ebones[3].tail= Mathutils.Vector(0,0,4)
|
||||
|
||||
ebones[1].parent= ebones[0]
|
||||
ebones[2].parent= ebones[1]
|
||||
ebones[3].parent= ebones[2]
|
||||
|
||||
arm_data.update()
|
||||
# Done with editing the armature
|
||||
|
||||
# Assign the pose animation
|
||||
arm_pose = arm_ob.getPose()
|
||||
|
||||
act = arm_ob.getAction()
|
||||
if not act: # Add a pose action if we dont have one
|
||||
act = Armature.NLA.NewAction()
|
||||
act.setActive(arm_ob)
|
||||
|
||||
xbones=arm_ob.data.bones.values()
|
||||
pbones = arm_pose.bones.values()
|
||||
|
||||
frame = 1
|
||||
for pbone in pbones: # set bones to no rotation
|
||||
pbone.quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
|
||||
|
||||
# Set a different rotation at frame 25
|
||||
pbones[0].quat[:] = 1.000,0.1000,0.2000,0.20000
|
||||
pbones[1].quat[:] = 1.000,0.6000,0.5000,0.40000
|
||||
pbones[2].quat[:] = 1.000,0.1000,0.3000,0.40000
|
||||
pbones[3].quat[:] = 1.000,-0.2000,-0.3000,0.30000
|
||||
|
||||
frame = 25
|
||||
for i in xrange(4):
|
||||
pbones[i].insertKey(arm_ob, frame, Object.Pose.ROT)
|
||||
|
||||
pbones[0].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbones[1].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbones[2].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbones[3].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
|
||||
frame = 50
|
||||
for pbone in pbones: # set bones to no rotation
|
||||
pbone.quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
|
||||
|
||||
return arm_ob
|
||||
|
||||
########################################
|
||||
def tstMoveOb(ob): # makes a simple LocRot animation of object in the scene
|
||||
anim = [
|
||||
#Loc Rot/10
|
||||
#
|
||||
( 0,0,0, 0, 0, 0), #frame 1 origin
|
||||
( 1,0,0, 0, 0, 0), #frame 2
|
||||
( 1,1,0, 0, 0, 0),
|
||||
( 1,1,1, 0, 0, 0),
|
||||
( 1,1,1,4.5, 0, 0),
|
||||
( 1,1,1,4.5,4.5, 0),
|
||||
( 1,1,1,4.5,4.5,4.5)
|
||||
]
|
||||
space = COORD_LOCAL
|
||||
ipo = createIpo(ob) #create an Ipo and curves for this object
|
||||
ipos = getCurves(ipo)
|
||||
|
||||
# span this motion over the currently set anim range
|
||||
# to set points, i need time but do not know how it is computed, so will have to advance the animation
|
||||
staframe,endframe,curframe = getRenderInfo()
|
||||
|
||||
frame = staframe #x position of new ipo datapoint. set to staframe if you want a match
|
||||
frameDelta=(endframe-staframe)/(len(anim)) #accomplish the animation in frame range
|
||||
for key in anim: #effectively does a getLocRot()
|
||||
#tell Blender to advace to frame
|
||||
Blender.Set('curframe',frame) # computes the constrained location of the 'real' objects
|
||||
time = Blender.Get('curtime')
|
||||
|
||||
ipos = addPoint(time,key,ipos) #add this data at this time to the ipos
|
||||
|
||||
debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (ipo.name, frame, time, key[0], key[1], key[2], key[3], key[4], key[5]))
|
||||
frame += frameDelta
|
||||
Blender.Set(CURFRAME,curframe) # reset back to where we started
|
||||
return
|
||||
#=================
|
||||
# Program Template
|
||||
#=================
|
||||
########################################
|
||||
def main():
|
||||
# return code set via rt button in Blender Buttons Scene Context Anim panel
|
||||
if MODE == 1: #create test armature #1
|
||||
ob = tstCreateArm() # make test arm and select it
|
||||
tstMoveOb(ob)
|
||||
scn.objects.selected = [ob]
|
||||
|
||||
obs= Blender.Object.GetSelected() #scn.objects.selected
|
||||
obs= sortObjects(obs)
|
||||
debug(0,'Baking %i objects' % len(obs))
|
||||
|
||||
if len(obs) >= 1: # user might have multiple objects selected
|
||||
i= 0
|
||||
clones=[] # my clone army
|
||||
for ob in obs:
|
||||
par= ob.getParent()
|
||||
if not usrParent:
|
||||
if par in obs:
|
||||
par= clones[obs.index(par)]
|
||||
clones.append(bake(ob,par))
|
||||
scn.objects.selected = clones
|
||||
else:
|
||||
error('Please select at least one object')
|
||||
return
|
||||
|
||||
########################################
|
||||
def benchmark(): # This lets you benchmark (time) the script's running duration
|
||||
Window.WaitCursor(1)
|
||||
t = sys.time()
|
||||
debug(60,'%s began at %.0f' %(__script__,sys.time()))
|
||||
|
||||
# Run the function on the active scene
|
||||
in_editmode = Window.EditMode()
|
||||
if in_editmode: Window.EditMode(0)
|
||||
|
||||
main()
|
||||
|
||||
if in_editmode: Window.EditMode(1)
|
||||
|
||||
# Timing the script is a good way to be aware on any speed hits when scripting
|
||||
debug(0,'%s Script finished in %.2f seconds' % (__script__,sys.time()-t) )
|
||||
Window.WaitCursor(0)
|
||||
return
|
||||
|
||||
########################################
|
||||
# This lets you can import the script without running it
|
||||
if __name__ == '__main__':
|
||||
debug(0, "------------------------------------")
|
||||
debug(0, "%s %s Script begins with mode=%i debug=%i batch=%s" % (__script__,__version__,MODE,DEBUG,BATCH))
|
||||
benchmark()
|
||||
@@ -1,192 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Clean Animation Curves'
|
||||
Blender: 249
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Remove unused keyframes for ipo curves'
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2008-2009: Blender Foundation
|
||||
#
|
||||
# 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,
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import bpy
|
||||
from Blender import IpoCurve, Draw, Window
|
||||
|
||||
def clean_ipos(ipos):
|
||||
eul = 0.001
|
||||
|
||||
def isflat(vec):
|
||||
prev_y = vec[0][1]
|
||||
mid_y = vec[1][1]
|
||||
next_y = vec[2][1]
|
||||
|
||||
# flat status for prev and next
|
||||
return abs(mid_y-prev_y) < eul, abs(mid_y-next_y) < eul
|
||||
|
||||
|
||||
|
||||
X=0
|
||||
Y=1
|
||||
PREV=0
|
||||
MID=1
|
||||
NEXT=2
|
||||
|
||||
LEFT = 0
|
||||
RIGHT = 1
|
||||
|
||||
TOT = 0
|
||||
TOTBEZ = 0
|
||||
# for ipo in bpy.data.ipos:
|
||||
for ipo in ipos:
|
||||
if ipo.lib:
|
||||
continue
|
||||
# print ipo
|
||||
for icu in ipo:
|
||||
interp = icu.interpolation
|
||||
extend = icu.extend
|
||||
|
||||
bezierPoints = icu.bezierPoints
|
||||
bezierVecs = [bez.vec for bez in bezierPoints]
|
||||
|
||||
l = len(bezierPoints)
|
||||
|
||||
TOTBEZ += l
|
||||
|
||||
# our aim is to simplify this ipo as much as possible!
|
||||
if interp == IpoCurve.InterpTypes.BEZIER or interp == interp == IpoCurve.InterpTypes.LINEAR:
|
||||
#print "Not yet supported"
|
||||
|
||||
if interp == IpoCurve.InterpTypes.BEZIER:
|
||||
flats = [isflat(bez) for bez in bezierVecs]
|
||||
else:
|
||||
# A bit of a waste but fake the locations for these so they will always be flats
|
||||
# IS better then too much duplicate code.
|
||||
flats = [(True, True)] * l
|
||||
for v in bezierVecs:
|
||||
v[PREV][Y] = v[NEXT][Y] = v[MID][Y]
|
||||
|
||||
|
||||
# remove middle points
|
||||
if l>2:
|
||||
done_nothing = False
|
||||
|
||||
while not done_nothing and len(bezierVecs) > 2:
|
||||
done_nothing = True
|
||||
i = l-2
|
||||
|
||||
while i > 0:
|
||||
#print i
|
||||
#print i, len(bezierVecs)
|
||||
if flats[i]==(True,True) and flats[i-1][RIGHT] and flats[i+1][LEFT]:
|
||||
|
||||
if abs(bezierVecs[i][MID][Y] - bezierVecs[i-1][MID][Y]) < eul and abs(bezierVecs[i][MID][Y] - bezierVecs[i+1][MID][Y]) < eul:
|
||||
done_nothing = False
|
||||
|
||||
del flats[i]
|
||||
del bezierVecs[i]
|
||||
icu.delBezier(i)
|
||||
TOT += 1
|
||||
l-=1
|
||||
i-=1
|
||||
|
||||
# remove endpoints
|
||||
if extend == IpoCurve.ExtendTypes.CONST and len(bezierVecs) > 1:
|
||||
#print l, len(bezierVecs)
|
||||
# start
|
||||
|
||||
while l > 2 and (flats[0][RIGHT] and flats[1][LEFT] and (abs(bezierVecs[0][MID][Y] - bezierVecs[1][MID][Y]) < eul)):
|
||||
print "\tremoving 1 point from start of the curve"
|
||||
del flats[0]
|
||||
del bezierVecs[0]
|
||||
icu.delBezier(0)
|
||||
TOT += 1
|
||||
l-=1
|
||||
|
||||
|
||||
# End
|
||||
while l > 2 and flats[-2][RIGHT] and flats[-1][LEFT] and (abs(bezierVecs[-2][MID][Y] - bezierVecs[-1][MID][Y]) < eul):
|
||||
print "\tremoving 1 point from end of the curve", l
|
||||
del flats[l-1]
|
||||
del bezierVecs[l-1]
|
||||
icu.delBezier(l-1)
|
||||
TOT += 1
|
||||
l-=1
|
||||
|
||||
|
||||
|
||||
if l==2:
|
||||
if isflat( bezierVecs[0] )[RIGHT] and isflat( bezierVecs[1] )[LEFT] and abs(bezierVecs[0][MID][Y] - bezierVecs[1][MID][Y]) < eul:
|
||||
# remove the second point
|
||||
print "\tremoving 1 point from 2 point bez curve"
|
||||
# remove the second point
|
||||
del flats[1]
|
||||
del bezierVecs[1]
|
||||
icu.delBezier(1)
|
||||
TOT+=1
|
||||
l-=1
|
||||
|
||||
# Change to linear for faster evaluation
|
||||
'''
|
||||
if l==1:
|
||||
print 'Linear'
|
||||
icu.interpolation = IpoCurve.InterpTypes.LINEAR
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
||||
if interp== IpoCurve.InterpTypes.CONST:
|
||||
print "Not yet supported"
|
||||
|
||||
print 'total', TOT, TOTBEZ
|
||||
return TOT, TOTBEZ
|
||||
|
||||
def main():
|
||||
ret = Draw.PupMenu('Clean Selected Objects Ipos%t|Object IPO%x1|Object Action%x2|%l|All IPOs (be careful!)%x3')
|
||||
|
||||
sce = bpy.data.scenes.active
|
||||
ipos = []
|
||||
|
||||
if ret == 3:
|
||||
ipos.extend(list(bpy.data.ipos))
|
||||
else:
|
||||
for ob in sce.objects.context:
|
||||
if ret == 1:
|
||||
ipo = ob.ipo
|
||||
if ipo:
|
||||
ipos.append(ipo)
|
||||
|
||||
elif ret == 2:
|
||||
action = ob.action
|
||||
if action:
|
||||
ipos.extend([ipo for ipo in action.getAllChannelIpos().values() if ipo])
|
||||
|
||||
|
||||
|
||||
if not ipos:
|
||||
Draw.PupMenu('Error%t|No ipos found')
|
||||
else:
|
||||
total_removed, total = clean_ipos(ipos)
|
||||
Draw.PupMenu('Done!%t|Removed ' + str(total_removed) + ' of ' + str(total) + ' points')
|
||||
|
||||
Window.RedrawAll()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,575 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus: <- these words are ignored
|
||||
Name: 'Trajectory'
|
||||
Blender: 243
|
||||
Group: 'Animation'
|
||||
Tip: 'See Trajectory of selected object'
|
||||
"""
|
||||
|
||||
__author__ = '3R - R3gis'
|
||||
__version__ = '2.43'
|
||||
__url__ = ["Script's site , http://blenderfrance.free.fr/python/Trajectory_en.htm","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__ = """
|
||||
|
||||
Usage:
|
||||
|
||||
* Launch with alt+P (or put it in .script folder)
|
||||
|
||||
Allow to see in real time trajectory of selected object.
|
||||
|
||||
On first run, it ask you
|
||||
- If you want that actually selected object have they trajectory always shown
|
||||
- If you want to use Space Handler or a Scriptlink in Redraw mode
|
||||
- Future and Past : it is the frame in past and future
|
||||
of the beggining and the end of the path
|
||||
- Width of line that represent the trajectory
|
||||
|
||||
Then the object's trajectory will be shown in all 3D areas.
|
||||
When trajectory is red, you can modifiy it by moving object.
|
||||
When trajectory is blue and you want to be able to modify it, inser a Key (I-Key)
|
||||
|
||||
Points appears on trajectory :
|
||||
- Left Clic to modify position
|
||||
- Right Clic to go to the frame it represents
|
||||
|
||||
Notes:<br>
|
||||
In scriptlink mode, it create one script link so make sure that 'Enable Script Link' toogle is on
|
||||
In SpaceHandler mode, you have to go in View>>SpaceHandlerScript menu to activate Trajectory
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004-2006: Regis Montoya
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
#################################
|
||||
# by 3R - 26/08/05
|
||||
# for any problem :
|
||||
# r3gis@free.fr
|
||||
# ou sur le newsgroup:
|
||||
# http://zoo-logique.org/3D.Blender/
|
||||
#################################
|
||||
#Many thanks to cambo for his fixes
|
||||
#################################
|
||||
|
||||
|
||||
|
||||
import Blender
|
||||
|
||||
|
||||
scene= Blender.Scene.GetCurrent()
|
||||
|
||||
|
||||
#Writing
|
||||
def write_script(name, script):
|
||||
global scene
|
||||
#List texts and their name
|
||||
#write : type of writing : 1->New, 2->Overwrite
|
||||
scripting= None
|
||||
for text in Blender.Text.Get():
|
||||
if text.name==name and text.asLines()[1] != "#"+str(__version__):
|
||||
scripting = text
|
||||
scripting.clear()
|
||||
scripting.write(script)
|
||||
break
|
||||
|
||||
if not scripting:
|
||||
scripting= Blender.Text.New(name)
|
||||
scripting.write(script)
|
||||
|
||||
def link_script(name, type):
|
||||
global scene
|
||||
scriptlinks = scene.getScriptLinks(type) # none or list
|
||||
if not scriptlinks or name not in scriptlinks:
|
||||
scene.addScriptLink(name, type)
|
||||
|
||||
|
||||
#Deleting of a text
|
||||
def text_remove(name):
|
||||
global scene
|
||||
#try to delete text if already linked
|
||||
try:
|
||||
text= Blender.Text.Get(name)
|
||||
# Texte.clear()
|
||||
scene.clearScriptLinks([name])
|
||||
Blender.Text.unlink(text)
|
||||
except:
|
||||
print('---Initialisation of Trajectory_'+str(__version__)+'.py---')
|
||||
|
||||
#Whether is already running, also check if it's the last version of the script : second line contain the version fo the script
|
||||
ask_modif= 0 # Default
|
||||
for text in Blender.Text.Get():
|
||||
if text.name == 'Trajectory' and text.asLines()[1] == "#"+str(__version__):
|
||||
#We ask if script modify his seetings, keep it or stop script
|
||||
ask_modif= Blender.Draw.PupMenu("Script already launch %t|Modify settings%x0|Keep settings%x1|Stop script%x2|")
|
||||
if ask_modif==-1: # user canceled.
|
||||
ask_modif= 1
|
||||
break
|
||||
|
||||
selection_mode= 0
|
||||
future= 35
|
||||
past= 20
|
||||
width= 2
|
||||
|
||||
#In modify case
|
||||
if ask_modif==0:
|
||||
handle_mode= Blender.Draw.Create(0)
|
||||
selection_mode= Blender.Draw.Create(0)
|
||||
future= Blender.Draw.Create(35)
|
||||
past= Blender.Draw.Create(20)
|
||||
width= Blender.Draw.Create(2)
|
||||
|
||||
block= []
|
||||
block.append(("Space Handlers", handle_mode, "You have to activate for each area by View>>SpaceHandler")) #You can delete this option...
|
||||
block.append(("Always Draw", selection_mode, "Selected object will have their trajectory always shown"))
|
||||
block.append(("Past :", past, 1, 900))
|
||||
block.append(("Futur:", future, 1, 900))
|
||||
block.append(("Width:", width, 1,5))
|
||||
|
||||
if not Blender.Draw.PupBlock("Trajectory seetings", block):
|
||||
ask_modif=1
|
||||
|
||||
handle_mode= handle_mode.val
|
||||
selection_mode= selection_mode.val
|
||||
future= future.val
|
||||
past= past.val
|
||||
width= width.val
|
||||
|
||||
|
||||
#put names of selected objects in objects_select if option choosen by user
|
||||
if selection_mode==1:
|
||||
objects_select= [ob.name for ob in scene.objects.context]
|
||||
else:
|
||||
objects_select= []
|
||||
|
||||
|
||||
try:
|
||||
if handle_mode==1:
|
||||
DrawPart="#SPACEHANDLER.VIEW3D.DRAW\n"
|
||||
else:
|
||||
DrawPart="#!BPY\n"
|
||||
except:DrawPart="#BadlyMade"
|
||||
|
||||
|
||||
#Here is the script to write in Blender and to link, options are also written now
|
||||
DrawPart=DrawPart+"#"+str(__version__)+"""
|
||||
#This script is a part of Trajectory.py and have to be linked to the scene in Redraw if not in HANDLER mode.
|
||||
#Author : 3R - Regis Montoya
|
||||
#It's better to use the Trajectory_"version_number".py
|
||||
#You can modify the two following value to change the path settings
|
||||
future="""+str(future)+"""
|
||||
past="""+str(past)+"""
|
||||
object_init_names="""+str(objects_select)+"""
|
||||
|
||||
|
||||
import Blender, math
|
||||
from Blender import BGL, Draw, Ipo
|
||||
from Blender.BGL import *
|
||||
from Blender.Draw import *
|
||||
from math import *
|
||||
|
||||
from Blender.Mathutils import Vector
|
||||
|
||||
#take actual frame
|
||||
frameC=Blender.Get('curframe')
|
||||
scene = Blender.Scene.GetCurrent()
|
||||
render_context=scene.getRenderingContext()
|
||||
#ajust number of frames with NewMap and OldMapvalue values
|
||||
k=1.00*render_context.oldMapValue()/render_context.newMapValue()
|
||||
if k<1:
|
||||
tr=-1*int(log(k*0.1, 10))
|
||||
else:
|
||||
tr=-1*int(log(k, 10))
|
||||
#The real and integer frame to compare to ipos keys frames
|
||||
frameCtr=round(frameC*k, tr)
|
||||
frameCr=frameC*k
|
||||
frameC=int(round(frameC*k, 0))
|
||||
|
||||
|
||||
#List objects that we have to show trajectory in $objects
|
||||
# In this case, using a dict for unique objects is the fastest way.
|
||||
object_dict= dict([(ob.name, ob) for ob in scene.objects.context])
|
||||
for obname in object_init_names:
|
||||
if not object_dict.has_key(obname):
|
||||
try: # Object may be removed.
|
||||
object_dict[obname]= Blender.Object.Get(obname)
|
||||
except:
|
||||
pass # object was removed.
|
||||
|
||||
#This fonction give the resulting matrix of all parents at a given frame
|
||||
#parent_list is the list of all parents [object, matrix, locX_ipo, locY, Z, rotX, Y, Z, sizeX, Y, Z] of current object
|
||||
def matrixForTraj(frame, parent_list):
|
||||
DecMatC=Blender.Mathutils.Matrix([1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1])
|
||||
|
||||
for parent_data in parent_list:
|
||||
parent_ob= parent_data[0]
|
||||
|
||||
try: X= parent_data[5][frame]*pi/18
|
||||
except: X= parent_ob.RotX
|
||||
try: Y= parent_data[6][frame]*pi/18
|
||||
except: Y= parent_ob.RotY
|
||||
try: Z= parent_data[7][frame]*pi/18
|
||||
except: Z= parent_ob.RotZ
|
||||
try: LX= parent_data[2][frame]
|
||||
except: LX= parent_ob.LocX
|
||||
try: LY= parent_data[3][frame]
|
||||
except: LY= parent_ob.LocY
|
||||
try: LZ= parent_data[4][frame]
|
||||
except: LZ= parent_ob.LocZ
|
||||
try: SX= parent_data[8][frame]
|
||||
except: SX= parent_ob.SizeX
|
||||
try: SY= parent_data[9][frame]
|
||||
except: SY= parent_ob.SizeY
|
||||
try: SZ= parent_data[10][frame]
|
||||
except: SZ= parent_ob.SizeZ
|
||||
|
||||
NMat=Blender.Mathutils.Matrix([cos(Y)*cos(Z)*SX,SX*cos(Y)*sin(Z),-SX*sin(Y),0],
|
||||
[(-cos(X)*sin(Z)+sin(Y)*sin(X)*cos(Z))*SY,(sin(X)*sin(Y)*sin(Z)+cos(X)*cos(Z))*SY,sin(X)*cos(Y)*SY,0],
|
||||
[(cos(X)*sin(Y)*cos(Z)+sin(X)*sin(Z))*SZ,(cos(X)*sin(Y)*sin(Z)-sin(X)*cos(Z))*SZ,SZ*cos(X)*cos(Y),0],
|
||||
[LX,LY,LZ,1])
|
||||
DecMatC=DecMatC*parent_data[1]*NMat
|
||||
return DecMatC
|
||||
|
||||
#####
|
||||
TestLIST=[]
|
||||
matview=Blender.Window.GetPerspMatrix()
|
||||
###########
|
||||
#Fonction to draw trajectories
|
||||
###########
|
||||
|
||||
def Trace_Traj(ob):
|
||||
global TestLIST, matview
|
||||
#we draw trajectories for all objects in list
|
||||
|
||||
LocX=[]
|
||||
LocY=[]
|
||||
LocZ=[]
|
||||
#List with trajectories' vertexs
|
||||
vertexX=[]
|
||||
|
||||
contextIpo= ob.ipo
|
||||
if contextIpo:
|
||||
ipoLocX=contextIpo[Ipo.OB_LOCX]
|
||||
ipoLocY=contextIpo[Ipo.OB_LOCY]
|
||||
ipoLocZ=contextIpo[Ipo.OB_LOCZ]
|
||||
ipoTime=contextIpo[Ipo.OB_TIME]
|
||||
else: # only do if there is no IPO (if no ipo curves : return None object and don't go in this except)
|
||||
ipoLocX= ipoLocY= ipoLocZ= ipoTime= None
|
||||
|
||||
if ipoTime:
|
||||
return 0
|
||||
|
||||
#Get all parents of ob
|
||||
parent=ob.parent
|
||||
backup_ob= ob
|
||||
child= ob
|
||||
parent_list= []
|
||||
|
||||
#Get parents's infos :
|
||||
#list of [name, initial matrix at make parent, ipo in X,Y,Z,rotX,rotY,rotZ,sizeX,Y,Z]
|
||||
while parent:
|
||||
Init_Mat=Blender.Mathutils.Matrix(child.getMatrix('worldspace')) #must be done like it (it isn't a matrix otherwise)
|
||||
Init_Mat.invert()
|
||||
Init_Mat=Init_Mat*child.getMatrix('localspace')
|
||||
Init_Mat=parent.getMatrix()*Init_Mat
|
||||
Init_Mat.invert()
|
||||
|
||||
contextIpo= parent.ipo # None or IPO
|
||||
if contextIpo:
|
||||
ipo_Parent_LocX=contextIpo[Ipo.OB_LOCX]
|
||||
ipo_Parent_LocY=contextIpo[Ipo.OB_LOCY]
|
||||
ipo_Parent_LocZ=contextIpo[Ipo.OB_LOCZ]
|
||||
ipo_Parent_RotX=contextIpo[Ipo.OB_ROTX]
|
||||
ipo_Parent_RotY=contextIpo[Ipo.OB_ROTY]
|
||||
ipo_Parent_RotZ=contextIpo[Ipo.OB_ROTZ]
|
||||
ipo_Parent_SizeX=contextIpo[Ipo.OB_SIZEX]
|
||||
ipo_Parent_SizeY=contextIpo[Ipo.OB_SIZEY]
|
||||
ipo_Parent_SizeZ=contextIpo[Ipo.OB_SIZEZ]
|
||||
else:
|
||||
ipo_Parent_LocX=ipo_Parent_LocY=ipo_Parent_LocZ=\
|
||||
ipo_Parent_RotX=ipo_Parent_RotY=ipo_Parent_RotZ=\
|
||||
ipo_Parent_SizeX=ipo_Parent_SizeY=ipo_Parent_SizeZ= None
|
||||
|
||||
parent_list.append([parent, Init_Mat, ipo_Parent_LocX, ipo_Parent_LocY, ipo_Parent_LocZ, ipo_Parent_RotX, ipo_Parent_RotY, ipo_Parent_RotZ, ipo_Parent_SizeX, ipo_Parent_SizeY, ipo_Parent_SizeZ])
|
||||
|
||||
child=parent
|
||||
parent=parent.parent
|
||||
|
||||
#security : if one of parents object are a path>>follow : trajectory don't work properly so it have to draw nothing
|
||||
for parent in parent_list:
|
||||
if parent[0].type == 'Curve':
|
||||
if parent[0].data.flag & 1<<4: # Follow path, 4th bit
|
||||
return 1
|
||||
|
||||
#ob >> re-assign obj and not parent
|
||||
ob= backup_ob
|
||||
ob= backup_ob
|
||||
|
||||
|
||||
if ipoLocX: LXC= ipoLocX[frameC]
|
||||
else: LXC= ob.LocX
|
||||
if ipoLocY: LYC= ipoLocY[frameC]
|
||||
else: LYC= ob.LocY
|
||||
if ipoLocZ: LZC= ipoLocZ[frameC]
|
||||
else: LZC= ob.LocZ
|
||||
|
||||
vect= Vector([ob.LocX, ob.LocY, ob.LocZ, 1])
|
||||
color=[0, 1]
|
||||
|
||||
#If trajectory is being modified and we are at a frame where a ipo key already exist
|
||||
if round(ob.LocX, 5)!=round(LXC, 5):
|
||||
for bez in ipoLocX.bezierPoints:
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
bez.pt = [frameCr, vect[0]]
|
||||
ipoLocX.recalc()
|
||||
if round(ob.LocY, 5)!=round(LYC, 5):
|
||||
for bez in ipoLocY.bezierPoints:
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
bez.pt = [frameCr, vect[1]]
|
||||
ipoLocY.recalc()
|
||||
if round(ob.LocZ, 5)!=round(LZC, 5):
|
||||
for bez in ipoLocZ.bezierPoints:
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
bez.pt = [frameCr, vect[2]]
|
||||
ipoLocZ.recalc()
|
||||
|
||||
#change trajectory color if at an ipoKey
|
||||
VertexFrame=[]
|
||||
bezier_Coord=0
|
||||
if ipoLocX: # FIXED like others it was just in case ipoLocX==None
|
||||
for bez in ipoLocX.bezierPoints:
|
||||
bezier_Coord=round(bez.pt[0], tr)
|
||||
if bezier_Coord not in VertexFrame:
|
||||
VertexFrame.append(bezier_Coord)
|
||||
if bezier_Coord==frameCtr:
|
||||
color=[1, color[1]-0.3]
|
||||
if ipoLocY: # FIXED
|
||||
for bez in ipoLocY.bezierPoints:
|
||||
bezier_Coord=round(bez.pt[0], tr)
|
||||
if bezier_Coord not in VertexFrame:
|
||||
VertexFrame.append(bezier_Coord)
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
color=[1, color[1]-0.3]
|
||||
if ipoLocZ: # FIXED
|
||||
for bez in ipoLocZ.bezierPoints:
|
||||
bezier_Coord=round(bez.pt[0], tr)
|
||||
if bezier_Coord not in VertexFrame:
|
||||
VertexFrame.append(bezier_Coord)
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
color=[1, color[1]-0.3]
|
||||
|
||||
|
||||
#put in LocX, LocY and LocZ all points of trajectory
|
||||
for frame in xrange(frameC-past, frameC+future):
|
||||
DecMat=matrixForTraj(frame, parent_list)
|
||||
|
||||
if ipoLocX: LX= ipoLocX[frame]
|
||||
else: LX= ob.LocX
|
||||
if ipoLocY: LY= ipoLocY[frame]
|
||||
else: LY= ob.LocY
|
||||
if ipoLocZ: LZ= ipoLocZ[frame]
|
||||
else: LZ= ob.LocZ
|
||||
|
||||
vect=Vector(LX, LY, LZ)*DecMat
|
||||
LocX.append(vect[0])
|
||||
LocY.append(vect[1])
|
||||
LocZ.append(vect[2])
|
||||
|
||||
|
||||
#draw part : get current view
|
||||
MatPreBuff= [matview[i][j] for i in xrange(4) for j in xrange(4)]
|
||||
|
||||
MatBuff=BGL.Buffer(GL_FLOAT, 16, MatPreBuff)
|
||||
|
||||
glLoadIdentity()
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glPushMatrix()
|
||||
glLoadMatrixf(MatBuff)
|
||||
|
||||
#draw trajectory line
|
||||
glLineWidth("""+str(width)+""")
|
||||
|
||||
glBegin(GL_LINE_STRIP)
|
||||
for i in xrange(len(LocX)):
|
||||
glColor3f((i+1)*1.00/len(LocX)*color[0], 0, (i+1)*1.00/len(LocX)*color[1])
|
||||
glVertex3f(LocX[i], LocY[i], LocZ[i])
|
||||
|
||||
glEnd()
|
||||
|
||||
#draw trajectory's "vertexs"
|
||||
if not Blender.Window.EditMode():
|
||||
glPointSize(5)
|
||||
glBegin(GL_POINTS)
|
||||
TestPOINTS=[]
|
||||
TestFRAME=[]
|
||||
i=0
|
||||
for frame in VertexFrame:
|
||||
ix=int(frame)-frameC+past
|
||||
if ix>=0 and ix<len(LocX):
|
||||
glColor3f(1, 0.7, 0.2)
|
||||
glVertex3f(LocX[ix], LocY[ix], LocZ[ix])
|
||||
TestPOINTS.append(Vector([LocX[ix], LocY[ix], LocZ[ix], 1]))
|
||||
TestFRAME.append(int(frame))
|
||||
i+=1
|
||||
glEnd()
|
||||
#this list contains info about where to check if we click over a "vertex" in 3D view
|
||||
TestLIST.append((ob, TestPOINTS, TestFRAME))
|
||||
|
||||
glLineWidth(1)
|
||||
return 0
|
||||
|
||||
|
||||
for ob in object_dict.itervalues():
|
||||
Trace_Traj(ob)
|
||||
|
||||
###########
|
||||
#Fonction to handle trajectories
|
||||
###########
|
||||
|
||||
def Manip():
|
||||
#use TestLIST and matview defined by Trace_Traj
|
||||
global TestLIST, matview
|
||||
for screen in Blender.Window.GetScreenInfo(Blender.Window.Types.VIEW3D):
|
||||
if screen['id']==Blender.Window.GetAreaID():
|
||||
x0, y0, x1, y1= screen['vertices']
|
||||
break
|
||||
|
||||
#Projection of GL matrix in 3D view
|
||||
glPushMatrix()
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glPushMatrix()
|
||||
glLoadIdentity()
|
||||
#Global coordinates' matrix
|
||||
glOrtho(x0, x1, y0, y1, -1, 0)
|
||||
glMatrixMode(GL_MODELVIEW)
|
||||
glLoadIdentity()
|
||||
#Test mouse clics and other events
|
||||
|
||||
|
||||
if Blender.Window.QTest():
|
||||
evt, val= Blender.Window.QRead()
|
||||
if (evt==LEFTMOUSE or evt==RIGHTMOUSE) and not Blender.Window.EditMode():
|
||||
mouse_co=Blender.Window.GetMouseCoords()
|
||||
#if click on trajectory "vertexs"...
|
||||
for ob, TestPOINTS, TestFRAME in TestLIST: # ob is now used, line 552 to know what object it had to select
|
||||
for k, Vect in enumerate(TestPOINTS):
|
||||
proj=Vect*matview
|
||||
|
||||
pt=[(proj[0]/proj[3])*(x1-x0)/2+(x1+x0)/2, (proj[1]/proj[3])*(y1-y0)/2+(y1+y0)/2]
|
||||
|
||||
if mouse_co[0]<pt[0]+4 and mouse_co[0]>pt[0]-4 and mouse_co[1]>pt[1]-4 and mouse_co[1]<pt[1]+4:
|
||||
if evt==LEFTMOUSE:
|
||||
#remember current selected object
|
||||
object_names=[obj.name for obj in Blender.Object.GetSelected()]
|
||||
#this script allow to simulate a GKey, but I have to write a script
|
||||
#another way would made a infinit redraw or don't allow to move object
|
||||
#it auto unlink and delete itself
|
||||
script=\"\"\"
|
||||
import Blender
|
||||
from Blender import Draw, Window
|
||||
from Blender.Window import *
|
||||
from Blender.Draw import *
|
||||
|
||||
from Blender.Mathutils import Vector
|
||||
|
||||
# The following code is a bit of a hack, it allows clicking on the points and dragging directly
|
||||
#It simulate user press GKey
|
||||
#It also set the cursor position at center (because user have previously clic on area and moved the cursor):
|
||||
#And I can't get previous cursor position : redraw appear after it has been moved
|
||||
#If there is no better way you can remove this comments
|
||||
f= GetAreaID()
|
||||
SetCursorPos(0,0,0)
|
||||
#SetKeyQualifiers(1) #FIXED : the bug in older versions seems to have been fixed
|
||||
SetKeyQualifiers(0)
|
||||
QAdd(f, Blender.Draw.GKEY, 1, 0)
|
||||
QHandle(f)
|
||||
Blender.Redraw()
|
||||
done=0
|
||||
while not done:
|
||||
while Blender.Window.QTest():
|
||||
ev=Blender.Window.QRead()[0]
|
||||
if ev not in (4, 5, 18, 112, 213): #all event needed to move object
|
||||
#SetKeyQualifiers(1) #FIXED too, same reason that above
|
||||
#SetKeyQualifiers(0)
|
||||
SetKeyQualifiers(Blender.Window.GetKeyQualifiers())
|
||||
QAdd(f, ev, 1, 0)
|
||||
QHandle(f)
|
||||
Blender.Redraw()
|
||||
if ev in (RIGHTMOUSE, LEFTMOUSE, ESCKEY):
|
||||
done=1
|
||||
Blender.Set('curframe',\"\"\"+str(Blender.Get('curframe'))+\"\"\")
|
||||
Blender.Object.GetSelected()[0].sel= False
|
||||
for obname in \"\"\"+str(object_names)+\"\"\":
|
||||
ob=Blender.Object.Get(obname)
|
||||
ob.sel= True
|
||||
SetCursorPos(0,0,0)
|
||||
scripting=Blender.Text.Get('Edit_Trajectory')
|
||||
scripting.clear()
|
||||
Blender.Text.unlink(scripting)
|
||||
\"\"\"
|
||||
|
||||
#FIXED Edit_Trajectory was longer : all SetKeyQualifiers removed
|
||||
scene=Blender.Scene.GetCurrent()
|
||||
try:
|
||||
scripting=Blender.Text.Get('Edit_Trajectory')
|
||||
scripting.clear()
|
||||
except:
|
||||
scripting=Blender.Text.New('Edit_Trajectory')
|
||||
|
||||
scripting.write(script)
|
||||
#script= scripting #FIXED seems not needed anymore
|
||||
|
||||
#Go to frame that correspond to selected "vertex"
|
||||
Blender.Set('curframe', TestFRAME[k])
|
||||
|
||||
scene.objects.selected = [] #un select all objects
|
||||
|
||||
#FIXED TestLIST[j][0].sel=0, but no j. So ob.sel and above variable changed in obj
|
||||
ob.sel= True
|
||||
Blender.Run('Edit_Trajectory')
|
||||
|
||||
#work well now !!!
|
||||
if evt==RIGHTMOUSE :
|
||||
Blender.Set('curframe', TestFRAME[k])
|
||||
|
||||
Manip()
|
||||
#retrieve a normal matrix
|
||||
glPopMatrix()
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glPopMatrix()
|
||||
glMatrixMode(GL_MODELVIEW)
|
||||
"""
|
||||
|
||||
if ask_modif==0:
|
||||
text_remove('Trajectory')
|
||||
write_script('Trajectory', DrawPart)
|
||||
if handle_mode==1:
|
||||
Blender.UpdateMenus()
|
||||
else:
|
||||
link_script('Trajectory', 'Redraw')
|
||||
if ask_modif==2:
|
||||
text_remove('Trajectory')
|
||||
print("---End of Trajectory_"+str(__version__)+".py---\n--- Thanks for use ---")
|
||||
@@ -1,325 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Armature Symmetry'
|
||||
Blender: 242
|
||||
Group: 'Armature'
|
||||
Tooltip: 'Make an Armature symmetrical'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ("blender", "blenderartist")
|
||||
__version__ = "1.0 2006-7-26"
|
||||
|
||||
__doc__ = """\
|
||||
This script creates perfectly symmetrical armatures,
|
||||
based on the best fit when comparing the mirrored locations of 2 bones.
|
||||
Hidden bones are ignored, and optionally only operate on selected bones.
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) Campbell J Barton 2006
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
import bpy
|
||||
Vector= Blender.Mathutils.Vector
|
||||
|
||||
|
||||
def VecXFlip(vec):
|
||||
'''
|
||||
Return a copy of this vector x flipped.
|
||||
'''
|
||||
x,y,z= vec
|
||||
return Vector(-x,y,z)
|
||||
|
||||
def editbone_mirror_diff(editbone1, editbone2):
|
||||
'''
|
||||
X Mirror bone compare
|
||||
return a float representing the difference between the 2 bones
|
||||
the smaller the better the match
|
||||
'''
|
||||
h1= editbone1.head
|
||||
h2= editbone2.head
|
||||
|
||||
t1= editbone1.tail
|
||||
t2= editbone2.tail
|
||||
|
||||
# Mirror bone2's location
|
||||
h2= VecXFlip(h2)
|
||||
t2= VecXFlip(t2)
|
||||
|
||||
#return (h1-h2).length + (t1-t2).length # returns the length only
|
||||
|
||||
# For this function its easier to return the bones also
|
||||
return ((h1-h2).length + (t1-t2).length)/2, editbone1, editbone2
|
||||
|
||||
def editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L):
|
||||
'''
|
||||
Merge these 2 bones to their mirrored locations
|
||||
'''
|
||||
h1= editbone1.head
|
||||
h2= editbone2.head
|
||||
|
||||
t1= editbone1.tail
|
||||
t2= editbone2.tail
|
||||
|
||||
if PREF_MODE_L2R and PREF_MODE_R2L:
|
||||
# Median, flip bone2's locations and average, then apply to editbone1, flip and apply to editbone2
|
||||
h2_f= VecXFlip(h2)
|
||||
t2_f= VecXFlip(t2)
|
||||
|
||||
h_med= (h1+h2_f)*0.5 # middle between t1 and flipped t2
|
||||
t_med= (t1+t2_f)*0.5 # middle between h1 and flipped h2
|
||||
|
||||
# Apply the median to editbone1
|
||||
editbone1.head= h_med
|
||||
editbone1.tail= t_med
|
||||
|
||||
# Flip in place for editbone2
|
||||
h_med.x= -h_med.x
|
||||
t_med.x= -t_med.x
|
||||
|
||||
# Apply the median to editbone2
|
||||
editbone2.head= h_med
|
||||
editbone2.tail= t_med
|
||||
|
||||
# Average the roll, this might need some logical work, but looks good for now.
|
||||
r1= editbone1.roll
|
||||
r2= -editbone2.roll
|
||||
# print 'rolls are', r1,r2
|
||||
r_med= (r1+r2)/2
|
||||
# print 'new roll is', r_med
|
||||
editbone1.roll= r_med
|
||||
editbone2.roll= -r_med # mirror roll
|
||||
|
||||
else: # Copy from 1 side to another
|
||||
|
||||
# Crafty function we can use so L>R and R>L can use the same code
|
||||
def IS_XMIRROR_SOURCE(xval):
|
||||
'''Source means is this the value we want to copy from'''
|
||||
|
||||
if PREF_MODE_L2R:
|
||||
if xval<0: return True
|
||||
else: return False
|
||||
else: # PREF_MODE_R2L
|
||||
if xval<0: return False
|
||||
else: return True
|
||||
|
||||
if IS_XMIRROR_SOURCE( h1.x ):# head bone 1s negative, so copy it to h2
|
||||
editbone2.head= VecXFlip(h1)
|
||||
else:
|
||||
'''
|
||||
assume h2.x<0 - not a big deal if were wrong,
|
||||
its unlikely to ever happen because the bones would both be on the same side.
|
||||
'''
|
||||
|
||||
# head bone 2s negative, so copy it to h1
|
||||
editbone1.head= VecXFlip(h2)
|
||||
|
||||
# Same as above for tail
|
||||
if IS_XMIRROR_SOURCE(t1.x):
|
||||
editbone2.tail= VecXFlip(t1)
|
||||
else:
|
||||
editbone1.tail= VecXFlip(t2)
|
||||
|
||||
# Copy roll from 1 bone to another, use the head's location to decide which side it's on.
|
||||
if IS_XMIRROR_SOURCE(editbone1.head):
|
||||
editbone2.roll= -editbone1.roll
|
||||
else:
|
||||
editbone1.roll= -editbone2.roll
|
||||
|
||||
|
||||
def armature_symetry(\
|
||||
arm_ob,\
|
||||
PREF_MAX_DIST,\
|
||||
PREF_XMID_SNAP,\
|
||||
PREF_XZERO_THRESH,\
|
||||
PREF_MODE_L2R,\
|
||||
PREF_MODE_R2L,\
|
||||
PREF_SEL_ONLY):
|
||||
|
||||
'''
|
||||
Main function that does all the work,
|
||||
return the number of
|
||||
'''
|
||||
arm_data= arm_ob.data
|
||||
arm_data.makeEditable()
|
||||
|
||||
# Get the bones
|
||||
bones= []
|
||||
HIDDEN_EDIT= Blender.Armature.HIDDEN_EDIT
|
||||
BONE_SELECTED= Blender.Armature.BONE_SELECTED
|
||||
|
||||
if PREF_SEL_ONLY:
|
||||
for eb in arm_data.bones.values():
|
||||
options= eb.options
|
||||
if HIDDEN_EDIT not in options and BONE_SELECTED in options:
|
||||
bones.append(eb)
|
||||
else:
|
||||
# All non hidden bones
|
||||
for eb in arm_data.bones.values():
|
||||
options= eb.options
|
||||
if HIDDEN_EDIT not in options:
|
||||
bones.append(eb)
|
||||
|
||||
del HIDDEN_EDIT # remove temp variables
|
||||
del BONE_SELECTED
|
||||
|
||||
# Store the numder of bones we have modified for a message
|
||||
tot_editbones= len(bones)
|
||||
tot_editbones_modified= 0
|
||||
|
||||
if PREF_XMID_SNAP:
|
||||
# Remove bones that are in the middle (X Zero)
|
||||
# reverse loop so we can remove items in the list.
|
||||
for eb_idx in xrange(len(bones)-1, -1, -1):
|
||||
edit_bone= bones[eb_idx]
|
||||
if abs(edit_bone.head.x) + abs(edit_bone.tail.x) <= PREF_XZERO_THRESH/2:
|
||||
|
||||
# This is a center bone, clamp and remove from the bone list so we dont use again.
|
||||
if edit_bone.tail.x or edit_bone.head.x:
|
||||
tot_editbones_modified += 1
|
||||
|
||||
edit_bone.tail.x= edit_bone.head.x= 0
|
||||
del bones[eb_idx]
|
||||
|
||||
|
||||
|
||||
|
||||
bone_comparisons= []
|
||||
|
||||
# Compare every bone with every other bone, shouldn't be too slow.
|
||||
# These 2 "for" loops only compare once
|
||||
for eb_idx_a in xrange(len(bones)-1, -1, -1):
|
||||
edit_bone_a= bones[eb_idx_a]
|
||||
for eb_idx_b in xrange(eb_idx_a-1, -1, -1):
|
||||
edit_bone_b= bones[eb_idx_b]
|
||||
# Error float the first value from editbone_mirror_diff() so we can sort the resulting list.
|
||||
bone_comparisons.append(editbone_mirror_diff(edit_bone_a, edit_bone_b))
|
||||
|
||||
|
||||
bone_comparisons.sort() # best matches first
|
||||
|
||||
# Make a dict() of bone names that have been used so we dont mirror more then once
|
||||
bone_mirrored= {}
|
||||
|
||||
for error, editbone1, editbone2 in bone_comparisons:
|
||||
# print 'Trying to merge at error %.3f' % error
|
||||
if error > PREF_MAX_DIST:
|
||||
# print 'breaking, max error limit reached PREF_MAX_DIST: %.3f' % PREF_MAX_DIST
|
||||
break
|
||||
|
||||
if not bone_mirrored.has_key(editbone1.name) and not bone_mirrored.has_key(editbone2.name):
|
||||
# Were not used, execute the mirror
|
||||
editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L)
|
||||
# print 'Merging bones'
|
||||
|
||||
# Add ourselves so we aren't touched again
|
||||
bone_mirrored[editbone1.name] = None # dummy value, would use sets in python 2.4
|
||||
bone_mirrored[editbone2.name] = None
|
||||
|
||||
# If both options are enabled, then we have changed 2 bones
|
||||
tot_editbones_modified+= PREF_MODE_L2R + PREF_MODE_R2L
|
||||
|
||||
arm_data.update() # get out of armature editmode
|
||||
return tot_editbones, tot_editbones_modified
|
||||
|
||||
|
||||
def main():
|
||||
'''
|
||||
User interface function that gets the options and calls armature_symetry()
|
||||
'''
|
||||
|
||||
scn= bpy.data.scenes.active
|
||||
arm_ob= scn.objects.active
|
||||
|
||||
if not arm_ob or arm_ob.type!='Armature':
|
||||
Blender.Draw.PupMenu('No Armature object selected.')
|
||||
return
|
||||
|
||||
# Cant be in editmode for armature.makeEditable()
|
||||
is_editmode= Blender.Window.EditMode()
|
||||
if is_editmode: Blender.Window.EditMode(0)
|
||||
Draw= Blender.Draw
|
||||
|
||||
# Defaults for the user input
|
||||
PREF_XMID_SNAP= Draw.Create(1)
|
||||
PREF_MAX_DIST= Draw.Create(0.4)
|
||||
PREF_XZERO_THRESH= Draw.Create(0.02)
|
||||
|
||||
PREF_MODE_L2R= Draw.Create(1)
|
||||
PREF_MODE_R2L= Draw.Create(0)
|
||||
PREF_SEL_ONLY= Draw.Create(1)
|
||||
|
||||
pup_block = [\
|
||||
'Left (-), Right (+)',\
|
||||
('Left > Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc.'),\
|
||||
('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc.'),\
|
||||
'',\
|
||||
('MaxDist:', PREF_MAX_DIST, 0.0, 4.0, 'Maximum difference in mirror bones to match up pairs.'),\
|
||||
('XZero limit:', PREF_XZERO_THRESH, 0.0, 2.0, 'Tolerance for locking bones into the middle (X/zero).'),\
|
||||
('XMidSnap Bones', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\
|
||||
('Selected Only', PREF_SEL_ONLY, 'Only xmirror selected bones.'),\
|
||||
]
|
||||
|
||||
# Popup, exit if the user doesn't click OK
|
||||
if not Draw.PupBlock("X Mirror mesh tool", pup_block):
|
||||
return
|
||||
|
||||
# Replace the variables with their button values.
|
||||
PREF_XMID_SNAP= PREF_XMID_SNAP.val
|
||||
PREF_MAX_DIST= PREF_MAX_DIST.val
|
||||
PREF_MODE_L2R= PREF_MODE_L2R.val
|
||||
PREF_MODE_R2L= PREF_MODE_R2L.val
|
||||
PREF_XZERO_THRESH= PREF_XZERO_THRESH.val
|
||||
PREF_SEL_ONLY= PREF_SEL_ONLY.val
|
||||
|
||||
# If both are off assume mid-point and enable both
|
||||
if not PREF_MODE_R2L and not PREF_MODE_L2R:
|
||||
PREF_MODE_R2L= PREF_MODE_L2R= True
|
||||
|
||||
|
||||
tot_editbones, tot_editbones_modified = armature_symetry(\
|
||||
arm_ob,\
|
||||
PREF_MAX_DIST,\
|
||||
PREF_XMID_SNAP,\
|
||||
PREF_XZERO_THRESH,\
|
||||
PREF_MODE_L2R,\
|
||||
PREF_MODE_R2L,\
|
||||
PREF_SEL_ONLY)
|
||||
|
||||
if is_editmode: Blender.Window.EditMode(1)
|
||||
|
||||
# Redraw all views before popup
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
# Print results
|
||||
if PREF_SEL_ONLY:
|
||||
msg= 'moved %i bones of %i selected' % (tot_editbones_modified, tot_editbones)
|
||||
else:
|
||||
msg= 'moved %i bones of %i visible' % (tot_editbones_modified, tot_editbones)
|
||||
|
||||
|
||||
Blender.Draw.PupMenu(msg)
|
||||
|
||||
# Check for __main__ so this function can be imported by other scripts without running the script.
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
@@ -1,474 +0,0 @@
|
||||
#!BPY
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Registration info for Blender menus
|
||||
Name: 'Bevel Center'
|
||||
Blender: 243
|
||||
Group: 'Mesh'
|
||||
Tip: 'Bevel selected faces, edges, and vertices'
|
||||
"""
|
||||
|
||||
__author__ = "Loic BERTHE"
|
||||
__url__ = ("blender", "blenderartists.org")
|
||||
__version__ = "2.0"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script implements vertex and edges bevelling in Blender.
|
||||
|
||||
Usage:
|
||||
|
||||
Select the mesh you want to work on, enter Edit Mode and select the edges
|
||||
to bevel. Then run this script from the 3d View's Mesh->Scripts menu.
|
||||
|
||||
You can control the thickness of the bevel with the slider -- redefine the
|
||||
end points for bigger or smaller ranges. The thickness can be changed even
|
||||
after applying the bevel, as many times as needed.
|
||||
|
||||
For an extra smoothing after or instead of direct bevel, set the level of
|
||||
recursiveness and use the "Recursive" button.
|
||||
|
||||
This "Recursive" Button, won't work in face select mode, unless you choose
|
||||
"faces" in the select mode menu.
|
||||
|
||||
Notes:<br>
|
||||
You can undo and redo your steps just like with normal mesh operations in
|
||||
Blender.
|
||||
"""
|
||||
|
||||
######################################################################
|
||||
# Bevel Center v2.0 for Blender
|
||||
|
||||
# This script lets you bevel the selected vertices or edges and control the
|
||||
# thickness of the bevel
|
||||
|
||||
# (c) 2004-2006 Loïc Berthe (loic+blender@lilotux.net)
|
||||
# released under Blender Artistic License
|
||||
|
||||
######################################################################
|
||||
|
||||
import Blender
|
||||
from Blender import NMesh, Window, Scene
|
||||
from Blender.Draw import *
|
||||
from Blender.Mathutils import *
|
||||
from Blender.BGL import *
|
||||
import BPyMessages
|
||||
#PY23 NO SETS#
|
||||
'''
|
||||
try:
|
||||
set()
|
||||
except:
|
||||
from sets import set
|
||||
'''
|
||||
|
||||
######################################################################
|
||||
# Functions to handle the global structures of the script NF, NE and NC
|
||||
# which contain informations about faces and corners to be created
|
||||
|
||||
global E_selected
|
||||
E_selected = NMesh.EdgeFlags['SELECT']
|
||||
|
||||
old_dist = None
|
||||
|
||||
def act_mesh_ob():
|
||||
scn = Scene.GetCurrent()
|
||||
ob = scn.objects.active
|
||||
if ob == None or ob.type != 'Mesh':
|
||||
BPyMessages.Error_NoMeshActive()
|
||||
return
|
||||
|
||||
if ob.getData(mesh=1).multires:
|
||||
BPyMessages.Error_NoMeshMultiresEdit()
|
||||
return
|
||||
|
||||
return ob
|
||||
|
||||
def make_sel_vert(*co):
|
||||
v= NMesh.Vert(*co)
|
||||
v.sel = 1
|
||||
me.verts.append(v)
|
||||
return v
|
||||
|
||||
def make_sel_face(verts):
|
||||
f = NMesh.Face(verts)
|
||||
f.sel = 1
|
||||
me.addFace(f)
|
||||
|
||||
def add_to_NV(old,dir,new):
|
||||
try:
|
||||
NV[old][dir] = new
|
||||
except:
|
||||
NV[old] = {dir:new}
|
||||
|
||||
def get_v(old, *neighbors):
|
||||
# compute the direction of the new vert
|
||||
if len(neighbors) == 1: dir = (neighbors[0].co - old.co).normalize()
|
||||
#dir
|
||||
else: dir = (neighbors[0].co - old.co).normalize() + (neighbors[1].co-old.co).normalize()
|
||||
|
||||
# look in NV if this vert already exists
|
||||
key = tuple(dir)
|
||||
if old in NV and key in NV[old] : return NV[old][key]
|
||||
|
||||
# else, create it
|
||||
new = old.co + dist.val*dir
|
||||
v = make_sel_vert(new.x,new.y,new.z)
|
||||
add_to_NV(old,key,v)
|
||||
return v
|
||||
|
||||
def make_faces():
|
||||
""" Analyse the mesh, make the faces corresponding to selected faces and
|
||||
fill the structures NE and NC """
|
||||
|
||||
# make the differents flags consistent
|
||||
for e in me.edges:
|
||||
if e.flag & E_selected :
|
||||
e.v1.sel = 1
|
||||
e.v2.sel = 1
|
||||
|
||||
NF =[] # NF : New faces
|
||||
for f in me.faces:
|
||||
V = f.v
|
||||
nV = len(V)
|
||||
enumV = range(nV)
|
||||
E = [me.findEdge(V[i],V[(i+1) % nV]) for i in enumV]
|
||||
Esel = [x.flag & E_selected for x in E]
|
||||
|
||||
# look for selected vertices and creates a list containing the new vertices
|
||||
newV = V[:]
|
||||
changes = False
|
||||
for (i,v) in enumerate(V):
|
||||
if v.sel :
|
||||
changes = True
|
||||
if Esel[i-1] == 0 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1])
|
||||
elif Esel[i-1] == 1 and Esel[i] == 0 : newV[i] = get_v(v,V[(i+1) % nV])
|
||||
elif Esel[i-1] == 1 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1],V[(i+1) % nV])
|
||||
else : newV[i] = [get_v(v,V[i-1]),get_v(v,V[(i+1) % nV])]
|
||||
|
||||
if changes:
|
||||
# determine and store the face to be created
|
||||
|
||||
lenV = [len(x) for x in newV]
|
||||
if 2 not in lenV :
|
||||
new_f = NMesh.Face(newV)
|
||||
if sum(Esel) == nV : new_f.sel = 1
|
||||
NF.append(new_f)
|
||||
|
||||
else :
|
||||
nb2 = lenV.count(2)
|
||||
|
||||
if nV == 4 : # f is a quad
|
||||
if nb2 == 1 :
|
||||
ind2 = lenV.index(2)
|
||||
NF.append(NMesh.Face([newV[ind2-1],newV[ind2][0],newV[ind2][1],newV[ind2-3]]))
|
||||
NF.append(NMesh.Face([newV[ind2-1],newV[ind2-2],newV[ind2-3]]))
|
||||
|
||||
elif nb2 == 2 :
|
||||
# We must know if the tuples are neighbours
|
||||
ind2 = ''.join([str(x) for x in lenV+lenV[:1]]).find('22')
|
||||
|
||||
if ind2 != -1 : # They are
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-3][0],newV[ind2-3][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2],newV[ind2-3][1]]))
|
||||
|
||||
else: # They aren't
|
||||
ind2 = lenV.index(2)
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-2][0],newV[ind2-2][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3],newV[ind2-2][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2][1]]))
|
||||
|
||||
elif nb2 == 3 :
|
||||
ind2 = lenV.index(3)
|
||||
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-3][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2-3][0],newV[ind2-3][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0]]))
|
||||
|
||||
else:
|
||||
if (newV[0][1].co-newV[3][0].co).length + (newV[1][0].co-newV[2][1].co).length \
|
||||
< (newV[0][0].co-newV[1][1].co).length + (newV[2][0].co-newV[3][1].co).length :
|
||||
ind2 = 0
|
||||
else :
|
||||
ind2 = 1
|
||||
NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2][0],newV[ind2][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3][0],newV[ind2-2][1],newV[ind2-1][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-3][0],newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1]]))
|
||||
|
||||
else : # f is a tri
|
||||
if nb2 == 1:
|
||||
ind2 = lenV.index(2)
|
||||
NF.append(NMesh.Face([newV[ind2-2],newV[ind2-1],newV[ind2][0],newV[ind2][1]]))
|
||||
|
||||
elif nb2 == 2:
|
||||
ind2 = lenV.index(3)
|
||||
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-2][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
|
||||
|
||||
else:
|
||||
ind2 = min( [((newV[i][1].co-newV[i-1][0].co).length, i) for i in enumV] )[1]
|
||||
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2][0],newV[ind2][1],newV[ind2-2][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
|
||||
|
||||
# Preparing the corners
|
||||
for i in enumV:
|
||||
if lenV[i] == 2 : NC.setdefault(V[i],[]).append(newV[i])
|
||||
|
||||
|
||||
old_faces.append(f)
|
||||
|
||||
# Preparing the Edges
|
||||
for i in enumV:
|
||||
if Esel[i]:
|
||||
verts = [newV[i],newV[(i+1) % nV]]
|
||||
if V[i].index > V[(i+1) % nV].index : verts.reverse()
|
||||
NE.setdefault(E[i],[]).append(verts)
|
||||
|
||||
# Create the faces
|
||||
for f in NF: me.addFace(f)
|
||||
|
||||
def make_edges():
|
||||
""" Make the faces corresponding to selected edges """
|
||||
|
||||
for old,new in NE.iteritems() :
|
||||
if len(new) == 1 : # This edge was on a border
|
||||
oldv = [old.v1, old.v2]
|
||||
if old.v1.index < old.v2.index : oldv.reverse()
|
||||
|
||||
make_sel_face(oldv+new[0])
|
||||
|
||||
me.findEdge(*oldv).flag |= E_selected
|
||||
me.findEdge(*new[0]).flag |= E_selected
|
||||
|
||||
#PY23 NO SETS# for v in oldv : NV_ext.add(v)
|
||||
for v in oldv : NV_ext[v]= None
|
||||
|
||||
else:
|
||||
make_sel_face(new[0] + new[1][::-1])
|
||||
|
||||
me.findEdge(*new[0]).flag |= E_selected
|
||||
me.findEdge(*new[1]).flag |= E_selected
|
||||
|
||||
def make_corners():
|
||||
""" Make the faces corresponding to corners """
|
||||
|
||||
for v in NV.iterkeys():
|
||||
V = NV[v].values()
|
||||
nV = len(V)
|
||||
|
||||
if nV == 1: pass
|
||||
|
||||
elif nV == 2 :
|
||||
#PY23 NO SETS# if v in NV_ext:
|
||||
if v in NV_ext.iterkeys():
|
||||
make_sel_face(V+[v])
|
||||
me.findEdge(*V).flag |= E_selected
|
||||
|
||||
else:
|
||||
#PY23 NO SETS# if nV == 3 and v not in NV_ext : make_sel_face(V)
|
||||
if nV == 3 and v not in NV_ext.iterkeys() : make_sel_face(V)
|
||||
|
||||
|
||||
else :
|
||||
|
||||
# We need to know which are the edges around the corner.
|
||||
# First, we look for the quads surrounding the corner.
|
||||
eed = []
|
||||
for old, new in NE.iteritems():
|
||||
if v in (old.v1,old.v2) :
|
||||
if v.index == min(old.v1.index,old.v2.index) : ind = 0
|
||||
else : ind = 1
|
||||
|
||||
if len(new) == 1: eed.append([v,new[0][ind]])
|
||||
else : eed.append([new[0][ind],new[1][ind]])
|
||||
|
||||
# We will add the edges coming from faces where only one vertice is selected.
|
||||
# They are stored in NC.
|
||||
if v in NC: eed = eed+NC[v]
|
||||
|
||||
# Now we have to sort these vertices
|
||||
hc = {}
|
||||
for (a,b) in eed :
|
||||
hc.setdefault(a,[]).append(b)
|
||||
hc.setdefault(b,[]).append(a)
|
||||
|
||||
for x0,edges in hc.iteritems():
|
||||
if len(edges) == 1 : break
|
||||
|
||||
b = [x0] # b will contain the sorted list of vertices
|
||||
|
||||
for i in xrange(len(hc)-1):
|
||||
for x in hc[x0] :
|
||||
if x not in b : break
|
||||
b.append(x)
|
||||
x0 = x
|
||||
|
||||
b.append(b[0])
|
||||
|
||||
# Now we can create the faces
|
||||
if len(b) == 5: make_sel_face(b[:4])
|
||||
|
||||
else:
|
||||
New_V = Vector(0.0, 0.0,0.0)
|
||||
New_d = [0.0, 0.0,0.0]
|
||||
|
||||
for x in hc.iterkeys(): New_V += x.co
|
||||
for dir in NV[v] :
|
||||
for i in xrange(3): New_d[i] += dir[i]
|
||||
|
||||
New_V *= 1./len(hc)
|
||||
for i in xrange(3) : New_d[i] /= nV
|
||||
|
||||
center = make_sel_vert(New_V.x,New_V.y,New_V.z)
|
||||
add_to_NV(v,tuple(New_d),center)
|
||||
|
||||
for k in xrange(len(b)-1): make_sel_face([center, b[k], b[k+1]])
|
||||
|
||||
if 2 < nV and v in NC :
|
||||
for edge in NC[v] : me.findEdge(*edge).flag |= E_selected
|
||||
|
||||
def clear_old():
|
||||
""" Erase old faces and vertices """
|
||||
|
||||
for f in old_faces: me.removeFace(f)
|
||||
|
||||
for v in NV.iterkeys():
|
||||
#PY23 NO SETS# if v not in NV_ext : me.verts.remove(v)
|
||||
if v not in NV_ext.iterkeys() : me.verts.remove(v)
|
||||
|
||||
for e in me.edges:
|
||||
if e.flag & E_selected :
|
||||
e.v1.sel = 1
|
||||
e.v2.sel = 1
|
||||
|
||||
|
||||
######################################################################
|
||||
# Interface
|
||||
|
||||
global dist
|
||||
|
||||
dist = Create(0.2)
|
||||
left = Create(0.0)
|
||||
right = Create(1.0)
|
||||
num = Create(2)
|
||||
|
||||
# Events
|
||||
EVENT_NOEVENT = 1
|
||||
EVENT_BEVEL = 2
|
||||
EVENT_UPDATE = 3
|
||||
EVENT_RECURS = 4
|
||||
EVENT_EXIT = 5
|
||||
|
||||
def draw():
|
||||
global dist, left, right, num, old_dist
|
||||
global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
Button("Bevel",EVENT_BEVEL,10,100,280,25)
|
||||
|
||||
BeginAlign()
|
||||
left=Number('', EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider')
|
||||
dist=Slider("Thickness ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0, \
|
||||
"Thickness of the bevel, can be changed even after bevelling")
|
||||
right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider")
|
||||
|
||||
EndAlign()
|
||||
glRasterPos2d(8,40)
|
||||
Text('To finish, you can use recursive bevel to smooth it')
|
||||
|
||||
|
||||
if old_dist != None:
|
||||
num=Number('', EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level')
|
||||
Button("Recursive",EVENT_RECURS,55,10,100,16)
|
||||
|
||||
Button("Exit",EVENT_EXIT,210,10,80,20)
|
||||
|
||||
def event(evt, val):
|
||||
if ((evt == QKEY or evt == ESCKEY) and not val): Exit()
|
||||
|
||||
def bevent(evt):
|
||||
if evt == EVENT_EXIT : Exit()
|
||||
elif evt == EVENT_BEVEL : bevel()
|
||||
elif evt == EVENT_UPDATE :
|
||||
try: bevel_update()
|
||||
except NameError : pass
|
||||
elif evt == EVENT_RECURS : recursive()
|
||||
|
||||
Register(draw, event, bevent)
|
||||
|
||||
######################################################################
|
||||
def bevel():
|
||||
""" The main function, which creates the bevel """
|
||||
global me,NV,NV_ext,NE,NC, old_faces,old_dist
|
||||
|
||||
ob = act_mesh_ob()
|
||||
if not ob: return
|
||||
|
||||
Window.WaitCursor(1) # Change the Cursor
|
||||
t= Blender.sys.time()
|
||||
is_editmode = Window.EditMode()
|
||||
if is_editmode: Window.EditMode(0)
|
||||
|
||||
me = ob.data
|
||||
|
||||
NV = {}
|
||||
#PY23 NO SETS# NV_ext = set()
|
||||
NV_ext= {}
|
||||
NE = {}
|
||||
NC = {}
|
||||
old_faces = []
|
||||
|
||||
make_faces()
|
||||
make_edges()
|
||||
make_corners()
|
||||
clear_old()
|
||||
|
||||
old_dist = dist.val
|
||||
print '\tbevel in %.6f sec' % (Blender.sys.time()-t)
|
||||
me.update(1)
|
||||
if is_editmode: Window.EditMode(1)
|
||||
Window.WaitCursor(0)
|
||||
Blender.Redraw()
|
||||
|
||||
def bevel_update():
|
||||
""" Use NV to update the bevel """
|
||||
global dist, old_dist
|
||||
|
||||
if old_dist == None:
|
||||
# PupMenu('Error%t|Must bevel first.')
|
||||
return
|
||||
|
||||
is_editmode = Window.EditMode()
|
||||
if is_editmode: Window.EditMode(0)
|
||||
|
||||
fac = dist.val - old_dist
|
||||
old_dist = dist.val
|
||||
|
||||
for old_v in NV.iterkeys():
|
||||
for dir in NV[old_v].iterkeys():
|
||||
for i in xrange(3):
|
||||
NV[old_v][dir].co[i] += fac*dir[i]
|
||||
|
||||
me.update(1)
|
||||
if is_editmode: Window.EditMode(1)
|
||||
Blender.Redraw()
|
||||
|
||||
def recursive():
|
||||
""" Make a recursive bevel... still experimental """
|
||||
global dist
|
||||
from math import pi, sin
|
||||
|
||||
if num.val > 1:
|
||||
a = pi/4
|
||||
ang = []
|
||||
for k in xrange(num.val):
|
||||
ang.append(a)
|
||||
a = (pi+2*a)/4
|
||||
|
||||
l = [2*(1-sin(x))/sin(2*x) for x in ang]
|
||||
R = dist.val/sum(l)
|
||||
l = [x*R for x in l]
|
||||
|
||||
dist.val = l[0]
|
||||
bevel_update()
|
||||
|
||||
for x in l[1:]:
|
||||
dist.val = x
|
||||
bevel()
|
||||
|
||||
@@ -1,729 +0,0 @@
|
||||
#!BPY
|
||||
# coding: utf-8
|
||||
"""
|
||||
Name: 'BlenderLipSynchro'
|
||||
Blender: 242
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Import phonemes from Papagayo or JLipSync for lip synchronization'
|
||||
"""
|
||||
|
||||
__author__ = "Dienben: Benoit Foucque dienben_mail@yahoo.fr"
|
||||
__url__ = ["blenderLipSynchro Blog, http://blenderlipsynchro.blogspot.com/",
|
||||
"Papagayo (Python), http://www.lostmarble.com/papagayo/index.shtml",
|
||||
"JLipSync (Java), http://jlipsync.sourceforge.net/"]
|
||||
__version__ = "2.0"
|
||||
__bpydoc__ = """\
|
||||
Description:
|
||||
|
||||
This script imports Voice Export made by Papagayo or JLipSync and maps the export with your shapes.
|
||||
|
||||
Usage:
|
||||
|
||||
Import a Papagayo or JLipSync voice export file and link it with your shapes.
|
||||
|
||||
Note:<br>
|
||||
- Naturally, you need files exported from one of the supported lip synching
|
||||
programs. Check their sites to learn more and download them.
|
||||
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# BlenderLipSynchro
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#il y a 3 etapes
|
||||
#la deuxieme on charge le dictionnaire de correspondance
|
||||
#la troisieme on fait le choix des correpondance
|
||||
#la quatrieme on construit les cles a partir du fichiers frame
|
||||
|
||||
#there are 3 stages
|
||||
#the second one load the mapping dictionnary
|
||||
#the tird make the mapping
|
||||
#the fourth make the key in the IPO Curve
|
||||
|
||||
#voici mes differents imports
|
||||
#the imports
|
||||
import os
|
||||
import Blender
|
||||
|
||||
from Blender import Ipo
|
||||
from Blender.Draw import *
|
||||
from Blender.BGL import *
|
||||
from Blender.sys import basename
|
||||
|
||||
|
||||
|
||||
#ici commencent mes fonctions
|
||||
#here begin my functions
|
||||
#cette fonction trace l'interface graphique
|
||||
#this functions draw the User interface
|
||||
def trace():
|
||||
#voici mes variables pouvant etre modifie
|
||||
#my variables
|
||||
global nbr_phoneme, mon_fichier_dico
|
||||
global let01, let02, let03, let04,let05, let06, let07, let08, let09, let10
|
||||
global let11, let12, let13, let14,let15, let16, let17, let18, let19, let20
|
||||
global let21, let22, let23, let24
|
||||
|
||||
global let01selectkey,let02selectkey,let03selectkey,let04selectkey,let05selectkey
|
||||
global let06selectkey,let07selectkey,let08selectkey,let09selectkey,let10selectkey,let11selectkey
|
||||
global let12selectkey,let13selectkey,let14selectkey,let15selectkey,let16selectkey,let17selectkey
|
||||
global let18selectkey,let19selectkey,let20selectkey,let21selectkey,let22selectkey,let23selectkey
|
||||
global let24selectkey
|
||||
|
||||
glClearColor(0.4,0.5,0.6 ,0.0)
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(87, 375)
|
||||
Text("Blendersynchro V 2.0")
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(84, 360)
|
||||
Text("Programming: Dienben")
|
||||
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(13, 342)
|
||||
Text("Lip Synchronization Tool")
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(13, 326)
|
||||
Text("Thanks to Chris Clawson and Liubomir Kovatchev")
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(5, 320)
|
||||
Text("_______________________________________________________")
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(6, 318)
|
||||
Text("_______________________________________________________")
|
||||
|
||||
|
||||
if (etape==1):
|
||||
#cette etape permet de choisi la correspondance entre les phonemes et les cles
|
||||
#this stage offer the possibility to choose the mapping between phonems and shapes
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(140, 300)
|
||||
Text("Objet: "+Blender.Object.GetSelected()[0].getName() )
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(5, 215)
|
||||
Text("Assign phonems to shapes:")
|
||||
|
||||
#on mesure la taille de la liste de phonemes
|
||||
#this is the lenght of the phonem list
|
||||
nbr_phoneme=len(liste_phoneme)
|
||||
|
||||
#on dessine les listes de choix
|
||||
#we draw the choice list
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 0):
|
||||
let01 = String(" ", 4, 5, 185, 30, 16, liste_phoneme[0], 3)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 188)
|
||||
Text("=")
|
||||
let01selectkey = Menu(key_menu, 50, 50, 185, 70, 16, let01selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 1):
|
||||
let02 = String(" ", 4, 150, 185, 30, 16, liste_phoneme[1], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 188)
|
||||
Text("=")
|
||||
let02selectkey = Menu(key_menu, 51, 195, 185, 70, 16, let02selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 2):
|
||||
let03 = String(" ", 4, 5, 165, 30, 16, liste_phoneme[2], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 168)
|
||||
Text("=")
|
||||
let03selectkey = Menu(key_menu, 52, 50, 165, 70, 16, let03selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 3):
|
||||
let04 = String(" ", 4, 150, 165, 30, 16, liste_phoneme[3], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 168)
|
||||
Text("=")
|
||||
let04selectkey = Menu(key_menu, 53, 195, 165, 70, 16, let04selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 4):
|
||||
let05 = String(" ", 4, 5, 145, 30, 16, liste_phoneme[4], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 148)
|
||||
Text("=")
|
||||
let05selectkey = Menu(key_menu, 54, 50, 145, 70, 16, let05selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 5):
|
||||
let06 = String(" ", 4, 150, 145, 30, 16, liste_phoneme[5], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 148)
|
||||
Text("=")
|
||||
let06selectkey = Menu(key_menu, 55, 195, 145, 70, 16, let06selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 6):
|
||||
let07 = String(" ", 4, 5, 125, 30, 16, liste_phoneme[6], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 128)
|
||||
Text("=")
|
||||
let07selectkey = Menu(key_menu, 56, 50, 125, 70, 16, let07selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 7):
|
||||
let08 = String(" ", 4, 150, 125, 30, 16, liste_phoneme[7], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 128)
|
||||
Text("=")
|
||||
let08selectkey = Menu(key_menu, 57, 195, 125, 70, 16,let08selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 8):
|
||||
let09 = String(" ", 4, 5, 105, 30, 16, liste_phoneme[8], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 108)
|
||||
Text("=")
|
||||
let09selectkey = Menu(key_menu, 58, 50, 105, 70, 16,let09selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 9):
|
||||
let10 = String(" ", 4, 150, 105, 30, 16, liste_phoneme[9], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 108)
|
||||
Text("=")
|
||||
let10selectkey = Menu(key_menu, 59, 195, 105, 70, 16, let10selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 10):
|
||||
let11 = String(" ", 4, 5, 85, 30, 16, liste_phoneme[10], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 88)
|
||||
Text("=")
|
||||
let11selectkey = Menu(key_menu, 60, 50, 85, 70, 16, let11selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 11):
|
||||
let12 = String(" ", 4, 150, 85, 30, 16, liste_phoneme[11], 2)
|
||||
glColor3d(0,0,0)
|
||||
Text("=")
|
||||
let12selectkey = Menu(key_menu, 61, 195, 85, 70, 16, let12selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 12):
|
||||
let13 = String(" ", 4, 5, 65, 30, 16, liste_phoneme[12], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 68)
|
||||
Text("=")
|
||||
let13selectkey = Menu(key_menu, 62, 50, 65, 70, 16, let13selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 13):
|
||||
let14 = String(" ", 4, 150, 65, 30, 16, liste_phoneme[13], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 68)
|
||||
Text("=")
|
||||
let14selectkey = Menu(key_menu, 63, 195, 65, 70, 16, let14selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 14):
|
||||
let15 = String(" ", 4, 5, 45, 30, 16, liste_phoneme[14], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 48)
|
||||
Text("=")
|
||||
let15selectkey = Menu(key_menu, 64, 50, 45, 70, 16, let15selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 15):
|
||||
let16 = String(" ", 4, 150, 45, 30, 16, liste_phoneme[15], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 48)
|
||||
Text("=")
|
||||
let16selectkey = Menu(key_menu, 65, 195, 45, 70, 16, let16selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 16):
|
||||
let17 = String(" ", 4, 295, 185, 30, 16, liste_phoneme[16], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 188)
|
||||
Text("=")
|
||||
let17selectkey = Menu(key_menu, 66, 340, 185, 70, 16, let17selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 17):
|
||||
let18 = String(" ", 4, 440, 185, 70, 16, liste_phoneme[17], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 188)
|
||||
Text("=")
|
||||
let18selectkey = Menu(key_menu, 67, 525, 185, 70, 16, let18selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 18):
|
||||
let19 = String(" ", 4, 295, 165, 30, 16, liste_phoneme[18], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 168)
|
||||
Text("=")
|
||||
let19selectkey = Menu(key_menu, 68, 340, 165, 70, 16, let19selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 19):
|
||||
let20 = String(" ", 4, 440, 165, 70, 16, liste_phoneme[19], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 168)
|
||||
Text("=")
|
||||
let20selectkey = Menu(key_menu, 69, 525, 165, 70, 16, let20selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 20):
|
||||
let21 = String(" ", 4, 295, 145, 30, 16, liste_phoneme[20], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 148)
|
||||
Text("=")
|
||||
let21selectkey = Menu(key_menu, 70, 340, 145, 70, 16, let21selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 21):
|
||||
let22 = String(" ", 4, 440, 145, 70, 16, liste_phoneme[21], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 148)
|
||||
Text("=")
|
||||
let22selectkey = Menu(key_menu, 71, 525, 145, 70, 16, let22selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 22):
|
||||
let23 = String(" ", 4, 295, 125, 30, 16, liste_phoneme[22], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 128)
|
||||
Text("=")
|
||||
let23selectkey = Menu(key_menu, 72, 340, 125, 70, 16,let23selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 23):
|
||||
let24 = String(" ", 4, 440, 125, 70, 16, liste_phoneme[23], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 128)
|
||||
Text("=")
|
||||
let24selectkey = Menu(key_menu, 73, 525, 125, 70, 16, let24selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 24):
|
||||
let25 = String(" ", 4, 295, 105, 30, 16, liste_phoneme[24], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 108)
|
||||
Text("=")
|
||||
let25selectkey = Menu(key_menu, 74, 340, 105, 70, 16, let25selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 25):
|
||||
let26 = String(" ", 4, 440, 105, 70, 16, liste_phoneme[25], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 108)
|
||||
Text("=")
|
||||
let26selectkey = Menu(key_menu, 75, 525, 105, 70, 16,let26selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 26):
|
||||
let27 = String(" ", 4, 295, 85, 30, 16, liste_phoneme[26], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 88)
|
||||
Text("=")
|
||||
let27selectkey = Menu(key_menu, 76, 340, 85, 70, 16, let27selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 27):
|
||||
let28 = String(" ", 4, 440, 85, 70, 16, liste_phoneme[27], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 88)
|
||||
Text("=")
|
||||
let28selectkey = Menu(key_menu, 77, 525, 85, 70, 16,let28selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 28):
|
||||
let29 = String(" ", 4, 295, 65, 30, 16, liste_phoneme[28], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 68)
|
||||
Text("=")
|
||||
let29selectkey = Menu(key_menu, 78, 340, 65, 70, 16, let29selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 29):
|
||||
let30 = String(" ", 4, 440, 65, 70, 16, liste_phoneme[29], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 68)
|
||||
Text("=")
|
||||
let30selectkey = Menu(key_menu, 79, 525, 65, 70, 16, let30selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 30):
|
||||
let31 = String(" ", 4, 295, 45, 30, 16, liste_phoneme[30], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 48)
|
||||
Text("=")
|
||||
let31selectkey = Menu(key_menu, 80, 340, 45, 70, 16, let31selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 31):
|
||||
let32 = String(" ", 4, 440, 45, 70, 16, liste_phoneme[31], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 48)
|
||||
Text("=")
|
||||
let32selectkey = Menu(key_menu, 81, 525, 45, 70, 16, let32selectkey.val)
|
||||
|
||||
Button("Go", 3, 155, 5, 145, 22)
|
||||
|
||||
if (etape==2):
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(125, 200)
|
||||
Text("Operation Completed")
|
||||
|
||||
if (etape==0):
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(125, 200)
|
||||
Text("Please select a Mesh'Object and Create all the IPO Curves for your Shapes")
|
||||
|
||||
if (etape==3):
|
||||
#this stage permits to load a custom dictionnary
|
||||
load_file_text = "Load File"
|
||||
if mon_fichier_dico:
|
||||
Button("Import Loaded File", 2, 5, 5, 145, 22)
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(6, 50)
|
||||
Text("loaded file: %s" % basename(mon_fichier_dico))
|
||||
load_file_text = "Choose Another File"
|
||||
Button(load_file_text, 8, 125, 180, 145, 22)
|
||||
|
||||
glRasterPos2i(6, 40)
|
||||
Text("_______________________________________________________")
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(6, 38)
|
||||
Text("_______________________________________________________")
|
||||
|
||||
Button("Exit", 1, 305, 5, 80, 22)
|
||||
|
||||
|
||||
|
||||
#cette fonction sur evenement quite en cas d'ESC
|
||||
#this functions catch the ESC event and quit
|
||||
def event(evt,val):
|
||||
if (evt == ESCKEY and not val): Exit()
|
||||
|
||||
#cette fonction gere les evenements
|
||||
#the event functions
|
||||
def bevent(evt):
|
||||
global etape,soft_type,liste_phoneme,dico_phoneme_export
|
||||
|
||||
if (evt == 1):
|
||||
Exit()
|
||||
|
||||
elif (evt == 2):
|
||||
#c'est l'import du dictionnaire
|
||||
#we create and import the dictionnary
|
||||
lecture_chaine(mon_fichier_dico,dico_phoneme_export)
|
||||
construction_dictionnaire_phoneme()
|
||||
#we change the stage
|
||||
etape=1
|
||||
|
||||
elif (evt == 3):
|
||||
#c'est l'import
|
||||
#we import
|
||||
lecture_chaine(mon_fichier_export,dico_phoneme_export)
|
||||
construction_dico_correspondance()
|
||||
construction_lipsynchro()
|
||||
#on change d'etape
|
||||
#we change the stage
|
||||
etape=2
|
||||
|
||||
elif (evt == 8):
|
||||
#we choose the file
|
||||
Blender.Window.FileSelector(selectionner_fichier,"Select File")
|
||||
|
||||
Blender.Redraw()
|
||||
|
||||
#cette fonction recupere le nom et le chemin du fichier dictionnaire
|
||||
#we catch the name and the path of the dictionnary
|
||||
def selectionner_fichier(filename):
|
||||
global mon_fichier_dico,mon_fichier_export
|
||||
mon_fichier_dico=filename
|
||||
mon_fichier_export=filename
|
||||
|
||||
#fonction de lecture de la liste frame phoneme
|
||||
#we read the frame and phonems
|
||||
def lecture_chaine(fichier,liste):
|
||||
mon_fichier=open(fichier)
|
||||
#je lis la premiere ligne qui contiens la version de moho
|
||||
#first, we read the moho version
|
||||
mon_fichier.readline()
|
||||
|
||||
#je lis jusqu'a la fin
|
||||
#then we read until the end of the file
|
||||
while 1:
|
||||
ma_ligne=mon_fichier.readline()
|
||||
if ma_ligne=='':
|
||||
break
|
||||
decoup=ma_ligne.split()
|
||||
liste[decoup[0]]=decoup[1]
|
||||
print liste
|
||||
|
||||
|
||||
|
||||
|
||||
#fonction qui construit la liste dictionnaire simple
|
||||
#we make the dictionnary
|
||||
def construction_dictionnaire_phoneme():
|
||||
global liste_phoneme
|
||||
index_liste=0
|
||||
#je transforme mon dictionnaire en list de tulpes
|
||||
#we transform the list in tulpes
|
||||
ma_liste=dico_phoneme_export.items()
|
||||
#je parcours ma liste a la recherche d'elements non existant
|
||||
#we read the list to find non existing elements
|
||||
print dico_phoneme
|
||||
for index in range(len(ma_liste)):
|
||||
if ma_liste[index][1] not in liste_phoneme:
|
||||
liste_phoneme[index_liste:index_liste]=[ma_liste[index][1]]
|
||||
index_liste=index_liste+1
|
||||
print liste_phoneme
|
||||
|
||||
|
||||
#cette fonction recupere les courbes cible
|
||||
#this functon catch the IPO curve
|
||||
def recuperation_courbe():
|
||||
global key_menu,dico_key
|
||||
|
||||
#on recupere le nom des shapes
|
||||
#we catch the shapes
|
||||
key=Blender.Object.GetSelected()[0].getData().getKey().getBlocks()
|
||||
for n in range(len(key)):
|
||||
#on vire la premi<6D>re cle (en effet basic n'est pas une cle en tant que telle)
|
||||
#we threw away the basic shapes
|
||||
if (n>0):
|
||||
key_menu=key_menu+key[n].name + " %x" + str(n-1) + "|"
|
||||
dico_key[str(n-1)]=Blender.Object.GetSelected()[0].getData().getKey().getIpo().getCurves()[n-1]
|
||||
|
||||
|
||||
print "dico_key"
|
||||
print dico_key
|
||||
print 'end dico_key'
|
||||
|
||||
#cette fonction construit un dictionnaire de correspondance entre les phonemes prononces et les cles a utiliser
|
||||
#we make the dictionnary for the mapping between shapes and phonems
|
||||
def construction_dico_correspondance():
|
||||
global dico_correspondance
|
||||
#je parcours les phonemes
|
||||
#we read the phonems
|
||||
if (nbr_phoneme>0):
|
||||
dico_correspondance[liste_phoneme[0]]=dico_key[str(let01selectkey.val)]
|
||||
if (nbr_phoneme>1):
|
||||
dico_correspondance[liste_phoneme[1]]=dico_key[str(let02selectkey.val)]
|
||||
if (nbr_phoneme>2):
|
||||
dico_correspondance[liste_phoneme[2]]=dico_key[str(let03selectkey.val)]
|
||||
if (nbr_phoneme>3):
|
||||
dico_correspondance[liste_phoneme[3]]=dico_key[str(let04selectkey.val)]
|
||||
if (nbr_phoneme>4):
|
||||
dico_correspondance[liste_phoneme[4]]=dico_key[str(let05selectkey.val)]
|
||||
if (nbr_phoneme>5):
|
||||
dico_correspondance[liste_phoneme[5]]=dico_key[str(let06selectkey.val)]
|
||||
if (nbr_phoneme>6):
|
||||
dico_correspondance[liste_phoneme[6]]=dico_key[str(let07selectkey.val)]
|
||||
if (nbr_phoneme>7):
|
||||
dico_correspondance[liste_phoneme[7]]=dico_key[str(let08selectkey.val)]
|
||||
if (nbr_phoneme>8):
|
||||
dico_correspondance[liste_phoneme[8]]=dico_key[str(let09selectkey.val)]
|
||||
if (nbr_phoneme>9):
|
||||
dico_correspondance[liste_phoneme[9]]=dico_key[str(let10selectkey.val)]
|
||||
if (nbr_phoneme>10):
|
||||
dico_correspondance[liste_phoneme[10]]=dico_key[str(let11selectkey.val)]
|
||||
if (nbr_phoneme>11):
|
||||
dico_correspondance[liste_phoneme[11]]=dico_key[str(let12selectkey.val)]
|
||||
if (nbr_phoneme>12):
|
||||
dico_correspondance[liste_phoneme[12]]=dico_key[str(let13selectkey.val)]
|
||||
if (nbr_phoneme>13):
|
||||
dico_correspondance[liste_phoneme[13]]=dico_key[str(let14selectkey.val)]
|
||||
if (nbr_phoneme>14):
|
||||
dico_correspondance[liste_phoneme[14]]=dico_key[str(let15selectkey.val)]
|
||||
if (nbr_phoneme>15):
|
||||
dico_correspondance[liste_phoneme[15]]=dico_key[str(let16selectkey.val)]
|
||||
if (nbr_phoneme>16):
|
||||
dico_correspondance[liste_phoneme[16]]=dico_key[str(let17selectkey.val)]
|
||||
if (nbr_phoneme>17):
|
||||
dico_correspondance[liste_phoneme[17]]=dico_key[str(let18selectkey.val)]
|
||||
if (nbr_phoneme>18):
|
||||
dico_correspondance[liste_phoneme[18]]=dico_key[str(let19selectkey.val)]
|
||||
if (nbr_phoneme>19):
|
||||
dico_correspondance[liste_phoneme[19]]=dico_key[str(let20selectkey.val)]
|
||||
if (nbr_phoneme>20):
|
||||
dico_correspondance[liste_phoneme[20]]=dico_key[str(let21selectkey.val)]
|
||||
if (nbr_phoneme>21):
|
||||
dico_correspondance[liste_phoneme[21]]=dico_key[str(let22selectkey.val)]
|
||||
if (nbr_phoneme>22):
|
||||
dico_correspondance[liste_phoneme[22]]=dico_key[str(let23selectkey.val)]
|
||||
if (nbr_phoneme>23):
|
||||
dico_correspondance[liste_phoneme[23]]=dico_key[str(let24selectkey.val)]
|
||||
if (nbr_phoneme>24):
|
||||
dico_correspondance[liste_phoneme[24]]=dico_key[str(let25selectkey.val)]
|
||||
if (nbr_phoneme>25):
|
||||
dico_correspondance[liste_phoneme[25]]=dico_key[str(let26selectkey.val)]
|
||||
if (nbr_phoneme>26):
|
||||
dico_correspondance[liste_phoneme[26]]=dico_key[str(let27selectkey.val)]
|
||||
if (nbr_phoneme>27):
|
||||
dico_correspondance[liste_phoneme[27]]=dico_key[str(let28selectkey.val)]
|
||||
if (nbr_phoneme>28):
|
||||
dico_correspondance[liste_phoneme[28]]=dico_key[str(let29selectkey.val)]
|
||||
if (nbr_phoneme>29):
|
||||
dico_correspondance[liste_phoneme[29]]=dico_key[str(let30selectkey.val)]
|
||||
if (nbr_phoneme>30):
|
||||
dico_correspondance[liste_phoneme[30]]=dico_key[str(let31selectkey.val)]
|
||||
if (nbr_phoneme>31):
|
||||
dico_correspondance[liste_phoneme[31]]=dico_key[str(let32selectkey.val)]
|
||||
|
||||
print dico_correspondance
|
||||
|
||||
|
||||
#cette fonction ajoute un points a la cle donnee a la frame donnee
|
||||
#we add a point to the IPO curve Target
|
||||
def ajoute_point(cle,frame,valeur):
|
||||
cle.setInterpolation('Linear')
|
||||
cle.append((frame,valeur))
|
||||
cle.Recalc()
|
||||
|
||||
#cette fonction parcours le dictionnaire des frame <20> ajouter et construit les points
|
||||
#we add all the point to the IPO Curve
|
||||
def construction_lipsynchro():
|
||||
print "je construit"
|
||||
doublet_old=""
|
||||
#construction de la liste des frame
|
||||
cpt=0
|
||||
liste_frame=[]
|
||||
for frame in dico_phoneme_export:
|
||||
liste_frame.append(int(frame))
|
||||
cpt=cpt+1
|
||||
liste_frame.sort()
|
||||
print "listeframe"
|
||||
print liste_frame
|
||||
print "fini"
|
||||
|
||||
for doublet in liste_frame:
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],doublet,1)
|
||||
if (doublet_old==""):
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0)
|
||||
if (doublet_old!=''):
|
||||
if (dico_correspondance[dico_phoneme_export[str(doublet)]]!=dico_correspondance[dico_phoneme_export[doublet_old]]):
|
||||
print "doublet:"+str(doublet)
|
||||
print "doublet old:"+doublet_old
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[doublet_old]],(int(doublet_old)+2),0)
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0)
|
||||
doublet_old=str(doublet)
|
||||
|
||||
|
||||
#end of my functions we begin the execution
|
||||
#je commence l execution-----------------------------------------------------------------------------------------------
|
||||
#voici mes variables
|
||||
|
||||
#declaration et instanciation
|
||||
#decleration and instanciation
|
||||
|
||||
|
||||
#voici mon objet de travail
|
||||
objet_travail=Create(0)
|
||||
|
||||
#my soft type
|
||||
soft_type=1
|
||||
|
||||
#voici la liste des phoneme effectivement utilise
|
||||
#the phonems'list
|
||||
#liste_phoneme_papagayo=['AI','E','O','U','FV','L','WQ','MBP','etc','rest']
|
||||
#liste_phoneme_jlipsinch=['A','B','C','Closed','D','E','F','G','I','K','L','M','N','O','P','Q','R','S','SH','T','TH','U','V','W']
|
||||
|
||||
liste_phoneme=[]
|
||||
#voici mon dictionnaire des frames o
|
||||
dico_phoneme_export = Create(0)
|
||||
dico_phoneme_export={}
|
||||
dico_phoneme={}
|
||||
|
||||
|
||||
#voici mes cle
|
||||
key_menu=""
|
||||
dico_key={}
|
||||
|
||||
#voici mes ipo
|
||||
dico_bloc={}
|
||||
iponame = Create(0)
|
||||
|
||||
#voici mon dictionnaire de correspondance
|
||||
dico_correspondance={}
|
||||
|
||||
try:
|
||||
#on verifie est bien une mesh et qu'il a des courbes
|
||||
if ((Blender.Object.GetSelected()[0].getType()=='Mesh')):
|
||||
#on verifie que l'objet a bien toute ses Courbes
|
||||
if (len(Blender.Object.GetSelected()[0].getData().getKey().getBlocks())-1==Blender.Object.GetSelected()[0].getData().getKey().getIpo().getNcurves()):
|
||||
etape=3
|
||||
#on lance la creation du dictionnaire
|
||||
recuperation_courbe()
|
||||
else:
|
||||
print "not the good number of IPO Curve"
|
||||
etape = 0
|
||||
else:
|
||||
print "error: bad object Type:"
|
||||
print Blender.Object.GetSelected()[0].getType()
|
||||
etape = 0
|
||||
except:
|
||||
print 'error: exception'
|
||||
etape = 0
|
||||
|
||||
|
||||
#voici le fichier dictionnaire
|
||||
mon_fichier_dico=""
|
||||
|
||||
#voici le fichier export pamela
|
||||
mon_fichier_export=""
|
||||
|
||||
|
||||
let01selectkey = Create(0)
|
||||
let02selectkey = Create(0)
|
||||
let03selectkey = Create(0)
|
||||
let04selectkey = Create(0)
|
||||
let05selectkey = Create(0)
|
||||
let06selectkey = Create(0)
|
||||
let07selectkey = Create(0)
|
||||
let08selectkey = Create(0)
|
||||
let09selectkey = Create(0)
|
||||
let10selectkey = Create(0)
|
||||
let11selectkey = Create(0)
|
||||
let12selectkey = Create(0)
|
||||
let13selectkey = Create(0)
|
||||
let14selectkey = Create(0)
|
||||
let15selectkey = Create(0)
|
||||
let16selectkey = Create(0)
|
||||
let17selectkey = Create(0)
|
||||
let18selectkey = Create(0)
|
||||
let19selectkey = Create(0)
|
||||
let20selectkey = Create(0)
|
||||
let21selectkey = Create(0)
|
||||
let22selectkey = Create(0)
|
||||
let23selectkey = Create(0)
|
||||
let24selectkey = Create(0)
|
||||
|
||||
|
||||
Register (trace,event,bevent)
|
||||
@@ -1,121 +0,0 @@
|
||||
Version 3.233-2004
|
||||
******************
|
||||
Espanol
|
||||
Sale del programa
|
||||
Utilidades de...%t|Alinea objetos%x1|Creacion%x2|Edita mallas%x3|Edita objetos%x4
|
||||
11
|
||||
Mov
|
||||
Esc
|
||||
Encaja
|
||||
Abarca
|
||||
Separa
|
||||
Alinea
|
||||
Rota
|
||||
Incr.
|
||||
Crea nuevos objetos
|
||||
Es+
|
||||
Es*
|
||||
Separar entre:%t|Origenes%x1|Centros geometricos%x2|Minimos%x3|Maximos%x4|Baricentro%x5|Objetos%x6
|
||||
Crear%t|Arco (3 ptos.)%x1|Arco (interactivo)%x2|Circunferencia (3 ptos.)%x3
|
||||
12
|
||||
Puntos
|
||||
Centro
|
||||
Orden
|
||||
Objeto
|
||||
AngIni:
|
||||
AngFin:
|
||||
Angulo:
|
||||
Radio:
|
||||
Puntos:
|
||||
Centro
|
||||
Nombre:
|
||||
Puntos
|
||||
Modifica vertices%t|Subdivide%x1|Envia a un plano%x2|Aplica LocRotSize%x3
|
||||
Partes
|
||||
Proyectar en el plano:%t|Coordenado global...%x1|Coordenado local...%x2
|
||||
Actuar sobre el plano%t|Yz%x1|Zx%x2|Xy%x3
|
||||
En la direcci<63>n%t|X%x1|Y%x2|Z%x3|Ortogonal al plano%x4
|
||||
Captura
|
||||
Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacion%x3|Copia media LocRotSiz%x4|Ver buffer en consola%x5
|
||||
Transformar LocRotSize%t|Hacia el obj. activo%x1|Aleatoriamente%x2
|
||||
Poner a distancia fija%x1|Sumar (desp. absoluto)%x2|Multiplicar (desp. relativo)%x3
|
||||
********************
|
||||
English
|
||||
Exit program
|
||||
Utils about:%t|Align Objects%x1|Create%x2|Edit Meshes%x3|Edit Objects%x4
|
||||
11
|
||||
Mov
|
||||
Sca
|
||||
Fit
|
||||
Embrace
|
||||
Separate
|
||||
Align
|
||||
Rota
|
||||
Incr.
|
||||
Create new objects
|
||||
Sc+
|
||||
Sc*
|
||||
Separate between:%t|Origins%x1|Geometric centers%x2|Minimum%x3|Maximum%x4|Baricenter%x5|Objects%x6
|
||||
Create what%t|Arc (3 pts.)%x1|Arc (interactive)%x2|Circunference (3 pts.)%x3
|
||||
12
|
||||
Points
|
||||
Centre
|
||||
Sort
|
||||
Object
|
||||
AngIni:
|
||||
AngEnd:
|
||||
Angle:
|
||||
Radius:
|
||||
Points:
|
||||
Centre
|
||||
ObjName:
|
||||
Points
|
||||
Modify vertices%t|Subdivide edges%x1|Send to a plane%x2|Set LocRotSize%x3
|
||||
Parts
|
||||
Project onto the plane:%t|Global coordinated...%x1|Local coordinated...%x2
|
||||
Act on plane%t|Yz%x1|Zx%x2|Xy%x3
|
||||
In direction%t|X%x1|Y%x2|Z%x3|Ortogonal to plane%x4
|
||||
Get
|
||||
Buffer%t|Copy diference vector%x1|Copy distance%x2|Copy rot diference%x3|Copy LocRotSiz average%x4|Show Buffer in Console%x5
|
||||
Transform LocRotSize%t|Close to active%x1|Randomly%x2
|
||||
Set at fixed distance%x1|Add (absolute displ.)%x2|Multiply (relative displ.)%x3
|
||||
********************
|
||||
Catala
|
||||
Surt del programa
|
||||
Utilitats de...%t|Alinea objectes%x1|Creacio%x2|Edita malles%x3|Edita objetes%x4
|
||||
11
|
||||
Mov
|
||||
Esc
|
||||
Encaixa
|
||||
Abarca
|
||||
Separa
|
||||
Alinea
|
||||
Rotacio
|
||||
Incr.
|
||||
Crea objectes nous
|
||||
Es+
|
||||
Es*
|
||||
Separa entra:%t|Origens%x1|Centres geometrics%x2|Minims%x3|Maxims%x4|Baricentre%x5|Objectes%x6
|
||||
Crear%t|Arc (3 pts.)%x1|Arc (interactiu)%x2|Circumferencia (3 pts.)%x3
|
||||
12
|
||||
Punts
|
||||
Centre
|
||||
Ordre
|
||||
Objecte
|
||||
AngIni:
|
||||
AngFi:
|
||||
Angle:
|
||||
Radi:
|
||||
Punts:
|
||||
Centre
|
||||
Nom:
|
||||
Punts
|
||||
Modifica vertex%t|Subdivideix%x1|Envia a un pla%x2|Aplica LocRotSize%x3
|
||||
Parts
|
||||
Projectar en el pla:%t|Coordenacio global...%x1|Coordenacio local...%x2
|
||||
Actuar sobre el pla%t|Yz%x1|Zx%x2|Xy%x3
|
||||
En la direccio%t|X%x1|Y%x2|Z%x3|Ortogonal al pla%x4
|
||||
Captura
|
||||
Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacio%x3|Copia mitjana LocRotSiz%x4|Veure buffer en consola%x5
|
||||
Transformar LocRotSize%t|Cap al obj. actiu%x1|Aleatoriamente%x2
|
||||
Posar a distancia fixa%x1|Sumar (desp. absolut)%x2|Multiplicar (desp. relatiu)%x3
|
||||
@@ -1,6 +0,0 @@
|
||||
This folder is for automatically saved scripts configuration data.
|
||||
|
||||
To use this feature scripts just need to set a proper Blender.Registry key.
|
||||
|
||||
To know more, check the API Reference doc (specifically the API_related and
|
||||
Registry parts) and the documentation for the "Scripts Config Editor" script.
|
||||
@@ -1,9 +0,0 @@
|
||||
This directory is the default place for scripts to put their data,
|
||||
like internal files needed by the script and its saved configuration.
|
||||
|
||||
Scripts can find the path to this dir using Blender.Get("datadir").
|
||||
Ex:
|
||||
|
||||
import Blender
|
||||
print Blender.Get("datadir")
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
import Blender
|
||||
from Blender.Window import EditMode, GetCursorPos, GetViewQuat
|
||||
import bpy
|
||||
import BPyMessages
|
||||
|
||||
def add_mesh_simple(name, verts, edges, faces):
|
||||
'''
|
||||
Adds a mesh from verts, edges and faces
|
||||
|
||||
name - new object/mesh name
|
||||
verts - list of 3d vectors
|
||||
edges - list of int pairs
|
||||
faces - list of int triplets/quads
|
||||
'''
|
||||
|
||||
scn = bpy.data.scenes.active
|
||||
if scn.lib: return
|
||||
ob_act = scn.objects.active
|
||||
|
||||
is_editmode = EditMode()
|
||||
|
||||
cursor = GetCursorPos()
|
||||
quat = None
|
||||
if is_editmode or Blender.Get('add_view_align'): # Aligning seems odd for editmode, but blender does it, oh well
|
||||
try: quat = Blender.Mathutils.Quaternion(GetViewQuat())
|
||||
except: pass
|
||||
|
||||
# Exist editmode for non mesh types
|
||||
if ob_act and ob_act.type != 'Mesh' and is_editmode:
|
||||
EditMode(0)
|
||||
|
||||
# We are in mesh editmode
|
||||
if EditMode():
|
||||
me = ob_act.getData(mesh=1)
|
||||
|
||||
if me.multires:
|
||||
BPyMessages.Error_NoMeshMultiresEdit()
|
||||
return
|
||||
|
||||
# Add to existing mesh
|
||||
# must exit editmode to modify mesh
|
||||
EditMode(0)
|
||||
|
||||
me.sel = False
|
||||
|
||||
vert_offset = len(me.verts)
|
||||
edge_offset = len(me.edges)
|
||||
face_offset = len(me.faces)
|
||||
|
||||
# transform the verts
|
||||
txmat = Blender.Mathutils.TranslationMatrix(Blender.Mathutils.Vector(cursor))
|
||||
if quat:
|
||||
mat = quat.toMatrix()
|
||||
mat.invert()
|
||||
mat.resize4x4()
|
||||
txmat = mat * txmat
|
||||
|
||||
txmat = txmat * ob_act.matrixWorld.copy().invert()
|
||||
|
||||
|
||||
me.verts.extend(verts)
|
||||
# Transform the verts by the cursor and view rotation
|
||||
me.transform(txmat, selected_only=True)
|
||||
|
||||
if vert_offset:
|
||||
me.edges.extend([[i+vert_offset for i in e] for e in edges])
|
||||
me.faces.extend([[i+vert_offset for i in f] for f in faces])
|
||||
else:
|
||||
# Mesh with no data, unlikely
|
||||
me.edges.extend(edges)
|
||||
me.faces.extend(faces)
|
||||
else:
|
||||
|
||||
# Object mode add new
|
||||
|
||||
me = bpy.data.meshes.new(name)
|
||||
me.verts.extend(verts)
|
||||
me.edges.extend(edges)
|
||||
me.faces.extend(faces)
|
||||
me.sel = True
|
||||
|
||||
# Object creation and location
|
||||
scn.objects.selected = []
|
||||
ob_act = scn.objects.new(me, name)
|
||||
scn.objects.active = ob_act
|
||||
|
||||
if quat:
|
||||
mat = quat.toMatrix()
|
||||
mat.invert()
|
||||
mat.resize4x4()
|
||||
ob_act.setMatrix(mat)
|
||||
|
||||
ob_act.loc = cursor
|
||||
|
||||
me.calcNormals()
|
||||
|
||||
if is_editmode or Blender.Get('add_editmode'):
|
||||
EditMode(1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def write_mesh_script(filepath, me):
|
||||
'''
|
||||
filepath - path to py file
|
||||
me - mesh to write
|
||||
'''
|
||||
|
||||
name = me.name
|
||||
file = open(filepath, 'w')
|
||||
|
||||
file.write('#!BPY\n')
|
||||
file.write('"""\n')
|
||||
file.write('Name: \'%s\'\n' % name)
|
||||
file.write('Blender: 245\n')
|
||||
file.write('Group: \'AddMesh\'\n')
|
||||
file.write('"""\n\n')
|
||||
file.write('import BPyAddMesh\n')
|
||||
file.write('from Blender.Mathutils import Vector\n\n')
|
||||
|
||||
file.write('verts = [\\\n')
|
||||
for v in me.verts:
|
||||
file.write('Vector(%f,%f,%f),\\\n' % tuple(v.co))
|
||||
file.write(']\n')
|
||||
|
||||
file.write('edges = []\n') # TODO, write loose edges
|
||||
|
||||
file.write('faces = [\\\n')
|
||||
for f in me.faces:
|
||||
file.write('%s,\\\n' % str(tuple([v.index for v in f])))
|
||||
file.write(']\n')
|
||||
|
||||
file.write('BPyAddMesh.add_mesh_simple("%s", verts, edges, faces)\n' % name)
|
||||
|
||||
# The script below can make a file from a mesh with teh above function...
|
||||
'''
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Mesh as AddMesh Script'
|
||||
Blender: 242
|
||||
Group: 'Mesh'
|
||||
Tip: ''
|
||||
"""
|
||||
import BPyAddMesh
|
||||
reload(BPyAddMesh)
|
||||
|
||||
import bpy
|
||||
|
||||
def main():
|
||||
# Add error checking
|
||||
scn = bpy.data.scenes.active
|
||||
ob = scn.objects.active
|
||||
me = ob.getData(mesh=1)
|
||||
|
||||
BPyAddMesh.write_mesh_script('/test.py', me)
|
||||
|
||||
main()
|
||||
'''
|
||||
@@ -1,152 +0,0 @@
|
||||
# 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
|
||||
# Version History:
|
||||
# 1.0 original release bakes an armature into a matrix
|
||||
# 1.1 optional params (ACTION_BAKE, ACTION_BAKE_FIRST_FRAME, direct function to key and return the Action
|
||||
|
||||
import Blender
|
||||
from Blender import sys
|
||||
import bpy
|
||||
def getBakedPoseData(ob_arm, start_frame, end_frame, ACTION_BAKE = False, ACTION_BAKE_FIRST_FRAME = True):
|
||||
'''
|
||||
If you are currently getting IPO's this function can be used to
|
||||
ACTION_BAKE==False: return a list of frame aligned bone dictionary's
|
||||
ACTION_BAKE==True: return an action with keys aligned to bone constrained movement
|
||||
if ACTION_BAKE_FIRST_FRAME is not supplied or is true: keys begin at frame 1
|
||||
|
||||
The data in these can be swaped in for the IPO loc and quat
|
||||
|
||||
If you want to bake an action, this is not as hard and the ipo hack can be removed.
|
||||
'''
|
||||
|
||||
# --------------------------------- Dummy Action! Only for this functon
|
||||
backup_action = ob_arm.action
|
||||
backup_frame = Blender.Get('curframe')
|
||||
|
||||
DUMMY_ACTION_NAME = '~DONT_USE~'
|
||||
# Get the dummy action if it has no users
|
||||
try:
|
||||
new_action = bpy.data.actions[DUMMY_ACTION_NAME]
|
||||
if new_action.users:
|
||||
new_action = None
|
||||
except:
|
||||
new_action = None
|
||||
|
||||
if not new_action:
|
||||
new_action = bpy.data.actions.new(DUMMY_ACTION_NAME)
|
||||
new_action.fakeUser = False
|
||||
# ---------------------------------- Done
|
||||
|
||||
Matrix = Blender.Mathutils.Matrix
|
||||
Quaternion = Blender.Mathutils.Quaternion
|
||||
Vector = Blender.Mathutils.Vector
|
||||
POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT]
|
||||
|
||||
# Each dict a frame
|
||||
bake_data = [{} for i in xrange(1+end_frame-start_frame)]
|
||||
|
||||
pose= ob_arm.getPose()
|
||||
armature_data= ob_arm.getData();
|
||||
pose_bones= pose.bones
|
||||
|
||||
# --------------------------------- Build a list of arma data for reuse
|
||||
armature_bone_data = []
|
||||
bones_index = {}
|
||||
for bone_name, rest_bone in armature_data.bones.items():
|
||||
pose_bone = pose_bones[bone_name]
|
||||
rest_matrix = rest_bone.matrix['ARMATURESPACE']
|
||||
rest_matrix_inv = rest_matrix.copy().invert()
|
||||
armature_bone_data.append( [len(bones_index), -1, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, None ])
|
||||
bones_index[bone_name] = len(bones_index)
|
||||
|
||||
# Set the parent ID's
|
||||
for bone_name, pose_bone in pose_bones.items():
|
||||
parent = pose_bone.parent
|
||||
if parent:
|
||||
bone_index= bones_index[bone_name]
|
||||
parent_index= bones_index[parent.name]
|
||||
armature_bone_data[ bone_index ][1]= parent_index
|
||||
# ---------------------------------- Done
|
||||
|
||||
|
||||
|
||||
# --------------------------------- Main loop to collect IPO data
|
||||
frame_index = 0
|
||||
NvideoFrames= end_frame-start_frame
|
||||
for current_frame in xrange(start_frame, end_frame+1):
|
||||
if frame_index==0: start=sys.time()
|
||||
elif frame_index==15: print NvideoFrames*(sys.time()-start),"seconds estimated..." #slows as it grows *3
|
||||
elif frame_index >15:
|
||||
percom= frame_index*100/NvideoFrames
|
||||
print "Frame %i Overall %i percent complete\r" % (current_frame, percom),
|
||||
ob_arm.action = backup_action
|
||||
#pose.update() # not needed
|
||||
Blender.Set('curframe', current_frame)
|
||||
#Blender.Window.RedrawAll()
|
||||
#frame_data = bake_data[frame_index]
|
||||
ob_arm.action = new_action
|
||||
###for i,pose_bone in enumerate(pose_bones):
|
||||
|
||||
for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data:
|
||||
matrix= pose_bone.poseMatrix
|
||||
parent_bone= rest_bone.parent
|
||||
if parent_index != -1:
|
||||
parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix
|
||||
parent_bone_matrix_inv = armature_bone_data[parent_index][5]
|
||||
matrix= matrix * parent_pose_matrix.copy().invert()
|
||||
rest_matrix= rest_matrix * parent_bone_matrix_inv
|
||||
|
||||
matrix=matrix * rest_matrix.copy().invert()
|
||||
pose_bone.quat= matrix.toQuat()
|
||||
pose_bone.loc= matrix.translationPart()
|
||||
if ACTION_BAKE==False:
|
||||
pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1
|
||||
|
||||
# THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE
|
||||
# - use a temp action and bake into that, always at the same frame
|
||||
# so as not to make big IPO's, then collect the result from the IPOs
|
||||
|
||||
# Now get the data from the IPOs
|
||||
if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name)
|
||||
|
||||
loc = Vector()
|
||||
quat = Quaternion()
|
||||
|
||||
for curve in ipo:
|
||||
val = curve.evaluate(1)
|
||||
curve_name= curve.name
|
||||
if curve_name == 'LocX': loc[0] = val
|
||||
elif curve_name == 'LocY': loc[1] = val
|
||||
elif curve_name == 'LocZ': loc[2] = val
|
||||
elif curve_name == 'QuatW': quat[3] = val
|
||||
elif curve_name == 'QuatX': quat[0] = val
|
||||
elif curve_name == 'QuatY': quat[1] = val
|
||||
elif curve_name == 'QuatZ': quat[2] = val
|
||||
|
||||
bake_data[frame_index][bone_name] = loc, quat
|
||||
else:
|
||||
if ACTION_BAKE_FIRST_FRAME: pose_bone.insertKey(ob_arm, frame_index+1, POSE_XFORM)
|
||||
else: pose_bone.insertKey(ob_arm, current_frame , POSE_XFORM)
|
||||
frame_index+=1
|
||||
print "\nBaking Complete."
|
||||
ob_arm.action = backup_action
|
||||
if ACTION_BAKE==False:
|
||||
Blender.Set('curframe', backup_frame)
|
||||
return bake_data
|
||||
elif ACTION_BAKE==True:
|
||||
return new_action
|
||||
else: print "ERROR: Invalid ACTION_BAKE %i sent to BPyArmature" % ACTION_BAKE
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# BPyBlender.py version 0.3 Mar 20, 2005
|
||||
# --------------------------------------------------------------------------
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# Basic set of modules Blender should have in all supported platforms.
|
||||
# The second and third lines are the contents of the Python23.zip file
|
||||
# included with Windows Blender binaries along with zlib.pyd.
|
||||
# Other platforms are assumed to have Python installed.
|
||||
basic_modules = [
|
||||
'Blender',
|
||||
'chunk','colorsys','copy','copy_reg','gzip','os','random','repr','stat',
|
||||
'string','StringIO','types','UserDict','webbrowser', 'zlib', 'math',
|
||||
'BPyBlender', 'BPyRegistry'
|
||||
]
|
||||
@@ -1,79 +0,0 @@
|
||||
# --------------------------------------------------------------------------
|
||||
# BPyImage.py version 0.15
|
||||
# --------------------------------------------------------------------------
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
from Blender import *
|
||||
|
||||
def curve2vecs(ob, WORLDSPACE= True):
|
||||
'''
|
||||
Takes a curve object and retuirns a list of vec lists (polylines)
|
||||
one list per curve
|
||||
|
||||
This is usefull as a way to get a polyline per curve
|
||||
so as not to have to deal with the spline types directly
|
||||
'''
|
||||
if ob.type != 'Curve':
|
||||
raise 'must be a curve object'
|
||||
|
||||
me_dummy = Mesh.New()
|
||||
me_dummy.getFromObject(ob)
|
||||
|
||||
if WORLDSPACE:
|
||||
me_dummy.transform(ob.matrixWorld)
|
||||
|
||||
# build an edge dict
|
||||
edges = {} # should be a set
|
||||
|
||||
def sort_pair(i1, i2):
|
||||
if i1 > i2: return i2, i1
|
||||
else: return i1, i2
|
||||
|
||||
for ed in me_dummy.edges:
|
||||
edges[sort_pair(ed.v1.index,ed.v2.index)] = None # dummy value
|
||||
|
||||
# now set the curves
|
||||
first_time = True
|
||||
|
||||
current_vecs = []
|
||||
vec_list = [current_vecs]
|
||||
|
||||
for v in me_dummy.verts:
|
||||
if first_time:
|
||||
first_time = False
|
||||
current_vecs.append(v.co.copy())
|
||||
last_index = v.index
|
||||
else:
|
||||
index = v.index
|
||||
if edges.has_key(sort_pair(index, last_index)):
|
||||
current_vecs.append( v.co.copy() )
|
||||
else:
|
||||
current_vecs = []
|
||||
vec_list.append(current_vecs)
|
||||
|
||||
last_index = index
|
||||
|
||||
me_dummy.verts = None
|
||||
|
||||
return vec_list
|
||||
|
||||
|
||||
@@ -1,318 +0,0 @@
|
||||
# --------------------------------------------------------------------------
|
||||
# BPyImage.py version 0.15
|
||||
# --------------------------------------------------------------------------
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
#===========================================================================#
|
||||
# Comprehensive image loader, will search and find the image #
|
||||
# Will return a blender image or a new image if the image is missing #
|
||||
#===========================================================================#
|
||||
import bpy
|
||||
from Blender import sys
|
||||
try:
|
||||
import os
|
||||
except:
|
||||
os=None
|
||||
|
||||
#==============================================#
|
||||
# Return directory, where the file is #
|
||||
#==============================================#
|
||||
def stripFile(path):
|
||||
lastSlash = max(path.rfind('\\'), path.rfind('/'))
|
||||
if lastSlash != -1:
|
||||
path = path[:lastSlash]
|
||||
newpath= '%s%s' % (path, sys.sep)
|
||||
else:
|
||||
newpath= path
|
||||
return newpath
|
||||
|
||||
#==============================================#
|
||||
# Strips the slashes from the back of a string #
|
||||
#==============================================#
|
||||
def stripPath(path):
|
||||
return path.split('/')[-1].split('\\')[-1]
|
||||
|
||||
#====================================================#
|
||||
# Strips the prefix off the name before writing #
|
||||
#====================================================#
|
||||
def stripExt(name): # name is a string
|
||||
index = name.rfind('.')
|
||||
if index != -1:
|
||||
return name[ : index ]
|
||||
else:
|
||||
return name
|
||||
|
||||
def getExt(name):
|
||||
index = name.rfind('.')
|
||||
if index != -1:
|
||||
return name[index+1:]
|
||||
return name
|
||||
|
||||
#====================================================#
|
||||
# Adds a slash to the end of a path if its not there #
|
||||
#====================================================#
|
||||
def addSlash(path):
|
||||
if not path:
|
||||
return ''
|
||||
|
||||
elif path.endswith('\\') or path.endswith('/'):
|
||||
return path
|
||||
return path + sys.sep
|
||||
|
||||
|
||||
def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False, CONVERT_CALLBACK=None):
|
||||
'''
|
||||
imagePath: The image filename
|
||||
If a path precedes it, this will be searched as well.
|
||||
|
||||
filePath: is the directory where the image may be located - any file at teh end will be ignored.
|
||||
|
||||
PLACE_HOLDER: if True a new place holder image will be created.
|
||||
this is usefull so later you can relink the image to its original data.
|
||||
|
||||
VERBOSE: If True debug info will be printed.
|
||||
|
||||
RECURSIVE: If True, directories will be recursivly searched.
|
||||
Be carefull with this if you have files in your root directory because it may take a long time.
|
||||
|
||||
CASE_INSENSITIVE: for non win32 systems, find the correct case for the file.
|
||||
|
||||
CONVERT_CALLBACK: a function that takes an existing path and returns a new one.
|
||||
Use this when loading image formats blender may not support, the CONVERT_CALLBACK
|
||||
can take the path for a GIF (for example), convert it to a PNG and return the PNG's path.
|
||||
For formats blender can read, simply return the path that is given.
|
||||
'''
|
||||
|
||||
# VERBOSE = True
|
||||
|
||||
if VERBOSE: print 'img:', imagePath, 'file:', filePath
|
||||
|
||||
if os == None and CASE_INSENSITIVE:
|
||||
CASE_INSENSITIVE = True
|
||||
|
||||
# When we have the file load it with this. try/except niceness.
|
||||
def imageLoad(path):
|
||||
#if path.endswith('\\') or path.endswith('/'):
|
||||
# raise 'INVALID PATH'
|
||||
|
||||
if CONVERT_CALLBACK:
|
||||
path = CONVERT_CALLBACK(path)
|
||||
|
||||
try:
|
||||
img = bpy.data.images.new(filename=path)
|
||||
if VERBOSE: print '\t\tImage loaded "%s"' % path
|
||||
return img
|
||||
except:
|
||||
if VERBOSE:
|
||||
if sys.exists(path): print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path)
|
||||
else: print '\t\tImage not found, making a place holder "%s"' % (path)
|
||||
if PLACE_HOLDER:
|
||||
img= bpy.data.images.new(stripPath(path),4,4)
|
||||
img.filename= path
|
||||
return img #blank image
|
||||
else:
|
||||
return None
|
||||
|
||||
# Image formats blender can read
|
||||
IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal
|
||||
'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try.
|
||||
|
||||
imageFileName = stripPath(imagePath) # image path only
|
||||
imageFileName_lower = imageFileName.lower() # image path only
|
||||
|
||||
if VERBOSE: print '\tSearchingExisting Images for "%s"' % imagePath
|
||||
for i in bpy.data.images:
|
||||
if stripPath(i.filename.lower()) == imageFileName_lower:
|
||||
if VERBOSE: print '\t\tUsing existing image.'
|
||||
return i
|
||||
|
||||
|
||||
if VERBOSE: print '\tAttempting to load "%s"' % imagePath
|
||||
if sys.exists(imagePath):
|
||||
if VERBOSE: print '\t\tFile found where expected "%s".' % imagePath
|
||||
return imageLoad(imagePath)
|
||||
|
||||
|
||||
|
||||
imageFileName_noext = stripExt(imageFileName) # With no extension.
|
||||
imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension.
|
||||
imageFilePath = stripFile(imagePath)
|
||||
|
||||
# Remove relative path from image path
|
||||
if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'):
|
||||
imageFilePath = imageFilePath[2:]
|
||||
|
||||
|
||||
# Attempt to load from obj path.
|
||||
tmpPath = stripFile(filePath) + stripPath(imageFileName)
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tFile found in path (1)"%s".' % tmpPath
|
||||
return imageLoad(tmpPath)
|
||||
|
||||
|
||||
# os needed if we go any further.
|
||||
if not os:
|
||||
if VERBOSE: print '\t\tCreating a placeholder with a face path: "%s".' % imagePath
|
||||
return imageLoad(imagePath) # Will jus treturn a placeholder.
|
||||
|
||||
|
||||
# We have os.
|
||||
# GATHER PATHS.
|
||||
paths = {} # Store possible paths we may use, dict for no doubles.
|
||||
tmpPath = addSlash(sys.expandpath('//')) # Blenders path
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
tmpPath = imageFilePath
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
tmpPath = stripFile(filePath)
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
tmpPath = addSlash(bpy.config.textureDir)
|
||||
if tmpPath and sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
# Add path if relative image patrh was given.
|
||||
tmp_paths= paths.keys()
|
||||
for k in tmp_paths:
|
||||
tmpPath = k + imageFilePath
|
||||
if sys.exists(tmpPath):
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
# DONE
|
||||
#
|
||||
for path, files in paths.iteritems():
|
||||
if sys.exists(path + imageFileName):
|
||||
if VERBOSE: print '\tFound image at path: "%s" file" "%s"' % (path, imageFileName)
|
||||
return imageLoad(path + imageFileName)
|
||||
|
||||
# If the files not there then well do a case insensitive seek.
|
||||
filesOrigCase = files[0]
|
||||
filesLower = files[1]
|
||||
filesLowerNoExt = files[2]
|
||||
|
||||
# We are going to try in index the file directly, if its not there just keep on
|
||||
|
||||
index = None
|
||||
try:
|
||||
# Is it just a case mismatch?
|
||||
index = filesLower.index(imageFileName_lower)
|
||||
except:
|
||||
try:
|
||||
# Have the extensions changed?
|
||||
index = filesLowerNoExt.index(imageFileName_noext_lower)
|
||||
|
||||
ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext.
|
||||
|
||||
# Check that the ext is useable eg- not a 3ds file :)
|
||||
if ext.lower() not in IMAGE_EXT:
|
||||
index = None
|
||||
|
||||
except:
|
||||
index = None
|
||||
|
||||
if index != None:
|
||||
tmpPath = path + filesOrigCase[index]
|
||||
img = imageLoad( tmpPath )
|
||||
if img != None:
|
||||
if VERBOSE: print '\t\tImage Found "%s"' % tmpPath
|
||||
return img
|
||||
|
||||
if RECURSIVE:
|
||||
# IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH.
|
||||
if VERBOSE: print '\t\tImage Not Found in any of the dirs, doing a recusrive search'
|
||||
for path in paths.iterkeys():
|
||||
# Were not going to use files
|
||||
if path == '/' or len(path) == 3 and path[1:] == ':\\':
|
||||
continue
|
||||
|
||||
# print path , 'ASS'
|
||||
|
||||
#------------------
|
||||
# finds the file starting at the root.
|
||||
# def findImage(findRoot, imagePath):
|
||||
#W---------------
|
||||
|
||||
# ROOT, DIRS, FILES
|
||||
pathWalk = os.walk(path)
|
||||
pathList = [True]
|
||||
|
||||
matchList = [] # Store a list of (match, size), choose the biggest.
|
||||
while True:
|
||||
try:
|
||||
pathList = pathWalk.next()
|
||||
except:
|
||||
break
|
||||
|
||||
for file in pathList[2]:
|
||||
file_lower = file.lower()
|
||||
# FOUND A MATCH
|
||||
if (file_lower == imageFileName_lower) or\
|
||||
(stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT):
|
||||
name = pathList[0] + sys.sep + file
|
||||
size = os.path.getsize(name)
|
||||
if VERBOSE: print '\t\t\tfound:', name
|
||||
matchList.append( (name, size) )
|
||||
|
||||
if matchList:
|
||||
# Sort by file size
|
||||
matchList.sort(lambda A, B: cmp(B[1], A[1]) )
|
||||
|
||||
if VERBOSE: print '\t\tFound "%s"' % matchList[0][0]
|
||||
|
||||
# Loop through all we have found
|
||||
img = None
|
||||
for match in matchList:
|
||||
img = imageLoad(match[0]) # 0 - first, 0 - pathname
|
||||
if img != None:
|
||||
break
|
||||
return img
|
||||
|
||||
# No go.
|
||||
if VERBOSE: print '\t\tImage Not Found after looking everywhere! "%s"' % imagePath
|
||||
return imageLoad(imagePath) # Will jus treturn a placeholder.
|
||||
@@ -1,228 +0,0 @@
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender.Mathutils import *
|
||||
|
||||
# ------ Mersenne Twister - start
|
||||
|
||||
# Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura.
|
||||
# Any feedback is very welcome. For any question, comments,
|
||||
# see http://www.math.keio.ac.jp/matumoto/emt.html or email
|
||||
# matumoto@math.keio.ac.jp
|
||||
|
||||
# The link above is dead, this is the new one:
|
||||
# http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/emt.html
|
||||
# And here the license info, from Mr. Matsumoto's site:
|
||||
# Until 2001/4/6, MT had been distributed under GNU Public License,
|
||||
# but after 2001/4/6, we decided to let MT be used for any purpose, including
|
||||
# commercial use. 2002-versions mt19937ar.c, mt19937ar-cok.c are considered
|
||||
# to be usable freely.
|
||||
#
|
||||
# So from the year above (1997), this code is under GPL.
|
||||
|
||||
# Period parameters
|
||||
N = 624
|
||||
M = 397
|
||||
MATRIX_A = 0x9908b0dfL # constant vector a
|
||||
UPPER_MASK = 0x80000000L # most significant w-r bits
|
||||
LOWER_MASK = 0x7fffffffL # least significant r bits
|
||||
|
||||
# Tempering parameters
|
||||
TEMPERING_MASK_B = 0x9d2c5680L
|
||||
TEMPERING_MASK_C = 0xefc60000L
|
||||
|
||||
def TEMPERING_SHIFT_U(y):
|
||||
return (y >> 11)
|
||||
|
||||
def TEMPERING_SHIFT_S(y):
|
||||
return (y << 7)
|
||||
|
||||
def TEMPERING_SHIFT_T(y):
|
||||
return (y << 15)
|
||||
|
||||
def TEMPERING_SHIFT_L(y):
|
||||
return (y >> 18)
|
||||
|
||||
mt = [] # the array for the state vector
|
||||
mti = N+1 # mti==N+1 means mt[N] is not initialized
|
||||
|
||||
# initializing the array with a NONZERO seed
|
||||
def sgenrand(seed):
|
||||
# setting initial seeds to mt[N] using
|
||||
# the generator Line 25 of Table 1 in
|
||||
# [KNUTH 1981, The Art of Computer Programming
|
||||
# Vol. 2 (2nd Ed.), pp102]
|
||||
|
||||
global mt, mti
|
||||
|
||||
mt = []
|
||||
|
||||
mt.append(seed & 0xffffffffL)
|
||||
for i in xrange(1, N + 1):
|
||||
mt.append((69069 * mt[i-1]) & 0xffffffffL)
|
||||
|
||||
mti = i
|
||||
# end sgenrand
|
||||
|
||||
|
||||
def genrand():
|
||||
global mt, mti
|
||||
|
||||
mag01 = [0x0L, MATRIX_A]
|
||||
# mag01[x] = x * MATRIX_A for x=0,1
|
||||
y = 0
|
||||
|
||||
if mti >= N: # generate N words at one time
|
||||
if mti == N+1: # if sgenrand() has not been called,
|
||||
sgenrand(4357) # a default initial seed is used
|
||||
|
||||
for kk in xrange((N-M) + 1):
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK)
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1]
|
||||
|
||||
for kk in xrange(kk, N):
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK)
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1]
|
||||
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK)
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]
|
||||
|
||||
mti = 0
|
||||
|
||||
y = mt[mti]
|
||||
mti += 1
|
||||
y ^= TEMPERING_SHIFT_U(y)
|
||||
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B
|
||||
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C
|
||||
y ^= TEMPERING_SHIFT_L(y)
|
||||
|
||||
return ( float(y) / 0xffffffffL ) # reals
|
||||
|
||||
#------ Mersenne Twister -- end
|
||||
|
||||
|
||||
|
||||
|
||||
""" 2d convexhull
|
||||
Based from Dinu C. Gherman's work,
|
||||
modified for Blender/Mathutils by Campell Barton
|
||||
"""
|
||||
######################################################################
|
||||
# Public interface
|
||||
######################################################################
|
||||
def convexHull(point_list_2d):
|
||||
"""Calculate the convex hull of a set of vectors
|
||||
The vectors can be 3 or 4d but only the Xand Y are used.
|
||||
returns a list of convex hull indicies to the given point list
|
||||
"""
|
||||
|
||||
######################################################################
|
||||
# Helpers
|
||||
######################################################################
|
||||
|
||||
def _myDet(p, q, r):
|
||||
"""Calc. determinant of a special matrix with three 2D points.
|
||||
|
||||
The sign, "-" or "+", determines the side, right or left,
|
||||
respectivly, on which the point r lies, when measured against
|
||||
a directed vector from p to q.
|
||||
"""
|
||||
return (q.x*r.y + p.x*q.y + r.x*p.y) - (q.x*p.y + r.x*q.y + p.x*r.y)
|
||||
|
||||
def _isRightTurn((p, q, r)):
|
||||
"Do the vectors pq:qr form a right turn, or not?"
|
||||
#assert p[0] != q[0] and q[0] != r[0] and p[0] != r[0]
|
||||
if _myDet(p[0], q[0], r[0]) < 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
# Get a local list copy of the points and sort them lexically.
|
||||
points = [(p, i) for i, p in enumerate(point_list_2d)]
|
||||
|
||||
try: points.sort(key = lambda a: (a[0].x, a[0].y))
|
||||
except: points.sort(lambda a,b: cmp((a[0].x, a[0].y), (b[0].x, b[0].y)))
|
||||
|
||||
# Build upper half of the hull.
|
||||
upper = [points[0], points[1]] # cant remove these.
|
||||
for i in xrange(len(points)-2):
|
||||
upper.append(points[i+2])
|
||||
while len(upper) > 2 and not _isRightTurn(upper[-3:]):
|
||||
del upper[-2]
|
||||
|
||||
# Build lower half of the hull.
|
||||
points.reverse()
|
||||
lower = [points.pop(0), points.pop(1)]
|
||||
for p in points:
|
||||
lower.append(p)
|
||||
while len(lower) > 2 and not _isRightTurn(lower[-3:]):
|
||||
del lower[-2]
|
||||
|
||||
# Concatenate both halfs and return.
|
||||
return [p[1] for ls in (upper, lower) for p in ls]
|
||||
|
||||
|
||||
def plane2mat(plane, normalize= False):
|
||||
'''
|
||||
Takes a plane and converts to a matrix
|
||||
points between 0 and 1 are up
|
||||
1 and 2 are right
|
||||
assumes the plane has 90d corners
|
||||
'''
|
||||
cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0
|
||||
|
||||
|
||||
up= cent - ((plane[0]+plane[1])/2.0)
|
||||
right= cent - ((plane[1]+plane[2])/2.0)
|
||||
z= up.cross(right)
|
||||
|
||||
if normalize:
|
||||
up.normalize()
|
||||
right.normalize()
|
||||
z.normalize()
|
||||
|
||||
mat= Matrix(up, right, z)
|
||||
|
||||
# translate
|
||||
mat.resize4x4()
|
||||
tmat= Blender.Mathutils.TranslationMatrix(cent)
|
||||
return mat * tmat
|
||||
|
||||
|
||||
# Used for mesh_solidify.py and mesh_wire.py
|
||||
|
||||
# returns a length from an angle
|
||||
# Imaging a 2d space.
|
||||
# there is a hoz line at Y1 going to inf on both X ends, never moves (LINEA)
|
||||
# down at Y0 is a unit length line point up at (angle) from X0,Y0 (LINEB)
|
||||
# This function returns the length of LINEB at the point it would intersect LINEA
|
||||
# - Use this for working out how long to make the vector - differencing it from surrounding faces,
|
||||
# import math
|
||||
from math import pi, sin, cos, sqrt
|
||||
|
||||
def angleToLength(angle):
|
||||
# Alredy accounted for
|
||||
if angle < 0.000001: return 1.0
|
||||
else: return abs(1.0 / cos(pi*angle/180));
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,652 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# (C) Copyright 2006 MetaVR, Inc.
|
||||
# http://www.metavr.com
|
||||
# Written by Campbell Barton
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
import bpy
|
||||
Vector= Blender.Mathutils.Vector
|
||||
Ang= Blender.Mathutils.AngleBetweenVecs
|
||||
MidpointVecs= Blender.Mathutils.MidpointVecs
|
||||
import BPyMesh
|
||||
|
||||
# If python version is less than 2.4, try to get set stuff from module
|
||||
|
||||
try:
|
||||
set
|
||||
except:
|
||||
try:
|
||||
from sets import Set as set
|
||||
except:
|
||||
set= None
|
||||
|
||||
def uv_key(uv):
|
||||
return round(uv.x, 5), round(uv.y, 5)
|
||||
|
||||
def uv_key_mix(uv1, uv2, w1, w2):
|
||||
# Weighted mix. w1+w2==1.0
|
||||
return w1*uv1[0]+w2*uv2[0], w1*uv1[1]+w2*uv2[1]
|
||||
|
||||
def col_key(col):
|
||||
return col.r, col.g, col.b
|
||||
|
||||
def col_key_mix(col1, col2, w1, w2):
|
||||
# Weighted mix. w1+w2==1.0
|
||||
return int(w1*col1[0] + w2*col2[0]), int(w1*col1[1] + w2*col2[1]), int(w1*col1[2]+col2[2]*w2)
|
||||
|
||||
|
||||
def redux(ob, REDUX=0.5, BOUNDRY_WEIGHT=2.0, REMOVE_DOUBLES=False, FACE_AREA_WEIGHT=1.0, FACE_TRIANGULATE=True, DO_UV=True, DO_VCOL=True, DO_WEIGHTS=True, VGROUP_INF_REDUX= None, VGROUP_INF_WEIGHT=0.5):
|
||||
"""
|
||||
BOUNDRY_WEIGHT - 0 is no boundry weighting. 2.0 will make them twice as unlikely to collapse.
|
||||
FACE_AREA_WEIGHT - 0 is no weight. 1 is normal, 2.0 is higher.
|
||||
"""
|
||||
|
||||
if REDUX<0 or REDUX>1.0:
|
||||
raise 'Error, factor must be between 0 and 1.0'
|
||||
elif not set:
|
||||
raise 'Error, this function requires Python 2.4 or a full install of Python 2.3'
|
||||
|
||||
BOUNDRY_WEIGHT= 1+BOUNDRY_WEIGHT
|
||||
|
||||
""" # DEBUG!
|
||||
if Blender.Get('rt') == 1000:
|
||||
DEBUG=True
|
||||
else:
|
||||
DEBUG= False
|
||||
"""
|
||||
|
||||
me= ob.getData(mesh=1)
|
||||
me.hide= False # unhide all data,.
|
||||
if len(me.faces)<5:
|
||||
return
|
||||
|
||||
|
||||
|
||||
if FACE_TRIANGULATE or REMOVE_DOUBLES:
|
||||
me.sel= True
|
||||
|
||||
if FACE_TRIANGULATE:
|
||||
me.quadToTriangle()
|
||||
|
||||
if REMOVE_DOUBLES:
|
||||
me.remDoubles(0.0001)
|
||||
|
||||
vgroups= me.getVertGroupNames()
|
||||
|
||||
if not me.getVertGroupNames():
|
||||
DO_WEIGHTS= False
|
||||
|
||||
if (VGROUP_INF_REDUX!= None and VGROUP_INF_REDUX not in vgroups) or\
|
||||
VGROUP_INF_WEIGHT==0.0:
|
||||
VGROUP_INF_REDUX= None
|
||||
|
||||
try:
|
||||
VGROUP_INF_REDUX_INDEX= vgroups.index(VGROUP_INF_REDUX)
|
||||
except:
|
||||
VGROUP_INF_REDUX_INDEX= -1
|
||||
|
||||
# del vgroups
|
||||
len_vgroups= len(vgroups)
|
||||
|
||||
|
||||
|
||||
OLD_MESH_MODE= Blender.Mesh.Mode()
|
||||
Blender.Mesh.Mode(Blender.Mesh.SelectModes.VERTEX)
|
||||
|
||||
if DO_UV and not me.faceUV:
|
||||
DO_UV= False
|
||||
|
||||
if DO_VCOL and not me.vertexColors:
|
||||
DO_VCOL = False
|
||||
|
||||
current_face_count= len(me.faces)
|
||||
target_face_count= int(current_face_count * REDUX)
|
||||
# % of the collapseable faces to collapse per pass.
|
||||
#collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster.
|
||||
collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster.
|
||||
|
||||
"""# DEBUG!
|
||||
if DEBUG:
|
||||
COUNT= [0]
|
||||
def rd():
|
||||
if COUNT[0]< 330:
|
||||
COUNT[0]+=1
|
||||
return
|
||||
me.update()
|
||||
Blender.Window.RedrawAll()
|
||||
print 'Press key for next, count "%s"' % COUNT[0]
|
||||
try: input()
|
||||
except KeyboardInterrupt:
|
||||
raise "Error"
|
||||
except:
|
||||
pass
|
||||
|
||||
COUNT[0]+=1
|
||||
"""
|
||||
|
||||
class collapseEdge(object):
|
||||
__slots__ = 'length', 'key', 'faces', 'collapse_loc', 'v1', 'v2','uv1', 'uv2', 'col1', 'col2', 'collapse_weight'
|
||||
def __init__(self, ed):
|
||||
self.init_from_edge(ed) # So we can re-use the classes without using more memory.
|
||||
|
||||
def init_from_edge(self, ed):
|
||||
self.key= ed.key
|
||||
self.length= ed.length
|
||||
self.faces= []
|
||||
self.v1= ed.v1
|
||||
self.v2= ed.v2
|
||||
if DO_UV or DO_VCOL:
|
||||
self.uv1= []
|
||||
self.uv2= []
|
||||
self.col1= []
|
||||
self.col2= []
|
||||
|
||||
# self.collapse_loc= None # new collapse location.
|
||||
# Basic weighting.
|
||||
#self.collapse_weight= self.length * (1+ ((ed.v1.no-ed.v2.no).length**2))
|
||||
self.collapse_weight= 1.0
|
||||
|
||||
def collapse_locations(self, w1, w2):
|
||||
'''
|
||||
Generate a smart location for this edge to collapse to
|
||||
w1 and w2 are vertex location bias
|
||||
'''
|
||||
|
||||
v1co= self.v1.co
|
||||
v2co= self.v2.co
|
||||
v1no= self.v1.no
|
||||
v2no= self.v2.no
|
||||
|
||||
# Basic operation, works fine but not as good as predicting the best place.
|
||||
#between= ((v1co*w1) + (v2co*w2))
|
||||
#self.collapse_loc= between
|
||||
|
||||
# normalize the weights of each vert - se we can use them as scalers.
|
||||
wscale= w1+w2
|
||||
if not wscale: # no scale?
|
||||
w1=w2= 0.5
|
||||
else:
|
||||
w1/=wscale
|
||||
w2/=wscale
|
||||
|
||||
length= self.length
|
||||
between= MidpointVecs(v1co, v2co)
|
||||
|
||||
# Collapse
|
||||
# new_location = between # Replace tricky code below. this code predicts the best collapse location.
|
||||
|
||||
# Make lines at right angles to the normals- these 2 lines will intersect and be
|
||||
# the point of collapsing.
|
||||
|
||||
# Enlarge so we know they intersect: self.length*2
|
||||
cv1= v1no.cross(v1no.cross(v1co-v2co))
|
||||
cv2= v2no.cross(v2no.cross(v2co-v1co))
|
||||
|
||||
# Scale to be less then the edge lengths.
|
||||
cv2.length = cv1.length = 1
|
||||
|
||||
cv1 = cv1 * (length* 0.4)
|
||||
cv2 = cv2 * (length* 0.4)
|
||||
|
||||
smart_offset_loc= between + (cv1 + cv2)
|
||||
|
||||
# Now we need to blend between smart_offset_loc and w1/w2
|
||||
# you see were blending between a vert and the edges midpoint, so we cant use a normal weighted blend.
|
||||
if w1 > 0.5: # between v1 and smart_offset_loc
|
||||
#self.collapse_loc= v1co*(w2+0.5) + smart_offset_loc*(w1-0.5)
|
||||
w2*=2
|
||||
w1= 1-w2
|
||||
new_loc_smart= v1co*w1 + smart_offset_loc*w2
|
||||
else: # w between v2 and smart_offset_loc
|
||||
w1*=2
|
||||
w2= 1-w1
|
||||
new_loc_smart= v2co*w2 + smart_offset_loc*w1
|
||||
|
||||
if new_loc_smart.x != new_loc_smart.x: # NAN LOCATION, revert to between
|
||||
new_loc_smart= None
|
||||
|
||||
return new_loc_smart, between, v1co*0.99999 + v2co*0.00001, v1co*0.00001 + v2co*0.99999
|
||||
|
||||
|
||||
class collapseFace(object):
|
||||
__slots__ = 'verts', 'normal', 'area', 'index', 'orig_uv', 'orig_col', 'uv', 'col' # , 'collapse_edge_count'
|
||||
def __init__(self, f):
|
||||
self.init_from_face(f)
|
||||
|
||||
def init_from_face(self, f):
|
||||
self.verts= f.v
|
||||
self.normal= f.no
|
||||
self.area= f.area
|
||||
self.index= f.index
|
||||
if DO_UV:
|
||||
self.orig_uv= [uv_key(uv) for uv in f.uv]
|
||||
self.uv= f.uv
|
||||
if DO_VCOL:
|
||||
self.orig_col= [col_key(col) for col in f.col]
|
||||
self.col= f.col
|
||||
|
||||
collapse_edges= collapse_faces= None
|
||||
|
||||
# So meshCalcNormals can avoid making a new list all the time.
|
||||
reuse_vertNormals= [ Vector() for v in xrange(len(me.verts)) ]
|
||||
|
||||
while target_face_count <= len(me.faces):
|
||||
BPyMesh.meshCalcNormals(me, reuse_vertNormals)
|
||||
|
||||
if DO_WEIGHTS:
|
||||
#groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
|
||||
groupNames, vWeightList= BPyMesh.meshWeight2List(me)
|
||||
|
||||
# THIS CRASHES? Not anymore.
|
||||
verts= list(me.verts)
|
||||
edges= list(me.edges)
|
||||
faces= list(me.faces)
|
||||
|
||||
# THIS WORKS
|
||||
#verts= me.verts
|
||||
#edges= me.edges
|
||||
#faces= me.faces
|
||||
|
||||
# if DEBUG: DOUBLE_CHECK= [0]*len(verts)
|
||||
me.sel= False
|
||||
|
||||
if not collapse_faces: # Initialize the list.
|
||||
collapse_faces= [collapseFace(f) for f in faces]
|
||||
collapse_edges= [collapseEdge(ed) for ed in edges]
|
||||
else:
|
||||
for i, ed in enumerate(edges):
|
||||
collapse_edges[i].init_from_edge(ed)
|
||||
|
||||
# Strip the unneeded end off the list
|
||||
collapse_edges[i+1:]= []
|
||||
|
||||
for i, f in enumerate(faces):
|
||||
collapse_faces[i].init_from_face(f)
|
||||
|
||||
# Strip the unneeded end off the list
|
||||
collapse_faces[i+1:]= []
|
||||
|
||||
|
||||
collapse_edges_dict= dict( [(ced.key, ced) for ced in collapse_edges] )
|
||||
|
||||
# Store verts edges.
|
||||
vert_ed_users= [[] for i in xrange(len(verts))]
|
||||
for ced in collapse_edges:
|
||||
vert_ed_users[ced.key[0]].append(ced)
|
||||
vert_ed_users[ced.key[1]].append(ced)
|
||||
|
||||
# Store face users
|
||||
vert_face_users= [[] for i in xrange(len(verts))]
|
||||
|
||||
# Have decieded not to use this. area is better.
|
||||
#face_perim= [0.0]* len(me.faces)
|
||||
|
||||
for ii, cfa in enumerate(collapse_faces):
|
||||
for i, v1 in enumerate(cfa.verts):
|
||||
vert_face_users[v1.index].append( (i,cfa) )
|
||||
|
||||
# add the uv coord to the vert
|
||||
v2 = cfa.verts[i-1]
|
||||
i1= v1.index
|
||||
i2= v2.index
|
||||
|
||||
if i1>i2: ced= collapse_edges_dict[i2,i1]
|
||||
else: ced= collapse_edges_dict[i1,i2]
|
||||
|
||||
ced.faces.append(cfa)
|
||||
if DO_UV or DO_VCOL:
|
||||
# if the edge is flipped from its order in the face then we need to flip the order indicies.
|
||||
if cfa.verts[i]==ced.v1: i1,i2 = i, i-1
|
||||
else: i1,i2 = i-1, i
|
||||
|
||||
if DO_UV:
|
||||
ced.uv1.append( cfa.orig_uv[i1] )
|
||||
ced.uv2.append( cfa.orig_uv[i2] )
|
||||
|
||||
if DO_VCOL:
|
||||
ced.col1.append( cfa.orig_col[i1] )
|
||||
ced.col2.append( cfa.orig_col[i2] )
|
||||
|
||||
|
||||
# PERIMITER
|
||||
#face_perim[ii]+= ced.length
|
||||
|
||||
|
||||
|
||||
# How weight the verts by the area of their faces * the normal difference.
|
||||
# when the edge collapses, to vert weights are taken into account
|
||||
|
||||
vert_weights= [0.5] * len(verts)
|
||||
|
||||
for ii, vert_faces in enumerate(vert_face_users):
|
||||
for f in vert_faces:
|
||||
try:
|
||||
no_ang= (Ang(verts[ii].no, f[1].normal)/180) * f[1].area
|
||||
except:
|
||||
no_ang= 1.0
|
||||
|
||||
vert_weights[ii] += no_ang
|
||||
|
||||
# Use a vertex group as a weighting.
|
||||
if VGROUP_INF_REDUX!=None:
|
||||
|
||||
# Get Weights from a vgroup.
|
||||
"""
|
||||
vert_weights_map= [1.0] * len(verts)
|
||||
for i, wd in enumerate(vWeightDict):
|
||||
try: vert_weights_map[i]= 1+(wd[VGROUP_INF_REDUX] * VGROUP_INF_WEIGHT)
|
||||
except: pass
|
||||
"""
|
||||
vert_weights_map= [1+(wl[VGROUP_INF_REDUX_INDEX]*VGROUP_INF_WEIGHT) for wl in vWeightList ]
|
||||
|
||||
|
||||
# BOUNDRY CHECKING AND WEIGHT EDGES. CAN REMOVE
|
||||
# Now we know how many faces link to an edge. lets get all the boundry verts
|
||||
if BOUNDRY_WEIGHT > 0:
|
||||
verts_boundry= [1] * len(verts)
|
||||
#for ed_idxs, faces_and_uvs in edge_faces_and_uvs.iteritems():
|
||||
for ced in collapse_edges:
|
||||
if len(ced.faces) < 2:
|
||||
for key in ced.key: # only ever 2 key indicies.
|
||||
verts_boundry[key]= 2
|
||||
|
||||
for ced in collapse_edges:
|
||||
b1= verts_boundry[ced.key[0]]
|
||||
b2= verts_boundry[ced.key[1]]
|
||||
if b1 != b2:
|
||||
# Edge has 1 boundry and 1 non boundry vert. weight higher
|
||||
ced.collapse_weight= BOUNDRY_WEIGHT
|
||||
#elif b1==b2==2: # if both are on a seam then weigh half as bad.
|
||||
# ced.collapse_weight= ((BOUNDRY_WEIGHT-1)/2) +1
|
||||
# weight the verts by their boundry status
|
||||
del b1
|
||||
del b2
|
||||
|
||||
for ii, boundry in enumerate(verts_boundry):
|
||||
if boundry==2:
|
||||
vert_weights[ii] *= BOUNDRY_WEIGHT
|
||||
|
||||
vert_collapsed= verts_boundry
|
||||
del verts_boundry
|
||||
else:
|
||||
vert_collapsed= [1] * len(verts)
|
||||
|
||||
|
||||
|
||||
|
||||
# Best method, no quick hacks here, Correction. Should be the best but needs tweaks.
|
||||
def ed_set_collapse_error(ced):
|
||||
# Use the vertex weights to bias the new location.
|
||||
new_locs= ced.collapse_locations(vert_weights[ced.key[0]], vert_weights[ced.key[1]])
|
||||
|
||||
|
||||
# Find the connecting faces of the 2 verts.
|
||||
i1, i2= ced.key
|
||||
test_faces= set()
|
||||
for i in (i1,i2): # faster then LC's
|
||||
for f in vert_face_users[i]:
|
||||
test_faces.add(f[1].index)
|
||||
for f in ced.faces:
|
||||
test_faces.remove(f.index)
|
||||
|
||||
|
||||
v1_orig= Vector(ced.v1.co)
|
||||
v2_orig= Vector(ced.v2.co)
|
||||
|
||||
def test_loc(new_loc):
|
||||
'''
|
||||
Takes a location and tests the error without changing anything
|
||||
'''
|
||||
new_weight= ced.collapse_weight
|
||||
ced.v1.co= ced.v2.co= new_loc
|
||||
|
||||
new_nos= [faces[i].no for i in test_faces]
|
||||
|
||||
# So we can compare the befire and after normals
|
||||
ced.v1.co= v1_orig
|
||||
ced.v2.co= v2_orig
|
||||
|
||||
# now see how bad the normals are effected
|
||||
angle_diff= 1.0
|
||||
|
||||
for ii, i in enumerate(test_faces): # local face index, global face index
|
||||
cfa= collapse_faces[i] # this collapse face
|
||||
try:
|
||||
# can use perim, but area looks better.
|
||||
if FACE_AREA_WEIGHT:
|
||||
# Psudo code for wrighting
|
||||
# angle_diff= The before and after angle difference between the collapsed and un-collapsed face.
|
||||
# ... devide by 180 so the value will be between 0 and 1.0
|
||||
# ... add 1 so we can use it as a multiplyer and not make the area have no eefect (below)
|
||||
# area_weight= The faces original area * the area weight
|
||||
# ... add 1.0 so a small area face dosent make the angle_diff have no effect.
|
||||
#
|
||||
# Now multiply - (angle_diff * area_weight)
|
||||
# ... The weight will be a minimum of 1.0 - we need to subtract this so more faces done give the collapse an uneven weighting.
|
||||
|
||||
angle_diff+= ((1+(Ang(cfa.normal, new_nos[ii])/180)) * (1+(cfa.area * FACE_AREA_WEIGHT))) -1 # 4 is how much to influence area
|
||||
else:
|
||||
angle_diff+= (Ang(cfa.normal), new_nos[ii])/180
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# This is very arbirary, feel free to modify
|
||||
try: no_ang= (Ang(ced.v1.no, ced.v2.no)/180) + 1
|
||||
except: no_ang= 2.0
|
||||
|
||||
# do *= because we face the boundry weight to initialize the weight. 1.0 default.
|
||||
new_weight *= ((no_ang * ced.length) * (1-(1/angle_diff)))# / max(len(test_faces), 1)
|
||||
return new_weight
|
||||
# End testloc
|
||||
|
||||
|
||||
# Test the collapse locatons
|
||||
collapse_loc_best= None
|
||||
collapse_weight_best= 1000000000
|
||||
ii= 0
|
||||
for collapse_loc in new_locs:
|
||||
if collapse_loc: # will only ever fail if smart loc is NAN
|
||||
test_weight= test_loc(collapse_loc)
|
||||
if test_weight < collapse_weight_best:
|
||||
iii= ii
|
||||
collapse_weight_best = test_weight
|
||||
collapse_loc_best= collapse_loc
|
||||
ii+=1
|
||||
|
||||
ced.collapse_loc= collapse_loc_best
|
||||
ced.collapse_weight= collapse_weight_best
|
||||
|
||||
|
||||
# are we using a weight map
|
||||
if VGROUP_INF_REDUX:
|
||||
v= vert_weights_map[i1]+vert_weights_map[i2]
|
||||
ced.collapse_weight*= v
|
||||
# End collapse Error
|
||||
|
||||
# We can calculate the weights on __init__ but this is higher qualuity.
|
||||
for ced in collapse_edges:
|
||||
if ced.faces: # dont collapse faceless edges.
|
||||
ed_set_collapse_error(ced)
|
||||
|
||||
# Wont use the function again.
|
||||
del ed_set_collapse_error
|
||||
# END BOUNDRY. Can remove
|
||||
|
||||
# sort by collapse weight
|
||||
try: collapse_edges.sort(key = lambda ced: ced.collapse_weight) # edges will be used for sorting
|
||||
except: collapse_edges.sort(lambda ced1, ced2: cmp(ced1.collapse_weight, ced2.collapse_weight)) # edges will be used for sorting
|
||||
|
||||
|
||||
vert_collapsed= [0]*len(verts)
|
||||
|
||||
collapse_edges_to_collapse= []
|
||||
|
||||
# Make a list of the first half edges we can collapse,
|
||||
# these will better edges to remove.
|
||||
collapse_count=0
|
||||
for ced in collapse_edges:
|
||||
if ced.faces:
|
||||
i1, i2= ced.key
|
||||
# Use vert selections
|
||||
if vert_collapsed[i1] or vert_collapsed[i2]:
|
||||
pass
|
||||
else:
|
||||
# Now we know the verts havnyt been collapsed.
|
||||
vert_collapsed[i2]= vert_collapsed[i1]= 1 # Dont collapse again.
|
||||
collapse_count+=1
|
||||
collapse_edges_to_collapse.append(ced)
|
||||
|
||||
# Get a subset of the entire list- the first "collapse_per_pass", that are best to collapse.
|
||||
if collapse_count > 4:
|
||||
collapse_count = int(collapse_count*collapse_per_pass)
|
||||
else:
|
||||
collapse_count = len(collapse_edges)
|
||||
# We know edge_container_list_collapse can be removed.
|
||||
for ced in collapse_edges_to_collapse:
|
||||
"""# DEBUG!
|
||||
if DEBUG:
|
||||
if DOUBLE_CHECK[ced.v1.index] or\
|
||||
DOUBLE_CHECK[ced.v2.index]:
|
||||
raise 'Error'
|
||||
else:
|
||||
DOUBLE_CHECK[ced.v1.index]=1
|
||||
DOUBLE_CHECK[ced.v2.index]=1
|
||||
|
||||
tmp= (ced.v1.co+ced.v2.co)*0.5
|
||||
Blender.Window.SetCursorPos(tmp.x, tmp.y, tmp.z)
|
||||
Blender.Window.RedrawAll()
|
||||
"""
|
||||
|
||||
# Chech if we have collapsed our quota.
|
||||
collapse_count-=1
|
||||
if not collapse_count:
|
||||
break
|
||||
|
||||
current_face_count -= len(ced.faces)
|
||||
|
||||
# Find and assign the real weights based on collapse loc.
|
||||
|
||||
# Find the weights from the collapse error
|
||||
if DO_WEIGHTS or DO_UV or DO_VCOL:
|
||||
i1, i2= ced.key
|
||||
# Dont use these weights since they may not have been used to make the collapse loc.
|
||||
#w1= vert_weights[i1]
|
||||
#w2= vert_weights[i2]
|
||||
w1= (ced.v2.co-ced.collapse_loc).length
|
||||
w2= (ced.v1.co-ced.collapse_loc).length
|
||||
|
||||
# Normalize weights
|
||||
wscale= w1+w2
|
||||
if not wscale: # no scale?
|
||||
w1=w2= 0.5
|
||||
else:
|
||||
w1/= wscale
|
||||
w2/= wscale
|
||||
|
||||
|
||||
# Interpolate the bone weights.
|
||||
if DO_WEIGHTS:
|
||||
|
||||
# add verts vgroups to eachother
|
||||
wl1= vWeightList[i1] # v1 weight dict
|
||||
wl2= vWeightList[i2] # v2 weight dict
|
||||
for group_index in xrange(len_vgroups):
|
||||
wl1[group_index]= wl2[group_index]= (wl1[group_index]*w1) + (wl2[group_index]*w2)
|
||||
# Done finding weights.
|
||||
|
||||
|
||||
|
||||
if DO_UV or DO_VCOL:
|
||||
# Handel UV's and vert Colors!
|
||||
for v, my_weight, other_weight, edge_my_uvs, edge_other_uvs, edge_my_cols, edge_other_cols in (\
|
||||
(ced.v1, w1, w2, ced.uv1, ced.uv2, ced.col1, ced.col2),\
|
||||
(ced.v2, w2, w1, ced.uv2, ced.uv1, ced.col2, ced.col1)\
|
||||
):
|
||||
uvs_mixed= [ uv_key_mix(edge_my_uvs[iii], edge_other_uvs[iii], my_weight, other_weight) for iii in xrange(len(edge_my_uvs)) ]
|
||||
cols_mixed= [ col_key_mix(edge_my_cols[iii], edge_other_cols[iii], my_weight, other_weight) for iii in xrange(len(edge_my_cols)) ]
|
||||
|
||||
for face_vert_index, cfa in vert_face_users[v.index]:
|
||||
if len(cfa.verts)==3 and cfa not in ced.faces: # if the face is apart of this edge then dont bother finding the uvs since the face will be removed anyway.
|
||||
|
||||
if DO_UV:
|
||||
# UV COORDS
|
||||
uvk= cfa.orig_uv[face_vert_index]
|
||||
try:
|
||||
tex_index= edge_my_uvs.index(uvk)
|
||||
except:
|
||||
tex_index= None
|
||||
""" # DEBUG!
|
||||
if DEBUG:
|
||||
print 'not found', uvk, 'in', edge_my_uvs, 'ed index', ii, '\nwhat about', edge_other_uvs
|
||||
"""
|
||||
if tex_index != None: # This face uses a uv in the collapsing face. - do a merge
|
||||
other_uv= edge_other_uvs[tex_index]
|
||||
uv_vec= cfa.uv[face_vert_index]
|
||||
uv_vec.x, uv_vec.y= uvs_mixed[tex_index]
|
||||
|
||||
# TEXFACE COLORS
|
||||
if DO_VCOL:
|
||||
colk= cfa.orig_col[face_vert_index]
|
||||
try: tex_index= edge_my_cols.index(colk)
|
||||
except: pass
|
||||
if tex_index != None:
|
||||
other_col= edge_other_cols[tex_index]
|
||||
col_ob= cfa.col[face_vert_index]
|
||||
col_ob.r, col_ob.g, col_ob.b= cols_mixed[tex_index]
|
||||
|
||||
# DEBUG! if DEBUG: rd()
|
||||
|
||||
# Execute the collapse
|
||||
ced.v1.sel= ced.v2.sel= True # Select so remove doubles removed the edges and faces that use it
|
||||
ced.v1.co= ced.v2.co= ced.collapse_loc
|
||||
|
||||
# DEBUG! if DEBUG: rd()
|
||||
if current_face_count <= target_face_count:
|
||||
break
|
||||
|
||||
# Copy weights back to the mesh before we remove doubles.
|
||||
if DO_WEIGHTS:
|
||||
#BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
|
||||
BPyMesh.list2MeshWeight(me, groupNames, vWeightList)
|
||||
|
||||
doubles= me.remDoubles(0.0001)
|
||||
current_face_count= len(me.faces)
|
||||
|
||||
if current_face_count <= target_face_count or not doubles: # not doubles shoule never happen.
|
||||
break
|
||||
|
||||
me.update()
|
||||
Blender.Mesh.Mode(OLD_MESH_MODE)
|
||||
|
||||
|
||||
# Example usage
|
||||
def main():
|
||||
Blender.Window.EditMode(0)
|
||||
scn= bpy.data.scenes.active
|
||||
active_ob= scn.objects.active
|
||||
t= Blender.sys.time()
|
||||
redux(active_ob, 0.5)
|
||||
print '%.4f' % (Blender.sys.time()-t)
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
@@ -1,61 +0,0 @@
|
||||
from Blender import Draw, sys
|
||||
def Error_NoMeshSelected():
|
||||
Draw.PupMenu('Error%t|No mesh objects selected')
|
||||
def Error_NoActive():
|
||||
Draw.PupMenu('Error%t|No active object')
|
||||
def Error_NoMeshActive():
|
||||
Draw.PupMenu('Error%t|Active object is not a mesh')
|
||||
def Error_NoMeshUvSelected():
|
||||
Draw.PupMenu('Error%t|No mesh objects with texface selected')
|
||||
def Error_NoMeshUvActive():
|
||||
Draw.PupMenu('Error%t|Active object is not a mesh with texface')
|
||||
def Error_NoMeshMultiresEdit():
|
||||
Draw.PupMenu('Error%t|Unable to complete action with multires enabled')
|
||||
def Error_NoMeshFaces():
|
||||
Draw.PupMenu('Error%t|Mesh has no faces')
|
||||
|
||||
# File I/O messages
|
||||
def Error_NoFile(path):
|
||||
'''True if file missing, False if files there
|
||||
|
||||
Use simply by doing...
|
||||
if Error_NoFile(path): return
|
||||
'''
|
||||
if not sys.exists(sys.expandpath(path)):
|
||||
Draw.PupMenu("Error%t|Can't open file: " + path)
|
||||
return True
|
||||
return False
|
||||
|
||||
def Error_NoDir(path):
|
||||
'''True if dirs missing, False if dirs there
|
||||
|
||||
Use simply by doing...
|
||||
if Error_NoDir(path): return
|
||||
'''
|
||||
if not sys.exists(sys.expandpath(path)):
|
||||
Draw.PupMenu("Error%t|Path does not exist: " + path)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def Warning_MeshDistroyLayers(mesh):
|
||||
'''Returns true if we can continue to edit the mesh, warn when using NMesh'''
|
||||
if len(mesh.getUVLayerNames()) >1 and len(mesh.getColorLayerNames()) >1:
|
||||
return True
|
||||
|
||||
ret = Draw.PupMenu('Warning%t|This script will distroy inactive UV and Color layers, OK?')
|
||||
if ret == -1:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def Warning_SaveOver(path):
|
||||
'''Returns - True to save, False dont save'''
|
||||
if sys.exists(sys.expandpath(path)):
|
||||
ret= Draw.PupMenu('Save over%t|' + path)
|
||||
if ret == -1:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# $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()
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import Blender
|
||||
|
||||
def getObjectArmature(ob):
|
||||
'''
|
||||
This returns the first armature the mesh uses.
|
||||
remember there can be more then 1 armature but most people dont do that.
|
||||
'''
|
||||
if ob.type != 'Mesh':
|
||||
return None
|
||||
|
||||
arm = ob.parent
|
||||
if arm and arm.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE:
|
||||
return arm
|
||||
|
||||
for m in ob.modifiers:
|
||||
if m.type== Blender.Modifier.Types.ARMATURE:
|
||||
arm = m[Blender.Modifier.Settings.OBJECT]
|
||||
if arm:
|
||||
return arm
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def getDerivedObjects(ob, PARTICLES= True):
|
||||
'''
|
||||
Takes an objects and returnes a list of (ob, maxrix4x4) pairs
|
||||
that are derived from this object -
|
||||
This will include the object its self if it would be rendered.
|
||||
all dupli's for eg are not rendered themselves.
|
||||
|
||||
currently supports
|
||||
* dupligroups
|
||||
* dupliverts
|
||||
* dupliframes
|
||||
* static particles as a mesh
|
||||
|
||||
it is possible this function will return an empty list.
|
||||
'''
|
||||
|
||||
ob_mtx_pairs = ob.DupObjects
|
||||
effects= ob.effects
|
||||
|
||||
# Ignore self if were a dupli* or our parent is a duplivert.
|
||||
if ob.enableDupFrames or ob.enableDupGroup or ob.enableDupVerts:
|
||||
pass
|
||||
else:
|
||||
parent= ob.parent
|
||||
if parent and parent.enableDupVerts:
|
||||
pass
|
||||
else:
|
||||
if effects and (not effects[0].flag & Blender.Effect.Flags.EMESH):
|
||||
# Particles mesh wont render
|
||||
pass
|
||||
else:
|
||||
ob_mtx_pairs.append((ob, ob.matrixWorld))
|
||||
|
||||
|
||||
if PARTICLES:
|
||||
type_vec= type(Blender.Mathutils.Vector())
|
||||
type_tp= type((0,0))
|
||||
type_ls= type([])
|
||||
|
||||
# TODO, particles per child object.
|
||||
# TODO Support materials
|
||||
me= Blender.Mesh.New()
|
||||
for eff in effects:
|
||||
par= eff.getParticlesLoc()
|
||||
|
||||
if par:
|
||||
type_par= type(par[0])
|
||||
|
||||
if type_par == type_vec:
|
||||
# point particles
|
||||
me.verts.extend(par)
|
||||
|
||||
elif type_par == type_tp:
|
||||
# edge pairs
|
||||
start_index= len(me.verts)
|
||||
me.verts.extend([v for p in par for v in p])
|
||||
me.edges.extend( [(i, i+1) for i in xrange(start_index, start_index + len(par) - 1 )] )
|
||||
|
||||
elif type_par == type_ls:
|
||||
# lines of edges
|
||||
start_index= len(me.verts)
|
||||
me.verts.extend([v for line in par for v in line])
|
||||
|
||||
edges= []
|
||||
for line in par:
|
||||
edges.extend( [(i,i+1) for i in xrange(start_index, start_index+len(line)-1) ] )
|
||||
start_index+= len(line)
|
||||
|
||||
me.edges.extend(edges)
|
||||
|
||||
if me.verts:
|
||||
# If we have verts, then add the mesh
|
||||
ob_par = Blender.Object.New('Mesh')
|
||||
ob_par.link( me )
|
||||
|
||||
LOOSE= Blender.Mesh.EdgeFlags.LOOSE
|
||||
for ed in me.edges:
|
||||
ed.flag |= LOOSE
|
||||
|
||||
# Particle's are in worldspace so an identity matrix is fine.
|
||||
ob_mtx_pairs.append( (ob_par, Blender.Mathutils.Matrix()) )
|
||||
|
||||
return ob_mtx_pairs
|
||||
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
# --------------------------------------------------------------------------
|
||||
# Module BPyRegistry version 0.1
|
||||
# Helper functions to store / restore configuration data.
|
||||
# --------------------------------------------------------------------------
|
||||
# $Id$
|
||||
#
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
|
||||
#
|
||||
# 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,
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# The Registry is a Python dictionary that is kept in Blender for as long as
|
||||
# the program is running, where scripts can store / restore persistent data
|
||||
# (data that is not lost when the script exits). This module provides
|
||||
# functions to save and restore Registry entries as config data in the
|
||||
# bpydata/config folder. Scripts just need to give an extra parameter to
|
||||
# the Blender.Registry.Get/Set() functions to have their data automatically
|
||||
# saved and restored when needed.
|
||||
#
|
||||
# Note: entries starting with an underscore are not saved, so script authors
|
||||
# can use that fact to define data that is not meant to be stored in a
|
||||
# config file. Example: data to be passed to another script and references to
|
||||
# invalid data, like Blender objects and any function or method.
|
||||
#
|
||||
# Check the Blender.Registry documentation for more information.
|
||||
|
||||
import Blender
|
||||
from Blender import Registry, sys as bsys
|
||||
|
||||
_EXT = '.cfg' # file extension for saved config data
|
||||
|
||||
# limits:
|
||||
#MAX_ITEMS_NUM = 60 # max number of keys per dict and itens per list and tuple
|
||||
#MAX_STR_LEN = 300 # max string length (remember this is just for config data)
|
||||
|
||||
_CFG_DIR = ''
|
||||
if Blender.Get('udatadir'):
|
||||
_CFG_DIR = Blender.sys.join(Blender.Get('udatadir'), 'config')
|
||||
if not _CFG_DIR or not bsys.exists(_CFG_DIR):
|
||||
_CFG_DIR = Blender.sys.join(Blender.Get('datadir'), 'config')
|
||||
if not bsys.exists(_CFG_DIR):
|
||||
_CFG_DIR = ''
|
||||
|
||||
# to compare against, so we don't write to a cvs tree:
|
||||
_CVS_SUBPATH = 'release/scripts/bpydata/config/'
|
||||
if bsys.dirsep == '\\':
|
||||
_CVS_SUBPATH = _CVS_SUBPATH.replace('/', '\\')
|
||||
|
||||
_KEYS = [k for k in Registry.Keys() if k[0] != '_']
|
||||
|
||||
# _ITEMS_NUM = 0
|
||||
|
||||
def _sanitize(o):
|
||||
"Check recursively that all objects are valid, set invalid ones to None"
|
||||
|
||||
# global MAX_ITEMS_NUM, MAX_STR_LEN, _ITEMS_NUM
|
||||
|
||||
valid_types = [int, float, bool, long, type]
|
||||
valid_checked_types = [str, unicode]
|
||||
# Only very simple types are considered valid for configuration data,
|
||||
# functions, methods and Blender objects (use their names instead) aren't.
|
||||
|
||||
t = type(o)
|
||||
|
||||
if t == dict:
|
||||
'''
|
||||
_ITEMS_NUM += len(o)
|
||||
if _ITEMS_NUM > MAX_ITEMS_NUM:
|
||||
return None
|
||||
'''
|
||||
for k, v in o.iteritems():
|
||||
o[k] = _sanitize(v)
|
||||
elif t in [list, tuple]:
|
||||
'''
|
||||
_ITEMS_NUM += len(o)
|
||||
if _ITEMS_NUM > MAX_ITEMS_NUM:
|
||||
return None
|
||||
'''
|
||||
return [_sanitize(i) for i in o]
|
||||
elif t in valid_types:
|
||||
return o
|
||||
elif t in valid_checked_types:
|
||||
'''
|
||||
if len(o) > MAX_STR_LEN:
|
||||
o = o[:MAX_STR_LEN]
|
||||
'''
|
||||
return o
|
||||
else: return None
|
||||
|
||||
return o
|
||||
|
||||
|
||||
def _dict_to_str(name, d):
|
||||
"Return a pretty-print version of the passed dictionary"
|
||||
if not d: return 'None' # d can be None if there was no config to pass
|
||||
|
||||
if name: l = ['%s = {' % name]
|
||||
else: l = ['{']
|
||||
#keys = d.keys()
|
||||
for k,v in d.iteritems(): # .keys()
|
||||
if type(v) == dict:
|
||||
l.append("'%s': %s" % (k, _dict_to_str(None, v)))
|
||||
else:
|
||||
l.append("'%s': %s," % (k, repr(v)))
|
||||
if name: l.append('}')
|
||||
else: l.append('},')
|
||||
return "\n".join(l)
|
||||
|
||||
_HELP_MSG = """
|
||||
Please create a valid scripts config dir tree either by
|
||||
copying release/scripts/ tree to your <blenderhome> dir
|
||||
or by copying release/scripts/bpydata/ tree to a user
|
||||
defined scripts dir that you can set in the
|
||||
User Preferences -> Paths tab -> Python path input box.
|
||||
"""
|
||||
|
||||
def _check_dir():
|
||||
global _CFG_DIR, _CVS_SUBPATH, _HELP_MSG
|
||||
|
||||
if not _CFG_DIR:
|
||||
errmsg = "scripts config dir not found!\n%s" % _HELP_MSG
|
||||
raise IOError, errmsg
|
||||
elif _CFG_DIR.find(_CVS_SUBPATH) > 0:
|
||||
errmsg = """
|
||||
Your scripts config dir:\n%s
|
||||
seems to reside in your local Blender's cvs tree.\n%s""" % (_CFG_DIR, _HELP_MSG)
|
||||
raise SystemError, errmsg
|
||||
else: return
|
||||
|
||||
|
||||
# API:
|
||||
|
||||
BPY_KEY_MISSING = 0
|
||||
BPY_KEY_IN_REGISTRY = 1
|
||||
BPY_KEY_IN_FILE = 2
|
||||
|
||||
def HasConfigData (key):
|
||||
"""
|
||||
Check if the given key exists, either already loaded in the Registry dict or
|
||||
as a file in the script data config dir.
|
||||
@type key: string
|
||||
@param key: a given key name.
|
||||
@returns:
|
||||
- 0: key does not exist;
|
||||
- 1: key exists in the Registry dict only;
|
||||
- 2: key exists as a file only;
|
||||
- 3: key exists in the Registry dict and also as a file.
|
||||
@note: for readability it's better to check against the constant bitmasks
|
||||
BPY_KEY_MISSING = 0, BPY_KEY_IN_REGISTRY = 1 and BPY_KEY_IN_FILE = 2.
|
||||
"""
|
||||
|
||||
fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT))
|
||||
|
||||
result = BPY_KEY_MISSING
|
||||
if key in Registry.Keys(): result |= BPY_KEY_IN_REGISTRY
|
||||
if bsys.exists(fname): result |= BPY_KEY_IN_FILE
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def LoadConfigData (key = None):
|
||||
"""
|
||||
Load config data from file(s) to the Registry dictionary.
|
||||
@type key: string
|
||||
@param key: a given key name. If None (default), all available keys are
|
||||
loaded.
|
||||
@returns: None
|
||||
"""
|
||||
|
||||
_check_dir()
|
||||
|
||||
import os
|
||||
|
||||
if not key:
|
||||
files = \
|
||||
[bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)]
|
||||
else:
|
||||
files = []
|
||||
fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT))
|
||||
if bsys.exists(fname): files.append(fname)
|
||||
|
||||
for p in files:
|
||||
try:
|
||||
f = file(p, 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
if lines: # Lines may be blank
|
||||
mainkey = lines[0].split('=')[0].strip()
|
||||
pysrc = "\n".join(lines)
|
||||
exec(pysrc)
|
||||
exec("Registry.SetKey('%s', %s)" % (str(mainkey), mainkey))
|
||||
except Exception, e:
|
||||
raise Warning(e) # Resend exception as warning
|
||||
|
||||
|
||||
def RemoveConfigData (key = None):
|
||||
"""
|
||||
Remove this key's config file from the <(u)datadir>/config/ folder.
|
||||
@type key: string
|
||||
@param key: the name of the key to be removed. If None (default) all
|
||||
available config files are deleted.
|
||||
"""
|
||||
|
||||
_check_dir()
|
||||
|
||||
if not key:
|
||||
files = \
|
||||
[bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)]
|
||||
else:
|
||||
files = []
|
||||
fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT))
|
||||
if bsys.exists(fname): files.append(fname)
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
for p in files:
|
||||
os.remove(p) # remove the file(s)
|
||||
except Exception, e:
|
||||
raise Warning(e) # Resend exception as warning
|
||||
|
||||
|
||||
def SaveConfigData (key = None):
|
||||
"""
|
||||
Save Registry key(s) as file(s) in the <(u)datadir>/config/ folder.
|
||||
@type key: string
|
||||
@param key: the name of the key to be saved. If None (default) all
|
||||
available keys are saved.
|
||||
"""
|
||||
|
||||
global _KEYS, _CFG_DIR
|
||||
|
||||
_check_dir()
|
||||
|
||||
if key: keys = [key]
|
||||
else: keys = _KEYS
|
||||
|
||||
for mainkey in keys:
|
||||
cfgdict = Registry.GetKey(mainkey).copy()
|
||||
for k in cfgdict: # .keys()
|
||||
if not k or k[0] == '_':
|
||||
del cfgdict[k]
|
||||
|
||||
if not cfgdict: continue
|
||||
|
||||
try:
|
||||
filename = bsys.join(_CFG_DIR, "%s%s" % (mainkey, _EXT))
|
||||
f = file(filename, 'w')
|
||||
output = _dict_to_str(mainkey, _sanitize(cfgdict))
|
||||
if output!='None':
|
||||
f.write(output)
|
||||
f.close()
|
||||
except Exception, e:
|
||||
raise Warning(e) # Resend exception as warning
|
||||
@@ -1,633 +0,0 @@
|
||||
import Blender
|
||||
from Blender import Scene, sys, Camera, Object, Image
|
||||
from Blender.Scene import Render
|
||||
Vector= Blender.Mathutils.Vector
|
||||
|
||||
|
||||
def extFromFormat(format):
|
||||
if format == Render.TARGA: return 'tga'
|
||||
if format == Render.RAWTGA: return 'tga'
|
||||
if format == Render.HDR: return 'hdr'
|
||||
if format == Render.PNG: return 'png'
|
||||
if format == Render.BMP: return 'bmp'
|
||||
if format == Render.JPEG: return 'jpg'
|
||||
if format == Render.HAMX: return 'ham'
|
||||
if format == Render.TIFF: return 'tif'
|
||||
if format == Render.CINEON: return 'cine'
|
||||
if format == Render.DPX: return 'tif'
|
||||
if format == Render.OPENEXR: return 'exr'
|
||||
if format == Render.IRIS: return 'rgb'
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, camera_matrix= None, format=Render.PNG):
|
||||
'''
|
||||
Takes any number of objects and renders them on the z axis, between x:y-0 and x:y-1
|
||||
Usefull for making images from a mesh without per pixel operations
|
||||
- objects must be alredy placed
|
||||
- smooth, anti alias True/False
|
||||
- path renders to a PNG image
|
||||
- alpha weather to render background as alpha
|
||||
|
||||
returns the blender image
|
||||
'''
|
||||
ext = '.' + extFromFormat(format)
|
||||
print ext
|
||||
# remove an extension if its alredy there
|
||||
if path.lower().endswith(ext):
|
||||
path= path[:-4]
|
||||
|
||||
path_expand= sys.expandpath(path) + ext
|
||||
|
||||
print path_expand, 'path'
|
||||
|
||||
# Touch the path
|
||||
try:
|
||||
f= open(path_expand, 'w')
|
||||
f.close()
|
||||
except:
|
||||
raise 'Error, could not write to path:' + path_expand
|
||||
|
||||
|
||||
# RENDER THE FACES.
|
||||
scn= Scene.GetCurrent()
|
||||
render_scn= Scene.New()
|
||||
render_scn.makeCurrent()
|
||||
render_scn.Layers |= (1<<20)-1 # all layers enabled
|
||||
|
||||
# Add objects into the current scene
|
||||
for ob in objects:
|
||||
render_scn.link(ob)
|
||||
|
||||
render_context= render_scn.getRenderingContext()
|
||||
render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path.
|
||||
|
||||
|
||||
render_context.imageSizeX(width)
|
||||
render_context.imageSizeY(height)
|
||||
|
||||
if smooth:
|
||||
render_context.enableOversampling(True)
|
||||
render_context.setOversamplingLevel(16)
|
||||
else:
|
||||
render_context.enableOversampling(False)
|
||||
|
||||
render_context.setRenderWinSize(100)
|
||||
render_context.setImageType(format)
|
||||
render_context.enableExtensions(True)
|
||||
#render_context.enableSky() # No alpha needed.
|
||||
if alpha:
|
||||
render_context.alphaMode= 1
|
||||
render_context.enableRGBAColor()
|
||||
else:
|
||||
render_context.alphaMode= 0
|
||||
render_context.enableRGBColor()
|
||||
|
||||
render_context.displayMode= 0 # fullscreen
|
||||
|
||||
# New camera and object
|
||||
render_cam_data= Camera.New('ortho')
|
||||
render_cam_ob= Object.New('Camera')
|
||||
render_cam_ob.link(render_cam_data)
|
||||
render_scn.link(render_cam_ob)
|
||||
render_scn.objects.camera = render_cam_ob
|
||||
|
||||
render_cam_data.type= 'ortho'
|
||||
|
||||
|
||||
|
||||
# Position the camera
|
||||
if camera_matrix:
|
||||
render_cam_ob.setMatrix(camera_matrix)
|
||||
# We need to take into account the matrix scaling when setting the size
|
||||
# so we get the image bounds defined by the matrix
|
||||
# first get the x and y factors from the matrix.
|
||||
# To render the correct dimensions we must use the aspy and aspy to force the matrix scale to
|
||||
# override the aspect enforced by the width and weight.
|
||||
cent= Vector() * camera_matrix
|
||||
xvec= Vector(1,0,0) * camera_matrix
|
||||
yvec= Vector(0,1,0) * camera_matrix
|
||||
# zvec= Vector(0,0,1) * camera_matrix
|
||||
xlen = (cent-xvec).length # half height of the image
|
||||
ylen = (cent-yvec).length # half width of the image
|
||||
# zlen = (cent-zvec).length # dist to place the camera? - just use the loc for now.
|
||||
|
||||
|
||||
# less then 1.0 portrate, 1.0 or more is portrate
|
||||
asp_cam_mat= xlen/ylen # divide by zero? - possible but scripters fault.
|
||||
asp_image_res= float(width)/height
|
||||
#print 'asp quad', asp_cam_mat, 'asp_image', asp_image_res
|
||||
#print 'xylen', xlen, ylen, 'w/h', width, height
|
||||
# Setup the aspect
|
||||
|
||||
if asp_cam_mat > asp_image_res:
|
||||
# camera is wider then image res.
|
||||
# to make the image wider, reduce the aspy
|
||||
asp_diff= asp_image_res/asp_cam_mat
|
||||
min_asp= asp_diff * 200
|
||||
#print 'X', min_asp
|
||||
|
||||
elif asp_cam_mat < asp_image_res: # asp_cam_mat < asp_image_res
|
||||
# camera is narrower then image res
|
||||
# to make the image narrower, reduce the aspx
|
||||
asp_diff= asp_cam_mat/asp_image_res
|
||||
min_asp= asp_diff * 200
|
||||
#print 'Y', min_asp
|
||||
else:
|
||||
min_asp= 200
|
||||
|
||||
# set the camera size
|
||||
if xlen > ylen:
|
||||
if asp_cam_mat > asp_image_res:
|
||||
render_context.aspectX= 200 # get the greatest range possible
|
||||
render_context.aspectY= min_asp # get the greatest range possible
|
||||
else:
|
||||
render_context.aspectY= 200 # get the greatest range possible
|
||||
render_context.aspectX= min_asp # get the greatest range possible
|
||||
#print "xlen bigger"
|
||||
render_cam_data.scale= xlen * 2
|
||||
elif xlen < ylen:# ylen is bigger
|
||||
if asp_cam_mat > asp_image_res:
|
||||
render_context.aspectX= 200 # get the greatest range possible
|
||||
render_context.aspectY= min_asp # get the greatest range possible
|
||||
else:
|
||||
render_context.aspectY= 200 # get the greatest range possible
|
||||
render_context.aspectX= min_asp # get the greatest range possible
|
||||
#print "ylen bigger"
|
||||
render_cam_data.scale= ylen *2
|
||||
else:
|
||||
# asppect 1:1
|
||||
#print 'NOLEN Bigger'
|
||||
render_cam_data.scale= xlen * 2
|
||||
|
||||
#print xlen, ylen, 'xlen, ylen'
|
||||
|
||||
else:
|
||||
if width > height:
|
||||
min_asp = int((float(height) / width) * 200)
|
||||
render_context.aspectX= min_asp
|
||||
render_context.aspectY= 200
|
||||
else:
|
||||
min_asp = int((float(width) / height) * 200)
|
||||
render_context.aspectX= 200
|
||||
render_context.aspectY= min_asp
|
||||
|
||||
|
||||
render_cam_data.scale= 1.0
|
||||
render_cam_ob.LocZ= 1.0
|
||||
render_cam_ob.LocX= 0.5
|
||||
render_cam_ob.LocY= 0.5
|
||||
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
render_context.render()
|
||||
render_context.saveRenderedImage(path)
|
||||
Render.CloseRenderWindow()
|
||||
#if not B.sys.exists(PREF_IMAGE_PATH_EXPAND):
|
||||
# raise 'Error!!!'
|
||||
|
||||
scn.makeCurrent()
|
||||
Scene.Unlink(render_scn)
|
||||
|
||||
# NOW APPLY THE SAVED IMAGE TO THE FACES!
|
||||
#print PREF_IMAGE_PATH_EXPAND
|
||||
try:
|
||||
target_image= Image.Load(path_expand)
|
||||
return target_image
|
||||
except:
|
||||
raise 'Error: Could not render or load the image at path "%s"' % path_expand
|
||||
return
|
||||
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------#
|
||||
# UV Baking functions, make a picture from mesh(es) uvs #
|
||||
#-----------------------------------------------------------------------------#
|
||||
|
||||
def mesh2uv(me_s, PREF_SEL_FACES_ONLY=False):
|
||||
'''
|
||||
Converts a uv mapped mesh into a 2D Mesh from UV coords.
|
||||
returns a triple -
|
||||
(mesh2d, face_list, col_list)
|
||||
"mesh" is the new mesh and...
|
||||
"face_list" is the faces that were used to make the mesh,
|
||||
"material_list" is a list of materials used by each face
|
||||
These are in alligned with the meshes faces, so you can easerly copy data between them
|
||||
|
||||
'''
|
||||
render_me= Blender.Mesh.New()
|
||||
render_me.verts.extend( [Vector(0,0,0),] ) # 0 vert uv bugm dummy vert
|
||||
face_list= []
|
||||
material_list= []
|
||||
for me in me_s:
|
||||
me_materials= me.materials
|
||||
if PREF_SEL_FACES_ONLY:
|
||||
me_faces= [f for f in me.faces if f.sel]
|
||||
else:
|
||||
me_faces= me.faces
|
||||
|
||||
face_list.extend(me_faces)
|
||||
|
||||
# Dittro
|
||||
if me_materials:
|
||||
material_list.extend([me_materials[f.mat] for f in me_faces])
|
||||
else:
|
||||
material_list.extend([None]*len(me_faces))
|
||||
|
||||
# Now add the verts
|
||||
render_me.verts.extend( [ Vector(uv.x, uv.y, 0) for f in face_list for uv in f.uv ] )
|
||||
|
||||
# Now add the faces
|
||||
tmp_faces= []
|
||||
vert_offset= 1
|
||||
for f in face_list:
|
||||
tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] )
|
||||
vert_offset+= len(f)
|
||||
|
||||
render_me.faces.extend(tmp_faces)
|
||||
render_me.faceUV=1
|
||||
return render_me, face_list, material_list
|
||||
|
||||
|
||||
def uvmesh_apply_normals(render_me, face_list):
|
||||
'''Worldspace normals to vertex colors'''
|
||||
for i, f in enumerate(render_me.faces):
|
||||
face_orig= face_list[i]
|
||||
f_col= f.col
|
||||
for j, v in enumerate(face_orig):
|
||||
c= f_col[j]
|
||||
nx, ny, nz= v.no
|
||||
c.r= int((nx+1)*128)-1
|
||||
c.g= int((ny+1)*128)-1
|
||||
c.b= int((nz+1)*128)-1
|
||||
|
||||
def uvmesh_apply_image(render_me, face_list):
|
||||
'''Copy the image and uvs from the original faces'''
|
||||
for i, f in enumerate(render_me.faces):
|
||||
f.uv= face_list[i].uv
|
||||
f.image= face_list[i].image
|
||||
|
||||
|
||||
def uvmesh_apply_vcol(render_me, face_list):
|
||||
'''Copy the vertex colors from the original faces'''
|
||||
for i, f in enumerate(render_me.faces):
|
||||
face_orig= face_list[i]
|
||||
f_col= f.col
|
||||
for j, c_orig in enumerate(face_orig.col):
|
||||
c= f_col[j]
|
||||
c.r= c_orig.r
|
||||
c.g= c_orig.g
|
||||
c.b= c_orig.b
|
||||
|
||||
def uvmesh_apply_matcol(render_me, material_list):
|
||||
'''Get the vertex colors from the original materials'''
|
||||
for i, f in enumerate(render_me.faces):
|
||||
mat_orig= material_list[i]
|
||||
f_col= f.col
|
||||
if mat_orig:
|
||||
for c in f_col:
|
||||
c.r= int(mat_orig.R*255)
|
||||
c.g= int(mat_orig.G*255)
|
||||
c.b= int(mat_orig.B*255)
|
||||
else:
|
||||
for c in f_col:
|
||||
c.r= 255
|
||||
c.g= 255
|
||||
c.b= 255
|
||||
|
||||
def uvmesh_apply_col(render_me, color):
|
||||
'''Get the vertex colors from the original materials'''
|
||||
r,g,b= color
|
||||
for i, f in enumerate(render_me.faces):
|
||||
f_col= f.col
|
||||
for c in f_col:
|
||||
c.r= r
|
||||
c.g= g
|
||||
c.b= b
|
||||
|
||||
|
||||
def vcol2image(me_s,\
|
||||
PREF_IMAGE_PATH,\
|
||||
PREF_IMAGE_SIZE,\
|
||||
PREF_IMAGE_BLEED,\
|
||||
PREF_IMAGE_SMOOTH,\
|
||||
PREF_IMAGE_WIRE,\
|
||||
PREF_IMAGE_WIRE_INVERT,\
|
||||
PREF_IMAGE_WIRE_UNDERLAY,\
|
||||
PREF_USE_IMAGE,\
|
||||
PREF_USE_VCOL,\
|
||||
PREF_USE_MATCOL,\
|
||||
PREF_USE_NORMAL,\
|
||||
PREF_USE_TEXTURE,\
|
||||
PREF_SEL_FACES_ONLY):
|
||||
|
||||
|
||||
def rnd_mat():
|
||||
render_mat= Blender.Material.New()
|
||||
mode= render_mat.mode
|
||||
|
||||
# Dont use lights ever
|
||||
mode |= Blender.Material.Modes.SHADELESS
|
||||
|
||||
if PREF_IMAGE_WIRE:
|
||||
# Set the wire color
|
||||
if PREF_IMAGE_WIRE_INVERT:
|
||||
render_mat.rgbCol= (1,1,1)
|
||||
else:
|
||||
render_mat.rgbCol= (0,0,0)
|
||||
|
||||
mode |= Blender.Material.Modes.WIRE
|
||||
if PREF_USE_VCOL or PREF_USE_MATCOL or PREF_USE_NORMAL: # both vcol and material color use vertex cols to avoid the 16 max limit in materials
|
||||
mode |= Blender.Material.Modes.VCOL_PAINT
|
||||
if PREF_USE_IMAGE:
|
||||
mode |= Blender.Material.Modes.TEXFACE
|
||||
|
||||
# Copy back the mode
|
||||
render_mat.mode |= mode
|
||||
return render_mat
|
||||
|
||||
|
||||
render_me, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY)
|
||||
|
||||
# Normals exclude all others
|
||||
if PREF_USE_NORMAL:
|
||||
uvmesh_apply_normals(render_me, face_list)
|
||||
else:
|
||||
if PREF_USE_IMAGE:
|
||||
uvmesh_apply_image(render_me, face_list)
|
||||
uvmesh_apply_vcol(render_me, face_list)
|
||||
|
||||
elif PREF_USE_VCOL:
|
||||
uvmesh_apply_vcol(render_me, face_list)
|
||||
|
||||
elif PREF_USE_MATCOL:
|
||||
uvmesh_apply_matcol(render_me, material_list)
|
||||
|
||||
elif PREF_USE_TEXTURE:
|
||||
# if we have more then 16 materials across all the mesh objects were stuffed :/
|
||||
# get unique materials
|
||||
tex_unique_materials= dict([(mat.name, mat) for mat in material_list]).values()[:16] # just incase we have more then 16
|
||||
tex_me= Blender.Mesh.New()
|
||||
|
||||
# Backup the original shadless setting
|
||||
tex_unique_materials_shadeless= [ mat.mode & Blender.Material.Modes.SHADELESS for mat in tex_unique_materials ]
|
||||
|
||||
# Turn shadeless on
|
||||
for mat in tex_unique_materials:
|
||||
mat.mode |= Blender.Material.Modes.SHADELESS
|
||||
|
||||
# Assign materials
|
||||
render_me.materials= tex_unique_materials
|
||||
|
||||
|
||||
|
||||
tex_material_indicies= dict([(mat.name, i) for i, mat in enumerate(tex_unique_materials)])
|
||||
|
||||
tex_me.verts.extend([Vector(0,0,0),]) # dummy
|
||||
tex_me.verts.extend( [ Vector(v.co) for f in face_list for v in f ] )
|
||||
|
||||
# Now add the faces
|
||||
tmp_faces= []
|
||||
vert_offset= 1
|
||||
for f in face_list:
|
||||
tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] )
|
||||
vert_offset+= len(f)
|
||||
|
||||
tex_me.faces.extend(tmp_faces)
|
||||
|
||||
# Now we have the faces, put materials and normal, uvs into the mesh
|
||||
if len(tex_me.faces) != len(face_list):
|
||||
# Should never happen
|
||||
raise "Error face length mismatch"
|
||||
|
||||
# Copy data to the mesh that could be used as texture coords
|
||||
for i, tex_face in enumerate(tex_me.faces):
|
||||
orig_face= face_list[i]
|
||||
|
||||
# Set the material index
|
||||
try:
|
||||
render_face.mat= tex_material_indicies[ material_list[i].name ]
|
||||
except:
|
||||
# more then 16 materials
|
||||
pass
|
||||
|
||||
|
||||
# set the uvs on the texmesh mesh
|
||||
tex_face.uv= orig_face.uv
|
||||
|
||||
orig_face_v= orig_face.v
|
||||
# Set the normals
|
||||
for j, v in enumerate(tex_face):
|
||||
v.no= orig_face_v[j].no
|
||||
|
||||
# Set the texmesh
|
||||
render_me.texMesh= tex_me
|
||||
# END TEXMESH
|
||||
|
||||
|
||||
# Handel adding objects
|
||||
render_ob= Blender.Object.New('Mesh')
|
||||
render_ob.link(render_me)
|
||||
|
||||
if not PREF_USE_TEXTURE: # textures use the original materials
|
||||
render_me.materials= [rnd_mat()]
|
||||
|
||||
|
||||
obs= [render_ob]
|
||||
|
||||
|
||||
if PREF_IMAGE_WIRE_UNDERLAY:
|
||||
# Make another mesh with the material colors
|
||||
render_me_under, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY)
|
||||
|
||||
uvmesh_apply_matcol(render_me_under, material_list)
|
||||
|
||||
# Handel adding objects
|
||||
render_ob= Blender.Object.New('Mesh')
|
||||
render_ob.link(render_me_under)
|
||||
render_ob.LocZ= -0.01
|
||||
|
||||
# Add material and disable wire
|
||||
mat= rnd_mat()
|
||||
mat.rgbCol= 1,1,1
|
||||
mat.alpha= 0.5
|
||||
mat.mode &= ~Blender.Material.Modes.WIRE
|
||||
mat.mode |= Blender.Material.Modes.VCOL_PAINT
|
||||
|
||||
render_me_under.materials= [mat]
|
||||
|
||||
obs.append(render_ob)
|
||||
|
||||
elif PREF_IMAGE_BLEED and not PREF_IMAGE_WIRE:
|
||||
# EVIL BLEEDING CODE!! - Just do copys of the mesh and place behind. Crufty but better then many other methods I have seen. - Cam
|
||||
BLEED_PIXEL= 1.0/PREF_IMAGE_SIZE
|
||||
z_offset= 0.0
|
||||
for i in xrange(PREF_IMAGE_BLEED):
|
||||
for diag1, diag2 in ((-1,-1),(-1,1),(1,-1),(1,1), (1,0), (0,1), (-1,0), (0, -1)): # This line extends the object in 8 different directions, top avoid bleeding.
|
||||
|
||||
render_ob= Blender.Object.New('Mesh')
|
||||
render_ob.link(render_me)
|
||||
|
||||
render_ob.LocX= (i+1)*diag1*BLEED_PIXEL
|
||||
render_ob.LocY= (i+1)*diag2*BLEED_PIXEL
|
||||
render_ob.LocZ= -z_offset
|
||||
|
||||
obs.append(render_ob)
|
||||
z_offset += 0.01
|
||||
|
||||
|
||||
|
||||
image= imageFromObjectsOrtho(obs, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_IMAGE_SIZE, PREF_IMAGE_SMOOTH)
|
||||
|
||||
# Clear from memory as best as we can
|
||||
render_me.verts= None
|
||||
|
||||
if PREF_IMAGE_WIRE_UNDERLAY:
|
||||
render_me_under.verts= None
|
||||
|
||||
if PREF_USE_TEXTURE:
|
||||
tex_me.verts= None
|
||||
# Restire Shadeless setting
|
||||
for i, mat in enumerate(tex_unique_materials):
|
||||
# we know there all on so turn it off of its not set
|
||||
if not tex_unique_materials_shadeless[i]:
|
||||
mat.mode &= ~Blender.Material.Modes.SHADELESS
|
||||
|
||||
return image
|
||||
|
||||
def bakeToPlane(sce, ob_from, width, height, bakemodes, axis='z', margin=0, depth=32):
|
||||
'''
|
||||
Bakes terrain onto a plane from one object
|
||||
sce - scene to bake with
|
||||
ob_from - mesh object
|
||||
width/height - image size
|
||||
bakemodes - list of baking modes to use, Blender.Scene.Render.BakeModes.NORMALS, Blender.Scene.Render.BakeModes.AO ... etc
|
||||
axis - axis to allign the plane to.
|
||||
margin - margin setting for baking.
|
||||
depth - bit depth for the images to bake into, (32 or 128 for floating point images)
|
||||
Example:
|
||||
import Blender
|
||||
from Blender import *
|
||||
import BPyRender
|
||||
sce = Scene.GetCurrent()
|
||||
ob = Object.Get('Plane')
|
||||
BPyRender.bakeToPlane(sce, ob, 512, 512, [Scene.Render.BakeModes.DISPLACEMENT, Scene.Render.BakeModes.NORMALS], 'z', 8 )
|
||||
'''
|
||||
|
||||
# Backup bake settings
|
||||
rend = sce.render
|
||||
BACKUP_bakeDist = rend.bakeDist
|
||||
BACKUP_bakeBias = rend.bakeBias
|
||||
BACKUP_bakeMode = rend.bakeMode
|
||||
BACKUP_bakeClear = rend.bakeClear
|
||||
BACKUP_bakeMargin = rend.bakeMargin
|
||||
BACKUP_bakeToActive = rend.bakeToActive
|
||||
BACKUP_bakeNormalize = rend.bakeNormalize
|
||||
|
||||
# Backup object selection
|
||||
BACKUP_obsel = list(sce.objects.selected)
|
||||
BACKUP_obact = sce.objects.active
|
||||
|
||||
# New bake settings
|
||||
rend.bakeClear = True
|
||||
rend.bakeMargin = margin
|
||||
rend.bakeToActive = True
|
||||
rend.bakeNormalize = True
|
||||
|
||||
# Assume a mesh
|
||||
me_from = ob_from.getData(mesh=1)
|
||||
|
||||
xmin = ymin = zmin = 10000000000
|
||||
xmax = ymax = zmax =-10000000000
|
||||
|
||||
# Dont trust bounding boxes :/
|
||||
#bounds = ob_from.boundingBox
|
||||
#for v in bounds:
|
||||
# x,y,z = tuple(v)
|
||||
mtx = ob_from.matrixWorld
|
||||
for v in me_from.verts:
|
||||
x,y,z = tuple(v.co*mtx)
|
||||
|
||||
xmax = max(xmax, x)
|
||||
ymax = max(ymax, y)
|
||||
zmax = max(zmax, z)
|
||||
|
||||
xmin = min(xmin, x)
|
||||
ymin = min(ymin, y)
|
||||
zmin = min(zmin, z)
|
||||
|
||||
if axis=='x':
|
||||
xmed = (xmin+xmax)/2.0
|
||||
co1 = (xmed, ymin, zmin)
|
||||
co2 = (xmed, ymin, zmax)
|
||||
co3 = (xmed, ymax, zmax)
|
||||
co4 = (xmed, ymax, zmin)
|
||||
rend.bakeDist = ((xmax-xmin)/2.0) + 0.000001 # we need a euler value for this since it
|
||||
elif axis=='y':
|
||||
ymed = (ymin+ymax)/2.0
|
||||
co1 = (xmin, ymed, zmin)
|
||||
co2 = (xmin, ymed, zmax)
|
||||
co3 = (xmax, ymed, zmax)
|
||||
co4 = (xmax, ymed, zmin)
|
||||
rend.bakeDist = ((ymax-ymin)/2.0) + 0.000001
|
||||
elif axis=='z':
|
||||
zmed = (zmin+zmax)/2.0
|
||||
co1 = (xmin, ymin, zmed)
|
||||
co2 = (xmin, ymax, zmed)
|
||||
co3 = (xmax, ymax, zmed)
|
||||
co4 = (xmax, ymin, zmed)
|
||||
rend.bakeDist = ((zmax-zmin)/2.0) + 0.000001
|
||||
else:
|
||||
raise "invalid axis"
|
||||
me_plane = Blender.Mesh.New()
|
||||
ob_plane = Blender.Object.New('Mesh')
|
||||
ob_plane.link(me_plane)
|
||||
sce.objects.link(ob_plane)
|
||||
ob_plane.Layers = ob_from.Layers
|
||||
|
||||
ob_from.sel = 1 # make active
|
||||
sce.objects.active = ob_plane
|
||||
ob_plane.sel = 1
|
||||
|
||||
me_plane.verts.extend([co4, co3, co2, co1])
|
||||
me_plane.faces.extend([(0,1,2,3)])
|
||||
me_plane.faceUV = True
|
||||
me_plane_face = me_plane.faces[0]
|
||||
uvs = me_plane_face.uv
|
||||
uvs[0].x = 0.0; uvs[0].y = 0.0
|
||||
uvs[1].x = 0.0; uvs[1].y = 1.0
|
||||
uvs[2].x = 1.0; uvs[2].y = 1.0
|
||||
uvs[3].x = 1.0; uvs[3].y = 0.0
|
||||
|
||||
images_return = []
|
||||
|
||||
for mode in bakemodes:
|
||||
img = Blender.Image.New('bake', width, height, depth)
|
||||
|
||||
me_plane_face.image = img
|
||||
rend.bakeMode = mode
|
||||
rend.bake()
|
||||
images_return.append( img )
|
||||
|
||||
# Restore bake settings
|
||||
#'''
|
||||
rend.bakeDist = BACKUP_bakeDist
|
||||
rend.bakeBias = BACKUP_bakeBias
|
||||
rend.bakeMode = BACKUP_bakeMode
|
||||
rend.bakeClear = BACKUP_bakeClear
|
||||
rend.bakeMargin = BACKUP_bakeMargin
|
||||
rend.bakeToActive = BACKUP_bakeToActive
|
||||
rend.bakeNormalize = BACKUP_bakeNormalize
|
||||
|
||||
|
||||
# Restore obsel
|
||||
sce.objects.selected = BACKUP_obsel
|
||||
sce.objects.active = BACKUP_obact
|
||||
|
||||
me_plane.verts = None
|
||||
sce.objects.unlink(ob_plane)
|
||||
#'''
|
||||
|
||||
return images_return
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
|
||||
## This was used to make V, but faster not to do all that
|
||||
##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_'
|
||||
##v = range(255)
|
||||
##for c in valid: v.remove(ord(c))
|
||||
v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,58,59,60,61,62,63,64,91,92,93,94,96,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254]
|
||||
invalid = ''.join([chr(i) for i in v])
|
||||
## del v, c, i, valid
|
||||
del v, i
|
||||
|
||||
def cleanName(name):
|
||||
for ch in invalid: name = name.replace(ch, '_')
|
||||
return name
|
||||
|
||||
def caseInsensitivePath(path, RET_FOUND=False):
|
||||
'''
|
||||
Get a case insensitive path on a case sensitive system
|
||||
|
||||
RET_FOUND is for internal use only, to avoid too many calls to os.path.exists
|
||||
# Example usage
|
||||
getCaseInsensitivePath('/hOmE/mE/sOmEpAtH.tXt')
|
||||
'''
|
||||
import os # todo, what happens with no os?
|
||||
|
||||
if os==None:
|
||||
if RET_FOUND: ret = path, True
|
||||
else: ret = path
|
||||
return ret
|
||||
|
||||
if path=='' or os.path.exists(path):
|
||||
if RET_FOUND: ret = path, True
|
||||
else: ret = path
|
||||
return ret
|
||||
|
||||
f = os.path.basename(path) # f may be a directory or a file
|
||||
d = os.path.dirname(path)
|
||||
|
||||
suffix = ''
|
||||
if not f: # dir ends with a slash?
|
||||
if len(d) < len(path):
|
||||
suffix = path[:len(path)-len(d)]
|
||||
|
||||
f = os.path.basename(d)
|
||||
d = os.path.dirname(d)
|
||||
|
||||
if not os.path.exists(d):
|
||||
d, found = caseInsensitivePath(d, True)
|
||||
|
||||
if not found:
|
||||
if RET_FOUND: ret = path, False
|
||||
else: ret = path
|
||||
return ret
|
||||
|
||||
# at this point, the directory exists but not the file
|
||||
|
||||
try: # we are expecting 'd' to be a directory, but it could be a file
|
||||
files = os.listdir(d)
|
||||
except:
|
||||
if RET_FOUND: ret = path, False
|
||||
else: ret = path
|
||||
|
||||
f_low = f.lower()
|
||||
|
||||
try: f_nocase = [fl for fl in files if fl.lower() == f_low][0]
|
||||
except: f_nocase = None
|
||||
|
||||
if f_nocase:
|
||||
if RET_FOUND: ret = os.path.join(d, f_nocase) + suffix, True
|
||||
else: ret = os.path.join(d, f_nocase) + suffix
|
||||
return ret
|
||||
else:
|
||||
if RET_FOUND: ret = path, False
|
||||
else: ret = path
|
||||
return ret # cant find the right one, just return the path as is.
|
||||
@@ -1,814 +0,0 @@
|
||||
"""The BPyTextPlugin Module
|
||||
|
||||
Use get_cached_descriptor(txt) to retrieve information about the script held in
|
||||
the txt Text object.
|
||||
|
||||
Use print_cache_for(txt) to print the information to the console.
|
||||
|
||||
Use line, cursor = current_line(txt) to get the logical line and cursor position
|
||||
|
||||
Use get_targets(line, cursor) to find out what precedes the cursor:
|
||||
aaa.bbb.cc|c.ddd -> ['aaa', 'bbb', 'cc']
|
||||
|
||||
Use resolve_targets(txt, targets) to turn a target list into a usable object if
|
||||
one is found to match.
|
||||
"""
|
||||
|
||||
import bpy, sys, os
|
||||
import __builtin__, tokenize
|
||||
from Blender.sys import time
|
||||
from tokenize import generate_tokens, TokenError, \
|
||||
COMMENT, DEDENT, INDENT, NAME, NEWLINE, NL, STRING, NUMBER
|
||||
|
||||
class Definition:
|
||||
"""Describes a definition or defined object through its name, line number
|
||||
and docstring. This is the base class for definition based descriptors.
|
||||
"""
|
||||
|
||||
def __init__(self, name, lineno, doc=''):
|
||||
self.name = name
|
||||
self.lineno = lineno
|
||||
self.doc = doc
|
||||
|
||||
class ScriptDesc:
|
||||
"""Describes a script through lists of further descriptor objects (classes,
|
||||
defs, vars) and dictionaries to built-in types (imports). If a script has
|
||||
not been fully parsed, its incomplete flag will be set. The time of the last
|
||||
parse is held by the time field and the name of the text object from which
|
||||
it was parsed, the name field.
|
||||
"""
|
||||
|
||||
def __init__(self, name, imports, classes, defs, vars, incomplete=False):
|
||||
self.name = name
|
||||
self.imports = imports
|
||||
self.classes = classes
|
||||
self.defs = defs
|
||||
self.vars = vars
|
||||
self.incomplete = incomplete
|
||||
self.parse_due = 0
|
||||
|
||||
def set_delay(self, delay):
|
||||
self.parse_due = time() + delay
|
||||
|
||||
class ClassDesc(Definition):
|
||||
"""Describes a class through lists of further descriptor objects (defs and
|
||||
vars). The name of the class is held by the name field and the line on
|
||||
which it is defined is held in lineno.
|
||||
"""
|
||||
|
||||
def __init__(self, name, parents, defs, vars, lineno, doc=''):
|
||||
Definition.__init__(self, name, lineno, doc)
|
||||
self.parents = parents
|
||||
self.defs = defs
|
||||
self.vars = vars
|
||||
|
||||
class FunctionDesc(Definition):
|
||||
"""Describes a function through its name and list of parameters (name,
|
||||
params) and the line on which it is defined (lineno).
|
||||
"""
|
||||
|
||||
def __init__(self, name, params, lineno, doc=''):
|
||||
Definition.__init__(self, name, lineno, doc)
|
||||
self.params = params
|
||||
|
||||
class VarDesc(Definition):
|
||||
"""Describes a variable through its name and type (if ascertainable) and the
|
||||
line on which it is defined (lineno). If no type can be determined, type
|
||||
will equal None.
|
||||
"""
|
||||
|
||||
def __init__(self, name, type, lineno):
|
||||
Definition.__init__(self, name, lineno)
|
||||
self.type = type # None for unknown (supports: dict/list/str)
|
||||
|
||||
# Context types
|
||||
CTX_UNSET = -1
|
||||
CTX_NORMAL = 0
|
||||
CTX_SINGLE_QUOTE = 1
|
||||
CTX_DOUBLE_QUOTE = 2
|
||||
CTX_COMMENT = 3
|
||||
|
||||
# Python keywords
|
||||
KEYWORDS = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global',
|
||||
'or', 'with', 'assert', 'else', 'if', 'pass', 'yield',
|
||||
'break', 'except', 'import', 'print', 'class', 'exec', 'in',
|
||||
'raise', 'continue', 'finally', 'is', 'return', 'def', 'for',
|
||||
'lambda', 'try' ]
|
||||
|
||||
# Module file extensions
|
||||
MODULE_EXTS = ['.py', '.pyc', '.pyo', '.pyw', '.pyd']
|
||||
|
||||
ModuleType = type(__builtin__)
|
||||
NoneScriptDesc = ScriptDesc('', dict(), dict(), dict(), dict(), True)
|
||||
|
||||
_modules = {}
|
||||
_modules_updated = 0
|
||||
_parse_cache = dict()
|
||||
|
||||
def _load_module_names():
|
||||
"""Searches the sys.path for module files and lists them, along with
|
||||
sys.builtin_module_names, in the global dict _modules.
|
||||
"""
|
||||
|
||||
global _modules
|
||||
|
||||
for n in sys.builtin_module_names:
|
||||
_modules[n] = None
|
||||
for p in sys.path:
|
||||
if p == '': p = os.curdir
|
||||
if not os.path.isdir(p): continue
|
||||
for f in os.listdir(p):
|
||||
for ext in MODULE_EXTS:
|
||||
if f.endswith(ext):
|
||||
_modules[f[:-len(ext)]] = None
|
||||
break
|
||||
|
||||
_load_module_names()
|
||||
|
||||
def _trim_doc(doc):
|
||||
"""Trims the quotes from a quoted STRING token (eg. "'''text'''" -> "text")
|
||||
"""
|
||||
|
||||
l = len(doc)
|
||||
i = 0
|
||||
while i < l/2 and (doc[i] == "'" or doc[i] == '"'):
|
||||
i += 1
|
||||
return doc[i:-i]
|
||||
|
||||
def resolve_targets(txt, targets):
|
||||
"""Attempts to return a useful object for the locally or externally defined
|
||||
entity described by targets. If the object is local (defined in txt), a
|
||||
Definition instance is returned. If the object is external (imported or
|
||||
built in), the object itself is returned. If no object can be found, None is
|
||||
returned.
|
||||
"""
|
||||
|
||||
count = len(targets)
|
||||
if count==0: return None
|
||||
|
||||
obj = None
|
||||
local = None
|
||||
i = 1
|
||||
|
||||
desc = get_cached_descriptor(txt)
|
||||
b = targets[0].find('(')
|
||||
if b==-1: b = None # Trick to let us use [:b] and get the whole string
|
||||
|
||||
if desc.classes.has_key(targets[0][:b]):
|
||||
local = desc.classes[targets[0][:b]]
|
||||
elif desc.defs.has_key(targets[0]):
|
||||
local = desc.defs[targets[0]]
|
||||
elif desc.vars.has_key(targets[0]):
|
||||
obj = desc.vars[targets[0]].type
|
||||
|
||||
if local:
|
||||
while i < count:
|
||||
b = targets[i].find('(')
|
||||
if b==-1: b = None
|
||||
if hasattr(local, 'classes') and local.classes.has_key(targets[i][:b]):
|
||||
local = local.classes[targets[i][:b]]
|
||||
elif hasattr(local, 'defs') and local.defs.has_key(targets[i]):
|
||||
local = local.defs[targets[i]]
|
||||
elif hasattr(local, 'vars') and local.vars.has_key(targets[i]):
|
||||
obj = local.vars[targets[i]].type
|
||||
local = None
|
||||
i += 1
|
||||
break
|
||||
else:
|
||||
local = None
|
||||
break
|
||||
i += 1
|
||||
|
||||
if local: return local
|
||||
|
||||
if not obj:
|
||||
if desc.imports.has_key(targets[0]):
|
||||
obj = desc.imports[targets[0]]
|
||||
else:
|
||||
builtins = get_builtins()
|
||||
if builtins.has_key(targets[0]):
|
||||
obj = builtins[targets[0]]
|
||||
|
||||
while obj and i < count:
|
||||
if hasattr(obj, targets[i]):
|
||||
obj = getattr(obj, targets[i])
|
||||
else:
|
||||
obj = None
|
||||
break
|
||||
i += 1
|
||||
|
||||
return obj
|
||||
|
||||
def get_cached_descriptor(txt, force_parse=0):
|
||||
"""Returns the cached ScriptDesc for the specified Text object 'txt'. If the
|
||||
script has not been parsed in the last 'period' seconds it will be reparsed
|
||||
to obtain this descriptor.
|
||||
|
||||
Specifying TP_AUTO for the period (default) will choose a period based on the
|
||||
size of the Text object. Larger texts are parsed less often.
|
||||
"""
|
||||
|
||||
global _parse_cache
|
||||
|
||||
parse = True
|
||||
key = hash(txt)
|
||||
if not force_parse and _parse_cache.has_key(key):
|
||||
desc = _parse_cache[key]
|
||||
if desc.parse_due > time():
|
||||
parse = desc.incomplete
|
||||
|
||||
if parse:
|
||||
desc = parse_text(txt)
|
||||
|
||||
return desc
|
||||
|
||||
def parse_text(txt):
|
||||
"""Parses an entire script's text and returns a ScriptDesc instance
|
||||
containing information about the script.
|
||||
|
||||
If the text is not a valid Python script (for example if brackets are left
|
||||
open), parsing may fail to complete. However, if this occurs, no exception
|
||||
is thrown. Instead the returned ScriptDesc instance will have its incomplete
|
||||
flag set and information processed up to this point will still be accessible.
|
||||
"""
|
||||
|
||||
start_time = time()
|
||||
txt.reset()
|
||||
tokens = generate_tokens(txt.readline) # Throws TokenError
|
||||
|
||||
curl, cursor = txt.getCursorPos()
|
||||
linen = curl + 1 # Token line numbers are one-based
|
||||
|
||||
imports = dict()
|
||||
imp_step = 0
|
||||
|
||||
classes = dict()
|
||||
cls_step = 0
|
||||
|
||||
defs = dict()
|
||||
def_step = 0
|
||||
|
||||
vars = dict()
|
||||
var1_step = 0
|
||||
var2_step = 0
|
||||
var3_step = 0
|
||||
var_accum = dict()
|
||||
var_forflag = False
|
||||
|
||||
indent = 0
|
||||
prev_type = -1
|
||||
prev_text = ''
|
||||
incomplete = False
|
||||
|
||||
while True:
|
||||
try:
|
||||
type, text, start, end, line = tokens.next()
|
||||
except StopIteration:
|
||||
break
|
||||
except (TokenError, IndentationError):
|
||||
incomplete = True
|
||||
break
|
||||
|
||||
# Skip all comments and line joining characters
|
||||
if type == COMMENT or type == NL:
|
||||
continue
|
||||
|
||||
#################
|
||||
## Indentation ##
|
||||
#################
|
||||
|
||||
if type == INDENT:
|
||||
indent += 1
|
||||
elif type == DEDENT:
|
||||
indent -= 1
|
||||
|
||||
#########################
|
||||
## Module importing... ##
|
||||
#########################
|
||||
|
||||
imp_store = False
|
||||
|
||||
# Default, look for 'from' or 'import' to start
|
||||
if imp_step == 0:
|
||||
if text == 'from':
|
||||
imp_tmp = []
|
||||
imp_step = 1
|
||||
elif text == 'import':
|
||||
imp_from = None
|
||||
imp_tmp = []
|
||||
imp_step = 2
|
||||
|
||||
# Found a 'from', create imp_from in form '???.???...'
|
||||
elif imp_step == 1:
|
||||
if text == 'import':
|
||||
imp_from = '.'.join(imp_tmp)
|
||||
imp_tmp = []
|
||||
imp_step = 2
|
||||
elif type == NAME:
|
||||
imp_tmp.append(text)
|
||||
elif text != '.':
|
||||
imp_step = 0 # Invalid syntax
|
||||
|
||||
# Found 'import', imp_from is populated or None, create imp_name
|
||||
elif imp_step == 2:
|
||||
if text == 'as':
|
||||
imp_name = '.'.join(imp_tmp)
|
||||
imp_step = 3
|
||||
elif type == NAME or text == '*':
|
||||
imp_tmp.append(text)
|
||||
elif text != '.':
|
||||
imp_name = '.'.join(imp_tmp)
|
||||
imp_symb = imp_name
|
||||
imp_store = True
|
||||
|
||||
# Found 'as', change imp_symb to this value and go back to step 2
|
||||
elif imp_step == 3:
|
||||
if type == NAME:
|
||||
imp_symb = text
|
||||
else:
|
||||
imp_store = True
|
||||
|
||||
# Both imp_name and imp_symb have now been populated so we can import
|
||||
if imp_store:
|
||||
|
||||
# Handle special case of 'import *'
|
||||
if imp_name == '*':
|
||||
parent = get_module(imp_from)
|
||||
imports.update(parent.__dict__)
|
||||
|
||||
else:
|
||||
# Try importing the name as a module
|
||||
try:
|
||||
if imp_from:
|
||||
module = get_module(imp_from +'.'+ imp_name)
|
||||
else:
|
||||
module = get_module(imp_name)
|
||||
except (ImportError, ValueError, AttributeError, TypeError):
|
||||
# Try importing name as an attribute of the parent
|
||||
try:
|
||||
module = __import__(imp_from, globals(), locals(), [imp_name])
|
||||
imports[imp_symb] = getattr(module, imp_name)
|
||||
except (ImportError, ValueError, AttributeError, TypeError):
|
||||
pass
|
||||
else:
|
||||
imports[imp_symb] = module
|
||||
|
||||
# More to import from the same module?
|
||||
if text == ',':
|
||||
imp_tmp = []
|
||||
imp_step = 2
|
||||
else:
|
||||
imp_step = 0
|
||||
|
||||
###################
|
||||
## Class parsing ##
|
||||
###################
|
||||
|
||||
# If we are inside a class then def and variable parsing should be done
|
||||
# for the class. Otherwise the definitions are considered global
|
||||
|
||||
# Look for 'class'
|
||||
if cls_step == 0:
|
||||
if text == 'class':
|
||||
cls_name = None
|
||||
cls_lineno = start[0]
|
||||
cls_indent = indent
|
||||
cls_step = 1
|
||||
|
||||
# Found 'class', look for cls_name followed by '(' parents ')'
|
||||
elif cls_step == 1:
|
||||
if not cls_name:
|
||||
if type == NAME:
|
||||
cls_name = text
|
||||
cls_sline = False
|
||||
cls_parents = dict()
|
||||
cls_defs = dict()
|
||||
cls_vars = dict()
|
||||
elif type == NAME:
|
||||
if classes.has_key(text):
|
||||
parent = classes[text]
|
||||
cls_parents[text] = parent
|
||||
cls_defs.update(parent.defs)
|
||||
cls_vars.update(parent.vars)
|
||||
elif text == ':':
|
||||
cls_step = 2
|
||||
|
||||
# Found 'class' name ... ':', now check if it's a single line statement
|
||||
elif cls_step == 2:
|
||||
if type == NEWLINE:
|
||||
cls_sline = False
|
||||
else:
|
||||
cls_sline = True
|
||||
cls_doc = ''
|
||||
cls_step = 3
|
||||
|
||||
elif cls_step == 3:
|
||||
if not cls_doc and type == STRING:
|
||||
cls_doc = _trim_doc(text)
|
||||
if cls_sline:
|
||||
if type == NEWLINE:
|
||||
classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
|
||||
cls_step = 0
|
||||
else:
|
||||
if type == DEDENT and indent <= cls_indent:
|
||||
classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
|
||||
cls_step = 0
|
||||
|
||||
#################
|
||||
## Def parsing ##
|
||||
#################
|
||||
|
||||
# Look for 'def'
|
||||
if def_step == 0:
|
||||
if text == 'def':
|
||||
def_name = None
|
||||
def_lineno = start[0]
|
||||
def_step = 1
|
||||
|
||||
# Found 'def', look for def_name followed by '('
|
||||
elif def_step == 1:
|
||||
if type == NAME:
|
||||
def_name = text
|
||||
def_params = []
|
||||
elif def_name and text == '(':
|
||||
def_step = 2
|
||||
|
||||
# Found 'def' name '(', now identify the parameters upto ')'
|
||||
# TODO: Handle ellipsis '...'
|
||||
elif def_step == 2:
|
||||
if type == NAME:
|
||||
def_params.append(text)
|
||||
elif text == ':':
|
||||
def_step = 3
|
||||
|
||||
# Found 'def' ... ':', now check if it's a single line statement
|
||||
elif def_step == 3:
|
||||
if type == NEWLINE:
|
||||
def_sline = False
|
||||
else:
|
||||
def_sline = True
|
||||
def_doc = ''
|
||||
def_step = 4
|
||||
|
||||
elif def_step == 4:
|
||||
if type == STRING:
|
||||
def_doc = _trim_doc(text)
|
||||
newdef = None
|
||||
if def_sline:
|
||||
if type == NEWLINE:
|
||||
newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
|
||||
else:
|
||||
if type == NAME:
|
||||
newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
|
||||
if newdef:
|
||||
if cls_step > 0: # Parsing a class
|
||||
cls_defs[def_name] = newdef
|
||||
else:
|
||||
defs[def_name] = newdef
|
||||
def_step = 0
|
||||
|
||||
##########################
|
||||
## Variable assignation ##
|
||||
##########################
|
||||
|
||||
if cls_step > 0: # Parsing a class
|
||||
# Look for 'self.???'
|
||||
if var1_step == 0:
|
||||
if text == 'self':
|
||||
var1_step = 1
|
||||
elif var1_step == 1:
|
||||
if text == '.':
|
||||
var_name = None
|
||||
var1_step = 2
|
||||
else:
|
||||
var1_step = 0
|
||||
elif var1_step == 2:
|
||||
if type == NAME:
|
||||
var_name = text
|
||||
if cls_vars.has_key(var_name):
|
||||
var_step = 0
|
||||
else:
|
||||
var1_step = 3
|
||||
elif var1_step == 3:
|
||||
if text == '=':
|
||||
var1_step = 4
|
||||
elif text != ',':
|
||||
var1_step = 0
|
||||
elif var1_step == 4:
|
||||
var_type = None
|
||||
if type == NUMBER:
|
||||
close = end[1]
|
||||
if text.find('.') != -1: var_type = float
|
||||
else: var_type = int
|
||||
elif type == STRING:
|
||||
close = end[1]
|
||||
var_type = str
|
||||
elif text == '[':
|
||||
close = line.find(']', end[1])
|
||||
var_type = list
|
||||
elif text == '(':
|
||||
close = line.find(')', end[1])
|
||||
var_type = tuple
|
||||
elif text == '{':
|
||||
close = line.find('}', end[1])
|
||||
var_type = dict
|
||||
elif text == 'dict':
|
||||
close = line.find(')', end[1])
|
||||
var_type = dict
|
||||
if var_type and close+1 < len(line):
|
||||
if line[close+1] != ' ' and line[close+1] != '\t':
|
||||
var_type = None
|
||||
cls_vars[var_name] = VarDesc(var_name, var_type, start[0])
|
||||
var1_step = 0
|
||||
|
||||
elif def_step > 0: # Parsing a def
|
||||
# Look for 'global ???[,???]'
|
||||
if var2_step == 0:
|
||||
if text == 'global':
|
||||
var2_step = 1
|
||||
elif var2_step == 1:
|
||||
if type == NAME:
|
||||
if not vars.has_key(text):
|
||||
vars[text] = VarDesc(text, None, start[0])
|
||||
elif text != ',' and type != NL:
|
||||
var2_step == 0
|
||||
|
||||
else: # In global scope
|
||||
if var3_step == 0:
|
||||
# Look for names
|
||||
if text == 'for':
|
||||
var_accum = dict()
|
||||
var_forflag = True
|
||||
elif text == '=' or (var_forflag and text == 'in'):
|
||||
var_forflag = False
|
||||
var3_step = 1
|
||||
elif type == NAME:
|
||||
if prev_text != '.' and not vars.has_key(text):
|
||||
var_accum[text] = VarDesc(text, None, start[0])
|
||||
elif not text in [',', '(', ')', '[', ']']:
|
||||
var_accum = dict()
|
||||
var_forflag = False
|
||||
elif var3_step == 1:
|
||||
if len(var_accum) != 1:
|
||||
var_type = None
|
||||
vars.update(var_accum)
|
||||
else:
|
||||
var_name = var_accum.keys()[0]
|
||||
var_type = None
|
||||
if type == NUMBER:
|
||||
if text.find('.') != -1: var_type = float
|
||||
else: var_type = int
|
||||
elif type == STRING: var_type = str
|
||||
elif text == '[': var_type = list
|
||||
elif text == '(': var_type = tuple
|
||||
elif text == '{': var_type = dict
|
||||
vars[var_name] = VarDesc(var_name, var_type, start[0])
|
||||
var3_step = 0
|
||||
|
||||
#######################
|
||||
## General utilities ##
|
||||
#######################
|
||||
|
||||
prev_type = type
|
||||
prev_text = text
|
||||
|
||||
desc = ScriptDesc(txt.name, imports, classes, defs, vars, incomplete)
|
||||
desc.set_delay(10 * (time()-start_time) + 0.05)
|
||||
|
||||
global _parse_cache
|
||||
_parse_cache[hash(txt)] = desc
|
||||
return desc
|
||||
|
||||
def get_modules(since=1):
|
||||
"""Returns the set of built-in modules and any modules that have been
|
||||
imported into the system upto 'since' seconds ago.
|
||||
"""
|
||||
|
||||
global _modules, _modules_updated
|
||||
|
||||
t = time()
|
||||
if _modules_updated < t - since:
|
||||
_modules.update(sys.modules)
|
||||
_modules_updated = t
|
||||
return _modules.keys()
|
||||
|
||||
def suggest_cmp(x, y):
|
||||
"""Use this method when sorting a list of suggestions.
|
||||
"""
|
||||
|
||||
return cmp(x[0].upper(), y[0].upper())
|
||||
|
||||
def get_module(name):
|
||||
"""Returns the module specified by its name. The module itself is imported
|
||||
by this method and, as such, any initialization code will be executed.
|
||||
"""
|
||||
|
||||
mod = __import__(name)
|
||||
components = name.split('.')
|
||||
for comp in components[1:]:
|
||||
mod = getattr(mod, comp)
|
||||
return mod
|
||||
|
||||
def type_char(v):
|
||||
"""Returns the character used to signify the type of a variable. Use this
|
||||
method to identify the type character for an item in a suggestion list.
|
||||
|
||||
The following values are returned:
|
||||
'm' if the parameter is a module
|
||||
'f' if the parameter is callable
|
||||
'v' if the parameter is variable or otherwise indeterminable
|
||||
|
||||
"""
|
||||
|
||||
if isinstance(v, ModuleType):
|
||||
return 'm'
|
||||
elif callable(v):
|
||||
return 'f'
|
||||
else:
|
||||
return 'v'
|
||||
|
||||
def get_context(txt):
|
||||
"""Establishes the context of the cursor in the given Blender Text object
|
||||
|
||||
Returns one of:
|
||||
CTX_NORMAL - Cursor is in a normal context
|
||||
CTX_SINGLE_QUOTE - Cursor is inside a single quoted string
|
||||
CTX_DOUBLE_QUOTE - Cursor is inside a double quoted string
|
||||
CTX_COMMENT - Cursor is inside a comment
|
||||
|
||||
"""
|
||||
|
||||
l, cursor = txt.getCursorPos()
|
||||
lines = txt.asLines(0, l+1)
|
||||
|
||||
# FIXME: This method is too slow in large files for it to be called as often
|
||||
# as it is. So for lines below the 1000th line we do this... (quorn)
|
||||
if l > 1000: return CTX_NORMAL
|
||||
|
||||
# Detect context (in string or comment)
|
||||
in_str = CTX_NORMAL
|
||||
for line in lines:
|
||||
if l == 0:
|
||||
end = cursor
|
||||
else:
|
||||
end = len(line)
|
||||
l -= 1
|
||||
|
||||
# Comments end at new lines
|
||||
if in_str == CTX_COMMENT:
|
||||
in_str = CTX_NORMAL
|
||||
|
||||
for i in range(end):
|
||||
if in_str == 0:
|
||||
if line[i] == "'": in_str = CTX_SINGLE_QUOTE
|
||||
elif line[i] == '"': in_str = CTX_DOUBLE_QUOTE
|
||||
elif line[i] == '#': in_str = CTX_COMMENT
|
||||
else:
|
||||
if in_str == CTX_SINGLE_QUOTE:
|
||||
if line[i] == "'":
|
||||
in_str = CTX_NORMAL
|
||||
# In again if ' escaped, out again if \ escaped, and so on
|
||||
for a in range(i-1, -1, -1):
|
||||
if line[a] == '\\': in_str = 1-in_str
|
||||
else: break
|
||||
elif in_str == CTX_DOUBLE_QUOTE:
|
||||
if line[i] == '"':
|
||||
in_str = CTX_NORMAL
|
||||
# In again if " escaped, out again if \ escaped, and so on
|
||||
for a in range(i-1, -1, -1):
|
||||
if line[i-a] == '\\': in_str = 2-in_str
|
||||
else: break
|
||||
|
||||
return in_str
|
||||
|
||||
def current_line(txt):
|
||||
"""Extracts the Python script line at the cursor in the Blender Text object
|
||||
provided and cursor position within this line as the tuple pair (line,
|
||||
cursor).
|
||||
"""
|
||||
|
||||
lineindex, cursor = txt.getCursorPos()
|
||||
lines = txt.asLines()
|
||||
line = lines[lineindex]
|
||||
|
||||
# Join previous lines to this line if spanning
|
||||
i = lineindex - 1
|
||||
while i > 0:
|
||||
earlier = lines[i].rstrip()
|
||||
if earlier.endswith('\\'):
|
||||
line = earlier[:-1] + ' ' + line
|
||||
cursor += len(earlier)
|
||||
i -= 1
|
||||
|
||||
# Join later lines while there is an explicit joining character
|
||||
i = lineindex
|
||||
while i < len(lines)-1 and lines[i].rstrip().endswith('\\'):
|
||||
later = lines[i+1].strip()
|
||||
line = line + ' ' + later[:-1]
|
||||
i += 1
|
||||
|
||||
return line, cursor
|
||||
|
||||
def get_targets(line, cursor):
|
||||
"""Parses a period separated string of valid names preceding the cursor and
|
||||
returns them as a list in the same order.
|
||||
"""
|
||||
|
||||
brk = 0
|
||||
targets = []
|
||||
j = cursor
|
||||
i = j-1
|
||||
while i >= 0:
|
||||
if line[i] == ')': brk += 1
|
||||
elif brk:
|
||||
if line[i] == '(': brk -= 1
|
||||
else:
|
||||
if line[i] == '.':
|
||||
targets.insert(0, line[i+1:j]); j=i
|
||||
elif not (line[i].isalnum() or line[i] == '_' or line[i] == '.'):
|
||||
break
|
||||
i -= 1
|
||||
targets.insert(0, line[i+1:j])
|
||||
return targets
|
||||
|
||||
def get_defs(txt):
|
||||
"""Returns a dictionary which maps definition names in the source code to
|
||||
a list of their parameter names.
|
||||
|
||||
The line 'def doit(one, two, three): print one' for example, results in the
|
||||
mapping 'doit' : [ 'one', 'two', 'three' ]
|
||||
"""
|
||||
|
||||
return get_cached_descriptor(txt).defs
|
||||
|
||||
def get_vars(txt):
|
||||
"""Returns a dictionary of variable names found in the specified Text
|
||||
object. This method locates all names followed directly by an equal sign:
|
||||
'a = ???' or indirectly as part of a tuple/list assignment or inside a
|
||||
'for ??? in ???:' block.
|
||||
"""
|
||||
|
||||
return get_cached_descriptor(txt).vars
|
||||
|
||||
def get_imports(txt):
|
||||
"""Returns a dictionary which maps symbol names in the source code to their
|
||||
respective modules.
|
||||
|
||||
The line 'from Blender import Text as BText' for example, results in the
|
||||
mapping 'BText' : <module 'Blender.Text' (built-in)>
|
||||
|
||||
Note that this method imports the modules to provide this mapping as as such
|
||||
will execute any initilization code found within.
|
||||
"""
|
||||
|
||||
return get_cached_descriptor(txt).imports
|
||||
|
||||
def get_builtins():
|
||||
"""Returns a dictionary of built-in modules, functions and variables."""
|
||||
|
||||
return __builtin__.__dict__
|
||||
|
||||
|
||||
#################################
|
||||
## Debugging utility functions ##
|
||||
#################################
|
||||
|
||||
def print_cache_for(txt, period=sys.maxint):
|
||||
"""Prints out the data cached for a given Text object. If no period is
|
||||
given the text will not be reparsed and the cached version will be returned.
|
||||
Otherwise if the period has expired the text will be reparsed.
|
||||
"""
|
||||
|
||||
desc = get_cached_descriptor(txt, period)
|
||||
print '================================================'
|
||||
print 'Name:', desc.name, '('+str(hash(txt))+')'
|
||||
print '------------------------------------------------'
|
||||
print 'Defs:'
|
||||
for name, ddesc in desc.defs.items():
|
||||
print ' ', name, ddesc.params, ddesc.lineno
|
||||
print ' ', ddesc.doc
|
||||
print '------------------------------------------------'
|
||||
print 'Vars:'
|
||||
for name, vdesc in desc.vars.items():
|
||||
print ' ', name, vdesc.type, vdesc.lineno
|
||||
print '------------------------------------------------'
|
||||
print 'Imports:'
|
||||
for name, item in desc.imports.items():
|
||||
print ' ', name.ljust(15), item
|
||||
print '------------------------------------------------'
|
||||
print 'Classes:'
|
||||
for clsnme, clsdsc in desc.classes.items():
|
||||
print ' *********************************'
|
||||
print ' Name:', clsnme
|
||||
print ' ', clsdsc.doc
|
||||
print ' ---------------------------------'
|
||||
print ' Defs:'
|
||||
for name, ddesc in clsdsc.defs.items():
|
||||
print ' ', name, ddesc.params, ddesc.lineno
|
||||
print ' ', ddesc.doc
|
||||
print ' ---------------------------------'
|
||||
print ' Vars:'
|
||||
for name, vdesc in clsdsc.vars.items():
|
||||
print ' ', name, vdesc.type, vdesc.lineno
|
||||
print ' *********************************'
|
||||
print '================================================'
|
||||
@@ -1,206 +0,0 @@
|
||||
import Blender
|
||||
from Blender import Mathutils, Window, Scene, Draw, Mesh
|
||||
from Blender.Mathutils import Matrix, Vector, Intersect
|
||||
|
||||
# DESCRIPTION:
|
||||
# screen_x, screen_y the origin point of the pick ray
|
||||
# it is either the mouse location
|
||||
# localMatrix is used if you want to have the returned values in an objects localspace.
|
||||
# this is usefull when dealing with an objects data such as verts.
|
||||
# or if useMid is true, the midpoint of the current 3dview
|
||||
# returns
|
||||
# Origin - the origin point of the pick ray
|
||||
# Direction - the direction vector of the pick ray
|
||||
# in global coordinates
|
||||
epsilon = 1e-3 # just a small value to account for floating point errors
|
||||
|
||||
def mouseViewRay(screen_x, screen_y, localMatrix=None, useMid = False):
|
||||
|
||||
# Constant function variables
|
||||
p = mouseViewRay.p
|
||||
d = mouseViewRay.d
|
||||
|
||||
for win3d in Window.GetScreenInfo(Window.Types.VIEW3D): # we search all 3dwins for the one containing the point (screen_x, screen_y) (could be the mousecoords for example)
|
||||
win_min_x, win_min_y, win_max_x, win_max_y = win3d['vertices']
|
||||
# calculate a few geometric extents for this window
|
||||
|
||||
win_mid_x = (win_max_x + win_min_x + 1.0) * 0.5
|
||||
win_mid_y = (win_max_y + win_min_y + 1.0) * 0.5
|
||||
win_size_x = (win_max_x - win_min_x + 1.0) * 0.5
|
||||
win_size_y = (win_max_y - win_min_y + 1.0) * 0.5
|
||||
|
||||
#useMid is for projecting the coordinates when we subdivide the screen into bins
|
||||
if useMid: # == True
|
||||
screen_x = win_mid_x
|
||||
screen_y = win_mid_y
|
||||
|
||||
# if the given screencoords (screen_x, screen_y) are within the 3dwin we fount the right one...
|
||||
if (win_max_x > screen_x > win_min_x) and ( win_max_y > screen_y > win_min_y):
|
||||
# first we handle all pending events for this window (otherwise the matrices might come out wrong)
|
||||
Window.QHandle(win3d['id'])
|
||||
|
||||
# now we get a few matrices for our window...
|
||||
# sorry - i cannot explain here what they all do
|
||||
# - if you're not familiar with all those matrices take a look at an introduction to OpenGL...
|
||||
pm = Window.GetPerspMatrix() # the prespective matrix
|
||||
pmi = Matrix(pm); pmi.invert() # the inverted perspective matrix
|
||||
|
||||
if (1.0 - epsilon < pmi[3][3] < 1.0 + epsilon):
|
||||
# pmi[3][3] is 1.0 if the 3dwin is in ortho-projection mode (toggled with numpad 5)
|
||||
hms = mouseViewRay.hms
|
||||
ortho_d = mouseViewRay.ortho_d
|
||||
|
||||
# ortho mode: is a bit strange - actually there's no definite location of the camera ...
|
||||
# but the camera could be displaced anywhere along the viewing direction.
|
||||
|
||||
ortho_d.x, ortho_d.y, ortho_d.z = Window.GetViewVector()
|
||||
ortho_d.w = 0
|
||||
|
||||
# all rays are parallel in ortho mode - so the direction vector is simply the viewing direction
|
||||
#hms.x, hms.y, hms.z, hms.w = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0
|
||||
hms[:] = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0
|
||||
|
||||
# these are the homogenious screencoords of the point (screen_x, screen_y) ranging from -1 to +1
|
||||
p=(hms*pmi) + (1000*ortho_d)
|
||||
p.resize3D()
|
||||
d[:] = ortho_d[:3]
|
||||
|
||||
|
||||
# Finally we shift the position infinitely far away in
|
||||
# the viewing direction to make sure the camera if outside the scene
|
||||
# (this is actually a hack because this function
|
||||
# is used in sculpt_mesh to initialize backface culling...)
|
||||
else:
|
||||
# PERSPECTIVE MODE: here everything is well defined - all rays converge at the camera's location
|
||||
vmi = Matrix(Window.GetViewMatrix()); vmi.invert() # the inverse viewing matrix
|
||||
fp = mouseViewRay.fp
|
||||
|
||||
dx = pm[3][3] * (((screen_x-win_min_x)/win_size_x)-1.0) - pm[3][0]
|
||||
dy = pm[3][3] * (((screen_y-win_min_y)/win_size_y)-1.0) - pm[3][1]
|
||||
|
||||
fp[:] = \
|
||||
pmi[0][0]*dx+pmi[1][0]*dy,\
|
||||
pmi[0][1]*dx+pmi[1][1]*dy,\
|
||||
pmi[0][2]*dx+pmi[1][2]*dy
|
||||
|
||||
# fp is a global 3dpoint obtained from "unprojecting" the screenspace-point (screen_x, screen_y)
|
||||
#- figuring out how to calculate this took me quite some time.
|
||||
# The calculation of dxy and fp are simplified versions of my original code
|
||||
#- so it's almost impossible to explain what's going on geometrically... sorry
|
||||
|
||||
p[:] = vmi[3][:3]
|
||||
|
||||
# the camera's location in global 3dcoords can be read directly from the inverted viewmatrix
|
||||
#d.x, d.y, d.z =normalize_v3(sub_v3v3(p, fp))
|
||||
d[:] = p.x-fp.x, p.y-fp.y, p.z-fp.z
|
||||
|
||||
#print 'd', d, 'p', p, 'fp', fp
|
||||
|
||||
|
||||
# the direction vector is simply the difference vector from the virtual camera's position
|
||||
#to the unprojected (screenspace) point fp
|
||||
|
||||
# Do we want to return a direction in object's localspace?
|
||||
|
||||
if localMatrix:
|
||||
localInvMatrix = Matrix(localMatrix)
|
||||
localInvMatrix.invert()
|
||||
localInvMatrix_notrans = localInvMatrix.rotationPart()
|
||||
p = p * localInvMatrix
|
||||
d = d * localInvMatrix # normalize_v3
|
||||
|
||||
# remove the translation from d
|
||||
d.x -= localInvMatrix[3][0]
|
||||
d.y -= localInvMatrix[3][1]
|
||||
d.z -= localInvMatrix[3][2]
|
||||
|
||||
|
||||
d.normalize()
|
||||
'''
|
||||
# Debugging
|
||||
me = Blender.Mesh.New()
|
||||
me.verts.extend([p[0:3]])
|
||||
me.verts.extend([(p-d)[0:3]])
|
||||
me.edges.extend([0,1])
|
||||
ob = Blender.Scene.GetCurrent().objects.new(me)
|
||||
'''
|
||||
return True, p, d # Origin, Direction
|
||||
|
||||
# Mouse is not in any view, return None.
|
||||
return False, None, None
|
||||
|
||||
# Constant function variables
|
||||
mouseViewRay.d = Vector(0,0,0) # Perspective, 3d
|
||||
mouseViewRay.p = Vector(0,0,0)
|
||||
mouseViewRay.fp = Vector(0,0,0)
|
||||
|
||||
mouseViewRay.hms = Vector(0,0,0,0) # ortho only 4d
|
||||
mouseViewRay.ortho_d = Vector(0,0,0,0) # ortho only 4d
|
||||
|
||||
|
||||
LMB= Window.MButs['L']
|
||||
def mouseup():
|
||||
# Loop until click
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
while not mouse_buttons & LMB:
|
||||
Blender.sys.sleep(10)
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
while mouse_buttons & LMB:
|
||||
Blender.sys.sleep(10)
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
mouseup()
|
||||
x,y= Window.GetMouseCoords()
|
||||
isect, point, dir= mouseViewRay(x,y)
|
||||
if isect:
|
||||
scn= Blender.Scene.GetCurrent()
|
||||
me = Blender.Mesh.New()
|
||||
ob= Blender.Object.New('Mesh')
|
||||
ob.link(me)
|
||||
scn.link(ob)
|
||||
ob.sel= 1
|
||||
me.verts.extend([point, dir])
|
||||
me.verts[0].sel= 1
|
||||
|
||||
print isect, point, dir
|
||||
|
||||
|
||||
|
||||
def spaceRect():
|
||||
'''
|
||||
Returns the space rect
|
||||
xmin,ymin,width,height
|
||||
'''
|
||||
|
||||
__UI_RECT__ = Blender.BGL.Buffer(Blender.BGL.GL_FLOAT, 4)
|
||||
Blender.BGL.glGetFloatv(Blender.BGL.GL_SCISSOR_BOX, __UI_RECT__)
|
||||
__UI_RECT__ = __UI_RECT__.list
|
||||
__UI_RECT__ = int(__UI_RECT__[0]), int(__UI_RECT__[1]), int(__UI_RECT__[2])-1, int(__UI_RECT__[3])
|
||||
|
||||
return __UI_RECT__
|
||||
|
||||
def mouseRelativeLoc2d(__UI_RECT__= None):
|
||||
if not __UI_RECT__:
|
||||
__UI_RECT__ = spaceRect()
|
||||
|
||||
mco = Window.GetMouseCoords()
|
||||
if mco[0] > __UI_RECT__[0] and\
|
||||
mco[1] > __UI_RECT__[1] and\
|
||||
mco[0] < __UI_RECT__[0] + __UI_RECT__[2] and\
|
||||
mco[1] < __UI_RECT__[1] + __UI_RECT__[3]:
|
||||
|
||||
return (mco[0] - __UI_RECT__[0], mco[1] - __UI_RECT__[1])
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import struct
|
||||
|
||||
# In Blender, selecting scenes in the databrowser (shift+f4) will tag for rendering.
|
||||
|
||||
# This struct wont change according to ton.
|
||||
# Note that the size differs on 32/64bit
|
||||
'''
|
||||
typedef struct BHead {
|
||||
int code, len;
|
||||
void *old;
|
||||
int SDNAnr, nr;
|
||||
} BHead;
|
||||
'''
|
||||
|
||||
|
||||
def read_blend_rend_chunk(path):
|
||||
file = open(path, 'rb')
|
||||
|
||||
if file.read(len('BLENDER')) != 'BLENDER':
|
||||
return []
|
||||
|
||||
#
|
||||
if file.read(1) == '-':
|
||||
is64bit = True
|
||||
else: # '_'
|
||||
is64bit = False
|
||||
|
||||
if file.read(1) == 'V':
|
||||
isBigEndian = True # ppc
|
||||
else: # 'V'
|
||||
isBigEndian = False # x86
|
||||
|
||||
|
||||
# Now read the bhead chunk!!!
|
||||
file.read(3) # skip the version
|
||||
|
||||
scenes = []
|
||||
|
||||
while file.read(4) == 'REND':
|
||||
|
||||
if is64bit: sizeof_bhead = sizeof_bhead_left = 24 # 64bit
|
||||
else: sizeof_bhead = sizeof_bhead_left = 20 # 32bit
|
||||
|
||||
sizeof_bhead_left -= 4
|
||||
|
||||
if isBigEndian: rend_length = struct.unpack('>i', file.read(4))[0]
|
||||
else: rend_length = struct.unpack('<i', file.read(4))[0]
|
||||
|
||||
sizeof_bhead_left -= 4
|
||||
|
||||
# We dont care about the rest of the bhead struct
|
||||
file.read(sizeof_bhead_left)
|
||||
|
||||
# Now we want the scene name, start and end frame. this is 32bites long
|
||||
|
||||
if isBigEndian: start_frame, end_frame = struct.unpack('>2i', file.read(8))
|
||||
else: start_frame, end_frame = struct.unpack('<2i', file.read(8))
|
||||
|
||||
scene_name = file.read(24)
|
||||
scene_name = scene_name[ : scene_name.index('\0') ]
|
||||
|
||||
scenes.append( (start_frame, end_frame, scene_name) )
|
||||
return scenes
|
||||
|
||||
def main():
|
||||
import sys
|
||||
for arg in sys.argv[1:]:
|
||||
if arg.lower().endswith('.blend'):
|
||||
print read_blend_rend_chunk(arg)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -1,941 +0,0 @@
|
||||
# Default Doodad Set for Discombobulator
|
||||
# by Evan J. Rosky, 2005
|
||||
# GPL- http://www.gnu.org/copyleft/gpl.html
|
||||
#
|
||||
# $Id$
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2005: Evan J. Rosky
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
#Run discombobulator.py, not this.
|
||||
|
||||
import Blender
|
||||
from Blender import NMesh,Object,Material
|
||||
from Blender.NMesh import Vert,Face
|
||||
from Blender.Mathutils import *
|
||||
|
||||
import BPyMathutils
|
||||
from BPyMathutils import genrand
|
||||
a = BPyMathutils.sgenrand(4859)
|
||||
|
||||
#Create random numbers
|
||||
def randnum(low,high):
|
||||
num = genrand()
|
||||
num = num*(high-low)
|
||||
num = num+low
|
||||
return num
|
||||
|
||||
face = Face()
|
||||
xmin = Vector([0,0,0])
|
||||
xmax = Vector([0,0,0])
|
||||
ymin = Vector([0,0,0])
|
||||
ymax = Vector([0,0,0])
|
||||
mxmin = Vector([0,0,0])
|
||||
mxmax = Vector([0,0,0])
|
||||
mymin = Vector([0,0,0])
|
||||
mymax = Vector([0,0,0])
|
||||
doodadCenter = Vector([0,0,0])
|
||||
orientation = 0
|
||||
center = Vector([0,0,0])
|
||||
tosel = 0
|
||||
seltopsonly = 0
|
||||
tempx = []
|
||||
doodadMesh = NMesh.GetRaw()
|
||||
|
||||
global materialArray
|
||||
global reassignMats
|
||||
global thereAreMats
|
||||
global currmat
|
||||
global doodSideMat
|
||||
global doodTopMat
|
||||
|
||||
#face is the face to add the doodad to.
|
||||
#sizeX and sizeY are values from 0.0 to 1.0 that represents a percentage the face that is covered by the doodad.
|
||||
#height is how tall the doodad is.
|
||||
|
||||
def settings(seltops,matArr,reasMats,therMats,sidemat,topmat):
|
||||
global seltopsonly
|
||||
global materialArray
|
||||
global reassignMats
|
||||
global thereAreMats
|
||||
global currmat
|
||||
global doodSideMat
|
||||
global doodTopMat
|
||||
materialArray = matArr
|
||||
reassignMats = reasMats
|
||||
thereAreMats = therMats
|
||||
seltopsonly = seltops
|
||||
doodSideMat = sidemat
|
||||
doodTopMat = topmat
|
||||
|
||||
def setCurrMat(curma):
|
||||
global currmat
|
||||
currmat = curma
|
||||
|
||||
#Find center and orientation of doodad
|
||||
def findDoodadCenter(sizeX, sizeY):
|
||||
#globalizing junk
|
||||
global face
|
||||
global xmin
|
||||
global xmax
|
||||
global ymin
|
||||
global ymax
|
||||
global orientation
|
||||
global doodadCenter
|
||||
global center
|
||||
global tosel
|
||||
global mxmin
|
||||
global mxmax
|
||||
global mymin
|
||||
global mymax
|
||||
global tempx
|
||||
global seltopsonly
|
||||
|
||||
#Find the center of the face
|
||||
center = Vector([0,0,0])
|
||||
for pt in face.v:
|
||||
center = center + pt.co
|
||||
center = divideVectorByInt(center,len(face.v))
|
||||
|
||||
#Find Temp Location Range by looking at the sizes
|
||||
txmin = ((divideVectorByInt((face.v[0].co + face.v[3].co),2)) - center)*(1-sizeX) + center
|
||||
txmax = ((divideVectorByInt((face.v[1].co + face.v[2].co),2)) - center)*(1-sizeX) + center
|
||||
tymin = ((divideVectorByInt((face.v[0].co + face.v[1].co),2)) - center)*(1-sizeY) + center
|
||||
tymax = ((divideVectorByInt((face.v[2].co + face.v[3].co),2)) - center)*(1-sizeY) + center
|
||||
|
||||
#Find Center of doodad
|
||||
amtx = randnum(0.0,1.0)
|
||||
amty = randnum(0.0,1.0)
|
||||
thepoint = (((((txmin - txmax)*amtx + txmax) - ((tymin - tymax)*amty + tymax))*.5 + ((tymin - tymax)*amty + tymax)) - center)*2 + center
|
||||
doodadCenter = Vector([thepoint[0],thepoint[1],thepoint[2]])
|
||||
|
||||
#Find Main Range by looking at the sizes
|
||||
mxmin = divideVectorByInt((face.v[0].co + face.v[3].co),2)
|
||||
mxmax = divideVectorByInt((face.v[1].co + face.v[2].co),2)
|
||||
mymin = divideVectorByInt((face.v[0].co + face.v[1].co),2)
|
||||
mymax = divideVectorByInt((face.v[2].co + face.v[3].co),2)
|
||||
|
||||
#Find x/y equivs for whole face
|
||||
ve1 = (txmin - txmax)*amtx + txmax
|
||||
ve1 = ve1 - mxmax
|
||||
nax = ve1.length
|
||||
ve1 = (mxmin - mxmax)
|
||||
nax = nax/ve1.length
|
||||
|
||||
ve1 = (tymin - tymax)*amty + tymax
|
||||
ve1 = ve1 - mymax
|
||||
nay = ve1.length
|
||||
ve1 = (mymin - mymax)
|
||||
nay = nay/ve1.length
|
||||
|
||||
#Find new box thing
|
||||
tempx = []
|
||||
amtx = nax-sizeX/2
|
||||
amty = nay-sizeY/2
|
||||
tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center)
|
||||
|
||||
amtx = nax-sizeX/2
|
||||
amty = nay+sizeY/2
|
||||
tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center)
|
||||
|
||||
amtx = nax+sizeX/2
|
||||
amty = nay+sizeY/2
|
||||
tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center)
|
||||
|
||||
amtx = nax+sizeX/2
|
||||
amty = nay-sizeY/2
|
||||
tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center)
|
||||
|
||||
#Find New Location Range by looking at the sizes
|
||||
xmin = divideVectorByInt((tempx[0] + tempx[3]),2)
|
||||
xmax = divideVectorByInt((tempx[1] + tempx[2]),2)
|
||||
ymin = divideVectorByInt((tempx[0] + tempx[1]),2)
|
||||
ymax = divideVectorByInt((tempx[2] + tempx[3]),2)
|
||||
|
||||
#Make a point
|
||||
def makePoint(x,y,z=0):
|
||||
global xmin
|
||||
global xmax
|
||||
global ymin
|
||||
global ymax
|
||||
global doodadCenter
|
||||
global tosel
|
||||
global seltopsonly
|
||||
global face
|
||||
|
||||
amtx = x
|
||||
amty = y
|
||||
thepoint = (((((xmin - xmax)*amtx + xmax) - ((ymin - ymax)*amty + ymax))*.5 + ((ymin - ymax)*amty + ymax)) - doodadCenter)*2 + doodadCenter
|
||||
thepoint = thepoint + z*Vector(face.no)
|
||||
tver = Vert(thepoint[0],thepoint[1],thepoint[2])
|
||||
if tosel == 1 and seltopsonly == 0 and z == 0:
|
||||
tver.sel = 1
|
||||
return tver
|
||||
|
||||
#extrude ground-plane(s)
|
||||
def extrudedoodad(vArray,heig):
|
||||
global face
|
||||
global doodadMesh
|
||||
global tosel
|
||||
|
||||
topVArray = []
|
||||
|
||||
doodadMesh.verts.extend(vArray)
|
||||
|
||||
#Create array for extruded verts
|
||||
for ind in range(0,(len(vArray))):
|
||||
point = vArray[ind].co + heig*Vector(face.no)
|
||||
ver = Vert(point[0],point[1],point[2])
|
||||
if tosel == 1:
|
||||
ver.sel = 1
|
||||
topVArray.append(ver)
|
||||
doodadMesh.verts.append(topVArray[ind])
|
||||
|
||||
#make faces around sides
|
||||
for ind in range(0,(len(vArray) - 1)):
|
||||
face = Face()
|
||||
face.v.extend([vArray[ind],vArray[ind+1],topVArray[ind+1],topVArray[ind]])
|
||||
if tosel == 1 and seltopsonly == 0: face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodSideMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodSideMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vArray[len(vArray) - 1],vArray[0],topVArray[0],topVArray[len(topVArray) - 1]])
|
||||
if tosel == 1 and seltopsonly == 0:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodSideMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodSideMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
return topVArray
|
||||
|
||||
#For switching face vertices
|
||||
def fixvertindex(ind):
|
||||
if ind > 3:
|
||||
indx = ind - 4
|
||||
else:
|
||||
indx = ind
|
||||
return indx
|
||||
|
||||
#runs doodads
|
||||
def createDoodad(indexArray,facec,minsi,maxsi,minhei,maxhei,selec,amtmin,amtmax,facpercent):
|
||||
global doodadMesh
|
||||
global seltopsonly
|
||||
global tosel
|
||||
|
||||
doodadMesh = NMesh.GetRaw()
|
||||
|
||||
theamt = round(randnum(amtmin,amtmax),0)
|
||||
theamt = int(theamt)
|
||||
tosel = selec
|
||||
|
||||
for i in range(0,(theamt)):
|
||||
if randnum(0,1) <= facpercent:
|
||||
index = round(randnum(1,len(indexArray)),0)
|
||||
index = indexArray[(int(index) - 1)]
|
||||
|
||||
Xsi = randnum(minsi,maxsi)
|
||||
Ysi = randnum(minsi,maxsi)
|
||||
hei = randnum(minhei,maxhei)
|
||||
|
||||
#Determine orientation
|
||||
orient = int(round(randnum(0.0,3.0)))
|
||||
|
||||
#face to use as range
|
||||
facer = Face()
|
||||
facer.v.extend([facec.v[orient],facec.v[fixvertindex(1+orient)],facec.v[fixvertindex(2+orient)],facec.v[fixvertindex(3+orient)]])
|
||||
|
||||
if index == 1:
|
||||
singleBox(facer,Xsi,Ysi,hei)
|
||||
if index == 2:
|
||||
doubleBox(facer,Xsi,Ysi,hei)
|
||||
if index == 3:
|
||||
tripleBox(facer,Xsi,Ysi,hei)
|
||||
if index == 4:
|
||||
LShape(facer,Xsi,Ysi,hei)
|
||||
if index == 5:
|
||||
TShape(facer,Xsi,Ysi,hei)
|
||||
if index == 6:
|
||||
if randnum(0.0,1.0) > .5:
|
||||
SShape(facer,Xsi,Ysi,hei)
|
||||
else:
|
||||
ZShape(facer,Xsi,Ysi,hei)
|
||||
|
||||
return doodadMesh
|
||||
|
||||
def divideVectorByInt(thevect,theint):
|
||||
thevect.x = thevect.x/theint
|
||||
thevect.y = thevect.y/theint
|
||||
thevect.z = thevect.z/theint
|
||||
return thevect
|
||||
|
||||
#Single Box Doodad
|
||||
def singleBox(facel, Xsize, Ysize, height):
|
||||
#globaling junk
|
||||
global face
|
||||
global tosel
|
||||
global doodadMesh
|
||||
|
||||
face = Face()
|
||||
face = facel
|
||||
|
||||
findDoodadCenter(Xsize, Ysize)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place four points
|
||||
vertArray.append(makePoint(0,0))
|
||||
vertArray.append(makePoint(0,1))
|
||||
vertArray.append(makePoint(1,1))
|
||||
vertArray.append(makePoint(1,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
face = Face()
|
||||
face.v.extend(vertArray)
|
||||
face.v.reverse()
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend(topVertArray)
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#Double Box Doodad
|
||||
def doubleBox(facel, Xsize, Ysize, height):
|
||||
#globaling junk
|
||||
global face
|
||||
global tosel
|
||||
global doodadMesh
|
||||
|
||||
face = Face()
|
||||
face = facel
|
||||
|
||||
findDoodadCenter(Xsize, Ysize)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place first box
|
||||
vertArray.append(makePoint(0,0))
|
||||
vertArray.append(makePoint(0,1))
|
||||
vertArray.append(makePoint(0.45,1))
|
||||
vertArray.append(makePoint(0.45,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
face = Face()
|
||||
face.v.extend(vertArray)
|
||||
face.v.reverse()
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend(topVertArray)
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place second box
|
||||
vertArray.append(makePoint(0.55,0))
|
||||
vertArray.append(makePoint(0.55,1))
|
||||
vertArray.append(makePoint(1,1))
|
||||
vertArray.append(makePoint(1,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
face = Face()
|
||||
face.v.extend(vertArray)
|
||||
face.v.reverse()
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend(topVertArray)
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#Triple Box Doodad
|
||||
def tripleBox(facel, Xsize, Ysize, height):
|
||||
#globaling junk
|
||||
global face
|
||||
global tosel
|
||||
global doodadMesh
|
||||
|
||||
face = Face()
|
||||
face = facel
|
||||
|
||||
findDoodadCenter(Xsize, Ysize)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place first box
|
||||
vertArray.append(makePoint(0,0))
|
||||
vertArray.append(makePoint(0,1))
|
||||
vertArray.append(makePoint(0.3,1))
|
||||
vertArray.append(makePoint(0.3,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
face = Face()
|
||||
face.v.extend(vertArray)
|
||||
face.v.reverse()
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend(topVertArray)
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place second box
|
||||
vertArray.append(makePoint(0.35,0))
|
||||
vertArray.append(makePoint(0.35,1))
|
||||
vertArray.append(makePoint(0.65,1))
|
||||
vertArray.append(makePoint(0.65,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
face = Face()
|
||||
face.v.extend(vertArray)
|
||||
face.v.reverse()
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend(topVertArray)
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place third box
|
||||
vertArray.append(makePoint(0.7,0))
|
||||
vertArray.append(makePoint(0.7,1))
|
||||
vertArray.append(makePoint(1,1))
|
||||
vertArray.append(makePoint(1,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
face = Face()
|
||||
face.v.extend(vertArray)
|
||||
face.v.reverse()
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend(topVertArray)
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#The "L" Shape
|
||||
def LShape(facel, Xsize, Ysize, height):
|
||||
#globaling junk
|
||||
global face
|
||||
global tosel
|
||||
global doodadMesh
|
||||
|
||||
face = Face()
|
||||
face = facel
|
||||
|
||||
findDoodadCenter(Xsize, Ysize)
|
||||
|
||||
rcon1 = randnum(0.2,0.8)
|
||||
rcon2 = randnum(0.2,0.8)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place L shape
|
||||
vertArray.append(makePoint(0,0))
|
||||
vertArray.append(makePoint(0,rcon1))
|
||||
vertArray.append(makePoint(0,1))
|
||||
vertArray.append(makePoint(rcon2,1))
|
||||
vertArray.append(makePoint(rcon2,rcon1))
|
||||
vertArray.append(makePoint(1,rcon1))
|
||||
vertArray.append(makePoint(1,0))
|
||||
vertArray.append(makePoint(rcon2,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
#This fills in the bottom of doodad with faceness
|
||||
face = Face()
|
||||
face.v.extend([vertArray[0],vertArray[1],vertArray[4],vertArray[7]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[4]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#This fills in the top with faceness
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[0],topVertArray[1],topVertArray[4],topVertArray[7]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[4]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#The "T" Shape
|
||||
def TShape(facel, Xsize, Ysize, height):
|
||||
#globaling junk
|
||||
global face
|
||||
global tosel
|
||||
global doodadMesh
|
||||
|
||||
face = Face()
|
||||
face = facel
|
||||
|
||||
findDoodadCenter(Xsize, Ysize)
|
||||
|
||||
rcony = randnum(0.25,0.75)
|
||||
rconx1 = randnum(0.1,0.49)
|
||||
rconx2 = randnum(0.51,0.9)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place T shape
|
||||
vertArray.append(makePoint(0,0))
|
||||
vertArray.append(makePoint(0,rcony))
|
||||
vertArray.append(makePoint(rconx1,rcony))
|
||||
vertArray.append(makePoint(rconx1,1))
|
||||
vertArray.append(makePoint(rconx2,1))
|
||||
vertArray.append(makePoint(rconx2,rcony))
|
||||
vertArray.append(makePoint(1,rcony))
|
||||
vertArray.append(makePoint(1,0))
|
||||
vertArray.append(makePoint(rconx2,0))
|
||||
vertArray.append(makePoint(rconx1,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
#fills bottom with faceness
|
||||
face = Face()
|
||||
face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[9]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[2],vertArray[3],vertArray[4],vertArray[5]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[8],vertArray[9],vertArray[2],vertArray[5]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#fills top with faceness
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[9]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[2],topVertArray[3],topVertArray[4],topVertArray[5]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[8],topVertArray[9],topVertArray[2],topVertArray[5]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#The "S" or "Z" Shapes
|
||||
def SShape(facel, Xsize, Ysize, height):
|
||||
#globaling junk
|
||||
global face
|
||||
global tosel
|
||||
global doodadMesh
|
||||
|
||||
face = Face()
|
||||
face = facel
|
||||
|
||||
findDoodadCenter(Xsize, Ysize)
|
||||
|
||||
rcony1 = randnum(0.1,0.49)
|
||||
rcony2 = randnum(0.51,0.9)
|
||||
rconx1 = randnum(0.1,0.49)
|
||||
rconx2 = randnum(0.51,0.9)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place S shape
|
||||
vertArray.append(makePoint(0,0))
|
||||
vertArray.append(makePoint(0,rcony1))
|
||||
vertArray.append(makePoint(rconx1,rcony1))
|
||||
vertArray.append(makePoint(rconx1,rcony2))
|
||||
vertArray.append(makePoint(rconx1,1))
|
||||
vertArray.append(makePoint(rconx2,1))
|
||||
vertArray.append(makePoint(1,1))
|
||||
vertArray.append(makePoint(1,rcony2))
|
||||
vertArray.append(makePoint(rconx2,rcony2))
|
||||
vertArray.append(makePoint(rconx2,rcony1))
|
||||
vertArray.append(makePoint(rconx2,0))
|
||||
vertArray.append(makePoint(rconx1,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
#fills bottom with faceness
|
||||
face = Face()
|
||||
face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[11]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[2],vertArray[9],vertArray[10],vertArray[11]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[2],vertArray[3],vertArray[8],vertArray[9]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[3],vertArray[4],vertArray[5],vertArray[8]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#fills top with faceness
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[11]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[2],topVertArray[9],topVertArray[10],topVertArray[11]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[2],topVertArray[3],topVertArray[8],topVertArray[9]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[3],topVertArray[4],topVertArray[5],topVertArray[8]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
def ZShape(facel, Xsize, Ysize, height):
|
||||
#globaling junk
|
||||
global face
|
||||
global tosel
|
||||
global doodadMesh
|
||||
|
||||
face = Face()
|
||||
face = facel
|
||||
|
||||
findDoodadCenter(Xsize, Ysize)
|
||||
|
||||
rcony1 = randnum(0.1,0.49)
|
||||
rcony2 = randnum(0.51,0.9)
|
||||
rconx1 = randnum(0.1,0.49)
|
||||
rconx2 = randnum(0.51,0.9)
|
||||
|
||||
vertArray = []
|
||||
|
||||
#place Z shape
|
||||
vertArray.append(makePoint(0,0))
|
||||
vertArray.append(makePoint(0,rcony1))
|
||||
vertArray.append(makePoint(0,rcony2))
|
||||
vertArray.append(makePoint(rconx1,rcony2))
|
||||
vertArray.append(makePoint(rconx2,rcony2))
|
||||
vertArray.append(makePoint(rconx2,1))
|
||||
vertArray.append(makePoint(1,1))
|
||||
vertArray.append(makePoint(1,rcony2))
|
||||
vertArray.append(makePoint(1,rcony1))
|
||||
vertArray.append(makePoint(rconx2,rcony1))
|
||||
vertArray.append(makePoint(rconx1,rcony1))
|
||||
vertArray.append(makePoint(rconx1,0))
|
||||
topVertArray = extrudedoodad(vertArray,height)
|
||||
|
||||
#fills bottom with faceness
|
||||
face = Face()
|
||||
face.v.extend([vertArray[0],vertArray[1],vertArray[10],vertArray[11]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[10]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[3],vertArray[4],vertArray[9],vertArray[10]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[4],vertArray[7],vertArray[8],vertArray[9]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]])
|
||||
face.v.reverse()
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
#fills top with faceness
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[0],topVertArray[1],topVertArray[10],topVertArray[11]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[10]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[3],topVertArray[4],topVertArray[9],topVertArray[10]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[4],topVertArray[7],topVertArray[8],topVertArray[9]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
face = Face()
|
||||
face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]])
|
||||
if tosel == 1:
|
||||
face.sel = 1
|
||||
if thereAreMats == 1:
|
||||
if reassignMats == 0 or doodTopMat == 0:
|
||||
face.materialIndex = currmat
|
||||
else:
|
||||
face.materialIndex = doodTopMat-1
|
||||
doodadMesh.faces.append(face)
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
# dictionary mapping AutoCAD color indexes with Blender colors
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# color_map.py Final by Ed Blake (AKA Kitsu)
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
color_map = {
|
||||
0:[0.0, 0.0, 0.0],
|
||||
1:[0.99609375, 0.0, 0.0],
|
||||
2:[0.99609375, 0.99609375, 0.0],
|
||||
3:[0.0, 0.99609375, 0.0],
|
||||
4:[0.0, 0.99609375, 0.99609375],
|
||||
5:[0.0, 0.0, 0.99609375],
|
||||
6:[0.99609375, 0.0, 0.99609375],
|
||||
7:[0.99609375, 0.99609375, 0.99609375],
|
||||
8:[0.25390625, 0.25390625, 0.25390625],
|
||||
9:[0.5, 0.5, 0.5],
|
||||
10:[0.99609375, 0.0, 0.0],
|
||||
11:[0.99609375, 0.6640625, 0.6640625],
|
||||
12:[0.73828125, 0.0, 0.0],
|
||||
13:[0.73828125, 0.4921875, 0.4921875],
|
||||
14:[0.50390625, 0.0, 0.0],
|
||||
15:[0.50390625, 0.3359375, 0.3359375],
|
||||
16:[0.40625, 0.0, 0.0],
|
||||
17:[0.40625, 0.26953125, 0.26953125],
|
||||
18:[0.30859375, 0.0, 0.0],
|
||||
19:[0.30859375, 0.20703125, 0.20703125],
|
||||
20:[0.99609375, 0.24609375, 0.0],
|
||||
21:[0.99609375, 0.74609375, 0.6640625],
|
||||
22:[0.73828125, 0.1796875, 0.0],
|
||||
23:[0.73828125, 0.55078125, 0.4921875],
|
||||
24:[0.50390625, 0.12109375, 0.0],
|
||||
25:[0.50390625, 0.375, 0.3359375],
|
||||
26:[0.40625, 0.09765625, 0.0],
|
||||
27:[0.40625, 0.3046875, 0.26953125],
|
||||
28:[0.30859375, 0.07421875, 0.0],
|
||||
29:[0.30859375, 0.23046875, 0.20703125],
|
||||
30:[0.99609375, 0.49609375, 0.0],
|
||||
31:[0.99609375, 0.828125, 0.6640625],
|
||||
32:[0.73828125, 0.3671875, 0.0],
|
||||
33:[0.73828125, 0.61328125, 0.4921875],
|
||||
34:[0.50390625, 0.25, 0.0],
|
||||
35:[0.50390625, 0.41796875, 0.3359375],
|
||||
36:[0.40625, 0.203125, 0.0],
|
||||
37:[0.40625, 0.3359375, 0.26953125],
|
||||
38:[0.30859375, 0.15234375, 0.0],
|
||||
39:[0.30859375, 0.2578125, 0.20703125],
|
||||
40:[0.99609375, 0.74609375, 0.0],
|
||||
41:[0.99609375, 0.9140625, 0.6640625],
|
||||
42:[0.73828125, 0.55078125, 0.0],
|
||||
43:[0.73828125, 0.67578125, 0.4921875],
|
||||
44:[0.50390625, 0.375, 0.0],
|
||||
45:[0.50390625, 0.4609375, 0.3359375],
|
||||
46:[0.40625, 0.3046875, 0.0],
|
||||
47:[0.40625, 0.37109375, 0.26953125],
|
||||
48:[0.30859375, 0.23046875, 0.0],
|
||||
49:[0.30859375, 0.28515625, 0.20703125],
|
||||
50:[0.99609375, 0.99609375, 0.0],
|
||||
51:[0.99609375, 0.99609375, 0.6640625],
|
||||
52:[0.73828125, 0.73828125, 0.0],
|
||||
53:[0.73828125, 0.73828125, 0.4921875],
|
||||
54:[0.50390625, 0.50390625, 0.0],
|
||||
55:[0.50390625, 0.50390625, 0.3359375],
|
||||
56:[0.40625, 0.40625, 0.0],
|
||||
57:[0.40625, 0.40625, 0.26953125],
|
||||
58:[0.30859375, 0.30859375, 0.0],
|
||||
59:[0.30859375, 0.30859375, 0.20703125],
|
||||
60:[0.74609375, 0.99609375, 0.0],
|
||||
61:[0.9140625, 0.99609375, 0.6640625],
|
||||
62:[0.55078125, 0.73828125, 0.0],
|
||||
63:[0.67578125, 0.73828125, 0.4921875],
|
||||
64:[0.375, 0.50390625, 0.0],
|
||||
65:[0.4609375, 0.50390625, 0.3359375],
|
||||
66:[0.3046875, 0.40625, 0.0],
|
||||
67:[0.37109375, 0.40625, 0.26953125],
|
||||
68:[0.23046875, 0.30859375, 0.0],
|
||||
69:[0.28515625, 0.30859375, 0.20703125],
|
||||
70:[0.49609375, 0.99609375, 0.0],
|
||||
71:[0.828125, 0.99609375, 0.6640625],
|
||||
72:[0.3671875, 0.73828125, 0.0],
|
||||
73:[0.61328125, 0.73828125, 0.4921875],
|
||||
74:[0.25, 0.50390625, 0.0],
|
||||
75:[0.41796875, 0.50390625, 0.3359375],
|
||||
76:[0.203125, 0.40625, 0.0],
|
||||
77:[0.3359375, 0.40625, 0.26953125],
|
||||
78:[0.15234375, 0.30859375, 0.0],
|
||||
79:[0.2578125, 0.30859375, 0.20703125],
|
||||
80:[0.24609375, 0.99609375, 0.0],
|
||||
81:[0.74609375, 0.99609375, 0.6640625],
|
||||
82:[0.1796875, 0.73828125, 0.0],
|
||||
83:[0.55078125, 0.73828125, 0.4921875],
|
||||
84:[0.12109375, 0.50390625, 0.0],
|
||||
85:[0.375, 0.50390625, 0.3359375],
|
||||
86:[0.09765625, 0.40625, 0.0],
|
||||
87:[0.3046875, 0.40625, 0.26953125],
|
||||
88:[0.07421875, 0.30859375, 0.0],
|
||||
89:[0.23046875, 0.30859375, 0.20703125],
|
||||
90:[0.0, 0.99609375, 0.0],
|
||||
91:[0.6640625, 0.99609375, 0.6640625],
|
||||
92:[0.0, 0.73828125, 0.0],
|
||||
93:[0.4921875, 0.73828125, 0.4921875],
|
||||
94:[0.0, 0.50390625, 0.0],
|
||||
95:[0.3359375, 0.50390625, 0.3359375],
|
||||
96:[0.0, 0.40625, 0.0],
|
||||
97:[0.26953125, 0.40625, 0.26953125],
|
||||
98:[0.0, 0.30859375, 0.0],
|
||||
99:[0.20703125, 0.30859375, 0.20703125],
|
||||
100:[0.0, 0.99609375, 0.24609375],
|
||||
101:[0.6640625, 0.99609375, 0.74609375],
|
||||
102:[0.0, 0.73828125, 0.1796875],
|
||||
103:[0.4921875, 0.73828125, 0.55078125],
|
||||
104:[0.0, 0.50390625, 0.12109375],
|
||||
105:[0.3359375, 0.50390625, 0.375],
|
||||
106:[0.0, 0.40625, 0.09765625],
|
||||
107:[0.26953125, 0.40625, 0.3046875],
|
||||
108:[0.0, 0.30859375, 0.07421875],
|
||||
109:[0.20703125, 0.30859375, 0.23046875],
|
||||
110:[0.0, 0.99609375, 0.49609375],
|
||||
111:[0.6640625, 0.99609375, 0.828125],
|
||||
112:[0.0, 0.73828125, 0.3671875],
|
||||
113:[0.4921875, 0.73828125, 0.61328125],
|
||||
114:[0.0, 0.50390625, 0.25],
|
||||
115:[0.3359375, 0.50390625, 0.41796875],
|
||||
116:[0.0, 0.40625, 0.203125],
|
||||
117:[0.26953125, 0.40625, 0.3359375],
|
||||
118:[0.0, 0.30859375, 0.15234375],
|
||||
119:[0.20703125, 0.30859375, 0.2578125],
|
||||
120:[0.0, 0.99609375, 0.74609375],
|
||||
121:[0.6640625, 0.99609375, 0.9140625],
|
||||
122:[0.0, 0.73828125, 0.55078125],
|
||||
123:[0.4921875, 0.73828125, 0.67578125],
|
||||
124:[0.0, 0.50390625, 0.375],
|
||||
125:[0.3359375, 0.50390625, 0.4609375],
|
||||
126:[0.0, 0.40625, 0.3046875],
|
||||
127:[0.26953125, 0.40625, 0.37109375],
|
||||
128:[0.0, 0.30859375, 0.23046875],
|
||||
129:[0.20703125, 0.30859375, 0.28515625],
|
||||
130:[0.0, 0.99609375, 0.99609375],
|
||||
131:[0.6640625, 0.99609375, 0.99609375],
|
||||
132:[0.0, 0.73828125, 0.73828125],
|
||||
133:[0.4921875, 0.73828125, 0.73828125],
|
||||
134:[0.0, 0.50390625, 0.50390625],
|
||||
135:[0.3359375, 0.50390625, 0.50390625],
|
||||
136:[0.0, 0.40625, 0.40625],
|
||||
137:[0.26953125, 0.40625, 0.40625],
|
||||
138:[0.0, 0.30859375, 0.30859375],
|
||||
139:[0.20703125, 0.30859375, 0.30859375],
|
||||
140:[0.0, 0.74609375, 0.99609375],
|
||||
141:[0.6640625, 0.9140625, 0.99609375],
|
||||
142:[0.0, 0.55078125, 0.73828125],
|
||||
143:[0.4921875, 0.67578125, 0.73828125],
|
||||
144:[0.0, 0.375, 0.50390625],
|
||||
145:[0.3359375, 0.4609375, 0.50390625],
|
||||
146:[0.0, 0.3046875, 0.40625],
|
||||
147:[0.26953125, 0.37109375, 0.40625],
|
||||
148:[0.0, 0.23046875, 0.30859375],
|
||||
149:[0.20703125, 0.28515625, 0.30859375],
|
||||
150:[0.0, 0.49609375, 0.99609375],
|
||||
151:[0.6640625, 0.828125, 0.99609375],
|
||||
152:[0.0, 0.3671875, 0.73828125],
|
||||
153:[0.4921875, 0.61328125, 0.73828125],
|
||||
154:[0.0, 0.25, 0.50390625],
|
||||
155:[0.3359375, 0.41796875, 0.50390625],
|
||||
156:[0.0, 0.203125, 0.40625],
|
||||
157:[0.26953125, 0.3359375, 0.40625],
|
||||
158:[0.0, 0.15234375, 0.30859375],
|
||||
159:[0.20703125, 0.2578125, 0.30859375],
|
||||
160:[0.0, 0.24609375, 0.99609375],
|
||||
161:[0.6640625, 0.74609375, 0.99609375],
|
||||
162:[0.0, 0.1796875, 0.73828125],
|
||||
163:[0.4921875, 0.55078125, 0.73828125],
|
||||
164:[0.0, 0.12109375, 0.50390625],
|
||||
165:[0.3359375, 0.375, 0.50390625],
|
||||
166:[0.0, 0.09765625, 0.40625],
|
||||
167:[0.26953125, 0.3046875, 0.40625],
|
||||
168:[0.0, 0.07421875, 0.30859375],
|
||||
169:[0.20703125, 0.23046875, 0.30859375],
|
||||
170:[0.0, 0.0, 0.99609375],
|
||||
171:[0.6640625, 0.6640625, 0.99609375],
|
||||
172:[0.0, 0.0, 0.73828125],
|
||||
173:[0.4921875, 0.4921875, 0.73828125],
|
||||
174:[0.0, 0.0, 0.50390625],
|
||||
175:[0.3359375, 0.3359375, 0.50390625],
|
||||
176:[0.0, 0.0, 0.40625],
|
||||
177:[0.26953125, 0.26953125, 0.40625],
|
||||
178:[0.0, 0.0, 0.30859375],
|
||||
179:[0.20703125, 0.20703125, 0.30859375],
|
||||
180:[0.24609375, 0.0, 0.99609375],
|
||||
181:[0.74609375, 0.6640625, 0.99609375],
|
||||
182:[0.1796875, 0.0, 0.73828125],
|
||||
183:[0.55078125, 0.4921875, 0.73828125],
|
||||
184:[0.12109375, 0.0, 0.50390625],
|
||||
185:[0.375, 0.3359375, 0.50390625],
|
||||
186:[0.09765625, 0.0, 0.40625],
|
||||
187:[0.3046875, 0.26953125, 0.40625],
|
||||
188:[0.07421875, 0.0, 0.30859375],
|
||||
189:[0.23046875, 0.20703125, 0.30859375],
|
||||
190:[0.49609375, 0.0, 0.99609375],
|
||||
191:[0.828125, 0.6640625, 0.99609375],
|
||||
192:[0.3671875, 0.0, 0.73828125],
|
||||
193:[0.61328125, 0.4921875, 0.73828125],
|
||||
194:[0.25, 0.0, 0.50390625],
|
||||
195:[0.41796875, 0.3359375, 0.50390625],
|
||||
196:[0.203125, 0.0, 0.40625],
|
||||
197:[0.3359375, 0.26953125, 0.40625],
|
||||
198:[0.15234375, 0.0, 0.30859375],
|
||||
199:[0.2578125, 0.20703125, 0.30859375],
|
||||
200:[0.74609375, 0.0, 0.99609375],
|
||||
201:[0.9140625, 0.6640625, 0.99609375],
|
||||
202:[0.55078125, 0.0, 0.73828125],
|
||||
203:[0.67578125, 0.4921875, 0.73828125],
|
||||
204:[0.375, 0.0, 0.50390625],
|
||||
205:[0.4609375, 0.3359375, 0.50390625],
|
||||
206:[0.3046875, 0.0, 0.40625],
|
||||
207:[0.37109375, 0.26953125, 0.40625],
|
||||
208:[0.23046875, 0.0, 0.30859375],
|
||||
209:[0.28515625, 0.20703125, 0.30859375],
|
||||
210:[0.99609375, 0.0, 0.99609375],
|
||||
211:[0.99609375, 0.6640625, 0.99609375],
|
||||
212:[0.73828125, 0.0, 0.73828125],
|
||||
213:[0.73828125, 0.4921875, 0.73828125],
|
||||
214:[0.50390625, 0.0, 0.50390625],
|
||||
215:[0.50390625, 0.3359375, 0.50390625],
|
||||
216:[0.40625, 0.0, 0.40625],
|
||||
217:[0.40625, 0.26953125, 0.40625],
|
||||
218:[0.30859375, 0.0, 0.30859375],
|
||||
219:[0.30859375, 0.20703125, 0.30859375],
|
||||
220:[0.99609375, 0.0, 0.74609375],
|
||||
221:[0.99609375, 0.6640625, 0.9140625],
|
||||
222:[0.73828125, 0.0, 0.55078125],
|
||||
223:[0.73828125, 0.4921875, 0.67578125],
|
||||
224:[0.50390625, 0.0, 0.375],
|
||||
225:[0.50390625, 0.3359375, 0.4609375],
|
||||
226:[0.40625, 0.0, 0.3046875],
|
||||
227:[0.40625, 0.26953125, 0.37109375],
|
||||
228:[0.30859375, 0.0, 0.23046875],
|
||||
229:[0.30859375, 0.20703125, 0.28515625],
|
||||
230:[0.99609375, 0.0, 0.49609375],
|
||||
231:[0.99609375, 0.6640625, 0.828125],
|
||||
232:[0.73828125, 0.0, 0.3671875],
|
||||
233:[0.73828125, 0.4921875, 0.61328125],
|
||||
234:[0.50390625, 0.0, 0.25],
|
||||
235:[0.50390625, 0.3359375, 0.41796875],
|
||||
236:[0.40625, 0.0, 0.203125],
|
||||
237:[0.40625, 0.26953125, 0.3359375],
|
||||
238:[0.30859375, 0.0, 0.15234375],
|
||||
239:[0.30859375, 0.20703125, 0.2578125],
|
||||
240:[0.99609375, 0.0, 0.24609375],
|
||||
241:[0.99609375, 0.6640625, 0.74609375],
|
||||
242:[0.73828125, 0.0, 0.1796875],
|
||||
243:[0.73828125, 0.4921875, 0.55078125],
|
||||
244:[0.50390625, 0.0, 0.12109375],
|
||||
245:[0.50390625, 0.3359375, 0.375],
|
||||
246:[0.40625, 0.0, 0.09765625],
|
||||
247:[0.40625, 0.26953125, 0.3046875],
|
||||
248:[0.30859375, 0.0, 0.07421875],
|
||||
249:[0.30859375, 0.20703125, 0.23046875],
|
||||
250:[0.19921875, 0.19921875, 0.19921875],
|
||||
251:[0.3125, 0.3125, 0.3125],
|
||||
252:[0.41015625, 0.41015625, 0.41015625],
|
||||
253:[0.5078125, 0.5078125, 0.5078125],
|
||||
254:[0.7421875, 0.7421875, 0.7421875],
|
||||
255:[0.99609375, 0.99609375, 0.99609375],
|
||||
}
|
||||
@@ -1,880 +0,0 @@
|
||||
#dxfLibrary.py : provides functions for generating DXF files
|
||||
# --------------------------------------------------------------------------
|
||||
__version__ = "v1.33 - 2009.06.16"
|
||||
__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)"
|
||||
__license__ = "GPL"
|
||||
__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf"
|
||||
__bpydoc__ ="""The library to export geometry data to DXF format r12 version.
|
||||
|
||||
Copyright %s
|
||||
Version %s
|
||||
License %s
|
||||
Homepage %s
|
||||
|
||||
See the homepage for documentation.
|
||||
Dedicated thread on BlenderArtists: http://blenderartists.org/forum/showthread.php?t=136439
|
||||
|
||||
IDEAs:
|
||||
-
|
||||
|
||||
TODO:
|
||||
- add support for DXFr14 (needs extended file header)
|
||||
- add support for SPLINEs (possible first in DXFr14 version)
|
||||
- add user preset for floating point precision (3-16?)
|
||||
|
||||
History
|
||||
v1.33 - 2009.06.16 by migius
|
||||
- modif _point(): converts all coords to floats
|
||||
- modif LineType class: implement elements
|
||||
- added VPORT class, incl. defaults
|
||||
- fix Insert class
|
||||
v1.32 - 2009.06.06 by migius
|
||||
- modif Style class: changed defaults to widthFactor=1.0, obliqueAngle=0.0
|
||||
- modif Text class: alignment parameter reactivated
|
||||
v1.31 - 2009.06.02 by migius
|
||||
- modif _Entity class: added paperspace,elevation
|
||||
v1.30 - 2009.05.28 by migius
|
||||
- bugfix 3dPOLYLINE/POLYFACE: VERTEX needs x,y,z coordinates, index starts with 1 not 0
|
||||
v1.29 - 2008.12.28 by Yorik
|
||||
- modif POLYLINE to support bulge segments
|
||||
v1.28 - 2008.12.13 by Steeve/BlenderArtists
|
||||
- bugfix for EXTMIN/EXTMAX to suit Cycas-CAD
|
||||
v1.27 - 2008.10.07 by migius
|
||||
- beautifying output code: keys whitespace prefix
|
||||
- refactoring DXF-strings format: NewLine moved to the end of
|
||||
v1.26 - 2008.10.05 by migius
|
||||
- modif POLYLINE to support POLYFACE
|
||||
v1.25 - 2008.09.28 by migius
|
||||
- modif FACE class for r12
|
||||
v1.24 - 2008.09.27 by migius
|
||||
- modif POLYLINE class for r12
|
||||
- changing output format from r9 to r12(AC1009)
|
||||
v1.1 (20/6/2005) by www.stani.be/python/sdxf
|
||||
- Python library to generate dxf drawings
|
||||
______________________________________________________________
|
||||
""" % (__author__,__version__,__license__,__url__)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# DXF Library: copyright (C) 2005 by Stani Michiels (AKA Stani)
|
||||
# 2008/2009 modif by Remigiusz Fiedler (AKA migius)
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
|
||||
|
||||
#import Blender
|
||||
#from Blender import Mathutils, Window, Scene, sys, Draw
|
||||
#import BPyMessages
|
||||
|
||||
try:
|
||||
import copy
|
||||
#from struct import pack
|
||||
except:
|
||||
copy = None
|
||||
|
||||
####1) Private (only for developpers)
|
||||
_HEADER_POINTS=['insbase','extmin','extmax']
|
||||
|
||||
#---helper functions-----------------------------------
|
||||
def _point(x,index=0):
|
||||
"""Convert tuple to a dxf point"""
|
||||
#print 'deb: _point=', x #-------------
|
||||
return '\n'.join([' %s\n%s'%((i+1)*10+index,float(x[i])) for i in range(len(x))])
|
||||
|
||||
def _points(plist):
|
||||
"""Convert a list of tuples to dxf points"""
|
||||
out = '\n'.join([_point(plist[i],i)for i in range(len(plist))])
|
||||
return out
|
||||
|
||||
#---base classes----------------------------------------
|
||||
class _Call:
|
||||
"""Makes a callable class."""
|
||||
def copy(self):
|
||||
"""Returns a copy."""
|
||||
return copy.deepcopy(self)
|
||||
|
||||
def __call__(self,**attrs):
|
||||
"""Returns a copy with modified attributes."""
|
||||
copied=self.copy()
|
||||
for attr in attrs:setattr(copied,attr,attrs[attr])
|
||||
return copied
|
||||
|
||||
#-------------------------------------------------------
|
||||
class _Entity(_Call):
|
||||
"""Base class for _common group codes for entities."""
|
||||
def __init__(self,paperspace=None,color=None,layer='0',
|
||||
lineType=None,lineTypeScale=None,lineWeight=None,
|
||||
extrusion=None,elevation=None,thickness=None,
|
||||
parent=None):
|
||||
"""None values will be omitted."""
|
||||
self.paperspace = paperspace
|
||||
self.color = color
|
||||
self.layer = layer
|
||||
self.lineType = lineType
|
||||
self.lineTypeScale = lineTypeScale
|
||||
self.lineWeight = lineWeight
|
||||
self.extrusion = extrusion
|
||||
self.elevation = elevation
|
||||
self.thickness = thickness
|
||||
#self.visible = visible
|
||||
self.parent = parent
|
||||
|
||||
def _common(self):
|
||||
"""Return common group codes as a string."""
|
||||
if self.parent:parent=self.parent
|
||||
else:parent=self
|
||||
result =''
|
||||
if parent.paperspace==1: result+=' 67\n1\n'
|
||||
if parent.layer!=None: result+=' 8\n%s\n'%parent.layer
|
||||
if parent.color!=None: result+=' 62\n%s\n'%parent.color
|
||||
if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType
|
||||
# TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight
|
||||
# TODO: if parent.visible!=None: result+='60\n%s\n'%parent.visible
|
||||
if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale
|
||||
if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation
|
||||
if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness
|
||||
if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200)
|
||||
return result
|
||||
|
||||
#--------------------------
|
||||
class _Entities:
|
||||
"""Base class to deal with composed objects."""
|
||||
def __dxf__(self):
|
||||
return []
|
||||
|
||||
def __str__(self):
|
||||
return ''.join([str(x) for x in self.__dxf__()])
|
||||
|
||||
#--------------------------
|
||||
class _Collection(_Call):
|
||||
"""Base class to expose entities methods to main object."""
|
||||
def __init__(self,entities=[]):
|
||||
self.entities=copy.copy(entities)
|
||||
#link entities methods to drawing
|
||||
for attr in dir(self.entities):
|
||||
if attr[0]!='_':
|
||||
attrObject=getattr(self.entities,attr)
|
||||
if callable(attrObject):
|
||||
setattr(self,attr,attrObject)
|
||||
|
||||
####2) Constants
|
||||
#---color values
|
||||
BYBLOCK=0
|
||||
BYLAYER=256
|
||||
|
||||
#---block-type flags (bit coded values, may be combined):
|
||||
ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application
|
||||
NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all)
|
||||
XREF =4 # This block is an external reference (xref)
|
||||
XREF_OVERLAY =8 # This block is an xref overlay
|
||||
EXTERNAL =16 # This block is externally dependent
|
||||
RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input)
|
||||
REFERENCED =64 # This definition is a referenced external reference (ignored on input)
|
||||
|
||||
#---mtext flags
|
||||
#attachment point
|
||||
TOP_LEFT = 1
|
||||
TOP_CENTER = 2
|
||||
TOP_RIGHT = 3
|
||||
MIDDLE_LEFT = 4
|
||||
MIDDLE_CENTER = 5
|
||||
MIDDLE_RIGHT = 6
|
||||
BOTTOM_LEFT = 7
|
||||
BOTTOM_CENTER = 8
|
||||
BOTTOM_RIGHT = 9
|
||||
#drawing direction
|
||||
LEFT_RIGHT = 1
|
||||
TOP_BOTTOM = 3
|
||||
BY_STYLE = 5 #the flow direction is inherited from the associated text style
|
||||
#line spacing style (optional):
|
||||
AT_LEAST = 1 #taller characters will override
|
||||
EXACT = 2 #taller characters will not override
|
||||
|
||||
#---polyline flags
|
||||
CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction)
|
||||
CURVE_FIT =2 # Curve-fit vertices have been added
|
||||
SPLINE_FIT =4 # Spline-fit vertices have been added
|
||||
POLYLINE_3D =8 # This is a 3D polyline
|
||||
POLYGON_MESH =16 # This is a 3D polygon mesh
|
||||
CLOSED_N =32 # The polygon mesh is closed in the N direction
|
||||
POLYFACE_MESH =64 # The polyline is a polyface mesh
|
||||
CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline
|
||||
|
||||
#---text flags
|
||||
#horizontal
|
||||
LEFT = 0
|
||||
CENTER = 1
|
||||
RIGHT = 2
|
||||
ALIGNED = 3 #if vertical alignment = 0
|
||||
MIDDLE = 4 #if vertical alignment = 0
|
||||
FIT = 5 #if vertical alignment = 0
|
||||
#vertical
|
||||
BASELINE = 0
|
||||
BOTTOM = 1
|
||||
MIDDLE = 2
|
||||
TOP = 3
|
||||
|
||||
####3) Classes
|
||||
#---entitities -----------------------------------------------
|
||||
#--------------------------
|
||||
class Arc(_Entity):
|
||||
"""Arc, angles in degrees."""
|
||||
def __init__(self,center=(0,0,0),radius=1,
|
||||
startAngle=0.0,endAngle=90,**common):
|
||||
"""Angles in degrees."""
|
||||
_Entity.__init__(self,**common)
|
||||
self.center=center
|
||||
self.radius=radius
|
||||
self.startAngle=startAngle
|
||||
self.endAngle=endAngle
|
||||
def __str__(self):
|
||||
return ' 0\nARC\n%s%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\
|
||||
(self._common(),_point(self.center),
|
||||
self.radius,self.startAngle,self.endAngle)
|
||||
|
||||
#-----------------------------------------------
|
||||
class Circle(_Entity):
|
||||
"""Circle"""
|
||||
def __init__(self,center=(0,0,0),radius=1,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.center=center
|
||||
self.radius=radius
|
||||
def __str__(self):
|
||||
return ' 0\nCIRCLE\n%s%s\n 40\n%s\n'%\
|
||||
(self._common(),_point(self.center),self.radius)
|
||||
|
||||
#-----------------------------------------------
|
||||
class Face(_Entity):
|
||||
"""3dface"""
|
||||
def __init__(self,points,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
while len(points)<4: #fix for r12 format
|
||||
points.append(points[-1])
|
||||
self.points=points
|
||||
|
||||
def __str__(self):
|
||||
out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points))
|
||||
#print 'deb:out=', out #-------------------
|
||||
return out
|
||||
|
||||
#-----------------------------------------------
|
||||
class Insert(_Entity):
|
||||
"""Block instance."""
|
||||
def __init__(self,name,point=(0,0,0),
|
||||
xscale=None,yscale=None,zscale=None,
|
||||
cols=None,colspacing=None,rows=None,rowspacing=None,
|
||||
rotation=None,
|
||||
**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.name=name
|
||||
self.point=point
|
||||
self.xscale=xscale
|
||||
self.yscale=yscale
|
||||
self.zscale=zscale
|
||||
self.cols=cols
|
||||
self.colspacing=colspacing
|
||||
self.rows=rows
|
||||
self.rowspacing=rowspacing
|
||||
self.rotation=rotation
|
||||
|
||||
def __str__(self):
|
||||
result=' 0\nINSERT\n 2\n%s\n%s%s\n'%\
|
||||
(self.name,self._common(),_point(self.point))
|
||||
if self.xscale!=None:result+=' 41\n%s\n'%self.xscale
|
||||
if self.yscale!=None:result+=' 42\n%s\n'%self.yscale
|
||||
if self.zscale!=None:result+=' 43\n%s\n'%self.zscale
|
||||
if self.rotation:result+=' 50\n%s\n'%self.rotation
|
||||
if self.cols!=None:result+=' 70\n%s\n'%self.cols
|
||||
if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing
|
||||
if self.rows!=None:result+=' 71\n%s\n'%self.rows
|
||||
if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing
|
||||
return result
|
||||
|
||||
#-----------------------------------------------
|
||||
class Line(_Entity):
|
||||
"""Line"""
|
||||
def __init__(self,points,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.points=points
|
||||
def __str__(self):
|
||||
return ' 0\nLINE\n%s%s\n' %(
|
||||
self._common(), _points(self.points))
|
||||
|
||||
|
||||
#-----------------------------------------------
|
||||
class PolyLine(_Entity):
|
||||
def __init__(self,points,org_point=[0,0,0],flag=0,width=None,**common):
|
||||
#width = number, or width = list [width_start=None, width_end=None]
|
||||
#for 2d-polyline: points = [ [x, y, z, width_start=None, width_end=None, bulge=0 or None], ...]
|
||||
#for 3d-polyline: points = [ [x, y, z], ...]
|
||||
#for polyface: points = [points_list, faces_list]
|
||||
_Entity.__init__(self,**common)
|
||||
self.points=points
|
||||
self.org_point=org_point
|
||||
self.flag=flag
|
||||
self.polyface = False
|
||||
self.polyline2d = False
|
||||
self.faces = [] # dummy value
|
||||
self.width= None # dummy value
|
||||
if self.flag & POLYFACE_MESH:
|
||||
self.polyface=True
|
||||
self.points=points[0]
|
||||
self.faces=points[1]
|
||||
self.p_count=len(self.points)
|
||||
self.f_count=len(self.faces)
|
||||
elif not self.flag & POLYLINE_3D:
|
||||
self.polyline2d = True
|
||||
if width:
|
||||
if type(width)!='list':
|
||||
width=[width,width]
|
||||
self.width=width
|
||||
|
||||
def __str__(self):
|
||||
result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.flag)
|
||||
result+=' 66\n1\n'
|
||||
result+='%s\n' %_point(self.org_point)
|
||||
if self.polyface:
|
||||
result+=' 71\n%s\n' %self.p_count
|
||||
result+=' 72\n%s\n' %self.f_count
|
||||
elif self.polyline2d:
|
||||
if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1])
|
||||
for point in self.points:
|
||||
result+=' 0\nVERTEX\n'
|
||||
result+=' 8\n%s\n' %self.layer
|
||||
if self.polyface:
|
||||
result+='%s\n' %_point(point[0:3])
|
||||
result+=' 70\n192\n'
|
||||
elif self.polyline2d:
|
||||
result+='%s\n' %_point(point[0:2])
|
||||
if len(point)>4:
|
||||
width1, width2 = point[3], point[4]
|
||||
if width1!=None: result+=' 40\n%s\n' %width1
|
||||
if width2!=None: result+=' 41\n%s\n' %width2
|
||||
if len(point)==6:
|
||||
bulge = point[5]
|
||||
if bulge: result+=' 42\n%s\n' %bulge
|
||||
else:
|
||||
result+='%s\n' %_point(point[0:3])
|
||||
for face in self.faces:
|
||||
result+=' 0\nVERTEX\n'
|
||||
result+=' 8\n%s\n' %self.layer
|
||||
result+='%s\n' %_point(self.org_point)
|
||||
result+=' 70\n128\n'
|
||||
result+=' 71\n%s\n' %face[0]
|
||||
result+=' 72\n%s\n' %face[1]
|
||||
result+=' 73\n%s\n' %face[2]
|
||||
if len(face)==4: result+=' 74\n%s\n' %face[3]
|
||||
result+=' 0\nSEQEND\n'
|
||||
result+=' 8\n%s\n' %self.layer
|
||||
return result
|
||||
|
||||
#-----------------------------------------------
|
||||
class Point(_Entity):
|
||||
"""Point."""
|
||||
def __init__(self,points=None,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.points=points
|
||||
def __str__(self): # TODO:
|
||||
return ' 0\nPOINT\n%s%s\n' %(self._common(),
|
||||
_points(self.points)
|
||||
)
|
||||
|
||||
#-----------------------------------------------
|
||||
class Solid(_Entity):
|
||||
"""Colored solid fill."""
|
||||
def __init__(self,points=None,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.points=points
|
||||
def __str__(self):
|
||||
return ' 0\nSOLID\n%s%s\n' %(self._common(),
|
||||
_points(self.points[:2]+[self.points[3],self.points[2]])
|
||||
)
|
||||
|
||||
|
||||
#-----------------------------------------------
|
||||
class Text(_Entity):
|
||||
"""Single text line."""
|
||||
def __init__(self,text='',point=(0,0,0),alignment=None,
|
||||
flag=None,height=1,justifyhor=None,justifyver=None,
|
||||
rotation=None,obliqueAngle=None,style=None,xscale=None,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.text=text
|
||||
self.point=point
|
||||
self.alignment=alignment
|
||||
self.flag=flag
|
||||
self.height=height
|
||||
self.justifyhor=justifyhor
|
||||
self.justifyver=justifyver
|
||||
self.rotation=rotation
|
||||
self.obliqueAngle=obliqueAngle
|
||||
self.style=style
|
||||
self.xscale=xscale
|
||||
def __str__(self):
|
||||
result= ' 0\nTEXT\n%s%s\n 40\n%s\n 1\n%s\n'%\
|
||||
(self._common(),_point(self.point),self.height,self.text)
|
||||
if self.rotation: result+=' 50\n%s\n'%self.rotation
|
||||
if self.xscale: result+=' 41\n%s\n'%self.xscale
|
||||
if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle
|
||||
if self.style: result+=' 7\n%s\n'%self.style
|
||||
if self.flag: result+=' 71\n%s\n'%self.flag
|
||||
if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor
|
||||
if self.alignment: result+='%s\n'%_point(self.alignment,1)
|
||||
if self.justifyver: result+=' 73\n%s\n'%self.justifyver
|
||||
return result
|
||||
|
||||
#-----------------------------------------------
|
||||
class Mtext(Text):
|
||||
"""Surrogate for mtext, generates some Text instances."""
|
||||
def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options):
|
||||
Text.__init__(self,text=text,point=point,**options)
|
||||
if down:spacingFactor*=-1
|
||||
self.spacingFactor=spacingFactor
|
||||
self.spacingWidth=spacingWidth
|
||||
self.width=width
|
||||
self.down=down
|
||||
def __str__(self):
|
||||
texts=self.text.replace('\r\n','\n').split('\n')
|
||||
if not self.down:texts.reverse()
|
||||
result=''
|
||||
x=y=0
|
||||
if self.spacingWidth:spacingWidth=self.spacingWidth
|
||||
else:spacingWidth=self.height*self.spacingFactor
|
||||
for text in texts:
|
||||
while text:
|
||||
result+='%s\n'%Text(text[:self.width],
|
||||
point=(self.point[0]+x*spacingWidth,
|
||||
self.point[1]+y*spacingWidth,
|
||||
self.point[2]),
|
||||
alignment=self.alignment,flag=self.flag,height=self.height,
|
||||
justifyhor=self.justifyhor,justifyver=self.justifyver,
|
||||
rotation=self.rotation,obliqueAngle=self.obliqueAngle,
|
||||
style=self.style,xscale=self.xscale,parent=self
|
||||
)
|
||||
text=text[self.width:]
|
||||
if self.rotation:x+=1
|
||||
else:y+=1
|
||||
return result[1:]
|
||||
|
||||
#-----------------------------------------------
|
||||
##class _Mtext(_Entity):
|
||||
## """Mtext not functioning for minimal dxf."""
|
||||
## def __init__(self,text='',point=(0,0,0),attachment=1,
|
||||
## charWidth=None,charHeight=1,direction=1,height=100,rotation=0,
|
||||
## spacingStyle=None,spacingFactor=None,style=None,width=100,
|
||||
## xdirection=None,**common):
|
||||
## _Entity.__init__(self,**common)
|
||||
## self.text=text
|
||||
## self.point=point
|
||||
## self.attachment=attachment
|
||||
## self.charWidth=charWidth
|
||||
## self.charHeight=charHeight
|
||||
## self.direction=direction
|
||||
## self.height=height
|
||||
## self.rotation=rotation
|
||||
## self.spacingStyle=spacingStyle
|
||||
## self.spacingFactor=spacingFactor
|
||||
## self.style=style
|
||||
## self.width=width
|
||||
## self.xdirection=xdirection
|
||||
## def __str__(self):
|
||||
## input=self.text
|
||||
## text=''
|
||||
## while len(input)>250:
|
||||
## text+='3\n%s\n'%input[:250]
|
||||
## input=input[250:]
|
||||
## text+='1\n%s\n'%input
|
||||
## result= '0\nMTEXT\n%s\n%s\n40\n%s\n41\n%s\n71\n%s\n72\n%s%s\n43\n%s\n50\n%s\n'%\
|
||||
## (self._common(),_point(self.point),self.charHeight,self.width,
|
||||
## self.attachment,self.direction,text,
|
||||
## self.height,
|
||||
## self.rotation)
|
||||
## if self.style:result+='7\n%s\n'%self.style
|
||||
## if self.xdirection:result+='%s\n'%_point(self.xdirection,1)
|
||||
## if self.charWidth:result+='42\n%s\n'%self.charWidth
|
||||
## if self.spacingStyle:result+='73\n%s\n'%self.spacingStyle
|
||||
## if self.spacingFactor:result+='44\n%s\n'%self.spacingFactor
|
||||
## return result
|
||||
|
||||
#---tables ---------------------------------------------------
|
||||
#-----------------------------------------------
|
||||
class Block(_Collection):
|
||||
"""Use list methods to add entities, eg append."""
|
||||
def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]):
|
||||
self.entities=copy.copy(entities)
|
||||
_Collection.__init__(self,entities)
|
||||
self.layer=layer
|
||||
self.name=name
|
||||
self.flag=0
|
||||
self.base=base
|
||||
def __str__(self): # TODO:
|
||||
e=''.join([str(x)for x in self.entities])
|
||||
return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\
|
||||
(self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e)
|
||||
|
||||
#-----------------------------------------------
|
||||
class Layer(_Call):
|
||||
"""Layer"""
|
||||
def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64):
|
||||
self.name=name
|
||||
self.color=color
|
||||
self.lineType=lineType
|
||||
self.flag=flag
|
||||
def __str__(self):
|
||||
return ' 0\nLAYER\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\
|
||||
(self.name.upper(),self.flag,self.color,self.lineType)
|
||||
|
||||
#-----------------------------------------------
|
||||
class LineType(_Call):
|
||||
"""Custom linetype"""
|
||||
def __init__(self,name='CONTINUOUS',description='Solid line',elements=[0.0],flag=0):
|
||||
self.name=name
|
||||
self.description=description
|
||||
self.elements=copy.copy(elements)
|
||||
self.flag=flag
|
||||
def __str__(self):
|
||||
result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\
|
||||
(self.name.upper(),self.flag,self.description)
|
||||
if self.elements:
|
||||
elements = ' 73\n%s\n' %(len(self.elements)-1)
|
||||
elements += ' 40\n%s\n' %(self.elements[0])
|
||||
for e in self.elements[1:]:
|
||||
elements += ' 49\n%s\n' %e
|
||||
result += elements
|
||||
return result
|
||||
|
||||
|
||||
#-----------------------------------------------
|
||||
class Style(_Call):
|
||||
"""Text style"""
|
||||
def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0,
|
||||
mirror=0,lastHeight=1,font='arial.ttf',bigFont=''):
|
||||
self.name=name
|
||||
self.flag=flag
|
||||
self.height=height
|
||||
self.widthFactor=widthFactor
|
||||
self.obliqueAngle=obliqueAngle
|
||||
self.mirror=mirror
|
||||
self.lastHeight=lastHeight
|
||||
self.font=font
|
||||
self.bigFont=bigFont
|
||||
def __str__(self):
|
||||
return ' 0\nSTYLE\n 2\n%s\n 70\n%s\n 40\n%s\n 41\n%s\n 50\n%s\n 71\n%s\n 42\n%s\n 3\n%s\n 4\n%s\n'%\
|
||||
(self.name.upper(),self.flag,self.flag,self.widthFactor,
|
||||
self.obliqueAngle,self.mirror,self.lastHeight,
|
||||
self.font.upper(),self.bigFont.upper())
|
||||
|
||||
#-----------------------------------------------
|
||||
class VPort(_Call):
|
||||
def __init__(self,name,flag=0,
|
||||
leftBottom=(0.0,0.0),
|
||||
rightTop=(1.0,1.0),
|
||||
center=(0.5,0.5),
|
||||
snap_base=(0.0,0.0),
|
||||
snap_spacing=(0.1,0.1),
|
||||
grid_spacing=(0.1,0.1),
|
||||
direction=(0.0,0.0,1.0),
|
||||
target=(0.0,0.0,0.0),
|
||||
height=1.0,
|
||||
ratio=1.0,
|
||||
lens=50,
|
||||
frontClipping=0,
|
||||
backClipping=0,
|
||||
snap_rotation=0,
|
||||
twist=0,
|
||||
mode=0,
|
||||
circle_zoom=100,
|
||||
fast_zoom=1,
|
||||
ucsicon=1,
|
||||
snap_on=0,
|
||||
grid_on=0,
|
||||
snap_style=0,
|
||||
snap_isopair=0
|
||||
):
|
||||
self.name=name
|
||||
self.flag=flag
|
||||
self.leftBottom=leftBottom
|
||||
self.rightTop=rightTop
|
||||
self.center=center
|
||||
self.snap_base=snap_base
|
||||
self.snap_spacing=snap_spacing
|
||||
self.grid_spacing=grid_spacing
|
||||
self.direction=direction
|
||||
self.target=target
|
||||
self.height=float(height)
|
||||
self.ratio=float(ratio)
|
||||
self.lens=float(lens)
|
||||
self.frontClipping=float(frontClipping)
|
||||
self.backClipping=float(backClipping)
|
||||
self.snap_rotation=float(snap_rotation)
|
||||
self.twist=float(twist)
|
||||
self.mode=mode
|
||||
self.circle_zoom=circle_zoom
|
||||
self.fast_zoom=fast_zoom
|
||||
self.ucsicon=ucsicon
|
||||
self.snap_on=snap_on
|
||||
self.grid_on=grid_on
|
||||
self.snap_style=snap_style
|
||||
self.snap_isopair=snap_isopair
|
||||
def __str__(self):
|
||||
output = [' 0', 'VPORT',
|
||||
' 2', self.name,
|
||||
' 70', self.flag,
|
||||
_point(self.leftBottom),
|
||||
_point(self.rightTop,1),
|
||||
_point(self.center,2), # View center point (in DCS)
|
||||
_point(self.snap_base,3),
|
||||
_point(self.snap_spacing,4),
|
||||
_point(self.grid_spacing,5),
|
||||
_point(self.direction,6), #view direction from target (in WCS)
|
||||
_point(self.target,7),
|
||||
' 40', self.height,
|
||||
' 41', self.ratio,
|
||||
' 42', self.lens,
|
||||
' 43', self.frontClipping,
|
||||
' 44', self.backClipping,
|
||||
' 50', self.snap_rotation,
|
||||
' 51', self.twist,
|
||||
' 71', self.mode,
|
||||
' 72', self.circle_zoom,
|
||||
' 73', self.fast_zoom,
|
||||
' 74', self.ucsicon,
|
||||
' 75', self.snap_on,
|
||||
' 76', self.grid_on,
|
||||
' 77', self.snap_style,
|
||||
' 78', self.snap_isopair
|
||||
]
|
||||
|
||||
output_str = ''
|
||||
for s in output:
|
||||
output_str += '%s\n' %s
|
||||
return output_str
|
||||
|
||||
|
||||
|
||||
#-----------------------------------------------
|
||||
class View(_Call):
|
||||
def __init__(self,name,flag=0,
|
||||
width=1,
|
||||
height=1,
|
||||
center=(0.5,0.5),
|
||||
direction=(0,0,1),
|
||||
target=(0,0,0),
|
||||
lens=50,
|
||||
frontClipping=0,
|
||||
backClipping=0,
|
||||
twist=0,mode=0
|
||||
):
|
||||
self.name=name
|
||||
self.flag=flag
|
||||
self.width=float(width)
|
||||
self.height=float(height)
|
||||
self.center=center
|
||||
self.direction=direction
|
||||
self.target=target
|
||||
self.lens=float(lens)
|
||||
self.frontClipping=float(frontClipping)
|
||||
self.backClipping=float(backClipping)
|
||||
self.twist=float(twist)
|
||||
self.mode=mode
|
||||
def __str__(self):
|
||||
output = [' 0', 'VIEW',
|
||||
' 2', self.name,
|
||||
' 70', self.flag,
|
||||
' 40', self.height,
|
||||
_point(self.center),
|
||||
' 41', self.width,
|
||||
_point(self.direction,1),
|
||||
_point(self.target,2),
|
||||
' 42', self.lens,
|
||||
' 43', self.frontClipping,
|
||||
' 44', self.backClipping,
|
||||
' 50', self.twist,
|
||||
' 71', self.mode
|
||||
]
|
||||
output_str = ''
|
||||
for s in output:
|
||||
output_str += '%s\n' %s
|
||||
return output_str
|
||||
|
||||
#-----------------------------------------------
|
||||
def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options):
|
||||
width=abs(rightTop[0]-leftBottom[0])
|
||||
height=abs(rightTop[1]-leftBottom[1])
|
||||
center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5)
|
||||
return View(name=name,width=width,height=height,center=center,**options)
|
||||
|
||||
#---drawing
|
||||
#-----------------------------------------------
|
||||
class Drawing(_Collection):
|
||||
"""Dxf drawing. Use append or any other list methods to add objects."""
|
||||
def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0,0.0),extmax=(0.0,0.0,0.0),
|
||||
layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[],
|
||||
views=[],vports=[],entities=None,fileName='test.dxf'):
|
||||
# TODO: replace list with None,arial
|
||||
if not entities:
|
||||
entities=[]
|
||||
_Collection.__init__(self,entities)
|
||||
self.insbase=insbase
|
||||
self.extmin=extmin
|
||||
self.extmax=extmax
|
||||
self.layers=copy.copy(layers)
|
||||
self.linetypes=copy.copy(linetypes)
|
||||
self.styles=copy.copy(styles)
|
||||
self.views=copy.copy(views)
|
||||
self.vports=copy.copy(vports)
|
||||
self.blocks=copy.copy(blocks)
|
||||
self.fileName=fileName
|
||||
#private
|
||||
#self.acadver='9\n$ACADVER\n1\nAC1006\n'
|
||||
self.acadver=' 9\n$ACADVER\n 1\nAC1009\n'
|
||||
"""DXF AutoCAD-Release format codes
|
||||
AC1021 2008, 2007
|
||||
AC1018 2006, 2005, 2004
|
||||
AC1015 2002, 2000i, 2000
|
||||
AC1014 R14,14.01
|
||||
AC1012 R13
|
||||
AC1009 R12,11
|
||||
AC1006 R10
|
||||
AC1004 R9
|
||||
AC1002 R2.6
|
||||
AC1.50 R2.05
|
||||
"""
|
||||
|
||||
def _name(self,x):
|
||||
"""Helper function for self._point"""
|
||||
return ' 9\n$%s\n' %x.upper()
|
||||
|
||||
def _point(self,name,x):
|
||||
"""Point setting from drawing like extmin,extmax,..."""
|
||||
return '%s%s' %(self._name(name),_point(x))
|
||||
|
||||
def _section(self,name,x):
|
||||
"""Sections like tables,blocks,entities,..."""
|
||||
if x: xstr=''.join(x)
|
||||
else: xstr=''
|
||||
return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr)
|
||||
|
||||
def _table(self,name,x):
|
||||
"""Tables like ltype,layer,style,..."""
|
||||
if x: xstr=''.join(x)
|
||||
else: xstr=''
|
||||
return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr)
|
||||
|
||||
def __str__(self):
|
||||
"""Returns drawing as dxf string."""
|
||||
header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS]
|
||||
header=self._section('header',header)
|
||||
|
||||
tables=[self._table('vport',[str(x) for x in self.vports]),
|
||||
self._table('ltype',[str(x) for x in self.linetypes]),
|
||||
self._table('layer',[str(x) for x in self.layers]),
|
||||
self._table('style',[str(x) for x in self.styles]),
|
||||
self._table('view',[str(x) for x in self.views]),
|
||||
]
|
||||
tables=self._section('tables',tables)
|
||||
|
||||
blocks=self._section('blocks',[str(x) for x in self.blocks])
|
||||
|
||||
entities=self._section('entities',[str(x) for x in self.entities])
|
||||
|
||||
all=''.join([header,tables,blocks,entities,' 0\nEOF\n'])
|
||||
return all
|
||||
|
||||
def saveas(self,fileName):
|
||||
self.fileName=fileName
|
||||
self.save()
|
||||
|
||||
def save(self):
|
||||
test=open(self.fileName,'w')
|
||||
test.write(str(self))
|
||||
test.close()
|
||||
|
||||
|
||||
#---extras
|
||||
#-----------------------------------------------
|
||||
class Rectangle(_Entity):
|
||||
"""Rectangle, creates lines."""
|
||||
def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.point=point
|
||||
self.width=width
|
||||
self.height=height
|
||||
self.solid=solid
|
||||
self.line=line
|
||||
def __str__(self):
|
||||
result=''
|
||||
points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]),
|
||||
(self.point[0]+self.width,self.point[1]+self.height,self.point[2]),
|
||||
(self.point[0],self.point[1]+self.height,self.point[2]),self.point]
|
||||
if self.solid:
|
||||
result+= Solid(points=points[:-1],parent=self.solid)
|
||||
if self.line:
|
||||
for i in range(4):
|
||||
result+= Line(points=[points[i],points[i+1]],parent=self)
|
||||
return result[1:]
|
||||
|
||||
#-----------------------------------------------
|
||||
class LineList(_Entity):
|
||||
"""Like polyline, but built of individual lines."""
|
||||
def __init__(self,points=[],org_point=[0,0,0],closed=0,**common):
|
||||
_Entity.__init__(self,**common)
|
||||
self.closed=closed
|
||||
self.points=copy.copy(points)
|
||||
def __str__(self):
|
||||
if self.closed:points=self.points+[self.points[0]]
|
||||
else: points=self.points
|
||||
result=''
|
||||
for i in range(len(points)-1):
|
||||
result+= Line(points=[points[i],points[i+1]],parent=self)
|
||||
return result[1:]
|
||||
|
||||
#-----------------------------------------------------
|
||||
def test():
|
||||
#Blocks
|
||||
b=Block('test')
|
||||
b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1))
|
||||
b.append(Arc(center=(1,0,0),color=2))
|
||||
|
||||
#Drawing
|
||||
d=Drawing()
|
||||
#tables
|
||||
d.blocks.append(b) #table blocks
|
||||
d.styles.append(Style()) #table styles
|
||||
d.views.append(View('Normal')) #table view
|
||||
d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1))) #idem
|
||||
|
||||
#entities
|
||||
d.append(Circle(center=(1,1,0),color=3))
|
||||
d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4))
|
||||
d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2))
|
||||
d.append(Line(points=[(0,0,0),(1,1,1)]))
|
||||
d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90))
|
||||
d.append(Text('Please donate!',point=(3,0,1)))
|
||||
#d.append(Rectangle(point=(2,2,2),width=4,height=3,color=6,solid=Solid(color=2)))
|
||||
d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3))
|
||||
#d.append(PolyLine(points=[(1,1,1),(2,1,1),(2,2,1),(1,2,1)],flag=1,color=1))
|
||||
|
||||
#d.saveas('c:\\test.dxf')
|
||||
d.saveas('test.dxf')
|
||||
|
||||
#-----------------------------------------------------
|
||||
if __name__=='__main__':
|
||||
if not copy:
|
||||
Draw.PupMenu('Error%t|This script requires a full python install')
|
||||
else: test()
|
||||
|
||||
@@ -1,381 +0,0 @@
|
||||
"""This module provides a function for reading dxf files and parsing them into a useful tree of objects and data.
|
||||
|
||||
The convert function is called by the readDXF fuction to convert dxf strings into the correct data based
|
||||
on their type code. readDXF expects a (full path) file name as input.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# DXF Reader v0.9 by Ed Blake (AKA Kitsu)
|
||||
# 2008.05.08 modif.def convert() by Remigiusz Fiedler (AKA migius)
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
#from dxfImportObjects import *
|
||||
|
||||
class Object:
|
||||
"""Empty container class for dxf objects"""
|
||||
|
||||
def __init__(self, _type='', block=False):
|
||||
"""_type expects a string value."""
|
||||
self.type = _type
|
||||
self.name = ''
|
||||
self.data = []
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
return self.name
|
||||
else:
|
||||
return self.type
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.data)
|
||||
|
||||
def get_type(self, kind=''):
|
||||
"""Despite the name, this method actually returns all objects of type 'kind' from self.data."""
|
||||
if type:
|
||||
objects = []
|
||||
for item in self.data:
|
||||
if type(item) != list and item.type == kind:
|
||||
# we want this type of object
|
||||
objects.append(item)
|
||||
elif type(item) == list and item[0] == kind:
|
||||
# we want this type of data
|
||||
objects.append(item[1])
|
||||
return objects
|
||||
|
||||
|
||||
class InitializationError(Exception): pass
|
||||
|
||||
class StateMachine:
|
||||
"""(finite) State Machine from the great David Mertz's great Charming Python article."""
|
||||
|
||||
def __init__(self):
|
||||
self.handlers = []
|
||||
self.startState = None
|
||||
self.endStates = []
|
||||
|
||||
def add_state(self, handler, end_state=0):
|
||||
"""All states and handlers are functions which return
|
||||
a state and a cargo."""
|
||||
self.handlers.append(handler)
|
||||
if end_state:
|
||||
self.endStates.append(handler)
|
||||
def set_start(self, handler):
|
||||
"""Sets the starting handler function."""
|
||||
self.startState = handler
|
||||
|
||||
|
||||
def run(self, cargo=None):
|
||||
if not self.startState:
|
||||
raise InitializationError,\
|
||||
"must call .set_start() before .run()"
|
||||
if not self.endStates:
|
||||
raise InitializationError, \
|
||||
"at least one state must be an end_state"
|
||||
handler = self.startState
|
||||
while 1:
|
||||
(newState, cargo) = handler(cargo)
|
||||
#print cargo
|
||||
if newState in self.endStates:
|
||||
return newState(cargo)
|
||||
#break
|
||||
elif newState not in self.handlers:
|
||||
raise RuntimeError, "Invalid target %s" % newState
|
||||
else:
|
||||
handler = newState
|
||||
|
||||
def get_name(data):
|
||||
"""Get the name of an object from its object data.
|
||||
|
||||
Returns a pair of (data_item, name) where data_item is the list entry where the name was found
|
||||
(the data_item can be used to remove the entry from the object data). Be sure to check
|
||||
name not None before using the returned values!
|
||||
"""
|
||||
value = None
|
||||
for item in data:
|
||||
if item[0] == 2:
|
||||
value = item[1]
|
||||
break
|
||||
return item, value
|
||||
|
||||
def get_layer(data):
|
||||
"""Expects object data as input.
|
||||
|
||||
Returns (entry, layer_name) where entry is the data item that provided the layer name.
|
||||
"""
|
||||
value = None
|
||||
for item in data:
|
||||
if item[0] == 8:
|
||||
value = item[1]
|
||||
break
|
||||
return item, value
|
||||
|
||||
|
||||
def convert(code, value):
|
||||
"""Convert a string to the correct Python type based on its dxf code.
|
||||
code types:
|
||||
ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070
|
||||
longs = 90-99, 420-429, 440-459, 1071
|
||||
floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059
|
||||
hex = 105, 310-379, 390-399
|
||||
strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009
|
||||
"""
|
||||
if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071:
|
||||
value = int(float(value))
|
||||
elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071:
|
||||
value = long(float(value))
|
||||
elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060:
|
||||
value = float(value)
|
||||
elif code == 105 or 309 < code < 380 or 389 < code < 400:
|
||||
value = int(value, 16) # should be left as string?
|
||||
else: # it's already a string so do nothing
|
||||
pass
|
||||
return value
|
||||
|
||||
|
||||
def findObject(infile, kind=''):
|
||||
"""Finds the next occurance of an object."""
|
||||
obj = False
|
||||
while 1:
|
||||
line = infile.readline()
|
||||
if not line: # readline returns '' at eof
|
||||
return False
|
||||
if not obj: # We're still looking for our object code
|
||||
if line.lower().strip() == '0':
|
||||
obj = True # found it
|
||||
else: # we are in an object definition
|
||||
if kind: # if we're looking for a particular kind
|
||||
if line.lower().strip() == kind:
|
||||
obj = Object(line.lower().strip())
|
||||
break
|
||||
else: # otherwise take anything non-numeric
|
||||
if line.lower().strip() not in string.digits:
|
||||
obj = Object(line.lower().strip())
|
||||
break
|
||||
obj = False # whether we found one or not it's time to start over
|
||||
return obj
|
||||
|
||||
def handleObject(infile):
|
||||
"""Add data to an object until end of object is found."""
|
||||
line = infile.readline()
|
||||
if line.lower().strip() == 'section':
|
||||
return 'section' # this would be a problem
|
||||
elif line.lower().strip() == 'endsec':
|
||||
return 'endsec' # this means we are done with a section
|
||||
else: # add data to the object until we find a new object
|
||||
obj = Object(line.lower().strip())
|
||||
obj.name = obj.type
|
||||
done = False
|
||||
data = []
|
||||
while not done:
|
||||
line = infile.readline()
|
||||
if not data:
|
||||
if line.lower().strip() == '0':
|
||||
#we've found an object, time to return
|
||||
return obj
|
||||
else:
|
||||
# first part is always an int
|
||||
data.append(int(line.lower().strip()))
|
||||
else:
|
||||
data.append(convert(data[0], line.strip()))
|
||||
obj.data.append(data)
|
||||
data = []
|
||||
|
||||
def handleTable(table, infile):
|
||||
"""Special handler for dealing with nested table objects."""
|
||||
item, name = get_name(table.data)
|
||||
if name: # We should always find a name
|
||||
table.data.remove(item)
|
||||
table.name = name.lower()
|
||||
# This next bit is from handleObject
|
||||
# handleObject should be generalized to work with any section like object
|
||||
while 1:
|
||||
obj = handleObject(infile)
|
||||
if obj.type == 'table':
|
||||
print "Warning: previous table not closed!"
|
||||
return table
|
||||
elif obj.type == 'endtab':
|
||||
return table # this means we are done with the table
|
||||
else: # add objects to the table until one of the above is found
|
||||
table.data.append(obj)
|
||||
|
||||
|
||||
|
||||
|
||||
def handleBlock(block, infile):
|
||||
"""Special handler for dealing with nested table objects."""
|
||||
item, name = get_name(block.data)
|
||||
if name: # We should always find a name
|
||||
block.data.remove(item)
|
||||
block.name = name
|
||||
# This next bit is from handleObject
|
||||
# handleObject should be generalized to work with any section like object
|
||||
while 1:
|
||||
obj = handleObject(infile)
|
||||
if obj.type == 'block':
|
||||
print "Warning: previous block not closed!"
|
||||
return block
|
||||
elif obj.type == 'endblk':
|
||||
return block # this means we are done with the table
|
||||
else: # add objects to the table until one of the above is found
|
||||
block.data.append(obj)
|
||||
|
||||
|
||||
|
||||
|
||||
"""These are the states/functions used in the State Machine.
|
||||
states:
|
||||
start - find first section
|
||||
start_section - add data, find first object
|
||||
object - add obj-data, watch for next obj (called directly by start_section)
|
||||
end_section - look for next section or eof
|
||||
end - return results
|
||||
"""
|
||||
|
||||
def start(cargo):
|
||||
"""Expects the infile as cargo, initializes the cargo."""
|
||||
#print "Entering start state!"
|
||||
infile = cargo
|
||||
drawing = Object('drawing')
|
||||
section = findObject(infile, 'section')
|
||||
if section:
|
||||
return start_section, (infile, drawing, section)
|
||||
else:
|
||||
return error, (infile, "Failed to find any sections!")
|
||||
|
||||
def start_section(cargo):
|
||||
"""Expects [infile, drawing, section] as cargo, builds a nested section object."""
|
||||
#print "Entering start_section state!"
|
||||
infile = cargo[0]
|
||||
drawing = cargo[1]
|
||||
section = cargo[2]
|
||||
# read each line, if it is an object declaration go to object mode
|
||||
# otherwise create a [index, data] pair and add it to the sections data.
|
||||
done = False
|
||||
data = []
|
||||
while not done:
|
||||
line = infile.readline()
|
||||
|
||||
if not data: # if we haven't found a dxf code yet
|
||||
if line.lower().strip() == '0':
|
||||
# we've found an object
|
||||
while 1: # no way out unless we find an end section or a new section
|
||||
obj = handleObject(infile)
|
||||
if obj == 'section': # shouldn't happen
|
||||
print "Warning: failed to close previous section!"
|
||||
return end_section, (infile, drawing)
|
||||
elif obj == 'endsec': # This section is over, look for the next
|
||||
drawing.data.append(section)
|
||||
return end_section, (infile, drawing)
|
||||
elif obj.type == 'table': # tables are collections of data
|
||||
obj = handleTable(obj, infile) # we need to find all there contents
|
||||
section.data.append(obj) # before moving on
|
||||
elif obj.type == 'block': # the same is true of blocks
|
||||
obj = handleBlock(obj, infile) # we need to find all there contents
|
||||
section.data.append(obj) # before moving on
|
||||
else: # found another sub-object
|
||||
section.data.append(obj)
|
||||
else:
|
||||
data.append(int(line.lower().strip()))
|
||||
else: # we have our code, now we just need to convert the data and add it to our list.
|
||||
data.append(convert(data[0], line.strip()))
|
||||
section.data.append(data)
|
||||
data = []
|
||||
def end_section(cargo):
|
||||
"""Expects (infile, drawing) as cargo, searches for next section."""
|
||||
#print "Entering end_section state!"
|
||||
infile = cargo[0]
|
||||
drawing = cargo[1]
|
||||
section = findObject(infile, 'section')
|
||||
if section:
|
||||
return start_section, (infile, drawing, section)
|
||||
else:
|
||||
return end, (infile, drawing)
|
||||
|
||||
def end(cargo):
|
||||
"""Expects (infile, drawing) as cargo, called when eof has been reached."""
|
||||
#print "Entering end state!"
|
||||
infile = cargo[0]
|
||||
drawing = cargo[1]
|
||||
#infile.close()
|
||||
return drawing
|
||||
|
||||
def error(cargo):
|
||||
"""Expects a (infile, string) as cargo, called when there is an error during processing."""
|
||||
#print "Entering error state!"
|
||||
infile = cargo[0]
|
||||
err = cargo[1]
|
||||
infile.close()
|
||||
print "There has been an error:"
|
||||
print err
|
||||
return False
|
||||
|
||||
def readDXF(filename, objectify):
|
||||
"""Given a file name try to read it as a dxf file.
|
||||
|
||||
Output is an object with the following structure
|
||||
drawing
|
||||
header
|
||||
header data
|
||||
classes
|
||||
class data
|
||||
tables
|
||||
table data
|
||||
blocks
|
||||
block data
|
||||
entities
|
||||
entity data
|
||||
objects
|
||||
object data
|
||||
where foo data is a list of sub-objects. True object data
|
||||
is of the form [code, data].
|
||||
"""
|
||||
infile = open(filename)
|
||||
|
||||
sm = StateMachine()
|
||||
sm.add_state(error, True)
|
||||
sm.add_state(end, True)
|
||||
sm.add_state(start_section)
|
||||
sm.add_state(end_section)
|
||||
sm.add_state(start)
|
||||
sm.set_start(start)
|
||||
try:
|
||||
drawing = sm.run(infile)
|
||||
if drawing:
|
||||
drawing.name = filename
|
||||
for obj in drawing.data:
|
||||
item, name = get_name(obj.data)
|
||||
if name:
|
||||
obj.data.remove(item)
|
||||
obj.name = name.lower()
|
||||
setattr(drawing, name.lower(), obj)
|
||||
# Call the objectify function to cast
|
||||
# raw objects into the right types of object
|
||||
obj.data = objectify(obj.data)
|
||||
#print obj.name
|
||||
finally:
|
||||
infile.close()
|
||||
return drawing
|
||||
if __name__ == "__main__":
|
||||
filename = r".\examples\block-test.dxf"
|
||||
drawing = readDXF(filename)
|
||||
for item in drawing.entities.data:
|
||||
print item
|
||||
@@ -1,229 +0,0 @@
|
||||
# This is not to be used directly, vertexGradientPick can be used externaly
|
||||
|
||||
import Blender
|
||||
import BPyMesh
|
||||
import BPyWindow
|
||||
|
||||
mouseViewRay= BPyWindow.mouseViewRay
|
||||
from Blender import Mathutils, Window, Scene, Draw, sys
|
||||
from Blender.Mathutils import Vector, Intersect, LineIntersect, AngleBetweenVecs
|
||||
LMB= Window.MButs['L']
|
||||
|
||||
def mouseup():
|
||||
# Loop until click
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
while not mouse_buttons & LMB:
|
||||
sys.sleep(10)
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
while mouse_buttons & LMB:
|
||||
sys.sleep(10)
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
|
||||
def mousedown_wait():
|
||||
# If the menu has just been pressed dont use its mousedown,
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
while mouse_buttons & LMB:
|
||||
mouse_buttons = Window.GetMouseButtons()
|
||||
|
||||
eps= 0.0001
|
||||
def vertexGradientPick(ob, MODE):
|
||||
#MODE 0 == VWEIGHT, 1 == VCOL
|
||||
|
||||
me= ob.getData(mesh=1)
|
||||
if not me.faceUV: me.faceUV= True
|
||||
|
||||
Window.DrawProgressBar (0.0, '')
|
||||
|
||||
mousedown_wait()
|
||||
|
||||
if MODE==0:
|
||||
act_group= me.activeGroup
|
||||
if act_group == None:
|
||||
mousedown_wait()
|
||||
Draw.PupMenu('Error, mesh has no active group.')
|
||||
return
|
||||
|
||||
# Loop until click
|
||||
Window.DrawProgressBar (0.25, 'Click to set gradient start')
|
||||
mouseup()
|
||||
|
||||
obmat= ob.matrixWorld
|
||||
screen_x, screen_y = Window.GetMouseCoords()
|
||||
mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat)
|
||||
if not mouseInView or not OriginA:
|
||||
return
|
||||
|
||||
# get the mouse weight
|
||||
|
||||
if MODE==0:
|
||||
pickValA= BPyMesh.pickMeshGroupWeight(me, act_group, OriginA, DirectionA)
|
||||
if MODE==1:
|
||||
pickValA= BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA)
|
||||
|
||||
Window.DrawProgressBar (0.75, 'Click to set gradient end')
|
||||
mouseup()
|
||||
|
||||
TOALPHA= Window.GetKeyQualifiers() & Window.Qual.SHIFT
|
||||
|
||||
screen_x, screen_y = Window.GetMouseCoords()
|
||||
mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat)
|
||||
if not mouseInView or not OriginB:
|
||||
return
|
||||
|
||||
if not TOALPHA: # Only get a second opaque value if we are not blending to alpha
|
||||
if MODE==0: pickValB= BPyMesh.pickMeshGroupWeight(me, act_group, OriginB, DirectionB)
|
||||
else:
|
||||
pickValB= BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB)
|
||||
else:
|
||||
if MODE==0: pickValB= 0.0
|
||||
else: pickValB= [0.0, 0.0, 0.0] # Dummy value
|
||||
|
||||
# Neither points touched a face
|
||||
if pickValA == pickValB == None:
|
||||
return
|
||||
|
||||
# clicking on 1 non face is fine. just set the weight to 0.0
|
||||
if pickValA==None:
|
||||
pickValA= 0.0
|
||||
|
||||
# swap A/B
|
||||
OriginA, OriginB= OriginB, OriginA
|
||||
DirectionA, DirectionB= DirectionB, DirectionA
|
||||
pickValA, pickValB= pickValA, pickValB
|
||||
|
||||
TOALPHA= True
|
||||
|
||||
if pickValB==None:
|
||||
pickValB= 0.0
|
||||
TOALPHA= True
|
||||
|
||||
# set up 2 lines so we can measure their distances and calc the gradient
|
||||
|
||||
# make a line 90d to the grad in screenspace.
|
||||
if (OriginA-OriginB).length <= eps: # Persp view. same origin different direction
|
||||
cross_grad= DirectionA.cross(DirectionB)
|
||||
ORTHO= False
|
||||
|
||||
else: # Ortho - Same direction, different origin
|
||||
cross_grad= DirectionA.cross(OriginA-OriginB)
|
||||
ORTHO= True
|
||||
|
||||
cross_grad.normalize()
|
||||
cross_grad= cross_grad * 100
|
||||
|
||||
lineA= (OriginA, OriginA+(DirectionA*100))
|
||||
lineB= (OriginB, OriginB+(DirectionB*100))
|
||||
|
||||
if not ORTHO:
|
||||
line_angle= AngleBetweenVecs(lineA[1], lineB[1])/2
|
||||
line_mid= (lineA[1]+lineB[1])*0.5
|
||||
|
||||
VSEL= [False] * (len(me.verts))
|
||||
|
||||
# Get the selected faces and apply the selection to the verts.
|
||||
for f in me.faces:
|
||||
if f.sel:
|
||||
for v in f.v:
|
||||
VSEL[v.index]= True
|
||||
groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
|
||||
|
||||
|
||||
|
||||
def grad_weight_from_co(v):
|
||||
'''
|
||||
Takes a vert and retuens its gradient radio between A and B
|
||||
'''
|
||||
|
||||
if not VSEL[v.index]: # Not bart of a selected face?
|
||||
return None, None
|
||||
|
||||
v_co= v.co
|
||||
# make a line 90d to the 2 lines the user clicked.
|
||||
vert_line= (v_co - cross_grad, v_co + cross_grad)
|
||||
|
||||
xA= LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1])
|
||||
xB= LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1])
|
||||
|
||||
if not xA or not xB: # Should never happen but support it anyhow
|
||||
return None, None
|
||||
|
||||
wA= (xA[0]-xA[1]).length
|
||||
wB= (xB[0]-xB[1]).length
|
||||
|
||||
wTot= wA+wB
|
||||
if not wTot: # lines are on the same point.
|
||||
return None, None
|
||||
|
||||
'''
|
||||
Get the length of the line between both intersections on the
|
||||
2x view lines.
|
||||
if the dist between lineA+VertLine and lineB+VertLine is
|
||||
greater then the lenth between lineA and lineB intersection points, it means
|
||||
that the verts are not inbetween the 2 lines.
|
||||
'''
|
||||
lineAB_length= (xA[1]-xB[1]).length
|
||||
|
||||
# normalzie
|
||||
wA= wA/wTot
|
||||
wB= wB/wTot
|
||||
|
||||
if ORTHO: # Con only use line length method with parelelle lines
|
||||
if wTot > lineAB_length+eps:
|
||||
# vert is outside the range on 1 side. see what side of the grad
|
||||
if wA>wB: wA, wB= 1.0, 0.0
|
||||
else: wA, wB= 0.0, 1.0
|
||||
else:
|
||||
# PERSP, lineA[0] is the same origin as lineB[0]
|
||||
|
||||
# Either xA[0] or xB[0] can be used instead of a possible x_mid between the 2
|
||||
# as long as the point is inbetween lineA and lineB it dosent matter.
|
||||
a= AngleBetweenVecs(lineA[0]-xA[0], line_mid)
|
||||
if a>line_angle:
|
||||
# vert is outside the range on 1 side. see what side of the grad
|
||||
if wA>wB: wA, wB= 1.0, 0.0
|
||||
else: wA, wB= 0.0, 1.0
|
||||
|
||||
return wA, wB
|
||||
|
||||
|
||||
grad_weights= [grad_weight_from_co(v) for v in me.verts]
|
||||
|
||||
|
||||
if MODE==0:
|
||||
for v in me.verts:
|
||||
i= v.index
|
||||
if VSEL[i]:
|
||||
wA, wB = grad_weights[i]
|
||||
if wA != None: # and wB
|
||||
if TOALPHA:
|
||||
# Do alpha by using the exiting weight for
|
||||
try: pickValB= vWeightDict[i][act_group]
|
||||
except: pickValB= 0.0 # The weights not there? assume zero
|
||||
# Mix2 2 opaque weights
|
||||
vWeightDict[i][act_group]= pickValB*wA + pickValA*wB
|
||||
|
||||
else: # MODE==1 VCol
|
||||
for f in me.faces:
|
||||
if f.sel:
|
||||
f_v= f.v
|
||||
for i in xrange(len(f_v)):
|
||||
v= f_v[i]
|
||||
wA, wB = grad_weights[v.index]
|
||||
|
||||
c= f.col[i]
|
||||
|
||||
if TOALPHA:
|
||||
pickValB= c.r, c.g, c.b
|
||||
|
||||
c.r = int(pickValB[0]*wA + pickValA[0]*wB)
|
||||
c.g = int(pickValB[1]*wA + pickValA[1]*wB)
|
||||
c.b = int(pickValB[2]*wA + pickValA[2]*wB)
|
||||
|
||||
|
||||
|
||||
|
||||
# Copy weights back to the mesh.
|
||||
BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
|
||||
Window.DrawProgressBar (1.0, '')
|
||||
|
||||
|
||||
@@ -1,355 +0,0 @@
|
||||
# $Id$
|
||||
#
|
||||
# +---------------------------------------------------------+
|
||||
# | Copyright (c) 2001 Anthony D'Agostino |
|
||||
# | http://www.redrival.com/scorpius |
|
||||
# | scorpius@netzero.com |
|
||||
# | September 28, 2002 |
|
||||
# +---------------------------------------------------------+
|
||||
# | Common Functions & Global Variables For All IO Modules |
|
||||
# +---------------------------------------------------------+
|
||||
|
||||
# ***** 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 *****
|
||||
|
||||
import Blender
|
||||
import sys
|
||||
|
||||
show_progress = 1 # Set to 0 for faster performance
|
||||
average_vcols = 1 # Off for per-face, On for per-vertex
|
||||
overwrite_mesh_name = 0 # Set to 0 to increment object-name version
|
||||
|
||||
blender_version = Blender.Get('version')
|
||||
blender_version_str = `blender_version`[0] + '.' + `blender_version`[1:]
|
||||
|
||||
try:
|
||||
import operator
|
||||
except:
|
||||
msg = "Error: you need a full Python install to run this script."
|
||||
meshtools.print_boxed(msg)
|
||||
Blender.Draw.PupMenu("ERROR%t|"+msg)
|
||||
|
||||
# =================================
|
||||
# === Append Faces To Face List ===
|
||||
# =================================
|
||||
def append_faces(mesh, faces, facesuv, uvcoords):
|
||||
for i in xrange(len(faces)):
|
||||
if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(faces), "Generating Faces")
|
||||
numfaceverts=len(faces[i])
|
||||
if numfaceverts == 2: #This is not a face is an edge
|
||||
if mesh.edges == None: #first run
|
||||
mesh.addEdgeData()
|
||||
#rev_face = revert(cur_face)
|
||||
i1 = faces[i][0]
|
||||
i2 = faces[i][1]
|
||||
ee = mesh.addEdge(mesh.verts[i1],mesh.verts[i2])
|
||||
ee.flag |= Blender.NMesh.EdgeFlags.EDGEDRAW
|
||||
ee.flag |= Blender.NMesh.EdgeFlags.EDGERENDER
|
||||
elif numfaceverts in [3,4]: # This face is a triangle or quad
|
||||
face = Blender.NMesh.Face()
|
||||
for j in xrange(numfaceverts):
|
||||
index = faces[i][j]
|
||||
face.v.append(mesh.verts[index])
|
||||
if len(uvcoords) > 1:
|
||||
uvidx = facesuv[i][j]
|
||||
face.uv.append(uvcoords[uvidx])
|
||||
face.mode = 0
|
||||
face.col = [Blender.NMesh.Col()]*4
|
||||
mesh.faces.append(face)
|
||||
else: # Triangulate n-sided convex polygon.
|
||||
a, b, c = 0, 1, 2 # Indices of first triangle.
|
||||
for j in xrange(numfaceverts-2): # Number of triangles in polygon.
|
||||
face = Blender.NMesh.Face()
|
||||
face.v.append(mesh.verts[faces[i][a]])
|
||||
face.v.append(mesh.verts[faces[i][b]])
|
||||
face.v.append(mesh.verts[faces[i][c]])
|
||||
b = c; c += 1
|
||||
mesh.faces.append(face)
|
||||
#face.smooth = 1
|
||||
|
||||
# ===================================
|
||||
# === Append Verts to Vertex List ===
|
||||
# ===================================
|
||||
def append_verts(mesh, verts, normals):
|
||||
#print "Number of normals:", len(normals)
|
||||
#print "Number of verts :", len(verts)
|
||||
for i in xrange(len(verts)):
|
||||
if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(verts), "Generating Verts")
|
||||
x, y, z = verts[i]
|
||||
mesh.verts.append(Blender.NMesh.Vert(x, y, z))
|
||||
if normals:
|
||||
mesh.verts[i].no[0] = normals[i][0]
|
||||
mesh.verts[i].no[1] = normals[i][1]
|
||||
mesh.verts[i].no[2] = normals[i][2]
|
||||
|
||||
# ===========================
|
||||
# === Create Blender Mesh ===
|
||||
# ===========================
|
||||
def create_mesh(verts, faces, objname, facesuv=[], uvcoords=[], normals=[]):
|
||||
if normals: normal_flag = 0
|
||||
else: normal_flag = 1
|
||||
mesh = Blender.NMesh.GetRaw()
|
||||
append_verts(mesh, verts, normals)
|
||||
append_faces(mesh, faces, facesuv, uvcoords)
|
||||
if not overwrite_mesh_name:
|
||||
objname = versioned_name(objname)
|
||||
ob= Blender.NMesh.PutRaw(mesh, objname, normal_flag) # Name the Mesh
|
||||
ob.name= objname # Name the Object
|
||||
Blender.Redraw()
|
||||
|
||||
# ==============================
|
||||
# === Increment Name Version ===
|
||||
# ==============================
|
||||
def versioned_name(objname):
|
||||
existing_names = []
|
||||
for object in Blender.Object.Get():
|
||||
existing_names.append(object.name)
|
||||
existing_names.append(object.getData(name_only=1))
|
||||
if objname in existing_names: # don't over-write other names
|
||||
try:
|
||||
name, ext = objname.split('.')
|
||||
except ValueError:
|
||||
name, ext = objname, ''
|
||||
try:
|
||||
num = int(ext)
|
||||
root = name
|
||||
except ValueError:
|
||||
root = objname
|
||||
for i in xrange(1, 1000):
|
||||
objname = "%s.%03d" % (root, i)
|
||||
if objname not in existing_names:
|
||||
break
|
||||
return objname
|
||||
|
||||
# ===========================
|
||||
# === Print Text In A Box ===
|
||||
# ===========================
|
||||
def print_boxed(text):
|
||||
lines = text.splitlines()
|
||||
maxlinelen = max(map(len, lines))
|
||||
if sys.platform[:3] == "win":
|
||||
print chr(218)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(191)
|
||||
for line in lines:
|
||||
print chr(179) + ' ' + line.ljust(maxlinelen) + ' ' + chr(179)
|
||||
print chr(192)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(217)
|
||||
else:
|
||||
print '+-' + '-'*maxlinelen + '-+'
|
||||
for line in lines: print '| ' + line.ljust(maxlinelen) + ' |'
|
||||
print '+-' + '-'*maxlinelen + '-+'
|
||||
print '\a\r', # beep when done
|
||||
|
||||
# ===============================================
|
||||
# === Get euler angles from a rotation matrix ===
|
||||
# ===============================================
|
||||
def mat2euler(mat):
|
||||
angle_y = -math.asin(mat[0][2])
|
||||
c = math.cos(angle_y)
|
||||
if math.fabs(c) > 0.005:
|
||||
angle_x = math.atan2(mat[1][2]/c, mat[2][2]/c)
|
||||
angle_z = math.atan2(mat[0][1]/c, mat[0][0]/c)
|
||||
else:
|
||||
angle_x = 0.0
|
||||
angle_z = -math.atan2(mat[1][0], mat[1][1])
|
||||
return (angle_x, angle_y, angle_z)
|
||||
|
||||
# ==========================
|
||||
# === Transpose A Matrix ===
|
||||
# ==========================
|
||||
def transpose(A):
|
||||
S = len(A)
|
||||
T = len(A[0])
|
||||
B = [[None]*S for i in xrange(T)]
|
||||
for i in xrange(T):
|
||||
for j in xrange(S):
|
||||
B[i][j] = A[j][i]
|
||||
return B
|
||||
|
||||
# =======================
|
||||
# === Apply Transform ===
|
||||
# =======================
|
||||
def apply_transform(vertex, matrix):
|
||||
x, y, z = vertex
|
||||
xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
|
||||
xcomponent = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc
|
||||
ycomponent = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc
|
||||
zcomponent = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
|
||||
vertex = [xcomponent, ycomponent, zcomponent]
|
||||
return vertex
|
||||
|
||||
# =========================
|
||||
# === Has Vertex Colors ===
|
||||
# =========================
|
||||
def has_vertex_colors(mesh):
|
||||
# My replacement/workaround for hasVertexColours()
|
||||
# The docs say:
|
||||
# "Warning: If a mesh has both vertex colours and textured faces,
|
||||
# this function will return False. This is due to the way Blender
|
||||
# deals internally with the vertex colours array (if there are
|
||||
# textured faces, it is copied to the textured face structure and
|
||||
# the original array is freed/deleted)."
|
||||
try:
|
||||
return mesh.faces[0].col[0]
|
||||
except:
|
||||
return 0
|
||||
|
||||
# ===========================
|
||||
# === Generate Edge Table ===
|
||||
# ===========================
|
||||
def generate_edgetable(mesh):
|
||||
edge_table = {}
|
||||
numfaces = len(mesh.faces)
|
||||
|
||||
for i in xrange(numfaces):
|
||||
if not i%100 and show_progress:
|
||||
Blender.Window.DrawProgressBar(float(i)/numfaces, "Generating Edge Table")
|
||||
if len(mesh.faces[i].v) == 4: # Process Quadrilaterals
|
||||
generate_entry_from_quad(mesh, i, edge_table)
|
||||
elif len(mesh.faces[i].v) == 3: # Process Triangles
|
||||
generate_entry_from_tri(mesh, i, edge_table)
|
||||
else: # Skip This Face
|
||||
print "Face #", i, "was skipped."
|
||||
|
||||
# === Sort Edge_Table Keys & Add Edge Indices ===
|
||||
i = 0
|
||||
keys = edge_table.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
edge_table[key][6] = i
|
||||
i += 1
|
||||
|
||||
# === Replace Tuples With Indices ===
|
||||
for key in keys:
|
||||
for i in [2,3,4,5]:
|
||||
if edge_table.has_key(edge_table[key][i]):
|
||||
edge_table[key][i] = edge_table[edge_table[key][i]][6]
|
||||
else:
|
||||
keyrev = (edge_table[key][i][1], edge_table[key][i][0])
|
||||
edge_table[key][i] = edge_table[keyrev][6]
|
||||
|
||||
return edge_table
|
||||
|
||||
# ================================
|
||||
# === Generate Entry From Quad ===
|
||||
# ================================
|
||||
def generate_entry_from_quad(mesh, i, edge_table):
|
||||
vertex4, vertex3, vertex2, vertex1 = mesh.faces[i].v
|
||||
|
||||
if has_vertex_colors(mesh):
|
||||
vcolor4, vcolor3, vcolor2, vcolor1 = mesh.faces[i].col
|
||||
Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0)
|
||||
Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0)
|
||||
Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0)
|
||||
Dcol = (vcolor4.r/255.0, vcolor4.g/255.0, vcolor4.b/255.0)
|
||||
|
||||
# === verts are upper case, edges are lower case ===
|
||||
A, B, C, D = vertex1.index, vertex2.index, vertex3.index, vertex4.index
|
||||
a, b, c, d = (A, B), (B, C), (C, D), (D, A)
|
||||
|
||||
if edge_table.has_key((B, A)):
|
||||
edge_table[(B, A)][1] = i
|
||||
edge_table[(B, A)][4] = d
|
||||
edge_table[(B, A)][5] = b
|
||||
if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol
|
||||
else:
|
||||
if has_vertex_colors(mesh):
|
||||
edge_table[(A, B)] = [i, None, d, b, None, None, None, Bcol, None]
|
||||
else:
|
||||
edge_table[(A, B)] = [i, None, d, b, None, None, None]
|
||||
|
||||
if edge_table.has_key((C, B)):
|
||||
edge_table[(C, B)][1] = i
|
||||
edge_table[(C, B)][4] = a
|
||||
edge_table[(C, B)][5] = c
|
||||
if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol
|
||||
else:
|
||||
if has_vertex_colors(mesh):
|
||||
edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None]
|
||||
else:
|
||||
edge_table[(B, C)] = [i, None, a, c, None, None, None]
|
||||
|
||||
if edge_table.has_key((D, C)):
|
||||
edge_table[(D, C)][1] = i
|
||||
edge_table[(D, C)][4] = b
|
||||
edge_table[(D, C)][5] = d
|
||||
if has_vertex_colors(mesh): edge_table[(D, C)][8] = Dcol
|
||||
else:
|
||||
if has_vertex_colors(mesh):
|
||||
edge_table[(C, D)] = [i, None, b, d, None, None, None, Dcol, None]
|
||||
else:
|
||||
edge_table[(C, D)] = [i, None, b, d, None, None, None]
|
||||
|
||||
if edge_table.has_key((A, D)):
|
||||
edge_table[(A, D)][1] = i
|
||||
edge_table[(A, D)][4] = c
|
||||
edge_table[(A, D)][5] = a
|
||||
if has_vertex_colors(mesh): edge_table[(A, D)][8] = Acol
|
||||
else:
|
||||
if has_vertex_colors(mesh):
|
||||
edge_table[(D, A)] = [i, None, c, a, None, None, None, Acol, None]
|
||||
else:
|
||||
edge_table[(D, A)] = [i, None, c, a, None, None, None]
|
||||
|
||||
# ====================================
|
||||
# === Generate Entry From Triangle ===
|
||||
# ====================================
|
||||
def generate_entry_from_tri(mesh, i, edge_table):
|
||||
vertex3, vertex2, vertex1 = mesh.faces[i].v
|
||||
|
||||
if has_vertex_colors(mesh):
|
||||
vcolor3, vcolor2, vcolor1, _vcolor4_ = mesh.faces[i].col
|
||||
Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0)
|
||||
Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0)
|
||||
Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0)
|
||||
|
||||
# === verts are upper case, edges are lower case ===
|
||||
A, B, C = vertex1.index, vertex2.index, vertex3.index
|
||||
a, b, c = (A, B), (B, C), (C, A)
|
||||
|
||||
if edge_table.has_key((B, A)):
|
||||
edge_table[(B, A)][1] = i
|
||||
edge_table[(B, A)][4] = c
|
||||
edge_table[(B, A)][5] = b
|
||||
if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol
|
||||
else:
|
||||
if has_vertex_colors(mesh):
|
||||
edge_table[(A, B)] = [i, None, c, b, None, None, None, Bcol, None]
|
||||
else:
|
||||
edge_table[(A, B)] = [i, None, c, b, None, None, None]
|
||||
|
||||
if edge_table.has_key((C, B)):
|
||||
edge_table[(C, B)][1] = i
|
||||
edge_table[(C, B)][4] = a
|
||||
edge_table[(C, B)][5] = c
|
||||
if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol
|
||||
else:
|
||||
if has_vertex_colors(mesh):
|
||||
edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None]
|
||||
else:
|
||||
edge_table[(B, C)] = [i, None, a, c, None, None, None]
|
||||
|
||||
if edge_table.has_key((A, C)):
|
||||
edge_table[(A, C)][1] = i
|
||||
edge_table[(A, C)][4] = b
|
||||
edge_table[(A, C)][5] = a
|
||||
if has_vertex_colors(mesh): edge_table[(A, C)][8] = Acol
|
||||
else:
|
||||
if has_vertex_colors(mesh):
|
||||
edge_table[(C, A)] = [i, None, b, a, None, None, None, Acol, None]
|
||||
else:
|
||||
edge_table[(C, A)] = [i, None, b, a, None, None, None]
|
||||
|
||||
@@ -1,506 +0,0 @@
|
||||
# -*- coding: latin-1 -*-
|
||||
"""
|
||||
paths_ai2obj.py
|
||||
# ---------------------------------------------------------------
|
||||
Copyright (c) jm soler juillet/novembre 2004-april 2007,
|
||||
# ---------------------------------------------------------------
|
||||
released under GNU Licence
|
||||
for the Blender 2.45 Python Scripts Bundle.
|
||||
Ce programme est libre, vous pouvez le redistribuer et/ou
|
||||
le modifier selon les termes de la Licence Publique G<>n<EFBFBD>rale GNU
|
||||
publi<EFBFBD>e par la Free Software Foundation (version 2 ou bien toute
|
||||
autre version ult<6C>rieure choisie par vous).
|
||||
|
||||
Ce programme est distribu<62> car potentiellement utile, mais SANS
|
||||
AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties
|
||||
de commercialisation ou d'adaptation dans un but sp<73>cifique.
|
||||
Reportez-vous <20> la Licence Publique G<>n<EFBFBD>rale GNU pour plus de d<>tails.
|
||||
|
||||
Vous devez avoir re<72>u une copie de la Licence Publique G<>n<EFBFBD>rale GNU
|
||||
en m<>me temps que ce programme ; si ce n'est pas le cas, <20>crivez <20> la
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
MA 02111-1307, <20>tats-Unis.
|
||||
|
||||
|
||||
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
# ---------------------------------------------------------------
|
||||
#----------------------------------------------
|
||||
#
|
||||
# Page officielle :
|
||||
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_ai_en.htm
|
||||
# Communiquer les problemes et erreurs sur:
|
||||
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
|
||||
#----------------------------------------------
|
||||
|
||||
#Changelog
|
||||
#----------------------------------------------
|
||||
# 0.1.1 : 2004/08/03, bug in boundingbox reading when Value are negative
|
||||
# 0.1.2 : 2005/06/12, gmove tranformation properties
|
||||
# 0.1.3 : 2005/06/25, added a __name__ test to use the script alone
|
||||
# 0.1.4 : 2005/06/25, closepath improvements
|
||||
# 0.1.5 : 2005/06/25, ...
|
||||
# 0.1.6 : 2005/06/26, warning for compacted file
|
||||
compatibility increased up to AI 10.0 plain text
|
||||
# 0.1.7 : 2005/06/25, two more closepath improvements
|
||||
#
|
||||
# 0.1.8 : 2006/07/03, two more closepath improvements
|
||||
# 0.1.9 : 2007/05/06, modif on the method that gets the last object on
|
||||
the list data
|
||||
# 2008/03/12, Added character encoding line so french text
|
||||
# does not break python interpreters.
|
||||
|
||||
"""
|
||||
SHARP_IMPORT=0
|
||||
SCALE=1
|
||||
NOTHING_TODO=1
|
||||
AI_VERSION=''
|
||||
|
||||
GSTACK = []
|
||||
GSCALE = []
|
||||
GTRANSLATE = []
|
||||
|
||||
import sys
|
||||
#oldpath=sys.path
|
||||
import Blender
|
||||
BLversion=Blender.Get('version')
|
||||
|
||||
try:
|
||||
import nt
|
||||
os=nt
|
||||
os.sep='\\'
|
||||
|
||||
except:
|
||||
import posix
|
||||
os=posix
|
||||
os.sep='/'
|
||||
|
||||
def isdir(path):
|
||||
try:
|
||||
st = os.stat(path)
|
||||
return 1
|
||||
except:
|
||||
return 0
|
||||
|
||||
def split(pathname):
|
||||
if pathname.find(os.sep)!=-1:
|
||||
k0=pathname.split(os.sep)
|
||||
else:
|
||||
if os.sep=='/':
|
||||
k0=pathname.split('\\')
|
||||
else:
|
||||
k0=pathname.split('/')
|
||||
|
||||
directory=pathname.replace(k0[len(k0)-1],'')
|
||||
Name=k0[len(k0)-1]
|
||||
return directory, Name
|
||||
|
||||
def join(l0,l1):
|
||||
return l0+os.sep+l1
|
||||
|
||||
os.isdir=isdir
|
||||
os.split=split
|
||||
os.join=join
|
||||
|
||||
def filtreFICHIER(nom):
|
||||
f=open(nom,'rU')
|
||||
t=f.readlines()
|
||||
f.close()
|
||||
|
||||
if len(t)>1 and t[0].find('EPSF')==-1:
|
||||
return t
|
||||
else:
|
||||
name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1
|
||||
result = Blender.Draw.PupMenu(name)
|
||||
|
||||
return 'false'
|
||||
|
||||
#===============================
|
||||
# Data
|
||||
#===============================
|
||||
#===============================
|
||||
# Blender Curve Data
|
||||
#===============================
|
||||
objBEZIER=0
|
||||
objSURFACE=5
|
||||
typBEZIER3D=1 #3D
|
||||
typBEZIER2D=9 #2D
|
||||
|
||||
class Bez:
|
||||
def __init__(self):
|
||||
self.co=[]
|
||||
self.ha=[0,0]
|
||||
self.tag=''
|
||||
|
||||
class ITEM:
|
||||
def __init__(self):
|
||||
self.type = typBEZIER3D,
|
||||
self.pntsUV = [0,0]
|
||||
self.resolUV = [32,0]
|
||||
self.orderUV = [0,0]
|
||||
self.flagUV = [0,0]
|
||||
self.Origine = [0.0,0.0]
|
||||
self.beziers_knot = []
|
||||
|
||||
class COURBE:
|
||||
def __init__(self):
|
||||
self.magic_number='3DG3'
|
||||
self.type = objBEZIER
|
||||
self.number_of_items = 0
|
||||
self.ext1_ext2 = [0,0]
|
||||
self.matrix = """0.0 0.0 1.0 0.0
|
||||
0.0 1.0 0.0 0.0
|
||||
0.0 0.0 1.0 0.0
|
||||
0.0 0.0 0.0 1.0 """
|
||||
self.ITEM = {}
|
||||
|
||||
courbes=COURBE()
|
||||
|
||||
PATTERN={}
|
||||
|
||||
BOUNDINGBOX={'rec':[],'coef':1.0}
|
||||
npat=0
|
||||
#=====================================================================
|
||||
#======== name of the curve in teh courbes dictionnary ===============
|
||||
#=====================================================================
|
||||
n0=0
|
||||
|
||||
#=====================================================================
|
||||
#====================== current Point ================================
|
||||
#=====================================================================
|
||||
CP=[0.0,0.0] #currentPoint
|
||||
|
||||
|
||||
# modifs 12/06/2005
|
||||
#=====================================================================
|
||||
#====================== current transform ============================
|
||||
#=====================================================================
|
||||
class transform:
|
||||
def __init__(self,matrix=[1,0,01],x=0.0,y=0.0):
|
||||
self.matrix=matrix[:]
|
||||
self.xy=[x,y]
|
||||
|
||||
def G_move(l,a):
|
||||
global GSCALE, GTRANSLATE, GSTACK
|
||||
#print GSCALE, GTRANSLATE, GSTACK
|
||||
return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a])
|
||||
# modifs 12/06/2005
|
||||
|
||||
|
||||
#=====================================================================
|
||||
#===== to compare last position to the original move to displacement =
|
||||
#===== needed for cyclic efinition =================================
|
||||
#=====================================================================
|
||||
def test_egalitedespositions(f1,f2):
|
||||
if f1[0]==f2[0] and f1[1]==f2[1]:
|
||||
return Blender.TRUE
|
||||
else:
|
||||
return Blender.FALSE
|
||||
|
||||
|
||||
def Open_GEOfile(dir,nom):
|
||||
if BLversion>=233:
|
||||
in_editmode = Blender.Window.EditMode()
|
||||
if in_editmode: Blender.Window.EditMode(0)
|
||||
Blender.Load(dir+nom+'OOO.obj', 1)
|
||||
BO=Blender.Scene.GetCurrent().objects.active
|
||||
BO.RotY=0.0
|
||||
BO.RotX=1.57
|
||||
BO.makeDisplayList()
|
||||
Blender.Window.RedrawAll()
|
||||
else:
|
||||
print "Not yet implemented"
|
||||
|
||||
def create_GEOtext(courbes):
|
||||
global SCALE, B, BOUNDINGBOX
|
||||
r=BOUNDINGBOX['rec']
|
||||
|
||||
if SCALE==1:
|
||||
SCALE=1.0
|
||||
elif SCALE==2:
|
||||
SCALE=r[2]-r[0]
|
||||
elif SCALE==3:
|
||||
SCALE=r[3]-r[1]
|
||||
|
||||
t=[]
|
||||
t.append(courbes.magic_number+'\n')
|
||||
t.append(str(courbes.type)+'\n')
|
||||
t.append(str(courbes.number_of_items)+'\n')
|
||||
t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n')
|
||||
t.append(courbes.matrix+'\n')
|
||||
|
||||
for k in courbes.ITEM.keys():
|
||||
if len(courbes.ITEM[k].beziers_knot)>1 :
|
||||
t.append("%s\n"%courbes.ITEM[k].type)
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1]))
|
||||
|
||||
flag =courbes.ITEM[k].flagUV[0]
|
||||
|
||||
for k2 in range(len(courbes.ITEM[k].beziers_knot)):
|
||||
#print k2
|
||||
k1 =courbes.ITEM[k].beziers_knot[k2]
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE))
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE))
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE))
|
||||
|
||||
t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n')
|
||||
return t
|
||||
|
||||
def save_GEOfile(dir,nom,t):
|
||||
f=open(dir+nom+'OOO.obj','w')
|
||||
f.writelines(t)
|
||||
f.close()
|
||||
#warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1"
|
||||
#result = Blender.Draw.PupMenu(warning)
|
||||
|
||||
|
||||
#=====================================================================
|
||||
#===== AI format : DEBUT =========================
|
||||
#=====================================================================
|
||||
def mouvement_vers(l,n0,CP):
|
||||
if n0 in courbes.ITEM.keys():
|
||||
n0+=1
|
||||
|
||||
CP=[l[-3].replace('d',''),l[-2]]
|
||||
courbes.ITEM[n0]=ITEM()
|
||||
courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]]
|
||||
|
||||
B=Bez()
|
||||
B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]]
|
||||
B.ha=[0,0]
|
||||
B.tag=l[-1]
|
||||
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
|
||||
return courbes,n0,CP
|
||||
|
||||
def courbe_vers_c(l,l2, n0,CP): #c,C
|
||||
|
||||
B=Bez()
|
||||
B.co=[l[4],l[5],l[2],l[3],l[4],l[5]]
|
||||
B.tag=l[-1]
|
||||
B.ha=[0,0]
|
||||
|
||||
BP=courbes.ITEM[n0].beziers_knot[-1]
|
||||
|
||||
BP.co[0]=l[0]
|
||||
BP.co[1]=l[1]
|
||||
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
|
||||
CP=[B.co[4],B.co[5]]
|
||||
return courbes,n0,CP
|
||||
|
||||
|
||||
def courbe_vers_v(l,n0,CP): #v-V
|
||||
|
||||
B=Bez()
|
||||
B.tag=l[-1]
|
||||
B.co=[l[2],l[3],l[0],l[1],l[2],l[3]]
|
||||
B.ha=[0,0]
|
||||
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
|
||||
CP=[B.co[4],B.co[5]]
|
||||
return courbes,n0,CP
|
||||
|
||||
def courbe_vers_y(l,n0,CP): #y
|
||||
B=Bez()
|
||||
B.tag=l[-1]
|
||||
B.co=[l[2],l[3],l[2],l[3],l[2],l[3]]
|
||||
B.ha=[0,0]
|
||||
|
||||
BP=courbes.ITEM[n0].beziers_knot[-1]
|
||||
BP.co[0]=l[0]
|
||||
BP.co[1]=l[1]
|
||||
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
CP=[B.co[4],B.co[5]]
|
||||
return courbes,n0,CP
|
||||
|
||||
|
||||
def ligne_tracee_l(l,n0,CP):
|
||||
B=Bez()
|
||||
B.tag=l[-1]
|
||||
B.co=[l[0],l[1],l[0],l[1],l[0],l[1]]
|
||||
B.ha=[0,0]
|
||||
|
||||
BP=courbes.ITEM[n0].beziers_knot[-1]
|
||||
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
CP=[B.co[4],B.co[5]]
|
||||
return courbes,n0,CP
|
||||
|
||||
def ligne_fermee(l,n0,CP):
|
||||
courbes.ITEM[n0].flagUV[0]=1
|
||||
|
||||
if len(courbes.ITEM[n0].beziers_knot)>1:
|
||||
BP=courbes.ITEM[n0].beziers_knot[-1]
|
||||
BP0=courbes.ITEM[n0].beziers_knot[0]
|
||||
|
||||
if BP.tag not in ['l','L']:
|
||||
BP.co[0]=BP0.co[0] #4-5 point prec
|
||||
BP.co[1]=BP0.co[1]
|
||||
|
||||
del courbes.ITEM[n0].beziers_knot[0]
|
||||
return courbes,n0,CP
|
||||
|
||||
def passe(l,n0,CP):
|
||||
return courbes,n0,CP
|
||||
|
||||
Actions= { "C" : courbe_vers_c,
|
||||
"c" : courbe_vers_c,
|
||||
"V" : courbe_vers_v,
|
||||
"v" : courbe_vers_v,
|
||||
"Y" : courbe_vers_y,
|
||||
"y" : courbe_vers_y,
|
||||
"m" : mouvement_vers,
|
||||
"l" : ligne_tracee_l,
|
||||
"L" : ligne_tracee_l,
|
||||
"F" : passe,
|
||||
"f" : ligne_fermee,
|
||||
"B" : passe,
|
||||
"b" : ligne_fermee,
|
||||
"S" : passe,
|
||||
"s" : ligne_fermee,
|
||||
"N" : ligne_fermee,
|
||||
"n" : passe,
|
||||
}
|
||||
|
||||
TAGcourbe=Actions.keys()
|
||||
|
||||
def pik_pattern(t,l):
|
||||
global npat, PATTERN, BOUNDINGBOX, AI_VERSION
|
||||
while t[l].find('%%EndSetup')!=0:
|
||||
if t[l].find('%%Creator: Adobe Illustrator(R)')!=-1:
|
||||
print t[l]
|
||||
AI_VERSION=t[l].split()[-1]
|
||||
print AI_VERSION
|
||||
|
||||
if t[l].find('%%BoundingBox:')!=-1:
|
||||
t[l]=t[l][t[l].find(':')+1:]
|
||||
l0=t[l].split()
|
||||
BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])]
|
||||
r=BOUNDINGBOX['rec']
|
||||
BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0])
|
||||
#print l,
|
||||
if t[l].find('BeginPattern')!=-1:
|
||||
nomPattern=t[l][t[l].find('(')+1:t[l].find(')')]
|
||||
PATTERN[nomPattern]={}
|
||||
|
||||
if t[l].find('BeginPatternLayer')!=-1:
|
||||
npat+=1
|
||||
PATTERN[nomPattern][npat]=[]
|
||||
while t[l].find('EndPatternLayer')==-1:
|
||||
#print t[l]
|
||||
PATTERN[nomPattern][npat].append(l)
|
||||
l+=1
|
||||
if l+1<len(t):
|
||||
l=l+1
|
||||
else:
|
||||
return 1,l
|
||||
return 1,l
|
||||
|
||||
def scan_FILE(nom):
|
||||
global CP, courbes, SCALE, NOTHING_TODO
|
||||
dir,name=split(nom)
|
||||
name=name.split('.')
|
||||
n0=0
|
||||
result=0
|
||||
t=filtreFICHIER(nom)
|
||||
|
||||
if nom.upper().find('.AI')!=-1 and t!='false':
|
||||
if not SHARP_IMPORT:
|
||||
warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3"
|
||||
SCALE = Blender.Draw.PupMenu(warning)
|
||||
|
||||
npat=0
|
||||
l=0
|
||||
do=0
|
||||
while l <len(t)-1 :
|
||||
if not do:
|
||||
do,l=pik_pattern(t,l)
|
||||
#print 'len(t)',len(t)
|
||||
t[l].replace('\n','')
|
||||
if t[l].find('%%EOF')==0:
|
||||
break
|
||||
if t[l][0]!='%':
|
||||
l0=t[l].split()
|
||||
#print l0
|
||||
if l0[0][0] in ['F','f','N','n','B','b']:
|
||||
l3=l0[0][0]
|
||||
courbes,n0,CP=Actions[l3](l3,n0,CP)
|
||||
l0[0]=l0[1:]
|
||||
|
||||
if l0[-1] in TAGcourbe:
|
||||
NOTHING_TODO=0
|
||||
if l0[-1] in ['C','c']:
|
||||
l2=t[l+1].split()
|
||||
courbes,n0,CP=Actions[l0[-1]](l0,l2,n0,CP)
|
||||
else:
|
||||
courbes,n0,CP=Actions[l0[-1]](l0,n0,CP)
|
||||
l=l+1; #print l
|
||||
t=[]
|
||||
|
||||
|
||||
courbes.number_of_items=len(courbes.ITEM.keys())
|
||||
for k in courbes.ITEM.keys():
|
||||
courbes.ITEM[k].pntsUV[0] =len(courbes.ITEM[k].beziers_knot)
|
||||
|
||||
|
||||
if courbes.number_of_items>0:
|
||||
if len(PATTERN.keys() )>0:
|
||||
#print len(PATTERN.keys() )
|
||||
warning = "Pattern list (for info not used): %t| "
|
||||
p0=1
|
||||
for P in PATTERN.keys():
|
||||
warning+="%s %%x%s|"%(P,p0)
|
||||
p0+=1
|
||||
Padd = Blender.Draw.PupMenu(warning)
|
||||
|
||||
t=create_GEOtext(courbes)
|
||||
save_GEOfile(dir,name[0],t)
|
||||
|
||||
# 0.1.8 ---------------------------------
|
||||
# [O.select(0) for O in Blender.Scene.getCurrent().getChildren()]
|
||||
# 0.1.8 ---------------------------------
|
||||
|
||||
Open_GEOfile(dir,name[0])
|
||||
|
||||
# 0.1.8 ---------------------------------
|
||||
Blender.Object.Get()[-1].setName(name[0])
|
||||
# 0.1.8 ---------------------------------
|
||||
|
||||
else:
|
||||
pass
|
||||
#=====================================================================
|
||||
#====================== AI format mouvements =========================
|
||||
#=====================================================================
|
||||
#=========================================================
|
||||
# une sorte de contournement qui permet d'utiliser la fonction
|
||||
# et de documenter les variables Window.FileSelector
|
||||
#=========================================================
|
||||
def fonctionSELECT(nom):
|
||||
global NOTHING_TODO,AI_VERSION
|
||||
scan_FILE(nom)
|
||||
if NOTHING_TODO==1:
|
||||
warning = "AI %s compatible file "%AI_VERSION+" but nothing to do ? %t| Perhaps a compacted file ... "
|
||||
NOTHING = Blender.Draw.PupMenu(warning)
|
||||
|
||||
if __name__=="__main__":
|
||||
Blender.Window.FileSelector (fonctionSELECT, 'SELECT AI FILE')
|
||||
#sys.path=oldpath
|
||||
@@ -1,452 +0,0 @@
|
||||
#----------------------------------------------
|
||||
# (c) jm soler juillet 2004-juin 2005 , released under Blender Artistic Licence
|
||||
# for the Blender 2.34-2.37 Python Scripts Bundle.
|
||||
#
|
||||
# last update: 06/05/2007
|
||||
#----------------------------------------------
|
||||
# Page officielle :
|
||||
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_eps.htm
|
||||
# Communiquer les problemes et erreurs sur:
|
||||
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
|
||||
#----------------------------------------------
|
||||
SHARP_IMPORT = 0
|
||||
SCALE = 1.0
|
||||
scale = 1
|
||||
|
||||
import sys
|
||||
#oldpath=sys.path
|
||||
|
||||
import Blender
|
||||
from Blender import Draw
|
||||
BLversion=Blender.Get('version')
|
||||
|
||||
try:
|
||||
import nt
|
||||
os=nt
|
||||
os.sep='\\'
|
||||
|
||||
except:
|
||||
import posix
|
||||
os=posix
|
||||
os.sep='/'
|
||||
|
||||
def isdir(path):
|
||||
try:
|
||||
st = os.stat(path)
|
||||
return 1
|
||||
except:
|
||||
return 0
|
||||
|
||||
def split(pathname):
|
||||
if pathname.find(os.sep)!=-1:
|
||||
k0=pathname.split(os.sep)
|
||||
else:
|
||||
if os.sep=='/':
|
||||
k0=pathname.split('\\')
|
||||
else:
|
||||
k0=pathname.split('/')
|
||||
|
||||
directory=pathname.replace(k0[len(k0)-1],'')
|
||||
Name=k0[len(k0)-1]
|
||||
return directory, Name
|
||||
|
||||
def join(l0,l1):
|
||||
return l0+os.sep+l1
|
||||
|
||||
os.isdir=isdir
|
||||
os.split=split
|
||||
os.join=join
|
||||
|
||||
def filtreFICHIER(nom):
|
||||
f=open(nom,'rU')
|
||||
t=f.readlines()
|
||||
f.close()
|
||||
if len(t)==1 and t[0].find('\r'):
|
||||
t=t[0].split('\r')
|
||||
if len(t)>1 and t[0].find('PS-Adobe-3.0')==-1 and t[0].find('EPSF')==-1:
|
||||
return t
|
||||
else:
|
||||
name = "OK?%t| Not a valid file or an empty file or... %x1| not a pure PS-Adobe-2.0 file %x2 "
|
||||
result = Blender.Draw.PupMenu(name)
|
||||
return 'false'
|
||||
|
||||
#===============================
|
||||
# Data
|
||||
#===============================
|
||||
#===============================
|
||||
# Blender Curve Data
|
||||
#===============================
|
||||
objBEZIER=0
|
||||
objSURFACE=5
|
||||
typBEZIER3D=1 #3D
|
||||
typBEZIER2D=9 #2D
|
||||
|
||||
class Bez:
|
||||
def __init__(self):
|
||||
self.co=[]
|
||||
self.ha=[0,0]
|
||||
|
||||
class ITEM:
|
||||
def __init__(self):
|
||||
self.type = typBEZIER3D,
|
||||
self.pntsUV = [0,0]
|
||||
self.resolUV = [32,0]
|
||||
self.orderUV = [0,0]
|
||||
self.flagUV = [0,0]
|
||||
self.Origine = [0.0,0.0]
|
||||
self.beziers_knot = []
|
||||
|
||||
class COURBE:
|
||||
def __init__(self):
|
||||
self.magic_number='3DG3'
|
||||
self.type = objBEZIER
|
||||
self.number_of_items = 0
|
||||
self.ext1_ext2 = [0,0]
|
||||
self.matrix = """0.0 0.0 1.0 0.0
|
||||
0.0 1.0 0.0 0.0
|
||||
0.0 0.0 1.0 0.0
|
||||
0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size
|
||||
self.ITEM = {}
|
||||
|
||||
courbes=COURBE()
|
||||
PATTERN={}
|
||||
BOUNDINGBOX={'rec':[],'coef':1.0}
|
||||
npat=0
|
||||
#=====================================================================
|
||||
#======== name of the curve in teh courbes dictionnary ===============
|
||||
#=====================================================================
|
||||
n0=0
|
||||
|
||||
#=====================================================================
|
||||
#====================== current Point ================================
|
||||
#=====================================================================
|
||||
CP=[0.0,0.0] #currentPoint
|
||||
|
||||
# modifs 12/06/2005
|
||||
#=====================================================================
|
||||
#====================== current transform ============================
|
||||
#=====================================================================
|
||||
class transform:
|
||||
def __init__(self,matrix=[1,0,01],x=0.0,y=0.0):
|
||||
self.matrix=matrix[:]
|
||||
self.xy=[x,y]
|
||||
|
||||
GSTACK = []
|
||||
stack=transform()
|
||||
GSTACK.append(stack)
|
||||
|
||||
GSCALE = [1.0,1.0]
|
||||
GTRANSLATE = [0.0,0.0]
|
||||
|
||||
def G_move(l,a):
|
||||
global GSCALE, GTRANSLATE, GSTACK
|
||||
#print GSCALE, GTRANSLATE, GSTACK
|
||||
return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a])
|
||||
# modifs 12/06/2005
|
||||
|
||||
#=====================================================================
|
||||
#===== to compare last position to the original move to displacement =
|
||||
#===== needed for cyclic efinition =================================
|
||||
#=====================================================================
|
||||
def test_egalitedespositions(f1,f2):
|
||||
if f1[0]==f2[0] and f1[1]==f2[1]:
|
||||
return Blender.TRUE
|
||||
else:
|
||||
return Blender.FALSE
|
||||
|
||||
|
||||
def Open_GEOfile(dir,nom):
|
||||
global SCALE,BOUNDINGBOX, scale
|
||||
if BLversion>=233:
|
||||
Blender.Load(dir+nom+'OOO.obj', 1)
|
||||
BO=Blender.Scene.GetCurrent().objects.active
|
||||
BO.RotY=3.1416
|
||||
BO.RotZ=3.1416
|
||||
BO.RotX=3.1416/2.0
|
||||
if scale==1:
|
||||
BO.LocY+=BOUNDINGBOX['rec'][3]
|
||||
else:
|
||||
BO.LocY+=BOUNDINGBOX['rec'][3]/SCALE
|
||||
|
||||
BO.makeDisplayList()
|
||||
Blender.Window.RedrawAll()
|
||||
else:
|
||||
print "Not yet implemented"
|
||||
|
||||
def create_GEOtext(courbes):
|
||||
global SCALE, B, BOUNDINGBOX,scale
|
||||
r=BOUNDINGBOX['rec']
|
||||
|
||||
if scale==1:
|
||||
SCALE=1.0
|
||||
elif scale==2:
|
||||
SCALE=r[2]-r[0]
|
||||
elif scale==3:
|
||||
SCALE=r[3]-r[1]
|
||||
|
||||
t=[]
|
||||
t.append(courbes.magic_number+'\n')
|
||||
t.append(str(courbes.type)+'\n')
|
||||
t.append(str(courbes.number_of_items)+'\n')
|
||||
t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n')
|
||||
t.append(courbes.matrix+'\n')
|
||||
|
||||
for k in courbes.ITEM.keys():
|
||||
t.append("%s\n"%courbes.ITEM[k].type)
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1]))
|
||||
|
||||
flag =courbes.ITEM[k].flagUV[0]
|
||||
|
||||
for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)):
|
||||
k1 =courbes.ITEM[k].beziers_knot[k2]
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE))
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE))
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE))
|
||||
t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n')
|
||||
return t
|
||||
|
||||
def save_GEOfile(dir,nom,t):
|
||||
f=open(dir+nom+'OOO.obj','w')
|
||||
f.writelines(t)
|
||||
f.close()
|
||||
|
||||
#name = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1"
|
||||
#result = Blender.Draw.PupMenu(name)
|
||||
|
||||
|
||||
#=====================================================================
|
||||
#===== EPS format : DEBUT =========================
|
||||
#=====================================================================
|
||||
def mouvement_vers(l,n0,CP):
|
||||
if n0 in courbes.ITEM.keys():
|
||||
#if test_egalitedespositions(courbes.ITEM[n0].Origine,CP):
|
||||
# courbes.ITEM[n0].flagUV[0]=1
|
||||
n0+=1
|
||||
CP=[l[-3].replace('d',''),l[-2]]
|
||||
else:
|
||||
CP=[l[-3].replace('d',''),l[-2]]
|
||||
#i=
|
||||
courbes.ITEM[n0]=ITEM()
|
||||
courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]]
|
||||
|
||||
B=Bez()
|
||||
B.co=[G_move(CP[0],0),
|
||||
G_move(CP[1],1),
|
||||
G_move(CP[0],0),
|
||||
G_move(CP[1],1),
|
||||
G_move(CP[0],0),
|
||||
G_move(CP[1],1)]
|
||||
|
||||
B.ha=[0,0]
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
|
||||
return courbes,n0,CP
|
||||
|
||||
def rmouvement_vers(l,n0,CP):
|
||||
if n0 in courbes.ITEM.keys():
|
||||
#if test_egalitedespositions(courbes.ITEM[n0].Origine,CP):
|
||||
# courbes.ITEM[n0].flagUV[0]=1
|
||||
n0+=1
|
||||
CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))]
|
||||
else:
|
||||
CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))]
|
||||
#i=
|
||||
courbes.ITEM[n0]=ITEM()
|
||||
courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]]
|
||||
|
||||
B=Bez()
|
||||
B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]]
|
||||
B.ha=[0,0]
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
return courbes,n0,CP
|
||||
|
||||
def courbe_vers_c(l, l2, n0,CP): #c,C
|
||||
"""
|
||||
B=Bez()
|
||||
B.co=[l[0],l[1],l[2],l[3],l[4],l[5]]
|
||||
B.ha=[0,0]
|
||||
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
"""
|
||||
B=Bez()
|
||||
B.co=[G_move(l[2],0),
|
||||
G_move(l[3],1),
|
||||
G_move(l[4],0),
|
||||
G_move(l[5],1),
|
||||
G_move(l[0],0),
|
||||
G_move(l[1],1)]
|
||||
if len(courbes.ITEM[n0].beziers_knot)==1:
|
||||
CP=[l[0],l[1]]
|
||||
courbes.ITEM[n0].Origine=[l[0],l[1]]
|
||||
if l[-1]=='C':
|
||||
B.ha=[2,2]
|
||||
else:
|
||||
B.ha=[0,0]
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
if len(l2)>1 and l2[-1] in Actions.keys():
|
||||
B.co[-2]=G_move(l2[0],0)
|
||||
B.co[-1]=G_move(l2[1],1)
|
||||
else:
|
||||
B.co[-2]=G_move(CP[0],0)
|
||||
B.co[-1]=G_move(CP[1],1)
|
||||
return courbes,n0,CP
|
||||
|
||||
def ligne_tracee_l(l,n0,CP):
|
||||
B=Bez()
|
||||
B.co=[G_move(l[0],0),
|
||||
G_move(l[1],1),
|
||||
G_move(l[0],0),
|
||||
G_move(l[1],1),
|
||||
G_move(l[0],0),
|
||||
G_move(l[1],1)]
|
||||
B.ha=[0,0]
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
CP=[l[0],l[1]]
|
||||
return courbes,n0,CP
|
||||
|
||||
def rligne_tracee_l(l,n0,CP):
|
||||
B=Bez()
|
||||
B.co=["%4f"%(float(l[0])+float(CP[0])),
|
||||
"%4f"%(float(l[1])+float(CP[1])),
|
||||
"%4f"%(float(l[0])+float(CP[0])),
|
||||
"%4f"%(float(l[1])+float(CP[1])),
|
||||
"%4f"%(float(l[0])+float(CP[0])),
|
||||
"%4f"%(float(l[1])+float(CP[1]))]
|
||||
B.ha=[0,0]
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
CP=[l[0],l[1]]
|
||||
return courbes,n0,CP
|
||||
|
||||
Actions= { "curveto" : courbe_vers_c,
|
||||
"curveto" : courbe_vers_c,
|
||||
"moveto" : mouvement_vers,
|
||||
"rmoveto" : mouvement_vers,
|
||||
"lineto" : ligne_tracee_l,
|
||||
"rlineto" : rligne_tracee_l
|
||||
}
|
||||
|
||||
TAGcourbe=Actions.keys()
|
||||
|
||||
"""
|
||||
def pik_pattern(t,l):
|
||||
global npat, PATTERN, BOUNDINGBOX
|
||||
while t[l].find('%%EndSetup')!=0:
|
||||
if t[l].find('%%BoundingBox:')!=-1:
|
||||
l0=t[l].split()
|
||||
BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])]
|
||||
r=BOUNDINGBOX['rec']
|
||||
BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0])
|
||||
print l,
|
||||
if t[l].find('BeginPatternLayer')!=-1:
|
||||
npat+=1
|
||||
PATTERN[npat]=[]
|
||||
while t[l].find('EndPatternLayer')==-1:
|
||||
print t[l]
|
||||
PATTERN[npat].append(l)
|
||||
l+=1
|
||||
if l+1<len(t):
|
||||
l=l+1
|
||||
else:
|
||||
return 1,l
|
||||
return 1,l
|
||||
"""
|
||||
|
||||
def scan_FILE(nom):
|
||||
global CP, courbes, SCALE, scale, GSTACK, GSCALE, GTRANSLATE
|
||||
dir,name=split(nom)
|
||||
name=name.split('.')
|
||||
n0=0
|
||||
result=0
|
||||
t=filtreFICHIER(nom)
|
||||
#print t
|
||||
if t!='false' and (nom.upper().find('.EPS')!=-1 or nom.upper().find('.PS')!=-1 ):
|
||||
if not SHARP_IMPORT:
|
||||
warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3"
|
||||
scale = Blender.Draw.PupMenu(warning)
|
||||
npat=0
|
||||
l=0
|
||||
do=0
|
||||
while l <len(t)-1 :
|
||||
if t[l].find('%%BoundingBox:')!=-1:
|
||||
l0=t[l].split()
|
||||
BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])]
|
||||
r=BOUNDINGBOX['rec']
|
||||
BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0])
|
||||
"""
|
||||
if not do:
|
||||
do,l=pik_pattern(t,l)
|
||||
"""
|
||||
#print 'len(t)',len(t)
|
||||
t[l].replace('\n','')
|
||||
if t[l][0]!='%':
|
||||
l0=t[l].split()
|
||||
if l0!=[] and l0[-1] in TAGcourbe:
|
||||
if l0[-1] in ['curveto']:
|
||||
l2=t[l+1].split()
|
||||
courbes,n0,CP=Actions[l0[-1]](l0,l2,n0,CP)
|
||||
else:
|
||||
courbes,n0,CP=Actions[l0[-1]](l0,n0,CP)
|
||||
# modifs 10/06/2005
|
||||
elif l0!=[] and l0[-1] in ['scale']:
|
||||
GSCALE=[float(l0[-3]),float(l0[-2])]
|
||||
elif l0!=[] and l0[-1] in ['translate']:
|
||||
GTRANSLATE=[float(l0[-3]),float(l0[-2])]
|
||||
elif l0!=[] and l0[-1] in ['concat'] and l0[0] in ['gsave']:
|
||||
l0[1]=l0[1].replace('[','')
|
||||
l0[-2]=l0[-2].replace(']','')
|
||||
stack=transform([float(l0[1]),float(l0[2]),float(l0[3]),float(l0[4])],float(l0[5]),float(l0[6]))
|
||||
GSTACK.append(stack)
|
||||
#print GSTACK
|
||||
elif l0!=[] and l0[-1] in ['concat'] and l0[0] in ['grestore']:
|
||||
del GSTACK[-1]
|
||||
# modifs 12/06/2005 : end
|
||||
|
||||
|
||||
l=l+1#; print l
|
||||
t=[]
|
||||
|
||||
if t!='false':
|
||||
courbes.number_of_items=len(courbes.ITEM.keys())
|
||||
|
||||
for k in courbes.ITEM.keys():
|
||||
courbes.ITEM[k].pntsUV[0] =len(courbes.ITEM[k].beziers_knot)
|
||||
|
||||
if test_egalitedespositions(courbes.ITEM[k].Origine,
|
||||
[courbes.ITEM[k].beziers_knot[-1].co[-2],
|
||||
courbes.ITEM[k].beziers_knot[-1].co[-1]]):
|
||||
courbes.ITEM[k].flagUV[0]=1
|
||||
courbes.ITEM[k].pntsUV[0] -=1
|
||||
|
||||
if courbes.number_of_items>0:
|
||||
if len(PATTERN.keys() )>0:
|
||||
#print len(PATTERN.keys() )
|
||||
pass
|
||||
t=create_GEOtext(courbes)
|
||||
save_GEOfile(dir,name[0],t)
|
||||
Open_GEOfile(dir,name[0])
|
||||
|
||||
# 03 juillet 2006 ----------------------
|
||||
Blender.Object.Get()[-1].setName(name[0])
|
||||
# 03 juillet 2006 ----------------------
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
#=====================================================================
|
||||
#====================== EPS format mouvements =========================
|
||||
#=====================================================================
|
||||
#=========================================================
|
||||
# une sorte de contournement qui permet d'utiliser la fonction
|
||||
# et de documenter les variables Window.FileSelector
|
||||
#=========================================================
|
||||
def fonctionSELECT(nom):
|
||||
scan_FILE(nom)
|
||||
|
||||
if __name__=="__main__":
|
||||
Blender.Window.FileSelector (fonctionSELECT, 'SELECT EPS FILE')
|
||||
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
# -*- coding: latin-1 -*-
|
||||
"""
|
||||
#----------------------------------------------
|
||||
# (c) jm soler juillet 2004,
|
||||
#----------------------------------------------
|
||||
released under GNU Licence
|
||||
for the Blender 2.45 Python Scripts Bundle.
|
||||
Ce programme est libre, vous pouvez le redistribuer et/ou
|
||||
le modifier selon les termes de la Licence Publique G<>n<EFBFBD>rale GNU
|
||||
publi<EFBFBD>e par la Free Software Foundation (version 2 ou bien toute
|
||||
autre version ult<6C>rieure choisie par vous).
|
||||
|
||||
Ce programme est distribu<62> car potentiellement utile, mais SANS
|
||||
AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties
|
||||
de commercialisation ou d'adaptation dans un but sp<73>cifique.
|
||||
Reportez-vous <20> la Licence Publique G<>n<EFBFBD>rale GNU pour plus de d<>tails.
|
||||
|
||||
Vous devez avoir re<72>u une copie de la Licence Publique G<>n<EFBFBD>rale GNU
|
||||
en m<>me temps que ce programme ; si ce n'est pas le cas, <20>crivez <20> la
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
MA 02111-1307, <20>tats-Unis.
|
||||
|
||||
|
||||
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
"""
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# last update : 07/05/2007
|
||||
#----------------------------------------------
|
||||
# Page officielle :
|
||||
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_gimp.htm
|
||||
# Communiquer les problemes et erreurs sur:
|
||||
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
|
||||
# Modification History:
|
||||
# 2008-03-12 Added character encoding line so french text does not break
|
||||
# python interpreters.
|
||||
#---------------------------------------------
|
||||
|
||||
SHARP_IMPORT=0
|
||||
SCALE=1
|
||||
|
||||
import sys
|
||||
#oldpath=sys.path
|
||||
|
||||
import Blender
|
||||
BLversion=Blender.Get('version')
|
||||
|
||||
try:
|
||||
import nt
|
||||
os=nt
|
||||
os.sep='\\'
|
||||
|
||||
except:
|
||||
import posix
|
||||
os=posix
|
||||
os.sep='/'
|
||||
|
||||
def isdir(path):
|
||||
try:
|
||||
st = os.stat(path)
|
||||
return 1
|
||||
except:
|
||||
return 0
|
||||
|
||||
def split(pathname):
|
||||
if pathname.find(os.sep)!=-1:
|
||||
k0=pathname.split(os.sep)
|
||||
else:
|
||||
if os.sep=='/':
|
||||
k0=pathname.split('\\')
|
||||
else:
|
||||
k0=pathname.split('/')
|
||||
|
||||
directory=pathname.replace(k0[len(k0)-1],'')
|
||||
Name=k0[len(k0)-1]
|
||||
return directory, Name
|
||||
|
||||
def join(l0,l1):
|
||||
return l0+os.sep+l1
|
||||
|
||||
os.isdir=isdir
|
||||
os.split=split
|
||||
os.join=join
|
||||
|
||||
def filtreFICHIER(nom):
|
||||
f=open(nom,'r')
|
||||
t=f.readlines()
|
||||
f.close()
|
||||
if len(t)==1 and t[0].find('\r'):
|
||||
t=t[0].split('\r')
|
||||
if len(t)>1 and t[1].find('#POINTS:')==0:
|
||||
return t
|
||||
else:
|
||||
warning = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1
|
||||
result = Blender.Draw.PupMenu(warning)
|
||||
return "false"
|
||||
|
||||
#===============================
|
||||
# Data
|
||||
#===============================
|
||||
#===============================
|
||||
# Blender Curve Data
|
||||
#===============================
|
||||
objBEZIER=0
|
||||
objSURFACE=5
|
||||
typBEZIER3D=1 #3D
|
||||
typBEZIER2D=9 #2D
|
||||
|
||||
class Bez:
|
||||
def __init__(self):
|
||||
self.co=[]
|
||||
self.ha=[0,0]
|
||||
|
||||
def echo(self):
|
||||
#print 'co = ', self.co
|
||||
#print 'ha = ', self.ha
|
||||
pass
|
||||
|
||||
class ITEM:
|
||||
def __init__(self):
|
||||
self.type = typBEZIER3D,
|
||||
self.pntsUV = [0,0]
|
||||
self.resolUV = [32,0]
|
||||
self.orderUV = [0,0]
|
||||
self.flagUV = [0,0]
|
||||
self.Origine = [0.0,0.0]
|
||||
self.beziers_knot = []
|
||||
|
||||
class COURBE:
|
||||
def __init__(self):
|
||||
self.magic_number='3DG3'
|
||||
self.type = objBEZIER
|
||||
self.number_of_items = 0
|
||||
self.ext1_ext2 = [0,0]
|
||||
self.matrix = """0.0 0.0 1.0 0.0
|
||||
0.0 1.0 0.0 0.0
|
||||
0.0 0.0 1.0 0.0
|
||||
0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size
|
||||
self.ITEM = {}
|
||||
|
||||
courbes=COURBE()
|
||||
PATTERN={}
|
||||
BOUNDINGBOX={'rec':[],'coef':1.0}
|
||||
npat=0
|
||||
#=====================================================================
|
||||
#======== name of the curve in the courbes dictionnary ===============
|
||||
#=====================================================================
|
||||
n0=0
|
||||
|
||||
#=====================================================================
|
||||
#====================== current Point ================================
|
||||
#=====================================================================
|
||||
CP=[0.0,0.0] #currentPoint
|
||||
|
||||
def MINMAX(b):
|
||||
global BOUNDINGBOX
|
||||
r=BOUNDINGBOX['rec']
|
||||
for m in range(0,len(b)-2,2):
|
||||
#print m, m+1 , len(b)-1
|
||||
#print b[m], r, r[0]
|
||||
if float(b[m])<r[0]:
|
||||
r[0]=float(b[m])
|
||||
|
||||
if float(b[m])>r[2]: r[2]=float(b[m])
|
||||
|
||||
if float(b[m+1])<r[1]: r[1]=float(b[m+1])
|
||||
if float(b[m+1])>r[3]: r[3]=float(b[m+1])
|
||||
|
||||
#=====================================================================
|
||||
#===== to compare last position to the original move to displacement =
|
||||
#===== needed for cyclic efinition =================================
|
||||
#=====================================================================
|
||||
def test_egalitedespositions(f1,f2):
|
||||
if f1[0]==f2[0] and f1[1]==f2[1]:
|
||||
return Blender.TRUE
|
||||
else:
|
||||
return Blender.FALSE
|
||||
|
||||
|
||||
def Open_GEOfile(dir,nom):
|
||||
if BLversion>=233:
|
||||
Blender.Load(dir+nom+'OOO.obj', 1)
|
||||
BO=Blender.Scene.GetCurrent().objects.active
|
||||
BO.LocZ=1.0
|
||||
BO.makeDisplayList()
|
||||
Blender.Window.RedrawAll()
|
||||
else:
|
||||
print "Not yet implemented"
|
||||
|
||||
def create_GEOtext(courbes):
|
||||
global SCALE, B, BOUNDINGBOX
|
||||
r=BOUNDINGBOX['rec']
|
||||
if SCALE==1:
|
||||
SCALE=1.0
|
||||
elif SCALE==2:
|
||||
SCALE=r[2]-r[0]
|
||||
elif SCALE==3:
|
||||
SCALE=r[3]-r[1]
|
||||
|
||||
t=[]
|
||||
t.append(courbes.magic_number+'\n')
|
||||
t.append(str(courbes.type)+'\n')
|
||||
t.append(str(courbes.number_of_items)+'\n')
|
||||
t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n')
|
||||
t.append(courbes.matrix+'\n')
|
||||
|
||||
for k in courbes.ITEM.keys():
|
||||
|
||||
t.append("%s\n"%courbes.ITEM[k].type)
|
||||
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1]))
|
||||
t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1]))
|
||||
|
||||
flag =0#courbes.ITEM[k].flagUV[0]
|
||||
|
||||
for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)):
|
||||
k1 =courbes.ITEM[k].beziers_knot[k2]
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE))
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE))
|
||||
t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE))
|
||||
t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n')
|
||||
return t
|
||||
|
||||
def save_GEOfile(dir,nom,t):
|
||||
f=open(dir+nom+'OOO.obj','w')
|
||||
f.writelines(t)
|
||||
f.close()
|
||||
#warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1"
|
||||
#result = Blender.Draw.PupMenu(warning)
|
||||
|
||||
|
||||
#=====================================================================
|
||||
#===== GIMP format : DEBUT =========================
|
||||
#=====================================================================
|
||||
CLOSED=0
|
||||
|
||||
def mouvement_vers(l,l1,l2,n0):
|
||||
global BOUNDINGBOX, CP
|
||||
if l[1] == '3' :
|
||||
n0+=1
|
||||
courbes.ITEM[n0]=ITEM()
|
||||
courbes.ITEM[n0].Origine=[l[-3],l[-1],]
|
||||
courbes.ITEM[n0-1].beziers_knot[0].co[0]=CP[0]
|
||||
courbes.ITEM[n0-1].beziers_knot[0].co[1]=CP[1]
|
||||
CP=[l2[-3], l2[-1]]
|
||||
|
||||
elif l[1]=='1' and (n0 not in courbes.ITEM.keys()):
|
||||
courbes.ITEM[n0]=ITEM()
|
||||
courbes.ITEM[n0].Origine=[l[-3],l[-1],]
|
||||
CP=[l2[-3], l2[-1]]
|
||||
|
||||
B=Bez()
|
||||
B.co=[ CP[0],CP[1],
|
||||
l1[-3], l1[-1],
|
||||
l[-3], l[-1]]
|
||||
|
||||
CP=[l2[-3], l2[-1]]
|
||||
|
||||
if BOUNDINGBOX['rec']==[]:
|
||||
BOUNDINGBOX['rec']=[float(l2[-3]), float(l2[-1]), float(l[-3]), float(l[-1])]
|
||||
B.ha=[0,0]
|
||||
|
||||
"""
|
||||
if len( courbes.ITEM[n0].beziers_knot)>=1:
|
||||
courbes.ITEM[n0].beziers_knot[-1].co[2]=l1[-3]
|
||||
courbes.ITEM[n0].beziers_knot[-1].co[3]=l1[-1]
|
||||
"""
|
||||
|
||||
MINMAX(B.co)
|
||||
courbes.ITEM[n0].beziers_knot.append(B)
|
||||
return courbes,n0
|
||||
|
||||
Actions= { "1" : mouvement_vers,
|
||||
"3" : mouvement_vers }
|
||||
|
||||
TAGcourbe=Actions.keys()
|
||||
|
||||
def scan_FILE(nom):
|
||||
global CP, courbes, SCALE, MAX, MIN, CLOSED
|
||||
dir,name=split(nom)
|
||||
name=name.split('.')
|
||||
#print name
|
||||
n0=0
|
||||
result=0
|
||||
t=filtreFICHIER(nom)
|
||||
if t!="false":
|
||||
if not SHARP_IMPORT:
|
||||
warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3"
|
||||
SCALE = Blender.Draw.PupMenu(warning)
|
||||
npat=0
|
||||
l=0
|
||||
while l <len(t)-1 :
|
||||
#print 'len(t)',len(t)
|
||||
t[l].replace('\n','')
|
||||
if t[l][0]!='%':
|
||||
l0=t[l].split()
|
||||
#print l0[0], l0[1]
|
||||
if l0[0]=='TYPE:' and l0[1] in TAGcourbe:
|
||||
#print l0[0], l0[1],
|
||||
l1=t[l+1].split()
|
||||
l2=t[l+2].split()
|
||||
courbes,n0=Actions[l0[1]](l0,l1,l2,n0)
|
||||
elif l0[0]=='#Point':
|
||||
POINTS= int(l0[0])
|
||||
elif l0[0]=='CLOSED:' and l0[1]=='1':
|
||||
CLOSED=1
|
||||
l=l+1;
|
||||
|
||||
courbes.number_of_items=len(courbes.ITEM.keys())
|
||||
|
||||
courbes.ITEM[n0].beziers_knot[0].co[0]=CP[0]
|
||||
courbes.ITEM[n0].beziers_knot[0].co[1]=CP[1]
|
||||
|
||||
for k in courbes.ITEM.keys():
|
||||
#print k
|
||||
if CLOSED == 1:
|
||||
B=Bez()
|
||||
B.co=courbes.ITEM[k].beziers_knot[0].co[:]
|
||||
B.ha=courbes.ITEM[k].beziers_knot[0].ha[:]
|
||||
B.echo()
|
||||
courbes.ITEM[k].beziers_knot.append(B)
|
||||
courbes.ITEM[k].flagUV[0]=1
|
||||
courbes.ITEM[k].pntsUV[0] =len(courbes.ITEM[k].beziers_knot)
|
||||
|
||||
if courbes.number_of_items>0:
|
||||
t=create_GEOtext(courbes)
|
||||
save_GEOfile(dir,name[0],t)
|
||||
Open_GEOfile(dir,name[0])
|
||||
# 0.1.8 ---------------------------------
|
||||
Blender.Object.Get()[-1].setName(name[0])
|
||||
# 0.1.8 ---------------------------------
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
#=====================================================================
|
||||
#====================== GIMP Path format mouvements =========================
|
||||
#=====================================================================
|
||||
#=========================================================
|
||||
# une sorte de contournement qui permet d'utiliser la fonction
|
||||
# et de documenter les variables Window.FileSelector
|
||||
#=========================================================
|
||||
def fonctionSELECT(nom):
|
||||
scan_FILE(nom)
|
||||
|
||||
if __name__=="__main__":
|
||||
Blender.Window.FileSelector (fonctionSELECT, 'SELECT GIMP FILE')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,757 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Motion Capture (.bvh)...'
|
||||
Blender: 242
|
||||
Group: 'Import'
|
||||
Tip: 'Import a (.bvh) motion capture file'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ("blender.org", "blenderartists.org")
|
||||
__version__ = "1.90 06/08/01"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script imports BVH motion capture data to Blender.
|
||||
as empties or armatures.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# BVH Import v2.0 by Campbell Barton (AKA Ideasman)
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
import bpy
|
||||
import BPyMessages
|
||||
Vector= Blender.Mathutils.Vector
|
||||
Euler= Blender.Mathutils.Euler
|
||||
Matrix= Blender.Mathutils.Matrix
|
||||
RotationMatrix = Blender.Mathutils.RotationMatrix
|
||||
TranslationMatrix= Blender.Mathutils.TranslationMatrix
|
||||
|
||||
DEG2RAD = 0.017453292519943295
|
||||
|
||||
class bvh_node_class(object):
|
||||
__slots__=(\
|
||||
'name',# bvh joint name
|
||||
'parent',# bvh_node_class type or None for no parent
|
||||
'children',# a list of children of this type.
|
||||
'rest_head_world',# worldspace rest location for the head of this node
|
||||
'rest_head_local',# localspace rest location for the head of this node
|
||||
'rest_tail_world',# # worldspace rest location for the tail of this node
|
||||
'rest_tail_local',# # worldspace rest location for the tail of this node
|
||||
'channels',# list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple
|
||||
'rot_order',# a triple of indicies as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation.
|
||||
'anim_data',# a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz)
|
||||
'has_loc',# Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1)
|
||||
'has_rot',# Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1)
|
||||
'temp')# use this for whatever you want
|
||||
|
||||
def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order):
|
||||
self.name= name
|
||||
self.rest_head_world= rest_head_world
|
||||
self.rest_head_local= rest_head_local
|
||||
self.rest_tail_world= None
|
||||
self.rest_tail_local= None
|
||||
self.parent= parent
|
||||
self.channels= channels
|
||||
self.rot_order= rot_order
|
||||
|
||||
# convenience functions
|
||||
self.has_loc= channels[0] != -1 or channels[1] != -1 or channels[2] != -1
|
||||
self.has_rot= channels[3] != -1 or channels[4] != -1 or channels[5] != -1
|
||||
|
||||
|
||||
self.children= []
|
||||
|
||||
# list of 6 length tuples: (lx,ly,lz, rx,ry,rz)
|
||||
# even if the channels arnt used they will just be zero
|
||||
#
|
||||
self.anim_data= [(0,0,0,0,0,0)]
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return 'BVH name:"%s", rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)' %\
|
||||
(self.name,\
|
||||
self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z,\
|
||||
self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z)
|
||||
|
||||
|
||||
|
||||
# Change the order rotation is applied.
|
||||
MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1])
|
||||
MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])
|
||||
|
||||
def eulerRotate(x,y,z, rot_order):
|
||||
# Clamp all values between 0 and 360, values outside this raise an error.
|
||||
mats=[RotationMatrix(x%360,3,'x'), RotationMatrix(y%360,3,'y'), RotationMatrix(z%360,3,'z')]
|
||||
# print rot_order
|
||||
# Standard BVH multiplication order, apply the rotation in the order Z,X,Y
|
||||
return (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).toEuler()
|
||||
|
||||
def read_bvh(file_path, GLOBAL_SCALE=1.0):
|
||||
# File loading stuff
|
||||
# Open the file for importing
|
||||
file = open(file_path, 'rU')
|
||||
|
||||
# Seperate into a list of lists, each line a list of words.
|
||||
file_lines = file.readlines()
|
||||
# Non standard carrage returns?
|
||||
if len(file_lines) == 1:
|
||||
file_lines = file_lines[0].split('\r')
|
||||
|
||||
# Split by whitespace.
|
||||
file_lines =[ll for ll in [ l.split() for l in file_lines] if ll]
|
||||
|
||||
|
||||
# Create Hirachy as empties
|
||||
|
||||
if file_lines[0][0].lower() == 'hierarchy':
|
||||
#print 'Importing the BVH Hierarchy for:', file_path
|
||||
pass
|
||||
else:
|
||||
raise 'ERROR: This is not a BVH file'
|
||||
|
||||
bvh_nodes= {None:None}
|
||||
bvh_nodes_serial = [None]
|
||||
|
||||
channelIndex = -1
|
||||
|
||||
|
||||
lineIdx = 0 # An index for the file.
|
||||
while lineIdx < len(file_lines) -1:
|
||||
#...
|
||||
if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint':
|
||||
|
||||
# Join spaces into 1 word with underscores joining it.
|
||||
if len(file_lines[lineIdx]) > 2:
|
||||
file_lines[lineIdx][1] = '_'.join(file_lines[lineIdx][1:])
|
||||
file_lines[lineIdx] = file_lines[lineIdx][:2]
|
||||
|
||||
# MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.??
|
||||
|
||||
# Make sure the names are unique- Object names will match joint names exactly and both will be unique.
|
||||
name = file_lines[lineIdx][1]
|
||||
|
||||
#print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1])
|
||||
|
||||
lineIdx += 2 # Incriment to the next line (Offset)
|
||||
rest_head_local = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) )
|
||||
lineIdx += 1 # Incriment to the next line (Channels)
|
||||
|
||||
# newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
|
||||
# newChannel references indecies to the motiondata,
|
||||
# if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended
|
||||
# We'll add a zero value onto the end of the MotionDATA so this is always refers to a value.
|
||||
my_channel = [-1, -1, -1, -1, -1, -1]
|
||||
my_rot_order= [None, None, None]
|
||||
rot_count= 0
|
||||
for channel in file_lines[lineIdx][2:]:
|
||||
channel= channel.lower()
|
||||
channelIndex += 1 # So the index points to the right channel
|
||||
if channel == 'xposition': my_channel[0] = channelIndex
|
||||
elif channel == 'yposition': my_channel[1] = channelIndex
|
||||
elif channel == 'zposition': my_channel[2] = channelIndex
|
||||
|
||||
elif channel == 'xrotation':
|
||||
my_channel[3] = channelIndex
|
||||
my_rot_order[rot_count]= 0
|
||||
rot_count+=1
|
||||
elif channel == 'yrotation':
|
||||
my_channel[4] = channelIndex
|
||||
my_rot_order[rot_count]= 1
|
||||
rot_count+=1
|
||||
elif channel == 'zrotation':
|
||||
my_channel[5] = channelIndex
|
||||
my_rot_order[rot_count]= 2
|
||||
rot_count+=1
|
||||
|
||||
channels = file_lines[lineIdx][2:]
|
||||
|
||||
my_parent= bvh_nodes_serial[-1] # account for none
|
||||
|
||||
|
||||
# Apply the parents offset accumletivly
|
||||
if my_parent==None:
|
||||
rest_head_world= Vector(rest_head_local)
|
||||
else:
|
||||
rest_head_world= my_parent.rest_head_world + rest_head_local
|
||||
|
||||
bvh_node= bvh_nodes[name]= bvh_node_class(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order)
|
||||
|
||||
# If we have another child then we can call ourselves a parent, else
|
||||
bvh_nodes_serial.append(bvh_node)
|
||||
|
||||
# Account for an end node
|
||||
if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it.
|
||||
lineIdx += 2 # Incriment to the next line (Offset)
|
||||
rest_tail = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) )
|
||||
|
||||
bvh_nodes_serial[-1].rest_tail_world= bvh_nodes_serial[-1].rest_head_world + rest_tail
|
||||
bvh_nodes_serial[-1].rest_tail_local= rest_tail
|
||||
|
||||
|
||||
# Just so we can remove the Parents in a uniform way- End end never has kids
|
||||
# so this is a placeholder
|
||||
bvh_nodes_serial.append(None)
|
||||
|
||||
if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}']
|
||||
bvh_nodes_serial.pop() # Remove the last item
|
||||
|
||||
if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion':
|
||||
#print '\nImporting motion data'
|
||||
lineIdx += 3 # Set the cursor to the first frame
|
||||
break
|
||||
|
||||
lineIdx += 1
|
||||
|
||||
|
||||
# Remove the None value used for easy parent reference
|
||||
del bvh_nodes[None]
|
||||
# Dont use anymore
|
||||
del bvh_nodes_serial
|
||||
|
||||
bvh_nodes_list= bvh_nodes.values()
|
||||
|
||||
while lineIdx < len(file_lines):
|
||||
line= file_lines[lineIdx]
|
||||
for bvh_node in bvh_nodes_list:
|
||||
#for bvh_node in bvh_nodes_serial:
|
||||
lx= ly= lz= rx= ry= rz= 0.0
|
||||
channels= bvh_node.channels
|
||||
anim_data= bvh_node.anim_data
|
||||
if channels[0] != -1:
|
||||
lx= GLOBAL_SCALE * float( line[channels[0]] )
|
||||
|
||||
if channels[1] != -1:
|
||||
ly= GLOBAL_SCALE * float( line[channels[1]] )
|
||||
|
||||
if channels[2] != -1:
|
||||
lz= GLOBAL_SCALE * float( line[channels[2]] )
|
||||
|
||||
if channels[3] != -1 or channels[4] != -1 or channels[5] != -1:
|
||||
rx, ry, rz = eulerRotate(float( line[channels[3]] ), float( line[channels[4]] ), float( line[channels[5]] ), bvh_node.rot_order)
|
||||
#x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d
|
||||
|
||||
# Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling.
|
||||
# Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation.
|
||||
|
||||
while anim_data[-1][3] - rx > 180: rx+=360
|
||||
while anim_data[-1][3] - rx < -180: rx-=360
|
||||
|
||||
while anim_data[-1][4] - ry > 180: ry+=360
|
||||
while anim_data[-1][4] - ry < -180: ry-=360
|
||||
|
||||
while anim_data[-1][5] - rz > 180: rz+=360
|
||||
while anim_data[-1][5] - rz < -180: rz-=360
|
||||
|
||||
# Done importing motion data #
|
||||
anim_data.append( (lx, ly, lz, rx, ry, rz) )
|
||||
lineIdx += 1
|
||||
|
||||
# Assign children
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
bvh_node_parent= bvh_node.parent
|
||||
if bvh_node_parent:
|
||||
bvh_node_parent.children.append(bvh_node)
|
||||
|
||||
# Now set the tip of each bvh_node
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
|
||||
if not bvh_node.rest_tail_world:
|
||||
if len(bvh_node.children)==0:
|
||||
# could just fail here, but rare BVH files have childless nodes
|
||||
bvh_node.rest_tail_world = Vector(bvh_node.rest_head_world)
|
||||
bvh_node.rest_tail_local = Vector(bvh_node.rest_head_local)
|
||||
elif len(bvh_node.children)==1:
|
||||
bvh_node.rest_tail_world= Vector(bvh_node.children[0].rest_head_world)
|
||||
bvh_node.rest_tail_local= Vector(bvh_node.children[0].rest_head_local)
|
||||
else:
|
||||
# allow this, see above
|
||||
#if not bvh_node.children:
|
||||
# raise 'error, bvh node has no end and no children. bad file'
|
||||
|
||||
# Removed temp for now
|
||||
rest_tail_world= Vector(0,0,0)
|
||||
rest_tail_local= Vector(0,0,0)
|
||||
for bvh_node_child in bvh_node.children:
|
||||
rest_tail_world += bvh_node_child.rest_head_world
|
||||
rest_tail_local += bvh_node_child.rest_head_local
|
||||
|
||||
bvh_node.rest_tail_world= rest_tail_world * (1.0/len(bvh_node.children))
|
||||
bvh_node.rest_tail_local= rest_tail_local * (1.0/len(bvh_node.children))
|
||||
|
||||
# Make sure tail isnt the same location as the head.
|
||||
if (bvh_node.rest_tail_local-bvh_node.rest_head_local).length <= 0.001*GLOBAL_SCALE:
|
||||
|
||||
bvh_node.rest_tail_local.y= bvh_node.rest_tail_local.y + GLOBAL_SCALE/10
|
||||
bvh_node.rest_tail_world.y= bvh_node.rest_tail_world.y + GLOBAL_SCALE/10
|
||||
|
||||
|
||||
|
||||
return bvh_nodes
|
||||
|
||||
|
||||
|
||||
def bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False):
|
||||
|
||||
if IMPORT_START_FRAME<1:
|
||||
IMPORT_START_FRAME= 1
|
||||
|
||||
scn= bpy.data.scenes.active
|
||||
scn.objects.selected = []
|
||||
|
||||
objects= []
|
||||
|
||||
def add_ob(name):
|
||||
ob = scn.objects.new('Empty')
|
||||
objects.append(ob)
|
||||
return ob
|
||||
|
||||
# Add objects
|
||||
for name, bvh_node in bvh_nodes.iteritems():
|
||||
bvh_node.temp= add_ob(name)
|
||||
|
||||
# Parent the objects
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
bvh_node.temp.makeParent([ bvh_node_child.temp for bvh_node_child in bvh_node.children ], 1, 0) # ojbs, noninverse, 1 = not fast.
|
||||
|
||||
# Offset
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
# Make relative to parents offset
|
||||
bvh_node.temp.loc= bvh_node.rest_head_local
|
||||
|
||||
# Add tail objects
|
||||
for name, bvh_node in bvh_nodes.iteritems():
|
||||
if not bvh_node.children:
|
||||
ob_end= add_ob(name + '_end')
|
||||
bvh_node.temp.makeParent([ob_end], 1, 0) # ojbs, noninverse, 1 = not fast.
|
||||
ob_end.loc= bvh_node.rest_tail_local
|
||||
|
||||
|
||||
# Animate the data, the last used bvh_node will do since they all have the same number of frames
|
||||
for current_frame in xrange(len(bvh_node.anim_data)):
|
||||
Blender.Set('curframe', current_frame+IMPORT_START_FRAME)
|
||||
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame]
|
||||
|
||||
rest_head_local= bvh_node.rest_head_local
|
||||
bvh_node.temp.loc= rest_head_local.x+lx, rest_head_local.y+ly, rest_head_local.z+lz
|
||||
|
||||
bvh_node.temp.rot= rx*DEG2RAD,ry*DEG2RAD,rz*DEG2RAD
|
||||
|
||||
bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT)
|
||||
|
||||
scn.update(1)
|
||||
return objects
|
||||
|
||||
|
||||
|
||||
def bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False):
|
||||
|
||||
if IMPORT_START_FRAME<1:
|
||||
IMPORT_START_FRAME= 1
|
||||
|
||||
|
||||
# Add the new armature,
|
||||
scn = bpy.data.scenes.active
|
||||
scn.objects.selected = []
|
||||
|
||||
arm_data= bpy.data.armatures.new()
|
||||
arm_ob = scn.objects.new(arm_data)
|
||||
scn.objects.context = [arm_ob]
|
||||
scn.objects.active = arm_ob
|
||||
|
||||
# Put us into editmode
|
||||
arm_data.makeEditable()
|
||||
|
||||
# Get the average bone length for zero length bones, we may not use this.
|
||||
average_bone_length= 0.0
|
||||
nonzero_count= 0
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
l= (bvh_node.rest_head_local-bvh_node.rest_tail_local).length
|
||||
if l:
|
||||
average_bone_length+= l
|
||||
nonzero_count+=1
|
||||
|
||||
# Very rare cases all bones couldbe zero length???
|
||||
if not average_bone_length:
|
||||
average_bone_length = 0.1
|
||||
else:
|
||||
# Normal operation
|
||||
average_bone_length = average_bone_length/nonzero_count
|
||||
|
||||
|
||||
|
||||
ZERO_AREA_BONES= []
|
||||
for name, bvh_node in bvh_nodes.iteritems():
|
||||
# New editbone
|
||||
bone= bvh_node.temp= Blender.Armature.Editbone()
|
||||
|
||||
bone.name= name
|
||||
arm_data.bones[name]= bone
|
||||
|
||||
bone.head= bvh_node.rest_head_world
|
||||
bone.tail= bvh_node.rest_tail_world
|
||||
|
||||
# ZERO AREA BONES.
|
||||
if (bone.head-bone.tail).length < 0.001:
|
||||
if bvh_node.parent:
|
||||
ofs= bvh_node.parent.rest_head_local- bvh_node.parent.rest_tail_local
|
||||
if ofs.length: # is our parent zero length also?? unlikely
|
||||
bone.tail= bone.tail+ofs
|
||||
else:
|
||||
bone.tail.y= bone.tail.y+average_bone_length
|
||||
else:
|
||||
bone.tail.y= bone.tail.y+average_bone_length
|
||||
|
||||
ZERO_AREA_BONES.append(bone.name)
|
||||
|
||||
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
if bvh_node.parent:
|
||||
# bvh_node.temp is the Editbone
|
||||
|
||||
# Set the bone parent
|
||||
bvh_node.temp.parent= bvh_node.parent.temp
|
||||
|
||||
# Set the connection state
|
||||
if not bvh_node.has_loc and\
|
||||
bvh_node.parent and\
|
||||
bvh_node.parent.temp.name not in ZERO_AREA_BONES and\
|
||||
bvh_node.parent.rest_tail_local == bvh_node.rest_head_local:
|
||||
bvh_node.temp.options= [Blender.Armature.CONNECTED]
|
||||
|
||||
# Replace the editbone with the editbone name,
|
||||
# to avoid memory errors accessing the editbone outside editmode
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
bvh_node.temp= bvh_node.temp.name
|
||||
|
||||
arm_data.update()
|
||||
|
||||
# Now Apply the animation to the armature
|
||||
|
||||
# Get armature animation data
|
||||
pose= arm_ob.getPose()
|
||||
pose_bones= pose.bones
|
||||
|
||||
action = Blender.Armature.NLA.NewAction("Action")
|
||||
action.setActive(arm_ob)
|
||||
#xformConstants= [ Blender.Object.Pose.LOC, Blender.Object.Pose.ROT ]
|
||||
|
||||
# Replace the bvh_node.temp (currently an editbone)
|
||||
# With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv)
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
bone_name= bvh_node.temp # may not be the same name as the bvh_node, could have been shortened.
|
||||
pose_bone= pose_bones[bone_name]
|
||||
rest_bone= arm_data.bones[bone_name]
|
||||
bone_rest_matrix = rest_bone.matrix['ARMATURESPACE'].rotationPart()
|
||||
|
||||
bone_rest_matrix_inv= Matrix(bone_rest_matrix)
|
||||
bone_rest_matrix_inv.invert()
|
||||
|
||||
bone_rest_matrix_inv.resize4x4()
|
||||
bone_rest_matrix.resize4x4()
|
||||
bvh_node.temp= (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv)
|
||||
|
||||
|
||||
# Make a dict for fast access without rebuilding a list all the time.
|
||||
xformConstants_dict={
|
||||
(True,True): [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],\
|
||||
(False,True): [Blender.Object.Pose.ROT],\
|
||||
(True,False): [Blender.Object.Pose.LOC],\
|
||||
(False,False): [],\
|
||||
}
|
||||
|
||||
|
||||
# KEYFRAME METHOD, SLOW, USE IPOS DIRECT
|
||||
|
||||
# Animate the data, the last used bvh_node will do since they all have the same number of frames
|
||||
for current_frame in xrange(len(bvh_node.anim_data)-1): # skip the first frame (rest frame)
|
||||
# print current_frame
|
||||
|
||||
#if current_frame==40: # debugging
|
||||
# break
|
||||
|
||||
# Dont neet to set the current frame
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp
|
||||
lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame+1]
|
||||
|
||||
if bvh_node.has_rot:
|
||||
# Set the rotation, not so simple
|
||||
bone_rotation_matrix= Euler(rx,ry,rz).toMatrix()
|
||||
bone_rotation_matrix.resize4x4()
|
||||
pose_bone.quat= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()
|
||||
|
||||
if bvh_node.has_loc:
|
||||
# Set the Location, simple too
|
||||
pose_bone.loc= (\
|
||||
TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local ) *\
|
||||
bone_rest_matrix_inv).translationPart() # WHY * 10? - just how pose works
|
||||
|
||||
# Get the transform
|
||||
xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot]
|
||||
|
||||
|
||||
if xformConstants:
|
||||
# Insert the keyframe from the loc/quat
|
||||
pose_bone.insertKey(arm_ob, current_frame+IMPORT_START_FRAME, xformConstants, True )
|
||||
|
||||
# First time, set the IPO's to linear
|
||||
if current_frame==0:
|
||||
for ipo in action.getAllChannelIpos().itervalues():
|
||||
if ipo:
|
||||
for cur in ipo:
|
||||
cur.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
|
||||
if IMPORT_LOOP:
|
||||
cur.extend = Blender.IpoCurve.ExtendTypes.CYCLIC
|
||||
|
||||
|
||||
|
||||
|
||||
# END KEYFRAME METHOD
|
||||
|
||||
|
||||
"""
|
||||
# IPO KEYFRAME SETTING
|
||||
# Add in the IPOs by adding keyframes, AFAIK theres no way to add IPOs to an action so I do this :/
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp
|
||||
|
||||
# Get the transform
|
||||
xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot]
|
||||
if xformConstants:
|
||||
pose_bone.loc[:]= 0,0,0
|
||||
pose_bone.quat[:]= 0,0,1,0
|
||||
# Insert the keyframe from the loc/quat
|
||||
pose_bone.insertKey(arm_ob, IMPORT_START_FRAME, xformConstants)
|
||||
|
||||
|
||||
action_ipos= action.getAllChannelIpos()
|
||||
|
||||
|
||||
for bvh_node in bvh_nodes.itervalues():
|
||||
has_loc= bvh_node.has_loc
|
||||
has_rot= bvh_node.has_rot
|
||||
|
||||
if not has_rot and not has_loc:
|
||||
# No animation data
|
||||
continue
|
||||
|
||||
ipo= action_ipos[bvh_node.temp[0].name] # posebones name as key
|
||||
|
||||
if has_loc:
|
||||
curve_xloc= ipo[Blender.Ipo.PO_LOCX]
|
||||
curve_yloc= ipo[Blender.Ipo.PO_LOCY]
|
||||
curve_zloc= ipo[Blender.Ipo.PO_LOCZ]
|
||||
|
||||
curve_xloc.interpolation= \
|
||||
curve_yloc.interpolation= \
|
||||
curve_zloc.interpolation= \
|
||||
Blender.IpoCurve.InterpTypes.LINEAR
|
||||
|
||||
|
||||
if has_rot:
|
||||
curve_wquat= ipo[Blender.Ipo.PO_QUATW]
|
||||
curve_xquat= ipo[Blender.Ipo.PO_QUATX]
|
||||
curve_yquat= ipo[Blender.Ipo.PO_QUATY]
|
||||
curve_zquat= ipo[Blender.Ipo.PO_QUATZ]
|
||||
|
||||
curve_wquat.interpolation= \
|
||||
curve_xquat.interpolation= \
|
||||
curve_yquat.interpolation= \
|
||||
curve_zquat.interpolation= \
|
||||
Blender.IpoCurve.InterpTypes.LINEAR
|
||||
|
||||
# Get the bone
|
||||
pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp
|
||||
|
||||
|
||||
def pose_rot(anim_data):
|
||||
bone_rotation_matrix= Euler(anim_data[3], anim_data[4], anim_data[5]).toMatrix()
|
||||
bone_rotation_matrix.resize4x4()
|
||||
return tuple((bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()) # qw,qx,qy,qz
|
||||
|
||||
def pose_loc(anim_data):
|
||||
return tuple((TranslationMatrix(Vector(anim_data[0], anim_data[1], anim_data[2])) * bone_rest_matrix_inv).translationPart())
|
||||
|
||||
|
||||
last_frame= len(bvh_node.anim_data)+IMPORT_START_FRAME-1
|
||||
|
||||
if has_loc:
|
||||
pose_locations= [pose_loc(anim_key) for anim_key in bvh_node.anim_data]
|
||||
|
||||
# Add the start at the end, we know the start is just 0,0,0 anyway
|
||||
curve_xloc.append((last_frame, pose_locations[-1][0]))
|
||||
curve_yloc.append((last_frame, pose_locations[-1][1]))
|
||||
curve_zloc.append((last_frame, pose_locations[-1][2]))
|
||||
|
||||
if len(pose_locations) > 1:
|
||||
ox,oy,oz= pose_locations[0]
|
||||
x,y,z= pose_locations[1]
|
||||
|
||||
for i in xrange(1, len(pose_locations)-1): # from second frame to second last frame
|
||||
|
||||
nx,ny,nz= pose_locations[i+1]
|
||||
xset= yset= zset= True # we set all these by default
|
||||
if abs((ox+nx)/2 - x) < 0.00001: xset= False
|
||||
if abs((oy+ny)/2 - y) < 0.00001: yset= False
|
||||
if abs((oz+nz)/2 - z) < 0.00001: zset= False
|
||||
|
||||
if xset: curve_xloc.append((i+IMPORT_START_FRAME, x))
|
||||
if yset: curve_yloc.append((i+IMPORT_START_FRAME, y))
|
||||
if zset: curve_zloc.append((i+IMPORT_START_FRAME, z))
|
||||
|
||||
# Set the old and use the new
|
||||
ox,oy,oz= x,y,z
|
||||
x,y,z= nx,ny,nz
|
||||
|
||||
|
||||
if has_rot:
|
||||
pose_rotations= [pose_rot(anim_key) for anim_key in bvh_node.anim_data]
|
||||
|
||||
# Add the start at the end, we know the start is just 0,0,0 anyway
|
||||
curve_wquat.append((last_frame, pose_rotations[-1][0]))
|
||||
curve_xquat.append((last_frame, pose_rotations[-1][1]))
|
||||
curve_yquat.append((last_frame, pose_rotations[-1][2]))
|
||||
curve_zquat.append((last_frame, pose_rotations[-1][3]))
|
||||
|
||||
|
||||
if len(pose_rotations) > 1:
|
||||
ow,ox,oy,oz= pose_rotations[0]
|
||||
w,x,y,z= pose_rotations[1]
|
||||
|
||||
for i in xrange(1, len(pose_rotations)-1): # from second frame to second last frame
|
||||
|
||||
nw, nx,ny,nz= pose_rotations[i+1]
|
||||
wset= xset= yset= zset= True # we set all these by default
|
||||
if abs((ow+nw)/2 - w) < 0.00001: wset= False
|
||||
if abs((ox+nx)/2 - x) < 0.00001: xset= False
|
||||
if abs((oy+ny)/2 - y) < 0.00001: yset= False
|
||||
if abs((oz+nz)/2 - z) < 0.00001: zset= False
|
||||
|
||||
if wset: curve_wquat.append((i+IMPORT_START_FRAME, w))
|
||||
if xset: curve_xquat.append((i+IMPORT_START_FRAME, x))
|
||||
if yset: curve_yquat.append((i+IMPORT_START_FRAME, y))
|
||||
if zset: curve_zquat.append((i+IMPORT_START_FRAME, z))
|
||||
|
||||
# Set the old and use the new
|
||||
ow,ox,oy,oz= w,x,y,z
|
||||
w,x,y,z= nw,nx,ny,nz
|
||||
|
||||
# IPO KEYFRAME SETTING
|
||||
"""
|
||||
pose.update()
|
||||
return arm_ob
|
||||
|
||||
|
||||
#=============#
|
||||
# TESTING #
|
||||
#=============#
|
||||
|
||||
#('/metavr/mocap/bvh/boxer.bvh')
|
||||
#('/d/staggered_walk.bvh')
|
||||
#('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF
|
||||
#('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings.
|
||||
#('/metavr/mocap/bvh/walk4.bvh') # 0 channels
|
||||
|
||||
'''
|
||||
import os
|
||||
DIR = '/metavr/mocap/bvh/'
|
||||
for f in ('/d/staggered_walk.bvh',):
|
||||
#for f in os.listdir(DIR)[5:6]:
|
||||
#for f in os.listdir(DIR):
|
||||
if f.endswith('.bvh'):
|
||||
s = Blender.Scene.New(f)
|
||||
s.makeCurrent()
|
||||
#file= DIR + f
|
||||
file= f
|
||||
print f
|
||||
bvh_nodes= read_bvh(file, 1.0)
|
||||
bvh_node_dict2armature(bvh_nodes, 1)
|
||||
'''
|
||||
|
||||
def load_bvh_ui(file, PREF_UI= True):
|
||||
|
||||
if BPyMessages.Error_NoFile(file):
|
||||
return
|
||||
|
||||
Draw= Blender.Draw
|
||||
|
||||
IMPORT_SCALE = Draw.Create(0.1)
|
||||
IMPORT_START_FRAME = Draw.Create(1)
|
||||
IMPORT_AS_ARMATURE = Draw.Create(1)
|
||||
IMPORT_AS_EMPTIES = Draw.Create(0)
|
||||
IMPORT_LOOP = Draw.Create(0)
|
||||
|
||||
# Get USER Options
|
||||
if PREF_UI:
|
||||
pup_block = [\
|
||||
('As Armature', IMPORT_AS_ARMATURE, 'Imports the BVH as an armature'),\
|
||||
('As Empties', IMPORT_AS_EMPTIES, 'Imports the BVH as empties'),\
|
||||
('Scale: ', IMPORT_SCALE, 0.001, 100.0, 'Scale the BVH, Use 0.01 when 1.0 is 1 metre'),\
|
||||
('Start Frame: ', IMPORT_START_FRAME, 1, 30000, 'Frame to start BVH motion'),\
|
||||
('Loop Animation', IMPORT_LOOP, 'Enable cyclic IPOs'),\
|
||||
]
|
||||
|
||||
if not Draw.PupBlock('BVH Import...', pup_block):
|
||||
return
|
||||
|
||||
print 'Attempting import BVH', file
|
||||
|
||||
IMPORT_SCALE = IMPORT_SCALE.val
|
||||
IMPORT_START_FRAME = IMPORT_START_FRAME.val
|
||||
IMPORT_AS_ARMATURE = IMPORT_AS_ARMATURE.val
|
||||
IMPORT_AS_EMPTIES = IMPORT_AS_EMPTIES.val
|
||||
IMPORT_LOOP = IMPORT_LOOP.val
|
||||
|
||||
if not IMPORT_AS_ARMATURE and not IMPORT_AS_EMPTIES:
|
||||
Blender.Draw.PupMenu('No import option selected')
|
||||
return
|
||||
Blender.Window.WaitCursor(1)
|
||||
# Get the BVH data and act on it.
|
||||
t1= Blender.sys.time()
|
||||
print '\tparsing bvh...',
|
||||
bvh_nodes= read_bvh(file, IMPORT_SCALE)
|
||||
print '%.4f' % (Blender.sys.time()-t1)
|
||||
t1= Blender.sys.time()
|
||||
print '\timporting to blender...',
|
||||
if IMPORT_AS_ARMATURE: bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP)
|
||||
if IMPORT_AS_EMPTIES: bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP)
|
||||
|
||||
print 'Done in %.4f\n' % (Blender.sys.time()-t1)
|
||||
Blender.Window.WaitCursor(0)
|
||||
|
||||
def main():
|
||||
Blender.Window.FileSelector(load_bvh_ui, 'Import BVH', '*.bvh')
|
||||
|
||||
if __name__ == '__main__':
|
||||
#def foo():
|
||||
main()
|
||||
'''
|
||||
scn = bpy.data.scenes.active
|
||||
for ob in list(scn.objects):
|
||||
if ob.name!='arm__':
|
||||
scn.objects.unlink(ob)
|
||||
load_bvh_ui('/test.bvh', False)
|
||||
'''
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,121 +0,0 @@
|
||||
#!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:<br>
|
||||
- a camera called "10" will become active at frame 10.<br>
|
||||
- a camera called "10,25,185" will become active at frames 10, 25 and 185.
|
||||
|
||||
Notes:<br>
|
||||
- This script creates another script named camera.py, which is linked to the current scene.<br>
|
||||
- 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.
|
||||
- Script inspired by Jean-Michel (jms) Soler's:<br>
|
||||
http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm
|
||||
"""
|
||||
|
||||
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004-2005: Regis Montoya
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
#Script inspired of the idea of 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
|
||||
|
||||
header = '# camera.py 1.3 scriptlink'
|
||||
|
||||
camera_change_scriptlink = header + \
|
||||
'''
|
||||
import Blender
|
||||
def main():
|
||||
scn = Blender.Scene.GetCurrent()
|
||||
frame = str(Blender.Get('curframe'))
|
||||
|
||||
# change the camera if it has the current frame
|
||||
for ob_cam in [ob for ob in scn.objects if ob.type == 'Camera']:
|
||||
for number in ob_cam.name.split(','):
|
||||
if number == frame:
|
||||
scn.setCurrentCamera(ob_cam)
|
||||
return
|
||||
main()
|
||||
'''
|
||||
|
||||
def main():
|
||||
|
||||
# Get the text
|
||||
try: cam_text = Blender.Text.Get('camera.py')
|
||||
except: cam_text = None
|
||||
|
||||
if cam_text:
|
||||
if cam_text.asLines()[0] != header:
|
||||
ret = Blender.Draw.PupMenu("WARNING: An old camera.py exists%t|Overwrite|Rename old version text")
|
||||
if ret == -1: return # EXIT DO NOTHING
|
||||
elif ret == 1: Text.unlink(cam_text)
|
||||
elif ret == 2: cam_text.name = 'old_camera.txt'
|
||||
cam_text = None
|
||||
|
||||
if not cam_text:
|
||||
scripting=Blender.Text.New('camera.py')
|
||||
scripting.write(camera_change_scriptlink)
|
||||
|
||||
scn=Scene.GetCurrent()
|
||||
scriptlinks = scn.getScriptLinks('FrameChanged')
|
||||
if not scriptlinks or ('camera.py' not in scriptlinks):
|
||||
scn.addScriptLink('camera.py','FrameChanged')
|
||||
Blender.Draw.PupMenu('FrameChange Scriptlink Added%t|Name camera objects to their activation frame numbers(s) seperated by commas|valid names are "1,10,46" or "1,10,200" or "200" (without quotation marks)')
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,801 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Scripts Config Editor'
|
||||
Blender: 236
|
||||
Group: 'System'
|
||||
Tooltip: 'View and edit available scripts configuration data'
|
||||
"""
|
||||
|
||||
__author__ = "Willian P. Germano"
|
||||
__version__ = "0.1 2005/04/14"
|
||||
__email__ = ('scripts', 'Author, wgermano:ig*com*br')
|
||||
__url__ = ('blender', 'blenderartists.org')
|
||||
|
||||
__bpydoc__ ="""\
|
||||
This script can be used to view and edit configuration data stored
|
||||
by other scripts.
|
||||
|
||||
Technical: this data is saved as dictionary keys with the
|
||||
Blender.Registry module functions. It is persistent while Blender is
|
||||
running and, if the script's author chose to, is also saved to a file
|
||||
in the scripts config data dir.
|
||||
|
||||
Usage:
|
||||
|
||||
- Start Screen:
|
||||
|
||||
To access any available key, select it from (one of) the menu(s).
|
||||
|
||||
Hotkeys:<br>
|
||||
ESC or Q: [Q]uit<br>
|
||||
H: [H]elp
|
||||
|
||||
- Keys Config Screen:
|
||||
|
||||
This screen exposes the configuration data for the chosen script key. If the
|
||||
buttons don't fit completely on the screen, you can scroll up or down with
|
||||
arrow keys or a mouse wheel. Leave the mouse pointer over any button to get
|
||||
a tooltip about that option.
|
||||
|
||||
Any change can be reverted -- unless you have already applied it.
|
||||
|
||||
If the key is already stored in a config file, there will be a toggle button
|
||||
(called 'file') that controls whether the changes will be written back to
|
||||
the file or not. If you just want to change the configuration for the current
|
||||
session, simply unset that button. Note, though, that data from files has
|
||||
precedence over those keys already loaded in Blender, so if you re-run this
|
||||
config editor, unsaved changes will not be seen.
|
||||
|
||||
Hotkeys:<br>
|
||||
ESC: back to Start Screen<br>
|
||||
Q: [Q]uit<br>
|
||||
U: [U]ndo changes<br>
|
||||
ENTER: apply changes (can't be reverted, then)<br>
|
||||
UP, DOWN Arrows and mouse wheel: scroll text up / down
|
||||
|
||||
Notes:
|
||||
|
||||
a) Available keys are determined by which scripts you use. If the key you
|
||||
expect isn't available (or maybe there are none or too few keys), either the
|
||||
related script doesn't need or still doesn't support this feature or the key
|
||||
has not been stored yet, in which case you just need to run that script once
|
||||
to make its config data available.
|
||||
|
||||
b) There are two places where config data files can be saved: the
|
||||
bpydata/config/ dir (1) inside the default scripts dir or (2) inside the user
|
||||
defined Python scripts dir
|
||||
(User Preferences window -> File Paths tab -> Python path). If available,
|
||||
(2) is the default and also the recommended option, because then fresh Blender
|
||||
installations won't delete your config data. To use this option, simply set a
|
||||
dir for Python scripts at the User Preferences window and make sure this dir
|
||||
has the subdirs bpydata/ and bpydata/config/ inside it.
|
||||
|
||||
c) The key called "General" in the "Other" menu has general config options.
|
||||
All scripts where that data is relevant are recommended to access it and set
|
||||
behaviors accordingly.
|
||||
"""
|
||||
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# config.py version 0.1 2005/04/08
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender import Draw, BGL, Registry, Window, sys as bsys
|
||||
from Blender.Window import Theme
|
||||
from BPyRegistry import LoadConfigData, SaveConfigData, HasConfigData,\
|
||||
BPY_KEY_IN_FILE
|
||||
|
||||
MAX_STR_LEN = 300 # max length for a string
|
||||
MAX_ITEMS_NUM = 100 # max number for each type of button
|
||||
|
||||
# ---
|
||||
# The "General" configure options key is managed from this script.
|
||||
verbose = True
|
||||
confirm_overwrite = True
|
||||
|
||||
tooltips = {
|
||||
'verbose': 'print script messages (info, warnings, errors) to the console',
|
||||
'confirm_overwrite': 'scripts should always confirm before overwriting files'
|
||||
}
|
||||
|
||||
CFG_LIST = ['verbose', 'confirm_overwrite', 'tooltips']
|
||||
KEY_NAME = 'General'
|
||||
|
||||
def update_registry():
|
||||
rd = {}
|
||||
for var in CFG_LIST:
|
||||
exec("rd['%s']=%s" % (var, var))
|
||||
Registry.SetKey(KEY_NAME, rd, True)
|
||||
|
||||
rd = Registry.GetKey('General', True)
|
||||
if rd:
|
||||
try:
|
||||
for var in CFG_LIST[:-1]: # no need to update tooltips
|
||||
exec("%s=rd['%s']" % (var, var))
|
||||
except: update_registry()
|
||||
|
||||
else:
|
||||
update_registry()
|
||||
# ---
|
||||
|
||||
# script globals:
|
||||
CFGKEY = ''
|
||||
LABELS = []
|
||||
GD = {} # groups dict (includes "Other" for unmapped keys)
|
||||
INDEX = 0 # to pass button indices to fs callbacks
|
||||
FREEKEY_IDX = 0 # index of set of keys not mapped to a script name
|
||||
KEYMENUS = []
|
||||
ALL_SCRIPTS = {}
|
||||
ALL_GROUPS = []
|
||||
START_SCREEN = 0
|
||||
CONFIG_SCREEN = 1
|
||||
DISK_UPDATE = True # write changed data to its config file
|
||||
|
||||
ACCEPTED_TYPES = [bool, int, float, str, unicode]
|
||||
|
||||
SCREEN = START_SCREEN
|
||||
|
||||
SCROLL_DOWN = 0
|
||||
|
||||
# events:
|
||||
BEVT_START = 50
|
||||
BEVT_EXIT = 0 + BEVT_START
|
||||
BEVT_BACK = 1 + BEVT_START
|
||||
BEVT_DISK = 2 + BEVT_START
|
||||
BEVT_CANCEL = 3 + BEVT_START
|
||||
BEVT_APPLY = 4 + BEVT_START
|
||||
BEVT_HELP = 5 + BEVT_START
|
||||
BEVT_DEL = 6 + BEVT_START
|
||||
BEVT_KEYMENU = []
|
||||
BUT_KEYMENU = []
|
||||
BEVT_BOOL = 100
|
||||
BEVT_INT = BEVT_BOOL + MAX_ITEMS_NUM
|
||||
BEVT_FLOAT = BEVT_BOOL + 2*MAX_ITEMS_NUM
|
||||
BEVT_STR = BEVT_BOOL + 3*MAX_ITEMS_NUM
|
||||
BEVT_BROWSEDIR = BEVT_BOOL + 4*MAX_ITEMS_NUM
|
||||
BEVT_BROWSEFILE = BEVT_BOOL + 5*MAX_ITEMS_NUM
|
||||
BUT_TYPES = {
|
||||
bool: 0,
|
||||
int: 0,
|
||||
float: 0,
|
||||
str: 0
|
||||
}
|
||||
|
||||
# Function definitions:
|
||||
|
||||
def get_keys():
|
||||
LoadConfigData() # loads all data from files in (u)scripts/bpydata/config/
|
||||
return [k for k in Registry.Keys() if k[0] != "_"]
|
||||
|
||||
|
||||
def show_help(script = 'config.py'):
|
||||
Blender.ShowHelp(script)
|
||||
|
||||
|
||||
def fs_dir_callback(pathname):
|
||||
global CFGKEY, INDEX
|
||||
|
||||
pathname = bsys.dirname(pathname)
|
||||
datatypes = CFGKEY.sorteddata
|
||||
datatypes[str][INDEX][1] = pathname
|
||||
|
||||
|
||||
def fs_file_callback(pathname):
|
||||
global CFGKEY, INDEX
|
||||
|
||||
datatypes = CFGKEY.sorteddata
|
||||
datatypes[str][INDEX][1] = pathname
|
||||
|
||||
|
||||
# parse Bpymenus file to get all script filenames
|
||||
# (used to show help for a given key)
|
||||
def fill_scripts_dict():
|
||||
global ALL_SCRIPTS, ALL_GROUPS
|
||||
|
||||
group = ''
|
||||
group_len = 0
|
||||
sep = bsys.sep
|
||||
home = Blender.Get('homedir')
|
||||
if not home:
|
||||
errmsg = """
|
||||
Can't find Blender's home dir and so can't find the
|
||||
Bpymenus file automatically stored inside it, which
|
||||
is needed by this script. Please run the
|
||||
Help -> System -> System Information script to get
|
||||
information about how to fix this.
|
||||
"""
|
||||
raise SystemError, errmsg
|
||||
fname = bsys.join(home, 'Bpymenus')
|
||||
if not bsys.exists(fname): return False
|
||||
f = file(fname, 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
for l in lines:
|
||||
if l.rfind('{') > 0:
|
||||
group = l.split()[0]
|
||||
ALL_GROUPS.append(group)
|
||||
group_len += 1
|
||||
continue
|
||||
elif l[0] != "'": continue
|
||||
fields = l.split("'")
|
||||
if len(fields) > 2:
|
||||
menuname = fields[1].replace('...','')
|
||||
fields = fields[2].split()
|
||||
if len(fields) > 1:
|
||||
fname = fields[1].split(sep)[-1]
|
||||
i = 1
|
||||
while not fname.endswith('.py'):
|
||||
i += 1
|
||||
fname = "%s %s" % (fname, fields[i])
|
||||
ALL_SCRIPTS[fname] = (menuname, group_len - 1)
|
||||
return True
|
||||
|
||||
|
||||
def map_to_registered_script(name):
|
||||
global ALL_SCRIPTS
|
||||
|
||||
if not name.endswith('.py'):
|
||||
name = "%s.py" % name
|
||||
if ALL_SCRIPTS.has_key(name):
|
||||
return ALL_SCRIPTS[name] # == (menuname, group index)
|
||||
return None
|
||||
|
||||
|
||||
def reset():
|
||||
global LABELS, GD, KEYMENUS, KEYS
|
||||
|
||||
# init_data is recalled when a key is deleted, so:
|
||||
LABELS = []
|
||||
GD = {}
|
||||
KEYMENUS = []
|
||||
KEYS = get_keys()
|
||||
|
||||
|
||||
# gather all script info, fill gui menus
|
||||
def init_data():
|
||||
global KEYS, GD, ALL_GROUPS, ALL_SCRIPTS, KEYMENUS, LABELS
|
||||
global BUT_KEYMENU, BEVT_KEYMENU, FREEKEY_IDX
|
||||
|
||||
for k in ALL_GROUPS:
|
||||
GD[k] = []
|
||||
GD[None] = []
|
||||
|
||||
for k in KEYS:
|
||||
res = map_to_registered_script(k)
|
||||
if res:
|
||||
GD[ALL_GROUPS[res[1]]].append((k, res[0]))
|
||||
else: GD[None].append((k, k))
|
||||
|
||||
for k in GD.keys():
|
||||
if not GD[k]: GD.pop(k)
|
||||
|
||||
if GD.has_key(None):
|
||||
GD['Other'] = GD[None]
|
||||
GD.pop(None)
|
||||
FREEKEY_IDX = -1
|
||||
|
||||
BUT_KEYMENU = range(len(GD))
|
||||
|
||||
for k in GD.keys():
|
||||
kmenu = ['Configuration Keys: %s%%t' % k]
|
||||
for j in GD[k]:
|
||||
kmenu.append(j[1])
|
||||
kmenu = "|".join(kmenu)
|
||||
KEYMENUS.append(kmenu)
|
||||
LABELS.append(k)
|
||||
|
||||
if FREEKEY_IDX < 0:
|
||||
FREEKEY_IDX = LABELS.index('Other')
|
||||
|
||||
length = len(KEYMENUS)
|
||||
BEVT_KEYMENU = range(1, length + 1)
|
||||
BUT_KEYMENU = range(length)
|
||||
|
||||
|
||||
# for theme colors:
|
||||
def float_colors(cols):
|
||||
return map(lambda x: x / 255.0, cols)
|
||||
|
||||
|
||||
|
||||
class Config:
|
||||
|
||||
def __init__(self, key, has_group = True):
|
||||
global DISK_UPDATE
|
||||
|
||||
self.key = key
|
||||
self.has_group = has_group
|
||||
self.name = key
|
||||
self.fromdisk = HasConfigData(key) & BPY_KEY_IN_FILE
|
||||
if not self.fromdisk: DISK_UPDATE = False
|
||||
else: DISK_UPDATE = True
|
||||
|
||||
self.origdata = Registry.GetKey(key, True)
|
||||
data = self.data = self.origdata.copy()
|
||||
|
||||
if not data:
|
||||
Draw.PupMenu('ERROR: couldn\'t find requested data')
|
||||
self.data = None
|
||||
return
|
||||
|
||||
keys = data.keys()
|
||||
nd = {}
|
||||
for k in keys:
|
||||
nd[k.lower()] = k
|
||||
|
||||
if nd.has_key('tooltips'):
|
||||
ndval = nd['tooltips']
|
||||
self.tips = data[ndval]
|
||||
data.pop(ndval)
|
||||
else: self.tips = 0
|
||||
|
||||
if nd.has_key('limits'):
|
||||
ndval = nd['limits']
|
||||
self.limits = data[ndval]
|
||||
data.pop(ndval)
|
||||
else: self.limits = 0
|
||||
|
||||
if self.has_group:
|
||||
scriptname = key
|
||||
if not scriptname.endswith('.py'):
|
||||
scriptname = "%s.py" % scriptname
|
||||
elif nd.has_key('script'):
|
||||
ndval = nd['script']
|
||||
scriptname = data[ndval]
|
||||
data.pop(ndval)
|
||||
if not scriptname.endswith('.py'):
|
||||
scriptname = "%s.py" % scriptname
|
||||
else: scriptname = None
|
||||
|
||||
self.scriptname = scriptname
|
||||
|
||||
self.sort()
|
||||
|
||||
|
||||
def needs_update(self): # check if user changed data
|
||||
data = self.data
|
||||
new = self.sorteddata
|
||||
|
||||
for vartype in new.keys():
|
||||
for i in new[vartype]:
|
||||
if data[i[0]] != i[1]: return 1
|
||||
|
||||
return 0 # no changes
|
||||
|
||||
|
||||
def update(self): # update original key
|
||||
global DISK_UPDATE
|
||||
|
||||
data = self.data
|
||||
odata = self.origdata
|
||||
new = self.sorteddata
|
||||
for vartype in new.keys():
|
||||
for i in new[vartype]:
|
||||
if data[i[0]] != i[1]: data[i[0]] = i[1]
|
||||
if odata[i[0]] != i[1]: odata[i[0]] = i[1]
|
||||
|
||||
if DISK_UPDATE: Registry.SetKey(self.key, odata, True)
|
||||
|
||||
def delete(self):
|
||||
global DISK_UPDATE
|
||||
|
||||
delmsg = 'OK?%t|Delete key from memory'
|
||||
if DISK_UPDATE:
|
||||
delmsg = "%s and from disk" % delmsg
|
||||
if Draw.PupMenu(delmsg) == 1:
|
||||
Registry.RemoveKey(self.key, DISK_UPDATE)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def revert(self): # revert to original key
|
||||
data = self.data
|
||||
new = self.sorteddata
|
||||
for vartype in new.keys():
|
||||
for i in new[vartype]:
|
||||
if data[i[0]] != i[1]: i[1] = data[i[0]]
|
||||
|
||||
|
||||
def sort(self): # create a new dict with types as keys
|
||||
global ACCEPTED_TYPES, BUT_TYPES
|
||||
|
||||
data = self.data
|
||||
datatypes = {}
|
||||
keys = [k for k in data.keys() if k[0] != '_']
|
||||
for k in keys:
|
||||
val = data[k]
|
||||
tval = type(val)
|
||||
if tval not in ACCEPTED_TYPES: continue
|
||||
if not datatypes.has_key(tval):
|
||||
datatypes[tval] = []
|
||||
datatypes[type(val)].append([k, val])
|
||||
if datatypes.has_key(unicode):
|
||||
if not datatypes.has_key(str): datatypes[str] = datatypes[unicode]
|
||||
else:
|
||||
for i in datatypes[unicode]: datatypes[str].append(i)
|
||||
datatypes.pop(unicode)
|
||||
for k in datatypes.keys():
|
||||
dk = datatypes[k]
|
||||
dk.sort()
|
||||
dk.reverse()
|
||||
BUT_TYPES[k] = range(len(dk))
|
||||
self.sorteddata = datatypes
|
||||
|
||||
|
||||
# GUI:
|
||||
|
||||
# gui callbacks:
|
||||
|
||||
def gui(): # drawing the screen
|
||||
|
||||
global SCREEN, START_SCREEN, CONFIG_SCREEN, KEYMENUS, LABELS
|
||||
global BEVT_KEYMENU, BUT_KEYMENU, CFGKEY
|
||||
global BUT_TYPES, SCROLL_DOWN, VARS_NUM
|
||||
|
||||
WIDTH, HEIGHT = Window.GetAreaSize()
|
||||
|
||||
theme = Theme.Get()[0]
|
||||
tui = theme.get('ui')
|
||||
ttxt = theme.get('text')
|
||||
|
||||
COL_BG = float_colors(ttxt.back)
|
||||
COL_TXT = ttxt.text
|
||||
COL_TXTHI = ttxt.text_hi
|
||||
|
||||
BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3])
|
||||
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
|
||||
BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
|
||||
|
||||
if SCREEN == START_SCREEN:
|
||||
x = 10
|
||||
y = 10
|
||||
h = 20
|
||||
w = 90
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text('Select a configuration key to access it. Press Q or ESC to leave.')
|
||||
km_len = len(KEYMENUS)
|
||||
km_columns = (WIDTH - x) / w
|
||||
if km_columns == 0: km_rows = km_len
|
||||
else:
|
||||
km_rows = km_len / km_columns
|
||||
if (km_len % km_columns): km_rows += 1
|
||||
if km_rows == 0: km_rows = 1
|
||||
ystart = y + 2*h*km_rows
|
||||
if ystart > (HEIGHT - 70): ystart = HEIGHT - 70
|
||||
y = ystart
|
||||
column = 1
|
||||
for i, km in enumerate(KEYMENUS):
|
||||
column += 1
|
||||
BGL.glRasterPos2i(x + 2, y + h + 5)
|
||||
Draw.Text(LABELS[i])
|
||||
BUT_KEYMENU[i] = Draw.Menu(km, BEVT_KEYMENU[i],
|
||||
x, y, w - 10, h, 0, 'Choose a key to access its configuration data')
|
||||
if column > km_columns:
|
||||
column = 1
|
||||
y -= 2*h
|
||||
if y < 35: break
|
||||
x = 10
|
||||
else: x += w
|
||||
x = 10
|
||||
y = 50 + ystart
|
||||
BGL.glColor3ub(COL_TXTHI[0], COL_TXTHI[1], COL_TXTHI[2])
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text('Scripts Configuration Editor')
|
||||
Draw.PushButton('help', BEVT_HELP, x, 22, 45, 16,
|
||||
'View help information about this script (hotkey: H)')
|
||||
|
||||
elif SCREEN == CONFIG_SCREEN:
|
||||
x = y = 10
|
||||
h = 18
|
||||
data = CFGKEY.sorteddata
|
||||
tips = CFGKEY.tips
|
||||
fromdisk = CFGKEY.fromdisk
|
||||
limits = CFGKEY.limits
|
||||
VARS_NUM = 0
|
||||
for k in data.keys():
|
||||
VARS_NUM += len(data[k])
|
||||
lines = VARS_NUM + 5 # to account for header and footer
|
||||
y = lines*h
|
||||
if y > HEIGHT - 20: y = HEIGHT - 20
|
||||
BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text('Scripts Configuration Editor')
|
||||
y -= 20
|
||||
BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
|
||||
txtsize = 10
|
||||
if HEIGHT < lines*h:
|
||||
BGL.glRasterPos2i(10, 5)
|
||||
txtsize += Draw.Text('Arrow keys or mouse wheel to scroll, ')
|
||||
BGL.glRasterPos2i(txtsize, 5)
|
||||
Draw.Text('Q or ESC to return.')
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text('Key: "%s"' % CFGKEY.name)
|
||||
bh = 16
|
||||
bw = 45
|
||||
by = 16
|
||||
i = -1
|
||||
if CFGKEY.scriptname:
|
||||
i = 0
|
||||
Draw.PushButton('help', BEVT_HELP, x, by, bw, bh,
|
||||
'Show documentation for the script that owns this key (hotkey: H)')
|
||||
Draw.PushButton('back', BEVT_BACK, x + (1+i)*bw, by, bw, bh,
|
||||
'Back to config keys selection screen (hotkey: ESC)')
|
||||
Draw.PushButton('exit', BEVT_EXIT, x + (2+i)*bw, by, bw, bh,
|
||||
'Exit from Scripts Config Editor (hotkey: Q)')
|
||||
Draw.PushButton('revert', BEVT_CANCEL, x + (3+i)*bw, by, bw, bh,
|
||||
'Revert data to original values (hotkey: U)')
|
||||
Draw.PushButton('apply', BEVT_APPLY, x + (4+i)*bw, by, bw, bh,
|
||||
'Apply changes, if any (hotkey: ENTER)')
|
||||
delmsg = 'Delete this data key from memory'
|
||||
if fromdisk: delmsg = "%s and from disk" % delmsg
|
||||
Draw.PushButton('delete', BEVT_DEL, x + (5+i)*bw, by, bw, bh,
|
||||
'%s (hotkey: DELETE)' % delmsg)
|
||||
if fromdisk:
|
||||
Draw.Toggle("file", BEVT_DISK, x + 3 + (6+i)*bw, by, bw, bh, DISK_UPDATE,
|
||||
'Update also the file where this config key is stored')
|
||||
i = -1
|
||||
top = -1
|
||||
y -= 20
|
||||
yend = 30
|
||||
if data.has_key(bool) and y > 0:
|
||||
lst = data[bool]
|
||||
for l in lst:
|
||||
top += 1
|
||||
i += 1
|
||||
if top < SCROLL_DOWN: continue
|
||||
y -= h
|
||||
if y < yend: break
|
||||
w = 20
|
||||
tog = data[bool][i][1]
|
||||
if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
|
||||
else: tooltip = "click to toggle"
|
||||
BUT_TYPES[bool][i] = Draw.Toggle("", BEVT_BOOL + i,
|
||||
x, y, w, h, tog, tooltip)
|
||||
BGL.glRasterPos2i(x + w + 3, y + 5)
|
||||
Draw.Text(l[0].lower().replace('_', ' '))
|
||||
i = -1
|
||||
y -= 5
|
||||
if data.has_key(int) and y > 0:
|
||||
lst = data[int]
|
||||
for l in lst:
|
||||
w = 70
|
||||
top += 1
|
||||
i += 1
|
||||
if top < SCROLL_DOWN: continue
|
||||
y -= h
|
||||
if y < yend: break
|
||||
val = data[int][i][1]
|
||||
if limits: min, max = limits[l[0]]
|
||||
else: min, max = 0, 10
|
||||
if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
|
||||
else: tooltip = "click / drag to change"
|
||||
BUT_TYPES[int][i] = Draw.Number("", BEVT_INT + i,
|
||||
x, y, w, h, val, min, max, tooltip)
|
||||
BGL.glRasterPos2i(x + w + 3, y + 3)
|
||||
Draw.Text(l[0].lower().replace('_', ' '))
|
||||
i = -1
|
||||
y -= 5
|
||||
if data.has_key(float) and y > 0:
|
||||
lst = data[float]
|
||||
for l in lst:
|
||||
w = 70
|
||||
top += 1
|
||||
i += 1
|
||||
if top < SCROLL_DOWN: continue
|
||||
y -= h
|
||||
if y < yend: break
|
||||
val = data[float][i][1]
|
||||
if limits: min, max = limits[l[0]]
|
||||
else: min, max = 0.0, 1.0
|
||||
if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
|
||||
else: tooltip = "click and drag to change"
|
||||
BUT_TYPES[float][i] = Draw.Number("", BEVT_FLOAT + i,
|
||||
x, y, w, h, val, min, max, tooltip)
|
||||
BGL.glRasterPos2i(x + w + 3, y + 3)
|
||||
Draw.Text(l[0].lower().replace('_', ' '))
|
||||
i = -1
|
||||
y -= 5
|
||||
if data.has_key(str) and y > 0:
|
||||
lst = data[str]
|
||||
for l in lst:
|
||||
top += 1
|
||||
i += 1
|
||||
if top < SCROLL_DOWN: continue
|
||||
y -= h
|
||||
if y < yend: break
|
||||
name = l[0].lower()
|
||||
is_dir = is_file = False
|
||||
if name.find('_dir', -4) > 0: is_dir = True
|
||||
elif name.find('_file', -5) > 0: is_file = True
|
||||
w = WIDTH - 20
|
||||
wbrowse = 50
|
||||
if is_dir and w > wbrowse: w -= wbrowse
|
||||
if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
|
||||
else: tooltip = "click to write a new string"
|
||||
name = name.replace('_',' ') + ': '
|
||||
if len(l[1]) > MAX_STR_LEN:
|
||||
l[1] = l[1][:MAX_STR_LEN]
|
||||
BUT_TYPES[str][i] = Draw.String(name, BEVT_STR + i,
|
||||
x, y, w, h, l[1], MAX_STR_LEN, tooltip)
|
||||
if is_dir:
|
||||
Draw.PushButton('browse', BEVT_BROWSEDIR + i, x+w+1, y, wbrowse, h,
|
||||
'click to open a file selector (pick any file in the desired dir)')
|
||||
elif is_file:
|
||||
Draw.PushButton('browse', BEVT_BROWSEFILE + i, x + w + 1, y, 50, h,
|
||||
'click to open a file selector')
|
||||
|
||||
|
||||
def fit_scroll():
|
||||
global SCROLL_DOWN, VARS_NUM
|
||||
max = VARS_NUM - 1 # so last item is always visible
|
||||
if SCROLL_DOWN > max:
|
||||
SCROLL_DOWN = max
|
||||
elif SCROLL_DOWN < 0:
|
||||
SCROLL_DOWN = 0
|
||||
|
||||
|
||||
def event(evt, val): # input events
|
||||
|
||||
global SCREEN, START_SCREEN, CONFIG_SCREEN
|
||||
global SCROLL_DOWN, CFGKEY
|
||||
|
||||
if not val: return
|
||||
|
||||
if evt == Draw.ESCKEY:
|
||||
if SCREEN == START_SCREEN: Draw.Exit()
|
||||
else:
|
||||
if CFGKEY.needs_update():
|
||||
if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
|
||||
CFGKEY.update()
|
||||
SCREEN = START_SCREEN
|
||||
SCROLL_DOWN = 0
|
||||
Draw.Redraw()
|
||||
return
|
||||
elif evt == Draw.QKEY:
|
||||
if SCREEN == CONFIG_SCREEN and CFGKEY.needs_update():
|
||||
if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
|
||||
CFGKEY.update()
|
||||
Draw.Exit()
|
||||
return
|
||||
elif evt == Draw.HKEY:
|
||||
if SCREEN == START_SCREEN: show_help()
|
||||
elif CFGKEY.scriptname: show_help(CFGKEY.scriptname)
|
||||
return
|
||||
|
||||
elif SCREEN == CONFIG_SCREEN:
|
||||
if evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE]:
|
||||
SCROLL_DOWN += 1
|
||||
fit_scroll()
|
||||
elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE]:
|
||||
SCROLL_DOWN -= 1
|
||||
fit_scroll()
|
||||
elif evt == Draw.UKEY:
|
||||
if CFGKEY.needs_update():
|
||||
CFGKEY.revert()
|
||||
elif evt == Draw.RETKEY or evt == Draw.PADENTER:
|
||||
if CFGKEY.needs_update():
|
||||
CFGKEY.update()
|
||||
elif evt == Draw.DELKEY:
|
||||
if CFGKEY.delete():
|
||||
reset()
|
||||
init_data()
|
||||
SCREEN = START_SCREEN
|
||||
SCROLL_DOWN = 0
|
||||
else: return
|
||||
Draw.Redraw()
|
||||
|
||||
|
||||
def button_event(evt): # gui button events
|
||||
|
||||
global SCREEN, START_SCREEN, CONFIG_SCREEN, CFGKEY, DISK_UPDATE
|
||||
global BEVT_KEYMENU, BUT_KEYMENU, BUT_TYPES, SCROLL_DOWN, GD, INDEX
|
||||
global BEVT_EXIT, BEVT_BACK, BEVT_APPLY, BEVT_CANCEL, BEVT_HELP, FREEKEY_IDX
|
||||
|
||||
if SCREEN == START_SCREEN:
|
||||
for e in BEVT_KEYMENU:
|
||||
if evt == e:
|
||||
index = e - 1
|
||||
k = BUT_KEYMENU[index].val - 1
|
||||
CFGKEY = Config(GD[LABELS[index]][k][0], index != FREEKEY_IDX)
|
||||
if CFGKEY.data:
|
||||
SCREEN = CONFIG_SCREEN
|
||||
Draw.Redraw()
|
||||
return
|
||||
if evt == BEVT_EXIT:
|
||||
Draw.Exit()
|
||||
elif evt == BEVT_HELP:
|
||||
show_help()
|
||||
return
|
||||
|
||||
elif SCREEN == CONFIG_SCREEN:
|
||||
datatypes = CFGKEY.sorteddata
|
||||
if evt >= BEVT_BROWSEFILE:
|
||||
INDEX = evt - BEVT_BROWSEFILE
|
||||
Window.FileSelector(fs_file_callback, 'Choose file')
|
||||
elif evt >= BEVT_BROWSEDIR:
|
||||
INDEX = evt - BEVT_BROWSEDIR
|
||||
Window.FileSelector(fs_dir_callback, 'Choose any file')
|
||||
elif evt >= BEVT_STR:
|
||||
var = BUT_TYPES[str][evt - BEVT_STR].val
|
||||
datatypes[str][evt - BEVT_STR][1] = var
|
||||
elif evt >= BEVT_FLOAT:
|
||||
var = BUT_TYPES[float][evt - BEVT_FLOAT].val
|
||||
datatypes[float][evt - BEVT_FLOAT][1] = var
|
||||
elif evt >= BEVT_INT:
|
||||
var = BUT_TYPES[int][evt - BEVT_INT].val
|
||||
datatypes[int][evt - BEVT_INT][1] = var
|
||||
elif evt >= BEVT_BOOL:
|
||||
var = datatypes[bool][evt - BEVT_BOOL][1]
|
||||
if var == True: var = False
|
||||
else: var = True
|
||||
datatypes[bool][evt - BEVT_BOOL][1] = var
|
||||
|
||||
elif evt == BEVT_BACK:
|
||||
if SCREEN == CONFIG_SCREEN:
|
||||
SCREEN = START_SCREEN
|
||||
SCROLL_DOWN = 0
|
||||
Draw.Redraw()
|
||||
elif evt == BEVT_EXIT:
|
||||
if CFGKEY.needs_update():
|
||||
if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
|
||||
CFGKEY.update()
|
||||
Draw.Exit()
|
||||
return
|
||||
elif evt == BEVT_APPLY:
|
||||
if CFGKEY.needs_update():
|
||||
CFGKEY.update()
|
||||
elif evt == BEVT_CANCEL:
|
||||
if CFGKEY.needs_update():
|
||||
CFGKEY.revert()
|
||||
elif evt == BEVT_DEL:
|
||||
if CFGKEY.delete():
|
||||
reset()
|
||||
init_data()
|
||||
SCREEN = START_SCREEN
|
||||
SCROLL_DOWN = 0
|
||||
elif evt == BEVT_DISK:
|
||||
if DISK_UPDATE: DISK_UPDATE = False
|
||||
else: DISK_UPDATE = True
|
||||
elif evt == BEVT_HELP:
|
||||
show_help(CFGKEY.scriptname)
|
||||
return
|
||||
else:
|
||||
return
|
||||
Draw.Redraw()
|
||||
|
||||
# End of definitions
|
||||
|
||||
|
||||
KEYS = get_keys()
|
||||
|
||||
if not KEYS:
|
||||
Draw.PupMenu("NO DATA: please read this help screen")
|
||||
Blender.ShowHelp('config.py')
|
||||
else:
|
||||
fill_scripts_dict()
|
||||
init_data()
|
||||
Draw.Register(gui, event, button_event)
|
||||
@@ -1,861 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Interactive Python Console'
|
||||
Blender: 245
|
||||
Group: 'System'
|
||||
Tooltip: 'Interactive Python Console'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton aka ideasman42"
|
||||
__url__ = ["www.blender.org", "blenderartists.org", "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 are recommended to check the link button above
|
||||
that points to its official homepage, with news, downloads and documentation.
|
||||
|
||||
Usage:<br>
|
||||
Type your code and hit "Enter" to get it executed.<br>
|
||||
- Right mouse click: Console Menu (Save output, etc);<br>
|
||||
- Mousewheel: Scroll text
|
||||
- Arrow keys: command history and cursor;<br>
|
||||
- Shift + Backspace: Backspace whole word;<br>
|
||||
- Shift + Arrow keys: jump words;<br>
|
||||
- Ctrl + (+/- or mousewheel): Zoom text size;<br>
|
||||
- Ctrl + Enter: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;<br>
|
||||
- Shift + Enter: multiline functions -- delays executing code until only Enter is pressed.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
import bpy
|
||||
from Blender import *
|
||||
import sys as python_sys
|
||||
import StringIO
|
||||
|
||||
# Constants
|
||||
__DELIMETERS__ = '. ,=+-*/%<>&~][{}():\t'
|
||||
__VARIABLE_DELIMETERS__ = ' ,=+-*/%<>&~{}():\t'
|
||||
|
||||
__LINE_HISTORY__ = 500
|
||||
|
||||
global __FONT_SIZE__
|
||||
|
||||
__FONT_SIZES__ = ( ('tiny', 10), ('small', 12), ('normalfix', 14), ('large', 16) )
|
||||
__FONT_SIZE__ = 2 # index for the list above, normal default.
|
||||
|
||||
global __CONSOLE_LINE_OFFSET__
|
||||
__CONSOLE_LINE_OFFSET__ = 0
|
||||
|
||||
cmdBuffer = [] # dosnt need to be global
|
||||
|
||||
'''
|
||||
# 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
|
||||
'''
|
||||
|
||||
|
||||
# menuText, # per group
|
||||
def PupMenuLess(menu, groupSize=35):
|
||||
more = [' more...']
|
||||
less = [' less...']
|
||||
|
||||
menuList= menu.split('|')
|
||||
|
||||
# No Less Needed, just call.
|
||||
if len(menuList) < groupSize:
|
||||
return Draw.PupMenu(menu)
|
||||
|
||||
title = menuList[0].split('%t')[0]
|
||||
|
||||
# Split the list into groups
|
||||
menuGroups = [[]]
|
||||
for li in menuList[1:]:
|
||||
if len(menuGroups[-1]) < groupSize:
|
||||
menuGroups[-1].append(li)
|
||||
else:
|
||||
menuGroups.append([li])
|
||||
|
||||
# Stores teh current menu group we are looking at
|
||||
groupIdx = 0
|
||||
while 1:
|
||||
# Give us a title with the menu number
|
||||
numTitle = [ ' '.join([title, str(groupIdx + 1), 'of', str(len(menuGroups)), '%t'])]
|
||||
if groupIdx == 0:
|
||||
menuString = '|'.join(numTitle + menuGroups[groupIdx] + more)
|
||||
elif groupIdx == len(menuGroups)-1:
|
||||
menuString = '|'.join(numTitle + less + menuGroups[groupIdx])
|
||||
else: # In the middle somewhere so Show a more and less
|
||||
menuString = '|'.join(numTitle + less + menuGroups[groupIdx] + more)
|
||||
result = Draw.PupMenu(menuString)
|
||||
# User Exit
|
||||
if result == -1:
|
||||
return -1
|
||||
|
||||
if groupIdx == 0: # First menu
|
||||
if result-1 < groupSize:
|
||||
return result
|
||||
else: # must be more
|
||||
groupIdx +=1
|
||||
elif groupIdx == len(menuGroups): # Last Menu
|
||||
if result == 1: # Must be less
|
||||
groupIdx -= 1
|
||||
else: # Must be a choice
|
||||
return result + (groupIdx*groupSize)
|
||||
|
||||
else:
|
||||
if result == 1: # Must be less
|
||||
groupIdx -= 1
|
||||
elif result-2 == groupSize:
|
||||
groupIdx +=1
|
||||
else:
|
||||
return result - 1 + (groupIdx*groupSize)
|
||||
|
||||
|
||||
|
||||
# Use newstyle classes, Im not bothering with inheretence
|
||||
# but slots are faster.
|
||||
class cmdLine(object):
|
||||
__slots__ = [\
|
||||
'cmd', # is the command string, or any other message
|
||||
'type',# 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(type):
|
||||
newText = Text.New('command_output.py', 1)
|
||||
if type == 3: newText.write('\n'.join( [ myCmd.cmd for myCmd in cmdBuffer ] ))
|
||||
else: newText.write('\n'.join( [ myCmd.cmd for myCmd in cmdBuffer if myCmd.type is type] ))
|
||||
Draw.PupMenu('%s written' % newText.name)
|
||||
|
||||
def insertCmdData():
|
||||
texts = list(bpy.data.texts)
|
||||
textNames = [tex.name for tex in texts]
|
||||
if textNames:
|
||||
choice = Draw.PupMenu('|'.join(textNames))
|
||||
if choice != -1:
|
||||
text = texts[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
|
||||
unused_types = str, dict, list, float, int, str, type, tuple, type(dir), type(None)
|
||||
def rdir(dirString, depth=0):
|
||||
#print ' ' * depth, dirString
|
||||
# MAX DEPTH SET HERE
|
||||
if depth > 5:
|
||||
# print 'maxdepoth reached.'
|
||||
return
|
||||
|
||||
global COLLECTED_VAR_NAMES
|
||||
dirStringSplit = dirString.split('.')
|
||||
|
||||
exec('value=' + dirString)
|
||||
|
||||
if type(value) in unused_types:
|
||||
# print 'bad type'
|
||||
return
|
||||
dirList = dir(value)
|
||||
|
||||
for dirItem in dirList:
|
||||
if dirItem.startswith('_'):
|
||||
continue
|
||||
|
||||
dirData = None
|
||||
try:
|
||||
# Rare cases this can mess up, material.shader was a problem.
|
||||
exec('dirData = %s.%s' % (dirString, dirItem))
|
||||
#print dirData
|
||||
except:
|
||||
# Dont bother with this data.
|
||||
continue
|
||||
#print 'HEY', dirData, dirItem
|
||||
#if type(dirItem) != str:
|
||||
# print dirItem, type(dirItem)
|
||||
|
||||
if dirItem not in COLLECTED_VAR_NAMES: # .keys()
|
||||
COLLECTED_VAR_NAMES[dirItem] = []
|
||||
|
||||
# Add the string
|
||||
# splitD = dirString.split('"')[-2]
|
||||
|
||||
# Example of dirString
|
||||
# __CONSOLE_VAR_DICT__["Main"].scenes.active.render
|
||||
|
||||
# Works but can be faster
|
||||
# splitD = dirString.replace('__CONSOLE_VAR_DICT__["', '').replace('"]', '')
|
||||
|
||||
splitD = dirString[22:].replace('"]', '')
|
||||
|
||||
if splitD not in COLLECTED_VAR_NAMES[dirItem]:
|
||||
# print dirItem, dirString, splitD,
|
||||
COLLECTED_VAR_NAMES[dirItem].append(splitD)
|
||||
|
||||
|
||||
# Stops recursice stuff, overlooping
|
||||
#print type(dirItem)
|
||||
#if type(dirData) == types.ClassType or \
|
||||
# type(dirData) == types.ModuleType:
|
||||
type_dirData = type(dirData)
|
||||
if type_dirData not in unused_types:
|
||||
# print type(dirData), dirItem
|
||||
# Dont loop up dirs for strings ints etc.
|
||||
if dirItem not in dirStringSplit:
|
||||
rdir( '%s.%s' % (dirString, dirItem), depth+1)
|
||||
'''
|
||||
elif depth == 0: # Add local variables
|
||||
# print type(dirData), dirItem
|
||||
# Dont loop up dirs for strings ints etc.
|
||||
if dirItem not in dirStringSplit:
|
||||
rdir( '%s.%s' % (dirString, dirItem), depth+1)
|
||||
'''
|
||||
|
||||
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.
|
||||
__TMP_VAR_NAME__ = __TMP_VAR__ = '' # so as not to raise an error when del'ing
|
||||
|
||||
for __TMP_VAR_NAME__, __TMP_VAR__ in __CONSOLE_VAR_DICT__.items():
|
||||
exec('%s%s' % (__TMP_VAR_NAME__,'=__TMP_VAR__'))
|
||||
del __TMP_VAR_NAME__
|
||||
del __TMP_VAR__
|
||||
|
||||
# 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'))
|
||||
|
||||
# Flush global dict, allow the user to remove items.
|
||||
__CONSOLE_VAR_DICT__ = {}
|
||||
|
||||
__TMP_VAR_NAME__ = '' # so as not to raise an error when del'ing
|
||||
# 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 = '%s: %s' % (python_sys.exc_type, 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 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
|
||||
|
||||
def getIndent(string):
|
||||
# Gather white space to add in the previous line
|
||||
# Ignore the last char since its padding.
|
||||
whiteSpace = ''
|
||||
#for i in range(len(cmdBuffer[-1].cmd)):
|
||||
for i in xrange(len(string)-1):
|
||||
if cmdBuffer[-1].cmd[i] == ' ' or cmdBuffer[-1].cmd[i] == '\t':
|
||||
whiteSpace += string[i]
|
||||
else:
|
||||
break
|
||||
return whiteSpace
|
||||
|
||||
# Autocomplete
|
||||
if Window.GetKeyQualifiers() & Window.Qual.CTRL:
|
||||
actionAutoCompleate()
|
||||
return
|
||||
|
||||
# Are we in the middle of a multiline part or not?
|
||||
# try be smart about it
|
||||
if cmdBuffer[-1].cmd.split('#')[0].rstrip().endswith(':'):
|
||||
# : indicates an indent is needed
|
||||
cmdBuffer.append(cmdLine('\t%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0))
|
||||
print ': indicates an indent is needed'
|
||||
|
||||
elif cmdBuffer[-1].cmd[0] in [' ', '\t'] and len(cmdBuffer[-1].cmd) > 1 and cmdBuffer[-1].cmd.split():
|
||||
# white space at the start means he havnt finished the multiline.
|
||||
cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0))
|
||||
print 'white space at the start means he havnt finished the multiline.'
|
||||
|
||||
elif Window.GetKeyQualifiers() & Window.Qual.SHIFT:
|
||||
# Crtl forces multiline
|
||||
cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0))
|
||||
print 'Crtl forces multiline'
|
||||
|
||||
else: # Execute multiline code block
|
||||
|
||||
# Multiline code will still run with 1 line,
|
||||
multiLineCode = ['if 1:'] # End of the multiline first.
|
||||
|
||||
# Seek the start of the file multiline
|
||||
i = 1
|
||||
while cmdBuffer[-i].exe == 0:
|
||||
i+=1
|
||||
|
||||
while i > 1:
|
||||
i-=1
|
||||
|
||||
if cmdBuffer[-i].cmd == ' ':# Tag as an output type so its not used in the key history
|
||||
cmdBuffer[-i].type = 1
|
||||
else: # Tab added at the start for added if 1: statement
|
||||
multiLineCode.append('\t%s' % cmdBuffer[-i].cmd )
|
||||
|
||||
# Mark as executed
|
||||
cmdBuffer[-i].exe = 1
|
||||
|
||||
multiLineCode.append('\tpass') # reverse will make this the start.
|
||||
|
||||
# Dubug, print the code that is executed.
|
||||
#for m in multiLineCode: print m
|
||||
|
||||
runUserCode('\n'.join(multiLineCode))
|
||||
|
||||
# Clear the output based on __LINE_HISTORY__
|
||||
if len(cmdBuffer) > __LINE_HISTORY__:
|
||||
cmdBuffer[:__LINE_HISTORY__] = []
|
||||
|
||||
histIndex = cursor = -1 # Reset cursor and history
|
||||
|
||||
def actionUpKey():
|
||||
global histIndex
|
||||
if abs(histIndex)+1 >= len(cmdBuffer):
|
||||
histIndex = -1
|
||||
|
||||
# When wrapping allow 1 plank lines
|
||||
if cmdBuffer[-1].cmd != ' ':
|
||||
cmdBuffer[-1].cmd = ' '
|
||||
return
|
||||
|
||||
histIndex_orig = histIndex
|
||||
histIndex -= 1
|
||||
|
||||
while (cmdBuffer[histIndex].type != 0 and abs(histIndex) < len(cmdBuffer)) or \
|
||||
( cmdBuffer[histIndex].cmd == cmdBuffer[histIndex_orig].cmd):
|
||||
histIndex -= 1
|
||||
|
||||
if cmdBuffer[histIndex].type == 0: # we found one
|
||||
cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd
|
||||
|
||||
def actionDownKey():
|
||||
global histIndex
|
||||
if histIndex >= -2:
|
||||
histIndex = -len(cmdBuffer)
|
||||
|
||||
# When wrapping allow 1 plank lines
|
||||
if cmdBuffer[-1].cmd != ' ':
|
||||
cmdBuffer[-1].cmd = ' '
|
||||
return
|
||||
|
||||
histIndex_orig = histIndex
|
||||
histIndex += 1
|
||||
while (cmdBuffer[histIndex].type != 0 and histIndex != -2) or \
|
||||
( cmdBuffer[histIndex].cmd == cmdBuffer[histIndex_orig].cmd):
|
||||
|
||||
histIndex += 1
|
||||
|
||||
if cmdBuffer[histIndex].type == 0: # we found one
|
||||
cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd
|
||||
|
||||
def actionRightMouse():
|
||||
global __FONT_SIZE__
|
||||
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|Font Size|%l|Clear Output|Quit')
|
||||
|
||||
if choice == 1:
|
||||
writeCmdData(0) # type 0 user
|
||||
elif choice == 2:
|
||||
writeCmdData(1) # type 1 user output
|
||||
elif choice == 3:
|
||||
writeCmdData(2) # type 2 errors
|
||||
elif choice == 4:
|
||||
writeCmdData(3) # All
|
||||
elif choice == 6:
|
||||
insertCmdData() # Insert text from Blender and run it.
|
||||
elif choice == 8:
|
||||
# Fontsize.
|
||||
font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny')
|
||||
if font_choice != -1:
|
||||
if font_choice == 1:
|
||||
__FONT_SIZE__ = 3
|
||||
elif font_choice == 2:
|
||||
__FONT_SIZE__ = 2
|
||||
elif font_choice == 3:
|
||||
__FONT_SIZE__ = 1
|
||||
elif font_choice == 4:
|
||||
__FONT_SIZE__ = 0
|
||||
Draw.Redraw()
|
||||
elif choice == 10: # Clear all output
|
||||
cmdBuffer[:] = [cmd for cmd in cmdBuffer if cmd.type == 0] # keep user input
|
||||
Draw.Redraw()
|
||||
elif choice == 11: # Exit
|
||||
Draw.Exit()
|
||||
|
||||
|
||||
# Auto compleating, quite complex- use recutsice dir for the moment.
|
||||
def actionAutoCompleate(): # Ctrl + Tab
|
||||
if not cmdBuffer[-1].cmd[:cursor].split():
|
||||
return
|
||||
|
||||
|
||||
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 __VARIABLE_DELIMETERS__:
|
||||
editVar = editVar[:-1].split(splitChar)[-1] + editVar[-1]
|
||||
|
||||
|
||||
# Now we should have the var by its self
|
||||
if editVar:
|
||||
possibilities = []
|
||||
|
||||
for __TMP_VAR_NAME__ in RECURSIVE_DIR: #.keys():
|
||||
#print '\t', __TMP_VAR_NAME__
|
||||
if __TMP_VAR_NAME__ == editVar:
|
||||
# print 'ADITVAR IS A VAR'
|
||||
pass
|
||||
'''
|
||||
elif __TMP_VAR_NAME__.startswith( editVar ):
|
||||
print __TMP_VAR_NAME__, 'aaa'
|
||||
possibilities.append( __TMP_VAR_NAME__ )
|
||||
'''
|
||||
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))
|
||||
|
||||
menuList = [] # A lits of tuples- ABSOLUTE, RELATIVE
|
||||
|
||||
for __TMP_VAR_NAME__ in possibilities:
|
||||
for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]:
|
||||
# Account for non absolute (variables for eg.)
|
||||
if usage: # not ''
|
||||
absName = '%s.%s' % (usage, __TMP_VAR_NAME__)
|
||||
|
||||
if __TMP_VAR_NAME__.startswith(editVar):
|
||||
menuList.append( # Used for names and can be entered when pressing shift.
|
||||
(absName, # Absolute name
|
||||
__TMP_VAR_NAME__) # Relative name, non shift
|
||||
)
|
||||
|
||||
#else:
|
||||
# if absName.find(editVar) != -1:
|
||||
# menuList.append((__TMP_VAR_NAME__, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift.
|
||||
|
||||
# No items to display? no menu
|
||||
if not menuList:
|
||||
return
|
||||
|
||||
menuList.sort()
|
||||
|
||||
choice = PupMenuLess( # Menu for the user to choose the autocompleate
|
||||
'Choices (Shift for local name, Ctrl for Docs)%t|' + # Title Text
|
||||
'|'.join(['%s, %s' % m for m in menuList])) # Use Absolute names m[0]
|
||||
|
||||
if choice != -1:
|
||||
if Window.GetKeyQualifiers() & Window.Qual.CTRL: # Help
|
||||
cmdBuffer[-1].cmd = ('help(%s%s) ' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0]))
|
||||
elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Put in the long name
|
||||
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][1], cmdBuffer[-1].cmd[cursor:]))
|
||||
else: # Only paste in the Short name
|
||||
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0], cmdBuffer[-1].cmd[cursor:]))
|
||||
|
||||
|
||||
else:
|
||||
# print 'NO EDITVAR'
|
||||
return
|
||||
|
||||
# ------------------end------------------ #
|
||||
|
||||
# Quit from menu only
|
||||
#if (evt == Draw.ESCKEY and not val):
|
||||
# Draw.Exit()
|
||||
if evt == Draw.MOUSEX or evt == Draw.MOUSEY: # AVOID TOO MANY REDRAWS.
|
||||
return
|
||||
|
||||
|
||||
global cursor
|
||||
global histIndex
|
||||
global __FONT_SIZE__
|
||||
global __CONSOLE_LINE_OFFSET__
|
||||
|
||||
ascii = Blender.event
|
||||
|
||||
resetScroll = True
|
||||
|
||||
#------------------------------------------------------------------------------#
|
||||
# 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):
|
||||
if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
|
||||
wordJump = False
|
||||
newCursor = cursor+1
|
||||
while newCursor<0:
|
||||
|
||||
if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__:
|
||||
newCursor+=1
|
||||
else:
|
||||
wordJump = True
|
||||
break
|
||||
if wordJump: # Did we find a new cursor pos?
|
||||
cursor = newCursor
|
||||
else:
|
||||
cursor = -1 # end of line
|
||||
else:
|
||||
cursor +=1
|
||||
if cursor > -1:
|
||||
cursor = -1
|
||||
|
||||
elif (evt == Draw.LEFTARROWKEY and val):
|
||||
if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
|
||||
wordJump = False
|
||||
newCursor = cursor-1
|
||||
while abs(newCursor) < len(cmdBuffer[-1].cmd):
|
||||
|
||||
if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__ or\
|
||||
newCursor == cursor:
|
||||
newCursor-=1
|
||||
else:
|
||||
wordJump = True
|
||||
break
|
||||
if wordJump: # Did we find a new cursor pos?
|
||||
cursor = newCursor
|
||||
else:
|
||||
cursor = -len(cmdBuffer[-1].cmd) # Start of line
|
||||
|
||||
else:
|
||||
if len(cmdBuffer[-1].cmd) > abs(cursor):
|
||||
cursor -=1
|
||||
|
||||
elif (evt == Draw.HOMEKEY and val):
|
||||
cursor = -len(cmdBuffer[-1].cmd)
|
||||
|
||||
elif (evt == Draw.ENDKEY and val):
|
||||
cursor = -1
|
||||
|
||||
elif (evt == Draw.TABKEY and val):
|
||||
insCh('\t')
|
||||
|
||||
elif (evt == Draw.BACKSPACEKEY and val):
|
||||
if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
|
||||
i = -1
|
||||
for d in __DELIMETERS__:
|
||||
i = max(i, cmdBuffer[-1].cmd[:cursor-1].rfind(d))
|
||||
if i == -1:
|
||||
i=0
|
||||
cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:i] , cmdBuffer[-1].cmd[cursor:]))
|
||||
|
||||
else:
|
||||
# Normal backspace.
|
||||
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 (evt == Draw.PADPLUSKEY or evt == Draw.EQUALKEY or evt == Draw.WHEELUPMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL:
|
||||
__FONT_SIZE__ += 1
|
||||
__FONT_SIZE__ = min(len(__FONT_SIZES__)-1, __FONT_SIZE__)
|
||||
elif (evt == Draw.PADMINUS or evt == Draw.MINUSKEY or evt == Draw.WHEELDOWNMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL:
|
||||
__FONT_SIZE__ -=1
|
||||
__FONT_SIZE__ = max(0, __FONT_SIZE__)
|
||||
|
||||
|
||||
elif evt == Draw.WHEELUPMOUSE and val:
|
||||
__CONSOLE_LINE_OFFSET__ += 1
|
||||
__CONSOLE_LINE_OFFSET__ = min(len(cmdBuffer)-2, __CONSOLE_LINE_OFFSET__)
|
||||
resetScroll = False
|
||||
|
||||
elif evt == Draw.WHEELDOWNMOUSE and val:
|
||||
__CONSOLE_LINE_OFFSET__ -= 1
|
||||
__CONSOLE_LINE_OFFSET__ = max(0, __CONSOLE_LINE_OFFSET__)
|
||||
resetScroll = False
|
||||
|
||||
|
||||
elif ascii:
|
||||
insCh(chr(ascii))
|
||||
else:
|
||||
return # dont redraw.
|
||||
|
||||
# If the user types in anything then scroll to bottom.
|
||||
if resetScroll:
|
||||
__CONSOLE_LINE_OFFSET__ = 0
|
||||
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
|
||||
|
||||
|
||||
# Fixed margin. use a margin since 0 margin can be hard to seewhen close to a crt's edge.
|
||||
margin = 4
|
||||
|
||||
# Convenience
|
||||
FNT_NAME, FNT_HEIGHT = __FONT_SIZES__[__FONT_SIZE__]
|
||||
|
||||
# Draw cursor location colour
|
||||
if __CONSOLE_LINE_OFFSET__ == 0:
|
||||
cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], FNT_NAME)
|
||||
BGL.glColor3f(0.8, 0.2, 0.2)
|
||||
if cmd2curWidth == 0:
|
||||
BGL.glRecti(margin,2,margin+2, FNT_HEIGHT+2)
|
||||
else:
|
||||
BGL.glRecti(margin + cmd2curWidth-2,2, margin+cmd2curWidth, FNT_HEIGHT+2)
|
||||
|
||||
BGL.glColor3f(1,1,1)
|
||||
# Draw the set of cammands to the buffer
|
||||
consoleLineIdx = __CONSOLE_LINE_OFFSET__ + 1
|
||||
wrapLineIndex = 0
|
||||
while consoleLineIdx < len(cmdBuffer) and __CONSOLE_RECT__[3] > (consoleLineIdx - __CONSOLE_LINE_OFFSET__) * FNT_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: # user input
|
||||
BGL.glRasterPos2i(margin, (FNT_HEIGHT * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8)
|
||||
Draw.Text(cmdBuffer[-consoleLineIdx].cmd, FNT_NAME)
|
||||
else: # WRAP
|
||||
lwid = Draw.GetStringWidth(cmdBuffer[-consoleLineIdx].cmd, FNT_NAME)
|
||||
if margin + lwid > __CONSOLE_RECT__[2]:
|
||||
wrapLineList = []
|
||||
wtext = cmdBuffer[-consoleLineIdx].cmd
|
||||
wlimit = len(wtext)
|
||||
chunksz = int(( __CONSOLE_RECT__[2] - margin ) / (lwid / len(wtext)))
|
||||
lstart = 0
|
||||
fsize = FNT_NAME
|
||||
while lstart < wlimit:
|
||||
lend = min(lstart+chunksz,wlimit)
|
||||
ttext = wtext[lstart:lend]
|
||||
while lend < wlimit and Draw.GetStringWidth(ttext, fsize) + margin < __CONSOLE_RECT__[2]:
|
||||
lend += 1
|
||||
ttext = wtext[lstart:lend]
|
||||
while lend > lstart+1 and Draw.GetStringWidth(ttext, fsize) + margin > __CONSOLE_RECT__[2]:
|
||||
lend -= 1
|
||||
ttext = wtext[lstart:lend]
|
||||
wrapLineList.append(ttext)
|
||||
lstart = lend
|
||||
# Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change)
|
||||
wrapLineList.reverse()
|
||||
for wline in wrapLineList:
|
||||
BGL.glRasterPos2i(margin, (FNT_HEIGHT*((consoleLineIdx-__CONSOLE_LINE_OFFSET__) + wrapLineIndex)) - 8)
|
||||
Draw.Text(wline, FNT_NAME)
|
||||
wrapLineIndex += 1
|
||||
wrapLineIndex-=1 # otherwise we get a silly extra line.
|
||||
|
||||
else: # no wrapping.
|
||||
|
||||
BGL.glRasterPos2i(margin, (FNT_HEIGHT * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8)
|
||||
Draw.Text(cmdBuffer[-consoleLineIdx].cmd, FNT_NAME)
|
||||
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, add __bpydoc__ to the console startup.
|
||||
for l in __bpydoc__.split('<br>'):
|
||||
cmdBuffer.append( cmdLine(l, 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.
|
||||
scriptDir = Get('scriptsdir')
|
||||
console_autoexec = None
|
||||
if scriptDir:
|
||||
if not scriptDir.endswith(Blender.sys.sep):
|
||||
scriptDir += Blender.sys.sep
|
||||
|
||||
console_autoexec = '%s%s' % (scriptDir, 'console_autoexec.py')
|
||||
|
||||
if not sys.exists(console_autoexec):
|
||||
# touch the file
|
||||
try:
|
||||
open(console_autoexec, 'w').close()
|
||||
cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts dir', 1, None))
|
||||
except:
|
||||
cmdBuffer.append(cmdLine('...console_autoexec.py could not write, this is ok', 1, None))
|
||||
scriptDir = None # make sure we only use this for console_autoexec.py
|
||||
|
||||
if not sys.exists(console_autoexec):
|
||||
console_autoexec = None
|
||||
|
||||
else:
|
||||
cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts 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 include_console(includeFile):
|
||||
global __CONSOLE_VAR_DICT__ # write autoexec vars to this.
|
||||
|
||||
# Execute an external py file as if local
|
||||
exec(include(includeFile))
|
||||
|
||||
def standard_imports():
|
||||
# Write local to global __CONSOLE_VAR_DICT__ for reuse,
|
||||
|
||||
exec('%s%s' % ('__CONSOLE_VAR_DICT__["bpy"]=', 'bpy'))
|
||||
exec('%s%s' % ('__CONSOLE_VAR_DICT__["Blender"]=', 'Blender'))
|
||||
|
||||
for ls in (dir(), dir(Blender)):
|
||||
for __TMP_VAR_NAME__ in ls:
|
||||
# Execute the local > global coversion.
|
||||
exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__))
|
||||
|
||||
# Add dummy imports to input so output scripts to a text file work as expected
|
||||
cmdBuffer.append(cmdLine('import bpy', 0, 1))
|
||||
cmdBuffer.append(cmdLine('import Blender', 0, 1)) # pretend we have been executed, as we kindof have.
|
||||
cmdBuffer.append(cmdLine('from Blender import *', 0, 1))
|
||||
|
||||
if scriptDir and console_autoexec:
|
||||
include_console(console_autoexec) # pass the blender module
|
||||
|
||||
standard_imports() # import Blender and bpy
|
||||
|
||||
#-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)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Envelope Symmetry'
|
||||
Blender: 234
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Make envelope symmetrical'
|
||||
"""
|
||||
|
||||
__author__ = "Jonas Petersen"
|
||||
__url__ = ("blender", "blenderartists.org", "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:
|
||||
|
||||
<bone name>:<float value>
|
||||
|
||||
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):
|
||||
for obj in Blender.Scene.GetCurrent().objects:
|
||||
if obj.type == "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_only=1) == mesh_name:
|
||||
return obj
|
||||
return False
|
||||
|
||||
SUFFIX_LEN = len(REF_SUFFIX);
|
||||
|
||||
Blender.Window.EditMode(0)
|
||||
|
||||
count = 0
|
||||
for obj in Blender.Scene.GetCurrent().objects:
|
||||
if obj.type != 'Mesh':
|
||||
continue
|
||||
|
||||
count += 1
|
||||
name = obj.name
|
||||
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 xrange(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 = obj.data
|
||||
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)
|
||||
@@ -1,304 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'OpenInventor (.iv)...'
|
||||
Blender: 236
|
||||
Group: 'Export'
|
||||
Tip: 'Export to OpenInventor file format. (.iv)'
|
||||
"""
|
||||
__author__ = ("Radek Barton")
|
||||
__url__ = ["http://blackhex.no-ip.org/"]
|
||||
__email__ = ["scripts"]
|
||||
__version__ = "0.1"
|
||||
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script exports to the Open Inventor format.
|
||||
|
||||
Usage:
|
||||
|
||||
Run this script from "File->Export" menu.
|
||||
|
||||
Note:
|
||||
"""
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) Radek Barton
|
||||
#
|
||||
# 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 *****
|
||||
#
|
||||
|
||||
import Blender
|
||||
math_pi= 3.1415926535897931
|
||||
|
||||
def WriteHeader(file):
|
||||
file.write("#Inventor V2.1 ascii\n\n")
|
||||
file.write("Separator\n")
|
||||
file.write("{\n")
|
||||
file.write(" ShapeHints\n")
|
||||
file.write(" {\n")
|
||||
file.write(" vertexOrdering COUNTERCLOCKWISE\n")
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteFooter(file):
|
||||
file.write("}\n")
|
||||
|
||||
def WriteMesh(file, ob):
|
||||
file.write(" Separator\n")
|
||||
file.write(" {\n")
|
||||
file.write(" # %s\n" % ob.name)
|
||||
WriteMatrix(file, ob)
|
||||
mesh = ob.getData()
|
||||
WriteMaterials(file, mesh)
|
||||
WriteTexture(file, mesh)
|
||||
WriteNormals(file, mesh)
|
||||
WriteVertices(file, mesh)
|
||||
WriteFaces(file, mesh)
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteMatrix(file, ob):
|
||||
matrix = ob.getMatrix()
|
||||
file.write(" MatrixTransform\n")
|
||||
file.write(" {\n")
|
||||
file.write(" matrix\n")
|
||||
for line in matrix:
|
||||
file.write(" %.6f %.6f %.6f %.6f\n" % (line[0], line[1], line[2], line[3]))
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteColors(file, mesh):
|
||||
file.write(" vertexProperty VertexProperty\n")
|
||||
file.write(" {\n")
|
||||
file.write(" orderedRGBA\n")
|
||||
file.write(" [\n")
|
||||
for face in mesh.faces:
|
||||
for I in xrange(len(face)):
|
||||
file.write(" 0x%02x%02x%02x%02x,\n" % (face.col[I].r,
|
||||
face.col[I].g, face.col[I].b, face.col[I].a))
|
||||
file.write(" ]\n")
|
||||
file.write(" materialBinding PER_VERTEX\n")
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteMaterials(file, mesh):
|
||||
if mesh.materials:
|
||||
file.write(" Material\n")
|
||||
file.write(" {\n")
|
||||
file.write(" ambientColor\n")
|
||||
file.write(" [\n")
|
||||
for mat in mesh.materials:
|
||||
file.write(" %.6f %.6f %.6f,\n" % (mat.mirCol[0], mat.mirCol[1],
|
||||
mat.mirCol[2]))
|
||||
file.write(" ]\n")
|
||||
file.write(" diffuseColor\n")
|
||||
file.write(" [\n")
|
||||
for mat in mesh.materials:
|
||||
file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0], mat.rgbCol[1],
|
||||
mat.rgbCol[2]))
|
||||
file.write(" ]\n")
|
||||
file.write(" specularColor\n")
|
||||
file.write(" [\n")
|
||||
for mat in mesh.materials:
|
||||
file.write(" %.6f %.6f %.6f,\n" % (mat.specCol[0] * mat.spec / 2.0,
|
||||
mat.specCol[1] * mat.spec / 2.0, mat.specCol[2] * mat.spec / 2.0))
|
||||
file.write(" ]\n")
|
||||
file.write(" emissiveColor\n")
|
||||
file.write(" [\n")
|
||||
for mat in mesh.materials:
|
||||
file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0] * mat.emit,
|
||||
mat.rgbCol[1] * mat.emit, mat.rgbCol[0] * mat.emit))
|
||||
file.write(" ]\n")
|
||||
file.write(" shininess\n")
|
||||
file.write(" [\n")
|
||||
for mat in mesh.materials:
|
||||
file.write(" %.6f,\n" % (mat.hard / 255.0))
|
||||
file.write(" ]\n")
|
||||
file.write(" transparency\n")
|
||||
file.write(" [\n")
|
||||
for mat in mesh.materials:
|
||||
file.write(" %.6f,\n" % (1.0 - mat.alpha))
|
||||
file.write(" ]\n")
|
||||
file.write(" }\n")
|
||||
file.write(" MaterialBinding\n")
|
||||
file.write(" {\n")
|
||||
file.write(" value PER_FACE_INDEXED\n")
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteTexture(file, mesh):
|
||||
texture = mesh.faces[0].image # BAD Ju Ju
|
||||
if texture:
|
||||
file.write(" Texture2\n")
|
||||
file.write(" {\n")
|
||||
file.write(' filename "%s"\n' % texture.getName())
|
||||
file.write(" }\n")
|
||||
file.write(" TextureCoordinate2\n")
|
||||
file.write(" {\n")
|
||||
file.write(" point\n")
|
||||
file.write(" [\n")
|
||||
if mesh.hasVertexUV():
|
||||
for vert in mesh.verts:
|
||||
file.write(" %s %s,\n" % (vert.uvco[0], vert.uvco[1]))
|
||||
file.write(" ]\n")
|
||||
file.write(" }\n")
|
||||
file.write(" TextureCoordinateBinding\n")
|
||||
file.write(" {\n")
|
||||
file.write(" value PER_VERTEX_INDEXED\n")
|
||||
file.write(" }\n")
|
||||
elif mesh.hasFaceUV():
|
||||
for face in mesh.faces:
|
||||
for uv in face.uv:
|
||||
file.write(" %.6f %.6f,\n" % (uv[0], uv[1]))
|
||||
file.write(" ]\n")
|
||||
file.write(" }\n")
|
||||
file.write(" TextureCoordinateBinding\n")
|
||||
file.write(" {\n")
|
||||
file.write(" value PER_VERTEX\n")
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteVertices(file, mesh):
|
||||
file.write(" Coordinate3\n")
|
||||
file.write(" {\n")
|
||||
file.write(" point\n")
|
||||
file.write(" [\n")
|
||||
for vert in mesh.verts:
|
||||
file.write(" %.6f %.6f %.6f,\n" % (vert[0], vert[1], vert[2]))
|
||||
file.write(" ]\n")
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteNormals(file, mesh):
|
||||
file.write(" Normal\n")
|
||||
file.write(" {\n")
|
||||
file.write(" vector\n")
|
||||
file.write(" [\n")
|
||||
|
||||
# make copy of vertex normals
|
||||
normals = []
|
||||
for face in mesh.faces:
|
||||
if len(face.v) in [3, 4]:
|
||||
if face.smooth:
|
||||
for v in face.v:
|
||||
normals.append(v.no)
|
||||
else:
|
||||
for v in face.v:
|
||||
normals.append(face.no)
|
||||
|
||||
# write normals
|
||||
for no in normals:
|
||||
file.write(" %.6f %.6f %.6f,\n" % (no[0], no[1], no[2]))
|
||||
file.write(" ]\n")
|
||||
file.write(" }\n")
|
||||
|
||||
# write way how normals are binded
|
||||
file.write(" NormalBinding\n")
|
||||
file.write(" {\n")
|
||||
file.write(" value PER_VERTEX\n")
|
||||
file.write(" }\n")
|
||||
|
||||
def WriteFaces(file, mesh):
|
||||
file.write(" IndexedFaceSet\n")
|
||||
file.write(" {\n")
|
||||
|
||||
# write vertex paint
|
||||
if mesh.hasVertexColours():
|
||||
WriteColors(file, mesh)
|
||||
|
||||
# write material indexes
|
||||
file.write(" materialIndex\n")
|
||||
file.write(" [\n")
|
||||
for face in mesh.faces:
|
||||
file.write(" %i,\n" % face.mat);
|
||||
file.write(" ]\n")
|
||||
|
||||
# write faces with coordinate indexes
|
||||
file.write(" coordIndex\n")
|
||||
file.write(" [\n")
|
||||
for face in mesh.faces:
|
||||
face_v= face.v
|
||||
if len(face_v) == 3:
|
||||
file.write(" %i, %i, %i, -1,\n" % (face_v[0].index,
|
||||
face_v[1].index, face_v[2].index))
|
||||
elif len(face_v) == 4:
|
||||
file.write(" %i, %i, %i, %i, -1,\n" % (face_v[0].index,
|
||||
face_v[1].index, face_v[2].index, face_v[3].index))
|
||||
file.write(" ]\n")
|
||||
file.write(" }\n")
|
||||
|
||||
|
||||
def WriteCamera(file, ob):
|
||||
camera = ob.getData();
|
||||
# perspective camera
|
||||
if camera.type == 0:
|
||||
file.write(" PerspectiveCamera\n")
|
||||
file.write(" {\n")
|
||||
file.write(" nearDistance %s\n" % (camera.clipStart))
|
||||
file.write(" farDistance %s\n" % (camera.clipEnd))
|
||||
file.write(" }\n")
|
||||
# ortho camera
|
||||
else:
|
||||
print camera.type
|
||||
|
||||
def WriteLamp(file, ob):
|
||||
lamp = ob.getData();
|
||||
# spot lamp
|
||||
if lamp.type == 2:
|
||||
file.write(" SpotLight\n")
|
||||
file.write(" {\n")
|
||||
file.write(" intensity %s\n" % (lamp.energy / 10.0))
|
||||
file.write(" color %s %s %s\n" % (lamp.col[0], lamp.col[1], lamp.col[2]))
|
||||
#file.write(" location %s\n" % ())
|
||||
#file.write(" direction %s\n" % ())
|
||||
file.write(" dropOffRate %s\n" % (lamp.spotBlend))
|
||||
file.write(" cutOffAngle %s\n" % (lamp.spotSize * math_pi / 180.0))
|
||||
file.write(" }\n")
|
||||
|
||||
# script main function
|
||||
def ExportToIv(file_name):
|
||||
scene = Blender.Scene.GetCurrent()
|
||||
file = open(file_name, "w")
|
||||
|
||||
# make lists of individual ob types
|
||||
meshes = []
|
||||
lamps = []
|
||||
cameras = []
|
||||
for ob in scene.objects:
|
||||
obtype= ob.type
|
||||
if obtype == "Mesh":
|
||||
meshes.append(ob);
|
||||
#elif obtype == "Lamp":
|
||||
# lamps.append(ob);
|
||||
#elif obtype == "Camera":
|
||||
# cameras.append(ob);
|
||||
#else:
|
||||
# print "Exporting %s objects isn't supported!" % ob.type
|
||||
|
||||
# write header, footer and groups of ob types
|
||||
WriteHeader(file);
|
||||
#for camera in cameras:
|
||||
# WriteCamera(file, camera);
|
||||
#for lamp in lamps:
|
||||
# WriteLamp(file, lamp)
|
||||
for mesh in meshes:
|
||||
WriteMesh(file, mesh)
|
||||
WriteFooter(file)
|
||||
|
||||
file.close()
|
||||
|
||||
def FileSelectorCB(file_name):
|
||||
if not file_name.lower().endswith('.iv'):
|
||||
file_name += '.iv'
|
||||
ExportToIv(file_name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
Blender.Window.FileSelector(FileSelectorCB, "Export IV", Blender.sys.makename(ext='.iv'))
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,157 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus: <- these words are ignored
|
||||
Name: 'Lightwave Motion (.mot)...'
|
||||
Blender: 241
|
||||
Group: 'Export'
|
||||
Tip: 'Export Loc Rot Size chanels to a Lightwave .mot file'
|
||||
"""
|
||||
|
||||
__author__ = "Daniel Salazar (ZanQdo)"
|
||||
__url__ = ("blender", "blenderartists.org",
|
||||
"e-mail: zanqdo@gmail.com")
|
||||
__version__ = "16/04/08"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script exports the selected object's motion channels to Lightwave
|
||||
motion files (.mot).
|
||||
|
||||
Usage:
|
||||
Run the script with one or more objects selected (any kind), frames exported
|
||||
are between Start and End frames in Render buttons.
|
||||
|
||||
"""
|
||||
|
||||
# $Id$
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2003, 2004: A Vanpoucke
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
import Blender as B
|
||||
import math as M
|
||||
#------------------------------------
|
||||
#Declarados:
|
||||
TotalCanales = 9
|
||||
#------------------------------------
|
||||
|
||||
def FuncionPrincipal (Dir):
|
||||
B.Window.WaitCursor(1)
|
||||
ObjSelect = B.Object.GetSelected()
|
||||
|
||||
if not ObjSelect:
|
||||
B.Draw.PupMenu('Select 1 or more objects, aborting.')
|
||||
return
|
||||
|
||||
if not Dir.lower().endswith('.mot'):
|
||||
Dir += '.mot'
|
||||
|
||||
|
||||
SC = B.Scene.GetCurrent()
|
||||
SCR = SC.getRenderingContext()
|
||||
|
||||
for ob in ObjSelect:
|
||||
origName= NombreObjeto= ob.name
|
||||
print '----\nExporting Object "%s" motion file...' % origName
|
||||
|
||||
FrameA = B.Get('curframe')
|
||||
FrameP = B.Get('staframe')
|
||||
FrameF = B.Get('endframe')
|
||||
|
||||
FrameRate = float(SCR.framesPerSec())
|
||||
|
||||
#---------------------------------------------
|
||||
|
||||
# Replace danger characters by '_'
|
||||
for ch in ' /\\~!@#$%^&*()+=[];\':",./<>?\t\r\n':
|
||||
NombreObjeto = NombreObjeto.replace(ch, '_')
|
||||
|
||||
# Check for file path extension
|
||||
if len(ObjSelect) > 1:
|
||||
DirN= '%s_%s.mot' % (Dir[:-4], NombreObjeto)
|
||||
else:
|
||||
DirN= Dir
|
||||
|
||||
# Open the file
|
||||
File = open(DirN,'w')
|
||||
File.write ('LWMO\n3\n\n') # 3 is the version number.
|
||||
|
||||
# number of channels
|
||||
File.write ('NumChannels %i\n' % TotalCanales)
|
||||
|
||||
# ----------------------------
|
||||
# Main Cycle
|
||||
|
||||
def CicloPrimario(NumCanal):
|
||||
B.Set('curframe', FrameP)
|
||||
|
||||
File.write ('Channel %i\n{ Envelope\n %i\n' % (NumCanal, (FrameF - FrameP + 1)))
|
||||
|
||||
FrameA = FrameP
|
||||
while FrameA < (FrameF + 1):
|
||||
|
||||
B.Set('curframe', FrameA)
|
||||
|
||||
mat= ob.mat # Worldspace matrix
|
||||
|
||||
if NumCanal == 0:
|
||||
Val = mat.translationPart().x
|
||||
elif NumCanal == 1:
|
||||
Val = mat.translationPart().z
|
||||
elif NumCanal == 2:
|
||||
Val = mat.translationPart().y
|
||||
elif NumCanal == 3:
|
||||
Val = M.radians (-mat.toEuler().z)
|
||||
elif NumCanal == 4:
|
||||
Val = M.radians (-mat.toEuler().x)
|
||||
elif NumCanal == 5:
|
||||
Val = M.radians (-mat.toEuler().y)
|
||||
elif NumCanal == 6:
|
||||
Val = mat.scalePart().x
|
||||
elif NumCanal == 7:
|
||||
Val = mat.scalePart().z
|
||||
elif NumCanal == 8:
|
||||
Val = mat.scalePart().y
|
||||
File.write (' Key %f %f 3 0 0 0 0 0 0\n' % (Val, (FrameA/FrameRate)))
|
||||
|
||||
FrameA += 1
|
||||
# Ending Stuff
|
||||
File.write (' Behaviors 1 1\n}\n')
|
||||
|
||||
NumObjetoActual = len(ObjSelect)
|
||||
Iteraciones = 0
|
||||
ProgBarVal = 0.0
|
||||
while Iteraciones < TotalCanales:
|
||||
CicloPrimario(Iteraciones)
|
||||
|
||||
# Start Progress Bar
|
||||
B.Window.DrawProgressBar(ProgBarVal, origName)
|
||||
ProgBarVal = (float(Iteraciones) / TotalCanales) * 0.98
|
||||
Iteraciones += 1
|
||||
|
||||
B.Window.DrawProgressBar(1.0, '') # Done
|
||||
print '\nDone, %s motion file location is:\n%s\n' % (origName, DirN)
|
||||
B.Window.WaitCursor(0)
|
||||
|
||||
# Check if there are selected objects
|
||||
def main():
|
||||
B.Window.FileSelector(FuncionPrincipal, "Write .mot File", B.sys.makename(ext='.mot'))
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,454 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Quake 3 (.map)'
|
||||
Blender: 249
|
||||
Group: 'Export'
|
||||
Tooltip: 'Export to Quake map format'
|
||||
"""
|
||||
|
||||
__author__ = 'Campbell Barton'
|
||||
__version__ = '0.1a'
|
||||
__email__ = "ideasman42@gmail.com"
|
||||
__bpydoc__ = """\
|
||||
This script Exports a Quake 3 map format.
|
||||
|
||||
Supports meshes, lights and nurbs patch surfaces
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C): Campbell Barton
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
from Blender import *
|
||||
import BPyMesh
|
||||
|
||||
PREF_SCALE= Draw.Create(100)
|
||||
PREF_FACE_THICK= Draw.Create(0.1)
|
||||
PREF_GRID_SNAP= Draw.Create(0)
|
||||
# Quake 1/2?
|
||||
# PREF_DEF_TEX_OPTS= Draw.Create(' 0 0 0 1 1\n') # not user settable yet
|
||||
# Quake 3+?
|
||||
PREF_DEF_TEX_OPTS= Draw.Create(' 0 0 0 1 1 0 0 0\n') # not user settable yet
|
||||
|
||||
PREF_NULL_TEX= Draw.Create('NULL') # not user settable yet
|
||||
PREF_INVIS_TEX= Draw.Create('common/caulk')
|
||||
|
||||
def write_cube2brush(file, faces):
|
||||
'''
|
||||
Takes 6 faces and writes a brush,
|
||||
these faces can be from 1 mesh, 1 cube within a mesh of larger cubes
|
||||
Faces could even come from different meshes or be contrived.
|
||||
'''
|
||||
# comment only
|
||||
# file.write('// brush "%s", "%s"\n' % (ob.name, ob.getData(name_only=1)))
|
||||
file.write('// brush from cube\n{\n')
|
||||
|
||||
if PREF_GRID_SNAP.val: format_vec= '( %d %d %d ) '
|
||||
else: format_vec= '( %.8f %.8f %.8f ) '
|
||||
|
||||
for f in faces:
|
||||
# from 4 verts this gets them in reversed order and only 3 of them
|
||||
# 0,1,2,3 -> 2,1,0
|
||||
for v in f.v[2::-1]:
|
||||
file.write(format_vec % tuple(v.co) )
|
||||
|
||||
try: mode= f.mode
|
||||
except: mode= 0
|
||||
|
||||
if mode & Mesh.FaceModes.INVISIBLE:
|
||||
file.write(PREF_INVIS_TEX.val)
|
||||
else:
|
||||
try: image= f.image
|
||||
except: image= None
|
||||
|
||||
if image: file.write(sys.splitext(sys.basename(image.filename))[0])
|
||||
else: file.write(PREF_NULL_TEX.val)
|
||||
|
||||
# Texture stuff ignored for now
|
||||
file.write(PREF_DEF_TEX_OPTS.val)
|
||||
file.write('}\n')
|
||||
|
||||
|
||||
def round_vec(v):
|
||||
if PREF_GRID_SNAP.val:
|
||||
return round(v.x), round(v.y), round(v.z)
|
||||
else:
|
||||
return tuple(v)
|
||||
|
||||
def write_face2brush(file, face):
|
||||
'''
|
||||
takes a face and writes it as a brush
|
||||
each face is a cube/brush
|
||||
'''
|
||||
|
||||
if PREF_GRID_SNAP.val: format_vec= '( %d %d %d ) '
|
||||
else: format_vec= '( %.8f %.8f %.8f ) '
|
||||
|
||||
|
||||
image_text= PREF_NULL_TEX.val
|
||||
|
||||
try: mode= face.mode
|
||||
except: mode= 0
|
||||
|
||||
if mode & Mesh.FaceModes.INVISIBLE:
|
||||
image_text= PREF_INVIS_TEX.val
|
||||
else:
|
||||
try: image= face.image
|
||||
except: image= None
|
||||
if image: image_text = sys.splitext(sys.basename(image.filename))[0]
|
||||
|
||||
# original verts as tuples for writing
|
||||
orig_vco= [tuple(v.co) for v in face]
|
||||
|
||||
# new verts that give the face a thickness
|
||||
dist= PREF_SCALE.val * PREF_FACE_THICK.val
|
||||
new_vco= [round_vec(v.co - (v.no * dist)) for v in face]
|
||||
#new_vco= [round_vec(v.co - (face.no * dist)) for v in face]
|
||||
|
||||
file.write('// brush from face\n{\n')
|
||||
# front
|
||||
for co in orig_vco[2::-1]:
|
||||
file.write(format_vec % co )
|
||||
file.write(image_text)
|
||||
# Texture stuff ignored for now
|
||||
file.write(PREF_DEF_TEX_OPTS.val)
|
||||
|
||||
|
||||
for co in new_vco[:3]:
|
||||
file.write(format_vec % co )
|
||||
if mode & Mesh.FaceModes.TWOSIDE:
|
||||
file.write(image_text)
|
||||
else:
|
||||
file.write(PREF_INVIS_TEX.val)
|
||||
|
||||
# Texture stuff ignored for now
|
||||
file.write(PREF_DEF_TEX_OPTS.val)
|
||||
|
||||
# sides.
|
||||
if len(orig_vco)==3: # Tri, it seemms tri brushes are supported.
|
||||
index_pairs= ((0,1), (1,2), (2,0))
|
||||
else:
|
||||
index_pairs= ((0,1), (1,2), (2,3), (3,0))
|
||||
|
||||
for i1, i2 in index_pairs:
|
||||
for co in orig_vco[i1], orig_vco[i2], new_vco[i2]:
|
||||
file.write( format_vec % co )
|
||||
file.write(PREF_INVIS_TEX.val)
|
||||
file.write(PREF_DEF_TEX_OPTS.val)
|
||||
|
||||
file.write('}\n')
|
||||
|
||||
def is_cube_facegroup(faces):
|
||||
'''
|
||||
Returens a bool, true if the faces make up a cube
|
||||
'''
|
||||
# cube must have 6 faces
|
||||
if len(faces) != 6:
|
||||
print '1'
|
||||
return False
|
||||
|
||||
# Check for quads and that there are 6 unique verts
|
||||
verts= {}
|
||||
for f in faces:
|
||||
if len(f)!= 4:
|
||||
return False
|
||||
|
||||
for v in f:
|
||||
verts[v.index]= 0
|
||||
|
||||
if len(verts) != 8:
|
||||
return False
|
||||
|
||||
# Now check that each vert has 3 face users
|
||||
for f in faces:
|
||||
for v in f:
|
||||
verts[v.index] += 1
|
||||
|
||||
for v in verts.itervalues():
|
||||
if v != 3: # vert has 3 users?
|
||||
return False
|
||||
|
||||
# Could we check for 12 unique edges??, probably not needed.
|
||||
return True
|
||||
|
||||
def is_tricyl_facegroup(faces):
|
||||
'''
|
||||
is the face group a tri cylinder
|
||||
Returens a bool, true if the faces make an extruded tri solid
|
||||
'''
|
||||
|
||||
# cube must have 5 faces
|
||||
if len(faces) != 5:
|
||||
print '1'
|
||||
return False
|
||||
|
||||
# Check for quads and that there are 6 unique verts
|
||||
verts= {}
|
||||
tottri= 0
|
||||
for f in faces:
|
||||
if len(f)== 3:
|
||||
tottri+=1
|
||||
|
||||
for v in f:
|
||||
verts[v.index]= 0
|
||||
|
||||
if len(verts) != 6 or tottri != 2:
|
||||
return False
|
||||
|
||||
# Now check that each vert has 3 face users
|
||||
for f in faces:
|
||||
for v in f:
|
||||
verts[v.index] += 1
|
||||
|
||||
for v in verts.itervalues():
|
||||
if v != 3: # vert has 3 users?
|
||||
return False
|
||||
|
||||
# Could we check for 12 unique edges??, probably not needed.
|
||||
return True
|
||||
|
||||
def write_node_map(file, ob):
|
||||
'''
|
||||
Writes the properties of an object (empty in this case)
|
||||
as a MAP node as long as it has the property name - classname
|
||||
returns True/False based on weather a node was written
|
||||
'''
|
||||
props= [(p.name, p.data) for p in ob.game_properties]
|
||||
|
||||
IS_MAP_NODE= False
|
||||
for name, value in props:
|
||||
if name=='classname':
|
||||
IS_MAP_NODE= True
|
||||
break
|
||||
|
||||
if not IS_MAP_NODE:
|
||||
return False
|
||||
|
||||
# Write a node
|
||||
file.write('{\n')
|
||||
for name_value in props:
|
||||
file.write('"%s" "%s"\n' % name_value)
|
||||
if PREF_GRID_SNAP.val:
|
||||
file.write('"origin" "%d %d %d"\n' % tuple([round(axis*PREF_SCALE.val) for axis in ob.getLocation('worldspace')]) )
|
||||
else:
|
||||
file.write('"origin" "%.6f %.6f %.6f"\n' % tuple([axis*PREF_SCALE.val for axis in ob.getLocation('worldspace')]) )
|
||||
file.write('}\n')
|
||||
return True
|
||||
|
||||
|
||||
def export_map(filepath):
|
||||
|
||||
pup_block = [\
|
||||
('Scale:', PREF_SCALE, 1, 1000, 'Scale the blender scene by this value.'),\
|
||||
('Face Width:', PREF_FACE_THICK, 0.01, 10, 'Thickness of faces exported as brushes.'),\
|
||||
('Grid Snap', PREF_GRID_SNAP, 'snaps floating point values to whole numbers.'),\
|
||||
'Null Texture',\
|
||||
('', PREF_NULL_TEX, 1, 128, 'Export textureless faces with this texture'),\
|
||||
'Unseen Texture',\
|
||||
('', PREF_INVIS_TEX, 1, 128, 'Export invisible faces with this texture'),\
|
||||
]
|
||||
|
||||
if not Draw.PupBlock('map export', pup_block):
|
||||
return
|
||||
|
||||
Window.WaitCursor(1)
|
||||
time= sys.time()
|
||||
print 'Map Exporter 0.0'
|
||||
file= open(filepath, 'w')
|
||||
|
||||
|
||||
obs_mesh= []
|
||||
obs_lamp= []
|
||||
obs_surf= []
|
||||
obs_empty= []
|
||||
|
||||
SCALE_MAT= Mathutils.Matrix()
|
||||
SCALE_MAT[0][0]= SCALE_MAT[1][1]= SCALE_MAT[2][2]= PREF_SCALE.val
|
||||
|
||||
dummy_mesh= Mesh.New()
|
||||
|
||||
TOTBRUSH= TOTLAMP= TOTNODE= 0
|
||||
|
||||
for ob in Object.GetSelected():
|
||||
type= ob.type
|
||||
if type == 'Mesh': obs_mesh.append(ob)
|
||||
elif type == 'Surf': obs_surf.append(ob)
|
||||
elif type == 'Lamp': obs_lamp.append(ob)
|
||||
elif type == 'Empty': obs_empty.append(ob)
|
||||
|
||||
if obs_mesh or obs_surf:
|
||||
# brushes and surf's must be under worldspan
|
||||
file.write('\n// entity 0\n')
|
||||
file.write('{\n')
|
||||
file.write('"classname" "worldspawn"\n')
|
||||
|
||||
|
||||
print '\twriting cubes from meshes'
|
||||
for ob in obs_mesh:
|
||||
dummy_mesh.getFromObject(ob.name)
|
||||
|
||||
#print len(mesh_split2connected(dummy_mesh))
|
||||
|
||||
# Is the object 1 cube? - object-is-a-brush
|
||||
dummy_mesh.transform(ob.matrixWorld*SCALE_MAT) # 1 to tx the normals also
|
||||
|
||||
if PREF_GRID_SNAP.val:
|
||||
for v in dummy_mesh.verts:
|
||||
co= v.co
|
||||
co.x= round(co.x)
|
||||
co.y= round(co.y)
|
||||
co.z= round(co.z)
|
||||
|
||||
# High quality normals
|
||||
BPyMesh.meshCalcNormals(dummy_mesh)
|
||||
|
||||
# Split mesh into connected regions
|
||||
for face_group in BPyMesh.mesh2linkedFaces(dummy_mesh):
|
||||
if is_cube_facegroup(face_group):
|
||||
write_cube2brush(file, face_group)
|
||||
TOTBRUSH+=1
|
||||
elif is_tricyl_facegroup(face_group):
|
||||
write_cube2brush(file, face_group)
|
||||
TOTBRUSH+=1
|
||||
else:
|
||||
for f in face_group:
|
||||
write_face2brush(file, f)
|
||||
TOTBRUSH+=1
|
||||
|
||||
#print 'warning, not exporting "%s" it is not a cube' % ob.name
|
||||
|
||||
|
||||
dummy_mesh.verts= None
|
||||
|
||||
|
||||
valid_dims= 3,5,7,9,11,13,15
|
||||
for ob in obs_surf:
|
||||
'''
|
||||
Surf, patches
|
||||
'''
|
||||
surf_name= ob.getData(name_only=1)
|
||||
data= Curve.Get(surf_name)
|
||||
mat = ob.matrixWorld*SCALE_MAT
|
||||
|
||||
# This is what a valid patch looks like
|
||||
|
||||
"""
|
||||
// brush 0
|
||||
{
|
||||
patchDef2
|
||||
{
|
||||
NULL
|
||||
( 3 3 0 0 0 )
|
||||
(
|
||||
( ( -64 -64 0 0 0 ) ( -64 0 0 0 -2 ) ( -64 64 0 0 -4 ) )
|
||||
( ( 0 -64 0 2 0 ) ( 0 0 0 2 -2 ) ( 0 64 0 2 -4 ) )
|
||||
( ( 64 -64 0 4 0 ) ( 64 0 0 4 -2 ) ( 80 88 0 4 -4 ) )
|
||||
)
|
||||
}
|
||||
}
|
||||
"""
|
||||
for i, nurb in enumerate(data):
|
||||
u= nurb.pointsU
|
||||
v= nurb.pointsV
|
||||
if u in valid_dims and v in valid_dims:
|
||||
|
||||
file.write('// brush %d surf_name\n' % i)
|
||||
file.write('{\n')
|
||||
file.write('patchDef2\n')
|
||||
file.write('{\n')
|
||||
file.write('NULL\n')
|
||||
file.write('( %d %d 0 0 0 )\n' % (u, v) )
|
||||
file.write('(\n')
|
||||
|
||||
u_iter = 0
|
||||
for p in nurb:
|
||||
|
||||
if u_iter == 0:
|
||||
file.write('(')
|
||||
|
||||
u_iter += 1
|
||||
|
||||
# add nmapping 0 0 ?
|
||||
if PREF_GRID_SNAP.val:
|
||||
file.write(' ( %d %d %d 0 0 )' % round_vec(Mathutils.Vector(p[0:3]) * mat))
|
||||
else:
|
||||
file.write(' ( %.6f %.6f %.6f 0 0 )' % tuple(Mathutils.Vector(p[0:3]) * mat))
|
||||
|
||||
# Move to next line
|
||||
if u_iter == u:
|
||||
file.write(' )\n')
|
||||
u_iter = 0
|
||||
|
||||
file.write(')\n')
|
||||
file.write('}\n')
|
||||
file.write('}\n')
|
||||
|
||||
|
||||
# Debugging
|
||||
# for p in nurb: print 'patch', p
|
||||
|
||||
else:
|
||||
print "NOT EXPORTING PATCH", surf_name, u,v, 'Unsupported'
|
||||
|
||||
|
||||
if obs_mesh or obs_surf:
|
||||
file.write('}\n') # end worldspan
|
||||
|
||||
|
||||
print '\twriting lamps'
|
||||
for ob in obs_lamp:
|
||||
print '\t\t%s' % ob.name
|
||||
lamp= ob.data
|
||||
file.write('{\n')
|
||||
file.write('"classname" "light"\n')
|
||||
file.write('"light" "%.6f"\n' % (lamp.dist* PREF_SCALE.val))
|
||||
if PREF_GRID_SNAP.val:
|
||||
file.write('"origin" "%d %d %d"\n' % tuple([round(axis*PREF_SCALE.val) for axis in ob.getLocation('worldspace')]) )
|
||||
else:
|
||||
file.write('"origin" "%.6f %.6f %.6f"\n' % tuple([axis*PREF_SCALE.val for axis in ob.getLocation('worldspace')]) )
|
||||
file.write('"_color" "%.6f %.6f %.6f"\n' % tuple(lamp.col))
|
||||
file.write('"style" "0"\n')
|
||||
file.write('}\n')
|
||||
TOTLAMP+=1
|
||||
|
||||
|
||||
print '\twriting empty objects as nodes'
|
||||
for ob in obs_empty:
|
||||
if write_node_map(file, ob):
|
||||
print '\t\t%s' % ob.name
|
||||
TOTNODE+=1
|
||||
else:
|
||||
print '\t\tignoring %s' % ob.name
|
||||
|
||||
Window.WaitCursor(0)
|
||||
|
||||
print 'Exported Map in %.4fsec' % (sys.time()-time)
|
||||
print 'Brushes: %d Nodes: %d Lamps %d\n' % (TOTBRUSH, TOTNODE, TOTLAMP)
|
||||
|
||||
|
||||
def main():
|
||||
Window.FileSelector(export_map, 'EXPORT MAP', '*.map')
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
# export_map('/foo.map')
|
||||
@@ -1,168 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Vertex Keyframe Animation (.mdd)...'
|
||||
Blender: 242
|
||||
Group: 'Export'
|
||||
Tooltip: 'Animated mesh to MDD vertex keyframe file.'
|
||||
"""
|
||||
|
||||
__author__ = "Bill L.Nieuwendorp"
|
||||
__bpydoc__ = """\
|
||||
This script Exports Lightwaves MotionDesigner format.
|
||||
|
||||
The .mdd format has become quite a popular Pipeline format<br>
|
||||
for moving animations from package to package.
|
||||
|
||||
Be sure not to use modifiers that change the number or order of verts in the mesh
|
||||
"""
|
||||
#Please send any fixes,updates,bugs to Slow67_at_Gmail.com or cbarton_at_metavr.com
|
||||
#Bill Niewuendorp
|
||||
# ***** 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 *****
|
||||
|
||||
import bpy
|
||||
import Blender
|
||||
from Blender import *
|
||||
import BPyMessages
|
||||
try:
|
||||
from struct import pack
|
||||
except:
|
||||
pack = None
|
||||
|
||||
|
||||
def zero_file(filepath):
|
||||
'''
|
||||
If a file fails, this replaces it with 1 char, better not remove it?
|
||||
'''
|
||||
file = open(filepath, 'w')
|
||||
file.write('\n') # aparently macosx needs some data in a blank file?
|
||||
file.close()
|
||||
|
||||
|
||||
def check_vertcount(mesh,vertcount):
|
||||
'''
|
||||
check and make sure the vertcount is consistent throghout the frame range
|
||||
'''
|
||||
if len(mesh.verts) != vertcount:
|
||||
Blender.Draw.PupMenu('Error%t|Number of verts has changed during animation|cannot export')
|
||||
f.close()
|
||||
zero_file(filepath)
|
||||
return
|
||||
|
||||
|
||||
def mdd_export(filepath, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
|
||||
|
||||
Window.EditMode(0)
|
||||
Blender.Window.WaitCursor(1)
|
||||
mesh_orig = Mesh.New()
|
||||
mesh_orig.getFromObject(ob.name)
|
||||
|
||||
#Flip y and z
|
||||
'''
|
||||
mat = Mathutils.Matrix()
|
||||
mat[2][2] = -1
|
||||
rotmat = Mathutils.RotationMatrix(90, 4, 'x')
|
||||
mat_flip = mat*rotmat
|
||||
'''
|
||||
# Above results in this matrix
|
||||
mat_flip= Mathutils.Matrix(\
|
||||
[1.0, 0.0, 0.0, 0.0],\
|
||||
[0.0, 0.0, 1.0, 0.0],\
|
||||
[0.0, 1.0, 0.0, 0.0],\
|
||||
[0.0, 0.0, 0.0, 1.0],\
|
||||
)
|
||||
|
||||
me_tmp = Mesh.New() # container mesh
|
||||
|
||||
numverts = len(mesh_orig.verts)
|
||||
numframes = PREF_ENDFRAME-PREF_STARTFRAME+1
|
||||
PREF_FPS= float(PREF_FPS)
|
||||
f = open(filepath, 'wb') #no Errors yet:Safe to create file
|
||||
|
||||
# Write the header
|
||||
f.write(pack(">2i", numframes, numverts))
|
||||
|
||||
# Write the frame times (should we use the time IPO??)
|
||||
f.write( pack(">%df" % (numframes), *[frame/PREF_FPS for frame in xrange(numframes)]) ) # seconds
|
||||
|
||||
#rest frame needed to keep frames in sync
|
||||
Blender.Set('curframe', PREF_STARTFRAME)
|
||||
me_tmp.getFromObject(ob.name)
|
||||
check_vertcount(me_tmp,numverts)
|
||||
me_tmp.transform(ob.matrixWorld * mat_flip)
|
||||
f.write(pack(">%df" % (numverts*3), *[axis for v in me_tmp.verts for axis in v.co]))
|
||||
me_tmp.verts= None
|
||||
|
||||
for frame in xrange(PREF_STARTFRAME,PREF_ENDFRAME+1):#in order to start at desired frame
|
||||
Blender.Set('curframe', frame)
|
||||
|
||||
me_tmp.getFromObject(ob.name)
|
||||
|
||||
check_vertcount(me_tmp,numverts)
|
||||
|
||||
me_tmp.transform(ob.matrixWorld * mat_flip)
|
||||
|
||||
# Write the vertex data
|
||||
f.write(pack(">%df" % (numverts*3), *[axis for v in me_tmp.verts for axis in v.co]))
|
||||
|
||||
me_tmp.verts= None
|
||||
f.close()
|
||||
|
||||
print'MDD Exported: %s frames:%d\n'% (filepath, numframes-1)
|
||||
Blender.Window.WaitCursor(0)
|
||||
|
||||
|
||||
def mdd_export_ui(filepath):
|
||||
# Dont overwrite
|
||||
if not BPyMessages.Warning_SaveOver(filepath):
|
||||
return
|
||||
|
||||
scn= bpy.data.scenes.active
|
||||
ob_act= scn.objects.active
|
||||
if not ob_act or ob_act.type != 'Mesh':
|
||||
BPyMessages.Error_NoMeshActive()
|
||||
|
||||
ctx = scn.getRenderingContext()
|
||||
orig_frame = Blender.Get('curframe')
|
||||
PREF_STARTFRAME= Blender.Draw.Create(int(ctx.startFrame()))
|
||||
PREF_ENDFRAME= Blender.Draw.Create(int(ctx.endFrame()))
|
||||
PREF_FPS= Blender.Draw.Create(ctx.fps)
|
||||
|
||||
block = [\
|
||||
("Start Frame: ", PREF_STARTFRAME, 1, 30000, "Start Bake from what frame?: Default 1"),\
|
||||
("End Frame: ", PREF_ENDFRAME, 1, 30000, "End Bake on what Frame?"),\
|
||||
("FPS: ", PREF_FPS, 1, 100, "Frames per second")\
|
||||
]
|
||||
|
||||
if not Blender.Draw.PupBlock("Export MDD", block):
|
||||
return
|
||||
|
||||
PREF_STARTFRAME, PREF_ENDFRAME=\
|
||||
min(PREF_STARTFRAME.val, PREF_ENDFRAME.val),\
|
||||
max(PREF_STARTFRAME.val, PREF_ENDFRAME.val)
|
||||
|
||||
print (filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val)
|
||||
mdd_export(filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val)
|
||||
Blender.Set('curframe', orig_frame)
|
||||
|
||||
if __name__=='__main__':
|
||||
if not pack:
|
||||
Draw.PupMenu('Error%t|This script requires a full python install')
|
||||
|
||||
Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd'))
|
||||
@@ -1,933 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Wavefront (.obj)...'
|
||||
Blender: 249
|
||||
Group: 'Export'
|
||||
Tooltip: 'Save a Wavefront OBJ File'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton, Jiri Hnidek, Paolo Ciccone"
|
||||
__url__ = ['http://wiki.blender.org/index.php/Scripts/Manual/Export/wavefront_obj', 'www.blender.org', 'blenderartists.org']
|
||||
__version__ = "1.22"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script is an exporter to OBJ file format.
|
||||
|
||||
Usage:
|
||||
|
||||
Select the objects you wish to export and run this script from "File->Export" menu.
|
||||
Selecting the default options from the popup box will be good in most cases.
|
||||
All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d)
|
||||
will be exported as mesh data.
|
||||
"""
|
||||
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) Campbell J Barton 2007-2009
|
||||
# - V1.22- bspline import/export added (funded by PolyDimensions GmbH)
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
import Blender
|
||||
from Blender import Mesh, Scene, Window, sys, Image, Draw
|
||||
import BPyMesh
|
||||
import BPyObject
|
||||
import BPySys
|
||||
import BPyMessages
|
||||
|
||||
# Returns a tuple - path,extension.
|
||||
# 'hello.obj' > ('hello', '.obj')
|
||||
def splitExt(path):
|
||||
dotidx = path.rfind('.')
|
||||
if dotidx == -1:
|
||||
return path, ''
|
||||
else:
|
||||
return path[:dotidx], path[dotidx:]
|
||||
|
||||
def fixName(name):
|
||||
if name == None:
|
||||
return 'None'
|
||||
else:
|
||||
return name.replace(' ', '_')
|
||||
|
||||
# A Dict of Materials
|
||||
# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
|
||||
MTL_DICT = {}
|
||||
|
||||
def write_mtl(filename):
|
||||
|
||||
world = Blender.World.GetCurrent()
|
||||
if world:
|
||||
worldAmb = world.getAmb()
|
||||
else:
|
||||
worldAmb = (0,0,0) # Default value
|
||||
|
||||
file = open(filename, "w")
|
||||
file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
|
||||
file.write('# Material Count: %i\n' % len(MTL_DICT))
|
||||
# Write material/image combinations we have used.
|
||||
for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems():
|
||||
|
||||
# Get the Blender data for the material and the image.
|
||||
# Having an image named None will make a bug, dont do it :)
|
||||
|
||||
file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname
|
||||
|
||||
if mat:
|
||||
file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's
|
||||
file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour,
|
||||
file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse
|
||||
file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular
|
||||
file.write('Ni %.6f\n' % mat.IOR) # Refraction index
|
||||
file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve)
|
||||
|
||||
# 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
|
||||
if mat.getMode() & Blender.Material.Modes['SHADELESS']:
|
||||
file.write('illum 0\n') # ignore lighting
|
||||
elif mat.getSpec() == 0:
|
||||
file.write('illum 1\n') # no specular.
|
||||
else:
|
||||
file.write('illum 2\n') # light normaly
|
||||
|
||||
else:
|
||||
#write a dummy material here?
|
||||
file.write('Ns 0\n')
|
||||
file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour,
|
||||
file.write('Kd 0.8 0.8 0.8\n')
|
||||
file.write('Ks 0.8 0.8 0.8\n')
|
||||
file.write('d 1\n') # No alpha
|
||||
file.write('illum 2\n') # light normaly
|
||||
|
||||
# Write images!
|
||||
if img: # We have an image on the face!
|
||||
file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image
|
||||
|
||||
elif mat: # No face image. if we havea material search for MTex image.
|
||||
for mtex in mat.getTextures():
|
||||
if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
|
||||
try:
|
||||
filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1]
|
||||
file.write('map_Kd %s\n' % filename) # Diffuse mapping image
|
||||
break
|
||||
except:
|
||||
# Texture has no image though its an image type, best ignore.
|
||||
pass
|
||||
|
||||
file.write('\n\n')
|
||||
|
||||
file.close()
|
||||
|
||||
def copy_file(source, dest):
|
||||
file = open(source, 'rb')
|
||||
data = file.read()
|
||||
file.close()
|
||||
|
||||
file = open(dest, 'wb')
|
||||
file.write(data)
|
||||
file.close()
|
||||
|
||||
|
||||
def copy_images(dest_dir):
|
||||
if dest_dir[-1] != sys.sep:
|
||||
dest_dir += sys.sep
|
||||
|
||||
# Get unique image names
|
||||
uniqueImages = {}
|
||||
for matname, mat, image in MTL_DICT.itervalues(): # Only use image name
|
||||
# Get Texface images
|
||||
if image:
|
||||
uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default.
|
||||
|
||||
# Get MTex images
|
||||
if mat:
|
||||
for mtex in mat.getTextures():
|
||||
if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
|
||||
image_tex = mtex.tex.image
|
||||
if image_tex:
|
||||
try:
|
||||
uniqueImages[image_tex] = image_tex
|
||||
except:
|
||||
pass
|
||||
|
||||
# Now copy images
|
||||
copyCount = 0
|
||||
|
||||
for bImage in uniqueImages.itervalues():
|
||||
image_path = sys.expandpath(bImage.filename)
|
||||
if sys.exists(image_path):
|
||||
# Make a name for the target path.
|
||||
dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
|
||||
if not sys.exists(dest_image_path): # Image isnt alredy there
|
||||
print '\tCopying "%s" > "%s"' % (image_path, dest_image_path)
|
||||
copy_file(image_path, dest_image_path)
|
||||
copyCount+=1
|
||||
print '\tCopied %d images' % copyCount
|
||||
|
||||
|
||||
def test_nurbs_compat(ob):
|
||||
if ob.type != 'Curve':
|
||||
return False
|
||||
|
||||
for nu in ob.data:
|
||||
if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def write_nurb(file, ob, ob_mat):
|
||||
tot_verts = 0
|
||||
cu = ob.data
|
||||
|
||||
# use negative indices
|
||||
Vector = Blender.Mathutils.Vector
|
||||
for nu in cu:
|
||||
|
||||
if nu.type==0: DEG_ORDER_U = 1
|
||||
else: DEG_ORDER_U = nu.orderU-1 # Tested to be correct
|
||||
|
||||
if nu.type==1:
|
||||
print "\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported"
|
||||
continue
|
||||
|
||||
if nu.knotsV:
|
||||
print "\tWarning, surface:", ob.name, "only poly and nurbs curves supported"
|
||||
continue
|
||||
|
||||
if len(nu) <= DEG_ORDER_U:
|
||||
print "\tWarning, orderU is lower then vert count, skipping:", ob.name
|
||||
continue
|
||||
|
||||
pt_num = 0
|
||||
do_closed = (nu.flagU & 1)
|
||||
do_endpoints = (do_closed==0) and (nu.flagU & 2)
|
||||
|
||||
for pt in nu:
|
||||
pt = Vector(pt[0], pt[1], pt[2]) * ob_mat
|
||||
file.write('v %.6f %.6f %.6f\n' % (pt[0], pt[1], pt[2]))
|
||||
pt_num += 1
|
||||
tot_verts += pt_num
|
||||
|
||||
file.write('g %s\n' % (fixName(ob.name))) # fixName(ob.getData(1)) could use the data name too
|
||||
file.write('cstype bspline\n') # not ideal, hard coded
|
||||
file.write('deg %d\n' % DEG_ORDER_U) # not used for curves but most files have it still
|
||||
|
||||
curve_ls = [-(i+1) for i in xrange(pt_num)]
|
||||
|
||||
# 'curv' keyword
|
||||
if do_closed:
|
||||
if DEG_ORDER_U == 1:
|
||||
pt_num += 1
|
||||
curve_ls.append(-1)
|
||||
else:
|
||||
pt_num += DEG_ORDER_U
|
||||
curve_ls = curve_ls + curve_ls[0:DEG_ORDER_U]
|
||||
|
||||
file.write('curv 0.0 1.0 %s\n' % (' '.join( [str(i) for i in curve_ls] ))) # Blender has no U and V values for the curve
|
||||
|
||||
# 'parm' keyword
|
||||
tot_parm = (DEG_ORDER_U + 1) + pt_num
|
||||
tot_parm_div = float(tot_parm-1)
|
||||
parm_ls = [(i/tot_parm_div) for i in xrange(tot_parm)]
|
||||
|
||||
if do_endpoints: # end points, force param
|
||||
for i in xrange(DEG_ORDER_U+1):
|
||||
parm_ls[i] = 0.0
|
||||
parm_ls[-(1+i)] = 1.0
|
||||
|
||||
file.write('parm u %s\n' % ' '.join( [str(i) for i in parm_ls] ))
|
||||
|
||||
file.write('end\n')
|
||||
|
||||
return tot_verts
|
||||
|
||||
def write(filename, objects,\
|
||||
EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_NORMALS_HQ=False,\
|
||||
EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\
|
||||
EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\
|
||||
EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=False,\
|
||||
EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
|
||||
'''
|
||||
Basic write function. The context and options must be alredy set
|
||||
This can be accessed externaly
|
||||
eg.
|
||||
write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
|
||||
'''
|
||||
|
||||
def veckey3d(v):
|
||||
return round(v.x, 6), round(v.y, 6), round(v.z, 6)
|
||||
|
||||
def veckey2d(v):
|
||||
return round(v.x, 6), round(v.y, 6)
|
||||
|
||||
def findVertexGroupName(face, vWeightMap):
|
||||
"""
|
||||
Searches the vertexDict to see what groups is assigned to a given face.
|
||||
We use a frequency system in order to sort out the name because a given vetex can
|
||||
belong to two or more groups at the same time. To find the right name for the face
|
||||
we list all the possible vertex group names with their frequency and then sort by
|
||||
frequency in descend order. The top element is the one shared by the highest number
|
||||
of vertices is the face's group
|
||||
"""
|
||||
weightDict = {}
|
||||
for vert in face:
|
||||
vWeights = vWeightMap[vert.index]
|
||||
for vGroupName, weight in vWeights:
|
||||
weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight
|
||||
|
||||
if weightDict:
|
||||
alist = [(weight,vGroupName) for vGroupName, weight in weightDict.iteritems()] # sort least to greatest amount of weight
|
||||
alist.sort()
|
||||
return(alist[-1][1]) # highest value last
|
||||
else:
|
||||
return '(null)'
|
||||
|
||||
|
||||
print 'OBJ Export path: "%s"' % filename
|
||||
temp_mesh_name = '~tmp-mesh'
|
||||
|
||||
time1 = sys.time()
|
||||
scn = Scene.GetCurrent()
|
||||
|
||||
file = open(filename, "w")
|
||||
|
||||
# Write Header
|
||||
file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
|
||||
file.write('# www.blender3d.org\n')
|
||||
|
||||
# Tell the obj file what material file to use.
|
||||
if EXPORT_MTL:
|
||||
mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
|
||||
file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
|
||||
|
||||
# Get the container mesh. - used for applying modifiers and non mesh objects.
|
||||
containerMesh = meshName = tempMesh = None
|
||||
for meshName in Blender.NMesh.GetNames():
|
||||
if meshName.startswith(temp_mesh_name):
|
||||
tempMesh = Mesh.Get(meshName)
|
||||
if not tempMesh.users:
|
||||
containerMesh = tempMesh
|
||||
if not containerMesh:
|
||||
containerMesh = Mesh.New(temp_mesh_name)
|
||||
|
||||
if EXPORT_ROTX90:
|
||||
mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
|
||||
|
||||
del meshName
|
||||
del tempMesh
|
||||
|
||||
# Initialize totals, these are updated each object
|
||||
totverts = totuvco = totno = 1
|
||||
|
||||
face_vert_index = 1
|
||||
|
||||
globalNormals = {}
|
||||
|
||||
# Get all meshes
|
||||
for ob_main in objects:
|
||||
for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
|
||||
|
||||
# Nurbs curve support
|
||||
if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
|
||||
if EXPORT_ROTX90:
|
||||
ob_mat = ob_mat * mat_xrot90
|
||||
|
||||
totverts += write_nurb(file, ob, ob_mat)
|
||||
|
||||
continue
|
||||
# end nurbs
|
||||
|
||||
# Will work for non meshes now! :)
|
||||
# getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
|
||||
me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
|
||||
if not me:
|
||||
continue
|
||||
|
||||
if EXPORT_UV:
|
||||
faceuv= me.faceUV
|
||||
else:
|
||||
faceuv = False
|
||||
|
||||
# We have a valid mesh
|
||||
if EXPORT_TRI and me.faces:
|
||||
# Add a dummy object to it.
|
||||
has_quads = False
|
||||
for f in me.faces:
|
||||
if len(f) == 4:
|
||||
has_quads = True
|
||||
break
|
||||
|
||||
if has_quads:
|
||||
oldmode = Mesh.Mode()
|
||||
Mesh.Mode(Mesh.SelectModes['FACE'])
|
||||
|
||||
me.sel = True
|
||||
tempob = scn.objects.new(me)
|
||||
me.quadToTriangle(0) # more=0 shortest length
|
||||
oldmode = Mesh.Mode(oldmode)
|
||||
scn.objects.unlink(tempob)
|
||||
|
||||
Mesh.Mode(oldmode)
|
||||
|
||||
# Make our own list so it can be sorted to reduce context switching
|
||||
faces = [ f for f in me.faces ]
|
||||
|
||||
if EXPORT_EDGES:
|
||||
edges = me.edges
|
||||
else:
|
||||
edges = []
|
||||
|
||||
if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write
|
||||
continue # dont bother with this mesh.
|
||||
|
||||
if EXPORT_ROTX90:
|
||||
me.transform(ob_mat*mat_xrot90)
|
||||
else:
|
||||
me.transform(ob_mat)
|
||||
|
||||
# High Quality Normals
|
||||
if EXPORT_NORMALS and faces:
|
||||
if EXPORT_NORMALS_HQ:
|
||||
BPyMesh.meshCalcNormals(me)
|
||||
else:
|
||||
# transforming normals is incorrect
|
||||
# when the matrix is scaled,
|
||||
# better to recalculate them
|
||||
me.calcNormals()
|
||||
|
||||
# # Crash Blender
|
||||
#materials = me.getMaterials(1) # 1 == will return None in the list.
|
||||
materials = me.materials
|
||||
|
||||
materialNames = []
|
||||
materialItems = materials[:]
|
||||
if materials:
|
||||
for mat in materials:
|
||||
if mat: # !=None
|
||||
materialNames.append(mat.name)
|
||||
else:
|
||||
materialNames.append(None)
|
||||
# Cant use LC because some materials are None.
|
||||
# materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.
|
||||
|
||||
# Possible there null materials, will mess up indicies
|
||||
# but at least it will export, wait until Blender gets fixed.
|
||||
materialNames.extend((16-len(materialNames)) * [None])
|
||||
materialItems.extend((16-len(materialItems)) * [None])
|
||||
|
||||
# Sort by Material, then images
|
||||
# so we dont over context switch in the obj file.
|
||||
if EXPORT_KEEP_VERT_ORDER:
|
||||
pass
|
||||
elif faceuv:
|
||||
try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
|
||||
except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
|
||||
elif len(materials) > 1:
|
||||
try: faces.sort(key = lambda a: (a.mat, a.smooth))
|
||||
except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
|
||||
else:
|
||||
# no materials
|
||||
try: faces.sort(key = lambda a: a.smooth)
|
||||
except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
|
||||
|
||||
# Set the default mat to no material and no image.
|
||||
contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
|
||||
contextSmooth = None # Will either be true or false, set bad to force initialization switch.
|
||||
|
||||
if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
|
||||
name1 = ob.name
|
||||
name2 = ob.getData(1)
|
||||
if name1 == name2:
|
||||
obnamestring = fixName(name1)
|
||||
else:
|
||||
obnamestring = '%s_%s' % (fixName(name1), fixName(name2))
|
||||
|
||||
if EXPORT_BLEN_OBS:
|
||||
file.write('o %s\n' % obnamestring) # Write Object name
|
||||
else: # if EXPORT_GROUP_BY_OB:
|
||||
file.write('g %s\n' % obnamestring)
|
||||
|
||||
|
||||
# Vert
|
||||
for v in me.verts:
|
||||
file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
|
||||
|
||||
# UV
|
||||
if faceuv:
|
||||
uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
|
||||
|
||||
uv_dict = {} # could use a set() here
|
||||
for f_index, f in enumerate(faces):
|
||||
|
||||
for uv_index, uv in enumerate(f.uv):
|
||||
uvkey = veckey2d(uv)
|
||||
try:
|
||||
uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
|
||||
except:
|
||||
uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
|
||||
file.write('vt %.6f %.6f\n' % tuple(uv))
|
||||
|
||||
uv_unique_count = len(uv_dict)
|
||||
del uv, uvkey, uv_dict, f_index, uv_index
|
||||
# Only need uv_unique_count and uv_face_mapping
|
||||
|
||||
# NORMAL, Smooth/Non smoothed.
|
||||
if EXPORT_NORMALS:
|
||||
for f in faces:
|
||||
if f.smooth:
|
||||
for v in f:
|
||||
noKey = veckey3d(v.no)
|
||||
if not globalNormals.has_key( noKey ):
|
||||
globalNormals[noKey] = totno
|
||||
totno +=1
|
||||
file.write('vn %.6f %.6f %.6f\n' % noKey)
|
||||
else:
|
||||
# Hard, 1 normal from the face.
|
||||
noKey = veckey3d(f.no)
|
||||
if not globalNormals.has_key( noKey ):
|
||||
globalNormals[noKey] = totno
|
||||
totno +=1
|
||||
file.write('vn %.6f %.6f %.6f\n' % noKey)
|
||||
|
||||
if not faceuv:
|
||||
f_image = None
|
||||
|
||||
if EXPORT_POLYGROUPS:
|
||||
# Retrieve the list of vertex groups
|
||||
vertGroupNames = me.getVertGroupNames()
|
||||
|
||||
currentVGroup = ''
|
||||
# Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to
|
||||
vgroupsMap = [[] for _i in xrange(len(me.verts))]
|
||||
for vertexGroupName in vertGroupNames:
|
||||
for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1):
|
||||
vgroupsMap[vIdx].append((vertexGroupName, vWeight))
|
||||
|
||||
for f_index, f in enumerate(faces):
|
||||
f_v= f.v
|
||||
f_smooth= f.smooth
|
||||
f_mat = min(f.mat, len(materialNames)-1)
|
||||
if faceuv:
|
||||
f_image = f.image
|
||||
f_uv= f.uv
|
||||
|
||||
# MAKE KEY
|
||||
if faceuv and f_image: # Object is always true.
|
||||
key = materialNames[f_mat], f_image.name
|
||||
else:
|
||||
key = materialNames[f_mat], None # No image, use None instead.
|
||||
|
||||
# Write the vertex group
|
||||
if EXPORT_POLYGROUPS:
|
||||
if vertGroupNames:
|
||||
# find what vertext group the face belongs to
|
||||
theVGroup = findVertexGroupName(f,vgroupsMap)
|
||||
if theVGroup != currentVGroup:
|
||||
currentVGroup = theVGroup
|
||||
file.write('g %s\n' % theVGroup)
|
||||
|
||||
# CHECK FOR CONTEXT SWITCH
|
||||
if key == contextMat:
|
||||
pass # Context alredy switched, dont do anything
|
||||
else:
|
||||
if key[0] == None and key[1] == None:
|
||||
# Write a null material, since we know the context has changed.
|
||||
if EXPORT_GROUP_BY_MAT:
|
||||
file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null)
|
||||
file.write('usemtl (null)\n') # mat, image
|
||||
|
||||
else:
|
||||
mat_data= MTL_DICT.get(key)
|
||||
if not mat_data:
|
||||
# First add to global dict so we can export to mtl
|
||||
# Then write mtl
|
||||
|
||||
# Make a new names from the mat and image name,
|
||||
# converting any spaces to underscores with fixName.
|
||||
|
||||
# If none image dont bother adding it to the name
|
||||
if key[1] == None:
|
||||
mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
|
||||
else:
|
||||
mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
|
||||
|
||||
if EXPORT_GROUP_BY_MAT:
|
||||
file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null)
|
||||
|
||||
file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null)
|
||||
|
||||
contextMat = key
|
||||
if f_smooth != contextSmooth:
|
||||
if f_smooth: # on now off
|
||||
file.write('s 1\n')
|
||||
contextSmooth = f_smooth
|
||||
else: # was off now on
|
||||
file.write('s off\n')
|
||||
contextSmooth = f_smooth
|
||||
|
||||
file.write('f')
|
||||
if faceuv:
|
||||
if EXPORT_NORMALS:
|
||||
if f_smooth: # Smoothed, use vertex normals
|
||||
for vi, v in enumerate(f_v):
|
||||
file.write( ' %d/%d/%d' % (\
|
||||
v.index+totverts,\
|
||||
totuvco + uv_face_mapping[f_index][vi],\
|
||||
globalNormals[ veckey3d(v.no) ])) # vert, uv, normal
|
||||
|
||||
else: # No smoothing, face normals
|
||||
no = globalNormals[ veckey3d(f.no) ]
|
||||
for vi, v in enumerate(f_v):
|
||||
file.write( ' %d/%d/%d' % (\
|
||||
v.index+totverts,\
|
||||
totuvco + uv_face_mapping[f_index][vi],\
|
||||
no)) # vert, uv, normal
|
||||
|
||||
else: # No Normals
|
||||
for vi, v in enumerate(f_v):
|
||||
file.write( ' %d/%d' % (\
|
||||
v.index+totverts,\
|
||||
totuvco + uv_face_mapping[f_index][vi])) # vert, uv
|
||||
|
||||
face_vert_index += len(f_v)
|
||||
|
||||
else: # No UV's
|
||||
if EXPORT_NORMALS:
|
||||
if f_smooth: # Smoothed, use vertex normals
|
||||
for v in f_v:
|
||||
file.write( ' %d//%d' % (\
|
||||
v.index+totverts,\
|
||||
globalNormals[ veckey3d(v.no) ]))
|
||||
else: # No smoothing, face normals
|
||||
no = globalNormals[ veckey3d(f.no) ]
|
||||
for v in f_v:
|
||||
file.write( ' %d//%d' % (\
|
||||
v.index+totverts,\
|
||||
no))
|
||||
else: # No Normals
|
||||
for v in f_v:
|
||||
file.write( ' %d' % (\
|
||||
v.index+totverts))
|
||||
|
||||
file.write('\n')
|
||||
|
||||
# Write edges.
|
||||
if EXPORT_EDGES:
|
||||
LOOSE= Mesh.EdgeFlags.LOOSE
|
||||
for ed in edges:
|
||||
if ed.flag & LOOSE:
|
||||
file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts))
|
||||
|
||||
# Make the indicies global rather then per mesh
|
||||
totverts += len(me.verts)
|
||||
if faceuv:
|
||||
totuvco += uv_unique_count
|
||||
me.verts= None
|
||||
file.close()
|
||||
|
||||
|
||||
# Now we have all our materials, save them
|
||||
if EXPORT_MTL:
|
||||
write_mtl(mtlfilename)
|
||||
if EXPORT_COPY_IMAGES:
|
||||
dest_dir = filename
|
||||
# Remove chars until we are just the path.
|
||||
while dest_dir and dest_dir[-1] not in '\\/':
|
||||
dest_dir = dest_dir[:-1]
|
||||
if dest_dir:
|
||||
copy_images(dest_dir)
|
||||
else:
|
||||
print '\tError: "%s" could not be used as a base for an image path.' % filename
|
||||
|
||||
print "OBJ Export time: %.2f" % (sys.time() - time1)
|
||||
|
||||
|
||||
|
||||
def write_ui(filename):
|
||||
|
||||
if not filename.lower().endswith('.obj'):
|
||||
filename += '.obj'
|
||||
|
||||
if not BPyMessages.Warning_SaveOver(filename):
|
||||
return
|
||||
|
||||
global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\
|
||||
EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\
|
||||
EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\
|
||||
EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\
|
||||
EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
|
||||
EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS
|
||||
|
||||
EXPORT_APPLY_MODIFIERS = Draw.Create(0)
|
||||
EXPORT_ROTX90 = Draw.Create(1)
|
||||
EXPORT_TRI = Draw.Create(0)
|
||||
EXPORT_EDGES = Draw.Create(1)
|
||||
EXPORT_NORMALS = Draw.Create(0)
|
||||
EXPORT_NORMALS_HQ = Draw.Create(0)
|
||||
EXPORT_UV = Draw.Create(1)
|
||||
EXPORT_MTL = Draw.Create(1)
|
||||
EXPORT_SEL_ONLY = Draw.Create(1)
|
||||
EXPORT_ALL_SCENES = Draw.Create(0)
|
||||
EXPORT_ANIMATION = Draw.Create(0)
|
||||
EXPORT_COPY_IMAGES = Draw.Create(0)
|
||||
EXPORT_BLEN_OBS = Draw.Create(0)
|
||||
EXPORT_GROUP_BY_OB = Draw.Create(0)
|
||||
EXPORT_GROUP_BY_MAT = Draw.Create(0)
|
||||
EXPORT_KEEP_VERT_ORDER = Draw.Create(1)
|
||||
EXPORT_POLYGROUPS = Draw.Create(0)
|
||||
EXPORT_CURVE_AS_NURBS = Draw.Create(1)
|
||||
|
||||
|
||||
# Old UI
|
||||
'''
|
||||
# removed too many options are bad!
|
||||
|
||||
# Get USER Options
|
||||
pup_block = [\
|
||||
('Context...'),\
|
||||
('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\
|
||||
('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\
|
||||
('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\
|
||||
('Object Prefs...'),\
|
||||
('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\
|
||||
('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\
|
||||
('Keep Vert Order', EXPORT_KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
|
||||
('Extra Data...'),\
|
||||
('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\
|
||||
('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\
|
||||
('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\
|
||||
('UVs', EXPORT_UV, 'Export texface UV coords.'),\
|
||||
('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\
|
||||
('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\
|
||||
('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\
|
||||
('Grouping...'),\
|
||||
('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\
|
||||
('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\
|
||||
('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\
|
||||
]
|
||||
|
||||
if not Draw.PupBlock('Export...', pup_block):
|
||||
return
|
||||
'''
|
||||
|
||||
# BEGIN ALTERNATIVE UI *******************
|
||||
if True:
|
||||
|
||||
EVENT_NONE = 0
|
||||
EVENT_EXIT = 1
|
||||
EVENT_REDRAW = 2
|
||||
EVENT_EXPORT = 3
|
||||
|
||||
GLOBALS = {}
|
||||
GLOBALS['EVENT'] = EVENT_REDRAW
|
||||
#GLOBALS['MOUSE'] = Window.GetMouseCoords()
|
||||
GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()]
|
||||
|
||||
def obj_ui_set_event(e,v):
|
||||
GLOBALS['EVENT'] = e
|
||||
|
||||
def do_split(e,v):
|
||||
global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER, EXPORT_POLYGROUPS
|
||||
if EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val:
|
||||
EXPORT_KEEP_VERT_ORDER.val = 0
|
||||
else:
|
||||
EXPORT_KEEP_VERT_ORDER.val = 1
|
||||
|
||||
def do_vertorder(e,v):
|
||||
global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER
|
||||
if EXPORT_KEEP_VERT_ORDER.val:
|
||||
EXPORT_BLEN_OBS.val = EXPORT_GROUP_BY_OB.val = EXPORT_GROUP_BY_MAT.val = EXPORT_APPLY_MODIFIERS.val = 0
|
||||
else:
|
||||
if not (EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val):
|
||||
EXPORT_KEEP_VERT_ORDER.val = 1
|
||||
|
||||
|
||||
def do_help(e,v):
|
||||
url = __url__[0]
|
||||
print 'Trying to open web browser with documentation at this address...'
|
||||
print '\t' + url
|
||||
|
||||
try:
|
||||
import webbrowser
|
||||
webbrowser.open(url)
|
||||
except:
|
||||
print '...could not open a browser window.'
|
||||
|
||||
def obj_ui():
|
||||
ui_x, ui_y = GLOBALS['MOUSE']
|
||||
|
||||
# Center based on overall pup size
|
||||
ui_x -= 165
|
||||
ui_y -= 140
|
||||
|
||||
global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\
|
||||
EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\
|
||||
EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\
|
||||
EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\
|
||||
EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
|
||||
EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS
|
||||
|
||||
Draw.Label('Context...', ui_x+9, ui_y+239, 220, 20)
|
||||
Draw.BeginAlign()
|
||||
EXPORT_SEL_ONLY = Draw.Toggle('Selection Only', EVENT_NONE, ui_x+9, ui_y+219, 110, 20, EXPORT_SEL_ONLY.val, 'Only export objects in visible selection. Else export whole scene.')
|
||||
EXPORT_ALL_SCENES = Draw.Toggle('All Scenes', EVENT_NONE, ui_x+119, ui_y+219, 110, 20, EXPORT_ALL_SCENES.val, 'Each scene as a separate OBJ file.')
|
||||
EXPORT_ANIMATION = Draw.Toggle('Animation', EVENT_NONE, ui_x+229, ui_y+219, 110, 20, EXPORT_ANIMATION.val, 'Each frame as a numbered OBJ file.')
|
||||
Draw.EndAlign()
|
||||
|
||||
|
||||
Draw.Label('Output Options...', ui_x+9, ui_y+189, 220, 20)
|
||||
Draw.BeginAlign()
|
||||
EXPORT_APPLY_MODIFIERS = Draw.Toggle('Apply Modifiers', EVENT_REDRAW, ui_x+9, ui_y+170, 110, 20, EXPORT_APPLY_MODIFIERS.val, 'Use transformed mesh data from each object. May break vert order for morph targets.', do_split)
|
||||
EXPORT_ROTX90 = Draw.Toggle('Rotate X90', EVENT_NONE, ui_x+119, ui_y+170, 110, 20, EXPORT_ROTX90.val, 'Rotate on export so Blenders UP is translated into OBJs UP')
|
||||
EXPORT_COPY_IMAGES = Draw.Toggle('Copy Images', EVENT_NONE, ui_x+229, ui_y+170, 110, 20, EXPORT_COPY_IMAGES.val, 'Copy image files to the export directory, never overwrite.')
|
||||
Draw.EndAlign()
|
||||
|
||||
|
||||
Draw.Label('Export...', ui_x+9, ui_y+139, 220, 20)
|
||||
Draw.BeginAlign()
|
||||
EXPORT_EDGES = Draw.Toggle('Edges', EVENT_NONE, ui_x+9, ui_y+120, 50, 20, EXPORT_EDGES.val, 'Edges not connected to faces.')
|
||||
EXPORT_TRI = Draw.Toggle('Triangulate', EVENT_NONE, ui_x+59, ui_y+120, 70, 20, EXPORT_TRI.val, 'Triangulate quads.')
|
||||
Draw.EndAlign()
|
||||
Draw.BeginAlign()
|
||||
EXPORT_MTL = Draw.Toggle('Materials', EVENT_NONE, ui_x+139, ui_y+120, 70, 20, EXPORT_MTL.val, 'Write a separate MTL file with the OBJ.')
|
||||
EXPORT_UV = Draw.Toggle('UVs', EVENT_NONE, ui_x+209, ui_y+120, 31, 20, EXPORT_UV.val, 'Export texface UV coords.')
|
||||
Draw.EndAlign()
|
||||
Draw.BeginAlign()
|
||||
EXPORT_NORMALS = Draw.Toggle('Normals', EVENT_NONE, ui_x+250, ui_y+120, 59, 20, EXPORT_NORMALS.val, 'Export vertex normal data (Ignored on import).')
|
||||
EXPORT_NORMALS_HQ = Draw.Toggle('HQ', EVENT_NONE, ui_x+309, ui_y+120, 31, 20, EXPORT_NORMALS_HQ.val, 'Calculate high quality normals for rendering.')
|
||||
Draw.EndAlign()
|
||||
EXPORT_POLYGROUPS = Draw.Toggle('Polygroups', EVENT_REDRAW, ui_x+9, ui_y+95, 120, 20, EXPORT_POLYGROUPS.val, 'Export vertex groups as OBJ groups (one group per face approximation).')
|
||||
|
||||
EXPORT_CURVE_AS_NURBS = Draw.Toggle('Nurbs', EVENT_NONE, ui_x+139, ui_y+95, 100, 20, EXPORT_CURVE_AS_NURBS.val, 'Export 3D nurbs curves and polylines as OBJ curves, (bezier not supported).')
|
||||
|
||||
|
||||
Draw.Label('Blender Objects as OBJ:', ui_x+9, ui_y+59, 220, 20)
|
||||
Draw.BeginAlign()
|
||||
EXPORT_BLEN_OBS = Draw.Toggle('Objects', EVENT_REDRAW, ui_x+9, ui_y+39, 60, 20, EXPORT_BLEN_OBS.val, 'Export blender objects as "OBJ objects".', do_split)
|
||||
EXPORT_GROUP_BY_OB = Draw.Toggle('Groups', EVENT_REDRAW, ui_x+69, ui_y+39, 60, 20, EXPORT_GROUP_BY_OB.val, 'Export blender objects as "OBJ Groups".', do_split)
|
||||
EXPORT_GROUP_BY_MAT = Draw.Toggle('Material Groups', EVENT_REDRAW, ui_x+129, ui_y+39, 100, 20, EXPORT_GROUP_BY_MAT.val, 'Group by materials.', do_split)
|
||||
Draw.EndAlign()
|
||||
|
||||
EXPORT_KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+239, ui_y+39, 100, 20, EXPORT_KEEP_VERT_ORDER.val, 'Keep vert and face order, disables some other options. Use for morph targets.', do_vertorder)
|
||||
|
||||
Draw.BeginAlign()
|
||||
Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 20, 'Load the wiki page for this script', do_help)
|
||||
Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 20, '', obj_ui_set_event)
|
||||
Draw.PushButton('Export', EVENT_EXPORT, ui_x+229, ui_y+9, 110, 20, 'Export with these settings', obj_ui_set_event)
|
||||
Draw.EndAlign()
|
||||
|
||||
|
||||
# hack so the toggle buttons redraw. this is not nice at all
|
||||
while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_EXPORT):
|
||||
Draw.UIBlock(obj_ui, 0)
|
||||
|
||||
if GLOBALS['EVENT'] != EVENT_EXPORT:
|
||||
return
|
||||
|
||||
# END ALTERNATIVE UI *********************
|
||||
|
||||
|
||||
if EXPORT_KEEP_VERT_ORDER.val:
|
||||
EXPORT_BLEN_OBS.val = False
|
||||
EXPORT_GROUP_BY_OB.val = False
|
||||
EXPORT_GROUP_BY_MAT.val = False
|
||||
EXPORT_APPLY_MODIFIERS.val = False
|
||||
|
||||
Window.EditMode(0)
|
||||
Window.WaitCursor(1)
|
||||
|
||||
EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
|
||||
EXPORT_ROTX90 = EXPORT_ROTX90.val
|
||||
EXPORT_TRI = EXPORT_TRI.val
|
||||
EXPORT_EDGES = EXPORT_EDGES.val
|
||||
EXPORT_NORMALS = EXPORT_NORMALS.val
|
||||
EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val
|
||||
EXPORT_UV = EXPORT_UV.val
|
||||
EXPORT_MTL = EXPORT_MTL.val
|
||||
EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val
|
||||
EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val
|
||||
EXPORT_ANIMATION = EXPORT_ANIMATION.val
|
||||
EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val
|
||||
EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val
|
||||
EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val
|
||||
EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val
|
||||
EXPORT_KEEP_VERT_ORDER = EXPORT_KEEP_VERT_ORDER.val
|
||||
EXPORT_POLYGROUPS = EXPORT_POLYGROUPS.val
|
||||
EXPORT_CURVE_AS_NURBS = EXPORT_CURVE_AS_NURBS.val
|
||||
|
||||
|
||||
base_name, ext = splitExt(filename)
|
||||
context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension
|
||||
|
||||
# Use the options to export the data using write()
|
||||
# def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True):
|
||||
orig_scene = Scene.GetCurrent()
|
||||
if EXPORT_ALL_SCENES:
|
||||
export_scenes = Scene.Get()
|
||||
else:
|
||||
export_scenes = [orig_scene]
|
||||
|
||||
# Export all scenes.
|
||||
for scn in export_scenes:
|
||||
scn.makeCurrent() # If alredy current, this is not slow.
|
||||
context = scn.getRenderingContext()
|
||||
orig_frame = Blender.Get('curframe')
|
||||
|
||||
if EXPORT_ALL_SCENES: # Add scene name into the context_name
|
||||
context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
|
||||
|
||||
# Export an animation?
|
||||
if EXPORT_ANIMATION:
|
||||
scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame.
|
||||
else:
|
||||
scene_frames = [orig_frame] # Dont export an animation.
|
||||
|
||||
# Loop through all frames in the scene and export.
|
||||
for frame in scene_frames:
|
||||
if EXPORT_ANIMATION: # Add frame to the filename.
|
||||
context_name[2] = '_%.6d' % frame
|
||||
|
||||
Blender.Set('curframe', frame)
|
||||
if EXPORT_SEL_ONLY:
|
||||
export_objects = scn.objects.context
|
||||
else:
|
||||
export_objects = scn.objects
|
||||
|
||||
full_path= ''.join(context_name)
|
||||
|
||||
# erm... bit of a problem here, this can overwrite files when exporting frames. not too bad.
|
||||
# EXPORT THE FILE.
|
||||
write(full_path, export_objects,\
|
||||
EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
|
||||
EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\
|
||||
EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\
|
||||
EXPORT_ROTX90, EXPORT_BLEN_OBS,\
|
||||
EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
|
||||
EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS)
|
||||
|
||||
Blender.Set('curframe', orig_frame)
|
||||
|
||||
# Restore old active scene.
|
||||
orig_scene.makeCurrent()
|
||||
Window.WaitCursor(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj'))
|
||||
@@ -1,111 +0,0 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Same Weights...'
|
||||
Blender: 245
|
||||
Group: 'FaceSelect'
|
||||
Tooltip: 'Select same faces with teh same weight for the active group.'
|
||||
"""
|
||||
|
||||
__author__ = ["Campbell Barton aka ideasman42"]
|
||||
__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"]
|
||||
__version__ = "0.1"
|
||||
__bpydoc__ = """\
|
||||
|
||||
Select Same Weights
|
||||
|
||||
Select same weights as the active face on the active group.
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) Campbell J Barton
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
from Blender import Scene, Draw, Mesh
|
||||
import BPyMesh
|
||||
|
||||
def selSameWeights(me, PREF_TOLERENCE):
|
||||
|
||||
# Check for missing data
|
||||
if not me.faceUV: return
|
||||
|
||||
act_group= me.activeGroup
|
||||
if not act_group: return
|
||||
|
||||
act_face = me.faces[me.activeFace]
|
||||
if act_face == None: return
|
||||
|
||||
|
||||
|
||||
groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
|
||||
|
||||
def get_face_weight(f):
|
||||
'''
|
||||
Return the faces median weight and weight range.
|
||||
'''
|
||||
wmin = 1.0
|
||||
wmax = 0.0
|
||||
w = 0.0
|
||||
for v in f:
|
||||
try:
|
||||
new_weight = vWeightDict[v.index][act_group]
|
||||
if wmin > new_weight: wmin = new_weight
|
||||
if wmax < new_weight: wmax = new_weight
|
||||
w += new_weight
|
||||
except:
|
||||
pass
|
||||
return w, wmax-wmin # weight, range
|
||||
|
||||
weight_from, weight_range_from = get_face_weight(act_face)
|
||||
for f in me.faces:
|
||||
if (not f.sel) and f != act_face:
|
||||
weight, weight_range = get_face_weight(f)
|
||||
|
||||
# Compare the 2 faces weight difference and difference in their contrast.
|
||||
if\
|
||||
abs(weight - weight_from) <= PREF_TOLERENCE and\
|
||||
abs(weight_range - weight_range_from) <= PREF_TOLERENCE:
|
||||
f.sel = True
|
||||
|
||||
|
||||
def main():
|
||||
scn= Scene.GetCurrent()
|
||||
ob= scn.objects.active
|
||||
|
||||
if not ob or ob.type != 'Mesh':
|
||||
Draw.PupMenu('Error, no active mesh object, aborting.')
|
||||
return
|
||||
|
||||
me= ob.getData(mesh=1)
|
||||
|
||||
PREF_TOLERENCE= Draw.Create(0.1)
|
||||
|
||||
pup_block= [\
|
||||
('Tolerence:', PREF_TOLERENCE, 0.01, 1.0, 'Tolerence for selecting faces of the same weight.'),\
|
||||
]
|
||||
|
||||
if not Draw.PupBlock('Select Same Weight...', pup_block):
|
||||
return
|
||||
|
||||
PREF_TOLERENCE= PREF_TOLERENCE.val
|
||||
|
||||
selSameWeights(me, PREF_TOLERENCE)
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
File diff suppressed because one or more lines are too long
@@ -1,835 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'FLT DOF Editor'
|
||||
Blender: 240
|
||||
Group: 'Misc'
|
||||
Tooltip: 'Degree of Freedom editor for FLT nodes'
|
||||
"""
|
||||
|
||||
__author__ = "Geoffrey Bantle"
|
||||
__version__ = "1.0 11/21/07"
|
||||
__email__ = ('scripts', 'Author, ')
|
||||
__url__ = ('blender', 'blenderartists.org')
|
||||
|
||||
__bpydoc__ ="""\
|
||||
This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a
|
||||
registered trademark of MultiGen-Paradigm, Inc.
|
||||
|
||||
Feature overview and more availible at:
|
||||
http://wiki.blender.org/index.php/Scripts/Manual/FLTools
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# flt_palettemanager.py version 0.1 2005/04/08
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2007: Blender Foundation
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender.Draw as Draw
|
||||
from Blender.BGL import *
|
||||
import Blender
|
||||
import flt_properties
|
||||
reload(flt_properties)
|
||||
from flt_properties import *
|
||||
|
||||
#event codes
|
||||
evcode = {
|
||||
"DOF_MAKE" : 100,
|
||||
"DOF_UPDATE" : 138,
|
||||
"DOF_DELETE" : 101,
|
||||
"DOF_TRANSX" : 102,
|
||||
"DOF_TRANSY" : 103,
|
||||
"DOF_TRANSZ" : 104,
|
||||
"DOF_ROTX" : 105,
|
||||
"DOF_ROTY" : 106,
|
||||
"DOF_ROTZ" : 107,
|
||||
"DOF_SCALEX" : 108,
|
||||
"DOF_SCALEY" : 109,
|
||||
"DOF_SCALEZ" : 110,
|
||||
"DOF_MIN_TRANSX" : 111,
|
||||
"DOF_MIN_TRANSY" : 112,
|
||||
"DOF_MIN_TRANSZ" : 113,
|
||||
"DOF_MIN_ROTX" : 114,
|
||||
"DOF_MIN_ROTY" : 115,
|
||||
"DOF_MIN_ROTZ" : 116,
|
||||
"DOF_MIN_SCALEX" : 117,
|
||||
"DOF_MIN_SCALEY" : 118,
|
||||
"DOF_MIN_SCALEZ" : 119,
|
||||
"DOF_MAX_TRANSX" : 120,
|
||||
"DOF_MAX_TRANSY" : 121,
|
||||
"DOF_MAX_TRANSZ" : 122,
|
||||
"DOF_MAX_ROTX" : 123,
|
||||
"DOF_MAX_ROTY" : 124,
|
||||
"DOF_MAX_ROTZ" : 125,
|
||||
"DOF_MAX_SCALEX" : 126,
|
||||
"DOF_MAX_SCALEY" : 127,
|
||||
"DOF_MAX_SCALEZ" : 128,
|
||||
"DOF_STEP_TRANSX" : 129,
|
||||
"DOF_STEP_TRANSY" : 130,
|
||||
"DOF_STEP_TRANSZ" : 131,
|
||||
"DOF_STEP_ROTX" : 132,
|
||||
"DOF_STEP_ROTY" : 133,
|
||||
"DOF_STEP_ROTZ" : 134,
|
||||
"DOF_STEP_SCALEX" : 135,
|
||||
"DOF_STEP_SCALEY" : 136,
|
||||
"DOF_STEP_SCALEZ" : 137
|
||||
}
|
||||
|
||||
#system
|
||||
DOF_MAKE = None
|
||||
DOF_UPDATE = None
|
||||
DOF_DELETE = None
|
||||
|
||||
#toggle buttons
|
||||
DOF_TRANSX = None
|
||||
DOF_TRANSY = None
|
||||
DOF_TRANSZ = None
|
||||
DOF_ROTX = None
|
||||
DOF_ROTY = None
|
||||
DOF_ROTZ = None
|
||||
DOF_SCALEX = None
|
||||
DOF_SCALEY = None
|
||||
DOF_SCALEZ = None
|
||||
|
||||
#Minimums
|
||||
DOF_MIN_TRANSX = None
|
||||
DOF_MIN_TRANSY = None
|
||||
DOF_MIN_TRANSZ = None
|
||||
DOF_MIN_ROTX = None
|
||||
DOF_MIN_ROTY = None
|
||||
DOF_MIN_ROTZ = None
|
||||
DOF_MIN_SCALEX = None
|
||||
DOF_MIN_SCALEY = None
|
||||
DOF_MIN_SCALEZ = None
|
||||
|
||||
#maximums
|
||||
DOF_MAX_TRANSX = None
|
||||
DOF_MAX_TRANSY = None
|
||||
DOF_MAX_TRANSZ = None
|
||||
DOF_MAX_ROTX = None
|
||||
DOF_MAX_ROTY = None
|
||||
DOF_MAX_ROTZ = None
|
||||
DOF_MAX_SCALEX = None
|
||||
DOF_MAX_SCALEY = None
|
||||
DOF_MAX_SCALEZ = None
|
||||
|
||||
#step
|
||||
DOF_STEP_TRANSX = None
|
||||
DOF_STEP_TRANSY = None
|
||||
DOF_STEP_TRANSZ = None
|
||||
DOF_STEP_ROTX = None
|
||||
DOF_STEP_ROTY = None
|
||||
DOF_STEP_ROTZ = None
|
||||
DOF_STEP_SCALEX = None
|
||||
DOF_STEP_SCALEY = None
|
||||
DOF_STEP_SCALEZ = None
|
||||
|
||||
#labels
|
||||
DOF_ROTSTRING = None
|
||||
DOF_TRANSTRING = None
|
||||
DOF_SCALESTRING = None
|
||||
DOF_EDITLABEL = None
|
||||
|
||||
#make ID props easier/morereadable
|
||||
zmin = '14d!ZMIN'
|
||||
zmax = '15d!ZMAX'
|
||||
zcur = '16d!ZCUR'
|
||||
zstep = '17d!ZSTEP'
|
||||
ymin = '18d!YMIN'
|
||||
ymax = '19d!YMAX'
|
||||
ycur = '20d!YCUR'
|
||||
ystep = '21d!YSTEP'
|
||||
xmin = '22d!XMIN'
|
||||
xmax = '23d!XMAX'
|
||||
xcur = '24d!XCUR'
|
||||
xstep = '25d!XSTEP'
|
||||
pitchmin = '26d!PITCH-MIN'
|
||||
pitchmax = '27d!PITCH-MAX'
|
||||
pitchcur = '28d!PITCH-CUR'
|
||||
pitchstep = '29d!PITCH-STEP'
|
||||
rollmin = '30d!ROLL-MIN'
|
||||
rollmax = '31d!ROLL-MAX'
|
||||
rollcur = '32d!ROLL-CUR'
|
||||
rollstep = '33d!ROLL-STEP'
|
||||
yawmin = '34d!YAW-MIN'
|
||||
yawmax = '35d!YAW-MAX'
|
||||
yawcur = '36d!YAW-CUR'
|
||||
yawstep = '37d!YAW-STEP'
|
||||
zscalemin = '38d!ZSIZE-MIN'
|
||||
zscalemax = '39d!ZSIZE-MAX'
|
||||
zscalecur = '40d!ZSIZE-CUR'
|
||||
zscalestep = '41d!ZSIZE-STEP'
|
||||
yscalemin = '42d!YSIZE-MIN'
|
||||
yscalemax = '43d!YSIZE-MAX'
|
||||
yscalecur = '44d!YSIZE-CUR'
|
||||
yscalestep = '45d!YSIZE-STEP'
|
||||
xscalemin = '46d!XSIZE-MIN'
|
||||
xscalemax = '47d!XSIZE-MAX'
|
||||
xscalecur = '48d!XSIZE-CUR'
|
||||
xscalestep = '49d!XSIZE-STEP'
|
||||
|
||||
|
||||
|
||||
def update_state():
|
||||
state = dict()
|
||||
state["activeScene"] = Blender.Scene.GetCurrent()
|
||||
state["activeObject"] = state["activeScene"].objects.active
|
||||
if state["activeObject"] and not state["activeObject"].sel:
|
||||
state["activeObject"] = None
|
||||
state["activeMesh"] = None
|
||||
if state["activeObject"] and state["activeObject"].type == 'Mesh':
|
||||
state["activeMesh"] = state["activeObject"].getData(mesh=True)
|
||||
|
||||
|
||||
state["activeFace"] = None
|
||||
if state["activeMesh"]:
|
||||
if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None:
|
||||
state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace]
|
||||
|
||||
|
||||
#update editmode
|
||||
state["editmode"] = Blender.Window.EditMode()
|
||||
|
||||
return state
|
||||
|
||||
def idprops_append(object, typecode, props):
|
||||
object.properties["FLT"] = dict()
|
||||
object.properties["FLT"]['type'] = typecode
|
||||
for prop in props:
|
||||
object.properties["FLT"][prop] = props[prop]
|
||||
object.properties["FLT"]['3t8!id'] = object.name
|
||||
|
||||
def idprops_kill():
|
||||
state = update_state()
|
||||
if state["activeObject"] and state["activeObject"].properties.has_key('FLT'):
|
||||
state["activeObject"].properties.pop('FLT')
|
||||
|
||||
def idprops_copy(source):
|
||||
state = update_state()
|
||||
if source.properties.has_key('FLT'):
|
||||
for object in state["activeScene"].objects:
|
||||
if object.sel and object != source and (state["activeScene"].Layers & object.Layers):
|
||||
idprops_kill(object)
|
||||
object.properties['FLT'] = dict()
|
||||
for key in source.properties['FLT']:
|
||||
object.properties['FLT'][key] = source.properties['FLT'][key]
|
||||
|
||||
def select_by_typecode(typecode):
|
||||
state = update_state()
|
||||
|
||||
for object in state["activeScene"].objects:
|
||||
if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers:
|
||||
object.select(1)
|
||||
|
||||
def DOF_get_frame():
|
||||
state = update_state()
|
||||
|
||||
if not state["activeObject"] and not id_props_type(state["activeObject"], 14):
|
||||
return
|
||||
|
||||
#Warning! assumes 1 BU == 10 meters.
|
||||
#do origin
|
||||
state["activeObject"].properties['FLT']['5d!ORIGX'] = state["activeObject"].getLocation('worldspace')[0]*10.0
|
||||
state["activeObject"].properties['FLT']['6d!ORIGY'] = state["activeObject"].getLocation('worldspace')[1]*10.0
|
||||
state["activeObject"].properties['FLT']['7d!ORIGZ'] = state["activeObject"].getLocation('worldspace')[2]*10.0
|
||||
#do X axis
|
||||
x = Blender.Mathutils.Vector(1.0,0.0,0.0)
|
||||
x = x * state["activeObject"].getMatrix('worldspace')
|
||||
x = x * 10.0
|
||||
state["activeObject"].properties['FLT']['8d!XAXIS-X'] = x[0]
|
||||
state["activeObject"].properties['FLT']['9d!XAXIS-Y'] = x[1]
|
||||
state["activeObject"].properties['FLT']['10d!XAXIS-Z'] = x[2]
|
||||
#do X/Y plane
|
||||
x = Blender.Mathutils.Vector(0.0,1.0,0.0)
|
||||
x.normalize()
|
||||
x = x * state["activeObject"].getMatrix('worldspace')
|
||||
x = x * 10.0
|
||||
state["activeObject"].properties['FLT']['11d!XYPLANE-X'] = x[0]
|
||||
state["activeObject"].properties['FLT']['12d!XYPLANE-Y'] = x[1]
|
||||
state["activeObject"].properties['FLT']['13d!XZPLANE-Z'] = x[2]
|
||||
|
||||
def idprops_type(object, typecode):
|
||||
if object.properties.has_key('FLT') and object.properties['FLT'].has_key('type') and object.properties['FLT']['type'] == typecode:
|
||||
return True
|
||||
return False
|
||||
|
||||
#ui type code
|
||||
def get_prop(typecode, prop):
|
||||
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], typecode):
|
||||
props = state["activeObject"].properties['FLT']
|
||||
else:
|
||||
props = flt_properties.FLTDOF
|
||||
|
||||
return props[prop]
|
||||
|
||||
def set_prop(typecode, prop, value):
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"],typecode):
|
||||
state["activeObject"].properties['FLT'][prop] = value
|
||||
|
||||
lockxtrans = (1 << 31)
|
||||
lockytrans = (1 << 30)
|
||||
lockztrans = (1 << 29)
|
||||
lockxrot = (1 << 28)
|
||||
lockyrot = (1 << 27)
|
||||
lockzrot = (1 << 26)
|
||||
lockxscale = (1 << 25)
|
||||
lockyscale = (1 << 24)
|
||||
lockzscale = (1 << 23)
|
||||
|
||||
def get_lockmask(mask):
|
||||
state = update_state()
|
||||
if state["activeObject"]:
|
||||
flag = get_prop(14,'50I!FLAG')
|
||||
if flag & mask:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_lockmask(mask):
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], 14):
|
||||
oldvalue = state["activeObject"].properties['FLT']['50I!FLAG']
|
||||
oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0]
|
||||
oldvalue |= mask
|
||||
state["activeObject"].properties['FLT']['50I!FLAG'] = struct.unpack('>i', struct.pack(">I", oldvalue))[0]
|
||||
|
||||
def clear_lockmask(mask):
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], 14):
|
||||
oldvalue = state["activeObject"].properties['FLT']['50I!FLAG']
|
||||
oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0]
|
||||
oldvalue &= ~mask
|
||||
state["activeObject"].properties['FLT']['50I!FLAG'] = struct.unpack('>i',struct.pack('>I',oldvalue))[0]
|
||||
|
||||
|
||||
def create_dof():
|
||||
state = update_state()
|
||||
actobj = state["activeObject"]
|
||||
if actobj and not idprops_type(actobj, 14):
|
||||
idprops_kill()
|
||||
idprops_append(actobj,14, flt_properties.FLTDOF)
|
||||
DOF_get_frame()
|
||||
|
||||
|
||||
def event(evt,val):
|
||||
if evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
|
||||
def but_event(evt):
|
||||
global DOF_MAKE
|
||||
global DOF_UPDATE
|
||||
global DOF_DELETE
|
||||
|
||||
global DOF_TRANSX
|
||||
global DOF_TRANSY
|
||||
global DOF_TRANSZ
|
||||
global DOF_ROTX
|
||||
global DOF_ROTY
|
||||
global DOF_ROTZ
|
||||
global DOF_SCALEX
|
||||
global DOF_SCALEY
|
||||
global DOF_SCALEZ
|
||||
|
||||
global DOF_MIN_TRANSX
|
||||
global DOF_MIN_TRANSY
|
||||
global DOF_MIN_TRANSZ
|
||||
global DOF_MIN_ROTX
|
||||
global DOF_MIN_ROTY
|
||||
global DOF_MIN_ROTZ
|
||||
global DOF_MIN_SCALEX
|
||||
global DOF_MIN_SCALEY
|
||||
global DOF_MIN_SCALEZ
|
||||
|
||||
global DOF_MAX_TRANSX
|
||||
global DOF_MAX_TRANSY
|
||||
global DOF_MAX_TRANSZ
|
||||
global DOF_MAX_ROTX
|
||||
global DOF_MAX_ROTY
|
||||
global DOF_MAX_ROTZ
|
||||
global DOF_MAX_SCALEX
|
||||
global DOF_MAX_SCALEY
|
||||
global DOF_MAX_SCALEZ
|
||||
|
||||
global DOF_STEP_TRANSX
|
||||
global DOF_STEP_TRANSY
|
||||
global DOF_STEP_TRANSZ
|
||||
global DOF_STEP_ROTX
|
||||
global DOF_STEP_ROTY
|
||||
global DOF_STEP_ROTZ
|
||||
global DOF_STEP_SCALEX
|
||||
global DOF_STEP_SCALEY
|
||||
global DOF_STEP_SCALEZ
|
||||
|
||||
#labels
|
||||
global DOF_ROTSTRING
|
||||
global DOF_TRANSTRING
|
||||
global DOF_SCALESTRING
|
||||
|
||||
|
||||
#masks
|
||||
global lockxtrans
|
||||
global lockytrans
|
||||
global lockztrans
|
||||
global lockxrot
|
||||
global lockyrot
|
||||
global lockzrot
|
||||
global lockxscale
|
||||
global lockyscale
|
||||
global lockzscale
|
||||
|
||||
global zmin
|
||||
global zmax
|
||||
global zcur
|
||||
global zstep
|
||||
global ymin
|
||||
global ymax
|
||||
global ycur
|
||||
global ystep
|
||||
global xmin
|
||||
global xmax
|
||||
global xcur
|
||||
global xstep
|
||||
global pitchmin
|
||||
global pitchmax
|
||||
global pitchcur
|
||||
global pitchstep
|
||||
global rollmin
|
||||
global rollmax
|
||||
global rollcur
|
||||
global rollstep
|
||||
global yawmin
|
||||
global yawmax
|
||||
global yawcur
|
||||
global yawstep
|
||||
global zscalemin
|
||||
global zscalemax
|
||||
global zscalecur
|
||||
global zscalestep
|
||||
global yscalemin
|
||||
global yscalemax
|
||||
global yscalecur
|
||||
global yscalestep
|
||||
global xscalemin
|
||||
global xscalemax
|
||||
global xscalecur
|
||||
global xscalestep
|
||||
|
||||
|
||||
|
||||
#do "system" events
|
||||
if evt == evcode["DOF_MAKE"]:
|
||||
create_dof()
|
||||
|
||||
if evt == evcode["DOF_UPDATE"]:
|
||||
DOF_get_frame()
|
||||
|
||||
if evt == evcode["DOF_DELETE"]:
|
||||
idprops_kill()
|
||||
#do translation lock events
|
||||
if evt == evcode["DOF_TRANSX"]:
|
||||
if DOF_TRANSX.val == True:
|
||||
set_lockmask(lockxtrans)
|
||||
else:
|
||||
clear_lockmask(lockxtrans)
|
||||
|
||||
if evt == evcode["DOF_TRANSY"]:
|
||||
if DOF_TRANSY.val == True:
|
||||
set_lockmask(lockytrans)
|
||||
else:
|
||||
clear_lockmask(lockytrans)
|
||||
|
||||
if evt == evcode["DOF_TRANSZ"]:
|
||||
if DOF_TRANSZ.val == True:
|
||||
set_lockmask(lockztrans)
|
||||
else:
|
||||
clear_lockmask(lockztrans)
|
||||
|
||||
|
||||
#do rotation lock events
|
||||
if evt == evcode["DOF_ROTX"]:
|
||||
if DOF_ROTX.val == True:
|
||||
set_lockmask(lockxrot)
|
||||
else:
|
||||
clear_lockmask(lockxrot)
|
||||
|
||||
if evt == evcode["DOF_ROTY"]:
|
||||
if DOF_ROTY.val == True:
|
||||
set_lockmask(lockyrot)
|
||||
else:
|
||||
clear_lockmask(lockyrot)
|
||||
|
||||
if evt == evcode["DOF_ROTZ"]:
|
||||
if DOF_ROTZ.val == True:
|
||||
set_lockmask(lockzrot)
|
||||
else:
|
||||
clear_lockmask(lockzrot)
|
||||
|
||||
#do scale lock events
|
||||
if evt == evcode["DOF_SCALEX"]:
|
||||
if DOF_SCALEX.val == True:
|
||||
set_lockmask(lockxscale)
|
||||
else:
|
||||
clear_lockmask(lockxscale)
|
||||
|
||||
if evt == evcode["DOF_SCALEY"]:
|
||||
if DOF_SCALEY.val == True:
|
||||
set_lockmask(lockyscale)
|
||||
else:
|
||||
clear_lockmask(lockyscale)
|
||||
|
||||
if evt == evcode["DOF_SCALEZ"]:
|
||||
if DOF_SCALEZ.val == True:
|
||||
set_lockmask(lockzscale)
|
||||
else:
|
||||
clear_lockmask(lockzscale)
|
||||
|
||||
|
||||
#do translation buttons
|
||||
if evt == evcode["DOF_MIN_TRANSX"]:
|
||||
set_prop(14, xmin, DOF_MIN_TRANSX.val)
|
||||
if evt == evcode["DOF_MAX_TRANSX"]:
|
||||
set_prop(14,xmax, DOF_MAX_TRANSX.val)
|
||||
if evt == evcode["DOF_STEP_TRANSX"]:
|
||||
set_prop(14,xstep, DOF_STEP_TRANSX.val)
|
||||
|
||||
if evt == evcode["DOF_MIN_TRANSY"]:
|
||||
set_prop(14, ymin, DOF_MIN_TRANSY.val)
|
||||
if evt == evcode["DOF_MAX_TRANSY"]:
|
||||
set_prop(14,ymax, DOF_MAX_TRANSY.val)
|
||||
if evt == evcode["DOF_STEP_TRANSY"]:
|
||||
set_prop(14,ystep, DOF_STEP_TRANSY.val)
|
||||
|
||||
if evt == evcode["DOF_MIN_TRANSZ"]:
|
||||
set_prop(14, zmin, DOF_MIN_TRANSZ.val)
|
||||
if evt == evcode["DOF_MAX_TRANSZ"]:
|
||||
set_prop(14, zmax, DOF_MAX_TRANSZ.val)
|
||||
if evt == evcode["DOF_STEP_TRANSZ"]:
|
||||
set_prop(14, zstep, DOF_STEP_TRANSZ.val)
|
||||
|
||||
#do rotation buttons
|
||||
if evt == evcode["DOF_MIN_ROTX"]:
|
||||
set_prop(14, pitchmin, DOF_MIN_ROTX.val)
|
||||
if evt == evcode["DOF_MAX_ROTX"]:
|
||||
set_prop(14, pitchmax, DOF_MAX_ROTX.val)
|
||||
if evt == evcode["DOF_STEP_ROTX"]:
|
||||
set_prop(14, pitchstep, DOF_STEP_ROTX.val)
|
||||
|
||||
if evt == evcode["DOF_MIN_ROTY"]:
|
||||
set_prop(14, rollmin, DOF_MIN_ROTY.val)
|
||||
if evt == evcode["DOF_MAX_ROTY"]:
|
||||
set_prop(14, rollmax, DOF_MAX_ROTY.val)
|
||||
if evt == evcode["DOF_STEP_ROTY"]:
|
||||
set_prop(14, rollstep, DOF_STEP_ROTY.val)
|
||||
|
||||
if evt == evcode["DOF_MIN_ROTZ"]:
|
||||
set_prop(14, yawmin, DOF_MIN_ROTZ.val)
|
||||
if evt == evcode["DOF_MAX_ROTZ"]:
|
||||
set_prop(14, yawmax, DOF_MAX_ROTZ.val)
|
||||
if evt == evcode["DOF_STEP_ROTZ"]:
|
||||
set_prop(14, yawstep, DOF_STEP_ROTZ.val)
|
||||
|
||||
#do scale buttons
|
||||
if evt == evcode["DOF_MIN_SCALEX"]:
|
||||
set_prop(14, xscalemin, DOF_MIN_SCALEX.val)
|
||||
if evt == evcode["DOF_MAX_SCALEX"]:
|
||||
set_prop(14, xscalemax, DOF_MAX_SCALEX.val)
|
||||
if evt == evcode["DOF_STEP_SCALEX"]:
|
||||
set_prop(14, xscalestep, DOF_STEP_SCALEX.val)
|
||||
|
||||
if evt == evcode["DOF_MIN_SCALEY"]:
|
||||
set_prop(14, yscalemin, DOF_MIN_SCALEY.val)
|
||||
if evt == evcode["DOF_MAX_SCALEY"]:
|
||||
set_prop(14, yscalemax, DOF_MAX_SCALEY.val)
|
||||
if evt == evcode["DOF_STEP_SCALEY"]:
|
||||
set_prop(14, yscalestep, DOF_STEP_SCALEY.val)
|
||||
|
||||
if evt == evcode["DOF_MIN_SCALEZ"]:
|
||||
set_prop(14, zscalemin, DOF_MIN_SCALEZ.val)
|
||||
if evt == evcode["DOF_MAX_SCALEZ"]:
|
||||
set_prop(14, zscalemax, DOF_MAX_SCALEZ.val)
|
||||
if evt == evcode["DOF_STEP_SCALEZ"]:
|
||||
set_prop(14, zscalestep, DOF_STEP_SCALEZ.val)
|
||||
|
||||
|
||||
Draw.Redraw(1)
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
def draw_propsheet(x,y):
|
||||
#UI buttons
|
||||
global DOF_MAKE
|
||||
global DOF_UPDATE
|
||||
global DOF_DELETE
|
||||
|
||||
global DOF_TRANSX
|
||||
global DOF_TRANSY
|
||||
global DOF_TRANSZ
|
||||
global DOF_ROTX
|
||||
global DOF_ROTY
|
||||
global DOF_ROTZ
|
||||
global DOF_SCALEX
|
||||
global DOF_SCALEY
|
||||
global DOF_SCALEZ
|
||||
|
||||
global DOF_MIN_TRANSX
|
||||
global DOF_MIN_TRANSY
|
||||
global DOF_MIN_TRANSZ
|
||||
global DOF_MIN_ROTX
|
||||
global DOF_MIN_ROTY
|
||||
global DOF_MIN_ROTZ
|
||||
global DOF_MIN_SCALEX
|
||||
global DOF_MIN_SCALEY
|
||||
global DOF_MIN_SCALEZ
|
||||
|
||||
global DOF_MAX_TRANSX
|
||||
global DOF_MAX_TRANSY
|
||||
global DOF_MAX_TRANSZ
|
||||
global DOF_MAX_ROTX
|
||||
global DOF_MAX_ROTY
|
||||
global DOF_MAX_ROTZ
|
||||
global DOF_MAX_SCALEX
|
||||
global DOF_MAX_SCALEY
|
||||
global DOF_MAX_SCALEZ
|
||||
|
||||
global DOF_STEP_TRANSX
|
||||
global DOF_STEP_TRANSY
|
||||
global DOF_STEP_TRANSZ
|
||||
global DOF_STEP_ROTX
|
||||
global DOF_STEP_ROTY
|
||||
global DOF_STEP_ROTZ
|
||||
global DOF_STEP_SCALEX
|
||||
global DOF_STEP_SCALEY
|
||||
global DOF_STEP_SCALEZ
|
||||
|
||||
#labels
|
||||
global DOF_ROTSTRING
|
||||
global DOF_TRANSTRING
|
||||
global DOF_SCALESTRING
|
||||
global DOF_EDITLABEL
|
||||
|
||||
#masks
|
||||
global lockxtrans
|
||||
global lockytrans
|
||||
global lockztrans
|
||||
global lockxrot
|
||||
global lockyrot
|
||||
global lockzrot
|
||||
global lockxscale
|
||||
global lockyscale
|
||||
global lockzscale
|
||||
|
||||
global zmin
|
||||
global zmax
|
||||
global zcur
|
||||
global zstep
|
||||
global ymin
|
||||
global ymax
|
||||
global ycur
|
||||
global ystep
|
||||
global xmin
|
||||
global xmax
|
||||
global xcur
|
||||
global xstep
|
||||
global pitchmin
|
||||
global pitchmax
|
||||
global pitchcur
|
||||
global pitchstep
|
||||
global rollmin
|
||||
global rollmax
|
||||
global rollcur
|
||||
global rollstep
|
||||
global yawmin
|
||||
global yawmax
|
||||
global yawcur
|
||||
global yawstep
|
||||
global zscalemin
|
||||
global zscalemax
|
||||
global zscalecur
|
||||
global zscalestep
|
||||
global yscalemin
|
||||
global yscalemax
|
||||
global yscalecur
|
||||
global yscalestep
|
||||
global xscalemin
|
||||
global xscalemax
|
||||
global xscalecur
|
||||
global xscalestep
|
||||
|
||||
|
||||
global evcode
|
||||
|
||||
state = update_state()
|
||||
|
||||
row_height = 20
|
||||
toggle_width = 50
|
||||
input_width = 100
|
||||
pad = 10
|
||||
origx = x
|
||||
origy = (row_height * 15) + (pad * 15)
|
||||
|
||||
|
||||
#editor label
|
||||
x = origx
|
||||
y = origy
|
||||
#y = y - (row_height + pad)
|
||||
DOF_EDITLABEL = Blender.Draw.Label("FLT Degree of Freedom Editor", x, y, 200, row_height)
|
||||
|
||||
|
||||
#draw Translation limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_TRANSTRING = Blender.Draw.Label("Translation Limits", x, y, input_width, row_height)
|
||||
|
||||
|
||||
#X limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_TRANSX = Blender.Draw.Toggle("LimX", evcode["DOF_TRANSX"], x, y, toggle_width, row_height, get_lockmask(lockxtrans), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_TRANSX = Blender.Draw.Number("MinX", evcode["DOF_MIN_TRANSX"], x, y, input_width, row_height,get_prop(14,xmin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_TRANSX = Blender.Draw.Number("MaxX", evcode["DOF_MAX_TRANSX"], x, y, input_width, row_height,get_prop(14,xmax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_TRANSX = Blender.Draw.Number("StepX", evcode["DOF_STEP_TRANSX"], x, y, input_width, row_height,get_prop(14,xstep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#Y limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_TRANSY = Blender.Draw.Toggle("LimY", evcode["DOF_TRANSY"], x, y, toggle_width, row_height, get_lockmask(lockytrans), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_TRANSY = Blender.Draw.Number("MinY", evcode["DOF_MIN_TRANSY"], x, y, input_width, row_height, get_prop(14,ymin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_TRANSY = Blender.Draw.Number("MaxY", evcode["DOF_MAX_TRANSY"], x, y, input_width, row_height, get_prop(14,ymax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_TRANSY = Blender.Draw.Number("StepY", evcode["DOF_STEP_TRANSY"], x, y, input_width, row_height, get_prop(14,ystep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#Z limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_TRANSZ = Blender.Draw.Toggle("LimZ", evcode["DOF_TRANSZ"], x, y, toggle_width, row_height, get_lockmask(lockztrans), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_TRANSZ = Blender.Draw.Number("MinZ", evcode["DOF_MIN_TRANSZ"], x, y, input_width, row_height, get_prop(14,zmin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_TRANSZ = Blender.Draw.Number("MaxZ", evcode["DOF_MAX_TRANSZ"], x, y, input_width, row_height, get_prop(14,zmax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_TRANSZ = Blender.Draw.Number("StepZ", evcode["DOF_STEP_TRANSZ"], x, y, input_width, row_height, get_prop(14,zstep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#draw Rotation limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_ROTSTRING = Blender.Draw.Label("Rotation Limits", x, y, input_width, row_height)
|
||||
|
||||
#draw Rotation limits
|
||||
#X limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_ROTX = Blender.Draw.Toggle("LimX", evcode["DOF_ROTX"], x, y, toggle_width, row_height, get_lockmask(lockxrot), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_ROTX = Blender.Draw.Number("MinX", evcode["DOF_MIN_ROTX"], x, y, input_width, row_height, get_prop(14,pitchmin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_ROTX = Blender.Draw.Number("MaxX", evcode["DOF_MAX_ROTX"], x, y, input_width, row_height, get_prop(14,pitchmax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_ROTX = Blender.Draw.Number("StepX", evcode["DOF_STEP_ROTX"], x, y, input_width, row_height, get_prop(14,pitchstep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#Y limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_ROTY = Blender.Draw.Toggle("LimY", evcode["DOF_ROTY"], x, y, toggle_width, row_height, get_lockmask(lockyrot), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_ROTY = Blender.Draw.Number("MinY", evcode["DOF_MIN_ROTY"], x, y, input_width, row_height, get_prop(14,rollmin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_ROTY = Blender.Draw.Number("MaxY", evcode["DOF_MAX_ROTY"], x, y, input_width, row_height, get_prop(14,rollmax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_ROTY = Blender.Draw.Number("StepY", evcode["DOF_STEP_ROTY"], x, y, input_width, row_height, get_prop(14,rollstep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#Z limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_ROTZ = Blender.Draw.Toggle("LimZ", evcode["DOF_ROTZ"], x, y, toggle_width, row_height, get_lockmask(lockzrot), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_ROTZ = Blender.Draw.Number("MinZ", evcode["DOF_MIN_ROTZ"], x, y, input_width, row_height, get_prop(14, yawmin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_ROTZ = Blender.Draw.Number("MaxZ", evcode["DOF_MAX_ROTZ"], x, y, input_width, row_height, get_prop(14, yawmax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_ROTZ = Blender.Draw.Number("StepZ", evcode["DOF_STEP_ROTZ"], x, y, input_width, row_height, get_prop(14, yawstep), -1000000.0, 1000000.0, "")
|
||||
|
||||
|
||||
#draw Scale limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_SCALESTRING = Blender.Draw.Label("Scale Limits", x, y, input_width, row_height)
|
||||
|
||||
#draw Scale limits
|
||||
#X limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_SCALEX = Blender.Draw.Toggle("LimX", evcode["DOF_SCALEX"], x, y, toggle_width, row_height, get_lockmask(lockxscale), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_SCALEX = Blender.Draw.Number("MinX", evcode["DOF_MIN_SCALEX"], x, y, input_width, row_height, get_prop(14, xscalemin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_SCALEX = Blender.Draw.Number("MaxX", evcode["DOF_MAX_SCALEX"], x, y, input_width, row_height, get_prop(14, xscalemax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_SCALEX = Blender.Draw.Number("StepX", evcode["DOF_STEP_SCALEX"], x, y, input_width, row_height, get_prop(14, xscalestep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#Y limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_SCALEY = Blender.Draw.Toggle("LimY", evcode["DOF_SCALEY"], x, y, toggle_width, row_height, get_lockmask(lockyscale), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_SCALEY = Blender.Draw.Number("MinY", evcode["DOF_MIN_SCALEY"], x, y, input_width, row_height, get_prop(14, yscalemin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_SCALEY = Blender.Draw.Number("MaxY", evcode["DOF_MAX_SCALEY"], x, y, input_width, row_height, get_prop(14, yscalemax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_SCALEY = Blender.Draw.Number("StepY", evcode["DOF_STEP_SCALEY"], x, y, input_width, row_height, get_prop(14, yscalestep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#Z limits
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
DOF_SCALEZ = Blender.Draw.Toggle("LimZ", evcode["DOF_SCALEZ"], x, y, toggle_width, row_height, get_lockmask(lockzscale), "")
|
||||
x = x + (toggle_width + pad)
|
||||
DOF_MIN_SCALEZ = Blender.Draw.Number("MinZ", evcode["DOF_MIN_SCALEZ"], x, y, input_width, row_height, get_prop(14, zscalemin), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_MAX_SCALEZ = Blender.Draw.Number("MaxZ", evcode["DOF_MAX_SCALEZ"], x, y, input_width, row_height, get_prop(14, zscalemax), -1000000.0, 1000000.0, "")
|
||||
x = x + (input_width + pad)
|
||||
DOF_STEP_SCALEZ = Blender.Draw.Number("StepZ", evcode["DOF_STEP_SCALEZ"], x, y, input_width, row_height, get_prop(14, zscalestep), -1000000.0, 1000000.0, "")
|
||||
|
||||
#System
|
||||
x = origx
|
||||
y = y - (row_height + (pad)*3)
|
||||
DOF_MAKE = Blender.Draw.PushButton("Make DOF", evcode["DOF_MAKE"], x, y, input_width, row_height, "Make a Dof Node out of Active Object")
|
||||
x = x + (input_width + pad)
|
||||
DOF_UPDATE = Blender.Draw.PushButton("Grab Loc/Rot", evcode["DOF_UPDATE"], x, y, input_width, row_height, "Update the Dof Node position/orientation")
|
||||
x = x + (input_width + pad)
|
||||
DOF_DELETE = Blender.Draw.PushButton("Delete DOF", evcode["DOF_DELETE"], x, y, input_width, row_height, "Delete the Dof Node properties")
|
||||
|
||||
|
||||
|
||||
|
||||
def gui():
|
||||
#draw the propsheet/toolbox.
|
||||
psheety = 800
|
||||
#psheetx = psheety + 10
|
||||
draw_propsheet(20,psheety)
|
||||
|
||||
Draw.Register(gui,event,but_event)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,286 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
# flt_filewalker.py is an utility module for OpenFlight IO scripts for blender.
|
||||
# Copyright (C) 2005 Greg MacDonald
|
||||
#
|
||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
__bpydoc__ ="""\
|
||||
File read/write module used by OpenFlight I/O and tool scripts. OpenFlight is a
|
||||
registered trademark of MultiGen-Paradigm, Inc.
|
||||
"""
|
||||
|
||||
import Blender
|
||||
from struct import *
|
||||
import re
|
||||
|
||||
class FltIn:
|
||||
def __init__(self, filename):
|
||||
self.file = open(filename, 'rb')
|
||||
self.position = 0
|
||||
self.next_position = 100000
|
||||
self.opcode = 0
|
||||
self.length = 0
|
||||
self.level = 0
|
||||
self.repeat = False # Repeat the last record.
|
||||
|
||||
def begin_record(self):
|
||||
if self.repeat == True:
|
||||
self.repeat = False
|
||||
else:
|
||||
self.position += self.length
|
||||
try:
|
||||
self.file.seek(self.position)
|
||||
input = self.file.read(4)
|
||||
except:
|
||||
print 'Parse Error!'
|
||||
return False
|
||||
|
||||
if not input:
|
||||
self.close_file()
|
||||
return False
|
||||
|
||||
self.opcode = unpack('>h', input[:2])[0]
|
||||
self.length = unpack('>H', input[-2:])[0]
|
||||
|
||||
self.next_position = self.position + self.length
|
||||
|
||||
return True
|
||||
|
||||
def repeat_record(self):
|
||||
self.repeat = True
|
||||
|
||||
def get_opcode(self):
|
||||
return self.opcode
|
||||
|
||||
def get_level(self):
|
||||
return self.level
|
||||
|
||||
def up_level(self):
|
||||
self.level += 1
|
||||
|
||||
def down_level(self):
|
||||
self.level -= 1
|
||||
|
||||
def read_string(self, length):
|
||||
s = ''
|
||||
if self.file.tell() + length <= self.next_position:
|
||||
start = self.file.tell()
|
||||
for i in xrange(length):
|
||||
char = self.file.read(1)
|
||||
if char == '\x00':
|
||||
break
|
||||
s = s + char
|
||||
|
||||
self.file.seek(start+length)
|
||||
# else:
|
||||
# print 'Warning: string truncated'
|
||||
|
||||
return s
|
||||
|
||||
def read_int(self):
|
||||
if self.file.tell() + 4 <= self.next_position:
|
||||
return unpack('>i', self.file.read(4))[0]
|
||||
else:
|
||||
#print 'Warning: int truncated'
|
||||
return 0
|
||||
|
||||
def read_uint(self):
|
||||
if self.file.tell() + 4 <= self.next_position:
|
||||
return unpack('>I', self.file.read(4))[0]
|
||||
else:
|
||||
#print 'Warning: uint truncated'
|
||||
return 0
|
||||
|
||||
def read_double(self):
|
||||
if self.file.tell() + 8 <= self.next_position:
|
||||
return unpack('>d', self.file.read(8))[0]
|
||||
else:
|
||||
#print 'Warning: double truncated'
|
||||
return 0.0
|
||||
|
||||
def read_float(self):
|
||||
if self.file.tell() + 4 <= self.next_position:
|
||||
return unpack('>f', self.file.read(4))[0]
|
||||
else:
|
||||
#print 'Warning: float truncated'
|
||||
return 0.0
|
||||
|
||||
def read_ushort(self):
|
||||
if self.file.tell() + 2 <= self.next_position:
|
||||
return unpack('>H', self.file.read(2))[0]
|
||||
else:
|
||||
#print 'Warning: ushort truncated'
|
||||
return 0
|
||||
|
||||
def read_short(self):
|
||||
if self.file.tell() + 2 <= self.next_position:
|
||||
return unpack('>h', self.file.read(2))[0]
|
||||
else:
|
||||
#print 'Warning: short trunated'
|
||||
return 0
|
||||
|
||||
def read_uchar(self):
|
||||
if self.file.tell() + 1 <= self.next_position:
|
||||
return unpack('>B', self.file.read(1))[0]
|
||||
else:
|
||||
#print 'Warning: uchar truncated'
|
||||
return 0
|
||||
|
||||
def read_char(self):
|
||||
if self.file.tell() + 1 <= self.next_position:
|
||||
return unpack('>b', self.file.read(1))[0]
|
||||
else:
|
||||
#print 'Warning: char truncated'
|
||||
return 0
|
||||
|
||||
def read_ahead(self, i):
|
||||
if self.file.tell() + i <= self.next_position:
|
||||
self.file.seek(i, 1)
|
||||
# else:
|
||||
# print 'Warning: attempt to seek past record'
|
||||
|
||||
def get_length(self):
|
||||
return self.length
|
||||
|
||||
def close_file(self):
|
||||
self.file.close()
|
||||
|
||||
class FltOut:
|
||||
# Length includes terminating null
|
||||
def write_string(self, string, length):
|
||||
if len(string) > length - 1:
|
||||
str_len = length - 1
|
||||
else:
|
||||
str_len = len(string)
|
||||
|
||||
pad_len = length - str_len
|
||||
|
||||
self.file.write(string[:str_len])
|
||||
|
||||
self.pad(pad_len)
|
||||
|
||||
def write_int(self, a):
|
||||
self.file.write( pack('>i', a) )
|
||||
|
||||
def write_uint(self, a):
|
||||
self.file.write( pack('>I', a) )
|
||||
|
||||
def write_double(self, a):
|
||||
self.file.write( pack('>d', a) )
|
||||
|
||||
def write_float(self, a):
|
||||
self.file.write( pack('>f', a) )
|
||||
|
||||
def write_ushort(self, a):
|
||||
self.file.write( pack('>H', a) )
|
||||
|
||||
def write_short(self, a):
|
||||
self.file.write( pack('>h', a) )
|
||||
|
||||
def write_uchar(self, a):
|
||||
self.file.write( pack('>B', a) )
|
||||
|
||||
def write_char(self, a):
|
||||
self.file.write( pack('>b', a) )
|
||||
|
||||
def pad(self, reps):
|
||||
for i in xrange(reps):
|
||||
self.file.write('\x00')
|
||||
|
||||
def close_file(self):
|
||||
self.file.close()
|
||||
|
||||
def __init__(self, filename):
|
||||
self.file = open(filename, 'wb')
|
||||
self.filename = filename
|
||||
|
||||
|
||||
class FileFinder:
|
||||
def add_file_to_search_path(self, filename):
|
||||
dir = Blender.sys.dirname(filename)
|
||||
if dir != None and dir != '':
|
||||
self.search_dirs.append(dir)
|
||||
|
||||
def strip_path(self, full_path):
|
||||
# One of my flt files had a windows path with unix seperation. Basename
|
||||
# returned the whole path + filename, which isn't expected. So my
|
||||
# attempt to fix it is to replace all / or \ with the platform specific
|
||||
# dir seperator.
|
||||
#
|
||||
# note: \\\\ is actually just one \ indirected twice, once for python
|
||||
# then again for re.sub
|
||||
if Blender.sys.sep == '\\':
|
||||
full_path = re.sub('/', '\\\\', full_path)
|
||||
elif Blender.sys.sep == '/':
|
||||
full_path = re.sub('\\\\', '/', full_path)
|
||||
|
||||
filename = Blender.sys.basename(full_path)
|
||||
return filename
|
||||
|
||||
def find(self, full_path):
|
||||
if full_path == '':
|
||||
return None
|
||||
|
||||
# Seperate out the path.
|
||||
dirname = Blender.sys.dirname(full_path)
|
||||
|
||||
# Try it first.
|
||||
if Blender.sys.exists(full_path):
|
||||
if not dirname in self.search_dirs:
|
||||
self.search_dirs.append(dirname)
|
||||
return full_path
|
||||
|
||||
# Maybe it's relative.
|
||||
for path in self.search_dirs:
|
||||
rel_full_path = Blender.sys.join(path, full_path)
|
||||
if Blender.sys.exists(rel_full_path):
|
||||
return rel_full_path
|
||||
|
||||
# Search previous directories that have worked.
|
||||
filename = self.strip_path(full_path)
|
||||
for path in self.search_dirs:
|
||||
t = Blender.sys.join(path, filename)
|
||||
if Blender.sys.exists(t):
|
||||
return t
|
||||
|
||||
# Ask user where it is.
|
||||
self.user_input = Blender.Draw.PupStrInput(filename + "? ", '', 100)
|
||||
#self.user_input = None
|
||||
if self.user_input != None:
|
||||
t = Blender.sys.join(self.user_input, filename)
|
||||
if Blender.sys.exists(t):
|
||||
user_dirname = Blender.sys.dirname(t)
|
||||
if not user_dirname in self.search_dirs:
|
||||
self.search_dirs.append(user_dirname)
|
||||
return t
|
||||
|
||||
# Couldn't find it.
|
||||
return None
|
||||
|
||||
def __init__(self):
|
||||
self.user_input = ''
|
||||
self.current_file = ''
|
||||
self.search_dirs = []
|
||||
|
||||
dir = Blender.Get('texturesdir')
|
||||
if dir != None and dir != '':
|
||||
self.search_dirs.append(dir)
|
||||
|
||||
dir = Blender.sys.dirname(Blender.Get('filename'))
|
||||
if dir != None and dir != '':
|
||||
print dir
|
||||
self.search_dirs.append(dir)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,502 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'FLT LOD Editor'
|
||||
Blender: 240
|
||||
Group: 'Misc'
|
||||
Tooltip: 'Level of Detail Edtior for FLT nodes'
|
||||
"""
|
||||
|
||||
__author__ = "Geoffrey Bantle"
|
||||
__version__ = "1.0 11/21/07"
|
||||
__email__ = ('scripts', 'Author, ')
|
||||
__url__ = ('blender', 'blenderartists.org')
|
||||
|
||||
__bpydoc__ ="""\
|
||||
This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a
|
||||
registered trademark of MultiGen-Paradigm, Inc.
|
||||
|
||||
Feature overview and more availible at:
|
||||
http://wiki.blender.org/index.php/Scripts/Manual/FLTools
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# flt_palettemanager.py version 0.1 2005/04/08
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2007: Blender Foundation
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender.Draw as Draw
|
||||
from Blender.BGL import *
|
||||
import Blender
|
||||
import flt_properties
|
||||
reload(flt_properties)
|
||||
from flt_properties import *
|
||||
|
||||
#event codes
|
||||
evcode = {
|
||||
"LOD_MAKE" : 100,
|
||||
"LOD_DELETE" : 101,
|
||||
"LOD_CALC_CENTER" : 102,
|
||||
"LOD_GRAB_CENTER" : 103,
|
||||
"LOD_X" : 104,
|
||||
"LOD_Y" : 105,
|
||||
"LOD_Z" : 106,
|
||||
"LOD_FREEZE" : 107,
|
||||
"LOD_SIG" : 108,
|
||||
"LOD_IN" : 109,
|
||||
"LOD_OUT" : 110,
|
||||
"LOD_TRANS" : 111,
|
||||
"LOD_PREVIOUS" : 112
|
||||
}
|
||||
|
||||
|
||||
#system
|
||||
LOD_MAKE = None #PushButton
|
||||
LOD_DELETE = None #PushButton
|
||||
LOD_CALC_CENTER = None #PushButton
|
||||
LOD_GRAB_CENTER = None #Pushbutton
|
||||
LOD_FREEZE = None #Toggle
|
||||
LOD_PREVIOUS = None #Toggle
|
||||
|
||||
LOD_X = None #Input
|
||||
LOD_Y = None #Input
|
||||
LOD_Z = None #Input
|
||||
|
||||
LOD_SIG = None #Input
|
||||
LOD_IN = None #Input
|
||||
LOD_OUT = None #Input
|
||||
LOD_TRANS = None #Input
|
||||
|
||||
#labels
|
||||
LOD_EDITLABEL = None
|
||||
LOD_SWITCHLABEL = None
|
||||
LOD_CENTERLABEL = None
|
||||
|
||||
LOD_XLABEL = None
|
||||
LOD_YLABEL = None
|
||||
LOD_ZLABEL = None
|
||||
LOD_SIGLABEL = None
|
||||
LOD_INLABEL = None
|
||||
LOD_OUTLABEL = None
|
||||
LOD_TRANSLABEL = None
|
||||
|
||||
|
||||
#ID Props
|
||||
switch_in = '5d!switch in'
|
||||
switch_out = '6d!switch out'
|
||||
xco = '10d!X co'
|
||||
yco = '11d!Y co'
|
||||
zco = '12d!Z co'
|
||||
trans = '13d!Transition'
|
||||
sig_size = '14d!Sig Size'
|
||||
|
||||
#Flags
|
||||
lodflag = '9I!flags'
|
||||
previous_mask = (1 << 31)
|
||||
freeze_mask = (1 << 29)
|
||||
|
||||
def update_state():
|
||||
state = dict()
|
||||
state["activeScene"] = Blender.Scene.GetCurrent()
|
||||
state["activeObject"] = state["activeScene"].objects.active
|
||||
if state["activeObject"] and not state["activeObject"].sel:
|
||||
state["activeObject"] = None
|
||||
state["activeMesh"] = None
|
||||
if state["activeObject"] and state["activeObject"].type == 'Mesh':
|
||||
state["activeMesh"] = state["activeObject"].getData(mesh=True)
|
||||
|
||||
state["activeFace"] = None
|
||||
if state["activeMesh"]:
|
||||
if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None:
|
||||
state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace]
|
||||
|
||||
|
||||
#update editmode
|
||||
state["editmode"] = Blender.Window.EditMode()
|
||||
|
||||
return state
|
||||
|
||||
def idprops_append(object, typecode, props):
|
||||
object.properties["FLT"] = dict()
|
||||
object.properties["FLT"]['type'] = typecode
|
||||
for prop in props:
|
||||
object.properties["FLT"][prop] = props[prop]
|
||||
object.properties["FLT"]['3t8!id'] = object.name
|
||||
|
||||
def idprops_kill():
|
||||
state = update_state()
|
||||
if state["activeObject"] and state["activeObject"].properties.has_key('FLT'):
|
||||
state["activeObject"].properties.pop('FLT')
|
||||
|
||||
def idprops_copy(source):
|
||||
state = update_state()
|
||||
if source.properties.has_key('FLT'):
|
||||
for object in state["activeScene"].objects:
|
||||
if object.sel and object != source and (state["activeScene"].Layers & object.Layers):
|
||||
idprops_kill(object)
|
||||
object.properties['FLT'] = dict()
|
||||
for key in source.properties['FLT']:
|
||||
object.properties['FLT'][key] = source.properties['FLT'][key]
|
||||
|
||||
def select_by_typecode(typecode):
|
||||
state = update_state()
|
||||
|
||||
for object in state["activeScene"].objects:
|
||||
if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers:
|
||||
object.select(1)
|
||||
|
||||
def idprops_type(object, typecode):
|
||||
if object.properties.has_key('FLT') and object.properties['FLT'].has_key('type') and object.properties['FLT']['type'] == typecode:
|
||||
return True
|
||||
return False
|
||||
|
||||
#ui type code
|
||||
def get_prop(typecode, prop):
|
||||
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], typecode):
|
||||
props = state["activeObject"].properties['FLT']
|
||||
else:
|
||||
props = flt_properties.FLTLOD
|
||||
|
||||
return props[prop]
|
||||
|
||||
def set_prop(typecode, prop, value):
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"],typecode):
|
||||
state["activeObject"].properties['FLT'][prop] = value
|
||||
|
||||
|
||||
|
||||
def get_lockmask(mask):
|
||||
global lodflag
|
||||
state = update_state()
|
||||
if state["activeObject"]:
|
||||
flag = get_prop(73,lodflag)
|
||||
if flag & mask:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_lockmask(mask):
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], 73):
|
||||
oldvalue = state["activeObject"].properties['FLT'][lodflag]
|
||||
oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0]
|
||||
oldvalue |= mask
|
||||
state["activeObject"].properties['FLT'][lodflag] = struct.unpack('>i', struct.pack(">I", oldvalue))[0]
|
||||
|
||||
def clear_lockmask(mask):
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], 73):
|
||||
oldvalue = state["activeObject"].properties['FLT'][lodflag]
|
||||
oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0]
|
||||
oldvalue &= ~mask
|
||||
state["activeObject"].properties['FLT'][lodflag] = struct.unpack('>i',struct.pack('>I',oldvalue))[0]
|
||||
|
||||
def findchildren(object):
|
||||
state = update_state()
|
||||
children = list()
|
||||
for candidate in state["activeScene"].objects:
|
||||
if candidate.parent == object:
|
||||
children.append(candidate)
|
||||
retlist = list(children)
|
||||
for child in children:
|
||||
retlist = retlist + findchildren(child)
|
||||
return retlist
|
||||
|
||||
def get_object_center(object):
|
||||
bbox = object.getBoundBox(1)
|
||||
average = Blender.Mathutils.Vector(0.0, 0.0, 0.0)
|
||||
|
||||
for point in bbox:
|
||||
average[0] += point[0]
|
||||
average[1] += point[1]
|
||||
average[2] += point[2]
|
||||
|
||||
average[0] = average[0] / 8.0
|
||||
average[1] = average[1] / 8.0
|
||||
average[2] = average[2] / 8.0
|
||||
|
||||
return average
|
||||
|
||||
|
||||
def calc_center():
|
||||
|
||||
global xco
|
||||
global yco
|
||||
global zco
|
||||
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], 73):
|
||||
average = Blender.Mathutils.Vector(0.0, 0.0, 0.0)
|
||||
children = findchildren(state["activeObject"]) #get children objects
|
||||
if children:
|
||||
for child in children:
|
||||
center = get_object_center(child)
|
||||
average[0] += center[0]
|
||||
average[1] += center[1]
|
||||
average[2] += center[2]
|
||||
|
||||
average[0] = average[0] / len(children)
|
||||
average[1] = average[1] / len(children)
|
||||
average[2] = average[2] / len(children)
|
||||
|
||||
set_prop(73, xco, average[0])
|
||||
set_prop(73, yco, average[1])
|
||||
set_prop(73, zco, average[2])
|
||||
|
||||
|
||||
def grab_center():
|
||||
|
||||
global xco
|
||||
global yco
|
||||
global zco
|
||||
|
||||
state = update_state()
|
||||
if state["activeObject"] and idprops_type(state["activeObject"], 73):
|
||||
center = Blender.Window.GetCursorPos()
|
||||
|
||||
set_prop(73, xco, center[0])
|
||||
set_prop(73, yco, center[1])
|
||||
set_prop(73, zco, center[2])
|
||||
|
||||
|
||||
def create_lod():
|
||||
state = update_state()
|
||||
actobj = state["activeObject"]
|
||||
if actobj and not idprops_type(actobj, 73):
|
||||
idprops_kill()
|
||||
idprops_append(actobj,73, flt_properties.FLTLOD)
|
||||
calc_center()
|
||||
|
||||
|
||||
|
||||
def event(evt,val):
|
||||
if evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
|
||||
def but_event(evt):
|
||||
|
||||
global LOD_MAKE
|
||||
global LOD_DELETE
|
||||
global LOD_CALC_CENTER
|
||||
global LOD_GRAB_CENTER
|
||||
global LOD_FREEZE
|
||||
global LOD_PREVIOUS
|
||||
global LOD_X
|
||||
global LOD_Y
|
||||
global LOD_Z
|
||||
global LOD_SIG
|
||||
global LOD_IN
|
||||
global LOD_OUT
|
||||
global LOD_TRANS
|
||||
|
||||
global switch_in
|
||||
global switch_out
|
||||
global xco
|
||||
global yco
|
||||
global zco
|
||||
global trans
|
||||
global sig_size
|
||||
|
||||
global lodflag
|
||||
global previous_mask
|
||||
global freeze_mask
|
||||
|
||||
global evcode
|
||||
|
||||
#do "system" events
|
||||
if evt == evcode["LOD_MAKE"]:
|
||||
create_lod()
|
||||
|
||||
if evt == evcode["LOD_CALC_CENTER"]:
|
||||
calc_center()
|
||||
|
||||
if evt == evcode["LOD_DELETE"]:
|
||||
idprops_kill()
|
||||
|
||||
if evt == evcode["LOD_GRAB_CENTER"]:
|
||||
grab_center()
|
||||
|
||||
#do mask events
|
||||
if evt == evcode["LOD_FREEZE"]:
|
||||
if LOD_FREEZE.val == True:
|
||||
set_lockmask(freeze_mask)
|
||||
else:
|
||||
clear_lockmask(freeze_mask)
|
||||
|
||||
if evt == evcode["LOD_PREVIOUS"]:
|
||||
if LOD_PREVIOUS.val == True:
|
||||
set_lockmask(previous_mask)
|
||||
else:
|
||||
clear_lockmask(previous_mask)
|
||||
|
||||
#do input events
|
||||
if evt == evcode["LOD_X"]:
|
||||
set_prop(73, xco, LOD_X.val)
|
||||
if evt == evcode["LOD_Y"]:
|
||||
set_prop(73, yco, LOD_Y.val)
|
||||
if evt == evcode["LOD_Z"]:
|
||||
set_prop(73, zco, LOD_Z.val)
|
||||
if evt == evcode["LOD_SIG"]:
|
||||
set_prop(73, sig_size, LOD_SIG.val)
|
||||
if evt == evcode["LOD_IN"]:
|
||||
set_prop(73, switch_in, LOD_IN.val)
|
||||
if evt == evcode["LOD_OUT"]:
|
||||
set_prop(73, switch_out, LOD_OUT.val)
|
||||
if evt == evcode["LOD_TRANS"]:
|
||||
set_prop(73, trans, LOD_TRANS.val)
|
||||
|
||||
|
||||
Draw.Redraw(1)
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
def draw_propsheet(x,y):
|
||||
|
||||
global LOD_MAKE
|
||||
global LOD_DELETE
|
||||
global LOD_CALC_CENTER
|
||||
global LOD_GRAB_CENTER
|
||||
global LOD_FREEZE
|
||||
global LOD_PREVIOUS
|
||||
global LOD_X
|
||||
global LOD_Y
|
||||
global LOD_Z
|
||||
global LOD_SIG
|
||||
global LOD_IN
|
||||
global LOD_OUT
|
||||
global LOD_TRANS
|
||||
|
||||
#labels
|
||||
global LOD_EDITLABEL
|
||||
global LOD_SWITCHLABEL
|
||||
global LOD_CENTERLABEL
|
||||
global LOD_XLABEL
|
||||
global LOD_YLABEL
|
||||
global LOD_ZLABEL
|
||||
global LOD_SIGLABEL
|
||||
global LOD_INLABEL
|
||||
global LOD_OUTLABEL
|
||||
global LOD_TRANSLABEL
|
||||
|
||||
|
||||
global switch_in
|
||||
global switch_out
|
||||
global xco
|
||||
global yco
|
||||
global zco
|
||||
global trans
|
||||
global sig_size
|
||||
|
||||
global lodflag
|
||||
global previous_mask
|
||||
global freeze_mask
|
||||
|
||||
global evcode
|
||||
|
||||
|
||||
global evcode
|
||||
|
||||
state = update_state()
|
||||
|
||||
label_width = 100
|
||||
row_height = 20
|
||||
toggle_width = 50
|
||||
input_width = 100
|
||||
pad = 10
|
||||
origx = x
|
||||
origy = (row_height * 16) + (pad * 16)
|
||||
|
||||
|
||||
#editor label
|
||||
x = origx
|
||||
y = origy
|
||||
LOD_EDITLABEL = Blender.Draw.Label("FLT Level of Detail Editor", x, y, 250, row_height)
|
||||
|
||||
|
||||
#Center inputs
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
LOD_CENTERLABEL = Blender.Draw.Label("LOD center", x, y, label_width, row_height)
|
||||
y = y- (row_height + pad)
|
||||
LOD_XLABEL = Blender.Draw.Label("X Coordinate", x, y, label_width, row_height)
|
||||
x = origx + (label_width + pad)
|
||||
LOD_X = Blender.Draw.Number("", evcode["LOD_X"], x, y, input_width, row_height,get_prop(73,xco), -1000000.0, 1000000.0, "")
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
LOD_YLABEL = Blender.Draw.Label("Y Coordinate", x, y, label_width, row_height)
|
||||
x = origx + (label_width + pad)
|
||||
LOD_Y = Blender.Draw.Number("", evcode["LOD_Y"], x, y, input_width, row_height,get_prop(73,yco), -1000000.0, 1000000.0, "")
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
LOD_ZLABEL = Blender.Draw.Label("Z Coordinate", x, y, label_width, row_height)
|
||||
x = origx + (label_width + pad)
|
||||
LOD_Z = Blender.Draw.Number("", evcode["LOD_Z"], x, y, input_width, row_height,get_prop(73,zco), -1000000.0, 1000000.0, "")
|
||||
|
||||
|
||||
#Switch inputs
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
LOD_SWITCHLABEL = Blender.Draw.Label("Switch Settings", x, y, input_width, row_height)
|
||||
y = y- (row_height + pad)
|
||||
LOD_SIGLABEL = Blender.Draw.Label("Significant Size", x, y, label_width, row_height)
|
||||
x = origx + (label_width + pad)
|
||||
LOD_SIG = Blender.Draw.Number("", evcode["LOD_SIG"], x, y, input_width, row_height, get_prop(73,sig_size), -1000000.0, 1000000.0, "")
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
LOD_INLABEL = Blender.Draw.Label("Switch In", x, y, label_width, row_height)
|
||||
x = origx + (label_width + pad)
|
||||
LOD_IN = Blender.Draw.Number("", evcode["LOD_IN"], x, y, input_width, row_height, get_prop(73,switch_in), -1000000.0, 1000000.0, "")
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
LOD_OUTLABEL = Blender.Draw.Label("Switch Out", x, y, label_width, row_height)
|
||||
x = origx + (label_width + pad)
|
||||
LOD_OUT = Blender.Draw.Number("", evcode["LOD_OUT"], x, y, input_width, row_height, get_prop(73,switch_out), -1000000.0, 1000000.0, "")
|
||||
x = origx
|
||||
y = y- (row_height + pad)
|
||||
LOD_TRANSLABEL = Blender.Draw.Label("Transition", x, y, label_width, row_height)
|
||||
x = origx + (label_width + pad)
|
||||
LOD_TRANS = Blender.Draw.Number("", evcode["LOD_TRANS"], x, y, input_width, row_height, get_prop(73,trans), -1000000.0, 1000000.0, "")
|
||||
|
||||
|
||||
x = origx
|
||||
y = y - (row_height + pad)
|
||||
LOD_MAKE = Blender.Draw.PushButton("Make LOD", evcode["LOD_MAKE"], x, y, input_width + label_width + pad, row_height, "Make a LOD Node out of Active Object")
|
||||
y = y - (row_height + pad)
|
||||
LOD_DELETE = Blender.Draw.PushButton("Delete LOD", evcode["LOD_DELETE"], x, y, input_width + label_width + pad, row_height, "Delete the LOD Node properties")
|
||||
y = y - (row_height + pad)
|
||||
LOD_CALC_CENTER = Blender.Draw.PushButton("Calculate Center", evcode["LOD_CALC_CENTER"], x, y, input_width + label_width + pad, row_height, "Calculate the center of this LOD")
|
||||
y = y - (row_height + pad)
|
||||
LOD_GRAB_CENTER = Blender.Draw.PushButton("Grab Center", evcode["LOD_GRAB_CENTER"], x, y, input_width + label_width + pad, row_height, "Grab center from 3d cursor")
|
||||
y = y - (row_height + pad)
|
||||
LOD_FREEZE = Blender.Draw.Toggle("Freeze Center", evcode["LOD_FREEZE"], x, y, input_width + label_width + pad, row_height, get_lockmask(freeze_mask), "")
|
||||
y = y - (row_height + pad)
|
||||
LOD_PREVIOUS = Blender.Draw.Toggle("Previous Range", evcode["LOD_PREVIOUS"], x, y, input_width + label_width + pad, row_height, get_lockmask(previous_mask), "")
|
||||
|
||||
def gui():
|
||||
#draw the propsheet/toolbox.
|
||||
psheety = 800
|
||||
#psheetx = psheety + 10
|
||||
draw_propsheet(20,psheety)
|
||||
|
||||
Draw.Register(gui,event,but_event)
|
||||
|
||||
@@ -1,505 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'FLT Palette Manager'
|
||||
Blender: 240
|
||||
Group: 'Misc'
|
||||
Tooltip: 'Manage FLT colors'
|
||||
"""
|
||||
|
||||
__author__ = "Geoffrey Bantle"
|
||||
__version__ = "1.0 11/21/2007"
|
||||
__email__ = ('scripts', 'Author, ')
|
||||
__url__ = ('blender', 'blenderartists.org')
|
||||
|
||||
__bpydoc__ ="""\
|
||||
|
||||
This script manages colors in OpenFlight databases. OpenFlight is a
|
||||
registered trademark of MultiGen-Paradigm, Inc.
|
||||
|
||||
Todo:
|
||||
-Figure out whats causing the PC speaker to beep when initializing...
|
||||
|
||||
Feature overview and more availible at:
|
||||
http://wiki.blender.org/index.php/Scripts/Manual/FLTools
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# flt_palettemanager.py version 1.0 2005/04/08
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2007: Blender Foundation
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender.Draw as Draw
|
||||
from Blender.BGL import *
|
||||
import Blender
|
||||
import flt_properties
|
||||
import flt_defaultp as defaultp
|
||||
from flt_properties import *
|
||||
|
||||
def RGBtoHSV( r, g, b):
|
||||
minc = min( r, g, b )
|
||||
maxc = max( r, g, b )
|
||||
v = maxc
|
||||
|
||||
delta = maxc - minc
|
||||
|
||||
if( max != 0 ):
|
||||
s = delta / maxc
|
||||
else:
|
||||
s = 0
|
||||
h = -1
|
||||
return (h,s,v)
|
||||
|
||||
if( r == maxc ):
|
||||
h = ( g - b ) / delta
|
||||
elif( g == maxc ):
|
||||
h = 2 + ( b - r ) / delta
|
||||
else:
|
||||
h = 4 + ( r - g ) / delta
|
||||
|
||||
h *= 60
|
||||
if( h < 0 ):
|
||||
h += 360
|
||||
|
||||
return(h,s,v)
|
||||
|
||||
def HSVtoRGB(h,s,v):
|
||||
|
||||
if( s == 0 ):
|
||||
return (v,v,v)
|
||||
|
||||
|
||||
h /= 60
|
||||
i = math.floor( h)
|
||||
f = h - i
|
||||
p = v * ( 1 - s )
|
||||
q = v * ( 1 - s * f )
|
||||
t = v * ( 1 - s * ( 1 - f ) )
|
||||
|
||||
if i == 0:
|
||||
r = v
|
||||
g = t
|
||||
b = p
|
||||
elif i == 1:
|
||||
r = q
|
||||
g = v
|
||||
b = p
|
||||
|
||||
elif i== 2:
|
||||
r = p
|
||||
g = v
|
||||
b = t
|
||||
elif i==3:
|
||||
r = p
|
||||
g = q
|
||||
b = v
|
||||
elif i==4:
|
||||
r = t
|
||||
g = p
|
||||
b = v
|
||||
|
||||
else:
|
||||
r = v
|
||||
g = p
|
||||
b = q
|
||||
|
||||
return(r,g,b)
|
||||
|
||||
|
||||
palette_size = 12
|
||||
palette_x = 0
|
||||
palette_y = 0
|
||||
|
||||
colors = list()
|
||||
curint = 1.0
|
||||
curswatch = 0
|
||||
#make a default palette, not very useful.
|
||||
cinc = 1.0 / 1024.0
|
||||
cstep = 0.0
|
||||
picker = None
|
||||
ptt = ""
|
||||
|
||||
|
||||
ts1=None
|
||||
ts2=None
|
||||
ts3=None
|
||||
ts4=None
|
||||
ts5=None
|
||||
|
||||
for i in xrange(1024):
|
||||
colors.append([cstep,cstep,cstep])
|
||||
cstep = cstep + cinc
|
||||
def update_state():
|
||||
state = dict()
|
||||
state["activeScene"] = Blender.Scene.getCurrent()
|
||||
state["activeObject"] = state["activeScene"].getActiveObject()
|
||||
state["activeMesh"] = None
|
||||
if state["activeObject"] and state["activeObject"].type == 'Mesh':
|
||||
state["activeMesh"] = state["activeObject"].getData(mesh=True)
|
||||
|
||||
state["activeFace"] = None
|
||||
if state["activeMesh"]:
|
||||
if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None:
|
||||
state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace]
|
||||
|
||||
return state
|
||||
|
||||
def pack_face_index(index, intensity):
|
||||
return ((127*intensity)+(128*index))
|
||||
def unpack_face_index(face_index):
|
||||
index = face_index / 128
|
||||
intensity = float(face_index - 128.0 * index) / 127.0
|
||||
return(index,intensity)
|
||||
|
||||
def event(evt,val):
|
||||
global palette_size
|
||||
global palette_x
|
||||
global palette_y
|
||||
global colors
|
||||
global curint
|
||||
global curswatch
|
||||
|
||||
areas = Blender.Window.GetScreenInfo()
|
||||
curarea = Blender.Window.GetAreaID()
|
||||
curRect = None
|
||||
editmode = 0
|
||||
|
||||
for area in areas:
|
||||
if area['id'] == curarea:
|
||||
curRect = area['vertices']
|
||||
break
|
||||
|
||||
if evt == Draw.LEFTMOUSE:
|
||||
mval = Blender.Window.GetMouseCoords()
|
||||
rastx = mval[0] - curRect[0]
|
||||
rasty = mval[1] - curRect[1]
|
||||
|
||||
swatchx = (rastx -palette_x) / palette_size #+state["palette_x"]
|
||||
swatchy = (rasty -palette_y) / palette_size #+state["palette_y"]
|
||||
if rastx > palette_x and rastx < (palette_x + palette_size * 32) and rasty > palette_y and rasty < (palette_y+ palette_size* 32):
|
||||
if swatchx < 32 and swatchy < 32:
|
||||
curswatch = (swatchx * 32) + swatchy
|
||||
Draw.Redraw(1)
|
||||
|
||||
elif swatchy < 34 and swatchx < 32:
|
||||
curint = 1.0 - (float(rastx-palette_x)/(palette_size*32.0))
|
||||
Draw.Redraw(1)
|
||||
|
||||
#copy current color and intensity to selected faces.
|
||||
elif evt == Draw.VKEY:
|
||||
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode = 1
|
||||
state = update_state()
|
||||
|
||||
#retrieve color from palette
|
||||
color = struct.unpack('>BBBB',struct.pack('>i',colors[curswatch]))
|
||||
actmesh = state["activeMesh"]
|
||||
if actmesh:
|
||||
if(Blender.Window.GetKeyQualifiers() != Blender.Window.Qual["CTRL"]):
|
||||
selfaces = list()
|
||||
for face in actmesh.faces:
|
||||
if face.sel:
|
||||
selfaces.append(face)
|
||||
|
||||
if not "FLT_COL" in actmesh.faces.properties:
|
||||
actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"])
|
||||
for face in actmesh.faces:
|
||||
face.setProperty("FLT_COL",127) #default
|
||||
try:
|
||||
actmesh.activeColorLayer = "FLT_Fcol"
|
||||
except:
|
||||
actmesh.addColorLayer("FLT_Fcol")
|
||||
actmesh.activeColorLayer = "FLT_Fcol"
|
||||
|
||||
|
||||
for face in selfaces:
|
||||
#First append packed index + color and store in face property
|
||||
face.setProperty("FLT_COL",int(pack_face_index(curswatch,curint)))
|
||||
#Save baked color to face vertex colors
|
||||
for col in face.col:
|
||||
col.r = int(color[0] * curint)
|
||||
col.g = int(color[1] * curint)
|
||||
col.b = int(color[2] * curint)
|
||||
col.a = int(color[3] * curint)
|
||||
else:
|
||||
if Blender.Mesh.Mode() == Blender.Mesh.SelectModes['VERTEX']:
|
||||
if not 'FLT_VCOL' in actmesh.verts.properties:
|
||||
actmesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"])
|
||||
for vert in actmesh.verts:
|
||||
vert.setProperty("FLT_VCOL",127)
|
||||
else:
|
||||
for vert in actmesh.verts:
|
||||
if vert.sel:
|
||||
vert.setProperty("FLT_VCOL",int(pack_face_index(curswatch,curint)))
|
||||
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
#grab color and intensity from active face
|
||||
elif evt == Draw.CKEY:
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode = 1
|
||||
state = update_state()
|
||||
|
||||
actmesh = state["activeMesh"]
|
||||
activeFace = state["activeFace"]
|
||||
|
||||
|
||||
if activeFace:
|
||||
if not "FLT_COL" in actmesh.faces.properties:
|
||||
actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"])
|
||||
for face in actmesh.faces:
|
||||
face.setProperty("FLT_COL",127) #default
|
||||
try:
|
||||
actmesh.activeColorLayer = "FLT_Fcol"
|
||||
except:
|
||||
actmesh.addColorLayer("FLT_Fcol")
|
||||
actmesh.activeColorLayer = "FLT_Fcol"
|
||||
tcol = activeFace.getProperty("FLT_COL")
|
||||
(index,intensity) = unpack_face_index(tcol)
|
||||
curswatch = index
|
||||
curint = intensity
|
||||
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
elif evt == Draw.GKEY:
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode =1
|
||||
state = update_state()
|
||||
|
||||
actmesh = state["activeMesh"]
|
||||
activeFace = state["activeFace"]
|
||||
|
||||
if activeFace and "FLT_COL" in actmesh.faces.properties:
|
||||
(index,intensity) = unpack_face_index(activeFace.getProperty("FLT_COL"))
|
||||
for face in actmesh.faces:
|
||||
(index2, intensity2) = unpack_face_index(face.getProperty("FLT_COL"))
|
||||
if index == index2:
|
||||
face.sel = 1
|
||||
|
||||
|
||||
elif evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
def update_all():
|
||||
global colors
|
||||
state = update_state()
|
||||
#update the baked FLT colors for all meshes.
|
||||
for object in state["activeScene"].objects:
|
||||
if object.type == "Mesh":
|
||||
mesh = object.getData(mesh=True)
|
||||
if 'FLT_COL' in mesh.faces.properties and "FLT_Fcol" in mesh.getColorLayerNames():
|
||||
mesh.activeColorLayer = "FLT_Fcol"
|
||||
for face in mesh.faces:
|
||||
(index,intensity) = unpack_face_index(face.getProperty('FLT_COL'))
|
||||
color = struct.unpack('>BBBB',struct.pack('>i',colors[index]))
|
||||
#update the vertex colors for this face
|
||||
for col in face.col:
|
||||
col.r = int(color[0] * intensity)
|
||||
col.g = int(color[1] * intensity)
|
||||
col.b = int(color[2] * intensity)
|
||||
col.a = 255
|
||||
|
||||
|
||||
def but_event(evt):
|
||||
global palette_size
|
||||
global palette_x
|
||||
global palette_y
|
||||
global colors
|
||||
global curint
|
||||
global curswatch
|
||||
global picker
|
||||
state = update_state()
|
||||
|
||||
if evt == 1:
|
||||
if picker.val:
|
||||
rval = (int(picker.val[0]*255),int(picker.val[1]*255),int(picker.val[2]*255),255)
|
||||
rval = struct.pack('>BBBB',rval[0],rval[1],rval[2],rval[3])
|
||||
rval = struct.unpack('>i',rval)
|
||||
colors[curswatch] = rval[0]
|
||||
#go cd through all meshes and update their FLT colors
|
||||
update_all()
|
||||
|
||||
Draw.Redraw(1)
|
||||
def init_pal():
|
||||
global palette_size
|
||||
global palette_x
|
||||
global palette_y
|
||||
global colors
|
||||
global curint
|
||||
global curswatch
|
||||
|
||||
state = update_state()
|
||||
|
||||
if not state["activeScene"].properties.has_key('FLT'):
|
||||
state["activeScene"].properties['FLT'] = dict()
|
||||
|
||||
try:
|
||||
colors = state["activeScene"].properties['FLT']['Color Palette']
|
||||
except:
|
||||
state["activeScene"].properties['FLT']['Color Palette'] = defaultp.pal
|
||||
colors = state["activeScene"].properties['FLT']['Color Palette']
|
||||
|
||||
def draw_palette():
|
||||
global palette_size
|
||||
global palette_x
|
||||
global palette_y
|
||||
global colors
|
||||
global curint
|
||||
global curswatch
|
||||
global picker
|
||||
global ts1
|
||||
global ts2
|
||||
global ts3
|
||||
global ts4
|
||||
global ts5
|
||||
|
||||
state = update_state()
|
||||
init_pal()
|
||||
|
||||
ssize = palette_size
|
||||
xpos = palette_x
|
||||
cid = 0
|
||||
|
||||
highlight = [(palette_x,palette_y),(palette_x+palette_size,palette_y),(palette_x+palette_size,palette_y+palette_size),(palette_x,palette_y+palette_size)]
|
||||
for x in xrange(32):
|
||||
ypos = palette_y
|
||||
for y in xrange(32):
|
||||
color = struct.unpack('>BBBB',struct.pack('>i',colors[cid]))
|
||||
glColor3f(color[0]/255.0,color[1]/255.0,color[2]/255.0)
|
||||
glBegin(GL_POLYGON)
|
||||
glVertex2i(xpos,ypos)
|
||||
glVertex2i(xpos+ssize,ypos)
|
||||
glVertex2i(xpos+ssize,ypos+ssize)
|
||||
glVertex2i(xpos,ypos+ssize)
|
||||
glEnd()
|
||||
|
||||
if curswatch == cid:
|
||||
highlight[0] = (xpos,ypos)
|
||||
highlight[1] = (xpos+ssize,ypos)
|
||||
highlight[2] = (xpos+ssize,ypos+ssize)
|
||||
highlight[3] = (xpos,ypos+ssize)
|
||||
|
||||
glColor3f(0.0,0.0,0.0)
|
||||
glBegin(GL_LINE_LOOP)
|
||||
glVertex2i(xpos,ypos)
|
||||
glVertex2i(xpos+ssize,ypos)
|
||||
glVertex2i(xpos+ssize,ypos+ssize)
|
||||
glVertex2i(xpos,ypos+ssize)
|
||||
glVertex2i(xpos,ypos)
|
||||
glEnd()
|
||||
|
||||
|
||||
cid = cid + 1
|
||||
ypos = ypos + ssize
|
||||
|
||||
xpos = xpos + ssize
|
||||
|
||||
#draw intensity gradient
|
||||
color = struct.unpack('>BBBB',struct.pack('>i',colors[curswatch]))
|
||||
color = [color[0]/255.0,color[1]/255.0,color[2]/255.0]
|
||||
colsteps = [color[0]/255.0,color[1]/255.0,color[2]/255.0]
|
||||
stripwidth = (palette_size * 32.0) / 256
|
||||
strippad = palette_size / 2.0
|
||||
|
||||
xpos = palette_x
|
||||
grady = (palette_y + (palette_size * 32.0)) + strippad
|
||||
for x in xrange(256):
|
||||
color[0] = color[0] - colsteps[0]
|
||||
color[1] = color[1] - colsteps[1]
|
||||
color[2] = color[2] - colsteps[2]
|
||||
|
||||
glColor3f(color[0], color[1] ,color[2])
|
||||
glBegin(GL_POLYGON)
|
||||
glVertex2f(xpos,grady)
|
||||
glVertex2f(xpos+stripwidth,grady)
|
||||
glVertex2f(xpos+stripwidth,grady+palette_size)
|
||||
glVertex2f(xpos,grady+palette_size)
|
||||
glEnd()
|
||||
xpos = xpos + stripwidth
|
||||
|
||||
#draw intensity slider bar
|
||||
#xposition == 512 - ((curint) * 512)
|
||||
xpos = ((palette_size*32) * (1.0 - curint)) + palette_x
|
||||
glColor3f(1.0,1.0,1.0)
|
||||
glBegin(GL_LINE_LOOP)
|
||||
glVertex2i(int(xpos-6),int(grady-1))
|
||||
glVertex2i(int(xpos+6),int(grady-1))
|
||||
glVertex2i(int(xpos+6),int(grady+palette_size+1))
|
||||
glVertex2i(int(xpos-6),int(grady+palette_size+1))
|
||||
#glVertex2i(xpos-6,grady+7)
|
||||
glEnd()
|
||||
|
||||
#draw color picker
|
||||
color = struct.unpack('>BBBB',struct.pack('>i',colors[curswatch]))
|
||||
pickcol = (color[0]/255.0,color[1]/255.0,color[2]/255.0)
|
||||
picker = Blender.Draw.ColorPicker(1,highlight[0][0]+1,highlight[0][1]+1,ssize-2,ssize-2,pickcol,ptt)
|
||||
|
||||
#draw highlight swatch
|
||||
glColor3f(1.0,1.0,1.0)
|
||||
glBegin(GL_LINE_LOOP)
|
||||
glVertex2i(highlight[0][0],highlight[0][1])
|
||||
glVertex2i(highlight[1][0],highlight[1][1])
|
||||
glVertex2i(highlight[2][0],highlight[2][1])
|
||||
glVertex2i(highlight[3][0],highlight[3][1])
|
||||
glVertex2i(highlight[0][0],highlight[0][1])
|
||||
glEnd()
|
||||
|
||||
#draw text string explanations
|
||||
xpos = palette_size*32+20
|
||||
ypos = palette_size*32+10
|
||||
glRasterPos2d(xpos,ypos)
|
||||
ts1 = Blender.Draw.Text("FLT Palette Manager V 1.0")
|
||||
ypos = ypos - 20
|
||||
glRasterPos2d(xpos,ypos)
|
||||
ts3 = Blender.Draw.Text("CKEY - Copy Active Face Color*")
|
||||
ypos = ypos - 20
|
||||
glRasterPos2d(xpos,ypos)
|
||||
ts2 = Blender.Draw.Text("VKEY - Paste Color to Selected Faces")
|
||||
ypos = ypos - 20
|
||||
glRasterPos2d(xpos,ypos)
|
||||
ts4 = Blender.Draw.Text("GKEY - Select Faces With Same Color")
|
||||
ypos = ypos - 15
|
||||
glRasterPos2d(xpos,ypos)
|
||||
ts5 = Blender.Draw.Text("(*Requires mesh with UV coordinates)", 'small')
|
||||
|
||||
def gui():
|
||||
glClearColor(0.5,0.5,0.5,1.0)
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
draw_palette()
|
||||
|
||||
|
||||
init_pal()
|
||||
Draw.Register(gui,event,but_event)
|
||||
|
||||
@@ -1,630 +0,0 @@
|
||||
# flt_properties.py. For setting default OpenFLight ID property types
|
||||
# Copyright (C) 2007 Blender Foundation
|
||||
#
|
||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
__bpydoc__ ="""\
|
||||
Utility functions and data defintions used by OpenFlight I/O and tool scripts. OpenFlight is a
|
||||
registered trademark of MultiGen-Paradigm, Inc.
|
||||
"""
|
||||
|
||||
|
||||
import struct
|
||||
|
||||
bitsLSB = [2147483648]
|
||||
for i in xrange(31):
|
||||
bitsLSB.append(bitsLSB[-1]/2)
|
||||
bitsRSB = bitsLSB[:]
|
||||
bitsRSB.reverse()
|
||||
|
||||
def pack_color(col):
|
||||
return struct.pack('>B',col[3]) + struct.pack('>B',col[2]) + struct.pack('>B',col[1]) + struct.pack('>B',col[0])
|
||||
|
||||
def unpack_color(col):
|
||||
string = struct.pack('>I', col)
|
||||
r = struct.unpack('>B',string[3:4])
|
||||
g = struct.unpack('>B',string[2:3])
|
||||
b = struct.unpack('>B',string[1:2])
|
||||
a = struct.unpack('>B',string[0:1])
|
||||
return [r,g,b,a]
|
||||
|
||||
def reverse_bits(len,num):
|
||||
bitbucket = list()
|
||||
rval = 0
|
||||
|
||||
for i in xrange(len):
|
||||
if num & bitsRSB[i]:
|
||||
bitbucket.append(1)
|
||||
else:
|
||||
bitbucket.append(0)
|
||||
|
||||
bitbucket.reverse()
|
||||
|
||||
for i, bit in enumerate(bitbucket):
|
||||
if bit:
|
||||
rval |= bitsLSB[i]
|
||||
|
||||
return rval
|
||||
|
||||
|
||||
opcode_name = { 0: 'db',
|
||||
1: 'head',
|
||||
2: 'grp',
|
||||
4: 'obj',
|
||||
5: 'face',
|
||||
10: 'push',
|
||||
11: 'pop',
|
||||
14: 'dof',
|
||||
19: 'push sub',
|
||||
20: 'pop sub',
|
||||
21: 'push ext',
|
||||
22: 'pop ext',
|
||||
23: 'cont',
|
||||
31: 'comment',
|
||||
32: 'color pal',
|
||||
33: 'long id',
|
||||
49: 'matrix',
|
||||
50: 'vector',
|
||||
52: 'multi-tex',
|
||||
53: 'uv lst',
|
||||
55: 'bsp',
|
||||
60: 'rep',
|
||||
61: 'inst ref',
|
||||
62: 'inst def',
|
||||
63: 'ext ref',
|
||||
64: 'tex pal',
|
||||
67: 'vert pal',
|
||||
68: 'vert w col',
|
||||
69: 'vert w col & norm',
|
||||
70: 'vert w col, norm & uv',
|
||||
71: 'vert w col & uv',
|
||||
72: 'vert lst',
|
||||
73: 'lod',
|
||||
74: 'bndin box',
|
||||
76: 'rot edge',
|
||||
78: 'trans',
|
||||
79: 'scl',
|
||||
80: 'rot pnt',
|
||||
81: 'rot and/or scale pnt',
|
||||
82: 'put',
|
||||
83: 'eyepoint & trackplane pal',
|
||||
84: 'mesh',
|
||||
85: 'local vert pool',
|
||||
86: 'mesh prim',
|
||||
87: 'road seg',
|
||||
88: 'road zone',
|
||||
89: 'morph vert lst',
|
||||
90: 'link pal',
|
||||
91: 'snd',
|
||||
92: 'rd path',
|
||||
93: 'snd pal',
|
||||
94: 'gen matrix',
|
||||
95: 'txt',
|
||||
96: 'sw',
|
||||
97: 'line styl pal',
|
||||
98: 'clip reg',
|
||||
100: 'ext',
|
||||
101: 'light src',
|
||||
102: 'light src pal',
|
||||
103: 'reserved',
|
||||
104: 'reserved',
|
||||
105: 'bndin sph',
|
||||
106: 'bndin cyl',
|
||||
107: 'bndin hull',
|
||||
108: 'bndin vol cntr',
|
||||
109: 'bndin vol orient',
|
||||
110: 'rsrvd',
|
||||
111: 'light pnt',
|
||||
112: 'tex map pal',
|
||||
113: 'mat pal',
|
||||
114: 'name tab',
|
||||
115: 'cat',
|
||||
116: 'cat dat',
|
||||
117: 'rsrvd',
|
||||
118: 'rsrvd',
|
||||
119: 'bounding hist',
|
||||
120: 'rsrvd',
|
||||
121: 'rsrvd',
|
||||
122: 'push attrib',
|
||||
123: 'pop attrib',
|
||||
124: 'rsrvd',
|
||||
125: 'rsrvd',
|
||||
126: 'curv',
|
||||
127: 'road const',
|
||||
128: 'light pnt appear pal',
|
||||
129: 'light pnt anim pal',
|
||||
130: 'indexed lp',
|
||||
131: 'lp sys',
|
||||
132: 'indx str',
|
||||
133: 'shdr pal'}
|
||||
|
||||
|
||||
typecodes = ['c','C','s','S','i','I','f','d','t']
|
||||
|
||||
FLT_GRP = 2
|
||||
FLT_OBJ = 4
|
||||
FLT_LOD = 73
|
||||
FLT_XRF = 63
|
||||
FLT_DOF = 14
|
||||
FLT_ILP = 111
|
||||
FLT_DB = 1
|
||||
FLT_FCE = 5
|
||||
|
||||
#not actual opcodes
|
||||
FLT_NUL = 0
|
||||
FLT_EXP = -1
|
||||
|
||||
#valid childtypes for each FLT node type
|
||||
FLT_CHILDTYPES = {
|
||||
FLT_GRP : [111,2,73,4,14,63],
|
||||
FLT_OBJ : [111],
|
||||
FLT_LOD : [111,2,73,4,14,63],
|
||||
FLT_XRF : [],
|
||||
FLT_DOF : [111,2,73,4,14,63],
|
||||
FLT_ILP : []
|
||||
}
|
||||
|
||||
#List of nodes that can have faces as children
|
||||
FLT_FACETYPES = [
|
||||
FLT_GRP,
|
||||
FLT_OBJ,
|
||||
FLT_LOD,
|
||||
FLT_DOF
|
||||
]
|
||||
|
||||
def write_prop(fw,type,value,length):
|
||||
if type == 'c':
|
||||
fw.write_char(value)
|
||||
elif type == 'C':
|
||||
fw.write_uchar(value)
|
||||
elif type == 's':
|
||||
fw.write_short(value)
|
||||
elif type == 'S':
|
||||
fw.write_ushort(value)
|
||||
elif type == 'i':
|
||||
fw.write_int(value)
|
||||
elif type == 'I':
|
||||
#NOTE!:
|
||||
#there is no unsigned int type in python, but we can only store signed ints in ID props
|
||||
newvalue = struct.unpack('>I', struct.pack('>i', value))[0]
|
||||
fw.write_uint(newvalue)
|
||||
elif type == 'd':
|
||||
fw.write_double(value)
|
||||
elif type == 'f':
|
||||
fw.write_float(value)
|
||||
elif type == 't':
|
||||
fw.write_string(value,length)
|
||||
|
||||
def read_prop(fw,type,length):
|
||||
rval = None
|
||||
if type == 'c':
|
||||
rval = fw.read_char()
|
||||
elif type == 'C':
|
||||
rval = fw.read_uchar()
|
||||
elif type == 's':
|
||||
rval = fw.read_short()
|
||||
elif type == 'S':
|
||||
rval = fw.read_ushort()
|
||||
elif type == 'i':
|
||||
rval = fw.read_int()
|
||||
elif type == 'I':
|
||||
rval = fw.read_uint()
|
||||
elif type == 'd':
|
||||
rval = fw.read_double()
|
||||
elif type == 'f':
|
||||
rval = fw.read_float()
|
||||
elif type == 't':
|
||||
rval = fw.read_string(length)
|
||||
return rval
|
||||
|
||||
|
||||
FLTExt = {
|
||||
'3t8!id' : 'Ext',
|
||||
'4t8!sid' : '',
|
||||
'5c!reserved': 0,
|
||||
'6c!revision' : 0,
|
||||
'7S!recordcode' : 0
|
||||
}
|
||||
FLTGroup = {
|
||||
'3t8!id' : 'G',
|
||||
'4s!priority' : 0,
|
||||
'5s!reserved1' : 0,
|
||||
'6i!flags' : 0,
|
||||
'7s!special1' : 0,
|
||||
'8s!special2' : 0,
|
||||
'9s!significance' : 0,
|
||||
'10c!layer code' : 0,
|
||||
'11c!reserved2' : 0,
|
||||
'12i!reserved3' : 0,
|
||||
'13i!loop count' : 0,
|
||||
'14f!loop duration' : 0,
|
||||
'15f!last frame duration' : 0
|
||||
}
|
||||
FLTGroupDisplay = [5,11,12]
|
||||
|
||||
FLTObject = {
|
||||
'3t8!id' : 'O',
|
||||
'4I!flags' : 0,
|
||||
'5s!priority' : 0,
|
||||
'6S!transp' : 0,
|
||||
'7s!SFX1' : 0,
|
||||
'8s!SFX2' : 0,
|
||||
'9s!significance' : 0,
|
||||
'10s!reserved' : 0
|
||||
}
|
||||
FLTObjectDisplay = [10]
|
||||
|
||||
FLTLOD = {
|
||||
'3t8!id' : 'L',
|
||||
'4i!reserved' : 0,
|
||||
'5d!switch in' : 0.0,
|
||||
'6d!switch out' : 0.0,
|
||||
'7s!sfx ID1' : 0,
|
||||
'8s!sfx ID2' : 0,
|
||||
'9I!flags' : 0,
|
||||
'10d!X co' : 0.0,
|
||||
'11d!Y co' : 0.0,
|
||||
'12d!Z co' : 0.0,
|
||||
'13d!Transition' : 0.0,
|
||||
'14d!Sig Size' : 0.0
|
||||
}
|
||||
FLTLODDisplay = [4]
|
||||
|
||||
FLTInlineLP = {
|
||||
'3t8!id' : 'Lp',
|
||||
'4s!smc' : 0,
|
||||
'5s!fid' : 0,
|
||||
'6C!back color: a' : 255,
|
||||
'7C!back color: b' : 255,
|
||||
'8C!back color: g' : 255,
|
||||
'9C!back color: r' : 255,
|
||||
'10i!display mode' : 0,
|
||||
'11f!intensity' : 1.0,
|
||||
'12f!back intensity' : 0.0,
|
||||
'13f!minimum defocus' : 0.0,
|
||||
'14f!maximum defocus' : 1.0,
|
||||
'15i!fading mode' : 0,
|
||||
'16i!fog punch mode' : 0,
|
||||
'17i!directional mode' : 1,
|
||||
'18i!range mode' : 0,
|
||||
'19f!min pixel size' : 1.0,
|
||||
'20f!max pixel size' : 1024,
|
||||
'21f!actual size' : 0.25,
|
||||
'22f!trans falloff pixel size' : 0.25,
|
||||
'23f!trans falloff exponent' : 1.0,
|
||||
'24f!trans falloff scalar' : 1.0,
|
||||
'25f!trans falloff clamp' : 1.0,
|
||||
'26f!fog scalar' : 0.25,
|
||||
'27f!fog intensity' : 1.0,
|
||||
'28f!size threshold' : 0.1,
|
||||
'29i!directionality' : 0,
|
||||
'30f!horizontal lobe angle' : 180.0,
|
||||
'31f!vertical lobe angle' : 180.0,
|
||||
'32f!lobe roll angle' : 0.0,
|
||||
'33f!dir falloff exponent' : 1.0,
|
||||
'34f!dir ambient intensity' : 0.1,
|
||||
'35f!anim period' : 2,
|
||||
'36f!anim phase' : 0,
|
||||
'37f!anim enabled' : 1.0,
|
||||
'38f!significance' : 0.0,
|
||||
'39i!draw order' : 0,
|
||||
'40I!flags' : 277004288,
|
||||
'41f!roti' : 0,
|
||||
'42f!rotj' : 0,
|
||||
'43f!rotk' : 1.0
|
||||
}
|
||||
|
||||
FLTInlineLPDisplay = [35,36,37,41,42,43]
|
||||
|
||||
FLTXRef = {
|
||||
'3t200!filename' : '', #we dont actually use this value on export
|
||||
'4i!reserved' : 0,
|
||||
'5I!flag' : -478150656,
|
||||
'6s!bbox' : 0,
|
||||
'7s!reserved' : 0
|
||||
}
|
||||
|
||||
FLTXRefDisplay = [4,7,3]
|
||||
|
||||
FLTDOF = {
|
||||
'3t8!id' : 'D',
|
||||
'4i!reserved' : 0,
|
||||
'5d!ORIGX' : 0.0,
|
||||
'6d!ORIGY' : 0.0,
|
||||
'7d!ORIGZ' : 0.0,
|
||||
'8d!XAXIS-X' : 10.0,
|
||||
'9d!XAXIS-Y' : 0.0,
|
||||
'10d!XAXIS-Z' : 0.0,
|
||||
'11d!XYPLANE-X' : 0.0,
|
||||
'12d!XYPLANE-Y' : 10.0,
|
||||
'13d!XZPLANE-Z' : 0.0,
|
||||
'14d!ZMIN' : 0.0,
|
||||
'15d!ZMAX' : 0.0,
|
||||
'16d!ZCUR' : 0.0,
|
||||
'17d!ZSTEP' : 0.0,
|
||||
'18d!YMIN' : 0.0,
|
||||
'19d!YMAX' : 0.0,
|
||||
'20d!YCUR' : 0.0,
|
||||
'21d!YSTEP' : 0.0,
|
||||
'22d!XMIN' : 0.0,
|
||||
'23d!XMAX' : 0.0,
|
||||
'24d!XCUR' : 0.0,
|
||||
'25d!XSTEP' : 0.0,
|
||||
'26d!PITCH-MIN' : 0.0,
|
||||
'27d!PITCH-MAX' : 0.0,
|
||||
'28d!PITCH-CUR' : 0.0,
|
||||
'29d!PITCH-STEP' : 0.0,
|
||||
'30d!ROLL-MIN' : 0.0,
|
||||
'31d!ROLL-MAX' : 0.0,
|
||||
'32d!ROLL-CUR' : 0.0,
|
||||
'33d!ROLL-STEP' : 0.0,
|
||||
'34d!YAW-MIN' : 0.0,
|
||||
'35d!YAW-MAX' : 0.0,
|
||||
'36d!YAW-CUR' : 0.0,
|
||||
'37d!YAW-STEP' : 0.0,
|
||||
'38d!ZSIZE-MIN' : 0.0,
|
||||
'39d!ZSIZE-MAX' : 0.0,
|
||||
'40d!ZSIZE-CUR' : 1.0,
|
||||
'41d!ZSIZE-STEP' : 0.0,
|
||||
'42d!YSIZE-MIN' : 0.0,
|
||||
'43d!YSIZE-MAX' : 0.0,
|
||||
'44d!YSIZE-CUR' : 1.0,
|
||||
'45d!YSIZE-STEP' : 0.0,
|
||||
'46d!XSIZE-MIN' : 0.0,
|
||||
'47d!XSIZE-MAX' : 0.0,
|
||||
'48d!XSIZE-CUR' : 1.0,
|
||||
'49d!XSIZE-STEP' : 0.0,
|
||||
'50I!FLAG' : 1897582,
|
||||
'51i!reserved2' : 0
|
||||
}
|
||||
|
||||
FLTDOFDisplay = [4]
|
||||
|
||||
FLTImage = {
|
||||
'3i!RealU Direction' : 0,
|
||||
'4i!RealV Direction' : 0,
|
||||
'5i!UpX' : 0,
|
||||
'6i!UpY' : 0,
|
||||
'7i!File Format' : 0,
|
||||
'8i!Min Filter' : 6,
|
||||
'9i!Mag Filter' : 1,
|
||||
'10i!Wrap' : 0,
|
||||
'11i!WrapU' : 0,
|
||||
'12i!WrapV' : 0,
|
||||
'13i!Modified' : 0,
|
||||
'14i!PivotX' : 0,
|
||||
'15i!PivotY' : 0,
|
||||
'16i!Enviorment' : 0,
|
||||
'17i!WhiteAlpha' : 0,
|
||||
'18i!reserved1' : 0,
|
||||
'19i!reserved2' : 0,
|
||||
'20i!reserved3' : 0,
|
||||
'21i!reserved4' : 0,
|
||||
'22i!reserved5' : 0,
|
||||
'23i!reserved6' : 0,
|
||||
'24i!reserved7' : 0,
|
||||
'25i!reserved8' : 0,
|
||||
'26i!reserved9' : 0,
|
||||
'27d!RealU Direction' : 0,
|
||||
'28d!RealV Direction' : 0,
|
||||
'29i!Origin' : 0,
|
||||
'30i!Kernel no.' : 0,
|
||||
'31i!Internal Format' : 0,
|
||||
'32i!External Format' : 0,
|
||||
'33i!MipMap Filter?' : 0,
|
||||
'34f!MMF1' : 0.0,
|
||||
'35f!MMF2' : 0.0,
|
||||
'36f!MMF3' : 0.0,
|
||||
'37f!MMF4' : 0.0,
|
||||
'38f!MMF5' : 0.0,
|
||||
'39f!MMF6' : 0.0,
|
||||
'40f!MMF7' : 0.0,
|
||||
'41f!MMF8' : 0.0,
|
||||
'42i!Tex CPs?' : 0,
|
||||
'43f!LOD0 CP' : 0.0,
|
||||
'44f!Scale0 CP' : 0.0,
|
||||
'45f!LOD1 CP' : 0.0,
|
||||
'46f!Scale1 CP' : 0.0,
|
||||
'47f!LOD2 CP' : 0.0,
|
||||
'48f!Scale2 CP' : 0.0,
|
||||
'49f!LOD3 CP' : 0.0,
|
||||
'50f!Scale3 CP' : 0.0,
|
||||
'51f!LOD4 CP' : 0.0,
|
||||
'52f!Scale4 CP' : 0.0,
|
||||
'53f!LOD5 CP' : 0.0,
|
||||
'54f!Scale5 CP' : 0.0,
|
||||
'55f!LOD6 CP' : 0.0,
|
||||
'56f!Scale6 CP' : 0.0,
|
||||
'57f!LOD7 CP' : 0.0,
|
||||
'58f!Scale7 CP' : 0.0,
|
||||
'59f!Control Clamp' : 0.0,
|
||||
'60i!Mag Alpha Filter' : 0,
|
||||
'61i!Mag Color Filter' : 0,
|
||||
'62f!reserved10' : 0,
|
||||
'63f!reserved11' : 0,
|
||||
'64f!reserved12' : 0,
|
||||
'65f!reserved13' : 0,
|
||||
'66f!reserved14' : 0,
|
||||
'67f!reserved15' : 0,
|
||||
'68f!reserved16' : 0,
|
||||
'69f!reserved17' : 0,
|
||||
'70f!reserved18' : 0,
|
||||
'71d!Lambert Central' : 0.0,
|
||||
'72d!Lambert Upper' : 0.0,
|
||||
'73d!Lambert Lower' : 0.0,
|
||||
'74d!reserved19' : 0,
|
||||
'75f!reserved20' : 0,
|
||||
'76f!reserved21' : 0,
|
||||
'77f!reserved22' : 0,
|
||||
'78f!reserved23' : 0,
|
||||
'79f!reserved24' : 0,
|
||||
'80i!Tex Detail?' : 0,
|
||||
'81i!Tex J' : 0,
|
||||
'82i!Tex K' : 0,
|
||||
'83i!Tex M' : 0,
|
||||
'84i!Tex N' : 0,
|
||||
'85i!Tex Scramble' : 0,
|
||||
'86i!Tex Tile?' : 0,
|
||||
'87f!Tex Tile LLU' : 0.0,
|
||||
'88f!Tex Tile LLV' : 0.0,
|
||||
'89f!Tex Tile URU' : 0.0,
|
||||
'90f!Tex Tile URV' : 0.0,
|
||||
'91i!Projection' : 0,
|
||||
'92i!Earth Model' : 0,
|
||||
'93i!reserved25' : 0,
|
||||
'94i!UTM Zone' : 0,
|
||||
'95i!Image Origin' : 0,
|
||||
'96i!GPU' : 0,
|
||||
'97i!reserved26' : 0,
|
||||
'98i!reserved27' : 0,
|
||||
'99i!GPU Hemi' : 0,
|
||||
'100i!reserved41' : 0,
|
||||
'101i!reserved42' : 0,
|
||||
'102i!reserved43' : 0,
|
||||
'103i!Cubemap' : 0,
|
||||
'104t588!reserved44' : '',
|
||||
'105t512!Comments' : '',
|
||||
'106i!reserved28' : 0,
|
||||
'107i!reserved29' : 0,
|
||||
'108i!reserved30' : 0,
|
||||
'109i!reserved31' : 0,
|
||||
'110i!reserved32' : 0,
|
||||
'111i!reserved33' : 0,
|
||||
'112i!reserved34' : 0,
|
||||
'113i!reserved35' : 0,
|
||||
'114i!reserved36' : 0,
|
||||
'115i!reserved37' : 0,
|
||||
'116i!reserved38' : 0,
|
||||
'117i!reserved39' : 0,
|
||||
'118i!reserved40' : 0,
|
||||
'119i!reserved45' : 0,
|
||||
'120i!Format Version' : 0,
|
||||
'121i!GPU num' : 0,
|
||||
}
|
||||
|
||||
FLTImageDisplay = [18,19,29,21,22,23,24,25,26,62,63,64,65,66,67,68,69,70,74,75,76,77,78,79,93,97,98,102,114]
|
||||
|
||||
FLTHeader = {
|
||||
'3t8!id' : 'db',
|
||||
'4i!version' : 1620,
|
||||
'5i!editversion' : 0,
|
||||
'6t32!date' : 0,
|
||||
'7s!NGID' : 0,
|
||||
'8s!NLID' : 0,
|
||||
'9s!NOID' : 0,
|
||||
'10s!NFID' : 0,
|
||||
'11s!UMULT' : 1,
|
||||
'12c!units' : 0,
|
||||
'13c!set white' : 0,
|
||||
'14I!flags' : 0x80000000,
|
||||
'15i!reserved1' : 0,
|
||||
'16i!reserved2' : 0,
|
||||
'17i!reserved3' : 0,
|
||||
'18i!reserved4' : 0,
|
||||
'19i!reserved5' : 0,
|
||||
'20i!reserved6' : 0,
|
||||
'21i!projection type' : 0,
|
||||
'22i!reserved7' : 0,
|
||||
'23i!reserved8' : 0,
|
||||
'24i!reserved9' : 0,
|
||||
'25i!reserved10' : 0,
|
||||
'26i!reserved11' : 0,
|
||||
'27i!reserved12' : 0,
|
||||
'28i!reserved13' : 0,
|
||||
'29s!NDID' : 0,
|
||||
'30s!vstore' : 1,
|
||||
'31i!origin' : 0,
|
||||
'32d!sw x' : 0,
|
||||
'33d!sw y' : 0,
|
||||
'34d!dx' : 0,
|
||||
'35d!dy' : 0,
|
||||
'36s!NSID' : 0,
|
||||
'37s!NPID' : 0,
|
||||
'38i!reserved14' : 0,
|
||||
'39i!reserved15' : 0,
|
||||
'40s!NCID' : 0,
|
||||
'41s!NTID' : 0,
|
||||
'42s!NBID' : 0,
|
||||
'43s!NWID' : 0,
|
||||
'44i!reserved14' : 0,
|
||||
'45d!sw lat' : 0,
|
||||
'46d!sw lon' : 0,
|
||||
'47d!ne lat' : 0,
|
||||
'48d!ne lon' : 0,
|
||||
'49d!origin lat' : 0,
|
||||
'50d!origin lon' : 0,
|
||||
'51d!lambert lat1' : 0,
|
||||
'52d!lambert lat2' : 0,
|
||||
'53s!NLSID' : 0,
|
||||
'54s!NLPID' : 0,
|
||||
'55s!NRID' : 0,
|
||||
'56s!NCATID' : 0,
|
||||
'57s!reserved15' : 0,
|
||||
'58s!reserved16' : 0,
|
||||
'59s!reserved17' : 0,
|
||||
'60s!reserved18' : 0,
|
||||
'61i!ellipsoid model' : 1,
|
||||
'62s!NAID' : 0,
|
||||
'63s!NCVID' : 0,
|
||||
'64s!utm zone' : 0,
|
||||
'65t6!reserved19' : 0,
|
||||
'66d!dz' : 0,
|
||||
'67d!radius' : 0,
|
||||
'68S!NMID' : 0,
|
||||
'69S!NLPSID' : 0,
|
||||
'70i!reserved20' : 0,
|
||||
'71d!major axis' : 0,
|
||||
'72d!minor axis' : 0,
|
||||
}
|
||||
|
||||
FLT_Records = {
|
||||
2 : FLTGroup,
|
||||
4 : FLTObject,
|
||||
73 : FLTLOD,
|
||||
63 : FLTXRef,
|
||||
14 : FLTDOF,
|
||||
1 : FLTHeader,
|
||||
111 : FLTInlineLP,
|
||||
100 : FLTExt,
|
||||
'Image' : FLTImage
|
||||
}
|
||||
|
||||
def process_recordDefs():
|
||||
records = dict()
|
||||
for record in FLT_Records:
|
||||
props = dict()
|
||||
for prop in FLT_Records[record]:
|
||||
position = ''
|
||||
slice = 0
|
||||
(format,name) = prop.split('!')
|
||||
for i in format:
|
||||
if i not in typecodes:
|
||||
position = position + i
|
||||
slice = slice + 1
|
||||
else:
|
||||
break
|
||||
type = format[slice:]
|
||||
length = type[1:]
|
||||
if len(length) == 0:
|
||||
length = 1
|
||||
else:
|
||||
type = type[0]
|
||||
length = int(length)
|
||||
|
||||
props[int(position)] = (type,length,prop)
|
||||
records[record] = props
|
||||
return records
|
||||
|
||||
|
||||
@@ -1,809 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'FLT Toolbar'
|
||||
Blender: 240
|
||||
Group: 'Misc'
|
||||
Tooltip: 'Tools for working with FLT databases'
|
||||
"""
|
||||
|
||||
__author__ = "Geoffrey Bantle"
|
||||
__version__ = "1.0 11/21/07"
|
||||
__email__ = ('scripts', 'Author, ')
|
||||
__url__ = ('blender', 'blenderartists.org')
|
||||
|
||||
__bpydoc__ ="""\
|
||||
This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a
|
||||
registered trademark of MultiGen-Paradigm, Inc.
|
||||
|
||||
Feature overview and more availible at:
|
||||
http://wiki.blender.org/index.php/Scripts/Manual/FLTools
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# flt_palettemanager.py version 0.1 2005/04/08
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2007: Blender Foundation
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender.Draw as Draw
|
||||
from Blender.BGL import *
|
||||
import Blender
|
||||
import flt_properties
|
||||
reload(flt_properties)
|
||||
from flt_properties import *
|
||||
|
||||
xrefprefix = ""
|
||||
xrefstack = list()
|
||||
vofsstack = list()
|
||||
vquatstack = list()
|
||||
prop_w = 256
|
||||
prop_h = 256
|
||||
|
||||
|
||||
#event codes
|
||||
evcode = {
|
||||
"XREF_MAKE" : 100,
|
||||
"XREF_EDIT" : 101,
|
||||
"XREF_FILE" : 102,
|
||||
"XREF_PICK" : 103,
|
||||
"XREF_SELECT" : 104,
|
||||
"XREF_POP" : 105,
|
||||
"XREF_PREFIX" : 106,
|
||||
"FACE_NAME" : 200,
|
||||
"FACE_MAKESUB" : 201,
|
||||
"FACE_KILLSUB" : 202,
|
||||
"FACE_SELSUB" : 203,
|
||||
"SCENE_UPDATE" : 303,
|
||||
"IDPROP_COPY" : 501,
|
||||
"IDPROP_KILL" : 502,
|
||||
"CLIGHT_MAKE" : 700,
|
||||
"DFROMACT" : 701,
|
||||
"FIXCOL" : 702
|
||||
}
|
||||
|
||||
XREF_PREFIX = None
|
||||
XREF_MAKE = None
|
||||
XREF_EDIT = None
|
||||
XREF_SELECT = None
|
||||
XREF_POP = None
|
||||
FACE_MAKESUB = None
|
||||
FACE_SELSUB = None
|
||||
FACE_KILLSUB = None
|
||||
IDPROP_KILL = None
|
||||
IDPROP_COPY = None
|
||||
SCENE_UPDATE = None
|
||||
CLIGHT_MAKE = None
|
||||
DFROMACT = None
|
||||
FIXCOL = None
|
||||
|
||||
|
||||
def RGBtoHSV( r, g, b):
|
||||
cmin = min( r, g, b )
|
||||
cmax = max( r, g, b )
|
||||
v = cmax
|
||||
|
||||
if(cmax!=0.0):
|
||||
s = (cmax-cmin)/cmax
|
||||
else:
|
||||
s = 0.0
|
||||
h = 0.0
|
||||
|
||||
if(s == 0.0):
|
||||
h = -1.0
|
||||
else:
|
||||
cdelta = cmax-cmin
|
||||
rc = (cmax-r)/cdelta
|
||||
gc = (cmax-g)/cdelta
|
||||
bc = (cmax-b)/cdelta
|
||||
if(r==cmax):
|
||||
h = bc-gc
|
||||
else:
|
||||
if(g==cmax):
|
||||
h = 2.0+rc-bc
|
||||
else:
|
||||
h = 4.0+gc-rc
|
||||
h = h*60.0
|
||||
if(h<0.0):
|
||||
h += 360.0
|
||||
|
||||
|
||||
h = h/360.0
|
||||
if(h < 0.0):
|
||||
h = 0.0
|
||||
return (h,s,v)
|
||||
|
||||
|
||||
def update_state():
|
||||
state = dict()
|
||||
state["activeScene"] = Blender.Scene.GetCurrent()
|
||||
state["activeObject"] = state["activeScene"].objects.active
|
||||
if state["activeObject"] and not state["activeObject"].sel:
|
||||
state["activeObject"] = None
|
||||
state["activeMesh"] = None
|
||||
if state["activeObject"] and state["activeObject"].type == 'Mesh':
|
||||
state["activeMesh"] = state["activeObject"].getData(mesh=True)
|
||||
|
||||
state["activeFace"] = None
|
||||
if state["activeMesh"]:
|
||||
if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None:
|
||||
state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace]
|
||||
|
||||
#update editmode
|
||||
state["editmode"] = Blender.Window.EditMode()
|
||||
|
||||
return state
|
||||
def pack_face_index(index, intensity):
|
||||
return ((127*intensity)+(128*index))
|
||||
def unpack_face_index(face_index):
|
||||
index = face_index / 128
|
||||
intensity = float(face_index - 128.0 * index) / 127.0
|
||||
return(index,intensity)
|
||||
|
||||
def idprops_append(object, typecode, props):
|
||||
object.properties["FLT"] = dict()
|
||||
object.properties["FLT"]['type'] = typecode
|
||||
for prop in props:
|
||||
object.properties["FLT"][prop] = props[prop]
|
||||
object.properties["FLT"]['3t8!id'] = object.name
|
||||
|
||||
def idprops_kill(object):
|
||||
state = update_state()
|
||||
if object and object.properties.has_key('FLT'):
|
||||
object.properties.pop('FLT')
|
||||
|
||||
def idprops_copy(source):
|
||||
state = update_state()
|
||||
if source.properties.has_key('FLT'):
|
||||
for object in state["activeScene"].objects:
|
||||
if object.sel and object != source and (state["activeScene"].Layers & object.Layers):
|
||||
idprops_kill(object)
|
||||
object.properties['FLT'] = dict()
|
||||
for key in source.properties['FLT']:
|
||||
object.properties['FLT'][key] = source.properties['FLT'][key]
|
||||
|
||||
def unpack_color(color):
|
||||
return struct.unpack('>BBBB',struct.pack('>I',color))
|
||||
|
||||
|
||||
def findColorKey(colordict, hsv):
|
||||
hdelta = 0.001
|
||||
for key in colordict:
|
||||
if not (((hsv[0] < (key[0] + hdelta)) and (hsv[0] > (key[0] - hdelta))) and ((hsv[1] < (key[1] + hdelta)) and (hsv[1] > (key[1] - hdelta)))):
|
||||
return key
|
||||
return None
|
||||
|
||||
def hsvsort(a, b):
|
||||
(index1, mag1) = a
|
||||
(index2, mag2) = b
|
||||
if mag1 > mag2:
|
||||
return 1
|
||||
elif mag1 < mag2:
|
||||
return -1
|
||||
return 0
|
||||
|
||||
def fix_colors():
|
||||
|
||||
editmode = 0
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode = 1
|
||||
state = update_state()
|
||||
|
||||
scene = state["activeScene"]
|
||||
colors = None
|
||||
if state["activeScene"].properties.has_key('FLT'):
|
||||
try:
|
||||
colors = state["activeScene"].properties['FLT']['Color Palette']
|
||||
except:
|
||||
pass
|
||||
if not colors:
|
||||
return
|
||||
|
||||
#first build a HSV version of our palette
|
||||
hsvpalette = list()
|
||||
for swatch in colors:
|
||||
color = unpack_color(swatch)
|
||||
hsv = RGBtoHSV(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0)
|
||||
hsvpalette.append(hsv)
|
||||
|
||||
#collect all of our meshes
|
||||
meshes = list()
|
||||
for object in scene.objects.context:
|
||||
if object.sel and object.type == 'Mesh':
|
||||
mesh = object.getData(mesh=True)
|
||||
if "FLT_COL" in mesh.faces.properties:
|
||||
meshes.append(mesh)
|
||||
|
||||
|
||||
#Now go through our meshes, and build a dictionary of face lists keyed according to (hue,saturation) of the baked color
|
||||
colordict = dict()
|
||||
for mesh in meshes:
|
||||
for face in mesh.faces:
|
||||
hsv = RGBtoHSV(face.col[0].r/255.0, face.col[0].g/255.0, face.col[0].b/255.0) #retrieve baked color
|
||||
if colordict.has_key((hsv[0],hsv[1])):
|
||||
colordict[(hsv[0],hsv[1])].append(face)
|
||||
else:
|
||||
colordict[(hsv[0],hsv[1])] = [face]
|
||||
|
||||
|
||||
#for each color key in the color dict, build a list of distances from it to the values in hsvpalette and then quicksort them for closest match
|
||||
for key in colordict:
|
||||
maglist = list()
|
||||
for i, hsv in enumerate(hsvpalette):
|
||||
norm = Blender.Mathutils.Vector(hsv[0], hsv[1]) - Blender.Mathutils.Vector(key[0],key[1])
|
||||
maglist.append((i,norm.length))
|
||||
maglist.sort(hsvsort)
|
||||
print maglist[0]
|
||||
for face in colordict[key]:
|
||||
(index, intensity) = unpack_face_index(face.getProperty("FLT_COL"))
|
||||
newfindex = pack_face_index(maglist[0][0],intensity)
|
||||
face.setProperty("FLT_COL", int(newfindex))
|
||||
|
||||
for mesh in meshes:
|
||||
update_mesh_colors(colors,mesh)
|
||||
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
|
||||
def update_mesh_colors(colors, mesh):
|
||||
if 'FLT_COL' in mesh.faces.properties:
|
||||
mesh.activeColorLayer = "FLT_Fcol"
|
||||
for face in mesh.faces:
|
||||
(index,intensity) = unpack_face_index(face.getProperty('FLT_COL'))
|
||||
color = struct.unpack('>BBBB',struct.pack('>I',colors[index]))
|
||||
|
||||
if index == 0 and intensity == 0:
|
||||
color = (255,255,255)
|
||||
intensity = 1.0
|
||||
#update the vertex colors for this face
|
||||
for col in face.col:
|
||||
col.r = int(color[0] * intensity)
|
||||
col.g = int(color[1] * intensity)
|
||||
col.b = int(color[2] * intensity)
|
||||
col.a = 255
|
||||
|
||||
|
||||
def update_all():
|
||||
|
||||
editmode = 0
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode = 1
|
||||
state = update_state()
|
||||
colors = None
|
||||
if state["activeScene"].properties.has_key('FLT'):
|
||||
try:
|
||||
colors = state["activeScene"].properties['FLT']['Color Palette']
|
||||
except:
|
||||
pass
|
||||
if colors:
|
||||
#update the baked FLT colors for all meshes.
|
||||
for object in state["activeScene"].objects:
|
||||
if object.type == "Mesh":
|
||||
mesh = object.getData(mesh=True)
|
||||
update_mesh_colors(colors,mesh)
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
#Change this to find the deep parent
|
||||
def xref_create():
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
|
||||
state = update_state()
|
||||
|
||||
def findchildren(object):
|
||||
children = list()
|
||||
for candidate in state["activeScene"].objects:
|
||||
if candidate.parent == object:
|
||||
children.append(candidate)
|
||||
retlist = list(children)
|
||||
for child in children:
|
||||
retlist = retlist + findchildren(child)
|
||||
return retlist
|
||||
|
||||
actObject = state["activeObject"]
|
||||
if actObject and xrefprefix:
|
||||
scenenames = list()
|
||||
for scene in Blender.Scene.Get():
|
||||
scenenames.append(scene.name)
|
||||
|
||||
if xrefprefix in scenenames:
|
||||
#build a unique name for the xref...
|
||||
suffix = 1
|
||||
found = False
|
||||
while not found:
|
||||
candidate = xrefprefix + str(suffix)
|
||||
if not candidate in scenenames:
|
||||
xrefname = candidate
|
||||
found = True
|
||||
suffix+=1
|
||||
else:
|
||||
xrefname = xrefprefix
|
||||
#create our XRef node
|
||||
xnode = state["activeScene"].objects.new('Empty')
|
||||
xnode.name = 'X:' + xrefname
|
||||
xnode.properties['FLT'] = dict()
|
||||
for prop in FLTXRef:
|
||||
xnode.properties['FLT'][prop] = FLTXRef[prop]
|
||||
xnode.properties['FLT']['3t200!filename'] = xrefname + '.flt'
|
||||
xnode.properties['FLT']['type'] = 63
|
||||
xnode.enableDupGroup = True
|
||||
xnode.DupGroup = Blender.Group.New(xrefname) #this is dangerous... be careful!
|
||||
|
||||
#copy rot and loc of actObject
|
||||
xnode.setLocation(actObject.getLocation())
|
||||
xnode.setEuler(actObject.getEuler())
|
||||
|
||||
#build the new scene
|
||||
xrefscene = Blender.Scene.New(xrefname)
|
||||
xrefscene.properties['FLT'] = dict()
|
||||
xrefscene.properties['FLT']['Filename'] = xrefname
|
||||
xrefscene.properties['FLT']['Main'] = 0
|
||||
|
||||
#find the children of actObject so that we can add them to the group
|
||||
linkobjects = findchildren(actObject)
|
||||
linkobjects.append(actObject)
|
||||
for object in linkobjects:
|
||||
xrefscene.objects.link(object)
|
||||
state["activeScene"].objects.unlink(object)
|
||||
xnode.DupGroup.objects.link(object)
|
||||
#clear rotation of actObject and location
|
||||
actObject.setLocation(0.0,0.0,0.0)
|
||||
actObject.setEuler(0.0,0.0,0.0)
|
||||
|
||||
xrefscene.update(1)
|
||||
state["activeScene"].update(1)
|
||||
|
||||
def xref_select():
|
||||
state = update_state()
|
||||
candidates = list()
|
||||
scenelist = [scene.name for scene in Blender.Scene.Get()]
|
||||
for object in state["activeScene"].objects:
|
||||
if object.type == 'Empty' and object.enableDupGroup == True and object.DupGroup:
|
||||
candidates.append(object)
|
||||
|
||||
for object in candidates:
|
||||
if object.DupGroup.name in scenelist:
|
||||
object.sel = 1
|
||||
|
||||
def xref_edit():
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
|
||||
state = update_state()
|
||||
|
||||
actObject = state["activeObject"]
|
||||
|
||||
if actObject and actObject.type == 'Empty' and actObject.DupGroup:
|
||||
# if actObject.properties.has_key('FLT') and actObject.properties['FLT']['type'] == 63:
|
||||
for FLTscene in Blender.Scene.Get():
|
||||
if FLTscene.properties.has_key('FLT') and FLTscene.name == actObject.DupGroup.name:
|
||||
actObject.sel = 0
|
||||
xrefstack.append(state["activeScene"])
|
||||
vofsstack.append(Blender.Window.GetViewOffset())
|
||||
vquatstack.append(Blender.Window.GetViewQuat())
|
||||
FLTscene.makeCurrent()
|
||||
Blender.Window.SetViewOffset(0.0,0.0,0.0)
|
||||
|
||||
def xref_finish():
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
|
||||
state = update_state()
|
||||
if xrefstack:
|
||||
scene = xrefstack.pop()
|
||||
Blender.Window.SetViewQuat(vquatstack.pop())
|
||||
Blender.Window.SetViewOffset(vofsstack.pop())
|
||||
scene.makeCurrent()
|
||||
|
||||
|
||||
def sortSub(a,b):
|
||||
aindex = a.getProperty("FLT_ORIGINDEX")
|
||||
bindex = b.getProperty("FLT_ORIGINDEX")
|
||||
|
||||
if aindex > bindex:
|
||||
return 1
|
||||
elif aindex < bindex:
|
||||
return -1
|
||||
return 0
|
||||
|
||||
def subface_make():
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
|
||||
editmode = 0
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode = 1
|
||||
|
||||
state = update_state()
|
||||
|
||||
actmesh = state["activeMesh"]
|
||||
activeFace = state["activeFace"]
|
||||
if actmesh:
|
||||
if not "FLT_ORIGINDEX" in actmesh.faces.properties:
|
||||
actmesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"])
|
||||
for i, face in enumerate(actmesh.faces):
|
||||
face.setProperty("FLT_ORIGINDEX",i)
|
||||
if not "FLT_SFLEVEL" in actmesh.faces.properties:
|
||||
actmesh.faces.addPropertyLayer("FLT_SFLEVEL",Blender.Mesh.PropertyTypes["INT"])
|
||||
|
||||
#attach the subfaces to the active face. Note, this doesnt really work 100 percent properly yet, just enough for one level!
|
||||
if activeFace:
|
||||
#steps:
|
||||
#remove actface and selected faces from the facelist
|
||||
#quicksort facelist
|
||||
#append actface and subfaces to end of facelist.
|
||||
#generate new indices
|
||||
facelist = list()
|
||||
sublist = list()
|
||||
for face in actmesh.faces:
|
||||
facelist.append(face)
|
||||
for face in facelist:
|
||||
if face == activeFace:
|
||||
face.setProperty("FLT_SFLEVEL",0)
|
||||
sublist.insert(0,face)
|
||||
elif face.sel:
|
||||
face.setProperty("FLT_SFLEVEL",1)
|
||||
sublist.append(face)
|
||||
for face in sublist:
|
||||
facelist.remove(face)
|
||||
facelist.sort(sortSub)
|
||||
for face in sublist:
|
||||
facelist.append(face)
|
||||
for i, face in enumerate(facelist):
|
||||
face.setProperty("FLT_ORIGINDEX",i)
|
||||
else:
|
||||
pass
|
||||
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
def subface_kill():
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
|
||||
editmode = 0
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode = 1
|
||||
state = update_state()
|
||||
|
||||
actmesh = state["activeMesh"]
|
||||
if actmesh:
|
||||
if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties:
|
||||
for i,face in enumerate(actmesh.faces):
|
||||
face.setProperty("FLT_ORIGINDEX",i)
|
||||
face.setProperty("FLT_SFLEVEL",0)
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
def subface_select():
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
|
||||
editmode = 0
|
||||
if Blender.Window.EditMode():
|
||||
Blender.Window.EditMode(0)
|
||||
editmode = 1
|
||||
state = update_state()
|
||||
|
||||
actmesh = state["activeMesh"]
|
||||
activeFace = state["activeFace"]
|
||||
if actmesh and activeFace:
|
||||
if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties:
|
||||
facelist = list()
|
||||
actIndex = None
|
||||
sublevel = None
|
||||
for face in actmesh.faces:
|
||||
facelist.append(face)
|
||||
facelist.sort(sortSub)
|
||||
for i, face in enumerate(facelist):
|
||||
if face == activeFace:
|
||||
actIndex = i
|
||||
sublevel = face.getProperty("FLT_SFLEVEL")+1
|
||||
break
|
||||
leftover = facelist[actIndex+1:]
|
||||
for face in leftover:
|
||||
if face.getProperty("FLT_SFLEVEL") == sublevel:
|
||||
face.sel = 1
|
||||
else:
|
||||
break
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
def select_by_typecode(typecode):
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
|
||||
state = update_state()
|
||||
|
||||
for object in state["activeScene"].objects:
|
||||
if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers:
|
||||
object.select(1)
|
||||
def clight_make():
|
||||
state = update_state()
|
||||
actmesh = state["activeMesh"]
|
||||
actobj = state["activeObject"]
|
||||
|
||||
if actobj and actmesh:
|
||||
actobj.properties['FLT'] = dict()
|
||||
actobj.properties['FLT']['type'] = 111
|
||||
for prop in FLTInlineLP:
|
||||
actobj.properties['FLT'][prop] = FLTInlineLP[prop]
|
||||
|
||||
actmesh.verts.addPropertyLayer("FLT_VCOL", Blender.Mesh.PropertyTypes["INT"])
|
||||
for v in actmesh.verts:
|
||||
v.setProperty("FLT_VCOL", 83815)
|
||||
|
||||
def dfromact():
|
||||
state = update_state()
|
||||
actobj = state["activeObject"]
|
||||
actscene = state["activeScene"]
|
||||
dof = None
|
||||
|
||||
for object in actscene.objects.context:
|
||||
if object.sel and (object != actobj):
|
||||
if not dof:
|
||||
dof = object
|
||||
else:
|
||||
break
|
||||
|
||||
if not dof:
|
||||
return
|
||||
|
||||
if 'FLT' not in dof.properties:
|
||||
dof.properties['FLT'] = dict()
|
||||
|
||||
#Warning! assumes 1 BU == 10 meters.
|
||||
#do origin
|
||||
dof.properties['FLT']['5d!ORIGX'] = actobj.getLocation('worldspace')[0]*10.0
|
||||
dof.properties['FLT']['6d!ORIGY'] = actobj.getLocation('worldspace')[1]*10.0
|
||||
dof.properties['FLT']['7d!ORIGZ'] = actobj.getLocation('worldspace')[2]*10.0
|
||||
#do X axis
|
||||
x = Blender.Mathutils.Vector(1.0,0.0,0.0)
|
||||
x = x * actobj.getMatrix('worldspace')
|
||||
x = x * 10.0
|
||||
dof.properties['FLT']['8d!XAXIS-X'] = x[0]
|
||||
dof.properties['FLT']['9d!XAXIS-Y'] = x[1]
|
||||
dof.properties['FLT']['10d!XAXIS-Z'] = x[2]
|
||||
#do X/Y plane
|
||||
x = Blender.Mathutils.Vector(1.0,1.0,0.0)
|
||||
x.normalize()
|
||||
x = x * actobj.getMatrix('worldspace')
|
||||
x = x * 10.0
|
||||
dof.properties['FLT']['11d!XYPLANE-X'] = x[0]
|
||||
dof.properties['FLT']['12d!XYPLANE-Y'] = x[1]
|
||||
dof.properties['FLT']['13d!XZPLANE-Z'] = x[2]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def event(evt,val):
|
||||
if evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
|
||||
def but_event(evt):
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
global evcode
|
||||
|
||||
state = update_state()
|
||||
|
||||
#do Xref buttons
|
||||
if evt == evcode["XREF_PREFIX"]:
|
||||
xrefprefix = XREF_PREFIX.val
|
||||
if evt == evcode["XREF_EDIT"]:
|
||||
xref_edit()
|
||||
if evt == evcode["XREF_SELECT"]:
|
||||
xref_select()
|
||||
if evt == evcode["XREF_MAKE"]:
|
||||
xref_create()
|
||||
#do scene buttons
|
||||
if evt == evcode["SCENE_UPDATE"]:
|
||||
update_all()
|
||||
#do face buttons
|
||||
if evt == evcode["FACE_MAKESUB"]:
|
||||
subface_make()
|
||||
if evt== evcode["FACE_KILLSUB"]:
|
||||
subface_kill()
|
||||
if evt== evcode["FACE_SELSUB"]:
|
||||
subface_select()
|
||||
#common buttons
|
||||
if evt == evcode["IDPROP_KILL"]:
|
||||
if state["activeObject"]:
|
||||
idprops_kill(state["activeObject"])
|
||||
if evt == evcode["IDPROP_COPY"]:
|
||||
if state["activeObject"]:
|
||||
idprops_copy(state["activeObject"])
|
||||
if evt == evcode["XREF_POP"]:
|
||||
xref_finish()
|
||||
if evt == evcode["CLIGHT_MAKE"]:
|
||||
clight_make()
|
||||
if evt == evcode["DFROMACT"]:
|
||||
dfromact()
|
||||
if evt == evcode["FIXCOL"]:
|
||||
fix_colors()
|
||||
Draw.Redraw(1)
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
|
||||
def box(x,y,w,h,c,mode):
|
||||
glColor3f(c[0],c[1],c[2])
|
||||
if mode == "outline":
|
||||
glBegin(GL_LINE_LOOP)
|
||||
else:
|
||||
glBegin(GL_POLYGON)
|
||||
glVertex2i(x,y)
|
||||
glVertex2i(x+w,y)
|
||||
glVertex2i(x+w,y+h)
|
||||
glVertex2i(x,y+h)
|
||||
glEnd()
|
||||
|
||||
def draw_postcommon(x,y,finaly):
|
||||
global sheetlabel
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
global evcode
|
||||
|
||||
state = update_state()
|
||||
|
||||
width = prop_w
|
||||
height = prop_h
|
||||
|
||||
#draw the header
|
||||
glColor3f(0.15,0.15,0.15)
|
||||
glBegin(GL_POLYGON)
|
||||
glVertex2i(x-1,y)
|
||||
glVertex2i(x+width+1,y)
|
||||
glVertex2i(x+width+1,y-25)
|
||||
glVertex2i(x-1,y-25)
|
||||
glEnd()
|
||||
glColor3f(1,1,1)
|
||||
glRasterPos2i(x,y-20)
|
||||
sheetlabel = Blender.Draw.Text("FLT Tools Panel")
|
||||
#draw the box outline
|
||||
glColor3f(0,0,0)
|
||||
glBegin(GL_LINE_LOOP)
|
||||
glVertex2i(x-1,y)
|
||||
glVertex2i(x+1+width,y)
|
||||
glVertex2i(x+1+width,finaly-1)
|
||||
glVertex2i(x-1,finaly-1)
|
||||
glEnd()
|
||||
return finaly
|
||||
|
||||
|
||||
def draw_propsheet(x,y):
|
||||
global XREF_PREFIX
|
||||
global XREF_MAKE
|
||||
global XREF_EDIT
|
||||
global XREF_SELECT
|
||||
global XREF_POP
|
||||
global FACE_MAKESUB
|
||||
global FACE_SELSUB
|
||||
global FACE_KILLSUB
|
||||
global IDPROP_KILL
|
||||
global IDPROP_COPY
|
||||
global SCENE_UPDATE
|
||||
global DFROMACT
|
||||
global FIXCOL
|
||||
|
||||
global CLIGHT_MAKE
|
||||
global xrefprefix
|
||||
global xrefstack
|
||||
global vofsstack
|
||||
global vquatstack
|
||||
global prop_w
|
||||
global prop_h
|
||||
global evcode
|
||||
|
||||
state = update_state()
|
||||
|
||||
width = prop_w
|
||||
height = prop_h
|
||||
origx = x
|
||||
origy = y
|
||||
|
||||
#draw Xref tools
|
||||
y = y-20
|
||||
XREF_PREFIX = Blender.Draw.String("XRef Name:",evcode["XREF_PREFIX"],x,y,width,20,xrefprefix,18,"Xref prefix name, Actual name is generated from this")
|
||||
y = y-20
|
||||
XREF_MAKE = Blender.Draw.PushButton("Make XRef",evcode["XREF_MAKE"],x,y,width,20,"Make External Reference")
|
||||
y = y-20
|
||||
XREF_EDIT = Blender.Draw.PushButton("Edit XRef",evcode["XREF_EDIT"],x,y,width,20,"Edit External Reference")
|
||||
y = y-20
|
||||
XREF_SELECT = Blender.Draw.PushButton("Select XRefs",evcode["XREF_SELECT"],x,y,width,20,"Select External References")
|
||||
y = y - 20
|
||||
XREF_POP = Blender.Draw.PushButton("Return to previous scene",evcode["XREF_POP"],x,y,width,20,"Go up one level in xref hierarchy")
|
||||
|
||||
#Draw facetools
|
||||
y = y-20
|
||||
FACE_MAKESUB = Blender.Draw.PushButton("Make Subfaces",evcode["FACE_MAKESUB"],x,y,width,20,"Make subfaces")
|
||||
y = y-20
|
||||
FACE_SELSUB = Blender.Draw.PushButton("Select Subfaces",evcode["FACE_SELSUB"],x,y,width,20,"Select subfaces")
|
||||
y = y-20
|
||||
FACE_KILLSUB = Blender.Draw.PushButton("Kill Subfaces",evcode["FACE_KILLSUB"],x,y,width,20,"Kill subfaces")
|
||||
|
||||
#Draw ID Property tools
|
||||
y = y - 20
|
||||
IDPROP_KILL = Blender.Draw.PushButton("Delete ID props",evcode["IDPROP_KILL"],x,y,width,20,"Delete ID props")
|
||||
y = y - 20
|
||||
IDPROP_COPY = Blender.Draw.PushButton("Copy to selected",evcode["IDPROP_COPY"],x,y,width,20, "Copy from active to all selected")
|
||||
|
||||
y= y - 20
|
||||
CLIGHT_MAKE = Blender.Draw.PushButton("Make Light Point", evcode["CLIGHT_MAKE"],x,y,width,20,"Create inline light points from current mesh")
|
||||
#General tools
|
||||
y = y-20
|
||||
SCENE_UPDATE = Blender.Draw.PushButton("Update All",evcode["SCENE_UPDATE"],x,y,width,20,"Update all vertex colors")
|
||||
|
||||
y=y-20
|
||||
DFROMACT = Blender.Draw.PushButton("Dof from Active", evcode["DFROMACT"],x,y,width,20,"Get Dof origin from active object")
|
||||
y=y-20
|
||||
FIXCOL = Blender.Draw.PushButton("Fix Colors", evcode["FIXCOL"],x,y,width,20,"Fix baked FLT colors of selected meshes")
|
||||
draw_postcommon(origx, origy,y)
|
||||
|
||||
def gui():
|
||||
#draw the propsheet/toolbox.
|
||||
psheety = 300
|
||||
#psheetx = psheety + 10
|
||||
draw_propsheet(0,psheety)
|
||||
Draw.Register(gui,event,but_event)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Blender/Python Scripting API'
|
||||
Blender: 248
|
||||
Group: 'Help'
|
||||
Tooltip: 'The Blender Python API reference manual'
|
||||
"""
|
||||
|
||||
__author__ = "Matt Ebb"
|
||||
__url__ = ("blender", "blenderartist")
|
||||
__version__ = "1.0.1"
|
||||
__bpydoc__ = """\
|
||||
This script opens the user's default web browser at http://www.blender.org's
|
||||
"Blender Python API Reference" page.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Blender/Python Scripting Reference Help Menu Item
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
try: import webbrowser
|
||||
except: webbrowser = None
|
||||
|
||||
if webbrowser:
|
||||
version = str(int(Blender.Get('version')))
|
||||
webbrowser.open('http://www.blender.org/documentation/'+ version +'PythonDoc/')
|
||||
else:
|
||||
Blender.Draw.PupMenu("Error%t|This script requires a full python installation")
|
||||
@@ -1,814 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Scripts Help Browser'
|
||||
Blender: 234
|
||||
Group: 'Help'
|
||||
Tooltip: 'Show help information about a chosen installed script.'
|
||||
"""
|
||||
|
||||
__author__ = "Willian P. Germano"
|
||||
__version__ = "0.3 01/21/09"
|
||||
__email__ = ('scripts', 'Author, wgermano:ig*com*br')
|
||||
__url__ = ('blender', 'blenderartists.org')
|
||||
|
||||
__bpydoc__ ="""\
|
||||
This script shows help information for scripts registered in the menus.
|
||||
|
||||
Usage:
|
||||
|
||||
- Start Screen:
|
||||
|
||||
To read any script's "user manual" select a script from one of the
|
||||
available category menus. If the script has help information in the format
|
||||
expected by this Help Browser, it will be displayed in the Script Help
|
||||
Screen. Otherwise you'll be offered the possibility of loading the chosen
|
||||
script's source file in Blender's Text Editor. The programmer(s) may have
|
||||
written useful comments there for users.
|
||||
|
||||
Hotkeys:<br>
|
||||
ESC or Q: [Q]uit
|
||||
|
||||
- Script Help Screen:
|
||||
|
||||
This screen shows the user manual page for the chosen script. If the text
|
||||
doesn't fit completely on the screen, you can scroll it up or down with
|
||||
arrow keys or a mouse wheel. There may be link and email buttons that if
|
||||
clicked should open your default web browser and email client programs for
|
||||
further information or support.
|
||||
|
||||
Hotkeys:<br>
|
||||
ESC: back to Start Screen<br>
|
||||
Q: [Q]uit<br>
|
||||
S: view script's [S]ource code in Text Editor<br>
|
||||
UP, DOWN Arrows and mouse wheel: scroll text up / down
|
||||
"""
|
||||
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
# Thanks: Brendon Murphy (suggestion) and Kevin Morgan (implementation)
|
||||
# for the "run" button; Jean-Michel Soler for pointing a parsing error
|
||||
# with multilines using triple single quotes.
|
||||
|
||||
import Blender
|
||||
from Blender import sys as bsys, Draw, Window, Registry
|
||||
|
||||
WEBBROWSER = True
|
||||
try:
|
||||
import webbrowser
|
||||
except:
|
||||
WEBBROWSER = False
|
||||
|
||||
DEFAULT_EMAILS = {
|
||||
'scripts': ['Bf-scripts-dev', 'bf-scripts-dev@blender.org']
|
||||
}
|
||||
|
||||
DEFAULT_LINKS = {
|
||||
'blender': ["blender.org\'s Python forum", "http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewforum&f=9"]
|
||||
}
|
||||
|
||||
PADDING = 15
|
||||
COLUMNS = 1
|
||||
TEXT_WRAP = 100
|
||||
WIN_W = WIN_H = 200
|
||||
SCROLL_DOWN = 0
|
||||
|
||||
def screen_was_resized():
|
||||
global WIN_W, WIN_H
|
||||
|
||||
w, h = Window.GetAreaSize()
|
||||
if WIN_W != w or WIN_H != h:
|
||||
WIN_W = w
|
||||
WIN_H = h
|
||||
return True
|
||||
return False
|
||||
|
||||
def fit_on_screen():
|
||||
global TEXT_WRAP, PADDING, WIN_W, WIN_H, COLUMNS
|
||||
|
||||
COLUMNS = 1
|
||||
WIN_W, WIN_H = Window.GetAreaSize()
|
||||
TEXT_WRAP = int((WIN_W - PADDING) / 6)
|
||||
if TEXT_WRAP < 40:
|
||||
TEXT_WRAP = 40
|
||||
elif TEXT_WRAP > 100:
|
||||
if TEXT_WRAP > 110:
|
||||
COLUMNS = 2
|
||||
TEXT_WRAP /= 2
|
||||
else: TEXT_WRAP = 100
|
||||
|
||||
def cut_point(text, length):
|
||||
"Returns position of the last space found before 'length' chars"
|
||||
l = length
|
||||
c = text[l]
|
||||
while c != ' ':
|
||||
l -= 1
|
||||
if l == 0: return length # no space found
|
||||
c = text[l]
|
||||
return l
|
||||
|
||||
def text_wrap(text, length = None):
|
||||
global TEXT_WRAP
|
||||
|
||||
wrapped = []
|
||||
lines = text.split('<br>')
|
||||
llen = len(lines)
|
||||
if llen > 1:
|
||||
if lines[-1] == '': llen -= 1
|
||||
for i in range(llen - 1):
|
||||
lines[i] = lines[i].rstrip() + '<br>'
|
||||
lines[llen-1] = lines[llen-1].rstrip()
|
||||
|
||||
if not length: length = TEXT_WRAP
|
||||
|
||||
for l in lines:
|
||||
while len(l) > length:
|
||||
cpt = cut_point(l, length)
|
||||
line, l = l[:cpt], l[cpt + 1:]
|
||||
wrapped.append(line)
|
||||
wrapped.append(l)
|
||||
return wrapped
|
||||
|
||||
def load_script_text(script):
|
||||
global PATHS, SCRIPT_INFO
|
||||
|
||||
if script.userdir:
|
||||
path = PATHS['uscripts']
|
||||
else:
|
||||
path = PATHS['scripts']
|
||||
|
||||
fname = bsys.join(path, script.fname)
|
||||
|
||||
source = Blender.Text.Load(fname)
|
||||
if source:
|
||||
Draw.PupMenu("File loaded%%t|Please check the file \"%s\" in the Text Editor window" % source.name)
|
||||
|
||||
|
||||
# for theme colors:
|
||||
def float_colors(cols):
|
||||
return map(lambda x: x / 255.0, cols)
|
||||
|
||||
# globals
|
||||
|
||||
SCRIPT_INFO = None
|
||||
|
||||
PATHS = {
|
||||
'home': Blender.Get('homedir'),
|
||||
'scripts': Blender.Get('scriptsdir'),
|
||||
'uscripts': Blender.Get('uscriptsdir')
|
||||
}
|
||||
|
||||
if not PATHS['home']:
|
||||
errmsg = """
|
||||
Can't find Blender's home dir and so can't find the
|
||||
Bpymenus file automatically stored inside it, which
|
||||
is needed by this script. Please run the
|
||||
Help -> System -> System Information script to get
|
||||
information about how to fix this.
|
||||
"""
|
||||
raise SystemError, errmsg
|
||||
|
||||
BPYMENUS_FILE = bsys.join(PATHS['home'], 'Bpymenus')
|
||||
|
||||
f = file(BPYMENUS_FILE, 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
AllGroups = []
|
||||
|
||||
class Script:
|
||||
|
||||
def __init__(self, data):
|
||||
self.name = data[0]
|
||||
self.version = data[1]
|
||||
self.fname = data[2]
|
||||
self.userdir = data[3]
|
||||
self.tip = data[4]
|
||||
|
||||
# End of class Script
|
||||
|
||||
|
||||
class Group:
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.scripts = []
|
||||
|
||||
def add_script(self, script):
|
||||
self.scripts.append(script)
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_scripts(self):
|
||||
return self.scripts
|
||||
|
||||
# End of class Group
|
||||
|
||||
|
||||
class BPy_Info:
|
||||
|
||||
def __init__(self, script, dict):
|
||||
|
||||
self.script = script
|
||||
|
||||
self.d = dict
|
||||
|
||||
self.header = []
|
||||
self.len_header = 0
|
||||
self.content = []
|
||||
self.len_content = 0
|
||||
self.spaces = 0
|
||||
self.fix_urls()
|
||||
self.make_header()
|
||||
self.wrap_lines()
|
||||
|
||||
def make_header(self):
|
||||
|
||||
sc = self.script
|
||||
d = self.d
|
||||
|
||||
header = self.header
|
||||
|
||||
title = "Script: %s" % sc.name
|
||||
version = "Version: %s for Blender %1.2f or newer" % (d['__version__'],
|
||||
sc.version / 100.0)
|
||||
|
||||
if len(d['__author__']) == 1:
|
||||
asuffix = ':'
|
||||
else: asuffix = 's:'
|
||||
|
||||
authors = "%s%s %s" % ("Author", asuffix, ", ".join(d['__author__']))
|
||||
|
||||
header.append(title)
|
||||
header.append(version)
|
||||
header.append(authors)
|
||||
self.len_header = len(header)
|
||||
|
||||
|
||||
def fix_urls(self):
|
||||
|
||||
emails = self.d['__email__']
|
||||
fixed = []
|
||||
for a in emails:
|
||||
if a in DEFAULT_EMAILS.keys():
|
||||
fixed.append(DEFAULT_EMAILS[a])
|
||||
else:
|
||||
a = a.replace('*','.').replace(':','@')
|
||||
ltmp = a.split(',')
|
||||
if len(ltmp) != 2:
|
||||
ltmp = [ltmp[0], ltmp[0]]
|
||||
fixed.append(ltmp)
|
||||
|
||||
self.d['__email__'] = fixed
|
||||
|
||||
links = self.d['__url__']
|
||||
fixed = []
|
||||
for a in links:
|
||||
if a in DEFAULT_LINKS.keys():
|
||||
fixed.append(DEFAULT_LINKS[a])
|
||||
else:
|
||||
ltmp = a.split(',')
|
||||
if len(ltmp) != 2:
|
||||
ltmp = [ltmp[0], ltmp[0]]
|
||||
fixed.append([ltmp[0].strip(), ltmp[1].strip()])
|
||||
|
||||
self.d['__url__'] = fixed
|
||||
|
||||
|
||||
def wrap_lines(self, reset = 0):
|
||||
|
||||
lines = self.d['__bpydoc__'].split('\n')
|
||||
self.content = []
|
||||
newlines = []
|
||||
newline = []
|
||||
|
||||
if reset:
|
||||
self.len_content = 0
|
||||
self.spaces = 0
|
||||
|
||||
for l in lines:
|
||||
if l == '' and newline:
|
||||
newlines.append(newline)
|
||||
newline = []
|
||||
newlines.append('')
|
||||
else: newline.append(l)
|
||||
if newline: newlines.append(newline)
|
||||
|
||||
for lst in newlines:
|
||||
wrapped = text_wrap(" ".join(lst))
|
||||
for l in wrapped:
|
||||
self.content.append(l)
|
||||
if l: self.len_content += 1
|
||||
else: self.spaces += 1
|
||||
|
||||
if not self.content[-1]:
|
||||
self.len_content -= 1
|
||||
|
||||
|
||||
# End of class BPy_Info
|
||||
|
||||
def parse_pyobj_close(closetag, lines, i):
|
||||
i += 1
|
||||
l = lines[i]
|
||||
while l.find(closetag) < 0:
|
||||
i += 1
|
||||
l = "%s%s" % (l, lines[i])
|
||||
return [l, i]
|
||||
|
||||
def parse_pyobj(var, lines, i):
|
||||
"Bad code, was in a hurry for release"
|
||||
|
||||
l = lines[i].replace(var, '').replace('=','',1).strip()
|
||||
|
||||
i0 = i - 1
|
||||
|
||||
if l[0] == '"':
|
||||
if l[1:3] == '""': # """
|
||||
if l.find('"""', 3) < 0: # multiline
|
||||
l2, i = parse_pyobj_close('"""', lines, i)
|
||||
if l[-1] == '\\': l = l[:-1]
|
||||
l = "%s%s" % (l, l2)
|
||||
elif l[-1] == '"' and l[-2] != '\\': # single line: "..."
|
||||
pass
|
||||
else:
|
||||
l = "ERROR"
|
||||
|
||||
elif l[0] == "'":
|
||||
if l[1:3] == "''": # '''
|
||||
if l.find("'''", 3) < 0: # multiline
|
||||
l2, i = parse_pyobj_close("'''", lines, i)
|
||||
if l[-1] == '\\': l = l[:-1]
|
||||
l = "%s%s" % (l, l2)
|
||||
elif l[-1] == '\\':
|
||||
l2, i = parse_pyobj_close("'", lines, i)
|
||||
l = "%s%s" % (l, l2)
|
||||
elif l[-1] == "'" and l[-2] != '\\': # single line: '...'
|
||||
pass
|
||||
else:
|
||||
l = "ERROR"
|
||||
|
||||
elif l[0] == '(':
|
||||
if l[-1] != ')':
|
||||
l2, i = parse_pyobj_close(')', lines, i)
|
||||
l = "%s%s" % (l, l2)
|
||||
|
||||
elif l[0] == '[':
|
||||
if l[-1] != ']':
|
||||
l2, i = parse_pyobj_close(']', lines, i)
|
||||
l = "%s%s" % (l, l2)
|
||||
|
||||
return [l, i - i0]
|
||||
|
||||
# helper functions:
|
||||
|
||||
def parse_help_info(script):
|
||||
|
||||
global PATHS, SCRIPT_INFO
|
||||
|
||||
if script.userdir:
|
||||
path = PATHS['uscripts']
|
||||
else:
|
||||
path = PATHS['scripts']
|
||||
|
||||
fname = bsys.join(path, script.fname)
|
||||
|
||||
if not bsys.exists(fname):
|
||||
Draw.PupMenu('IO Error: couldn\'t find script %s' % fname)
|
||||
return None
|
||||
|
||||
f = file(fname, 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
# fix line endings:
|
||||
if lines[0].find('\r'):
|
||||
unixlines = []
|
||||
for l in lines:
|
||||
unixlines.append(l.replace('\r',''))
|
||||
lines = unixlines
|
||||
|
||||
llen = len(lines)
|
||||
has_doc = 0
|
||||
|
||||
doc_data = {
|
||||
'__author__': '',
|
||||
'__version__': '',
|
||||
'__url__': '',
|
||||
'__email__': '',
|
||||
'__bpydoc__': '',
|
||||
'__doc__': ''
|
||||
}
|
||||
|
||||
i = 0
|
||||
while i < llen:
|
||||
l = lines[i]
|
||||
incr = 1
|
||||
for k in doc_data.keys():
|
||||
if l.find(k, 0, 20) == 0:
|
||||
value, incr = parse_pyobj(k, lines, i)
|
||||
exec("doc_data['%s'] = %s" % (k, value))
|
||||
has_doc = 1
|
||||
break
|
||||
i += incr
|
||||
|
||||
# fix these to seqs, simplifies coding elsewhere
|
||||
for w in ['__author__', '__url__', '__email__']:
|
||||
val = doc_data[w]
|
||||
if val and type(val) == str:
|
||||
doc_data[w] = [doc_data[w]]
|
||||
|
||||
if not doc_data['__bpydoc__']:
|
||||
if doc_data['__doc__']:
|
||||
doc_data['__bpydoc__'] = doc_data['__doc__']
|
||||
|
||||
if has_doc: # any data, maybe should confirm at least doc/bpydoc
|
||||
info = BPy_Info(script, doc_data)
|
||||
SCRIPT_INFO = info
|
||||
return True
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def parse_script_line(l):
|
||||
|
||||
tip = 'No tooltip'
|
||||
try:
|
||||
pieces = l.split("'")
|
||||
name = pieces[1].replace('...','')
|
||||
data = pieces[2].strip().split()
|
||||
version = data[0]
|
||||
userdir = data[-1]
|
||||
fname = data[1]
|
||||
i = 1
|
||||
while not fname.endswith('.py'):
|
||||
i += 1
|
||||
fname = '%s %s' % (fname, data[i])
|
||||
if len(pieces) > 3: tip = pieces[3]
|
||||
except:
|
||||
return None
|
||||
|
||||
return [name, int(version), fname, int(userdir), tip]
|
||||
|
||||
|
||||
def parse_bpymenus(lines):
|
||||
|
||||
global AllGroups
|
||||
|
||||
llen = len(lines)
|
||||
|
||||
for i in range(llen):
|
||||
l = lines[i].strip()
|
||||
if not l: continue
|
||||
if l[-1] == '{':
|
||||
group = Group(l[:-2])
|
||||
AllGroups.append(group)
|
||||
i += 1
|
||||
l = lines[i].strip()
|
||||
while l != '}':
|
||||
if l[0] != '|':
|
||||
data = parse_script_line(l)
|
||||
if data:
|
||||
script = Script(data)
|
||||
group.add_script(script)
|
||||
i += 1
|
||||
l = lines[i].strip()
|
||||
|
||||
# AllGroups.reverse()
|
||||
|
||||
|
||||
def create_group_menus():
|
||||
|
||||
global AllGroups
|
||||
menus = []
|
||||
|
||||
for group in AllGroups:
|
||||
|
||||
name = group.get_name()
|
||||
menu = []
|
||||
scripts = group.get_scripts()
|
||||
for s in scripts: menu.append(s.name)
|
||||
menu = "|".join(menu)
|
||||
menu = "%s%%t|%s" % (name, menu)
|
||||
menus.append([name, menu])
|
||||
|
||||
return menus
|
||||
|
||||
|
||||
# Collecting data:
|
||||
fit_on_screen()
|
||||
parse_bpymenus(lines)
|
||||
GROUP_MENUS = create_group_menus()
|
||||
|
||||
|
||||
# GUI:
|
||||
|
||||
from Blender import BGL
|
||||
from Blender.Window import Theme
|
||||
|
||||
# globals:
|
||||
|
||||
START_SCREEN = 0
|
||||
SCRIPT_SCREEN = 1
|
||||
|
||||
SCREEN = START_SCREEN
|
||||
|
||||
# gui buttons:
|
||||
len_gmenus = len(GROUP_MENUS)
|
||||
|
||||
BUT_GMENU = range(len_gmenus)
|
||||
for i in range(len_gmenus):
|
||||
BUT_GMENU[i] = Draw.Create(0)
|
||||
|
||||
# events:
|
||||
BEVT_LINK = None # range(len(SCRIPT_INFO.links))
|
||||
BEVT_EMAIL = None # range(len(SCRIPT_INFO.emails))
|
||||
BEVT_GMENU = range(100, len_gmenus + 100)
|
||||
BEVT_VIEWSOURCE = 1
|
||||
BEVT_EXIT = 2
|
||||
BEVT_BACK = 3
|
||||
BEVT_EXEC = 4 # Executes Script
|
||||
|
||||
# gui callbacks:
|
||||
|
||||
def gui(): # drawing the screen
|
||||
|
||||
global SCREEN, START_SCREEN, SCRIPT_SCREEN
|
||||
global SCRIPT_INFO, AllGroups, GROUP_MENUS
|
||||
global BEVT_EMAIL, BEVT_LINK
|
||||
global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU, BEVT_EXEC
|
||||
global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS, FMODE
|
||||
|
||||
theme = Theme.Get()[0]
|
||||
tui = theme.get('ui')
|
||||
ttxt = theme.get('text')
|
||||
|
||||
COL_BG = float_colors(ttxt.back)
|
||||
COL_TXT = ttxt.text
|
||||
COL_TXTHI = ttxt.text_hi
|
||||
|
||||
BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3])
|
||||
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
|
||||
BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
|
||||
|
||||
resize = screen_was_resized()
|
||||
if resize: fit_on_screen()
|
||||
|
||||
if SCREEN == START_SCREEN:
|
||||
x = PADDING
|
||||
bw = 85
|
||||
bh = 25
|
||||
hincr = 50
|
||||
|
||||
butcolumns = (WIN_W - 2*x)/ bw
|
||||
if butcolumns < 2: butcolumns = 2
|
||||
elif butcolumns > 7: butcolumns = 7
|
||||
|
||||
len_gm = len(GROUP_MENUS)
|
||||
butlines = len_gm / butcolumns
|
||||
if len_gm % butcolumns: butlines += 1
|
||||
|
||||
h = hincr * butlines + 20
|
||||
y = h + bh
|
||||
|
||||
BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text('Scripts Help Browser')
|
||||
|
||||
y -= bh
|
||||
|
||||
BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
for group_menu in GROUP_MENUS:
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text(group_menu[0]+':')
|
||||
BUT_GMENU[j] = Draw.Menu(group_menu[1], BEVT_GMENU[j],
|
||||
x, y-bh-5, bw, bh, 0,
|
||||
'Choose a script to read its help information')
|
||||
if i == butcolumns - 1:
|
||||
x = PADDING
|
||||
i = 0
|
||||
y -= hincr
|
||||
else:
|
||||
i += 1
|
||||
x += bw + 3
|
||||
j += 1
|
||||
|
||||
x = PADDING
|
||||
y = 10
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text('Select script for its help. Press Q or ESC to leave.')
|
||||
|
||||
elif SCREEN == SCRIPT_SCREEN:
|
||||
if SCRIPT_INFO:
|
||||
|
||||
if resize:
|
||||
SCRIPT_INFO.wrap_lines(1)
|
||||
SCROLL_DOWN = 0
|
||||
|
||||
h = 18 * SCRIPT_INFO.len_content + 12 * SCRIPT_INFO.spaces
|
||||
x = PADDING
|
||||
y = WIN_H
|
||||
bw = 38
|
||||
bh = 16
|
||||
|
||||
BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
|
||||
for line in SCRIPT_INFO.header:
|
||||
y -= 18
|
||||
BGL.glRasterPos2i(x, y)
|
||||
size = Draw.Text(line)
|
||||
|
||||
for line in text_wrap('Tooltip: %s' % SCRIPT_INFO.script.tip):
|
||||
y -= 18
|
||||
BGL.glRasterPos2i(x, y)
|
||||
size = Draw.Text(line)
|
||||
|
||||
i = 0
|
||||
y -= 28
|
||||
for data in SCRIPT_INFO.d['__url__']:
|
||||
Draw.PushButton('link %d' % (i + 1), BEVT_LINK[i],
|
||||
x + i*bw, y, bw, bh, data[0])
|
||||
i += 1
|
||||
y -= bh + 1
|
||||
|
||||
i = 0
|
||||
for data in SCRIPT_INFO.d['__email__']:
|
||||
Draw.PushButton('email', BEVT_EMAIL[i], x + i*bw, y, bw, bh, data[0])
|
||||
i += 1
|
||||
y -= 18
|
||||
|
||||
y0 = y
|
||||
BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
|
||||
for line in SCRIPT_INFO.content[SCROLL_DOWN:]:
|
||||
if line:
|
||||
line = line.replace('<br>', '')
|
||||
BGL.glRasterPos2i(x, y)
|
||||
Draw.Text(line)
|
||||
y -= 18
|
||||
else: y -= 12
|
||||
if y < PADDING + 20: # reached end, either stop or go to 2nd column
|
||||
if COLUMNS == 1: break
|
||||
elif x == PADDING: # make sure we're still in column 1
|
||||
x = 6*TEXT_WRAP + PADDING / 2
|
||||
y = y0
|
||||
|
||||
x = PADDING
|
||||
Draw.PushButton('source', BEVT_VIEWSOURCE, x, 17, 45, bh,
|
||||
'View this script\'s source code in the Text Editor (hotkey: S)')
|
||||
Draw.PushButton('exit', BEVT_EXIT, x + 45, 17, 45, bh,
|
||||
'Exit from Scripts Help Browser (hotkey: Q)')
|
||||
if not FMODE:
|
||||
Draw.PushButton('back', BEVT_BACK, x + 2*45, 17, 45, bh,
|
||||
'Back to scripts selection screen (hotkey: ESC)')
|
||||
Draw.PushButton('run script', BEVT_EXEC, x + 3*45, 17, 60, bh, 'Run this script')
|
||||
|
||||
BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
|
||||
BGL.glRasterPos2i(x, 5)
|
||||
Draw.Text('use the arrow keys or the mouse wheel to scroll text', 'small')
|
||||
|
||||
def fit_scroll():
|
||||
global SCROLL_DOWN
|
||||
if not SCRIPT_INFO:
|
||||
SCROLL_DOWN = 0
|
||||
return
|
||||
max = SCRIPT_INFO.len_content + SCRIPT_INFO.spaces - 1
|
||||
if SCROLL_DOWN > max: SCROLL_DOWN = max
|
||||
if SCROLL_DOWN < 0: SCROLL_DOWN = 0
|
||||
|
||||
|
||||
def event(evt, val): # input events
|
||||
|
||||
global SCREEN, START_SCREEN, SCRIPT_SCREEN
|
||||
global SCROLL_DOWN, FMODE
|
||||
|
||||
if not val: return
|
||||
|
||||
if evt == Draw.ESCKEY:
|
||||
if SCREEN == START_SCREEN or FMODE: Draw.Exit()
|
||||
else:
|
||||
SCREEN = START_SCREEN
|
||||
SCROLL_DOWN = 0
|
||||
Draw.Redraw()
|
||||
return
|
||||
elif evt == Draw.QKEY:
|
||||
Draw.Exit()
|
||||
return
|
||||
elif evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE] and SCREEN == SCRIPT_SCREEN:
|
||||
SCROLL_DOWN += 1
|
||||
fit_scroll()
|
||||
Draw.Redraw()
|
||||
return
|
||||
elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE] and SCREEN == SCRIPT_SCREEN:
|
||||
SCROLL_DOWN -= 1
|
||||
fit_scroll()
|
||||
Draw.Redraw()
|
||||
return
|
||||
elif evt == Draw.SKEY:
|
||||
if SCREEN == SCRIPT_SCREEN and SCRIPT_INFO:
|
||||
load_script_text(SCRIPT_INFO.script)
|
||||
return
|
||||
|
||||
def button_event(evt): # gui button events
|
||||
|
||||
global SCREEN, START_SCREEN, SCRIPT_SCREEN
|
||||
global BEVT_LINK, BEVT_EMAIL, BEVT_GMENU, BUT_GMENU, SCRIPT_INFO
|
||||
global SCROLL_DOWN, FMODE
|
||||
|
||||
if evt >= 100: # group menus
|
||||
for i in range(len(BUT_GMENU)):
|
||||
if evt == BEVT_GMENU[i]:
|
||||
group = AllGroups[i]
|
||||
index = BUT_GMENU[i].val - 1
|
||||
if index < 0: return # user didn't pick a menu entry
|
||||
script = group.get_scripts()[BUT_GMENU[i].val - 1]
|
||||
if parse_help_info(script):
|
||||
SCREEN = SCRIPT_SCREEN
|
||||
BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20)
|
||||
BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50)
|
||||
Draw.Redraw()
|
||||
else:
|
||||
res = Draw.PupMenu("No help available%t|View Source|Cancel")
|
||||
if res == 1:
|
||||
load_script_text(script)
|
||||
elif evt >= 20:
|
||||
if not WEBBROWSER:
|
||||
Draw.PupMenu('Missing standard Python module%t|You need module "webbrowser" to access the web')
|
||||
return
|
||||
|
||||
if evt >= 50: # script screen email buttons
|
||||
email = SCRIPT_INFO.d['__email__'][evt - 50][1]
|
||||
webbrowser.open("mailto:%s" % email)
|
||||
else: # >= 20: script screen link buttons
|
||||
link = SCRIPT_INFO.d['__url__'][evt - 20][1]
|
||||
webbrowser.open(link)
|
||||
elif evt == BEVT_VIEWSOURCE:
|
||||
if SCREEN == SCRIPT_SCREEN: load_script_text(SCRIPT_INFO.script)
|
||||
elif evt == BEVT_EXIT:
|
||||
Draw.Exit()
|
||||
return
|
||||
elif evt == BEVT_BACK:
|
||||
if SCREEN == SCRIPT_SCREEN and not FMODE:
|
||||
SCREEN = START_SCREEN
|
||||
SCRIPT_INFO = None
|
||||
SCROLL_DOWN = 0
|
||||
Draw.Redraw()
|
||||
elif evt == BEVT_EXEC: # Execute script
|
||||
exec_line = ''
|
||||
if SCRIPT_INFO.script.userdir:
|
||||
exec_line = bsys.join(Blender.Get('uscriptsdir'), SCRIPT_INFO.script.fname)
|
||||
else:
|
||||
exec_line = bsys.join(Blender.Get('scriptsdir'), SCRIPT_INFO.script.fname)
|
||||
|
||||
Blender.Run(exec_line)
|
||||
|
||||
keepon = True
|
||||
FMODE = False # called by Blender.ShowHelp(name) API function ?
|
||||
|
||||
KEYNAME = '__help_browser'
|
||||
rd = Registry.GetKey(KEYNAME)
|
||||
if rd:
|
||||
rdscript = rd['script']
|
||||
keepon = False
|
||||
Registry.RemoveKey(KEYNAME)
|
||||
for group in AllGroups:
|
||||
for script in group.get_scripts():
|
||||
if rdscript == script.fname:
|
||||
parseit = parse_help_info(script)
|
||||
if parseit == True:
|
||||
keepon = True
|
||||
SCREEN = SCRIPT_SCREEN
|
||||
BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20)
|
||||
BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50)
|
||||
FMODE = True
|
||||
elif parseit == False:
|
||||
Draw.PupMenu("ERROR: script doesn't have proper help data")
|
||||
break
|
||||
|
||||
if not keepon:
|
||||
Draw.PupMenu("ERROR: couldn't find script")
|
||||
else:
|
||||
Draw.Register(gui, event, button_event)
|
||||
@@ -1,944 +0,0 @@
|
||||
#!BPY
|
||||
# coding: utf-8
|
||||
""" Registration info for Blender menus:
|
||||
Name: 'HotKey and MouseAction Reference'
|
||||
Blender: 242
|
||||
Group: 'Help'
|
||||
Tip: 'All the hotkeys/short keys'
|
||||
"""
|
||||
|
||||
__author__ = "Jean-Michel Soler (jms)"
|
||||
__url__ = ("blender", "blenderartist",
|
||||
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm",
|
||||
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
||||
__version__ = "21/01/2007"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script is a reference about all hotkeys and mouse actions in Blender.
|
||||
|
||||
Usage:
|
||||
|
||||
Open the script from the Help menu and select group of keys to browse.
|
||||
|
||||
Notes:<br>
|
||||
Additional entries in the database (c) 2004 by Bart.
|
||||
Additional entries in the database for blender 2.37 --> 2.43 (c) 2003-2007/01 by jms.
|
||||
|
||||
"""
|
||||
|
||||
#------------------------
|
||||
# Hotkeys script
|
||||
# (c) jm soler (2003-->01/2007)
|
||||
# -----------------------
|
||||
# Page officielle :
|
||||
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm
|
||||
# Communiquer les problemes et les erreurs sur:
|
||||
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
|
||||
#---------------------------------------------
|
||||
# ce script est propos<6F> sous licence GPL pour etre associe
|
||||
# a la distribution de Blender 2.33 et suivant
|
||||
# --------------------------------------------------------------------------
|
||||
# this script is released under GPL licence
|
||||
# for the Blender 2.33 scripts package
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) 2003, 2004: Jean-Michel Soler
|
||||
# Additionnal entries in the original data base (c) 2004 by 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender.Draw import *
|
||||
from Blender.BGL import *
|
||||
|
||||
# INTERNATIONAL={0:'English','1':'French'}
|
||||
# LANGUAGE=0
|
||||
|
||||
hotkeys={
|
||||
'Search ':[['', '']],
|
||||
'Specials 1 ':[
|
||||
[',', 'Set Bounding Box rotation scaling pivot'],
|
||||
['Ctrl-,', 'Set Median Point rotation scaling pivot'],
|
||||
['.', 'Set 3D cursor as rotation scaling pivot'],
|
||||
['.', 'Outliner : to get the current active data in center of view'],
|
||||
['Ctrl-.', 'Set Individual Object Centers as rotation scaling pivot'],
|
||||
['~', 'Display all layers (German keys: <20>,french keyboard: <20>)'],
|
||||
['Shift-~', 'Display all/previous layers (German keys: Shift-<2D>, french keyboard: shift-<2D>)'],
|
||||
['ENTER', 'Outliner : to open a subtree, works on entire item line. '],
|
||||
['HOME', 'Outliner : to show the entire Object hierarchy. '],
|
||||
['SHIFT+BACKSPACE',' Text edit mode: Clear text '],
|
||||
['SPACE', 'Popup menu'],
|
||||
['SPACE', '3D View: camera selected'],
|
||||
['Ctrl-SPACE', 'Manipulator (transform widget) Menu'],
|
||||
['TAB', 'Enter/exit Edit Mode'],
|
||||
['TAB', 'Edit Mode and Numerical Edit (see N key) : move to next input value'],
|
||||
['TAB', 'Sequencer: Edit meta strip'],
|
||||
['TAB', 'IPO: Edit selected'],
|
||||
['TAB', 'Text Editor : indent'],
|
||||
['TAB', 'NODE window : Edit group'], #243
|
||||
['Shift-TAB', 'Text Editor : unindent'],
|
||||
['Shift-TAB', 'Edit Mode: Toggle snaping'],
|
||||
['Ctrl-TAB', 'ARMATURE : Enter/exit Pose Mode'],
|
||||
['Ctrl-TAB','MESH : all views, enter exit weight paint mode.'],
|
||||
['Shift-TAB', 'Edit Mode : Enter Object Mode'],
|
||||
['Ctrl-Open menu /', ''],
|
||||
['Ctrl-Load Image', 'Opens a thumbnail browser instead of file browser for images'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
'Mouse ':[
|
||||
['Actions:', ''],
|
||||
['LMB', '3D View: Set 3D Cursor'],
|
||||
['LMB', '3D View: camera selected'],
|
||||
['LMB drag', 'Border select circle: add to selection'],
|
||||
['LMB hold down', 'Popup menu'],
|
||||
['LMB hold down drag', 'Gesture'],
|
||||
['Ctrl-LMB', 'IPO: Add key'],
|
||||
['Ctrl-LMB', '3D View: OBJECT or EDIT mode, select with the Lasso tool'],
|
||||
['Ctrl-LMB', '3D View: ARMATURE EDIT mode, add a new bone to the selected end '],
|
||||
['Shift-LMB','MANIPULATOR (transform widget): select the axe to remove in the current'],
|
||||
['Shift-LMB','MANIPULATOR transformation ( if there is a problem with small step adjustment'],
|
||||
['Shift-LMB','MANIPULATOR first select the axe or axes with LBM alone)'],
|
||||
['Shift-LMB', 'Outliner : Hold Shift while clicking on a triangle arrow to open/close the subtree below'],
|
||||
['MMB', 'Rotate'],
|
||||
['Ctrl-MMB', 'Zoom view'],
|
||||
['Ctrl-LMB', 'Outliner : Hold CTRL while clicking on a name allows you to edit a name.'],
|
||||
['Ctrl-LMB', 'Outliner : This works for all visualized data, including bones or vertex groups,'],
|
||||
['Ctrl-LMB', 'Outliner : but not for \'nameless\' items that draw the links to Hooks, Deform '],
|
||||
['Ctrl-LMB', 'Outliner : Groups or Constraints.'],
|
||||
['Shift-MMB', 'Move view'],
|
||||
['RMB', 'Select'],
|
||||
['RMB drag', 'Border select circle: subtract from selection'],
|
||||
['RMB hold down', 'Popup menu'],
|
||||
['Alt-RMB', 'Object Mode :Select but in a displayed list of objects located under the mouse cursor'],
|
||||
['Alt-RMB', 'Edit Mode: Select EDGES LOOP '],
|
||||
['Alt-Ctrl-RMB', 'Edit Mode: Select FACES LOOP'],
|
||||
['Alt-Ctrl-RMB', 'UV Image Editor: Select face'],
|
||||
['Shift-RMB', 'Add/subtract to/from selection'],
|
||||
['Wheel', 'Zoom view'],
|
||||
['Transformations:', ''],
|
||||
['Drag+Ctrl', 'Step adjustment'],
|
||||
['Drag+Ctrl-Shift', 'Small step adjustment (Transform Widget : first select the axe or axes with LBM alone)'],
|
||||
['Drag+Shift', 'Fine adjustment (Transform Widget : first select the axe or axes with LBM alone)'],
|
||||
['LMB', 'Confirm transformation'],
|
||||
['MMB', 'Toggle optional transform feature'],
|
||||
['RMB', 'Abort transformation'],
|
||||
['LMB', 'Grease Pencil: when "Draw Mode On", draw new stroke'],
|
||||
['RMB', 'Grease Pencil: when "Draw Mode On", eraser tool for stroke segments'],
|
||||
['Shift-LMB', 'Grease Pencil: draw new stroke'],
|
||||
['Alt-RMB', 'Grease Pencil: eraser tool for stroke segments'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
'F-Keys ':[
|
||||
['F1', 'Open File'],
|
||||
['Shift-F1', 'Library Data Select'],
|
||||
['F2', 'Save File'],
|
||||
['Shift-F2', 'Export DXF'],
|
||||
['Ctrl-F2', 'Save/export in vrml 1.0 format' ],
|
||||
['F3', 'Save image'],
|
||||
['Ctrl-F3', 'Save image : dump 3d view'],
|
||||
['Ctrl-Shift-F3', 'Save image : dump screen'],
|
||||
['F4', 'Logic Window (may change)'],
|
||||
['Shift-F4', 'Object manager Data Select '],
|
||||
['F5', 'Material Window'],
|
||||
['Shift-F5', '3D Window'],
|
||||
['F6', 'Texture Window'],
|
||||
['Shift-F6', 'IPO Window'],
|
||||
['F7', 'Object Window'],
|
||||
['Shift-F7', 'Buttons Window'],
|
||||
['F8', 'World Window'],
|
||||
['Shift-F8', 'Video Sequencer Window'],
|
||||
['F9', 'Edit Mode Window'],
|
||||
['Shift-F9', 'OOP Window'],
|
||||
['Alt-Shift-F9', 'OutLiner Window'],
|
||||
['F10', 'Render Window'],
|
||||
['Shift-F10', 'UV Image Editor'],
|
||||
['F11', 'Recall the last rendered image'],
|
||||
['Shift-F11', 'Text Editor'],
|
||||
['ctrl-F11', 'replay the last rendered animation'],
|
||||
['F12', 'Render current Scene'],
|
||||
['Ctrl-F12', 'Render animation'],
|
||||
['Ctrl-Shift-F12', 'NLA Editor'],
|
||||
['Shift-F12', 'Action Editor'],
|
||||
['Shift-F12', 'Action Editor'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
'Numbers ':[
|
||||
['1..2..0-=', 'Show layer 1..2..12'],
|
||||
['1..2..0-=', 'Edit Mode with Size, Grab, rotate tools : enter value'],
|
||||
['Alt-1..2..0', 'Show layer 11..12..20'],
|
||||
['Shift-1..2..0', 'Toggle layer 1..2..12'],
|
||||
['Ctrl-1..4', 'Object/Edit Mode : change subsurf level to the selected value'],
|
||||
['Shift-ALT-...', 'Toggle layer 11..12..20'],
|
||||
['Crtl-Shift-ALT-3', 'Edit Mode & Face Mode : Triangle faces'],
|
||||
['Crtl-Shift-ALT-4', 'Edit Mode & Face Mode : Quad faces'],
|
||||
['Crtl-Shift-ALT-5', 'Edit Mode & Face Mode : Non quad or triangle faces'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
'Numpad ':[
|
||||
['Numpad DEL', 'Zoom on object'],
|
||||
['Numpad /', 'Local view on object (hide others)'],
|
||||
['Numpad *', 'Rotate view to objects local axes'],
|
||||
['Numpad +', 'Zoom in (works everywhere)'],
|
||||
['Numpad -', 'OutLiner window, Collapse one level of the hierarchy'],
|
||||
['Alt-Numpad +', 'Proportional vertex Edit Mode: Increase range of influence'],
|
||||
['Ctrl-Numpad +', 'Edit Mode: Select More vertices'],
|
||||
['Numpad -', 'Zoom out (works everywhere)'],
|
||||
['Numpad +', 'OutLiner window, Expand one level of the hierarchy'],
|
||||
['Alt-Numpad -', 'Proportional vertex Edit Mode: Decrease range of influence'],
|
||||
['Ctrl-Numpad +', 'Edit Mode: Select Less vertices'],
|
||||
['Numpad 0', 'Set Camera view'],
|
||||
['Ctrl-Numpad 0', 'Set active object as camera'],
|
||||
['Alt-Numbad 0', 'Restore old camera'],
|
||||
['Ctrl-Alt-Numpad 0', 'Align active camera to view'],
|
||||
['Numpad 1', 'Front view'],
|
||||
['Ctrl-Numpad 1', 'Back view'],
|
||||
['Numpad 3', 'Right view'],
|
||||
['Ctrl-Numpad 3', 'Left view'],
|
||||
['Numpad 7', 'Top view'],
|
||||
['Ctrl-Numpad 7', 'Bottom view '],
|
||||
['Numpad 5', 'Toggle orthogonal/perspective view'],
|
||||
['Numpad 9', 'Redraw view'],
|
||||
['Numpad 4', 'Rotate view left'],
|
||||
['ctrl-Shift-Numpad 4', 'Previous Screen'],
|
||||
['Numpad 6', 'Rotate view right'],
|
||||
['ctrl-Shift-Numpad 6', 'Next Screen'],
|
||||
['Numpad 8', 'Rotate view up'],
|
||||
['Numpad 2', 'Rotate view down'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
'Arrows ':[
|
||||
['Home/Pos1', 'View all',''],
|
||||
['Home', 'OutLiner Windows, Show hierarchy'],
|
||||
['PgUp', 'Edit Mode and Proportionnal Editing Tools, increase influence'],
|
||||
['PgUp', 'Strip Editor, Move Down'],
|
||||
['PgUp', 'TimeLine: Jump to next marker'],
|
||||
['PgUp', 'IPO: Select next keyframe'],
|
||||
['Ctrl-PgUp', 'IPO: Select and jump to next keyframe'],
|
||||
['Ctrl-PgUn', 'TimeLine: Jump to next key'],
|
||||
['PgDn', 'Edit Mode and Proportionnal Editing Tools, decrease influence'],
|
||||
['PgDn', 'Strip Editor, Move Up'],
|
||||
['PgDn', 'TimeLine: Jump to prev marker'],
|
||||
['PgDn', 'IPO: Select previous keyframe'],
|
||||
['Ctrl-PgDn', 'IPO: Select and jump to previous keyframe'],
|
||||
['Ctrl-PgDn', 'TimeLine: Jump to prev key'],
|
||||
['Left', 'One frame backwards'],
|
||||
['Right', 'One frame forwards'],
|
||||
['Down', '10 frames backwards'],
|
||||
['Up', '10 frames forwards'],
|
||||
['Alt-Down', 'Blender in Window mode'],
|
||||
['Alt-Up', 'Blender in Fullscreen mode'],
|
||||
['Ctrl-Left', 'Previous screen'],
|
||||
['Ctrl-Right', 'Next screen'],
|
||||
['Ctrl-Down', 'Maximize window toggle'],
|
||||
['Ctrl-Up', 'Maximize window toggle'],
|
||||
['Shift-Arrow', 'Toggle first frame/ last frame'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
'Letters ':[
|
||||
{
|
||||
"A":[
|
||||
['A', 'Select all/Deselect all'],
|
||||
['A', 'Outliner : Select all/Deselect all'],
|
||||
['A', 'Ipo Editor : Object mode, Select all/Deselect all displayed Curves'], #243
|
||||
['A', 'Ipo Editor : Edit mode, Select all/Deselect all vertices'], #243
|
||||
['A', 'Render window (F12) : Display alpha plane'],
|
||||
['Alt-A', 'Play animation in current window'],
|
||||
['Ctrl-A', 'Apply objects size/rotation to object data'],
|
||||
['Ctrl-A', 'Text Editor: Select all'],
|
||||
['Ctrl-ALT-A', '3D-View: Armature Edit mode, align selected bones to active bone'],
|
||||
['Shift-A', 'Sequencer: Add menu'],
|
||||
['Shift-A', '3D-View: Add menu'],
|
||||
['Shift-A', 'Sculpt Mode: Keep the brush center anchored to the initial location'],
|
||||
['Shift-ALT-A', 'Play animation in all windows'],
|
||||
['Shift-CTRL-A', 'Apply lattice / Make dupliverts real'],
|
||||
['Shift-CTRL-A', 'Apply Deform '],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"B":[
|
||||
['B', 'Border select'],
|
||||
['BB', 'Circle select'],
|
||||
['Alt-B', 'Object Mode: Select visible view section in 3D space'],
|
||||
['Shift-B', 'Set render border (in active camera view)'],
|
||||
['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake (on an image in the uv editor window) the selected Meshes'], #243
|
||||
['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Full render of selected Meshes'], #243
|
||||
['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Ambient Occlusion of selected Meshes'], #243
|
||||
['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Normals of the selected Meshes'], #243
|
||||
['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Texture Only of selected Meshes'], #243
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"C":[
|
||||
['C', 'Center view on cursor'],
|
||||
['C', 'UV Image Editor: Active Face Select toggle'],
|
||||
['C', 'Sequencer: Change content of the strip '], #243
|
||||
['C', 'IPO: Snap current frame to selected key'],
|
||||
['C', 'TimeLine: Center View'],
|
||||
['C', 'File Selector : Copy file'],
|
||||
['C', 'NODE window : Show cyclic referencies'], #243
|
||||
['Alt-C', 'Object Mode: Convert menu'],
|
||||
['Alt-C', 'Text Editor: Copy '],
|
||||
['Ctrl-Alt-C', 'Object Mode : Add Constraint'],
|
||||
['Ctrl-Shift-C', 'Text Editor: Copy selection to clipboard'],
|
||||
['Ctrl-C', 'Copy menu (Copy properties of active to selected objects)'],
|
||||
['Ctrl-C', 'UV Image Editor: Stick UVs to mesh vertex'],
|
||||
['Ctrl-C','ARMATURE : posemode, Copy pose attributes'],
|
||||
['Ctrl-Alt-C',' ARMATURE : posemode, add constraint to new empty object.'],
|
||||
['Shift-C', 'Center and zoom view on selected objects'],
|
||||
['Shift-C', 'UV Image Editor: Stick local UVs to mesh vertex'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"D":[
|
||||
['D', 'Set 3d draw mode'],
|
||||
['Alt-D', 'Object Mode: Create new instance of object'],
|
||||
['Ctrl-D', 'Display alpha of image texture as wire'],
|
||||
['Ctrl-D', 'Text Editor : uncomment'],
|
||||
['Shift-D', 'Create full copy of object'],
|
||||
['Shift-D', 'NODE window : duplicate'], #243
|
||||
['CTRL-SHIFT-D', 'NLA editor : Duplicate markers'],
|
||||
['CTRL-SHIFT-D', 'Action editor : Duplicate markers'],
|
||||
['CTRL-SHIFT-D', 'IPO editor : Duplicate markers'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"E":[
|
||||
['E', 'Edit Mode: Extrude'],
|
||||
['E', 'UV Image Editor: LSCM Unwrap'],
|
||||
['E', 'TimeLine: Set current frame as End '],
|
||||
['E', 'NODE window : Execute composite'], #243
|
||||
['ER', 'Edit Mode: Extrude Rotate'],
|
||||
['ES', 'Edit Mode: Extrude Scale'],
|
||||
['ESX', 'Edit Mode: Extrude Scale X axis'],
|
||||
['ESY', 'Edit Mode: Extrude Scale Y axis'],
|
||||
['ESZ', 'Edit Mode: Extrude Scale Z axis'],
|
||||
['EX', 'Edit Mode: Extrude along X axis'],
|
||||
['EY', 'Edit Mode: Extrude along Y axis'],
|
||||
['EZ', 'Edit Mode: Extrude along Z axis'],
|
||||
['Alt-E', 'Edit Mode: exit Edit Mode'],
|
||||
['Ctrl-E', 'Edit Mode: Edge Specials menu'],
|
||||
['Ctrl-E', 'Edit Mode: Edge Specials menu, Mark seams'],
|
||||
['Ctrl-E', 'Edit Mode: Edge Specials menu, Clear seams'],
|
||||
['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CW'],
|
||||
['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CCW'],
|
||||
['Ctrl-E', 'Edit Mode: Edge Specials menu, Loop Cut'],
|
||||
['Ctrl-E', 'Edit Mode: Edge Specials menu, Edge Slide'],
|
||||
['Shift-E', 'Edit Mode: SubSurf Edge Sharpness'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"F":[
|
||||
['F', 'Edit mode: Make edge/face'],
|
||||
['F', 'Sequencer: Set Filter Y'],
|
||||
['F', 'Object Mode: UV/Face Select mode'],
|
||||
['Alt-F', 'Edit Mode: Beautify fill'],
|
||||
['Alt-F,','Text editor : find again '],
|
||||
['Alt-Ctrl-F,','Text editor : find '],
|
||||
['Ctrl-F', 'Object Mode: Sort faces in Z direction'],
|
||||
['Ctrl-F', 'Edit Mode: Flip triangle edges'],
|
||||
['Shift-F', 'Edit Mode: Fill with triangles'],
|
||||
['Shift-F', 'Object Mode: fly mode (see header for fly mode keys)'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"G":[
|
||||
['G', 'Grab (move)'],
|
||||
['G', 'Timeline : Grab (move) Marker'],
|
||||
['Alt-G', 'Clear location (this does only make sense in Object mode)'],
|
||||
['Alt-G', 'NODE window : ungroup'], #243
|
||||
['Shift-ALT-G', 'Object mode: Remove selected objects from group'],
|
||||
['Ctrl-G', 'NODE window : group'], #243
|
||||
['Ctrl-G', 'Add selected objects to group'],
|
||||
['Ctrl-G', 'IPO editor, Grab/move marker'],
|
||||
['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Grab Mode'],
|
||||
['Shift-G', 'Object mode: Selected Group menu'],
|
||||
['Shift-G', 'Object mode: Selected Group menu 1, Children'],
|
||||
['Shift-G', 'Object mode: Selected Group menu 2, Immediate Children'],
|
||||
['Shift-G', 'Object mode: Selected Group menu 3, Parent'],
|
||||
['Shift-G', 'Object mode: Selected Group menu 4, Sibling'],
|
||||
['Shift-G', 'Object mode: Selected Group menu 5, Object of same type'],
|
||||
['Shift-G', 'Object mode: Selected Group menu 6, Object in same shared layers'],
|
||||
['Shift-G', 'Object mode: Selected Group menu 7, Objects in same group'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"H":[
|
||||
['H', 'Hide selected vertices/faces'],
|
||||
['H', 'Curves: Set handle type'],
|
||||
['H', 'Action editor: Handle type aligned'],
|
||||
['H', 'Action editor: Handle type free'],
|
||||
['H', 'NODE window : hide/unhide'], #243
|
||||
['Alt-H', 'Edit Mode : Show Hidden vertices/faces'],
|
||||
['Shift-H', 'Curves: Automatic handle calculation'],
|
||||
['Shift-H', 'Action editor: Handle type auto'],
|
||||
['Shift-H', 'Edit Mode : Hide deselected vertices/faces'],
|
||||
['Ctrl-H', 'Edit Mode : Add a hook on selected points or show the hook menu .'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"I":[
|
||||
['I', 'Insert Keyframe menu'],
|
||||
['Alt-I','Delete Keyframe menu'],
|
||||
['Ctrl-I','Select Inverse'],
|
||||
['Shift-I','ARMATURE : add IK constraint'],
|
||||
['Ctrl-Alt-I','ARMATURE : posemode, remove IK constraints.'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"J":[
|
||||
['J', 'IPO: Join menu'],
|
||||
['J', 'Mesh: Join all adjacent triangles to quads'],
|
||||
['J', 'Render Window: Swap render buffer'],
|
||||
['Alt-J,','Text editor : Jump '],
|
||||
['Ctrl-J', 'Join selected objects'],
|
||||
['Ctrl-J', 'Nurbs: Add segment'],
|
||||
['Ctrl-J', 'IPO: Join keyframes menu'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"K":[
|
||||
['K', '3d Window: Show keyframe positions'],
|
||||
['K', 'Edit Mode: Loop/Cut menu'],
|
||||
['K', 'IPO: Show keyframe positions'],
|
||||
['K', 'Nurbs: Print knots'],
|
||||
['K', 'VIDEO editor : cut at current frame'], #243
|
||||
['Ctrl-K', 'Make skeleton from armature'],
|
||||
['Shift-K', 'Show and select all keyframes for object'],
|
||||
['Shift-K', 'Edit Mode: Knife Mode select'],
|
||||
['Shift-K', 'UV Face Select: Clear vertex colours'],
|
||||
['Shift-K', 'Vertex Paint: All vertex colours are erased; they are changed to the current drawing colour.'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"L":[
|
||||
['L', 'Make local menu'],
|
||||
['L', 'Edit Mode: Select linked vertices (near mouse pointer)'],
|
||||
['L', 'NODE window: Select linked from '], #243
|
||||
['L', 'OOPS window: Select linked objects'],
|
||||
['L', 'UV Face Select: Select linked faces'],
|
||||
['Ctrl-L', 'Make links menu (for instance : to scene...)'],
|
||||
['Shift-L', 'Select links menu'],
|
||||
['Shift-L', 'NODE window: Select linked to '], #243
|
||||
['Ctrl-L', 'POSELIB: browse poses'],
|
||||
['Shift-L', 'POSELIB: add/replace pose'],
|
||||
['Ctrl-Shift-L', 'POSELIB: rename pose'],
|
||||
['Alt-L', 'POSELIB: remove pose'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"M":[
|
||||
['M', 'Object mode : Move object to different layer'],
|
||||
['M', 'Sequencer: Make meta strip (group) from selected strips'],
|
||||
['M', 'Edit Mode: Mirros Axis menu'],
|
||||
['M', 'File Selector: rename file'],
|
||||
['M', 'Video Sequence Editor : Make Meta strip...'],
|
||||
['M', 'NLA editor: Add marker'],
|
||||
['M', 'Action editor: Add marker'],
|
||||
['M', 'IPO editor: Add marker'],
|
||||
['M', 'TimeLine: Add marker'],
|
||||
['Alt-M', 'Edit Mode: Merge vertices menu'],
|
||||
['Alt-M', 'Video Sequence Editor : Separate Meta strip...'],
|
||||
['Ctrl-M', 'Object Mode: Mirros Axis menu'],
|
||||
['Shift-M', 'TimeLine: Name marker'],
|
||||
['Shift-M', 'IPO editor : Name marker'],
|
||||
['Shift-M', 'NLA editor : Name marker'],
|
||||
['Shift-M', 'Actions editor : Name marker'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"N":[
|
||||
['N', 'Transform Properties panel'] ,
|
||||
['N', 'OOPS window: Rename object'],
|
||||
['N', 'VIDEO SEQUENCE editor : display strip properties '], #243
|
||||
['Alt-N', 'Text Editor : New text '],
|
||||
['Ctrl-N', 'Armature: Recalculate bone roll angles'] ,
|
||||
['Ctrl-N', 'Edit Mode: Recalculate normals to outside'] ,
|
||||
['Ctrl-Shift-N', 'Edit Mode: Recalculate normals to inside'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"O":[
|
||||
['O', 'Edit Mode/UV Image Editor: Toggle proportional vertex editing'],
|
||||
['O', 'IPO editor: Clean ipo curves (beware to the thresold needed value)'], #243
|
||||
['Alt-O', 'Clear object origin'],
|
||||
['Alt-O', 'Edit mode, 3dview with prop-edit-mode, enables/disables connected'],
|
||||
['Alt-O', 'Text Editor : Open file '],
|
||||
['Ctrl-O', 'Open a panel with the ten most recent projets files'], #243
|
||||
['Shift-O', 'Proportional vertex Edit Mode: Toggle smooth/steep falloff'],
|
||||
['Shift-O', 'Object Mode: Add a subsurf modifier to the selected mesh'],
|
||||
['Shift-O', 'IPO editor: Smooth ipo curves'], #243
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"P":[
|
||||
['P', 'Object Mode: Start realtime engine'],
|
||||
['P', 'Edit mode: Seperate vertices to new object'],
|
||||
['Shift-P', 'Edit mode: Push-Pull'],
|
||||
['Shift-P', 'Object mode: Add a preview window in the D window'],
|
||||
['P', 'UV Image Editor: Pin selected vertices. Pinned vertices will stay in place on the UV editor when executing an LSCM unwrap.'],
|
||||
['Alt-P', 'Clear parent relationship'],
|
||||
['Alt-P', 'UV Image Editor: Unpin UVs'],
|
||||
['Alt-P', 'Text Editor : Run current script '],
|
||||
['Ctrl-P', 'Make active object parent of selected object'],
|
||||
['Ctrl-Shift-P', 'Make active object parent of selected object without inverse'],
|
||||
['Ctrl-P', 'Edit mode: Make active vertex parent of selected object'],
|
||||
['Ctrl-P', 'ARMATURE : editmode, make bone parent.'],
|
||||
['Ctrl-Alt-P', 'ARMATURE: edimode, separate bones to new object'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"Q":[['Ctrl-Q', 'Quit'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"R":[
|
||||
['R', 'FileSelector : remove file'],
|
||||
['R', 'Rotate'],
|
||||
['R', 'IPO: Record mouse movement as IPO curve'],
|
||||
['R', 'UV Face Select: Rotate menu uv coords or vertex colour'],
|
||||
['R', 'NODE window : read saved render result'], #243
|
||||
['R', 'SEQUENCER window : re-assign entries to another strip '], #243
|
||||
['RX', 'Rotate around X axis'],
|
||||
['RXX', "Rotate around object's local X axis"],
|
||||
['RY', 'Rotate around Y axis'],
|
||||
['RYY', "Rotate around object's local Y axis"],
|
||||
['RZ', 'Rotate around Z axis'],
|
||||
['RZZ', "Rotate around object's local Z axis"],
|
||||
['Alt-R', 'Clear object rotation'],
|
||||
['Alt-R', 'Text editor : reopen text.'],
|
||||
['Ctrl-R', 'Edit Mode: Knife, cut selected edges, accept left mouse/ cancel right mouse'],
|
||||
['Ctrl-Alt-R', 'MANIPULATOR (transform widget): set in Rotate Mode'],
|
||||
['Shift-R', 'Edit Mode: select Face Loop'],
|
||||
['Shift-R', 'Nurbs: Select row'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"S":[
|
||||
['S', 'Scale'] ,
|
||||
['S', 'TimeLine: Set Start'],
|
||||
['SX', 'Flip around X axis'] ,
|
||||
['SY', 'Flip around Y axis'] ,
|
||||
['SZ', 'Flip around Z axis'] ,
|
||||
['SXX', 'Flip around X axis and show axis'] ,
|
||||
['SYY', 'Flip around Y axis and show axis'] ,
|
||||
['SZZ', 'Flip around Z axis and show axis'] ,
|
||||
['Alt-S', 'Edit mode: Shrink/fatten (Scale along vertex normals)'] ,
|
||||
['Alt-S', 'Text Editor : Save the current text to file '],
|
||||
['Alt-S',' ARMATURE : posemode editmode: Scale envalope.'],
|
||||
['Ctrl-Shift-S', 'Edit mode: To Sphere'] ,
|
||||
['Ctrl-Alt-Shift-S', 'Edit mode: Shear'] ,
|
||||
['Alt-S', 'Clear object size'] ,
|
||||
['Ctrl-S', 'Edit mode: Shear'] ,
|
||||
['Alt-Shift-S,','Text editor : Select the line '],
|
||||
['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Size Mode'],
|
||||
['Shift-S', 'Cursor/Grid snap menu'],
|
||||
['Shift-S', 'Sculpt Mode: Smooth Stroke.'],
|
||||
['Shift-S+1', 'VIDEO SEQUENCE editor : jump to the current frame '],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"T":[
|
||||
['T', 'Adjust texture space'],
|
||||
['T', 'Edit mode: Flip 3d curve'],
|
||||
['T', 'IPO: Menu Change IPO type, 1 Constant'],
|
||||
['T', 'IPO: Menu Change IPO type, 2 Linear'],
|
||||
['T', 'IPO: Menu Change IPO type, 3 Bezier'],
|
||||
['T', 'TimeLine: Show second'],
|
||||
['T', 'VIDEO SEQUENCE editor : toggle between show second andd show frame'], #243
|
||||
['Alt-T', 'Clear tracking of object'],
|
||||
['Ctrl-T', 'Make selected object track active object'],
|
||||
['Ctrl-T', 'Edit Mode: Convert to triangles'],
|
||||
['Ctrl-Alt-T', 'Benchmark'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"U":[
|
||||
['U', 'Make single user menu (for import completly linked object to another scene for instance) '] ,
|
||||
['U', '3D View: Make Single user Menu'] ,
|
||||
['U', 'UV Face Select: Automatic UV calculation menu'] ,
|
||||
['U', 'Vertex-/Weightpaint mode: Undo'] ,
|
||||
['Ctrl-U', 'Save current state as user default'],
|
||||
['Shift-U', 'Edit Mode: Redo Menu'],
|
||||
['Alt-U', 'Edit Mode & Object Mode: Undo Menu'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"V":[
|
||||
['V', 'Curves/Nurbs: Vector handle'],
|
||||
['V', 'Edit Mode : Rip selected vertices'],
|
||||
['V', 'Vertexpaint mode'],
|
||||
['V', 'UV Image Editor: Stitch UVs'],
|
||||
['Ctrl-V',' UV Image Editor: maximize stretch.'],
|
||||
['V', 'Action editor: Vector'],
|
||||
['Alt-V', "Scale object to match image texture's aspect ratio"],
|
||||
['Alt-V', 'Text Editor : Paste '],
|
||||
['Alt-Shift-V', 'Text Editor : View menu'],
|
||||
['Alt-Shift-V', 'Text Editor : View menu 1, Top of the file '],
|
||||
['Alt-Shift-V', 'Text Editor : View menu 2, Bottom of the file '],
|
||||
['Alt-Shift-V', 'Text Editor : View menu 3, PageUp'],
|
||||
['Alt-Shift-V', 'Text Editor : View menu 4, PageDown'],
|
||||
['Ctrl-Shift-V', 'Text Editor: Paste from clipboard'],
|
||||
['Shift-V', 'Edit mode: Align view to selected vertices'],
|
||||
['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"W":[
|
||||
['W', 'Edit Mode: Specials menu'],
|
||||
['W', 'Edit Mode: Specials menu, ARMATURE 1 Subdivide'],
|
||||
['W', 'Edit Mode: Specials menu, ARMATURE 2 Subdivide Multi'],
|
||||
['W', 'Edit Mode: Specials menu, ARMATURE 3 Switch Direction'],
|
||||
['W', 'Edit Mode: Specials menu, ARMATURE 4 Flip Left-Right Name'],
|
||||
['W', 'Edit Mode: Specials menu, ARMATURE 5 AutoName Left-Right'],
|
||||
['W', 'Edit Mode: Specials menu, ARMATURE 6 AutoName Front-Back'],
|
||||
['W', 'Edit Mode: Specials menu, ARMATURE 7 AutoName Top-Bottom'],
|
||||
['W', 'Edit Mode: Specials menu, CURVE 1 Subdivide'],
|
||||
['W', 'Edit Mode: Specials menu, CURVE 2 Swich Direction'],
|
||||
['W', 'Edit Mode: Specials menu, CURVE 3 Set Goal Weight'],
|
||||
['W', 'Edit Mode: Specials menu, CURVE 4 Set Radius'],
|
||||
['W', 'Edit Mode: Specials menu, CURVE 5 Smooth'],
|
||||
['W', 'Edit Mode: Specials menu, CURVE 6 Smooth Radius'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 1 Subdivide'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 2 Subdivide Multi'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 3 Subdivide Multi Fractal'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 4 Subdivide Smooth'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 5 Merge'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 6 Remove Double'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 7 Hide'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 8 Reveal'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 9 Select Swap'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 10 Flip Normal'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 11 Smooth'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 12 Bevel'],
|
||||
['W', 'Edit Mode: Specials menu, MESH 13 Set Smooth'],
|
||||
['W', 'Edit Mode : Specials menu, MESH 14 Set Solid'],
|
||||
['W', 'Object Mode : on MESH objects, Boolean Tools menu'],
|
||||
['W', 'Object Mode : on MESH objects, Boolean Tools 1 Intersect'],
|
||||
['W', 'Object Mode : on MESH objects, Boolean Tools 2 union'],
|
||||
['W', 'Object Mode : on MESH objects, Boolean Tools 3 difference'],
|
||||
['W', 'Object Mode : on MESH objects, Boolean Tools 4 Add an intersect Modifier'],
|
||||
['W', 'Object Mode : on MESH objects, Boolean Tools 5 Add an union Modifier'],
|
||||
['W', 'Object Mode : on MESH objects, Boolean Tools 6 Add a difference Modifier'],
|
||||
['W', 'Object mode : on TEXT object, Split characters, a new TEXT object by character in the selected string '],
|
||||
['W', 'UV Image Editor: Weld/Align'],
|
||||
['WX', 'UV Image Editor: Weld/Align X axis'],
|
||||
['WY', 'UV Image Editor: Weld/Align Y axis'],
|
||||
['Ctrl-W', 'Save current file'] ,
|
||||
['Shift-W', 'Warp/bend selected vertices around cursor'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"X":[
|
||||
['X', 'Delete menu'] ,
|
||||
['X', 'TimeLine : Remove marker'],
|
||||
['X', 'NLA : Remove marker'],
|
||||
['X', 'IPO : Remove marker'],
|
||||
['X', 'NODE window : delete'], #243
|
||||
['Alt-X', 'Text Editor : Cut '],
|
||||
['Alt-X', 'Grease Pencil: Delete menu'],
|
||||
['Ctrl-X', 'Restore default state (Erase all)'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"Y":[
|
||||
['Y', 'Edit Mode & Mesh : Split selected vertices/faces from the rest'],
|
||||
['Ctrl-Y', 'Object Mode : Redo'],
|
||||
['.', '...']
|
||||
],
|
||||
|
||||
"Z":[
|
||||
['Z', 'Render Window: 200% zoom from mouse position'],
|
||||
['Z', 'Switch 3d draw type : solide/ wireframe (see also D)'],
|
||||
['Alt-Z', 'Switch 3d draw type : solid / textured (see also D)'],
|
||||
['Alt-Z,','Text editor : undo '],
|
||||
['Ctrl-Z', 'Object Mode : Undo'],
|
||||
['Ctrl-Z,','Text editor : undo '],
|
||||
['Ctrl-Shift-Z,','Text editor : Redo '],
|
||||
['Shift-Z', 'Switch 3d draw type : shaded / wireframe (see also D)'],
|
||||
['.', '...']
|
||||
]}]}
|
||||
|
||||
up=128
|
||||
down=129
|
||||
UP=0
|
||||
SEARCH=131
|
||||
OLDSEARCHLINE=''
|
||||
SEARCHLINE=Create('')
|
||||
LINE=130
|
||||
FINDED=[]
|
||||
LEN=0
|
||||
|
||||
for k in hotkeys.keys():
|
||||
hotkeys[k].append(Create(0))
|
||||
|
||||
for k in hotkeys['Letters '][0]:
|
||||
hotkeys['Letters '][0][k].append(Create(0))
|
||||
|
||||
hotL=hotkeys['Letters '][0].keys()
|
||||
hotL.sort()
|
||||
|
||||
hot=hotkeys.keys()
|
||||
hot.sort()
|
||||
|
||||
def searchfor(SEARCHLINE):
|
||||
global hotkeys, hot
|
||||
FINDLIST=[]
|
||||
for k in hot:
|
||||
if k not in ['Letters ', 'Search '] :
|
||||
for l in hotkeys[k][:-1]:
|
||||
#print 'k, l : ', k, l, l[1]
|
||||
if l[1].upper().find(SEARCHLINE.upper())!=-1:
|
||||
FINDLIST.append(l)
|
||||
|
||||
elif k == 'Letters ':
|
||||
for l in hotL :
|
||||
for l0 in hotkeys['Letters '][0][l][:-1]:
|
||||
#print 'k, l : ',l, k, l0
|
||||
if l0[1].upper().find(SEARCHLINE.upper())!=-1:
|
||||
FINDLIST.append(l0)
|
||||
#print 'FINDLIST',FINDLIST
|
||||
FINDLIST.append(['Find list','Entry'])
|
||||
return FINDLIST
|
||||
|
||||
|
||||
glCr=glRasterPos2d
|
||||
glCl3=glColor3f
|
||||
glCl4=glColor4f
|
||||
glRct=glRectf
|
||||
|
||||
cf=[0.95,0.95,0.9,0.0]
|
||||
c1=[0.95,0.95,0.9,0.0]
|
||||
c=cf
|
||||
r=[0,0,0,0]
|
||||
|
||||
def trace_rectangle4(r,c):
|
||||
glCl4(c[0],c[1],c[2],c[3])
|
||||
glRct(r[0],r[1],r[2],r[3])
|
||||
|
||||
def trace_rectangle3(r,c,c1):
|
||||
glCl3(c[0],c[1],c[2])
|
||||
glRct(r[0],r[1],r[2],r[3])
|
||||
glCl3(c1[0],c1[1],c1[2])
|
||||
|
||||
def draw():
|
||||
global r,c,c1,hotkeys, hot, hotL, up, down, UP, SEARCH, SEARCHLINE,LINE
|
||||
global OLDSEARCHLINE, FINDED, SCROLL, LEN
|
||||
size=Buffer(GL_FLOAT, 4)
|
||||
glGetFloatv(GL_SCISSOR_BOX, size)
|
||||
size= size.list
|
||||
|
||||
for s in [0,1,2,3]: size[s]=int(size[s])
|
||||
|
||||
c=[0.75,0.75,0.75,0]
|
||||
c1=[0.6,0.6,0.6,0]
|
||||
|
||||
r=[0,size[3],size[2],0]
|
||||
trace_rectangle4(r,c)
|
||||
|
||||
c=[0.64,0.64,0.64,0]
|
||||
c1=[0.95,0.95,0.9,0.0]
|
||||
|
||||
r=[0,size[3],size[2],size[3]-40]
|
||||
trace_rectangle4(r,c)
|
||||
|
||||
c1=[0.7,0.7,0.9,0.0]
|
||||
c=[0.2,0.2,0.4,0.0]
|
||||
c2=[0.71,0.71,0.71,0.0]
|
||||
|
||||
glColor3f(1, 1, 1)
|
||||
glRasterPos2f(42, size[3]-25)
|
||||
|
||||
Text("HotKey and MouseAction Reference")
|
||||
|
||||
l=0
|
||||
listed=0
|
||||
Llisted=0
|
||||
size[3]=size[3]-18
|
||||
|
||||
BeginAlign()
|
||||
for i, k in enumerate(hot):
|
||||
hotkeys[k][-1]=Toggle(k, i+10, 78*i, size[3]-(47), 78, 24, hotkeys[k][-1].val )
|
||||
l+=len(k)
|
||||
if hotkeys[k][-1].val==1.0:
|
||||
listed= i
|
||||
EndAlign()
|
||||
l=0
|
||||
size[3]=size[3]-4
|
||||
|
||||
if hot[listed]!='Letters ' and hot[listed]!='Search ' :
|
||||
size[3]=size[3]-8
|
||||
SCROLL=size[3]/21
|
||||
END=-1
|
||||
if SCROLL < len(hotkeys[hot[listed]][:-1]):
|
||||
BeginAlign()
|
||||
Button('/\\',up,4,size[3]+8,20,14,'Scroll up')
|
||||
Button('\\/',down,4,size[3]-8,20,14,'Scroll down')
|
||||
EndAlign()
|
||||
if (SCROLL+UP)<len(hotkeys[hot[listed]][:-1]):
|
||||
END=(UP+SCROLL)
|
||||
else:
|
||||
END=-1
|
||||
UP=len(hotkeys[hot[listed]][:-1])-SCROLL
|
||||
else :
|
||||
UP=0
|
||||
for n in hotkeys[hot[listed]][:-1][UP:END]:
|
||||
if l%2==0:
|
||||
r=[0,size[3]-(21*l+66),
|
||||
size[2], size[3]-(21*l+43)]
|
||||
trace_rectangle4(r,c2)
|
||||
glColor3f(0,0,0)
|
||||
glRasterPos2f(4+8, size[3]-(58+21*l))
|
||||
Text(n[0])
|
||||
glRasterPos2f(4+8*15, size[3]-(58+21*l))
|
||||
Text(' : '+n[1])
|
||||
l+=1
|
||||
|
||||
elif hot[listed]=='Search ' :
|
||||
r=[0,size[3]-70,
|
||||
size[2], size[3]-44]
|
||||
trace_rectangle4(r,c2)
|
||||
SEARCHLINE=String(' ', LINE, 42, size[3]-68,200,18,SEARCHLINE.val, 256,'')
|
||||
if len(FINDED)>0:
|
||||
LEN=len(FINDED)
|
||||
size[3]=size[3]-8
|
||||
SCROLL=size[3]/21
|
||||
END=-1
|
||||
|
||||
if SCROLL < len(FINDED):
|
||||
BeginAlign()
|
||||
Button('/\\',up,4,size[3]+8,20,14,'Scroll up')
|
||||
Button('\\/',down,4,size[3]-8,20,14,'Scroll down')
|
||||
EndAlign()
|
||||
if (SCROLL+UP)<len(FINDED):
|
||||
END=(UP+SCROLL-1)
|
||||
else:
|
||||
END=-1
|
||||
#UP=len(FINDED)-SCROLL
|
||||
else:
|
||||
UP=0
|
||||
for n in FINDED[UP:END]:
|
||||
if l%2==0:
|
||||
r=[0,size[3]-(21*l+66+24),
|
||||
size[2], size[3]-(21*l+43+24)]
|
||||
trace_rectangle4(r,c2)
|
||||
glColor3f(0,0,0)
|
||||
glRasterPos2f(4+8, size[3]-(58+24+21*l))
|
||||
Text(n[0])
|
||||
glRasterPos2f(4+8*15, size[3]-(58+24+21*l))
|
||||
Text(' : '+n[1])
|
||||
l+=1
|
||||
else:
|
||||
BeginAlign()
|
||||
for pos, k in enumerate(hotL):
|
||||
hotkeys['Letters '][0][k][-1]=Toggle(k,pos+20,pos*21, size[3]-(52+18), 21, 18, hotkeys['Letters '][0][k][-1].val )
|
||||
if hotkeys['Letters '][0][k][-1].val==1.0:
|
||||
Llisted=pos
|
||||
EndAlign()
|
||||
size[3]=size[3]-8
|
||||
SCROLL=(size[3]-88)/21
|
||||
END=-1
|
||||
if SCROLL < len(hotkeys['Letters '][0][hotL[Llisted]]):
|
||||
LEN=len(hotkeys['Letters '][0][hotL[Llisted]])
|
||||
BeginAlign()
|
||||
Button('/\\',up,4,size[3]+8,20,14,'Scroll up, you can use arrow or page keys too ')
|
||||
Button('\\/',down,4,size[3]-8,20,14,'Scroll down, you can use arrow or page keys too ')
|
||||
EndAlign()
|
||||
if (UP+SCROLL)<len(hotkeys['Letters '][0][hotL[Llisted]]):
|
||||
END=(UP+SCROLL)
|
||||
else:
|
||||
END=-1
|
||||
UP=len(hotkeys['Letters '][0][hotL[Llisted]])-SCROLL
|
||||
else :
|
||||
UP=0
|
||||
|
||||
for n in hotkeys['Letters '][0][hotL[Llisted]][UP:END]:
|
||||
if l%2==0:
|
||||
r=[4,size[3]-(21*l+92),
|
||||
size[2], size[3]-(69+21*l+1)]
|
||||
trace_rectangle4(r,c2)
|
||||
|
||||
glColor3f(0.1, 0.1, 0.15)
|
||||
glRasterPos2f(4+8, (size[3]-(88+21*l))+3)
|
||||
Text(n[0])
|
||||
glRasterPos2f(4+8*15, (size[3]-(88+21*l))+3)
|
||||
Text(' : '+n[1])
|
||||
l+=1
|
||||
|
||||
def event(evt, val):
|
||||
global hotkeys, UP, SCROLL , LEN
|
||||
if (evt== QKEY or evt== ESCKEY):
|
||||
Exit()
|
||||
elif val:
|
||||
if (evt== PAGEUPKEY):
|
||||
if (UP+SCROLL)<LEN-5:
|
||||
UP+=5
|
||||
elif (evt== PAGEDOWNKEY):
|
||||
if UP>4:
|
||||
UP-=5
|
||||
elif (evt== UPARROWKEY):
|
||||
if (UP+SCROLL)<LEN-1:
|
||||
UP+=1
|
||||
elif (evt== DOWNARROWKEY):
|
||||
if UP>0:
|
||||
UP-=1
|
||||
Redraw()
|
||||
|
||||
def bevent(evt):
|
||||
global hotkeysmhot, hotL, up,down,UP, FINDED
|
||||
global SEARCH, SEARCHLINE,LINE, OLDSEARCHLINE
|
||||
|
||||
if (evt== 1):
|
||||
Exit()
|
||||
|
||||
elif 9 < evt < 20:
|
||||
for i, k in enumerate(hot):
|
||||
if i+10!=evt:
|
||||
hotkeys[k][-1].val=0
|
||||
UP=0
|
||||
Blender.Window.Redraw()
|
||||
|
||||
elif 19 < evt < 46:
|
||||
for i, k in enumerate(hotL):
|
||||
if i+20!=evt:
|
||||
hotkeys['Letters '][0][k][-1].val=0
|
||||
UP=0
|
||||
Blender.Window.Redraw()
|
||||
|
||||
elif (evt==up):
|
||||
UP+=1
|
||||
Blender.Window.Redraw()
|
||||
|
||||
elif (evt==down):
|
||||
if UP>0: UP-=1
|
||||
Blender.Window.Redraw()
|
||||
|
||||
elif (evt==LINE):
|
||||
if SEARCHLINE.val!='' and SEARCHLINE.val!=OLDSEARCHLINE:
|
||||
OLDSEARCHLINE=SEARCHLINE.val
|
||||
FINDED=searchfor(OLDSEARCHLINE)
|
||||
Blender.Window.Redraw()
|
||||
|
||||
if __name__ == '__main__':
|
||||
Register(draw, event, bevent)
|
||||
@@ -1,559 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: '2D Cutout Image Importer'
|
||||
Blender: 249
|
||||
Group: 'Image'
|
||||
Tooltip: 'Batch UV Map images to Planes'
|
||||
"""
|
||||
|
||||
__author__ = "Kevin Morgan (forTe)"
|
||||
__url__ = ("Home page, http://gamulabs.freepgs.com")
|
||||
__version__ = "1.2.1"
|
||||
__bpydoc__ = """\
|
||||
This Script will take an image and
|
||||
UV map it to a plane sharing the same width to height ratio as the image.
|
||||
Import options allow for the image to be a still or sequence type image
|
||||
<br><br>
|
||||
Imports can be single images or whole directories of images depending on the chosen
|
||||
option.
|
||||
"""
|
||||
|
||||
####################################################
|
||||
#Copyright (C) 2008: Kevin Morgan
|
||||
####################################################
|
||||
#-------------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 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#This program is distributed in the hopes 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, see <http://www.gnu.org/licenses>.
|
||||
####################################################
|
||||
####################################################
|
||||
#V1.0
|
||||
#Basic Functionality
|
||||
#Published June 28, 2007
|
||||
####################################################
|
||||
#V1.1
|
||||
#Added Support for enabling viewport transparency
|
||||
#Added more options to the UI for materials
|
||||
#Added Proportionality code (Pixels per unit)
|
||||
#Added GPL License Block
|
||||
#Published June 29, 2007
|
||||
####################################################
|
||||
#V1.2
|
||||
#Added Support for Copying Existing Materials
|
||||
#Import Images as Sequences
|
||||
#Refreshed GUI - now with more clutter :(
|
||||
#Miscellaneous and Housekeeping
|
||||
#Published June 16, 2008
|
||||
####################################################
|
||||
#V1.2.1
|
||||
#Added Extend Texture Mode option at request of a user
|
||||
#Published September 24, 2008
|
||||
####################################################
|
||||
|
||||
import Blender
|
||||
from Blender import BGL, Draw, Image, Mesh, Material, Texture, Window
|
||||
from Blender.Mathutils import *
|
||||
import bpy
|
||||
|
||||
# Global Constants
|
||||
DIR = 0
|
||||
SINGLE = 1
|
||||
CUROFFS = 0
|
||||
|
||||
# GUI CONSTANTS
|
||||
NO_EVT = 0
|
||||
SINGLE_IMG = 1
|
||||
DIRECTORY_IMG = 2
|
||||
CLR_PATH = 3
|
||||
CHG_EXT = 4
|
||||
EXIT = 5
|
||||
DO_SCRIPT = 6
|
||||
|
||||
VERSIONSTRING = '1.2.1'
|
||||
|
||||
# Note the two parameter dicts could be combined, I just, liked them seperate...
|
||||
# GUI Buttons Dict
|
||||
GUIPARAMS = {
|
||||
'Path': Draw.Create(''),
|
||||
'ImageExt': Draw.Create(''),
|
||||
'Seq': Draw.Create(0),
|
||||
'PackImage': Draw.Create(0),
|
||||
'PPU': Draw.Create(50),
|
||||
'VPTransp': Draw.Create(1),
|
||||
'XOff': Draw.Create(0.0),
|
||||
'YOff': Draw.Create(0.0),
|
||||
'ZOff': Draw.Create(0.0),
|
||||
'CopyMat': Draw.Create(0),
|
||||
'MatId': Draw.Create(0),
|
||||
'MatCol': Draw.Create(1.0, 0.0, 0.0),
|
||||
'Ref': Draw.Create(0.8),
|
||||
'Spec': Draw.Create(0.5),
|
||||
'Hard': Draw.Create(50),
|
||||
'Alpha': Draw.Create(1.0),
|
||||
'ZTransp': Draw.Create(1),
|
||||
'Shadeless': Draw.Create(0),
|
||||
'TexChan': Draw.Create(1),
|
||||
'MPTCol': Draw.Create(1),
|
||||
'MPTAlpha': Draw.Create(1),
|
||||
'UseAlpha': Draw.Create(1),
|
||||
'CalcAlpha': Draw.Create(0),
|
||||
'ExtendMode': Draw.Create(0),
|
||||
'AutoRefresh': Draw.Create(0),
|
||||
'Cyclic': Draw.Create(0),
|
||||
'Frames': Draw.Create(100),
|
||||
'Offs': Draw.Create(0),
|
||||
'StartFr': Draw.Create(1),
|
||||
'RedrawImp': Draw.Create(0)
|
||||
}
|
||||
|
||||
# Script Execution Paramaters
|
||||
PARAMS = {
|
||||
'ImagePaths': [], # Path to images to import
|
||||
'ImportType': SINGLE, # Import a Directory or a Single Image?
|
||||
'ImageProp': Image.Sources.STILL, # What sources for the image, still or sequence
|
||||
'PackImage': 0, # Pack the Image(s)?
|
||||
'PPU': 20, # Pixels Per Blender Unit
|
||||
'MakeTransp': 1, # Make face transparent in viewport
|
||||
|
||||
'NewMat': 1, # If true make a new material, otherwise duplicate an existing one, replacing appropriate attributes
|
||||
'MaterialId': 0, # ID to take from the Materials list upon copy
|
||||
'Materials': None, # Materials in Scene
|
||||
'MatProps': {'Col': [1.0, 0.0, 0.0], 'Shadeless': 1, 'Ref': 0.5, 'Spec': 0.5, 'Hard': 200, 'Alpha': 1.0, 'ZTransp': 1},
|
||||
|
||||
'TexProps': {'UseAlpha': 1, 'CalcAlpha': 0, 'ExtendMode': 0}, # Texture Properties
|
||||
'TexChannel': 0, # Texture Channel
|
||||
'TexMapTo': {'Col': 1, 'Alpha': 1}, # Map to Col and/or Alpha
|
||||
'SeqProps': {'AutoRefresh': 0, 'Cyclic': 0, 'Frames': 100, 'Offs': 0, 'StartFr': 1},
|
||||
'ObOffset': Vector(1, 0, 0) # Offset by this vector upon creation for multifile import
|
||||
}
|
||||
|
||||
# Get the Active Scene, of course
|
||||
scn = bpy.data.scenes.active
|
||||
|
||||
##########################################
|
||||
# MAIN SCRIPT FUNCTIONS
|
||||
##########################################
|
||||
|
||||
def imgImport(imgPath):
|
||||
global CUROFFS, PARAMS
|
||||
######################################
|
||||
# Load the image
|
||||
######################################
|
||||
try:
|
||||
img = Image.Load(imgPath)
|
||||
imgDimensions = img.getSize() # do this to ensure the data is available
|
||||
except:
|
||||
Blender.Draw.PupMenu('Error%t|Unsupported image format for "'+ imgPath.split('\\')[-1].split('/')[-1] +'"')
|
||||
return
|
||||
|
||||
if PARAMS['PackImage']:
|
||||
img.pack()
|
||||
name = Blender.sys.makename(imgPath, strip = 1)
|
||||
|
||||
######################################
|
||||
# Construct the mesh
|
||||
######################################
|
||||
|
||||
me = Mesh.New(name)
|
||||
|
||||
# Calculate Dimensions from Image Size
|
||||
dim = [float(i)/PARAMS['PPU'] for i in imgDimensions]
|
||||
v = [[dim[0], dim[1], 0], [-dim[0], dim[1], 0], [-dim[0], -dim[1], 0], [dim[0], -dim[1], 0]]
|
||||
me.verts.extend(v)
|
||||
me.faces.extend([0, 1, 2, 3])
|
||||
|
||||
me.faces[0].image = img
|
||||
me.faces[0].uv = [Vector(1.0, 1.0), Vector(0.0, 1.0), Vector(0.0, 0.0), Vector(1.0, 0.0)]
|
||||
|
||||
if PARAMS['MakeTransp']:
|
||||
me.faces[0].transp = Mesh.FaceTranspModes.ALPHA
|
||||
|
||||
######################################
|
||||
# Modify the Material
|
||||
######################################
|
||||
|
||||
mat = None
|
||||
if not PARAMS['NewMat']:
|
||||
mat = PARAMS['Materials'][PARAMS['MaterialId']].__copy__()
|
||||
mat.setName(name)
|
||||
else:
|
||||
mat = Material.New(name)
|
||||
properties = PARAMS['MatProps']
|
||||
mat.setRGBCol(properties['Col'])
|
||||
mat.setRef(properties['Ref'])
|
||||
mat.setSpec(properties['Spec'])
|
||||
mat.setHardness(properties['Hard'])
|
||||
mat.setAlpha(properties['Alpha'])
|
||||
|
||||
if properties['Shadeless']:
|
||||
mat.mode |= Material.Modes.SHADELESS
|
||||
if properties['ZTransp']:
|
||||
mat.mode |= Material.Modes.ZTRANSP
|
||||
|
||||
properties = PARAMS['TexProps']
|
||||
|
||||
tex = Texture.New(name)
|
||||
tex.setType('Image')
|
||||
tex.setImage(img)
|
||||
if properties['UseAlpha']:
|
||||
tex.useAlpha = Texture.ImageFlags.USEALPHA
|
||||
|
||||
if properties['CalcAlpha']:
|
||||
tex.calcAlpha = Texture.ImageFlags.CALCALPHA
|
||||
|
||||
if properties['ExtendMode']:
|
||||
tex.setExtend('Extend')
|
||||
|
||||
if PARAMS['ImageProp'] == Image.Sources.SEQUENCE:
|
||||
properties = PARAMS['SeqProps']
|
||||
|
||||
img.source = PARAMS['ImageProp'] # Needs to be done here, otherwise an error with earlier getSize()
|
||||
|
||||
tex.animStart = properties['StartFr']
|
||||
tex.animOffset = properties['Offs']
|
||||
tex.animFrames = properties['Frames']
|
||||
tex.autoRefresh = properties['AutoRefresh']
|
||||
tex.cyclic = properties['Cyclic']
|
||||
|
||||
texMapSetters = Texture.TexCo.UV
|
||||
|
||||
# PARAMS['TexMapTo']['Col'] (and alpha) will either be 0 or 1 because its from a toggle, otherwise this line doesn't work
|
||||
texChanSetters = Texture.MapTo.COL * PARAMS['TexMapTo']['Col'] | Texture.MapTo.ALPHA * PARAMS['TexMapTo']['Alpha']
|
||||
|
||||
mat.setTexture(PARAMS['TexChannel'], tex, texMapSetters, texChanSetters)
|
||||
me.materials += [mat]
|
||||
|
||||
######################################
|
||||
# Object Construction
|
||||
######################################
|
||||
|
||||
ob = scn.objects.new(me, name)
|
||||
p = Vector(ob.getLocation()) # Should be the origin, but just to be safe, get it
|
||||
ob.setLocation((CUROFFS * PARAMS['ObOffset']) + p)
|
||||
|
||||
return
|
||||
|
||||
def translateParams():
|
||||
# Translates (or assigns for the most part) GUI values to those that can be read by the
|
||||
# Import Function
|
||||
|
||||
global GUIPARAMS, PARAMS
|
||||
|
||||
if GUIPARAMS['Seq'].val and PARAMS['ImportType'] != DIR:
|
||||
PARAMS['ImageProp'] = Image.Sources.SEQUENCE
|
||||
|
||||
PARAMS['PackImage'] = GUIPARAMS['PackImage'].val
|
||||
PARAMS['PPU'] = GUIPARAMS['PPU'].val
|
||||
PARAMS['MakeTransp'] = GUIPARAMS['VPTransp'].val
|
||||
PARAMS['ObOffset'] = Vector(GUIPARAMS['XOff'].val, GUIPARAMS['YOff'].val, GUIPARAMS['ZOff'].val)
|
||||
|
||||
PARAMS['NewMat'] = not GUIPARAMS['CopyMat'].val
|
||||
PARAMS['MaterialId'] = GUIPARAMS['MatId'].val
|
||||
PARAMS['MatProps']['Col'] = list(GUIPARAMS['MatCol'].val)
|
||||
PARAMS['MatProps']['Ref'] = GUIPARAMS['Ref'].val
|
||||
PARAMS['MatProps']['Spec'] = GUIPARAMS['Spec'].val
|
||||
PARAMS['MatProps']['Hard'] = GUIPARAMS['Hard'].val
|
||||
PARAMS['MatProps']['Alpha'] = GUIPARAMS['Alpha'].val
|
||||
PARAMS['MatProps']['ZTransp'] = GUIPARAMS['ZTransp'].val
|
||||
PARAMS['MatProps']['Shadeless'] = GUIPARAMS['Shadeless'].val
|
||||
|
||||
PARAMS['TexChannel'] = GUIPARAMS['TexChan'].val - 1 #Channels are 0-9, but GUI shows 1-10
|
||||
PARAMS['TexProps']['UseAlpha'] = GUIPARAMS['UseAlpha'].val
|
||||
PARAMS['TexProps']['CalcAlpha'] = GUIPARAMS['CalcAlpha'].val
|
||||
PARAMS['TexProps']['ExtendMode'] = GUIPARAMS['ExtendMode'].val
|
||||
PARAMS['TexMapTo']['Col'] = GUIPARAMS['MPTCol'].val
|
||||
PARAMS['TexMapTo']['Alpha'] = GUIPARAMS['MPTAlpha'].val
|
||||
|
||||
PARAMS['SeqProps']['AutoRefresh'] = GUIPARAMS['AutoRefresh'].val
|
||||
PARAMS['SeqProps']['Cyclic'] = GUIPARAMS['Cyclic'].val
|
||||
PARAMS['SeqProps']['Frames'] = GUIPARAMS['Frames'].val
|
||||
PARAMS['SeqProps']['Offs'] = GUIPARAMS['Offs'].val
|
||||
PARAMS['SeqProps']['StartFr'] = GUIPARAMS['StartFr'].val
|
||||
return
|
||||
|
||||
def doScript():
|
||||
# Main script Function
|
||||
# Consists of choosing between 2 loops, one with a redraw, one without, see comments for why
|
||||
|
||||
global CUROFFS
|
||||
|
||||
translateParams()
|
||||
|
||||
total = len(PARAMS['ImagePaths'])
|
||||
broken = 0
|
||||
|
||||
if GUIPARAMS['RedrawImp'].val: # Reduces the need to compare on every go through the loop
|
||||
for i, path in enumerate(PARAMS['ImagePaths']):
|
||||
CUROFFS = i # Could be passed to the import Function, but I chose a global instead
|
||||
Window.DrawProgressBar(float(i)/total, "Importing %i of %i Images..." %(i+1, total))
|
||||
imgImport(path)
|
||||
Blender.Redraw()
|
||||
if Blender.Get('version') >= 246:
|
||||
if Window.TestBreak():
|
||||
broken = 1
|
||||
break
|
||||
else:
|
||||
for i, path in enumerate(PARAMS['ImagePaths']):
|
||||
CUROFFS = i
|
||||
Window.DrawProgressBar(float(i)/total, "Importing %i of %i Images..." %(i+1, total))
|
||||
imgImport(path)
|
||||
if Blender.Get('version') >= 246:
|
||||
if Window.TestBreak():
|
||||
broken = 1
|
||||
break
|
||||
|
||||
if broken:
|
||||
Window.DrawProgressBar(1.0, "Script Execution Aborted")
|
||||
else:
|
||||
Window.DrawProgressBar(1.0, "Finished Importing")
|
||||
|
||||
Blender.Redraw() # Force a refresh, since the user may have chosen to not refresh as they go along
|
||||
|
||||
return
|
||||
|
||||
##########################################
|
||||
# PATH SETTERS AND CHANGERS
|
||||
##########################################
|
||||
|
||||
def setSinglePath(filename):
|
||||
global GUIPARAMS, PARAMS
|
||||
GUIPARAMS['Path'].val = filename
|
||||
PARAMS['ImagePaths'] = [filename]
|
||||
return
|
||||
|
||||
def setDirPath(filename):
|
||||
global GUIPARAMS, PARAMS
|
||||
|
||||
try:
|
||||
import os
|
||||
except:
|
||||
Draw.PupMenu('Full install of python required to be able to set Directory Paths')
|
||||
Draw.Exit()
|
||||
return
|
||||
|
||||
path = os.path.dirname(filename) # Blender.sys.dirname fails on '/'
|
||||
GUIPARAMS['Path'].val = path
|
||||
|
||||
ext_lower = GUIPARAMS['ImageExt'].val.lower()
|
||||
for f in os.listdir(path):
|
||||
if f.lower().endswith(ext_lower):
|
||||
PARAMS['ImagePaths'].append(os.path.join(path, f))
|
||||
|
||||
return
|
||||
|
||||
def changeExtension():
|
||||
global GUIPARAMS, PARAMS
|
||||
|
||||
if PARAMS['ImportType'] == SINGLE:
|
||||
return
|
||||
|
||||
try:
|
||||
import os
|
||||
except:
|
||||
Draw.PupMenu('Full install of python required to be able to set Directory Paths')
|
||||
Draw.Exit()
|
||||
return
|
||||
|
||||
PARAMS['ImagePaths'] = []
|
||||
|
||||
ext_lower = GUIPARAMS['ImageExt'].val.lower()
|
||||
for f in os.listdir(GUIPARAMS['Path'].val):
|
||||
if f.lower().endswith(ext_lower):
|
||||
PARAMS['ImagePaths'].append(os.path.join(GUIPARAMS['Path'].val, f))
|
||||
|
||||
return
|
||||
|
||||
##########################################
|
||||
# INTERFACE FUNCTIONS
|
||||
##########################################
|
||||
def compileMaterialList():
|
||||
# Pretty straight forward, just grabs the materials in the blend file and constructs
|
||||
# an appropriate string for use as a menu
|
||||
|
||||
mats = [mat for mat in bpy.data.materials]
|
||||
PARAMS['Materials'] = mats
|
||||
title = 'Materials%t|'
|
||||
menStrs = [mat.name + '%x' + str(i) + '|' for i, mat in enumerate(mats)]
|
||||
return title + ''.join(menStrs)
|
||||
|
||||
def event(evt, val):
|
||||
# Disabled, since Esc is often used from the file browser
|
||||
#if evt == Draw.ESCKEY:
|
||||
# Draw.Exit()
|
||||
|
||||
return
|
||||
|
||||
def bevent(evt):
|
||||
global GUIPARAMS, PARAMS
|
||||
|
||||
if evt == NO_EVT:
|
||||
Draw.Redraw()
|
||||
|
||||
elif evt == SINGLE_IMG:
|
||||
Window.FileSelector(setSinglePath, 'Image', Blender.sys.expandpath('//'))
|
||||
Draw.Redraw()
|
||||
PARAMS['ImportType'] = SINGLE
|
||||
|
||||
elif evt == DIRECTORY_IMG:
|
||||
Window.FileSelector(setDirPath, 'Directory', Blender.sys.expandpath('//'))
|
||||
Draw.Redraw()
|
||||
PARAMS['ImportType'] = DIR
|
||||
|
||||
elif evt == CLR_PATH:
|
||||
GUIPARAMS['Path'].val = ''
|
||||
PARAMS['ImagePaths'] = []
|
||||
GUIPARAMS['ImageExt'].val = ''
|
||||
Draw.Redraw()
|
||||
|
||||
elif evt == CHG_EXT:
|
||||
changeExtension()
|
||||
Draw.Redraw()
|
||||
|
||||
elif evt == EXIT:
|
||||
Draw.Exit()
|
||||
|
||||
elif evt == DO_SCRIPT:
|
||||
doScript()
|
||||
|
||||
else:
|
||||
print "ERROR: UNEXPECTED BUTTON EVENT"
|
||||
|
||||
return
|
||||
|
||||
# GUI Colors ######
|
||||
ScreenColor = [0.7, 0.7, 0.7]
|
||||
BackgroundColor = [0.8, 0.8, 0.8]
|
||||
TitleBG = [0.6, 0.6, 0.6]
|
||||
TitleCol = [1.0, 1.0, 1.0]
|
||||
ErrCol = [1.0, 0.0, 0.0]
|
||||
TextCol = [0.4, 0.4, 0.5]
|
||||
###################
|
||||
|
||||
def GUI():
|
||||
global GUIPARAMS, PARAMS
|
||||
|
||||
BGL.glClearColor(*(ScreenColor + [1.0]))
|
||||
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
minx = 5
|
||||
maxx = 500
|
||||
miny = 5
|
||||
maxy = 450
|
||||
|
||||
lineheight = 24
|
||||
buPad = 5 # Generic Button Padding, most buttons should have 24-19 (or 5) px space around them
|
||||
|
||||
lP = 5 # Left Padding
|
||||
rP = 5 # Right Padding
|
||||
|
||||
# Draw Background Box
|
||||
BGL.glColor3f(*BackgroundColor)
|
||||
BGL.glRecti(minx, miny, maxx, maxy)
|
||||
|
||||
# Draw Title
|
||||
BGL.glColor3f(*TitleBG)
|
||||
BGL.glRecti(minx, maxy - (lineheight), maxx, maxy)
|
||||
BGL.glColor3f(*TitleCol)
|
||||
|
||||
title = "2D Cutout Image Importer v" + VERSIONSTRING
|
||||
BGL.glRasterPos2i(minx + lP, maxy - 15)
|
||||
Draw.Text(title, 'large')
|
||||
|
||||
Draw.PushButton('Exit', EXIT, maxx-50-rP, maxy - lineheight + 2, 50, 19, "Exit Script")
|
||||
|
||||
# Path Buttons
|
||||
if GUIPARAMS['Path'].val == '':
|
||||
Draw.PushButton('Single Image', SINGLE_IMG, minx + lP, maxy - (2*lineheight), 150, 19, "Select a Single Image to Import")
|
||||
Draw.PushButton('Directory', DIRECTORY_IMG, minx + lP + 150, maxy - (2*lineheight), 150, 19, "Select a Directory of Images to Import")
|
||||
|
||||
else:
|
||||
Draw.PushButton('Clear', CLR_PATH, minx+lP, maxy - (2*lineheight), 50, 19, "Clear Path and Change Import Options")
|
||||
|
||||
GUIPARAMS['Path'] = Draw.String('Path: ', NO_EVT, minx + lP, maxy - (3*lineheight), (maxx-minx-lP-rP), 19, GUIPARAMS['Path'].val, 399, 'Path to Import From')
|
||||
if PARAMS['ImportType'] == DIR:
|
||||
GUIPARAMS['ImageExt'] = Draw.String('Image Ext: ', CHG_EXT, minx + lP, maxy - (4*lineheight), 110, 19, GUIPARAMS['ImageExt'].val, 6, 'Image extension for batch directory importing (case insensitive)')
|
||||
GUIPARAMS['PackImage'] = Draw.Toggle('Pack', NO_EVT, maxx - rP - 50, maxy - (4*lineheight), 50, 19, GUIPARAMS['PackImage'].val, 'Pack Image(s) into .Blend File')
|
||||
|
||||
# Geometry and Viewport Options
|
||||
BGL.glColor3f(*TextCol)
|
||||
BGL.glRecti(minx+lP, maxy - (5*lineheight), maxx-rP, maxy - (5*lineheight) + 1)
|
||||
BGL.glRasterPos2i(minx + lP, maxy-(5*lineheight) + 3)
|
||||
Draw.Text('Geometry and Display Options', 'small')
|
||||
|
||||
GUIPARAMS['PPU'] = Draw.Slider('Pixels Per Unit: ', NO_EVT, minx + lP, maxy - (6*lineheight), (maxx-minx)/2 - lP, 19, GUIPARAMS['PPU'].val, 1, 5000, 0, 'Set the Number of Pixels Per Blender Unit to preserve Image Size Relations')
|
||||
GUIPARAMS['VPTransp'] = Draw.Toggle('Viewport Transparency', NO_EVT, minx + lP, maxy - (8*lineheight), (maxx-minx)/2 - lP, 2*lineheight - buPad, GUIPARAMS['VPTransp'].val, 'Display Alpha Transparency in the Viewport')
|
||||
|
||||
GUIPARAMS['XOff'] = Draw.Slider('Offs X: ', NO_EVT, minx + lP + (maxx-minx)/2, maxy - (6*lineheight), (maxx-minx)/2 - lP - rP, 19, GUIPARAMS['XOff'].val, 0, 5.0, 0, 'Amount to Offset Each Imported in the X-Direction if Importing Multiple Images')
|
||||
GUIPARAMS['YOff'] = Draw.Slider('Offs Y: ', NO_EVT, minx + lP + (maxx-minx)/2, maxy - (7*lineheight), (maxx-minx)/2 - lP - rP, 19, GUIPARAMS['YOff'].val, 0, 5.0, 0, 'Amount to Offset Each Imported in the Y-Direction if Importing Multiple Images')
|
||||
GUIPARAMS['ZOff'] = Draw.Slider('Offs Z: ', NO_EVT, minx + lP + (maxx-minx)/2, maxy - (8*lineheight), (maxx-minx)/2 - lP - rP, 19, GUIPARAMS['ZOff'].val, 0, 5.0, 0, 'Amount to Offset Each Imported in the Z-Direction if Importing Multiple Images')
|
||||
|
||||
# Material and Texture Options
|
||||
BGL.glColor3f(*TextCol)
|
||||
BGL.glRecti(minx+lP, maxy - (9*lineheight), maxx-rP, maxy - (9*lineheight) + 1)
|
||||
BGL.glRasterPos2i(minx + lP, maxy-(9*lineheight) + 3)
|
||||
Draw.Text('Material and Texture Options', 'small')
|
||||
|
||||
half = (maxx-minx-lP-rP)/2
|
||||
GUIPARAMS['CopyMat'] = Draw.Toggle('Copy Existing Material', NO_EVT, minx + lP, maxy-(10*lineheight), half, 19, GUIPARAMS['CopyMat'].val, 'Copy an Existing Material')
|
||||
if GUIPARAMS['CopyMat'].val:
|
||||
menStr = compileMaterialList()
|
||||
GUIPARAMS['MatId'] = Draw.Menu(menStr, NO_EVT, minx + lP, maxy - (11*lineheight), half, 19, GUIPARAMS['MatId'].val, 'Material to Copy Settings From')
|
||||
else:
|
||||
GUIPARAMS['MatCol'] = Draw.ColorPicker(NO_EVT, minx+lP, maxy - (13*lineheight), 40, (3*lineheight) - buPad, GUIPARAMS['MatCol'].val, 'Color of Newly Created Material')
|
||||
GUIPARAMS['Ref'] = Draw.Slider('Ref: ', NO_EVT, minx +lP+45, maxy - (11*lineheight), half-45, 19, GUIPARAMS['Ref'].val, 0.0, 1.0, 0, 'Set the Ref Value for Created Materials')
|
||||
GUIPARAMS['Spec'] = Draw.Slider('Spec: ', NO_EVT, minx +lP+45, maxy - (12*lineheight), half-45, 19, GUIPARAMS['Spec'].val, 0.0, 2.0, 0, 'Set the Spec Value for Created Materials')
|
||||
GUIPARAMS['Hard'] = Draw.Slider('Hard: ', NO_EVT, minx +lP+45, maxy - (13*lineheight), half-45, 19, GUIPARAMS['Hard'].val, 1, 500, 0, 'Set the Hardness Value for Created Materials')
|
||||
GUIPARAMS['Alpha'] = Draw.Slider('A: ', NO_EVT, minx +lP, maxy - (14*lineheight), half, 19, GUIPARAMS['Alpha'].val, 0.0, 1.0, 0, 'Set the Alpha Value for Created Materials')
|
||||
|
||||
GUIPARAMS['ZTransp'] = Draw.Toggle('ZTransparency', NO_EVT, minx + lP, maxy - (15*lineheight), half, 19, GUIPARAMS['ZTransp'].val, 'Enable ZTransparency')
|
||||
GUIPARAMS['Shadeless'] = Draw.Toggle('Shadeless', NO_EVT, minx + lP, maxy - (16*lineheight), half, 19, GUIPARAMS['Shadeless'].val, 'Enable Shadeless')
|
||||
|
||||
GUIPARAMS['TexChan'] = Draw.Number('Texture Channel: ', NO_EVT, minx + lP+ half + buPad, maxy - (10*lineheight), half-rP, 19, GUIPARAMS['TexChan'].val, 1, 10, 'Texture Channel for Image Texture')
|
||||
|
||||
GUIPARAMS['MPTCol'] = Draw.Toggle('Color', NO_EVT, minx + lP + half + buPad, maxy - (11*lineheight), half/2, 19, GUIPARAMS['MPTCol'].val, 'Map To Color Channel')
|
||||
GUIPARAMS['MPTAlpha'] = Draw.Toggle('Alpha', NO_EVT, minx + lP + int((1.5)*half) + buPad, maxy - (11*lineheight), half/2 - rP, 19, GUIPARAMS['MPTAlpha'].val, 'Map To Alpha Channel')
|
||||
|
||||
third = int((maxx-minx-lP-rP)/6)
|
||||
GUIPARAMS['UseAlpha'] = Draw.Toggle('Use Alpha', NO_EVT, minx + lP + half + buPad, maxy - (12*lineheight), third, 19, GUIPARAMS['UseAlpha'].val, "Use the Images' Alpha Values")
|
||||
GUIPARAMS['CalcAlpha'] = Draw.Toggle('Calc Alpha', NO_EVT, minx + lP + half + third + buPad, maxy - (12*lineheight), third, 19, GUIPARAMS['CalcAlpha'].val, "Calculate Images' Alpha Values")
|
||||
GUIPARAMS['ExtendMode'] = Draw.Toggle('Extend', NO_EVT, minx+lP+half+third+third+buPad, maxy - (12*lineheight), third-3, 19, GUIPARAMS['ExtendMode'].val, "Use Extend texture mode. If deselected, Repeat is used")
|
||||
GUIPARAMS['Seq'] = Draw.Toggle('Sequence', NO_EVT, minx + lP + half + buPad, maxy - (13*lineheight), half-rP, 19, GUIPARAMS['Seq'].val, 'Set the Image(s) to use a Sequence instead of a Still')
|
||||
|
||||
if GUIPARAMS['Seq'].val and not PARAMS['ImportType'] == DIR:
|
||||
GUIPARAMS['AutoRefresh'] = Draw.Toggle('Auto Refresh', NO_EVT, minx + lP + half + buPad, maxy - (14*lineheight), half/2, 19, GUIPARAMS['AutoRefresh'].val, 'Use Auto Refresh')
|
||||
GUIPARAMS['Cyclic'] = Draw.Toggle('Cyclic', NO_EVT, minx + lP + half + buPad + half/2, maxy - (14*lineheight), half/2 - rP, 19, GUIPARAMS['Cyclic'].val, 'Repeat Frames Cyclically`')
|
||||
|
||||
GUIPARAMS['Frames'] = Draw.Number('Frames: ', NO_EVT, minx +lP + half + buPad, maxy - (15*lineheight), half - rP, 19, GUIPARAMS['Frames'].val, 1, 30000, 'Sets the Number of Images of a Movie to Use')
|
||||
GUIPARAMS['Offs'] = Draw.Number('Offs: ', NO_EVT, minx +lP + half + buPad, maxy - (16*lineheight), half/2, 19, GUIPARAMS['Offs'].val, -30000, 30000, 'Offsets the Number of the Frame to use in the Animation')
|
||||
GUIPARAMS['StartFr'] = Draw.Number('StartFr: ', NO_EVT, minx +lP + half + buPad + half/2, maxy - (16*lineheight), half/2 - rP, 19, GUIPARAMS['StartFr'].val, 1, 30000, 'Sets the Global Starting Frame of the Movie')
|
||||
elif GUIPARAMS['Seq'].val and PARAMS['ImportType'] == DIR:
|
||||
BGL.glColor3f(*ErrCol)
|
||||
BGL.glRasterPos2i(minx + lP + half + buPad + 7, maxy-(14 * lineheight) + 5)
|
||||
Draw.Text('Sequence only available for Single Image Import', 'small')
|
||||
|
||||
# Import Options
|
||||
BGL.glColor3f(*TextCol)
|
||||
BGL.glRecti(minx+lP, maxy - (17*lineheight), maxx-rP, maxy - (17*lineheight) + 1)
|
||||
BGL.glRasterPos2i(minx + lP, maxy-(17*lineheight) + 3)
|
||||
Draw.Text('Import', 'small')
|
||||
|
||||
if GUIPARAMS['Path'].val and GUIPARAMS['ImageExt'].val or GUIPARAMS['Path'].val and PARAMS['ImportType'] == SINGLE:
|
||||
Draw.PushButton('Import', DO_SCRIPT, minx + lP, maxy - (18*lineheight), 75, 19, "Import Image(s)")
|
||||
else:
|
||||
BGL.glColor3f(*ErrCol)
|
||||
BGL.glRasterPos2i(minx+lP, maxy - (18*lineheight) + 5)
|
||||
Draw.Text('A path and image type must be specified to import images')
|
||||
|
||||
GUIPARAMS['RedrawImp'] = Draw.Toggle('Redraw During Import', NO_EVT, maxx - rP - 150, maxy - (18*lineheight), 150, 19, GUIPARAMS['RedrawImp'].val, 'Redraw the View as Images Import')
|
||||
|
||||
Draw.Register(GUI, event, bevent)
|
||||
@@ -1,455 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Consolidate into one image'
|
||||
Blender: 243
|
||||
Group: 'Image'
|
||||
Tooltip: 'Pack all texture images into 1 image and remap faces.'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ("blender", "blenderartists.org")
|
||||
__version__ = "1.1a 2009/04/01"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script makes a new image from the used areas of all the images mapped to the selected mesh objects.
|
||||
Image are packed into 1 new image that is assigned to the original faces.
|
||||
This is usefull for game models where 1 image is faster then many, and saves the labour of manual texture layout in an image editor.
|
||||
|
||||
"""
|
||||
# --------------------------------------------------------------------------
|
||||
# Auto Texture Layout v1.0 by Campbell Barton (AKA Ideasman)
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Function to find all the images we use
|
||||
import Blender as B
|
||||
from Blender.Mathutils import Vector, RotationMatrix
|
||||
from Blender.Scene import Render
|
||||
import BPyMathutils
|
||||
BIGNUM= 1<<30
|
||||
TEXMODE= B.Mesh.FaceModes.TEX
|
||||
|
||||
def pointBounds(points):
|
||||
'''
|
||||
Takes a list of points and returns the
|
||||
area, center, bounds
|
||||
'''
|
||||
ymax= xmax= -BIGNUM
|
||||
ymin= xmin= BIGNUM
|
||||
|
||||
for p in points:
|
||||
x= p.x
|
||||
y= p.y
|
||||
|
||||
if x>xmax: xmax=x
|
||||
if y>ymax: ymax=y
|
||||
|
||||
if x<xmin: xmin=x
|
||||
if y<ymin: ymin=y
|
||||
|
||||
# area and center
|
||||
return\
|
||||
(xmax-xmin) * (ymax-ymin),\
|
||||
Vector((xmin+xmax)/2, (ymin+ymax)/2),\
|
||||
(xmin, ymin, xmax, ymax)
|
||||
|
||||
|
||||
def bestBoundsRotation(current_points):
|
||||
'''
|
||||
Takes a list of points and returns the best rotation for those points
|
||||
so they fit into the samllest bounding box
|
||||
'''
|
||||
|
||||
current_area, cent, bounds= pointBounds(current_points)
|
||||
|
||||
total_rot_angle= 0.0
|
||||
rot_angle= 45
|
||||
while rot_angle > 0.1:
|
||||
mat_pos= RotationMatrix( rot_angle, 2)
|
||||
mat_neg= RotationMatrix( -rot_angle, 2)
|
||||
|
||||
new_points_pos= [v*mat_pos for v in current_points]
|
||||
area_pos, cent_pos, bounds_pos= pointBounds(new_points_pos)
|
||||
|
||||
# 45d rotations only need to be tested in 1 direction.
|
||||
if rot_angle == 45:
|
||||
area_neg= area_pos
|
||||
else:
|
||||
new_points_neg= [v*mat_neg for v in current_points]
|
||||
area_neg, cent_neg, bounds_neg= pointBounds(new_points_neg)
|
||||
|
||||
|
||||
# Works!
|
||||
#print 'Testing angle', rot_angle, current_area, area_pos, area_neg
|
||||
|
||||
best_area= min(area_pos, area_neg, current_area)
|
||||
if area_pos == best_area:
|
||||
current_area= area_pos
|
||||
cent= cent_pos
|
||||
bounds= bounds_pos
|
||||
current_points= new_points_pos
|
||||
total_rot_angle+= rot_angle
|
||||
elif rot_angle != 45 and area_neg == best_area:
|
||||
current_area= area_neg
|
||||
cent= cent_neg
|
||||
bounds= bounds_neg
|
||||
current_points= new_points_neg
|
||||
total_rot_angle-= rot_angle
|
||||
|
||||
rot_angle *= 0.5
|
||||
|
||||
# Return the optimal rotation.
|
||||
return total_rot_angle
|
||||
|
||||
|
||||
class faceGroup(object):
|
||||
'''
|
||||
A Group of faces that all use the same image, each group has its UVs packed into a square.
|
||||
'''
|
||||
__slots__= 'xmax', 'ymax', 'xmin', 'ymin',\
|
||||
'image', 'faces', 'box_pack', 'size', 'ang', 'rot_mat', 'cent'\
|
||||
|
||||
def __init__(self, mesh_list, image, size, PREF_IMAGE_MARGIN):
|
||||
self.image= image
|
||||
self.size= size
|
||||
self.faces= [f for me in mesh_list for f in me.faces if f.mode & TEXMODE and f.image == image]
|
||||
|
||||
# Find the best rotation.
|
||||
all_points= [uv for f in self.faces for uv in f.uv]
|
||||
bountry_indicies= BPyMathutils.convexHull(all_points)
|
||||
bountry_points= [all_points[i] for i in bountry_indicies]
|
||||
|
||||
# Pre Rotation bounds
|
||||
self.cent= pointBounds(bountry_points)[1]
|
||||
|
||||
# Get the optimal rotation angle
|
||||
self.ang= bestBoundsRotation(bountry_points)
|
||||
self.rot_mat= RotationMatrix(self.ang, 2), RotationMatrix(-self.ang, 2)
|
||||
|
||||
# Post rotation bounds
|
||||
bounds= pointBounds([\
|
||||
((uv-self.cent) * self.rot_mat[0]) + self.cent\
|
||||
for uv in bountry_points])[2]
|
||||
|
||||
# Break the bounds into useable values.
|
||||
xmin, ymin, xmax, ymax= bounds
|
||||
|
||||
# Store the bounds, include the margin.
|
||||
# The bounds rect will need to be rotated to the rotation angle.
|
||||
self.xmax= xmax + (PREF_IMAGE_MARGIN/size[0])
|
||||
self.xmin= xmin - (PREF_IMAGE_MARGIN/size[0])
|
||||
self.ymax= ymax + (PREF_IMAGE_MARGIN/size[1])
|
||||
self.ymin= ymin - (PREF_IMAGE_MARGIN/size[1])
|
||||
|
||||
self.box_pack=[\
|
||||
0.0, 0.0,\
|
||||
size[0]*(self.xmax - self.xmin),\
|
||||
size[1]*(self.ymax - self.ymin),\
|
||||
image.name]
|
||||
|
||||
'''
|
||||
# default.
|
||||
self.scale= 1.0
|
||||
|
||||
def set_worldspace_scale(self):
|
||||
scale_uv= 0.0
|
||||
scale_3d= 0.0
|
||||
for f in self.faces:
|
||||
for i in xrange(len(f.v)):
|
||||
scale_uv+= (f.uv[i]-f.uv[i-1]).length * 0.1
|
||||
scale_3d+= (f.v[i].co-f.v[i-1].co).length * 0.1
|
||||
self.scale= scale_3d/scale_uv
|
||||
'''
|
||||
|
||||
|
||||
|
||||
def move2packed(self, width, height):
|
||||
'''
|
||||
Moves the UV coords to their packed location
|
||||
using self.box_pack as the offset, scaler.
|
||||
box_pack must be set to its packed location.
|
||||
width and weight are the w/h of the overall packed area's bounds.
|
||||
'''
|
||||
# packedLs is a list of [(anyUniqueID, left, bottom, width, height)...]
|
||||
# Width and height in float pixel space.
|
||||
|
||||
# X Is flipped :/
|
||||
#offset_x= (1-(self.box_pack[1]/d)) - (((self.xmax-self.xmin) * self.image.size[0])/d)
|
||||
offset_x= self.box_pack[0]/width
|
||||
offset_y= self.box_pack[1]/height
|
||||
|
||||
for f in self.faces:
|
||||
for uv in f.uv:
|
||||
uv_rot= ((uv-self.cent) * self.rot_mat[0]) + self.cent
|
||||
uv.x= offset_x+ (((uv_rot.x-self.xmin) * self.size[0])/width)
|
||||
uv.y= offset_y+ (((uv_rot.y-self.ymin) * self.size[1])/height)
|
||||
|
||||
def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN): #, PREF_SIZE_FROM_UV=True):
|
||||
'''
|
||||
Main packing function
|
||||
|
||||
All meshes from mesh_list must have faceUV else this function will fail.
|
||||
'''
|
||||
face_groups= {}
|
||||
|
||||
for me in mesh_list:
|
||||
for f in me.faces:
|
||||
if f.mode & TEXMODE:
|
||||
image= f.image
|
||||
if image:
|
||||
try:
|
||||
face_groups[image.name] # will fail if teh groups not added.
|
||||
except:
|
||||
try:
|
||||
size= image.size
|
||||
except:
|
||||
B.Draw.PupMenu('Aborting: Image cold not be loaded|' + image.name)
|
||||
return
|
||||
|
||||
face_groups[image.name]= faceGroup(mesh_list, image, size, PREF_IMAGE_MARGIN)
|
||||
|
||||
if not face_groups:
|
||||
B.Draw.PupMenu('No Images found in mesh(es). Aborting!')
|
||||
return
|
||||
|
||||
if len(face_groups)<2:
|
||||
B.Draw.PupMenu('Only 1 image found|Select a mesh(es) using 2 or more images.')
|
||||
return
|
||||
|
||||
'''
|
||||
if PREF_SIZE_FROM_UV:
|
||||
for fg in face_groups.itervalues():
|
||||
fg.set_worldspace_scale()
|
||||
'''
|
||||
|
||||
# RENDER THE FACES.
|
||||
render_scn= B.Scene.New()
|
||||
render_scn.makeCurrent()
|
||||
render_context= render_scn.getRenderingContext()
|
||||
render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path.
|
||||
|
||||
PREF_IMAGE_PATH_EXPAND= B.sys.expandpath(PREF_IMAGE_PATH) + '.png'
|
||||
|
||||
# TEST THE FILE WRITING.
|
||||
try:
|
||||
# Can we write to this file???
|
||||
f= open(PREF_IMAGE_PATH_EXPAND, 'w')
|
||||
f.close()
|
||||
except:
|
||||
B.Draw.PupMenu('Error%t|Could not write to path|' + PREF_IMAGE_PATH_EXPAND)
|
||||
return
|
||||
|
||||
render_context.imageSizeX(PREF_IMAGE_SIZE)
|
||||
render_context.imageSizeY(PREF_IMAGE_SIZE)
|
||||
render_context.enableOversampling(True)
|
||||
render_context.setOversamplingLevel(16)
|
||||
render_context.setRenderWinSize(100)
|
||||
render_context.setImageType(Render.PNG)
|
||||
render_context.enableExtensions(True)
|
||||
render_context.enablePremultiply() # No alpha needed.
|
||||
render_context.enableRGBAColor()
|
||||
render_context.threads = 2
|
||||
|
||||
#Render.EnableDispView() # Broken??
|
||||
|
||||
# New Mesh and Object
|
||||
render_mat= B.Material.New()
|
||||
render_mat.mode |= \
|
||||
B.Material.Modes.SHADELESS | \
|
||||
B.Material.Modes.TEXFACE | \
|
||||
B.Material.Modes.TEXFACE_ALPHA | \
|
||||
B.Material.Modes.ZTRANSP
|
||||
|
||||
render_mat.setAlpha(0.0)
|
||||
|
||||
render_me= B.Mesh.New()
|
||||
render_me.verts.extend([Vector(0,0,0)]) # Stupid, dummy vert, preverts errors. when assigning UV's/
|
||||
render_ob= B.Object.New('Mesh')
|
||||
render_ob.link(render_me)
|
||||
render_scn.link(render_ob)
|
||||
render_me.materials= [render_mat]
|
||||
|
||||
|
||||
# New camera and object
|
||||
render_cam_data= B.Camera.New('ortho')
|
||||
render_cam_ob= B.Object.New('Camera')
|
||||
render_cam_ob.link(render_cam_data)
|
||||
render_scn.link(render_cam_ob)
|
||||
render_scn.objects.camera = render_cam_ob
|
||||
|
||||
render_cam_data.type= 'ortho'
|
||||
render_cam_data.scale= 1.0
|
||||
|
||||
|
||||
# Position the camera
|
||||
render_cam_ob.LocZ= 1.0
|
||||
render_cam_ob.LocX= 0.5
|
||||
render_cam_ob.LocY= 0.5
|
||||
|
||||
# List to send to to boxpack function.
|
||||
boxes2Pack= [ fg.box_pack for fg in face_groups.itervalues()]
|
||||
packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack)
|
||||
|
||||
if PREF_KEEP_ASPECT:
|
||||
packWidth= packHeight= max(packWidth, packHeight)
|
||||
|
||||
|
||||
# packedLs is a list of [(anyUniqueID, left, bottom, width, height)...]
|
||||
# Re assign the face groups boxes to the face_group.
|
||||
for box in boxes2Pack:
|
||||
face_groups[ box[4] ].box_pack= box # box[4] is the ID (image name)
|
||||
|
||||
|
||||
# Add geometry to the mesh
|
||||
for fg in face_groups.itervalues():
|
||||
# Add verts clockwise from the bottom left.
|
||||
_x= fg.box_pack[0] / packWidth
|
||||
_y= fg.box_pack[1] / packHeight
|
||||
_w= fg.box_pack[2] / packWidth
|
||||
_h= fg.box_pack[3] / packHeight
|
||||
|
||||
render_me.verts.extend([\
|
||||
Vector(_x, _y, 0),\
|
||||
Vector(_x, _y +_h, 0),\
|
||||
Vector(_x + _w, _y +_h, 0),\
|
||||
Vector(_x + _w, _y, 0),\
|
||||
])
|
||||
|
||||
render_me.faces.extend([\
|
||||
render_me.verts[-1],\
|
||||
render_me.verts[-2],\
|
||||
render_me.verts[-3],\
|
||||
render_me.verts[-4],\
|
||||
])
|
||||
|
||||
target_face= render_me.faces[-1]
|
||||
target_face.image= fg.image
|
||||
target_face.mode |= TEXMODE
|
||||
|
||||
# Set the UV's, we need to flip them HOZ?
|
||||
target_face.uv[0].x= target_face.uv[1].x= fg.xmax
|
||||
target_face.uv[2].x= target_face.uv[3].x= fg.xmin
|
||||
|
||||
target_face.uv[0].y= target_face.uv[3].y= fg.ymin
|
||||
target_face.uv[1].y= target_face.uv[2].y= fg.ymax
|
||||
|
||||
for uv in target_face.uv:
|
||||
uv_rot= ((uv-fg.cent) * fg.rot_mat[1]) + fg.cent
|
||||
uv.x= uv_rot.x
|
||||
uv.y= uv_rot.y
|
||||
|
||||
render_context.render()
|
||||
Render.CloseRenderWindow()
|
||||
render_context.saveRenderedImage(PREF_IMAGE_PATH_EXPAND)
|
||||
|
||||
#if not B.sys.exists(PREF_IMAGE_PATH_EXPAND):
|
||||
# raise 'Error!!!'
|
||||
|
||||
|
||||
# NOW APPLY THE SAVED IMAGE TO THE FACES!
|
||||
#print PREF_IMAGE_PATH_EXPAND
|
||||
try:
|
||||
target_image= B.Image.Load(PREF_IMAGE_PATH_EXPAND)
|
||||
except:
|
||||
B.Draw.PupMenu('Error: Could not render or load the image at path|' + PREF_IMAGE_PATH_EXPAND)
|
||||
return
|
||||
|
||||
# Set to the 1 image.
|
||||
for me in mesh_list:
|
||||
for f in me.faces:
|
||||
if f.mode & TEXMODE and f.image:
|
||||
f.image= target_image
|
||||
|
||||
for fg in face_groups.itervalues():
|
||||
fg.move2packed(packWidth, packHeight)
|
||||
|
||||
scn.makeCurrent()
|
||||
render_me.verts= None # free a tiny amount of memory.
|
||||
B.Scene.Unlink(render_scn)
|
||||
target_image.makeCurrent()
|
||||
|
||||
|
||||
def main():
|
||||
scn= B.Scene.GetCurrent()
|
||||
scn_objects = scn.objects
|
||||
ob= scn_objects.active
|
||||
|
||||
if not ob or ob.type != 'Mesh':
|
||||
B.Draw.PupMenu('Error, no active mesh object, aborting.')
|
||||
return
|
||||
|
||||
# Create the variables.
|
||||
# Filename without path or extension.
|
||||
newpath= B.Get('filename').split('/')[-1].split('\\')[-1].replace('.blend', '')
|
||||
|
||||
PREF_IMAGE_PATH = B.Draw.Create('//%s_grp' % newpath)
|
||||
PREF_IMAGE_SIZE = B.Draw.Create(1024)
|
||||
PREF_IMAGE_MARGIN = B.Draw.Create(6)
|
||||
PREF_KEEP_ASPECT = B.Draw.Create(0)
|
||||
PREF_ALL_SEL_OBS = B.Draw.Create(0)
|
||||
|
||||
pup_block = [\
|
||||
'Image Path: (no ext)',\
|
||||
('', PREF_IMAGE_PATH, 3, 100, 'Path to new Image. "//" for curent blend dir.'),\
|
||||
'Image Options',
|
||||
('Pixel Size:', PREF_IMAGE_SIZE, 64, 4096, 'Image Width and Height.'),\
|
||||
('Pixel Margin:', PREF_IMAGE_MARGIN, 0, 64, 'Use a margin to stop mipmapping artifacts.'),\
|
||||
('Keep Aspect', PREF_KEEP_ASPECT, 'If disabled, will stretch the images to the bounds of the texture'),\
|
||||
'Texture Source',\
|
||||
('All Sel Objects', PREF_ALL_SEL_OBS, 'Combine all selected objects into 1 texture, otherwise active object only.'),\
|
||||
]
|
||||
|
||||
if not B.Draw.PupBlock('Consolidate images...', pup_block):
|
||||
return
|
||||
|
||||
PREF_IMAGE_PATH= PREF_IMAGE_PATH.val
|
||||
PREF_IMAGE_SIZE= PREF_IMAGE_SIZE.val
|
||||
PREF_IMAGE_MARGIN= float(PREF_IMAGE_MARGIN.val) # important this is a float otherwise division wont work properly
|
||||
PREF_KEEP_ASPECT= PREF_KEEP_ASPECT.val
|
||||
PREF_ALL_SEL_OBS= PREF_ALL_SEL_OBS.val
|
||||
|
||||
if PREF_ALL_SEL_OBS:
|
||||
mesh_list= [ob.getData(mesh=1) for ob in scn_objects.context if ob.type=='Mesh']
|
||||
# Make sure we have no doubles- dict by name, then get the values back.
|
||||
|
||||
for me in mesh_list: me.tag = False
|
||||
|
||||
mesh_list_new = []
|
||||
for me in mesh_list:
|
||||
if me.faceUV and me.tag==False:
|
||||
me.tag = True
|
||||
mesh_list_new.append(me)
|
||||
|
||||
# replace list with possible doubles
|
||||
mesh_list = mesh_list_new
|
||||
|
||||
else:
|
||||
mesh_list= [ob.getData(mesh=1)]
|
||||
if not mesh_list[0].faceUV:
|
||||
B.Draw.PupMenu('Error, active mesh has no images, Aborting!')
|
||||
return
|
||||
|
||||
consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN)
|
||||
B.Window.RedrawAll()
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
@@ -1,269 +0,0 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Billboard Render on Active'
|
||||
Blender: 242
|
||||
Group: 'Image'
|
||||
Tooltip: 'Selected objects and lamps to rendered faces on the act mesh'
|
||||
"""
|
||||
__author__= "Campbell Barton"
|
||||
__url__= ["blender", "blenderartist"]
|
||||
__version__= "1.0"
|
||||
|
||||
__bpydoc__= """\
|
||||
Render Billboard Script
|
||||
This can texture a simple billboard mesh from any number of selected objects.
|
||||
|
||||
Renders objects in the selection to quad faces on the active mesh.
|
||||
|
||||
Usage
|
||||
* Light your model or enable the shadless flag so it is visible
|
||||
* Make a low poly mesh out of quads with 90d corners. (this will be you billboard mesh)
|
||||
* Select the model and any lamps that light it
|
||||
* Select the billboard mesh so that it is active
|
||||
* Run this script, Adjust settings such as image size or oversampling.
|
||||
* Select a place to save the PNG image.
|
||||
* Once the script has finished running return to the 3d view by pressing Shift+F5
|
||||
* To see the newly applied textures change the drawtype to 'Textured Solid'
|
||||
"""
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) Campbell J Barton 2006
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender import Mesh, Material, Draw
|
||||
import BPyMathutils
|
||||
import bpy
|
||||
import BPyRender
|
||||
from Blender.Scene import Render
|
||||
|
||||
# reload(BPyRender)
|
||||
# reload(BPyMathutils)
|
||||
|
||||
import os
|
||||
Vector= Blender.Mathutils.Vector
|
||||
|
||||
def alpha_mat(image):
|
||||
# returns a material useable for
|
||||
mtl= bpy.data.materials.new()
|
||||
mtl.mode |= (Material.Modes.SHADELESS | Material.Modes.ZTRANSP | Material.Modes.FULLOSA | Material.Modes.TEXFACE | Material.Modes.TEXFACE_ALPHA )
|
||||
return mtl
|
||||
|
||||
# PupBlock Settings
|
||||
GLOBALS= {}
|
||||
PREF_RES= Draw.Create(512)
|
||||
PREF_TILE_RES= Draw.Create(256)
|
||||
PREF_AA = Draw.Create(1)
|
||||
PREF_ALPHA= Draw.Create(1)
|
||||
PREF_Z_OFFSET = Draw.Create(10.0)
|
||||
PREF_IMG_PACK= Draw.Create(1)
|
||||
|
||||
|
||||
def save_billboard(PREF_IMAGE_PATH):
|
||||
Blender.Window.WaitCursor(1)
|
||||
# remove png, add it later
|
||||
PREF_IMAGE_PATH= PREF_IMAGE_PATH.replace('.png', '')
|
||||
|
||||
ob_sel= GLOBALS['ob_sel']
|
||||
me_ob = GLOBALS['me_ob']
|
||||
me_data = GLOBALS['me_data']
|
||||
|
||||
time= Blender.sys.time()
|
||||
|
||||
me_mat= me_ob.matrixWorld
|
||||
|
||||
# Render images for all faces
|
||||
face_data= [] # Store faces, images etc
|
||||
boxes2Pack= []
|
||||
me_data.faceUV= True
|
||||
|
||||
for i, f in enumerate(me_data.faces):
|
||||
no= f.no
|
||||
|
||||
# Offset the plane by the zoffset on the faces normal
|
||||
plane= [v.co * me_mat for v in f]
|
||||
|
||||
# Horizontal stacking, make sure 0,1 and 2,3 are the longest
|
||||
if\
|
||||
(plane[0]-plane[1]).length + (plane[2]-plane[3]).length < \
|
||||
(plane[1]-plane[2]).length + (plane[3]-plane[0]).length:
|
||||
plane.append(plane.pop(0))
|
||||
rot90= True
|
||||
else:
|
||||
rot90= False
|
||||
|
||||
no= Blender.Mathutils.QuadNormal(*plane)
|
||||
plane= [v + no*PREF_Z_OFFSET.val for v in plane]
|
||||
|
||||
cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0
|
||||
camera_matrix= BPyMathutils.plane2mat(plane)
|
||||
tmp_path= '%s_%d' % (PREF_IMAGE_PATH, i)
|
||||
img= BPyRender.imageFromObjectsOrtho(ob_sel, tmp_path, PREF_TILE_RES.val, PREF_TILE_RES.val, PREF_AA.val, PREF_ALPHA.val, camera_matrix)
|
||||
img.reload()
|
||||
#img.pack() # se we can keep overwriting the path
|
||||
#img.filename= ""
|
||||
|
||||
if rot90:
|
||||
f.uv=Vector(1,1), Vector(0,1), Vector(0,0), Vector(1,0)
|
||||
else:
|
||||
f.uv= Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1)
|
||||
|
||||
if not PREF_IMG_PACK.val:
|
||||
f.mode |= Mesh.FaceModes.TEX
|
||||
f.image = img
|
||||
|
||||
if PREF_ALPHA.val:
|
||||
f.transp |= Mesh.FaceTranspModes.ALPHA
|
||||
else:
|
||||
w= ((plane[0]-plane[1]).length + (plane[2]-plane[3]).length)/2
|
||||
h= ((plane[1]-plane[2]).length + (plane[3]-plane[0]).length)/2
|
||||
|
||||
face_data.append( (f, img) )
|
||||
boxes2Pack.append( [0.0,0.0,h, w, i] )
|
||||
|
||||
if PREF_IMG_PACK.val:
|
||||
# pack the quads into a square
|
||||
packWidth, packHeight = Blender.Geometry.BoxPack2D(boxes2Pack)
|
||||
|
||||
render_obs= []
|
||||
|
||||
render_mat= alpha_mat(img)
|
||||
|
||||
# Add geometry to the mesh
|
||||
for box in boxes2Pack:
|
||||
i= box[4]
|
||||
|
||||
orig_f, img= face_data[i]
|
||||
|
||||
# New Mesh and Object
|
||||
|
||||
render_me= bpy.data.meshes.new()
|
||||
|
||||
render_ob= Blender.Object.New('Mesh')
|
||||
render_me.materials= [render_mat]
|
||||
render_ob.link(render_me)
|
||||
|
||||
render_obs.append(render_ob)
|
||||
|
||||
# Add verts clockwise from the bottom left.
|
||||
_x= box[0] / packWidth
|
||||
_y= box[1] / packHeight
|
||||
_w= box[2] / packWidth
|
||||
_h= box[3] / packHeight
|
||||
|
||||
|
||||
render_me.verts.extend([\
|
||||
Vector(_x, _y, 0),\
|
||||
Vector(_x, _y +_h, 0),\
|
||||
Vector(_x + _w, _y +_h, 0),\
|
||||
Vector(_x + _w, _y, 0),\
|
||||
])
|
||||
|
||||
render_me.faces.extend(list(render_me.verts))
|
||||
render_me.faceUV= True
|
||||
|
||||
render_me.faces[0].uv = [Vector(0,0), Vector(0,1), Vector(1,1), Vector(1,0)]
|
||||
render_me.faces[0].image = img
|
||||
|
||||
# Set the UV's, we need to flip them HOZ?
|
||||
for uv in orig_f.uv:
|
||||
uv.x = _x + (uv.x * _w)
|
||||
uv.y = _y + (uv.y * _h)
|
||||
|
||||
target_image= BPyRender.imageFromObjectsOrtho(render_obs, PREF_IMAGE_PATH, PREF_RES.val, PREF_RES.val, PREF_AA.val, PREF_ALPHA.val, None)
|
||||
target_image.reload() # incase your overwriting an existing image.
|
||||
|
||||
# Set to the 1 image.
|
||||
for f in me_data.faces:
|
||||
f.image= target_image
|
||||
if PREF_ALPHA.val:
|
||||
f.transp |= Mesh.FaceTranspModes.ALPHA
|
||||
|
||||
# Free the images data and remove
|
||||
for data in face_data:
|
||||
img= data[1]
|
||||
os.remove(img.filename)
|
||||
img.reload()
|
||||
|
||||
# Finish pack
|
||||
|
||||
me_data.update()
|
||||
me_ob.makeDisplayList()
|
||||
Blender.Window.WaitCursor(0)
|
||||
print '%.2f secs taken' % (Blender.sys.time()-time)
|
||||
|
||||
|
||||
def main():
|
||||
scn= bpy.data.scenes.active
|
||||
ob_sel= list(scn.objects.context)
|
||||
|
||||
PREF_KEEP_ASPECT= False
|
||||
|
||||
# Error Checking
|
||||
if len(ob_sel) < 2:
|
||||
Draw.PupMenu("Error%t|Select 2 mesh objects")
|
||||
return
|
||||
|
||||
me_ob= scn.objects.active
|
||||
|
||||
if not me_ob:
|
||||
Draw.PupMenu("Error%t|No active mesh selected.")
|
||||
|
||||
try:
|
||||
ob_sel.remove(me_ob)
|
||||
except:
|
||||
pass
|
||||
|
||||
if me_ob.type != 'Mesh':
|
||||
Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too")
|
||||
return
|
||||
|
||||
me_data= me_ob.getData(mesh=1)
|
||||
|
||||
for f in me_data.faces:
|
||||
if len(f) != 4:
|
||||
Draw.PupMenu("Error%t|Active mesh must have only quads")
|
||||
return
|
||||
|
||||
|
||||
# Get user input
|
||||
block = [\
|
||||
'Image Pixel Size',\
|
||||
("Packed Size: ", PREF_RES, 128, 2048, "Pixel width and height to render the billboard to"),\
|
||||
("Tile Size: ", PREF_TILE_RES, 64, 1024, "Pixel width and height for each tile to render to"),\
|
||||
'Render Settings',\
|
||||
("Pack Final", PREF_IMG_PACK , "Pack the image for each face into images into a single image"),\
|
||||
("Oversampling", PREF_AA , "Higher quality woth extra sampling"),\
|
||||
("Alpha Clipping", PREF_ALPHA , "Render empty areas as transparent"),\
|
||||
("Cam ZOffset: ", PREF_Z_OFFSET, 0.1, 100, "Distance to place the camera away from the quad when rendering")\
|
||||
]
|
||||
|
||||
if not Draw.PupBlock("Billboard Render", block):
|
||||
return
|
||||
|
||||
# Set globals
|
||||
GLOBALS['ob_sel'] = ob_sel
|
||||
GLOBALS['me_ob'] = me_ob
|
||||
GLOBALS['me_data'] = me_data
|
||||
|
||||
Blender.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', Blender.sys.makename(ext='.png'))
|
||||
# save_billboard('/tmp/test.png')
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
@@ -1,158 +0,0 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Edit Externally'
|
||||
Blender: 242a
|
||||
Group: 'Image'
|
||||
Tooltip: 'Open in an application for editing. (hold Shift to configure)'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ["blender", "blenderartists.org"]
|
||||
__version__ = "1.0"
|
||||
__bpydoc__ = """\
|
||||
This script opens the current image in an external application for editing.
|
||||
|
||||
Usage:
|
||||
Choose an image for editing in the UV/Image view.
|
||||
|
||||
To configure the application to open the image with, hold Shift as you
|
||||
click on this menu item.
|
||||
|
||||
For first time users try running the default application for your
|
||||
operating system. If the application does not open you can type in
|
||||
the full path. You can choose that the last entered application will
|
||||
be saved as a default.
|
||||
|
||||
* Note, default commants for opening an image are "start" for win32
|
||||
and "open" for macos. This will use the system default associated
|
||||
application.
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) Campbell J Barton 2006
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender import Image, sys, Draw, Registry
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
import sys as py_sys
|
||||
platform = py_sys.platform
|
||||
except:
|
||||
Draw.PupMenu('Error: Recent version of Python not installed.')
|
||||
subprocess=None
|
||||
|
||||
def os_run(appstring, filename):
|
||||
'''
|
||||
Run the app, take into account different python versions etc
|
||||
looks like python 2.6 wants a list for
|
||||
'''
|
||||
|
||||
# evil trick, temp replace spaces so we can allow spaces in filenames
|
||||
# also allows multiple instances of %f
|
||||
appstring = appstring.replace(' ', '\t')
|
||||
appstring = appstring.replace('%f', filename)
|
||||
appstring = appstring.split('\t')
|
||||
|
||||
print ' '.join(appstring)
|
||||
|
||||
try: # only python 2.6 wants a list?
|
||||
p = subprocess.Popen(appstring)
|
||||
except:
|
||||
p = subprocess.Popen(' '.join(appstring))
|
||||
|
||||
|
||||
def edit_extern(image=None):
|
||||
|
||||
if not image:
|
||||
image = Image.GetCurrent()
|
||||
|
||||
if not image: # Image is None
|
||||
Draw.PupMenu('ERROR: Please select active Image.')
|
||||
return
|
||||
if image.packed:
|
||||
Draw.PupMenu('ERROR: Image is packed, unpack before editing.')
|
||||
return
|
||||
|
||||
imageFileName = sys.expandpath( image.filename )
|
||||
|
||||
if not sys.exists(imageFileName):
|
||||
Draw.PupMenu('ERROR: Image path does not exist.')
|
||||
return
|
||||
|
||||
pupblock = [imageFileName.split('/')[-1].split('\\')[-1]]
|
||||
|
||||
new_text= False
|
||||
try:
|
||||
appstring = Registry.GetKey('ExternalImageEditor', True)
|
||||
appstring = appstring['path']
|
||||
|
||||
# for ZanQdo if he removed the path from the textbox totaly. ;) - Cam
|
||||
if not appstring or appstring.find('%f')==-1:
|
||||
new_text= True
|
||||
except:
|
||||
new_text= True
|
||||
|
||||
if new_text:
|
||||
pupblock.append('first time, set path.')
|
||||
if platform == 'win32':
|
||||
# Example of path to popular image editor... ;-)
|
||||
# appstring = '"C:\\Program Files\\Adobe\\Photoshop CS\\photoshop.exe" "%f"'
|
||||
# Have to add "cmd /c" to make sure we're using Windows shell.
|
||||
appstring = 'cmd /c start "" /B "%f"'
|
||||
elif platform == 'darwin':
|
||||
appstring = 'open "%f"'
|
||||
else:
|
||||
appstring = 'gimp %f'
|
||||
|
||||
appstring_but = Draw.Create(appstring)
|
||||
save_default_but = Draw.Create(0)
|
||||
|
||||
pupblock.append(('editor: ', appstring_but, 0, 99, 'Path to application, %f will be replaced with the image path.'))
|
||||
pupblock.append(('Set Default', save_default_but, 'Store this path in the blender registry.'))
|
||||
|
||||
# Only configure if Shift is held,
|
||||
if Blender.Window.GetKeyQualifiers() & Blender.Window.Qual.SHIFT:
|
||||
if not Draw.PupBlock('External Image Editor...', pupblock):
|
||||
return
|
||||
|
||||
appstring = appstring_but.val
|
||||
save_default= save_default_but.val
|
||||
|
||||
if save_default:
|
||||
Registry.SetKey('ExternalImageEditor', {'path':appstring}, True)
|
||||
|
||||
if appstring.find('%f') == -1:
|
||||
Draw.PupMenu('ERROR: No filename specified! ("%f")')
|
||||
return
|
||||
|
||||
# -------------------------------
|
||||
|
||||
os_run(appstring, imageFileName)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
edit_extern()
|
||||
|
||||
|
||||
if __name__ == '__main__' and subprocess:
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,961 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Video Sequence (.edl)...'
|
||||
Blender: 248
|
||||
Group: 'Import'
|
||||
Tooltip: 'Load a CMX formatted EDL into the sequencer'
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2009: Campbell Barton, ideasman42@gmail.com
|
||||
#
|
||||
# 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,
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
class TimeCode(object):
|
||||
'''
|
||||
Simple timecode class
|
||||
also supports conversion from other time strings used by EDL
|
||||
'''
|
||||
def __init__(self, data, fps):
|
||||
self.fps= fps
|
||||
if type(data)==str:
|
||||
self.fromString(data)
|
||||
frame = self.asFrame()
|
||||
self.fromFrame(frame)
|
||||
else:
|
||||
self.fromFrame(data)
|
||||
|
||||
def fromString(self, text):
|
||||
# hh:mm:ss:ff
|
||||
# No dropframe support yet
|
||||
|
||||
if text.lower().endswith('mps'): # 5.2mps
|
||||
return self.fromFrame( int( float(text[:-3]) * self.fps ) )
|
||||
elif text.lower().endswith('s'): # 5.2s
|
||||
return self.fromFrame( int( float(text[:-1]) * self.fps ) )
|
||||
elif text.isdigit(): # 1234
|
||||
return self.fromFrame( int(text) )
|
||||
elif ':' in text: # hh:mm:ss:ff
|
||||
text= text.replace(';', ':').replace(',', ':').replace('.', ':')
|
||||
text= text.split(':')
|
||||
|
||||
self.hours= int(text[0])
|
||||
self.minutes= int(text[1])
|
||||
self.seconds= int(text[2])
|
||||
self.frame= int(text[3])
|
||||
return self
|
||||
else:
|
||||
print 'ERROR: could not convert this into timecode "%s"' % test
|
||||
return self
|
||||
|
||||
|
||||
def fromFrame(self, frame):
|
||||
|
||||
if frame < 0:
|
||||
frame = -frame;
|
||||
neg=True
|
||||
else:
|
||||
neg=False
|
||||
|
||||
fpm = 60 * self.fps
|
||||
fph = 60 * fpm
|
||||
|
||||
if frame < fph:
|
||||
self.hours= 0
|
||||
else:
|
||||
self.hours= int(frame/fph)
|
||||
frame = frame % fph
|
||||
|
||||
if frame < fpm:
|
||||
self.minutes= 0
|
||||
else:
|
||||
self.minutes= int(frame/fpm)
|
||||
frame = frame % fpm
|
||||
|
||||
if frame < self.fps:
|
||||
self.seconds= 0
|
||||
else:
|
||||
self.seconds= int(frame/self.fps)
|
||||
frame = frame % self.fps
|
||||
|
||||
self.frame= frame
|
||||
|
||||
if neg:
|
||||
self.frame = -self.frame
|
||||
self.seconds = -self.seconds
|
||||
self.minutes = -self.minutes
|
||||
self.hours = -self.hours
|
||||
|
||||
return self
|
||||
|
||||
def asFrame(self):
|
||||
abs_frame= self.frame
|
||||
abs_frame += self.seconds * self.fps
|
||||
abs_frame += self.minutes * 60 * self.fps
|
||||
abs_frame += self.hours * 60 * 60 * self.fps
|
||||
|
||||
return abs_frame
|
||||
|
||||
def asString(self):
|
||||
self.fromFrame(int(self))
|
||||
return '%.2d:%.2d:%.2d:%.2d' % (self.hours, self.minutes, self.seconds, self.frame)
|
||||
|
||||
def __repr__(self):
|
||||
return self.asString()
|
||||
|
||||
# Numeric stuff, may as well have this
|
||||
def __neg__(self): return TimeCode(-int(self), self.fps)
|
||||
def __int__(self): return self.asFrame()
|
||||
def __sub__(self, other): return TimeCode(int(self)-int(other), self.fps)
|
||||
def __add__(self, other): return TimeCode(int(self)+int(other), self.fps)
|
||||
def __mul__(self, other): return TimeCode(int(self)*int(other), self.fps)
|
||||
def __div__(self, other): return TimeCode(int(self)/int(other), self.fps)
|
||||
def __abs__(self): return TimeCode(abs(int(self)), self.fps)
|
||||
def __iadd__(self, other): return self.fromFrame(int(self)+int(other))
|
||||
def __imul__(self, other): return self.fromFrame(int(self)*int(other))
|
||||
def __idiv__(self, other): return self.fromFrame(int(self)/int(other))
|
||||
# end timecode
|
||||
|
||||
|
||||
'''Comments
|
||||
Comments can appear at the beginning of the EDL file (header) or between the edit lines in the EDL. The first block of comments in the file is defined to be the header comments and they are associated with the EDL as a whole. Subsequent comments in the EDL file are associated with the first edit line that appears after them.
|
||||
Edit Entries
|
||||
<filename|tag> <EditMode> <TransitionType>[num] [duration] [srcIn] [srcOut] [recIn] [recOut]
|
||||
|
||||
* <filename|tag>: Filename or tag value. Filename can be for an MPEG file, Image file, or Image file template. Image file templates use the same pattern matching as for command line glob, and can be used to specify images to encode into MPEG. i.e. /usr/data/images/image*.jpg
|
||||
* <EditMode>: 'V' | 'A' | 'VA' | 'B' | 'v' | 'a' | 'va' | 'b' which equals Video, Audio, Video_Audio edits (note B or b can be used in place of VA or va).
|
||||
* <TransitonType>: 'C' | 'D' | 'E' | 'FI' | 'FO' | 'W' | 'c' | 'd' | 'e' | 'fi' | 'fo' | 'w'. which equals Cut, Dissolve, Effect, FadeIn, FadeOut, Wipe.
|
||||
* [num]: if TransitionType = Wipe, then a wipe number must be given. At the moment only wipe 'W0' and 'W1' are supported.
|
||||
* [duration]: if the TransitionType is not equal to Cut, then an effect duration must be given. Duration is in frames.
|
||||
* [srcIn]: Src in. If no srcIn is given, then it defaults to the first frame of the video or the first frame in the image pattern. If srcIn isn't specified, then srcOut, recIn, recOut can't be specified.
|
||||
* [srcOut]: Src out. If no srcOut is given, then it defaults to the last frame of the video - or last image in the image pattern. if srcOut isn't given, then recIn and recOut can't be specified.
|
||||
* [recIn]: Rec in. If no recIn is given, then it is calculated based on its position in the EDL and the length of its input.
|
||||
[recOut]: Rec out. If no recOut is given, then it is calculated based on its position in the EDL and the length of its input. first frame of the video.
|
||||
|
||||
For srcIn, srcOut, recIn, recOut, the values can be specified as either timecode, frame number, seconds, or mps seconds. i.e.
|
||||
[tcode | fnum | sec | mps], where:
|
||||
|
||||
* tcode : SMPTE timecode in hh:mm:ss:ff
|
||||
* fnum : frame number (the first decodable frame in the video is taken to be frame 0).
|
||||
* sec : seconds with 's' suffix (e.g. 5.2s)
|
||||
* mps : seconds with 'mps' suffix (e.g. 5.2mps). This corresponds to the 'seconds' value displayed by Windows MediaPlayer.
|
||||
|
||||
More notes,
|
||||
Key
|
||||
|
||||
'''
|
||||
|
||||
enum= 0
|
||||
TRANSITION_UNKNOWN= enum
|
||||
TRANSITION_CUT= enum; enum+=1
|
||||
TRANSITION_DISSOLVE= enum; enum+=1
|
||||
TRANSITION_EFFECT= enum; enum+=1
|
||||
TRANSITION_FADEIN= enum; enum+=1
|
||||
TRANSITION_FADEOUT= enum; enum+=1
|
||||
TRANSITION_WIPE= enum; enum+=1
|
||||
TRANSITION_KEY= enum; enum+=1
|
||||
|
||||
TRANSITION_DICT={ \
|
||||
'c':TRANSITION_CUT,
|
||||
'd':TRANSITION_DISSOLVE,
|
||||
'e':TRANSITION_EFFECT,
|
||||
'fi':TRANSITION_FADEIN,
|
||||
'fo':TRANSITION_FADEOUT,
|
||||
'w':TRANSITION_WIPE,
|
||||
'k':TRANSITION_KEY,
|
||||
}
|
||||
|
||||
enum= 0
|
||||
EDIT_UNKNOWN= 1<<enum; enum+=1
|
||||
EDIT_VIDEO= 1<<enum; enum+=1
|
||||
EDIT_AUDIO= 1<<enum; enum+=1
|
||||
EDIT_AUDIO_STEREO= 1<<enum; enum+=1
|
||||
EDIT_VIDEO_AUDIO= 1<<enum; enum+=1
|
||||
|
||||
EDIT_DICT= { \
|
||||
'v':EDIT_VIDEO,
|
||||
'a':EDIT_AUDIO,
|
||||
'aa':EDIT_AUDIO_STEREO,
|
||||
'va':EDIT_VIDEO_AUDIO,
|
||||
'b':EDIT_VIDEO_AUDIO
|
||||
}
|
||||
|
||||
|
||||
enum= 0
|
||||
WIPE_UNKNOWN= enum
|
||||
WIPE_0= enum; enum+=1
|
||||
WIPE_1= enum; enum+=1
|
||||
|
||||
enum= 0
|
||||
KEY_UNKNOWN= enum
|
||||
KEY_BG= enum; enum+=1 # K B
|
||||
KEY_IN= enum; enum+=1 # This is assumed if no second type is set
|
||||
KEY_OUT= enum; enum+=1 # K O
|
||||
|
||||
|
||||
'''
|
||||
Most sytems:
|
||||
Non-dropframe: 1:00:00:00 - colon in last position
|
||||
Dropframe: 1:00:00;00 - semicolon in last position
|
||||
PAL/SECAM: 1:00:00:00 - colon in last position
|
||||
|
||||
SONY:
|
||||
Non-dropframe: 1:00:00.00 - period in last position
|
||||
Dropframe: 1:00:00,00 - comma in last position
|
||||
PAL/SECAM: 1:00:00.00 - period in last position
|
||||
'''
|
||||
|
||||
'''
|
||||
t = abs(timecode('-124:-12:-43:-22', 25))
|
||||
t /= 2
|
||||
print t
|
||||
'''
|
||||
|
||||
def editFlagsToText(flag):
|
||||
items = []
|
||||
for item, val in EDIT_DICT.items():
|
||||
if val & flag:
|
||||
items.append(item)
|
||||
return '/'.join(items)
|
||||
|
||||
|
||||
class EditDecision(object):
|
||||
def __init__(self, text= None, fps= 25):
|
||||
# print text
|
||||
self.number = -1
|
||||
self.reel = '' # Uniqie name for this 'file' but not filename, when BL signifies black
|
||||
self.transition_duration= 0
|
||||
self.edit_type= EDIT_UNKNOWN
|
||||
self.transition_type= TRANSITION_UNKNOWN
|
||||
self.wipe_type = WIPE_UNKNOWN
|
||||
self.key_type = KEY_UNKNOWN
|
||||
self.key_fade = -1 # true/false
|
||||
self.srcIn = None # Where on the original field recording the event begins
|
||||
self.srcOut = None # Where on the original field recording the event ends
|
||||
self.recIn = None # Beginning of the original event in the edited program
|
||||
self.recOut = None # End of the original event in the edited program
|
||||
self.m2 = None # fps set by the m2 command
|
||||
self.filename = ''
|
||||
|
||||
self.custom_data= [] # use for storing any data you want (blender strip for eg)
|
||||
|
||||
if text != None:
|
||||
self.read(text, fps)
|
||||
|
||||
def __repr__(self):
|
||||
txt= 'num: %d, ' % self.number
|
||||
txt += 'reel: %s, ' % self.reel
|
||||
txt += 'edit_type: '
|
||||
txt += editFlagsToText(self.edit_type) + ', '
|
||||
|
||||
txt += 'trans_type: '
|
||||
for item, val in TRANSITION_DICT.items():
|
||||
if val == self.transition_type:
|
||||
txt += item + ', '
|
||||
break
|
||||
|
||||
|
||||
txt += 'm2: '
|
||||
if self.m2:
|
||||
txt += '%g' % float(self.m2.fps)
|
||||
txt += '\n\t'
|
||||
txt += self.m2.data
|
||||
else:
|
||||
txt += 'nil'
|
||||
|
||||
txt += ', '
|
||||
txt += 'recIn: ' + str(self.recIn) + ', '
|
||||
txt += 'recOut: ' + str(self.recOut) + ', '
|
||||
txt += 'srcIn: ' + str(self.srcIn) + ', '
|
||||
txt += 'srcOut: ' + str(self.srcOut) + ', '
|
||||
|
||||
return txt
|
||||
|
||||
|
||||
def read(self, line, fps):
|
||||
line= line.split()
|
||||
index= 0
|
||||
self.number= int(line[index]); index+=1
|
||||
self.reel= line[index].lower(); index+=1
|
||||
|
||||
# AA/V can be an edit type
|
||||
self.edit_type= 0
|
||||
for edit_type in line[index].lower().split('/'):
|
||||
self.edit_type |= EDIT_DICT[edit_type];
|
||||
index+=1
|
||||
|
||||
tx_name = ''.join([c for c in line[index].lower() if not c.isdigit()])
|
||||
self.transition_type= TRANSITION_DICT[tx_name]; # advance the index later
|
||||
|
||||
if self.transition_type== TRANSITION_WIPE:
|
||||
tx_num = ''.join([c for c in line[index].lower() if c.isdigit()])
|
||||
if tx_num: tx_num = int(tx_num)
|
||||
else: tx_num = 0
|
||||
|
||||
self.wipe_type= tx_num
|
||||
|
||||
elif self.transition_type== TRANSITION_KEY: # UNTESTED
|
||||
|
||||
val= line[index+1].lower()
|
||||
|
||||
if val == 'b':
|
||||
self.key_type= KEY_BG
|
||||
index+=1
|
||||
elif val == 'o':
|
||||
self.key_type= KEY_OUT
|
||||
index+=1
|
||||
else:
|
||||
self.key_type= KEY_IN # if no args given
|
||||
|
||||
# there may be an (F) after, eg 'K B (F)'
|
||||
# in the docs this should only be after K B but who knows, it may be after K O also?
|
||||
val= line[index+1].lower()
|
||||
if val == '(f)':
|
||||
index+=1
|
||||
self.key_fade = True
|
||||
else:
|
||||
self.key_fade = False
|
||||
|
||||
index+=1
|
||||
|
||||
if self.transition_type in (TRANSITION_DISSOLVE, TRANSITION_EFFECT, TRANSITION_FADEIN, TRANSITION_FADEOUT, TRANSITION_WIPE):
|
||||
self.transition_duration= TimeCode(line[index], fps); index+=1
|
||||
|
||||
if index < len(line):
|
||||
self.srcIn= TimeCode(line[index], fps); index+=1
|
||||
if index < len(line):
|
||||
self.srcOut= TimeCode(line[index], fps); index+=1
|
||||
|
||||
if index < len(line):
|
||||
self.recIn= TimeCode(line[index], fps); index+=1
|
||||
if index < len(line):
|
||||
self.recOut= TimeCode(line[index], fps); index+=1
|
||||
|
||||
def renumber(self):
|
||||
self.edits.sort( key=lambda e: int(e.recIn) )
|
||||
for i, edit in enumerate(self.edits):
|
||||
edit.number= i
|
||||
|
||||
def clean(self):
|
||||
'''
|
||||
Clean up double ups
|
||||
'''
|
||||
self.renumber()
|
||||
|
||||
# TODO
|
||||
def asName(self):
|
||||
cut_type = 'nil'
|
||||
for k,v in TRANSITION_DICT.iteritems():
|
||||
if v==self.transition_type:
|
||||
cut_type = k
|
||||
break
|
||||
|
||||
return '%d_%s_%s' % (self.number, self.reel, cut_type)
|
||||
|
||||
class M2(object):
|
||||
def __init__(self):
|
||||
self.reel = None
|
||||
self.fps = None
|
||||
self.time = None
|
||||
self.data = None
|
||||
|
||||
self.index = -1
|
||||
self.tot = -1
|
||||
|
||||
def read(self, line, fps):
|
||||
|
||||
# M2 TAPEC 050.5 00:08:11:08
|
||||
words = line.split()
|
||||
|
||||
self.reel= words[1].lower()
|
||||
self.fps= float(words[2])
|
||||
self.time= TimeCode(words[3], fps)
|
||||
|
||||
self.data = line
|
||||
|
||||
class EditList(object):
|
||||
def __init__(self):
|
||||
self.edits= []
|
||||
self.title= ''
|
||||
|
||||
def parse(self, filename, fps):
|
||||
try:
|
||||
file= open(filename, 'rU')
|
||||
except:
|
||||
return False
|
||||
|
||||
self.edits= []
|
||||
edits_m2 = [] # edits with m2's
|
||||
|
||||
has_m2 = False
|
||||
|
||||
for line in file:
|
||||
line= ' '.join(line.split())
|
||||
|
||||
if not line or line.startswith('*') or line.startswith('#'):
|
||||
continue
|
||||
elif line.startswith('TITLE:'):
|
||||
self.title= ' '.join(line.split()[1:])
|
||||
elif line.split()[0].lower() == 'm2':
|
||||
has_m2 = True
|
||||
m2 = M2()
|
||||
m2.read(line, fps)
|
||||
edits_m2.append( m2 )
|
||||
elif not line.split()[0].isdigit():
|
||||
print 'Ignoring:', line
|
||||
else:
|
||||
self.edits.append( EditDecision(line, fps) )
|
||||
edits_m2.append( self.edits[-1] )
|
||||
|
||||
if has_m2:
|
||||
# Group indexes
|
||||
i = 0
|
||||
for item in edits_m2:
|
||||
if isinstance(item, M2):
|
||||
item.index = i
|
||||
i += 1
|
||||
else:
|
||||
# not an m2
|
||||
i = 0
|
||||
|
||||
# Set total group indexes
|
||||
for item in reversed(edits_m2):
|
||||
if isinstance(item, M2):
|
||||
if tot_m2 == -1:
|
||||
tot_m2 = item.index + 1
|
||||
|
||||
item.tot = tot_m2
|
||||
else:
|
||||
# not an m2
|
||||
tot_m2 = -1
|
||||
|
||||
|
||||
for i, item in enumerate(edits_m2):
|
||||
if isinstance(item, M2):
|
||||
# make a list of all items that match the m2's reel name
|
||||
edits_m2_tmp = [item_tmp for item_tmp in edits_m2 if (isinstance(item, M2) or item_tmp.reel == item.reel)]
|
||||
|
||||
# get the new index
|
||||
i_tmp = edits_m2_tmp.index(item)
|
||||
|
||||
# Seek back to get the edit.
|
||||
edit = edits_m2[i_tmp-item.tot]
|
||||
|
||||
# Note, docs say time should also match with edit start time
|
||||
# but from final cut pro, this seems not to be the case
|
||||
if not isinstance(edit, EditDecision):
|
||||
print "ERROR!", 'M2 incorrect'
|
||||
else:
|
||||
edit.m2 = item
|
||||
|
||||
|
||||
return True
|
||||
|
||||
def testOverlap(self, edit_test):
|
||||
recIn= int(edit_test.recIn)
|
||||
recOut= int(edit_test.recOut)
|
||||
|
||||
for edit in self.edits:
|
||||
if edit is edit_test:
|
||||
break
|
||||
|
||||
recIn_other= int(edit.recIn)
|
||||
recOut_other= int(edit.recOut)
|
||||
|
||||
if recIn_other < recIn < recOut_other:
|
||||
return True
|
||||
if recIn_other < recOut < recOut_other:
|
||||
return True
|
||||
|
||||
if recIn < recIn_other < recOut:
|
||||
return True
|
||||
if recIn < recOut_other < recOut:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def getReels(self):
|
||||
reels = {}
|
||||
for edit in self.edits:
|
||||
reels.setdefault(edit.reel, []).append(edit)
|
||||
|
||||
return reels
|
||||
|
||||
|
||||
|
||||
# from DNA
|
||||
SEQ_IMAGE= 0
|
||||
SEQ_META= 1
|
||||
SEQ_SCENE= 2
|
||||
SEQ_MOVIE= 3
|
||||
SEQ_RAM_SOUND= 4
|
||||
SEQ_HD_SOUND= 5
|
||||
SEQ_MOVIE_AND_HD_SOUND= 6
|
||||
|
||||
SEQ_EFFECT= 8
|
||||
SEQ_CROSS= 8
|
||||
SEQ_ADD= 9
|
||||
SEQ_SUB= 10
|
||||
SEQ_ALPHAOVER= 11
|
||||
SEQ_ALPHAUNDER= 12
|
||||
SEQ_GAMCROSS= 13
|
||||
SEQ_MUL= 14
|
||||
SEQ_OVERDROP= 15
|
||||
SEQ_PLUGIN= 24
|
||||
SEQ_WIPE= 25
|
||||
SEQ_GLOW= 26
|
||||
SEQ_TRANSFORM= 27
|
||||
SEQ_COLOR= 28
|
||||
SEQ_SPEED= 29
|
||||
|
||||
# Blender spesific stuff starts here
|
||||
import bpy
|
||||
import Blender
|
||||
|
||||
def scale_meta_speed(seq, mov, scale):
|
||||
# Add an effect
|
||||
speed= seq.new((SEQ_SPEED, mov,), 199, mov.channel+1)
|
||||
speed.speedEffectFrameBlending = True
|
||||
meta= seq.new([mov, speed], 199, mov.channel)
|
||||
|
||||
if scale >= 1.0:
|
||||
mov.endStill = int(mov.length * (scale - 1.0))
|
||||
else:
|
||||
speed.speedEffectGlobalSpeed = 1.0/scale
|
||||
meta.endOffset = mov.length - int(mov.length*scale)
|
||||
|
||||
speed.update()
|
||||
meta.update()
|
||||
return meta
|
||||
|
||||
def apply_dissolve_ipo(mov, blendin):
|
||||
len_disp = float(mov.endDisp - mov.startDisp)
|
||||
|
||||
if len_disp <= 0.0:
|
||||
print 'Error, strip is zero length'
|
||||
return
|
||||
|
||||
mov.ipo= ipo= bpy.data.ipos.new("fade", "Sequence")
|
||||
icu= ipo.addCurve('Fac')
|
||||
|
||||
icu.interpolation= Blender.IpoCurve.InterpTypes.LINEAR
|
||||
icu.append((0, 0))
|
||||
icu.append(((int(blendin)/len_disp) * 100, 1))
|
||||
|
||||
if mov.type not in (SEQ_HD_SOUND, SEQ_RAM_SOUND):
|
||||
mov.blendMode = Blender.Scene.Sequence.BlendModes.ALPHAOVER
|
||||
|
||||
|
||||
def replace_ext(path, ext):
|
||||
return path[:path.rfind('.')+1] + ext
|
||||
|
||||
def load_edl(filename, reel_files, reel_offsets):
|
||||
'''
|
||||
reel_files - key:reel <--> reel:filename
|
||||
'''
|
||||
|
||||
# For test file
|
||||
# frame_offset = -769
|
||||
|
||||
|
||||
sce= bpy.data.scenes.active
|
||||
fps= sce.render.fps
|
||||
|
||||
elist= EditList()
|
||||
if not elist.parse(filename, fps):
|
||||
return 'Unable to parse "%s"' % filename
|
||||
# elist.clean()
|
||||
|
||||
|
||||
seq= sce.sequence
|
||||
|
||||
track= 0
|
||||
|
||||
edits = elist.edits[:]
|
||||
# edits.sort(key = lambda edit: int(edit.recIn))
|
||||
|
||||
prev_edit = None
|
||||
for edit in edits:
|
||||
print edit
|
||||
frame_offset = reel_offsets[edit.reel]
|
||||
|
||||
|
||||
src_start= int(edit.srcIn) + frame_offset
|
||||
src_end= int(edit.srcOut) + frame_offset
|
||||
src_length= src_end-src_start
|
||||
|
||||
rec_start= int(edit.recIn) + 1
|
||||
rec_end= int(edit.recOut) + 1
|
||||
rec_length= rec_end-rec_start
|
||||
|
||||
# print src_length, rec_length, src_start
|
||||
|
||||
if edit.m2 != None: scale = fps/float(edit.m2.fps)
|
||||
else: scale = 1.0
|
||||
|
||||
unedited_start= rec_start - src_start
|
||||
offset_start = src_start - int(src_start*scale) # works for scaling up AND down
|
||||
|
||||
if edit.transition_type == TRANSITION_CUT and (not elist.testOverlap(edit)):
|
||||
track = 1
|
||||
|
||||
strip= None
|
||||
final_strips = []
|
||||
if edit.reel.lower()=='bw':
|
||||
strip= seq.new((0,0,0), rec_start, track+1)
|
||||
strip.length= rec_length # for color its simple
|
||||
final_strips.append(strip)
|
||||
else:
|
||||
|
||||
path_full = reel_files[edit.reel]
|
||||
path_fileonly= path_full.split('/')[-1].split('\\')[-1] # os.path.basename(full)
|
||||
path_dironly= path_full[:-len(path_fileonly)] # os.path.dirname(full)
|
||||
|
||||
if edit.edit_type & EDIT_VIDEO: #and edit.transition_type == TRANSITION_CUT:
|
||||
|
||||
try:
|
||||
strip= seq.new((path_fileonly, path_dironly, path_full, 'movie'), unedited_start + offset_start, track+1)
|
||||
except:
|
||||
return 'Invalid input for movie'
|
||||
|
||||
# Apply scaled rec in bounds
|
||||
if scale != 1.0:
|
||||
meta = scale_meta_speed(seq, strip, scale)
|
||||
final_strip = meta
|
||||
else:
|
||||
final_strip = strip
|
||||
|
||||
|
||||
final_strip.update()
|
||||
final_strip.startOffset= rec_start - final_strip.startDisp
|
||||
final_strip.endOffset= rec_end- final_strip.endDisp
|
||||
final_strip.update()
|
||||
final_strip.endOffset += (final_strip.endDisp - rec_end)
|
||||
final_strip.update()
|
||||
|
||||
|
||||
if edit.transition_duration:
|
||||
if not prev_edit:
|
||||
print "Error no previous strip"
|
||||
else:
|
||||
new_end = rec_start + int(edit.transition_duration)
|
||||
for other in prev_edit.custom_data:
|
||||
if other.type != SEQ_HD_SOUND and other.type != SEQ_RAM_SOUND:
|
||||
other.endOffset += (other.endDisp - new_end)
|
||||
other.update()
|
||||
|
||||
# Apply disolve
|
||||
if edit.transition_type == TRANSITION_DISSOLVE:
|
||||
apply_dissolve_ipo(final_strip, edit.transition_duration)
|
||||
|
||||
if edit.transition_type == TRANSITION_WIPE:
|
||||
other_track = track + 2
|
||||
for other in prev_edit.custom_data:
|
||||
if other.type != SEQ_HD_SOUND and other.type != SEQ_RAM_SOUND:
|
||||
|
||||
strip_wipe= seq.new((SEQ_WIPE, other, final_strip), 1, other_track)
|
||||
|
||||
if edit.wipe_type == WIPE_0:
|
||||
strip_wipe.wipeEffectAngle = 90
|
||||
else:
|
||||
strip_wipe.wipeEffectAngle = -90
|
||||
|
||||
other_track += 1
|
||||
|
||||
|
||||
|
||||
# strip.endOffset= strip.length - int(edit.srcOut)
|
||||
#end_offset= (unedited_start+strip.length) - end
|
||||
# print start, end, end_offset
|
||||
#strip.endOffset = end_offset
|
||||
|
||||
# break
|
||||
# print strip
|
||||
|
||||
final_strips.append(final_strip)
|
||||
|
||||
|
||||
if edit.edit_type & (EDIT_AUDIO | EDIT_AUDIO_STEREO | EDIT_VIDEO_AUDIO):
|
||||
|
||||
if scale == 1.0: # TODO - scaled audio
|
||||
|
||||
try:
|
||||
strip= seq.new((path_fileonly, path_dironly, path_full, 'audio_hd'), unedited_start + offset_start, track+6)
|
||||
except:
|
||||
|
||||
# See if there is a wave file there
|
||||
path_full_wav = replace_ext(path_full, 'wav')
|
||||
path_fileonly_wav = replace_ext(path_fileonly, 'wav')
|
||||
|
||||
#try:
|
||||
strip= seq.new((path_fileonly_wav, path_dironly, path_full_wav, 'audio_hd'), unedited_start + offset_start, track+6)
|
||||
#except:
|
||||
# return 'Invalid input for audio'
|
||||
|
||||
final_strip = strip
|
||||
|
||||
# Copied from above
|
||||
final_strip.update()
|
||||
final_strip.startOffset= rec_start - final_strip.startDisp
|
||||
final_strip.endOffset= rec_end- final_strip.endDisp
|
||||
final_strip.update()
|
||||
final_strip.endOffset += (final_strip.endDisp - rec_end)
|
||||
final_strip.update()
|
||||
|
||||
if edit.transition_type == TRANSITION_DISSOLVE:
|
||||
apply_dissolve_ipo(final_strip, edit.transition_duration)
|
||||
|
||||
final_strips.append(final_strip)
|
||||
|
||||
# strip= seq.new((0.6, 0.6, 0.6), start, track+1)
|
||||
|
||||
if final_strips:
|
||||
for strip in final_strips:
|
||||
# strip.length= length
|
||||
final_strip.name = edit.asName()
|
||||
edit.custom_data[:]= final_strips
|
||||
# track = not track
|
||||
prev_edit = edit
|
||||
track += 1
|
||||
|
||||
#break
|
||||
|
||||
|
||||
def recursive_update(s):
|
||||
s.update(1)
|
||||
for s_kid in s:
|
||||
recursive_update(s_kid)
|
||||
|
||||
|
||||
for s in seq:
|
||||
recursive_update(s)
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
#load_edl('/fe/edl/EP30CMXtrk1.edl') # /tmp/test.edl
|
||||
#load_edl('/fe/edl/EP30CMXtrk2.edl') # /tmp/test.edl
|
||||
#load_edl('/fe/edl/EP30CMXtrk3.edl') # /tmp/test.edl
|
||||
#load_edl('/root/vid/rush/blender_edl.edl', ['/root/vid/rush/rushes3.avi',]) # /tmp/test.edl
|
||||
|
||||
|
||||
|
||||
|
||||
# ---------------------- Blender UI part
|
||||
from Blender import Draw, Window
|
||||
import BPyWindow
|
||||
|
||||
if 0:
|
||||
DEFAULT_FILE_EDL = '/root/vid/rush/blender_edl.edl'
|
||||
DEFAULT_FILE_MEDIA = '/root/vid/rush/rushes3_wav.avi'
|
||||
DEFAULT_FRAME_OFFSET = -769
|
||||
else:
|
||||
DEFAULT_FILE_EDL = ''
|
||||
DEFAULT_FILE_MEDIA = ''
|
||||
DEFAULT_FRAME_OFFSET = 0
|
||||
|
||||
B_EVENT_IMPORT = 1
|
||||
B_EVENT_RELOAD = 2
|
||||
B_EVENT_FILESEL_EDL = 3
|
||||
B_EVENT_NOP = 4
|
||||
|
||||
B_EVENT_FILESEL = 100 # or greater
|
||||
|
||||
class ReelItemUI(object):
|
||||
__slots__ = 'filename_but', 'offset_but', 'ui_text'
|
||||
def __init__(self):
|
||||
self.filename_but = Draw.Create(DEFAULT_FILE_MEDIA)
|
||||
self.offset_but = Draw.Create(DEFAULT_FRAME_OFFSET)
|
||||
self.ui_text = ''
|
||||
|
||||
|
||||
|
||||
REEL_UI = {} # reel:ui_string
|
||||
|
||||
|
||||
#REEL_FILENAMES = {} # reel:filename
|
||||
#REEL_OFFSETS = {} # reel:filename
|
||||
|
||||
PREF = {}
|
||||
|
||||
PREF['filename'] = Draw.Create(DEFAULT_FILE_EDL)
|
||||
PREF['reel_act'] = ''
|
||||
|
||||
def edl_reload():
|
||||
Window.WaitCursor(1)
|
||||
filename = PREF['filename'].val
|
||||
sce= bpy.data.scenes.active
|
||||
fps= sce.render.fps
|
||||
|
||||
elist= EditList()
|
||||
|
||||
if filename:
|
||||
if not elist.parse(filename, fps):
|
||||
Draw.PupMenu('Error%t|Could not open the file "' + filename + '"')
|
||||
reels = elist.getReels()
|
||||
else:
|
||||
reels = {}
|
||||
|
||||
REEL_UI.clear()
|
||||
for reel_key, edits in reels.iteritems():
|
||||
|
||||
if reel_key == 'bw':
|
||||
continue
|
||||
|
||||
flag = 0
|
||||
for edit in edits:
|
||||
flag |= edit.edit_type
|
||||
|
||||
reel_item = REEL_UI[reel_key] = ReelItemUI()
|
||||
|
||||
reel_item.ui_text = '%s (%s): ' % (reel_key, editFlagsToText(flag))
|
||||
|
||||
Window.WaitCursor(0)
|
||||
|
||||
def edl_set_path(filename):
|
||||
PREF['filename'].val = filename
|
||||
edl_reload()
|
||||
Draw.Redraw()
|
||||
|
||||
def edl_set_path_reel(filename):
|
||||
REEL_UI[PREF['reel_act']].filename_but.val = filename
|
||||
Draw.Redraw()
|
||||
|
||||
def edl_reel_keys():
|
||||
reel_keys = REEL_UI.keys()
|
||||
|
||||
if 'bw' in reel_keys:
|
||||
reel_keys.remove('bw')
|
||||
|
||||
reel_keys.sort()
|
||||
return reel_keys
|
||||
|
||||
def edl_draw():
|
||||
|
||||
MARGIN = 4
|
||||
rect = BPyWindow.spaceRect()
|
||||
but_width = int((rect[2]-MARGIN*2)/4.0) # 72
|
||||
# Clamp
|
||||
if but_width>100: but_width = 100
|
||||
but_height = 17
|
||||
|
||||
x=MARGIN
|
||||
y=rect[3]-but_height-MARGIN
|
||||
xtmp = x
|
||||
|
||||
|
||||
|
||||
# ---------- ---------- ---------- ----------
|
||||
Blender.Draw.BeginAlign()
|
||||
PREF['filename'] = Draw.String('edl path: ', B_EVENT_RELOAD, xtmp, y, (but_width*3)-20, but_height, PREF['filename'].val, 256, 'EDL Path'); xtmp += (but_width*3)-20;
|
||||
Draw.PushButton('..', B_EVENT_FILESEL_EDL, xtmp, y, 20, but_height, 'Select an EDL file'); xtmp += 20;
|
||||
Blender.Draw.EndAlign()
|
||||
|
||||
Draw.PushButton('Reload', B_EVENT_RELOAD, xtmp + MARGIN, y, but_width - MARGIN, but_height, 'Read the ID Property settings from the active curve object'); xtmp += but_width;
|
||||
y-=but_height + MARGIN
|
||||
xtmp = x
|
||||
# ---------- ---------- ---------- ----------
|
||||
|
||||
reel_keys = edl_reel_keys()
|
||||
|
||||
|
||||
|
||||
if reel_keys: text = 'Reel file list...'
|
||||
elif PREF['filename'].val == '': text = 'No EDL loaded.'
|
||||
else: text = 'No reels found!'
|
||||
|
||||
Draw.Label(text, xtmp + MARGIN, y, but_width*4, but_height); xtmp += but_width*4;
|
||||
|
||||
y-=but_height + MARGIN
|
||||
xtmp = x
|
||||
|
||||
# ---------- ---------- ---------- ----------
|
||||
|
||||
|
||||
for i, reel_key in enumerate(reel_keys):
|
||||
reel_item = REEL_UI[reel_key]
|
||||
|
||||
Blender.Draw.BeginAlign()
|
||||
REEL_UI[reel_key].filename_but = Draw.String(reel_item.ui_text, B_EVENT_NOP, xtmp, y, (but_width*3)-20, but_height, REEL_UI[reel_key].filename_but.val, 256, 'Select the reel path'); xtmp += (but_width*3)-20;
|
||||
Draw.PushButton('..', B_EVENT_FILESEL + i, xtmp, y, 20, but_height, 'Media path to use for this reel'); xtmp += 20;
|
||||
Blender.Draw.EndAlign()
|
||||
|
||||
reel_item.offset_but= Draw.Number('ofs:', B_EVENT_NOP, xtmp + MARGIN, y, but_width - MARGIN, but_height, reel_item.offset_but.val, -100000, 100000, 'Start offset in frames when applying timecode'); xtmp += but_width - MARGIN;
|
||||
|
||||
y-=but_height + MARGIN
|
||||
xtmp = x
|
||||
|
||||
# ---------- ---------- ---------- ----------
|
||||
|
||||
Draw.PushButton('Import CMX-EDL Sequencer Strips', B_EVENT_IMPORT, xtmp + MARGIN, MARGIN, but_width*4 - MARGIN, but_height, 'Load the EDL file into the sequencer'); xtmp += but_width*4;
|
||||
y-=but_height + MARGIN
|
||||
xtmp = x
|
||||
|
||||
|
||||
def edl_event(evt, val):
|
||||
pass
|
||||
|
||||
def edl_bevent(evt):
|
||||
|
||||
if evt == B_EVENT_NOP:
|
||||
pass
|
||||
elif evt == B_EVENT_IMPORT:
|
||||
'''
|
||||
Load the file into blender with UI settings
|
||||
'''
|
||||
filename = PREF['filename'].val
|
||||
|
||||
reel_files = {}
|
||||
reel_offsets = {}
|
||||
|
||||
for reel_key, reel_item in REEL_UI.iteritems():
|
||||
reel_files[reel_key] = reel_item.filename_but.val
|
||||
reel_offsets[reel_key] = reel_item.offset_but.val
|
||||
|
||||
error = load_edl(filename, reel_files, reel_offsets)
|
||||
if error != '':
|
||||
Draw.PupMenu('Error%t|' + error)
|
||||
else:
|
||||
Window.RedrawAll()
|
||||
|
||||
elif evt == B_EVENT_RELOAD:
|
||||
edl_reload()
|
||||
Draw.Redraw()
|
||||
|
||||
elif evt == B_EVENT_FILESEL_EDL:
|
||||
filename = PREF['filename'].val
|
||||
if not filename: filename = Blender.sys.join(Blender.sys.expandpath('//'), '*.edl')
|
||||
|
||||
Window.FileSelector(edl_set_path, 'Select EDL', filename)
|
||||
|
||||
elif evt >= B_EVENT_FILESEL:
|
||||
reel_keys = edl_reel_keys()
|
||||
reel_key = reel_keys[evt - B_EVENT_FILESEL]
|
||||
|
||||
filename = REEL_UI[reel_key].filename_but.val
|
||||
if not filename: filename = Blender.sys.expandpath('//')
|
||||
|
||||
PREF['reel_act'] = reel_key # so file set path knows which one to set
|
||||
Window.FileSelector(edl_set_path_reel, 'Reel Media', filename)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Draw.Register(edl_draw, edl_event, edl_bevent)
|
||||
edl_reload()
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus: <- these words are ignored
|
||||
Name: 'Lightwave Motion (.mot)...'
|
||||
Blender: 245
|
||||
Group: 'Import'
|
||||
Tip: 'Import Loc Rot Size chanels from a Lightwave .mot file'
|
||||
"""
|
||||
|
||||
__author__ = "Daniel Salazar (ZanQdo)"
|
||||
__url__ = ("blender", "blenderartists.org",
|
||||
"e-mail: zanqdo@gmail.com")
|
||||
__version__ = "16/04/08"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script loads Lightwave motion files (.mot)
|
||||
into the selected objects
|
||||
|
||||
Usage:
|
||||
Run the script with one or more objects selected (any kind)
|
||||
Be sure to set the framerate correctly
|
||||
|
||||
"""
|
||||
|
||||
# $Id$
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2003, 2004: A Vanpoucke
|
||||
#
|
||||
# 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import math as M
|
||||
import Blender as B
|
||||
import bpy
|
||||
|
||||
|
||||
def FuncionPrincipal (Dir):
|
||||
B.Window.WaitCursor(1)
|
||||
ObjSelect = B.Object.GetSelected()
|
||||
|
||||
if not ObjSelect:
|
||||
B.Draw.PupMenu('Select one or more objects, aborting.')
|
||||
return
|
||||
|
||||
|
||||
SC = B.Scene.GetCurrent()
|
||||
SCR = SC.getRenderingContext()
|
||||
FrameRate = float(SCR.framesPerSec())
|
||||
|
||||
|
||||
# Creating new IPO
|
||||
|
||||
IPO = B.Ipo.New('Object', 'LW_Motion')
|
||||
|
||||
|
||||
# Creating Curves in the IPO
|
||||
|
||||
LocX = IPO.addCurve("LocX")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
LocY = IPO.addCurve("LocY")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
LocZ = IPO.addCurve("LocZ")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
RotX = IPO.addCurve("RotX")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
RotY = IPO.addCurve("RotY")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
RotZ = IPO.addCurve("RotZ")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
ScaleX = IPO.addCurve("ScaleX")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
ScaleY = IPO.addCurve("ScaleY")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
ScaleZ = IPO.addCurve("ScaleZ")
|
||||
LocX.setInterpolation("Bezier")
|
||||
|
||||
|
||||
# Opening the mot file
|
||||
|
||||
File = open (Dir, 'rU')
|
||||
|
||||
|
||||
# Init flags
|
||||
|
||||
CurChannel = -1
|
||||
ScaleFlag = 0
|
||||
|
||||
# Main file reading cycle
|
||||
|
||||
for Line in File:
|
||||
|
||||
'''
|
||||
# Number of channels in the file
|
||||
|
||||
if "NumChannels" in Line:
|
||||
Line = Line.split (' ')
|
||||
NumChannels = int(Line[1])
|
||||
'''
|
||||
|
||||
# Current Channel Flag
|
||||
|
||||
if "Channel 0" in Line:
|
||||
CurChannel = 0
|
||||
|
||||
elif "Channel 1" in Line:
|
||||
CurChannel = 1
|
||||
|
||||
elif "Channel 2" in Line:
|
||||
CurChannel = 2
|
||||
|
||||
elif "Channel 3" in Line:
|
||||
CurChannel = 3
|
||||
|
||||
elif "Channel 4" in Line:
|
||||
CurChannel = 4
|
||||
|
||||
elif "Channel 5" in Line:
|
||||
CurChannel = 5
|
||||
|
||||
elif "Channel 6" in Line:
|
||||
CurChannel = 6
|
||||
|
||||
elif "Channel 7" in Line:
|
||||
CurChannel = 7
|
||||
|
||||
elif "Channel 8" in Line:
|
||||
CurChannel = 8
|
||||
|
||||
|
||||
# Getting the data and writing to IPOs
|
||||
|
||||
if CurChannel == 0:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_0 = float (Line [3])
|
||||
TimeCh_0 = float (Line [4]) * FrameRate
|
||||
LocX.addBezier ((TimeCh_0, ValCh_0))
|
||||
|
||||
if CurChannel == 1:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_1 = float (Line [3])
|
||||
TimeCh_1 = float (Line [4]) * FrameRate
|
||||
LocZ.addBezier ((TimeCh_1, ValCh_1))
|
||||
|
||||
if CurChannel == 2:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_2 = float (Line [3])
|
||||
TimeCh_2 = float (Line [4]) * FrameRate
|
||||
LocY.addBezier ((TimeCh_2, ValCh_2))
|
||||
|
||||
if CurChannel == 3:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_3 = M.degrees ( - float (Line [3]) ) / 10
|
||||
TimeCh_3 = float (Line [4]) * FrameRate
|
||||
RotZ.addBezier ((TimeCh_3, ValCh_3))
|
||||
|
||||
if CurChannel == 4:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_4 = M.degrees ( - float (Line [3]) ) / 10
|
||||
TimeCh_4 = float (Line [4]) * FrameRate
|
||||
RotX.addBezier ((TimeCh_4, ValCh_4))
|
||||
|
||||
if CurChannel == 5:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_5 = M.degrees ( - float (Line [3]) ) / 10
|
||||
TimeCh_5 = float (Line [4]) * FrameRate
|
||||
RotY.addBezier ((TimeCh_5, ValCh_5))
|
||||
|
||||
if CurChannel == 6:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_6 = float (Line [3])
|
||||
TimeCh_6 = float (Line [4]) * FrameRate
|
||||
ScaleX.addBezier ((TimeCh_6, ValCh_6))
|
||||
elif ScaleFlag < 3:
|
||||
ScaleFlag += 1
|
||||
ScaleX.addBezier ((0, 1))
|
||||
|
||||
if CurChannel == 7:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_7 = float (Line [3])
|
||||
TimeCh_7 = float (Line [4]) * FrameRate
|
||||
ScaleZ.addBezier ((TimeCh_7, ValCh_7))
|
||||
elif ScaleFlag < 3:
|
||||
ScaleFlag += 1
|
||||
ScaleZ.addBezier ((0, 1))
|
||||
|
||||
if CurChannel == 8:
|
||||
if "Key" in Line:
|
||||
Line = Line.split (' ')
|
||||
ValCh_8 = float (Line [3])
|
||||
TimeCh_8 = float (Line [4]) * FrameRate
|
||||
ScaleY.addBezier ((TimeCh_8, ValCh_8))
|
||||
elif ScaleFlag < 3:
|
||||
ScaleFlag += 1
|
||||
ScaleY.addBezier ((0, 1))
|
||||
|
||||
|
||||
# Link the IPO to all selected objects
|
||||
|
||||
for ob in ObjSelect:
|
||||
ob.setIpo(IPO)
|
||||
|
||||
File.close()
|
||||
|
||||
print '\nDone, the following motion file has been loaded:\n\n%s' % Dir
|
||||
B.Window.WaitCursor(0)
|
||||
|
||||
def main():
|
||||
B.Window.FileSelector(FuncionPrincipal, "Load IPO from .mot File", B.sys.makename(ext='.mot'))
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Load MDD to Mesh RVKs'
|
||||
Blender: 242
|
||||
Group: 'Import'
|
||||
Tooltip: 'baked vertex animation to active mesh object.'
|
||||
"""
|
||||
__author__ = "Bill L.Nieuwendorp"
|
||||
__bpydoc__ = """\
|
||||
This script Imports Lightwaves MotionDesigner format.
|
||||
|
||||
The .mdd format has become quite a popular Pipeline format<br>
|
||||
for moving animations from package to package.
|
||||
"""
|
||||
# mdd importer
|
||||
#
|
||||
# Warning if the vertex order or vertex count differs from the
|
||||
# origonal model the mdd was Baked out from their will be Strange
|
||||
# behavior
|
||||
#
|
||||
#
|
||||
#vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0
|
||||
#A modifier to read mdd files would be Ideal but thats for another day :)
|
||||
#
|
||||
#Please send any fixes,updates,bugs to Slow67_at_Gmail.com
|
||||
#Bill Niewuendorp
|
||||
|
||||
# ***** 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 *****
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
from struct import unpack
|
||||
except:
|
||||
unpack = None
|
||||
|
||||
import Blender
|
||||
from Blender import Mesh, Object, Scene
|
||||
import BPyMessages
|
||||
|
||||
def mdd_import(filepath, ob, PREF_IPONAME, PREF_START_FRAME, PREF_JUMP):
|
||||
|
||||
print '\n\nimporting mdd "%s"' % filepath
|
||||
|
||||
Blender.Window.DrawProgressBar (0.0, "Importing mdd ...")
|
||||
Blender.Window.EditMode(0)
|
||||
Blender.Window.WaitCursor(1)
|
||||
|
||||
file = open(filepath, 'rb')
|
||||
frames, points = unpack(">2i", file.read(8))
|
||||
time = unpack((">%df" % frames), file.read(frames * 4))
|
||||
|
||||
print '\tpoints:%d frames:%d' % (points,frames)
|
||||
|
||||
scn = Scene.GetCurrent()
|
||||
ctx = scn.getRenderingContext()
|
||||
Blender.Set("curframe", PREF_START_FRAME)
|
||||
me = ob.getData(mesh=1)
|
||||
|
||||
def UpdateMesh(me,fr):
|
||||
for v in me.verts:
|
||||
# 12 is the size of 3 floats
|
||||
x,y,z= unpack('>3f', file.read(12))
|
||||
v.co[:] = x,z,y
|
||||
me.update()
|
||||
|
||||
Blender.Window.DrawProgressBar (0.4, "4 Importing mdd ...")
|
||||
|
||||
|
||||
curfr = ctx.currentFrame()
|
||||
print'\twriting mdd data...'
|
||||
for i in xrange(frames):
|
||||
Blender.Set("curframe", i+PREF_START_FRAME)
|
||||
if len(me.verts) > 1 and (curfr >= PREF_START_FRAME) and (curfr <= PREF_START_FRAME+frames):
|
||||
UpdateMesh(me, i)
|
||||
ob.insertShapeKey()
|
||||
|
||||
Blender.Window.DrawProgressBar (0.5, "5 Importing mdd ...")
|
||||
|
||||
key= me.key
|
||||
|
||||
# Add the key of its not there
|
||||
if not key:
|
||||
me.insertKey(1, 'relative')
|
||||
key= me.key
|
||||
|
||||
key.ipo = Blender.Ipo.New('Key', PREF_IPONAME)
|
||||
ipo = key.ipo
|
||||
# block = key.getBlocks() # not used.
|
||||
all_keys = ipo.curveConsts
|
||||
|
||||
for i in xrange(PREF_JUMP+1, len(all_keys), PREF_JUMP):
|
||||
curve = ipo.getCurve(i)
|
||||
if curve == None:
|
||||
curve = ipo.addCurve(all_keys[i])
|
||||
|
||||
curve.append((PREF_START_FRAME+i-1,1))
|
||||
curve.append((PREF_START_FRAME+i- PREF_JUMP -1,0))
|
||||
curve.append((PREF_START_FRAME+i+ PREF_JUMP-1,0))
|
||||
curve.setInterpolation('Linear')
|
||||
curve.recalc()
|
||||
|
||||
print 'done'
|
||||
Blender.Window.WaitCursor(0)
|
||||
Blender.Window.DrawProgressBar (1.0, '')
|
||||
|
||||
|
||||
def mdd_import_ui(filepath):
|
||||
|
||||
if BPyMessages.Error_NoFile(filepath):
|
||||
return
|
||||
|
||||
scn= Scene.GetCurrent()
|
||||
ob_act= scn.objects.active
|
||||
|
||||
if ob_act == None or ob_act.type != 'Mesh':
|
||||
BPyMessages.Error_NoMeshActive()
|
||||
return
|
||||
|
||||
PREF_IPONAME = Blender.Draw.Create(filepath.split('/')[-1].split('\\')[-1].split('.')[0])
|
||||
PREF_START_FRAME = Blender.Draw.Create(1)
|
||||
PREF_JUMP = Blender.Draw.Create(1)
|
||||
|
||||
block = [\
|
||||
("Ipo Name: ", PREF_IPONAME, 0, 30, "Ipo name for the new shape key"),\
|
||||
("Start Frame: ", PREF_START_FRAME, 1, 3000, "Start frame for the animation"),\
|
||||
("Key Skip: ", PREF_JUMP, 1, 100, "KeyReduction, Skip every Nth Frame")\
|
||||
]
|
||||
|
||||
if not Blender.Draw.PupBlock("Import MDD", block):
|
||||
return
|
||||
orig_frame = Blender.Get('curframe')
|
||||
mdd_import(filepath, ob_act, PREF_IPONAME.val, PREF_START_FRAME.val, PREF_JUMP.val)
|
||||
Blender.Set('curframe', orig_frame)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not unpack:
|
||||
Draw.PupMenu('Error%t|This script requires a full python install')
|
||||
|
||||
Blender.Window.FileSelector(mdd_import_ui, 'IMPORT MDD', '*.mdd')
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user