[Editor] Create Auto Tile asset

This commit is contained in:
2022-08-26 18:18:53 +02:00
parent 843e0a9613
commit bf577471b3
14 changed files with 265 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ import com.bartlomiejpluta.base.editor.animation.asset.AnimationAsset
import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.asset.model.AssetCategory
import com.bartlomiejpluta.base.editor.audio.asset.SoundAsset
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
@@ -73,6 +74,7 @@ class AssetTreeCell(renameAsset: (asset: Asset, name: String) -> Asset, deleteAs
is AssetCategory -> FontIcon("fa-folder")
is GameMapAsset -> FontIcon("fa-map")
is TileSetAsset -> FontIcon("fa-th")
is AutoTileAsset -> FontIcon("fa-th-large")
is ImageAsset -> FontIcon("fa-image")
is CharacterSetAsset -> FontIcon("fa-male")
is AnimationAsset -> FontIcon("fa-film")

View File

@@ -26,6 +26,10 @@ class AssetsListView : View() {
menuitem("Import Tile Set...") { mainController.importTileSet() }
}
private val autoTiles = AssetCategory("Auto Tiles").apply {
menuitem("Import Auto Tile...") { mainController.importAutoTile() }
}
private val images = AssetCategory("Images").apply {
menuitem("Import Image...") { mainController.importImage() }
}
@@ -58,6 +62,7 @@ class AssetsListView : View() {
name = "Project", items = observableListOf(
maps,
tileSets,
autoTiles,
images,
characterSet,
animations,
@@ -74,6 +79,7 @@ class AssetsListView : View() {
rootItem.nameProperty.bind(it.nameProperty)
bindContent(maps.items, it.maps)
bindContent(tileSets.items, it.tileSets)
bindContent(autoTiles.items, it.autoTiles)
bindContent(images.items, it.images)
bindContent(characterSet.items, it.characterSets)
bindContent(animations.items, it.animations)

View File

@@ -0,0 +1,7 @@
package com.bartlomiejpluta.base.editor.autotile.asset
import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset
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)

View File

@@ -0,0 +1,28 @@
package com.bartlomiejpluta.base.editor.autotile.asset
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.SimpleStringProperty
import tornadofx.getValue
import tornadofx.setValue
import java.io.File
class AutoTileAssetData {
val nameProperty = SimpleStringProperty()
var name by nameProperty
val rowsProperty = SimpleIntegerProperty(6)
var rows by rowsProperty
val columnsProperty = SimpleIntegerProperty(4)
var columns by columnsProperty
val tileWidthProperty = SimpleIntegerProperty(1)
var tileWidth by tileWidthProperty
val tileHeightProperty = SimpleIntegerProperty(1)
var tileHeight by tileHeightProperty
val fileProperty = SimpleObjectProperty<File>()
var file by fileProperty
}

View File

@@ -0,0 +1,133 @@
package com.bartlomiejpluta.base.editor.autotile.view.importing
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAssetData
import com.bartlomiejpluta.base.editor.autotile.viewmodel.AutoTileAssetDataVM
import com.bartlomiejpluta.base.editor.util.fx.TextFieldUtil
import javafx.beans.property.SimpleObjectProperty
import javafx.scene.Cursor
import javafx.scene.image.Image
import javafx.stage.FileChooser
import tornadofx.*
class ImportAutoTileFragment : Fragment("Import Auto Tile") {
private val dataVM = find<AutoTileAssetDataVM>()
private val imagePreview = SimpleObjectProperty<Image?>()
private var onCompleteConsumer: ((AutoTileAssetData) -> Unit)? = null
init {
dataVM.fileProperty.addListener { _, _, file ->
when (file) {
null -> imagePreview.value = null
else -> file.inputStream().use { imagePreview.value = Image(it) }
}
}
imagePreview.addListener { _, _, image ->
image?.let {
dataVM.tileWidth = it.width.toInt() / dataVM.columns
dataVM.tileHeight = it.height.toInt() / dataVM.rows
}
}
}
fun onComplete(consumer: (AutoTileAssetData) -> Unit) {
this.onCompleteConsumer = consumer
}
override val root = form {
prefHeight = 480.0
fieldset("Import Auto Tile") {
hbox {
vbox {
scrollpane {
prefWidth = 300.0
prefHeightProperty().bind(this@form.heightProperty())
imageview(imagePreview)
tooltip = tooltip("Click to choose Auto Tile file")
cursor = Cursor.HAND
setOnMouseClicked {
dataVM.file = chooseFile(
title = "Select Auto Tile",
filters = arrayOf(FileChooser.ExtensionFilter("PNG Images (*.png)", "*.png"))
).getOrNull(0)
}
dataVM.validationContext.addValidator(this@vbox, dataVM.fileProperty) {
when {
it == null -> error("This field is required")
!it.exists() -> error("The file must exist")
else -> null
}
}
}
}
vbox {
paddingLeft = 20.0
field("Auto Tile Name") {
textfield(dataVM.nameProperty) {
required()
trimWhitespace()
}
}
field("Auto Tile Rows") {
enableWhen(false.toProperty())
spinner(min = 1, max = Integer.MAX_VALUE, property = dataVM.rowsProperty, editable = true) {
required()
editor.textFormatter = TextFieldUtil.integerFormatter(dataVM.rows)
}
}
field("Auto Tile Columns") {
enableWhen(false.toProperty())
spinner(min = 1, max = Integer.MAX_VALUE, property = dataVM.columnsProperty, editable = true) {
required()
editor.textFormatter = TextFieldUtil.integerFormatter(dataVM.columns)
}
}
field("Tile width") {
enableWhen(false.toProperty())
spinner(min = 1, max = Integer.MAX_VALUE, property = dataVM.tileWidthProperty, editable = true) {
required()
editor.textFormatter = TextFieldUtil.integerFormatter(dataVM.rows)
}
}
field("Tile height") {
enableWhen(false.toProperty())
spinner(min = 1, max = Integer.MAX_VALUE, property = dataVM.tileHeightProperty, editable = true) {
required()
editor.textFormatter = TextFieldUtil.integerFormatter(dataVM.columns)
}
}
}
}
}
buttonbar {
button("Import") {
action {
if (dataVM.commit()) {
onCompleteConsumer?.let { it(dataVM.item) }
close()
}
}
}
button("Reset") {
action { dataVM.rollback() }
}
button("Cancel") {
action { close() }
}
}
}
}

View File

@@ -0,0 +1,24 @@
package com.bartlomiejpluta.base.editor.autotile.viewmodel
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAssetData
import tornadofx.*
class AutoTileAssetDataVM : ItemViewModel<AutoTileAssetData>(AutoTileAssetData()) {
val nameProperty = bind(AutoTileAssetData::nameProperty)
var name by nameProperty
val rowsProperty = bind(AutoTileAssetData::rowsProperty)
var rows by rowsProperty
val columnsProperty = bind(AutoTileAssetData::columnsProperty)
var columns by columnsProperty
val tileWidthProperty = bind(AutoTileAssetData::tileWidthProperty)
var tileWidth by tileWidthProperty
val tileHeightProperty = bind(AutoTileAssetData::tileHeightProperty)
var tileHeight by tileHeightProperty
val fileProperty = bind(AutoTileAssetData::fileProperty)
var file by fileProperty
}

View File

@@ -28,6 +28,7 @@ class AssetMapCodeGenerator : CodeGenerator {
listOf(
generateMapAssetClass("maps", project.maps),
generateAssetClass("tilesets", project.tileSets),
generateAssetClass("autotiles", project.autoTiles),
generateAssetClass("charsets", project.characterSets),
generateAssetClass("images", project.images),
generateAssetClass("animations", project.animations),

View File

@@ -26,6 +26,7 @@ class DefaultProjectAssembler : ProjectAssembler {
private fun tryToAssembly(project: Project, targetJar: File) {
packager.pack(project.mapsDirectory, targetJar, "BOOT-INF/classes/project/maps")
packager.pack(project.tileSetsDirectory, targetJar, "BOOT-INF/classes/project/tilesets")
packager.pack(project.autoTilesDirectory, targetJar, "BOOT-INF/classes/project/autotiles")
packager.pack(project.imagesDirectory, targetJar, "BOOT-INF/classes/project/images")
packager.pack(project.characterSetsDirectory, targetJar, "BOOT-INF/classes/project/charsets")
packager.pack(project.animationsDirectory, targetJar, "BOOT-INF/classes/project/animations")

View File

@@ -8,6 +8,8 @@ import com.bartlomiejpluta.base.editor.asset.view.select.SelectGraphicAssetFragm
import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM
import com.bartlomiejpluta.base.editor.audio.view.importing.ImportSoundFragment
import com.bartlomiejpluta.base.editor.audio.viewmodel.SoundAssetDataVM
import com.bartlomiejpluta.base.editor.autotile.view.importing.ImportAutoTileFragment
import com.bartlomiejpluta.base.editor.autotile.viewmodel.AutoTileAssetDataVM
import com.bartlomiejpluta.base.editor.characterset.view.importing.ImportCharacterSetFragment
import com.bartlomiejpluta.base.editor.characterset.viewmodel.CharacterSetAssetDataVM
import com.bartlomiejpluta.base.editor.code.model.CodeScope
@@ -216,6 +218,20 @@ class MainController : Controller() {
}
}
fun importAutoTile() {
val vm = AutoTileAssetDataVM()
val scope = Scope()
setInScope(vm, scope)
find<ImportAutoTileFragment>(scope).apply {
onComplete {
projectContext.importAutoTile(it)
}
openModal(block = true, resizable = false)
}
}
fun importImage() {
val vm = ImageAssetDataVM()
val scope = Scope()
@@ -294,6 +310,7 @@ class MainController : Controller() {
}.showAndWait().map(::WidgetAssetData).map(projectContext::createWidget).ifPresent(this::openScript)
}
fun importSound() {
val vm = SoundAssetDataVM()
val scope = Scope()
@@ -308,7 +325,6 @@ class MainController : Controller() {
}
}
fun closeAsset(asset: Asset) {
when (asset) {
is GameMapAsset -> openItems.entries.firstOrNull { (_, item) -> item is GameMapVM && item.uid == asset.uid }?.key?.let {

View File

@@ -5,6 +5,8 @@ import com.bartlomiejpluta.base.editor.animation.asset.AnimationAssetData
import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.audio.asset.SoundAsset
import com.bartlomiejpluta.base.editor.audio.asset.SoundAssetData
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAssetData
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAssetData
import com.bartlomiejpluta.base.editor.code.model.Code
@@ -177,6 +179,19 @@ class DefaultProjectContext : ProjectContext {
}
}
override fun importAutoTile(data: AutoTileAssetData) {
project?.let {
UID.next(it.autoTiles.map(Asset::uid)).let { uid ->
val source = "$uid.${data.file.extension}"
val targetFile = File(it.autoTilesDirectory, source)
data.file.copyTo(targetFile)
it.autoTiles += AutoTileAsset(it, uid, source, data.name)
save()
}
}
}
override fun loadTileSet(uid: String) = tileSetCache.getOrPut(uid) {
project?.let {
val asset = it.tileSets.firstOrNull { tileSet -> tileSet.uid == uid }

View File

@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.editor.project.context
import com.bartlomiejpluta.base.editor.animation.asset.AnimationAssetData
import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.audio.asset.SoundAssetData
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAssetData
import com.bartlomiejpluta.base.editor.code.model.Code
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAssetData
import com.bartlomiejpluta.base.editor.file.model.FileNode
@@ -36,9 +37,11 @@ interface ProjectContext {
fun importTileSet(data: TileSetAssetData)
fun loadTileSet(uid: String): TileSet
fun findTileSetAsset(uid: String): TileSetAsset
fun importAutoTile(data: AutoTileAssetData)
fun findTileSetAsset(uid: String): TileSetAsset
fun importImage(data: ImageAssetData)
fun findImageAsset(uid: String): ImageAsset
fun loadImage(uid: String): Image
@@ -50,7 +53,6 @@ interface ProjectContext {
fun importIconSet(data: IconSetAssetData)
fun importFont(data: FontAssetData)
fun createWidget(data: WidgetAssetData): WidgetAsset
fun importSound(data: SoundAssetData)
fun deleteAsset(asset: Asset)

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.project.model
import com.bartlomiejpluta.base.editor.animation.asset.AnimationAsset
import com.bartlomiejpluta.base.editor.audio.asset.SoundAsset
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset
import com.bartlomiejpluta.base.editor.database.source.DataSource
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
@@ -37,6 +38,7 @@ class Project {
val maps = observableListOf<GameMapAsset>()
val tileSets = observableListOf<TileSetAsset>()
val autoTiles = observableListOf<AutoTileAsset>()
val images = observableListOf<ImageAsset>()
val characterSets = observableListOf<CharacterSetAsset>()
val animations = observableListOf<AnimationAsset>()
@@ -45,7 +47,7 @@ class Project {
val widgets = observableListOf<WidgetAsset>()
val sounds = observableListOf<SoundAsset>()
val assetLists = listOf(maps, tileSets, images, characterSets, animations, iconSets, fonts, widgets, sounds)
val assetLists = listOf(maps, tileSets, autoTiles, images, characterSets, animations, iconSets, fonts, widgets, sounds)
val mapsDirectoryProperty = SimpleObjectProperty<File>()
var mapsDirectory by mapsDirectoryProperty
@@ -55,6 +57,10 @@ class Project {
var tileSetsDirectory by tileSetsDirectoryProperty
private set
val autoTilesDirectoryProperty = SimpleObjectProperty<File>()
var autoTilesDirectory by autoTilesDirectoryProperty
private set
val imagesDirectoryProperty = SimpleObjectProperty<File>()
var imagesDirectory by imagesDirectoryProperty
private set
@@ -129,6 +135,7 @@ class Project {
dir?.let {
mapsDirectory = File(it, MAPS_DIR)
tileSetsDirectory = File(it, TILE_SETS_DIR)
autoTilesDirectory = File(it, AUTO_TILES)
imagesDirectory = File(it, IMAGES_DIR)
characterSetsDirectory = File(it, CHARACTER_SETS_DIR)
animationsDirectory = File(it, ANIMATIONS_DIR)
@@ -160,6 +167,7 @@ class Project {
sourceDirectory?.mkdirs()
mapsDirectory?.mkdirs()
tileSetsDirectory?.mkdirs()
autoTilesDirectory?.mkdirs()
imagesDirectory?.mkdirs()
characterSetsDirectory?.mkdirs()
animationsDirectory?.mkdirs()
@@ -178,6 +186,7 @@ class Project {
const val MAPS_DIR = "maps"
const val TILE_SETS_DIR = "tilesets"
const val AUTO_TILES = "autotiles"
const val IMAGES_DIR = "images"
const val CHARACTER_SETS_DIR = "charsets"
const val ANIMATIONS_DIR = "animations"

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.project.serial
import com.bartlomiejpluta.base.editor.animation.asset.AnimationAsset
import com.bartlomiejpluta.base.editor.audio.asset.SoundAsset
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
@@ -25,6 +26,7 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
runner = proto.runner
maps.addAll(proto.mapsList.map { deserializeMap(this, it) })
tileSets.addAll(proto.tileSetsList.map { deserializeTileSet(this, it) })
autoTiles.addAll(proto.autoTilesList.map { deserializeAutoTile(this, it) })
images.addAll(proto.imagesList.map { deserializeImage(this, it) })
characterSets.addAll(proto.characterSetsList.map { deserializeCharacterSet(this, it) })
animations.addAll(proto.animationsList.map { deserializeAnimation(this, it) })
@@ -50,6 +52,13 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
columns = tileSet.columns
)
private fun deserializeAutoTile(project: Project, autoTile: ProjectProto.AutoTileSetAsset) = AutoTileAsset(
project = project,
uid = autoTile.uid,
source = autoTile.source,
name = autoTile.name
)
private fun deserializeImage(project: Project, image: ProjectProto.ImageAsset) = ImageAsset(
project = project,
uid = image.uid,

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.project.serial
import com.bartlomiejpluta.base.editor.animation.asset.AnimationAsset
import com.bartlomiejpluta.base.editor.audio.asset.SoundAsset
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
@@ -23,6 +24,7 @@ class ProtobufProjectSerializer : ProjectSerializer {
proto.runner = item.runner
proto.addAllMaps(item.maps.map(this::serializeMap))
proto.addAllTileSets(item.tileSets.map(this::serializeTileSet))
proto.addAllAutoTiles(item.autoTiles.map(this::serializeAutoTile))
proto.addAllImages(item.images.map(this::serializeImage))
proto.addAllCharacterSets(item.characterSets.map(this::serializeCharacterSet))
proto.addAllAnimations(item.animations.map(this::serializeAnimation))
@@ -47,6 +49,12 @@ class ProtobufProjectSerializer : ProjectSerializer {
.setColumns(tileSet.columns)
.build()
private fun serializeAutoTile(autoTile: AutoTileAsset) = ProjectProto.AutoTileSetAsset.newBuilder()
.setUid(autoTile.uid)
.setSource(autoTile.source)
.setName(autoTile.name)
.build()
private fun serializeImage(image: ImageAsset) = ProjectProto.ImageAsset.newBuilder()
.setUid(image.uid)
.setSource(image.source)