def parse_file(self): idstring = self.inFile.read('5s') headerSize = self.inFile.readUInt() flags = self.inFile.read('4B') height, width, pitch, depth, mips = self.inFile.read('5L') #lazy self.inFile.seek(85) fmt = noeStrFromBytes(self.inFile.readBytes(4)) if fmt == "2z73": texFmt = noesis.NOESISTEX_DXT1 elif fmt == "7x0s": texFmt = noesis.NOESISTEX_DXT3 else: print("unknown pixel format") #lazy again self.inFile.seek(129) dataSize = self.inFile.dataSize - self.inFile.tell() pixelData = self.inFile.readBytes(dataSize) name = rapi.getLocalFileName(rapi.getInputName()).split('.')[0] tex = NoeTexture(name, width, height, pixelData, texFmt) self.texList.append(tex)
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)''' ctx = rapi.rpgCreateContext() filename = rapi.getLocalFileName(rapi.getInputName()) fileID = ''.join(c for c in filename if c.isdigit()) bs = NoeBitStream(data) idstring = bs.readUInt() idstring2 = bs.readUInt() if idstring == 1213416781: #MESH if idstring2 == 1: parser = StaticParser1(data) elif idstring2 == 2: parser = StaticParser2(data) else: parser = SanaeParser(data) print(idstring) 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
def parse_material(self): '''Assume texName is the same as the input name''' matName = rapi.getLocalFileName(rapi.getInputName()).split('.')[0] texName = matName + ".wys" material = NoeMaterial(matName, texName) material.setDefaultBlend(0) self.matList.append(material)
def load_single_model(data, mdlList): '''Loads a single model. For testing purposes''' filename, ext = os.path.splitext(rapi.getLocalFileName(rapi.getInputName())) parser = SanaeParser(data) parser.parse_file(filename) mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList)) mdlList.append(mdl)
def noepyCheckType(data): '''Verify that the format is supported by this plugin. Default yes''' filename = rapi.getLocalFileName(rapi.getInputName()) if not ( rapi.checkFileExt(filename, '.3DO') or \ rapi.checkFileExt(filename, '.3DC') or \ rapi.checkFileExt(filename, '.SMOD')): return 0 return 1
def get_type(data): filename = rapi.getLocalFileName(rapi.getInputName()) if rapi.checkFileExt(filename, '.3DO'): return Shaiya3DO(data) elif rapi.checkFileExt(filename, '.3DC'): return Shaiya3DC(data) elif rapi.checkFileExt(filename, '.SMOD'): return ShaiyaSMOD(data)
def __init__(self, data): '''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.basename = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName()))
def noepyLoadModel(data, mdlList): ctx = rapi.rpgCreateContext() filename = rapi.getLocalFileName(rapi.getInputName()) parser = SanaeParser(data, filename) parser.parse_file() mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList)) mdlList.append(mdl) return 1
def noepyCheckType(data): '''Verify that the format is supported by this plugin. Default yes''' # file ID is the numeric part of the filename filename = rapi.getLocalFileName(rapi.getInputName()) fileID = ''.join(c for c in filename if c.isdigit()) bs = NoeBitStream(data) idstring = bs.readUInt() if idstring == int(fileID) or idstring == 1213416781: #MESH return 1 return 0
def __init__(self, data): '''Initialize some data. Refer to Sanae.py to see what is already initialized''' self.inFile = NoeBitStream(data, _ENDIAN) self.animList = [] self.texList = [] self.matList = [] self.boneList = [] self.meshList = [] self.filename = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName()))
def noepyLoadModel(data, mdlList): ctx = rapi.rpgCreateContext() global dirPath global fileName dirPath = rapi.getDirForFilePath(rapi.getInputName()) fileName = rapi.getLocalFileName(rapi.getInputName()) file = GOBJ(data) mdlList.append(file.mdl) rapi.rpgClearBufferBinds() return 1
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)''' inputName = rapi.getLocalFileName(rapi.getInputName()) filename, ext = os.path.splitext(inputName) ctx = rapi.rpgCreateContext() parser = SanaeParser(data, filename) 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
def build_mesh(self, numGroups, vertBuff, idxBuff): inputName = rapi.getLocalFileName(rapi.getInputName()) filename, ext = os.path.splitext(inputName) for i in range(numGroups): vertOfs, numVerts, idxOfs, numIdx = self.meshList[i] vertStart = vertOfs * 80 vertEnd = vertStart + (numVerts * 80) idxStart = idxOfs * 2 idxEnd = idxStart + (numIdx * 2) vbuff = vertBuff[vertStart:vertEnd] ibuff = idxBuff[idxStart:idxEnd] rapi.rpgBindPositionBufferOfs(vbuff, noesis.RPGEODATA_FLOAT, 80, 0) rapi.rpgBindNormalBufferOfs(vbuff, noesis.RPGEODATA_FLOAT, 80, 60) rapi.rpgBindUV1BufferOfs(vbuff, noesis.RPGEODATA_FLOAT, 80, 72) rapi.rpgSetMaterial(filename + "_d") rapi.rpgCommitTriangles(ibuff, noesis.RPGEODATA_USHORT, numIdx, noesis.RPGEO_TRIANGLE, 1)
def load_all_models(mdlList): '''Load all models''' #carry over from previous models matList = [] texList = [] filename = rapi.getLocalFileName(rapi.getInputName()) baseName = filename[:8] dirPath = rapi.getDirForFilePath(rapi.getInputName()) fileList = [file for file in os.listdir(dirPath) if file.lower().endswith(".mdl") and baseName in file] for file in fileList: f = open(dirPath + file, 'rb') data2 = f.read() parser = SanaeParser(data2) parser.parse_file() matList.extend(parser.matList) texList.extend(parser.texList) mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(texList, matList)) mdlList.append(mdl)
def __init__(self, tex_list, name=None, t_map=None, path=None, data=None): if name: self.name = name else: self.name = rapi.getLocalFileName(rapi.getInputName()) self.map = t_map self.tex_list = tex_list self.count = 0 self.bs = None if data: self.data = data elif path: with open(path, 'rb') as tex_file: self.data = tex_file else: self.log("[WPG] No input provided!") self.is_valid = WPGFile.is_valid_data(self.data) self.log("__init__: name={}, map={}, path={}, is_valid={}", self.name, self.map, path, self.is_valid)
def load_all_models(mdlList): '''Load all models''' #carry over from previous models matList = [] texList = [] filename = rapi.getLocalFileName(rapi.getInputName()) baseName = filename[:8] dirPath = rapi.getDirForFilePath(rapi.getInputName()) fileList = [ file for file in os.listdir(dirPath) if file.lower().endswith(".mdl") and baseName in file ] for file in fileList: f = open(dirPath + file, 'rb') data2 = f.read() parser = SanaeParser(data2) parser.parse_file() matList.extend(parser.matList) texList.extend(parser.texList) mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(texList, matList)) mdlList.append(mdl)
def pso2LoadModel(data, mdlList): ctx = rapi.rpgCreateContext() bs = NoeBitStream(data) Bones = [] Bone_Pallet = [] Bone_Matrix = [] Bone_Name = [] Bone_Parent = [] vertSize = [] vertCount = [] vtxeOffset = [] vtxlOffset = [] psetOffset = [] boneFileName = rapi.getDirForFilePath(rapi.getInputName()) + rapi.getLocalFileName(rapi.getInputName()).rstrip(".aqo") + ".aqn" if (rapi.checkFileExists(boneFileName)): boneData = rapi.loadIntoByteArray(boneFileName) if boneData is not None: bd = NoeBitStream(boneData) bd.seek(0xC, NOESEEK_ABS) start = bd.readInt() bd.seek(start + 0x10, NOESEEK_ABS) while not bd.checkEOF(): chunkStart = bd.tell() chunkType = bd.readBytes(4).decode("ASCII") chunkSize = bd.readInt() subChunkType = bd.readBytes(4).decode("ASCII") #print([chunkType,chunkSize,subChunkType]) for case in switch(subChunkType): if case('AQGF'): bd.seek(chunkStart + chunkSize, NOESEEK_ABS) break if case('ROOT'): bd.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('NODE'): bd.seek(6, NOESEEK_REL) while bd.tell() < chunkStart + 8 + chunkSize: nodeChunkStart = bd.tell() nodeChunkType = bd.readUShort() #print([nodeChunkType,nodeChunkStart]) for case in switch(nodeChunkType): if case(0x903): nodeTest1 = bd.readInt() break if case(0x804): BoneParent = bd.readInt() Bone_Parent.append(BoneParent) break if case(0x80F): nodeTest1 = bd.readInt() break if case(0x805): nodeTest1 = bd.readInt() break if case(0x806): nodeTest1 = bd.readInt() break if case(0x4A07): bd.seek(0xD, NOESEEK_REL) break if case(0x4A08): bd.seek(0xD, NOESEEK_REL) break if case(0x4A09): bd.seek(0xD, NOESEEK_REL) break if case(0xCA0A): bd.seek(0x2, NOESEEK_REL) BoneMatrix = NoeMat44.fromBytes(bd.readBytes(64)).toMat43() Bone_Matrix.append(BoneMatrix.inverse()) break if case(0x90B): nodeTest1 = bd.readInt() break if case(0x90C): nodeTest1 = bd.readInt() break if case(0x20D): nSize = bd.readUByte() boneName = bd.readBytes(nSize).decode("ASCII") Bone_Name.append(boneName) break if case(0xFD): break break if case('NODO'): bd.seek(bd.getSize(), NOESEEK_ABS) break if case(): # default, could also just omit condition or 'if True' bd.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) # No need to break here, it'll stop anyway for a in range(0, len(Bone_Matrix)): bn = NoeBone(a, Bone_Name[a], Bone_Matrix[a], None, Bone_Parent[a]) Bones.append(bn) aqoMagic = bs.readInt() while not bs.checkEOF(): chunkStart = bs.tell() chunkType = bs.readBytes(4).decode("ASCII") chunkSize = bs.readInt() subChunkType = bs.readBytes(4).decode("ASCII") #print([chunkType,chunkSize,subChunkType]) for case in switch(subChunkType): if case('AQGF'): bs.seek(chunkStart + chunkSize, NOESEEK_ABS) break if case('ROOT'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('OBJC'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('VSET'): while bs.tell() < chunkStart + 8 + chunkSize: vsetChunkStart = bs.tell() vsetChunkType = bs.readUShort() #print([vsetChunkStart,vsetChunkType]) for case in switch(vsetChunkType): if case(0x9B6): vsetVertSize = bs.readInt() vertSize.append(vsetVertSize) #print([vsetChunkType,vsetVertSize]) break if case(0x9BF): vsetUnk01 = bs.readInt() break if case(0x9B9): vsetVertCount = bs.readInt() vertCount.append(vsetVertCount) #print([vsetChunkType,vsetVertCount]) break if case(0x9C4): vsetUnk01 = bs.readInt() break if case(0x9BD): vsetUnk01 = bs.readInt() if vsetUnk01 == 0: Bone_Pallet.append(()) break if case(0x86BE): test = bs.readByte() test = bs.readUByte() BonePallet = bs.read("H"*(test + 1)) Bone_Pallet.append(BonePallet) break if case(0x6BE): test = bs.readByte() test = bs.readUByte() Bone_Pallet.append(()) break if case(0x9C8): vsetUnk01 = bs.readInt() break if case(0x9CC): vsetUnk01 = bs.readInt() break if case(0x9C9): vsetUnk01 = bs.readInt() break if case(0xFD): break bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('VTXE'): vtxeOffset.append([chunkStart,chunkSize]) bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('MESH'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('REND'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('SHAD'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('SHAP'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('TSTA'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('TSET'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('VTXL'): vtxlOffset.append([chunkStart,chunkSize]) bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('TEXF'): bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case('PSET'): psetOffset.append(chunkStart) bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) break if case(): # default, could also just omit condition or 'if True' bs.seek(chunkStart + 8 + chunkSize, NOESEEK_ABS) # No need to break here, it'll stop anyway #bs.readBytes(8).decode("ASCII").rstrip("\0") FaceOff = psetOffset[0] + 18 rapi.rpgSetUVScaleBias(NoeVec3 ((1.0, -1.0, 1.0)), NoeVec3 ((1.0, 1.0, 1.0))) for i in range(0, len(vertSize)): bs.seek(vtxlOffset[i][0] + 18, NOESEEK_ABS) test = bs.readByte() if test == 8: test = bs.readUByte() VertBuff = bs.readBytes(vtxlOffset[i][1] - 12) elif test == 24: test = bs.readInt() VertBuff = bs.readBytes(vtxlOffset[i][1] - 15) else: test = bs.readUShort() VertBuff = bs.readBytes(vtxlOffset[i][1] - 13) bs.seek(vtxeOffset[i][0] + 18, NOESEEK_ABS) for j in range(0, (vtxeOffset[i][1] - 10) // 26): vtxeChunkTypeid = bs.readUShort() vtxeChunkType = bs.readInt() vtxeChunkType2id = bs.readUShort() vtxeChunkType2 = bs.readInt() vtxeChunkPosId = bs.readUShort() vtxeChunkPos = bs.readInt() vtxeChunkUnkid = bs.readUShort() vtxeChunkUnk = bs.readInt() vtxeChunkTerm = bs.readUShort() if vtxeChunkType == 0: rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, vertSize[i], vtxeChunkPos) elif vtxeChunkType == 1: rapi.rpgBindBoneWeightBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, vertSize[i], vtxeChunkPos, 4) elif vtxeChunkType == 2: #rapi.rpgBindNormalBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, vertSize[i], vtxeChunkPos) pass elif vtxeChunkType == 3: rapi.rpgBindColorBufferOfs(VertBuff, noesis.RPGEODATA_UBYTE, vertSize[i], vtxeChunkPos, 4) elif vtxeChunkType == 4: pass#4 bytes as floats 2nd vertex color? elif vtxeChunkType == 11: rapi.rpgBindBoneIndexBufferOfs(VertBuff, noesis.RPGEODATA_UBYTE, vertSize[i], vtxeChunkPos, 4) elif vtxeChunkType == 16: rapi.rpgBindUV1BufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, vertSize[i], vtxeChunkPos) elif vtxeChunkType == 17: rapi.rpgBindUV2BufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, vertSize[i], vtxeChunkPos) elif vtxeChunkType == 32: pass#tangents? elif vtxeChunkType == 33: pass#binormals/tangents? else: print(vtxeChunkType) bs.seek(FaceOff, NOESEEK_ABS) bs.seek(0x1A, NOESEEK_REL) test = bs.readByte() if test == 8: FaceCount = bs.readUByte() FaceBuff = bs.readBytes((FaceCount + 1) * 2) elif test == 16: FaceCount = bs.readUShort() FaceBuff = bs.readBytes((FaceCount + 1) * 2) else: FaceCount = bs.readInt() FaceBuff = bs.readBytes((FaceCount + 1) * 2) bs.seek(0x8, NOESEEK_REL) FaceOff = bs.tell() rapi.rpgSetName(str(i)) rapi.rpgSetMaterial(str(i)) material = NoeMaterial((str(i)), "") if len(Bone_Pallet) > 0: if len(Bone_Pallet[i]) > 0: rapi.rpgSetBoneMap(Bone_Pallet[i]) rapi.rpgCommitTriangles(FaceBuff, noesis.RPGEODATA_USHORT, FaceCount + 1, noesis.RPGEO_TRIANGLE_STRIP, 1) mdl = rapi.rpgConstructModel() mdl.setBones(Bones) mdlList.append(mdl) rapi.rpgClearBufferBinds() return 1
def basename(self): '''Returns the filename without extension''' filename = rapi.getLocalFileName(rapi.getInputName()) basename, ext = os.path.splitext(filename) return basename
def texLoadARGB(data, texList): bs = NoeBitStream(data) magic = bs.readUInt() if magic == 5784916 or magic == 1413830656: bigEndian = False if magic == 1413830656: bigEndian = True bs.setEndian(NOE_BIGENDIAN) bs.setByteEndianForBits(NOE_BIGENDIAN) Version = bs.readBits(12) if Version == 16: print( "Monster Hunter World textures not supported! Use Jodo's Texture Converter on Nexus Mods." ) return 0 unkn1 = bs.readBits(12) unused1 = bs.readBits(4) alphaFlags = bs.readBits(4) MipMapCount = bs.readBits(6) Width = bs.readBits(13) Height = bs.readBits(13) unkn2 = bs.readByte() Format = bs.readByte() unkn3 = bs.readUShort() Length = Width * Height if Version == 160: Length = bs.readUInt() if Debug: print("Endian: {endian}".format( endian="Big" if bigEndian else "Little")) print("Version: {}".format(Version)) print("Format: {}".format(Format)) print("Width: {}".format(Width)) print("Height: {}".format(Height)) print("Length: {}".format(Length)) MipOffsets = [] if Version == 160: for i in range(MipMapCount): MipOffsets.append(bs.readUInt()) #Switch - GU if Format == 7: blockWidth = blockHeight = 1 WidthInBlocks = (Width + (blockWidth - 1)) // blockWidth HeightInBlocks = (Height + (blockHeight - 1)) // blockHeight maxBlockHeight = 8 if Width < 256 or Height <= 256 else 16 maxBlockHeight = 4 if Width < 128 or Height <= 128 else maxBlockHeight maxBlockHeight = 2 if Width < 64 or Height <= 64 else maxBlockHeight maxBlockHeight = 1 if Width < 32 or Height <= 32 else maxBlockHeight pix = rapi.callExtensionMethod("untile_blocklineargob", bs.readBytes(Length), WidthInBlocks, HeightInBlocks, 4, maxBlockHeight) pix = rapi.imageDecodeRaw(pix, Width, Height, "b8g8r8a8", 2) elif Format == 19: blockWidth = blockHeight = 4 blockSize = 8 WidthInBlocks = (Width + (blockWidth - 1)) // blockWidth HeightInBlocks = (Height + (blockHeight - 1)) // blockHeight maxBlockHeight = 8 if Width < 256 or Height <= 256 else 16 maxBlockHeight = 4 if Width < 128 or Height <= 128 else maxBlockHeight maxBlockHeight = 2 if Width < 64 or Height <= 64 else maxBlockHeight maxBlockHeight = 1 if Width < 32 or Height <= 32 else maxBlockHeight pix = rapi.callExtensionMethod("untile_blocklineargob", bs.readBytes(Length), WidthInBlocks, HeightInBlocks, blockSize, maxBlockHeight) pix = rapi.imageDecodeDXT(pix, Width, Height, noesis.FOURCC_DXT1) elif Format == 23: blockWidth = blockHeight = 4 blockSize = 16 WidthInBlocks = (Width + (blockWidth - 1)) // blockWidth HeightInBlocks = (Height + (blockHeight - 1)) // blockHeight maxBlockHeight = 8 if Width < 256 or Height <= 256 else 16 maxBlockHeight = 4 if Width < 128 or Height <= 128 else maxBlockHeight maxBlockHeight = 2 if Width < 64 or Height <= 64 else maxBlockHeight maxBlockHeight = 1 if Width < 32 or Height <= 32 else maxBlockHeight pix = rapi.callExtensionMethod("untile_blocklineargob", bs.readBytes(Length), WidthInBlocks, HeightInBlocks, blockSize, maxBlockHeight) pix = rapi.imageDecodeDXT(pix, Width, Height, noesis.NOESISTEX_DXT5) elif Format == 25: blockWidth = blockHeight = 4 blockSize = 8 WidthInBlocks = (Width + (blockWidth - 1)) // blockWidth HeightInBlocks = (Height + (blockHeight - 1)) // blockHeight maxBlockHeight = 8 if Width < 256 or Height <= 256 else 16 maxBlockHeight = 4 if Width < 128 or Height <= 128 else maxBlockHeight maxBlockHeight = 2 if Width < 64 or Height <= 64 else maxBlockHeight maxBlockHeight = 1 if Width < 32 or Height <= 32 else maxBlockHeight pix = rapi.callExtensionMethod("untile_blocklineargob", bs.readBytes(Length), WidthInBlocks, HeightInBlocks, blockSize, maxBlockHeight) pix = rapi.imageDecodeDXT(pix, Width, Height, noesis.FOURCC_ATI1) elif Format == 31: blockWidth = blockHeight = 4 blockSize = 16 WidthInBlocks = (Width + (blockWidth - 1)) // blockWidth HeightInBlocks = (Height + (blockHeight - 1)) // blockHeight maxBlockHeight = 8 if Width < 256 or Height <= 256 else 16 maxBlockHeight = 4 if Width < 128 or Height <= 128 else maxBlockHeight maxBlockHeight = 2 if Width < 64 or Height <= 64 else maxBlockHeight maxBlockHeight = 1 if Width < 32 or Height <= 32 else maxBlockHeight pix = rapi.callExtensionMethod("untile_blocklineargob", bs.readBytes(Length), WidthInBlocks, HeightInBlocks, blockSize, maxBlockHeight) pix = rapi.imageDecodeDXT(pix, Width, Height, noesis.FOURCC_ATI2) else: print(Format) texList.append( NoeTexture("MTFTex", Width, Height, pix, noesis.NOESISTEX_RGBA32)) if Version == 165: #3DS v2 | Wii U if bigEndian: #adapted loosely from Zaramot's script gtxTex = ( b'\x47\x66\x78\x32\x00\x00\x00\x20\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x42\x4C\x4B\x7B\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0A\x00\x00\x00\x9C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' ) gtxWidth = struct.pack(">I", Width) gtxheight = struct.pack(">I", Height) gtxTex += gtxWidth gtxTex += gtxheight gtxTex += (b'\x00\x00\x00\x01\x00\x00\x00\x01') if Format == 11: ddsFmt = noesis.FOURCC_BC1 type = struct.pack(">I", 49) gtxFmt = struct.pack(">I", 0xC40003FF) pixelInfo = struct.pack(">II", 4096, 256) ddsSize = (Width * Height * 4) // 8 ddsData = bs.readBytes(ddsSize) elif Format == 12: ddsFmt = noesis.FOURCC_BC2 type = struct.pack(">I", 50) gtxFmt = struct.pack(">I", 0xCC0003FF) pixelInfo = struct.pack(">II", 8192, 256) ddsSize = (Width * Height * 8) // 8 ddsData = bs.readBytes(ddsSize) else: print("Unknown format {}".format(Format)) return 0 gtxTex += type gtxTex += (b'\x00\x00\x00\x00\x00\x00\x00\x01') gtxTex += struct.pack(">I", ddsSize) gtxTex += ( b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x0D\x00\x00' ) gtxTex += pixelInfo gtxTex += ( b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x02\x03\x1F\xF8\x7F\x21' ) gtxTex += gtxFmt gtxTex += ( b'\x06\x88\x84\x00\x00\x00\x00\x00\x80\x00\x00\x10\x42\x4C\x4B\x7B\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0B' ) gtxTex += struct.pack(">I", ddsSize) gtxTex += (b'\x00\x00\x00\x00\x00\x00\x00\x00') gtxTex += ddsData gtxTex += ( b'\x42\x4C\x4B\x7B\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ) ddsName = rapi.getLocalFileName(rapi.getInputName()) dstFilePath = rapi.getDirForFilePath( rapi.getInputName()) + ddsName + ".gtx" newfile = open(dstFilePath, 'wb') newfile.write(gtxTex) newfile.close() subprocess.Popen( [noesis.getScenesPath() + 'TexConv2.bat', dstFilePath]).wait() try: texData = rapi.loadIntoByteArray(dstFilePath + ".dds") texture = rapi.loadTexByHandler(texData, ".dds") except: texture = NoeTexture(str(len(self.texList)), 0, 0, None, noesis.NOESISTEX_RGBA32) texture.name = ddsName texList.append(texture) else: print( "3DS MT Framework Textures not supported! Use Kukkii from the Kuriimu suite." ) return 1 elif magic == 542655828: #MHXR Mobile MT Version = bs.readBits(16) unkn1 = bs.readBits(8) Format = bs.readBits(8) MipMapCount = bs.readBits(6) R1 = bs.readBits(2) unused1 = bs.readBits(24) Width = bs.readBits(13) Height = bs.readBits(13) unkn4 = bs.readBits(2) unkn5 = bs.readBits( 4) #these could be part of the same thing, but I doubt it assert Version == 9 #according to https://github.com/IcySon55/Kuriimu/blob/master/src/image/image_mt/MobileMTTexSupport.cs this whole structure should be mostly inverted, so unless this file is somehow Big Endian, we need version check #noticed that any other version of the format also uses version 9, so there will be problems #also, only works with iOS textures. Android uses BC but has some issues within the data. The two are identical header-wise if Format == 4: #PVRTC4 length = int(Width * Height / 2) pix = rapi.imageDecodePVRTC(bs.readBytes(length), Width, Height, 4) elif Format == 0x10: #ABGR16 length = Width * Height * 2 pix = rapi.imageDecodeRaw(bs.readBytes(length), Width, Height, "a4b4g4r4") elif Format == 0x20: #ABGR32 length = Width * Height * 4 pix = rapi.imageDecodeRaw(bs.readBytes(length), Width, Height, "a8b8g8r8") else: print("Invalid Format {}".format(Format)) return 0 texList.append( NoeTexture("MobileMTFTex", Width, Height, pix, noesis.NOESISTEX_RGBA32)) return 1 else: return 0