BPyObject.py - function for getting an objects armature, look at both parent and modifier. editmesh_add.c and BPyAddMesh.py - check for multires filesel.c, Append/Link had a bug where files linked in, didnt have the LIB_APPEND_TAG unset, and appending these into a new blend file would link instead. BKE_library.h, library.c - utility functions for flagging listbases flag_all_listbases_ids and and flag_listbase_ids
		
			
				
	
	
		
			1296 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1296 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!BPY
 | |
| """
 | |
| Name: 'Autodesk FBX (.fbx)...'
 | |
| Blender: 243
 | |
| Group: 'Export'
 | |
| Tooltip: 'Selection to an ASCII Autodesk FBX '
 | |
| """
 | |
| __author__ = "Campbell Barton"
 | |
| __url__ = ['www.blender.org', 'blenderartists.org']
 | |
| __version__ = "1.1"
 | |
| 
 | |
| __bpydoc__ = """\
 | |
| This script is an exporter to the FBX file format.
 | |
| 
 | |
| Usage:
 | |
| 
 | |
| Select the objects you wish to export and run this script from "File->Export" menu.
 | |
| All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d)
 | |
| will be exported as mesh data.
 | |
| """
 | |
| 
 | |
| # --------------------------------------------------------------------------
 | |
| # FBX Export v0.1 by Campbell Barton (AKA Ideasman)
 | |
| # --------------------------------------------------------------------------
 | |
| # ***** BEGIN GPL LICENSE BLOCK *****
 | |
| #
 | |
| # 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 the Free Software Foundation; either version 2
 | |
| # of the License, or (at your option) any later version.
 | |
| #
 | |
| # This program is distributed in the hope that it will be useful,
 | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| # GNU General Public License for more details.
 | |
| #
 | |
| # You should have received a copy of the GNU General Public License
 | |
| # along with this program; if not, write to the Free Software Foundation,
 | |
| # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 | |
| #
 | |
| # ***** END GPL LICENCE BLOCK *****
 | |
| # --------------------------------------------------------------------------
 | |
| 
 | |
| import Blender
 | |
| import BPyObject
 | |
| import BPyMesh
 | |
| import BPySys
 | |
| import BPyMessages
 | |
| import time
 | |
| from math import degrees
 | |
| # Used to add the scene name into the filename without using odd chars
 | |
| sane_name_mapping_ob = {}
 | |
| sane_name_mapping_mat = {}
 | |
| sane_name_mapping_tex = {}
 | |
| sane_name_mapping_arm = {}
 | |
| 
 | |
| # Copied from CVS bpyObject
 | |
| def getObjectArmature(ob):
 | |
| 	'''
 | |
| 	This returns the first armature the mesh uses.
 | |
| 	remember there can be more then 1 armature but most people dont do that.
 | |
| 	'''
 | |
| 	arm = ob.parent
 | |
| 	if arm and arm.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE:
 | |
| 		arm
 | |
| 	
 | |
| 	for m in ob.modifiers:
 | |
| 		if m.type== Blender.Modifier.Types.ARMATURE:
 | |
| 			arm = m[Blender.Modifier.Settings.OBJECT]
 | |
| 			if arm:
 | |
| 				return arm
 | |
| 	
 | |
| 	return None
 | |
| 
 | |
| BPyObject.getObjectArmature = getObjectArmature
 | |
| 
 | |
| 
 | |
| 
 | |
| def strip_path(p):
 | |
| 	return p.split('\\')[-1].split('/')[-1]
 | |
| 
 | |
| def sane_name(data, dct):
 | |
| 	if not data: return None
 | |
| 	name = data.name
 | |
| 	try:		return dct[name]
 | |
| 	except:		pass
 | |
| 	
 | |
| 	orig_name = name
 | |
| 	name = BPySys.cleanName(name)
 | |
| 	dct[orig_name] = name
 | |
| 	return name
 | |
| 
 | |
| def sane_obname(data):
 | |
| 	return sane_name(data, sane_name_mapping_ob)
 | |
| 
 | |
| def sane_matname(data):
 | |
| 	return sane_name(data, sane_name_mapping_mat)
 | |
| 
 | |
| def sane_texname(data):
 | |
| 	return sane_name(data, sane_name_mapping_tex)
 | |
| 
 | |
| def sane_armname(data):
 | |
| 	return sane_name(data, sane_name_mapping_arm)
 | |
| 
 | |
| # May use this later
 | |
| """
 | |
| # Auto class, use for datastorage only, a like a dictionary but with limited slots
 | |
| def auto_class(slots):
 | |
| 	exec('class container_class(object): __slots__=%s' % slots)
 | |
| 	return container_class
 | |
| """
 | |
| 
 | |
| 
 | |
| header_comment = \
 | |
| '''; FBX 6.1.0 project file
 | |
| ; Created by Blender FBX Exporter
 | |
| ; for support mail cbarton@metavr.com
 | |
| ; ----------------------------------------------------
 | |
| 
 | |
| '''
 | |
| 
 | |
| def write_header(file):
 | |
| 	file.write(header_comment)
 | |
| 	curtime = time.localtime()[0:6]
 | |
| 	# 
 | |
| 	file.write(\
 | |
| '''FBXHeaderExtension:  {
 | |
| 	FBXHeaderVersion: 1003
 | |
| 	FBXVersion: 6100
 | |
| 	CreationTimeStamp:  {
 | |
| 		Version: 1000
 | |
| 		Year: %.4i
 | |
| 		Month: %.2i
 | |
| 		Day: %.2i
 | |
| 		Hour: %.2i
 | |
| 		Minute: %.2i
 | |
| 		Second: %.2i
 | |
| 		Millisecond: 0
 | |
| 	}
 | |
| 	Creator: "FBX SDK/FBX Plugins build 20070228"
 | |
| 	OtherFlags:  {
 | |
| 		FlagPLE: 0
 | |
| 	}
 | |
| }
 | |
| ''' % (curtime))
 | |
| 	
 | |
| 	file.write('CreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"\n' % curtime)
 | |
| 	file.write('Creator: "Blender3D version %.2f"\n' % Blender.Get('version'))
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| def write_scene(file, sce, world):
 | |
| 	
 | |
| 	def write_camera_switch():
 | |
