Misc updates to the ac3d importer and exporter:
- use Mesh instead of NMesh;
- properly export modified data and materials from either ob or obdata (thanks for mesh.getFromObject :) );
- option to export local rot and loc info;
- better import / export of hierarchies;
- + tiny updates here and there to support old or weird .ac files.
This commit is contained in:
Willian Padovani Germano 2007-01-14 18:13:47 +00:00
parent d90c686bdb
commit 82bfd281f2
2 changed files with 479 additions and 258 deletions

@ -2,7 +2,7 @@
""" Registration info for Blender menus: """ Registration info for Blender menus:
Name: 'AC3D (.ac)...' Name: 'AC3D (.ac)...'
Blender: 236 Blender: 242
Group: 'Export' Group: 'Export'
Tip: 'Export selected meshes to AC3D (.ac) format' Tip: 'Export selected meshes to AC3D (.ac) format'
""" """
@ -10,7 +10,7 @@ Tip: 'Export selected meshes to AC3D (.ac) format'
__author__ = "Willian P. Germano" __author__ = "Willian P. Germano"
__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", __url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org",
"PLib 3d gaming lib, http://plib.sf.net") "PLib 3d gaming lib, http://plib.sf.net")
__version__ = "2.41a 2006-06-16" __version__ = "2.43 2007-01-14"
__bpydoc__ = """\ __bpydoc__ = """\
This script exports selected Blender meshes to AC3D's .ac file format. This script exports selected Blender meshes to AC3D's .ac file format.
@ -37,6 +37,7 @@ Config Options:<br>
toggle:<br> toggle:<br>
- AC3D 4 mode: unset it to export without the 'crease' tag that was - AC3D 4 mode: unset it to export without the 'crease' tag that was
introduced with AC3D 4.0 and with the old material handling;<br> introduced with AC3D 4.0 and with the old material handling;<br>
- global coords: transform all vertices of all meshes to global coordinates;<br>
- skip data: set it if you don't want mesh names (ME:, not OB: field) - 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);<br> to be exported as strings for AC's "data" tags (19 chars max);<br>
- rgb mirror color can be exported as ambient and/or emissive if needed, - rgb mirror color can be exported as ambient and/or emissive if needed,
@ -56,10 +57,13 @@ to export (read notes below about tokens, too);<br>
toggle is "on". toggle is "on".
Notes:<br> Notes:<br>
This version is considerably faster than previous ones for large meshes;<br> This version updates:<br>
- modified meshes are correctly exported, no need to apply the modifiers in Blender;<br>
- correctly export each used material, be it assigned to the object or to its mesh data;<br>
- exporting lines (edges) is again supported;<br>
- there's a new option to choose between exporting meshes with transformed (global) coordinates or local ones;<br>
Multiple textures per mesh are supported (mesh gets split);<br> Multiple textures per mesh are supported (mesh gets split);<br>
Parenting with meshes or empties as parents is converted to AC3D group Parents are exported as a group containing both the parent and its children;<br>
information;<br>
Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;<br> Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;<br>
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. 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.
""" """
@ -67,17 +71,20 @@ information;<br>
# $Id$ # $Id$
# #
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# AC3DExport version 2.41 # AC3DExport version 2.43
# Program versions: Blender 2.36+ and AC3Db files (means version 0xb) # Program versions: Blender 2.42+ and AC3Db files (means version 0xb)
# new: faster, supports multiple textures per object and parenting is # new: updated for new Blender version and Mesh module; supports lines (edges) again;
# properly exported as group info, adapted to work with the Config Editor # 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.
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Thanks: Steve Baker for discussions and inspiration; for testing, bug # Thanks: Steve Baker for discussions and inspiration; for testing, bug
# reports, suggestions: David Megginson, Filippo di Natale, Franz Melchior # reports, suggestions, patches: David Megginson, Filippo di Natale,
# Franz Melchior, Campbell Barton, Josh Babcock, Ralf Gerlich
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK ***** # ***** BEGIN GPL LICENSE BLOCK *****
# #
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br # Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -94,8 +101,8 @@ information;<br>
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
import Blender import Blender
from Blender import Object, Mesh, Material, Image, Mathutils, Registry
from Blender import sys as bsys from Blender import sys as bsys
from Blender import Mathutils
# Globals # Globals
ERROR_MSG = '' # popup error msg ERROR_MSG = '' # popup error msg
@ -108,11 +115,18 @@ REPORT_DATA = {
} }
TOKENS_DONT_EXPORT = ['!', '#'] TOKENS_DONT_EXPORT = ['!', '#']
TOKENS_DONT_SPLIT = ['=', '$'] TOKENS_DONT_SPLIT = ['=', '$']
MATIDX_ERROR = False
MATIDX_ERROR = 0
# flags:
LOOSE = Mesh.EdgeFlags['LOOSE']
FACE_TWOSIDED = Mesh.FaceModes['TWOSIDE']
MESH_TWOSIDED = Mesh.Modes['TWOSIDED']
REG_KEY = 'ac3d_export' REG_KEY = 'ac3d_export'
# config options: # config options:
GLOBAL_COORDS = True
SKIP_DATA = False SKIP_DATA = False
MIRCOL_AS_AMB = False MIRCOL_AS_AMB = False
MIRCOL_AS_EMIS = False MIRCOL_AS_EMIS = False
@ -126,6 +140,7 @@ EXPORT_DIR = ''
PER_FACE_1_OR_2_SIDED = True PER_FACE_1_OR_2_SIDED = True
tooltips = { tooltips = {
'GLOBAL_COORDS': "transform all vertices of all meshes to global coordinates",
'SKIP_DATA': "don't export mesh names as data fields", 'SKIP_DATA': "don't export mesh names as data fields",
'MIRCOL_AS_AMB': "export mirror color as ambient color", 'MIRCOL_AS_AMB': "export mirror color as ambient color",
'MIRCOL_AS_EMIS': "export mirror color as emissive color", 'MIRCOL_AS_EMIS': "export mirror color as emissive color",
@ -153,10 +168,11 @@ def update_RegistryInfo():
d['ONLY_SELECTED'] = ONLY_SELECTED d['ONLY_SELECTED'] = ONLY_SELECTED
d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED
d['tooltips'] = tooltips d['tooltips'] = tooltips
Blender.Registry.SetKey(REG_KEY, d, True) d['GLOBAL_COORDS'] = GLOBAL_COORDS
Registry.SetKey(REG_KEY, d, True)
# Looking for a saved key in Blender.Registry dict: # Looking for a saved key in Blender.Registry dict:
rd = Blender.Registry.GetKey(REG_KEY, True) rd = Registry.GetKey(REG_KEY, True)
if rd: if rd:
try: try:
@ -171,6 +187,7 @@ if rd:
ONLY_SELECTED = rd['ONLY_SELECTED'] ONLY_SELECTED = rd['ONLY_SELECTED']
NO_SPLIT = rd['NO_SPLIT'] NO_SPLIT = rd['NO_SPLIT']
PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED'] PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED']
GLOBAL_COORDS = rd['GLOBAL_COORDS']
except KeyError: update_RegistryInfo() except KeyError: update_RegistryInfo()
else: else:
@ -180,7 +197,7 @@ VERBOSE = True
CONFIRM_OVERWRITE = True CONFIRM_OVERWRITE = True
# check General scripts config key for default behaviors # check General scripts config key for default behaviors
rd = Blender.Registry.GetKey('General', True) rd = Registry.GetKey('General', True)
if rd: if rd:
try: try:
VERBOSE = rd['verbose'] VERBOSE = rd['verbose']
@ -194,9 +211,10 @@ DEFAULT_MAT = \
spec 0.5 0.5 0.5 shi 64 trans 0' spec 0.5 0.5 0.5 shi 64 trans 0'
# This transformation aligns Blender and AC3D coordinate systems: # This transformation aligns Blender and AC3D coordinate systems:
acmatrix = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1]) BLEND_TO_AC3D_MATRIX = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1])
def Round(f): def Round_s(f):
"Round to default precision and turn value to a string"
r = round(f,6) # precision set to 10e-06 r = round(f,6) # precision set to 10e-06
if r == int(r): if r == int(r):
return str(int(r)) return str(int(r))
@ -206,11 +224,15 @@ def Round(f):
def transform_verts(verts, m): def transform_verts(verts, m):
vecs = [] vecs = []
for v in verts: for v in verts:
vec = Mathutils.Vector([v[0],v[1],v[2], 1]) x, y, z = v.co
#vecs.append(Mathutils.VecMultMat(vec, m)) vec = Mathutils.Vector([x, y, z, 1])
vecs.append(vec*m) vecs.append(vec*m)
return vecs 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 # meshes with more than one texture assigned
@ -242,29 +264,27 @@ class FooMesh:
def __init__(self, tex, faces, mesh): def __init__(self, tex, faces, mesh):
self.name = mesh.name self.name = mesh.name
self.mesh = mesh self.mesh = mesh
self.faces = [] self.looseEdges = []
self.verts = verts = [] self.faceUV = mesh.faceUV
self.degr = mesh.degr
vidxs = [0]*len(mesh.verts) vidxs = [0]*len(mesh.verts)
faces2 = [0]*len(faces) foofaces = []
for f in faces: for f in faces:
self.faces.append(self.FooFace(self, f)) foofaces.append(self.FooFace(self, f))
for v in f.v: for v in f.v:
if v: vidxs[v.index] = 1 if v: vidxs[v.index] = 1
i = 0 i = 0
fooverts = []
for v in mesh.verts: for v in mesh.verts:
if vidxs[v.index]: if vidxs[v.index]:
verts.append(v) fooverts.append(v)
vidxs[v.index] = i vidxs[v.index] = i
i += 1 i += 1
for f in self.faces: for f in foofaces:
for v in f.v: for v in f.v:
if v: v.index = vidxs[v.v.index] if v: v.index = vidxs[v.v.index]
self.faces = foofaces
def hasFaceUV(self): self.verts = fooverts
return self.mesh.hasFaceUV()
def getMaxSmoothAngle(self):
return self.mesh.getMaxSmoothAngle()
class AC3DExport: # the ac3d exporter part class AC3DExport: # the ac3d exporter part
@ -272,15 +292,14 @@ class AC3DExport: # the ac3d exporter part
def __init__(self, scene_objects, filename): def __init__(self, scene_objects, filename):
global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT
global ERROR_MSG, MATIDX_ERROR global ERROR_MSG
MATIDX_ERROR = 0
header = 'AC3Db' header = 'AC3Db'
self.buf = '' self.buf = ''
self.mbuf = '' self.mbuf = ''
self.mlist = [] self.mlist = []
world_kids = 0 world_kids = 0
parents_list = self.parents_list = []
kids_dict = self.kids_dict = {} kids_dict = self.kids_dict = {}
objs = [] objs = []
exp_objs = self.exp_objs = [] exp_objs = self.exp_objs = []
@ -299,37 +318,50 @@ class AC3DExport: # the ac3d exporter part
objs = \ objs = \
[o for o in scene_objects if o.type in ['Mesh', 'Empty']] [o for o in scene_objects if o.type in ['Mesh', 'Empty']]
# create a tree from parents to children objects
for obj in objs[:]: for obj in objs[:]:
parent = obj.parent parent = obj.parent
list = [obj] lineage = [obj]
while parent: while parent:
parents_list.append(parent.name)
obj = parent obj = parent
parent = parent.getParent() parent = parent.getParent()
list.insert(0, obj) lineage.insert(0, obj)
dict = tree d = tree
for i in xrange(len(list)): for i in xrange(len(lineage)):
lname = list[i].getType()[:2] + list[i].name lname = lineage[i].getType()[:2] + lineage[i].name
if lname not in dict.keys(): if lname not in d.keys():
dict[lname] = {} d[lname] = {}
dict = dict[lname] d = d[lname]
# traverse the tree to get an ordered list of names of objects to export
self.traverse_dict(tree) self.traverse_dict(tree)
world_kids = len(tree.keys()) world_kids = len(tree.keys())
objlist = [Blender.Object.Get(name) for name in exp_objs] # 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'] meshlist = [o for o in objlist if o.type == 'Mesh']
self.MATERIALS(meshlist) # 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)
if not self.mbuf or ADD_DEFAULT_MAT: if not self.mbuf or ADD_DEFAULT_MAT:
self.mbuf = DEFAULT_MAT + '\n' + self.mbuf self.mbuf = "%s\n%s" % (DEFAULT_MAT, self.mbuf)
file.write(self.mbuf) file.write(self.mbuf)
file.write('OBJECT world\nkids %s\n' % world_kids) file.write('OBJECT world\nkids %s\n' % world_kids)
# write the objects
for obj in objlist: for obj in objlist:
self.obj = obj self.obj = obj
@ -337,21 +369,33 @@ class AC3DExport: # the ac3d exporter part
objname = obj.name objname = obj.name
kidsnum = kids_dict[objname] 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: if kidsnum:
self.OBJECT('group') self.OBJECT('group')
parent_is_mesh = 0 self.name(objname)
if objtype == 'Mesh': if objtype == 'Mesh':
kidsnum += 1 kidsnum += 1
parent_is_mesh = 1 if not GLOBAL_COORDS:
self.name(objname) localmatrix = obj.getMatrix('localspace')
if not obj.getParent():
localmatrix *= BLEND_TO_AC3D_MATRIX
self.rot(localmatrix.rotationPart())
self.loc(localmatrix.translationPart())
self.kids(kidsnum) self.kids(kidsnum)
if objtype == 'Mesh': if objtype == 'Mesh':
mesh = self.mesh = obj.getData() mesh = TMP_mesh # temporary mesh to hold actual (modified) mesh data
meshes = self.split_mesh(mesh) mesh.getFromObject(objname)
self.mesh = mesh
if mesh.faceUV:
meshes = self.split_mesh(mesh)
else:
meshes = [mesh]
if len(meshes) > 1: if len(meshes) > 1:
if NO_SPLIT or self.dont_split(objname): if NO_SPLIT or self.dont_split(objname):
self.export_mesh(mesh, obj) self.export_mesh(mesh, ob)
REPORT_DATA['nosplit'].append(objname) REPORT_DATA['nosplit'].append(objname)
else: else:
self.OBJECT('group') self.OBJECT('group')
@ -370,27 +414,27 @@ class AC3DExport: # the ac3d exporter part
file.close() file.close()
REPORT_DATA['main'].append("Done. Saved to: %s" % filename) REPORT_DATA['main'].append("Done. Saved to: %s" % filename)
def traverse_dict(self, dict): def traverse_dict(self, d):
kids_dict = self.kids_dict kids_dict = self.kids_dict
exp_objs = self.exp_objs exp_objs = self.exp_objs
keys = dict.keys() keys = d.keys()
for k in keys: for k in keys:
objname = k[2:] objname = k[2:]
klen = len(dict[k]) klen = len(d[k])
kids_dict[objname] = klen kids_dict[objname] = klen
if self.dont_export(objname): if self.dont_export(objname):
dict.pop(k) d.pop(k)
parent = Blender.Object.Get(objname).getParent() parent = Object.Get(objname).getParent()
if parent: kids_dict[parent.name] -= 1 if parent: kids_dict[parent.name] -= 1
REPORT_DATA['noexport'].append(objname) REPORT_DATA['noexport'].append(objname)
continue continue
if klen: if klen:
self.traverse_dict(dict[k]) self.traverse_dict(d[k])
exp_objs.insert(0, objname) exp_objs.insert(0, objname)
else: else:
if k.find('Em', 0) == 0: # Empty w/o children if k.find('Em', 0) == 0: # Empty w/o children
dict.pop(k) d.pop(k)
parent = Blender.Object.Get(objname).getParent() parent = Object.Get(objname).getParent()
if parent: kids_dict[parent.name] -= 1 if parent: kids_dict[parent.name] -= 1
else: else:
exp_objs.insert(0, objname) exp_objs.insert(0, objname)
@ -440,6 +484,7 @@ class AC3DExport: # the ac3d exporter part
for k in keys: for k in keys:
faces = tex_dict[k] faces = tex_dict[k]
foo_meshes.append(FooMesh(k, faces, mesh)) foo_meshes.append(FooMesh(k, faces, mesh))
foo_meshes[0].edges = get_loose_edges(mesh)
return foo_meshes return foo_meshes
return [mesh] return [mesh]
@ -449,17 +494,37 @@ class AC3DExport: # the ac3d exporter part
if not name: name = obj.name if not name: name = obj.name
self.name(name) self.name(name)
if not SKIP_DATA: if not SKIP_DATA:
self.data(len(mesh.name), mesh.name) meshname = obj.getData(name_only = True)
texline = self.texture(mesh.faces) self.data(len(meshname), meshname)
if texline: file.write(texline) if mesh.faceUV:
texline = self.texture(mesh.faces)
if texline: file.write(texline)
if AC3D_4: if AC3D_4:
self.crease(mesh.getMaxSmoothAngle()) self.crease(mesh.degr)
self.numvert(mesh.verts, obj.getMatrix())
self.numsurf(mesh.faces, mesh.hasFaceUV(), foomesh)
def MATERIALS(self, meshlist): # 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: for meobj in meshlist:
me = meobj.getData() me.getFromObject(meobj)
mat = me.materials mat = me.materials
mbuf = [] mbuf = []
mlist = self.mlist mlist = self.mlist
@ -469,23 +534,24 @@ class AC3DExport: # the ac3d exporter part
mlist.index(name) mlist.index(name)
except ValueError: except ValueError:
mlist.append(name) mlist.append(name)
M = Blender.Material.Get(name) M = Material.Get(name)
material = 'MATERIAL "%s"' % name material = 'MATERIAL "%s"' % name
mirCol = "%s %s %s" % (Round(M.mirCol[0]), Round(M.mirCol[1]), mirCol = "%s %s %s" % (Round_s(M.mirCol[0]), Round_s(M.mirCol[1]),
Round(M.mirCol[2])) Round_s(M.mirCol[2]))
rgb = "rgb %s %s %s" % (Round(M.R), Round(M.G), Round(M.B)) rgb = "rgb %s %s %s" % (Round_s(M.R), Round_s(M.G), Round_s(M.B))
amb = "amb %s %s %s" % (Round(M.amb), Round(M.amb), Round(M.amb)) ambval = Round_s(M.amb)
spec = "spec %s %s %s" % (Round(M.specCol[0]), amb = "amb %s %s %s" % (ambval, ambval, ambval)
Round(M.specCol[1]), Round(M.specCol[2])) spec = "spec %s %s %s" % (Round_s(M.specCol[0]),
Round_s(M.specCol[1]), Round_s(M.specCol[2]))
if AC3D_4: if AC3D_4:
emit = Round(M.emit) emit = Round_s(M.emit)
emis = "emis %s %s %s" % (emit, emit, emit) emis = "emis %s %s %s" % (emit, emit, emit)
shival = int(M.spec * 64) shival = int(M.spec * 64)
else: else:
emis = "emis 0 0 0" emis = "emis 0 0 0"
shival = 72 shival = 72
shi = "shi %s" % shival shi = "shi %s" % shival
trans = "trans %s" % (Round(1 - M.alpha)) trans = "trans %s" % (Round_s(1 - M.alpha))
if MIRCOL_AS_AMB: if MIRCOL_AS_AMB:
amb = "amb %s" % mirCol amb = "amb %s" % mirCol
if MIRCOL_AS_EMIS: if MIRCOL_AS_EMIS:
@ -516,12 +582,12 @@ class AC3DExport: # the ac3d exporter part
tex = f.image.name tex = f.image.name
break break
if tex: if tex:
image = Blender.Image.Get(tex) image = Image.Get(tex)
texfname = image.filename texfname = image.filename
if SET_TEX_DIR: if SET_TEX_DIR:
texfname = Blender.sys.basename(texfname) texfname = bsys.basename(texfname)
if TEX_DIR: if TEX_DIR:
texfname = Blender.sys.join(TEX_DIR, texfname) texfname = bsys.join(TEX_DIR, texfname)
buf = 'texture "%s"\n' % texfname buf = 'texture "%s"\n' % texfname
xrep = image.xrep xrep = image.xrep
yrep = image.yrep yrep = image.yrep
@ -530,41 +596,65 @@ class AC3DExport: # the ac3d exporter part
def rot(self, matrix): def rot(self, matrix):
rot = '' rot = ''
not_I = 0 not_I = 0 # not identity
matstr = []
for i in [0, 1, 2]: for i in [0, 1, 2]:
r = map(Round, matrix[i]) r = map(Round_s, matrix[i])
not_I += (r[0] != '0.0')+(r[1] != '0.0')+(r[2] != '0.0') not_I += (r[0] != '0')+(r[1] != '0')+(r[2] != '0')
not_I -= (r[i] == '1.0') not_I -= (r[i] == '1')
for j in [0, 1, 2]: for j in [0, 1, 2]:
rot = "%s %s" % (rot, r[j]) matstr.append(' %s' % r[j])
if not_I: if not_I: # no need to write identity
self.file.write('rot %s\n' % rot.strip()) self.file.write('rot%s\n' % "".join(matstr))
def loc(self, loc): def loc(self, loc):
loc = map(Round, loc) loc = map(Round_s, loc)
if loc[0] or loc[1] or loc[2]: if loc != ['0', '0', '0']: # no need to write default
self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2])) self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2]))
def crease(self, crease): def crease(self, crease):
self.file.write('crease %s\n' % crease) self.file.write('crease %f\n' % crease)
def numvert(self, verts, matrix): def numvert(self, verts, matrix):
file = self.file file = self.file
file.write("numvert %s\n" % len(verts)) nvstr = []
m = matrix * acmatrix nvstr.append("numvert %s\n" % len(verts))
verts = transform_verts(verts, m)
for v in verts:
v0, v1, v2 = Round(v[0]), Round(v[1]), Round(v[2])
file.write("%s %s %s\n" % (v0, v1, v2))
def numsurf(self, faces, hasFaceUV, foomesh = False): 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)
global ADD_DEFAULT_MAT, MATIDX_ERROR
file = self.file file = self.file
file.write("numsurf %s\n" % len(faces)) file.write("numsurf %s\n" % (len(faces) + len(looseEdges)))
if not foomesh: verts = self.mesh.verts if not foomesh: verts = list(self.mesh.verts)
mlist = self.mlist mlist = self.mlist
omlist = {} omlist = {}
@ -573,33 +663,33 @@ class AC3DExport: # the ac3d exporter part
for i in range(len(objmats)): for i in range(len(objmats)):
objmats[i] = objmats[i].name objmats[i] = objmats[i].name
for f in faces: for f in faces:
m_idx = f.materialIndex m_idx = f.mat
try: try:
m_idx = mlist.index(objmats[m_idx]) m_idx = mlist.index(objmats[m_idx])
except IndexError: except IndexError:
if not MATIDX_ERROR: if not lc_MATIDX_ERROR:
rdat = REPORT_DATA['warns'] rdat = REPORT_DATA['warns']
rdat.append("Object %s" % self.obj.name) rdat.append("Object %s" % self.obj.name)
rdat.append("has at least one material *index* assigned but not") rdat.append("has at least one material *index* assigned but not")
rdat.append("defined (not linked to an existing material).") rdat.append("defined (not linked to an existing material).")
rdat.append("Result: some faces may be exported with a wrong color.") rdat.append("Result: some faces may be exported with a wrong color.")
rdat.append("You can link materials in the Edit Buttons window (F9).") rdat.append("You can assign materials in the Edit Buttons window (F9).")
elif not matidx_error_told: elif not matidx_error_told:
midxmsg = "- Same for object %s." % self.obj.name midxmsg = "- Same for object %s." % self.obj.name
REPORT_DATA['warns'].append(midxmsg) REPORT_DATA['warns'].append(midxmsg)
MATIDX_ERROR += 1 lc_MATIDX_ERROR += 1
matidx_error_told = 1 matidx_error_told = 1
m_idx = 0 m_idx = 0
refs = len(f) refs = len(f)
flaglow = (refs == 2) << 1 flaglow = 0 # polygon
if PER_FACE_1_OR_2_SIDED: # per face attribute if lc_PER_FACE_1_OR_2_SIDED and hasFaceUV: # per face attribute
two_side = f.mode & Blender.NMesh.FaceModes['TWOSIDE'] two_side = f.mode & lc_FACE_TWOSIDED
else: # global, for the whole mesh else: # global, for the whole mesh
two_side = self.mesh.mode & Blender.NMesh.Modes['TWOSIDED'] two_side = self.mesh.mode & lc_MESH_TWOSIDED
two_side = (two_side > 0) << 1 two_side = (two_side > 0) << 1
flaghigh = f.smooth | two_side flaghigh = f.smooth | two_side
surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow) surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
if ADD_DEFAULT_MAT and objmats: m_idx += 1 if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1
matstr = "mat %s\n" % m_idx matstr = "mat %s\n" % m_idx
refstr = "refs %s\n" % refs refstr = "refs %s\n" % refs
u, v, vi = 0, 0, 0 u, v, vi = 0, 0, 0
@ -625,6 +715,24 @@ class AC3DExport: # the ac3d exporter part
file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr)) file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr))
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 0\n" # for now, use first material
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 # End of Class AC3DExport
from Blender.Window import FileSelector from Blender.Window import FileSelector
@ -687,7 +795,9 @@ def fs_callback(filename):
# -- End of definitions # -- End of definitions
scn = Blender.Scene.GetCurrent() scn = Blender.Scene.GetCurrent()
if ONLY_SELECTED: if ONLY_SELECTED:
OBJS = list(scn.objects.context) OBJS = list(scn.objects.context)
else: else:

