Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillian Padovani Germano <wpgermano@gmail.com>2004-11-30 05:27:46 +0300
committerWillian Padovani Germano <wpgermano@gmail.com>2004-11-30 05:27:46 +0300
commit6d9c02be4cfd61b985af789e167f7fa78dbc0868 (patch)
tree1bb8758f454cb90e0659e6122f11ec13b02a7b3f /release
parente4562134d28af07b6115436fdfaa4523020ea733 (diff)
Scripts:
- Fixes by Jean-Michel Soler: mod_ai2obj.py, mod_svg2obj.py; - Fixes by Campbell Barton: obj_import.py; - Small fix to mod_meshtools.py (fixes bug #1605: http://projects.blender.org/tracker/?func=detail&atid=125&aid=1605&group_id=9); - Updates by Jean-Baptiste (Jiba) to his blender2cal3d.py; - Updates to all his import / export scripts (added doc data) by Anthony D'Agostino; - Update to off_import: support for uv data, by Arne Schmitz. BPython: - Removed Object.get and .getSelected (deprecated long ago, we use .Get and .GetSelected) -- fixes #1861: http://projects.blender.org/tracker/?func=detail&atid=125&aid=1861&group_id=9 - Applied patch by Michael Reimpell: quat.c - fix for wrong initialization with newQuaternionObject; Mathutils documentation improvements. - Stani reported a wrong return msg in IpoCurve.Get (that is unimplemented). Thanks to all coders mentioned above!
Diffstat (limited to 'release')
-rw-r--r--release/scripts/blender2cal3d.py1444
-rw-r--r--release/scripts/lightwave_export.py23
-rw-r--r--release/scripts/lightwave_import.py24
-rw-r--r--release/scripts/mod_ai2obj.py9
-rw-r--r--release/scripts/mod_meshtools.py3
-rw-r--r--release/scripts/mod_svg2obj.py47
-rw-r--r--release/scripts/nendo_export.py33
-rw-r--r--release/scripts/nendo_import.py29
-rw-r--r--release/scripts/obj_import.py73
-rw-r--r--release/scripts/off_export.py18
-rw-r--r--release/scripts/off_import.py32
-rw-r--r--release/scripts/radiosity_export.py24
-rw-r--r--release/scripts/radiosity_import.py10
-rw-r--r--release/scripts/raw_export.py11
-rw-r--r--release/scripts/raw_import.py15
-rw-r--r--release/scripts/slp_import.py12
-rw-r--r--release/scripts/truespace_export.py35
-rw-r--r--release/scripts/truespace_import.py58
-rw-r--r--release/scripts/videoscape_export.py29
-rw-r--r--release/scripts/wings_export.py29
-rw-r--r--release/scripts/wings_import.py26
21 files changed, 957 insertions, 1027 deletions
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:<br>
- Cal3D versions 0.7 -> 0.9.
-
-Known issues:<br>
- Material color is not supported yet;<br>
- Cal3D springs (for clothes and hair) are not supported yet;<br>
- 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;<br>
- 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;<br>
- 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:<br>
- Objects/bones/actions whose names start by "_" are not exported so call IK
-and null bones _LegIK, for example;<br>
- 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.<br>
- 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)
-#
-
-# This script was written by Jiba, modified by Chris and later modified by Damien
-
-# Changes:
-#
-# 0.7 Damien McGinnes <mcginnes at netspeed com au>
-# 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 <jiba@tuxfamily.org>
-# Initial Release for Blender 2.28
+__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)
+USAGE:
+To install it, place the script in your $HOME/.blender/scripts directory.
-# 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
+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, ...).
-# 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
+You should be able to open the .cfg file in cal3d_miniviewer.
-# 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
+NOT (YET) SUPPORTED:
-# 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...
+ - 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.<br>
+ - no support for exporting springs yet<br>
+ - no support for exporting material colors (most games should only use images
+I think...)
-# Parameters :
+KNOWN ISSUES:
-# The directory where the data are saved.
-SAVE_TO_DIR = "/tmp/tutorial/"
+ - Cal3D versions <=0.9.1 have a bug where animations aren't played when the root bone
+is not animated;<br>
+ - Cal3D versions <=0.9.1 have a bug where objects that aren't influenced by any bones
+are not drawn (fixed in Cal3D CVS).
-# 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
+NOTES:
-# Prefix for all created files
-FILE_PREFIX = "Test"
+It requires a very recent version of Blender (>= 2.35).
-# Remove path from imagelocation
-REMOVE_PATH_FROM_IMAGE = 0
+Build a model following a few rules:<br>
+ - Use only a single armature;<br>
+ - Use only a single rootbone (Cal3D doesn't support floating bones);<br>
+ - Use only locrot keys (Cal3D doesn't support bone's size change);<br>
+ - Don't try to create child/parent constructs in blender object, that gets exported
+incorrectly at the moment;<br>
+ - Don't put "." in action or bone names, and do not start these names by a figure;<br>
+ - Objects or animations whose names start by "_" are not exported (hidden object).
-# 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/"
+It can be run in batch mode, as following :<br>
+ blender model.blend -P blender2cal3d.py --blender2cal3d FILENAME=model.cfg EXPORT_FOR_SOYA=1
-# Export to new (>= 900) Cal3D XML-format
-EXPORT_TO_XML = 0
+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.
+"""
-# Set scalefactor for model
-SCALE = 0.5
+# Parameters :
-# frames per second - used to convert blender frames to times
-FPS = 25
+# Filename to export to (if "", display a file selector dialog).
+FILENAME = ""
-# 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
-# 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
+# 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
+# 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.
-################################################################################
+#########################################################################################
# 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 = "<HEADER MAGIC=\"XRF\" VERSION=\"%i\"/>\n" % CAL3D_XML_VERSION
- s += " <MATERIAL NUMMAPS=\"%i\">\n" % len(self.maps_filenames)
- s += " <AMBIENT>%f %f %f %f</AMBIENT>\n" % \
- (self.ambient_r, self.ambient_g, self.ambient_b, self.ambient_a)
- s += " <DIFFUSE>%f %f %f %f</DIFFUSE>\n" % \
- (self.diffuse_r, self.diffuse_g, self.diffuse_b, self.diffuse_a)
- s += " <SPECULAR>%f %f %f %f</SPECULAR>\n" % \
- (self.specular_r, self.specular_g, self.specular_b, self.specular_a)
- s += " <SHININESS>%f</SHININESS>\n" % self.shininess
+ s = "<?xml version=\"1.0\"?>\n"
+ s += "<HEADER MAGIC=\"XRF\" VERSION=\"%i\"/>\n" % CAL3D_VERSION
+ s += "<MATERIAL NUMMAPS=\"" + str(len(self.maps_filenames)) + "\">\n"
+ s += " <AMBIENT>" + str(self.ambient_r) + " " + str(self.ambient_g) + " " + str(self.ambient_b) + " " + str(self.ambient_a) + "</AMBIENT>\n";
+ s += " <DIFFUSE>" + str(self.diffuse_r) + " " + str(self.diffuse_g) + " " + str(self.diffuse_b) + " " + str(self.diffuse_a) + "</DIFFUSE>\n";
+ s += " <SPECULAR>" + str(self.specular_r) + " " + str(self.specular_g) + " " + str(self.specular_b) + " " + str(self.specular_a) + "</SPECULAR>\n";
+ s += " <SHININESS>" + str(self.shininess) + "</SHININESS>\n";
for map_filename in self.maps_filenames:
- s += " <MAP>%s</MAP>\n" % map_filename
- s += "</MATERIAL>\n"
+ s += " <MAP>" + map_filename + "</MAP>\n";
+
+ s += "</MATERIAL>\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 = "<HEADER MAGIC=\"XMF\" VERSION=\"%i\"/>\n" % CAL3D_XML_VERSION
+ s = "<?xml version=\"1.0\"?>\n"
+ s += "<HEADER MAGIC=\"XMF\" VERSION=\"%i\"/>\n" % CAL3D_VERSION
s += "<MESH NUMSUBMESH=\"%i\">\n" % len(self.submeshes)
s += "".join(map(SubMesh.to_cal3d_xml, self.submeshes))
- s += "</MESH>\n"
+ s += "</MESH>\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 += " <PHYSIQUE>%f</PHYSIQUE>\n" % len(self.weight)
s += " </VERTEX>\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 " <TEXCOORD>%f %f</TEXCOORD>\n" % (self.u, self.v)
-
+ return " <TEXCOORD>%f %f</TEXCOORD>\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 " <INFLUENCE ID=\"%i\">%f</INFLUENCE>\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 " <SPRING VERTEXID=\"%i %i\" COEF=\"%f\" LENGTH=\"%f\"/>\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 " <FACE VERTEXID=\"%i %i %i\"/>\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 = "<HEADER MAGIC=\"XSF\" VERSION=\"%i\"/>\n" % CAL3D_XML_VERSION
+ s = "<?xml version=\"1.0\"?>\n"
+ s += "<HEADER MAGIC=\"XSF\" VERSION=\"%i\"/>\n" % CAL3D_VERSION
s += "<SKELETON NUMBONES=\"%i\">\n" % len(self.bones)
s += "".join(map(Bone.to_cal3d_xml, self.bones))
s += "</SKELETON>\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 = " <BONE ID=\"%i\" NAME=\"%s\" NUMCHILDS=\"%i\">\n" % \
+ s = " <BONE ID=\"%i\" NAME=\"%s\" NUMCHILD=\"%i\">\n" % \
(self.id, self.name, len(self.children))
# We need to negate quaternion W value, but why ?
s += " <TRANSLATION>%f %f %f</TRANSLATION>\n" % \
@@ -877,31 +764,30 @@ class Bone:
self.children))
s += " </BONE>\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 = "<HEADER MAGIC=\"XAF\" VERSION=\"%i\"/>\n" % CAL3D_XML_VERSION
+ s = "<?xml version=\"1.0\"?>\n"
+ s += "<HEADER MAGIC=\"XAF\" VERSION=\"%i\"/>\n" % CAL3D_VERSION
s += "<ANIMATION DURATION=\"%f\" NUMTRACKS=\"%i\">\n" % \
- (self.duration, len(self.tracks))
+ (self.duration, len(self.tracks))
s += "".join(map(Track.to_cal3d_xml, self.tracks.values()))
s += "</ANIMATION>\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 = " <TRACK BONEID=\"%i\" NUMKEYFRAMES=\"%i\">\n" % \
(self.bone.id, len(self.keyframes))
@@ -922,16 +808,15 @@ class Track:
class KeyFrame:
def __init__(self, track, time, loc, rot):
self.time = time
- self.loc = loc
- self.rot = rot
+ self.loc = loc
+ self.rot = rot
self.track = track
track.keyframes.append(self)
def to_cal3d(self):
# We need to negate quaternion W value, but why ?
- return struct.pack("ffffffff", self.time, self.loc[0], self.loc[1],
- self.loc[2], self.rot[0], self.rot[1], self.rot[2], -self.rot[3])
+ return struct.pack("ffffffff", self.time, self.loc[0], self.loc[1], self.loc[2], self.rot[0], self.rot[1], self.rot[2], -self.rot[3])
def to_cal3d_xml(self):
s = " <KEYFRAME TIME=\"%f\">\n" % self.time
@@ -941,633 +826,394 @@ class KeyFrame:
s += " <ROTATION>%f %f %f %f</ROTATION>\n" % \
(self.rot[0], self.rot[1], self.rot[2], -self.rot[3])
s += " </KEYFRAME>\n"
- return s
-
-
-def export():
- global STATUS
- STATUS = "Start export..."
- Draw()
-
- # Hack for having the model rotated right.
- # Put in BASE_MATRIX your own rotation if you need some.
+ return s
+def export(filename):
+ global MESSAGES
+
if EXPORT_FOR_SOYA:
+ global BASE_MATRIX
BASE_MATRIX = matrix_rotate_x(-math.pi / 2.0)
- else:
- BASE_MATRIX = None
-
+
# Get the scene
-
scene = Blender.Scene.getCurrent()
-
- # Export skeleton (=armature)
-
- STATUS = "Calculate skeleton"
- Draw()
+ # ---- Export skeleton (=armature) ----------------------------------------
skeleton = Skeleton()
+ foundarmature = False
for obj in Blender.Object.Get():
data = obj.getData()
- if type(data) is Blender.Types.ArmatureType:
- matrix = obj.getMatrix()
- if BASE_MATRIX: matrix = matrix_multiply(BASE_MATRIX, matrix)
+ if type(data) is not Blender.Types.ArmatureType:
+ continue
+
+ if foundarmature == True:
+ MESSAGES += "Found multiple armatures! '" + obj.getName() + "' ignored.\n"
+ continue
+
+ foundarmature = True
+ matrix = obj.getMatrix()
+ if BASE_MATRIX:
+ matrix = matrix_multiply(BASE_MATRIX, matrix)
+
+ def treat_bone(b, parent = None):
+ head = b.getHead()
+ tail = b.getTail()
+
+ # Turns the Blender's head-tail-roll notation into a quaternion
+ quat = matrix2quaternion(blender_bone2matrix(head, tail, b.getRoll()))
- def treat_bone(b, parent = None):
- #skip bones that start with _
- #also skips children of that bone so be careful
- if b.getName()[0] == '_' : return
- head = b.getHead()
- tail = b.getTail()
+ if parent:
+ # Compute the translation from the parent bone's head to the child
+ # bone's head, in the parent bone coordinate system.
+ # The translation is parent_tail - parent_head + child_head,
+ # but parent_tail and parent_head must be converted from the parent's parent
+ # system coordinate into the parent system coordinate.
- # Turns the Blender's head-tail-roll notation into a quaternion
- quat = matrix2quaternion(blender_bone2matrix(head, tail, b.getRoll()))
+ parent_invert_transform = matrix_invert(quaternion2matrix(parent.rot))
+ parent_head = vector_by_matrix(parent.head, parent_invert_transform)
+ parent_tail = vector_by_matrix(parent.tail, parent_invert_transform)
+
+ ploc = vector_add(head, b.getLoc())
+ parentheadtotail = vector_sub(parent_tail, parent_head)
+ # hmm this should be handled by the IPos, but isn't for non-animated
+ # bones which are transformed in the pose mode...
+ #loc = vector_add(ploc, parentheadtotail)
+ #rot = quaternion_multiply(blender2cal3dquat(b.getQuat()), quat)
+ loc = parentheadtotail
+ rot = quat
- if parent:
- # Compute the translation from the parent bone's head to the child
- # bone's head, in the parent bone coordinate system.
- # The translation is parent_tail - parent_head + child_head,
- # but parent_tail and parent_head must be converted from the parent's
- # parent system coordinate into the parent system coordinate.
-
- parent_invert_transform = matrix_invert(quaternion2matrix(parent.rot))
- parent_head = vector_by_matrix(parent.head, parent_invert_transform)
- parent_tail = vector_by_matrix(parent.tail, parent_invert_transform)
-
- bone = Bone(skeleton, parent, b.getName(),
- [parent_tail[0] - parent_head[0] + head[0],
- parent_tail[1] - parent_head[1] + head[1],
- parent_tail[2] - parent_head[2] + head[2]], quat)
- else:
- # Apply the armature's matrix to the root bones
- head = point_by_matrix(head, matrix)
- tail = point_by_matrix(tail, matrix)
- quat = matrix2quaternion(matrix_multiply(matrix,
- quaternion2matrix(quat))) # Probably not optimal
-
- # Here, the translation is simply the head vector
- bone = Bone(skeleton, parent, b.getName(), head, quat)
-
- bone.head = head
- bone.tail = tail
+ bone = Bone(skeleton, parent, b.getName(), loc, rot)
+ else:
+ # Apply the armature's matrix to the root bones
+ head = point_by_matrix(head, matrix)
+ tail = point_by_matrix(tail, matrix)
+ quat = matrix2quaternion(matrix_multiply(matrix, quaternion2matrix(quat))) # Probably not optimal
+
+ # loc = vector_add(head, b.getLoc())
+ # rot = quaternion_multiply(blender2cal3dquat(b.getQuat()), quat)
+ loc = head
+ rot = quat
- for child in b.getChildren():
- treat_bone(child, bone)
+ # Here, the translation is simply the head vector
+ bone = Bone(skeleton, None, b.getName(), loc, rot)
- for b in data.getBones():
- # treat this bone if not already treated as a child bone
- if not BONES.has_key(b.getName()):
- treat_bone(b)
+ bone.head = head
+ bone.tail = tail
- # Only one armature / skeleton
- break
-
-
- # Export Mesh data
-
- if EXPORT_MESH or EXPORT_MATERIAL:
-
- STATUS = "Calculate mesh and materials"
- Draw()
+ for child in b.getChildren():
+ treat_bone(child, bone)
+
+ foundroot = False
+ for b in data.getBones():
+ # child bones are handled in treat_bone
+ if b.getParent() != None:
+ continue
+ if foundroot == True:
+ print "Warning: Found multiple root-bones, this may not be supported in cal3d."
+ #print "Ignoring bone '" + b.getName() + "' and it's childs."
+ #continue
+
+ treat_bone(b)
+ foundroot = True
- meshes = []
+ # ---- Export Mesh data ---------------------------------------------------
+
+ meshes = []
+
+ for obj in Blender.Object.Get():
+ data = obj.getData()
+ if (type(data) is Blender.Types.NMeshType) and data.faces:
+ mesh_name = obj.getName()
+ mesh = Mesh(mesh_name)
+ meshes.append(mesh)
- for obj in Blender.Object.Get():
- data = obj.getData()
- if (type(data) is Blender.Types.NMeshType) and data.faces and EXPORT_MESH:
- mesh = Mesh(obj.name)
-
- if mesh.name[0] == '_' :
- print "skipping object ", mesh.name
- continue
-
- meshes.append(mesh)
-
- matrix = obj.getMatrix()
- if BASE_MATRIX:
- matrix = matrix_multiply(BASE_MATRIX, matrix)
-
- faces = data.faces
- while faces:
- image = faces[0].image
- image_filename = image and image.filename
- # for windows
- image_filename_t = str(image_filename)
- #print image_filename_t
- # end for windows
- if REMOVE_PATH_FROM_IMAGE:
- if image_filename_t == "None":
- print "Something wrong with material (is none), set name to none..."
- image_file = "none.tga"
- else:
- # for windows
- if image_filename_t[0] == "/":
- tmplist = image_filename_t.split("/")
- else:
- tmplist = image_filename_t.split("\\")
- #print "tmplist: " + repr(tmplist)
- image_file = IMAGE_PREFIX + tmplist[-1]
- # end for windows
- # for linux
- # image_file = IMAGE_PREFIX + os.path.basename(image_filename)
- else:
- image_file = image_filename
- material = MATERIALS.get(image_file) or Material(image_file)
-
- # TODO add material color support here
+ matrix = obj.getMatrix()
+ if BASE_MATRIX:
+ matrix = matrix_multiply(BASE_MATRIX, matrix)
+
+ faces = data.faces
+ while faces:
+ image = faces[0].image
+ image_filename = image and image.filename
+ material = MATERIALS.get(image_filename) or Material(image_filename)
+ outputuv = len(material.maps_filenames) > 0
+
+ # TODO add material color support here
+
+ submesh = SubMesh(mesh, material)
+ vertices = {}
+ for face in faces[:]:
+ if (face.image and face.image.filename) == image_filename:
+ faces.remove(face)
- submesh = SubMesh(mesh, material)
- vertices = {}
- for face in faces[:]:
- if (face.image and face.image.filename) == image_filename:
- faces.remove(face)
+ if not face.smooth:
+ p1 = face.v[0].co
+ p2 = face.v[1].co
+ p3 = face.v[2].co
+ normal = vector_normalize(vector_by_matrix(vector_crossproduct(
+ [p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]],
+ [p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2]],
+ ), matrix))
+
+ face_vertices = []
+ for i in range(len(face.v)):
+ vertex = vertices.get(face.v[i].index)
+ if not vertex:
+ coord = point_by_matrix (face.v[i].co, matrix)
+ if face.smooth:
+ normal = vector_normalize(vector_by_matrix(face.v[i].no, matrix))
+ vertex = vertices[face.v[i].index] = Vertex(submesh, coord, normal)
+
+ influences = data.getVertexInfluences(face.v[i].index)
+ # should this really be a warning? (well currently enabled,
+ # because blender has some bugs where it doesn't return
+ # influences in python api though they are set, and because
+ # cal3d<=0.9.1 had bugs where objects without influences
+ # aren't drawn.
+ if not influences:
+ MESSAGES += "A vertex of object '%s' has no influences.\n(This occurs on objects placed in an invisible layer, you can fix it by using a single layer)\n" \
+ % obj.getName()
+
+ # sum of influences is not always 1.0 in Blender ?!?!
+ sum = 0.0
+ for bone_name, weight in influences:
+ sum += weight
- if not face.smooth:
- #if len(face.v) < 3 :
- # print "mesh contains a dodgy face, skipping it"
- # continue
- p1 = face.v[0].co
- p2 = face.v[1].co
- p3 = face.v[2].co
- normal = vector_normalize(vector_by_matrix(vector_crossproduct(
- [p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]],
- [p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2]],
- ), matrix))
+ for bone_name, weight in influences:
+ if bone_name not in BONES:
+ MESSAGES += "Couldn't find bone '%s' which influences" \
+ "object '%s'.\n" % (bone_name, obj.getName())
+ continue
+ vertex.influences.append(Influence(BONES[bone_name], weight / sum))
- face_vertices = []
- for i in range(len(face.v)):
- vertex = vertices.get(face.v[i].index)
- if not vertex:
- coord = point_by_matrix (face.v[i].co, matrix)
- if face.smooth:
- normal = vector_normalize(vector_by_matrix(face.v[i].no,
- matrix))
- vertex = vertices[face.v[i].index] = Vertex(submesh, coord,
- normal)
-
- influences = data.getVertexInfluences(face.v[i].index)
- if not influences:
- print "Warning: vertex %i (%i) has no influence !" % \
- (face.v[i].index, face.v[i].sel)
-
- # sum of influences is not always 1.0 in Blender ?!?!
- sum = 0.0
- for bone_name, weight in influences:
- sum += weight
-
- # Select vertex with no weight at all (sum = 0.0).
- # To find out which one it is, select part of vertices in mesh,
- # exit editmode and see if value between brackets is 1. If so,
- # the vertex is in selection. You can narrow the selection
- # this way, to find the offending vertex...
- if sum == 0.0:
- print "Warning: vertex %i in mesh %s (selected: %i) has influence sum of 0.0!" % \
- (face.v[i].index, mesh.name, face.v[i].sel)
- print "Set the sum to 1.0, otherwise there will " + \
- "be a division by zero. Better find the offending " + \
- "vertex..."
- # face.v[i].sel = 1 # does not work???
- sum = 1.0
- if face.v[i].sel:
- print "Vertex %i is selected" % (face.v[i].index)
-
- for bone_name, weight in influences:
- #print "bone: %s, weight: %f, sum: %f" % (bone_name, weight, sum)
- vertex.influences.append(Influence(BONES[bone_name],
- weight / sum))
-
- elif not face.smooth:
- # We cannot share vertex for non-smooth faces,
- # since Cal3D does not support vertex sharing
- # for 2 vertices with different normals.
- # => we must clone the vertex.
-
+ elif not face.smooth:
+ # We cannot share vertex for non-smooth faces, since Cal3D does not
+ # support vertex sharing for 2 vertices with different normals.
+ # => we must clone the vertex.
+
+ old_vertex = vertex
+ vertex = Vertex(submesh, vertex.loc, normal)
+ vertex.cloned_from = old_vertex
+ vertex.influences = old_vertex.influences
+ old_vertex.clones.append(vertex)
+
+ if data.hasFaceUV():
+ uv = [face.uv[i][0], 1.0 - face.uv[i][1]]
+ if not vertex.maps:
+ if outputuv: vertex.maps.append(Map(*uv))
+ elif (vertex.maps[0].u != uv[0]) or (vertex.maps[0].v != uv[1]):
+ # This vertex can be shared for Blender, but not for Cal3D !!!
+ # Cal3D does not support vertex sharing for 2 vertices with
+ # different UV texture coodinates.
+ # => we must clone the vertex.
+
+ for clone in vertex.clones:
+ if (clone.maps[0].u == uv[0]) and (clone.maps[0].v == uv[1]):
+ vertex = clone
+ break
+ else: # Not yet cloned...
old_vertex = vertex
- vertex = Vertex(submesh, vertex.loc, normal)
+ vertex = Vertex(submesh, vertex.loc, vertex.normal)
vertex.cloned_from = old_vertex
vertex.influences = old_vertex.influences
+ if outputuv: vertex.maps.append(Map(*uv))
old_vertex.clones.append(vertex)
- if data.hasFaceUV():
- uv = [face.uv[i][0], face.uv[i][1]] #1.0 - face.uv[i][1]]
- if not vertex.maps:
- vertex.maps.append(Map(*uv))
- elif (vertex.maps[0].u != uv[0]) or (vertex.maps[0].v != uv[1]):
- # This vertex can be shared for Blender, but not for Cal3D !!!
- # Cal3D does not support vertex sharing for 2 vertices with
- # different UV texture coodinates.
- # => we must clone the vertex.
-
- for clone in vertex.clones:
- if (clone.maps[0].u == uv[0]) and \
- (clone.maps[0].v == uv[1]):
- vertex = clone
- break
- else: # Not yet cloned...
- old_vertex = vertex
- vertex = Vertex(submesh, vertex.loc, vertex.normal)
- vertex.cloned_from = old_vertex
- vertex.influences = old_vertex.influences
- vertex.maps.append(Map(*uv))
- old_vertex.clones.append(vertex)
-
- face_vertices.append(vertex)
-
- # Split faces with more than 3 vertices
- for i in range(1, len(face.v) - 1):
- Face(submesh, face_vertices[0], face_vertices[i],
- face_vertices[i + 1])
-
- # Computes LODs info
- if LODS:
- submesh.compute_lods()
-
- # Export animations
+ face_vertices.append(vertex)
+
+ # Split faces with more than 3 vertices
+ for i in range(1, len(face.v) - 1):
+ Face(submesh, face_vertices[0], face_vertices[i], face_vertices[i + 1])
- if EXPORT_ANIMATION:
+ # Computes LODs info
+ if LODS:
+ submesh.compute_lods()
+
+ # ---- Export animations --------------------------------------------------
+ ANIMATIONS = {}
- ipoCurveType = ['LocX', 'LocY', 'LocZ', 'QuatX', 'QuatY', 'QuatZ', 'QuatW']
-
- STATUS = "Calculate animations"
- Draw()
+ for a in Blender.Armature.NLA.GetActions().iteritems():
+ animation_name = a[0]
+ animation = Animation(animation_name)
+ animation.duration = 0.0
+
+ for b in a[1].getAllChannelIpos().iteritems():
+ bone_name = b[0]
+ if bone_name not in BONES:
+ MESSAGES += "No Bone '" + bone_name + "' defined (from Animation '" \
+ + animation_name + "' ?!?\n"
+ continue
+
+ bone = BONES[bone_name]
- ANIMATIONS = {}
+ track = Track(animation, bone)
+ track.finished = 0
+ animation.tracks[bone_name] = track
+
+ ipo = b[1]
- actions = Blender.Armature.NLA.GetActions()
-
- for a in actions:
-
- #skip actions beginning with _
- if a[0] == '_' : continue
-
- #create the animation object
- animation_name = a
-
- #if the name starts with @ then it is a oneshot action otherwise its a cycle
- if a[0] == '@':
- animation_name = a.split("@")[1]
- aact = 1
- else:
- aact = 0
-
- print "Animationname: %s" % (animation_name)
-
- if REMOVE_BAKED:
- tmp = animation_name.split('.BAKED')
- animation_name = "".join(tmp)
-
- #check for duplicate animation names and work around
- test = animation_name
- suffix = 1
- while ANIMATIONS.get(test):
- print "Warning %s already exists!! renaming" % animation_name
- test = "%s__%i" % (animation_name, suffix)
- suffix += 1
- animation_name = test
-
- animation = ANIMATIONS[animation_name] = Animation(animation_name, aact)
-
- ipos = actions[a].getAllChannelIpos()
- for bone_name in ipos:
- #skip bones that start with _
- if bone_name[0] == '_' :
- continue
-
- ipo = ipos[bone_name]
- try: nbez = ipo.getNBezPoints(0)
- except TypeError:
- print "No key frame for action %s, ipo %s, skipping..." % (a, bone_name)
- nbez = 0
-
- bone = BONES[bone_name]
- track = animation.tracks.get(bone_name)
- if not track:
- track = animation.tracks[bone_name] = Track(animation, bone)
- track.finished = 0
+ times = []
- curve = []
- for ctype in ipoCurveType:
- curve.append(ipo.getCurve(ctype))
-
- for bez in range(nbez):
- time1 = ipo.getCurveBeztriple(0, bez)[3]
- time = (time1 - 1.0) / FPS
-
- if animation.duration < time:
- animation.duration = time
-
- loc = bone.loc
- rot = bone.rot
-
- if (curve[0]):
- trans = vector_by_matrix((
- curve[0].evaluate(time1),
- curve[1].evaluate(time1),
- curve[2].evaluate(time1)), bone.matrix)
-
- loc = [
- bone.loc[0] + trans[0],
- bone.loc[1] + trans[1],
- bone.loc[2] + trans[2]]
-
- if (curve[3]):
-
- ipo_rot = [
- curve[3].evaluate(time1),
- curve[4].evaluate(time1),
- curve[5].evaluate(time1),
- curve[6].evaluate(time1)]
-
- # We need to blend the rotation from the bone rest state
- # (=bone.rot) with ipo_rot.
-
- rot = quaternion_multiply(ipo_rot, bone.rot)
+ # SideNote: MatzeB: Ipo.getCurve(curvename) is broken in blender 2.33 and
+ # below if the Ipo comes from an Action, so only use Ipo.getCurves()!
+ # also blender upto 2.33a had a bug where IpoCurve.evaluate was not
+ # exposed to the python interface :-/
+
+ #run 1: we need to find all time values where we need to produce keyframes
+ for curve in ipo.getCurves():
+ curve_name = curve.getName()
- KeyFrame(track, time, loc, rot)
+ if curve_name not in ["QuatW", "QuatX", "QuatY", "QuatZ", "LocX", "LocY", "LocZ"]:
+ MESSAGES += "Curve type %s not supported in Action '%s' Bone '%s'.\n"\
+ % (curve_name, animation_name, bone_name)
+
+ for p in curve.getPoints():
+ time = p.getPoints() [0]
+ if time not in times:
+ times.append(time)
+
+ times.sort()
+
+ # run2: now create keyframes
+ for time in times:
+ cal3dtime = (time-1) / 25.0 # assume 25FPS by default
+ if cal3dtime > animation.duration:
+ animation.duration = cal3dtime
+ trans = [0, 0, 0]
+ quat = [0, 0, 0, 0]
+ for curve in ipo.getCurves():
+ val = curve.evaluate(time)
+ if curve.getName() == "LocX": trans[0] = val
+ if curve.getName() == "LocY": trans[1] = val
+ if curve.getName() == "LocZ": trans[2] = val
+ if curve.getName() == "QuatW": quat[3] = val
+ if curve.getName() == "QuatX": quat[0] = val
+ if curve.getName() == "QuatY": quat[1] = val
+ if curve.getName() == "QuatZ": quat[2] = val
+ transt = vector_by_matrix(trans, bone.matrix)
+ loc = vector_add(bone.loc, transt)
+ rot = quaternion_multiply(quat, bone.rot)
+ rot = quaternion_normalize(rot)
+
+ KeyFrame(track, cal3dtime, loc, rot)
+
+ if animation.duration <= 0:
+ MESSAGES += "Ignoring Animation '" + animation_name + \
+ "': duration is 0.\n"
+ continue
+ ANIMATIONS[animation_name] = animation
+
# Save all data
+ if filename.endswith(".cfg"):
+ filename = os.path.splitext(filename)[0]
+ BASENAME = os.path.basename(filename)
+ DIRNAME = os.path.dirname(filename)
+ if PREFIX_FILE_WITH_MODEL_NAME: PREFIX = BASENAME + "_"
+ else: PREFIX = ""
+ if XML: FORMAT_PREFIX = "x"; encode = lambda x: x.to_cal3d_xml()
+ else: FORMAT_PREFIX = "c"; encode = lambda x: x.to_cal3d()
+ print DIRNAME + " - " + BASENAME
+
+ cfg = open(os.path.join(DIRNAME, BASENAME + ".cfg"), "wb")
+ print >> cfg, "# Cal3D model exported from Blender with blender2cal3d.py"
+ print >> cfg
- STATUS = "Save files"
- Draw()
-
- EXPORT_ALL = EXPORT_SKELETON and EXPORT_ANIMATION and \
- EXPORT_MESH and EXPORT_MATERIAL
- cfg_buffer = ""
-
- if FILE_PREFIX == "":
- std_fname = "cal3d"
- else:
- std_fname = ""
+ if SCALE != 1.0:
+ print >> cfg, "scale=%s" % SCALE
+ print >> cfg
+
+ filename = BASENAME + "." + FORMAT_PREFIX + "sf"
+ open(os.path.join(DIRNAME, filename), "wb").write(encode(skeleton))
+ print >> cfg, "skeleton=%s" % filename
+ print >> cfg
- if not os.path.exists(SAVE_TO_DIR):
- os.makedirs(SAVE_TO_DIR)
- else:
- if DELETE_ALL_FILES:
- for file in os.listdir(SAVE_TO_DIR):
- if file.endswith(".cfg") or file.endswith(".caf") or \
- file.endswith(".cmf") or file.endswith(".csf") or \
- file.endswith(".crf") or file.endswith(".xsf") or \
- file.endswith(".xaf") or file.endswith(".xmf") or \
- file.endswith(".xrf"):
- os.unlink(os.path.join(SAVE_TO_DIR, file))
+ for animation in ANIMATIONS.values():
+ if not animation.name.startswith("_"):
+ if animation.duration: # Cal3D does not support animation with only one state
+ filename = PREFIX + animation.name + "." + FORMAT_PREFIX + "af"
+ open(os.path.join(DIRNAME, filename), "wb").write(encode(animation))
+ print >> cfg, "animation=%s" % filename
- cfg_buffer += "# Cal3D model exported from Blender with blender2cal3d.py\n\n"
- if EXPORT_ALL:
- cfg_buffer += "# --- Scale of model ---\n"
- cfg_buffer += "scale=%f\n\n" % SCALE
- else:
- cfg_buffer += "# Append this file to the model configuration file\n\n"
+ print >> cfg
+
+ for mesh in meshes:
+ if not mesh.name.startswith("_"):
+ filename = PREFIX + mesh.name + "." + FORMAT_PREFIX + "mf"
+ open(os.path.join(DIRNAME, filename), "wb").write(encode(mesh))
+ print >> cfg, "mesh=%s" % filename
+ print >> cfg
- if EXPORT_SKELETON:
- cfg_buffer += "# --- Skeleton ---\n"
- if EXPORT_TO_XML:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + std_fname + \
- os.path.basename(SAVE_TO_DIR) +".xsf"),
- "wb").write(skeleton.to_cal3d_xml())
- cfg_buffer += "skeleton=%s.xsf\n" % (FILE_PREFIX + std_fname +\
- os.path.basename(SAVE_TO_DIR))
+ materials = MATERIALS.values()
+ materials.sort(lambda a, b: cmp(a.id, b.id))
+ for material in materials:
+ if material.maps_filenames:
+ filename = PREFIX + os.path.splitext(os.path.basename(material.maps_filenames[0]))[0] + "." + FORMAT_PREFIX + "rf"
else:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + std_fname + \
- os.path.basename(SAVE_TO_DIR) + ".csf"),
- "wb").write(skeleton.to_cal3d())
- cfg_buffer += "skeleton=%s.csf\n" % (FILE_PREFIX + std_fname +\
- os.path.basename(SAVE_TO_DIR))
- cfg_buffer += "\n"
+ filename = PREFIX + "plain." + FORMAT_PREFIX + "rf"
+ open(os.path.join(DIRNAME, filename), "wb").write(encode(material))
+ print >> cfg, "material=%s" % filename
+ print >> cfg
- if EXPORT_ANIMATION:
- cfg_buffer += "# --- Animations ---\n"
- for animation in ANIMATIONS.values():
- # Cal3D does not support animation with only one state
- if animation.duration:
- animation.name = RENAME_ANIMATIONS.get(animation.name) or animation.name
-
- action_suffix=""
- if animation.action:
- action_suffix = "_action"
-
- if EXPORT_TO_XML:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + \
- animation.name + ".xaf"), "wb").write(animation.to_cal3d_xml())
- cfg_buffer += "animation%s=%s.xaf\n" % (action_suffix, (FILE_PREFIX + animation.name))
- else:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + \
- animation.name + ".caf"), "wb").write(animation.to_cal3d())
- cfg_buffer += "animation%s=%s.caf\n" % (action_suffix, (FILE_PREFIX + animation.name))
-
- # Prints animation names and durations
- print animation.name, "duration", animation.duration * FPS + 1.0
- cfg_buffer += "\n"
-
- if EXPORT_MESH:
- cfg_buffer += "# --- Meshes ---\n"
- for mesh in meshes:
- if not mesh.name.startswith("_"):
- if EXPORT_TO_XML:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + mesh.name + ".xmf"),
- "wb").write(mesh.to_cal3d_xml())
- cfg_buffer += "mesh=%s.xmf\n" % (FILE_PREFIX + mesh.name)
- else:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + mesh.name + ".cmf"),
- "wb").write(mesh.to_cal3d())
- cfg_buffer += "mesh=%s.cmf\n" % (FILE_PREFIX + mesh.name)
- cfg_buffer += "\n"
+ MESSAGES += "Saved to '%s.cfg'\n" % BASENAME
+ MESSAGES += "Done."
- if EXPORT_MATERIAL:
- cfg_buffer += "# --- Materials ---\n"
- materials = MATERIALS.values()
- materials.sort(lambda a, b: cmp(a.id, b.id))
- for material in materials:
- if material.maps_filenames:
- fname = os.path.splitext(os.path.basename(material.maps_filenames[0]))[0]
- else:
- fname = "plain"
- if EXPORT_TO_XML:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + fname + ".xrf"),
- "wb").write(material.to_cal3d_xml())
- cfg_buffer += "material=%s.xrf\n" % (FILE_PREFIX + fname)
- else:
- open(os.path.join(SAVE_TO_DIR, FILE_PREFIX + fname + ".crf"),
- "wb").write(material.to_cal3d())
- cfg_buffer += "material=%s.crf\n" % (FILE_PREFIX + fname)
- cfg_buffer += "\n"
-
- if EXPORT_ALL:
- cfg_prefix = ""
- else:
- cfg_prefix = "append_to_"
-
- cfg = open(os.path.join(SAVE_TO_DIR, cfg_prefix + FILE_PREFIX + std_fname +\
- os.path.basename(SAVE_TO_DIR) + ".cfg"), "wb")
- print >> cfg, cfg_buffer
- cfg.close()
-
- print "Saved to", SAVE_TO_DIR
- print "Done."
-
- STATUS = "Export finished."
- Draw()
-
-
-# ::: GUI around the whole thing, not very clean, but it works for me...
-
-_save_dir = Create(SAVE_TO_DIR)
-_file_prefix = Create(FILE_PREFIX)
-_image_prefix = Create(IMAGE_PREFIX)
-_scale = Create(SCALE)
-_framepsec = Create(FPS)
-STATUS = "Done nothing yet"
+ # show messages
+ print MESSAGES
+# some (ugly) gui to show the error messages - no scrollbar or other luxury,
+# please improve this if you know how
def gui():
- global EXPORT_TO_XML, EXPORT_SKELETON, EXPORT_ANIMATION, EXPORT_MESH, \
- EXPORT_MATERIAL, SAVE_TO_DIR, _save_dir, _scale, SCALE, \
- EXPORT_FOR_SOYA, REMOVE_PATH_FROM_IMAGE, LODS, _file_prefix, \
- FILE_PREFIX, _image_prefix, IMAGE_PREFIX, DELETE_ALL_FILES, STATUS, \
- _framepsec, FPS
-
- glRasterPos2i(8, 14)
- Text("Status: %s" % STATUS)
-
- _export_button = Button("Export (E)", 1, 8, 36, 100, 20,
- "Start export to Cal3D format")
- _quit_button = Button("Quit (Q)", 5, 108, 36, 100, 20, "Exit from script")
-
- _delete_toggle = Toggle("X", 15, 8, 64, 20, 20, DELETE_ALL_FILES,
- "Delete all existing Cal3D files in export directory")
- _SF_toggle = Toggle("_SF", 6, 28, 64, 45, 20, EXPORT_SKELETON,
- "Export skeleton (CSF/XSF)")
- _AF_toggle = Toggle("_AF", 7, 73, 64, 45, 20, EXPORT_ANIMATION,
- "Export animations (CAF/XAF)")
- _MF_toggle = Toggle("_MF", 8, 118, 64, 45, 20, EXPORT_MESH,
- "Export mesh (CMF/XMF)")
- _RF_toggle = Toggle("_RF", 9, 163, 64, 45, 20, EXPORT_MATERIAL,
- "Export materials (CRF/XRF)")
-
- _XML_toggle = Toggle("Export to XML", 2, 8, 84, 100, 20, EXPORT_TO_XML,
- "Export to Cal3D XML or binary fileformat")
- _soya_toggle = Toggle("Export for Soya", 10, 108, 84, 100, 20,
- EXPORT_FOR_SOYA, "Export for Soya 3D Engine")
-
- _imagepath_toggle = Toggle("X imagepath", 11, 8, 104, 100, 20,
- REMOVE_PATH_FROM_IMAGE, "Remove path from imagename")
- _lods_toggle = Toggle("Calculate LODS", 12, 108, 104, 100, 20,
- LODS, "Calculate LODS, quit slow and not optimal")
-
- _scale = Slider("S:", 4, 8, 132, 100, 20, SCALE, 0.00, 10.00, 0, \
- "Sets the scale of the model (small number will scale up)")
-
- _framepsec = Slider("F:", 16, 108, 132, 100, 20, FPS, 0.00, 100.0, 0, \
- "Sets the export framerate (FPS)")
-
- _image_prefix = String("Image prefix: ", 13, 8, 160, 200, 20, IMAGE_PREFIX, \
- 256, "Prefix used for imagename (if you have the " + \
- "textures in a subdirectory called textures, " + \
- "the prefix would be \"textures\\\\\")")
-
- _file_prefix = String("File prefix: ", 14, 8, 180, 200, 20, FILE_PREFIX, \
- 256, "Prefix to all exported Cal3D files "+ \
- "(f.e. \"model_\")")
-
- _save_dir = String("Export to: ", 3, 8, 200, 200, 20, _save_dir.val, 256, \
- "Directory to save files to")
-
-
+ global MESSAGES
+ button = Blender.Draw.Button("Ok", 1, 0, 0, 50, 20, "Close Window")
+
+ lines = MESSAGES.split("\n")
+ if len(lines) > 15:
+ lines.append("Please also take a look at your console")
+ pos = len(lines) * 15 + 20
+ for line in lines:
+ Blender.BGL.glRasterPos2i(0, pos)
+ Blender.Draw.Text(line)
+ pos -= 15
def event(evt, val):
- global STATUS
-
- if (evt == QKEY or evt == ESCKEY):
- Exit()
+ if evt == Blender.Draw.ESCKEY:
+ Blender.Draw.Exit()
return
- if evt == EKEY:
- update_reg()
- export()
-
-def bevent(evt):
- global EXPORT_TO_XML, EXPORT_SKELETON, EXPORT_ANIMATION, EXPORT_MESH, \
- EXPORT_MATERIAL, _save_dir, SAVE_TO_DIR, _scale, SCALE, \
- EXPORT_FOR_SOYA, REMOVE_PATH_FROM_IMAGE, LODS, _file_prefix, \
- FILE_PREFIX, _image_prefix, IMAGE_PREFIX, DELETE_ALL_FILES, STATUS, \
- _framepsec, FPS
+def button_event(evt):
if evt == 1:
- update_reg()
- export()
- if evt == 2:
- EXPORT_TO_XML = 1 - EXPORT_TO_XML
- if evt == 3:
- SAVE_TO_DIR = _save_dir.val
- if evt == 4:
- SCALE = _scale.val
- if evt == 5:
- Exit()
+ Blender.Draw.Exit()
return
- if evt == 6:
- EXPORT_SKELETON = 1 - EXPORT_SKELETON
- if evt == 7:
- EXPORT_ANIMATION = 1 - EXPORT_ANIMATION
- if evt == 8:
- EXPORT_MESH = 1 - EXPORT_MESH
- if evt == 9:
- EXPORT_MATERIAL = 1 - EXPORT_MATERIAL
- if evt == 10:
- EXPORT_FOR_SOYA = 1 - EXPORT_FOR_SOYA
- if evt == 11:
- REMOVE_PATH_FROM_IMAGE = 1 - REMOVE_PATH_FROM_IMAGE
- if evt == 12:
- LODS = 1 - LODS
- if evt == 13:
- IMAGE_PREFIX = _image_prefix.val
- if evt == 14:
- FILE_PREFIX = _file_prefix.val
- if evt == 15:
- DELETE_ALL_FILES = 1 - DELETE_ALL_FILES
- if evt == 16:
- FPS = _framepsec.val
- Draw()
-
-def update_reg():
- x = {}
- x['sd'] = SAVE_TO_DIR
- x['da'] = DELETE_ALL_FILES
- x['es'] = EXPORT_SKELETON
- x['ea'] = EXPORT_ANIMATION
- x['em'] = EXPORT_MESH
- x['emat'] = EXPORT_MATERIAL
- x['fp'] = FILE_PREFIX
- x['rp'] = REMOVE_PATH_FROM_IMAGE
- x['ip'] = IMAGE_PREFIX
- x['ex'] = EXPORT_TO_XML
- x['sc'] = SCALE
- x['fps'] = FPS
- x['soya'] = EXPORT_FOR_SOYA
- x['lod'] = LODS
- Blender.Registry.SetKey('Cal3dExporter', x)
-
-def get_from_reg():
- global SAVE_TO_DIR, DELETE_ALL_FILES, EXPORT_SKELETON, \
- EXPORT_ANIMATION, EXPORT_MESH, EXPORT_MATERIAL, FILE_PREFIX, \
- REMOVE_PATH_FROM_IMAGE, IMAGE_PREFIX, EXPORT_TO_XML, SCALE, \
- FPS, EXPORT_FOR_SOYA, LODS
-
- tmp = Blender.Registry.GetKey("Cal3dExporter")
- if tmp:
- SAVE_TO_DIR = tmp['sd']
- #DELETE_ALL_FILES = tmp['da']
- EXPORT_SKELETON = tmp['es']
- EXPORT_ANIMATION = tmp['ea']
- EXPORT_MESH = tmp['em']
- EXPORT_MATERIAL = tmp['emat']
- FILE_PREFIX = tmp['fp']
- REMOVE_PATH_FROM_IMAGE = tmp['rp']
- IMAGE_PREFIX = tmp['ip']
- EXPORT_TO_XML = tmp['ex']
- SCALE = tmp['sc']
- FPS = tmp['fps']
- EXPORT_FOR_SOYA = tmp['soya']
- LODS = tmp['lod']
-
-get_from_reg()
-Register(gui, event, bevent)
+
+# Main script
+def fs_callback(filename):
+ export(filename)
+ Blender.Draw.Register(gui, event, button_event)
+
+
+# Check for batch mode
+if "--blender2cal3d" in sys.argv:
+ args = sys.argv[sys.argv.index("--blender2cal3d") + 1:]
+ for arg in args:
+ attr, val = arg.split("=")
+ try: val = int(val)
+ except:
+ try: val = float(val)
+ except: pass
+ globals()[attr] = val
+ export(FILENAME)
+ Blender.Quit()
+
+else:
+ if FILENAME: fs_callback(FILENAME)
+ else:
+ defaultname = Blender.Get("filename")
+ if defaultname.endswith(".blend"):
+ defaultname = defaultname[0:len(defaultname)-len(".blend")] + ".cfg"
+ Blender.Window.FileSelector(fs_callback, "Cal3D Export", defaultname)
+
+
diff --git a/release/scripts/lightwave_export.py b/release/scripts/lightwave_export.py
index 1df2cec66fa..99d7deab440 100644
--- a/release/scripts/lightwave_export.py
+++ b/release/scripts/lightwave_export.py
@@ -15,9 +15,28 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to LightWave file format.
-Usage:
+LightWave is a full-featured commercial modeling and rendering
+application. The lwo file format is composed of 'chunks,' is well
+defined, and easy to read and write. It is similar in structure to the
+trueSpace cob format.
-Select meshes to be exported and run this script from "File->Export" menu.
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
+
+Supported:<br>
+ UV Coordinates, Meshes, Materials, Material Indices, Specular
+Highlights, and Vertex Colors. For added functionality, each object is
+placed on its own layer.
+
+Missing:<br>
+ Not too much, I hope! :).
+
+Known issues:<br>
+ Empty objects crash has been fixed.
+
+Notes:<br>
+ For compatibility reasons, it also reads lwo files in the old LW
+v5.5 format.
"""
# $Id$
diff --git a/release/scripts/lightwave_import.py b/release/scripts/lightwave_import.py
index 758c3b0229a..c795358c734 100644
--- a/release/scripts/lightwave_import.py
+++ b/release/scripts/lightwave_import.py
@@ -15,10 +15,28 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script imports LightWave files to Blender.
-Usage:
+LightWave is a full-featured commercial modeling and rendering
+application. The lwo file format is composed of 'chunks,' is well
+defined, and easy to read and write. It is similar in structure to the
+trueSpace cob format.
-Execute this script from the "File->Import" menu and choose a LightWave file to
-open.
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose a LightWave
+file to open.
+
+Supported:<br>
+ Meshes only.
+
+Missing:<br>
+ Materials, UV Coordinates, and Vertex Color info will be ignored.
+
+Known issues:<br>
+ Triangulation of convex polygons works fine, and uses a very simple
+fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
+require a different algorithm, and will be triagulated incorrectly.
+
+Notes:<br>
+ Also reads lwo files in the old LW v5.5 format.
"""
# $Id$
diff --git a/release/scripts/mod_ai2obj.py b/release/scripts/mod_ai2obj.py
index 07342737aad..8be6c5e18eb 100644
--- a/release/scripts/mod_ai2obj.py
+++ b/release/scripts/mod_ai2obj.py
@@ -58,20 +58,17 @@ os.split=split
os.join=join
def filtreFICHIER(nom):
- f=open(nom,'r')
+ f=open(nom,'rU')
t=f.readlines()
f.close()
- if len(t)==1 and t[0].find('\r'):
- t=t[0].split('\r')
-
if len(t)>1:
return t
else:
name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1
result = Draw.PupMenu(name)
- return 'false'
+ return 'false'
#===============================
# Data
@@ -140,6 +137,8 @@ def test_egalitedespositions(f1,f2):
def Open_GEOfile(dir,nom):
if BLversion>=233:
+ in_editmode = Blender.Window.EditMode()
+ if in_editmode: Blender.Window.EditMode(0)
Blender.Load(dir+nom+'OOO.obj', 1)
BO=Blender.Object.Get()
BO[-1].RotY=0.0
diff --git a/release/scripts/mod_meshtools.py b/release/scripts/mod_meshtools.py
index 6409f7ad72b..772b7549a11 100644
--- a/release/scripts/mod_meshtools.py
+++ b/release/scripts/mod_meshtools.py
@@ -94,7 +94,8 @@ def versioned_name(objname):
existing_names = []
for object in Blender.Object.Get():
existing_names.append(object.name)
- existing_names.append(object.data.name)
+ data = object.data
+ if data: existing_names.append(data.name)
if objname in existing_names: # don't over-write other names
try:
name, ext = objname.split('.')
diff --git a/release/scripts/mod_svg2obj.py b/release/scripts/mod_svg2obj.py
index d180b0d26c5..7445b13a4a7 100644
--- a/release/scripts/mod_svg2obj.py
+++ b/release/scripts/mod_svg2obj.py
@@ -1,6 +1,7 @@
"""
-(c) jm soler juillet 2004, released under Blender Artistic Licence
- for the Blender 2.34 Python Scripts Bundle.
+SVG 2 OBJ translater, 0.2.6
+(c) jm soler juillet/novembre 2004, released under Blender Artistic Licence
+ for the Blender 2.34/35 Python Scripts Bundle.
#---------------------------------------------------------------------------
# Page officielle :
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg.htm
@@ -9,7 +10,6 @@
#---------------------------------------------------------------------------
-- Concept : translate SVG file in GEO .obj file and try to load it.
--- Real problem : the name of the blender file is changed ...
-- Curiousity : the original matrix must be :
0.0 0.0 1.0 0.0
@@ -55,14 +55,17 @@ Changelog:
0.2.3 : - read a few new relative displacements
0.2.4 : - better hash for command with followed by a lone data
(h,v) or uncommun number (a)
+ 0.2.5 : - correction for gimp import
+ 0.2.6 : - correction for illustrator 10 SVG
+
==================================================================================
=================================================================================="""
SHARP_IMPORT=0
SCALE=1
scale=1
-DEBUG =0
-DEVELOPPEMENT=1
+DEBUG =0 #print
+DEVELOPPEMENT=0
import sys
#oldpath=sys.path
@@ -107,16 +110,21 @@ os.split=split
os.join=join
def filtreFICHIER(nom):
- f=open(nom,'r')
+ f=open(nom,'rU')
t=f.read()
f.close()
+
t=t.replace('\r','')
t=t.replace('\n','')
- if t.upper().find('<SVG')==-1:
+ if t.upper().find('<SVG')==-1 :
name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1
result = Blender.Draw.PupMenu(name)
return "false"
+ elif t.upper().find('<PATH')==-1:
+ name = "OK?%t| Sorry, no Path in this file ... " # if no %xN int is set, indices start from 1
+ result = Blender.Draw.PupMenu(name)
+ return "false"
else:
return t
@@ -329,7 +337,7 @@ def courbe_vers_s(c,D,n0,CP): #S,s
if DEBUG==1: print B.co,BP.co
CP=[l[4],l[5]]
- if D[c[1]+3] not in TAGcourbe :
+ if len(D)<c[1]+3 and D[c[1]+3] not in TAGcourbe :
c[1]+=2
courbe_vers_c(c, D, n0,CP)
return courbes,n0,CP
@@ -379,8 +387,10 @@ def courbe_vers_c(c, D, n0,CP): #c,C
if DEBUG==1: print B.co,BP.co
CP=[l[4],l[5]]
-
- if D[c[1]+4] not in TAGcourbe :
+ if DEBUG==1:
+ print 'D[c[1]]', D[c[1]], c
+ print D
+ if len(D)<c[1]+4 and D[c[1]+4] not in TAGcourbe :
c[1]+=3
courbe_vers_c(c, D, n0,CP)
@@ -402,7 +412,7 @@ def ligne_tracee_l(c, D, n0,CP): #L,l
CP=[l[0],l[1]]
- if D[c[1]+2] not in TAGcourbe :
+ if len(D)<c[1]+2 and D[c[1]+2] not in TAGcourbe :
c[1]+=1
ligne_tracee_l(c, D, n0,CP) #L
@@ -557,6 +567,13 @@ def format_PATH(t):
#print "D0= :",D
D=D.split(' ')
+
+ try:
+ while D.index(''):
+ del D[D.index('')]
+ except:
+ pass
+
#print len(D)
#for D0 in D:
#print " ----> D = :", D0
@@ -600,16 +617,12 @@ def scan_FILE(nom):
#print t
while t.find('path')!=-1:
-
t,D=format_PATH(t)
-
cursor=0
for cell in D:
if DEBUG==2 : print 'cell : ',cell ,' --'
- #print 'cell',cell
if len(cell)>=1 and cell[0] in TAGcourbe:
- courbes,n0,CP=Actions[cell]([cell,cursor], D, n0,CP)
-
+ courbes,n0,CP=Actions[cell]([cell,cursor], D, n0,CP)
cursor+=1
courbes.number_of_items=len(courbes.ITEM.keys())
@@ -642,6 +655,6 @@ def ajustement(v,s):
def fonctionSELECT(nom):
scan_FILE(nom)
-if DEVELOPPEMENT==0:
+if DEVELOPPEMENT==1:
Blender.Window.FileSelector (fonctionSELECT, 'SELECT a .SVG FILE')
#sys.path=oldpath
diff --git a/release/scripts/nendo_export.py b/release/scripts/nendo_export.py
index 4f0aac905fa..1dd84bb6d81 100644
--- a/release/scripts/nendo_export.py
+++ b/release/scripts/nendo_export.py
@@ -15,12 +15,37 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to Nendo file format.
-Usage:
-
-Select meshes to be exported and run this script from "File->Export" menu.
+Nendo is (was) a commercial polygon modeler that has about half of the
+features found in Wings. The .ndo file format is a simple, uncompressed,
+memory dump of structures that represent the mesh objects, uv coords,
+and image textures.
+
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
+
+Supported:<br>
+ 1. Exports meshes only. Hint: use ALT-C to convert non-mesh objects,
+and CTRL-ALT-A if you have "dupliverts" objects.<br>
+ 2. Exports Vertex Colors & Radiosity Solutions.
+
+Missing:<br>
+ Materials and UV Coordinates info will be ignored.
+
+Known issues:<br>
+ Exports only well-behaved and topologically correct meshes (i.e,
+closed meshes, manifolds, meshes imported from wings, etc). The mesh
+cannot have duplicate vertices, missing faces (holes), open edges, etc.<br>
+ PowerUser Hint: In editmode, if CTRL-ALT-SHIFT-M results in a selection,
+then your mesh is not a manifold and most likely will not export.
+
+Notes:<br>
+ Blender & Wings can read/write ndo files with a maximum of 65,535 edges.
+Nendo can read/write ndo files with a maximum of 32,767 edges.<br>
+ If you have a very large mesh that you want to import into nendo, modify
+the 'write_edge_table' function to use a signed integer (i.e., ">h") for the 'len(edge_table)'
+field.
"""
-
# $Id$
#
# +---------------------------------------------------------+
diff --git a/release/scripts/nendo_import.py b/release/scripts/nendo_import.py
index 2d041aadd53..2af19ff5a5d 100644
--- a/release/scripts/nendo_import.py
+++ b/release/scripts/nendo_import.py
@@ -15,13 +15,32 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script imports Nendo files to Blender.
-Usage:
-
-Execute this script from the "File->Import" menu and choose a Nendo file to
-open.
+Nendo is (was) a commercial polygon modeler that has about half of the
+features found in Wings. The .ndo file format is a simple, uncompressed,
+memory dump of structures that represent the mesh objects, uv coords,
+and image textures.
+
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose a Nendo file
+to open.
+
+Supported:<br>
+ Meshes only.
+
+Missing:<br>
+ Materials, UV Coordinates, and Vertex Color info will be ignored.
+
+Known issues:<br>
+ Triangulation of convex polygons works fine, and uses a very simple
+fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
+require a different algorithm, and will be triagulated incorrectly.
+
+Notes:<br>
+ Last tested with Wings 3D 0.98.25 & Nendo 1.1.6. Some models cannot be
+imported due to the fact that Nendo erroneously creates doubled back
+edges during the course of modeling.
"""
-
# $Id$
#
# +---------------------------------------------------------+
diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py
index c860a9707df..c6cb032a632 100644
--- a/release/scripts/obj_import.py
+++ b/release/scripts/obj_import.py
@@ -202,8 +202,11 @@ def getUniqueName(name):
name += '.' + str(uniqueInt)
uniqueInt +=1
except:
- return name
-
+ if NMesh.GetRaw(name) == None:
+ return name
+ else:
+ name += '.' + str(uniqueInt)
+ uniqueInt +=1
#==================================================================================#
# This loads data from .obj file #
@@ -215,16 +218,16 @@ def load_obj(file):
if len( meshList[objectName][0].materials ) >= MATLIMIT:
print 'Warning, max material limit reached, using an existing material'
return meshList[objectName][0]
-
+
mIdx = 0
for m in meshList[objectName][0].materials:
if m.getName() == mat.getName():
break
mIdx+=1
-
+
if mIdx == len(mesh.materials):
meshList[objectName][0].addMaterial(mat)
-
+
f.mat = mIdx
return f
@@ -263,25 +266,26 @@ def load_obj(file):
# Load all verts first (texture verts too) #
#==================================================================================#
lIdx = 0
+ print len(fileLines)
while lIdx < len(fileLines):
- l = fileLines[lIdx]
-
- # EMPTY LINE
- if len(l) == 0 or l[0] == '#':
- pass
- # VERTEX
+ l = fileLines[lIdx]
+ if len(l) == 0:
+ fileLines.pop(lIdx)
+ lIdx-=1
+
elif l[0] == 'v':
# This is a new vert, make a new mesh
vertList.append( NMesh.Vert(float(l[1]), float(l[2]), float(l[3]) ) )
- fileLines.remove(fileLines[lIdx])
+ fileLines.pop(lIdx)
lIdx-=1
+
# UV COORDINATE
elif l[0] == 'vt':
# This is a new vert, make a new mesh
uvMapList.append( (float(l[1]), float(l[2])) )
- fileLines.remove(fileLines[lIdx])
+ fileLines.pop(lIdx)
lIdx-=1
lIdx+=1
@@ -298,6 +302,7 @@ def load_obj(file):
meshList = {}
meshList[objectName] = (NMesh.GetRaw(), [-1]*len(vertList)) # Mesh/meshList[objectName][1]
meshList[objectName][0].verts.append(vertList[0])
+ meshList[objectName][0].hasFaceUV(1)
#==================================================================================#
# Load all faces into objects, main loop #
@@ -306,15 +311,15 @@ def load_obj(file):
# Face and Object loading LOOP
while lIdx < len(fileLines):
l = fileLines[lIdx]
-
- # COMMENTS AND EMPTY LINES
- if len(l) == 0 or l[0] == '#':
- pass
-
+
# VERTEX
- elif l[0] == 'v':
+ if l[0] == 'v':
pass
+ # Comment
+ if l[0] == '#':
+ pass
+
# VERTEX NORMAL
elif l[0] == 'vn':
pass
@@ -374,8 +379,9 @@ def load_obj(file):
# UV MAPPING
if fHasUV:
- for i in [0,1,2,3]:
- f.uv.append( uvMapList[ vtIdxLs[i] ] )
+ f.uv.extend([uvMapList[ vtIdxLs[0] ],uvMapList[ vtIdxLs[1] ],uvMapList[ vtIdxLs[2] ],uvMapList[ vtIdxLs[3] ]])
+ #for i in [0,1,2,3]:
+ # f.uv.append( uvMapList[ vtIdxLs[i] ] )
if f.v > 0:
f = applyMat(meshList[objectName][0], f, currentMat)
@@ -400,9 +406,7 @@ def load_obj(file):
# UV MAPPING
if fHasUV:
- f.uv.append( uvMapList[ vtIdxLs[0] ] )
- f.uv.append( uvMapList[ vtIdxLs[i+1] ] )
- f.uv.append( uvMapList[ vtIdxLs[i+2] ] )
+ f.uv.extent([uvMapList[ vtIdxLs[0] ], uvMapList[ vtIdxLs[i+1] ], uvMapList[ vtIdxLs[i+2] ]])
if f.v > 0:
f = applyMat(meshList[objectName][0], f, currentMat)
@@ -450,6 +454,7 @@ def load_obj(file):
# if we have then we'll just keep appending to it, this is required for soem files.
if objectName not in meshList.keys():
meshList[objectName] = (NMesh.GetRaw(), [-1]*len(vertList))
+ meshList[objectName][0].hasFaceUV(1)
meshList[objectName][0].verts.append( vertList[0] )
@@ -466,7 +471,7 @@ def load_obj(file):
currentImg = NULL_IMG
else:
currentImg = getImg(DIR + ' '.join(l[1:])) # Use join in case of spaces
-
+
# MATERIAL FILE
elif l[0] == 'mtllib':
mtl_fileName = ' '.join(l[1:])
@@ -482,12 +487,24 @@ def load_obj(file):
if mtl_fileName != '':
load_mtl(DIR, mtl_fileName, meshList[mk][0])
if len(meshList[mk][0].verts) >1:
- meshList[mk][0].verts.remove(meshList[mk][0].verts[0])
+ meshList[mk][0].verts.pop(0)
name = getUniqueName(mk)
- ob = NMesh.PutRaw(meshList[mk][0], mk)
- ob.name = mk
+ ob = NMesh.PutRaw(meshList[mk][0], name)
+ ob.name = name
print "obj import time: ", sys.time() - time1
Window.FileSelector(load_obj, 'Import Wavefront OBJ')
+
+'''
+# For testing compatability
+import os
+for obj in os.listdir('/obj/'):
+ if obj[-3:] == 'obj':
+ print obj
+ newScn = Scene.New(obj)
+ newScn.makeCurrent()
+ load_obj('/obj/' + obj)
+
+''' \ No newline at end of file
diff --git a/release/scripts/off_export.py b/release/scripts/off_export.py
index 328854d39f8..332d553b389 100644
--- a/release/scripts/off_export.py
+++ b/release/scripts/off_export.py
@@ -1,10 +1,10 @@
#!BPY
"""
-Name: 'Object File Format (.off)...'
+Name: 'DEC Object File Format (.off)...'
Blender: 232
Group: 'Export'
-Tooltip: 'Export selected mesh to Object File Format (*.off)'
+Tooltip: 'Export selected mesh to DEC Object File Format (*.off)'
"""
__author__ = "Anthony D'Agostino (Scorpius)"
@@ -13,11 +13,19 @@ __url__ = ("blender", "elysiun",
__version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
-This script exports meshes to Object File Format.
+This script exports meshes to DEC Object File Format.
-Usage:
+The DEC (Digital Equipment Corporation) OFF format is very old and
+almost identical to Wavefront's OBJ. I wrote this so I could get my huge
+meshes into Moonlight Atelier. (DXF can also be used but the file size
+is five times larger than OFF!) Blender/Moonlight users might find this
+script to be very useful.
-Select meshes to be exported and run this script from "File->Export" menu.
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
+
+Notes:<br>
+ Only exports a single selected mesh.
"""
# +---------------------------------------------------------+
diff --git a/release/scripts/off_import.py b/release/scripts/off_import.py
index b70a935b4a9..94b6423149a 100644
--- a/release/scripts/off_import.py
+++ b/release/scripts/off_import.py
@@ -1,10 +1,10 @@
#!BPY
"""
-Name: 'Object File Format (.off)...'
+Name: 'DEC Object File Format (.off)...'
Blender: 232
Group: 'Import'
-Tooltip: 'Import Object File Format (*.off)'
+Tooltip: 'Import DEC Object File Format (*.off)'
"""
__author__ = "Anthony D'Agostino (Scorpius)"
@@ -13,12 +13,20 @@ __url__ = ("blender", "elysiun",
__version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
-This script imports Object File Format files to Blender.
+This script imports DEC Object File Format files to Blender.
-Usage:
+The DEC (Digital Equipment Corporation) OFF format is very old and
+almost identical to Wavefront's OBJ. I wrote this so I could get my huge
+meshes into Moonlight Atelier. (DXF can also be used but the file size
+is five times larger than OFF!) Blender/Moonlight users might find this
+script to be very useful.
-Execute this script from the "File->Import" menu and choose an OFF file to
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose an OFF file to
open.
+
+Notes:<br>
+ UV Coordinate support has been added.
"""
@@ -45,19 +53,27 @@ def read(filename):
verts = []
faces = []
+ uv = []
# === OFF Header ===
offheader = file.readline()
numverts, numfaces, null = file.readline().split()
numverts = int(numverts)
numfaces = int(numfaces)
+ if offheader.find('ST') >= 0:
+ has_uv = True
+ else:
+ has_uv = False
# === Vertex List ===
for i in range(numverts):
if not i%100 and mod_meshtools.show_progress:
Blender.Window.DrawProgressBar(float(i)/numverts, "Reading Verts")
- x, y, z = file.readline().split()
- x, y, z = float(x), float(y), float(z)
+ if has_uv:
+ x, y, z, u, v = map(float, file.readline().split())
+ uv.append((u, v))
+ else:
+ x, y, z = map(float, file.readline().split())
verts.append((x, y, z))
# === Face List ===
@@ -75,7 +91,7 @@ def read(filename):
objname = Blender.sys.splitext(Blender.sys.basename(filename))[0]
- mod_meshtools.create_mesh(verts, faces, objname)
+ mod_meshtools.create_mesh(verts, faces, objname, faces, uv)
Blender.Window.DrawProgressBar(1.0, '') # clear progressbar
file.close()
#end = time.clock()
diff --git a/release/scripts/radiosity_export.py b/release/scripts/radiosity_export.py
index 27a32c810d0..c9d5128b367 100644
--- a/release/scripts/radiosity_export.py
+++ b/release/scripts/radiosity_export.py
@@ -15,11 +15,29 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to Radiosity file format.
-Usage:
+The Radiosity file format is my own personal format. I created it to
+learn how meshes and vertex colors were stored. See IO-Examples.zip, the
+example *.radio files on my web page.
-Select meshes to be exported and run this script from "File->Export" menu.
-"""
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
+
+Notes:<br>
+ Before exporting to .radio format, the mesh must have vertex colors.
+Here's how to assign them:
+
+1. Use radiosity!
+
+2. Set up lights and materials, select a mesh, switch the drawing mode
+to "textured," press the VKEY.
+3. Press the VKEY and paint manually.
+
+4. Use a custom script to calculate and apply simple diffuse shading and
+specular highlights to the vertex colors.
+
+5. The Videoscape format also allows vertex colors to be specified.
+"""
# $Id$
#
diff --git a/release/scripts/radiosity_import.py b/release/scripts/radiosity_import.py
index 3966a9be88a..f3e14d669a6 100644
--- a/release/scripts/radiosity_import.py
+++ b/release/scripts/radiosity_import.py
@@ -15,13 +15,15 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script imports Radiosity files to Blender.
-Usage:
+The Radiosity file format is my own personal format. I created it to
+learn how meshes and vertex colors were stored. See IO-Examples.zip, the
+example *.radio files on my web page.
-Execute this script from the "File->Import" menu and choose a Radiosity file to
-open.
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose a Radiosity
+file to open.
"""
-
# $Id$
#
# +---------------------------------------------------------+
diff --git a/release/scripts/raw_export.py b/release/scripts/raw_export.py
index 843c3f6d32c..4cc49baff1e 100644
--- a/release/scripts/raw_export.py
+++ b/release/scripts/raw_export.py
@@ -15,9 +15,14 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to Raw Triangle file format.
-Usage:
-
-Select meshes to be exported and run this script from "File->Export" menu.
+The raw triangle format is very simple; it has no verts or faces lists.
+It's just a simple ascii text file with the vertices of each triangle
+listed on each line. There were some very old utilities (when the PovRay
+forum was in existence on CompuServe) that preformed operations on these
+files.
+
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
"""
diff --git a/release/scripts/raw_import.py b/release/scripts/raw_import.py
index d650d11a23c..13b2e187826 100644
--- a/release/scripts/raw_import.py
+++ b/release/scripts/raw_import.py
@@ -15,12 +15,21 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script imports Raw Triangle File format files to Blender.
-Usage:
+The raw triangle format is very simple; it has no verts or faces lists.
+It's just a simple ascii text file with the vertices of each triangle
+listed on each line. There were some very old utilities (when the PovRay
+forum was in existence on CompuServe) that preformed operations on these
+files.
-Execute this script from the "File->Import" menu and choose a Raw file to
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose a Raw file to
open.
-"""
+Notes:<br>
+ Generates the standard verts and faces lists, but without duplicate
+verts. Only *exact* duplicates are removed, there is no way to specify a
+tolerance.
+"""
# $Id$
#
diff --git a/release/scripts/slp_import.py b/release/scripts/slp_import.py
index f9ab52b3724..e8c84f62ba2 100644
--- a/release/scripts/slp_import.py
+++ b/release/scripts/slp_import.py
@@ -15,10 +15,18 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script imports Pro Engineer files to Blender.
-Usage:
+This format can be exported from Pro/Engineer and most other CAD
+applications. Written at the request of a Blender user. It is almost
+identical to RAW format.
-Execute this script from the "File->Import" menu and choose an SLP file to
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose an SLP file to
open.
+
+Notes:<br>
+ Generates the standard verts and faces lists, but without duplicate
+verts. Only *exact* duplicates are removed, there is no way to specify a
+tolerance.
"""
# $Id$
diff --git a/release/scripts/truespace_export.py b/release/scripts/truespace_export.py
index df96552467f..d9cd0b1ad99 100644
--- a/release/scripts/truespace_export.py
+++ b/release/scripts/truespace_export.py
@@ -15,9 +15,38 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to TrueSpace file format.
-Usage:
-
-Select meshes to be exported and run this script from "File->Export" menu.
+TrueSpace is a commercial modeling and rendering application. The .cob
+file format is composed of 'chunks,' is well defined, and easy to read and
+write. It's very similar to LightWave's lwo format.
+
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
+
+Supported:<br>
+ Vertex colors will be exported, if they are present.
+
+Known issues:<br>
+ Before exporting to .cob format, the mesh must have real-time UV
+coordinates. Press the FKEY to assign them.
+
+Notes:<br>
+ There are a few differences between how Blender & TrueSpace represent
+their objects' transformation matrices. Blender simply uses a 4x4 matrix,
+and trueSpace splits it into the following two fields.
+
+ For the 'Local Axes' values: The x, y, and z-axis represent a simple
+rotation matrix. This is equivalent to Blender's object matrix before
+it was combined with the object's scaling matrix. Dividing each value by
+the appropriate scaling factor (and transposing at the same time)
+produces the original rotation matrix.
+
+ For the 'Current Position' values: This is equivalent to Blender's
+object matrix except that the last row is omitted and the xyz location
+is used in the last column. Binary format uses a 4x3 matrix, ascii
+format uses a 4x4 matrix.
+
+For Cameras: The matrix here gets a little confusing, and I'm not sure of
+how to handle it.
"""
diff --git a/release/scripts/truespace_import.py b/release/scripts/truespace_import.py
index 5250c5e24af..d1bfd3ab6bf 100644
--- a/release/scripts/truespace_import.py
+++ b/release/scripts/truespace_import.py
@@ -13,12 +13,46 @@ __url__ = ("blender", "elysiun",
__version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
-This script imports TrueSpace files to Blender.
+This script imports TrueSpace files to Blender
-Usage:
+TrueSpace is a commercial modeling and rendering application. The .cob
+file format is composed of 'chunks,' is well defined, and easy to read and
+write. It's very similar to LightWave's lwo format.
-Execute this script from the "File->Import" menu and choose a TrueSpace file to
-open.
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose a TrueSpace
+file to open.
+
+Supported:<br>
+ Meshes only. Supports UV Coordinates. COB files in ascii format can't be
+read.
+
+Missing:<br>
+ Materials, and Vertex Color info will be ignored.
+
+Known issues:<br>
+ Triangulation of convex polygons works fine, and uses a very simple
+fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
+require a different algorithm, and will be triagulated incorrectly.
+
+Notes:<br>
+ There are a few differences between how Blender & TrueSpace represent
+their objects' transformation matrices. Blender simply uses a 4x4 matrix,
+and trueSpace splits it into the following two fields.
+
+ For the 'Local Axes' values: The x, y, and z-axis represent a simple
+rotation matrix. This is equivalent to Blender's object matrix before
+it was combined with the object's scaling matrix. Dividing each value by
+the appropriate scaling factor (and transposing at the same time)
+produces the original rotation matrix.
+
+ For the 'Current Position' values: This is equivalent to Blender's
+object matrix except that the last row is omitted and the xyz location
+is used in the last column. Binary format uses a 4x3 matrix, ascii
+format uses a 4x4 matrix.
+
+For Cameras: The matrix here gets a little confusing, and I'm not sure of
+how to handle it.
"""
# $Id$
@@ -227,19 +261,3 @@ def fs_callback(filename):
Blender.Window.FileSelector(fs_callback, "Import COB")
-# === Matrix Differences between Blender & trueSpace ===
-#
-# For the 'Local Axes' values:
-# The x, y, and z-axis represent a simple rotation matrix.
-# This is equivalent to Blender's object matrix before it was
-# combined with the object's scaling matrix. Dividing each value
-# by the appropriate scaling factor (and transposing at the same
-# time) produces the original rotation matrix.
-#
-# For the 'Current Position' values:
-# This is equivalent to Blender's object matrix except that the
-# last row is omitted and the xyz location is used in the last
-# column. Binary format uses a 4x3 matrix, ascii format uses a 4x4
-# matrix.
-#
-# For Cameras: The matrix is a little confusing.
diff --git a/release/scripts/videoscape_export.py b/release/scripts/videoscape_export.py
index 362ecdc0d60..26bd7d08b01 100644
--- a/release/scripts/videoscape_export.py
+++ b/release/scripts/videoscape_export.py
@@ -15,9 +15,32 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes (including vertex colors) to VideoScape File Format.
-Usage:
+The VideoScape file format is a simple format that is natively supported
+in Blender. I wrote this module because Blender's internal exporter
+doesn't export vertex colors correctly. Check the source for a *fast* algorithm for
+averaging vertex colors.
-Select meshes to be exported and run this script from "File->Export" menu.
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
+
+Supported:<br>
+ Exports meshes only. Hint: use ALT-C to convert non-mesh objects,
+and CTRL-ALT-A if you have "dupliverts" objects.
+
+Notes:<br>
+ Before exporting, the mesh must have vertex colors. Here's how to assign them:
+
+1. Use radiosity!
+
+2. Set up lights and materials, select a mesh, switch the drawing mode
+to "textured," press the VKEY.
+
+3. Press the VKEY and paint manually.
+
+4. Use a custom script to calculate and apply simple diffuse shading and
+specular highlights to the vertex colors.
+
+5. The Videoscape format also allows vertex colors to be specified.
"""
@@ -32,8 +55,6 @@ Select meshes to be exported and run this script from "File->Export" menu.
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Write Videoscape File Format (*.obj NOT WAVEFRONT OBJ) |
-# | Includes a *fast* algorithm for averaging vertex colors |
-# | Blender's a|w doesn't export proper vertex colors |
# +---------------------------------------------------------+
import Blender, mod_meshtools
diff --git a/release/scripts/wings_export.py b/release/scripts/wings_export.py
index 3fb02673ed3..c35b141cc97 100644
--- a/release/scripts/wings_export.py
+++ b/release/scripts/wings_export.py
@@ -14,13 +14,34 @@ __url__ = ("blender", "elysiun",
__version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
-This script exports meshes to Wings 3D file format.
+This script exports meshes to Wings3D file format.
-Usage:
+Wings3D is an open source polygon modeler written in Erlang, a
+language similar to Lisp. The .wings file format is a binary
+representation of erlang terms (lists, tuples, atoms, etc.) and is
+compressed with zlib.
-Select meshes to be exported and run this script from "File->Export" menu.
-"""
+Usage:<br>
+ Select meshes to be exported and run this script from "File->Export" menu.
+
+Supported:<br>
+ 1. Exports meshes only. Hint: use ALT-C to convert non-mesh objects,
+and CTRL-ALT-A if you have "dupliverts" objects.<br>
+ 2. Exports Vertex Colors & Radiosity Solutions.
+
+Missing:<br>
+ Materials and UV Coordinates info will be ignored.
+Known issues:<br>
+ Exports only well-behaved and topologically correct meshes (i.e,
+closed meshes, manifolds, meshes imported from wings, etc). The mesh
+cannot have duplicate vertices, missing faces (holes), open edges, etc.<br>
+ PowerUser Hint: In editmode, if CTRL-ALT-SHIFT-M results in a selection,
+then your mesh is not a manifold and most likely will not export.
+
+Notes:<br>
+ Last tested with Wings 3D 0.98.25 & Blender 2.35a.
+"""
# $Id$
#
diff --git a/release/scripts/wings_import.py b/release/scripts/wings_import.py
index 9633c94355e..dc28e978aae 100644
--- a/release/scripts/wings_import.py
+++ b/release/scripts/wings_import.py
@@ -14,12 +14,30 @@ __url__ = ("blender", "elysiun",
__version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
-This script imports Wings 3d files to Blender.
+This script imports Wings3D files to Blender.
-Usage:
+Wings3D is an open source polygon modeler written in Erlang, a
+language similar to Lisp. The .wings file format is a binary
+representation of erlang terms (lists, tuples, atoms, etc.) and is
+compressed with zlib.
-Execute this script from the "File->Import" menu and choose a Wings file to
-open.
+Usage:<br>
+ Execute this script from the "File->Import" menu and choose a Wings file
+to open.
+
+Supported:<br>
+ Meshes only. Not guaranteed to work in all situations.
+
+Missing:<br>
+ Materials, UV Coordinates, and Vertex Color info will be ignored.
+
+Known issues:<br>
+ Triangulation of convex polygons works fine, and uses a very simple
+fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
+require a different algorithm, and will be triagulated incorrectly.
+
+Notes:<br>
+ Last tested with Wings 3D 0.98.25 & Blender 2.35a.
"""
# $Id$