Browse Source

add support for 810 opcodes, tiled map loader

James Bowman 6 years ago
parent
commit
9e09958343
2 changed files with 134 additions and 12 deletions
  1. 25 2
      gameduino2/base.py
  2. 109 10
      gameduino2/prep.py

+ 25 - 2
gameduino2/base.py

@@ -258,14 +258,37 @@ class GD2:
     def cmd_setrotate(self, o):
         self.c(struct.pack("II", 0xffffff36, o))
 
+    #
+    # The new 810 opcodes
+    #
+
+    def VertexFormat(self, frac):
+        self.c4((39 << 24) | (((frac) & 7) << 0))
+
+    def BitmapLayoutH(self, linestride,height):
+        self.c4((40 << 24) | (((linestride) & 3) << 2) | (((height) & 3) << 0))
+
+    def BitmapSizeH(self, width,height):
+        self.c4((41 << 24) | (((width) & 3) << 2) | (((height) & 3) << 0))
+
+    def PaletteSource(self, addr):
+        self.c4((42 << 24) | (((addr) & 4194303) << 0))
+
+    def VertexTranslateX(self, x):
+        self.c4((43 << 24) | (((x) & 131071) << 0))
+
+    def VertexTranslateY(self, y):
+        self.c4((44 << 24) | (((y) & 131071) << 0))
+
+    def Nop(self):
+        self.c4((45 << 24))
+
     # def cmd_snapshot2(self, 
     # def cmd_setbase(self, 
     # def cmd_mediafifo(self, 
     # def cmd_playvideo(self, 
     # def cmd_setfont2(self, 
     # def cmd_setscratch(self, 
-    # def cmd_int_ramshared(self, 
-    # def cmd_int_swloadimage(self, 
 
     def cmd_romfont(self, *a):
         self.c(struct.pack("III", 0xffffff3f, *a))

+ 109 - 10
gameduino2/prep.py

@@ -7,12 +7,11 @@ import textwrap
 import wave
 import audioop
 
-import Image
-import ImageFont
-import ImageDraw
+from PIL import Image, ImageFont, ImageDraw, ImageChops
 
 import gameduino2 as gd2
 import gameduino2.convert
+import gameduino2.tmxreader
 from gameduino2.imbytes import imbytes
 
 def stretch(im):
@@ -134,6 +133,22 @@ def preview(np, fmt, size, data):
 
 import gameduino2.base
 
+def pma(im):
+    im = im.convert("RGBA")
+    (r,g,b,a) = im.split()
+    (r,g,b) = [ImageChops.multiply(a, c) for c in (r,g,b)]
+    return Image.merge("RGBA", (r, g, b, a))
+
+class EVE(gameduino2.base.GD2):
+    def __init__(self):
+        self.d = ""
+
+    def c(self, s):
+        self.d += s
+
+def chunker(seq, size):
+    return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
+
 class AssetBin(gameduino2.base.GD2):
 
     asset_file = None
@@ -194,15 +209,15 @@ class AssetBin(gameduino2.base.GD2):
 
         (w, h) = images[0].size
 
-        self.define("%s_HANDLE" % name, self.handle)
-        name = self.prefix + name
-        self.defines.append(("%s_WIDTH" % name, w))
-        self.defines.append(("%s_HEIGHT" % name, h))
-        self.defines.append(("%s_CELLS" % name, len(images)))
-
         self.align(2)
 
-        self.bitmaps.append((name.lower(), w, h, w / 2, h / 2, len(self.alldata), fmt, self.handle))
+        if name is not None:
+            self.define("%s_HANDLE" % name, self.handle)
+            name = self.prefix + name
+            self.defines.append(("%s_WIDTH" % name, w))
+            self.defines.append(("%s_HEIGHT" % name, h))
+            self.defines.append(("%s_CELLS" % name, len(images)))
+            self.bitmaps.append((name.lower(), w, h, w / 2, h / 2, len(self.alldata), fmt, self.handle))
 
         self.BitmapHandle(self.handle);
         self.BitmapSource(len(self.alldata));
@@ -305,6 +320,90 @@ class AssetBin(gameduino2.base.GD2):
         widths = ([0] * 32) + [w for (w, _) in sizes]
         self.load_font(name, ims, widths, format)
 
+    def load_tiles(self, name, file_name, scale = 1.0):
+        world_map = gameduino2.tmxreader.TileMapParser().parse_decode(file_name)
+
+        # print("loaded map:", world_map.map_file_name)
+
+        x_pixels = world_map.pixel_width
+        y_pixels = world_map.pixel_height
+        # print("map size in pixels:", x_pixels, y_pixels)
+
+        # print("tile size used:",  world_map.tilewidth, world_map.tileheight)
+        # print("tiles used:", world_map.width, world_map.height)
+        # print("found '", len(world_map.layers), "' layers on this map")
+
+        layers = [l for l in world_map.layers if hasattr(l, 'decoded_content')]
+        # print layers
+
+        w,h = (world_map.width, world_map.height)
+
+        ts = world_map.tile_sets[0]
+        tw = int(ts.tilewidth)
+        th = int(ts.tileheight)
+        if scale is not None:
+            stw,sth = (int(tw * scale), int(th * scale))
+        else:
+            stw,sth = tw,th
+
+        used = set()
+        for layer in layers:
+            used |= set(layer.decoded_content)
+        used = sorted(used - set([0]))
+
+        def reindex(i):
+            if i == 0:
+                return None
+            else:
+                return used.index(i)
+
+        def fetchtile(l, i, j):
+            if (i < world_map.width) and (j < world_map.height):
+                return reindex(l.decoded_content[i + (j * world_map.width)])
+            else:
+                return None
+
+        eve = EVE()
+        # print world_map.width * world_map.height * 4
+
+        for j in range(0, world_map.height, 4):
+            for i in range(0, world_map.width, 4):
+                for layer in layers:
+                    for y in range(4):
+                        for x in range(4):
+                            t = fetchtile(layer, i + x, j + y)
+                            if t is not None:
+                                eve.Vertex2ii(stw * x, sth * y, t / 128, t % 128)
+                            else:
+                                eve.Nop()
+        stride = ((w + 3) / 4)
+        self.add(name, struct.pack("6H", w * stw, h * sth, stw * 4, sth * 4, stride, len(layers)) + eve.d)
+        self.tile_files = world_map.tile_sets[0].images[0].source
+        # print 'Size of tiles: %d (compressed %d)' % (len(eve.d), len(zlib.compress(eve.d)))
+        # print 'Tile size', (tw, th)
+        im = pma(Image.open(self.tile_files))
+        def extract(i):
+            w = im.size[0] / 72
+            x = 72 * (i % w)
+            y = 72 * (i / w)
+            return im.crop((x + 0, y + 0, x + 70, y + 70)).resize((32, 32))
+        def extract(i):
+            if hasattr(ts, 'columns'):
+                w = int(ts.columns)
+            else:
+                w = im.size[0] / tw
+            x = ts.margin + (tw + ts.spacing) * (i % w)
+            y = ts.margin + (th + ts.spacing) * (i / w)
+            r = im.crop((x + 0, y + 0, x + tw, y + th))
+            if scale:
+                r = r.resize((stw, sth), Image.ANTIALIAS)
+            return r
+        for i,g128 in enumerate(chunker(used, 128)):
+            # print 'g128', len(g128), g128
+            for j,t in enumerate(g128):
+                extract(t - 1).save("xx_%d_%d.png" % (i, j))
+            self.load_handle(None, [extract(t - 1) for t in g128], gd2.ARGB4, dither=0)
+
     """
     def dxt1(self, imagefile):
         import numpy