summaryrefslogtreecommitdiff
path: root/src/exporter.py
blob: fec2f86f501a1353ba79443ca0865da3fd8ef795 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
from common import *
import array
import sys


class KPMapExporter:
	class LayerExporter:
		def __init__(self, layer):
			self.layer = layer

		def buildSectors(self, sectors, indices):
			# we'll use the cache held by the layer: why reinvent the wheel?
			layer.updateCache()
			cache = layer.cache

			# first off, get all the info and figure out the sector bounds
			layerX, layerY = layer.cacheBasePos
			layerWidth, layerHeight = layer.cacheSize

			sectorLeft = layerX / 16
			sectorTop = layerY / 16
			sectorRight = (layerX + layerWidth) / 16
			sectorBottom = (layerY + layerHeight) / 16

			rawSectors = []
			for i in xrange(sectorBottom - sectorTop + 1):
				rawSectors.append([None for j in xrange(sectorRight - sectorLeft + 1)])

			# copy every tile index over
			for srcY in xrange(layerHeight):
				srcRow = cache[srcY]
				worldY = srcY + layerY
				sectorY = worldY / 16
				destY = worldY % 16

				destRow = rawSectors[sectorY]
				
				for srcX in xrange(layerX, layerX+layerWidth):
					worldX = srcX + layerX
					sectorX = worldX / 16
					destX = worldX % 16

					tile = srcRow[i]
					if tile == -1: continue

					destSector = destRow[sectorX]
					if destSector is None:
						destSector = [[-1 for j in xrange(16)] for i in xrange(16)]
						destRow[sectorX] = destSector

					destSector[destY][destX] = tile

			# now add the created sectors to the data
			sectorMap = [-1 for i in xrange(len(self.rawSectors))]

			for srcRow, mapRow in zip(self.rawSectors, sectorMap):
				for index, sector in enumerate(srcRow):
					if sector is not None:
						# see if it's a duplicate or not
						sectorKey = '|'.join(map(lambda x: ','.join(map(str, x)), sector))

						try:
							mapRow[index] = sectorIndices[sectorKey]
						except ValueError:
							sectorIndices[sectorKey] = len(sectors)
							mapRow[index] = len(sectors)
							sectors.append(sector)

			self.sectorBounds = (sectorLeft, sectorTop, sectorRight, sectorBottom)
			self.sectorMap = sectorMap


	
	def __init__(self, mapObj):
		self.map = mapObj

		self.layers = map(KPMapExporter.LayerExporter, self.map.layers)

		self.archive = WiiArchiveU8()
	
	def buildAndPack(self, handle=None):
		# make the BG data
		sectors = []
		sectorIndices = {}

		for layer in self.layers:
			layer.buildSectors(sectors, sectorIndices)

		# pack it into the arc
		self.archive.resolvePath('/sectors.bin').data = self._packSectorData(sectors)
		self.archive.resolvePath('/sectorMaps.bin').data = self._packSectorMaps()

		return self.archive.pack(handle)


	def _packSectorData(self, sectors):
		rowStruct = struct.Struct('>16h')
		output = []

		for sector in sectors:
			for row in sector:
				output.append(rowStruct.pack(*row))

		return ''.join(output)

	def _packSectorMaps(self):
		offsets = array.array('I')
		assert offsets.itemsize == 4

		currentOffset = len(self.layers) * 4

		data = []

		for index, layer in enumerate(self.layers):
			offsets.append(currentOffset)

			data.append(struct.pack('>hhhh', *layer.sectorBounds))
			currentOffset += 8
			
			first = layer.sectorMap[0]
			rowStruct = struct.Struct('>%dh' % len(first))
			for row in layer.sectorMap:
				data.append(rowStruct.pack(*row))

			currentOffset += (len(first) * len(layer.sectorMap) * 2)

		if sys.byteorder == 'little': offsets.byteswap()
		return offsets.tostring() + ''.join(data)