Skip to content

Instantly share code, notes, and snippets.

@BlockoS
Created April 25, 2010 20:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BlockoS/378672 to your computer and use it in GitHub Desktop.
Save BlockoS/378672 to your computer and use it in GitHub Desktop.
#!BPY
""" Registration info for Blender menus:
Name: 'BlockoS (.blcks)...'
Blender: 243
Group: 'Export'
Tip: 'Export scene to BlockoS stuffs'
"""
__author__ = "Vincent 'MooZ' Cruz"
__url__ = ("BlockoS' homepage, http://www.blockos.org")
__version__ = "04232010"
__bpydoc__ = """\
This script exports to the BlockoS format.
Usage:
Run this script from "File->Export" menu.
"""
import os
import Blender
from Blender import Mesh, Scene, Window, sys, Image, Draw
import BPyMesh
import BPyObject
import BPySys
import BPyMessages
#
class Exporter:
def __init__(self, out):
self.level = 0 # indentation level
self.out = out # output stream
# indentation and output methods
def beginBlock(self):
self.level = self.level+1
def endBlock(self):
self.level = self.level-1
def indent(self):
return " "*self.level
def writeLine(self, line):
self.out.write( self.indent() + line + '\n');
# Vector output
def writeVec3(self, name, x, y, z):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f/>' % (x,y,z))
def writeVec3(self, name, v):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f/>' % tuple(v))
def writeVec4(self, name, x, y, z, w):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f/>' % (x,y,z,w))
def writeVec4(self, name, v):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f w=%.6f/>' % tuple(v))
# Transformation output
def writeTransform(self, transform=Blender.Mathutils.Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])):
position = transform.translationPart()
self.writeVec3("position", position)
rotationQuat = transform.toQuat()
self.writeVec4("rotation", rotationQuat.x, rotationQuat.y, rotationQuat.z, rotationQuat.w)
rotationQuat.inverse()
inverseRotationMatrix = rotationQuaternion.toMatrix()
inverseRotationMatrix.resize4x4()
scale = transform*inverseRotationMatrix
self.writeVec3("scale", scale[0][0], scale[1][1], scale[2][2])
#
class CameraExporter:
def __init__(self, exporter):
self.exporter = exporter
def export(self, camera, id):
self.exporter.writeLine('<camera name="' + camera.name + ' id=%d/>' % (id))
self.exporter.beginBlock()
if camera.type == 'persp':
# type fov dof
self.exporter.writeLine('<perspective fov=%f focale=%f/>' % (camera.angle, camera.dofDist))
else:
self.exporter.writeLine('<ortho %f/>' % (camera.scale))
self.exporter.writeLine('<clip min=%f max=%f>' % (camera.clipStart, camera.clipEnd))
# extract view position, direction, up and right vectors
cameraObj = Blender.Object.Get(camera.name)
modelviewMatrix = cameraObj.getMatrix()
# eye position
w = modelviewMatrix[3][3]
eye = (modelviewMatrix[3][0] / w, modelviewMatrix[3][1] / w, -modelviewMatrix[3][2] / w)
# direction vector
dir = (modelviewMatrix[2][0], modelviewMatrix[2][1], -modelviewMatrix[2][2])
# up vector
up = (modelviewMatrix[1][0], modelviewMatrix[1][1], -modelviewMatrix[1][2])
# right vector
right = (modelviewMatrix[0][0], modelviewMatrix[0][1], -modelviewMatrix[0][2])
self.exporter.writeVec3('eye', eye)
self.exporter.writeVec3('direction', dir)
self.exporter.writeVec3('up', up)
self.exporter.writeVec3('right', right)
self.exporter.endBlock()
self.exporter.writeLine('</camera>')
# write face
def export_face(file, f):
# vertex/normal/uv
file.write('%6f %6f %6f ' % tuple(f.verts[0].co))
file.write('%6f %6f %6f ' % tuple(f.verts[0].no))
file.write('%6f %6f\n' % tuple(f.uv[0]))
file.write('%6f %6f %6f ' % tuple(f.verts[1].co))
file.write('%6f %6f %6f ' % tuple(f.verts[1].no))
file.write('%6f %6f\n' % tuple(f.uv[1]))
file.write('%6f %6f %6f ' % tuple(f.verts[2].co))
file.write('%6f %6f %6f ' % tuple(f.verts[2].no))
file.write('%6f %6f\n' % tuple(f.uv[2]))
if len(f.verts) == 4:
# split face
file.write('%6f %6f %6f ' % tuple(f.verts[0].co))
file.write('%6f %6f %6f ' % tuple(f.verts[0].no))
file.write('%6f %6f\n' % tuple(f.uv[0]))
file.write('%6f %6f %6f ' % tuple(f.verts[1].co))
file.write('%6f %6f %6f ' % tuple(f.verts[1].no))
file.write('%6f %6f\n' % tuple(f.uv[1]))
file.write('%6f %6f %6f ' % tuple(f.verts[2].co))
file.write('%6f %6f %6f ' % tuple(f.verts[2].no))
file.write('%6f %6f\n' % tuple(f.uv[2]))
# Export the whole scene
def export_blcks(filename):
file = open(filename, "wb")
export = Exporter(file)
camExport = CameraExporter(export)
scene = Blender.Scene.GetCurrent()
objectList = scene.objects
imageList = Blender.Image.Get()
imageDict = {}
context = scene.getRenderingContext()
cameraList = Blender.Camera.Get()
# todo : lights, make a class with method for writing camera/face/material/....
# frames and fix the file format :D
# context
width = context.imageSizeX()
height = context.imageSizeY()
aspectX = context.aspectX
aspectY = context.aspectY
aspect = float(width*aspectX) / float(height*aspectY)
#
export.writeLine('<context aspect=%f width=%d height=%d/>' % (aspect, width*aspectX/aspectY, height))
# output cameras
for i,camera in enumerate(cameraList):
camExport.export(camera, i)
# check if the directory
imageDir = os.path.join(os.path.dirname(filename), 'textures')
if not os.access(imageDir, os.F_OK):
os.mkdir(imageDir)
# build image dictionary and save images
for j,image in enumerate(imageList):
if not j%100:
Blender.Window.DrawProgressBar(float(j)/len(imageList), 'Writing ' + image.name)
imageDict[image.name] = j
export.writeLine('<image filename="' + image.name + '" clampU=%d clampV=%d/>' % (image.clampX, image.clampY))
image.filename = os.path.join(imageDir, image.name)
image.save()
# write objects
file.write('%d \n' %len(objectList))
for j,obj in enumerate(objectList):
# mesh
mesh = BPyMesh.getMeshFromObject(obj, None, True, False, scene)
if mesh:
# compute face count
faceCount = 0
for f in mesh.faces:
if len(f.verts) == 4:
# We split quads
faceCount += 2
else:
faceCount += 1
# calculate normal
mesh.calcNormals()
# sort faces by material
matFaceList = [list() for i in range(15)]
for f in mesh.faces:
matFaceList[f.mat].append(f)
# write materials
for i,material in enumerate(mesh.materials):
if not i%100:
Blender.Window.DrawProgressBar(float(i)/len(mesh.materials), "Writing material %d:%d" %(j,i))
file.write( material.name + ' %d\n' % i )
file.write('%.6f %.6f %.6f\n' % tuple(material.rgbCol))
file.write('%.6f %.6f %.6f\n' % tuple(material.specCol))
file.write('%.6f %.6f %.6f %.6f\n' % (material.amb, material.emit, material.ref, material.spec))
for tIndex, texture in enumerate(material.textures):
if texture == None:
continue
if texture.tex.type == Blender.Texture.Types.IMAGE:
file.write( '%d ' % imageDict[texture.tex.image.name] )
file.write('\n')
# write faces
faceIdx = 0
if mesh.faceUV:
file.write('0\n')
file.write('%d\n' % faceCount)
for mIndex, fList in enumerate(matFaceList):
if not fList:
continue
file.write('%d\n' % mIndex)
for f in fList:
if not faceIdx%100:
Blender.Window.DrawProgressBar(float(faceIdx)/len(mesh.faces), "Writing face %d:%d" %(j,faceIdx))
export_face(file, f)
faceIdx+=1
else:
file.write('0\n')
file.write('%d %d\n' %(faceCount, len(mesh.verts)))
# indices
for mIndex, fList in enumerate(matFaceList):
if not fList:
continue
file.write('%d\n' % mIndex)
for f in fList:
if not faceIdx%100:
Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing indices %d:%d" %(j,faceIdx))
file.write('%d %d %d\n' %(f.verts[0].index, f.verts[1].index, f.verts[2].index))
if len(f.verts) == 4:
# split face
file.write('%d %d %d\n' %(f.verts[0].index, f.verts[2].index, f.verts[3].index))
faceIdx+=1
# vertices
for i,v in enumerate(mesh.verts):
if not i%100:
Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing vertices %d:%d" %(j,i))
file.write('%.6f %.6f %.6f ' % tuple(v.co))
file.write('%.6f %.6f %.6f\n' % tuple(v.no))
# uv
if mesh.vertexUV:
for i,v in enumerate(mesh.verts):
if not i%100:
Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing UV %d:%d" %(j,i))
file.write('%.6f %.6f\n' % tuple(v.uvco))
def main():
Blender.Window.FileSelector(export_blcks, "Export Blockos", Blender.sys.makename(ext='.blcks'))
if __name__=='__main__':
main()
#!BPY
""" Registration info for Blender menus:
Name: 'BlockoS Mesh Exporter(.blcks)...'
Blender: 243
Group: 'Export'
Tip: 'Export meshes to BlockoS stuffs'
"""
__author__ = "Vincent 'MooZ' Cruz"
__url__ = ("BlockoS' homepage, http://www.blockos.org")
__version__ = "04232010"
__bpydoc__ = """\
This script exports meshs to the BlockoS format.
Usage:
Run this script from "File->Export" menu.
"""
# TODO : maybe add more stuffs to ImageManager
# see how to copy/save image without destroying/changing anything
# submesh, mesh, armatures and all
# TESTS TESTS TESTS and TESTS!
import os
import Blender
from Blender import Mesh, Scene, Window, sys, Image, Draw, Mathutils
import BPyMesh
import BPyObject
import BPySys
import BPyMessages
EPSILON = 1e-6
#
def clamp(v, min, max):
if v < min:
return min
if v > max:
return max
return v
#
class Exporter:
def __init__(self, out):
self.level = 0 # indentation level
self.out = out # output stream
# indentation and output methods
def beginBlock(self):
self.level = self.level+1
def endBlock(self):
self.level = self.level-1
def indent(self):
return " "*self.level
def writeLine(self, line):
self.out.write( self.indent() + line + '\n');
# Vector output
def writeVec3(self, name, x, y, z):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f/>' % (x,y,z))
def writeVec3(self, name, v):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f/>' % tuple(v))
def writeVec4(self, name, x, y, z, w):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f/>' % (x,y,z,w))
def writeVec4(self, name, v):
self.writeLine('<' + name + ' x=%.6f y=%.6f z=%.6f w=%.6f/>' % tuple(v))
# Transformation output
def writeTransform(self, transform=Blender.Mathutils.Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])):
position = transform.translationPart()
self.writeVec3("position", position)
rotationQuat = transform.toQuat()
self.writeVec4("rotation", rotationQuat.x, rotationQuat.y, rotationQuat.z, rotationQuat.w)
rotationQuat.inverse()
inverseRotationMatrix = rotationQuaternion.toMatrix()
inverseRotationMatrix.resize4x4()
scale = transform*inverseRotationMatrix
self.writeVec3("scale", scale[0][0], scale[1][1], scale[2][2])
class ImageManager:
def __init__(self):
self.dict = {}
self.lastID = 0
# fill the dictionary with images from the scene
imageList = Blender.Image.Get()
for image in imageList:
self.dict[image.getName()] = [self.lastID, image]
self.lastID = self.lastID + 1
def fetchID(self, image):
key = image.getName()
if not self.dict.has_key(key):
self.dict[key] = [self.lastID, image]
self.lastID = self.lastID + 1
elif self.dict[key][1].getFilename() != image.getFilename() :
# WTF!
pass
return self.dict[key][0]
def write(self, export):
# Must be done once (at the end) !
data = []
for key, data in self.dict.items():
export.writeLine('<image id=%d name="%s"/>' % (data[0], key))
# Blender material parser/exporter
class Material:
def __init__(self, blenderMesh, blenderFace, index):
self.mesh = blenderMesh
self.face = blenderFace
self.material = None
self.name = 'None'
self.index = index
self.diffuseTex = None
self.specularTex = None
self.normalTex = None
self.key = 0
try:
self.material = blenderMesh.materials[blenderFace.mat]
for texObj in self.material.textures:
if texObj == None:
continue
if texObj.tex.type != Blender.Texture.Types['IMAGE']:
continue
if not (texObj.texco & Blender.Texture.TexCo['UV']):
continue
if texObj.mapto & Blender.Texture.MapTo['COL']:
self.key |= 16
self.diffuseTex = texObj
if texObj.mapto & Blender.Texture.MapTo['NOR']:
self.key |= 32
self.normalTex = texObj
if texObj.mapto & Blender.Texture.MapTo['CSP']:
self.key |= 64
self.specularTex = texObj
self.name = self.material.name + '/%04x' % self.key
except:
pass
# TODO : add more infos to key
def getName(self):
return self.name
def _writeShadowAttr(self, export):
cast = 0
receive = 0
if self.material.mode & Blender.Material.Modes.SHADOW :
receive=1
if self.material.mode & Blender.Material.Modes.SHADOWBUF :
cast=1
export.writeLine('<shadow cast=%d receive=%d/>' % (receive, cast) );
def _writeColors(self, export):
# diffuse
col = self.material.rgbCol[:3]
export.writeLine('<diffuse r=%.6f g=%.6f b=%.6f reflectivity=%.6f/>' % (col[0], col[1], col[2], self.material.ref))
# specular
col = self.material.specCol[:3]
export.writeLine('<specular r=%.6f g=%.6f b=%.6f specularity=%.6f shininess=%d/>' % (col[0], col[1], col[2], self.material.ref, self.material.hard) )
def _writeTextureInfos(self, texObj, export):
# wrap
clampU = 'clamp'
clampV = 'clamp'
if texObj.tex.extend & Blender.Texture.ExtendModes['REPEAT'] :
if texObj.tex.flags & Blender.Texture.Flags['REPEAT_XMIR']:
clampU = 'mirroredRepeat'
else :
clampU = 'repeat'
if texObj.tex.flags & Blender.Texture.Flags['REPEAT_YMIR']:
clampV = 'mirroredRepeat'
else:
clampV = 'repeat'
elif texObj.tex.extend & Blender.Texture.ExtendModes['EXTEND'] :
clampU = clampV = 'clampToEdge'
elif texObj.tex.extend & Blender.Texture.ExtendModes['CLIP'] :
clampU = clampV = 'clamp'
# minification/magnification
minFilter = 'nearest'
magFilter = 'nearest'
if texObj.tex.imageFlags & Blender.Texture.ImageFlags['INTERPOL']:
magFilter = 'linear'
if texObj.tex.imageFlags & Blender.Texture.ImageFlags['MIPMAP']:
minFilter = 'linearMipmapLinear'
else:
minFilter= 'linear'
else:
if texObj.tex.imageFlags & Blender.Texture.ImageFlags['MIPMAP']:
minFilter = 'nearestMipmapLinear'
export.writeLine('<wrap u="%s" v="%s"/>' % (clampU, clampV))
export.writeLine('<filter min="%s" mag="%s"/>' % (minFilter, magFilter))
def _writeTexture(self, targetname, texObj, imageManager, export):
export.writeLine('<texture target="%s" unit=%d>' % (targetname, imageManager.fetchID(texObj.tex.getImage())))
export.beginBlock()
self._writeTextureInfos(texObj, export)
export.endBlock()
export.writeLine('</texture>')
def _writeGlobalSettings(self, export):
# ambient/emitivity/alpha
export.writeLine( '<global ambient=%.6f alpha=%.6f emit=%.6f/>' %(self.material.amb, self.material.alpha, self.material.emit))
# zbuffer test
depthWrite = 1
if self.material.alpha < 1.0:
depthWrite = 0
else:
for texObj in self.material.textures:
if texObj == None:
continue
if ( (texObj.tex.type == Blender.Texture.Types['IMAGE'])
and (texObj.mapto & Blender.Texture.MapTo['ALPHA']) ) :
depthWrite = 0
break
depthFunc = 'less'
if self.material.mode & Blender.Material.Modes['ENV'] :
depthFunc = 'never'
elif self.material.mode & Blender.Material.Modes['ZINVERT'] :
depthFunc = 'greater_equal'
export.writeLine( '<depth write=%d func="%s"/>' % (depthWrite, depthFunc) )
# cull mode
cullface = 'back'
if self.face.mode & Blender.Mesh.FaceModes['TWOSIDE'] :
culface = 'disabled'
export.writeLine( '<cull face="' + cullface + '"/>');
def write(self, imageManager, export):
if self.material == None:
return
export.writeLine('<material id=%d name="%s">' % (self.index, self.name))
export.beginBlock()
self._writeGlobalSettings(export)
self._writeShadowAttr(export)
self._writeColors(export)
if self.diffuseTex:
self._writeTexture('diffuse', self.diffuseTex, imageManager, export)
if self.normalTex:
self._writeTexture('normal', self.normalTex, imageManager, export)
if self.specularTex:
self._writeTexture('specular', self.specularTex, imageManager, export)
export.endBlock()
export.writeLine("</material>")
#
class MaterialManager:
def __init__(self, imageManager):
self.dict = {}
self.lastID = 0
self.imageManager = imageManager
def get(self, blenderMesh, blenderFace):
# TODO : add a "default" material if there's no material
material = Material(blenderMesh, blenderFace, self.lastID)
key = material.getName()
if not self.dict.has_key(key):
self.lastID = self.lastID + 1
self.dict[key] = material
material = self.dict[key]
return material
def write(self, export):
export.writeLine("<materialList>")
export.beginBlock()
for material in self.dict.values():
material.write(self.imageManager, export)
export.endBlock()
export.writeLine("</materialList>")
# Big fat vertex
class Vertex:
def __init__(self, blenderMesh, blenderFace, vfIndex, buffIndex, ):
self.mesh = blenderMesh
self.face = blenderFace
self.index = buffIndex
self.v = self.face.v[vfIndex]
self.n = None
self.uv = []
if blenderFace.smooth:
self.n = self.v.no
else:
# todo : bones
v0 = self.face.v[0].co
v1 = self.face.v[1].co
v2 = self.face.v[2].co
self.n = Blender.Mathutils.TriangleNormal(v0, v1, v2)
# Save current active layer
activeUVLayer = self.mesh.activeUVLayer
if activeUVLayer:
# Extract coordinates for each layer
for i, uvLayer in enumerate(self.mesh.getUVLayerNames()):
self.mesh.activeUVLayer = uvLayer
if self.mesh.faceUV:
self.uv.append( (self.face.uv[bIndex][0], self.face.uv[bIndex][1], i, uvLayer) )
elif self.mesh.vertexUV:
self.uv.append( (self.v.uvco[0], self.v.uvco[1], i, uvLayer) )
# Restore active layer
bMesh.activeUVLayer = activeUVLayer
# Check if uv layers of 2 points match
def _eqUV(self, p):
if len(self.uv) != len(p.uv) :
return False
for i, coord in enumerate(self.uv) :
if (math.fabs(coord[0] - p.uv[i][0]) > EPSILON) or (math.fabs(coord[1] - p.uv[i][1]) > EPSILON):
return False
return True
def __eq__ (self, p):
return (self.v.index == p.v.index) and (self.index == p.index) and (self._eqUV(p))
def write(self, export):
export.writeLine("<vertex>")
export.beginBlock()
self.export.writeVec3("position", self.v.co)
self.export.writeVec3("normal", self.n )
export.writeLine("<uvList count=%d>" %len(self.uv));
export.beginBlock()
for coord in self.uv:
export.writeLine('<uv x=%.6f y=%.6f unit=%d name="%s"/>' % self.uv );
export.endBlock()
export.writeLine("<uvList/>");
export.endBlock()
export.writeLine("</vertex>")
# TODO :
# vertex buffer/dictionnary
# submesh
# mesh
# animation (bones etc..)
# write face
def export_face(file, f):
# vertex/normal/uv
file.write('%6f %6f %6f ' % tuple(f.verts[0].co))
file.write('%6f %6f %6f ' % tuple(f.verts[0].no))
file.write('%6f %6f\n' % tuple(f.uv[0]))
file.write('%6f %6f %6f ' % tuple(f.verts[1].co))
file.write('%6f %6f %6f ' % tuple(f.verts[1].no))
file.write('%6f %6f\n' % tuple(f.uv[1]))
file.write('%6f %6f %6f ' % tuple(f.verts[2].co))
file.write('%6f %6f %6f ' % tuple(f.verts[2].no))
file.write('%6f %6f\n' % tuple(f.uv[2]))
if len(f.verts) == 4:
# split face
file.write('%6f %6f %6f ' % tuple(f.verts[0].co))
file.write('%6f %6f %6f ' % tuple(f.verts[0].no))
file.write('%6f %6f\n' % tuple(f.uv[0]))
file.write('%6f %6f %6f ' % tuple(f.verts[1].co))
file.write('%6f %6f %6f ' % tuple(f.verts[1].no))
file.write('%6f %6f\n' % tuple(f.uv[1]))
file.write('%6f %6f %6f ' % tuple(f.verts[2].co))
file.write('%6f %6f %6f ' % tuple(f.verts[2].no))
file.write('%6f %6f\n' % tuple(f.uv[2]))
# Export the whole scene
def export_blcks(filename):
file = open(filename, "wb")
export = Exporter(file)
scene = Blender.Scene.GetCurrent()
objectList = scene.objects
imageManager = ImageManager()
materialManager = MaterialManager(imageManager)
# write objects
for j,obj in enumerate(objectList):
# mesh
mesh = BPyMesh.getMeshFromObject(obj, None, True, False, scene)
if mesh:
for face in mesh.faces:
mat = materialManager.get(mesh, face)
imageManager.write(export)
materialManager.write(export)
# write vertices
file.close()
def main():
Blender.Window.FileSelector(export_blcks, "Export Blockos", Blender.sys.makename(ext='.blcks'))
if __name__=='__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment