diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | chickadee/graphics/tile-map.scm | 926 | ||||
-rw-r--r-- | chickadee/graphics/tiled.scm | 500 | ||||
-rw-r--r-- | doc/api.texi | 25 | ||||
-rw-r--r-- | examples/images/serene-village.png | bin | 0 -> 122591 bytes | |||
-rw-r--r-- | examples/images/tiles.png | bin | 100846 -> 0 bytes | |||
-rw-r--r-- | examples/maps/example.tmx | 348 | ||||
-rw-r--r-- | examples/maps/serene-village.tsx | 84 | ||||
-rw-r--r-- | examples/tile-map.scm (renamed from examples/tiled.scm) | 59 |
9 files changed, 1336 insertions, 608 deletions
diff --git a/Makefile.am b/Makefile.am index d397f3a..a853edd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -77,7 +77,7 @@ SOURCES = \ chickadee/graphics/sprite.scm \ chickadee/graphics/9-patch.scm \ chickadee/graphics/font.scm \ - chickadee/graphics/tiled.scm \ + chickadee/graphics/tile-map.scm \ chickadee/graphics/particles.scm \ chickadee/graphics/phong.scm \ chickadee/graphics/pbr.scm \ diff --git a/chickadee/graphics/tile-map.scm b/chickadee/graphics/tile-map.scm new file mode 100644 index 0000000..8984691 --- /dev/null +++ b/chickadee/graphics/tile-map.scm @@ -0,0 +1,926 @@ +;;; Chickadee Game Toolkit +;;; Copyright © 2018, 2020, 2021 David Thompson <dthompson2@worcester.edu> +;;; +;;; Chickadee is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published +;;; by the Free Software Foundation, either version 3 of the License, +;;; or (at your option) any later version. +;;; +;;; Chickadee is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program. If not, see +;;; <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; Tile map renderer and Tiled map format loader. +;; +;;; Code: + +(define-module (chickadee graphics tile-map) + #:use-module (chickadee) + #:use-module (chickadee math matrix) + #:use-module (chickadee math rect) + #:use-module (chickadee math vector) + #:use-module (chickadee graphics blend) + #:use-module (chickadee graphics buffer) + #:use-module (chickadee graphics color) + #:use-module (chickadee graphics engine) + #:use-module (chickadee graphics shader) + #:use-module (chickadee graphics sprite) + #:use-module (chickadee graphics texture) + #:use-module (chickadee graphics viewport) + #:use-module (chickadee utils) + #:use-module (ice-9 match) + #:use-module ((rnrs base) #:select (mod)) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-43) + #:use-module (sxml simple) + #:use-module (sxml xpath) + #:export (animation-frame? + animation-frame-tile + animation-frame-duration + + animation? + animation-frames + animation-duration + + tile? + tile-id + tile-texture + tile-animation + tile-properties + + make-tileset + tileset? + tileset-name + tileset-first-gid + tileset-size + tileset-tile-width + tileset-tile-height + tileset-rows + tileset-columns + tileset-properties + + make-map-tile + map-tile? + map-tile-ref + map-tile-flipped-horizontally? + map-tile-flipped-vertically? + map-tile-flipped-diagonally? + + make-tile-layer + tile-layer? + tile-layer-name + tile-layer-width + tile-layer-height + tile-layer-chunk-size + tile-layer-properties + tile-layer-ref + tile-layer-set! + + object-layer? + object-layer-name + object-layer-objects + object-layer-properties + + polygon? + polygon-points + + map-object? + map-object-id + map-object-name + map-object-type + map-object-shape + map-object-properties + + make-tile-map + tile-map? + tile-map-orientation + tile-map-width + tile-map-height + tile-map-tile-width + tile-map-tile-height + tile-map-tilesets + tile-map-layers + tile-map-properties + tile-map-rect + tile-map-layer-ref + point->tile + load-tile-map + draw-tile-map + draw-tile-map*)) + + +;;; +;;; Tileset +;;; + +(define-record-type <animation-frame> + (make-animation-frame texture duration) + animation-frame? + (texture animation-frame-texture) + (duration animation-frame-duration)) + +(define-record-type <animation> + (%make-animation frames duration) + animation? + (frames animation-frames) + (duration animation-duration)) + +(define (make-animation atlas first-gid frame-spec) + (let ((frames (map (match-lambda + ((id duration) + (let ((texture (texture-atlas-ref atlas + (- id first-gid)))) + (make-animation-frame texture duration)))) + frame-spec))) + (%make-animation (list->vector frames) + (fold (lambda (frame memo) + (+ (animation-frame-duration frame) memo)) + 0 frames)))) + +(define (animation-frame-for-time animation time) + (let* ((time (mod time (animation-duration animation))) + (frames (animation-frames animation))) + (let loop ((i 0) + (t 0)) + (let* ((frame (vector-ref frames i)) + (d (animation-frame-duration frame))) + (if (< time (+ t d)) + frame + (loop (+ i 1) (+ t d))))))) + +(define-record-type <tile> + (make-tile id texture animation properties) + tile? + (id tile-id) + (texture tile-texture) + (animation tile-animation) + (properties tile-properties)) + +(define (animated-tile? tile) + (animation? (tile-animation tile))) + +(define (tile-frame-for-time tile time) + (let ((animation (tile-animation tile))) + (and animation (animation-frame-for-time animation time)))) + +(define-record-type <tileset> + (%make-tileset name first-gid tile-width tile-height + rows columns atlas tiles properties) + tileset? + (name tileset-name) + (first-gid tileset-first-gid) + (tile-width tileset-tile-width) + (tile-height tileset-tile-height) + (rows tileset-rows) + (columns tileset-columns) + (atlas tileset-atlas) + (tiles tileset-tiles) + (properties tileset-properties)) + +(define* (make-tileset texture tile-width tile-height #:key + (first-gid 1) (margin 0) (spacing 0) + (name "anonymous") (properties '()) + (custom-tiles '())) + (call-with-values (lambda () + (texture-tileset-dimensions texture tile-width tile-height + #:margin margin + #:spacing spacing)) + (lambda (columns rows) + (let* ((atlas (split-texture texture tile-width tile-height + #:margin margin + #:spacing spacing)) + (tiles (make-vector (texture-atlas-size atlas)))) + (for-range ((i (vector-length tiles))) + (let* ((id (+ first-gid i)) + (custom (or (assv-ref custom-tiles id) '())) + (animation (assq-ref custom 'animation)) + (properties (assq-ref custom 'properties)) + (tile (make-tile id (texture-atlas-ref atlas i) + (and animation (make-animation atlas first-gid animation)) + (or properties '())))) + (vector-set! tiles i tile))) + (%make-tileset name first-gid tile-width tile-height rows columns + atlas tiles properties))))) + +(define (tileset-size tileset) + (texture-atlas-size (tileset-atlas tileset))) + +(define (tileset-ref tileset i) + (vector-ref (tileset-tiles tileset) (- i (tileset-first-gid tileset)))) + + +;;; +;;; Object Layer +;;; + +(define-record-type <object-layer> + (%make-object-layer name objects properties) + object-layer? + (name object-layer-name) + (objects object-layer-objects) + (properties object-layer-properties)) + +(define-record-type <polygon> + (make-polygon points) + polygon? + (points polygon-points)) + +(define-record-type <map-object> + (%make-map-object id name type shape properties) + map-object? + (id map-object-id) + (name map-object-name) + (type map-object-type) + (shape map-object-shape) + (properties map-object-properties)) + + +;;; +;;; Chunk +;;; + +(define-record-type <map-tile> + (%make-map-tile tile flipped-horizontally? flipped-vertically? + flipped-diagonally?) + map-tile? + (tile map-tile-ref) + (flipped-horizontally? map-tile-flipped-horizontally?) + (flipped-vertically? map-tile-flipped-vertically?) + (flipped-diagonally? map-tile-flipped-diagonally?)) + +(define* (make-map-tile tile #:key flipped-horizontally? + flipped-vertically? flipped-diagonally?) + (%make-map-tile tile flipped-horizontally? flipped-vertically? + flipped-diagonally?)) + +(define-record-type <chunk> + (%make-chunk size tile-x tile-y tile-width tile-height anim-tiles + anim-frames tiles rebuild-geometry? geometry) + chunk? + (size chunk-size) + (tile-x chunk-tile-x) + (tile-y chunk-tile-y) + (tile-width chunk-tile-width) + (tile-height chunk-tile-height) + (anim-tiles chunk-anim-tiles) + (anim-frames chunk-anim-frames) + (tiles chunk-tiles) + (rebuild-geometry? chunk-rebuild-geometry? set-chunk-rebuild-geometry!) + (geometry chunk-geometry)) + +(define %default-chunk-size 30) + +(define-geometry-type <chunk-vertex> + chunk-vertex-ref + chunk-vertex-set! + chunk-vertex-append! + (position vec2) + (texture vec2)) + +(define (make-chunk size tile-x tile-y tile-width tile-height) + (let ((tiles (make-vector size))) + (for-range ((y size)) + (let ((row (make-vector size))) + (for-range ((x size)) + (vector-set! row x #f)) + (vector-set! tiles y row))) + (%make-chunk size tile-x tile-y tile-width tile-height + (make-hash-table) (make-hash-table) tiles #t + (make-hash-table)))) + +(define (chunk-anim-decrement chunk tile) + (let* ((t (chunk-anim-tiles chunk)) + (n (hashq-ref t tile 0))) + (cond + ((= n 0) + #f) + ((= n 1) + (hashq-remove! t tile) + (hashq-remove! (chunk-anim-frames chunk) tile)) + (else + (hashq-set! t tile (- n 1)))))) + +(define (chunk-anim-increment chunk tile) + (let ((t (chunk-anim-tiles chunk))) + (hashq-set! t tile (+ (or (hashq-ref t tile) 0) 1)))) + +(define (chunk-bounds-check chunk x y) + (let ((n (chunk-size chunk))) + (unless (and (>= x 0) (>= y 0) (< x n) (< y n)) + (error "chunk index out of bounds" x y)))) + +(define (chunk-ref chunk x y) + (chunk-bounds-check chunk x y) + (vector-ref (vector-ref (chunk-tiles chunk) y) x)) + +(define (chunk-ensure-geometry chunk texture) + (let ((chunk-size (chunk-size chunk)) + (geometry-table (chunk-geometry chunk))) + (unless (hashq-ref geometry-table texture) + (let ((g (make-geometry <chunk-vertex> + (* chunk-size chunk-size 4) + #:index-capacity + (* chunk-size chunk-size 6)))) + (hashq-set! geometry-table texture g))))) + +(define (chunk-set! chunk x y tile) + (let ((tiles (chunk-tiles chunk))) + (chunk-bounds-check chunk x y) + (let ((existing-tile (chunk-ref chunk x y))) + (when (and existing-tile (animated-tile? (map-tile-ref existing-tile))) + (chunk-anim-decrement chunk (map-tile-ref existing-tile)))) + (vector-set! (vector-ref tiles y) x tile) + (when tile + (let* ((tile* (map-tile-ref tile)) + (texture (texture-parent (tile-texture tile*)))) + (when (animated-tile? tile*) + (chunk-anim-increment chunk tile*)) + (chunk-ensure-geometry chunk texture))) + (set-chunk-rebuild-geometry! chunk #t))) + +(define (chunk-rebuild-geometry! chunk) + (let* ((anim-frames (chunk-anim-frames chunk)) + (t (chunk-geometry chunk)) + (n (chunk-size chunk)) + (tw (exact->inexact (chunk-tile-width chunk))) + (th (exact->inexact (chunk-tile-height chunk))) + (x0 (* (chunk-tile-x chunk) tw)) + (y0 (* (chunk-tile-y chunk) th))) + (hash-for-each (lambda (texture geometry) + (geometry-begin! geometry)) + t) + (for-range ((x n) (y n)) + (let ((tile (chunk-ref chunk x y))) + (when tile + (let* ((tile* (map-tile-ref tile)) + (texture (if (animated-tile? tile*) + (animation-frame-texture + (hashq-ref anim-frames tile*)) + (tile-texture tile*))) + (geometry (hashq-ref t (texture-parent texture))) + (vertex-offset (geometry-vertex-count geometry <chunk-vertex>)) + (x1 (+ x0 (* x tw))) + (y1 (+ y0 (* y th))) + (x2 (+ x1 tw)) + (y2 (+ y1 th)) + (texcoords (texture-gl-tex-rect texture)) + (s1 (rect-left texcoords)) + (t1 (rect-bottom texcoords)) + (s2 (rect-right texcoords)) + (t2 (rect-top texcoords)) + (flip-h? (map-tile-flipped-horizontally? tile)) + (flip-v? (map-tile-flipped-vertically? tile)) + (flip-d? (map-tile-flipped-diagonally? tile)) + (as (cond + ((and flip-d? flip-h?) s2) + ((and flip-d? flip-v?) s1) + (flip-h? s2) + (else s1))) + (at (cond + ((and flip-d? flip-h?) t1) + ((and flip-d? flip-v?) t2) + (flip-v? t2) + (else t1))) + (bs (cond + ((and flip-d? flip-h?) s2) + ((and flip-d? flip-v?) s1) + (flip-h? s1) + (else s2))) + (bt (cond + ((and flip-d? flip-h?) t2) + ((and flip-d? flip-v?) t1) + (flip-v? t2) + (else t1))) + (cs (cond + ((and flip-d? flip-h?) s1) + ((and flip-d? flip-v?) s2) + (flip-h? s1) + (else s2))) + (ct (cond + ((and flip-d? flip-h?) t2) + ((and flip-d? flip-v?) t1) + (flip-v? t1) + (else t2))) + (ds (cond + ((and flip-d? flip-h?) s1) + ((and flip-d? flip-v?) s2) + (flip-h? s2) + (else s1))) + (dt (cond + ((and flip-d? flip-h?) t1) + ((and flip-d? flip-v?) t2) + (flip-v? t1) + (else t2)))) + (chunk-vertex-append! geometry + (x1 y1 as at) + (x2 y1 bs bt) + (x2 y2 cs ct) + (x1 y2 ds dt)) + (geometry-index-append! geometry + vertex-offset + (+ vertex-offset 3) + (+ vertex-offset 2) + vertex-offset + (+ vertex-offset 2) + (+ vertex-offset 1)))))) + (hash-for-each (lambda (texture geometry) + (geometry-end! geometry)) + t))) + +(define-graphics-variable tile-map-chunk-shader + (strings->shader + " +#ifdef GLSL330 +layout (location = 0) in vec2 position; +layout (location = 1) in vec2 tex; +#elif defined(GLSL130) +in vec2 position; +in vec2 tex; +#elif defined(GLSL120) +attribute vec2 position; +attribute vec2 tex; +#endif +#ifdef GLSL120 +varying vec2 fragTex; +#else +out vec2 fragTex; +#endif +uniform mat4 mvp; + +void main(void) { + fragTex = tex; + gl_Position = mvp * vec4(position.xy, 0.0, 1.0); +} +" + " +#ifdef GLSL120 +varying vec2 fragTex; +#else +in vec2 fragTex; +#endif +#ifdef GLSL330 +out vec4 fragColor; +#endif +uniform sampler2D colorTexture; +uniform vec4 tint; + +void main (void) { +#ifdef GLSL330 + fragColor = texture(colorTexture, fragTex) * tint; +#else + gl_FragColor = texture2D(colorTexture, fragTex) * tint; +#endif +} +")) + +(define (draw-chunk-geometry texture geometry matrix tint) + (with-graphics-state ((g:texture-0 texture)) + (shader-apply* (graphics-variable-ref tile-map-chunk-shader) + (geometry-vertex-array geometry) + 0 + (geometry-index-count geometry) + #:tint tint + #:mvp matrix))) + +(define (draw-chunk chunk matrix blend-mode tint time) + (let ((anim-tiles (chunk-anim-tiles chunk)) + (anim-frames (chunk-anim-frames chunk))) + (hash-for-each (lambda (tile count) + (let ((old-frame (hashq-ref anim-frames tile)) + (new-frame (tile-frame-for-time tile time))) + (unless (eq? old-frame new-frame) + (hashq-set! anim-frames tile new-frame) + (set-chunk-rebuild-geometry! chunk #t)))) + anim-tiles)) + (when (chunk-rebuild-geometry? chunk) + (chunk-rebuild-geometry! chunk) + (set-chunk-rebuild-geometry! chunk #f)) + (with-graphics-state ((g:blend-mode blend-mode)) + (hash-for-each (lambda (texture geometry) + (draw-chunk-geometry texture geometry matrix tint)) + (chunk-geometry chunk)))) + + +;;; +;;; Tile Layer +;;; + +(define-record-type <tile-layer> + (%make-tile-layer name width height properties chunk-size chunks) + tile-layer? + (name tile-layer-name) + (width tile-layer-width) + (height tile-layer-height) + (properties tile-layer-properties) + (chunk-size tile-layer-chunk-size) + (chunks tile-layer-chunks)) + +(define* (make-tile-layer width height tile-width tile-height #:key + (name "anonymous") + (properties '()) + (chunk-size %default-chunk-size)) + (let* ((h (ceiling (/ height chunk-size))) + (chunks (make-vector h))) + (for-range ((y h)) + (let* ((w (ceiling (/ width chunk-size))) + (row (make-vector w))) + (for-range ((x w)) + (vector-set! row x (make-chunk chunk-size + (* x chunk-size) + (* y chunk-size) + tile-width tile-height))) + (vector-set! chunks y row))) + (%make-tile-layer name width height properties chunk-size chunks))) + +(define (tile-layer-bounds-check layer x y) + (unless (and (>= x 0) (>= y 0) + (< x (tile-layer-width layer)) + (< y (tile-layer-height layer))) + (error "tile layer coordinates out of bounds" layer x y))) + +(define (call-with-chunk layer x y proc) + (tile-layer-bounds-check layer x y) + (let ((n (tile-layer-chunk-size layer))) + (proc (vector-ref (vector-ref (tile-layer-chunks layer) + (floor (/ y n))) + (floor (/ x n))) + (modulo x n) + (modulo y n)))) + +(define (tile-layer-ref! layer x y) + (call-with-chunk layer x y + (lambda (chunk cx cy) + (chunk-ref chunk cx cy)))) + +(define (tile-layer-set! layer x y tile) + (call-with-chunk layer x y + (lambda (chunk cx cy) + (chunk-set! chunk cx cy tile)))) + +(define (draw-tile-layer layer matrix x1 y1 x2 y2 blend-mode tint time) + (let ((width (tile-layer-width layer)) + (height (tile-layer-height layer)) + (chunk-size (tile-layer-chunk-size layer)) + (chunks (tile-layer-chunks layer))) + ;; Render only the visible chunks. + (for-range ((x (ceiling (/ x2 chunk-size)) + (floor (/ x1 chunk-size))) + (y (ceiling (/ y2 chunk-size)) + (floor (/ y1 chunk-size)))) + (draw-chunk (vector-ref (vector-ref chunks y) x) + matrix blend-mode tint time)))) + + +;;; +;;; Tile Map +;;; + +(define-record-type <tile-map> + (%make-tile-map orientation width height tile-width tile-height + tilesets layers properties) + tile-map? + (orientation tile-map-orientation) + (width tile-map-width) + (height tile-map-height) + (tile-width tile-map-tile-width) + (tile-height tile-map-tile-height) + (tilesets tile-map-tilesets) + (layers tile-map-layers) + (properties tile-map-properties)) + +(define* (make-tile-map width height tile-width tile-height #:key + (orientation 'orthogonal) (tilesets '()) + (layers '()) (properties '())) + "Make a tile map that is WIDTH x HEIGHT tiles in size and each tile +is TILE-WIDTH x TILE-HEIGHT pixels in size. TILESETS is a list of +tilesets to be associated with the map. LAYERS is a list of object +and/or tile layers, sorted from bottom to top. PROPERTIES is an alist +of arbitrary custom data to associate with the map. Currently, only +the default ORIENTATION value of 'orthogonal' is supported." + (unless (eq? orientation 'orthogonal) + (error "unsupport tile map orientation" orientation)) + (%make-tile-map orientation width height tile-width tile-height + tilesets (list->vector layers) properties)) + +(define (tile-map-layer-ref tile-map name) + "Return the map layer named NAME." + (define (layer-name layer) + (if (tile-layer? layer) + (tile-layer-name layer) + (object-layer-name layer))) + (let ((layers (tile-map-layers tile-map))) + (let loop ((i 0)) + (cond + ((= i (vector-length layers)) + #f) + ((string=? name (layer-name (vector-ref layers i))) + (vector-ref layers i)) + (else + (loop (+ i 1))))))) + +(define (point->tile tile-map x y) + "Translate the pixel coordinates (X, Y) into tile coordinates." + (values (inexact->exact (floor (/ x (tile-map-tile-width tile-map)))) + (inexact->exact (floor (/ y (tile-map-tile-height tile-map)))))) + +(define* (load-tile-map file-name #:key (chunk-size %default-chunk-size)) + "Load the Tiled TMX formatted map in FILE-NAME." + (define map-directory + (if (absolute-file-name? file-name) + (dirname file-name) + (string-append (getcwd) "/" (dirname file-name)))) + (define (scope file-name) + (string-append map-directory "/" file-name)) + (define* (attr node name #:optional (parse identity)) + (let ((result ((sxpath `(@ ,name *text*)) node))) + (if (null? result) + #f + (parse (car result))))) + (define (parse-color-channel s start) + (/ (string->number (substring s start (+ start 2)) 16) 255.0)) + (define (parse-property node) + (let ((name (attr node 'name string->symbol)) + (type (or (attr node 'type string->symbol) 'string)) + (value (attr node 'value))) + (cons name + (match type + ((or 'string 'file) value) + ('bool (not (string=? value "false"))) + ((or 'int 'float) (string->number value)) + ('color + (make-color (parse-color-channel value 3) + (parse-color-channel value 5) + (parse-color-channel value 7) + (parse-color-channel value 1))) + (_ (error "unsupported property type" type)))))) + (define (parse-image node) + (let ((source (attr node 'source)) + (trans (attr node 'trans))) + (load-image (scope source) + #:transparent-color (and trans (string->color trans))))) + (define (invert-tile-id id first-gid rows columns) + (let ((id* (- id first-gid))) + (+ (* (- rows (floor (/ id* columns)) 1) + columns) + (modulo id* columns) + first-gid))) + (define (parse-frame node first-gid rows columns) + (let ((tile-id (attr node 'tileid string->number)) + (duration (attr node 'duration string->number))) + (list (+ first-gid (invert-tile-id tile-id 0 rows columns)) + (/ duration 1000.0)))) + (define (parse-tiles nodes first-gid rows columns) + (let ((frames (sxpath '(animation frame))) + (properties (sxpath '(properties property)))) + (fold (lambda (node memo) + (let ((id (+ first-gid + (invert-tile-id (attr node 'id string->number) + 0 rows columns)))) + (cons `(,id . ((animation . ,(map (lambda (f) + (parse-frame f first-gid + rows columns)) + (frames node))) + (properties . ,(map parse-property + (properties node))))) + memo))) + '() + nodes))) + (define (first-gid node) + (attr node 'firstgid string->number)) + (define (parse-tileset node first-gid) + (let* ((name (attr node 'name)) + (tile-width (attr node 'tilewidth string->number)) + (tile-height (attr node 'tileheight string->number)) + (margin (or (attr node 'margin string->number) 0)) + (spacing (or (attr node 'spacing string->number) 0)) + (texture (parse-image ((sxpath '(image)) node))) + (tiles (call-with-values + (lambda () + (texture-tileset-dimensions texture + tile-width + tile-height + #:margin margin + #:spacing spacing)) + (lambda (columns rows) + (parse-tiles ((sxpath '(tile)) node) first-gid rows columns)))) + (properties (map parse-property + ((sxpath '(properties property)) node)))) + (make-tileset texture tile-width tile-height + #:margin margin + #:spacing spacing + #:name name + #:first-gid first-gid + #:properties properties + #:custom-tiles tiles))) + (define (parse-external-tileset node) + (let* ((first-gid (attr node 'firstgid string->number)) + (source (scope (attr node 'source))) + (tree (call-with-input-file source xml->sxml))) + (parse-tileset (car ((sxpath '(tileset)) tree)) first-gid))) + (define (parse-tileset* node) + (if (attr node 'source) + (parse-external-tileset node) + (parse-tileset node (first-gid node)))) + (define (tile-gid->map-tile raw-gid tilesets x y tile-width tile-height) + ;; The top 3 bits of the tile gid are flags for various types of + ;; flipping. + (let* ((flipped-horizontally? (> (logand raw-gid #x80000000) 0)) + (flipped-vertically? (> (logand raw-gid #x40000000) 0)) + (flipped-diagonally? (> (logand raw-gid #x20000000) 0)) + ;; Remove the upper 3 bits to get the true tile id. + (gid (logand raw-gid #x1FFFFFFF)) + (tileset (find (lambda (t) + (and (>= gid (tileset-first-gid t)) + (< gid (+ (tileset-first-gid t) + (tileset-size t))))) + tilesets)) + (tw (tileset-tile-width tileset)) + (th (tileset-tile-height tileset)) + (first-gid (tileset-first-gid tileset)) + (rows (tileset-rows tileset)) + (columns (tileset-columns tileset)) + (id (invert-tile-id gid first-gid rows columns))) + (make-map-tile (tileset-ref tileset id) + #:flipped-horizontally? flipped-horizontally? + #:flipped-vertically? flipped-vertically? + #:flipped-diagonally? flipped-diagonally?))) + (define (tile-gids->map-tiles gids width height tilesets) + (let ((tiles (make-vector (* width height)))) + (let y-loop ((y 0) + (rows (reverse gids))) ; invert y + (when (< y height) + (match rows + ((row . rest) + (let x-loop ((x 0) + (columns row)) + (when (< x width) + (match columns + ((gid . rest) + (vector-set! tiles + (+ (* width y) x) + (if (zero? gid) + #f + (tile-gid->map-tile gid tilesets + x y width height))) + (x-loop (+ x 1) rest))))) + (y-loop (+ y 1) rest))))) + tiles)) + (define (parse-csv lines width height tilesets) + (let ((gids (map (lambda (line) + (filter-map (lambda (s) + (and (not (string-null? s)) + (string->number s))) + (string-split line #\,))) + (take (drop (string-split lines #\newline) 1) height)))) + (tile-gids->map-tiles gids width height tilesets))) + (define (parse-layer-data node width height tilesets) + (let ((encoding (attr node 'encoding string->symbol)) + (data (car ((sxpath '(*text*)) node)))) + (match encoding + ('csv (parse-csv data width height tilesets)) + (_ (error "unsupported tile layer encoding" encoding))))) + (define (parse-tile-layer node tile-width tile-height tilesets) + (let* ((name (attr node 'name)) + (width (attr node 'width string->number)) + (height (attr node 'height string->number)) + (tiles (parse-layer-data ((sxpath '(data)) node) + width height tilesets)) + (properties (map parse-property + ((sxpath '(properties property)) node))) + (layer (make-tile-layer width height tile-width tile-height + #:name name + #:properties properties + #:chunk-size chunk-size))) + (for-range ((x width) + (y height)) + (tile-layer-set! layer x y (vector-ref tiles (+ (* y width) x)))) + layer)) + (define (parse-polygon node pixel-height) + (make-polygon + (list->vector + (map (lambda (s) + (match (string-split s #\,) + ((x y) + (vec2 (string->number x) + (- pixel-height (string->number y)))))) + (string-split (attr node 'points) #\space))))) + (define (parse-object node pixel-height) + (let* ((id (attr node 'id string->number)) + (name (attr node 'name)) + (type (attr node 'type string->symbol)) + (x (attr node 'x string->number)) + (y (- pixel-height (attr node 'y string->number))) + (width (attr node 'width string->number)) + (height (attr node 'height string->number)) + (shape (if (and width height) + (make-rect x y width height) + (parse-polygon (car ((sxpath '(polygon)) node)) + pixel-height))) + (properties (map parse-property + ((sxpath '(properties property)) node)))) + (%make-map-object id name type shape properties))) + (define (parse-object-layer node pixel-height) + (let ((name (attr node 'name)) + (objects (map (lambda (node) + (parse-object node pixel-height)) + ((sxpath '(object)) node))) + (properties (map parse-property + ((sxpath '(properties property)) node)))) + (%make-object-layer name objects properties))) + (let* ((tree (call-with-input-file file-name xml->sxml)) + (m ((sxpath '(map)) tree)) + (version (attr m 'version)) + (orientation (attr m 'orientation string->symbol)) + (width (attr m 'width string->number)) + (height (attr m 'height string->number)) + (tile-width (attr m 'tilewidth string->number)) + (tile-height (attr m 'tileheight string->number)) + (properties ((sxpath '(map properties property)) tree)) + (tilesets (map parse-tileset* ((sxpath '(map tileset)) tree))) + (layers ((node-or (sxpath '(map layer)) + (sxpath '(map objectgroup))) + tree))) + (make-tile-map width height tile-width tile-height + #:orientation orientation + #:tilesets tilesets + #:layers (map (lambda (node) + (match node + (('layer . _) + (parse-tile-layer node tile-width tile-height tilesets)) + (('objectgroup . _) + (parse-object-layer node (* height tile-height))))) + layers) + #:properties (map parse-property properties)))) + +(define* (draw-tile-map* tile-map matrix region #:key + layers (time (elapsed-time)) + (blend-mode blend:alpha) (tint white)) + ;; Calculate the tiles that are visible so we don't waste time + ;; drawing unnecessary sprites. + (let* ((w (tile-map-width tile-map)) + (h (tile-map-height tile-map)) + (tw (tile-map-tile-width tile-map)) + (th (tile-map-tile-height tile-map)) + (rx (rect-x region)) + (ry (rect-y region)) + (rw (rect-width region)) + (rh (rect-height region)) + (x1 (max (inexact->exact (floor (/ rx tw))) 0)) + (y1 (max (inexact->exact (floor (/ ry th))) 0)) + (x2 (min (inexact->exact (ceiling (/ (+ rx rw) tw))) w)) + (y2 (min (inexact->exact (ceiling (/ (+ ry rh) th))) h))) + (vector-for-each (lambda (i layer) + (when (and (tile-layer? layer) + (or (not layers) + (memv i layers))) + (draw-tile-layer layer matrix x1 y1 x2 y2 blend-mode tint time))) + (tile-map-layers tile-map)))) + +(define %null-vec2 (vec2 0.0 0.0)) +(define %default-scale (vec2 1.0 1.0)) +(define *matrix* (make-null-matrix4)) +(define *position* (vec2 0.0 0.0)) +(define *region* (make-rect 0.0 0.0 0.0 0.0)) + +(define* (draw-tile-map tile-map + #:key + layers + (camera %null-vec2) + (position %null-vec2) + (origin %null-vec2) + (scale %default-scale) + (rotation 0.0) + (blend-mode blend:alpha) + (tint white) + (time (elapsed-time))) + "Draw TILE-MAP. By default, all layers are drawn. The LAYERS +argument may be used to specify a list of layers to draw, instead." + ;; Make the region as big as the current viewport. + (let ((vp (current-viewport))) + (set-rect-x! *region* (vec2-x camera)) + (set-rect-y! *region* (vec2-y camera)) + (set-rect-width! *region* (viewport-width vp)) + (set-rect-height! *region* (viewport-height vp))) + ;; Translation must be adjusted by inverse of camera. + (vec2-copy! camera *position*) + (vec2-mult! *position* -1.0) + (vec2-add! *position* position) + (matrix4-2d-transform! *matrix* + #:origin origin + #:position *position* + #:rotation rotation + #:scale scale) + (matrix4-mult! *matrix* *matrix* (current-projection)) + (draw-tile-map* tile-map *matrix* *region* + #:layers layers + #:blend-mode blend-mode + #:tint tint + #:time time)) diff --git a/chickadee/graphics/tiled.scm b/chickadee/graphics/tiled.scm deleted file mode 100644 index 2692418..0000000 --- a/chickadee/graphics/tiled.scm +++ /dev/null @@ -1,500 +0,0 @@ -;;; Chickadee Game Toolkit -;;; Copyright © 2018, 2020, 2021 David Thompson <davet@gnu.org> -;;; -;;; Chickadee is free software: you can redistribute it and/or modify -;;; it under the terms of the GNU General Public License as published -;;; by the Free Software Foundation, either version 3 of the License, -;;; or (at your option) any later version. -;;; -;;; Chickadee is distributed in the hope that it will be useful, but -;;; WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; General Public License for more details. -;;; -;;; You should have received a copy of the GNU General Public License -;;; along with this program. If not, see -;;; <http://www.gnu.org/licenses/>. - -;;; Commentary: -;; -;; Tiled map format parser and renderer. -;; -;;; Code: - -(define-module (chickadee graphics tiled) - #:use-module (chickadee math matrix) - #:use-module (chickadee math rect) - #:use-module (chickadee math vector) - #:use-module (chickadee graphics color) - #:use-module (chickadee graphics sprite) - #:use-module (chickadee graphics texture) - #:use-module (chickadee graphics viewport) - #:use-module (chickadee utils) - #:use-module (ice-9 match) - #:use-module (srfi srfi-1) - #:use-module (srfi srfi-9) - #:use-module (srfi srfi-43) - #:use-module (sxml simple) - #:use-module (sxml xpath) - #:export (tile-map? - tile-map-orientation - tile-map-width - tile-map-height - tile-map-tile-width - tile-map-tile-height - tile-map-tilesets - tile-map-layers - tile-map-properties - tile-map-rect - tile-map-layer-ref - point->tile - - animation-frame? - animation-frame-tile - animation-frame-duration - - tile? - tile-id - tile-animation - tile-properties - - tileset? - tileset-name - tileset-first-gid - tileset-size - tileset-tile-width - tileset-tile-height - tileset-atlas - tileset-tiles - tileset-properties - - map-tile? - map-tile-ref - map-tile-rect - - tile-layer? - tile-layer-name - tile-layer-width - tile-layer-height - tile-layer-tiles - tile-layer-properties - - object-layer? - object-layer-name - object-layer-objects - object-layer-properties - - polygon? - polygon-points - - map-object? - map-object-id - map-object-name - map-object-type - map-object-shape - map-object-properties - - load-tile-map - draw-tile-map - draw-tile-map*)) - -(define-record-type <tile-map> - (%make-tile-map orientation width height tile-width tile-height - tilesets layers properties rect) - tile-map? - (orientation tile-map-orientation) - (width tile-map-width) - (height tile-map-height) - (tile-width tile-map-tile-width) - (tile-height tile-map-tile-height) - (tilesets tile-map-tilesets) - (layers tile-map-layers) - (properties tile-map-properties) - (rect tile-map-rect)) - -(define-record-type <animation-frame> - (%make-animation-frame tile duration) - animation-frame? - (tile animation-frame-tile) - (duration animation-frame-duration)) - -(define-record-type <tile> - (%make-tile id texture batch animation properties) - tile? - (id tile-id) - (texture tile-texture) - (batch tile-batch) - (animation tile-animation) - (properties tile-properties)) - -(define-record-type <tileset> - (%make-tileset name first-gid size tile-width tile-height - atlas tiles properties batch) - tileset? - (name tileset-name) - (first-gid tileset-first-gid) - (size tileset-size) - (tile-width tileset-tile-width) - (tile-height tileset-tile-height) - (atlas tileset-atlas) - (tiles tileset-tiles) - (properties tileset-properties) - (batch tileset-batch)) - -(define-record-type <map-tile> - (%make-map-tile tile rect) - map-tile? - (tile map-tile-ref) - (rect map-tile-rect)) - -(define-record-type <tile-layer> - (%make-tile-layer name width height tiles properties) - tile-layer? - (name tile-layer-name) - (width tile-layer-width) - (height tile-layer-height) - (tiles tile-layer-tiles) - (properties tile-layer-properties)) - -(define-record-type <object-layer> - (%make-object-layer name objects properties) - object-layer? - (name object-layer-name) - (objects object-layer-objects) - (properties object-layer-properties)) - -;; TODO: This should probably be a generic thing that we can use -;; outside of tiled maps. -(define-record-type <polygon> - (make-polygon points) - polygon? - (points polygon-points)) - -(define-record-type <map-object> - (%make-map-object id name type shape properties) - map-object? - (id map-object-id) - (name map-object-name) - (type map-object-type) - (shape map-object-shape) - (properties map-object-properties)) - -(define (tile-map-layer-ref tile-map name) - "Return the layer named NAME." - (define (layer-name layer) - (if (tile-layer? layer) - (tile-layer-name layer) - (object-layer-name layer))) - (let ((layers (tile-map-layers tile-map))) - (let loop ((i 0)) - (cond - ((= i (vector-length layers)) - #f) - ((string=? name (layer-name (vector-ref layers i))) - (vector-ref layers i)) - (else - (loop (+ i 1))))))) - -(define (point->tile tile-map x y) - "Translate the pixel coordinates (X, Y) into tile coordinates." - (values (inexact->exact (floor (/ x (tile-map-tile-width tile-map)))) - (inexact->exact (floor (/ y (tile-map-tile-height tile-map)))))) - -(define (load-tile-map file-name) - "Load the Tiled TMX formatted map in FILE-NAME." - (define map-directory - (if (absolute-file-name? file-name) - (dirname file-name) - (string-append (getcwd) "/" (dirname file-name)))) - (define (scope file-name) - (string-append map-directory "/" file-name)) - (define* (attr node name #:optional (parse identity)) - (let ((result ((sxpath `(@ ,name *text*)) node))) - (if (null? result) - #f - (parse (car result))))) - (define (parse-color-channel s start) - (/ (string->number (substring s start (+ start 2)) 16) 255.0)) - (define (parse-property node) - (let ((name (attr node 'name string->symbol)) - (type (or (attr node 'type string->symbol) 'string)) - (value (attr node 'value))) - (cons name - (match type - ((or 'string 'file) value) - ('bool (not (string=? value "false"))) - ((or 'int 'float) (string->number value)) - ('color - (make-color (parse-color-channel value 3) - (parse-color-channel value 5) - (parse-color-channel value 7) - (parse-color-channel value 1))) - (_ (error "unsupported property type" type)))))) - (define (parse-image node) - (let ((source (attr node 'source)) - (trans (attr node 'trans))) - (load-image (scope source) - #:transparent-color (and trans (string->color trans))))) - (define (parse-frame node) - (let ((tile-id (attr node 'tileid string->number)) - (duration (attr node 'duration string->number))) - ;; TODO: lookup actual tile in tileset - (%make-animation-frame tile-id duration))) - (define (atlas-ref atlas id rows columns) - ;; Tiled enumerates tiles from the top-left of the tileset image, - ;; but here in OpenGL land the origin is in the bottom-left, so we - ;; have to do some math invert the rows. - (texture-atlas-ref atlas - (+ (* (- rows (floor (/ id columns)) 1) - columns) - (modulo id columns)))) - (define (parse-tile node rows columns atlas batch) - (let ((id (attr node 'id string->number)) - (animation (map parse-frame ((sxpath '(animation frame)) node))) - (properties (map parse-property - ((sxpath '(properties property)) node)))) - (%make-tile id (atlas-ref atlas id rows columns) - batch animation properties))) - (define (parse-tiles nodes size columns atlas batch) - (let ((table (make-hash-table)) - (tiles (make-vector size)) - (rows (/ size columns))) - (for-each (lambda (node) - (let ((tile (parse-tile node rows columns atlas batch))) - (hash-set! table (tile-id tile) tile))) - nodes) - (for-range ((i size)) - (let ((tile - (or (hash-ref table i) - (%make-tile i (atlas-ref atlas i rows columns) - batch #f '())))) - (vector-set! tiles i tile))) - tiles)) - (define (first-gid node) - (attr node 'firstgid string->number)) - (define (parse-internal-tileset node first-gid) - (let* ((name (attr node 'name)) - (tile-width (attr node 'tilewidth string->number)) - (tile-height (attr node 'tileheight string->number)) - (margin (or (attr node 'margin string->number) 0)) - (spacing (or (attr node 'spacing string->number) 0)) - (columns (attr node 'columns string->number)) - (size (attr node 'tilecount string->number)) - (texture (parse-image ((sxpath '(image)) node))) - (atlas (split-texture texture tile-width tile-height - #:margin margin #:spacing spacing)) - (batch (make-sprite-batch texture)) - (tiles (parse-tiles ((sxpath '(tile)) node) size columns atlas batch)) - (properties (map parse-property - ((sxpath '(properties property)) node)))) - (%make-tileset name first-gid size tile-width tile-height - atlas tiles properties batch))) - (define (parse-external-tileset node) - (let* ((first-gid (attr node 'firstgid string->number)) - (source (scope (attr node 'source))) - (tree (call-with-input-file source xml->sxml))) - (parse-internal-tileset (car ((sxpath '(tileset)) tree)) first-gid))) - (define (parse-tileset node) - (if (attr node 'source) - (parse-external-tileset node) - (parse-internal-tileset node (first-gid node)))) - (define (tile-gid->map-tile raw-gid tilesets x y tile-width tile-height) - ;; The top 3 bits of the tile gid are flags for various types of - ;; flipping. - ;; - ;; TODO: Respect the flipping settings. - (let* ((flipped-horizontally? (> (logand raw-gid #x80000000) 0)) - (flipped-vertically? (> (logand raw-gid #x40000000) 0)) - (flipped-diagonally? (> (logand raw-gid #x20000000) 0)) - ;; Remove the upper 3 bits to get the true tile id. - (gid (logand raw-gid #x1FFFFFFF)) - (tileset (find (lambda (t) - (and (>= gid (tileset-first-gid t)) - (< gid (+ (tileset-first-gid t) - (tileset-size t))))) - tilesets)) - (tw (tileset-tile-width tileset)) - (th (tileset-tile-height tileset))) - (%make-map-tile (vector-ref (tileset-tiles tileset) - (- gid (tileset-first-gid tileset))) - (make-rect (* x tw) (* y th) tw th)))) - (define (tile-gids->map-tiles gids width height tilesets) - (let ((tiles (make-vector (* width height)))) - (let y-loop ((y 0) - (rows (reverse gids))) ; invert y - (when (< y height) - (match rows - ((row . rest) - (let x-loop ((x 0) - (columns row)) - (when (< x width) - (match columns - ((gid . rest) - (vector-set! tiles - (+ (* width y) x) - (if (zero? gid) - #f - (tile-gid->map-tile gid tilesets - x y width height))) - (x-loop (+ x 1) rest))))) - (y-loop (+ y 1) rest))))) - tiles)) - (define (parse-csv lines width height tilesets) - (let ((gids (map (lambda (line) - (filter-map (lambda (s) - (and (not (string-null? s)) - (string->number s))) - (string-split line #\,))) - (take (drop (string-split lines #\newline) 1) height)))) - (tile-gids->map-tiles gids width height tilesets))) - (define (parse-layer-data node width height tilesets) - (let ((encoding (attr node 'encoding string->symbol)) - (data (car ((sxpath '(*text*)) node)))) - (match encoding - ('csv (parse-csv data width height tilesets)) - (_ (error "unsupported tile layer encoding" encoding))))) - (define (parse-tile-layer node tilesets) - (let* ((name (attr node 'name)) - (width (attr node 'width string->number)) - (height (attr node 'height string->number)) - (tiles (parse-layer-data ((sxpath '(data)) node) - width height tilesets)) - (properties (map parse-property - ((sxpath '(properties property)) node)))) - (%make-tile-layer name width height tiles properties))) - (define (parse-polygon node pixel-height) - (make-polygon - (list->vector - (map (lambda (s) - (match (string-split s #\,) - ((x y) - (vec2 (string->number x) - (- pixel-height (string->number y)))))) - (string-split (attr node 'points) #\space))))) - (define (parse-object node pixel-height) - (let* ((id (attr node 'id string->number)) - (name (attr node 'name)) - (type (attr node 'type string->symbol)) - (x (attr node 'x string->number)) - (y (- pixel-height (attr node 'y string->number))) - (width (attr node 'width string->number)) - (height (attr node 'height string->number)) - (shape (if (and width height) - (make-rect x y width height) - (parse-polygon (car ((sxpath '(polygon)) node)) - pixel-height))) - (properties (map parse-property - ((sxpath '(properties property)) node)))) - (%make-map-object id name type shape properties))) - (define (parse-object-layer node pixel-height) - (let ((name (attr node 'name)) - (objects (map (lambda (node) - (parse-object node pixel-height)) - ((sxpath '(object)) node))) - (properties (map parse-property - ((sxpath '(properties property)) node)))) - (%make-object-layer name objects properties))) - (let* ((tree (call-with-input-file file-name xml->sxml)) - (m ((sxpath '(map)) tree)) - (version (attr m 'version)) - (orientation (attr m 'orientation string->symbol)) - (width (attr m 'width string->number)) - (height (attr m 'height string->number)) - (tile-width (attr m 'tilewidth string->number)) - (tile-height (attr m 'tileheight string->number)) - (properties ((sxpath '(map properties property)) tree)) - (tilesets (map parse-tileset ((sxpath '(map tileset)) tree))) - (layers ((node-or (sxpath '(map layer)) - (sxpath '(map objectgroup))) - tree))) - (%make-tile-map orientation width height tile-width tile-height - tilesets - (list->vector - (map (lambda (node) - (match node - (('layer . _) - (parse-tile-layer node tilesets)) - (('objectgroup . _) - (parse-object-layer node (* height tile-height))))) - layers)) - (map parse-property properties) - (make-rect 0.0 - 0.0 - (* width tile-width) - (* height tile-height))))) - - -(define (draw-tile-layer layer matrix x1 y1 x2 y2) - (let ((width (tile-layer-width layer)) - (height (tile-layer-height layer))) - (for-range ((x x2 x1) - (y y2 y1)) - (let ((tile (vector-ref (tile-layer-tiles layer) - (+ (* y width) x)))) - (when tile - (let ((tref (map-tile-ref tile))) - (sprite-batch-add* (tile-batch tref) - (map-tile-rect tile) - matrix - #:texture-region (tile-texture tref)))))))) - -(define* (draw-tile-map* tile-map matrix region #:key layers) - ;; Calculate the tiles that are visible so we don't waste time - ;; drawing unnecessary sprites. - (let* ((w (tile-map-width tile-map)) - (h (tile-map-height tile-map)) - (tw (tile-map-tile-width tile-map)) - (th (tile-map-tile-height tile-map)) - (rx (rect-x region)) - (ry (rect-y region)) - (rw (rect-width region)) - (rh (rect-height region)) - (x1 (max (inexact->exact (floor (/ rx tw))) 0)) - (y1 (max (inexact->exact (floor (/ ry th))) 0)) - (x2 (min (inexact->exact (ceiling (/ (+ rx rw) tw))) w)) - (y2 (min (inexact->exact (ceiling (/ (+ ry rh) th))) h))) - (vector-for-each (lambda (i layer) - (when (and (tile-layer? layer) - (or (not layers) - (memv i layers))) - (for-each (lambda (tileset) - (sprite-batch-clear! (tileset-batch tileset))) - (tile-map-tilesets tile-map)) - (draw-tile-layer layer matrix x1 y1 x2 y2) - (for-each (lambda (tileset) - (draw-sprite-batch (tileset-batch tileset))) - (tile-map-tilesets tile-map)))) - (tile-map-layers tile-map)))) - -(define %null-vec2 (vec2 0.0 0.0)) -(define %default-scale (vec2 1.0 1.0)) -(define *matrix* (make-null-matrix4)) -(define *position* (vec2 0.0 0.0)) -(define *region* (make-rect 0.0 0.0 0.0 0.0)) - -(define* (draw-tile-map tile-map - #:key - layers - (camera %null-vec2) - (position %null-vec2) - (origin %null-vec2) - (scale %default-scale) - (rotation 0.0)) - "Draw TILE-MAP. By default, all layers are drawn. The LAYERS -argument may be used to specify a list of layers to draw, instead." - ;; Make the region as big as the current viewport. - (let ((vp (current-viewport))) - (set-rect-x! *region* (vec2-x camera)) - (set-rect-y! *region* (vec2-y camera)) - (set-rect-width! *region* (viewport-width vp)) - (set-rect-height! *region* (viewport-height vp))) - ;; Translation must be adjusted by inverse of camera. - (vec2-copy! camera *position*) - (vec2-mult! *position* -1.0) - (vec2-add! *position* position) - (matrix4-2d-transform! *matrix* - #:origin origin - #:position *position* - #:rotation rotation - #:scale scale) - (draw-tile-map* tile-map *matrix* *region* #:layers layers)) diff --git a/doc/api.texi b/doc/api.texi index e99c89c..28a5553 100644 --- a/doc/api.texi +++ b/doc/api.texi @@ -2532,7 +2532,7 @@ A tile map is a scene created by composing lots of small sprites, called ``tiles'', into a larger image. One program for editing such maps is called @url{http://mapeditor.org,Tiled}. Chickadee has native support for loading and rendering Tiled maps in the @code{(chickadee -graphics tiled)} module. +graphics tile-map)} module. @deffn {Procedure} load-tile-map file-name Load the Tiled formatted map in @var{file-name} and return a new tile @@ -2581,7 +2581,8 @@ coordinates. @end deffn @deffn {Procedure} draw-tile-map tile-map [#:layers] [#:camera] @ - [#:origin] [#:position] [#:scale] [#:rotation] + [#:origin] [#:position] [#:scale] [#:rotation] [#:blend-mode] @ + [#:tint] [#:time] [#:chunk-size] Draw the layers of @var{tile-map} as viewed from @var{camera}, a 2D vector offset. By default, all layers are drawn. To draw a subset of @@ -2621,6 +2622,14 @@ Return the texture atlas for @var{tileset}. Return the tiles in @var{tileset}. @end deffn +@deffn {Procedure} tileset-rows tileset +Return the number of rows in @var{tileset}. +@end deffn + +@deffn {Procedure} tileset-columns tileset +Return the number of columns in @var{tileset}. +@end deffn + @deffn {Procedure} tileset-properties tileset Return the custom properties of @var{tileset}. @end deffn @@ -2641,6 +2650,18 @@ Return the animation for @var{tile}. Return the custom properties of @var{tile}. @end deffn +@deffn {Procedure} animation? obj +Return @code{#t} if @var{obj} is an animation. +@end deffn + +@deffn {Procedure} animation-frames animation +Return a vector of frames in @var{animation}. +@end deffn + +@deffn {Procedure} animation-duration animation +Return the duration of @var{animation}. +@end deffn + @deffn {Procedure} animation-frame? obj Return @code{#t} if @var{obj} is an animation frame. @end deffn diff --git a/examples/images/serene-village.png b/examples/images/serene-village.png Binary files differnew file mode 100644 index 0000000..d94cb31 --- /dev/null +++ b/examples/images/serene-village.png diff --git a/examples/images/tiles.png b/examples/images/tiles.png Binary files differdeleted file mode 100644 index d8a3dfd..0000000 --- a/examples/images/tiles.png +++ /dev/null diff --git a/examples/maps/example.tmx b/examples/maps/example.tmx index 6c8bc3d..4a3a77a 100644 --- a/examples/maps/example.tmx +++ b/examples/maps/example.tmx @@ -1,96 +1,274 @@ <?xml version="1.0" encoding="UTF-8"?> -<map version="1.0" tiledversion="1.1.0" orientation="orthogonal" renderorder="right-up" width="20" height="15" tilewidth="16" tileheight="16" infinite="0" nextobjectid="1"> - <tileset firstgid="1" name="tiles" tilewidth="16" tileheight="16" tilecount="1440" columns="40"> - <image source="../images/tiles.png" width="640" height="576"/> - <terraintypes> - <terrain name="grass" tile="0"/> - <terrain name="dark-grass" tile="1"/> - <terrain name="tree" tile="1"/> - <terrain name="nothing" tile="1"/> - </terraintypes> - <tile id="0" terrain="0,0,0,0"/> - <tile id="360" terrain="0,0,0,1"/> - <tile id="361" terrain="0,0,1,0"/> - <tile id="400" terrain="0,1,0,0"/> - <tile id="401" terrain="1,0,0,0"/> - <tile id="642" terrain="2,2,2,2"/> - <tile id="643" terrain="3,2,2,2"/> - <tile id="644" terrain="2,3,2,2"/> - <tile id="645" terrain="3,3,3,2"/> - <tile id="646" terrain="3,3,2,3"/> - <tile id="648" terrain="3,3,3,3"/> - <tile id="685" terrain="3,2,3,3"/> - <tile id="686" terrain="2,3,3,3"/> - <tile id="725" terrain="3,3,2,2"/> - <tile id="1174" terrain="0,0,0,1"/> - <tile id="1175" terrain="0,0,1,1"/> - <tile id="1176" terrain="0,0,1,0"/> - <tile id="1214" terrain="0,1,0,1"/> - <tile id="1215" terrain="1,1,1,1"/> - <tile id="1216" terrain="1,0,1,0"/> - <tile id="1254" terrain="0,1,0,0"/> - <tile id="1255" terrain="1,1,0,0"/> - <tile id="1256" terrain="1,0,0,0"/> - <tile id="1294" terrain="1,1,1,0"/> - <tile id="1295" terrain="1,1,0,1"/> - <tile id="1334" terrain="1,0,1,1"/> - <tile id="1335" terrain="0,1,1,1"/> - </tileset> - <layer name="background" width="20" height="15"> +<map version="1.5" tiledversion="1.5.0" orientation="orthogonal" renderorder="right-down" width="50" height="50" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="1"> + <tileset firstgid="1" source="serene-village.tsx"/> + <layer id="1" name="Water" width="50" height="50"> <data encoding="csv"> -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1175,1176,1176,1177,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1215,1216,1216,1217,1, -1,1,1,1,1,1175,1176,1177,1,1,1,1,1,1,1,1215,1216,1216,1217,1, -1,1,1,1175,1176,1336,1216,1335,1177,1,1,1,1,1,1,1255,1296,1216,1217,1, -1,1,1,1215,1216,1216,1216,1216,1335,1177,1,1,1,1,1,1,1215,1216,1217,1, -1,1,1,1215,1216,1216,1216,1216,1216,1335,1176,1176,1176,1176,1177,1,1255,1256,1257,1, -1,1,1,1215,1216,1216,1216,1295,1296,1216,1216,1216,1216,1216,1217,1,1,1,1,1, -1,1,1,1255,1296,1216,1216,1217,1255,1256,1296,1216,1295,1256,1257,1,1,1,1,1, -1,1,1,1,1255,1256,1256,1257,1,367,1255,1256,1257,365,1,1,1,1,1,1, -446,446,446,446,446,446,446,446,446,447,212,253,253,445,446,446,446,446,446,446, -486,486,486,486,486,486,486,486,486,527,252,213,213,525,486,486,486,486,486,526, -566,566,566,566,566,566,566,566,566,567,252,253,253,565,566,566,566,566,566,566, -1,1,1,1,1,1,1,1,1,1,1175,1176,1177,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1215,1216,1335,1177,1,1,1,1,1,1 +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,0,0,0,0,0,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,0,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,0,0,0,0,0,0,0,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210 </data> </layer> - <layer name="overlay" width="20" height="15"> + <layer id="2" name="Land" width="50" height="50"> <data encoding="csv"> -685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,646,647,0,0,0,0, -0,646,647,483,0,0,484,321,0,7,8,9,10,11,686,687,0,0,0,0, -0,686,687,0,444,0,827,0,321,47,48,49,50,51,0,0,0,0,0,0, -0,321,0,484,0,828,867,829,0,87,88,89,90,91,0,0,0,0,0,0, -0,0,483,0,0,868,0,869,0,127,128,129,130,131,646,647,0,0,0,0, -0,483,483,321,0,0,0,0,0,167,168,169,170,171,686,687,0,0,646,647, -0,0,444,0,0,0,0,0,73,0,0,0,0,0,483,0,484,0,686,687, -646,647,321,0,0,0,0,0,113,0,0,0,0,0,73,444,483,0,0,0, -686,687,483,0,484,321,484,0,444,0,528,0,0,0,113,483,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,116,0,0,0,0,0,0, -606,606,606,606,606,606,606,606,606,322,608,0,0,605,606,606,606,606,606,606, -0,0,0,0,0,0,0,0,483,484,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,81,84,84,83,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,84,82,81,84,21,5,47,4,24,22,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,83,81,21,100,101,101,103,47,43,101,4,62,103,22,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,80,84,84,84,21,62,4,101,102,43,100,6,62,102,46,62,103,4,5,22,82,85,80,83,82,83,82,84,85,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,99,62,5,24,101,62,24,102,103,4,103,62,62,102,24,5,43,62,6,6,4,22,21,6,4,100,102,103,22,85,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,80,82,84,81,21,24,100,46,62,101,4,46,6,43,46,100,24,102,46,101,6,102,46,103,62,43,62,103,103,102,24,6,47,22,85,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,80,21,6,102,6,24,46,6,102,43,103,6,6,5,24,6,43,103,62,62,47,43,103,46,47,103,5,62,24,100,5,24,5,103,46,104,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,99,24,46,47,4,6,102,102,43,43,103,24,5,103,46,46,4,62,5,62,102,101,101,5,43,102,101,46,47,46,4,101,43,102,100,104,0,0,0,0,0,0, +0,0,0,0,0,0,0,80,21,5,24,47,5,100,101,102,5,103,6,24,44,65,65,42,46,5,24,46,5,24,5,6,24,100,62,46,62,6,101,46,47,100,100,22,85,0,0,0,0,0, +0,0,0,0,0,0,0,99,103,101,102,47,46,46,102,100,100,46,43,43,48,49,49,64,65,65,66,66,65,66,66,42,100,5,6,102,6,4,100,24,101,102,62,100,104,0,0,0,0,0, +0,0,0,0,0,0,0,99,101,6,47,6,102,100,43,47,62,43,100,43,48,49,49,49,49,49,49,49,49,49,49,64,42,100,101,43,5,4,46,5,24,4,46,46,104,0,0,0,0,0, +0,0,0,0,0,0,0,99,103,47,47,103,103,103,24,43,62,44,66,66,67,49,49,49,49,49,49,49,49,49,49,49,64,66,42,46,43,5,102,101,4,46,5,46,104,0,0,0,0,0, +0,0,0,0,0,0,0,99,47,47,4,100,46,5,43,5,101,25,28,27,27,28,27,28,28,27,28,28,29,49,49,49,49,49,45,100,102,4,24,46,62,5,24,41,123,0,0,0,0,0, +0,0,0,0,0,0,0,118,40,47,5,101,101,24,6,101,4,103,62,24,47,102,4,4,6,5,5,46,48,26,27,28,27,27,23,6,5,6,46,24,24,5,41,123,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,118,40,5,102,102,4,47,102,46,5,47,5,62,103,62,100,4,100,46,47,48,45,100,43,102,5,43,102,62,46,6,62,4,41,123,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,118,40,100,24,4,43,24,100,43,102,102,100,101,46,4,100,4,5,62,25,23,5,102,47,101,4,6,102,47,5,41,120,123,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,118,119,119,120,119,122,121,120,40,24,102,24,47,4,46,24,62,62,5,43,5,101,101,102,4,101,43,41,119,123,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,119,121,121,120,120,121,119,122,121,121,122,121,121,119,40,101,41,121,123,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,122,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,80,82,81,85,0,0,0,0,0,0,0,0,0,0,0,0,0,80,83,81,84,84,81,83,82,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,80,84,81,81,21,47,4,104,0,0,0,0,0,0,0,0,0,0,0,80,84,21,46,100,46,6,6,4,62,22,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,99,101,46,43,24,6,100,22,85,0,0,0,0,0,0,0,0,0,80,21,24,44,66,66,65,42,47,6,5,43,22,82,85,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,80,21,47,102,62,47,102,24,102,22,85,0,0,0,0,0,0,0,0,99,46,4,48,49,49,49,61,103,100,24,43,102,62,104,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,80,21,102,47,5,62,47,102,6,6,47,22,85,0,0,0,0,0,0,80,21,103,43,63,49,26,27,23,43,101,46,100,62,47,22,85,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,99,101,101,62,43,103,62,103,47,62,43,4,104,0,0,0,0,0,80,21,5,4,4,63,49,61,100,100,6,4,4,5,101,4,101,104,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,99,5,102,100,4,5,6,43,43,24,43,4,22,85,0,0,0,0,99,5,100,100,100,63,49,45,102,101,24,5,102,62,62,100,24,104,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,99,100,62,43,100,24,6,102,100,46,24,6,5,104,0,0,0,80,21,46,46,5,62,63,49,61,103,102,47,46,101,5,24,103,47,104,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,99,100,24,43,103,5,47,62,43,46,100,43,47,22,85,0,0,99,100,100,47,62,103,63,49,61,46,5,24,46,5,102,102,101,46,104,0,0,0,0,0,0,0,0,0,0,0,0, +0,80,21,103,103,44,65,66,65,42,47,24,102,5,6,46,104,0,80,21,5,102,43,6,103,63,49,45,4,5,46,43,100,47,62,5,24,104,0,0,0,0,0,0,0,0,0,0,0,0, +0,99,101,24,44,67,49,49,49,64,66,65,66,65,65,42,104,0,99,44,66,65,66,65,66,67,49,45,24,4,24,4,46,103,102,101,46,104,0,0,0,0,0,0,0,0,0,0,0,0, +0,99,46,101,63,49,49,49,49,49,49,49,49,49,49,45,104,0,99,63,49,49,49,49,49,49,49,45,46,100,103,101,62,6,101,102,101,104,0,0,0,0,0,0,0,0,0,0,0,0, +80,21,46,4,48,49,49,49,49,49,26,28,28,28,28,23,104,0,99,25,28,28,28,28,27,28,27,23,100,62,6,103,6,24,24,24,41,123,0,0,0,0,0,0,0,0,0,0,0,0, +99,100,102,24,25,29,49,49,49,49,45,62,43,103,62,100,104,0,99,4,101,103,100,5,101,43,46,43,100,4,43,103,43,103,103,5,104,0,0,0,0,0,0,0,0,0,0,0,0,0, +99,43,5,46,103,25,28,28,28,28,23,102,102,43,46,41,123,0,118,121,120,122,119,121,40,6,100,101,24,24,46,4,24,46,24,103,104,0,0,0,0,0,0,0,0,0,0,0,0,0, +118,121,40,4,101,5,46,4,100,103,24,47,4,6,41,123,0,0,0,0,0,0,0,0,118,40,101,62,100,102,47,24,46,46,41,119,123,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,118,122,122,120,40,100,6,47,62,100,46,47,104,0,0,0,0,0,0,0,0,0,0,118,120,122,122,122,122,121,120,120,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,118,121,119,119,122,122,120,122,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 </data> </layer> - <layer name="overoverlay" width="20" height="15"> + <layer id="5" name="Decoration Under" width="50" height="50"> <data encoding="csv"> -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,450,451,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,490,491,0,0,0,0,0,45,46,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,290,291,0,0,0,291,290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,309,0,0,0,0,0,309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,309,0,0,0,0,0,309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,328,329,312,0,329,329,328,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,290,291,0,0,0,291,290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,309,0,0,0,0,0,311,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,290,291,0,0,0,291,291,292,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,309,0,0,0,0,0,311,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,309,0,0,0,0,0,0,311,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,328,329,0,0,329,329,330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,309,0,0,0,0,0,0,311,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,328,329,329,0,329,329,329,330,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +</data> + </layer> + <layer id="3" name="Buildings" width="50" height="50"> + <data encoding="csv"> +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,411,412,413,414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,429,430,431,432,433,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,552,553,554,0,0,0,0,0,0,448,449,450,451,452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,571,572,573,0,0,0,0,0,0,467,468,469,470,471,0,0,0,0,0,710,711,712,713,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,590,591,592,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,729,730,731,732,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,609,610,611,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,748,749,750,751,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,767,768,769,770,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,628,629,630,631,632,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,647,648,649,650,651,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,785,786,787,788,789,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,666,667,668,669,670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,804,805,806,807,808,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,685,686,687,688,689,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,823,824,825,826,827,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,842,843,844,845,846,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,71,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,109,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +</data> + </layer> + <layer id="4" name="Decoration Over" width="50" height="50"> + <data encoding="csv"> +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,269,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,269,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,368,369,0,368,369,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,233,0,0,0,234,0,0,0,234,0,0,0,0,0,0,0,97,0,0,0,0,0,0,236,0,0,0,0,236,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,234,348,0,348,234,0,0,0,0,0,0,0,0,0,0,0,0,0,0,236,0,0,0,0,236,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,270,0,0,0,0,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,236,350,0,366,367,236,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,233,96,289,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,115,116,117,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,115,117,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,250,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,232,0,0,0,0,0,0,250,0,0,0,646,719,646,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,665,0,665,0,0,0,0,0,0,0,269,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,274,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,352,353,354,355,356,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,371,372,373,374,375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,390,391,392,393,394,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,236,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,368,369,0,368,369,0,0,0,0,0,0,0,0,0,0,0,0,269,0,0,0,0,236,0,0,0,0,0,0,347,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,331,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,305,306,0,0,0,236,0,366,367,0,366,367,347,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,275,0,0,0,0,0,0,0,382,324,325,0,0,0,236,0,0,0,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,115,115,97,97,117,0,269,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,269,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 </data> </layer> </map> diff --git a/examples/maps/serene-village.tsx b/examples/maps/serene-village.tsx new file mode 100644 index 0000000..aec16da --- /dev/null +++ b/examples/maps/serene-village.tsx @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tileset version="1.5" tiledversion="1.5.0" name="Serene Village" tilewidth="32" tileheight="32" tilecount="855" columns="19"> + <image source="../images/serene-village.png" width="608" height="1440"/> + <tile id="209"> + <animation> + <frame tileid="209" duration="100"/> + <frame tileid="210" duration="100"/> + <frame tileid="211" duration="100"/> + <frame tileid="212" duration="100"/> + <frame tileid="213" duration="100"/> + <frame tileid="214" duration="100"/> + <frame tileid="215" duration="100"/> + <frame tileid="216" duration="100"/> + <frame tileid="217" duration="100"/> + <frame tileid="218" duration="100"/> + <frame tileid="219" duration="100"/> + <frame tileid="220" duration="100"/> + <frame tileid="221" duration="100"/> + <frame tileid="222" duration="100"/> + </animation> + </tile> + <tile id="718"> + <animation> + <frame tileid="718" duration="100"/> + <frame tileid="719" duration="100"/> + <frame tileid="720" duration="100"/> + <frame tileid="721" duration="100"/> + </animation> + </tile> + <wangsets> + <wangset name="Unnamed Set" type="corner" tile="-1"> + <wangcolor name="Grass" color="#ff0000" tile="-1" probability="1"/> + <wangcolor name="Water" color="#00ff00" tile="-1" probability="1"/> + <wangcolor name="Dirt" color="#0000ff" tile="-1" probability="1"/> + <wangtile tileid="3" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="4" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="5" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="20" wangid="0,1,0,1,0,1,0,0"/> + <wangtile tileid="21" wangid="0,0,0,1,0,1,0,1"/> + <wangtile tileid="22" wangid="0,1,0,1,0,1,0,3"/> + <wangtile tileid="23" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="24" wangid="0,3,0,1,0,1,0,1"/> + <wangtile tileid="25" wangid="0,3,0,1,0,3,0,3"/> + <wangtile tileid="26" wangid="0,3,0,1,0,1,0,3"/> + <wangtile tileid="27" wangid="0,3,0,1,0,1,0,3"/> + <wangtile tileid="28" wangid="0,3,0,3,0,1,0,3"/> + <wangtile tileid="39" wangid="0,1,0,1,0,0,0,1"/> + <wangtile tileid="40" wangid="0,1,0,0,0,1,0,1"/> + <wangtile tileid="41" wangid="0,1,0,1,0,3,0,1"/> + <wangtile tileid="42" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="43" wangid="0,1,0,3,0,1,0,1"/> + <wangtile tileid="44" wangid="0,1,0,1,0,3,0,3"/> + <wangtile tileid="45" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="46" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="47" wangid="0,3,0,3,0,1,0,1"/> + <wangtile tileid="48" wangid="0,3,0,3,0,3,0,3"/> + <wangtile tileid="60" wangid="0,1,0,1,0,3,0,3"/> + <wangtile tileid="61" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="62" wangid="0,3,0,3,0,1,0,1"/> + <wangtile tileid="63" wangid="0,1,0,3,0,3,0,3"/> + <wangtile tileid="64" wangid="0,1,0,3,0,3,0,1"/> + <wangtile tileid="65" wangid="0,1,0,3,0,3,0,1"/> + <wangtile tileid="66" wangid="0,3,0,3,0,3,0,1"/> + <wangtile tileid="79" wangid="0,0,0,1,0,0,0,0"/> + <wangtile tileid="80" wangid="0,0,0,1,0,1,0,0"/> + <wangtile tileid="81" wangid="0,0,0,1,0,1,0,0"/> + <wangtile tileid="82" wangid="0,0,0,1,0,1,0,0"/> + <wangtile tileid="83" wangid="0,0,0,1,0,1,0,0"/> + <wangtile tileid="84" wangid="0,0,0,0,0,1,0,0"/> + <wangtile tileid="98" wangid="0,1,0,1,0,0,0,0"/> + <wangtile tileid="99" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="100" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="101" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="102" wangid="0,1,0,1,0,1,0,1"/> + <wangtile tileid="103" wangid="0,0,0,0,0,1,0,1"/> + <wangtile tileid="117" wangid="0,1,0,0,0,0,0,0"/> + <wangtile tileid="118" wangid="0,1,0,0,0,0,0,1"/> + <wangtile tileid="119" wangid="0,1,0,0,0,0,0,1"/> + <wangtile tileid="120" wangid="0,1,0,0,0,0,0,1"/> + <wangtile tileid="121" wangid="0,1,0,0,0,0,0,1"/> + <wangtile tileid="122" wangid="0,0,0,0,0,0,0,1"/> + </wangset> + </wangsets> +</tileset> diff --git a/examples/tiled.scm b/examples/tile-map.scm index c528f74..52d6b94 100644 --- a/examples/tiled.scm +++ b/examples/tile-map.scm @@ -3,11 +3,13 @@ (chickadee math rect) (chickadee graphics color) (chickadee graphics font) - (chickadee graphics tiled) + (chickadee graphics tile-map) (ice-9 format) (ice-9 match) (srfi srfi-11)) +(define window-width 960) +(define window-height 540) (define map #f) (define prev-camera (vec2 0.0 0.0)) (define camera (vec2 0.0 0.0)) @@ -20,12 +22,12 @@ (define start-time 0.0) (define avg-frame-time 16) (define stats-text (stats-message)) -(define stats-text-pos (vec2 4.0 464.0)) +(define stats-text-pos (vec2 4.0 (- window-height 16.0))) (define last-update start-time) (define scroll-speed 6.0) (define (load) - (set! map (load-tile-map "maps/example.tmx"))) + (set! map (load-tile-map "maps/example3.tmx"))) (define (draw alpha) ;; Linearly interpolate between the current camera position and the @@ -34,11 +36,13 @@ ;; loop does not render in lock-step with updates. (let ((beta (- 1.0 alpha))) (set-vec2-x! render-camera - (+ (* (vec2-x camera) alpha) - (* (vec2-x prev-camera) beta))) + (round + (+ (* (vec2-x camera) alpha) + (* (vec2-x prev-camera) beta)))) (set-vec2-y! render-camera - (+ (* (vec2-y camera) alpha) - (* (vec2-y prev-camera) beta)))) + (round + (+ (* (vec2-y camera) alpha) + (* (vec2-y prev-camera) beta))))) (draw-tile-map map #:camera render-camera) (draw-text text text-position #:color black) (draw-text stats-text stats-text-pos #:color black) @@ -47,20 +51,36 @@ (+ (* (- current-time start-time) 0.1) (* avg-frame-time 0.9))) (set! start-time current-time) - (when (>= (- current-time last-update) 1000) + (when (>= (- current-time last-update) 1.0) (set! stats-text (stats-message)) (set! last-update current-time)))) +(define (refresh-tile-coords x y) + (call-with-values (lambda () + (point->tile map + (+ x (vec2-x camera)) + (+ y (vec2-y camera)))) + (lambda (tx ty) + (set! text (format #f "~d, ~d" tx ty))))) + (define (update dt) (vec2-copy! camera prev-camera) - (set-vec2-x! camera - (+ (vec2-x camera) - (if (key-pressed? 'right) scroll-speed 0.0) - (if (key-pressed? 'left) (- scroll-speed) 0.0))) - (set-vec2-y! camera - (+ (vec2-y camera) - (if (key-pressed? 'up) scroll-speed 0.0) - (if (key-pressed? 'down) (- scroll-speed) 0.0)))) + (set-vec2! camera + (min (max (+ (vec2-x camera) + (if (key-pressed? 'right) scroll-speed 0.0) + (if (key-pressed? 'left) (- scroll-speed) 0.0)) + 0.0) + (- (* (tile-map-width map) (tile-map-tile-width map)) + window-width)) + (min (max (+ (vec2-y camera) + (if (key-pressed? 'up) scroll-speed 0.0) + (if (key-pressed? 'down) (- scroll-speed) 0.0)) + 0.0) + (- (* (tile-map-height map) (tile-map-tile-height map)) + window-height))) + (when (or (key-pressed? 'left) (key-pressed? 'right) + (key-pressed? 'down) (key-pressed? 'up)) + (refresh-tile-coords (mouse-x) (mouse-y)))) (define (key-press key modifiers repeat?) (match key @@ -68,11 +88,10 @@ (_ #t))) (define (mouse-move x y x-rel y-rel buttons) - (let-values (((tx ty) (point->tile map (- x (vec2-x camera)) (- y (vec2-y camera))))) - (set! text (format #f "~d, ~d" tx ty)))) + (refresh-tile-coords x y)) -(run-game #:window-width 640 - #:window-height 480 +(run-game #:window-width window-width + #:window-height window-height #:window-title "tile map demo" #:load load #:draw draw |