stk-code_catmod/tools/python/export_track.py
grumbel 7a6d165641 - moved trunk/ to trunk/supertuxkart
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1118 178a84e3-b1eb-0310-8ba1-8eac791a3b58
2007-05-27 16:01:53 +00:00

947 lines
29 KiB
Python

#!BPY
""" Registration info for Blender menus:
Name: 'Super Tux Kart Track'
Blender: 233
Group: 'Export'
Submenu: 'All meshes and empties ...' all
Submenu: 'Only selected ...' sel
Submenu: 'Configure' config
Tip: 'Create Super Tux Kart racing tracks.'
"""
# --------------------------------------------------------------------------
# This script turns the AC3D exporter script into a TuxKart track exporter.
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
# Copyright (C) 2006: Eduardo Hernández, coz.eduardo.hernandez _at_ gmail.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
VERSION = '0.2'
HELPTEXT = HELPTEXT_INTRO = [
'This script can export racing tracks with all needed data for TuxKart.',
'',
'TuxKart is an open source 3D kart racing game by Steve and Oliver Baker.',
'It is written in portable C++ using OpenGL and Steve\'s PLib 3D gaming library.',
'',
'Links:',
'TuxKart: tuxkart.sf.net PLib: plib.sf.net OpenGL: opengl.org',
'',
'The game\'s site contains a text describing how to add new tracks.',
'Please read it to understand better how to use this script.',
]
HELPTEXT_DRV = [
'To export the drive path file you need to create two mesh objects,',
'which are the left and right borders of the track. They must be only',
'linked 2D line segments (aka a curve). The left border mesh object must',
'be called "DRV_LEFT" and the right border mesh object is to be',
'called "DRV_RIGHT".',
'',
'Hints to create the drive line in the 3D View window (use TOP VIEW):',
'',
'- select the track mesh (the actual path);',
'- enter edit mode, and select all the vertex of one of the borders;',
'- use the P-KEY to separate that border from the main mesh;',
'- select the other border and separate it;',
'- change the name of the mesh objects to DRV_LEFT and DRV_RIGHT;',
'',
'To write the vertices in the correct order, the script starts with the',
'closest one to (0,0,0), looks for the edge that goes the most "up" ('
'increasing y coordinate) then follows the line segments till the last one.'
]
HELPTEXT_LOC = [
'To put items on the track add Empties (SPACEBAR->ADD->EMPTY)',
'where you want them to appear and give them a proper name.',
'Examples:',
'(x,y,z are coordinates and h,p,r are rotation angles)'
'',
'- sign.ac is exported as .loc line: "sign.ac",x,y,z,h,p,r',
'- sign.ac{Z}: "sign.ac",x,y,{},h,p,r',
'- sign.ac{ZPR}: "sign.ac",x,y,{},h,{},{}',
'- RHERRING exported as: RHERRING,x,y,z',
'',
'So (did you read the text about this at TuxKart\'s site?):',
'- to have z,p or r calculated by the game, append them inside {};',
'- names without an extension (.something) are considered hardcoded',
' game objects, like GHERRING (default if name is left as Empty);',
'- item examples: zipper.ac, RHERRING, GHERRING, YHERRING;',
'- don\'t worry about the .001 etc. extensions appended by Blender.',
'',
'You can assign a song file for your track in the Config screen.'
]
HELPTEXT_AC = [
'The script uses the AC3D exporter.',
'',
'AC3D is a shareware 3D modeler with a simple text format (.ac).',
'',
'There are a few options you can configure:',
'- 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...',
'',
'To export mesh groups, parent each set to an Empty that has the suffix "GR_".'
]
import Blender
from Blender import sys as bsys
from Blender import Mathutils
from math import sqrt
# Globals / config options:
ARG = __script__['arg'] # user selected argument
HELPME = CONFIG = 0 # secondary screens
TK_ALL = 0
TK_DRV = 1
TK_LOC = 0
TK_TRK = 0
TK_PATH = bsys.dirname(Blender.Get('filename')) + bsys.sep
TK_TUNE = ''
AC_SKIP_DATA = 0
AC_MIRCOL_AS_AMB = 0
AC_MIRCOL_AS_EMIS = 0
AC_ADD_DEFAULT_MAT = 1
# Looking for a saved key in Blender.Registry dict:
rd = Blender.Registry.GetKey('TuxKart')
if rd:
TK_ALL = rd['TK_ALL']
TK_DRV = rd['TK_DRV']
TK_LOC = rd['TK_LOC']
TK_TRK = rd['TK_TRK']
TK_PATH = rd['TK_PATH']
TK_TUNE = rd['TK_TUNE']
AC_SKIP_DATA = rd['AC_SKIP_DATA']
AC_MIRCOL_AS_AMB = rd['AC_MIRCOL_AS_AMB']
AC_MIRCOL_AS_EMIS = rd['AC_MIRCOL_AS_EMIS']
AC_ADD_DEFAULT_MAT = rd['AC_ADD_DEFAULT_MAT']
if "DRV_LEFT" and "DRV_RIGHT" in Blender.Object.Get():
TK_DRV = 1 # found both DRV meshes
def update_RegistryInfo():
d = {}
d['TK_ALL'] = TK_ALL
d['TK_DRV'] = TK_DRV
d['TK_LOC'] = TK_LOC
d['TK_TRK'] = TK_TRK
d['TK_PATH'] = TK_PATH
d['TK_TUNE'] = TK_TUNE
d['AC_SKIP_DATA'] = AC_SKIP_DATA
d['AC_MIRCOL_AS_AMB'] = AC_MIRCOL_AS_AMB
d['AC_MIRCOL_AS_EMIS'] = AC_MIRCOL_AS_EMIS
d['AC_ADD_DEFAULT_MAT'] = AC_ADD_DEFAULT_MAT
Blender.Registry.SetKey('TuxKart', d)
# The default material to be used when necessary (see AC_ADD_DEFAULT_MAT)
DEFAULT_MAT = \
'MATERIAL "DefaultWhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 \
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])
def Round(f):
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:
vec = Mathutils.Vector([v[0],v[1],v[2], 1])
vecs.append(vec * m)
return vecs
# ---
def WriteLocation(objs, filename):
"Write the .loc file"
filename = Blender.sys.splitext(filename)[0]
trackname = Blender.sys.basename(filename)+".ac"
filename += '.loc'
locfile = file(filename, "w")
print "Writing %s file..." % filename
locfile.write("# Created by tuxkart.py v%s Blender Python script.\n#\n" \
% VERSION)
locfile.write('"%s",0,0,0,0,0,0\n' % trackname)
rad2deg = 180/3.1415926535 #from radians to degrees
for item in objs:
x,y,z = map(str, map(Round, item.loc))
rx,ry,rz = map(lambda x: rad2deg*x, item.rot)
h,p,r = map(str, map(Round, [rz,rx,ry]))
name = item.name.split(".")
hardcoded = 1 # name has extension (like .ac) ?
if len(name) == 1:
name = name[0]
else:
if name[-1].isdigit():
name = name[:-1]
if name == 'Empty': name = 'GHERRING'
if len(name) == 1:
name = name[0]
else:
name = ".".join(name)
hardcoded = 0 # has extension, isn't harcoded
if name.find("{") > 0:
name, encoded = name.split("{", 1)
encoded = encoded.split("}")[0].lower()
if encoded.find("z") >= 0: z = '{}'
if encoded.find("p") >= 0: p = '{}'
if encoded.find("r") >= 0: r = '{}'
locline = '%s,%s,%s' % (x,y,z)
if not hardcoded:
name = '"'+name+'"'
locline += ',%s,%s,%s' % (h,p,r)
locfile.write('%s,%s\n' % (name, locline))
if TK_TUNE:
locfile.write('MUSIC "%s"\n' % TK_TUNE)
locfile.close()
def WriteLeftDriveLine(obj, filename):
"Write the .drvl file"
mesh = obj.getData()
mesh.transform(obj.getMatrix())
for f in mesh.faces:
if len(f.v) != 2:
print "Can't export Drive Line .drvl file: invalid mesh."
print "The mesh must be made of linked line segments only."
return
filename = Blender.sys.splitext(filename)[0]
filename += '.drvl'
drvfile = file(filename, "w")
print "Writing drive line file: %s" % filename
verts = mesh.verts
shortest_distance = 100000
for v in verts:
#find vertex closest to 0,0
distance = sqrt(v[0]**2 + v[1]**2)
if distance < shortest_distance:
shortest_distance = distance
first_vertex = v
#Find the two vertex that are linked to the first vertex
e_v = []
edges = mesh.edges
for e in edges:
if first_vertex == e.v1:
e_v.append(e.v2)
elif first_vertex == e.v2:
e_v.append(e.v1)
second_vertex = first_vertex
#Find the vertex which has the higher Y value
for v in e_v:
if v[1] > second_vertex[1]:
second_vertex = v
if second_vertex == first_vertex:
print "Can't export Drive Line .drvl file: invalid mesh."
print "The mesh only has one point."
return
sorted_vertex = [first_vertex, second_vertex]
prev_vertex = first_vertex
curr_vertex = second_vertex
count = 2
#Find the edge that contains the second vertex but does not has first vertex
while count != len(verts):
for e in edges:
if prev_vertex != e.v1 and prev_vertex != e.v2:
#Find which vertex is the next_vertex
if curr_vertex == e.v1:
prev_vertex = curr_vertex
curr_vertex = e.v2
sorted_vertex.append(curr_vertex)
count = count + 1
break
elif curr_vertex == e.v2:
prev_vertex = curr_vertex
curr_vertex = e.v1
sorted_vertex.append(curr_vertex)
count = count + 1
break
for v in sorted_vertex:
drvfile.write('%f,%f,%f\n' % (v[0], v[1], v[2]))
drvfile.close()
def WriteRightDriveLine(obj, filename):
"Write the .drvl file"
mesh = obj.getData()
mesh.transform(obj.getMatrix())
for f in mesh.faces:
if len(f.v) != 2:
print "Can't export Drive Line .drvr file: invalid mesh."
print "The mesh must be made of linked line segments only."
return
filename = Blender.sys.splitext(filename)[0]
filename += '.drvr'
drvfile = file(filename, "w")
print "Writing drive line file: %s" % filename
verts = mesh.verts
shortest_distance = 100000
for v in verts:
#find vertex closest to 0,0
distance = sqrt(v[0]**2 + v[1]**2)
if distance < shortest_distance:
shortest_distance = distance
first_vertex = v
#Find the two vertex that are linked to the first vertex
e_v = []
edges = mesh.edges
for e in edges:
if first_vertex == e.v1:
e_v.append(e.v2)
elif first_vertex == e.v2:
e_v.append(e.v1)
second_vertex = first_vertex
#Find the vertex which has the higher Y value
for v in e_v:
if v[1] > second_vertex[1]:
second_vertex = v
if second_vertex == first_vertex:
print "Can't export Drive Line .drvr file: invalid mesh."
print "The mesh only has one point."
return
sorted_vertex = [first_vertex, second_vertex]
prev_vertex = first_vertex
curr_vertex = second_vertex
count = 2
#Find the edge that contains the second vertex but does not has first vertex
while count != len(verts):
for e in edges:
if prev_vertex != e.v1 and prev_vertex != e.v2:
#Find which vertex is the next_vertex
if curr_vertex == e.v1:
prev_vertex = curr_vertex
curr_vertex = e.v2
sorted_vertex.append(curr_vertex)
count = count + 1
break
elif curr_vertex == e.v2:
prev_vertex = curr_vertex
curr_vertex = e.v1
sorted_vertex.append(curr_vertex)
count = count + 1
break
for v in sorted_vertex:
drvfile.write('%f,%f,%f\n' % (v[0], v[1], v[2]))
drvfile.close()
class Track: # the ac3d exporter part
def __init__(self, bl_objlist, filename):
from Blender.sys import time
TIME = time()
global ARG, AC_SKIP_DATA, AC_ADD_DEFAULT_MAT, DEFAULT_MAT
print 'Exporting track model(s) to AC3D format...'
header = 'AC3Db'
self.buf = ''
self.mbuf = ''
world_kids = 0
self.mlist = []
kids_dict = {}
objlist = []
bl_objlist2 = []
if filename.find('.ac', -3) <= 0: filename += '.ac'
try:
file = open(filename, 'w')
except IOError, (errno, strerror):
errmsg = "IOError #%s" % errno
errmsg = errmsg + "%t|" + strerror
Blender.Draw.PupMenu(errmsg)
return None
file.write(header+'\n')
for obj in bl_objlist:
if obj.getType() != 'Mesh' and obj.getType() != 'Empty':
continue
else: kids_dict[obj.name] = 0
if obj.getParent() == None:
objlist.append(obj)
else:
bl_objlist2.append(obj)
bl_objlist = bl_objlist2[:]
world_kids = len(objlist)
while bl_objlist2:
for obj in bl_objlist:
obj2 = obj
dad = obj.getParent()
kids_dict[dad.name] += 1
while dad.name not in objlist:
obj2 = dad
dad = dad.getParent()
kids_dict[dad.name] += 1
objlist.insert(objlist.index(dad.name)+1, obj2.name)
bl_objlist2.remove(obj2)
meshlist = [o for o in objlist if o.getType() == 'Mesh']
self.MATERIALS(meshlist)
if not self.mbuf or AC_ADD_DEFAULT_MAT:
self.mbuf = DEFAULT_MAT + '\n' + self.mbuf
file.write(self.mbuf)
file.write('OBJECT world\nkids %s\n' % world_kids)
for obj in objlist:
self.obj = obj
if obj.getType == 'Empty':
file.write('OBJECT group\n')
emptyname = obj.name # skip the GR_ prefix
if len(emptyname) > 3: emptyname = emptyname[3:]
file.write(emptyname+'\n')
#self.rot(obj.rot)
#self.loc(obj.loc)
else:
mesh = self.mesh = obj.getData()
file.write('OBJECT poly\nname "%s"\n' % obj.name)
if not AC_SKIP_DATA:
file.write('data %s\n%s\n' % (len(mesh.name), mesh.name))
texline = self.texture(mesh.faces)
if texline: file.write(texline)
self.numvert(mesh.verts, obj.getMatrix(), file)
self.numsurf(mesh.faces, mesh.hasFaceUV(), file)
file.write('kids %s\n' % kids_dict[obj.name])
file.close()
print "Done. Saved to %s\n" % filename
def MATERIALS(self, meshlist):
for meobj in meshlist:
me = meobj.getData()
mat = me.materials
mbuf = []
mlist = self.mlist
for m in xrange(len(mat)):
name = mat[m].name
try:
mlist.index(name)
except ValueError:
mlist.append(name)
M = Blender.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))
if AC_MIRCOL_AS_AMB:
amb = "amb %s" % mirCol
emis = "emis 0 0 0"
if AC_MIRCOL_AS_EMIS:
emis = "emis %s" % mirCol
spec = "spec %s %s %s" % (Round(M.specCol[0]),
Round(M.specCol[1]), Round(M.specCol[2]))
shi = "shi 72"
trans = "trans %s" % (Round(1 - M.alpha))
mbuf.append("%s %s %s %s %s %s %s\n" \
% (material, rgb, amb, emis, spec, shi, trans))
self.mlist = mlist
self.mbuf += "".join(mbuf)
def texture(self, faces):
tex = []
for f in faces:
if f.image and f.image.name not in tex:
tex.append(f.image.name)
if tex:
if len(tex) > 1:
print "\nAC3Db format supports only one texture per object."
print "Object %s -- using only the first one: %s\n" % \
(self.obj.name, tex[0])
image = Blender.Image.Get(tex[0])
buf = 'texture "%s"\n' % image.filename
xrep = image.xrep
yrep = image.yrep
buf += 'texrep %s %s\n' % (xrep, yrep)
return buf
def rot(self, matrix):
rot = ''
not_I = 0
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')
for j in [0, 1, 2]:
rot = "%s %s" % (rot, r[j])
if not_I:
rot = rot.strip()
buf = 'rot %s\n' % rot
self.buf = self.buf + buf
def loc(self, loc):
loc = map(Round, loc)
if loc[0] or loc[1] or loc[2]:
buf = 'loc %s %s %s\n' % (loc[0], loc[1], loc[2])
self.buf = self.buf + buf
def numvert(self, verts, matrix, 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))
def numsurf(self, faces, hasFaceUV, file):
global AC_ADD_DEFAULT_MAT
file.write("numsurf %s\n" % len(faces))
mlist = self.mlist
indexerror = 0
omlist = {}
objmats = self.mesh.materials
for i in range(len(objmats)):
objmats[i] = objmats[i].name
for f in faces:
m_idx = f.materialIndex
try:
m_idx = mlist.index(objmats[m_idx])
except IndexError:
if not indexerror:
print "\nNotice: object " + self.obj.name + \
" has at least one material *index* assigned\n" \
"\tbut not defined (not linked to an existing material).\n" \
"\tThis can make some faces be exported with a wrong color.\n" \
"\tYou can fix the problem in the Edit Buttons Window (F9).\n"
indexerror = 1
m_idx = 0
refs = len(f)
flaglow = (refs == 2) << 1
two_side = f.mode & Blender.NMesh.FaceModes['TWOSIDE']
two_side = (two_side > 0) << 1
flaghigh = f.smooth | two_side
surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
if AC_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
fvstr = ''
for vert in f.v:
fvstr = fvstr + str(self.mesh.verts.index(vert))
if hasFaceUV:
u = f.uv[vi][0]
v = f.uv[vi][1]
vi += 1
fvstr = fvstr + " %s %s\n" % (u, v)
file.write(surfstr + matstr + refstr + fvstr)
# End of Class Track
from Blender import Draw, BGL
from Blender.Window import FileSelector
# Special Buttons
BUTPATH = Draw.Create(TK_PATH)
BUTTUNE = Draw.Create(TK_TUNE)
BUTTRK = Draw.Create(TK_TRK)
BUTDRV = Draw.Create(TK_DRV)
BUTALL = Draw.Create(TK_ALL)
BUTLOC = Draw.Create(TK_LOC)
HTRK = Draw.Create(0)
HDRV = Draw.Create(0)
HLOC = Draw.Create(0)
HINTRO = Draw.Create(0)
HTOG = HTOG_INTRO = 0
HTOG_TRK = 1
HTOG_LOC = 2
HTOG_DRV = 3
# Button Events
EVT_CONFIG = 1
EVT_AC_DMAT = 2
EVT_AC_SKIP = 3
EVT_AC_MIR = 4
EVT_AC_EMIS = 5
EVT_AC_ALL = 6
EVT_AC_SEL = 7
EVT_HELP = 10
EVT_HELP_DRV = 11
EVT_HELP_LOC = 12
EVT_HELP_TRK = 13
EVT_HELP_INTRO = 14
EVT_ALL = 20
EVT_TRK = 21
EVT_DRV = 22
EVT_LOC = 23
EVT_PATH = 24
EVT_BROWSE = 25
EVT_TUNE = 26
EVT_TUNEBROWSE = 27
EVT_EXPORT = 30
EVT_EXIT = 31
def gui(): # gui drawing callback
global AC_SKIP_DATA, AC_MIRCOL_AS_AMB, AC_MIRCOL_AS_EMIS, AC_ADD_DEFAULT_MAT
global HELPME, CONFIG, HELPTEXT, HTRK, HDRV, HLOC, HINTRO
global HTOG, HTOG_INTRO, HTOG_TRK, HTOG_LOC, HTOG_DRV
global BUTPATH, BUTTRK, BUTDRV, BUTALL, BUTLOC, BUTTUNE
if HELPME: # help screen
BGL.glClearColor(0.4,0.5,0.8,1)
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
BGL.glColor3f(1,1,1)
x = 55
y = 50+20*len(HELPTEXT)
for line in HELPTEXT:
y -= 20
BGL.glRasterPos2i(x, y)
Draw.Text(line)
w = 35
h = 20
y = 10
HINTRO = Draw.Toggle("intro", EVT_HELP_INTRO, x, y, w, h,(HTOG==HTOG_INTRO),
"Intro Help screen.")
HLOC = Draw.Toggle("loc", EVT_HELP_LOC, x+w, y, w, h, (HTOG==HTOG_LOC),
"Help for location (.loc) file.")
HTRK = Draw.Toggle("track", EVT_HELP_TRK, x+2*w, y, w, h, (HTOG==HTOG_TRK),
"Help for the mesh exporter.")
HDRV = Draw.Toggle("drv", EVT_HELP_DRV, x+3*w, y, w, h, (HTOG==HTOG_DRV),
"Help for drive line (.drv) file.")
Draw.Button("back", EVT_HELP, x+4*w, y, w, h, "Return to main screen.")
elif CONFIG: # config screen
BGL.glClearColor(0.4,0.5,0.8,1)
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
BGL.glColor3f(0.9,0.85,0.75)
BUTTUNE = Draw.String('song: ', EVT_TUNE, 10, 10, 210, 20, \
BUTTUNE.val, 150, 'Song filename for your race track.')
Draw.PushButton('browse...', EVT_TUNEBROWSE, 222, 10, 53, 20,
'Open file selector (select any file in the chosen dir)')
x = 15
y = 40
w = 80
h = 20
BGL.glRecti(x-4,y-5,x+205,y+84)
BGL.glColor3f(1,1,1)
Draw.Button("BACK", EVT_CONFIG, x+w+127, y-5, 53, 30,
"Click to return to main screen.")
Draw.Button("Export Selected...", EVT_AC_SEL, x+w+10, y+4, 110, 30,
"Export now selected meshes to an AC3D file.")
Draw.Button("Export All...", EVT_AC_ALL, x+w+10, y+44, 110, 30,
"Export now all meshes to an AC3D file.")
Draw.Toggle("Mir2Emis", EVT_AC_EMIS, x, y, w, h, AC_MIRCOL_AS_EMIS,
"Get AC3D's emissive RGB color for each object from its mirror color "
"in Blender.")
Draw.Toggle("Mir2Amb", EVT_AC_MIR, x, y+h, w, h, AC_MIRCOL_AS_AMB,
"Get AC3D's ambient RGB color for each object from its mirror color "
"in Blender.")
Draw.Toggle("Skip data", EVT_AC_SKIP, x, y+2*h, w, h, AC_SKIP_DATA,
"Don't export mesh names as 'data' info.")
Draw.Toggle("Default mat", EVT_AC_DMAT, x, y+3*h, w, h, AC_ADD_DEFAULT_MAT,
"Objects without materials assigned get a default (white) one "
"automatically.")
BGL.glRasterPos2i(x-4, y+5*h)
Draw.Text("Additional Configuration")
else: # main screen
# let's count our objects first:
meshnr = meshsel = emptynr = emptysel = 0
ob = Blender.Object.Get()
for o in ob:
if o.getType() == "Mesh":
meshnr += 1
if o.sel: meshsel += 1
elif o.getType() == "Empty":
emptynr += 1
if o.sel: emptysel += 1
obinfo = "%d/%d meshes" % (meshsel, meshnr)
if emptynr:
obinfo += ", %d/%d empties" % (emptysel, emptynr)
if len(obinfo) < 27: obinfo = 'Selected: ' + obinfo
BGL.glClearColor(0.4,0.5,0.8,1)
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
BGL.glColor3f(1,1,1)
x = y = 20
w = 60
h = 25
BGL.glRasterPos2i(x, y + 9)
Draw.Text(obinfo)
Draw.PushButton('EXPORT', EVT_EXPORT, x+202, y, w, h,
'Write track file(s).')
y += 30
w = 40
h = 20
pathmsg = 'Base dir where files will be saved.'
if BUTPATH.val[-1] != bsys.sep: pathmsg += ' And data filename head.'
BUTPATH = Draw.String('path: ', EVT_PATH, x, y, 5*w, h, BUTPATH.val, 100,
pathmsg)
Draw.PushButton('browse...', EVT_BROWSE, x+202, y, 60, 20,
'Open file selector (select any file in the chosen dir)')
y += 24
w = 26
h = 15
BUTALL = Draw.Toggle('all', EVT_ALL, x, y, w, h, BUTALL.val,
"Export all meshes and empties, not only selected ones.")
x += 7
BUTTRK = Draw.Toggle('trk', EVT_TRK, x+w, y, w, h, BUTTRK.val,
"Write track (.ac) file.")
BUTLOC = Draw.Toggle('loc', EVT_LOC, x+2*w, y, w, h, BUTLOC.val,
"Write location (.loc) file.")
BUTDRV = Draw.Toggle('drv', EVT_DRV, x+3*w, y, w, h, BUTDRV.val,
"Write drive line (.drv) file.")
x += 7 + 4*w
w = 41
Draw.PushButton('config', EVT_CONFIG, x, y, w, h,
'Additional configurations (see help).')
Draw.PushButton('help', EVT_HELP, x+w, y, w, h,
'About, links and instructions.')
Draw.PushButton('exit', EVT_EXIT, x+2*w+2, y, 60, h,
'Exit from script (shortcuts: Esc, q).')
x = 20
y += 46
BGL.glRasterPos2i(x, y)
title = "TuxKart Track Exporter v%s" % VERSION
tlen = Draw.Text(title)
BGL.glBegin(BGL.GL_LINE_LOOP)
BGL.glVertex2i(x+2+tlen, y+18)
BGL.glVertex2i(x+2+tlen, y-10)
BGL.glVertex2i(x-4, y-10)
BGL.glVertex2i(x-4, y+18)
BGL.glEnd()
def event(evt, val): # input event callback
global HELPME, CONFIG
if not val: return
if HELPME or CONFIG:
if evt == Draw.ESCKEY or evt == Draw.QKEY:
HELPME = CONFIG = 0
Draw.Redraw()
return
if evt == Draw.ESCKEY or evt == Draw.QKEY:
update_RegistryInfo()
Draw.Exit()
return
def b_event(evt): # gui button events callback
global AC_SKIP_DATA, AC_MIRCOL_AS_AMB, AC_MIRCOL_AS_EMIS, AC_ADD_DEFAULT_MAT
global CONFIG, HELPTEXT, TK_ALL, TK_DRV, TK_LOC, TK_TRK, TK_PATH, TK_TUNE
global HELPME, ARG, BUTPATH, BUTTRK, BUTDRV, BUTALL, BUTLOC, BUTTUNE
global HTOG, HTOG_TRK, HTOG_DRV, HTOG_LOC, HTOG_INTRO
if evt == EVT_EXPORT:
fname = TK_PATH
if bsys.exists(TK_PATH) == 2:
fname += bsys.makename(Blender.Get('filename'), strip=1)
FileSelector(fs_callback, "Export TuxKart track", fname)
else: TK_Export(fname, 0)
elif evt == EVT_ALL:
TK_ALL = BUTALL.val
if TK_ALL: ARG = 'all'
else: ARG = 'sel'
elif evt == EVT_DRV:
TK_DRV = BUTDRV.val
elif evt == EVT_LOC:
TK_LOC = BUTLOC.val
elif evt == EVT_TRK:
TK_TRK = BUTTRK.val
elif evt == EVT_PATH:
TK_PATH = BUTPATH.val
pathtype = bsys.exists(TK_PATH)
if pathtype:
if pathtype == 2 and TK_PATH[-1] != bsys.sep:
TK_PATH += bsys.sep
else: TKPATH = bsys.splitext(TK_PATH)[0]
BUTPATH.val = TK_PATH
elif evt == EVT_BROWSE:
FileSelector(fs_cbPath, "Ok", TK_PATH)
elif evt == EVT_TUNE:
TK_TUNE = BUTTUNE.val
if bsys.exists(TK_TUNE) != 1: # 1 is file
Draw.PupMenu("ERROR%t|No such file.")
TK_TUNE = ''
BUTTUNE.val = TK_TUNE
elif evt == EVT_TUNEBROWSE:
FileSelector(fs_cbTune, "Select Song", TK_TUNE)
elif evt == EVT_AC_DMAT:
AC_ADD_DEFAULT_MAT = 1 - AC_ADD_DEFAULT_MAT
elif evt == EVT_AC_SKIP:
AC_SKIP_DATA = 1 - AC_SKIP_DATA
elif evt == EVT_AC_MIR:
AC_MIRCOL_AS_AMB = 1 - AC_MIRCOL_AS_AMB
elif evt == EVT_AC_EMIS:
AC_MIRCOL_AS_EMIS = 1 - AC_MIRCOL_AS_EMIS
elif evt == EVT_AC_ALL:
ARG = 'AC_all'
fname = bsys.makename(ext=".ac")
FileSelector(fs_callback, "Export AC3D", fname)
return
elif evt == EVT_AC_SEL:
ARG = 'AC_sel'
fname = bsys.makename(ext=".ac")
FileSelector(fs_callback, "Export AC3D", fname)
return
elif evt == EVT_CONFIG:
CONFIG = 1 - CONFIG
elif evt == EVT_HELP:
HELPME = 1 - HELPME
elif evt == EVT_HELP_DRV:
HELPTEXT = HELPTEXT_DRV
HTOG = HTOG_DRV
elif evt == EVT_HELP_LOC:
HELPTEXT = HELPTEXT_LOC
HTOG = HTOG_LOC
elif evt == EVT_HELP_TRK:
HELPTEXT = HELPTEXT_AC
HTOG = HTOG_TRK
elif evt == EVT_HELP_INTRO:
HELPTEXT = HELPTEXT_INTRO
HTOG = HTOG_INTRO
elif evt == EVT_EXIT:
update_RegistryInfo()
Draw.Exit()
return
else: return
Draw.Redraw()
def TK_Export(filename, onlytrack):
global ARG
starttime = bsys.time()
# Here we check if given dir is TuxKart's one.
# If so we save .ac in models/ and .loc and .drv in data/
# else we save all in the given dir.
datapath = modelspath = filename
basename = bsys.basename(filename)
dirname = bsys.dirname(filename)
modelsdir = bsys.join(dirname, 'models')
datadir = bsys.join(dirname, 'data')
if bsys.exists (modelsdir) == 2:
if bsys.exists(datadir) == 2:
datapath = bsys.join(datadir, basename)
modelspath = bsys.join(modelsdir, basename)
scene = Blender.Scene.GetCurrent()
objs = []
# just the .ac export from the config screen:
if onlytrack:
if ARG == ('AC_sel'): objs = Blender.Object.GetSelected()
else: objs = scene.getChildren()
test = Track(objs, filename)
endtime = bsys.time() - starttime
Blender.Draw.PupMenu("OK|Data exported in %.2f seconds." % endtime)
return
if ARG == 'sel': objs = Blender.Object.GetSelected()
else: objs = scene.getChildren()
track = []
thingies = []
list = [o for o in objs if o.getType() == "Mesh" or o.getType() == "Empty"]
for o in list:
if o.getType() == "Empty": # empties whose names start with GR_
if o.name.find("GR_") < 0: # are exported as AC groups info
thingies.append(o)
elif o.name == "DRV_LEFT":
WriteLeftDriveLine(o, datapath)
elif o.name == "DRV_RIGHT":
WriteRightDriveLine(o, datapath)
else: track.append(o)
WriteLocation(thingies, datapath)
test = Track(track, modelspath)
endtime = bsys.time() - starttime
Blender.Draw.PupMenu("OK|Data exported in %.2f seconds." % endtime)
# File Selector callbacks:
def fs_cbPath(path):
global TK_PATH, BUTPATH
TK_PATH = bsys.splitext(path)[0]
BUTPATH.val = TK_PATH
def fs_cbTune(filename):
global TK_TUNE, BUTTUNE
TK_TUNE = filename
BUTTUNE.val = TK_TUNE
def fs_callback(filename):
global ARG
#if hasattr(ARG, find):
# if ARG.find('AC_') == 0: onlytrack = 1
# else: onlytrack = 0
onlytrack = 0
TK_Export(filename, onlytrack)
# -- End of definitions
if not ARG or ARG == 'config': # not ARG if executed as loaded Blender Text
Draw.Register(gui, event, b_event)
else:
fname = Blender.sys.makename()
FileSelector(fs_callback, "Export Tuxkart track", fname)