Added research data, testing blender mesh generation

This commit is contained in:
2021-05-23 15:34:33 -05:00
parent f2efb7c42d
commit 505df54a1e
205 changed files with 124004 additions and 40 deletions

View File

@@ -0,0 +1,159 @@
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()
'''

View File

@@ -0,0 +1,152 @@
# 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

View File

@@ -0,0 +1,36 @@
# $Id: BPyBlender.py 5652 2005-10-30 19:19:38Z aphex $
#
# --------------------------------------------------------------------------
# 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'
]

View File

@@ -0,0 +1,79 @@
# --------------------------------------------------------------------------
# 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

View File

@@ -0,0 +1,318 @@
# --------------------------------------------------------------------------
# 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.

View File

@@ -0,0 +1,228 @@
# $Id: BPyMathutils.py 20333 2009-05-22 03:45:46Z campbellbarton $
#
# --------------------------------------------------------------------------
# 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

View File

@@ -0,0 +1,652 @@
# ***** 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()

View File

@@ -0,0 +1,61 @@
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

View File

@@ -0,0 +1,48 @@
# $Id: BPyNMesh.py 4439 2005-05-17 07:17:52Z ianwill $
#
# --------------------------------------------------------------------------
# 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()

View File

@@ -0,0 +1,108 @@
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

View File

@@ -0,0 +1,267 @@
# --------------------------------------------------------------------------
# Module BPyRegistry version 0.1
# Helper functions to store / restore configuration data.
# --------------------------------------------------------------------------
# $Id: BPyRegistry.py 14353 2008-04-07 20:56:45Z theeth $
#
# ***** 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

View File

@@ -0,0 +1,633 @@
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

View File

@@ -0,0 +1,74 @@
## 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.

View File

@@ -0,0 +1,814 @@
"""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 '================================================'

View File

@@ -0,0 +1,206 @@
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

View File

@@ -0,0 +1,95 @@
#!/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()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,726 @@
# --------------------------------------------------------------------------
# Illusoft Collada 1.4 plugin for Blender
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Illusoft - colladablender@illusoft.com
# 2008.05.08 modif. for debug mode by migius (AKA Remigiusz Fiedler)
#
# 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.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
debug = False #--- debug mode
debprn = False #--- print debug "print 'deb: ..."
_ERROR = False
_PERROR = False
import sys
try:
import Blender
except NameError:
print "Error! Could not find Blender modules!"
_ERROR = True
__version__ = '0.3.162'
# Show the wait cursor in blender
Blender.Window.WaitCursor(1)
# indicates if the user can choose a file to import
useDefaultFile = True
defaultFileUrl = 'animation.DAE'
#defaultFileUrl = 'animation.DAE'
#defaultFileUrl = 'animated_letters.DAE'
#defaultFileUrl = 'animation_robot.DAE'
defaultExportUrl = ''
# Check if full version of python is installed.
try:
import os
import xml
except ImportError:
print"Error! Could not find full version of Python..."
_ERROR = True
if _ERROR:
from sys import version_info
version = '%s.%s' % version_info[0:2]
print """
To run the collada importer and exporter you need to have
Python version %s installed in your system. It can be downloaded from:
http://www.python.org
Notes:
- The minor (third) version number doesn't matter, you can have either
Python %s.1 or %s.2 or higher.
- If you do have Python %s installed and still can't run the scripts, then
make sure Blender's Python interpreter is finding the standalone modules
(run 'System Information' from Blender's Help -> System menu).
""" % (version, version, version, version)
Blender.Draw.PupMenu("Please install full version of python %t | Check the console for more info")
raise StandardError()
else:
# Try to load the Plugin modules
try:
import cutils
except NameError:
print "\nError! Could not find Collada Utils (cutils) module!"
_ERROR = True
try:
import xmlUtils
except NameError:
print "\nError! Could not find XML module!"
_PERROR = True
try:
import collada
except NameError:
print "Error! Could not find Collada(collada.py) module"
_PERROR = True
try:
import translator
except NameError:
print "Error! Could not find Collada Translator (translator.py) module"
_PERROR = True
try:
import helperObjects
except NameError:
print "Error! Could not find Collada helperObjects (helperObjects.py) module"
_PERROR = True
# Try to load extra python modules
try:
import math
except NameError:
print "Error! Could not find math module"
_PERROR = True
if _PERROR:
Blender.Draw.PupMenu("Cannot load plugin modules.")
else:
# A List with al the modules (in the scriptsdir) to be reloaded
modules = [cutils, xmlUtils, collada, helperObjects, translator]
def Main(doImp, scriptsLoc):
global debug, __version__, doImport, scriptsLocation, defaultFilename, valsLoaded
if _ERROR or _PERROR:
return
valsLoaded = False
doImport = doImp
if scriptsLoc == "":
scriptsLoc = Blender.Get('scriptsdir')
if not scriptsLoc: scriptsLoc = Blender.Get('uscriptsdir')
if scriptsLoc:
scriptsLocation = scriptsLoc+Blender.sys.sep+'bpymodules'+Blender.sys.sep+'colladaImEx'+Blender.sys.sep
else:
print 'Could not find a scripts path'
else:
scriptsLocation = scriptsLoc
if not ReloadModules():
print 'cannot reload all modules'
return False
# Clear the console
cutils.ClearConsole()
# set the debuglevel
if debug:
cutils.Debug.SetLevel('DEBUG')
else:
cutils.Debug.SetLevel('FEEDBACK')
cutils.Debug.Debug('Illusoft Collada 1.4 Plugin v%s started'%(__version__),'FEEDBACK')
# Create a Collada <-> Blender Translator
if debug:
print 'keep track of the time to execute this script' #---------
startTime = Blender.sys.time()
##fileurl = scriptsDir
fileurl = ''
if doImport:
fileurl+= defaultFileUrl
else :
fileurl += defaultExportUrl
if debprn: print 'deb: fileurl=',fileurl #-------
useTriangles = False
usePolygons = False
bakeMatrices = False
exportSelection = False
newScene = True
clearScene = False
lookAt = False
usePhysics = True
exportCurrentScene = False
exportRelativePaths = False
useUV = False
sampleAnimation = False
onlyMainScene = False
transl = translator.Translator(doImport,__version__,debug,fileurl, useTriangles, usePolygons, bakeMatrices, exportSelection, newScene, clearScene, lookAt, usePhysics, exportCurrentScene, exportRelativePaths, useUV, sampleAnimation, onlyMainScene)
##transl = translator.Translator(doImport,__version__,debug,fileurl)
##translator = Translator(False,__version__,debug,scriptsDir+defaultExportUrl)
##translator = Translator(True,__version__,debug,scriptsDir+defaultExportUrl)
# Redraw al 3D windows.
if debprn: print 'deb: ---- the end ----' #-----
Blender.Window.RedrawAll()
# calculate the elapsed time
endTime = Blender.sys.time()
elapsedTime = endTime - startTime
cutils.Debug.Debug('FINISHED - time elapsed: %.1f'%(elapsedTime),'FEEDBACK')
# Hide the wait cursor in blender
Blender.Window.WaitCursor(0)
else:
defFilename = Blender.sys.dirname(Blender.sys.progname)+Blender.sys.sep
colladaReg = Blender.Registry.GetKey('collada',True)
if not (colladaReg is None) and 'path' in colladaReg and Blender.sys.exists(colladaReg['path']):
defFilename = colladaReg['path']
elif not (doImport):
defFilename += 'untitled.dae'
defaultFilename = defFilename
Blender.Draw.Register(Gui, Event, ButtonEvent) # registering the 3 callbacks
def ReloadModules():
# Loop through all the modules and try to reload them
for module in modules:
try:
reload(module)
except NameError:
cutils.Debug.Debug('cannot reload module %s' %(module),'ERROR')
return False
return True
def FileSelected(fileName):
global doImport, fileButton
if fileName != '':
# check if file exists
if Blender.sys.exists(fileName) != 1 and doImport:
cutils.Debug.Debug('File(%s) does not exist' % (fileName),'ERROR')
return False
# must the file to import end with .dae or .xml?
## if doImport:
## # Check if the file has a valid extension .DAE or .XML
## extension = fileName.rsplit('.',1)[1].lower()
## if extension != 'xml' and extension != 'dae':
## cutils.Debug.Debug('File(%s) is not a .dae or .xml file' % (fileName),'ERROR')
fileButton.val = fileName
##transl = translator.Translator(doImport,__version__,debug,fileName)
else:
cutils.Debug.Debug('ERROR: filename is empty','ERROR')
toggle = 0
fileButton = None
toggleTriangles = None
togglePolygons = None
toggleExportSelection = None
toggleClearScene = None
toggleNewScene = None
toggleBakeMatrix = None
toggleSampleAnimation = None
toggleLookAt = None
togglePhysics = None
toggleExportCurrentScene = None
toggleExportRelativePaths = None
toggleUseUV = None
toggleSampleAnimation = None
toggleOnlyMainScene = None
toggleApplyModifiers = None
def LoadDefaultVals():
global toggleLookAt, toggleBakeMatrix, toggleSampleAnimation, toggleNewScene, \
toggleClearScene, toggleTriangles, togglePolygons, toggleExportSelection, \
scriptsLocation, doImport, defaultFilename, fileButton, valsLoaded, \
togglePhysics, toggleExportCurrentScene, toggleExportRelativePaths, \
toggleUseUV, toggleOnlyMainScene, toggleApplyModifiers
if valsLoaded:
return None
colladaReg = Blender.Registry.GetKey('collada',True)
if not (colladaReg is None):
fileButton.val = colladaReg.get('path', '')
fileParts = []
filePath = "";
fileParts = fileButton.val.split("\\");
partCount = len(fileParts);
if partCount > 0 :
for i in range(partCount):
if i == 0:
filePath = fileParts[i];
else :
if i != partCount - 1:
filePath = filePath + "\\" + fileParts[i];
else:
filePath = filePath + "\\";
blenderFilename = Blender.Get('filename');
fileParts = []
fileParts = blenderFilename.split("\\");
partCount = len(fileParts);
if partCount > 0 :
blenderFileOnlyName = fileParts[partCount -1];
blenderFileOnlyName = blenderFileOnlyName.replace(".blend", ".dae");
filePath = filePath + blenderFileOnlyName;
else :
filePath = filePath + "untitled.dae";
if len(filePath) > 0 :
fileButton.val = filePath;
if doImport:
toggleOnlyMainScene.val = colladaReg.get('onlyMainScene', False)
toggleNewScene.val = colladaReg.get('newScene', False)
toggleClearScene.val = colladaReg.get('clearScene', False)
else:
##toggleLookAt.val = colladaReg.get('lookAt', False)
toggleBakeMatrix.val = colladaReg.get('bakeMatrices', False)
toggleTriangles.val = colladaReg.get('useTriangles', False)
togglePolygons.val = colladaReg.get('usePolygons', False)
toggleExportSelection.val = colladaReg.get('exportSelection', False)
togglePhysics.val = not colladaReg.get('usePhysics', True)
toggleExportCurrentScene.val = colladaReg.get('exportCurrentScene', False)
toggleExportRelativePaths.val = colladaReg.get('exportRelativePaths', True)
toggleSampleAnimation.val = colladaReg.get('sampleAnimation', False)
toggleUseUV.val = colladaReg.get('useUV', False)
#TODO: "toggleOnlyMainScene" left out intentionally by the original plugin author?
toggleApplyModifiers.val = colladaReg.get('applyModifiers', True)
valsLoaded = True
def Gui():
global toggleLookAt, toggleBakeMatrix, toggleSampleAnimation, toggleNewScene, \
toggleClearScene, toggleTriangles, togglePolygons, toggleExportSelection, \
scriptsLocation, doImport, defaultFilename, fileButton, togglePhysics, \
toggleExportCurrentScene, toggleExportRelativePaths, toggleUseUV, \
toggleOnlyMainScene, toggleApplyModifiers
Blender.BGL.glClearColor(0.898,0.910,0.808,1) # Set BG Color1
Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
Blender.BGL.glColor3f(0.835,0.848,0.745) # BG Color 2
size = Blender.Window.GetAreaSize()
Blender.BGL.glRectd(40,0,200,size[1])
try:
logoImage = Blender.Image.Load(scriptsLocation + 'logo.png')
Blender.BGL.glEnable(Blender.BGL.GL_BLEND ) # Only needed for alpha blending images with background.
Blender.BGL.glBlendFunc(Blender.BGL.GL_SRC_ALPHA, Blender.BGL.GL_ONE_MINUS_SRC_ALPHA)
try: Blender.Draw.Image(logoImage, 45, size[1]-30)
except: pass
Blender.BGL.glDisable(Blender.BGL.GL_BLEND)
except IOError: # image not found
Blender.BGL.glColor3i(0.255,0.255,0.2)
Blender.BGL.glRasterPos2i(45, size[1]-30)
Blender.Draw.Text("Collada 1.4.0 Plugin for Blender", "large")
Blender.BGL.glColor3f(0.255,0.255,0.2)
Blender.BGL.glRasterPos2i(45, size[1]-40)
Blender.Draw.Text("Version: %s"%(__version__),"small")
# Write donation text
donateText1 = "If this plugin is valuable to you or your company, please consider a donation at"
donateText2 = "http://colladablender.illusoft.com to support this plugin. Thanks a lot!"
Blender.BGL.glRasterPos2i(45, size[1]-60)
Blender.Draw.Text(donateText1, "small")
Blender.BGL.glRasterPos2i(45, size[1]-70)
Blender.Draw.Text(donateText2, "small")
# Write import / export text
Blender.BGL.glColor3f(0.9,0.08,0.08)
Blender.BGL.glRasterPos2i(45, size[1]-95)
if doImport:
importExportText = "Import"
else:
importExportText = "Export"
Blender.Draw.Text(importExportText, "normal")
Blender.BGL.glColor3f(0.255,0.255,0.2)
# Create File path input
yval = size[1]-130
Blender.BGL.glRasterPos2i(45, yval)
if fileButton is None or fileButton.val == '':
fileName = defaultFilename
else:
fileName = fileButton.val
Blender.Draw.Text('%s file:'%(importExportText),"normal")
maxWidth = 400
if size[0] - (105 + 35) > maxWidth:
fileWidth = maxWidth
else:
fileWidth = size[0] - (105 + 35)
fileButton = Blender.Draw.String('', 5, 105, yval-5, fileWidth, 20, fileName, 255)
Blender.Draw.PushButton('...', 2, 105 + fileWidth, yval-5, 30, 20, 'browse file')
Blender.Draw.PushButton("Cancel", 3, 45, 10, 55, 20, "Cancel")
Blender.Draw.PushButton(importExportText + ' and Close', 4, 45+55+35, 10, 100, 20, importExportText + ' and close this screen')
# Create Export Options:
if not doImport:
yval = yval - 50
# Create Triangle / Polygons Options
if not (toggleTriangles is None):
toggleTrianglesVal = toggleTriangles.val
else:
toggleTrianglesVal = 0
if not (togglePolygons is None):
togglePolygonsVal = togglePolygons.val
else:
togglePolygonsVal = 0
toggleTriangles = Blender.Draw.Toggle('Triangles',6,45, yval, 60, 20, toggleTrianglesVal, 'Export all geometry as triangles')
togglePolygons = Blender.Draw.Toggle('Polygons',7,45+60 + 30, yval, 60, 20, togglePolygonsVal, 'Export all geometry as polygons')
yval = yval - 40
# Create Export Selection Option
if not (toggleExportSelection is None):
toggleExportSelectionVal = toggleExportSelection.val
else:
toggleExportSelectionVal = 0
toggleExportSelection = Blender.Draw.Toggle('Only Export Selection',8,45, yval, 150, 20, toggleExportSelectionVal, 'Only export selected objects')
yval = yval - 40
# Create Bake Matrix Option
if not (toggleBakeMatrix is None):
toggleBakeMatrixVal = toggleBakeMatrix.val
else:
toggleBakeMatrixVal = 0
toggleBakeMatrix = Blender.Draw.Toggle('Bake Matrices',11,45, yval, 150, 20, toggleBakeMatrixVal, 'Put all transformations in a single matrix')
yval = yval - 40
# Create Sample Anim
if not (toggleSampleAnimation is None):
toggleSampleAnimationVal = toggleSampleAnimation.val
else:
toggleSampleAnimationVal = 0
toggleSampleAnimation = Blender.Draw.Toggle('Sample Animation',16,45, yval, 150, 20, toggleSampleAnimationVal, 'Export information for every frame of animation.')
yval = yval - 40
#Create Physics Option
if not (togglePhysics is None):
togglePhysicsVal = togglePhysics.val
else:
togglePhysicsVal = 0
togglePhysics = Blender.Draw.Toggle('Disable Physics',13,45, yval, 150, 20, togglePhysicsVal, 'Disable Export physics information')
yval = yval - 40
#Create Physics Option
if not (toggleExportCurrentScene is None):
toggleExportCurrentSceneVal = toggleExportCurrentScene.val
else:
toggleExportCurrentSceneVal = 0
toggleExportCurrentScene = Blender.Draw.Toggle('Only Current Scene',14,45, yval, 150, 20, toggleExportCurrentSceneVal, 'Only Export the current scene')
yval = yval - 40
#Create Relative Path's Option
if not (toggleExportRelativePaths is None):
toggleExportRelativePathsVal = toggleExportRelativePaths.val
else:
toggleExportRelativePathsVal = 0
toggleExportRelativePaths = Blender.Draw.Toggle('Use Relative Paths',15,45, yval, 150, 20, toggleExportRelativePathsVal, 'Export paths relative to the collada file')
yval = yval - 40
#Create Relative Path's Option
if not (toggleUseUV is None):
toggleUseUVVal = toggleUseUV.val
else:
toggleUseUVVal = 0
toggleUseUV = Blender.Draw.Toggle('Use UV Image Mats',15,45, yval, 150, 20, toggleUseUVVal, 'Use UV Image instead of the material textures. Use this if you did not use the Material Textures window. Note: If you reimport this file, they will have moved to the materials section!!')
##yval = yval - 40
# Create Lookat Option
if not (toggleLookAt is None):
toggleLookAtVal = toggleLookAt.val
else:
toggleLookAtVal = 0
##toggleLookAt = Blender.Draw.Toggle('Camera as Lookat',14,45, yval, 150, 20, toggleLookAtVal, 'Export the transformation of camera\'s as lookat')
yval = yval - 40
if not (toggleApplyModifiers is None):
toggleApplyModifiersVal = toggleApplyModifiers.val
else:
toggleApplyModifiersVal = 0
toggleApplyModifiers = Blender.Draw.Toggle('Apply modifiers',14,45, yval, 150, 20, toggleApplyModifiersVal, 'Apply modifiers, like mirroring, transformations, etc.')
Blender.Draw.PushButton(importExportText, 12, 45+55+35+100+35, 10, 55, 20, importExportText)
else: # IMPORT GUI
yval = yval - 50
# Create Import To new Scene Options
if not (toggleNewScene is None):
toggleNewSceneVal = toggleNewScene.val
else:
toggleNewSceneVal = 0
if not (toggleClearScene is None):
toggleClearSceneVal = toggleClearScene.val
else:
toggleClearSceneVal = 0
if not (toggleOnlyMainScene is None):
toggleOnlyMainSceneVal = toggleOnlyMainScene.val
else:
toggleOnlyMainSceneVal = 0
if toggleOnlyMainSceneVal == 0:
if toggleClearSceneVal == 0 and toggleNewSceneVal == 0:
toggleNewSceneVal = 1
newSceneText = 'Import file into a new Scene';
newSceneTitle = 'New Scene'
clearSceneText = 'Clear everything on the current scene'
clearSceneTitle = 'Clear Scene'
if toggleOnlyMainSceneVal == 0:
newSceneText = 'Import file into a new Scenes'
newSceneTitle = 'New Scenes'
clearSceneText = 'Delete all the Blender Scenes'
clearSceneTitle = 'Delete Scenes'
toggleOnlyMainScene = Blender.Draw.Toggle('Only Import Main Scene',17,40, yval, 190, 20, toggleOnlyMainSceneVal, 'Only import the main scene from Collada')
yval = yval - 40
toggleNewScene = Blender.Draw.Toggle(newSceneTitle,9,40, yval, 90, 20, toggleNewSceneVal, newSceneText)
toggleClearScene = Blender.Draw.Toggle(clearSceneTitle,10,40+90 + 10, yval, 90, 20, toggleClearSceneVal, clearSceneText)
LoadDefaultVals()
def CalcElapsedTime(startTime):
'''
Calc elapsed time between now and start time.
'''
return Blender.sys.time() - startTime
def Event(evt, val):
pass
def ButtonEvent(evt):
global toggleLookAt, toggleBakeMatrix, toggleExportSelection,toggleNewScene, \
toggleClearScene, toggleTriangles, togglePolygons, doImport, defaultFilename, \
fileSelectorShown, fileButton, valsLoaded, togglePhysics, \
toggleExportCurrentScene, toggleExportRelativePaths, toggleUseUV, \
toggleSampleAnimation, toggleOnlyMainScene
checkImportButtons = False
if evt == 1:
toggle = 1 - toggle
Blender.Draw.Redraw(1)
elif evt == 2: # browse file
browseText = ''
if doImport:
browseText = 'Import .dae'
else:
browseText = 'Export .dae'
Blender.Window.FileSelector(FileSelected,browseText,defaultFilename)
Blender.Draw.Redraw(1)
elif evt == 3:
Blender.Draw.Exit()
elif evt == 4 or evt == 12: # Ok, time to export/import
#keep track of the time to execute this script
startTime = Blender.sys.time()
fileName = fileButton.val
dirName = Blender.sys.dirname(fileName) + Blender.sys.sep
exists = Blender.sys.exists(fileName)
if exists == 1 and not doImport:
overwrite = Blender.Draw.PupMenu( "File Already Exists, Overwrite?%t|Yes%x1|No%x0" )
if not overwrite == 1:
return False
elif exists != 1 and doImport:
Blender.Draw.PupMenu("File does not exist: %t|"+fileName)
cutils.Debug.Debug('File(%s) does not exist' % (fileName),'ERROR')
return False
elif not Blender.sys.exists(dirName):
Blender.Draw.PupMenu("Path is not valid: %t|"+dirName)
cutils.Debug.Debug('Path is not valid: %s' % (dirName),'ERROR')
return False
if toggleTriangles is None:
useTriangles = False
else:
useTriangles = bool(toggleTriangles.val)
if togglePolygons is None:
usePolygons = False
else:
usePolygons = bool(togglePolygons.val)
if toggleBakeMatrix is None:
bakeMatrices = False
else:
bakeMatrices = bool(toggleBakeMatrix.val)
if toggleExportSelection is None:
exportSelection = False
else:
exportSelection = bool(toggleExportSelection.val)
if toggleNewScene is None:
newScene = False
else:
newScene = bool(toggleNewScene.val)
if toggleClearScene is None:
clearScene = False
else:
clearScene = bool(toggleClearScene.val)
if toggleOnlyMainScene is None:
onlyMainScene = False
else:
onlyMainScene = bool(toggleOnlyMainScene.val)
if toggleLookAt is None:
lookAt = False
else:
lookAt = bool(toggleLookAt.val)
if togglePhysics is None:
usePhysics = True
else:
usePhysics = not bool(togglePhysics.val)
if toggleExportCurrentScene is None:
exportCurrentScene = False
else:
exportCurrentScene = bool(toggleExportCurrentScene.val)
if toggleExportRelativePaths is None:
exportRelativePaths = False
else:
exportRelativePaths = bool(toggleExportRelativePaths.val)
if toggleUseUV is None:
useUV = False
else:
useUV = bool(toggleUseUV.val)
if toggleSampleAnimation is None:
sampleAnimation = False
else:
sampleAnimation = bool(toggleSampleAnimation.val)
if toggleApplyModifiers is None:
applyModifiers = False
else:
applyModifiers = bool(toggleApplyModifiers.val)
d = Blender.Registry.GetKey('collada',True)
if d is None:
d = dict()
d['path'] = fileName
if doImport:
d['newScene'] = newScene
d['clearScene'] = clearScene
d['onlyMainScene'] = onlyMainScene
else:
d['useTriangles'] = useTriangles
d['usePolygons'] = usePolygons
d['bakeMatrices'] = bakeMatrices
d['exportSelection'] = exportSelection
d['lookAt'] = lookAt
d['usePhysics'] = usePhysics
d['exportCurrentScene'] = exportCurrentScene
d['exportRelativePaths'] = exportRelativePaths
d['useUV'] = useUV
d['sampleAnimation'] = sampleAnimation
d['applyModifiers'] = applyModifiers
Blender.Registry.SetKey('collada',d, True)
if doImport:
importExportText = "Import"
else:
importExportText = "Export"
try:
transl = translator.Translator(doImport,__version__,debug,fileName, \
useTriangles, usePolygons, bakeMatrices,\
exportSelection, newScene, clearScene, \
lookAt, usePhysics, exportCurrentScene, \
exportRelativePaths, useUV, sampleAnimation, \
onlyMainScene, applyModifiers)
cutils.Debug.Debug('Time to process and save data: %.1f' \
% CalcElapsedTime(startTime), 'FEEDBACK')
# Redraw all 3D windows.
Blender.Window.RedrawAll()
Blender.Draw.PupMenu(importExportText + " Successful %t")
except:
Blender.Draw.PupMenu(importExportText + "ing failed%t | Check the console for more info")
raise # throw the exception
cutils.Debug.Debug('FINISHED - time elapsed: %.1f' % CalcElapsedTime(startTime), \
'FEEDBACK')
# Hide the wait cursor in blender
Blender.Window.WaitCursor(0)
if evt == 4:
Blender.Draw.Exit()
valsLoaded = False
elif evt == 6: # Toggle Triangles
if toggleTriangles.val:
togglePolygons.val = 0
Blender.Draw.Redraw(1)
elif evt == 7: # Toggle Polygons
if togglePolygons.val:
toggleTriangles.val = 0
Blender.Draw.Redraw(1)
elif evt == 9: # Toggle Create new Scene
if toggleNewScene.val:
toggleClearScene.val = 0
checkImportButtons = True
elif evt == 10: # Toggle Clear current Scene
if toggleClearScene.val:
toggleNewScene.val = 0
checkImportButtons = True
elif evt == 17: # Toggle Only Main Scene
checkImportButtons = True
if checkImportButtons:
if not toggleOnlyMainScene.val:
if not toggleClearScene.val and not toggleNewScene.val:
toggleNewScene.val = True
Blender.Draw.Redraw(1)

View File

@@ -0,0 +1,404 @@
# --------------------------------------------------------------------------
# Illusoft Collada 1.4 plugin for Blender
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Illusoft - colladablender@illusoft.com
# 2008.05.08 modif. for debug mode by migius (AKA Remigiusz Fiedler)
#
# 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.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import sys
import os
import Blender
from Blender.Mathutils import *
import string
'''
Translation map.
Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
included. Look at the IDREF XSD declaration for more.
Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars,
like special chars (e.g. micro sign), umlauts and so on.
The COLLADA spec also allows additional chars for member access ('.'), these
must obviously be removed too, otherwise they would be heavily misinterpreted.
'''
translateMap = "" + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(45) + chr(95) + chr(95) + \
chr(48) + chr(49) + chr(50) + chr(51) + chr(52) + chr(53) + chr(54) + chr(55) + \
chr(56) + chr(57) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(65) + chr(66) + chr(67) + chr(68) + chr(69) + chr(70) + chr(71) + \
chr(72) + chr(73) + chr(74) + chr(75) + chr(76) + chr(77) + chr(78) + chr(79) + \
chr(80) + chr(81) + chr(82) + chr(83) + chr(84) + chr(85) + chr(86) + chr(87) + \
chr(88) + chr(89) + chr(90) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(97) + chr(98) + chr(99) + chr(100) + chr(101) + chr(102) + chr(103) + \
chr(104) + chr(105) + chr(106) + chr(107) + chr(108) + chr(109) + chr(110) + chr(111) + \
chr(112) + chr(113) + chr(114) + chr(115) + chr(116) + chr(117) + chr(118) + chr(119) + \
chr(120) + chr(121) + chr(122) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(183) + \
chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + chr(95) + \
chr(192) + chr(193) + chr(194) + chr(195) + chr(196) + chr(197) + chr(198) + chr(199) + \
chr(200) + chr(201) + chr(202) + chr(203) + chr(204) + chr(205) + chr(206) + chr(207) + \
chr(208) + chr(209) + chr(210) + chr(211) + chr(212) + chr(213) + chr(214) + chr(95) + \
chr(216) + chr(217) + chr(218) + chr(219) + chr(220) + chr(221) + chr(222) + chr(223) + \
chr(224) + chr(225) + chr(226) + chr(227) + chr(228) + chr(229) + chr(230) + chr(231) + \
chr(232) + chr(233) + chr(234) + chr(235) + chr(236) + chr(237) + chr(238) + chr(239) + \
chr(240) + chr(241) + chr(242) + chr(243) + chr(244) + chr(245) + chr(246) + chr(95) + \
chr(248) + chr(249) + chr(250) + chr(251) + chr(252) + chr(253) + chr(254) + chr(255)
#---Classes---
class Debug(object):
__debugLevels = ['ALL','DEBUG','FEEDBACK','WARNING','ERROR','NONE']
# the current debugLevel
debugLevel = 'ALL'
# Method: Debug a message
def Debug(message, level):
#print 'deb:', level, message #deb--------
currentLevelIndex = Debug.__debugLevels.index(Debug.debugLevel)
if str(level).isdigit() and level >= currentLevelIndex:
print Debug.__debugLevels[level] + ': ' + message
else:
try:
i = Debug.__debugLevels.index(level)
if i >= currentLevelIndex :
print level + ': ' + str(message)
except:
print 'exception in cutils.py-Debug()'
pass
# make Debug a static method
Debug = staticmethod(Debug)
# Method: Set the Debug Level
def SetLevel(level):
try:
Debug.__debugLevels.index(level)
Debug.debugLevel = level
return True
except:
Debug('Debuglevel not available','WARNING')
return False
# Make SetLevel a static method
SetLevel = staticmethod(SetLevel)
#---Functions----
angleToRadian = 3.1415926 / 180.0
radianToAngle = 180.0 / 3.1415926
# Convert a string to a float if the value exists
def ToFloat(val):
if val is None or val == '':
return None
else:
return float(val)
# Convert a string to a int if the value exists
def ToInt(val):
if val is None or val == '':
return None
else:
return int(val)
# Convert a string to a list of 3 floats e.g '1.0 2.0 3.0' -> [1.0, 2.0, 3.0]
def ToFloat3(stringValue):
if stringValue is None:
return None
split = stringValue.split( )
return [ float( split[ 0 ] ), float( split[ 1 ] ), float( split[ 2 ] ) ]
# Convert a string to a list of 2 floats e.g '1.0 2.0' -> [1.0, 2.0]
def ToFloat2(stringValue, errorText=''):
if stringValue is None:
return None
split = stringValue.split( )
try:
return [ float( split[ 0 ] ), float( split[ 1 ] )]
except IndexError:
print 'Error: ' + errorText
raise
def CreateRelativePath(basePath, filePath):
if basePath is None or basePath is '' or filePath is None or filePath is '':
return ''
try:
if not Blender.sys.exists(filePath):
return ''
except TypeError:
return ''
basePathAr = basePath.lower().split(Blender.sys.sep)
filePathAr = filePath.lower().split(Blender.sys.sep)
filePathLength = len(filePathAr)
if not basePathAr[0] == filePathAr[0]: # Files must have the same root.
return filePath
result = ''
equalIndex = -1
for i in range(len(basePathAr)-1):
if basePathAr[i] == filePathAr[i]:
pass
else:
if equalIndex == -1:
equalIndex = i
result += '..'+ Blender.sys.sep
if equalIndex == -1:
equalIndex = len(basePathAr)-1
for i in range(equalIndex, filePathLength):
result += filePathAr[i]
if not i == filePathLength-1:
result += Blender.sys.sep
return result
def ToList(var):
result = []
if var is None:
return result
split = var.split( )
for i in split:
result.append(i)
return result
# Convert a string or list to a list of floats
def ToFloatList(var):
result = []
if var is None:
return result
if type(var) == list:
for i in var:
result.append(float(i))
else:
split = var.split( )
for i in split:
result.append(float(i))
return result
def ToIntList(lst):
result = []
if lst is None:
return result
if type(lst) == list:
for i in lst:
result.append(int(i))
else:
split = lst.split( )
for i in split:
result.append(int(i))
return result
def ToBoolList(lst):
result = []
if lst is None:
return result
for i in lst:
result.append(bool(i))
return result
# Convert a string to a list of 4 floats e.g '1.0 2.0 3.0 4.0' -> [1.0, 2.0, 3.0, 4.0]
def ToFloat4(stringValue):
split = stringValue.split( )
return [ float( split[ 0 ] ), float( split[ 1 ] ), float( split[ 2 ] ) , float( split[3])]
def ToFloat7(stringValue):
data = stringValue.split( )
return [ float(data[0]), float(data[1]), float(data[2]), float(data[3]), float(data[4]), float(data[5]), float(data[6])]
def AddVec3( vector1, vector2 ):
vector1.x += vector2.x
vector1.y += vector2.y
vector1.z += vector2.z
def ToMatrix4( matrixElement ):
if matrixElement is None:
return None
if not isinstance(matrixElement,list):
data = matrixElement.split( )
vec1 = [ float(data[0]), float(data[4]), float(data[8]), float(data[12]) ]
vec2 = [ float(data[1]), float(data[5]), float(data[9]), float(data[13]) ]
vec3 = [ float(data[2]), float(data[6]), float(data[10]), float(data[14]) ]
vec4 = [ float(data[3]), float(data[7]), float(data[11]), float(data[15]) ]
else:
vec1 = matrixElement[0:4]
vec2 = matrixElement[4:8]
vec3 = matrixElement[8:12]
vec4 = matrixElement[12:16]
return Blender.Mathutils.Matrix( vec1, vec2, vec3, vec4 )
def ToMatrix3(matrixElement):
data = matrixElement.split( )
vec1 = [ float(data[0]), float(data[3]), float(data[6]) ]
vec2 = [ float(data[1]), float(data[4]), float(data[7])]
vec3 = [ float(data[2]), float(data[5]), float(data[8])]
return Blender.Mathutils.Matrix( vec1, vec2, vec3)
def GetVector3( element ):
value = [ float( element[ 0 ] ), float( element[ 1 ] ), float( element[ 2 ] ) ]
return Blender.Mathutils.Vector( value )
def GetEuler( rotateElement ):
euler = [ float( rotateElement[ 0 ] ) * float( rotateElement[ 3 ] ) * angleToRadian,
float( rotateElement[ 1 ] ) * float( rotateElement[ 3 ] ) * angleToRadian,
float( rotateElement[ 2 ] ) * float( rotateElement[ 3 ] ) * angleToRadian ]
return Blender.Mathutils.Euler( euler )
def AddEuler(euler1, euler2):
euler1.x += euler2.x
euler1.y += euler2.y
euler1.z += euler2.z
# Clear the console
def ClearConsole():
if sys.platform == 'linux-i386' or sys.platform == 'linux2':
sysCommand = 'clear'
elif sys.platform == 'win32' or sys.platform == 'dos' or sys.platform[0:5] == 'ms-dos' :
sysCommand = 'cls'
else :
sysCommand = 'unknown'
if sysCommand != 'unknown':
os.system(sysCommand)
def MatrixToString(mat, nDigits):
result = ''
if mat is None:
return result
for vec in mat:
result += '\n\t'
for i in vec:
result += str(round(i, nDigits))+' '
return result+'\n'
def MatrixToList(mat):
result = []
for vec in mat:
result.extend(list(vec))
return result
def RoundList(lst, nDigits):
result = []
for i in lst:
val = round(i, nDigits)
if val < (1.0 / 10**nDigits):
val = 0
result.append(round(i, nDigits))
return result
def ListToString(lst, nDigits = 5):
val = ''
if lst is None:
return val
else:
for i in lst:
if type(i) == list:
val += ListToString(i)+'\n'
elif isinstance(i, float):
f = '%.'+str(nDigits)+'f '
val += f % i
else:
val += str(i)+' '
return val[:-1]
def GetValidFilename(filename):
filename = Blender.sys.expandpath( filename )
filename = filename.replace( "//", "/" )
filename = filename.replace( Blender.sys.sep, "/" )
return "file://" + filename
def GetColumnVector(matrix, colNumber, rowCount):
if rowCount == 4:
return Vector(matrix[0][colNumber], matrix[1][colNumber], matrix[2][colNumber], matrix[3][colNumber])
else:
return Vector(matrix[0][colNumber], matrix[1][colNumber], matrix[2][colNumber])
def PrintTransforms(matrix, name):
print "\n",name, "matrix\n", matrix
newMat = Matrix(matrix).transpose()
print name,"loc: ", newMat.translationPart()
print name,"euler: ", newMat.toEuler()
print name,"scale: ", newMat.scalePart()
def MakeIDXMLConform(id):
'''
Make the name/id COLLADA XML/XSD conform.
See StripString and translateMap docu for more information.
'''
if (len(id) > 0 and id[0] == '#'):
return '#' + string.translate(id[1:], translateMap)
else:
return string.translate(id, translateMap)
def AdjustName(adjustedName):
'''
Make the name/id COLLADA XML/XSD conform.
See StripString and translateMap docu for more information.
'''
if len(adjustedName) > 0 and not adjustedName[0].isalpha():
adjustedName = "i"+adjustedName
return MakeIDXMLConform(adjustedName)
'''
List of error IDs and common strings.
'''
# Expects 1 argument: The mesh name.
# Means that the armature modifier for a mesh couldn't be found,
# probably the parenting is wrong.
ERROR_MESH_ARMATURE_PARENT = 1
MSG_ERROR_FATAL = "Fatal error. Exit script."
def HandleError(failureId, *args):
'''
Prints the error message belonging to the given Id.
May raise an exception if it's a fatal error.
'''
if (failureId == ERROR_MESH_ARMATURE_PARENT):
print("Can't read armature modifier for mesh %s.\n" \
"Most likely your armature isn't correctly parenting the mesh.\n" \
% args[0])
raise MSG_ERROR_FATAL
else:
print("Wrong failure id: %i" % failureId)

View File

@@ -0,0 +1,305 @@
# --------------------------------------------------------------------------
# Illusoft Collada 1.4 plugin for Blender
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Illusoft - colladablender@illusoft.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,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import Blender
import collada
from Blender.Mathutils import *
debprn = 0 #False #--- print debug "print 'deb: ..."
class Armature(object):
# static vars
# A list of all created armatures
_armatures = dict()
def __init__(self, armatureBObject, daeNode):
self.armatureBObject = armatureBObject
self.blenderArmature = Blender.Armature.New()
self.armatureBObject.link(self.blenderArmature)
print self.armatureBObject
self.boneInfos = dict()
self.rootBoneInfos = dict()
# The real blender name of this armature
self.realName = None
self.deaNode = daeNode
def GetBlenderObject(self):
return self.armatureBObject
def GetBlenderArmature(self):
return self.blenderArmature
def HasBone(self, boneName):
return boneName in self.boneInfos
def AddNewBone(self, boneName, parentBoneName, daeNode):
# Create a new Editbone.
editBone = Blender.Armature.Editbone()
# Add the bone to the armature
self.blenderArmature.bones[boneName] = editBone
# Get the boneInfo for the parent of this bone. (if it exists)
parentBoneInfo = None
if not parentBoneName is None and parentBoneName in self.boneInfos:
parentBoneInfo = self.boneInfos[parentBoneName]
# Create a new boneInfo object
boneInfo = BoneInfo(boneName, parentBoneInfo, self, daeNode)
# Store the boneInfo object in the boneInfos collection of this armature.
self.boneInfos[boneName] = boneInfo
# If this bone has a parent, set it.
if not parentBoneName is None and parentBoneName in self.boneInfos:
parentBoneInfo = self.boneInfos[parentBoneName]
parentBoneInfo.childs[boneName] = boneInfo
editBone.parent = self.GetBone(parentBoneName)
##boneInfo.SetConnected()
else:
self.rootBoneInfos[boneName] = boneInfo
return boneInfo
def MakeEditable(self,makeEditable):
if makeEditable:
self.GetBlenderArmature().makeEditable()
else:
self.GetBlenderArmature().update()
def GetBone(self, boneName):
if boneName is None or not (boneName in self.blenderArmature.bones.keys()):
return None
else:
return self.blenderArmature.bones[boneName]
# Get the location of the armature (VECTOR)
def GetLocation(self):
return Vector(self.armatureBObject.loc).resize4D()
def GetTransformation(self):
return self.armatureBObject.matrix
def GetBoneInfo(self, boneName):
if boneName is None:
return None
else:
return self.boneInfos[boneName]
def GetBoneInfoFromJoint(self, jointName):
for boneInfo in self.boneInfos:
if boneInfo.jointName == jointName:
return boneInfo
return None
def GetJointList(self):
result = dict()
for boneInfo in self.boneInfos.values():
result[boneInfo.GetJointName()] = boneInfo
return result
#---CLASSMETHODS
# Factory method
def CreateArmature(cls,objectName,armatureName, realArmatureName, daeNode):
armatureBObject = armature_obj = Blender.Object.New ('Armature', objectName)
armatureBObject.name = str(realArmatureName)
armature = Armature(armatureBObject, daeNode)
armature.name = armatureName
cls._armatures[armatureName] = armature
return armature
CreateArmature = classmethod(CreateArmature)
def GetArmature(cls, armatureName):
return cls._armatures.setdefault(armatureName)
GetArmature = classmethod(GetArmature)
def FindArmatureWithJoint(cls, jointName):
for armature in cls._armatures.values():
jointList = armature.GetJointList()
if jointName in jointList:
return armature
return None
FindArmatureWithJoint = classmethod(FindArmatureWithJoint)
class BoneInfo(object):
def __init__(self, boneName, parentBoneInfo, armature, daeNode):
if debprn: print 'deb:class BoneInfo_INITIALIZE............' #--------
if debprn: print 'deb: boneName=', boneName #--------
if debprn: print 'deb: parentBoneInfo=', #--------
if parentBoneInfo: print parentBoneInfo.name #, parentBoneInfo #--------
else: print parentBoneInfo #--------
#if debprn: print 'deb: armature=', #--------
#if armature: print armature.name #, armature #--------
#else: print armature, #--------
self.name = boneName
self.parent = parentBoneInfo
self.armature = armature
self.childs = dict()
self.daeNode = daeNode
self.headTransformMatrix = None
self.tailTransformMatrix = None
self.localTransformMatrix = Matrix()
self.worldTransformMatrix = Matrix()
def GetBone(self):
return self.armature.GetBone(self.name)
def SetTail(self, tailLocVector):
if len(tailLocVector) == 4:
tailLocVector.resize3D()
self.GetBone().tail = tailLocVector
def GetTail(self):
return self.GetBone().tail
def SetHead(self, headLocVector):
if len(headLocVector) == 4:
headLocVector.resize3D()
self.GetBone().head = headLocVector
def GetHead(self):
return self.GetBone().head
def SetConnected(self):
self.GetBone().options = Blender.Armature.CONNECTED
def IsEnd(self):
return len(self.childs) == 0
def IsRoot(self):
return self.parent is None
def GetTailName(self):
return self.daeNode.name
def GetJointName(self):
return self.name
## if not self.parent is None:
## return self.parent.name
## else:
## return self.armature.name
class AnimationInfo(object):
_animations = dict()
def __init__(self, nodeId):
self.nodeId = nodeId
self.times = dict()
def GetTypes(self, daeNode):
types = []
if len(self.times) > 0:
for target in self.times.values()[0]:
ta = self.GetType(daeNode, target)
if ta[0] == collada.DaeSyntax.TRANSLATE and not Blender.Object.Pose.LOC in types:
types.append(Blender.Object.Pose.LOC)
elif ta[0] == collada.DaeSyntax.ROTATE and not Blender.Object.Pose.ROT in types:
types.append(Blender.Object.Pose.ROT)
#TODO: check if scale correct implemented
elif ta[0] == collada.DaeSyntax.SCALE and not Blender.Object.Pose.SCALE in types:
types.append(Blender.Object.Pose.SCALE)
return types
def GetType(self, daeNode, target):
ta = target.split('.', 1)
for t in daeNode.transforms:
if t[2] == ta[0]:
return [t[0], ta]
def CreateAnimations(cls, animationsLibrary, fps, axiss):
for daeAnimation in animationsLibrary.daeLibrary.items:
for channel in daeAnimation.channels:
# Get the id of the node
targetArray = channel.target.split("/", 1)
nodeId = targetArray[0]
targetId = targetArray[1]
# Get the animationInfo object for this node (or create a new one)
animation = cls._animations.setdefault(nodeId, AnimationInfo(nodeId))
#if debprn: print 'deb:helperObj.py:class AnimationInfo CreateAnimations() dir(animation)', dir(animation) #----------
# loop trough all samplers
sampler = None
if debprn: print 'deb:helperObj.py:class AnimationInfo CreateAnimations() \ndeb: channel.source= ', channel.source #----------
for s in daeAnimation.samplers:
#if debprn: print 'deb: sampler.id = ', s.id #----------
#if debprn: print 'deb: channel.source[1:]= ', channel.source[1:] #----------
#org if s.id == channel.source[1:]:
if s.id == channel.source:
sampler = s
# Get the values for all the inputs
if not sampler is None:
input = sampler.GetInput("INPUT")
inputSource = daeAnimation.GetSource(input.source)
if inputSource.techniqueCommon.accessor.HasParam("TIME") and len(inputSource.techniqueCommon.accessor.params) == 1:
if debprn: print 'deb: DDDDD getting target' #----------
output = sampler.GetInput("OUTPUT")
outputSource = daeAnimation.GetSource(output.source)
outputAccessor = outputSource.techniqueCommon.accessor
accessorCount = outputAccessor.count
accessorStride = outputAccessor.stride
interpolations = sampler.GetInput("INTERPOLATION")
interpolationsSource = daeAnimation.GetSource(interpolations.source)
if 0: #because probably interpolationsAccessor is identical to outputAccessor
interpolationsAccessor = interpolationsSource.techniqueCommon.accessor
accessorCount = interpolationsAccessor.count
accessorStride = interpolationsAccessor.stride
if debprn: print 'deb: outputSource.source.data: ', outputSource.source.data #----------
#if debprn: print 'deb: dir(outputAccessor.params): ', dir(outputAccessor.params) #----------
#if debprn: print 'deb: dir(outputAccessor.params[0]): ', str(outputAccessor.params[0]) #----------
times = [x*fps for x in inputSource.source.data]
if debprn: print 'deb: times=', times #---------
for timeIndex in range(len(times)):
time = animation.times.setdefault(times[timeIndex], dict())
target = time.setdefault(targetId, dict())
#interp = time.setdefault(targetId, dict())
#if debprn: print 'deb: accessorStride=', accessorStride #---------
value = []
for j in range(accessorStride):
#if debprn: print 'deb: timeIndex,j,data=',timeIndex, j, outputSource.source.data[timeIndex*accessorStride + j] #---------
#if debprn: print 'deb: outputAccessor.params[j]=',outputAccessor.params[j] #---------
#target[outputAccessor.params[j]] = outputSource.source.data[timeIndex*accessorStride + j]
value.append(outputSource.source.data[timeIndex*accessorStride + j])
if debprn: print 'deb: value=', value #---------
target[outputAccessor.params[0]] = value
#interp[outputAccessor.params[j]] = interpolationsSource.source.data[timeIndex*accessorStride + j]
if debprn: print 'deb: time=', time #---------
if debprn: print 'deb: target=', target #---------
#if debprn: print 'deb:helperObj.py: X X X X X X X X X class AnimationInfo CreateAnimations() animation=', animation #----------
CreateAnimations = classmethod(CreateAnimations)
def GetAnimationInfo(cls, nodeId):
for animation in cls._animations.values():
if animation.nodeId == nodeId:
return animation
return None
GetAnimationInfo = classmethod(GetAnimationInfo)

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,183 @@
# --------------------------------------------------------------------------
# Illusoft Collada 1.4 plugin for Blender
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Illusoft - colladablender@illusoft.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,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
from datetime import *
from cutils import *
from xml.dom.minidom import *
debprn = False #--- print debug "print 'deb: ..."
#---XML Utils---
# Returns the first child of the specified type in node
def FindElementByTagName(parentNode, type):
child = parentNode.firstChild
while child != None:
if child.localName == type:
return child
child = child.nextSibling
## childs = parentNode.getElementsByTagName(type)
## if len(childs) > 0:
## return childs[0]
return None
def FindElementsByTagName(parentNode, type):
result = []
child = parentNode.firstChild
while child != None:
if child.localName == type:
result.append(child)
child = child.nextSibling
return result
def ReadAttribute(node,attributeName):
if node != None and attributeName != None:
attribute = node.getAttribute(attributeName)
return attribute
return None
def ReadContents(node):
if node != None:
child = node.firstChild
if child != None and child.nodeType == child.TEXT_NODE:
return child.nodeValue
return None
def ReadDateTime(node):
if node == None:
return None
return GetDateTime(ReadContents(node))
def RemoveWhiteSpace(parent):
for child in list(parent.childNodes):
if child.nodeType==child.TEXT_NODE and child.data.strip()=='':
parent.removeChild(child)
else:
RemoveWhiteSpace(child)
def RemoveWhiteSpaceNode(parent):
for child in list(parent.childNodes):
if child.nodeType == child.TEXT_NODE and child.data.strip()=='':
parent.removeChild(child)
return parent
def RemoveComments(parent):
for child in list(parent.childNodes):
if child.__class__.__name__ == "Comment":
parent.removeChild(child)
return parent
##def RemoveWhiteSpace(node):
## removeList = []
## for child in node.childNodes:
## if child.nodeType == child.TEXT_NODE and not child.data.strip():
## removeList.append(child)
## elif child.hasChildNodes():
## RemoveWhiteSpace(child)
##
## for node in removeList:
## node.parentNode.removeChild(node)
def GetDateTime(xmlvalue):
vals = xmlvalue.split('T')
datestr = vals[0]
timestr = vals[1]
date = datestr.split('-')
time = timestr.split(':')
time[2]=time[2].rstrip('Z')
return datetime(int(date[0]), int(date[1]), int(date[2]),int(time[0]), int(time[1]), int(float(time[2])))
def ToDateTime(val):
return '%s-%s-%sT%s:%s:%sZ'%(val.year,str(val.month).zfill(2),str(val.day).zfill(2), str(val.hour).zfill(2), str(val.minute).zfill(2),str(val.second).zfill(2))
def GetStringArrayFromNodes(xmlNodes):
vals = []
if xmlNodes == None:
return vals
for xmlNode in xmlNodes:
stringvals = ReadContents(xmlNode).split( )
for string in stringvals:
vals.append(string)
return vals
def GetListFromNodes(xmlNodes, cast=None):
result = []
if xmlNodes is None:
return result
for xmlNode in xmlNodes:
val = ReadContents(xmlNode).split( )
if cast == float:
val = ToFloatList(val)
elif cast == int:
val = ToIntList(val)
elif cast == bool:
val = ToBoolList(val)
result.append(val)
return result
def ToXml(xmlNode, indent='\t', newl='\n'):
return '<?xml version="1.0" encoding="utf-8"?>\n%s'%(__ToXml(xmlNode, indent,newl))
def __ToXml(xmlNode, indent='\t',newl='\n',totalIndent=''):
childs = xmlNode.childNodes
if len(childs) > 0:
attrs = ''
attributes = xmlNode.attributes
if attributes != None:
for attr in attributes.keys():
val = attributes[attr].nodeValue
attrs += ' %s="%s"'%(attr,val)
result = '%s<%s%s>'%(totalIndent,xmlNode.localName,attrs)
tempnewl = newl
tempTotIndent = totalIndent
for child in childs:
if child.nodeType == child.TEXT_NODE:
tempnewl = ''
tempTotIndent = ''
result += '%s%s'%(tempnewl,__ToXml(child, indent, newl, totalIndent+indent))
result += '%s%s</%s>'%(tempnewl,tempTotIndent,xmlNode.localName)
return result
else:
if xmlNode.nodeType == xmlNode.TEXT_NODE:
return xmlNode.toxml().replace('\n','\n'+totalIndent[:-1])
else:
return totalIndent+xmlNode.toxml()
def AppendChilds(xmlNode, syntax, lst):
if lst is None or syntax is None or xmlNode is None:
return
for i in lst:
el = Element(syntax)
text = Text()
text.data = ListToString(i)
el.appendChild(text)
xmlNode.appendChild(el)
return xmlNode

View File

@@ -0,0 +1,941 @@
# Default Doodad Set for Discombobulator
# by Evan J. Rosky, 2005
# GPL- http://www.gnu.org/copyleft/gpl.html
#
# $Id: defaultdoodads.py 5497 2005-10-11 19:05:56Z ianwill $
# --------------------------------------------------------------------------
# ***** 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)

View File

@@ -0,0 +1,282 @@
# 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],
}

View File

@@ -0,0 +1,880 @@
#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()

View File

@@ -0,0 +1,381 @@
"""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

View File

@@ -0,0 +1,229 @@
# 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, '')

View File

@@ -0,0 +1,355 @@
# $Id: meshtools.py 9294 2006-12-12 10:38:43Z campbellbarton $
#
# +---------------------------------------------------------+
# | 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]

View File

@@ -0,0 +1,506 @@
# -*- 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

View File

@@ -0,0 +1,452 @@
#----------------------------------------------
# (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')

View File

@@ -0,0 +1,363 @@
# -*- 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