| 		file.write('''
 | |
| 	Model: "Model::Camera Switcher", "CameraSwitcher" {
 | |
| 		Version: 232
 | |
| 		Properties60:  {
 | |
| 			Property: "QuaternionInterpolate", "bool", "",0
 | |
| 			Property: "Visibility", "Visibility", "A+",0
 | |
| 			Property: "Lcl Translation", "Lcl Translation", "A+",0,0,0
 | |
| 			Property: "Lcl Rotation", "Lcl Rotation", "A+",0,0,0
 | |
| 			Property: "Lcl Scaling", "Lcl Scaling", "A+",1,1,1
 | |
| 			Property: "RotationOffset", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationPivot", "Vector3D", "",0,0,0
 | |
| 			Property: "ScalingOffset", "Vector3D", "",0,0,0
 | |
| 			Property: "ScalingPivot", "Vector3D", "",0,0,0
 | |
| 			Property: "TranslationActive", "bool", "",0
 | |
| 			Property: "TranslationMin", "Vector3D", "",0,0,0
 | |
| 			Property: "TranslationMax", "Vector3D", "",0,0,0
 | |
| 			Property: "TranslationMinX", "bool", "",0
 | |
| 			Property: "TranslationMinY", "bool", "",0
 | |
| 			Property: "TranslationMinZ", "bool", "",0
 | |
| 			Property: "TranslationMaxX", "bool", "",0
 | |
| 			Property: "TranslationMaxY", "bool", "",0
 | |
| 			Property: "TranslationMaxZ", "bool", "",0
 | |
| 			Property: "RotationOrder", "enum", "",0
 | |
| 			Property: "RotationSpaceForLimitOnly", "bool", "",0
 | |
| 			Property: "AxisLen", "double", "",10
 | |
| 			Property: "PreRotation", "Vector3D", "",0,0,0
 | |
| 			Property: "PostRotation", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationActive", "bool", "",0
 | |
| 			Property: "RotationMin", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationMax", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationMinX", "bool", "",0
 | |
| 			Property: "RotationMinY", "bool", "",0
 | |
| 			Property: "RotationMinZ", "bool", "",0
 | |
| 			Property: "RotationMaxX", "bool", "",0
 | |
| 			Property: "RotationMaxY", "bool", "",0
 | |
| 			Property: "RotationMaxZ", "bool", "",0
 | |
| 			Property: "RotationStiffnessX", "double", "",0
 | |
| 			Property: "RotationStiffnessY", "double", "",0
 | |
| 			Property: "RotationStiffnessZ", "double", "",0
 | |
| 			Property: "MinDampRangeX", "double", "",0
 | |
| 			Property: "MinDampRangeY", "double", "",0
 | |
| 			Property: "MinDampRangeZ", "double", "",0
 | |
| 			Property: "MaxDampRangeX", "double", "",0
 | |
| 			Property: "MaxDampRangeY", "double", "",0
 | |
| 			Property: "MaxDampRangeZ", "double", "",0
 | |
| 			Property: "MinDampStrengthX", "double", "",0
 | |
| 			Property: "MinDampStrengthY", "double", "",0
 | |
| 			Property: "MinDampStrengthZ", "double", "",0
 | |
| 			Property: "MaxDampStrengthX", "double", "",0
 | |
| 			Property: "MaxDampStrengthY", "double", "",0
 | |
| 			Property: "MaxDampStrengthZ", "double", "",0
 | |
| 			Property: "PreferedAngleX", "double", "",0
 | |
| 			Property: "PreferedAngleY", "double", "",0
 | |
| 			Property: "PreferedAngleZ", "double", "",0
 | |
| 			Property: "InheritType", "enum", "",0
 | |
| 			Property: "ScalingActive", "bool", "",0
 | |
| 			Property: "ScalingMin", "Vector3D", "",1,1,1
 | |
| 			Property: "ScalingMax", "Vector3D", "",1,1,1
 | |
| 			Property: "ScalingMinX", "bool", "",0
 | |
| 			Property: "ScalingMinY", "bool", "",0
 | |
| 			Property: "ScalingMinZ", "bool", "",0
 | |
| 			Property: "ScalingMaxX", "bool", "",0
 | |
| 			Property: "ScalingMaxY", "bool", "",0
 | |
| 			Property: "ScalingMaxZ", "bool", "",0
 | |
| 			Property: "GeometricTranslation", "Vector3D", "",0,0,0
 | |
| 			Property: "GeometricRotation", "Vector3D", "",0,0,0
 | |
| 			Property: "GeometricScaling", "Vector3D", "",1,1,1
 | |
| 			Property: "LookAtProperty", "object", ""
 | |
| 			Property: "UpVectorProperty", "object", ""
 | |
| 			Property: "Show", "bool", "",0
 | |
| 			Property: "NegativePercentShapeSupport", "bool", "",1
 | |
| 			Property: "DefaultAttributeIndex", "int", "",0
 | |
| 			Property: "Color", "Color", "A",0.8,0.8,0.8
 | |
| 			Property: "Camera Index", "Integer", "A+",100
 | |
| 		}
 | |
| 		MultiLayer: 0
 | |
| 		MultiTake: 1
 | |
| 		Hidden: "True"
 | |
| 		Shading: W
 | |
| 		Culling: "CullingOff"
 | |
| 		Version: 101
 | |
| 		Name: "Model::Camera Switcher"
 | |
| 		CameraId: 0
 | |
| 		CameraName: 100
 | |
| 		CameraIndexName: 
 | |
| 	}''')
 | |
| 	
 | |
| 	def write_camera(name, loc, near, far, proj_type, up):
 | |
| 		file.write('\n\tModel: "Model::%s", "Camera" {\n' % name )
 | |
| 		file.write('\t\tVersion: 232\n')
 | |
| 		file.write('\t\tProperties60:  {\n')
 | |
| 		file.write('\t\t\tProperty: "QuaternionInterpolate", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "Visibility", "Visibility", "A+",0\n')
 | |
| 		file.write('\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.6f,%.6f,%.6f\n' % loc)
 | |
| 		file.write('\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",1,1,1\n')
 | |
| 		file.write('\t\t\tProperty: "RotationOffset", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationPivot", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingOffset", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingPivot", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationActive", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMin", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMax", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMinX", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMinY", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMinZ", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMaxX", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMaxY", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "TranslationMaxZ", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationOrder", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationSpaceForLimitOnly", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "AxisLen", "double", "",10\n')
 | |
| 		file.write('\t\t\tProperty: "PreRotation", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "PostRotation", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationActive", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMin", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMax", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMinX", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMinY", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMinZ", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMaxX", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMaxY", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationMaxZ", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationStiffnessX", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationStiffnessY", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "RotationStiffnessZ", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MinDampRangeX", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MinDampRangeY", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MinDampRangeZ", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MaxDampRangeX", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MaxDampRangeY", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MaxDampRangeZ", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MinDampStrengthX", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MinDampStrengthY", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MinDampStrengthZ", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MaxDampStrengthX", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MaxDampStrengthY", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "MaxDampStrengthZ", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "PreferedAngleX", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "PreferedAngleY", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "PreferedAngleZ", "double", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "InheritType", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingActive", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMin", "Vector3D", "",1,1,1\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMax", "Vector3D", "",1,1,1\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMinX", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMinY", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMinZ", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMaxX", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMaxY", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ScalingMaxZ", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "GeometricTranslation", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "GeometricRotation", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "GeometricScaling", "Vector3D", "",1,1,1\n')
 | |
| 		file.write('\t\t\tProperty: "LookAtProperty", "object", ""\n')
 | |
| 		file.write('\t\t\tProperty: "UpVectorProperty", "object", ""\n')
 | |
| 		file.write('\t\t\tProperty: "Show", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "NegativePercentShapeSupport", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "DefaultAttributeIndex", "int", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8\n')
 | |
| 		file.write('\t\t\tProperty: "Roll", "Roll", "A+",0\n')
 | |
| 		file.write('\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40\n')
 | |
| 		file.write('\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1\n')
 | |
| 		file.write('\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1\n')
 | |
| 		file.write('\t\t\tProperty: "OpticalCenterX", "Real", "A+",0\n')
 | |
| 		file.write('\t\t\tProperty: "OpticalCenterY", "Real", "A+",0\n')
 | |
| 		file.write('\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63\n')
 | |
| 		file.write('\t\t\tProperty: "TurnTable", "Real", "A+",0\n')
 | |
| 		file.write('\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1\n')
 | |
| 		file.write('\t\t\tProperty: "UseMotionBlur", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "ResolutionMode", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ApertureMode", "enum", "",2\n')
 | |
| 		file.write('\t\t\tProperty: "GateFit", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486\n')
 | |
| 		file.write('\t\t\tProperty: "CameraFormat", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "AspectW", "double", "",320\n')
 | |
| 		file.write('\t\t\tProperty: "AspectH", "double", "",200\n')
 | |
| 		file.write('\t\t\tProperty: "PixelAspectRatio", "double", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "UseFrameColor", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3\n')
 | |
