732 lines
17 KiB
Python
732 lines
17 KiB
Python
"""
|
|
|
|
MIT License
|
|
|
|
Copyright (c) 2020 Benjamin Collins (kion @ dashgl.com)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import struct
|
|
|
|
from PowerVR import PowerVR
|
|
from NinjaTexture import NinjaTexture
|
|
from NinjaMaterial import NinjaMaterial
|
|
from NinjaVertex import NinjaVertex
|
|
from NinjaFace import NinjaFace
|
|
from NinjaBone import NinjaBone
|
|
from NinjaMotion import NinjaMotion
|
|
|
|
class NinjaModel:
|
|
|
|
def __init__(self, model_name, tex_name = ''):
|
|
|
|
self.debug = False
|
|
self.hasMesh = []
|
|
|
|
# File Information
|
|
self.model_name = model_name
|
|
self.model_path = 'input/' + model_name
|
|
self.file = open(self.model_path, 'rb')
|
|
self.length = os.path.getsize(self.model_path)
|
|
|
|
self.tex_name = tex_name
|
|
self.tex_path = 'input/' + tex_name
|
|
|
|
# Textures
|
|
self.mat_list = []
|
|
self.tex_list = []
|
|
self.anim_list = []
|
|
|
|
# Bone List
|
|
self.bones = []
|
|
|
|
#Vertex List
|
|
self.index_lookup = []
|
|
self.vertex_list = []
|
|
self.face_list = []
|
|
self.strip_count = 0;
|
|
|
|
return None
|
|
|
|
def parse(self):
|
|
self.parseTexture()
|
|
self.parseModel()
|
|
return None
|
|
|
|
def parseTexture(self):
|
|
pvm = PowerVR(self.tex_name)
|
|
self.tex_list = pvm.parse()
|
|
return None
|
|
|
|
def parseModel(self):
|
|
while self.file.tell() < self.length:
|
|
|
|
bytes = self.file.read(4)
|
|
|
|
if(bytes == b'NJTL') :
|
|
bytes = self.file.read(4)
|
|
length = struct.unpack('I', bytes)[0]
|
|
pos = self.file.tell() + length
|
|
self.readNjtl()
|
|
self.file.seek(pos, 0)
|
|
elif (bytes == b'NJCM') :
|
|
bytes = self.file.read(4)
|
|
length = struct.unpack('I', bytes)[0]
|
|
pos = self.file.tell() + length
|
|
self.pof = self.file.tell()
|
|
self.readNjcm(None)
|
|
self.file.seek(pos, 0)
|
|
elif (bytes == b'NMDM') :
|
|
bytes = self.file.read(4)
|
|
length = struct.unpack('I', bytes)[0]
|
|
pos = self.file.tell() + length
|
|
self.pof = self.file.tell()
|
|
self.readNmdm()
|
|
self.file.seek(pos, 0)
|
|
|
|
print(self.hasMesh)
|
|
self.file.close()
|
|
return None
|
|
|
|
def readNjtl(self):
|
|
pof = self.file.tell()
|
|
bytes = self.file.read(8)
|
|
n = struct.unpack('II', bytes)
|
|
str_ofs = []
|
|
|
|
self.file.seek(n[0] + pof, 0)
|
|
for i in range(0, n[1]):
|
|
bytes = self.file.read(12)
|
|
m = struct.unpack('III', bytes)
|
|
str_ofs.append(m[0] + pof)
|
|
|
|
for ofs in str_ofs:
|
|
name = ''
|
|
self.file.seek(ofs, 0)
|
|
while 1:
|
|
ch = self.file.read(1)
|
|
if(ch == b'\0'):
|
|
break
|
|
name += ch.decode()
|
|
return None
|
|
|
|
def readNjcm(self, parentBone):
|
|
|
|
bytes = self.file.read(52)
|
|
b = struct.unpack('IIfffiiifffII', bytes)
|
|
|
|
flags = b[0]
|
|
model_ofs = b[1]
|
|
|
|
c = 2 * 3.141592 / 0xFFFF;
|
|
pos = ( b[2], b[3], b[4] )
|
|
rot = ( b[5] * c, b[6] * c, b[7] *c)
|
|
scl = ( b[8], b[9], b[10] )
|
|
|
|
child_ofs = b[11]
|
|
sibling_ofs = b[12]
|
|
|
|
self.bone = NinjaBone()
|
|
num = len(self.bones)
|
|
self.bone.setName(num)
|
|
self.bones.append(self.bone)
|
|
|
|
if self.debug:
|
|
print("Reading bone: %s" % self.bone.name)
|
|
|
|
if ( (flags & 0x04) == 0):
|
|
self.bone.setScale(scl)
|
|
if self.debug:
|
|
print("Setting Scale: %s", scl)
|
|
|
|
if ( (flags & 0x02) == 0):
|
|
zxy_set = flags & 0x20
|
|
self.bone.setRotation(rot)
|
|
if self.debug:
|
|
print("Setting Rotation: ", rot)
|
|
|
|
if ( (flags & 0x01) == 0):
|
|
self.bone.setPosition(pos)
|
|
if self.debug:
|
|
print("Setting Position: ", pos)
|
|
|
|
if parentBone:
|
|
parentBone.add(self.bone)
|
|
|
|
if model_ofs:
|
|
self.hasMesh.append(self.bone.index)
|
|
if self.debug:
|
|
print("Reading Mesh @ 0x%08x" % self.file.tell())
|
|
self.file.seek(model_ofs + self.pof, 0)
|
|
self.readModel()
|
|
|
|
if child_ofs:
|
|
self.file.seek(child_ofs + self.pof, 0)
|
|
self.readNjcm(self.bone)
|
|
|
|
if sibling_ofs:
|
|
self.file.seek(sibling_ofs + self.pof, 0)
|
|
self.readNjcm(parentBone)
|
|
|
|
return None
|
|
|
|
def readModel(self):
|
|
|
|
bytes = self.file.read(24)
|
|
m = struct.unpack('IIffff', bytes)
|
|
|
|
vertex_ofs = m[0]
|
|
chunk_ofs = m[1]
|
|
center = (m[2], m[3], m[4])
|
|
radius = m[5]
|
|
|
|
if vertex_ofs:
|
|
self.file.seek(vertex_ofs + self.pof, 0)
|
|
self.readVertexList()
|
|
|
|
if chunk_ofs:
|
|
self.file.seek(chunk_ofs + self.pof, 0)
|
|
self.readChunkList()
|
|
|
|
return None
|
|
|
|
def readVertexList(self):
|
|
|
|
bytes = self.file.read(8)
|
|
c = struct.unpack('BBHHH', bytes)
|
|
chunk_head = c[0]
|
|
chunk_flag = c[1]
|
|
chunk_len = c[2]
|
|
vertex_ofs = c[3]
|
|
vertex_count = c[4]
|
|
|
|
readColor = False
|
|
readNormal = False
|
|
|
|
if chunk_head == 0x23:
|
|
readColor = True
|
|
elif chunk_head == 0x29:
|
|
readNormal = True
|
|
else:
|
|
print("ERROR!!! NEW VERTEX TYPE!!!!")
|
|
print("New Vertex Type: 0x%02x" % chunk_head)
|
|
|
|
if self.debug:
|
|
print("--- Reading vertex list ---")
|
|
print("Vertex Count: %d" % vertex_count)
|
|
print("Vertex Offset: %d" % vertex_ofs)
|
|
|
|
for i in range(vertex_count):
|
|
|
|
vertex = NinjaVertex()
|
|
|
|
# Position
|
|
bytes = self.file.read(12)
|
|
v = struct.unpack('fff', bytes)
|
|
pos = [ v[0], v[1], v[2] ]
|
|
pos = self.bone.apply(pos)
|
|
vertex.setPosition( pos[0], pos[1], pos[2] )
|
|
|
|
# Normal
|
|
if readNormal:
|
|
bytes = self.file.read(12)
|
|
v = struct.unpack('fff', bytes)
|
|
norm = [ v[0], v[1], v[2] ]
|
|
norm = self.bone.applyNorm(norm)
|
|
vertex.setNormal( norm[0], norm[1], norm[2] )
|
|
|
|
# Vertex Color
|
|
if readColor:
|
|
bytes = self.file.read(4)
|
|
v = struct.unpack('BBBB', bytes)
|
|
r = v[0]
|
|
b = v[1]
|
|
g = v[2]
|
|
a = v[3]
|
|
vertex.setColor(r, g, b, a)
|
|
|
|
vertex.setSkinWeight(0, self.bone.index, 1.0)
|
|
|
|
while len(self.index_lookup) < vertex_ofs + 1:
|
|
self.index_lookup.append(None)
|
|
|
|
self.index_lookup[vertex_ofs] = len(self.vertex_list)
|
|
vertex_ofs += 1
|
|
self.vertex_list.append(vertex)
|
|
|
|
pos = self.file.tell()
|
|
bytes = self.file.read(2)
|
|
c = struct.unpack('BB', bytes)
|
|
chunk_head = c[0]
|
|
chunk_flag = c[1]
|
|
|
|
if chunk_head != 255:
|
|
print("ERROR ANOTHER VERTEX LIST DETECTED")
|
|
|
|
return None
|
|
|
|
def readChunkList(self):
|
|
|
|
if self.debug:
|
|
print("--- Reading Chunks @ 0x%08x ---" % self.file.tell())
|
|
|
|
while 1:
|
|
|
|
bytes = self.file.read(2)
|
|
c = struct.unpack('BB', bytes)
|
|
chunk_head = c[0]
|
|
chunk_flag = c[1]
|
|
|
|
if chunk_head == 255:
|
|
if self.debug:
|
|
print("End Chunk Found")
|
|
break
|
|
elif chunk_head == 0:
|
|
if self.debug:
|
|
print("Null Chunk Found")
|
|
continue
|
|
elif chunk_head >= 1 and chunk_head <= 5:
|
|
if self.debug:
|
|
print("Bits Chunk Found")
|
|
|
|
if chunk_head == 1:
|
|
print("Blend Alpha Adjust!!")
|
|
elif chunk_head == 2:
|
|
print("Mipmap adjust")
|
|
elif chunk_head == 3:
|
|
print("Specular exponent")
|
|
elif chunk_head == 4:
|
|
print("Save offset!!!")
|
|
elif chunk_head == 5:
|
|
print("Jumpt to offset!!!")
|
|
|
|
elif chunk_head >= 17 and chunk_head <= 23:
|
|
if self.debug:
|
|
print("Material Chunk Found @ 0x%08x" % self.file.tell())
|
|
|
|
bytes = self.file.read(2)
|
|
short_len = struct.unpack('H', bytes)
|
|
self.material = NinjaMaterial()
|
|
|
|
dst_alpha = chunk_flag & 0x07
|
|
src_alpha = chunk_flag >> 3
|
|
|
|
if chunk_head & 0x01:
|
|
bytes = self.file.read(4)
|
|
c = struct.unpack('BBBB', bytes)
|
|
b = c[0] / 255.0
|
|
g = c[1] / 255.0
|
|
r = c[2] / 255.0
|
|
a = c[3] / 255.0
|
|
self.material.setDiffuseColor(r, g, b, a)
|
|
|
|
if chunk_head & 0x02:
|
|
bytes = self.file.read(4)
|
|
c = struct.unpack('BBBB', bytes)
|
|
b = c[0] / 255.0,
|
|
g = c[1] / 255.0,
|
|
r = c[2] / 255.0,
|
|
a = c[3] / 255.0
|
|
|
|
if chunk_head & 0x04:
|
|
bytes = self.file.read(4)
|
|
c = struct.unpack('BBBB', bytes)
|
|
b = c[0] / 255.0,
|
|
g = c[1] / 255.0,
|
|
r = c[2] / 255.0,
|
|
coef = c[3] / 255.0
|
|
|
|
elif chunk_head >= 8 and chunk_head <= 9:
|
|
if self.debug:
|
|
print("Texture Chunk Found @ 0x%08x" % self.file.tell())
|
|
|
|
bytes = self.file.read(2)
|
|
chunk_body = struct.unpack('H', bytes)[0]
|
|
mip_depth = chunk_flag & 0x07
|
|
clamp_u = chunk_flag & 0x08
|
|
clamp_v = chunk_flag & 0x10
|
|
flip_u = chunk_flag & 0x20
|
|
flip_v = chunk_flag & 0x40
|
|
tex_id = chunk_body & 0x1fff
|
|
super_sample = chunk_body >> 13 & 0x01
|
|
filter_sample = chunk_body >> 14 & 0x03
|
|
self.material = self.material.clone()
|
|
self.material.setTexIndex(tex_id)
|
|
elif chunk_head >= 64 and chunk_head <= 66:
|
|
|
|
if self.debug:
|
|
print("Strip Chunk Found @ 0x%08x" % self.file.tell())
|
|
|
|
bytes = self.file.read(2)
|
|
h = struct.unpack('H', bytes)
|
|
chunk_len = h[0] * 2
|
|
snap_to = self.file.tell() + chunk_len
|
|
|
|
bytes = self.file.read(2)
|
|
h = struct.unpack('H', bytes)
|
|
chunk_body = h[0]
|
|
|
|
if self.debug:
|
|
print("Strip Length (bytes): 0x%04x" % chunk_len)
|
|
print("Expected End: 0x%08x" % (self.file.tell() + chunk_len))
|
|
|
|
mat_index = -1
|
|
for i in range(len(self.mat_list)):
|
|
if self.material != self.mat_list[i]:
|
|
continue
|
|
mat_index = i
|
|
break
|
|
|
|
if mat_index == -1:
|
|
mat_index = len(self.mat_list)
|
|
self.material.setIndex(len(self.mat_list))
|
|
self.mat_list.append(self.material)
|
|
|
|
ignore_light = chunk_flag & 0x01
|
|
ignore_specular = chunk_flag & 0x02
|
|
ignore_ambient = chunk_flag & 0x04
|
|
use_alpha = chunk_flag & 0x08
|
|
double_side = chunk_flag & 0x10
|
|
flat_shading = chunk_flag & 0x20
|
|
environment_mapping = chunk_flag & 0x20
|
|
|
|
strip_count = chunk_body & 0x3fff;
|
|
user_offset = chunk_body >> 14
|
|
|
|
if self.debug:
|
|
print("Strip Count: %d" % strip_count)
|
|
print("User Offset: %d" % user_offset)
|
|
|
|
for i in range (strip_count): # {
|
|
|
|
bytes = self.file.read(2)
|
|
strip_len = struct.unpack('h', bytes)[0]
|
|
|
|
if self.debug:
|
|
print("Strip length: %d" % strip_len)
|
|
|
|
clockwise = strip_len < 0
|
|
strip_len = abs(strip_len)
|
|
strip = []
|
|
indices = []
|
|
|
|
for k in range (strip_len): # {
|
|
bytes = self.file.read(2)
|
|
index = struct.unpack('H', bytes)[0]
|
|
indices.append(index)
|
|
index = self.index_lookup[index]
|
|
|
|
if chunk_head == 64:
|
|
strip.append({
|
|
'index' : index,
|
|
'uv' : { 'u' : 0, 'v' : 0 }
|
|
})
|
|
continue
|
|
|
|
bytes = self.file.read(4)
|
|
uv = struct.unpack('hh', bytes)
|
|
u = uv[0]
|
|
v = uv[1]
|
|
|
|
if chunk_head == 65:
|
|
u = u / 255.0
|
|
v = v / 255.0
|
|
elif chunk_head == 66:
|
|
u = u / 1023.0
|
|
v = v / 1023.0
|
|
|
|
strip.append({
|
|
'index' : index,
|
|
'uv' : { 'u' : u, 'v' : v }
|
|
})
|
|
|
|
for k in range(len(strip) - 2):
|
|
|
|
if ((clockwise and not (k % 2)) or ( not clockwise and k % 2)):
|
|
a = strip[k + 2]
|
|
b = strip[k + 1]
|
|
c = strip[k + 0]
|
|
else :
|
|
a = strip[k + 2]
|
|
b = strip[k + 0]
|
|
c = strip[k + 1]
|
|
|
|
ai = a['index']
|
|
bi = b['index']
|
|
ci = c['index']
|
|
|
|
va = self.vertex_list[ai]
|
|
vb = self.vertex_list[bi]
|
|
vc = self.vertex_list[ci]
|
|
|
|
face = NinjaFace()
|
|
face.setMatIndex(mat_index)
|
|
face.setIndexes(ai, bi, ci)
|
|
face.setNormals(va.norm, vb.norm, vc.norm)
|
|
face.setDiffuseUv(a['uv'], b['uv'], c['uv'])
|
|
self.face_list.append(face)
|
|
|
|
self.file.seek(snap_to, 0)
|
|
self.strip_count = self.strip_count + 1
|
|
|
|
else:
|
|
print("Unknown File Position: 0x%08x" % self.file.tell())
|
|
|
|
return None
|
|
|
|
def readNmdm(self):
|
|
|
|
if self.debug:
|
|
print("READING NINJA MOTION")
|
|
|
|
# Read Header
|
|
bytes = self.file.read(12)
|
|
p = struct.unpack('IIHH', bytes)
|
|
table_ofs = self.pof + p[0]
|
|
frame_count = p[1]
|
|
flags = p[2]
|
|
|
|
factor_count = p[3] & 0x03
|
|
spline_interpolation = p[3] & 0x40
|
|
user_function_interpolation = p[3] & 0x80
|
|
|
|
anim = NinjaMotion()
|
|
anim.setName(len(self.anim_list))
|
|
anim.setFrames(frame_count)
|
|
anim.setSkeleton(self.bones)
|
|
self.anim_list.append(anim)
|
|
|
|
if self.debug:
|
|
print("Frame Count: %d" % frame_count)
|
|
print("Flags: %x" % flags)
|
|
print("Animation Name: ", anim.name)
|
|
if flags & 0x01:
|
|
print("Has Position!")
|
|
if flags & 0x20:
|
|
print("Has Position!")
|
|
if flags & 0x01:
|
|
print("Has Position!")
|
|
|
|
# Read Motion Table
|
|
anim_vals = []
|
|
|
|
self.file.seek(table_ofs, 0)
|
|
for i in range(len(self.bones)):
|
|
|
|
entry = {
|
|
'bone_index' : i,
|
|
'pos_ofs' : 0,
|
|
'pos_num' : 0,
|
|
'rot_ofs' : 0,
|
|
'rot_num' : 0,
|
|
'scl_ofs' : 0,
|
|
'scl_num' : 0
|
|
}
|
|
|
|
if flags & 0x01:
|
|
bytes = self.file.read(4)
|
|
p = struct.unpack('I', bytes)
|
|
if(p[0]):
|
|
entry['pos_ofs'] = self.pof + p[0]
|
|
|
|
if flags & 0x20:
|
|
bytes = self.file.read(4)
|
|
p = struct.unpack('I', bytes)
|
|
if(p[0]):
|
|
entry['rot_ofs'] = self.pof + p[0]
|
|
|
|
if flags & 0x04:
|
|
bytes = self.file.read(4)
|
|
p = struct.unpack('I', bytes)
|
|
if(p[0]):
|
|
entry['scl_ofs'] = self.pof + p[0]
|
|
|
|
if flags & 0x01:
|
|
bytes = self.file.read(4)
|
|
p = struct.unpack('I', bytes)
|
|
entry['pos_num'] = p[0]
|
|
|
|
if flags & 0x20:
|
|
bytes = self.file.read(4)
|
|
p = struct.unpack('I', bytes)
|
|
entry['rot_num'] = p[0]
|
|
|
|
if flags & 0x04:
|
|
bytes = self.file.read(4)
|
|
p = struct.unpack('I', bytes)
|
|
entry['scl_num'] = p[0]
|
|
anim_vals.append(entry)
|
|
|
|
c = 2 * 3.141592 / 0x10000;
|
|
for entry in anim_vals:
|
|
boneIndex = entry['bone_index']
|
|
|
|
self.file.seek(entry['pos_ofs'], 0)
|
|
for i in range(entry['pos_num']):
|
|
bytes = self.file.read(16)
|
|
p = struct.unpack('Ifff', bytes)
|
|
frame = p[0]
|
|
vec3 = [ p[1], p[2], p[3] ]
|
|
anim.appendKeyFrame(boneIndex, frame, vec3, 'pos')
|
|
|
|
self.file.seek(entry['rot_ofs'], 0)
|
|
for i in range(entry['rot_num']):
|
|
bytes = self.file.read(8)
|
|
p = struct.unpack('Hhhh', bytes)
|
|
frame = p[0]
|
|
vec3 = [ p[1]*c, p[2]*c, p[3]*c ]
|
|
anim.appendKeyFrame(boneIndex, frame, vec3, 'rot')
|
|
|
|
self.file.seek(entry['scl_ofs'], 0)
|
|
for i in range(entry['scl_num']):
|
|
bytes = self.file.read(16)
|
|
p = struct.unpack('Ifff', bytes)
|
|
frame = p[0]
|
|
vec3 = [ p[1], p[2], p[3] ]
|
|
anim.appendKeyFrame(boneIndex, frame, vec3, 'scl')
|
|
anim.save(boneIndex)
|
|
|
|
return None
|
|
|
|
def exportObj(self):
|
|
|
|
pre, ext = os.path.splitext(self.model_name)
|
|
pre = pre.replace('/', '_')
|
|
f = open('output/' + pre + '.OBJ', 'w')
|
|
|
|
for vert in self.vertex_list:
|
|
f.write('v')
|
|
f.write(' %.03f' % vert.pos['x'])
|
|
f.write(' %.03f' % vert.pos['y'])
|
|
f.write(' %.03f' % vert.pos['z'])
|
|
f.write('\r\n')
|
|
f.write('\r\n')
|
|
|
|
for face in self.face_list:
|
|
f.write('f')
|
|
f.write(' %d' % (face.index[0] + 1))
|
|
f.write(' %d' % (face.index[1] + 1))
|
|
f.write(' %d' % (face.index[2] + 1))
|
|
f.write('\r\n')
|
|
f.write('\r\n')
|
|
f.close()
|
|
|
|
return None
|
|
|
|
def export(self):
|
|
pre, ext = os.path.splitext(self.model_name)
|
|
pre = pre.replace('/', '_')
|
|
f = open('output/' + pre + '.DMF', 'wb')
|
|
|
|
# Write Magic
|
|
f.write(b'DASH')
|
|
f.write(struct.pack('HHII', 1, 5, 0x10, 0x06))
|
|
|
|
#Write Table
|
|
f.write(b'tex\0')
|
|
f.write(struct.pack('III', 0, 0, 0))
|
|
f.write(b'mat\0')
|
|
f.write(struct.pack('III', 0, 0, 0))
|
|
f.write(b'vert')
|
|
f.write(struct.pack('III', 0, 0, 0))
|
|
f.write(b'face')
|
|
f.write(struct.pack('III', 0, 0, 0))
|
|
f.write(b'bone')
|
|
f.write(struct.pack('III', 0, 0, 0))
|
|
f.write(b'anim')
|
|
f.write(struct.pack('III', 0, 0, 0))
|
|
|
|
# Write Textures
|
|
pos = f.tell()
|
|
count = len(self.tex_list)
|
|
f.seek(0x18, 0)
|
|
f.write(struct.pack('II', pos, count))
|
|
f.seek(0, 2)
|
|
|
|
for tex in self.tex_list:
|
|
tex.createDmfEntry(f)
|
|
for tex in self.tex_list:
|
|
tex.writeDmfTexture(f)
|
|
|
|
# Write Materials
|
|
pos = f.tell()
|
|
count = len(self.mat_list)
|
|
f.seek(0x28, 0)
|
|
f.write(struct.pack('II', pos, count))
|
|
f.seek(0, 2)
|
|
|
|
for mat in self.mat_list:
|
|
mat.createDmfEntry(f)
|
|
|
|
# Write Vertices
|
|
pos = f.tell()
|
|
count = len(self.vertex_list)
|
|
f.seek(0x38, 0)
|
|
f.write(struct.pack('II', pos, count))
|
|
f.seek(0, 2)
|
|
|
|
for vert in self.vertex_list:
|
|
vert.createDmfEntry(f)
|
|
|
|
while f.tell() % 0x10:
|
|
f.write(struct.pack('B', 0))
|
|
|
|
# Write Faces
|
|
pos = f.tell()
|
|
count = len(self.face_list)
|
|
f.seek(0x48, 0)
|
|
f.write(struct.pack('II', pos, count))
|
|
f.seek(0, 2)
|
|
|
|
for face in self.face_list:
|
|
face.createDmfEntry(f)
|
|
|
|
while f.tell() % 0x10:
|
|
f.write(struct.pack('B', 0))
|
|
|
|
# Write Bones
|
|
pos = f.tell()
|
|
count = len(self.bones)
|
|
f.seek(0x58, 0)
|
|
f.write(struct.pack('II', pos, count))
|
|
f.seek(0, 2)
|
|
|
|
for bone in self.bones:
|
|
bone.createDmfEntry(f)
|
|
|
|
#Write Animations
|
|
pos = f.tell()
|
|
count = len(self.anim_list)
|
|
f.seek(0x68, 0)
|
|
f.write(struct.pack('II', pos, count))
|
|
f.seek(0, 2)
|
|
|
|
for anim in self.anim_list:
|
|
anim.generateDmfEntry(f)
|
|
|
|
for anim in self.anim_list:
|
|
anim.writeDmfAnimation(f)
|
|
|
|
f.close()
|
|
return None
|
|
|