warzone2100/tools/blender/pie_export.py

275 lines
9.1 KiB
Python

#!BPY
#from __future__ import division
"""
Name: 'Warzone model (.pie)...'
Blender: 244
Group: 'Export'
Tooltip: 'Save a Warzone model file'
"""
__author__ = "Gerard Krol"
__version__ = "1.0"
__bpydoc__ = """\
This script exports Warzone 2100 PIE files.
"""
#
# --------------------------------------------------------------------------
# PIE Export v0.1 by Gerard Krol (gerard_)
# v0.2 by Kevin Gillette (kage)
# v1.0 --
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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 *****
# --------------------------------------------------------------------------
import Blender
import os
import math
from pie_common import *
def fs_callback(ui, filepath, levels, connectors):
texture_precision = point_precision = ui.getData('precision')
if point_precision > 0:
point_format = "\t" + (" %%.%if" % point_precision * 3)[1:] + "\n"
uv_format = " %%.%if" % texture_precision * 2
pie_version = 5
else:
point_format = "\t%i %i %i\n"
uv_format = " %i %i"
pie_version = 2
out = file(filepath, 'w')
out.write( "PIE %i\n" % pie_version )
out.write( 'TYPE 200\n' )
texture = levels[0].getMaterials()
if len(texture): texture = texture[0]
else: texture = levels[0].getData(mesh=1).faces[0].image
if texture:
texturename = os.path.basename(texture.getFilename())
if texturename.count('.') is not 1:
ui.debug("texture names in warzone can only have one period. " + filepath, 'error')
else:
texturename = 'NOTEXTURE'
out.write("NO")
ui.debug('texture: ' + texturename)
if pie_version is 2:
out.write("TEXTURE 0 %s 256 256\n" % texturename)
texture_mult = 256.0
else:
if texture: x, y = texture.getSize()
else: x, y = 256, 256
out.write("TEXTURE 0 %s %i %i\n" % (texturename, x, y))
texture_mult = 1.0
out.write("LEVELS %i\n" % len(levels))
for i, level in enumerate(levels):
mesh = level.getData(mesh=True)
mesh.flipNormals()
out.write('LEVEL %i\n' % (i + 1))
out.write('POINTS %i\n' % len(mesh.verts))
for vert in mesh.verts:
out.write(point_format % (-vert.co.x * 128, vert.co.z * 128, -vert.co.y * 128))
out.write("POLYGONS %i\n" % len(mesh.faces))
for j, face in enumerate(mesh.faces):
line_buffer = str(len(face.verts))
line_buffer += ''.join([" " + str(vert.index) for vert in face.verts])
flags = 0
mesh.activeUVLayer = "teamcolor_meta"
meta = get_teamcolor_meta(face.uv)
mesh.activeUVLayer = "base"
if meta:
ui.debug("teamcolor meta: " + repr(meta))
line_buffer += (" %i %i" + uv_format) % tuple(meta)
flags |= 0x4000
if face.mode & Blender.Mesh.FaceModes['TWOSIDE']:
flags |= 0x2000
if face.transp == Blender.Mesh.FaceTranspModes['ALPHA']:
flags |= 0x800
if not face.mode & Blender.Mesh.FaceModes['TEX']:
ui.debug("face %i is not textured" % j, "error")
flags |= 0x200
for u, v in face.uv:
u *= texture_mult
if pie_version is 2:
v = (1.0 - v) * texture_mult
else:
v *= texture_mult
line_buffer += uv_format % (u, v)
out.write("\t%s %s\n" % (hex(flags).split('x')[-1], line_buffer))
mesh.flipNormals()
# export the connectors
numconnectors = len(connectors)
if numconnectors:
out.write('CONNECTORS %i\n' % numconnectors)
for c in connectors:
x, y, z = c.getLocation()
out.write(point_format % (x * 128, -y * 128, z * 128))
out.close()
def pie_sel_process(ui):
pie_names, pie_parts, levels, connectors = list(), list(), list(), list()
for ob in Object.Get():
name = ob.getName()
if name.startswith("PIE_"):
pie_names.append(name)
pie_parts.append([list(), list()])
elif name.startswith("LEVEL_"):
levels.append(ob)
elif name.startswith("CONNECTOR_"):
connectors.append(ob)
if len(pie_names) == 0:
Draw.PupMenu("Error %t|No valid PIE objects found")
# return False
for i, lst in enumerate((levels, connectors)):
for ob in lst:
parent = ob.getParent()
if parent:
name = parent.getName()
if name in pie_names:
index = pie_names.index(name)
pie_parts[index][i].append(ob)
sort_key = lambda ob: ob.getName()
pie_errors = list()
for i, children in enumerate(pie_parts):
children[0].sort(key=sort_key)
children[1].sort(key=sort_key)
pie_errors.append(validate(children[0]))
rows = min(11, len(pie_names))
ui.setData('pie_selection', [Draw.Create(not i) for i in pie_errors])
ui.setData('pie_filenames', [Draw.Create( \
normalizeObjectName(name[4:].lower()) + '.pie') for name in pie_names])
ui.setData('rows', rows)
ui.setData("pie_errors", pie_errors)
ui.setData("pie_names", pie_names)
ui.setData("pie_parts", pie_parts)
ui.setScrollRange(0, len(pie_names) - rows)
def pie_sel_draw(ui):
pie_names = ui.getData('pie_names')
pie_parts = ui.getData('pie_parts')
num_pies = len(pie_names)
Draw.PushButton("Cancel", num_pies + 1, 68, 10, 140, 30, "Cancel the import operation")
Draw.PushButton("Proceed", num_pies, 217, 10, 140, 30, "Confirm texpage selection and continue")
BGL.glClearColor(0.7, 0.7, 0.7, 1)
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
BGL.glColor3f(0.8, 0.8, 0.8)
BGL.glRecti(5, 5, 430, 390)
BGL.glColor3f(0.7, 0.7, 0.7)
BGL.glRecti(10, 355, 425, 385)
BGL.glRecti(10, 45, 425, 325)
scroll = ui.getData('scroll-position', 0)
pie_errors = ui.getData('pie_errors')
pie_selection = ui.getData('pie_selection')
pie_filenames = ui.getData('pie_filenames')
rows = ui.getData('rows')
ypos = 301
row_height = 20
ymargin = 5
for i in xrange(scroll, scroll + rows):
if pie_errors[i]:
Draw.PushButton('!! ' + pie_names[i], i, 15, ypos, 160, row_height,
"cannot be exported with errors. click to view errors")
else:
pie_selection[i] = Draw.Toggle(pie_names[i], i, 15, ypos, 160, row_height,
pie_selection[i].val, "select/deselect this object for export")
pie_filenames[i] = Draw.String('', i, 180, ypos, 240, row_height,
pie_filenames[i].val, 80, "filename to export")
ypos -= row_height + ymargin
dir = ui.getData('export-dir', Draw.Create(os.getcwd()))
dir = Draw.String("dir: ", num_pies + 4, 10, 330, 340, 20, dir.val, 399)
ui.setData('export-dir', dir)
Draw.PushButton("Browse", num_pies + 3, 355, 330, 70, 20)
BGL.glColor3i(0, 0, 0)
text = ("Select PIEs to export", "large")
BGL.glRasterPos2i(int((425 - Draw.GetStringWidth(*text)) / 2 + 10), 366)
Draw.Text(*text)
def pie_sel_evt(ui, val):
pie_errors = ui.getData('pie_errors')
num_pies = len(pie_errors)
if val >= num_pies:
val -= num_pies
if val == 0:
dir = ui.getData('export-dir').val
if not dir: dir = './'
else:
if not os.path.isdir(dir):
Draw.PupMenu('Error %t|' + dir + ' is not a valid directory')
return
pie_sel = ui.getData('pie_selection')
pie_parts = ui.getData('pie_parts')
pie_filenames = ui.getData('pie_filenames')
pies = dict()
for i, name in enumerate(pie_filenames):
if not pie_errors[i] and pie_sel[i].val:
pies[name.val] = pie_parts[i]
ui.setData('pies', pies, True)
dir = ui.getData('export-dir').val
ui.setData('export-dir', dir, True)
return True
elif val == 1:
return False
elif 3 == val:
setdir = lambda path: ui.setData('export-dir', Draw.Create(path))
Window.FileSelector(setdir, 'Select export path', '')
Draw.Redraw()
return
pie_names = ui.getData('pie_names')
if pie_errors[val]:
Draw.PupMenu("Errors in " + pie_names[val] + " %t|" + \
'|'.join(["%s: %s" % err for err in pie_errors[val]]))
return
if not ui.getData('pie_filenames')[val].val:
ui.getData('pie_selection')[val].val = 0
Draw.Redraw()
def opts_draw(ui):
precision = ui.getData('precision', Draw.Create(0))
if precision.val > 0: pie_version = 5
else: pie_version = 2
Blender.Draw.Label("Version: PIE %i" % pie_version, 10, 80, 130, 30)
precision = Blender.Draw.Number("precision", 2, 10, 50, 130, 30,
precision.val, 0, 5)
Blender.Draw.Button("Export", 0, 10, 10, 60, 30)
Blender.Draw.Button("Cancel", 1, 80, 10, 60, 30)
ui.setData('precision', precision)
def opts_evt(ui, val):
if 0 == val:
precision = ui.getData('precision').val
ui.debug("starting export at floating-point precision of %i" % precision)
ui.setData('precision', precision, True)
return True
elif 1 == val:
return False
else:
Draw.Redraw()
def export_process(ui):
dir = ui.getData('export-dir')
for name, parts in ui.getData('pies').iteritems():
name = os.path.join(dir, name)
ui.debug('exporting to ' + name)
fs_callback(ui, name, *parts)
ui = BeltFedUI(True)
ui.append(pie_sel_process, pie_sel_draw, pie_sel_evt)
ui.append(None, opts_draw, opts_evt)
ui.append(export_process)
ui.Run()