Advertisement
Guest User

B3D Blender

a guest
Jan 1st, 2013
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 56.99 KB | None | 0 0
  1. #!BPY
  2.  
  3. """
  4. Name: 'B3D Exporter (.b3d)...'
  5. Blender: 259
  6. Group: 'Export'
  7. Tooltip: 'Export to Blitz3D file format (.b3d)'
  8. """
  9. __author__ = ["Diego 'GaNDaLDF' Parisi"]
  10. __url__ = ["www.gandaldf.com"]
  11. __version__ = "3.0"
  12. __bpydoc__ = """\
  13. """
  14.  
  15. # BLITZ3D EXPORTER 3.0
  16. # Copyright (C) 2009 by Diego "GaNDaLDF" Parisi  -  www.gandaldf.com
  17. #
  18. # Lightmap issue fixed by Capricorn 76 Pty. Ltd. - www.capricorn76.com
  19. #
  20. # With changes by Marianne Gagnon and Joerg Henrichs, supertuxkart.sf.net
  21. #
  22. # LICENSE:
  23. # This program is free software; you can redistribute it and/or modify
  24. # it under the terms of the GNU General Public License as published by
  25. # the Free Software Foundation; either version 2 of the License, or
  26. # (at your option) any later version.
  27. #
  28. # This program is distributed in the hope that it will be useful,
  29. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  31. # GNU General Public License for more details.
  32. #
  33. # You should have received a copy of the GNU General Public License
  34. # along with this program; if not, write to the Free Software
  35. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  36.  
  37. bl_info = {
  38.     "name": "B3D (BLITZ3D) Model Exporter",
  39.     "description": "Exports a blender scene or object to the B3D (BLITZ3D) format",
  40.     "author": "Diego 'GaNDaLDF' Parisi, Joerg Henrichs, Marianne Gagnon",
  41.     "version": (3,1),
  42.     "blender": (2, 5, 9),
  43.     "api": 31236,
  44.     "location": "File > Export",
  45.     "warning": '', # used for warning icon and text in addons panel
  46.     "wiki_url": "http://supertuxkart.sourceforge.net/Get_involved",
  47.     "tracker_url": "https://sourceforge.net/apps/trac/supertuxkart/",
  48.     "category": "Import-Export"}
  49.  
  50.  
  51. #If you get an error here, it might be
  52. #because you don't have Python installed.
  53. import bpy
  54. import sys,os,os.path,struct,math,string
  55. import mathutils
  56. import math
  57.  
  58. if not hasattr(sys,"argv"): sys.argv = ["???"]
  59.  
  60.  
  61. #Global Stacks
  62. b3d_parameters = {}
  63. texture_flags  = []
  64. texs_stack     = {}
  65. brus_stack     = []
  66. vertex_groups  = []
  67. bone_stack     = {}
  68. keys_stack     = []
  69.  
  70. texture_count = 0
  71.  
  72. # bone_stack indices constants
  73. BONE_PARENT_MATRIX = 0
  74. BONE_PARENT = 1
  75. BONE_ITSELF = 2
  76.  
  77. # texture stack indices constants
  78. TEXTURE_ID = 0
  79. TEXTURE_FLAGS = 1
  80.  
  81. per_face_vertices = {}
  82.  
  83. the_scene = None
  84.  
  85. #Transformation Matrix
  86. TRANS_MATRIX = mathutils.Matrix([[1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]])
  87. BONE_TRANS_MATRIX = mathutils.Matrix([[-1,0,0,0],[0,0,-1,0],[0,-1,0,0],[0,0,0,1]])
  88.  
  89. DEBUG = False
  90. PROGRESS = True
  91. PROGRESS_VERBOSE = False
  92.  
  93. #Support Functions
  94. def write_int(value):
  95.     return struct.pack("<i",value)
  96.  
  97. def write_float(value):
  98.     return struct.pack("<f",value)
  99.  
  100. def write_float_couple(value1, value2):
  101.     return struct.pack("<ff", value1, value2)
  102.  
  103. def write_float_triplet(value1, value2, value3):
  104.     return struct.pack("<fff", value1, value2, value3)
  105.  
  106. def write_float_quad(value1, value2, value3, value4):
  107.     return struct.pack("<ffff", value1, value2, value3, value4)
  108.    
  109. def write_string(value):
  110.     binary_format = "<%ds"%(len(value)+1)
  111.     return struct.pack(binary_format, str.encode(value))
  112.  
  113. def write_chunk(name,value):
  114.     dummy = bytearray()
  115.     return dummy + name + write_int(len(value)) + value
  116.  
  117. trimmed_paths = {}
  118.  
  119. def getArmatureAnimationEnd(armature):
  120.     end_frame = 1
  121.     if armature.animation_data.action:
  122.         ipo = armature.animation_data.action.fcurves
  123.         for curve in ipo:
  124.             if "pose" in curve.data_path:
  125.                 end_frame = max(end_frame, curve.keyframe_points[-1].co[0])
  126.    
  127.     for nla_track in armature.animation_data.nla_tracks:
  128.         if len(nla_track.strips) > 0:
  129.             end_frame = max(end_frame, nla_track.strips[-1].frame_end)
  130.        
  131.     return end_frame
  132.  
  133. # ==== Write B3D File ====
  134. # (main exporter function)
  135. def write_b3d_file(filename, objects=[]):
  136.     global texture_flags, texs_stack, trimmed_paths
  137.     global brus_stack, vertex_groups, bone_stack, keys_stack
  138.  
  139.     #Global Stacks
  140.     texture_flags = []
  141.     texs_stack = {}
  142.     brus_stack = []
  143.     vertex_groups = []
  144.     bone_stack = []
  145.     keys_stack = []
  146.     trimmed_paths = {}
  147.     file_buf = bytearray()
  148.     temp_buf = bytearray()
  149.  
  150.     import time
  151.     start = time.time()
  152.  
  153.     temp_buf += write_int(1) #Version
  154.     temp_buf += write_texs(objects) #TEXS
  155.     temp_buf += write_brus(objects) #BRUS
  156.     temp_buf += write_node(objects) #NODE
  157.  
  158.     if len(temp_buf) > 0:
  159.         file_buf += write_chunk(b"BB3D",temp_buf)
  160.         temp_buf = ""
  161.  
  162.     file = open(filename,'wb')
  163.     file.write(file_buf)
  164.     file.close()
  165.    
  166.     # free memory
  167.     trimmed_paths = {}
  168.    
  169.     end = time.time()
  170.    
  171.     print("Exported in", (end - start))
  172.  
  173. # ==== Write TEXS Chunk ====
  174. def write_texs(objects=[]):
  175.     global b3d_parameters
  176.     global trimmed_paths
  177.     global texture_count
  178.     texs_buf = bytearray()
  179.     temp_buf = bytearray()
  180.     layer_max = 0
  181.     obj_count = 0
  182.     set_wrote = 0
  183.  
  184.     if objects:
  185.         exp_obj = objects
  186.     else:
  187.         if b3d_parameters.get("export-selected"):
  188.             exp_obj = [ob for ob in bpy.data.objects if ob.select]
  189.         else:
  190.             exp_obj = bpy.data.objects
  191.  
  192.     if PROGRESS: print(len(exp_obj),"TEXS")
  193.  
  194.     if PROGRESS_VERBOSE: progress = 0
  195.  
  196.     for obj in exp_obj:
  197.        
  198.         if PROGRESS_VERBOSE:
  199.             progress = progress + 1
  200.             if (progress % 10 == 0): print("TEXS",progress,"/",len(exp_obj))
  201.        
  202.         if obj.type == "MESH":
  203.             set_count = 0
  204.             set_wrote = 0
  205.             #data = obj.getData(mesh = True)
  206.             data = obj.data
  207.            
  208.             # FIXME?
  209.             #orig_uvlayer = data.activeUVLayer
  210.            
  211.             layer_set = [[],[],[],[],[],[],[],[]]
  212.            
  213.             # 8 UV layers are supported
  214.             texture_flags.append([None,None,None,None,None,None,None,None])
  215.  
  216.             #if len(data.getUVLayerNames()) <= 8:
  217.             if len(data.uv_textures) <= 8:
  218.                 if len(data.uv_textures) > layer_max:
  219.                     layer_max = len(data.uv_textures)
  220.             else:
  221.                 layer_max = 8
  222.  
  223.             for face in data.faces:
  224.                 for iuvlayer,uvlayer in enumerate(data.uv_textures):
  225.                     if iuvlayer < 8:
  226.                        
  227.                         # FIXME?
  228.                         #data.activeUVLayer = uvlayer
  229.                        
  230.                         #layer_set[iuvlayer].append(face.uv)
  231.                         new_data = None
  232.                         try:
  233.                             new_data = uvlayer.data[face.index].uv
  234.                         except:
  235.                            pass
  236.                        
  237.                         layer_set[iuvlayer].append( new_data )
  238.  
  239.             for i in range(len(data.uv_textures)):
  240.                 if set_wrote:
  241.                     set_count += 1
  242.                     set_wrote = 0
  243.  
  244.                 for iuvlayer in range(i,len(data.uv_textures)):
  245.                     if layer_set[i] == layer_set[iuvlayer]:
  246.                         if texture_flags[obj_count][iuvlayer] is None:
  247.                             if set_count == 0:
  248.                                 tex_flag = 1
  249.                             elif set_count == 1:
  250.                                 tex_flag = 65536
  251.                             elif set_count > 1:
  252.                                 tex_flag = 1
  253.                             if b3d_parameters.get("mipmap"):
  254.                                 enable_mipmaps=8
  255.                             else:
  256.                                 enable_mipmaps=0
  257.                             texture_flags[obj_count][iuvlayer] = tex_flag | enable_mipmaps
  258.                             set_wrote = 1
  259.  
  260.             for face in data.faces:
  261.                 for iuvlayer,uvlayer in enumerate(data.uv_textures):
  262.                     if iuvlayer < 8:
  263.                        
  264.                         if not (iuvlayer < len(data.uv_textures)):
  265.                             continue
  266.                        
  267.                         # FIXME?
  268.                         #data.activeUVLayer = uvlayer
  269.                        
  270.                         #if DEBUG: print("<uv face=", face.index, ">")
  271.                        
  272.                         img = data.uv_textures[iuvlayer].data[face.index].image
  273.                        
  274.                         if img:
  275.                            
  276.                             if img.filepath in trimmed_paths:
  277.                                 img_name = trimmed_paths[img.filepath]
  278.                             else:
  279.                                 img_name = bpy.path.basename(img.filepath)
  280.                                 trimmed_paths[img.filepath] = img_name
  281.  
  282.                             if not img_name in texs_stack:
  283.                                 texs_stack[img_name] = [len(texs_stack), texture_flags[obj_count][iuvlayer]]
  284.                                 temp_buf += write_string(img_name) #Texture File Name
  285.                                 temp_buf += write_int(texture_flags[obj_count][iuvlayer]) #Flags
  286.                                 temp_buf += write_int(2)   #Blend
  287.                                 temp_buf += write_float(0) #X_Pos
  288.                                 temp_buf += write_float(0) #Y_Pos
  289.                                 temp_buf += write_float(1) #X_Scale
  290.                                 temp_buf += write_float(1) #Y_Scale
  291.                                 temp_buf += write_float(0) #Rotation
  292.                             #else:
  293.                             #    if DEBUG: print("    <image id=(previous)","name=","'"+img_name+"'","/>")
  294.                            
  295.                         #if DEBUG: print("</uv>")
  296.  
  297.             obj_count += 1
  298.  
  299.             #FIXME?
  300.             #if orig_uvlayer:
  301.             #    data.activeUVLayer = orig_uvlayer
  302.  
  303.     texture_count = layer_max
  304.  
  305.     if len(temp_buf) > 0:
  306.         texs_buf += write_chunk(b"TEXS",temp_buf)
  307.         temp_buf = ""
  308.  
  309.     return texs_buf
  310.  
  311. # ==== Write BRUS Chunk ====
  312. def write_brus(objects=[]):
  313.     global b3d_parameters
  314.     global trimmed_paths
  315.     global texture_count
  316.     brus_buf = bytearray()
  317.     temp_buf = bytearray()
  318.     mat_count = 0
  319.     obj_count = 0
  320.  
  321.     if DEBUG: print("<!-- BRUS chunk -->")
  322.  
  323.     if objects:
  324.         exp_obj = objects
  325.     else:
  326.         if  b3d_parameters.get("export-selected"):
  327.             exp_obj = [ob for ob in bpy.data.objects if ob.select]
  328.         else:
  329.             exp_obj = bpy.data.objects
  330.  
  331.     if PROGRESS: print(len(exp_obj),"BRUS")
  332.     if PROGRESS_VERBOSE: progress = 0
  333.  
  334.     for obj in exp_obj:
  335.        
  336.         if PROGRESS_VERBOSE:
  337.             progress += 1
  338.             if (progress % 10 == 0): print("BRUS",progress,"/",len(exp_obj))
  339.            
  340.         if obj.type == "MESH":
  341.             data = obj.data
  342.            
  343.             if len(data.uv_textures) <= 0:
  344.                 continue
  345.  
  346.             if DEBUG: print("<obj name=",obj.name,">")
  347.  
  348.             img_found = 0
  349.            
  350.             for face in data.faces:
  351.                
  352.                 face_stack = []
  353.                
  354.                 for iuvlayer,uvlayer in enumerate(data.uv_textures):
  355.                     if iuvlayer < 8:
  356.                        
  357.                         img_id = -1
  358.                        
  359.                         if face.index >= len(data.uv_textures[iuvlayer].data):
  360.                             continue
  361.                        
  362.                         img = data.uv_textures[iuvlayer].data[face.index].image
  363.                        
  364.                         if not img:
  365.                             continue
  366.                        
  367.                         img_found = 1
  368.                        
  369.                         if img.filepath in trimmed_paths:
  370.                             img_name = trimmed_paths[img.filepath]
  371.                         else:
  372.                             img_name = os.path.basename(img.filepath)
  373.                             trimmed_paths[img.filepath] = img_name
  374.                        
  375.                         if DEBUG: print("    <!-- Building FACE 'stack' -->")
  376.                        
  377.                         if img_name in texs_stack:
  378.                             img_id = texs_stack[img_name][TEXTURE_ID]
  379.                        
  380.                         face_stack.insert(iuvlayer,img_id)
  381.                         if DEBUG: print("    <uv face=",face.index,"layer=", iuvlayer, " imgid=", img_id, "/>")
  382.  
  383.                 for i in range(len(face_stack),texture_count):
  384.                     face_stack.append(-1)
  385.  
  386.  
  387.                 if DEBUG: print("    <!-- Writing chunk -->")
  388.                
  389.                 if not img_found:
  390.                     if data.materials:
  391.                         if data.materials[face.material_index]:
  392.                             mat_data = data.materials[face.material_index]
  393.                             mat_colr = mat_data.diffuse_color[0]
  394.                             mat_colg = mat_data.diffuse_color[1]
  395.                             mat_colb = mat_data.diffuse_color[2]
  396.                             mat_alpha = mat_data.alpha
  397.                             mat_name = mat_data.name
  398.  
  399.                             if not mat_name in brus_stack:
  400.                                 brus_stack.append(mat_name)
  401.                                 temp_buf += write_string(mat_name) #Brush Name
  402.                                 temp_buf += write_float(mat_colr)  #Red
  403.                                 temp_buf += write_float(mat_colg)  #Green
  404.                                 temp_buf += write_float(mat_colb)  #Blue
  405.                                 temp_buf += write_float(mat_alpha) #Alpha
  406.                                 temp_buf += write_float(0)         #Shininess
  407.                                 temp_buf += write_int(1)           #Blend
  408.                                 if b3d_parameters.get("vertex-colors") and len(data.vertex_colors):
  409.                                     temp_buf += write_int(2) #Fx
  410.                                 else:
  411.                                     temp_buf += write_int(0) #Fx
  412.  
  413.                                 for i in face_stack:
  414.                                     temp_buf += write_int(i) #Texture ID
  415.                     else:
  416.                         if b3d_parameters.get("vertex-colors") and len(data.vertex_colors) > 0:
  417.                             if not face_stack in brus_stack:
  418.                                 brus_stack.append(face_stack)
  419.                                 mat_count += 1
  420.                                 temp_buf += write_string("Brush.%.3i"%mat_count) #Brush Name
  421.                                 temp_buf += write_float(1) #Red
  422.                                 temp_buf += write_float(1) #Green
  423.                                 temp_buf += write_float(1) #Blue
  424.                                 temp_buf += write_float(1) #Alpha
  425.                                 temp_buf += write_float(0) #Shininess
  426.                                 temp_buf += write_int(1)   #Blend
  427.                                 temp_buf += write_int(2)   #Fx
  428.  
  429.                                 for i in face_stack:
  430.                                     temp_buf += write_int(i) #Texture ID
  431.                 else: # img_found
  432.                
  433.                     if not face_stack in brus_stack:
  434.                         brus_stack.append(face_stack)
  435.                         mat_count += 1
  436.                         temp_buf += write_string("Brush.%.3i"%mat_count) #Brush Name
  437.                         temp_buf += write_float(1) #Red
  438.                         temp_buf += write_float(1) #Green
  439.                         temp_buf += write_float(1) #Blue
  440.                         temp_buf += write_float(1) #Alpha
  441.                         temp_buf += write_float(0) #Shininess
  442.                         temp_buf += write_int(1)   #Blend
  443.                        
  444.                         if DEBUG: print("    <brush id=",len(brus_stack),">")
  445.                        
  446.                         if b3d_parameters.get("vertex-colors") and len(data.vertex_colors) > 0:
  447.                             temp_buf += write_int(2) #Fx
  448.                         else:
  449.                             temp_buf += write_int(0) #Fx
  450.  
  451.                         for i in face_stack:
  452.                             temp_buf += write_int(i) #Texture ID
  453.                             if DEBUG: print("        <texture id=",i,">")
  454.                        
  455.                         if DEBUG: print("    </brush>")
  456.                
  457.                 if DEBUG: print("")
  458.  
  459.             if DEBUG: print("</obj>")
  460.             obj_count += 1
  461.  
  462.             #FIXME?
  463.             #if orig_uvlayer:
  464.             #    data.activeUVLayer = orig_uvlayer
  465.  
  466.     if len(temp_buf) > 0:
  467.         brus_buf += write_chunk(b"BRUS",write_int(texture_count) + temp_buf) #N Texs
  468.         temp_buf = ""
  469.    
  470.     return brus_buf
  471.  
  472. # ==== Write NODE Chunk ====
  473. def write_node(objects=[]):
  474.     global bone_stack
  475.     global keys_stack
  476.     global b3d_parameters
  477.     global the_scene
  478.    
  479.     root_buf = []
  480.     node_buf = []
  481.     main_buf = bytearray()
  482.     temp_buf = []
  483.     obj_count = 0
  484.     amb_light = 0
  485.  
  486.     num_mesh = 0
  487.     num_ligs = 0
  488.     num_cams = 0
  489.     num_lorc = 0
  490.     #exp_scn = Blender.Scene.GetCurrent()
  491.     #exp_scn = the_scene
  492.     #exp_con = exp_scn.getRenderingContext()
  493.  
  494.     #first_frame = Blender.Draw.Create(exp_con.startFrame())
  495.     #last_frame = Blender.Draw.Create(exp_con.endFrame())
  496.     #num_frames = last_frame.val - first_frame.val
  497.     first_frame = the_scene.frame_start
  498.  
  499.     if DEBUG: print("<node first_frame=", first_frame, ">")
  500.  
  501.     if objects:
  502.         exp_obj = objects
  503.     else:
  504.         if b3d_parameters.get("export-selected"):
  505.             exp_obj = [ob for ob in bpy.data.objects if ob.select]
  506.         else:
  507.             exp_obj = bpy.data.objects
  508.  
  509.     for obj in exp_obj:
  510.         if obj.type == "MESH":
  511.             num_mesh += 1
  512.         if obj.type == "CAMERA":
  513.             num_cams += 1
  514.         if obj.type == "LAMP":
  515.             num_ligs += 1
  516.  
  517.     if b3d_parameters.get("cameras"):
  518.         num_lorc += num_cams
  519.  
  520.     if b3d_parameters.get("lights"):
  521.         num_lorc += 1
  522.         num_lorc += num_ligs
  523.  
  524.     if num_mesh + num_lorc > 1:
  525.         exp_root = 1
  526.     else:
  527.         exp_root = 0
  528.  
  529.     if exp_root:
  530.         root_buf.append(write_string("ROOT")) #Node Name
  531.  
  532.         root_buf.append(write_float_triplet(0, 0, 0)) #Position X,Y,Z
  533.         root_buf.append(write_float_triplet(1, 1, 1)) #Scale X, Y, Z
  534.         root_buf.append(write_float_quad(1, 0, 0, 0)) #Rotation W, X, Y, Z
  535.  
  536.     if PROGRESS: progress = 0
  537.  
  538.     for obj in exp_obj:
  539.        
  540.         if PROGRESS:
  541.             progress += 1
  542.             print("NODE:",progress,"/",len(exp_obj))
  543.        
  544.         if obj.type == "MESH":
  545.            
  546.             if DEBUG: print("    <mesh name=",obj.name,">")
  547.            
  548.             bone_stack = {}
  549.             keys_stack = []
  550.  
  551.             anim_data = None
  552.            
  553.             # check if this object has an armature modifier
  554.             for curr_mod in obj.modifiers:
  555.                 if curr_mod.type == 'ARMATURE':
  556.                     arm = curr_mod.object
  557.                     anim_data = arm.animation_data
  558.  
  559.             # check if this object has an armature parent (second way to do armature animations in blender)
  560.             if anim_data is None:
  561.                 if obj.parent:
  562.                     if obj.parent.type == "ARMATURE":
  563.                         arm = obj.parent
  564.                         if arm.animation_data:
  565.                             anim_data = arm.animation_data
  566.  
  567.             if anim_data:
  568.                 matrix = mathutils.Matrix()
  569.  
  570.                 temp_buf.append(write_string(obj.name)) #Node Name
  571.                
  572.                 position = matrix.to_translation()
  573.                 temp_buf.append(write_float_triplet(position[0], position[1], position[2])) #Position X, Y, Z
  574.  
  575.                 scale = matrix.to_scale()
  576.                 temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1])) #Scale X, Y, Z
  577.  
  578.                 if DEBUG: print("        <arm name=", obj.name, " loc=", -position[0], position[1], position[2], " scale=", scale[0], scale[1], scale[2], "/>")
  579.                
  580.                 quat = matrix.to_quaternion()
  581.                 quat.normalize()
  582.  
  583.                 temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y))
  584.             else:
  585.                 if b3d_parameters.get("local-space"):
  586.                     matrix = TRANS_MATRIX.copy()
  587.                     scale_matrix = mathutils.Matrix()
  588.                 else:
  589.                     matrix = obj.matrix_world*TRANS_MATRIX
  590.                     scale_matrix = obj.matrix_world.copy()
  591.                
  592.                
  593.                 if bpy.app.version[1] >= 62:
  594.                     # blender 2.62 broke the API : Column-major access was changed to row-major access
  595.                     # TODO: test me
  596.                     tmp = mathutils.Vector([matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1]])
  597.                     matrix[0][1] = matrix[0][2]
  598.                     matrix[1][1] = matrix[1][2]
  599.                     matrix[2][1] = matrix[2][2]
  600.                     matrix[3][1] = matrix[3][2]
  601.                    
  602.                     matrix[0][2] = tmp[0]
  603.                     matrix[1][2] = tmp[1]
  604.                     matrix[2][2] = tmp[2]
  605.                     matrix[3][2] = tmp[3]
  606.                 else:
  607.                     tmp = mathutils.Vector(matrix[1])
  608.                     matrix[1] = matrix[2]
  609.                     matrix[2] = tmp
  610.  
  611.                 temp_buf.append(write_string(obj.name)) #Node Name
  612.  
  613.                 #print("Matrix : ", matrix)
  614.                 position = matrix.to_translation()
  615.  
  616.                 temp_buf.append(write_float_triplet(position[0], position[2], position[1]))
  617.  
  618.                 scale = scale_matrix.to_scale()
  619.                 temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1]))
  620.  
  621.                 quat = matrix.to_quaternion()
  622.                 quat.normalize()
  623.  
  624.                 temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y))
  625.                  
  626.                 if DEBUG:
  627.                     print("        <position>",position[0],position[2],position[1],"</position>")
  628.                     print("        <scale>",scale[0],scale[1],scale[2],"</scale>")
  629.                     print("        <rotation>", quat.w, quat.x, quat.y, quat.z, "</rotation>")
  630.            
  631.             if anim_data:
  632.                 the_scene.frame_set(1,subframe=0.0)
  633.                
  634.                 arm_matrix = arm.matrix_world
  635.                
  636.                 if b3d_parameters.get("local-space"):
  637.                     arm_matrix = mathutils.Matrix()
  638.                
  639.                 def read_armature(arm_matrix,bone,parent = None):
  640.                     if (parent and not bone.parent.name == parent.name):
  641.                         return
  642.  
  643.                     matrix = mathutils.Matrix(bone.matrix)
  644.                    
  645.                     if parent:
  646.  
  647.                         #print("==== "+bone.name+" ====")
  648.                         a = (bone.matrix_local)
  649.                        
  650.                         #print("A : [%.2f %.2f %.2f %.2f]" % (a[0][0], a[0][1], a[0][2], a[0][3]))
  651.                         #print("    [%.2f %.2f %.2f %.2f]" % (a[1][0], a[1][1], a[1][2], a[1][3]))
  652.                         #print("    [%.2f %.2f %.2f %.2f]" % (a[2][0], a[2][1], a[2][2], a[2][3]))
  653.                         #print("    [%.2f %.2f %.2f %.2f]" % (a[3][0], a[3][1], a[3][2], a[3][3]))
  654.                        
  655.                         b = (parent.matrix_local.inverted().to_4x4())
  656.                        
  657.                         #print("B : [%.2f %.2f %.2f %.2f]" % (b[0][0], b[0][1], b[0][2], b[0][3]))
  658.                         #print("    [%.2f %.2f %.2f %.2f]" % (b[1][0], b[1][1], b[1][2], b[1][3]))
  659.                         #print("    [%.2f %.2f %.2f %.2f]" % (b[2][0], b[2][1], b[2][2], b[2][3]))
  660.                         #print("    [%.2f %.2f %.2f %.2f]" % (b[3][0], b[3][1], b[3][2], b[3][3]))
  661.                        
  662.                         par_matrix = b * a
  663.                        
  664.                         transform = mathutils.Matrix([[1,0,0,0],[0,0,-1,0],[0,-1,0,0],[0,0,0,1]])
  665.                         par_matrix = transform*par_matrix*transform
  666.                        
  667.                         # FIXME: that's ugly, find a clean way to change the matrix.....
  668.                         if bpy.app.version[1] >= 62:
  669.                             # blender 2.62 broke the API : Column-major access was changed to row-major access
  670.                             # TODO: test me
  671.                             par_matrix[1][3] = -par_matrix[1][3]
  672.                             par_matrix[2][3] = -par_matrix[2][3]
  673.                         else:
  674.                             par_matrix[3][1] = -par_matrix[3][1]
  675.                             par_matrix[3][2] = -par_matrix[3][2]
  676.                        
  677.                         #c = par_matrix
  678.                         #print("With parent")
  679.                         #print("C : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3]))
  680.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3]))
  681.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3]))
  682.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3]))
  683.                        
  684.                     else:
  685.                        
  686.                         #print("==== "+bone.name+" ====")
  687.                         #print("Without parent")
  688.  
  689.                         m = arm_matrix*bone.matrix_local
  690.                        
  691.                         #c = arm.matrix_world
  692.                         #print("A : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3]))
  693.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3]))
  694.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3]))
  695.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3]))
  696.                        
  697.                         #c = bone.matrix_local
  698.                         #print("B : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3]))
  699.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3]))
  700.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3]))
  701.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3]))
  702.                        
  703.                         par_matrix = m*mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]])
  704.                                                
  705.                         #c = par_matrix
  706.                         #print("C : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3]))
  707.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3]))
  708.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3]))
  709.                         #print("    [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3]))
  710.                        
  711.  
  712.                     bone_stack[bone.name] = [par_matrix,parent,bone]
  713.  
  714.                     if bone.children:
  715.                         for child in bone.children: read_armature(arm_matrix,child,bone)
  716.  
  717.                 for bone in arm.data.bones.values():
  718.                     if not bone.parent:
  719.                         read_armature(arm_matrix,bone)
  720.  
  721.                 frame_count = first_frame
  722.                
  723.                 last_frame = int(getArmatureAnimationEnd(arm))
  724.                 num_frames = last_frame - first_frame
  725.  
  726.                 while frame_count <= last_frame:
  727.  
  728.                     the_scene.frame_set(int(frame_count), subframe=0.0)
  729.                    
  730.                     if DEBUG: print("        <frame id=", int(frame_count), ">")
  731.                     arm_pose = arm.pose
  732.                     arm_matrix = arm.matrix_world
  733.                    
  734.                     transform = mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]])
  735.                     arm_matrix = transform*arm_matrix
  736.  
  737.                     for bone_name in arm.data.bones.keys():
  738.                         #bone_matrix = mathutils.Matrix(arm_pose.bones[bone_name].poseMatrix)
  739.                         bone_matrix = mathutils.Matrix(arm_pose.bones[bone_name].matrix)
  740.                        
  741.                         #print("(outer loop) bone_matrix for",bone_name,"=", bone_matrix)
  742.                        
  743.                         #print(bone_name,":",bone_matrix)
  744.                        
  745.                         #bone_matrix = bpy.data.scenes[0].objects[0].pose.bones['Bone'].matrix
  746.                        
  747.                         for ibone in bone_stack:
  748.                            
  749.                             bone = bone_stack[ibone]
  750.                            
  751.                             if bone[BONE_ITSELF].name == bone_name:
  752.                                
  753.                                 if DEBUG: print("            <bone id=",ibone,"name=",bone_name,">")
  754.                                
  755.                                 # == 2.4 exporter ==
  756.                                 #if bone_stack[ibone][1]:
  757.                                 #    par_matrix = Blender.Mathutils.Matrix(arm_pose.bones[bone_stack[ibone][1].name].poseMatrix)
  758.                                 #    bone_matrix *= par_matrix.invert()
  759.                                 #else:
  760.                                 #    if b3d_parameters.get("local-space"):
  761.                                 #        bone_matrix *= TRANS_MATRIX
  762.                                 #    else:
  763.                                 #        bone_matrix *= arm_matrix
  764.                                 #bone_loc = bone_matrix.translationPart()
  765.                                 #bone_rot = bone_matrix.rotationPart().toQuat()
  766.                                 #bone_rot.normalize()
  767.                                 #bone_sca = bone_matrix.scalePart()
  768.                                 #keys_stack.append([frame_count - first_frame.val+1,bone_name,bone_loc,bone_sca,bone_rot])
  769.                                
  770.                                 # if has parent
  771.                                 if bone[BONE_PARENT]:
  772.                                     par_matrix = mathutils.Matrix(arm_pose.bones[bone[BONE_PARENT].name].matrix)
  773.                                     bone_matrix = par_matrix.inverted()*bone_matrix
  774.                                 else:
  775.                                     if b3d_parameters.get("local-space"):
  776.                                         bone_matrix = bone_matrix*mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]])
  777.                                     else:
  778.                                        
  779.                                         #if frame_count == 1:
  780.                                         #    print("====",bone_name,"====")
  781.                                         #    print("arm_matrix = ", arm_matrix)
  782.                                         #    print("bone_matrix = ", bone_matrix)
  783.                                        
  784.                                         bone_matrix = arm_matrix*bone_matrix
  785.                                        
  786.                                         #if frame_count == 1:
  787.                                         #    print("arm_matrix*bone_matrix", bone_matrix)
  788.                                        
  789.                                
  790.                                 #print("bone_matrix =", bone_matrix)
  791.                                
  792.                                 bone_sca = bone_matrix.to_scale()
  793.                                 bone_loc = bone_matrix.to_translation()
  794.                                
  795.                                 # FIXME: silly tweaks to resemble the Blender 2.4 exporter output
  796.                                 if b3d_parameters.get("local-space"):
  797.                                    
  798.                                     bone_rot = bone_matrix.to_quaternion()
  799.                                     bone_rot.normalize()
  800.                                    
  801.                                    
  802.                                     if not bone[BONE_PARENT]:
  803.                                         tmp = bone_rot.z
  804.                                         bone_rot.z = bone_rot.y
  805.                                         bone_rot.y = tmp
  806.                                        
  807.                                         bone_rot.x = -bone_rot.x
  808.                                     else:
  809.                                         tmp = bone_loc.z
  810.                                         bone_loc.z = bone_loc.y
  811.                                         bone_loc.y = tmp
  812.  
  813.                                 else:
  814.                                     bone_rot = bone_matrix.to_quaternion()
  815.                                     bone_rot.normalize()
  816.  
  817.                                 keys_stack.append([frame_count - first_frame+1, bone_name, bone_loc, bone_sca, bone_rot])
  818.                                 if DEBUG: print("                <loc>", bone_loc, "</loc>")
  819.                                 if DEBUG: print("                <rot>", bone_rot, "</rot>")
  820.                                 if DEBUG: print("                <scale>", bone_sca, "</scale>")
  821.                                 if DEBUG: print("            </bone>")
  822.  
  823.                     frame_count += 1
  824.  
  825.                     if DEBUG: print("        </frame>")
  826.  
  827.                 #Blender.Set("curframe",0)
  828.                 #Blender.Window.Redraw()
  829.  
  830.             temp_buf.append(write_node_mesh(obj,obj_count,anim_data,exp_root)) #NODE MESH
  831.            
  832.             if anim_data:
  833.                 temp_buf.append(write_node_anim(num_frames)) #NODE ANIM
  834.  
  835.                 for ibone in bone_stack:
  836.                     if not bone_stack[ibone][BONE_PARENT]:
  837.                         temp_buf.append(write_node_node(ibone)) #NODE NODE
  838.  
  839.             obj_count += 1
  840.  
  841.             if len(temp_buf) > 0:
  842.                 node_buf.append(write_chunk(b"NODE",b"".join(temp_buf)))
  843.                 temp_buf = []
  844.            
  845.             if DEBUG: print("    </mesh>")
  846.  
  847.         if b3d_parameters.get("cameras"):
  848.             if obj.type == "CAMERA":
  849.                 data = obj.data
  850.                 matrix = obj.getMatrix("worldspace")
  851.                 matrix *= TRANS_MATRIX
  852.  
  853.                 if data.type == "ORTHO":
  854.                     cam_type = 2
  855.                     cam_zoom = round(data.scale,4)
  856.                 else:
  857.                     cam_type = 1
  858.                     cam_zoom = round(data.lens,4)
  859.  
  860.                 cam_near = round(data.clipStart,4)
  861.                 cam_far = round(data.clipEnd,4)
  862.  
  863.                 node_name = ("CAMS"+"\n%s"%obj.name+"\n%s"%cam_type+\
  864.                              "\n%s"%cam_zoom+"\n%s"%cam_near+"\n%s"%cam_far)
  865.                 temp_buf.append(write_string(node_name)) #Node Name
  866.  
  867.                 position = matrix.translation_part()
  868.                 temp_buf.append(write_float_triplet(-position[0], position[1], position[2]))
  869.  
  870.                 scale = matrix.scale_part()
  871.                 temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2]))
  872.  
  873.                 matrix *= mathutils.Matrix.Rotation(180,4,'Y')
  874.                 quat = matrix.to_quat()
  875.                 quat.normalize()
  876.  
  877.                 temp_buf.append(write_float_quad(quat.w, quat.x, quat.y, -quat.z))
  878.  
  879.                 if len(temp_buf) > 0:
  880.                     node_buf.append(write_chunk(b"NODE",b"".join(temp_buf)))
  881.                     temp_buf = []
  882.  
  883.         if b3d_parameters.get("lights"):
  884.             if amb_light == 0:
  885.                 data = Blender.World.GetCurrent()
  886.  
  887.                 amb_light = 1
  888.                 amb_color = (int(data.amb[2]*255) |(int(data.amb[1]*255) << 8) | (int(data.amb[0]*255) << 16))
  889.  
  890.                 node_name = (b"AMBI"+"\n%s"%amb_color)
  891.                 temp_buf.append(write_string(node_name)) #Node Name
  892.  
  893.                 temp_buf.append(write_float_triplet(0, 0, 0)) #Position X, Y, Z
  894.                 temp_buf.append(write_float_triplet(1, 1, 1)) #Scale X, Y, Z
  895.                 temp_buf.append(write_float_quad(1, 0, 0, 0)) #Rotation W, X, Y, Z
  896.  
  897.                 if len(temp_buf) > 0:
  898.                     node_buf.append(write_chunk(b"NODE",b"".join(temp_buf)))
  899.                     temp_buf = []
  900.  
  901.             if obj.type == "LAMP":
  902.                 data = obj.getData()
  903.                 matrix = obj.getMatrix("worldspace")
  904.                 matrix *= TRANS_MATRIX
  905.  
  906.                 if data.type == 0:
  907.                     lig_type = 2
  908.                 elif data.type == 2:
  909.                     lig_type = 3
  910.                 else:
  911.                     lig_type = 1
  912.  
  913.                 lig_angle = round(data.spotSize,4)
  914.                 lig_color = (int(data.b*255) |(int(data.g*255) << 8) | (int(data.r*255) << 16))
  915.                 lig_range = round(data.dist,4)
  916.  
  917.                 node_name = ("LIGS"+"\n%s"%obj.name+"\n%s"%lig_type+\
  918.                              "\n%s"%lig_angle+"\n%s"%lig_color+"\n%s"%lig_range)
  919.                 temp_buf.append(write_string(node_name)) #Node Name
  920.  
  921.                 position = matrix.translation_part()
  922.                 temp_buf.append(write_float_triplet(-position[0], position[1], position[2]))
  923.                 if DEBUG: print("        <position>",-position[0],position[1],position[2],"</position>")
  924.  
  925.                 scale = matrix.scale_part()
  926.                 temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2]))
  927.                
  928.                 if DEBUG: print("        <scale>",scale[0],scale[1],scale[2],"</scale>")
  929.  
  930.                 matrix *= mathutils.Matrix.Rotation(180,4,'Y')
  931.                 quat = matrix.toQuat()
  932.                 quat.normalize()
  933.  
  934.                 temp_buf.append(write_float_quad(quat.w, quat.x, quat.y, -quat.z))
  935.                 if DEBUG: print("        <rotation>", quat.w, quat.x, quat.y, quat.z, "</rotation>")
  936.  
  937.                 if len(temp_buf) > 0:
  938.                     node_buf.append(write_chunk(b"NODE","b".join(temp_buf)))
  939.                     temp_buf = []
  940.    
  941.     if len(node_buf) > 0:
  942.         if exp_root:
  943.             main_buf += write_chunk(b"NODE",b"".join(root_buf) + b"".join(node_buf))
  944.         else:
  945.             main_buf += b"".join(node_buf)
  946.  
  947.         node_buf = []
  948.         root_buf = []
  949.  
  950.     if DEBUG: print("</node>")
  951.  
  952.     return main_buf
  953.  
  954. # ==== Write NODE MESH Chunk ====
  955. def write_node_mesh(obj,obj_count,arm_action,exp_root):
  956.     global vertex_groups
  957.     vertex_groups = []
  958.     mesh_buf = bytearray()
  959.     temp_buf = bytearray()
  960.  
  961.     if arm_action:
  962.         data = obj.data
  963.     else:
  964.         data = obj.to_mesh(the_scene, True, 'PREVIEW')
  965.    
  966.     temp_buf += write_int(-1) #Brush ID
  967.     temp_buf += write_node_mesh_vrts(obj, data, obj_count, arm_action, exp_root) #NODE MESH VRTS
  968.     temp_buf += write_node_mesh_tris(obj, data, obj_count, arm_action, exp_root) #NODE MESH TRIS
  969.  
  970.     if len(temp_buf) > 0:
  971.         mesh_buf += write_chunk(b"MESH",temp_buf)
  972.         temp_buf = ""
  973.  
  974.     return mesh_buf
  975.  
  976. #ids_count = 0
  977.  
  978. def build_vertex_groups(data):
  979.     for f in data.faces:
  980.         for v in f.vertices:
  981.             vertex_groups.append({})
  982.  
  983. #time_in_a = 0
  984. #time_in_b = 0
  985. #time_in_b1 = 0
  986. #time_in_b2 = 0
  987. #time_in_b3 = 0
  988. #time_in_b4 = 0
  989.  
  990. # ==== Write NODE MESH VRTS Chunk ====
  991. def write_node_mesh_vrts(obj, data, obj_count, arm_action, exp_root):
  992.     #global ids_count
  993.     vrts_buf = bytearray()
  994.     temp_buf = []
  995.     obj_flags = 0
  996.     ids_count = 0
  997.    
  998.     #global time_in_a
  999.     #global time_in_b
  1000.     #global time_in_b1
  1001.     #global time_in_b2
  1002.     #global time_in_b3
  1003.     #global time_in_b4
  1004.  
  1005.     #data = obj.getData(mesh = True)
  1006.     global the_scene
  1007.    
  1008.     # FIXME: port to 2.5 API?
  1009.     #orig_uvlayer = data.activeUVLayer
  1010.  
  1011.     if b3d_parameters.get("vertex-normals"):
  1012.         obj_flags += 1
  1013.  
  1014.     #if b3d_parameters.get("vertex-colors") and data.getColorLayerNames():
  1015.     if b3d_parameters.get("vertex-colors") and len(data.vertex_colors) > 0:
  1016.         obj_flags += 2
  1017.  
  1018.     temp_buf.append(write_int(obj_flags)) #Flags
  1019.     #temp_buf += write_int(len(data.getUVLayerNames())) #UV Set
  1020.     temp_buf.append(write_int(len(data.uv_textures))) #UV Set
  1021.     temp_buf.append(write_int(2)) #UV Set Size
  1022.  
  1023.     # ---- Prepare the mesh "stack"
  1024.     build_vertex_groups(data)
  1025.  
  1026.     amount = 0
  1027.    
  1028.     # ---- Fill the mesh "stack"
  1029.     if DEBUG: print("")
  1030.     if DEBUG: print("        <!-- Building vertex_groups -->\n")
  1031.  
  1032.     ivert = -1
  1033.  
  1034.  
  1035.     if PROGRESS_VERBOSE:
  1036.         progress = 0
  1037.         print("    vertex_groups, face:",0,"/",len(data.faces))
  1038.    
  1039.     the_scene.frame_set(1,subframe=0.0)
  1040.    
  1041.     if b3d_parameters.get("local-space"):
  1042.         mesh_matrix = mathutils.Matrix()
  1043.     else:
  1044.         mesh_matrix = obj.matrix_world.copy()
  1045.    
  1046.     import time
  1047.    
  1048.    
  1049.     uv_layers_count = len(data.uv_textures)
  1050.     for face in data.faces:
  1051.        
  1052.         if DEBUG: print("        <!-- Face",face.index,"-->")
  1053.        
  1054.         #if PROGRESS_VERBOSE:
  1055.         #    progress += 1
  1056.         #    if (progress % 50 == 0): print("    vertex_groups, face:",progress,"/",len(data.faces))
  1057.        
  1058.         per_face_vertices[face.index] = []
  1059.        
  1060.         for vertex_id,vert in enumerate(face.vertices):
  1061.            
  1062.             ivert += 1
  1063.                        
  1064.             per_face_vertices[face.index].append(ivert)
  1065.            
  1066.             #a = time.time()
  1067.                            
  1068.             if arm_action:
  1069.                 v = mesh_matrix * data.vertices[vert].co
  1070.                 vert_matrix = mathutils.Matrix.Translation(v)
  1071.             else:
  1072.                 vert_matrix = mathutils.Matrix.Translation(data.vertices[vert].co)
  1073.  
  1074.             vert_matrix *= TRANS_MATRIX
  1075.             vcoord = vert_matrix.to_translation()
  1076.  
  1077.             temp_buf.append(write_float_triplet(vcoord.x, vcoord.z, vcoord.y))
  1078.  
  1079.             #b = time.time()
  1080.             #time_in_a += b - a
  1081.            
  1082.             if b3d_parameters.get("vertex-normals"):
  1083.                 norm_matrix = mathutils.Matrix.Translation(data.vertices[vert].normal)
  1084.  
  1085.                 if arm_action:
  1086.                     norm_matrix *= mesh_matrix
  1087.  
  1088.                 norm_matrix *= TRANS_MATRIX
  1089.                 normal_vector = norm_matrix.to_translation()
  1090.                
  1091.                 temp_buf.append(write_float_triplet(normal_vector.x,  #NX
  1092.                                                     normal_vector.z,  #NY
  1093.                                                     normal_vector.y)) #NZ
  1094.  
  1095.             #c = time.time()
  1096.             #time_in_b += c - b
  1097.  
  1098.             if b3d_parameters.get("vertex-colors") and len(data.vertex_colors) > 0:
  1099.                 if vertex_id == 0:
  1100.                     vcolor = data.vertex_colors[0].data[face.index].color1
  1101.                 elif vertex_id == 1:
  1102.                     vcolor = data.vertex_colors[0].data[face.index].color2
  1103.                 elif vertex_id == 2:
  1104.                     vcolor = data.vertex_colors[0].data[face.index].color3
  1105.                 elif vertex_id == 3:
  1106.                     vcolor = data.vertex_colors[0].data[face.index].color4
  1107.                
  1108.                 temp_buf.append(write_float_quad(vcolor.r, #R
  1109.                                                  vcolor.g, #G
  1110.                                                  vcolor.b, #B
  1111.                                                  1.0))     #A (FIXME?)
  1112.            
  1113.             #d = time.time()
  1114.             #time_in_b1 += d - c
  1115.            
  1116.             for vg in obj.vertex_groups:
  1117.                 w = 0.0
  1118.                 try:
  1119.                     w = vg.weight(vert)
  1120.                 except:
  1121.                     pass
  1122.                 vertex_groups[ivert][vg.name] = w
  1123.            
  1124.             #e = time.time()
  1125.             #time_in_b2 += e - d
  1126.            
  1127.             # ==== !!bottleneck here!! (40% of the function)
  1128.             if vertex_id == 0:
  1129.                 for iuvlayer in range(uv_layers_count):
  1130.                     uv = data.uv_textures[iuvlayer].data[face.index].uv1
  1131.                     temp_buf.append(write_float_couple(uv[0], 1-uv[1]) ) # U, V
  1132.             elif vertex_id == 1:
  1133.                 for iuvlayer in range(uv_layers_count):
  1134.                     uv = data.uv_textures[iuvlayer].data[face.index].uv2
  1135.                     temp_buf.append(write_float_couple(uv[0], 1-uv[1]) ) # U, V
  1136.             elif vertex_id == 2:
  1137.                 for iuvlayer in range(uv_layers_count):
  1138.                     uv = data.uv_textures[iuvlayer].data[face.index].uv3
  1139.                     temp_buf.append(write_float_couple(uv[0], 1-uv[1]) ) # U, V
  1140.             elif vertex_id == 3:
  1141.                 for iuvlayer in range(uv_layers_count):
  1142.                     uv = data.uv_textures[iuvlayer].data[face.index].uv4
  1143.                     temp_buf.append(write_float_couple(uv[0], 1-uv[1]) ) # U, V
  1144.  
  1145.             #f = time.time()
  1146.             #time_in_b3 += f - e
  1147.             # =====================
  1148.  
  1149.    
  1150.     if DEBUG: print("")
  1151.    
  1152.     #c = time.time()
  1153.     #time_in_b += c - b
  1154.     #print("time_in_a = ",time_in_a)
  1155.     #print("time_in_b = ",time_in_b)
  1156.     #print("time_in_b1 = ", time_in_b1)
  1157.     #print("time_in_b2 = ", time_in_b2)
  1158.     #print("time_in_b3 = ", time_in_b3)
  1159.     #print("time_in_b4 = ", time_in_b4)
  1160.  
  1161.     if len(temp_buf) > 0:
  1162.         vrts_buf += write_chunk(b"VRTS",b"".join(temp_buf))
  1163.         temp_buf = []
  1164.  
  1165.     return vrts_buf
  1166.  
  1167. # ==== Write NODE MESH TRIS Chunk ====
  1168. def write_node_mesh_tris(obj, data, obj_count,arm_action,exp_root):
  1169.  
  1170.     global texture_count
  1171.  
  1172.     #FIXME?
  1173.     #orig_uvlayer = data.activeUVLayer
  1174.  
  1175.     # An dictoriary that maps all brush-ids to a list of faces
  1176.     # using this brush. This helps to sort the triangles by
  1177.     # brush, creating less mesh buffer in irrlicht.
  1178.     dBrushId2Face = {}
  1179.    
  1180.     if DEBUG: print("")
  1181.    
  1182.     for face in data.faces:
  1183.         img_found = 0
  1184.         face_stack = []
  1185.        
  1186.         #for iuvlayer,uvlayer in enumerate(data.getUVLayerNames()):
  1187.         for iuvlayer,uvlayer in enumerate(data.uv_textures):
  1188.             if iuvlayer < 8:
  1189.                
  1190.                 if iuvlayer >= len(data.uv_textures):
  1191.                     continue
  1192.  
  1193.                 # Blender 2.5 :
  1194.                 # data.uv_textures[0].data[0].image
  1195.  
  1196.                 img_id = -1
  1197.  
  1198.                 img = data.uv_textures[iuvlayer].data[face.index].image
  1199.                 if img:
  1200.                    
  1201.                     if img.filepath in trimmed_paths:
  1202.                         img_name = trimmed_paths[img.filepath]
  1203.                     else:
  1204.                         img_name = os.path.basename(img.filepath)
  1205.                         trimmed_paths[img.filepath] = img_name
  1206.                    
  1207.                     img_found = 1
  1208.                     if img_name in texs_stack:
  1209.                         img_id = texs_stack[img_name][TEXTURE_ID]
  1210.  
  1211.                 face_stack.insert(iuvlayer,img_id)
  1212.  
  1213.         for i in range(len(face_stack),texture_count):
  1214.             face_stack.append(-1)
  1215.  
  1216.         if img_found == 0:
  1217.             brus_id = -1
  1218.             if data.materials and data.materials[face.material_index]:
  1219.                 mat_name = data.materials[face.material_index].name
  1220.                 for i in range(len(brus_stack)):
  1221.                     if brus_stack[i] == mat_name:
  1222.                         brus_id = i
  1223.                         break
  1224.             else:
  1225.                 for i in range(len(brus_stack)):
  1226.                     if brus_stack[i] == face_stack:
  1227.                         brus_id = i
  1228.                         break
  1229.         else:
  1230.             brus_id = -1
  1231.             for i in range(len(brus_stack)):
  1232.                 if brus_stack[i] == face_stack:
  1233.                     brus_id = i
  1234.                     break
  1235.             if brus_id == -1:
  1236.                 print("Cannot find in brus stack : ", face_stack)
  1237.  
  1238.         if brus_id in dBrushId2Face:
  1239.             dBrushId2Face[brus_id].append(face)
  1240.         else:
  1241.             dBrushId2Face[brus_id] = [face]
  1242.        
  1243.         if DEBUG: print("        <!-- Face",face.index,"in brush",brus_id,"-->")
  1244.    
  1245.     tris_buf = bytearray()
  1246.    
  1247.     if DEBUG: print("")
  1248.     if DEBUG: print("        <!-- TRIS chunk -->")
  1249.    
  1250.     if PROGRESS_VERBOSE: progress = 0
  1251.                
  1252.     for brus_id in dBrushId2Face.keys():
  1253.        
  1254.         if PROGRESS_VERBOSE:
  1255.             progress += 1
  1256.             print("BRUS:",progress,"/",len(dBrushId2Face.keys()))
  1257.        
  1258.         temp_buf = [write_int(brus_id)] #Brush ID
  1259.        
  1260.         if DEBUG: print("        <brush id=", brus_id, ">")
  1261.        
  1262.         if PROGRESS_VERBOSE: progress2 = 0
  1263.                
  1264.         for face in dBrushId2Face[brus_id]:
  1265.            
  1266.             if PROGRESS_VERBOSE:
  1267.                 progress2 += 1
  1268.                 if (progress2 % 50 == 0): print("    TRIS:",progress2,"/",len(dBrushId2Face[brus_id]))
  1269.  
  1270.             vertices = per_face_vertices[face.index]
  1271.  
  1272.             temp_buf.append(write_int(vertices[2])) #A
  1273.             temp_buf.append(write_int(vertices[1])) #B
  1274.             temp_buf.append(write_int(vertices[0])) #C
  1275.  
  1276.             if DEBUG: print("            <face id=", vertices[2], vertices[1], vertices[0],"/> <!-- face",face.index,"-->")
  1277.  
  1278.             if len(face.vertices) == 4:
  1279.                 temp_buf.append(write_int(vertices[3])) #A
  1280.                 temp_buf.append(write_int(vertices[2])) #B
  1281.                 temp_buf.append(write_int(vertices[0])) #C
  1282.                 if DEBUG: print("            <face id=", vertices[3], vertices[2], vertices[0],"/> <!-- face",face.index,"-->")
  1283.  
  1284.         if DEBUG: print("        </brush>")
  1285.         tris_buf += write_chunk(b"TRIS", b"".join(temp_buf))
  1286.  
  1287.     return tris_buf
  1288.  
  1289. # ==== Write NODE ANIM Chunk ====
  1290. def write_node_anim(num_frames):
  1291.     anim_buf = bytearray()
  1292.     temp_buf = bytearray()
  1293.  
  1294.     temp_buf += write_int(0) #Flags
  1295.     temp_buf += write_int(num_frames) #Frames
  1296.     temp_buf += write_float(60) #FPS
  1297.  
  1298.     if len(temp_buf) > 0:
  1299.         anim_buf += write_chunk(b"ANIM",temp_buf)
  1300.         temp_buf = ""
  1301.  
  1302.     return anim_buf
  1303.  
  1304. # ==== Write NODE NODE Chunk ====
  1305. def write_node_node(ibone):
  1306.     node_buf = bytearray()
  1307.     temp_buf = []
  1308.  
  1309.     bone = bone_stack[ibone]
  1310.  
  1311.     matrix = bone[BONE_PARENT_MATRIX]
  1312.     temp_buf.append(write_string(bone[BONE_ITSELF].name)) #Node Name
  1313.  
  1314.     # FIXME: we should use the same matrix format everywhere to not require this
  1315.     position = matrix.to_translation()
  1316.     if not b3d_parameters.get("local-space") and bone[BONE_PARENT]:
  1317.         temp_buf.append(write_float_triplet(-position[0], position[2], position[1]))
  1318.     else:
  1319.         temp_buf.append(write_float_triplet(position[0], position[2], position[1]))
  1320.    
  1321.     scale = matrix.to_scale()
  1322.     temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1]))
  1323.  
  1324.     quat = matrix.to_quaternion()
  1325.     quat.normalize()
  1326.  
  1327.     temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y))
  1328.  
  1329.     temp_buf.append(write_node_bone(ibone))
  1330.     temp_buf.append(write_node_keys(ibone))
  1331.  
  1332.     for iibone in bone_stack:
  1333.         if bone_stack[iibone][BONE_PARENT] == bone_stack[ibone][BONE_ITSELF]:
  1334.             temp_buf.append(write_node_node(iibone))
  1335.  
  1336.     if len(temp_buf) > 0:
  1337.         node_buf += write_chunk(b"NODE", b"".join(temp_buf))
  1338.         temp_buf = []
  1339.  
  1340.     return node_buf
  1341.  
  1342. # ==== Write NODE BONE Chunk ====
  1343. def write_node_bone(ibone):
  1344.     bone_buf = bytearray()
  1345.     temp_buf = []
  1346.  
  1347.     my_name = bone_stack[ibone][BONE_ITSELF].name
  1348.  
  1349.     for ivert in range(len(vertex_groups)):
  1350.         if my_name in vertex_groups[ivert]:
  1351.             vert_influ = vertex_groups[ivert][my_name]
  1352.             if DEBUG: print("        <bone name=",bone_stack[ibone][BONE_ITSELF].name,"face_vertex_id=", ivert + iuv,
  1353.                             " weigth=", vert_influ[1] , "/>")
  1354.             temp_buf.append(write_int(ivert)) # Face Vertex ID
  1355.             temp_buf.append(write_float(vert_influ)) #Weight
  1356.  
  1357.     bone_buf += write_chunk(b"BONE", b"".join(temp_buf))
  1358.     temp_buf = []
  1359.  
  1360.     return bone_buf
  1361.  
  1362. # ==== Write NODE KEYS Chunk ====
  1363. def write_node_keys(ibone):
  1364.     keys_buf = bytearray()
  1365.     temp_buf = []
  1366.  
  1367.     temp_buf.append(write_int(7)) #Flags
  1368.  
  1369.     my_name = bone_stack[ibone][BONE_ITSELF].name
  1370.  
  1371.     for ikeys in range(len(keys_stack)):
  1372.         if keys_stack[ikeys][1] == my_name:
  1373.             temp_buf.append(write_int(keys_stack[ikeys][0])) #Frame
  1374.  
  1375.             position = keys_stack[ikeys][2]
  1376.             # FIXME: we should use the same matrix format everywhere and not require this
  1377.             if b3d_parameters.get("local-space"):
  1378.                 temp_buf.append(write_float_triplet(position[0], position[2], position[1]))
  1379.             else:
  1380.                 temp_buf.append(write_float_triplet(-position[0], position[1], position[2]))
  1381.  
  1382.             scale = keys_stack[ikeys][3]
  1383.             temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2]))
  1384.  
  1385.             quat = keys_stack[ikeys][4]
  1386.             quat.normalize()
  1387.  
  1388.             temp_buf.append(write_float_quad(quat.w, -quat.x, quat.y, quat.z))
  1389.             #break
  1390.  
  1391.     keys_buf += write_chunk(b"KEYS",b"".join(temp_buf))
  1392.     temp_buf = []
  1393.  
  1394.     return keys_buf
  1395.  
  1396.  
  1397. # ==== CONFIRM OPERATOR ====
  1398. class B3D_Confirm_Operator(bpy.types.Operator):
  1399.     bl_idname = ("screen.b3d_confirm")
  1400.     bl_label = ("File Exists, Overwrite?")
  1401.    
  1402.     def invoke(self, context, event):
  1403.         wm = context.window_manager
  1404.         return wm.invoke_props_dialog(self)
  1405.    
  1406.     def execute(self, context):
  1407.         write_b3d_file(B3D_Confirm_Operator.filepath)
  1408.         return {'FINISHED'}
  1409.  
  1410.  
  1411. #class ObjectListItem(bpy.types.PropertyGroup):
  1412. #    id = bpy.props.IntProperty(name="ID")
  1413. #
  1414. #bpy.utils.register_class(ObjectListItem)
  1415.    
  1416. # ==== EXPORT OPERATOR ====
  1417.  
  1418. class B3D_Export_Operator(bpy.types.Operator):
  1419.     bl_idname = ("screen.b3d_export")
  1420.     bl_label = ("B3D Export")
  1421.     filepath = bpy.props.StringProperty(subtype="FILE_PATH")
  1422.  
  1423.     selected = bpy.props.BoolProperty(name="Export Selected Only", default=False)
  1424.     vnormals = bpy.props.BoolProperty(name="Export Vertex Normals", default=True)
  1425.     vcolors  = bpy.props.BoolProperty(name="Export Vertex Colors", default=True)
  1426.     cameras  = bpy.props.BoolProperty(name="Export Cameras", default=False)
  1427.     lights   = bpy.props.BoolProperty(name="Export Lights", default=False)
  1428.     mipmap   = bpy.props.BoolProperty(name="Mipmap", default=False)
  1429.     localsp  = bpy.props.BoolProperty(name="Use Local Space Coords", default=False)
  1430.  
  1431.     overwrite_without_asking  = bpy.props.BoolProperty(name="Overwrite without asking", default=False)
  1432.    
  1433.     #skip_dialog = False
  1434.    
  1435.     #objects = bpy.props.CollectionProperty(type=ObjectListItem, options={'HIDDEN'})
  1436.    
  1437.     def invoke(self, context, event):
  1438.         blend_filepath = context.blend_data.filepath
  1439.         if not blend_filepath:
  1440.             blend_filepath = "Untitled.b3d"
  1441.         else:
  1442.             import os
  1443.             blend_filepath = os.path.splitext(blend_filepath)[0] + ".b3d"
  1444.         self.filepath = blend_filepath
  1445.        
  1446.         context.window_manager.fileselect_add(self)
  1447.         return {'RUNNING_MODAL'}
  1448.    
  1449.     def execute(self, context):
  1450.        
  1451.         global b3d_parameters
  1452.         global the_scene
  1453.         b3d_parameters["export-selected"] = self.selected
  1454.         b3d_parameters["vertex-normals" ] = self.vnormals
  1455.         b3d_parameters["vertex-colors"  ] = self.vcolors
  1456.         b3d_parameters["cameras"        ] = self.cameras
  1457.         b3d_parameters["lights"         ] = self.lights
  1458.         b3d_parameters["mipmap"         ] = self.mipmap
  1459.         b3d_parameters["local-space"    ] = self.localsp
  1460.        
  1461.         the_scene = context.scene
  1462.        
  1463.         if self.filepath == "":
  1464.             return {'FINISHED'}
  1465.  
  1466.         if not self.filepath.endswith(".b3d"):
  1467.             self.filepath += ".b3d"
  1468.  
  1469.         obj_list = []
  1470.         try:
  1471.             # FIXME: silly and ugly hack, the list of objects to export is passed through
  1472.             #        a custom scene property
  1473.             obj_list = context.scene.obj_list
  1474.         except:
  1475.              pass
  1476.        
  1477.         if len(obj_list) > 0:
  1478.          
  1479.             #objlist = []
  1480.             #for a in self.objects:
  1481.             #    objlist.append(bpy.data.objects[a.id])
  1482.             #
  1483.             #write_b3d_file(self.filepath, obj_list)
  1484.            
  1485.             write_b3d_file(self.filepath, obj_list)
  1486.         else:
  1487.             if os.path.exists(self.filepath) and not self.overwrite_without_asking:
  1488.                 #self.report({'ERROR'}, "File Exists")
  1489.                 B3D_Confirm_Operator.filepath = self.filepath
  1490.                 bpy.ops.screen.b3d_confirm('INVOKE_DEFAULT')
  1491.                 return {'FINISHED'}
  1492.             else:
  1493.                 write_b3d_file(self.filepath)
  1494.         return {'FINISHED'}
  1495.  
  1496.  
  1497. # Add to a menu
  1498. def menu_func_export(self, context):
  1499.     global the_scene
  1500.     the_scene = context.scene
  1501.     self.layout.operator(B3D_Export_Operator.bl_idname, text="B3D (.b3d)")
  1502.  
  1503. def register():
  1504.     bpy.types.INFO_MT_file_export.append(menu_func_export)
  1505.     bpy.utils.register_module(__name__)
  1506.  
  1507. def unregister():
  1508.     bpy.types.INFO_MT_file_export.remove(menu_func_export)
  1509.  
  1510. if __name__ == "__main__":
  1511.     register()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement