From 69787af02dc3e8c54ed02ca4a758c916f7faa72c Mon Sep 17 00:00:00 2001 From: cutealien Date: Sun, 18 Mar 2018 15:11:26 +0000 Subject: [PATCH] Add B3DExporter script for Blender from SuperTuxKart. It is copied from here: https://sourceforge.net/p/supertuxkart/code/17112/tree/media/trunk/blender_25/B3DExport.py Reason is that STK uses now different scripts and this one was getting hard to find for users (that was the last version before they removed it). It's GPL licensed, but not combined with rest of library, so no problem for us. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5604 dfc29bdd-3216-0410-991c-e03cc46cb475 --- tools/Exporters/Blender/B3DExport.py | 1611 ++++++++++++++++++++++++++ 1 file changed, 1611 insertions(+) create mode 100644 tools/Exporters/Blender/B3DExport.py diff --git a/tools/Exporters/Blender/B3DExport.py b/tools/Exporters/Blender/B3DExport.py new file mode 100644 index 00000000..025b64eb --- /dev/null +++ b/tools/Exporters/Blender/B3DExport.py @@ -0,0 +1,1611 @@ +#!BPY + +""" +Name: 'B3D Exporter (.b3d)...' +Blender: 259 +Group: 'Export' +Tooltip: 'Export to Blitz3D file format (.b3d)' +""" +__author__ = ["iego 'GaNDaLDF' Parisi, MTLZ (is06), Joerg Henrichs, Marianne Gagnon"] +__url__ = ["www.gandaldf.com"] +__version__ = "3.0" +__bpydoc__ = """\ +""" + +# BLITZ3D EXPORTER 3.0 +# Copyright (C) 2009 by Diego "GaNDaLDF" Parisi - www.gandaldf.com +# Lightmap issue fixed by Capricorn 76 Pty. Ltd. - www.capricorn76.com +# Blender 2.63 compatiblity based on work by MTLZ, www.is06.com +# With changes by Marianne Gagnon, Joerg Henrichs and Vincent Lejeune, supertuxkart.sf.net (Copyright (C) 2011-2012) +# +# LICENSE: +# 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 + +bl_info = { + "name": "B3D (BLITZ3D) Model Exporter", + "description": "Exports a blender scene or object to the B3D (BLITZ3D) format", + "author": "Diego 'GaNDaLDF' Parisi, MTLZ (is06), Joerg Henrichs, Marianne Gagnon, Vincent Lejeune", + "version": (3,1), + "blender": (2, 5, 9), + "api": 31236, + "location": "File > Export", + "warning": '', # used for warning icon and text in addons panel + "wiki_url": "http://supertuxkart.sourceforge.net/Get_involved", + "tracker_url": "https://sourceforge.net/apps/trac/supertuxkart/", + "category": "Import-Export"} + + +import bpy +import sys,os,os.path,struct,math,string +import mathutils +import math + +if not hasattr(sys,"argv"): sys.argv = ["???"] + + +#Global Stacks +b3d_parameters = {} +texture_flags = [] +texs_stack = {} +brus_stack = [] +vertex_groups = [] +bone_stack = {} +keys_stack = [] + +texture_count = 0 + +# bone_stack indices constants +BONE_PARENT_MATRIX = 0 +BONE_PARENT = 1 +BONE_ITSELF = 2 + +# texture stack indices constants +TEXTURE_ID = 0 +TEXTURE_FLAGS = 1 + +per_face_vertices = {} + +the_scene = None + +#Transformation Matrix +TRANS_MATRIX = mathutils.Matrix([[1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) +BONE_TRANS_MATRIX = mathutils.Matrix([[-1,0,0,0],[0,0,-1,0],[0,-1,0,0],[0,0,0,1]]) + +DEBUG = False +PROGRESS = True +PROGRESS_VERBOSE = False + +tesselated_objects = {} + +#Support Functions +def write_int(value): + return struct.pack(" 48: + value = encoded[0:48] + binary_format = "<%ds"%(len(encoded)+1) + return struct.pack(binary_format, encoded) + +def write_chunk(name,value): + dummy = bytearray() + return dummy + name + write_int(len(value)) + value + +trimmed_paths = {} + +def getArmatureAnimationEnd(armature): + end_frame = 1 + if armature.animation_data.action: + ipo = armature.animation_data.action.fcurves + for curve in ipo: + if "pose" in curve.data_path: + end_frame = max(end_frame, curve.keyframe_points[-1].co[0]) + + for nla_track in armature.animation_data.nla_tracks: + if len(nla_track.strips) > 0: + end_frame = max(end_frame, nla_track.strips[-1].frame_end) + + return end_frame + +# ==== Write B3D File ==== +# (main exporter function) +def write_b3d_file(filename, objects=[]): + global texture_flags, texs_stack, trimmed_paths, tesselated_objects + global brus_stack, vertex_groups, bone_stack, keys_stack + + #Global Stacks + texture_flags = [] + texs_stack = {} + brus_stack = [] + vertex_groups = [] + bone_stack = [] + keys_stack = [] + trimmed_paths = {} + file_buf = bytearray() + temp_buf = bytearray() + tesselated_objects = {} + + import time + start = time.time() + + temp_buf += write_int(1) #Version + temp_buf += write_texs(objects) #TEXS + temp_buf += write_brus(objects) #BRUS + temp_buf += write_node(objects) #NODE + + if len(temp_buf) > 0: + file_buf += write_chunk(b"BB3D",temp_buf) + temp_buf = "" + + file = open(filename,'wb') + file.write(file_buf) + file.close() + + # free memory + trimmed_paths = {} + + end = time.time() + + print("Exported in", (end - start)) + + +def tesselate_if_needed(objdata): + if objdata not in tesselated_objects: + objdata.calc_tessface() + tesselated_objects[objdata] = True + return objdata + +def getUVTextures(obj_data): + # BMesh in blender 2.63 broke this + if bpy.app.version[1] >= 63: + return tesselate_if_needed(obj_data).tessface_uv_textures + else: + return obj_data.uv_textures + +def getFaces(obj_data): + # BMesh in blender 2.63 broke this + if bpy.app.version[1] >= 63: + return tesselate_if_needed(obj_data).tessfaces + else: + return obj_data.faces + +def getVertexColors(obj_data): + # BMesh in blender 2.63 broke this + if bpy.app.version[1] >= 63: + return tesselate_if_needed(obj_data).tessface_vertex_colors + else: + return obj_data.vertex_colors + +# ==== Write TEXS Chunk ==== +def write_texs(objects=[]): + global b3d_parameters + global trimmed_paths + global texture_count + texs_buf = bytearray() + temp_buf = bytearray() + layer_max = 0 + obj_count = 0 + set_wrote = 0 + + if objects: + exp_obj = objects + else: + if b3d_parameters.get("export-selected"): + exp_obj = [ob for ob in bpy.data.objects if ob.select] + else: + exp_obj = bpy.data.objects + + if PROGRESS: print(len(exp_obj),"TEXS") + + if PROGRESS_VERBOSE: progress = 0 + + for obj in exp_obj: + + if PROGRESS_VERBOSE: + progress = progress + 1 + if (progress % 10 == 0): print("TEXS",progress,"/",len(exp_obj)) + + if obj.type == "MESH": + set_count = 0 + set_wrote = 0 + #data = obj.getData(mesh = True) + data = obj.data + + # FIXME? + #orig_uvlayer = data.activeUVLayer + + layer_set = [[],[],[],[],[],[],[],[]] + + # 8 UV layers are supported + texture_flags.append([None,None,None,None,None,None,None,None]) + + #if len(data.getUVLayerNames()) <= 8: + uv_textures = getUVTextures(data) + if len(uv_textures) <= 8: + if len(uv_textures) > layer_max: + layer_max = len(uv_textures) + else: + layer_max = 8 + + for face in getFaces(data): + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + # FIXME? + #data.activeUVLayer = uvlayer + + #layer_set[iuvlayer].append(face.uv) + new_data = None + try: + new_data = uvlayer.data[face.index].uv + except: + pass + + layer_set[iuvlayer].append( new_data ) + + for i in range(len(uv_textures)): + if set_wrote: + set_count += 1 + set_wrote = 0 + + for iuvlayer in range(i,len(uv_textures)): + if layer_set[i] == layer_set[iuvlayer]: + if texture_flags[obj_count][iuvlayer] is None: + if set_count == 0: + tex_flag = 1 + elif set_count == 1: + tex_flag = 65536 + elif set_count > 1: + tex_flag = 1 + if b3d_parameters.get("mipmap"): + enable_mipmaps=8 + else: + enable_mipmaps=0 + texture_flags[obj_count][iuvlayer] = tex_flag | enable_mipmaps + set_wrote = 1 + + for face in getFaces(data): + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + if not (iuvlayer < len(uv_textures)): + continue + + # FIXME? + #data.activeUVLayer = uvlayer + + #if DEBUG: print("") + + img = getUVTextures(data)[iuvlayer].data[face.index].image + + if img: + + if img.filepath in trimmed_paths: + img_name = trimmed_paths[img.filepath] + else: + img_name = bpy.path.basename(img.filepath) + trimmed_paths[img.filepath] = img_name + + if not img_name in texs_stack: + texs_stack[img_name] = [len(texs_stack), texture_flags[obj_count][iuvlayer]] + temp_buf += write_string(img_name) #Texture File Name + temp_buf += write_int(texture_flags[obj_count][iuvlayer]) #Flags + temp_buf += write_int(2) #Blend + temp_buf += write_float(0) #X_Pos + temp_buf += write_float(0) #Y_Pos + temp_buf += write_float(1) #X_Scale + temp_buf += write_float(1) #Y_Scale + temp_buf += write_float(0) #Rotation + #else: + # if DEBUG: print(" ") + + #if DEBUG: print("") + + obj_count += 1 + + #FIXME? + #if orig_uvlayer: + # data.activeUVLayer = orig_uvlayer + + texture_count = layer_max + + if len(temp_buf) > 0: + texs_buf += write_chunk(b"TEXS",temp_buf) + temp_buf = "" + + return texs_buf + +# ==== Write BRUS Chunk ==== +def write_brus(objects=[]): + global b3d_parameters + global trimmed_paths + global texture_count + brus_buf = bytearray() + temp_buf = bytearray() + mat_count = 0 + obj_count = 0 + + if DEBUG: print("") + + if objects: + exp_obj = objects + else: + if b3d_parameters.get("export-selected"): + exp_obj = [ob for ob in bpy.data.objects if ob.select] + else: + exp_obj = bpy.data.objects + + if PROGRESS: print(len(exp_obj),"BRUS") + if PROGRESS_VERBOSE: progress = 0 + + for obj in exp_obj: + + if PROGRESS_VERBOSE: + progress += 1 + if (progress % 10 == 0): print("BRUS",progress,"/",len(exp_obj)) + + if obj.type == "MESH": + data = obj.data + + uv_textures = getUVTextures(data) + + if len(uv_textures) <= 0: + continue + + if DEBUG: print("") + + img_found = 0 + + for face in getFaces(data): + + face_stack = [] + + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + img_id = -1 + + if face.index >= len(uv_textures[iuvlayer].data): + continue + + img = uv_textures[iuvlayer].data[face.index].image + + if not img: + continue + + img_found = 1 + + if img.filepath in trimmed_paths: + img_name = trimmed_paths[img.filepath] + else: + img_name = os.path.basename(img.filepath) + trimmed_paths[img.filepath] = img_name + + if DEBUG: print(" ") + + if img_name in texs_stack: + img_id = texs_stack[img_name][TEXTURE_ID] + + face_stack.insert(iuvlayer,img_id) + if DEBUG: print(" ") + + for i in range(len(face_stack),texture_count): + face_stack.append(-1) + + + if DEBUG: print(" ") + + if not img_found: + if data.materials: + if data.materials[face.material_index]: + mat_data = data.materials[face.material_index] + mat_colr = mat_data.diffuse_color[0] + mat_colg = mat_data.diffuse_color[1] + mat_colb = mat_data.diffuse_color[2] + mat_alpha = mat_data.alpha + mat_name = mat_data.name + + if not mat_name in brus_stack: + brus_stack.append(mat_name) + temp_buf += write_string(mat_name) #Brush Name + temp_buf += write_float(mat_colr) #Red + temp_buf += write_float(mat_colg) #Green + temp_buf += write_float(mat_colb) #Blue + temp_buf += write_float(mat_alpha) #Alpha + temp_buf += write_float(0) #Shininess + temp_buf += write_int(1) #Blend + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)): + temp_buf += write_int(2) #Fx + else: + temp_buf += write_int(0) #Fx + + for i in face_stack: + temp_buf += write_int(i) #Texture ID + else: + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + if not face_stack in brus_stack: + brus_stack.append(face_stack) + mat_count += 1 + temp_buf += write_string("Brush.%.3i"%mat_count) #Brush Name + temp_buf += write_float(1) #Red + temp_buf += write_float(1) #Green + temp_buf += write_float(1) #Blue + temp_buf += write_float(1) #Alpha + temp_buf += write_float(0) #Shininess + temp_buf += write_int(1) #Blend + temp_buf += write_int(2) #Fx + + for i in face_stack: + temp_buf += write_int(i) #Texture ID + else: # img_found + + if not face_stack in brus_stack: + brus_stack.append(face_stack) + mat_count += 1 + temp_buf += write_string("Brush.%.3i"%mat_count) #Brush Name + temp_buf += write_float(1) #Red + temp_buf += write_float(1) #Green + temp_buf += write_float(1) #Blue + temp_buf += write_float(1) #Alpha + temp_buf += write_float(0) #Shininess + temp_buf += write_int(1) #Blend + + if DEBUG: print(" ") + + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + temp_buf += write_int(2) #Fx + else: + temp_buf += write_int(0) #Fx + + for i in face_stack: + temp_buf += write_int(i) #Texture ID + if DEBUG: print(" ") + + if DEBUG: print(" ") + + if DEBUG: print("") + + if DEBUG: print("") + obj_count += 1 + + #FIXME? + #if orig_uvlayer: + # data.activeUVLayer = orig_uvlayer + + if len(temp_buf) > 0: + brus_buf += write_chunk(b"BRUS",write_int(texture_count) + temp_buf) #N Texs + temp_buf = "" + + return brus_buf + +# ==== Write NODE Chunk ==== +def write_node(objects=[]): + global bone_stack + global keys_stack + global b3d_parameters + global the_scene + + root_buf = [] + node_buf = [] + main_buf = bytearray() + temp_buf = [] + obj_count = 0 + amb_light = 0 + + num_mesh = 0 + num_ligs = 0 + num_cams = 0 + num_lorc = 0 + #exp_scn = Blender.Scene.GetCurrent() + #exp_scn = the_scene + #exp_con = exp_scn.getRenderingContext() + + #first_frame = Blender.Draw.Create(exp_con.startFrame()) + #last_frame = Blender.Draw.Create(exp_con.endFrame()) + #num_frames = last_frame.val - first_frame.val + first_frame = the_scene.frame_start + + if DEBUG: print("") + + if objects: + exp_obj = objects + else: + if b3d_parameters.get("export-selected"): + exp_obj = [ob for ob in bpy.data.objects if ob.select] + else: + exp_obj = bpy.data.objects + + for obj in exp_obj: + if obj.type == "MESH": + num_mesh += 1 + if obj.type == "CAMERA": + num_cams += 1 + if obj.type == "LAMP": + num_ligs += 1 + + if b3d_parameters.get("cameras"): + num_lorc += num_cams + + if b3d_parameters.get("lights"): + num_lorc += 1 + num_lorc += num_ligs + + if num_mesh + num_lorc > 1: + exp_root = 1 + else: + exp_root = 0 + + if exp_root: + root_buf.append(write_string("ROOT")) #Node Name + + root_buf.append(write_float_triplet(0, 0, 0)) #Position X,Y,Z + root_buf.append(write_float_triplet(1, 1, 1)) #Scale X, Y, Z + root_buf.append(write_float_quad(1, 0, 0, 0)) #Rotation W, X, Y, Z + + if PROGRESS: progress = 0 + + for obj in exp_obj: + + if PROGRESS: + progress += 1 + print("NODE:",progress,"/",len(exp_obj),obj.name) + + if obj.type == "MESH": + + if DEBUG: print(" ") + + bone_stack = {} + keys_stack = [] + + anim_data = None + + # check if this object has an armature modifier + for curr_mod in obj.modifiers: + if curr_mod.type == 'ARMATURE': + arm = curr_mod.object + if arm is not None: + anim_data = arm.animation_data + + # check if this object has an armature parent (second way to do armature animations in blender) + if anim_data is None: + if obj.parent: + if obj.parent.type == "ARMATURE": + arm = obj.parent + if arm.animation_data: + anim_data = arm.animation_data + + if anim_data: + matrix = mathutils.Matrix() + + temp_buf.append(write_string(obj.name)) #Node Name + + position = matrix.to_translation() + temp_buf.append(write_float_triplet(position[0], position[1], position[2])) #Position X, Y, Z + + scale = matrix.to_scale() + temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1])) #Scale X, Y, Z + + if DEBUG: print(" ") + + quat = matrix.to_quaternion() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y)) + else: + if b3d_parameters.get("local-space"): + matrix = TRANS_MATRIX.copy() + scale_matrix = mathutils.Matrix() + else: + matrix = obj.matrix_world*TRANS_MATRIX + scale_matrix = obj.matrix_world.copy() + + + if bpy.app.version[1] >= 62: + # blender 2.62 broke the API : Column-major access was changed to row-major access + tmp = mathutils.Vector([matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1]]) + matrix[0][1] = matrix[0][2] + matrix[1][1] = matrix[1][2] + matrix[2][1] = matrix[2][2] + matrix[3][1] = matrix[3][2] + + matrix[0][2] = tmp[0] + matrix[1][2] = tmp[1] + matrix[2][2] = tmp[2] + matrix[3][2] = tmp[3] + else: + tmp = mathutils.Vector(matrix[1]) + matrix[1] = matrix[2] + matrix[2] = tmp + + temp_buf.append(write_string(obj.name)) #Node Name + + #print("Matrix : ", matrix) + position = matrix.to_translation() + + temp_buf.append(write_float_triplet(position[0], position[2], position[1])) + + scale = scale_matrix.to_scale() + temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1])) + + quat = matrix.to_quaternion() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y)) + + if DEBUG: + print(" ",position[0],position[2],position[1],"") + print(" ",scale[0],scale[1],scale[2],"") + print(" ", quat.w, quat.x, quat.y, quat.z, "") + + if anim_data: + the_scene.frame_set(1,subframe=0.0) + + arm_matrix = arm.matrix_world + + if b3d_parameters.get("local-space"): + arm_matrix = mathutils.Matrix() + + def read_armature(arm_matrix,bone,parent = None): + if (parent and not bone.parent.name == parent.name): + return + + matrix = mathutils.Matrix(bone.matrix) + + if parent: + + #print("==== "+bone.name+" ====") + a = (bone.matrix_local) + + #print("A : [%.2f %.2f %.2f %.2f]" % (a[0][0], a[0][1], a[0][2], a[0][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (a[1][0], a[1][1], a[1][2], a[1][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (a[2][0], a[2][1], a[2][2], a[2][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (a[3][0], a[3][1], a[3][2], a[3][3])) + + b = (parent.matrix_local.inverted().to_4x4()) + + #print("B : [%.2f %.2f %.2f %.2f]" % (b[0][0], b[0][1], b[0][2], b[0][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (b[1][0], b[1][1], b[1][2], b[1][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (b[2][0], b[2][1], b[2][2], b[2][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (b[3][0], b[3][1], b[3][2], b[3][3])) + + par_matrix = b * a + + transform = mathutils.Matrix([[1,0,0,0],[0,0,-1,0],[0,-1,0,0],[0,0,0,1]]) + par_matrix = transform*par_matrix*transform + + # FIXME: that's ugly, find a clean way to change the matrix..... + if bpy.app.version[1] >= 62: + # blender 2.62 broke the API : Column-major access was changed to row-major access + # TODO: test me + par_matrix[1][3] = -par_matrix[1][3] + par_matrix[2][3] = -par_matrix[2][3] + else: + par_matrix[3][1] = -par_matrix[3][1] + par_matrix[3][2] = -par_matrix[3][2] + + #c = par_matrix + #print("With parent") + #print("C : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + else: + + #print("==== "+bone.name+" ====") + #print("Without parent") + + m = arm_matrix*bone.matrix_local + + #c = arm.matrix_world + #print("A : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + #c = bone.matrix_local + #print("B : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + par_matrix = m*mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) + + #c = par_matrix + #print("C : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + + bone_stack[bone.name] = [par_matrix,parent,bone] + + if bone.children: + for child in bone.children: read_armature(arm_matrix,child,bone) + + for bone in arm.data.bones.values(): + if not bone.parent: + read_armature(arm_matrix,bone) + + frame_count = first_frame + + last_frame = int(getArmatureAnimationEnd(arm)) + num_frames = last_frame - first_frame + + while frame_count <= last_frame: + + the_scene.frame_set(int(frame_count), subframe=0.0) + + if DEBUG: print(" ") + arm_pose = arm.pose + arm_matrix = arm.matrix_world + + transform = mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) + arm_matrix = transform*arm_matrix + #arm_quat = arm_matrix.to_quaternion() + #arm_quat.normalize() + + for bone_name in arm.data.bones.keys(): + #bone_matrix = mathutils.Matrix(arm_pose.bones[bone_name].poseMatrix) + bone_matrix = mathutils.Matrix(arm_pose.bones[bone_name].matrix) + + #print("(outer loop) bone_matrix for",bone_name,"=", bone_matrix) + + #print(bone_name,":",bone_matrix) + + #bone_matrix = bpy.data.scenes[0].objects[0].pose.bones['Bone'].matrix + + for ibone in bone_stack: + + bone = bone_stack[ibone] + + if bone[BONE_ITSELF].name == bone_name: + + if DEBUG: print(" ") + + # == 2.4 exporter == + #if bone_stack[ibone][1]: + # par_matrix = Blender.Mathutils.Matrix(arm_pose.bones[bone_stack[ibone][1].name].poseMatrix) + # bone_matrix *= par_matrix.invert() + #else: + # if b3d_parameters.get("local-space"): + # bone_matrix *= TRANS_MATRIX + # else: + # bone_matrix *= arm_matrix + #bone_loc = bone_matrix.translationPart() + #bone_rot = bone_matrix.rotationPart().toQuat() + #bone_rot.normalize() + #bone_sca = bone_matrix.scalePart() + #keys_stack.append([frame_count - first_frame.val+1,bone_name,bone_loc,bone_sca,bone_rot]) + + # if has parent + if bone[BONE_PARENT]: + par_matrix = mathutils.Matrix(arm_pose.bones[bone[BONE_PARENT].name].matrix) + bone_matrix = par_matrix.inverted()*bone_matrix + else: + if b3d_parameters.get("local-space"): + bone_matrix = bone_matrix*mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) + else: + + #if frame_count == 1: + # print("====",bone_name,"====") + # print("arm_matrix = ", arm_matrix) + # print("bone_matrix = ", bone_matrix) + + bone_matrix = arm_matrix*bone_matrix + + #if frame_count == 1: + # print("arm_matrix*bone_matrix", bone_matrix) + + + #print("bone_matrix =", bone_matrix) + + bone_sca = bone_matrix.to_scale() + bone_loc = bone_matrix.to_translation() + + # FIXME: silly tweaks to resemble the Blender 2.4 exporter output + if b3d_parameters.get("local-space"): + + bone_rot = bone_matrix.to_quaternion() + bone_rot.normalize() + + + if not bone[BONE_PARENT]: + tmp = bone_rot.z + bone_rot.z = bone_rot.y + bone_rot.y = tmp + + bone_rot.x = -bone_rot.x + else: + tmp = bone_loc.z + bone_loc.z = bone_loc.y + bone_loc.y = tmp + + else: + bone_rot = bone_matrix.to_quaternion() + bone_rot.normalize() + + # Sometimes to_quaternion exhibits precision issue with parent bone + # Use quaternion product instead of getting quaternion from the product. + #if not bone[BONE_PARENT]: + # bone_rot = arm_pose.bones[bone_name].matrix.to_quaternion() * arm_quat + # bone_rot.x = -bone_rot.x + # tmp = bone_rot.z + # bone_rot.z = bone_rot.y + # bone_rot.y = tmp + + keys_stack.append([frame_count - first_frame+1, bone_name, bone_loc, bone_sca, bone_rot]) + if DEBUG: print(" ", bone_loc, "") + if DEBUG: print(" ", bone_rot, "") + if DEBUG: print(" ", bone_sca, "") + if DEBUG: print(" ") + + frame_count += 1 + + if DEBUG: print(" ") + + #Blender.Set("curframe",0) + #Blender.Window.Redraw() + + temp_buf.append(write_node_mesh(obj,obj_count,anim_data,exp_root)) #NODE MESH + + if anim_data: + temp_buf.append(write_node_anim(num_frames)) #NODE ANIM + + for ibone in bone_stack: + if not bone_stack[ibone][BONE_PARENT]: + temp_buf.append(write_node_node(ibone)) #NODE NODE + + obj_count += 1 + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE",b"".join(temp_buf))) + temp_buf = [] + + if DEBUG: print(" ") + + if b3d_parameters.get("cameras"): + if obj.type == "CAMERA": + data = obj.data + matrix = obj.getMatrix("worldspace") + matrix *= TRANS_MATRIX + + if data.type == "ORTHO": + cam_type = 2 + cam_zoom = round(data.scale,4) + else: + cam_type = 1 + cam_zoom = round(data.lens,4) + + cam_near = round(data.clipStart,4) + cam_far = round(data.clipEnd,4) + + node_name = ("CAMS"+"\n%s"%obj.name+"\n%s"%cam_type+\ + "\n%s"%cam_zoom+"\n%s"%cam_near+"\n%s"%cam_far) + temp_buf.append(write_string(node_name)) #Node Name + + position = matrix.translation_part() + temp_buf.append(write_float_triplet(-position[0], position[1], position[2])) + + scale = matrix.scale_part() + temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2])) + + matrix *= mathutils.Matrix.Rotation(180,4,'Y') + quat = matrix.to_quat() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.y, -quat.z)) + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE",b"".join(temp_buf))) + temp_buf = [] + + if b3d_parameters.get("lights"): + if amb_light == 0: + data = Blender.World.GetCurrent() + + amb_light = 1 + amb_color = (int(data.amb[2]*255) |(int(data.amb[1]*255) << 8) | (int(data.amb[0]*255) << 16)) + + node_name = (b"AMBI"+"\n%s"%amb_color) + temp_buf.append(write_string(node_name)) #Node Name + + temp_buf.append(write_float_triplet(0, 0, 0)) #Position X, Y, Z + temp_buf.append(write_float_triplet(1, 1, 1)) #Scale X, Y, Z + temp_buf.append(write_float_quad(1, 0, 0, 0)) #Rotation W, X, Y, Z + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE",b"".join(temp_buf))) + temp_buf = [] + + if obj.type == "LAMP": + data = obj.getData() + matrix = obj.getMatrix("worldspace") + matrix *= TRANS_MATRIX + + if data.type == 0: + lig_type = 2 + elif data.type == 2: + lig_type = 3 + else: + lig_type = 1 + + lig_angle = round(data.spotSize,4) + lig_color = (int(data.b*255) |(int(data.g*255) << 8) | (int(data.r*255) << 16)) + lig_range = round(data.dist,4) + + node_name = ("LIGS"+"\n%s"%obj.name+"\n%s"%lig_type+\ + "\n%s"%lig_angle+"\n%s"%lig_color+"\n%s"%lig_range) + temp_buf.append(write_string(node_name)) #Node Name + + position = matrix.translation_part() + temp_buf.append(write_float_triplet(-position[0], position[1], position[2])) + if DEBUG: print(" ",-position[0],position[1],position[2],"") + + scale = matrix.scale_part() + temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2])) + + if DEBUG: print(" ",scale[0],scale[1],scale[2],"") + + matrix *= mathutils.Matrix.Rotation(180,4,'Y') + quat = matrix.toQuat() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.y, -quat.z)) + if DEBUG: print(" ", quat.w, quat.x, quat.y, quat.z, "") + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE","b".join(temp_buf))) + temp_buf = [] + + if len(node_buf) > 0: + if exp_root: + main_buf += write_chunk(b"NODE",b"".join(root_buf) + b"".join(node_buf)) + else: + main_buf += b"".join(node_buf) + + node_buf = [] + root_buf = [] + + if DEBUG: print("") + + return main_buf + +# ==== Write NODE MESH Chunk ==== +def write_node_mesh(obj,obj_count,arm_action,exp_root): + global vertex_groups + vertex_groups = [] + mesh_buf = bytearray() + temp_buf = bytearray() + + if arm_action: + data = obj.data + elif b3d_parameters.get("apply-modifiers"): + data = obj.to_mesh(the_scene, True, 'PREVIEW') # Apply modifiers + else: + data = obj.data + + temp_buf += write_int(-1) #Brush ID + temp_buf += write_node_mesh_vrts(obj, data, obj_count, arm_action, exp_root) #NODE MESH VRTS + temp_buf += write_node_mesh_tris(obj, data, obj_count, arm_action, exp_root) #NODE MESH TRIS + + if len(temp_buf) > 0: + mesh_buf += write_chunk(b"MESH",temp_buf) + temp_buf = "" + + return mesh_buf + +def build_vertex_groups(data): + for f in getFaces(data): + for v in f.vertices: + vertex_groups.append({}) + + +# ==== Write NODE MESH VRTS Chunk ==== +def write_node_mesh_vrts(obj, data, obj_count, arm_action, exp_root): + vrts_buf = bytearray() + temp_buf = [] + obj_flags = 0 + + #global time_in_a + #global time_in_b + #global time_in_b1 + #global time_in_b2 + #global time_in_b3 + #global time_in_b4 + + #data = obj.getData(mesh = True) + global the_scene + + # FIXME: port to 2.5 API? + #orig_uvlayer = data.activeUVLayer + + if b3d_parameters.get("vertex-normals"): + obj_flags += 1 + + #if b3d_parameters.get("vertex-colors") and data.getColorLayerNames(): + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + obj_flags += 2 + + temp_buf.append(write_int(obj_flags)) #Flags + #temp_buf += write_int(len(data.getUVLayerNames())) #UV Set + temp_buf.append(write_int(len(getUVTextures(data)))) #UV Set + temp_buf.append(write_int(2)) #UV Set Size + + # ---- Prepare the mesh "stack" + build_vertex_groups(data) + + # ---- Fill the mesh "stack" + if DEBUG: print("") + if DEBUG: print(" \n") + + ivert = -1 + + + #if PROGRESS_VERBOSE: + # progress = 0 + # print(" vertex_groups, face:",0,"/",len(getFaces(data))) + + the_scene.frame_set(1,subframe=0.0) + + if b3d_parameters.get("local-space"): + mesh_matrix = mathutils.Matrix() + else: + mesh_matrix = obj.matrix_world.copy() + + #import time + + uvdata = getUVTextures(data) + uv_layers_count = len(uvdata) + uv_textures = {} + weldable_vertices = {} + vertex_id_mapping = {} + for face in getFaces(data): + for vertex_index,vert in enumerate(face.vertices): + #for id,vert in enumerate(data.vertices): + + if vert not in uv_textures: + uv_textures[vert] = {} + if face not in uv_textures[vert]: + uv_textures[vert][face] = {} + + for iuvlayer in range(uv_layers_count): + if vertex_index == 0: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv1 + elif vertex_index == 1: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv2 + elif vertex_index == 2: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv3 + elif vertex_index == 3: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv4 + + for idVertex, vertexFaces in uv_textures.items(): + is_weldable = True + + for iuvlayer in range(uv_layers_count): + u = None + v = None + for idFace, face in vertexFaces.items(): + if iuvlayer not in face: + continue + faceuvlayer = face[iuvlayer] + if u is None: + u = round(faceuvlayer[0]*1000) + v = round(faceuvlayer[1]*1000) + else: + if round(faceuvlayer[0] * 1000) != u or round(faceuvlayer[1]*1000) != v: + is_weldable = False + break + if not is_weldable: + break + + weldable_vertices[idVertex] = is_weldable + + + #print('uv_textures', uv_textures) + #print('weldable_vertices', weldable_vertices) + + for face in getFaces(data): + + if DEBUG: print(" ") + + #if PROGRESS_VERBOSE: + # progress += 1 + # if (progress % 50 == 0): print(" vertex_groups, face:",progress,"/",len(data.faces)) + + per_face_vertices[face.index] = [] + + for vertex_id,vert in enumerate(face.vertices): + + if vert in weldable_vertices and weldable_vertices[vert] and vert in vertex_id_mapping: + per_face_vertices[face.index].append(vertex_id_mapping[vert]) + continue + + ivert += 1 + vertex_id_mapping[vert] = ivert + per_face_vertices[face.index].append(ivert) + + #a = time.time() + + if arm_action: + v = mesh_matrix * data.vertices[vert].co + vert_matrix = mathutils.Matrix.Translation(v) + else: + vert_matrix = mathutils.Matrix.Translation(data.vertices[vert].co) + + vert_matrix *= TRANS_MATRIX + vcoord = vert_matrix.to_translation() + + temp_buf.append(write_float_triplet(vcoord.x, vcoord.z, vcoord.y)) + + #b = time.time() + #time_in_a += b - a + + if b3d_parameters.get("vertex-normals"): + norm_matrix = mathutils.Matrix.Translation(data.vertices[vert].normal) + + if arm_action: + norm_matrix *= mesh_matrix + + norm_matrix *= TRANS_MATRIX + normal_vector = norm_matrix.to_translation() + + temp_buf.append(write_float_triplet(normal_vector.x, #NX + normal_vector.z, #NY + normal_vector.y)) #NZ + + #c = time.time() + #time_in_b += c - b + + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + vertex_colors = getVertexColors(data) + if vertex_id == 0: + vcolor = vertex_colors[0].data[face.index].color1 + elif vertex_id == 1: + vcolor = vertex_colors[0].data[face.index].color2 + elif vertex_id == 2: + vcolor = vertex_colors[0].data[face.index].color3 + elif vertex_id == 3: + vcolor = vertex_colors[0].data[face.index].color4 + + valpha = 1.0 + if (len(vertex_colors) > 1): + if vertex_id == 0: + valpha = vertex_colors[1].data[face.index].color1.r + elif vertex_id == 1: + valpha = vertex_colors[1].data[face.index].color2.r + elif vertex_id == 2: + valpha = vertex_colors[1].data[face.index].color3.r + elif vertex_id == 3: + valpha = vertex_colors[1].data[face.index].color4.r + + temp_buf.append(write_float_quad(vcolor.r, #R + vcolor.g, #G + vcolor.b, #B + valpha)) #A (FIXME?) + + #d = time.time() + #time_in_b1 += d - c + + for vg in obj.vertex_groups: + w = 0.0 + try: + w = vg.weight(vert) + except: + pass + vertex_groups[ivert][vg.name] = w + + #e = time.time() + #time_in_b2 += e - d + + for iuvlayer in range(uv_layers_count): + uv = [10, 10] + if vert in uv_textures: + vertex_uv = uv_textures[vert] + + if face in vertex_uv: + vertex_face_uv = vertex_uv[face] + + if iuvlayer in vertex_face_uv: + uv = vertex_face_uv[iuvlayer] + + temp_buf.append(write_float_couple(uv[0], 1-uv[1]) ) # U, V + + + + if DEBUG: print("") + + #c = time.time() + #time_in_b += c - b + #print("time_in_a = ",time_in_a) + #print("time_in_b = ",time_in_b) + #print("time_in_b1 = ", time_in_b1) + #print("time_in_b2 = ", time_in_b2) + #print("time_in_b3 = ", time_in_b3) + #print("time_in_b4 = ", time_in_b4) + + if len(temp_buf) > 0: + vrts_buf += write_chunk(b"VRTS",b"".join(temp_buf)) + temp_buf = [] + + return vrts_buf + +# ==== Write NODE MESH TRIS Chunk ==== +def write_node_mesh_tris(obj, data, obj_count,arm_action,exp_root): + + global texture_count + + #FIXME? + #orig_uvlayer = data.activeUVLayer + + # An dictoriary that maps all brush-ids to a list of faces + # using this brush. This helps to sort the triangles by + # brush, creating less mesh buffer in irrlicht. + dBrushId2Face = {} + + if DEBUG: print("") + + for face in getFaces(data): + img_found = 0 + face_stack = [] + + uv_textures = getUVTextures(data) + uv_layer_count = len(uv_textures) + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + if iuvlayer >= uv_layer_count: + continue + + img_id = -1 + + img = uv_textures[iuvlayer].data[face.index].image + if img: + + if img.filepath in trimmed_paths: + img_name = trimmed_paths[img.filepath] + else: + img_name = os.path.basename(img.filepath) + trimmed_paths[img.filepath] = img_name + + img_found = 1 + if img_name in texs_stack: + img_id = texs_stack[img_name][TEXTURE_ID] + + face_stack.insert(iuvlayer,img_id) + + for i in range(len(face_stack),texture_count): + face_stack.append(-1) + + if img_found == 0: + brus_id = -1 + if data.materials and data.materials[face.material_index]: + mat_name = data.materials[face.material_index].name + for i in range(len(brus_stack)): + if brus_stack[i] == mat_name: + brus_id = i + break + else: + for i in range(len(brus_stack)): + if brus_stack[i] == face_stack: + brus_id = i + break + else: + brus_id = -1 + for i in range(len(brus_stack)): + if brus_stack[i] == face_stack: + brus_id = i + break + if brus_id == -1: + print("Cannot find in brus stack : ", face_stack) + + if brus_id in dBrushId2Face: + dBrushId2Face[brus_id].append(face) + else: + dBrushId2Face[brus_id] = [face] + + if DEBUG: print(" ") + + tris_buf = bytearray() + + if DEBUG: print("") + if DEBUG: print(" ") + + if PROGRESS_VERBOSE: progress = 0 + + for brus_id in dBrushId2Face.keys(): + + if PROGRESS_VERBOSE: + progress += 1 + print("BRUS:",progress,"/",len(dBrushId2Face.keys())) + + temp_buf = [write_int(brus_id)] #Brush ID + + if DEBUG: print(" ") + + if PROGRESS_VERBOSE: progress2 = 0 + + for face in dBrushId2Face[brus_id]: + + if PROGRESS_VERBOSE: + progress2 += 1 + if (progress2 % 50 == 0): print(" TRIS:",progress2,"/",len(dBrushId2Face[brus_id])) + + vertices = per_face_vertices[face.index] + + temp_buf.append(write_int(vertices[2])) #A + temp_buf.append(write_int(vertices[1])) #B + temp_buf.append(write_int(vertices[0])) #C + + if DEBUG: print(" ") + + if len(face.vertices) == 4: + temp_buf.append(write_int(vertices[3])) #A + temp_buf.append(write_int(vertices[2])) #B + temp_buf.append(write_int(vertices[0])) #C + if DEBUG: print(" ") + + if DEBUG: print(" ") + tris_buf += write_chunk(b"TRIS", b"".join(temp_buf)) + + return tris_buf + +# ==== Write NODE ANIM Chunk ==== +def write_node_anim(num_frames): + anim_buf = bytearray() + temp_buf = bytearray() + + temp_buf += write_int(0) #Flags + temp_buf += write_int(num_frames) #Frames + temp_buf += write_float(60) #FPS + + if len(temp_buf) > 0: + anim_buf += write_chunk(b"ANIM",temp_buf) + temp_buf = "" + + return anim_buf + +# ==== Write NODE NODE Chunk ==== +def write_node_node(ibone): + node_buf = bytearray() + temp_buf = [] + + bone = bone_stack[ibone] + + matrix = bone[BONE_PARENT_MATRIX] + temp_buf.append(write_string(bone[BONE_ITSELF].name)) #Node Name + + + + # FIXME: we should use the same matrix format everywhere to not require this + + position = matrix.to_translation() + if bone[BONE_PARENT]: + temp_buf.append(write_float_triplet(-position[0], position[2], position[1])) + else: + temp_buf.append(write_float_triplet(position[0], position[2], position[1])) + + + scale = matrix.to_scale() + temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1])) + + quat = matrix.to_quaternion() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y)) + + temp_buf.append(write_node_bone(ibone)) + temp_buf.append(write_node_keys(ibone)) + + for iibone in bone_stack: + if bone_stack[iibone][BONE_PARENT] == bone_stack[ibone][BONE_ITSELF]: + temp_buf.append(write_node_node(iibone)) + + if len(temp_buf) > 0: + node_buf += write_chunk(b"NODE", b"".join(temp_buf)) + temp_buf = [] + + return node_buf + +# ==== Write NODE BONE Chunk ==== +def write_node_bone(ibone): + bone_buf = bytearray() + temp_buf = [] + + my_name = bone_stack[ibone][BONE_ITSELF].name + + for ivert in range(len(vertex_groups)): + if my_name in vertex_groups[ivert]: + vert_influ = vertex_groups[ivert][my_name] + #if DEBUG: print(" ") + temp_buf.append(write_int(ivert)) # Face Vertex ID + temp_buf.append(write_float(vert_influ)) #Weight + + bone_buf += write_chunk(b"BONE", b"".join(temp_buf)) + temp_buf = [] + + return bone_buf + +# ==== Write NODE KEYS Chunk ==== +def write_node_keys(ibone): + keys_buf = bytearray() + temp_buf = [] + + temp_buf.append(write_int(7)) #Flags + + my_name = bone_stack[ibone][BONE_ITSELF].name + + for ikeys in range(len(keys_stack)): + if keys_stack[ikeys][1] == my_name: + temp_buf.append(write_int(keys_stack[ikeys][0])) #Frame + + position = keys_stack[ikeys][2] + # FIXME: we should use the same matrix format everywhere and not require this + if b3d_parameters.get("local-space"): + if bone_stack[ibone][BONE_PARENT]: + temp_buf.append(write_float_triplet(-position[0], position[2], position[1])) + else: + temp_buf.append(write_float_triplet(position[0], position[2], position[1])) + else: + temp_buf.append(write_float_triplet(-position[0], position[1], position[2])) + + scale = keys_stack[ikeys][3] + temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2])) + + quat = keys_stack[ikeys][4] + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, -quat.x, quat.y, quat.z)) + #break + + keys_buf += write_chunk(b"KEYS",b"".join(temp_buf)) + temp_buf = [] + + return keys_buf + + +# ==== CONFIRM OPERATOR ==== +class B3D_Confirm_Operator(bpy.types.Operator): + bl_idname = ("screen.b3d_confirm") + bl_label = ("File Exists, Overwrite?") + + def invoke(self, context, event): + wm = context.window_manager + return wm.invoke_props_dialog(self) + + def execute(self, context): + write_b3d_file(B3D_Confirm_Operator.filepath) + return {'FINISHED'} + + +#class ObjectListItem(bpy.types.PropertyGroup): +# id = bpy.props.IntProperty(name="ID") +# +#bpy.utils.register_class(ObjectListItem) + +# ==== EXPORT OPERATOR ==== + +class B3D_Export_Operator(bpy.types.Operator): + bl_idname = ("screen.b3d_export") + bl_label = ("B3D Export") + filepath = bpy.props.StringProperty(subtype="FILE_PATH") + + selected = bpy.props.BoolProperty(name="Export Selected Only", default=False) + vnormals = bpy.props.BoolProperty(name="Export Vertex Normals", default=True) + vcolors = bpy.props.BoolProperty(name="Export Vertex Colors", default=True) + cameras = bpy.props.BoolProperty(name="Export Cameras", default=False) + lights = bpy.props.BoolProperty(name="Export Lights", default=False) + mipmap = bpy.props.BoolProperty(name="Mipmap", default=False) + localsp = bpy.props.BoolProperty(name="Use Local Space Coords", default=False) + applymodifiers = bpy.props.BoolProperty(name="Apply modifiers", default=True) + + overwrite_without_asking = bpy.props.BoolProperty(name="Overwrite without asking", default=False) + + #skip_dialog = False + + #objects = bpy.props.CollectionProperty(type=ObjectListItem, options={'HIDDEN'}) + + def invoke(self, context, event): + blend_filepath = context.blend_data.filepath + if not blend_filepath: + blend_filepath = "Untitled.b3d" + else: + blend_filepath = os.path.splitext(blend_filepath)[0] + ".b3d" + self.filepath = blend_filepath + + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} + + def execute(self, context): + + global b3d_parameters + global the_scene + b3d_parameters["export-selected"] = self.selected + b3d_parameters["vertex-normals" ] = self.vnormals + b3d_parameters["vertex-colors" ] = self.vcolors + b3d_parameters["cameras" ] = self.cameras + b3d_parameters["lights" ] = self.lights + b3d_parameters["mipmap" ] = self.mipmap + b3d_parameters["local-space" ] = self.localsp + b3d_parameters["apply-modifiers"] = self.applymodifiers + + the_scene = context.scene + + if self.filepath == "": + return {'FINISHED'} + + if not self.filepath.endswith(".b3d"): + self.filepath += ".b3d" + + print("EXPORT", self.filepath," vcolor = ", self.vcolors) + + obj_list = [] + try: + # FIXME: silly and ugly hack, the list of objects to export is passed through + # a custom scene property + obj_list = context.scene.obj_list + except: + pass + + if len(obj_list) > 0: + + #objlist = [] + #for a in self.objects: + # objlist.append(bpy.data.objects[a.id]) + # + #write_b3d_file(self.filepath, obj_list) + + write_b3d_file(self.filepath, obj_list) + else: + if os.path.exists(self.filepath) and not self.overwrite_without_asking: + #self.report({'ERROR'}, "File Exists") + B3D_Confirm_Operator.filepath = self.filepath + bpy.ops.screen.b3d_confirm('INVOKE_DEFAULT') + return {'FINISHED'} + else: + write_b3d_file(self.filepath) + return {'FINISHED'} + + +# Add to a menu +def menu_func_export(self, context): + global the_scene + the_scene = context.scene + self.layout.operator(B3D_Export_Operator.bl_idname, text="B3D (.b3d)") + +def register(): + bpy.types.INFO_MT_file_export.append(menu_func_export) + bpy.utils.register_module(__name__) + +def unregister(): + bpy.types.INFO_MT_file_export.remove(menu_func_export) + +if __name__ == "__main__": + register() +