diff --git a/src/tools/blender/speed_dreams_ac3d_export.py b/src/tools/blender/speed_dreams_ac3d_export.py
new file mode 100644
index 00000000..f72d5ae9
--- /dev/null
+++ b/src/tools/blender/speed_dreams_ac3d_export.py
@@ -0,0 +1,832 @@
+#!BPY
+
+""" Registration info for Blender menus:
+Name: 'Speed Dreams AC3D (.ac)...'
+Blender: 243
+Group: 'Export'
+Tip: 'Export selected meshes to AC3D (.ac) format'
+"""
+
+__author__ = "Willian P. Germano"
+__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org",
+ "PLib 3d gaming lib, http://plib.sf.net")
+__version__ = "2.44 2007-05-05"
+
+__bpydoc__ = """\
+This script exports selected Blender meshes to AC3D's .ac file format.
+
+AC3D is a simple commercial 3d modeller also built with OpenGL.
+The .ac file format is an easy to parse text format well supported,
+for example, by the PLib 3d gaming library (AC3D 3.x).
+
+Supported:
+ UV-textured meshes with hierarchy (grouping) information.
+
+Missing:
+ The 'url' tag, specific to AC3D. It is easy to add by hand to the exported
+file, if needed.
+
+Known issues:
+ The ambient and emit data we can retrieve from Blender are single values,
+that this script copies to R, G, B, giving shades of gray.
+ Loose edges (lines) receive the first material found in the mesh, if any, or a default white material.
+ In AC3D 4 "compatibility mode":
+ - shininess of materials is taken from the shader specularity value in Blender, mapped from [0.0, 2.0] to [0, 128];
+ - crease angle is exported, but in Blender it is limited to [1, 80], since there are other more powerful ways to control surface smoothing. In AC3D 4.0 crease's range is [0.0, 180.0];
+
+Config Options:
+ toggle:
+ - AC3D 4 mode: unset it to export without the 'crease' tag that was
+introduced with AC3D 4.0 and with the old material handling;
+ - global coords: transform all vertices of all meshes to global coordinates;
+ - skip data: set it if you don't want mesh names (ME:, not OB: field)
+to be exported as strings for AC's "data" tags (19 chars max);
+ - rgb mirror color can be exported as ambient and/or emissive if needed,
+since Blender handles these differently;
+ - default mat: a default (white) material is added if some mesh was
+left without mats -- it's better to always add your own materials;
+ - no split: don't split meshes (see above);
+ - set texture dir: override the actual textures path with a given default
+path (or simply export the texture names, without dir info, if the path is
+empty);
+ - per face 1 or 2 sided: override the "Double Sided" button that defines this behavior per whole mesh in favor of the UV Face Select mode "twosided" per face atribute;
+ - only selected: only consider selected objects when looking for meshes
+to export (read notes below about tokens, too);
+ strings:
+ - export dir: default dir to export to;
+ - texture dir: override textures path with this path if 'set texture dir'
+toggle is "on".
+
+Notes:
+ This version updates:
+ - modified meshes are correctly exported, no need to apply the modifiers in Blender;
+ - correctly export each used material, be it assigned to the object or to its mesh data;
+ - exporting lines (edges) is again supported; color comes from first material found in the mesh, if any, or a default white one.
+ - there's a new option to choose between exporting meshes with transformed (global) coordinates or local ones;
+ Multiple textures per mesh are supported (mesh gets split);
+ Parents are exported as a group containing both the parent and its children;
+ Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;
+ Start mesh object names (OB: field) with "=" or "$" to prevent them from being split (meshes with multiple textures or both textured and non textured faces are split unless this trick is used or the "no split" option is set.
+"""
+
+# $Id: ac3d_export.py 14530 2008-04-23 14:04:05Z campbellbarton $
+#
+# --------------------------------------------------------------------------
+# AC3DExport version 2.44
+# Program versions: Blender 2.42+ and AC3Db files (means version 0xb)
+# new: updated for new Blender version and Mesh module; supports lines (edges) again;
+# option to export vertices transformed to global coordinates or not; now the modified
+# (by existing mesh modifiers) mesh is exported; materials are properly exported, no
+# matter if each of them is linked to the mesh or to the object. New (2.43.1): loose
+# edges use color of first material found in the mesh, if any.
+# --------------------------------------------------------------------------
+# Thanks: Steve Baker for discussions and inspiration; for testing, bug
+# reports, suggestions, patches: David Megginson, Filippo di Natale,
+# Franz Melchior, Campbell Barton, Josh Babcock, Ralf Gerlich, Stewart Andreason.
+# --------------------------------------------------------------------------
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# --------------------------------------------------------------------------
+
+import Blender
+from Blender import Object, Mesh, Material, Image, Mathutils, Registry
+from Blender import sys as bsys
+
+# Globals
+REPORT_DATA = {
+ 'main': [],
+ 'errors': [],
+ 'warns': [],
+ 'nosplit': [],
+ 'noexport': []
+}
+TOKENS_DONT_EXPORT = ['!', '#']
+TOKENS_DONT_SPLIT = ['=', '$']
+
+MATIDX_ERROR = 0
+
+# flags:
+LOOSE = Mesh.EdgeFlags['LOOSE']
+FACE_TWOSIDED = Mesh.FaceModes['TWOSIDE']
+MESH_TWOSIDED = Mesh.Modes['TWOSIDED']
+
+REG_KEY = 'ac3d_export'
+
+# config options:
+GLOBAL_COORDS = True
+SKIP_DATA = False
+MIRCOL_AS_AMB = False
+MIRCOL_AS_EMIS = False
+ADD_DEFAULT_MAT = True
+SET_TEX_DIR = True
+TEX_DIR = ''
+AC3D_4 = True # export crease value, compatible with AC3D 4 loaders
+NO_SPLIT = False
+ONLY_SELECTED = True
+EXPORT_DIR = ''
+PER_FACE_1_OR_2_SIDED = True
+
+tooltips = {
+ 'GLOBAL_COORDS': "transform all vertices of all meshes to global coordinates",
+ 'SKIP_DATA': "don't export mesh names as data fields",
+ 'MIRCOL_AS_AMB': "export mirror color as ambient color",
+ 'MIRCOL_AS_EMIS': "export mirror color as emissive color",
+ 'ADD_DEFAULT_MAT': "always add a default white material",
+ 'SET_TEX_DIR': "don't export default texture paths (edit also \"tex dir\")",
+ 'EXPORT_DIR': "default / last folder used to export .ac files to",
+ 'TEX_DIR': "(see \"set tex dir\") dir to prepend to all exported texture names (leave empty for no dir)",
+ 'AC3D_4': "compatibility mode, adds 'crease' tag and slightly better material support",
+ 'NO_SPLIT': "don't split meshes with multiple textures (or both textured and non textured polygons)",
+ 'ONLY_SELECTED': "export only selected objects",
+ 'PER_FACE_1_OR_2_SIDED': "override \"Double Sided\" button in favor of per face \"twosided\" attribute (UV Face Select mode)"
+}
+
+def update_RegistryInfo():
+ d = {}
+ d['SKIP_DATA'] = SKIP_DATA
+ d['MIRCOL_AS_AMB'] = MIRCOL_AS_AMB
+ d['MIRCOL_AS_EMIS'] = MIRCOL_AS_EMIS
+ d['ADD_DEFAULT_MAT'] = ADD_DEFAULT_MAT
+ d['SET_TEX_DIR'] = SET_TEX_DIR
+ d['TEX_DIR'] = TEX_DIR
+ d['AC3D_4'] = AC3D_4
+ d['NO_SPLIT'] = NO_SPLIT
+ d['EXPORT_DIR'] = EXPORT_DIR
+ d['ONLY_SELECTED'] = ONLY_SELECTED
+ d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED
+ d['tooltips'] = tooltips
+ d['GLOBAL_COORDS'] = GLOBAL_COORDS
+ Registry.SetKey(REG_KEY, d, True)
+
+# Looking for a saved key in Blender.Registry dict:
+rd = Registry.GetKey(REG_KEY, True)
+
+if rd:
+ try:
+ AC3D_4 = rd['AC3D_4']
+ SKIP_DATA = rd['SKIP_DATA']
+ MIRCOL_AS_AMB = rd['MIRCOL_AS_AMB']
+ MIRCOL_AS_EMIS = rd['MIRCOL_AS_EMIS']
+ ADD_DEFAULT_MAT = rd['ADD_DEFAULT_MAT']
+ SET_TEX_DIR = rd['SET_TEX_DIR']
+ TEX_DIR = rd['TEX_DIR']
+ EXPORT_DIR = rd['EXPORT_DIR']
+ ONLY_SELECTED = rd['ONLY_SELECTED']
+ NO_SPLIT = rd['NO_SPLIT']
+ PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED']
+ GLOBAL_COORDS = rd['GLOBAL_COORDS']
+ except KeyError: update_RegistryInfo()
+
+else:
+ update_RegistryInfo()
+
+VERBOSE = True
+CONFIRM_OVERWRITE = True
+
+# check General scripts config key for default behaviors
+rd = Registry.GetKey('General', True)
+if rd:
+ try:
+ VERBOSE = rd['verbose']
+ CONFIRM_OVERWRITE = rd['confirm_overwrite']
+ except: pass
+
+
+# The default material to be used when necessary (see ADD_DEFAULT_MAT)
+DEFAULT_MAT = ''
+
+# This transformation aligns Blender and AC3D coordinate systems:
+BLEND_TO_AC3D_MATRIX = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1])
+
+def Round_s(f):
+ "Round to default precision and turn value to a string"
+ r = round(f,6) # precision set to 10e-06
+ if r == int(r):
+ return str(int(r))
+ else:
+ return str(r)
+
+def transform_verts(verts, m):
+ vecs = []
+ for v in verts:
+ x, y, z = v.co
+ vec = Mathutils.Vector([x, y, z, 1])
+ vecs.append(vec*m)
+ return vecs
+
+def get_loose_edges(mesh):
+ loose = LOOSE
+ return [e for e in mesh.edges if e.flag & loose]
+
+# ---
+
+# meshes with more than one texture assigned
+# are split and saved as these foomeshes
+class FooMesh:
+
+ class FooVert:
+ def __init__(self, v):
+ self.v = v
+ self.index = 0
+
+ class FooFace:
+ def __init__(self, foomesh, f):
+ self.f = f
+ foov = foomesh.FooVert
+ self.v = [foov(f.v[0]), foov(f.v[1])]
+ len_fv = len(f.v)
+ if len_fv > 2 and f.v[2]:
+ self.v.append(foov(f.v[2]))
+ if len_fv > 3 and f.v[3]: self.v.append(foov(f.v[3]))
+
+ def __getattr__(self, attr):
+ if attr == 'v': return self.v
+ return getattr(self.f, attr)
+
+ def __len__(self):
+ return len(self.f)
+
+ def __init__(self, tex, faces, mesh):
+ self.name = mesh.name
+ self.mesh = mesh
+ self.looseEdges = []
+ self.faceUV = mesh.faceUV
+ self.degr = mesh.degr
+ vidxs = [0]*len(mesh.verts)
+ foofaces = []
+ for f in faces:
+ foofaces.append(self.FooFace(self, f))
+ for v in f.v:
+ if v: vidxs[v.index] = 1
+ i = 0
+ fooverts = []
+ for v in mesh.verts:
+ if vidxs[v.index]:
+ fooverts.append(v)
+ vidxs[v.index] = i
+ i += 1
+ for f in foofaces:
+ for v in f.v:
+ if v: v.index = vidxs[v.v.index]
+ self.faces = foofaces
+ self.verts = fooverts
+
+
+class AC3DExport: # the ac3d exporter part
+
+ def __init__(self, scene_objects, file):
+
+ global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT
+
+ header = 'AC3Db'
+ headermat ='MATERIAL "" rgb 0.40 0.40 0.40 amb 0.80 0.80 0.80 emis 0.40 0.40 0.40 spec 0.05 0.05 0.05 shi 50 trans 0'
+ self.file = file
+ self.buf = ''
+ self.mbuf = []
+ self.mlist = []
+ world_kids = 0
+ parents_list = self.parents_list = []
+ kids_dict = self.kids_dict = {}
+ objs = []
+ exp_objs = self.exp_objs = []
+ tree = {}
+
+ file.write(header+'\n')
+ file.write(headermat)
+
+ objs = \
+ [o for o in scene_objects if o.type in ['Mesh', 'Empty']]
+
+ # create a tree from parents to children objects
+
+ for obj in objs[:]:
+ parent = obj.parent
+ lineage = [obj]
+
+ while parent:
+ parents_list.append(parent.name)
+ obj = parent
+ parent = parent.getParent()
+ lineage.insert(0, obj)
+
+ d = tree
+ for i in xrange(len(lineage)):
+ lname = lineage[i].getType()[:2] + lineage[i].name
+ if lname not in d.keys():
+ d[lname] = {}
+ d = d[lname]
+
+ # traverse the tree to get an ordered list of names of objects to export
+ self.traverse_dict(tree)
+
+ world_kids = len(tree.keys())
+
+ # get list of objects to export, start writing the .ac file
+
+ objlist = [Object.Get(name) for name in exp_objs]
+
+ meshlist = [o for o in objlist if o.type == 'Mesh']
+
+ # create a temporary mesh to hold actual (modified) mesh data
+ TMP_mesh = Mesh.New('tmp_for_ac_export')
+
+ # write materials
+
+ self.MATERIALS(meshlist, TMP_mesh)
+ mbuf = self.mbuf
+ if not mbuf or ADD_DEFAULT_MAT:
+ mbuf.insert(0, "%s\n" % DEFAULT_MAT)
+ mbuf = "".join(mbuf)
+ file.write(mbuf)
+
+ file.write('OBJECT world\nkids %s\n' % world_kids)
+
+ # write the objects
+
+ for obj in objlist:
+ self.obj = obj
+
+ objtype = obj.type
+ objname = obj.name
+ kidsnum = kids_dict[objname]
+
+ # A parent plus its children are exported as a group.
+ # If the parent is a mesh, its rot and loc are exported as the
+ # group rot and loc and the mesh (w/o rot and loc) is added to the group.
+ if kidsnum:
+ self.OBJECT('group')
+ self.name(objname)
+ if objtype == 'Mesh':
+ kidsnum += 1
+ if not GLOBAL_COORDS:
+ localmatrix = obj.getMatrix('localspace')
+ if not obj.getParent():
+ localmatrix *= BLEND_TO_AC3D_MATRIX
+ self.rot(localmatrix.rotationPart())
+ self.loc(localmatrix.translationPart())
+ self.kids(kidsnum)
+
+ if objtype == 'Mesh':
+ mesh = TMP_mesh # temporary mesh to hold actual (modified) mesh data
+ mesh.getFromObject(objname)
+ self.mesh = mesh
+ if mesh.faceUV:
+ meshes = self.split_mesh(mesh)
+ else:
+ meshes = [mesh]
+ if len(meshes) > 1:
+ if NO_SPLIT or self.dont_split(objname):
+ self.export_mesh(mesh, ob)
+ REPORT_DATA['nosplit'].append(objname)
+ else:
+ self.OBJECT('group')
+ self.name(objname)
+ self.kids(len(meshes))
+ counter = 0
+ for me in meshes:
+ self.export_mesh(me, obj,
+ name = '%s_%s' % (obj.name, counter), foomesh = True)
+ self.kids()
+ counter += 1
+ else:
+ self.export_mesh(mesh, obj)
+ self.kids()
+
+
+ def traverse_dict(self, d):
+ kids_dict = self.kids_dict
+ exp_objs = self.exp_objs
+ keys = d.keys()
+ keys.sort() # sort for predictable output
+ keys.reverse()
+ for k in keys:
+ objname = k[2:]
+ klen = len(d[k])
+ kids_dict[objname] = klen
+ if self.dont_export(objname):
+ d.pop(k)
+ parent = Object.Get(objname).getParent()
+ if parent: kids_dict[parent.name] -= 1
+ REPORT_DATA['noexport'].append(objname)
+ continue
+ if klen:
+ self.traverse_dict(d[k])
+ exp_objs.insert(0, objname)
+ else:
+ if k.find('Em', 0) == 0: # Empty w/o children
+ d.pop(k)
+ parent = Object.Get(objname).getParent()
+ if parent: kids_dict[parent.name] -= 1
+ else:
+ exp_objs.insert(0, objname)
+
+ def dont_export(self, name): # if name starts with '!' or '#'
+ length = len(name)
+ if length >= 1:
+ if name[0] in TOKENS_DONT_EXPORT: # '!' or '#' doubled (escaped): export
+ if length > 1 and name[1] == name[0]:
+ return 0
+ return 1
+
+ def dont_split(self, name): # if name starts with '=' or '$'
+ length = len(name)
+ if length >= 1:
+ if name[0] in TOKENS_DONT_SPLIT: # '=' or '$' doubled (escaped): split
+ if length > 1 and name[1] == name[0]:
+ return 0
+ return 1
+
+ def split_mesh(self, mesh):
+ tex_dict = {0:[]}
+ for f in mesh.faces:
+ if f.image:
+ if not f.image.name in tex_dict: tex_dict[f.image.name] = []
+ tex_dict[f.image.name].append(f)
+ else: tex_dict[0].append(f)
+ keys = tex_dict.keys()
+ len_keys = len(keys)
+ if not tex_dict[0]:
+ len_keys -= 1
+ tex_dict.pop(0)
+ keys.remove(0)
+ elif len_keys > 1:
+ lines = []
+ anyimgkey = [k for k in keys if k != 0][0]
+ for f in tex_dict[0]:
+ if len(f.v) < 3:
+ lines.append(f)
+ if len(tex_dict[0]) == len(lines):
+ for l in lines:
+ tex_dict[anyimgkey].append(l)
+ len_keys -= 1
+ tex_dict.pop(0)
+ if len_keys > 1:
+ foo_meshes = []
+ for k in keys:
+ faces = tex_dict[k]
+ foo_meshes.append(FooMesh(k, faces, mesh))
+ foo_meshes[0].edges = get_loose_edges(mesh)
+ return foo_meshes
+ return [mesh]
+
+ def export_mesh(self, mesh, obj, name = None, foomesh = False):
+ file = self.file
+ self.OBJECT('poly')
+ if not name: name = obj.name
+ self.name(name)
+ if not SKIP_DATA:
+ meshname = obj.getData(name_only = True)
+ self.data(len(meshname), meshname)
+ if mesh.faceUV:
+ texline = self.texture(mesh.faces)
+ if texline: file.write(texline)
+ if AC3D_4:
+ self.crease(mesh.degr)
+
+ # If exporting using local coordinates, children object coordinates should not be
+ # transformed to ac3d's coordinate system, since that will be accounted for in
+ # their topmost parents (the parents w/o parents) transformations.
+ if not GLOBAL_COORDS:
+ # We hold parents in a list, so they also don't get transformed,
+ # because for each parent we create an ac3d group to hold both the
+ # parent and its children.
+ if obj.name not in self.parents_list:
+ localmatrix = obj.getMatrix('localspace')
+ if not obj.getParent():
+ localmatrix *= BLEND_TO_AC3D_MATRIX
+ self.rot(localmatrix.rotationPart())
+ self.loc(localmatrix.translationPart())
+ matrix = None
+ else:
+ matrix = obj.getMatrix() * BLEND_TO_AC3D_MATRIX
+
+ self.numvert(mesh.verts, matrix)
+ self.numsurf(mesh, foomesh)
+
+ def MATERIALS(self, meshlist, me):
+ for meobj in meshlist:
+ me.getFromObject(meobj)
+ mats = me.materials
+ mbuf = []
+ mlist = self.mlist
+ for m in mats:
+ if not m: continue
+ name = m.name
+ if name not in mlist:
+ mlist.append(name)
+ M = Material.Get(name)
+ material = 'MATERIAL "%s"' % name
+ mirCol = "%s %s %s" % (Round_s(M.mirCol[0]), Round_s(M.mirCol[1]),
+ Round_s(M.mirCol[2]))
+ rgb = "rgb %s %s %s" % (Round_s(M.R), Round_s(M.G), Round_s(M.B))
+ ambval = Round_s(M.amb)
+ amb = "amb %s %s %s" % (ambval, ambval, ambval)
+ spec = "spec %s %s %s" % (Round_s(M.specCol[0]),
+ Round_s(M.specCol[1]), Round_s(M.specCol[2]))
+ if AC3D_4:
+ emit = Round_s(M.emit)
+ emis = "emis %s %s %s" % (emit, emit, emit)
+ shival = int(M.spec * 64)
+ else:
+ emis = "emis 0 0 0"
+ shival = 72
+ shi = "shi %s" % shival
+ trans = "trans %s" % (Round_s(1 - M.alpha))
+ if MIRCOL_AS_AMB:
+ amb = "amb %s" % mirCol
+ if MIRCOL_AS_EMIS:
+ emis = "emis %s" % mirCol
+ #mbuf.append("%s %s %s %s %s %s %s\n" \
+ # % (material, rgb, amb, emis, spec, shi, trans))
+ self.mlist = mlist
+ self.mbuf.append("".join(mbuf))
+
+ def OBJECT(self, type):
+ self.file.write('OBJECT %s\n' % type)
+
+ def name(self, name):
+ if name[0] in TOKENS_DONT_EXPORT or name[0] in TOKENS_DONT_SPLIT:
+ if len(name) > 1: name = name[1:]
+ self.file.write('name "%s"\n' % name)
+
+ def kids(self, num = 0):
+ self.file.write('kids %s\n' % num)
+
+ def data(self, num, str):
+ # self.file.write('data %s\n%s\n' % (num, str))
+ waste = 0;
+
+ def texture(self, faces):
+ tex = ""
+ for f in faces:
+ if f.image:
+ tex = f.image.name
+ break
+ if tex:
+ image = Image.Get(tex)
+ texfname = image.filename
+ if SET_TEX_DIR:
+ texfname = bsys.basename(texfname)
+ if TEX_DIR:
+ texfname = bsys.join(TEX_DIR, texfname)
+ buf = 'texture "%s"\n' % texfname
+ xrep = image.xrep
+ yrep = image.yrep
+ # buf += 'texrep %s %s\n' % (xrep, yrep)
+ self.file.write(buf)
+
+ def rot(self, matrix):
+ rot = ''
+ not_I = 0 # not identity
+ matstr = []
+ for i in [0, 1, 2]:
+ r = map(Round_s, matrix[i])
+ not_I += (r[0] != '0')+(r[1] != '0')+(r[2] != '0')
+ not_I -= (r[i] == '1')
+ for j in [0, 1, 2]:
+ matstr.append(' %s' % r[j])
+ if not_I: # no need to write identity
+ self.file.write('rot%s\n' % "".join(matstr))
+
+ def loc(self, loc):
+ loc = map(Round_s, loc)
+ if loc != ['0', '0', '0']: # no need to write default
+ self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2]))
+
+ def crease(self, crease):
+ # self.file.write('crease %f\n' % crease)
+ waste =0;
+
+ def numvert(self, verts, matrix):
+ file = self.file
+ nvstr = []
+ nvstr.append("numvert %s\n" % len(verts))
+
+ if matrix:
+ verts = transform_verts(verts, matrix)
+ for v in verts:
+ v = map (Round_s, v)
+ nvstr.append("%s %s %s\n" % (v[0], v[1], v[2]))
+ else:
+ for v in verts:
+ v = map(Round_s, v.co)
+ nvstr.append("%s %s %s\n" % (v[0], v[1], v[2]))
+
+ file.write("".join(nvstr))
+
+ def numsurf(self, mesh, foomesh = False):
+
+ global MATIDX_ERROR
+
+ # local vars are faster and so better in tight loops
+ lc_ADD_DEFAULT_MAT = ADD_DEFAULT_MAT
+ lc_MATIDX_ERROR = MATIDX_ERROR
+ lc_PER_FACE_1_OR_2_SIDED = PER_FACE_1_OR_2_SIDED
+ lc_FACE_TWOSIDED = FACE_TWOSIDED
+ lc_MESH_TWOSIDED = MESH_TWOSIDED
+
+ faces = mesh.faces
+ hasFaceUV = mesh.faceUV
+ if foomesh:
+ looseEdges = mesh.looseEdges
+ else:
+ looseEdges = get_loose_edges(mesh)
+
+ file = self.file
+
+ file.write("numsurf %s\n" % (len(faces) + len(looseEdges)))
+
+ if not foomesh: verts = list(self.mesh.verts)
+
+ materials = self.mesh.materials
+ mlist = self.mlist
+ matidx_error_reported = False
+ objmats = []
+ for omat in materials:
+ if omat: objmats.append(omat.name)
+ else: objmats.append(None)
+ for f in faces:
+ if not objmats:
+ m_idx = 0
+ elif objmats[f.mat] in mlist:
+ m_idx = mlist.index(objmats[f.mat])
+ else:
+ if not lc_MATIDX_ERROR:
+ rdat = REPORT_DATA['warns']
+ rdat.append("Object %s" % self.obj.name)
+ rdat.append("has at least one material *index* assigned but not")
+ rdat.append("defined (not linked to an existing material).")
+ rdat.append("Result: some faces may be exported with a wrong color.")
+ rdat.append("You can assign materials in the Edit Buttons window (F9).")
+ elif not matidx_error_reported:
+ midxmsg = "- Same for object %s." % self.obj.name
+ REPORT_DATA['warns'].append(midxmsg)
+ lc_MATIDX_ERROR += 1
+ matidx_error_reported = True
+ m_idx = 0
+ if lc_ADD_DEFAULT_MAT: m_idx -= 1
+ refs = len(f)
+ flaglow = 0 # polygon
+ if lc_PER_FACE_1_OR_2_SIDED and hasFaceUV: # per face attribute
+ two_side = f.mode & lc_FACE_TWOSIDED
+ else: # global, for the whole mesh
+ two_side = self.mesh.mode & lc_MESH_TWOSIDED
+ two_side = (two_side > 0) << 1
+ flaghigh = f.smooth | two_side
+ surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
+ if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1
+ # matstr = "mat %s\n" % m_idx
+ matstr = "mat 0\n"
+ refstr = "refs %s\n" % refs
+ u, v, vi = 0, 0, 0
+ fvstr = []
+ if foomesh:
+ for vert in f.v:
+ fvstr.append(str(vert.index))
+ if hasFaceUV:
+ u = f.uv[vi][0]
+ v = f.uv[vi][1]
+ vi += 1
+ fvstr.append(" %s %s\n" % (str(u), str(v)))
+ else:
+ for vert in f.v:
+ fvstr.append(str(verts.index(vert)))
+ if hasFaceUV:
+ u = f.uv[vi][0]
+ v = f.uv[vi][1]
+ vi += 1
+ fvstr.append(" %s %s\n" % (str(u), str(v)))
+
+ fvstr = "".join(fvstr)
+
+ file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr))
+
+ # material for loose edges
+ edges_mat = 0 # default to first material
+ for omat in objmats: # but look for a material from this mesh
+ if omat in mlist:
+ edges_mat = mlist.index(omat)
+ if lc_ADD_DEFAULT_MAT: edges_mat += 1
+ break
+
+ for e in looseEdges:
+ fvstr = []
+ #flaglow = 2 # 1 = closed line, 2 = line
+ #flaghigh = 0
+ #surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
+ surfstr = "SURF 0x02\n"
+
+ fvstr.append("%d 0 0\n" % verts.index(e.v1))
+ fvstr.append("%d 0 0\n" % verts.index(e.v2))
+ fvstr = "".join(fvstr)
+
+ #matstr = "mat %d\n" % edges_mat # for now, use first material
+ matstr = "mat 0\n"
+ refstr = "refs 2\n" # 2 verts
+
+ file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr))
+
+ MATIDX_ERROR = lc_MATIDX_ERROR
+
+# End of Class AC3DExport
+
+from Blender.Window import FileSelector
+
+def report_data():
+ global VERBOSE
+
+ if not VERBOSE: return
+
+ d = REPORT_DATA
+ msgs = {
+ '0main': '%s\nExporting meshes to AC3D format' % str(19*'-'),
+ '1warns': 'Warnings',
+ '2errors': 'Errors',
+ '3nosplit': 'Not split (because name starts with "=" or "$")',
+ '4noexport': 'Not exported (because name starts with "!" or "#")'
+ }
+ if NO_SPLIT:
+ l = msgs['3nosplit']
+ l = "%s (because OPTION NO_SPLIT is set)" % l.split('(')[0]
+ msgs['3nosplit'] = l
+ keys = msgs.keys()
+ keys.sort()
+ for k in keys:
+ msgk = msgs[k]
+ msg = '\n'.join(d[k[1:]])
+ if msg:
+ print '\n-%s:' % msgk
+ print msg
+
+# File Selector callback:
+def fs_callback(filename):
+ global EXPORT_DIR, OBJS, CONFIRM_OVERWRITE, VERBOSE
+
+ if not filename.endswith('.ac'): filename = '%s.ac' % filename
+
+ if bsys.exists(filename) and CONFIRM_OVERWRITE:
+ if Blender.Draw.PupMenu('OVERWRITE?%t|File exists') != 1:
+ return
+
+ Blender.Window.WaitCursor(1)
+ starttime = bsys.time()
+
+ export_dir = bsys.dirname(filename)
+ if export_dir != EXPORT_DIR:
+ EXPORT_DIR = export_dir
+ update_RegistryInfo()
+
+ try:
+ file = open(filename, 'w')
+ except IOError, (errno, strerror):
+ error = "IOError #%s: %s" % (errno, strerror)
+ REPORT_DATA['errors'].append("Saving failed - %s." % error)
+ error_msg = "Couldn't save file!%%t|%s" % error
+ Blender.Draw.PupMenu(error_msg)
+ return
+
+ try:
+ test = AC3DExport(OBJS, file)
+ except:
+ file.close()
+ raise
+ else:
+ file.close()
+ endtime = bsys.time() - starttime
+ REPORT_DATA['main'].append("Done. Saved to: %s" % filename)
+ REPORT_DATA['main'].append("Data exported in %.3f seconds." % endtime)
+
+ if VERBOSE: report_data()
+ Blender.Window.WaitCursor(0)
+
+
+# -- End of definitions
+
+scn = Blender.Scene.GetCurrent()
+
+if ONLY_SELECTED:
+ OBJS = list(scn.objects.context)
+else:
+ OBJS = list(scn.objects)
+
+if not OBJS:
+ Blender.Draw.PupMenu('ERROR: no objects selected')
+else:
+ fname = bsys.makename(ext=".ac")
+ if EXPORT_DIR:
+ fname = bsys.join(EXPORT_DIR, bsys.basename(fname))
+ FileSelector(fs_callback, "Export AC3D", fname)