diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAsset.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAsset.kt index 5c098daa..9af1d85e 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAsset.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAsset.kt @@ -1,7 +1,8 @@ package com.bartlomiejpluta.base.editor.autotile.asset import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset +import com.bartlomiejpluta.base.editor.autotile.model.AutoTile import com.bartlomiejpluta.base.editor.project.model.Project class AutoTileAsset(project: Project, uid: String, source: String, name: String) : - GraphicAsset(project.autoTilesDirectoryProperty, uid, source, name, 6, 4) \ No newline at end of file + GraphicAsset(project.autoTilesDirectoryProperty, uid, source, name, AutoTile.ROWS, AutoTile.COLUMNS) \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAssetData.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAssetData.kt index 796b2957..f7ff8c6b 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAssetData.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/asset/AutoTileAssetData.kt @@ -1,5 +1,6 @@ package com.bartlomiejpluta.base.editor.autotile.asset +import com.bartlomiejpluta.base.editor.autotile.model.AutoTile import javafx.beans.property.SimpleIntegerProperty import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleStringProperty @@ -11,10 +12,10 @@ class AutoTileAssetData { val nameProperty = SimpleStringProperty() var name by nameProperty - val rowsProperty = SimpleIntegerProperty(6) + val rowsProperty = SimpleIntegerProperty(AutoTile.ROWS) var rows by rowsProperty - val columnsProperty = SimpleIntegerProperty(4) + val columnsProperty = SimpleIntegerProperty(AutoTile.COLUMNS) var columns by columnsProperty val tileWidthProperty = SimpleIntegerProperty(1) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/model/AutoTile.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/model/AutoTile.kt index e15cff88..17e1afa2 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/model/AutoTile.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/model/AutoTile.kt @@ -1,12 +1,16 @@ package com.bartlomiejpluta.base.editor.autotile.model +import com.bartlomiejpluta.base.editor.map.model.layer.AutoTileLayer +import com.bartlomiejpluta.base.editor.util.ImageUtil import javafx.beans.property.ReadOnlyStringWrapper import javafx.beans.property.SimpleIntegerProperty import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleStringProperty import javafx.scene.image.Image +import tornadofx.div import tornadofx.getValue +// Algorithm source: https://love2d.org/forums/viewtopic.php?t=7826 class AutoTile(uid: String, name: String, image: Image) { val uidProperty = ReadOnlyStringWrapper(uid) val uid by uidProperty @@ -17,10 +21,10 @@ class AutoTile(uid: String, name: String, image: Image) { val imageProperty = SimpleObjectProperty(image) val image by imageProperty - val rowsProperty = SimpleIntegerProperty(6) + val rowsProperty = SimpleIntegerProperty(ROWS) val rows by rowsProperty - val columnsProperty = SimpleIntegerProperty(4) + val columnsProperty = SimpleIntegerProperty(COLUMNS) val columns by columnsProperty val tileWidthProperty = SimpleIntegerProperty(image.width.toInt() / columns) @@ -34,4 +38,121 @@ class AutoTile(uid: String, name: String, image: Image) { val heightProperty = SimpleIntegerProperty(tileHeight * rows) val height by heightProperty + + val halfWidthProperty = tileWidthProperty.div(2) + val halfWidth by halfWidthProperty + + val halfHeightProperty = tileWidthProperty.div(2) + val halfHeight by halfHeightProperty + + val islandSubTiles: Array + val topLeftSubTiles: Array + val topRightSubTiles: Array + val bottomLeftSubTiles: Array + val bottomRightSubTiles: Array + + init { + val islandTile = cropTile(0, 0) + val crossTile = cropTile(1, 0) + val topLeftCornerTile = cropTile(0, 1) + val topRightCornerTile = cropTile(1, 1) + val bottomLeftCornerTile = cropTile(0, 2) + val bottomRightCornerTile = cropTile(1, 2) + + /* + * Indexes: + * 0 - No connected tiles + * 1 - Left tile is connected + * 2 - Right tile is connected + * 3 - Left and Right tiles are connected + * 4 - Left, Right, and Center tiles are connected. + */ + val (tl3, tr3, bl3, br3) = cutSubTiles(crossTile) + val (tl0, tr2, bl1, br4) = cutSubTiles(topLeftCornerTile) + val (tl1, tr0, bl4, br2) = cutSubTiles(topRightCornerTile) + val (tl2, tr4, bl0, br1) = cutSubTiles(bottomLeftCornerTile) + val (tl4, tr1, bl2, br0) = cutSubTiles(bottomRightCornerTile) + + islandSubTiles = cutSubTiles(islandTile) + topLeftSubTiles = arrayOf(tl0, tl1, tl2, tl3, tl4) + topRightSubTiles = arrayOf(tr0, tr1, tr2, tr3, tr4) + bottomLeftSubTiles = arrayOf(bl0, bl1, bl2, bl3, bl4) + bottomRightSubTiles = arrayOf(br0, br1, br2, br3, br4) + } + + fun getTile(layer: AutoTileLayer, row: Int, column: Int): Array { + var topLeft = 0 + var topRight = 0 + var bottomLeft = 0 + var bottomRight = 0 + + // Top + if (row > 0 && layer.layer[row - 1][column]) { + topLeft += 2 + topRight += 1 + } + + // Bottom + if (row < layer.rows - 1 && layer.layer[row + 1][column]) { + bottomLeft += 1 + bottomRight += 2 + } + + // Left + if (column > 0 && layer.layer[row][column - 1]) { + topLeft += 1 + bottomLeft += 2 + } + + // Right + if (column < layer.columns - 1 && layer.layer[row][column + 1]) { + topRight += 2 + bottomRight += 1 + } + + // Top left + if (row > 0 && column > 0 && layer.layer[row - 1][column - 1] && topLeft == 3) { + topLeft = 4 + } + + // Top right + if (row > 0 && column < layer.columns - 1 && layer.layer[row - 1][column + 1] && topRight == 3) { + topRight = 4 + } + + // Bottom left + if (row < layer.rows - 1 && column > 0 && layer.layer[row + 1][column - 1] && bottomLeft == 3) { + bottomLeft = 4 + } + + // Bottom right + if (row < layer.rows - 1 && column < layer.columns - 1 && layer.layer[row + 1][column + 1] && bottomRight == 3) { + bottomRight = 4 + } + + if (topLeft == 0 && topRight == 0 && bottomLeft == 0 && bottomRight == 0) { + return islandSubTiles + } + + return arrayOf(topLeftSubTiles[topLeft], topRightSubTiles[topRight], bottomLeftSubTiles[bottomLeft], bottomRightSubTiles[bottomRight]) + } + + private fun cropTile(column: Int, row: Int) = + ImageUtil.cropImage(image, column * tileWidth, row * tileHeight, tileWidth, tileHeight) + + private fun cutSubTiles(tile: Image): Array { + val halfWidth = tileWidth / 2 + val halfHeight = tileHeight / 2 + val topLeft = ImageUtil.cropImage(tile, 0, 0, halfWidth, halfHeight) + val topRight = ImageUtil.cropImage(tile, halfWidth, 0, halfWidth, halfHeight) + val bottomLeft = ImageUtil.cropImage(tile, 0, halfHeight, halfWidth, halfHeight) + val bottomRight = ImageUtil.cropImage(tile, halfWidth, halfHeight, halfWidth, halfHeight) + + return arrayOf(topLeft, topRight, bottomLeft, bottomRight) + } + + companion object { + const val ROWS = 3 + const val COLUMNS = 2 + } } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt index 7f0a00f6..2fa46223 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt @@ -1,5 +1,6 @@ package com.bartlomiejpluta.base.editor.map.canvas +import com.bartlomiejpluta.base.editor.autotile.model.AutoTile import com.bartlomiejpluta.base.editor.map.model.enumeration.ImageLayerMode import com.bartlomiejpluta.base.editor.map.model.layer.* import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM @@ -129,33 +130,23 @@ class MapCanvas(val map: GameMapVM, private val editorStateVM: EditorStateVM, pr private fun renderAutoTileLayer(gc: GraphicsContext, layer: AutoTileLayer) { for ((row, columns) in layer.layer.withIndex()) { for ((column, tile) in columns.withIndex()) { - - if (tile) { - gc.fill = Color.BLACK - gc.fillOval(column.toDouble() * tileWidth, row.toDouble() * tileHeight, tileWidth, tileHeight) + if(tile) { + renderAutoTile(gc, layer.autoTile, layer, column, row) } - - var i = 0; - var total = 0 - for (x in max(column - 1, 0) .. min(column + 1, map.rows - 1)) { - for (y in max(row - 1, 0) .. min(row + 1, map.columns - 1)) { - if (layer.layer[y][x]) { - total += 2.0.pow(i).toInt() - } - - ++i - } - } - - gc.textAlign = TextAlignment.CENTER - gc.fill = Color.WHITE - gc.stroke = Color.WHITE - gc.globalAlpha = 1.0 - gc.fillText(total.toString(), column.toDouble() * tileWidth + tileWidth * 0.5 , row.toDouble() * tileHeight + 20) } } } + private fun renderAutoTile(gc: GraphicsContext, autoTile: AutoTile, layer: AutoTileLayer, column: Int, row: Int) { + val (topLeft, topRight, bottomLeft, bottomRight) = autoTile.getTile(layer, row, column) + val x = column * tileWidth + val y = row * tileHeight + gc.drawImage(topLeft, x, y) + gc.drawImage(topRight, x + tileWidth/2, y) + gc.drawImage(bottomLeft, x, y + tileHeight/2) + gc.drawImage(bottomRight, x + tileWidth/2, y + tileHeight/2) + } + private fun renderObjectLayer(gc: GraphicsContext, objectLayer: ObjectLayer) { if (editorStateVM.selectedLayer !is ObjectLayer) { return diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt index 9347ca58..0838ae53 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt @@ -19,6 +19,12 @@ class AutoTileLayer( var layer = layer private set + var rows = rows + private set + + var columns = columns + private set + val autoTileAssetProperty = autoTileAsset.toProperty() var autoTileAsset by autoTileAssetProperty @@ -30,6 +36,9 @@ class AutoTileLayer( override val nameProperty = SimpleStringProperty(name) override fun resize(rows: Int, columns: Int) { + this.rows = rows + this.columns = columns + layer = Array(rows) { row -> Array(columns) { column -> layer.getOrNull(row)?.getOrNull(column) ?: false diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/util/ImageUtil.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/util/ImageUtil.kt new file mode 100644 index 00000000..1e40b5c3 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/util/ImageUtil.kt @@ -0,0 +1,19 @@ +package com.bartlomiejpluta.base.editor.util + +import javafx.scene.image.Image +import javafx.scene.image.PixelFormat +import javafx.scene.image.WritableImage +import java.nio.ByteBuffer + +object ImageUtil { + fun cropImage(image: Image, x: Int, y: Int, w: Int, h: Int): Image { + val reader = image.pixelReader + val buffer = ByteBuffer.allocate(w * h * 4) + reader.getPixels(x, y, w, h, PixelFormat.getByteBgraInstance(), buffer, 4 * w) + val output = WritableImage(w, h) + val writer = output.pixelWriter + writer.setPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), buffer, 4 * w) + + return output + } +} \ No newline at end of file