|
@@ -1,17 +1,20 @@
|
|
|
package tile
|
|
|
|
|
|
+import "gitlab.com/beoran/ebsgo/monolog"
|
|
|
import "fmt"
|
|
|
+import "strings"
|
|
|
+import "bytes"
|
|
|
import "strconv"
|
|
|
import "io/ioutil"
|
|
|
import "compress/gzip"
|
|
|
import "compress/zlib"
|
|
|
-import "encoding/csv"
|
|
|
import "encoding/binary"
|
|
|
+import "encoding/base64"
|
|
|
|
|
|
|
|
|
import "gitlab.com/beoran/al5go/al"
|
|
|
|
|
|
-import "gitlab.com/beoran/ebsgo/engine/physics/camera"
|
|
|
+
|
|
|
import "gitlab.com/beoran/ebsgo/engine/fifi"
|
|
|
|
|
|
import "github.com/beevik/etree"
|
|
@@ -22,39 +25,39 @@ const (
|
|
|
TMX_FLIPPED_HORIZONTALLY = 0x80000000
|
|
|
TMX_FLIPPED_VERTICALLY = 0x40000000
|
|
|
TMX_FLIPPED_DIAGONALLY = 0x20000000
|
|
|
- TMX_FLIPPED_FILTER = (~0xE0000000)
|
|
|
+ TMX_FLIPPED_FILTER = (^uint32(0xE0000000))
|
|
|
)
|
|
|
|
|
|
|
|
|
-func AttrInt(e * etree.Element, string key) (int, error) {
|
|
|
+func AttrInt(e * etree.Element, key string) (int, error) {
|
|
|
return strconv.Atoi(e.SelectAttrValue(key, ""))
|
|
|
}
|
|
|
|
|
|
-func AttrFloat64(e * etree.Element, string key) (float64, error) {
|
|
|
+func AttrFloat64(e * etree.Element, key string) (float64, error) {
|
|
|
return strconv.ParseFloat(e.SelectAttrValue(key, ""), 64)
|
|
|
}
|
|
|
|
|
|
|
|
|
-func Property(e * etree.Element, propname string) string, bool {
|
|
|
- properties := e.FindElements('//properties/property')
|
|
|
+func Property(e * etree.Element, propname string) (string, bool) {
|
|
|
+ properties := e.FindElements("//properties/property")
|
|
|
|
|
|
- for property := range properties {
|
|
|
- name := e.SelectAttrValue("name", "")
|
|
|
+ for _, property := range properties {
|
|
|
+ name := property.SelectAttrValue("name", "")
|
|
|
if name == propname {
|
|
|
- return e.SelectAttrValue("value", ""), true
|
|
|
+ return property.SelectAttrValue("value", ""), true
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return "", false
|
|
|
}
|
|
|
|
|
|
-func PropertyInt(e * etree.Element, propname string) int, error {
|
|
|
+func PropertyInt(e * etree.Element, propname string) (int, error) {
|
|
|
value , ok := Property(e, propname)
|
|
|
if (!ok) {
|
|
|
return 0, fmt.Errorf("no such property")
|
|
|
}
|
|
|
|
|
|
- return strconv.Atoi(e.SelectAttrValue(key, ""))
|
|
|
+ return strconv.Atoi(value)
|
|
|
}
|
|
|
|
|
|
|
|
@@ -76,7 +79,9 @@ func LoadFrame(xml_frame * etree.Element, tile * Tile, set * Set) * Tile {
|
|
|
|
|
|
duration /= 1000.0
|
|
|
|
|
|
- tile.AddAnimationFrame(tile_id, duration)
|
|
|
+ frame := tile.AddAnimationFrame(tile_id, duration)
|
|
|
+
|
|
|
+ monolog.Log("TILEIO", "Frame loaded: %d %f", frame.Index, frame.Duration)
|
|
|
|
|
|
return tile
|
|
|
}
|
|
@@ -89,15 +94,18 @@ func LoadAnimation(xml_tile * etree.Element, tile * Tile, set * Set) * Tile {
|
|
|
}
|
|
|
|
|
|
xml_frames := xml_anim.FindElements("//frame")
|
|
|
- for xml_frame := range xml_frames {
|
|
|
+ for _, xml_frame := range xml_frames {
|
|
|
LoadFrame(xml_frame, tile, set)
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ monolog.Log("TILEIO", "Loaded animation: %d", len(tile.Frames))
|
|
|
return tile
|
|
|
}
|
|
|
|
|
|
-func XmlToTileType(xml_tile * etree.Element) int, error {
|
|
|
+func XmlToTileType(xml_tile * etree.Element) (uint, error) {
|
|
|
|
|
|
- value , ok := Property(e, "type")
|
|
|
+ value , ok := Property(xml_tile, "type")
|
|
|
if (!ok) {
|
|
|
return 0, fmt.Errorf("no type property")
|
|
|
}
|
|
@@ -114,17 +122,27 @@ func XmlToTileType(xml_tile * etree.Element) int, error {
|
|
|
|
|
|
func LoadTile(xml_tile * etree.Element, index int, set * Set, tm * Map) (*Tile, error) {
|
|
|
|
|
|
- if id, err := AttrInt(xml_tile, "id") ; err != nil {
|
|
|
- return nil, fmr.Errorf("Tile id not found: %s", err)
|
|
|
+ id, err := AttrInt(xml_tile, "id")
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("Tile id not found: %s", err)
|
|
|
}
|
|
|
|
|
|
tile := set.Tile(id)
|
|
|
+ monolog.Log("TILEIO", "Got tile: %d <- %d", tile.Active, tile.Index)
|
|
|
+
|
|
|
+
|
|
|
if tile == nil {
|
|
|
- return nil, fmr.Errorf("Tile id not found in tile set: %d", id)
|
|
|
+ return nil, fmt.Errorf("Tile id not found in tile set: %d", id)
|
|
|
}
|
|
|
|
|
|
- if tiletype, err := XmlToTileType(xml_tile) ; err == nil {
|
|
|
- tile.Type = tiletype
|
|
|
+ value , ok := Property(xml_tile, "type")
|
|
|
+ if (ok) {
|
|
|
+ parts := strings.Split(value, ",")
|
|
|
+ for _, part := range parts {
|
|
|
+ clean := strings.Trim(part, "")
|
|
|
+ tile.SetProperty(clean)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
@@ -146,16 +164,18 @@ func LoadTile(xml_tile * etree.Element, index int, set * Set, tm * Map) (*Tile,
|
|
|
tile.ShadowMask = ishadowmask
|
|
|
|
|
|
|
|
|
- return LoadAnimation(xml_tile, tile, set)
|
|
|
+ LoadAnimation(xml_tile, tile, set)
|
|
|
+ monolog.Log("TILEIO", "Loaded tile: (%d x %d)", tile.SheetX(tile.Tileset), tile.SheetY(tile.Tileset))
|
|
|
+ return tile, nil
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-func TmxTileIndexFlagsAndRotation(tmx_index int32) int, int, float32 {
|
|
|
+func TmxTileIndexFlagsAndRotation(tmx_index uint32) (int, int, float32) {
|
|
|
index := int(tmx_index & TMX_FLIPPED_FILTER)
|
|
|
- flags := 0
|
|
|
- rotate := 0.0
|
|
|
+ flags := int(0)
|
|
|
+ rotate := float32(0.0)
|
|
|
|
|
|
if (tmx_index & TMX_FLIPPED_HORIZONTALLY) != 0 {
|
|
|
flags |= al.FLIP_HORIZONTAL
|
|
@@ -165,15 +185,15 @@ func TmxTileIndexFlagsAndRotation(tmx_index int32) int, int, float32 {
|
|
|
flags |= al.FLIP_VERTICAL
|
|
|
}
|
|
|
|
|
|
- if (tmx_index & TMX_FLIPPED_DIAGONALLY) {
|
|
|
- rotate := al.PI / 2.0
|
|
|
+ if (tmx_index & TMX_FLIPPED_DIAGONALLY) != 0 {
|
|
|
+ rotate = float32(al.PI / 2.0)
|
|
|
}
|
|
|
|
|
|
return index, flags, rotate
|
|
|
}
|
|
|
|
|
|
|
|
|
-func LoadSet(xml_set * etree.Element, index int, tm * Map) * Set, error {
|
|
|
+func LoadSet(xml_set * etree.Element, index int, tm * Map) (* Set, error) {
|
|
|
firstgid, err := AttrInt(xml_set, "firstgid")
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("Could not find firstgid for tile set %d: %s", index, err)
|
|
@@ -185,8 +205,8 @@ func LoadSet(xml_set * etree.Element, index int, tm * Map) * Set, error {
|
|
|
return nil, fmt.Errorf("Could not find image data for tile set %d", index)
|
|
|
}
|
|
|
|
|
|
- tile_w, err := AttrInt("tilewidth")
|
|
|
- tile_h, err := AttrInt("tilewidth")
|
|
|
+ tile_w, err := AttrInt(xml_set, "tilewidth")
|
|
|
+ tile_h, err := AttrInt(xml_set, "tilewidth")
|
|
|
|
|
|
if (tile_w < 1) || (tile_h < 1) {
|
|
|
return nil, fmt.Errorf("Tile size too small for tile set %d: %d x %d", index, tile_w, tile_h)
|
|
@@ -194,55 +214,70 @@ func LoadSet(xml_set * etree.Element, index int, tm * Map) * Set, error {
|
|
|
|
|
|
iname := xml_image.SelectAttrValue("source", "tile_set_default.png")
|
|
|
bmp := fifi.LoadBitmap("map/" + iname)
|
|
|
+
|
|
|
+ if bmp == nil {
|
|
|
+ return nil, fmt.Errorf("Could not load tile set sheet: %s", iname)
|
|
|
+ }
|
|
|
+
|
|
|
set := NewSet(bmp, tile_w, tile_h, firstgid)
|
|
|
+ monolog.Log("TILEIO", "Loaded tile set: (%d x %d) (%d x %d) %d", set.TileW, set.TileH, set.W, set.H, set.FirstGID)
|
|
|
|
|
|
xml_tiles := xml_set.FindElements("//tile")
|
|
|
|
|
|
- for xml_tile, tile_index := range xml_tiles {
|
|
|
+ for tile_index, xml_tile := range xml_tiles {
|
|
|
LoadTile(xml_tile, tile_index, set, tm)
|
|
|
}
|
|
|
|
|
|
+ set.Recalculate()
|
|
|
+
|
|
|
return set, nil
|
|
|
}
|
|
|
|
|
|
-type Expander(in []byte) []byte, error
|
|
|
+type Expander func(in []byte) ([]byte, error)
|
|
|
|
|
|
-type Decoder(data string, w, h int, expand Expander) [][]uint32, error
|
|
|
+type Decoder func(data string, w, h int, expand Expander) ([][]uint32, error)
|
|
|
|
|
|
|
|
|
-func CsvDecoder(data string, w, h int, expand Expander) [][]uint32, error {
|
|
|
+func CsvDecoder(data string, w, h int, expand Expander) ([][]uint32, error) {
|
|
|
+ lines := strings.Split(data, "\n")
|
|
|
+ x := 0
|
|
|
+ y := 0
|
|
|
|
|
|
- r := csv.NewReader(strings.NewReader(data))
|
|
|
- records, err := r.ReadAll()
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- result := make([][]uint32, h)
|
|
|
- for i := 0 ; i < h; i++ {
|
|
|
- result[i] := make([]uint32, w)
|
|
|
- for j := 0 ; i < w ; j++ {
|
|
|
- res, err := strconv.ParseUint(records[i][j], 10, 32)
|
|
|
- if err != nil {
|
|
|
- result[i][j] = 0
|
|
|
- } else {
|
|
|
- result[i][j] = uint32(res)
|
|
|
+ result := make([][]uint32, h)
|
|
|
+ for _, line := range lines {
|
|
|
+ if line != "" {
|
|
|
+ cells := strings.Split(line, ",")
|
|
|
+ result[y] = make([]uint32, w)
|
|
|
+ for x = 0 ; x < w ; x++ {
|
|
|
+ value := uint32(0)
|
|
|
+ if ( x >= len(cells) ) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ res, err := strconv.ParseUint(cells[x], 10, 32)
|
|
|
+ if err == nil {
|
|
|
+ value = uint32(res)
|
|
|
+ }
|
|
|
+ result[y][x] = value
|
|
|
}
|
|
|
+ y++
|
|
|
+ }
|
|
|
+ if y >= h {
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
- return result
|
|
|
+ return result, nil
|
|
|
}
|
|
|
|
|
|
-func GzipExpander(in []byte) []byte, error {
|
|
|
- zr, err := gzip.NewReader(&in)
|
|
|
+func GzipExpander(in []byte) ([]byte, error) {
|
|
|
+ zr, err := gzip.NewReader(bytes.NewReader(in))
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return ioutil.ReadAll(zr)
|
|
|
}
|
|
|
|
|
|
-func ZlibExpander(in []byte) []byte, error {
|
|
|
- zr, err := lib.NewReader(&in)
|
|
|
+func ZlibExpander(in []byte) ([]byte, error) {
|
|
|
+ zr, err := zlib.NewReader(bytes.NewReader(in))
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
@@ -250,8 +285,8 @@ func ZlibExpander(in []byte) []byte, error {
|
|
|
}
|
|
|
|
|
|
|
|
|
-func Base64Decoder(data string, w, h int, expand Expander) [][]uint32, error {
|
|
|
- bytes, err := base64.StdEncoding.DecodeString()
|
|
|
+func Base64Decoder(data string, w, h int, expand Expander) ([][]uint32, error) {
|
|
|
+ bytes, err := base64.StdEncoding.DecodeString(data)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
@@ -265,7 +300,7 @@ func Base64Decoder(data string, w, h int, expand Expander) [][]uint32, error {
|
|
|
|
|
|
result := make([][]uint32, h)
|
|
|
for i := 0 ; i < h; i++ {
|
|
|
- result[i] := make([]uint32, w)
|
|
|
+ result[i] = make([]uint32, w)
|
|
|
for j := 0 ; i < w ; j++ {
|
|
|
index := (i * w + j) * 4
|
|
|
value := binary.LittleEndian.Uint32(bytes[index:4])
|
|
@@ -289,13 +324,13 @@ var Expanders map[string]Expander = map[string]Expander {
|
|
|
|
|
|
|
|
|
|
|
|
-func LoadPane(xml_pane * etree.Element, int index, tm * Map) (* Pane, error) {
|
|
|
- err, width := AttrInt(xml_pane, "width")
|
|
|
- err, height := AttrInt(xml_pane, "height")
|
|
|
+func LoadPane(xml_pane * etree.Element, index int, tm * Map) (* Pane, error) {
|
|
|
+ width, err := AttrInt(xml_pane, "width")
|
|
|
+ height, err := AttrInt(xml_pane, "height")
|
|
|
|
|
|
if (width < 1) || (height < 1) {
|
|
|
return nil,
|
|
|
- fmr.Errorf("Layer %i size too small: %d x %d, ", index, width, height)
|
|
|
+ fmt.Errorf("Layer %i size too small: %d x %d, ", index, width, height)
|
|
|
}
|
|
|
|
|
|
name := xml_pane.SelectAttrValue("name", "")
|
|
@@ -315,10 +350,10 @@ func LoadPane(xml_pane * etree.Element, int index, tm * Map) (* Pane, error) {
|
|
|
|
|
|
pane := NewPane(set, width, height, name)
|
|
|
|
|
|
- xml_data := xml_pane.FindElement('//data')
|
|
|
+ xml_data := xml_pane.FindElement("//data")
|
|
|
|
|
|
if xml_data == nil {
|
|
|
- return nil, fmr.Errorf("Cannot find layer data for layer %d", index)
|
|
|
+ return nil, fmt.Errorf("Cannot find layer data for layer %d", index)
|
|
|
}
|
|
|
|
|
|
encoding := xml_data.SelectAttrValue("encoding" , "csv")
|
|
@@ -335,25 +370,28 @@ func LoadPane(xml_pane * etree.Element, int index, tm * Map) (* Pane, error) {
|
|
|
grid, err := decoder(xml_data.Text(), width, height, expander)
|
|
|
|
|
|
if err != nil {
|
|
|
- return nil, fmt.Errorf("Could not decode data for layer %d: %s %s: %s",
|
|
|
- index, decoder, expander, err )
|
|
|
+ return nil, fmt.Errorf("Could not decode data for layer %d: %s %s: %s;\nData:>%s<",
|
|
|
+ index, encoding, compression, err, xml_data.Text())
|
|
|
}
|
|
|
|
|
|
- for y := 0 : y < height, y ++ {
|
|
|
- for x := 0 ; x < width ; x++ {
|
|
|
- tmx_index = grid[y][x]
|
|
|
+ monolog.Log("TILEIO", "Loaded grid size: (%d x %d) vs size (%d x %d)\n",len(grid), len(grid[0]), height, width)
|
|
|
+
|
|
|
+ for y := 0 ; y < height ; y ++ {
|
|
|
+ row := grid[y]
|
|
|
+ for x := 0 ; x < width && x < len(row) ; x++ {
|
|
|
+ tmx_index := row[x]
|
|
|
if tmx_index == 0 {
|
|
|
pane.SetTile(x, y, nil)
|
|
|
} else {
|
|
|
index, flags, rotation := TmxTileIndexFlagsAndRotation(tmx_index)
|
|
|
- if pane.Set == nil {
|
|
|
- pane.Set = tm.LookupTmxTileset(index)
|
|
|
+ if pane.Tileset == nil {
|
|
|
+ pane.Tileset = tm.LookupTmxTileset(index)
|
|
|
}
|
|
|
- ebs_index := index - pane.FirstGID + 1
|
|
|
+ ebs_index := index - pane.FirstGID()
|
|
|
cell := pane.Cell(x, y)
|
|
|
- cell.Tile = pane.Set.Tile(ebs_index)
|
|
|
- cell.Tile.Flags = flags
|
|
|
- cell.Tile.Rotate= rotation
|
|
|
+ cell.Tile = pane.Tileset.Tile(ebs_index)
|
|
|
+ cell.Flags = flags
|
|
|
+ cell.Rotate = rotation
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -363,16 +401,19 @@ func LoadPane(xml_pane * etree.Element, int index, tm * Map) (* Pane, error) {
|
|
|
|
|
|
|
|
|
func LoadMapXml(doc * etree.Document) (* Map, error) {
|
|
|
- root ::= doc.Root()
|
|
|
+ root := doc.Root()
|
|
|
if root.Tag != "map" {
|
|
|
return nil, fmt.Errorf("File is not a TMX map file: %s", root.Tag)
|
|
|
}
|
|
|
|
|
|
- if wide, err := AttrInt(root, "width"); err != nil {
|
|
|
+ wide, err := AttrInt(root, "width")
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
return nil, fmt.Errorf("Width not a number: %s", err)
|
|
|
}
|
|
|
|
|
|
- if high, err := AttrInt(root, "height"); err != nil {
|
|
|
+ high, err := AttrInt(root, "height");
|
|
|
+ if err != nil {
|
|
|
return nil, fmt.Errorf("Height not a number: %s", err)
|
|
|
}
|
|
|
|
|
@@ -382,21 +423,21 @@ func LoadMapXml(doc * etree.Document) (* Map, error) {
|
|
|
|
|
|
tm := NewMap(wide, high)
|
|
|
|
|
|
- xml_sets := root.FindElements('//tileset')
|
|
|
+ xml_sets := root.FindElements("//tileset")
|
|
|
|
|
|
- for xml_set, i := range xml_sets {
|
|
|
- set, err := LoadSet(xml_set, i)
|
|
|
+ for i, xml_set := range xml_sets {
|
|
|
+ set, err := LoadSet(xml_set, i, tm)
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("Could not load tile set: %s", err)
|
|
|
} else {
|
|
|
- set := tm.AddSet(set)
|
|
|
+ _ = tm.AddSet(set)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- xml_panes := root.FindElements('//layer')
|
|
|
+ xml_panes := root.FindElements("//layer")
|
|
|
|
|
|
- for xml_pane, i := range xml_panes {
|
|
|
- pane, err := LoadLayer(xml_pane, i, tm.Sets)
|
|
|
+ for i, xml_pane := range xml_panes {
|
|
|
+ pane, err := LoadPane(xml_pane, i, tm)
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("Could not load tile layer: %s", err)
|
|
|
} else {
|
|
@@ -411,10 +452,16 @@ func LoadMapXml(doc * etree.Document) (* Map, error) {
|
|
|
|
|
|
func LoadMap(filename string) (* Map, error) {
|
|
|
doc := etree.NewDocument()
|
|
|
- err = doc.ReadFromFile(filename)
|
|
|
+ err := doc.ReadFromFile(filename)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return LoadMapXml(doc)
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+func LoadMapFifi(relname string) (* Map, error) {
|
|
|
+ realname := fifi.Map(relname)
|
|
|
+ return LoadMap(realname)
|
|
|
+}
|
|
|
+
|