chuanhsing

PoE fmt

Aug 5th, 2015
324
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.38 KB | None | 0 0
  1. """
  2. Script: Path of exile full importer and exporter
  3. import requires all art assets to be extracted from the archive
  4.  
  5. How to use:
  6.    needs:  .sm  file (link to materials and model file)
  7.            .smd file (mesh file)
  8.            .ast file (armature) if rig.ast is not present a file dialog will open for you to select an .ast
  9.            textures @ TEXPATH (see below)
  10.            
  11. """
  12.  
  13.  
  14. ################################
  15. ###  Only change this line  ####
  16. ################################
  17. TEXPATH = r"c:\users\Andrew\Desktop\XentaxScript\PoE\Art"
  18.  
  19. ################################
  20. ### Do not change below here ###
  21. ################################
  22. from inc_noesis import *
  23. import noesis
  24. import rapi
  25. import struct
  26.  
  27. def registerNoesisTypes():
  28.     handle = noesis.register("Path of Exile",".sm")
  29.     noesis.setHandlerTypeCheck(handle,noepyCheckType)
  30.     noesis.setHandlerLoadModel(handle,noepyLoadModel)
  31.     handle = noesis.register("Path of Exile",".@smd")
  32.     noesis.setHandlerWriteModel(handle, noepyWriteModel)
  33.     return 1
  34.  
  35. def noepyCheckType(data):
  36.     fName=rapi.getInputName().split('\\')[-1]
  37.     dirPath = rapi.getDirForFilePath(rapi.getInputName())
  38.     bs = open(dirPath + "/" + fName)
  39.     idstring = line = bs.readline()
  40.     idstring =''.join(idstring.split('\x00'))
  41.     bs.close()
  42.     if not "version" in idstring.lower() : return 0
  43.     return 1
  44.  
  45.  
  46. def noepyLoadModel(data,mdlList):
  47.     ctx = rapi.rpgCreateContext()
  48.    
  49.     model       = POE()
  50.     matList     = model.matList
  51.     texList     = model.texList
  52.     bones       = model.bones
  53.     anims       = model.anims
  54.  
  55.     mdl = rapi.rpgConstructModelSlim()
  56.     mdl.setModelMaterials(NoeModelMaterials(texList, matList))
  57.     mdl.setBones(bones)
  58.     mdl.setAnims(anims)
  59.     mdlList.append(mdl)
  60.     return 1
  61. class POE:
  62.     def __init__(self):
  63.         self.filename       = rapi.getInputName().split('\\')[-1]
  64.         self.dirPath        = rapi.getDirForFilePath(rapi.getInputName())
  65.         self.matList        = []
  66.         self.texList        = []
  67.         self.bones          = []
  68.         self.anims          = []
  69.         self.GetMaterials()
  70.         self.LoadModel()
  71.         try:self.LoadArmature()
  72.         except:print('Armature failed to init');pass
  73.     def GetMaterials(self):
  74.         sm          = open(self.dirPath + '/' + self.filename)
  75.         materials   = []
  76.         while 1:
  77.             line    = sm.readline()
  78.             line    = ''.join(line.split('\x00'))
  79.  
  80.             if 'skinnedmeshdata' in line.lower(): self.model = line[17:].split('/')[-1][:-2]
  81.             if 'materials'       in line.lower():
  82.                 numMat  = int(line.lower().split('materials ')[1])
  83.                 for i in range(numMat):
  84.                     sm.readline() # skip the damn \n\n
  85.                     line        = sm.readline().lower()
  86.                     line        = ''.join(line.split('\x00'))
  87.                     material    = line.split('art/')[-1]
  88.                     mat         = material.split('.mat')
  89.                     material    = mat[0] + '.mat'
  90.                     count       = int(mat[1].strip(' ').strip('\n').strip('"'))
  91.                     for x in range(count):materials.append(material)
  92.                 break
  93.         sm.close()
  94.         self.materials = materials
  95.     def CreateMaterial(self,index):
  96.         try:mF                  = open( TEXPATH + '/' +self.materials[index] ,'r')
  97.         except:
  98.             for mat in self.materials:print(mat)
  99.             raise
  100.         diffuse     = None
  101.         normal      = None
  102.         specular    = None
  103.         for i in range(10):
  104.             line    = mF.readline()
  105.             line    = ''.join(line.split('\x00')).lower()
  106.             if 'colourtexture' in line:
  107.                 diffuse     = line[14:-2].split('art/')[-1]
  108.             elif 'normalspeculartexture' in line:
  109.                 normal      = line[14:-2].split('art/')[-1]
  110.                 specular    = normal
  111.             mF.readline()
  112.         material            = NoeMaterial( self.meshNames[index] , '' )
  113.         material.setTexture(diffuse.split('/')[-1])
  114.         try:
  115.             material.setNormalTexture(normal.split('/')[-1])
  116.             material.setSpecularTexture(specular.split('/')[-1])
  117.         except: pass
  118.         for t in [diffuse,normal,specular]:
  119.             try:
  120.                 tex         = open(TEXPATH + '/' +t,'rb').read()
  121.                 tex         = rapi.loadTexByHandler(tex,'.dds')
  122.                 tex.name    = t.split('/')[-1]
  123.                 self.texList.append(tex)
  124.             except:pass
  125.         self.matList.append(material)
  126.        
  127.     def LoadModel(self):
  128.         self.data           = NoeBitStream( open(self.dirPath + self.model,'rb').read() )
  129.         self.data.seek(1,1)
  130.         self.numIdx         = self.data.readUInt()
  131.         self.numVert        = self.data.readUInt()
  132.         prop                = self.data.read('3B')
  133.         totalStringLength   = self.data.readUInt()
  134.         boundingBox         = self.data.read('6f')
  135.         meshNames           = []
  136.         stringLengths       = []
  137.         idxGroups           = []
  138.  
  139.         for i in range(prop[1]):
  140.             stringLengths.append(self.data.readUInt())
  141.             idxGroups.append    (self.data.readUInt())
  142.        
  143.         for i in range(prop[1]):
  144.             meshNames.append    (noeStrFromBytes(self.data.readBytes(stringLengths[i])))
  145.         self.meshNames      = meshNames
  146.  
  147.         self.idxBuffer      = self.data.readBytes(self.numIdx * 6)
  148.         self.vertBuffer     = self.data.readBytes(self.numVert * 64)
  149.  
  150.         for i in range(prop[1]):
  151.             name            = ''.join(meshNames[i].split('\x00'))
  152.             meshNames[i]    = name.split('Shape')[0]
  153.  
  154.         idxG    = []
  155.         idxGroups.append(self.numIdx)
  156.         for i in range(prop[1]):
  157.             idxG.append(idxGroups[i+1] - idxGroups[i])
  158.  
  159.         for i in range(prop[1]):
  160.             rapi.rpgBindPositionBufferOfs   (self.vertBuffer, noesis.RPGEODATA_FLOAT, 64, 0)
  161.             rapi.rpgBindUV1BufferOfs        (self.vertBuffer, noesis.RPGEODATA_FLOAT, 64, 40)
  162.             rapi.rpgBindNormalBufferOfs     (self.vertBuffer, noesis.RPGEODATA_FLOAT, 64, 12)
  163.             #rapi.rpgBindColorBufferOfs      (self.vertBuffer, noesis.RPGEODATA_FLOAT, 64, 24, 4)
  164.             rapi.rpgBindBoneIndexBufferOfs  (self.vertBuffer, noesis.RPGEODATA_UBYTE, 64, 48, 4)
  165.             rapi.rpgBindBoneWeightBufferOfs (self.vertBuffer, noesis.RPGEODATA_FLOAT, 64, 52, 3)
  166.  
  167.             self.CreateMaterial(i)
  168.             rapi.rpgSetMaterial(self.meshNames[i])
  169.  
  170.             min = idxGroups[i] * 6
  171.             max = idxGroups[i+1] * 6
  172.             rapi.rpgCommitTriangles(self.idxBuffer[min:max], noesis.RPGEODATA_USHORT,idxG[i]*3, noesis.RPGEO_TRIANGLE, 1)
  173.     def LoadArmature(self):
  174.         if not rapi.checkFileExists(self.dirPath+'/rig.ast'):
  175.             data = rapi.loadPairedFileOptional('Path of Exile armature','ast')
  176.             if data == None: return
  177.             data = NoeBitStream(data)
  178.         else:
  179.             data = NoeBitStream(open(self.dirPath + '/rig.ast','rb').read())
  180.  
  181.         data.seek(1,1)
  182.         numBones        = data.readUByte()
  183.         data.seek(1,1)
  184.         numAnim         = data.readUShort()
  185.         data.seek(3,1)
  186.  
  187.         bones           = []
  188.         parent          = []
  189.  
  190.         for i in range(numBones):
  191.             parent.append( data.read('2B') )
  192.             bone        = data.read('16f')
  193.             length      = data.readUByte()
  194.             name        = noeStrFromBytes( data.readBytes(length) )
  195.             mat         = NoeMat44()
  196.             mat.__setitem__(0, NoeVec4(bone[0 :4 ]))
  197.             mat.__setitem__(1, NoeVec4(bone[4 :8 ]))
  198.             mat.__setitem__(2, NoeVec4(bone[8 :12]))
  199.             mat.__setitem__(3, NoeVec4(bone[12:  ]))
  200.             mat         = mat.toMat43()
  201.             bones.append(NoeBone(i,name,mat,None,-1))
  202.  
  203.         Parent = { 0:{'parent':-1} }
  204.         for i in range(len(parent)):
  205.             mod=parent[i]
  206.             if mod[0] !=255:
  207.                 Parent[mod[0]] = {'parent':Parent[i]['parent']}
  208.             if mod[1] !=255:
  209.                 Parent[mod[1]] = {'parent':i}
  210.         for i in range(len(bones)):
  211.             bone = bones[i]
  212.             bone.parentIndex = Parent[i]['parent']
  213.         animation={}
  214.         animL=[]
  215.         for i in range(numAnim):
  216.             nBones = data.readUByte()
  217.             data.seek(3,1)
  218.             length = data.readUByte()
  219.             name = noeStrFromBytes(data.readBytes(length))
  220.             animation[i] = {'name':name,'data':[]}
  221.            
  222.             for t in range(nBones):
  223.                 data.seek(1,1)
  224.                 boneID = data.readUShort()
  225.                 dID=data.tell()
  226.                 data.seek(2,1)
  227.                 mod = data.readUShort()
  228.                 mods= data.read('12B')
  229.                 data.seek(12,1)
  230.                 numFrames = data.readUShort()
  231.                 data.seek(12,1)
  232.                 if mod == 3:
  233.                     numFrames=data.readUShort()
  234.                     data.seek(12,1)
  235.                 rot={}
  236.                 pos={}
  237.                 printing=[]
  238.                 for f in range(numFrames+1):
  239.                     try:
  240.                         ID=data.readUShort()
  241.                         rot[ID]=data.read('4f')
  242.                         if ID >=numFrames:break
  243.                     except:
  244.                         print("animation:",i,"\nbone:",t,"total:",nBones,"\nframe:",f,"ID:",ID)
  245.                         raise
  246.                 for f in range(numFrames+1):
  247.                     ID=data.readUShort()
  248.                     pos[ID]=data.read('3f')
  249.                     printing.append(ID)
  250.                     if ID >=numFrames:break
  251.                 animation[i]['data'].append((boneID,(rot,pos),numFrames+1))
  252.                 data.seek(14*mods[8],1)
  253.                 if t == nBones: print(data.tell())
  254.             animL.append(numFrames+1)
  255.         anims=[]
  256.         pLine=''
  257.         for i in range(numAnim):
  258.             anim = animation[i]
  259.             name = anim['name']
  260.             data = anim['data']
  261.             frameMat=[]
  262.             for b in range(len(data)):
  263.                 frameMat.append([])
  264.                 bone = data[b]
  265.                 rot  = bone[1][0]
  266.                 pos  = bone[1][1]
  267.                 for f in range(bone[2]):
  268.                    
  269.                     if f in rot:
  270.                         mat = NoeQuat((rot[f][0],rot[f][1],rot[f][2],rot[f][3]))
  271.                         mat = mat.toMat43()
  272.                     else:
  273.                         mat = frameMat[b][-1]
  274.                        
  275.                    
  276.                     if f in pos:
  277.                         mat.__setitem__(3,NoeVec3((pos[f])))
  278.                     else:
  279.                         mat.__setitem__(3,frameMat[b][-1][3])
  280.                     if b == 0 and f==0:
  281.                         rotate = NoeMat43(((-1,0,0),(0,0,-1),(0,-1,0),(0,0,0)))
  282.                     frameMat[b].append(mat)
  283.             matFrame=[]
  284.             for f in range(animL[i]):
  285.                 mat = NoeMat43()
  286.                 for b in range(len(data)):
  287.                     try:matFrame.append(frameMat[b][f])
  288.                     except:print("%d %d"%(f,b))
  289.             anims.append(NoeAnim(name,bones,animL[i],matFrame,1))
  290.        
  291.         bones = rapi.multiplyBones(bones)
  292.         self.bones = bones
  293.         self.anims = anims
  294. def noepyWriteModel(mdl,bs):
  295.     return 1
Advertisement
Add Comment
Please, Sign In to add comment