[Editor] Introduce BrushVM view-model object

This commit is contained in:
2021-02-05 17:55:26 +01:00
parent 8f3fca3f4b
commit 7266b3fdac
9 changed files with 59 additions and 33 deletions

View File

@@ -4,7 +4,7 @@ import com.bartlomiejpluta.base.editor.model.tileset.Tile
import javafx.beans.property.SimpleIntegerProperty import javafx.beans.property.SimpleIntegerProperty
import tornadofx.* import tornadofx.*
class Brush { class Brush(newBrush: Array<Array<Tile>>) {
val brush = observableListOf<Tile>() val brush = observableListOf<Tile>()
val rowsProperty = SimpleIntegerProperty(this, "", 0) val rowsProperty = SimpleIntegerProperty(this, "", 0)
var rows by rowsProperty var rows by rowsProperty
@@ -15,10 +15,7 @@ class Brush {
val centerColumnProperty = SimpleIntegerProperty(0) val centerColumnProperty = SimpleIntegerProperty(0)
var centerColumn by centerColumnProperty var centerColumn by centerColumnProperty
init {
fun updateBrush(newBrush: Array<Array<Tile>>) {
brush.clear()
columns = 0
rowsProperty.value = newBrush.size rowsProperty.value = newBrush.size
newBrush.forEach { brush.addAll(it) } newBrush.forEach { brush.addAll(it) }
@@ -31,11 +28,9 @@ class Brush {
centerColumn = columns/2 centerColumn = columns/2
} }
fun tileAt(row: Int, column: Int) = brush[row * columns + column]
fun forEach(consumer: (row: Int, column: Int, tile: Tile) -> Unit) { fun forEach(consumer: (row: Int, column: Int, tile: Tile) -> Unit) {
brush.forEachIndexed { id, tile -> brush.forEachIndexed { id, tile ->
consumer(id / columns, id % columns, tile) consumer(id / columns, id % columns, tile)
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package com.bartlomiejpluta.base.editor.model.tileset package com.bartlomiejpluta.base.editor.model.tileset
import com.bartlomiejpluta.base.editor.model.map.brush.Brush
import javafx.scene.image.Image import javafx.scene.image.Image
import javafx.scene.image.PixelFormat import javafx.scene.image.PixelFormat
import javafx.scene.image.WritableImage import javafx.scene.image.WritableImage
@@ -15,6 +16,9 @@ class TileSet(private val image: Image, val rows: Int, val columns: Int) {
val tiles: Array<Array<Tile>> = val tiles: Array<Array<Tile>> =
Array(rows) { row -> Array(columns) { column -> cropTile(row, column) } } Array(rows) { row -> Array(columns) { column -> cropTile(row, column) } }
val baseBrush: Brush
get() = Brush(arrayOf(arrayOf(tiles[0][0])))
private fun cropTile(row: Int, column: Int): Tile { private fun cropTile(row: Int, column: Int): Tile {
val reader = image.pixelReader val reader = image.pixelReader
val buffer = ByteBuffer.allocate(tileWidth * tileHeight * 4) val buffer = ByteBuffer.allocate(tileWidth * tileHeight * 4)

View File

@@ -1,18 +1,18 @@
package com.bartlomiejpluta.base.editor.render.canvas.map package com.bartlomiejpluta.base.editor.render.canvas.map
import com.bartlomiejpluta.base.editor.model.map.brush.Brush
import com.bartlomiejpluta.base.editor.model.map.map.GameMap import com.bartlomiejpluta.base.editor.model.map.map.GameMap
import com.bartlomiejpluta.base.editor.model.tileset.Tile import com.bartlomiejpluta.base.editor.model.tileset.Tile
import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent
import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEventHandler import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEventHandler
import com.bartlomiejpluta.base.editor.render.model.Renderable import com.bartlomiejpluta.base.editor.render.model.Renderable
import com.bartlomiejpluta.base.editor.viewmodel.map.brush.BrushVM
import javafx.scene.canvas.GraphicsContext import javafx.scene.canvas.GraphicsContext
import javafx.scene.input.MouseButton import javafx.scene.input.MouseButton
import javafx.scene.input.MouseEvent import javafx.scene.input.MouseEvent
class MapPainter( class MapPainter(
private val map: GameMap, private val map: GameMap,
private val brush: Brush, private val brushVM: BrushVM,
private val paintingCallback: (MapPaintingTrace) -> Unit private val paintingCallback: (MapPaintingTrace) -> Unit
) : Renderable, MapMouseEventHandler { ) : Renderable, MapMouseEventHandler {
private val tileWidth = map.tileSet.tileWidth.toDouble() private val tileWidth = map.tileSet.tileWidth.toDouble()
@@ -27,7 +27,7 @@ class MapPainter(
val alpha = gc.globalAlpha val alpha = gc.globalAlpha
gc.globalAlpha = 0.4 gc.globalAlpha = 0.4
brush.forEach { row, column, tile -> renderTile(gc, tile, column, row) } brushVM.forEach { row, column, tile -> renderTile(gc, tile, column, row) }
gc.globalAlpha = alpha gc.globalAlpha = alpha
@@ -36,8 +36,8 @@ class MapPainter(
private fun renderTile(gc: GraphicsContext, tile: Tile, column: Int, row: Int) { private fun renderTile(gc: GraphicsContext, tile: Tile, column: Int, row: Int) {
gc.drawImage( gc.drawImage(
tile.image, tile.image,
tileWidth * (mouseColumn - brush.centerColumn + column), tileWidth * (mouseColumn - brushVM.centerColumn + column),
tileHeight * (mouseRow - brush.centerRow + row) tileHeight * (mouseRow - brushVM.centerRow + row)
) )
} }
@@ -55,8 +55,8 @@ class MapPainter(
private fun beginTrace(event: MapMouseEvent) { private fun beginTrace(event: MapMouseEvent) {
if (event.button == MouseButton.PRIMARY) { if (event.button == MouseButton.PRIMARY) {
currentTrace = MapPaintingTrace(map, "Paint trace").apply { currentTrace = MapPaintingTrace(map, "Paint trace").apply {
brush.forEach { row, column, tile -> brushVM.forEach { row, column, tile ->
paint(0, mouseRow - brush.centerRow + row, mouseColumn - brush.centerColumn + column, tile) paint(0, mouseRow - brushVM.centerRow + row, mouseColumn - brushVM.centerColumn + column, tile)
} }
} }
} }
@@ -65,8 +65,8 @@ class MapPainter(
private fun proceedTrace(event: MapMouseEvent) { private fun proceedTrace(event: MapMouseEvent) {
if (event.button == MouseButton.PRIMARY) { if (event.button == MouseButton.PRIMARY) {
currentTrace?.apply { currentTrace?.apply {
brush.forEach { row, column, tile -> brushVM.forEach { row, column, tile ->
paint(0, mouseRow - brush.centerRow + row, mouseColumn - brush.centerColumn + column, tile) paint(0, mouseRow - brushVM.centerRow + row, mouseColumn - brushVM.centerColumn + column, tile)
} }
} }
} }

View File

@@ -6,14 +6,15 @@ import com.bartlomiejpluta.base.editor.model.tileset.TileSet
import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent
import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEventHandler import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEventHandler
import com.bartlomiejpluta.base.editor.render.model.Renderable import com.bartlomiejpluta.base.editor.render.model.Renderable
import com.bartlomiejpluta.base.editor.viewmodel.map.brush.BrushVM
import javafx.scene.canvas.GraphicsContext import javafx.scene.canvas.GraphicsContext
import javafx.scene.input.MouseButton import javafx.scene.input.MouseButton
import javafx.scene.input.MouseEvent import javafx.scene.input.MouseEvent
import javafx.scene.paint.Color import javafx.scene.paint.Color
class TileSetCanvas(private val tileSet: TileSet, brush: Brush) : Renderable, MapMouseEventHandler { class TileSetCanvas(private val tileSet: TileSet, brushVM: BrushVM) : Renderable, MapMouseEventHandler {
private val tiles = tileSet.tiles private val tiles = tileSet.tiles
private var selection = TileSetSelection(tileSet, brush) private var selection = TileSetSelection(tileSet, brushVM)
private var mouseRow = -1 private var mouseRow = -1
private var mouseColumn = -1 private var mouseColumn = -1

View File

@@ -4,6 +4,7 @@ import com.bartlomiejpluta.base.editor.model.map.brush.Brush
import com.bartlomiejpluta.base.editor.model.tileset.Tile import com.bartlomiejpluta.base.editor.model.tileset.Tile
import com.bartlomiejpluta.base.editor.model.tileset.TileSet import com.bartlomiejpluta.base.editor.model.tileset.TileSet
import com.bartlomiejpluta.base.editor.render.model.Renderable import com.bartlomiejpluta.base.editor.render.model.Renderable
import com.bartlomiejpluta.base.editor.viewmodel.map.brush.BrushVM
import javafx.scene.canvas.GraphicsContext import javafx.scene.canvas.GraphicsContext
import javafx.scene.paint.Color import javafx.scene.paint.Color
import kotlin.math.abs import kotlin.math.abs
@@ -12,7 +13,7 @@ import kotlin.math.min
class TileSetSelection( class TileSetSelection(
private val tileSet: TileSet, private val tileSet: TileSet,
private val brush: Brush private val brushVM: BrushVM
) : Renderable { ) : Renderable {
private val tileWidth = tileSet.tileWidth.toDouble() private val tileWidth = tileSet.tileWidth.toDouble()
private val tileHeight = tileSet.tileHeight.toDouble() private val tileHeight = tileSet.tileHeight.toDouble()
@@ -67,7 +68,7 @@ class TileSetSelection(
} }
} }
brush.updateBrush(brushArray) brushVM.item = Brush(brushArray)
} }
override fun render(gc: GraphicsContext) { override fun render(gc: GraphicsContext) {

View File

@@ -1,20 +1,19 @@
package com.bartlomiejpluta.base.editor.view.component.map package com.bartlomiejpluta.base.editor.view.component.map
import com.bartlomiejpluta.base.editor.model.map.map.GameMap import com.bartlomiejpluta.base.editor.model.map.map.GameMap
import com.bartlomiejpluta.base.editor.model.tileset.Tile
import com.bartlomiejpluta.base.editor.render.canvas.map.MapCanvas
import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent
import com.bartlomiejpluta.base.editor.model.map.brush.Brush import com.bartlomiejpluta.base.editor.render.canvas.map.MapCanvas
import com.bartlomiejpluta.base.editor.render.canvas.map.MapPainter import com.bartlomiejpluta.base.editor.render.canvas.map.MapPainter
import com.bartlomiejpluta.base.editor.render.canvas.map.MapPaintingTrace import com.bartlomiejpluta.base.editor.render.canvas.map.MapPaintingTrace
import com.bartlomiejpluta.base.editor.viewmodel.map.brush.BrushVM
import javafx.event.EventHandler import javafx.event.EventHandler
import javafx.scene.canvas.Canvas import javafx.scene.canvas.Canvas
import javafx.scene.input.MouseEvent import javafx.scene.input.MouseEvent
class MapPane(map: GameMap, brush: Brush, paintingCallback: (MapPaintingTrace) -> Unit) : Canvas(), EventHandler<MouseEvent> { class MapPane(map: GameMap, brushVM: BrushVM, paintingCallback: (MapPaintingTrace) -> Unit) : Canvas(), EventHandler<MouseEvent> {
private var tileSet = map.tileSet private var tileSet = map.tileSet
private val painter = MapPainter(map, brush, paintingCallback) private val painter = MapPainter(map, brushVM, paintingCallback)
private val mapCanvas = MapCanvas(map, painter) private val mapCanvas = MapCanvas(map, painter)
init { init {

View File

@@ -5,12 +5,13 @@ import com.bartlomiejpluta.base.editor.model.tileset.Tile
import com.bartlomiejpluta.base.editor.model.tileset.TileSet import com.bartlomiejpluta.base.editor.model.tileset.TileSet
import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent import com.bartlomiejpluta.base.editor.render.canvas.input.MapMouseEvent
import com.bartlomiejpluta.base.editor.render.canvas.tileset.TileSetCanvas import com.bartlomiejpluta.base.editor.render.canvas.tileset.TileSetCanvas
import com.bartlomiejpluta.base.editor.viewmodel.map.brush.BrushVM
import javafx.event.EventHandler import javafx.event.EventHandler
import javafx.scene.canvas.Canvas import javafx.scene.canvas.Canvas
import javafx.scene.input.MouseEvent import javafx.scene.input.MouseEvent
class TileSetPane(private val tileSet: TileSet, brush: Brush) : Canvas(), EventHandler<MouseEvent> { class TileSetPane(private val tileSet: TileSet, brushVM: BrushVM) : Canvas(), EventHandler<MouseEvent> {
private val tileSetCanvas = TileSetCanvas(tileSet, brush) private val tileSetCanvas = TileSetCanvas(tileSet, brushVM)
init { init {
onMouseMoved = this onMouseMoved = this

View File

@@ -3,9 +3,9 @@ package com.bartlomiejpluta.base.editor.view.fragment
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent
import com.bartlomiejpluta.base.editor.model.map.map.GameMap import com.bartlomiejpluta.base.editor.model.map.map.GameMap
import com.bartlomiejpluta.base.editor.model.map.brush.Brush
import com.bartlomiejpluta.base.editor.view.component.map.MapPane import com.bartlomiejpluta.base.editor.view.component.map.MapPane
import com.bartlomiejpluta.base.editor.view.component.tileset.TileSetPane import com.bartlomiejpluta.base.editor.view.component.tileset.TileSetPane
import com.bartlomiejpluta.base.editor.viewmodel.map.brush.BrushVM
import javafx.beans.property.SimpleDoubleProperty import javafx.beans.property.SimpleDoubleProperty
import javafx.scene.input.MouseButton import javafx.scene.input.MouseButton
import javafx.scene.input.MouseEvent import javafx.scene.input.MouseEvent
@@ -16,12 +16,13 @@ import tornadofx.*
class MapFragment : Fragment() { class MapFragment : Fragment() {
private val undoRedoService: UndoRedoService by di() private val undoRedoService: UndoRedoService by di()
private val brush = Brush()
val scaleProperty = SimpleDoubleProperty(1.0)
val map: GameMap by param() val map: GameMap by param()
private val mapPane = MapPane(map, brush) { undoRedoService.push(it) } private val brushVM = find<BrushVM>()
private val tileSetPane = TileSetPane(map.tileSet, brush) val scaleProperty = SimpleDoubleProperty(1.0)
private val mapPane = MapPane(map, brushVM) { undoRedoService.push(it) }
private val tileSetPane = TileSetPane(map.tileSet, brushVM)
private val transformation = Scale(1.0, 1.0, 0.0, 0.0).apply { private val transformation = Scale(1.0, 1.0, 0.0, 0.0).apply {
xProperty().bind(scaleProperty) xProperty().bind(scaleProperty)
@@ -30,6 +31,7 @@ class MapFragment : Fragment() {
init { init {
subscribe<RedrawMapRequestEvent> { mapPane.render() } subscribe<RedrawMapRequestEvent> { mapPane.render() }
brushVM.item = map.tileSet.baseBrush
} }
override val root = borderpane { override val root = borderpane {

View File

@@ -0,0 +1,23 @@
package com.bartlomiejpluta.base.editor.viewmodel.map.brush
import com.bartlomiejpluta.base.editor.model.map.brush.Brush
import com.bartlomiejpluta.base.editor.model.tileset.Tile
import tornadofx.*
class BrushVM : ItemViewModel<Brush>(Brush(arrayOf(arrayOf()))) {
val brush = bind(Brush::brush)
val rowsProperty = bind(Brush::rowsProperty)
val rows by rowsProperty
val columnsProperty = bind(Brush::columnsProperty)
val columns by columnsProperty
val centerRowProperty = bind(Brush::centerRowProperty)
val centerRow by centerRowProperty
val centerColumnProperty = bind(Brush::centerColumnProperty)
val centerColumn by centerColumnProperty
fun forEach(consumer: (row: Int, column: Int, tile: Tile) -> Unit) = item.forEach(consumer)
}