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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillian Padovani Germano <wpgermano@gmail.com>2007-01-14 21:13:47 +0300
committerWillian Padovani Germano <wpgermano@gmail.com>2007-01-14 21:13:47 +0300
commit82bfd281f2ef3fc793cff335051d8c50ee142679 (patch)
treefcba686a068cbb16fccac490f493eb908e631ab0 /release
parentd90c686bdb11f8d5d48671e8de283db1bcf64ddf (diff)
Scripts:
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.
Diffstat (limited to 'release')
-rw-r--r--release/scripts/ac3d_export.py332
-rw-r--r--release/scripts/ac3d_import.py413
2 files changed, 483 insertions, 262 deletions
diff --git a/release/scripts/ac3d_export.py b/release/scripts/ac3d_export.py
index 2180fa1e128..80e88d933c8 100644
--- a/release/scripts/ac3d_export.py
+++ b/release/scripts/ac3d_export.py
@@ -2,7 +2,7 @@
""" Registration info for Blender menus:
Name: 'AC3D (.ac)...'
-Blender: 236
+Blender: 242
Group: 'Export'
Tip: 'Export selected meshes to AC3D (.ac) format'
"""
@@ -10,7 +10,7 @@ Tip: 'Export selected meshes to AC3D (.ac) format'
__author__ = "Willian P. Germano"
__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org",
"PLib 3d gaming lib, http://plib.sf.net")
-__version__ = "2.41a 2006-06-16"
+__version__ = "2.43 2007-01-14"
__bpydoc__ = """\
This script exports selected Blender meshes to AC3D's .ac file format.
@@ -37,6 +37,7 @@ Config Options:<br>
toggle:<br>
- 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>
+ - 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)
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,
@@ -56,10 +57,13 @@ to export (read notes below about tokens, too);<br>
toggle is "on".
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>
- Parenting with meshes or empties as parents is converted to AC3D group
-information;<br>
+ Parents are exported as a group containing both the parent and its children;<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.
"""
@@ -67,17 +71,20 @@ information;<br>
# $Id$
#
# --------------------------------------------------------------------------
-# AC3DExport version 2.41
-# Program versions: Blender 2.36+ and AC3Db files (means version 0xb)
-# new: faster, supports multiple textures per object and parenting is
-# properly exported as group info, adapted to work with the Config Editor
+# AC3DExport version 2.43
+# 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.
# --------------------------------------------------------------------------
# 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 *****
#
-# 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
# modify it under the terms of the GNU General Public License
@@ -94,8 +101,8 @@ information;<br>
# --------------------------------------------------------------------------
import Blender
+from Blender import Object, Mesh, Material, Image, Mathutils, Registry
from Blender import sys as bsys
-from Blender import Mathutils
# Globals
ERROR_MSG = '' # popup error msg
@@ -108,11 +115,18 @@ REPORT_DATA = {
}
TOKENS_DONT_EXPORT = ['!', '#']
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'
# config options:
+GLOBAL_COORDS = True
SKIP_DATA = False
MIRCOL_AS_AMB = False
MIRCOL_AS_EMIS = False
@@ -126,6 +140,7 @@ 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",
@@ -153,10 +168,11 @@ def update_RegistryInfo():
d['ONLY_SELECTED'] = ONLY_SELECTED
d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED
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:
-rd = Blender.Registry.GetKey(REG_KEY, True)
+rd = Registry.GetKey(REG_KEY, True)
if rd:
try:
@@ -171,6 +187,7 @@ if rd:
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:
@@ -180,7 +197,7 @@ VERBOSE = True
CONFIRM_OVERWRITE = True
# check General scripts config key for default behaviors
-rd = Blender.Registry.GetKey('General', True)
+rd = Registry.GetKey('General', True)
if rd:
try:
VERBOSE = rd['verbose']
@@ -194,9 +211,10 @@ DEFAULT_MAT = \
spec 0.5 0.5 0.5 shi 64 trans 0'
# 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
if r == int(r):
return str(int(r))
@@ -206,11 +224,15 @@ def Round(f):
def transform_verts(verts, m):
vecs = []
for v in verts:
- vec = Mathutils.Vector([v[0],v[1],v[2], 1])
- #vecs.append(Mathutils.VecMultMat(vec, m))
+ 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
@@ -242,29 +264,27 @@ class FooMesh:
def __init__(self, tex, faces, mesh):
self.name = mesh.name
self.mesh = mesh
- self.faces = []
- self.verts = verts = []
+ self.looseEdges = []
+ self.faceUV = mesh.faceUV
+ self.degr = mesh.degr
vidxs = [0]*len(mesh.verts)
- faces2 = [0]*len(faces)
+ foofaces = []
for f in faces:
- self.faces.append(self.FooFace(self, f))
+ 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]:
- verts.append(v)
+ fooverts.append(v)
vidxs[v.index] = i
i += 1
- for f in self.faces:
+ for f in foofaces:
for v in f.v:
if v: v.index = vidxs[v.v.index]
-
- def hasFaceUV(self):
- return self.mesh.hasFaceUV()
-
- def getMaxSmoothAngle(self):
- return self.mesh.getMaxSmoothAngle()
+ self.faces = foofaces
+ self.verts = fooverts
class AC3DExport: # the ac3d exporter part
@@ -272,15 +292,14 @@ class AC3DExport: # the ac3d exporter part
def __init__(self, scene_objects, filename):
global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT
- global ERROR_MSG, MATIDX_ERROR
-
- MATIDX_ERROR = 0
+ global ERROR_MSG
header = 'AC3Db'
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 = []
@@ -299,37 +318,50 @@ class AC3DExport: # the ac3d exporter part
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
- list = [obj]
+ lineage = [obj]
while parent:
+ parents_list.append(parent.name)
obj = parent
parent = parent.getParent()
- list.insert(0, obj)
+ lineage.insert(0, obj)
- dict = tree
- for i in xrange(len(list)):
- lname = list[i].getType()[:2] + list[i].name
- if lname not in dict.keys():
- dict[lname] = {}
- dict = dict[lname]
+ 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())
- 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']
- 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:
- self.mbuf = DEFAULT_MAT + '\n' + self.mbuf
+ self.mbuf = "%s\n%s" % (DEFAULT_MAT, self.mbuf)
file.write(self.mbuf)
file.write('OBJECT world\nkids %s\n' % world_kids)
+ # write the objects
+
for obj in objlist:
self.obj = obj
@@ -337,21 +369,33 @@ class AC3DExport: # the ac3d exporter part
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')
- parent_is_mesh = 0
+ self.name(objname)
if objtype == 'Mesh':
kidsnum += 1
- parent_is_mesh = 1
- self.name(objname)
+ 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 = self.mesh = obj.getData()
- meshes = self.split_mesh(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, obj)
+ self.export_mesh(mesh, ob)
REPORT_DATA['nosplit'].append(objname)
else:
self.OBJECT('group')
@@ -370,27 +414,27 @@ class AC3DExport: # the ac3d exporter part
file.close()
REPORT_DATA['main'].append("Done. Saved to: %s" % filename)
- def traverse_dict(self, dict):
+ def traverse_dict(self, d):
kids_dict = self.kids_dict
exp_objs = self.exp_objs
- keys = dict.keys()
+ keys = d.keys()
for k in keys:
objname = k[2:]
- klen = len(dict[k])
+ klen = len(d[k])
kids_dict[objname] = klen
if self.dont_export(objname):
- dict.pop(k)
- parent = Blender.Object.Get(objname).getParent()
+ 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(dict[k])
+ self.traverse_dict(d[k])
exp_objs.insert(0, objname)
else:
if k.find('Em', 0) == 0: # Empty w/o children
- dict.pop(k)
- parent = Blender.Object.Get(objname).getParent()
+ d.pop(k)
+ parent = Object.Get(objname).getParent()
if parent: kids_dict[parent.name] -= 1
else:
exp_objs.insert(0, objname)
@@ -440,6 +484,7 @@ class AC3DExport: # the ac3d exporter part
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]
@@ -449,17 +494,37 @@ class AC3DExport: # the ac3d exporter part
if not name: name = obj.name
self.name(name)
if not SKIP_DATA:
- self.data(len(mesh.name), mesh.name)
- texline = self.texture(mesh.faces)
- if texline: file.write(texline)
+ 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.getMaxSmoothAngle())
- self.numvert(mesh.verts, obj.getMatrix())
- self.numsurf(mesh.faces, mesh.hasFaceUV(), foomesh)
-
- def MATERIALS(self, meshlist):
+ 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 = meobj.getData()
+ me.getFromObject(meobj)
mat = me.materials
mbuf = []
mlist = self.mlist
@@ -469,23 +534,24 @@ class AC3DExport: # the ac3d exporter part
mlist.index(name)
except ValueError:
mlist.append(name)
- M = Blender.Material.Get(name)
+ M = Material.Get(name)
material = 'MATERIAL "%s"' % name
- mirCol = "%s %s %s" % (Round(M.mirCol[0]), Round(M.mirCol[1]),
- Round(M.mirCol[2]))
- rgb = "rgb %s %s %s" % (Round(M.R), Round(M.G), Round(M.B))
- amb = "amb %s %s %s" % (Round(M.amb), Round(M.amb), Round(M.amb))
- spec = "spec %s %s %s" % (Round(M.specCol[0]),
- Round(M.specCol[1]), Round(M.specCol[2]))
+ 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(M.emit)
+ 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(1 - M.alpha))
+ trans = "trans %s" % (Round_s(1 - M.alpha))
if MIRCOL_AS_AMB:
amb = "amb %s" % mirCol
if MIRCOL_AS_EMIS:
@@ -516,12 +582,12 @@ class AC3DExport: # the ac3d exporter part
tex = f.image.name
break
if tex:
- image = Blender.Image.Get(tex)
+ image = Image.Get(tex)
texfname = image.filename
if SET_TEX_DIR:
- texfname = Blender.sys.basename(texfname)
+ texfname = bsys.basename(texfname)
if TEX_DIR:
- texfname = Blender.sys.join(TEX_DIR, texfname)
+ texfname = bsys.join(TEX_DIR, texfname)
buf = 'texture "%s"\n' % texfname
xrep = image.xrep
yrep = image.yrep
@@ -530,41 +596,65 @@ class AC3DExport: # the ac3d exporter part
def rot(self, matrix):
rot = ''
- not_I = 0
+ not_I = 0 # not identity
+ matstr = []
for i in [0, 1, 2]:
- r = map(Round, matrix[i])
- not_I += (r[0] != '0.0')+(r[1] != '0.0')+(r[2] != '0.0')
- not_I -= (r[i] == '1.0')
+ 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]:
- rot = "%s %s" % (rot, r[j])
- if not_I:
- self.file.write('rot %s\n' % rot.strip())
+ 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, loc)
- if loc[0] or loc[1] or loc[2]:
+ 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 %s\n' % crease)
+ self.file.write('crease %f\n' % crease)
def numvert(self, verts, matrix):
file = self.file
- file.write("numvert %s\n" % len(verts))
- m = matrix * acmatrix
- 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))
+ 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)
- def numsurf(self, faces, hasFaceUV, foomesh = False):
-
- global ADD_DEFAULT_MAT, MATIDX_ERROR
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
omlist = {}
@@ -573,33 +663,33 @@ class AC3DExport: # the ac3d exporter part
for i in range(len(objmats)):
objmats[i] = objmats[i].name
for f in faces:
- m_idx = f.materialIndex
+ m_idx = f.mat
try:
m_idx = mlist.index(objmats[m_idx])
except IndexError:
- if not MATIDX_ERROR:
+ 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 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:
midxmsg = "- Same for object %s." % self.obj.name
REPORT_DATA['warns'].append(midxmsg)
- MATIDX_ERROR += 1
+ lc_MATIDX_ERROR += 1
matidx_error_told = 1
m_idx = 0
refs = len(f)
- flaglow = (refs == 2) << 1
- if PER_FACE_1_OR_2_SIDED: # per face attribute
- two_side = f.mode & Blender.NMesh.FaceModes['TWOSIDE']
+ 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 & Blender.NMesh.Modes['TWOSIDED']
+ 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 ADD_DEFAULT_MAT and objmats: m_idx += 1
+ if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1
matstr = "mat %s\n" % m_idx
refstr = "refs %s\n" % refs
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))
+ 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
from Blender.Window import FileSelector
@@ -687,7 +795,9 @@ def fs_callback(filename):
# -- End of definitions
+
scn = Blender.Scene.GetCurrent()
+
if ONLY_SELECTED:
OBJS = list(scn.objects.context)
else:
diff --git a/release/scripts/ac3d_import.py b/release/scripts/ac3d_import.py
index 4dcde65fb4a..0fd5d3e5625 100644
--- a/release/scripts/ac3d_import.py
+++ b/release/scripts/ac3d_import.py
@@ -2,7 +2,7 @@
""" Registration info for Blender menus:
Name: 'AC3D (.ac)...'
-Blender: 236
+Blender: 242
Group: 'Import'
Tip: 'Import an AC3D (.ac) file.'
"""
@@ -10,7 +10,7 @@ Tip: 'Import an AC3D (.ac) file.'
__author__ = "Willian P. Germano"
__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org",
"PLib 3d gaming lib, http://plib.sf.net")
-__version__ = "2.36a 2005-12-04"
+__version__ = "2.43 2007-01-14"
__bpydoc__ = """\
This script imports AC3D models into Blender.
@@ -29,8 +29,6 @@ Known issues:<br>
None.
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
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$
#
# --------------------------------------------------------------------------
-# AC3DImport version 2.36a Dec 04, 2005
-# Program versions: Blender 2.36+ and AC3Db files (means version 0xb)
-# changed: fixed a bug: error on 1 vertex "closed" polylines
+# AC3DImport version 2.43 Jan 04, 2007
+# Program versions: Blender 2.43 and AC3Db files (means version 0xb)
+# changed: updated for new Blender version, Mesh module
# --------------------------------------------------------------------------
# ***** 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
# 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
# avoid problems.
+from math import radians
+
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.Mathutils import Vector, Matrix, Euler
# Default folder for AC3D textures, to override wrong paths, change to your
# liking or leave as "":
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 = {
- 'TEXTURES_DIR': 'additional dir to look for missing textures',
- 'GROUP': 'mimick grouping information by parenting grouped meshes to empties'
+ 'TEXTURES_DIR': 'additional dir to look for missing textures'
}
def update_registry():
- global GROUP, TEXTURES_DIR
- rd = dict([('GROUP', GROUP), ('TEXTURES_DIR', TEXTURES_DIR)])
+ global TEXTURES_DIR
+ rd = dict([('TEXTURES_DIR', TEXTURES_DIR)])
Registry.SetKey('ac3d_import', rd, True)
rd = Registry.GetKey('ac3d_import', True)
if rd:
TEXTURES_DIR = rd['TEXTURES_DIR']
- GROUP = rd['GROUP']
else: update_registry()
if TEXTURES_DIR:
@@ -119,11 +114,31 @@ if rd:
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):
global VERBOSE
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:
@@ -135,23 +150,31 @@ class Obj:
self.tex = ''
self.texrep = [1,1]
self.texoff = None
- self.loc = [0, 0, 0]
+ self.loc = []
self.rot = []
+ self.size = []
self.crease = 30
self.vlist = []
- self.flist = []
+ self.flist_cfg = []
+ self.flist_v = []
+ self.flist_uv = []
+ self.elist = []
self.matlist = []
self.kids = 0
+ self.bl_obj = None # the actual Blender object created from this data
+
class AC3DImport:
def __init__(self, filename):
global errmsg
+ self.scene = Scene.GetCurrent()
+
self.i = 0
errmsg = ''
- self.importdir = Blender.sys.dirname(filename)
+ self.importdir = bsys.dirname(filename)
try:
file = open(filename, 'r')
except IOError, (errno, strerror):
@@ -187,8 +210,7 @@ class AC3DImport:
self.objlist = []
self.mlist = []
- self.dads = []
- self.kids = []
+ self.kidsnumlist = []
self.dad = None
self.lines = file.readlines()
@@ -199,12 +221,12 @@ class AC3DImport:
self.testAC3DImport()
def parse_obj(self, value):
- if self.kids:
- while not self.kids[-1]:
- self.kids.pop()
+ if self.kidsnumlist:
+ while not self.kidsnumlist[-1]:
+ self.kidsnumlist.pop()
self.dad = self.dad.dad
- self.kids[-1] -= 1
- new = Obj(value)
+ self.kidsnumlist[-1] -= 1
+ new = Obj(AC_OB_TYPES[value])
new.dad = self.dad
new.name = value
self.objlist.append(new)
@@ -212,7 +234,7 @@ class AC3DImport:
def parse_kids(self, value):
kids = int(value)
if kids:
- self.kids.append(kids)
+ self.kidsnumlist.append(kids)
self.dad = self.objlist[-1]
self.objlist[-1].kids = kids
@@ -269,23 +291,24 @@ class AC3DImport:
def parse_rot(self, trash):
i = self.i - 1
+ ob = self.objlist[-1]
rot = self.lines[i].split(' ', 1)[1]
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):
i = self.i - 1
loc = self.lines[i].split(' ', 1)[1]
loc = map(float, loc.split())
- self.objlist[-1].loc = loc
+ self.objlist[-1].loc = Vector(loc)
def parse_crease(self, value):
# AC3D: range is [0.0, 180.0]; Blender: [1, 80]
- try:
- value = int(value)
- except ValueError:
- value = int(float(value)) # duh
- self.objlist[-1].crease = value
+ value = float(value)
+ self.objlist[-1].crease = int(value)
def parse_vert(self, value):
i = self.i
@@ -303,28 +326,6 @@ class AC3DImport:
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):
i = self.i
is_smooth = 0
@@ -333,6 +334,7 @@ class AC3DImport:
obj = self.objlist[-1]
matlist = obj.matlist
numsurf = int(value)
+ NUMSURF = numsurf
while numsurf:
flags = lines[i].split()
@@ -349,45 +351,51 @@ class AC3DImport:
i += 3
face = []
faces = []
+ edges = []
fuv = []
+ fuvs = []
rfs = refs
while rfs:
line = lines[i].split()
v = int(line[0])
uv = [float(line[1]), float(line[2])]
- face.append([v, uv])
+ face.append(v)
+ fuv.append(Vector(uv))
rfs -= 1
i += 1
- if flaglow:
+ if flaglow: # it's a line or closed line, not a polygon
while len(face) >= 2:
cut = face[:2]
- faces.append(cut)
+ edges.append(cut)
face = face[1:]
- if flaglow == 1 and faces:
- face = [faces[-1][-1], faces[0][0]]
- faces.append(face)
+ if flaglow == 1 and edges:
+ face = [edges[-1][-1], edges[0][0]]
+ edges.append(face)
else:
while len(face) > 4:
cut = face[:4]
+ cutuv = fuv[:4]
face = face[3:]
+ fuv = fuv[3:]
face.insert(0, cut[0])
- faces.append(cut)
+ fuv.insert(0, cutuv[0])
+ faces.append(cut)
+ fuvs.append(cutuv)
faces.append(face)
+ fuvs.append(fuv)
- for f in faces:
- f.append(mat)
- f.append(is_smooth)
- f.append(twoside)
- self.objlist[-1].flist.append(f)
+ obj.flist_cfg.extend([[mat, is_smooth, twoside]] * len(faces))
+ obj.flist_v.extend(faces)
+ obj.flist_uv.extend(fuvs)
+ obj.elist.extend(edges) # loose edges
numsurf -= 1
-
self.i = i
def parse_file(self):
@@ -408,14 +416,86 @@ class AC3DImport:
i = self.i
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):
- 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 = []
for mat in self.mlist:
name = mat[0]
- m = Blender.Material.New(name)
+ m = Material.New(name)
m.rgbCol = (mat[1][0], mat[1][1], mat[1][2])
m.amb = mat[2]
m.emit = mat[3]
@@ -424,102 +504,133 @@ class AC3DImport:
m.alpha = mat[6]
bmat.append(m)
- for obj in self.objlist:
- if obj.type == 'world':
+ obj_idx = 0 # index of current obj in loop
+ for obj in objlist:
+ if obj.type == AC_GROUP:
continue
- elif obj.type == 'group':
- if not GROUP: continue
- empty = Blender.Object.New('Empty')
- empty.name = obj.name
- scene.link(empty)
- if self.dads:
- dadobj = Blender.Object.get(self.dads.pop())
- dadobj.makeParent([empty])
- while obj.kids:
- self.dads.append(empty.name)
- obj.kids -= 1
+ elif obj.type == AC_LIGHT:
+ light = Lamp.New('Lamp')
+ object = scene.objects.new(light, obj.name)
+ object.select(True)
+ obj.bl_obj = object
+ if obj.data:
+ light.name = obj.data
continue
- mesh = Blender.NMesh.New()
- if obj.data: mesh.name = obj.data
- mesh.setMaxSmoothAngle(obj.crease) # will clamp to [1, 80]
- mesh.hasFaceUV(1)
- tex = None
- 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)
+ # type AC_POLY:
- for v in obj.vlist:
- bvert = Blender.NMesh.Vert(v[0],v[1],v[2])
- mesh.verts.append(bvert)
+ # 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
+ mesh.degr = obj.crease # will auto clamp to [1, 80]
+
+ mesh.verts.extend(obj.vlist)
objmat_indices = []
for mat in bmat:
if bmat.index(mat) in obj.matlist:
objmat_indices.append(bmat.index(mat))
- mesh.materials.append(mat)
- for f in obj.flist:
- twoside = f[-1]
- is_smooth = f[-2]
- fmat = f[-3]
- f=f[:-3]
- bface = Blender.NMesh.Face()
+ mesh.materials += [mat]
+
+ for e in obj.elist:
+ mesh.edges.extend(e)
+
+ mesh.faces.extend(obj.flist_v)
+
+ # 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
- if twoside: bface.mode |= Blender.NMesh.FaceModes['TWOSIDE']
- if tex:
- bface.mode |= Blender.NMesh.FaceModes['TEX']
- bface.image = tex
- bface.materialIndex = objmat_indices.index(fmat)
+ if twoside: bface.mode |= FACE_TWOSIDE
+ if img:
+ bface.mode |= FACE_TEX
+ bface.image = img
+ bface.mat = objmat_indices.index(fmat)
+ fuv = obj.flist_uv[i]
if obj.texoff:
uoff = obj.texoff[0]
voff = obj.texoff[1]
urep = obj.texrep[0]
vrep = obj.texrep[1]
- for vi in range(len(f)):
- f[vi][1][0] *= urep
- f[vi][1][1] *= vrep
- f[vi][1][0] += uoff
- f[vi][1][1] += voff
-
- for vi in range(len(f)):
- 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
- object = Blender.NMesh.PutRaw(mesh)
- object.setName(obj.name)
- object.setEuler([1.5707963,0,0]) # align ac3d w/ Blender
- if self.dads:
- dadobj = Blender.Object.get(self.dads.pop())
- dadobj.makeParent([object])
+ for uv in fuv:
+ uv[0] *= urep
+ uv[1] *= vrep
+ uv[0] += uoff
+ uv[1] += voff
+
+ mesh.faces[i].uv = fuv
+
+ i += 1
+
+ mesh.mode = MESH_AUTOSMOOTH
+
+ obj_idx += 1
+
+ self.build_hierarchy()
+ scene.update()
# End of class AC3DImport
def filesel_callback(filename):
- inform("Trying to import AC3D model(s) from %s ..." % filename)
- Blender.Window.WaitCursor(1)
- starttime = Blender.sys.time()
+ inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename)
+ Window.WaitCursor(1)
+ starttime = bsys.time()
test = AC3DImport(filename)
- Blender.Window.WaitCursor(0)
- endtime = Blender.sys.time() - starttime
- inform('... done! Data imported in %.3f seconds.\n' % endtime)
+ Window.WaitCursor(0)
+ endtime = bsys.time() - starttime
+ inform('Done! Data imported in %.3f seconds.\n' % endtime)
-Blender.Window.FileSelector(filesel_callback, "Import AC3D", "*.ac")
+Window.FileSelector(filesel_callback, "Import AC3D", "*.ac")