Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Microsoft Permissive License (Ms-PL)
- #
- # This license governs use of the accompanying software. If you use the
- # software, you accept this license. If you do not accept the license, do not
- # use the software.
- #
- # 1. Definitions
- #
- # The terms "reproduce," "reproduction," "derivative works," and "distribution"
- # have the same meaning here as under U.S. copyright law.
- #
- # A "contribution" is the original software, or any additions or changes to the
- # software.
- #
- # A "contributor" is any person that distributes its contribution under this
- # license.
- #
- # "Licensed patents" are a contributor's patent claims that read directly on
- # its contribution.
- #
- # 2. Grant of Rights
- #
- # (A) Copyright Grant- Subject to the terms of this license, including the
- # license conditions and limitations in section 3, each contributor grants you
- # a non-exclusive, worldwide, royalty-free copyright license to reproduce its
- # contribution, prepare derivative works of its contribution, and distribute
- # its contribution or any derivative works that you create.
- #
- # (B) Patent Grant- Subject to the terms of this license, including the license
- # conditions and limitations in section 3, each contributor grants you a non-
- # exclusive, worldwide, royalty-free license under its licensed patents to make,
- # have made, use, sell, offer for sale, import, and/or otherwise dispose of its
- # contribution in the software or derivative works of the contribution in the
- # software.
- #
- # 3. Conditions and Limitations
- #
- # (A) No Trademark License- This license does not grant you rights to use any
- # contributors' name, logo, or trademarks.
- #
- # (B) If you bring a patent claim against any contributor over patents that you
- # claim are infringed by the software, your patent license from such contributor
- # to the software ends automatically.
- #
- # (C) If you distribute any portion of the software, you must retain all
- # copyright, patent, trademark, and attribution notices that are present in the
- # software.
- #
- # (D) If you distribute any portion of the software in source code form, you may
- # do so only under this license by including a complete copy of this license
- # with your distribution. If you distribute any portion of the software in
- # compiled or object code form, you may only do so under a license that complies
- # with this license.
- #
- # (E) The software is licensed "as-is." You bear the risk of using it. The
- # contributors give no express warranties, guarantees or conditions. You may
- # have additional consumer rights under your local laws which this license
- # cannot change. To the extent permitted under your local laws, the contributors
- # exclude the implied warranties of merchantability, fitness for a particular
- # purpose and non-infringement.
- #
- # Co-Author support and thanks too:
- #
- # Robert Ludewig
- # Leslie Godwin
- # Tiaan Geldenhuys
- #
- bl_info = {
- "name": "XAML format (.xaml)",
- "author": "Daniel Lehenbauer and Robert Hogue",
- "version": (0, 0, 48),
- "blender": (2, 71, 0),
- "location": "File > Export > XAML",
- "description": "Export mesh to XAML",
- "warning": "",
- "wiki_url": "https://archive.codeplex.com/?p=xamlexporter",
- "category": "Import-Export"}
- from io import StringIO
- from math import *
- import bpy
- #import Blender
- #from Blender import Scene
- #from Blender import Texture
- #from Blender import Mathutils
- #from Blender import Lamp
- #import BPyMesh
- #import BPyObject
- # Ignore rotations which are less than 1/2 a degree
- _rotationLimit = 0.5
- #
- # Script Configuration
- #
- #def getConfig():
- # return Blender.Registry.GetKey("Xaml_Export", True)
- #def getBatchExportFilename():
- # config = getConfig()
- # if config:
- # return config["Batch_Export"]
- # return;
- #
- # Debug
- #
- TraceLevels = {"None": 0, "Error": 1, "Warning": 2, "Trace": 3, "Verbose": 4}
- DEBUG=TraceLevels["Warning"]
- DEBUG_INDENT=0
- def debugPrint(level, message):
- global DEBUG, DEBUG_INDENT
- if level <= DEBUG:
- for i in range(DEBUG_INDENT):
- print(" "),
- print(message)
- def indent():
- global DEBUG_INDENT
- DEBUG_INDENT += 1
- def unindent():
- global DEBUG_INDENT
- DEBUG_INDENT -= 1
- def verbose(message):
- debugPrint(TraceLevels["Trace"], message)
- def trace(message):
- debugPrint(TraceLevels["Trace"], message)
- def traceMatrix(matrix):
- indent()
- for i in xrange(4):
- str = ""
- for j in xrange(4):
- str += "%f" % matrix[i][j]
- if j < 3: str += ","
- trace(str)
- unindent()
- def warn(message):
- debugPrint(TraceLevels["Warning"], message)
- def error(message):
- debugPrint(TraceLevels["Error"], message)
- #
- # Simple XamlWriter
- #
- class XamlWriter :
- def __init__(self):
- self.indentLevel = 0
- self.tagStack = []
- self.singleLineElement = True
- self.outfile = StringIO()
- def writeIndentation(self):
- for i in range(self.indentLevel):
- self.outfile.write(" ")
- def beginElement(self, name):
- if len(self.tagStack) > 0 and self.singleLineElement:
- self.outfile.write(">\n")
- self.writeIndentation()
- self.singleLineElement = True
- self.indentLevel += 1
- self.outfile.write("<" + name)
- self.tagStack.append(name)
- def endElement(self):
- name = self.tagStack.pop()
- self.indentLevel -= 1
- if self.singleLineElement:
- self.outfile.write("/>\n")
- else:
- self.writeIndentation()
- self.outfile.write("</" + name + ">\n")
- self.singleLineElement = False
- def writeAttribute(self, name, value):
- self.outfile.write(" " + name + '="' + value + '"')
- def writeFragment(self, fragment):
- if fragment == "":
- return
- if len(self.tagStack) > 0 and self.singleLineElement:
- self.outfile.write(">\n")
- self.singleLineElement = False
- lines = fragment.split("\n")
- for line in lines:
- self.writeIndentation()
- self.outfile.write(line)
- self.outfile.write("\n")
- def toString(self):
- return self.outfile.getvalue()
- def writeString(self, str):
- self.outfile.write(str)
- return
- #
- # Math Utility
- #
- def degToRad(angle):
- return angle/180*pi
- def radToDeg(angle):
- return angle*180/pi
- # Mathutils.Euler seems to expect euler angles in degrees where
- # Object.rot is euler angles in radians.
- def rotToEuler(rot):
- return Mathutils.Euler(
- radToDeg(rot[0]),
- radToDeg(rot[1]),
- radToDeg(rot[2]))
- # Blender objects seem to have a rest orientation facing 0,-1,0.
- def rotToDirection(rot):
- euler = rotToEuler(rot)
- matrix = euler.toMatrix()
- restDirection = Mathutils.Vector(0,-1,0)
- return tuple(restDirection * matrix)
- def rotToQuaternion(rot):
- return rot.toQuat()
- #return rotToEuler(rot).toQuat()
- #
- # General Utility
- #
- _usedNames = {}
- def incrementNameUsage(name):
- global _usedNames
- n = 0
- if name in _usedNames:
- n = _usedNames[name]
- n = n + 1
- _usedNames[name] = n
- return n
- def createSafeName(name):
- result = ""
- # CLS identifiers may not begin with a digit
- if name[0].isdigit():
- result = "_"
- # CLS identifiers may contain [_a-zA-Z0-9]
- for i in xrange(len(name)):
- if name[i].isalnum():
- result = result + name[i]
- else:
- result = result + "_"
- n = incrementNameUsage(result)
- if n > 1:
- result = result + "_%d" % n
- return result
- def rgbToHexString(rgb):
- return "#%.2x%.2x%.2x" % (rgb[0]*255, rgb[1]*255, rgb[2]*255)
- def writeXYZ(writer, propertyName, value):
- dimensions = ["X", "Y", "Z"]
- for i in xrange(3):
- writer.writeAttribute(propertyName + dimensions[i], value[i])
- def listToString(format, list):
- str = ""
- spc = ""
- tempLength = 0
- tempstr = ""
- for i in xrange(len(list)):
- tempstr = spc + format % list[i]
- tempLength += len(tempstr)
- str += tempstr
- spc = " "
- if tempLength > 4096 :
- str += "\n"
- tempLength = 0;
- return str
- def compactFloat(number):
- str = "%.6f" % number
- if len(str) == 0 : return str
- backStr = str[-5:]
- frontStr = str[:-5]
- str = frontStr + backStr.rstrip("0")
- return str
- # Runs the contained tuple values through compactFloat() and breaks lines at ~4k chars.
- def listToStringCompact(list):
- str = ""
- spc = ""
- tempLength = 0
- for i in xrange(len(list)):
- tuple = list[i]
- if tempLength > 4096 :
- str += "\n"
- tempLength = 0;
- for j in xrange(len(tuple)) :
- strCompact = compactFloat(tuple[j])
- tempLength += len(strCompact)
- str += spc + compactFloat(tuple[j])
- spc = " "
- return str
- def matrixToString(matrix):
- str = ""
- for i in xrange(4):
- for j in xrange(4):
- str += "%f" % matrix[i][j]
- if j < 3: str += ","
- if i < 3: str += " "
- return str
- def quaternionToString(quat):
- # Blender appears to store quaternions as WXYZ
- return "%f,%f,%f,%f" % (quat[1], quat[2], quat[3], quat[0])
- #
- # Xaml Exporter
- #
- class XamlExporter :
- def __init__(self):
- self.writer = XamlWriter()
- #
- # Transforms
- #
- def writeTranslateTransform(self, writer, loc):
- trace("loc: %f,%f,%f" % tuple(loc))
- if loc[0] == 0 and loc[1] == 0 and loc[2] == 0:
- return False
- writer.beginElement("TranslateTransform3D")
- writeXYZ(writer, "Offset", loc)
- writer.endElement()
- return True
- def writeScaleTransform(self, writer, size):
- trace("size: %f,%f,%f" % tuple(size))
- if size[0] == 1 and size[1] == 1 and size[2] == 1:
- return False
- writer.beginElement("ScaleTransform3D")
- writeXYZ(writer, "Scale", size)
- writer.endElement()
- return True
- def writeQuaternionRotation(self, writer, quaternion):
- # Blender appears to store quaternions as WXYZ
- if quaternion[0] > _quaternionWLimit:
- writer.beginElement("AxisAngleRotation3D")
- writer.endElement()
- return False
- writer.beginElement("AxisAngleRotation3D")
- # Blender appears to store Quaternions in WXYZ order
- len = sqrt(1 - quaternion[0]*quaternion[0])
- x = quaternion[1]/len
- y = quaternion[2]/len
- z = quaternion[3]/len
- angle = radToDeg(2 * acos(quaternion[0]))
- writer.writeAttribute("Axis", "%f,%f,%f" % (x,y,z))
- writer.writeAttribute("Angle", angle)
- writer.endElement()
- return True
- def writeQuaternionRotateTransform(self, writer, quaternion):
- rotationWriter = XamlWriter()
- if not self.writeQuaternionRotation(rotationWriter, quaternion):
- return False
- writer.beginElement("RotateTransform3D")
- writer.beginElement("RotateTransform3D.Rotation")
- writer.writeFragment(rotationWriter.toString())
- writer.endElement()
- writer.endElement()
- return True
- def writeRotateTransform(self, writer, rot):
- trace("rot: %f,%f,%f" % tuple(rot))
- return self.writeQuaternionRotateTransform(writer, rotToQuaternion(rot))
- def writeTransformGroup(self, writer, transformWriter, numTransforms):
- assert(numTransforms >= 0)
- assert(numTransforms > 0 or len(transformWriter.toString()) == 0)
- if numTransforms == 0:
- return False
- if numTransforms > 1:
- writer.beginElement("Transform3DGroup")
- writer.writeFragment(transformWriter.toString())
- if numTransforms > 1:
- writer.endElement()
- return True
- def writeTransforms(self, writer, obj):
- numTransforms = 0
- transformWriter = XamlWriter()
- if self.writeRotateTransform(transformWriter, obj.matrixLocal.rotationPart().toEuler()):
- numTransforms += 1
- if self.writeScaleTransform(transformWriter, obj.matrixLocal.scalePart()):
- numTransforms += 1
- if self.writeTranslateTransform(transformWriter, obj.matrixLocal.translationPart()):
- numTransforms += 1
- return self.writeTransformGroup(writer, transformWriter, numTransforms)
- #
- # Materials
- #
- def writeSolidColorBrush(self, writer, rgbCol):
- trace("rgbCol: %s" % rgbToHexString(rgbCol))
- writer.beginElement("SolidColorBrush")
- writer.writeAttribute("Color", rgbToHexString(rgbCol))
- writer.endElement()
- def writeImageBrush(self, writer, texture):
- assert texture.getType() == "Image"
- textureName = texture.getName()
- image = texture.image
- trace("image: %s" % image.getName())
- trace("filename: %s" % image.filename)
- writer.beginElement("ImageBrush")
- writer.writeAttribute("x:Name", createSafeName("TE_" + textureName))
- writer.writeAttribute("ImageSource", image.filename)
- # By default WPF brush space is relative to the bounds of the
- # texture coordinates. Blender texture coordinates are absolute
- # in the [0,0] - [1,1] range.
- writer.writeAttribute("ViewportUnits", "Absolute")
- # The default WPF brush space has (0,0) in the upper left corner.
- # Blender's UV space has (0,0) in the bottom left corner.
- writer.writeAttribute("Transform", "1,0,0,-1,0,1")
- # Blender handles texture coordinates outside of the [0,0] - [1,1]
- # range by tiling. We need to enable this behavior in WPF.
- writer.writeAttribute("TileMode", "Tile")
- writer.endElement()
- def writeMaterial(self, writer, material):
- if material == None:
- return False
- materialName = material.getName()
- trace("Material ('%s'):" % materialName)
- indent()
- writer.beginElement("DiffuseMaterial")
- writer.writeAttribute("x:Name", createSafeName("MA_" + materialName))
- writer.beginElement("DiffuseMaterial.Brush")
- foundTexture = False
- for mTex in material.getTextures():
- if mTex != None:
- texture = mTex.tex
- trace("Texture ('%s'):" % texture.getName())
- indent()
- textureType = texture.getType()
- if textureType == "Image":
- self.writeImageBrush(writer, texture)
- foundTexture = True
- elif textureType != "None":
- warn("Skipping unsupported Texture type: '%s'" % textureType)
- unindent()
- if foundTexture == False:
- trace("Texture not found for Material '%s', falling back to solid color." % materialName)
- self.writeSolidColorBrush(writer, material.rgbCol)
- writer.endElement()
- writer.endElement()
- unindent()
- return True
- def writeDefaultMaterial(self, writer):
- writer.beginElement("DiffuseMaterial")
- writer.beginElement("DiffuseMaterial.Brush")
- self.writeSolidColorBrush(writer, [0.8, 0.8, 0.8])
- writer.endElement()
- writer.endElement()
- def writeMaterials(self, writer, mesh):
- numMaterials = 0
- materialWriter = XamlWriter()
- for material in mesh.materials:
- if self.writeMaterial(materialWriter, material):
- numMaterials += 1
- if numMaterials == 0:
- warn("No material found for mesh '%s'. Using default material." % mesh.name)
- self.writeDefaultMaterial(writer)
- return True
- if numMaterials > 1:
- writer.beginElement("MaterialGroup")
- writer.writeFragment(materialWriter.toString())
- if numMaterials > 1:
- writer.endElement()
- return True
- #
- # Mesh
- #
- def writeMesh(self, meshObj):
- objectName = meshObj.getName()
- trace("Object ('%s'):" % objectName)
- indent()
- scn = Scene.GetCurrent()
- mesh = BPyMesh.getMeshFromObject(meshObj, None, True, False, scn)
- if not mesh:
- return
- meshName = mesh.name
- trace("Mesh ('%s'):" % meshName)
- indent()
- positions = []
- normals = []
- textureCoordinates = []
- triangleIndices = []
- # WPF does not currently support indexed normals or texture coordinates.
- # To work around this we split the vertices for each face. In order
- # to correlate the original indices with the WPF indices we maintain a
- # dictionary which maps each Blender index to a list of WPF indices.
- indexMap = {}
- # check for particles - if there are no faces but verts are found, the verts are single points. TODO: create a mesh out of the vert points which include UV mapping. Each point could be a plane, billboarding would need to happen on the wpf code side.
- if len(mesh.faces) == 0:
- if len(mesh.verts) > 0:
- warn("Particles Not currently supported.")
- return
- for face in mesh.faces:
- numVerts = len(face.v)
- # We expect mesh faces to be triangles or quads
- assert 3 <= numVerts and numVerts <= 4
- newIndices = []
- uvIndex = 0;
- for vertex in face.v:
- index = vertex.index
- position = mesh.verts[index].co
- if face.smooth:
- # If face is smooth shaded use vertex normal
- normal = mesh.verts[index].no
- else:
- # If face is solid (flat) shaded use face normal
- normal = face.no
- if mesh.faceUV:
- textureCoordinate = face.uv[uvIndex]
- uvIndex += 1
- if not indexMap.has_key(index):
- indexMap[index] = []
- else:
- # If this index is already mapped scan our entries to see if
- # there is already a position/normal/textureCoordinate set
- # which matches.
- for i in indexMap[index]:
- if positions[i] == position and normals[i] == normal and textureCoordinates[i] == textureCoordinate:
- newIndices.append(index)
- continue
- # We do not already have a matching position/normal/textureCoordinate
- # for this index so we create one and add it to our indexMap.
- indexMap[index].append(len(positions))
- newIndices.append(len(positions))
- positions.append(tuple(position))
- normals.append(tuple(normal))
- if mesh.faceUV:
- textureCoordinates.append(tuple(textureCoordinate))
- assert len(newIndices) == numVerts
- triangleIndices.extend([newIndices[0], newIndices[1], newIndices[2]])
- if numVerts == 4:
- triangleIndices.extend([newIndices[0], newIndices[2], newIndices[3]])
- assert len(positions) == len(normals)
- assert len(textureCoordinates) == len(positions) or len(textureCoordinates) == 0
- self.writer.beginElement("GeometryModel3D")
- self.writer.writeAttribute("x:Name", createSafeName("OB_" + objectName))
- materialWriter = XamlWriter()
- backmaterialWriter = XamlWriter()
- if self.writeMaterials(materialWriter, mesh):
- self.writer.beginElement("GeometryModel3D.Material")
- self.writer.writeFragment(materialWriter.toString())
- self.writer.endElement()
- isDoubleSided = mesh.mode & Blender.NMesh.Modes.TWOSIDED
- print(isDoubleSided)
- if isDoubleSided:
- if self.writeMaterials(backmaterialWriter, mesh):
- self.writer.beginElement("GeometryModel3D.BackMaterial")
- self.writer.writeFragment(backmaterialWriter.toString())
- self.writer.endElement()
- self.writer.beginElement("GeometryModel3D.Geometry")
- self.writer.beginElement("MeshGeometry3D")
- self.writer.writeAttribute("x:Name", createSafeName("ME_" + meshName))
- self.writer.writeString("\n")
- self.writer.writeAttribute("Positions", listToStringCompact(positions))
- self.writer.writeString("\n")
- self.writer.writeAttribute("Normals", listToStringCompact(normals))
- self.writer.writeString("\n")
- self.writer.writeAttribute("TextureCoordinates", listToStringCompact(textureCoordinates))
- self.writer.writeString("\n")
- self.writer.writeAttribute("TriangleIndices", listToString("%d", triangleIndices))
- self.writer.writeString("\n")
- self.writer.endElement()
- self.writer.endElement()
- self.writer.endElement()
- unindent()
- unindent()
- def writeLightCommon(self, lampObj):
- lamp = lampObj.getData()
- #BUGBUG: lamp.getName() disappeared in Blender 2.45.
- #self.writer.writeAttribute("x:Name", createSafeName("LA_" + lamp.getName()))
- self.writer.writeAttribute("Color", rgbToHexString(lamp.col))
- def writeDirectionalLight(self, lampObj):
- trace("type: Sun (Directional)")
- self.writer.beginElement("DirectionalLight")
- self.writeLightCommon(lampObj)
- self.writer.writeAttribute("Direction", "%f,%f,%f" % rotToDirection(lampObj.rot))
- self.writer.endElement()
- def writePointLightCommon(self, lampObj):
- loc = lampObj.loc
- lamp = lampObj.getData()
- self.writer.writeAttribute("Position", "%f,%f,%f" % lampObj.loc)
- mode = lamp.getMode()
- energy = lamp.getEnergy()
- dist = lamp.getDist()
- if mode & Lamp.Modes.Sphere:
- warn("The Sphere feature on lamps is approximated during export.");
- self.writer.writeAttribute("Range", dist)
- cAttn = 1/energy;
- lAttn = 1/(energy * dist);
- qAttn = 0;
- if mode & Lamp.Modes.Quad:
- warn("The Quad feature on lamps is approximated during export.");
- qAttn = lAttn * lamp.getQuad1();
- lAttn = lAttn * lamp.getQuad2();
- if cAttn != 1: self.writer.writeAttribute("ConstantAttenuation", cAttn)
- if lAttn != 0: self.writer.writeAttribute("LinearAttenuation", lAttn)
- if qAttn != 0: self.writer.writeAttribute("QuadraticAttenuation", qAttn)
- def writePointLight(self, lampObj):
- trace("type: Lamp (Point)")
- self.writer.beginElement("PointLight")
- self.writeLightCommon(lampObj)
- self.writePointLightCommon(lampObj)
- self.writer.endElement()
- def writeSpotLight(self, lampObj):
- trace("type: Spot")
- lamp = lampObj.getData()
- self.writer.beginElement("SpotLight")
- self.writeLightCommon(lampObj)
- self.writer.writeAttribute("Direction", "%f,%f,%f" % rotToDirection(lampObj.rot))
- self.writePointLightCommon(lampObj)
- self.writer.writeAttribute("OuterConeAngle", "%f" % lamp.getSpotSize())
- if lamp.getSpotBlend() > 0:
- innerAngle = lamp.getSpotSize() * (1 - lamp.getSpotBlend())
- assert innerAngle < lamp.getSpotSize()
- self.writer.writeAttribute("InnerConeAngle", "%f" % innerAngle)
- self.writer.endElement()
- def writeCameras(self, objects):
- i = 0;
- for ob in objects:
- childType = ob.getType()
- if childType == "Camera":
- i += 1
- self.writeCamera(ob)
- if i == 0:
- self.writeCamera(None)
- print("default camera")
- #end def writeCameras
- def writeCamera(self, cameraObj):
- camera = None
- if cameraObj != None:
- camera = cameraObj.getData()
- cameraTypeName = "PerspectiveCamera"
- if camera != None and camera.type == "ortho":
- cameraTypeName = "OrthographicCamera"
- #compute all the variables to set the camera
- yfov = 60
- clipStart = 0.10
- clipEnd = 100.0
- if camera != None:
- matrix = cameraObj.getMatrix('worldspace') # matrix with euler and translation information
- rotMat = matrix.rotationPart()
- euler = rotMat.toEuler()
- rotQuat = euler.toQuat()
- loc = matrix[3][0], matrix[3][1], matrix[3][2]
- yfov = 2 * ( atan( 16.0 / camera.lens ) ) * ( 180.0 / 3.1415926 )
- clipEnd = camera.getClipEnd()
- clipStart = camera.getClipStart()
- # write attributes
- self.writer.beginElement(cameraTypeName)
- self.writer.writeAttribute("FarPlaneDistance", "%f" % clipEnd)
- self.writer.writeAttribute("NearPlaneDistance", "%f" % clipStart)
- self.writer.writeAttribute("UpDirection", "%s" % "0,1,0")
- self.writer.writeAttribute("LookDirection", "%s" % "0,0,-1")
- self.writer.writeAttribute("Position", "%s" % "0,0,0")
- if cameraTypeName == "OrthographicCamera":
- self.writer.writeAttribute("Width", "%f" % camera.scale)
- else:
- self.writer.writeAttribute("FieldOfView", "%f" % yfov)
- # write Transforms
- if camera != None:
- tranformName = cameraTypeName + ".Transform"
- self.writer.beginElement(tranformName)
- self.writer.beginElement("Transform3DGroup")
- self.writeQuaternionRotateTransform(self.writer, rotQuat)
- self.writeTranslateTransform(self.writer, loc)
- self.writer.endElement() #</Transform3DGroup >
- self.writer.endElement() #</cameratype.Transform >
- self.writer.endElement() #</cameratype >
- #end def WriteCamera
- def writeLamp(self, lampObj):
- lamp = lampObj.getData()
- #BUGBUG: lamp.getName() disappeared in Blender 2.45.
- #lampName = lamp.getName()
- lampName = "?"
- trace("Lamp ('%s'):" % lampName)
- indent()
- lampType = lamp.getType()
- if lampType == Lamp.Types.Sun:
- self.writeDirectionalLight(lampObj)
- elif lampType == Lamp.Types.Lamp:
- self.writePointLight(lampObj)
- elif lampType == Lamp.Types.Spot:
- self.writeSpotLight(lampObj)
- else:
- unsupportedLamps = { 3 : "Hemi", 4 : "Area", 5 : "Photon" }
- if unsupportedLamps.has_key(lampType):
- warn("Skipping unsupported Lamp type '%s'" % unsupportedLamps[lampType])
- else:
- warn("Skipping unknown Lamp type '%u'" % lampType)
- trace("loc: %f,%f,%f" % (lampObj.loc))
- #BUGBUG: In Blender 2.45 I began having to coerce rotation values to a float tuple.
- #trace("rot: %f,%f,%f" % (lampObj.rot))
- trace("rot: %f,%f,%f" % (lampObj.rot[0], lampObj.rot[1], lampObj.rot[2]))
- trace("bias: %f" % lamp.getBias())
- trace("clipEnd: %f" % lamp.getClipEnd())
- trace("clipStart: %f" % lamp.getClipStart())
- trace("col: %s" % rgbToHexString(lamp.getCol()))
- trace("dist: %f" % lamp.getDist())
- trace("energy: %f" % lamp.getEnergy())
- trace("haloInt: %f" % lamp.getHaloInt())
- trace("haloStep: %i" % lamp.getHaloStep())
- trace("mode: %i" % lamp.getMode())
- trace("quad1: %f" % lamp.getQuad1())
- trace("quad2: %f" % lamp.getQuad2())
- trace("samples: %i" % lamp.getSamples())
- trace("softness: %f" % lamp.getSoftness())
- trace("spotBlend: %f" % lamp.getSpotBlend())
- trace("spotSize: %f" % lamp.getSpotSize())
- unindent()
- def writeBeginModel3DGroup(self, object):
- self.writer.beginElement("Model3DGroup")
- self.writer.writeAttribute("x:Name", createSafeName("MG_" + object.name))
- transformWriter = XamlWriter()
- if self.writeTransforms(transformWriter, object):
- self.writer.beginElement("Model3DGroup.Transform")
- self.writer.writeFragment(transformWriter.toString())
- self.writer.endElement()
- def writeEndModel3DGroup(self):
- self.writer.endElement() # end Model3DGroup
- def GetIndentString (self, level):
- str = ""
- for i in range(level):
- str = str + " "
- return str
- def FindNameIndex (self, objects, object):
- i = 0
- for ob in objects:
- if ob.name == object.name:
- return i
- i+=1
- return -1
- #
- # Write out mesh or lamp object based on results of getDerievedObjects
- #
- def writeDerivedObject (self, object):
- for ob, ob_mat in BPyObject.getDerivedObjects(object):
- childType = ob.getType()
- if childType == "Mesh":
- self.writeMesh(ob)
- elif childType == "Lamp":
- self.writeLamp(ob)
- #end for
- # end def writeDerivedObject
- #
- # recusively write out the objects based on parent relationships
- #
- def writeChildrenObjects(self, objects, sorted_objects,root):
- for ob in objects:
- parent = ob.parent
- if parent == None:
- continue
- if parent.name == root.name:
- findIndex = self.FindNameIndex(sorted_objects, ob)
- if findIndex != -1:
- continue
- self.writeBeginModel3DGroup(ob)
- if ob.sel == 1:
- self.writeDerivedObject (ob)
- sorted_objects.append(ob)
- self.writeChildrenObjects (objects, sorted_objects, ob)
- self.writeEndModel3DGroup()
- #def end writeChildrenObjects
- #
- # setup the lists for a recursive call to write out children
- #
- def writeBlenderObjects(self, objects):
- rootNodes = []
- sorted_objects = []
- # add the root nodes, and ignore the camera
- for ob in objects:
- childType = ob.getType()
- if childType == "Camera":
- continue
- if ob.parent == None:
- if ob.sel == 1:
- rootNodes.append(ob)
- # write out the tree based on he root nodes
- for ob in rootNodes:
- findIndex = self.FindNameIndex(sorted_objects,ob)
- if findIndex > 0:
- continue
- self.writeBeginModel3DGroup(ob)
- self.writeDerivedObject(ob)
- sorted_objects.append(ob)
- self.writeChildrenObjects (objects, sorted_objects, ob)
- self.writeEndModel3DGroup()
- #def end writeBlenderObjects
- def writeScene(self, sceneObj, fileout):
- self.writer.beginElement("Viewport3D")
- self.writer.writeAttribute("xmlns", "http://schemas.microsoft.com/winfx/2006/xaml/presentation")
- self.writer.writeAttribute("xmlns:x", "http://schemas.microsoft.com/winfx/2006/xaml")
- orig_scene = sceneObj
- orig_scene.makeCurrent() # If already current, this is not slow.
- context = orig_scene.getRenderingContext()
- orig_frame = Blender.Get('curframe')
- # Export an animation?
- # if EXPORT_ANIMATION:
- # scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame.
- # else:
- scene_frames = [orig_frame] # Dont export an animation.
- # Loop through all frames in the scene and export.
- for frame in scene_frames:
- #if EXPORT_ANIMATION: # Add frame to the filename.
- # context_name[2] = '_%.6d' % frame
- Blender.Set('curframe', frame)
- scn = Scene.GetCurrent()
- all_objects = scn.objects
- # write out any cameras
- self.writer.beginElement("Viewport3D.Camera")
- self.writeCameras(all_objects)
- self.writer.endElement()
- # write out ModelVisual3D to hold all the objects
- self.writer.beginElement("ModelVisual3D")
- self.writer.beginElement("ModelVisual3D.Content")
- self.writer.beginElement("Model3DGroup")
- # write out all the blender objects
- all_objects = scn.objects
- self.writeBlenderObjects(all_objects)
- #test code for quick debugging
- #print("------")
- #for ob_main in all_objects:
- # for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
- #
- # childType = ob.getType()
- #
- # if childType == "Mesh":
- # print(ob.name)
- # print(ob.matrixLocal)
- # print(ob.matrixLocal.translationPart())
- # print(ob.matrixLocal.scalePart())
- # print(ob.matrixLocal.rotationPart().toEuler())
- # print(ob.rot)
- # elif childType == "Lamp":
- # self.writeLamp(ob)
- # elif childType == "Camera":
- # self.writeCamera(ob)
- # else:
- # warn("Skipping unsupported object type in scene: '" + ob.getType() + "'")
- #
- # end loop through all frames
- self.writer.endElement() # </Model3DGroup>
- self.writer.endElement() # </ModelVisual3D.Content>
- self.writer.endElement() # </ModelVisual3D>
- self.writer.endElement() # </Viewport3D>
- fileout.write(self.writer.toString())
- #
- # Global
- #
- class ExportXaml():
- """ Guess these are properties"""
- bl_idname = "export.xaml"
- bl_label = "Export to XAML"
- filename_ext = ".xaml"
- _quaternionWLimit = cos(degToRad(_rotationLimit)/2)
- def export(filename):
- trace("Exporting to file: '" + filename)
- verbose("Configuration:")
- indent()
- verbose("_rotationLimit='%f'" % _rotationLimit)
- verbose("_quaternionWLimit='%f'" % _quaternionWLimit)
- unindent()
- exporter = XamlExporter()
- fileout = open(filename, 'w')
- try:
- exporter.writeScene(Scene.GetCurrent(), fileout)
- finally:
- fileout.close()
- def onFileSelected(filename):
- if filename.find('.xaml', -5) <= 0:
- filename += '.xaml'
- # if Blender.sys.exists(filename):
- # if Blender.Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0") != 1:
- # return
- export(filename)
- @classmethod
- def poll(cls, context):
- active = context.active_object
- selected = context.selected_objects
- camera = context.scene.camera
- ok = selected or camera
- return ok
- def execute(self, context):
- filepath = self.filepath
- filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
- export(self.filepath)
- ### REGISTER ###
- def menu_func(self, context):
- self.layout.operator(ExportXaml.bl_idname, text="XAML (.xaml)")
- def register():
- bpy.utils.register_module(__name__)
- bpy.types.INFO_MT_file_export.append(menu_func)
- def unregister():
- bpy.utils.unregister_module(__name__)
- bpy.types.INFO_MT_file_export.remove(menu_func)
- if __name__ == "__main__":
- register()
- trace("io_export_xaml.py Finished.")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement