Advertisement
Guest User

Untitled

a guest
Oct 9th, 2019
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 46.44 KB | None | 0 0
  1. ## ***** BEGIN GPL LICENSE BLOCK *****
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software Foundation,
  15. # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  16. #
  17. # ***** END GPL LICENCE BLOCK *****
  18. #
  19. #
  20. # REQUIRED OPTIONS -
  21. # - Make Normals Consistent
  22. # - Remove Doubles
  23. # **********************************
  24. bl_info = {
  25.     "name": "ASCII Scene Exporter v2.5.9",
  26.     "author": "Richard Bartlett, MCampagnini, scorpion81( copy/separate option, fix for non-udk materials, material name only specification, ui cleanup)",
  27.     "version": ( 2, 5, 9 ),
  28.     "blender": ( 2, 80, 0 ),
  29.     "location": "File > Export > ASCII Scene Export(.ase)",
  30.     "description": "ASCII Scene Export(.ase) v2.5.9",
  31.     "warning": "",
  32.     "wiki_url": "",
  33.     "tracker_url": "",
  34.     "category": "Import-Export"
  35. }
  36.  
  37. """
  38. --  This script is intended to export in the ASE file format for STATIC MESHES ONLY.
  39. --  This script WILL NOT export skeletal meshes, these should be exported using a
  40. --  different file format.
  41.  
  42. --  More Information at http://code.google.com/p/ase-export-vmc/
  43. --  UDK Thread at http://forums.epicgames.com/threads/776986-Blender-2-57-ASE-export
  44. """
  45.  
  46. import os
  47. import bpy
  48. import math
  49. import time
  50.  
  51. # settings
  52. aseFloat = lambda x: '''{0: 0.4f}'''.format( x )
  53. optionScale = 16.0
  54. optionSubmaterials = False
  55. optionSmoothingGroups = True
  56. optionAllowMultiMats = True
  57.  
  58. # ASE components
  59. aseHeader = ''
  60. aseScene = ''
  61. aseMaterials = ''
  62. aseGeometry = ''
  63.  
  64. # Other
  65. matList = []
  66. numMats = 0
  67. currentMatId = 0
  68.  
  69. #== cError ==================================================================
  70. class cError( Exception ):
  71.  
  72.     def __init__( self, message ):
  73.         self.message = message
  74.         print( '\n\n' + message + '\n\n' )
  75.  
  76. #== Header =================================================================
  77. class cHeader:
  78.     def __init__( self ):
  79.         self.comment = "Ascii Scene Exporter v2.51"
  80.  
  81.     def __repr__( self ):
  82.         return '''*3DSMAX_ASCIIEXPORT\t200\n*COMMENT "{0}"\n'''.format( self.comment )
  83.  
  84. #== Scene ==================================================================
  85. class cScene:
  86.     def __init__( self ):
  87.         self.filename = bpy.data.filepath
  88.         self.firstframe = 0
  89.         self.lastframe = 100
  90.         self.framespeed = 30
  91.         self.ticksperframe = 160
  92.         self.backgroundstatic = ''.join( [aseFloat( x ) for x in [0.0, 0.0, 0.0]] )
  93.         self.ambientstatic = ''.join( [aseFloat( x ) for x in [0.0, 0.0, 0.0]] )
  94.  
  95.     def __repr__( self ):
  96.         return '''*SCENE {{\n\t*SCENE_FILENAME "{0}"\
  97.               \n\t*SCENE_FIRSTFRAME {1}\
  98.               \n\t*SCENE_LASTFRAME {2}\
  99.               \n\t*SCENE_FRAMESPEED {3}\
  100.               \n\t*SCENE_TICKSPERFxRAME {4}\
  101.               \n\t*SCENE_BACKGROUND_STATIC {5}\
  102.               \n\t*SCENE_AMBIENT_STATIC {6}\
  103.               \n}}\n'''.format( self.filename, self.firstframe, self.lastframe, self.framespeed, self.ticksperframe, self.backgroundstatic, self.ambientstatic )
  104.  
  105. #== Materials ==============================================================
  106. class cMaterials:
  107.     def __init__( self ):
  108.         global optionSubmaterials
  109.         global matList
  110.         global numMats
  111.  
  112.         self.material_list = []
  113.  
  114.         # Get all of the materials used by non-collision object meshes  
  115.         for object in bpy.context.selected_objects:
  116.             if collisionObject( object ) == True:
  117.                 continue
  118.             elif object.type != 'MESH':
  119.                 continue
  120.             else:
  121.                 print( object.name + ': Constructing Materials' )
  122.                 for slot in object.material_slots:
  123.                     # if the material is not in the material_list, add it
  124.                     if self.material_list.count( slot.material ) == 0:
  125.                         self.material_list.append( slot.material )
  126.                         matList.append( slot.material.name )
  127.  
  128.         self.material_count = len( self.material_list )
  129.         numMats = self.material_count
  130.  
  131.         # Raise an error if there are no materials found
  132.         if self.material_count == 0:
  133.             raise cError( 'Mesh must have at least one applied material' )
  134.         else:
  135.             if ( optionSubmaterials ):
  136.                 self.dump = cSubMaterials( self.material_list )
  137.             else:
  138.                 self.dump = cMultiMaterials( self.material_list )
  139.  
  140.     def __repr__( self ):
  141.         return str( self.dump )
  142. class cMultiMaterials:
  143.     def __init__( self, material_list ):
  144.         self.numMtls = len( material_list )
  145.         # Initialize material information
  146.         self.dump = '''*MATERIAL_LIST {{\
  147.                    \n\t*MATERIAL_COUNT {0}\
  148.                    '''.format( str( self.numMtls ) )
  149.  
  150.         for index, slot in enumerate( material_list ):
  151.             self.dump += '''\n\t*MATERIAL {0} {{\
  152.                            {1}\
  153.                            \n\t}}'''.format( index, cMaterial( slot ) )
  154.  
  155.         self.dump += '\n}'
  156.  
  157.     def __repr__( self ):
  158.         return self.dump
  159. class cSubMaterials:
  160.     def __init__( self, material_list ):
  161.         slot = material_list[0]
  162.         # Initialize material information
  163.         self.dump = '''*MATERIAL_LIST {\
  164.                    \n\t*MATERIAL_COUNT 1\
  165.                    \n\t*MATERIAL 0 {\
  166.                    '''
  167.         self.matDump = ''
  168.         self.name = material_list[0].name
  169.         self.numSubMtls = len( material_list )
  170.         self.diffusemap = cDiffusemap( slot.texture_slots[0] )
  171.         if ( self.numSubMtls > 1 ):
  172.             self.matClass = 'Multi/Sub-Object'
  173.             self.diffuseDump = ''
  174.         else:
  175.             self.matClass = 'Standard'
  176.             self.numSubMtls = 0
  177.             self.diffuseDump = self.diffdump()
  178.         self.ambient = ''.join( [aseFloat( x ) for x in [0.0, 0.0, 0.0]] )
  179.         self.diffuse = ''.join( [aseFloat( x ) for x in slot.diffuse_color] )
  180.         self.specular = ''.join( [aseFloat( x ) for x in slot.specular_color] )
  181.         self.shine = aseFloat( slot.specular_hardness / 511 )
  182.         self.shinestrength = aseFloat( slot.specular_intensity )
  183.         self.transparency = aseFloat( slot.translucency * slot.alpha )
  184.         self.wiresize = aseFloat( 1.0 )
  185.         self.shading = str( material_list[0].specular_shader ).capitalize()
  186.         self.xpfalloff = aseFloat( 0.0 )
  187.         self.xptype = 'Filter'
  188.         self.falloff = 'In'
  189.         self.soften = False
  190.         self.submtls = []
  191.         self.selfillum = aseFloat( material_list[0].emit )
  192.  
  193.         if ( len( material_list ) > 1 ):
  194.             # Build SubMaterials
  195.             for index, slot in enumerate( material_list ):
  196.                 self.matDump += '''\n\t\t*SUBMATERIAL {0} {{\
  197.                                {1}\
  198.                                \n\t\t}}'''.format( index, cMaterial( slot ) )
  199.  
  200.         self.dump += '''\n\t\t*MATERIAL_NAME "{0}"\
  201.                       \n\t\t*MATERIAL_CLASS "{1}"\
  202.                       \n\t\t*MATERIAL_AMBIENT {2}\
  203.                       \n\t\t*MATERIAL_DIFFUSE {3}\
  204.                       \n\t\t*MATERIAL_SPECULAR {4}\
  205.                       \n\t\t*MATERIAL_SHINE {5}\
  206.                       \n\t\t*MATERIAL_SHINESTRENGTH {6}\
  207.                       \n\t\t*MATERIAL_TRANSPARENCY {7}\
  208.                       \n\t\t*MATERIAL_WIRESIZE {8}\
  209.                       \n\t\t*MATERIAL_SHADING {9}\
  210.                       \n\t\t*MATERIAL_XP_FALLOFF {10}\
  211.                       \n\t\t*MATERIAL_SELFILLUM {11}\
  212.                       \n\t\t*MATERIAL_FALLOFF {12}\
  213.                       \n\t\t*MATERIAL_XP_TYPE {13}\
  214.                       {14}\
  215.                       \n\t\t*NUMSUBMTLS {15}\
  216.                       {16}'''.format( self.name, self.matClass, self.ambient, self.diffuse, self.specular, self.shine, self.shinestrength, self.transparency, self.wiresize, self.shading, self.xpfalloff, self.selfillum, self.falloff, self.xptype, self.diffuseDump, self.numSubMtls, self.matDump )
  217.  
  218.  
  219.         self.dump += '\n}'
  220.  
  221.     def diffdump( self ):
  222.         for x in [self.diffusemap]:
  223.             return x
  224.  
  225.     def __repr__( self ):
  226.         return self.dump
  227. class cMaterial:
  228.     def __init__( self, slot ):
  229.         self.dump = ''
  230.         self.name = slot.name
  231.         self.matClass = 'Standard'
  232.         self.ambient = ''.join( [aseFloat( x ) for x in [0.0, 0.0, 0.0]] )
  233.         self.diffuse = ''.join( [aseFloat( x ) for x in slot.diffuse_color] )
  234.         self.specular = ''.join( [aseFloat( x ) for x in slot.specular_color] )
  235.         self.shine = aseFloat( slot.specular_hardness / 511 )
  236.         self.shinestrength = aseFloat( slot.specular_intensity )
  237.         self.transparency = aseFloat( slot.translucency * slot.alpha )
  238.         self.wiresize = aseFloat( 1.0 )
  239.  
  240.         # Material Definition
  241.         self.shading = str( slot.specular_shader ).capitalize()
  242.         self.xpfalloff = aseFloat( 0.0 )
  243.         self.xptype = 'Filter'
  244.         self.falloff = 'In'
  245.         self.soften = False
  246.         self.diffusemap = cDiffusemap(slot) #slot.texture_slots[0] )
  247.         self.submtls = []
  248.         self.selfillum = aseFloat( slot.emit )
  249.         self.dump = '''\n\t\t*MATERIAL_NAME "{0}"\
  250.                       \n\t\t*MATERIAL_CLASS "{1}"\
  251.                       \n\t\t*MATERIAL_AMBIENT {2}\
  252.                       \n\t\t*MATERIAL_DIFFUSE {3}\
  253.                       \n\t\t*MATERIAL_SPECULAR {4}\
  254.                       \n\t\t*MATERIAL_SHINE {5}\
  255.                       \n\t\t*MATERIAL_SHINESTRENGTH {6}\
  256.                       \n\t\t*MATERIAL_TRANSPARENCY {7}\
  257.                       \n\t\t*MATERIAL_WIRESIZE {8}\
  258.                       \n\t\t*MATERIAL_SHADING {9}\
  259.                       \n\t\t*MATERIAL_XP_FALLOFF {10}\
  260.                       \n\t\t*MATERIAL_SELFILLUM {11}\
  261.                       \n\t\t*MATERIAL_FALLOFF {12}\
  262.                       \n\t\t*MATERIAL_XP_TYPE {13}\
  263.                       {14}\
  264.                       '''.format( self.name, self.matClass, self.ambient, self.diffuse, self.specular, self.shine, self.shinestrength, self.transparency, self.wiresize, self.shading, self.xpfalloff, self.selfillum, self.falloff, self.xptype, self.diffdump() )
  265.  
  266.     def diffdump( self ):
  267.         for x in [self.diffusemap]:
  268.             return x
  269.  
  270.     def __repr__( self ):
  271.         return self.dump
  272. class cDiffusemap:
  273.     def __init__( self, slot ):
  274.         import os
  275.         self.dump = ''
  276.         if slot is None:
  277.             self.name = 'default'
  278.             self.mapclass = 'Bitmap'
  279.             self.bitmap = 'None'
  280.         else:
  281.             self.name = slot.name
  282.            
  283.             #texture slot
  284.             if hasattr(slot, 'texture'):
  285.                 if slot.texture.type == 'IMAGE':
  286.                     self.mapclass = 'Bitmap'
  287.                     self.bitmap = slot.texture.image.filepath
  288.                     if slot.texture.image.has_data:
  289.                         pass
  290.                     else:
  291.                         self.bitmap = '\\\\base\\' + self.bitmap.replace( '/', '\\' )
  292.                 else:
  293.                     self.mapclass = 'Bitmap'
  294.                     self.bitmap = 'None'
  295.             #material slot
  296.             else:
  297.                 self.mapclass = 'Bitmap'
  298.                 self.bitmap = '\\\\base\\' + self.name.replace( '/', '\\' )
  299.                
  300.         self.subno = 1
  301.         self.amount = aseFloat( 1.0 )
  302.         self.type = 'Screen'
  303.         self.uoffset = aseFloat( 0.0 )
  304.         self.voffset = aseFloat( 0.0 )
  305.         self.utiling = aseFloat( 1.0 )
  306.         self.vtiling = aseFloat( 1.0 )
  307.         self.angle = aseFloat( 0.0 )
  308.         self.blur = aseFloat( 1.0 )
  309.         self.bluroffset = aseFloat( 0.0 )
  310.         self.noiseamt = aseFloat( 1.0 )
  311.         self.noisesize = aseFloat( 1.0 )
  312.         self.noiselevel = 1
  313.         self.noisephase = aseFloat( 0.0 )
  314.         self.bitmapfilter = 'Pyramidal'
  315.  
  316.         self.dump = '''\n\t\t*MAP_DIFFUSE {{\
  317.                       \n\t\t\t*MAP_NAME "{0}"\
  318.                       \n\t\t\t*MAP_CLASS "{1}"\
  319.                       \n\t\t\t*MAP_SUBNO {2}\
  320.                       \n\t\t\t*MAP_AMOUNT {3}\
  321.                       \n\t\t\t*BITMAP "{4}"\
  322.                       \n\t\t\t*MAP_TYPE {5}\
  323.                       \n\t\t\t*UVW_U_OFFSET {6}\
  324.                       \n\t\t\t*UVW_V_OFFSET {7}\
  325.                       \n\t\t\t*UVW_U_TILING {8}\
  326.                       \n\t\t\t*UVW_V_TILING {9}\
  327.                       \n\t\t\t*UVW_ANGLE {10}\
  328.                       \n\t\t\t*UVW_BLUR {11}\
  329.                       \n\t\t\t*UVW_BLUR_OFFSET {12}\
  330.                       \n\t\t\t*UVW_NOUSE_AMT {13}\
  331.                       \n\t\t\t*UVW_NOISE_SIZE {14}\
  332.                       \n\t\t\t*UVW_NOISE_LEVEL {15}\
  333.                       \n\t\t\t*UVW_NOISE_PHASE {16}\
  334.                       \n\t\t\t*BITMAP_FILTER {17}\
  335.                       \n\t\t}}\
  336.                       '''.format( self.name, self.mapclass, self.subno, self.amount, self.bitmap, self.type, self.uoffset, self.voffset, self.utiling, self.vtiling, self.angle, self.blur, self.bluroffset, self.noiseamt, self.noisesize, self.noiselevel, self.noisephase, self.bitmapfilter )
  337.  
  338.     def __repr__( self ):
  339.         return self.dump
  340.  
  341. #== Geometry ===============================================================
  342. class cGeomObject:
  343.     def __init__( self, object ):
  344.         print( object.name + ": Constructing Geometry" )
  345.         global optionAllowMultiMats
  346.         global currentMatId
  347.  
  348.         self.name = object.name
  349.         self.prop_motionblur = 0
  350.         self.prop_castshadow = 1
  351.         self.prop_recvshadow = 1
  352.  
  353.         if optionAllowMultiMats:
  354.             self.material_ref = 0
  355.         else:
  356.             self.material_ref = matList.index( object.material_slots[object.data.polygons[0].material_index].material.name ) #currentMatId
  357.  
  358.         self.nodetm = cNodeTM( object )
  359.         self.mesh = cMesh( object )
  360.  
  361.         self.dump = '''\n*GEOMOBJECT {{\n\t*NODE_NAME "{0}"\n{1}\n{2}\n\t*PROP_MOTIONBLUR {3}\n\t*PROP_CASTSHADOW {4}\n\t*PROP_RECVSHADOW {5}\n\t*MATERIAL_REF {6}\n}}'''.format( self.name, self.nodetm, self.mesh, self.prop_motionblur, self.prop_castshadow, self.prop_recvshadow, self.material_ref )
  362.  
  363.     def __repr__( self ):
  364.         return self.dump
  365. class cNodeTM:
  366.     def __init__( self, object ):
  367.         self.name = object.name
  368.         self.inherit_pos = '0 0 0'
  369.         self.inherit_rot = '0 0 0'
  370.         self.inherit_scl = '0 0 0'
  371.         self.tm_row0 = '1.0000 0.0000 0.0000'
  372.         self.tm_row1 = '0.0000 1.0000 0.0000'
  373.         self.tm_row2 = '0.0000 0.0000 1.0000'
  374.         self.tm_row3 = '0.0000 0.0000 0.0000'
  375.         self.tm_pos = '0.0000 0.0000 0.0000'
  376.         self.tm_rotaxis = '0.0000 0.0000 0.0000'
  377.         self.tm_rotangle = '0.0000'
  378.         self.tm_scale = '1.0000 1.0000 1.0000'
  379.         self.tm_scaleaxis = '0.0000 0.0000 0.0000'
  380.         self.tm_scaleaxisang = '0.0000'
  381.  
  382.         self.dump = '''\t*NODE_TM {{\
  383.                       \n\t\t*NODE_NAME "{0}"\
  384.                       \n\t\t*INHERIT_POS {1}\
  385.                       \n\t\t*INHERIT_ROT {2}\
  386.                       \n\t\t*INHERIT_SCL {3}\
  387.                       \n\t\t*TM_ROW0 {4}\
  388.                       \n\t\t*TM_ROW1 {5}\
  389.                       \n\t\t*TM_ROW2 {6}\
  390.                       \n\t\t*TM_ROW3 {7}\
  391.                       \n\t\t*TM_POS {8}\
  392.                       \n\t\t*TM_ROTAXIS {9}\
  393.                       \n\t\t*TM_ROTANGLE {10}\
  394.                       \n\t\t*TM_SCALE {11}\
  395.                       \n\t\t*TM_SCALEAXIS {12}\
  396.                       \n\t\t*TM_SCALEAXISANG {13}\
  397.                       \n\t}}'''.format( self.name, self.inherit_pos, self.inherit_rot, self.inherit_scl, self.tm_row0, self.tm_row1, self.tm_row2, self.tm_row3, self.tm_pos, self.tm_rotaxis, self.tm_rotangle, self.tm_scale, self.tm_scaleaxis, self.tm_scaleaxisang )
  398.  
  399.     def __repr__( self ):
  400.         return self.dump
  401. class cMesh:
  402.     def __init__( self, object ):
  403.         bpy.ops.mesh.reveal
  404.  
  405.         if collisionObject( object ) == False:
  406.             object.data.uv_textures.active_index = 0
  407.             object.data.uv_texture_stencil_index = 0
  408.             self.tvertlist = cTVertlist( object )
  409.             self.numtvertex = self.tvertlist.length
  410.             self.numtvfaces = len( object.data.uv_texture_stencil.data )
  411.             self.tfacelist = cTFacelist( self.numtvfaces )
  412.             self.uvmapchannels = self.uvdump( object )
  413.  
  414.             # OUTPUT
  415.             self.tvertlist_str = '\n\t\t*MESH_TVERTLIST ' + str( self.tvertlist )
  416.             self.numtvertex_str = '\n\t\t*MESH_NUMTVERTEX ' + str( self.numtvertex )
  417.             self.numtvfaces_str = '\n\t\t*MESH_NUMTVFACES ' + str( self.numtvfaces )
  418.             self.tfacelist_str = '\n\t\t*MESH_TFACELIST ' + str( self.tfacelist )
  419.  
  420.         else:
  421.             self.tvertlist_str = ''
  422.             self.numtvertex_str = ''
  423.             self.numtvfaces_str = ''
  424.             self.tfacelist_str = ''
  425.             self.uvmapchannels = ''
  426.  
  427.         self.timevalue = '0'
  428.         self.numvertex = len( object.data.vertices )
  429.         self.numfaces = len( object.data.polygons )
  430.         self.vertlist = cVertlist( object )
  431.         self.facelist = cFacelist( object )
  432.  
  433.         # Vertex Paint
  434.         if len( object.data.vertex_colors ) > 0:
  435.             self.cvertlist = cCVertlist( object )
  436.             self.numcvertex = self.cvertlist.length
  437.             self.numcvfaces = len( object.data.vertex_colors.data.polygons )
  438.             self.cfacelist = cCFacelist( self.numcvfaces )
  439.             # change them into strings now
  440.             self.cvertlist = '\n{0}'.format( self.cvertlist )
  441.             self.numcvertex = '\n\t\t*MESH_NUMCVERTEX {0}'.format( self.numcvertex )
  442.             self.numcvfaces = '\n\t\t*MESH_NUMCVFACES {0}'.format( self.numcvfaces )
  443.             self.cfacelist = '\n{0}'.format( self.cfacelist )
  444.         else:
  445.             self.cvertlist = ''
  446.             self.numcvertex = ''
  447.             self.numcvfaces = ''
  448.             self.cfacelist = ''
  449.  
  450.         self.normals = cNormallist( object )
  451.  
  452.     # get uv layer names for specified object
  453.     def getUVLayerNames( self, object ):
  454.         self.uvLayerNames = []
  455.         obj = object.data
  456.         for uv in obj.uv_textures.keys():
  457.             self.uvLayerNames.append( str( uv ) )
  458.  
  459.     def uvdump( self, object ):
  460.         self.mappingchannels = ''
  461.         # if there is more than 1 uv layer
  462.         if collisionObject( object ) == False:
  463.             self.getUVLayerNames( object )
  464.             if len( self.uvLayerNames ) > 1:
  465.                 # save uv actives
  466.                 active_uv = object.data.uv_textures.active_index
  467.                 obj = object.data
  468.                 activeUV = 0
  469.                 for uvname in self.uvLayerNames:
  470.                     if activeUV == 0:
  471.                         activeUV += 1
  472.                         continue
  473.                     obj.uv_textures.active_index = activeUV
  474.                     obj.uv_texture_stencil_index = activeUV
  475.                     self.uvm_tvertlist = cTVertlist( object )
  476.                     self.uvm_numtvertex = self.uvm_tvertlist.length
  477.                     self.uvm_numtvfaces = len( object.data.uv_texture_stencil.data )
  478.                     self.uvm_tfacelist = cTFacelist( self.uvm_numtvfaces )
  479.  
  480.                     # if len(object.data.vertex_colors) > 0:
  481.                         # self.uvm_cvertlist = cCVertlist(object)
  482.                         # self.uvm_numcvertex = self.uvm_cvertlist.length
  483.                         # self.uvm_numcvfaces = len(object.data.vertex_colors[0].data)
  484.                         # self.uvm_cfacelist = cCFacelist(self.uvm_numcvfaces)
  485.  
  486.                         # self.uvm_cvertlist = '\n{0}'.format(self.uvm_cvertlist)
  487.                         # self.uvm_numcvertex = '\n\t\t*MESH_NUMCVERTEX {0}'.format(self.uvm_numcvertex)
  488.                         # self.uvm_numcvfaces = '\n\t\t*MESH_NUMCVFACES {0}'.format(self.uvm_numcvfaces)
  489.                         # self.uvm_cfacelist = '\n{0}'.format(self.uvm_cfacelist)
  490.                     # else:
  491.                     self.uvm_numcvertex = ''
  492.                     self.uvm_numcvfaces = ''
  493.                     self.uvm_cvertlist = ''
  494.                     self.uvm_cfacelist = ''
  495.  
  496.                     # print extra mapping channels
  497.                     self.mappingchannels += '''\n\t\t*MESH_MAPPINGCHANNEL {0} {{\n\t\t\t*MESH_NUMTVERTEX {1}\n\t\t\t*MESH_TVERTLIST {2}\n\t\t*MESH_NUMTVFACES {3}\n\t\t*MESH_TFACELIST {4}{5}{6}{7}{8}\n\t\t}}'''.format( str( activeUV + 1 ), self.uvm_numtvertex, self.uvm_tvertlist, self.uvm_numtvfaces, self.uvm_tfacelist, self.uvm_numcvertex, self.uvm_cvertlist, self.uvm_numcvfaces, self.uvm_cfacelist )
  498.                     activeUV = activeUV + 1
  499.  
  500.                 # restore uv actives
  501.                 object.data.uv_textures.active_index = active_uv
  502.  
  503.         return self.mappingchannels
  504.  
  505.     # UV textures go AFTER MESH_FACE_LIST
  506.     # MESH_NUMTVERTEX, MESH_TVERTLIST, MESH_NUMTVFACES, MESH_TFACELIST        
  507.     def __repr__( self ):
  508.         temp = '''\t*MESH {{\n\t\t*TIMEVALUE {0}\n\t\t*MESH_NUMVERTEX {1}\n\t\t*MESH_NUMFACES {2}\n\t\t*MESH_VERTEX_LIST {3}\n\t\t*MESH_FACE_LIST {4}{5}{6}{7}{8}{9}{10}{11}{12}{13}\n{14}\n\t}}'''.format( self.timevalue, self.numvertex, self.numfaces, self.vertlist, self.facelist, self.numtvertex_str, self.tvertlist_str, self.numtvfaces_str, self.tfacelist_str, self.numcvertex, self.cvertlist, self.numcvfaces, self.cfacelist, self.uvmapchannels, self.normals )
  509.         return temp
  510. class cVertlist:
  511.     def __init__( self, object ):
  512.         self.vertlist = []
  513.         for data in object.data.vertices:
  514.             temp = cVert( data.index, data.co.to_tuple( 4 ) )
  515.             self.vertlist.append( temp )
  516.  
  517.     def dump( self ):
  518.         temp = ''
  519.         for x in self.vertlist:
  520.             temp += str( x )
  521.         return temp
  522.  
  523.     def __repr__( self ):
  524.         return '''{{\n{0}\t\t}}'''.format( self.dump() )
  525. class cVert:
  526.     def __init__( self, index, coord ):
  527.         global optionScale
  528.  
  529.         self.index = index
  530.         self.x = aseFloat( coord[0] * optionScale )
  531.         self.y = aseFloat( coord[1] * optionScale )
  532.         self.z = aseFloat( coord[2] * optionScale )
  533.  
  534.     def __repr__( self ):
  535.         return '''\t\t\t*MESH_VERTEX {0} {1} {2} {3}\n'''.format( self.index, self.x, self.y, self.z )
  536. class cFacelist:
  537.     def __init__( self, object ):
  538.         global optionAllowMultiMats
  539.         global matList
  540.         global numMats
  541.         global currentMatId
  542.  
  543.         self.facelist = []
  544.         sgID = 0
  545.  
  546.         # Define smoothing groups (if enabled)
  547.         if ( collisionObject( object ) == False ):
  548.             if ( optionSmoothingGroups ):
  549.                 self.smoothing_groups = defineSmoothing( self, object )
  550.             else:
  551.                 self.smoothing_groups = ''
  552.  
  553.         for face in object.data.polygons:
  554.             if optionAllowMultiMats:
  555.                 if ( collisionObject( object ) == False ):
  556.                     self.matid = matList.index( object.material_slots[face.material_index].material.name )
  557.                 else:
  558.                     self.matid = 0
  559.             else:
  560.                 self.matid = currentMatId
  561.             if ( collisionObject( object ) == False ):
  562.                 if ( optionSmoothingGroups ):
  563.                     for group in self.smoothing_groups:
  564.                         if group.count( face.index ) == 0:
  565.                             continue
  566.                         else:
  567.                             #TODO: Compress sg's
  568.                             index = self.smoothing_groups.index( group )
  569.                             sgID = index % 32
  570.  
  571.             temp = '''\t\t\t*MESH_FACE {0}: A: {1} B: {2} C: {3} AB: 0 BC: 0 CA: 0 *MESH_SMOOTHING {4} *MESH_MTLID {5}\n'''.format( face.index, face.vertices[0], face.vertices[1], face.vertices[2], sgID, self.matid )
  572.             self.facelist.append( temp )
  573.  
  574.         #if currentMatId < numMats - 1:
  575.         #    currentMatId += 1
  576.         #else:
  577.         #    currentMatId = 0
  578.         #currentMatId = matList.index( object.material_slots[0].material.name )
  579.  
  580.     def dump( self ):
  581.         temp = ''
  582.         for x in self.facelist:
  583.             temp = temp + str( x )
  584.         return temp
  585.  
  586.     def __repr__( self ):
  587.         return '''{{\n{0}\t\t}}'''.format( self.dump() )
  588. class cTVertlist:
  589.     def __init__( self, object ):
  590.         self.vertlist = []
  591.  
  592.         # update tessface
  593.         mesh = object.data
  594.         mesh.update( calc_tessface = True )
  595.         uv_layers_count = len( object.data.tessface_uv_textures )
  596.  
  597.         for index, face in enumerate( object.data.tessfaces ):
  598.             if len( object.data.tessface_uv_textures ) == 0:
  599.                 raise cError( "cError:  No UV texture data for " + object.name )
  600.             else:
  601.                 temp = cTVert( ( index * 3 ), object.data.tessface_uv_textures[object.data.uv_textures.active_index].data[face.index].uv1 )
  602.                 self.vertlist.append( temp )
  603.                 temp = cTVert( ( index * 3 ) + 1, object.data.tessface_uv_textures[object.data.uv_textures.active_index].data[face.index].uv2 )
  604.                 self.vertlist.append( temp )
  605.                 temp = cTVert( ( index * 3 ) + 2, object.data.tessface_uv_textures[object.data.uv_textures.active_index].data[face.index].uv3 )
  606.                 self.vertlist.append( temp )
  607.  
  608.         self.length = len( self.vertlist )
  609.  
  610.     def dump( self ):
  611.         temp = ''
  612.         for x in self.vertlist:
  613.             temp += str( x )
  614.         return temp
  615.  
  616.     def __repr__( self ):
  617.         return '''{{\n{0}\t\t}}'''.format( self.dump() )
  618. class cTVert:
  619.     def __init__( self, index, coord ):
  620.         self.index = index
  621.         self.u = aseFloat( coord[0] )
  622.         self.v = aseFloat( coord[1] )
  623.  
  624.     def __repr__( self ):
  625.         return '''\t\t\t*MESH_TVERT {0} {1} {2} 0.0000\n'''.format( self.index, self.u, self.v )
  626. class cTFacelist:
  627.     def __init__( self, facecount ):
  628.         self.facelist = []
  629.         for data in range( facecount ):
  630.             temp = cTFace( data )
  631.             self.facelist.append( temp )
  632.  
  633.     def dump( self ):
  634.         temp = ''
  635.         for x in self.facelist:
  636.             temp = temp + str( x )
  637.         return temp
  638.  
  639.     def __repr__( self ):
  640.         return '''{{\n{0}\t\t}}'''.format( self.dump() )
  641. class cTFace:
  642.     def __init__( self, x ):
  643.         self.index = x
  644.         self.vertices = []
  645.         self.vertices.append( x * 3 )
  646.         self.vertices.append( ( x * 3 ) + 1 )
  647.         self.vertices.append( ( x * 3 ) + 2 )
  648.  
  649.     def __repr__( self ):
  650.         return '''\t\t\t*MESH_TFACE {0} {1} {2} {3}\n'''.format( self.index, self.vertices[0], self.vertices[1], self.vertices[2] )
  651. class cCVertlist:
  652.     def __init__( self, object ):
  653.         self.vertlist = []
  654.         self.index = 0
  655.  
  656.         # Blender 2.63+
  657.         bpy.ops.object.mode_set( mode = 'OBJECT' )
  658.         object.data.calc_tessface()
  659.  
  660.         for face in object.data.tessfaces:
  661.             temp = object.data.tessface_vertex_colors[0].data[face.index].color1
  662.             self.vertlist.append( cCVert( self.index, temp ) )
  663.             temp = object.data.tessface_vertex_colors[0].data[face.index].color2
  664.             self.vertlist.append( cCVert( self.index + 1, temp ) )
  665.             temp = object.data.tessface_vertex_colors[0].data[face.index].color3
  666.             self.vertlist.append( cCVert( self.index + 2, temp ) )
  667.             self.index += 3
  668.  
  669.         self.length = len( self.vertlist )
  670.  
  671.     def dump( self ):
  672.         temp = ''
  673.         for x in self.vertlist:
  674.             temp = temp + str( x )
  675.         return temp
  676.  
  677.     def __repr__( self ):
  678.         return '''\t\t*MESH_CVERTLIST {{\n{0}\t\t}}'''.format( self.dump() )
  679. class cCVert:
  680.     def __init__( self, index, temp ):
  681.         self.index = index
  682.         self.r = aseFloat( float( temp[0] ) )
  683.         self.g = aseFloat( float( temp[1] ) )
  684.         self.b = aseFloat( float( temp[2] ) )
  685.  
  686.     def __repr__( self ):
  687.         return '''\t\t\t*MESH_VERTCOL {0} {1} {2} {3}\n'''.format( self.index, self.r, self.g, self.b )
  688. class cCFacelist:
  689.     def __init__( self, facecount ):
  690.         temp = [0 for x in range( facecount )]
  691.         self.facelist = []
  692.         for index, data in enumerate( temp ):
  693.             self.facelist.append( cCFace( index, data ) )
  694.  
  695.     def dump( self ):
  696.         temp = ''
  697.         for x in self.facelist:
  698.             temp = temp + str( x )
  699.         return temp
  700.  
  701.     def __repr__( self ):
  702.         return '''\t\t*MESH_CFACELIST {{\n{0}\t\t}}'''.format( self.dump() )
  703. class cCFace:
  704.     def __init__( self, index, data ):
  705.         self.index = index
  706.         self.vertices = []
  707.         self.vertices.append( index * 3 )
  708.         self.vertices.append( ( index * 3 ) + 1 )
  709.         self.vertices.append( ( index * 3 ) + 2 )
  710.  
  711.     def __repr__( self ):
  712.         return '''\t\t\t*MESH_CFACE {0} {1} {2} {3}\n'''.format( self.index, self.vertices[0], self.vertices[1], self.vertices[2] )
  713. class cNormallist:
  714.     def __init__( self, object ):
  715.         self.normallist = []
  716.         for face in object.data.polygons:
  717.             self.normallist.append( cNormal( face, object ) )
  718.  
  719.     def dump( self ):
  720.         temp = ''
  721.         for x in self.normallist:
  722.             temp = temp + str( x )
  723.         return temp
  724.  
  725.     def __repr__( self ):
  726.         return '''\t\t*MESH_NORMALS {{\n{0}\t\t}}'''.format( self.dump() )
  727. class cNormal:
  728.     def __init__( self, face, object ):
  729.         self.faceindex = face.index
  730.         self.facenormal = [aseFloat( x ) for x in face.normal.to_tuple( 4 )]
  731.         self.vertnormals = []
  732.         for x in face.vertices:
  733.             self.vertnormals.append( [x, [aseFloat( y ) for y in object.data.vertices[x].normal.to_tuple( 4 )]] )
  734.  
  735.     def __repr__( self ):
  736.         return '''\t\t\t*MESH_FACENORMAL {0} {1} {2} {3}\n\t\t\t\t*MESH_VERTEXNORMAL {4} {5} {6} {7}\n\t\t\t\t*MESH_VERTEXNORMAL {8} {9} {10} {11}\n\t\t\t\t*MESH_VERTEXNORMAL {12} {13} {14} {15}\n'''.format( self.faceindex, self.facenormal[0], self.facenormal[1], self.facenormal[2], self.vertnormals[0][0], self.vertnormals[0][1][0], self.vertnormals[0][1][1], self.vertnormals[0][1][2], self.vertnormals[1][0], self.vertnormals[1][1][0], self.vertnormals[1][1][1], self.vertnormals[1][1][2], self.vertnormals[2][0], self.vertnormals[2][1][0], self.vertnormals[2][1][1], self.vertnormals[2][1][2] )
  737.  
  738. #== Smoothing Groups and Helper Methods =================================
  739. def defineSmoothing( self, object ):
  740.     print( object.name + ": Constructing Smoothing Groups" )
  741.  
  742.     seam_edge_list = []
  743.     sharp_edge_list = []
  744.  
  745.     _mode = object.mode
  746.     #ctx = bpy.context.copy()
  747.     #ctx["object"] = object
  748.     #print("MODE: ", _mode)
  749.     #bpy.context.scene.objects.active = object
  750.     bpy.ops.object.mode_set(mode = 'EDIT')
  751.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  752.     setSelMode( 'EDGE' )
  753.  
  754.     # Get seams and clear them
  755.     #bpy.ops.object.mode_set(ctx, mode = 'OBJECT' )
  756.     for edge in object.data.edges:
  757.         if edge.use_seam:
  758.             seam_edge_list.append( edge.index )
  759.             edge.select = True
  760.  
  761.     #bpy.ops.object.mode_set(ctx, mode = 'EDIT' )
  762.     bpy.ops.mesh.select_all( action = 'SELECT' )
  763.     bpy.ops.mesh.mark_seam( clear = True )
  764.  
  765.     # Get sharp edges, convert them to seams
  766.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  767.     #bpy.ops.object.mode_set(ctx, mode = 'OBJECT' )
  768.     for edge in object.data.edges:
  769.         if edge.use_edge_sharp:
  770.             sharp_edge_list.append( edge )
  771.             edge.select = True
  772.  
  773.    # bpy.ops.object.mode_set( mode = 'EDIT' )
  774.     bpy.ops.mesh.mark_seam()
  775.  
  776.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  777.  
  778.     smoothing_groups = []
  779.     face_list = []
  780.  
  781.     mode = getSelMode( self, False )
  782.     setSelMode( 'FACE' )
  783.  
  784.     for face in object.data.polygons:
  785.         face_list.append( face.index )
  786.  
  787.     while len( face_list ) > 0:
  788.         bpy.ops.object.mode_set( mode = 'OBJECT' )
  789.         object.data.polygons[face_list[0]].select = True
  790.         bpy.ops.object.mode_set( mode = 'EDIT' )
  791.         bpy.ops.mesh.select_linked( limit = True )
  792.  
  793.         # TODO - update when API is updated
  794.         selected_faces = getSelectedFaces( self, True )
  795.         smoothing_groups.append( selected_faces )
  796.         for face_index in selected_faces:
  797.             if face_list.count( face_index ) > 0:
  798.                 face_list.remove( face_index )
  799.         bpy.ops.mesh.select_all( action = 'DESELECT' )
  800.  
  801.     setSelMode( mode, False )
  802.  
  803.     # Clear seams created by sharp edges
  804.     #bpy.ops.object.mode_set( mode = 'OBJECT' )
  805.     for edge in object.data.edges:
  806.         if edge.use_seam:
  807.             edge.select = True
  808.  
  809.     #bpy.ops.object.mode_set( mode = 'EDIT' )
  810.     bpy.ops.mesh.mark_seam( clear = True )
  811.  
  812.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  813.     # Restore original uv seams
  814.    # bpy.ops.object.mode_set( mode = 'OBJECT' )
  815.     for edge_index in seam_edge_list:
  816.         object.data.edges[edge_index].select = True
  817.  
  818.    # bpy.ops.object.mode_set( mode = 'EDIT' )
  819.     bpy.ops.mesh.mark_seam()
  820.  
  821.     bpy.ops.object.mode_set(mode = 'OBJECT' )
  822.     print( '\t' + str( len( smoothing_groups ) ) + ' smoothing groups found.' )
  823.     return smoothing_groups
  824.  
  825. #===========================================================================
  826. # // General Helpers
  827. #===========================================================================
  828.  
  829. # Check if the mesh is a collider
  830. # Return True if collision model, else: false
  831. def collisionObject( object ):
  832.     collisionPrefixes = ['UCX_', 'UBX_', 'USX_']
  833.     for prefix in collisionPrefixes:
  834.         if object.name.find( str( prefix ) ) >= 0:
  835.             return True
  836.     return False
  837.  
  838. # Set the selection mode    
  839. def setSelMode( mode, default = True ):
  840.     if default:
  841.         if mode == 'VERT':
  842.             bpy.context.tool_settings.mesh_select_mode = [True, False, False]
  843.         elif mode == 'EDGE':
  844.             bpy.context.tool_settings.mesh_select_mode = [False, True, False]
  845.         elif mode == 'FACE':
  846.             bpy.context.tool_settings.mesh_select_mode = [False, False, True]
  847.         else:
  848.             return False
  849.     else:
  850.         bpy.context.tool_settings.mesh_select_mode = mode
  851.         return True
  852. def getSelMode( self, default = True ):
  853.     if default:
  854.         if bpy.context.tool_settings.mesh_select_mode[0] == True:
  855.             return 'VERT'
  856.         elif bpy.context.tool_settings.mesh_select_mode[1] == True:
  857.             return 'EDGE'
  858.         elif bpy.context.tool_settings.mesh_select_mode[2] == True:
  859.             return 'FACE'
  860.         return False
  861.     else:
  862.         mode = []
  863.         for value in bpy.context.tool_settings.mesh_select_mode:
  864.             mode.append( value )
  865.  
  866.         return mode
  867. def getSelectedFaces( self, index = False ):
  868.     selected_faces = []
  869.     # Update mesh data
  870.     bpy.ops.object.editmode_toggle()
  871.     bpy.ops.object.editmode_toggle()
  872.  
  873.     _mode = bpy.context.scene.objects.active.mode
  874.     bpy.ops.object.mode_set( mode = 'EDIT' )
  875.  
  876.     object = bpy.context.scene.objects.active
  877.     for face in object.data.polygons:
  878.         if face.select == True:
  879.             if index == False:
  880.                 selected_faces.append( face )
  881.             else:
  882.                 selected_faces.append( face.index )
  883.  
  884.     bpy.ops.object.mode_set( mode = _mode )
  885.  
  886.     return selected_faces
  887.  
  888. #== Core ===================================================================
  889.  
  890. from bpy_extras.io_utils import ExportHelper
  891. from bpy.props import StringProperty, BoolProperty, FloatProperty
  892.  
  893. class ExportAse( bpy.types.Operator, ExportHelper ):
  894.     '''Load an Ascii Scene Export File'''
  895.     bl_idname = "export.ase"
  896.     bl_label = "Export"
  897.     __doc__ = "Ascii Scene Exporter (.ase)"
  898.     filename_ext = ".ase"
  899.     filter_glob : StringProperty( default = "*.ase", options = {'HIDDEN'} )
  900.  
  901.     filepath : StringProperty(
  902.         name = "File Path",
  903.         description = "File path used for exporting the ASE file",
  904.         maxlen = 1024,
  905.         default = "" )
  906.  
  907.     option_triangulate : BoolProperty(
  908.             name = "Triangulate",
  909.             description = "Triangulates all exportable objects",
  910.             default = False )
  911.  
  912.     option_normals : BoolProperty(
  913.             name = "Recalculate Normals",
  914.             description = "Recalculate normals before exporting",
  915.             default = True )
  916.  
  917.     option_remove_doubles : BoolProperty(
  918.             name = "Remove Doubles",
  919.             description = "Remove any duplicate vertices before exporting",
  920.             default = True )
  921.  
  922.     option_apply_scale : BoolProperty(
  923.             name = "Scale",
  924.             description = "Apply scale transformation",
  925.             default = True )
  926.  
  927.     option_apply_location : BoolProperty(
  928.             name = "Location",
  929.             description = "Apply location transformation",
  930.             default = True )
  931.  
  932.     option_apply_rotation : BoolProperty(
  933.             name = "Rotation",
  934.             description = "Apply rotation transformation",
  935.             default = True )
  936.  
  937.     option_smoothinggroups = False # BoolProperty(
  938.             #name = "Smoothing Groups",
  939.             #description = "Construct hard edge islands as smoothing groups",
  940.             #default = False )
  941.  
  942.     option_separate : BoolProperty(
  943.             name = "Separate",
  944.             description = "A separate ASE file for every selected object",
  945.             default = False )
  946.    
  947.     # motorsep 01-16-2016
  948.     option_split : BoolProperty(
  949.             name = "Split per material",
  950.             description = "Split object into several per material",
  951.             default = False )
  952.            
  953.     option_submaterials = False #BoolProperty(
  954.             #name = "Use Submaterials (UDK)",
  955.             #description = "Export a single material with multiple sub materials",
  956.             #default = False )
  957.  
  958.     option_allowmultimats = False #BoolProperty(
  959.             #name = "Allow Multiple Materials (UDK)",
  960.             #description = "Allow multiple materials per geometry object",
  961.             #default = False )
  962.  
  963.     option_scale : FloatProperty(
  964.             name = "Scale",
  965.             description = "Object scaling factor (default: 1.0)",
  966.             min = 0.01,
  967.             max = 1000.0,
  968.             soft_min = 0.01,
  969.             soft_max = 1000.0,
  970.             default = 16.0 )
  971.    
  972.     option_copy : BoolProperty(
  973.             name = "Export Copy",
  974.             description = "Export a copy of the objects, use e.g. together with triangulate modifier",
  975.             default = True )
  976.  
  977.     def draw( self, context ):
  978.         layout = self.layout
  979.  
  980.         box = layout.box()
  981.         box.label( 'Essentials:' )
  982.         box.prop( self, 'option_triangulate' )
  983.         box.prop( self, 'option_copy')
  984.         box.prop( self, 'option_normals' )
  985.         box.prop( self, 'option_remove_doubles' )
  986.         box.label( "Transformations:" )
  987.         box.prop( self, 'option_apply_scale' )
  988.         box.prop( self, 'option_apply_rotation' )
  989.         box.prop( self, 'option_apply_location' )
  990.         #box.label( "Materials:" )
  991.        # box.prop( self, 'option_submaterials' )
  992.         #box.prop( self, 'option_allowmultimats' )
  993.         box.label( "Advanced:" )
  994.         box.prop( self, 'option_scale' )
  995.         box.prop( self, 'option_separate')
  996.         box.prop( self, 'option_split')                # motorsep 01-16-2016
  997.         #box.prop( self, 'option_smoothinggroups' )
  998.        
  999.     @classmethod
  1000.     def poll( cls, context ):
  1001.         active = context.active_object
  1002.         selected = context.selected_objects
  1003.         camera = context.scene.camera
  1004.         ok = selected or camera
  1005.         return ok
  1006.  
  1007.     def writeASE( self, filename, data ):
  1008.         print( '\nWriting', filename )
  1009.         try:
  1010.             file = open( filename, 'w' )
  1011.         except IOcError:
  1012.             print( 'cError: The file could not be written to. Aborting.' )
  1013.         else:
  1014.             file.write( data )
  1015.             file.close()
  1016.  
  1017.     def execute( self, context ):
  1018.         start = time.clock()
  1019.  
  1020.         global optionScale
  1021.         global optionSubmaterials
  1022.         global optionSmoothingGroups
  1023.         global optionAllowMultiMats
  1024.  
  1025.         global aseHeader
  1026.         global aseScene
  1027.         global aseMaterials
  1028.         global aseGeometry
  1029.  
  1030.         global currentMatId
  1031.         global numMats
  1032.         global matList
  1033.  
  1034.         # Set globals and reinitialize ase components
  1035.         aseHeader = ''
  1036.         aseScene = ''
  1037.         aseMaterials = ''
  1038.         aseGeometry = ''
  1039.  
  1040.         optionScale = self.option_scale
  1041.         optionSubmaterials = self.option_submaterials
  1042.         optionSmoothingGroups = self.option_smoothinggroups
  1043.         optionAllowMultiMats = self.option_allowmultimats
  1044.  
  1045.         matList = []
  1046.         currentMatId = 0
  1047.         numMats = 0
  1048.  
  1049.         # Build ASE Header, Scene
  1050.         print( '\nAscii Scene Export by MCampagnini\n' )
  1051.         print( 'Objects selected: ' + str( len( bpy.context.selected_objects ) ) )
  1052.         aseHeader = str( cHeader() )
  1053.         aseScene = str( cScene() )
  1054.         aseMaterials = str( cMaterials() )
  1055.  
  1056.         # Apply applicable options
  1057.         for object in bpy.context.selected_objects:
  1058.             if object.type == 'MESH':
  1059.                 bpy.context.scene.objects.active = object
  1060.                 object.select = True
  1061.  
  1062.                 # Options
  1063.                 bpy.ops.object.mode_set( mode = 'EDIT' )
  1064.                 if self.option_remove_doubles:
  1065.                     bpy.ops.object.mode_set( mode = 'EDIT' )
  1066.                     bpy.ops.mesh.select_all( action = 'SELECT' )
  1067.                     bpy.ops.mesh.remove_doubles()
  1068.                 if self.option_triangulate:
  1069.                     print( object.name + ': Converting to triangles' )
  1070.                     bpy.ops.mesh.select_all( action = 'SELECT' )
  1071.                     bpy.ops.mesh.quads_convert_to_tris()
  1072.                 if self.option_normals:
  1073.                     print( object.name + ': Recalculating normals' )
  1074.                     bpy.ops.object.mode_set( mode = 'EDIT' )
  1075.                     bpy.ops.mesh.select_all( action = 'SELECT' )
  1076.                     bpy.ops.mesh.normals_make_consistent()
  1077.  
  1078.                 # Transformations
  1079.                 bpy.ops.object.mode_set( mode = 'OBJECT' )
  1080.                 bpy.ops.object.transform_apply( location = self.option_apply_location, rotation = self.option_apply_rotation, scale = self.option_apply_scale )
  1081.  
  1082.                 #Construct ASE Geometry Nodes
  1083.                
  1084.                 aseGeom = ''
  1085.                 #Copy object by creating a new mesh from it, applying modifiers
  1086.                
  1087.                 if (self.option_copy):
  1088.                     orig_mesh = object.data
  1089.                     meshes = [bpy.data.meshes.new_from_object(context.scene, object, True, 'PREVIEW')]
  1090.  
  1091.                     if self.option_split:
  1092.                         import bmesh
  1093.  
  1094.                         object.data = meshes[0]
  1095.                         bpy.ops.object.mode_set(mode = 'EDIT')
  1096.                         meshes = []
  1097.  
  1098.                         bm = bmesh.from_edit_mesh(object.data)
  1099.                         for midx, mslot in enumerate(object.material_slots):
  1100.                             mat = mslot.material
  1101.                             if mat:
  1102.                                 bm_new = bm.copy()
  1103.                                 faces = None
  1104.                                 for f in bm_new.faces:
  1105.                                     if f.material_index == midx:
  1106.                                         # type=201 = material
  1107.                                         faces = set(bmesh.ops.similar_faces(bm_new, faces=[f], type=201)['faces'])
  1108.                                         faces = [f for f in bm_new.faces if f not in faces]
  1109.                                         break
  1110.                                 if faces:
  1111.                                     for f in faces:
  1112.                                         bm_new.faces.remove(f)
  1113.                                     new_mesh = orig_mesh.copy()
  1114.                                     bm_new.to_mesh(new_mesh)
  1115.                                     meshes.append(new_mesh)
  1116.  
  1117.                         bpy.ops.object.mode_set(mode = 'OBJECT')
  1118.                         old_mesh = object.data
  1119.                         object.data = orig_mesh
  1120.                         bpy.data.meshes.remove(old_mesh)
  1121.  
  1122.                     for mesh in meshes:
  1123.                         object.data = mesh
  1124.                         aseGeom += str(cGeomObject(object))
  1125.  
  1126.                     object.data = orig_mesh
  1127.                     for mesh in meshes:
  1128.                         bpy.data.meshes.remove(mesh)
  1129.                 else:
  1130.                     aseGeom = str( cGeomObject( object ) )
  1131.                
  1132.                 if (self.option_separate):
  1133.                     aseModel = ''
  1134.                     aseModel += aseHeader
  1135.                     aseModel += aseScene
  1136.                     aseModel += aseMaterials
  1137.                     aseModel += aseGeom
  1138.  
  1139.                     # Write the ASE file
  1140.                     filename = os.path.dirname(self.filepath)
  1141.                     filename += (os.sep + object.name.replace('.', '_'))
  1142.                     filename += ".ase"
  1143.                     self.writeASE(filename, aseModel )
  1144.                 else:
  1145.                     aseGeometry += aseGeom
  1146.                  
  1147.  
  1148.             else:
  1149.                 continue
  1150.  
  1151.         if (self.option_separate == False):
  1152.             aseModel = ''
  1153.             aseModel += aseHeader
  1154.             aseModel += aseScene
  1155.             aseModel += aseMaterials
  1156.             aseModel += aseGeometry
  1157.  
  1158.             # Write the ASE file
  1159.             self.writeASE( self.filepath, aseModel )
  1160.        
  1161.  
  1162.         lapse = ( time.clock() - start )
  1163.         print( 'Completed in ' + str( lapse ) + ' seconds' )
  1164.  
  1165.         return {'FINISHED'}
  1166.  
  1167. def menu_func( self, context ):
  1168.     self.layout.operator( ExportAse.bl_idname, text = "Ascii Scene Exporter (.ase) v2.5.9" )
  1169.  
  1170. #addonClasses = (
  1171. #    ExportAse,
  1172. #)
  1173.  
  1174. #register, unregister = bpy.utils.register_classes_factory(addonClasses)
  1175.  
  1176. def register():
  1177.     bpy.utils.register_class( ExportAse )
  1178.     bpy.types.TOPBAR_MT_file_export.append( menu_func )
  1179.  
  1180. def unregister():
  1181.     bpy.utils.unregister_class( ExportAse )
  1182.     bpy.types.TOPBAR_MT_file_export.remove( menu_func )
  1183.  
  1184. if __name__ == "__main__":
  1185.     register()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement