Newer
Older
kotlin-webgl-test / lib / kotludens / com / persesgames / map / tiled / TiledMap.kt
package com.persesgames.map.tiled

import com.persesgames.game.Game
import com.persesgames.net.getUrlAsString
import com.persesgames.texture.Texture
import com.persesgames.texture.Textures
import java.util.*

/**
 * Created by rnentjes on 22-7-16.
 */

class MapData {
    var version: Int = 1
    var properties: MutableMap<String, String> = HashMap()
    var layers: Array<MapLayer>? = null
    var tilesets: Array<MapTileset>? = null

    var height: Int = 0
    var width: Int = 0

    var nextobjectid: Int = 0
    var orientation: String =  "orthogonal"
    var renderorder: String =  "right-down"
    var tileheight: Int = 0
    var tilewidth: Int = 0
}

class MapLayer {
    var properties: MutableMap<String, String> = HashMap()

    var data: Array<Int>? = null
    var encoding: String = ""
    var x: Int = 0
    var y: Int = 0
    var width: Int = 0
    var height: Int = 0
    var name: String = ""
    var opacity: Float = 1f
    var type: String = ""
    var visible: Boolean = true
    var draworder: String = ""
}

class MapTileset {
    var properties: MutableMap<String, String> = HashMap()

    var firstgid: Int = 0
    var image: String = ""
    var imageheight: Int = 0
    var imagewidth: Int = 0
    var margin: Int = 0
    var name: String = ""
    var spacing: Int = 0
    var tilecount: Int = 0
    var tileheight: Int = 0
    var tilewidth: Int = 0
    var tileproperties: MutableMap<String, MutableMap<String, String>> = HashMap()
}

class TilesetIndex(
  val texture: Texture,
  val tcLeft: Float,
  val tcTop: Float,
  val tcRight: Float,
  val tcBottom: Float
  ) {
    fun render(x: Float, y: Float) {
        texture.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom)
    }
}

class TiledMap(dir: String = "", url: String) {
    val properties: Map<String, String> = HashMap()
    val data: MapData
    val tiles: Array<String>
    var first = true
    //var tilesetIndex: Array<TilesetIndex> = Array(0, { TilesetIndex() })

    init {
        var tileDir = dir
        if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
            tileDir = tileDir + "/"
        }

        data = JSON.parse<MapData>(getUrlAsString(tileDir + url))
        println("map data is loaded")
        val tilesets = data.tilesets
        if (tilesets != null) {
            tiles = Array(tilesets.size, { "" })
            for (index in 0..tilesets.size - 1) {
                tiles[index] = tilesets[index].name
                Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
            }
        } else {
            tiles = Array(0, { "" })
        }
    }

    fun drawTile(tile: Int, x: Float, y: Float) {
        if (first) {
            println("Draw $tileĀ on ($x, $y)")
        }
        val tilesets = data.tilesets
        var name: String? = null
        var gid: Int
        var tcLeft = 0f
        var tcTop = 0f
        var tcRight = 0f
        var tcBottom = 0f

        if (tilesets != null) {
            for (tileset in tilesets) {
                val tilesHor = tileset.imagewidth / tileset.tilewidth
                val tilesVer = tileset.imageheight / tileset.tileheight

                if (tile >= tileset.firstgid && tile < tileset.firstgid + tileset.tilecount) {
                    name = tileset.name
                    gid = tile - tileset.firstgid

                    val xi = gid % tilesHor
                    val yi = gid / tilesHor
                    val tw = 1f / tilesHor.toFloat()
                    val th = 1f / tilesVer.toFloat()

                    val pixelW = 0.1f / tileset.tilewidth
                    val pixelH = 0.1f / tileset.tileheight

                    tcLeft = xi * tw + pixelW
                    tcTop = yi * th + pixelH
                    tcRight = tcLeft + tw - pixelW
                    tcBottom = tcTop - th - pixelH
                }
            }
        }

        if (name != null) {
            val texture = Textures.get(name)

            texture.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom)
        }
    }

    fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
        var x = 0f
        var y = 0f
        val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
        val layer = layers[layerIndex]

        val layerData = layer.data
        if (layerData != null) {
            for (index in layerData.indices) {
                // todo: determine if in view
                // todo: determine tilewidth
                if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
                    drawTile(layerData[index], xo + x * 128f, yo + y * 128f)

                    when (data.renderorder) {
                        "right-down" -> {
                            x++
                            if (x > layer.width) {
                                x = 0f
                                y++
                            }
                        }
                        else -> {
                            throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
                        }
                    }
                }
            }
        }
        first = false
    }
}