Last active
February 23, 2016 16:16
-
-
Save Numbers11/34d9a567736b03ba4a3d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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