Advertisement
Guest User

blender 2.5 panda3d minimalistic exporter

a guest
Sep 6th, 2011
143
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # -*- coding: utf-8 -*-
  2.  
  3. #------------------------------------------------------------------------------
  4. # panda3d-egg exporter for blender 2.5
  5. #   written by Reto Spoerri (Dez.2010) (rspoerri at nouser dot org)
  6. #------------------------------------------------------------------------------
  7. # whats done:
  8. # - basic material settings (diffuse color and specular and shininess)
  9. # - smooth and flat shaded faces
  10. # - multi-uv maps
  11. # - basic texturing stuff
  12. #------------------------------------------------------------------------------
  13. # missing functionality:
  14. # - face vertex colors
  15. # - bone animations (any animations)
  16. # - uv-wrapping-modes
  17. # - testing
  18. # - double sided vertices
  19. # - interface, currently the output path needs to be defined manually
  20. #------------------------------------------------------------------------------
  21. # known or possible bugs:
  22. # - lots of
  23. #------------------------------------------------------------------------------
  24. # functionality:
  25. #  exports blender 2.5 data as egg file
  26. # how it works:
  27. # (1) the blender node-tree is walked trough (class __init__ functions)
  28. #   - Root
  29. #     - World (not used)
  30. #     - Scene
  31. #       - Object
  32. #         - Object (recursive)
  33. #         - MeshData
  34. #           - Face
  35. #           - Vertex
  36. #           - UvTexture
  37. #             - UvTextureData
  38. #         - Curve (not implemented)
  39. #     - Material
  40. #       - TextureSlot
  41. #         - Texture
  42. # (2) the write funtion of each class goes trough
  43. #   - Materials
  44. #   - Textures
  45. #   - Scene
  46. #     - Object
  47. #       - Object (recursive)
  48. #       - MeshData
  49. #         -> the MeshData.write function converts blender faces and vertices
  50. #            into egg face and vertice data which is then written
  51. #------------------------------------------------------------------------------
  52.  
  53. bl_addon_info = {
  54.     "name": "Export Panda3d Egg Format (.egg)",
  55.     "author": "Reto Spoerri",
  56.     "version": (0, 1),
  57.     "blender": (2, 5, 4),
  58.     "api": 31847,
  59.     "location": "File > Export",
  60.     "description": "Export to the Panda3d Model Format (.x)",
  61.     "warning": "",
  62.     "category": "Import/Export"}
  63.  
  64. pviewBinary = '/Developer/Tools/Panda3D/pview'
  65.  
  66. #------------------------------------------------------------------------------
  67. # dont need to change
  68. #------------------------------------------------------------------------------
  69. import bpy
  70. import subprocess
  71. import os
  72. import time
  73. #from bpy.props import *
  74. from io_utils import ExportHelper
  75.  
  76. eggFilename = 'out-004.egg'
  77. rootFolder = '/Users/rspoerri/Desktop/eggExporter25/'
  78.  
  79. logFilename = 'eggExporter.log'
  80. # number of spaces to indent on each level
  81. indentAdd = 2
  82.  
  83. DEBUG = 2 # 0 disabled, 1 file, 2 print
  84.  
  85. #------------------------------------------------------------------------------
  86. # DEBUG WRITER
  87. #------------------------------------------------------------------------------
  88. class Debug(object):
  89.   def __init__(self):
  90.     if DEBUG == 0:
  91.       pass
  92.     if DEBUG == 1:
  93.       self.debugfile = open(os.path.join(rootFolder, logFilename), 'wt')
  94.       self.write(time.asctime()+":\n")
  95.     if DEBUG == 2:
  96.       pass
  97.  
  98.   def write(self, *text):
  99.     if DEBUG == 1:
  100.       if len(text) == 1 and isinstance(text, str):
  101.         self.debugfile.write(text[0].rstrip()+"\n")
  102.       else:
  103.         self.debugfile.write(str(text)+"\n")
  104.       self.debugfile.flush()
  105.     if DEBUG == 2:
  106.       if len(text) == 1 and isinstance(text, str):
  107.         print(text[0].rstrip()+"\n")
  108.       else:
  109.         print(str(text)+"\n")
  110.  
  111.  
  112.  
  113. debug = Debug()
  114. #------------------------------------------------------------------------------
  115. # SOME FUNCTIONS, taken from the 2.49 exporter
  116. #------------------------------------------------------------------------------
  117. def eggSafeName(s):
  118.   """Function that converts names into something suitable for the egg file format - simply puts " around names that contain spaces and prunes bad characters, replacing them with an underscore."""
  119.   s = s.replace('"','_') # Sure there are more bad characters, but this will do for now.
  120.   if ' ' in s:
  121.     return '"' + s + '"'
  122.   else:
  123.     return s
  124.  
  125. def convertFileNameToPanda(filename):
  126.   """Converts Blender filenames to Panda 3D filenames."""
  127.   path =  filename.replace('//', './').replace('\\', '/')
  128.   if os.name == 'nt' and path.find(':') != -1:
  129.     path = '/'+ path[0].lower() + path[2:]
  130.   return path
  131.  
  132. #------------------------------------------------------------------------------
  133. # A SIMPLE RECURSIVE HIERARCHY
  134. #------------------------------------------------------------------------------
  135. class Node(object):
  136.   def __init__(self, parent):
  137.     self.parent = parent
  138.     self.children = list()
  139.  
  140.   def write(self, recursion):
  141.     eggContent = ''
  142.     for child in self.children:
  143.       eggContent += child.write(recursion+1)
  144.     return eggContent
  145.  
  146. #------------------------------------------------------------------------------
  147. # indent function, prints (argument) number of spaces
  148. #------------------------------------------------------------------------------
  149. def indent(level):
  150.   return level*indentAdd*" "
  151.  
  152. #------------------------------------------------------------------------------
  153. # A BLENDER CURVE
  154. #------------------------------------------------------------------------------
  155. class CurveData(Node):
  156.   def __init__(self, parent, node):
  157.     super(Curve, self).__init__(parent)
  158.  
  159. #------------------------------------------------------------------------------
  160. # A BLENDER VERTEX
  161. #------------------------------------------------------------------------------
  162. class Vertex(Node):
  163.   def __init__(self, parent, vertexNode):
  164.     super(Vertex, self).__init__(parent)
  165.    
  166.     self.index      = vertexNode.index
  167.     # the coordinate system must be in world coordinates
  168.     self.coordinate = (self.parent.parent.worldTransform * vertexNode.co)
  169.     self.normal     = vertexNode.normal[:]
  170.     if vertexNode.normal.length != 0:
  171.       # convert into world coordinates
  172.       self.normal     = (self.parent.parent.worldTransform.rotation_part() * vertexNode.normal).normalize()[:]
  173.  
  174.   def __repr__(self):
  175.     out = 'vertex: %i : %s (%s)\n' % (self.index, " ".join(map(str, self.coordinate)), " ".join(map(str, self.normal)))
  176.     for [uvName, uvData] in self.uvTextures:
  177.       out += "  - uv: %s : %s\n" % (uvName, " ".join(map(str, uvData)))
  178.    
  179.     return out
  180.  
  181.  
  182. #------------------------------------------------------------------------------
  183. # A BLENDER FACE
  184. #------------------------------------------------------------------------------
  185. class Face(Node):
  186.   def __init__(self, parent, faceNode):
  187.     super(Face, self).__init__(parent)
  188.     self.index          = faceNode.index
  189.     self.vertices       = faceNode.vertices[:]
  190.     self.normal         = faceNode.normal[:]
  191.     if faceNode.normal.length != 0:
  192.       # convert into world coordinates
  193.       self.normal      = (self.parent.parent.worldTransform.rotation_part() * faceNode.normal).normalize()[:]
  194.     self.flat_faces     = not faceNode.use_smooth
  195.     self.material_index = faceNode.material_index
  196.  
  197.   def __repr__(self):
  198.     out = 'face: %i : %s (%s)\n' % (self.index, " ".join(map(str, self.vertices)), " ".join(map(str, self.normal)))
  199.     return out
  200.  
  201.  
  202. #------------------------------------------------------------------------------
  203. # A BLENDER MESH
  204. #------------------------------------------------------------------------------
  205. class MeshData(Node):
  206.   def __init__(self, parent, meshDataNode):
  207.     super(MeshData, self).__init__(parent)
  208.    
  209.     self.name = eggSafeName(meshDataNode.name)
  210.     self.materials = list()
  211.     self.textures = list()
  212.     for material in meshDataNode.materials:
  213.       if material:
  214.         self.materials.append(eggSafeName(material.name))
  215.         for texture_slots in material.texture_slots:
  216.           if texture_slots:
  217.             self.textures.append(eggSafeName(texture_slots.name))
  218.    
  219.     # add all faces and remember smooth ones, by default it's set to hard
  220.     self.faces = list()
  221.     for faceNode in meshDataNode.faces:
  222.       self.faces.append(Face(self, faceNode))
  223.    
  224.     # add all vertices
  225.     self.vertices = list()
  226.     for vertexNode in meshDataNode.vertices:
  227.       self.vertices.append(Vertex(self, vertexNode))
  228.    
  229.     self.uvTextures = list()
  230.     for uvTexturesNode in meshDataNode.uv_textures:
  231.       self.uvTextures.append(UvTextures(self, uvTexturesNode))
  232.  
  233.   def write(self, recursion):
  234.    
  235.     eggVertexList = list()
  236.     class EggVertex():
  237.       def __init__(self, index, coordinate, smooth, normal, uvData):
  238.         eggVertexList.append(self)
  239.         self.index = index
  240.         self.coordinate = coordinate
  241.         self.smooth = smooth
  242.         self.normal = normal
  243.         self.uvData = uvData
  244.       def write(self, recursion):
  245.         # hard version
  246.         eggContent  = ""
  247.         eggContent += indent(recursion+1)+"<Vertex> %i {\n" % (self.index)
  248.         eggContent += indent(recursion+2)+"%s\n" % " ".join(map(str, self.coordinate))
  249.         # uv & vertex_color & normal untested
  250.         for uvName, uvCoord in self.uvData:
  251.           eggContent += indent(recursion+2)+"<UV> %s { %s }\n" % (uvName, " ".join(map(str, uvCoord)))
  252.         # without normals these are smooth edges
  253.         if self.smooth:
  254.           eggContent += indent(recursion+2)+"<Normal> { %s }" % " ".join(map(str, self.normal))+"\n"
  255.         # this is not implemented yet
  256.         #if self.vertex_color:
  257.         #  eggContent += indent(recursion+2)+"<RGBA> { %s }" % " ".join(map(str, self.vertex_color))+"\n"
  258.         eggContent += indent(recursion+1)+"}\n"
  259.         return eggContent
  260.    
  261.     eggFaceList = list()
  262.     class EggFace():
  263.       def __init__(self, index, name, vertices, normal, flat, material, textures):
  264.         eggFaceList.append(self)
  265.         self.index = index
  266.         self.name = name
  267.         self.vertices = vertices
  268.         self.normal = normal
  269.         self.flat = flat
  270.         self.material = material
  271.         self.textures = textures
  272.       def write(self, recursion):
  273.         eggContent  = ""
  274.         eggContent += indent(recursion  )+"<Polygon> {\n"
  275.         eggContent += indent(recursion+1)+"<VertexRef> {\n"
  276.         eggContent += indent(recursion+2)+" ".join(map(str, self.vertices))+"\n"
  277.         eggContent += indent(recursion+2)+"<Ref> { %s }\n" % self.name
  278.         eggContent += indent(recursion+1)+"}\n"
  279.         # this makes hard edges, but is overridden by smooth ones (which dont know if it shall be smooth or hard)
  280.         if self.flat:
  281.           eggContent += indent(recursion+1)+"<Normal> { %s }\n" % " ".join(map(str, self.normal))
  282.         if self.material:
  283.           eggContent += indent(recursion+1)+"<MRef> { %s }\n" % self.material
  284.         for texture in self.textures:
  285.           if texture:
  286.             eggContent += indent(recursion+1)+"<TRef> { %s }\n" % texture
  287.         eggContent += indent(recursion)+"}\n"
  288.         return eggContent
  289.    
  290.    
  291.     eggVertexIndex = 0
  292.     for faceId, face in enumerate(self.faces):
  293.       faceIndex    = face.index
  294.       faceVertices = face.vertices
  295.       faceNormal   = face.normal
  296.       faceFlat     = face.flat_faces
  297.       faceMaterial = None
  298.       if face.material_index < len(self.materials):
  299.         faceMaterial = self.materials[face.material_index]
  300.       faceTextures = self.textures
  301.       # list of the vertex id's for the egg file
  302.       eggFaceVertexList = list()
  303.       for faceVerticesId, vertexIndex in enumerate(faceVertices):
  304.         vertex = self.vertices[vertexIndex]
  305.         vertexCoordinate = vertex.coordinate
  306.         vertexNormal = vertex.normal
  307.         vertexSmooth = not faceFlat
  308.         #vertexUv = faceUvs[faceVerticesId]
  309.         uvData   = []
  310.         for uvTexture in self.uvTextures:
  311.           uvData.append([uvTexture.name, uvTexture.uvTextureData[faceIndex].uv[faceVerticesId]])
  312.         if len(uvData) > 0:
  313.           uvData[0][0] = ""
  314.         # create the vertices for the egg file
  315.         EggVertex(eggVertexIndex, vertexCoordinate, vertexSmooth, vertexNormal, uvData)
  316.         eggFaceVertexList.append(eggVertexIndex)
  317.         eggVertexIndex += 1
  318.       # create the faces for the egg file
  319.       EggFace(faceIndex, self.name, eggFaceVertexList, faceNormal, faceFlat, faceMaterial, faceTextures)
  320.    
  321.     # handle vertices first
  322.     eggContent  = ""
  323.     eggContent += indent(recursion)+"<VertexPool> %s {\n" % self.name
  324.     for vertex in eggVertexList:
  325.       eggContent += vertex.write(recursion)
  326.     eggContent += indent(recursion)+"}\n"
  327.    
  328.     # handle faces afterwards
  329.     for face in eggFaceList:
  330.       #if isinstance(childNode, Face):
  331.       eggContent += face.write(recursion)
  332.    
  333.     return eggContent
  334.  
  335.   def __repr__(self):
  336.     ''' for debugging purposes '''
  337.     out = ''
  338.     for c in self.materials:
  339.       out += c.__repr__()+"\n"
  340.     for c in self.faces:
  341.       out += c.__repr__()+"\n"
  342.     for c in self.vertices:
  343.       out += c.__repr__()+"\n"
  344.     for c in self.uvTextures:
  345.       out += c.__repr__()+"\n"
  346.     return out
  347.  
  348.  
  349. #------------------------------------------------------------------------------
  350. # BLENDER OBJECT NODE
  351. #------------------------------------------------------------------------------
  352. class Object(Node):
  353.   def __init__(self, parent, objectNode):
  354.     super(Object, self).__init__(parent)
  355.    
  356.     self.name = eggSafeName(objectNode.name)
  357.     self.worldTransform = objectNode.matrix_world
  358.     self.localTransform = objectNode.matrix_local
  359.    
  360.     # different type of objects
  361.     if objectNode.type == 'MESH':
  362.       self.children.append(MeshData(self, objectNode.data))
  363.     if objectNode.type == 'CURVE':
  364.       self.children.append(CurveData(self, objectNode.data))
  365.    
  366.     # childrens
  367.     for childNode in objectNode.children:
  368.       self.children.append(Object(self, childNode))
  369.  
  370.   def write(self, recursion):
  371.     eggContent = ""
  372.     eggContent += indent(recursion)+"<Group> %s {\n" % (self.name)
  373.     if self.worldTransform:
  374.       eggContent += indent(recursion+1)+"<Transform> {\n"
  375.       eggContent += indent(recursion+2)+"<Matrix4> {\n"
  376.       eggContent += indent(recursion+3)+" ".join(map(str, self.worldTransform[0]))+"\n"
  377.       eggContent += indent(recursion+3)+" ".join(map(str, self.worldTransform[1]))+"\n"
  378.       eggContent += indent(recursion+3)+" ".join(map(str, self.worldTransform[2]))+"\n"
  379.       eggContent += indent(recursion+3)+" ".join(map(str, self.worldTransform[3]))+"\n"
  380.       eggContent += indent(recursion+2)+"}\n"
  381.       eggContent += indent(recursion+1)+"}\n"
  382.     eggContent += super(Object, self).write(recursion)
  383.     eggContent += indent(recursion)+"}\n"
  384.     return eggContent
  385.  
  386.  
  387. #------------------------------------------------------------------------------
  388. # BLENDER SCENE NODE
  389. #------------------------------------------------------------------------------
  390. class Scene(Node):
  391.   def __init__(self, parent, sceneNode):
  392.     super(Scene, self).__init__(parent)
  393.     self.name = eggSafeName(sceneNode.name)
  394.    
  395.     for object in sceneNode.objects:
  396.       if not object.parent: # only handle objects without parents
  397.         self.children.append(Object(self, object))
  398.  
  399.   def write(self, recursion):
  400.     eggContent = ""
  401.     for childNode in self.children:
  402.       eggContent += childNode.write(recursion)
  403.     return eggContent
  404.  
  405.  
  406. #------------------------------------------------------------------------------
  407. # BLENDER WORLD NODE
  408. #------------------------------------------------------------------------------
  409. class World(Node):
  410.   # dont know what worlds are used for...
  411.   def __init__(self, parent, worldNode):
  412.     super(World, self).__init__(parent)
  413.  
  414.   def write(self, recursion):
  415.     eggContent = ""
  416.     for childNode in self.children:
  417.       eggContent += childNode.write(recursion)
  418.     return eggContent
  419.  
  420.  
  421. #------------------------------------------------------------------------------
  422. # THE BLENDER UVTEXTURE (a single entry of a uv)
  423. #------------------------------------------------------------------------------
  424. class UvTextureData(Node):
  425.   def __init__(self, parent, uvTextureDataNode):
  426.     super(UvTextureData, self).__init__(parent)
  427.     self.uv = list()
  428.     for uvCoordinate in uvTextureDataNode.uv:
  429.       self.uv.append(uvCoordinate[:])
  430.  
  431.   def __repr__(self):
  432.     out = ''
  433.     for c in self.uv:
  434.       out += str(c)
  435.     return out
  436.  
  437.  
  438. #------------------------------------------------------------------------------
  439. # THE BLENDER UVTEXTURES
  440. #------------------------------------------------------------------------------
  441. class UvTextures(Node):
  442.   def __init__(self, parent, uvTexturesNode):
  443.     super(UvTextures, self).__init__(parent)
  444.     self.name = uvTexturesNode.name
  445.    
  446.     self.uvTextureData = list()
  447.     for uvTextureDataNode in uvTexturesNode.data:
  448.       self.uvTextureData.append(UvTextureData(self, uvTextureDataNode))
  449.  
  450.   def __repr__(self):
  451.     out = self.name+"\n"
  452.     for c in self.uvTextureData:
  453.       out += c.__repr__()+"\n"
  454.     return out
  455.  
  456.  
  457. #------------------------------------------------------------------------------
  458. # MATERIALS
  459. #------------------------------------------------------------------------------
  460. all_materials = dict()
  461. class Material(Node):
  462.   def __init__(self, parent, materialNode):
  463.     super(Material, self).__init__(parent)
  464.     debug.write("MATERIAL")
  465.     self.name           = eggSafeName(materialNode.name)
  466.     self.diffuse_color  = materialNode.diffuse_color[:]
  467.     specular_intensity  = materialNode.specular_intensity/2.0
  468.     self.specular_color = [
  469.         materialNode.specular_color[0]*specular_intensity,
  470.         materialNode.specular_color[1]*specular_intensity,
  471.         materialNode.specular_color[2]*specular_intensity,
  472.       ]
  473.     self.shininess      = materialNode.specular_hardness/4.0
  474.     self.texture_slot_names = list()
  475.     self.texture_slots = list()
  476.     for texture_slot in materialNode.texture_slots:
  477.       if texture_slot:
  478.         self.texture_slot_names.append(texture_slot.name)
  479.         self.texture_slots.append(TextureSlot(self, texture_slot))
  480.    
  481.     # store in global all_materials
  482.     global all_materials
  483.     all_materials[self.name] = self
  484.    
  485.   def write(self, recursion):
  486.     eggContent = ""
  487.     if self.name:
  488.       eggContent += indent(recursion)+"<Material> %s {\n" % self.name
  489.       if self.diffuse_color:
  490.         eggContent += indent(recursion+1)+"<Scalar> diffr { %f }\n" % self.diffuse_color[0]
  491.         eggContent += indent(recursion+1)+"<Scalar> diffg { %f }\n" % self.diffuse_color[1]
  492.         eggContent += indent(recursion+1)+"<Scalar> diffb { %f }\n" % self.diffuse_color[2]
  493.       if self.specular_color:
  494.         eggContent += indent(recursion+1)+"<Scalar> specr { %f }\n" % self.specular_color[0]
  495.         eggContent += indent(recursion+1)+"<Scalar> specg { %f }\n" % self.specular_color[1]
  496.         eggContent += indent(recursion+1)+"<Scalar> specb { %f }\n" % self.specular_color[2]
  497.       if self.shininess:
  498.         eggContent += indent(recursion+1)+"<Scalar> shininess { %f }\n" % self.shininess
  499.       eggContent += indent(recursion)+"}\n"
  500.     eggContent += super(Material, self).write(recursion+1)
  501.     return eggContent
  502.  
  503. #------------------------------------------------------------------------------
  504. # TEXTURE
  505. # a texture is a subpart of a material[x]->texture_slot[x]->texture
  506. # or directly accessable on the root
  507. #------------------------------------------------------------------------------
  508. all_textures = dict()
  509. class Texture(Node):
  510.   def __init__(self, parent, textureNode):
  511.     super(Texture, self).__init__(parent)
  512.    
  513.     if textureNode.type != 'IMAGE':
  514.       debug.write('texture with invalid type')
  515.    
  516.     all_textures[self.name] = self
  517.    
  518.   def write(self, recursion):
  519.     eggContent = ""
  520.     return eggContent
  521.  
  522. #------------------------------------------------------------------------------
  523. # TEXTURE_SLOT
  524. # it has access to more informations then the texture itself
  525. # it knows about the modes, that the texture is defined to
  526. #------------------------------------------------------------------------------
  527. all_texture_slots = dict()
  528. class TextureSlot(Node):  
  529.   def __init__(self, parent, textureSlotNode):
  530.     super(TextureSlot, self).__init__(parent)
  531.    
  532.     self.name = eggSafeName(textureSlotNode.name)
  533.     #self.texture = Texture(self, textureSlotNode.texture)
  534.    
  535.     self.envType = 'MODULATE' # default
  536.     # "normal" coloring modes
  537.     if textureSlotNode.blend_type == 'MIX':
  538.       self.envType = 'MIX'
  539.       # or when there is a texture on the object already
  540.       #self.envType = 'MODULATE'
  541.     if textureSlotNode.blend_type == 'MULTIPLY':
  542.       self.envType = 'MODULATE'
  543.     if textureSlotNode.blend_type == 'ADD':
  544.       self.envType = 'ADD'
  545.     if textureSlotNode.blend_type == 'SCREEN':
  546.       self.envType = 'DECAL'
  547.     # if it's a normal map
  548.     debug.write("textureSlotNode.use_map_normal", textureSlotNode.use_map_normal)
  549.     if textureSlotNode.use_map_normal:
  550.       debug.write("textureSlotNode.texture.use_normal_map", textureSlotNode.texture.use_normal_map)
  551.       if textureSlotNode.texture.use_normal_map:
  552.         self.envType = 'NORMAL'
  553.       else:
  554.         self.envType = 'HEIGHT'
  555.     # if it's a glossmap
  556.     if textureSlotNode.use_map_specular:
  557.       self.envType = 'GLOSS'
  558.     # if it's a glowmap
  559.     if textureSlotNode.use_map_emit:
  560.       self.envType = 'GLOW'
  561.     debug.write("envtype", self.envType)
  562.    
  563.     self.textureName = eggSafeName(textureSlotNode.texture.name)
  564.     self.textureImageName = None
  565.     self.textureImageFilepath = "INVALID"
  566.    
  567.     self.wrapMode = 'REPEAT'
  568.    
  569.     self.filter = 'LINEAR_MIPMAP_LINEAR'
  570.     if textureSlotNode.texture.use_mipmap:
  571.       if not textureSlotNode.texture.use_interpolation:
  572.         self.filter = 'NEAREST'
  573.    
  574.     if textureSlotNode.texture.image:
  575.       if textureSlotNode.texture.image.source != 'FILE':
  576.         debug.write('texture.image with invalid source')
  577.       if textureSlotNode.texture.image.mapping != 'UV':
  578.         debug.write('texture.image with invalid mapping')
  579.       if textureSlotNode.texture.image.type != 'IMAGE':
  580.         debug.write('texture.image with invalid type')
  581.      
  582.       self.textureImageName = eggSafeName(textureSlotNode.texture.image.name)
  583.       self.textureImageFilepath = textureSlotNode.texture.image.filepath
  584.    
  585.     global all_texture_slots
  586.     debug.write("found texture slot", self.name, self)
  587.     all_texture_slots[self.name] = self
  588.     debug.write("all_texture_slots", all_texture_slots.keys())
  589.    
  590.   def write(self, recursion):
  591.     eggContent = ""
  592.     eggContent += indent(recursion)+"<Texture> %s {\n" % self.textureName
  593.     if self.textureImageFilepath:
  594.       eggContent += indent(recursion+1)+'"%s"\n' % self.textureImageFilepath
  595.     eggContent += indent(recursion+1)+"<Scalar> saved-result { 1 }\n"
  596.     eggContent += indent(recursion+1)+"<Scalar> envtype { %s }\n" % self.envType
  597.     eggContent += indent(recursion+1)+"<Scalar> minfilter { %s }\n" % self.filter
  598.     eggContent += indent(recursion+1)+"<Scalar> magfilter { %s }\n" % self.filter
  599.     eggContent += indent(recursion+1)+"<Scalar> wrap { %s }\n" % self.wrapMode
  600.     eggContent += indent(recursion)+"}\n"
  601.     return eggContent
  602.  
  603. #------------------------------------------------------------------------------
  604. # BLENDER SCENE ROOT
  605. #------------------------------------------------------------------------------
  606. class Root(Node):
  607.   def __init__(self, rootNode):
  608.     super(Root, self).__init__(None)
  609.     for worldNode in rootNode.worlds:
  610.       self.children.append(World(self, worldNode))
  611.     for sceneNode in rootNode.scenes:
  612.       self.children.append(Scene(self, sceneNode))
  613.     for materialNode in rootNode.materials:
  614.       self.children.append(Material(self, materialNode))
  615.     #for textureNode in rootNode.textures:
  616.     #  self.children.append(Texture(self, textureNode))
  617.  
  618.   def write(self, filename):
  619.     outfile = open(filename, 'wt')
  620.     eggContent = ""
  621.     # handle materials first
  622.     for child in self.children:
  623.       if isinstance(child, Material):
  624.         eggContent += child.write(0)
  625.     # handle textures
  626.     global all_texture_slots
  627.     debug.write("final all_texture_slots", all_texture_slots.keys())
  628.     for childName, child in all_texture_slots.items():
  629.       if isinstance(child, TextureSlot):
  630.         debug.write(childName, child)
  631.         eggContent += child.write(0)
  632.     # handle scenes second
  633.     for child in self.children:
  634.       if isinstance(child, Scene):
  635.         eggContent += child.write(0)
  636.     # handle worlds last
  637.     for child in self.children:
  638.       if isinstance(child, World):
  639.         eggContent += child.write(0)
  640.     outfile.write(eggContent)
  641.     outfile.close()
  642.  
  643.  
  644. #------------------------------------------------------------------------------
  645. # BLENDER GUI STUFF
  646. #------------------------------------------------------------------------------
  647. class ExportEgg(bpy.types.Operator):
  648.   '''Export a Panda3d Egg file (.egg)'''
  649.   bl_idname = "export.panda3d_egg"
  650.   bl_label = "Export Panda3d EGG"
  651.   filename_ext = ".egg"
  652.  
  653.   filepath = bpy.props.StringProperty()
  654.   filename = bpy.props.StringProperty()
  655.   directory = bpy.props.StringProperty()
  656.  
  657.   verbose = bpy.props.BoolProperty(
  658.       name="Verbose",
  659.       description="Run the exporter in debug mode.  Check the console for output.",
  660.       default=False
  661.     )
  662.   preview = bpy.props.BoolProperty(
  663.       name="Preview",
  664.       description="View the exported Egg in PView",
  665.       default=True,
  666.     )
  667.  
  668.   def execute(self, context):
  669.     #Append .x if needed
  670.     filepath = self.filepath
  671.     if not filepath.lower().endswith(".egg"):
  672.       filepath += ".egg"
  673.  
  674.     Root(bpy.data).write(filepath)
  675.    
  676.     if self.preview:
  677.       pid = subprocess.Popen([pviewBinary, eggFilename]).pid
  678.    
  679.     return {"FINISHED"}
  680.  
  681.   def invoke(self, context, event):
  682.     if not self.filepath:
  683.       self.filepath = os.path.splitext(context.blend_data.filepath)[0] + self.filename_ext
  684.     context.window_manager.add_fileselect(self)
  685.     return {"RUNNING_MODAL"}
  686.  
  687. def menu_func(self, context):
  688.   default_path = os.path.splitext(bpy.data.filepath)[0] + ".egg"
  689.   self.layout.operator(ExportEgg.bl_idname, text="Panda3d Egg (.egg)").filepath = default_path
  690.  
  691. def register():
  692.   bpy.types.INFO_MT_file_export.append(menu_func)
  693.  
  694. def unregister():
  695.   bpy.types.INFO_MT_file_export.remove(menu_func)
  696.  
  697. if __name__ == "__main__":
  698.   register()
Advertisement
RAW Paste Data Copied
Advertisement