diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/canvas/AutoTileCanvas.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/canvas/AutoTileCanvas.kt new file mode 100644 index 00000000..182e5e28 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/canvas/AutoTileCanvas.kt @@ -0,0 +1,99 @@ +package com.bartlomiejpluta.base.editor.autotile.canvas + +import com.bartlomiejpluta.base.editor.autotile.model.AutoTile +import com.bartlomiejpluta.base.editor.map.model.layer.AutoTileLayer +import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM +import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM +import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent +import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler +import com.bartlomiejpluta.base.editor.render.model.Renderable +import javafx.scene.canvas.GraphicsContext +import javafx.scene.input.MouseButton +import javafx.scene.input.MouseEvent +import javafx.scene.paint.Color +import kotlin.math.roundToInt + +class AutoTileCanvas(private val editorStateVM: EditorStateVM, private val gameMapVM: GameMapVM, private val selection: AutoTileSelection) : Renderable, + MapMouseEventHandler { + private var mouseRow = -1 + private var mouseColumn = -1 + + override fun render(gc: GraphicsContext) { + gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height) + + if (editorStateVM.selectedLayer is AutoTileLayer) { + val autoTile = (editorStateVM.selectedLayer as AutoTileLayer).autoTile + renderBackground(gc) + renderTiles(gc, autoTile) + renderGrid(gc, autoTile) + selection.render(gc) + } + } + + private fun renderBackground(gc: GraphicsContext) { + for (x in 0 until (gc.canvas.width / BACKGROUND_TILE_WIDTH).roundToInt()) { + for (y in 0 until (gc.canvas.height / BACKGROUND_TILE_HEIGHT).roundToInt()) { + gc.fill = when ((x + y) % 2) { + 0 -> BACKGROUND_COLOR1 + else -> BACKGROUND_COLOR2 + } + + gc.fillRect(x * BACKGROUND_TILE_WIDTH, y * BACKGROUND_TILE_HEIGHT, BACKGROUND_TILE_WIDTH, BACKGROUND_TILE_HEIGHT) + } + } + } + + private fun renderTiles(gc: GraphicsContext, autoTile: AutoTile) { + autoTile.islandSubTiles.forEachIndexed { i, (topLeft, topRight, bottomLeft, bottomRight) -> + val x = (i % autoTile.columns) * gameMapVM.tileWidth + val y = (i / autoTile.columns) * gameMapVM.tileHeight + gc.drawImage(topLeft, x, y) + gc.drawImage(topRight, x + gameMapVM.tileWidth/2, y) + gc.drawImage(bottomLeft, x, y + gameMapVM.tileHeight/2) + gc.drawImage(bottomRight, x + gameMapVM.tileWidth/2, y + gameMapVM.tileHeight/2) + + + } +// autoTile.forEach { row, column, tile -> +// gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height) +// } + } + + private fun renderGrid(gc: GraphicsContext, autoTile: AutoTile) { + gc.stroke = Color.BLACK + gc.lineWidth = 0.5 + + for (x in 0 until (gc.canvas.width / autoTile.tileWidth).roundToInt()) { + gc.strokeLine(x.toDouble() * autoTile.tileWidth, 0.0, x.toDouble() * autoTile.tileWidth, gc.canvas.height) + } + + for (y in 0 until (gc.canvas.height / autoTile.tileHeight).roundToInt()) { + gc.strokeLine(0.0, y.toDouble() * autoTile.tileHeight, gc.canvas.width, y.toDouble() * autoTile.tileHeight) + } + + val w = gc.canvas.width - 1 + val h = gc.canvas.height - 1 + + gc.strokeLine(0.0, 0.0, w, 0.0) + gc.strokeLine(w, 0.0, w, h) + gc.strokeLine(0.0, h, w, h) + gc.strokeLine(0.0, 0.0, 0.0, h) + } + + override fun handleMouseInput(event: MapMouseEvent) { + mouseRow = event.row + mouseColumn = event.column + + if(event.type == MouseEvent.MOUSE_PRESSED && event.button == MouseButton.PRIMARY) { + selection.select(event.row.toDouble(), event.column.toDouble()) + } + } + + + companion object { + private const val BACKGROUND_TILE_WIDTH = 5.0 + private const val BACKGROUND_TILE_HEIGHT = 5.0 + private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.0) + private val BACKGROUND_COLOR2 = Color.color(0.95, 0.95, 0.95, 1.0) + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/canvas/AutoTileSelection.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/canvas/AutoTileSelection.kt new file mode 100644 index 00000000..90dce922 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/canvas/AutoTileSelection.kt @@ -0,0 +1,52 @@ +package com.bartlomiejpluta.base.editor.autotile.canvas + +import com.bartlomiejpluta.base.editor.map.model.layer.AutoTileLayer +import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM +import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM +import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM +import com.bartlomiejpluta.base.editor.render.model.Renderable +import javafx.scene.canvas.GraphicsContext +import javafx.scene.paint.Color + +class AutoTileSelection(private val editorStateVM: EditorStateVM, private val gameMapVM: GameMapVM, private val brushVM: BrushVM) : + Renderable { + private var x = 0.0 + private var y = 0.0 + private var width = gameMapVM.tileWidth.toDouble() + private var height = gameMapVM.tileHeight.toDouble() + + + fun select(row: Double, column: Double) { + x = column * width + y = row * height + + if (editorStateVM.selectedLayer is AutoTileLayer) { + + } + +// if (editorStateVM.selectedLayer is TileLayer) { +// val tileSet = (editorStateVM.selectedLayer as TileLayer).tileSetProperty.value +// val brushArray = Array(rows) { rowIndex -> +// Array(columns) { columnIndex -> +// tileSet.getTile(firstRow + rowIndex, firstColumn + columnIndex) +// } +// } +// +// brushVM.item = Brush.of(brushArray) +// brushVM.commit() +// } + } + + override fun render(gc: GraphicsContext) { + gc.fill = SELECTION_FILL_COLOR + gc.fillRect(x, y, width, height) + + gc.stroke = SELECTION_STROKE_COLOR + gc.strokeRect(x, y, width, height) + } + + companion object { + private val SELECTION_FILL_COLOR = Color.color(0.0, 0.7, 1.0, 0.4) + private val SELECTION_STROKE_COLOR = Color.color(0.0, 0.7, 1.0, 1.0) + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/component/AutoTilePane.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/component/AutoTilePane.kt new file mode 100644 index 00000000..ba721bbb --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/component/AutoTilePane.kt @@ -0,0 +1,61 @@ +package com.bartlomiejpluta.base.editor.autotile.component + +import com.bartlomiejpluta.base.editor.autotile.canvas.AutoTileCanvas +import com.bartlomiejpluta.base.editor.autotile.canvas.AutoTileSelection +import com.bartlomiejpluta.base.editor.map.model.layer.AutoTileLayer +import com.bartlomiejpluta.base.editor.map.model.layer.Layer +import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM +import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM +import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM +import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent +import javafx.event.EventHandler +import javafx.scene.canvas.Canvas +import javafx.scene.input.MouseEvent + +class AutoTilePane(editorStateVM: EditorStateVM, private val gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas(), + EventHandler { + private val selection = AutoTileSelection(editorStateVM, gameMapVM, brushVM) + private val autoTileCanvas = AutoTileCanvas(editorStateVM, gameMapVM, selection) + + init { + onMouseMoved = this + onMouseDragged = this + onMousePressed = this + onMouseReleased = this + + updateSize(editorStateVM.selectedLayer) + + editorStateVM.selectedLayerProperty.addListener { _, _, layer -> + updateSize(layer) + } + + brushVM.itemProperty.addListener { _, _, _ -> render() } + + render() + } + + private fun updateSize(layer: Layer?) { + if (layer is AutoTileLayer) { + val tileSet = layer.autoTile + width = (tileSet.tileWidth * tileSet.columns).toDouble() + height = (tileSet.tileHeight * tileSet.rows).toDouble() + } else { + width = 0.0 + height = 0.0 + } + + render() + } + + private fun render() { + autoTileCanvas.render(graphicsContext2D) + } + + override fun handle(event: MouseEvent?) { + if (event != null) { + autoTileCanvas.handleMouseInput(MapMouseEvent.of(event, gameMapVM)) + } + + autoTileCanvas.render(graphicsContext2D) + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/view/editor/AutoTileView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/view/editor/AutoTileView.kt new file mode 100644 index 00000000..c0f56a8d --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/autotile/view/editor/AutoTileView.kt @@ -0,0 +1,21 @@ +package com.bartlomiejpluta.base.editor.autotile.view.editor + +import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM +import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM +import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM +import com.bartlomiejpluta.base.editor.autotile.component.AutoTilePane +import tornadofx.View +import tornadofx.plusAssign +import tornadofx.scrollpane + +class AutoTileView : View() { + private val gameMapVM = find() + private val brushVM = find() + private val editorStateVM = find() + + private val autoTilePane = AutoTilePane(editorStateVM, gameMapVM, brushVM) + + override val root = scrollpane { + this += autoTilePane + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt index 674637cc..4a15f210 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt @@ -1,5 +1,6 @@ package com.bartlomiejpluta.base.editor.map.view.editor +import com.bartlomiejpluta.base.editor.autotile.view.editor.AutoTileView import com.bartlomiejpluta.base.editor.command.context.UndoableScope import com.bartlomiejpluta.base.editor.command.service.UndoRedoService import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent @@ -8,6 +9,7 @@ import com.bartlomiejpluta.base.editor.main.component.EditorTab.Companion.REDO_S import com.bartlomiejpluta.base.editor.main.component.EditorTab.Companion.SAVE_SHORTCUT import com.bartlomiejpluta.base.editor.main.component.EditorTab.Companion.UNDO_SHORTCUT import com.bartlomiejpluta.base.editor.map.controller.MapController +import com.bartlomiejpluta.base.editor.map.model.layer.AutoTileLayer import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM @@ -29,6 +31,7 @@ class MapFragment : EditorFragment() { private val mapView = find() private val layersView = find() private val tileSetView = find() + private val autoTileView = find() private val toolbarView = find() private val statusBarView = find() private val layerParameters = find() @@ -39,6 +42,11 @@ class MapFragment : EditorFragment() { editorStateVM.selectedLayerProperty ) + private val isAutoTileLayerSelected = Bindings.createBooleanBinding( + { editorStateVM.selectedLayer is AutoTileLayer }, + editorStateVM.selectedLayerProperty + ) + override val root = borderpane { top = toolbarView.root @@ -59,6 +67,14 @@ class MapFragment : EditorFragment() { } } + item("Auto Tile", expanded = false) { + enableWhen(isAutoTileLayerSelected) + + this += autoTileView.root.apply { + maxHeightProperty().bind(this@item.heightProperty()) + } + } + item("Layer Parameters", expanded = false) { this += layerParameters } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt index 00d42741..1cb4b136 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt @@ -70,39 +70,6 @@ class TileSetCanvas(private val editorStateVM: EditorStateVM, private val select gc.strokeLine(0.0, 0.0, 0.0, h) } -// private fun createGrid(gc: GraphicsContext, chunkWidth: Int, chunkHeight: Int): WritableImage { -// val grid = WritableImage(gc.canvas.width.toInt(), gc.canvas.height.toInt()) -// -// val writer = grid.pixelWriter -// val color = Color.BLACK -// for (x in 0 until grid.width.toInt()) { -// for (y in 0 until grid.height.toInt()) { -// if (x % chunkWidth == 0) { -// writer.setColor(x, y, color) -// } -// -// if (y % chunkHeight == 0) { -// writer.setColor(x, y, color) -// } -// } -// } -// -// val lastX = grid.width.toInt() - 1 -// val lastY = grid.height.toInt() - 1 -// -// for (x in 0 until grid.width.toInt()) { -// writer.setColor(x, 0, color) -// writer.setColor(x, lastY, color) -// } -// -// for (y in 0 until grid.height.toInt()) { -// writer.setColor(0, y, color) -// writer.setColor(lastX, y, color) -// } -// -// return grid -// } - override fun handleMouseInput(event: MapMouseEvent) { mouseRow = event.row mouseColumn = event.column