Advertisement
Guest User

Untitled

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