Show ms3d_ascii_export.py syntax highlighted
#!BPY
"""
Name: 'MS3D ASCII (.txt) v 1.5'
Blender: 242
Group: 'Export'
Tooltip: 'MilkShape3d ASCII format for Scorched3d models v1.5'
"""
#Copyright (C) 2004-2007 Paul Vint cbx550f@sourceforge.net
#
# 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.
#
#
#-------------------------------------------------------------
#
# initial alpha release, 17/08/2004
# update: Fixed point of view - front, side top etc are now correct 27/08/2004
# Added error checking for number of verts per face 07/09/2004
# Reversed vertex winding to fix flipped normals problem & misc speedups 12/03/06
# Updated for Blender 2.4x - thanks for the help, Berem!
# TODO: Stop using face nrmals, should be vertex normals! - done. 05/09/06
# Added proper support for emitted light 05/11/06
import Blender
from Blender import Draw, BGL
from Blender.BGL import *
from Blender.Draw import *
import os, time, sys
import meshtools
import mesh_tri2quad
## Events
EVENT_NOEVENT = 1
EVENT_DRAW = 2
EVENT_EXIT = 3
EVENT_EXPORT = 4
EVENT_CHOOSE_FILENAME = 5
EVENT_PROGRESS = 6
def stripPath(path):
return path.split('/')[-1].split('\\')[-1]
def fs_callback(filename):
global FILENAME
if filename.find('.txt', -4) <= 0: filename += '.txt'
FILENAME.val = filename
#write(filename)
def createS3DPath():
global FILENAME
filename = Blender.Get('filename')
if filename.find('.') != -1:
filename = filename.split('.')[0]
filename += ".txt"
#return filename
FILENAME.val = filename
return filename
def fileSelect():
Blender.Window.FileSelector(fs_callback, "Select", createS3DPath())
FILENAME = Create('filename')
createS3DPath()
showProgress = Create(1)
### Basic GUI functions
def draw(): # Define the draw function (which draws your GUI).
#Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT) # This clears the window
# Add here drawing commands to draw your GUI, for example:
#Blender.Draw.Toggle("Clear origin",1,10,20,100,20,0,"Tooltip")
# The line abive will draw a toggle button.
# Note the first number, '1' means this is button number 1
global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT,EVENT_EXPORT,EVENT_CHOOSE_FILENAME,FILENAME,EVENT_PROGRESS, showProgress
ypos = 110
glClear(GL_COLOR_BUFFER_BIT)
glRasterPos2d(8, ypos)
Text("MilkShape3d ASCII Export version 1.5")
glRasterPos2d(8, ypos - 15)
Text("Copyright 2007 - Paul Vint cbx550f@users.sourceforge.net")
glRasterPos2d(8, ypos - 30)
Text("For updates visit http://sourceforge.net/projects/scorched3d-mods")
## Buttons etc
glRasterPos2d(8, 83)
Button("Export",EVENT_EXPORT, 10, 10, 80, 18)
Button("Exit",EVENT_EXIT, 140, 10, 80, 18)
showProgress = Toggle("Show Progress",EVENT_PROGRESS,10, 30, 80, 18, showProgress.val, "Deselect to disable the progress bar (faster exporting)")
glRasterPos2d(8, 83)
FILENAME = String("Filename: ", EVENT_NOEVENT, 10, 55, 210, 18,
FILENAME.val, 255, ".txt file to export")
Button("Browse",EVENT_CHOOSE_FILENAME,220,55,80,18)
def event(evt,val): # Define mouse and keyboard press events
if (evt == Blender.Draw.ESCKEY): # Example if esc key pressed
Blender.Draw.Exit() # then exit script
return # return from the function
def bevent(evt): #Manage button events
global FILENAME,showProgress
if (evt == EVENT_EXIT):
Blender.Draw.Exit()
return
elif (evt == EVENT_CHOOSE_FILENAME):
fileSelect()
Blender.Redraw()
return
elif (evt == EVENT_EXPORT):
#print showProgress
#showProgress = showProgress
write(FILENAME.val)
Blender.Draw.Exit()
return
#Blender.Draw.Register(draw,event,button)
#======= Write ms3d .txt format =========
dbg = 0 #set to enable debugging
def write(filename):
global showProgress
print showProgress
start = time.clock()
convertToTris = 0;
if Blender.sys.exists(filename) and (Blender.Draw.PupMenu("File exists, replace?%t|YES|NO") == 2):
fileSelect()
return
file = open(filename, "wb")
# ms3d header
file.write("// MilkShape 3D ASCII\n\nFrames: 30\nFrame: 1\n\n")
file.write("Meshes: " + str(len(Blender.Object.GetSelected())) + '\n')
objects = Blender.Object.GetSelected()
for obj in range(len(objects)):
meshname = objects[ obj].data.name
mesh = Blender.NMesh.GetRaw(meshname)
thismesh = meshname
if dbg:
print "\nDEBUG: Mesh", mesh, "Obj: ", obj, "Name: ", objects[obj].data.name
if mesh:
print "Mesh",objects[obj].data.name,
meshname = "\"" + objects[obj].data.name + "\" 0 " + str(obj) + "\n" # Setting flags=0, mat index=object number for now, also note that I'm using object name, not meshname
file.write(meshname)
file.write(str(3 * len(mesh.faces)) + '\n') # should be better way to get # of verts, but this is fast
for i in range(len(mesh.faces)): # New in v 0.3 - getting verts from faces directly
faceVerts = len(mesh.faces[i].v) # Reversing the winding to fix flipped normals problem
for fv in range(faceVerts): # Scan through each vert in face
line = '0 ' + str(-round(mesh.faces[i].v[faceVerts-fv-1][0],4)) + ' ' + str(round(mesh.faces[i].v[faceVerts-fv-1][2],4)) + ' ' + str(round(-mesh.faces[i].v[faceVerts-fv-1][1],4)) + ' ' #+ str(round(mesh.faces[i].uv[fv][0],5)) + ' ' + str(round(mesh.faces[i].uv[fv][1],5)) + ' -1\n'
if (len(mesh.faces[i].uv)):
line += str(round(mesh.faces[i].uv[faceVerts-fv-1][0],5)) + ' ' + str(round(1-mesh.faces[i].uv[faceVerts-fv-1][1],5)) + ' -1\n'
else:
line += '0.0 0.0 -1\n'
if not i%50 and showProgress.val:
Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), thismesh + "Verts")
file.write(line)
# Normals
#print "Norms: ",len(mesh.faces), #FIX! Temp only using # of faces
file.write(str(3 * len(mesh.faces)))
for i in range(len(mesh.faces)):
if not i%50 and showProgress.val:
Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), thismesh + "Normals")
#file.write('\n' + str(round(mesh.faces[i].no[0],4)) + ' ' + str(round(mesh.faces[i].no[2],4)) + ' ' + str(round(mesh.faces[i].no[1],4)))
faceVerts = len(mesh.faces[i].v)
for fv in range(faceVerts): # Scan through each vert in face
file.write('\n' + str(round(-mesh.faces[i].v[faceVerts-fv-1].no[0],4)))
file.write(' ' + str(round(mesh.faces[i].v[faceVerts-fv-1].no[2],4)))
file.write(' ' + str(round(-mesh.faces[i].v[faceVerts-fv-1].no[1],4)))
# Faces
print "Triangles: " ,len(mesh.faces)
file.write('\n' + str(len(mesh.faces)) + '\n')
idx = 0
line = ""
for i in range(len(mesh.faces)): # one face at a time
if not i%50 and showProgress.val:
Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), thismesh + "Triangles")
if (len(mesh.faces[i].v) != 3): #Ensure each face is a triangle!
print "\n\n*********** Error! **********\n"
print "Object",objects[obj].data.name, "has", len(mesh.faces[i].v), "vertices in face", i, "Must have THREE verts per face - convert to triangles with CTRL-T!"
Blender.Window.WaitCursor(0)
exitmsg = 'MS3D Export Error:|Mesh \"' + objects[obj].data.name + '\" has ' + str(len(mesh.faces[i].v)) + ' verts in a face, needs to be converted to triangles with CTRL-T!'
Blender.Draw.PupMenu(exitmsg)
return
#if convertToTris==0: #only ask once
# print "Object",objects[obj].data.name, "has", len(mesh.faces[i].v), "vertices in face", i, "Must have THREE verts per face"
# convertToTris=Blender.Draw.PupMenu("Model not made entirely out of Triangles-Convert?%t|YES|NO")
#if convertToTris==1:
# for f in mesh.faces:
# f.sel = 1
# Blender.Mesh.Mode(3)
# mesh.quadToTriangle(0)
#elif convertToTris==2:
# exitmsg = 'MS3D Export Error:|Mesh \"' + objects[obj].data.name + '\" has ' + str(len(mesh.faces[i].v)) + ' verts in a face, needs to be converted to triangles with CTRL-T!'
# Blender.Draw.PupMenu(exitmsg)
# return
for v in range(len(mesh.faces[i].v)): #Go through each vertex in face - only need triangles for MS3D, but this would allow for quads too for portability
line += str(idx) + " "
idx += 1
#print cnt #debug info
#file.write('1 ' + line + str( i) + ' ' + str(i) + ' ' + str(i) + ' 1\n')
file.write('1 ' + line + line + ' 1\n')
line = "" # fresh start for next face
######### Materials! ##########
numMats = 0
for obj in range(len(objects)): #FIXME! Stupid cludge for counting materials
meshname = objects[ obj].data.name
mesh = Blender.NMesh.GetRaw(meshname)
if (len(mesh.materials) == 0): #Ensure the mesh has a material
print '*** Error! ', meshname, 'must have a material & texture!'
message = 'MS3D Export Error:|Mesh \"' + objects[obj].data.name + '\"needs to have a material!'
meshtools.print_boxed(message)
Blender.Window.WaitCursor(0)
Blender.Draw.PupMenu(message)
return
if mesh.materials[0]:
numMats+=1
file.write("\nMaterials: " + str(numMats) + "\n")
for obj in range(len(objects)):
meshname = objects[ obj].data.name
mesh = Blender.NMesh.GetRaw(meshname)
for material in mesh.materials:
file.write("\"" + material.name + "\"\n")
#file.write(str(round(material.ref,5))+ " " + str(round(material.ref,5))+ " " + str(round(material.ref,5)) + " " + str(round(material.alpha,5)) + "\n")
#TODO Why are these values the same??? TODO
# file.write(str("%5f %5f %5f %5f\n" % (material.ref,material.ref,material.ref,material.alpha)))
file.write(str("%5f %5f %5f %5f\n" % (material.amb,material.amb,material.amb,material.alpha)))
#file.write(str(round(material.rgbCol[0],5)) + " " + str(round(material.rgbCol[1],5)) + " " + str(round(material.rgbCol[2],5)) + " " + str(round(material.alpha,5)) + "\n")
file.write(str("%5f %5f %5f %5f\n" % (material.rgbCol[0],material.rgbCol[1],material.rgbCol[2],material.alpha)))
file.write(str("%5f %5f %5f %5f\n" % (material.spec,material.spec,material.spec,material.alpha)))
#file.write(str(round(material.spec,5)) + " " + str(round(material.spec,5)) + " " + str(round(material.spec,5)) + " " + str(round(material.alpha,5)))
file.write(str("%5f %5f %5f %5f\n" % (material.emit,material.emit,material.emit,material.alpha)))
file.write(str(material.ref) + "\n")
file.write(str(material.alpha) + "\n")
# get the current texture image
imageName=""
mytex = material.getTextures()
if (dbg):
print 'MyTex: ', mytex[0]
if ( mytex[0] != None ):
image = material.getTextures()[0].tex.getImage()
imageName = Blender.sys.basename(image.getFilename())
file.write("\".\\" + stripPath(imageName) + "\"")
else:
print 'Warning: Mesh ' + meshname + ' does not have a texture image!'
message = 'MS3D Export Warning:|Mesh \"' + meshname + '\" does not have a texture image!'
meshtools.print_boxed(message)
Blender.Window.WaitCursor(0)
Blender.Draw.PupMenu(message)
file.write("\"\"")
#file.write("\".\\" + imageName + "\"")
file.write("\n\"\"\n")
file.write('\nBones: 0\n') # we don't need no stinking bones for Scorched! ;)
file.write('GroupComments: 0\n')
file.write('MaterialComments: 0\n')
file.write('BoneComments: 0\n')
file.write('ModelComment: 0\n')
Blender.Window.DrawProgressBar(1.0, '') #clear progressbar
file.close()
end = time.clock()
seconds = " in %.2f %s" % (end-start, "seconds")
message = "Successfully exported " + os.path.basename(filename) + seconds
meshtools.print_boxed(message)
Blender.Window.WaitCursor(0)
Blender.Draw.PupMenu(message)
return
Blender.Draw.Register(draw,event,bevent)
See more files for this project here