import os
import sys
import collections
import struct
import traceback
assert sys.version_info >= (2, 7), 'Python with version less than 2.7 is not supported, your version is: %s' % sys.version
# RK model parser
_chunkTypesNames = [
'RKCHUNK_TYPE_UNUSED',
'RKCHUNK_TYPE_MATERIAL_MESH_ARRAY',
'RKCHUNK_TYPE_MATERIAL_ARRAY',
'RKCHUNK_TYPE_VERTEX_ARRAY',
'RKCHUNK_TYPE_INDEX_ARRAY',
'RKCHUNK_TYPE_REFPOINT_ARRAY',
'RKCHUNK_TYPE_VOLUME_ARRAY',
'RKCHUNK_TYPE_BONE_ARRAY',
'RKCHUNK_TYPE_TRIANGLE_COLLISION_VERTEX_ARRAY',
'RKCHUNK_TYPE_TRIANGLE_COLLISION_INDEX_ARRAY',
'RKCHUNK_TYPE_TRIANGLE_COLLISION_MESH_ARRAY',
'RKCHUNK_TYPE_CONVEX_COLLISION_VERTEX_ARRAY',
'RKCHUNK_TYPE_CONVEX_COLLISION_MESH_ARRAY',
'RKCHUNK_TYPE_VERTEX_ELEMENTS',
'RKCHUNK_TYPE_COOKED_TRIANGLE_MESH_ARRAY',
'RKCHUNK_TYPE_COOKED_TRIANGLE_DATA_ARRAY',
'RKCHUNK_TYPE_SUB_OBJECT_NAME',
'RKCHUNK_TYPE_VERTEX_SKIN_ARRAY',
'RKCHUNK_TYPE_SPLINE_KNOT_ARRAY',
'RKCHUNK_TYPE_SPLINE_ARRAY',
'RKCHUNK_TYPE_MODEL_PIVOT',
'RKCHUNK_TYPE_PHYSICSSHAPE_ARRAY',
'RKCHUNK_TYPE_PHYSICSVOLUME_ARRAY',
'RKCHUNK_TYPE_ANIM_BONE_MAP_ARRAY',
]
def _readRKString(f, size=64):
data = f.read(size)
for idx in range(len(data)):
if data[idx] == '\0':
return str(data[:idx])
return str(data)
def parseANIM(filePath):
params = collections.OrderedDict()
params['type'] = 'animation'
params['filePath'] = filePath
with open(filePath, 'rb') as f:
params['id'] = _readRKString(f, 8)
versionMajor, versionMinor = struct.unpack('II', f.read(8))
params['versionMajor'] = versionMajor
params['versionMinor'] = versionMinor
params['name'] = _readRKString(f)
bonesCount, keyFramesCount, compressionType, frameRate = struct.unpack('IIII', f.read(16))
params['bonesCount'] = bonesCount
params['keyFramesCount'] = keyFramesCount
params['compression'] = compressionType
params['frameRate'] = frameRate
return params
def parseRK(filePath):
params = collections.OrderedDict()
params['type'] = 'model'
params['filePath'] = filePath
with open(filePath, 'rb') as f:
params['id'] = _readRKString(f, 8)
versionMajor, versionMinor = struct.unpack('II', f.read(8))
params['versionMajor'] = versionMajor
params['versionMinor'] = versionMinor
params['name'] = _readRKString(f)
chunks = {}
try:
if params['versionMajor'] >= 2:
for i in range(24):
chunkType, chunkOffset, chunkElementsCount, chunkSize = struct.unpack('IIII', f.read(16))
if chunkType != 0:
if chunkType >= len(_chunkTypesNames):
chunkTypeName = 'RKCHUNK_TYPE_MODEL_UNKNOWN_%i' % chunkType
else:
chunkTypeName = _chunkTypesNames[chunkType]
assert not chunkTypeName in params
chunks[chunkTypeName] = chunkElementsCount
except Exception, e:
print 'Error parsing file chunks: %s' % filePath
traceback.print_exc()
params['clipsCount'] = 0
animClipsFile = os.path.splitext(filePath)[0] + '.csv'
if os.path.exists(animClipsFile):
with open(animClipsFile) as f:
lines = f.readlines()
lines = filter(lambda x : bool(x.strip()), lines)
params['clipsCount'] = len(lines)
params['keyFramesCount'] = 0
params['animRawSize'] = 0
animFile = os.path.splitext(filePath)[0] + '.anim'
if os.path.exists(animFile):
params['animRawSize'] = os.path.getsize(animFile)
with open(animFile, 'rb') as f:
animName = _readRKString(f)
bonesCount, keyFramesCount = struct.unpack('II', f.read(8))
params['keyFramesCount'] = keyFramesCount
params['meshesCount'] = 0
if 'RKCHUNK_TYPE_MATERIAL_MESH_ARRAY' in chunks:
params['meshesCount'] = chunks['RKCHUNK_TYPE_MATERIAL_MESH_ARRAY']
params['bonesCount'] = 0
if 'RKCHUNK_TYPE_BONE_ARRAY' in chunks:
params['bonesCount'] = chunks['RKCHUNK_TYPE_BONE_ARRAY']
params['materialsCount'] = 0
if 'RKCHUNK_TYPE_MATERIAL_ARRAY' in chunks:
params['materialsCount'] = chunks['RKCHUNK_TYPE_MATERIAL_ARRAY']
params.update(chunks)
return params
def parse(filePath):
if filePath.endswith('.anim'):
return parseANIM(filePath)
else:
return parseRK(filePath)
def getVersion(filePath):
params = parse(filePath)
return params['versionMajor'], params['versionMinor']
if __name__ == '__main__':
if len(sys.argv) != 2:
print 'Usage: [python.exe] rk.py <filename.rk>'
sys.exit(1)
rk = parse(sys.argv[1])
for key, value in rk.items():
print '%s = %s' % (key, value)