Scripts:
- Fixes by Jean-Michel Soler: mod_ai2obj.py, mod_svg2obj.py; - Fixes by Campbell Barton: obj_import.py; - Small fix to mod_meshtools.py (fixes bug #1605: http://projects.blender.org/tracker/?func=detail&atid=125&aid=1605&group_id=9); - Updates by Jean-Baptiste (Jiba) to his blender2cal3d.py; - Updates to all his import / export scripts (added doc data) by Anthony D'Agostino; - Update to off_import: support for uv data, by Arne Schmitz. BPython: - Removed Object.get and .getSelected (deprecated long ago, we use .Get and .GetSelected) -- fixes #1861: http://projects.blender.org/tracker/?func=detail&atid=125&aid=1861&group_id=9 - Applied patch by Michael Reimpell: quat.c - fix for wrong initialization with newQuaternionObject; Mathutils documentation improvements. - Stani reported a wrong return msg in IpoCurve.Get (that is unimplemented). Thanks to all coders mentioned above!
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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('.')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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$
|
||||
#
|
||||
# +---------------------------------------------------------+
|
||||
|
||||
@@ -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$
|
||||
#
|
||||
# +---------------------------------------------------------+
|
||||
|
||||
@@ -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)
|
||||
|
||||
'''
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
# +---------------------------------------------------------+
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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$
|
||||
#
|
||||
# +---------------------------------------------------------+
|
||||
|
||||
@@ -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$
|
||||
#
|
||||
# +---------------------------------------------------------+
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -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$
|
||||
#
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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$
|
||||
#
|
||||
# +---------------------------------------------------------+
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -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 */
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -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
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user