diff --git a/release/scripts/blender2cal3d.py b/release/scripts/blender2cal3d.py
index 3d7d148a55c..835ec16ae1f 100644
--- a/release/scripts/blender2cal3d.py
+++ b/release/scripts/blender2cal3d.py
@@ -1,56 +1,15 @@
#!BPY
"""
-Name: 'Cal3D Exporter V0.7'
-Blender: 234
+Name: 'Cal3D v0.9'
+Blender: 235
Group: 'Export'
-Tip: 'Export armature/bone data to the Cal3D library.'
+Tip: 'Export armature/bone/mesh/action data to the Cal3D format.'
"""
-__author__ = ["Jean-Baptiste Lamy (Jiba)", "Chris Montijin", "Damien McGinnes"]
-__url__ = ("blender", "elysiun", "Cal3D, http://cal3d.sf.net")
-__version__ = "0.7"
-
-__bpydoc__ = """\
-This script exports armature / bone data to the well known open source Cal3D
-library.
-
-Usage:
-
-Simply run the script to export available armatures.
-
-Supported:
- Cal3D versions 0.7 -> 0.9.
-
-Known issues:
- Material color is not supported yet;
- Cal3D springs (for clothes and hair) are not supported yet;
- Cal3d has a bug in that a cycle that doesn't have a root bone channel
-will segfault cal3d. Until cal3d supports this, add a keyframe for the
-root bone;
- When you finish an animation and run the script you can get an error
-(something with KeyError). Just save your work and reload the model. This is
-usually caused by deleted items hanging around;
- If a vertex is assigned to one or more bones, but has for each bone a
-weight of zero, there used to be a subdivision by zero error somewhere. As a
-workaround, if sum is 0.0 then sum becomes 1.0. It's recommended that you give
-weights to all bones to avoid problems.
-
-Notes:
- Objects/bones/actions whose names start by "_" are not exported so call IK
-and null bones _LegIK, for example;
- All your armature's exported bones must be connected to another bone
- (except for the root bone). Contrary to Blender, Cal3D doesn't support
-"floating" bones.
- Actions that start with '@' will be exported as actions, others will be
-exported as cycles.
-"""
-
-# $Id$
-#
-# Copyright (C) 2003 Jean-Baptiste LAMY -- jiba@tuxfamily.org
-# Copyright (C) 2004 Chris Montijin
-# Copyright (C) 2004 Damien McGinnes
+# blender2cal3D.py
+# Copyright (C) 2003-2004 Jean-Baptiste LAMY -- jibalamy@free.fr
+# Copyright (C) 2004 Matthias Braun -- matze@braunis.de
#
# 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
@@ -67,150 +26,111 @@ exported as cycles.
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-# This script is a Blender 2.34 => Cal3D 0.7/0.8/0.9 converter.
-# (See http://blender.org and http://cal3d.sourceforge.net)
-#
+__version__ = "0.11"
+__author__ = "Jean-Baptiste 'Jiba' Lamy"
+__email__ = ["Author's email, jibalamy:free*fr"]
+__url__ = ["Soya3d's homepage, http://home.gna.org/oomadness/en/soya/",
+ "Cal3d, http://cal3d.sourceforge.net"]
+__bpydoc__ = """\
+This script is a Blender => Cal3D converter.
+(See http://blender.org and http://cal3d.sourceforge.net)
-# This script was written by Jiba, modified by Chris and later modified by Damien
+USAGE:
-# Changes:
-#
-# 0.7 Damien McGinnes
-# Added NLA functionality for IPOs - this simplifies
-# the animation export and speeds it up significantly
-# it also removes the constraints on channel names -
-# they no longer have to match the bone or action and
-# .L .R etc are supported
-# bones starting with _ are not exported
-# textures no longer flipped vertically
-# fixed a filename bug for .csf and .cfg
-# actions that are prefixed with '@' go into the cfg file
-# as actions rather than cycles
-# works with baked IK actions, unbaked ones wont work well
-# because you wont have the constraints evaluated
-# added an FPS slider into the gui
-# added registry saving for gui state.
-#
-# 0.6 Chris Montjin
-# Updated for Blender 2.32, 2.33
-# added basic GUI
-# generally improved flexibility
-#
-# 0.5 Jiba
-# Initial Release for Blender 2.28
+To install it, place the script in your $HOME/.blender/scripts directory.
+
+Then open the File->Export->Cal3d v0.9 menu. And select the filename of the .cfg file.
+The exporter will create a set of other files with same prefix (ie. bla.cfg, bla.xsf,
+bla_Action1.xaf, bla_Action2.xaf, ...).
+
+You should be able to open the .cfg file in cal3d_miniviewer.
+NOT (YET) SUPPORTED:
-# HOW TO USE :
-# 1 - load the script in Blender's text editor
-# 2 - type M-P (meta/alt + P) and wait until script execution is finished
-# or install it in .scripts and access from the export menu
-
-# ADVICE
-# - Objects/bones/actions whose names start by "_" are not exported
-# so call IK and null bones _LegIK for example
-# - All your armature's exported bones must be connected to another bone (except
-# for the rootbone). Contrary to Blender, Cal3D doesn't support "floating" bones.
-# - Actions that start with '@' will be exported as actions, others will be
-# exported as cycles
-
-# BUGS / TODO :
-# - Material color is not supported yet
-# - Cal3D springs (for clothes and hair) are not supported yet
-# - Cal3d has a bug in that a cycle that doesnt have as rootbone channel
-# will segfault cal3d. until cal3d supports this, add a keyframe for the rootbone
+ - Rotation, translation, or stretching Blender objects is still quite
+buggy, so AVOID MOVING / ROTATING / RESIZE OBJECTS (either mesh or armature) !
+Instead, edit the object (with tab), select all points / bones (with "a"),
+and move / rotate / resize them.
+ - no support for exporting springs yet
+ - no support for exporting material colors (most games should only use images
+I think...)
-# REMARKS
-# 1. When you finished an animation and run the script
-# you can get an error (something with KeyError). Just save your work,
-# and reload the model. This is usualy caused by deleted items hanging around
-# 2. If a vertex is assigned to one or more bones, but is has a for each
-# bone a weight of zero, there was a subdivision by zero somewhere
-# Made a workaround (if sum is 0.0 then sum becomes 1.0).
-# I have not checked what the outcome of that is, so you better nail 'm,
-# and give it some weight...
+KNOWN ISSUES:
+ - Cal3D versions <=0.9.1 have a bug where animations aren't played when the root bone
+is not animated;
+ - Cal3D versions <=0.9.1 have a bug where objects that aren't influenced by any bones
+are not drawn (fixed in Cal3D CVS).
+
+
+NOTES:
+
+It requires a very recent version of Blender (>= 2.35).
+
+Build a model following a few rules:
+ - Use only a single armature;
+ - Use only a single rootbone (Cal3D doesn't support floating bones);
+ - Use only locrot keys (Cal3D doesn't support bone's size change);
+ - Don't try to create child/parent constructs in blender object, that gets exported
+incorrectly at the moment;
+ - Don't put "." in action or bone names, and do not start these names by a figure;
+ - Objects or animations whose names start by "_" are not exported (hidden object).
+
+It can be run in batch mode, as following :
+ blender model.blend -P blender2cal3d.py --blender2cal3d FILENAME=model.cfg EXPORT_FOR_SOYA=1
+
+You can pass as many parameters as you want at the end, "EXPORT_FOR_SOYA=1" is just an
+example. The parameters are the same as below.
+"""
# Parameters :
-# The directory where the data are saved.
-SAVE_TO_DIR = "/tmp/tutorial/"
+# Filename to export to (if "", display a file selector dialog).
+FILENAME = ""
-# Delete all existing Cal3D files in directory?
-DELETE_ALL_FILES = 0
-
-# What do you wanna export? If all are true then a .cfg file is created,
-# otherwise no .cfg file is made. You have to make one by hand.
-EXPORT_SKELETON = 1
-EXPORT_ANIMATION = 0
-EXPORT_MESH = 1
-EXPORT_MATERIAL = 0
-
-# Prefix for all created files
-FILE_PREFIX = "Test"
-
-# Remove path from imagelocation
-REMOVE_PATH_FROM_IMAGE = 0
-
-# prefix or subdir for imagepathname (if you place your textures in a
-# subdir or just need a prefix or something). Only used when
-# REMOVE_PATH_FROM_IMAGE = 1. Set to "" if none.
-IMAGE_PREFIX = "textures/"
-
-# Export to new (>= 900) Cal3D XML-format
-EXPORT_TO_XML = 0
-
-# Set scalefactor for model
-SCALE = 0.5
-
-# frames per second - used to convert blender frames to times
-FPS = 25
-
-# Use this dictionary to rename animations, as their name is lost at the
-# exportation.
-RENAME_ANIMATIONS = {
- # "OldName" : "NewName",
-
- }
-
-# True (=1) to export for the Soya 3D engine
-# (http://oomadness.tuxfamily.org/en/soya).
+# True (=1) to export for the Soya 3D engine
+# (http://oomadness.tuxfamily.org/en/soya).
# (=> rotate meshes and skeletons so as X is right, Y is top and -Z is front)
EXPORT_FOR_SOYA = 0
+# Enables LODs computation. LODs computation is quite slow, and the algo is
+# surely not optimal :-(
+LODS = 0
+
+# Scale the model (not supported by Soya).
+SCALE = 1.0
+
+# Set to 1 if you want to prefix all filename with the model name
+# (e.g. knight_walk.xaf instead of walk.xaf)
+PREFIX_FILE_WITH_MODEL_NAME = 0
+
+# Set to 0 to use Cal3D binary format
+XML = 1
+
+
+MESSAGES = ""
+
# See also BASE_MATRIX below, if you want to rotate/scale/translate the model at
# the exportation.
-
-# Enables LODs computation. LODs computation is quite slow, and the algo is
-# surely not optimal :-(
-LODS = 0
-
-#remove the word '.BAKED' from exported baked animations
-REMOVE_BAKED = 1
-
-
-################################################################################
+#########################################################################################
# Code starts here.
-# The script should be quite re-useable for writing another Blender animation
-# exporter. Most of the hell of it is to deal with Blender's head-tail-roll
-# bone's definition.
+# The script should be quite re-useable for writing another Blender animation exporter.
+# Most of the hell of it is to deal with Blender's head-tail-roll bone's definition.
import sys, os, os.path, struct, math, string
import Blender
-from Blender.BGL import *
-from Blender.Draw import *
-from Blender.Armature import *
-from Blender.Registry import *
# HACK -- it seems that some Blender versions don't define sys.argv,
# which may crash Python if a warning occurs.
-
if not hasattr(sys, "argv"): sys.argv = ["???"]
-# Math stuff
+# transforms a blender to a cal3d quaternion notation (x,y,z,w)
+def blender2cal3dquat(q):
+ return [q.x, q.y, q.z, q.w]
def quaternion2matrix(q):
xx = q[0] * q[0]
@@ -222,12 +142,10 @@ def quaternion2matrix(q):
wx = q[3] * q[0]
wy = q[3] * q[1]
wz = q[3] * q[2]
- return [
- [1.0 - 2.0 * (yy + zz), 2.0 * (xy + wz), 2.0 * (xz - wy), 0.0],
- [2.0 * (xy - wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + wx), 0.0],
- [2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (xx + yy), 0.0],
- [0.0, 0.0, 0.0, 1.0]
- ]
+ return [[1.0 - 2.0 * (yy + zz), 2.0 * (xy + wz), 2.0 * (xz - wy), 0.0],
+ [ 2.0 * (xy - wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + wx), 0.0],
+ [ 2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (xx + yy), 0.0],
+ [0.0 , 0.0 , 0.0 , 1.0]]
def matrix2quaternion(m):
s = math.sqrt(abs(m[0][0] + m[1][1] + m[2][2] + m[3][3]))
@@ -249,25 +167,14 @@ def quaternion_normalize(q):
l = math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3])
return q[0] / l, q[1] / l, q[2] / l, q[3] / l
+# multiplies 2 quaternions in x,y,z,w notation
def quaternion_multiply(q1, q2):
- r = [
+ return [
q2[3] * q1[0] + q2[0] * q1[3] + q2[1] * q1[2] - q2[2] * q1[1],
q2[3] * q1[1] + q2[1] * q1[3] + q2[2] * q1[0] - q2[0] * q1[2],
q2[3] * q1[2] + q2[2] * q1[3] + q2[0] * q1[1] - q2[1] * q1[0],
q2[3] * q1[3] - q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2],
]
- d = math.sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2] + r[3] * r[3])
- if d == 0:
- r[0] = d
- r[1] = d
- r[2] = d
- r[3] = d
- else:
- r[0] /= d
- r[1] /= d
- r[2] /= d
- r[3] /= d
- return r
def matrix_translate(m, v):
m[3][0] += v[0]
@@ -369,9 +276,9 @@ def matrix_rotate(axis, angle):
sin = math.sin(angle)
co1 = 1.0 - cos
return [
- [vx2 * co1 + cos, vx * vy * co1 + vz * sin, vz * vx * co1 - vy * sin, 0.0],
- [vx * vy * co1 - vz * sin, vy2 * co1 + cos, vy * vz * co1 + vx * sin, 0.0],
- [vz * vx * co1 + vy * sin, vy * vz * co1 - vx * sin, vz2 * co1 + cos, 0.0],
+ [vx2 * co1 + cos, vx * vy * co1 + vz * sin, vz * vx * co1 - vy * sin, 0.0],
+ [vx * vy * co1 - vz * sin, vy2 * co1 + cos, vy * vz * co1 + vx * sin, 0.0],
+ [vz * vx * co1 + vy * sin, vy * vz * co1 - vx * sin, vz2 * co1 + cos, 0.0],
[0.0, 0.0, 0.0, 1.0],
]
@@ -389,9 +296,14 @@ def point_by_matrix(p, m):
p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]]
def point_distance(p1, p2):
- return math.sqrt((p2[0] - p1[0]) ** 2 + \
- (p2[1] - p1[1]) ** 2 + (p2[2] - p1[2]) ** 2)
+ return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2 + (p2[2] - p1[2]) ** 2)
+def vector_add(v1, v2):
+ return [v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]]
+
+def vector_sub(v1, v2):
+ return [v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]]
+
def vector_by_matrix(p, m):
return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0],
p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1],
@@ -438,46 +350,49 @@ def blender_bone2matrix(head, tail, roll):
bMatrix = matrix_rotate(axis, theta)
else:
- if vector_crossproduct(target, nor) > 0.0: updown = 1.0
- else: updown = -1.0
+ if vector_dotproduct(target, nor) > 0.0: updown = 1.0
+ else: updown = -1.0
# Quoted from Blender source : "I think this should work ..."
bMatrix = [
- [updown, 0.0, 0.0, 0.0],
- [0.0, updown, 0.0, 0.0],
- [0.0, 0.0, 1.0, 0.0],
- [0.0, 0.0, 0.0, 1.0],
+ [updown, 0.0, 0.0, 0.0],
+ [0.0, updown, 0.0, 0.0],
+ [0.0, 0.0, 1.0, 0.0],
+ [0.0, 0.0, 0.0, 1.0],
]
rMatrix = matrix_rotate(nor, roll)
return matrix_multiply(rMatrix, bMatrix)
+# Hack for having the model rotated right.
+# Put in BASE_MATRIX your own rotation if you need some.
+
+BASE_MATRIX = None
+
+
# Cal3D data structures
-CAL3D_VERSION = 700
-CAL3D_XML_VERSION = 900
+CAL3D_VERSION = 910
NEXT_MATERIAL_ID = 0
class Material:
def __init__(self, map_filename = None):
- self.ambient_r = 255
- self.ambient_g = 255
- self.ambient_b = 255
- self.ambient_a = 255
- self.diffuse_r = 255
- self.diffuse_g = 255
- self.diffuse_b = 255
- self.diffuse_a = 255
+ self.ambient_r = 255
+ self.ambient_g = 255
+ self.ambient_b = 255
+ self.ambient_a = 255
+ self.diffuse_r = 255
+ self.diffuse_g = 255
+ self.diffuse_b = 255
+ self.diffuse_a = 255
self.specular_r = 255
self.specular_g = 255
self.specular_b = 255
self.specular_a = 255
self.shininess = 1.0
- if map_filename:
- self.maps_filenames = [map_filename]
- else:
- self.maps_filenames = []
+ if map_filename: self.maps_filenames = [map_filename]
+ else: self.maps_filenames = []
MATERIALS[map_filename] = self
@@ -485,37 +400,35 @@ class Material:
self.id = NEXT_MATERIAL_ID
NEXT_MATERIAL_ID += 1
+ # old cal3d format
def to_cal3d(self):
- s = "CRF\0" + struct.pack("iBBBBBBBBBBBBfi", CAL3D_VERSION,
- self.ambient_r, self.ambient_g, self.ambient_b, self.ambient_a,
- self.diffuse_r, self.diffuse_g, self.diffuse_b, self.diffuse_a,
- self.specular_r, self.specular_g, self.specular_b, self.specular_a,
- self.shininess, len(self.maps_filenames))
+ s = "CRF\0" + struct.pack("iBBBBBBBBBBBBfi", CAL3D_VERSION, self.ambient_r, self.ambient_g, self.ambient_b, self.ambient_a, self.diffuse_r, self.diffuse_g, self.diffuse_b, self.diffuse_a, self.specular_r, self.specular_g, self.specular_b, self.specular_a, self.shininess, len(self.maps_filenames))
for map_filename in self.maps_filenames:
s += struct.pack("i", len(map_filename) + 1)
s += map_filename + "\0"
return s
-
+
+ # new xml format
def to_cal3d_xml(self):
- s = "\n" % CAL3D_XML_VERSION
- s += " \n" % len(self.maps_filenames)
- s += " %f %f %f %f\n" % \
- (self.ambient_r, self.ambient_g, self.ambient_b, self.ambient_a)
- s += " %f %f %f %f\n" % \
- (self.diffuse_r, self.diffuse_g, self.diffuse_b, self.diffuse_a)
- s += " %f %f %f %f\n" % \
- (self.specular_r, self.specular_g, self.specular_b, self.specular_a)
- s += " %f\n" % self.shininess
+ s = "\n"
+ s += "\n" % CAL3D_VERSION
+ s += "\n"
+ s += " " + str(self.ambient_r) + " " + str(self.ambient_g) + " " + str(self.ambient_b) + " " + str(self.ambient_a) + "\n";
+ s += " " + str(self.diffuse_r) + " " + str(self.diffuse_g) + " " + str(self.diffuse_b) + " " + str(self.diffuse_a) + "\n";
+ s += " " + str(self.specular_r) + " " + str(self.specular_g) + " " + str(self.specular_b) + " " + str(self.specular_a) + "\n";
+ s += " " + str(self.shininess) + "\n";
for map_filename in self.maps_filenames:
- s += " \n" % map_filename
- s += "\n"
+ s += " \n";
+
+ s += "\n";
+
return s
MATERIALS = {}
class Mesh:
def __init__(self, name):
- self.name = name
+ self.name = name
self.submeshes = []
self.next_submesh_id = 0
@@ -524,21 +437,22 @@ class Mesh:
s = "CMF\0" + struct.pack("ii", CAL3D_VERSION, len(self.submeshes))
s += "".join(map(SubMesh.to_cal3d, self.submeshes))
return s
-
+
def to_cal3d_xml(self):
- s = "\n" % CAL3D_XML_VERSION
+ s = "\n"
+ s += "\n" % CAL3D_VERSION
s += "\n" % len(self.submeshes)
s += "".join(map(SubMesh.to_cal3d_xml, self.submeshes))
- s += "\n"
+ s += "\n"
return s
-
+
class SubMesh:
def __init__(self, mesh, material):
- self.material = material
- self.vertices = []
- self.faces = []
+ self.material = material
+ self.vertices = []
+ self.faces = []
self.nb_lodsteps = 0
- self.springs = []
+ self.springs = []
self.next_vertex_id = 0
@@ -555,41 +469,34 @@ class SubMesh:
for face in self.faces:
for vertex in (face.vertex1, face.vertex2, face.vertex3):
l = vertex2faces.get(vertex)
- if not l:
- vertex2faces[vertex] = [face]
- else:
- l.append(face)
+ if not l: vertex2faces[vertex] = [face]
+ else: l.append(face)
- couple_treated = {}
+ couple_treated = {}
couple_collapse_factor = []
for face in self.faces:
- for a, b in ((face.vertex1, face.vertex2), (face.vertex1, face.vertex3),
- (face.vertex2, face.vertex3)):
+ for a, b in ((face.vertex1, face.vertex2), (face.vertex1, face.vertex3), (face.vertex2, face.vertex3)):
a = a.cloned_from or a
b = b.cloned_from or b
- if a.id > b.id:
- a, b = b, a
+ if a.id > b.id: a, b = b, a
if not couple_treated.has_key((a, b)):
# The collapse factor is simply the distance between the 2 points :-(
# This should be improved !!
- if vector_dotproduct(a.normal, b.normal) < 0.9:
- continue
+ if vector_dotproduct(a.normal, b.normal) < 0.9: continue
couple_collapse_factor.append((point_distance(a.loc, b.loc), a, b))
couple_treated[a, b] = 1
couple_collapse_factor.sort()
- collapsed = {}
+ collapsed = {}
new_vertices = []
- new_faces = []
+ new_faces = []
for factor, v1, v2 in couple_collapse_factor:
# Determines if v1 collapses to v2 or v2 to v1.
- # We choose to keep the vertex which is on the
- # smaller number of faces, since
+ # We choose to keep the vertex which is on the smaller number of faces, since
# this one has more chance of being in an extrimity of the body.
# Though heuristic, this rule yields very good results in practice.
- if len(vertex2faces[v1]) < len(vertex2faces[v2]):
- v2, v1 = v1, v2
+ if len(vertex2faces[v1]) < len(vertex2faces[v2]): v2, v1 = v1, v2
elif len(vertex2faces[v1]) == len(vertex2faces[v2]):
if collapsed.get(v1, 0): v2, v1 = v1, v2 # v1 already collapsed, try v2
@@ -597,13 +504,12 @@ class SubMesh:
collapsed[v1] = 1
collapsed[v2] = 1
- # Check if v2 is already collapsed
- while v2.collapse_to:
- v2 = v2.collapse_to
+ # Check if v2 is already colapsed
+ while v2.collapse_to: v2 = v2.collapse_to
common_faces = filter(vertex2faces[v1].__contains__, vertex2faces[v2])
- v1.collapse_to = v2
+ v1.collapse_to = v2
v1.face_collapse_count = len(common_faces)
for clone in v1.clones:
@@ -622,11 +528,9 @@ class SubMesh:
clone.face_collapse_count = 0
new_vertices.append(clone)
- # HACK -- all faces get collapsed with v1
- # (and no faces are collapsed with v1's
+ # HACK -- all faces get collapsed with v1 (and no faces are collapsed with v1's
# clones). This is why we add v1 in new_vertices after v1's clones.
- # This hack has no other incidence that consuming
- # a little few memory for the
+ # This hack has no other incidence that consuming a little few memory for the
# extra faces if some v1's clone are collapsed but v1 is not.
new_vertices.append(v1)
@@ -642,8 +546,7 @@ class SubMesh:
vertex2faces[face.vertex3].remove(face)
vertex2faces[v2].extend(vertex2faces[v1])
- new_vertices.extend(filter(lambda vertex: not vertex.collapse_to,
- self.vertices))
+ new_vertices.extend(filter(lambda vertex: not vertex.collapse_to, self.vertices))
new_vertices.reverse() # Cal3D want LODed vertices at the end
for i in range(len(new_vertices)): new_vertices[i].id = i
self.vertices = new_vertices
@@ -652,24 +555,18 @@ class SubMesh:
new_faces.reverse() # Cal3D want LODed faces at the end
self.faces = new_faces
- print "LODs computed : %s vertices can be removed (from a total of %s)." % \
- (self.nb_lodsteps, len(self.vertices))
+ print "LODs computed : %s vertices can be removed (from a total of %s)." % (self.nb_lodsteps, len(self.vertices))
def rename_vertices(self, new_vertices):
- """Rename (change ID) of all vertices, such as self.vertices ==
- new_vertices.
- """
- for i in range(len(new_vertices)):
- new_vertices[i].id = i
+ """Rename (change ID) of all vertices, such as self.vertices == new_vertices."""
+ for i in range(len(new_vertices)): new_vertices[i].id = i
self.vertices = new_vertices
def to_cal3d(self):
- s = struct.pack("iiiiii", self.material.id, len(self.vertices),
- len(self.faces), self.nb_lodsteps, len(self.springs),
- len(self.material.maps_filenames))
+ s = struct.pack("iiiiii", self.material.id, len(self.vertices), len(self.faces), self.nb_lodsteps, len(self.springs), len(self.material.maps_filenames))
s += "".join(map(Vertex.to_cal3d, self.vertices))
s += "".join(map(Spring.to_cal3d, self.springs))
- s += "".join(map(Face.to_cal3d, self.faces))
+ s += "".join(map(Face .to_cal3d, self.faces))
return s
def to_cal3d_xml(self):
@@ -686,16 +583,16 @@ class SubMesh:
class Vertex:
def __init__(self, submesh, loc, normal):
- self.loc = loc
+ self.loc = loc
self.normal = normal
- self.collapse_to = None
+ self.collapse_to = None
self.face_collapse_count = 0
- self.maps = []
+ self.maps = []
self.influences = []
self.weight = None
self.cloned_from = None
- self.clones = []
+ self.clones = []
self.submesh = submesh
self.id = submesh.next_vertex_id
@@ -703,20 +600,15 @@ class Vertex:
submesh.vertices.append(self)
def to_cal3d(self):
- if self.collapse_to:
- collapse_id = self.collapse_to.id
- else:
- collapse_id = -1
- s = struct.pack("ffffffii", self.loc[0], self.loc[1], self.loc[2],
- self.normal[0], self.normal[1], self.normal[2], collapse_id,
- self.face_collapse_count)
+ if self.collapse_to: collapse_id = self.collapse_to.id
+ else: collapse_id = -1
+ s = struct.pack("ffffffii", self.loc[0], self.loc[1], self.loc[2], self.normal[0], self.normal[1], self.normal[2], collapse_id, self.face_collapse_count)
s += "".join(map(Map.to_cal3d, self.maps))
s += struct.pack("i", len(self.influences))
s += "".join(map(Influence.to_cal3d, self.influences))
- if not self.weight is None:
- s += struct.pack("f", len(self.weight))
+ if not self.weight is None: s += struct.pack("f", len(self.weight))
return s
-
+
def to_cal3d_xml(self):
if self.collapse_to:
collapse_id = self.collapse_to.id
@@ -737,7 +629,7 @@ class Vertex:
s += " %f\n" % len(self.weight)
s += " \n"
return s
-
+
class Map:
def __init__(self, u, v):
self.u = u
@@ -745,22 +637,22 @@ class Map:
def to_cal3d(self):
return struct.pack("ff", self.u, self.v)
-
+
def to_cal3d_xml(self):
- return " %f %f\n" % (self.u, self.v)
-
+ return " %f %f\n" % (self.u, self.v)
+
class Influence:
def __init__(self, bone, weight):
- self.bone = bone
+ self.bone = bone
self.weight = weight
def to_cal3d(self):
return struct.pack("if", self.bone.id, self.weight)
-
+
def to_cal3d_xml(self):
return " %f\n" % \
(self.bone.id, self.weight)
-
+
class Spring:
def __init__(self, vertex1, vertex2):
self.vertex1 = vertex1
@@ -769,8 +661,7 @@ class Spring:
self.idlelength = 0.0
def to_cal3d(self):
- return struct.pack("iiff", self.vertex1.id, self.vertex2.id,
- self.spring_coefficient, self.idlelength)
+ return struct.pack("iiff", self.vertex1.id, self.vertex2.id, self.spring_coefficient, self.idlelength)
def to_cal3d_xml(self):
return " \n" % \
@@ -790,11 +681,11 @@ class Face:
def to_cal3d(self):
return struct.pack("iii", self.vertex1.id, self.vertex2.id, self.vertex3.id)
-
+
def to_cal3d_xml(self):
return " \n" % \
(self.vertex1.id, self.vertex2.id, self.vertex3.id)
-
+
class Skeleton:
def __init__(self):
self.bones = []
@@ -807,7 +698,8 @@ class Skeleton:
return s
def to_cal3d_xml(self):
- s = "\n" % CAL3D_XML_VERSION
+ s = "\n"
+ s += "\n" % CAL3D_VERSION
s += "\n" % len(self.bones)
s += "".join(map(Bone.to_cal3d_xml, self.bones))
s += "\n"
@@ -818,7 +710,7 @@ BONES = {}
class Bone:
def __init__(self, skeleton, parent, name, loc, rot):
self.parent = parent
- self.name = name
+ self.name = name
self.loc = loc
self.rot = rot
self.children = []
@@ -828,8 +720,8 @@ class Bone:
self.matrix = matrix_multiply(parent.matrix, self.matrix)
parent.children.append(self)
- # lloc and lrot are the bone => model space transformation
- # (translation and rotation). They are probably specific to Cal3D.
+ # lloc and lrot are the bone => model space transformation (translation and rotation).
+ # They are probably specific to Cal3D.
m = matrix_invert(self.matrix)
self.lloc = m[3][0], m[3][1], m[3][2]
self.lrot = matrix2quaternion(m)
@@ -842,23 +734,18 @@ class Bone:
BONES[name] = self
def to_cal3d(self):
- s = struct.pack("i", len(self.name) + 1) + self.name + "\0"
+ s = struct.pack("i", len(self.name) + 1) + self.name + "\0"
# We need to negate quaternion W value, but why ?
- s += struct.pack("ffffffffffffff", self.loc[0], self.loc[1], self.loc[2],
- self.rot[0], self.rot[1], self.rot[2], -self.rot[3],
- self.lloc[0], self.lloc[1], self.lloc[2],
- self.lrot[0], self.lrot[1], self.lrot[2], -self.lrot[3])
- if self.parent:
- s += struct.pack("i", self.parent.id)
- else:
- s += struct.pack("i", -1)
+ s += struct.pack("ffffffffffffff", self.loc[0], self.loc[1], self.loc[2], self.rot[0], self.rot[1], self.rot[2], -self.rot[3], self.lloc[0], self.lloc[1], self.lloc[2], self.lrot[0], self.lrot[1], self.lrot[2], -self.lrot[3])
+ if self.parent: s += struct.pack("i", self.parent.id)
+ else: s += struct.pack("i", -1)
s += struct.pack("i", len(self.children))
s += "".join(map(lambda bone: struct.pack("i", bone.id), self.children))
return s
-
+
def to_cal3d_xml(self):
- s = " \n" % \
+ s = " \n" % \
(self.id, self.name, len(self.children))
# We need to negate quaternion W value, but why ?
s += " %f %f %f\n" % \
@@ -877,31 +764,30 @@ class Bone:
self.children))
s += " \n"
return s
-
+
class Animation:
- def __init__(self, name, action, duration = 0.0):
- self.name = name
- self.action = action
+ def __init__(self, name, duration = 0.0):
+ self.name = name
self.duration = duration
- self.tracks = {} # Map bone names to tracks
+ self.tracks = {} # Map bone names to tracks
def to_cal3d(self):
- s = "CAF\0" + struct.pack("ifi",
- CAL3D_VERSION, self.duration, len(self.tracks))
+ s = "CAF\0" + struct.pack("ifi", CAL3D_VERSION, self.duration, len(self.tracks))
s += "".join(map(Track.to_cal3d, self.tracks.values()))
return s
-
+
def to_cal3d_xml(self):
- s = "\n" % CAL3D_XML_VERSION
+ s = "\n"
+ s += "\n" % CAL3D_VERSION
s += "\n" % \
- (self.duration, len(self.tracks))
+ (self.duration, len(self.tracks))
s += "".join(map(Track.to_cal3d_xml, self.tracks.values()))
s += "\n"
- return s
-
+ return s
+
class Track:
def __init__(self, animation, bone):
- self.bone = bone
+ self.bone = bone
self.keyframes = []
self.animation = animation
@@ -911,7 +797,7 @@ class Track:
s = struct.pack("ii", self.bone.id, len(self.keyframes))
s += "".join(map(KeyFrame.to_cal3d, self.keyframes))
return s
-
+
def to_cal3d_xml(self):
s = "