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)