509 lines
14 KiB
Python
Executable File
509 lines
14 KiB
Python
Executable File
#
|
|
# Torque Game Engine DTS exporter for blender
|
|
#
|
|
import Blender
|
|
import string
|
|
#from Blender import NMesh,Object
|
|
from math import *
|
|
|
|
VERSION = "0.1"
|
|
|
|
##############################
|
|
# Vector class
|
|
##############################
|
|
class Vector:
|
|
members = [0, 0, 0]
|
|
def __init__(self, x, y, z):
|
|
self.members = [float(x), float(y), float(z)]
|
|
def __getitem__(self, key):
|
|
return(self.members[key])
|
|
def __setitem__(self, key, value):
|
|
self.members[key] = value
|
|
def __add__(self, other):
|
|
# iterate through the members
|
|
for i in range(len(self.members)):
|
|
# add them together
|
|
self[i] = float(self[i]) + float(other[i])
|
|
return(self)
|
|
def __sub__(self, other):
|
|
# iterate through the members
|
|
for i in range(len(self.members)):
|
|
# subtract them
|
|
self[i] = float(self[i]) - float(other[i])
|
|
return(self)
|
|
def __mul__(self, other):
|
|
# iterate through the members
|
|
for i in range(len(self.members)):
|
|
# multiply by the val stored in other
|
|
self[i] *= float(other)
|
|
return(self)
|
|
def __div__(self, other):
|
|
# iterate through the members
|
|
for i in range(len(self.members)):
|
|
# divide by the val stored in other
|
|
self[i] /= float(other)
|
|
return(self)
|
|
#def normalize(self):
|
|
##############################
|
|
# end of Vector class
|
|
##############################
|
|
##############################
|
|
# Node class - DTS tree node
|
|
##############################
|
|
class Node:
|
|
name = 0 # index of its name in the DTS string table
|
|
parent = -1 # number of the parent node; -1 if root
|
|
firstObject = -1 # deprecated; set to -1
|
|
child = -1 # deprecated; set to -1
|
|
sibling = -1 # deprecated; set to -1
|
|
##############################
|
|
# end of Node class
|
|
##############################
|
|
##############################
|
|
# Object class - DTS object
|
|
##############################
|
|
class Object:
|
|
name = 0 # index of its name in the DTS string table
|
|
numMeshes = 0 # number of meshes (only one for detail level)
|
|
firstMesh = 0 # number of the first mesh (meshes must be consecutive)
|
|
node = 0 # number of the node where the object is stored
|
|
sibling = -1 # deprecated; set to -1
|
|
firstDecal = -1 # deprecated; set to -1
|
|
##############################
|
|
# end of Object class
|
|
##############################
|
|
##############################
|
|
# Material class - DTS material
|
|
##############################
|
|
class Material:
|
|
name = 0 # texture name; materials don't use the DTS string table
|
|
flags = 0 # boolean properties
|
|
reflectance = 0 # number of reflectance map?
|
|
bump = 0 # number of bump map? or -1 if none
|
|
detail = 0 # number of detail map? or -1 if none
|
|
detailScale = 0 # ?
|
|
reflection = 0 # ?
|
|
# material flags
|
|
SWrap = 0x00000001
|
|
TWrap = 0x00000002
|
|
Translucent = 0x00000004
|
|
Additive = 0x00000008
|
|
Subtractive = 0x00000010
|
|
SelfIlluminating = 0x00000020
|
|
NeverEnvMap = 0x00000040
|
|
NoMipMap = 0x00000080
|
|
MipMapZeroBorder = 0x00000100
|
|
IFLMaterial = 0x00000000
|
|
IFLFrame = 0x10000000
|
|
DetailMap = 0x20000000
|
|
BumpMap = 0x40000000
|
|
ReflectanceMap = 0x80000000
|
|
AuxiliaryMask = 0xF0000000
|
|
##############################
|
|
# end of Material class
|
|
##############################
|
|
##############################
|
|
# IFLMaterial class - DTS animated material
|
|
##############################
|
|
class IFLMaterial:
|
|
name = 0
|
|
slot = 0
|
|
firstFrame = 0
|
|
time = 0
|
|
numFrames = 0
|
|
##############################
|
|
# end of IFLMaterial class
|
|
##############################
|
|
##############################
|
|
# DetailLevel class - DTS detail level
|
|
##############################
|
|
class DetailLevel:
|
|
name = 0 # index of the name in the DTS string table
|
|
subshape = 0 # number of the subshape it belongs to
|
|
objectDetail = 0 # number of object mesh to draw for each object
|
|
size = 0 # minimum pixel size
|
|
avgError = -1 # ?
|
|
maxError = -1 # ?
|
|
polyCount = 0 # polygon count of the meshes to draw
|
|
##############################
|
|
# end of DetailLevel class
|
|
##############################
|
|
##############################
|
|
# Subshape class - DTS subshape (defines a range of nodes and objects)
|
|
##############################
|
|
class Subshape:
|
|
firstNode = 0
|
|
firstObject = 0
|
|
firstDecal = 0
|
|
numNodes = 0
|
|
numObjects = 0
|
|
numDecals = 0
|
|
firstTranslucent = 0 # not used?
|
|
##############################
|
|
# end of Subshape class
|
|
##############################
|
|
##############################
|
|
# ObjectState class - related to animated materials?
|
|
##############################
|
|
class ObjectState:
|
|
vis = 0
|
|
frame = 0
|
|
matFrame = 0
|
|
##############################
|
|
# end of ObjectState class
|
|
##############################
|
|
##############################
|
|
# Trigger class
|
|
##############################
|
|
class Trigger:
|
|
state = 0
|
|
pos = 0
|
|
##############################
|
|
# end of Trigger class
|
|
##############################
|
|
##############################
|
|
# Sequence class
|
|
##############################
|
|
nameIndex = 0
|
|
flags = 0
|
|
numKeyFrames = 0
|
|
duration = 0
|
|
priority = 0
|
|
firstGroundFrame = 0
|
|
numGroundFrames = 0
|
|
baseRotation = 0
|
|
baseTranslation = 0
|
|
baseScale = 0
|
|
baseObjectState = 0
|
|
baseDecalState = 0
|
|
firstTrigger = 0
|
|
numTriggers = 0
|
|
toolBegin = 0
|
|
matters = 0
|
|
# flags
|
|
UniformScale = 0x0001
|
|
AlignedScale = 0x0002
|
|
ArbitraryScale = 0x0004
|
|
Blend = 0x0008
|
|
Cyclic = 0x0010
|
|
MakePath = 0x0020
|
|
IFLInit = 0x0040
|
|
HasTranslucency = 0x0080
|
|
##############################
|
|
# end of Sequence class
|
|
##############################
|
|
##############################
|
|
# Matters class
|
|
##############################
|
|
class Matters:
|
|
rotation = 0
|
|
translation = 0
|
|
scale = 0
|
|
decal = 0
|
|
ifl = 0
|
|
vis = 0
|
|
frame = 0
|
|
matframe = 0
|
|
##############################
|
|
# end of Matters class
|
|
##############################
|
|
##############################
|
|
# Box class
|
|
##############################
|
|
class Box:
|
|
min = Vector
|
|
max = Vector
|
|
##############################
|
|
# end of Box class
|
|
##############################
|
|
##############################
|
|
# Primitive class
|
|
##############################
|
|
class Primitive:
|
|
firstElement = 0
|
|
numElements = 0
|
|
type = 0
|
|
# types
|
|
Triangles = 0x00000000
|
|
Strip = 0x40000000
|
|
Fan = 0x80000000 # may not be supported in the engine?
|
|
TypeMask = 0xC0000000
|
|
Indexed = 0x20000000 # not supported in the engine?
|
|
NoMaterial = 0x10000000
|
|
MaterialMask = 0x0FFFFFFF
|
|
##############################
|
|
# end of Primitive class
|
|
##############################
|
|
##############################
|
|
# Primitive class
|
|
##############################
|
|
class Mesh:
|
|
# members
|
|
type = 0
|
|
numFrames = 0
|
|
matFRames = 0
|
|
parent = 0
|
|
|
|
verts = []
|
|
tverts = []
|
|
normals = []
|
|
enormals = []
|
|
primitives = []
|
|
indices = []
|
|
mindices = []
|
|
### BOX ###
|
|
bounds = Box
|
|
### BOX ###
|
|
center = Vector(0, 0, 0)
|
|
radius = 0
|
|
vertsPerFrame = 0
|
|
flags = 0
|
|
# data used by skin meshes
|
|
vindex = 0
|
|
vbone = 0
|
|
vweight = 0
|
|
nodeIndex = 0
|
|
nodeTransform = 0
|
|
|
|
# types
|
|
T_Standard = 0
|
|
T_Skin = 1
|
|
T_Decal = 2
|
|
T_Sorted = 3
|
|
T_Null = 4
|
|
# flags
|
|
Billboard = 0x80000000
|
|
HasDetail = 0x40000000
|
|
BillboardZ = 0x20000000
|
|
EncodedNormals = 0x10000000
|
|
|
|
def __init__(self, t):
|
|
self.bounds.min = Vector(0, 0, 0)
|
|
self.bounds.max = Vector(0, 0, 0)
|
|
self.center = Vector(0, 0, 0)
|
|
self.radius = float(0.0)
|
|
self.numFrames = 1
|
|
self.matFrames = 1
|
|
self.vertsPerFrame = 0
|
|
self.parent = -1
|
|
self.flags = 0
|
|
self.type = t
|
|
def getType(self):
|
|
return(type)
|
|
def setType(self, t):
|
|
type = t
|
|
def setFlag(self, f):
|
|
flags |= f
|
|
def getPolyCount(self):
|
|
count = 0
|
|
for p in range(len(primitives)):
|
|
if (primitives[p].type & Primitive.Stripe):
|
|
count += primitives[p].numElements - 2
|
|
else:
|
|
count += primitives[p].numElements / 3
|
|
return(count)
|
|
def getRadius(self):
|
|
return(radius)
|
|
def getCenter(self):
|
|
return(center)
|
|
def getBounds(self):
|
|
return(bounds)
|
|
def setMaterial(self, n):
|
|
for p in range(len(primitives)):
|
|
p.type = (p.type & ~Primitive.MaterialMask) | (n & Primitive.MaterialMask)
|
|
def getVertexBone(self, node):
|
|
b = 0
|
|
for b in range(len(nodeIndex)):
|
|
if (nodeIndex[b] == node):
|
|
return(b)
|
|
def getNodeIndexCount(self):
|
|
return(len(nodeIndex))
|
|
def getNodeIndex(self, node):
|
|
if node >= 0:
|
|
if node < len((nodeIndex)):
|
|
return(nodeIndex[node])
|
|
return(-1)
|
|
#def setNodeTransform(self, node, t, q):
|
|
def setCenter(self, c):
|
|
center = c
|
|
def setBounds(self, b):
|
|
bounds = b
|
|
def setRadius(self, r):
|
|
radius = r
|
|
def setFrames(self, n):
|
|
self.numFrames = n
|
|
self.vertsPerFrame = len(self.verts)/n
|
|
def setParent(self, n):
|
|
parent = n
|
|
def calculateBounds(self):
|
|
self.bounds.max = Vector(-10e30, -10e30, -10e30)
|
|
self.bounds.min = Vector(10e30, 10e30, 10e30)
|
|
for vertex in self.verts:
|
|
if vertex[0] < self.bounds.min[0]:
|
|
self.bounds.min[0] = vertex[0]
|
|
if vertex[1] < self.bounds.min[1]:
|
|
self.bounds.min[1] = vertex[1]
|
|
if vertex[2] < self.bounds.min[2]:
|
|
self.bounds.min[2] = vertex[2]
|
|
if vertex[0] > self.bounds.max[0]:
|
|
self.bounds.max[0] = vertex[0]
|
|
if vertex[1] > self.bounds.max[1]:
|
|
self.bounds.max[1] = vertex[1]
|
|
if vertex[2] > self.bounds.max[2]:
|
|
self.bounds.max[2] = vertex[2]
|
|
def calculateCenter(self):
|
|
for v in range(len(self.bounds.max.members)):
|
|
self.center[v] = ((self.bounds.min.members[v] - self.bounds.max.members[v])/2) + self.bounds.max.members[v]
|
|
def calculateRadius(self):
|
|
for vertex in self.verts:
|
|
tV = vertex - self.center
|
|
result = 0
|
|
for n in range(len(tV.members)):
|
|
result += tV.members[n] * tV.members[n]
|
|
distance = sqrt(result)
|
|
if distance > self.radius:
|
|
self.radius = distance
|
|
def encodeNormal(self, p):
|
|
bestIndex = 0
|
|
#def save(self):
|
|
##############################
|
|
# end of Mesh class
|
|
##############################
|
|
##############################
|
|
# Shape class
|
|
##############################
|
|
class Shape:
|
|
nodes = 0
|
|
objects = 0
|
|
decals = 0
|
|
subshapes = 0
|
|
IFLmaterials = 0
|
|
materials = 0
|
|
nodeDefRotations = 0
|
|
nodeDefTranslations = 0
|
|
|
|
#def save(self):
|
|
#def read(self):
|
|
#def getBounds(self):
|
|
#def getRadius(self):
|
|
#def getTubeRadius(self):
|
|
#def addName(self, s):
|
|
#def calculateBounds(self):
|
|
#def calculateRadius(self):
|
|
#def calculateTubeRadius(self):
|
|
#def calculateCenter(self):
|
|
#def setSmallestSize(self, i):
|
|
#def setCenter(self, p):
|
|
#def getNodeWorldPosRot(self, n, trans, rot):
|
|
#def write(self):
|
|
##############################
|
|
# end of Shape class
|
|
##############################
|
|
|
|
# functions
|
|
# strips the path off of a filepath specified.
|
|
def basename(filepath):
|
|
if "\\" in filepath:
|
|
words = string.split(filepath, "\\")
|
|
else:
|
|
words = string.split(filepath, "/")
|
|
words = string.split(words[-1], ".")
|
|
return string.join(words[:-1], ".")
|
|
|
|
def process_objects(objnames):
|
|
# objects
|
|
dtsobjs = []
|
|
numdtsobjs = 0
|
|
print "Objects:"
|
|
for objname in objnames:
|
|
if not type(objname.data) == Blender.Types.NMeshType:
|
|
continue
|
|
print "--> ", objname.data.name
|
|
print "location = ", objname.getLocation()
|
|
meshobj = Blender.NMesh.GetRaw(objname.data.name)
|
|
dtsobj = Mesh(Mesh.T_Standard)
|
|
dtsobj.numFrames = 1
|
|
dtsobj.matFrames = 1
|
|
dtsobj.verts = []
|
|
dtsobj.tverts = []
|
|
dtsobj.normals = []
|
|
dtsobj.enormals = []
|
|
# get verts, uv coords, normals, and enormals
|
|
for v in range(len(meshobj.verts)):
|
|
###print "v = ", v, "x = ", meshobj.verts[v].co[0], ", y = ", meshobj.verts[v].co[1], ", z = ", meshobj.verts[v].co[2]
|
|
# verts
|
|
dtsobj.verts.append(Vector(meshobj.verts[v].co[0], meshobj.verts[v].co[1], meshobj.verts[v].co[2]))
|
|
|
|
# uv coords
|
|
dtsobj.tverts.append(meshobj.verts[v].uvco[0])
|
|
dtsobj.tverts.append(meshobj.verts[v].uvco[1])
|
|
|
|
# normals
|
|
dtsobj.normals.append(meshobj.verts[v].no[0])
|
|
dtsobj.normals.append(meshobj.verts[v].no[1])
|
|
dtsobj.normals.append(meshobj.verts[v].no[2])
|
|
|
|
# enormals
|
|
dtsobj.enormals.append(meshobj.verts[v].no[0])
|
|
dtsobj.enormals.append(meshobj.verts[v].no[1])
|
|
dtsobj.enormals.append(meshobj.verts[v].no[2])
|
|
for f in meshobj.faces:
|
|
print "vIx = ", meshobj.verts.index(f.v[0]), "vIy = ", meshobj.verts.index(f.v[1]), "vIz = ", meshobj.verts.index(f.v[2])
|
|
dtsobj.indices.append(meshobj.verts.index(f.v[2]))
|
|
dtsobj.indices.append(meshobj.verts.index(f.v[1]))
|
|
dtsobj.indices.append(meshobj.verts.index(f.v[0]))
|
|
|
|
# create our primitive
|
|
p = Primitive
|
|
p.firstElement = len(dtsobj.indices)
|
|
p.numElements = 3
|
|
p.type = Primitive.Strip | Primitive.Indexed
|
|
# no materials for now
|
|
p.type |= Primitive.NoMaterial
|
|
|
|
dtsobj.setFrames(1)
|
|
dtsobj.setParent(-1)
|
|
dtsobj.calculateBounds()
|
|
dtsobj.calculateCenter()
|
|
dtsobj.calculateRadius()
|
|
dtsobj.vertsPerFrame = len(dtsobj.verts)
|
|
|
|
dtsobj.primitives.append(p)
|
|
dtsobjs.insert(numdtsobjs, dtsobj)
|
|
numdtsobjs += 1
|
|
|
|
##############################
|
|
# main logic
|
|
##############################
|
|
if __name__ == "__main__":
|
|
print "DTS Exporter running..."
|
|
|
|
# filename to write out
|
|
filename = basename(Blender.Get("filename")) + ".dts"
|
|
print "Writing file: \"%s\"" % filename
|
|
|
|
# get all of the objects
|
|
objs = Blender.Object.get()
|
|
# count the objects
|
|
numdtsobjs = 0
|
|
for objname in objs:
|
|
if not type(objname.data) == Blender.Types.NMeshType:
|
|
continue
|
|
numdtsobjs += 1
|
|
if numdtsobjs <= 0:
|
|
print "Nothing to export"
|
|
exit
|
|
|
|
# process our objects
|
|
process_objects(objs)
|
|
|
|
# fun times
|
|
t = Vector(1, 2, 3)
|
|
s = Vector(3, 3, 4)
|
|
v = s / 2
|
|
print "x = ", v[0], ", y = ", v[1], ", z = ", v[2]
|
|
print "Primitive.Strip = 0x%x" % Primitive.Strip
|
|
# end of the fun times
|
|
|
|
print "DTS Exporter complete."
|