All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almasb.fxgl.entity.level.tiled.TilesetLoader.kt Maven / Gradle / Ivy

There is a newer version: 21.1
Show newest version
/*
 * FXGL - JavaFX Game Library. The MIT License (MIT).
 * Copyright (c) AlmasB ([email protected]).
 * See LICENSE for details.
 */

package com.almasb.fxgl.entity.level.tiled

import com.almasb.fxgl.texture.Texture
import com.almasb.sslogger.Logger
import javafx.scene.Node
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.image.WritableImage
import javafx.scene.paint.Color
import java.net.URL

/**
 *
 * @author Almas Baimagambetov ([email protected])
 */
class TilesetLoader(private val map: TiledMap, private val mapURL: URL) {

    private val log = Logger.get()

    private val imageCache = hashMapOf()

    fun loadView(gidArg: Int, isFlippedHorizontal: Boolean, isFlippedVertical: Boolean): Node {
        var gid = gidArg

        val tileset = findTileset(gid, map.tilesets)

        // we offset because data is encoded as continuous
        gid -= tileset.firstgid

        // image source
        val tilex = gid % tileset.columns
        val tiley = gid / tileset.columns

        val w = map.tilewidth
        val h = map.tileheight

        val buffer = WritableImage(w, h)

        val sourceImage = loadTilesetImage(tileset)

        buffer.pixelWriter.setPixels(0, 0,
                w, h, sourceImage.pixelReader,
                tilex * w + tileset.margin + tilex * tileset.spacing,
                tiley * h + tileset.margin + tiley * tileset.spacing)

        return ImageView(buffer).also {
            it.scaleX = if (isFlippedHorizontal) -1.0 else 1.0
            it.scaleY = if (isFlippedVertical) -1.0 else 1.0
        }
    }

    fun loadView(layerName: String): Node {
        log.debug("Loading view for layer $layerName")

        val layer = map.getLayerByName(layerName)

        val buffer = WritableImage(
                layer.width * map.tilewidth,
                layer.height * map.tileheight
        )

        log.debug("Created buffer with size ${buffer.width}x${buffer.height}")

        for (i in 0 until layer.data.size) {

            var gid = layer.data.get(i)

            // empty tile
            if (gid == 0)
                continue

            val tileset = findTileset(gid, map.tilesets)

            // we offset because data is encoded as continuous
            gid -= tileset.firstgid

            // image source
            val tilex = gid % tileset.columns
            val tiley = gid / tileset.columns

            // image destination
            val x = i % layer.width
            val y = i / layer.width

            val w = map.tilewidth
            val h = map.tileheight

            val sourceImage = loadTilesetImage(tileset)

            val srcx = tilex * w + tileset.margin + tilex * tileset.spacing
            val srcy = tiley * h + tileset.margin + tiley * tileset.spacing

            log.debug("Writing to buffer: dst=${x*w},${y*h}, w=$w,h=$h, src=$srcx,$srcy")

            buffer.pixelWriter.setPixels(x * w, y * h,
                    w, h, sourceImage.pixelReader,
                    srcx,
                    srcy)
        }

        return ImageView(buffer)
    }

    /**
     * Finds tileset where gid is located.
     *
     * @param gid tile id
     * @param tilesets all tilesets
     * @return tileset
     */
    private fun findTileset(gid: Int, tilesets: List): Tileset {
        for (tileset in tilesets) {
            if (gid >= tileset.firstgid && gid < tileset.firstgid + tileset.tilecount) {
                return tileset
            }

        }
        throw IllegalArgumentException("Tileset for gid=$gid not found")
    }

    private fun loadTilesetImage(tileset: Tileset): Image {
        var imageName = tileset.image
        imageName = imageName.substring(imageName.lastIndexOf("/") + 1)

        if (imageName in imageCache) {
            return imageCache[imageName]!!
        }

        val ext = mapURL.toExternalForm().substringBeforeLast("/") + "/"

        val image = if (tileset.transparentcolor.isEmpty())
            Image(ext + imageName)
        else
            Texture(Image(ext + imageName)).transparentColor(Color.web(tileset.transparentcolor)).image

        if (image.isError)
            throw IllegalArgumentException("${ext + imageName} cannot be loaded")

        imageCache[imageName] = image

        return image
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy