'''
Scarlet Legacy plugin
Updated Jun 20, 2012
'''

from inc_noesis import *
import noesis
import rapi

def registerNoesisTypes():
    '''Register the plugin'''
    
    handle = noesis.register("Scarlet Legacy", ".bsm")
    noesis.setHandlerTypeCheck(handle, noepyCheckType)
    noesis.setHandlerLoadModel(handle, noepyLoadModel)
    return 1

def noepyCheckType(data):
    '''Verify the file format matches this plugin. Return 1 if yes,
    0 otherwise'''
    
    bs = NoeBitStream(data)
    idstring = noeStrFromBytes(bs.readBytes(3))
    bs.readByte()
    bs.readUInt()
    delimiter = bs.readByte()
    if idstring == "UJV" or delimiter == 1:
        return 1
    return 0

def zlib_decompress(bs):
    
    bs.seek(bs.dataSize - 4)
    size = bs.readUInt()
    bs.seek(0x40)
    zsize = bs.readUInt()    
    cmpData = bs.readBytes(zsize)
    decompData = rapi.decompInflate(cmpData, size)
    return decompData

def noepyLoadModel(data, mdlList):
    '''Build the model, set materials, bones, and animations. You do not
    need all of them as long as they are empty lists (they are by default)'''
    
    bs = NoeBitStream(data)
    if noeStrFromBytes(bs.readBytes(3)) == "UJV":
        data = zlib_decompress(bs)
    
    ctx = rapi.rpgCreateContext()
    parser = SanaeParser(data)
    parser.parse_file()
    mdl = rapi.rpgConstructModel()
    mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList))
    mdl.setBones(parser.boneList)
    mdl.setAnims(parser.animList)
    mdlList.append(mdl)
    return 1

class Mesh(object):
    
    def __init__(self):
        
        self.name = ""
        self.vertBuff = bytes()
        self.numVerts = 0
        self.idxBuff = bytes()
        self.numIdx = 0

class SanaeParser(object):
    
    def __init__(self, data):    
        self.inFile = NoeBitStream(data)
        self.animList = []
        self.texList = []
        self.matList = []
        self.boneList = []
        self.meshList = []
      
    def read_name(self):

        string = self.inFile.readBytes(self.inFile.readUInt())
        return noeStrFromBytes(string)
    
    def build_meshes(self):
        
        for i in range(len(self.meshList)):
            mesh = self.meshList[i]
            print(mesh.name)
            if "lod01" not in mesh.name:
                continue
            rapi.rpgBindPositionBufferOfs(mesh.vertBuff, noesis.RPGEODATA_FLOAT, mesh.vertSize, 0)
            rapi.rpgBindNormalBufferOfs(mesh.vertBuff, noesis.RPGEODATA_HALFFLOAT, mesh.vertSize, 6)
            rapi.rpgBindUV1BufferOfs(mesh.vertBuff, noesis.RPGEODATA_HALFFLOAT, mesh.vertSize, 10)
            matName = self.matList[i].name
            rapi.rpgSetMaterial(matName)
            rapi.rpgCommitTriangles(mesh.idxBuff, noesis.RPGEODATA_USHORT, mesh.numIdx, noesis.RPGEO_TRIANGLE, 1)
    
    def parse_vertices(self, numVerts, vertSize):
        
        return self.inFile.readBytes(numVerts*vertSize)
           
    def parse_faces(self, numIdx):
        
        return self.inFile.readBytes(numIdx*2)
            
    def parse_unkData1(self):
        
        unk1 = self.inFile.readUInt()
        for i in range(unk1):
            self.read_name()
            self.read_name()
            self.inFile.read('7b')
            self.inFile.read('48f')
            check = self.inFile.readUInt()
            while check:
                self.read_name()
                self.inFile.read('7b')
                self.inFile.read('48f')
                check = self.inFile.readUInt()
        
    def parse_materials(self):
        
        unk2 = self.inFile.readUInt()
        self.inFile.read('2L')
        for i in range(unk2):
            self.inFile.read('2L')
        if unk2 == 1:
            matName = self.read_name()
            
            material = NoeMaterial(matName, "")
            material.setTexture(matName + "_D")
            self.matList.append(material)
        else:
            count = self.inFile.readUInt()
            for i in range(count):
                matName = self.read_name()
            material = NoeMaterial(matName, "")
            material.setTexture(matName + "_D")
            self.matList.append(material)            
                
    def parse_meshBones(self, numBones):
        
        for i in range(numBones):
            self.read_name()
                
    def parse_mesh(self, numMesh):
        
        for i in range(numMesh):
            mesh = Mesh()
            self.inFile.readUByte()
            mesh.name = self.read_name()
            meshType = self.inFile.readUInt()
            self.inFile.readUInt()
            if meshType == 6:
                self.inFile.seek(98, 1)
            elif meshType == 5:
                self.inFile.seek(81, 1)
                
            mesh.numVerts, mesh.vertSize = self.inFile.read('2L')
            self.inFile.readUByte()
            mesh.vertBuff = self.parse_vertices(mesh.numVerts, mesh.vertSize)
            
            mesh.numIdx, idxSize = self.inFile.read('2L')
            self.inFile.readUByte()
            mesh.idxBuff = self.parse_faces(mesh.numIdx)
            self.inFile.readUInt()
            self.inFile.read('6f')
            numBones = self.inFile.readUInt()
            self.parse_meshBones(numBones)
            self.parse_unkData1()
            self.parse_materials()
            self.meshList.append(mesh)

    def parse_file(self):
        '''Main parser method. Can be replaced'''
        
        self.inFile.readUInt()
        numMesh = self.inFile.readUInt()
        self.parse_mesh(numMesh)
        self.build_meshes()