Skip to content

Instantly share code, notes, and snippets.

@Numbers11
Last active February 23, 2016 16:16
Show Gist options
  • Save Numbers11/34d9a567736b03ba4a3d to your computer and use it in GitHub Desktop.
Save Numbers11/34d9a567736b03ba4a3d to your computer and use it in GitHub Desktop.
import struct
global file
import fbx
import sys
import math
import FbxCommon
import functools
import itertools
def readcstr(f):
toeof = iter(functools.partial(f.read, 1), '')
return ''.join(itertools.takewhile('\0'.__ne__, toeof))
class BinaryReaderEOFException(Exception):
def __init__(self):
pass
def __str__(self):
return 'Not enough bytes in file to satisfy read request'
class BinaryReader:
# Map well-known type names into struct format characters.
typeNames = {
'int8' :'b',
'uint8' :'B',
'int16' :'h',
'uint16' :'H',
'int32' :'i',
'uint32' :'I',
'int64' :'q',
'uint64' :'Q',
'float' :'f',
'double' :'d',
'char' :'s'}
def __init__(self, fileName):
self.file = fileName
def read(self, typeName):
typeFormat = BinaryReader.typeNames[typeName.lower()]
typeSize = struct.calcsize(typeFormat)
value = self.file.read(typeSize)
if typeSize != len(value):
raise BinaryReaderEOFException
return struct.unpack(typeFormat, value)[0]
def readString(self, length):
typeFormat = str(length) + "s"
typeSize = struct.calcsize(typeFormat)
value = self.file.read(typeSize)
if typeSize != len(value):
raise BinaryReaderEOFException
return struct.unpack(typeFormat, value)[0]
def __del__(self):
self.file.close()
def readFileHeader():
try:
signature = binaryReader.read('uint32')
unkown1 = binaryReader.read('uint32')
unkown2 = binaryReader.read('uint32')
blocknum = binaryReader.read('uint32')
#print blocknum
blocks = []
for x in range(0, blocknum):
#struct.unpack('4s', name)
block = {}
block["name"] = binaryReader.readString(4)
#pos = BinaryReader.getPos();
pos = file.tell()
block["offset"] = binaryReader.read('uint32')
block["link"] = pos + block["offset"];
block["size"] = binaryReader.read('uint32')
blocks.append(block)
#print block
return blocks
except BinaryReaderEOFException:
# One of our attempts to read a field went beyond the end of the file.
print "Error: File seems to be corrupted."
def readVBIB(offset):
file.seek(offset)
pos = file.tell()
header = {}
header["vertexHOffset"] = binaryReader.read('uint32')
header["vertexHLink"] = pos + header["vertexHOffset"]
header["vertexHCount"] = binaryReader.read('uint32')
pos = file.tell()
header["indexHOffset"] = binaryReader.read('uint32')
header["indexHLink"] = pos + header["indexHOffset"]
header["indexHCount"] = binaryReader.read('uint32')
return header
def readVertices(offset, count):
vertexgroups = []
for x in range(0, count):
vertices = {}
file.seek(offset + x * 24)
vertices["count"] = binaryReader.read('uint32')
file.seek(offset + x * 24 + 16)
vertices["link"] = offset + x * 24 + 16 + binaryReader.read('uint32')
vertices["vertex"] = []
vertices["boneid"] = []
vertices["boneweight"] = []
file.seek(offset + x * 24 + 4)
vertices["size"] = binaryReader.read('uint32');
file.seek(vertices["link"])
for q in range(0, vertices["count"]):
x = binaryReader.read("float")
y = binaryReader.read("float")
z = binaryReader.read("float")
bonenum = binaryReader.read("uint8")
#print bonenum
#print x, y, z
boneid1 = binaryReader.read("uint8")
boneid2 = binaryReader.read("uint8")
boneid3 = binaryReader.read("uint8")
#print boneid1,boneid2,boneid3
boneweight1 = binaryReader.read("uint8")
boneweight2 = binaryReader.read("uint8")
boneweight3 = binaryReader.read("uint8")
#print boneweight1,boneweight2,boneweight3
#not sure what any of this shit is except the vertices
binaryReader.read("char") #crap?
binaryReader.readString(vertices["size"] - 20) #skip whatever is still there
vertices["vertex"].append(fbx.FbxVector4(x,y,z))
vertices["boneid"].append([boneid1,boneid2,boneid3])
vertices["boneweight"].append([boneweight1,boneweight2,boneweight3])
vertexgroups.append(vertices)
return vertexgroups
def readAttributes(offset, count):
attributes = {}
for x in range(0, count):
file.seek(offset + x * 24 + 12)
acount = binaryReader.read("uint32")
# print acount
file.seek(offset + 24 * x + 8)
pos = binaryReader.read("uint32")
# print pos
link = offset + 24 * x + 8 + pos
#print link
for y in range (0,acount):
here = link + y *56
file.seek(here)
name = readcstr(file)
# print name
file.seek(here + 40)
attributes[name] = binaryReader.read("uint32")
return attributes
def readTexcoords(vertices, offset):
htexcoords = []
for x in range (0,len(vertices)):
texcoords = []
for y in range (0,len(vertices[x]["vertex"])):
#aaaaaaaaaaaaaaaaaaaaaaaahhhh
# u =
# v =
#texcoord.u = decodeFloat16(this.binary.read('uint16', header.vertices[x].link + (y * header.vertices[x].size) + header.vertices[x].attributes.TEXCOORD));
#texcoord.v = decodeFloat16(this.binary.read('uint16', header.vertices[x].link + (y * header.vertices[x].size) + header.vertices[x].attributes.TEXCOORD + 2));
texcoords.append(fbx.FbxVector2(u, v))
htexcoords.append(texcoords)
def readIndices(offset, count):
indexgroups = []
for x in range(0, count):
indices = {}
file.seek(offset + x * 24)
indices["count"] = binaryReader.read('uint32')
file.seek(offset + x * 24 + 16)
indices["link"] = offset + x * 24 + 16 + binaryReader.read('uint32')
indices["index"] = []
file.seek(indices["link"])
for q in range(0, indices["count"] / 3):
a = binaryReader.read("uint16")
b = binaryReader.read("uint16")
c = binaryReader.read("uint16")
#print a,b,c
indices["index"].append((a,b,c))
indexgroups.append(indices)
return indexgroups
###########
##fbx stuff
def createMesh(scene, name):
cubeMesh = fbx.FbxMesh.Create( scene, name + 'Mesh' )
cubeMesh.InitControlPoints(len(vertices))
for x in range(len(vertices)):
cubeMesh.SetControlPointAt( vertices[x], x )
# Now that the control points per polygon have been defined, we can create
# the actual polygons within the mesh.
for i in range( 0, len( indices ) ):
cubeMesh.BeginPolygon( i )
for j in range( 0, len( indices[i] ) ):
cubeMesh.AddPolygon( indices[i][j] )
cubeMesh.EndPolygon()
return cubeMesh
#create basic geometry
def addCube( pScene, cubeName, **kwargs ): #todo change this
''' Adds a cubic mesh to the scene. '''
cubeLocation = (0.0, 0.0, 0.0)
cubeScale = (1.0, 1.0, 1.0)
if kwargs.has_key("location"):
cubeLocation = kwargs["location"]
if kwargs.has_key("scale"):
cubeScale = kwargs["scale"]
rootNode = pScene.GetRootNode()
newNode = addNode(pScene, cubeName, scaling = cubeScale, location = cubeLocation)
rootNode.AddChild( newNode )
# Create a new mesh node attribute in the scene, and set it as the new node's attribute
newMesh = createMesh( pScene, cubeName )
newNode.SetNodeAttribute( newMesh )
return newNode
def addNode( pScene, nodeName, **kwargs ):
# Obtain a reference to the scene's root node.
scaling = kwargs["scaling"]
location = kwargs["location"]
newNode = fbx.FbxNode.Create( pScene, nodeName )
newNode.LclScaling.Set(fbx.FbxDouble3(scaling[0], scaling[1], scaling[2]))
newNode.LclTranslation.Set(fbx.FbxDouble3(location[0], location[1], location[2]))
# Create a new node in the scene.
return newNode
def getASCIIFormatIndex( pManager ):
''' Obtain the index of the ASCII export format. '''
# Count the number of formats we can write to.
numFormats = pManager.GetIOPluginRegistry().GetWriterFormatCount()
# Set the default format to the native binary format.
formatIndex = pManager.GetIOPluginRegistry().GetNativeWriterFormat()
# Get the FBX format index whose corresponding description contains "ascii".
for i in range( 0, numFormats ):
# First check if the writer is an FBX writer.
if pManager.GetIOPluginRegistry().WriterIsFBX( i ):
# Obtain the description of the FBX writer.
description = pManager.GetIOPluginRegistry().GetWriterFormatDescription( i )
# Check if the description contains 'ascii'.
if 'ascii' in description:
formatIndex = i
break
# Return the file format.
return formatIndex
def saveScene( pFilename, pFbxManager, pFbxScene, pAsASCII=False ):
''' Save the scene using the Python FBX API '''
exporter = fbx.FbxExporter.Create( pFbxManager, '' )
if pAsASCII:
#DEBUG: Initialize the FbxExporter object to export in ASCII.
asciiFormatIndex = getASCIIFormatIndex( pFbxManager )
isInitialized = exporter.Initialize( pFilename, asciiFormatIndex )
else:
isInitialized = exporter.Initialize( pFilename )
if( isInitialized == False ):
raise Exception( 'Exporter failed to initialize. Error returned: ' + str( exporter.GetLastErrorString() ) )
exporter.Export( pFbxScene )
exporter.Destroy()
##MAIN PROGRAM
#read data from model
filename = 'otter_dragon_model.vmesh_c'
file = open(filename, 'rb')
binaryReader = BinaryReader(file)
header = readFileHeader()
#print header
vbibheader = readVBIB(header[3]["link"])
#print vbibheader
hvertices = readVertices(vbibheader["vertexHLink"], vbibheader["vertexHCount"])
hindices = readIndices(vbibheader["indexHLink"], vbibheader["indexHCount"])
print "Number of vertices: ", hvertices[0]["count"]
print "Number of indices: ", hindices[0]["count"] / 3
attributes = readAttributes(vbibheader["vertexHLink"], vbibheader["vertexHCount"])
print attributes
#print readTexcoords(hvertices, attributes["TEXCOORD"])
#todo pass this differently, globals (?) are bad
vertices = hvertices[0]["vertex"]
indices = hindices[0]["index"]
#build fbx
global fbxManager
sceneName = filename[:filename.index('.')] #filename unril first .
fbxManager = fbx.FbxManager.Create()
fbxScene = fbx.FbxScene.Create( fbxManager, '' )
cylinderNode = addCube( fbxScene, "axesms" )
cylinderNode.SetShadingMode(fbx.FbxNode.eTextureShading);
saveScene( sceneName + ".fbx", fbxManager, fbxScene, True)
print "Save as", sceneName + ".fbx"
fbxManager.Destroy()
del fbxScene
del fbxManager
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment