prep.py 24 KB

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