from inc_noesis import * import noesis import rapi import struct def registerNoesisTypes(): '''Register the plugin''' handle = noesis.register("AliceSoft", ".pol") 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) < 3: return 0 bs = NoeBitStream(data) idstring = noeStrFromBytes(bs.readBytes(4)) if idstring in ["ZLB", "POL"]: return 1 return 0 def zlib_decompress(bs): unk, size, zsize = bs.read('3L') cmpData = bs.readBytes(zsize) decompData = rapi.decompInflate(cmpData, size) return decompData def noepyLoadModel(data, mdlList): '''Load the model''' ctx = rapi.rpgCreateContext() #check for compression bs = NoeBitStream(data) idstring = noeStrFromBytes(bs.readBytes(4)) if idstring == "ZLB": data = zlib_decompress(bs) parser = RanceQuest_POL(data) parser.parse_file() mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList)) mdlList.append(mdl) return 1 class Mesh(object): def __init__(self): self.name = "" self.matNum = -1 self.vertBuff = bytes() self.numVerts = 0 self.normBuff = bytes() self.uvBuff = bytes() self.uv2Buff = bytes() self.numUV = 0 self.idxList = [] self.uvList = [] self.numFaces = 0 class RanceQuest_POL(object): def __init__(self, data): self.inFile = NoeBitStream(data) self.animList = [] self.texList = [] self.matList = [] self.boneList = [] self.meshList = [] def check_padding(self): unk = self.inFile.readInt() while unk == -1: unk = self.inFile.readInt() return unk def read_name(self): string = bytes() char = self.inFile.readBytes(1) while char != b'\x00': string += char char = self.inFile.readBytes(1) try: return noeStrFromBytes(string) except: return noeStrFromBytes(string, "shift-JIS") def invert_faces(self): '''Negates the x-coord of all vertices in the mesh''' trans = NoeMat43((NoeVec3((-1, 0, 0)), NoeVec3((0, 1, 0)), NoeVec3((0, 0, 1)), NoeVec3((0, 0, 0)))) rapi.rpgSetTransform(trans) #def build_buffers(self, mesh): #idxBuff = bytes() #normBuff = bytes() #vertBuff = bytes() #uvBuff = bytes() #count = 0 #for i in range(mesh.numFaces): #for j in range(3): #index = mesh.idxList[i][j] #uvIdx = mesh.uvList[i][j] #vertBuff += mesh.vertBuff[index*4: index*4 + 12] #uvBuff += mesh.uvBuff[uvIdx*4 : uvIdx*4 + 8] #idxBuff += struct.pack('L', count) #count += 1 #mesh.vertBuff = vertBuff #mesh.uvBuff = uvBuff #mesh.idxBuff = idxBuff #mesh.numIdx = len(idxBuff) // 4 #mesh.numVerts = len(vertBuff) // 12 def build_meshes(self): for i in range(len(self.meshList)): mesh = self.meshList[i] if mesh.numVerts > 0: rapi.rpgBindPositionBuffer(mesh.vertBuff, noesis.RPGEODATA_FLOAT, 12) self.invert_faces() if mesh.matNum != -1: matName = self.matList[mesh.matNum].name rapi.rpgSetMaterial(matName) rapi.rpgCommitTriangles(mesh.idxBuff, noesis.RPGEODATA_UINT, mesh.numIdx, noesis.RPGEO_TRIANGLE, 1) def parse_bones(self, numBones): for i in range(numBones): boneName = self.read_name() unk1, unk2 = self.inFile.read('2L') self.inFile.read('7f') def parse_submaterials(self, numMat): for i in range(numMat): matName = self.read_name() index = self.inFile.readUInt() if index >= 1: texName = self.read_name() unk2 = self.inFile.readUInt() if index >= 2: texName2 = self.read_name() unk3 = self.inFile.readUInt() if index >= 3: self.read_name() self.inFile.readUInt() if index >= 4: self.read_name() self.inFile.readUInt() def parse_materials(self, numMat): for i in range(numMat): matName = self.read_name() material = NoeMaterial(matName, "") index = self.inFile.readUInt() if index == 0: #submaterials numSubMat = self.inFile.readUInt() self.parse_submaterials(numSubMat) else: texName = self.read_name() material.setTexture(texName) if index >= 2: self.inFile.readUInt() specName = self.read_name() if index >= 3: self.inFile.readUInt() glareName = self.read_name() if index >= 4: self.inFile.readUInt() normName = self.read_name() if index >= 5: self.inFile.readUInt() heightName = self.read_name() unk2, unk3 = self.inFile.read('2L') self.matList.append(material) def parse_vertices(self, numVerts): vertBuff = bytes() if self.meshType == 1: for i in range(numVerts): verts = self.inFile.readBytes(12) unk1, unk2 = self.inFile.read('2H') if unk1 == 1 and unk2 != 0: self.inFile.readFloat() else: for j in range(unk1): boneIndex = self.inFile.readUInt() boneWeight = self.inFile.readFloat() vertBuff += verts elif self.meshType == 2: for i in range(numVerts): verts = self.inFile.readBytes(12) unk1 = self.inFile.readUShort() for j in range(unk1): boneIndex = self.inFile.readUShort() boneWeight = self.inFile.readFloat() vertBuff += verts return vertBuff def parse_UV(self, numUV): return self.inFile.readBytes(numUV * 8) def parse_UV2(self, numUV): return self.inFile.readBytes(numUV * 8) def parse_faces(self, numFace, numUV2, unk2): idxBuff = bytes() uvList = [] for j in range(numFace): indexes = self.inFile.readBytes(12) #indexes = self.inFile.read('3L') uvs = self.inFile.read('3L') if numUV2 or unk2: uv21, uv22, uv23 = self.inFile.read('3L') self.inFile.read('3L') self.inFile.read('9f') self.inFile.readUInt() idxBuff += indexes uvList.append(uvs) return idxBuff, uvList def parse_unk(self, count): if self.meshType == 1: self.inFile.seek(count*12, 1) elif self.meshType == 2: self.inFile.seek(count*4, 1) def parse_unk2(self, count): self.inFile.seek(count, 1) def parse_meshes(self, numMesh): for i in range(numMesh): mesh = Mesh() mesh.name = self.read_name() mesh.matNum = self.inFile.readInt() mesh.numVerts = self.inFile.readUInt() mesh.vertBuff = self.parse_vertices(mesh.numVerts) mesh.numUV = self.inFile.readUInt() mesh.uvBuff = self.parse_UV(mesh.numUV) numUV2 = self.inFile.readUInt() self.parse_UV2(numUV2) numUnk = self.inFile.readUInt() self.parse_unk(numUnk) numUnk2 = 0 if self.meshType == 2: numUnk2 = self.inFile.readUInt() self.parse_unk2(numUnk2) mesh.numFaces = self.inFile.readUInt() mesh.idxBuff, mesh.uvList = self.parse_faces(mesh.numFaces, numUV2, numUnk2) mesh.numIdx = mesh.numFaces * 3 if self.meshType == 1: self.inFile.seek(8, 1) self.meshList.append(mesh) numBones = self.check_padding() if numBones > 0: break #self.parse_bones(numBones) def parse_file(self): idstring = self.inFile.readBytes(4) self.meshType = self.inFile.readUInt() numMat = self.inFile.readUInt() self.parse_materials(numMat) numMesh = self.inFile.readUInt() self.check_padding() self.parse_meshes(numMesh) self.build_meshes()