| 		file.write('\t\t\tProperty: "ShowName", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "ShowGrid", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "ShowOpticalCenter", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ShowAzimut", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "ShowTimeCode", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "NearPlane", "double", "",%.6f\n' % near)
 | |
| 		file.write('\t\t\tProperty: "FarPlane", "double", "",%.6f\n' % far)
 | |
| 		file.write('\t\t\tProperty: "FilmWidth", "double", "",0.816\n')
 | |
| 		file.write('\t\t\tProperty: "FilmHeight", "double", "",0.612\n')
 | |
| 		file.write('\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333\n')
 | |
| 		file.write('\t\t\tProperty: "FilmSqueezeRatio", "double", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "FilmFormatIndex", "enum", "",4\n')
 | |
| 		file.write('\t\t\tProperty: "ViewFrustum", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2\n')
 | |
| 		file.write('\t\t\tProperty: "BackPlaneDistance", "double", "",100\n')
 | |
| 		file.write('\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "LockMode", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "LockInterestNavigation", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "FitImage", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "Crop", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "Center", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "KeepRatio", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "BackgroundMode", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5\n')
 | |
| 		file.write('\t\t\tProperty: "ForegroundTransparent", "bool", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "DisplaySafeArea", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333\n')
 | |
| 		file.write('\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100\n')
 | |
| 		file.write('\t\t\tProperty: "2D Magnifier X", "Real", "A+",50\n')
 | |
| 		file.write('\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50\n')
 | |
| 		file.write('\t\t\tProperty: "CameraProjectionType", "enum", "",%i\n' % proj_type)
 | |
| 		file.write('\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "UseDepthOfField", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "FocusSource", "enum", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "FocusAngle", "double", "",3.5\n')
 | |
| 		file.write('\t\t\tProperty: "FocusDistance", "double", "",200\n')
 | |
| 		file.write('\t\t\tProperty: "UseAntialiasing", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777\n')
 | |
| 		file.write('\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "FrameSamplingCount", "int", "",7\n')
 | |
| 		file.write('\t\t}\n')
 | |
| 		file.write('\t\tMultiLayer: 0\n')
 | |
| 		file.write('\t\tMultiTake: 0\n')
 | |
| 		file.write('\t\tHidden: "True"\n')
 | |
| 		file.write('\t\tShading: Y\n')
 | |
| 		file.write('\t\tCulling: "CullingOff"\n')
 | |
| 		file.write('\t\tTypeFlags: "Camera"\n')
 | |
| 		file.write('\t\tGeometryVersion: 124\n')
 | |
| 		file.write('\t\tPosition: 0,71.3,287.5\n')
 | |
| 		file.write('\t\tUp: %i,%i,%i\n' % up)
 | |
| 		file.write('\t\tLookAt: 0,0,0\n')
 | |
| 		file.write('\t\tShowInfoOnMoving: 1\n')
 | |
| 		file.write('\t\tShowAudio: 0\n')
 | |
| 		file.write('\t\tAudioColor: 0,1,0\n')
 | |
| 		file.write('\t\tCameraOrthoZoom: 1\n')
 | |
| 		file.write('\t}\n')
 | |
| 	
 | |
| 	def write_camera_default():
 | |
| 		# This sucks but to match FBX converter its easier to
 | |
| 		# write the cameras though they are not needed.
 | |
