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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Luc Peurière <jlp@nerim.net>2008-03-14 02:54:02 +0300
committerJean-Luc Peurière <jlp@nerim.net>2008-03-14 02:54:02 +0300
commita68a7f42b02ad0260220d94f36ab61c772db071a (patch)
tree620b763cd24fbfc1259f00ccb005217914af0c6f /release
parent526d0bec4722900a86d81ff0f5d71504b2b4ad8c (diff)
parent15215493bf9d1d08e650109e6eb6189fc76e289e (diff)
resolved conflict state with HEAD r14096
blenderbuttons still bad not let this compile
Diffstat (limited to 'release')
-rw-r--r--release/Makefile105
-rw-r--r--release/datafiles/preview.blendbin459544 -> 433792 bytes
-rw-r--r--release/datafiles/prviconsbin0 -> 13732 bytes
-rw-r--r--release/datafiles/splash.jpgbin0 -> 84581 bytes
-rwxr-xr-xrelease/getversion.py55
-rw-r--r--release/scripts/3ds_import.py15
-rw-r--r--release/scripts/DirectX8Importer.py231
-rw-r--r--release/scripts/ac3d_import.py2
-rw-r--r--release/scripts/add_mesh_empty.py13
-rw-r--r--release/scripts/add_mesh_torus.py9
-rw-r--r--release/scripts/bpymodules/BPyMesh.py2
-rw-r--r--release/scripts/bpymodules/BPyMessages.py2
-rw-r--r--release/scripts/bpymodules/BPyObject.py2
-rw-r--r--release/scripts/bpymodules/BPyRender.py135
-rw-r--r--release/scripts/bpymodules/blend2renderinfo.py95
-rw-r--r--release/scripts/bpymodules/paths_ai2obj.py10
-rw-r--r--release/scripts/bpymodules/paths_gimp2obj.py4
-rw-r--r--release/scripts/bvh_import.py4
-rw-r--r--release/scripts/console.py35
-rw-r--r--release/scripts/export_fbx.py2352
-rw-r--r--release/scripts/export_m3g.py39
-rw-r--r--release/scripts/export_mdd.py3
-rw-r--r--release/scripts/export_obj.py198
-rw-r--r--release/scripts/flt_defaultp.py1
-rw-r--r--[-rwxr-xr-x]release/scripts/flt_export.py1501
-rw-r--r--release/scripts/flt_filewalker.py9
-rw-r--r--[-rwxr-xr-x]release/scripts/flt_import.py1585
-rw-r--r--release/scripts/flt_palettemanager.py388
-rw-r--r--release/scripts/flt_properties.py619
-rw-r--r--release/scripts/flt_toolbar.py654
-rw-r--r--release/scripts/image_auto_layout.py57
-rw-r--r--release/scripts/image_billboard.py142
-rw-r--r--release/scripts/image_find_paths.py167
-rw-r--r--release/scripts/import_dxf.py8089
-rw-r--r--release/scripts/import_mdd.py12
-rw-r--r--release/scripts/import_obj.py5
-rw-r--r--release/scripts/lightwave_import.py193
-rw-r--r--release/scripts/mesh_edges2curves.py12
-rw-r--r--release/scripts/mesh_skin.py2
-rw-r--r--release/scripts/mesh_unfolder.py194
-rw-r--r--release/scripts/mesh_wire.py27
-rw-r--r--release/scripts/object_drop.py5
-rw-r--r--release/scripts/object_find.py35
-rw-r--r--[-rwxr-xr-x]release/scripts/object_random_loc_sz_rot.py65
-rw-r--r--release/scripts/object_timeofs_follow_act.py107
-rw-r--r--release/scripts/ply_export.py15
-rw-r--r--release/scripts/ply_import.py8
-rw-r--r--release/scripts/render_save_layers.py116
-rw-r--r--release/scripts/save_theme.py6
-rw-r--r--release/scripts/scripttemplate_mesh_edit.py1
-rw-r--r--release/scripts/scripttemplate_pyconstraint.py114
-rw-r--r--release/scripts/uv_export.py64
-rw-r--r--release/scripts/uv_seams_from_islands.py7
-rw-r--r--release/scripts/uvcalc_follow_active_coords.py12
-rw-r--r--release/scripts/uvcalc_from_adjacent.py129
-rw-r--r--release/scripts/uvcalc_lightmap.py15
-rw-r--r--release/scripts/uvcalc_quad_clickproj.py11
-rw-r--r--release/scripts/uvcalc_smart_project.py3
-rw-r--r--release/scripts/vertexpaint_selfshadow_ao.py11
-rw-r--r--release/scripts/vrml97_export.py8
-rw-r--r--release/scripts/weightpaint_average.py121
-rw-r--r--release/scripts/weightpaint_invert.py95
-rw-r--r--release/scripts/weightpaint_normalize.py126
-rw-r--r--release/scripts/wizard_curve2tree.py4007
-rw-r--r--release/scripts/x3d_export.py12
-rw-r--r--release/windows/installer/00.sconsblender.nsi41
66 files changed, 17449 insertions, 4653 deletions
diff --git a/release/Makefile b/release/Makefile
index 2791982a6fa..fa288314f03 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -31,54 +31,63 @@
include nan_definitions.mk
-export VERSION := $(shell cat VERSION)
+export VERSION := $(shell ./getversion.py)
-BLENDNAME=blender-$(VERSION)-$(CONFIG_GUESS)$(TYPE)
+BLENDNAME=blender-$(VERSION)-$(CONFIG_GUESS)-py$(NAN_PYTHON_VERSION)$(TYPE)
export DISTDIR=$(NAN_OBJDIR)/$(BLENDNAME)
export CONFDIR=$(DISTDIR)/.blender
+ifeq ($(OS),beos)
+ TAR="zip"
+ TARFLAGS="-ry9"
+ EXT0=""
+ EXT1=".zip"
+ COMPRESS=""
+ EXT2=""
+ NOPLUGINS?=true
+endif
+
+ifeq ($(OS),$(findstring $(OS), "freebsd irix linux openbsd solaris"))
+ TAR="tar"
+ TARFLAGS="cf"
+ EXT0=""
+ EXT1=".tar"
+ COMPRESS="bzip2"
+ COMPRESSFLAGS="-f"
+ EXT2=".bz2"
+ ifeq ($(OS), solaris)
+ ifeq ($(CPU), i386)
+ NOPLUGINS?=true
+ endif
+ endif
+endif
+
+ifeq ($(OS),windows)
+ TAR="zip"
+ TARFLAGS="-r9"
+ EXT0=".exe"
+ EXT1=".zip"
+ NOPLUGINS?=true
+ NOSTRIP?=true
+endif
+
+ifeq ($(OS),darwin)
+ TAR="tar"
+ TARFLAGS="cf"
+ EXT0=".app"
+ EXT1=".tar"
+ COMPRESS="bzip2"
+ COMPRESSFLAGS="-f"
+ EXT2=".bz2"
+endif
release: all
all:
- ifeq ($(OS),beos)
- @$(MAKE) pkg TYPE="" TAR="zip -ry9" EXT1=".zip" NOPLUGINS="true"
- endif
- ifeq ($(OS),freebsd)
- @$(MAKE) pkg TYPE="" TAR="tar cf" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- endif
- ifeq ($(OS),irix)
- @$(MAKE) pkg TYPE="" TAR="tar cf" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- endif
- ifeq ($(OS),linux)
- ifeq ($(CPU),alpha)
- @$(MAKE) pkg TYPE="" TAR="tar cf" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- else
- @$(MAKE) pkg TYPE="" TAR="tar cf" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- @$(MAKE) pkg TYPE="-static" TAR="tar cf" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- endif
- endif
- ifeq ($(OS),openbsd)
- @$(MAKE) pkg TYPE="-static" TAR="tar cf" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- endif
- ifeq ($(OS),solaris)
- @$(MAKE) pkg TYPE="" TAR="tar cf" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- endif
- ifeq ($(OS),windows)
- @$(MAKE) pkg TYPE="" TAR="zip -r9" EXT0=".exe" EXT1=".zip" \
- NOPLUGINS="true" NOSTRIP="true"
- endif
- ifeq ($(OS),darwin)
- @$(MAKE) pkg TYPE="" TAR="tar cf" EXT0"=.app" EXT1=".tar" \
- COMPRESS="bzip2 -f" EXT2=".bz2"
- endif
+ @$(MAKE) pkg TYPE=""
+ifeq ($(WITH_BF_STATICOPENGL), true)
+ @$(MAKE) pkg TYPE="-static"
+endif
# OS independent targets below:
@@ -112,8 +121,9 @@ install: package
ifneq ($(OS), darwin)
@[ ! -d $(OCGDIR)/bin/.blender ] || \
cp -r $(OCGDIR)/bin/.blender $(DISTDIR)
- cp $(NANBLENDERHOME)/bin/.blender/.Blanguages $(CONFDIR)
- cp $(NANBLENDERHOME)/bin/.blender/.bfont.ttf $(CONFDIR)
+ @rm -rf $(DISTDIR)/.svn $(DISTDIR)/*/.svn $(DISTDIR)/*/*/.svn
+ @cp $(NANBLENDERHOME)/bin/.blender/.Blanguages $(CONFDIR)
+ @cp $(NANBLENDERHOME)/bin/.blender/.bfont.ttf $(CONFDIR)
endif
@echo "----> Copy blender$(EXT0) executable"
ifeq ($(TYPE),-static)
@@ -137,7 +147,7 @@ ifneq ($(NOPLUGINS),true)
@cp ../source/blender/blenpluginapi/*.h $(DISTDIR)/plugins/include/
@chmod 755 $(DISTDIR)/plugins/bmake
@$(MAKE) -C $(DISTDIR)/plugins all > /dev/null || exit 1;
- @rm -fr $(DISTDIR)/plugins/CVS $(DISTDIR)/plugins/*/CVS \
+ @rm -fr $(DISTDIR)/plugins/.svn $(DISTDIR)/plugins/*/.svn \
$(DISTDIR)/plugins/*/*.o
#on OS X the plugins move to the installation directory
@@ -151,7 +161,7 @@ endif
@echo "----> Copy python infrastructure"
@[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts
- @[ ! -d $(CONFDIR)/scripts ] || rm -fr $(CONFDIR)/scripts/CVS
+ @[ ! -d $(CONFDIR)/scripts ] || rm -fr $(CONFDIR)/scripts/.svn $(CONFDIR)/scripts/*/.svn $(CONFDIR)/scripts/*/*/.svn
ifeq ($(OS),darwin)
@echo "----> Move .blender to .app/Contents/MacOS/"
@@ -178,12 +188,11 @@ pkg: install
@echo "----> Create distribution file $(BLENDNAME)$(EXT1)"
@#enable the next sleep if you get 'tar file changed while reading'
@#sleep 10
- @cd $(NAN_OBJDIR) && \
- rm -f $(VERSION)/$(BLENDNAME)$(EXT1)* && \
- $(TAR) $(VERSION)/$(BLENDNAME)$(EXT1) $(BLENDNAME)
+ rm -f $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)*
+ @cd $(NAN_OBJDIR) && $(TAR) $(TARFLAGS) $(VERSION)/$(BLENDNAME)$(EXT1) $(BLENDNAME)
ifdef COMPRESS
@echo "----> Compressing distribution to $(BLENDNAME)$(EXT1)$(EXT2)"
- @$(COMPRESS) $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)
+ @$(COMPRESS) $(COMPRESSFLAGS) $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)
endif
@#echo "****> Clean up temporary distribution directory"
@rm -fr $(DISTDIR)
diff --git a/release/datafiles/preview.blend b/release/datafiles/preview.blend
index 8d67a88f679..9e09d579b2b 100644
--- a/release/datafiles/preview.blend
+++ b/release/datafiles/preview.blend
Binary files differ
diff --git a/release/datafiles/prvicons b/release/datafiles/prvicons
new file mode 100644
index 00000000000..de3980f9676
--- /dev/null
+++ b/release/datafiles/prvicons
Binary files differ
diff --git a/release/datafiles/splash.jpg b/release/datafiles/splash.jpg
new file mode 100644
index 00000000000..243e779273d
--- /dev/null
+++ b/release/datafiles/splash.jpg
Binary files differ
diff --git a/release/getversion.py b/release/getversion.py
new file mode 100755
index 00000000000..a64a6189b6f
--- /dev/null
+++ b/release/getversion.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env 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.
+#
+# The Original Code is Copyright (C) 2008 by the Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+import sys, os, re
+
+nanblenderhome = os.getenv("NANBLENDERHOME");
+
+if nanblenderhome == None:
+ nanblenderhome = os.path.dirname(os.path.abspath(sys.argv[0]))+"/.."
+
+config = nanblenderhome+"/source/blender/blenkernel/BKE_blender.h"
+
+infile = open(config)
+
+major = None
+minor = None
+
+for line in infile.readlines():
+ m = re.search("#define BLENDER_VERSION\s+(\d+)", line)
+ if m:
+ major = m.group(1)
+ m = re.search("#define BLENDER_SUBVERSION\s+(\d+)", line)
+ if m:
+ minor = m.group(1)
+ if minor and major:
+ major = float(major) / 100.0
+ break
+
+infile.close()
+
+if minor and major:
+ print str(major)+"."+minor
+else:
+ print "unknownversion"
diff --git a/release/scripts/3ds_import.py b/release/scripts/3ds_import.py
index 56acc50e38d..07da4df1603 100644
--- a/release/scripts/3ds_import.py
+++ b/release/scripts/3ds_import.py
@@ -1,7 +1,7 @@
#!BPY
"""
Name: '3D Studio (.3ds)...'
-Blender: 241
+Blender: 244
Group: 'Import'
Tooltip: 'Import from 3DS file format (.3ds)'
"""
@@ -382,7 +382,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
# +1 because of DUMMYVERT
face_mapping= bmesh.faces.extend( [ [ bmesh_verts[ myVertMapping[vindex]+1] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces ], indexList=True )
- if contextMeshUV or img:
+ if bmesh.faces and (contextMeshUV or img):
bmesh.faceUV= 1
for ii, i in enumerate(faces):
@@ -945,6 +945,7 @@ if __name__=='__main__' and not DEBUG:
#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False)
#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False)
'''
+
else:
# DEBUG ONLY
TIME= Blender.sys.time()
@@ -956,6 +957,11 @@ else:
file= open('/tmp/temp3ds_list', 'r')
lines= file.readlines()
file.close()
+ # sort by filesize for faster testing
+ lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
+ lines_size.sort()
+ lines = [f[1] for f in lines_size]
+
def between(v,a,b):
if v <= max(a,b) and v >= min(a,b):
@@ -963,8 +969,8 @@ else:
return False
for i, _3ds in enumerate(lines):
- if between(i, 1,200):
- _3ds= _3ds[:-1]
+ if between(i, 650,800):
+ #_3ds= _3ds[:-1]
print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines)
_3ds_file= _3ds.split('/')[-1].split('\\')[-1]
newScn= Blender.Scene.New(_3ds_file)
@@ -972,4 +978,5 @@ else:
load_3ds(_3ds, False)
print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
+
''' \ No newline at end of file
diff --git a/release/scripts/DirectX8Importer.py b/release/scripts/DirectX8Importer.py
index 7e6a8429759..0dda654944d 100644
--- a/release/scripts/DirectX8Importer.py
+++ b/release/scripts/DirectX8Importer.py
@@ -2,7 +2,7 @@
""" Registration info for Blender menus:
Name: 'DirectX(.x)...'
-Blender: 240
+Blender: 244
Group: 'Import'
Tip: 'Import from DirectX text file format format.'
@@ -25,7 +25,7 @@ Tip: 'Import from DirectX text file format format.'
# Grab the latest version here :www.omariben.too.it
import bpy
import Blender
-from Blender import NMesh,Object,Material,Texture,Image,Draw
+from Blender import Mesh,Object,Material,Texture,Image,Draw
class xImport:
@@ -41,13 +41,16 @@ class xImport:
lines = self.lines
print "importing into Blender ..."
scene = bpy.data.scenes.active
- mesh = NMesh.GetRaw()
+
+ mesh_indicies = {} # the index of each 'Mesh' is used as the key for those meshes indicies
+ context_indicies = None # will raise an error if used!
+
+
#Get the line of Texture Coords
nr_uv_ind = 0
#Get Materials
nr_fac_mat = 0
- idx = 0
i = -1
mat_list = []
tex_list = []
@@ -56,31 +59,33 @@ class xImport:
l = line.strip()
words = line.split()
if words[0] == "Material" :
- idx += 1
- self.writeMaterials(j, idx, mat_list, tex_list)
+ #context_indicies["Material"] = j
+ self.loadMaterials(j, mat_list, tex_list)
elif words[0] == "MeshTextureCoords" :
- nr_uv_ind = j
+ context_indicies["MeshTextureCoords"] = j
+ #nr_uv_ind = j
elif words[0] == "MeshMaterialList" :
- nr_fac_mat = j + 2
+ context_indicies["MeshMaterialList"] = j+2
+ #nr_fac_mat = j + 2
elif words[0] == "Mesh": # Avoid a second loop
- mesh_line_indicies.append(j)
-
- #Create The Mesh
- for nr_vr_ind in mesh_line_indicies:
- self.writeVertices(nr_vr_ind, mesh, nr_uv_ind, nr_fac_mat, tex_list)
-
- mesh.setMaterials(mat_list)
- if nr_fac_mat:
- self.writeMeshMaterials(nr_fac_mat, mesh)
- NMesh.PutRaw(mesh,"Mesh",1)
-
+ context_indicies = mesh_indicies[j] = {'MeshTextureCoords':0, 'MeshMaterialList':0}
+
+ for mesh_index, value in mesh_indicies.iteritems():
+ mesh = Mesh.New()
+ self.loadVertices(mesh_index, mesh, value['MeshTextureCoords'], value['MeshMaterialList'], tex_list)
+
+ mesh.materials = mat_list[:16]
+ if value['MeshMaterialList']:
+ self.loadMeshMaterials(value['MeshMaterialList'], mesh)
+ scene.objects.new(mesh)
+
self.file.close()
print "... finished"
#------------------------------------------------------------------------------
# CREATE THE MESH
#------------------------------------------------------------------------------
- def writeVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list):
+ def loadVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list):
v_ind = nr_vr_ind + 1
lin = self.lines[v_ind]
if lin :
@@ -92,7 +97,6 @@ class xImport:
lin_c = self.CleanLine(lin)
nr_vert = int((lin_c.split()[0]))
- vx_array = range(v_ind + 1, (v_ind + nr_vert +1))
#--------------------------------------------------
nr_fac_li = v_ind + nr_vert +1
lin_f = self.lines[nr_fac_li]
@@ -105,136 +109,80 @@ class xImport:
lin_fc = self.CleanLine(lin_f)
nr_face = int((lin_fc.split()[0]))
- fac_array = range(nr_fac_li + 1, (nr_fac_li + nr_face + 1))
#Get Coordinates
- for l in vx_array:
+ verts_list = [(0,0,0)] # WARNING - DUMMY VERT - solves EEKADOODLE ERROR
+ for l in xrange(v_ind + 1, (v_ind + nr_vert +1)):
line_v = self.lines[l]
lin_v = self.CleanLine(line_v)
words = lin_v.split()
if len(words)==3:
- mesh.verts.append(NMesh.Vert(float(words[0]),float(words[1]),float(words[2])))
-
+ verts_list.append((float(words[0]),float(words[1]),float(words[2])))
+
+ mesh.verts.extend(verts_list)
+ del verts_list
+
+ face_list = []
#Make Faces
i = 0
mesh_verts = mesh.verts
- for f in fac_array:
+ for f in xrange(nr_fac_li + 1, (nr_fac_li + nr_face + 1)):
i += 1
line_f = self.lines[f]
lin_f = self.CleanLine(line_f)
+
+ # +1 for dummy vert only!
words = lin_f.split()
if len(words) == 5:
- f= NMesh.Face([\
- mesh_verts[int(words[1])],
- mesh_verts[int(words[2])],
- mesh_verts[int(words[3])],
- mesh_verts[int(words[4])]])
-
- mesh.faces.append(f)
- if nr_uv :
- uv = []
- #---------------------------------
- l1_uv = self.lines[nr_uv + 2 + int(words[1])]
- fixed_l1_uv = self.CleanLine(l1_uv)
- w1 = fixed_l1_uv.split()
- uv_1 = (float(w1[0]), -float(w1[1]))
- uv.append(uv_1)
- #---------------------------------
- l2_uv = self.lines[nr_uv + 2 + int(words[2])]
- fixed_l2_uv = self.CleanLine(l2_uv)
- w2 = fixed_l2_uv.split()
- uv_2 = (float(w2[0]), -float(w2[1]))
- uv.append(uv_2)
- #---------------------------------
- l3_uv = self.lines[nr_uv + 2 + int(words[3])]
- fixed_l3_uv = self.CleanLine(l3_uv)
- w3 = fixed_l3_uv.split()
- uv_3 = (float(w3[0]), -float(w3[1]))
- uv.append(uv_3)
- #---------------------------------
- l4_uv = self.lines[nr_uv + 2 + int(words[4])]
- fixed_l4_uv = self.CleanLine(l4_uv)
- w4 = fixed_l4_uv.split()
- uv_4 = (float(w4[0]), -float(w4[1]))
- uv.append(uv_4)
- #---------------------------------
- f.uv = uv
- if nr_fac_mat :
- fac_line = self.lines[nr_fac_mat + i]
- fixed_fac = self.CleanLine(fac_line)
- w_tex = int(fixed_fac.split()[0])
- name_tex = tex_list[w_tex]
- if name_tex :
- name_file = Blender.sys.join(my_path,name_tex)
- try:
- img = Image.Load(name_file)
- f.image = img
- except:
- #Draw.PupMenu("No image to load")
- #print "No image " + name_tex + " to load"
- pass
-
+ face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]), 1+int(words[4])))
elif len(words) == 4:
- f=NMesh.Face([\
- mesh_verts[int(words[1])],\
- mesh_verts[int(words[2])],\
- mesh_verts[int(words[3])]])
-
- mesh.faces.append(f)
- if nr_uv :
- uv = []
- #---------------------------------
- l1_uv = self.lines[nr_uv + 2 + int(words[1])]
- fixed_l1_uv = self.CleanLine(l1_uv)
- w1 = fixed_l1_uv.split()
- uv_1 = (float(w1[0]), -float(w1[1]))
- uv.append(uv_1)
- #---------------------------------
- l2_uv = self.lines[nr_uv + 2 + int(words[2])]
- fixed_l2_uv = self.CleanLine(l2_uv)
- w2 = fixed_l2_uv.split()
- uv_2 = (float(w2[0]), -float(w2[1]))
- uv.append(uv_2)
- #---------------------------------
- l3_uv = self.lines[nr_uv + 2 + int(words[3])]
- fixed_l3_uv = self.CleanLine(l3_uv)
- w3 = fixed_l3_uv.split()
- uv_3 = (float(w3[0]), -float(w3[1]))
- uv.append(uv_3)
- #---------------------------------
- f.uv = uv
- if nr_fac_mat :
- fac_line = self.lines[nr_fac_mat + i]
- fixed_fac = self.CleanLine(fac_line)
- w_tex = int(fixed_fac.split()[0])
- name_tex = tex_list[w_tex]
- if name_tex :
- name_file = Blender.sys.join(my_path ,name_tex)
- try:
- img = Image.Load(name_file)
- f.image = img
- except:
- #Draw.PupMenu("No image to load")
- #print "No image " + name_tex + " to load"
- pass
-
-
-
-
+ face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3])))
+
+ mesh.faces.extend(face_list)
+ del face_list
+
+ if nr_uv :
+ mesh.faceUV = True
+ for f in mesh.faces:
+ fuv = f.uv
+ for ii, v in enumerate(f):
+ # _u, _v = self.CleanLine(self.lines[nr_uv + 2 + v.index]).split()
+
+ # Use a dummy vert
+ _u, _v = self.CleanLine(self.lines[nr_uv + 1 + v.index]).split()
+
+ fuv[ii].x = float(_u)
+ fuv[ii].y = float(_v)
+
+ if nr_fac_mat :
+ fac_line = self.lines[nr_fac_mat + i]
+ fixed_fac = self.CleanLine(fac_line)
+ w_tex = int(fixed_fac.split()[0])
+ f.image = tex_list[w_tex]
+
+ # remove dummy vert
+ mesh.verts.delete([0,])
+
def CleanLine(self,line):
- fix_line = line.replace(";", " ")
- fix_1_line = fix_line.replace('"', ' ')
- fix_2_line = fix_1_line.replace("{", " ")
- fix_3_line = fix_2_line.replace("}", " ")
- fix_4_line = fix_3_line.replace(",", " ")
- fix_5_line = fix_4_line.replace("'", " ")
- return fix_5_line
+ return line.replace(\
+ ";", " ").replace(\
+ '"', ' ').replace(\
+ "{", " ").replace(\
+ "}", " ").replace(\
+ ",", " ").replace(\
+ "'", " ")
#------------------------------------------------------------------
# CREATE MATERIALS
#------------------------------------------------------------------
- def writeMaterials(self, nr_mat, idx, mat_list, tex_list):
- name = "Material_" + str(idx)
- mat = Material.New(name)
+ def loadMaterials(self, nr_mat, mat_list, tex_list):
+
+ def load_image(name):
+ try:
+ return Image.Load(Blender.sys.join(my_path,name))
+ except:
+ return None
+
+ mat = bpy.data.materials.new()
line = self.lines[nr_mat + 1]
fixed_line = self.CleanLine(line)
words = fixed_line.split()
@@ -244,35 +192,33 @@ class xImport:
l = self.lines[nr_mat + 5]
fix_3_line = self.CleanLine(l)
tex_n = fix_3_line.split()
-
+
if tex_n and tex_n[0] == "TextureFilename" :
if len(tex_n) > 1:
- tex_list.append(tex_n[1])
+ tex_list.append(load_image(tex_n[1]))
if len(tex_n) <= 1 :
l_succ = self.lines[nr_mat + 6]
fix_3_succ = self.CleanLine(l_succ)
tex_n_succ = fix_3_succ.split()
- tex_list.append(tex_n_succ[0])
+ tex_list.append(load_image(tex_n_succ[0]))
else :
- tex_name = None
- tex_list.append(tex_name)
+ tex_list.append(None) # no texture for this index
return mat_list, tex_list
#------------------------------------------------------------------
# SET MATERIALS
#------------------------------------------------------------------
- def writeMeshMaterials(self, nr_fc_mat, mesh):
+ def loadMeshMaterials(self, nr_fc_mat, mesh):
for face in mesh.faces:
nr_fc_mat += 1
line = self.lines[nr_fc_mat]
fixed_line = self.CleanLine(line)
wrd = fixed_line.split()
mat_idx = int(wrd[0])
- face.materialIndex = mat_idx
-
+ face.mat = mat_idx
#------------------------------------------------------------------
# MAIN
@@ -286,4 +232,7 @@ arg = __script__['arg']
if __name__ == '__main__':
Blender.Window.FileSelector(my_callback, "Import DirectX", "*.x")
-# my_callback('/directxterrain.x')
+
+#my_callback('/fe/x/directxterrain.x')
+#my_callback('/fe/x/Male_Normal_MAX.X')
+#my_callback('/fe/x/male_ms3d.x')
diff --git a/release/scripts/ac3d_import.py b/release/scripts/ac3d_import.py
index d538838fdf3..9a7004e4b4d 100644
--- a/release/scripts/ac3d_import.py
+++ b/release/scripts/ac3d_import.py
@@ -679,6 +679,8 @@ class AC3DImport:
baseimgname = bsys.basename(objtex)
if bsys.exists(objtex) == 1:
texfname = objtex
+ elif bsys.exists(bsys.join(self.importdir, objtex)):
+ texfname = bsys.join(self.importdir, objtex)
else:
if baseimgname.find('\\') > 0:
baseimgname = bsys.basename(objtex.replace('\\','/'))
diff --git a/release/scripts/add_mesh_empty.py b/release/scripts/add_mesh_empty.py
new file mode 100644
index 00000000000..537bd1e2c3d
--- /dev/null
+++ b/release/scripts/add_mesh_empty.py
@@ -0,0 +1,13 @@
+#!BPY
+"""
+Name: 'Empty mesh'
+Blender: 243
+Group: 'AddMesh'
+"""
+import BPyAddMesh
+import Blender
+
+def main():
+ BPyAddMesh.add_mesh_simple('EmptyMesh', [], [], [])
+
+main() \ No newline at end of file
diff --git a/release/scripts/add_mesh_torus.py b/release/scripts/add_mesh_torus.py
index de2db42d482..4f759256497 100644
--- a/release/scripts/add_mesh_torus.py
+++ b/release/scripts/add_mesh_torus.py
@@ -51,9 +51,9 @@ def main():
if not Draw.PupBlock('Add Torus', [\
('Major Radius:', PREF_MAJOR_RAD, 0.01, 100, 'Radius for the main ring of the torus'),\
- ('Minor Radius:', PREF_MINOR_RAD, 0.01, 100, 'Radius for the minor ring of the torus setting the thickness of the ring.'),\
- ('Major Segments:', PREF_MAJOR_SEG, 3, 256, 'Radius for the main ring of the torus'),\
- ('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Radius for the minor ring of the torus setting the thickness of the ring.'),\
+ ('Minor Radius:', PREF_MINOR_RAD, 0.01, 100, 'Radius for the minor ring of the torus setting the thickness of the ring'),\
+ ('Major Segments:', PREF_MAJOR_SEG, 3, 256, 'Number of segments for the main ring of the torus'),\
+ ('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Number of segments for the minor ring of the torus'),\
]):
return
@@ -61,4 +61,5 @@ def main():
BPyAddMesh.add_mesh_simple('Torus', verts, [], faces)
-main() \ No newline at end of file
+main()
+
diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py
index 70fc1a87a52..415c2a12c69 100644
--- a/release/scripts/bpymodules/BPyMesh.py
+++ b/release/scripts/bpymodules/BPyMesh.py
@@ -56,7 +56,7 @@ def meshWeight2List(me):
if not len_groupNames:
# no verts? return a vert aligned empty list
- return [[] for i in xrange(len(me.verts))]
+ return [[] for i in xrange(len(me.verts))], []
else:
vWeightList= [[0.0]*len_groupNames for i in xrange(len(me.verts))]
diff --git a/release/scripts/bpymodules/BPyMessages.py b/release/scripts/bpymodules/BPyMessages.py
index 0ff8e178ac1..8ee1aa6c707 100644
--- a/release/scripts/bpymodules/BPyMessages.py
+++ b/release/scripts/bpymodules/BPyMessages.py
@@ -11,6 +11,8 @@ 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):
diff --git a/release/scripts/bpymodules/BPyObject.py b/release/scripts/bpymodules/BPyObject.py
index 7de2c4113f9..54ff949218d 100644
--- a/release/scripts/bpymodules/BPyObject.py
+++ b/release/scripts/bpymodules/BPyObject.py
@@ -10,7 +10,7 @@ def getObjectArmature(ob):
arm = ob.parent
if arm and arm.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE:
- arm
+ return arm
for m in ob.modifiers:
if m.type== Blender.Modifier.Types.ARMATURE:
diff --git a/release/scripts/bpymodules/BPyRender.py b/release/scripts/bpymodules/BPyRender.py
index bb5ef628356..a83eb6a8de8 100644
--- a/release/scripts/bpymodules/BPyRender.py
+++ b/release/scripts/bpymodules/BPyRender.py
@@ -91,7 +91,7 @@ def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, cam
render_cam_ob= Object.New('Camera')
render_cam_ob.link(render_cam_data)
render_scn.link(render_cam_ob)
- render_scn.setCurrentCamera(render_cam_ob)
+ render_scn.objects.camera = render_cam_ob
render_cam_data.type= 'ortho'
@@ -181,7 +181,6 @@ def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, cam
Blender.Window.RedrawAll()
- render_context.threads= 2 # good for dual core cpu's
render_context.render()
render_context.saveRenderedImage(path)
Render.CloseRenderWindow()
@@ -496,3 +495,135 @@ def vcol2image(me_s,\
mat.mode &= ~Blender.Material.Modes.SHADELESS
return image
+
+def bakeToPlane(sce, ob_from, width, height, bakemodes, axis='z', margin=0):
+ '''
+ 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.
+
+ 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 object selection
+ BACKUP_obsel = list(sce.objects.selected)
+ BACKUP_obact = sce.objects.active
+
+ # New bake settings
+ rend.bakeClear = True
+ rend.bakeMargin = margin
+ BACKUP_bakeToActive = 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
+ 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
+ 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
+ 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, 24)
+
+ 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
+
+ # Restore obsel
+ sce.objects.selected = BACKUP_obsel
+ sce.objects.active = BACKUP_obact
+
+ me_plane.verts = None
+ sce.objects.unlink(ob_plane)
+ #'''
+
+ return images_return
+
diff --git a/release/scripts/bpymodules/blend2renderinfo.py b/release/scripts/bpymodules/blend2renderinfo.py
new file mode 100644
index 00000000000..1b9dec58d55
--- /dev/null
+++ b/release/scripts/bpymodules/blend2renderinfo.py
@@ -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()
+
diff --git a/release/scripts/bpymodules/paths_ai2obj.py b/release/scripts/bpymodules/paths_ai2obj.py
index dcf56853184..6eb5023a8d4 100644
--- a/release/scripts/bpymodules/paths_ai2obj.py
+++ b/release/scripts/bpymodules/paths_ai2obj.py
@@ -1,3 +1,4 @@
+# -*- coding: latin-1 -*-
"""
paths_ai2obj.py
# ---------------------------------------------------------------
@@ -42,10 +43,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# Communiquer les problemes et erreurs sur:
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
#----------------------------------------------
+
+#Changelog
#----------------------------------------------
-#Chagelog
-#----------------------------------------------
-# 0.1.1 : 2004/08/03, bug in boudingbox reading when Value are negative
+# 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
@@ -57,6 +58,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# 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
diff --git a/release/scripts/bpymodules/paths_gimp2obj.py b/release/scripts/bpymodules/paths_gimp2obj.py
index 8b31c5d7294..c2ce9718c71 100644
--- a/release/scripts/bpymodules/paths_gimp2obj.py
+++ b/release/scripts/bpymodules/paths_gimp2obj.py
@@ -1,3 +1,4 @@
+# -*- coding: latin-1 -*-
"""
#----------------------------------------------
# (c) jm soler juillet 2004,
@@ -43,6 +44,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# 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
diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py
index d027956a507..2093ac109f7 100644
--- a/release/scripts/bvh_import.py
+++ b/release/scripts/bvh_import.py
@@ -110,7 +110,7 @@ def eulerRotate(x,y,z, rot_order):
def read_bvh(file_path, GLOBAL_SCALE=1.0):
# File loading stuff
# Open the file for importing
- file = open(file_path, 'r')
+ file = open(file_path, 'rU')
# Seperate into a list of lists, each line a list of words.
file_lines = file.readlines()
@@ -354,7 +354,7 @@ def bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False):
bvh_node.temp.rot= rx*DEG2RAD,ry*DEG2RAD,rz*DEG2RAD
- bvh_node.temp.insertIpoKey(Blender.Object.IpoKeys.LOCROT)
+ bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT)
scn.update(1)
return objects
diff --git a/release/scripts/console.py b/release/scripts/console.py
index e253e3c9857..7d9d8be5e9e 100644
--- a/release/scripts/console.py
+++ b/release/scripts/console.py
@@ -285,6 +285,8 @@ def runUserCode(__USER_CODE_STRING__):
# Try and run the user entered line(s)
try:
# Load all variabls from global dict to local space.
+ __TMP_VAR_NAME__ = __TMP_VAR__ = '' # so as not to raise an error when del'ing
+
for __TMP_VAR_NAME__, __TMP_VAR__ in __CONSOLE_VAR_DICT__.items():
exec('%s%s' % (__TMP_VAR_NAME__,'=__TMP_VAR__'))
del __TMP_VAR_NAME__
@@ -295,7 +297,8 @@ def runUserCode(__USER_CODE_STRING__):
# Flush global dict, allow the user to remove items.
__CONSOLE_VAR_DICT__ = {}
-
+
+ __TMP_VAR_NAME__ = '' # so as not to raise an error when del'ing
# Write local veriables to global __CONSOLE_VAR_DICT__
for __TMP_VAR_NAME__ in dir():
if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\
@@ -715,6 +718,15 @@ def draw_gui():
else:
BGL.glColor3f(1, 1, 0)
+ if consoleLineIdx == 1: # user input
+ BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8)
+ Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0])
+ else:
+ BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8)
+ Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0])
+
+ # Wrapping is totally slow, can even hang blender - dont do it!
+ '''
if consoleLineIdx == 1: # NEVER WRAP THE USER INPUT
BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8)
# BUG, LARGE TEXT DOSENT DISPLAY
@@ -751,7 +763,7 @@ def draw_gui():
BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8)
Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0])
-
+ '''
consoleLineIdx += 1
@@ -774,8 +786,9 @@ histIndex = cursor = -1 # How far back from the first letter are we? - in curren
# Autoexec, startup code.
scriptDir = Get('scriptsdir')
+console_autoexec = None
if scriptDir:
- if scriptDir.endswith(Blender.sys.sep):
+ if not scriptDir.endswith(Blender.sys.sep):
scriptDir += Blender.sys.sep
console_autoexec = '%s%s' % (scriptDir, 'console_autoexec.py')
@@ -788,7 +801,10 @@ if scriptDir:
except:
cmdBuffer.append(cmdLine('...console_autoexec.py could not write, this is ok', 1, None))
scriptDir = None # make sure we only use this for console_autoexec.py
-
+
+ if not sys.exists(console_autoexec):
+ console_autoexec = None
+
else:
cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts dir', 1, None))
@@ -802,7 +818,8 @@ def include_console(includeFile):
# Execute an external py file as if local
exec(include(includeFile))
-
+
+def standard_imports():
# Write local to global __CONSOLE_VAR_DICT__ for reuse,
for ls in (dir(), dir(Blender)):
for __TMP_VAR_NAME__ in ls:
@@ -810,10 +827,12 @@ def include_console(includeFile):
exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__))
exec('%s%s' % ('__CONSOLE_VAR_DICT__["bpy"]=', 'bpy'))
-
-if scriptDir:
+
+if scriptDir and console_autoexec:
include_console(console_autoexec) # pass the blender module
+standard_imports() # import Blender and bpy
+
#-end autoexec-----------------------------------------------------------------#
@@ -827,4 +846,4 @@ def main():
Draw.Register(draw_gui, handle_event, handle_button_event)
if __name__ == '__main__':
- main() \ No newline at end of file
+ main()
diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py
index a4a4787d5f3..99d036b38bc 100644
--- a/release/scripts/export_fbx.py
+++ b/release/scripts/export_fbx.py
@@ -1,7 +1,7 @@
#!BPY
"""
Name: 'Autodesk FBX (.fbx)...'
-Blender: 243
+Blender: 244
Group: 'Export'
Tooltip: 'Selection to an ASCII Autodesk FBX '
"""
@@ -12,13 +12,8 @@ __version__ = "1.1"
__bpydoc__ = """\
This script is an exporter to the FBX file format.
-Usage:
-
-Select the objects you wish to export and run this script from "File->Export" menu.
-All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d)
-will be exported as mesh data.
+http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx
"""
-
# --------------------------------------------------------------------------
# FBX Export v0.1 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
@@ -41,57 +36,470 @@ will be exported as mesh data.
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
+try:
+ import time
+ # import os # only needed for batch export, nbot used yet
+except:
+ time = None # use this to check if they have python modules installed
+
+# for python 2.3 support
+try:
+ set()
+except:
+ try:
+ from sets import Set as set
+ except:
+ set = None # so it complains you dont have a !
+
+# os is only needed for batch 'own dir' option
+try:
+ import os
+except:
+ os = None
+
import Blender
+import bpy
+from Blender.Mathutils import Matrix, Vector, RotationMatrix
+
import BPyObject
import BPyMesh
import BPySys
import BPyMessages
-import time
-from math import degrees, atan, pi
-# Used to add the scene name into the filename without using odd chars
+import sys
+
+## 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,42,43,47,58,59,60,61,62,63,64,92,94,96,124,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])
+def cleanName(name):
+ for ch in invalid: name = name.replace(ch, '_')
+ return name
+del v, i
+
+
+def copy_file(source, dest):
+ file = open(source, 'rb')
+ data = file.read()
+ file.close()
+
+ file = open(dest, 'wb')
+ file.write(data)
+ file.close()
+
+
+def copy_images(dest_dir, textures):
+ if not dest_dir.endswith(Blender.sys.sep):
+ dest_dir += Blender.sys.sep
+
+ image_paths = set()
+ for img in textures:
+ image_paths.add(Blender.sys.expandpath(img.filename))
+
+ # Now copy images
+ copyCount = 0
+ for image_path in image_paths:
+ if Blender.sys.exists(image_path):
+ # Make a name for the target path.
+ dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
+ if not Blender.sys.exists(dest_image_path): # Image isnt alredy there
+ print '\tCopying "%s" > "%s"' % (image_path, dest_image_path)
+ try:
+ copy_file(image_path, dest_image_path)
+ copyCount+=1
+ except:
+ print '\t\tWarning, file failed to copy, skipping.'
+
+ print '\tCopied %d images' % copyCount
+
+mtx4_identity = Matrix()
+
+# testing
+mtx_x90 = RotationMatrix( 90, 3, 'x') # used
+#mtx_x90n = RotationMatrix(-90, 3, 'x')
+#mtx_y90 = RotationMatrix( 90, 3, 'y')
+#mtx_y90n = RotationMatrix(-90, 3, 'y')
+#mtx_z90 = RotationMatrix( 90, 3, 'z')
+#mtx_z90n = RotationMatrix(-90, 3, 'z')
+
+#mtx4_x90 = RotationMatrix( 90, 4, 'x')
+mtx4_x90n = RotationMatrix(-90, 4, 'x') # used
+#mtx4_y90 = RotationMatrix( 90, 4, 'y')
+mtx4_y90n = RotationMatrix(-90, 4, 'y') # used
+mtx4_z90 = RotationMatrix( 90, 4, 'z') # used
+mtx4_z90n = RotationMatrix(-90, 4, 'z') # used
+
+def strip_path(p):
+ return p.split('\\')[-1].split('/')[-1]
+
+# Used to add the scene name into the filename without using odd chars
sane_name_mapping_ob = {}
sane_name_mapping_mat = {}
sane_name_mapping_tex = {}
+sane_name_mapping_take = {}
+sane_name_mapping_group = {}
-def strip_path(p):
- return p.split('\\')[-1].split('/')[-1]
+# Make sure reserved names are not used
+sane_name_mapping_ob['Scene'] = 'Scene_'
+sane_name_mapping_ob['blend_root'] = 'blend_root_'
+
+def increment_string(t):
+ name = t
+ num = ''
+ while name and name[-1].isdigit():
+ num = name[-1] + num
+ name = name[:-1]
+ if num: return '%s%d' % (name, int(num)+1)
+ else: return name + '_0'
+
+
+# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up.
def sane_name(data, dct):
- if not data: return None
+ #if not data: return None
name = data.name
- try: return dct[name]
- except: pass
+
+ # dont cache, only ever call once for each data type now,
+ # so as to avoid namespace collision between types - like with objects <-> bones
+ #try: return dct[name]
+ #except: pass
orig_name = name
- name = BPySys.cleanName(name)
+ if not name:
+ name = 'unnamed' # blank string, ASKING FOR TROUBLE!
+ else:
+ #name = BPySys.cleanName(name)
+ name = cleanName(name) # use our own
+
+ while name in dct.itervalues(): name = increment_string(name)
+
dct[orig_name] = name
return name
def sane_obname(data): return sane_name(data, sane_name_mapping_ob)
def sane_matname(data): return sane_name(data, sane_name_mapping_mat)
def sane_texname(data): return sane_name(data, sane_name_mapping_tex)
+def sane_takename(data): return sane_name(data, sane_name_mapping_take)
+def sane_groupname(data): return sane_name(data, sane_name_mapping_group)
+
-# May use this later
-"""
-# Auto class, use for datastorage only, a like a dictionary but with limited slots
-def auto_class(slots):
- exec('class container_class(object): __slots__=%s' % slots)
- return container_class
-"""
+def mat4x4str(mat):
+ return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ])
+
+def meshNormalizedWeights(me):
+ try: # account for old bad BPyMesh
+ groupNames, vWeightList = BPyMesh.meshWeight2List(me)
+ except:
+ return [],[]
+
+ if not groupNames:
+ return [],[]
+
+ for i, vWeights in enumerate(vWeightList):
+ tot = 0.0
+ for w in vWeights:
+ tot+=w
+
+ if tot:
+ for j, w in enumerate(vWeights):
+ vWeights[j] = w/tot
+
+ return groupNames, vWeightList
+
header_comment = \
'''; FBX 6.1.0 project file
; Created by Blender FBX Exporter
-; for support mail cbarton@metavr.com
+; for support mail: ideasman42@gmail.com
; ----------------------------------------------------
'''
-def write_header(file):
+# This func can be called with just the filename
+def write(filename, batch_objects = None, \
+ EXP_OBS_SELECTED = True,
+ EXP_MESH = True,
+ EXP_MESH_APPLY_MOD = True,
+ EXP_MESH_HQ_NORMALS = False,
+ EXP_ARMATURE = True,
+ EXP_LAMP = True,
+ EXP_CAMERA = True,
+ EXP_EMPTY = True,
+ EXP_IMAGE_COPY = False,
+ GLOBAL_MATRIX = Matrix(),
+ ANIM_ENABLE = True,
+ ANIM_OPTIMIZE = True,
+ ANIM_OPTIMIZE_PRECISSION = 6,
+ ANIM_ACTION_ALL = False,
+ BATCH_ENABLE = False,
+ BATCH_GROUP = True,
+ BATCH_SCENE = False,
+ BATCH_FILE_PREFIX = '',
+ BATCH_OWN_DIR = False
+ ):
+
+ # ----------------- Batch support!
+ if BATCH_ENABLE:
+ if os == None: BATCH_OWN_DIR = False
+
+ fbxpath = filename
+
+ # get the path component of filename
+ tmp_exists = Blender.sys.exists(fbxpath)
+
+ if tmp_exists != 2: # a file, we want a path
+ while fbxpath and fbxpath[-1] not in ('/', '\\'):
+ fbxpath = fbxpath[:-1]
+ if not filename:
+ Draw.PupMenu('Error%t|Directory does not exist!')
+ return
+
+ tmp_exists = Blender.sys.exists(fbxpath)
+
+ if tmp_exists != 2:
+ Draw.PupMenu('Error%t|Directory does not exist!')
+ return
+
+ if not fbxpath.endswith(Blender.sys.sep):
+ fbxpath += Blender.sys.sep
+ del tmp_exists
+
+
+ if BATCH_GROUP:
+ data_seq = bpy.data.groups
+ else:
+ data_seq = bpy.data.scenes
+
+ # call this function within a loop with BATCH_ENABLE == False
+ orig_sce = bpy.data.scenes.active
+
+
+ new_fbxpath = fbxpath # own dir option modifies, we need to keep an original
+ for data in data_seq: # scene or group
+ newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name)
+
+
+ if BATCH_OWN_DIR:
+ new_fbxpath = fbxpath + newname + Blender.sys.sep
+ # path may alredy exist
+ # TODO - might exist but be a file. unlikely but should probably account for it.
+
+ if Blender.sys.exists(new_fbxpath) == 0:
+ os.mkdir(new_fbxpath)
+
+
+ filename = new_fbxpath + newname + '.fbx'
+
+ print '\nBatch exporting %s as...\n\t"%s"' % (data, filename)
+
+ if BATCH_GROUP: #group
+ # group, so objects update properly, add a dummy scene.
+ sce = bpy.data.scenes.new()
+ sce.Layers = (1<<20) -1
+ bpy.data.scenes.active = sce
+ for ob_base in data.objects:
+ sce.objects.link(ob_base)
+
+ sce.update(1)
+
+ # TODO - BUMMER! Armatures not in the group wont animate the mesh
+
+ else:# scene
+
+
+ data_seq.active = data
+
+
+ # Call self with modified args
+ # Dont pass batch options since we alredy usedt them
+ write(filename, data.objects,
+ False,
+ EXP_MESH,
+ EXP_MESH_APPLY_MOD,
+ EXP_MESH_HQ_NORMALS,
+ EXP_ARMATURE,
+ EXP_LAMP,
+ EXP_CAMERA,
+ EXP_EMPTY,
+ EXP_IMAGE_COPY,
+ GLOBAL_MATRIX,
+ ANIM_ENABLE,
+ ANIM_OPTIMIZE,
+ ANIM_OPTIMIZE_PRECISSION,
+ ANIM_ACTION_ALL
+ )
+
+ if BATCH_GROUP:
+ # remove temp group scene
+ bpy.data.scenes.unlink(sce)
+
+ bpy.data.scenes.active = orig_sce
+
+ return # so the script wont run after we have batch exported.
+
+ # end batch support
+
+
+ # ----------------------------------------------
+ # storage classes
+ class my_bone_class:
+ __slots__ =(\
+ 'blenName',\
+ 'blenBone',\
+ 'blenMeshes',\
+ 'restMatrix',\
+ 'parent',\
+ 'blenName',\
+ 'fbxName',\
+ 'fbxArm',\
+ '__pose_bone',\
+ '__anim_poselist')
+
+ def __init__(self, blenBone, fbxArm):
+
+ # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace
+ self.fbxName = sane_obname(blenBone)
+
+ self.blenName = blenBone.name
+ self.blenBone = blenBone
+ self.blenMeshes = {} # fbxMeshObName : mesh
+ self.fbxArm = fbxArm
+ self.restMatrix = blenBone.matrix['ARMATURESPACE']
+
+ # not used yet
+ # self.restMatrixInv = self.restMatrix.copy().invert()
+ # self.restMatrixLocal = None # set later, need parent matrix
+
+ self.parent = None
+
+ # not public
+ pose = fbxArm.blenObject.getPose()
+ self.__pose_bone = pose.bones[self.blenName]
+
+ # store a list if matricies here, (poseMatrix, head, tail)
+ # {frame:posematrix, frame:posematrix, ...}
+ self.__anim_poselist = {}
+
+ '''
+ def calcRestMatrixLocal(self):
+ if self.parent:
+ self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert()
+ else:
+ self.restMatrixLocal = self.restMatrix.copy()
+ '''
+ def setPoseFrame(self, f):
+ # cache pose info here, frame must be set beforehand
+
+ # Didnt end up needing head or tail, if we do - here it is.
+ '''
+ self.__anim_poselist[f] = (\
+ self.__pose_bone.poseMatrix.copy(),\
+ self.__pose_bone.head.copy(),\
+ self.__pose_bone.tail.copy() )
+ '''
+
+ self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy()
+
+ # get pose from frame.
+ def getPoseMatrix(self, f):# ----------------------------------------------
+ return self.__anim_poselist[f]
+ '''
+ def getPoseHead(self, f):
+ #return self.__pose_bone.head.copy()
+ return self.__anim_poselist[f][1].copy()
+ def getPoseTail(self, f):
+ #return self.__pose_bone.tail.copy()
+ return self.__anim_poselist[f][2].copy()
+ '''
+ # end
+
+ def getAnimParRelMatrix(self, frame):
+ #arm_mat = self.fbxArm.matrixWorld
+ #arm_mat = self.fbxArm.parRelMatrix()
+ if not self.parent:
+ #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore
+ return mtx4_z90 * self.getPoseMatrix(frame)
+ else:
+ #return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert()
+ return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert()
+
+ # we need thes because cameras and lights modified rotations
+ def getAnimParRelMatrixRot(self, frame):
+ return self.getAnimParRelMatrix(frame)
+
+ def flushAnimData(self):
+ self.__anim_poselist.clear()
+
+
+ class my_object_generic:
+ # Other settings can be applied for each type - mesh, armature etc.
+ def __init__(self, ob, matrixWorld = None):
+ self.fbxName = sane_obname(ob)
+ self.blenObject = ob
+ self.fbxGroupNames = []
+ self.fbxParent = None # set later on IF the parent is in the selection.
+ if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX
+ else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX
+ self.__anim_poselist = {} # we should only access this
+
+ def parRelMatrix(self):
+ if self.fbxParent:
+ return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert()
+ else:
+ return self.matrixWorld
+
+ def setPoseFrame(self, f):
+ self.__anim_poselist[f] = self.blenObject.matrixWorld.copy()
+
+ def getAnimParRelMatrix(self, frame):
+ if self.fbxParent:
+ #return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX
+ return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert()
+ else:
+ return self.__anim_poselist[frame] * GLOBAL_MATRIX
+
+ def getAnimParRelMatrixRot(self, frame):
+ type = self.blenObject.type
+ if self.fbxParent:
+ matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotationPart()
+ else:
+ matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart()
+
+ # Lamps need to be rotated
+ if type =='Lamp':
+ matrix_rot = mtx_x90 * matrix_rot
+ elif ob and type =='Camera':
+ y = Vector(0,1,0) * matrix_rot
+ matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y)
+
+ return matrix_rot
+
+ # ----------------------------------------------
+
+
+
+
+
+ print '\nFBX export starting...', filename
+ start_time = Blender.sys.time()
+ try:
+ file = open(filename, 'w')
+ except:
+ return False
+
+ sce = bpy.data.scenes.active
+ world = sce.world
+
+
+ # ---------------------------- Write the header first
file.write(header_comment)
- curtime = time.localtime()[0:6]
+ if time:
+ curtime = time.localtime()[0:6]
+ else:
+ curtime = [0,0,0,0,0,0]
#
file.write(\
'''FBXHeaderExtension: {
@@ -115,49 +523,78 @@ def write_header(file):
file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime)
file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version'))
-
-
-
-
-def write_scene(file, sce, world):
- def write_object_tx(ob, loc, matrix):
+ pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way
+
+ # --------------- funcs for exporting
+ def object_tx(ob, loc, matrix, matrix_mod = None):
'''
- We have loc to set the location if non blender objects that have a location
+ Matrix mod is so armature objects can modify their bone matricies
'''
-
- if ob and not matrix: matrix = ob.matrixWorld
- matrix_rot = matrix
- #if matrix:
- # matrix = matrix_scale * matrix
-
- if matrix:
- loc = tuple(matrix.translationPart())
- scale = tuple(matrix.scalePart())
+ if isinstance(ob, Blender.Types.BoneType):
+
+ # we know we have a matrix
+ # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod)
+ matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
+
+ parent = ob.parent
+ if parent:
+ #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod)
+ par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
+ matrix = matrix * par_matrix.copy().invert()
+
+ matrix_rot = matrix.rotationPart()
+
+ loc = tuple(matrix.translationPart())
+ scale = tuple(matrix.scalePart())
+ rot = tuple(matrix_rot.toEuler())
- matrix_rot = matrix.rotationPart()
- # Lamps need to be rotated
- if ob and ob.type =='Lamp':
- matrix_rot = Blender.Mathutils.RotationMatrix(90, 4, 'x') * matrix
- rot = tuple(matrix_rot.toEuler())
- elif ob and ob.type =='Camera':
- y = Blender.Mathutils.Vector(0,1,0) * matrix_rot
- matrix_rot = matrix_rot * Blender.Mathutils.RotationMatrix(90, 3, 'r', y)
- rot = tuple(matrix_rot.toEuler())
- else:
- rot = tuple(matrix_rot.toEuler())
else:
- if not loc:
- loc = 0,0,0
- scale = 1,1,1
- rot = 0,0,0
+ # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore
+ #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX
+ if ob and not matrix: raise "error: this should never happen!"
+
+ matrix_rot = matrix
+ #if matrix:
+ # matrix = matrix_scale * matrix
+
+ if matrix:
+ loc = tuple(matrix.translationPart())
+ scale = tuple(matrix.scalePart())
+
+ matrix_rot = matrix.rotationPart()
+ # Lamps need to be rotated
+ if ob and ob.type =='Lamp':
+ matrix_rot = mtx_x90 * matrix_rot
+ rot = tuple(matrix_rot.toEuler())
+ elif ob and ob.type =='Camera':
+ y = Vector(0,1,0) * matrix_rot
+ matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y)
+ rot = tuple(matrix_rot.toEuler())
+ else:
+ rot = tuple(matrix_rot.toEuler())
+ else:
+ if not loc:
+ loc = 0,0,0
+ scale = 1,1,1
+ rot = 0,0,0
+
+ return loc, rot, scale, matrix, matrix_rot
+
+ def write_object_tx(ob, loc, matrix, matrix_mod= None):
+ '''
+ We have loc to set the location if non blender objects that have a location
+
+ matrix_mod is only used for bones at the moment
+ '''
+ loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod)
file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc)
file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot)
file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale)
return loc, rot, scale, matrix, matrix_rot
- def write_object_props(ob=None, loc=None, matrix=None):
+ def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None):
# if the type is 0 its an empty otherwise its a mesh
# only difference at the moment is one has a color
file.write('''
@@ -165,16 +602,16 @@ def write_scene(file, sce, world):
Property: "QuaternionInterpolate", "bool", "",0
Property: "Visibility", "Visibility", "A+",1''')
- loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix)
+ loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod)
- # Rotation order
- # eEULER_XYZ
+ # Rotation order, note, for FBX files Iv loaded normal order is 1
+ # setting to zero.
+ # eEULER_XYZ = 0
# eEULER_XZY
# eEULER_YZX
# eEULER_YXZ
# eEULER_ZXY
- # eEULER_ZYX
-
+ # eEULER_ZYX
file.write('''
Property: "RotationOffset", "Vector3D", "",0,0,0
@@ -190,7 +627,7 @@ def write_scene(file, sce, world):
Property: "TranslationMaxX", "bool", "",0
Property: "TranslationMaxY", "bool", "",0
Property: "TranslationMaxZ", "bool", "",0
- Property: "RotationOrder", "enum", "",1
+ Property: "RotationOrder", "enum", "",0
Property: "RotationSpaceForLimitOnly", "bool", "",0
Property: "AxisLen", "double", "",10
Property: "PreRotation", "Vector3D", "",0,0,0
@@ -240,7 +677,7 @@ def write_scene(file, sce, world):
Property: "Show", "bool", "",1
Property: "NegativePercentShapeSupport", "bool", "",1
Property: "DefaultAttributeIndex", "int", "",0''')
- if ob:
+ if ob and type(ob) != Blender.Types.BoneType:
# Only mesh objects have color
file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
file.write('\n\t\t\tProperty: "Size", "double", "",100')
@@ -248,6 +685,42 @@ def write_scene(file, sce, world):
return loc, rot, scale, matrix, matrix_rot
+
+ # -------------------------------------------- Armatures
+ #def write_bone(bone, name, matrix_mod):
+ def write_bone(my_bone):
+ file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName)
+ file.write('\n\t\tVersion: 232')
+
+ #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3]
+ poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore
+ pose_items.append( (my_bone.fbxName, poseMatrix) )
+
+
+ # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length)
+ file.write('\n\t\t\tProperty: "Size", "double", "",1')
+
+ #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length)
+
+ """
+ file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\
+ ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length)
+ """
+
+ file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\
+ (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length)
+
+ #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1')
+ file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8')
+ file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
+ file.write('\n\t\t}')
+ file.write('\n\t\tMultiLayer: 0')
+ file.write('\n\t\tMultiTake: 1')
+ file.write('\n\t\tShading: Y')
+ file.write('\n\t\tCulling: "CullingOff"')
+ file.write('\n\t\tTypeFlags: "Skeleton"')
+ file.write('\n\t}')
+
def write_camera_switch():
file.write('''
Model: "Model::Camera Switcher", "CameraSwitcher" {
@@ -370,7 +843,7 @@ def write_scene(file, sce, world):
write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0))
write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0))
- def write_camera(ob, name):
+ def write_camera(my_cam):
'''
Write a blender camera
'''
@@ -379,11 +852,11 @@ def write_scene(file, sce, world):
height = render.sizeY
aspect = float(width)/height
- data = ob.data
+ data = my_cam.blenObject.data
- file.write('\n\tModel: "Model::%s", "Camera" {' % name )
+ file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName )
file.write('\n\t\tVersion: 232')
- loc, rot, scale, matrix, matrix_rot = write_object_props(ob)
+ loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix())
file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0')
file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle)
@@ -471,8 +944,8 @@ def write_scene(file, sce, world):
file.write('\n\t\tTypeFlags: "Camera"')
file.write('\n\t\tGeometryVersion: 124')
file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc)
- file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Blender.Mathutils.Vector(0,1,0) * matrix_rot) )
- file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Blender.Mathutils.Vector(0,0,-1)*matrix_rot) )
+ file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) )
+ file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) )
#file.write('\n\t\tUp: 0,0,0' )
#file.write('\n\t\tLookAt: 0,0,0' )
@@ -483,12 +956,12 @@ def write_scene(file, sce, world):
file.write('\n\t\tCameraOrthoZoom: 1')
file.write('\n\t}')
- def write_light(ob, name):
- light = ob.data
- file.write('\n\tModel: "Model::%s", "Light" {' % name)
+ def write_light(my_light):
+ light = my_light.blenObject.data
+ file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName)
file.write('\n\t\tVersion: 232')
- write_object_props(ob)
+ write_object_props(my_light.blenObject, None, my_light.parRelMatrix())
# Why are these values here twice?????? - oh well, follow the holy sdk's output
@@ -499,7 +972,20 @@ def write_scene(file, sce, world):
#eSPOT
light_type = light.type
if light_type > 3: light_type = 0
-
+
+ mode = light.mode
+ if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows:
+ do_shadow = 1
+ else:
+ do_shadow = 0
+
+ if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular):
+ do_light = 0
+ else:
+ do_light = 1
+
+ scale = abs(GLOBAL_MATRIX.scalePart()[0]) # scale is always uniform in this case
+
file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type)
file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1')
file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1')
@@ -507,15 +993,15 @@ def write_scene(file, sce, world):
file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0')
file.write('\n\t\t\tProperty: "GoboProperty", "object", ""')
file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1')
- file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (light.energy*100))
- file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % light.spotSize)
+ file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
+ file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col))
- file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (light.energy*100))
- file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % light.spotSize)
+ file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
+ file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type)
- file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1')
+ file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light)
file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1')
file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0')
file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1')
@@ -528,7 +1014,7 @@ def write_scene(file, sce, world):
file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0')
file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0')
file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0')
- file.write('\n\t\t\tProperty: "CastShadows", "bool", "",0')
+ file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow)
file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1')
file.write('\n\t\t}')
file.write('\n\t\tMultiLayer: 0')
@@ -539,12 +1025,36 @@ def write_scene(file, sce, world):
file.write('\n\t\tGeometryVersion: 124')
file.write('\n\t}')
- # Material Settings
- if world:
- world_amb = world.getAmb()
- else:
- world_amb = (0,0,0) # Default value
+ # matrixOnly is not used at the moment
+ def write_null(my_null = None, fbxName = None, matrixOnly = None):
+ # ob can be null
+ if not fbxName: fbxName = my_null.fbxName
+
+ file.write('\n\tModel: "Model::%s", "Null" {' % fbxName)
+ file.write('\n\t\tVersion: 232')
+
+ # only use this for the root matrix at the moment
+ if matrixOnly:
+ poseMatrix = write_object_props(None, None, matrixOnly)[3]
+
+ else: # all other Null's
+ if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3]
+ else: poseMatrix = write_object_props()[3]
+
+ pose_items.append((fbxName, poseMatrix))
+
+ file.write('''
+ }
+ MultiLayer: 0
+ MultiTake: 1
+ Shading: Y
+ Culling: "CullingOff"
+ TypeFlags: "Null"
+ }''')
+ # Material Settings
+ if world: world_amb = world.getAmb()
+ else: world_amb = (0,0,0) # Default value
def write_material(matname, mat):
file.write('\n\tMaterial: "Material::%s", "" {' % matname)
@@ -561,6 +1071,7 @@ def write_scene(file, sce, world):
mat_hard = (float(mat.hard)-1)/5.10
mat_spec = mat.spec/2.0
mat_alpha = mat.alpha
+ mat_emit = mat.emit
mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS
if mat_shadeless:
mat_shader = 'Lambert'
@@ -578,6 +1089,7 @@ def write_scene(file, sce, world):
mat_hard = 20.0
mat_spec = 0.2
mat_alpha = 1.0
+ mat_emit = 0.0
mat_shadeless = False
mat_shader = 'Phong'
@@ -588,27 +1100,27 @@ def write_scene(file, sce, world):
file.write('\n\t\tProperties60: {')
file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader)
file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0')
- file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",0,0,0')
- file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",1')
+ file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender
+ file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_dif)
- file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb)
- file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.1f' % mat_amb)
- file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold)
- file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.1f' % mat_dif)
+ file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb)
+ file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb)
+ file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold)
+ file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_emit)
file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0')
file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1')
- file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",0')
+ file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha))
if not mat_shadeless:
- file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols)
- file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.1f' % mat_spec)
+ file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols)
+ file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec)
file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0')
file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0')
file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1')
- file.write('\n\t\t\tProperty: "Emissive", "Vector3D", "",0,0,0')
- file.write('\n\t\t\tProperty: "Ambient", "Vector3D", "",%.1f,%.1f,%.1f' % mat_colamb)
- file.write('\n\t\t\tProperty: "Diffuse", "Vector3D", "",%.1f,%.1f,%.1f' % mat_cold)
+ file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0')
+ file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb)
+ file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold)
if not mat_shadeless:
- file.write('\n\t\t\tProperty: "Specular", "Vector3D", "",%.1f,%.1f,%.1f' % mat_cols)
+ file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols)
file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard)
file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha)
if not mat_shadeless:
@@ -669,15 +1181,21 @@ def write_scene(file, sce, world):
Property: "Rotation", "Vector", "A+",0,0,0
Property: "Scaling", "Vector", "A+",1,1,1''')
file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num)
+
+
+ # WrapModeU/V 0==rep, 1==clamp, TODO add support
file.write('''
Property: "TextureTypeUse", "enum", "",0
Property: "CurrentTextureBlendMode", "enum", "",1
Property: "UseMaterial", "bool", "",0
Property: "UseMipMap", "bool", "",0
Property: "CurrentMappingType", "enum", "",0
- Property: "UVSwap", "bool", "",0
- Property: "WrapModeU", "enum", "",0
- Property: "WrapModeV", "enum", "",0
+ Property: "UVSwap", "bool", "",0''')
+
+ file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX)
+ file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY)
+
+ file.write('''
Property: "TextureRotationPivot", "Vector3D", "",0,0,0
Property: "TextureScalingPivot", "Vector3D", "",0,0,0
Property: "VideoProperty", "object", ""
@@ -698,194 +1216,143 @@ def write_scene(file, sce, world):
Texture_Alpha_Source: "None"
Cropping: 0,0,0,0
}''')
-
- ob_meshes = []
- ob_lights = []
- ob_cameras = []
- materials = {}
- textures = {}
- armatures = [] # We should export standalone armatures also
- armatures_totbones = 0 # we need this because each bone is a model
- for ob_base in sce.objects.context:
- for ob, mtx in BPyObject.getDerivedObjects(ob_base):
- #for ob in [ob_base,]:
- ob_type = ob.type
- if ob_type == 'Camera':
- ob_cameras.append((sane_obname(ob), ob))
- elif ob_type == 'Lamp':
- ob_lights.append((sane_obname(ob), ob))
-
- else:
- if ob_type == 'Mesh': me = ob.getData(mesh=1)
- else: me = BPyMesh.getMeshFromObject(ob)
-
- if me:
- mats = me.materials
- for mat in mats:
- # 2.44 use mat.lib too for uniqueness
- if mat: materials[mat.name] = mat
-
- if me.faceUV:
- uvlayer_orig = me.activeUVLayer
- for uvlayer in me.getUVLayerNames():
- me.activeUVLayer = uvlayer
- for f in me.faces:
- img = f.image
- if img: textures[img.name] = img
-
- me.activeUVLayer = uvlayer_orig
-
- arm = BPyObject.getObjectArmature(ob)
-
- if arm:
- armname = sane_obname(arm)
- bones = arm.bones.values()
- armatures_totbones += len(bones)
- armatures.append((arm, armname, bones))
- else:
- armname = None
-
- #### me.transform(ob.matrixWorld) # Export real ob coords.
- #### High Quality, not realy needed for now.
- #BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
- ob_meshes.append( (sane_obname(ob), ob, mtx, me, mats, arm, armname) )
-
- del ob_type
-
- materials = [(sane_matname(mat), mat) for mat in materials.itervalues()]
- textures = [(sane_texname(img), img) for img in textures.itervalues()]
- materials.sort() # sort by name
- textures.sort()
-
- if not materials:
- materials = [('null', None)]
-
- material_mapping = {} # blen name : index
- if textures:
- texture_mapping_local = {None:0} # ditto
- i = 0
- for texname, tex in textures:
- texture_mapping_local[tex.name] = i
- i+=1
- textures.insert(0, ('_empty_', None))
-
- i = 0
- for matname, mat in materials:
- if mat: mat = mat.name
- material_mapping[mat] = i
- i+=1
-
- camera_count = 8
- file.write('''
-
-; Object definitions
-;------------------------------------------------------------------
-Definitions: {
- Version: 100
- Count: %i''' % (\
- 1+1+camera_count+\
- len(ob_meshes)+\
- len(ob_lights)+\
- len(ob_cameras)+\
- len(armatures)+\
- armatures_totbones+\
- len(materials)+\
- (len(textures)*2))) # add 1 for the root model 1 for global settings
-
- file.write('''
- ObjectType: "Model" {
- Count: %i
- }''' % (\
- 1+camera_count+\
- len(ob_meshes)+\
- len(ob_lights)+\
- len(ob_cameras)+\
- len(armatures)+\
- armatures_totbones)) # add 1 for the root model
-
- file.write('''
- ObjectType: "Geometry" {
- Count: %i
- }''' % len(ob_meshes))
-
- if materials:
- file.write('''
- ObjectType: "Material" {
- Count: %i
- }''' % len(materials))
-
- if textures:
- file.write('''
- ObjectType: "Texture" {
- Count: %i
- }''' % len(textures)) # add 1 for an empty tex
+ def write_deformer_skin(obname):
+ '''
+ Each mesh has its own deformer
+ '''
+ file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname)
file.write('''
- ObjectType: "Video" {
- Count: %i
- }''' % len(textures)) # add 1 for an empty tex
-
- file.write('''
- ObjectType: "GlobalSettings" {
- Count: 1
- }
-}
-''')
-
- file.write(\
-'''
-; Object properties
-;------------------------------------------------------------------
-
-Objects: {''')
-
- # To comply with other FBX FILES
- write_camera_switch()
-
- # Write the null object
- file.write('''
- Model: "Model::blend_root", "Null" {
- Version: 232''')
- write_object_props()
-
- file.write('''
- }
+ Version: 100
MultiLayer: 0
- MultiTake: 1
- Shading: Y
- Culling: "CullingOff"
- TypeFlags: "Null"
+ Type: "Skin"
+ Properties60: {
+ }
+ Link_DeformAcuracy: 50
}''')
- for obname, ob in ob_cameras:
- write_camera(ob, obname)
-
- for obname, ob in ob_lights:
- write_light(ob, obname)
+ # in the example was 'Bip01 L Thigh_2'
+ def write_sub_deformer_skin(my_mesh, my_bone, weights):
+
+ '''
+ Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers
+ So the SubDeformer needs the mesh-object name as a prefix to make it unique
+
+ Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer,
+ a but silly but dosnt really matter
+ '''
+ file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName))
+
+ file.write('''
+ Version: 100
+ MultiLayer: 0
+ Type: "Cluster"
+ Properties60: {
+ Property: "SrcModel", "object", ""
+ Property: "SrcModelReference", "object", ""
+ }
+ UserData: "", ""''')
+
+ # Support for bone parents
+ if my_mesh.fbxBoneParent:
+ if my_mesh.fbxBoneParent == my_bone:
+ # TODO - this is a bit lazy, we could have a simple write loop
+ # for this case because all weights are 1.0 but for now this is ok
+ # Parent Bones arent used all that much anyway.
+ vgroup_data = [(j, 1.0) for j in xrange(len(my_mesh.blenData.verts))]
+ else:
+ # This bone is not a parent of this mesh object, no weights
+ vgroup_data = []
+
+ else:
+ # Normal weight painted mesh
+ if my_bone.blenName in weights[0]:
+ # Before we used normalized wright list
+ #vgroup_data = me.getVertsFromGroup(bone.name, 1)
+ group_index = weights[0].index(my_bone.blenName)
+ vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]]
+ else:
+ vgroup_data = []
+
+ file.write('\n\t\tIndexes: ')
+
+ i = -1
+ for vg in vgroup_data:
+ if i == -1:
+ file.write('%i' % vg[0])
+ i=0
+ else:
+ if i==23:
+ file.write('\n\t\t')
+ i=0
+ file.write(',%i' % vg[0])
+ i+=1
+
+ file.write('\n\t\tWeights: ')
+ i = -1
+ for vg in vgroup_data:
+ if i == -1:
+ file.write('%.8f' % vg[1])
+ i=0
+ else:
+ if i==38:
+ file.write('\n\t\t')
+ i=0
+ file.write(',%.8f' % vg[1])
+ i+=1
+
+ if my_mesh.fbxParent:
+ # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible!
+ m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() )
+ else:
+ # Yes! this is it... - but dosnt work when the mesh is a.
+ m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() )
+
+ #m = mtx4_z90 * my_bone.restMatrix
+ matstr = mat4x4str(m)
+ matstr_i = mat4x4str(m.invert())
+
+ file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/
+ file.write('\n\t\tTransformLink: %s' % matstr)
+ file.write('\n\t}')
- for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
- file.write('\n\tModel: "Model::%s", "Mesh" {' % sane_obname(ob))
+ def write_mesh(my_mesh):
+
+ me = my_mesh.blenData
+
+ # if there are non NULL materials on this mesh
+ if [mat for mat in my_mesh.blenMaterials if mat]: do_materials = True
+ else: do_materials = False
+
+ if my_mesh.blenTextures: do_textures = True
+ else: do_textures = False
+
+
+ file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName)
file.write('\n\t\tVersion: 232') # newline is added in write_object_props
- write_object_props(ob, None, mtx)
+
+ write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())
+
file.write('\n\t\t}')
file.write('\n\t\tMultiLayer: 0')
file.write('\n\t\tMultiTake: 1')
file.write('\n\t\tShading: Y')
file.write('\n\t\tCulling: "CullingOff"')
+
# Write the Real Mesh data here
file.write('\n\t\tVertices: ')
i=-1
+
for v in me.verts:
if i==-1:
- file.write('%.6f,%.6f,%.6f' % tuple(v.co))
- i=0
+ file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0
else:
if i==7:
- file.write('\n\t\t')
- i=0
+ file.write('\n\t\t'); i=0
file.write(',%.6f,%.6f,%.6f'% tuple(v.co))
i+=1
+
file.write('\n\t\tPolygonVertexIndex: ')
i=-1
for f in me.faces:
@@ -932,22 +1399,20 @@ Objects: {''')
MappingInformationType: "ByVertice"
ReferenceInformationType: "Direct"
Normals: ''')
-
+
i=-1
for v in me.verts:
if i==-1:
- file.write('%.15f,%.15f,%.15f' % tuple(v.no))
- i=0
+ file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0
else:
if i==2:
- file.write('\n ')
- i=0
+ file.write('\n '); i=0
file.write(',%.15f,%.15f,%.15f' % tuple(v.no))
i+=1
file.write('\n\t\t}')
-
# Write VertexColor Layers
+ # note, no programs seem to use this info :/
collayers = []
if me.vertexColors:
collayers = me.getColorLayerNames()
@@ -1043,32 +1508,47 @@ Objects: {''')
file.write('\n\t\t}')
- if textures:
+ if do_textures:
file.write('\n\t\tLayerElementTexture: %i {' % uvindex)
file.write('\n\t\t\tVersion: 101')
file.write('\n\t\t\tName: "%s"' % uvlayer)
- file.write('''
- MappingInformationType: "ByPolygon"
- ReferenceInformationType: "IndexToDirect"
- BlendMode: "Translucent"
- TextureAlpha: 1
- TextureId: ''')
- i=-1
- for f in me.faces:
- img_key = f.image
- if img_key: img_key = img_key.name
+ if len(my_mesh.blenTextures) == 1:
+ file.write('\n\t\t\tMappingInformationType: "AllSame"')
+ else:
+ file.write('\n\t\t\tMappingInformationType: "ByPolygon"')
+
+ file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"')
+ file.write('\n\t\t\tBlendMode: "Translucent"')
+ file.write('\n\t\t\tTextureAlpha: 1')
+ file.write('\n\t\t\tTextureId: ')
+
+ if len(my_mesh.blenTextures) == 1:
+ file.write('0')
+ else:
+ #texture_mapping_local = {None:0}
+ texture_mapping_local = {None:-1}
- if i==-1:
- i=0
- file.write( '%s' % texture_mapping_local[img_key])
- else:
- if i==55:
- file.write('\n ')
- i=0
+ i = 0 # 1 for dummy
+ for tex in my_mesh.blenTextures:
+ texture_mapping_local[tex] = i
+ i+=1
+
+ i=-1
+ for f in me.faces:
+ img_key = f.image
- file.write(',%s' % texture_mapping_local[img_key])
- i+=1
+ if i==-1:
+ i=0
+ file.write( '%s' % texture_mapping_local[img_key])
+ else:
+ if i==55:
+ file.write('\n ')
+ i=0
+
+ file.write(',%s' % texture_mapping_local[img_key])
+ i+=1
+
else:
file.write('''
LayerElementTexture: 0 {
@@ -1085,44 +1565,50 @@ Objects: {''')
# Done with UV/textures.
- if materials:
- file.write('''
- LayerElementMaterial: 0 {
- Version: 101
- Name: ""
- MappingInformationType: "ByPolygon"
- ReferenceInformationType: "IndexToDirect"
- Materials: ''')
-
- # Build a material mapping for this
- material_mapping_local = {} # local-index : global index.
- for i, mat in enumerate(mats):
- if mat:
- material_mapping_local[i] = material_mapping[mat.name]
- else:
- material_mapping_local[i] = 0 # None material is zero for now.
+ if do_materials:
+ file.write('\n\t\tLayerElementMaterial: 0 {')
+ file.write('\n\t\t\tVersion: 101')
+ file.write('\n\t\t\tName: ""')
- if not material_mapping_local:
- material_mapping_local[0] = 0
+ if len(my_mesh.blenMaterials) == 1:
+ file.write('\n\t\t\tMappingInformationType: "AllSame"')
+ else:
+ file.write('\n\t\t\tMappingInformationType: "ByPolygon"')
- len_material_mapping_local = len(material_mapping_local)
+ file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"')
+ file.write('\n\t\t\tMaterials: ')
- i=-1
- for f in me.faces:
- f_mat = f.mat
- if f_mat >= len_material_mapping_local:
- f_mat = 0
+ if len(my_mesh.blenMaterials) == 1:
+ file.write('0')
+ else:
+ # Build a material mapping for this
+ #material_mapping_local = [0] * 16 # local-index : global index.
+ material_mapping_local = [-1] * 16 # local-index : global index.
+ i= 0 # 1
+ for j, mat in enumerate(my_mesh.blenMaterials):
+ if mat:
+ material_mapping_local[j] = i
+ i+=1
+ # else leave as -1
- if i==-1:
- i=0
- file.write( '%s' % material_mapping_local[f_mat])
- else:
- if i==55:
- file.write('\n\t\t\t\t')
- i=0
+ len_material_mapping_local = len(material_mapping_local)
+
+ i=-1
+ for f in me.faces:
+ f_mat = f.mat
+ if f_mat >= len_material_mapping_local:
+ f_mat = 0
- file.write(',%s' % material_mapping_local[f_mat])
- i+=1
+ if i==-1:
+ i=0
+ file.write( '%s' % (material_mapping_local[f_mat]))
+ else:
+ if i==55:
+ file.write('\n\t\t\t\t')
+ i=0
+
+ file.write(',%s' % (material_mapping_local[f_mat]))
+ i+=1
file.write('\n\t\t}')
@@ -1134,7 +1620,7 @@ Objects: {''')
TypedIndex: 0
}''')
- if materials:
+ if do_materials:
file.write('''
LayerElement: {
Type: "LayerElementMaterial"
@@ -1142,7 +1628,7 @@ Objects: {''')
}''')
# Always write this
- if textures:
+ if do_textures:
file.write('''
LayerElement: {
Type: "LayerElementTexture"
@@ -1179,7 +1665,7 @@ Objects: {''')
file.write('\n\t\t\t\tTypedIndex: %i' % i)
file.write('\n\t\t\t}')
- if textures:
+ if do_textures:
file.write('''
LayerElement: {
@@ -1206,7 +1692,425 @@ Objects: {''')
file.write('\n\t\t\t\tTypedIndex: %i' % i)
file.write('\n\t\t\t}')
file.write('\n\t\t}')
- file.write('\n\t}')
+ file.write('\n\t}')
+
+ def write_group(name):
+ file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name)
+
+ file.write('''
+ Properties60: {
+ Property: "MultiLayer", "bool", "",0
+ Property: "Pickable", "bool", "",1
+ Property: "Transformable", "bool", "",1
+ Property: "Show", "bool", "",1
+ }
+ MultiLayer: 0
+ }''')
+
+
+ # add meshes here to clear because they are not used anywhere.
+ meshes_to_clear = []
+
+ ob_meshes = []
+ ob_lights = []
+ ob_cameras = []
+ # in fbx we export bones as children of the mesh
+ # armatures not a part of a mesh, will be added to ob_arms
+ ob_bones = []
+ ob_arms = []
+ ob_null = [] # emptys
+
+ # List of types that have blender objects (not bones)
+ ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null]
+
+ groups = [] # blender groups, only add ones that have objects in the selections
+ materials = {}
+ textures = {}
+
+ tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error
+
+ # if EXP_OBS_SELECTED is false, use sceens objects
+ if not batch_objects:
+ if EXP_OBS_SELECTED: tmp_objects = sce.objects.context
+ else: tmp_objects = sce.objects
+ else:
+ tmp_objects = batch_objects
+
+ if EXP_ARMATURE:
+ # This is needed so applying modifiers dosnt apply the armature deformation, its also needed
+ # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes.
+ # set every armature to its rest, backup the original values so we done mess up the scene
+ ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures]
+
+ for arm in bpy.data.armatures:
+ arm.restPosition = True
+
+ if ob_arms_orig_rest:
+ for ob_base in bpy.data.objects:
+ #if ob_base.type == 'Armature':
+ ob_base.makeDisplayList()
+
+ # This causes the makeDisplayList command to effect the mesh
+ Blender.Set('curframe', Blender.Get('curframe'))
+
+
+ for ob_base in tmp_objects:
+ for ob, mtx in BPyObject.getDerivedObjects(ob_base):
+ #for ob in [ob_base,]:
+ tmp_ob_type = ob.type
+ if tmp_ob_type == 'Camera':
+ if EXP_CAMERA:
+ ob_cameras.append(my_object_generic(ob, mtx))
+ elif tmp_ob_type == 'Lamp':
+ if EXP_LAMP:
+ ob_lights.append(my_object_generic(ob, mtx))
+ elif tmp_ob_type == 'Armature':
+ if EXP_ARMATURE:
+ # TODO - armatures dont work in dupligroups!
+ if ob not in ob_arms: ob_arms.append(ob)
+ # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)"
+ elif tmp_ob_type == 'Empty':
+ if EXP_EMPTY:
+ ob_null.append(my_object_generic(ob, mtx))
+ elif EXP_MESH:
+ origData = True
+ if tmp_ob_type != 'Mesh':
+ me = bpy.data.meshes.new()
+ try: me.getFromObject(ob)
+ except: me = None
+ if me:
+ meshes_to_clear.append( me )
+ mats = me.materials
+ origData = False
+ else:
+ # Mesh Type!
+ if EXP_MESH_APPLY_MOD:
+ me = bpy.data.meshes.new()
+ me.getFromObject(ob)
+
+ # so we keep the vert groups
+ if EXP_ARMATURE:
+ orig_mesh = ob.getData(mesh=1)
+ if orig_mesh.getVertGroupNames():
+ ob.copy().link(me)
+ # If new mesh has no vgroups we can try add if verts are teh same
+ if not me.getVertGroupNames(): # vgroups were not kept by the modifier
+ if len(me.verts) == len(orig_mesh.verts):
+ groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh)
+ BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
+
+ # print ob, me, me.getVertGroupNames()
+ meshes_to_clear.append( me )
+ origData = False
+ mats = me.materials
+ else:
+ me = ob.getData(mesh=1)
+ mats = me.materials
+
+ # Support object colors
+ tmp_colbits = ob.colbits
+ if tmp_colbits:
+ tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too.
+ for i in xrange(16):
+ if tmp_colbits & (1<<i):
+ mats[i] = tmp_ob_mats[i]
+ del tmp_ob_mats
+ del tmp_colbits
+
+
+ if me:
+ # This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled.
+ # so strictly this is bad. but only in rare cases would it have negative results
+ # say with dupliverts the objects would rotate a bit differently
+ if EXP_MESH_HQ_NORMALS:
+ BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
+
+ for mat in mats:
+ # 2.44 use mat.lib too for uniqueness
+ if mat: materials[mat] = mat
+
+ texture_mapping_local = {}
+ if me.faceUV:
+ uvlayer_orig = me.activeUVLayer
+ for uvlayer in me.getUVLayerNames():
+ me.activeUVLayer = uvlayer
+ for f in me.faces:
+ img = f.image
+ textures[img] = texture_mapping_local[img] = img
+
+ me.activeUVLayer = uvlayer_orig
+
+ if EXP_ARMATURE:
+ armob = BPyObject.getObjectArmature(ob)
+ blenParentBoneName = None
+
+ # Note - Fixed in BPyObject but for now just copy the function because testers wont have up to date modukes,
+ # TODO - remove this for 2.45 release since getObjectArmature has been fixed
+ if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE:
+ armob = ob.parent
+
+ # parent bone - special case
+ if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE:
+ armob = ob.parent
+ blenParentBoneName = ob.parentbonename
+
+
+ if armob and armob not in ob_arms:
+ ob_arms.append(armob)
+
+ else:
+ blenParentBoneName = armob = None
+
+ my_mesh = my_object_generic(ob, mtx)
+ my_mesh.blenData = me
+ my_mesh.origData = origData
+ my_mesh.blenMaterials = mats
+ my_mesh.blenTextures = texture_mapping_local.values()
+
+ # if only 1 null texture then empty the list
+ if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None:
+ my_mesh.blenTextures = []
+
+ my_mesh.fbxArm = armob # replace with my_object_generic armature instance later
+ my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later
+
+ ob_meshes.append( my_mesh )
+
+ if EXP_ARMATURE:
+ # now we have the meshes, restore the rest arm position
+ for i, arm in enumerate(bpy.data.armatures):
+ arm.restPosition = ob_arms_orig_rest[i]
+
+ if ob_arms_orig_rest:
+ for ob_base in bpy.data.objects:
+ if ob_base.type == 'Armature':
+ ob_base.makeDisplayList()
+ # This causes the makeDisplayList command to effect the mesh
+ Blender.Set('curframe', Blender.Get('curframe'))
+
+ del tmp_ob_type, tmp_objects
+
+ # now we have collected all armatures, add bones
+ for i, ob in enumerate(ob_arms):
+
+ ob_arms[i] = my_arm = my_object_generic(ob)
+
+ my_arm.fbxBones = []
+ my_arm.blenData = ob.data
+ my_arm.blenAction = ob.action
+ my_arm.blenActionList = []
+
+ # fbxName, blenderObject, my_bones, blenderActions
+ #ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, [])
+
+ for bone in my_arm.blenData.bones.values():
+ my_bone = my_bone_class(bone, my_arm)
+ my_arm.fbxBones.append( my_bone )
+ ob_bones.append( my_bone )
+
+ # add the meshes to the bones and replace the meshes armature with own armature class
+ #for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
+ for my_mesh in ob_meshes:
+ # Replace
+ # ...this could be sped up with dictionary mapping but its unlikely for
+ # it ever to be a bottleneck - (would need 100+ meshes using armatures)
+ if my_mesh.fbxArm:
+ for my_arm in ob_arms:
+ if my_arm.blenObject == my_mesh.fbxArm:
+ my_mesh.fbxArm = my_arm
+ break
+
+ for my_bone in ob_bones:
+
+ # The mesh uses this bones armature!
+ if my_bone.fbxArm == my_mesh.fbxArm:
+ my_bone.blenMeshes[my_mesh.fbxName] = me
+
+
+ # parent bone: replace bone names with our class instances
+ # my_mesh.fbxBoneParent is None or a blender bone name initialy, replacing if the names match.
+ if my_mesh.fbxBoneParent == my_bone.blenName:
+ my_mesh.fbxBoneParent = my_bone
+
+ bone_deformer_count = 0 # count how many bones deform a mesh
+ my_bone_blenParent = None
+ for my_bone in ob_bones:
+ my_bone_blenParent = my_bone.blenBone.parent
+ if my_bone_blenParent:
+ for my_bone_parent in ob_bones:
+ # Note 2.45rc2 you can compare bones normally
+ if my_bone_blenParent.name == my_bone_parent.blenName and my_bone.fbxArm == my_bone_parent.fbxArm:
+ my_bone.parent = my_bone_parent
+ break
+
+ # Not used at the moment
+ # my_bone.calcRestMatrixLocal()
+ bone_deformer_count += len(my_bone.blenMeshes)
+
+ del my_bone_blenParent
+
+
+ # Build blenObject -> fbxObject mapping
+ # this is needed for groups as well as fbxParenting
+ bpy.data.objects.tag = False
+ tmp_obmapping = {}
+ for ob_generic in ob_all_typegroups:
+ for ob_base in ob_generic:
+ ob_base.blenObject.tag = True
+ tmp_obmapping[ob_base.blenObject] = ob_base
+
+ # Build Groups from objects we export
+ for blenGroup in bpy.data.groups:
+ fbxGroupName = None
+ for ob in blenGroup.objects:
+ if ob.tag:
+ if fbxGroupName == None:
+ fbxGroupName = sane_groupname(blenGroup)
+ groups.append((fbxGroupName, blenGroup))
+
+ tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames
+
+ groups.sort() # not really needed
+
+ # Assign parents using this mapping
+ for ob_generic in ob_all_typegroups:
+ for my_ob in ob_generic:
+ parent = my_ob.blenObject.parent
+ if parent and parent.tag: # does it exist and is it in the mapping
+ my_ob.fbxParent = tmp_obmapping[parent]
+
+
+ del tmp_obmapping
+ # Finished finding groups we use
+
+
+ materials = [(sane_matname(mat), mat) for mat in materials.itervalues() if mat]
+ textures = [(sane_texname(img), img) for img in textures.itervalues() if img]
+ materials.sort() # sort by name
+ textures.sort()
+
+ camera_count = 8
+ file.write('''
+
+; Object definitions
+;------------------------------------------------------------------
+
+Definitions: {
+ Version: 100
+ Count: %i''' % (\
+ 1+1+camera_count+\
+ len(ob_meshes)+\
+ len(ob_lights)+\
+ len(ob_cameras)+\
+ len(ob_arms)+\
+ len(ob_null)+\
+ len(ob_bones)+\
+ bone_deformer_count+\
+ len(materials)+\
+ (len(textures)*2))) # add 1 for the root model 1 for global settings
+
+ del bone_deformer_count
+
+ file.write('''
+ ObjectType: "Model" {
+ Count: %i
+ }''' % (\
+ 1+camera_count+\
+ len(ob_meshes)+\
+ len(ob_lights)+\
+ len(ob_cameras)+\
+ len(ob_arms)+\
+ len(ob_null)+\
+ len(ob_bones))) # add 1 for the root model
+
+ file.write('''
+ ObjectType: "Geometry" {
+ Count: %i
+ }''' % len(ob_meshes))
+
+ if materials:
+ file.write('''
+ ObjectType: "Material" {
+ Count: %i
+ }''' % len(materials))
+
+ if textures:
+ file.write('''
+ ObjectType: "Texture" {
+ Count: %i
+ }''' % len(textures)) # add 1 for an empty tex
+ file.write('''
+ ObjectType: "Video" {
+ Count: %i
+ }''' % len(textures)) # add 1 for an empty tex
+
+ tmp = 0
+ # Add deformer nodes
+ for my_mesh in ob_meshes:
+ if my_mesh.fbxArm:
+ tmp+=1
+
+ # Add subdeformers
+ for my_bone in ob_bones:
+ tmp += len(my_bone.blenMeshes)
+
+ if tmp:
+ file.write('''
+ ObjectType: "Deformer" {
+ Count: %i
+ }''' % tmp)
+ del tmp
+
+ # we could avoid writing this possibly but for now just write it
+
+ file.write('''
+ ObjectType: "Pose" {
+ Count: 1
+ }''')
+
+ if groups:
+ file.write('''
+ ObjectType: "GroupSelection" {
+ Count: %i
+ }''' % len(groups))
+
+ file.write('''
+ ObjectType: "GlobalSettings" {
+ Count: 1
+ }
+}''')
+
+ file.write('''
+
+; Object properties
+;------------------------------------------------------------------
+
+Objects: {''')
+
+ # To comply with other FBX FILES
+ write_camera_switch()
+
+ # Write the null object
+ write_null(None, 'blend_root')# , GLOBAL_MATRIX)
+
+ for my_null in ob_null:
+ write_null(my_null)
+
+ for my_arm in ob_arms:
+ write_null(my_arm)
+
+ for my_cam in ob_cameras:
+ write_camera(my_cam)
+
+ for my_light in ob_lights:
+ write_light(my_light)
+
+ for my_mesh in ob_meshes:
+ write_mesh(my_mesh)
+
+ #for bonename, bone, obname, me, armob in ob_bones:
+ for my_bone in ob_bones:
+ write_bone(my_bone)
write_camera_default()
@@ -1221,6 +2125,51 @@ Objects: {''')
write_texture(texname, tex, i)
i+=1
+ for groupname, group in groups:
+ write_group(groupname)
+
+ # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do.
+
+ # Write armature modifiers
+ # TODO - add another MODEL? - because of this skin definition.
+ for my_mesh in ob_meshes:
+ if my_mesh.fbxArm:
+ write_deformer_skin(my_mesh.fbxName)
+
+ # Get normalized weights for temorary use
+ if my_mesh.fbxBoneParent:
+ weights = None
+ else:
+ weights = meshNormalizedWeights(my_mesh.blenData)
+
+ #for bonename, bone, obname, bone_mesh, armob in ob_bones:
+ for my_bone in ob_bones:
+ if me in my_bone.blenMeshes.itervalues():
+ write_sub_deformer_skin(my_mesh, my_bone, weights)
+
+ # Write pose's really weired, only needed when an armature and mesh are used together
+ # each by themselves dont need pose data. for now only pose meshes and bones
+
+ file.write('''
+ Pose: "Pose::BIND_POSES", "BindPose" {
+ Type: "BindPose"
+ Version: 100
+ Properties60: {
+ }
+ NbPoseNodes: ''')
+ file.write(str(len(pose_items)))
+
+
+ for fbxName, matrix in pose_items:
+ file.write('\n\t\tPoseNode: {')
+ file.write('\n\t\t\tNode: "Model::%s"' % fbxName )
+ if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix))
+ else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity))
+ file.write('\n\t\t}')
+
+ file.write('\n\t}')
+
+
# Finish Writing Objects
# Write global settings
file.write('''
@@ -1233,7 +2182,7 @@ Objects: {''')
Property: "FrontAxisSign", "int", "",1
Property: "CoordAxis", "int", "",0
Property: "CoordAxisSign", "int", "",1
- Property: "UnitScaleFactor", "double", "",1
+ Property: "UnitScaleFactor", "double", "",100
}
}
''')
@@ -1247,14 +2196,26 @@ Objects: {''')
Relations: {''')
file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}')
- for obname, ob in ob_cameras:
- file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % obname)
+
+ for my_null in ob_null:
+ file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName)
+
+ for my_arm in ob_arms:
+ file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName)
+
+ for my_mesh in ob_meshes:
+ file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName)
+
+ # TODO - limbs can have the same name for multiple armatures, should prefix.
+ #for bonename, bone, obname, me, armob in ob_bones:
+ for my_bone in ob_bones:
+ file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName)
- for obname, ob in ob_lights:
- file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % obname)
+ for my_cam in ob_cameras:
+ file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName)
- for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
- file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % obname)
+ for my_light in ob_lights:
+ file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName)
file.write('''
Model: "Model::Producer Perspective", "Camera" {
@@ -1283,6 +2244,23 @@ Relations: {''')
for texname, tex in textures:
file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname)
+ # deformers - modifiers
+ for my_mesh in ob_meshes:
+ if my_mesh.fbxArm:
+ file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName)
+
+ #for bonename, bone, obname, me, armob in ob_bones:
+ for my_bone in ob_bones:
+ for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName
+ # is this bone effecting a mesh?
+ file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName))
+
+ # This should be at the end
+ # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}')
+
+ for groupname, group in groups:
+ file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname)
+
file.write('\n}')
file.write('''
@@ -1290,64 +2268,357 @@ Relations: {''')
;------------------------------------------------------------------
Connections: {''')
+
+ # NOTE - The FBX SDK dosnt care about the order but some importers DO!
+ # for instance, defining the material->mesh connection
+ # before the mesh->blend_root crashes cinema4d
+
# write the fake root node
file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"')
- for obname, ob in ob_cameras:
- file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
-
- for obname, ob in ob_lights:
- file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
-
- for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
- file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
+ for ob_generic in ob_all_typegroups: # all blender 'Object's we support
+ for my_ob in ob_generic:
+ if my_ob.fbxParent:
+ file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName))
+ else:
+ file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName)
- for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
- # Connect all materials to all objects, not good form but ok for now.
- for mat in mats:
- file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_matname(mat), obname))
+ if materials:
+ for my_mesh in ob_meshes:
+ # Connect all materials to all objects, not good form but ok for now.
+ for mat in my_mesh.blenMaterials:
+ if mat:
+ file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName))
if textures:
- for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
- for texname, tex in textures:
- file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (texname, obname))
+ for my_mesh in ob_meshes:
+ if my_mesh.blenTextures:
+ # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName)
+ for tex in my_mesh.blenTextures:
+ if tex:
+ file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName))
for texname, tex in textures:
file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname))
+ for my_mesh in ob_meshes:
+ if my_mesh.fbxArm:
+ file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName))
+
+ #for bonename, bone, obname, me, armob in ob_bones:
+ for my_bone in ob_bones:
+ for fbxMeshObName in my_bone.blenMeshes: # .keys()
+ file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName))
+
+ # limbs -> deformers
+ # for bonename, bone, obname, me, armob in ob_bones:
+ for my_bone in ob_bones:
+ for fbxMeshObName in my_bone.blenMeshes: # .keys()
+ file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName))
+
+
+ #for bonename, bone, obname, me, armob in ob_bones:
+ for my_bone in ob_bones:
+ # Always parent to armature now
+ if my_bone.parent:
+ file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) )
+ else:
+ # the armature object is written as an empty and all root level bones connect to it
+ file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) )
+
+ # groups
+ if groups:
+ for ob_generic in ob_all_typegroups:
+ for ob_base in ob_generic:
+ for fbxGroupName in ob_base.fbxGroupNames:
+ file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName))
+
+ for my_arm in ob_arms:
+ file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName)
+
file.write('\n}')
- # Clear mesh data Only when writing with modifiers applied
- #for obname, ob, me, mats, arm, armname in objects:
- # me.verts = None
+ # Needed for scene footer as well as animation
+ render = sce.render
+
+ # from the FBX sdk
+ #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000))
+ def fbx_time(t):
+ # 0.5 + val is the same as rounding.
+ return int(0.5 + ((t/fps) * 46186158000))
+
+ fps = float(render.fps)
+ start = render.sFrame
+ end = render.eFrame
+ if end < start: start, end = end, start
+ if start==end: ANIM_ENABLE = False
+
+ # animations for these object types
+ ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms
+
+ if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]:
+
+ frame_orig = Blender.Get('curframe')
+
+ if ANIM_OPTIMIZE:
+ ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION
+
+ # default action, when no actions are avaioable
+ tmp_actions = [None] # None is the default action
+ blenActionDefault = None
+ action_lastcompat = None
+
+ if ANIM_ACTION_ALL:
+ bpy.data.actions.tag = False
+ tmp_actions = list(bpy.data.actions)
+
+
+ # find which actions are compatible with the armatures
+ # blenActions is not yet initialized so do it now.
+ tmp_act_count = 0
+ for my_arm in ob_arms:
+
+ # get the default name
+ if not blenActionDefault:
+ blenActionDefault = my_arm.blenAction
+
+ arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones])
+
+ for action in tmp_actions:
+
+ action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) )
+
+ if action_chan_names: # at least one channel matches.
+ my_arm.blenActionList.append(action)
+ action.tag = True
+ tmp_act_count += 1
+
+ # incase there is no actions applied to armatures
+ action_lastcompat = action
+
+ if tmp_act_count:
+ # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature.
+ if not blenActionDefault:
+ blenActionDefault = action_lastcompat
+
+ del action_lastcompat
+
+ file.write('''
+;Takes and animation section
+;----------------------------------------------------
+Takes: {''')
+
+ if blenActionDefault:
+ file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault))
+ else:
+ file.write('\n\tCurrent: "Default Take"')
+
+ for blenAction in tmp_actions:
+ # we have tagged all actious that are used be selected armatures
+ if blenAction:
+ if blenAction.tag:
+ print '\taction: "%s" exporting...' % blenAction.name
+ else:
+ print '\taction: "%s" has no armature using it, skipping' % blenAction.name
+ continue
+
+ if blenAction == None:
+ # Warning, this only accounts for tmp_actions being [None]
+ file.write('\n\tTake: "Default Take" {')
+ act_start = start
+ act_end = end
+ else:
+ # use existing name
+ if blenAction == blenActionDefault: # have we alredy got the name
+ file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name])
+ else:
+ file.write('\n\tTake: "%s" {' % sane_takename(blenAction))
+
+ tmp = blenAction.getFrameNumbers()
+ if tmp:
+ act_start = min(tmp)
+ act_end = max(tmp)
+ del tmp
+ else:
+ # Fallback on this, theres not much else we can do? :/
+ # when an action has no length
+ act_start = start
+ act_end = end
+
+ # Set the action active
+ for my_bone in ob_arms:
+ if blenAction in my_bone.blenActionList:
+ ob.action = blenAction
+ # print '\t\tSetting Action!', blenAction
+ # sce.update(1)
+
+ file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed
+ file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed
+ file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed
+
+ file.write('''
-def write_footer(file, sce, world):
+ ;Models animation
+ ;----------------------------------------------------''')
+
+
+ # set pose data for all bones
+ # do this here incase the action changes
+ '''
+ for my_bone in ob_bones:
+ my_bone.flushAnimData()
+ '''
+ i = act_start
+ while i <= act_end:
+ Blender.Set('curframe', i)
+ for ob_generic in ob_anim_lists:
+ for my_ob in ob_generic:
+ #Blender.Window.RedrawAll()
+ if ob_generic == ob_meshes and my_ob.fbxArm:
+ # We cant animate armature meshes!
+ pass
+ else:
+ my_ob.setPoseFrame(i)
+
+ i+=1
+
+
+ #for bonename, bone, obname, me, armob in ob_bones:
+ for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms):
+
+ for my_ob in ob_generic:
+
+ if ob_generic == ob_meshes and my_ob.fbxArm:
+ # do nothing,
+ pass
+ else:
+
+ file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed
+ file.write('\n\t\t\tVersion: 1.1')
+ file.write('\n\t\t\tChannel: "Transform" {')
+
+ context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ]
+
+ # ----------------
+ # ----------------
+ for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale
+
+ if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats]
+ elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats]
+ else: context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats]
+
+ file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation
+
+ for i in xrange(3):
+ # Loop on each axis of the bone
+ file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation
+ file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] )
+ file.write('\n\t\t\t\t\t\tKeyVer: 4005')
+
+ if not ANIM_OPTIMIZE:
+ # Just write all frames, simple but in-eficient
+ file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start))
+ file.write('\n\t\t\t\t\t\tKey: ')
+ frame = act_start
+ while frame <= act_end:
+ if frame!=act_start:
+ file.write(',')
+
+ # Curve types are
+ # C,n is for bezier? - linear is best for now so we can do simple keyframe removal
+ file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] ))
+ #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] ))
+ frame+=1
+ else:
+ # remove unneeded keys, j is the frame, needed when some frames are removed.
+ context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ]
+
+ # last frame to fisrt frame, missing 1 frame on either side.
+ # removeing in a backwards loop is faster
+ for j in xrange( (act_end-act_start)-1, 0, -1 ):
+ # Is this key reduenant?
+ if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\
+ abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT:
+ del context_bone_anim_keys[j]
+
+ if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]:
+ # This axis has no moton, its okay to skip KeyCount and Keys in this case
+ pass
+ else:
+ # We only need to write these if there is at least one
+ file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys))
+ file.write('\n\t\t\t\t\t\tKey: ')
+ for val, frame in context_bone_anim_keys:
+ if frame != context_bone_anim_keys[0][1]: # not the first
+ file.write(',')
+ # frame is alredy one less then blenders frame
+ file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame), val ))
+ #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val ))
+
+ if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0')
+ elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0')
+ elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1')
+
+ file.write('\n\t\t\t\t\t}')
+ file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) )
+ file.write('\n\t\t\t\t}')
+
+ # ---------------
+
+ file.write('\n\t\t\t}')
+ file.write('\n\t\t}')
+
+ # end the take
+ file.write('\n\t}')
+
+ # end action loop. set original actions
+ # do this after every loop incase actions effect eachother.
+ for my_bone in ob_arms:
+ my_bone.blenObject.action = my_bone.blenAction
+
+ file.write('\n}')
+
+ Blender.Set('curframe', frame_orig)
+
+ else:
+ # no animation
+ file.write('\n;Takes and animation section')
+ file.write('\n;----------------------------------------------------')
+ file.write('\n')
+ file.write('\nTakes: {')
+ file.write('\n\tCurrent: ""')
+ file.write('\n}')
- tuple(world.hor)
- tuple(world.amb)
- has_mist = world.mode & 1
+ # write meshes animation
+ #for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
+
- mist_intense, mist_start, mist_end, mist_height = world.mist
+ # Clear mesh data Only when writing with modifiers applied
+ for me in meshes_to_clear:
+ me.verts = None
- render = sce.render
- file.write('\n;Takes and animation section')
- file.write('\n;----------------------------------------------------')
- file.write('\n')
- file.write('\nTakes: {')
- file.write('\n\tCurrent: ""')
- file.write('\n}')
+
+ # --------------------------- Footer
+ if world:
+ has_mist = world.mode & 1
+ mist_intense, mist_start, mist_end, mist_height = world.mist
+ world_hor = world.hor
+ else:
+ has_mist = mist_intense = mist_start = mist_end = mist_height = 0
+ world_hor = 0,0,0
+
file.write('\n;Version 5 settings')
file.write('\n;------------------------------------------------------------------')
file.write('\n')
file.write('\nVersion5: {')
file.write('\n\tAmbientRenderSettings: {')
file.write('\n\t\tVersion: 101')
- file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world.amb))
+ file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb))
file.write('\n\t}')
file.write('\n\tFogOptions: {')
file.write('\n\t\tFlogEnable: %i' % has_mist)
@@ -1355,15 +2626,15 @@ def write_footer(file, sce, world):
file.write('\n\t\tFogDensity: %.3f' % mist_intense)
file.write('\n\t\tFogStart: %.3f' % mist_start)
file.write('\n\t\tFogEnd: %.3f' % mist_end)
- file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world.hor))
+ file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor))
file.write('\n\t}')
file.write('\n\tSettings: {')
- file.write('\n\t\tFrameRate: "%i"' % render.fps)
+ file.write('\n\t\tFrameRate: "%i"' % int(fps))
file.write('\n\t\tTimeFormat: 1')
file.write('\n\t\tSnapOnFrames: 0')
file.write('\n\t\tReferenceTimeIndex: -1')
- file.write('\n\t\tTimeLineStartTime: %i' % render.sFrame)
- file.write('\n\t\tTimeLineStopTime: %i' % render.eFrame)
+ file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1))
+ file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1))
file.write('\n\t}')
file.write('\n\tRendererSetting: {')
file.write('\n\t\tDefaultCamera: "Producer Perspective"')
@@ -1377,24 +2648,329 @@ def write_footer(file, sce, world):
sane_name_mapping_mat.clear()
sane_name_mapping_tex.clear()
+ ob_arms[:] = []
+ ob_bones[:] = []
+ ob_cameras[:] = []
+ ob_lights[:] = []
+ ob_meshes[:] = []
+ ob_null[:] = []
+
+
+ # copy images if enabled
+ if EXP_IMAGE_COPY:
+ copy_images( Blender.sys.dirname(filename), [ tex[1] for tex in textures if tex[1] != None ])
+
+ print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)
+ return True
+
-import bpy
-def write_ui(filename):
- if not filename.lower().endswith('.fbx'):
- filename += '.fbx'
+# --------------------------------------------
+# UI Function - not a part of the exporter.
+# this is to seperate the user interface from the rest of the exporter.
+from Blender import Draw, Window
+EVENT_NONE = 0
+EVENT_EXIT = 1
+EVENT_REDRAW = 2
+EVENT_FILESEL = 3
+
+GLOBALS = {}
+
+# export opts
+
+def do_redraw(e,v): GLOBALS['EVENT'] = e
+
+# toggle between these 2, only allow one on at once
+def do_obs_sel(e,v):
+ GLOBALS['EVENT'] = e
+ GLOBALS['EXP_OBS_SCENE'].val = 0
+ GLOBALS['EXP_OBS_SELECTED'].val = 1
+
+def do_obs_sce(e,v):
+ GLOBALS['EVENT'] = e
+ GLOBALS['EXP_OBS_SCENE'].val = 1
+ GLOBALS['EXP_OBS_SELECTED'].val = 0
+
+def do_obs_sce(e,v):
+ GLOBALS['EVENT'] = e
+ GLOBALS['EXP_OBS_SCENE'].val = 1
+ GLOBALS['EXP_OBS_SELECTED'].val = 0
+
+def do_batch_type_grp(e,v):
+ GLOBALS['EVENT'] = e
+ GLOBALS['BATCH_GROUP'].val = 1
+ GLOBALS['BATCH_SCENE'].val = 0
+
+def do_batch_type_sce(e,v):
+ GLOBALS['EVENT'] = e
+ GLOBALS['BATCH_GROUP'].val = 0
+ GLOBALS['BATCH_SCENE'].val = 1
+
+def do_anim_act_all(e,v):
+ GLOBALS['EVENT'] = e
+ GLOBALS['ANIM_ACTION_ALL'][0].val = 1
+ GLOBALS['ANIM_ACTION_ALL'][1].val = 0
+
+def do_anim_act_cur(e,v):
+ if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val:
+ Draw.PupMenu('Warning%t|Cant use this with batch export group option')
+ else:
+ GLOBALS['EVENT'] = e
+ GLOBALS['ANIM_ACTION_ALL'][0].val = 0
+ GLOBALS['ANIM_ACTION_ALL'][1].val = 1
+
+def fbx_ui_exit(e,v):
+ GLOBALS['EVENT'] = e
+
+def do_help(e,v):
+ url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx'
+ print 'Trying to open web browser with documentation at this address...'
+ print '\t' + url
- #if not BPyMessages.Warning_SaveOver(filename):
- # return
- sce = bpy.data.scenes.active
- world = sce.world
+ try:
+ import webbrowser
+ webbrowser.open(url)
+ except:
+ print '...could not open a browser window.'
+
+
+
+# run when export is pressed
+#def fbx_ui_write(e,v):
+def fbx_ui_write(filename):
+
+ # Dont allow overwriting files when saving normally
+ if not GLOBALS['BATCH_ENABLE'].val:
+ if not BPyMessages.Warning_SaveOver(filename):
+ return
+
+ GLOBALS['EVENT'] = EVENT_EXIT
+
+ # Keep the order the same as above for simplicity
+ # the [] is a dummy arg used for objects
Blender.Window.WaitCursor(1)
- file = open(filename, 'w')
- write_header(file)
- write_scene(file, sce, world)
- write_footer(file, sce, world)
+
+ # Make the matrix
+ GLOBAL_MATRIX = mtx4_identity
+ GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val
+ if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n
+ if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n
+ if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n
+
+ ret = write(\
+ filename, None,\
+ GLOBALS['EXP_OBS_SELECTED'].val,\
+ GLOBALS['EXP_MESH'].val,\
+ GLOBALS['EXP_MESH_APPLY_MOD'].val,\
+ GLOBALS['EXP_MESH_HQ_NORMALS'].val,\
+ GLOBALS['EXP_ARMATURE'].val,\
+ GLOBALS['EXP_LAMP'].val,\
+ GLOBALS['EXP_CAMERA'].val,\
+ GLOBALS['EXP_EMPTY'].val,\
+ GLOBALS['EXP_IMAGE_COPY'].val,\
+ GLOBAL_MATRIX,\
+ GLOBALS['ANIM_ENABLE'].val,\
+ GLOBALS['ANIM_OPTIMIZE'].val,\
+ GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,\
+ GLOBALS['ANIM_ACTION_ALL'][0].val,\
+ GLOBALS['BATCH_ENABLE'].val,\
+ GLOBALS['BATCH_GROUP'].val,\
+ GLOBALS['BATCH_SCENE'].val,\
+ GLOBALS['BATCH_FILE_PREFIX'].val,\
+ GLOBALS['BATCH_OWN_DIR'].val,\
+ )
+
Blender.Window.WaitCursor(0)
+ GLOBALS.clear()
+
+ if ret == False:
+ Draw.PupMenu('Error%t|Path cannot be written to!')
+
+
+def fbx_ui():
+ # Only to center the UI
+ x,y = GLOBALS['MOUSE']
+ x-=180; y-=0 # offset... just to get it centered
+
+ Draw.Label('Export Objects...', x+20,y+165, 200, 20)
+
+ if not GLOBALS['BATCH_ENABLE'].val:
+ Draw.BeginAlign()
+ GLOBALS['EXP_OBS_SELECTED'] = Draw.Toggle('Selected Objects', EVENT_REDRAW, x+20, y+145, 160, 20, GLOBALS['EXP_OBS_SELECTED'].val, 'Export selected objects on visible layers', do_obs_sel)
+ GLOBALS['EXP_OBS_SCENE'] = Draw.Toggle('Scene Objects', EVENT_REDRAW, x+180, y+145, 160, 20, GLOBALS['EXP_OBS_SCENE'].val, 'Export all objects in this scene', do_obs_sce)
+ Draw.EndAlign()
+
+ Draw.BeginAlign()
+ GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)')
+ GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis')
+ GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis')
+ GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis')
+ Draw.EndAlign()
+
+ y -= 35
+
+ Draw.BeginAlign()
+ GLOBALS['EXP_EMPTY'] = Draw.Toggle('Empty', EVENT_NONE, x+20, y+120, 60, 20, GLOBALS['EXP_EMPTY'].val, 'Export empty objects')
+ GLOBALS['EXP_CAMERA'] = Draw.Toggle('Camera', EVENT_NONE, x+80, y+120, 60, 20, GLOBALS['EXP_CAMERA'].val, 'Export camera objects')
+ GLOBALS['EXP_LAMP'] = Draw.Toggle('Lamp', EVENT_NONE, x+140, y+120, 60, 20, GLOBALS['EXP_LAMP'].val, 'Export lamp objects')
+ GLOBALS['EXP_ARMATURE'] = Draw.Toggle('Armature', EVENT_NONE, x+200, y+120, 60, 20, GLOBALS['EXP_ARMATURE'].val, 'Export armature objects')
+ GLOBALS['EXP_MESH'] = Draw.Toggle('Mesh', EVENT_REDRAW, x+260, y+120, 80, 20, GLOBALS['EXP_MESH'].val, 'Export mesh objects', do_redraw) #, do_axis_z)
+ Draw.EndAlign()
+
+ if GLOBALS['EXP_MESH'].val:
+ # below mesh but
+ Draw.BeginAlign()
+ GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Toggle('Modifiers', EVENT_NONE, x+260, y+100, 80, 20, GLOBALS['EXP_MESH_APPLY_MOD'].val, 'Apply modifiers to mesh objects') #, do_axis_z)
+ GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Toggle('HQ Normals', EVENT_NONE, x+260, y+80, 80, 20, GLOBALS['EXP_MESH_HQ_NORMALS'].val, 'Generate high quality normals') #, do_axis_z)
+ Draw.EndAlign()
+
+ GLOBALS['EXP_IMAGE_COPY'] = Draw.Toggle('Copy Image Files', EVENT_NONE, x+20, y+80, 160, 20, GLOBALS['EXP_IMAGE_COPY'].val, 'Copy image files to the destination path') #, do_axis_z)
+
+
+ Draw.Label('Export Armature Animation...', x+20,y+45, 300, 20)
+
+ GLOBALS['ANIM_ENABLE'] = Draw.Toggle('Enable Animation', EVENT_REDRAW, x+20, y+25, 160, 20, GLOBALS['ANIM_ENABLE'].val, 'Export keyframe animation', do_redraw)
+ if GLOBALS['ANIM_ENABLE'].val:
+ Draw.BeginAlign()
+ GLOBALS['ANIM_OPTIMIZE'] = Draw.Toggle('Optimize Keyframes', EVENT_REDRAW, x+20, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val, 'Remove double keyframes', do_redraw)
+ if GLOBALS['ANIM_OPTIMIZE'].val:
+ GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Number('Precission: ', EVENT_NONE, x+180, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val, 3, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)')
+ Draw.EndAlign()
+
+ Draw.BeginAlign()
+ GLOBALS['ANIM_ACTION_ALL'][1] = Draw.Toggle('Current Action', EVENT_REDRAW, x+20, y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][1].val, 'Use actions currently applied to the armatures (use scene start/end frame)', do_anim_act_cur)
+ GLOBALS['ANIM_ACTION_ALL'][0] = Draw.Toggle('All Actions', EVENT_REDRAW, x+180,y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][0].val, 'Use all actions for armatures', do_anim_act_all)
+ Draw.EndAlign()
+
+
+ Draw.Label('Export Batch...', x+20,y-60, 300, 20)
+ GLOBALS['BATCH_ENABLE'] = Draw.Toggle('Enable Batch', EVENT_REDRAW, x+20, y-80, 160, 20, GLOBALS['BATCH_ENABLE'].val, 'Automate exporting multiple scenes or groups to files', do_redraw)
+
+ if GLOBALS['BATCH_ENABLE'].val:
+ Draw.BeginAlign()
+ GLOBALS['BATCH_GROUP'] = Draw.Toggle('Group > File', EVENT_REDRAW, x+20, y-105, 160, 20, GLOBALS['BATCH_GROUP'].val, 'Export each group as an FBX file', do_batch_type_grp)
+ GLOBALS['BATCH_SCENE'] = Draw.Toggle('Scene > File', EVENT_REDRAW, x+180, y-105, 160, 20, GLOBALS['BATCH_SCENE'].val, 'Export each scene as an FBX file', do_batch_type_sce)
+
+ # Own dir requires OS module
+ if os:
+ GLOBALS['BATCH_OWN_DIR'] = Draw.Toggle('Own Dir', EVENT_NONE, x+20, y-125, 80, 20, GLOBALS['BATCH_OWN_DIR'].val, 'Create a dir for each exported file')
+ GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+100, y-125, 240, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ')
+ else:
+ GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+20, y-125, 320, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ')
+
+
+ Draw.EndAlign()
+ #y+=80
+
+ '''
+ Draw.BeginAlign()
+ GLOBALS['FILENAME'] = Draw.String('path: ', EVENT_NONE, x+20, y-170, 300, 20, GLOBALS['FILENAME'].val, 64, 'Prefix each file with this name ')
+ Draw.PushButton('..', EVENT_FILESEL, x+320, y-170, 20, 20, 'Select the path', do_redraw)
+ '''
+ # Until batch is added
+ #
+
+
+ #Draw.BeginAlign()
+ Draw.PushButton('Online Help', EVENT_REDRAW, x+20, y-160, 100, 20, 'Open online help in a browser window', do_help)
+ Draw.PushButton('Cancel', EVENT_EXIT, x+130, y-160, 100, 20, 'Exit the exporter', fbx_ui_exit)
+ Draw.PushButton('Export', EVENT_FILESEL, x+240, y-160, 100, 20, 'Export the fbx file', do_redraw)
+
+ #Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write)
+ #Draw.EndAlign()
+
+ # exit when mouse out of the view?
+ # GLOBALS['EVENT'] = EVENT_EXIT
+
+#def write_ui(filename):
+def write_ui():
+
+ # globals
+ GLOBALS['EVENT'] = 2
+ #GLOBALS['MOUSE'] = Window.GetMouseCoords()
+ GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()]
+ GLOBALS['FILENAME'] = ''
+ '''
+ # IF called from the fileselector
+ if filename == None:
+ GLOBALS['FILENAME'] = filename # Draw.Create(Blender.sys.makename(ext='.fbx'))
+ else:
+ GLOBALS['FILENAME'].val = filename
+ '''
+ GLOBALS['EXP_OBS_SELECTED'] = Draw.Create(1) # dont need 2 variables but just do this for clarity
+ GLOBALS['EXP_OBS_SCENE'] = Draw.Create(0)
+
+ GLOBALS['EXP_MESH'] = Draw.Create(1)
+ GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Create(1)
+ GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Create(0)
+ GLOBALS['EXP_ARMATURE'] = Draw.Create(1)
+ GLOBALS['EXP_LAMP'] = Draw.Create(1)
+ GLOBALS['EXP_CAMERA'] = Draw.Create(1)
+ GLOBALS['EXP_EMPTY'] = Draw.Create(1)
+ GLOBALS['EXP_IMAGE_COPY'] = Draw.Create(0)
+ # animation opts
+ GLOBALS['ANIM_ENABLE'] = Draw.Create(1)
+ GLOBALS['ANIM_OPTIMIZE'] = Draw.Create(1)
+ GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Create(6) # decimal places
+ GLOBALS['ANIM_ACTION_ALL'] = [Draw.Create(0), Draw.Create(1)] # not just the current action
+
+ # batch export options
+ GLOBALS['BATCH_ENABLE'] = Draw.Create(0)
+ GLOBALS['BATCH_GROUP'] = Draw.Create(1) # cant have both of these enabled at once.
+ GLOBALS['BATCH_SCENE'] = Draw.Create(0) # see above
+ GLOBALS['BATCH_FILE_PREFIX'] = Draw.Create(Blender.sys.makename(ext='_').split('\\')[-1].split('/')[-1])
+ GLOBALS['BATCH_OWN_DIR'] = Draw.Create(0)
+ # done setting globals
+
+ # Used by the user interface
+ GLOBALS['_SCALE'] = Draw.Create(1.0)
+ GLOBALS['_XROT90'] = Draw.Create(True)
+ GLOBALS['_YROT90'] = Draw.Create(False)
+ GLOBALS['_ZROT90'] = Draw.Create(False)
+
+ # horrible ugly hack so tooltips draw, dosnt always work even
+ # Fixed in Draw.UIBlock for 2.45rc2, but keep this until 2.45 is released
+ Window.SetKeyQualifiers(0)
+ while Window.GetMouseButtons(): Blender.sys.sleep(10)
+ for i in xrange(100): Window.QHandle(i)
+ # END HORRID HACK
+
+ # best not do move the cursor
+ # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()])
+
+ # hack so the toggle buttons redraw. this is not nice at all
+ while GLOBALS['EVENT'] != EVENT_EXIT:
+
+ if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val and GLOBALS['ANIM_ACTION_ALL'][1].val:
+ #Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ")
+ GLOBALS['ANIM_ACTION_ALL'][0].val = 1
+ GLOBALS['ANIM_ACTION_ALL'][1].val = 0
+
+ if GLOBALS['EVENT'] == EVENT_FILESEL:
+ if GLOBALS['BATCH_ENABLE'].val:
+ txt = 'Batch FBX Dir'
+ name = Blender.sys.expandpath('//')
+ else:
+ txt = 'Export FBX'
+ name = Blender.sys.makename(ext='.fbx')
+
+ Blender.Window.FileSelector(fbx_ui_write, txt, name)
+ #fbx_ui_write('/test.fbx')
+ break
+
+ Draw.UIBlock(fbx_ui)
+
+
+ # GLOBALS.clear()
+#test = [write_ui]
if __name__ == '__main__':
- Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx'))
- #write_ui('/test.fbx')
+ # Cant call the file selector first because of a bug in the interface that crashes it.
+ # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx'))
+ #write('/scratch/test.fbx')
+ #write_ui('/scratch/test.fbx')
+
+ if not set:
+ Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.')
+ else:
+ write_ui()
diff --git a/release/scripts/export_m3g.py b/release/scripts/export_m3g.py
index afb019fcc1e..08215b3d027 100644
--- a/release/scripts/export_m3g.py
+++ b/release/scripts/export_m3g.py
@@ -234,6 +234,19 @@ Tooltip: 'Export to M3G'
#
# * Modul shutil is not needed any longer. Exporter has its own copy_file.
# (realized and inspired by ideasman_42 and Martin Neumann)
+#
+# History 0.8
+#
+# * Blender works with SpotAngles 1..180 but M3G works only with 0..90
+# M3G use the 'half angle' (cut off angle) (Thanks to Martin Storsjö)
+#
+# * Error fixed: Texture coordinates was not calculated correct.
+# (Thanks to Milan Piskla, Vlad, Max Gilead, Regis Cosnier ...)
+#
+# * New options in GUI:
+# M3G Version 2.0 : Will export M3G files Vers. 2.0 in future
+# Game Physics: Adds Game Physics infos for NOPE API
+#
# --------------------------------------------------------------------------#
# TODO: Export only selected mesh
# TODO: Optimize Bones <--> Vertex Group mapping
@@ -1213,7 +1226,7 @@ class M3GVertexArray(M3GObject3D):
# Reverse t coordinate because M3G uses a different 2D coordinate system than Blender.
if self.uvmapping:
for i in range(0,len(self.components),2):
- self.components[i]= int(self.components[i]*(-1))
+ self.components[i+1]= int(self.components[i+1]*(-1)) #Error in Version 0.7
for i in range(len(self.components)):
if abs(self.components[i])>maxValue:raise Exception( i+". element too great/small!")
@@ -1284,7 +1297,7 @@ class M3GVertexArray(M3GObject3D):
self.blenderIndexes[key]=index
#print"blenderIndexes",self.blenderIndexes
else:
- # print "VertexArray.append: element=",element
+ print "VertexArray.append: element=",element
self.components.append(element)
class M3GVertexBuffer(M3GObject3D):
@@ -2001,7 +2014,7 @@ class M3GTranslator:
self.scene = Blender.Scene.GetCurrent()
self.world = self.translateWorld(self.scene)
- for obj in self.scene.objects:
+ for obj in self.scene.objects :
if obj.getType()=='Camera': # older Version: isinstance(obj.getData(),Types.CameraType)
self.translateCamera(obj)
elif obj.getType()=='Mesh':
@@ -2176,7 +2189,7 @@ class M3GTranslator:
if mOptions.createAmbientLight & mOptions.lightingEnabled:
lLight = M3GLight()
lLight.mode = lLight.modes['AMBIENT']
- lLight.color = self.translateRGB(AllWorlds[0].getAmb())
+ lLight.color = self.translateRGB(blWorld.getAmb())
self.nodes.append(lLight)
#TODO: Set background picture from world
@@ -2550,7 +2563,7 @@ class M3GTranslator:
mLight.intensity = lamp.energy
#SpotAngle, SpotExponent (SPOT)
if lampType == Lamp.Types.Spot:
- mLight.spotAngle = lamp.spotSize
+ mLight.spotAngle = lamp.spotSize/2
mLight.spotExponent = lamp.spotBlend
self.translateToNode(obj,mLight)
@@ -2945,6 +2958,8 @@ class OptionMgr:
self.perspectiveCorrection = rdict['perspectiveCorrection']
self.smoothShading = rdict['smoothShading']
self.exportAsJava = rdict['exportAsJava']
+ self.exportVersion2 = rdict['exportVersion2']
+ self.exportGamePhysics = rdict['exportGamePhysics']
except: self.save() # if data isn't valid, rewrite it
@@ -2958,6 +2973,8 @@ class OptionMgr:
self.perspectiveCorrection = False
self.smoothShading = True
self.exportAsJava = False
+ self.exportVersion2 = False
+ self.exportGamePhysics = False
def save(self):
d = {}
@@ -2970,7 +2987,9 @@ class OptionMgr:
d['perspectiveCorrection'] = self.perspectiveCorrection
d['smoothShading'] = self.smoothShading
d['exportAsJava'] = self.exportAsJava
-
+ d['exportVersion2'] = self.exportVersion2
+ d['exportGamePhysics'] = self.exportGamePhysics
+
Blender.Registry.SetKey('M3GExport', d, True)
@@ -2993,6 +3012,8 @@ def gui():
perspectiveCorrection = Draw.Create(mOptions.perspectiveCorrection)
smoothShading = Draw.Create(mOptions.smoothShading)
exportAsJava = Draw.Create(mOptions.exportAsJava)
+ exportVersion2 = Draw.Create(mOptions.exportVersion2)
+ exportGamePhysics = Draw.Create(mOptions.exportGamePhysics)
pupBlock = [\
('Texturing'),\
@@ -3008,7 +3029,9 @@ def gui():
('Posing'),\
('All Armature Actions', exportAllActions, 'Exports all actions for armatures'),\
('Export'),\
- ('As Java Source', exportAsJava, 'Exports scene as Java source code')
+ ('As Java Source', exportAsJava, 'Exports scene as Java source code'),\
+ ('M3G Version 2.0', exportVersion2, 'Exports M3G Version 2.0 File'),\
+ ('Game Physics', exportGamePhysics, 'Includes Game Physics infos for NOPE in export')
]
# Only execute if use didn't quit (ESC).
@@ -3022,6 +3045,8 @@ def gui():
mOptions.perspectiveCorrection = perspectiveCorrection.val
mOptions.smoothShading = smoothShading.val
mOptions.exportAsJava = exportAsJava.val
+ mOptions.exportVersion2 = exportVersion2.val
+ mOptions.exportGamePhysics = exportGamePhysics.val
mOptions.save()
if mOptions.exportAsJava:
diff --git a/release/scripts/export_mdd.py b/release/scripts/export_mdd.py
index 42a85029505..8173059ca5a 100644
--- a/release/scripts/export_mdd.py
+++ b/release/scripts/export_mdd.py
@@ -58,7 +58,8 @@ def mdd_export(filepath, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
Window.EditMode(0)
Blender.Window.WaitCursor(1)
- mesh_orig = ob.getData(mesh=1)
+ mesh_orig = Mesh.New()
+ mesh_orig.getFromObject(ob.name)
#Flip y and z
'''
diff --git a/release/scripts/export_obj.py b/release/scripts/export_obj.py
index 4c7ced2d200..8e7374f02b5 100644
--- a/release/scripts/export_obj.py
+++ b/release/scripts/export_obj.py
@@ -68,15 +68,11 @@ def fixName(name):
else:
return name.replace(' ', '_')
-# Used to add the scene name into the filename without using odd chars
-global MTL_DICT
-
# A Dict of Materials
# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
MTL_DICT = {}
def write_mtl(filename):
- global MTL_DICT
world = Blender.World.GetCurrent()
if world:
@@ -88,23 +84,14 @@ def write_mtl(filename):
file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
file.write('# Material Count: %i\n' % len(MTL_DICT))
# Write material/image combinations we have used.
- for key, mtl_mat_name in MTL_DICT.iteritems():
+ for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems():
# Get the Blender data for the material and the image.
# Having an image named None will make a bug, dont do it :)
file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname
- if key[0] == None:
- #write a dummy material here?
- file.write('Ns 0\n')
- file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour,
- file.write('Kd 0.8 0.8 0.8\n')
- file.write('Ks 0.8 0.8 0.8\n')
- file.write('d 1\n') # No alpha
- file.write('illum 2\n') # light normaly
- else:
- mat = Blender.Material.Get(key[0])
+ if mat:
file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's
file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour,
file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse
@@ -120,13 +107,20 @@ def write_mtl(filename):
else:
file.write('illum 2\n') # light normaly
+ else:
+ #write a dummy material here?
+ file.write('Ns 0\n')
+ file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour,
+ file.write('Kd 0.8 0.8 0.8\n')
+ file.write('Ks 0.8 0.8 0.8\n')
+ file.write('d 1\n') # No alpha
+ file.write('illum 2\n') # light normaly
# Write images!
- if key[1] != None: # We have an image on the face!
- img = Image.Get(key[1])
+ if img: # We have an image on the face!
file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image
- elif key[0] != None: # No face image. if we havea material search for MTex image.
+ elif not mat: # No face image. if we havea material search for MTex image.
for mtex in mat.getTextures():
if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
try:
@@ -157,26 +151,26 @@ def copy_images(dest_dir):
# Get unique image names
uniqueImages = {}
- for matname, imagename in MTL_DICT.iterkeys(): # Only use image name
+ for matname, mat, image in MTL_DICT.itervalues(): # Only use image name
# Get Texface images
- if imagename != None:
- uniqueImages[imagename] = None # Should use sets here. wait until Python 2.4 is default.
+ if image:
+ uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default.
# Get MTex images
- if matname != None:
- mat= Blender.Material.Get(matname)
+ if mat:
for mtex in mat.getTextures():
if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
- try:
- uniqueImages[mtex.tex.image.name] = None
- except:
- pass
+ image_tex = mtex.tex.image
+ if image_tex:
+ try:
+ uniqueImages[image_tex] = image_tex
+ except:
+ pass
# Now copy images
copyCount = 0
- for imageName in uniqueImages.iterkeys():
- bImage = Image.Get(imageName)
+ for bImage in uniqueImages.itervalues():
image_path = sys.expandpath(bImage.filename)
if sys.exists(image_path):
# Make a name for the target path.
@@ -187,12 +181,6 @@ def copy_images(dest_dir):
copyCount+=1
print '\tCopied %d images' % copyCount
-def veckey3d(v):
- return round(v.x, 6), round(v.y, 6), round(v.z, 6)
-
-def veckey2d(v):
- return round(v.x, 6), round(v.y, 6)
-
def write(filename, objects,\
EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_NORMALS_HQ=False,\
EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\
@@ -204,8 +192,14 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
eg.
write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
'''
+
+ def veckey3d(v):
+ return round(v.x, 6), round(v.y, 6), round(v.z, 6)
+
+ def veckey2d(v):
+ return round(v.x, 6), round(v.y, 6)
+
print 'OBJ Export path: "%s"' % filename
- global MTL_DICT
temp_mesh_name = '~tmp-mesh'
time1 = sys.time()
@@ -241,7 +235,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
# Initialize totals, these are updated each object
totverts = totuvco = totno = 1
- face_vert_index = 1 # used for uvs now
+ face_vert_index = 1
globalNormals = {}
@@ -253,7 +247,11 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn)
if not me:
continue
- faceuv= me.faceUV
+
+ if EXPORT_UV:
+ faceuv= me.faceUV
+ else:
+ faceuv = False
# We have a valid mesh
if EXPORT_TRI and me.faces:
@@ -293,14 +291,21 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
me.transform(ob_mat)
# High Quality Normals
- if EXPORT_NORMALS and EXPORT_NORMALS_HQ and faces:
- BPyMesh.meshCalcNormals(me)
+ if EXPORT_NORMALS and faces:
+ if EXPORT_NORMALS_HQ:
+ BPyMesh.meshCalcNormals(me)
+ else:
+ # transforming normals is incorrect
+ # when the matrix is scaled,
+ # better to recalculate them
+ me.calcNormals()
# # Crash Blender
#materials = me.getMaterials(1) # 1 == will return None in the list.
materials = me.materials
materialNames = []
+ materialItems = materials[:]
if materials:
for mat in materials:
if mat: # !=None
@@ -313,13 +318,13 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
# Possible there null materials, will mess up indicies
# but at least it will export, wait until Blender gets fixed.
materialNames.extend((16-len(materialNames)) * [None])
-
+ materialItems.extend((16-len(materialItems)) * [None])
# Sort by Material, then images
# so we dont over context switch in the obj file.
if EXPORT_MORPH_TARGET:
pass
- elif faceuv and EXPORT_UV:
+ elif faceuv:
try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
elif len(materials) > 1:
@@ -353,10 +358,23 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
# UV
- if faceuv and EXPORT_UV:
- for f in faces:
- for uv in f.uv:
- file.write('vt %.6f %.6f 0.0\n' % tuple(uv))
+ if faceuv:
+ uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
+
+ uv_dict = {} # could use a set() here
+ for f_index, f in enumerate(faces):
+
+ for uv_index, uv in enumerate(f.uv):
+ uvkey = veckey2d(uv)
+ try:
+ uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
+ except:
+ uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
+ file.write('vt %.6f %.6f\n' % tuple(uv))
+
+ uv_unique_count = len(uv_dict)
+ del uv, uvkey, uv_dict, f_index, uv_index
+ # Only need uv_unique_count and uv_face_mapping
# NORMAL, Smooth/Non smoothed.
if EXPORT_NORMALS:
@@ -376,18 +394,22 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
totno +=1
file.write('vn %.6f %.6f %.6f\n' % noKey)
- for f in faces:
+ if not faceuv:
+ f_image = None
+
+ for f_index, f in enumerate(faces):
f_v= f.v
+ f_smooth= f.smooth
+ f_mat = min(f.mat, len(materialNames)-1)
if faceuv:
+ f_image = f.image
f_uv= f.uv
# MAKE KEY
- if EXPORT_UV and faceuv and f.image: # Object is always true.
- key = materialNames[min(f.mat,len(materialNames)-1)], f.image.name
- #key = materialNames[f.mat], f.image.name
+ if faceuv and f_image: # Object is always true.
+ key = materialNames[f_mat], f_image.name
else:
- key = materialNames[min(f.mat,len(materialNames)-1)], None # No image, use None instead.
- #key = materialNames[f.mat], None # No image, use None instead.
+ key = materialNames[f_mat], None # No image, use None instead.
# CHECK FOR CONTEXT SWITCH
if key == contextMat:
@@ -395,16 +417,13 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
else:
if key[0] == None and key[1] == None:
# Write a null material, since we know the context has changed.
- matstring = '(null)'
+ if EXPORT_GROUP_BY_MAT:
+ file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null)
file.write('usemtl (null)\n') # mat, image
else:
- try: # Faster to try then 2x dict lookups.
- # We have the material, just need to write the context switch,
- matstring = MTL_DICT[key]
-
-
- except KeyError:
+ mat_data= MTL_DICT.get(key)
+ if not mat_data:
# First add to global dict so we can export to mtl
# Then write mtl
@@ -413,32 +432,31 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
# If none image dont bother adding it to the name
if key[1] == None:
- matstring = MTL_DICT[key] ='%s' % fixName(key[0])
+ mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
else:
- matstring = MTL_DICT[key] = '%s_%s' % (fixName(key[0]), fixName(key[1]))
-
- if EXPORT_GROUP_BY_MAT:
- file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), matstring) ) # can be mat_image or (null)
- file.write('usemtl %s\n' % matstring) # can be mat_image or (null)
+ mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
+
+ if EXPORT_GROUP_BY_MAT:
+ file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null)
+ file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null)
contextMat = key
-
- if f.smooth != contextSmooth:
- if contextSmooth: # on now off
- file.write('s off\n')
- contextSmooth = True
- else: # was off now on
+ if f_smooth != contextSmooth:
+ if f_smooth: # on now off
file.write('s 1\n')
- contextSmooth = False
+ contextSmooth = f_smooth
+ else: # was off now on
+ file.write('s off\n')
+ contextSmooth = f_smooth
file.write('f')
- if faceuv and EXPORT_UV:
+ if faceuv:
if EXPORT_NORMALS:
- if f.smooth: # Smoothed, use vertex normals
+ if f_smooth: # Smoothed, use vertex normals
for vi, v in enumerate(f_v):
file.write( ' %d/%d/%d' % (\
v.index+totverts,\
- face_vert_index + vi,\
+ totuvco + uv_face_mapping[f_index][vi],\
globalNormals[ veckey3d(v.no) ])) # vert, uv, normal
else: # No smoothing, face normals
@@ -446,20 +464,20 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
for vi, v in enumerate(f_v):
file.write( ' %d/%d/%d' % (\
v.index+totverts,\
- face_vert_index + vi,\
+ totuvco + uv_face_mapping[f_index][vi],\
no)) # vert, uv, normal
else: # No Normals
for vi, v in enumerate(f_v):
file.write( ' %d/%d' % (\
v.index+totverts,\
- face_vert_index + vi)) # vert, uv
+ totuvco + uv_face_mapping[f_index][vi])) # vert, uv
face_vert_index += len(f_v)
else: # No UV's
if EXPORT_NORMALS:
- if f.smooth: # Smoothed, use vertex normals
+ if f_smooth: # Smoothed, use vertex normals
for v in f_v:
file.write( ' %d//%d' % (\
v.index+totverts,\
@@ -486,6 +504,8 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False)
# Make the indicies global rather then per mesh
totverts += len(me.verts)
+ if faceuv:
+ totuvco += uv_unique_count
me.verts= None
file.close()
@@ -512,9 +532,8 @@ def write_ui(filename):
if not filename.lower().endswith('.obj'):
filename += '.obj'
- #if not BPyMessages.Warning_SaveOver(filename):
- # return
-
+ if not BPyMessages.Warning_SaveOver(filename):
+ return
EXPORT_APPLY_MODIFIERS = Draw.Create(1)
EXPORT_ROTX90 = Draw.Create(1)
@@ -535,7 +554,6 @@ def write_ui(filename):
# removed too many options are bad!
-
# Get USER Options
pup_block = [\
('Context...'),\
@@ -631,14 +649,14 @@ def write_ui(filename):
full_path= ''.join(context_name)
- if BPyMessages.Warning_SaveOver(full_path):
- # EXPORT THE FILE.
- write(full_path, export_objects,\
- EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
- EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\
- EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\
- EXPORT_ROTX90, EXPORT_BLEN_OBS,\
- EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_MORPH_TARGET)
+ # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad.
+ # EXPORT THE FILE.
+ write(full_path, export_objects,\
+ EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
+ EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\
+ EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\
+ EXPORT_ROTX90, EXPORT_BLEN_OBS,\
+ EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_MORPH_TARGET)
Blender.Set('curframe', orig_frame)
diff --git a/release/scripts/flt_defaultp.py b/release/scripts/flt_defaultp.py
new file mode 100644
index 00000000000..5dca8ba63d7
--- /dev/null
+++ b/release/scripts/flt_defaultp.py
@@ -0,0 +1 @@
+pal = [-256,0,16711680,-16777216,-19529984,-19726592,-19923200,-20119808,-20316416,-20578560,-20840704,-21102848,-21364992,-21692672,-22020352,-22413568,-22806784,-23200000,-23658752,-24117504,-24641792,-25166080,-25755904,-26411264,-27066624,-27787520,-28573952,-29425920,-30343424,-31326464,-32375040,-33489152,-354550016,-371458304,-388366592,-405274880,-422183168,-439156992,-456130816,-473104640,-506855680,-540672256,-574488832,-608305408,-642121984,-676004096,-709886208,-760611072,-811335936,-862060800,-912851200,-980418816,-1048051968,-1115685120,-1183383808,-1267925248,-1352466688,-1453850880,-1555300608,-1656815872,-1775173888,-1893597440,-2028863744,2130771712,-1010376448,-1043996416,-1077681920,-1111367424,-1145052928,-1178738432,-1229201152,-1279663872,-1330126592,-1380654848,-1431183104,-1498488576,-1565794048,-1633165056,-1700536064,-1784684288,-1868832512,-1969823488,-2070814464,2123096320,2005262592,1887428864,1752752384,1601298688,1449779456,1281417472,1096278272,911073536,709026048,490201344,254533888,2023680,-1380857856,-1397700608,-1431320576,-1464940544,-1498560512,-1532180480,-1565865984,-1599551488,-1650014208,-1700476928,-1750939648,-1801402368,-1851865088,-1919170560,-1986476032,-2053781504,-2121086976,2089797632,2005649408,1904723968,1803798528,1686030336,1568262144,1450493952,1315883008,1164494848,1013041152,844810240,659736576,457885696,239192064,3655680,-1767919872,-1784762624,-1801605376,-1818448128,-1852068096,-1885688064,-1919308032,-1952928000,-1986547968,-2020167936,-2070565120,-2120962304,2123542272,2073079552,2022616832,1955376896,1888136960,1820897024,1736879872,1652797184,1568714496,1467854592,1366994688,1249357568,1131654912,997175040,862695168,711372544,560049920,391950080,207007488,5287680,2139657728,2122880512,2106103296,2089326080,2072548864,2055771648,2022217216,1988662784,1955108352,1921553920,1887933952,1854313984,1803916800,1753519616,1703122432,1652725248,1602328064,1535153664,1467979264,1400804864,1316853248,1232901632,1148950016,1048221184,947426816,846632448,729060864,611489280,477140480,326014464,174888448,6919680,1837268224,1820491008,1803713792,1786936576,1770159360,1753382144,1736604928,1719827712,1686273280,1652718848,1619164416,1585609984,1552055552,1518501120,1468169472,1417837824,1367506176,1317174528,1266842880,1199734016,1132625152,1065516288,998407424,914521344,830635264,729971968,629308672,528645376,411204864,293764352,159546624,8551680,-2086957824,-2103735040,-2120512256,-2137289472,2140900608,2107346176,2073791744,2040237056,2006682368,1973127680,1939572992,1906018304,1855686400,1805354496,1755022592,1704690688,1654358784,1587249664,1520140544,1453031424,1369145088,1285258496,1201371904,1100708096,1000044288,882603264,765162240,630943744,496725248,345729536,177956608,10183680,-1699438080,-1716215552,-1732993024,-1766547712,-1800102400,-1833657088,-1867211776,-1900766464,-1934321152,-1967875840,-2018207744,-2068539904,-2118872064,2125763072,2058653696,1991544320,1924434944,1857325568,1773438720,1689551872,1588887808,1488223744,1387559424,1270117888,1152676352,1018457600,884238592,733242368,565468672,397694976,213144064,11815680,-1311918848,-1345473536,-1379028224,-1412582912,-1446137600,-1479692544,-1513247488,-1546802432,-1597134592,-1647466752,-1697798912,-1748131072,-1798463488,-1865573120,-1932682752,-1999792384,-2083679232,2127400960,2043513856,1942849536,1842184960,1724743168,1607301376,1473082112,1338862848,1187866112,1020092160,852317952,667766528,466437632,248331264,13447680,-924399104,-957954048,-991508992,-1025063936,-1058618880,-1092173824,-1142505984,-1192838144,-1243170560,-1293502976,-1343835392,-1410945024,-1478054656,-1545164544,-1629051648,-1712938752,-1796826112,-1897490688,-1998155264,-2098820096,2078705152,1961262848,1827043328,1676046336,1525049344,1357274880,1172722944,971393792,753287168,518403072,283518720,15079680,-570434304,-603989248,-637544192,-671099136,-704654080,-754986496,-805318912,-855651328,-905983744,-973093632,-1040203520,-1107313408,-1174423296,-1258310656,-1342198016,-1442862848,-1543527680,-1644192512,-1761634816,-1879077120,-2013296896,2147450624,1996453376,1828678656,1660903936,1476351744,1275022080,1056914944,822030336,570368256,301928704,16711680,-503325440,-536880384,-570435328,-603990272,-637545216,-671100416,-721432832,-771765248,-822097664,-872430336,-922763008,-989872896,-1056982784,-1124092928,-1191203072,-1275090688,-1358978304,-1459643136,-1560308224,-1660973312,-1778415872,-1895858432,-2030078464,2113891328,1962893824,1795118848,1610566400,1426013696,1224683520,1006575872,771690752,520028160,-452993792,-469771520,-503326464,-536881408,-570436352,-603991552,-637546752,-671101952,-721434368,-771767040,-822099712,-872432384,-922765056,-989875200,-1056985344,-1124095744,-1191206144,-1275093760,-1358981632,-1459646720,-1560312064,-1677754624,-1795197440,-1912640512,-2046860800,2097108736,1946110720,1778335232,1593782272,1392451840,1174343936,939458560,-419439360,-436217088,-452994816,-469772544,-503327488,-536882688,-570437888,-603993088,-637548288,-671103744,-721436416,-771769088,-822101760,-872434688,-922767616,-989878016,-1056988416,-1124098816,-1207986688,-1291874560,-1375762688,-1476428032,-1577093632,-1694536704,-1811979776,-1946200320,-2080421120,2063547904,1912549376,1744773376,1560219904,1358888960,-385884928,-402662656,-419440384,-436218112,-452995840,-469773824,-503329024,-536884224,-570439424,-603994880,-637550336,-671105792,-721438464,-771771392,-822104320,-872437504,-922770688,-989881088,-1056991744,-1124102400,-1191213312,-1275101440,-1358989824,-1459655680,-1560321536,-1677764864,-1795208448,-1912652288,-2046873600,2097094912,1946095872,1778319360,-335553280,-352331008,-369108736,-385886464,-402664192,-419442176,-436220160,-452998144,-486553344,-520108800,-553664256,-587219712,-620775168,-654330880,-687886592,-738219776,-788552960,-838886144,-889219584,-939553024,-1006663936,-1073774848,-1140886016,-1224774656,-1308663296,-1392552192,-1493218560,-1593885184,-1711329280,-1828773632,-1962995456,-2097217536,-285221632,-301999360,-318777088,-335554816,-352332544,-369110528,-385888512,-402666496,-419444480,-436222720,-453000960,-469779200,-503334656,-536890368,-570446080,-604002048,-637558016,-671113984,-721447424,-771780864,-822114560,-872448256,-922782208,-989893632,-1057005056,-1124116736,-1191228672,-1275118080,-1359007744,-1459674880,-1560342272,-1677787136,-234889984,-234890496,-251668224,-268445952,-285223680,-302001664,-318779648,-335557632,-352335616,-369113856,-385892096,-402670336,-419448576,-436227072,-453005568,-469784320,-503340288,-536896256,-570452480,-604008704,-637565184,-671121664,-704678400,-755012608,-805346816,-855681280,-906016000,-973128192,-1040240640,-1107353344,-1174466304,-1258356736,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-251673344,-268451584,-285229824,-302008064,-318786560,-335565056,-352343808,-369122560,-385901312,-402680320,-419459328,-436238592,-453017856,-486574592,-520131584,-553688576,-587245824,-620803328,-654361088,-687919104,-738254592,-788590336,-838926336,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-234896128,-234897152,-234898176,-234899200,-234900480,-234901760,-234903296,-234904832,-234906368,-234908160,-234909952,-234912000,-251691264,-268470784,-285250560,-302030336,-318810368,-335590656,-352371200,-369152000,-385933056,-402714368,-419495936,-8960,-9472,-9984,-10496,-11008,-11776,-12544,-13312,-14080,-15104,-16128,-17152,-18176,-19456,-20736,-22272,-23808,-25344,-27136,-28928,-30976,-33024,-35328,-37888,-40448,-43264,-46336,-49664,-53248,-57088,-61184,-65536,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-930816,-931584,-932608,-933632,-934656,-935680,-936960,-938240,-939776,-941312,-1008384,-1075712,-1143040,-1210624,-1278208,-1346048,-1414144,-1482240,-1550592,-1619200,-1688064,-1757184,-1826560,-1896192,-2031616,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-996352,-1062656,-1129216,-1195776,-1262336,-1328896,-1395712,-1462528,-1529600,-1596672,-1663744,-1731072,-1798400,-1865984,-1999104,-2132480,-2266112,-2399744,-2533632,-2667776,-2867712,-3067904,-3268352,-3469056,-3670016,-926464,-992512,-1058560,-1124608,-1190656,-1256960,-1323264,-1389568,-1455872,-1522432,-1588992,-1655552,-1722112,-1788928,-1855744,-1988352,-2120960,-2253568,-2386432,-2519296,-2652416,-2785536,-2984448,-3183616,-3382784,-3582208,-3847424,-4112896,-4378624,-4644608,-4976384,-5308416,-1188608,-1254656,-1320704,-1386752,-1452800,-1519104,-1585408,-1651712,-1718016,-1784576,-1851136,-1983232,-2115328,-2247680,-2380032,-2512640,-2645248,-2777856,-2976256,-3174656,-3373312,-3571968,-3836416,-4101120,-4365824,-4630784,-4961536,-5292544,-5689344,-6086400,-6483712,-6946816,-1385216,-1451264,-1517312,-1583360,-1649408,-1715712,-1782016,-1848320,-1980160,-2112256,-2244352,-2376448,-2508544,-2640896,-2838784,-3036928,-3235072,-3433216,-3631616,-3895552,-4159744,-4423936,-4688384,-5018624,-5348864,-5744896,-6141184,-6537728,-7000064,-7462656,-7991040,-8585216,-1581824,-1647872,-1713920,-1779968,-1846016,-1977856,-2109696,-2241536,-2373376,-2505472,-2637568,-2769664,-2967296,-3165184,-3363072,-3561216,-3759360,-4023040,-4286976,-4550912,-4880640,-5210368,-5540352,-5936128,-6331904,-6793472,-7255296,-7782912,-8310784,-8904448,-9563904,-10223616,-1712896,-1778944,-1844992,-1976576,-2108160,-2240000,-2371840,-2503680,-2635520,-2767616,-2965248,-3162880,-3360512,-3558400,-3821824,-4085504,-4349184,-4612864,-4942336,-5271808,-5667072,-6062336,-6457856,-6919168,-7380480,-7907584,-8434944,-9028096,-9687040,-10346240,-11071232,-11862016,-1843968,-1975552,-2107136,-2238720,-2370304,-2502144,-2633984,-2765824,-2963200,-3160832,-3358464,-3556096,-3753728,-4017152,-4280576,-4544256,-4873472,-5202688,-5532160,-5927168,-6322432,-6783232,-7244288,-7771136,-8297984,-8890624,-9549056,-10207744,-10932224,-11722496,-12578560,-13500416,-1975040,-2106624,-2238208,-2369792,-2501376,-2633216,-2830592,-3027968,-3225344,-3422976,-3620608,-3883776,-4146944,-4410368,-4673792,-5003008,-5332224,-5726976,-6121984,-6582528,-7043328,-7504128,-8030720,-8623104,-9215488,-9873664,-10597632,-11387392,-12242944,-13164288,-14085888,-15138816,-2237184,-2368768,-2500352,-2631936,-2763520,-2960896,-3158272,-3355648,-3553024,-3816192,-4079360,-4342528,-4605696,-4934656,-5263616,-5658368,-6053120,-6447872,-6908416,-7368960,-7895296,-8421632,-9013760,-9671680,-10329600,-11053312,-11842816,-12698112,-13619200,-14606080,-15658752,-16777216] \ No newline at end of file
diff --git a/release/scripts/flt_export.py b/release/scripts/flt_export.py
index 283c24a3ad0..5e69e203374 100755..100644
--- a/release/scripts/flt_export.py
+++ b/release/scripts/flt_export.py
@@ -1,45 +1,25 @@
#!BPY
""" Registration info for Blender menus:
Name: 'OpenFlight (.flt)...'
-Blender: 237
+Blender: 245
Group: 'Export'
Tip: 'Export to OpenFlight v16.0 (.flt)'
"""
-__author__ = "Greg MacDonald"
-__version__ = "1.2 10/20/05"
+__author__ = "Greg MacDonald, Geoffrey Bantle"
+__version__ = "2.0 11/21/07"
__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/")
__bpydoc__ = """\
This script exports v16.0 OpenFlight files. OpenFlight is a
registered trademark of MultiGen-Paradigm, Inc.
-Run from "File->Export" menu.
-
-Options are available from Blender's "Scripts Config Editor," accessible through
-the "Scripts->System" menu from the scripts window.
-
-Features:<br>
-* Heirarchy retained.<br>
-* Normals retained.<br>
-* First texture exported.<br>
-* Diffuse material color is exported as the face color, material color, or both
-depending on the option settings.<br>
-* Double sided faces are exported as two faces.<br>
-* Object transforms exported.
-
-Things To Be Aware Of:<br>
-* Object names are exported, not mesh or data names.
-* Material indices that don't have a material associated with them will confuse the
-exporter. If a warning appears about this, correct it by deleting the offending
-material indices in Blender.
-
-What's Not Handled:<br>
-* Animations.<br>
-* Vetex colors.<br>
+Feature overview and more availible at:
+http://wiki.blender.org/index.php/Scripts/Manual/Export/openflight_flt
"""
# flt_export.py is an OpenFlight exporter for blender.
-# Copyright (C) 2005 Greg MacDonald
+#
+# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -56,29 +36,87 @@ What's Not Handled:<br>
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import Blender
+from Blender import Modifier
+import os.path
+import flt_properties
+import flt_defaultp as defaultp
from flt_filewalker import FltOut
+from flt_filewalker import FileFinder
+from flt_properties import *
+import shutil
+
+FF = FileFinder()
+records = process_recordDefs()
class ExporterOptions:
def __init__(self):
- self.defaults = { 'Diffuse Color To OpenFlight Material': False,
- 'Diffuse Color To OpenFlight Face': True}
+ self.verbose = 1
+ self.tolerance = 0.001
+ self.writevcol = True
- d = Blender.Registry.GetKey('flt_export', True)
+ #new stuff
+ self.export_shading = 0
+ self.shading_default = 45.0
+ self.basepath = os.path.dirname(Blender.Get('filename'))
+ self.scale = 1.0
- if d == None or d.keys() != self.defaults.keys():
- d = self.defaults
- Blender.Registry.SetKey('flt_export', d, True)
+ #set externals path
+ if(os.path.exists(os.path.join(self.basepath,'externals'))):
+ self.externalspath = os.path.join(self.basepath,'externals')
+ else:
+ self.externalspath = self.basepath
- self.verbose = 1
- self.tolerance = 0.001
- self.use_mat_color = d['Diffuse Color To OpenFlight Material']
- self.use_face_color = d['Diffuse Color To OpenFlight Face']
+ self.doxrefs = 1
+
+ #texture options
+ if(os.path.exists(os.path.join(self.basepath,'textures'))):
+ self.texturespath = os.path.join(self.basepath,'textures')
+ else:
+ self.texturespath = self.basepath
+
+ #misc
+ self.write_attrib_files = 0
+ self.copy_textures = 0
+ self.export_transform = 0
+ self.flattenmesh = False
+ self.xapp = 1
+ reg = Blender.Registry.GetKey('flt_export',1)
+ if(reg and 'xappath' in reg.keys()):
+ self.xappath = reg['xappath']
+ else:
+ self.xappath = ''
options = ExporterOptions()
+tex_files = dict() #a list of (possibly) modified texture path names
+
+tex_layers = ['Layer0', 'Layer1', 'Layer2', 'Layer3', 'Layer4', 'Layer5', 'Layer6', 'Layer7']
+mask = 2147483648
+mtexmasks = []
+for i in xrange(7):
+ mtexmasks.append(mask)
+ mask = mask / 2
FLOAT_TOLERANCE = options.tolerance
+#need to move all this stuff to flt_properties.py.
identity_matrix = [[1.0, 0.0, 0.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]]
+alltypes = [2,4,14,11,73,63,111]
+childtypes = {
+ 2 : [111,2,73,4,14,63],
+ 4 : [111],
+ 73 : [111,2,73,4,14,63],
+ 63 : [],
+ 14 : [111,2,73,4,14,63],
+ 111 : []
+}
+recordlen = {
+ 2: 44,
+ 4: 28,
+ 73: 80,
+ 63: 216,
+ 14: 384,
+ 111: 156
+}
def is_identity(m):
for i in xrange(4):
@@ -102,13 +140,47 @@ class MaterialDesc:
self.alpha = 1.0 # Range is [0.0, 1.0]
class VertexDesc:
- def __init__(self, co=None, no=None, uv=None):
+ def __init__(self, co=None, no=None, uv=None, fltindex=None,cindex=None):
if co: self.x, self.y, self.z = tuple(co)
else: self.x = self.y = self.z = 0.0
if no: self.nx, self.ny, self.nz = tuple(no)
else: self.nx = self.ny = self.nz = 0.0
if uv: self.u, self.v = tuple(uv)
else: self.u = self.v = 0.0
+ if cindex: self.cindex = cindex
+ else: self.cindex = 127
+ self.fltindex = fltindex
+ self.accum = 0
+
+class shadowVert:
+ def __init__(self,bvert,object,world,normal):
+ global options
+
+ self.co = Blender.Mathutils.Vector(bvert.co[0],bvert.co[1],bvert.co[2])
+ #if world:
+ # vec = self.co
+ # vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale
+ # self.co = Blender.Mathutils.TranslationMatrix(vec) * (self.co * object.getMatrix('worldspace'))
+
+ if normal:
+ #if world:
+ # self.no = Blender.Mathutils.Vector(normal * object.getMatrix('worldspace')).normalize()
+ #else:
+ self.no = Blender.Mathutils.Vector(normal[0],normal[1],normal[2])
+
+ else:
+ #if world:
+ #self.no = Blender.Mathutils.Vector(bvert.no * object.getMatrix('worldspace')).normalize()
+ #else:
+ self.no = Blender.Mathutils.Vector(bvert.no[0],bvert.no[1],bvert.no[2])
+
+ #do scaling factor
+ #if options.scale != 1.0:
+ #self.co[0] = self.co[0] * options.scale
+ #self.co[1] = self.co[1] * options.scale
+ #self.co[2] = self.co[2] * options.scale
+
+ self.index = bvert.index
class GlobalResourceRepository:
def new_face_name(self):
@@ -121,44 +193,104 @@ class GlobalResourceRepository:
def request_vertex_desc(self, i):
return self.vertex_lst[i]
- def request_vertex_index(self, desc):
- match = None
- for i, v in enumerate(self.vertex_lst):
- if\
- abs(v.x - desc.x) > FLOAT_TOLERANCE or\
- abs(v.y - desc.y) > FLOAT_TOLERANCE or\
- abs(v.z - desc.z) > FLOAT_TOLERANCE or\
- abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\
- abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\
- abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\
- abs(v.u - desc.u) > FLOAT_TOLERANCE or\
- abs(v.v - desc.v) > FLOAT_TOLERANCE:
- pass
- else:
- match = i
- break
+ def request_vertex_index(self, object, mesh, face, vfindex, uvok,cindex):
- if match != None:
- return match
- else:
- self.vertex_lst.append(desc)
- return len(self.vertex_lst) - 1
+ flatShadeNorm = None
+ vno = None
- def request_texture_index(self, filename):
+
+ if type(face) is list:
+ vertex = face[vfindex]
+ elif str(type(face)) == "<type " + "'Blender MVert'>":
+ vertex = face
+ vno = Blender.Mathutils.Vector(0.0,0.0,1.0)
+ elif str(type(face)) == "<type " + "'Blender MEdge'>":
+ if vfindex == 1:
+ vertex = face.v1
+ elif vfindex == 2:
+ vertex = face.v2
+ elif str(type(face)) == "<type " + "'Blender MFace'>":
+ if not face.smooth:
+ flatShadeNorm = face.no
+ vertex = face.v[vfindex]
+ else:
+ return None
+
+ if not self.namehash.has_key(object.name):
+ self.namehash[object.name] = dict()
+ indexhash = self.namehash[object.name]
+
+ #export in global space? THIS HAS BEEN MADE REDUNDANT... REMOVE ME
+ if not options.export_transform:
+ vertex = shadowVert(vertex,object,True,flatShadeNorm)
+ else:
+ vertex = shadowVert(vertex,object,False,flatShadeNorm)
+
+ if vno:
+ vertex.no = vno
+
+
+ #Check to see if this vertex has been visited before. If not, add
+ if not indexhash.has_key(vertex.index):
+ if uvok:
+ newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex)
+ else:
+ newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex)
+
+ indexhash[vertex.index] = [newvdesc]
+ self.vertex_lst.append(newvdesc)
+ self.nextvindex = self.nextvindex + 1
+ return newvdesc.fltindex
+
+ else:
+ desclist = indexhash[vertex.index]
+ if uvok:
+ faceu = face.uv[vfindex][0]
+ facev = face.uv[vfindex][1]
+ else:
+ faceu = 0.0
+ facev = 0.0
+ for vdesc in desclist:
+ if\
+ abs(vdesc.x - vertex.co[0]) > FLOAT_TOLERANCE or\
+ abs(vdesc.y - vertex.co[1]) > FLOAT_TOLERANCE or\
+ abs(vdesc.z - vertex.co[2]) > FLOAT_TOLERANCE or\
+ abs(vdesc.nx - vertex.no[0]) > FLOAT_TOLERANCE or\
+ abs(vdesc.ny - vertex.no[1]) > FLOAT_TOLERANCE or\
+ abs(vdesc.nz - vertex.no[2]) > FLOAT_TOLERANCE or\
+ vdesc.cindex != cindex or\
+ abs(vdesc.u - faceu) > FLOAT_TOLERANCE or\
+ abs(vdesc.v - facev) > FLOAT_TOLERANCE:
+ pass
+ else:
+ return vdesc.fltindex
+
+ #if we get this far, we didnt find a match. Add a new one and return
+ if uvok:
+ newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex)
+ else:
+ newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex)
+ indexhash[vertex.index].append(newvdesc)
+ self.vertex_lst.append(newvdesc)
+ self.nextvindex = self.nextvindex + 1
+ return newvdesc.fltindex
+
+
+ def request_texture_index(self, image):
match = None
for i in xrange(len(self.texture_lst)):
- if self.texture_lst[i] != filename:
+ if self.texture_lst[i] != image:
continue
match = i
break
if match != None:
return match
else:
- self.texture_lst.append(filename)
+ self.texture_lst.append(image)
return len(self.texture_lst) - 1
def request_texture_filename(self, index):
- return self.texture_lst[index]
+ return Blender.sys.expandpath(self.texture_lst[index].getFilename())
def texture_count(self):
return len(self.texture_lst)
@@ -239,7 +371,11 @@ class GlobalResourceRepository:
return len(self.color_lst)
def __init__(self):
+ #Vertex handling
self.vertex_lst = []
+ self.nextvindex = 0
+ self.namehash = dict()
+
self.texture_lst = []
self.material_lst = []
self.color_lst = [[255, 255, 255]]
@@ -253,7 +389,6 @@ class Node:
if self.object:
if options.verbose >= 2:
print '\t' * level[0], self.name, self.object.type
-
level[0] += 1
for child in self.children:
@@ -288,183 +423,537 @@ class Node:
self.header.fw.write_ushort(length+5) # Length of record
self.header.fw.write_string(name, length+1) # name + zero terminator
+ def write_comment(self,comment):
+ length = len(comment)
+ if length >= 65535:
+ comment = comment[:65530]
+ length = len(comment)
+
+ pad = (length % 4) - 1
+ if pad < 0:
+ pad = None
+ reclength = length + 5
+ else:
+ reclength = length + 5 + pad
+
+ self.header.fw.write_short(31) # Comment Opcode
+ self.header.fw.write_ushort(reclength) # Length of record is 4 + comment length + null terminator + pad
+ self.header.fw.write_string(comment,length+1) # comment + zero terminator
+ if pad:
+ self.header.fw.pad(pad) # pad to multiple of 4 bytes
+
# Initialization sets up basic tree structure.
- def __init__(self, parent, header, object, object_lst):
+ def __init__(self, parent, header, object,props):
+ global options
+
self.header = header
self.object = object
if object:
self.name = self.object.name
- self.matrix = self.object.getMatrix('localspace')
+ if not options.export_transform:
+ oloc = Blender.Mathutils.Vector(object.getLocation('worldspace'))
+ vec = Blender.Mathutils.Vector(oloc[0] * options.scale, oloc[1] * options.scale, oloc[2] * options.scale) #scale
+ self.matrix = self.object.getMatrix('worldspace') * Blender.Mathutils.TranslationMatrix(vec - oloc)
+ else:
+ self.matrix = self.object.getMatrix('localspace') #do matrix mult here.
+ self.props = props
+ self.child_objects = self.header.parenthash[object.name]
else:
self.name = 'no name'
self.matrix = None
-
+ self.props = None
+ self.child_objects = self.header.child_objects
+
self.children = []
self.parent = parent
if parent:
parent.children.append(self)
-
- left_over = object_lst[:]
- self.child_objects = []
-
- # Add children to child list and remove from left_over list.
- # Pop is faster then remove
- i = len(object_lst)
- while i:
- i-=1
- if object_lst[i].parent == object:
- self.child_objects.append(left_over.pop(i))
-
# Spawn children.
- self.has_object_child = False # For Database class.
for child in self.child_objects:
- if child.type == 'Mesh':
- BlenderMesh(self, header, child, left_over)
- self.has_object_child = True
- else: # Treat all non meshes as emptys
- BlenderEmpty(self, header, child, left_over)
-
+ if(not child.restrictDisplay):
+ childprops = None
+ type = None
+ if not child.properties.has_key('FLT'):
+ if child.type == 'Empty':
+ if child.DupGroup:
+ childprops = FLTXRef.copy()
+ type = 63
+ else:
+ childprops = FLTGroup.copy()
+ type = 2
+ elif child.type == 'Mesh':
+ if self.header.childhash[child.name] or not child.parent:
+ childprops = FLTGroup.copy()
+ type = 2
+ else:
+ childprops = FLTObject.copy()
+ type = 4
+
+ else:
+ childprops = dict()
+ for prop in child.properties['FLT']:
+ childprops[prop] = child.properties['FLT'][prop]
+ type = child.properties['FLT']['type']
+
+ if type in self.childtypes and type in alltypes:
+ Newnode = FLTNode(self,header,child,childprops,type)
+ if child.type == 'Mesh':
+ self.header.mnodes.append(Newnode)
class FaceDesc:
def __init__(self):
self.vertex_index_lst = []
+ self.mface = None
self.texture_index = -1
self.material_index = -1
self.color_index = 127
-
-class BlenderMesh(Node):
- def blender_export(self):
- Node.blender_export(self)
-
- mesh = self.object.getData()
- mesh_hasuv = mesh.hasFaceUV()
- # Gather materials and textures.
- tex_index_lst = []
- mat_index_lst = []
- color_index_lst = []
- materials = mesh.getMaterials()
-
- if not materials:
- materials = [Blender.Material.New()]
-
- for mat in materials:
- # Gather Color.
- if options.use_face_color:
- color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol()))
+ self.renderstyle = 0
+ self.twoside = 0
+ self.name = None #uses next FLT name if not set... fix resolution of conflicts!
+ self.billboard = 0
+
+ #Multi-Tex info. Dosn't include first UV Layer!
+ self.uvlayer = list() #list of list of tuples for UV coordinates.
+ self.images = list() #list of texture indices for seperate UV layers
+ self.mtex = list()
+ self.subface = None #can either be 'Push' or 'Pop'
+
+def edge_get_othervert(vert, edge):
+ if edge.v1 == vert:
+ return edge.v2
+ elif edge.v2 == vert:
+ return edge.v1
+ return None
+
+class FLTNode(Node):
+ def walkLoop(self, targetvert, startvert, startedge, edgelist, visited, vedges, closeloop):
+ loop = [targetvert]
+
+ curvert = startvert
+ curedge = startedge
+ visited[curedge] = True
+ found = False
+
+ while not found:
+ loop.append(curvert)
+ disk = vedges[curvert.index]
+ if not closeloop:
+ if len(disk) == 1:
+ visited[curedge] = True
+ break
else:
- color_index_lst.append(127) # white
- # Gather Texture.
- mtex_lst = mat.getTextures()
-
- index = -1
- mtex = mtex_lst[0] # Not doing multi-texturing at the moment.
- if mtex != None:
- tex = mtex_lst[0].tex
- if tex != None:
- image = tex.getImage()
- if image != None:
- filename = image.getFilename()
- index = self.header.GRR.request_texture_index(filename)
-
- tex_index_lst.append(index)
-
- # Gather Material
- mat_desc = MaterialDesc()
- mat_desc.name = mat.name
- mat_desc.alpha = mat.getAlpha()
- mat_desc.shininess = mat.getSpec() * 64.0 # 2.0 => 128.0
- if options.use_mat_color:
- mat_desc.diffuse = mat.getRGBCol()
+ if len(disk) < 2: #what?
+ visited[curedge] = True
+ return None
+
+ if disk[0] == curedge:
+ curedge = disk[1]
+ else:
+ curedge = disk[0]
+ if curedge.v1.index == curvert.index:
+ curvert = curedge.v2
else:
- mat_desc.diffuse = [1.0, 1.0, 1.0]
+ curvert = curedge.v1
- mat_desc.specular = mat.getSpecCol()
- amb = mat.getAmb()
- mat_desc.ambient = [amb, amb, amb]
- emit = mat.getEmit()
- mat_desc.emissive = [emit, emit, emit]
+ visited[curedge] = True
+
+ if(curvert == targetvert):
+ found = True
+
+ return loop
+
+ def buildVertFaces(self,vertuse):
+ for vert in self.exportmesh.verts:
+ if vertuse[vert.index][0] == False and vertuse[vert.index][1] == 0:
+ face_desc = FaceDesc()
+ face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, vert, 0,0,0))
+ face_desc.renderstyle = 3
+ face_desc.color_index = 227
+ self.face_lst.append(face_desc)
- mat_index_lst.append(self.header.GRR.request_material_index(mat_desc))
+ def buildEdgeFaces(self,vertuse):
+ for edge in self.exportmesh.edges:
+ v1 = vertuse[edge.v1.index]
+ v2 = vertuse[edge.v2.index]
+ if v1[0] == False and v2[0] == False:
+ if v1[1] == 1 and v2[1] == 1:
+ face_desc = FaceDesc()
+ face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 1, 0,0))
+ face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 2, 0,0))
+ face_desc.renderstyle = 3
+ face_desc.color_index = 227
+ self.face_lst.append(face_desc)
+
+
+ def vertwalk(self, startvert, loop, disk, visited):
+ visited[startvert] = True
+ for edge in disk[startvert]:
+ othervert = edge_get_othervert(startvert, edge)
+ if not visited[othervert]:
+ loop.append(othervert)
+ self.vertwalk(othervert,loop,disk,visited)
+
+ def buildOpenFacesNew(self, vertuse):
+ wireverts = list()
+ wiredges = list()
+ visited = dict()
+ disk = dict()
+ loops = list()
+
+ for edge in self.exportmesh.edges:
+ v1 = vertuse[edge.v1.index]
+ v2 = vertuse[edge.v2.index]
+ if v1[0] == False and v2[0] == False:
+ if v1[1] < 3 and v2[1] < 3:
+ wireverts.append(edge.v1)
+ wireverts.append(edge.v2)
+ wiredges.append(edge)
+
+ #build disk data
+ for vert in wireverts:
+ visited[vert] = False
+ disk[vert] = list()
+ for edge in wiredges:
+ disk[edge.v1].append(edge)
+ disk[edge.v2].append(edge)
+
+ #first pass: do open faces
+ for vert in wireverts:
+ if not visited[vert] and vertuse[vert.index][1] == 1:
+ visited[vert] = True
+ loop = [vert]
+ othervert = edge_get_othervert(vert, disk[vert][0])
+ self.vertwalk(othervert, loop, disk, visited)
+ if len(loop) > 2: loops.append( ('Open', loop) )
+
+ for vert in wireverts:
+ if not visited[vert]:
+ visited[vert] = True
+ loop = [vert]
+ othervert = edge_get_othervert(vert,disk[vert][0])
+ self.vertwalk(othervert, loop, disk, visited)
+ if len(loop) > 2: loops.append( ('closed', loop) )
+
+ #now go through the loops and append.
+ for l in loops:
+ (type, loop) = l
+ face_desc = FaceDesc()
+ for i,vert in enumerate(loop):
+ face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,loop,i,0,0))
+ if type == 'closed':
+ face_desc.renderstyle = 2
+ else:
+ face_desc.renderstyle = 3
+ face_desc.color_index = 227
+ self.face_lst.append(face_desc)
- # Faces described as lists of indices into the GRR's vertex_lst.
- for face in mesh.faces:
-
- face_v = face.v # Faster access
-
- # Create vertex description list for each face.
- if mesh_hasuv:
- vertex_lst = [VertexDesc(v.co, v.no, face.uv[i]) for i, v in enumerate(face_v)]
- else:
- vertex_lst = [VertexDesc(v.co, v.no) for i, v in enumerate(face_v)]
+ def sortFLTFaces(self,a,b):
+ aindex = a.getProperty("FLT_ORIGINDEX")
+ bindex = b.getProperty("FLT_ORIGINDEX")
+
+ if aindex > bindex:
+ return 1
+ elif aindex < bindex:
+ return -1
+ return 0
+
+ def buildNormFaces(self):
+
+ global options
+ meshlayers = self.exportmesh.getUVLayerNames()
+ oldlayer = self.exportmesh.activeUVLayer
+ uvok = 0
+ subfaceok = 0
+ subfacelevel = 0
+
+ #special case
+ if self.exportmesh.faceUV and len(meshlayers) == 1:
+ uvok = 1
+ elif self.exportmesh.faceUV and tex_layers[0] in meshlayers:
+ self.exportmesh.activeUVLayer = tex_layers[0]
+ uvok = 1
+
+ #Sort faces according to the subfaces/FLT indices
+ if "FLT_ORIGINDEX" in self.exportmesh.faces.properties and "FLT_SFLEVEL" in self.exportmesh.faces.properties:
+ exportfaces = list()
+ for face in self.exportmesh.faces:
+ exportfaces.append(face)
+ exportfaces.sort(self.sortFLTFaces)
+ subfaceok = 1
+ else:
+ exportfaces = self.exportmesh.faces
+ # Faces described as lists of indices into the GRR's vertex_lst.
+ for face in exportfaces:
+ descs = list()
+ #first we export the face as normal
index_lst = []
- for vert_desc in vertex_lst:
- index_lst.append(self.header.GRR.request_vertex_index(vert_desc))
-
+ face_v = face.verts
+ for i, v in enumerate(face_v):
+ index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,face,i,uvok,0))
face_desc = FaceDesc()
face_desc.vertex_index_lst = index_lst
+ face_desc.mface = face
+ descs.append(face_desc)
- if face.materialIndex < len(materials):
- face_desc.color_index = color_index_lst[face.materialIndex]
- face_desc.texture_index = tex_index_lst[face.materialIndex]
- face_desc.material_index = mat_index_lst[face.materialIndex]
- else:
- if options.verbose >=1:
- print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.'
+ #deal with subfaces
+ if subfaceok:
+ fsflevel = face.getProperty("FLT_SFLEVEL")
+ for face_desc in descs:
+ if fsflevel > subfacelevel:
+ face_desc.subface = 'Push'
+ subfacelevel = fsflevel
+ elif fsflevel < subfacelevel:
+ face_desc.subface = 'Pop'
+ subfacelevel = fsflevel
+
+
+ if uvok and (face.mode & Blender.Mesh.FaceModes.TWOSIDE):
+ face_desc.renderstyle = 1
+ for face_desc in descs:
+ if "FLT_COL" in self.exportmesh.faces.properties:
+ color_index = face.getProperty("FLT_COL")
+# if(color_index < 127):
+# color_index = 127 #sanity check for face color indices
+ if(color_index == 0):
+ color_index = 127
+ face_desc.color_index = color_index
+ else:
+ face_desc.color_index = 127
+ if "FLT_ID" in self.exportmesh.faces.properties:
+ face_desc.name = face.getProperty("FLT_ID") #need better solution than this.
+
+ if uvok and face.mode & Blender.Mesh.FaceModes["BILLBOARD"]:
+ face_desc.billboard = 1
+
+ self.face_lst.append(face_desc)
+ if uvok:
+ self.exportmesh.activeUVLayer = oldlayer
- self.face_lst.append(face_desc)
+ def buildTexData(self):
+
+ meshlayers = self.exportmesh.getUVLayerNames()
+ oldlayer = self.exportmesh.activeUVLayer
+ uvok = 0
+
+ if self.exportmesh.faceUV and len(meshlayers) == 1:
+ uvok = 1
+ if self.exportmesh.faceUV and tex_layers[0] in meshlayers:
+ self.exportmesh.activeUVLayer = tex_layers[0]
+ uvok = 1
+
+ if uvok:
+ #do base layer. UVs have been stored on vertices directly already.
+ for i, face in enumerate(self.face_lst):
+ if face.mface:
+ mface = face.mface
+ image = mface.image
+ if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]:
+ index = self.header.GRR.request_texture_index(image)
+ else:
+ index = -1
+ face.texture_index = index
+
+ for i, face in enumerate(self.face_lst):
+ if face.mface:
+ mface_v = face.mface.v
+ for v in mface_v:
+ face.uvlayer.append([])
- # Export double sided face as 2 faces with opposite orientations.
- if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']:
- # Create vertex description list for each face. they have a face mode, so we know they have a UV too.
- vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)]
- vertex_lst.reverse() # Reversing flips the face.
+ for layername in tex_layers[1:]:
+ if layername in meshlayers:
+ self.exportmesh.activeUVLayer=layername
+ for i, face in enumerate(self.face_lst):
+ if face.mface:
+
+ face.mtex.append(layername)
+ mface = face.mface
+ mface_v = mface.v
+ image = mface.image
+
+ if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]:
+ index = self.header.GRR.request_texture_index(image)
+ face.images.append(index)
+ else:
+ face.images.append(-1)
+
+ for j, v in enumerate(mface_v):
+ face.uvlayer[j].append(tuple(mface.uv[j]))
+ if uvok:
+ self.exportmesh.activeUVLayer = oldlayer
+ def blender_export(self):
+ global options
+ Node.blender_export(self)
+ if self.opcode == 111:
+ self.exportmesh = Blender.Mesh.New()
+ self.exportmesh.getFromObject(self.object.name)
+
+ for vert in self.exportmesh.verts:
+ if not options.export_transform:
+ vec = vert.co
+ vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale
+ vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace'))
- index_lst = []
- for vert_desc in vertex_lst:
- index_lst.append(self.header.GRR.request_vertex_index(vert_desc))
+ if options.scale != 1.0:
+ vert.co = vert.co * options.scale
+
+ if("FLT_VCOL") in self.mesh.verts.properties:
+ for v in self.exportmesh.verts:
+ self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,v,0,0,v.getProperty("FLT_VCOL")))
+ else:
+ for v in self.mesh.verts:
+ self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.mesh,v,0,0,127))
+
+
+
+ elif self.mesh:
+ orig_mesh = self.object.getData(mesh=True)
+ self.exportmesh = Blender.Mesh.New()
+ default = None
+
+
+ if options.export_shading:
+ mods = self.object.modifiers
+ hasedsplit = False
+ for mod in mods:
+ if mod.type == Blender.Modifier.Types.EDGESPLIT:
+ hasedsplit = True
+ break
+ if not hasedsplit:
+ default = mods.append(Modifier.Types.EDGESPLIT)
+ default[Modifier.Settings.EDGESPLIT_ANGLE] = options.shading_default
+ default[Modifier.Settings.EDGESPLIT_FROM_ANGLE] = True
+ default[Modifier.Settings.EDGESPLIT_FROM_SHARP] = False
+ self.object.makeDisplayList()
+
+ self.exportmesh.getFromObject(self.object.name)
+
+ #recalculate vertex positions
+ for vert in self.exportmesh.verts:
+ if not options.export_transform:
+ vec = vert.co
+ vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale
+ vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace'))
- face_desc = FaceDesc()
- face_desc.vertex_index_lst = index_lst
- if face.materialIndex < len(materials):
- face_desc.color_index = color_index_lst[face.materialIndex]
- face_desc.texture_index = tex_index_lst[face.materialIndex]
- face_desc.material_index = mat_index_lst[face.materialIndex]
- else:
- if options.verbose >=1:
- print 'Error: No material for material index. Delete abandoned material indices in Blender.'
-
- self.face_lst.append(face_desc)
+ if options.scale != 1.0:
+ vert.co = vert.co * options.scale
+
+ flipped = self.object.getMatrix('worldspace').determinant()
+
+ if not options.export_transform:
+ self.exportmesh.calcNormals()
+
+
+ if default:
+ #remove modifier from list
+ mods.remove(default)
+ self.object.makeDisplayList()
+
+ #build some adjacency data
+ vertuse = list()
+ wiredges = list()
+ openends = list()
+ for v in self.exportmesh.verts:
+ vertuse.append([False,0])
+
+ #build face incidence data
+ for face in self.exportmesh.faces:
+ for i, v in enumerate(face.verts):
+ vertuse[v.index][0] = True
+
+ for edge in self.exportmesh.edges: #count valance
+ vertuse[edge.v1.index][1] = vertuse[edge.v1.index][1] + 1
+ vertuse[edge.v2.index][1] = vertuse[edge.v2.index][1] + 1
+
+ #create all face types
+ self.buildVertFaces(vertuse)
+ self.buildEdgeFaces(vertuse)
+ self.buildOpenFacesNew(vertuse)
+ self.buildNormFaces()
+ self.buildTexData()
+
+ if not options.export_transform:
+ if flipped < 0:
+ for vdesc in self.header.GRR.vertex_lst:
+ vdesc.accum = 0
+ for face in self.face_lst:
+ face.vertex_index_lst.reverse()
+ for vert in face.vertex_index_lst:
+ self.header.GRR.vertex_lst[vert].accum = 1
+
+ for vdesc in self.header.GRR.vertex_lst:
+ if vdesc.accum:
+ vdesc.nx = vdesc.nx * -1
+ vdesc.ny = vdesc.ny * -1
+ vdesc.nz = vdesc.nz * -1
+
def write_faces(self):
+ sublevel = 0
for face_desc in self.face_lst:
- face_name = self.header.GRR.new_face_name()
+ if face_desc.name:
+ face_name = face_desc.name
+ else:
+ face_name = self.header.GRR.new_face_name()
+ #grab the alpha value.
+ alpha = 0
+ if face_desc.texture_index > -1:
+ try:
+ typestring = os.path.splitext(self.header.GRR.texture_lst[face_desc.texture_index].getFilename())[1]
+ if typestring == '.inta' or typestring == '.rgba':
+ alpha = 1
+ except:
+ pass
+
+ if not alpha:
+ for index in face_desc.images:
+ try:
+ typestring = os.path.splitext(self.header.GRR.texture_lst[index].getFilename())[1]
+ if typestring == '.inta' or typestring == '.rgba':
+ alpha = 1
+ except:
+ pass
+
+ if face_desc.billboard:
+ alpha = 2
+
+ if face_desc.subface:
+ if face_desc.subface == 'Push':
+ self.header.fw.write_short(19)
+ self.header.fw.write_ushort(4)
+ sublevel += 1
+ else:
+ self.header.fw.write_short(20)
+ self.header.fw.write_ushort(4)
+ sublevel -= 1
self.header.fw.write_short(5) # Face opcode
self.header.fw.write_ushort(80) # Length of record
self.header.fw.write_string(face_name, 8) # ASCII ID
self.header.fw.write_int(-1) # IR color code
- self.header.fw.write_short(0) # Relative priority
- self.header.fw.write_char(0) # Draw type
+ self.header.fw.write_short(0) # Relative priority
+ self.header.fw.write_char(face_desc.renderstyle) # Draw type
self.header.fw.write_char(0) # Draw textured white.
self.header.fw.write_ushort(0) # Color name index
self.header.fw.write_ushort(0) # Alt color name index
self.header.fw.write_char(0) # Reserved
- self.header.fw.write_char(1) # Template
+ self.header.fw.write_char(alpha) # Template
self.header.fw.write_short(-1) # Detail tex pat index
self.header.fw.write_short(face_desc.texture_index) # Tex pattern index
self.header.fw.write_short(face_desc.material_index) # material index
self.header.fw.write_short(0) # SMC code
- self.header.fw.write_short(0) # Feature code
+ self.header.fw.write_short(0) # Feature code
self.header.fw.write_int(0) # IR material code
self.header.fw.write_ushort(0) # transparency 0 = opaque
self.header.fw.write_uchar(0) # LOD generation control
self.header.fw.write_uchar(0) # line style index
- self.header.fw.write_int(0x00000000) # Flags
+ self.header.fw.write_int(0) # Flags
self.header.fw.write_uchar(2) # Light mode
+ #self.header.fw.write_uchar(3) # Light mode
+
self.header.fw.pad(7) # Reserved
- self.header.fw.write_uint(-1) # Packed color
- self.header.fw.write_uint(-1) # Packed alt color
+ self.header.fw.write_uint(0) # Packed color
+ self.header.fw.write_uint(0) # Packed alt color
self.header.fw.write_short(-1) # Tex map index
self.header.fw.write_short(0) # Reserved
self.header.fw.write_uint(face_desc.color_index) # Color index
@@ -473,7 +962,24 @@ class BlenderMesh(Node):
self.header.fw.write_short(-1) # Shader index
self.write_longid(face_name)
-
+
+
+ #Write Multitexture field if appropriate
+ mtex = len(face_desc.mtex)
+ if mtex:
+ uvmask = 0
+ for layername in face_desc.mtex:
+ mask = mtexmasks[tex_layers.index(layername)-1]
+ uvmask |= mask
+ self.header.fw.write_ushort(52) # MultiTexture Opcode
+ self.header.fw.write_ushort(8 + (mtex * 8)) # Length
+ self.header.fw.write_uint(uvmask) # UV mask
+ for i in xrange(mtex):
+ self.header.fw.write_ushort(face_desc.images[i]) # Tex pattern index
+ self.header.fw.write_ushort(0) # Tex effect
+ self.header.fw.write_ushort(0) # Tex Mapping index
+ self.header.fw.write_ushort(0) # Tex data. User defined
+
self.write_push()
# Vertex list record
@@ -484,72 +990,97 @@ class BlenderMesh(Node):
for vert_index in face_desc.vertex_index_lst:
# Offset into vertex palette
self.header.fw.write_int(vert_index*64+8)
-
+
+ #UV list record
+ if mtex:
+ #length = 8 + (numverts * multitex * 8)
+ self.header.fw.write_ushort(53) # UV List Ocode
+ self.header.fw.write_ushort(8 + (num_verts*mtex*8)) # Record Length
+ self.header.fw.write_uint(uvmask) # UV mask
+ for i, vert_index in enumerate(face_desc.vertex_index_lst):
+ for uv in face_desc.uvlayer[i]:
+ self.header.fw.write_float(uv[0]) #U coordinate
+ self.header.fw.write_float(uv[1]) #V coordinate
self.write_pop()
+ #clean up faces at the end of meshes....
+ if sublevel:
+ self.header.fw.write_short(20)
+ self.header.fw.write_ushort(4)
+
+ def write_lps(self):
+ # Vertex list record
+ self.write_push()
+ self.header.fw.write_short(72) # Vertex list opcode
+ num_verts = len(self.vert_lst)
+ self.header.fw.write_ushort(4*num_verts+4) # Length of record
+ for vert_index in self.vert_lst:
+ # Offset into vertex palette
+ self.header.fw.write_int(vert_index*64+8)
+ self.write_pop()
def write(self):
- if self.open_flight_type == 'Object':
- self.header.fw.write_short(4) # Object opcode
- self.header.fw.write_ushort(28) # Length of record
- self.header.fw.write_string(self.name, 8) # ASCII ID
- self.header.fw.pad(16)
-
- self.write_longid(self.name)
+ self.header.fw.write_short(self.opcode)
+ self.header.fw.write_ushort(recordlen[self.opcode])
+ exportdict = FLT_Records[self.opcode].copy()
+ if self.object:
+ self.props['3t8!id'] = self.object.name[:7]
+ for key in exportdict.keys():
+ if self.props.has_key(key):
+ exportdict[key] = self.props[key]
+
+ if self.opcode == 63 and options.externalspath:
+ try:
+ exportdict['3t200!filename'] = os.path.join(options.externalspath,self.object.DupGroup.name+'.flt')
+ self.header.xrefnames.append(self.object.DupGroup.name)
+ except:
+ pass
+
+ for key in records[self.opcode]:
+ (type,length,propname) = records[self.opcode][key]
+ write_prop(self.header.fw,type,exportdict[propname],length)
+
+ if self.props.has_key('comment'):
+ self.write_comment(self.props['comment'])
+ self.write_longid(self.name) #fix this!
+
+ if options.export_transform or self.opcode == 63:
+ #writing transform matrix....
self.write_matrix()
-
+
+ if self.opcode == 111:
+ self.write_lps()
+ elif self.face_lst != [] or self.children:
+ self.write_push()
if self.face_lst != []:
- self.write_push()
-
+ #self.write_push()
self.write_faces()
+ #self.write_pop()
- self.write_pop()
- else:
- self.header.fw.write_short(2) # Group opcode
- self.header.fw.write_ushort(44) # Length of record
- self.header.fw.write_string(self.name, 8) # ASCII ID
- self.header.fw.pad(32)
-
- self.write_longid(self.name)
-
- # Because a group can contain faces as well as children.
- self.write_push()
-
- self.write_faces()
-
- for child in self.children:
- child.write()
-
+ if self.children:
+ #self.write_push()
+ for child in self.children:
+ child.write()
+ #self.write_pop()
self.write_pop()
-
- def __init__(self, parent, header, object, object_lst):
- Node.__init__(self, parent, header, object, object_lst)
- self.face_lst = []
-
- if self.children:
- self.open_flight_type= 'Group'
- else: # Empty list.
- self.open_flight_type = 'Object'
-
-class BlenderEmpty(Node):
- def write(self):
- self.header.fw.write_short(2) # Group opcode
- self.header.fw.write_ushort(44) # Length of record
- self.header.fw.write_string(self.name, 8) # ASCII ID
- self.header.fw.pad(32)
-
- self.write_longid(self.name)
-
- self.write_matrix()
+ def __init__(self, parent, header, object,props,type):
+ self.opcode = type #both these next two lines need to be in the node class....
+ self.childtypes = childtypes[self.opcode]
+ Node.__init__(self, parent, header, object,props)
+ self.face_lst = []
+ self.vert_lst = [] #for light points.
+ self.mesh = None
+ self.uvlayer = 0
+ self.flipx = False
+ self.flipy = False
+ self.flipz = False
- if self.children: # != []
- self.write_push()
-
- for child in self.children:
- child.write()
- self.write_pop()
+ if self.object.type == 'Mesh':
+ self.mesh = self.object.getData(mesh=True)
+ if(self.mesh.faceUV):
+ self.uvLayer = len(self.mesh.getUVLayerNames())
class Database(Node):
def write_header(self):
@@ -568,8 +1099,19 @@ class Database(Node):
self.fw.write_int(0) # projection type, 0 = flat earth
self.fw.pad(30)
self.fw.write_short(1) # double precision
- self.fw.pad(140)
+ self.fw.write_int(100) # database origin type
+ self.fw.pad(88)
+ try:
+ self.fw.write_double(self.header.scene.properties['FLT']['origin lat']) #database origin lattitude
+ except:
+ self.fw.write_double(0)
+ try:
+ self.fw.write_double(self.header.scene.properties['FLT']['origin lon']) #database origin longitude
+ except:
+ self.fw.write_double(0)
+ self.fw.pad(32)
self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984
+
self.fw.pad(52)
def write_vert_pal(self):
@@ -579,14 +1121,13 @@ class Database(Node):
self.fw.write_short(67) # Vertex palette opcode.
self.fw.write_short(8) # Length of record
self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything.
-
# Write records for individual vertices.
for i in xrange(self.GRR.vertex_count()):
desc = self.GRR.request_vertex_desc(i)
self.fw.write_short(70) # Vertex with color normal and uv opcode.
self.fw.write_ushort(64) # Length of record
- self.fw.write_ushort(0) # Color name index
- self.fw.write_short(0x2000) # Flags set to no color
+ self.fw.write_ushort(0) # Color name index
+ self.fw.write_short(0x20000000) # Flags
self.fw.write_double(desc.x)
self.fw.write_double(desc.y)
self.fw.write_double(desc.z)
@@ -595,16 +1136,19 @@ class Database(Node):
self.fw.write_float(desc.nz)
self.fw.write_float(desc.u)
self.fw.write_float(desc.v)
- self.fw.pad(12)
+ self.fw.pad(4)
+ self.fw.write_uint(desc.cindex)
+ self.fw.pad(4)
def write_tex_pal(self):
if options.verbose >= 2:
print 'Writing texture palette.'
# Write record for texture palette
- for i in xrange(self.GRR.texture_count()):
+ for i, img in enumerate(self.GRR.texture_lst):
+ filename = tex_files[img.name]
self.fw.write_short(64) # Texture palette opcode.
self.fw.write_short(216) # Length of record
- self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename
+ self.fw.write_string(filename, 200) # Filename
self.fw.write_int(i) # Texture index
self.fw.write_int(0) # X
self.fw.write_int(0) # Y
@@ -641,13 +1185,17 @@ class Database(Node):
self.fw.write_short(32) # Color palette opcode.
self.fw.write_short(4228) # Length of record
self.fw.pad(128)
- count = self.GRR.color_count()
+ try:
+ cpalette = self.scene.properties['FLT']['Color Palette']
+ except:
+ cpalette = defaultp.pal
+ count = len(cpalette)
for i in xrange(count):
- col = self.GRR.request_max_color(i)
- self.fw.write_uchar(255) # alpha
- self.fw.write_uchar(col[2]) # b
- self.fw.write_uchar(col[1]) # g
- self.fw.write_uchar(col[0]) # r
+ color = struct.unpack('>BBBB',struct.pack('>I',cpalette[i]))
+ self.fw.write_uchar(color[3]) # alpha
+ self.fw.write_uchar(color[2]) # b
+ self.fw.write_uchar(color[1]) # g
+ self.fw.write_uchar(color[0]) # r
self.fw.pad(max(4096-count*4, 0))
def write(self):
@@ -657,66 +1205,429 @@ class Database(Node):
self.write_mat_pal()
self.write_col_pal()
- # Wrap everything in a group if it has an object child.
- if self.has_object_child:
- self.header.fw.write_short(2) # Group opcode
- self.header.fw.write_ushort(44) # Length of record
- self.header.fw.write_string('g1', 8) # ASCII ID
- self.header.fw.pad(32)
-
self.write_push()
-
- for child in self.children:
- child.write()
-
+
+ if options.flattenmesh:
+ self.mnodes.reverse()
+ for mnode in self.mnodes:
+ mnode.write_faces()
+ else:
+ for child in self.children:
+ child.write()
self.write_pop()
+
+ def export_textures(self,texturepath):
+ for i in xrange(self.GRR.texture_count()):
+ texture = self.GRR.texture_lst[i]
+
+ if options.copy_textures:
+ filename = os.path.normpath(os.path.join(options.texturespath, os.path.basename(self.GRR.request_texture_filename(i))))
+ else:
+ filename = os.path.normpath(self.GRR.request_texture_filename(i))
+
+ tex_files[texture.name] = filename
+ def blender_export(self):
+ Node.blender_export(self)
+ self.export_textures(self)
+ return self.xrefnames
def __init__(self, scene, fw):
self.fw = fw
+ self.opcode = 1
+ self.childtypes = [73,14,2,63]
self.scene = scene
- self.all_objects = list(scene.objects)
- self.GRR = GlobalResourceRepository()
+ self.childhash = dict()
+ self.parenthash = dict()
+ self.child_objects = list()
+ self.mnodes = list()
+ self.xrefnames = list()
+ for i in self.scene.objects:
+ self.parenthash[i.name] = list()
+ self.childhash[i.name] = False
+ for i in self.scene.objects:
+ if i.parent:
+ self.childhash[i.parent.name] = True
+ self.parenthash[i.parent.name].append(i)
+ else:
+ self.child_objects.append(i)
- Node.__init__(self, None, self, None, self.all_objects)
+ self.GRR = GlobalResourceRepository()
+ Node.__init__(self, None, self, None,None)
-def fs_callback(filename):
- Blender.Window.WaitCursor(True)
-
- if Blender.sys.exists(filename):
- r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No')
- if r != 1:
- if options.verbose >= 1:
- print 'Export cancelled.'
- return
-
- time1 = Blender.sys.time() # Start timing
+def write_attribute_files():
+ for imgname in tex_files:
+ blentex = Blender.Image.Get(imgname)
+ exportdict = FLT_Records['Image'].copy()
+
+ if blentex.properties.has_key('FLT'):
+ for key in exportdict.keys():
+ if blentex.properties.has_key(key):
+ exportdict[key] = blentex.properties['FLT'][key]
+
+ # ClampX/Y override
+ if blentex.clampX:
+ exportdict['11i!WrapU'] = 1
+ if blentex.clampY:
+ exportdict['12i!WrapV'] = 1
+
+ exportdict['16i!Enviorment'] = 0
+
+ # File type
+ typecode = 0
+ try:
+ typestring = os.path.splitext(blentex.getFilename())[1]
+
+ if typestring == '.rgba':
+ typecode = 5
+ elif typestring == '.rgb':
+ typecode = 4
+ elif typestring == '.inta':
+ typecode = 3
+ elif typestring == '.int':
+ typecode = 2
+ except:
+ pass
+
+ exportdict['7i!File Format'] = typecode
+
+ fw = FltOut(tex_files[imgname] + '.attr')
+ size = blentex.getSize()
+ fw.write_int(size[0])
+ fw.write_int(size[1])
+ for key in records['Image']:
+ (type,length,propname) = records['Image'][key]
+ write_prop(fw,type,exportdict[propname],length)
+ fw.close_file()
+
+#globals used by the scene export function
+exportlevel = None
+xrefsdone = None
+
+def dbexport_internal(scene):
+ global exportlevel
+ global xrefsdone
+ global options
+
+ if exportlevel == 0 or not options.externalspath:
+ fname = os.path.join(options.basepath,scene.name + '.flt')
+ else:
+ fname = os.path.join(options.externalspath,scene.name + '.flt')
- fw = FltOut(filename)
-
- db = Database(Blender.Scene.GetCurrent(), fw)
+ fw = FltOut(fname)
+ db = Database(scene,fw)
if options.verbose >= 1:
- print 'Pass 1: Exporting from Blender.\n'
-
- db.blender_export()
+ print 'Pass 1: Exporting ', scene.name,'.flt from Blender.\n'
+ xreflist = db.blender_export()
if options.verbose >= 1:
- print 'Pass 2: Writing %s\n' % filename
-
+ print 'Pass 2: Writing %s\n' % fname
db.write()
-
fw.close_file()
+
+ if options.doxrefs:
+ for xname in xreflist:
+ try:
+ xrefscene = Blender.Scene.Get(xname)
+ except:
+ xrefscene = None
+ if xrefscene and xname not in xrefsdone:
+ xrefsdone.append(xname)
+ exportlevel+=1
+ dbexport_internal(xrefscene)
+ exportlevel-=1
+ return fname
+#main database export function
+def dbexport():
+ global exportlevel
+ global xrefsdone
+ exportlevel = 0
+ xrefsdone = list()
+
+ Blender.Window.WaitCursor(True)
+ time1 = Blender.sys.time() # Start timing
+
if options.verbose >= 1:
+ print '\nOpenFlight Exporter'
+ print 'Version:', __version__
+ print 'Author: Greg MacDonald, Geoffrey Bantle'
+ print __url__[2]
+ print
+
+ fname = dbexport_internal(Blender.Scene.GetCurrent())
+ if options.verbose >=1:
print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1)
-
Blender.Window.WaitCursor(False)
+
+ #optional: Copy textures
+ if options.copy_textures:
+ for imgname in tex_files:
+ #Check to see if texture exists in target directory
+ if not os.path.exists(tex_files[imgname]):
+ #Get original Blender file name
+ origpath = Blender.sys.expandpath(Blender.Image.Get(imgname).getFilename())
+ #copy original to new
+ if os.path.exists(origpath):
+ shutil.copyfile(origpath,tex_files[imgname])
+
+ #optional: Write attribute files
+ if options.write_attrib_files:
+ write_attribute_files()
+
+ if options.xapp:
+ cmd= options.xappath + " " + fname
+ status = os.system(cmd)
+
+
+#Begin UI code
+FLTExport = None
+FLTClose = None
+FLTLabel = None
+
+FLTBaseLabel = None
+FLTTextureLabel = None
+FLTXRefLabel = None
+
+FLTBaseString = None
+FLTTextureString = None
+FLTXRefString = None
+
+FLTBasePath = None
+FLTTexturePath = None
+FLTXRefPath = None
+
+FLTShadeExport = None
+FLTShadeDefault = None
+
+FLTCopyTex = None
+FLTDoXRef = None
+FLTGlobal = None
+
+FLTScale = None
+
+FLTXAPP = None
+FLTXAPPath = None
+FLTXAPPString = None
+FLTXAPPLabel = None
+FLTXAPPChooser = None
+
+FLTAttrib = None
+
+def setshadingangle(ID,val):
+ global options
+ options.shading_default = val
+def setBpath(fname):
+ global options
+ options.basepath = os.path.dirname(fname)
+ #update xref and textures path too....
+ if(os.path.exists(os.path.join(options.basepath,'externals'))):
+ options.externalspath = os.path.join(options.basepath,'externals')
+ if(os.path.exists(os.path.join(options.texturespath,'textures'))):
+ options.texturespath = os.path.join(options.basepath,'textures')
+def setexportscale(ID,val):
+ global options
+ options.scale = val
+
+def setTpath(fname):
+ global options
+ options.texturespath = os.path.dirname(fname)
+def setXpath(fname):
+ global options
+ options.externalspath = os.path.dirname(fname)
+def setXApath(fname):
+ global options
+ options.xappath = fname
+ d = dict()
+ d['xappath'] = options.xappath
+ Blender.Registry.SetKey('flt_export', d, 1)
+def event(evt, val):
+ x = 1
+def but_event(evt):
+ global options
+
+ global FLTExport
+ global FLTClose
+ global FLTLabel
+
+ global FLTBaseLabel
+ global FLTTextureLabel
+ global FLTXRefLabel
-if options.verbose >= 1:
- print '\nOpenFlight Exporter'
- print 'Version:', __version__
- print 'Author: Greg MacDonald'
- print __url__[2]
- print
+ global FLTBaseString
+ global FLTTextureString
+ global FLTXRefString
+
+ global FLTBasePath
+ global FLTTexturePath
+ global FLTXRefPath
+
+ global FLTShadeExport
+ global FLTShadeDefault
+
+ global FLTCopyTex
+ global FLTDoXRef
+ global FLTGlobal
+
+ global FLTScale
+
+
+ global FLTXAPP
+ global FLTXAPPath
+ global FLTXAPPString
+ global FLTXAPPLabel
+ global FLTXAPPChooser
+
+ global FLTAttrib
+
+
-fname = Blender.sys.makename(ext=".flt")
-Blender.Window.FileSelector(fs_callback, "Export OpenFlight v16.0", fname)
+ #choose base path for export
+ if evt == 4:
+ Blender.Window.FileSelector(setBpath, "DB Root", options.basepath)
+
+ #choose XREF path
+ if evt == 6:
+ Blender.Window.FileSelector(setXpath,"DB Externals",options.externalspath)
+
+ #choose texture path
+ if evt == 8:
+ Blender.Window.FileSelector(setTpath,"DB Textures",options.texturespath)
+
+ #export shading toggle
+ if evt == 9:
+ options.export_shading = FLTShadeExport.val
+ #export Textures
+ if evt == 11:
+ options.copy_textures = FLTCopyTex.val
+ #export XRefs
+ if evt == 13:
+ options.doxrefs = FLTDoXRef.val
+ #export Transforms
+ if evt == 12:
+ options.export_transform = FLTGlobal.val
+
+ if evt == 14:
+ options.xapp = FLTXAPP.val
+ if evt == 16:
+ Blender.Window.FileSelector(setXApath,"External Application",options.xappath)
+ if evt == 20:
+ options.write_attrib_files = FLTAttrib.val
+
+ #Export DB
+ if evt == 1:
+ dbexport()
+
+ #exit
+ if evt == 2:
+ Draw.Exit()
+
+from Blender.BGL import *
+from Blender import Draw
+def gui():
+
+ global options
+
+ global FLTExport
+ global FLTClose
+ global FLTLabel
+
+ global FLTBaseLabel
+ global FLTTextureLabel
+ global FLTXRefLabel
+
+ global FLTBaseString
+ global FLTTextureString
+ global FLTXRefString
+
+ global FLTBasePath
+ global FLTTexturePath
+ global FLTXRefPath
+
+ global FLTShadeExport
+ global FLTShadeDefault
+
+ global FLTCopyTex
+ global FLTDoXRef
+ global FLTGlobal
+
+ global FLTScale
+
+ global FLTXAPP
+ global FLTXAPPath
+ global FLTXAPPString
+ global FLTXAPPLabel
+ global FLTXAPPChooser
+
+ global FLTAttrib
+
+ glClearColor(0.880,0.890,0.730,1.0 )
+ glClear(GL_COLOR_BUFFER_BIT)
+
+ areas = Blender.Window.GetScreenInfo()
+ curarea = Blender.Window.GetAreaID()
+ curRect = None
+
+ for area in areas:
+ if area['id'] == curarea:
+ curRect = area['vertices']
+ break
+
+ width = curRect[2] - curRect[0]
+ height = curRect[3] - curRect[1]
+ #draw from top to bottom....
+ cx = 50
+ #Draw Title Bar...
+ #glRasterPos2d(cx, curRect[3]-100)
+ #FLTLabel = Draw.Text("FLT Exporter V2.0",'large')
+ cy = height - 80
+
+ #base path
+ FLTBaseLabel = Draw.Label("Base Path:",cx,cy,100,20)
+ FLTBaseString = Draw.String("",3,cx+100,cy,300,20,options.basepath,255,"Folder to export to")
+ FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder")
+
+ cy = cy-40
+
+ #externals path
+ FLTXRefLabel = Draw.Label("XRefs:",cx,cy,100,20)
+ FLTXRefString = Draw.String("",5,cx+100,cy,300,20,options.externalspath,255,"Folder for external references")
+ FLTXRefChooser = Draw.PushButton("...",6,cx+400,cy,20,20,"Choose Folder")
+ cy = cy-40
+ #Textures path
+ FLTTextureLabel = Draw.Label("Textures:",cx,cy,100,20)
+ FLTTextureString = Draw.String("",7,cx+100,cy,300,20,options.texturespath,255,"Folder for texture files")
+ FLTTextureChooser = Draw.PushButton("...",8,cx+400,cy,20,20,"Choose Folder")
+ cy=cy-40
+ #External application path
+ FLTXAPPLabel = Draw.Label("XApp:",cx,cy,100,20)
+ FLTXAPPString = Draw.String("",15,cx+100,cy,300,20,options.xappath,255,"External application to launch when done")
+ FLTXAPPChooser = Draw.PushButton("...",16,cx+400, cy,20,20,"Choose Folder")
+
+ cy = cy-60
+ #Shading Options
+ FLTShadeExport = Draw.Toggle("Default Shading",9,cx,cy,100,20,options.export_shading,"Turn on export of custom shading")
+ FLTShadDefault = Draw.Number("",10,cx + 120,cy,100,20,options.shading_default,0.0,180.0,"Default shading angle for objects with no custom shading assigned",setshadingangle)
+
+ cy = cy-40
+ FLTScale = Draw.Number("Export Scale",14,cx,cy,220,20,options.scale,0.0,100.0,"Export scaling factor",setexportscale)
+
+ cy = cy-40
+ #misc Options
+ FLTCopyTex = Draw.Toggle("Copy Textures",11,cx,cy,220,20,options.copy_textures,"Copy textures to folder indicated above")
+ cy = cy-40
+ FLTGlobal = Draw.Toggle("Export Transforms",12,cx,cy,220,20,options.export_transform,"If unchecked, Global coordinates are used (recommended)")
+ cy = cy-40
+ FLTDoXRef = Draw.Toggle("Export XRefs", 13,cx,cy,220,20,options.doxrefs,"Export External references (only those below current scene!)")
+ cy = cy-40
+ FLTXAPP = Draw.Toggle("Launch External App", 14, cx,cy,220,20,options.xapp,"Launch External Application on export")
+ cy = cy-40
+ FLTAttrib = Draw.Toggle("Write Attribute Files", 20, cx, cy, 220,20,options.write_attrib_files, "Write Texture Attribute files")
+ #FLTXAPPATH = Draw.String("",15,cx,cy,300,20,options.xappath,255,"External application path")
+
+
+ #Draw export/close buttons
+ FLTExport = Draw.PushButton("Export",1,cx,20,100,20,"Export to FLT")
+ FLTClose = Draw.PushButton("Close", 2, cx+120,20,100,20,"Close window")
+
+
+Draw.Register(gui,event,but_event) \ No newline at end of file
diff --git a/release/scripts/flt_filewalker.py b/release/scripts/flt_filewalker.py
index 442c9728e91..4a9b86c45d2 100644
--- a/release/scripts/flt_filewalker.py
+++ b/release/scripts/flt_filewalker.py
@@ -17,6 +17,11 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+__bpydoc__ ="""\
+File read/write module used by OpenFlight I/O and tool scripts. OpenFlight is a
+registered trademark of MultiGen-Paradigm, Inc.
+"""
+
import Blender
from struct import *
import re
@@ -199,7 +204,9 @@ class FltOut:
self.file.close()
def __init__(self, filename):
- self.file = open(filename, 'wb')
+ self.file = open(filename, 'wb')
+ self.filename = filename
+
class FileFinder:
def add_file_to_search_path(self, filename):
diff --git a/release/scripts/flt_import.py b/release/scripts/flt_import.py
index ca0db650447..3ba118c0d18 100755..100644
--- a/release/scripts/flt_import.py
+++ b/release/scripts/flt_import.py
@@ -1,72 +1,26 @@
#!BPY
""" Registration info for Blender menus:
Name: 'OpenFlight (.flt)...'
-Blender: 238
+Blender: 245
Group: 'Import'
Tip: 'Import OpenFlight (.flt)'
"""
-__author__ = "Greg MacDonald, Campbell Barton"
-__version__ = "1.2 10/20/05"
+__author__ = "Greg MacDonald, Campbell Barton, Geoffrey Bantle"
+__version__ = "2.0 11/21/07"
__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/")
__bpydoc__ = """\
This script imports OpenFlight files into Blender. OpenFlight is a
registered trademark of MultiGen-Paradigm, Inc.
-Run from "File->Import" menu.
-
-Options are available from Blender's "Scripts Config Editor," accessible through
-the "Scripts->System" menu from the scripts window.
-
-All global_prefs are toggle switches that let the user choose what is imported. Most
-are straight-forward, but one option could be a source of confusion. The
-"Diffuse Color From Face" option when set pulls the diffuse color from the face
-colors. Otherwise the diffuse color comes from the material. What may be
-confusing is that this global_prefs only works if the "Diffuse Color" option is set.
-
-New Features:<br>
-* Importer is 14 times faster.<br>
-* External triangle module is no longer required, but make sure the importer
-has a 3d View screen open while its running or triangulation won't work.<br>
-* Should be able to import all versions of flight files.
-
-Features:<br>
-* Heirarchy retained.<br>
-* First texture imported.<br>
-* Colors imported from face or material.<br>
-* LOD seperated out into different layers.<br>
-* Asks for location of unfound textures or external references.<br>
-* Searches Blender's texture directory in the user preferences panel.<br>
-* Triangles with more than 4 verts are triangulated if the Triangle python
-module is installed.<br>
-* Matrix transforms imported.<br>
-* External references to whole files are imported.
-
-Things To Be Aware Of:<br>
-* Each new color and face attribute creates a new material and there are only a maximum of 16
-materials per object.<br>
-* For triangulated faces, normals must be recomputed outward manually by typing
-CTRL+N in edit mode.<br>
-* You can change global_prefs only after an initial import.<br>
-* External references are imported as geometry and will be exported that way.<br>
-* A work around for not using the Triangle python module is to simply to
-triangulate in Creator before importing. This is only necessary if your
-model contains 5 or more vertices.<br>
-* You have to manually blend the material color with the texture color.
-
-What's Not Handled:<br>
-* Special texture repeating modes.<br>
-* Replications and instancing.<br>
-* Comment and attribute fields.<br>
-* Light points.<br>
-* Animations.<br>
-* External references to a node within a file.<br>
-* Multitexturing.<br>
-* Vetex colors.<br>
+Feature overview and more availible at:
+http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_flt
+
+Note: This file is a grab-bag of old and new code. It needs some cleanup still.
"""
# flt_import.py is an OpenFlight importer for blender.
-# Copyright (C) 2005 Greg MacDonald
+# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -87,15 +41,33 @@ import os
import BPyMesh
import BPyImage
import flt_filewalker
+import flt_properties
+reload(flt_properties)
+from flt_properties import *
-Vector= Blender.Mathutils.Vector
+#Globals. Should Clean these up and minimize their usage.
-def col_to_gray(c):
- return 0.3*c[0] + 0.59*c[1] + 0.11*c[2]
+typecodes = ['c','C','s','S','i','I','f','d','t']
+records = dict()
+
+FLTBaseLabel = None
+FLTBaseString = None
+FLTBaseChooser = None
+FLTExport = None
+FLTClose = None
+FLTDoXRef = None
+FLTScale = None
+FLTShadeImport = None
+FLTAttrib = None
+
+Vector= Blender.Mathutils.Vector
+FLOAT_TOLERANCE = 0.01
+FF = flt_filewalker.FileFinder()
+current_layer = 0x01
global_prefs = dict()
-global_prefs['verbose']= 1
+global_prefs['verbose']= 4
global_prefs['get_texture'] = True
global_prefs['get_diffuse'] = True
global_prefs['get_specular'] = False
@@ -105,8 +77,41 @@ global_prefs['get_ambient'] = False
global_prefs['get_shininess'] = True
global_prefs['color_from_face'] = True
global_prefs['fltfile']= ''
+global_prefs['smoothshading'] = 1
+global_prefs['doxrefs'] = 1
+global_prefs['scale'] = 1.0
+global_prefs['attrib'] = 0
msg_once = False
+throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63,111] # Opcodes that indicate its time to return control to parent.
+do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125]
+
+#Process FLT record definitions
+for record in FLT_Records:
+ props = dict()
+ for prop in FLT_Records[record]:
+ position = ''
+ slice = 0
+ (format,name) = prop.split('!')
+ for i in format:
+ if i not in typecodes:
+ position = position + i
+ slice = slice + 1
+ else:
+ break
+ type = format[slice:]
+ length = type[1:]
+ if len(length) == 0:
+ length = 1
+ else:
+ type = type[0]
+ length = int(length)
+
+ props[int(position)] = (type,length,prop)
+ records[record] = props
+
+def col_to_gray(c):
+ return 0.3*c[0] + 0.59*c[1] + 0.11*c[2]
class MaterialDesc:
# Was going to use int(f*1000.0) instead of round(f,3), but for some reason
# round produces better results, as in less dups.
@@ -185,16 +190,14 @@ class VertexDesc:
self.y = 0.0
self.z = 0.0
- ''' # IGNORE_NORMALS
+
self.nx = 0.0
- self.ny = 1.0
+ self.ny = 0.0
self.nz = 0.0
- '''
+
self.uv= Vector(0,0)
- self.r = 1.0
- self.g = 1.0
- self.b = 1.0
- self.a = 1.0
+ self.cindex = 127 #default/lowest
+ self.cnorm = False
class LightPointAppDesc:
def make_key(self):
@@ -222,7 +225,7 @@ class LightPointAppDesc:
self.props.update({'LOD scale': 0.0})
class GlobalResourceRepository:
- def request_lightpoint_app(self, desc):
+ def request_lightpoint_app(self, desc, scene):
match = self.light_point_app.get(desc.make_key())
if match:
@@ -231,7 +234,7 @@ class GlobalResourceRepository:
# Create empty and fill with properties.
name = desc.props['type'] + ': ' + desc.props['id']
object = Blender.Object.New('Empty', name)
- scene.link(object)
+ scene.objects.link(object)
object.Layers= current_layer
object.sel= 1
@@ -306,6 +309,9 @@ class GlobalResourceRepository:
return tex
def __init__(self):
+
+ #list of scenes xrefs belong to.
+ self.xrefs = dict()
# material
self.mat_dict = dict()
mat_lst = Blender.Material.Get()
@@ -341,108 +347,6 @@ class GlobalResourceRepository:
# light point
self.light_point_app = dict()
-# Globals
-GRR = GlobalResourceRepository()
-FF = flt_filewalker.FileFinder()
-scene = Blender.Scene.GetCurrent() # just hope they dont chenge scenes once the file selector pops up.
-current_layer = 0x01
-
-
-# Opcodes that indicate its time to return control to parent.
-throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63]
-do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125]
-
-opcode_name = { 0: 'db',
- 1: 'head',
- 2: 'grp',
- 4: 'obj',
- 5: 'face',
- 10: 'push',
- 11: 'pop',
- 14: 'dof',
- 19: 'push sub',
- 20: 'pop sub',
- 21: 'push ext',
- 22: 'pop ext',
- 23: 'cont',
- 31: 'comment',
- 32: 'color pal',
- 33: 'long id',
- 49: 'matrix',
- 50: 'vector',
- 52: 'multi-tex',
- 53: 'uv lst',
- 55: 'bsp',
- 60: 'rep',
- 61: 'inst ref',
- 62: 'inst def',
- 63: 'ext ref',
- 64: 'tex pal',
- 67: 'vert pal',
- 68: 'vert w col',
- 69: 'vert w col & norm',
- 70: 'vert w col, norm & uv',
- 71: 'vert w col & uv',
- 72: 'vert lst',
- 73: 'lod',
- 74: 'bndin box',
- 76: 'rot edge',
- 78: 'trans',
- 79: 'scl',
- 80: 'rot pnt',
- 81: 'rot and/or scale pnt',
- 82: 'put',
- 83: 'eyepoint & trackplane pal',
- 84: 'mesh',
- 85: 'local vert pool',
- 86: 'mesh prim',
- 87: 'road seg',
- 88: 'road zone',
- 89: 'morph vert lst',
- 90: 'link pal',
- 91: 'snd',
- 92: 'rd path',
- 93: 'snd pal',
- 94: 'gen matrix',
- 95: 'txt',
- 96: 'sw',
- 97: 'line styl pal',
- 98: 'clip reg',
- 100: 'ext',
- 101: 'light src',
- 102: 'light src pal',
- 103: 'reserved',
- 104: 'reserved',
- 105: 'bndin sph',
- 106: 'bndin cyl',
- 107: 'bndin hull',
- 108: 'bndin vol cntr',
- 109: 'bndin vol orient',
- 110: 'rsrvd',
- 111: 'light pnt',
- 112: 'tex map pal',
- 113: 'mat pal',
- 114: 'name tab',
- 115: 'cat',
- 116: 'cat dat',
- 117: 'rsrvd',
- 118: 'rsrvd',
- 119: 'bounding hist',
- 120: 'rsrvd',
- 121: 'rsrvd',
- 122: 'push attrib',
- 123: 'pop attrib',
- 124: 'rsrvd',
- 125: 'rsrvd',
- 126: 'curv',
- 127: 'road const',
- 128: 'light pnt appear pal',
- 129: 'light pnt anim pal',
- 130: 'indexed lp',
- 131: 'lp sys',
- 132: 'indx str',
- 133: 'shdr pal'}
-
class Handler:
def in_throw_back_lst(self, opcode):
return opcode in self.throw_back_lst
@@ -487,11 +391,11 @@ class Node:
print '-', self.props['comment'],
print
-
+
for child in self.children:
child.blender_import()
-
- # Import comment.
+
+# Import comment.
# if self.props['comment'] != '':
# name = 'COMMENT: ' + self.props['id']
# t = Blender.Text.New(name)
@@ -568,8 +472,8 @@ class Node:
else:
if global_prefs['verbose'] >= 3:
print p + ' ignored'
- elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name:
- print opcode_name[opcode], 'not handled'
+ elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name:
+ print 'not handled'
def get_level(self):
return self.level
@@ -581,7 +485,19 @@ class Node:
def parse_comment(self):
self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4)
return True
-
+
+ def parse_record(self):
+ self.props['type'] = self.opcode
+ props = records[self.opcode]
+ propkeys = props.keys()
+ propkeys.sort()
+ for position in propkeys:
+ (type,length,name) = props[position]
+ self.props[name] = read_prop(self.header.fw,type,length)
+ try: #remove me!
+ self.props['id'] = self.props['3t8!id']
+ except:
+ pass
def __init__(self, parent, header):
self.root_handler = Handler()
self.child_handler = Handler()
@@ -647,20 +563,16 @@ class VertexPalette(Node):
return v
def parse_vertex_post_common(self, v):
- if not v.flags & 0x2000: # 0x2000 = no color
- if v.flags & 0x1000: # 0x1000 = packed color
- v.a = self.header.fw.read_uchar()
- v.b = self.header.fw.read_uchar()
- v.g = self.header.fw.read_uchar()
- v.r = self.header.fw.read_uchar()
- else:
- self.header.fw.read_ahead(4)
-
- color_index = self.header.fw.read_uint()
- v.r, v.g, v.b, v.a= self.header.get_color(color_index)
-
+ #if not v.flags & 0x2000: # 0x2000 = no color
+ #if v.flags & 0x1000: # 0x1000 = packed color
+ # v.a = self.header.fw.read_uchar()
+ # v.b = self.header.fw.read_uchar()
+ # v.g = self.header.fw.read_uchar()
+ # v.r = self.header.fw.read_uchar()
+ #else:
+ self.header.fw.read_ahead(4) #skip packed color
+ v.cindex = self.header.fw.read_uint()
self.vert_desc_lst.append(v)
-
return True
def parse_vertex_c(self):
@@ -672,16 +584,10 @@ class VertexPalette(Node):
def parse_vertex_cn(self):
v = self.parse_vertex_common()
-
- '''
+ v.cnorm = True
v.nx = self.header.fw.read_float()
v.ny = self.header.fw.read_float()
v.nz = self.header.fw.read_float()
- '''
- # Just to advance
- self.header.fw.read_float()
- self.header.fw.read_float()
- self.header.fw.read_float()
self.parse_vertex_post_common(v)
@@ -698,15 +604,10 @@ class VertexPalette(Node):
def parse_vertex_cnuv(self):
v = self.parse_vertex_common()
- '''
+ v.cnorm = True
v.nx = self.header.fw.read_float()
v.ny = self.header.fw.read_float()
v.nz = self.header.fw.read_float()
- '''
- # Just to advance
- self.header.fw.read_float()
- self.header.fw.read_float()
- self.header.fw.read_float()
v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float()
@@ -721,89 +622,374 @@ class InterNode(Node):
def __init__(self):
self.object = None
self.mesh = None
- self.isMesh = False
+ self.hasMesh = False
self.faceLs= []
self.matrix = None
-
- def blender_import_my_faces(self):
+ self.vis = True
+ self.hasmtex = False
+ self.uvlayers = dict()
+ self.blayernames = dict()
+ self.subfacelevel = 0
+
+ mask = 2147483648
+ for i in xrange(7):
+ self.uvlayers[mask] = False
+ mask = mask / 2
+
+ def blender_import_my_faces(self):
+
# Add the verts onto the mesh
- mesh = self.mesh
blender_verts= self.header.vert_pal.blender_verts
vert_desc_lst= self.header.vert_pal.vert_desc_lst
- vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices]
-
- mesh.verts.extend([blender_verts[i] for i in vert_list])
-
+ vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] #splitting faces apart. Is this a good thing?
+ face_edges= []
+ face_verts= []
+ self.mesh.verts.extend([blender_verts[i] for i in vert_list])
new_faces= []
new_faces_props= []
ngon= BPyMesh.ngon
vert_index= 1
+
+ #add vertex color layer for baked face colors.
+ self.mesh.addColorLayer("FLT_Fcol")
+ self.mesh.activeColorLayer = "FLT_Fcol"
+
+ FLT_OrigIndex = 0
for flt_face in self.faceLs:
- material_index= flt_face.blen_mat_idx
- image= flt_face.blen_image
-
+ if flt_face.tex_index != -1:
+ try:
+ image= self.header.tex_pal[flt_face.tex_index][1]
+ except KeyError:
+ image= None
+ else:
+ image= None
face_len= len(flt_face.indices)
+ #create dummy uvert dicts
+ if len(flt_face.uverts) == 0:
+ for i in xrange(face_len):
+ flt_face.uverts.append(dict())
+ #May need to patch up MTex info
+ if self.hasmtex:
+ #For every layer in mesh, there should be corresponding layer in the face
+ for mask in self.uvlayers.keys():
+ if self.uvlayers[mask]:
+ if not flt_face.uvlayers.has_key(mask): #Does the face have this layer?
+ #Create Layer info for this face
+ flt_face.uvlayers[mask] = dict()
+ flt_face.uvlayers[mask]['texture index'] = -1
+ flt_face.uvlayers[mask]['texture enviorment'] = 3
+ flt_face.uvlayers[mask]['texture mapping'] = 0
+ flt_face.uvlayers[mask]['texture data'] = 0
+
+ #now go through and create dummy uvs for this layer
+ for uvert in flt_face.uverts:
+ uv = Vector(0.0,0.0)
+ uvert[mask] = uv
+
# Get the indicies in reference to the mesh.
-
uvs= [vert_desc_lst[j].uv for j in flt_face.indices]
- if face_len <=4: # tri or quad
+ if face_len == 1:
+ pass
+ elif face_len == 2:
+ face_edges.append((vert_index, vert_index+1))
+ elif flt_face.props['draw type'] == 2 or flt_face.props['draw type'] == 3:
+ i = 0
+ while i < (face_len-1):
+ face_edges.append((vert_index + i, vert_index + i + 1))
+ i = i + 1
+ if flt_face.props['draw type'] == 2:
+ face_edges.append((vert_index + i,vert_index))
+ elif face_len == 3 or face_len == 4: # tri or quad
+ #if face_len == 1:
+ # pass
+ #if face_len == 2:
+ # face_edges.append((vert_index, vert_index+1))
new_faces.append( [i+vert_index for i in xrange(face_len)] )
- new_faces_props.append((material_index, image, uvs))
+ new_faces_props.append((None, image, uvs, flt_face.uverts, flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,0, flt_face.subfacelevel))
else: # fgon
mesh_face_indicies = [i+vert_index for i in xrange(face_len)]
- tri_ngons= ngon(mesh, mesh_face_indicies)
+ tri_ngons= ngon(self.mesh, mesh_face_indicies)
new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons])
- new_faces_props.extend( [ (material_index, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]) ) for tri in tri_ngons ] )
+ new_faces_props.extend( [ (None, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]), [flt_face.uverts[tri[0]], flt_face.uverts[tri[1]], flt_face.uverts[tri[2]]], flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,1, flt_face.subfacelevel) for tri in tri_ngons ])
vert_index+= face_len
-
- mesh.faces.extend(new_faces)
-
- try: mesh.faceUV= True
- except: pass
-
- for i, f in enumerate(mesh.faces):
- f.mat, f.image, f.uv= new_faces_props[i]
-
+ FLT_OrigIndex+=1
+
+ self.mesh.faces.extend(new_faces)
+ self.mesh.edges.extend(face_edges)
+
+ #add in the FLT_ORIGINDEX layer
+ if len(self.mesh.faces):
+ try: self.mesh.faceUV= True
+ except: pass
+
+ if self.mesh.faceUV == True:
+ self.mesh.renameUVLayer(self.mesh.activeUVLayer, 'Layer0')
+
+ #create name layer for faces
+ self.mesh.faces.addPropertyLayer("FLT_ID",Blender.Mesh.PropertyTypes["STRING"])
+ #create layer for face color indices
+ self.mesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"])
+ #create index layer for faces. This is needed by both FGONs and subfaces
+ self.mesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"])
+ #create temporary FGON flag layer. Delete after remove doubles
+ self.mesh.faces.addPropertyLayer("FLT_FGON",Blender.Mesh.PropertyTypes["INT"])
+ self.mesh.faces.addPropertyLayer("FLT_SFLEVEL", Blender.Mesh.PropertyTypes["INT"])
+
+ for i, f in enumerate(self.mesh.faces):
+ props = new_faces_props[i]
+ if props[6]['template billboard'] > 0:
+ f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"]
+ if props[6]['template billboard'] == 2:
+ f.mode |= Blender.Mesh.FaceModes["BILLBOARD"]
+ f.mode |= Blender.Mesh.FaceModes["LIGHT"]
+
+ #f.mat = props[0]
+ f.image = props[1]
+ f.uv = props[2]
+ #set vertex colors
+ color = self.header.get_color(props[5])
+ if not color:
+ color = [255,255,255,255]
+ for mcol in f.col:
+ mcol.a = color[3]
+ mcol.r = color[0]
+ mcol.g = color[1]
+ mcol.b = color[2]
+
+ f.setProperty("FLT_SFLEVEL", props[9])
+ f.setProperty("FLT_ORIGINDEX",i)
+ f.setProperty("FLT_ID",props[6]['id'])
+ #if props[5] > 13199:
+ # print "Warning, invalid color index read in! Using default!"
+ # f.setProperty("FLT_COL",127)
+ #else:
+ if(1): #uh oh....
+ value = struct.unpack('>i',struct.pack('>I',props[5]))[0]
+ f.setProperty("FLT_COL",value)
+
+ #if props[8]:
+ # f.setProperty("FLT_FGON",1)
+ #else:
+ # f.setProperty("FLT_FGON",0)
+
+
+ #Create multitex layers, if present.
+ actuvlayer = self.mesh.activeUVLayer
+ if(self.hasmtex):
+ #For every multi-tex layer, we have to add a new UV layer to the mesh
+ for i,mask in enumerate(reversed(sorted(self.uvlayers))):
+ if self.uvlayers[mask]:
+ self.blayernames[mask] = "Layer" + str(i+1)
+ self.mesh.addUVLayer(self.blayernames[mask])
+
+ #Cycle through availible multi-tex layers and add face UVS
+ for mask in self.uvlayers:
+ if self.uvlayers[mask]:
+ self.mesh.activeUVLayer = self.blayernames[mask]
+ for j, f in enumerate(self.mesh.faces):
+ f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"]
+ f.mode |= Blender.Mesh.FaceModes["LIGHT"]
+ props = new_faces_props[j]
+ uvlayers = props[4]
+ if uvlayers.has_key(mask): #redundant
+ uverts = props[3]
+ for k, uv in enumerate(f.uv):
+ uv[0] = uverts[k][mask][0]
+ uv[1] = uverts[k][mask][1]
+
+ uvlayer = uvlayers[mask]
+ tex_index = uvlayer['texture index']
+ if tex_index != -1:
+ try:
+ f.image = self.header.tex_pal[tex_index][1]
+ except KeyError:
+ f.image = None
+
+ if global_prefs['smoothshading'] == True and len(self.mesh.faces):
+ #We need to store per-face vertex normals in the faces as UV layers and delete them later.
+ self.mesh.addUVLayer("FLTNorm1")
+ self.mesh.addUVLayer("FLTNorm2")
+ self.mesh.activeUVLayer = "FLTNorm1"
+ for f in self.mesh.faces:
+ f.smooth = 1
+ #grab the X and Y components of normal and store them in UV
+ for i, uv in enumerate(f.uv):
+ vert = f.v[i].index
+ vert_desc = vert_desc_lst[vert_list[vert-1]]
+ if vert_desc.cnorm:
+ uv[0] = vert_desc.nx
+ uv[1] = vert_desc.ny
+ else:
+ uv[0] = 0.0
+ uv[1] = 0.0
+
+ #Now go through and populate the second UV Layer with the z component
+ self.mesh.activeUVLayer = "FLTNorm2"
+ for f in self.mesh.faces:
+ for i, uv in enumerate(f.uv):
+ vert = f.v[i].index
+ vert_desc = vert_desc_lst[vert_list[vert-1]]
+ if vert_desc.cnorm:
+ uv[0] = vert_desc.nz
+ uv[1] = 0.0
+ else:
+ uv[0] = 0.0
+ uv[1] = 0.0
+
+
+
+ #Finally, go through, remove dummy vertex, remove doubles and add edgesplit modifier.
+ Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX'])
+ self.mesh.verts.delete(0) # remove the dummy vert
+ self.mesh.sel= 1
+ self.header.scene.update(1) #slow!
+ self.mesh.remDoubles(0.0001)
+
+ edgeHash = dict()
+
+ for edge in self.mesh.edges:
+ edgeHash[edge.key] = edge.index
+
+
+ if global_prefs['smoothshading'] == True and len(self.mesh.faces):
+
+ #rip out the custom vertex normals from the mesh and place them in a face aligned list. Easier to compare this way.
+ facenorms = []
+ self.mesh.activeUVLayer = "FLTNorm1"
+ for face in self.mesh.faces:
+ facenorm = []
+ for uv in face.uv:
+ facenorm.append(Vector(uv[0],uv[1],0.0))
+ facenorms.append(facenorm)
+ self.mesh.activeUVLayer = "FLTNorm2"
+ for i, face in enumerate(self.mesh.faces):
+ facenorm = facenorms[i]
+ for j, uv in enumerate(face.uv):
+ facenorm[j][2] = uv[0]
+ self.mesh.removeUVLayer("FLTNorm1")
+ self.mesh.removeUVLayer("FLTNorm2")
+
+ #find hard edges
+ #store edge data for lookup by faces
+ #edgeHash = dict()
+ #for edge in self.mesh.edges:
+ # edgeHash[edge.key] = edge.index
+
+ edgeNormHash = dict()
+ #make sure to align the edgenormals to key value!
+ for i, face in enumerate(self.mesh.faces):
+
+ facenorm = facenorms[i]
+ faceEdges = []
+ faceEdges.append((face.v[0].index,face.v[1].index,facenorm[0],facenorm[1],face.edge_keys[0]))
+ faceEdges.append((face.v[1].index,face.v[2].index,facenorm[1],facenorm[2],face.edge_keys[1]))
+ if len(face.v) == 3:
+ faceEdges.append((face.v[2].index,face.v[0].index,facenorm[2],facenorm[0],face.edge_keys[2]))
+ elif len(face.v) == 4:
+ faceEdges.append((face.v[2].index,face.v[3].index,facenorm[2],facenorm[3],face.edge_keys[2]))
+ faceEdges.append((face.v[3].index,face.v[0].index,facenorm[3],facenorm[0],face.edge_keys[3]))
+
+ #check to see if edgeNormal has been placed in the edgeNormHash yet
+ #this is a redundant test, and should be optimized to not be called as often as it is.
+ for j, faceEdge in enumerate(faceEdges):
+ #the value we are looking for is (faceEdge[2],faceEdge[3])
+ hashvalue = (faceEdge[2],faceEdge[3])
+ if (faceEdge[0],faceEdge[1]) != faceEdge[4]:
+ hashvalue = (hashvalue[1],hashvalue[0])
+ assert (faceEdge[1],faceEdge[0]) == faceEdge[4]
+ if edgeNormHash.has_key(faceEdge[4]):
+ #compare value in the hash, if different, mark as sharp
+ edgeNorm = edgeNormHash[faceEdge[4]]
+ if\
+ abs(hashvalue[0][0] - edgeNorm[0][0]) > FLOAT_TOLERANCE or\
+ abs(hashvalue[0][1] - edgeNorm[0][1]) > FLOAT_TOLERANCE or\
+ abs(hashvalue[0][2] - edgeNorm[0][2]) > FLOAT_TOLERANCE or\
+ abs(hashvalue[1][0] - edgeNorm[1][0]) > FLOAT_TOLERANCE or\
+ abs(hashvalue[1][1] - edgeNorm[1][1]) > FLOAT_TOLERANCE or\
+ abs(hashvalue[1][2] - edgeNorm[1][2]) > FLOAT_TOLERANCE:
+ edge = self.mesh.edges[edgeHash[faceEdge[4]]]
+ edge.flag |= Blender.Mesh.EdgeFlags.SHARP
+
+ else:
+ edgeNormHash[faceEdge[4]] = hashvalue
+
+ #add in edgesplit modifier
+ mod = self.object.modifiers.append(Blender.Modifier.Types.EDGESPLIT)
+ mod[Blender.Modifier.Settings.EDGESPLIT_FROM_SHARP] = True
+ mod[Blender.Modifier.Settings.EDGESPLIT_FROM_ANGLE] = False
+
+ if(actuvlayer):
+ self.mesh.activeUVLayer = actuvlayer
+
def blender_import(self):
-# name = self.props['type'] + ': ' + self.props['id']
+ if self.vis and self.parent:
+ self.vis = self.parent.vis
name = self.props['id']
- if self.isMesh:
- self.object = Blender.Object.New('Mesh', name)
- #self.mesh = self.object.getData()
+
+ if self.hasMesh:
self.mesh = Blender.Mesh.New()
- self.mesh.verts.extend( Vector() ) # DUMMYVERT
- self.object.link(self.mesh)
+ self.mesh.name = 'FLT_FaceList'
+ self.mesh.fakeUser = True
+ self.mesh.verts.extend( Vector()) #DUMMYVERT
+ self.object = self.header.scene.objects.new(self.mesh)
else:
- self.object = Blender.Object.New('Empty', name)
+ self.object = self.header.scene.objects.new('Empty')
- if self.parent:
- self.parent.object.makeParent([self.object])
+ self.object.name = name
+ self.header.group.objects.link(self.object)
- scene.link(self.object)
- self.object.Layer = current_layer
- self.object.sel = 1
+ #id props import
+ self.object.properties['FLT'] = dict()
+ for key in self.props:
+ try:
+ self.object.properties['FLT'][key] = self.props[key]
+ except: #horrible...
+ pass
+ if self.parent and self.parent.object and (self.header.scene == self.parent.header.scene):
+ self.parent.object.makeParent([self.object])
+
+ if self.vis == False:
+ self.object.restrictDisplay = True
+ self.object.restrictRender = True
+
+ else: #check for LOD children and set the proper flags
+ lodlist = list()
+ for child in self.children:
+ if child.props.has_key('type') and child.props['type'] == 73:
+ lodlist.append(child)
+
+ def LODmin(a,b):
+ if a.props['5d!switch in'] < b.props['5d!switch in']:
+ return a
+ return b
+
+ min= None
+ if len(lodlist) > 1:
+ for lod in lodlist:
+ lod.vis = False
+ min = lodlist[0]
+ for i in xrange(len(lodlist)):
+ min= LODmin(min,lodlist[i])
+ min.vis = True
+
+ if self.matrix:
+ self.object.setMatrix(self.matrix)
+
Node.blender_import(self) # Attach faces to self.faceLs
- if self.isMesh:
+ if self.hasMesh:
# Add all my faces into the mesh at once
self.blender_import_my_faces()
-
- if self.matrix:
- self.object.setMatrix(self.matrix)
-
- # Attach properties
- #for name, value in self.props.items():
- # self.object.addProperty(name, value)
-
+
def parse_face(self):
- child = Face(self)
+ child = Face(self, self.subfacelevel)
child.parse()
return True
@@ -838,6 +1024,11 @@ class InterNode(Node):
child.parse()
return True
+ def parse_dof(self):
+ child = DOF(self)
+ child.parse()
+ return True
+
def parse_indexed_light_point(self):
child = IndexedLightPoint(self)
child.parse()
@@ -857,32 +1048,42 @@ class InterNode(Node):
m[i].append(f)
self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3])
-EDGE_FGON= Blender.Mesh.EdgeFlags['FGON']
-FACE_TEX= Blender.Mesh.FaceModes['TEX']
+ def parse_subpush(self):
+ self.parse_push()
+ self.subfacelevel+= 1
+ return True
+ def parse_subpop(self):
+ self.parse_pop()
+ self.subfacelevel -= 1
+ return True
+
+
class Face(Node):
- def __init__(self, parent):
+ def __init__(self, parent,subfacelevel):
Node.__init__(self, parent, parent.header)
self.root_handler.set_handler({31: self.parse_comment,
- 10: self.parse_push})
+ 10: self.parse_push,
+ 52: self.parse_multitex})
self.root_handler.set_throw_back_lst(throw_back_opcodes)
self.child_handler.set_handler({72: self.parse_vertex_list,
10: self.parse_push,
- 11: self.parse_pop})
+ 11: self.parse_pop,
+ 53: self.parse_uvlist})
if parent:
- parent.isMesh = True
+ parent.hasMesh = True
- self.indices = list() # face verts here
+ self.subfacelevel = subfacelevel
+ self.indices = list() # face verts here
+ self.uvlayers = dict() # MultiTexture layers keyed to layer bitmask.
+ self.uverts = list() # Vertex aligned list of dictionaries keyed to layer bitmask.
+ self.uvmask = 0 # Bitfield read from MTex record
self.comment = ''
- self.props = dict.fromkeys(['ir color', 'priority',
- 'draw type', 'texture white', 'template billboard',
- 'smc', 'fid', 'ir material', 'lod generation control',
- 'flags', 'light mode'])
-
- self.header.fw.read_ahead(8) # face id
+ self.props = dict()
+ self.props['id'] = self.header.fw.read_string(8)
# Load face.
self.props['ir color'] = self.header.fw.read_int()
self.props['priority'] = self.header.fw.read_short()
@@ -919,186 +1120,14 @@ class Face(Node):
self.alt_color_index = self.header.fw.read_uint()
#self.header.fw.read_ahead(2)
#self.shader_index = self.header.fw.read_short()
-
-
- """
- def blender_import_face(self, material_index, image):
-
-
- mesh = self.parent.mesh
- face_len= len(self.indices)
-
- mesh_vert_len_orig= len(mesh.verts)
- mesh.verts.extend([ self.header.vert_pal.blender_verts[i] for i in self.indices])
-
- # Exception for an edge
- if face_len==2:
- mesh.edges.extend((mesh.verts[-1], mesh.verts[-2]))
- return
-
-
- mesh_face_indicies = range(mesh_vert_len_orig, mesh_vert_len_orig+face_len)
-
- #print mesh_face_indicies , 'mesh_face_indicies '
-
- # First we need to triangulate NGONS
- if face_len>4:
- tri_indicies = [[i+mesh_vert_len_orig for i in t] for t in BPyMesh.ngon(mesh, mesh_face_indicies) ] # use range because the verts are in order.
- else:
- tri_indicies= [mesh_face_indicies] # can be a quad but thats ok
-
- # Extend face or ngon
-
- mesh.faces.extend(tri_indicies)
- #print mesh.faces, 'mesh.faces'
- mesh.faceUV= True
-
- # Now set UVs
- for i in xrange(len(mesh.faces)-len(tri_indicies), len(mesh.faces)):
- f= mesh.faces[i]
- f_v= f.v
- for j, uv in enumerate(f.uv):
- vertex_index_flt= self.indices[f_v[j].index - mesh_vert_len_orig]
-
- vert_desc = self.header.vert_pal.vert_desc_lst[vertex_index_flt]
- uv.x, uv.y= vert_desc.u, vert_desc.v
-
- # Only a bug in 2.42, fixed in cvs
- for c in f.col:
- c.r=c.g=c.b= 255
-
- f.mat = material_index
- if image:
- f.image = image
- else:
- f.mode &= ~FACE_TEX
-
- # FGon
-
- if face_len>4:
- # Add edges we know are not fgon
- end_index= len(mesh.verts)
- start_index= end_index - len(self.indices)
- edge_dict= dict([ ((i, i+1), None) for i in xrange(start_index, end_index-1)])
- edge_dict[(start_index, end_index)]= None # wish this was a set
-
- fgon_edges= {}
- for tri in tri_indicies:
- for i in (0,1,2):
- i1= tri[i]
- i2= tri[i-1]
-
- # Sort
- if i1>i2:
- i1,i2= i2,i1
-
- if not edge_dict.has_key( (i1,i2) ): # if this works its an edge vert
- fgon_edges[i1,i2]= None
-
-
- # Now set fgon flags
- for ed in mesh.edges:
- i1= ed.v1.index
- i2= ed.v2.index
- if i1>i2:
- i1,i2= i2,i1
-
- if fgon_edges.has_key( (i1,i2) ):
- # This is an edge tagged for fgonning?
- fgon_edges[i1, i2]
- ed.flag |= EDGE_FGON
- del fgon_edges[i1, i2] # make later searches faster?
-
- if not fgon_edges:
- break
- """
-
+
def parse_comment(self):
self.comment = self.header.fw.read_string(self.header.fw.get_length()-4)
return True
- # returns a tuple (material, image) where material is the blender material and
- # image is the blender image or None.
- def create_blender_material(self):
- # Create face material.
- mat_desc = MaterialDesc()
-
- if self.mat_index != -1:
- if not self.mat_index in self.header.mat_desc_pal:
- if global_prefs['verbose'] >= 1:
- #print 'Warning: Material index', self.mat_index, 'not in material palette.'
- pass
- else:
- mat_pal_desc = self.header.mat_desc_pal[self.mat_index]
- mat_desc.alpha = mat_pal_desc.alpha * self.alpha # combine face and mat alphas
- mat_desc.ambient = mat_pal_desc.ambient
- mat_desc.diffuse = mat_pal_desc.diffuse
- mat_desc.specular = mat_pal_desc.specular
- mat_desc.emissive = mat_pal_desc.emissive
- mat_desc.shininess = mat_pal_desc.shininess
- else:
- # if no material get alpha from just face.
- mat_desc.alpha = self.alpha
-
- # Color.
- if global_prefs['color_from_face']:
- color = None
- if not self.props['flags'] & 0x40000000:
- if self.props['flags'] & 0x10000000: # packed color
- color = self.packed_color
- else:
- color = self.header.get_color(self.color_index)
-
- if color:
- r = float(color[0])/255.0
- g = float(color[1])/255.0
- b = float(color[2])/255.0
- mat_desc.diffuse = [r, g, b]
-
- # Texture
- image = None
- if self.tex_index != -1 and self.tex_index in self.header.bl_tex_pal:
- mat_desc.tex0 = self.header.bl_tex_pal[self.tex_index]
- if mat_desc.tex0:
- mat_desc.name = FF.strip_path(self.header.tex_pal[self.tex_index])
- image = mat_desc.tex0.image
-
- # OpenFlight Face Attributes
- mat_desc.face_props = self.props
-
- # Get material.
- mat = GRR.request_mat(mat_desc)
-
- # Add material to mesh.
- mesh = self.parent.mesh
-
- # Return where it is in the mesh for faces.
- mesh_materials= mesh.materials
-
- material_index= -1
- for i,m in enumerate(mesh_materials):
- if m.name==mat.name:
- material_index= i
- break
-
- if material_index==-1:
- material_index= len(mesh_materials)
- if material_index==16:
- material_index= 15
- if global_prefs['verbose'] >= 1:
- print 'Warning: Too many materials per mesh object. Only a maximum of 16 ' + \
- 'allowed. Using 16th material instead.'
-
- else:
- mesh_materials.append(mat)
- mesh.materials= mesh_materials
-
- return (material_index, image)
-
-
def blender_import(self):
vert_count = len(self.indices)
- if vert_count < 3:
+ if vert_count < 1:
if global_prefs['verbose'] >= 2:
print 'Warning: Ignoring face with no vertices.'
return
@@ -1106,18 +1135,21 @@ class Face(Node):
# Assign material and image
self.parent.faceLs.append(self)
- self.blen_mat_idx, self.blen_image= self.create_blender_material()
-
-
-
+ #need to store comment in mesh prop layer!
# Store comment info in parent.
- if self.comment != '':
- if self.parent.props['comment'] != '':
- self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment
- else:
- self.parent.props['comment'] = self.comment
-
+ #if self.comment != '':
+ # if self.parent.props['comment'] != '':
+ # self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment
+ # else:
+ # self.parent.props['comment'] = self.comment
+
+ if self.uvlayers:
+ #Make sure that the mesh knows about the layers that this face uses
+ self.parent.hasmtex = True
+ for mask in self.uvlayers.keys():
+ self.parent.uvlayers[mask] = True
+
def parse_vertex_list(self):
length = self.header.fw.get_length()
fw = self.header.fw
@@ -1138,8 +1170,49 @@ class Face(Node):
' to vertex index.' % byte_offset
'''
return True
-
-
+
+ def parse_multitex(self):
+ #Parse MultiTex Record.
+ length = self.header.fw.get_length()
+ fw = self.header.fw
+ #num layers == (length - 8) / 4
+ uvmask = fw.read_uint()
+ mask = 2147483648
+ for i in xrange(7):
+ if mask & uvmask:
+ uvlayer = dict()
+ self.uvlayers[mask] = uvlayer
+ mask = mask / 2
+
+ #read in record for each individual layer.
+ for key in reversed(sorted(self.uvlayers)):
+ uvlayer = self.uvlayers[key]
+ uvlayer['texture index'] = fw.read_ushort()
+ uvlayer['texture enviorment'] = fw.read_ushort()
+ uvlayer['texture mapping'] = fw.read_ushort()
+ uvlayer['texture data'] = fw.read_ushort()
+
+ self.uvmask = uvmask
+
+ def parse_uvlist(self):
+ #for each uvlayer, add uv vertices
+ length = self.header.fw.get_length()
+ fw = self.header.fw
+ uvmask = fw.read_uint()
+ if uvmask != self.uvmask: #This should never happen!
+ fw.read_ahead(self.length - 4) #potentially unnessecary?
+ else:
+ #need to store in uvverts dictionary for each vertex.
+ totverts = len(self.indices)
+ for i in xrange(totverts):
+ uvert = dict()
+ for key in reversed(sorted(self.uvlayers)):
+ uv = Vector(0.0,0.0)
+ uv[0] = fw.read_float()
+ uv[1] = fw.read_float()
+ uvert[key] = uv
+ self.uverts.append(uvert)
+
class Object(InterNode):
def __init__(self, parent):
Node.__init__(self, parent, parent.header)
@@ -1152,15 +1225,15 @@ class Object(InterNode):
self.root_handler.set_throw_back_lst(throw_back_opcodes)
self.child_handler.set_handler({5: self.parse_face,
- #130: self.parse_indexed_light_point,
- #111: self.parse_inline_light_point,
+ 19: self.parse_subpush,
+ 20: self.parse_subpop,
+ 111: self.parse_inline_light_point,
10: self.parse_push,
11: self.parse_pop})
- self.props['type'] = 'Object'
- self.props['id'] = self.header.fw.read_string(8)
-
-
+ self.props = dict()
+ self.props['comment'] = ''
+ self.parse_record()
class Group(InterNode):
def __init__(self, parent):
@@ -1174,15 +1247,16 @@ class Group(InterNode):
self.root_handler.set_throw_back_lst(throw_back_opcodes)
self.child_handler.set_handler({5: self.parse_face,
- #130: self.parse_indexed_light_point,
- #111: self.parse_inline_light_point,
+ 19: self.parse_subpush,
+ 20: self.parse_subpop,
+ 111: self.parse_inline_light_point,
2: self.parse_group,
73: self.parse_lod,
4: self.parse_object,
10: self.parse_push,
11: self.parse_pop,
96: self.parse_unhandled,
- 14: self.parse_unhandled,
+ 14: self.parse_dof,
91: self.parse_unhandled,
98: self.parse_unhandled,
63: self.parse_xref})
@@ -1190,20 +1264,48 @@ class Group(InterNode):
'special2', 'significance', 'layer code', 'loop count',
'loop duration', 'last frame duration'])
- self.props['type'] = 'Group'
self.props['comment'] = ''
- self.props['id'] = self.header.fw.read_string(8)
- self.props['priority'] = self.header.fw.read_short()
- self.header.fw.read_ahead(2)
- self.props['flags'] = self.header.fw.read_int()
- self.props['special1'] = self.header.fw.read_short()
- self.props['special2'] = self.header.fw.read_short()
- self.props['significance'] = self.header.fw.read_short()
- self.props['layer code'] = self.header.fw.read_char()
- self.header.fw.read_ahead(5)
- self.props['loop count'] = self.header.fw.read_int()
- self.props['loop duration'] = self.header.fw.read_float()
- self.props['last frame duration'] = self.header.fw.read_float()
+ self.parse_record()
+
+ #self.props['type'] = str(self.opcode) + ':' + opcode_name[self.opcode]
+ #props = records[self.opcode]
+ #propkeys = props.keys()
+ #propkeys.sort()
+ #for position in propkeys:
+ # (type,length,name) = props[position]
+ # self.props[name] = read_prop(self.header.fw,type,length)
+ #self.props['id'] = self.props['3t8!id']
+
+class DOF(InterNode):
+ def blender_import(self):
+ InterNode.blender_import(self)
+
+ def __init__(self, parent):
+ Node.__init__(self, parent, parent.header)
+ InterNode.__init__(self)
+
+ self.root_handler.set_handler({33: self.parse_long_id,
+ 31: self.parse_comment,
+ 10: self.parse_push,
+ 49: self.parse_matrix})
+ self.root_handler.set_throw_back_lst(throw_back_opcodes)
+
+ self.child_handler.set_handler({#130: self.parse_indexed_light_point,
+ 111: self.parse_inline_light_point,
+ 2: self.parse_group,
+ 73: self.parse_lod,
+ 4: self.parse_object,
+ 10: self.parse_push,
+ 11: self.parse_pop,
+ 96: self.parse_unhandled,
+ 14: self.parse_dof,
+ 91: self.parse_unhandled,
+ 98: self.parse_unhandled,
+ 63: self.parse_xref})
+ self.props = dict()
+ self.props['comment'] = ''
+ self.parse_record()
+
class XRef(InterNode):
def parse(self):
@@ -1214,31 +1316,66 @@ class XRef(InterNode):
def __init__(self, parent):
Node.__init__(self, parent, parent.header)
InterNode.__init__(self)
-
+
self.root_handler.set_handler({49: self.parse_matrix})
self.root_handler.set_throw_back_lst(throw_back_opcodes)
- xref_filename = self.header.fw.read_string(200)
- filename = FF.find(xref_filename)
+ self.props = dict()
+ self.props['comment'] = ''
+ self.parse_record()
- self.props['type'] = 'XRef'
+ xref_filename = self.props['3t200!filename']
+ self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(xref_filename))[0] #this is really wrong as well....
- if filename != None:
- self.xref = Database(filename, self)
- self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(filename))[0]
+ if global_prefs['doxrefs'] and os.path.exists(xref_filename) and not self.header.grr.xrefs.has_key(xref_filename):
+ self.xref = Database(xref_filename, self.header.grr, self)
+ self.header.grr.xrefs[xref_filename] = self.xref
else:
self.xref = None
- self.props['id'] = 'X: broken'
+
+
+ def blender_import(self):
+ #name = self.props['type'] + ': ' + self.props['id']
+ name = self.props['id']
+ self.object = self.header.scene.objects.new('Empty')
+ self.object.name = name
+ self.object.enableDupGroup = True
+ self.header.group.objects.link(self.object)
+
+ #for broken links its ok to leave this empty! they purely for visual purposes anyway.....
+ try:
+ self.object.DupGroup = self.header.grr.xrefs[self.props['3t200!filename']].group
+ except:
+ pass
+
+ if self.parent and self.parent.object:
+ self.parent.object.makeParent([self.object])
+
+ #id props import
+ self.object.properties['FLT'] = dict()
+ for key in self.props:
+ try:
+ self.object.properties['FLT'][key] = self.props[key]
+ except: #horrible...
+ pass
+ self.object.Layer = current_layer
+ self.object.sel = 1
+ if self.matrix:
+ self.object.setMatrix(self.matrix)
+ Node.blender_import(self)
+
+
class LOD(InterNode):
def blender_import(self):
- self.move_to_next_layer()
+ #self.move_to_next_layer()
InterNode.blender_import(self)
-
+ #self.object.properties['FLT'] = self.props.copy()
+
def __init__(self, parent):
Node.__init__(self, parent, parent.header)
InterNode.__init__(self)
-
+
self.root_handler.set_handler({33: self.parse_long_id,
31: self.parse_comment,
10: self.parse_push,
@@ -1246,18 +1383,20 @@ class LOD(InterNode):
self.root_handler.set_throw_back_lst(throw_back_opcodes)
self.child_handler.set_handler({2: self.parse_group,
+ 111: self.parse_inline_light_point,
73: self.parse_lod,
4: self.parse_object,
10: self.parse_push,
11: self.parse_pop,
96: self.parse_unhandled, # switch
- 14: self.parse_unhandled, # DOF
+ 14: self.parse_dof, # DOF
91: self.parse_unhandled, # sound
98: self.parse_unhandled, # clip
63: self.parse_xref})
- self.props['type'] = 'LOD'
- self.props['id'] = self.header.fw.read_string(8)
+ self.props = dict()
+ self.props['comment'] = ''
+ self.parse_record()
class InlineLightPoint(InterNode):
def __init__(self, parent):
@@ -1274,119 +1413,49 @@ class InlineLightPoint(InterNode):
11: self.parse_pop})
self.indices = list()
-
- self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance'])
- self.app_props = dict()
-
+ self.props = dict()
self.props['comment'] = ''
- self.props['type'] = 'Light Point'
- self.props['id'] = self.header.fw.read_string(8)
-
- self.app_props.update({'smc': self.header.fw.read_short()})
- self.app_props.update({'fid': self.header.fw.read_short()})
- self.app_props.update({'back color: a': self.header.fw.read_uchar()})
- self.app_props.update({'back color: b': self.header.fw.read_uchar()})
- self.app_props.update({'back color: g': self.header.fw.read_uchar()})
- self.app_props.update({'back color: r': self.header.fw.read_uchar()})
- self.app_props.update({'display mode': self.header.fw.read_int()})
- self.app_props.update({'intensity': self.header.fw.read_float()})
- self.app_props.update({'back intensity': self.header.fw.read_float()})
- self.app_props.update({'minimum defocus': self.header.fw.read_float()})
- self.app_props.update({'maximum defocus': self.header.fw.read_float()})
- self.app_props.update({'fading mode': self.header.fw.read_int()})
- self.app_props.update({'fog punch mode': self.header.fw.read_int()})
- self.app_props.update({'directional mode': self.header.fw.read_int()})
- self.app_props.update({'range mode': self.header.fw.read_int()})
- self.app_props.update({'min pixel size': self.header.fw.read_float()})
- self.app_props.update({'max pixel size': self.header.fw.read_float()})
- self.app_props.update({'actual size': self.header.fw.read_float()})
- self.app_props.update({'trans falloff pixel size': self.header.fw.read_float()})
- self.app_props.update({'trans falloff exponent': self.header.fw.read_float()})
- self.app_props.update({'trans falloff scalar': self.header.fw.read_float()})
- self.app_props.update({'trans falloff clamp': self.header.fw.read_float()})
- self.app_props.update({'fog scalar': self.header.fw.read_float()})
- self.app_props.update({'fog intensity': self.header.fw.read_float()})
- self.app_props.update({'size threshold': self.header.fw.read_float()})
- self.app_props.update({'directionality': self.header.fw.read_int()})
- self.app_props.update({'horizontal lobe angle': self.header.fw.read_float()})
- self.app_props.update({'vertical lobe angle': self.header.fw.read_float()})
- self.app_props.update({'lobe roll angle': self.header.fw.read_float()})
- self.app_props.update({'dir falloff exponent': self.header.fw.read_float()})
- self.app_props.update({'dir ambient intensity': self.header.fw.read_float()})
- self.header.fw.read_ahead(12) # Animation settings.
- self.app_props.update({'significance': self.header.fw.read_float()})
- self.props['draw order'] = self.header.fw.read_int()
- self.app_props.update({'flags': self.header.fw.read_int()})
- #self.fw.read_ahead(12) # More animation settings.
-
- # return dictionary: lp_app name => index list
- def group_points(self, props):
-
- name_to_indices = {}
-
- for i in self.indices:
- vert_desc = self.header.vert_pal.vert_desc_lst[i]
- app_desc = LightPointAppDesc()
- app_desc.props.update(props)
- # add vertex normal and color
- app_desc.props.update({'nx': vert_desc.nx})
- app_desc.props.update({'ny': vert_desc.ny})
- app_desc.props.update({'nz': vert_desc.nz})
-
- app_desc.props.update({'r': vert_desc.r})
- app_desc.props.update({'g': vert_desc.g})
- app_desc.props.update({'b': vert_desc.b})
- app_desc.props.update({'a': vert_desc.a})
-
- app_name = GRR.request_lightpoint_app(app_desc)
+ self.parse_record()
- if name_to_indices.get(app_name):
- name_to_indices[app_name].append(i)
- else:
- name_to_indices.update({app_name: [i]})
-
- return name_to_indices
def blender_import(self):
- name = '%s: %s' % (self.props['type'], self.props['id'])
+
- name_to_indices = self.group_points(self.app_props)
+ name = self.props['id']
+ self.mesh= Blender.Mesh.New()
+ self.mesh.name = 'FLT_LP'
+ self.object = self.header.scene.objects.new(self.mesh)
+ self.object.name = name
+ #self.mesh.verts.extend(Vector() ) # DUMMYVERT
+ self.object.Layer = current_layer
+ self.object.sel= 1
+
+ self.object.properties['FLT'] = dict()
+ for key in self.props:
+ try:
+ self.object.properties['FLT'][key] = self.props[key]
+ except: #horrible...
+ pass
+
+ if self.parent and self.parent.object and self.header.scene == self.parent.header.scene:
+ self.parent.object.makeParent([self.object])
- for app_name, indices in name_to_indices.iteritems():
- self.object = Blender.Object.New('Mesh', name)
- #self.mesh = self.object.getData()
- self.mesh= Blender.Mesh.New()
- self.mesh.verts.extend( Vector() ) # DUMMYVERT
- self.object.link(self.mesh)
+ if self.matrix:
+ self.object.setMatrix(self.matrix)
- if self.parent:
- self.parent.object.makeParent([self.object])
+ self.mesh.verts.extend([self.header.vert_pal.blender_verts[i] for i in self.indices])
+
+ #add color index information.
+ self.mesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"])
+ for i, vindex in enumerate(self.indices):
+ vdesc = self.header.vert_pal.vert_desc_lst[vindex]
+ v = self.mesh.verts[i]
+ v.setProperty("FLT_VCOL",vdesc.cindex)
+ #for i, v in enumerate(self.mesh.verts):
+ # vdesc = self.header.vert_pal.vert_desc_lst[i]
+ # v.setProperty("FLT_VCOL",vdesc.cindex)
+ self.mesh.update()
- for i in indices:
- vert = self.header.vert_pal.blender_verts[i]
- self.mesh.verts.append(vert)
-
- scene.link(self.object)
- self.object.Layer = current_layer
- self.object.sel= 1
-
- if self.matrix:
- self.object.setMatrix(self.matrix)
-
- # Import comment.
- if self.props['comment'] != '':
- name = 'COMMENT: ' + self.props['id']
- t = Blender.Text.New(name)
- t.write(self.props['comment'])
- self.props['comment'] = name
-
- # Attach properties.
- self.props.update({'appearance': app_name})
- for name, value in self.props.iteritems():
- self.object.addProperty(name, value)
-
- self.mesh.update()
-
def parse_vertex_list(self):
length = self.header.fw.get_length()
fw = self.header.fw
@@ -1432,7 +1501,7 @@ class IndexedLightPoint(InterNode):
app_desc.props.update({'b': vert_desc.b})
app_desc.props.update({'a': vert_desc.a})
- app_name = GRR.request_lightpoint_app(app_desc)
+ app_name = self.header.grr.request_lightpoint_app(app_desc, self.header.scene)
if name_to_indices.get(app_name):
name_to_indices[app_name].append(i)
@@ -1448,7 +1517,6 @@ class IndexedLightPoint(InterNode):
for app_name, indices in name_to_indices.iteritems():
self.object = Blender.Object.New('Mesh', name)
- #self.mesh = self.object.getData()
self.mesh= Blender.Mesh.New()
self.mesh.verts.extend( Vector() ) # DUMMYVERT
self.object.link(self.mesh)
@@ -1460,7 +1528,7 @@ class IndexedLightPoint(InterNode):
vert = self.header.vert_pal.blender_verts[i]
self.mesh.verts.append(vert)
- scene.link(self.object)
+ self.header.scene.objects.link(self.object)
self.object.Layer = current_layer
@@ -1543,7 +1611,7 @@ class Unhandled(InterNode):
10: self.parse_push,
11: self.parse_pop,
96: self.parse_unhandled, # switch
- 14: self.parse_unhandled, # DOF
+ 14: self.parse_dof, # DOF
91: self.parse_unhandled, # sound
98: self.parse_unhandled, # clip
63: self.parse_xref})
@@ -1552,30 +1620,31 @@ class Unhandled(InterNode):
class Database(InterNode):
def blender_import(self):
- self.tex_pal = dict(self.tex_pal_lst)
- del self.tex_pal_lst
-
- # Setup Textures
- bl_tex_pal_lst = list()
- for i in self.tex_pal.iterkeys():
- path_filename = FF.find(self.tex_pal[i])
+ for key in self.tex_pal.keys():
+ path_filename= FF.find(self.tex_pal[key][0])
if path_filename != None:
- img = GRR.request_image(path_filename)
+ img = self.grr.request_image(path_filename)
if img:
- tex = GRR.request_texture(img)
- tex.setName(FF.strip_path(self.tex_pal[i]))
- bl_tex_pal_lst.append( (i, tex) )
- else:
- bl_tex_pal_lst.append( (i, None) )
+ self.tex_pal[key][1] = img
elif global_prefs['verbose'] >= 1:
- print 'Warning: Unable to find', self.tex_pal[i]
-
- self.bl_tex_pal = dict(bl_tex_pal_lst)
-
- # Setup Materials
- self.mat_desc_pal = dict(self.mat_desc_pal_lst)
-
- InterNode.blender_import(self)
+ print 'Warning: Unable to find', self.tex_pal[key][0]
+
+ self.scene.properties['FLT'] = dict()
+ for key in self.props:
+ try:
+ self.scene.properties['FLT'][key] = self.props[key]
+ except: #horrible...
+ pass
+
+ self.scene.properties['FLT']['Main'] = 0
+ self.scene.properties['FLT']['Filename'] = self.bname
+
+ #import color palette
+ carray = list()
+ for color in self.col_pal:
+ carray.append(struct.unpack('>i',struct.pack('>BBBB',color[0],color[1],color[2],color[3]))[0])
+ self.scene.properties['FLT']['Color Palette'] = carray
+ Node.blender_import(self)
def parse_appearance_palette(self):
props = dict()
@@ -1696,9 +1765,10 @@ class Database(InterNode):
return True
def get_color(self, color_index):
+ color = None
index = color_index / 128
intensity = float(color_index - 128.0 * index) / 127.0
-
+
if index >= 0 and index <= 1023:
brightest = self.col_pal[index]
r = int(brightest[0] * intensity)
@@ -1707,7 +1777,7 @@ class Database(InterNode):
a = int(brightest[3])
color = [r, g, b, a]
-
+
return color
def parse_color_palette(self):
@@ -1728,15 +1798,56 @@ class Database(InterNode):
def parse_texture_palette(self):
name = self.fw.read_string(200)
index = self.fw.read_int()
- self.tex_pal_lst.append( (index, name) )
+ self.tex_pal[index]= [name, None]
return True
-
- def __init__(self, filename, parent=None):
+
+ def read_attribute_files(self):
+ for tex in self.tex_pal.keys():
+ [name,image] = self.tex_pal[tex]
+ basename = os.path.basename(name)
+ if(image):
+ basename = basename + ".attr"
+ dirname = os.path.dirname(Blender.sys.expandpath(image.getFilename())) #can't rely on original info stored in pallette since it might be relative link
+ newpath = os.path.join(dirname, basename)
+ if os.path.exists(newpath) and not image.properties.has_key('FLT'):
+ fw = flt_filewalker.FltIn(newpath)
+ fw.read_ahead(8) #We dont care what the attribute file says about x/y dimensions
+ image.properties['FLT']={}
+
+ #need to steal code from parse records....
+ props = records['Image']
+ propkeys = props.keys()
+ propkeys.sort()
+ for position in propkeys:
+ (type,length,name) = props[position]
+ image.properties['FLT'][name] = read_prop(fw,type,length)
+ fw.close_file()
+
+ #copy clamp settings
+ wrap = image.properties['FLT']['10i!Wrap']
+ wrapu = image.properties['FLT']['11i!WrapU']
+ wrapv = image.properties['FLT']['12i!WrapV']
+
+ if wrapu == 3 or wrapv == 3:
+ wrapuv = (wrap,wrap)
+ else:
+ wrapuv = (wrapu, wrapv)
+ image.clampX = wrapuv[0]
+ image.clampY = wrapuv[1]
+
+ elif not os.path.exists(newpath):
+ print "Cannot read attribute file:" + newpath
+
+ def __init__(self, filename, grr, parent=None):
if global_prefs['verbose'] >= 1:
print 'Parsing:', filename
print
self.fw = flt_filewalker.FltIn(filename)
+ self.filename = filename
+ self.bname = os.path.splitext(os.path.basename(filename))[0]
+ self.grr = grr
+
Node.__init__(self, parent, self)
InterNode.__init__(self)
@@ -1753,23 +1864,26 @@ class Database(InterNode):
self.root_handler.set_throw_back_lst(throw_back_opcodes)
self.child_handler.set_handler({#130: self.parse_indexed_light_point,
- #111: self.parse_inline_light_point,
+ 111: self.parse_inline_light_point,
2: self.parse_group,
73: self.parse_lod,
4: self.parse_object,
10: self.parse_push,
11: self.parse_pop,
96: self.parse_unhandled,
- 14: self.parse_unhandled,
+ 14: self.parse_dof,
91: self.parse_unhandled,
98: self.parse_unhandled,
63: self.parse_xref})
+ self.scene = Blender.Scene.New(self.bname)
+ self.group = Blender.Group.New(self.bname)
+
self.vert_pal = None
self.lightpoint_appearance_pal = dict()
self.tex_pal = dict()
- self.tex_pal_lst = list()
- self.bl_tex_pal = dict()
+ #self.tex_pal_lst = list()
+ #self.bl_tex_pal = dict()
self.col_pal = list()
self.mat_desc_pal_lst = list()
self.mat_desc_pal = dict()
@@ -1778,7 +1892,70 @@ class Database(InterNode):
'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1',
'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis'])
-def select_file(filename):
+
+def clearparent(root,childhash):
+ for child in childhash[root]:
+ clearparent(child,childhash)
+ root.clrParent(2,0)
+
+def fixscale(root,childhash):
+ for child in childhash[root]:
+ fixscale(child,childhash)
+ location = Blender.Mathutils.Vector(root.getLocation('worldspace'))
+ if location[0] != 0.0 and location[1] != 0.0 and location[2] != 0.0:
+ #direction = Blender.Mathutils.Vector(0-location[0],0-location[1],0-location[2]) #reverse vector
+ smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4)
+ root.setLocation(location * smat)
+ #if its a mesh, we need to scale all of its vertices too
+ if root.type == 'Mesh':
+ smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4)
+ rmesh = root.getData(mesh=True)
+ for v in rmesh.verts:
+ v.co = v.co * smat
+
+
+def reparent(root,childhash,sce):
+ for child in childhash[root]:
+ reparent(child,childhash,sce)
+
+ root.makeParent(childhash[root])
+ sce.update(1)
+
+def update_scene(root,sdone):
+ for object in root.objects:
+ if object.DupGroup:
+ try:
+ child = Blender.Scene.Get(object.DupGroup.name)
+ except:
+ child = None
+ if child and child not in sdone:
+ update_scene(child,sdone)
+ root.makeCurrent()
+ #create a list of children for each object
+ childhash = dict()
+ for object in root.objects:
+ childhash[object] = list()
+
+ for object in root.objects:
+ if object.parent:
+ childhash[object.parent].append(object)
+
+ for object in root.objects:
+ if not object.parent:
+ #recursivley go through and clear all the children of their transformation, starting at deepest level first.
+ clearparent(object,childhash)
+ #now fix the location of everything
+ fixscale(object,childhash)
+ #now fix the parenting
+ reparent(object,childhash,root)
+
+ for object in root.objects:
+ object.makeDisplayList()
+ root.update(1)
+ sdone.append(root)
+
+
+def select_file(filename, grr):
if not Blender.sys.exists(filename):
msg = 'Error: File ' + filename + ' does not exist.'
Blender.Draw.PupMenu(msg)
@@ -1801,13 +1978,12 @@ def select_file(filename):
global_prefs['get_ambient'] = False
global_prefs['get_shininess'] = True
global_prefs['color_from_face'] = True
+ global_prefs['log to blender'] = True
+
+
- # Start loading the file,
- # first set the context
Blender.Window.WaitCursor(True)
Blender.Window.EditMode(0)
- for ob in scene.objects:
- ob.sel=0
FF.add_file_to_search_path(filename)
@@ -1817,7 +1993,7 @@ def select_file(filename):
print
load_time = Blender.sys.time()
- db = Database(filename)
+ db = Database(filename,grr)
db.parse()
load_time = Blender.sys.time() - load_time
@@ -1828,23 +2004,15 @@ def select_file(filename):
import_time = Blender.sys.time()
db.blender_import()
- import_time = Blender.sys.time() - import_time
-
- Blender.Window.ViewLayer(range(1,21))
-
- # FIX UP AFTER DUMMY VERT AND REMOVE DOUBLES
- Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX'])
- for ob in scene.objects.context:
- if ob.type=='Mesh':
- me=ob.getData(mesh=1)
- me.verts.delete(0) # remove the dummy vert
- me.sel= 1
- me.remDoubles(0.0001)
+ if global_prefs['attrib']:
+ print "reading attribute files"
+ db.read_attribute_files()
+ Blender.Window.ViewLayer(range(1,21))
- Blender.Window.RedrawAll()
-
+ update_scene(db.scene,[])
+ import_time = Blender.sys.time() - import_time
if global_prefs['verbose'] >= 1:
print 'Done.'
print
@@ -1854,37 +2022,112 @@ def select_file(filename):
Blender.Window.WaitCursor(False)
+def setimportscale(ID,val):
+ global global_prefs
+ global_prefs['scale'] = val
+def setBpath(fname):
+ global_prefs['fltfile'] = fname
-if global_prefs['verbose'] >= 1:
- print
- print 'OpenFlight Importer'
- print 'Version:', __version__
- print 'Author: Greg MacDonald'
- print __url__[2]
- print
+def event(evt,val):
+ pass
+def but_event(evt):
+
+ global FLTBaseLabel
+ global FLTBaseString
+ global FLTBaseChooser
+ global FLTExport
+ global FLTClose
+
+ global FLTDoXRef
+ global FLTShadeImport
+ global FLTAttrib
+
+ #Import DB
+ if evt == 1:
+ if global_prefs['verbose'] >= 1:
+ print
+ print 'OpenFlight Importer'
+ print 'Version:', __version__
+ print 'Author: Greg MacDonald, Campbell Barton, Geoffrey Bantle'
+ print __url__[2]
+ print
+
+ GRR = GlobalResourceRepository()
+ select_file(global_prefs['fltfile'], GRR)
+ #choose base path for export
+ if evt == 4:
+ Blender.Window.FileSelector(setBpath, "DB Root", global_prefs['fltfile'])
+ #Import custom shading?
+ if evt == 9:
+ global_prefs['smoothshading'] = FLTShadeImport.val
+ #Import Image attribute files
+ if evt == 10:
+ global_prefs['attrib'] = FLTAttrib.val
+ #export XRefs
+ if evt == 13:
+ global_prefs['doxrefs'] = FLTDoXRef.val
+
+ if evt == 2:
+ Draw.Exit()
+
-if __name__ == '__main__':
- Blender.Window.FileSelector(select_file, "Import OpenFlight", "*.flt")
- #select_file('/fe/flt/helnwsflt/helnws.flt')
- #select_file('/fe/flt/Container_006.flt')
- #select_file('/fe/flt/NaplesORIGINALmesh.flt')
- #select_file('/Anti_tank_D30.flt')
- #select_file('/metavr/file_examples/flt/cherrypoint/CherryPoint_liter_runway.flt')
+
+from Blender.BGL import *
+from Blender import Draw
+def gui():
+
+ global FLTBaseLabel
+ global FLTBaseString
+ global FLTBaseChooser
-"""
-TIME= Blender.sys.time()
-import os
-PATH= 'c:\\flt_test'
-for FNAME in os.listdir(PATH):
- if FNAME.lower().endswith('.flt'):
- FPATH= os.path.join(PATH, FNAME)
- newScn= Blender.Scene.New(FNAME)
- newScn.makeCurrent()
- scene= newScn
- select_file(FPATH)
-
-print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
-"""
- \ No newline at end of file
+ global FLTExport
+ global FLTClose
+
+ global FLTDoXRef
+ global FLTShadeImport
+
+ global FLTAttrib
+
+
+ glClearColor(0.772,0.832,0.847,1.0)
+ glClear(GL_COLOR_BUFFER_BIT)
+
+ areas = Blender.Window.GetScreenInfo()
+ curarea = Blender.Window.GetAreaID()
+ curRect = None
+
+ for area in areas:
+ if area['id'] == curarea:
+ curRect = area['vertices']
+ break
+
+ width = curRect[2] - curRect[0]
+ height = curRect[3] - curRect[1]
+ cx = 50
+ cy = height - 80
+
+ FLTBaseLabel = Draw.Label("Base file:",cx,cy,100,20)
+ FLTBaseString = Draw.String("",3,cx+100,cy,300,20,global_prefs['fltfile'],255,"Root DB file")
+ FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder")
+
+ cy = cy-40
+ FLTScale = Draw.Number("Import Scale",14,cx,cy,220,20,global_prefs['scale'],0.0,100.0,"Export scaleing factor",setimportscale)
+
+ cy = cy-40
+ FLTDoXRef = Draw.Toggle("Import XRefs", 13,cx,cy,220,20,global_prefs['doxrefs'],"Import External references")
+
+ cy = cy-40
+ FLTShadeImport = Draw.Toggle("Import Custom Shading",9,cx,cy,220,20,global_prefs['smoothshading'],"Import custom shading via edgesplit modifiers")
+
+ cy = cy-40
+ FLTAttrib = Draw.Toggle("Import Attribute Files", 10,cx,cy,220,20,global_prefs['attrib'],"Import Image Attribute files")
+
+ cy = cy - 40
+ FLTExport = Draw.PushButton("Import",1,cx,20,100,20,"Import FLT Database")
+ FLTClose = Draw.PushButton("Close",2,cx+120,20,100,20,"Close Window")
+
+
+
+Draw.Register(gui,event,but_event) \ No newline at end of file
diff --git a/release/scripts/flt_palettemanager.py b/release/scripts/flt_palettemanager.py
new file mode 100644
index 00000000000..c641a0a4f08
--- /dev/null
+++ b/release/scripts/flt_palettemanager.py
@@ -0,0 +1,388 @@
+#!BPY
+
+"""
+Name: 'FLT Palette Manager'
+Blender: 240
+Group: 'Misc'
+Tooltip: 'Manage FLT colors'
+"""
+
+__author__ = "Geoffrey Bantle"
+__version__ = "1.0 11/21/2007"
+__email__ = ('scripts', 'Author, ')
+__url__ = ('blender', 'elysiun')
+
+__bpydoc__ ="""\
+
+This script manages colors in OpenFlight databases. OpenFlight is a
+registered trademark of MultiGen-Paradigm, Inc.
+
+Todo:
+-Figure out whats causing the PC speaker to beep when initializing...
+
+Feature overview and more availible at:
+http://wiki.blender.org/index.php/Scripts/Manual/FLTools
+"""
+
+# --------------------------------------------------------------------------
+# flt_palettemanager.py version 0.1 2005/04/08
+# --------------------------------------------------------------------------
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# Copyright (C) 2007: Blender Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+# --------------------------------------------------------------------------
+
+import Blender.Draw as Draw
+from Blender.BGL import *
+import Blender
+import flt_properties
+import flt_defaultp as defaultp
+from flt_properties import *
+
+
+palette_size = 12
+palette_x = 0
+palette_y = 0
+
+colors = list()
+curint = 1.0
+curswatch = 0
+#make a default palette, not very useful.
+cinc = 1.0 / 1024.0
+cstep = 0.0
+picker = None
+ptt = ""
+for i in xrange(1024):
+ colors.append([cstep,cstep,cstep])
+ cstep = cstep + cinc
+def update_state():
+ state = dict()
+ state["activeScene"] = Blender.Scene.getCurrent()
+ state["activeObject"] = state["activeScene"].getActiveObject()
+ state["activeMesh"] = None
+ if state["activeObject"] and state["activeObject"].type == 'Mesh':
+ state["activeMesh"] = state["activeObject"].getData(mesh=True)
+
+ state["activeFace"] = None
+ if state["activeMesh"]:
+ if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None:
+ state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace]
+
+ return state
+
+def pack_face_index(index, intensity):
+ return ((127*intensity)+(128*index))
+def unpack_face_index(face_index):
+ index = face_index / 128
+ intensity = float(face_index - 128.0 * index) / 127.0
+ return(index,intensity)
+
+def event(evt,val):
+ global palette_size
+ global palette_x
+ global palette_y
+ global colors
+ global curint
+ global curswatch
+
+ areas = Blender.Window.GetScreenInfo()
+ curarea = Blender.Window.GetAreaID()
+ curRect = None
+ editmode = 0
+
+ for area in areas:
+ if area['id'] == curarea:
+ curRect = area['vertices']
+ break
+
+ if evt == Draw.LEFTMOUSE:
+ mval = Blender.Window.GetMouseCoords()
+ rastx = mval[0] - curRect[0]
+ rasty = mval[1] - curRect[1]
+
+ swatchx = (rastx -palette_x) / palette_size #+state["palette_x"]
+ swatchy = (rasty -palette_y) / palette_size #+state["palette_y"]
+ if rastx > palette_x and rastx < (palette_x + palette_size * 32) and rasty > palette_y and rasty < (palette_y+ palette_size* 32):
+ if swatchx < 32 and swatchy < 32:
+ curswatch = (swatchx * 32) + swatchy
+ Draw.Redraw(1)
+
+ elif swatchy < 34 and swatchx < 32:
+ curint = 1.0 - (float(rastx-palette_x)/(palette_size*32.0))
+ Draw.Redraw(1)
+
+ #copy current color and intensity to selected faces.
+ elif evt == Draw.CKEY:
+
+ if Blender.Window.EditMode():
+ Blender.Window.EditMode(0)
+ editmode = 1
+ state = update_state()
+
+ #retrieve color from palette
+ color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch]))
+ actmesh = state["activeMesh"]
+ if actmesh:
+ if(Blender.Window.GetKeyQualifiers() != Blender.Window.Qual["CTRL"]):
+ selfaces = list()
+ for face in actmesh.faces:
+ if face.sel:
+ selfaces.append(face)
+
+ if not "FLT_COL" in actmesh.faces.properties:
+ actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"])
+ for face in actmesh.faces:
+ face.setProperty("FLT_COL",127) #default
+ try:
+ actmesh.activeColorLayer = "FLT_Fcol"
+ except:
+ actmesh.addColorLayer("FLT_Fcol")
+ actmesh.activeColorLayer = "FLT_Fcol"
+
+
+ for face in selfaces:
+ #First append packed index + color and store in face property
+ face.setProperty("FLT_COL",int(pack_face_index(curswatch,curint)))
+ #Save baked color to face vertex colors
+ for col in face.col:
+ col.r = int(color[0] * curint)
+ col.g = int(color[1] * curint)
+ col.b = int(color[2] * curint)
+ col.a = int(color[3] * curint)
+ else:
+ if Blender.Mesh.Mode() == Blender.Mesh.SelectModes['VERTEX']:
+ if not 'FLT_VCOL' in actmesh.verts.properties:
+ actmesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"])
+ for vert in actmesh.verts:
+ vert.setProperty("FLT_VCOL",127)
+ else:
+ for vert in actmesh.verts:
+ if vert.sel:
+ vert.setProperty("FLT_VCOL",int(pack_face_index(curswatch,curint)))
+
+ if editmode:
+ Blender.Window.EditMode(1)
+
+ Blender.Window.RedrawAll()
+
+ #grab color and intensity from active face
+ elif evt == Draw.VKEY:
+ if Blender.Window.EditMode():
+ Blender.Window.EditMode(0)
+ editmode = 1
+ state = update_state()
+
+ actmesh = state["activeMesh"]
+ activeFace = state["activeFace"]
+
+
+ if activeFace:
+ if not "FLT_COL" in actmesh.faces.properties:
+ actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"])
+ for face in actmesh.faces:
+ face.setProperty("FLT_COL",127) #default
+ try:
+ actmesh.activeColorLayer = "FLT_Fcol"
+ except:
+ actmesh.addColorLayer("FLT_Fcol")
+ actmesh.activeColorLayer = "FLT_Fcol"
+ tcol = activeFace.getProperty("FLT_COL")
+ (index,intensity) = unpack_face_index(tcol)
+ curswatch = index
+ curint = intensity
+
+ if editmode:
+ Blender.Window.EditMode(1)
+
+ Blender.Window.RedrawAll()
+
+ elif evt == Draw.ESCKEY:
+ Draw.Exit()
+
+ if editmode:
+ Blender.Window.EditMode(1)
+
+def update_all():
+ global colors
+ state = update_state()
+ #update the baked FLT colors for all meshes.
+ for object in state["activeScene"].objects:
+ if object.type == "Mesh":
+ mesh = object.getData(mesh=True)
+ if 'FLT_COL' in mesh.faces.properties:
+ mesh.activeColorLayer = "FLT_Fcol"
+ for face in mesh.faces:
+ (index,intensity) = unpack_face_index(face.getProperty('FLT_COL'))
+ color = struct.unpack('>BBBB',struct.pack('>I',colors[index]))
+ #update the vertex colors for this face
+ for col in face.col:
+ col.r = int(color[0] * intensity)
+ col.g = int(color[1] * intensity)
+ col.b = int(color[2] * intensity)
+ col.a = 255
+
+
+def but_event(evt):
+ global palette_size
+ global palette_x
+ global palette_y
+ global colors
+ global curint
+ global curswatch
+ global picker
+ state = update_state()
+
+ if evt == 1:
+ if picker.val:
+ rval = (int(picker.val[0]*255),int(picker.val[1]*255),int(picker.val[2]*255),255)
+ rval = struct.pack('>BBBB',rval[0],rval[1],rval[2],rval[3])
+ rval = struct.unpack('>i',rval)
+ colors[curswatch] = rval[0]
+ #go cd through all meshes and update their FLT colors
+ update_all()
+
+ Draw.Redraw(1)
+def init_pal():
+ global palette_size
+ global palette_x
+ global palette_y
+ global colors
+ global curint
+ global curswatch
+
+ state = update_state()
+
+ if not state["activeScene"].properties.has_key('FLT'):
+ state["activeScene"].properties['FLT'] = dict()
+
+ try:
+ colors = state["activeScene"].properties['FLT']['Color Palette']
+ except:
+ state["activeScene"].properties['FLT']['Color Palette'] = defaultp.pal
+ colors = state["activeScene"].properties['FLT']['Color Palette']
+
+def draw_palette():
+ global palette_size
+ global palette_x
+ global palette_y
+ global colors
+ global curint
+ global curswatch
+ global picker
+
+ state = update_state()
+ init_pal()
+
+ ssize = palette_size
+ xpos = palette_x
+ cid = 0
+
+ highlight = [(palette_x,palette_y),(palette_x+palette_size,palette_y),(palette_x+palette_size,palette_y+palette_size),(palette_x,palette_y+palette_size)]
+ for x in xrange(32):
+ ypos = palette_y
+ for y in xrange(32):
+ color = struct.unpack('>BBBB',struct.pack('>I',colors[cid]))
+ glColor3f(color[0]/255.0,color[1]/255.0,color[2]/255.0)
+ glBegin(GL_POLYGON)
+ glVertex2i(xpos,ypos)
+ glVertex2i(xpos+ssize,ypos)
+ glVertex2i(xpos+ssize,ypos+ssize)
+ glVertex2i(xpos,ypos+ssize)
+ glEnd()
+
+ if curswatch == cid:
+ highlight[0] = (xpos,ypos)
+ highlight[1] = (xpos+ssize,ypos)
+ highlight[2] = (xpos+ssize,ypos+ssize)
+ highlight[3] = (xpos,ypos+ssize)
+
+ glColor3f(0.0,0.0,0.0)
+ glBegin(GL_LINE_LOOP)
+ glVertex2i(xpos,ypos)
+ glVertex2i(xpos+ssize,ypos)
+ glVertex2i(xpos+ssize,ypos+ssize)
+ glVertex2i(xpos,ypos+ssize)
+ glVertex2i(xpos,ypos)
+ glEnd()
+
+
+ cid = cid + 1
+ ypos = ypos + ssize
+
+ xpos = xpos + ssize
+
+ #draw intensity gradient
+ color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch]))
+ color = [color[0]/255.0,color[1]/255.0,color[2]/255.0]
+ colsteps = [color[0]/255.0,color[1]/255.0,color[2]/255.0]
+ stripwidth = (palette_size * 32.0) / 256
+ strippad = palette_size / 2.0
+
+ xpos = palette_x
+ grady = (palette_y + (palette_size * 32.0)) + strippad
+ for x in xrange(256):
+ color[0] = color[0] - colsteps[0]
+ color[1] = color[1] - colsteps[1]
+ color[2] = color[2] - colsteps[2]
+
+ glColor3f(color[0], color[1] ,color[2])
+ glBegin(GL_POLYGON)
+ glVertex2f(xpos,grady)
+ glVertex2f(xpos+stripwidth,grady)
+ glVertex2f(xpos+stripwidth,grady+palette_size)
+ glVertex2f(xpos,grady+palette_size)
+ glEnd()
+ xpos = xpos + stripwidth
+
+ #draw intensity slider bar
+ #xposition == 512 - ((curint) * 512)
+ xpos = ((palette_size*32) * (1.0 - curint)) + palette_x
+ glColor3f(1.0,1.0,1.0)
+ glBegin(GL_LINE_LOOP)
+ glVertex2i(xpos-6,grady-1)
+ glVertex2i(xpos+6,grady-1)
+ glVertex2i(xpos+6,grady+palette_size+1)
+ glVertex2i(xpos-6,grady+palette_size+1)
+ #glVertex2i(xpos-6,grady+7)
+ glEnd()
+
+ #draw color picker
+ color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch]))
+ pickcol = (color[0]/255.0,color[1]/255.0,color[2]/255.0)
+ picker = Blender.Draw.ColorPicker(1,highlight[0][0]+1,highlight[0][1]+1,ssize-2,ssize-2,pickcol,ptt)
+
+ #draw highlight swatch
+ glColor3f(1.0,1.0,1.0)
+ glBegin(GL_LINE_LOOP)
+ glVertex2i(highlight[0][0],highlight[0][1])
+ glVertex2i(highlight[1][0],highlight[1][1])
+ glVertex2i(highlight[2][0],highlight[2][1])
+ glVertex2i(highlight[3][0],highlight[3][1])
+ glVertex2i(highlight[0][0],highlight[0][1])
+ glEnd()
+
+def gui():
+ glClearColor(0.5,0.5,0.5,1.0)
+ glClear(GL_COLOR_BUFFER_BIT)
+ draw_palette()
+
+
+init_pal()
+Draw.Register(gui,event,but_event)
+
diff --git a/release/scripts/flt_properties.py b/release/scripts/flt_properties.py
new file mode 100644
index 00000000000..2c9e9d7667b
--- /dev/null
+++ b/release/scripts/flt_properties.py
@@ -0,0 +1,619 @@
+#!BPY
+# flt_properties.py. For setting default OpenFLight ID property types
+# Copyright (C) 2007 Blender Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+__bpydoc__ ="""\
+Utility functions and data defintions used by OpenFlight I/O and tool scripts. OpenFlight is a
+registered trademark of MultiGen-Paradigm, Inc.
+"""
+
+
+import struct
+
+bitsLSB = [2147483648]
+for i in xrange(31):
+ bitsLSB.append(bitsLSB[-1]/2)
+bitsRSB = bitsLSB[:]
+bitsRSB.reverse()
+
+def pack_color(col):
+ return struct.pack('>B',col[3]) + struct.pack('>B',col[2]) + struct.pack('>B',col[1]) + struct.pack('>B',col[0])
+
+def unpack_color(col):
+ string = struct.pack('>I', col)
+ r = struct.unpack('>B',string[3:4])
+ g = struct.unpack('>B',string[2:3])
+ b = struct.unpack('>B',string[1:2])
+ a = struct.unpack('>B',string[0:1])
+ return [r,g,b,a]
+
+def reverse_bits(len,num):
+ bitbucket = list()
+ rval = 0
+
+ for i in xrange(len):
+ if num & bitsRSB[i]:
+ bitbucket.append(1)
+ else:
+ bitbucket.append(0)
+
+ bitbucket.reverse()
+
+ for i, bit in enumerate(bitbucket):
+ if bit:
+ rval |= bitsLSB[i]
+
+ return rval
+
+
+opcode_name = { 0: 'db',
+ 1: 'head',
+ 2: 'grp',
+ 4: 'obj',
+ 5: 'face',
+ 10: 'push',
+ 11: 'pop',
+ 14: 'dof',
+ 19: 'push sub',
+ 20: 'pop sub',
+ 21: 'push ext',
+ 22: 'pop ext',
+ 23: 'cont',
+ 31: 'comment',
+ 32: 'color pal',
+ 33: 'long id',
+ 49: 'matrix',
+ 50: 'vector',
+ 52: 'multi-tex',
+ 53: 'uv lst',
+ 55: 'bsp',
+ 60: 'rep',
+ 61: 'inst ref',
+ 62: 'inst def',
+ 63: 'ext ref',
+ 64: 'tex pal',
+ 67: 'vert pal',
+ 68: 'vert w col',
+ 69: 'vert w col & norm',
+ 70: 'vert w col, norm & uv',
+ 71: 'vert w col & uv',
+ 72: 'vert lst',
+ 73: 'lod',
+ 74: 'bndin box',
+ 76: 'rot edge',
+ 78: 'trans',
+ 79: 'scl',
+ 80: 'rot pnt',
+ 81: 'rot and/or scale pnt',
+ 82: 'put',
+ 83: 'eyepoint & trackplane pal',
+ 84: 'mesh',
+ 85: 'local vert pool',
+ 86: 'mesh prim',
+ 87: 'road seg',
+ 88: 'road zone',
+ 89: 'morph vert lst',
+ 90: 'link pal',
+ 91: 'snd',
+ 92: 'rd path',
+ 93: 'snd pal',
+ 94: 'gen matrix',
+ 95: 'txt',
+ 96: 'sw',
+ 97: 'line styl pal',
+ 98: 'clip reg',
+ 100: 'ext',
+ 101: 'light src',
+ 102: 'light src pal',
+ 103: 'reserved',
+ 104: 'reserved',
+ 105: 'bndin sph',
+ 106: 'bndin cyl',
+ 107: 'bndin hull',
+ 108: 'bndin vol cntr',
+ 109: 'bndin vol orient',
+ 110: 'rsrvd',
+ 111: 'light pnt',
+ 112: 'tex map pal',
+ 113: 'mat pal',
+ 114: 'name tab',
+ 115: 'cat',
+ 116: 'cat dat',
+ 117: 'rsrvd',
+ 118: 'rsrvd',
+ 119: 'bounding hist',
+ 120: 'rsrvd',
+ 121: 'rsrvd',
+ 122: 'push attrib',
+ 123: 'pop attrib',
+ 124: 'rsrvd',
+ 125: 'rsrvd',
+ 126: 'curv',
+ 127: 'road const',
+ 128: 'light pnt appear pal',
+ 129: 'light pnt anim pal',
+ 130: 'indexed lp',
+ 131: 'lp sys',
+ 132: 'indx str',
+ 133: 'shdr pal'}
+
+
+typecodes = ['c','C','s','S','i','I','f','d','t']
+
+FLT_GRP = 2
+FLT_OBJ = 4
+FLT_LOD = 73
+FLT_XRF = 63
+FLT_DOF = 14
+FLT_ILP = 111
+FLT_DB = 1
+FLT_FCE = 5
+
+#not actual opcodes
+FLT_NUL = 0
+FLT_EXP = -1
+
+#valid childtypes for each FLT node type
+FLT_CHILDTYPES = {
+ FLT_GRP : [111,2,73,4,14,63],
+ FLT_OBJ : [111],
+ FLT_LOD : [111,2,73,4,14,63],
+ FLT_XRF : [],
+ FLT_DOF : [111,2,73,4,14,63],
+ FLT_ILP : []
+}
+
+#List of nodes that can have faces as children
+FLT_FACETYPES = [
+ FLT_GRP,
+ FLT_OBJ,
+ FLT_LOD,
+ FLT_DOF
+]
+
+def write_prop(fw,type,value,length):
+ if type == 'c':
+ fw.write_char(value)
+ elif type == 'C':
+ fw.write_uchar(value)
+ elif type == 's':
+ fw.write_short(value)
+ elif type == 'S':
+ fw.write_ushort(value)
+ elif type == 'i':
+ fw.write_int(value)
+ elif type == 'I':
+ fw.write_uint(value)
+ elif type == 'd':
+ fw.write_double(value)
+ elif type == 'f':
+ fw.write_float(value)
+ elif type == 't':
+ fw.write_string(value,length)
+
+def read_prop(fw,type,length):
+ rval = None
+ if type == 'c':
+ rval = fw.read_char()
+ elif type == 'C':
+ rval = fw.read_uchar()
+ elif type == 's':
+ rval = fw.read_short()
+ elif type == 'S':
+ rval = fw.read_ushort()
+ elif type == 'i':
+ rval = fw.read_int()
+ elif type == 'I':
+ rval = fw.read_uint()
+ elif type == 'd':
+ rval = fw.read_double()
+ elif type == 'f':
+ rval = fw.read_float()
+ elif type == 't':
+ rval = fw.read_string(length)
+ return rval
+
+FLTGroup = {
+ '3t8!id' : 'G',
+ '4s!priority' : 0,
+ '5s!reserved1' : 0,
+ '6i!flags' : 0,
+ '7s!special1' : 0,
+ '8s!special2' : 0,
+ '9s!significance' : 0,
+ '10c!layer code' : 0,
+ '11c!reserved2' : 0,
+ '12i!reserved3' : 0,
+ '13i!loop count' : 0,
+ '14f!loop duration' : 0,
+ '15f!last frame duration' : 0
+}
+FLTGroupDisplay = [5,11,12]
+
+FLTObject = {
+ '3t8!id' : 'O',
+ '4I!flags' : 0,
+ '5s!priority' : 0,
+ '6S!transp' : 0,
+ '7s!SFX1' : 0,
+ '8s!SFX2' : 0,
+ '9s!significance' : 0,
+ '10s!reserved' : 0
+}
+FLTObjectDisplay = [10]
+
+FLTLOD = {
+ '3t8!id' : 'L',
+ '4i!reserved' : 0,
+ '5d!switch in' : 0,
+ '6d!switch out' : 0,
+ '7s!sfx ID1' : 0,
+ '8s!sfx ID2' : 0,
+ '9I!flags' : 0,
+ '10d!X co' : 0,
+ '11d!Y co' : 0,
+ '12d!Z co' : 0,
+ '13d!Transition' : 0,
+ '14d!Sig Size' : 0
+}
+FLTLODDisplay = [4]
+
+FLTInlineLP = {
+ '3t8!id' : 'Lp',
+ '4s!smc' : 0,
+ '5s!fid' : 0,
+ '6C!back color: a' : 255,
+ '7C!back color: b' : 255,
+ '8C!back color: g' : 255,
+ '9C!back color: r' : 255,
+ '10i!display mode' : 255,
+ '11f!intensity' : 1.0,
+ '12f!back intensity' : 0.0,
+ '13f!minimum defocus' : 0.0,
+ '14f!maximum defocus' : 1.0,
+ '15i!fading mode' : 0,
+ '16i!fog punch mode' : 0,
+ '17i!directional mode' : 1,
+ '18i!range mode' : 0,
+ '19f!min pixel size' : 1.0,
+ '20f!max pixel size' : 1024,
+ '21f!actual size' : 0.25,
+ '22f!trans falloff pixel size' : 0.25,
+ '23f!trans falloff exponent' : 1.0,
+ '24f!trans falloff scalar' : 1.0,
+ '25f!trans falloff clamp' : 1.0,
+ '26f!fog scalar' : 0.25,
+ '27f!fog intensity' : 1.0,
+ '28f!size threshold' : 0.1,
+ '29i!directionality' : 0,
+ '30f!horizontal lobe angle' : 180.0,
+ '31f!vertical lobe angle' : 180.0,
+ '32f!lobe roll angle' : 0.0,
+ '33f!dir falloff exponent' : 1.0,
+ '34f!dir ambient intensity' : 0.1,
+ '35f!anim period' : 0,
+ '36f!anim phase' : 0,
+ '37f!anim enabled' : 0,
+ '38f!significance' : 0.0,
+ '39i!draw order' : 0,
+ '40I!flags' : 813875616,
+ '41f!roti' : 0,
+ '42f!rotj' : 0,
+ '43f!rotk' : 0
+}
+
+FLTInlineLPDisplay = [35,36,37,41,42,43]
+
+FLTXRef = {
+ '3t200!filename' : '', #we dont actually use this value on export
+ '4i!reserved' : 0,
+ '5I!flag' : -478150656,
+ '6s!bbox' : 0,
+ '7s!reserved' : 0
+}
+
+FLTXRefDisplay = [4,7,3]
+
+FLTDOF = {
+ '3t8!id' : 'D',
+ '4i!reserved' : 0,
+ '5d!ORIGX' : 0.0,
+ '6d!ORIGY' : 0.0,
+ '7d!ORIGZ' : 0.0,
+ '8d!XAXIS-X' : 10.0,
+ '9d!XAXIS-Y' : 0.0,
+ '10d!XAXIS-Z' : 0.0,
+ '11d!XYPLANE-X' : 0.0,
+ '12d!XYPLANE-Y' : 10.0,
+ '13d!XZPLANE-Z' : 0.0,
+ '14d!ZMIN' : 0.0,
+ '15d!ZMAX' : 0.0,
+ '16d!ZCUR' : 0.0,
+ '17d!ZSTEP' : 0.0,
+ '18d!YMIN' : 0.0,
+ '19d!YMAX' : 0.0,
+ '20d!YCUR' : 0.0,
+ '21d!YSTEP' : 0.0,
+ '22d!XMIN' : 0.0,
+ '23d!XMAX' : 0.0,
+ '24d!XCUR' : 0.0,
+ '25d!XSTEP' : 0.0,
+ '26d!PITCH-MIN' : 0.0,
+ '27d!PITCH-MAX' : 0.0,
+ '28d!PITCH-CUR' : 0.0,
+ '29d!PITCH-STEP' : 0.0,
+ '30d!ROLL-MIN' : 0.0,
+ '31d!ROLL-MAX' : 0.0,
+ '32d!ROLL-CUR' : 0.0,
+ '33d!ROLL-STEP' : 0.0,
+ '34d!YAW-MIN' : 0.0,
+ '35d!YAW-MAX' : 0.0,
+ '36d!YAW-CUR' : 0.0,
+ '37d!YAW-STEP' : 0.0,
+ '38d!ZSIZE-MIN' : 0.0,
+ '39d!ZSIZE-MAX' : 0.0,
+ '40d!ZSIZE-CUR' : 1.0,
+ '41d!ZSIZE-STEP' : 0.0,
+ '42d!YSIZE-MIN' : 0.0,
+ '43d!YSIZE-MAX' : 0.0,
+ '44d!YSIZE-CUR' : 1.0,
+ '45d!YSIZE-STEP' : 0.0,
+ '46d!XSIZE-MIN' : 0.0,
+ '47d!XSIZE-MAX' : 0.0,
+ '48d!XSIZE-CUR' : 1.0,
+ '49d!XSIZE-STEP' : 0.0,
+ '50I!FLAG' : 1897582,
+ '51i!reserved2' : 0
+}
+
+FLTDOFDisplay = [4]
+
+FLTImage = {
+ '3i!RealU Direction' : 0,
+ '4i!RealV Direction' : 0,
+ '5i!UpX' : 0,
+ '6i!UpY' : 0,
+ '7i!File Format' : 0,
+ '8i!Min Filter' : 6,
+ '9i!Mag Filter' : 1,
+ '10i!Wrap' : 0,
+ '11i!WrapU' : 0,
+ '12i!WrapV' : 0,
+ '13i!Modified' : 0,
+ '14i!PivotX' : 0,
+ '15i!PivotY' : 0,
+ '16i!Enviorment' : 0,
+ '17i!WhiteAlpha' : 0,
+ '18i!reserved1' : 0,
+ '19i!reserved2' : 0,
+ '20i!reserved3' : 0,
+ '21i!reserved4' : 0,
+ '22i!reserved5' : 0,
+ '23i!reserved6' : 0,
+ '24i!reserved7' : 0,
+ '25i!reserved8' : 0,
+ '26i!reserved9' : 0,
+ '27d!RealU Direction' : 0,
+ '28d!RealV Direction' : 0,
+ '29i!Origin' : 0,
+ '30i!Kernel no.' : 0,
+ '31i!Internal Format' : 0,
+ '32i!External Format' : 0,
+ '33i!MipMap Filter?' : 0,
+ '34f!MMF1' : 0.0,
+ '35f!MMF2' : 0.0,
+ '36f!MMF3' : 0.0,
+ '37f!MMF4' : 0.0,
+ '38f!MMF5' : 0.0,
+ '39f!MMF6' : 0.0,
+ '40f!MMF7' : 0.0,
+ '41f!MMF8' : 0.0,
+ '42i!Tex CPs?' : 0,
+ '43f!LOD0 CP' : 0.0,
+ '44f!Scale0 CP' : 0.0,
+ '45f!LOD1 CP' : 0.0,
+ '46f!Scale1 CP' : 0.0,
+ '47f!LOD2 CP' : 0.0,
+ '48f!Scale2 CP' : 0.0,
+ '49f!LOD3 CP' : 0.0,
+ '50f!Scale3 CP' : 0.0,
+ '51f!LOD4 CP' : 0.0,
+ '52f!Scale4 CP' : 0.0,
+ '53f!LOD5 CP' : 0.0,
+ '54f!Scale5 CP' : 0.0,
+ '55f!LOD6 CP' : 0.0,
+ '56f!Scale6 CP' : 0.0,
+ '57f!LOD7 CP' : 0.0,
+ '58f!Scale7 CP' : 0.0,
+ '59f!Control Clamp' : 0.0,
+ '60i!Mag Alpha Filter' : 0,
+ '61i!Mag Color Filter' : 0,
+ '62f!reserved10' : 0,
+ '63f!reserved11' : 0,
+ '64f!reserved12' : 0,
+ '65f!reserved13' : 0,
+ '66f!reserved14' : 0,
+ '67f!reserved15' : 0,
+ '68f!reserved16' : 0,
+ '69f!reserved17' : 0,
+ '70f!reserved18' : 0,
+ '71d!Lambert Central' : 0.0,
+ '72d!Lambert Upper' : 0.0,
+ '73d!Lambert Lower' : 0.0,
+ '74d!reserved19' : 0,
+ '75f!reserved20' : 0,
+ '76f!reserved21' : 0,
+ '77f!reserved22' : 0,
+ '78f!reserved23' : 0,
+ '79f!reserved24' : 0,
+ '80i!Tex Detail?' : 0,
+ '81i!Tex J' : 0,
+ '82i!Tex K' : 0,
+ '83i!Tex M' : 0,
+ '84i!Tex N' : 0,
+ '85i!Tex Scramble' : 0,
+ '86i!Tex Tile?' : 0,
+ '87f!Tex Tile LLU' : 0.0,
+ '88f!Tex Tile LLV' : 0.0,
+ '89f!Tex Tile URU' : 0.0,
+ '90f!Tex Tile URV' : 0.0,
+ '91i!Projection' : 0,
+ '92i!Earth Model' : 0,
+ '93i!reserved25' : 0,
+ '94i!UTM Zone' : 0,
+ '95i!Image Origin' : 0,
+ '96i!GPU' : 0,
+ '97i!reserved26' : 0,
+ '98i!reserved27' : 0,
+ '99i!GPU Hemi' : 0,
+ '100i!reserved41' : 0,
+ '101i!reserved42' : 0,
+ '102i!reserved43' : 0,
+ '103i!Cubemap' : 0,
+ '104t588!reserved44' : '',
+ '105t512!Comments' : '',
+ '106i!reserved28' : 0,
+ '107i!reserved29' : 0,
+ '108i!reserved30' : 0,
+ '109i!reserved31' : 0,
+ '110i!reserved32' : 0,
+ '111i!reserved33' : 0,
+ '112i!reserved34' : 0,
+ '113i!reserved35' : 0,
+ '114i!reserved36' : 0,
+ '115i!reserved37' : 0,
+ '116i!reserved38' : 0,
+ '117i!reserved39' : 0,
+ '118i!reserved40' : 0,
+ '119i!reserved45' : 0,
+ '120i!Format Version' : 0,
+ '121i!GPU num' : 0,
+}
+
+FLTImageDisplay = [18,19,29,21,22,23,24,25,26,62,63,64,65,66,67,68,69,70,74,75,76,77,78,79,93,97,98,102,114]
+
+FLTHeader = {
+ '3t8!id' : 'db',
+ '4i!version' : 1620,
+ '5i!editversion' : 0,
+ '6t32!date' : 0,
+ '7s!NGID' : 0,
+ '8s!NLID' : 0,
+ '9s!NOID' : 0,
+ '10s!NFID' : 0,
+ '11s!UMULT' : 1,
+ '12c!units' : 0,
+ '13c!set white' : 0,
+ '14I!flags' : 0x80000000,
+ '15i!reserved1' : 0,
+ '16i!reserved2' : 0,
+ '17i!reserved3' : 0,
+ '18i!reserved4' : 0,
+ '19i!reserved5' : 0,
+ '20i!reserved6' : 0,
+ '21i!projection type' : 0,
+ '22i!reserved7' : 0,
+ '23i!reserved8' : 0,
+ '24i!reserved9' : 0,
+ '25i!reserved10' : 0,
+ '26i!reserved11' : 0,
+ '27i!reserved12' : 0,
+ '28i!reserved13' : 0,
+ '29s!NDID' : 0,
+ '30s!vstore' : 1,
+ '31i!origin' : 0,
+ '32d!sw x' : 0,
+ '33d!sw y' : 0,
+ '34d!dx' : 0,
+ '35d!dy' : 0,
+ '36s!NSID' : 0,
+ '37s!NPID' : 0,
+ '38i!reserved14' : 0,
+ '39i!reserved15' : 0,
+ '40s!NCID' : 0,
+ '41s!NTID' : 0,
+ '42s!NBID' : 0,
+ '43s!NWID' : 0,
+ '44i!reserved14' : 0,
+ '45d!sw lat' : 0,
+ '46d!sw lon' : 0,
+ '47d!ne lat' : 0,
+ '48d!ne lon' : 0,
+ '49d!origin lat' : 0,
+ '50d!origin lon' : 0,
+ '51d!lambert lat1' : 0,
+ '52d!lambert lat2' : 0,
+ '53s!NLSID' : 0,
+ '54s!NLPID' : 0,
+ '55s!NRID' : 0,
+ '56s!NCATID' : 0,
+ '57s!reserved15' : 0,
+ '58s!reserved16' : 0,
+ '59s!reserved17' : 0,
+ '60s!reserved18' : 0,
+ '61i!ellipsoid model' : 1,
+ '62s!NAID' : 0,
+ '63s!NCVID' : 0,
+ '64s!utm zone' : 0,
+ '65t6!reserved19' : 0,
+ '66d!dz' : 0,
+ '67d!radius' : 0,
+ '68S!NMID' : 0,
+ '69S!NLPSID' : 0,
+ '70i!reserved20' : 0,
+ '71d!major axis' : 0,
+ '72d!minor axis' : 0,
+}
+
+FLT_Records = {
+ 2 : FLTGroup,
+ 4 : FLTObject,
+ 73 : FLTLOD,
+ 63 : FLTXRef,
+ 14 : FLTDOF,
+ 1 : FLTHeader,
+ 111 : FLTInlineLP,
+ 'Image' : FLTImage
+}
+
+def process_recordDefs():
+ records = dict()
+ for record in FLT_Records:
+ props = dict()
+ for prop in FLT_Records[record]:
+ position = ''
+ slice = 0
+ (format,name) = prop.split('!')
+ for i in format:
+ if i not in typecodes:
+ position = position + i
+ slice = slice + 1
+ else:
+ break
+ type = format[slice:]
+ length = type[1:]
+ if len(length) == 0:
+ length = 1
+ else:
+ type = type[0]
+ length = int(length)
+
+ props[int(position)] = (type,length,prop)
+ records[record] = props
+ return records
+
+
diff --git a/release/scripts/flt_toolbar.py b/release/scripts/flt_toolbar.py
new file mode 100644
index 00000000000..213fac1bb3c
--- /dev/null
+++ b/release/scripts/flt_toolbar.py
@@ -0,0 +1,654 @@
+#!BPY
+
+"""
+Name: 'FLT Toolbar'
+Blender: 240
+Group: 'Misc'
+Tooltip: 'Tools for working with FLT databases'
+"""
+
+__author__ = "Geoffrey Bantle"
+__version__ = "1.0 11/21/07"
+__email__ = ('scripts', 'Author, ')
+__url__ = ('blender', 'elysiun')
+
+__bpydoc__ ="""\
+This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a
+registered trademark of MultiGen-Paradigm, Inc.
+
+Feature overview and more availible at:
+http://wiki.blender.org/index.php/Scripts/Manual/FLTools
+"""
+
+# --------------------------------------------------------------------------
+# flt_palettemanager.py version 0.1 2005/04/08
+# --------------------------------------------------------------------------
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# Copyright (C) 2007: Blender Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+# --------------------------------------------------------------------------
+
+import Blender.Draw as Draw
+from Blender.BGL import *
+import Blender
+import flt_properties
+reload(flt_properties)
+from flt_properties import *
+
+xrefprefix = ""
+xrefstack = list()
+vofsstack = list()
+vquatstack = list()
+prop_w = 256
+prop_h = 256
+
+
+#event codes
+evcode = {
+ "XREF_MAKE" : 100,
+ "XREF_EDIT" : 101,
+ "XREF_FILE" : 102,
+ "XREF_PICK" : 103,
+ "XREF_SELECT" : 104,
+ "XREF_POP" : 105,
+ "XREF_PREFIX" : 106,
+ "FACE_NAME" : 200,
+ "FACE_MAKESUB" : 201,
+ "FACE_KILLSUB" : 202,
+ "FACE_SELSUB" : 203,
+ "SCENE_UPDATE" : 303,
+ "IDPROP_COPY" : 501,
+ "IDPROP_KILL" : 502,
+ "CLIGHT_MAKE" : 700,
+ "DFROMACT" : 701
+}
+
+XREF_PREFIX = None
+XREF_MAKE = None
+XREF_EDIT = None
+XREF_SELECT = None
+XREF_POP = None
+FACE_MAKESUB = None
+FACE_SELSUB = None
+FACE_KILLSUB = None
+IDPROP_KILL = None
+IDPROP_COPY = None
+SCENE_UPDATE = None
+CLIGHT_MAKE = None
+DFROMACT = None
+
+def update_state():
+ state = dict()
+ state["activeScene"] = Blender.Scene.getCurrent()
+ state["activeObject"] = state["activeScene"].getActiveObject()
+ if state["activeObject"] and not state["activeObject"].sel:
+ state["activeObject"] = None
+ state["activeMesh"] = None
+ if state["activeObject"] and state["activeObject"].type == 'Mesh':
+ state["activeMesh"] = state["activeObject"].getData(mesh=True)
+
+ state["activeFace"] = None
+ if state["activeMesh"]:
+ if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None:
+ state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace]
+
+ #update editmode
+ state["editmode"] = Blender.Window.EditMode()
+
+ return state
+def pack_face_index(index, intensity):
+ return ((127*intensity)+(128*index))
+def unpack_face_index(face_index):
+ index = face_index / 128
+ intensity = float(face_index - 128.0 * index) / 127.0
+ return(index,intensity)
+
+def idprops_append(object, typecode, props):
+ object.properties["FLT"] = dict()
+ object.properties["FLT"]['type'] = typecode
+ for prop in props:
+ object.properties["FLT"][prop] = props[prop]
+ object.properties["FLT"]['3t8!id'] = object.name
+
+def idprops_kill(object):
+ state = update_state()
+ if object and object.properties.has_key('FLT'):
+ object.properties.pop('FLT')
+
+def idprops_copy(source):
+ state = update_state()
+ if source.properties.has_key('FLT'):
+ for object in state["activeScene"].objects:
+ if object.sel and object != source and (state["activeScene"].Layers & object.Layers):
+ idprops_kill(object)
+ object.properties['FLT'] = dict()
+ for key in source.properties['FLT']:
+ object.properties['FLT'][key] = source.properties['FLT'][key]
+
+def update_all():
+ state = update_state()
+ #update the baked FLT colors for all meshes.
+ for object in state["activeScene"].objects:
+ if object.type == "Mesh":
+ mesh = object.getData(mesh=True)
+ if 'FLT_COL' in mesh.faces.properties:
+ mesh.activeColorLayer = "FLT_Fcol"
+ for face in mesh.faces:
+ (index,intensity) = unpack_face_index(face.getProperty('FLT_COL'))
+ color = struct.unpack('>BBBB',struct.pack('>I',state["colors"][index]))
+ #update the vertex colors for this face
+ for col in face.col:
+ col.r = int(color[0] * intensity)
+ col.g = int(color[1] * intensity)
+ col.b = int(color[2] * intensity)
+ col.a = 255
+
+
+#Change this to find the deep parent
+def xref_create():
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+
+ state = update_state()
+
+ def findchildren(object):
+ children = list()
+ for candidate in state["activeScene"].objects:
+ if candidate.parent == object:
+ children.append(candidate)
+ retlist = list(children)
+ for child in children:
+ retlist = retlist + findchildren(child)
+ return retlist
+
+ actObject = state["activeObject"]
+ if actObject and xrefprefix:
+ scenenames = list()
+ for scene in Blender.Scene.Get():
+ scenenames.append(scene.name)
+
+ if xrefprefix in scenenames:
+ #build a unique name for the xref...
+ suffix = 1
+ found = False
+ while not found:
+ candidate = xrefprefix + str(suffix)
+ if not candidate in scenenames:
+ xrefname = candidate
+ found = True
+ suffix+=1
+ else:
+ xrefname = xrefprefix
+ #create our XRef node
+ xnode = state["activeScene"].objects.new('Empty')
+ xnode.name = 'X:' + xrefname
+ xnode.properties['FLT'] = dict()
+ for prop in FLTXRef:
+ xnode.properties['FLT'][prop] = FLTXRef[prop]
+ xnode.properties['FLT']['3t200!filename'] = xrefname + '.flt'
+ xnode.properties['FLT']['type'] = 63
+ xnode.enableDupGroup = True
+ xnode.DupGroup = Blender.Group.New(xrefname) #this is dangerous... be careful!
+
+ #copy rot and loc of actObject
+ xnode.setLocation(actObject.getLocation())
+ xnode.setEuler(actObject.getEuler())
+
+ #build the new scene
+ xrefscene = Blender.Scene.New(xrefname)
+ xrefscene.properties['FLT'] = dict()
+ xrefscene.properties['FLT']['Filename'] = xrefname
+ xrefscene.properties['FLT']['Main'] = 0
+
+ #find the children of actObject so that we can add them to the group
+ linkobjects = findchildren(actObject)
+ linkobjects.append(actObject)
+ for object in linkobjects:
+ xrefscene.objects.link(object)
+ state["activeScene"].objects.unlink(object)
+ xnode.DupGroup.objects.link(object)
+ #clear rotation of actObject and location
+ actObject.setLocation(0.0,0.0,0.0)
+ actObject.setEuler(0.0,0.0,0.0)
+
+ xrefscene.update(1)
+ state["activeScene"].update(1)
+
+def xref_select():
+ state = update_state()
+ candidates = list()
+ scenelist = [scene.name for scene in Blender.Scene.Get()]
+ for object in state["activeScene"].objects:
+ if object.type == 'Empty' and object.enableDupGroup == True and object.DupGroup:
+ candidates.append(object)
+
+ for object in candidates:
+ if object.DupGroup.name in scenelist:
+ object.sel = 1
+
+def xref_edit():
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+
+ state = update_state()
+
+ actObject = state["activeObject"]
+
+ if actObject and actObject.type == 'Empty' and actObject.DupGroup:
+# if actObject.properties.has_key('FLT') and actObject.properties['FLT']['type'] == 63:
+ for FLTscene in Blender.Scene.Get():
+ if FLTscene.properties.has_key('FLT') and FLTscene.name == actObject.DupGroup.name:
+ actObject.sel = 0
+ xrefstack.append(state["activeScene"])
+ vofsstack.append(Blender.Window.GetViewOffset())
+ vquatstack.append(Blender.Window.GetViewQuat())
+ FLTscene.makeCurrent()
+ Blender.Window.SetViewOffset(0.0,0.0,0.0)
+
+def xref_finish():
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+
+ state = update_state()
+ if xrefstack:
+ scene = xrefstack.pop()
+ Blender.Window.SetViewQuat(vquatstack.pop())
+ Blender.Window.SetViewOffset(vofsstack.pop())
+ scene.makeCurrent()
+
+
+def sortSub(a,b):
+ aindex = a.getProperty("FLT_ORIGINDEX")
+ bindex = b.getProperty("FLT_ORIGINDEX")
+
+ if aindex > bindex:
+ return 1
+ elif aindex < bindex:
+ return -1
+ return 0
+
+def subface_make():
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+
+ editmode = 0
+ if Blender.Window.EditMode():
+ Blender.Window.EditMode(0)
+ editmode = 1
+
+ state = update_state()
+
+ actmesh = state["activeMesh"]
+ activeFace = state["activeFace"]
+ if actmesh:
+ if not "FLT_ORIGINDEX" in actmesh.faces.properties:
+ actmesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"])
+ for i, face in enumerate(actmesh.faces):
+ face.setProperty("FLT_ORIGINDEX",i)
+ if not "FLT_SFLEVEL" in actmesh.faces.properties:
+ actmesh.faces.addPropertyLayer("FLT_SFLEVEL",Blender.Mesh.PropertyTypes["INT"])
+
+ #attach the subfaces to the active face. Note, this doesnt really work 100 percent properly yet, just enough for one level!
+ if activeFace:
+ #steps:
+ #remove actface and selected faces from the facelist
+ #quicksort facelist
+ #append actface and subfaces to end of facelist.
+ #generate new indices
+ facelist = list()
+ sublist = list()
+ for face in actmesh.faces:
+ facelist.append(face)
+ for face in facelist:
+ if face == activeFace:
+ face.setProperty("FLT_SFLEVEL",0)
+ sublist.insert(0,face)
+ elif face.sel:
+ face.setProperty("FLT_SFLEVEL",1)
+ sublist.append(face)
+ for face in sublist:
+ facelist.remove(face)
+ facelist.sort(sortSub)
+ for face in sublist:
+ facelist.append(face)
+ for i, face in enumerate(facelist):
+ face.setProperty("FLT_ORIGINDEX",i)
+ else:
+ pass
+
+ if editmode:
+ Blender.Window.EditMode(1)
+
+def subface_kill():
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+
+ editmode = 0
+ if Blender.Window.EditMode():
+ Blender.Window.EditMode(0)
+ editmode = 1
+ state = update_state()
+
+ actmesh = state["activeMesh"]
+ if actmesh:
+ if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties:
+ for i,face in enumerate(actmesh.faces):
+ face.setProperty("FLT_ORIGINDEX",i)
+ face.setProperty("FLT_SFLEVEL",0)
+ if editmode:
+ Blender.Window.EditMode(1)
+
+def subface_select():
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+
+ editmode = 0
+ if Blender.Window.EditMode():
+ Blender.Window.EditMode(0)
+ editmode = 1
+ state = update_state()
+
+ actmesh = state["activeMesh"]
+ activeFace = state["activeFace"]
+ if actmesh and activeFace:
+ if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties:
+ facelist = list()
+ actIndex = None
+ sublevel = None
+ for face in actmesh.faces:
+ facelist.append(face)
+ facelist.sort(sortSub)
+ for i, face in enumerate(facelist):
+ if face == activeFace:
+ actIndex = i
+ sublevel = face.getProperty("FLT_SFLEVEL")+1
+ break
+ leftover = facelist[actIndex+1:]
+ for face in leftover:
+ if face.getProperty("FLT_SFLEVEL") == sublevel:
+ face.sel = 1
+ else:
+ break
+ if editmode:
+ Blender.Window.EditMode(1)
+
+def select_by_typecode(typecode):
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+
+ state = update_state()
+
+ for object in state["activeScene"].objects:
+ if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers:
+ object.select(1)
+def clight_make():
+ state = update_state()
+ actmesh = state["activeMesh"]
+ actobj = state["activeObject"]
+
+ if actobj and actmesh:
+ actobj.properties['FLT'] = dict()
+ actobj.properties['FLT']['type'] = 111
+ for prop in FLTInlineLP:
+ actobj.properties['FLT'][prop] = FLTInlineLP[prop]
+
+ actmesh.verts.addPropertyLayer("FLT_VCOL", Blender.Mesh.PropertyTypes["INT"])
+ for v in actmesh.verts:
+ v.setProperty("FLT_VCOL", 83815)
+
+def dfromact():
+ state = update_state()
+ actobj = state["activeObject"]
+ actscene = state["activeScene"]
+ dof = None
+
+ for object in actscene.objects.context:
+ if object.sel and (object != actobj):
+ if not dof:
+ dof = object
+ else:
+ return
+
+ if 'FLT' not in dof.properties:
+ dof.properties['FLT'] = dict()
+
+ #Warning! assumes 1 BU == 10 meters.
+ #do origin
+ dof.properties['FLT']['5d!ORIGX'] = actobj.getLocation('worldspace')[0]*10.0
+ dof.properties['FLT']['6d!ORIGY'] = actobj.getLocation('worldspace')[1]*10.0
+ dof.properties['FLT']['7d!ORIGZ'] = actobj.getLocation('worldspace')[2]*10.0
+ #do X axis
+ x = Blender.Mathutils.Vector(1.0,0.0,0.0)
+ x = x * actobj.getMatrix('worldspace')
+ x = x * 10.0
+ dof.properties['FLT']['8d!XAXIS-X'] = x[0]
+ dof.properties['FLT']['9d!XAXIS-Y'] = x[1]
+ dof.properties['FLT']['10d!XAXIS-Z'] = x[2]
+ #do X/Y plane
+ x = Blender.Mathutils.Vector(1.0,1.0,0.0)
+ x.normalize()
+ x = x * actobj.getMatrix('worldspace')
+ x = x * 10.0
+ dof.properties['FLT']['11d!XYPLANE-X'] = x[0]
+ dof.properties['FLT']['12d!XYPLANE-Y'] = x[1]
+ dof.properties['FLT']['13d!XZPLANE-Z'] = x[2]
+
+
+
+
+
+def event(evt,val):
+ if evt == Draw.ESCKEY:
+ Draw.Exit()
+
+def but_event(evt):
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+ global evcode
+
+ state = update_state()
+
+ #do Xref buttons
+ if evt == evcode["XREF_PREFIX"]:
+ xrefprefix = XREF_PREFIX.val
+ if evt == evcode["XREF_EDIT"]:
+ xref_edit()
+ if evt == evcode["XREF_SELECT"]:
+ xref_select()
+ if evt == evcode["XREF_MAKE"]:
+ xref_create()
+ #do scene buttons
+ if evt == evcode["SCENE_UPDATE"]:
+ update_all()
+ #do face buttons
+ if evt == evcode["FACE_MAKESUB"]:
+ subface_make()
+ if evt== evcode["FACE_KILLSUB"]:
+ subface_kill()
+ if evt== evcode["FACE_SELSUB"]:
+ subface_select()
+ #common buttons
+ if evt == evcode["IDPROP_KILL"]:
+ if state["activeObject"]:
+ idprops_kill(state["activeObject"])
+ if evt == evcode["IDPROP_COPY"]:
+ if state["activeObject"]:
+ idprops_copy(state["activeObject"])
+ if evt == evcode["XREF_POP"]:
+ xref_finish()
+ if evt == evcode["CLIGHT_MAKE"]:
+ clight_make()
+ if evt == evcode["DFROMACT"]:
+ dfromact()
+ Draw.Redraw(1)
+ Blender.Window.RedrawAll()
+
+
+def box(x,y,w,h,c,mode):
+ glColor3f(c[0],c[1],c[2])
+ if mode == "outline":
+ glBegin(GL_LINE_LOOP)
+ else:
+ glBegin(GL_POLYGON)
+ glVertex2i(x,y)
+ glVertex2i(x+w,y)
+ glVertex2i(x+w,y+h)
+ glVertex2i(x,y+h)
+ glEnd()
+
+def draw_postcommon(x,y,finaly):
+ global sheetlabel
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+ global evcode
+
+ state = update_state()
+
+ width = prop_w
+ height = prop_h
+
+ #draw the header
+ glColor3f(0.15,0.15,0.15)
+ glBegin(GL_POLYGON)
+ glVertex2i(x-1,y)
+ glVertex2i(x+width+1,y)
+ glVertex2i(x+width+1,y-25)
+ glVertex2i(x-1,y-25)
+ glEnd()
+ glColor3f(1,1,1)
+ glRasterPos2i(x,y-20)
+ sheetlabel = Blender.Draw.Text("FLT Tools Panel")
+ #draw the box outline
+ glColor3f(0,0,0)
+ glBegin(GL_LINE_LOOP)
+ glVertex2i(x-1,y)
+ glVertex2i(x+1+width,y)
+ glVertex2i(x+1+width,finaly-1)
+ glVertex2i(x-1,finaly-1)
+ glEnd()
+ return finaly
+
+
+def draw_propsheet(x,y):
+ global XREF_PREFIX
+ global XREF_MAKE
+ global XREF_EDIT
+ global XREF_SELECT
+ global XREF_POP
+ global FACE_MAKESUB
+ global FACE_SELSUB
+ global FACE_KILLSUB
+ global IDPROP_KILL
+ global IDPROP_COPY
+ global SCENE_UPDATE
+ global CLIGHT_MAKE
+ global xrefprefix
+ global xrefstack
+ global vofsstack
+ global vquatstack
+ global prop_w
+ global prop_h
+ global evcode
+
+ state = update_state()
+
+ width = prop_w
+ height = prop_h
+ origx = x
+ origy = y
+
+ #draw Xref tools
+ y = y-20
+ XREF_PREFIX = Blender.Draw.String("XRef Name:",evcode["XREF_PREFIX"],x,y,width,20,xrefprefix,18,"Xref prefix name, Actual name is generated from this")
+ y = y-20
+ XREF_MAKE = Blender.Draw.PushButton("Make XRef",evcode["XREF_MAKE"],x,y,width,20,"Make External Reference")
+ y = y-20
+ XREF_EDIT = Blender.Draw.PushButton("Edit XRef",evcode["XREF_EDIT"],x,y,width,20,"Edit External Reference")
+ y = y-20
+ XREF_SELECT = Blender.Draw.PushButton("Select XRefs",evcode["XREF_SELECT"],x,y,width,20,"Select External References")
+ y = y - 20
+ XREF_POP = Blender.Draw.PushButton("Return to previous scene",evcode["XREF_POP"],x,y,width,20,"Go up one level in xref hierarchy")
+
+ #Draw facetools
+ y = y-20
+ FACE_MAKESUB = Blender.Draw.PushButton("Make Subfaces",evcode["FACE_MAKESUB"],x,y,width,20,"Make subfaces")
+ y = y-20
+ FACE_SELSUB = Blender.Draw.PushButton("Select Subfaces",evcode["FACE_SELSUB"],x,y,width,20,"Select subfaces")
+ y = y-20
+ FACE_KILLSUB = Blender.Draw.PushButton("Kill Subfaces",evcode["FACE_KILLSUB"],x,y,width,20,"Kill subfaces")
+
+ #Draw ID Property tools
+ y = y - 20
+ IDPROP_KILL = Blender.Draw.PushButton("Delete ID props",evcode["IDPROP_KILL"],x,y,width,20,"Delete ID props")
+ y = y - 20
+ IDPROP_COPY = Blender.Draw.PushButton("Copy to selected",evcode["IDPROP_COPY"],x,y,width,20, "Copy from active to all selected")
+
+ y= y - 20
+ CLIGHT_MAKE = Blender.Draw.PushButton("Make Light Point", evcode["CLIGHT_MAKE"],x,y,width,20,"Create inline light points from current mesh")
+ #General tools
+ y = y-20
+ SCENE_UPDATE = Blender.Draw.PushButton("Update All",evcode["SCENE_UPDATE"],x,y,width,20,"Update all vertex colors")
+
+ y=y-20
+ DFROMACT = Blender.Draw.PushButton("Dof from Active", evcode["DFROMACT"],x,y,width,20,"Get Dof origin from active object")
+ draw_postcommon(origx, origy,y)
+
+def gui():
+ #draw the propsheet/toolbox.
+ psheety = 280
+ #psheetx = psheety + 10
+ draw_propsheet(0,psheety)
+Draw.Register(gui,event,but_event)
+ \ No newline at end of file
diff --git a/release/scripts/image_auto_layout.py b/release/scripts/image_auto_layout.py
index a4a9e82955f..19ee396c3b1 100644
--- a/release/scripts/image_auto_layout.py
+++ b/release/scripts/image_auto_layout.py
@@ -42,7 +42,6 @@ This is usefull for game models where 1 image is faster then many, and saves the
# Function to find all the images we use
import Blender as B
-import boxpack2d
from Blender.Mathutils import Vector, RotationMatrix
from Blender.Scene import Render
import BPyMathutils
@@ -162,9 +161,10 @@ class faceGroup(object):
self.ymin= ymin - (PREF_IMAGE_MARGIN/size[1])
self.box_pack=[\
- image.name,\
+ 0.0, 0.0,\
size[0]*(self.xmax - self.xmin),\
- size[1]*(self.ymax - self.ymin)]
+ size[1]*(self.ymax - self.ymin),\
+ image.name]
'''
# default.
@@ -194,8 +194,8 @@ class faceGroup(object):
# X Is flipped :/
#offset_x= (1-(self.box_pack[1]/d)) - (((self.xmax-self.xmin) * self.image.size[0])/d)
- offset_x= self.box_pack[1]/width
- offset_y= self.box_pack[2]/height
+ offset_x= self.box_pack[0]/width
+ offset_y= self.box_pack[1]/height
for f in self.faces:
for uv in f.uv:
@@ -204,7 +204,11 @@ class faceGroup(object):
uv.y= offset_y+ (((uv_rot.y-self.ymin) * self.size[1])/height)
def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN): #, PREF_SIZE_FROM_UV=True):
- '''Main packing function'''
+ '''
+ Main packing function
+
+ All meshes from mesh_list must have faceUV else this function will fail.
+ '''
face_groups= {}
for me in mesh_list:
@@ -224,11 +228,11 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR
face_groups[image.name]= faceGroup(mesh_list, image, size, PREF_IMAGE_MARGIN)
if not face_groups:
- B.Draw.PupMenu('No Images found in mesh. aborting.')
+ B.Draw.PupMenu('No Images found in mesh(es). Aborting!')
return
if len(face_groups)<2:
- B.Draw.PupMenu('Only 1 image found|Select a mesh using 2 or more images.')
+ B.Draw.PupMenu('Only 1 image found|Select a mesh(es) using 2 or more images.')
return
'''
@@ -286,7 +290,7 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR
render_cam_ob= B.Object.New('Camera')
render_cam_ob.link(render_cam_data)
render_scn.link(render_cam_ob)
- render_scn.setCurrentCamera(render_cam_ob)
+ render_scn.objects.camera = render_cam_ob
render_cam_data.type= 'ortho'
render_cam_data.scale= 1.0
@@ -299,8 +303,7 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR
# List to send to to boxpack function.
boxes2Pack= [ fg.box_pack for fg in face_groups.itervalues()]
-
- packWidth, packHeight, packedLs = boxpack2d.boxPackIter(boxes2Pack)
+ packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack)
if PREF_KEEP_ASPECT:
packWidth= packHeight= max(packWidth, packHeight)
@@ -308,17 +311,17 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR
# packedLs is a list of [(anyUniqueID, left, bottom, width, height)...]
# Re assign the face groups boxes to the face_group.
- for box in packedLs:
- face_groups[ box[0] ].box_pack= box # box[0] is the ID (image name)
+ for box in boxes2Pack:
+ face_groups[ box[4] ].box_pack= box # box[4] is the ID (image name)
# Add geometry to the mesh
for fg in face_groups.itervalues():
# Add verts clockwise from the bottom left.
- _x= fg.box_pack[1] / packWidth
- _y= fg.box_pack[2] / packHeight
- _w= fg.box_pack[3] / packWidth
- _h= fg.box_pack[4] / packHeight
+ _x= fg.box_pack[0] / packWidth
+ _y= fg.box_pack[1] / packHeight
+ _w= fg.box_pack[2] / packWidth
+ _h= fg.box_pack[3] / packHeight
render_me.verts.extend([\
Vector(_x, _y, 0),\
@@ -374,10 +377,11 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR
for fg in face_groups.itervalues():
fg.move2packed(packWidth, packHeight)
-
+
scn.makeCurrent()
- B.Scene.Unlink(render_scn)
render_me.verts= None # free a tiny amount of memory.
+ B.Scene.Unlink(render_scn)
+ target_image.makeCurrent()
def main():
@@ -422,10 +426,23 @@ def main():
if PREF_ALL_SEL_OBS:
mesh_list= [ob.getData(mesh=1) for ob in scn_objects.context if ob.type=='Mesh']
# Make sure we have no doubles- dict by name, then get the values back.
- mesh_list= dict([(me.name, me) for me in mesh_list]).values()
+
+ for me in mesh_list: me.tag = False
+
+ mesh_list_new = []
+ for me in mesh_list:
+ if me.faceUV and me.tag==False:
+ me.tag = True
+ mesh_list_new.append(me)
+
+ # replace list with possible doubles
+ mesh_list = mesh_list_new
else:
mesh_list= [ob.getData(mesh=1)]
+ if not mesh_list[0].faceUV:
+ B.Draw.PupMenu('Error, active mesh has no images, Aborting!')
+ return
consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN)
B.Window.RedrawAll()
diff --git a/release/scripts/image_billboard.py b/release/scripts/image_billboard.py
index 2ca1d9d46e4..54f0f7c5c55 100644
--- a/release/scripts/image_billboard.py
+++ b/release/scripts/image_billboard.py
@@ -46,47 +46,37 @@ Usage
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
-import Blender as B
+import Blender
+from Blender import Mesh, Material, Draw
import BPyMathutils
-# reload(BPyMathutils)
+import bpy
import BPyRender
-reload(BPyRender)
-import boxpack2d
-# reload(boxpack2d) # for developing.
from Blender.Scene import Render
+# reload(BPyRender)
+# reload(BPyMathutils)
+
import os
-Vector= B.Mathutils.Vector
+Vector= Blender.Mathutils.Vector
def alpha_mat(image):
# returns a material useable for
- mtl= B.Material.New()
- mtl.mode |= (B.Material.Modes.SHADELESS | B.Material.Modes.ZTRANSP | B.Material.Modes.FULLOSA )
- mtl.alpha= 0.0 # so image sets the alpha
-
- tex= B.Texture.New()
- tex.type= B.Texture.Types.IMAGE
- image.antialias = True
- tex.setImageFlags('InterPol', 'UseAlpha')
- tex.setExtend('Clip')
- tex.image= image
-
- mtl.setTexture(0, tex, B.Texture.TexCo.UV, B.Texture.MapTo.COL | B.Texture.MapTo.ALPHA)
-
+ mtl= bpy.data.materials.new()
+ mtl.mode |= (Material.Modes.SHADELESS | Material.Modes.ZTRANSP | Material.Modes.FULLOSA | Material.Modes.TEXFACE | Material.Modes.TEXFACE_ALPHA )
return mtl
# PupBlock Settings
GLOBALS= {}
-PREF_RES= B.Draw.Create(512)
-PREF_TILE_RES= B.Draw.Create(256)
-PREF_AA = B.Draw.Create(1)
-PREF_ALPHA= B.Draw.Create(1)
-PREF_Z_OFFSET = B.Draw.Create(10.0)
-PREF_IMG_PACK= B.Draw.Create(1)
+PREF_RES= Draw.Create(512)
+PREF_TILE_RES= Draw.Create(256)
+PREF_AA = Draw.Create(1)
+PREF_ALPHA= Draw.Create(1)
+PREF_Z_OFFSET = Draw.Create(10.0)
+PREF_IMG_PACK= Draw.Create(1)
def save_billboard(PREF_IMAGE_PATH):
- B.Window.WaitCursor(1)
+ Blender.Window.WaitCursor(1)
# remove png, add it later
PREF_IMAGE_PATH= PREF_IMAGE_PATH.replace('.png', '')
@@ -94,7 +84,7 @@ def save_billboard(PREF_IMAGE_PATH):
me_ob = GLOBALS['me_ob']
me_data = GLOBALS['me_data']
- time= B.sys.time()
+ time= Blender.sys.time()
me_mat= me_ob.matrixWorld
@@ -102,9 +92,10 @@ def save_billboard(PREF_IMAGE_PATH):
face_data= [] # Store faces, images etc
boxes2Pack= []
me_data.faceUV= True
-
+
for i, f in enumerate(me_data.faces):
no= f.no
+
# Offset the plane by the zoffset on the faces normal
plane= [v.co * me_mat for v in f]
@@ -117,61 +108,64 @@ def save_billboard(PREF_IMAGE_PATH):
else:
rot90= False
-
- #plane.reverse()
- no= B.Mathutils.QuadNormal(*plane)
+ no= Blender.Mathutils.QuadNormal(*plane)
plane= [v + no*PREF_Z_OFFSET.val for v in plane]
cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0
camera_matrix= BPyMathutils.plane2mat(plane)
tmp_path= '%s_%d' % (PREF_IMAGE_PATH, i)
img= BPyRender.imageFromObjectsOrtho(ob_sel, tmp_path, PREF_TILE_RES.val, PREF_TILE_RES.val, PREF_AA.val, PREF_ALPHA.val, camera_matrix)
- # img.reload()
+ img.reload()
#img.pack() # se we can keep overwriting the path
#img.filename= ""
+ if rot90:
+ f.uv=Vector(1,1), Vector(0,1), Vector(0,0), Vector(1,0)
+ else:
+ f.uv= Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1)
if not PREF_IMG_PACK.val:
- f.mode |= B.Mesh.FaceModes.TEX
+ f.mode |= Mesh.FaceModes.TEX
f.image = img
- f.uv=Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1)
if PREF_ALPHA.val:
- f.transp |= B.Mesh.FaceTranspModes.ALPHA
+ f.transp |= Mesh.FaceTranspModes.ALPHA
else:
w= ((plane[0]-plane[1]).length + (plane[2]-plane[3]).length)/2
h= ((plane[1]-plane[2]).length + (plane[3]-plane[0]).length)/2
- face_data.append( (f, img, rot90) )
- boxes2Pack.append( (i, h, w) )
+ face_data.append( (f, img) )
+ boxes2Pack.append( [0.0,0.0,h, w, i] )
if PREF_IMG_PACK.val:
# pack the quads into a square
+ packWidth, packHeight = Blender.Geometry.BoxPack2D(boxes2Pack)
- packWidth, packHeight, packedLs = boxpack2d.boxPackIter(boxes2Pack)
render_obs= []
+ render_mat= alpha_mat(img)
+
# Add geometry to the mesh
- for box in packedLs:
- i= box[0]
+ for box in boxes2Pack:
+ i= box[4]
- orig_f, img, rot90= face_data[i]
+ orig_f, img= face_data[i]
# New Mesh and Object
- render_mat= alpha_mat(img)
- render_me= B.Mesh.New()
- render_ob= B.Object.New('Mesh')
+ render_me= bpy.data.meshes.new()
+
+ render_ob= Blender.Object.New('Mesh')
render_me.materials= [render_mat]
render_ob.link(render_me)
render_obs.append(render_ob)
# Add verts clockwise from the bottom left.
- _x= box[1] / packWidth
- _y= box[2] / packHeight
- _w= box[3] / packWidth
- _h= box[4] / packHeight
+ _x= box[0] / packWidth
+ _y= box[1] / packHeight
+ _w= box[2] / packWidth
+ _h= box[3] / packHeight
render_me.verts.extend([\
@@ -180,65 +174,56 @@ def save_billboard(PREF_IMAGE_PATH):
Vector(_x + _w, _y +_h, 0),\
Vector(_x + _w, _y, 0),\
])
-
+
render_me.faces.extend(list(render_me.verts))
render_me.faceUV= True
- # target_face= render_me.faces[-1]
- # TEXFACE isnt used because of the renderign engine cant to alpha's for texdface.
- #target_face.image= img
- #target_face.mode |= B.Mesh.FaceModes.TEX
+ render_me.faces[0].uv = [Vector(0,0), Vector(0,1), Vector(1,1), Vector(1,0)]
+ render_me.faces[0].image = img
# Set the UV's, we need to flip them HOZ?
- uv1, uv2, uv3, uv4= orig_f.uv
- uv3.x= uv4.x= _x+_w
- uv1.x= uv2.x= _x
-
- uv2.y= uv3.y= _y+_h
- uv1.y= uv4.y= _y
-
- if rot90:
- orig_f.uv= Vector(uv4), Vector(uv1), Vector(uv2), Vector(uv3)
-
+ for uv in orig_f.uv:
+ uv.x = _x + (uv.x * _w)
+ uv.y = _y + (uv.y * _h)
+
target_image= BPyRender.imageFromObjectsOrtho(render_obs, PREF_IMAGE_PATH, PREF_RES.val, PREF_RES.val, PREF_AA.val, PREF_ALPHA.val, None)
+ target_image.reload() # incase your overwriting an existing image.
# Set to the 1 image.
for f in me_data.faces:
f.image= target_image
if PREF_ALPHA.val:
- f.transp |= B.Mesh.FaceTranspModes.ALPHA
+ f.transp |= Mesh.FaceTranspModes.ALPHA
# Free the images data and remove
for data in face_data:
img= data[1]
os.remove(img.filename)
img.reload()
+
# Finish pack
me_data.update()
me_ob.makeDisplayList()
- B.Window.WaitCursor(0)
- print '%.2f secs taken' % (B.sys.time()-time)
-
-
+ Blender.Window.WaitCursor(0)
+ print '%.2f secs taken' % (Blender.sys.time()-time)
def main():
- scn= B.Scene.GetCurrent()
+ scn= bpy.data.scenes.active
ob_sel= list(scn.objects.context)
PREF_KEEP_ASPECT= False
-
# Error Checking
if len(ob_sel) < 2:
- B.Draw.PupMenu("Error%t|Select 2 mesh objects")
+ Draw.PupMenu("Error%t|Select 2 mesh objects")
return
me_ob= scn.objects.active
if not me_ob:
- B.Draw.PupMenu("Error%t|No active mesh selected.")
+ Draw.PupMenu("Error%t|No active mesh selected.")
try:
ob_sel.remove(me_ob)
@@ -246,32 +231,30 @@ def main():
pass
if me_ob.type != 'Mesh':
- B.Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too")
+ Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too")
return
me_data= me_ob.getData(mesh=1)
for f in me_data.faces:
if len(f) != 4:
- B.Draw.PupMenu("Error%t|Active mesh must have only quads")
+ Draw.PupMenu("Error%t|Active mesh must have only quads")
return
-
-
# Get user input
block = [\
'Image Pixel Size',\
("Packed Size: ", PREF_RES, 128, 2048, "Pixel width and height to render the billboard to"),\
("Tile Size: ", PREF_TILE_RES, 64, 1024, "Pixel width and height for each tile to render to"),\
'Render Settings',\
- ("Pack Final", PREF_IMG_PACK , "Pack all images into 1 image"),\
+ ("Pack Final", PREF_IMG_PACK , "Pack the image for each face into images into a single image"),\
("Oversampling", PREF_AA , "Higher quality woth extra sampling"),\
("Alpha Clipping", PREF_ALPHA , "Render empty areas as transparent"),\
("Cam ZOffset: ", PREF_Z_OFFSET, 0.1, 100, "Distance to place the camera away from the quad when rendering")\
]
- if not B.Draw.PupBlock("Billboard Render", block):
+ if not Draw.PupBlock("Billboard Render", block):
return
# Set globals
@@ -279,7 +262,8 @@ def main():
GLOBALS['me_ob'] = me_ob
GLOBALS['me_data'] = me_data
- B.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', B.sys.makename(ext='.png'))
+ Blender.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', Blender.sys.makename(ext='.png'))
+ # save_billboard('/tmp/test.png')
if __name__=='__main__':
main()
diff --git a/release/scripts/image_find_paths.py b/release/scripts/image_find_paths.py
deleted file mode 100644
index 266ecee9435..00000000000
--- a/release/scripts/image_find_paths.py
+++ /dev/null
@@ -1,167 +0,0 @@
-#!BPY
-
-"""
-Name: 'Fix Broken Paths'
-Blender: 242
-Group: 'Image'
-Tooltip: 'Search for new image paths to make relative links to'
-"""
-
-__author__ = "Campbell Barton AKA Ideasman"
-__url__ = ["blenderartist.org"]
-
-__bpydoc__ = """\
-Find image target paths
-
-This script searches for images whos
-file paths do not point to an existing image file,
-all image paths are made relative where possible.
-usefull when moving projects between computers, when absolute paths links are broken.
-"""
-
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# Script copyright (C) Campbell J Barton
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# ***** END GPL LICENCE BLOCK *****
-# --------------------------------------------------------------------------
-
-
-from Blender import *
-
-try:
- import os
-except:
- Draw.PupMenu('You need a full python install to use this script')
- os= None
-
-
-#==============================================#
-# Strips the slashes from the back of a string #
-#==============================================#
-def stripPath(path):
- return path.split('/')[-1].split('\\')[-1]
-
-# finds the file starting at the root.
-def findImage(findRoot, imagePath):
- newImageFile = None
-
- imageFile = imagePath.split('/')[-1].split('\\')[-1]
-
- # ROOT, DIRS, FILES
- pathWalk = os.walk(findRoot)
- 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]:
- # FOUND A MATCH
- if file.lower() == imageFile.lower():
- name = pathList[0] + sys.sep + file
- try:
- size = os.path.getsize(name)
- except:
- size = 0
-
- if size:
- print ' found:', name
- matchList.append( (name, size) )
-
- if matchList == []:
- print 'no match for:', imageFile
- return None
- else:
- # Sort by file size
- matchList.sort(lambda A, B: cmp(B[1], A[1]) )
-
- print 'using:', matchList[0][0]
- # First item is the largest
- return matchList[0][0] # 0 - first, 0 - pathname
-
-
-# Makes the pathe relative to the blend file path.
-def makeRelative(path, blendBasePath):
- if path.startswith(blendBasePath):
- path = path.replace(blendBasePath, '//')
- path = path.replace('//\\', '//')
- return path
-
-def find_images(findRoot):
- print findRoot
-
- # findRoot = Draw.PupStrInput ('find in: ', '', 100)
-
- if findRoot == '':
- Draw.PupMenu('No Directory Selected')
- return
-
- # Account for //
- findRoot = sys.expandpath(findRoot)
-
- # Strip filename
- while findRoot[-1] != '/' and findRoot[-1] != '\\':
- findRoot = findRoot[:-1]
-
-
- if not findRoot.endswith(sys.sep):
- findRoot += sys.sep
-
-
- if findRoot != '/' and not sys.exists(findRoot[:-1]):
- Draw.PupMenu('Directory Dosent Exist')
-
- blendBasePath = sys.expandpath('//')
-
-
- Window.WaitCursor(1)
- # ============ DIR DONE\
- images = Image.Get()
- len_images = float(len(images))
- for idx, i in enumerate(images):
-
- progress = idx / len_images
- Window.DrawProgressBar(progress, 'searching for images')
-
- # If files not there?
- if not sys.exists(sys.expandpath(i.filename )):
- newImageFile = findImage(findRoot, i.filename)
- if newImageFile != None:
- newImageFile= makeRelative(newImageFile, blendBasePath)
- print 'newpath relink:', newImageFile
- i.filename = newImageFile
- i.reload()
- else:
- # Exists
- newImageFile= makeRelative(i.filename, blendBasePath)
- if newImageFile!=i.filename:
- print 'newpath relative:', newImageFile
- i.filename = newImageFile
-
-
- Window.RedrawAll()
- Window.DrawProgressBar(1.0, '')
- Window.WaitCursor(0)
-
-if __name__ == '__main__' and os:
- Window.FileSelector(find_images, 'SEARCH ROOT DIR', sys.expandpath('//'))
-
-
diff --git a/release/scripts/import_dxf.py b/release/scripts/import_dxf.py
index a4e4e69b366..4fa7a6472cf 100644
--- a/release/scripts/import_dxf.py
+++ b/release/scripts/import_dxf.py
@@ -1,54 +1,263 @@
#!BPY
-# """
-# Name: 'Drawing eXchange Format (.dxf)'
-# Blender: 243
-# Group: 'Import'
-# Tooltip: 'Import DXF file.'
-# """
-__author__ = 'Kitsu (Ed Blake)'
-__version__ = '0.9 1/2007'
-__url__ = ["elysiun.com", "BlenderArtists.org"]
-__email__ = ["Kitsune_e@yahoo.com"]
+"""
+Name: 'Autodesk DXF (.dxf)'
+Blender: 244
+Group: 'Import'
+Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).'
+"""
+__author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)'
+__version__ = '1.0.12 - 2008.02.08 by migius'
+__url__ = ["http://blenderartists.org/forum/showthread.php?t=84319",
+ "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"]
+__email__ = ["Kitsune_e(at)yahoo.com", "migius(at)4d-vectors.de"]
__bpydoc__ = """\
-This is a Blender import script for dxf files.
-
-This script imports the dxf Geometery from dxf versions 2007 and earlier.
-
-Supported:<br>
- At this time only mesh based imports are supported.<br>
- Future support for all curve import is planned.<br>
- <br>
-Currently Supported DXF Ojects:<br>
- Lines<br>
- LightWeight polylines<br>
- True polylines<br>
- Text<br>
- Mtext<br>
- Circles<br>
- Arcs<br>
- Ellipses<br>
- Blocks<br>
- 3Dfaces<br>
-
-Known issues:<br>
- Does not convert perfectly between Object Coordinate System (OCS)
- and World Coordinate System (WCS). Only rudimentary support for
- true polylines have been implimented - splines/fitted curves/
- 3d plines/polymeshes are not supported.
- No support for most 3d entities. Doesn't support the new style object
- visability. There are problems importing some curves/arcs/circles.
-
-Notes:<br>
- This is primarally a 2d drawing release. Currently only support for
- 3d faces has been added.
- Blocks are created on layer 19 then referenced at each insert point. The
- insert point is designated with a small 3d crosshair. This handle does not render.
+This script imports objects from DXF (2d/3d) into Blender.
+
+This script imports 2d and 3d geometery from DXFr12 format files.
+Enhanced features are:
+- configurable object filtering and geometry manipulation,
+- configurable material pre-processing,
+- DXF-data analyze and raporting.
+
+Supported DXF r12 objects:
+LINE,
+POINT,
+SOLID,
+TRACE,
+TEXT,
+INSERT (=block),
+MINSERT (=array of blocks),
+CIRCLE,
+ARC,
+3DFACE,
+2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline),
+3d-POLYLINE (=non-plane),
+3d-POLYMESH,
+3d-POLYFACE,
+VIEW, VPORT
+XREF (External Reference).
+
+Supported DXF>r12 objects:
+ELLIPSE,
+(wip v1.0.12 partly supported) LWPOLYLINE (LightWeight),
+(wip v1.0.12) MLINE,
+(wip v1.0.12) MTEXT
+
+Unsupported Objects:
+DXF r12: DIMENSION.
+DXF>r12: SPLINE, GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK
+
+Supported Geometry: 2d and 3d DXF-objects.
+Curves imported as curves or meshes optionally.
+
+Supported layout modes:
+"model space" is default,
+"paper space" as option (= "layout views")
+
+Scene definitions produced with AVE_RENDER:
+scene: selection of lights assigned to the camera,
+lights: DIRECT, OVERHEAD, SH_SPOT,
+(wip v1.0.13 import of AVE_RENDER material definitions)
+
+Hierarchy:
+Entire DXF BLOCK hierarchy is preserved after import into Blender
+(BLOCKs as groups on layer19, INSERTs as dupliGroups on target layer).
+
+Supported properties:
+visibility status,
+frozen status,
+thickness,
+width,
+color,
+layer,
+(wip v1.0.12: XDATA, grouped status)
+It is recommended to use DXF-object properties for assign Blender materials.
+
+Notes:
+- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script
+- Blocks are created on layer 19 then referenced at each insert point.
+- Big DXF-files (over 1500 objects) decrease import performance.
+The problem is not the inefficiency of python-scripting but Blenders performance
+in creating new objects in his database - probably a database management problem.
+
+TODO:
+- the new style object visibility
+- support for real 3d-solids (ACIS)
+- (to see more, search for "--todo--" in script code)
+
+"""
+
+"""
+History:
+ v1.0 - 2008.01. by migius
+ planned tasks:
+ -- command-line-mode/batch-mode
+ -- in-place-editing for dupliGroups
+ -- support for MLINE (is exported to r12 as BLOCK*Unnamed with LINEs)
+ -- support for MTEXT (is exported to r12 as TEXT???)
+ -- blender_object.properties['dxf_layer_name']
+ -- better support for long dxf-layer-names
+ -- add configuration file.ini handles multiple material setups
+ -- added f_layerFilter
+ -- to-check: obj/mat/group/_mapping-idea from ideasman42:
+ -- curves: added "fill/non-fill" option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs
+ -- bug:? object = Object.Get(obname) -> = SCENE.getChildren(obname)
+ -- "normalize Z" option to correct non-planar figures
+ -- LINEs need "width" in 3d-space incl vGroups
+ -- support width_force for LINEs/ELLIPSEs = "solidify"
+ -- add better support for color_index BYLAYER=256, BYBLOCK=0
+ -- bug: "oneMesh" produces sometimes errors
+ -- bug: Registry recall from hd_cache ?? only win32 bug??
+
+ v1.0.12: 2008.02.08 by migius
+ -- support DXF-definitions of scene, lights and cameras
+ -- support ortho mode for VIEWs and VPORTs as cameras
+ a9 bugfix by non-existing tables views, vports, layers (Kai reported)
+ v1.0.12: 2008.01.17 by migius
+ a8 lately used INI-dir/filename persistently stored in Registry
+ a8 lately used DXF-dir/filename persistently stored in Registry
+ a7 fix missing layersmap{} for dxf-files without "section:layer"
+ a6 added support for XREF external referenced BLOCKs
+ a6 check for bug in AutoCAD2002:DXFr12export: ELLIPSE->POLYLINE_ARC fault angles
+ a6 support VIEWs and VPORTs as cameras: ortho and perspective mode
+ a6 save resources through ignoring unused BLOCKs (not-inserted or on frozen/blocked layers)
+ a6 added try_finally: f.close() for all IO-files
+ a6 added handling for TypeError raise
+ a5 bugfix f_getOCS for (0,0,z!=1.0) (ellipse in Kai's dxf)
+ a4 added to analyzeTool: report about VIEWs, VPORTs, unused/xref BLOCKs
+ a4 bugfix: individual support for 2D/3DPOLYLINE/POLYMESH
+ a4 added to UI: (*wip)BLOCK-(F): name filtering for BLOCKs
+ a4 added to UI: BLOCK-(n): filter anoname/hatch BLOCKs *X...
+ a2 g_scale_as is no more GUI_A-variable
+ a2 bugfix "material": negative sign color_index
+ a2 added support for BLOCKs defined with origin !=(0,0,0)
+ a1 added 'global.reLocation-vector' option
+
+ v1.0.11: 2007.11.24 by migius
+ c8 added 'curve_resolution_U' option
+ c8 added context_sensitivity for some UI-buttons
+ c8 bugfix ELLIPSE rotation, added closed_variant and caps
+ c7 rebuild UI: new layout, grouping and meta-buttons
+ c6 rewritten support for ELLIPSE mesh & curve representation
+ c6 restore selector-buttons for DXF-drawTypes: LINE & Co
+ c6 change header of INI/INF-files: # at begin
+ c6 apply scale(1,1,1) after glob.Scale for all mesh objects, not for curve objects.
+ c5 fixing 'material_on' option
+ c4 added "analyze DXF-file" UI-option: print LAYER/BLOCK-dependences into a textfile
+ c3 human-formating of data in INI-Files
+ c2 added "caps" for closed Bezier-curves
+ c2 added "set elevation" UI-option
+ c1 rewrite POLYLINE2d-arc-segments Bezier-interpreter
+ b9 many bugs fixed
+ b9 rewrite POLYLINE2d-arc-segments trimming (clean-trim)
+ b8 added "import from frozen layers" UI-option
+ b8 added "import from paper space" UI-option
+ b8 support Bezier curves for LINEs incl.thickness(0.0-10.0)
+ b8 added meshSmooth_on for circle/arc/polyline
+ b8 added vertexGroups for circle/arc
+ b7 added width_force for ARCs/CIRCLEs = "thin_box" option
+ b3 cleanup code, rename f_drawArc/Bulg->f_calcArc/Bulg
+ b2 fixing material assignment by LAYER+COLOR
+ b1 fixing Bezier curves representation of POLYLINEs-arc-segments
+ b0 added global_scale_presets: "yard/feet/inch to meter"
+
+ v1.0.10: 2007.10.18 by migius
+ a6 bugfix CircleDrawCaps for OSX
+ a5 added two "curve_res" UI-buttons for Bezier curves representation
+ a5 improved Bezier curves representation of circles/arcs: correct handlers
+ a4 try to fix malformed endpoints of Blender curves of ARC/POLYLINE-arc segments.
+ a3 bugfix: open-POLYLINEs with end_point.loc==start_point.loc
+ a2 bugfix: f_transform for OCS=(0,0,-1) oriented objects
+ a1 added "fill_on=caps" option to draw top and bottom sides of CIRCLEs and ELLIPSEs
+ a1 rewrite f_CIRCLE.Draw: from Mesh.Primitive to Mesh
+ a1 bugfix "newScene"-mode: all Cylinders/Arcs were drawn at <0,0,0>location
+
+ v1.0.beta09: 2007.09.02 by migius
+ g5 redesign UI: grouping of buttons
+ g3 update multi-import-mode: <*.*> button
+ g- added multi-import-mode: (path/*) for importing many dxf-files at once
+ g- added import into newScene
+ g- redesign UI: user presets, into newScene-import
+ f- cleanup code
+ f- bugfix: thickness for Bezier/Bsplines into Blender-curves
+ f- BlenderWiki documentation, on-line Manual
+ f- added import POLYLINE-Bsplines into Blender-NURBSCurves
+ f- added import POLYLINE-arc-segments into Blender-BezierCurves
+ f- added import POLYLINE-Bezier-curves into Blender-Curves
+ d5 rewrite: Optimization Levels, added 'directDrawing'
+ d4 added: f_set_thick(controlled by ini-parameters)
+ d4 bugfix: face-normals in objects with minus thickness
+ d4 added: placeholder'Empty'-size in f_Insert.draw
+ d3 rewrite f_Text.Draw: added support for all Text's parameters
+ d2 redesign: progressbar
+ e- tuning by ideasman42: better use of the Py API.
+ c- tuning by ideasman42
+ b- rewrite f_Text.Draw rotation/transform
+ b- bugfix: POLYLINE-segment-intersection more reliable now
+ b- bugfix: circle:_thic, 'Empties':no material_assignment
+ b- added material assignment (from layer and/or color)
+ a- added empty, cylinder and UVsphere for POINTs
+ a- added support for 2d-POLYLINE: splines, fitted curves, fitted surfaces
+ a- redesign f_Drawer for block_definitions
+ a- rewrite import into Blender-Curve-Object
+
+ v1.0.beta08 - 2007.07.27 by migius: "full 3d"-release
+ l- bugfix: solid_vgroups, clean:scene.objects.new()
+ l- redesign UI to standard Draw.Register+FileSelector, advanced_config_option
+ k- bugfix UI:fileSelect() for MacOSX os.listdir()
+ k- added reset/save/load for config-data
+ k- redesign keywords/drawTypes/Draw.Create_Buttons
+ j- new UI using UIBlock() with own FileSelector, cause problem Window.FileSelector()
+ i- rewritten Class:Settings for better config-parameter management
+ h- bugfix: face-normals in objects with minus thickness
+ h- added Vertex-Groups in POLYLINE and SOLID meshes, for easy material assignment
+ h- beautify code, whitespace->tabs
+ h- added settings.thic_force switch for forcing thickness
+ h- added "one Mesh" option for all entities from the same Layer, sorted in<br>
+ Vertex-Groups(color_name) (fewer objects = better import performance)
+ g- rewrote: insert-point-handle-object is a small tetrahedron
+ e- bugfix: closed-polymesh3d
+ - rewrote: UI, type_map.keys, f_drawer, all class_f_draw(added "settings" as attribut)
+ - added 2d/3d-support for Polyline_Width incl. angle intersection
+ beta07: 2007.06.19 by migius
+ - added 3d-support for LWPolylines
+ - added 2d/3d-support for Points
+ beta06: 2007.06.15 by migius
+ - cleanup code
+ - added 2d/3d-support for MINSERT=BlockArray in f_drawer, added f_rotXY_Vec
+ beta05: 2007.06.14 by migius
+ - added 2d/3d-support for 3d-PolyLine, PolyMesh and PolyFace
+ - added Global-Scale for size control of imported scenes
+ beta04: 2007.06.12 by migius
+ - rewrote the f_drawBulge for correct import the arc-segments of Polylines
+ beta03: 2007.06.10 by migius
+ - rewrote interface
+ beta02: 2007.06.09 by migius
+ - added 3d-support for Arcs and Circles
+ - added support for Object_Thickness(=height)
+ beta01: 2007.06.08 by migius
+ - added 3d-support for Blocks/Inserts within nested-structures
+ - rewrote f_transform for correct 3d-location/3d-rotation
+ - added 3d-support Lines, 3dFaces
+ - added 2d+3d-support for Solids and Traces
+
+ v0.9 - 2007.01 by kitsu: (for 2.43)
+ - first draft of true POLYLINE import
+ -
+
+ v0.8 - 2006.12 by kitsu:
+ - first draft of object space coordinates OCS import
+ -
+
+ v0.5b - 2006.10 by kitsu: (for 2.42a)
+ - dxfReader.py
+ - color_map.py
"""
# --------------------------------------------------------------------------
-# DXF Import v0.9 by Ed Blake (AKA Kitsu)
+# DXF Import v1.0 by Ed Blake (AKA kitsu) and Remigiusz Fiedler (AKA migius)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -70,2195 +279,5667 @@ Notes:<br>
# --------------------------------------------------------------------------
import Blender
+#import bpy
from Blender import *
-Sys = sys
+#from Blender.Mathutils import Vector, Matrix
+#import BPyMessages
-from dxfReader import readDXF, get_name, get_layer
+from dxfReader import readDXF
+#from dxfReader import get_name, get_layer
from dxfReader import Object as dxfObject
from dxfColorMap import color_map
+
from math import *
try:
- import os
- if os.name:# != 'mac':
- import psyco
- psyco.log()
- psyco.full(memory=100)
- psyco.profile(0.05, memory=100)
- psyco.profile(0.2)
+ import os
+ if os.name:# != 'mac':
+ import psyco
+ psyco.log(Blender.Get('tempdir')+"/blender.log-psyco")
+ #psyco.log()
+ psyco.full(memory=100)
+ psyco.profile(0.05, memory=100)
+ psyco.profile(0.2)
+ #print 'psyco imported'
except ImportError:
- pass
+ #print 'psyco not imported'
+ pass
+
+print '\n\n\n\n'
+print 'DXF-Importer *** start ***' #---------------------
-SCENE = Scene.GetCurrent()
+SCENE = None
WORLDX = Mathutils.Vector((1,0,0))
+WORLDY = Mathutils.Vector((1,1,0))
+WORLDZ = Mathutils.Vector((0,0,1))
+
+G_SCALE = 1.0 #(0.0001-1000) global scaling factor for all dxf data
+G_ORIGIN_X = 0.0 #global translation-vector (x,y,z) in DXF units
+G_ORIGIN_Y = 0.0
+G_ORIGIN_Z = 0.0
+MIN_DIST = 0.001 #cut-off value for sort out short-distance polyline-"duoble_vertex"
+ARC_RESOLUTION = 64 #(4-500) arc/circle resolution - number of segments
+ARC_RADIUS = 1.0 #(0.01-100) arc/circle radius for number of segments algorithm
+CURV_RESOLUTION = 12 #(1-128) Bezier curves U-resolution
+CURVARC_RESOLUTION = 4 #(3-32) resolution of circle represented as Bezier curve
+THIN_RESOLUTION = 8 #(4-64) thin_cylinder arc_resolution - number of segments
+MIN_THICK = MIN_DIST * 10.0 #minimal thickness by forced thickness
+MIN_WIDTH = MIN_DIST * 10.0 #minimal width by forced width
+TRIM_LIMIT = 3.0 #limit for triming of polylines-wide-segments (values:0.0 - 5.0)
+ELEVATION = 0.0 #standard elevation = coordinate Z
+
+TARGET_LAYER = 3 #target blender_layer
+GROUP_BYLAYER = 0 #(0/1) all entities from same layer import into one blender-group
+
+FILENAME_MAX = 180 #max length of path+file_name string (FILE_MAXDIR + FILE_MAXFILE)
+MAX_NAMELENGTH = 17 #max_effective_obnamelength in blender =21=17+(.001)
+INIFILE_DEFAULT_NAME = 'importDXF'
+INIFILE_EXTENSION = '.ini'
+INIFILE_HEADER = '#ImportDXF.py ver.1.0 config data'
+INFFILE_HEADER = '#ImportDXF.py ver.1.0 analyze of DXF-data'
+
AUTO = BezTriple.HandleTypes.AUTO
-BYLAYER=256
+FREE = BezTriple.HandleTypes.FREE
+VECT = BezTriple.HandleTypes.VECT
+ALIGN = BezTriple.HandleTypes.ALIGN
+cur_COUNTER = 0 #counter for progress_bar
+
+
"""This module provides wrapper objects for dxf entities.
-
- The wrappers expect a "dxf object" as input. The dxf object is
- an object with a type and a data attribute. Type is a lowercase
- string matching the 0 code of a dxf entity. Data is a list containing
- dxf objects or lists of [code, data] pairs.
-
- This module is not general, and is only for dxf import.
+
+ The wrappers expect a "dxf object" as input. The dxf object is
+ an object with a type and a data attribute. Type is a lowercase
+ string matching the 0 code of a dxf entity. Data is a list containing
+ dxf objects or lists of [code, data] pairs.
+
+ This module is not general, and is only for dxf import.
"""
# from Stani's dxf writer v1.1 (c)www.stani.be (GPL)
#---color values
-BYBLOCK=0
-BYLAYER=256
+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
+#---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)
+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)
+
+#---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
#---mtext flags
#attachment point
-TOP_LEFT = 1
-TOP_CENTER = 2
-TOP_RIGHT = 3
-MIDDLE_LEFT = 4
+TOP_LEFT = 1
+TOP_CENTER = 2
+TOP_RIGHT = 3
+MIDDLE_LEFT = 4
MIDDLE_CENTER = 5
-MIDDLE_RIGHT = 6
-BOTTOM_LEFT = 7
+MIDDLE_RIGHT = 6
+BOTTOM_LEFT = 7
BOTTOM_CENTER = 8
-BOTTOM_RIGHT = 9
+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
+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
-class Layer:
- """Class for objects representing dxf layers."""
-
- def __init__(self, obj, name=None, color=None, frozen=None):
- """Expects an entity object of type line as input."""
- self.type = obj.type
- self.data = obj.data[:]
-
- if name:
- self.name = name
- else:
- self.name = obj.get_type(2)[0]
- if color:
- self.color = color
- else:
- self.color = obj.get_type(62)[0]
- if frozen:
- self.frozen = frozen
- else:
- self.flags = obj.get_type(70)[0]
- self.frozen = self.flags&1
-
- def __repr__(self):
- return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color)
-
-
-
-class Line:
- """Class for objects representing dxf lines."""
-
- def __init__(self, obj):
- """Expects an entity object of type line as input."""
- if not obj.type == 'line':
- raise TypeError, "Wrong type %s for line object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.points = self.get_points(obj.data)
-
-
-
-
- def get_points(self, data):
- """Gets start and end points for a line type object.
-
- Lines have a fixed number of points (two) and fixed codes for each value.
- """
-
- # start x, y, z and end x, y, z = 0
- sx, sy, sz, ex, ey, ez = 0, 0, 0, 0, 0, 0
- for item in data:
- if item[0] == 10: # 10 = x
- sx = item[1]
- elif item[0] == 20: # 20 = y
- sy = item[1]
- elif item[0] == 30: # 30 = z
- sz = item[1]
- elif item[0] == 11: # 11 = x
- ex = item[1]
- elif item[0] == 21: # 21 = y
- ey = item[1]
- elif item[0] == 31: # 31 = z
- ez = item[1]
- return [[sx, sy, sz], [ex, ey, ez]]
-
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import lines into Blender."""
- # Generate the geometery
- points = self.points
- edges = [[0, 1]]
-
- me = Mesh.New('line') # create a new mesh
-
- me.verts.extend(points) # add vertices to mesh
- me.edges.extend(edges) # add edges to the mesh
-
- # Now Create an object
- ob = Object.New('Mesh', 'line') # link mesh to an object
- ob.link(me)
-
- return ob
-
-
-
-
-class LWpolyline:
- """Class for objects representing dxf LWpolylines."""
-
- def __init__(self, obj):
- """Expects an entity object of type lwpolyline as input."""
- if not obj.type == 'lwpolyline':
- raise TypeError, "Wrong type %s for polyline object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.num_points = obj.get_type(90)[0]
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.elevation = obj.get_type(38)
- if self.elevation:
- self.elevation = self.elevation[0]
- else:
- self.elevation = 0
-
- self.flags = obj.get_type(70)
- if self.flags:
- self.flags = self.flags[0]
- else:
- self.flags = 0
-
- self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.points = self.get_points(obj.data)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
-
- def get_points(self, data):
- """Gets points for a polyline type object.
-
- Polylines have no fixed number of verts, and
- each vert can have a number of properties.
- Verts should be coded as
- 10:xvalue
- 20:yvalue
- 40:startwidth or 0
- 41:endwidth or 0
- 42:bulge or 0
- for each vert
- """
- num = self.num_points
- point = None
- points = []
- for item in data:
- if item[0] == 10: # 10 = x
- if point:
- points.append(point)
- point = Vertex()
- point.x = item[1]
- elif item[0] == 20: # 20 = y
- point.y = item[1]
- elif item[0] == 40: # 40 = start width
- point.swidth = item[1]
- elif item[0] == 41: # 41 = end width
- point.ewidth = item[1]
- elif item[0] == 42: # 42 = bulge
- point.bulge = item[1]
- points.append(point)
- return points
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import plines into Blender."""
- # Generate the geometery
- points = []
- for i in range(len(self.points)):
- point = self.points[i]
- if not point.bulge:
- points.append(point.loc)
- elif point.bulge and i < len(self.points)-1:# > 0:
- center, radius, start, end = solveBulge(point, self.points[i+1])
- #print center, radius, start, end
- verts, nosense = drawArc(center, radius, start, end)
- verts.pop(0) # remove first
- verts.pop() #remove last
- if point.bulge >= 0:
- verts.reverse()
- points.extend(verts)
- edges = [[num, num+1] for num in range(len(points)-1)]
- if self.closed:
- edges.append([len(self.points)-1, 0])
-
- me = Mesh.New('lwpline') # create a new mesh
-
- me.verts.extend(points) # add vertices to mesh
- me.edges.extend(edges) # add edges to the mesh
-
- # Now Create an object
- ob = Object.New('Mesh', 'lwpline') # link mesh to an object
- ob.link(me)
- transform(self.extrusion, ob)
- ob.LocZ = self.elevation
-
- return ob
-
-
-
-class Polyline:
- """Class for objects representing dxf LWpolylines."""
-
- def __init__(self, obj):
- """Expects an entity object of type polyline as input."""
- if not obj.type == 'polyline':
- raise TypeError, "Wrong type %s for polyline object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
- self.points = []
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.elevation = obj.get_type(30)
- if self.elevation:
- self.elevation = self.elevation[0]
- else:
- self.elevation = 0
-
- self.flags = obj.get_type(70)
- if self.flags:
- self.flags = self.flags[0]
- else:
- self.flags = 0
-
- self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import plines into Blender."""
- # Generate the geometery
- points = []
- for i in range(len(self.points)):
- point = self.points[i]
- if not point.bulge:
- points.append(point.loc)
- elif point.bulge and i < len(self.points)-1:# > 0:
- center, radius, start, end = solveBulge(point, self.points[i+1])
- #print center, radius, start, end
- verts, nosense = drawArc(center, radius, start, end)
- verts.pop(0) # remove first
- verts.pop() #remove last
- if point.bulge >= 0:
- verts.reverse()
- points.extend(verts)
- edges = [[num, num+1] for num in range(len(points)-1)]
- if self.closed:
- edges.append([len(self.points)-1, 0])
-
- me = Mesh.New('pline') # create a new mesh
-
- me.verts.extend(points) # add vertices to mesh
- me.edges.extend(edges) # add edges to the mesh
-
- # Now Create an object
- ob = Object.New('Mesh', 'pline') # link mesh to an object
- ob.link(me)
- transform(self.extrusion, ob)
- ob.LocZ = self.elevation
-
- return ob
-
-
-
-
-class Vertex(object):
- """Generic vertex object used by polylines (and maybe others)."""
-
- def __init__(self, obj=None):
- """Initializes vertex data.
-
- The optional obj arg is an entity object of type vertex.
- """
- self.loc = [0,0,0]
- self.bulge = 0
- self.swidth = 0
- self.ewidth = 0
- self.flags = 0
-
- if obj is not None:
- if not obj.type == 'vertex':
- raise TypeError, "Wrong type %s for vertex object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- self.get_props(obj.data)
-
-
- def get_props(self, data):
- """Gets coords for a vertex type object.
-
- Each vert can have a number of properties.
- Verts should be coded as
- 10:xvalue
- 20:yvalue
- 40:startwidth or 0
- 41:endwidth or 0
- 42:bulge or 0
- """
- for item in data:
- if item[0] == 10: # 10 = x
- self.x = item[1]
- elif item[0] == 20: # 20 = y
- self.y = item[1]
- elif item[0] == 30: # 30 = z
- self.z = item[1]
- elif item[0] == 40: # 40 = start width
- self.swidth = item[1]
- elif item[0] == 41: # 41 = end width
- self.ewidth = item[1]
- elif item[0] == 42: # 42 = bulge
- self.bulge = item[1]
- elif item[0] == 70: # 70 = vert flags
- self.flags = item[1]
-
-
- def __len__(self):
- return 3
-
-
- def __getitem__(self, key):
- return self.loc[key]
-
-
- def __setitem__(self, key, value):
- if key in [0,1,2]:
- self.loc[key]
-
-
- def __iter__(self):
- return self.loc.__iter__()
-
-
- def __str__(self):
- return str(self.loc)
-
-
- def __repr__(self):
- return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s" %(self.loc, self.swidth, self.ewidth, self.bulge)
-
-
- def getx(self):
- return self.loc[0]
-
- def setx(self, value):
- self.loc[0] = value
-
- x = property(getx, setx)
-
-
- def gety(self):
- return self.loc[1]
-
- def sety(self, value):
- self.loc[1] = value
-
- y = property(gety, sety)
-
-
- def getz(self):
- return self.loc[2]
-
- def setz(self, value):
- self.loc[2] = value
-
- z = property(getz, setz)
-
-
-
-class Text:
- """Class for objects representing dxf Text."""
-
- def __init__(self, obj):
- """Expects an entity object of type text as input."""
- if not obj.type == 'text':
- raise TypeError, "Wrong type %s for text object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.height = obj.get_type(40)[0]
- self.value = obj.get_type(1)[0] # The text string value
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.rotation = obj.get_type(50) # radians?
- if not self.rotation:
- self.rotation = 0
- else:
- self.rotation = self.rotation[0]
-
- self.width_factor = obj.get_type(41) # Scaling factor along local x axis
- if not self.width_factor:
- self.width_factor = 1
- else:
- self.width_factor = self.width_factor[0]
-
- self.oblique = obj.get_type(51) # skew in degrees -90 <= oblique <= 90
- if not self.oblique:
- self.oblique = 0
- else:
- self.oblique = self.oblique[0]
-
- self.halignment = obj.get_type(72) # horiz. alignment
- if not self.halignment: # 0=left, 1=center, 2=right, 3=aligned, 4=middle, 5=fit
- self.halignment = 0
- else:
- self.halignment = self.halignment[0]
-
- self.valignment = obj.get_type(73) # vert. alignment
- if not self.valignment: # 0=baseline, 1=bottom, 2=middle, 3=top
- self.valignment = 0
- else:
- self.valignment = self.valignment[0]
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.loc = self.get_loc(obj.data, self.halignment, self.valignment)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
- def get_loc(self, data, halign, valign):
- """Gets adjusted location for text type objects.
-
- If group 72 and/or 73 values are nonzero then the first alignment point values
- are ignored and AutoCAD calculates new values based on the second alignment
- point and the length and height of the text string itself (after applying the
- text style). If the 72 and 73 values are zero or missing, then the second
- alignment point is meaningless.
-
- I don't know how to calc text size...
- """
- # bottom left x, y, z and justification x, y, z = 0
- x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0
- for item in data:
- if item[0] == 10: # 10 = x
- x = item[1]
- elif item[0] == 20: # 20 = y
- y = item[1]
- elif item[0] == 30: # 30 = z
- z = item[1]
- elif item[0] == 11: # 11 = x
- jx = item[1]
- elif item[0] == 21: # 21 = y
- jy = item[1]
- elif item[0] == 31: # 31 = z
- jz = item[1]
-
- if halign or valign:
- x, y, z = jx, jy, jz
- return [x, y, z]
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import texts into Blender."""
- # Generate the geometery
- txt = Text3d.New("text")
- txt.setSize(1)
- txt.setShear(self.oblique/90)
- txt.setExtrudeDepth(0.5)
- if self.halignment == 0:
- align = Text3d.LEFT
- elif self.halignment == 1:
- align = Text3d.MIDDLE
- elif self.halignment == 2:
- align = Text3d.RIGHT
- elif self.halignment == 3:
- align = Text3d.FLUSH
- else:
- align = Text3d.MIDDLE
- txt.setAlignment(align)
- txt.setText(self.value)
-
- # Now Create an object
- ob = Object.New('Text', 'text') # link mesh to an object
- ob.link(txt)
-
- transform(self.extrusion, ob)
-
- # move the object center to the text location
- ob.loc = tuple(self.loc)
- # scale it to the text size
- ob.SizeX = self.height*self.width_factor
- ob.SizeY = self.height
- ob.SizeZ = self.height
- # and rotate it around z
- ob.RotZ = radians(self.rotation)
-
- return ob
-
-
-
-
-class Mtext:
- """Class for objects representing dxf Mtext."""
-
- def __init__(self, obj):
- """Expects an entity object of type mtext as input."""
- if not obj.type == 'mtext':
- raise TypeError, "Wrong type %s for mtext object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.height = obj.get_type(40)[0]
- self.width = obj.get_type(41)[0]
- self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR
- self.value = self.get_text(obj.data) # The text string value
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.rotation = obj.get_type(50) # radians
- if not self.rotation:
- self.rotation = 0
- else:
- self.rotation = self.rotation[0]
-
- self.width_factor = obj.get_type(42) # Scaling factor along local x axis
- if not self.width_factor:
- self.width_factor = 1
- else:
- self.width_factor = self.width_factor[0]
-
- self.line_space = obj.get_type(44) # percentage of default
- if not self.line_space:
- self.line_space = 1
- else:
- self.line_space = self.line_space[0]
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.loc = self.get_loc(obj.data)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
- def get_text(self, data):
- """Reconstructs mtext data from dxf codes."""
- primary = ''
- secondary = []
- for item in data:
- if item[0] == 1: # There should be only one primary...
- primary = item[1]
- elif item[0] == 3: # There may be any number of extra strings (in order)
- secondary.append(item[1])
- if not primary:
- #raise ValueError, "Empty Mtext Object!"
- string = "Empty Mtext Object!"
- if not secondary:
- string = primary.replace(r'\P', '\n')
- else:
- string = ''.join(secondary)+primary
- string = string.replace(r'\P', '\n')
- return string
- def get_loc(self, data):
- """Gets location for a mtext type objects.
-
- Mtext objects have only one point indicating location.
- """
- loc = [0,0,0]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import mtexts into Blender."""
- # Generate the geometery
- txt = Text3d.New("mtext")
- txt.setSize(1)
- # Blender doesn't give access to its text object width currently
- # only to the text3d's curve width...
- #txt.setWidth(text.width/10)
- txt.setLineSeparation(self.line_space)
- txt.setExtrudeDepth(0.5)
- txt.setText(self.value)
-
- # Now Create an object
- ob = Object.New('Text', 'mtext') # link mesh to an object
- ob.link(txt)
-
- transform(self.extrusion, ob)
-
- # move the object center to the text location
- ob.loc = tuple(self.loc)
- # scale it to the text size
- ob.SizeX = self.height*self.width_factor
- ob.SizeY = self.height
- ob.SizeZ = self.height
- # and rotate it around z
- ob.RotZ = radians(self.rotation)
-
- return ob
-
-
-
-
-
-
-class Circle:
- """Class for objects representing dxf Circles."""
-
- def __init__(self, obj):
- """Expects an entity object of type circle as input."""
- if not obj.type == 'circle':
- raise TypeError, "Wrong type %s for circle object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.radius = obj.get_type(40)[0]
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.loc = self.get_loc(obj.data)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
- def get_loc(self, data):
- """Gets the center location for circle type objects.
-
- Circles have a single coord location.
- """
- loc = [0, 0, 0]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import circles into Blender."""
- # Generate the geometery
- # Now Create an object
- if curves:
- ob = drawCurveCircle(self)
- else:
- center = self.loc
- radius = self.radius
-
- circ = 2 * pi * radius
- if circ < 65: # if circumfrance is too small
- verts = 32 # set a fixed number of 32 verts
- else:
- verts = circ/.5 # figure out how many verts we need
- if verts > 100: # Blender only accepts values
- verts = 100 # [3:100]
-
- c = Mesh.Primitives.Circle(int(verts), radius*2)
-
- ob = Object.New('Mesh', 'circle')
- ob.link(c) # link curve data with this object
-
- ob.loc = tuple(center)
- transform(self.extrusion, ob)
-
- return ob
-
-
-
-
-class Arc:
- """Class for objects representing dxf arcs."""
-
- def __init__(self, obj):
- """Expects an entity object of type arc as input."""
- if not obj.type == 'arc':
- raise TypeError, "Wrong type %s for arc object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.radius = obj.get_type(40)[0]
- self.start_angle = obj.get_type(50)[0]
- self.end_angle = obj.get_type(51)[0]
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.loc = self.get_loc(obj.data)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
- def get_loc(self, data):
- """Gets the center location for arc type objects.
-
- Arcs have a single coord location.
- """
- loc = [0, 0, 0]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import arcs into Blender."""
- # Generate the geometery
- # Now Create an object
- if curves:
- ob = drawCurveArc(self)
- else:
- center = self.loc
- radius = self.radius
- start = self.start_angle
- end = self.end_angle
- verts, edges = drawArc(None, radius, start, end)
-
- a = Mesh.New('arc')
-
- a.verts.extend(verts) # add vertices to mesh
- a.edges.extend(edges) # add edges to the mesh
-
- ob = Object.New('Mesh', 'arc')
- ob.link(a) # link curve data with this object
- ob.loc = tuple(center)
- ob.RotX = radians(180)
-
- transform(self.extrusion, ob)
- ob.size = (1,1,1)
-
- return ob
-
-
-class BlockRecord:
- """Class for objects representing dxf block_records."""
-
- def __init__(self, obj):
- """Expects an entity object of type block_record as input."""
- if not obj.type == 'block_record':
- raise TypeError, "Wrong type %s for block_record object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.name = obj.get_type(2)[0]
-
- # optional data (with defaults)
- self.insertion_units = obj.get_type(70)
- if not self.insertion_units:
- self.insertion_units = None
- else:
- self.insertion_units = self.insertion_units[0]
-
- self.insert_units = obj.get_type(1070)
- if not self.insert_units:
- self.insert_units = None
- else:
- self.insert_units = self.insert_units[0]
-
-
-
-
-
-
- def __repr__(self):
- return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units)
-
-
-
-
-class Block:
- """Class for objects representing dxf blocks."""
-
- def __init__(self, obj):
- """Expects an entity object of type block as input."""
- if not obj.type == 'block':
- raise TypeError, "Wrong type %s for block object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
- self.name = obj.name
-
- # required data
- self.flags = obj.get_type(70)[0]
- self.entities = dxfObject('block_contents')
- self.entities.data = objectify([ent for ent in obj.data if type(ent) != list])
-
- # optional data (with defaults)
- self.path = obj.get_type(1)
- if self.path:
- self.path = self.path[0]
- else:
- self.path = ''
-
- self.discription = obj.get_type(4)
- if self.discription:
- self.discription = self.discription[0]
- else:
- self.discription = ''
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.loc = self.get_loc(obj.data)
-
-
-
-
- def get_loc(self, data):
- """Gets the insert point of the block."""
- loc = [0, 0, 0]
- for item in data:
- if type(item) != list:
- continue
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def __repr__(self):
- return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path)
-
-
-
-
-class Insert:
- """Class for objects representing dxf inserts."""
-
- def __init__(self, obj):
- """Expects an entity object of type insert as input."""
- if not obj.type == 'insert':
- raise TypeError, "Wrong type %s for insert object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.block = obj.get_type(2)[0]
-
- # optional data (with defaults)
- self.rotation = obj.get_type(50)
- if self.rotation:
- self.rotation = self.rotation[0]
- else:
- self.rotation = 0
-
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.loc = self.get_loc(obj.data)
- self.scale = self.get_scale(obj.data)
- self.rows, self.columns = self.get_array(obj.data)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
- def get_loc(self, data):
- """Gets the center location for circle type objects.
-
- Circles have a single coord location.
- """
- loc = [0, 0, 0]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_scale(self, data):
- """Gets the x/y/z scale factor for the block.
- """
- scale = [1, 1, 1]
- for item in data:
- if item[0] == 41: # 41 = x scale
- scale[0] = item[1]
- elif item[0] == 42: # 42 = y scale
- scale[1] = item[1]
- elif item[0] == 43: # 43 = z scale
- scale[2] = item[1]
- return scale
-
-
-
- def get_array(self, data):
- """Returns the pair (row number, row spacing), (column number, column spacing)."""
- columns = 1
- rows = 1
- cspace = 0
- rspace = 0
- for item in data:
- if item[0] == 70: # 70 = columns
- columns = item[1]
- elif item[0] == 71: # 71 = rows
- rows = item[1]
- if item[0] == 44: # 44 = columns
- cspace = item[1]
- elif item[0] == 45: # 45 = rows
- rspace = item[1]
- return (rows, rspace), (columns, cspace)
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, block - %s" %(self.__class__.__name__, self.layer, self.block)
-
-
- def draw(self, handle, settings):
- """Do all the specific things needed to import blocks into Blender.
-
- Blocks are made of three objects:
- the block_record in the tables section
- the block in the blocks section
- the insert object in the entities section
-
- block_records give the insert units, blocks provide the objects drawn in the
- block, and the insert object gives the location/scale/rotation of the block
- instances. To draw a block you must first get a group with all the
- blocks entities drawn in it, then scale the entities to match the world
- units, then dupligroup that data to an object matching each insert object."""
-
- # Create an object
- ob = Object.New('Mesh', self.block)
- ob.link(handle) # Give the object a handle
-
- if settings.drawTypes['blocks']:
- # get our block group
- block = settings.blocks(self.block)
-
- ob.DupGroup = block
- ob.enableDupGroup = True
-
- ob.loc = tuple(self.loc)
- transform(self.extrusion, ob)
- ob.RotZ += radians(self.rotation)
- ob.size = tuple(self.scale)
-
- return ob
-
-
-
-
-class Ellipse:
- """Class for objects representing dxf ellipses."""
-
- def __init__(self, obj):
- """Expects an entity object of type ellipse as input."""
- if not obj.type == 'ellipse':
- raise TypeError, "Wrong type %s for ellipse object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # required data
- self.ratio = obj.get_type(40)[0]
- self.start_angle = obj.get_type(41)[0]
- self.end_angle = obj.get_type(42)[0]
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.loc = self.get_loc(obj.data)
- self.major = self.get_major(obj.data)
- self.extrusion = self.get_extrusion(obj.data)
- self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2)
-
-
-
-
- def get_loc(self, data):
- """Gets the center location for arc type objects.
-
- Arcs have a single coord location.
- """
- loc = [0, 0, 0]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_major(self, data):
- """Gets the major axis for ellipse type objects.
-
- The ellipse major axis defines the rotation of the ellipse and its radius.
- """
- loc = [0, 0, 0]
- for item in data:
- if item[0] == 11: # 11 = x
- loc[0] = item[1]
- elif item[0] == 21: # 21 = y
- loc[1] = item[1]
- elif item[0] == 31: # 31 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import ellipses into Blender."""
- # Generate the geometery
- # Now Create an object
- if curves:
- ob = drawCurveArc(self)
- else:
- major = Mathutils.Vector(self.major)
- delta = Mathutils.AngleBetweenVecs(major, WORLDX)
- center = self.loc
- radius = major.length
- start = degrees(self.start_angle)
- end = degrees(self.end_angle)
- verts, edges = drawArc(None, radius, start, end)
-
- e = Mesh.New('ellipse')
-
- e.verts.extend(verts) # add vertices to mesh
- e.edges.extend(edges) # add edges to the mesh
-
-
- ob = Object.New('Mesh', 'arc')
- ob.link(e) # link curve data with this object
- ob.loc = tuple(center)
- ob.SizeY = self.ratio
- #ob.RotZ = radians(delta)
- ob.RotX = radians(180)
-
-
- transform(self.extrusion, ob)
- ob.RotZ = radians(delta)
-
- return ob
-
-
-
-class Face:
- """Class for objects representing dxf 3d faces."""
-
- def __init__(self, obj):
- """Expects an entity object of type 3dfaceplot as input."""
- if not obj.type == '3dface':
- raise TypeError, "Wrong type %s for 3dface object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer = get_layer(obj.data)
- obj.data.remove(discard)
- self.points = self.get_points(obj.data)
-
-
-
-
- def get_points(self, data):
- """Gets 3-4 points for a 3d face type object.
-
- Faces have three or optionally four verts.
- """
-
- a = [0, 0, 0]
- b = [0, 0, 0]
- c = [0, 0, 0]
- d = False
- for item in data:
- # ----------- a -------------
- if item[0] == 10: # 10 = x
- a[0] = item[1]
- elif item[0] == 20: # 20 = y
- a[1] = item[1]
- elif item[0] == 30: # 30 = z
- a[2] = item[1]
- # ----------- b -------------
- elif item[0] == 11: # 11 = x
- b[0] = item[1]
- elif item[0] == 21: # 21 = y
- b[1] = item[1]
- elif item[0] == 31: # 31 = z
- b[2] = item[1]
- # ----------- c -------------
- elif item[0] == 12: # 12 = x
- c[0] = item[1]
- elif item[0] == 22: # 22 = y
- c[1] = item[1]
- elif item[0] == 32: # 32 = z
- c[2] = item[1]
- # ----------- d -------------
- elif item[0] == 13: # 13 = x
- d = [0, 0, 0]
- d[0] = item[1]
- elif item[0] == 23: # 23 = y
- d[1] = item[1]
- elif item[0] == 33: # 33 = z
- d[2] = item[1]
- out = [a,b,c]
- if d:
- out.append(d)
- return out
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
- def draw(self, curves=False):
- """Do all the specific things needed to import 3d faces into Blender."""
- # Generate the geometery
- points = self.points
- if len(self.points) > 3:
- faces = [[0, 1, 2, 3]]
- else:
- faces = [[0, 1, 2]]
-
- me = Mesh.New('3dface') # create a new mesh
-
- me.verts.extend(points) # add vertices to mesh
- me.faces.extend(faces) # add faces to the mesh
-
- # Now Create an object
- ob = Object.New('Mesh', '3dface') # link mesh to an object
- ob.link(me)
-
- return ob
-
-
-
-# type to object map
+class View: #-----------------------------------------------------------------
+ """Class for objects representing dxf VIEWs.
+ """
+ def __init__(self, obj, active=None):
+ """Expects an object of type VIEW as input.
+ """
+ if not obj.type == 'view':
+ raise TypeError, "Wrong type %s for VIEW object!" %obj.type
+
+ self.type = obj.type
+ self.name = obj.get_type(2)[0]
+ self.data = obj.data[:]
+
+
+ self.centerX = getit(obj.data, 10, 0.0) #view center pointX (in DCS)
+ self.centerY = getit(obj.data, 20, 0.0) #view center pointY (in DCS)
+ self.height = obj.get_type(40)[0] #view height (in DCS)
+ self.width = obj.get_type(41)[0] #view width (in DCS)
+
+ self.dir = [0,0,0]
+ self.dir[0] = getit(obj.data, 11, 0.0) #view directionX from target (in WCS)
+ self.dir[1] = getit(obj.data, 21, 0.0) #
+ self.dir[2] = getit(obj.data, 31, 0.0) #
+
+ self.target = [0,0,0]
+ self.target[0] = getit(obj.data, 12, 0.0) #target pointX(in WCS)
+ self.target[1] = getit(obj.data, 22, 0.0) #
+ self.target[2] = getit(obj.data, 32, 0.0) #
+
+ self.length = obj.get_type(42)[0] #Lens length
+ self.clip_front = getit(obj.data, 43) #Front clipping plane (offset from target point)
+ self.clip_back = getit(obj.data, 44) #Back clipping plane (offset from target point)
+ self.twist = obj.get_type(50)[0] #view twist angle in degrees
+
+ self.flags = getit(obj, 70, 0)
+ self.paperspace = self.flags & 1 #
+
+ self.mode = obj.get_type(71)[0] #view mode (VIEWMODE system variable)
+
+ def __repr__(self):
+ return "%s: name - %s, focus length - %s" %(self.__class__.__name__, self.name, self.length)
+
+
+ def draw(self, settings):
+ """for VIEW: generate Blender_camera.
+ """
+ obname = 'vw_%s' %self.name # create camera object name
+ #obname = 'ca_%s' %self.name # create camera object name
+ obname = obname[:MAX_NAMELENGTH]
+
+ if self.target == [0,0,0] and Mathutils.Vector(self.dir).length == 1.0:
+ cam= Camera.New('ortho', obname)
+ ob= SCENE.objects.new(cam)
+ cam.type = 'ortho'
+ cam.scale = 1.0 # for ortho cameras
+ else:
+ cam= Camera.New('persp', obname)
+ ob= SCENE.objects.new(cam)
+ cam.type = 'persp'
+ cam.angle = 60.0 # for persp cameras
+ if self.length:
+ #cam.angle = 2 * atan(17.5/self.length) * 180/pi
+ cam.lens = self.length #for persp cameras
+ # hack to update Camera>Lens setting (inaccurate as a focal length)
+ #curLens = cam.lens; cam.lens = curLens
+ # AutoCAD gets clip distance from target:
+ dist = Mathutils.Vector(self.dir).length
+ cam.clipEnd = dist - self.clip_back
+ cam.clipStart = dist - self.clip_front
+
+ cam.drawLimits = 1
+ cam.drawSize = 10
+
+ v = Mathutils.Vector(self.dir)
+# print 'deb:view cam:', cam #------------
+# print 'deb:view self.target:', self.target #------------
+# print 'deb:view self.dir:', self.dir #------------
+# print 'deb:view self.twist:', self.twist #------------
+# print 'deb:view self.clip_front=%s, self.clip_back=%s, dist=%s' %(self.clip_front, self.clip_back, dist) #------------
+ transform(v.normalize(), -self.twist, ob)
+ ob.loc = Mathutils.Vector(self.target) + Mathutils.Vector(self.dir)
+ return ob
+
+
+class Vport: #-----------------------------------------------------------------
+ """Class for objects representing dxf VPORTs.
+ """
+ def __init__(self, obj, active=None):
+ """Expects an object of type VPORT as input.
+ """
+ if not obj.type == 'vport':
+ raise TypeError, "Wrong type %s for VPORT object!" %obj.type
+
+ self.type = obj.type
+ self.name = obj.get_type(2)[0]
+ self.data = obj.data[:]
+ #print 'deb:vport name, data:', self.name #-------
+ #print 'deb:vport data:', self.data #-------
+
+ self.height = obj.get_type(40)[0] #vport height (in DCS)
+ self.centerX = getit(obj.data, 12, 0.0) #vport center pointX (in DCS)
+ self.centerY = getit(obj.data, 22, 0.0) #vport center pointY (in DCS)
+ self.width = self.height * obj.get_type(41)[0] #vport aspect ratio - width (in DCS)
+
+ self.dir = [0,0,0]
+ self.dir[0] = getit(obj.data, 16, 0.0) #vport directionX from target (in WCS)
+ self.dir[1] = getit(obj.data, 26, 0.0) #
+ self.dir[2] = getit(obj.data, 36, 0.0) #
+
+ self.target = [0,0,0]
+ self.target[0] = getit(obj.data, 17, 0.0) #target pointX(in WCS)
+ self.target[1] = getit(obj.data, 27, 0.0) #
+ self.target[2] = getit(obj.data, 37, 0.0) #
+
+ self.length = obj.get_type(42)[0] #Lens length
+ self.clip_front = getit(obj.data, 43) #Front clipping plane (offset from target point)
+ self.clip_back = getit(obj.data, 44) #Back clipping plane (offset from target point)
+ self.twist = obj.get_type(51)[0] #view twist angle
+
+ self.flags = getit(obj, 70, 0)
+ self.paperspace = self.flags & 1 #
+
+ self.mode = obj.get_type(71)[0] #view mode (VIEWMODE system variable)
+
+ def __repr__(self):
+ return "%s: name - %s, focus length - %s" %(self.__class__.__name__, self.name, self.length)
+
+ def draw(self, settings):
+ """for VPORT: generate Blender_camera.
+ """
+ obname = 'vp_%s' %self.name # create camera object name
+ #obname = 'ca_%s' %self.name # create camera object name
+ obname = obname[:MAX_NAMELENGTH]
+
+ if self.target == [0,0,0] and Mathutils.Vector(self.dir).length == 1.0:
+ cam= Camera.New('ortho', obname)
+ ob= SCENE.objects.new(cam)
+ cam.type = 'ortho'
+ cam.scale = 1.0 # for ortho cameras
+ else:
+ cam= Camera.New('persp', obname)
+ ob= SCENE.objects.new(cam)
+ cam.type = 'persp'
+ cam.angle = 60.0 # for persp cameras
+ if self.length:
+ #cam.angle = 2 * atan(17.5/self.length) * 180/pi
+ cam.lens = self.length #for persp cameras
+ # hack to update Camera>Lens setting (inaccurate as a focal length)
+ #curLens = cam.lens; cam.lens = curLens
+ # AutoCAD gets clip distance from target:
+ dist = Mathutils.Vector(self.dir).length
+ cam.clipEnd = dist - self.clip_back
+ cam.clipStart = dist - self.clip_front
+
+ cam.drawLimits = 1
+ cam.drawSize = 10
+
+ v = Mathutils.Vector(self.dir)
+# print 'deb:view cam:', cam #------------
+# print 'deb:view self.target:', self.target #------------
+# print 'deb:view self.dir:', self.dir #------------
+# print 'deb:view self.twist:', self.twist #------------
+# print 'deb:view self.clip_front=%s, self.clip_back=%s, dist=%s' %(self.clip_front, self.clip_back, dist) #------------
+ transform(v.normalize(), -self.twist, ob)
+ ob.loc = Mathutils.Vector(self.target) + Mathutils.Vector(self.dir)
+ return ob
+
+
+
+class Layer: #-----------------------------------------------------------------
+ """Class for objects representing dxf LAYERs.
+ """
+ def __init__(self, obj, name=None, color=None, frozen=None):
+ """Expects an object of type layer as input.
+ """
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ if name:
+ self.name = name
+ #self.bfname = name #--todo---see layernamesmap in f_getLayersmap ---
+ else:
+ self.name = obj.get_type(2)[0] #layer name of object
+
+ if color:
+ self.color = color
+ else:
+ self.color = obj.get_type(62)[0] #color of object
+
+ if frozen:
+ self.frozen = frozen
+ else:
+ self.flags = obj.get_type(70)[0]
+ self.frozen = self.flags & 1
+
+
+ def __repr__(self):
+ return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color)
+
+
+
+def getit(obj, typ, default=None): #------------------------------------------
+ """Universal procedure for geting data from list/objects.
+ """
+ it = default
+ if type(obj) == list: #if obj is a list, then searching in a list
+ for item in obj:
+ #print 'deb:getit item, type(item)', item, type(item)
+ try:
+ if item[0] == typ:
+ it = item[1]
+ break #as soon as the first found
+ except:
+ # --todo-- I found one case where item was a text instance
+ # that failed with no __getitem__
+ pass
+ else: #else searching in Object with get_type-Methode
+ item = obj.get_type(typ)
+ if item:
+ it = item[0]
+ #print 'deb:getit:typ, it', typ, it #----------
+ return it
+
+
+
+def get_extrusion(data): #-------------------------------------------------
+ """Find the axis of extrusion.
+
+ Used to get from object_data the objects Object_Coordinate_System (ocs).
+ """
+ #print 'deb:get_extrusion: data: \n', data #---------------
+ vec = [0,0,1]
+ vec[0] = getit(data, 210, 0) # 210 = x
+ vec[1] = getit(data, 220, 0) # 220 = y
+ vec[2] = getit(data, 230, 1) # 230 = z
+ #print 'deb:get_extrusion: vec: ', vec #---------------
+ return vec
+
+
+
+class Solid: #-----------------------------------------------------------------
+ """Class for objects representing dxf SOLID or TRACE.
+ """
+ def __init__(self, obj):
+ """Expects an entity object of type solid or trace as input.
+ """
+ if obj.type == 'trace':
+ obj.type = 'solid'
+ if not obj.type == 'solid':
+ raise TypeError, "Wrong type \'%s\' for solid/trace object!" %obj.type
+
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ self.space = getit(obj, 67, 0)
+ self.thic = getit(obj, 39, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.extrusion = get_extrusion(obj.data)
+ self.points = self.get_points(obj.data)
+
+
+
+ def get_points(self, data):
+ """Gets start and end points for a solid type object.
+
+ Solids have 3 or 4 points and fixed codes for each value.
+ """
+
+ # start x, y, z and end x, y, z = 0
+ a = [0, 0, 0]
+ b = [0, 0, 0]
+ c = [0, 0, 0]
+ d = [0, 0, 0]
+ a[0] = getit(data, 10, None) # 10 = x
+ a[1] = getit(data, 20, None) # 20 = y
+ a[2] = getit(data, 30, 0) # 30 = z
+ b[0] = getit(data, 11, None)
+ b[1] = getit(data, 21, None)
+ b[2] = getit(data, 31, 0)
+ c[0] = getit(data, 12, None)
+ c[1] = getit(data, 22, None)
+ c[2] = getit(data, 32, 0)
+ out = [a,b,c]
+
+ d[0] = getit(data, 13, None)
+ if d[0] != None:
+ d[1] = getit(data, 23, None)
+ d[2] = getit(data, 33, 0)
+ out.append(d)
+ #print 'deb:solid.vertices:---------\n', out #-----------------------
+ return out
+
+
+ def __repr__(self):
+ return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
+
+
+ def draw(self, settings):
+ """for SOLID: generate Blender_geometry.
+ """
+ points = self.points
+ if not points: return
+ edges, faces = [], []
+ l = len(self.points)
+
+ obname = 'so_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+
+ vg_left, vg_right, vg_top, vg_bottom, vg_start, vg_end = [], [], [], [], [], []
+ thic = set_thick(self.thic, settings)
+ if thic != 0:
+ thic_points = [[v[0], v[1], v[2] + thic] for v in points[:]]
+ if thic < 0.0:
+ thic_points.extend(points)
+ points = thic_points
+ else:
+ points.extend(thic_points)
+
+ if l == 4:
+ faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1],
+ [1,5,7,3], [3,7,6,2], [2,6,4,0]]
+ vg_left = [2,6,4,0]
+ vg_right = [1,5,7,3]
+ vg_top = [4,6,7,5]
+ vg_bottom = [0,1,3,2]
+ vg_start = [0,4,5,1]
+ vg_end = [3,7,6,2]
+ elif l == 3:
+ faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]]
+ vg_top = [3,4,5]
+ vg_bottom = [0,1,2]
+ vg_left = [2,5,3,0]
+ vg_right = [1,4,5,2]
+ vg_start = [0,3,4,1]
+ elif l == 2: faces = [[0,1,3,2]]
+ else:
+ if l == 4: faces = [[0,1,3,2]]
+ elif l == 3: faces = [[0,1,2]]
+ elif l == 2: edges = [[0,1]]
+
+
+
+ me = Mesh.New(obname) # create a new mesh
+ me.verts.extend(points) # add vertices to mesh
+ if faces: me.faces.extend(faces) # add faces to the mesh
+ if edges: me.edges.extend(edges) # add faces to the mesh
+
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ if settings.var['vGroup_on']:
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.ADD/REPLACE
+ if vg_left: me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace)
+ if vg_right:me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace)
+ if vg_top: me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace)
+ if vg_bottom:me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace)
+ if vg_start:me.addVertGroup('side.start') ; me.assignVertsToGroup('side.start', vg_start, 1.0, replace)
+ if vg_end: me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', vg_end, 1.0, replace)
+
+ transform(self.extrusion, 0, ob)
+
+ return ob
+
+
+
+
+class Line: #-----------------------------------------------------------------
+ """Class for objects representing dxf LINEs.
+ """
+ def __init__(self, obj):
+ """Expects an entity object of type line as input.
+ """
+ if not obj.type == 'line':
+ raise TypeError, "Wrong type \'%s\' for line object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ self.space = getit(obj, 67, 0)
+ self.thic = getit(obj, 39, 0)
+ #print 'deb:self.thic: ', self.thic #---------------------
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.extrusion = get_extrusion(obj.data)
+ self.points = self.get_points(obj.data)
+
+
+ def get_points(self, data):
+ """Gets start and end points for a line type object.
+
+ Lines have a fixed number of points (two) and fixed codes for each value.
+ """
+ # start x,y,z and end x,y,z = 0
+ a = [0, 0, 0]
+ b = [0, 0, 0]
+ a[0] = getit(data, 10, None) # 10 = x
+ a[1] = getit(data, 20, None) # 20 = y
+ a[2] = getit(data, 30, 0) # 30 = z
+ b[0] = getit(data, 11, None)
+ b[1] = getit(data, 21, None)
+ b[2] = getit(data, 31, 0)
+ out = [a,b]
+ return out
+
+
+ def __repr__(self):
+ return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
+
+
+ def draw(self, settings):
+ """for LINE: generate Blender_geometry.
+ """
+ # Generate the geometery
+ #settings.var['curves_on']=False
+
+ points = self.points
+ thic = set_thick(self.thic, settings)
+ width = 0.0
+ if settings.var['lines_as'] == 4: # as thin_box
+ thic = settings.var['thick_min']
+ width = settings.var['width_min']
+ elif settings.var['lines_as'] == 3: # as thin cylinder
+ cyl_rad = 0.5 * settings.var['width_min']
+
+ if settings.var['lines_as'] == 5: # LINE curve representation-------------------------
+ obname = 'li_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+
+ c = Curve.New(obname) # create new curve data
+ curve = c.appendNurb(BezTriple.New(points[0]))
+ curve.append(BezTriple.New(points[1]))
+ for point in curve:
+ point.handleTypes = [VECT, VECT]
+ curve.flagU = 0 # 0 sets the curve not cyclic=open
+ c.setResolu(settings.var['curve_res'])
+ c.update() #important for handles calculation
+
+ ob = SCENE.objects.new(c) # create a new curve_object
+
+ #if False: # --todo-- better support for 210-group
+ if thic != 0.0: #hack: Blender2.45 curve-extrusion
+ t = thic * 0.5
+ if abs(t) > 5.0: t = 5.0 * cmp(t,0) # Blender2.45 accepts only (0.0 - 5.0)
+ e = self.extrusion
+ c.setExt1(abs(t)) # curve-extrusion
+ ob.LocX += t * e[0]
+ ob.LocY += t * e[1]
+ ob.LocZ += t * e[2]
+ #c.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0)
+ #ob.LocZ = t + self.loc[2]
+ #ob.SizeZ *= abs(t)
+ return ob
+
+ else: # LINE mesh representation ------------------------------
+ global activObjectLayer
+ global activObjectName
+ #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #---------------------
+
+ if activObjectLayer == self.layer and settings.var['one_mesh_on']:
+ obname = activObjectName
+ #print 'deb:line.draw obname from activObjectName: ', obname #---------------------
+ ob = Object.Get(obname) # open an existing mesh_object
+ #ob = SCENE.getChildren(obname) # open an existing mesh_object
+ me = Mesh.Get(ob.name) # open objects mesh data
+ else:
+ obname = 'li_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ activObjectName = ob.name
+ activObjectLayer = self.layer
+ #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #---------------------
+
+ faces, edges = [], []
+ n = len(me.verts)
+
+ #if settings.var['width_force']: #--todo-----------
+
+ if thic != 0:
+ t, e = thic, self.extrusion
+ #print 'deb:thic, extr: ', t, e #---------------------
+ points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]])
+ faces = [[0+n, 1+n, 3+n, 2+n]]
+ else:
+ edges = [[0+n, 1+n]]
+
+ me.verts.extend(points) # adds vertices to global mesh
+ if faces: me.faces.extend(faces) # add faces to the mesh
+ if edges: me.edges.extend(edges) # add faces to the mesh
+
+ if settings.var['vGroup_on']:
+ # entities with the same color build one vertexGroup for easier material assignment ----
+ ob.link(me) # link mesh to that object
+ vG_name = 'color_%s' %self.color_index
+ if edges: faces = edges
+ replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD
+ try:
+ me.assignVertsToGroup(vG_name, faces[0], 1.0, replace)
+ #print 'deb: existed vGroup:', vG_name #---------------------
+ except:
+ me.addVertGroup(vG_name)
+ me.assignVertsToGroup(vG_name, faces[0], 1.0, replace)
+ #print 'deb: create new vGroup:', vG_name #---------------------
+
+
+ #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #---------------------
+ return ob
+
+
+
+class Point: #-----------------------------------------------------------------
+ """Class for objects representing dxf POINTs.
+ """
+ def __init__(self, obj):
+ """Expects an entity object of type point as input.
+ """
+ if not obj.type == 'point':
+ raise TypeError, "Wrong type %s for point object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ self.space = getit(obj, 67, 0)
+ self.thic = getit(obj, 39, 0)
+ #print 'deb:self.thic: ', self.thic #---------------------
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.extrusion = get_extrusion(obj.data)
+ self.points = self.get_points(obj.data)
+
+
+ def get_points(self, data):
+ """Gets coordinates for a point type object.
+
+ Points have fixed codes for each value.
+ """
+ a = [0, 0, 0]
+ a[0] = getit(data, 10, None) # 10 = x
+ a[1] = getit(data, 20, None) # 20 = y
+ a[2] = getit(data, 30, 0) # 30 = z
+ out = [a]
+ return out
+
+
+ def __repr__(self):
+ return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
+
+
+ def draw(self, settings):
+ """for POINT: generate Blender_geometry.
+ """
+ points = self.points
+ obname = 'po_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ points_as = settings.var['points_as']
+ thic = settings.var['thick_min']
+ if thic < settings.var['dist_min']: thic = settings.var['dist_min']
+
+ if True: #--todo-- points_as in [1,3,4,5]:
+ if True: # points_as in [1,5]: # as 'empty'
+ c = 'Empty'
+ elif points_as == 3: # as 'thin sphere'
+ res = settings.var['thin_res']
+ c = Mesh.Primitives.UVsphere(res,res,thic)
+ elif points_as == 4: # as 'thin box'
+ c = Mesh.Primitives.Cube(thic)
+ ob = SCENE.objects.new(c, obname) # create a new object
+ transform(self.extrusion, 0, ob)
+ ob.loc = tuple(points[0])
+
+ elif points_as == 2: # as 'vertex'
+ global activObjectLayer
+ global activObjectName
+ #print 'deb:draw:point.ob IN activObjectName: ', activObjectName #---------------------
+ if activObjectLayer == self.layer and settings.var['one_mesh_on']:
+ obname = activObjectName
+ #print 'deb:draw:point.ob obname from activObjectName: ', obname #---------------------
+ ob = Object.Get(obname) # open an existing mesh_object
+ #ob = SCENE.getChildren(obname) # open an existing mesh_object
+ me = Mesh.Get(ob.name) # open objects mesh data
+ else:
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ activObjectName = ob.name
+ activObjectLayer = self.layer
+ #print ('deb:draw:point new point.ob+mesh:"%s" created!' %ob.name) #---------------------
+ me.verts.extend(points) # add vertices to mesh
+
+ return ob
+
+
+
+class LWpolyline: #-----------------------------------------------------------------
+ """Class for objects representing dxf LWPOLYLINEs.
+ """
+ def __init__(self, obj):
+ """Expects an entity object of type lwpolyline as input.
+ """
+ #print 'deb:LWpolyline.START:----------------' #------------------------
+ if not obj.type == 'lwpolyline':
+ raise TypeError, "Wrong type %s for polyline object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # required data
+ self.num_points = obj.get_type(90)[0]
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.elevation = getit(obj, 30, 0)
+ self.thic = getit(obj, 39, 0)
+ self.flags = getit(obj, 70, 0)
+
+ self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen
+
+ self.layer = getit(obj.data, 8, None)
+ self.points = self.get_points(obj.data)
+ self.extrusion = get_extrusion(obj.data)
+
+ #print 'deb:LWpolyline.obj.data:\n', obj.data #------------------------
+ #print 'deb:LWpolyline.ENDinit:----------------' #------------------------
+
+
+ def get_points(self, data):
+ """Gets points for a polyline type object.
+
+ LW-Polylines have no fixed number of verts, and
+ each vert can have a number of properties.
+ Verts should be coded as
+ 10:xvalue
+ 20:yvalue
+ 40:startwidth or 0
+ 41:endwidth or 0
+ 42:bulge or 0
+ for each vert
+ """
+ num = self.num_points
+ point = None
+ points = []
+ for item in data:
+ if item[0] == 10: # 10 = x
+ if point:
+ points.append(point)
+ point = Vertex()
+ point.x = item[1]
+ elif item[0] == 20: # 20 = y
+ point.y = item[1]
+ elif item[0] == 40: # 40 = start width
+ point.swidth = item[1]
+ elif item[0] == 41: # 41 = end width
+ point.ewidth = item[1]
+ elif item[0] == 42: # 42 = bulge
+ point.bulge = item[1]
+ points.append(point)
+ return points
+
+
+
+ def __repr__(self):
+ return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
+
+
+ def draw(self, settings):
+ """for LWPOLYLINE: generate Blender_geometry.
+ """
+ #print 'deb:LWpolyline.draw.START:----------------' #------------------------
+ points = []
+ obname = 'lw_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ #settings.var['curves_on'] == True
+ #print 'deb:index_len: ', len(self.points) #------------------
+ for i, point in enumerate(self.points):
+ #print 'deb:index: ', i #------------------
+ if not point.bulge:
+ points.append(point.loc)
+ elif point.bulge and not self.closed and i == len(self.points)-1:
+ points.append(point.loc)
+ elif point.bulge: #
+ if i == len(self.points)-1:
+ point2 = self.points[0]
+ else:
+ point2 = self.points[i+1]
+ arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad'])
+ verts, center = calcBulge(point, point2, arc_res)
+# if i == len(self.points)-1:
+# if self.closed:
+# verts.pop() #remove last(=first) vertex
+# else:
+# verts.pop() #remove last vertex, because this point will be writen as the next vertex
+ points.extend(verts)
+
+ thic = self.thic
+ if settings.var['thick_force'] and thic == 0: thic = settings.var['thick_min']
+ if settings.var['thick_on'] and thic != 0:
+ len1 = len(points)
+ points.extend([[point[0], point[1], point[2]+thic] for point in points])
+ faces = []
+ #print 'deb:len1:', len1 #-----------------------
+ faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
+ if self.closed:
+ faces.append([len1-1, 0, len1, 2*len1-1])
+ #print 'deb:faces_list:\n', faces #-----------------------
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend(points) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+ else:
+ edges = [[num, num+1] for num in xrange(len(points)-1)]
+ if self.closed:
+ edges.append([len(points)-1, 0])
+ #print 'deb:edges_list:\n', edges #-----------------------
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend(points) # add vertices to mesh
+ me.edges.extend(edges) # add edges to the mesh
+
+ ob.LocZ = self.elevation
+ transform(self.extrusion, 0, ob)
+
+ #print 'deb:LWpolyline.draw.END:----------------' #------------------------
+ return ob
+
+
+
+class Polyline: #-----------------------------------------------------------------
+ """Class for objects representing dxf POLYLINEs.
+ """
+ def __init__(self, obj):
+ """Expects an entity object of type polyline as input.
+ """
+ #print 'deb:polyline.init.START:----------------' #------------------------
+ if not obj.type == 'polyline':
+ raise TypeError, "Wrong type %s for polyline object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+ #print 'deb:polyline.obj.data[:]:\n', obj.data[:] #------------------------
+ self.points = []
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+ self.elevation = getit(obj, 30, 0)
+ #print 'deb:elevation: ', self.elevation #---------------
+ self.thic = getit(obj, 39, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.flags = getit(obj, 70, 0)
+ self.closed = self.flags & 1 # closed in the M direction
+ self.curved = self.flags & 2 # Bezier-curve-fit vertices have been added
+ self.spline = self.flags & 4 # Bspline-fit vertices have been added
+ self.poly3d = self.flags & 8 # 3D-polyline
+ self.plmesh = self.flags & 16 # 3D-polygon mesh
+ self.closeN = self.flags & 32 # closed in the N direction
+ self.plface = self.flags & 64 # 3D-polyface mesh
+ self.contin = self.flags & 128 # the linetype pattern is generated continuously
+
+ if self.poly3d or self.plface or self.plmesh:
+ self.poly2d = False # its not a 2D-polyline
+ else:
+ self.poly2d = True # it is a 2D-polyline
+
+ self.swidth = getit(obj, 40, 0) # default start width
+ self.ewidth = getit(obj, 41, 0) # default end width
+ #self.bulge = getit(obj, 42, None) # bulge of the segment
+ self.vectorsM = getit(obj, 71, None) # PolyMesh: expansion in M-direction / PolyFace: number of the vertices
+ self.vectorsN = getit(obj, 72, None) # PolyMesh: expansion in M-direction / PolyFace: number of faces
+ #self.resolM = getit(obj, 73, None) # resolution of surface in M direction
+ #self.resolN = getit(obj, 74, None) # resolution of surface in N direction
+ self.curvetyp = getit(obj, 75, 0) # type of curve/surface: 0=None/5=Quadric/6=Cubic/8=Bezier
+ self.curvNormal = False
+ self.curvQBspline = False
+ self.curvCBspline = False
+ self.curvBezier = False
+ if self.curvetyp == 0: self.curvNormal = True
+ elif self.curvetyp == 5: self.curvQBspline = True
+ elif self.curvetyp == 6: self.curvCBspline = True
+ elif self.curvetyp == 8: self.curvBezier = True
+
+ self.layer = getit(obj.data, 8, None)
+ self.extrusion = get_extrusion(obj.data)
+
+ self.points = [] #list with vertices coordinats
+ self.faces = [] #list with vertices assigment to faces
+ #print 'deb:polyline.init.ENDinit:----------------' #------------
+
+
+
+ def __repr__(self):
+ return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
+
+
+
+ def draw(self, settings): #-------------%%%% DRAW POLYLINE %%%---------------
+ """for POLYLINE: generate Blender_geometry.
+ """
+ ob = []
+ #---- 3dPolyFace - mesh with free topology
+ if self.plface and settings.drawTypes['plmesh']:
+ ob = self.drawPlFace(settings)
+ #---- 3dPolyMesh - mesh with ortogonal topology
+ elif self.plmesh and settings.drawTypes['plmesh']:
+ ob = self.drawPlMesh(settings)
+ #---- 2dPolyline - plane polyline with arc/wide/thic segments
+ elif (self.poly2d and settings.drawTypes['polyline']):
+ if settings.var['plines_as'] == 5: # and self.spline:
+ ob = self.drawPolyCurve(settings)
+ else:
+ ob = self.drawPoly2d(settings)
+ #---- 3dPolyline - non-plane polyline (thin segments = without arc/wide/thic)
+ elif (self.poly3d and settings.drawTypes['pline3']):
+ if settings.var['plines3_as'] == 5: # and self.spline:
+ ob = self.drawPolyCurve(settings)
+ else:
+ ob = self.drawPoly2d(settings)
+ return ob
+
+
+
+ def drawPlFace(self, settings): #---- 3dPolyFace - mesh with free topology
+ """Generate the geometery of polyface.
+ """
+ #print 'deb:drawPlFace.START:----------------' #------------------------
+ points = []
+ faces = []
+ #print 'deb:len of pointsList ====== ', len(self.points) #------------------------
+ for point in self.points:
+ if point.face:
+ faces.append(point.face)
+ else:
+ points.append(point.loc)
+
+
+ #print 'deb:drawPlFace: len of points_list:\n', len(points) #-----------------------
+ #print 'deb:drawPlFace: len of faces_list:\n', len(faces) #-----------------------
+ #print 'deb:drawPlFace: points_list:\n', points #-----------------------
+ #print 'deb:drawPlFace: faces_list:\n', faces #-----------------------
+ obname = 'pf_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend(points) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+ #print 'deb:drawPlFace: len of me.faces:\n', len(me.faces) #-----------------------
+
+ if settings.var['meshSmooth_on']: # ----------------------
+ for i in xrange(len(me.faces)):
+ me.faces[i].smooth = True
+ #me.Mode(AUTOSMOOTH)
+ transform(self.extrusion, 0, ob)
+ #print 'deb:drawPlFace.END:----------------' #------------------------
+ return ob
+
+
+
+ def drawPlMesh(self, settings): #---- 3dPolyMesh - mesh with orthogonal topology
+ """Generate the geometery of polymesh.
+ """
+ #print 'deb:polymesh.draw.START:----------------' #------------------------
+ #points = []
+ #print 'deb:len of pointsList ====== ', len(self.points) #------------------------
+ faces = []
+ m = self.vectorsM
+ n = self.vectorsN
+ for j in xrange(m - 1):
+ for i in xrange(n - 1):
+ nn = j * n
+ faces.append([nn+i, nn+i+1, nn+n+i+1, nn+n+i])
+
+ if self.closed: #mesh closed in N-direction
+ nn = (m-1)*n
+ for i in xrange(n - 1):
+ faces.append([nn+i, nn+i+1, i+1, i])
+
+ if self.closeN: #mesh closed in M-direction
+ for j in xrange(m-1):
+ nn = j * n
+ faces.append([nn+n-1, nn, nn+n, nn+n-1+n])
+
+ if self.closed and self.closeN: #mesh closed in M/N-direction
+ faces.append([ (n*m)-1, (m-1)*n, 0, n-1])
+
+ #print 'deb:len of points_list:\n', len(points) #-----------------------
+ #print 'deb:faces_list:\n', faces #-----------------------
+ obname = 'pm_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend([point.loc for point in self.points]) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+ if settings.var['meshSmooth_on']: # ----------------------
+ for i in xrange(len(faces)):
+ me.faces[i].smooth = True
+ #me.Mode(AUTOSMOOTH)
+
+ transform(self.extrusion, 0, ob)
+ #print 'deb:polymesh.draw.END:----------------' #------------------------
+ return ob
+
+
+ def drawPolyCurve(self, settings): #---- Polyline - draw as Blender-curve
+ """Generate the geometery of polyline as Blender-curve.
+ """
+ #print 'deb:polyline2dCurve.draw.START:----------------' #---
+ if len(self.points) < 2:
+ #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #---------
+ return
+
+ if self.spline: pline_typ = 'ps' # Polyline-nurbSpline
+ elif self.curved: pline_typ = 'pc' # Polyline-bezierCurve
+ else: pline_typ = 'pl' # Polyline
+ obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ d_points = []
+
+ if settings.var['Z_force_on']:
+ self.elevation = settings.var['Z_elev']
+ for point in self.points:
+ point.loc[2] = self.elevation
+ d_points.append(point)
+ else: #for DXFr10-format: update all points[].loc[2] == None -> 0.0
+ for point in self.points:
+ if point.loc[2] == None:
+ point.loc[2] = self.elevation
+ d_points.append(point)
+
+ thic = set_thick(self.thic, settings)
+ if thic != 0.0: #hack: Blender<2.45 curve-extrusion
+ LocZ = d_points[0].loc[2]
+ temp_points = []
+ for point in d_points:
+ point.loc[2] = 0.0
+ temp_points.append(point)
+ d_points = temp_points
+
+ #print 'deb:polyline2dCurve.draw d_points=', d_points #---------------
+ pline = Curve.New(obname) # create new curve data
+ #pline.setResolu(24) #--todo-----
+
+ if False: #self.spline: # NURBSplines-----FAKE(with Bezier)-----
+ #print 'deb:polyline2dCurve.draw self.spline!' #---------------
+ curve = pline.appendNurb(BezTriple.New(d_points[0]))
+ for p in d_points[1:]:
+ curve.append(BezTriple.New(p))
+ for point in curve:
+ point.handleTypes = [AUTO, AUTO]
+ if self.closed:
+ curve.flagU = 1 # Set curve cyclic=close
+ else:
+ curve.flagU = 0 # Set curve not cyclic=open
+ curve[0].handleTypes = [FREE, ALIGN] #remi--todo-----
+ curve[-1].handleTypes = [ALIGN, FREE] #remi--todo-----
+
+ elif self.spline: # NURBSplines-----OK-----
+ #print 'deb:polyline2dCurve.draw self.spline!' #---------------
+ weight1 = 0.5
+ weight2 = 1.0
+ # generate middlepoints except start/end-segments ---
+ if self.curvQBspline:
+ temp_points = []
+ point = d_points[0].loc
+ point.append(weight1)
+ temp_points.append(point)
+ for i in xrange(1,len(d_points)-2):
+ point1 = d_points[i].loc
+ point2 = d_points[i+1].loc
+ mpoint = list((Mathutils.Vector(point1) + Mathutils.Vector(point2)) * 0.5)
+ mpoint.append(weight2)
+ point1.append(weight1)
+ temp_points.append(point1)
+ temp_points.append(mpoint)
+ point2.append(weight1)
+ temp_points.append(point2)
+ point = d_points[-1].loc
+ point.append(weight1)
+ temp_points.append(point)
+ d_points = temp_points
+ else:
+ temp_points = []
+ for d in d_points:
+ d = d.loc
+ d.append(weight1)
+ temp_points.append(d)
+ d_points = temp_points
+
+ if not self.closed:
+ # generate extended startpoint and endpoint------
+ point1 = Mathutils.Vector(d_points[0][:3])
+ point2 = Mathutils.Vector(d_points[1][:3])
+ startpoint = list(point1 - point2 + point1)
+ startpoint.append(weight1)
+ point1 = Mathutils.Vector(d_points[-1][:3])
+ point2 = Mathutils.Vector(d_points[-2][:3])
+ endpoint = list(point1 - point2 + point1)
+ endpoint.append(weight1)
+ temp_points = []
+ temp_points.append(startpoint)
+ temp_points.extend(d_points)
+ d_points = temp_points
+ d_points.append(endpoint)
+
+ point = d_points[0]
+ curve = pline.appendNurb(point)
+ curve.setType(4) #NURBS curve
+ for point in d_points[1:]:
+ curve.append(point)
+ if self.closed:
+ curve.flagU = 1 # Set curve cyclic=close
+ else:
+ curve.flagU = 0 # Set curve not cyclic=open
+
+ elif self.curved: #--Bezier-curves---OK-------
+ #print 'deb:polyline2dCurve.draw self.curved!' #---------------
+ curve = pline.appendNurb(BezTriple.New(d_points[0]))
+ for p in d_points[1:]:
+ curve.append(BezTriple.New(p))
+ for point in curve:
+ point.handleTypes = [AUTO, AUTO]
+ if self.closed:
+ curve.flagU = 1 # Set curve cyclic=close
+ else:
+ curve.flagU = 0 # Set curve not cyclic=open
+ curve[0].handleTypes = [FREE, ALIGN] #remi--todo-----
+ curve[-1].handleTypes = [ALIGN, FREE] #remi--todo-----
+
+ else: #--straight line- and arc-segments----OK------
+ #print 'deb:polyline2dCurve.draw curve:', curve #-----
+ points = []
+ arc_res = settings.var['curve_arc']
+ prevHandleType = VECT
+ #d_points.append(d_points[0]) #------ first vertex added at the end of list --------
+ #curve.setType(0) #polygon_type of Blender_curve
+ for i in xrange(len(d_points)):
+ point1 = d_points[i]
+ #point2 = d_points[i+1]
+ if False: #-----outdated!- standard calculation ----------------------------------
+ if point1.bulge and (i < len(d_points)-2 or self.closed):
+ verts, center = calcBulge(point1, point2, arc_res, triples=False)
+ if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0]))
+ else: curve.append(BezTriple.New(verts[0]))
+ curve[-1].handleTypes = [VECT, VECT] #--todo--calculation of bezier-tangents
+ for p in verts[1:]:
+ curve.append(BezTriple.New(p))
+ curve[-1].handleTypes = [AUTO, AUTO]
+ else:
+ if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc))
+ else: curve.append(BezTriple.New(point1.loc))
+ curve[-1].handleTypes = [VECT, VECT] #--todo--calculation of bezier-tangents
+
+ elif True: #----- optimised Bezier-Handles calculation --------------------------------
+ #print 'deb:drawPlineCurve: i:', i #---------
+ if point1.bulge and not (i == len(d_points)-1 and point1.bulge and not self.closed):
+ if i == len(d_points)-1: point2 = d_points[0]
+ else: point2 = d_points[i+1]
+
+
+ # calculate additional points for bulge
+ VectorTriples = calcBulge(point1, point2, arc_res, triples=True)
+
+ if prevHandleType == FREE:
+ #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #---------
+ VectorTriples[0][:3] = prevHandleVect
+ #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #---------
+
+ if i == 0: curve = pline.appendNurb(BezTriple.New(VectorTriples[0]))
+ else: curve.append(BezTriple.New(VectorTriples[0]))
+ curve[-1].handleTypes = [prevHandleType, FREE]
+
+ for p in VectorTriples[1:-1]:
+ curve.append(BezTriple.New(p))
+ curve[-1].handleTypes = [FREE, FREE]
+
+ prevHandleVect = VectorTriples[-1][:3]
+ prevHandleType = FREE
+ #print 'deb:drawPlineCurve: prevHandleVect:', prevHandleVect #---------
+ else:
+ #print 'deb:drawPlineCurve: else' #----------
+ if prevHandleType == FREE:
+ VectorTriples = prevHandleVect + list(point1) + list(point1)
+ #print 'deb:drawPlineCurve: VectorTriples:', VectorTriples #---------
+ curve.append(BezTriple.New(VectorTriples))
+ curve[-1].handleTypes = [FREE, VECT]
+ prevHandleType = VECT
+ else:
+ if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc))
+ else: curve.append(BezTriple.New(point1.loc))
+ curve[-1].handleTypes = [VECT, VECT]
+
+
+
+ #print 'deb:drawPlineCurve: curve[-1].vec[0]', curve[-1].vec[0] #----------
+
+ if self.closed:
+ curve.flagU = 1 # Set curve cyclic=close
+ if prevHandleType == FREE:
+ #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #----------
+ #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #----------
+ prevHandleType2 = curve[0].handleTypes[1]
+ p0h1,p0,p0h2 = curve[0].vec
+ #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #----------
+ p0h1 = prevHandleVect
+ #p0h1 = [0,0,0]
+ #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #----------
+ #curve[0].vec = [p0h1,p0,p0h2]
+ curve.__setitem__(0,BezTriple.New(p0h1+p0+p0h2))
+
+ curve[0].handleTypes = [FREE,prevHandleType2]
+ #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #----------
+ #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #----------
+ else:
+ curve[0].handleTypes[0] = VECT
+ else:
+ curve.flagU = 0 # Set curve not cyclic=open
+
+ if settings.var['fill_on']:
+ pline.setFlag(6) # 2+4 set top and button caps
+ else:
+ pline.setFlag(pline.getFlag() & ~6) # dont set top and button caps
+
+ pline.setResolu(settings.var['curve_res'])
+ pline.update()
+ ob = SCENE.objects.new(pline) # create a new curve_object
+
+ if thic != 0.0: #hack: Blender<2.45 curve-extrusion
+ thic = thic * 0.5
+ pline.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0)
+ ob.LocZ = thic + LocZ
+
+ transform(self.extrusion, 0, ob)
+ if thic != 0.0:
+ ob.SizeZ *= abs(thic)
+
+ #print 'deb:polyline2dCurve.draw.END:----------------' #-----
+ return ob
+
+
+ def drawPoly2d(self, settings): #---- 2dPolyline - plane lines/arcs with wide/thic
+ """Generate the geometery of regular polyline.
+ """
+ #print 'deb:polyline2d.draw.START:----------------' #------------------------
+ points = []
+ d_points = []
+ swidths = []
+ ewidths = []
+ swidth_default = self.swidth #default start width of POLYLINEs segments
+ ewidth_default = self.ewidth #default end width of POLYLINEs segments
+ thic = set_thick(self.thic, settings)
+ if self.spline: pline_typ = 'ps'
+ elif self.curved: pline_typ = 'pc'
+ else: pline_typ = 'pl'
+ obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+
+ if len(self.points) < 2:
+ #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #---------
+ return
+
+ if settings.var['Z_force_on']:
+ self.elevation = settings.var['Z_elev']
+ for point in self.points:
+ point.loc[2] = self.elevation
+ d_points.append(point)
+ else: #for DXFr10-format: update all non-existing LocZ points[].loc[2] == None -> 0.0 elevation
+ for point in self.points:
+ if point.loc[2] == None:
+ point.loc[2] = self.elevation
+ d_points.append(point)
+ #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------
+ #print 'deb:drawPoly2d d_pointsList ======:\n ', d_points #------------------------
+
+
+ #if closed polyline, add duplic of the first vertex at the end of pointslist
+ if self.closed: #new_b8
+ if d_points[-1].loc != d_points[0].loc: # if not equal, then set the first at the end of pointslist
+ d_points.append(d_points[0])
+ else:
+ if d_points[-1].loc == d_points[0].loc: # if equal, then set to closed, and modify the last point
+ d_points[-1] = d_points[0]
+ self.closed = True
+ #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------
+ #print 'deb:drawPoly2d d_pointsList ======:\n ', d_points #------------------------
+
+
+ # routine to sort out of "double.vertices" ------------------------------------
+ minimal_dist = settings.var['dist_min'] * 0.1
+ temp_points = []
+ for i in xrange(len(d_points)-1):
+ point = d_points[i]
+ point2 = d_points[i+1]
+ #print 'deb:double.vertex p1,p2', point, point2 #------------------------
+ delta = Mathutils.Vector(point2.loc) - Mathutils.Vector(point.loc)
+ if delta.length > minimal_dist:
+ temp_points.append(point)
+ #else: print 'deb:drawPoly2d double.vertex sort out!' #------------------------
+ temp_points.append(d_points[-1]) #------ incl. last vertex -------------
+ #if self.closed: temp_points.append(d_points[1]) #------ loop start vertex -------------
+ d_points = temp_points #-----vertex.list without "double.vertices"
+ #print 'deb:drawPoly2d d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------
+
+ #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------
+ if len(d_points) < 2: #if too few vertex, then return
+ #print 'deb:drawPoly2d corrupted Vertices' #---------
+ return
+
+ # analyze of straight- and bulge-segments
+ # generation of additional points for bulge segments
+ arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad'])
+ wide_segment_exist = False
+ bulg_points = [] # for each point set None (or center for arc-subPoints)
+ for i in xrange(len(d_points)-1):
+ point1 = d_points[i]
+ point2 = d_points[i+1]
+ #print 'deb:drawPoly2d_bulg tocalc.point1:', point1 #------------------------
+ #print 'deb:drawPoly2d_bulg tocalc.point2:', point2 #------------------------
+
+ swidth = point1.swidth
+ ewidth = point1.ewidth
+ if swidth == None: swidth = swidth_default
+ if ewidth == None: ewidth = ewidth_default
+ if swidth != 0.0 or ewidth != 0.0: wide_segment_exist = True
+
+ if settings.var['width_force']: # force minimal width for thin segments
+ width_min = settings.var['width_min']
+ if swidth < width_min: swidth = width_min
+ if ewidth < width_min: ewidth = width_min
+ if not settings.var['width_on']: # then force minimal width for all segments
+ swidth = width_min
+ ewidth = width_min
+
+ #if point1.bulge and (i < (len(d_points)-1) or self.closed):
+ if point1.bulge and i < (len(d_points)-1): #10_b8
+ verts, center = calcBulge(point1, point2, arc_res) #calculate additional points for bulge
+ points.extend(verts)
+ delta_width = (ewidth - swidth) / len(verts)
+ width_list = [swidth + (delta_width * ii) for ii in xrange(len(verts)+1)]
+ swidths.extend(width_list[:-1])
+ ewidths.extend(width_list[1:])
+ bulg_list = [center for ii in xrange(len(verts))]
+ #the last point in bulge has index False for better indexing of bulg_end!
+ bulg_list[-1] = None
+ bulg_points.extend(bulg_list)
+
+ else:
+ points.append(point1.loc)
+ swidths.append(swidth)
+ ewidths.append(ewidth)
+ bulg_points.append(None)
+ points.append(d_points[-1].loc)
+
+
+ #--calculate width_vectors: left-side- and right-side-points ----------------
+ # 1.level:IF width ---------------------------------------
+ if (settings.var['width_on'] and wide_segment_exist) or settings.var['width_force']:
+ #new_b8 points.append(d_points[0].loc) #temporarly add first vertex at the end (for better loop)
+ dist_min05 = 0.5 * settings.var['dist_min'] #minimal width for zero_witdh
+
+ pointsLs = [] # list of left-start-points
+ pointsLe = [] # list of left-end-points
+ pointsRs = [] # list of right-start-points
+ pointsRe = [] # list of right-end-points
+ pointsW = [] # list of all border-points
+ #rotMatr90 = Mathutils.Matrix(rotate 90 degree around Z-axis) = normalvectorXY
+ rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1])
+ bulg_in = False
+ last_bulg_point = False
+ for i in xrange(len(points)-1):
+ point1 = points[i]
+ point2 = points[i+1]
+ point1vec = Mathutils.Vector(point1)
+ point2vec = Mathutils.Vector(point2)
+ swidth05 = swidths[i] * 0.5
+ ewidth05 = ewidths[i] * 0.5
+ if swidth05 == 0: swidth05 = dist_min05
+ if ewidth05 == 0: ewidth05 = dist_min05
+ normal_vector = rotMatr90 * (point2vec-point1vec).normalize()
+ if last_bulg_point:
+ last_bulg_point = False
+ bulg_in = True
+ elif bulg_points[i] != None:
+ centerVec = Mathutils.Vector(bulg_points[i])
+ if bulg_points[i+1] == None: last_bulg_point = True
+ bulg_in = True
+ else: bulg_in = False
+
+ if bulg_in:
+ #makes clean intersections for arc-segments
+ radius1vec = point1vec - centerVec
+ radius2vec = point2vec - centerVec
+ angle = Mathutils.AngleBetweenVecs(normal_vector, radius1vec)
+ if angle < 90.0:
+ normal_vector1 = radius1vec.normalize()
+ normal_vector2 = radius2vec.normalize()
+ else:
+ normal_vector1 = - radius1vec.normalize()
+ normal_vector2 = - radius2vec.normalize()
+
+ swidth05vec = swidth05 * normal_vector1
+ ewidth05vec = ewidth05 * normal_vector2
+ pointsLs.append(point1vec + swidth05vec) #vertex left start
+ pointsRs.append(point1vec - swidth05vec) #vertex right start
+ pointsLe.append(point2vec + ewidth05vec) #vertex left end
+ pointsRe.append(point2vec - ewidth05vec) #vertex right end
+
+ else:
+ swidth05vec = swidth05 * normal_vector
+ ewidth05vec = ewidth05 * normal_vector
+ pointsLs.append(point1vec + swidth05vec) #vertex left start
+ pointsRs.append(point1vec - swidth05vec) #vertex right start
+ pointsLe.append(point2vec + ewidth05vec) #vertex left end
+ pointsRe.append(point2vec - ewidth05vec) #vertex right end
+
+ # additional last point is also calculated
+ #pointsLs.append(pointsLs[0])
+ #pointsRs.append(pointsRs[0])
+ #pointsLe.append(pointsLe[0])
+ #pointsRe.append(pointsRe[0])
+
+ pointsLc, pointsRc = [], [] # lists Left/Right corners = intersection points
+
+ # 2.level:IF width and corner-trim
+ if settings.var['pl_trim_on']: #optional clean corner-intersections
+ # loop preset
+ # set STARTpoints of the first point points[0]
+ if not self.closed:
+ pointsLc.append(pointsLs[0])
+ pointsRc.append(pointsRs[0])
+ else:
+ pointsLs.append(pointsLs[0])
+ pointsRs.append(pointsRs[0])
+ pointsLe.append(pointsLe[0])
+ pointsRe.append(pointsRe[0])
+ points.append(points[0])
+ vecL3, vecL4 = pointsLs[0], pointsLe[0]
+ vecR3, vecR4 = pointsRs[0], pointsRe[0]
+ lenL = len(pointsLs)-1
+ #print 'deb:drawPoly2d pointsLs():\n', pointsLs #----------------
+ #print 'deb:drawPoly2d lenL, len.pointsLs():', lenL,',', len(pointsLs) #----------------
+ bulg_in = False
+ last_bulg_point = False
+
+ # LOOP: makes (ENDpoints[i],STARTpoints[i+1])
+ for i in xrange(lenL):
+ if bulg_points[i] != None:
+ if bulg_points[i+1] == None: #makes clean intersections for arc-segments
+ last_bulg_point = True
+ if not bulg_in:
+ bulg_in = True
+ #pointsLc.extend((points[i], pointsLs[i]))
+ #pointsRc.extend((points[i], pointsRs[i]))
+ vecL1, vecL2 = vecL3, vecL4
+ vecR1, vecR2 = vecR3, vecR4
+ vecL3, vecL4 = pointsLs[i+1], pointsLe[i+1]
+ vecR3, vecR4 = pointsRs[i+1], pointsRe[i+1]
+ #compute left- and right-cornerpoints
+ #cornerpointL = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4)
+ cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4)
+ cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4)
+ #print 'deb:drawPoly2d cornerpointL: ', cornerpointL #-------------
+ #print 'deb:drawPoly2d cornerpointR: ', cornerpointR #-------------
+
+ # IF not cornerpoint THEN check if identic start-endpoints (=collinear segments)
+ if cornerpointL == None or cornerpointR == None:
+ if vecL2 == vecL3 and vecR2 == vecR3:
+ #print 'deb:drawPoly2d pointVec: ####### identic ##########' #----------------
+ pointsLc.append(pointsLe[i])
+ pointsRc.append(pointsRe[i])
+ else:
+ pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1]))
+ pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1]))
+ else:
+ cornerpointL = cornerpointL[0] # because Mathutils.LineIntersect() -> (pkt1,pkt2)
+ cornerpointR = cornerpointR[0]
+ #print 'deb:drawPoly2d cornerpointL: ', cornerpointL #-------------
+ #print 'deb:drawPoly2d cornerpointR: ', cornerpointR #-------------
+ pointVec0 = Mathutils.Vector(points[i])
+ pointVec = Mathutils.Vector(points[i+1])
+ pointVec2 = Mathutils.Vector(points[i+2])
+ #print 'deb:drawPoly2d pointVec0: ', pointVec0 #-------------
+ #print 'deb:drawPoly2d pointVec: ', pointVec #-------------
+ #print 'deb:drawPoly2d pointVec2: ', pointVec2 #-------------
+ # if diststance(cornerL-center-cornerR) < limiter * (seg1_endWidth + seg2_startWidth)
+ max_cornerDist = (vecL2 - vecR2).length + (vecL3 - vecR3).length
+ is_cornerDist = (cornerpointL - pointVec).length + (cornerpointR - pointVec).length
+ #corner_angle = Mathutils.AngleBetweenVecs((pointVec0 - pointVec),(pointVec - pointVec2))
+ #print 'deb:drawPoly2d corner_angle: ', corner_angle #-------------
+ #print 'deb:drawPoly2d max_cornerDist, is_cornerDist: ', max_cornerDist, is_cornerDist #-------------
+ #if abs(corner_angle) < 90.0:
+ # intersection --------- limited by TRIM_LIMIT (1.0 - 5.0)
+ if is_cornerDist < max_cornerDist * settings.var['pl_trim_max']:
+ # clean corner intersection
+ pointsLc.append(cornerpointL)
+ pointsRc.append(cornerpointR)
+ elif False: # the standard no-intersection
+ # --todo-- not optimal, because produces X-face
+ pointsLc.extend((pointsLe[i],pointsLs[i+1]))
+ pointsRc.extend((pointsRe[i],pointsRs[i+1]))
+ elif False: # --todo-- the optimised non-intersection
+ if (cornerpointL - vecL1).length < (cornerpointR - vecR1).length:
+ left_angle = True
+ else:
+ left_angle = False
+ limit_dist = settings.var['dist_min']
+ if left_angle: # if left turning angle
+ print 'deb:drawPoly2d it is left turning angle' #-------------
+ # to avoid triangelface/doubleVertex
+ delta1 = (cornerpointL - vecL1).normalize() * limit_dist
+ delta4 = (cornerpointL - vecL4).normalize() * limit_dist
+ pointsLc.extend((cornerpointL - delta1, cornerpointL - delta4))
+ pointsRc.extend((pointsRe[i],pointsRs[i+1]))
+ else: # if right turning angle
+ print 'deb:drawPoly2d right turning angle' #-------------
+ delta1 = (cornerpointR - vecR1).normalize() * limit_dist
+ delta4 = (cornerpointR - vecR4).normalize() * limit_dist
+ pointsRc.extend((cornerpointR - delta1, cornerpointR - delta4))
+ pointsLc.extend((pointsLe[i],pointsLs[i+1]))
+ else:
+ pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1]))
+ pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1]))
+ if not self.closed:
+ pointsLc.append(pointsLe[-1])
+ pointsRc.append(pointsRe[-1])
+
+ # 2.level:IF width but no-trim
+ else:
+ # loop preset
+ # set STARTpoints of the first point points[0]
+ if not self.closed:
+ pointsLc.append(pointsLs[0])
+ pointsRc.append(pointsRs[0])
+ else:
+ pointsLs.append(pointsLs[0])
+ pointsRs.append(pointsRs[0])
+ pointsLe.append(pointsLe[0])
+ pointsRe.append(pointsRe[0])
+ points.append(points[0])
+ vecL3, vecL4 = pointsLs[0], pointsLe[0]
+ vecR3, vecR4 = pointsRs[0], pointsRe[0]
+ lenL = len(pointsLs)-1
+ #print 'deb:drawPoly2d pointsLs():\n', pointsLs #----------------
+ #print 'deb:drawPoly2d lenL, len.pointsLs():', lenL,',', len(pointsLs) #----------------
+ bulg_in = False
+ last_bulg_point = False
+
+ # LOOP: makes (ENDpoints[i],STARTpoints[i+1])
+ for i in xrange(lenL):
+ vecL1, vecL2 = vecL3, vecL4
+ vecR1, vecR2 = vecR3, vecR4
+ vecL3, vecL4 = pointsLs[i+1], pointsLe[i+1]
+ vecR3, vecR4 = pointsRs[i+1], pointsRe[i+1]
+ if bulg_points[i] != None:
+ #compute left- and right-cornerpoints
+ if True:
+ cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4)
+ cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4)
+ pointsLc.append(cornerpointL[0])
+ pointsRc.append(cornerpointR[0])
+ else:
+ pointVec = Mathutils.Vector(point[i])
+
+ else: # IF non-bulg
+ pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1]))
+ pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1]))
+ if not self.closed:
+ pointsLc.append(pointsLe[-1])
+ pointsRc.append(pointsRe[-1])
+
+ len1 = len(pointsLc)
+ #print 'deb:drawPoly2d len1:', len1 #-----------------------
+ #print 'deb:drawPoly2d len1 len(pointsLc),len(pointsRc):', len(pointsLc),len(pointsRc) #-----------------------
+ pointsW = pointsLc + pointsRc # all_points_List = left_side + right_side
+ #print 'deb:drawPoly2d pointsW():\n', pointsW #----------------
+
+ # 2.level:IF width and thickness ---------------------
+ if thic != 0:
+ thic_pointsW = []
+ thic_pointsW.extend([[point[0], point[1], point[2]+thic] for point in pointsW])
+ if thic < 0.0:
+ thic_pointsW.extend(pointsW)
+ pointsW = thic_pointsW
+ else:
+ pointsW.extend(thic_pointsW)
+ faces = []
+ f_start, f_end = [], []
+ f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)]
+ f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)]
+ f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)]
+ f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)]
+
+ if self.closed:
+ f_bottom.append([len1-1, 0, len1, len1+len1-1]) #bottom face
+ f_top.append( [len1+len1+len1-1, len1+len1+len1+len1-1, len1+len1+len1, len1+len1+0]) #top face
+ f_left.append( [0, len1-1, len1+len1+len1-1, len1+len1]) #left face
+ f_right.append( [len1, len1+len1+len1, len1+len1+len1+len1-1, len1+len1-1]) #right face
+ else:
+ f_start = [[0, len1, len1+len1+len1, len1+len1]]
+ f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]]
+
+ faces = f_left + f_right + f_bottom + f_top + f_start + f_end
+ #faces = f_bottom + f_top
+ #faces = f_left + f_right + f_start + f_end
+ #print 'deb:faces_list:\n', faces #-----------------------
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend(pointsW) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ # The mesh must first be linked to an object so the method knows which object to update.
+ # This is because vertex groups in Blender are stored in the object -- not in the mesh,
+ # which may be linked to more than one object.
+ if settings.var['vGroup_on']:
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD
+ vg_left, vg_right, vg_top, vg_bottom = [], [], [], []
+ for v in f_left: vg_left.extend(v)
+ for v in f_right: vg_right.extend(v)
+ for v in f_top: vg_top.extend(v)
+ for v in f_bottom: vg_bottom.extend(v)
+ me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace)
+ me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace)
+ me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace)
+ me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace)
+ if not self.closed:
+ me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace)
+ me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace)
+
+ if settings.var['meshSmooth_on']: # left and right side become smooth ----------------------
+ #if self.spline or self.curved:
+ if True:
+ smooth_len = len(f_left) + len(f_right)
+ for i in xrange(smooth_len):
+ me.faces[i].smooth = True
+ #me.Modes(AUTOSMOOTH)
+
+ # 2.level:IF width, but no-thickness ---------------------
+ else:
+ faces = []
+ faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)]
+ if self.closed:
+ faces.append([len1, 0, len1-1, len1+len1-1])
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend(pointsW) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+
+ # 1.level:IF no-width, but thickness ---------------------
+ elif thic != 0:
+ len1 = len(points)
+ thic_points = []
+ thic_points.extend([[point[0], point[1], point[2]+thic] for point in points])
+ if thic < 0.0:
+ thic_points.extend(points)
+ points = thic_points
+ else:
+ points.extend(thic_points)
+ faces = []
+ faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
+ if self.closed:
+ faces.append([len1-1, 0, len1, 2*len1-1])
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend(points) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+ if settings.var['meshSmooth_on']: # left and right side become smooth ----------------------
+ #if self.spline or self.curved:
+ if True:
+ for i in xrange(len(faces)):
+ me.faces[i].smooth = True
+ #me.Modes(AUTOSMOOTH)
+
+ # 1.level:IF no-width and no-thickness ---------------------
+ else:
+ edges = [[num, num+1] for num in xrange(len(points)-1)]
+ if self.closed:
+ edges.append([len(points)-1, 0])
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ me.verts.extend(points) # add vertices to mesh
+ me.edges.extend(edges) # add edges to the mesh
+
+ transform(self.extrusion, 0, ob)
+ #print 'deb:polyline.draw.END:----------------' #-----------------------
+ return ob
+
+
+
+
+class Vertex(object): #-----------------------------------------------------------------
+ """Generic vertex object used by POLYLINEs (and maybe others).
+ """
+
+ def __init__(self, obj=None):
+ """Initializes vertex data.
+
+ The optional obj arg is an entity object of type vertex.
+ """
+ #print 'deb:Vertex.init.START:----------------' #-----------------------
+ self.loc = [0,0,0]
+ self.face = []
+ self.swidth = 0
+ self.ewidth = 0
+ self.bulge = 0
+ if obj is not None:
+ if not obj.type == 'vertex':
+ raise TypeError, "Wrong type %s for vertex object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+ self.get_props(obj.data)
+ #print 'deb:Vertex.init.END:----------------' #------------------------
+
+
+ def get_props(self, data):
+ """Gets coords for a VERTEX type object.
+
+ Each vert can have a number of properties.
+ Verts should be coded as
+ 10:xvalue
+ 20:yvalue
+ 40:startwidth or 0
+ 41:endwidth or 0
+ 42:bulge or 0
+ """
+ self.x = getit(data, 10, None)
+ self.y = getit(data, 20, None)
+ self.z = getit(data, 30, None)
+
+ self.flags = getit(data, 70, 0) # flags
+ self.curved = self.flags&1 # Bezier-curve-fit:additional-vertex
+ self.curv_t = self.flags&2 # Bezier-curve-fit:tangent exists
+ self.spline = self.flags&8 # Bspline-fit:additional-vertex
+ self.splin2 = self.flags&16 # Bspline-fit:control-vertex
+ self.poly3d = self.flags&32 # polyline3d:control-vertex
+ self.plmesh = self.flags&64 # polymesh3d:control-vertex
+ self.plface = self.flags&128 # polyface
+
+ # if PolyFace.Vertex with Face_definition
+ if self.curv_t:
+ self.curv_tangent = getit(data, 50, None) # curve_tangent
+
+ if self.plface and not self.plmesh:
+ v1 = getit(data, 71, 0) # polyface:Face.vertex 1.
+ v2 = getit(data, 72, 0) # polyface:Face.vertex 2.
+ v3 = getit(data, 73, 0) # polyface:Face.vertex 3.
+ v4 = getit(data, 74, None) # polyface:Face.vertex 4.
+ self.face = [abs(v1)-1,abs(v2)-1,abs(v3)-1]
+ if v4 != None:
+ if abs(v4) != abs(v1):
+ self.face.append(abs(v4)-1)
+ else: #--parameter for polyline2d
+ self.swidth = getit(data, 40, None) # start width
+ self.ewidth = getit(data, 41, None) # end width
+ self.bulge = getit(data, 42, 0) # bulge of segment
+
+
+ def __len__(self):
+ return 3
+
+
+ def __getitem__(self, key):
+ return self.loc[key]
+
+
+ def __setitem__(self, key, value):
+ if key in [0,1,2]:
+ self.loc[key]
+
+
+ def __iter__(self):
+ return self.loc.__iter__()
+
+
+ def __str__(self):
+ return str(self.loc)
+
+
+ def __repr__(self):
+ return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s, face=%s" %(self.loc, self.swidth, self.ewidth, self.bulge, self.face)
+
+
+ def getx(self):
+ return self.loc[0]
+ def setx(self, value):
+ self.loc[0] = value
+ x = property(getx, setx)
+
+
+ def gety(self):
+ return self.loc[1]
+ def sety(self, value):
+ self.loc[1] = value
+ y = property(gety, sety)
+
+
+ def getz(self):
+ return self.loc[2]
+ def setz(self, value):
+ self.loc[2] = value
+ z = property(getz, setz)
+
+
+
+class Text: #-----------------------------------------------------------------
+ """Class for objects representing dxf TEXT.
+ """
+ def __init__(self, obj):
+ """Expects an entity object of type text as input.
+ """
+ if not obj.type == 'text':
+ raise TypeError, "Wrong type %s for text object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # required data
+ self.height = 1.7 * obj.get_type(40)[0] #text.height
+ self.value = obj.get_type(1)[0] #The text string value
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+ self.thic = getit(obj, 39, 0)
+
+ self.rotation = getit(obj, 50, 0) # radians
+ self.width_factor = getit(obj, 41, 1) # Scaling factor along local x axis
+ self.oblique = getit(obj, 51, 0) # oblique angle: skew in degrees -90 <= oblique <= 90
+
+ #self.style = getit(obj, 7, 'STANDARD') # --todo---- Text style name (optional, default = STANDARD)
+
+ #Text generation flags (optional, default = 0):
+ #2 = backward (mirrored in X),
+ #4 = upside down (mirrored in Y)
+ self.flags = getit(obj, 71, 0)
+ self.mirrorX, self.mirrorY = 1.0, 1.0
+ if self.flags&2: self.mirrorX = - 1.0
+ if self.flags&4: self.mirrorY = - 1.0
+
+ # vertical.alignment: 0=baseline, 1=bottom, 2=middle, 3=top
+ self.valignment = getit(obj, 73, 0)
+ #Horizontal text justification type (optional, default = 0) integer codes (not bit-coded)
+ #0=left, 1=center, 2=right
+ #3=aligned, 4=middle, 5=fit
+ self.halignment = getit(obj, 72, 0)
+
+ self.layer = getit(obj.data, 8, None)
+ self.loc1, self.loc2 = self.get_loc(obj.data)
+ if self.loc2[0] != None and self.halignment != 5:
+ self.loc = self.loc2
+ else:
+ self.loc = self.loc1
+ self.extrusion = get_extrusion(obj.data)
+
+
+
+ def get_loc(self, data):
+ """Gets adjusted location for text type objects.
+
+ If group 72 and/or 73 values are nonzero then the first alignment point values
+ are ignored and AutoCAD calculates new values based on the second alignment
+ point and the length and height of the text string itself (after applying the
+ text style). If the 72 and 73 values are zero or missing, then the second
+ alignment point is meaningless.
+ I don't know how to calc text size...
+ """
+ # bottom left x, y, z and justification x, y, z = 0
+ #x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0
+ x = getit(data, 10, None) #First alignment point (in OCS).
+ y = getit(data, 20, None)
+ z = getit(data, 30, 0.0)
+ jx = getit(data, 11, None) #Second alignment point (in OCS).
+ jy = getit(data, 21, None)
+ jz = getit(data, 31, 0.0)
+ return [x, y, z],[jx, jy, jz]
+
+
+ def __repr__(self):
+ return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)
+
+
+ def draw(self, settings):
+ """for TEXTs: generate Blender_geometry.
+ """
+ obname = 'tx_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ txt = Text3d.New(obname)
+ ob = SCENE.objects.new(txt) # create a new text_object
+
+ txt.setText(self.value)
+ txt.setSize(1.0) #Blender<2.45 accepts only (0.0 - 5.0)
+ #txt.setSize(self.height)
+ #txt.setWidth(self.bold)
+ #setLineSeparation(sep)
+ txt.setShear(self.oblique/90)
+
+ thic = set_thick(self.thic, settings)
+ if thic != 0.0:
+ thic = self.thic * 0.5
+ self.loc[2] += thic
+ txt.setExtrudeDepth(1.0) #Blender<2.45 accepts only (0.1 - 10.0)
+ if self.halignment == 0:
+ align = Text3d.LEFT
+ elif self.halignment == 1:
+ align = Text3d.MIDDLE
+ elif self.halignment == 2:
+ align = Text3d.RIGHT
+ else:
+ align = Text3d.LEFT
+ txt.setAlignment(align)
+
+ if self.valignment == 1:
+ txt.setYoffset(0.0)
+ elif self.valignment == 2:
+ txt.setYoffset(- self.height * 0.5)
+ elif self.valignment == 3:
+ txt.setYoffset(- self.height)
+
+ # move the object center to the text location
+ ob.loc = tuple(self.loc)
+ transform(self.extrusion, self.rotation, ob)
+
+ # flip it and scale it to the text width
+ ob.SizeX *= self.height * self.width_factor * self.mirrorX
+ ob.SizeY *= self.height * self.mirrorY
+ if thic != 0.0: ob.SizeZ *= abs(thic)
+ return ob
+
+
+
+def set_thick(thickness, settings):
+ """Set thickness relative to settings variables.
+
+ Set thickness relative to settings variables:
+ 'thick_on','thick_force','thick_min'.
+ Accepted also minus values of thickness
+ python trick: sign(x)=cmp(x,0)
+ """
+ if settings.var['thick_force']:
+ if settings.var['thick_on']:
+ if abs(thickness) < settings.var['thick_min']:
+ thic = settings.var['thick_min'] * cmp(thickness,0)
+ else: thic = thickness
+ else: thic = settings.var['thick_min']
+ else:
+ if settings.var['thick_on']: thic = thickness
+ else: thic = 0.0
+ return thic
+
+
+
+
+class Mtext: #-----------------------------------------------------------------
+ """Class for objects representing dxf MTEXT.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type mtext as input.
+ """
+ if not obj.type == 'mtext':
+ raise TypeError, "Wrong type %s for mtext object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # required data
+ self.height = obj.get_type(40)[0]
+ self.width = obj.get_type(41)[0]
+ self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR
+ self.value = self.get_text(obj.data) # The text string value
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+ self.rotation = getit(obj, 50, 0) # radians
+
+ self.width_factor = getit(obj, 42, 1) # Scaling factor along local x axis
+ self.line_space = getit(obj, 44, 1) # percentage of default
+
+ self.layer = getit(obj.data, 8, None)
+ self.loc = self.get_loc(obj.data)
+ self.extrusion = get_extrusion(obj.data)
+
+
+ def get_text(self, data):
+ """Reconstructs mtext data from dxf codes.
+ """
+ primary = ''
+ secondary = []
+ for item in data:
+ if item[0] == 1: # There should be only one primary...
+ primary = item[1]
+ elif item[0] == 3: # There may be any number of extra strings (in order)
+ secondary.append(item[1])
+ if not primary:
+ #raise ValueError, "Empty Mtext Object!"
+ string = "Empty Mtext Object!"
+ if not secondary:
+ string = primary.replace(r'\P', '\n')
+ else:
+ string = ''.join(secondary)+primary
+ string = string.replace(r'\P', '\n')
+ return string
+
+
+ def get_loc(self, data):
+ """Gets location for a mtext type objects.
+
+ Mtext objects have only one point indicating
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 10, None)
+ loc[1] = getit(data, 20, None)
+ loc[2] = getit(data, 30, 0.0)
+ return loc
+
+
+ def __repr__(self):
+ return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)
+
+
+ def draw(self, settings):
+ """for MTEXTs: generate Blender_geometry.
+ """
+ # Now Create an object
+ obname = 'tm_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ txt = Text3d.New(obname)
+ ob = SCENE.objects.new(txt) # create a new text_object
+
+ txt.setSize(1)
+ # Blender doesn't give access to its text object width currently
+ # only to the text3d's curve width...
+ #txt.setWidth(text.width/10)
+ txt.setLineSeparation(self.line_space)
+ txt.setExtrudeDepth(0.5)
+ txt.setText(self.value)
+
+ # scale it to the text size
+ ob.SizeX = self.height * self.width_factor
+ ob.SizeY = self.height
+ ob.SizeZ = self.height
+
+ # move the object center to the text location
+ ob.loc = tuple(self.loc)
+ transform(self.extrusion, self.rotation, ob)
+
+ return ob
+
+
+
+
+class Circle: #-----------------------------------------------------------------
+ """Class for objects representing dxf CIRCLEs.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type circle as input.
+ """
+ if not obj.type == 'circle':
+ raise TypeError, "Wrong type %s for circle object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # required data
+ self.radius = obj.get_type(40)[0]
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+ self.thic = getit(obj, 39, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.loc = self.get_loc(obj.data)
+ self.extrusion = get_extrusion(obj.data)
+
+
+
+ def get_loc(self, data):
+ """Gets the center location for circle type objects.
+
+ Circles have a single coord location.
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 10, None)
+ loc[1] = getit(data, 20, None)
+ loc[2] = getit(data, 30, 0.0)
+ return loc
+
+
+
+ def __repr__(self):
+ return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
+
+
+ def draw(self, settings):
+ """for CIRCLE: generate Blender_geometry.
+ """
+ obname = 'ci_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ radius = self.radius
+
+ thic = set_thick(self.thic, settings)
+ width = 0.0
+ if settings.var['lines_as'] == 4: # as thin_box
+ thic = settings.var['thick_min']
+ width = settings.var['width_min']
+ if settings.var['lines_as'] == 3: # as thin cylinder
+ cyl_rad = 0.5 * settings.var['width_min']
+
+ if settings.var['lines_as'] == 5: # draw CIRCLE as curve -------------
+ if True: # universal version
+ arc_res = settings.var['curve_arc']
+ #arc_res = 3
+ start, end = 0.0, 360.0
+ VectorTriples = calcArc(None, radius, start, end, arc_res, True)
+ c = Curve.New(obname) # create new curve data
+ curve = c.appendNurb(BezTriple.New(VectorTriples[0]))
+ for p in VectorTriples[1:-1]:
+ curve.append(BezTriple.New(p))
+ for point in curve:
+ point.handleTypes = [FREE, FREE]
+ else: # standard version
+ c = Curve.New(obname) # create new curve data
+ p1 = (0, -radius, 0)
+ p2 = (radius, 0, 0)
+ p3 = (0, radius, 0)
+ p4 = (-radius, 0, 0)
+
+ p1 = BezTriple.New(p1)
+ p2 = BezTriple.New(p2)
+ p3 = BezTriple.New(p3)
+ p4 = BezTriple.New(p4)
+
+ curve = c.appendNurb(p1)
+ curve.append(p2)
+ curve.append(p3)
+ curve.append(p4)
+ for point in curve:
+ point.handleTypes = [AUTO, AUTO]
+
+ curve.flagU = 1 # 1 sets the curve cyclic=closed
+ if settings.var['fill_on']:
+ c.setFlag(6) # 2+4 set top and button caps
+ else:
+ c.setFlag(c.getFlag() & ~6) # dont set top and button caps
+
+ c.setResolu(settings.var['curve_res'])
+ c.update()
+
+ #--todo-----to check---------------------------
+ ob = SCENE.objects.new(c) # create a new curve_object
+ ob.loc = tuple(self.loc)
+ if thic != 0.0: #hack: Blender<2.45 curve-extrusion
+ thic = thic * 0.5
+ c.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0)
+ ob.LocZ = thic + self.loc[2]
+ transform(self.extrusion, 0, ob)
+ if thic != 0.0:
+ ob.SizeZ *= abs(thic)
+ return ob
+
+ elif False: # create a new mesh_object with buildin_circle_primitive
+ verts_num = settings.var['arc_res'] * sqrt(radius / settings.var['arc_rad'])
+ if verts_num > 100: verts_num = 100 # Blender accepts only values [3:500]
+ if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500]
+ if thic != 0:
+ loc2 = thic * 0.5 #-----blenderAPI draw Cylinder with 2*thickness
+ self.loc[2] += loc2 #---new location for the basis of cylinder
+ #print 'deb:circleDraw:self.loc2:', self.loc #-----------------------
+ c = Mesh.Primitives.Cylinder(int(verts_num), radius*2, abs(thic))
+ else:
+ c = Mesh.Primitives.Circle(int(verts_num), radius*2)
+
+ #c.update()
+ ob = SCENE.objects.new(c, obname) # create a new circle_mesh_object
+ ob.loc = tuple(self.loc)
+ transform(self.extrusion, 0, ob)
+ return ob
+
+ else: # draw CIRCLE as mesh -----------------------------------------------
+ cir = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(cir) # create a new circle_object
+ # set a number of segments in entire circle
+ arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad'])
+ start, end = 0.0 , 360.0
+ verts = calcArc(None, radius, start, end, arc_res, False)
+ verts = verts[:-1] #list without last point/edge (cause by circle it is equal to the first point)
+ #print 'deb:circleDraw: verts:', verts #---------------
+
+ if thic != 0:
+ len1 = len(verts)
+ thic_verts = []
+ thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
+ if thic < 0.0:
+ thic_verts.extend(verts)
+ verts = thic_verts
+ else:
+ verts.extend(thic_verts)
+ faces = []
+ f_band = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
+ #f_band = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1)]
+ f_band.append([len1 - 1, 0, len1, len1 + len1 -1])
+ faces = f_band
+ smooth_len = len(f_band)
+ if settings.var['fill_on']:
+ if thic < 0.0:
+ verts.append([0,0,thic]) #center of top side
+ verts.append([0,0,0]) #center of bottom side
+ else:
+ verts.append([0,0,0]) #center of bottom side
+ verts.append([0,0,thic]) #center of top side
+ center1 = len(verts)-2
+ center2 = len(verts)-1
+ f_bottom = [[num+1, num, center1] for num in xrange(len1 - 1)]
+ f_bottom.append([0, len1 - 1, center1])
+ f_top = [[num+len1, num+1+len1, center2] for num in xrange(len1 - 1)]
+ f_top.append([len1-1+len1, 0+len1, center2])
+ #print 'deb:circleDraw:verts:', verts #---------------
+ faces = f_band + f_bottom + f_top
+ #print 'deb:circleDraw:faces:', faces #---------------
+ cir.verts.extend(verts) # add vertices to mesh
+ cir.faces.extend(faces) # add faces to the mesh
+
+ if settings.var['meshSmooth_on']: # left and right side become smooth ----------------------
+ for i in xrange(smooth_len):
+ cir.faces[i].smooth = True
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ if settings.var['vGroup_on']:
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD
+ vg_band, vg_top, vg_bottom = [], [], []
+ for v in f_band: vg_band.extend(v)
+ cir.addVertGroup('side.band') ; cir.assignVertsToGroup('side.band', list(set(vg_band)), 1.0, replace)
+ if settings.var['fill_on']:
+ for v in f_top: vg_top.extend(v)
+ for v in f_bottom: vg_bottom.extend(v)
+ cir.addVertGroup('side.top') ; cir.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace)
+ cir.addVertGroup('side.bottom'); cir.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace)
+
+ else: # if thic == 0
+ if settings.var['fill_on']:
+ len1 = len(verts)
+ verts.append([0,0,0]) #center of circle
+ center1 = len1
+ faces = []
+ faces.extend([[num, num+1, center1] for num in xrange(len1)])
+ faces.append([len1-1, 0, center1])
+ #print 'deb:circleDraw:verts:', verts #---------------
+ #print 'deb:circleDraw:faces:', faces #---------------
+ cir.verts.extend(verts) # add vertices to mesh
+ cir.faces.extend(faces) # add faces to the mesh
+ else:
+ cir.verts.extend(verts) # add vertices to mesh
+ edges = [[num, num+1] for num in xrange(len(verts))]
+ edges[-1][1] = 0 # it points the "new" last edge to the first vertex
+ cir.edges.extend(edges) # add edges to the mesh
+
+ ob.loc = tuple(self.loc)
+ transform(self.extrusion, 0, ob)
+ return ob
+
+
+
+
+class Arc: #-----------------------------------------------------------------
+ """Class for objects representing dxf ARCs.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type arc as input.
+ """
+ if not obj.type == 'arc':
+ raise TypeError, "Wrong type %s for arc object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # required data
+ self.radius = obj.get_type(40)[0]
+ self.start_angle = obj.get_type(50)[0]
+ self.end_angle = obj.get_type(51)[0]
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+ self.thic = getit(obj, 39, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.loc = self.get_loc(obj.data)
+ self.extrusion = get_extrusion(obj.data)
+ #print 'deb:Arc__init__: center, radius, start, end:\n', self.loc, self.radius, self.start_angle, self.end_angle #---------
+
+
+
+ def get_loc(self, data):
+ """Gets the center location for arc type objects.
+
+ Arcs have a single coord location.
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 10, None)
+ loc[1] = getit(data, 20, None)
+ loc[2] = getit(data, 30, 0.0)
+ return loc
+
+
+
+ def __repr__(self):
+ return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
+
+
+ def draw(self, settings):
+ """for ARC: generate Blender_geometry.
+ """
+ obname = 'ar_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+
+ center = self.loc
+ radius = self.radius
+ start = self.start_angle
+ end = self.end_angle
+ #print 'deb:calcArcPoints:\n center, radius, start, end:\n', center, radius, start, end #---------
+ thic = set_thick(self.thic, settings)
+ width = 0.0
+ if settings.var['lines_as'] == 4: # as thin_box
+ thic = settings.var['thick_min']
+ width = settings.var['width_min']
+ if settings.var['lines_as'] == 3: # as thin cylinder
+ cyl_rad = 0.5 * settings.var['width_min']
+
+ if settings.var['lines_as'] == 5: # draw ARC as curve -------------
+ arc_res = settings.var['curve_arc']
+ triples = True
+ VectorTriples = calcArc(None, radius, start, end, arc_res, triples)
+ arc = Curve.New(obname) # create new curve data
+ curve = arc.appendNurb(BezTriple.New(VectorTriples[0]))
+ for p in VectorTriples[1:]:
+ curve.append(BezTriple.New(p))
+ for point in curve:
+ point.handleTypes = [FREE, FREE]
+ curve.flagU = 0 # 0 sets the curve not cyclic=open
+ arc.setResolu(settings.var['curve_res'])
+
+ arc.update() #important for handles calculation
+
+ ob = SCENE.objects.new(arc) # create a new curve_object
+ ob.loc = tuple(self.loc)
+ if thic != 0.0: #hack: Blender<2.45 curve-extrusion
+ thic = thic * 0.5
+ arc.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0)
+ ob.LocZ = thic + self.loc[2]
+ transform(self.extrusion, 0, ob)
+ if thic != 0.0:
+ ob.SizeZ *= abs(thic)
+ return ob
+
+ else: # draw ARC as mesh --------------------
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ # set a number of segments in entire circle
+ arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad'])
+
+ verts = calcArc(None, radius, start, end, arc_res, False)
+ #verts = [list(point) for point in verts]
+ len1 = len(verts)
+ #print 'deb:len1:', len1 #-----------------------
+ if width != 0:
+ radius_out = radius + (0.5 * width)
+ radius_in = radius - (0.5 * width)
+ if radius_in <= 0.0:
+ radius_in = settings.var['dist_min']
+ #radius_in = 0.0
+ verts_in = []
+ verts_out = []
+ for point in verts:
+ pointVec = Mathutils.Vector(point)
+ pointVec = pointVec.normalize()
+ verts_in.append(list(radius_in * pointVec)) #vertex inside
+ verts_out.append(list(radius_out * pointVec)) #vertex outside
+ verts = verts_in + verts_out
+
+ #print 'deb:verts:', verts #---------------------
+ if thic != 0:
+ thic_verts = []
+ thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
+ if thic < 0.0:
+ thic_verts.extend(verts)
+ verts = thic_verts
+ else:
+ verts.extend(thic_verts)
+ f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)]
+ f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)]
+ f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)]
+ f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)]
+ f_start = [[0, len1, len1+len1+len1, len1+len1]]
+ f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]]
+ faces = f_left + f_right + f_bottom + f_top + f_start + f_end
+
+ me.verts.extend(verts) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+ if settings.var['meshSmooth_on']: # left and right side become smooth ----------------------
+ smooth_len = len(f_left) + len(f_right)
+ for i in xrange(smooth_len):
+ me.faces[i].smooth = True
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ if settings.var['vGroup_on']:
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD
+ vg_left, vg_right, vg_top, vg_bottom = [], [], [], []
+ for v in f_left: vg_left.extend(v)
+ for v in f_right: vg_right.extend(v)
+ for v in f_top: vg_top.extend(v)
+ for v in f_bottom: vg_bottom.extend(v)
+ me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace)
+ me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace)
+ me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace)
+ me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace)
+ me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace)
+ me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace)
+
+
+ else: # if thick=0 - draw only flat ring
+ faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)]
+ me.verts.extend(verts) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+ elif thic != 0:
+ thic_verts = []
+ thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
+ if thic < 0.0:
+ thic_verts.extend(verts)
+ verts = thic_verts
+ else:
+ verts.extend(thic_verts)
+ faces = []
+ #print 'deb:len1:', len1 #-----------------------
+ #print 'deb:verts:', verts #---------------------
+ faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
+
+ me.verts.extend(verts) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+ if settings.var['meshSmooth_on']: # left and right side become smooth ----------------------
+ for i in xrange(len(faces)):
+ me.faces[i].smooth = True
+
+ else:
+ edges = [[num, num+1] for num in xrange(len(verts)-1)]
+ me.verts.extend(verts) # add vertices to mesh
+ me.edges.extend(edges) # add edges to the mesh
+
+ #me.update()
+ #ob = SCENE.objects.new(me) # create a new arc_object
+ #ob.link(me)
+ ob.loc = tuple(center)
+ #ob.loc = Mathutils.Vector(ob.loc)
+ transform(self.extrusion, 0, ob)
+ #ob.size = (1,1,1)
+ return ob
+
+
+class BlockRecord: #-----------------------------------------------------------------
+ """Class for objects representing dxf block_records.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type block_record as input.
+ """
+ if not obj.type == 'block_record':
+ raise TypeError, "Wrong type %s for block_record object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # required data
+ self.name = getit(obj, 2, None)
+
+ # optional data (with defaults)
+ self.insertion_units = getit(obj, 70, None)
+ self.insert_units = getit(obj, 1070, None)
+ """code 1070 Einfügeeinheiten:
+ 0 = Keine Einheiten; 1 = Zoll; 2 = Fuß; 3 = Meilen; 4 = Millimeter;
+ 5 = Zentimeter; 6 = Meter; 7 = Kilometer; 8 = Mikrozoll;
+ 9 = Mils; 10 = Yard; 11 = Angstrom; 12 = Nanometer;
+ 13 = Mikrons; 14 = Dezimeter; 15 = Dekameter;
+ 16 = Hektometer; 17 = Gigameter; 18 = Astronomische Einheiten;
+ 19 = Lichtjahre; 20 = Parsecs
+ """
+
+
+ def __repr__(self):
+ return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units)
+
+
+
+
+class Block: #-----------------------------------------------------------------
+ """Class for objects representing dxf BLOCKs.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type block as input.
+ """
+ if not obj.type == 'block':
+ raise TypeError, "Wrong type %s for block object!" %obj.type
+
+ self.type = obj.type
+ self.name = obj.name
+ self.data = obj.data[:]
+
+ # required data
+ self.flags = getit(obj, 70, 0)
+ self.anonim = self.flags & 1 #anonymous block generated by hatching, associative dimensioning, other
+ self.atrib = self.flags & 2 # has attribute definitions
+ self.xref = self.flags & 4 # is an external reference (xref)
+ self.xref_lay = self.flags & 8 # is an xref overlay
+ self.dep_ext = self.flags & 16 # is externally dependent
+ self.dep_res = self.flags & 32 # resolved external reference
+ self.xref_ext = self.flags & 64 # is a referenced external reference xref
+ #--todo--- if self.flag > 4: self.xref = True
+
+ # optional data (with defaults)
+ self.path = getit(obj, 1, '') # Xref path name
+ self.discription = getit(obj, 4, '')
+
+ self.entities = dxfObject('block_contents') #creates empty entities_container for this block
+ self.entities.data = objectify([ent for ent in obj.data if type(ent) != list])
+
+ self.layer = getit(obj.data, 8, None)
+ self.loc = self.get_loc(obj.data)
+
+ #print 'deb:Block %s data:\n%s' %(self.name, self.data) #------------
+ #print 'deb:Block %s self.entities.data:\n%s' %(self.name, self.entities.data) #------------
+
+
+
+ def get_loc(self, data):
+ """Gets the insert point of the block.
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 10, 0.0) # 10 = x
+ loc[1] = getit(data, 20, 0.0) # 20 = y
+ loc[2] = getit(data, 30, 0.0) # 30 = z
+ return loc
+
+
+ def __repr__(self):
+ return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path)
+
+
+
+
+class Insert: #-----------------------------------------------------------------
+ """Class for objects representing dxf INSERTs.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type insert as input.
+ """
+ if not obj.type == 'insert':
+ raise TypeError, "Wrong type %s for insert object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+ #print 'deb:Insert_init_ self.data:\n', self.data #-----------
+
+ # required data
+ self.name = obj.get_type(2)[0]
+
+ # optional data (with defaults)
+ self.rotation = getit(obj, 50, 0)
+ self.space = getit(obj, 67, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.loc = self.get_loc(obj.data)
+ self.scale = self.get_scale(obj.data)
+ self.rows, self.columns = self.get_array(obj.data)
+ self.extrusion = get_extrusion(obj.data)
+
+ #self.flags = getit(obj.data, 66, 0) #
+ #self.attrib = self.flags & 1
+
+
+ def get_loc(self, data):
+ """Gets the origin location of the insert.
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 10, 0.0)
+ loc[1] = getit(data, 20, 0.0)
+ loc[2] = getit(data, 30, 0.0)
+ return loc
+
+
+ def get_scale(self, data):
+ """Gets the x/y/z scale factors of the insert.
+ """
+ scale = [1, 1, 1]
+ scale[0] = getit(data, 41, 1.0)
+ scale[1] = getit(data, 42, 1.0)
+ scale[2] = getit(data, 43, 1.0)
+ return scale
+
+
+ def get_array(self, data):
+ """Returns the pair (row number, row spacing), (column number, column spacing).
+ """
+ columns = getit(data, 70, 1)
+ rows = getit(data, 71, 1)
+ cspace = getit(data, 44, 0.0)
+ rspace = getit(data, 45, 0.0)
+ return (rows, rspace), (columns, cspace)
+
+
+ def get_target(self, data):
+ """Gets the origin location of the insert.
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 1011, 0.0)
+ loc[1] = getit(data, 1021, 0.0)
+ loc[2] = getit(data, 1031, 0.0)
+ return loc
+
+
+ def get_color(self, data):
+ """Gets the origin location of the insert.
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 1010, 0.0)
+ loc[1] = getit(data, 1020, 0.0)
+ loc[2] = getit(data, 1030, 0.0)
+ return loc
+
+
+ def get_ave_render(self, data):
+ """Gets the origin location of the insert.
+ """
+ loc = [0, 0, 0]
+ loc[0] = getit(data, 1010, 0.0)
+ loc[1] = getit(data, 1020, 0.0)
+ loc[2] = getit(data, 1030, 0.0)
+ return loc
+
+
+ def __repr__(self):
+ return "%s: layer - %s, name - %s" %(self.__class__.__name__, self.layer, self.name)
+
+
+ def draw(self, settings, deltaloc):
+ """for INSERT(block): draw empty-marker for duplicated Blender_Group.
+
+ Blocks are made of three objects:
+ the block_record in the tables section
+ the block in the blocks section
+ the insert object (one or more) in the entities section
+ block_record gives the insert units,
+ block provides the objects drawn in the block,
+ insert object gives the location/scale/rotation of the block instances.
+ """
+
+ name = self.name.lower()
+ if name == 'ave_render':
+ if settings.var['lights_on']: #if lights support activated
+ a_data = get_ave_data(self.data)
+ # AVE_RENDER objects:
+ # 7:'Pref', 0:'Full Opt', 0:'Quick Opt', 1:'Scanl Opt', 2:'Raytr Opt', 0:'RFile Opt'
+ # 0:'Fog Opt', 0:'BG Opt', 0:'SCENE1','','','','','','','','','',
+ # '','','','','','','','','','','','',
+
+ if a_data.key == 'SCENE': # define set of lights as blender group
+ scene_lights = 1
+ elif False: # define set of lights as blender group
+ scene_lights = 1
+ return
+ elif name == 'ave_global':
+ if settings.var['lights_on']: #if lights support activated
+ return
+ elif name == 'sh_spot':
+ if settings.var['lights_on']: #if lights support activated
+ obname = settings.blocknamesmap[self.name]
+ obname = 'sp_%s' %obname # create object name from block name
+ #obname = obname[:MAX_NAMELENGTH]
+ # blender: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon'
+ li = Lamp.New('Spot', obname)
+ ob = SCENE.objects.new(li)
+ intensity = 2.0 #--todo-- -----------
+ li.setEnergy(intensity)
+ target = self.get_target(self.data)
+ color = self.get_color(self.data)
+ li.R = color[0]
+ li.G = color[1]
+ li.B = color[2]
+
+ ob.loc = tuple(self.loc)
+ transform(self.extrusion, 0, ob)
+ return ob
+
+ elif name == 'overhead':
+ if settings.var['lights_on']: #if lights support activated
+ obname = settings.blocknamesmap[self.name]
+ obname = 'la_%s' %obname # create object name from block name
+ #obname = obname[:MAX_NAMELENGTH]
+ # blender: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon'
+ li = Lamp.New('Lamp', obname)
+ ob = SCENE.objects.new(li)
+ intensity = 2.0 #--todo-- -----------
+ li.setEnergy(intensity)
+ target = self.get_target(self.data)
+ color = self.get_color(self.data)
+ li.R = color[0]
+ li.G = color[1]
+ li.B = color[2]
+
+ ob.loc = tuple(self.loc)
+ transform(self.extrusion, 0, ob)
+ return ob
+
+ elif name == 'direct':
+ if settings.var['lights_on']: #if lights support activated
+ obname = settings.blocknamesmap[self.name]
+ obname = 'su_%s' %obname # create object name from block name
+ #obname = obname[:MAX_NAMELENGTH]
+ # blender: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon'
+ li = Lamp.New('Sun', obname)
+ ob = SCENE.objects.new(li)
+ intensity = 2.0 #--todo-- -----------
+ li.setEnergy(intensity)
+ color = self.get_color(self.data)
+ li.R = color[0]
+ li.G = color[1]
+ li.B = color[2]
+
+ ob.loc = tuple(self.loc)
+ transform(self.extrusion, 0, ob)
+ return ob
+
+ elif settings.drawTypes['insert']: #if insert_drawType activated
+ print 'deb:draw. settings.blocknamesmap:', settings.blocknamesmap #--------------------
+ obname = settings.blocknamesmap[self.name]
+ obname = 'in_%s' %obname # create object name from block name
+ #obname = obname[:MAX_NAMELENGTH]
+
+ # if material BYBLOCK def needed: use as placeholder a mesh-vertex instead of empty
+ ob = SCENE.objects.new('Empty', obname) # create a new empty_object
+ empty_size = 1.0 * settings.var['g_scale']
+ if empty_size < 0.01: empty_size = 0.01 #Blender limits (0.01-10.0)
+ elif empty_size > 10.0: empty_size = 10.0
+ ob.drawSize = empty_size
+
+ # get our block_def-group
+ block = settings.blocks(self.name)
+ ob.DupGroup = block
+ ob.enableDupGroup = True
+
+ if block.name.startswith('xr_'):
+ ob.name = 'xb_' + ob.name[3:]
+
+ #print 'deb:draw.block.deltaloc:', deltaloc #--------------------
+ ob.loc = tuple(self.loc)
+ if deltaloc:
+ deltaloc = rotXY_Vec(self.rotation, deltaloc)
+ #print 'deb:draw.block.loc:', deltaloc #--------------------
+ ob.loc = [ob.loc[0]+deltaloc[0], ob.loc[1]+deltaloc[1], ob.loc[2]+deltaloc[2]]
+ transform(self.extrusion, self.rotation, ob)
+ ob.size = tuple(self.scale)
+ return ob
+
+
+
+
+class Ellipse: #-----------------------------------------------------------------
+ """Class for objects representing dxf ELLIPSEs.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type ellipse as input.
+ """
+ if not obj.type == 'ellipse':
+ raise TypeError, "Wrong type %s for ellipse object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # required data
+ self.ratio = obj.get_type(40)[0] # Ratio of minor axis to major axis
+ self.start_angle = obj.get_type(41)[0] # in radians
+ self.end_angle = obj.get_type(42)[0]
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+ self.thic = getit(obj, 39, 0.0)
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.loc = self.get_loc(obj.data)
+ self.major = self.get_major(obj.data)
+ self.extrusion = get_extrusion(obj.data)
+
+
+ def get_loc(self, data):
+ """Gets the center location for arc type objects.
+
+ Arcs have a single coord location.
+ """
+ loc = [0.0, 0.0, 0.0]
+ loc[0] = getit(data, 10, 0.0)
+ loc[1] = getit(data, 20, 0.0)
+ loc[2] = getit(data, 30, 0.0)
+ return loc
+
+
+ def get_major(self, data):
+ """Gets the major axis for ellipse type objects.
+
+ The ellipse major axis defines the rotation of the ellipse and its radius.
+ """
+ loc = [0.0, 0.0, 0.0]
+ loc[0] = getit(data, 11, 0.0)
+ loc[1] = getit(data, 21, 0.0)
+ loc[2] = getit(data, 31, 0.0)
+ return loc
+
+
+ def __repr__(self):
+ return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
+
+
+ def draw(self, settings):
+ """for ELLIPSE: generate Blender_geometry.
+ """
+ obname = 'el_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+
+ center = self.loc
+ if True:
+ start = degrees(self.start_angle)
+ end = degrees(self.end_angle)
+ if abs(end - 360.0) < 0.00001: end = 360.0
+ ellipse_closed = False
+ if end - start == 360.0: ellipse_closed = True
+
+ else: # bug in AutoCAD_2002 dxf-exporter into r12 for ELLIPSE->POLYLINE_ARC
+ #print 'deb:calcEllipse---------:\n start=%s\n end=%s' %(self.start_angle, self.end_angle) #---------
+ if self.start_angle > pi+pi: self.start_angle %= pi+pi
+ if self.end_angle > pi+pi: self.end_angle %= pi+pi
+ if abs(self.end_angle - pi - pi) < 0.00001: self.end_angle = pi + pi
+ ellipse_closed = False
+ if abs(self.end_angle - self.start_angle) == pi + pi: ellipse_closed = True
+ test = self.start_angle % pi
+ if test < 0.001 or pi - test < 0.001: start = self.start_angle
+ else:
+ start = atan(tan(self.start_angle) * self.ratio)
+ if start < 0.0: start += pi
+ if self.start_angle > pi: start += pi
+ test = self.end_angle % pi
+ if test < 0.001 or pi - test < 0.001: end = self.end_angle
+ else:
+ end = atan(tan(self.end_angle) * self.ratio)
+ if end < 0.0: end += pi
+ if self.end_angle > pi: end += pi
+ start = degrees(start)
+ end = degrees(end)
+
+ # rotation = Angle between major and WORLDX
+ # doesnt work, couse produces always positive value: rotation = Mathutils.AngleBetweenVecs(major, WORLDX)
+ if self.major[0] == 0:
+ rotation = 90.0
+ if self.major[1] < 0: rotation += 180
+ else:
+ rotation = degrees(atan(self.major[1] / self.major[0]))
+ if self.major[0] < 0:
+ rotation += 180.0
+
+ major = Mathutils.Vector(self.major)
+ #radius = sqrt(self.major[0]**2 + self.major[1]**2 + self.major[2]**2)
+ radius = major.length
+ #print 'deb:calcEllipse:\n center, radius, start, end:\n', center, radius, start, end #---------
+
+ thic = set_thick(self.thic, settings)
+ width = 0.0
+ if settings.var['lines_as'] == 4: # as thin_box
+ thic = settings.var['thick_min']
+ width = settings.var['width_min']
+ if settings.var['lines_as'] == 3: # as thin cylinder
+ cyl_rad = 0.5 * settings.var['width_min']
+
+ if settings.var['lines_as'] == 5: # draw ELLIPSE as curve -------------
+ arc_res = settings.var['curve_arc']
+ triples = True
+ VectorTriples = calcArc(None, radius, start, end, arc_res, triples)
+ arc = Curve.New(obname) # create new curve data
+ curve = arc.appendNurb(BezTriple.New(VectorTriples[0]))
+ if ellipse_closed:
+ for p in VectorTriples[1:-1]:
+ curve.append(BezTriple.New(p))
+ for point in curve:
+ point.handleTypes = [FREE, FREE]
+ curve.flagU = 1 # 0 sets the curve not cyclic=open
+ if settings.var['fill_on']:
+ arc.setFlag(6) # 2+4 set top and button caps
+ else:
+ arc.setFlag(arc.getFlag() & ~6) # dont set top and button caps
+ else:
+ for p in VectorTriples[1:]:
+ curve.append(BezTriple.New(p))
+ for point in curve:
+ point.handleTypes = [FREE, FREE]
+ curve.flagU = 0 # 0 sets the curve not cyclic=open
+
+ arc.setResolu(settings.var['curve_res'])
+ arc.update() #important for handles calculation
+
+ ob = SCENE.objects.new(arc) # create a new curve_object
+ ob.loc = tuple(self.loc)
+ if thic != 0.0: #hack: Blender<2.45 curve-extrusion
+ thic = thic * 0.5
+ arc.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0)
+ ob.LocZ = thic + self.loc[2]
+ transform(self.extrusion, rotation, ob)
+ ob.SizeY *= self.ratio
+ if thic != 0.0:
+ ob.SizeZ *= abs(thic)
+ return ob
+
+
+ else: # draw ELLIPSE as mesh --------------------------------------
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ # set a number of segments in entire circle
+ arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad'])
+
+
+ verts = calcArc(None, radius, start, end, arc_res, False)
+ #verts = [list(point) for point in verts]
+ if False: #--todo--: if ellipse_closed:
+ verts = verts[:-1] #list without last point/edge (cause closed curve)
+ len1 = len(verts)
+ #print 'deb:len1:', len1 #-----------------------
+ if width != 0:
+ radius_out = radius + (0.5 * width)
+ radius_in = radius - (0.5 * width)
+ if radius_in <= 0.0:
+ radius_in = settings.var['dist_min']
+ #radius_in = 0.0
+ verts_in = []
+ verts_out = []
+ for point in verts:
+ pointVec = Mathutils.Vector(point)
+ pointVec = pointVec.normalize()
+ verts_in.append(list(radius_in * pointVec)) #vertex inside
+ verts_out.append(list(radius_out * pointVec)) #vertex outside
+ verts = verts_in + verts_out
+
+ #print 'deb:verts:', verts #---------------------
+ if thic != 0:
+ thic_verts = []
+ thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
+ if thic < 0.0:
+ thic_verts.extend(verts)
+ verts = thic_verts
+ else:
+ verts.extend(thic_verts)
+ f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)]
+ f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)]
+ f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)]
+ f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)]
+ f_start = [[0, len1, len1+len1+len1, len1+len1]]
+ f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]]
+ faces = f_left + f_right + f_bottom + f_top + f_start + f_end
+
+ me.verts.extend(verts) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+ if settings.var['meshSmooth_on']: # left and right side become smooth ----------------------
+ smooth_len = len(f_left) + len(f_right)
+ for i in xrange(smooth_len):
+ me.faces[i].smooth = True
+
+ if settings.var['vGroup_on']:
+ # each MeshSide becomes vertexGroup for easier material assignment ---------------------
+ replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD
+ vg_left, vg_right, vg_top, vg_bottom = [], [], [], []
+ for v in f_left: vg_left.extend(v)
+ for v in f_right: vg_right.extend(v)
+ for v in f_top: vg_top.extend(v)
+ for v in f_bottom: vg_bottom.extend(v)
+ me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace)
+ me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace)
+ me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace)
+ me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace)
+ me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace)
+ me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace)
+
+
+ else: # if thick=0 - draw only flat ring
+ faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)]
+ me.verts.extend(verts) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+
+ elif thic != 0:
+ thic_verts = []
+ thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
+ if thic < 0.0:
+ thic_verts.extend(verts)
+ verts = thic_verts
+ else:
+ verts.extend(thic_verts)
+ faces = []
+ #print 'deb:len1:', len1 #-----------------------
+ #print 'deb:verts:', verts #---------------------
+ faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
+
+ me.verts.extend(verts) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh
+ if settings.var['meshSmooth_on']: # left and right side become smooth ----------------------
+ for i in xrange(len(faces)):
+ me.faces[i].smooth = True
+
+ else:
+ edges = [[num, num+1] for num in xrange(len(verts)-1)]
+ me.verts.extend(verts) # add vertices to mesh
+ me.edges.extend(edges) # add edges to the mesh
+
+ #print 'deb:calcEllipse transform rotation: ', rotation #---------
+ ob.loc = tuple(center)
+ #old ob.SizeY = self.ratio
+ transform(self.extrusion, rotation, ob)
+ #old transform(self.extrusion, 0, ob)
+ ob.SizeY *= self.ratio
+
+ return ob
+
+
+
+class Face: #-----------------------------------------------------------------
+ """Class for objects representing dxf 3DFACEs.
+ """
+
+ def __init__(self, obj):
+ """Expects an entity object of type 3dfaceplot as input.
+ """
+ if not obj.type == '3dface':
+ raise TypeError, "Wrong type %s for 3dface object!" %obj.type
+ self.type = obj.type
+ self.data = obj.data[:]
+
+ # optional data (with defaults)
+ self.space = getit(obj, 67, 0)
+ self.color_index = getit(obj, 62, BYLAYER)
+
+ self.layer = getit(obj.data, 8, None)
+ self.points = self.get_points(obj.data)
+
+
+ def get_points(self, data):
+ """Gets 3-4 points for a 3d face type object.
+
+ Faces have three or optionally four verts.
+ """
+ a = [0, 0, 0]
+ b = [0, 0, 0]
+ c = [0, 0, 0]
+ d = [0, 0, 0]
+ a[0] = getit(data, 10, None) # 10 = x
+ a[1] = getit(data, 20, None) # 20 = y
+ a[2] = getit(data, 30, 0.0) # 30 = z
+ b[0] = getit(data, 11, None)
+ b[1] = getit(data, 21, None)
+ b[2] = getit(data, 31, 0.0)
+ c[0] = getit(data, 12, None)
+ c[1] = getit(data, 22, None)
+ c[2] = getit(data, 32, 0.0)
+ out = [a,b,c]
+
+ d[0] = getit(data, 13, None)
+ if d[0] != None:
+ d[1] = getit(data, 23, None)
+ d[2] = getit(data, 33, 0.0)
+ out.append(d)
+
+ #if len(out) < 4: print '3dface with only 3 vertices:\n',a,b,c,d #-----------------
+ return out
+
+
+ def __repr__(self):
+ return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
+
+
+ def draw(self, settings):
+ """for 3DFACE: generate Blender_geometry.
+ """
+ # Generate the geometery
+ points = self.points
+
+ global activObjectLayer
+ global activObjectName
+ #print 'deb:draw:face.ob IN activObjectName: ', activObjectName #---------------------
+
+ if activObjectLayer == self.layer and settings.var['one_mesh_on']:
+ obname = activObjectName
+ #print 'deb:face.draw obname from activObjectName: ', obname #---------------------
+ ob = Object.Get(obname) # open an existing mesh_object
+ #ob = SCENE.getChildren(obname) # open an existing mesh_object
+ else:
+ obname = 'fa_%s' %self.layer # create object name from layer name
+ obname = obname[:MAX_NAMELENGTH]
+ me = Mesh.New(obname) # create a new mesh
+ ob = SCENE.objects.new(me) # create a new mesh_object
+ activObjectName = ob.name
+ activObjectLayer = self.layer
+ #print ('deb:except. new face.ob+mesh:"%s" created!' %ob.name) #---------------------
+
+ me = Mesh.Get(ob.name) # open objects mesh data
+ faces, edges = [], []
+ n = len(me.verts)
+ if len(self.points) == 4:
+ faces = [[0+n,1+n,2+n,3+n]]
+ elif len(self.points) == 3:
+ faces = [[0+n,1+n,2+n]]
+ elif len(self.points) == 2:
+ edges = [[0+n,1+n]]
+
+ me.verts.extend(points) # add vertices to mesh
+ if faces: me.faces.extend(faces) # add faces to the mesh
+ if edges: me.edges.extend(edges) # add faces to the mesh
+ if settings.var['vGroup_on']:
+ # entities with the same color build one vertexGroup for easier material assignment ---------------------
+ ob.link(me) # link mesh to that object
+ vG_name = 'color_%s' %self.color_index
+ if edges: faces = edges
+ replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD
+ try:
+ me.assignVertsToGroup(vG_name, faces[0], 1.0, replace)
+ #print 'deb: existed vGroup:', vG_name #---------------------
+ except:
+ me.addVertGroup(vG_name)
+ me.assignVertsToGroup(vG_name, faces[0], 1.0, replace)
+ #print 'deb: create new vGroup:', vG_name #--------------------
+
+ #print 'deb:draw:face.ob OUT activObjectName: ', activObjectName #---------------------
+ return ob
+
+
+#---------------------------------------------------------------------------------------
+# type to object maping (sorted-dictionary for f_obiectify ONLY!, format={'key':Class} )
type_map = {
- 'line':Line,
- 'lwpolyline':LWpolyline,
- 'text':Text,
- 'mtext':Mtext,
- 'circle':Circle,
- 'arc':Arc,
- 'layer':Layer,
- 'block_record':BlockRecord,
- 'block':Block,
- 'insert':Insert,
- 'ellipse':Ellipse,
- '3dface':Face
+ 'vport':Vport,
+ 'view':View,
+ 'layer':Layer,
+ 'block_record':BlockRecord,
+ 'block':Block,
+ 'insert':Insert,
+ 'point':Point,
+ '3dface':Face,
+ 'line':Line,
+# 'mline':MLine,
+ 'polyline':Polyline,
+ 'lwpolyline':LWpolyline,
+# 'region':Region,
+ 'trace':Solid,
+ 'solid':Solid,
+ 'text':Text,
+ 'mtext':Mtext,
+ 'circle':Circle,
+ 'ellipse':Ellipse,
+ 'arc':Arc
}
-def objectify(data):
- """Expects a section type object's data as input.
-
- Maps object data to the correct object type.
- """
- objects = [] # colector for finished objects
- known_types = type_map.keys() # so we don't have to call foo.keys() every iteration
- index = 0
- while index < len(data):
- item = data[index]
- if type(item) != list and item.type in known_types:
- # proccess the object and append the resulting object
- objects.append(type_map[item.type](item))
- elif type(item) != list and item.type == 'table':
- item.data = objectify(item.data) # tables have sub-objects
- objects.append(item)
- elif type(item) != list and item.type == 'polyline':
- pline = Polyline(item)
- while 1:
- index += 1
- item = data[index]
- if item.type == 'vertex':
- v = Vertex(item)
- pline.points.append(v)
- elif item.type == 'seqend':
- break
- else:
- print "Error: non-vertex found before seqend!"
- index -= 1
- break
- objects.append(pline)
- else:
- # we will just let the data pass un-harrased
- objects.append(item)
- index += 1
- return objects
-
-class MatColors:
- """A smart container for color based materials.
-
- This class is a wrapper around a dictionary mapping color indicies to materials.
- When called with a color index it returns a material corrisponding to that index.
- Behind the scenes it checks if that index is in its keys, and if not it creates
- a new material. It then adds the new index:material pair to its dict and returns
- the material.
- """
-
- def __init__(self, map):
- """Expects a dictionary mapping layer names to color idices."""
- self.map = map
- self.colors = {}
-
-
- def __call__(self, color=None):
- """Return the material associated with color.
-
- If a layer name is provided the color of that layer is used.
- """
- if not color:
- color = 0
- if type(color) == str: # Layer name
- try:
- color = self.map[color].color # color = layer_map[name].color
- except KeyError:
- layer = Layer(name=color, color=0, frozen=False)
- self.map[color] = layer
- color = 0
- color = abs(color)
- if color not in self.colors.keys():
- self.add(color)
- return self.colors[color]
-
-
-
-
- def add(self, color):
- """Create a new material using the provided color index."""
- global color_map
- mat = Material.New('ColorIndex-%s' %color)
- mat.setRGBCol(color_map[color])
- mat.setMode("Shadeless", "Wire")
- self.colors[color] = mat
-
-
-
-
-class Blocks:
- """A smart container for blocks.
-
- This class is a wrapper around a dictionary mapping block names to Blender data blocks.
- When called with a name string it returns a block corrisponding to that name.
- Behind the scenes it checks if that name is in its keys, and if not it creates
- a new data block. It then adds the new name:block pair to its dict and returns
- the block.
- """
-
- def __init__(self, map, settings):
- """Expects a dictionary mapping block names to block objects."""
- self.map = map
- self.settings = settings
- self.blocks = {}
-
-
- def __call__(self, name=None):
- """Return the data block associated with name.
-
- If no name is provided return self.blocks.
- """
- if not name:
- return self.blocks
- if name not in self.blocks.keys():
- self.add(name)
- return self.blocks[name]
-
-
-
- def add(self, name):
- """Create a new block group for the block with name."""
- write = self.settings.write
- group = Group.New(name)
- block = self.map[name]
- write("\nDrawing %s block entities..." %name)
- drawEntities(block.entities, self.settings, group)
- write("Done!")
- self.blocks[name] = group
-
-
-
-
-
-class Settings:
- """A container for all the import settings and objects used by the draw functions.
-
- This is like a collection of globally accessable persistant properties and functions.
- """
- # Optimization constants
- MIN = 0
- MID = 1
- PRO = 2
- MAX = 3
-
- def __init__(self, drawing, curves, optimization, **kwds):
- """Given the drawing initialize all the important settings used by the draw functions."""
- self.curves = curves
- self.optimization = optimization
- print "Setting optimization level %s!" %optimization
- self.drawTypes = kwds
- self.layers = True
- self.blocks = True
-
- # First sort out all the sections
- sections = dict([(item.name, item) for item in drawing.data])
-
- # The header section may be omited
- if 'header' in sections.keys():
- self.write("Found header!")
- else:
- self.write("File contains no header!")
-
- # The tables section may be partialy or completely missing.
- if 'tables' in sections.keys():
- self.write("Found tables!")
- tables = dict([(item.name, item) for item in sections["tables"].data])
- if 'layer' in tables.keys():
- self.write("Found layers!")
- # Read the layers table and get the layer colors
- self.colors = getLayers(drawing)
- else:
- self.write("File contains no layers table!")
- self.layers = False
- self.colors = MatColors({})
- else:
- self.write("File contains no tables!")
- self.write("File contains no layers table!")
- self.layers = False
- self.colors = MatColors({})
-
- # The blocks section may be omited
- if 'blocks' in sections.keys():
- self.write("Found blocks!")
- # Read the block definitions and build our block object
- if self.drawTypes['blocks']:
- self.blocks = getBlocks(drawing, self)
- else:
- self.write("File contains no blocks!")
- self.drawTypes['blocks'] = False
- def write(self, text, newline=True):
- """Wraps the built-in print command in a optimization check."""
- if self.optimization <= self.MID:
- if newline:
- print text
- else:
- print text,
-
- def redraw(self):
- """Update Blender if optimization level is low enough."""
- if self.optimization <= self.MIN:
- Blender.Redraw()
-
-
- def progress(self, done, text):
- """Wrapper for Blender.Window.DrawProgressBar."""
- if self.optimization <= self.PRO:
- Window.DrawProgressBar(done, text)
-
-
- def isOff(self, name):
- """Given a layer name look up the layer object and return its visable status."""
- # colors are negative if layer is off
- try:
- layer = self.colors.map[name]
- except KeyError:
- return False
-
- if layer.frozen or layer.color < 0:
- return True
- else:
- return False
-
-
-
-
-def main(filename=None):
- editmode = Window.EditMode() # are we in edit mode? If so ...
- if editmode: Window.EditMode(0) # leave edit mode before
- Window.WaitCursor(True) # Let the user know we are thinking
-
- try:
- if not filename:
- print "DXF import: error, no file selected. Attempting to load default file."
- try:
- filename = Sys.expandpath(r".\examples\big-test.dxf")
- except IOError:
- print "DXF import: error finding default test file, exiting..."
- return None
- drawing = readDXF(filename, objectify)
- drawDrawing(drawing)
- finally:
- # restore state even if things didn't work
- Window.WaitCursor(False)
- if editmode: Window.EditMode(1) # and put things back how we fond them
-
-def getOCS(az):
- """An implimentation of the Arbitrary Axis Algorithm."""
- # world x, y, and z axis
- wx = WORLDX
- wy = Mathutils.Vector((0,1,0))
- wz = Mathutils.Vector((0,0,1))
-
- #decide if we need to transform our coords
- if az[0] == 0 and az[1] == 0:
- return False
- # elif abs(az[0]) < 0.0001 or abs(az[1]) < 0.0001:
- # return False
- az = Mathutils.Vector(az)
-
- cap = 0.015625 # square polar cap value (1/64.0)
- if abs(az.x) < cap and abs(az.y) < cap:
- ax = Mathutils.CrossVecs(wy, az)
- else:
- ax = Mathutils.CrossVecs(wz, az)
- ax = ax.normalize()
- ay = Mathutils.CrossVecs(az, ax)
- ay = ay.normalize()
- return ax, ay, az
-
-def transform(normal, obj):
- """Use the calculated ocs to determine the objects location/orientation in space.
-
- Quote from dxf docs:
- The elevation value stored with an entity and output in DXF files is a sum
- of the Z-coordinate difference between the UCS XY plane and the OCS XY
- plane, and the elevation value that the user specified at the time the entity
- was drawn.
- """
- ocs = getOCS(normal)
- if ocs:
- #print ocs
- x, y, z = ocs
- x = x.resize4D()
- y = y.resize4D()
- z = -z.resize4D()
- x.w = 0
- y.w = 0
- z.w = 0
- o = Mathutils.Vector(obj.loc)
- o = o.resize4D()
- mat = Mathutils.Matrix(x, y, z, o)
- obj.setMatrix(mat)
-
-def getLayers(drawing):
- """Build a dictionary of name:color pairs for the given drawing."""
- tables = drawing.tables
- for table in tables.data:
- if table.name == 'layer':
- layers = table
- break
- map = {}
- for item in layers.data:
- if type(item) != list and item.type == 'layer':
- map[item.name] = item
- colors = MatColors(map)
- return colors
-def getBlocks(drawing, settings):
- """Build a dictionary of name:block pairs for the given drawing."""
- map = {}
- for item in drawing.blocks.data:
- if type(item) != list and item.type == 'block':
- try:
- map[item.name] = item
- except KeyError:
- # annon block
- print "Cannot map %s - %s!" %(item.name, item)
- blocks = Blocks(map, settings)
- return blocks
-def drawDrawing(drawing):
- """Given a drawing object recreate the drawing in Blender."""
- print "Getting settings..."
- Window.WaitCursor(False)
- #width, height = Window.GetScreenSize()
- Window.SetMouseCoords()
-
- # Create a PupBlock to get user preferences
- lines = Draw.Create(1)
- arcs = Draw.Create(1)
- circles = Draw.Create(1)
- polylines = Draw.Create(1)
- text = Draw.Create(1)
- blocks = Draw.Create(1)
- faces = Draw.Create(1)
- optim = Draw.Create(1)
-
- block = []
- block.append("Draw Options:")
- block.append(("Lines", lines, "Toggle drawing of lines"))
- block.append(("Arcs", arcs, "Toggle drawing of arcs"))
- block.append(("Circles", circles, "Toggle drawing of circles"))
- block.append(("Polylines", polylines, "Toggle drawing of polylines"))
- block.append(("Text", text, "Toggle drawing of text"))
- block.append(("Blocks", blocks, "Toggle drawing of blocks"))
- block.append(("Faces", faces, "Toggle drawing of faces"))
- block.append("Update Optimization:")
- block.append(("Level: ", optim, 0, 3))
-
- retval = Draw.PupBlock("DXF Import", block)
-
- Window.WaitCursor(True) # Let the user know we are thinking
- # The settings object controls how dxf entities are drawn
- settings = Settings(drawing, curves=False,
- optimization=int(optim.val),
- lines=bool(lines.val),
- arcs=bool(arcs.val),
- circles=bool(circles.val),
- polylines=bool(polylines.val),
- text=bool(text.val),
- blocks=bool(blocks.val),
- faces=bool(faces.val)
- )
-
- settings.write("Drawings entities...")
- # Draw all the know entity types in the current scene
- drawEntities(drawing.entities, settings)
-
- # Set the visable layers
- SCENE.setLayers([i+1 for i in range(18)])
- Blender.Redraw(-1)
- settings.write("Done!")
-
-
-def drawEntities(entities, settings, group=None):
- """Draw every kind of thing in the entity list.
-
- If provided 'group' is the Blender group new entities are to be added to.
- """
- for _type in type_map.keys():
- # for each known type get a list of that type and call the associated draw function
- drawer(_type, entities.get_type(_type), settings, group)
-
-
-def drawer(_type, entities, settings, group):
- """Call with a list of entities and a settings object to generate Blender geometry."""
- if entities:
- # Break out early if settings says we aren't drawing the current type
- block = False
- skip = False
- if _type == 'block_record':
- skip = True
- if _type == 'line' and not settings.drawTypes['lines']:
- skip = True
- elif _type == 'arc' and not settings.drawTypes['arcs']:
- skip = True
- elif _type == 'circle' and not settings.drawTypes['circles']:
- skip = True
- elif _type in ['lwpolyline', 'polyline'] and not settings.drawTypes['polylines']:
- skip = True
- elif _type in ['text', 'mtext'] and not settings.drawTypes['text']:
- skip = True
- elif _type == 'insert':
- if not settings.drawTypes['blocks']:
- skip = True
- block = True
- elif _type == '3dface' and not settings.drawTypes['faces']:
- skip = True
- if skip:
- settings.write("Skipping %s type entities!" %_type)
- return
-
- message = "Drawing %ss..." %_type
- settings.write(message, False)
- settings.progress(0, message)
-
- if block:
- # create one 'handle' data block to use with all blocks
- handle = Mesh.New('insert')
- handle.verts.extend(
- [(-0.01,0,0),
- (0.01,0,0),
- (0,-0.01,0),
- (0,0.01,0),
- (0,0,-0.01),
- (0,0,0.01)]
- )
- handle.edges.extend([(0,1),(2,3),(4,5)])
-
- # For now we only want model-space objects
- entities = [entity for entity in entities if entity.space == 0]
-
- if group:
- block_def = True
- else:
- block_def = False
-
- tot = len(entities)
- cur = 1.0
- for entity in entities:
- settings.write('\b.', False)
- settings.progress(cur/tot, message)
- cur += 1
-
- # First get the layer group
- if not block_def:
- group = getGroup('layer %s' %entity.layer) # add overhead just to make things a little cleaner
-
- if block:
- ob = entity.draw(handle, settings)
- else:
- ob = entity.draw(settings.curves)
-
- setColor(entity, ob, settings)
- # Link it to the scene and add it to the correct group
- SCENE.link(ob)
- setGroup(group, ob)
-
- # Set the visability
- if settings.isOff(entity.layer):
- ob.layers = [20]
- elif block_def:
- ob.layers = [19]
- else:
- ob.layers = [i+1 for i in range(20)]
-
- # # Set the visability
- # if settings.isOff(entity.layer) or block_def:
- # ob.restrictDisplay = True
- # ob.restrictRender = True
-
- settings.redraw()
- message = "\nFinished drawing %ss!" %entities[0].type
- settings.write(message)
- settings.progress(1, message)
-
-
-def getGroup(name):
- """Returns a Blender group object."""
- try:
- group = Group.Get(name)
- except: # What is the exception?
- group = Group.New(name)
- return group
-def setColor(entity, ob, settings):
- # Set the color
- if entity.color_index == BYLAYER:
- mat = settings.colors(entity.layer)
- else:
- mat = settings.colors(entity.color_index)
- try:
- ob.setMaterials([mat])
- except ValueError:
- settings.write("material error - %s!" %mat)
- ob.colbits = 0x01 # Set OB materials.
-def setGroup(group, it):
- try:
- group.objects.link(it)
- except:
- group.objects.append(it)
-
-def solveBulge(p1, p2):
- """return the center, radius, start angle, and end angle given two points.
-
- Needs to take into account bulge sign.
- negative = clockwise
- positive = counter-clockwise
-
- to find center given two points, and arc angle
- calculate radius
- Cord = sqrt(start^2 + end^2)
- S = (bulge*Cord)/2
- radius = ((Cord/2)^2+S^2)/2*S
- angle of arc = 4*atan( bulge )
- angle from p1 to center is (180-angle)/2
- get vector pointing from p1 to p2 (p2 - p1)
- normalize it and multiply by radius
- rotate around p1 by angle to center point to center.
-
- start angle = angle between (center - p1) and worldX
- end angle = start angle + angle of arc
- """
- bulge = p1.bulge
- p2 = Mathutils.Vector(p2.loc)
- p1 = Mathutils.Vector(p1.loc)
- cord = p2 - p1 # vector from p1 to p2
- clength = cord.length
- s = (bulge * clength)/2 # sagitta (height)
- radius = abs(((clength/2)**2 + s**2)/(2*s)) # magic formula
- angle = abs(degrees(4*atan(bulge))) # theta (included angle)
- delta = (180 - angle)/2 # the angle from cord to center
- if bulge > 0:
- delta = -delta
- radial = cord.normalize() * radius # a radius length vector aligned with cord
- rmat = Mathutils.RotationMatrix(delta, 3, 'Z')
- center = p1 + (rmat * radial) # rotate radial by delta degrees, then add to p1 to find center
- if bulge < 0:
- sv = (p1 - center) # start from point 2
- else:
- sv = (p2 - center) # start from point 1
- start = Mathutils.AngleBetweenVecs(sv, WORLDX) # start angle is the angle between the first leg of the section and the x axis
- # The next bit is my cludge to figure out if start should be negative
- rmat = Mathutils.RotationMatrix(start, 3, 'Z')
- rstart = rmat * sv
- if Mathutils.AngleBetweenVecs(rstart, WORLDX) < start:
- start = -start
- # the end angle is just 'angle' more than start angle
- end = start + angle
- return list(center), radius, start, end
-def drawArc(center, radius, start, end, step=0.5):
- """Draw a mesh arc with the given parameters."""
- # center is currently set by object
-
- # if start > end:
- # start = start - 360
- if end > 360:
- end = end%360
- startmatrix = Mathutils.RotationMatrix(start, 3, "Z")
- startpoint = startmatrix * Mathutils.Vector((radius, 0, 0))
- endmatrix = Mathutils.RotationMatrix(end, 3, "Z")
- endpoint = endmatrix * Mathutils.Vector((radius, 0, 0))
- points = [startpoint]
-
- if end < start:
- end +=360
-
- delta = end - start
- length = radians(delta) * radius
- if radius < step*10: # if circumfrance is too small
- pieces = int(delta/10) # set a fixed step of 10 degrees
- else:
- pieces = int(length/step) # figure out how many pieces we need for our arc
- if pieces == 0: # stupid way to avoid a div by zero error
- pieces = 1 # what would be a smarter way to fix this?
- step = delta/pieces # set step so pieces * step = degrees in arc
-
- stepmatrix = Mathutils.RotationMatrix(step, 3, "Z")
- point = Mathutils.Vector(startpoint)
- for i in range(int(pieces)):
- point = stepmatrix * point
- points.append(point)
- points.append(endpoint)
-
- if center:
- points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points]
- edges = [[num, num+1] for num in range(len(points)-1)]
-
- return points, edges
-# Here are some alternate drawing functions for creating curve geometery.
-
-def drawCurveCircle(circle):
- """Given a dxf circle object return a blender circle object using curves."""
- c = Curve.New('circle') # create new curve data
-
- center = circle.loc
- radius = circle.radius
-
- p1 = (0, -radius, 0)
- p2 = (radius, 0, 0)
- p3 = (0, radius, 0)
- p4 = (-radius, 0, 0)
-
- p1 = BezTriple.New(p1)
- p2 = BezTriple.New(p2)
- p3 = BezTriple.New(p3)
- p4 = BezTriple.New(p4)
-
- curve = c.appendNurb(p1)
- curve.append(p2)
- curve.append(p3)
- curve.append(p4)
- for point in curve:
- point.handleTypes = [AUTO, AUTO]
- curve.flagU = 1 # Set curve cyclic
- c.update()
-
- ob = Object.New('Curve', 'circle') # make curve object
- return ob
-
-def drawCurveArc(arc):
- """Given a dxf circle object return a blender circle object using curves."""
- if start > end:
- start = start - 360
- startmatrix = Mathutils.RotationMatrix(start, 3, "Z")
- startpoint = startmatrix * Mathutils.Vector((radius, 0, 0))
- endmatrix = Mathutils.RotationMatrix(end, 3, "Z")
- endpoint = endmatrix * Mathutils.Vector((radius, 0, 0))
- # Note: handles must be tangent to arc and of correct length...
-
- a = Curve.New('arc') # create new curve data
-
- center = circle.loc
- radius = circle.radius
-
- p1 = (0, -radius, 0)
- p2 = (radius, 0, 0)
- p3 = (0, radius, 0)
- p4 = (-radius, 0, 0)
-
- p1 = BezTriple.New(p1)
- p2 = BezTriple.New(p2)
- p3 = BezTriple.New(p3)
- p4 = BezTriple.New(p4)
-
- curve = a.appendNurb(p1)
- curve.append(p2)
- curve.append(p3)
- curve.append(p4)
- for point in curve:
- point.handleTypes = [AUTO, AUTO]
- curve.flagU = 1 # Set curve cyclic
- a.update()
-
- ob = Object.New('Curve', 'arc') # make curve object
- return ob
+
+
+def objectify(data): #-----------------------------------------------------------------
+ """Expects a section type object's data as input.
+
+ Maps object data to the correct object type.
+ """
+ #print 'deb:objectify start %%%%%%%%%%%' #---------------
+ objects = [] # colector for finished objects
+ known_types = type_map.keys() # so we don't have to call foo.keys() every iteration
+ curves_on = GUI_A['curves_on'].val
+ index = 0
+ while index < len(data):
+ item = data[index]
+ #print 'deb:objectify item: \n', item #------------
+ if type(item) != list and item.type == 'table':
+ item.data = objectify(item.data) # tables have sub-objects
+ objects.append(item)
+ elif type(item) != list and item.type == 'polyline': #remi --todo-----------
+ #print 'deb:gosub Polyline\n' #-------------
+ pline = Polyline(item)
+ while 1:
+ index += 1
+ item = data[index]
+ if item.type == 'vertex':
+ #print 'deb:objectify gosub Vertex--------' #-------------
+ v = Vertex(item)
+ if pline.spline: # if Bspline-curve
+ # then for Blender-mesh filter only additional_vertices
+ # OR
+ # then for Blender-curve filter only spline_control_vertices
+ if (v.spline and not curves_on) or (curves_on and v.splin2): #correct for real NURBS-import
+ #if (v.spline and not curves_on) or (curves_on and not v.splin2): #fake for Bezier-emulation of NURBS-import
+ pline.points.append(v)
+ elif pline.curved: # if Bezier-curve
+ # then for Blender-mesh filter only curve_additional_vertices
+ # OR
+ # then for Blender-curve filter curve_control_vertices
+ if not curves_on or (curves_on and not v.curved):
+ pline.points.append(v)
+ else:
+ pline.points.append(v)
+ elif item.type == 'seqend':
+ #print 'deb:objectify it is seqEND ---------\n' #-------------
+ break
+ else:
+ print "Error: non-vertex found before seqend!"
+ index -= 1 #so go back one step
+ break
+ objects.append(pline)
+ elif type(item) != list and item.type in ['block', 'insert']:
+ if not settings.var['block_nn'] and item.name.startswith('*X'):
+ #print 'deb:objectify item.type:"%s", item.name:"%s"' %(item.type, item.name) #------------
+ pass
+ elif settings.var['blockFilter_on'] and not settings.accepted_block(item.name):
+ pass
+ else:
+ try:
+ objects.append(type_map[item.type](item))
+ except TypeError:
+ pass
+ elif type(item) != list and item.type in known_types:
+ # proccess the object and append the resulting object
+ try:
+ objects.append(type_map[item.type](item))
+ except TypeError:
+ pass
+ else:
+ #we will just let the data pass un-harrased
+ #objects.append(item)
+ pass
+ index += 1
+ #print 'deb:objectify objects:\n', objects #------------
+ #print 'deb:objectify END %%%%%%%%' #------------
+ return objects
+
+
+
+class MatColors: #-----------------------------------------------------------------
+ """A smart container for dxf-color based materials.
+
+ This class is a wrapper around a dictionary mapping dxf-color indicies to materials.
+ When called with a color_index
+ it returns a material corresponding to that index.
+ Behind the scenes it checks if that index is in its keys, and if not it creates
+ a new material. It then adds the new index:material pair to its dict and returns
+ the material.
+ """
+
+ def __init__(self, layersmap):
+ """Expects a map - a dictionary mapping layer names to layers.
+ """
+ #self.layersmap = layersmap # a dictionary of layername:layerobject
+ self.colMaterials = {} # a dictionary of color_index:blender_material
+ #print 'deb:init_MatColors argument.map: ', map #------------------
+
+
+ def __call__(self, color=None):
+ """Return the material associated with color.
+
+ If a layer name is provided, the color of that layer is used.
+ """
+ if color == None: color = 256 # color 256=BYLAYER
+ if type(color) == str: # looking for color of LAYER named "color"
+ #--todo---bug with ARC from ARC-T0.DXF layer="T-3DARC-1"-----
+ #print 'deb:color is string:--------: ', color
+ #try:
+ #color = layersmap[color].color
+ #print 'deb:color=self.map[color].color:', color #------------------
+ #except KeyError:
+ #layer = Layer(name=color, color=256, frozen=False)
+ #layersmap[color] = layer
+ #color = 0
+ if layersmap: color = layersmap[color].color
+ if color == 256: # color 0 = BYLAYER
+ #--todo-- should looking for color of LAYER
+ #if layersmap: color = layersmap[color].color
+ color = 3
+ if color == 0: # color 0 = BYBLOCK
+ #--todo-- should looking for color of paret-BLOCK
+ #if layersmap: color = layersmap[color].color
+ color = 3
+ color = abs(color) # cause the value could be nagative = means the layer is turned off
+
+ if color not in self.colMaterials.keys():
+ self.add(color)
+ return self.colMaterials[color]
+
+
+ def add(self, color):
+ """Create a new material 'ColorNr-N' using the provided color index-N.
+ """
+ #global color_map #--todo-- has not to be global?
+ mat = Material.New('ColorNr-%s' %color)
+ mat.setRGBCol(color_map[color])
+ #mat.mode |= Material.Modes.SHADELESS #--todo--
+ #mat.mode |= Material.Modes.WIRE
+# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug
+# except: pass
+ self.colMaterials[color] = mat
+
+
+
+class MatLayers: #-----------------------------------------------------------------
+ """A smart container for dxf-layer based materials.
+
+ This class is a wrapper around a dictionary mapping dxf-layer names to materials.
+ When called with a layer name it returns a material corrisponding to that.
+ Behind the scenes it checks if that layername is in its keys, and if not it creates
+ a new material. It then adds the new layername:material pair to its dict and returns
+ the material.
+ """
+
+ def __init__(self, layersmap):
+ """Expects a map - a dictionary mapping layer names to layers.
+ """
+ #self.layersmap = layersmap # a dictionary of layername:layer
+ self.layMaterials = {} # a dictionary of layer_name:blender_material
+ #print 'deb:init_MatLayers argument.map: ', map #------------------
+
+
+ def __call__(self, layername=None, color=None):
+ """Return the material associated with dxf-layer.
+
+ If a dxf-layername is not provided, create a new material
+ """
+ #global layernamesmap
+ layername_short = layername
+ if layername in layernamesmap.keys():
+ layername_short = layernamesmap[layername]
+ colorlayername = layername_short
+ if color: colorlayername = str(color) + colorlayername
+ if colorlayername not in self.layMaterials.keys():
+ self.add(layername, color, colorlayername)
+ return self.layMaterials[colorlayername]
+
+
+ def add(self, layername, color, colorlayername):
+ """Create a new material 'layername'.
+ """
+ try: mat = Material.Get('L-%s' %colorlayername)
+ except: mat = Material.New('L-%s' %colorlayername)
+ #print 'deb:MatLayers material: ', mat #----------
+ #global settings
+ #print 'deb:MatLayers material_from: ', settings.var['material_from'] #----------
+ if settings.var['material_from'] == 3 and color:
+ if color == 0 or color == 256: mat_color = 3
+ else: mat_color = color
+ elif layersmap and layername:
+ mat_color = layersmap[layername].color
+ else: mat_color = 3
+ #print 'deb:MatLayers color: ', color #-----------
+ #print 'deb:MatLayers mat_color: ', mat_color #-----------
+ mat.setRGBCol(color_map[abs(mat_color)])
+ #mat.mode |= Material.Modes.SHADELESS
+ #mat.mode |= Material.Modes.WIRE
+# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug
+# except: pass
+ self.layMaterials[colorlayername] = mat
+
+
+
+
+class Blocks: #-----------------------------------------------------------------
+ """A smart container for blocks.
+
+ This class is a wrapper around a dictionary mapping block names to Blender data blocks.
+ When called with a name string it returns a block corresponding to that name.
+ Behind the scenes it checks if that name is in its keys, and if not it creates
+ a new data block. It then adds the new name:block_data pair to its dict and returns
+ the block.
+ """
+
+ def __init__(self, blocksmap, settings):
+ """Expects a dictionary mapping block_name:block_data.
+ """
+ self.blocksmap = blocksmap #a dictionary mapping block_name:block_data
+ self.settings = settings
+ self.blocks = {} #container for blender groups representing blocks
+
+
+ def __call__(self, name=None):
+ """Return the data block associated with that block_name.
+
+ If that name is not in its keys, it creates a new data block.
+ If no name is provided return entire self.blocks container.
+ """
+ if name == None:
+ return self.blocks
+ if name not in self.blocks.keys():
+ self.addBlock(name)
+ return self.blocks[name]
+
+
+ def addBlock(self, name):
+ """Create a new 'block group' for the block name.
+ """
+ block = self.blocksmap[name]
+ prefix = 'bl'
+ if block.xref: prefix = 'xr'
+ blender_group = Group.New('%s_%s' %(prefix,name)) # Blender groupObject contains definition of BLOCK
+ block_def = [blender_group, block.loc]
+ self.settings.write("\nDrawing block:\'%s\' ..." % name)
+
+ if block.xref:
+ obname = 'xr_%s' %name # create object name from xref block name
+ #obname = obname[:MAX_NAMELENGTH]
+ # if material BYBLOCK def needed: use as placeholder a mesh-vertex instead of empty
+ ob = SCENE.objects.new('Empty', obname) # create a new empty_object
+ empty_size = 1.0 * settings.var['g_scale']
+ if empty_size < 0.01: empty_size = 0.01 #Blender limits (0.01-10.0)
+ elif empty_size > 10.0: empty_size = 10.0
+ ob.drawSize = empty_size
+ ob.loc = tuple(block.loc)
+ ob.properties['xref_path'] = block.path
+ ob.layers = [19]
+ insertFlag=True; blockFlag=True
+ global oblist
+ oblist.append((ob, insertFlag, blockFlag))
+ else:
+ drawEntities(block.entities, self.settings, block_def)
+ self.settings.write("Drawing block:\'%s\' done!" %name)
+ self.blocks[name] = blender_group
+
+
+
+
+
+class Settings: #-----------------------------------------------------------------
+ """A container for all the import settings and objects used by the draw functions.
+
+ This is like a collection of globally accessable persistant properties and functions.
+ """
+ # Optimization constants
+ MIN = 0
+ MID = 1
+ PRO = 2
+ MAX = 3
+
+ def __init__(self, keywords, drawTypes):
+ """initialize all the important settings used by the draw functions.
+ """
+ self.obj_number = 1 #global object_number for progress_bar
+
+ self.var = dict(keywords) #a dictionary of (key_variable:Value) control parameter
+ self.drawTypes = dict(drawTypes) #a dictionary of (entity_type:True/False) = import on/off for this entity_type
+
+ self.var['colorFilter_on'] = False #deb:remi------------
+ self.acceptedColors = [0,2,3,4,5,6,7,8,9,
+ 10 ]
+
+ self.var['layerFilter_on'] = False #deb:remi------------
+ self.acceptedLayers = ['3',
+ '0'
+ ]
+
+ #self.var['blockFilter_on'] = 0 #deb:remi------------
+ self.acceptedBlocks = ['WALL_1871',
+ 'BOX02'
+ ]
+ self.unwantedBlocks = ['BOX05',
+ 'BOX04'
+ ]
+
+
+ def update(self, keywords, drawTypes):
+ """update all the important settings used by the draw functions.
+ mostly used after loading parameters from INI-file
+ """
+
+ for k, v in keywords.iteritems():
+ self.var[k] = v
+ #print 'deb:settings_update var %s= %s' %(k, self.var[k]) #--------------
+ for t, v in drawTypes.iteritems():
+ self.drawTypes[t] = v
+ #print 'deb:settings_update drawType %s= %s' %(t, self.drawTypes[t]) #--------------
+
+ self.drawTypes['arc'] = self.drawTypes['line']
+ self.drawTypes['circle'] = self.drawTypes['line']
+ self.drawTypes['ellipse'] = self.drawTypes['line']
+ self.drawTypes['trace'] = self.drawTypes['solid']
+ self.drawTypes['insert'] = self.drawTypes['block']
+ #self.drawTypes['vport'] = self.drawTypes['view']
+
+ #print 'deb:self.drawTypes', self.drawTypes #---------------
+
+
+ def validate(self, drawing):
+ """Given the drawing, build dictionaries of Layers, Colors and Blocks.
+ """
+
+ #de: paßt die distance parameter an globalScale
+ if self.var['g_scale'] != 1.0:
+ self.var['dist_min'] = self.var['dist_min'] / self.var['g_scale']
+ self.var['thick_min'] = self.var['thick_min'] / self.var['g_scale']
+ self.var['width_min'] = self.var['width_min'] / self.var['g_scale']
+ self.var['arc_rad'] = self.var['arc_rad'] / self.var['g_scale']
+
+ self.g_origin = Mathutils.Vector(self.var['g_originX'], self.var['g_originY'], self.var['g_originZ'])
+
+ # First sort out all the section_items
+ sections = dict([(item.name, item) for item in drawing.data])
+
+ # The section:header may be omited
+ if 'header' in sections.keys():
+ self.write("found section:header")
+ else:
+ self.write("File contains no section:header!")
+
+ if self.var['optimization'] == 0: self.var['one_mesh_on'] = 0
+ # The section:tables may be partialy or completely missing.
+ self.layersTable = False
+ self.colMaterials = MatColors({}) #A container for dxf-color based materials
+ self.layMaterials = MatLayers({}) #A container for dxf-layer based materials
+ #self.collayMaterials = MatColLayers({}) #A container for dxf-color+layer based materials
+ global layersmap, layernamesmap
+ layersmap, layernamesmap = {}, {}
+ if 'tables' in sections.keys():
+ self.write("found section:tables")
+ views, vports, layers = False, False, False
+ for table in drawing.tables.data:
+ if table.name == 'layer':
+ self.write("found table:layers")
+ layers = table
+ elif table.name == 'view':
+ print "found table:view"
+ views = table
+ elif table.name == 'vport':
+ print "found table:vport"
+ vports = table
+ if layers: #----------------------------------
+ # Read the layers table and get the layer colors
+ layersmap, layernamesmap = getLayersmap(layers)
+ self.colMaterials = MatColors(layersmap)
+ self.layMaterials = MatLayers(layersmap)
+ else:
+ self.write("File contains no table:layers!")
+
+
+ if views: #----------------------------------
+ if self.var['views_on']:
+ global oblist
+ for item in views.data:
+ if type(item) != list and item.type == 'view':
+ #print 'deb:settings_valid views dir(item)=', dir(item) #-------------
+ #print 'deb:settings_valid views item=', item #-------------
+ ob = item.draw(self)
+ #viewsmap[item.name] = [item.length]
+ #--todo-- add to obj_list for global.Scaling
+ insertFlag, blockFlag = False, False
+ oblist.append((ob, insertFlag, blockFlag))
+
+ else:
+ self.write("File contains no table:views!")
+
+
+ if vports: #----------------------------------
+ if self.var['views_on']:
+ global oblist
+ for item in vports.data:
+ if type(item) != list and item.type == 'vport':
+ #print 'deb:settings_valid views dir(item)=', dir(item) #-------------
+ #print 'deb:settings_valid views item=', item #-------------
+ ob = item.draw(self)
+ #viewsmap[item.name] = [item.length]
+ #--todo-- add to obj_list for global.Scaling
+ insertFlag, blockFlag = False, False
+ oblist.append((ob, insertFlag, blockFlag))
+ else:
+ self.write("File contains no table:vports!")
+
+
+ else:
+ self.write("File contains no section:tables!")
+ self.write("File contains no table:layers!")
+
+
+ # The section:blocks may be omited
+ if 'blocks' in sections.keys():
+ self.write("found section:blocks")
+ # Read the block definitions and build our block object
+ if self.drawTypes['insert']: #if support for entity type 'Insert' is activated
+ #Build a dictionary of blockname:block_data pairs
+ blocksmap, self.obj_number = getBlocksmap(drawing, layersmap, self.var['layFrozen_on'])
+ self.blocknamesmap = getBlocknamesmap(blocksmap)
+ self.blocks = Blocks(blocksmap, self) # initiates container for blocks_data
+ self.usedBlocks = blocksmap.keys()
+ #print 'deb:settings_valid self.usedBlocks', self.usedBlocks #----------
+ else:
+ self.write("ignored, because support for BLOCKs is turn off!")
+ #print 'deb:settings_valid self.obj_number', self.obj_number #----------
+ else:
+ self.write("File contains no section:blocks!")
+ self.drawTypes['insert'] = False
+
+ # The section:entities
+ if 'entities' in sections.keys():
+ self.write("found section:entities")
+
+ self.obj_number += len(drawing.entities.data)
+ #print 'deb:settings_valid self.obj_number', self.obj_number #----------
+ self.obj_number = 1.0 / self.obj_number
+
+
+ def accepted_block(self, name):
+ if name not in self.usedBlocks: return False
+ if name in self.unwantedBlocks: return False
+ elif name in self.acceptedBlocks: return True
+ #elif (name.find('*X')+1): return False
+ #elif name.startswith('3'): return True
+ #elif name.endswith('H'): return False
+ return True
+
+
+ def write(self, text, newline=True):
+ """Wraps the built-in print command in a optimization check.
+ """
+ if self.var['optimization'] <= self.MID:
+ if newline:
+ print text
+ else:
+ print text,
+
+
+ def redraw(self):
+ """Update Blender if optimization level is low enough.
+ """
+ if self.var['optimization'] <= self.MIN:
+ Blender.Redraw()
+
+
+ def progress(self, done, text):
+ """Wrapper for Blender.Window.DrawProgressBar.
+ """
+ if self.var['optimization'] <= self.PRO:
+ progressbar = done * self.obj_number
+ Window.DrawProgressBar(progressbar, text)
+ #print 'deb:drawer done, progressbar: ', done, progressbar #-----------------------
+
+ def layer_isOff(self, layername): # no more used -------
+ """Given a layer name, and return its visible status.
+ """
+ # if layer is off then color_index is negative
+ if layersmap and layersmap[layername].color < 0: return True
+ #print 'deb:layer_isOff: layer is ON' #---------------
+ return False
+
+
+ def layer_isFrozen(self, layername): # no more used -------
+ """Given a layer name, and return its frozen status.
+ """
+ if layersmap and layersmap[layername].frozen: return True
+ #print 'deb:layer_isFrozen: layer is not FROZEN' #---------------
+ return False
+
+
+
+def analyzeDXF(dxfFile): #---------------------------------------
+ """list statistics about LAYER and BLOCK dependences into textfile.INF
+
+ """
+ Window.WaitCursor(True) # Let the user know we are thinking
+ print 'reading DXF file: %s.' % dxfFile
+ time1 = Blender.sys.time() #time marker1
+ drawing = readDXF(dxfFile, objectify)
+ print 'finish reading in %.4f sec.' % (Blender.sys.time()-time1)
+
+ # First sort out all the section_items
+ sections = dict([(item.name, item) for item in drawing.data])
+
+ # The section:header may be omited
+ if 'header' in sections.keys(): print "found section:header"
+ else: print "File contains no section:header!"
+
+ # The section:tables may be partialy or completely missing.
+ layersTable = False
+ global layersmap
+ layersmap = {}
+ viewsmap = {}
+ vportsmap = {}
+ layersmap_str = '#File contains no table:layers!'
+ viewsmap_str = '#File contains no table:views!'
+ vportsmap_str = '#File contains no table:vports!'
+ if 'tables' in sections.keys():
+ print "found section:tables"
+ views, vports, layers = False, False, False
+ for table in drawing.tables.data:
+ if table.name == 'layer':
+ print "found table:layers"
+ layers = table
+ elif table.name == 'view':
+ print "found table:view"
+ views = table
+ elif table.name == 'vport':
+ print "found table:vport"
+ vports = table
+ if layers: #----------------------------------
+ for item in layers.data:
+ if type(item) != list and item.type == 'layer':
+ #print dir(item)
+ layersmap[item.name] = [item.color, item.frozen]
+ #print 'deb:analyzeDXF: layersmap=' , layersmap #-------------
+ layersmap_str = '#list of LAYERs: name, color, frozen_status ---------------------------\n'
+ key_list = layersmap.keys()
+ key_list.sort()
+ for key in key_list:
+ #for layer_name, layer_data in layersmap.iteritems():
+ layer_name, layer_data = key, layersmap[key]
+ layer_str = '\'%s\': col=%s' %(layer_name,layer_data[0])#-------------
+ if layer_data[1]: layer_str += ', frozen'
+ layersmap_str += layer_str + '\n'
+ #print 'deb:analyzeDXF: layersmap_str=\n' , layersmap_str #-------------
+ else:
+ print "File contains no table:layers!"
+
+ if views: #----------------------------------
+ for item in views.data:
+ if type(item) != list and item.type == 'view':
+ #print dir(item)
+ viewsmap[item.name] = [item.length]
+ #print 'deb:analyzeDXF: viewsmap=' , viewsmap #-------------
+ viewsmap_str = '#list of VIEWs: name, focus_length ------------------------------------\n'
+ key_list = viewsmap.keys()
+ key_list.sort()
+ for key in key_list:
+ #for view_name, view_data in viewsmap.iteritems():
+ view_name, view_data = key, viewsmap[key]
+ view_str = '\'%s\': length=%s' %(view_name,view_data[0])#-------------
+ #if view_data[1]: view_str += ', something'
+ viewsmap_str += view_str + '\n'
+ #print 'deb:analyzeDXF: layersmap_str=\n' , layersmap_str #-------------
+ else:
+ print "File contains no table:views!"
+
+ if vports: #----------------------------------
+ for item in vports.data:
+ if type(item) != list and item.type == 'vport':
+ #print dir(item)
+ vportsmap[item.name] = [item.length]
+ #print 'deb:analyzeDXF: vportsmap=' , vportsmap #-------------
+ vportsmap_str = '#list of VPORTs: name, focus_length -----------------------------------\n'
+ key_list = vportsmap.keys()
+ key_list.sort()
+ for key in key_list:
+ #for vport_name, vport_data in vportsmap.iteritems():
+ vport_name, vport_data = key, vportsmap[key]
+ vport_str = '\'%s\': length=%s' %(vport_name,vport_data[0])#-------------
+ #if vport_data[1]: vport_str += ', something'
+ vportsmap_str += vport_str + '\n'
+ #print 'deb:analyzeDXF: vportsmap_str=\n' , vportsmap_str #-------------
+ else:
+ print "File contains no table:vports!"
+
+ else:
+ print "File contains no section:tables!"
+ print "File contains no tables:layers,views,vports!"
+
+ # The section:blocks may be omited
+ if 'blocks' in sections.keys():
+ print "found section:blocks"
+ blocksmap = {}
+ for item in drawing.blocks.data:
+ #print 'deb:getBlocksmap item=' ,item #--------
+ #print 'deb:getBlocksmap item.entities=' ,item.entities #--------
+ #print 'deb:getBlocksmap item.entities.data=' ,item.entities.data #--------
+ if type(item) != list and item.type == 'block':
+ xref = False
+ if item.xref: xref = True
+ childList = []
+ used = False
+ for item2 in item.entities.data:
+ if type(item2) != list and item2.type == 'insert':
+ #print 'deb:getBlocksmap dir(item2)=', dir(item2) #----------
+ item2str = [item2.name, item2.layer, item2.color_index, item2.scale, item2.space]
+ childList.append(item2str)
+ try: blocksmap[item.name] = [used, childList, xref]
+ except KeyError: print 'Cannot map "%s" - "%s" as Block!' %(item.name, item)
+ #print 'deb:analyzeDXF: blocksmap=' , blocksmap #-------------
+
+ for item2 in drawing.entities.data:
+ if type(item2) != list and item2.type == 'insert':
+ if not layersmap or (layersmap and not layersmap[item2.layer][1]): #if insert_layer is not frozen
+ blocksmap[item2.name][0] = True # marked as world used BLOCK
+
+ key_list = blocksmap.keys()
+ key_list.reverse()
+ for key in key_list:
+ if blocksmap[key][0]: #if used
+ for child in blocksmap[key][1]:
+ if not layersmap or (layersmap and not layersmap[child[1]][1]): #if insert_layer is not frozen
+ blocksmap[child[0]][0] = True # marked as used BLOCK
+
+ blocksmap_str = '#list of BLOCKs: name:(unused)(xref) -[child_name, layer, color, scale, space]-------\n'
+ key_list = blocksmap.keys()
+ key_list.sort()
+ for key in key_list:
+ #for block_name, block_data in blocksmap.iteritems():
+ block_name, block_data = key, blocksmap[key]
+ block_str = '\'%s\': ' %(block_name) #-------------
+ used = '(unused)'
+ if block_data[0]: used = ''
+# else: used = '(unused)'
+ xref = ''
+ if block_data[2]: xref = '(xref)'
+ blocksmap_str += block_str + used + xref +'\n'
+ if block_data:
+ for block_item in block_data[1]:
+ block_data_str = ' - %s\n' %block_item
+ blocksmap_str += block_data_str
+ #print 'deb:analyzeDXF: blocksmap_str=\n' , blocksmap_str #-------------
+ else:
+ blocksmap_str = '#File contains no section:blocks!'
+ print "File contains no section:blocks!"
+
+ Window.WaitCursor(False)
+ output_str = '%s\n%s\n%s\n%s' %(viewsmap_str, vportsmap_str, layersmap_str, blocksmap_str)
+ infFile = dxfFile[:-4] + '_DXF.INF' # replace last char:'.dxf' with '_DXF.inf'
+ try:
+ f = file(infFile, 'w')
+ f.write(INFFILE_HEADER + '\n# this is a comment line\n\n')
+ f.write(output_str)
+ f.close()
+ Draw.PupMenu('DXF importer: report saved in INF-file:%t|' + '\'%s\'' %infFile)
+ except:
+ Draw.PupMenu('DXF importer: ERROR by writing report in INF-file:%t|' + '\'%s\'' %infFile)
+ finally:
+ f.close()
+
+
+
+
+def main(dxfFile): #---------------#############################-----------
+ #print 'deb:filename:', filename #--------------
+ global SCENE
+ editmode = Window.EditMode() # are we in edit mode? If so ...
+ if editmode:
+ Window.EditMode(0) # leave edit mode before
+
+ #SCENE = bpy.data.scenes.active
+ #SCENE.objects.selected = [] # deselect all
+
+ global cur_COUNTER #counter for progress_bar
+ cur_COUNTER = 0
+
+ try:
+ #print "Getting settings..."
+ global GUI_A, GUI_B, g_scale_as
+ if not GUI_A['g_scale_on'].val:
+ GUI_A['g_scale'].val = 1.0
+
+ keywords = {}
+ drawTypes = {}
+ for k, v in GUI_A.iteritems():
+ keywords[k] = v.val
+ for k, v in GUI_B.iteritems():
+ drawTypes[k] = v.val
+ #print 'deb:startUInew keywords: ', keywords #--------------
+ #print 'deb:startUInew drawTypes: ', drawTypes #--------------
+
+ # The settings object controls how dxf entities are drawn
+ settings.update(keywords, drawTypes)
+ #print 'deb:settings.var:\n', settings.var #-----------------------
+
+ if not settings:
+ #Draw.PupMenu('DXF importer: EXIT!%t')
+ #print '\nDXF Import: terminated by user!'
+ print '\nDXF Import: terminated, cause settings failure!'
+ Window.WaitCursor(False)
+ if editmode: Window.EditMode(1) # and put things back how we fond them
+ return None
+
+ #no more used dxfFile = dxfFileName.val
+ #print 'deb: dxfFile file: ', dxfFile #----------------------
+ if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile):
+ Window.WaitCursor(True) # Let the user know we are thinking
+ print 'reading file: %s.' % dxfFile
+ time1 = Blender.sys.time() #time marker1
+ drawing = readDXF(dxfFile, objectify)
+ print 'reading finished in %.4f sec.' % (Blender.sys.time()-time1)
+ Window.WaitCursor(False)
+ else:
+ if UI_MODE: Draw.PupMenu('DXF importer: Alert!%t| no valid DXF-file selected!')
+ print "DXF importer: Alert! - no valid DXF-file selected."
+ Window.WaitCursor(False)
+ if editmode: Window.EditMode(1) # and put things back how we fond them
+ return None
+
+ # Draw all the know entity types in the current scene
+ global oblist
+ oblist = [] # a list of all created AND linked objects for final f_globalScale
+ time2 = Blender.sys.time() #time marker2
+
+ Window.WaitCursor(True) # Let the user know we are thinking
+ settings.write("\n\nDrawing entities...")
+
+ settings.validate(drawing)
+
+ global activObjectLayer, activObjectName
+ activObjectLayer, activObjectName = None, None
+
+ drawEntities(drawing.entities, settings)
+
+ #print 'deb:drawEntities after: oblist:', oblist #-----------------------
+ if oblist: # and settings.var['g_scale'] != 1:
+ globalScale(oblist, settings.var['g_scale'])
+
+ # Set visibility for all layers on all View3d
+ #Window.ViewLayers([i+1 for i in range(18)]) # for 2.45
+ SCENE.setLayers([i+1 for i in range(18)])
+ SCENE.update(1)
+ SCENE.objects.selected = [i[0] for i in oblist] #select only the imported objects
+ #SCENE.objects.selected = SCENE.objects #select all objects in current scene
+ Blender.Redraw()
+
+ time_text = Blender.sys.time() - time2
+ Window.WaitCursor(False)
+ if settings.var['paper_space_on']: space = 'from paper space'
+ else: space = 'from model space'
+ ob_len = len(oblist)
+ message = ' %s objects imported %s in %.4f sec. -----DONE-----' % (ob_len, space, time_text)
+ settings.progress(1.0/settings.obj_number, 'DXF import done!')
+ print message
+ #settings.write(message)
+ if UI_MODE: Draw.PupMenu('DXF importer: Done!|finished in %.4f sec.' % time_text)
+
+ finally:
+ # restore state even if things didn't work
+ #print 'deb:drawEntities finally!' #-----------------------
+ Window.WaitCursor(False)
+ if editmode: Window.EditMode(1) # and put things back how we fond them
+
+
+
+def getOCS(az): #-----------------------------------------------------------------
+ """An implimentation of the Arbitrary Axis Algorithm.
+ """
+ #decide if we need to transform our coords
+ #if az[0] == 0 and az[1] == 0:
+ if abs(az[0]) < 0.00001 and abs(az[1]) < 0.00001:
+ if az[2] > 0.0:
+ return False
+ elif az[2] < 0.0:
+ ax = Mathutils.Vector(-1.0, 0, 0)
+ ay = Mathutils.Vector(0, 1.0, 0)
+ az = Mathutils.Vector(0, 0, -1.0)
+ return ax, ay, az
+
+ az = Mathutils.Vector(az)
+
+ cap = 0.015625 # square polar cap value (1/64.0)
+ if abs(az.x) < cap and abs(az.y) < cap:
+ ax = Mathutils.CrossVecs(WORLDY, az)
+ else:
+ ax = Mathutils.CrossVecs(WORLDZ, az)
+ ax = ax.normalize()
+ ay = Mathutils.CrossVecs(az, ax)
+ ay = ay.normalize()
+ return ax, ay, az
+
+
+
+def transform(normal, rotation, obj): #--------------------------------------------
+ """Use the calculated ocs to determine the objects location/orientation in space.
+
+ Quote from dxf docs:
+ The elevation value stored with an entity and output in DXF files is a sum
+ of the Z-coordinate difference between the UCS XY plane and the OCS XY
+ plane, and the elevation value that the user specified at the time the entity
+ was drawn.
+ """
+ ma = Mathutils.Matrix([1,0,0],[0,1,0],[0,0,1])
+ o = Mathutils.Vector(obj.loc)
+ ocs = getOCS(normal)
+ if ocs:
+ ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2])
+ o = ma.invert() * o
+ ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2])
+
+ if rotation != 0:
+ g = radians(-rotation)
+ rmat = Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1])
+ ma = rmat * ma
+
+ obj.setMatrix(ma)
+ obj.loc = o
+ #print 'deb:new obj.matrix:\n', obj.getMatrix() #--------------------
+
+
+
+def rotXY_Vec(rotation, vec): #----------------------------------------------------
+ """Rotate vector vec in XY-plane. vec must be in radians
+ """
+ if rotation != 0:
+ o = Mathutils.Vector(vec)
+ g = radians(-rotation)
+ vec = o * Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1])
+ return vec
+
+
+
+def getLayersmap(layers): #------------------------------------------------------
+ """Build two dictionaries: 1.layername:layer object, and 2.layername:layername_short
+ """
+ layersmap = {}
+ layernamesmap = {}
+ for item in layers.data:
+ if type(item) != list and item.type == 'layer':
+ layersmap[item.name] = item
+ layername_short = item.name[:MAX_NAMELENGTH-1]
+ i = 0 #sufix for layernames cause Blender-objectnames-limits
+ while layername_short in layernamesmap.keys():
+ i += 1
+ suffix = str(i)
+ layername_short = layername_short[:-2] + suffix
+ layernamesmap[item.name] = layername_short
+
+ #print 'deb:getLayersmap layersmap:\n', layersmap #------------
+ #print 'deb:getLayersmap layernamesmap:\n', layernamesmap #------------
+ return layersmap, layernamesmap
+
+
+
+def getBlocksmap(drawing, layersmap, layFrozen_on=False): #--------------------------------------------------------
+ """Build a dictionary of blockname:block_data pairs
+ """
+ usedblocks = {}
+ for item in drawing.blocks.data:
+ #print 'deb:getBlocksmap item=%s\n i.entities=%s\n i.data=%s' %(item,item.entities,item.entities.data)
+ if type(item) != list and item.type == 'block':
+ childList = []
+ used = False
+ for item2 in item.entities.data:
+ if type(item2) != list and item2.type == 'insert':
+ #print 'deb:getBlocksmap dir(item2)=', dir(item2) #----------
+ item2str = [item2.name, item2.layer]
+ childList.append(item2str)
+ try: usedblocks[item.name] = [used, childList]
+ except KeyError: print 'Cannot map "%s" - "%s" as Block!' %(item.name, item)
+ #print 'deb:getBlocksmap: usedblocks=' , usedblocks #-------------
+ print 'deb:getBlocksmap: layersmap=' , layersmap #-------------
+
+ for item in drawing.entities.data:
+ if type(item) != list and item.type == 'insert':
+ if not layersmap or (not layersmap[item.layer].frozen or layFrozen_on): #if insert_layer is not frozen
+ try: usedblocks[item.name][0] = True
+ except: pass
+
+ key_list = usedblocks.keys()
+ key_list.reverse()
+ for key in key_list:
+ if usedblocks[key][0]: #if parent used, then set used also all child blocks
+ for child in usedblocks[key][1]:
+ if not layersmap or (layersmap and not layersmap[child[1]].frozen): #if insert_layer is not frozen
+ usedblocks[child[0]][0] = True # marked as used BLOCK
+
+ usedblocks = [i for i in usedblocks.keys() if usedblocks[i][0]]
+ #print 'deb:getBlocksmap: usedblocks=' , usedblocks #-------------
+ obj_number = 0
+ blocksmap = {}
+ for item in drawing.blocks.data:
+ if type(item) != list and item.type == 'block' and item.name in usedblocks:
+ #if item.name.startswith('*X'): #--todo--
+ obj_number += len(item.entities.data)
+ try: blocksmap[item.name] = item
+ except KeyError: print 'Cannot map "%s" - "%s" as Block!' %(item.name, item)
+
+
+ #print 'deb:getBlocksmap: blocksmap:\n', blocksmap #------------
+ return blocksmap, obj_number
+
+
+def getBlocknamesmap(blocksmap): #--------------------------------------------------------
+ """Build a dictionary of blockname:blockname_short pairs
+ """
+ #print 'deb:getBlocknamesmap blocksmap:\n', blocksmap #------------
+ blocknamesmap = {}
+ for n in blocksmap.keys():
+ blockname_short = n[:MAX_NAMELENGTH-1]
+ i = 0 #sufix for blockname cause Blender-objectnamelength-limit
+ while blockname_short in blocknamesmap.keys():
+ i += 1
+ suffix = str(i)
+ blockname_short = blockname_short[:-2] + suffix
+ blocknamesmap[n] = blockname_short
+ #print 'deb:getBlocknamesmap blocknamesmap:\n', blocknamesmap #------------
+ return blocknamesmap
+
+
+def drawEntities(entities, settings, block_def=None): #----------------------------------------
+ """Draw every kind of thing in the entity list.
+
+ If provided 'block_def': the entities are to be added to the Blender 'group'.
+ """
+ for _type in type_map.keys():
+ #print 'deb:drawEntities_type:', _type #------------------
+ # for each known type get a list of that type and call the associated draw function
+ entities_type = entities.get_type(_type)
+ if entities_type: drawer(_type, entities_type, settings, block_def)
+
+
+def drawer(_type, entities, settings, block_def): #------------------------------------------
+ """Call with a list of entities and a settings object to generate Blender geometry.
+
+ If 'block_def': the entities are to be added to the Blender 'group'.
+ """
+ #print 'deb:drawer _type, entities:\n ', _type, entities #-----------------------
+
+ if entities:
+ # Break out early if settings says we aren't drawing the current dxf-type
+ global cur_COUNTER #counter for progress_bar
+ group = None
+ #print 'deb:drawer.check:_type: ', _type #--------------------
+ if _type == '3dface':_type = 'face' # hack, while python_variable_name can not beginn with a nummber
+ if not settings.drawTypes[_type] or _type == 'block_record':
+ message = 'Skipping dxf\'%ss\' entities' %_type
+ settings.write(message, True)
+ cur_COUNTER += len(entities)
+ settings.progress(cur_COUNTER, message)
+ return
+ #print 'deb:drawer.todo:_type:', _type #-----------------------
+ #print 'deb:drawer entities:\n ', entities #-----------------------
+
+ len_temp = len(entities)
+ # filtering only model-space enitities (no paper-space enitities)
+ if settings.var['paper_space_on']:
+ entities = [entity for entity in entities if entity.space != 0]
+ else:
+ entities = [entity for entity in entities if entity.space == 0]
+
+ # filtering only objects with color from acceptedColorsList
+ if settings.var['colorFilter_on']:
+ entities = [entity for entity in entities if entity.color in settings.acceptedColors]
+
+ # filtering only objects on layers from acceptedLayersList
+ if settings.var['layerFilter_on']:
+ #entities = [entity for entity in entities if entity.layer[0] in ['M','3','0'] and not entity.layer.endswith('H')]
+ entities = [entity for entity in entities if entity.layer in settings.acceptedLayers]
+
+ # filtering only objects on not-frozen layers
+ if layersmap and not settings.var['layFrozen_on']:
+ entities = [entity for entity in entities if not layersmap[entity.layer].frozen]
+
+ global activObjectLayer, activObjectName
+ activObjectLayer = ''
+ activObjectName = ''
+
+ message = "Drawing dxf\'%ss\'..." %_type
+ cur_COUNTER += len_temp - len(entities)
+ settings.write(message, False)
+ settings.progress(cur_COUNTER, message)
+ if len(entities) > 0.1 / settings.obj_number:
+ show_progress = int(0.03 / settings.obj_number)
+ else: show_progress = 0
+ cur_temp = 0
+
+ #print 'deb:drawer cur_COUNTER: ', cur_COUNTER #-----------------------
+
+ for entity in entities: #----loop-------------------------------------
+ settings.write('\b.', False)
+ cur_COUNTER += 1
+ if show_progress:
+ cur_temp += 1
+ if cur_temp == show_progress:
+ settings.progress(cur_COUNTER, message)
+ cur_temp = 0
+ #print 'deb:drawer show_progress=',show_progress #----------------
+
+ # get the layer group (just to make things a little cleaner)
+ if settings.var['group_bylayer_on'] and not block_def:
+ group = getGroup('l:%s' % layernamesmap[entity.layer])
+
+ if _type == 'insert': #---- INSERT and MINSERT=array --------------------
+ if not settings.var['block_nn'] and entity.name.startswith('*X'): #---- support for noname BLOCKs
+ #print 'deb:drawer entity.name:', entity.name #------------
+ continue
+ elif settings.var['blockFilter_on'] and not settings.accepted_block(entity.name):
+ continue
+
+ #print 'deb:insert entity.loc:', entity.loc #----------------
+ insertFlag = True
+ columns = entity.columns[0]
+ coldist = entity.columns[1]
+ rows = entity.rows[0]
+ rowdist = entity.rows[1]
+ deltaloc = [0,0,0]
+ #print 'deb:insert columns, rows:', columns, rows #-----------
+ for col in xrange(columns):
+ deltaloc[0] = col * coldist
+ for row in xrange(rows):
+ deltaloc[1] = row * rowdist
+ #print 'deb:insert col=%s, row=%s,deltaloc=%s' %(col, row, deltaloc) #------
+ ob = entity.draw(settings, deltaloc) #-----draw BLOCK----------
+ if block_def:
+ blockFlag = True
+ bl_loc = block_def[1]
+ ob.loc = [ob.loc[0]-bl_loc[0],ob.loc[1]-bl_loc[1],ob.loc[2]-bl_loc[2]]
+ else: blockFlag = False
+ setObjectProperties(ob, group, entity, settings, block_def)
+ if ob:
+ if settings.var['optimization'] <= settings.MIN:
+ #if settings.var['g_origin_on'] and not block_def: ob.loc = Mathutils.Vector(ob.loc) + settings.g_origin
+ if settings.var['g_scale_on']: globalScaleOne(ob, insertFlag, blockFlag, settings.var['g_scale'])
+ settings.redraw()
+ else: oblist.append((ob, insertFlag, blockFlag))
+
+ else: #---draw entities except BLOCKs/INSERTs---------------------
+ insertFlag = False
+ alt_obname = activObjectName
+ ob = entity.draw(settings)
+ if ob and ob.name != alt_obname:
+ if block_def:
+ blockFlag = True
+ bl_loc = block_def[1]
+ ob.loc = [ob.loc[0]-bl_loc[0],ob.loc[1]-bl_loc[1],ob.loc[2]-bl_loc[2]]
+ else: blockFlag = False
+ setObjectProperties(ob, group, entity, settings, block_def)
+ if settings.var['optimization'] <= settings.MIN:
+ #if settings.var['g_origin_on'] and not block_def: ob.loc = Mathutils.Vector(ob.loc) + settings.g_origin
+ if settings.var['g_scale_on']: globalScaleOne(ob, insertFlag, blockFlag, settings.var['g_scale'])
+ settings.redraw()
+ else: oblist.append((ob, insertFlag, blockFlag))
+
+ #print 'deb:Finished drawing:', entities[0].type #------------------------
+ message = "\nDrawing dxf\'%ss\' done!" % _type
+ settings.write(message, True)
+
+
+
+def globalScale(oblist, SCALE): #---------------------------------------------------------
+ """Global_scale for list of all imported objects.
+
+ oblist is a list of pairs (ob, insertFlag), where insertFlag=True/False
+ """
+ #print 'deb:globalScale.oblist: ---------%\n', oblist #---------------------
+ for l in oblist:
+ ob, insertFlag, blockFlag = l[0], l[1], l[2]
+ globalScaleOne(ob, insertFlag, blockFlag, SCALE)
+
+
+def globalScaleOne(ob, insertFlag, blockFlag, SCALE): #---------------------------------------------------------
+ """Global_scale imported object.
+ """
+ #print 'deb:globalScaleOne ob: ', ob #---------------------
+ if settings.var['g_origin_on'] and not blockFlag:
+ ob.loc = Mathutils.Vector(ob.loc) + settings.g_origin
+
+ SCALE_MAT= Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
+ if insertFlag: # by BLOCKs/INSERTs only insert-point coords must be scaled------------
+ ob.loc = Mathutils.Vector(ob.loc) * SCALE_MAT
+ else: # entire scaling for all other imported objects ------------
+ if ob.type == 'Mesh':
+ me = Mesh.Get(ob.name)
+ # set centers of all objects in (0,0,0)
+ #me.transform(ob.matrixWorld*SCALE_MAT)
+ #ob.loc = Mathutils.Vector([0,0,0])
+ # preseve centers of all objects
+ me.transform(SCALE_MAT)
+ ob.loc = Mathutils.Vector(ob.loc) * SCALE_MAT
+ else: #--todo-- also for curves: neutral scale factor after import
+ ob.setMatrix(ob.matrixWorld*SCALE_MAT)
+
+
+def setObjectProperties(ob, group, entity, settings, block_def): #-----------------------
+ """Link object to scene.
+ """
+
+ if not ob: #remi--todo-----------------------
+ message = "\nObject \'%s\' not found!" %entity
+ settings.write(message)
+ return
+
+ if group:
+ setGroup(group, ob) # if object belongs to group
+
+ if block_def: # if object belongs to BLOCK_def - Move it to layer nr19
+ setGroup(block_def[0], ob)
+ #print 'deb:setObjectProperties \'%s\' set to block_def_group!' %ob.name #---------
+ ob.layers = [19]
+ else:
+ #ob.layers = [i+1 for i in xrange(20)] #remi--todo------------
+ ob.layers = [settings.var['target_layer']]
+
+ # Set material for any objects except empties
+ if ob.type != 'Empty' and settings.var['material_on']:
+ setMaterial_from(entity, ob, settings, block_def)
+
+ # Set the visibility
+ #if settings.layer_isOff(entity.layer):
+ if layersmap and layersmap[entity.layer].color < 0: # color is negative if layer is off
+ #ob.layers = [20] #remi--todo-------------
+ ob.restrictDisplay = True
+ ob.restrictRender = True
+
+ #print 'deb:\n---------linking Object %s!' %ob.name #----------
+
+
+
+def getGroup(name): #-----------------------------------------------------------------
+ """Returns a Blender group-object.
+ """
+ try:
+ group = Group.Get(name)
+ except: # What is the exception?
+ group = Group.New(name)
+ return group
+
+
+def setGroup(group, ob): #------------------------------------------------------------
+ """Assigns object to Blender group.
+ """
+ try:
+ group.objects.link(ob)
+ except:
+ group.objects.append(ob) #remi?---------------
+
+
+
+def setMaterial_from(entity, ob, settings, block_def): #------------------------------------------------
+ """ Set Blender-material for the object controled by item.
+
+ Set Blender-material for the object
+ - controlled by settings.var['material_from']
+ """
+ if settings.var['material_from'] == 1: # 1= material from color
+ if entity.color_index == BYLAYER or entity.color_index == 256:
+ mat = settings.colMaterials(entity.layer)
+ elif entity.color_index == BYBLOCK or entity.color_index == 0:
+ #--todo-- looking for block.color_index
+ #mat = settings.colMaterials(block.color_index)
+ #if block_def: mat = settings.colMaterials(block_def[2])
+ mat = settings.colMaterials(3)
+ else:
+ mat = settings.colMaterials(entity.color_index)
+
+ elif settings.var['material_from'] == 2: # 2= material from layer_name
+ mat = settings.layMaterials(layername = entity.layer)
+
+ elif settings.var['material_from'] == 3: # 3= material from layer+color
+ mat = settings.layMaterials(layername=entity.layer, color=entity.color_index)
+
+# elif settings.var['material_from'] == 4: # 4= material from block_name
+
+# elif settings.var['material_from'] == 5: # 5= material from XDATA
+
+# elif settings.var['material_from'] == 6: # 6= material from INI-file
+
+ else: # set neutral material
+ try:
+ mat = Material.Get('dxf-neutral')
+ except:
+ mat = Material.New('dxf-neutral')
+ mat.setRGBCol(color_map[3])
+ try:mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc1-bug
+ except:
+ mat.mode |= Material.Modes.SHADELESS #
+ mat.mode |= Material.Modes.WIRE
+ try:
+ #print 'deb:material mat:', mat #-----------
+ ob.setMaterials([mat]) #assigns Blender-material to object
+ except ValueError:
+ settings.write("material error - \'%s\'!" %mat)
+ ob.colbits = 0x01 # Set OB materials.
+
+
+
+def calcBulge(p1, p2, arc_res, triples=False): #-------------------------------------------------
+ """given startpoint, endpoint and bulge of arc, returns points/segments of its representation.
+
+ Needs to take into account bulge sign.
+ negative = clockwise
+ positive = counter-clockwise
+
+ to find center given two points, and arc angle
+ calculate radius
+ Cord = sqrt(start^2 + end^2)
+ S = (bulge*Cord)/2
+ radius = ((Cord/2)^2+S^2)/2*S
+ angle of arc = 4*atan( bulge )
+ angle from p1 to center is (180-angle)/2
+ get vector pointing from p1 to p2 (p2 - p1)
+ normalize it and multiply by radius
+ rotate around p1 by angle to center, point to center.
+ start angle = angle between (center - p1) and worldX
+ end angle = angle between (center - p2) and worldX
+
+ calculate the center, radius, start angle, and end angle
+ returns points/segments of its mesh representation
+ incl.startpoint, without endpoint
+ """
+
+ bulge = p1.bulge
+ p1 = Mathutils.Vector(p1.loc)
+ p2 = Mathutils.Vector(p2.loc)
+ cord = p2 - p1 # vector from p1 to p2
+ clength = cord.length
+ s = (bulge * clength)/2.0 # sagitta (height)
+ radius = abs(((clength/2.0)**2.0 + s**2.0)/(2.0*s)) # magic formula
+ angle = (degrees(4.0*atan(bulge))) # theta (included angle)
+ radial = cord.normalize() * radius # a radius length vector aligned with cord
+ delta = (180.0 - abs(angle))/2.0 # the angle from cord to center
+ if bulge < 0: delta = -delta
+ rmat = Mathutils.RotationMatrix(-delta, 3, 'Z')
+ center = p1 + (rmat * radial) # rotate radial by delta degrees, then add to p1 to find center
+ #length = radians(abs(angle)) * radius
+ #print 'deb:calcBulge:\n angle, delta: ', angle, delta #----------------
+ #print 'deb:center, radius: ', center, radius #----------------------
+ startpoint = p1 - center
+ endpoint = p2 - center
+ #print 'deb:calcBulg: startpoint:', startpoint #---------
+ #print 'deb:calcBulg: endpoint:', endpoint #---------
+
+ if not triples: #IF mesh-representation -----------
+ if arc_res > 1024: arc_res = 1024
+ elif arc_res < 4: arc_res = 4
+ pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION
+ if pieces < 3: pieces = 3
+ else: #IF curve-representation -------------------------------
+ if arc_res > 32: arc_res = 32
+ elif arc_res < 3: arc_res = 3
+ pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION
+ if pieces < 2: pieces = 2
+
+ step = angle/pieces # set step so pieces * step = degrees in arc
+ stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z")
+
+ if not triples: #IF mesh-representation -----------
+ points = [startpoint]
+ point = startpoint
+ for i in xrange(int(pieces)-1): #fast (but not so acurate as: vector * RotMatrix(-step*i,3,"Z")
+ point = stepmatrix * point
+ points.append(point)
+ points = [ point+center for point in points]
+ # vector to point convertion:
+ points = [list(point) for point in points]
+ return points, list(center)
+
+ else: #IF curve-representation -------------------------------
+ # correct Bezier curves representation for free segmented circles/arcs
+ step2 = radians(step * 0.5)
+ bulg = radius * (1 - cos(step2))
+ deltaY = 4.0 * bulg / (3.0 * sin(step2) )
+ #print 'deb:calcArcCurve: bulg, deltaY:\n', bulg, deltaY #---------
+ #print 'deb:calcArcCurve: step:\n', step #---------
+
+ #org handler0 = Mathutils.Vector(0.0, -deltaY, 0.0)
+ #handler = startmatrix * handler0
+ #endhandler = endmatrix * handler0
+ rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1])
+ handler = rotMatr90 * startpoint
+ handler = - deltaY * handler.normalize()
+ endhandler = rotMatr90 * endpoint
+ endhandler = - deltaY * endhandler.normalize()
+
+ points = [startpoint]
+ handlers1 = [startpoint + handler]
+ handlers2 = [startpoint - handler]
+ point = Mathutils.Vector(startpoint)
+ for i in xrange(int(pieces)-1):
+ point = stepmatrix * point
+ handler = stepmatrix * handler
+ handler1 = point + handler
+ handler2 = point - handler
+ points.append(point)
+ handlers1.append(handler1)
+ handlers2.append(handler2)
+ points.append(endpoint)
+ handlers1.append(endpoint + endhandler)
+ handlers2.append(endpoint - endhandler)
+
+ points = [point + center for point in points]
+ handlers1 = [point + center for point in handlers1]
+ handlers2 = [point + center for point in handlers2]
+
+ VectorTriples = [list(h1)+list(p)+list(h2) for h1,p,h2 in zip(handlers1, points, handlers2)]
+ #print 'deb:calcBulgCurve: handlers1:\n', handlers1 #---------
+ #print 'deb:calcBulgCurve: points:\n', points #---------
+ #print 'deb:calcBulgCurve: handlers2:\n', handlers2 #---------
+ #print 'deb:calcBulgCurve: VectorTriples:\n', VectorTriples #---------
+ return VectorTriples
+
+
+
+
+def calcArc(center, radius, start, end, arc_res, triples): #-----------------------------------------
+ """calculate Points (or BezierTriples) for ARC/CIRCLEs representation.
+
+ Given parameters of the ARC/CIRCLE,
+ returns points/segments (or BezierTriples) and centerPoint
+ """
+ # center is currently set by object
+ # if start > end: start = start - 360
+ if end > 360: end = end % 360.0
+
+ startmatrix = Mathutils.RotationMatrix(-start, 3, "Z")
+ startpoint = startmatrix * Mathutils.Vector(radius, 0, 0)
+ endmatrix = Mathutils.RotationMatrix(-end, 3, "Z")
+ endpoint = endmatrix * Mathutils.Vector(radius, 0, 0)
+
+ if end < start: end +=360.0
+ angle = end - start
+ #length = radians(angle) * radius
+
+ if not triples: #IF mesh-representation -----------
+ if arc_res > 1024: arc_res = 1024
+ elif arc_res < 4: arc_res = 4
+ pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION
+ if pieces < 3: pieces = 3
+ step = angle/pieces # set step so pieces * step = degrees in arc
+ stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z")
+
+ points = [startpoint]
+ point = startpoint
+ for i in xrange(int(pieces)-1):
+ point = stepmatrix * point
+ points.append(point)
+ points.append(endpoint)
+
+ if center:
+ centerVec = Mathutils.Vector(center)
+ #points = [point + centerVec for point in points()]
+ points = [point + centerVec for point in points]
+ # vector to point convertion:
+ points = [list(point) for point in points]
+ return points
+
+ else: #IF curve-representation ---------------
+ if arc_res > 32: arc_res = 32
+ elif arc_res < 3: arc_res = 3
+ pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION
+ if pieces < 2: pieces = 2
+ step = angle/pieces # set step so pieces * step = degrees in arc
+ stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z")
+
+ # correct Bezier curves representation for free segmented circles/arcs
+ step2 = radians(step * 0.5)
+ bulg = radius * (1 - cos(step2))
+ deltaY = 4.0 * bulg / (3.0 * sin(step2) )
+ #print 'deb:calcArcCurve: bulg, deltaY:\n', bulg, deltaY #---------
+ #print 'deb:calcArcCurve: step:\n', step #---------
+ handler0 = Mathutils.Vector(0.0, -deltaY, 0.0)
+
+ points = [startpoint]
+ handler = startmatrix * handler0
+ endhandler = endmatrix * handler0
+ handlers1 = [startpoint + handler]
+ handlers2 = [startpoint - handler]
+ point = Mathutils.Vector(startpoint)
+ for i in xrange(int(pieces)-1):
+ point = stepmatrix * point
+ handler = stepmatrix * handler
+ handler1 = point + handler
+ handler2 = point - handler
+ points.append(point)
+ handlers1.append(handler1)
+ handlers2.append(handler2)
+ points.append(endpoint)
+ handlers1.append(endpoint + endhandler)
+ handlers2.append(endpoint - endhandler)
+ VectorTriples = [list(h1)+list(p)+list(h2) for h1,p,h2 in zip(handlers1, points, handlers2)]
+ #print 'deb:calcArcCurve: handlers1:\n', handlers1 #---------
+ #print 'deb:calcArcCurve: points:\n', points #---------
+ #print 'deb:calcArcCurve: handlers2:\n', handlers2 #---------
+ #print 'deb:calcArcCurve: VectorTriples:\n', VectorTriples #---------
+ return VectorTriples
+
+
+def drawCurveCircle(circle): #--- no more used --------------------------------------------
+ """Given a dxf circle object return a blender circle object using curves.
+ """
+ c = Curve.New('circle') # create new curve data
+ center = circle.loc
+ radius = circle.radius
+
+ p1 = (0, -radius, 0)
+ p2 = (radius, 0, 0)
+ p3 = (0, radius, 0)
+ p4 = (-radius, 0, 0)
+
+ p1 = BezTriple.New(p1)
+ p2 = BezTriple.New(p2)
+ p3 = BezTriple.New(p3)
+ p4 = BezTriple.New(p4)
+
+ curve = c.appendNurb(p1)
+ curve.append(p2)
+ curve.append(p3)
+ curve.append(p4)
+ for point in curve:
+ point.handleTypes = [AUTO, AUTO]
+ curve.flagU = 1 # Set curve cyclic
+ c.update()
+
+ ob = Object.New('Curve', 'circle') # make curve object
+ return ob
+
+
+def drawCurveArc(self): #---- only for ELLIPSE -------------------------------------------------------------
+ """Given a dxf ELLIPSE object return a blender_curve.
+ """
+ center = self.loc
+ radius = self.radius
+ start = self.start_angle
+ end = self.end_angle
+
+ if start > end:
+ start = start - 360.0
+ startmatrix = Mathutils.RotationMatrix(start, 3, "Z")
+ startpoint = startmatrix * Mathutils.Vector((radius, 0, 0))
+ endmatrix = Mathutils.RotationMatrix(end, 3, "Z")
+ endpoint = endmatrix * Mathutils.Vector((radius, 0, 0))
+ # Note: handles must be tangent to arc and of correct length...
+
+ a = Curve.New('arc') # create new curve data
+
+ p1 = (0, -radius, 0)
+ p2 = (radius, 0, 0)
+ p3 = (0, radius, 0)
+ p4 = (-radius, 0, 0)
+
+ p1 = BezTriple.New(p1)
+ p2 = BezTriple.New(p2)
+ p3 = BezTriple.New(p3)
+ p4 = BezTriple.New(p4)
+
+ curve = a.appendNurb(p1)
+ curve.append(p2)
+ curve.append(p3)
+ curve.append(p4)
+ for point in curve:
+ point.handleTypes = [AUTO, AUTO]
+ curve.flagU = 1 # Set curve cyclic
+ a.update()
+
+ ob = Object.New('Curve', 'arc') # make curve object
+ return ob
+
+
+
+
+# GUI STUFF -----#################################################-----------------
+from Blender.BGL import *
+
+EVENT_NONE = 1
+EVENT_START = 2
+EVENT_REDRAW = 3
+EVENT_LOAD_INI = 4
+EVENT_SAVE_INI = 5
+EVENT_RESET = 6
+EVENT_CHOOSE_INI = 7
+EVENT_CHOOSE_DXF = 8
+EVENT_HELP = 9
+EVENT_PRESETCURV = 10
+EVENT_PRESETS = 11
+EVENT_DXF_DIR = 12
+EVENT_DXF_NAME = 13
+EVENT_LIST = 14
+EVENT_ORIGIN = 15
+EVENT_SCALE = 16
+EVENT_PRESET2D = 20
+EVENT_PRESET3D = 21
+EVENT_EXIT = 100
+GUI_EVENT = EVENT_NONE
+
+GUI_A = {} # GUI-buttons dictionary for parameter
+GUI_B = {} # GUI-buttons dictionary for drawingTypes
+
+# settings default, initialize ------------------------
+
+points_as_menu = "convert to: %t|empty %x1|mesh.vertex %x2|thin sphere %x3|thin box %x4|*curve.vertex %x5"
+lines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|thin box %x4|curve %x5"
+mlines_as_menu = "convert to: %t|*edge %x1|*mesh %x2|*thin cylinder %x3|*thin box %x|*curve %x5"
+plines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4|curve %x5"
+plines3_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4|curve %x5"
+plmesh_as_menu = "convert to: %t|*edge %x1|mesh %x2"
+solids_as_menu = "convert to: %t|*edge %x1|mesh %x2"
+blocks_as_menu = "convert to: %t|dupliGroup %x1|*real.Group %x2|*exploded %x3"
+texts_as_menu = "convert to: %t|text %x1|*mesh %x2|*curve %x5"
+material_from_menu= "material from: %t|*LINESTYLE %x7|COLOR %x1|LAYER %x2|*LAYER+COLOR %x3|*BLOCK %x4|*XDATA %x5|*INI-File %x6"
+g_scale_list = ''.join((
+ 'scale factor: %t',
+ '|user def. %x12',
+ '|yard to m %x8',
+ '|feet to m %x7',
+ '|inch to m %x6',
+ '| x 1000 %x3',
+ '| x 100 %x2',
+ '| x 10 %x1',
+ '| x 1 %x0',
+ '| x 0.1 %x-1',
+ '| x 0.01 %x-2',
+ '| x 0.001 %x-3',
+ '| x 0.0001 %x-4',
+ '| x 0.00001 %x-5'))
+
+#print 'deb: g_scale_list', g_scale_list #-----------
+
+dxfFileName = Draw.Create("")
+iniFileName = Draw.Create(INIFILE_DEFAULT_NAME + INIFILE_EXTENSION)
+user_preset = 0
+config_UI = Draw.Create(0) #switch_on/off extended config_UI
+g_scale_as = Draw.Create(int(log10(G_SCALE)))
+
+
+keywords_org = {
+ 'curves_on' : 0,
+ 'optimization': 2,
+ 'one_mesh_on': 1,
+ 'vGroup_on' : 1,
+ 'dummy_on' : 0,
+ 'views_on' : 0,
+ 'cams_on' : 0,
+ 'lights_on' : 0,
+ 'xref_on' : 1,
+ 'block_nn': 0,
+ 'blockFilter_on': 0,
+ 'newScene_on' : 1,
+ 'target_layer' : TARGET_LAYER,
+ 'group_bylayer_on' : GROUP_BYLAYER,
+ 'g_originX' : G_ORIGIN_X,
+ 'g_originY' : G_ORIGIN_Y,
+ 'g_originZ' : G_ORIGIN_Z,
+ 'g_origin_on': 0,
+ 'g_scale' : float(G_SCALE),
+# 'g_scale_as': int(log10(G_SCALE)), # 0,
+ 'g_scale_on': 0,
+ 'thick_on' : 1,
+ 'thick_min' : float(MIN_THICK),
+ 'thick_force': 0,
+ 'width_on' : 1,
+ 'width_min' : float(MIN_WIDTH),
+ 'width_force': 0,
+ 'dist_on' : 1,
+ 'dist_min' : float(MIN_DIST),
+ 'dist_force': 0,
+ 'material_on': 1,
+ 'material_from': 2,
+ 'pl_3d' : 1,
+ 'fill_on' : 1,
+ 'meshSmooth_on': 1,
+ 'curve_res' : CURV_RESOLUTION,
+ 'curve_arc' : CURVARC_RESOLUTION,
+ 'arc_res' : ARC_RESOLUTION,
+ 'arc_rad' : ARC_RADIUS,
+ 'thin_res' : THIN_RESOLUTION,
+ 'pl_trim_max' : TRIM_LIMIT,
+ 'pl_trim_on': 1,
+ 'paper_space_on': 0,
+ 'layFrozen_on': 0,
+ 'Z_force_on': 0,
+ 'Z_elev': float(ELEVATION),
+ 'points_as' : 2,
+ 'lines_as' : 2,
+ 'mlines_as' : 2,
+ 'plines_as' : 2,
+ 'plines3_as': 2,
+ 'plmesh_as' : 2,
+ 'solids_as' : 2,
+ 'blocks_as' : 1,
+ 'texts_as' : 1
+ }
+
+drawTypes_org = {
+ 'point' : 1,
+ 'line' : 1,
+ 'arc' : 1,
+ 'circle': 1,
+ 'ellipse': 1,
+ 'mline' : 0,
+ 'polyline': 1,
+ 'plmesh': 1,
+ 'pline3': 1,
+ 'lwpolyline': 1,
+ 'text' : 1,
+ 'mtext' : 0,
+ 'block' : 1,
+ 'insert': 1,
+ 'solid' : 1,
+ 'trace' : 1,
+ 'face' : 1,
+# 'view' : 0,
+ }
+
+# creating of GUI-buttons
+# GUI_A - GUI-buttons dictionary for parameter
+# GUI_B - GUI-buttons dictionary for drawingTypes
+for k, v in keywords_org.iteritems():
+ GUI_A[k] = Draw.Create(v)
+for k, v in drawTypes_org.iteritems():
+ GUI_B[k] = Draw.Create(v)
+#print 'deb:init GUI_A: ', GUI_A #---------------
+#print 'deb:init GUI_B: ', GUI_B #---------------
+# initialize settings-object controls how dxf entities are drawn
+settings = Settings(keywords_org, drawTypes_org)
+
+
+def update_RegistryKey(key, item): #
+ """updates key in Blender.Registry
+ """
+ cache = True # data is also saved to a file
+ rdict = Registry.GetKey('DXF_Importer', cache)
+ if not rdict: rdict = {}
+ if item:
+ rdict[key] = item
+ Registry.SetKey('DXF_Importer', rdict, cache)
+ #print 'deb:update_RegistryKey rdict', rdict #---------------
+
+
+def check_RegistryKey(key):
+ """ check if the key is already there (saved on a previous execution of this script)
+ """
+ cache = True # data is also saved to a file
+ rdict = Registry.GetKey('DXF_Importer', cache)
+ #print 'deb:check_RegistryKey rdict:', rdict #----------------
+ if rdict: # if found, get the values saved there
+ try:
+ item = rdict[key]
+ return item
+ except:
+ #update_RegistryKey() # if data isn't valid rewrite it
+ pass
+
+def saveConfig(): #--todo-----------------------------------------------
+ """Save settings/config/materials from GUI to INI-file.
+
+ Write all config data to INI-file.
+ """
+ global iniFileName
+
+ iniFile = iniFileName.val
+ #print 'deb:saveConfig inifFile: ', inifFile #----------------------
+ if iniFile.lower().endswith(INIFILE_EXTENSION):
+
+ #--todo-- sort key.list for output
+ #key_list = GUI_A.keys().val
+ #key_list.sort()
+ #for key in key_list:
+ # l_name, l_data = key, GUI_A[key].val
+ # list_A
+
+ output_str = '[%s,%s]' %(GUI_A, GUI_B)
+ if output_str =='None':
+ Draw.PupMenu('DXF importer: INI-file: Alert!%t|no config-data present to save!')
+ else:
+ #if BPyMessages.Warning_SaveOver(iniFile): #<- remi find it too abstarct
+ if sys.exists(iniFile):
+ try:
+ f = file(iniFile, 'r')
+ try: header_str = f.readline()
+ finally: f.close()
+ except: pass
+ if header_str.startswith(INIFILE_HEADER[0:13]):
+ if Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile) == 1:
+ save_ok = True
+ else: save_ok = False
+ elif Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile +
+ '|Alert: this file has no valid ImportDXF-header| ! it may belong to another aplication !') == 1:
+ save_ok = True
+ else: save_ok = False
+ else: save_ok = True
+
+ if save_ok:
+ # replace: ',' -> ',\n'
+ # replace: '{' -> '\n{\n'
+ # replace: '}' -> '\n}\n'
+ output_str = ',\n'.join(output_str.split(','))
+ output_str = '\n}'.join(output_str.split('}'))
+ output_str = '{\n'.join(output_str.split('{'))
+ try:
+ f = file(iniFile, 'w')
+ try:
+ f.write(INIFILE_HEADER + '\n# this is a comment line\n')
+ f.write(output_str)
+ finally: f.close()
+ #Draw.PupMenu('DXF importer: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile)
+ except:
+ Draw.PupMenu('DXF importer: INI-file: Error!%t|failure by writing to ' + '\'%s\'|no config-data saved!' %iniFile)
+
+ else:
+ Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid name/extension for INI-file selected!')
+ print "DXF importer: Alert!: no valid INI-file selected."
+ if not iniFile:
+ if dxfFileName.val.lower().endswith('.dxf'):
+ iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION
+
+
+def loadConfig(): #remi--todo-----------------------------------------------
+ """Load settings/config/materials from INI-file.
+
+ Read material-assignements from config-file.
+ """
+ #070724 buggy Window.FileSelector(loadConfigFile, 'Load config data from INI-file', inifilename)
+ global iniFileName, GUI_A, GUI_B
+
+ iniFile = iniFileName.val
+ update_RegistryKey('iniFileName', iniFile)
+ #print 'deb:loadConfig iniFile: ', iniFile #----------------------
+ if iniFile.lower().endswith(INIFILE_EXTENSION) and sys.exists(iniFile):
+ try:
+ f = file(iniFile, 'r')
+ try:
+ header_str = f.readline()
+ if header_str.startswith(INIFILE_HEADER):
+ data_str = f.read()
+ f.close()
+ #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #-----------------
+ data = eval(data_str)
+ for k, v in data[0].iteritems():
+ try: GUI_A[k].val = v
+ except: GUI_A[k] = Draw.Create(v)
+ for k, v in data[1].iteritems():
+ try: GUI_B[k].val = v
+ except: GUI_B[k] = Draw.Create(v)
+ else:
+ Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile)
+ finally: f.close()
+ except: pass
+ else:
+ Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid INI-file selected!')
+ print "DXF importer: Alert!: no valid INI-file selected."
+ if not iniFileName:
+ if dxfFileName.val.lower().endswith('.dxf'):
+ iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION
+
+
+
+def updateConfig(keywords, drawTypes): #-----------------------------------------------
+ """updates GUI_settings with given dictionaries
+
+ """
+ global GUI_A, GUI_B
+ #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #---------
+ for k, v in keywords.iteritems():
+ GUI_A[k].val = v
+ for k, v in drawTypes.iteritems():
+ GUI_B[k].val = v
+
+def resetDefaultConfig(): #-----------------------------------------------
+ """Resets settings/config/materials to defaults.
+
+ """
+ #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #---------
+ updateConfig(keywords_org, drawTypes_org)
+
+
+def presetConfig_curv(): #-----------------------------------------------
+ """Sets settings/config/materials for curve representation.
+
+ """
+ global GUI_A
+ if GUI_A['curves_on'].val == 1:
+ GUI_A['points_as'].val = 5
+ GUI_A['lines_as'].val = 5
+ GUI_A['mlines_as'].val = 5
+ GUI_A['plines_as'].val = 5
+ GUI_A['plines3_as'].val = 5
+ else:
+ GUI_A['points_as'].val = 2
+ GUI_A['lines_as'].val = 2
+ GUI_A['mlines_as'].val = 2
+ GUI_A['plines_as'].val = 2
+ GUI_A['plines3_as'].val = 2
+
+
+def resetDefaultConfig_2D(): #-----------------------------------------------
+ """Sets settings/config/materials to defaults 2D.
+
+ """
+# presetConfig_curv()
+ keywords2d = {
+ 'views_on' : 0,
+ 'cams_on' : 0,
+ 'lights_on' : 0,
+ 'vGroup_on' : 1,
+ 'thick_on' : 0,
+ 'thick_force': 0,
+ 'width_on' : 1,
+ 'width_force': 0,
+ 'dist_on' : 1,
+ 'dist_force': 0,
+ 'pl_3d' : 0,
+ 'fill_on' : 0,
+ 'pl_trim_on': 1,
+ 'Z_force_on': 0,
+ 'meshSmooth_on': 0,
+ 'solids_as' : 2,
+ 'blocks_as' : 1,
+ 'texts_as' : 1
+ }
+
+ drawTypes2d = {
+ 'point' : 1,
+ 'line' : 1,
+ 'arc' : 1,
+ 'circle': 1,
+ 'ellipse': 1,
+ 'mline' : 0,
+ 'polyline': 1,
+ 'plmesh': 0,
+ 'pline3': 0,
+ 'lwpolyline': 1,
+ 'text' : 1,
+ 'mtext' : 0,
+ 'block' : 1,
+ 'insert': 1,
+ 'solid' : 1,
+ 'trace' : 1,
+ 'face' : 0,
+# 'view' : 0,
+ }
+
+ updateConfig(keywords2d, drawTypes2d)
+
+def resetDefaultConfig_3D(): #-----------------------------------------------
+ """Sets settings/config/materials to defaults 3D.
+
+ """
+# presetConfig_curv()
+ keywords3d = {
+ 'vGroup_on' : 1,
+ 'thick_on' : 1,
+ 'thick_force': 0,
+ 'width_on' : 1,
+ 'width_force': 0,
+ 'dist_on' : 1,
+ 'dist_force': 0,
+ 'pl_3d' : 0,
+ 'fill_on' : 1,
+ 'pl_trim_on': 1,
+ 'Z_force_on': 0,
+ 'meshSmooth_on': 1,
+ 'solids_as' : 2,
+ 'blocks_as' : 1,
+ 'texts_as' : 1
+ }
+
+ drawTypes3d = {
+ 'point' : 1,
+ 'line' : 1,
+ 'arc' : 1,
+ 'circle': 1,
+ 'ellipse': 1,
+ 'mline' : 0,
+ 'polyline': 1,
+ 'plmesh': 1,
+ 'pline3': 1,
+ 'lwpolyline': 1,
+ 'text' : 1,
+ 'mtext' : 0,
+ 'block' : 1,
+ 'insert': 1,
+ 'solid' : 1,
+ 'trace' : 1,
+ 'face' : 1,
+# 'view' : 0,
+ }
+
+ updateConfig(keywords3d, drawTypes3d)
+
+
+def inputGlobalScale():
+ """Pop-up UI-Block for global scale factor
+ """
+ global GUI_A
+ #print 'deb:inputGlobalScale ##########' #------------
+ x_scale = Draw.Create(GUI_A['g_scale'].val)
+ block = []
+ #block.append("global translation vector:")
+ block.append(("", x_scale, 0.0, 10000000.0))
+
+ retval = Draw.PupBlock("set global scale factor:", block)
+
+ GUI_A['g_scale'].val = float(x_scale.val)
+
+
+def inputOriginVector():
+ """Pop-up UI-Block for global translation vector
+ """
+ global GUI_A
+ #print 'deb:inputOriginVector ##########' #------------
+ x_origin = Draw.Create(GUI_A['g_originX'].val)
+ y_origin = Draw.Create(GUI_A['g_originY'].val)
+ z_origin = Draw.Create(GUI_A['g_originZ'].val)
+ block = []
+ #block.append("global translation vector:")
+ block.append(("X: ", x_origin, -100000000.0, 100000000.0))
+ block.append(("Y: ", y_origin, -100000000.0, 100000000.0))
+ block.append(("Z: ", z_origin, -100000000.0, 100000000.0))
+
+ retval = Draw.PupBlock("set global translation vector:", block)
+
+ GUI_A['g_originX'].val = x_origin.val
+ GUI_A['g_originY'].val = y_origin.val
+ GUI_A['g_originZ'].val = z_origin.val
+
+
+def draw_UI(): #-----------------------------------------------------------------
+ """ Draw startUI and setup Settings.
+ """
+ global GUI_A, GUI_B #__version__
+ global user_preset, iniFileName, dxfFileName, config_UI, g_scale_as
+
+ # This is for easy layout changes
+ but_0c = 70 #button 1.column width
+ but_1c = 70 #button 1.column width
+ but_2c = 70 #button 2.column
+ but_3c = 70 #button 3.column
+ menu_margin = 10
+ butt_margin = 10
+ menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c #menu width
+
+ simple_menu_h = 80
+ extend_menu_h = 350
+ y = simple_menu_h # y is menu upper.y
+ if config_UI.val: y += extend_menu_h
+ x = 20 #menu left.x
+ but0c = x + menu_margin #buttons 0.column position.x
+ but1c = but0c + but_0c + butt_margin
+ but2c = but1c + but_1c + butt_margin
+ but3c = but2c + but_2c + butt_margin
+ but4c = but3c + but_3c
+
+ # Here starts menu -----------------------------------------------------
+ #glClear(GL_COLOR_BUFFER_BIT)
+ #glRasterPos2d(8, 125)
+
+ y += 30
+ colorbox(x, y+20, x+menu_w+menu_margin*2, menu_margin)
+ Draw.Label("DXF-Importer ver." + __version__, but0c, y, menu_w, 20)
+
+ if config_UI.val:
+ b0, b0_ = but0c, but_0c + butt_margin
+ b1, b1_ = but1c, but_1c
+ y -= 10
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['point'] = Draw.Toggle('POINT', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['point'].val, "support dxf-POINT on/off")
+ if GUI_B['point'].val:
+ GUI_A['points_as'] = Draw.Menu(points_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['points_as'].val, "select target Blender-object")
+# Draw.Label('-->', but2c, y, but_2c, 20)
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['line'] = Draw.Toggle('LINE...etc', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['line'].val, "support dxf-LINE,ARC,CIRCLE,ELLIPSE on/off")
+ if GUI_B['line'].val:
+ GUI_A['lines_as'] = Draw.Menu(lines_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['lines_as'].val, "select target Blender-object")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['mline'] = Draw.Toggle('*MLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['mline'].val, "(*wip)support dxf-MLINE on/off")
+ if GUI_B['mline'].val:
+ GUI_A['mlines_as'] = Draw.Menu(mlines_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['mlines_as'].val, "select target Blender-object")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['polyline'] = Draw.Toggle('2D-PLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['polyline'].val, "support dxf-2D-POLYLINE on/off")
+ if GUI_B['polyline'].val:
+ GUI_A['plines_as'] = Draw.Menu(plines_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['plines_as'].val, "select target Blender-object")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['pline3'] = Draw.Toggle('3D-PLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['pline3'].val, "support dxf-3D-POLYLINE on/off")
+ if GUI_B['pline3'].val:
+ GUI_A['plines3_as'] = Draw.Menu(plines3_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['plines3_as'].val, "select target Blender-object")
+ Draw.EndAlign()
+
+ y -= 10
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['material_on'] = Draw.Toggle('material', EVENT_REDRAW, b0, y, b0_-20, 20, GUI_A['material_on'].val, "support for material assignment on/off")
+ if GUI_A['material_on'].val:
+ GUI_A['material_from'] = Draw.Menu(material_from_menu, EVENT_NONE, b1-20, y, b1_+20, 20, GUI_A['material_from'].val, "material assignment from?")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['g_origin_on'] = Draw.Toggle('glob.reLoc', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['g_origin_on'].val, "global relocate all DXF objects on/off")
+ if GUI_A['g_origin_on'].val:
+ tmp = Draw.PushButton('=', EVENT_ORIGIN, b1, y, 20, 20, "edit relocation-vector (x,y,z in DXF units)")
+ origin_str = '(%.4f, %.4f, %.4f)' % (
+ GUI_A['g_originX'].val,
+ GUI_A['g_originY'].val,
+ GUI_A['g_originZ'].val
+ )
+ tmp = Draw.Label(origin_str, b1+20, y, 300, 20)
+ #GUI_A['g_origin'] = Draw.String('', EVENT_ORIGIN, b1, y, b1_, 20, GUI_A['g_origin'].val, "global translation-vector (x,y,z) in DXF units")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['g_scale_on'] = Draw.Toggle('glob.Scale', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['g_scale_on'].val, "global scale all DXF objects on/off")
+ if GUI_A['g_scale_on'].val:
+ g_scale_as = Draw.Menu(g_scale_list, EVENT_SCALE, b1, y, 45, 20, g_scale_as.val, "factor for scaling the DXFdata")
+ if g_scale_as.val == 12:
+ pass
+ else:
+ if g_scale_as.val == 6: #scale inches to meters
+ GUI_A['g_scale'].val = 0.0254000
+ elif g_scale_as.val == 7: #scale feets to meters
+ GUI_A['g_scale'].val = 0.3048000
+ elif g_scale_as.val == 8: #scale yards to meters
+ GUI_A['g_scale'].val = 0.9144000
+ else:
+ GUI_A['g_scale'].val = 10.0 ** int(g_scale_as.val)
+ scale_float = GUI_A['g_scale'].val
+ if scale_float < 0.000001 or scale_float > 1000000:
+ scale_str = ' = %s' % GUI_A['g_scale'].val
+ else:
+ scale_str = ' = %.6f' % GUI_A['g_scale'].val
+ Draw.Label(scale_str, b1+45, y, 200, 20)
+ Draw.EndAlign()
+
+ y -= 10
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['meshSmooth_on'] = Draw.Toggle('smooth', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['meshSmooth_on'].val, "mesh smooth for circles/arcsegments on/off")
+ GUI_A['pl_trim_on'] = Draw.Toggle('trim', EVENT_NONE, b1-20, y, 32, 20, GUI_A['pl_trim_on'].val, "intersection of POLYLINE-wide-segments on/off")
+ GUI_A['pl_trim_max'] = Draw.Number('', EVENT_NONE, b1+12, y, b1_-12, 20, GUI_A['pl_trim_max'].val, 0, 5, "limit for intersection of POLYLINE-wide-segments: 0.0-5.0")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+# GUI_A['thin_res'] = Draw.Number('thin:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['thin_res'].val, 4, 64, "thin cylinder resolution - number of segments (4-64)")
+ GUI_A['arc_rad'] = Draw.Number('bR:', EVENT_NONE, b0, y, b0_, 20, GUI_A['arc_rad'].val, 0.01, 100, "basis radius for arc/circle resolution (0.01-100)")
+ GUI_A['arc_res'] = Draw.Number('', EVENT_NONE, b1, y, b1_/2, 20, GUI_A['arc_res'].val, 3, 500, "arc/circle resolution - number of segments (3-500)")
+ GUI_A['fill_on'] = Draw.Toggle('caps', EVENT_NONE, b1+b1_/2, y, b1_/2, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs/closed curves on/off")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_PRESETCURV, b0, y, b0_, 20, GUI_A['curves_on'].val, "import into curves instead into meshes on/off")
+ GUI_A['curve_arc'] = Draw.Number('', EVENT_NONE, b1, y, b1_/2, 20, GUI_A['curve_arc'].val, 3, 32, "Bezier circle: amount of segments: 3-32")
+ GUI_A['curve_res'] = Draw.Number('', EVENT_NONE, b1+b1_/2, y, b1_/2, 20, GUI_A['curve_res'].val, 1, 128, "Set the Curve's U-resolution value: 1-128")
+ Draw.EndAlign()
+
+ y -= 20
+ GUI_A['group_bylayer_on'] = Draw.Toggle('Lay', EVENT_NONE, b0, y, 30, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off")
+ GUI_A['vGroup_on'] = Draw.Toggle('vGroups', EVENT_NONE, b0+30, y, b1_-10, 20, GUI_A['vGroup_on'].val, "support Blender-VertexGroups on/off")
+ GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, b1+10, y, b1_-10, 20, GUI_A['one_mesh_on'].val, "draw DXF-entities into one mesh-object. Recommended for big DXF-files. on/off")
+
+ y -= 30
+ Draw.BeginAlign()
+ GUI_A['paper_space_on'] = Draw.Toggle('paper space', EVENT_NONE, b0, y, b0_+20, 20, GUI_A['paper_space_on'].val, "import only layout (paper space) on/off")
+ GUI_A['layFrozen_on'] = Draw.Toggle('frozen', EVENT_NONE, b1+20, y, b1_-20, 20, GUI_A['layFrozen_on'].val, "import also from frozen layers on/off")
+ #GUI_A['dummy_on'] = Draw.Toggle('-', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dummy_on'].val, "dummy on/off")
+ Draw.EndAlign()
+
+ y_down = y
+ # -----------------------------------------------
+ y = simple_menu_h + extend_menu_h +20
+ b0, b0_ = but2c, but_2c + butt_margin
+ b1, b1_ = but3c, but_3c
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['plmesh'] = Draw.Toggle('POLY-MESH/FACE', EVENT_NONE, b0, y, b0_+b1_, 20, GUI_B['plmesh'].val, "support dxf-POLYMESH/POLYFACE on/off")
+# GUI_A['plmesh_as'] = Draw.Menu(plmesh_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['plmesh_as'].val, "select target Blender-object")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['solid'] = Draw.Toggle('SOLID', EVENT_NONE, b0, y, b0_, 20, GUI_B['solid'].val, "support dxf-SOLID and TRACE on/off")
+ GUI_B['face'] = Draw.Toggle('3DFACE', EVENT_NONE, b1, y, b1_, 20, GUI_B['face'].val, "support dxf-3DFACE on/off")
+# GUI_A['solids_as'] = Draw.Menu(solids_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['solids_as'].val, "select target Blender-object")
+ Draw.EndAlign()
+ #print 'deb:support solid, trace', GUI_B['trace'].val, GUI_B['solid'].val # ------------
+
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['text'] = Draw.Toggle('TEXT', EVENT_NONE, b0, y, b0_, 20, GUI_B['text'].val, "support dxf-TEXT on/off")
+ GUI_B['mtext'] = Draw.Toggle('*MTEXT', EVENT_NONE, b1, y, b1_, 20, GUI_B['mtext'].val, "(*wip)support dxf-MTEXT on/off")
+# GUI_A['texts_as'] = Draw.Menu(texts_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['texts_as'].val, "select target Blender-object")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_B['block'] = Draw.Toggle('BLOCK', EVENT_REDRAW, b0, y, b0_-30, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off")
+ GUI_B['insert'].val = GUI_B['block'].val
+ if GUI_B['block'].val:
+ GUI_A['block_nn'] = Draw.Toggle('n', EVENT_NONE, b1-30, y, 15, 20, GUI_A['block_nn'].val, "support hatch/noname BLOCKs *X... on/off")
+ GUI_A['blockFilter_on'] = Draw.Toggle('F', EVENT_NONE, b1-15, y, 15, 20, GUI_A['blockFilter_on'].val, "(*wip) support name filtering of BLOCKs on/off")
+ GUI_A['xref_on'] = Draw.Toggle('Xref', EVENT_NONE, b1, y, 20, 20, GUI_A['xref_on'].val, "support place holder for XREF-BLOCKs on/off")
+ GUI_A['blocks_as'] = Draw.Menu(blocks_as_menu, EVENT_NONE, b1+20, y, b1_-20, 20, GUI_A['blocks_as'].val, "select target representation for imported BLOCKs")
+ Draw.EndAlign()
+
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['views_on'] = Draw.Toggle('views', EVENT_NONE, b0, y, b0_-25, 20, GUI_A['views_on'].val, "imports VIEWs and VIEWPORTs as cameras on/off")
+ GUI_A['cams_on'] = Draw.Toggle('*cams', EVENT_NONE, b1-25, y, b1_-25, 20, GUI_A['cams_on'].val, "(*wip) support ASHADE cameras on/off")
+ GUI_A['lights_on'] = Draw.Toggle('*lights', EVENT_NONE, b1+25, y, b1_-25, 20, GUI_A['lights_on'].val, "(*wip) support AVE_RENDER lights on/off")
+ Draw.EndAlign()
+
+ y -= 10
+ y -= 20
+ y -= 20
+ y -= 20
+
+ y -= 10
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['Z_force_on'] = Draw.Toggle('*elevation', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['Z_force_on'].val, "*set objects Z-coordinates to elevation on/off")
+ if GUI_A['Z_force_on'].val:
+ GUI_A['Z_elev'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['Z_elev'].val, -1000, 1000, "set default elevation(Z-coordinate)")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['dist_on'] = Draw.Toggle('dist.:', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['dist_on'].val, "support distance on/off")
+ GUI_A['dist_force'] = Draw.Toggle('F', EVENT_NONE, b0+b0_-20, y, 20, 20, GUI_A['dist_force'].val, "force minimal distance on/off")
+ GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['dist_min'].val, 0, 10, "minimal length/distance (double.vertex removing)")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['thick_on'] = Draw.Toggle('thick:', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['thick_on'].val, "support thickness on/off")
+ GUI_A['thick_force'] = Draw.Toggle('F', EVENT_REDRAW, b0+b0_-20, y, 20, 20, GUI_A['thick_force'].val, "force for thickness at least limiter value on/off")
+ if GUI_A['thick_force'].val:
+ GUI_A['thick_min'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['thick_min'].val, 0, 10, "minimal value for thickness")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ GUI_A['width_on'] = Draw.Toggle('width:', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['width_on'].val, "support width on/off")
+ GUI_A['width_force'] = Draw.Toggle('F', EVENT_REDRAW, b0+b0_-20, y, 20, 20, GUI_A['width_force'].val, "force for width at least limiter value on/off")
+ if GUI_A['width_force'].val:
+ GUI_A['width_min'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['width_min'].val, 0, 10, "minimal value for width")
+ Draw.EndAlign()
+
+ y -= 30
+ GUI_A['newScene_on'] = Draw.Toggle('newScene', EVENT_NONE, b0, y, b0_, 20, GUI_A['newScene_on'].val, "creates new Blender-Scene for each import on/off")
+ GUI_A['target_layer'] = Draw.Number('layer', EVENT_NONE, b1, y, b1_, 20, GUI_A['target_layer'].val, 1, 18, "imports into this Blender-layer (<19> reserved for block_definitions)")
+
+ #--------------------------------------
+ if y > y_down: y = y_down
+ #GUI_A['dummy_on'] = Draw.Toggle(' - ', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['dummy_on'].val, "reserved")
+ y -= 30
+ Draw.BeginAlign()
+ Draw.PushButton('INI file >', EVENT_CHOOSE_INI, but0c, y, but_0c, 20, 'Select INI-file from project directory')
+ iniFileName = Draw.String(' :', EVENT_NONE, but1c, y, menu_w-but_0c-butt_margin, 20, iniFileName.val, FILENAME_MAX, "write here the name of the INI-file")
+ Draw.EndAlign()
+
+ y -= 20
+ Draw.BeginAlign()
+ Draw.PushButton('#', EVENT_PRESETS, but0c, y, 20, 20, "tipist for Preset-INI-files")
+ Draw.PushButton('Load', EVENT_LOAD_INI, but0c+20, y, but_0c-20, 20, '.Loads configuration from ini-file: %s' % iniFileName.val)
+ Draw.PushButton('Save', EVENT_SAVE_INI, but1c, y, but_1c-20, 20, 'Saves configuration to ini-file: %s' % iniFileName.val)
+ Draw.EndAlign()
+ but_ = (but_2c+but_3c)/4
+ but = but2c
+ Draw.PushButton('reset', EVENT_RESET, but, y, but_, 20, "reset configuration to defaults")
+ Draw.PushButton('2D', EVENT_PRESET2D, but+but_, y, but_, 20, 'set configuration for 2D import')
+ Draw.PushButton('3D', EVENT_PRESET3D, but+but_*2, y, but_, 20, 'set configuration for 3D import')
+ GUI_A['optimization'] = Draw.Number('', EVENT_NONE, but4c-35, y, 35, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/directDrawing, 1=Verbose, 2=ProgressBar, 3=silentMode/fastest")
+
+
+ y = simple_menu_h
+ Draw.BeginAlign()
+ Draw.PushButton('DXFfile >', EVENT_CHOOSE_DXF, but0c, y, but_0c, 20, 'Select DXF-file from project directory')
+ dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, but_1c+but_2c+but_3c-20, 20, dxfFileName.val, FILENAME_MAX, "type the name of DXF-file or type *.dxf for multi-import")
+ Draw.PushButton('*.*', EVENT_DXF_DIR, but3c+but_3c-20, y, 20, 20, 'Set asterisk * as filter')
+ Draw.EndAlign()
+
+
+ y -= 50
+ Draw.BeginAlign()
+ Draw.PushButton('EXIT', EVENT_EXIT, but0c, y, but_0c, 40, '' )
+ Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c-20, 20, 'calls BlenderWiki for Manual, Updates and Support.')
+ Draw.PushButton('?', EVENT_LIST, but1c+but_1c-20, y, 20, 20, 'DXF analyze tool: print listing of LAYERs and BLOCKs into the text file .INF')
+ Draw.PushButton('START IMPORT', EVENT_START, but2c, y, but_2c+but_3c+butt_margin, 40, 'Start the import procedure')
+ Draw.EndAlign()
+
+ config_UI = Draw.Toggle('CONFIG', EVENT_REDRAW, but1c-butt_margin/2, y+20, but_1c+butt_margin, 20, config_UI.val, 'Advanced configuration on/off' )
+
+ y -= 20
+ Draw.BeginAlign()
+ Draw.Label(' ', but0c-menu_margin, y, menu_margin, 20)
+ Draw.Label("*) parts under construction", but0c, y, menu_w, 20)
+ Draw.Label(' ', but0c+menu_w, y, menu_margin, 20)
+ Draw.EndAlign()
+
+#-- END GUI Stuf-----------------------------------------------------
+
+def colorbox(x,y,xright,bottom):
+ glColor3f(0.75, 0.75, 0.75)
+ glRecti(x + 1, y + 1, xright - 1, bottom - 1)
+
+def dxf_callback(input_filename):
+ global dxfFileName
+ dxfFileName.val=input_filename
+# dirname == Blender.sys.dirname(Blender.Get('filename'))
+# update_RegistryKey('DirName', dirname)
+# update_RegistryKey('dxfFileName', input_filename)
+
+def ini_callback(input_filename):
+ global iniFileName
+ iniFileName.val=input_filename
+
+def event(evt, val):
+ if evt in (Draw.QKEY, Draw.ESCKEY) and not val:
+ Blender.Draw.Exit()
+
+def bevent(evt):
+# global EVENT_NONE,EVENT_LOAD_DXF,EVENT_LOAD_INI,EVENT_SAVE_INI,EVENT_EXIT
+ global config_UI, user_preset
+ global GUI_A
+
+ ######### Manages GUI events
+ if (evt==EVENT_EXIT):
+ Blender.Draw.Exit()
+ print 'DXF-Importer *** exit ***' #---------------------
+ elif (evt==EVENT_CHOOSE_INI):
+ Window.FileSelector(ini_callback, "INI-file Selection", '*.ini')
+ elif (evt==EVENT_REDRAW):
+ Draw.Redraw()
+ elif (evt==EVENT_RESET):
+ resetDefaultConfig()
+ Draw.Redraw()
+ elif (evt==EVENT_PRESET2D):
+ resetDefaultConfig_2D()
+ Draw.Redraw()
+ elif (evt==EVENT_SCALE):
+ if g_scale_as.val == 12:
+ inputGlobalScale()
+ if GUI_A['g_scale'].val < 0.00000001:
+ GUI_A['g_scale'].val = 0.00000001
+ Draw.Redraw()
+ elif (evt==EVENT_ORIGIN):
+ inputOriginVector()
+ Draw.Redraw()
+ elif (evt==EVENT_PRESET3D):
+ resetDefaultConfig_3D()
+ Draw.Redraw()
+ elif (evt==EVENT_PRESETCURV):
+ presetConfig_curv()
+ Draw.Redraw()
+ elif (evt==EVENT_PRESETS):
+ user_preset += 1
+ index = str(user_preset)
+ if user_preset > 5: user_preset = 0; index = ''
+ iniFileName.val = INIFILE_DEFAULT_NAME + index + INIFILE_EXTENSION
+ Draw.Redraw()
+ elif (evt==EVENT_LIST):
+ dxfFile = dxfFileName.val
+ update_RegistryKey('dxfFileName', dxfFileName.val)
+ if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile):
+ analyzeDXF(dxfFile)
+ else:
+ Draw.PupMenu('DXF importer: Alert!%t|no valid DXF-file selected!')
+ print "DXF importer: error, no valid DXF-file selected! try again"
+ Draw.Redraw()
+ elif (evt==EVENT_HELP):
+ try:
+ import webbrowser
+ webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D')
+ except:
+ Draw.PupMenu('DXF importer: HELP Alert!%t|no connection to manual-page on Blender-Wiki! try:|\
+http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D')
+ Draw.Redraw()
+ elif (evt==EVENT_LOAD_INI):
+ loadConfig()
+ Draw.Redraw()
+ elif (evt==EVENT_SAVE_INI):
+ saveConfig()
+ Draw.Redraw()
+ elif (evt==EVENT_DXF_DIR):
+ dxfFile = dxfFileName.val
+ dxfPathName = ''
+ if '/' in dxfFile:
+ dxfPathName = '/'.join(dxfFile.split('/')[:-1]) + '/'
+ elif '\\' in dxfFile:
+ dxfPathName = '\\'.join(dxfFile.split('\\')[:-1]) + '\\'
+ dxfFileName.val = dxfPathName + '*.dxf'
+# dirname == Blender.sys.dirname(Blender.Get('filename'))
+# update_RegistryKey('DirName', dirname)
+# update_RegistryKey('dxfFileName', dxfFileName.val)
+ GUI_A['newScene_on'].val = 1
+ Draw.Redraw()
+# elif (evt==EVENT_DXF_NAME):
+# dirname == Blender.sys.dirname(Blender.Get('filename'))
+# update_RegistryKey('DirName', dirname)
+# #print 'deb:EVENT_DXF_NAME dxfFileName.val:', dxfFileName.val #--------------
+# update_RegistryKey('dxfFileName', dxfFileName.val)
+ elif (evt==EVENT_CHOOSE_DXF):
+ filename = '' # '*.dxf'
+ if dxfFileName.val: filename = dxfFileName.val
+ Window.FileSelector(dxf_callback, "DXF-file Selection", filename)
+ elif (evt==EVENT_START):
+ dxfFile = dxfFileName.val
+ #print 'deb: dxfFile file: ', dxfFile #----------------------
+ update_RegistryKey('dxfFileName', dxfFileName.val)
+ if dxfFile.lower().endswith('*.dxf'):
+ if Draw.PupMenu('DXF importer: OK?|will import all DXF-files from:|%s' % dxfFile) == 1:
+ global UI_MODE
+ UI_MODE = False
+ multi_import(dxfFile[:-5]) # cut last 5 characters '*.dxf'
+ Draw.Redraw()
+ #Draw.Exit()
+ else:
+ Draw.Redraw()
+ elif dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile):
+ print '\nStandard Mode: active'
+ if GUI_A['newScene_on'].val:
+ _dxf_file = dxfFile.split('/')[-1].split('\\')[-1]
+ _dxf_file = _dxf_file[:-4] # cut last char:'.dxf'
+ _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:])
+ global SCENE
+ SCENE = Blender.Scene.New(_dxf_file)
+ SCENE.makeCurrent()
+ Blender.Redraw()
+ #or so? Blender.Scene.makeCurrent(_dxf_file)
+ #sce = bpy.data.scenes.new(_dxf_file)
+ #bpy.data.scenes.active = sce
+ else:
+ SCENE = Blender.Scene.GetCurrent()
+ SCENE.objects.selected = [] # deselect all
+ main(dxfFile)
+ #SCENE.objects.selected = SCENE.objects
+ #Window.RedrawAll()
+ #Blender.Redraw()
+ #Draw.Redraw()
+ else:
+ Draw.PupMenu('DXF importer: Alert!%t|no valid DXF-file selected!')
+ print "DXF importer: error, no valid DXF-file selected! try again"
+ Draw.Redraw()
+
+
+
+
+def multi_import(DIR):
+ """Imports all DXF-files from directory DIR.
+
+ """
+ global SCENE
+ batchTIME = Blender.sys.time()
+ #if #DIR == "": DIR = os.path.curdir
+ if DIR == "": DIR = Blender.sys.dirname(Blender.Get('filename'))
+ print 'Multifiles Import from %s' %DIR
+ files = \
+ [sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith('.dxf')]
+ if not files:
+ print '...None DXF-files found. Abort!'
+ return
+
+ i = 0
+ for dxfFile in files:
+ i += 1
+ print '\nDXF-file', i, 'of', len(files) #,'\nImporting', dxfFile
+ if GUI_A['newScene_on'].val:
+ _dxf_file = dxfFile.split('/')[-1].split('\\')[-1]
+ _dxf_file = _dxf_file[:-4] # cut last char:'.dxf'
+ _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:])
+ SCENE = Blender.Scene.New(_dxf_file)
+ SCENE.makeCurrent()
+ #or so? Blender.Scene.makeCurrent(_dxf_file)
+ #sce = bpy.data.scenes.new(_dxf_file)
+ #bpy.data.scenes.active = sce
+ else:
+ SCENE = Blender.Scene.GetCurrent()
+ SCENE.objects.selected = [] # deselect all
+ main(dxfFile)
+ #Blender.Redraw()
+
+ print 'TOTAL TIME: %.6f' % (Blender.sys.time() - batchTIME)
+ print '\a\r', # beep when done
+
+
if __name__ == "__main__":
- Window.FileSelector(main, 'Import a DXF file', '*.dxf')
+ UI_MODE = True
+ # recall last used DXF-file and INI-file names
+ dxffilename = check_RegistryKey('dxfFileName')
+ #print 'deb:start dxffilename:', dxffilename #----------------
+ if dxffilename: dxfFileName.val = dxffilename
+ else:
+ dirname = Blender.sys.dirname(Blender.Get('filename'))
+ #print 'deb:start dirname:', dirname #----------------
+ dxfFileName.val = sys.join(dirname, '')
+ inifilename = check_RegistryKey('iniFileName')
+ if inifilename: iniFileName.val = inifilename
+
+ Draw.Register(draw_UI, event, bevent)
+
+
+"""
+if 1:
+ # DEBUG ONLY
+ UI_MODE = False
+ TIME= Blender.sys.time()
+ #DIR = '/dxf_r12_testfiles/'
+ DIR = '/metavr/'
+ import os
+ print 'Searching for files'
+ os.system('find %s -iname "*.dxf" > /tmp/tempdxf_list' % DIR)
+ # os.system('find /storage/ -iname "*.dxf" > /tmp/tempdxf_list')
+ print '...Done'
+ file= open('/tmp/tempdxf_list', 'r')
+ lines= file.readlines()
+ file.close()
+ # sort by filesize for faster testing
+ lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
+ lines_size.sort()
+ lines = [f[1] for f in lines_size]
+
+ for i, _dxf in enumerate(lines):
+ if i >= 70:
+ #if 1:
+ print 'Importing', _dxf, '\nNUMBER', i, 'of', len(lines)
+ if True:
+ _dxf_file= _dxf.split('/')[-1].split('\\')[-1]
+ _dxf_file = _dxf_file[:-4] # cut last char:'.dxf'
+ _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:])
+ sce = bpy.data.scenes.new(_dxf_file)
+ bpy.data.scenes.active = sce
+ dxfFileName.val = _dxf
+ main(_dxf)
+
+ print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
+""" \ No newline at end of file
diff --git a/release/scripts/import_mdd.py b/release/scripts/import_mdd.py
index 8e7b9985d3d..1ee196ab67f 100644
--- a/release/scripts/import_mdd.py
+++ b/release/scripts/import_mdd.py
@@ -1,11 +1,11 @@
#!BPY
- #"""
- #Name: 'Load MDD to Mesh RVKs'
- #Blender: 242
- #Group: 'Import'
- #Tooltip: 'baked vertex animation to active mesh object.'
- #"""
+"""
+ Name: 'Load MDD to Mesh RVKs'
+ Blender: 242
+ Group: 'Import'
+ Tooltip: 'baked vertex animation to active mesh object.'
+"""
__author__ = "Bill L.Nieuwendorp"
__bpydoc__ = """\
This script Imports Lightwaves MotionDesigner format.
diff --git a/release/scripts/import_obj.py b/release/scripts/import_obj.py
index 753d8816ff9..e5bdc796e16 100644
--- a/release/scripts/import_obj.py
+++ b/release/scripts/import_obj.py
@@ -535,13 +535,16 @@ def get_float_func(filepath):
find the float function for this obj file
- weather to replace commas or not
'''
- file= open(filepath, 'r')
+ file= open(filepath, 'rU')
for line in file: #.xreadlines():
if line.startswith('v'): # vn vt v
if ',' in line:
return lambda f: float(f.replace(',', '.'))
elif '.' in line:
return float
+
+ # incase all vert values were ints
+ return float
def load_obj(filepath, CLAMP_SIZE= 0.0, CREATE_FGONS= True, CREATE_SMOOTH_GROUPS= True, CREATE_EDGES= True, SPLIT_OBJECTS= True, SPLIT_GROUPS= True, SPLIT_MATERIALS= True, IMAGE_SEARCH=True):
'''
diff --git a/release/scripts/lightwave_import.py b/release/scripts/lightwave_import.py
index 63506a6dc1a..2049fbd2380 100644
--- a/release/scripts/lightwave_import.py
+++ b/release/scripts/lightwave_import.py
@@ -656,7 +656,12 @@ def read_clip(lwochunk, dir_part):
# ima, IMAG, g_IMAG refers to clip dictionary 'ID' entries: refer to blok and surf
clip_dict = {}
data = cStringIO.StringIO(lwochunk.read())
- image_index, = struct.unpack(">L", data.read(4))
+ data_str = data.read(4)
+ if len(data_str) < 4: # can be zero also??? :/
+ # Should not happen but lw can import so we should too
+ return
+
+ image_index, = struct.unpack(">L", data_str)
clip_dict['ID'] = image_index
i = 4
while(i < lwochunk.chunksize):
@@ -693,7 +698,7 @@ def read_clip(lwochunk, dir_part):
i = i + 6 + subchunklen
#end loop on surf chunks
###if DEBUG: print "read image:%s" % clip_dict
- if clip_dict.has_key('XREF'):
+ if 'XREF' in clip_dict: # has_key
###if DEBUG: print "Cross-reference: no image pre-allocated."
return clip_dict
#look for images
@@ -985,7 +990,8 @@ def read_surfs(lwochunk, surf_list, tag_list):
if uvname: # != "":
my_dict['UVNAME'] = uvname #theoretically there could be a number of them: only one used per surf
- if not(my_dict.has_key('g_IMAG')) and (rr.has_key('CHAN')) and (rr.has_key('OPAC')) and (rr.has_key('IMAG')):
+ # all are dictionaries - so testing keys
+ if not('g_IMAG' in my_dict) and ('CHAN' in rr) and ('OPAC' in rr) and ('IMAG' in rr):
if (rr['CHAN'] == 'COLR') and (rr['OPAC'] == 0):
my_dict['g_IMAG'] = rr['IMAG'] #do not set anything, just save image object for later assignment
subchunklen = 0 #force ending
@@ -1005,40 +1011,6 @@ def read_surfs(lwochunk, surf_list, tag_list):
###if DEBUG: print "-> Material pre-allocated."
return my_dict
-
-
-def reduce_face(verts, face):
- TriangleArea= Blender.Mathutils.TriangleArea
- Vector= Blender.Mathutils.Vector
- ####if DEBUG: print len(face), face
- # wants indicies local to the face
- len_face= len(face)
- if len_face==3:
- return [face]
- elif len_face==4:
- vecs= [Vector(verts[i]) for i in face]
- # Get the convave quad area
- a1= TriangleArea(vecs[0], vecs[1], vecs[2])
- a2= TriangleArea(vecs[0], vecs[2], vecs[3])
-
- a3= TriangleArea(vecs[0], vecs[1], vecs[3])
- a4= TriangleArea(vecs[1], vecs[2], vecs[3])
-
- if abs((a1+a2) - (a3+a4)) < (a1+a2+a3+a4)/100: # Not convace
- ####if DEBUG: print 'planer'
- return [[0,1,2,3]]
- if a1+a2<a3+a4:
- return [[0,1,2], [0,2,3]]
- else:
- return [[0,1,3], [1,2,3]]
-
- else: # 5+
- ####if DEBUG: print 'SCANFILL...', len(face)
- ngons= BPyMesh.ngon(verts, face, PREF_FIX_LOOPS= True)
- return ngons
-
-
-
# =========================
# === Recalculate Faces ===
# =========================
@@ -1109,7 +1081,7 @@ def my_create_mesh(clip_list, surf, objspec_list, current_facelist, objname, not
pass
msh.mode |= Blender.Mesh.Modes.AUTOSMOOTH #smooth it anyway
- if surf.has_key('SMAN'):
+ if 'SMAN' in surf: # has_key
#not allowed mixed mode mesh (all the mesh is smoothed and all with the same angle)
#only one smoothing angle will be active! => take the max one
msh.degr = min(80, int(surf['SMAN']/3.1415926535897932384626433832795*180.0)) #lwo in radians - blender in degrees
@@ -1119,12 +1091,8 @@ def my_create_mesh(clip_list, surf, objspec_list, current_facelist, objname, not
except:
img= None
-
#uv_flag = ((surf.has_key('UVNAME')) and (uvcoords_dict.has_key(surf['UVNAME'])) and (img != None))
- uv_flag = ((surf.has_key('UVNAME')) and (uvcoords_dict.has_key(surf['UVNAME'])))
-
-
-
+ uv_flag = (('UVNAME' in surf) and (surf['UVNAME'] in uvcoords_dict))
###if DEBUG: print "\n#===================================================================#"
###if DEBUG: print "Processing Object: %s" % objname
@@ -1186,55 +1154,50 @@ def my_create_mesh(clip_list, surf, objspec_list, current_facelist, objname, not
uvs.append(default_uv)
return uvs
-
+ cur_face
for i in cur_ptag_faces_indexes:
cur_face = complete_facelist[i]
numfaceverts = len(cur_face)
if numfaceverts == 2: edges.append((vertex_map[cur_face[0]], vertex_map[cur_face[1]]))
- elif numfaceverts == 3:
- rev_face = (cur_face[2], cur_face[1], cur_face[0])
+ elif numfaceverts == 3 or numfaceverts == 4:
+ rev_face = [__i for __i in reversed(cur_face)]
face_data.append( [vertex_map[j] for j in rev_face] )
if uv_flag: face_uvs.append(tmp_get_face_uvs(rev_face, i))
-
- elif numfaceverts > 3:
- meta_faces= reduce_face(complete_vertlist, cur_face) # Indices of triangles
+ elif numfaceverts > 4:
+ meta_faces= BPyMesh.ngon(complete_vertlist, cur_face, PREF_FIX_LOOPS= True)
edge_face_count = {}
for mf in meta_faces:
- # ###if DEBUG: print meta_faces
+ # These will always be tri's since they are scanfill faces
+ mf = cur_face[mf[2]], cur_face[mf[1]], cur_face[mf[0]]
+ face_data.append( [vertex_map[j] for j in mf] )
- if len(mf) == 3: #triangle
- mf = cur_face[mf[2]], cur_face[mf[1]], cur_face[mf[0]]
- face_data.append( [vertex_map[j] for j in mf] )
-
- if uv_flag: face_uvs.append(tmp_get_face_uvs(mf, i))
-
- #if USE_FGON:
- if len(meta_faces) > 1:
- mf = face_data[-1] # reuse mf
- for i in xrange(3):
- v1= mf[i]
- v2= mf[i-1]
- if v1!=v2:
- if v1>v2:
- v2,v1= v1,v2
- try:
- edge_face_count[v1,v2]+= 1
- except:
- edge_face_count[v1,v2]= 0
+ if uv_flag: face_uvs.append(tmp_get_face_uvs(mf, i))
+
+ #if USE_FGON:
+ if len(meta_faces) > 1:
+ mf = face_data[-1] # reuse mf
+ for j in xrange(3):
+ v1= mf[j]
+ v2= mf[j-1]
+ if v1!=v2:
+ if v1>v2:
+ v2,v1= v1,v2
+ try:
+ edge_face_count[v1,v2]+= 1
+ except:
+ edge_face_count[v1,v2]= 0
- else: #quads
- mf= cur_face[mf[3]], cur_face[mf[2]], cur_face[mf[1]], cur_face[mf[0]]
- face_data.append( [vertex_map[j] for j in mf] )
- if uv_flag: face_uvs.append(tmp_get_face_uvs(mf, i))
+
if edge_face_count:
edges_fgon.extend( [vert_key for vert_key, count in edge_face_count.iteritems() if count] )
-
- msh.edges.extend(edges)
+ if edges:
+ msh.edges.extend(edges)
+
face_mapping_removed = msh.faces.extend(face_data, indexList=True)
- if surf.has_key('TRAN') or (mat and mat.alpha<1.0): # incase mat is null
+ if 'TRAN' in surf or (mat and mat.alpha<1.0): # incase mat is null
transp_flag = True
else:
transp_flag = False
@@ -1347,7 +1310,7 @@ def create_objects(clip_list, objspec_list, surf_list):
def lookup_imag(clip_list, ima_id):
for ii in clip_list:
if ii and ii['ID'] == ima_id:
- if ii.has_key('XREF'):
+ if 'XREF' in ii: # has_key
#cross reference - recursively look for images
return lookup_imag(clip_list, ii['XREF'])
else:
@@ -1415,7 +1378,7 @@ def create_blok(surf, mat, clip_list, obj_size, obj_pos):
#if not blok['ENAB']:
# ###if DEBUG: print "***Image is not ENABled! Quitting this block"
# break
- if not(blok.has_key('IMAG')):
+ if not('IMAG' in blok): # has_key
###if DEBUG: print "***No IMAGE for this block? Quitting"
break #extract out the image index within the clip_list
if blok['IMAG'] == 0: blok['IMAG'] = lastimag #experimental ....
@@ -1434,13 +1397,13 @@ def create_blok(surf, mat, clip_list, obj_size, obj_pos):
tname += "+"
else:
tname += "x" #let's signal when should not be enabled
- if blok.has_key('CHAN'):
+ if 'CHAN' in blok: # has_key
tname += blok['CHAN']
newtex = bpy.data.textures.new(tname)
newtex.setType('Image') # make it anu image texture
newtex.image = img
#how does it extends beyond borders
- if blok.has_key('WRAP'):
+ if 'WRAP' in blok: # has_key
if (blok['WRAP'] == 3) or (blok['WRAP'] == 2):
newtex.setExtend('Extend')
elif (blok['WRAP'] == 1):
@@ -1457,35 +1420,35 @@ def create_blok(surf, mat, clip_list, obj_size, obj_pos):
nega = False
mapflag = Blender.Texture.MapTo.COL #default to color
maptype = Blender.Texture.Mappings.FLAT
- if blok.has_key('CHAN'):
- if blok['CHAN'] == 'COLR' and blok.has_key('OPACVAL'):
+ if 'CHAN' in blok: # has_key
+ if blok['CHAN'] == 'COLR' and 'OPACVAL' in blok: # has_key
colfac = blok['OPACVAL']
# Blender needs this to be clamped
colfac = max(0.0, min(1.0, colfac))
###if DEBUG: print "!!!Set Texture -> MapTo -> Col = %.3f" % colfac
if blok['CHAN'] == 'BUMP':
mapflag = Blender.Texture.MapTo.NOR
- if blok.has_key('OPACVAL'): norfac = blok['OPACVAL']
+ if 'OPACVAL' in blok: norfac = blok['OPACVAL'] # has_key
###if DEBUG: print "!!!Set Texture -> MapTo -> Nor = %.3f" % norfac
if blok['CHAN'] == 'LUMI':
mapflag = Blender.Texture.MapTo.EMIT
- if blok.has_key('OPACVAL'): dvar = blok['OPACVAL']
+ if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
if blok['CHAN'] == 'DIFF':
mapflag = Blender.Texture.MapTo.REF
- if blok.has_key('OPACVAL'): dvar = blok['OPACVAL']
+ if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
if blok['CHAN'] == 'SPEC':
mapflag = Blender.Texture.MapTo.SPEC
- if blok.has_key('OPACVAL'): dvar = blok['OPACVAL']
+ if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
if blok['CHAN'] == 'TRAN':
mapflag = Blender.Texture.MapTo.ALPHA
- if blok.has_key('OPACVAL'): dvar = blok['OPACVAL']
+ if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
alphaflag = 1
nega = True
- if blok.has_key('NEGA'):
+ if 'NEGA' in blok: # has_key
###if DEBUG: print "!!!Watch-out: effect of this texture channel must be INVERTED!"
nega = not nega
@@ -1498,7 +1461,7 @@ def create_blok(surf, mat, clip_list, obj_size, obj_pos):
'Texture Displacement',
'Additive']
set_blendmode = 7 #default additive
- if blok.has_key('OPAC'):
+ if 'OPAC' in blok: # has_key
set_blendmode = blok['OPAC']
if set_blendmode == 5: #transparency
newtex.imageFlags |= Blender.Texture.ImageFlags.CALCALPHA
@@ -1509,7 +1472,7 @@ def create_blok(surf, mat, clip_list, obj_size, obj_pos):
axis = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z]
size = [1.0] * 3
ofs = [0.0] * 3
- if blok.has_key('PROJ'):
+ if 'PROJ' in blok: # has_key
if blok['PROJ'] == 0: #0 - Planar
###if DEBUG: print "!!!Flat projection"
coordflag = Blender.Texture.TexCo.ORCO
@@ -1598,44 +1561,44 @@ def update_material(clip_list, objspec, surf_list):
break
#mat = Blender.Material.New(surf['NAME'])
#surf['g_MAT'] = mat
- if surf.has_key('COLR'):
+ if 'COLR' in surf: # has_key
mat.rgbCol = surf['COLR']
- if surf.has_key('LUMI'):
+ if 'LUMI' in surf:
mat.setEmit(surf['LUMI'])
- if surf.has_key('GVAL'):
+ if 'GVAL' in surf: # has_key
mat.setAdd(surf['GVAL'])
- if surf.has_key('SPEC'):
- mat.setSpec(surf['SPEC']) #it should be * 2 but seems to be a bit higher lwo [0.0, 1.0] - blender [0.0, 2.0]
- if surf.has_key('DIFF'):
- mat.setRef(surf['DIFF']) #lwo [0.0, 1.0] - blender [0.0, 1.0]
- if surf.has_key('GLOS'): #lwo [0.0, 1.0] - blender [0, 255]
- glo = int(371.67 * surf['GLOS'] - 42.334) #linear mapping - seems to work better than exp mapping
- if glo <32: glo = 32 #clamped to 32-255
+ if 'SPEC' in surf: # has_key
+ mat.setSpec(surf['SPEC']) #it should be * 2 but seems to be a bit higher lwo [0.0, 1.0] - blender [0.0, 2.0]
+ if 'DIFF' in surf: # has_key
+ mat.setRef(surf['DIFF']) #lwo [0.0, 1.0] - blender [0.0, 1.0]
+ if 'GLOS' in surf: # has_key #lwo [0.0, 1.0] - blender [0, 255]
+ glo = int(371.67 * surf['GLOS'] - 42.334) #linear mapping - seems to work better than exp mapping
+ if glo <32: glo = 32 #clamped to 32-255
if glo >255: glo = 255
mat.setHardness(glo)
- if surf.has_key('TRNL'):
+ if 'TRNL' in surf: # has_key
mat.setTranslucency(surf['TRNL']) #NOT SURE ABOUT THIS lwo [0.0, 1.0] - blender [0.0, 1.0]
- mm = mat.getMode()
+ mm = mat.mode
mm |= Blender.Material.Modes.TRANSPSHADOW
- if surf.has_key('REFL'):
+ if 'REFL' in surf: # has_key
mat.setRayMirr(surf['REFL']) #lwo [0.0, 1.0] - blender [0.0, 1.0]
mm |= Blender.Material.Modes.RAYMIRROR
- if surf.has_key('TRAN'):
+ if 'TRAN' in surf: # has_key
mat.setAlpha(1.0-surf['TRAN']) #lwo [0.0, 1.0] - blender [1.0, 0.0]
mm |= Blender.Material.Modes.RAYTRANSP
- if surf.has_key('RIND'):
+ if 'RIND' in surf: # has_key
s = surf['RIND']
if s < 1.0: s = 1.0
if s > 3.0: s = 3.0
mat.setIOR(s) #clipped to blender [1.0, 3.0]
mm |= Blender.Material.Modes.RAYTRANSP
- if surf.has_key('BLOK') and surf['BLOK'] != []:
+ if 'BLOK' in surf and surf['BLOK'] != []:
#update the material according to texture.
alphaflag = create_blok(surf, mat, clip_list, obj_size, obj_pos)
if alphaflag:
mm |= Blender.Material.Modes.RAYTRANSP
- mat.setMode(mm)
+ mat.mode = mm
#finished setting up the material
#end if exist SURF
#end loop on materials (SURFs)
@@ -1679,9 +1642,10 @@ def main():
if __name__=='__main__':
main()
-"""
-# Cams debugging lwo loader
+
+# Cams debugging lwo loader
+"""
TIME= Blender.sys.time()
import os
print 'Searching for files'
@@ -1690,6 +1654,12 @@ os.system('find /fe/lwo/Objects/ -follow -iname "*.lwo" > /tmp/templwo_list')
print '...Done'
file= open('/tmp/templwo_list', 'r')
lines= file.readlines()
+
+# sort by filesize for faster testing
+lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
+lines_size.sort()
+lines = [f[1] for f in lines_size]
+
file.close()
def between(v,a,b):
@@ -1706,8 +1676,9 @@ for i, _lwo in enumerate(lines):
#if between(i, 525, 550):
#if i > 1635:
#if i != 1519: # 730
- if i>125:
- _lwo= _lwo[:-1]
+ if i>141:
+ #if 1:
+ # _lwo= _lwo[:-1]
print 'Importing', _lwo, '\nNUMBER', i, 'of', len(lines)
_lwo_file= _lwo.split('/')[-1].split('\\')[-1]
newScn= bpy.data.scenes.new(_lwo_file)
diff --git a/release/scripts/mesh_edges2curves.py b/release/scripts/mesh_edges2curves.py
index fdf61298ebc..f65eccae9a4 100644
--- a/release/scripts/mesh_edges2curves.py
+++ b/release/scripts/mesh_edges2curves.py
@@ -12,7 +12,7 @@ __version__ = "1.0 2006/02/08"
__bpydoc__ = """\
Edges to Curves
-This script converts open and closed edge loops into polylines
+This script converts open and closed edge loops into curve polylines
Supported:<br>
Polylines where each vert has no more then 2 edges attached to it.
@@ -39,17 +39,8 @@ Supported:<br>
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
-
from Blender import *
-def edkey(ed):
- i1 = ed.v1.index
- i2 = ed.v2.index
- if i1>i2:
- return (i2,i1), ed
- else:
- return (i1,i2), ed
-
def polysFromMesh(me):
# a polyline is 2
#polylines are a list
@@ -138,6 +129,7 @@ def mesh2polys():
v= poly[vIdx]
cu.appendNurb([v.co.x, v.co.y, v.co.z, w, t])
+ vIdx += 1
cu[i].type= 0 # Poly Line
# Close the polyline if its closed.
diff --git a/release/scripts/mesh_skin.py b/release/scripts/mesh_skin.py
index fdb721bc9f3..a554e128b41 100644
--- a/release/scripts/mesh_skin.py
+++ b/release/scripts/mesh_skin.py
@@ -628,7 +628,7 @@ def main():
try: me.faces.delete(1, [ f for f in me.faces if f.sel ])
except: pass
- me.faces.extend(faces)
+ me.faces.extend(faces, smooth = True)
print '\nSkin done in %.4f sec.' % (Blender.sys.time()-time1)
diff --git a/release/scripts/mesh_unfolder.py b/release/scripts/mesh_unfolder.py
index 8ebf1777c2e..906e0f0a300 100644
--- a/release/scripts/mesh_unfolder.py
+++ b/release/scripts/mesh_unfolder.py
@@ -1,10 +1,10 @@
#!BPY
"""
Name: 'Unfold'
-Blender: 243
+Blender: 245
Group: 'Mesh'
Tip: 'Unfold meshes to create nets'
-Version: v2.2.4
+Version: v2.5
Author: Matthew Chadwick
"""
import Blender
@@ -18,16 +18,18 @@ try:
from math import *
import sys
import random
- from decimal import *
import xml.sax, xml.sax.handler, xml.sax.saxutils
+
+ # annoying but need so classes dont raise errors
+ xml_sax_handler_ContentHandler = xml.sax.handler.ContentHandler
except:
- print "One of the Python modules required can't be found."
- print sys.exc_info()[1]
- traceback.print_exc(file=sys.stdout)
-
+ Draw.PupMenu('Error%t|A full python installation is required to run this script.')
+ xml = None
+ xml_sax_handler_ContentHandler = type(0)
+
__author__ = 'Matthew Chadwick'
-__version__ = '2.2.4 24032007'
+__version__ = '2.5 06102007'
__url__ = ["http://celeriac.net/unfolder/", "blender", "blenderartist"]
__email__ = ["post at cele[remove this text]riac.net", "scripts"]
__bpydoc__ = """\
@@ -79,7 +81,7 @@ class FacesAndEdges:
self.edgeFaces[key].append(face)
def findTakenAdjacentFace(self, bface, edge):
return self.findAdjacentFace(bface, edge)
- # find the first untaken (non-selected) adjacent face in the list of adjacent faces for the given edge
+ # find the first untaken (non-selected) adjacent face in the list of adjacent faces for the given edge (allows for manifold meshes too)
def findAdjacentFace(self, bface, edge):
faces = self.edgeFaces[edge.key()]
for i in xrange(len(faces)):
@@ -107,84 +109,7 @@ class FacesAndEdges:
if(bface!=None):
bface.sel= True
self.nfaces+=1
-
-
-class IntersectionResult:
- def __init__(self, rn, rd, v=None):
- self.v = v
- self.rd = rd
- self.rn = rn
- def intersected(self):
- return not(not(self.v))
- def isParallel(self):
- return (self.rd==0)
- def isColinear(self):
- return (self.rn==0)
- def intersection(self):
- return self.v
-
-# represents a line segment between two points [p1, p2]. the points are [x,y]
-class LineSegment:
- def __init__(self, p):
- self.p = p
- def intersects(self, s):
- rn = ((self.p[0].y-s.p[0].y)*(s.p[1].x-s.p[0].x)-(self.p[0].x-s.p[0].x)*(s.p[1].y-s.p[0].y))
- rd = ((self.p[1].x-self.p[0].x)*(s.p[1].y-s.p[0].y)-(self.p[1].y-self.p[0].y)*(s.p[1].x-s.p[0].x))
- # need an epsilon closeTo() here
- if(rd<0.0000001 or rn==0.0):
- return IntersectionResult(rn,rd)
- r = rn/rd
- s = ((self.p[0].y-s.p[0].y)*(self.p[1].x-self.p[0].x)-(self.p[0].x-s.p[0].x)*(self.p[1].y-self.p[0].y)) / rd
- i = (0.0<=r and r<=1.0 and 0.0<=s and s<=1.0)
- if not(i):
- return None
- ix = self.p[0].x + r*(self.p[1].x - self.p[0].x)
- iy = self.p[0].y + r*(self.p[1].y - self.p[0].y)
- t = 0.0001
- if ( abs(ix-self.p[0].x)>t and abs(iy-self.p[0].x)>t and abs(ix-self.p[1].x)>t and abs(iy-self.p[1].y)>t ):
- return IntersectionResult( rn, rd,Vector([ix,iy,0.0]))
- else:
- return None
-
-class LineSegments:
- def __init__(self, face):
- self.face = face
- def segmentAt(self, i):
- if(i>self.face.nPoints()-1):
- return None
- if(i==self.face.nPoints()-1):
- j = 0
- else:
- j = i+1
- return LineSegment([ self.face.v[i], self.face.v[j] ])
- def iterateSegments(self, something):
- results = []
- for i in xrange(self.face.nPoints()):
- results.extend(something.haveSegment(self.segmentAt(i)))
- return results
- def compareSegments(self, something, segment):
- results = []
- for i in xrange(self.face.nPoints()):
- results.append(something.compareSegments([self.segmentAt(i), segment]))
- return results
-
-class FaceOverlapTest:
- def __init__(self, face1, face2):
- self.faces = [face1, face2]
- self.segments = [ LineSegments(self.faces[0]), LineSegments(self.faces[1]) ]
- def suspectsOverlap(self):
- tests = self.segments[0].iterateSegments(self)
- gi = 0
- for i in tests:
- if( i!=None and i.intersected() ):
- gi+=1
- return gi>0
- def haveSegment(self, segment):
- return self.segments[1].compareSegments(self, segment)
- def compareSegments(self, segments):
- return segments[0].intersects(segments[1])
-
# A fold between two faces with a common edge
class Fold:
@@ -398,7 +323,7 @@ class Net:
if(len(ff.v)<3):
raise Exception("This mesh contains an isolated edge - it must consist only of faces")
testFace = Poly.fromVectors( [ Vector([0.0,0.0,0.0]), Vector([0.0,1.0,0.0]), Vector([1.0,1.0,0.0]) ] )
- # hmmm
+ # hmmm. I honestly can't remember why this needs to be done, but it does.
u=0
v=1
w=2
@@ -412,6 +337,7 @@ class Net:
xyFold = Fold(None, xyFace, refFace, Edge(xyFace.v[0], xyFace.v[1] ))
self.refFold = Fold(xyFold, refFace, ff, Edge(refFace.v[0], refFace.v[1] ))
self.refFold.srcFace = self.firstFace
+ # prepare to grow the trees
trunk = Tree(self, None, self.refFold)
trunk.generations = self.generations
self.firstPoly = ff
@@ -423,6 +349,7 @@ class Net:
self.folds.append(self.refFold)
trunk.grow()
i = 0
+ # keep the trees growing while they can
while(self.myFacesVisited<len(self.src.faces) and len(self.branches) > 0):
if self.edgeIteratorClass==RandomEdgeIterator:
i = random.randint(0,len(self.branches)-1)
@@ -459,11 +386,12 @@ class Net:
for afold in folds:
mdf = afold.unfoldedFace()
if(afold!=fold):
- it1 = FaceOverlapTest(mf, mdf)
- it2 = FaceOverlapTest(mdf, mf)
- overlap = (it1.suspectsOverlap() or it2.suspectsOverlap())
+ # currently need to get agreement from both polys because
+ # a touch by a vertex of one the other's edge is acceptable &
+ # they disagree on that
+ intersects = mf.intersects2D(mdf) and mdf.intersects2D(mf)
inside = ( mdf.containsAnyOf(mf) or mf.containsAnyOf(mdf) )
- if( overlap or inside or mdf.overlays(mf)):
+ if( intersects or inside or mdf.overlays(mf)):
c.append(afold)
return c
def getOverlapsBetweenGL(self, fold, folds):
@@ -644,9 +572,9 @@ class Net:
overlaps = self.report()
attempts+=1
return attempts
- def unfoldSelected(feedback=None, netName=None):
+ def fromSelected(feedback=None, netName=None):
return Net.createNet(Blender.Object.GetSelected()[0], feedback, netName)
- unfoldSelected = staticmethod(unfoldSelected)
+ fromSelected = staticmethod(fromSelected)
def clone(self, object=None):
if(object==None):
object = self.object
@@ -823,7 +751,7 @@ class Curvature(EdgeIterator):
g += f.dihedralAngle()
self.gooodness = g
-
+
class Edge:
def __init__(self, v1=None, v2=None, mEdge=None, i=-1):
self.idx = i
@@ -891,6 +819,23 @@ class Edge:
return +1
else:
return -1
+ # Does the given segment intersect this, for overlap detection.
+ # endpoints are allowed to touch the line segment
+ def intersects2D(self, s):
+ if(self.matches(s)):
+ return False
+ else:
+ i = Geometry.LineIntersect2D(self.v1, self.v2, s.v1, s.v2)
+ if(i!=None):
+ i.resize4D()
+ i.z = self.v1.z # hack to put the point on the same plane as this edge for comparison
+ return(i!=None and not(self.endsWith(i)))
+ def matches(self, s):
+ return ( (self.v1==s.v1 and self.v2==s.v2) or (self.v2==s.v1 and self.v1==s.v2) )
+ # Is the given point on the end of this segment ? 10-5 seems to an acceptable limit for closeness in Blender
+ def endsWith(self, aPoint, e=0.0001):
+ return ( (self.v1-aPoint).length < e or (self.v2-aPoint).length < e )
+
class Poly:
ids = -1
@@ -899,6 +844,7 @@ class Poly:
self.v = []
self.id = Poly.ids
self.boundz = None
+ self.edges = None
def getID(self):
return self.id
def normal(self):
@@ -910,6 +856,21 @@ class Poly:
q = a-c
q.resize3D()
return CrossVecs(p,q)
+ def makeEdges(self):
+ self.edges = []
+ for i in xrange(self.nPoints()):
+ self.edges.append(Edge( self.v[i % self.nPoints()], self.v[ (i+1) % self.nPoints()] ))
+ def edgeAt(self, i):
+ if(self.edges==None):
+ self.makeEdges()
+ return self.edges[i]
+ def intersects2D(self, poly):
+ for i in xrange(self.nPoints()):
+ edge = self.edgeAt(i)
+ for j in xrange(poly.nPoints()):
+ if edge.intersects2D(poly.edgeAt(j)):
+ return True
+ return False
def isBad(self):
badness = 0
for vv in self.v:
@@ -1031,8 +992,7 @@ class Poly:
def toString(self):
return self.v
# This is the BEST algorithm for point-in-polygon detection.
- # It's by W. Randolph Franklin. It's also very beautiful (looks even better in C).
- # All the others are shite; they give false positives.
+ # It's by W. Randolph Franklin.
# returns 1 for inside, 1 or 0 for edges
def contains(self, tp):
c = 0
@@ -1114,6 +1074,7 @@ class SVGExporter:
def export(self):
self.net.unfoldTo(1)
bb = self.object.getBoundBox()
+ print bb
self.vxmin = bb[0][0]
self.vymin = bb[0][1]
self.vxmax = bb[7][0]
@@ -1141,14 +1102,14 @@ class SVGExporter:
self.addPolys()
self.e.endElement("clipPath")
def addUVImage(self):
- image = Blender.Image.GetCurrent()
+ image = Blender.Image.GetCurrent() #hmm - how to determine the desired image ?
if image==None:
return
ifn = image.getFilename()
- #ifn = self.filename.replace(".svg", ".jpg")
- #image.setFilename(ifn)
- #ifn = ifn[ifn.rfind("/")+1:]
- #image.save()
+ ifn = self.filename.replace(".svg", ".jpg")
+ image.setFilename(ifn)
+ ifn = ifn[ifn.rfind("/")+1:]
+ image.save()
atts = {}
atts["clip-path"] = "url(#netClip)"
atts["xlink:href"] = ifn
@@ -1242,7 +1203,7 @@ class SVGExporter:
traceback.print_exc(file=sys.stdout)
fileSelected = staticmethod(fileSelected)
-
+# for importing nets saved by the above exporter
class NetHandler(xml.sax.handler.ContentHandler):
def __init__(self, net):
self.net = net
@@ -1413,7 +1374,7 @@ class GUI:
while(s):# and search < searchLimit):
if(net!=None):
name = net.des.name
- net = Net.unfoldSelected(self, name)
+ net = Net.fromSelected(self, name)
net.setAvoidsOverlaps(not(self.overlaps.val))
print
print "Unfolding selected object"
@@ -1516,6 +1477,14 @@ class GUI:
else:
self.nOverlaps = 0
Draw.Redraw(1)
+ if(evt==233):
+ f1 = Poly.fromBlenderFace(Blender.Object.GetSelected()[0].getData().faces[0])
+ f2 = Poly.fromBlenderFace(Blender.Object.GetSelected()[1].getData().faces[0])
+ print
+ print Blender.Object.GetSelected()[0].getName()
+ print Blender.Object.GetSelected()[1].getName()
+ print f1.intersects2D(f2)
+ print f2.intersects2D(f1)
if(evt==714):
Net.unfoldAll(self)
Draw.Redraw(1)
@@ -1567,6 +1536,7 @@ class GUI:
Draw.Button("Unfold", 1, l.nx(), l.ny(), l.cw, l.ch, "Unfold selected mesh to net")
Draw.Button("save", 104, l.nx(), l.ny(), l.cw, l.ch, "Save net as SVG")
Draw.Button("load", 107, l.nx(), l.ny(), l.cw, l.ch, "Load net from SVG")
+ #Draw.Button("test", 233, l.nx(), l.ny(), l.cw, l.ch, "test")
# unfolding enthusiasts - try uncommenting this
self.ancestors = Draw.Number("depth", 654, l.nx(), l.ny(), cw, ch, self.ancestors.val, 0, 9999, "depth of branching 0=diffuse")
#self.noise = Draw.Number("noise", 631, l.nx(), l.ny(), cw, ch, self.noise.val, 0.0, 1.0, "noisyness of branching")
@@ -1574,7 +1544,7 @@ class GUI:
options = "order %t|random %x0|brightest %x1|curvature %x2|winding %x3| 1010 %x4|largest %x5"
self.shape = Draw.Menu(options, 713, l.nx(), l.ny(), cw, ch, self.shape.val, "shape of net")
Draw.Button("exit", 6, l.nx(), l.ny(), l.cw, l.ch, "exit")
- BGL.glClearColor(0.5, 0.5, 0.5, 1)
+ BGL.glClearColor(0.3, 0.3, 0.3, 1)
BGL.glColor3f(0.3,0.3,0.3)
l.newLine()
BGL.glRasterPos2i(32, 100)
@@ -1601,10 +1571,12 @@ class FlowLayout:
self.y-=self.ch+self.margin
self.x = self.margin
-try:
- sys.setrecursionlimit(10000)
- gui = GUI()
- gui.makeStandardGUI()
- #gui.makePopupGUI()
-except:
- traceback.print_exc(file=sys.stdout)
+# if xml is None, then dont bother running the script
+if xml:
+ try:
+ sys.setrecursionlimit(10000)
+ gui = GUI()
+ gui.makeStandardGUI()
+ #gui.makePopupGUI()
+ except:
+ traceback.print_exc(file=sys.stdout)
diff --git a/release/scripts/mesh_wire.py b/release/scripts/mesh_wire.py
index 35cfa325497..bd38c47a9b9 100644
--- a/release/scripts/mesh_wire.py
+++ b/release/scripts/mesh_wire.py
@@ -44,6 +44,7 @@ from BPyMathutils import angleToLength
import mesh_solidify
import BPyMessages
+reload(BPyMessages)
import bpy
@@ -219,9 +220,7 @@ def solid_wire(ob_orig, me_orig, sce, PREF_THICKNESS, PREF_SOLID, PREF_SHARP, PR
for ii in vusers:
co += me.verts[ii].co
co /= len(vusers)
-
-
-
+
me.faces.delete(1, range(len(me.faces)))
me.faces.extend(new_faces)
@@ -245,6 +244,18 @@ def main():
BPyMessages.Error_NoMeshActive()
return
+ # Saves the editmode state and go's out of
+ # editmode if its enabled, we cant make
+ # changes to the mesh data while in editmode.
+ is_editmode = Window.EditMode()
+ Window.EditMode(0)
+
+ me = ob_act.getData(mesh=1) # old NMesh api is default
+ if len(me.faces)==0:
+ BPyMessages.Error_NoMeshFaces()
+ if is_editmode: Window.EditMode(1)
+ return
+
# Create the variables.
PREF_THICK = Blender.Draw.Create(0.005)
PREF_SOLID = Blender.Draw.Create(1)
@@ -259,16 +270,10 @@ def main():
]
if not Blender.Draw.PupBlock('Solid Wireframe', pup_block):
+ if is_editmode: Window.EditMode(1)
return
- # Saves the editmode state and go's out of
- # editmode if its enabled, we cant make
- # changes to the mesh data while in editmode.
- is_editmode = Window.EditMode()
- Window.EditMode(0)
-
Window.WaitCursor(1)
- me = ob_act.getData(mesh=1) # old NMesh api is default
t = sys.time()
# Run the mesh editing function
@@ -282,4 +287,4 @@ def main():
# This lets you can import the script without running it
if __name__ == '__main__':
- main() \ No newline at end of file
+ main()
diff --git a/release/scripts/object_drop.py b/release/scripts/object_drop.py
index 4ea8bde2ca8..63a0bd574fb 100644
--- a/release/scripts/object_drop.py
+++ b/release/scripts/object_drop.py
@@ -1,7 +1,7 @@
#!BPY
"""
Name: 'Drop Onto Ground'
-Blender: 243
+Blender: 245
Group: 'Object'
Tooltip: 'Drop the selected objects onto "ground" objects'
"""
@@ -221,4 +221,5 @@ def main():
if __name__ == '__main__':
main()
-GLOBALS.clear() \ No newline at end of file
+GLOBALS.clear()
+
diff --git a/release/scripts/object_find.py b/release/scripts/object_find.py
index 4ce93998f00..0cfd6ad1d92 100644
--- a/release/scripts/object_find.py
+++ b/release/scripts/object_find.py
@@ -41,20 +41,27 @@ import BPyMessages
def get_object_images(ob):
# Could optimize this
- if ob.type == 'Mesh':
- unique_images = {}
- me = ob.getData(mesh=1)
- orig_uvlayer = me.activeUVLayer
-
- for uvlayer in me.getUVLayerNames():
- me.activeUVLayer = uvlayer
- for f in me.faces:
- i = f.image
- if i: unique_images[i.name] = i
-
- me.activeUVLayer = orig_uvlayer
-
- return unique_images.values()
+ if ob.type != 'Mesh':
+ return []
+
+ me = ob.getData(mesh=1)
+
+ if not me.faceUV:
+ return []
+
+ unique_images = {}
+
+ orig_uvlayer = me.activeUVLayer
+
+ for uvlayer in me.getUVLayerNames():
+ me.activeUVLayer = uvlayer
+ for f in me.faces:
+ i = f.image
+ if i: unique_images[i.name] = i
+
+ me.activeUVLayer = orig_uvlayer
+
+ return unique_images.values()
# Todo, support other object types, materials
return []
diff --git a/release/scripts/object_random_loc_sz_rot.py b/release/scripts/object_random_loc_sz_rot.py
index 13c42e859d7..1af0dc7218a 100755..100644
--- a/release/scripts/object_random_loc_sz_rot.py
+++ b/release/scripts/object_random_loc_sz_rot.py
@@ -33,46 +33,67 @@ This script randomizes the selected objects location/size/rotation.
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
+'''
+30 Jun 07 - ZanQdo:
+ - Properly coded axis toggles for Loc random (didn't work at all)
+ - Made Rot input values meaningful (45 will give max 45 degres of rotation)
+ - Pumped up the Scale value limit
+ - Made Scale input values meaningful (15 will give max 15 units bigger model)
+'''
+
from Blender import Draw, Scene
from Blender.Mathutils import Rand
-def rnd():
- return Rand()-0.5
+def rnd(flag):
+ Random = Rand()
+ if flag == "LOC":
+ return (Random - 0.5) * 2
+ elif flag == "ROT":
+ return (Random - 0.5) * 0.035
+ elif flag == "SIZE":
+ return (Random - 0.5) * 1.8
def randomize(sel, PREF_LOC, PREF_SIZE, PREF_ROT, PREF_LINK_AXIS, PREF_X_AXIS, PREF_Y_AXIS, PREF_Z_AXIS):
for ob in sel:
if PREF_LOC:
if PREF_LINK_AXIS:
- rand = PREF_LOC*rnd()
+ rand = PREF_LOC*rnd("LOC")
ob.loc = (ob.LocX+(rand*PREF_X_AXIS), ob.LocY+(rand*PREF_Y_AXIS), ob.LocZ+(rand*PREF_Z_AXIS))
else:
- ob.loc = (ob.LocX+(PREF_LOC*rnd()), ob.LocY+(PREF_LOC*rnd()), ob.LocZ+(PREF_LOC*rnd()))
-
+ if PREF_X_AXIS: x= PREF_LOC*rnd("LOC")
+ else: x= 0
+ if PREF_Y_AXIS: y= PREF_LOC*rnd("LOC")
+ else: y= 0
+ if PREF_Z_AXIS: z= PREF_LOC*rnd("LOC")
+ else: z= 0
+ ob.loc = (ob.LocX+x, ob.LocY+y, ob.LocZ+z)
+
if PREF_SIZE:
if PREF_LINK_AXIS:
- rand = 1 + (PREF_SIZE*rnd())
+ rand = PREF_SIZE*rnd("SIZE")
if PREF_X_AXIS: x= rand
- else: x= 1
+ else: x= 0
if PREF_Y_AXIS: y= rand
- else: y= 1
+ else: y= 0
if PREF_Z_AXIS: z= rand
- else: z= 1
- ob.size = (ob.SizeX*x, ob.SizeY*y, ob.SizeZ*z)
+ else: z= 0
+
else:
- if PREF_X_AXIS: x= 1+ PREF_SIZE*rnd()
- else: x= 1
- if PREF_Y_AXIS: y= 1+ PREF_SIZE*rnd()
- else: y= 1
- if PREF_Z_AXIS: z= 1+ PREF_SIZE*rnd()
- else: z= 1
+ if PREF_X_AXIS: x= PREF_SIZE*rnd("SIZE")
+ else: x= 0
+ if PREF_Y_AXIS: y= PREF_SIZE*rnd("SIZE")
+ else: y= 0
+ if PREF_Z_AXIS: z= PREF_SIZE*rnd("SIZE")
+ else: z= 0
- ob.size = (ob.SizeX*x, ob.SizeY*y, ob.SizeZ*z)
+ ob.size = (abs(ob.SizeX+x), abs(ob.SizeY+y), abs(ob.SizeZ+z))
+
if PREF_ROT:
if PREF_LINK_AXIS:
- rand = PREF_ROT*rnd()
+ rand = PREF_ROT*rnd("ROT")
ob.rot = (ob.RotX+rand, ob.RotY+rand, ob.RotZ+rand)
else:
- ob.rot = (ob.RotX+(PREF_X_AXIS*PREF_ROT*rnd()), ob.RotY+(PREF_Y_AXIS*PREF_ROT*rnd()), ob.RotZ+(PREF_Z_AXIS*PREF_ROT*rnd()))
+ ob.rot = (ob.RotX+(PREF_X_AXIS*PREF_ROT*rnd("ROT")), ob.RotY+(PREF_Y_AXIS*PREF_ROT*rnd("ROT")), ob.RotZ+(PREF_Z_AXIS*PREF_ROT*rnd("ROT")))
def main():
@@ -89,9 +110,9 @@ def main():
PREF_Z_AXIS= Draw.Create(1)
pup_block = [\
- ('loc:', PREF_LOC, 0.0, 10.0, 'Amount to randomize the location'),\
- ('size:', PREF_SIZE, 0.0, 10.0, 'Amount to randomize the size'),\
- ('rot:', PREF_ROT, 0.0, 10.0, 'Amount to randomize the rotation'),\
+ ('loc:', PREF_LOC, 0.0, 100.0, 'Amount to randomize the location'),\
+ ('size:', PREF_SIZE, 0.0, 100.0, 'Amount to randomize the size'),\
+ ('rot:', PREF_ROT, 0.0, 360.0, 'Amount to randomize the rotation'),\
'',\
('Link Axis', PREF_LINK_AXIS, 'Use the same random value for each objects XYZ'),\
('X Axis', PREF_X_AXIS, 'Enable X axis randomization'),\
diff --git a/release/scripts/object_timeofs_follow_act.py b/release/scripts/object_timeofs_follow_act.py
new file mode 100644
index 00000000000..83863da7d8f
--- /dev/null
+++ b/release/scripts/object_timeofs_follow_act.py
@@ -0,0 +1,107 @@
+#!BPY
+"""
+Name: 'TimeOffset follow Active'
+Blender: 245
+Group: 'Object'
+Tooltip: 'ActObs animated loc sets TimeOffset on other objects at closest frame'
+"""
+__author__= "Campbell Barton"
+__url__= ["blender.org", "blenderartists.org"]
+__version__= "1.0"
+
+__bpydoc__= """
+"""
+
+# --------------------------------------------------------------------------
+# TimeOffset follow Active v1.0 by Campbell Barton (AKA Ideasman42)
+# --------------------------------------------------------------------------
+# ***** 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 Image, sys, Draw, Window, Scene, Group
+import bpy
+import BPyMessages
+
+
+def main():
+
+ sce = Scene.GetCurrent()
+
+ ob_act = sce.objects.active
+
+ if not ob_act:
+ Draw.PupMenu("Error%t|no active object")
+ return
+
+ objects = list(sce.objects.context)
+
+ try: objects.remove(ob_act)
+ except: pass
+
+ if not objects:
+ Draw.PupMenu("Error%t|no objects selected")
+ return
+
+ curframe = Blender.Get('curframe')
+
+ FRAME_START= Draw.Create( Blender.Get('staframe') )
+ FRAME_END= Draw.Create( Blender.Get('endframe') )
+
+ # Get USER Options
+ pup_block= [\
+ ('Start:', FRAME_START, 1, 300000, 'Use the active objects position starting at this frame'),\
+ ('End:', FRAME_END, 1, 300000, 'Use the active objects position starting at this frame'),\
+ ]
+
+ if not Draw.PupBlock('Set timeoffset...', pup_block):
+ return
+
+ FRAME_START = FRAME_START.val
+ FRAME_END = FRAME_END.val
+
+ if FRAME_START >= FRAME_END:
+ Draw.PupMenu("Error%t|frames are not valid")
+
+
+ # Ok - all error checking
+ locls_act = []
+ for f in xrange((FRAME_END-FRAME_START)):
+ i = FRAME_START+f
+ Blender.Set('curframe', i)
+ locls_act.append(ob_act.matrixWorld.translationPart())
+
+ for ob in objects:
+ loc = ob.matrixWorld.translationPart()
+ best_frame = -1
+ best_dist = 100000000
+ for i, loc_act in enumerate(locls_act):
+ dist = (loc_act-loc).length
+ if dist < best_dist:
+ best_dist = dist
+ best_frame = i + FRAME_START
+
+ ob.timeOffset = float(best_frame)
+
+ # Set the original frame
+ Blender.Set('curframe', curframe)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/release/scripts/ply_export.py b/release/scripts/ply_export.py
index 010ee72ec67..cecde5a0b59 100644
--- a/release/scripts/ply_export.py
+++ b/release/scripts/ply_export.py
@@ -7,6 +7,7 @@ Group: 'Export'
Tooltip: 'Export active object to Stanford PLY format'
"""
+import bpy
import Blender
from Blender import Mesh, Scene, Window, sys, Image, Draw
import BPyMesh
@@ -64,7 +65,7 @@ def file_callback(filename):
if not filename.lower().endswith('.ply'):
filename += '.ply'
- scn= Blender.Scene.GetCurrent()
+ scn= bpy.data.scenes.active
ob= scn.objects.active
if not ob:
Blender.Draw.PupMenu('Error%t|Select 1 active object')
@@ -89,6 +90,10 @@ def file_callback(filename):
if not Draw.PupBlock('Export...', pup_block):
return
+ is_editmode = Blender.Window.EditMode()
+ if is_editmode:
+ Blender.Window.EditMode(0, '', 0)
+
Window.WaitCursor(1)
EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
@@ -132,7 +137,7 @@ def file_callback(filename):
if vertexColors: col = f.col
for j, v in enumerate(f):
if smooth:
- normal= v.no
+ normal= tuple(v.no)
normal_key = rvec3d(normal)
if faceUV:
@@ -211,12 +216,12 @@ def file_callback(filename):
file.write('\n')
file.close()
-
-
+
+ if is_editmode:
+ Blender.Window.EditMode(1, '', 0)
def main():
Blender.Window.FileSelector(file_callback, 'PLY Export', Blender.sys.makename(ext='.ply'))
-
if __name__=='__main__':
main()
diff --git a/release/scripts/ply_import.py b/release/scripts/ply_import.py
index a1118d8356d..6b96777102a 100644
--- a/release/scripts/ply_import.py
+++ b/release/scripts/ply_import.py
@@ -199,10 +199,14 @@ def read(filename):
obj = obj_spec.load(format_specs[format], file)
except IOError, (errno, strerror):
- file.close()
+ try: file.close()
+ except: pass
+
return None
- file.close()
+ try: file.close()
+ except: pass
+
return (obj_spec, obj);
diff --git a/release/scripts/render_save_layers.py b/release/scripts/render_save_layers.py
new file mode 100644
index 00000000000..04bedde6e8d
--- /dev/null
+++ b/release/scripts/render_save_layers.py
@@ -0,0 +1,116 @@
+#!BPY
+
+"""
+Name: 'Save Render Layers...'
+Blender: 245
+Group: 'Render'
+Tooltip: 'Save current renderlayers as a BPython script'
+"""
+
+__author__ = "Campbell Barton"
+__url__ = ("blender", "elysiun")
+__version__ = "1.0"
+
+__bpydoc__ = """\
+"""
+
+# --------------------------------------------------------------------------
+# The scripts generated by this script are put under Public Domain by
+# default, but you are free to edit the ones you generate with this script
+# and change their license to another one of your choice.
+# --------------------------------------------------------------------------
+# ***** 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.Window import Theme, FileSelector
+from Blender import Scene
+
+sce = Scene.GetCurrent()
+rend = sce.render
+
+# default filename: theme's name + '_theme.py' in user's scripts dir:
+default_fname = Blender.Get("scriptsdir")
+default_fname = Blender.sys.join(default_fname, sce.name + '_renderlayer.py')
+default_fname = default_fname.replace(' ','_')
+
+def write_renderlayers(filename):
+ "Write the current renderlayer as a bpython script"
+
+ if not filename.endswith('.py'): filename += '.py'
+
+ fout = file(filename, "w")
+
+ fout.write("""#!BPY
+
+# \"\"\"
+# Name: '%s'
+# Blender: 245
+# Group: 'Render'
+# Tooltip: ''
+# \"\"\"
+
+__%s__ = "????"
+__%s__ = "2.43"
+__%s__ = ["blender"]
+__%s__ = \"\"\"\\
+You can edit this section to write something about your script that can
+be read then with the Scripts Help Browser script in Blender.
+
+Remember to also set author, version and possibly url(s) above. You can also
+define an __email__ tag, check some bundled script's source for examples.
+\"\"\"
+
+# This script was automatically generated by the save_theme.py bpython script.
+# By default, these generated scripts are released as Public Domain, but you
+# are free to change the license of the scripts you generate with
+# save_theme.py before releasing them.
+
+import Blender
+from Blender import Scene
+
+sce = Scene.GetCurrent()
+rend = sce.render
+""" % (sce.name, "author", "version", "url", "bpydoc"))
+
+ for lay in rend.renderLayers: #
+ fout.write("\nlay = rend.addRenderLayer()\n")
+ fout.write("lay.name = \"%s\"\n" % lay.name)
+
+ exec("vars = dir(lay)")
+
+ for var in vars:
+ if var.startswith('_'):
+ continue
+
+ v = "lay.%s" % var
+ exec("value = %s" % v)
+ if type(value) == str:
+ fout.write("%s = '%s'\n" % (v, value))
+ else:
+ fout.write("%s = %s\n" % (v, value))
+
+ fout.write('\nBlender.Redraw(-1)')
+ fout.close()
+ try:
+ Blender.UpdateMenus()
+ except:
+ Blender.Draw.PupMenu("Warning - check console!%t|Menus could not be automatically updated")
+
+FileSelector(write_renderlayers, "Save RenderLayers", default_fname) \ No newline at end of file
diff --git a/release/scripts/save_theme.py b/release/scripts/save_theme.py
index 7b21b5c74f7..a99050b404d 100644
--- a/release/scripts/save_theme.py
+++ b/release/scripts/save_theme.py
@@ -73,7 +73,11 @@ theme = Theme.Get()[0] # get current theme
# default filename: theme's name + '_theme.py' in user's scripts dir:
default_fname = Blender.Get("scriptsdir")
-default_fname = Blender.sys.join(default_fname, theme.name + '_theme.py')
+if (default_fname):
+ default_fname = Blender.sys.join(default_fname, theme.name + '_theme.py')
+else:
+ default_fname = theme.name + '_theme.py'
+
default_fname = default_fname.replace(' ','_')
def write_theme(filename):
diff --git a/release/scripts/scripttemplate_mesh_edit.py b/release/scripts/scripttemplate_mesh_edit.py
index e94b139a92d..159fb884925 100644
--- a/release/scripts/scripttemplate_mesh_edit.py
+++ b/release/scripts/scripttemplate_mesh_edit.py
@@ -70,6 +70,7 @@ def main():
# editmode if its enabled, we cant make
# changes to the mesh data while in editmode.
is_editmode = Window.EditMode()
+ if is_editmode: Window.EditMode(0)
Window.WaitCursor(1)
me = ob_act.getData(mesh=1) # old NMesh api is default
diff --git a/release/scripts/scripttemplate_pyconstraint.py b/release/scripts/scripttemplate_pyconstraint.py
new file mode 100644
index 00000000000..68aa9194435
--- /dev/null
+++ b/release/scripts/scripttemplate_pyconstraint.py
@@ -0,0 +1,114 @@
+#!BPY
+"""
+Name: 'Script Constraint'
+Blender: 245
+Group: 'ScriptTemplate'
+Tooltip: 'Add a new script for custom constraints'
+"""
+
+from Blender import Window
+import bpy
+
+script_data = \
+"""#BPYCONSTRAINT
+'''
+ PyConstraint template, access this in the "add constraint" scripts submenu.
+ Add docstring here
+'''
+
+import Blender
+from Blender import Draw
+from Blender import Mathutils
+import math
+
+'''
+ This variable specifies the number of targets
+ that this constraint can use
+'''
+NUM_TARGETS = 1
+
+
+'''
+ This function is called to evaluate the constraint
+ obmatrix: (Matrix) copy of owner's 'ownerspace' matrix
+ targetmatrices: (List) list of copies of the 'targetspace' matrices of the targets (where applicable)
+ idprop: (IDProperties) wrapped data referring to this
+ constraint instance's idproperties
+'''
+def doConstraint(obmatrix, targetmatrices, idprop):
+ # Separate out the tranformation components for easy access.
+ obloc = obmatrix.translationPart() # Translation
+ obrot = obmatrix.toEuler() # Rotation
+ obsca = obmatrix.scalePart() # Scale
+
+ # Define user-settable parameters.\
+ # Must also be defined in getSettings().
+ if not idprop.has_key('user_toggle'): idprop['user_toggle'] = 1
+ if not idprop.has_key('user_slider'): idprop['user_slider'] = 1.0
+
+
+ # Do stuff here, changing obloc, obrot, and obsca.
+
+
+ # Convert back into a matrix for loc, scale, rotation,
+ mtxloc = Mathutils.TranslationMatrix( obloc )
+ mtxrot = obrot.toMatrix().resize4x4()
+ mtxsca = Mathutils.Matrix([obsca[0],0,0,0], [0,obsca[1],0,0], [0,0,obsca[2],0], [0,0,0,1])
+
+ # Recombine the separate elements into a transform matrix.
+ outputmatrix = mtxsca * mtxrot * mtxloc
+
+ # Return the new matrix.
+ return outputmatrix
+
+
+
+'''
+ This function manipulates the matrix of a target prior to sending it to doConstraint()
+ target_object: wrapped data, representing the target object
+ subtarget_bone: wrapped data, representing the subtarget pose-bone/vertex-group (where applicable)
+ target_matrix: (Matrix) the transformation matrix of the target
+ id_properties_of_constraint: (IDProperties) wrapped idproperties
+'''
+def doTarget(target_object, subtarget_bone, target_matrix, id_properties_of_constraint):
+ return target_matrix
+
+
+'''
+ This function draws a pupblock that lets the user set
+ the values of custom settings the constraint defines.
+ This function is called when the user presses the settings button.
+ idprop: (IDProperties) wrapped data referring to this
+ constraint instance's idproperties
+'''
+def getSettings(idprop):
+ # Define user-settable parameters.
+ # Must also be defined in getSettings().
+ if not idprop.has_key('user_toggle'): idprop['user_toggle'] = 1
+ if not idprop.has_key('user_slider'): idprop['user_slider'] = 1.0
+
+ # create temporary vars for interface
+ utoggle = Draw.Create(idprop['user_toggle'])
+ uslider = Draw.Create(idprop['user_slider'])
+
+
+ # define and draw pupblock
+ block = []
+ block.append("Buttons: ")
+ block.append(("Toggle", utoggle, "This is a toggle button."))
+ block.append("More buttons: ")
+ block.append(("Slider", uslider, 0.0000001, 1000.0, "This is a number field."))
+
+ retval = Draw.PupBlock("Constraint Template", block)
+
+ # update id-property values after user changes settings
+ if (retval):
+ idprop['user_toggle']= utoggle.val
+ idprop['user_slider']= uslider.val
+
+"""
+
+new_text = bpy.data.texts.new('pyconstraint_template.py')
+new_text.write(script_data)
+bpy.data.texts.active = new_text
+Window.RedrawAll()
diff --git a/release/scripts/uv_export.py b/release/scripts/uv_export.py
index f32b5b4fc12..5977a3b76f6 100644
--- a/release/scripts/uv_export.py
+++ b/release/scripts/uv_export.py
@@ -9,7 +9,7 @@ Tooltip: 'Export the UV face layout of the selected object to a .TGA or .SVG fil
__author__ = "Martin 'theeth' Poirier"
__url__ = ("http://www.blender.org", "http://blenderartists.org/")
-__version__ = "2.4"
+__version__ = "2.5"
__bpydoc__ = """\
This script exports the UV face layout of the selected mesh object to
@@ -96,6 +96,11 @@ Notes:<br>See change logs in scripts for a list of contributors.
# Version 2.4
# Port from NMesh to Mesh by Daniel Salazar (zanqdo)
# --------------------------
+# Version 2.5
+# Fixed some old off by one rasterizing errors (didn't render points at 1.0 in the UV scale properly).
+# Fixed wire drawing for non 1 wire size (didn't wrap or stretch properly
+# and would often raise exceptions)
+# --------------------------
FullPython = False
@@ -178,12 +183,16 @@ def ExportCallback(f):
time1= Blender.sys.time()
- if obj.type != "Mesh":
+ if not obj or obj.type != "Mesh":
BPyMessages.Error_NoMeshActive()
return
-
+
+ is_editmode = Blender.Window.EditMode()
+ if is_editmode: Blender.Window.EditMode(0)
+
mesh = obj.getData(mesh=1)
if not mesh.faceUV:
+ if is_editmode: Blender.Window.EditMode(1)
BPyMessages.Error_NoMeshUvActive()
return
@@ -202,6 +211,8 @@ def ExportCallback(f):
UVFaces = ExtractUVFaces(mesh, bAllFaces.val)
+ if is_editmode: Blender.Window.EditMode(1)
+
if not bSVG.val:
print "TGA export is running..."
UV_Export_TGA(UVFaces, bSize.val, bWSize.val, bWrap.val, name)
@@ -322,7 +333,7 @@ def UV_Export_TGA(vList, size, wsize, wrap, file):
step = 0
- img = Buffer(size+1,size+1)
+ img = Buffer(size,size)
if wrap:
wrapSize = size
@@ -333,15 +344,16 @@ def UV_Export_TGA(vList, size, wsize, wrap, file):
for f in vList:
for v in f:
x = int(v[0] * size)
- maxx = max (x, maxx)
- minx = min (x, minx)
+ maxx = max (x + wsize - 1, maxx)
+ minx = min (x - wsize + 1, minx)
y = int(v[1] * size)
- maxy = max (y, maxy)
- miny = min (y, miny)
+ maxy = max (y + wsize - 1, maxy)
+ miny = min (y - wsize + 1, miny)
wrapSize = max (maxx - minx + 1, maxy - miny + 1)
scale = float (size) / float (wrapSize)
+ max_index = size - 1 # max index of the buffer (height or width)
fnum = 0
fcnt = len (vList)
@@ -361,31 +373,31 @@ def UV_Export_TGA(vList, size, wsize, wrap, file):
if step:
try:
for t in xrange(step):
- x = int(floor((co1[0] + t*(co2[0]-co1[0])/step) * size))
- y = int(floor((co1[1] + t*(co2[1]-co1[1])/step) * size))
+ x = int(floor((co1[0] + t*(co2[0]-co1[0])/step) * max_index))
+ y = int(floor((co1[1] + t*(co2[1]-co1[1])/step) * max_index))
- if wrap:
- x = x % wrapSize
- y = y % wrapSize
- else:
- x = int ((x - minx) * scale)
- y = int ((y - miny) * scale)
-
- co = x * 1 + y * 1 * size;
-
- img[co] = 0
- if wsize > 1:
- for x in range(-1*wsize + 1,wsize):
- for y in range(-1*wsize,wsize):
- img[co + 1 * x + y * 1 * size] = 0
+ for dx in range(-1*wsize + 1, wsize):
+ if wrap:
+ wx = (x + dx) % wrapSize
+ else:
+ wx = int ((x - minx + dx) * scale)
+
+ for dy in range(-1*wsize + 1, wsize):
+ if wrap:
+ wy = (y + dy) % wrapSize
+ else:
+ wy = int ((y - miny + dy) * scale)
+
+ co = wx * 1 + wy * 1 * size
+ img[co] = 0
except OverflowError:
if not extreme_warning:
print "Skipping extremely long UV edges, check your layout for excentric values"
extreme_warning = True
for v in f:
- x = int(v[0] * size)
- y = int(v[1] * size)
+ x = int(v[0] * max_index)
+ y = int(v[1] * max_index)
if wrap:
x = x % wrapSize
diff --git a/release/scripts/uv_seams_from_islands.py b/release/scripts/uv_seams_from_islands.py
index dd27aab4ce9..241f38fc4aa 100644
--- a/release/scripts/uv_seams_from_islands.py
+++ b/release/scripts/uv_seams_from_islands.py
@@ -37,7 +37,6 @@ def seams_from_islands(me):
# add seams
SEAM = Mesh.EdgeFlags.SEAM
for ed in me.edges:
- print len(set(edge_uvs[ed.key]))
if len(set(edge_uvs[ed.key])) > 1:
ed.flag |= SEAM
@@ -59,7 +58,7 @@ def main():
# editmode if its enabled, we cant make
# changes to the mesh data while in editmode.
is_editmode = Window.EditMode()
- if is_editmode: Window.EditMode(1)
+ if is_editmode: Window.EditMode(0)
Window.WaitCursor(1)
@@ -68,8 +67,10 @@ def main():
# Run the mesh editing function
seams_from_islands(me)
+ if is_editmode: Window.EditMode(1)
+
# Timing the script is a good way to be aware on any speed hits when scripting
- print 'My Script finished in %.2f seconds' % (sys.time()-t)
+ print 'UV Seams from Islands finished in %.2f seconds' % (sys.time()-t)
Window.WaitCursor(0)
diff --git a/release/scripts/uvcalc_follow_active_coords.py b/release/scripts/uvcalc_follow_active_coords.py
index c97e7168d2f..2a79d0d05df 100644
--- a/release/scripts/uvcalc_follow_active_coords.py
+++ b/release/scripts/uvcalc_follow_active_coords.py
@@ -51,6 +51,11 @@ def extend():
Draw.PupMenu('ERROR: No mesh object.')
return
+ # Toggle Edit mode
+ is_editmode = Window.EditMode()
+ if is_editmode:
+ Window.EditMode(0)
+
me = ob.getData(mesh=1)
me_verts = me.verts
@@ -233,7 +238,12 @@ def extend():
face_modes[i] = 2 # dont search again
print sys.time() - t
- me.update()
+
+ if is_editmode:
+ Window.EditMode(1)
+ else:
+ me.update()
+
Window.RedrawAll()
Window.WaitCursor(0)
diff --git a/release/scripts/uvcalc_from_adjacent.py b/release/scripts/uvcalc_from_adjacent.py
deleted file mode 100644
index 32bbd9e08e6..00000000000
--- a/release/scripts/uvcalc_from_adjacent.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#!BPY
-"""
-Name: 'UVs from unselected adjacent'
-Blender: 242
-Group: 'UVCalculation'
-Tooltip: 'Assign UVs to selected faces from surrounding unselected faces.'
-"""
-__author__ = "Campbell Barton"
-__url__ = ("blender", "elysiun")
-__version__ = "1.0 2006/02/07"
-
-__bpydoc__ = """\
-This script sets the UV mapping and image of selected faces from adjacent unselected faces.
-
-Use this script in face select mode for texturing between textured faces.
-"""
-
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# Script copyright (C) Campbell J Barton
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# ***** END GPL LICENCE BLOCK *****
-# --------------------------------------------------------------------------
-
-
-from Blender import *
-import bpy
-
-def mostUsedImage(imageList): # Returns the image most used in the list.
- if not imageList:
- return None
- elif len(imageList) < 3:
- return imageList[0]
-
- # 3+ Images, Get the most used image for surrounding faces.
- imageCount = {}
- for image in imageList:
- if image:
- image_key= image.name
- else:
- image_key = None
-
- try:
- imageCount[image_key]['imageCount'] +=1 # an extra user of this image
- except:
- imageCount[image_key] = {'imageCount':1, 'blenderImage':image} # start with 1 user.
-
- # Now a list of tuples, (imageName, {imageCount, image})
- imageCount = imageCount.items()
-
- try: imageCount.sort(key=lambda a: a[1])
- except: imageCount.sort(lambda a,b: cmp(a[1], b[1]))
-
-
- return imageCount[-1][1]['blenderImage']
-
-
-def main():
- scn = bpy.data.scenes.active
- ob = scn.objects.active
- if ob == None or ob.type != 'Mesh':
- Draw.PupMenu('ERROR: No mesh object in face select mode.')
- return
- me = ob.getData(mesh=1)
-
- if not me.faceUV:
- Draw.PupMenu('ERROR: No mesh object in face select mode.')
- return
-
- selfaces = [f for f in me.faces if f.sel]
- unselfaces = [f for f in me.faces if not f.sel if not f.hide]
-
- # Gather per Vert UV and Image, store in vertUvAverage
- vertUvAverage = [[[],[]] for i in xrange(len(me.verts))]
-
- for f in unselfaces: # Unselected faces only.
- fuv = f.uv
- for i,v in enumerate(f):
- vertUvAverage[v.index][0].append(fuv[i])
- vertUvAverage[v.index][1].append(f.image)
-
- # Average per vectex UV coords
- for vertUvData in vertUvAverage:
- uvList = vertUvData[0]
- if uvList:
- # Convert from a list of vectors into 1 vector.
- vertUvData[0] = reduce(lambda a,b: a+b, uvList, Mathutils.Vector(0,0)) * (1.0/len(uvList))
- else:
- vertUvData[0] = None
-
-
-
- # Assign to selected faces
- TEX_FLAG = Mesh.FaceModes['TEX']
- for f in selfaces:
- uvlist = []
- imageList = []
- for i,v in enumerate(f):
- uv, vImages = vertUvAverage[v.index]
- uvlist.append( uv )
- imageList.extend(vImages)
-
- if None not in uvlist:
- # all the faces images used by this faces vert. some faces will be added twice but thats ok.
- # Get the most used image and assign to the face.
- image = mostUsedImage(imageList)
- f.uv = uvlist
-
- if image:
- f.image = image
- f.mode |= TEX_FLAG
- Window.RedrawAll()
-
-if __name__ == '__main__':
- main() \ No newline at end of file
diff --git a/release/scripts/uvcalc_lightmap.py b/release/scripts/uvcalc_lightmap.py
index a4269149203..af9acb09e17 100644
--- a/release/scripts/uvcalc_lightmap.py
+++ b/release/scripts/uvcalc_lightmap.py
@@ -221,7 +221,11 @@ PREF_MARGIN_DIV= 512):
else:
face_groups = []
- for me in meshes:
+ for me in meshes:
+ # Add face UV if it does not exist.
+ # All new faces are selected.
+ me.faceUV = True
+
if PREF_SEL_ONLY:
faces = [f for f in me.faces if f.sel]
else:
@@ -540,6 +544,12 @@ def main():
Draw.PupMenu('Error%t|No mesh objects selected.')
return
+ # Toggle Edit mode
+ is_editmode = Window.EditMode()
+ if is_editmode:
+ Window.EditMode(0)
+
+
Window.WaitCursor(1)
lightmap_uvpack(meshes,\
PREF_SEL_ONLY.val,\
@@ -550,6 +560,9 @@ def main():
PREF_BOX_DIV.val,\
int(1/(PREF_MARGIN_DIV.val/100)))
+ if is_editmode:
+ Window.EditMode(1)
+
Window.WaitCursor(0)
if __name__ == '__main__':
diff --git a/release/scripts/uvcalc_quad_clickproj.py b/release/scripts/uvcalc_quad_clickproj.py
index 67b58885f9d..791fd661cc9 100644
--- a/release/scripts/uvcalc_quad_clickproj.py
+++ b/release/scripts/uvcalc_quad_clickproj.py
@@ -80,6 +80,10 @@ def main():
if not ob or ob.type!='Mesh':
return
+ is_editmode = Window.EditMode()
+ if is_editmode:
+ Window.EditMode(0)
+
mousedown_wait() # so the menu items clicking dosnt trigger the mouseclick
Window.DrawProgressBar (0.0, '')
@@ -100,10 +104,8 @@ def main():
mouse_buttons = Window.GetMouseButtons()
-
Window.DrawProgressBar (0.2, '(2 of 3 ) Click confirms the U coords')
-
mousedown_wait()
obmat= ob.matrixWorld
@@ -112,7 +114,7 @@ def main():
if not mouseInView or not OriginA:
return
-
+
me = ob.getData(mesh=1)
# Get the face under the mouse
@@ -255,6 +257,9 @@ def main():
Window.Redraw(Window.Types.VIEW3D)
Window.SetCursorPos(*orig_cursor)
+ if is_editmode:
+ Window.EditMode(1)
+
Window.RedrawAll()
if __name__=='__main__':
diff --git a/release/scripts/uvcalc_smart_project.py b/release/scripts/uvcalc_smart_project.py
index b10b69285e0..49d52d12d47 100644
--- a/release/scripts/uvcalc_smart_project.py
+++ b/release/scripts/uvcalc_smart_project.py
@@ -1121,6 +1121,9 @@ def main():
print "Smart Projection time: %.2f" % (sys.time() - time1)
# Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec." % (sys.time() - time1))
+ if is_editmode:
+ Window.EditMode(1)
+
Window.DrawProgressBar(1.0, "")
Window.WaitCursor(0)
Window.RedrawAll()
diff --git a/release/scripts/vertexpaint_selfshadow_ao.py b/release/scripts/vertexpaint_selfshadow_ao.py
index c083bc9e8b0..7a6f4f9176d 100644
--- a/release/scripts/vertexpaint_selfshadow_ao.py
+++ b/release/scripts/vertexpaint_selfshadow_ao.py
@@ -39,6 +39,7 @@ and optionaly blur the shading to remove artifacts from spesific edges.
# --------------------------------------------------------------------------
from Blender import Scene, Draw, sys, Window, Mathutils, Mesh
+import bpy
import BPyMesh
@@ -135,10 +136,10 @@ def vertexFakeAO(me, PREF_BLUR_ITERATIONS, PREF_BLUR_RADIUS, PREF_MIN_EDLEN, PRE
Window.WaitCursor(0)
def main():
- scn= Scene.GetCurrent()
- ob= scn.getActiveObject()
+ sce= bpy.data.scenes.active
+ ob= sce.objects.active
- if not ob or ob.getType() != 'Mesh':
+ if not ob or ob.type != 'Mesh':
Draw.PupMenu('Error, no active mesh object, aborting.')
return
@@ -174,8 +175,8 @@ def main():
PREF_SHADOW_ONLY= PREF_SHADOW_ONLY.val
PREF_SEL_ONLY= PREF_SEL_ONLY.val
- if not me.faceUV:
- me.faceUV= 1
+ if not me.vertexColors:
+ me.vertexColors= 1
t= sys.time()
vertexFakeAO(me, PREF_BLUR_ITERATIONS, PREF_BLUR_RADIUS, PREF_MIN_EDLEN, PREF_CLAMP_CONCAVE, PREF_CLAMP_CONVEX, PREF_SHADOW_ONLY, PREF_SEL_ONLY)
diff --git a/release/scripts/vrml97_export.py b/release/scripts/vrml97_export.py
index b5afacbe272..57ffd243bfc 100644
--- a/release/scripts/vrml97_export.py
+++ b/release/scripts/vrml97_export.py
@@ -656,10 +656,10 @@ class VRML2Export:
self.writeMaterial(mater, self.cleanStr(mater.name,''))
if (mater.mode & Blender.Material.Modes['TEXFACE']):
if image != None:
- self.writeImageTexture(image.name)
+ self.writeImageTexture(image.name, image.filename)
else:
if image != None:
- self.writeImageTexture(image.name)
+ self.writeImageTexture(image.name, image.filename)
self.writeIndented("}\n", -1)
@@ -837,7 +837,7 @@ class VRML2Export:
self.writeIndented("transparency %s\n" % (round(transp,self.cp)))
self.writeIndented("}\n",-1)
- def writeImageTexture(self, name):
+ def writeImageTexture(self, name, filename):
if self.texNames.has_key(name):
self.writeIndented("texture USE %s\n" % self.cleanStr(name))
self.texNames[name] += 1
@@ -846,7 +846,7 @@ class VRML2Export:
self.writeIndented("texture DEF %s ImageTexture {\n" % \
self.cleanStr(name), 1)
self.writeIndented('url "%s"\n' % \
- name.split("\\")[-1].split("/")[-1])
+ filename.split("\\")[-1].split("/")[-1])
self.writeIndented("}\n",-1)
self.texNames[name] = 1
diff --git a/release/scripts/weightpaint_average.py b/release/scripts/weightpaint_average.py
new file mode 100644
index 00000000000..4e8830256b2
--- /dev/null
+++ b/release/scripts/weightpaint_average.py
@@ -0,0 +1,121 @@
+#!BPY
+"""
+Name: 'Vertex Groups Island Average'
+Blender: 243
+Group: 'WeightPaint'
+Tooltip: 'Average the vertex weights for each connected set of verts'
+"""
+
+# --------------------------------------------------------------------------
+# ***** 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 Scene, Mesh, Window, sys, Draw
+from BPyMesh import meshWeight2List, list2MeshWeight, mesh2linkedFaces
+
+import BPyMessages
+import bpy
+
+def faceGroups2VertSets(face_groups):
+ ''' Return the face groups as sets of vert indicies '''
+ return [set([v.index for f in fg for v in f]) for fg in face_groups]
+
+
+def vgroup_average(ob_orig, me, sce, PREF_ALL_VGROUPS=True):
+ if not me.getVertGroupNames():
+ return
+
+ weight_names, weight_list = meshWeight2List(me)
+
+ weight_names_len = len(weight_names)
+ vgroup_dummy = [0.0] * weight_names_len
+ vgroup_range = range(weight_names_len)
+
+ if not PREF_ALL_VGROUPS:
+ weight_active_index = weight_names.index(me.activeGroup)
+
+ for vert_set in faceGroups2VertSets( mesh2linkedFaces(me) ):
+ if not vert_set:
+ continue
+
+
+ if PREF_ALL_VGROUPS:
+ # We need to average the vgroups
+ collected_group = vgroup_dummy[:]
+ for i in vert_set:
+ vert_group = weight_list[i] # get the original weight
+ weight_list[i] = collected_group # replace with the collected group
+
+ for j in vgroup_range: # iter through the vgroups
+ collected_group[j] += vert_group[j]
+
+ for j in vgroup_range:
+ collected_group[j] /= len(vert_set)
+ else:
+ # Active group only
+ vert_weight = 0.0
+ for i in vert_set:
+ vert_weight += weight_list[i][weight_active_index]
+
+ vert_weight /= len(vert_set)
+
+ for i in vert_set:
+ weight_list[i][weight_active_index] = vert_weight
+
+ list2MeshWeight(me, weight_names, weight_list)
+
+def main():
+
+ # Gets the current scene, there can be many scenes in 1 blend file.
+ sce = bpy.data.scenes.active
+
+ # Get the active object, there can only ever be 1
+ # and the active object is always the editmode object.
+ ob_act = sce.objects.active
+
+ if not ob_act or ob_act.type != 'Mesh':
+ BPyMessages.Error_NoMeshActive()
+ return
+
+ # Saves the editmode state and go's out of
+ # editmode if its enabled, we cant make
+ # changes to the mesh data while in editmode.
+ is_editmode = Window.EditMode()
+ Window.EditMode(0)
+
+ PREF_ALL_VGROUPS = Draw.PupMenu("All Groups?%t|All Groups%x1|Active Group Only%x0")
+ if PREF_ALL_VGROUPS==-1:
+ return
+
+ Window.WaitCursor(1)
+ me = ob_act.getData(mesh=1) # old NMesh api is default
+ t = sys.time()
+
+ # Run the mesh editing function
+ vgroup_average(ob_act, me, sce, PREF_ALL_VGROUPS)
+
+ # Timing the script is a good way to be aware on any speed hits when scripting
+ print 'Average VGroups in %.2f seconds' % (sys.time()-t)
+ Window.WaitCursor(0)
+ if is_editmode: Window.EditMode(1)
+
+
+# This lets you can import the script without running it
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/release/scripts/weightpaint_invert.py b/release/scripts/weightpaint_invert.py
new file mode 100644
index 00000000000..cdae83a9d50
--- /dev/null
+++ b/release/scripts/weightpaint_invert.py
@@ -0,0 +1,95 @@
+#!BPY
+"""
+Name: 'Invert Active Group'
+Blender: 245
+Group: 'WeightPaint'
+Tooltip: 'Invert the active vertex group'
+"""
+
+# --------------------------------------------------------------------------
+# ***** 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 Scene, Mesh, Window, sys
+
+import BPyMessages
+import bpy
+
+def vgroup_invert(ob_orig, me):
+ if not me.getVertGroupNames():
+ return
+ group_act = me.activeGroup
+ if group_act == None:
+ return
+
+ group_data = me.getVertsFromGroup(group_act, 1)
+
+ weights= [1.0] * len(me.verts) # 1.0 - initialize inverted
+
+ group_data = me.getVertsFromGroup(group_act, 1) # (i,w) tuples.
+
+ me.removeVertGroup(group_act) # messes up the active group.
+ for i,w in group_data:
+ weights[i] = 1.0-w
+
+ me.addVertGroup(group_act)
+
+ rep = Blender.Mesh.AssignModes.REPLACE
+ vertList= [None]
+ for i,weight in enumerate(weights):
+ vertList[0] = i
+ me.assignVertsToGroup(group_act, vertList, weight, rep)
+
+ me.activeGroup = group_act
+ me.update()
+
+def main():
+
+ # Gets the current scene, there can be many scenes in 1 blend file.
+ sce = bpy.data.scenes.active
+
+ # Get the active object, there can only ever be 1
+ # and the active object is always the editmode object.
+ ob_act = sce.objects.active
+
+ if not ob_act or ob_act.type != 'Mesh':
+ BPyMessages.Error_NoMeshActive()
+ return
+
+ # Saves the editmode state and go's out of
+ # editmode if its enabled, we cant make
+ # changes to the mesh data while in editmode.
+ is_editmode = Window.EditMode()
+ Window.EditMode(0)
+
+ Window.WaitCursor(1)
+ me = ob_act.getData(mesh=1) # old NMesh api is default
+ t = sys.time()
+
+ # Run the mesh editing function
+ vgroup_invert(ob_act, me)
+
+ # Timing the script is a good way to be aware on any speed hits when scripting
+ print 'Invert VGroup in %.2f seconds' % (sys.time()-t)
+ Window.WaitCursor(0)
+ if is_editmode: Window.EditMode(1)
+
+# This lets you can import the script without running it
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/release/scripts/weightpaint_normalize.py b/release/scripts/weightpaint_normalize.py
index 204868a79fc..1f6c3d201aa 100644
--- a/release/scripts/weightpaint_normalize.py
+++ b/release/scripts/weightpaint_normalize.py
@@ -40,54 +40,100 @@ proportion of the veighting is unchanged.
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
-from Blender import Scene, Draw
+from Blender import Scene, Draw, Object, Modifier
import BPyMesh
SMALL_NUM= 0.000001
-def actWeightNormalize(me, PREF_PEAKWEIGHT, PREF_KEEP_PROPORTION):
+
+def getArmatureGroups(ob, me):
+
+ arm_obs = []
+
+ arm = ob.parent
+ if arm and arm.type == 'Armature' and ob.parentType == Object.ParentTypes.ARMATURE:
+ arm_obs.append(arm)
+
+ for m in ob.modifiers:
+ if m.type== Modifier.Types.ARMATURE:
+ arm = m[Modifier.Settings.OBJECT]
+ if arm:
+ arm_obs.append(arm)
+
+ # convert to a dict and back, should be a set! :/ - python 2.3 dosnt like.
+ return dict([ (bonename, None) for arm in arm_obs for bonename in arm.data.bones.keys() ]).keys()
+
+
+
+def actWeightNormalize(me, ob, PREF_PEAKWEIGHT, PREF_ACTIVE_ONLY, PREF_ARMATURE_ONLY, PREF_KEEP_PROPORTION):
groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
new_weight= max_weight= -1.0
act_group= me.activeGroup
- vWeightDictUsed=[False] * len(vWeightDict)
-
- for i, wd in enumerate(vWeightDict):
- try:
- new_weight= wd[act_group]
- if new_weight > max_weight:
- max_weight= new_weight
- vWeightDictUsed[i]=wd
- except:
- pass
-
- if max_weight < SMALL_NUM or new_weight == -1:
- Draw.PupMenu('No verts to normalize. exiting.')
- return
+ if PREF_ACTIVE_ONLY:
+ normalizeGroups = [act_group]
+ else:
+ normalizeGroups = groupNames[:]
- if abs(max_weight-PREF_PEAKWEIGHT) < SMALL_NUM:
- Draw.PupMenu('Vert Weights are alredy normalized.')
- return
+ if PREF_ARMATURE_ONLY:
+
+ armature_groups = getArmatureGroups(ob, me)
+
+ i = len(normalizeGroups)
+ while i:
+ i-=1
+ if not normalizeGroups[i] in armature_groups:
+ del normalizeGroups[i]
- max_weight= max_weight/PREF_PEAKWEIGHT
- if PREF_KEEP_PROPORTION:
- # TODO, PROPORTIONAL WEIGHT SCALING.
- for wd in vWeightDictUsed:
- if wd: # not false.
- if len(wd) == 1:
- # Only 1 group for thsi vert. Simple
- wd[act_group] /= max_weight
- else:
- # More then 1 group. will need to scale all users evenly.
- local_maxweight= max(wd.itervalues()) / PREF_PEAKWEIGHT
- for weight in wd.iterkeys():
- wd[weight] /= local_maxweight
-
+ for act_group in normalizeGroups:
+ vWeightDictUsed=[False] * len(vWeightDict)
+
+ for i, wd in enumerate(vWeightDict):
+ try:
+ new_weight= wd[act_group]
+ if new_weight > max_weight:
+ max_weight= new_weight
+ vWeightDictUsed[i]=wd
+ except:
+ pass
- else: # Simple, just scale the weights up.
- for wd in vWeightDictUsed:
- if wd: # not false.
- wd[act_group] /= max_weight
+ # These can be skipped for now, they complicate things when using multiple vgroups,
+ '''
+ if max_weight < SMALL_NUM or new_weight == -1:
+ Draw.PupMenu('No verts to normalize. exiting.')
+ #return
+
+ if abs(max_weight-PREF_PEAKWEIGHT) < SMALL_NUM:
+ Draw.PupMenu('Vert Weights are alredy normalized.')
+ #return
+ '''
+ max_weight= max_weight/PREF_PEAKWEIGHT
+
+ if PREF_KEEP_PROPORTION:
+ # TODO, PROPORTIONAL WEIGHT SCALING.
+ for wd in vWeightDictUsed:
+ if wd: # not false.
+ if len(wd) == 1:
+ # Only 1 group for thsi vert. Simple
+ wd[act_group] /= max_weight
+ else:
+ # More then 1 group. will need to scale all users evenly.
+ if PREF_ARMATURE_ONLY:
+ local_maxweight= max([v for k, v in wd.iteritems() if k in armature_groups]) / PREF_PEAKWEIGHT
+ if local_maxweight > 0.0:
+ # So groups that are not used in any bones are ignored.
+ for weight in wd.iterkeys():
+ if weight in armature_groups:
+ wd[weight] /= local_maxweight
+ else:
+ local_maxweight= max(wd.itervalues()) / PREF_PEAKWEIGHT
+ for weight in wd.iterkeys():
+ wd[weight] /= local_maxweight
+
+ else: # Simple, just scale the weights up. we alredy know this is in an armature group (if needed)
+ for wd in vWeightDictUsed:
+ if wd: # not false.
+ wd[act_group] /= max_weight
# Copy weights back to the mesh.
BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
@@ -104,17 +150,21 @@ def main():
me= ob.getData(mesh=1)
PREF_PEAKWEIGHT= Draw.Create(1.0)
+ PREF_ACTIVE_ONLY= Draw.Create(1)
PREF_KEEP_PROPORTION= Draw.Create(1)
+ PREF_ARMATURE_ONLY= Draw.Create(0)
pup_block= [\
('Peak Weight:', PREF_PEAKWEIGHT, 0.01, 1.0, 'Upper weight for normalizing.'),\
+ ('Active Only', PREF_ACTIVE_ONLY, 'Only Normalize groups that have matching bones in an armature (when an armature is used).'),\
('Proportional', PREF_KEEP_PROPORTION, 'Scale other weights so verts (Keep weights with other groups in proportion).'),\
+ ('Armature Only', PREF_ARMATURE_ONLY, 'Only Normalize groups that have matching bones in an armature (when an armature is used).'),\
]
if not Draw.PupBlock('Clean Selected Meshes...', pup_block):
return
- actWeightNormalize(me, PREF_PEAKWEIGHT.val, PREF_KEEP_PROPORTION.val)
+ actWeightNormalize(me, ob, PREF_PEAKWEIGHT.val, PREF_ACTIVE_ONLY.val, PREF_ARMATURE_ONLY.val, PREF_KEEP_PROPORTION.val)
if __name__=='__main__':
main() \ No newline at end of file
diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py
new file mode 100644
index 00000000000..f11d797636f
--- /dev/null
+++ b/release/scripts/wizard_curve2tree.py
@@ -0,0 +1,4007 @@
+#!BPY
+"""
+Name: 'Tree from Curves'
+Blender: 245
+Group: 'Wizards'
+Tip: 'Generate trees from curve shapes'
+"""
+
+__author__ = "Campbell Barton"
+__url__ = ['www.blender.org', 'blenderartists.org']
+__version__ = "0.1"
+
+__bpydoc__ = """\
+
+"""
+
+# --------------------------------------------------------------------------
+# Tree from Curves v0.1 by Campbell Barton (AKA Ideasman42)
+# --------------------------------------------------------------------------
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+# --------------------------------------------------------------------------
+
+import bpy
+import Blender
+import BPyMesh
+from Blender.Mathutils import Vector, Matrix, CrossVecs, AngleBetweenVecs, LineIntersect, TranslationMatrix, ScaleMatrix, RotationMatrix, Rand
+from Blender.Geometry import ClosestPointOnLine
+from Blender.Noise import randuvec
+
+GLOBALS = {}
+GLOBALS['non_bez_error'] = 0
+
+def AngleBetweenVecsSafe(a1, a2):
+ try:
+ return AngleBetweenVecs(a1,a2)
+ except:
+ return 180.0
+
+# Copied from blender, we could wrap this! - BKE_curve.c
+# But probably not toooo bad in python
+def forward_diff_bezier(q0, q1, q2, q3, pointlist, steps, axis):
+ f= float(steps)
+ rt0= q0
+ rt1= 3.0*(q1-q0)/f
+ f*= f
+ rt2= 3.0*(q0-2.0*q1+q2)/f
+ f*= steps
+ rt3= (q3-q0+3.0*(q1-q2))/f
+
+ q0= rt0
+ q1= rt1+rt2+rt3
+ q2= 2*rt2+6*rt3
+ q3= 6*rt3
+ if axis == None:
+ for a in xrange(steps+1):
+ pointlist[a] = q0
+ q0+= q1
+ q1+= q2
+ q2+= q3;
+
+ else:
+ for a in xrange(steps+1):
+ pointlist[a][axis] = q0
+ q0+= q1
+ q1+= q2
+ q2+= q3;
+
+def points_from_bezier_seg(steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2):
+
+ # x,y,z,axis
+ for ii in (0,1,2):
+ forward_diff_bezier(bez1_vec[1][ii], bez1_vec[2][ii], bez2_vec[0][ii], bez2_vec[1][ii], pointlist, steps, ii)
+
+ # radius - no axis, Copied from blenders BBone roll interpolation.
+ forward_diff_bezier(radius1, radius1 + 0.390464*(radius2-radius1), radius2 - 0.390464*(radius2-radius1), radius2, radlist, steps, None)
+
+
+def debug_pt(co):
+ Blender.Window.SetCursorPos(tuple(co))
+ Blender.Window.RedrawAll()
+ print 'debugging', co
+
+def freshMesh(mesh):
+ '''
+ Utility function to get a new mesh or clear the existing one, but dont clear everything.
+ '''
+ if mesh:
+ materials = mesh.materials
+ mesh.verts = None
+ for group in mesh.getVertGroupNames():
+ mesh.removeVertGroup(group)
+
+ # Add materials back
+ mesh.materials = materials
+ else:
+ mesh = bpy.data.meshes.new()
+
+ return mesh
+
+def getObFromName(name):
+ if name:
+ try: return bpy.data.objects[name]
+ except: return None
+ else:
+ return None
+
+def getGroupFromName(name):
+ if name:
+ try: return bpy.data.groups[name]
+ except: return None
+ else:
+ return None
+
+def closestVecIndex(vec, vecls):
+ best= -1
+ best_dist = 100000000
+ for i, vec_test in enumerate(vecls):
+ # Dont use yet, we may want to tho
+ if vec_test: # Seems odd, but use this so we can disable some verts in the list.
+ dist = (vec-vec_test).length
+ if dist < best_dist:
+ best = i
+ best_dist = dist
+
+ return best
+
+IRATIONAL_NUM = 22.0/7.0
+def next_random_num(rnd):
+ '''
+ return a random number between 0.0 and 1.0
+ '''
+ rnd[0] += (rnd[0] * IRATIONAL_NUM) % 1
+ # prevent
+ if rnd[0] > 1000000:
+ rnd[0]-=1000000
+ return rnd[0] % 1
+
+eul = 0.00001
+
+BRANCH_TYPE_CURVE = 0
+BRANCH_TYPE_GROWN = 1
+BRANCH_TYPE_FILL = 2
+
+class tree:
+ def __init__(self):
+ self.branches_all = []
+ self.branches_root = []
+ self.branches_twigs = []
+ self.mesh = None
+ self.armature = None
+ self.objectCurve = None
+ self.objectCurveMat = None
+ self.objectCurveIMat = None
+
+ self.objectTwigBounds = None # use for twigs only at the moment.
+ self.objectTwigBoundsIMat = None
+ self.objectTwigBoundsMat = None
+ self.objectTwigBoundsMesh = None
+
+ self.objectLeafBounds = None
+ self.objectLeafBoundsIMat = None
+ self.objectLeafBoundsMesh = None
+
+ self.limbScale = 1.0
+
+ self.debug_objects = []
+ self.steps = 6 # defalt, curve overwrites
+
+ def __repr__(self):
+ s = ''
+ s += '[Tree]'
+ s += ' limbScale: %.6f' % self.limbScale
+ s += ' object: %s' % self.objectCurve
+
+ for brch in self.branches_root:
+ s += str(brch)
+ return s
+
+ def fromCurve(self, objectCurve):
+ # Now calculate the normals
+ self.objectCurve = objectCurve
+ self.objectCurveMat = objectCurve.matrixWorld
+ self.objectCurveIMat = self.objectCurveMat.copy().invert()
+ curve = objectCurve.data
+ self.steps = curve.resolu # curve resolution
+
+ # Set the curve object scale
+ if curve.bevob:
+ # A bit of a hack to guess the size of the curve object if you have one.
+ bb = curve.bevob.boundingBox
+ # self.limbScale = (bb[0] - bb[7]).length / 2.825 # THIS IS GOOD WHEN NON SUBSURRFED
+ self.limbScale = (bb[0] - bb[7]).length / 1.8
+ elif curve.ext2 != 0.0:
+ self.limbScale = curve.ext2 * 1.5
+
+ # forward_diff_bezier will fill in the blanks
+ # nice we can reuse these for every curve segment :)
+ pointlist = [[None, None, None] for i in xrange(self.steps+1)]
+ radlist = [ None for i in xrange(self.steps+1) ]
+
+ for spline in curve:
+
+ if len(spline) < 2: # Ignore single point splines
+ continue
+
+ if spline.type != 1: # 0 poly, 1 bez, 4 nurbs
+ GLOBALS['non_bez_error'] = 1
+ continue
+
+
+ brch = branch()
+ brch.type = BRANCH_TYPE_CURVE
+
+
+
+ bez_list = list(spline)
+ for i in xrange(1, len(bez_list)):
+ bez1 = bez_list[i-1]
+ bez2 = bez_list[i]
+ vec1 = bez1.vec
+ vec2 = bez2.vec
+ if abs(vec1[1][0]-vec2[1][0]) > 0.000001 or\
+ abs(vec1[1][1]-vec2[1][1]) > 0.000001 or\
+ abs(vec1[1][2]-vec2[1][2]) > 0.000001:
+
+ points_from_bezier_seg(self.steps, pointlist, radlist, vec1, vec2, bez1.radius, bez2.radius)
+
+ # remove endpoint for all but the last
+ len_pointlist = len(pointlist)
+ if i != len(bez_list)-1:
+ len_pointlist -= 1
+
+ brch.bpoints.extend([ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii] * self.limbScale) for ii in xrange(len_pointlist) ])
+
+ # Finalize once point data is there
+ if brch.bpoints:
+ # if all points are in the same location, this is possible
+ self.branches_all.append(brch)
+ if brch.bpoints[0].radius < brch.bpoints[-1].radius: # This means we dont have to worry about curve direction.
+ brch.bpoints.reverse()
+ brch.calcData()
+
+ # Sort from big to small, so big branches get priority
+ self.branches_all.sort( key = lambda brch: -brch.bpoints[0].radius )
+
+
+ def closestBranchPt(self, co):
+ best_brch = None
+ best_pt = None
+ best_dist = 10000000000
+ for brch in self.branches_all:
+ for pt in brch.bpoints:
+ # if pt.inTwigBounds: # only find twigs, give different results for leaves
+ l = (pt.co-co).length
+ if l < best_dist:
+ best_dist = l
+ best_brch = brch
+ best_pt = pt
+ return best_brch, best_pt
+
+ def setTwigBounds(self, objectMesh):
+ self.objectTwigBounds = objectMesh
+ self.objectTwigBoundsMesh = objectMesh.getData(mesh=1)
+ self.objectTwigBoundsMat = objectMesh.matrixWorld.copy()
+ self.objectTwigBoundsIMat = self.objectTwigBoundsMat.copy().invert()
+
+ for brch in self.branches_all:
+ brch.calcTwigBounds(self)
+
+ def setLeafBounds(self, objectMesh):
+ self.objectLeafBounds = objectMesh
+ self.objectLeafBoundsMesh = objectMesh.getData(mesh=1)
+ self.objectLeafBoundsIMat = objectMesh.matrixWorld.copy().invert()
+
+ def isPointInTwigBounds(self, co, selected_only=False):
+ return self.objectTwigBoundsMesh.pointInside(co * self.objectCurveMat * self.objectTwigBoundsIMat, selected_only)
+
+ def isPointInLeafBounds(self, co, selected_only=False):
+ return self.objectLeafBoundsMesh.pointInside(co * self.objectCurveMat * self.objectLeafBoundsIMat, selected_only)
+
+ def resetTags(self, value):
+ for brch in self.branches_all:
+ brch.tag = value
+
+ def buildConnections( self,\
+ sloppy = 1.0,\
+ connect_base_trim = 1.0,\
+ do_twigs = False,\
+ twig_ratio = 2.0,\
+ twig_select_mode = 0,\
+ twig_select_factor = 0.5,\
+ twig_scale = 0.8,\
+ twig_scale_width = 1.0,\
+ twig_random_orientation = 180,\
+ twig_random_angle = 33,\
+ twig_recursive=True,\
+ twig_recursive_limit=3,\
+ twig_ob_bounds=None,\
+ twig_ob_bounds_prune=True,\
+ twig_ob_bounds_prune_taper=1.0,\
+ twig_placement_maxradius=10.0,\
+ twig_placement_maxtwig=0,\
+ twig_follow_parent=0.0,\
+ twig_follow_x=0.0,\
+ twig_follow_y=0.0,\
+ twig_follow_z=0.0,\
+ do_variation = 0,\
+ variation_seed = 1,\
+ variation_orientation = 0.0,\
+ variation_scale = 0.0,\
+ do_twigs_fill = 0,\
+ twig_fill_levels=4,\
+ twig_fill_rand_scale=0.0,\
+ twig_fill_fork_angle_max=180.0,\
+ twig_fill_radius_min=0.1,\
+ twig_fill_radius_factor=0.75,\
+ twig_fill_shape_type=0,\
+ twig_fill_shape_rand=0.0,\
+ twig_fill_shape_power=0.3,\
+ ):
+ '''
+ build tree data - fromCurve must run first
+ '''
+
+
+ # Sort the branchs by the first radius, so big branchs get joins first
+ ### self.branches_all.sort( key = lambda brch: brch.bpoints[0].radius )
+
+ #self.branches_all.reverse()
+
+ # Connect branches
+ for i in xrange(len(self.branches_all)):
+ brch_i = self.branches_all[i]
+
+ for j in xrange(len(self.branches_all)):
+ if i != j:
+ # See if any of the points match this branch
+ # see if Branch 'i' is the child of branch 'j'
+
+ brch_j = self.branches_all[j]
+
+ if not brch_j.inParentChain(brch_i): # So we dont make cyclic tree!
+
+ pt_best_j, dist = brch_j.findClosest(brch_i.bpoints[0].co)
+
+ # Check its in range, allow for a bit out - hense the sloppy
+ if dist < pt_best_j.radius * sloppy:
+ brch_i.parent_pt = pt_best_j
+ pt_best_j.childCount += 1 # dont remove me
+
+ brch_i.baseTrim(connect_base_trim)
+
+ '''
+ if pt_best_j.childCount>4:
+ raise "ERROR"
+ '''
+
+ # addas a member of best_j.children later when we have the geometry info available.
+
+ #### print "Found Connection!!!", i, j
+ break # go onto the next branch
+
+ """
+ children = [brch_child for brch_child in pt.children]
+ if children:
+ # This pt is one side of the segment, pt.next joins this segment.
+ # calculate the median point the 2 segments would spanal
+ # Once this is done we need to adjust 2 things
+ # 1) move both segments up/down so they match the branches best.
+ # 2) set the spacing of the segments around the point.
+
+
+ # First try to get the ideal some space around each joint
+ # the spacing shoule be an average of
+ for brch.bpoints:
+ """
+
+ '''
+ for brch in self.branches_all:
+ brch.checkPointList()
+ '''
+
+ # Variations - use for making multiple versions of the same tree.
+ if do_variation:
+ irational_num = 22.0/7.0 # use to make the random number more odd
+ rnd = [variation_seed]
+
+ # Add children temporarily
+ for brch in self.branches_all:
+ if brch.parent_pt:
+ rnd_rot = ((next_random_num(rnd) * variation_orientation) - 0.5) * 720
+ mat_orientation = RotationMatrix(rnd_rot, 3, 'r', brch.parent_pt.no)
+ rnd_sca = 1 + ((next_random_num(rnd)-0.5)* variation_scale )
+ mat_scale = Matrix([rnd_sca,0,0],[0,rnd_sca,0],[0,0,rnd_sca])
+ # mat_orientation = RotationMatrix(0, 3, 'r', brch.parent_pt.no)
+ brch.transformRecursive(self, mat_scale * mat_orientation, brch.parent_pt.co)
+
+ if (do_twigs or do_twigs_fill) and twig_ob_bounds: # Only spawn twigs inside this mesh
+ self.setTwigBounds(twig_ob_bounds)
+
+ # Important we so this with existing parent/child but before connecting and calculating verts.
+ if do_twigs:
+
+ # scale values down
+ twig_random_orientation= twig_random_orientation/360.0
+ twig_random_angle= twig_random_angle/360.0
+
+ irational_num = 22.0/7.0 # use to make the random number more odd
+
+ if not twig_recursive:
+ twig_recursive_limit = 0
+
+ self.buildTwigs(twig_ratio, twig_select_mode, twig_select_factor)
+
+ branches_twig_attached = []
+
+ # This wont add all! :/
+ brch_twig_index = 0
+ brch_twig_index_LAST = -1 # use this to prevent in inf loop, since its possible we cant place every branch
+ while brch_twig_index < len(self.branches_twigs) and brch_twig_index_LAST != brch_twig_index:
+ ###print "While"
+ ### print brch_twig_index, len(self.branches_twigs) # if this dosnt change, quit the while
+
+ brch_twig_index_LAST = brch_twig_index
+
+ # new twigs have been added, recalculate
+ branches_twig_sort = [brch.bestTwigSegment() for brch in self.branches_all]
+ branches_twig_sort.sort() # this will sort the branches with best braches for adding twigs to at the start of the list
+
+ for tmp_sortval, twig_pt_index, brch_parent in branches_twig_sort: # tmp_sortval is not used.
+ if twig_pt_index != -1 and \
+ (twig_recursive_limit == 0 or brch_parent.generation < twig_recursive_limit) and \
+ (twig_placement_maxtwig == 0 or brch_parent.twig_count < twig_placement_maxtwig) and \
+ brch_parent.bpoints[twig_pt_index].radius < twig_placement_maxradius:
+
+ if brch_twig_index >= len(self.branches_twigs):
+ break
+
+ brch_twig = self.branches_twigs[brch_twig_index]
+ parent_pt = brch_parent.bpoints[twig_pt_index]
+
+ brch_twig.parent_pt = parent_pt
+ parent_pt.childCount += 1
+
+ # Scale this twig using this way...
+ # The size of the parent, scaled by the parent point's radius,
+ # ...compared to the parent branch;s root point radius.
+ # Also take into account the length of the parent branch
+ # Use this for pretend random numbers too.
+ scale = twig_scale * (parent_pt.branch.bpoints[0].radius / brch_twig.bpoints[0].radius) * (parent_pt.radius / parent_pt.branch.bpoints[0].radius)
+
+ # Random orientation
+ # THIS IS NOT RANDOM - Dont be real random so we can always get re-produceale results.
+ if twig_random_orientation: rnd1 = (((irational_num * scale * 10000000) % 360) - 180) * twig_random_orientation
+ else: rnd1 = 0.0
+ if twig_random_angle: rnd2 = (((irational_num * scale * 66666666) % 360) - 180) * twig_random_angle
+ else: rnd2 = 0.0
+
+ # Align this with the existing branch
+ angle = AngleBetweenVecsSafe(zup, parent_pt.no)
+ cross = CrossVecs(zup, parent_pt.no)
+ mat_align = RotationMatrix(angle, 3, 'r', cross)
+
+ # Use the bend on the point to work out which way to make the branch point!
+ if parent_pt.prev: cross = CrossVecs(parent_pt.no, parent_pt.prev.no - parent_pt.no)
+ else: cross = CrossVecs(parent_pt.no, parent_pt.next.no - parent_pt.no)
+
+ if parent_pt.branch.parent_pt:
+ angle = AngleBetweenVecsSafe(parent_pt.branch.parent_pt.no, parent_pt.no)
+ else:
+ # Should add a UI for this... only happens when twigs come off a root branch
+ angle = 66
+
+ mat_branch_angle = RotationMatrix(angle+rnd1, 3, 'r', cross)
+ mat_scale = Matrix([scale,0,0],[0,scale,0],[0,0,scale])
+
+ mat_orientation = RotationMatrix(rnd2, 3, 'r', parent_pt.no)
+
+ if twig_scale_width != 1.0:
+ # adjust length - no radius adjusting
+ for pt in brch_twig.bpoints:
+ pt.radius *= twig_scale_width
+
+ brch_twig.transform(mat_scale * mat_branch_angle * mat_align * mat_orientation, parent_pt.co)
+
+ # Follow the parent normal
+ if twig_follow_parent or twig_follow_x or twig_follow_y or twig_follow_z:
+
+ vecs = []
+ brch_twig_len = float(len(brch_twig.bpoints))
+
+ if twig_follow_parent:
+ no = parent_pt.no.copy() * twig_follow_parent
+ else:
+ no = Vector()
+
+ no.x += twig_follow_x
+ no.y += twig_follow_y
+ no.z += twig_follow_z
+
+ for i, pt in enumerate(brch_twig.bpoints):
+ if pt.prev:
+ fac = i / brch_twig_len
+
+ # Scale this value
+ fac_inv = 1-fac
+
+ no_orig = pt.co - pt.prev.co
+ len_orig = no_orig.length
+
+ no_new = (fac_inv * no_orig) + (fac * no)
+ no_new.length = len_orig
+
+ # Mix the 2 normals
+ vecs.append(no_new)
+
+ # Apply the coords
+ for i, pt in enumerate(brch_twig.bpoints):
+ if pt.prev:
+ pt.co = pt.prev.co + vecs[i-1]
+
+ brch_twig.calcPointExtras()
+
+
+ # When using a bounding mesh, clip and calculate points in bounds.
+ #print "Attempting to trim base"
+ brch_twig.baseTrim(connect_base_trim)
+
+ if twig_ob_bounds and (twig_ob_bounds_prune or twig_recursive):
+ brch_twig.calcTwigBounds(self)
+
+ # we would not have been but here if the bounds were outside
+ if twig_ob_bounds_prune:
+ brch_twig.boundsTrim()
+ if twig_ob_bounds_prune_taper != 1.0:
+ # taper to a point. we could use some nice taper algo here - just linear atm.
+
+ brch_twig.taper(twig_ob_bounds_prune_taper)
+
+ # Make sure this dosnt mess up anything else
+
+ brch_twig_index += 1
+
+ # Add to the branches
+ #self.branches_all.append(brch_twig)
+ if len(brch_twig.bpoints) > 2:
+ branches_twig_attached.append(brch_twig)
+ brch_twig.generation = brch_parent.generation + 1
+ brch_parent.twig_count += 1
+ else:
+ # Dont add the branch
+ parent_pt.childCount -= 1
+
+ # Watch This! - move 1 tab down for no recursive twigs
+ if twig_recursive:
+ self.branches_all.extend(branches_twig_attached)
+ branches_twig_attached = []
+
+ if not twig_recursive:
+ self.branches_all.extend(branches_twig_attached)
+ branches_twig_attached = []
+
+
+ if do_twigs_fill and twig_ob_bounds:
+ self.twigFill(\
+ twig_fill_levels,\
+ twig_fill_rand_scale,\
+ twig_fill_fork_angle_max,\
+ twig_fill_radius_min,\
+ twig_fill_radius_factor,\
+ twig_fill_shape_type,\
+ twig_fill_shape_rand,\
+ twig_fill_shape_power,\
+ )
+
+ ### self.branches_all.sort( key = lambda brch: brch.parent_pt != None )
+
+ # Calc points with dependancies
+ # detect circular loops!!! - TODO
+ #### self.resetTags(False) # NOT NEEDED NOW
+ done_nothing = False
+ while done_nothing == False:
+ done_nothing = True
+
+ for brch in self.branches_all:
+
+ if brch.tag == False and (brch.parent_pt == None or brch.parent_pt.branch.tag == True):
+ # Assign this to a spesific side of the parents point
+ # we know this is a child but not which side it should be attached to.
+ if brch.parent_pt:
+
+ child_locs = [\
+ brch.parent_pt.childPointUnused(0),\
+ brch.parent_pt.childPointUnused(1),\
+ brch.parent_pt.childPointUnused(2),\
+ brch.parent_pt.childPointUnused(3)]
+
+ best_idx = closestVecIndex(brch.bpoints[0].co, child_locs)
+
+ # best_idx could be -1 if all childPoint's are used however we check for this and dont allow it to happen.
+ #if best_idx==-1:
+ # raise "Error"z
+ brch.parent_pt.children[best_idx] = brch
+
+ for pt in brch.bpoints:
+ pt.calcVerts()
+
+ done_nothing = False
+ brch.tag = True
+
+ '''
+ for i in xrange(len(self.branches_all)):
+ brch_i = self.branches_all[i]
+ print brch_i.myindex,
+ print 'tag', brch_i.tag,
+ print 'parent is',
+ if brch_i.parent_pt:
+ print brch_i.parent_pt.branch.myindex
+ else:
+ print None
+ '''
+
+ def optimizeSpacing(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, joint_compression=1.0, joint_smooth=1.0):
+ '''
+ Optimize spacing, taking branch hierarchy children into account,
+ can add or subdivide segments so branch joins dont look horrible.
+ '''
+ for brch in self.branches_all:
+ brch.evenJointDistrobution(joint_compression)
+
+ # Correct points that were messed up from sliding
+ # This happens when one point is pushed past another and the branch gets an overlaping line
+
+ for brch in self.branches_all:
+ brch.fixOverlapError(joint_smooth)
+
+
+ # Collapsing
+ for brch in self.branches_all:
+ brch.collapsePoints(seg_density, seg_density_angle, seg_density_radius, joint_smooth)
+
+ '''
+ for brch in self.branches_all:
+ brch.branchReJoin()
+ '''
+
+ def twigFill(self_tree,\
+ twig_fill_levels,\
+ twig_fill_rand_scale,\
+ twig_fill_fork_angle_max,\
+ twig_fill_radius_min,\
+ twig_fill_radius_factor,\
+ twig_fill_shape_type,\
+ twig_fill_shape_rand,\
+ twig_fill_shape_power,\
+ ):
+ '''
+ Fill with twigs, this function uses its own class 'segment'
+
+ twig_fill_shape_type;
+ 0 - no child smoothing
+ 1 - smooth one child
+ 2 - smooth both children
+
+ '''
+
+ rnd = [1]
+
+ segments_all = []
+ segments_level = []
+
+ # Only for testing
+ def preview_curve():
+ TWIG_WIDTH_MAX = 1.0
+ TWIG_WIDTH_MIN = 0.1
+ cu = bpy.data.curves["cu"]
+ # remove all curves
+ while len(cu):
+ del cu[0]
+ # return
+
+ cu.setFlag(1)
+ cu.ext2 = 0.01
+
+ WIDTH_STEP = (TWIG_WIDTH_MAX-TWIG_WIDTH_MIN) / twig_fill_levels
+
+ for i, seg in enumerate(segments_all):
+
+ # 1 is the base and 2 is the tail
+
+ p1_h2 = seg.getHeadHandle() # isnt used
+ p1_co = seg.headCo
+ p1_h1 = seg.getHeadHandle()
+
+ p2_h1 = seg.getTailHandle()
+
+ p2_co = seg.tailCo
+ p2_h2 = seg.tailCo # isnt used
+
+ bez1 = Blender.BezTriple.New([ p1_h1[0], p1_h1[1], p1_h1[2], p1_co[0], p1_co[1], p1_co[2], p1_h2[0], p1_h2[1], p1_h2[2] ])
+ bez2 = Blender.BezTriple.New([ p2_h1[0], p2_h1[1], p2_h1[2], p2_co[0], p2_co[1], p2_co[2], p2_h2[0], p2_h2[1], p2_h2[2] ])
+ bez1.handleTypes = bez2.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE]
+
+ bez1.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * (seg.levelFromLeaf+1))
+ bez2.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * seg.levelFromLeaf)
+
+ cunurb = cu.appendNurb(bez1)
+ cunurb.append(bez2)
+
+ # This sucks
+ for bez in cunurb:
+ bez.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE]
+
+ ### cc = sce.objects.new( cu )
+ cu.update()
+
+
+ def mergeCo(parentCo, ch1Co, ch2Co, twig_fill_shape_rand):
+ if twig_fill_shape_rand==0.0:
+ return (parentCo + ch1Co + ch2Co) / 3.0
+ else:
+
+ w1 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
+ w2 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
+ w3 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
+ wtot = w1+w2+w3
+ w1=w1/wtot
+ w2=w2/wtot
+ w3=w3/wtot
+
+ # return (parentCo*w1 + ch1Co*w2 + ch2Co*w2)
+ co1 = (parentCo * w1) + (ch1Co * (1.0-w1))
+ co2 = (ch1Co * w2) + (ch2Co * (1.0-w2))
+ co3 = (ch2Co * w3) + (parentCo * (1.0-w3))
+
+ return (co1 + co2 + co3) / 3.0
+
+
+
+ class segment:
+ def __init__(self, level):
+ self.headCo = Vector()
+ self.tailCo = Vector()
+ self.parent = None
+ self.mergeCount = 0
+ self.levelFromLeaf = level # how far we are from the leaf in levels
+ self.levelFromRoot = -1 # set later, assume root bone
+ self.children = []
+ segments_all.append(self)
+
+ if level >= len(segments_level): segments_level.append([self])
+ else: segments_level[level].append(self)
+
+ self.brothers = []
+ self.no = Vector() # only endpoints have these
+ # self.id = len(segments_all)
+
+ # First value is the bpoint,
+ # Second value is what to do -
+ # 0 - dont join
+ # 1 - Join to parent (tree point)
+ # 2 - join to parent, point from another fill-twig branch we just created.
+
+ self.bpt = (None, False) # branch point for root segs only
+ self.new_bpt = None
+
+ self.used = False # use this to tell if we are apart of a branch
+
+ def sibling(self):
+ i = self.parent.children.index(self)
+
+ if i == 0:
+ return self.parent.children[ 1 ]
+ elif i == 1:
+ return self.parent.children[ 0 ]
+ else:
+ raise "error"
+
+
+ def getHeadHandle(self):
+ """
+ For Bezier only
+ """
+
+ if not self.parent:
+ return self.headCo
+
+ if twig_fill_shape_type == 0: # no smoothing
+ return self.headCo
+ elif twig_fill_shape_type == 1:
+ if self.parent.children[1] == self:
+ return self.headCo
+ # 2 - always do both
+
+
+ # Y shape with curve? optional
+
+ # we have a parent but it has no handle direction, easier
+ if not self.parent.parent: no = self.parent.headCo - self.parent.tailCo
+ else: no = self.parent.parent.headCo-self.parent.tailCo
+
+ no.length = self.getLength() * twig_fill_shape_power
+ # Ok we have to account for the parents handle
+ return self.headCo - no
+ # return self.headCo - Vector(1, 0,0)
+
+ def getTailHandle(self):
+ """
+ For Bezier only
+ """
+ if self.parent:
+ no = self.parent.headCo-self.tailCo
+ no.length = self.getLength() * twig_fill_shape_power
+ return self.tailCo + no
+ else:
+ return self.tailCo # isnt used
+
+ def getRootSeg(self):
+ seg = self
+ while seg.parent:
+ seg = seg.parent
+
+ return seg
+
+ def calcBrothers(self):
+ # Run on children first
+ self.brothers.extend( \
+ [seg_child_sibling.parent \
+ for seg_child in self.children \
+ for seg_child_sibling in seg_child.brothers \
+ if seg_child_sibling.parent not in (self, None)]\
+ )
+ #print self.brothers
+
+ def calcLevelFromRoot(self):
+ if self.parent:
+ self.levelFromRoot = self.parent.levelFromRoot + 1
+
+ for seg_child in self.children:
+ seg_child.calcLevelFromRoot()
+
+ # Dont use for now, but scale worked, transform was never tested.
+ """
+ def transform(self, matrix):
+ self.headCo = self.headCo * matrix
+ self.tailCo = self.tailCo * matrix
+
+ if self.children:
+ ch1 = self.children[0]
+ ch2 = self.children[1]
+
+ ch1.transform(matrix)
+ ch2.transform(matrix)
+
+ def scale(self, scale, cent=None):
+ # scale = 0.9
+ #matrix = Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4()
+ #self.transform(matrix)
+ if cent == None: # first iter
+ cent = self.headCo
+ self.tailCo = ((self.tailCo-cent) * scale) + cent
+ else:
+ self.headCo = ((self.headCo-cent) * scale) + cent
+ self.tailCo = ((self.tailCo-cent) * scale) + cent
+
+ if self.children:
+ self.children[0].scale(scale, cent)
+ self.children[1].scale(scale, cent)
+ """
+ def recalcChildLoc(self):
+ if not self.children:
+ return
+ ch1 = self.children[0]
+ ch2 = self.children[1]
+ new_mid = mergeCo(self.headCo, ch1.tailCo, ch2.tailCo, twig_fill_shape_rand)
+
+ self.tailCo[:] = ch1.headCo[:] = ch2.headCo[:] = new_mid
+
+ ch1.recalcChildLoc()
+ ch2.recalcChildLoc()
+
+ def merge(self, other):
+ """
+ Merge other into self and make a new segment
+ """
+ """
+ seg_child = segment(self.levelFromLeaf)
+ self.levelFromLeaf += 1
+
+ seg_child.parent = other.parent = self
+
+ # No need, recalcChildLoc sets the other coords
+ #self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0
+ #self.parent.headCo[:] = self.headCo
+
+ seg_child.headCo[:] = self.headCo
+
+ # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo)
+ # new_head = (isect[0]+isect[1]) * 0.5
+
+ seg_child.mergeCount += 1
+ other.mergeCount += 1
+
+ self.children.extend([ seg_child, other ])
+
+ self.recalcChildLoc()
+
+ # print 'merging', self.id, other.id
+ """
+
+ #new_head = (self.headCo + self.tailCo + other.headCo + other.tailCo) * 0.25
+
+ self.parent = other.parent = segment(self.levelFromLeaf + 1)
+
+ # No need, recalcChildLoc sets the self.parent.tailCo
+ # self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0
+
+ self.parent.headCo[:] = self.headCo
+ self.parent.bpt = self.bpt
+ self.bpt = (None, False)
+
+ # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo)
+ # new_head = (isect[0]+isect[1]) * 0.5
+
+ self.mergeCount += 1
+ other.mergeCount += 1
+
+ self.parent.children.extend([ self, other ])
+
+ self.parent.recalcChildLoc()
+ # print 'merging', self.id, other.id
+
+
+ def findBestMerge(self, twig_fill_fork_angle_max):
+ # print "findBestMerge"
+ if self.parent != None:
+ return
+
+ best_dist = 1000000
+ best_seg = None
+ for seg_list in (self.brothers, segments_level[self.levelFromLeaf]):
+ #for seg_list in (segments_level[self.levelFromLeaf],):
+
+ # only use all other segments if we cant find any from our brothers
+ if seg_list == segments_level[self.levelFromLeaf] and best_seg != None:
+ break
+
+ for seg in seg_list:
+ # 2 ppoint join
+ if seg != self and seg.mergeCount == 0 and seg.parent == None:
+
+ # find the point they would join
+ test_dist = (self.tailCo - seg.tailCo).length
+ if test_dist < best_dist:
+ if twig_fill_fork_angle_max > 179:
+ best_dist = test_dist
+ best_seg = seg
+ else:
+ # Work out if the desired angle range is ok.
+ mco = mergeCo( self.headCo, self.tailCo, seg.tailCo, 0.0 ) # we dont want the random value for this test
+ ang = AngleBetweenVecsSafe(self.tailCo-mco, seg.tailCo-mco)
+ if ang < twig_fill_fork_angle_max:
+ best_dist = test_dist
+ best_seg = seg
+ return best_seg
+
+ def getNormal(self):
+ return (self.headCo - self.tailCo).normalize()
+
+ def getLength(self):
+ return (self.headCo - self.tailCo).length
+ """
+ def toMatrix(self, LEAF_SCALE, LEAF_RANDSCALE, LEAF_RANDVEC):
+ if LEAF_RANDSCALE: scale = LEAF_SCALE * Rand(1.0-LEAF_RANDSCALE, 1.0+LEAF_RANDSCALE)
+ else: scale = LEAF_SCALE * 1.0
+
+ if LEAF_RANDVEC: rand_vec = Vector( Rand(-1, 1), Rand(-1, 1), Rand(-1, 1) ).normalize() * LEAF_RANDVEC
+ else: rand_vec = Vector( )
+
+ return Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4() * (self.no + rand_vec).toTrackQuat('x', 'z').toMatrix().resize4x4() * TranslationMatrix(self.tailCo)
+ """
+ def distripute_seg_on_mesh(me__, face_group):
+ """
+ add segment endpoints
+ """
+
+ vert_segment_mapping = {}
+ for f in face_group:
+ for v in f:
+ i = v.index
+ if i not in vert_segment_mapping:
+ vert_segment_mapping[i] = len(segments_all)
+ v.sel = True
+ seg = segment(0)
+ # seg.tailCo = v.co.copy() # headCo undefined atm.
+ seg.tailCo = v.co.copy() * self_tree.objectTwigBoundsMat * self_tree.objectCurveIMat
+
+ # self_tree.objectCurveMat
+
+ seg.no = v.no
+
+ # Build connectivity
+ for ed in me__.edges:
+ if ed.v1.sel and ed.v2.sel:
+ i1,i2 = ed.key
+ i1 = vert_segment_mapping[i1]
+ i2 = vert_segment_mapping[i2]
+
+ segments_all[i1].brothers.append( segments_all[i2] )
+ segments_all[i2].brothers.append( segments_all[i1] )
+
+ # Dont need to return anything, added when created.
+
+ def set_seg_attach_point(seg, interior_points, twig_fill_rand_scale):
+ """
+ Can only run on end nodes that have normals set
+ """
+ best_dist = 1000000000.0
+ best_point = None
+
+ co = seg.tailCo
+
+ for pt in interior_points:
+ # line from the point to the seg endpoint
+
+ line_normal = seg.tailCo - pt.nextMidCo
+ l = line_normal.length
+
+
+ cross1 = CrossVecs( seg.no, line_normal )
+ cross2 = CrossVecs( pt.no, line_normal )
+
+ angle_line = min(AngleBetweenVecsSafe(cross1, cross2), AngleBetweenVecsSafe(cross1, -cross2))
+ angle_leaf_no_diff = min(AngleBetweenVecsSafe(line_normal, seg.no), AngleBetweenVecsSafe(line_normal, -seg.no))
+
+ # BEST_ANG=66.0
+ # angle = 66.0 # min(AngleBetweenVecs(v2_co-v1_co, leaf.co-cc), AngleBetweenVecs(v1_co-v2_co, leaf.co-cc))
+ # print angle, angle2
+ # l = (l * ((1+abs(angle-BEST_ANG))**2 )) / (1+angle_line)
+ l = (1+(angle_leaf_no_diff/180)) * (1+(angle_line/180)) * l
+
+ if l < best_dist:
+ best_pt = pt
+ best_co = pt.nextMidCo
+
+ best_dist = l
+
+ # twig_fill_rand_scale
+ seg.headCo = best_co.copy()
+
+ if twig_fill_rand_scale:
+ seg_dir = seg.tailCo - seg.headCo
+
+ seg_dir.length = seg_dir.length * ( 1.0 - (next_random_num(rnd)*twig_fill_rand_scale) )
+ seg.tailCo = seg.headCo + seg_dir
+
+
+ if best_pt.childCount < 4:
+ # Watch this!!! adding a user before its attached and the branch is created!
+ # make sure if its not added later on, this isnt left added
+ best_pt.childCount += 1
+
+ # True/False denotes weather we try to connect to our parent branch
+ seg.bpt = (best_pt, True)
+ else:
+ seg.bpt = (best_pt, False)
+
+ return True
+
+
+ # END Twig code, next add them
+
+
+ """
+ Uses a reversed approch, fill in twigs from a bounding mesh
+ """
+ # print "twig_fill_fork_angle_max"
+ # twig_fill_fork_angle_max = 60.0 #
+ # forward_diff_bezier will fill in the blanks
+ # nice we can reuse these for every curve segment :)
+ pointlist = [[None, None, None] for i in xrange(self_tree.steps+1)]
+ radlist = [ None for i in xrange(self_tree.steps+1) ]
+
+ orig_branch_count = len(self_tree.branches_all)
+
+ for face_group in BPyMesh.mesh2linkedFaces(self_tree.objectTwigBoundsMesh):
+ # Set the selection to do point inside.
+ self_tree.objectTwigBoundsMesh.sel = False
+ for f in face_group: f.sel = True
+
+ interior_points = []
+ interior_normal = Vector()
+ for i, brch in enumerate(self_tree.branches_all):
+
+ if i == orig_branch_count:
+ break # no need to check new branches are inside us
+
+ for pt in brch.bpoints:
+ if pt.next and pt.childCount < 4: # cannot attach to the last points
+ if self_tree.isPointInTwigBounds(pt.co, True): # selected_only
+ interior_points.append(pt)
+ interior_normal += pt.no * pt.radius
+
+ segments_all[:] = []
+ segments_level[:] = []
+
+ if interior_points:
+ # Ok, we can add twigs now
+ distripute_seg_on_mesh( self_tree.objectTwigBoundsMesh, face_group )
+
+ for seg in segments_level[0]: # only be zero segments
+ # Warning, increments the child count for bpoints we attach to!!
+ set_seg_attach_point(seg, interior_points, twig_fill_rand_scale)
+
+ # Try sorting by other properties! this is ok for now
+ for segments_level_current in segments_level:
+ segments_level_current.sort( key = lambda seg: -(seg.headCo-seg.tailCo).length )
+
+ for level in xrange(twig_fill_levels):
+ if len(segments_level) > level:
+ for seg in segments_level[level]:
+ # print level, seg.brothers
+ if seg.mergeCount == 0:
+ seg_merge = seg.findBestMerge(twig_fill_fork_angle_max)
+ if seg_merge:
+ seg.merge( seg_merge )
+
+ if len(segments_level) > level+1:
+ for seg in segments_level[level+1]:
+ seg.calcBrothers()
+
+ for seg in segments_all:
+ if seg.parent == None:
+ seg.levelFromRoot = 0
+ seg.calcLevelFromRoot()
+
+ '''
+ for i, seg in enumerate(segments_all):
+ # Make a branch from this data!
+
+ brch = branch()
+ brch.type = BRANCH_TYPE_FILL
+ self_tree.branches_all.append(brch)
+
+ # ============================= do this per bez pair
+ # 1 is the base and 2 is the tail
+
+ #p1_h1 = seg.getHeadHandle()
+ p1_co = seg.headCo.copy()
+ p1_h2 = seg.getHeadHandle() # isnt used
+
+ p2_h1 = seg.getTailHandle()
+ p2_co = seg.tailCo.copy()
+ #p2_h2 = seg.getTailHandle() # isnt used
+
+
+ bez1_vec = (None, p1_co, p1_h2)
+ bez2_vec = (p2_h1, p2_co, None)
+
+ seg_root = seg.getRootSeg()
+
+ radius_root = seg_root.bpt.radius * twig_fill_radius_factor
+ # Clamp so the head is never smaller then the tail
+ if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min
+
+ if seg_root.levelFromLeaf:
+ # print seg_root.levelFromLeaf, seg.levelFromRoot
+ WIDTH_STEP = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1)
+
+ radius1 = twig_fill_radius_min + (WIDTH_STEP * (seg.levelFromLeaf+1))
+ if seg.levelFromLeaf: radius2 = twig_fill_radius_min + (WIDTH_STEP * seg.levelFromLeaf)
+ else: radius2 = twig_fill_radius_min
+ else:
+ radius1 = radius_root
+ radius2 = twig_fill_radius_min
+
+
+ points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2)
+
+ # dont apply self_tree.limbScale here! - its alredy done
+ bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(len(pointlist)) ]
+
+ # remove endpoint for all but the last
+ #if i != len(bez_list)-1:
+ # bpoints.pop()
+
+ brch.bpoints.extend(bpoints)
+ # =============================
+
+ # Finalize once point data is there
+ brch.calcData()
+ #
+ #preview_curve()
+ '''
+
+ for segments_level_current in reversed(segments_level):
+ for seg in segments_level_current:
+ if seg.used == False and (seg.parent == None or seg.parent.used == True):
+
+ # The root segment for this set of links.
+ # seg_root_linked = seg
+
+ brch = branch()
+ brch.type = BRANCH_TYPE_FILL
+ self_tree.branches_all.append(brch)
+
+ # Can we attach to a real branch?
+ if seg.parent == None:
+ if seg.bpt[1]: # we can do a real join into the attach point
+ brch.parent_pt = seg.bpt[0]
+ # brch.parent_pt.childCount # this has alredy changed from
+
+ '''
+ if seg.parent:
+ if seg.bpt[1] == 2:
+ #if seg.bpt[1]:
+ # print "Making Connection"
+ if seg.bpt[0] == None:
+ raise "Error"
+ if seg.bpt[1] != 2:
+ print seg.bpt[1]
+ raise "Error"
+
+ brch.parent_pt = seg.bpt[1]
+ brch.parent_pt.childCount += 1
+ if brch.parent_pt.childCount > 4:
+ raise "Aeeae"
+ print "\n\nM<aking Joint!!"
+ '''
+
+ if seg.parent:
+ sibling = seg.sibling()
+ if sibling.new_bpt:
+ if sibling.new_bpt.childCount < 4:
+ brch.parent_pt = sibling.new_bpt
+ brch.parent_pt.childCount +=1
+
+ # Go down the hierarhy
+ is_first = True
+ while seg != None:
+ seg.used = True
+
+ # ==============================================
+
+ #p1_h1 = seg.getHeadHandle()
+ p1_co = seg.headCo.copy()
+ p1_h2 = seg.getHeadHandle() # isnt used
+
+ p2_h1 = seg.getTailHandle()
+ p2_co = seg.tailCo.copy()
+ #p2_h2 = seg.getTailHandle() # isnt used
+
+
+ bez1_vec = (None, p1_co, p1_h2)
+ bez2_vec = (p2_h1, p2_co, None)
+
+ seg_root = seg.getRootSeg()
+
+ radius_root = seg_root.bpt[0].radius * twig_fill_radius_factor
+ # Clamp so the head is never smaller then the tail
+ if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min
+
+ if seg_root.levelFromLeaf:
+ # print seg_root.levelFromLeaf, seg.levelFromRoot
+ widthStep = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1)
+
+ radius1 = twig_fill_radius_min + (widthStep * (seg.levelFromLeaf+1))
+ if seg.levelFromLeaf: radius2 = twig_fill_radius_min + (widthStep * seg.levelFromLeaf)
+ else: radius2 = twig_fill_radius_min
+ else:
+ radius1 = radius_root
+ radius2 = twig_fill_radius_min
+
+ points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2)
+
+
+ start_pointlist = 0
+
+ # This is like baseTrim, (remove the base points to make nice joins, accounting for radius of parent point)
+ # except we do it before the branch is made
+
+ if brch.parent_pt:
+ while len(pointlist) - start_pointlist > 2 and (Vector(pointlist[start_pointlist]) - brch.parent_pt.co).length < (brch.parent_pt.radius*2):
+ start_pointlist +=1
+
+ if is_first and brch.parent_pt:
+ # We need to move the base point to a place where it looks good on the parent branch
+ # to do this. move the first point, then remove the following points that look horrible (double back on themself)
+
+ no = Vector(pointlist[0]) - Vector(pointlist[-1])
+ no.length = brch.parent_pt.radius*2
+ pointlist[0] = list(Vector(pointlist[0]) - no)
+
+ """
+ pointlist[1][0] = (pointlist[0][0] + pointlist[2][0])/2.0
+ pointlist[1][1] = (pointlist[0][1] + pointlist[2][1])/2.0
+ pointlist[1][2] = (pointlist[0][2] + pointlist[2][2])/2.0
+
+ pointlist[2][0] = (pointlist[1][0] + pointlist[3][0])/2.0
+ pointlist[2][1] = (pointlist[1][1] + pointlist[3][1])/2.0
+ pointlist[2][2] = (pointlist[1][2] + pointlist[3][2])/2.0
+ """
+
+
+ # Done setting the start point
+
+
+ len_pointlist = len(pointlist)
+ if seg.children:
+ len_pointlist -= 1
+
+ # dont apply self_tree.limbScale here! - its alredy done
+ bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(start_pointlist, len_pointlist) ]
+ brch.bpoints.extend( bpoints )
+ # ==============================================
+
+ seg.new_bpt = bpoints[0]
+
+ if seg.children:
+ seg = seg.children[0]
+ else:
+ seg = None
+
+ is_first = False
+
+ # done adding points
+ brch.calcData()
+
+
+
+
+ def buildTwigs(self, twig_ratio, twig_select_mode, twig_select_factor):
+
+ ratio_int = int(len(self.branches_all) * twig_ratio)
+ if ratio_int == 0:
+ return
+
+ # So we only mix branches of similar lengths
+ branches_sorted = self.branches_all[:]
+
+ # Get the branches based on our selection method!
+ if twig_select_mode==0:
+ branches_sorted.sort( key = lambda brch: brch.getLength())
+ elif twig_select_mode==1:
+ branches_sorted.sort( key = lambda brch:-brch.getLength())
+ elif twig_select_mode==2:
+ branches_sorted.sort( key = lambda brch:brch.getStraightness())
+ elif twig_select_mode==3:
+ branches_sorted.sort( key = lambda brch:-brch.getStraightness())
+
+ factor_int = int(len(self.branches_all) * twig_select_factor)
+ branches_sorted[factor_int:] = [] # remove the last part of the list
+
+ branches_sorted.sort( key = lambda brch: len(brch.bpoints))
+
+ branches_new = []
+ #for i in xrange(ratio_int):
+ tot_twigs = 0
+
+ step = 1
+ while tot_twigs < ratio_int and step < len(branches_sorted):
+ # Make branches from the existing
+ for j in xrange(step, len(branches_sorted)):
+ brch = branches_sorted[j-step].mixToNew(branches_sorted[j], None)
+ branches_new.append( brch )
+ tot_twigs +=1
+
+ if tot_twigs > ratio_int:
+ break
+
+ ### print "TwigCount", len(branches_new), ratio_int
+
+ self.branches_twigs = branches_new
+
+ def toDebugDisplay(self):
+ '''
+ Should be able to call this at any time to see whats going on, dosnt work so nice ATM.
+ '''
+ sce = bpy.data.scenes.active
+
+ for ob in self.debug_objects:
+ for ob in sce.objects:
+ sce.objects.unlink(ob)
+
+ for branch_index, brch in enumerate(self.branches_all):
+ pt_index = 0
+ for pt_index, pt in enumerate(brch.bpoints):
+ name = '%.3d_%.3d' % (branch_index, pt_index)
+ if pt.next==None:
+ name += '_end'
+ if pt.prev==None:
+ name += '_start'
+
+ ob = sce.objects.new('Empty', name)
+ self.debug_objects.append(ob)
+ mat = ScaleMatrix(pt.radius, 4) * TranslationMatrix(pt.co)
+ ob.setMatrix(mat)
+ ob.setDrawMode(8) # drawname
+ Blender.Window.RedrawAll()
+
+
+
+ def toMesh(self, mesh=None,\
+ do_uv=True,\
+ do_uv_keep_vproportion=True,\
+ do_uv_vnormalize=False,\
+ do_uv_uscale=False,\
+ uv_image = None,\
+ uv_x_scale=1.0,\
+ uv_y_scale=4.0,\
+ do_uv_blend_layer= False,\
+ do_cap_ends=False,\
+ ):
+
+ self.mesh = freshMesh(mesh)
+ totverts = 0
+
+ for brch in self.branches_all:
+ totverts += len(brch.bpoints)
+
+ self.mesh.verts.extend( [ (0.0,0.0,0.0) ] * ((totverts * 4)+1) ) # +1 is a dummy vert
+ verts = self.mesh.verts
+
+ # Assign verts to points, 4 verts for each point.
+ i = 1 # dummy vert, should be 0
+ for brch in self.branches_all:
+ for pt in brch.bpoints:
+ pt.verts[0] = verts[i]
+ pt.verts[1] = verts[i+1]
+ pt.verts[2] = verts[i+2]
+ pt.verts[3] = verts[i+3]
+ i+=4
+
+ # Do this again because of collapsing
+ # pt.calcVerts(brch)
+
+ # roll the tube so quads best meet up to their branches.
+ for brch in self.branches_all:
+ #for pt in brch.bpoints:
+ if brch.parent_pt:
+
+ # Use temp lists for gathering an average
+ if brch.parent_pt.roll_angle == None:
+ brch.parent_pt.roll_angle = [brch.getParentQuadAngle()]
+ # More then 2 branches use this point, add to the list
+ else:
+ brch.parent_pt.roll_angle.append( brch.getParentQuadAngle() )
+
+ # average the temp lists into floats
+ for brch in self.branches_all:
+ #for pt in brch.bpoints:
+ if brch.parent_pt and type(brch.parent_pt.roll_angle) == list:
+ # print brch.parent_pt.roll_angle
+ f = 0.0
+ for val in brch.parent_pt.roll_angle:
+ f += val
+ brch.parent_pt.roll_angle = f/len(brch.parent_pt.roll_angle)
+
+ # set the roll of all the first segments that have parents,
+ # this is because their roll is set from their parent quad and we dont want them to roll away from that.
+ for brch in self.branches_all:
+ if brch.parent_pt:
+ # if the first joint has a child then apply half the roll
+ # theres no correct solition here, but this seems ok
+ if brch.bpoints[0].roll_angle != None:
+ #brch.bpoints[0].roll_angle *= 0.5
+ #brch.bpoints[0].roll_angle = 0.0
+ #brch.bpoints[1].roll_angle = 0.0
+ brch.bpoints[0].roll_angle = 0.0
+ pass
+ else:
+ # our roll was set from the branches parent and needs no changing
+ # set it to zero so the following functions know to interpolate.
+ brch.bpoints[0].roll_angle = 45.0
+ #brch.bpoints[1].roll_angle = 0.0
+
+ '''
+ Now interpolate the roll!
+ The method used here is a little odd.
+
+ * first loop up the branch and set each points value to the "last defined" value and record the steps
+ since the last defined value
+ * Do the same again but backwards
+
+ now for each undefined value we have 1 or 2 values, if its 1 its simple we just use that value
+ ( no interpolation ), if there are 2 then we use the offsets from each end to work out the interpolation.
+
+ one up, one back, and another to set the values, so 3 loops all up.
+ '''
+ #### print "scan up the branch..."
+ for brch in self.branches_all:
+ last_value = None
+ last_index = -1
+ for i in xrange(len(brch.bpoints)):
+ pt = brch.bpoints[i]
+ if type(pt.roll_angle) in (float, int):
+ last_value = pt.roll_angle
+ last_index = i
+ else:
+ if type(last_value) in (float, int):
+ # Assign a list, because there may be a connecting roll value from another joint
+ pt.roll_angle = [(last_value, i-last_index)]
+
+ #### print "scan down the branch..."
+ last_value = None
+ last_index = -1
+ for i in xrange(len(brch.bpoints)-1, -1, -1): # same as above but reverse
+ pt = brch.bpoints[i]
+ if type(pt.roll_angle) in (float, int):
+ last_value = pt.roll_angle
+ last_index = i
+ else:
+ if last_value != None:
+ if type(pt.roll_angle) == list:
+ pt.roll_angle.append((last_value, last_index-i))
+ else:
+ #pt.roll_angle = [(last_value, last_index-i)]
+
+ # Dont bother assigning a list because we wont need to add to it later
+ pt.roll_angle = last_value
+
+ # print "looping ,...."
+ ### print "assigning/interpolating roll values"
+ for pt in brch.bpoints:
+
+ # print "this roll IS", pt.roll_angle
+
+ if pt.roll_angle == None:
+ continue
+ elif type(pt.roll_angle) in (float, int):
+ pass
+ elif len(pt.roll_angle) == 1:
+ pt.roll_angle = pt.roll_angle[0][0]
+ else:
+ # interpolate
+ tot = pt.roll_angle[0][1] + pt.roll_angle[1][1]
+ pt.roll_angle = \
+ (pt.roll_angle[0][0] * (tot - pt.roll_angle[0][1]) +\
+ pt.roll_angle[1][0] * (tot - pt.roll_angle[1][1])) / tot
+
+ #### print pt.roll_angle, 'interpolated roll'
+
+ pt.roll(pt.roll_angle)
+
+ # Done with temp average list. now we know the best roll for each branch.
+
+ # mesh the data
+ for brch in self.branches_all:
+ for pt in brch.bpoints:
+ pt.toMesh(self.mesh)
+
+ #faces_extend = [ face for brch in self.branches_all for pt in brch.bpoints for face in pt.faces if face ]
+
+
+
+ faces_extend = []
+ for brch in self.branches_all:
+ if brch.parent_pt:
+ faces_extend.extend(brch.faces)
+ for pt in brch.bpoints:
+ for face in pt.faces:
+ if face:
+ faces_extend.append(face)
+
+ if do_cap_ends:
+ # TODO - UV map and image?
+ faces_extend.extend([ brch.bpoints[-1].verts for brch in self.branches_all ])
+
+ faces = self.mesh.faces
+
+ faces.extend(faces_extend, smooth=True)
+
+ if do_uv:
+ # Assign the faces back
+ face_index = 0
+ for brch in self.branches_all:
+ if brch.parent_pt:
+ for i in (0,1,2,3):
+ face = brch.faces[i] = faces[face_index+i]
+ face_index +=4
+
+ for pt in brch.bpoints:
+ for i in (0,1,2,3):
+ if pt.faces[i]:
+ pt.faces[i] = faces[face_index]
+ face_index +=1
+
+ #if self.mesh.faces:
+ # self.mesh.faceUV = True
+ mesh.addUVLayer( 'base' )
+
+ # rename the uv layer
+ #mesh.renameUVLayer(mesh.getUVLayerNames()[0], 'base')
+
+ for brch in self.branches_all:
+
+ uv_x_scale_branch = 1.0
+ if do_uv_uscale:
+ uv_x_scale_branch = 0.0
+ for pt in brch.bpoints:
+ uv_x_scale_branch += pt.radius
+
+ uv_x_scale_branch = uv_x_scale_branch / len(brch.bpoints)
+ # uv_x_scale_branch = brch.bpoints[0].radius
+
+ if do_uv_vnormalize:
+ uv_normalize = []
+
+ def uvmap_faces(my_faces, y_val, y_size):
+ '''
+ Accept a branch or pt faces
+ '''
+ uv_ls = [None, None, None, None]
+ for i in (0,1,2,3):
+ if my_faces[i]:
+ if uv_image:
+ my_faces[i].image = uv_image
+ uvs = my_faces[i].uv
+ else:
+ # Use these for calculating blending values
+ uvs = [Vector(0,0), Vector(0,0), Vector(0,0), Vector(0,0)]
+
+ uv_ls[i] = uvs
+
+ x1 = i*0.25 * uv_x_scale * uv_x_scale_branch
+ x2 = (i+1)*0.25 * uv_x_scale * uv_x_scale_branch
+
+ uvs[3].x = x1;
+ uvs[3].y = y_val+y_size
+
+ uvs[0].x = x1
+ uvs[0].y = y_val
+
+ uvs[1].x = x2
+ uvs[1].y = y_val
+
+ uvs[2].x = x2
+ uvs[2].y = y_val+y_size
+
+ if do_uv_vnormalize:
+ uv_normalize.extend(uvs)
+
+ return uv_ls
+
+ # Done uvmap_faces
+
+ y_val = 0.0
+
+ if brch.parent_pt:
+ y_size = (brch.getParentFaceCent() - brch.bpoints[0].co).length
+
+ if do_uv_keep_vproportion:
+ y_size = y_size / ((brch.bpoints[0].radius + brch.parent_pt.radius)/2) * uv_y_scale
+
+ brch.uv = uvmap_faces(brch.faces, 0.0, y_size)
+
+ y_val += y_size
+
+ for pt in brch.bpoints:
+ if pt.next:
+ y_size = (pt.co-pt.next.co).length
+ # scale the uvs by the radius, avoids stritching.
+ if do_uv_keep_vproportion:
+ y_size = y_size / pt.radius * uv_y_scale
+ pt.uv = uvmap_faces(pt.faces, y_val, y_size)
+ y_val += y_size
+
+
+ if do_uv_vnormalize and uv_normalize:
+ # Use yscale here so you can choose to have half the normalized value say.
+ vscale = (1/uv_normalize[-1].y) * uv_y_scale
+ for uv in uv_normalize:
+ uv.y *= vscale
+
+
+ # Done with UV mapping the first layer! now map the blend layers
+ if do_uv_blend_layer:
+ # Set up the blend UV layer - this is simply the blending for branch joints
+ mesh.addUVLayer( 'blend' )
+ mesh.activeUVLayer = 'blend'
+
+ # Set all faces to be on full blend
+ for f in mesh.faces:
+ for uv in f.uv:
+ uv.y = uv.x = 0.0
+
+ for brch in self.branches_all:
+ if brch.parent_pt:
+ for f in brch.faces:
+ if f:
+ uvs = f.uv
+ uvs[0].x = uvs[1].x = uvs[2].x = uvs[3].x = 0.0
+ uvs[0].y = uvs[1].y = 1.0 # swap these? - same as inverting the blend
+ uvs[2].y = uvs[3].y = 0.0
+
+ # Set up the join UV layer, this overlays nice blended
+ mesh.addUVLayer( 'join' )
+ mesh.activeUVLayer = 'join'
+
+ # Set all faces to be on full blend
+ for f in mesh.faces:
+ for uv in f.uv:
+ uv.y = uv.x = 0.0
+
+ for brch in self.branches_all:
+ if brch.parent_pt:
+ # The UV's that this branch would cover if it was a face,
+ uvs_base = brch.parent_pt.uv[brch.getParentQuadIndex()]
+
+ uvs_base_mid = Vector(0,0)
+ for uv in uvs_base:
+ uvs_base_mid += uv
+
+ uvs_base_mid *= 0.25
+
+ # TODO - Factor scale and distance in here
+ ## uvs_base_small = [(uv+uvs_base_mid)*0.5 for uv in uvs_base]
+ uvs_base_small = [uvs_base_mid, uvs_base_mid, uvs_base_mid, uvs_base_mid]
+
+ if brch.faces[0]:
+ f = brch.faces[0]
+ uvs = f.uv
+ uvs[0][:] = uvs_base[0]
+ uvs[1][:] = uvs_base[1]
+
+ uvs[2][:] = uvs_base_small[1]
+ uvs[3][:] = uvs_base_small[0]
+
+ if brch.faces[1]:
+ f = brch.faces[1]
+ uvs = f.uv
+ uvs[0][:] = uvs_base[1]
+ uvs[1][:] = uvs_base[2]
+
+ uvs[2][:] = uvs_base_small[2]
+ uvs[3][:] = uvs_base_small[1]
+
+ if brch.faces[2]:
+ f = brch.faces[2]
+ uvs = f.uv
+ uvs[0][:] = uvs_base[2]
+ uvs[1][:] = uvs_base[3]
+
+ uvs[2][:] = uvs_base_small[3]
+ uvs[3][:] = uvs_base_small[2]
+
+ if brch.faces[3]:
+ f = brch.faces[3]
+ uvs = f.uv
+ uvs[0][:] = uvs_base[3]
+ uvs[1][:] = uvs_base[0]
+
+ uvs[2][:] = uvs_base_small[0]
+ uvs[3][:] = uvs_base_small[3]
+
+ mesh.activeUVLayer = 'base' # just so people dont get worried the texture is not there - dosnt effect rendering.
+ else:
+ # no UV's
+ pass
+
+ if do_cap_ends:
+ # de-select end points for
+ i = len(faces)-1
+
+ cap_end_face_start = len(faces) - len(self.branches_all)
+
+ j = 0
+ for i in xrange(cap_end_face_start, len(faces)):
+ self.branches_all[j].face_cap = faces[i]
+ faces[i].sel = 0
+
+ # default UV's are ok for now :/
+ if do_uv and uv_image:
+ faces[i].image = uv_image
+
+ j +=1
+
+ # set edge crease for capped ends.
+ for ed in self.mesh.edges:
+ if ed.v1.sel==False and ed.v2.sel==False:
+ ed.crease = 255
+ ed.sel = True # so its all selected still
+
+ del faces_extend
+
+ return self.mesh
+
+ def toLeafMesh(self, mesh_leaf,\
+ leaf_branch_limit = 0.5,\
+ leaf_branch_limit_rand = 0.8,\
+ leaf_branch_limit_type_curve = False,\
+ leaf_branch_limit_type_grow = False,\
+ leaf_branch_limit_type_fill = False,\
+ leaf_size = 0.5,\
+ leaf_size_rand = 0.5,\
+ leaf_branch_density = 0.2,\
+ leaf_branch_pitch_angle = 0.0,\
+ leaf_branch_pitch_rand = 0.2,\
+ leaf_branch_roll_rand = 0.2,\
+ leaf_branch_angle = 75.0,\
+ leaf_rand_seed = 1.0,\
+ leaf_object=None,\
+ ):
+
+ '''
+ return a mesh with leaves seperate from the tree
+
+ Add to the existing mesh.
+ '''
+
+ #radius = [(pt.radius for pt in self.branches_all for pt in brch.bpoints for pt in brch.bpoints]
+ mesh_leaf = freshMesh(mesh_leaf)
+ self.mesh_leaf = mesh_leaf
+
+ # if not leaf_object: return # make the dupli anyway :/ - they can do it later or the script could complain
+
+ if leaf_branch_limit == 1.0:
+ max_radius = 1000000.0
+ else:
+ # We wont place leaves on all branches so...
+ # first collect stats, we want to know the average radius and total segments
+ totpoints = 0
+ radius = 0.0
+ max_radius = 0.0
+ for brch in self.branches_all:
+ for pt in brch.bpoints:
+ radius += pt.radius
+ if pt.radius > max_radius:
+ max_radius = pt.radius
+
+ #totpoints += len(brch.bpoints)
+
+ radius_max = max_radius * leaf_branch_limit
+
+ verts_extend = []
+ faces_extend = []
+
+ co1 = Vector(0.0, -0.5, -0.5)
+ co2 = Vector(0.0, -0.5, 0.5)
+ co3 = Vector(0.0, 0.5, 0.5)
+ co4 = Vector(0.0, 0.5, -0.5)
+
+ rnd_seed = [leaf_rand_seed] # could have seed as an input setting
+
+ for brch in self.branches_all:
+
+ # quick test, do we need leaves on this branch?
+ if leaf_branch_limit != 1.0 and brch.bpoints[-1].radius > radius_max:
+ continue
+
+
+ for pt in brch.bpoints:
+
+ # For each point we can add 2 leaves
+ for odd_even in (0,1):
+
+
+ if (pt == brch.bpoints[-1] and odd_even==1) or \
+ (leaf_branch_density != 1.0 and leaf_branch_density < next_random_num(rnd_seed)):
+ pass
+ else:
+ if leaf_branch_limit_rand:
+ # (-1 : +1) * leaf_branch_limit_rand
+ rnd = 1 + (((next_random_num(rnd_seed) - 0.5) * 2 ) * leaf_branch_limit_rand)
+ else:
+ rnd = 1.0
+
+ if pt.childCount == 0 and (leaf_branch_limit == 1.0 or (pt.radius * rnd) < radius_max):
+ leaf_size_tmp = leaf_size * (1.0-(next_random_num(rnd_seed)*leaf_size_rand))
+
+ # endpoints dont rotate
+ if pt.next != None:
+ cross1 = CrossVecs(zup, pt.no) # use this to offset the leaf later
+ cross2 = CrossVecs(cross1, pt.no)
+ if odd_even ==0:
+ mat_yaw = RotationMatrix(leaf_branch_angle, 3, 'r', cross2)
+ else:
+ mat_yaw = RotationMatrix(-leaf_branch_angle, 3, 'r', cross2)
+
+ leaf_no = (pt.no * mat_yaw)
+
+ # Correct upwards pointing from changing the yaw
+ #my_up = zup * mat
+
+ # correct leaf location for branch width
+ cross1.length = pt.radius/2
+ leaf_co = pt.co + cross1
+ else:
+ # no correction needed, we are at the end of the branch
+ leaf_no = pt.no
+ leaf_co = pt.co
+
+ mat = Matrix([leaf_size_tmp,0,0],[0,leaf_size_tmp,0],[0,0,leaf_size_tmp]) * leaf_no.toTrackQuat('x', 'z').toMatrix()
+
+ # Randomize pitch and roll for the leaf
+
+ # work out the axis to pitch and roll
+ cross1 = CrossVecs(zup, leaf_no) # use this to offset the leaf later
+ if leaf_branch_pitch_rand or leaf_branch_pitch_angle:
+
+ angle = -leaf_branch_pitch_angle
+ if leaf_branch_pitch_rand:
+ angle += leaf_branch_pitch_rand * ((next_random_num(rnd_seed)-0.5)*360)
+
+ mat_pitch = RotationMatrix( angle, 3, 'r', cross1)
+ mat = mat * mat_pitch
+ if leaf_branch_roll_rand:
+ mat_roll = RotationMatrix( leaf_branch_roll_rand * ((next_random_num(rnd_seed)-0.5)*360), 3, 'r', leaf_no)
+ mat = mat * mat_roll
+
+ mat = mat.resize4x4() * TranslationMatrix(leaf_co)
+
+ i = len(verts_extend)
+ faces_extend.append( (i,i+1,i+2,i+3) )
+ verts_extend.extend([tuple(co4*mat), tuple(co3*mat), tuple(co2*mat), tuple(co1*mat)])
+ #count += 1
+
+
+ # setup dupli's
+
+ self.mesh_leaf.verts.extend(verts_extend)
+ self.mesh_leaf.faces.extend(faces_extend)
+
+ return self.mesh_leaf
+
+
+ def toArmature(self, ob_arm, armature):
+
+ armature.drawType = Blender.Armature.STICK
+ armature.makeEditable() # enter editmode
+
+ # Assume toMesh has run
+ self.armature = armature
+ for bonename in armature.bones.keys():
+ del armature.bones[bonename]
+
+
+ group_names = []
+
+ for i, brch in enumerate(self.branches_all):
+
+ # get a list of parent points to make into bones. use parents and endpoints
+ bpoints_parent = [pt for pt in brch.bpoints if pt.childCount or pt.prev == None or pt.next == None]
+ bpbone_last = None
+ for j in xrange(len(bpoints_parent)-1):
+
+ # bone container class
+ bpoints_parent[j].bpbone = bpbone = bpoint_bone()
+ bpbone.name = '%i_%i' % (i,j) # must be unique
+ group_names.append(bpbone.name)
+
+ bpbone.editbone = Blender.Armature.Editbone() # automatically added to the armature
+ self.armature.bones[bpbone.name] = bpbone.editbone
+
+ bpbone.editbone.head = bpoints_parent[j].co
+ bpbone.editbone.head = bpoints_parent[j].co
+ bpbone.editbone.tail = bpoints_parent[j+1].co
+
+ # parent the chain.
+ if bpbone_last:
+ bpbone.editbone.parent = bpbone_last.editbone
+ bpbone.editbone.options = [Blender.Armature.CONNECTED]
+
+ bpbone_last = bpbone
+
+ for brch in self.branches_all:
+ if brch.parent_pt: # We must have a parent
+
+ # find the bone in the parent chain to use for the parent of this
+ parent_pt = brch.parent_pt
+ bpbone_parent = None
+ while parent_pt:
+ bpbone_parent = parent_pt.bpbone
+ if bpbone_parent:
+ break
+
+ parent_pt = parent_pt.prev
+
+
+ if bpbone_parent:
+ brch.bpoints[0].bpbone.editbone.parent = bpbone_parent.editbone
+ else: # in rare cases this may not work. should be verry rare but check anyway.
+ print 'this is really odd... look into the bug.'
+
+ self.armature.update() # exit editmode
+
+ # Skin the mesh
+ if self.mesh:
+ for group in group_names:
+ self.mesh.addVertGroup(group)
+
+ for brch in self.branches_all:
+ vertList = []
+ group = '' # dummy
+
+ for pt in brch.bpoints:
+ if pt.bpbone:
+ if vertList:
+ self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD)
+
+ vertList = []
+ group = pt.bpbone.name
+
+ vertList.extend( [v.index for v in pt.verts] )
+
+ if vertList:
+ self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD)
+
+ return self.armature
+
+ def toAction(self, ob_arm, texture, anim_speed=1.0, anim_magnitude=1.0, anim_speed_size_scale=True, anim_offset_scale=1.0):
+ # Assume armature
+ action = ob_arm.action
+ if not action:
+ action = bpy.data.actions.new()
+ action.fakeUser = False # so we dont get masses of bad data
+ ob_arm.action = action
+
+ # Blender.Armature.NLA.ob_arm.
+ pose = ob_arm.getPose()
+
+ for pose_bone in pose.bones.values():
+ pose_bone.insertKey(ob_arm, 0, [Blender.Object.Pose.ROT], True)
+
+ # Now get all the IPO's
+
+ ipo_dict = action.getAllChannelIpos()
+ # print ipo_dict
+
+ # Sicne its per frame, it increases very fast. scale it down a bit
+ anim_speed = anim_speed/100
+
+ # When we have the same trees next to eachother, they will animate the same way unless we give each its own texture or offset settings.
+ # We can use the object's location as a factor - this also will have the advantage? of seeing the animation move across the tree's
+ # allow a scale so the difference between tree textures can be adjusted.
+ anim_offset = self.objectCurve.matrixWorld.translationPart() * anim_offset_scale
+
+ anim_speed_final = anim_speed
+ # Assign drivers to them all
+ for name, ipo in ipo_dict.iteritems():
+ tex_str = 'b.Texture.Get("%s")' % texture.name
+
+ if anim_speed_size_scale:
+ # Adjust the speed by the bone size.
+ # get the point from the name. a bit ugly but works fine ;) - Just dont mess the index up!
+ lookup = [int(val) for val in name.split('_')]
+ pt = self.branches_all[ lookup[0] ].bpoints[ lookup[1] ]
+ anim_speed_final = anim_speed / (1+pt.radius)
+
+ cu = ipo[Blender.Ipo.PO_QUATX]
+ try: cu.delBezier(0)
+ except: pass
+ cu.driver = 2 # Python expression
+ cu.driverExpression = '%.3f*(%s.evaluate(((b.Get("curframe")*%.3f)+%.3f,%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_speed_final, anim_offset.x, anim_offset.y, anim_offset.z)
+
+ cu = ipo[Blender.Ipo.PO_QUATY]
+ try: cu.delBezier(0)
+ except: pass
+ cu.driver = 2 # Python expression
+ cu.driverExpression = '%.3f*(%s.evaluate((%.3f,(b.Get("curframe")*%.3f)+%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_offset.x, anim_speed_final, anim_offset.y, anim_offset.z)
+
+ cu = ipo[Blender.Ipo.PO_QUATZ]
+ try: cu.delBezier(0)
+ except: pass
+ cu.driver = 2 # Python expression
+ cu.driverExpression = '%.3f*(%s.evaluate((%.3f,%.3f,(b.Get("curframe")*%.3f)+%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_offset.x, anim_offset.y, anim_speed_final, anim_offset.z)
+
+xyzup = Vector(1,1,1).normalize()
+xup = Vector(1,0,0)
+yup = Vector(0,1,0)
+zup = Vector(0,0,1)
+
+class bpoint_bone:
+ def __init__(self):
+ self.name = None
+ self.editbone = None
+ self.blenbone = None
+ self.posebone = None
+
+class bpoint(object):
+ ''' The point in the middle of the branch, not the mesh points
+ '''
+ __slots__ = 'branch', 'co', 'no', 'radius', 'vecs', 'verts', 'children', 'faces', 'uv', 'next', 'prev', 'childCount', 'bpbone', 'roll_angle', 'nextMidCo', 'childrenMidCo', 'childrenMidRadius', 'targetCos', 'inTwigBounds'
+ def __init__(self, brch, co, no, radius):
+ self.branch = brch
+ self.co = co
+ self.no = no
+ self.radius = radius
+ self.vecs = [None, None, None, None] # 4 for now
+ self.verts = [None, None, None, None]
+ self.children = [None, None, None, None] # child branches, dont fill in faces here
+ self.faces = [None, None, None, None]
+ self.uv = None # matching faces, except - UV's are calculated even if there is no face, this is so we can calculate the blending UV's
+ self.next = None
+ self.prev = None
+ self.childCount = 0
+ self.bpbone = None # bpoint_bone instance
+
+ # when set, This is the angle we need to roll to best face our branches
+ # the roll that is set may be interpolated if we are between 2 branches that need to roll.
+ # Set to None means that the roll will be left default (from parent)
+ self.roll_angle = None
+
+
+ # The location between this and the next point,
+ # if we want to be tricky we can try make this not just a simple
+ # inbetween and use the normals to have some curvature
+ self.nextMidCo = None
+
+ # Similar to above, median point of all children
+ self.childrenMidCo = None
+
+ # Similar as above, but for radius
+ self.childrenMidRadius = None
+
+ # Target locations are used when you want to move the point to a new location but there are
+ # more then 1 influence, build up a list and then apply
+ self.targetCos = []
+
+ # When we use twig bounding mesh, store if this point is in the bounding mesh. Assume true unless we set to false and do the test
+ self.inTwigBounds = True
+
+ def __repr__(self):
+ s = ''
+ s += '\t\tco:', self.co
+ s += '\t\tno:', self.no
+ s += '\t\tradius:', self.radius
+ s += '\t\tchildren:', [(child != False) for child in self.children]
+ return s
+
+ def makeLast(self):
+ self.next = None
+ self.nextMidCo = None
+ self.childrenMidCo = None
+
+ def setCo(self, co):
+ self.co[:] = co
+ self.calcNextMidCo()
+ self.calcNormal()
+
+ if self.prev:
+ self.prev.calcNextMidCo()
+ self.prev.calcNormal()
+ self.prev.calcChildrenMidData()
+
+ if self.next:
+ self.prev.calcNormal()
+
+ self.calcChildrenMidData()
+
+
+ def nextLength(self):
+ return (self.co-self.next.co).length
+ def prevLength(self):
+ return (self.co-self.prev.co).length
+
+ def hasOverlapError(self):
+ if self.prev == None:
+ return False
+ if self.next == None:
+ return False
+ '''
+ # see if this point sits on the line between its siblings.
+ co, fac = ClosestPointOnLine(self.co, self.prev.co, self.next.co)
+
+ if fac >= 0.0 and fac <= 1.0:
+ return False # no overlap, we are good
+ else:
+ return True # error, some overlap
+ '''
+
+
+ # Alternate method, maybe better
+ ln = self.nextLength()
+ lp = self.prevLength()
+ ls = (self.prev.co-self.next.co).length
+
+ # Are we overlapping? the length from our next or prev is longer then the next-TO-previous?
+ if ln>ls or lp>ls:
+ return True
+ else:
+ return False
+
+
+ def applyTargetLocation(self):
+ if not self.targetCos:
+ return False
+ elif len(self.targetCos) == 1:
+ co_all = self.targetCos[0]
+ else:
+ co_all = Vector()
+ for co in self.targetCos:
+ co_all += co
+ co_all = co_all / len(self.targetCos)
+
+ self.targetCos[:] = []
+
+ length = (self.co-co_all).length
+ # work out if we are moving up or down
+ if AngleBetweenVecsSafe(self.no, self.co - co_all) < 90:
+
+ # Up
+ while length > (self.co-self.prev.co).length:
+ if not self.collapseUp():
+ break
+
+ else:
+ # Down
+ while length*2 > (self.co-self.next.co).length:
+ if not self.collapseDown():
+ break
+
+ self.setCo(co_all)
+
+ return True
+
+ def calcNextMidCo(self):
+ if not self.next:
+ return None
+
+ # be tricky later.
+ self.nextMidCo = (self.co + self.next.co) * 0.5
+
+ def calcNormal(self):
+ if self.prev == None:
+ self.no = (self.next.co - self.co).normalize()
+ elif self.next == None:
+ self.no = (self.co - self.prev.co).normalize()
+ else:
+ self.no = (self.next.co - self.prev.co).normalize()
+
+ def calcChildrenMidData(self):
+ '''
+ Calculate childrenMidCo & childrenMidRadius
+ This is a bit tricky, we need to find a point between this and the next,
+ the medium of all children, this point will be on the line between this and the next.
+ '''
+ if not self.next:
+ return None
+
+ # factor between this and the next point
+ radius = factor = factor_i = 0.0
+
+ count = 0
+ for brch in self.children:
+ if brch: # we dont need the co at teh moment.
+ co, fac = ClosestPointOnLine(brch.bpoints[0].co, self.co, self.next.co)
+ factor_i += fac
+ count += 1
+
+ radius += brch.bpoints[0].radius
+
+ if not count:
+ return
+
+ # interpolate points
+ factor_i = factor_i/count
+ factor = 1-factor_i
+
+ self.childrenMidCo = (self.co * factor) + (self.next.co * factor_i)
+ self.childrenMidRadius = radius
+
+ #debug_pt(self.childrenMidCo)
+
+ def getAbsVec(self, index):
+ # print self.vecs, index
+ return self.co + self.vecs[index]
+
+ def slide(self, factor):
+ '''
+ Slides the segment up and down using the prev and next points
+ '''
+ self.setCo(self.slideCo(factor))
+
+ def slideCo(self, factor):
+ if self.prev == None or self.next == None or factor==0.0:
+ return
+
+ if factor < 0.0:
+ prev_co = self.prev.co
+ co = self.co
+
+ ofs = co-prev_co
+ ofs.length = abs(factor)
+ self.co - ofs
+
+ return self.co - ofs
+ else:
+ next_co = self.next.co
+ co = self.co
+
+ ofs = co-next_co
+ ofs.length = abs(factor)
+
+ return self.co - ofs
+
+
+ def collapseDown(self):
+ '''
+ Collapse the next point into this one
+ '''
+
+ # self.next.next == None check is so we dont shorten the final length of branches.
+ if self.next == None or self.next.next == None or self.childCount or self.next.childCount:
+ return False
+
+ self.branch.bpoints.remove(self.next)
+ self.next = self.next.next # skip
+ self.next.prev = self
+
+ # Watch this place - must update all data thats needed. roll is not calculaetd yet.
+ self.calcNextMidCo()
+ return True
+
+ def collapseUp(self):
+ '''
+ Collapse the previous point into this one
+ '''
+
+ # self.next.next == None check is so we dont shorten the final length of branches.
+ if self.prev == None or self.prev.prev == None or self.prev.childCount or self.prev.prev.childCount:
+ return False
+
+ self.branch.bpoints.remove(self.prev)
+ self.prev = self.prev.prev # skip
+ self.prev.next = self
+
+ # Watch this place - must update all data thats needed. roll is not calculaetd yet.
+ self.prev.calcNextMidCo()
+ return True
+
+
+ def smooth(self, factor, factor_joint):
+ '''
+ Blend this point into the other 2 points
+ '''
+ if self.next == None or self.prev == None:
+ return False
+
+ if self.childCount or self.prev.childCount:
+ factor = factor_joint;
+
+ if factor==0.0:
+ return False;
+
+ radius = (self.next.radius + self.prev.radius)/2.0
+ no = (self.next.no + self.prev.no).normalize()
+
+ # do a line intersect to work out the best location
+ '''
+ cos = LineIntersect( self.next.co, self.next.co+self.next.no,\
+ self.prev.co, self.prev.co+self.prev.no)
+ if cos == None:
+ co = (self.prev.co + self.next.co)/2.0
+ else:
+ co = (cos[0]+cos[1])/2.0
+ '''
+ # Above can give odd results every now and then
+ co = (self.prev.co + self.next.co)/2.0
+
+ # Now apply
+ factor_i = 1.0-factor
+ self.setCo(self.co*factor_i + co*factor)
+ self.radius = self.radius*factor_i + radius*factor
+
+ return True
+
+ def childPoint(self, index):
+ '''
+ Returns the middle point for any children between this and the next edge
+ '''
+ if self.next == None:
+ raise 'Error'
+
+ if index == 0: return (self.getAbsVec(0) + self.next.getAbsVec(1)) / 2
+ if index == 1: return (self.getAbsVec(1) + self.next.getAbsVec(2)) / 2
+ if index == 2: return (self.getAbsVec(2) + self.next.getAbsVec(3)) / 2
+ if index == 3: return (self.getAbsVec(3) + self.next.getAbsVec(0)) / 2
+
+ def childPointUnused(self, index):
+ '''
+ Same as above but return None when the point is alredy used.
+ '''
+ if self.children[index]:
+ return None
+ return self.childPoint(index)
+
+
+ def roll(self, angle):
+ '''
+ Roll the quad about its normal
+ use for aurienting the sides of a quad to meet a branch that stems from here...
+ '''
+
+ mat = RotationMatrix(angle, 3, 'r', self.no)
+ for i in xrange(4):
+ self.vecs[i] = self.vecs[i] * mat
+
+
+ def toMesh(self, mesh):
+ self.verts[0].co = self.getAbsVec(0)
+ self.verts[1].co = self.getAbsVec(1)
+ self.verts[2].co = self.getAbsVec(2)
+ self.verts[3].co = self.getAbsVec(3)
+
+ if not self.next:
+ return
+
+ if self.prev == None and self.branch.parent_pt:
+ # join from parent branch
+
+ # which side are we of the parents quad
+ index = self.branch.parent_pt.children.index(self.branch)
+
+ # collect the points we are to merge into between the parent its next point
+ if index==0: verts = [self.branch.parent_pt.verts[0], self.branch.parent_pt.verts[1], self.branch.parent_pt.next.verts[1], self.branch.parent_pt.next.verts[0]]
+ if index==1: verts = [self.branch.parent_pt.verts[1], self.branch.parent_pt.verts[2], self.branch.parent_pt.next.verts[2], self.branch.parent_pt.next.verts[1]]
+ if index==2: verts = [self.branch.parent_pt.verts[2], self.branch.parent_pt.verts[3], self.branch.parent_pt.next.verts[3], self.branch.parent_pt.next.verts[2]]
+ if index==3: verts = [self.branch.parent_pt.verts[3], self.branch.parent_pt.verts[0], self.branch.parent_pt.next.verts[0], self.branch.parent_pt.next.verts[3]]
+
+
+ # Watchout for overlapping faces!
+ self.branch.faces[:] =\
+ [verts[0], verts[1], self.verts[1], self.verts[0]],\
+ [verts[1], verts[2], self.verts[2], self.verts[1]],\
+ [verts[2], verts[3], self.verts[3], self.verts[2]],\
+ [verts[3], verts[0], self.verts[0], self.verts[3]]
+
+ # normal join, parents or no parents
+ if not self.children[0]: self.faces[0] = [self.verts[0], self.verts[1], self.next.verts[1], self.next.verts[0]]
+ if not self.children[1]: self.faces[1] = [self.verts[1], self.verts[2], self.next.verts[2], self.next.verts[1]]
+ if not self.children[2]: self.faces[2] = [self.verts[2], self.verts[3], self.next.verts[3], self.next.verts[2]]
+ if not self.children[3]: self.faces[3] = [self.verts[3], self.verts[0], self.next.verts[0], self.next.verts[3]]
+
+ def calcVerts(self):
+ if self.prev == None:
+ if self.branch.parent_pt:
+ cross = CrossVecs(self.no, self.branch.getParentFaceCent() - self.branch.parent_pt.getAbsVec( self.branch.getParentQuadIndex() ))
+ else:
+ # parentless branch - for best results get a cross thats not the same as the normal, in rare cases this happens.
+
+ # Was just doing
+ # cross = zup
+ # which works most of the time, but no verticle lines
+
+ if AngleBetweenVecsSafe(self.no, zup) > 1.0: cross = zup
+ elif AngleBetweenVecsSafe(self.no, yup) > 1.0: cross = yup
+ else: cross = xup
+
+ else:
+ cross = CrossVecs(self.prev.vecs[0], self.no)
+
+ self.vecs[0] = Blender.Mathutils.CrossVecs(self.no, cross)
+ self.vecs[0].length = abs(self.radius)
+ mat = RotationMatrix(90, 3, 'r', self.no)
+ self.vecs[1] = self.vecs[0] * mat
+ self.vecs[2] = self.vecs[1] * mat
+ self.vecs[3] = self.vecs[2] * mat
+
+ def hasChildren(self):
+ '''
+ Use .childCount where possible, this does the real check
+ '''
+ if self.children.count(None) == 4:
+ return False
+ else:
+ return True
+
+class branch:
+ def __init__(self):
+ self.bpoints = []
+ self.parent_pt = None
+ self.tag = False # have we calculated our points
+ self.face_cap = None
+ self.length = -1
+ # self.totchildren = 0
+ # Bones per branch
+ self.faces = [None, None, None, None]
+ self.uv = None # face uvs can be fake, always 4
+ self.bones = []
+ self.generation = 0 # use to limit twig reproduction
+ self.twig_count = 0 # count the number of twigs - so as to limit how many twigs a branch gets
+ # self.myindex = -1
+ ### self.segment_spacing_scale = 1.0 # use this to scale up the spacing - so small twigs dont get WAY too many polys
+ self.type = None
+
+ def __repr__(self):
+ s = ''
+ s += '\tbranch'
+ s += '\tbpoints:', len(self.bpoints)
+ for pt in brch.bpoints:
+ s += str(self.pt)
+
+ def getNormal(self):
+ return (self.bpoints[-1].co - self.bpoints[0].co).normalize()
+
+ def getParentAngle(self):
+ if self.parent_pt:
+ return AngleBetweenVecsSafe(self.parent_pt.no, self.bpoints[0].no )
+ else:
+ return 45.0
+
+ def getParentRadiusRatio(self):
+ if self.parent_pt:
+ return self.bpoints[0].radius / self.parent_pt.radius
+ else:
+ return 0.8
+
+ def getLength(self):
+ return (self.bpoints[0].co - self.bpoints[-1].co).length
+
+ def getStraightness(self):
+ straight = 0.0
+ pt = self.bpoints[0]
+ while pt.next:
+ straight += AngleBetweenVecsSafe(pt.no, pt.next.no)
+ pt = pt.next
+ return straight
+
+
+ '''
+ def calcTotChildren(self):
+ for pt in self.bpoints:
+ self.totchildren += pt.childCount
+ '''
+ def calcData(self):
+ '''
+ Finalize once point data is there
+ '''
+ self.calcPointLinkedList()
+ self.calcPointExtras()
+
+ def calcPointLinkedList(self):
+ for i in xrange(1, len(self.bpoints)-1):
+ self.bpoints[i].next = self.bpoints[i+1]
+ self.bpoints[i].prev = self.bpoints[i-1]
+
+ self.bpoints[0].next = self.bpoints[1]
+ self.bpoints[-1].prev = self.bpoints[-2]
+
+ def calcPointExtras(self):
+ '''
+ Run on a new branch or after transforming an existing one.
+ '''
+ for pt in self.bpoints:
+ pt.calcNormal()
+ pt.calcNextMidCo()
+
+ def calcTwigBounds(self, tree):
+ '''
+ Check if out points are
+ '''
+ for pt in self.bpoints:
+ pt.inTwigBounds = tree.isPointInTwigBounds(pt.co)
+ #if pt.inTwigBounds:
+ # debug_pt(pt.co)
+
+ def baseTrim(self, connect_base_trim):
+ # if 1) dont remove the whole branch, maybe an option but later
+ # if 2) we are alredy a parent, cant remove me now.... darn :/ not nice...
+ # could do this properly but it would be slower and its a corner case.
+ #
+ # if 3) this point is within the branch, remove it.
+ # Scale this value by the difference in radius, a low trim looks better when the parent is a lot bigger..
+ #
+
+ while len(self.bpoints)>2 and\
+ self.bpoints[0].childCount == 0 and\
+ (self.parent_pt.nextMidCo - self.bpoints[0].co).length < ((self.parent_pt.radius + self.parent_pt.next.radius)/4) + (self.bpoints[0].radius * connect_base_trim):
+ # Note /4 - is a bit odd, since /2 is correct, but /4 lets us have more tight joints by default
+
+
+ del self.bpoints[0]
+ self.bpoints[0].prev = None
+
+ def boundsTrim(self):
+ '''
+ depends on calcTwigBounds running first. - also assumes no children assigned yet! make sure this is always the case.
+ '''
+ trim = False
+ for i, pt in enumerate(self.bpoints):
+ if not pt.inTwigBounds:
+ trim = True
+ break
+
+ # We must have at least 2 points to be a valid branch. this will be a stump :/
+ if not trim or i < 3:
+ self.bpoints = [] #
+ return
+
+ # Shorten the point list
+ self.bpoints = self.bpoints[:i]
+ self.bpoints[-1].makeLast()
+
+ def taper(self, twig_ob_bounds_prune_taper = 0.0):
+ l = float(len( self.bpoints ))
+ for i, pt in enumerate(self.bpoints):
+ pt.radius *= (((l-i)/l) + (twig_ob_bounds_prune_taper*(i/l)) )
+
+ def getParentBranch(self):
+ if not self.parent_pt:
+ return None
+ return self.parent_pt.branch
+
+ def getParentQuadAngle(self):
+ '''
+ The angle off we are from our parent quad,
+ '''
+ # used to roll the parent so its faces us better
+
+ # Warning this can be zero sometimes, see the try below for the error
+ parent_normal = self.getParentFaceCent() - self.parent_pt.nextMidCo
+
+
+ self_normal = self.bpoints[1].co - self.parent_pt.co
+ # We only want the angle in relation to the parent points normal
+ # modify self_normal to make this so
+ cross = CrossVecs(self_normal, self.parent_pt.no)
+ self_normal = CrossVecs(self.parent_pt.no, cross) # CHECK
+
+ #try: angle = AngleBetweenVecs(parent_normal, self_normal)
+ #except: return 0.0
+ angle = AngleBetweenVecsSafe(parent_normal, self_normal)
+
+
+ # see if we need to rotate positive or negative
+ # USE DOT PRODUCT!
+ cross = CrossVecs(parent_normal, self_normal)
+ if AngleBetweenVecsSafe(cross, self.parent_pt.no) > 90:
+ angle = -angle
+
+ return angle
+
+ def getParentQuadIndex(self):
+ return self.parent_pt.children.index(self)
+ def getParentFaceCent(self):
+ return self.parent_pt.childPoint( self.getParentQuadIndex() )
+
+ def findClosest(self, co):
+ '''
+ Find the closest point that can bare a child
+ '''
+
+
+ ''' # this dosnt work, but could.
+ best = None
+ best_dist = 100000000
+ for pt in self.bpoints:
+ if pt.next:
+ co_on_line, fac = ClosestPointOnLine(co, pt.co, pt.next.co)
+ print fac
+ if fac >= 0.0 and fac <= 1.0:
+ return pt, (co-co_on_line).length
+
+ return best, best_dist
+ '''
+ best = None
+ best_dist = 100000000
+ for pt in self.bpoints:
+ if pt.nextMidCo and pt.childCount < 4:
+ dist = (pt.nextMidCo-co).length
+ if dist < best_dist:
+ best = pt
+ best_dist = dist
+
+ return best, best_dist
+
+ def inParentChain(self, brch):
+ '''
+ See if this branch is a parent of self or in the chain
+ '''
+
+ self_parent_lookup = self.getParentBranch()
+ while self_parent_lookup:
+ if self_parent_lookup == brch:
+ return True
+ self_parent_lookup = self_parent_lookup.getParentBranch()
+
+ return False
+
+ def transform(self, mat, loc=None, scale=None):
+ if scale==None:
+ scale = (xyzup * mat).length
+
+ for pt in self.bpoints:
+ if loc:
+ pt.co = (pt.co * mat) + loc
+ else:
+ pt.co = pt.co * mat
+ pt.radius *= scale
+
+ for pt in self.bpoints:
+ self.calcPointExtras()
+
+ def translate(self, co):
+ '''
+ Simply move the twig on the branch
+ '''
+ ofs = self.bpoints[0].co-co
+ for pt in self.bpoints:
+ pt.co -= ofs
+
+ def transformRecursive(self, tree, mat3x3, cent, scale=None):
+
+ if scale==None:
+ # incase this is a translation matrix
+ scale = ((xyzup * mat3x3) - (Vector(0,0,0) * mat3x3)).length
+
+ for pt in self.bpoints: pt.co = ((pt.co-cent) * mat3x3) + cent
+ #for pt in self.bpoints: pt.co = (pt.co * mat3x3)
+ for pt in self.bpoints: self.calcPointExtras()
+
+
+ for brch in tree.branches_all:
+ if brch.parent_pt:
+ if brch.parent_pt.branch == self:
+
+ brch.transformRecursive(tree, mat3x3, cent, scale)
+
+ '''
+ for pt in self.bpoints:
+ for brch in pt.children:
+ if brch:
+ brch.transformRecursive(mat3x3, cent, scale)
+ '''
+ def bestTwigSegment(self):
+ '''
+ Return the most free part on the branch to place a new twig
+ return (sort_value, best_index, self)
+ '''
+
+ # loop up and down the branch - counding how far from the last parent segment we are
+ spacing1 = [0] * (len(self.bpoints)-1)
+ spacing2 = spacing1[:]
+
+ step_from_parent = 0
+ for i in xrange(len(spacing1)): # -1 because the last pt cant have kits
+
+ if self.bpoints[i].childCount or self.bpoints[i].inTwigBounds==False:
+ step_from_parent = 0
+ else:
+ step_from_parent += 1
+
+ spacing1[i] += step_from_parent # -1 because the last pt cant have kits
+
+ best_index = -1
+ best_val = -1
+ step_from_parent = 0
+ for i in xrange(len(spacing1)-1, -1, -1):
+
+ if self.bpoints[i].childCount or self.bpoints[i].inTwigBounds==False:
+ step_from_parent = 0
+ else:
+ step_from_parent += 1
+
+ spacing2[i] += step_from_parent
+
+ # inTwigBounds is true by default, when twigBounds are used it can be false
+ if self.bpoints[i].childCount < 4 and self.bpoints[i].inTwigBounds:
+ # Dont allow to assign more verts then 4
+ val = spacing1[i] * spacing2[i]
+ if val > best_val:
+ best_val = val
+ best_index = i
+
+ #if best_index == -1:
+ # raise "Error"
+
+ # This value is only used for sorting, so the lower the value - the sooner it gets a twig.
+ #sort_val = -best_val + (1/self.getLength())
+ sort_val=self.getLength()
+
+ return sort_val, best_index, self
+
+ def evenPointDistrobution(self, factor=1.0, factor_joint=1.0):
+ '''
+ Redistribute points that are not evenly distributed
+ factor is between 0.0 and 1.0
+ '''
+
+ for pt in self.bpoints:
+ if pt.next and pt.prev and pt.childCount == 0 and pt.prev.childCount == 0:
+ w1 = pt.nextLength()
+ w2 = pt.prevLength()
+ wtot = w1+w2
+ if wtot > 0.0:
+ w1=w1/wtot
+ #w2=w2/wtot
+ w1 = abs(w1-0.5)*2 # make this from 0.0 to 1.0, where 0 is the middle and 1.0 is as far out of the middle as possible.
+ # print "%.6f" % w1
+ pt.smooth(w1*factor, w1*factor_joint)
+
+ def fixOverlapError(self, joint_smooth=1.0):
+ # Keep fixing until no hasOverlapError left to fix.
+
+ error = True
+ while error:
+ error = False
+ for pt in self.bpoints:
+ if pt.prev and pt.next:
+ if pt.hasOverlapError():
+ if pt.smooth(1.0, joint_smooth): # if we cant fix then dont bother trying again.
+ error = True
+
+ def evenJointDistrobution(self, joint_compression = 1.0):
+ # See if we need to evaluate this branch at all
+ if len(self.bpoints) <= 2: # Rare but in this case we cant do anything
+ return
+ has_children = False
+ for pt in self.bpoints:
+ if pt.childCount:
+ has_children = True
+ break
+
+ if not has_children:
+ return
+
+ # OK, we have children, so we have some work to do...
+ # center each segment
+
+ # work out the median location of all points children.
+ for pt in self.bpoints:
+ pt.calcChildrenMidData()
+ pt.targetCos[:] = []
+
+ for pt in self.bpoints:
+
+ if pt.childrenMidCo:
+ # Move this and the next segment to be around the child point.
+ # TODO - factor in the branch angle, be careful with this - close angles can have extreme values.
+ slide_dist = (pt.childrenMidCo - pt.co).length - (pt.childrenMidRadius * joint_compression)
+ co = pt.slideCo( slide_dist )
+ if co:
+ pt.targetCos.append( co )
+
+ slide_dist = (pt.childrenMidRadius * joint_compression) - (pt.childrenMidCo - pt.next.co).length
+ co = pt.next.slideCo( slide_dist )
+ if co:
+ pt.next.targetCos.append( co )
+
+ for pt in reversed(self.bpoints):
+ pt.applyTargetLocation()
+
+ def collapsePoints(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, smooth_joint=1.0):
+
+ collapse = True
+ while collapse:
+ collapse = False
+ pt = self.bpoints[0]
+ while pt:
+ # Collapse angles greater then 90. they are useually artifacts
+
+ if pt.prev and pt.next and pt.prev.childCount == 0:
+ if (pt.radius + pt.prev.radius) != 0.0 and abs(pt.radius - pt.prev.radius) / (pt.radius + pt.prev.radius) < seg_density_radius:
+ ang = AngleBetweenVecsSafe(pt.no, pt.prev.no)
+ if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle:
+ ## if (pt.prev.nextMidCo-pt.co).length < ((pt.radius + pt.prev.radius)/2) * seg_density:
+ if (pt.prev.nextMidCo-pt.co).length < seg_density or ang > 90:
+ pt_save = pt.prev
+ if pt.next.collapseUp(): # collapse this point
+ collapse = True
+ pt = pt_save # so we never reference a removed point
+
+ if pt.childCount == 0 and pt.next: #if pt.childrenMidCo == None:
+ if (pt.radius + pt.next.radius) != 0.0 and abs(pt.radius - pt.next.radius) / (pt.radius + pt.next.radius) < seg_density_radius:
+ ang = AngleBetweenVecsSafe(pt.no, pt.next.no)
+ if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle:
+ # do here because we only want to run this on points with no children,
+ # Are we closer theto eachother then the radius?
+ ## if (pt.nextMidCo-pt.co).length < ((pt.radius + pt.next.radius)/2) * seg_density:
+ if (pt.nextMidCo-pt.co).length < seg_density or ang > 90:
+ if pt.collapseDown():
+ collapse = True
+
+ pt = pt.next
+ ## self.checkPointList()
+ self.evenPointDistrobution(1.0, smooth_joint)
+
+ for pt in self.bpoints:
+ pt.calcNormal()
+ pt.calcNextMidCo()
+
+ # This is a bit dodgy - moving the branches around after placing can cause problems
+ """
+ def branchReJoin(self):
+ '''
+ Not needed but nice to run after collapsing incase segments moved a lot
+ '''
+ if not self.parent_pt:
+ return # nothing to do
+
+ # see if the next segment is closer now (after collapsing)
+ parent_pt = self.parent_pt
+ root_pt = self.bpoints[0]
+
+ #try:
+ index = parent_pt.children.index(self)
+ #except:
+ #print "This is bad!, but not being able to re-join isnt that big a deal"
+
+ current_dist = (parent_pt.nextMidCo - root_pt.co).length
+
+ # TODO - Check size of new area is ok to move into
+
+ if parent_pt.next and parent_pt.next.next and parent_pt.next.children[index] == None:
+ # We can go here if we want, see if its better
+ if current_dist > (parent_pt.next.nextMidCo - root_pt.co).length:
+ self.parent_pt.children[index] = None
+ self.parent_pt.childCount -= 1
+
+ self.parent_pt = parent_pt.next
+ self.parent_pt.children[index] = self
+ self.parent_pt.childCount += 1
+ return
+
+ if parent_pt.prev and parent_pt.prev.children[index] == None:
+ # We can go here if we want, see if its better
+ if current_dist > (parent_pt.prev.nextMidCo - root_pt.co).length:
+ self.parent_pt.children[index] = None
+ self.parent_pt.childCount -= 1
+
+ self.parent_pt = parent_pt.prev
+ self.parent_pt.children[index] = self
+ self.parent_pt.childCount += 1
+ return
+ """
+
+ def checkPointList(self):
+ '''
+ Error checking. use to check if collapsing worked.
+ '''
+ p_link = self.bpoints[0]
+ i = 0
+ while p_link:
+ if self.bpoints[i] != p_link:
+ raise "Error"
+
+ if p_link.prev and p_link.prev != self.bpoints[i-1]:
+ raise "Error Prev"
+
+ if p_link.next and p_link.next != self.bpoints[i+1]:
+ raise "Error Next"
+
+ p_link = p_link.next
+ i+=1
+
+ def mixToNew(self, other, BLEND_MODE):
+ '''
+ Generate a new branch based on 2 existing ones
+ These branches will point 'zup' - aurient 'xup' and have a tip length of 1.0
+ '''
+
+ # Lets be lazy! - if the branches are different sizes- use the shortest.
+ # brch1 is always smaller
+
+ brch1 = self
+ brch2 = other
+ if len(brch1.bpoints) > len(brch2.bpoints):
+ brch1, brch2 = brch2, brch1
+
+ if len(brch1.bpoints) == 1:
+ return None
+
+ co_start = brch1.bpoints[0].co
+ cos1 = [ pt.co - co_start for pt in brch1.bpoints ]
+
+ co_start = brch2.bpoints[0].co
+ if len(brch1.bpoints) == len(brch2.bpoints):
+ cos2 = [ pt.co - co_start for pt in brch2.bpoints ]
+ else: # truncate the points
+ cos2 = [ brch2.bpoints[i].co - co_start for i in xrange(len(brch1.bpoints)) ]
+
+ scales = []
+ for cos_ls in (cos1, cos2):
+ cross = CrossVecs(cos_ls[-1], zup)
+ mat = RotationMatrix(AngleBetweenVecsSafe(cos_ls[-1], zup), 3, 'r', cross)
+ cos_ls[:] = [co*mat for co in cos_ls]
+
+ # point z-up
+
+ # Now they are both pointing the same way aurient the curves to be rotated the same way
+ xy_nor = Vector(0,0,0)
+ for co in cos_ls:
+ xy_nor.x += co.x
+ xy_nor.y += co.y
+ cross = CrossVecs(xy_nor, xup)
+
+ # Also scale them here so they are 1.0 tall always
+ scale = 1.0/(cos_ls[0]-cos_ls[-1]).length
+ mat = RotationMatrix(AngleBetweenVecsSafe(xy_nor, xup), 3, 'r', cross) * Matrix([scale,0,0],[0,scale,0],[0,0,scale])
+ cos_ls[:] = [co*mat for co in cos_ls]
+
+ scales.append(scale)
+
+ # Make the new branch
+ new_brch = branch()
+ new_brch.type = BRANCH_TYPE_GROWN
+ for i in xrange(len(cos1)):
+ new_brch.bpoints.append( bpoint(new_brch, (cos1[i]+cos2[i])*0.5, Vector(), (brch1.bpoints[i].radius*scales[0] + brch2.bpoints[i].radius*scales[1])/2) )
+
+ new_brch.calcData()
+ return new_brch
+
+ '''
+ def toMesh(self):
+ pass
+ '''
+
+
+
+
+# No GUI code above this! ------------------------------------------------------
+
+# PREFS - These can be saved on the object's id property. use 'tree2curve' slot
+from Blender import Draw
+import BPyWindow
+ID_SLOT_NAME = 'Curve2Tree'
+
+EVENT_NONE = 0
+EVENT_EXIT = 1
+EVENT_UPDATE = 2
+EVENT_UPDATE_AND_UI = 2
+EVENT_REDRAW = 3
+
+
+# Prefs for each tree
+PREFS = {}
+PREFS['connect_sloppy'] = Draw.Create(1.0)
+PREFS['connect_base_trim'] = Draw.Create(1.0)
+PREFS['seg_density'] = Draw.Create(0.5)
+PREFS['seg_density_angle'] = Draw.Create(20.0)
+PREFS['seg_density_radius'] = Draw.Create(0.3)
+PREFS['seg_joint_compression'] = Draw.Create(1.0)
+PREFS['seg_joint_smooth'] = Draw.Create(2.0)
+PREFS['image_main'] = Draw.Create('')
+PREFS['do_uv'] = Draw.Create(0)
+PREFS['uv_x_scale'] = Draw.Create(4.0)
+PREFS['uv_y_scale'] = Draw.Create(1.0)
+PREFS['do_material'] = Draw.Create(0)
+PREFS['material_use_existing'] = Draw.Create(1)
+PREFS['material_texture'] = Draw.Create(1)
+PREFS['material_stencil'] = Draw.Create(1)
+PREFS['do_subsurf'] = Draw.Create(1)
+PREFS['do_cap_ends'] = Draw.Create(0)
+PREFS['do_uv_keep_vproportion'] = Draw.Create(1)
+PREFS['do_uv_vnormalize'] = Draw.Create(0)
+PREFS['do_uv_uscale'] = Draw.Create(0)
+PREFS['do_armature'] = Draw.Create(0)
+PREFS['do_anim'] = Draw.Create(1)
+try: PREFS['anim_tex'] = Draw.Create([tex for tex in bpy.data.textures][0].name)
+except: PREFS['anim_tex'] = Draw.Create('')
+
+PREFS['anim_speed'] = Draw.Create(0.2)
+PREFS['anim_magnitude'] = Draw.Create(0.2)
+PREFS['anim_speed_size_scale'] = Draw.Create(1)
+PREFS['anim_offset_scale'] = Draw.Create(1.0)
+
+PREFS['do_twigs_fill'] = Draw.Create(0)
+PREFS['twig_fill_levels'] = Draw.Create(4)
+
+PREFS['twig_fill_rand_scale'] = Draw.Create(0.1)
+PREFS['twig_fill_fork_angle_max'] = Draw.Create(180.0)
+PREFS['twig_fill_radius_min'] = Draw.Create(0.001)
+PREFS['twig_fill_radius_factor'] = Draw.Create(0.75)
+PREFS['twig_fill_shape_type'] = Draw.Create(1)
+PREFS['twig_fill_shape_rand'] = Draw.Create(0.5)
+PREFS['twig_fill_shape_power'] = Draw.Create(0.5)
+
+PREFS['do_twigs'] = Draw.Create(0)
+PREFS['twig_ratio'] = Draw.Create(2.0)
+PREFS['twig_select_mode'] = Draw.Create(0)
+PREFS['twig_select_factor'] = Draw.Create(0.5)
+PREFS['twig_scale'] = Draw.Create(0.8)
+PREFS['twig_scale_width'] = Draw.Create(1.0)
+PREFS['twig_random_orientation'] = Draw.Create(180)
+PREFS['twig_random_angle'] = Draw.Create(33)
+PREFS['twig_recursive'] = Draw.Create(1)
+PREFS['twig_recursive_limit'] = Draw.Create(3)
+PREFS['twig_ob_bounds'] = Draw.Create('') # WATCH out, used for do_twigs_fill AND do_twigs
+PREFS['twig_ob_bounds_prune'] = Draw.Create(1)
+PREFS['twig_ob_bounds_prune_taper'] = Draw.Create(1.0)
+PREFS['twig_placement_maxradius'] = Draw.Create(10.0)
+PREFS['twig_placement_maxtwig'] = Draw.Create(4)
+PREFS['twig_follow_parent'] = Draw.Create(0.0)
+PREFS['twig_follow_x'] = Draw.Create(0.0)
+PREFS['twig_follow_y'] = Draw.Create(0.0)
+PREFS['twig_follow_z'] = Draw.Create(0.0)
+
+PREFS['do_leaf'] = Draw.Create(0)
+
+PREFS['leaf_branch_limit'] = Draw.Create(0.25)
+PREFS['leaf_branch_limit_rand'] = Draw.Create(0.1)
+PREFS['leaf_branch_density'] = Draw.Create(0.1)
+PREFS['leaf_branch_pitch_angle'] = Draw.Create(0.0)
+PREFS['leaf_branch_pitch_rand'] = Draw.Create(0.2)
+PREFS['leaf_branch_roll_rand'] = Draw.Create(0.2)
+PREFS['leaf_branch_angle'] = Draw.Create(75.0)
+PREFS['leaf_rand_seed'] = Draw.Create(1.0)
+PREFS['leaf_size'] = Draw.Create(0.5)
+PREFS['leaf_size_rand'] = Draw.Create(0.5)
+
+PREFS['leaf_object'] = Draw.Create('')
+
+PREFS['do_variation'] = Draw.Create(0)
+PREFS['variation_seed'] = Draw.Create(1)
+PREFS['variation_orientation'] = Draw.Create(0.0)
+PREFS['variation_scale'] = Draw.Create(0.0)
+
+GLOBAL_PREFS = {}
+GLOBAL_PREFS['realtime_update'] = Draw.Create(0)
+
+
+def getContextCurveObjects():
+ sce = bpy.data.scenes.active
+ objects = []
+ ob_act = sce.objects.active
+ for ob in sce.objects.context:
+ if ob == ob_act: ob_act = None
+
+ if ob.type != 'Curve':
+ ob = ob.parent
+ if not ob or ob.type != 'Curve':
+ continue
+ objects.append(ob)
+
+ # Alredy delt with
+
+
+ # Add the active, important when using localview or local layers
+ if ob_act:
+ ob = ob_act
+ if ob.type != 'Curve':
+ ob = ob.parent
+ if not ob or ob.type != 'Curve':
+ pass
+ else:
+ objects.append(ob)
+
+ return objects
+
+
+def Prefs2Dict(prefs, new_prefs):
+ '''
+ Make a copy with no button settings
+ '''
+ new_prefs.clear()
+ for key, val in prefs.items():
+ try: new_prefs[key] = val.val
+ except: new_prefs[key] = val
+ return new_prefs
+
+def Dict2Prefs(prefs, new_prefs):
+ '''
+ Make a copy with button settings
+ '''
+ for key in prefs: # items would be nice for id groups
+ val = prefs[key]
+ ok = True
+
+ try:
+ # If we have this setting allredy but its a different type, use the old setting (converting int's to floats for instance)
+ new_val = new_prefs[key] # this may fail, thats ok
+ if (type(new_val)==Blender.Types.ButtonType) and (type(new_val.val) != type(val)):
+ ok = False
+ except:
+ pass
+
+ if ok:
+ try:
+ new_prefs[key] = Blender.Draw.Create( val )
+ except:
+ new_prefs[key] = val
+
+ return new_prefs
+
+def Prefs2IDProp(idprop, prefs):
+ new_prefs = {}
+ Prefs2Dict(prefs, new_prefs)
+ try: del idprop[ID_SLOT_NAME]
+ except: pass
+
+ idprop[ID_SLOT_NAME] = new_prefs
+
+def IDProp2Prefs(idprop, prefs):
+ try:
+ prefs = idprop[ID_SLOT_NAME]
+ except:
+ return False
+ Dict2Prefs(prefs, PREFS)
+ return True
+
+def buildTree(ob_curve, single=False):
+ '''
+ Must be a curve object, write to a child mesh
+ Must check this is a curve object!
+ '''
+ print 'Curve2Tree, starting...'
+ # if were only doing 1 object, just use the current prefs
+ prefs = {}
+
+ if single or not (IDProp2Prefs(ob_curve.properties, prefs)):
+ prefs = PREFS
+
+
+ # Check prefs are ok.
+
+
+ sce = bpy.data.scenes.active
+
+ def getObChild(parent, obtype):
+ try:
+ return [ _ob for _ob in sce.objects if _ob.type == obtype if _ob.parent == parent ][0]
+ except:
+ return None
+
+ def newObChild(parent, obdata):
+
+ ob_new = bpy.data.scenes.active.objects.new(obdata)
+ # ob_new.Layers = parent.Layers
+
+ # new object settings
+ parent.makeParent([ob_new])
+ ob_new.setMatrix(Matrix())
+ ob_new.sel = 0
+ return ob_new
+
+ def hasModifier(modtype):
+ return len([mod for mod in ob_mesh.modifiers if mod.type == modtype]) > 0
+
+
+ sce = bpy.data.scenes.active
+
+ if PREFS['image_main'].val:
+ try: image = bpy.data.images[PREFS['image_main'].val]
+ except: image = None
+ else: image = None
+
+ # Get the mesh child
+
+ print '\treading blenders curves...',
+ time1 = Blender.sys.time()
+
+ t = tree()
+ t.fromCurve(ob_curve)
+ if not t.branches_all:
+ return # Empty curve? - may as well not throw an error
+
+ time2 = Blender.sys.time() # time print
+ """
+ print '%.4f sec' % (time2-time1)
+ if PREFS['do_twigs'].val:
+ print '\tbuilding twigs...',
+ t.buildTwigs(ratio=PREFS['twig_ratio'].val)
+ time3 = Blender.sys.time() # time print
+ print '%.4f sec' % (time3 - time2)
+ """
+ if 0: pass
+ else:
+ time3 = Blender.sys.time() # time print
+
+ print '\tconnecting branches...',
+
+ twig_ob_bounds = getObFromName(PREFS['twig_ob_bounds'].val)
+
+ t.buildConnections(\
+ sloppy = PREFS['connect_sloppy'].val,\
+ connect_base_trim = PREFS['connect_base_trim'].val,\
+ do_twigs = PREFS['do_twigs'].val,\
+ twig_ratio = PREFS['twig_ratio'].val,\
+ twig_select_mode = PREFS['twig_select_mode'].val,\
+ twig_select_factor = PREFS['twig_select_factor'].val,\
+ twig_scale = PREFS['twig_scale'].val,\
+ twig_scale_width = PREFS['twig_scale_width'].val,\
+ twig_random_orientation = PREFS['twig_random_orientation'].val,\
+ twig_random_angle = PREFS['twig_random_angle'].val,\
+ twig_recursive = PREFS['twig_recursive'].val,\
+ twig_recursive_limit = PREFS['twig_recursive_limit'].val,\
+ twig_ob_bounds = twig_ob_bounds,\
+ twig_ob_bounds_prune = PREFS['twig_ob_bounds_prune'].val,\
+ twig_ob_bounds_prune_taper = PREFS['twig_ob_bounds_prune_taper'].val,\
+ twig_placement_maxradius = PREFS['twig_placement_maxradius'].val,\
+ twig_placement_maxtwig = PREFS['twig_placement_maxtwig'].val,\
+ twig_follow_parent = PREFS['twig_follow_parent'].val,\
+ twig_follow_x = PREFS['twig_follow_x'].val,\
+ twig_follow_y = PREFS['twig_follow_y'].val,\
+ twig_follow_z = PREFS['twig_follow_z'].val,\
+ do_variation = PREFS['do_variation'].val,\
+ variation_seed = PREFS['variation_seed'].val,\
+ variation_orientation = PREFS['variation_orientation'].val,\
+ variation_scale = PREFS['variation_scale'].val,\
+ do_twigs_fill = PREFS['do_twigs_fill'].val,\
+ twig_fill_levels = PREFS['twig_fill_levels'].val,\
+ twig_fill_rand_scale = PREFS['twig_fill_rand_scale'].val,\
+ twig_fill_fork_angle_max = PREFS['twig_fill_fork_angle_max'].val,\
+ twig_fill_radius_min = PREFS['twig_fill_radius_min'].val,\
+ twig_fill_radius_factor = PREFS['twig_fill_radius_factor'].val,\
+ twig_fill_shape_type = PREFS['twig_fill_shape_type'].val,\
+ twig_fill_shape_rand = PREFS['twig_fill_shape_rand'].val,\
+ twig_fill_shape_power = PREFS['twig_fill_shape_power'].val,\
+ )
+
+ time4 = Blender.sys.time() # time print
+ print '%.4f sec' % (time4-time3)
+ print '\toptimizing point spacing...',
+
+ t.optimizeSpacing(\
+ seg_density=PREFS['seg_density'].val,\
+ seg_density_angle=PREFS['seg_density_angle'].val,\
+ seg_density_radius=PREFS['seg_density_radius'].val,\
+ joint_compression = PREFS['seg_joint_compression'].val,\
+ joint_smooth = PREFS['seg_joint_smooth'].val\
+ )
+
+ time5 = Blender.sys.time() # time print
+ print '%.4f sec' % (time5-time4)
+ print '\tbuilding mesh...',
+
+ ob_mesh = getObChild(ob_curve, 'Mesh')
+ if not ob_mesh:
+ # New object
+ mesh = bpy.data.meshes.new('tree_' + ob_curve.name)
+ ob_mesh = newObChild(ob_curve, mesh)
+ # do subsurf later
+
+ else:
+ # Existing object
+ mesh = ob_mesh.getData(mesh=1)
+ ob_mesh.setMatrix(Matrix())
+
+ # Do we need a do_uv_blend_layer?
+ if PREFS['do_material'].val and PREFS['material_stencil'].val and PREFS['material_texture'].val:
+ do_uv_blend_layer = True
+ else:
+ do_uv_blend_layer = False
+
+ mesh = t.toMesh(mesh,\
+ do_uv = PREFS['do_uv'].val,\
+ uv_image = image,\
+ do_uv_keep_vproportion = PREFS['do_uv_keep_vproportion'].val,\
+ do_uv_vnormalize = PREFS['do_uv_vnormalize'].val,\
+ do_uv_uscale = PREFS['do_uv_uscale'].val,\
+ uv_x_scale = PREFS['uv_x_scale'].val,\
+ uv_y_scale = PREFS['uv_y_scale'].val,\
+ do_uv_blend_layer = do_uv_blend_layer,\
+ do_cap_ends = PREFS['do_cap_ends'].val
+ )
+
+ if PREFS['do_leaf'].val:
+ ob_leaf_dupliface = getObChild(ob_mesh, 'Mesh')
+ if not ob_leaf_dupliface: # New object
+ mesh_leaf = bpy.data.meshes.new('leaf_' + ob_curve.name)
+ ob_leaf_dupliface = newObChild(ob_mesh, mesh_leaf)
+ else:
+ mesh_leaf = ob_leaf_dupliface.getData(mesh=1)
+ ob_leaf_dupliface.setMatrix(Matrix())
+
+ leaf_object = getObFromName(PREFS['leaf_object'].val)
+
+ mesh_leaf = t.toLeafMesh(mesh_leaf,\
+ leaf_branch_limit = PREFS['leaf_branch_limit'].val,\
+ leaf_branch_limit_rand = PREFS['leaf_branch_limit_rand'].val,\
+ leaf_size = PREFS['leaf_size'].val,\
+ leaf_size_rand = PREFS['leaf_size_rand'].val,\
+ leaf_branch_density = PREFS['leaf_branch_density'].val,\
+ leaf_branch_pitch_angle = PREFS['leaf_branch_pitch_angle'].val,\
+ leaf_branch_pitch_rand = PREFS['leaf_branch_pitch_rand'].val,\
+ leaf_branch_roll_rand = PREFS['leaf_branch_roll_rand'].val,\
+ leaf_branch_angle = PREFS['leaf_branch_angle'].val,\
+ leaf_rand_seed = PREFS['leaf_rand_seed'].val,\
+ leaf_object = leaf_object,\
+ )
+
+ if leaf_object:
+ ob_leaf_dupliface.enableDupFaces = True
+ ob_leaf_dupliface.enableDupFacesScale = True
+ ob_leaf_dupliface.makeParent([leaf_object])
+ else:
+ ob_leaf_dupliface.enableDupFaces = False
+
+ mesh.calcNormals()
+
+ if PREFS['do_material'].val:
+
+ materials = mesh.materials
+ if PREFS['material_use_existing'].val and materials:
+ t.material = materials[0]
+ else:
+ t.material = bpy.data.materials.new(ob_curve.name)
+ mesh.materials = [t.material]
+
+ if PREFS['material_texture'].val:
+
+ # Set up the base image texture
+ t.texBase = bpy.data.textures.new('base_' + ob_curve.name)
+ t.material.setTexture(0, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL)
+ t.texBase.type = Blender.Texture.Types.IMAGE
+ if image:
+ t.texBase.image = image
+ t.texBaseMTex = t.material.getTextures()[0]
+ t.texBaseMTex.uvlayer = 'base'
+
+ if PREFS['material_stencil'].val:
+ # Set up the blend texture
+ t.texBlend = bpy.data.textures.new('blend_' + ob_curve.name)
+ t.material.setTexture(1, t.texBlend, Blender.Texture.TexCo.UV, 0) # map to None
+ t.texBlend.type = Blender.Texture.Types.BLEND
+ t.texBlend.flags |= Blender.Texture.Flags.FLIPBLEND
+ t.texBlendMTex = t.material.getTextures()[1]
+ t.texBlendMTex.stencil = True
+ t.texBlendMTex.uvlayer = 'blend'
+
+
+ # Now make the texture for the stencil to blend, can reuse texBase here, jus tdifferent settings for the mtex
+ t.material.setTexture(2, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL)
+ t.texJoinMTex = t.material.getTextures()[2]
+ t.texJoinMTex.uvlayer = 'join'
+
+ # Add a UV layer for blending
+
+
+
+
+ time6 = Blender.sys.time() # time print
+ print '%.4f sec' % (time6-time5)
+
+ # Do armature stuff....
+ if PREFS['do_armature'].val:
+
+ print '\tbuilding armature & animation...',
+
+ ob_arm = getObChild(ob_curve, 'Armature')
+ if ob_arm:
+ armature = ob_arm.data
+ ob_arm.setMatrix(Matrix())
+ else:
+ armature = bpy.data.armatures.new()
+ ob_arm = newObChild(ob_curve, armature)
+
+ t.toArmature(ob_arm, armature)
+
+ # Add the modifier.
+ if not hasModifier(Blender.Modifier.Types.ARMATURE):
+ mod = ob_mesh.modifiers.append(Blender.Modifier.Types.ARMATURE)
+
+ # TODO - assigne object anyway, even if an existing modifier exists.
+ mod[Blender.Modifier.Settings.OBJECT] = ob_arm
+
+ if PREFS['do_anim'].val:
+ try:
+ tex = bpy.data.textures[PREFS['anim_tex'].val]
+ except:
+ tex = None
+ Blender.Draw.PupMenu('error no texture, cannot animate bones')
+
+ if tex:
+ t.toAction(ob_arm, tex,\
+ anim_speed = PREFS['anim_speed'].val,\
+ anim_magnitude = PREFS['anim_magnitude'].val,\
+ anim_speed_size_scale= PREFS['anim_speed_size_scale'].val,\
+ anim_offset_scale=PREFS['anim_offset_scale'].val
+ )
+
+ time7 = Blender.sys.time() # time print
+ print '%.4f sec\n' % (time7-time6)
+ else:
+ time7 = Blender.sys.time() # time print
+
+ print 'done in %.4f sec' % (time7 - time1)
+
+ # Add subsurf last it needed. so armature skinning is done first.
+ # Do subsurf?
+ if PREFS['do_subsurf'].val:
+ if not hasModifier(Blender.Modifier.Types.SUBSURF):
+ mod = ob_mesh.modifiers.append(Blender.Modifier.Types.SUBSURF)
+
+ #ob_mesh.makeDisplayList()
+ #mesh.update()
+ bpy.data.scenes.active.update()
+
+def do_pref_read(e=0,v=0, quiet=False):
+ '''
+ We dont care about e and v values, only there because its a callback
+ '''
+ sce = bpy.data.scenes.active
+ ob = sce.objects.active
+
+ if not ob:
+ if not quiet:
+ Blender.Draw.PupMenu('No active curve object')
+ return
+
+ if ob.type != 'Curve':
+ ob = ob.parent
+
+ if ob == None or ob.type != 'Curve':
+ if not quiet:
+ Blender.Draw.PupMenu('No active curve object')
+ return
+
+ if not IDProp2Prefs(ob.properties, PREFS):
+ if not quiet:
+ Blender.Draw.PupMenu('Curve object has no settings stored on it')
+ return
+
+ Blender.Draw.Redraw()
+
+def do_pref_write(e,v):
+
+ objects = getContextCurveObjects()
+ if not objects:
+ Blender.Draw.PupMenu('No curve objects selected')
+ return
+
+ for ob in objects:
+ Prefs2IDProp(ob.properties, PREFS)
+
+def do_pref_clear(e,v):
+ objects = getContextCurveObjects()
+ if not objects:
+ Blender.Draw.PupMenu('No curve objects selected')
+ return
+
+ for ob in objects:
+ try: del idprop[ID_SLOT_NAME]
+ except: pass
+
+def do_tex_check(e,v):
+ if not v: return
+ try:
+ bpy.data.textures[v]
+ except:
+ PREFS['anim_tex'].val = ''
+ Draw.PupMenu('Texture dosnt exist!')
+ Draw.Redraw()
+
+def do_ob_check(e,v):
+ if not v: return
+ try:
+ bpy.data.objects[v]
+ except:
+ # PREFS['twig_ob_bounds'].val = ''
+ Draw.PupMenu('Object dosnt exist!')
+ Draw.Redraw()
+
+def do_group_check(e,v):
+ if not v: return
+ try:
+ bpy.data.groups[v]
+ except:
+ # PREFS['leaf_object'].val = ''
+ Draw.PupMenu('dosnt exist!')
+ Draw.Redraw()
+
+# Button callbacks
+def do_active_image(e,v):
+ img = bpy.data.images.active
+ if img:
+ PREFS['image_main'].val = img.name
+ else:
+ PREFS['image_main'].val = ''
+
+# Button callbacks
+def do_tree_generate__real():
+ sce = bpy.data.scenes.active
+ objects = getContextCurveObjects()
+
+ if not objects:
+ Draw.PupMenu('Select one or more curve objects or a mesh/armature types with curve parents')
+
+ is_editmode = Blender.Window.EditMode()
+ if is_editmode:
+ Blender.Window.EditMode(0, '', 0)
+ Blender.Window.WaitCursor(1)
+
+ for ob in objects:
+ buildTree(ob, len(objects)==1)
+
+ if is_editmode:
+ Blender.Window.EditMode(1, '', 0)
+
+ Blender.Window.RedrawAll()
+
+ Blender.Window.WaitCursor(0)
+
+
+# Profile
+# Had to do this to get it to work in ubuntu "sudo aptitude install python-profiler"
+'''
+import hotshot
+import profile
+from hotshot import stats
+'''
+def do_tree_generate(e,v):
+
+ do_tree_generate__real()
+ '''
+ prof = hotshot.Profile("hotshot_edi_stats")
+ prof.runcall(do_tree_generate__real)
+ prof.close()
+ s = stats.load("hotshot_edi_stats")
+ s.sort_stats("time").print_stats()
+ '''
+ if GLOBALS['non_bez_error']:
+ Blender.Draw.PupMenu('Error%t|Nurbs and Poly curve types cant be used!')
+ GLOBALS['non_bez_error'] = 0
+
+
+
+def evt(e,val):
+ pass
+
+def bevt(e):
+
+ if e==EVENT_NONE:
+ return
+
+ if e == EVENT_UPDATE or e == EVENT_UPDATE_AND_UI:
+ if GLOBAL_PREFS['realtime_update'].val:
+ do_tree_generate(0,0) # values dont matter
+
+ if e == EVENT_REDRAW or e == EVENT_UPDATE_AND_UI:
+ Draw.Redraw()
+ if e == EVENT_EXIT:
+ Draw.Exit()
+ pass
+
+def gui():
+ MARGIN = 4
+ rect = BPyWindow.spaceRect()
+ but_width = int((rect[2]-MARGIN*2)/4.0) # 72
+ # Clamp
+ if but_width>100: but_width = 100
+ but_height = 17
+
+ x=MARGIN
+ y=rect[3]-but_height-MARGIN
+ xtmp = x
+
+ Blender.Draw.BeginAlign()
+ PREFS['do_twigs_fill'] = Draw.Toggle('Fill Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs_fill'].val, 'Generate child branches based existing branches'); xtmp += but_width*2;
+ if PREFS['do_twigs_fill'].val:
+
+ PREFS['twig_fill_levels'] = Draw.Number('Generations', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_levels'].val, 1, 32, 'How many generations to make for filled twigs'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+ # WARNING USED IN 2 PLACES!! - see below
+ PREFS['twig_ob_bounds'] = Draw.String('OB Bound: ', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_ob_bounds'].val, 64, 'Only grow twigs inside this mesh object', do_ob_check); xtmp += but_width*2;
+ PREFS['twig_fill_rand_scale'] = Draw.Number('Randomize Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_rand_scale'].val, 0.0, 1.0, 'Randomize twig scale from the bounding mesh'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+
+ PREFS['twig_fill_radius_min'] = Draw.Number('Min Radius', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_radius_min'].val, 0.0, 1.0, 'Radius at endpoints of all twigs'); xtmp += but_width*2;
+ PREFS['twig_fill_radius_factor'] = Draw.Number('Inherit Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_radius_factor'].val, 0.0, 1.0, 'What attaching to branches, scale the radius by this value for filled twigs, 0.0 for fixed width twigs.'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+
+ #PREFS['twig_fill_shape_type'] = Draw.Number('Shape Type', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_type'].val, 0.0, 1.0, 'Shape used for the fork'); xtmp += but_width*2;
+ PREFS['twig_fill_shape_type'] = Draw.Menu('Join Type%t|Even%x0|Smooth One Child%x1|Smooth Both Children%x2',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_type'].val, 'Select the wat twigs '); xtmp += but_width*2;
+ PREFS['twig_fill_fork_angle_max'] = Draw.Number('Shape Max Ang', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_fork_angle_max'].val, 0.0, 180.0, 'Maximum fork angle'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+
+ PREFS['twig_fill_shape_rand'] = Draw.Number('Shape Rand', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_rand'].val, 0.0, 1.0, 'Randomize the shape of forks'); xtmp += but_width*2;
+ PREFS['twig_fill_shape_power'] = Draw.Number('Shape Strength', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_power'].val, 0.0, 1.0, 'Strength of curves'); xtmp += but_width*2;
+
+ Blender.Draw.EndAlign()
+
+ y-=but_height+MARGIN
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+
+
+ # ---------- ---------- ---------- ----------
+ Blender.Draw.BeginAlign()
+ PREFS['do_twigs'] = Draw.Toggle('Grow Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs'].val, 'Generate child branches based existing branches'); xtmp += but_width*2;
+ if PREFS['do_twigs'].val:
+
+ PREFS['twig_ratio'] = Draw.Number('Twig Multiply', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_ratio'].val, 0.01, 500.0, 'How many twigs to generate per branch'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+ PREFS['twig_select_mode'] = Draw.Menu('Branch Selection Method%t|From Short%x0|From Long%x1|From Straight%x2|From Bent%x3|',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_select_mode'].val, 'Select branches to use as twigs based on this attribute'); xtmp += but_width*2;
+ PREFS['twig_select_factor'] = Draw.Number('From Factor', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_select_factor'].val, 0.0, 16, 'Select branches, lower value is more strict and will give you less variation'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+ PREFS['twig_recursive'] = Draw.Toggle('Recursive Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_recursive'].val, 'Recursively add twigs into eachother'); xtmp += but_width*2;
+ PREFS['twig_recursive_limit'] = Draw.Number('Generations', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_recursive_limit'].val, 0.0, 16, 'Number of generations allowed, 0 is inf'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+
+ PREFS['twig_scale'] = Draw.Number('Twig Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale'].val, 0.01, 10.0, 'Scale down twigs in relation to their parents each generation'); xtmp += but_width*2;
+ PREFS['twig_scale_width'] = Draw.Number('Twig Scale Width', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale_width'].val, 0.01, 20.0, 'Scale the twig length only (not thickness)'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+
+ PREFS['twig_random_orientation'] = Draw.Number('Rand Orientation', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_orientation'].val, 0.0, 360.0, 'Random rotation around the parent'); xtmp += but_width*2;
+ PREFS['twig_random_angle'] = Draw.Number('Rand Angle', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_angle'].val, 0.0, 360.0, 'Random rotation to the parent joint'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+
+ PREFS['twig_placement_maxradius'] = Draw.Number('Place Max Radius', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxradius'].val, 0.0, 50.0, 'Only place twigs on branches below this radius'); xtmp += but_width*2;
+ PREFS['twig_placement_maxtwig'] = Draw.Number('Place Max Count', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxtwig'].val, 0.0, 50.0, 'Limit twig placement to this many per branch'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ PREFS['twig_follow_parent'] = Draw.Number('ParFollow', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_parent'].val, 0.0, 10.0, 'Follow the parent branch'); xtmp += but_width;
+ PREFS['twig_follow_x'] = Draw.Number('Grav X', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_x'].val, -10.0, 10.0, 'Twigs gravitate on the X axis'); xtmp += but_width;
+ PREFS['twig_follow_y'] = Draw.Number('Grav Y', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_y'].val, -10.0, 10.0, 'Twigs gravitate on the Y axis'); xtmp += but_width;
+ PREFS['twig_follow_z'] = Draw.Number('Grav Z', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_z'].val, -10.0, 10.0, 'Twigs gravitate on the Z axis'); xtmp += but_width;
+
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+ # WARNING USED IN 2 PLACES!!
+ PREFS['twig_ob_bounds'] = Draw.String('OB Bound: ', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_ob_bounds'].val, 64, 'Only grow twigs inside this mesh object', do_ob_check); xtmp += but_width*2;
+
+ if PREFS['twig_ob_bounds_prune'].val:
+ but_width_tmp = but_width
+ else:
+ but_width_tmp = but_width*2
+
+ PREFS['twig_ob_bounds_prune'] = Draw.Toggle('Prune',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['twig_ob_bounds_prune'].val, 'Prune twigs to the mesh object bounds'); xtmp += but_width_tmp;
+ if PREFS['twig_ob_bounds_prune'].val:
+ PREFS['twig_ob_bounds_prune_taper'] = Draw.Number('Taper', EVENT_UPDATE_AND_UI, xtmp, y, but_width, but_height, PREFS['twig_ob_bounds_prune_taper'].val, 0.0, 1.0, 'Taper pruned branches to a point'); xtmp += but_width;
+
+ #PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3;
+ #Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width;
+ Blender.Draw.EndAlign()
+
+ y-=but_height+MARGIN
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+
+
+ Blender.Draw.BeginAlign()
+ PREFS['do_leaf'] = Draw.Toggle('Generate Leaves',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_leaf'].val, 'Generate leaves using duplifaces'); xtmp += but_width*2;
+
+ if PREFS['do_leaf'].val:
+
+ PREFS['leaf_object'] = Draw.String('OB: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_object'].val, 64, 'Use this object as a leaf', do_ob_check); xtmp += but_width*2;
+ # ---------- ---------- ---------- ----------
+ y-=but_height
+ xtmp = x
+
+ PREFS['leaf_size'] = Draw.Number('Size', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0, 'size of the leaf'); xtmp += but_width*2;
+ PREFS['leaf_size_rand'] = Draw.Number('Randsize', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size_rand'].val, 0.0, 1.0, 'randomize the leaf size'); xtmp += but_width*2;
+
+ # ---------- ---------- ---------- ----------
+ y-=but_height
+ xtmp = x
+
+ # Dont use yet
+ PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit'].val, 0.0, 1.0, 'Maximum thichness where a branch can bare leaves, higher value to place leaves on bigger branches'); xtmp += but_width*2;
+ PREFS['leaf_branch_limit_rand'] = Draw.Number('Limit Random', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit_rand'].val, 0.0, 1.0, 'Randomize the allowed minimum branch width to place leaves'); xtmp += but_width*2;
+
+ # ---------- ---------- ---------- ----------
+ y-=but_height
+ xtmp = x
+
+ PREFS['leaf_branch_density'] = Draw.Number('Density', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_density'].val, 0.0, 1.0, 'Chance each segment has of baring a leaf, use a high value for more leaves'); xtmp += but_width*2;
+ PREFS['leaf_branch_angle'] = Draw.Number('Angle From Branch', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_angle'].val, 0.0, 90.0, 'angle the leaf is from the branch direction'); xtmp += but_width*2;
+
+ # ---------- ---------- ---------- ----------
+ y-=but_height
+ xtmp = x
+
+ PREFS['leaf_rand_seed'] = Draw.Number('Random Seed', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_rand_seed'].val, 0.0, 10000.0, 'Set the seed for leaf random values'); xtmp += but_width*2;
+ PREFS['leaf_branch_pitch_angle'] = Draw.Number('Pitch Angle', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_pitch_angle'].val, -180, 180.0, 'Change the pitch rotation of leaves, negative angle to point down'); xtmp += but_width*2;
+
+ # ---------- ---------- ---------- ----------
+ y-=but_height
+ xtmp = x
+
+ PREFS['leaf_branch_pitch_rand'] = Draw.Number('Random Pitch', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_pitch_rand'].val, 0.0, 1.0, 'Randomize the leaf rotation (up-down/pitch)'); xtmp += but_width*2;
+ PREFS['leaf_branch_roll_rand'] = Draw.Number('Random Roll', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_roll_rand'].val, 0.0, 1.0, 'Randomize the leaf rotation (roll/tilt/yaw)'); xtmp += but_width*2;
+
+
+ Blender.Draw.EndAlign()
+
+ y-=but_height+MARGIN
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+
+ Blender.Draw.BeginAlign()
+ if PREFS['do_uv'].val == 0: but_width_tmp = but_width*2
+ else: but_width_tmp = but_width*4
+ PREFS['do_uv'] = Draw.Toggle('Generate UVs',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_uv'].val, 'Calculate UVs coords'); xtmp += but_width_tmp;
+
+ if PREFS['do_uv'].val:
+ # ---------- ---------- ---------- ----------
+ y-=but_height
+ xtmp = x
+
+ PREFS['do_uv_uscale'] = Draw.Toggle('U-Scale', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_uscale'].val, 'Scale the width according to the face size (will NOT tile)'); xtmp += but_width;
+ PREFS['do_uv_keep_vproportion'] = Draw.Toggle('V-Aspect', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_keep_vproportion'].val, 'Correct the UV aspect with the branch width'); xtmp += but_width;
+ PREFS['do_uv_vnormalize'] = Draw.Toggle('V-Normaize', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_uv_vnormalize'].val, 'Scale the UVs to fit onto the image verticaly'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ PREFS['uv_x_scale'] = Draw.Number('Scale U', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_x_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
+ PREFS['uv_y_scale'] = Draw.Number('Scale V', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_y_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3;
+ Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width;
+ Blender.Draw.EndAlign()
+
+ y-=but_height+MARGIN
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ Blender.Draw.BeginAlign()
+ PREFS['do_material'] = Draw.Toggle('Generate Material',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_material'].val, 'Create material and textures (for seamless joints)'); xtmp += but_width*2;
+
+ if PREFS['do_material'].val:
+ PREFS['material_use_existing'] = Draw.Toggle('ReUse Existing',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_use_existing'].val, 'Modify the textures of the existing material'); xtmp += but_width*2;
+
+ # ---------- ---------- ---------- ----------
+ y-=but_height
+ xtmp = x
+
+ PREFS['material_texture'] = Draw.Toggle('Texture', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_texture'].val, 'Create an image texture for this material to use'); xtmp += but_width*2;
+ PREFS['material_stencil'] = Draw.Toggle('Blend Joints', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['material_stencil'].val, 'Use a 2 more texture and UV layers to blend the seams between joints'); xtmp += but_width*2;
+ Blender.Draw.EndAlign()
+
+ y-=but_height+MARGIN
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ Blender.Draw.BeginAlign()
+ if PREFS['do_armature'].val == 0:
+ but_width_tmp = but_width*2
+ else:
+ but_width_tmp = but_width*4
+
+ Blender.Draw.BeginAlign()
+ PREFS['do_armature'] = Draw.Toggle('Generate Motion', EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_armature'].val, 'Generate Armatuer animation and apply to branches'); xtmp += but_width_tmp;
+
+ # ---------- ---------- ---------- ----------
+ if PREFS['do_armature'].val:
+ y-=but_height
+ xtmp = x
+
+ PREFS['do_anim'] = Draw.Toggle('Texture Anim', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_anim'].val, 'Use a texture to animate the bones'); xtmp += but_width*2;
+
+ if PREFS['do_anim'].val:
+
+ PREFS['anim_tex'] = Draw.String('TEX: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_tex'].val, 64, 'Texture to use for the IPO Driver animation', do_tex_check); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ PREFS['anim_speed'] = Draw.Number('Speed', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_speed'].val, 0.001, 10.0, 'Animate the movement faster with a higher value'); xtmp += but_width*2;
+ PREFS['anim_magnitude'] = Draw.Number('Magnitude', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_magnitude'].val, 0.001, 10.0, 'Animate with more motion with a higher value'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ PREFS['anim_offset_scale'] = Draw.Number('Unique Offset Scale', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['anim_offset_scale'].val, 0.001, 10.0, 'Use the curve object location as input into the texture so trees have more unique motion, a low value is less unique'); xtmp += but_width*4;
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+
+ PREFS['anim_speed_size_scale'] = Draw.Toggle('Branch Size Scales Speed', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['anim_speed_size_scale'].val, 'Use the branch size as a factor when calculating speed'); xtmp += but_width*4;
+
+ Blender.Draw.EndAlign()
+
+ y-=but_height+MARGIN
+ xtmp = x
+
+
+
+
+ # ---------- ---------- ---------- ----------
+
+ Blender.Draw.BeginAlign()
+ PREFS['do_variation'] = Draw.Toggle('Generate Variation', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_variation'].val, 'Create a variant by moving the branches'); xtmp += but_width*2;
+
+ # ---------- ---------- ---------- ----------
+ if PREFS['do_variation'].val:
+ PREFS['variation_seed'] = Draw.Number('Rand Seed', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_seed'].val, 1, 100000, 'Change this to get a different variation'); xtmp += but_width*2;
+ y-=but_height
+ xtmp = x
+
+
+ PREFS['variation_orientation'] = Draw.Number('Orientation', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_orientation'].val, 0, 1.0, 'Randomize rotation of the branch around its parent'); xtmp += but_width*2;
+ PREFS['variation_scale'] = Draw.Number('Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_scale'].val, 0.0, 1.0, 'Randomize the scale of branches'); xtmp += but_width*2;
+
+ Blender.Draw.EndAlign()
+
+ y-=but_height+(MARGIN*2)
+ xtmp = x
+
+
+
+ # ---------- ---------- ---------- ----------
+ Blender.Draw.BeginAlign()
+ PREFS['seg_density'] = Draw.Number('Segment Spacing',EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['seg_density'].val, 0.05, 10.0, 'Scale the limit points collapse, that are closer then the branch width'); xtmp += but_width*4;
+
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+ PREFS['seg_density_angle'] = Draw.Number('Angle Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_angle'].val, 0.0, 180.0, 'Segments above this angle will not collapse (lower value for more detail)'); xtmp += but_width*2;
+ PREFS['seg_density_radius'] = Draw.Number('Radius Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_radius'].val, 0.0, 1.0, 'Segments above this difference in radius will not collapse (lower value for more detail)'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ PREFS['seg_joint_compression'] = Draw.Number('Joint Width', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_compression'].val, 0.1, 2.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
+ PREFS['seg_joint_smooth'] = Draw.Number('Joint Smooth', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_smooth'].val, 0.0, 1.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val, 0.1, 2.0, 'Strictness when connecting branches'); xtmp += but_width*2;
+ PREFS['connect_base_trim'] = Draw.Number('Joint Bevel', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_base_trim'].val, 0.0, 2.0, 'low value for a tight join, hi for a smoother bevel'); xtmp += but_width*2;
+ Blender.Draw.EndAlign()
+ y-=but_height+MARGIN
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+ Blender.Draw.BeginAlign()
+ PREFS['do_cap_ends'] = Draw.Toggle('Cap Ends',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_cap_ends'].val, 'Add faces onto branch endpoints'); xtmp += but_width*2;
+ PREFS['do_subsurf'] = Draw.Toggle('SubSurf',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_subsurf'].val, 'Enable subsurf for newly generated objects'); xtmp += but_width*2;
+ Blender.Draw.EndAlign()
+ y-=but_height+MARGIN
+ xtmp = x
+
+
+ # ---------- ---------- ---------- ----------
+ Blender.Draw.BeginAlign()
+ Draw.PushButton('Read Active Prefs', EVENT_REDRAW, xtmp, y, but_width*2, but_height, 'Read the ID Property settings from the active curve object', do_pref_read); xtmp += but_width*2;
+ Draw.PushButton('Write Prefs to Sel', EVENT_NONE, xtmp, y, but_width*2, but_height, 'Save these settings in the ID Properties of all selected curve objects', do_pref_write); xtmp += but_width*2;
+
+ y-=but_height
+ xtmp = x
+
+ # ---------- ---------- ---------- ----------
+ Draw.PushButton('Clear Prefs from Sel', EVENT_NONE, xtmp, y, but_width*4, but_height, 'Remove settings from the selected curve aaobjects', do_pref_clear); xtmp += but_width*4;
+ Blender.Draw.EndAlign()
+
+ y-=but_height+MARGIN
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ Blender.Draw.BeginAlign()
+ Draw.PushButton('Exit', EVENT_EXIT, xtmp, y, but_width, but_height, '', do_active_image); xtmp += but_width;
+ Draw.PushButton('Generate from selection', EVENT_REDRAW, xtmp, y, but_width*3, but_height, 'Generate mesh', do_tree_generate); xtmp += but_width*3;
+ Blender.Draw.EndAlign()
+ y-=but_height+MARGIN
+ xtmp = x
+ # ---------- ---------- ---------- ----------
+
+ GLOBAL_PREFS['realtime_update'] = Draw.Toggle('Automatic Update', EVENT_UPDATE, xtmp, y, but_width*4, but_height, GLOBAL_PREFS['realtime_update'].val, 'Update automatically when settings change'); xtmp += but_width*4;
+
+
+
+if __name__ == '__main__':
+ # Read the active objects prefs on load. if they exist
+ do_pref_read(quiet=True)
+
+ Draw.Register(gui, evt, bevt)
diff --git a/release/scripts/x3d_export.py b/release/scripts/x3d_export.py
index 36359f1d122..eb9d5d35d6c 100644
--- a/release/scripts/x3d_export.py
+++ b/release/scripts/x3d_export.py
@@ -162,7 +162,8 @@ class VRML2Export:
##########################################################
def writeHeader(self):
- bfile = sys.expandpath(Blender.Get('filename'))
+ #bfile = sys.expandpath( Blender.Get('filename') ).replace('<', '&lt').replace('>', '&gt')
+ bfile = self.filename.replace('<', '&lt').replace('>', '&gt') # use outfile name
self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n")
self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n")
@@ -246,17 +247,17 @@ class VRML2Export:
def writeNavigationInfo(self, scene):
allObj = []
allObj = list(scene.objects)
- headlight = "TRUE"
+ headlight = "true"
vislimit = 0.0
for thisObj in allObj:
objType=thisObj.type
if objType == "Camera":
vislimit = thisObj.data.clipEnd
elif objType == "Lamp":
- headlight = "FALSE"
+ headlight = "false"
self.file.write("<NavigationInfo headlight=\"%s\" " % headlight)
self.file.write("visibilityLimit=\"%s\" " % (round(vislimit,self.cp)))
- self.file.write("type=\"EXAMINE, ANY\" avatarSize=\"0.25, 1.75, 0.75\" />\n\n")
+ self.file.write("type=\"EXAMINE\", \"ANY\" avatarSize=\"0.25, 1.75, 0.75\" />\n\n")
def writeSpotLight(self, ob, lamp):
safeName = self.cleanStr(ob.name)
@@ -404,7 +405,7 @@ class VRML2Export:
self.writeIndented("<Appearance>\n", 1)
# right now this script can only handle a single material per mesh.
if len(maters) >= 1:
- mat=Blender.Material.Get(maters[0].name)
+ mat=maters[0]
matFlags = mat.getMode()
if not matFlags & Blender.Material.Modes['TEXFACE']:
self.writeMaterial(mat, self.cleanStr(maters[0].name,''))
@@ -452,6 +453,7 @@ class VRML2Export:
for face in mesh.faces:
if face.smooth:
issmooth=1
+ break
if issmooth==1 and self.wire == 0:
creaseAngle=(mesh.getMaxSmoothAngle())*(math.pi/180.0)
self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp)))
diff --git a/release/windows/installer/00.sconsblender.nsi b/release/windows/installer/00.sconsblender.nsi
index ff7a198d0b9..5875be289b6 100644
--- a/release/windows/installer/00.sconsblender.nsi
+++ b/release/windows/installer/00.sconsblender.nsi
@@ -3,6 +3,8 @@
;
; Blender Self-Installer for Windows (NSIS - http://nsis.sourceforge.net)
;
+; Requires the MoreInfo plugin - http://nsis.sourceforge.net/MoreInfo_plug-in
+;
!include "MUI.nsh"
!include "FileFunc.nsh"
@@ -209,13 +211,13 @@ Function .onInit
Call GetWindowsVersion
Pop $R0
Strcpy $winversion $R0
- !insertmacro MUI_INSTALLOPTIONS_EXTRACT "RELDIR\data.ini"
+ !insertmacro MUI_INSTALLOPTIONS_EXTRACT_AS "RELDIR\data.ini" "data.ini"
FunctionEnd
!define DLL_VER "8.00.50727.42"
+!define DLL_VER2 "7.10.3052.4"
-Function LocateCallback
-
+Function LocateCallback_80
MoreInfo::GetProductVersion "$R9"
Pop $0
@@ -236,12 +238,38 @@ Function LocateCallback
FunctionEnd
+Function LocateCallback_71
+ MoreInfo::GetProductVersion "$R9"
+ Pop $0
+
+ ${VersionCompare} "$0" "${DLL_VER2}" $R1
+
+ StrCmp $R1 0 0 new
+ new:
+ StrCmp $R1 1 0 old
+ old:
+ StrCmp $R1 2 0 end
+ ; Found DLL is older
+ Call PythonInstall
+
+ end:
+ StrCpy "$0" StopLocate
+ StrCpy $DLL_found "true"
+ Push "$0"
+
+FunctionEnd
+
Function DownloadDLL
MessageBox MB_OK "You will need to download the Microsoft Visual C++ 2005 Redistributable Package in order to run Blender. Pressing OK will take you to the download page, please follow the instructions on the page that appears."
StrCpy $0 "http://www.microsoft.com/downloads/details.aspx?familyid=32BC1BEE-A3F9-4C13-9C99-220B62A191EE&displaylang=en"
Call openLinkNewWindow
FunctionEnd
+Function PythonInstall
+ MessageBox MB_OK "You will need to install python 2.5 in order to run blender. Pressing OK will take you to the python.org website."
+ StrCpy $0 "http://www.python.org"
+ Call openLinkNewWindow
+FunctionEnd
Var HWND
Var DLGITEM
@@ -344,9 +372,14 @@ Section "Blender-VERSION (required)" SecCopyUI
MessageBox MB_OK "The installer will now check your system for the required system dlls."
StrCpy $1 $WINDIR
StrCpy $DLL_found "false"
- ${Locate} "$1" "/L=F /M=MSVCR80.DLL /S=0B" "LocateCallback"
+ ${Locate} "$1" "/L=F /M=MSVCR80.DLL /S=0B" "LocateCallback_80"
StrCmp $DLL_found "false" 0 +2
Call DownloadDLL
+ StrCpy $1 $WINDIR
+ StrCpy $DLL_found "false"
+ ${Locate} "$1" "/L=F /M=MSVCR71.DLL /S=0B" "LocateCallback_71"
+ StrCmp $DLL_found "false" 0 +2
+ Call PythonInstall
SectionEnd