prep.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. import os
  2. import sys
  3. import array
  4. import struct
  5. import zlib
  6. import textwrap
  7. import wave
  8. import audioop
  9. import Image, ImageFont, ImageDraw, ImageChops
  10. import gameduino2 as gd2
  11. import gameduino2.convert
  12. import gameduino2.tmxreader
  13. from gameduino2.imbytes import imbytes
  14. def stretch(im):
  15. d = imbytes(im)
  16. # print min(d), max(d)
  17. r = max(d) - min(d)
  18. return im.point(lambda x: (x - min(d)) * 255 / r)
  19. def getalpha(im):
  20. return im.split()[3]
  21. def tile(tw, th, im):
  22. tiles = []
  23. for y in range(0, im.size[1], th):
  24. for x in range(0, im.size[0], tw):
  25. tiles.append(im.crop((x, y, x + tw, y + th)))
  26. o = Image.new(im.mode, (tw, th * len(tiles)))
  27. for i,t in enumerate(tiles):
  28. o.paste(t, (0, i * th))
  29. return o
  30. def split(tw, th, im):
  31. tiles = []
  32. for y in range(0, im.size[1], th):
  33. for x in range(0, im.size[0], tw):
  34. tiles.append(im.crop((x, y, x + tw, y + th)))
  35. return tiles
  36. def join(tiles):
  37. (tw, th) = tiles[0].size
  38. o = Image.new(tiles[0].mode, (tw, th * len(tiles)))
  39. for i,t in enumerate(tiles):
  40. o.paste(t, (0, i * th))
  41. return o
  42. def setwidth(im, w):
  43. e = Image.new(im.mode, (w, im.size[1]))
  44. e.paste(im, (0, 0))
  45. return e
  46. def even(im):
  47. w = im.size[0]
  48. if (w % 2) == 0:
  49. return im
  50. else:
  51. return setwidth(im, w + 1)
  52. def extents(im):
  53. """ find pixel extents of im, as a box """
  54. w,h = im.size
  55. cols = [set(imbytes(im.crop((i, 0, i + 1, im.size[1])))) != set([0]) for i in range(w)]
  56. rows = [set(imbytes(im.crop((0, i, im.size[0], i + 1)))) != set([0]) for i in range(h)]
  57. if not True in cols:
  58. return (0, 0, 0, 0)
  59. else:
  60. x0 = cols.index(True)
  61. y0 = rows.index(True)
  62. while not cols[-1]:
  63. cols.pop()
  64. while not rows[-1]:
  65. rows.pop()
  66. return (x0, y0, len(cols), len(rows))
  67. def ul(x):
  68. return str(x) + "UL"
  69. def preview(np, fmt, size, data):
  70. def chan(x):
  71. return Image.fromstring("L", size, (255 * x).astype(np.uint8))
  72. if fmt == gd2.L1:
  73. r = Image.fromstring("1", size, data)
  74. elif fmt == gd2.L8:
  75. r = Image.fromstring("L", size, data)
  76. else:
  77. d8 = np.array(data)
  78. a = np.ones(size[0] * size[1])
  79. (r, g, b) = (a, a, a)
  80. if fmt == gd2.ARGB4:
  81. d16 = np.array(array.array('H', data.tostring()))
  82. a = (15 & (d16 >> 12)) / 15.
  83. r = (15 & (d16 >> 8)) / 15.
  84. g = (15 & (d16 >> 4)) / 15.
  85. b = (15 & (d16 >> 0)) / 15.
  86. elif fmt == gd2.RGB565:
  87. d16 = np.array(array.array('H', data.tostring()))
  88. r = (31 & (d16 >> 11)) / 31.
  89. g = (63 & (d16 >> 5)) / 63.
  90. b = (31 & (d16 >> 0)) / 31.
  91. elif fmt == gd2.ARGB1555:
  92. d16 = np.array(array.array('H', data.tostring()))
  93. a = (1 & (d16 >> 15))
  94. r = (31 & (d16 >> 10)) / 31.
  95. g = (31 & (d16 >> 5)) / 31.
  96. b = (31 & (d16 >> 0)) / 31.
  97. elif fmt == gd2.ARGB2:
  98. a = (3 & (d8 >> 6)) / 3.
  99. r = (3 & (d8 >> 4)) / 3.
  100. g = (3 & (d8 >> 2)) / 3.
  101. b = (3 & (d8 >> 0)) / 3.
  102. elif fmt == gd2.RGB332:
  103. r = (7 & (d8 >> 5)) / 7.
  104. g = (7 & (d8 >> 2)) / 7.
  105. b = (3 & (d8 >> 0)) / 3.
  106. elif fmt == gd2.L4:
  107. hi = d8 >> 4
  108. lo = d8 & 15
  109. d4 = np.column_stack((hi, lo)).flatten()
  110. r = d4 / 15.
  111. g = r
  112. b = r
  113. o = Image.merge("RGB", [chan(c) for c in (r, g, b)])
  114. bg = Image.new("RGB", size, (128, 128, 128))
  115. r = Image.composite(o, bg, chan(a))
  116. r = r.resize((r.size[0] * 5, r.size[1] * 5), Image.NEAREST)
  117. return r
  118. import gameduino2.base
  119. def pma(im):
  120. im = im.convert("RGBA")
  121. (r,g,b,a) = im.split()
  122. (r,g,b) = [ImageChops.multiply(a, c) for c in (r,g,b)]
  123. return Image.merge("RGBA", (r, g, b, a))
  124. class EVE(gameduino2.base.GD2):
  125. def __init__(self):
  126. self.d = ""
  127. def c(self, s):
  128. self.d += s
  129. def chunker(seq, size):
  130. return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
  131. class AssetBin(gameduino2.base.GD2):
  132. asset_file = None
  133. prefix = ""
  134. previews = False
  135. def __init__(self):
  136. self.alldata = ""
  137. self.commands = ""
  138. self.defines = []
  139. self.inits = []
  140. self.handle = 0
  141. self.np = None
  142. self.bitmaps = []
  143. # Set defaults for FT800. target_810() modifies these
  144. self.device = 'GD2'
  145. self.maxram = 256 * 1024
  146. self.maxhandles = 15
  147. def target_810(self):
  148. self.device = 'GD3'
  149. self.maxram = 1024 * 1024
  150. self.maxhandles = 32
  151. def define(self, n, v):
  152. self.defines.append((self.prefix + n, v))
  153. def add(self, name, s):
  154. if name:
  155. self.defines.append((name, ul(len(self.alldata))))
  156. self.alldata += s
  157. def c(self, s):
  158. self.commands += s
  159. def addim(self, name, im, fmt, dither = False):
  160. (_, imgdata) = gameduino2.convert.convert(im, dither, fmt = fmt)
  161. self.add(name, imgdata.tostring())
  162. (w, h) = im.size
  163. if name:
  164. self.defines.append(("%s_WIDTH" % name, w))
  165. self.defines.append(("%s_HEIGHT" % name, h))
  166. def align(self, n):
  167. while (len(self.alldata) % n) != 0:
  168. self.alldata += chr(0)
  169. def load_handle(self, name, images, fmt,
  170. dither = False,
  171. filter = gd2.NEAREST,
  172. scale = 1,
  173. rotating = False):
  174. if self.maxhandles <= self.handle:
  175. print "Error: too many bitmap handles used, limit is %d" % self.maxhandles
  176. sys.exit(1)
  177. (w, h) = images[0].size
  178. self.align(2)
  179. if name is not None:
  180. self.define("%s_HANDLE" % name, self.handle)
  181. name = self.prefix + name
  182. self.defines.append(("%s_WIDTH" % name, w))
  183. self.defines.append(("%s_HEIGHT" % name, h))
  184. self.defines.append(("%s_CELLS" % name, len(images)))
  185. self.bitmaps.append((name.lower(), w, h, w / 2, h / 2, len(self.alldata), fmt, self.handle))
  186. self.BitmapHandle(self.handle);
  187. self.BitmapSource(len(self.alldata));
  188. if not rotating:
  189. (vw, vh) = (scale * w, scale * h)
  190. vsz = 0
  191. else:
  192. vsz = int(scale * max(w, h))
  193. self.define("%s_SIZE" % name, vsz)
  194. (vw, vh) = (vsz, vsz)
  195. self.BitmapSize(filter, gd2.BORDER, gd2.BORDER, vw, vh);
  196. if name is not None:
  197. self.inits.append("static const shape_t %s_SHAPE = {%d, %d, %d, %d};" % (name, self.handle, w, h, vsz))
  198. # aw is aligned width
  199. # For L1, L2, L4 formats the width must be a whole number of bytes
  200. if fmt == gd2.L1:
  201. aw = (w + 7) & ~7
  202. elif fmt == gd2.L2:
  203. aw = (w + 3) & ~3
  204. elif fmt == gd2.L4:
  205. aw = (w + 1) & ~1
  206. else:
  207. aw = w
  208. bpl = {
  209. gd2.ARGB1555 : 2 * aw,
  210. gd2.L1 : aw / 8,
  211. gd2.L2 : aw / 4,
  212. gd2.L4 : aw / 2,
  213. gd2.L8 : aw,
  214. gd2.RGB332 : aw,
  215. gd2.ARGB2 : aw,
  216. gd2.ARGB4 : 2 * aw,
  217. gd2.RGB565 : 2 * aw,
  218. gd2.PALETTED : aw}[fmt]
  219. self.BitmapLayout(fmt, bpl, h);
  220. for i,im in enumerate(images):
  221. if aw != w:
  222. im = setwidth(im, aw)
  223. if hasattr(im, "imgdata"):
  224. imgdata = im.imgdata
  225. else:
  226. (_, imgdata) = gameduino2.convert.convert(im, dither, fmt = fmt)
  227. """
  228. if self.previews:
  229. if not self.np:
  230. import numpy
  231. self.np = numpy
  232. preview(self.np, fmt, im.size, imgdata).save("previews/%s-%s-%02d.png" % (self.name, name, i))
  233. """
  234. self.alldata += imgdata.tostring()
  235. self.handle += 1
  236. def load_font(self, name, ims, widths, fmt, **args):
  237. trim0 = 0
  238. while ims[trim0] is None:
  239. trim0 += 1
  240. p0 = len(self.alldata)
  241. h = self.handle
  242. tims = ims[trim0:]
  243. self.load_handle(name, tims, fmt, **args)
  244. self.align(4)
  245. p1 = len(self.alldata)
  246. # Compute memory required by one char
  247. onechar = (p1 - p0) / len(tims)
  248. # print name, 'font requires', (p1 - p0), 'bytes'
  249. sz = ims[trim0].size
  250. self.BitmapSource(p0 - (onechar * trim0));
  251. widths = [max(0, w) for w in widths]
  252. dblock = array.array('B', widths).tostring() + struct.pack("<5i", fmt, 1, sz[0], sz[1], p0 - (onechar * trim0))
  253. self.alldata += dblock
  254. self.cmd_setfont(h, p1);
  255. def load_ttf(self, name, ttfname, size, format):
  256. font = ImageFont.truetype(ttfname, size)
  257. sizes = [font.getsize(chr(c)) for c in range(32, 128)]
  258. fw = max([w for (w, _) in sizes])
  259. fh = max([h for (_, h) in sizes])
  260. # print fw, fh
  261. alle = {}
  262. for i in range(1, 96):
  263. im = Image.new("L", (fw+8, fh))
  264. dr = ImageDraw.Draw(im)
  265. dr.text((8,0), chr(32 + i), font=font, fill=255)
  266. alle[i] = gd2.prep.extents(im)
  267. fw = max([(x1 - x0) for (x0, y0, x1, y1) in alle.values()])
  268. ims = ([None] * 32) + [Image.new("L", (fw, fh)) for i in range(32, 128)]
  269. for i in range(33, 127):
  270. dr = ImageDraw.Draw(ims[i])
  271. (x0, y0, x1, y1) = alle[i - 32]
  272. x = max(0, 8 - x0)
  273. if x > 0:
  274. sizes[i - 32] = (sizes[i - 32][0] - x, sizes[i - 32][1])
  275. dr.text((x, 0), chr(i), font=font, fill=255)
  276. # imgtools.view(im)
  277. widths = ([0] * 32) + [w for (w, _) in sizes]
  278. self.load_font(name, ims, widths, format)
  279. def load_tiles(self, name, file_name, scale = None, preview = False):
  280. world_map = gameduino2.tmxreader.TileMapParser().parse_decode(file_name)
  281. # print("loaded map:", world_map.map_file_name)
  282. x_pixels = world_map.pixel_width
  283. y_pixels = world_map.pixel_height
  284. # print("map size in pixels:", x_pixels, y_pixels)
  285. # print("tile size used:", world_map.tilewidth, world_map.tileheight)
  286. # print("tiles used:", world_map.width, world_map.height)
  287. # print("found '", len(world_map.layers), "' layers on this map")
  288. layers = [l for l in world_map.layers if hasattr(l, 'decoded_content')]
  289. # print layers
  290. w,h = (world_map.width, world_map.height)
  291. ts = world_map.tile_sets[0]
  292. tw = int(ts.tilewidth)
  293. th = int(ts.tileheight)
  294. if scale is not None:
  295. stw,sth = (int(tw * scale), int(th * scale))
  296. else:
  297. stw,sth = tw,th
  298. used = set()
  299. for layer in layers:
  300. used |= set(layer.decoded_content)
  301. # used = sorted(used)
  302. used = sorted(used - set([0]))
  303. def reindex(i):
  304. if i == 0:
  305. return None
  306. else:
  307. return used.index(i)
  308. def fetchtile(l, i, j):
  309. if (i < world_map.width) and (j < world_map.height):
  310. return reindex(l.decoded_content[i + (j * world_map.width)])
  311. else:
  312. return None
  313. eve = EVE()
  314. # print world_map.width * world_map.height * 4
  315. for j in range(0, world_map.height, 4):
  316. for i in range(0, world_map.width, 4):
  317. for layer in layers:
  318. for y in range(4):
  319. for x in range(4):
  320. t = fetchtile(layer, i + x, j + y)
  321. # if i < (480 / 16) and j < (272 / 16): print 16 * (i + x), 16 * (j + y), "tile", t
  322. if t is not None:
  323. eve.Vertex2ii(stw * x, sth * y, t / 128, t % 128)
  324. else:
  325. eve.Nop()
  326. # assert 0
  327. stride = ((w + 3) / 4)
  328. self.add(name, struct.pack("6H", w * stw, h * sth, stw * 4, sth * 4, stride, len(layers)) + eve.d)
  329. self.tile_files = world_map.tile_sets[0].images[0].source
  330. # print 'Size of tiles: %d (compressed %d)' % (len(eve.d), len(zlib.compress(eve.d)))
  331. # print 'Tile size', (tw, th)
  332. im = pma(Image.open(self.tile_files))
  333. def extract(i):
  334. if hasattr(ts, 'columns'):
  335. w = int(ts.columns)
  336. elif not hasattr(ts, 'spacing'):
  337. w = im.size[0] / tw
  338. else:
  339. w = (im.size[0] + ts.spacing) / (tw + ts.spacing)
  340. x = ts.margin + (tw + ts.spacing) * (i % w)
  341. y = ts.margin + (th + ts.spacing) * (i / w)
  342. r = im.crop((x + 0, y + 0, x + tw, y + th))
  343. if scale:
  344. r = r.resize((stw, sth), Image.ANTIALIAS)
  345. return r
  346. for i,g128 in enumerate(chunker(used, 128)):
  347. self.load_handle(None, [extract(t - 1) for t in g128], gd2.ARGB4, dither=0)
  348. if preview:
  349. pv = Image.new("RGB", (tw * w, th * h))
  350. layer = layers[0]
  351. for y in range(pv.size[1] / th):
  352. for x in range(pv.size[0] / tw):
  353. t = fetchtile(layer, x, y)
  354. pv.paste(extract(used[t] - 1), (16 * x, 16 * y))
  355. return pv
  356. """
  357. def dxt1(self, imagefile):
  358. import numpy
  359. im = Image.open(imagefile).resize((480,272), Image.ANTIALIAS)
  360. dxt = "%s.dxt" % imagefile
  361. if not os.access(dxt, os.R_OK):
  362. im.save("tmp.png")
  363. assert os.system("squishpng tmp.png %s" % dxt) == 0
  364. sz = (480 / 4, 272 / 4)
  365. def rgb(cs):
  366. r = (cs >> 11) << 3
  367. g = 0xff & ((cs >> 5) << 2)
  368. b = 0xff & (cs << 3)
  369. return (r,g,b)
  370. def rgbim(cs):
  371. return Image.merge("RGB", [Image.fromarray(c.astype(numpy.uint8).reshape(*sz)) for c in rgb(cs)])
  372. def morton1(x):
  373. v = x & 0x55555555
  374. v = (v | (v >> 1)) & 0x33333333;
  375. v = (v | (v >> 2)) & 0x0F0F0F0F;
  376. v = (v | (v >> 4)) & 0x00FF00FF;
  377. v = (v | (v >> 8)) & 0x0000FFFF;
  378. return v.astype(numpy.uint16)
  379. h = open(dxt)
  380. h.read(8)
  381. c0s = []
  382. c1s = []
  383. bits = []
  384. for i in range(sz[0] * sz[1]):
  385. tile = h.read(8)
  386. c0,c1,bit = struct.unpack("2HI", tile)
  387. b0 = bit & 0x55555555
  388. b1 = (bit >> 1) & 0x55555555
  389. is0 = ~b1 & ~b0
  390. is1 = ~b1 & b0
  391. is2 = b1 & ~b0
  392. is3 = b1 & b0
  393. if c0<=c1:
  394. if bit == 0xaaaaaaaa:
  395. # print c0<c1,hex(bit)
  396. r0,g0,b0 = rgb(c0)
  397. r1,g1,b1 = rgb(c1)
  398. r = (r0 + r1) / 2
  399. g = (g0 + g1) / 2
  400. b = (b0 + b1) / 2
  401. # r,g,b = (255,0,255)
  402. c0 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)
  403. c1 = c0
  404. bit = 0
  405. else:
  406. if 0:
  407. for i in range(0, 32, 2):
  408. fld = (3 & (bit >> i))
  409. if 3 == fld:
  410. print c0, c1, hex(bit), i
  411. assert 0
  412. # Map as follows:
  413. # 0 -> 0
  414. # 1 -> 3
  415. # 2 -> 1
  416. bit = (is1 * 3) + (is2 * 1)
  417. assert is3 == 0
  418. else:
  419. # 0 -> 0
  420. # 1 -> 3
  421. # 2 -> 1
  422. # 3 -> 2
  423. bit = (is1 * 3) + (is2 * 1) + (is3 * 2)
  424. if 0:
  425. c0 = 63 << 5 # green
  426. c1 = 31 << 11 # red
  427. bit = 0x0f0f0f0f
  428. c0s.append(c0)
  429. c1s.append(c1)
  430. bits.append(bit)
  431. c0s = numpy.array(c0s, numpy.uint16)
  432. c1s = numpy.array(c1s, numpy.uint16)
  433. bits = numpy.array(bits, numpy.uint32)
  434. bits0 = morton1(bits)
  435. bits1 = morton1(bits >> 1)
  436. if 1:
  437. def im44(v):
  438. im = Image.new("1", (4,4))
  439. pix = im.load()
  440. for i in range(4):
  441. for j in range(4):
  442. if v & (1 << (4 * i + j)):
  443. pix[j,i] = 255
  444. return im
  445. ims = [im44(i) for i in range(65536)]
  446. b0im = Image.new("1", (480, 272))
  447. b1im = Image.new("1", (480, 272))
  448. xys = [(x,y) for y in range(0, 272, 4) for x in range(0, 480, 4)]
  449. for i,(x,y) in enumerate(xys):
  450. b0im.paste(ims[bits0[i]], (x, y))
  451. b1im.paste(ims[bits1[i]], (x, y))
  452. class MockImage:
  453. def __init__(self, s, size):
  454. self.imgdata = s
  455. self.size = size
  456. self.load_handle("BACKGROUND_COLOR", [MockImage(c0s, sz), MockImage(c1s, sz)], gd2.RGB565, scale = 4)
  457. self.load_handle("BACKGROUND_BITS", [b0im, b1im], gd2.L1)
  458. """
  459. def load_sample(self, name, filename):
  460. f = wave.open(filename, "rb")
  461. if f.getnchannels() != 1:
  462. print "Sorry - .wav file must be mono"
  463. sys.exit(1)
  464. if f.getsampwidth() != 2:
  465. print "Sorry - .wav file must be 16-bit"
  466. sys.exit(1)
  467. freq = f.getframerate()
  468. pcm16 = f.readframes(f.getnframes())
  469. (adpcm, _) = audioop.lin2adpcm(pcm16, f.getsampwidth(), (0,0))
  470. adpcm = adpcm[:len(adpcm) & ~7]
  471. da = array.array('B', [((ord(c) >> 4) | ((15 & ord(c)) << 4)) for c in adpcm])
  472. self.align(8)
  473. self.add(name, da.tostring())
  474. self.define(name + "_LENGTH", len(da))
  475. self.define(name + "_FREQ", freq)
  476. header = None
  477. header_intro = ""
  478. def make(self):
  479. if self.header is None:
  480. name = self.__class__.__name__.lower() + "_assets.h"
  481. else:
  482. name = self.header
  483. self.name = name
  484. self.addall()
  485. if len(self.alldata) > self.maxram:
  486. print "Error: The data (%d bytes) is larger the the %s RAM (%d)" % (len(self.alldata), self.device, self.maxram)
  487. sys.exit(1)
  488. self.defines.append((self.prefix + "ASSETS_END", ul(len(self.alldata))))
  489. self.cmd_inflate(0)
  490. calldata = zlib.compress(self.alldata, 9)
  491. print 'Assets report'
  492. print '-------------'
  493. print 'Header file: %s' % self.header
  494. print '%s RAM used: %d' % (self.device, len(self.alldata))
  495. if not self.asset_file:
  496. print 'Flash used: %d' % len(calldata)
  497. else:
  498. print 'Output file: %s' % self.asset_file
  499. print 'File size: %d' % len(calldata)
  500. commandblock = self.commands + calldata
  501. hh = open(name, "w")
  502. hh.write(self.header_intro)
  503. for (nm,v) in self.defines:
  504. print >>hh, "#define %s %s" % (nm, v)
  505. p = self.prefix
  506. if self.asset_file is None:
  507. print >>hh, "static const PROGMEM uint8_t %s__assets[%d] = {" % (p, len(commandblock))
  508. print >>hh, textwrap.fill(", ".join(["%d" % ord(c) for c in commandblock]))
  509. print >>hh, "};"
  510. print >>hh, "#define %sLOAD_ASSETS() (GD.copy(%s__assets, sizeof(%s__assets)), GD.loadptr = %sASSETS_END)" % (p, p, p, p)
  511. else:
  512. open(self.asset_file, "wb").write(commandblock)
  513. print >>hh, '#define %sLOAD_ASSETS() (GD.safeload("%s"), GD.loadptr = %sASSETS_END)' % (p, self.asset_file, p)
  514. print >>hh
  515. for i in self.inits:
  516. print >>hh, i
  517. self.dump_bitmaps(hh)
  518. self.extras(hh)
  519. def dump_bitmaps(self, hh):
  520. hh.write("struct {\n")
  521. hh.write("".join([" Bitmap %s;\n" % bm[0] for bm in self.bitmaps]))
  522. hh.write("} bitmaps = {\n")
  523. fmt = " /* %16s */ {{%3d, %3d}, {%3d, %3d}, %#8xUL, %2d, %2d}"
  524. hh.write(",\n".join([fmt % bm for bm in self.bitmaps]))
  525. hh.write("\n};\n")
  526. def addall(self):
  527. pass
  528. def extras(self, hh):
  529. pass
  530. class ForthAssetBin(AssetBin):
  531. def make(self):
  532. if self.header is None:
  533. name = self.__class__.__name__.lower() + "_assets.fs"
  534. else:
  535. name = self.header
  536. self.name = name
  537. self.addall()
  538. if len(self.alldata) > self.maxram:
  539. print "Error: The data (%d bytes) is larger the the GD2 RAM" % len(self.alldata)
  540. sys.exit(1)
  541. self.defines.append((self.prefix + "ASSETS_END", ul(len(self.alldata))))
  542. self.cmd_inflate(0)
  543. calldata = zlib.compress(self.alldata)
  544. print 'Assets report'
  545. print '-------------'
  546. print 'Header file: %s' % self.header
  547. print 'GD2 RAM used: %d' % len(self.alldata)
  548. if not self.asset_file:
  549. print 'Flash used: %d' % len(calldata)
  550. else:
  551. print 'Output file: %s' % self.asset_file
  552. print 'File size: %d' % len(calldata)
  553. commandblock = self.commands + calldata
  554. commandblock += chr(0) * ((-len(commandblock)) & 3)
  555. commandblock32 = array.array('I', commandblock)
  556. hh = open(name, "w")
  557. print >>hh, "base @"
  558. print >>hh, "hex"
  559. if self.asset_file is None:
  560. print >>hh, textwrap.fill(" ".join(["%08x GD.c" % c for c in commandblock32]))
  561. else:
  562. open(self.asset_file, "wb").write(commandblock)
  563. print >>hh, "decimal"
  564. for (nm,v) in self.defines:
  565. print >>hh, "%-8s constant %s" % (str(v).replace('UL', ''), nm)
  566. print >>hh, "base !"
  567. self.extras(hh)