- 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!
This commit is contained in:
Willian Padovani Germano
2004-11-30 02:27:46 +00:00
parent e4562134d2
commit 6d9c02be4c
25 changed files with 1000 additions and 1096 deletions

View File

@@ -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)
#
__version__ = "0.11"
__author__ = "Jean-Baptiste 'Jiba' Lamy"
__email__ = ["Author's email, jibalamy:free*fr"]
__url__ = ["Soya3d's homepage, http://home.gna.org/oomadness/en/soya/",
"Cal3d, http://cal3d.sourceforge.net"]
__bpydoc__ = """\
This script is a Blender => Cal3D converter.
(See http://blender.org and http://cal3d.sourceforge.net)
# This script was written by Jiba, modified by Chris and later modified by Damien
USAGE:
# Changes:
#
# 0.7 Damien McGinnes <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
To install it, place the script in your $HOME/.blender/scripts directory.
Then open the File->Export->Cal3d v0.9 menu. And select the filename of the .cfg file.
The exporter will create a set of other files with same prefix (ie. bla.cfg, bla.xsf,
bla_Action1.xaf, bla_Action2.xaf, ...).
You should be able to open the .cfg file in cal3d_miniviewer.
NOT (YET) SUPPORTED:
# HOW TO USE :
# 1 - load the script in Blender's text editor
# 2 - type M-P (meta/alt + P) and wait until script execution is finished
# or install it in .scripts and access from the export menu
# ADVICE
# - Objects/bones/actions whose names start by "_" are not exported
# so call IK and null bones _LegIK for example
# - All your armature's exported bones must be connected to another bone (except
# for the rootbone). Contrary to Blender, Cal3D doesn't support "floating" bones.
# - Actions that start with '@' will be exported as actions, others will be
# exported as cycles
# BUGS / TODO :
# - Material color is not supported yet
# - Cal3D springs (for clothes and hair) are not supported yet
# - Cal3d has a bug in that a cycle that doesnt have as rootbone channel
# will segfault cal3d. until cal3d supports this, add a keyframe for the rootbone
- Rotation, translation, or stretching Blender objects is still quite
buggy, so AVOID MOVING / ROTATING / RESIZE OBJECTS (either mesh or armature) !
Instead, edit the object (with tab), select all points / bones (with "a"),
and move / rotate / resize them.<br>
- no support for exporting springs yet<br>
- no support for exporting material colors (most games should only use images
I think...)
# REMARKS
# 1. When you finished an animation and run the script
# you can get an error (something with KeyError). Just save your work,
# and reload the model. This is usualy caused by deleted items hanging around
# 2. If a vertex is assigned to one or more bones, but is has a for each
# bone a weight of zero, there was a subdivision by zero somewhere
# Made a workaround (if sum is 0.0 then sum becomes 1.0).
# I have not checked what the outcome of that is, so you better nail 'm,
# and give it some weight...
KNOWN ISSUES:
- Cal3D versions <=0.9.1 have a bug where animations aren't played when the root bone
is not animated;<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).
NOTES:
It requires a very recent version of Blender (>= 2.35).
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).
It can be run in batch mode, as following :<br>
blender model.blend -P blender2cal3d.py --blender2cal3d FILENAME=model.cfg EXPORT_FOR_SOYA=1
You can pass as many parameters as you want at the end, "EXPORT_FOR_SOYA=1" is just an
example. The parameters are the same as below.
"""
# Parameters :
# The directory where the data are saved.
SAVE_TO_DIR = "/tmp/tutorial/"
# Filename to export to (if "", display a file selector dialog).
FILENAME = ""
# Delete all existing Cal3D files in directory?
DELETE_ALL_FILES = 0
# What do you wanna export? If all are true then a .cfg file is created,
# otherwise no .cfg file is made. You have to make one by hand.
EXPORT_SKELETON = 1
EXPORT_ANIMATION = 0
EXPORT_MESH = 1
EXPORT_MATERIAL = 0
# Prefix for all created files
FILE_PREFIX = "Test"
# Remove path from imagelocation
REMOVE_PATH_FROM_IMAGE = 0
# prefix or subdir for imagepathname (if you place your textures in a
# subdir or just need a prefix or something). Only used when
# REMOVE_PATH_FROM_IMAGE = 1. Set to "" if none.
IMAGE_PREFIX = "textures/"
# Export to new (>= 900) Cal3D XML-format
EXPORT_TO_XML = 0
# Set scalefactor for model
SCALE = 0.5
# frames per second - used to convert blender frames to times
FPS = 25
# Use this dictionary to rename animations, as their name is lost at the
# exportation.
RENAME_ANIMATIONS = {
# "OldName" : "NewName",
}
# True (=1) to export for the Soya 3D engine
# (http://oomadness.tuxfamily.org/en/soya).
# True (=1) to export for the Soya 3D engine
# (http://oomadness.tuxfamily.org/en/soya).
# (=> rotate meshes and skeletons so as X is right, Y is top and -Z is front)
EXPORT_FOR_SOYA = 0
# Enables LODs computation. LODs computation is quite slow, and the algo is
# surely not optimal :-(
LODS = 0
# Scale the model (not supported by Soya).
SCALE = 1.0
# Set to 1 if you want to prefix all filename with the model name
# (e.g. knight_walk.xaf instead of walk.xaf)
PREFIX_FILE_WITH_MODEL_NAME = 0
# Set to 0 to use Cal3D binary format
XML = 1
MESSAGES = ""
# See also BASE_MATRIX below, if you want to rotate/scale/translate the model at
# the exportation.
# Enables LODs computation. LODs computation is quite slow, and the algo is
# surely not optimal :-(
LODS = 0
#remove the word '.BAKED' from exported baked animations
REMOVE_BAKED = 1
################################################################################
#########################################################################################
# Code starts here.
# The script should be quite re-useable for writing another Blender animation
# exporter. Most of the hell of it is to deal with Blender's head-tail-roll
# bone's definition.
# The script should be quite re-useable for writing another Blender animation exporter.
# Most of the hell of it is to deal with Blender's head-tail-roll bone's definition.
import sys, os, os.path, struct, math, string
import Blender
from Blender.BGL import *
from Blender.Draw import *
from Blender.Armature import *
from Blender.Registry import *
# HACK -- it seems that some Blender versions don't define sys.argv,
# which may crash Python if a warning occurs.
if not hasattr(sys, "argv"): sys.argv = ["???"]
# Math stuff
# transforms a blender to a cal3d quaternion notation (x,y,z,w)
def blender2cal3dquat(q):
return [q.x, q.y, q.z, q.w]
def quaternion2matrix(q):
xx = q[0] * q[0]
@@ -222,12 +142,10 @@ def quaternion2matrix(q):
wx = q[3] * q[0]
wy = q[3] * q[1]
wz = q[3] * q[2]
return [
[1.0 - 2.0 * (yy + zz), 2.0 * (xy + wz), 2.0 * (xz - wy), 0.0],
[2.0 * (xy - wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + wx), 0.0],
[2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (xx + yy), 0.0],
[0.0, 0.0, 0.0, 1.0]
]
return [[1.0 - 2.0 * (yy + zz), 2.0 * (xy + wz), 2.0 * (xz - wy), 0.0],
[ 2.0 * (xy - wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + wx), 0.0],
[ 2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (xx + yy), 0.0],
[0.0 , 0.0 , 0.0 , 1.0]]
def matrix2quaternion(m):
s = math.sqrt(abs(m[0][0] + m[1][1] + m[2][2] + m[3][3]))
@@ -249,25 +167,14 @@ def quaternion_normalize(q):
l = math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3])
return q[0] / l, q[1] / l, q[2] / l, q[3] / l
# multiplies 2 quaternions in x,y,z,w notation
def quaternion_multiply(q1, q2):
r = [
return [
q2[3] * q1[0] + q2[0] * q1[3] + q2[1] * q1[2] - q2[2] * q1[1],
q2[3] * q1[1] + q2[1] * q1[3] + q2[2] * q1[0] - q2[0] * q1[2],
q2[3] * q1[2] + q2[2] * q1[3] + q2[0] * q1[1] - q2[1] * q1[0],
q2[3] * q1[3] - q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2],
]
d = math.sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2] + r[3] * r[3])
if d == 0:
r[0] = d
r[1] = d
r[2] = d
r[3] = d
else:
r[0] /= d
r[1] /= d
r[2] /= d
r[3] /= d
return r
def matrix_translate(m, v):
m[3][0] += v[0]
@@ -369,9 +276,9 @@ def matrix_rotate(axis, angle):
sin = math.sin(angle)
co1 = 1.0 - cos
return [
[vx2 * co1 + cos, vx * vy * co1 + vz * sin, vz * vx * co1 - vy * sin, 0.0],
[vx * vy * co1 - vz * sin, vy2 * co1 + cos, vy * vz * co1 + vx * sin, 0.0],
[vz * vx * co1 + vy * sin, vy * vz * co1 - vx * sin, vz2 * co1 + cos, 0.0],
[vx2 * co1 + cos, vx * vy * co1 + vz * sin, vz * vx * co1 - vy * sin, 0.0],
[vx * vy * co1 - vz * sin, vy2 * co1 + cos, vy * vz * co1 + vx * sin, 0.0],
[vz * vx * co1 + vy * sin, vy * vz * co1 - vx * sin, vz2 * co1 + cos, 0.0],
[0.0, 0.0, 0.0, 1.0],
]
@@ -389,9 +296,14 @@ def point_by_matrix(p, m):
p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]]
def point_distance(p1, p2):
return math.sqrt((p2[0] - p1[0]) ** 2 + \
(p2[1] - p1[1]) ** 2 + (p2[2] - p1[2]) ** 2)
return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2 + (p2[2] - p1[2]) ** 2)
def vector_add(v1, v2):
return [v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]]
def vector_sub(v1, v2):
return [v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]]
def vector_by_matrix(p, m):
return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0],
p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1],
@@ -438,46 +350,49 @@ def blender_bone2matrix(head, tail, roll):
bMatrix = matrix_rotate(axis, theta)
else:
if vector_crossproduct(target, nor) > 0.0: updown = 1.0
else: updown = -1.0
if vector_dotproduct(target, nor) > 0.0: updown = 1.0
else: updown = -1.0
# Quoted from Blender source : "I think this should work ..."
bMatrix = [
[updown, 0.0, 0.0, 0.0],
[0.0, updown, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
[updown, 0.0, 0.0, 0.0],
[0.0, updown, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
]
rMatrix = matrix_rotate(nor, roll)
return matrix_multiply(rMatrix, bMatrix)
# Hack for having the model rotated right.
# Put in BASE_MATRIX your own rotation if you need some.
BASE_MATRIX = None
# Cal3D data structures
CAL3D_VERSION = 700
CAL3D_XML_VERSION = 900
CAL3D_VERSION = 910
NEXT_MATERIAL_ID = 0
class Material:
def __init__(self, map_filename = None):
self.ambient_r = 255
self.ambient_g = 255
self.ambient_b = 255
self.ambient_a = 255
self.diffuse_r = 255
self.diffuse_g = 255
self.diffuse_b = 255
self.diffuse_a = 255
self.ambient_r = 255
self.ambient_g = 255
self.ambient_b = 255
self.ambient_a = 255
self.diffuse_r = 255
self.diffuse_g = 255
self.diffuse_b = 255
self.diffuse_a = 255
self.specular_r = 255
self.specular_g = 255
self.specular_b = 255
self.specular_a = 255
self.shininess = 1.0
if map_filename:
self.maps_filenames = [map_filename]
else:
self.maps_filenames = []
if map_filename: self.maps_filenames = [map_filename]
else: self.maps_filenames = []
MATERIALS[map_filename] = self
@@ -485,37 +400,35 @@ class Material:
self.id = NEXT_MATERIAL_ID
NEXT_MATERIAL_ID += 1
# old cal3d format
def to_cal3d(self):
s = "CRF\0" + struct.pack("iBBBBBBBBBBBBfi", CAL3D_VERSION,
self.ambient_r, self.ambient_g, self.ambient_b, self.ambient_a,
self.diffuse_r, self.diffuse_g, self.diffuse_b, self.diffuse_a,
self.specular_r, self.specular_g, self.specular_b, self.specular_a,
self.shininess, len(self.maps_filenames))
s = "CRF\0" + struct.pack("iBBBBBBBBBBBBfi", CAL3D_VERSION, self.ambient_r, self.ambient_g, self.ambient_b, self.ambient_a, self.diffuse_r, self.diffuse_g, self.diffuse_b, self.diffuse_a, self.specular_r, self.specular_g, self.specular_b, self.specular_a, self.shininess, len(self.maps_filenames))
for map_filename in self.maps_filenames:
s += struct.pack("i", len(map_filename) + 1)
s += map_filename + "\0"
return s
# new xml format
def to_cal3d_xml(self):
s = "<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
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.
if EXPORT_FOR_SOYA:
BASE_MATRIX = matrix_rotate_x(-math.pi / 2.0)
else:
BASE_MATRIX = None
# Get the scene
def export(filename):
global MESSAGES
if EXPORT_FOR_SOYA:
global BASE_MATRIX
BASE_MATRIX = matrix_rotate_x(-math.pi / 2.0)
# 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)
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()
# Turns the Blender's head-tail-roll notation into a quaternion
quat = matrix2quaternion(blender_bone2matrix(head, tail, b.getRoll()))
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
for child in b.getChildren():
treat_bone(child, bone)
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)
# Only one armature / skeleton
break
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)
# Export Mesh data
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()))
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)
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
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
# Here, the translation is simply the head vector
bone = Bone(skeleton, None, b.getName(), loc, rot)
bone.head = head
bone.tail = tail
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
# ---- Export Mesh data ---------------------------------------------------
if EXPORT_MESH or EXPORT_MATERIAL:
STATUS = "Calculate mesh and materials"
Draw()
meshes = []
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)
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)
# 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)
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()
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))
# sum of influences is not always 1.0 in Blender ?!?!
sum = 0.0
for bone_name, weight in influences:
sum += weight
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)
if EXPORT_ANIMATION:
ipoCurveType = ['LocX', 'LocY', 'LocZ', 'QuatX', 'QuatY', 'QuatZ', 'QuatW']
STATUS = "Calculate animations"
Draw()
ANIMATIONS = {}
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
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)]
# 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])
# We need to blend the rotation from the bone rest state
# (=bone.rot) with ipo_rot.
rot = quaternion_multiply(ipo_rot, bone.rot)
KeyFrame(track, time, loc, rot)
# Computes LODs info
if LODS:
submesh.compute_lods()
# ---- Export animations --------------------------------------------------
ANIMATIONS = {}
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]
track = Track(animation, bone)
track.finished = 0
animation.tracks[bone_name] = track
ipo = b[1]
times = []
# 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()
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
# Save all data
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 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))
transt = vector_by_matrix(trans, bone.matrix)
loc = vector_add(bone.loc, transt)
rot = quaternion_multiply(quat, bone.rot)
rot = quaternion_normalize(rot)
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"
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
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))
cfg = open(os.path.join(DIRNAME, BASENAME + ".cfg"), "wb")
print >> cfg, "# Cal3D model exported from Blender with blender2cal3d.py"
print >> cfg
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
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
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
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)
# Main script
def fs_callback(filename):
export(filename)
Blender.Draw.Register(gui, event, button_event)
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']
# 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)
get_from_reg()
Register(gui, event, bevent)

