Advertisement
Guest User

Untitled

a guest
Jul 26th, 2015
250
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.92 KB | None | 0 0
  1. #!/usr/bin/python
  2. ## sand2710 - 2015
  3.  
  4. import time
  5.  
  6. import sys
  7. import struct
  8. import os
  9. #import binascii
  10. import random
  11.  
  12. # blender only
  13. import bpy
  14.  
  15. # def enum(**enums):
  16. # return type('Enum', (), enums)
  17.  
  18. # meshType = enum(RIGID=0, SKINNED=1, COMPOSITE=2, TREE=4)
  19.  
  20. # so far all objects are 3 on pc
  21. # primitiveType = enum(TRIANGLELIST=3)
  22.  
  23. def H2F(H):
  24. F = int((H & 0x8000) << 16) | int(((H & 0x7fff) << 13) + 0x38000000)
  25. return struct.unpack("f", struct.pack("I", F))[0]
  26.  
  27. def U82F(B):
  28. return 1.0 / 255 * B
  29.  
  30. # # too slow
  31. # def H2F(float16):
  32. # s = int((float16 >> 15) & 0x00000001) # sign
  33. # e = int((float16 >> 10) & 0x0000001f) # exponent
  34. # f = int(float16 & 0x000003ff) # fraction
  35.  
  36. # if e == 0:
  37. # if f == 0:
  38. # return int(s << 31)
  39. # else:
  40. # while not (f & 0x00000400):
  41. # f = f << 1
  42. # e -= 1
  43. # e += 1
  44. # f &= ~0x00000400
  45. # #print(s,e,f)
  46. # elif e == 31:
  47. # if f == 0:
  48. # return int((s << 31) | 0x7f800000)
  49. # else:
  50. # return int((s << 31) | 0x7f800000 | (f << 13))
  51.  
  52. # e = e + (127 -15)
  53. # f = f << 13
  54. # return int((s << 31) | (e << 23) | f)
  55.  
  56. class Subset:
  57.  
  58. def __init__(self, fh, offset):
  59. self.useFloat = False
  60. self.uvOffset = 0
  61. self.boneWeightsOffset = 0
  62.  
  63. self.size = 0
  64. self.offset = -1
  65. self.name = ""
  66. self.primitiveCount = -1
  67. self.indexOffset = -1
  68. self.vertexOffset = -1
  69. self.vertexCount = -1
  70. self.vertexStride = -1
  71. self.primitiveType = -1
  72. self.bonesPerVertex = -1
  73. self.boneCount = -1
  74. # u0 streaming enabled?
  75. self.u0 = -1
  76. self.bones = []
  77.  
  78. self.fh = fh
  79.  
  80. self.offset = offset
  81. print(" file offset: " + str(self.offset))
  82. byte = fh.read(1).decode('ascii')
  83. self.size += 1
  84. while ord(byte) != 0:
  85. self.name += str(byte)
  86. byte = fh.read(1).decode('ascii')
  87. self.size += 1
  88. print(" name: " + self.name)
  89. header = fh.read(22)
  90. self.size += 22
  91. self.primitiveCount, self.vertexCount, self.indexOffset, \
  92. self.vertexOffset, self.vertexStride, self.primitiveType, \
  93. self.bonesPerVertex, self.boneCount, self.u0 \
  94. = struct.unpack("<I I I I B B B B H", header)
  95. print(" primitive count: "+str(self.primitiveCount))
  96. print(" index offset: "+str(self.indexOffset))
  97. print(" vertex offset: "+str(self.vertexOffset))
  98. print(" vertex count: "+str(self.vertexCount))
  99. print(" vertex stride: "+str(self.vertexStride))
  100. print(" primitive type: "+str(self.primitiveType))
  101. print(" bones per vertex: "+str(self.bonesPerVertex))
  102. # bone count and bone count 2 have always same value
  103. # the first is a byte, probable the subset header end here
  104. # bone count 2 is a short
  105. print(" bones count: "+str(self.boneCount))
  106. print(" bones count 2?: "+str(self.u0))
  107. for i in range(0, self.boneCount):
  108. boneId = struct.unpack("<H", fh.read(2))
  109. self.size += 2
  110. self.bones.append(boneId[0])
  111. print(" bones: "+str(self.bones))
  112.  
  113. def getV3(self,offset):
  114. ve = []
  115. if self.vertexStride < offset:
  116. return ve
  117. self.fh.seek(self.vxOffset, 0)
  118. for i in range(0, self.vertexCount):
  119. if self.useFloat:
  120. ix, iy, iz = struct.unpack_from("<f f f", self.fh.read(self.vertexStride), offset)
  121. ve.append(((ix), -(iz), (iy)))
  122. else:
  123. ix, iy, iz = struct.unpack_from("<H H H", self.fh.read(self.vertexStride), offset)
  124. # ve.append((H2F(ix), H2F(iy), H2F(iz)))
  125. # x, -z, y (zy swap and negative z are adjustment for blender)
  126. ve.append((H2F(ix), -H2F(iz), H2F(iy)))
  127. return ve
  128.  
  129. # def getWeightsOLD(self, offset):
  130. # # { boneId0: { weight0: [ vertexId0, ... vxN ], ... wN }, ... bN }
  131. # w = {}
  132.  
  133. # self.fh.seek(self.vxOffset, 0)
  134. # for vxId in range(0, self.vertexCount):
  135. # vxdata = self.fh.read(self.vertexStride)
  136. # for bone_i in range(0, self.boneCount):
  137. # boneId = self.bones[bone_i]
  138. # weight = struct.unpack_from("B", vxdata, offset + bone_i)[0]
  139. # if boneId in w:
  140. # if weight in w[boneId]:
  141. # w[boneId][weight].append(vxId) # bone and weight exist, append new vertex
  142. # else:
  143. # if type(w[boneId]) is dict:
  144. # w[boneId][weight] = [vxId] # there's already some weight create a new vx list
  145. # else:
  146. # w[boneId] = {weight:[vxId]} # there were no weights for this boneid, add one
  147. # else:
  148. # w[boneId] = {weight:[vxId]} # there's was not boneId, create it
  149. # return w
  150.  
  151. def saveWeight(self, w, vxId, boneId, weight):
  152. if boneId in w:
  153. if weight in w[boneId]:
  154. w[boneId][weight].append(vxId) # bone and weight exist, append new vertex
  155. else:
  156. if type(w[boneId]) is dict:
  157. w[boneId][weight] = [vxId] # there's already some weight create a new vx list
  158. else:
  159. w[boneId] = {weight:[vxId]} # there were no weights for this boneid, add one
  160. else:
  161. w[boneId] = {weight:[vxId]} # there's was not boneId, create it
  162.  
  163. def getWeights(self, iOffset, wOffset):
  164. # { boneId0-N(grpId): { weight0-255): [ vertexId0-N, ... vxIdN ], ... wN }, ... bIdN }
  165. w = {}
  166. self.fh.seek(self.vxOffset, 0)
  167. for vxId in range(0, self.vertexCount):
  168. vxdata = self.fh.read(self.vertexStride)
  169. for i in range(0, self.bonesPerVertex):
  170. bi = struct.unpack_from("b", vxdata, iOffset + i)[0]
  171. bw = struct.unpack_from("B", vxdata, wOffset + i)[0]
  172. self.saveWeight(w, vxId, bi, bw)
  173. return w
  174.  
  175. def getColors(self, offset):
  176. c = []
  177. self.fh.seek(self.vxOffset, 0)
  178. for vxId in range(0, self.vertexCount):
  179. vxdata = self.fh.read(self.vertexStride)
  180. R, G, B, A = struct.unpack_from("<B B B B", vxdata, offset)
  181. c.append((U82F(R), U82F(G), U82F(B)))
  182. return c
  183.  
  184. def getV2(self, offset):
  185. ve = []
  186. if self.vertexStride < offset:
  187. return ve
  188. self.fh.seek(self.vxOffset, 0)
  189. for i in range(0, self.vertexCount):
  190. iu, iv = struct.unpack_from("<H H", self.fh.read(self.vertexStride), offset)
  191. # v = 1.0 - value (v values negative relative to 1.0)
  192. ve.append((H2F(iu), 1.0 - H2F(iv)))
  193. return ve
  194.  
  195. def getIndices(self):
  196. fa = []
  197. self.fh.seek(self.idxOffset, 0)
  198. for i in range(0, self.primitiveCount):
  199. i1, i2, i3 = struct.unpack("<H H H", self.fh.read(6))
  200. fa.append((i1, i2, i3))
  201. return fa
  202.  
  203. class Meshdata:
  204.  
  205. def getUnknownChunk(self):
  206. self.unknownChunk = self.fh.read(28)
  207. self.size += 28
  208.  
  209. def getSubsets(self):
  210. for i in range(0, self.subsetCount):
  211. print("subset[{0:02d}]:".format(i))
  212. subset = Subset(self.fh, self.fh.tell())
  213. self.subset.append(subset)
  214. self.size += subset.size
  215.  
  216. def getSubsetExtraBytes(self):
  217. for i in range(0, self.subsetCount):
  218. extrabyte = struct.unpack("<B", self.fh.read(1))[0]
  219. self.size += 1
  220. print("subset[{0:02d}].extraByte: {1}".format(i, int(extrabyte)))
  221. self.subsetExtraByte.append(extrabyte)
  222.  
  223. def getHeader(self):
  224. if self.fh != None:
  225. self.fh.seek(0, 0)
  226. header = self.fh.read(7)
  227. self.size += 7
  228. self.meshType, self.u0, self.subsetCount \
  229. = struct.unpack("<I H B", header)
  230. print("mesh type: "+str(self.meshType))
  231. print("subset count: "+str(self.subsetCount))
  232.  
  233. def getVerticesSize(self):
  234. maxv = 0
  235. for i in range(0, self.subsetCount):
  236. subset = self.subset[i]
  237. if subset.vertexOffset + subset.vertexCount * subset.vertexStride > maxv:
  238. maxv = subset.vertexOffset + subset.vertexCount * subset.vertexStride
  239. return maxv
  240.  
  241. def getIndicesSize(self):
  242. maxi = 0
  243. for i in range(0, self.subsetCount):
  244. subset = self.subset[i]
  245. # 3 is the number of vertices per primitive (triangles)
  246. # 2 is bytes for sizeof(uint16_t)
  247. if (subset.indexOffset + subset.primitiveCount * 3) * 2 > maxi:
  248. maxi = (subset.indexOffset + subset.primitiveCount * 3) * 2
  249. return maxi
  250.  
  251. def __exit__(self, type, value, traceback):
  252. if self.fh != None:
  253. self.fh.close()
  254.  
  255. def adjustVxOffs(self):
  256. for i in range(0, self.subsetCount):
  257. subset = self.subset[i]
  258. subset.vxOffset = self.dataOffset + subset.vertexOffset
  259.  
  260. def adjustIdxOffs(self):
  261. verticesSize = self.getVerticesSize()
  262. for i in range(0, self.subsetCount):
  263. subset = self.subset[i]
  264. # * 2 bytes (sizeof(uint16_t))
  265. subset.idxOffset = self.dataOffset + verticesSize + (subset.indexOffset * 2)
  266.  
  267. def __init__(self, path):
  268. self.time_start = time.time()
  269.  
  270. self.size = 0
  271. self.meshType = -1
  272. self.u0 = -1
  273. self.subsetCount = -1
  274. self.subset = []
  275. self.subsetExtraByte = []
  276. self.unknownChunk = ""
  277.  
  278. self.path = path
  279. self.fh = open(path, "rb")
  280.  
  281. self.getHeader()
  282. self.getSubsets()
  283.  
  284. # TODO:
  285. # some file doesn't have extra bytes
  286. # but didn't found a way to know yet
  287. # just a workaround, the calculated size
  288. # of vertices and indices is right
  289. # set the offset relative to the end of the file
  290. # vxstart = eof-sizeof(vx+idx)
  291. self.getSubsetExtraBytes()
  292.  
  293. self.getUnknownChunk()
  294. self.dataOffset = self.fh.tell()
  295. self.size += self.getVerticesSize()
  296. self.size += self.getIndicesSize()
  297. print("data offset: "+str(self.dataOffset))
  298. self.adjustVxOffs()
  299. self.adjustIdxOffs()
  300. for i in range(0, self.subsetCount):
  301. subset = self.subset[i]
  302. print("subset[{0:02d}].vxOffset: 0x{1:08x}".format(i, subset.vxOffset))
  303. for i in range(0, self.subsetCount):
  304. subset = self.subset[i]
  305. print("subset[{0:02d}].idxOffset: 0x{1:08x}".format(i, subset.idxOffset))
  306.  
  307. def blenderCreate(self, useFloat, uvOffset, boneWeightsOffset):
  308.  
  309. for i in range(0,self. subsetCount):
  310. subset = self.subset[i]
  311. subset.useFloat = useFloat
  312. if "ZOnly" in subset.name:
  313. continue
  314. prefix = ""
  315. coords = subset.getV3(0)
  316. faces = subset.getIndices()
  317. me = bpy.data.meshes.new(prefix+subset.name+"_Mesh")
  318.  
  319. ob = bpy.data.objects.new(prefix+str(i).zfill(2)+'_'+subset.name, me)
  320. ob.location = (0, 0, 0)
  321.  
  322. bpy.context.scene.objects.link(ob)
  323. me.from_pydata(coords, [], faces)
  324. me.update(calc_edges=True)
  325.  
  326. # vertex colors
  327.  
  328. # for xoffset in range(40, 48-4):
  329. # rgb = subset.getColors(xoffset)
  330. # rgbvxmap = ob.data.vertex_colors.new("Colormap{0}".format(xoffset))
  331. # j = 0
  332. # for poly in me.polygons:
  333. # k = 0
  334. # for idx in poly.loop_indices:
  335. # rgbvxmap.data[idx].color = rgb[faces[j][k]]
  336. # k += 1
  337. # j += 1
  338.  
  339. # f1=open('/tmp/testfile', 'w+')
  340. # print("weigths:", file=f1)
  341. # print(weights, file=f1)
  342. # f1.close()
  343.  
  344. # vertex bones weights
  345.  
  346. if boneWeightsOffset > 0:
  347. weights = subset.getWeights(8, boneWeightsOffset) # 0x12
  348. for grpId, wv in weights.items():
  349. grpName = "Bone_"+str(boneWeightsOffset)+"_"+str(grpId).zfill(3)
  350. if not grpName in ob.vertex_groups:
  351. ob.vertex_groups.new(grpName)
  352. for w, vx in wv.items():
  353. ob.vertex_groups[grpName].add(vx, U82F(w), 'REPLACE')
  354.  
  355. mat = bpy.data.materials.new(subset.name)
  356. mat.diffuse_color = (random.uniform(0.0, 1.0), \
  357. random.uniform(0.0, 1.0), \
  358. random.uniform(0.0, 1.0))
  359. me.materials.append(mat)
  360.  
  361. for f in me.polygons:
  362. f.material_index = 0
  363. f.use_smooth = 1
  364.  
  365. if uvOffset > 0:
  366. vert_uvs = subset.getV2(uvOffset) # 0x28
  367. if len(vert_uvs) > 0:
  368. me.uv_textures.new("UV"+str(uvOffset))
  369. uvlist = [uv for pair in [vert_uvs[l.vertex_index] for l in me.loops] for uv in pair]
  370. me.uv_layers[-1].data.foreach_set("uv", uvlist)
  371.  
  372. # vert_uvs = subset.getV2(0x30)
  373. # if len(vert_uvs) > 0:
  374. # me.uv_textures.new("UV1")
  375. # uvlist = [uv for pair in [vert_uvs[l.vertex_index] for l in me.loops] for uv in pair]
  376. # me.uv_layers[-1].data.foreach_set("uv", uvlist)
  377.  
  378. print("useFloat: {0}".format(useFloat))
  379. print("Finished in: {:.4f} sec".format(time.time() - self.time_start))
  380.  
  381.  
  382. def process_meshdata(path):
  383. print("meshdata file: " + path)
  384. si = os.stat(path)
  385. print("file size: "+str(si.st_size))
  386. meshdata = Meshdata(path)
  387. print("mesh calculated size: "+str(meshdata.size))
  388. # for i in range(6,48):
  389. meshdata.blenderCreate()
  390.  
  391. def main(argv):
  392. for arg in argv:
  393. process_meshdata(arg)
  394.  
  395. if __name__ == "__main__":
  396. random.seed()
  397. # fileSel = FileSelector()
  398. # fileSel.invoke(bpy.context, None)
  399.  
  400. # main(sys.argv[1:])
  401. # main(["fbrb/Objects/Vehicles/Land/T90/T90_Mesh_lod0_data.meshdata"])
  402. # main(["fbrb/Objects/Vehicles/Sea/Pbl/Pbl_Mesh_lod0_data.meshdata"])
  403. # main(["fbrb/Characters/Us/US_Models/US_01_Body_Mesh_lod0_data.meshdata"])
  404. # main(["fbrb/Characters/Animals/Parrot/Parrot_01_Mesh_lod0_data.meshdata"])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement