[Editor] Enable displaying map
This commit is contained in:
@@ -34,4 +34,5 @@ compileTestKotlin {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
||||
implementation "no.tornado:tornadofx:${tornadoFxVersion}"
|
||||
implementation "org.joml:joml:${jomlVersion}"
|
||||
}
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
package com.bartlomiejpluta.base.editor
|
||||
|
||||
import com.bartlomiejpluta.base.editor.view.main.MainView
|
||||
import tornadofx.*
|
||||
|
||||
|
||||
class MyView : View() {
|
||||
override val root = vbox {
|
||||
button("Press me")
|
||||
label("Waiting")
|
||||
}
|
||||
}
|
||||
|
||||
class EditorApp : App(MyView::class)
|
||||
class EditorApp : App(MainView::class)
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
launch<EditorApp>(args)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.bartlomiejpluta.base.editor.controller.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.controller.tileset.TileSetController
|
||||
import com.bartlomiejpluta.base.editor.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.model.map.tileset.TileSet
|
||||
import tornadofx.Controller
|
||||
|
||||
class MapController : Controller() {
|
||||
private val tileSetController: TileSetController by inject()
|
||||
|
||||
val map = GameMap(tileSetController.tileset, 20, 20)
|
||||
.createTileLayer(0)
|
||||
.createTileLayer(3, 5)
|
||||
.createTileLayer(3, 5)
|
||||
.createTileLayer(3, 5)
|
||||
.createTileLayer(3, 5)
|
||||
.createTileLayer(3, 5)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.bartlomiejpluta.base.editor.controller.tileset
|
||||
|
||||
import com.bartlomiejpluta.base.editor.model.map.tileset.TileSet
|
||||
import tornadofx.Controller
|
||||
|
||||
class TileSetController : Controller() {
|
||||
val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.bartlomiejpluta.base.editor.model.map.layer
|
||||
|
||||
import com.bartlomiejpluta.base.editor.view.render.Renderable
|
||||
|
||||
interface Layer : Renderable
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.bartlomiejpluta.base.editor.model.map.layer
|
||||
|
||||
import com.bartlomiejpluta.base.editor.model.map.tileset.Tile
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
|
||||
class TileLayer(private val layer: Array<Array<Tile?>>) : Layer {
|
||||
|
||||
fun setTile(row: Int, column: Int, tile: Tile?) = apply { layer[row][column] = tile }
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
for ((row, columns) in layer.withIndex()) {
|
||||
for ((column, tile) in columns.withIndex()) {
|
||||
if (tile != null) {
|
||||
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.bartlomiejpluta.base.editor.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.model.map.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.model.map.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.model.map.tileset.Tile
|
||||
import com.bartlomiejpluta.base.editor.model.map.tileset.TileSet
|
||||
import com.bartlomiejpluta.base.editor.view.render.Renderable
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
|
||||
class Grid(private val tileSet: TileSet, private val rows: Int, private val columns: Int) : Renderable {
|
||||
private var tileWidth = tileSet.tileWidth.toDouble()
|
||||
private var tileHeight = tileSet.tileHeight.toDouble()
|
||||
private var mapWidth = columns * tileWidth
|
||||
private var mapHeight = rows * tileHeight
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
gc.lineWidth = LINE_WIDTH
|
||||
|
||||
for (row in 0 until rows) {
|
||||
gc.strokeLine(0.0, row * tileHeight, mapWidth, row * tileHeight)
|
||||
}
|
||||
|
||||
for (column in 0 until columns) {
|
||||
gc.strokeLine(column * tileWidth, 0.0, column * tileWidth, mapHeight)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LINE_WIDTH = 1.5
|
||||
}
|
||||
}
|
||||
|
||||
class GameMap(private val tileSet: TileSet, private val rows: Int, private val columns: Int) : Renderable {
|
||||
val layers = mutableListOf<Layer>()
|
||||
private val grid = Grid(tileSet, rows, columns)
|
||||
|
||||
val width = columns * tileSet.tileWidth
|
||||
|
||||
val height = columns * tileSet.tileWidth
|
||||
|
||||
fun createTileLayer(tile: Int) = createTileLayer().apply {
|
||||
val layerId = layers.size - 1
|
||||
for (row in 0 until rows) {
|
||||
for (column in 0 until columns) {
|
||||
setTile(layerId, row, column, tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createTileLayer(tileRow: Int, tileColumn: Int) = createTileLayer().apply {
|
||||
val layerId = layers.size - 1
|
||||
for (row in 0 until rows) {
|
||||
for (column in 0 until columns) {
|
||||
setTile(layerId, row, column, tileRow, tileColumn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createTileLayer() = apply { layers.add(TileLayer(Array(rows) { Array(columns) { null } })) }
|
||||
|
||||
fun setTile(layer: Int, row: Int, column: Int, tile: Int) = apply {
|
||||
(layers[layer] as TileLayer).setTile(row, column, tileSet.getTile(tile))
|
||||
}
|
||||
|
||||
fun setTile(layer: Int, row: Int, column: Int, tileRow: Int, tileColumn: Int) = apply {
|
||||
(layers[layer] as TileLayer).setTile(row, column, tileSet.getTile(tileRow, tileColumn))
|
||||
}
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
layers.forEach { it.render(gc) }
|
||||
grid.render(gc)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.bartlomiejpluta.base.editor.model.map.tileset
|
||||
|
||||
import javafx.scene.image.Image
|
||||
|
||||
import javafx.scene.image.PixelReader
|
||||
|
||||
import javafx.scene.image.WritableImage
|
||||
import javafx.scene.image.PixelWriter
|
||||
import javafx.scene.paint.Color
|
||||
|
||||
|
||||
class Tile(
|
||||
tileSet: TileSet,
|
||||
row: Int,
|
||||
column: Int,
|
||||
val image: Image,
|
||||
) {
|
||||
val id = row * tileSet.columns + column
|
||||
|
||||
private fun cloneImage(image: Image): Image {
|
||||
val height = image.height.toInt()
|
||||
val width = image.width.toInt()
|
||||
val pixelReader = image.pixelReader
|
||||
val writableImage = WritableImage(width, height)
|
||||
val pixelWriter = writableImage.pixelWriter
|
||||
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val color = pixelReader.getColor(x, y)
|
||||
pixelWriter.setColor(x, y, color)
|
||||
}
|
||||
}
|
||||
return writableImage
|
||||
}
|
||||
|
||||
fun scale(image: Image, factor: Int): Image {
|
||||
val width = image.width.toInt()
|
||||
val height = image.height.toInt()
|
||||
val output = WritableImage(width * factor, height * factor)
|
||||
|
||||
val reader: PixelReader = image.pixelReader
|
||||
val writer = output.pixelWriter
|
||||
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val argb = reader.getArgb(x, y)
|
||||
for (dy in 0 until factor) {
|
||||
for (dx in 0 until factor) {
|
||||
writer.setArgb(x * factor + dx, y * factor + dy, argb)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.bartlomiejpluta.base.editor.model.map.tileset
|
||||
|
||||
import javafx.scene.image.Image
|
||||
import javafx.scene.image.PixelFormat
|
||||
import javafx.scene.image.WritableImage
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
|
||||
class TileSet(private val image: Image, val rows: Int, val columns: Int) {
|
||||
val tileWidth = image.width.toInt() / columns
|
||||
|
||||
val tileHeight = image.height.toInt() / rows
|
||||
|
||||
private val tiles: Array<Array<Tile>> =
|
||||
Array(rows) { row -> Array(columns) { column -> cropTile(row, column) } }
|
||||
|
||||
private fun cropTile(row: Int, column: Int): Tile {
|
||||
val reader = image.pixelReader
|
||||
val buffer = ByteBuffer.allocate(tileWidth * tileHeight * 4)
|
||||
reader.getPixels(column * tileWidth, row * tileHeight, tileWidth, tileHeight, PixelFormat.getByteBgraInstance(), buffer, 4 * tileWidth)
|
||||
val tile = WritableImage(tileWidth, tileHeight)
|
||||
val writer = tile.pixelWriter
|
||||
writer.setPixels(0, 0, tileWidth, tileHeight, PixelFormat.getByteBgraInstance(), buffer, 4 * tileWidth)
|
||||
|
||||
return Tile(this, row, column, tile)
|
||||
}
|
||||
|
||||
fun getTile(row: Int, column: Int) = tiles[row][column]
|
||||
|
||||
fun getTile(id: Int) = tiles[id / rows][id % columns]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.bartlomiejpluta.base.editor.view.component.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.view.render.Renderer
|
||||
import javafx.scene.canvas.Canvas
|
||||
|
||||
class MapPane(map: GameMap) : Canvas() {
|
||||
private val renderer = Renderer(graphicsContext2D, map)
|
||||
|
||||
init {
|
||||
width = map.width.toDouble()
|
||||
height = map.height.toDouble()
|
||||
renderer.start()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.bartlomiejpluta.base.editor.view.fragment
|
||||
|
||||
import com.bartlomiejpluta.base.editor.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.view.component.map.MapPane
|
||||
import tornadofx.Fragment
|
||||
import tornadofx.group
|
||||
import tornadofx.plusAssign
|
||||
import tornadofx.scrollpane
|
||||
|
||||
class MapFragment : Fragment() {
|
||||
val map: GameMap by param()
|
||||
val pane = MapPane(map)
|
||||
|
||||
override val root = scrollpane {
|
||||
prefWidth = 300.0
|
||||
prefHeight = 300.0
|
||||
|
||||
group {
|
||||
group {
|
||||
this += pane
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/view/main/MainView.kt
Executable file
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/view/main/MainView.kt
Executable file
@@ -0,0 +1,14 @@
|
||||
package com.bartlomiejpluta.base.editor.view.main
|
||||
|
||||
import com.bartlomiejpluta.base.editor.controller.map.MapController
|
||||
import com.bartlomiejpluta.base.editor.view.fragment.MapFragment
|
||||
import tornadofx.View
|
||||
import tornadofx.borderpane
|
||||
|
||||
class MainView : View() {
|
||||
private val mapController: MapController by inject()
|
||||
|
||||
override val root = borderpane {
|
||||
center = find<MapFragment>(mapOf(MapFragment::map to mapController.map)).root
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.view.render
|
||||
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
|
||||
interface Renderable {
|
||||
fun render(gc: GraphicsContext)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.bartlomiejpluta.base.editor.view.render
|
||||
|
||||
import javafx.animation.AnimationTimer
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
|
||||
class Renderer(
|
||||
private val gc: GraphicsContext,
|
||||
private val renderable: Renderable
|
||||
) : AnimationTimer() {
|
||||
private var previous = System.nanoTime()
|
||||
|
||||
override fun handle(now: Long) {
|
||||
val dt = (now - previous) / 1000000000.0
|
||||
previous = now
|
||||
gc.isImageSmoothing = false
|
||||
|
||||
render()
|
||||
}
|
||||
|
||||
private fun render() {
|
||||
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height);
|
||||
|
||||
renderable.render(gc)
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,4 @@ springBootVersion=2.4.2
|
||||
springDependencyManagementVersion=1.0.11.RELEASE
|
||||
jomlVersion=1.10.0
|
||||
guavaVersion=29.0-jre
|
||||
tornadoFxVersion=2.0.0-SNAPSHOT
|
||||
tornadoFxVersion=2.0.0-SNAPSHOT
|
||||
Reference in New Issue
Block a user