@ -2,7 +2,7 @@
""" Registration info for Blender menus: """ Registration info for Blender menus:
Name: 'AC3D (.ac)...' Name: 'AC3D (.ac)...'
Blender: 236 Blender: 242
Group: 'Import' Group: 'Import'
Tip: 'Import an AC3D (.ac) file.' Tip: 'Import an AC3D (.ac) file.'
""" """
@ -10,7 +10,7 @@ Tip: 'Import an AC3D (.ac) file.'
__author__ = "Willian P. Germano" __author__ = "Willian P. Germano"
__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", __url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org",
"PLib 3d gaming lib, http://plib.sf.net") "PLib 3d gaming lib, http://plib.sf.net")
__version__ = "2.36a 2005-12-04" __version__ = "2.43 2007-01-14"
__bpydoc__ = """\ __bpydoc__ = """\
This script imports AC3D models into Blender. This script imports AC3D models into Blender.
@ -29,8 +29,6 @@ Known issues:<br>
None. None.
Config Options:<br> Config Options:<br>
- group (toggle): if "on", grouped objects in the .ac file are parented to
Empties.
- textures dir (string): if non blank, when imported texture paths are - textures dir (string): if non blank, when imported texture paths are
wrong in the .ac file, Blender will also look for them at this dir. wrong in the .ac file, Blender will also look for them at this dir.
@ -43,13 +41,13 @@ users can configure (see config options above).
# $Id$ # $Id$
# #
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# AC3DImport version 2.36a Dec 04, 2005 # AC3DImport version 2.43 Jan 04, 2007
# Program versions: Blender 2.36+ and AC3Db files (means version 0xb) # Program versions: Blender 2.43 and AC3Db files (means version 0xb)
# changed: fixed a bug: error on 1 vertex "closed" polylines # changed: updated for new Blender version, Mesh module
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK ***** # ***** BEGIN GPL LICENSE BLOCK *****
# #
# Copyright (C) 2005: Willian P. Germano, wgermano _at_ ig.com.br # Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -74,33 +72,30 @@ users can configure (see config options above).
# fixing. Avoiding or triangulating concave n-gons in AC3D is a simple way to # fixing. Avoiding or triangulating concave n-gons in AC3D is a simple way to
# avoid problems. # avoid problems.
from math import radians
import Blender import Blender
from Blender import Registry from Blender import Scene, Object, Mesh, Lamp, Registry, sys as bsys, Window, Image, Material
from Blender.sys import dirsep from Blender.sys import dirsep
from Blender.Mathutils import Vector, Matrix, Euler
# Default folder for AC3D textures, to override wrong paths, change to your # Default folder for AC3D textures, to override wrong paths, change to your
# liking or leave as "": # liking or leave as "":
TEXTURES_DIR = "" TEXTURES_DIR = ""
# Set 'GROUP' to True to make Blender group imported objects using Empties,
# to reproduce the object hierarchy in the .ac file
GROUP = False
tooltips = { tooltips = {
'TEXTURES_DIR': 'additional dir to look for missing textures', 'TEXTURES_DIR': 'additional dir to look for missing textures'
'GROUP': 'mimick grouping information by parenting grouped meshes to empties'
} }
def update_registry(): def update_registry():
global GROUP, TEXTURES_DIR global TEXTURES_DIR
rd = dict([('GROUP', GROUP), ('TEXTURES_DIR', TEXTURES_DIR)]) rd = dict([('TEXTURES_DIR', TEXTURES_DIR)])
Registry.SetKey('ac3d_import', rd, True) Registry.SetKey('ac3d_import', rd, True)
rd = Registry.GetKey('ac3d_import', True) rd = Registry.GetKey('ac3d_import', True)
if rd: if rd:
TEXTURES_DIR = rd['TEXTURES_DIR'] TEXTURES_DIR = rd['TEXTURES_DIR']
GROUP = rd['GROUP']
else: update_registry() else: update_registry()
if TEXTURES_DIR: if TEXTURES_DIR:
@ -119,11 +114,31 @@ if rd:
errmsg = "" errmsg = ""
# Matrix to align ac3d's coordinate system with Blender's one,
# it's a -90 degrees rotation around the x axis:
AC_TO_BLEND_MATRIX = Matrix([1, 0, 0], [0, 0, 1], [0, -1, 0])
AC_WORLD = 0
AC_GROUP = 1
AC_POLY = 2
AC_LIGHT = 3
AC_OB_TYPES = {
'world': AC_WORLD,
'group': AC_GROUP,
'poly': AC_POLY,
'light': AC_LIGHT
}
def inform(msg): def inform(msg):
global VERBOSE global VERBOSE
if VERBOSE: print msg if VERBOSE: print msg
def euler_in_radians(eul):
"Used while there's a bug in the BPY API"
eul.x = radians(eul.x)
eul.y = radians(eul.y)
eul.z = radians(eul.z)
return eul
class Obj: class Obj:
@ -135,23 +150,31 @@ class Obj:
self.tex = '' self.tex = ''
self.texrep = [1,1] self.texrep = [1,1]
self.texoff = None self.texoff = None
self.loc = [0, 0, 0] self.loc = []
self.rot = [] self.rot = []
self.size = []
self.crease = 30 self.crease = 30
self.vlist = [] self.vlist = []
self.flist = [] self.flist_cfg = []
self.flist_v = []
self.flist_uv = []
self.elist = []
self.matlist = [] self.matlist = []
self.kids = 0 self.kids = 0
self.bl_obj = None # the actual Blender object created from this data
class AC3DImport: class AC3DImport:
def __init__(self, filename): def __init__(self, filename):
global errmsg global errmsg
self.scene = Scene.GetCurrent()
self.i = 0 self.i = 0
errmsg = '' errmsg = ''
self.importdir = Blender.sys.dirname(filename) self.importdir = bsys.dirname(filename)
try: try:
file = open(filename, 'r') file = open(filename, 'r')
except IOError, (errno, strerror): except IOError, (errno, strerror):
@ -187,8 +210,7 @@ class AC3DImport:
self.objlist = [] self.objlist = []
self.mlist = [] self.mlist = []
self.dads = [] self.kidsnumlist = []
self.kids = []
self.dad = None self.dad = None
self.lines = file.readlines() self.lines = file.readlines()
@ -199,12 +221,12 @@ class AC3DImport:
self.testAC3DImport() self.testAC3DImport()
def parse_obj(self, value): def parse_obj(self, value):
if self.kids: if self.kidsnumlist:
while not self.kids[-1]: while not self.kidsnumlist[-1]:
self.kids.pop() self.kidsnumlist.pop()
self.dad = self.dad.dad self.dad = self.dad.dad
self.kids[-1] -= 1 self.kidsnumlist[-1] -= 1
new = Obj(value) new = Obj(AC_OB_TYPES[value])
new.dad = self.dad new.dad = self.dad
new.name = value new.name = value
self.objlist.append(new) self.objlist.append(new)
@ -212,7 +234,7 @@ class AC3DImport:
def parse_kids(self, value): def parse_kids(self, value):
kids = int(value) kids = int(value)
if kids: if kids:
self.kids.append(kids) self.kidsnumlist.append(kids)
self.dad = self.objlist[-1] self.dad = self.objlist[-1]
self.objlist[-1].kids = kids self.objlist[-1].kids = kids
@ -269,23 +291,24 @@ class AC3DImport:
def parse_rot(self, trash): def parse_rot(self, trash):
i = self.i - 1 i = self.i - 1
ob = self.objlist[-1]
rot = self.lines[i].split(' ', 1)[1] rot = self.lines[i].split(' ', 1)[1]
rot = map(float, rot.split()) rot = map(float, rot.split())
self.objlist[-1].rot = rot matrix = Matrix(rot[:3], rot[3:6], rot[6:])
ob.rot = matrix
size = matrix.scalePart() # vector
ob.size = size
def parse_loc(self, trash): def parse_loc(self, trash):
i = self.i - 1 i = self.i - 1
loc = self.lines[i].split(' ', 1)[1] loc = self.lines[i].split(' ', 1)[1]
loc = map(float, loc.split()) loc = map(float, loc.split())
self.objlist[-1].loc = loc self.objlist[-1].loc = Vector(loc)
def parse_crease(self, value): def parse_crease(self, value):
# AC3D: range is [0.0, 180.0]; Blender: [1, 80] # AC3D: range is [0.0, 180.0]; Blender: [1, 80]
try: value = float(value)
value = int(value) self.objlist[-1].crease = int(value)
except ValueError:
value = int(float(value)) # duh
self.objlist[-1].crease = value
def parse_vert(self, value): def parse_vert(self, value):
i = self.i i = self.i
@ -303,28 +326,6 @@ class AC3DImport:
self.i = i self.i = i
rot = obj.rot
if rot:
nv = len(vlist)
for j in range(nv):
v = vlist[j]
t = [0,0,0]
t[0] = rot[0]*v[0] + rot[3]*v[1] + rot[6]*v[2]
t[1] = rot[1]*v[0] + rot[4]*v[1] + rot[7]*v[2]
t[2] = rot[2]*v[0] + rot[5]*v[1] + rot[8]*v[2]
vlist[j] = t
loc = obj.loc
dad = obj.dad
while dad:
for j in [0, 1, 2]:
loc[j] += dad.loc[j]
dad = dad.dad
for v in vlist:
for j in [0, 1, 2]:
v[j] += loc[j]
def parse_surf(self, value): def parse_surf(self, value):
i = self.i i = self.i
is_smooth = 0 is_smooth = 0
@ -333,6 +334,7 @@ class AC3DImport:
obj = self.objlist[-1] obj = self.objlist[-1]
matlist = obj.matlist matlist = obj.matlist
numsurf = int(value) numsurf = int(value)
NUMSURF = numsurf
while numsurf: while numsurf:
flags = lines[i].split() flags = lines[i].split()
@ -349,45 +351,51 @@ class AC3DImport:
i += 3 i += 3
face = [] face = []
faces = [] faces = []
edges = []
fuv = [] fuv = []
fuvs = []
rfs = refs rfs = refs
while rfs: while rfs:
line = lines[i].split() line = lines[i].split()
v = int(line[0]) v = int(line[0])
uv = [float(line[1]), float(line[2])] uv = [float(line[1]), float(line[2])]
face.append([v, uv]) face.append(v)
fuv.append(Vector(uv))
rfs -= 1 rfs -= 1
i += 1 i += 1
if flaglow: if flaglow: # it's a line or closed line, not a polygon
while len(face) >= 2: while len(face) >= 2:
cut = face[:2] cut = face[:2]
faces.append(cut) edges.append(cut)
face = face[1:] face = face[1:]
if flaglow == 1 and faces: if flaglow == 1 and edges:
face = [faces[-1][-1], faces[0][0]] face = [edges[-1][-1], edges[0][0]]
faces.append(face) edges.append(face)
else: else:
while len(face) > 4: while len(face) > 4:
cut = face[:4] cut = face[:4]
cutuv = fuv[:4]
face = face[3:] face = face[3:]
fuv = fuv[3:]
face.insert(0, cut[0]) face.insert(0, cut[0])
faces.append(cut) fuv.insert(0, cutuv[0])
faces.append(cut)
fuvs.append(cutuv)
faces.append(face) faces.append(face)
fuvs.append(fuv)
for f in faces: obj.flist_cfg.extend([[mat, is_smooth, twoside]] * len(faces))
f.append(mat) obj.flist_v.extend(faces)
f.append(is_smooth) obj.flist_uv.extend(fuvs)
f.append(twoside) obj.elist.extend(edges) # loose edges
self.objlist[-1].flist.append(f)
numsurf -= 1 numsurf -= 1
self.i = i self.i = i
def parse_file(self): def parse_file(self):
@ -408,14 +416,86 @@ class AC3DImport:
i = self.i i = self.i
line = lines[i].split() line = lines[i].split()
# for each group of meshes we try to find one that can be used as
# parent of the group in Blender.
# If not found, we can use an Empty as parent.
def found_parent(self, groupname, olist):
l = [o for o in olist if o.type == AC_POLY \
and not o.kids and not o.rot and not o.loc]
if l:
if len(l) > 1:
for o in l:
if o.name == groupname:
return o
return l[0]
return None
def build_hierarchy(self):
blmatrix = AC_TO_BLEND_MATRIX
olist = self.objlist[1:]
olist.reverse()
newlist = []
for o in olist:
kids = o.kids
if kids:
children = newlist[-kids:]
newlist = newlist[:-kids]
if o.type == AC_GROUP:
parent = self.found_parent(o.name, children)
if parent:
children.remove(parent)
o.bl_obj = parent.bl_obj
else: # not found, use an empty
empty = Object.New('Empty', o.name)
self.scene.link(empty)
empty.select(True)
o.bl_obj = empty
bl_children = [c.bl_obj for c in children]
o.bl_obj.makeParent(bl_children, 0, 1)
for child in children:
if child.loc:
child.bl_obj.setLocation(child.loc)
if child.rot:
eul = euler_in_radians(child.rot.toEuler())
child.bl_obj.setEuler(eul)
if child.size:
child.bl_obj.size = child.size
newlist.append(o)
for o in newlist: # newlist now only has objs w/o parents
blob = o.bl_obj
if o.loc:
blob.setLocation(o.loc * blmatrix)
if o.size:
o.bl_obj.size = o.size
if not o.rot:
blob.setEuler([1.5707963267948966, 0, 0])
else:
matrix = o.rot * blmatrix
eul = euler_in_radians(matrix.toEuler())
blob.setEuler(eul)
def testAC3DImport(self): def testAC3DImport(self):
global GROUP
scene = Blender.Scene.GetCurrent() FACE_TWOSIDE = Mesh.FaceModes['TWOSIDE']
FACE_TEX = Mesh.FaceModes['TEX']
MESH_AUTOSMOOTH = Mesh.Modes['AUTOSMOOTH']
scene = self.scene
bl_images = {} # loaded texture images
objlist = self.objlist[1:] # skip 'world'
bmat = [] bmat = []
for mat in self.mlist: for mat in self.mlist:
name = mat[0] name = mat[0]
m = Blender.Material.New(name) m = Material.New(name)
m.rgbCol = (mat[1][0], mat[1][1], mat[1][2]) m.rgbCol = (mat[1][0], mat[1][1], mat[1][2])
m.amb = mat[2] m.amb = mat[2]
m.emit = mat[3] m.emit = mat[3]
@ -424,102 +504,133 @@ class AC3DImport:
m.alpha = mat[6] m.alpha = mat[6]
bmat.append(m) bmat.append(m)
for obj in self.objlist: obj_idx = 0 # index of current obj in loop
if obj.type == 'world': for obj in objlist:
if obj.type == AC_GROUP:
continue continue
elif obj.type == 'group': elif obj.type == AC_LIGHT:
if not GROUP: continue light = Lamp.New('Lamp')
empty = Blender.Object.New('Empty') object = scene.objects.new(light, obj.name)
empty.name = obj.name object.select(True)
scene.link(empty) obj.bl_obj = object
if self.dads: if obj.data:
dadobj = Blender.Object.get(self.dads.pop()) light.name = obj.data
dadobj.makeParent([empty])
while obj.kids:
self.dads.append(empty.name)
obj.kids -= 1
continue continue
mesh = Blender.NMesh.New()
# type AC_POLY:
# old .ac files used empty meshes as groups, convert to a real ac group
if not obj.vlist:
obj.type = AC_GROUP
continue
mesh = Mesh.New()
object = scene.objects.new(mesh, obj.name)
object.select(True)
obj.bl_obj = object
if obj.data: mesh.name = obj.data if obj.data: mesh.name = obj.data
mesh.setMaxSmoothAngle(obj.crease) # will clamp to [1, 80] mesh.degr = obj.crease # will auto clamp to [1, 80]
mesh.hasFaceUV(1)
tex = None mesh.verts.extend(obj.vlist)
if obj.tex != '':
try:
tex = Blender.Image.Load(obj.tex)
# Commented because it's unnecessary:
#tex.xrep = int(obj.texrep[0])
#tex.yrep = int(obj.texrep[1])
except:
basetexname = Blender.sys.basename(obj.tex)
try:
obj.tex = self.importdir + '/' + basetexname
tex = Blender.Image.Load(obj.tex)
except:
try:
obj.tex = TEXTURES_DIR + basetexname
tex = Blender.Image.Load(obj.tex)
except:
inform("Couldn't load texture: %s" % basetexname)
for v in obj.vlist:
bvert = Blender.NMesh.Vert(v[0],v[1],v[2])
mesh.verts.append(bvert)
objmat_indices = [] objmat_indices = []
for mat in bmat: for mat in bmat:
if bmat.index(mat) in obj.matlist: if bmat.index(mat) in obj.matlist:
objmat_indices.append(bmat.index(mat)) objmat_indices.append(bmat.index(mat))
mesh.materials.append(mat) mesh.materials += [mat]
for f in obj.flist:
twoside = f[-1] for e in obj.elist:
is_smooth = f[-2] mesh.edges.extend(e)
fmat = f[-3]
f=f[:-3] mesh.faces.extend(obj.flist_v)
bface = Blender.NMesh.Face()
# checking if the .ac file had duplicate faces (Blender ignores them):
if len(mesh.faces) != len(obj.flist_v):
# it has, ugh. Let's clean the uv list:
lenfl = len(obj.flist_v)
flist = obj.flist_v
uvlist = obj.flist_uv
cfglist = obj.flist_cfg
for f in flist:
f.sort()
for fi in range(lenfl - 1):
if flist[fi] in flist[fi+1:]:
uvlist.pop(fi)
cfglist.pop(fi)
if obj.flist_v: mesh.faceUV = True
img = None
tex = None
if obj.tex != '' and mesh.faceUV:
baseimgname = bsys.basename(obj.tex)
if obj.tex in bl_images.keys():
img = bl_images[obj.txt]
tex = bl_textures[img]
else:
try:
img = Image.Load(obj.tex)
# Commented because it's unnecessary:
#img.xrep = int(obj.texrep[0])
#img.yrep = int(obj.texrep[1])
except:
try:
obj.tex = self.importdir + '/' + baseimgname
img = Image.Load(obj.tex)
except:
try:
obj.tex = TEXTURES_DIR + baseimgname
img = Image.Load(obj.tex)
except:
inform("Couldn't load texture: %s" % baseimgname)
if img:
bl_images[obj.tex] = img
i = 0
for f in obj.flist_cfg:
fmat = f[0]
is_smooth = f[1]
twoside = f[2]
bface = mesh.faces[i]
bface.smooth = is_smooth bface.smooth = is_smooth
if twoside: bface.mode |= Blender.NMesh.FaceModes['TWOSIDE'] if twoside: bface.mode |= FACE_TWOSIDE
if tex: if img:
bface.mode |= Blender.NMesh.FaceModes['TEX'] bface.mode |= FACE_TEX
bface.image = tex bface.image = img
bface.materialIndex = objmat_indices.index(fmat) bface.mat = objmat_indices.index(fmat)
fuv = obj.flist_uv[i]
if obj.texoff: if obj.texoff:
uoff = obj.texoff[0] uoff = obj.texoff[0]
voff = obj.texoff[1] voff = obj.texoff[1]
urep = obj.texrep[0] urep = obj.texrep[0]
vrep = obj.texrep[1] vrep = obj.texrep[1]
for vi in range(len(f)): for uv in fuv:
f[vi][1][0] *= urep uv[0] *= urep
f[vi][1][1] *= vrep uv[1] *= vrep
f[vi][1][0] += uoff uv[0] += uoff
f[vi][1][1] += voff uv[1] += voff
for vi in range(len(f)): mesh.faces[i].uv = fuv
bface.v.append(mesh.verts[f[vi][0]])
bface.uv.append((f[vi][1][0], f[vi][1][1]))
#mesh.faces.append(bface)
# quick hack, will switch from NMesh to Mesh later:
if len(bface.v) > 1: mesh.addFace(bface)
mesh.mode = 0 i += 1
object = Blender.NMesh.PutRaw(mesh)
object.setName(obj.name) mesh.mode = MESH_AUTOSMOOTH
object.setEuler([1.5707963,0,0]) # align ac3d w/ Blender
if self.dads: obj_idx += 1
dadobj = Blender.Object.get(self.dads.pop())
dadobj.makeParent([object]) self.build_hierarchy()
scene.update()
# End of class AC3DImport # End of class AC3DImport
def filesel_callback(filename): def filesel_callback(filename):
inform("Trying to import AC3D model(s) from %s ..." % filename) inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename)
Blender.Window.WaitCursor(1) Window.WaitCursor(1)
starttime = Blender.sys.time() starttime = bsys.time()
test = AC3DImport(filename) test = AC3DImport(filename)
Blender.Window.WaitCursor(0) Window.WaitCursor(0)
endtime = Blender.sys.time() - starttime endtime = bsys.time() - starttime
inform('... done! Data imported in %.3f seconds.\n' % endtime) inform('Done! Data imported in %.3f seconds.\n' % endtime)
Blender.Window.FileSelector(filesel_callback, "Import AC3D", "*.ac") Window.FileSelector(filesel_callback, "Import AC3D", "*.ac")