View File

@@ -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$

View File

@@ -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$

View File

@@ -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

View File

@@ -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('.')

View File

@@ -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

View File

@@ -15,12 +15,37 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to Nendo file format.
Usage:
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.
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>
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$
#
# +---------------------------------------------------------+

View File

@@ -15,13 +15,32 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script imports Nendo files to Blender.
Usage:
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.
Execute this script from the "File->Import" menu and choose a Nendo file to
open.
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$
#
# +---------------------------------------------------------+

View File

@@ -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)
'''

View File

@@ -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.
"""
# +---------------------------------------------------------+

View File

@@ -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()

View File

@@ -15,12 +15,30 @@ __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$
#
# +---------------------------------------------------------+

View File

@@ -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$
#
# +---------------------------------------------------------+

View File

@@ -15,9 +15,14 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to Raw Triangle file format.
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.
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.
"""

View File

@@ -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$
#

View File

@@ -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$

View File

@@ -15,9 +15,38 @@ __version__ = "Part of IOSuite 0.5"
__bpydoc__ = """\
This script exports meshes to TrueSpace file format.
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.
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>
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.
"""

View File

@@ -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.

View File

@@ -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

View File

@@ -14,14 +14,35 @@ __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$
#
# +---------------------------------------------------------+

View File

@@ -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$

View File

@@ -195,7 +195,8 @@ PyObject *IpoCurve_Init( void )
/*****************************************************************************/
static PyObject *M_IpoCurve_Get( PyObject * self, PyObject * args )
{
return 0;
Py_INCREF(Py_None);
return Py_None;
}
/*****************************************************************************/

View File

@@ -57,9 +57,7 @@
/*****************************************************************************/
static PyObject *M_Object_New( PyObject * self, PyObject * args );
PyObject *M_Object_Get( PyObject * self, PyObject * args );
PyObject *M_Object_get( PyObject * self, PyObject * args );
static PyObject *M_Object_GetSelected( PyObject * self, PyObject * args );
static PyObject *M_Object_getSelected( PyObject * self, PyObject * args );
/*****************************************************************************/
/* The following string definitions are used for documentation strings. */
@@ -90,12 +88,8 @@ struct PyMethodDef M_Object_methods[] = {
M_Object_New_doc},
{"Get", ( PyCFunction ) M_Object_Get, METH_VARARGS,
M_Object_Get_doc},
{"get", ( PyCFunction ) M_Object_get, METH_VARARGS,
M_Object_Get_doc},
{"GetSelected", ( PyCFunction ) M_Object_GetSelected, METH_VARARGS,
M_Object_GetSelected_doc},
{"getSelected", ( PyCFunction ) M_Object_getSelected, METH_VARARGS,
M_Object_GetSelected_doc},
{NULL, NULL, 0, NULL}
};
@@ -516,21 +510,9 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args )
}
}
/*****************************************************************************/
/* Function: M_Object_get */
/* Python equivalent: Blender.Object.get */
/*****************************************************************************/
PyObject *M_Object_get( PyObject * self, PyObject * args )
{
PyErr_Warn( PyExc_DeprecationWarning,
"The Object.get() function will be removed in Blender 2.29\n"
"Please update the script to use Object.Get" );
return ( M_Object_Get( self, args ) );
}
/*****************************************************************************/
/* Function: M_Object_GetSelected */
/* Python equivalent: Blender.Object.getSelected */
/* Python equivalent: Blender.Object.GetSelected */
/*****************************************************************************/
static PyObject *M_Object_GetSelected( PyObject * self, PyObject * args )
{
@@ -583,19 +565,6 @@ static PyObject *M_Object_GetSelected( PyObject * self, PyObject * args )
return ( list );
}
/*****************************************************************************/
/* Function: M_Object_getSelected */
/* Python equivalent: Blender.Object.getSelected */
/*****************************************************************************/
static PyObject *M_Object_getSelected( PyObject * self, PyObject * args )
{
PyErr_Warn( PyExc_DeprecationWarning,
"The Object.getSelected() function will be removed in "
"Blender 2.29\n"
"Please update the script to use Object.GetSelected" );
return ( M_Object_GetSelected( self, args ) );
}
/*****************************************************************************/
/* Function: initObject */
/*****************************************************************************/

View File

@@ -319,7 +319,7 @@ class Vector:
v = Blender.Mathutils.Vector([1,0,0])
@type list: PyList of float or int
@param list: The list of values for the Vector object.
Must be 2, 3, or 4 values.
Must be 2, 3, or 4 values. The list is mapped to the parameters as [x,y,z,w].
@rtype: Vector object.
@return: It depends wheter a parameter was passed:
- (list): Vector object initialized with the given values;
@@ -420,16 +420,16 @@ class Quaternion:
in degrees.
"""
def __init__(list = None, angle = None):
def __init__(list, angle = None):
"""
Create a new quaternion object from initialized values.
Example::
quat = Mathutils.Quaternion()
quat = Mathutils.Quaternion([1.0,0.0,0.0])
@type list: PyList of int/float
@param list: A 3d or 4d list to initialize quaternion.
4d if intializing, 3d if will be used as an axis of rotation.
4d if intializing [w,x,y,z], 3d if used as an axis of rotation.
@type angle: float (optional)
@param angle: An arbitrary rotation amount around 'list'.
List is used as an axis of rotation in this case.
@@ -527,7 +527,7 @@ class Matrix:
def determinant():
"""
Return a the determinant of a matrix.
Return the determinant of a matrix.
@rtype: int
@return: Return a the determinant of a matrix.
@@ -540,9 +540,12 @@ class Matrix:
def rotationPart():
"""
Return the 3d rotation matrix.
Return the 3d submatrix corresponding to the linear term of the
embedded affine transformation in 3d. This matrix represents rotation
and scale. Note that the (4,4) element of a matrix can be used for uniform
scaling, too.
@rtype: Matrix object.
@return: Return the 3d rotation matrix.
@return: Return the 3d matrix for rotation and scale.
"""
@@ -561,17 +564,17 @@ class Matrix:
def toEuler():
"""
Return a euler representing the rotation matrix.
Return an Euler representation of the rotation matrix.
@rtype: Euler object
@return: Return a euler representing the rotation matrix.
@return: Euler representation of the rotation matrix.
"""
def toQuat():
"""
Return a quaternion representation the rotation matrix
Return a quaternion representation of the rotation matrix
@rtype: Quaternion object
@return: Quaternion representation the rotation matrix
@return: Quaternion representation of the rotation matrix
"""

View File

@@ -531,13 +531,17 @@ PyTypeObject quaternion_Type = {
&Quaternion_SeqMethods, /*tp_as_sequence */
};
/*
newQuaternionObject
if the quat arg is not null, this method allocates memory and copies *quat into it.
we will free the memory in the dealloc routine.
*/
/** Creates a new quaternion object.
*
* Memory for a new quaternion is allocated. The quaternion copies the given
* list of parameters or initializes to the identity, if a <code>NULL</code>
* pointer is given as parameter. The memory will be freed in the dealloc
* routine.
*
* @param quat Pointer to a list of floats for the quanternion parameters w, x, y, z.
* @return Quaternion Python object.
* @see Quaternion_Identity
*/
PyObject *newQuaternionObject( float *quat )
{
QuaternionObject *self;
@@ -550,10 +554,7 @@ PyObject *newQuaternionObject( float *quat )
self->quat = PyMem_Malloc( 4 * sizeof( float ) );
if( !quat ) {
for( x = 0; x < 4; x++ ) {
self->quat[x] = 0.0f;
}
self->quat[3] = 1.0f;
Quaternion_Identity(self);
} else {
for( x = 0; x < 4; x++ ) {
self->quat[x] = quat[x];