Skip to content
Permalink
 
 
Cannot retrieve contributors at this time
from inc_noesis import *
import noesis
import rapi
import os
#Define token constants
TOKEN_NAME = 1
TOKEN_STRING = 2
TOKEN_INTEGER = 3
TOKEN_GUID = 5
TOKEN_INTEGER_LIST = 6
TOKEN_FLOAT_LIST = 7
TOKEN_OBRACE = 10
TOKEN_CBRACE = 11
TOKEN_OPAREN = 12
TOKEN_CPAREN = 13
TOKEN_OBRACKET = 14
TOKEN_CBRACKET = 15
TOKEN_OANGLE = 16
TOKEN_CANGLE = 17
TOKEN_DOT = 18
TOKEN_COMMA = 19
TOKEN_SEMICOLON = 20
TOKEN_TEMPLATE = 31
TOKEN_WORD = 40
TOKEN_DWORD = 41
TOKEN_FLOAT = 42
TOKEN_DOUBLE = 43
TOKEN_CHAR = 44
TOKEN_UCHAR = 45
TOKEN_SWORD = 46
TOKEN_SDWORD = 47
TOKEN_VOID = 48
TOKEN_LPSTR = 49
TOKEN_UNICODE = 50
TOKEN_CSTRING = 51
TOKEN_ARRAY = 52
RECORD_BEARING = [TOKEN_NAME, TOKEN_STRING, TOKEN_INTEGER, TOKEN_GUID,
TOKEN_INTEGER_LIST, TOKEN_FLOAT_LIST]
def registerNoesisTypes():
'''Register the plugin'''
handle = noesis.register("DirectX Binary", ".x;.sxm")
noesis.setHandlerTypeCheck(handle, noepyCheckType)
noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
return 1
def noepyCheckType(data):
'''Verify that the format is supported by this plugin.'''
if len(data) < 16:
return 0
bs = NoeBitStream(data)
header = noeStrFromBytes(bs.readBytes(4))
if header != "xof ":
return 0
version = bs.read('2H')
format = noeStrFromBytes(bs.readBytes(4))
if format != "bin ":
return 0
return 1
def noepyLoadModel(data, mdlList):
'''Load the model'''
ctx = rapi.rpgCreateContext()
parser = DirectX_XBIN(data)
parser.parse_file()
mdl = rapi.rpgConstructModel()
mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList))
#mdl.setBones(parser.boneList)
mdlList.append(mdl)
return 1
class Template(object):
'''A template class that may contain tokens and other templates'''
def __init__(self, parent):
self.parent = parent
self.templates = []
self.tokens = []
self.name = ""
self.isDefinition = False
def __repr__(self):
return "Template: %s" %self.name
def get_token(self):
if self.tokens:
return self.tokens.pop(0)
else:
return None
def add_name(self, name):
if not self.name:
self.name = name
def add_token(self, token):
self.tokens.append(token)
def add_template(self, template):
self.templates.append(template)
def template_count(self):
count = 0
if self.templates:
for template in self.templates:
count = template.template_count()
return len(self.templates) + count
def print_templates(self, depth = 0):
'''Recursively prints out contents of the template and any nested
templates'''
print(" "*depth, "|-", self.name, self.tokens)
for template in self.templates:
template.print_templates(depth+1)
class Token(object):
'''A generic token'''
def __init__(self, tokenID):
self.token = tokenID
def __repr__(self):
return "<<%s>>" %self.token
def __eq__(self, other):
return self.token == other
class RecordToken(Token):
'''A record bearing token. Contains values'''
def __init__(self, tokenID):
super(RecordToken, self).__init__(tokenID)
self.value = ""
def get_value(self):
return self.value
def __repr__(self):
if self.token == TOKEN_NAME:
return "<<%s>>" %self.value
else:
return "<<%s>>" %self.token
class DirectX_XBIN(object):
def __init__(self, data):
self.inFile = NoeBitStream(data)
self.animList = []
self.texList = []
self.matList = []
self.boneList = []
self.meshes = []
self.materials = []
self.dirpath = rapi.getDirForFilePath(rapi.getInputName())
def read_name(self):
string = self.inFile.readBytes(self.inFile.readUInt())
return noeStrFromBytes(string)
def parse_header(self):
header = self.inFile.readBytes(16)
def parse_token_guid(self):
return self.inFile.read('16B')
def parse_int_list(self):
numInt = self.inFile.readUInt()
return [numInt, self.inFile.readBytes(4*numInt)]
def parse_float_list(self):
numFloat = self.inFile.readUInt()
data = self.inFile.readBytes(4*numFloat)
return [numFloat, data]
def update_template(self, tokens, template):
for token in tokens:
if token == TOKEN_TEMPLATE:
template.isDefinition = True
elif token == TOKEN_NAME:
if not template.name:
template.add_name(token.value)
else:
template.add_token(token)
def read_token(self, parent, tokens=None):
'''Read tokens for the template. Additional tokens may have been parsed
for this template before the OBRACE and are available in tokens'''
template = Template(parent)
if tokens:
self.update_template(tokens, template)
#temp token storage, for things like template name which is defined
#before the open brace
temp = []
#parse token
while self.inFile.tell() != self.inFile.dataSize:
token = self.inFile.readUShort()
if token in RECORD_BEARING:
new_token = RecordToken(token)
if token == TOKEN_NAME:
name = self.read_name()
new_token.value = name
temp.append(new_token)
elif token == TOKEN_STRING:
name = self.read_name()
terminator = self.inFile.readUShort()
new_token.value = name
template.add_token(new_token)
elif token == TOKEN_INTEGER:
value = self.inFile.readUInt()
new_token.value = value
template.add_token(new_token)
elif token == TOKEN_GUID:
self.parse_token_guid()
template.add_token(new_token)
elif token == TOKEN_INTEGER_LIST:
value = self.parse_int_list()
new_token.value = value
template.add_token(new_token)
elif token == TOKEN_FLOAT_LIST:
value = self.parse_float_list()
new_token.value = value
template.add_token(new_token)
elif token == TOKEN_TEMPLATE:
new_token = Token(token)
temp.append(new_token)
elif token == TOKEN_OBRACE:
#nested template
new_template = self.read_token(template, temp)
temp = []
elif token == TOKEN_CBRACE:
parent.add_template(template)
return template
elif token == TOKEN_OPAREN:
pass
elif token == TOKEN_CPAREN:
pass
elif token == TOKEN_DOT:
pass
elif token == TOKEN_OBRACKET:
pass
elif token == TOKEN_CBRACKET:
pass
elif token == TOKEN_ARRAY:
pass
elif token == TOKEN_SEMICOLON:
pass
elif token == TOKEN_FLOAT:
pass
elif token == TOKEN_DWORD:
pass
elif token == TOKEN_LPSTR:
pass
else:
print("unknown token", token, self.inFile.tell())
break
#add everything to the root
parent.add_template(template)
return template
def parse_file(self):
self.parse_header()
root = Template(None)
binx = self.read_token(root)
binx.add_name("root")
#binx.print_templates()
#Build the model
self.traverse_templates(binx, None)
self.build_model()
#====================================================
def build_faces(self, idxBuff, matUsed, materials):
start = 0
for i in range(len(matUsed)):
numIdx = matUsed[i] * 3
end = start + numIdx * 4
buff = idxBuff[start:end]
rapi.rpgSetMaterial(materials[i])
rapi.rpgCommitTriangles(buff, noesis.RPGEODATA_UINT, numIdx, noesis.RPGEO_TRIANGLE, 1)
start = end
def build_model(self):
for mesh in self.meshes:
positions = mesh["pos"]
rapi.rpgBindPositionBuffer(positions, noesis.RPGEODATA_FLOAT, 12)
if "norms" in mesh:
normals = mesh["norms"]
#rapi.rpgBindNormalBuffer(normals, noesis.RPGEODATA_FLOAT, 12)
if "uv" in mesh:
uv = mesh["uv"]
rapi.rpgBindUV1Buffer(uv, noesis.RPGEODATA_FLOAT, 8)
if "matIndexes" in mesh:
matUsed = mesh["matIndexes"]
idxBuff = mesh["idx"]
numIdx = mesh["numIdx"]
#print(numIdx)
if "materials" in mesh:
materials = mesh["materials"]
else:
materials = self.materials
#rapi.rpgCommitTriangles(idxBuff, noesis.RPGEODATA_UINT, numIdx, noesis.RPGEO_TRIANGLE, 1)
self.build_faces(idxBuff, matUsed, materials)
rapi.rpgClearBufferBinds()
#====================================================
def build_frame(self, tokens):
pass
def parse_faces(self, token):
data = token.get_value()[1]
stream = NoeBitStream(data)
idxBuff = bytes()
numFaces = stream.readUInt()
for i in range(numFaces):
verts = stream.readUInt()
idxBuff += stream.readBytes(verts*4)
self.meshes[-1]["numIdx"] = numFaces * 3
self.meshes[-1]["idx"] = idxBuff
def parse_vertices(self, token):
numFloats, data = token.get_value()
self.meshes[-1]["pos"] = data
def assign_normals(self, template):
token = template.get_token()
token = template.get_token()
numFloats, data = token.get_value()
self.meshes[-1]["norms"] = data
def assign_uv(self, template):
token = template.get_token()
token = template.get_token()
numFloats, data = token.get_value()
self.meshes[-1]["uv"] = data
def parse_material_list(self, template):
token = template.get_token()
if token:
numInt, data = token.get_value()
stream = NoeBitStream(data)
numMat, numFaces = stream.read('2L')
matIndexes = stream.read('%dL' %numFaces)
indexes = []
for i in range(30):
count = matIndexes.count(i)
if not count:
break
indexes.append(count)
self.meshes[-1]["matIndexes"] = indexes
def parse_material(self, template):
token = template.get_token()
if token == TOKEN_NAME:
token = template.get_token()
numFloats, data = token.get_value()
numMat = len(self.matList)
matName = "Material[%d]" %numMat
material = NoeMaterial(matName, "")
self.matList.append(material)
if self.meshes:
self.meshes[-1]["materials"].append(matName)
else:
self.materials.append(matName)
def parse_texture(self, template):
token = template.get_token()
if token:
texName = os.path.basename(token.get_value())
ext = os.path.splitext(texName)[1]
texPath = self.dirpath + texName
if rapi.checkFileExists(texPath):
f = open(texPath, 'rb')
tex = rapi.loadTexByHandler(f.read(), ext)
print(texName, ext)
if tex is not None:
tex.name = texName
self.texList.append(tex)
self.matList[-1].setTexture(texName)
f.close()
def parse_mesh(self, template):
'''Build a mesh from the template'''
#initialize a dict for the mesh object
self.meshes.append({})
self.meshes[-1]["materials"] = []
token = template.get_token()
if token == TOKEN_NAME:
rapi.rpgSetName(token.get_value())
token = template.get_token()
numVerts = token.get_value()[1]
token = template.get_token()
self.parse_vertices(token)
token = template.get_token()
self.parse_faces(token)
def traverse_templates(self, current, parent):
templateName = current.name
if not current.isDefinition:
if templateName == "Frame":
self.build_frame(current)
elif templateName == "Mesh":
self.parse_mesh(current)
elif templateName == "MeshNormals":
self.assign_normals(current)
elif templateName == "MeshTextureCoords":
self.assign_uv(current)
elif templateName == "MeshMaterialList":
self.parse_material_list(current)
elif templateName == "Material":
self.parse_material(current)
elif templateName == "TextureFilename":
self.parse_texture(current)
for template in current.templates:
self.traverse_templates(template, current)