perfect_dark/tools/assetmgr/mktiles

200 lines
5.2 KiB
Python
Executable File

#!/usr/bin/env python3
import assetmgr
import json
import os
import re
import struct
import sys
class App():
floortypes = {
'default': 0,
'wood': 1,
'stone': 2,
'carpet': 3,
'metal': 4,
'mud': 5,
'water': 6,
'dirt': 7,
'snow': 8,
}
def run(self):
self.load_data()
self.room_names = self.json['rooms'].keys()
self.make_header()
self.make_object()
def load_data(self):
fd = open(sys.argv[1], 'r')
data = fd.read()
fd.close()
self.json = json.loads(data)
self.shortname = os.path.basename(sys.argv[1]).replace('.json', '')
def make_header(self):
typename = 'room_%s' % self.shortname
enums = self.json['rooms'].keys()
filename = 'tiles/%s.h' % self.shortname
terminator = 'ROOM_%s_END' % self.shortname.upper()
assetmgr.write_enums(typename, enums, filename, terminator)
def make_object(self):
binary = self.make_binary()
zipped = assetmgr.zip(binary)
# Write the zipped file, purely so `make test` can verify it
assetmgr.writefile('build/%s/assets/files/bgdata/bg_%s_tilesZ' % (os.environ['ROMID'], self.shortname), zipped)
filename = 'files/bgdata/bg_%s_tilesZ.o' % self.shortname
assetmgr.write_object(zipped, filename)
# Order of stuff:
# - 0x00: number of rooms
# - 0x04: room offset table, with end marker
# - Room data
def make_binary(self):
rooms = self.make_rooms()
output = bytes()
# Write number of rooms
output += len(rooms).to_bytes(4, 'big')
# Write room offset table
pos = 4 + len(rooms) * 4 + 4
for room in rooms:
output += pos.to_bytes(4, 'big')
pos += len(room)
# Write end marker
output += pos.to_bytes(4, 'big')
# Write room data
output += b''.join(rooms)
output = assetmgr.pad16(output)
return output
def make_rooms(self):
rooms = []
for data in self.json['rooms'].values():
rooms.append(self.make_room(data))
return rooms
def make_room(self, tiles):
output = bytes()
for tile in tiles:
output += self.make_tile(tile)
return output
def make_tile(self, tile):
output = bytes()
bbox = self.find_bbox(tile['vertices'])
output += b'\x00'
output += len(tile['vertices']).to_bytes(1, 'big')
output += self.make_flags(tile).to_bytes(2, 'big')
output += self.floortypes[tile['floortype']].to_bytes(2, 'big')
output += bbox['xmin'].to_bytes(1, 'big')
output += bbox['ymin'].to_bytes(1, 'big')
output += bbox['zmin'].to_bytes(1, 'big')
output += bbox['xmax'].to_bytes(1, 'big')
output += bbox['ymax'].to_bytes(1, 'big')
output += bbox['zmax'].to_bytes(1, 'big')
output += tile['floorcolour'].to_bytes(2, 'big')
for vert in tile['vertices']:
output += self.make_unsigned(vert['x']).to_bytes(2, 'big')
output += self.make_unsigned(vert['y']).to_bytes(2, 'big')
output += self.make_unsigned(vert['z']).to_bytes(2, 'big')
return output
def find_bbox(self, verts):
values = {}
indices = {}
values['xmin'] = 99999
values['ymin'] = 99999
values['zmin'] = 99999
values['xmax'] = -99999
values['ymax'] = -99999
values['zmax'] = -99999
indices['xmin'] = 0
indices['ymin'] = 0
indices['zmin'] = 0
indices['xmax'] = 0
indices['ymax'] = 0
indices['zmax'] = 0
for index, vert in enumerate(verts):
if vert['x'] < values['xmin']:
values['xmin'] = vert['x']
indices['xmin'] = index
if vert['y'] < values['ymin']:
values['ymin'] = vert['y']
indices['ymin'] = index
if vert['z'] < values['zmin']:
values['zmin'] = vert['z']
indices['zmin'] = index
if vert['x'] > values['xmax']:
values['xmax'] = vert['x']
indices['xmax'] = index
if vert['y'] > values['ymax']:
values['ymax'] = vert['y']
indices['ymax'] = index
if vert['z'] > values['zmax']:
values['zmax'] = vert['z']
indices['zmax'] = index
return indices
def make_flags(self, room):
names = [
'flag0001',
'flag0002',
'flag0004',
'flag0008',
'flag0010',
'flag0020',
'ladder',
'flag0080',
'flag0100',
'underwater',
'flag0400',
'aibotcrouch',
'aibotduck',
'flag2000',
'die',
'climbableledge',
]
flags = 0
for index, name in enumerate(names):
if room[name]:
flags |= 1 << index
return flags
def make_unsigned(self, value):
if value < 0:
value = 0x10000 - abs(value)
return value
app = App()
app.run()