Added research data, testing blender mesh generation
This commit is contained in:
@@ -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()
|
||||
'''
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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'
|
||||
]
|
||||
@@ -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
|
||||
|
||||
|
||||
318
src_research_readme/blender_2.43_scripts/bpymodules/BPyImage.py
Normal file
318
src_research_readme/blender_2.43_scripts/bpymodules/BPyImage.py
Normal 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.
|
||||
@@ -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));
|
||||
1326
src_research_readme/blender_2.43_scripts/bpymodules/BPyMesh.py
Normal file
1326
src_research_readme/blender_2.43_scripts/bpymodules/BPyMesh.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
108
src_research_readme/blender_2.43_scripts/bpymodules/BPyObject.py
Normal file
108
src_research_readme/blender_2.43_scripts/bpymodules/BPyObject.py
Normal 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
|
||||
|
||||
|
||||
@@ -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
|
||||
633
src_research_readme/blender_2.43_scripts/bpymodules/BPyRender.py
Normal file
633
src_research_readme/blender_2.43_scripts/bpymodules/BPyRender.py
Normal 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
|
||||
|
||||
@@ -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.
|
||||
@@ -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 '================================================'
|
||||
206
src_research_readme/blender_2.43_scripts/bpymodules/BPyWindow.py
Normal file
206
src_research_readme/blender_2.43_scripts/bpymodules/BPyWindow.py
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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],
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
381
src_research_readme/blender_2.43_scripts/bpymodules/dxfReader.py
Normal file
381
src_research_readme/blender_2.43_scripts/bpymodules/dxfReader.py
Normal 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
|
||||
@@ -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, '')
|
||||
|
||||
|
||||
355
src_research_readme/blender_2.43_scripts/bpymodules/meshtools.py
Normal file
355
src_research_readme/blender_2.43_scripts/bpymodules/meshtools.py
Normal 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]
|
||||
|
||||
@@ -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
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
1651
src_research_readme/blender_2.43_scripts/bpymodules/paths_svg2obj.py
Normal file
1651
src_research_readme/blender_2.43_scripts/bpymodules/paths_svg2obj.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user