home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 6793 / fmt_EnchantedArms_mdl.7z / fmt_EnchantedArms_mdl.py
Encoding:
Python Source  |  2013-11-19  |  14.3 KB  |  400 lines

  1. #Base Model Class
  2.  
  3. from inc_noesis import *
  4.  
  5. def registerNoesisTypes():
  6.     handle = noesis.register("Enchanted Arms MDL", ".mdl")
  7.     noesis.setHandlerTypeCheck(handle, earmsCheckType)
  8.     noesis.setHandlerLoadModel(handle, earmsLoadModel)
  9.     #noesis.logPopup()
  10.  
  11.     handle = noesis.register("Enchanted Arms TBND", ".tbnd")
  12.     noesis.setHandlerTypeCheck(handle, tbndCheckType)
  13.     noesis.setHandlerLoadRGBA(handle, tbndLoadRGBA)
  14.  
  15.     return 1
  16.  
  17.  
  18. def tbndCheckType(data):
  19.     td = NoeBitStream(data)
  20.     Magic = td.readUInt()
  21.     if Magic != 0x33444E42:
  22.         return 0
  23.     return 1
  24.  
  25. def earmsCheckType(data):
  26.     bs = NoeBitStream(data)
  27.     Magic = bs.readUInt()
  28.     if Magic != 0x344C444D:
  29.         return 0
  30.     return 1
  31.  
  32. def tbndLoadRGBA(data, texList):
  33.     td = NoeBitStream(data, NOE_BIGENDIAN)
  34.     td.seek(0x10, NOESEEK_ABS)
  35.     texCount = td.readUInt(); td.seek(0x20, NOESEEK_ABS)
  36.     texOff = []
  37.     for i in range(0, texCount):
  38.         texOff.append(td.read(">" + 4 * "i"))
  39.     for i in range(0, texCount):
  40.         td.seek(texOff[i][2], NOESEEK_ABS)
  41.         tpfinfo = td.read(">" + 6 * "i")
  42.         tpfinfo2 = td.read(">" + 4 * "h")
  43.         td.seek(0x10, NOESEEK_REL)
  44.         texName = td.readBytes(0x50).decode("ASCII").rstrip("\0")
  45.         texData = td.readBytes(tpfinfo[5])
  46.         texFmt = noesis.NOESISTEX_DXT1
  47.         if tpfinfo2[0] == 0:
  48.             texFmt = noesis.NOESISTEX_DXT1
  49.         elif tpfinfo2[0] == 1:
  50.             texFmt = noesis.NOESISTEX_DXT1
  51.         elif tpfinfo2[0] == 768:
  52.             texFmt = noesis.NOESISTEX_DXT3
  53.         if tpfinfo2[0] == 1280:
  54.             texFmt = noesis.NOESISTEX_DXT5
  55.         texList.append(NoeTexture(texName, tpfinfo2[2], tpfinfo2[3], texData, texFmt))
  56.     return 1
  57.  
  58. class EnchArms(object): 
  59.       
  60.     def __init__(self, data):     
  61.         self.inFile   = NoeBitStream(data, NOE_BIGENDIAN)
  62.         rapi.rpgSetOption(noesis.RPGOPT_BIGENDIAN, 1)
  63.         rapi.rpgSetOption(noesis.RPGOPT_TRIWINDBACKWARD, 1)
  64.         rapi.setPreviewOption("setAngOfs", "0 90 90")
  65.         rapi.setPreviewOption("setAnimSpeed", "2.0")
  66.         #all morphs that we provide are relative to the base positions,
  67.         #so we just leave these options on.
  68.         #(otherwise, they affect things only at CommitMorphFrame time,
  69.         #and can be toggled on and off as needed)
  70.         rapi.rpgSetOption(noesis.RPGOPT_MORPH_RELATIVEPOSITIONS, 1)
  71.         rapi.rpgSetOption(noesis.RPGOPT_MORPH_RELATIVENORMALS, 1)
  72.         self.texList  = []
  73.         self.matList  = [] 
  74.         self.boneList = []
  75.         self.boneMap  = []
  76.         self.meshOffsets = []
  77.  
  78.     def alignPosition(self, bs, alignment):
  79.         alignment = alignment - 1
  80.         bs.seek(((bs.tell() + alignment) & ~alignment), NOESEEK_ABS)
  81.  
  82.     def loadHeader(self, bs):
  83.         magic = bs.readBytes(4).decode("ASCII").rstrip("\0")
  84.         mdlVersion,  mdlSubVersion = bs.read(">" + 2 * "H")
  85.         self.dataOffset, self.dataSize, self.count1, self.materialCount, \
  86.         self.boneCount, self.meshCount, self.meshCount2 \
  87.         = bs.read(">" + 7 * "i")
  88.         self.bbMin = NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
  89.         self.bbMax = NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
  90.         self.totalVertCount, self.totalFaceCount = bs.read(">" + 2 * "i")
  91.         bs.seek(0x80, NOESEEK_ABS)
  92.         #print("Data Offset:", self.dataOffset, " Data Size:", self.dataSize, " Count 1:", self.count1, \
  93.         #" Material Count:", self.materialCount, " Bone Count:", self.boneCount, " Mesh Count:", \
  94.         #self.meshCount, " Mesh Count 2:", self.meshCount2)
  95.         #print("Bounding Box Min:", self.bbMin, " Bounding Box Max:", self.bbMax)
  96.         #print("Vertex Count:", self.totalVertCount, " Face Count:", self.totalFaceCount)
  97.  
  98.     def loadSection1(self, bs):
  99.         #print("Section1 Start:", bs.tell())
  100.         bs.seek(0x30 * self.count1, NOESEEK_REL)
  101.  
  102.  
  103.     def loadMaterials(self, bs):
  104.         #print("Material Info Start:", bs.tell())
  105.         for i in range(0, self.materialCount):
  106.             matStart = bs.tell()
  107.             try:
  108.                 materialName = bs.readBytes(0x1F).decode("ASCII").rstrip("\0")
  109.             except:
  110.                 print("WARNING: Non-ASCII string data:")
  111.                 materialName = "material_" + str(i)
  112.             #materialName = bs.readBytes(0x1F).decode("ASCII").rstrip("\0")
  113.             shaderName = bs.readBytes(0x1F).decode("ASCII").rstrip("\0")
  114.             material = NoeMaterial(materialName, "")
  115.             modelID = bs.readUByte()
  116.             shaderCount = bs.readUByte()
  117.             for a in range(0, shaderCount):
  118.                 valueType = bs.readUByte()
  119.                 valueName = bs.readBytes(0x1F).decode("ASCII").rstrip("\0")
  120.                 if valueName in testMaterialLoaderDict:
  121.                     testMaterialLoaderDict[valueName](material, bs)
  122.                 else:
  123.                     print(bs.tell())
  124.                     print("New Material Found:",valueName)
  125.                     bs.seek(0x20, NOESEEK_REL)
  126.             self.matList.append(material)
  127.             bs.seek(0x840 + matStart, NOESEEK_ABS)
  128.  
  129.     def loadBones(self, bs):
  130.         #print("Bone Info Start:", bs.tell())
  131.         for i in range(0, self.boneCount):
  132.             try:
  133.                 boneName = bs.readBytes(0x20).decode("ASCII").rstrip("\0")
  134.             except:
  135.                 print("WARNING: Non-ASCII string data:")
  136.                 boneName = "bone_" + str(i)
  137.             pos = NoeVec3.fromBytes(bs.readBytes(12), NOE_BIGENDIAN)
  138.             boneMtx = NoeAngles.fromBytes(bs.readBytes(12), NOE_BIGENDIAN).toDegrees().toMat43_XYZ()
  139.             boneMtx[3] = pos
  140.             bs.seek(0x24, NOESEEK_REL)
  141.             bInfo = bs.read(">" + 4 * "h")
  142.             bs.seek(0x2C, NOESEEK_REL)
  143.             newBone = NoeBone(i, boneName, boneMtx, None, bInfo[0])
  144.             self.boneList.append(newBone)
  145.         self.boneList = rapi.multiplyBones(self.boneList)
  146.  
  147.  
  148.     def loadModelInfo(self, bs):
  149.         #print("Model Info Start:", bs.tell())
  150.         for i in range(0, self.meshCount):
  151.             morphInfo = []
  152.             bonePallet = []
  153.             #print(bs.tell())
  154.             flags = bs.read(4 * "b")
  155.             faceCount, unk = bs.read(">" + 2 * "h")
  156.             for a in range(0, 28):
  157.                 boneID = bs.readShort()
  158.                 if boneID != -1:
  159.                     bonePallet.append(boneID)
  160.             faceSize, faceStart, vertSize, vertStart = bs.read(">" + 4 * "i")
  161.             if flags[0] == 2:
  162.                 for a in range(0, 16):
  163.                     morphSize, morphOffset = bs.read(">" + 2 * "i")
  164.                     if morphSize != 0:
  165.                         morphInfo.append([morphSize, morphOffset])
  166.             self.meshOffsets.append([faceSize, faceStart, vertSize, vertStart, flags[0], flags[1], faceCount, morphInfo])
  167.             self.boneMap.append(bonePallet)
  168.             #print(flags)
  169.             #print((self.dataOffset + faceStart), (self.dataOffset + vertStart), vertSize)
  170.             #print(faceSize, faceStart, vertSize, vertStart)
  171.             
  172.  
  173.  
  174.     def loadMesh(self, bs):
  175.         bs.seek(self.dataOffset, NOESEEK_ABS)
  176.         #print("Mesh Start:", bs.tell())
  177.         for i in range(0, self.meshCount):
  178.             #print(self.meshOffsets[i][4])
  179.             bs.seek(self.dataOffset + self.meshOffsets[i][1], NOESEEK_ABS)
  180.             faceBuff = bs.readBytes(self.meshOffsets[i][0])
  181.             bs.seek(self.dataOffset + self.meshOffsets[i][3], NOESEEK_ABS)
  182.             vertBuff = bs.readBytes(self.meshOffsets[i][2])
  183.             rapi.rpgSetBoneMap(self.boneMap[i])
  184.             #rapi.rpgSetName(str(i))
  185.             rapi.rpgSetMaterial(self.matList[self.meshOffsets[i][5]].name)
  186.             if self.meshOffsets[i][4] == 0:
  187.                 rapi.rpgSetPosScaleBias(None, None)
  188.                 rapi.rpgBindPositionBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x40, 0)
  189.                 rapi.rpgBindColorBufferOfs(vertBuff, noesis.RPGEODATA_UBYTE, 0x40, 24, 4)
  190.                 rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x40, 28)
  191.                 rapi.rpgBindUV2BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x40, 44)
  192.                 #rapi.rpgBindBoneIndexBufferOfs(vertBuff, noesis.RPGEODATA_UBYTE, 0x40, 20, 4)
  193.                 #rapi.rpgBindBoneWeightBufferOfs(vertBuff, noesis.RPGEODATA_UBYTE, 0x40, 60, 4)
  194.                 rapi.rpgCommitTriangles(faceBuff, noesis.RPGEODATA_SHORT, self.meshOffsets[i][6], noesis.RPGEO_TRIANGLE_STRIP, 1)
  195.             elif self.meshOffsets[i][4] == 1:
  196.                 rapi.rpgSetPosScaleBias(None, None)
  197.                 rapi.rpgBindPositionBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x54, 0)
  198.                 #rapi.rpgBindColorBufferOfs(vertBuff, noesis.RPGEODATA_UBYTE, 0x54, 24, 4)
  199.                 rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x54, 28)
  200.                 rapi.rpgBindUV2BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x54, 44)
  201.                 rapi.rpgBindBoneIndexBufferOfs(vertBuff, noesis.RPGEODATA_SHORT, 0x54, 60, 4)
  202.                 rapi.rpgBindBoneWeightBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x54, 68, 4)
  203.                 rapi.rpgCommitTriangles(faceBuff, noesis.RPGEODATA_SHORT, self.meshOffsets[i][6], noesis.RPGEO_TRIANGLE_STRIP, 1)
  204.             elif self.meshOffsets[i][4] == 2:
  205.                 rapi.rpgSetPosScaleBias((328.0,328.0,328.0),(0,0,0))
  206.                 #print(self.meshOffsets[i][7][0])
  207.                 bs.seek(self.dataOffset + self.meshOffsets[i][7][0][1], NOESEEK_ABS)
  208.                 posBuff = bs.readBytes(self.meshOffsets[i][7][0][0])
  209.                 rapi.rpgBindPositionBufferOfs(posBuff, noesis.RPGEODATA_SHORT, 16, 0)
  210.                 #rapi.rpgBindColorBufferOfs(vertBuff, noesis.RPGEODATA_UBYTE, 0x3C, 0, 4)
  211.                 rapi.rpgBindUV1BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x3C, 4)
  212.                 rapi.rpgBindUV2BufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x3C, 20)
  213.                 rapi.rpgBindBoneIndexBufferOfs(vertBuff, noesis.RPGEODATA_SHORT, 0x3C, 36, 4)
  214.                 rapi.rpgBindBoneWeightBufferOfs(vertBuff, noesis.RPGEODATA_FLOAT, 0x3C, 44, 4)
  215.                 for a in range(1, len(self.meshOffsets[i][7])):
  216.                     bs.seek(self.dataOffset + self.meshOffsets[i][7][a][1], NOESEEK_ABS)
  217.                     morphBuff = bs.readBytes(self.meshOffsets[i][7][a][0])
  218.                     rapi.rpgFeedMorphTargetPositionsOfs(morphBuff, noesis.RPGEODATA_SHORT, 16, 0)
  219.                     rapi.rpgCommitMorphFrame(self.meshOffsets[i][7][a][0] // 16)
  220.                 rapi.rpgCommitMorphFrameSet()
  221.                 rapi.rpgCommitTriangles(faceBuff, noesis.RPGEODATA_SHORT, self.meshOffsets[i][6], noesis.RPGEO_TRIANGLE_STRIP, 1)
  222.  
  223.             rapi.rpgClearBufferBinds()
  224.     def load_tex(self): 
  225.         folderName = rapi.getDirForFilePath(rapi.getInputName())
  226.         baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName()))
  227.         texFile = folderName + baseName + ".tbnd"
  228.         if (rapi.checkFileExists(texFile)):
  229.             #print(texFile)
  230.             texData = rapi.loadIntoByteArray(texFile)
  231.             tbndLoadRGBA(texData, self.texList)
  232.  
  233.  
  234.     def parse_file(self): 
  235.         bs = self.inFile
  236.         self.loadHeader(bs)
  237.         self.load_tex()
  238.         self.loadSection1(bs)
  239.         self.loadMaterials(bs)
  240.         self.loadBones(bs)
  241.         self.loadModelInfo(bs)
  242.         self.loadMesh(bs)
  243.         return 1
  244.  
  245.  
  246. #Noesis blends:
  247. #0 - "None"
  248. #1 - "GL_ZERO"
  249. #2 - "GL_ONE"
  250. #3 - "GL_SRC_COLOR"
  251. #4 - "GL_ONE_MINUS_SRC_COLOR"
  252. #5 - "GL_SRC_ALPHA"
  253. #6 - "GL_ONE_MINUS_SRC_ALPHA"
  254. #7 - "GL_DST_ALPHA"
  255. #8 - "GL_ONE_MINUS_DST_ALPHA"
  256. #9 - "GL_DST_COLOR"
  257. #10 - "GL_ONE_MINUS_DST_COLOR"
  258. #11 - "GL_SRC_ALPHA_SATURATE"
  259.  
  260. class Material:
  261.     def _init_(self):
  262.         texColorExpr = "abs(mtl_diffuse_a, 0, 12)"
  263.         self.setExpr_texidx(texColorExpr)
  264.         pass
  265.         #self.setBlendMode("None", "None")
  266.  
  267.     def load_g_MatAlphaBlend(self, bs):
  268.         AlphaBlend = bs.readUInt()
  269.         bs.seek(0x1C, NOESEEK_REL)
  270.  
  271.     def load_g_MatAlphaRef(self, bs):
  272.         AlphaRef = bs.readUInt()
  273.         self.setDefaultBlend(0)
  274.         #if AlphaRef:
  275.         #    self.setBlendMode("GL_ONE_MINUS_SRC_COLOR", "None")
  276.         bs.seek(0x1C, NOESEEK_REL)
  277.  
  278.     def load_g_MatSelfIllumeCol(self, bs):
  279.         #self.setAmbientColor(NoeVec4.fromBytes(bs.readBytes(16), NOE_BIGENDIAN))
  280.         bs.seek(0x20, NOESEEK_REL)
  281.  
  282.     def load_g_MatSelfIllumeCoef(self, bs):
  283.         bs.seek(0x20, NOESEEK_REL)
  284.  
  285.     def load_g_MatDiffCol(self, bs):
  286.         #self.setDiffuseColor(NoeVec4.fromBytes(bs.readBytes(16), NOE_BIGENDIAN))
  287.         bs.seek(0x20, NOESEEK_REL)
  288.  
  289.     def load_g_MatDiffCoef(self, bs):
  290.         bs.seek(0x20, NOESEEK_REL)
  291.  
  292.     def load_g_MatDiffRough(self, bs):
  293.         bs.seek(0x20, NOESEEK_REL)
  294.  
  295.     def load_g_MatSpecCol(self, bs):
  296.         #self.setSpecularColor(NoeVec4.fromBytes(bs.readBytes(16), NOE_BIGENDIAN))
  297.         bs.seek(0x20, NOESEEK_REL)
  298.  
  299.     def load_g_MatSpecCoef(self, bs):
  300.         bs.seek(0x20, NOESEEK_REL)
  301.  
  302.     def load_g_MatSpecPower(self, bs):
  303.         bs.seek(0x20, NOESEEK_REL)
  304.  
  305.     def load_g_MatEnvmapFresnelScale(self, bs):
  306.         bs.seek(0x20, NOESEEK_REL)
  307.  
  308.     def load_g_MatEnvmapFresnelBias(self, bs):
  309.         bs.seek(0x20, NOESEEK_REL)
  310.  
  311.     def load_g_DiffuseTexture(self, bs):
  312.         self.setTexture(bs.readBytes(0x20).decode("ASCII").rstrip("\0"))
  313.  
  314.  
  315.     def load_g_DiffuseTexture2(self, bs):
  316.         bs.seek(0x20, NOESEEK_REL)
  317.         
  318.  
  319.     def load_g_AlphamapTexture(self, bs):
  320.         bs.seek(0x20, NOESEEK_REL)
  321.         #self.setOpacityTexture(bs.readBytes(0x20).decode("ASCII").rstrip("\0"))
  322.  
  323.     def load_g_LightmapTexture(self, bs):
  324.         bs.seek(0x20, NOESEEK_REL)
  325.         #self.setOpacityTexture(bs.readBytes(0x20).decode("ASCII").rstrip("\0"))
  326.  
  327.     def load_g_CubeEnvmapTexture(self, bs):
  328.         bs.seek(0x20, NOESEEK_REL)
  329.  
  330.     def load_g_EnvmapMaskTexture(self, bs):
  331.         bs.seek(0x20, NOESEEK_REL)
  332.         #self.setEnvTexture(bs.readBytes(0x20).decode("ASCII").rstrip("\0"))
  333.  
  334.     def load_g_BumpmapTexture(self, bs):
  335.         #bs.seek(0x20, NOESEEK_REL)
  336.         self.setBumpTexture(bs.readBytes(0x20).decode("ASCII").rstrip("\0"))
  337.  
  338.     def load_g_MatParallaxOffset(self, bs):
  339.         bs.seek(0x20, NOESEEK_REL)
  340.  
  341.     def load_g_EnchantMapTexture(self, bs):
  342.         bs.seek(0x20, NOESEEK_REL)
  343.         #self.setBumpTexture(bs.readBytes(0x20).decode("ASCII").rstrip("\0"))
  344.  
  345.     def load_g_MatEnchantMapParamID(self, bs):
  346.         MatEnchantMapParamID = bs.readUInt()
  347.         bs.seek(0x1C, NOESEEK_REL)
  348.  
  349.     def load_g_MatDiffLerpExp(self, bs):
  350.         bs.seek(0x20, NOESEEK_REL)
  351.  
  352. testmaterialTypeDict = {
  353.  
  354. }
  355.  
  356.  
  357.  
  358. testMaterialLoaderDict = {
  359.     "g_MatAlphaBlend"        : Material.load_g_MatAlphaBlend,
  360.     "g_MatAlphaRef"            : Material.load_g_MatAlphaRef,
  361.     "g_MatSelfIllumeCol"        : Material.load_g_MatSelfIllumeCol,
  362.     "g_MatSelfIllumeCoef"        : Material.load_g_MatSelfIllumeCoef,
  363.     "g_MatDiffCol"            : Material.load_g_MatDiffCol,
  364.     "g_MatDiffCoef"            : Material.load_g_MatDiffCoef,
  365.     "g_MatDiffRough"        : Material.load_g_MatDiffRough,
  366.     "g_MatSpecCol"            : Material.load_g_MatSpecCol,
  367.     "g_MatSpecCoef"            : Material.load_g_MatSpecCoef,
  368.     "g_MatSpecPower"        : Material.load_g_MatSpecPower,
  369.     "g_MatEnvmapFresnelScale"    : Material.load_g_MatEnvmapFresnelScale,
  370.     "g_MatEnvmapFresnelBias"    : Material.load_g_MatEnvmapFresnelBias,
  371.     "g_DiffuseTexture"        : Material.load_g_DiffuseTexture,
  372.     "g_DiffuseTexture2"        : Material.load_g_DiffuseTexture2,
  373.     "g_AlphamapTexture"        : Material.load_g_AlphamapTexture,
  374.     "g_LightmapTexture"        : Material.load_g_LightmapTexture,
  375.     "g_CubeEnvmapTexture"        : Material.load_g_CubeEnvmapTexture,
  376.     "g_EnvmapMaskTexture"        : Material.load_g_EnvmapMaskTexture,
  377.     "g_BumpmapTexture"        : Material.load_g_BumpmapTexture,
  378.     "g_MatParallaxOffset"        : Material.load_g_MatParallaxOffset,
  379.     "g_EnchantMapTexture"        : Material.load_g_EnchantMapTexture,
  380.     "g_MatEnchantMapParamID"    : Material.load_g_MatEnchantMapParamID,
  381.     "g_MatDiffLerpExp"        : Material.load_g_MatDiffLerpExp
  382.  
  383. }
  384.  
  385.  
  386.  
  387. def earmsLoadModel(data, mdlList):
  388.     ctx = rapi.rpgCreateContext()
  389.     parser = EnchArms(data)
  390.     parser.parse_file()
  391.     #rapi.rpgSmoothNormals()
  392.     #rapi.rpgSmoothTangents()
  393.     #rapi.rpgUnifyBinormals(1)
  394.     try:
  395.         mdl = rapi.rpgConstructModel()
  396.     except:
  397.         mdl = NoeModel()
  398.     mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList))
  399.     mdlList.append(mdl); mdl.setBones(parser.boneList)    
  400.     return 1