'''Noesis import plugin. Written by Tsukihime''' from inc_noesis import * import noesis import rapi import os MODE = 0 def registerNoesisTypes(): '''Register the plugin. Just change the Game name and extension.''' handle = noesis.register("Dark Blood", ".prt") noesis.setHandlerTypeCheck(handle, noepyCheckType) noesis.setHandlerLoadModel(handle, noepyLoadModel) return 1 def noepyCheckType(data): '''Verify that the format is supported by this plugin. Default yes''' return 1 def load_all_models(mdlList): '''Load all models''' #carry over from previous models matList = [] texList = [] dirPath = rapi.getDirForFilePath(rapi.getInputName()) fileList = [file for file in os.listdir(dirPath) if file.lower().endswith(".prt")] for file in fileList: f = open(dirPath + file, 'rb') data2 = f.read() parser = SanaeParser(data2, file) parser.parse_file() matList.extend(parser.matList) texList.extend(parser.texList) mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(texList, matList)) mdlList.append(mdl) def load_single_model(data, mdlList): '''Loads a single model. For testing purposes''' filename = rapi.getExtensionlessName(rapi.getInputName()) parser = SanaeParser(data, filename) parser.parse_file() mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList)) mdlList.append(mdl) def noepyLoadModel(data, mdlList): '''Load the model''' ctx = rapi.rpgCreateContext() if MODE == 1: load_all_models(mdlList) else: load_single_model(data, mdlList) return 1 class Mesh(object): def __init__(self): self.name = "" self.numIdx = 0 self.numVerts = 0 self.vertSize = 0 self.vertBuff = bytes() self.idxBuffs = {} self.materials = [] class SanaeParser(object): def __init__(self, data, filename): '''Initialize some data. Refer to Sanae.py to see what is already initialized''' self.inFile = NoeBitStream(data) self.animList = [] self.texList = [] self.matList = [] self.boneList = [] self.meshList = [] self.modelName = filename def build_mesh(self): for mesh in self.meshList: rapi.rpgBindPositionBufferOfs(mesh.vertBuff, noesis.RPGEODATA_FLOAT, 32, 0) rapi.rpgBindNormalBufferOfs(mesh.vertBuff, noesis.RPGEODATA_FLOAT, 32, 12) rapi.rpgBindUV1BufferOfs(mesh.vertBuff, noesis.RPGEODATA_FLOAT, 32, 24) for matNum in mesh.idxBuffs: matName = mesh.materials[matNum].name idxBuff = mesh.idxBuffs[matNum] numIdx = len(idxBuff) // 2 rapi.rpgSetMaterial(matName) rapi.rpgCommitTriangles(idxBuff, noesis.RPGEODATA_USHORT, numIdx, noesis.RPGEO_TRIANGLE, 1) def read_name(self): length = self.inFile.readUByte() - 128 string = self.inFile.readBytes(length) return noeStrFromBytes(string) def read_tag(self): tag = self.inFile.readUByte() #0x81 high = tag & 0b11110000 low = tag & 0b00001111 return high, low def read_null(self): char = self.inFile.readByte() while char: char = self.inFile.readByte() def parse_materials(self, numMat): matList = [] for i in range(numMat): matName = "%s[%d]" %(self.modelName, len(self.matList)) self.inFile.read('17f') material = NoeMaterial(matName, "") matList.append(material) self.matList.append(material) return matList #matName = texName[0] #material = NoeMaterial(matName, "") #diffName = ".".join([texName[0], texName[1]]) #material.setTexture(diffName) #normName = ".".join([texName[0] + "_dye", texName[1]]) #material.setNormalTexture(normName) #self.matList.append(material) return matList def parse_textures(self, numMat, mesh): for i in range(numMat): texName = self.read_name() mesh.materials[i].setTexture(texName) name, ext = os.path.split(texName) normName = name + "_dye" + ext mesh.materials[i].setNormalTexture(normName) def parse_vertices(self, numVerts): return self.inFile.readBytes(numVerts*32) def parse_faces(self, numIdx): return self.inFile.readBytes(numIdx*2) def parse_unk2(self, count): self.inFile.readBytes(count*12) def parse_unk3(self, num): LIMIT = 128 for i in range(num): tag, value = self.read_tag() self.inFile.readBytes(value) count = self.inFile.readUInt() if count > LIMIT: self.parse_unk4(count, 1) else: self.parse_unk4(count) def parse_unk4(self, count, large=0): if large: self.inFile.readShort() self.inFile.readBytes(count*4) #integers self.inFile.readShort() self.inFile.readBytes(count*4) else: self.inFile.readByte() self.inFile.readBytes(count*4) self.inFile.readByte() self.inFile.readBytes(count*4) self.inFile.read('16f') #matrix? def parse_face_materials(self, numFaces, idxBuff): idxBuffs = {} self.inFile.readBytes(numFaces * 4) tag, value = self.read_tag() for i in range(value): matNum, faceStart, faceCount, unk, unk = self.inFile.read('5L') start = faceStart * 6 end = start + (faceCount)*6 tempBuff = idxBuff[start:end] idxBuffs[i] = tempBuff return idxBuffs def parse_mesh(self): self.inFile.seek(6, 1) mesh = Mesh() mesh.numVerts = self.inFile.readUInt() numFaces = self.inFile.readUInt() mesh.vertBuff = self.parse_vertices(mesh.numVerts) mesh.numIdx = numFaces * 3 mesh.idxBuff = self.parse_faces(mesh.numIdx) #face material indices mesh.idxBuffs = self.parse_face_materials(numFaces, mesh.idxBuff) numMat = self.inFile.readUInt() self.inFile.readByte() #0x80 mesh.materials = self.parse_materials(numMat) self.inFile.readByte() self.parse_textures(numMat, mesh) self.parse_unk2(numFaces) #unk 3 numSect = self.inFile.readUInt() self.inFile.readUInt() self.parse_unk3(numSect) self.meshList.append(mesh) def parse_bones(self, numBones): pass def parse_file(self): '''Main parser method''' self.inFile.readUShort() self.read_null() while not self.inFile.checkEOF(): tag = self.inFile.readUByte() if tag == 0x01: self.parse_mesh() elif tag == 0x80: break self.build_mesh()