| 		write_camera('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0))
 | |
| 		write_camera('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1))
 | |
| 		write_camera('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1))
 | |
| 		write_camera('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0))
 | |
| 		write_camera('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0))
 | |
| 		write_camera('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0))
 | |
| 		write_camera('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0))
 | |
| 	
 | |
| 	def write_object_props(ob):
 | |
| 		# if the type is 0 its an empty otherwise its a mesh
 | |
| 		# only difference at the moment is one has a color
 | |
| 		file.write('''
 | |
| 		Properties60:  {
 | |
| 			Property: "QuaternionInterpolate", "bool", "",0
 | |
| 			Property: "Visibility", "Visibility", "A+",1''')
 | |
| 		
 | |
| 		if ob:
 | |
| 			file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % tuple(ob.getLocation('worldspace')))
 | |
| 			file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % tuple([degrees(a) for a in ob.getEuler('worldspace')]))
 | |
| 			file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % tuple(ob.getSize('worldspace')))
 | |
| 		else:
 | |
| 			file.write('''
 | |
| 			Property: "Lcl Translation", "Lcl Translation", "A+",0,0,0
 | |
| 			Property: "Lcl Rotation", "Lcl Rotation", "A+",0,0,0
 | |
| 			Property: "Lcl Scaling", "Lcl Scaling", "A+",1,1,1''')
 | |
| 		
 | |
| 		file.write('''
 | |
| 			Property: "RotationOffset", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationPivot", "Vector3D", "",0,0,0
 | |
| 			Property: "ScalingOffset", "Vector3D", "",0,0,0
 | |
| 			Property: "ScalingPivot", "Vector3D", "",0,0,0
 | |
| 			Property: "TranslationActive", "bool", "",0
 | |
| 			Property: "TranslationMin", "Vector3D", "",0,0,0
 | |
| 			Property: "TranslationMax", "Vector3D", "",0,0,0
 | |
| 			Property: "TranslationMinX", "bool", "",0
 | |
| 			Property: "TranslationMinY", "bool", "",0
 | |
| 			Property: "TranslationMinZ", "bool", "",0
 | |
| 			Property: "TranslationMaxX", "bool", "",0
 | |
| 			Property: "TranslationMaxY", "bool", "",0
 | |
| 			Property: "TranslationMaxZ", "bool", "",0
 | |
| 			Property: "RotationOrder", "enum", "",0
 | |
| 			Property: "RotationSpaceForLimitOnly", "bool", "",0
 | |
| 			Property: "AxisLen", "double", "",10
 | |
| 			Property: "PreRotation", "Vector3D", "",0,0,0
 | |
| 			Property: "PostRotation", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationActive", "bool", "",0
 | |
| 			Property: "RotationMin", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationMax", "Vector3D", "",0,0,0
 | |
| 			Property: "RotationMinX", "bool", "",0
 | |
| 			Property: "RotationMinY", "bool", "",0
 | |
| 			Property: "RotationMinZ", "bool", "",0
 | |
| 			Property: "RotationMaxX", "bool", "",0
 | |
| 			Property: "RotationMaxY", "bool", "",0
 | |
| 			Property: "RotationMaxZ", "bool", "",0
 | |
| 			Property: "RotationStiffnessX", "double", "",0
 | |
| 			Property: "RotationStiffnessY", "double", "",0
 | |
| 			Property: "RotationStiffnessZ", "double", "",0
 | |
| 			Property: "MinDampRangeX", "double", "",0
 | |
| 			Property: "MinDampRangeY", "double", "",0
 | |
| 			Property: "MinDampRangeZ", "double", "",0
 | |
| 			Property: "MaxDampRangeX", "double", "",0
 | |
| 			Property: "MaxDampRangeY", "double", "",0
 | |
| 			Property: "MaxDampRangeZ", "double", "",0
 | |
| 			Property: "MinDampStrengthX", "double", "",0
 | |
| 			Property: "MinDampStrengthY", "double", "",0
 | |
| 			Property: "MinDampStrengthZ", "double", "",0
 | |
| 			Property: "MaxDampStrengthX", "double", "",0
 | |
| 			Property: "MaxDampStrengthY", "double", "",0
 | |
| 			Property: "MaxDampStrengthZ", "double", "",0
 | |
| 			Property: "PreferedAngleX", "double", "",0
 | |
| 			Property: "PreferedAngleY", "double", "",0
 | |
| 			Property: "PreferedAngleZ", "double", "",0
 | |
| 			Property: "InheritType", "enum", "",0
 | |
| 			Property: "ScalingActive", "bool", "",0
 | |
| 			Property: "ScalingMin", "Vector3D", "",1,1,1
 | |
| 			Property: "ScalingMax", "Vector3D", "",1,1,1
 | |
| 			Property: "ScalingMinX", "bool", "",0
 | |
| 			Property: "ScalingMinY", "bool", "",0
 | |
| 			Property: "ScalingMinZ", "bool", "",0
 | |
| 			Property: "ScalingMaxX", "bool", "",0
 | |
| 			Property: "ScalingMaxY", "bool", "",0
 | |
| 			Property: "ScalingMaxZ", "bool", "",0
 | |
| 			Property: "GeometricTranslation", "Vector3D", "",0,0,0
 | |
| 			Property: "GeometricRotation", "Vector3D", "",0,0,0
 | |
| 			Property: "GeometricScaling", "Vector3D", "",1,1,1
 | |
| 			Property: "LookAtProperty", "object", ""
 | |
| 			Property: "UpVectorProperty", "object", ""
 | |
| 			Property: "Show", "bool", "",1
 | |
| 			Property: "NegativePercentShapeSupport", "bool", "",1
 | |
| 			Property: "DefaultAttributeIndex", "int", "",0''')
 | |
| 		if ob:
 | |
| 			# Only mesh objects have color 
 | |
| 			file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
 | |
| 			file.write('\n\t\t\tProperty: "Size", "double", "",100')
 | |
| 			file.write('\n\t\t\tProperty: "Look", "enum", "",1')
 | |
| 		
 | |
| 		file.write('\n\t\t}\n')
 | |
| 	
 | |
| 	
 | |
| 	
 | |
| 	# Material Settings
 | |
| 	if world:
 | |
| 		world_amb = world.getAmb()
 | |
| 	else:
 | |
| 		world_amb = (0,0,0) # Default value
 | |
| 	
 | |
| 	
 | |
| 	def write_material(matname, mat):
 | |
| 		file.write('\n\tMaterial: "Material::%s", "" {' % matname)
 | |
| 		
 | |
| 		# Todo, add more material Properties.
 | |
| 		if mat:
 | |
| 			mat_cold = tuple(mat.rgbCol)
 | |
| 			mat_cols = tuple(mat.specCol)
 | |
| 			#mat_colm = tuple(mat.mirCol)
 | |
| 			mat_colamb = tuple([c for c in world_amb])
 | |
| 			
 | |
| 			mat_dif = mat.ref
 | |
| 			mat_amb = mat.amb
 | |
| 			mat_hard = (float(mat.hard)-1)/5.10
 | |
| 			mat_spec = mat.spec/2.0
 | |
| 			mat_alpha = mat.alpha
 | |
| 			mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS
 | |
| 			if mat_shadeless:
 | |
| 				mat_shader = 'Lambert'
 | |
| 			else:
 | |
| 				if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT:
 | |
| 					mat_shader = 'Lambert'
 | |
| 				else:
 | |
| 					mat_shader = 'Phong'
 | |
| 		else:
 | |
| 			mat_cols = mat_cold = 0.8, 0.8, 0.8
 | |
| 			mat_colamb = 0.0,0.0,0.0
 | |
| 			# mat_colm 
 | |
| 			mat_dif = 1.0
 | |
| 			mat_amb = 0.5
 | |
| 			mat_hard = 20.0
 | |
| 			mat_spec = 0.2
 | |
| 			mat_alpha = 1.0
 | |
| 			mat_shadeless = False
 | |
| 			mat_shader = 'Phong'
 | |
| 		
 | |
| 		file.write('\n\t\tVersion: 102\n')
 | |
| 		file.write('\t\tShadingModel: "%s"\n' % mat_shader.lower())
 | |
| 		file.write('\t\tMultiLayer: 0\n')
 | |
| 		file.write('\t\tProperties60:  {\n')
 | |
| 		file.write('\t\t\tProperty: "ShadingModel", "KString", "", "%s"\n' % mat_shader)
 | |
| 		file.write('\t\t\tProperty: "MultiLayer", "bool", "",0\n')
 | |
| 		file.write('\t\t\tProperty: "EmissiveColor", "ColorRGB", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "EmissiveFactor", "double", "",1\n')
 | |
| 		
 | |
| 		file.write('\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.1f,%.1f,%.1f\n' % mat_colamb)
 | |
| 		file.write('\t\t\tProperty: "AmbientFactor", "double", "",%.1f\n' % mat_amb)
 | |
| 		file.write('\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.1f,%.1f,%.1f\n' % mat_cold)
 | |
| 		file.write('\t\t\tProperty: "DiffuseFactor", "double", "",%.1f\n' % mat_dif)
 | |
| 		file.write('\t\t\tProperty: "Bump", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1\n')
 | |
| 		file.write('\t\t\tProperty: "TransparencyFactor", "double", "",0\n')
 | |
| 		if not mat_shadeless:
 | |
| 			file.write('\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.1f,%.1f,%.1f\n' % mat_cols)
 | |
| 			file.write('\t\t\tProperty: "SpecularFactor", "double", "",%.1f\n' % mat_spec)
 | |
| 			file.write('\t\t\tProperty: "ShininessExponent", "double", "",80.0\n')
 | |
| 			file.write('\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0\n')
 | |
| 			file.write('\t\t\tProperty: "ReflectionFactor", "double", "",1\n')
 | |
| 		file.write('\t\t\tProperty: "Emissive", "Vector3D", "",0,0,0\n')
 | |
| 		file.write('\t\t\tProperty: "Ambient", "Vector3D", "",%.1f,%.1f,%.1f\n' % mat_colamb)
 | |
| 		file.write('\t\t\tProperty: "Diffuse", "Vector3D", "",%.1f,%.1f,%.1f\n' % mat_cold)
 | |
| 		if not mat_shadeless:
 | |
| 			file.write('\t\t\tProperty: "Specular", "Vector3D", "",%.1f,%.1f,%.1f\n' % mat_cols)
 | |
| 			file.write('\t\t\tProperty: "Shininess", "double", "",%.1f\n' % mat_hard)
 | |
| 		file.write('\t\t\tProperty: "Opacity", "double", "",%.1f\n' % mat_alpha)
 | |
| 		if not mat_shadeless:
 | |
| 			file.write('\t\t\tProperty: "Reflectivity", "double", "",0\n')
 | |
| 
 | |
| 		file.write('\t\t}\n')
 | |
| 		file.write('\t}')
 | |
| 	
 | |
| 	def write_video(texname, tex):
 | |
| 		# Same as texture really!
 | |
| 		file.write('\n\tVideo: "Video::%s", "Clip" {' % texname)
 | |
| 		
 | |
| 		file.write('''
 | |
| 		Type: "Clip"
 | |
| 		Properties60:  {
 | |
| 			Property: "FrameRate", "double", "",0
 | |
| 			Property: "LastFrame", "int", "",0
 | |
| 			Property: "Width", "int", "",0
 | |
| 			Property: "Height", "int", "",0''')
 | |
| 		if tex:
 | |
| 			fname = tex.filename
 | |
| 			fname_strip = strip_path(fname)
 | |
| 		else:
 | |
| 			fname = fname_strip = ''
 | |
| 		
 | |
| 		file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip)
 | |
| 		
 | |
| 		
 | |
| 		file.write('''
 | |
| 			Property: "StartFrame", "int", "",0
 | |
| 			Property: "StopFrame", "int", "",0
 | |
| 			Property: "PlaySpeed", "double", "",1
 | |
| 			Property: "Offset", "KTime", "",0
 | |
| 			Property: "InterlaceMode", "enum", "",0
 | |
| 			Property: "FreeRunning", "bool", "",0
 | |
| 			Property: "Loop", "bool", "",0
 | |
| 			Property: "AccessMode", "enum", "",0
 | |
| 		}
 | |
| 		UseMipMap: 0''')
 | |
| 		
 | |
| 		file.write('\n\t\tFilename: "%s"' % fname_strip)
 | |
| 		if fname_strip: fname_strip = '/' + fname_strip
 | |
| 		file.write('\n\t\tRelativeFilename: "fbx%s"' % fname_strip) # make relative
 | |
| 		file.write('\n\t}')
 | |
| 
 | |
| 	
 | |
| 	def write_texture(texname, tex, num):
 | |
| 		# if tex == None then this is a dummy tex
 | |
| 		file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname)
 | |
| 		file.write('\n\t\tType: "TextureVideoClip"')
 | |
| 		file.write('\n\t\tVersion: 202')
 | |
| 		# TODO, rare case _empty_ exists as a name.
 | |
| 		file.write('\n\t\tTextureName: "Texture::%s"' % texname)
 | |
| 		
 | |
| 		file.write('''
 | |
| 		Properties60:  {
 | |
| 			Property: "Translation", "Vector", "A+",0,0,0
 | |
| 			Property: "Rotation", "Vector", "A+",0,0,0
 | |
| 			Property: "Scaling", "Vector", "A+",1,1,1''')
 | |
| 		file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num)
 | |
| 		file.write('''
 | |
| 			Property: "TextureTypeUse", "enum", "",0
 | |
| 			Property: "CurrentTextureBlendMode", "enum", "",1
 | |
| 			Property: "UseMaterial", "bool", "",0
 | |
| 			Property: "UseMipMap", "bool", "",0
 | |
| 			Property: "CurrentMappingType", "enum", "",0
 | |
| 			Property: "UVSwap", "bool", "",0
 | |
| 			Property: "WrapModeU", "enum", "",0
 | |
| 			Property: "WrapModeV", "enum", "",0
 | |
| 			Property: "TextureRotationPivot", "Vector3D", "",0,0,0
 | |
| 			Property: "TextureScalingPivot", "Vector3D", "",0,0,0
 | |
| 			Property: "VideoProperty", "object", ""
 | |
| 		}''')
 | |
| 		
 | |
| 		file.write('\n\t\tMedia: "Video::%s"' % texname)
 | |
| 		if tex:
 | |
| 			fname = tex.filename
 | |
| 			file.write('\n\t\tFileName: "%s"' % strip_path(fname))
 | |
| 			file.write('\n\t\tRelativeFilename: "fbx/%s"' % strip_path(fname)) # need some make relative command
 | |
| 		else:
 | |
| 			file.write('\n\t\tFileName: ""')
 | |
| 			file.write('\n\t\tRelativeFilename: "fbx"')
 | |
| 		
 | |
| 		file.write('''
 | |
| 		ModelUVTranslation: 0,0
 | |
| 		ModelUVScaling: 1,1
 | |
| 		Texture_Alpha_Source: "None"
 | |
| 		Cropping: 0,0,0,0
 | |
| 	}''')
 | |
| 	
 | |
| 	objects = []
 | |
| 	materials = {}
 | |
| 	textures = {}
 | |
| 	armatures = [] # We should export standalone armatures also
 | |
| 	armatures_totbones = 0 # we need this because each bone is a model
 | |
| 	for ob in sce.objects.context:
 | |
| 		if ob.type == 'Mesh':	me = ob.getData(mesh=1)
 | |
| 		else:					me = BPyMesh.getMeshFromObject(ob)
 | |
| 		
 | |
| 		if me:
 | |
| 			mats = me.materials
 | |
| 			for mat in mats:
 | |
| 				# 2.44 use mat.lib too for uniqueness
 | |
| 				if mat: materials[mat.name] = mat
 | |
| 			
 | |
| 			if me.faceUV:
 | |
| 				uvlayer_orig = me.activeUVLayer
 | |
| 				for uvlayer in me.getUVLayerNames():
 | |
| 					me.activeUVLayer = uvlayer
 | |
| 					for f in me.faces:
 | |
| 						img = f.image
 | |
| 						if img: textures[img.name] = img
 | |
| 					
 | |
| 					me.activeUVLayer = uvlayer_orig
 | |
| 			
 | |
| 			arm = BPyObject.getObjectArmature(ob)
 | |
| 			
 | |
| 			if arm:
 | |
| 				armname = sane_armname(arm)
 | |
| 				bones = arm.bones.values()
 | |
| 				armatures_totbones += len(bones)
 | |
| 				armatures.append((arm, armname, bones))
 | |
| 			else:
 | |
| 				armname = None
 | |
| 			
 | |
| 			#### me.transform(ob.matrixWorld) # Export real ob coords.
 | |
| 			#### High Quality, not realy needed for now.
 | |
| 			#BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
 | |
| 			objects.append( (sane_obname(ob), ob, me, mats, arm, armname) )
 | |
| 	
 | |
| 	materials = [(sane_matname(mat), mat) for mat in materials.itervalues()]
 | |
| 	textures = [(sane_texname(img), img) for img in textures.itervalues()]
 | |
| 	materials.sort() # sort by name
 | |
| 	textures.sort()
 | |
| 	
 | |
| 	if not materials:
 | |
| 		materials = [('null', None)]
 | |
| 	
 | |
| 	material_mapping = {} # blen name : index
 | |
| 	if textures:
 | |
| 		texture_mapping_local = {None:0} # ditto
 | |
| 		i = 0
 | |
| 		for texname, tex in textures:
 | |
| 			texture_mapping_local[tex.name] = i
 | |
| 			i+=1
 | |
| 		textures.insert(0, ('_empty_', None))
 | |
| 	
 | |
| 	i = 0
 | |
| 	for matname, mat in materials:
 | |
| 		if mat: mat = mat.name
 | |
| 		material_mapping[mat] = i
 | |
| 		i+=1
 | |
| 
 | |
| 	camera_count = 8
 | |
| 	file.write(\
 | |
| '''
 | |
| ; Object definitions
 | |
| ;------------------------------------------------------------------
 | |
| 
 | |
| Definitions:  {
 | |
| 	Version: 100
 | |
| 	Count: %i''' % (1+1+camera_count+len(objects)+len(armatures)+armatures_totbones+len(materials)+(len(textures)*2))) # add 1 for the root model 1 for global settings
 | |
| 	
 | |
| 	file.write('''
 | |
| 	ObjectType: "Model" {
 | |
| 		Count: %i
 | |
| 	}''' % (1+camera_count+len(objects)+len(armatures)+armatures_totbones)) # add 1 for the root model
 | |
| 	
 | |
| 	file.write('''
 | |
| 	ObjectType: "Geometry" {
 | |
| 		Count: %i
 | |
| 	}''' % len(objects))
 | |
| 	
 | |
| 	if materials:
 | |
| 		file.write('''
 | |
| 	ObjectType: "Material" {
 | |
| 		Count: %i
 | |
| 	}''' % len(materials))
 | |
| 	
 | |
| 	if textures:
 | |
| 		file.write('''
 | |
| 	ObjectType: "Texture" {
 | |
| 		Count: %i
 | |
| 	}''' % len(textures)) # add 1 for an empty tex
 | |
| 		file.write('''
 | |
| 	ObjectType: "Video" {
 | |
| 		Count: %i
 | |
| 	}''' % len(textures)) # add 1 for an empty tex
 | |
| 	
 | |
| 	file.write('''
 | |
| 	ObjectType: "GlobalSettings" {
 | |
| 		Count: 1
 | |
| 	}
 | |
| }
 | |
| ''')
 | |
| 	
 | |
| 	file.write(\
 | |
| '''
 | |
| ; Object properties
 | |
| ;------------------------------------------------------------------
 | |
| 
 | |
| Objects:  {''')
 | |
| 	
 | |
| 	# To comply with other FBX FILES
 | |
| 	write_camera_switch()
 | |
| 	
 | |
| 	# Write the null object
 | |
| 	file.write('''
 | |
| 	Model: "Model::blend_root", "Null" {
 | |
| 		Version: 232''')
 | |
| 	write_object_props(None)
 | |
| 	file.write(\
 | |
| '''		MultiLayer: 0
 | |
| 		MultiTake: 1
 | |
| 		Shading: Y
 | |
| 		Culling: "CullingOff"
 | |
| 		TypeFlags: "Null"
 | |
| 	}''')
 | |
| 
 | |
| 	
 | |
| 	for obname, ob, me, mats, arm, armname in objects:
 | |
| 		file.write('\n\tModel: "Model::%s", "Mesh" {\n' % sane_obname(ob))
 | |
| 		file.write('\t\tVersion: 232') # newline is added in write_object_props
 | |
| 		write_object_props(ob)
 | |
| 		
 | |
| 		file.write('\t\tMultiLayer: 0\n')
 | |
| 		file.write('\t\tMultiTake: 1\n')
 | |
| 		file.write('\t\tShading: Y\n')
 | |
| 		file.write('\t\tCulling: "CullingOff"')
 | |
| 		
 | |
| 		# Write the Real Mesh data here
 | |
| 		file.write('\n\t\tVertices: ')
 | |
| 		i=-1
 | |
| 		for v in me.verts:
 | |
| 			if i==-1:
 | |
| 				file.write('%.6f,%.6f,%.6f' % tuple(v.co))
 | |
| 				i=0
 | |
| 			else:
 | |
| 				if i==7:
 | |
| 					file.write('\n		')
 | |
| 					i=0
 | |
| 				file.write(',%.6f,%.6f,%.6f'% tuple(v.co))
 | |
| 			i+=1
 | |
| 		file.write('\n\t\tPolygonVertexIndex: ')
 | |
| 		i=-1
 | |
| 		for f in me.faces:
 | |
| 			fi = [v.index for v in f]
 | |
| 			# flip the last index, odd but it looks like
 | |
| 			# this is how fbx tells one face from another
 | |
| 			fi[-1] = -(fi[-1]+1)
 | |
| 			fi = tuple(fi)
 | |
| 			if i==-1:
 | |
| 				if len(f) == 3:		file.write('%i,%i,%i' % fi )
 | |
| 				else:				file.write('%i,%i,%i,%i' % fi )
 | |
| 				i=0
 | |
| 			else:
 | |
| 				if i==13:
 | |
| 					file.write('\n		')
 | |
| 					i=0
 | |
| 				if len(f) == 3:		file.write(',%i,%i,%i' % fi )
 | |
| 				else:				file.write(',%i,%i,%i,%i' % fi )
 | |
| 			i+=1
 | |
| 		
 | |
| 		file.write('\n\t\tGeometryVersion: 124')
 | |
| 		
 | |
| 		file.write('''
 | |
| 		LayerElementNormal: 0 {
 | |
| 			Version: 101
 | |
| 			Name: ""
 | |
| 			MappingInformationType: "ByVertice"
 | |
| 			ReferenceInformationType: "Direct"
 | |
| 			Normals: ''')
 | |
| 
 | |
| 		i=-1
 | |
| 		for v in me.verts:
 | |
| 			if i==-1:
 | |
| 				file.write('%.15f,%.15f,%.15f' % tuple(v.no))
 | |
| 				i=0
 | |
| 			else:
 | |
| 				if i==2:
 | |
| 					file.write('\n			 ')
 | |
| 					i=0
 | |
| 				file.write(',%.15f,%.15f,%.15f' % tuple(v.no))
 | |
| 			i+=1
 | |
| 		file.write('\n\t\t}')
 | |
| 		
 | |
| 		
 | |
| 
 | |
| 		
 | |
| 		# Write VertexColor Layers
 | |
| 		collayers = []
 | |
| 		if me.vertexColors:
 | |
| 			collayers = me.getColorLayerNames()
 | |
| 			collayer_orig = me.activeColorLayer
 | |
| 			for colindex, collayer in enumerate(collayers):
 | |
| 				me.activeColorLayer = collayer
 | |
| 				file.write('\n\t\tLayerElementColor: %i {' % colindex)
 | |
| 				file.write('\n\t\t\tVersion: 101')
 | |
| 				file.write('\n\t\t\tName: "%s"' % collayer)
 | |
| 				
 | |
| 				file.write('''
 | |
| 			MappingInformationType: "ByPolygonVertex"
 | |
| 			ReferenceInformationType: "IndexToDirect"
 | |
| 			Colors: ''')
 | |
| 			
 | |
| 				i = -1
 | |
| 				ii = 0 # Count how many Colors we write
 | |
| 				
 | |
| 				for f in me.faces:
 | |
| 					for col in f.col:
 | |
| 						if i==-1:
 | |
| 							file.write('%i,%i,%i' % (col[0], col[1], col[2]))
 | |
| 							i=0
 | |
| 						else:
 | |
| 							if i==7:
 | |
| 								file.write('\n			 ')
 | |
| 								i=0
 | |
| 							file.write(',%i,%i,%i' % (col[0], col[1], col[2]))
 | |
| 						i+=1
 | |
| 						ii+=1 # One more Color
 | |
| 				
 | |
| 				file.write('\n\t\t\tColorIndex: ')
 | |
| 				i = -1
 | |
| 				for j in xrange(ii):
 | |
| 					if i == -1:
 | |
| 						file.write('%i' % j)
 | |
| 						i=0
 | |
| 					else:
 | |
| 						if i==55:
 | |
| 							file.write('\n			 ')
 | |
| 							i=0
 | |
| 						file.write(',%i' % j)
 | |
| 					i+=1
 | |
| 				
 | |
| 				file.write('\n\t\t}')
 | |
| 		
 | |
| 		
 | |
| 		
 | |
| 		
 | |
| 		
 | |
| 		
 | |
| 		# Write UV and texture layers.
 | |
| 		uvlayers = []
 | |
| 		if me.faceUV:
 | |
| 			uvlayers = me.getUVLayerNames()
 | |
| 			uvlayer_orig = me.activeUVLayer
 | |
| 			for uvindex, uvlayer in enumerate(uvlayers):
 | |
| 				me.activeUVLayer = uvlayer
 | |
| 				file.write('\n\t\tLayerElementUV: %i {' % uvindex)
 | |
| 				file.write('\n\t\t\tVersion: 101')
 | |
| 				file.write('\n\t\t\tName: "%s"' % uvlayer)
 | |
| 				
 | |
| 				file.write('''
 | |
| 			MappingInformationType: "ByPolygonVertex"
 | |
| 			ReferenceInformationType: "IndexToDirect"
 | |
| 			UV: ''')
 | |
| 			
 | |
| 				i = -1
 | |
| 				ii = 0 # Count how many UVs we write
 | |
| 				
 | |
| 				for f in me.faces:
 | |
| 					for uv in f.uv:
 | |
| 						if i==-1:
 | |
| 							file.write('%.6f,%.6f' % tuple(uv))
 | |
| 							i=0
 | |
| 						else:
 | |
| 							if i==7:
 | |
| 								file.write('\n			 ')
 | |
| 								i=0
 | |
| 							file.write(',%.6f,%.6f' % tuple(uv))
 | |
| 						i+=1
 | |
| 						ii+=1 # One more UV
 | |
| 				
 | |
| 				file.write('\n\t\t\tUVIndex: ')
 | |
| 				i = -1
 | |
| 				for j in xrange(ii):
 | |
| 					if i == -1:
 | |
| 						file.write('%i'  % j)
 | |
| 						i=0
 | |
| 					else:
 | |
| 						if i==55:
 | |
| 							file.write('\n\t\t\t\t')
 | |
| 							i=0
 | |
| 						file.write(',%i' % j)
 | |
| 					i+=1
 | |
| 				
 | |
| 				file.write('\n\t\t}')
 | |
| 				
 | |
| 				if textures:
 | |
| 					file.write('\n\t\tLayerElementTexture: %i {' % uvindex)
 | |
| 					file.write('\n\t\t\tVersion: 101')
 | |
| 					file.write('\n\t\t\tName: "%s"' % uvlayer)
 | |
| 					
 | |
| 					file.write('''
 | |
| 			MappingInformationType: "ByPolygon"
 | |
| 			ReferenceInformationType: "IndexToDirect"
 | |
| 			BlendMode: "Translucent"
 | |
| 			TextureAlpha: 1
 | |
| 			TextureId: ''')
 | |
| 					i=-1
 | |
| 					for f in me.faces:
 | |
| 						img_key = f.image
 | |
| 						if img_key: img_key = img_key.name
 | |
| 						
 | |
| 						if i==-1:
 | |
| 							i=0
 | |
| 							file.write( '%s' % texture_mapping_local[img_key])
 | |
| 						else:
 | |
| 							if i==55:
 | |
| 								file.write('\n			 ')
 | |
| 								i=0
 | |
| 							
 | |
| 							file.write(',%s' % texture_mapping_local[img_key])
 | |
| 						i+=1
 | |
| 				else:
 | |
| 					file.write('''
 | |
| 		LayerElementTexture: 0 {
 | |
| 			Version: 101
 | |
| 			Name: ""
 | |
| 			MappingInformationType: "NoMappingInformation"
 | |
| 			ReferenceInformationType: "IndexToDirect"
 | |
| 			BlendMode: "Translucent"
 | |
| 			TextureAlpha: 1
 | |
| 			TextureId: ''')
 | |
| 				file.write('\n\t\t}')
 | |
| 			
 | |
| 			me.activeUVLayer = uvlayer_orig
 | |
| 			
 | |
| 		# Done with UV/textures.
 | |
| 		
 | |
| 		if materials:
 | |
| 			file.write('''
 | |
| 		LayerElementMaterial: 0 {
 | |
| 			Version: 101
 | |
| 			Name: ""
 | |
| 			MappingInformationType: "ByPolygon"
 | |
| 			ReferenceInformationType: "IndexToDirect"
 | |
| 			Materials: ''')
 | |
| 			
 | |
| 			# Build a material mapping for this 
 | |
| 			material_mapping_local = {} # local-index : global index.
 | |
| 			for i, mat in enumerate(mats):
 | |
| 				if mat:
 | |
| 					material_mapping_local[i] = material_mapping[mat.name]
 | |
| 				else:
 | |
| 					material_mapping_local[i] = 0 # None material is zero for now.
 | |
| 			
 | |
| 			if not material_mapping_local:
 | |
| 				material_mapping_local[0] = 0
 | |
| 			
 | |
| 			len_material_mapping_local = len(material_mapping_local)
 | |
| 			
 | |
| 			i=-1
 | |
| 			for f in me.faces:
 | |
| 				if i==-1:
 | |
| 					i=0
 | |
| 					f_mat = f.mat
 | |
| 					if f_mat >= len_material_mapping_local:
 | |
| 						f_mat = 0
 | |
| 					
 | |
| 					file.write( '%s' % material_mapping_local[f_mat])
 | |
| 				else:
 | |
| 					if i==55:
 | |
| 						file.write('\n			 ')
 | |
| 						i=0
 | |
| 					
 | |
| 					file.write(',%s' % material_mapping_local[f_mat])
 | |
| 				i+=1
 | |
| 			
 | |
| 			file.write('\n		}')
 | |
| 		
 | |
| 		
 | |
| 		
 | |
| 		file.write('''
 | |
| 		Layer: 0 {
 | |
| 			Version: 100
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementNormal"
 | |
| 				TypedIndex: 0
 | |
| 			}''')
 | |
| 		
 | |
| 		if materials:
 | |
| 			file.write('''
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementMaterial"
 | |
| 				TypedIndex: 0
 | |
| 			}''')
 | |
| 			
 | |
| 		# Always write this
 | |
| 		if textures:
 | |
| 			file.write('''
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementTexture"
 | |
| 				TypedIndex: 0
 | |
| 			}''')
 | |
| 		
 | |
| 		if me.vertexColors:
 | |
| 			file.write('''
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementColor"
 | |
| 				TypedIndex: 0
 | |
| 			}''')
 | |
| 		
 | |
| 		if me.faceUV:
 | |
| 			file.write('''
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementUV"
 | |
| 				TypedIndex: 0
 | |
| 			}''')
 | |
| 		
 | |
| 		
 | |
| 		file.write('\n\t\t}')
 | |
| 		
 | |
| 		if len(uvlayers) > 1:
 | |
| 			for i in xrange(1, len(uvlayers)):
 | |
| 				
 | |
| 				file.write('\n\t\tLayer: %i {' % i)
 | |
| 				file.write('\n\t\t\tVersion: 100')
 | |
| 				
 | |
| 				file.write('''
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementUV"''')
 | |
| 				
 | |
| 				file.write('\n\t\t\t\tTypedIndex: %i' % i)
 | |
| 				file.write('\n\t\t\t}')
 | |
| 				
 | |
| 				if textures:
 | |
| 					
 | |
| 					file.write('''
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementTexture"''')
 | |
| 					
 | |
| 					file.write('\n\t\t\t\tTypedIndex: %i' % i)
 | |
| 					file.write('\n\t\t\t}')
 | |
| 				
 | |
| 				file.write('\n\t\t}')
 | |
| 		
 | |
| 		if len(collayers) > 1:
 | |
| 			# Take into account any UV layers
 | |
| 			layer_offset = 0
 | |
| 			if uvlayers: layer_offset = len(uvlayers)-1
 | |
| 			
 | |
| 			for i in xrange(layer_offset, len(collayers)+layer_offset):
 | |
| 				file.write('\n\t\tLayer: %i {' % i)
 | |
| 				file.write('\n\t\t\tVersion: 100')
 | |
| 				
 | |
| 				file.write('''
 | |
| 			LayerElement:  {
 | |
| 				Type: "LayerElementColor"''')
 | |
| 				
 | |
| 				file.write('\n\t\t\t\tTypedIndex: %i' % i)
 | |
| 				file.write('\n\t\t\t}')
 | |
| 				file.write('\n\t\t}')
 | |
| 		file.write('\n\t}')	
 | |
| 	
 | |
| 	
 | |
| 	write_camera_default()
 | |
| 	
 | |
| 	for matname, mat in materials:
 | |
| 		write_material(matname, mat)
 | |
| 	
 | |
| 	# each texture uses a video, odd
 | |
| 	for texname, tex in textures:
 | |
| 		write_video(texname, tex)
 | |
| 	i = 0
 | |
| 	for texname, tex in textures:
 | |
| 		write_texture(texname, tex, i)
 | |
| 		i+=1
 | |
| 	
 | |
| 	
 | |
| 	# Finish Writing Objects
 | |
| 	# Write global settings
 | |
| 	file.write('''
 | |
| 	GlobalSettings:  {
 | |
| 		Version: 1000
 | |
| 		Properties60:  {
 | |
| 			Property: "UpAxis", "int", "",1
 | |
| 			Property: "UpAxisSign", "int", "",1
 | |
| 			Property: "FrontAxis", "int", "",2
 | |
| 			Property: "FrontAxisSign", "int", "",1
 | |
| 			Property: "CoordAxis", "int", "",0
 | |
| 			Property: "CoordAxisSign", "int", "",1
 | |
| 			Property: "UnitScaleFactor", "double", "",1
 | |
| 		}
 | |
| 	}
 | |
| ''')	
 | |
| 	file.write('}\n\n')
 | |
| 	
 | |
| 	file.write(\
 | |
| '''; Object relations
 | |
| ;------------------------------------------------------------------
 | |
| 
 | |
| Relations:  {
 | |
| ''')
 | |
| 
 | |
| 	file.write('\tModel: "Model::blend_root", "Null" {\n\t}\n')
 | |
| 	
 | |
| 	for obname, ob, me, mats, arm, armname in objects:
 | |
| 		file.write('\tModel: "Model::%s", "Mesh" {\n\t}\n' % obname)
 | |
| 	
 | |
| 	file.write('''	Model: "Model::Producer Perspective", "Camera" {
 | |
| 	}
 | |
| 	Model: "Model::Producer Top", "Camera" {
 | |
| 	}
 | |
| 	Model: "Model::Producer Bottom", "Camera" {
 | |
| 	}
 | |
| 	Model: "Model::Producer Front", "Camera" {
 | |
| 	}
 | |
| 	Model: "Model::Producer Back", "Camera" {
 | |
| 	}
 | |
| 	Model: "Model::Producer Right", "Camera" {
 | |
| 	}
 | |
| 	Model: "Model::Producer Left", "Camera" {
 | |
| 	}
 | |
| 	Model: "Model::Camera Switcher", "CameraSwitcher" {
 | |
| 	}
 | |
| ''')
 | |
| 	
 | |
| 	for matname, mat in materials:
 | |
| 		file.write('\tMaterial: "Material::%s", "" {\n\t}\n' % matname)
 | |
| 
 | |
| 	if textures:
 | |
| 		for texname, tex in textures:
 | |
| 			file.write('\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}\n' % texname)
 | |
| 		for texname, tex in textures:
 | |
| 			file.write('\tVideo: "Video::%s", "Clip" {\n\t}\n' % texname)		
 | |
| 
 | |
| 	file.write('}\n')
 | |
| 	file.write(\
 | |
| '''
 | |
| ; Object connections
 | |
| ;------------------------------------------------------------------
 | |
| 
 | |
| Connections:  {
 | |
| ''')
 | |
| 
 | |
| 	# write the fake root node
 | |
| 	file.write('\tConnect: "OO", "Model::blend_root", "Model::Scene"\n')
 | |
| 	
 | |
| 	for obname, ob, me, mats, arm, armname in objects:
 | |
| 		file.write('\tConnect: "OO", "Model::%s", "Model::blend_root"\n' % obname)
 | |
| 	
 | |
| 	for obname, ob, me, mats, arm, armname in objects:
 | |
| 		# Connect all materials to all objects, not good form but ok for now.
 | |
| 		for mat in mats:
 | |
| 			file.write('	Connect: "OO", "Material::%s", "Model::%s"\n' % (sane_matname(mat), obname))
 | |
| 	
 | |
| 	if textures:
 | |
| 		for obname, ob, me, mats, arm, armname in objects:
 | |
| 			for texname, tex in textures:
 | |
| 				file.write('\tConnect: "OO", "Texture::%s", "Model::%s"\n' % (texname, obname))
 | |
| 		
 | |
| 		for texname, tex in textures:
 | |
| 			file.write('\tConnect: "OO", "Video::%s", "Texture::%s"\n' % (texname, texname))
 | |
| 	
 | |
| 	file.write('}\n')
 | |
| 	
 | |
| 	
 | |
| 	# Clear mesh data Only when writing with modifiers applied
 | |
| 	#for obname, ob, me, mats, arm, armname in objects:
 | |
| 	#	me.verts = None
 | |
| 
 | |
| 
 | |
| def write_footer(file, sce, world):
 | |
| 	
 | |
| 	tuple(world.hor)
 | |
| 	tuple(world.amb)
 | |
| 	
 | |
| 	has_mist = world.mode & 1
 | |
| 	
 | |
| 	mist_intense, mist_start, mist_end, mist_height = world.mist
 | |
| 	
 | |
| 	render = sce.getRenderingContext() # NEWAPY sce.render
 | |
| 	
 | |
| 	file.write(';Takes and animation section\n')
 | |
| 	file.write(';----------------------------------------------------\n')
 | |
| 	file.write('\n')
 | |
| 	file.write('Takes:  {\n')
 | |
| 	file.write('	Current: ""\n')
 | |
| 	file.write('}\n')
 | |
| 	file.write(';Version 5 settings\n')
 | |
| 	file.write(';------------------------------------------------------------------\n')
 | |
| 	file.write('\n')
 | |
| 	file.write('Version5:  {\n')
 | |
| 	file.write('\tAmbientRenderSettings:  {\n')
 | |
| 	file.write('\t\tVersion: 101\n')
 | |
| 	file.write('\t\tAmbientLightColor: %.1f,%.1f,%.1f,0\n' % tuple(world.amb))
 | |
| 	file.write('\t}\n')
 | |
| 	file.write('\tFogOptions:  {\n')
 | |
| 	file.write('\t\tFlogEnable: %i\n' % has_mist)
 | |
| 	file.write('\t\tFogMode: 0\n')
 | |
| 	file.write('\t\tFogDensity: %.3f\n' % mist_intense)
 | |
| 	file.write('\t\tFogStart: %.3f\n' % mist_start)
 | |
| 	file.write('\t\tFogEnd: %.3f\n' % mist_end)
 | |
| 	file.write('\t\tFogColor: %.1f,%.1f,%.1f,1\n' % tuple(world.hor))
 | |
| 	file.write('\t}\n')
 | |
| 	file.write('\tSettings:  {\n')
 | |
| 	file.write('\t\tFrameRate: "%i"\n' % render.fps)
 | |
| 	file.write('\t\tTimeFormat: 1\n')
 | |
| 	file.write('\t\tSnapOnFrames: 0\n')
 | |
| 	file.write('\t\tReferenceTimeIndex: -1\n')
 | |
| 	file.write('\t\tTimeLineStartTime: %i\n' % render.sFrame)
 | |
| 	file.write('\t\tTimeLineStopTime: %i\n' % render.eFrame)
 | |
| 	file.write('\t}\n')
 | |
| 	file.write('\tRendererSetting:  {\n')
 | |
| 	file.write('\t\tDefaultCamera: "Producer Perspective"\n')
 | |
| 	file.write('\t\tDefaultViewingMode: 0\n')
 | |
| 	file.write('\t}\n')
 | |
| 	file.write('}\n')
 | |
| 
 | |
| def write_ui(filename):
 | |
| 	if not BPyMessages.Warning_SaveOver(filename):
 | |
| 		return
 | |
| 	sce = Blender.Scene.GetCurrent() # NEWAPI bpy.data.scenes.active
 | |
| 	world = Blender.World.GetCurrent() # NEWAPI sce.world
 | |
| 	
 | |
| 	Blender.Window.WaitCursor(1)
 | |
| 	file = open(filename, 'w')
 | |
| 	write_header(file)
 | |
| 	write_scene(file, sce, world)
 | |
| 	write_footer(file, sce, world)
 | |
| 	Blender.Window.WaitCursor(0)
 | |
| 
 | |
| if __name__ == '__main__':
 | |
| 	Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx'))
 |