Advertisement
Guest User

Untitled

a guest
Oct 9th, 2019
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 46.01 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 = bpy.context.object.data
  590.         mesh.update()
  591.         uv_layers_count = len( mesh.uv_layers )
  592.         mesh.calc_loop_triangles()
  593.  
  594.         for index, face in enumerate( mesh.loop_triangles ):
  595.             if len( mesh.uv_layers ) == 0:
  596.                 raise cError( "cError:  No UV texture data for " + object.name )
  597.             else:
  598.                 temp = cTVert( ( index * 3 ), mesh.uv_layers[mesh.uv_layers.active_index].data[face.index].uv )
  599.                 self.vertlist.append( temp )
  600.                 temp = cTVert( ( index * 3 ) + 1, mesh.uv_layers[mesh.uv_layers.active_index].data[face.index + 1].uv )
  601.                 self.vertlist.append( temp )
  602.                 temp = cTVert( ( index * 3 ) + 2, mesh.uv_layers[mesh.uv_layers.active_index].data[face.index + 2].uv )
  603.                 self.vertlist.append( temp )
  604.  
  605.         self.length = len( self.vertlist )
  606.  
  607.     def dump( self ):
  608.         temp = ''
  609.         for x in self.vertlist:
  610.             temp += str( x )
  611.         return temp
  612.  
  613.     def __repr__( self ):
  614.         return '''{{\n{0}\t\t}}'''.format( self.dump() )
  615. class cTVert:
  616.     def __init__( self, index, coord ):
  617.         self.index = index
  618.         self.u = aseFloat( coord[0] )
  619.         self.v = aseFloat( coord[1] )
  620.  
  621.     def __repr__( self ):
  622.         return '''\t\t\t*MESH_TVERT {0} {1} {2} 0.0000\n'''.format( self.index, self.u, self.v )
  623. class cTFacelist:
  624.     def __init__( self, facecount ):
  625.         self.facelist = []
  626.         for data in range( facecount ):
  627.             temp = cTFace( data )
  628.             self.facelist.append( temp )
  629.  
  630.     def dump( self ):
  631.         temp = ''
  632.         for x in self.facelist:
  633.             temp = temp + str( x )
  634.         return temp
  635.  
  636.     def __repr__( self ):
  637.         return '''{{\n{0}\t\t}}'''.format( self.dump() )
  638. class cTFace:
  639.     def __init__( self, x ):
  640.         self.index = x
  641.         self.vertices = []
  642.         self.vertices.append( x * 3 )
  643.         self.vertices.append( ( x * 3 ) + 1 )
  644.         self.vertices.append( ( x * 3 ) + 2 )
  645.  
  646.     def __repr__( self ):
  647.         return '''\t\t\t*MESH_TFACE {0} {1} {2} {3}\n'''.format( self.index, self.vertices[0], self.vertices[1], self.vertices[2] )
  648. class cCVertlist:
  649.     def __init__( self, object ):
  650.         self.vertlist = []
  651.         self.index = 0
  652.  
  653.         # Blender 2.63+
  654.         bpy.ops.object.mode_set( mode = 'OBJECT' )
  655.         object.data.calc_loop_triangles()
  656.  
  657.         for face in object.data.loop_triangles:
  658.             temp = object.data.vertex_colors[0].data[face.index + 1].color
  659.             self.vertlist.append( cCVert( self.index, temp ) )
  660.             temp = object.data.vertex_colors[0].data[face.index + 2].color
  661.             self.vertlist.append( cCVert( self.index + 1, temp ) )
  662.             temp = object.data.vertex_colors[0].data[face.index + 3].color
  663.             self.vertlist.append( cCVert( self.index + 2, temp ) )
  664.             self.index += 3
  665.  
  666.         self.length = len( self.vertlist )
  667.  
  668.     def dump( self ):
  669.         temp = ''
  670.         for x in self.vertlist:
  671.             temp = temp + str( x )
  672.         return temp
  673.  
  674.     def __repr__( self ):
  675.         return '''\t\t*MESH_CVERTLIST {{\n{0}\t\t}}'''.format( self.dump() )
  676. class cCVert:
  677.     def __init__( self, index, temp ):
  678.         self.index = index
  679.         self.r = aseFloat( float( temp[0] ) )
  680.         self.g = aseFloat( float( temp[1] ) )
  681.         self.b = aseFloat( float( temp[2] ) )
  682.  
  683.     def __repr__( self ):
  684.         return '''\t\t\t*MESH_VERTCOL {0} {1} {2} {3}\n'''.format( self.index, self.r, self.g, self.b )
  685. class cCFacelist:
  686.     def __init__( self, facecount ):
  687.         temp = [0 for x in range( facecount )]
  688.         self.facelist = []
  689.         for index, data in enumerate( temp ):
  690.             self.facelist.append( cCFace( index, data ) )
  691.  
  692.     def dump( self ):
  693.         temp = ''
  694.         for x in self.facelist:
  695.             temp = temp + str( x )
  696.         return temp
  697.  
  698.     def __repr__( self ):
  699.         return '''\t\t*MESH_CFACELIST {{\n{0}\t\t}}'''.format( self.dump() )
  700. class cCFace:
  701.     def __init__( self, index, data ):
  702.         self.index = index
  703.         self.vertices = []
  704.         self.vertices.append( index * 3 )
  705.         self.vertices.append( ( index * 3 ) + 1 )
  706.         self.vertices.append( ( index * 3 ) + 2 )
  707.  
  708.     def __repr__( self ):
  709.         return '''\t\t\t*MESH_CFACE {0} {1} {2} {3}\n'''.format( self.index, self.vertices[0], self.vertices[1], self.vertices[2] )
  710. class cNormallist:
  711.     def __init__( self, object ):
  712.         self.normallist = []
  713.         for face in object.data.polygons:
  714.             self.normallist.append( cNormal( face, object ) )
  715.  
  716.     def dump( self ):
  717.         temp = ''
  718.         for x in self.normallist:
  719.             temp = temp + str( x )
  720.         return temp
  721.  
  722.     def __repr__( self ):
  723.         return '''\t\t*MESH_NORMALS {{\n{0}\t\t}}'''.format( self.dump() )
  724. class cNormal:
  725.     def __init__( self, face, object ):
  726.         self.faceindex = face.index
  727.         self.facenormal = [aseFloat( x ) for x in face.normal.to_tuple( 4 )]
  728.         self.vertnormals = []
  729.         for x in face.vertices:
  730.             self.vertnormals.append( [x, [aseFloat( y ) for y in object.data.vertices[x].normal.to_tuple( 4 )]] )
  731.  
  732.     def __repr__( self ):
  733.         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] )
  734.  
  735. #== Smoothing Groups and Helper Methods =================================
  736. def defineSmoothing( self, object ):
  737.     print( object.name + ": Constructing Smoothing Groups" )
  738.  
  739.     seam_edge_list = []
  740.     sharp_edge_list = []
  741.  
  742.     _mode = object.mode
  743.     #ctx = bpy.context.copy()
  744.     #ctx["object"] = object
  745.     #print("MODE: ", _mode)
  746.     #bpy.context.scene.objects.active = object
  747.     bpy.ops.object.mode_set(mode = 'EDIT')
  748.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  749.     setSelMode( 'EDGE' )
  750.  
  751.     # Get seams and clear them
  752.     #bpy.ops.object.mode_set(ctx, mode = 'OBJECT' )
  753.     for edge in object.data.edges:
  754.         if edge.use_seam:
  755.             seam_edge_list.append( edge.index )
  756.             edge.select = True
  757.  
  758.     #bpy.ops.object.mode_set(ctx, mode = 'EDIT' )
  759.     bpy.ops.mesh.select_all( action = 'SELECT' )
  760.     bpy.ops.mesh.mark_seam( clear = True )
  761.  
  762.     # Get sharp edges, convert them to seams
  763.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  764.     #bpy.ops.object.mode_set(ctx, mode = 'OBJECT' )
  765.     for edge in object.data.edges:
  766.         if edge.use_edge_sharp:
  767.             sharp_edge_list.append( edge )
  768.             edge.select = True
  769.  
  770.    # bpy.ops.object.mode_set( mode = 'EDIT' )
  771.     bpy.ops.mesh.mark_seam()
  772.  
  773.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  774.  
  775.     smoothing_groups = []
  776.     face_list = []
  777.  
  778.     mode = getSelMode( self, False )
  779.     setSelMode( 'FACE' )
  780.  
  781.     for face in object.data.polygons:
  782.         face_list.append( face.index )
  783.  
  784.     while len( face_list ) > 0:
  785.         bpy.ops.object.mode_set( mode = 'OBJECT' )
  786.         object.data.polygons[face_list[0]].select = True
  787.         bpy.ops.object.mode_set( mode = 'EDIT' )
  788.         bpy.ops.mesh.select_linked( limit = True )
  789.  
  790.         # TODO - update when API is updated
  791.         selected_faces = getSelectedFaces( self, True )
  792.         smoothing_groups.append( selected_faces )
  793.         for face_index in selected_faces:
  794.             if face_list.count( face_index ) > 0:
  795.                 face_list.remove( face_index )
  796.         bpy.ops.mesh.select_all( action = 'DESELECT' )
  797.  
  798.     setSelMode( mode, False )
  799.  
  800.     # Clear seams created by sharp edges
  801.     #bpy.ops.object.mode_set( mode = 'OBJECT' )
  802.     for edge in object.data.edges:
  803.         if edge.use_seam:
  804.             edge.select = True
  805.  
  806.     #bpy.ops.object.mode_set( mode = 'EDIT' )
  807.     bpy.ops.mesh.mark_seam( clear = True )
  808.  
  809.     bpy.ops.mesh.select_all( action = 'DESELECT' )
  810.     # Restore original uv seams
  811.    # bpy.ops.object.mode_set( mode = 'OBJECT' )
  812.     for edge_index in seam_edge_list:
  813.         object.data.edges[edge_index].select = True
  814.  
  815.    # bpy.ops.object.mode_set( mode = 'EDIT' )
  816.     bpy.ops.mesh.mark_seam()
  817.  
  818.     bpy.ops.object.mode_set(mode = 'OBJECT' )
  819.     print( '\t' + str( len( smoothing_groups ) ) + ' smoothing groups found.' )
  820.     return smoothing_groups
  821.  
  822. #===========================================================================
  823. # // General Helpers
  824. #===========================================================================
  825.  
  826. # Check if the mesh is a collider
  827. # Return True if collision model, else: false
  828. def collisionObject( object ):
  829.     collisionPrefixes = ['UCX_', 'UBX_', 'USX_']
  830.     for prefix in collisionPrefixes:
  831.         if object.name.find( str( prefix ) ) >= 0:
  832.             return True
  833.     return False
  834.  
  835. # Set the selection mode    
  836. def setSelMode( mode, default = True ):
  837.     if default:
  838.         if mode == 'VERT':
  839.             bpy.context.tool_settings.mesh_select_mode = [True, False, False]
  840.         elif mode == 'EDGE':
  841.             bpy.context.tool_settings.mesh_select_mode = [False, True, False]
  842.         elif mode == 'FACE':
  843.             bpy.context.tool_settings.mesh_select_mode = [False, False, True]
  844.         else:
  845.             return False
  846.     else:
  847.         bpy.context.tool_settings.mesh_select_mode = mode
  848.         return True
  849. def getSelMode( self, default = True ):
  850.     if default:
  851.         if bpy.context.tool_settings.mesh_select_mode[0] == True:
  852.             return 'VERT'
  853.         elif bpy.context.tool_settings.mesh_select_mode[1] == True:
  854.             return 'EDGE'
  855.         elif bpy.context.tool_settings.mesh_select_mode[2] == True:
  856.             return 'FACE'
  857.         return False
  858.     else:
  859.         mode = []
  860.         for value in bpy.context.tool_settings.mesh_select_mode:
  861.             mode.append( value )
  862.  
  863.         return mode
  864. def getSelectedFaces( self, index = False ):
  865.     selected_faces = []
  866.     # Update mesh data
  867.     bpy.ops.object.editmode_toggle()
  868.     bpy.ops.object.editmode_toggle()
  869.  
  870.     _mode = bpy.context.view_layer.objects.active.mode
  871.     bpy.ops.object.mode_set( mode = 'EDIT' )
  872.  
  873.     object = bpy.context.view_layer.objects.active
  874.     for face in object.data.polygons:
  875.         if face.select == True:
  876.             if index == False:
  877.                 selected_faces.append( face )
  878.             else:
  879.                 selected_faces.append( face.index )
  880.  
  881.     bpy.ops.object.mode_set( mode = _mode )
  882.  
  883.     return selected_faces
  884.  
  885. #== Core ===================================================================
  886.  
  887. from bpy_extras.io_utils import ExportHelper
  888. from bpy.props import StringProperty, BoolProperty, FloatProperty
  889.  
  890. class ExportAse( bpy.types.Operator, ExportHelper ):
  891.     '''Load an Ascii Scene Export File'''
  892.     bl_idname = "export.ase"
  893.     bl_label = "Export"
  894.     __doc__ = "Ascii Scene Exporter (.ase)"
  895.     filename_ext = ".ase"
  896.     filter_glob : StringProperty( default = "*.ase", options = {'HIDDEN'} )
  897.  
  898.     filepath : StringProperty(
  899.         name = "File Path",
  900.         description = "File path used for exporting the ASE file",
  901.         maxlen = 1024,
  902.         default = "" )
  903.  
  904.     option_triangulate : BoolProperty(
  905.             name = "Triangulate",
  906.             description = "Triangulates all exportable objects",
  907.             default = True )
  908.  
  909.     option_normals : BoolProperty(
  910.             name = "Recalculate Normals",
  911.             description = "Recalculate normals before exporting",
  912.             default = False )
  913.  
  914.     option_remove_doubles : BoolProperty(
  915.             name = "Remove Doubles",
  916.             description = "Remove any duplicate vertices before exporting",
  917.             default = False )
  918.  
  919.     option_apply_scale : BoolProperty(
  920.             name = "Scale",
  921.             description = "Apply scale transformation",
  922.             default = True )
  923.  
  924.     option_apply_location : BoolProperty(
  925.             name = "Location",
  926.             description = "Apply location transformation",
  927.             default = True )
  928.  
  929.     option_apply_rotation : BoolProperty(
  930.             name = "Rotation",
  931.             description = "Apply rotation transformation",
  932.             default = True )
  933.  
  934.     option_smoothinggroups = False # BoolProperty(
  935.             #name = "Smoothing Groups",
  936.             #description = "Construct hard edge islands as smoothing groups",
  937.             #default = False )
  938.  
  939.     option_separate : BoolProperty(
  940.             name = "Separate",
  941.             description = "A separate ASE file for every selected object",
  942.             default = False )
  943.    
  944.     # motorsep 01-16-2016
  945.     option_split : BoolProperty(
  946.             name = "Split per material",
  947.             description = "Split object into several per material",
  948.             default = False )
  949.            
  950.     option_submaterials = False #BoolProperty(
  951.             #name = "Use Submaterials (UDK)",
  952.             #description = "Export a single material with multiple sub materials",
  953.             #default = False )
  954.  
  955.     option_allowmultimats = False #BoolProperty(
  956.             #name = "Allow Multiple Materials (UDK)",
  957.             #description = "Allow multiple materials per geometry object",
  958.             #default = False )
  959.  
  960.     option_scale : FloatProperty(
  961.             name = "Scale",
  962.             description = "Object scaling factor (default: 1.0)",
  963.             min = 0.01,
  964.             max = 1000.0,
  965.             soft_min = 0.01,
  966.             soft_max = 1000.0,
  967.             default = 1.0 )
  968.    
  969.     option_copy : BoolProperty(
  970.             name = "Export Copy",
  971.             description = "Export a copy of the objects, use e.g. together with triangulate modifier",
  972.             default = True )
  973.  
  974.     def draw( self, context ):
  975.         layout = self.layout
  976.  
  977.         box = layout.box()
  978.         box.label( text = 'Essentials:' )
  979.         box.prop( self, 'option_triangulate' )
  980.         box.prop( self, 'option_copy')
  981.         box.prop( self, 'option_normals' )
  982.         box.prop( self, 'option_remove_doubles' )
  983.         box.label( text = "Transformations:" )
  984.         box.prop( self, 'option_apply_scale' )
  985.         box.prop( self, 'option_apply_rotation' )
  986.         box.prop( self, 'option_apply_location' )
  987.         #box.label( "Materials:" )
  988.        # box.prop( self, 'option_submaterials' )
  989.         #box.prop( self, 'option_allowmultimats' )
  990.         box.label( text = "Advanced:" )
  991.         box.prop( self, 'option_scale' )
  992.         box.prop( self, 'option_separate')
  993.         box.prop( self, 'option_split')                # motorsep 01-16-2016
  994.         #box.prop( self, 'option_smoothinggroups' )
  995.        
  996.     @classmethod
  997.     def poll( cls, context ):
  998.         active = context.active_object
  999.         selected = context.selected_objects
  1000.         camera = context.view_layer.camera
  1001.         ok = selected or camera
  1002.         return ok
  1003.  
  1004.     def writeASE( self, filename, data ):
  1005.         print( '\nWriting', filename )
  1006.         try:
  1007.             file = open( filename, 'w' )
  1008.         except IOcError:
  1009.             print( 'cError: The file could not be written to. Aborting.' )
  1010.         else:
  1011.             file.write( data )
  1012.             file.close()
  1013.  
  1014.     def execute( self, context ):
  1015.         start = time.clock()
  1016.  
  1017.         global optionScale
  1018.         global optionSubmaterials
  1019.         global optionSmoothingGroups
  1020.         global optionAllowMultiMats
  1021.  
  1022.         global aseHeader
  1023.         global aseScene
  1024.         global aseMaterials
  1025.         global aseGeometry
  1026.  
  1027.         global currentMatId
  1028.         global numMats
  1029.         global matList
  1030.  
  1031.         # Set globals and reinitialize ase components
  1032.         aseHeader = ''
  1033.         aseScene = ''
  1034.         aseMaterials = ''
  1035.         aseGeometry = ''
  1036.  
  1037.         optionScale = self.option_scale
  1038.         optionSubmaterials = self.option_submaterials
  1039.         optionSmoothingGroups = self.option_smoothinggroups
  1040.         optionAllowMultiMats = self.option_allowmultimats
  1041.  
  1042.         matList = []
  1043.         currentMatId = 0
  1044.         numMats = 0
  1045.  
  1046.         # Build ASE Header, Scene
  1047.         print( '\nAscii Scene Export by MCampagnini\n' )
  1048.         print( 'Objects selected: ' + str( len( bpy.context.selected_objects ) ) )
  1049.         aseHeader = str( cHeader() )
  1050.         aseScene = str( cScene() )
  1051.         aseMaterials = str( cMaterials() )
  1052.  
  1053.         # Apply applicable options
  1054.         for object in bpy.context.selected_objects:
  1055.             if object.type == 'MESH':
  1056.                 bpy.context.view_layer.objects.active = object
  1057.                 object.select_set(True)
  1058.  
  1059.                 # Options
  1060.                 bpy.ops.object.mode_set( mode = 'EDIT' )
  1061.                 if self.option_remove_doubles:
  1062.                     bpy.ops.object.mode_set( mode = 'EDIT' )
  1063.                     bpy.ops.mesh.select_all( action = 'SELECT' )
  1064.                     bpy.ops.mesh.remove_doubles()
  1065.                 if self.option_triangulate:
  1066.                     print( object.name + ': Converting to triangles' )
  1067.                     bpy.ops.mesh.select_all( action = 'SELECT' )
  1068.                     bpy.ops.mesh.quads_convert_to_tris()
  1069.                 if self.option_normals:
  1070.                     print( object.name + ': Recalculating normals' )
  1071.                     bpy.ops.object.mode_set( mode = 'EDIT' )
  1072.                     bpy.ops.mesh.select_all( action = 'SELECT' )
  1073.                     bpy.ops.mesh.normals_make_consistent()
  1074.  
  1075.                 # Transformations
  1076.                 bpy.ops.object.mode_set( mode = 'OBJECT' )
  1077.                 bpy.ops.object.transform_apply( location = self.option_apply_location, rotation = self.option_apply_rotation, scale = self.option_apply_scale )
  1078.  
  1079.                 #Construct ASE Geometry Nodes
  1080.                
  1081.                 aseGeom = ''
  1082.                 #Copy object by creating a new mesh from it, applying modifiers
  1083.                
  1084.                 if (self.option_copy):
  1085.                     orig_mesh = object.data
  1086.                     meshes = [bpy.data.meshes.new_from_object(object, preserve_all_data_layers=True)]
  1087.  
  1088.                     if self.option_split:
  1089.                         import bmesh
  1090.  
  1091.                         object.data = meshes[0]
  1092.                         bpy.ops.object.mode_set(mode = 'EDIT')
  1093.                         meshes = []
  1094.  
  1095.                         bm = bmesh.from_edit_mesh(object.data)
  1096.                         for midx, mslot in enumerate(object.material_slots):
  1097.                             mat = mslot.material
  1098.                             if mat:
  1099.                                 bm_new = bm.copy()
  1100.                                 faces = None
  1101.                                 for f in bm_new.faces:
  1102.                                     if f.material_index == midx:
  1103.                                         # type=201 = material
  1104.                                         faces = set(bmesh.ops.similar_faces(bm_new, faces=[f], type=201)['faces'])
  1105.                                         faces = [f for f in bm_new.faces if f not in faces]
  1106.                                         break
  1107.                                 if faces:
  1108.                                     for f in faces:
  1109.                                         bm_new.faces.remove(f)
  1110.                                     new_mesh = orig_mesh.copy()
  1111.                                     bm_new.to_mesh(new_mesh)
  1112.                                     meshes.append(new_mesh)
  1113.  
  1114.                         bpy.ops.object.mode_set(mode = 'OBJECT')
  1115.                         old_mesh = object.data
  1116.                         object.data = orig_mesh
  1117.                         bpy.data.meshes.remove(old_mesh)
  1118.  
  1119.                     for mesh in meshes:
  1120.                         object.data = mesh
  1121.                         aseGeom += str(cGeomObject(object))
  1122.  
  1123.                     object.data = orig_mesh
  1124.                     for mesh in meshes:
  1125.                         bpy.data.meshes.remove(mesh)
  1126.                 else:
  1127.                     aseGeom = str( cGeomObject( object ) )
  1128.                
  1129.                 if (self.option_separate):
  1130.                     aseModel = ''
  1131.                     aseModel += aseHeader
  1132.                     aseModel += aseScene
  1133.                     aseModel += aseMaterials
  1134.                     aseModel += aseGeom
  1135.  
  1136.                     # Write the ASE file
  1137.                     filename = os.path.dirname(self.filepath)
  1138.                     filename += (os.sep + object.name.replace('.', '_'))
  1139.                     filename += ".ase"
  1140.                     self.writeASE(filename, aseModel )
  1141.                 else:
  1142.                     aseGeometry += aseGeom
  1143.                  
  1144.  
  1145.             else:
  1146.                 continue
  1147.  
  1148.         if (self.option_separate == False):
  1149.             aseModel = ''
  1150.             aseModel += aseHeader
  1151.             aseModel += aseScene
  1152.             aseModel += aseMaterials
  1153.             aseModel += aseGeometry
  1154.  
  1155.             # Write the ASE file
  1156.             self.writeASE( self.filepath, aseModel )
  1157.        
  1158.  
  1159.         lapse = ( time.clock() - start )
  1160.         print( 'Completed in ' + str( lapse ) + ' seconds' )
  1161.  
  1162.         return {'FINISHED'}
  1163.  
  1164. def menu_func( self, context ):
  1165.     self.layout.operator( ExportAse.bl_idname, text = "Ascii Scene Exporter (.ase) v2.5.9" )
  1166.  
  1167. #addonClasses = (
  1168. #    ExportAse,
  1169. #)
  1170.  
  1171. #register, unregister = bpy.utils.register_classes_factory(addonClasses)
  1172.  
  1173. def register():
  1174.     bpy.utils.register_class( ExportAse )
  1175.     bpy.types.TOPBAR_MT_file_export.append( menu_func )
  1176.  
  1177. def unregister():
  1178.     bpy.utils.unregister_class( ExportAse )
  1179.     bpy.types.TOPBAR_MT_file_export.remove( menu_func )
  1180.  
  1181. if __name__ == "__main__":
  1182.     register()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement