-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
793 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
package tmx | ||
|
||
import ( | ||
"bytes" | ||
"compress/gzip" | ||
"compress/zlib" | ||
"encoding/base64" | ||
"encoding/binary" | ||
"encoding/csv" | ||
"encoding/xml" | ||
"errors" | ||
"io" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// Data contains the tile data for a map | ||
type Data struct { | ||
// Encoding is the encoding used for the data. It can either be "base64" | ||
// or "csv" | ||
Encoding string `xml:"encoding,attr"` | ||
// Compression is the compression used for the data. It can either be | ||
// "gzip" or "zlib" | ||
Compression string `xml:"compression,attr"` | ||
// Tiles are the tiles in the data. Not the same as TMXTiles from the Tileset. | ||
Tiles []TileData `xml:"tile"` | ||
// Chunks are sets of tiles over an area. Used for randomly generated maps. | ||
Chunks []Chunk `xml:"chunk"` | ||
// Inner is the inner data | ||
Inner string `xml:",innerxml"` | ||
} | ||
|
||
// Chunk contains chunk data for a map. A chunk is a set of more than one | ||
// tile that goes together, so when the map is set to randomly generate, these | ||
// tiles are generated together. | ||
type Chunk struct { | ||
// X is the x coordinate of the chunk in tiles | ||
X int `xml:"x,attr"` | ||
// Y is the y coordinate of the chunk in tiles | ||
Y int `xml:"y,attr"` | ||
// Width is the width of the chunk in tiles | ||
Width int `xml:"width,attr"` | ||
// Height is the height of the chunk in tiles | ||
Height int `xml:"height,attr"` | ||
// Tiles are the tiles in the chunk | ||
Tiles []TileData `xml:"tile"` | ||
} | ||
|
||
// TileData contains the gid that maps a tile to the sprite | ||
type TileData struct { | ||
// RawGID is the global tile ID given in the map | ||
RawGID uint32 `xml:"gid,attr"` | ||
// GID is the global tile ID with the flipping bits removed | ||
GID uint32 | ||
// Flipping is the flipping flags present | ||
// You can & this with the constants HorizontalFlipFlag, VerticalFlipFlag, and | ||
// DiagonalFlipFlag to find out if the flag was present on the tile. | ||
Flipping uint32 | ||
} | ||
|
||
const ( | ||
// HorizontalFlipFlag is a flag for a horizontally flipped tile | ||
HorizontalFlipFlag uint32 = 0x80000000 | ||
// VerticalFlipFlag is a flag for a vertically flipped tile | ||
VerticalFlipFlag uint32 = 0x40000000 | ||
// DiagonalFlipFlag is a flag for a diagonally flipped tile | ||
DiagonalFlipFlag uint32 = 0x20000000 | ||
) | ||
|
||
// UnmarshalXML implements the encoding/xml Unmarshaler interface | ||
func (da *Data) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { | ||
type data Data | ||
dat := data{} | ||
if err := d.DecodeElement(&dat, &start); err != nil { | ||
return err | ||
} | ||
*da = (Data)(dat) | ||
if len(da.Tiles) > 0 { | ||
return nil | ||
} | ||
if da.Encoding == "csv" { | ||
b := strings.NewReader(strings.TrimSpace(da.Inner)) | ||
cr := csv.NewReader(b) | ||
// We allow variable number of fields per record to allow line ending commas and then | ||
// empty strings appearing as a field. Later, we filter empty strings. This trick is | ||
// needed to allow TilEd-style CSVs with line-ending commas but no comma at the end | ||
// of last line. | ||
cr.FieldsPerRecord = -1 | ||
if recs, err := cr.ReadAll(); err == nil { | ||
if len(recs) < 1 { | ||
return errors.New("No csv records found") | ||
} | ||
for _, rec := range recs { | ||
for i, id := range rec { | ||
// An empty string appearing after last comma. We filter it. | ||
if id == "" && i == len(rec)-1 { | ||
continue | ||
} | ||
if nextInt, err2 := strconv.ParseUint(id, 10, 32); err == nil { | ||
da.Tiles = append(da.Tiles, TileData{GID: uint32(nextInt)}) | ||
} else { | ||
return err2 | ||
} | ||
} | ||
} | ||
if len(da.Tiles) < 1 { | ||
return errors.New("No Data Returned") | ||
} | ||
} else { | ||
return err | ||
} | ||
return nil | ||
} | ||
var breader io.Reader | ||
if da.Encoding == "base64" { | ||
buff, err := base64.StdEncoding.DecodeString(strings.TrimSpace(da.Inner)) | ||
if err != nil { | ||
return err | ||
} | ||
breader = bytes.NewReader(buff) | ||
} else { | ||
return errors.New("Unknown Encoding") | ||
} | ||
// Setup decompression if needed | ||
var zreader io.Reader | ||
if da.Compression == "" { | ||
zreader = breader | ||
} else if da.Compression == "zlib" { | ||
z, err := zlib.NewReader(breader) | ||
if err != nil { | ||
return err | ||
} | ||
defer z.Close() | ||
zreader = z | ||
} else if da.Compression == "gzip" { | ||
z, err := gzip.NewReader(breader) | ||
if err != nil { | ||
return err | ||
} | ||
defer z.Close() | ||
zreader = z | ||
} else { | ||
return errors.New("Unknown Compression") | ||
} | ||
var nextInt uint32 | ||
for { | ||
err := binary.Read(zreader, binary.LittleEndian, &nextInt) | ||
if err != nil { | ||
if err == io.EOF { | ||
break | ||
} | ||
return err | ||
} | ||
g, f := decodeGID(nextInt) | ||
da.Tiles = append(da.Tiles, TileData{ | ||
RawGID: nextInt, | ||
GID: g, | ||
Flipping: f, | ||
}) | ||
} | ||
return nil | ||
} | ||
|
||
func decodeGID(u uint32) (uint32, uint32) { | ||
h := u & HorizontalFlipFlag | ||
v := u & VerticalFlipFlag | ||
d := u & DiagonalFlipFlag | ||
ret := u & ^(HorizontalFlipFlag | VerticalFlipFlag | DiagonalFlipFlag) | ||
return ret, h | v | d | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package tmx | ||
|
||
import "encoding/xml" | ||
|
||
// Layer is a layer of the map | ||
type Layer struct { | ||
// Name is the name of the layer | ||
Name string `xml:"name,attr"` | ||
// X is the x coordinate of the layer in tiles | ||
X int `xml:"x,attr"` | ||
// Y is the y coordinate of the layer in tiles | ||
Y int `xml:"y,attr"` | ||
// Width is the width of the layer in tiles. Always the same as the map | ||
// width for fixed-size maps. | ||
Width int `xml:"width,attr"` | ||
// Height is the height of the layer in tiles. Always the same as the map | ||
// height for fixed-size maps. | ||
Height int `xml:"height,attr"` | ||
// Opacity is the opacity of the layer as a value from 0 to 1. Defaults to 1. | ||
Opacity int `xml:"opacity,attr"` | ||
// Visible is whether the layer is shown(1) or hidden(0). Defaults to 1. | ||
Visible int `xml:"visible,attr"` | ||
// OffsetX is the rendering offset for this layer in pixels. | ||
OffsetX float64 `xml:"offsetx,attr"` | ||
// OffsetY is the rendering offset for this layer in pixels. | ||
OffsetY float64 `xml:"offsety,attr"` | ||
// Properties are the properties of the layer | ||
Properties []Property `xml:"properties>property"` | ||
// Data is any data for the layer | ||
Data []Data `xml:"data"` | ||
} | ||
|
||
// UnmarshalXML implements the encoding/xml Unmarshaler interface | ||
func (l *Layer) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { | ||
type layer Layer | ||
la := layer{ | ||
Opacity: 1, | ||
Visible: 1, | ||
} | ||
if err := d.DecodeElement(&la, &start); err != nil { | ||
return err | ||
} | ||
*l = (Layer)(la) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package tmx | ||
|
||
import "encoding/xml" | ||
|
||
// Map is the root element of a TMX map | ||
type Map struct { | ||
// Version is the TMX format version | ||
Version string `xml:"version,attr"` | ||
// TiledVersion is the Version of Tiled Map Editor used to generate the TMX | ||
TiledVersion string `xml:"tiledversion,attr"` | ||
// Orientation is the orientation of the map. Tiled supports “orthogonal”, | ||
// “isometric”, “staggered” and “hexagonal” | ||
Orientation string `xml:"orientation,attr"` | ||
// RenderOrder is The order in which tiles on tile layers are rendered. | ||
// Valid values are right-down (the default), right-up, left-down and left-up. | ||
// In all cases, the map is drawn row-by-row. | ||
// (only supported for orthogonal maps at the moment) | ||
RenderOrder string `xml:"renderorder,attr"` | ||
// Width is the map width in tiles | ||
Width int `xml:"width,attr"` | ||
// Height is the map height in tiles | ||
Height int `xml:"height,attr"` | ||
// TileWidth is the width of each tile in pixels | ||
TileWidth int `xml:"tilewidth,attr"` | ||
// TileHeight is the height of each tile in pixels | ||
TileHeight int `xml:"tileheight,attr"` | ||
// HexSideLength determines the width or height (depending on the staggered | ||
// axis) of the tile’s edge, in pixels. Only for hexagonal maps. | ||
HexSideLength int `xml:"hexsidelength,attr"` | ||
// StaggerAxis is for staggered and hexagonal maps, determines which axis | ||
// (“x” or “y”) is staggered. | ||
StaggerAxis string `xml:"staggeraxis,attr"` | ||
// StaggerIndex is for staggered and hexagonal maps, determines whether the | ||
// “even” or “odd” indexes along the staggered axis are shifted. | ||
StaggerIndex string `xml:"staggerindex,attr"` | ||
// BackgroundColor is the background color of the map. Is of the form #AARRGGBB | ||
BackgroundColor string `xml:"backgroundcolor,attr"` | ||
// NextObjectID stores the next object id available for new objects. | ||
NextObjectID int `xml:"nextobjectid,attr"` | ||
// Properties are the properties of the map | ||
Properties []Property `xml:"properties>property"` | ||
// Tilesets are the tilesets of the map | ||
Tilesets []Tileset `xml:"tileset"` | ||
// Layers are the layers of the map | ||
Layers []Layer `xml:"layer"` | ||
// ObjectGroups are the object groups of the map | ||
ObjectGroups []ObjectGroup `xml:"objectgroup"` | ||
// ImageLayers are the image layers of the map | ||
ImageLayers []ImageLayer `xml:"imagelayer"` | ||
// Groups are the groups of the map | ||
Groups []Group `xml:"group"` | ||
} | ||
|
||
// UnmarshalXML implements the encoding/xml Unmarshaler interface | ||
func (m *Map) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { | ||
type maph Map | ||
ma := maph{ | ||
RenderOrder: "right-down", | ||
} | ||
if err := d.DecodeElement(&ma, &start); err != nil { | ||
return err | ||
} | ||
*m = (Map)(ma) | ||
return nil | ||
} |
Oops, something went wrong.