Migrate CRLF file endings to LF
This commit is contained in:
38
.gitattributes
vendored
Executable file → Normal file
38
.gitattributes
vendored
Executable file → Normal file
@@ -1,19 +1,19 @@
|
|||||||
#
|
#
|
||||||
# https://help.github.com/articles/dealing-with-line-endings/
|
# https://help.github.com/articles/dealing-with-line-endings/
|
||||||
#
|
#
|
||||||
# These are explicitly windows files and should use crlf
|
# These are explicitly windows files and should use crlf
|
||||||
*.bat text eol=crlf
|
*.bat text eol=crlf
|
||||||
|
|
||||||
# The rest of project files should use lf
|
# The rest of project files should use lf
|
||||||
*.gradle text eol=lf
|
*.gradle text eol=lf
|
||||||
*.kt text eol=lf
|
*.kt text eol=lf
|
||||||
*.yml text eol=lf
|
*.yml text eol=lf
|
||||||
*.java text eol=lf
|
*.java text eol=lf
|
||||||
*.fs text eol=lf
|
*.fs text eol=lf
|
||||||
*.vs text eol=lf
|
*.vs text eol=lf
|
||||||
*.properties text eol=lf
|
*.properties text eol=lf
|
||||||
*.proto text eol=lf
|
*.proto text eol=lf
|
||||||
gradlew text eol=lf
|
gradlew text eol=lf
|
||||||
|
|
||||||
# Binary files
|
# Binary files
|
||||||
*.jar binary
|
*.jar binary
|
||||||
|
|||||||
276
.gitignore
vendored
Executable file → Normal file
276
.gitignore
vendored
Executable file → Normal file
@@ -1,138 +1,138 @@
|
|||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/java,gradle,intellij
|
# Created by https://www.toptal.com/developers/gitignore/api/java,gradle,intellij
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,intellij
|
# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,intellij
|
||||||
|
|
||||||
### Intellij ###
|
### Intellij ###
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
# User-specific stuff
|
# User-specific stuff
|
||||||
.idea/
|
.idea/
|
||||||
# Gradle
|
# Gradle
|
||||||
.idea/**/gradle.xml
|
.idea/**/gradle.xml
|
||||||
.idea/**/libraries
|
.idea/**/libraries
|
||||||
|
|
||||||
# Gradle and Maven with auto-import
|
# Gradle and Maven with auto-import
|
||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
# auto-import.
|
# auto-import.
|
||||||
# .idea/artifacts
|
# .idea/artifacts
|
||||||
# .idea/compiler.xml
|
# .idea/compiler.xml
|
||||||
# .idea/jarRepositories.xml
|
# .idea/jarRepositories.xml
|
||||||
# .idea/modules.xml
|
# .idea/modules.xml
|
||||||
# .idea/*.iml
|
# .idea/*.iml
|
||||||
# .idea/modules
|
# .idea/modules
|
||||||
# *.iml
|
# *.iml
|
||||||
# *.ipr
|
# *.ipr
|
||||||
|
|
||||||
# CMake
|
# CMake
|
||||||
cmake-build-*/
|
cmake-build-*/
|
||||||
|
|
||||||
# Mongo Explorer plugin
|
# Mongo Explorer plugin
|
||||||
.idea/**/mongoSettings.xml
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
# File-based project format
|
# File-based project format
|
||||||
*.iws
|
*.iws
|
||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
out/
|
out/
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
# mpeltonen/sbt-idea plugin
|
||||||
.idea_modules/
|
.idea_modules/
|
||||||
|
|
||||||
# JIRA plugin
|
# JIRA plugin
|
||||||
atlassian-ide-plugin.xml
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
# Cursive Clojure plugin
|
# Cursive Clojure plugin
|
||||||
.idea/replstate.xml
|
.idea/replstate.xml
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
com_crashlytics_export_strings.xml
|
com_crashlytics_export_strings.xml
|
||||||
crashlytics.properties
|
crashlytics.properties
|
||||||
crashlytics-build.properties
|
crashlytics-build.properties
|
||||||
fabric.properties
|
fabric.properties
|
||||||
|
|
||||||
# Editor-based Rest Client
|
# Editor-based Rest Client
|
||||||
.idea/httpRequests
|
.idea/httpRequests
|
||||||
|
|
||||||
# Android studio 3.1+ serialized cache file
|
# Android studio 3.1+ serialized cache file
|
||||||
.idea/caches/build_file_checksums.ser
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
### Intellij Patch ###
|
### Intellij Patch ###
|
||||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
# *.iml
|
# *.iml
|
||||||
# modules.xml
|
# modules.xml
|
||||||
# .idea/misc.xml
|
# .idea/misc.xml
|
||||||
# *.ipr
|
# *.ipr
|
||||||
|
|
||||||
# Sonarlint plugin
|
# Sonarlint plugin
|
||||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||||
.idea/**/sonarlint/
|
.idea/**/sonarlint/
|
||||||
|
|
||||||
# SonarQube Plugin
|
# SonarQube Plugin
|
||||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||||
.idea/**/sonarIssues.xml
|
.idea/**/sonarIssues.xml
|
||||||
|
|
||||||
# Markdown Navigator plugin
|
# Markdown Navigator plugin
|
||||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||||
.idea/**/markdown-navigator.xml
|
.idea/**/markdown-navigator.xml
|
||||||
.idea/**/markdown-navigator-enh.xml
|
.idea/**/markdown-navigator-enh.xml
|
||||||
.idea/**/markdown-navigator/
|
.idea/**/markdown-navigator/
|
||||||
|
|
||||||
# Cache file creation bug
|
# Cache file creation bug
|
||||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||||
.idea/$CACHE_FILE$
|
.idea/$CACHE_FILE$
|
||||||
|
|
||||||
# CodeStream plugin
|
# CodeStream plugin
|
||||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||||
.idea/codestream.xml
|
.idea/codestream.xml
|
||||||
|
|
||||||
### Java ###
|
### Java ###
|
||||||
# Compiled class file
|
# Compiled class file
|
||||||
*.class
|
*.class
|
||||||
|
|
||||||
# Log file
|
# Log file
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# BlueJ files
|
# BlueJ files
|
||||||
*.ctxt
|
*.ctxt
|
||||||
|
|
||||||
# Mobile Tools for Java (J2ME)
|
# Mobile Tools for Java (J2ME)
|
||||||
.mtj.tmp/
|
.mtj.tmp/
|
||||||
|
|
||||||
# Package Files #
|
# Package Files #
|
||||||
*.jar
|
*.jar
|
||||||
*.war
|
*.war
|
||||||
*.nar
|
*.nar
|
||||||
*.ear
|
*.ear
|
||||||
*.zip
|
*.zip
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.rar
|
*.rar
|
||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
|
||||||
### Gradle ###
|
### Gradle ###
|
||||||
.gradle
|
.gradle
|
||||||
build/
|
build/
|
||||||
|
|
||||||
# Ignore Gradle GUI config
|
# Ignore Gradle GUI config
|
||||||
gradle-app.setting
|
gradle-app.setting
|
||||||
|
|
||||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
!gradle-wrapper.jar
|
!gradle-wrapper.jar
|
||||||
|
|
||||||
# Cache of project
|
# Cache of project
|
||||||
.gradletasknamecache
|
.gradletasknamecache
|
||||||
|
|
||||||
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||||
# gradle/wrapper/gradle-wrapper.properties
|
# gradle/wrapper/gradle-wrapper.properties
|
||||||
|
|
||||||
### Gradle Patch ###
|
### Gradle Patch ###
|
||||||
**/build/
|
**/build/
|
||||||
|
|
||||||
### Textures and other resources ###
|
### Textures and other resources ###
|
||||||
*.png
|
*.png
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/java,gradle,intellij
|
# End of https://www.toptal.com/developers/gitignore/api/java,gradle,intellij
|
||||||
|
|||||||
100
editor/build.gradle
Executable file → Normal file
100
editor/build.gradle
Executable file → Normal file
@@ -1,50 +1,50 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'org.jetbrains.kotlin.jvm' version '1.4.10'
|
id 'org.jetbrains.kotlin.jvm' version '1.4.10'
|
||||||
id 'org.openjfx.javafxplugin' version '0.0.8'
|
id 'org.openjfx.javafxplugin' version '0.0.8'
|
||||||
id 'org.springframework.boot' version "$springBootVersion"
|
id 'org.springframework.boot' version "$springBootVersion"
|
||||||
id 'io.spring.dependency-management' version "$springDependencyManagementVersion"
|
id 'io.spring.dependency-management' version "$springDependencyManagementVersion"
|
||||||
id 'idea'
|
id 'idea'
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'com.bartlomiejpluta.base'
|
group 'com.bartlomiejpluta.base'
|
||||||
version 'unspecified'
|
version 'unspecified'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.kotlin.srcDirs += 'src/main/kotlin'
|
main.kotlin.srcDirs += 'src/main/kotlin'
|
||||||
}
|
}
|
||||||
|
|
||||||
javafx {
|
javafx {
|
||||||
version = "11.0.2"
|
version = "11.0.2"
|
||||||
modules = ['javafx.controls', 'javafx.graphics']
|
modules = ['javafx.controls', 'javafx.graphics']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
compileKotlin {
|
compileKotlin {
|
||||||
kotlinOptions.jvmTarget = "14"
|
kotlinOptions.jvmTarget = "14"
|
||||||
}
|
}
|
||||||
|
|
||||||
compileTestKotlin {
|
compileTestKotlin {
|
||||||
kotlinOptions.jvmTarget = "14"
|
kotlinOptions.jvmTarget = "14"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":proto")
|
implementation project(":proto")
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
||||||
implementation "no.tornado:tornadofx:${tornadoFxVersion}"
|
implementation "no.tornado:tornadofx:${tornadoFxVersion}"
|
||||||
implementation platform("org.kordamp.ikonli:ikonli-bom:${ikonliVersion}")
|
implementation platform("org.kordamp.ikonli:ikonli-bom:${ikonliVersion}")
|
||||||
implementation 'org.kordamp.ikonli:ikonli-javafx'
|
implementation 'org.kordamp.ikonli:ikonli-javafx'
|
||||||
implementation 'org.kordamp.ikonli:ikonli-fontawesome-pack'
|
implementation 'org.kordamp.ikonli:ikonli-fontawesome-pack'
|
||||||
|
|
||||||
// Spring
|
// Spring
|
||||||
implementation 'org.springframework.boot:spring-boot-starter'
|
implementation 'org.springframework.boot:spring-boot-starter'
|
||||||
}
|
}
|
||||||
|
|
||||||
build {
|
build {
|
||||||
dependsOn(":proto:build")
|
dependsOn(":proto:build")
|
||||||
}
|
}
|
||||||
|
|||||||
68
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/App.kt
Executable file → Normal file
68
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/App.kt
Executable file → Normal file
@@ -1,35 +1,35 @@
|
|||||||
package com.bartlomiejpluta.base.editor
|
package com.bartlomiejpluta.base.editor
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.main.view.MainView
|
import com.bartlomiejpluta.base.editor.main.view.MainView
|
||||||
import org.springframework.boot.SpringApplication
|
import org.springframework.boot.SpringApplication
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.context.ConfigurableApplicationContext
|
import org.springframework.context.ConfigurableApplicationContext
|
||||||
import tornadofx.App
|
import tornadofx.App
|
||||||
import tornadofx.DIContainer
|
import tornadofx.DIContainer
|
||||||
import tornadofx.FX
|
import tornadofx.FX
|
||||||
import tornadofx.launch
|
import tornadofx.launch
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
open class EditorApp : App(MainView::class) {
|
open class EditorApp : App(MainView::class) {
|
||||||
private lateinit var context: ConfigurableApplicationContext
|
private lateinit var context: ConfigurableApplicationContext
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
this.context = SpringApplication.run(this.javaClass)
|
this.context = SpringApplication.run(this.javaClass)
|
||||||
context.autowireCapableBeanFactory.autowireBean(this)
|
context.autowireCapableBeanFactory.autowireBean(this)
|
||||||
|
|
||||||
FX.dicontainer = object : DIContainer {
|
FX.dicontainer = object : DIContainer {
|
||||||
override fun <T : Any> getInstance(type: KClass<T>): T = context.getBean(type.java)
|
override fun <T : Any> getInstance(type: KClass<T>): T = context.getBean(type.java)
|
||||||
override fun <T : Any> getInstance(type: KClass<T>, name: String): T = context.getBean(name, type.java)
|
override fun <T : Any> getInstance(type: KClass<T>, name: String): T = context.getBean(name, type.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stop() {
|
override fun stop() {
|
||||||
super.stop()
|
super.stop()
|
||||||
context.close()
|
context.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
launch<EditorApp>(args)
|
launch<EditorApp>(args)
|
||||||
}
|
}
|
||||||
4
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableContext.kt
Executable file → Normal file
4
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableContext.kt
Executable file → Normal file
@@ -1,3 +1,3 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.context
|
package com.bartlomiejpluta.base.editor.command.context
|
||||||
|
|
||||||
interface UndoableContext
|
interface UndoableContext
|
||||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableScope.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableScope.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.context
|
package com.bartlomiejpluta.base.editor.command.context
|
||||||
|
|
||||||
import tornadofx.Scope
|
import tornadofx.Scope
|
||||||
|
|
||||||
class UndoableScope : UndoableContext, Scope()
|
class UndoableScope : UndoableContext, Scope()
|
||||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Command.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Command.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.model.base
|
package com.bartlomiejpluta.base.editor.command.model.base
|
||||||
|
|
||||||
interface Command {
|
interface Command {
|
||||||
fun execute()
|
fun execute()
|
||||||
}
|
}
|
||||||
40
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/SimpleCommand.kt
Executable file → Normal file
40
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/SimpleCommand.kt
Executable file → Normal file
@@ -1,21 +1,21 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.model.base
|
package com.bartlomiejpluta.base.editor.command.model.base
|
||||||
|
|
||||||
class SimpleCommand<T>(
|
class SimpleCommand<T>(
|
||||||
override val commandName: String,
|
override val commandName: String,
|
||||||
private val formerValue: T,
|
private val formerValue: T,
|
||||||
private val value: T,
|
private val value: T,
|
||||||
private val execute: (T) -> Unit
|
private val execute: (T) -> Unit
|
||||||
) : Undoable, Command {
|
) : Undoable, Command {
|
||||||
|
|
||||||
override fun undo() {
|
override fun undo() {
|
||||||
execute(formerValue)
|
execute(formerValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo() {
|
override fun redo() {
|
||||||
execute()
|
execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
execute(value)
|
execute(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Undoable.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Undoable.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.model.base
|
package com.bartlomiejpluta.base.editor.command.model.base
|
||||||
|
|
||||||
interface Undoable {
|
interface Undoable {
|
||||||
fun undo()
|
fun undo()
|
||||||
fun redo()
|
fun redo()
|
||||||
val commandName: String
|
val commandName: String
|
||||||
}
|
}
|
||||||
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/CreateLayerCommand.kt
Executable file → Normal file
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/CreateLayerCommand.kt
Executable file → Normal file
@@ -1,23 +1,23 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.model.map
|
package com.bartlomiejpluta.base.editor.command.model.map
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
|
|
||||||
class CreateLayerCommand(private val map: GameMap, private val layer: Layer): Undoable, Command {
|
class CreateLayerCommand(private val map: GameMap, private val layer: Layer): Undoable, Command {
|
||||||
|
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
map.layers += layer
|
map.layers += layer
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun undo() {
|
override fun undo() {
|
||||||
map.layers -= layer
|
map.layers -= layer
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo() {
|
override fun redo() {
|
||||||
execute()
|
execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val commandName = "Create map layer"
|
override val commandName = "Create map layer"
|
||||||
}
|
}
|
||||||
42
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/MoveLayerCommand.kt
Executable file → Normal file
42
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/MoveLayerCommand.kt
Executable file → Normal file
@@ -1,22 +1,22 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.model.map
|
package com.bartlomiejpluta.base.editor.command.model.map
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
import tornadofx.swap
|
import tornadofx.swap
|
||||||
|
|
||||||
class MoveLayerCommand(private val map: GameMap, private val currentIndex: Int, private val newIndex: Int) : Undoable, Command {
|
class MoveLayerCommand(private val map: GameMap, private val currentIndex: Int, private val newIndex: Int) : Undoable, Command {
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
map.layers.swap(currentIndex, newIndex)
|
map.layers.swap(currentIndex, newIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun undo() {
|
override fun undo() {
|
||||||
map.layers.swap(newIndex, currentIndex)
|
map.layers.swap(newIndex, currentIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo() {
|
override fun redo() {
|
||||||
execute()
|
execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val commandName = "Move layer"
|
override val commandName = "Move layer"
|
||||||
}
|
}
|
||||||
48
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RemoveLayerCommand.kt
Executable file → Normal file
48
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RemoveLayerCommand.kt
Executable file → Normal file
@@ -1,25 +1,25 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.model.map
|
package com.bartlomiejpluta.base.editor.command.model.map
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
|
|
||||||
class RemoveLayerCommand(private val map: GameMap, private val layerIndex: Int) : Undoable, Command {
|
class RemoveLayerCommand(private val map: GameMap, private val layerIndex: Int) : Undoable, Command {
|
||||||
private var layer: Layer? = null
|
private var layer: Layer? = null
|
||||||
|
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
layer = map.layers.removeAt(layerIndex)
|
layer = map.layers.removeAt(layerIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun undo() {
|
override fun undo() {
|
||||||
map.layers.add(layerIndex, layer)
|
map.layers.add(layerIndex, layer)
|
||||||
layer = null
|
layer = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo() {
|
override fun redo() {
|
||||||
execute()
|
execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val commandName = "Remove layer"
|
override val commandName = "Remove layer"
|
||||||
}
|
}
|
||||||
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RenameLayerCommand.kt
Executable file → Normal file
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RenameLayerCommand.kt
Executable file → Normal file
@@ -1,23 +1,23 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.model.map
|
package com.bartlomiejpluta.base.editor.command.model.map
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
|
|
||||||
class RenameLayerCommand(private val layer: Layer, private val newName: String) : Undoable, Command {
|
class RenameLayerCommand(private val layer: Layer, private val newName: String) : Undoable, Command {
|
||||||
private val formerName = layer.name
|
private val formerName = layer.name
|
||||||
|
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
layer.name = newName
|
layer.name = newName
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun undo() {
|
override fun undo() {
|
||||||
layer.name = formerName
|
layer.name = formerName
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo() {
|
override fun redo() {
|
||||||
execute()
|
execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val commandName = "Rename layer"
|
override val commandName = "Rename layer"
|
||||||
}
|
}
|
||||||
242
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/DefaultUndoRedoService.kt
Executable file → Normal file
242
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/DefaultUndoRedoService.kt
Executable file → Normal file
@@ -1,122 +1,122 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.service
|
package com.bartlomiejpluta.base.editor.command.service
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.lang.Integer.toHexString
|
import java.lang.Integer.toHexString
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class DefaultUndoRedoService : UndoRedoService {
|
class DefaultUndoRedoService : UndoRedoService {
|
||||||
private val undo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
private val undo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
||||||
private val redo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
private val redo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
||||||
|
|
||||||
var sizeMax = 30
|
var sizeMax = 30
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value >= 0) {
|
if (value >= 0) {
|
||||||
for (i in 0 until undo.size - value) {
|
for (i in 0 until undo.size - value) {
|
||||||
undo.removeLast()
|
undo.removeLast()
|
||||||
}
|
}
|
||||||
|
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun push(undoable: Undoable) {
|
override fun push(undoable: Undoable) {
|
||||||
push(undoable, GLOBAL_CONTEXT)
|
push(undoable, GLOBAL_CONTEXT)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun push(undoable: Undoable, context: UndoableContext) {
|
override fun push(undoable: Undoable, context: UndoableContext) {
|
||||||
if (undo.size == sizeMax) {
|
if (undo.size == sizeMax) {
|
||||||
log.debug("The max size of [undo] stack has been reached. Removing the last item...")
|
log.debug("The max size of [undo] stack has been reached. Removing the last item...")
|
||||||
undo.removeLast()
|
undo.removeLast()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Pushing item to [undo] stack: ${undoable.commandName} (ctx: ${toHexString(context.hashCode())})")
|
log.debug("Pushing item to [undo] stack: ${undoable.commandName} (ctx: ${toHexString(context.hashCode())})")
|
||||||
undo.push(undoable to context)
|
undo.push(undoable to context)
|
||||||
redo.clear()
|
redo.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun undo() {
|
override fun undo() {
|
||||||
if (undo.isNotEmpty()) {
|
if (undo.isNotEmpty()) {
|
||||||
undo.pop().let {
|
undo.pop().let {
|
||||||
log.debug("Performing undo: ${it.first.commandName}")
|
log.debug("Performing undo: ${it.first.commandName}")
|
||||||
it.first.undo()
|
it.first.undo()
|
||||||
redo.push(it)
|
redo.push(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun undo(context: UndoableContext) {
|
override fun undo(context: UndoableContext) {
|
||||||
if (undo.isNotEmpty()) {
|
if (undo.isNotEmpty()) {
|
||||||
undo.firstOrNull { it.second === context }?.let {
|
undo.firstOrNull { it.second === context }?.let {
|
||||||
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) undo: ${it.first.commandName}")
|
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) undo: ${it.first.commandName}")
|
||||||
undo.remove(it)
|
undo.remove(it)
|
||||||
it.first.undo()
|
it.first.undo()
|
||||||
redo.push(it)
|
redo.push(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo() {
|
override fun redo() {
|
||||||
if (redo.isNotEmpty()) {
|
if (redo.isNotEmpty()) {
|
||||||
redo.pop().let {
|
redo.pop().let {
|
||||||
log.debug("Performing redo: ${it.first.commandName}")
|
log.debug("Performing redo: ${it.first.commandName}")
|
||||||
it.first.redo()
|
it.first.redo()
|
||||||
undo.push(it)
|
undo.push(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo(context: UndoableContext) {
|
override fun redo(context: UndoableContext) {
|
||||||
if (redo.isNotEmpty()) {
|
if (redo.isNotEmpty()) {
|
||||||
redo.firstOrNull { it.second === context }?.let {
|
redo.firstOrNull { it.second === context }?.let {
|
||||||
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) redo: ${it.first.commandName}")
|
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) redo: ${it.first.commandName}")
|
||||||
redo.remove(it)
|
redo.remove(it)
|
||||||
it.first.redo()
|
it.first.redo()
|
||||||
undo.push(it)
|
undo.push(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
log.debug("Clearing [undo] and [redo] stacks")
|
log.debug("Clearing [undo] and [redo] stacks")
|
||||||
undo.clear()
|
undo.clear()
|
||||||
redo.clear()
|
redo.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear(context: UndoableContext) {
|
override fun clear(context: UndoableContext) {
|
||||||
log.debug("Clearing [undo] and [redo] stacks (ctx: ${toHexString(context.hashCode())})")
|
log.debug("Clearing [undo] and [redo] stacks (ctx: ${toHexString(context.hashCode())})")
|
||||||
undo.removeIf { it.second == context }
|
undo.removeIf { it.second == context }
|
||||||
redo.removeIf { it.second == context }
|
redo.removeIf { it.second == context }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val lastUndoable: Undoable?
|
override val lastUndoable: Undoable?
|
||||||
get() = undo.first?.first
|
get() = undo.first?.first
|
||||||
|
|
||||||
override val lastRedoable: Undoable?
|
override val lastRedoable: Undoable?
|
||||||
get() = redo.first?.first
|
get() = redo.first?.first
|
||||||
|
|
||||||
override val undoCommandName: String
|
override val undoCommandName: String
|
||||||
get() = undo.first?.first?.commandName ?: ""
|
get() = undo.first?.first?.commandName ?: ""
|
||||||
|
|
||||||
override val redoCommandName: String
|
override val redoCommandName: String
|
||||||
get() = redo.first?.first?.commandName ?: ""
|
get() = redo.first?.first?.commandName ?: ""
|
||||||
|
|
||||||
override fun lastUndoable(context: UndoableContext) = undo.firstOrNull { it.second === context }?.first
|
override fun lastUndoable(context: UndoableContext) = undo.firstOrNull { it.second === context }?.first
|
||||||
|
|
||||||
override fun lastRedoable(context: UndoableContext) = redo.firstOrNull { it.second === context }?.first
|
override fun lastRedoable(context: UndoableContext) = redo.firstOrNull { it.second === context }?.first
|
||||||
|
|
||||||
override fun undoCommandName(context: UndoableContext) =
|
override fun undoCommandName(context: UndoableContext) =
|
||||||
undo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
undo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
||||||
|
|
||||||
override fun redoCommandName(context: UndoableContext) =
|
override fun redoCommandName(context: UndoableContext) =
|
||||||
redo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
redo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(DefaultUndoRedoService::class.java)
|
private val log = LoggerFactory.getLogger(DefaultUndoRedoService::class.java)
|
||||||
private val GLOBAL_CONTEXT = object : UndoableContext {}
|
private val GLOBAL_CONTEXT = object : UndoableContext {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/UndoRedoService.kt
Executable file → Normal file
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/UndoRedoService.kt
Executable file → Normal file
@@ -1,26 +1,26 @@
|
|||||||
package com.bartlomiejpluta.base.editor.command.service
|
package com.bartlomiejpluta.base.editor.command.service
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||||
|
|
||||||
interface UndoRedoService {
|
interface UndoRedoService {
|
||||||
fun push(undoable: Undoable)
|
fun push(undoable: Undoable)
|
||||||
fun undo()
|
fun undo()
|
||||||
fun redo()
|
fun redo()
|
||||||
fun clear()
|
fun clear()
|
||||||
|
|
||||||
fun push(undoable: Undoable, context: UndoableContext)
|
fun push(undoable: Undoable, context: UndoableContext)
|
||||||
fun undo(context: UndoableContext)
|
fun undo(context: UndoableContext)
|
||||||
fun redo(context: UndoableContext)
|
fun redo(context: UndoableContext)
|
||||||
fun clear(context: UndoableContext)
|
fun clear(context: UndoableContext)
|
||||||
|
|
||||||
val lastUndoable: Undoable?
|
val lastUndoable: Undoable?
|
||||||
val lastRedoable: Undoable?
|
val lastRedoable: Undoable?
|
||||||
val undoCommandName: String
|
val undoCommandName: String
|
||||||
val redoCommandName: String
|
val redoCommandName: String
|
||||||
|
|
||||||
fun lastUndoable(context: UndoableContext): Undoable?
|
fun lastUndoable(context: UndoableContext): Undoable?
|
||||||
fun lastRedoable(context: UndoableContext): Undoable?
|
fun lastRedoable(context: UndoableContext): Undoable?
|
||||||
fun undoCommandName(context: UndoableContext): String
|
fun undoCommandName(context: UndoableContext): String
|
||||||
fun redoCommandName(context: UndoableContext): String
|
fun redoCommandName(context: UndoableContext): String
|
||||||
}
|
}
|
||||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
package com.bartlomiejpluta.base.editor.common.serial
|
package com.bartlomiejpluta.base.editor.common.serial
|
||||||
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface Deserializer<T> {
|
interface Deserializer<T> {
|
||||||
fun deserialize(input: InputStream): T
|
fun deserialize(input: InputStream): T
|
||||||
}
|
}
|
||||||
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt
Executable file → Normal file
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
package com.bartlomiejpluta.base.editor.common.serial
|
package com.bartlomiejpluta.base.editor.common.serial
|
||||||
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
interface Serializer<T> {
|
interface Serializer<T> {
|
||||||
fun serialize(item: T, output: OutputStream)
|
fun serialize(item: T, output: OutputStream)
|
||||||
}
|
}
|
||||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/event/RedrawMapRequestEvent.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/event/RedrawMapRequestEvent.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
package com.bartlomiejpluta.base.editor.event
|
package com.bartlomiejpluta.base.editor.event
|
||||||
|
|
||||||
import tornadofx.EventBus.RunOn.ApplicationThread
|
import tornadofx.EventBus.RunOn.ApplicationThread
|
||||||
import tornadofx.EventBus.RunOn.BackgroundThread
|
import tornadofx.EventBus.RunOn.BackgroundThread
|
||||||
import tornadofx.FXEvent
|
import tornadofx.FXEvent
|
||||||
|
|
||||||
object RedrawMapRequestEvent : FXEvent(ApplicationThread)
|
object RedrawMapRequestEvent : FXEvent(ApplicationThread)
|
||||||
116
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt
Executable file → Normal file
116
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt
Executable file → Normal file
@@ -1,59 +1,59 @@
|
|||||||
package com.bartlomiejpluta.base.editor.main.controller
|
package com.bartlomiejpluta.base.editor.main.controller
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
import com.bartlomiejpluta.base.editor.map.view.MapSettingsFragment
|
import com.bartlomiejpluta.base.editor.map.view.MapSettingsFragment
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
import com.bartlomiejpluta.base.editor.project.manager.ProjectManager
|
import com.bartlomiejpluta.base.editor.project.manager.ProjectManager
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment
|
import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment
|
||||||
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.stage.FileChooser
|
import javafx.stage.FileChooser
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class MainController : Controller() {
|
class MainController : Controller() {
|
||||||
// In the future it'll be pulled from TileSetService or something like that
|
// In the future it'll be pulled from TileSetService or something like that
|
||||||
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
||||||
private val projectManager: ProjectManager by di()
|
private val projectManager: ProjectManager by di()
|
||||||
|
|
||||||
val openProject = SimpleObjectProperty<Project?>()
|
val openProject = SimpleObjectProperty<Project?>()
|
||||||
val openMaps = observableMapOf<Scope, GameMap>()
|
val openMaps = observableMapOf<Scope, GameMap>()
|
||||||
|
|
||||||
fun createEmptyProject() {
|
fun createEmptyProject() {
|
||||||
val project = Project()
|
val project = Project()
|
||||||
val vm = ProjectVM(project)
|
val vm = ProjectVM(project)
|
||||||
|
|
||||||
setInScope(vm)
|
setInScope(vm)
|
||||||
val modal = find<ProjectSettingsFragment>().apply { openModal(block = true, resizable = false) }
|
val modal = find<ProjectSettingsFragment>().apply { openModal(block = true, resizable = false) }
|
||||||
|
|
||||||
if(modal.result) {
|
if(modal.result) {
|
||||||
openProject.value = project
|
openProject.value = project
|
||||||
projectManager.saveProject(project)
|
projectManager.saveProject(project)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createEmptyMap() {
|
fun createEmptyMap() {
|
||||||
val map = GameMap(tileset)
|
val map = GameMap(tileset)
|
||||||
val scope = UndoableScope()
|
val scope = UndoableScope()
|
||||||
val vm = GameMapVM(map)
|
val vm = GameMapVM(map)
|
||||||
setInScope(vm, scope)
|
setInScope(vm, scope)
|
||||||
|
|
||||||
val modal = find<MapSettingsFragment>(scope).apply { openModal(block = true, resizable = false) }
|
val modal = find<MapSettingsFragment>(scope).apply { openModal(block = true, resizable = false) }
|
||||||
|
|
||||||
if (modal.result) {
|
if (modal.result) {
|
||||||
openMaps[scope] = map
|
openMaps[scope] = map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadProject() {
|
fun loadProject() {
|
||||||
chooseFile(
|
chooseFile(
|
||||||
title = "Load Project",
|
title = "Load Project",
|
||||||
filters = arrayOf(FileChooser.ExtensionFilter("BASE Editor Project (*.bep)", "*.bep")),
|
filters = arrayOf(FileChooser.ExtensionFilter("BASE Editor Project (*.bep)", "*.bep")),
|
||||||
).getOrNull(0)?.let { openProject.value = projectManager.openProject(it) }
|
).getOrNull(0)?.let { openProject.value = projectManager.openProject(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt
Executable file → Normal file
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt
Executable file → Normal file
@@ -1,40 +1,40 @@
|
|||||||
package com.bartlomiejpluta.base.editor.main.view
|
package com.bartlomiejpluta.base.editor.main.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class MainMenuView : View() {
|
class MainMenuView : View() {
|
||||||
private val mainController: MainController by di()
|
private val mainController: MainController by di()
|
||||||
|
|
||||||
override val root = menubar {
|
override val root = menubar {
|
||||||
menu("File") {
|
menu("File") {
|
||||||
menu("New") {
|
menu("New") {
|
||||||
item("Project...") {
|
item("Project...") {
|
||||||
action {
|
action {
|
||||||
mainController.createEmptyProject()
|
mainController.createEmptyProject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item("Map...") {
|
item("Map...") {
|
||||||
enableWhen(mainController.openProject.isNotNull)
|
enableWhen(mainController.openProject.isNotNull)
|
||||||
action {
|
action {
|
||||||
mainController.createEmptyMap()
|
mainController.createEmptyMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu("Open") {
|
menu("Open") {
|
||||||
item("Project...") {
|
item("Project...") {
|
||||||
action {
|
action {
|
||||||
mainController.loadProject()
|
mainController.loadProject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu("Edit") {
|
menu("Edit") {
|
||||||
item("Undo")
|
item("Undo")
|
||||||
item("Redo")
|
item("Redo")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt
Executable file → Normal file
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt
Executable file → Normal file
@@ -1,34 +1,34 @@
|
|||||||
package com.bartlomiejpluta.base.editor.main.view
|
package com.bartlomiejpluta.base.editor.main.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
||||||
import com.bartlomiejpluta.base.editor.map.view.MapFragment
|
import com.bartlomiejpluta.base.editor.map.view.MapFragment
|
||||||
import javafx.scene.control.Tab
|
import javafx.scene.control.Tab
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
|
|
||||||
class MainView : View("BASE Game Editor") {
|
class MainView : View("BASE Game Editor") {
|
||||||
private val mainController: MainController by di()
|
private val mainController: MainController by di()
|
||||||
|
|
||||||
private val mainMenuView = find<MainMenuView>()
|
private val mainMenuView = find<MainMenuView>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
mainController.openProject.addListener { _, _, project ->
|
mainController.openProject.addListener { _, _, project ->
|
||||||
val projectName = project?.let { " :: ${it.name} (${it.sourceDirectory.absolutePath})" } ?: ""
|
val projectName = project?.let { " :: ${it.name} (${it.sourceDirectory.absolutePath})" } ?: ""
|
||||||
title = "BASE Game Editor$projectName"
|
title = "BASE Game Editor$projectName"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
top = mainMenuView.root
|
top = mainMenuView.root
|
||||||
|
|
||||||
center = tabpane {
|
center = tabpane {
|
||||||
tabs.bind(mainController.openMaps) { scope, map ->
|
tabs.bind(mainController.openMaps) { scope, map ->
|
||||||
Tab().apply {
|
Tab().apply {
|
||||||
textProperty().bindBidirectional(map.nameProperty)
|
textProperty().bindBidirectional(map.nameProperty)
|
||||||
content = find<MapFragment>(scope).root
|
content = find<MapFragment>(scope).root
|
||||||
setOnClosed { mainController.openMaps.remove(scope) }
|
setOnClosed { mainController.openMaps.remove(scope) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt
Executable file → Normal file
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt
Executable file → Normal file
@@ -1,98 +1,98 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.canvas
|
package com.bartlomiejpluta.base.editor.map.canvas
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
import javafx.scene.canvas.GraphicsContext
|
import javafx.scene.canvas.GraphicsContext
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
|
|
||||||
|
|
||||||
class MapCanvas(val map: GameMapVM, private val editorStateVM: EditorStateVM, private val painter: MapPainter) : Renderable {
|
class MapCanvas(val map: GameMapVM, private val editorStateVM: EditorStateVM, private val painter: MapPainter) : Renderable {
|
||||||
var tileSet = map.tileSet
|
var tileSet = map.tileSet
|
||||||
private var tileWidth = map.tileWidth
|
private var tileWidth = map.tileWidth
|
||||||
private var tileHeight = map.tileHeight
|
private var tileHeight = map.tileHeight
|
||||||
|
|
||||||
|
|
||||||
override fun render(gc: GraphicsContext) {
|
override fun render(gc: GraphicsContext) {
|
||||||
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
||||||
|
|
||||||
renderBackground(gc)
|
renderBackground(gc)
|
||||||
renderUnderlyingLayers(gc)
|
renderUnderlyingLayers(gc)
|
||||||
renderCover(gc)
|
renderCover(gc)
|
||||||
renderSelectedLayer(gc)
|
renderSelectedLayer(gc)
|
||||||
renderGrid(gc)
|
renderGrid(gc)
|
||||||
painter.render(gc)
|
painter.render(gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderSelectedLayer(gc: GraphicsContext) {
|
private fun renderSelectedLayer(gc: GraphicsContext) {
|
||||||
map.layers.getOrNull(editorStateVM.selectedLayer) ?. let { dispatchLayerRender(gc, it) }
|
map.layers.getOrNull(editorStateVM.selectedLayer) ?. let { dispatchLayerRender(gc, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderCover(gc: GraphicsContext) {
|
private fun renderCover(gc: GraphicsContext) {
|
||||||
if(!editorStateVM.coverUnderlyingLayers) {
|
if(!editorStateVM.coverUnderlyingLayers) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.fill = Color.color(0.0, 0.0, 0.0, 0.4)
|
gc.fill = Color.color(0.0, 0.0, 0.0, 0.4)
|
||||||
gc.fillRect(0.0, 0.0, map.width, map.height)
|
gc.fillRect(0.0, 0.0, map.width, map.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderUnderlyingLayers(gc: GraphicsContext) {
|
private fun renderUnderlyingLayers(gc: GraphicsContext) {
|
||||||
for(layer in map.layers.dropLast(if(editorStateVM.selectedLayer < 0) 0 else map.layers.size - editorStateVM.selectedLayer)) {
|
for(layer in map.layers.dropLast(if(editorStateVM.selectedLayer < 0) 0 else map.layers.size - editorStateVM.selectedLayer)) {
|
||||||
dispatchLayerRender(gc, layer)
|
dispatchLayerRender(gc, layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dispatchLayerRender(gc: GraphicsContext, layer: Layer) {
|
private fun dispatchLayerRender(gc: GraphicsContext, layer: Layer) {
|
||||||
when (layer) {
|
when (layer) {
|
||||||
is TileLayer -> renderTileLayer(gc, layer)
|
is TileLayer -> renderTileLayer(gc, layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderBackground(gc: GraphicsContext) {
|
private fun renderBackground(gc: GraphicsContext) {
|
||||||
for (row in 0 until map.rows) {
|
for (row in 0 until map.rows) {
|
||||||
for (column in 0 until map.columns) {
|
for (column in 0 until map.columns) {
|
||||||
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
||||||
gc.fillRect(column * tileWidth, row * tileHeight, tileWidth, tileHeight)
|
gc.fillRect(column * tileWidth, row * tileHeight, tileWidth, tileHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTileLayer(gc: GraphicsContext, tileLayer: TileLayer) {
|
private fun renderTileLayer(gc: GraphicsContext, tileLayer: TileLayer) {
|
||||||
for ((row, columns) in tileLayer.layer.withIndex()) {
|
for ((row, columns) in tileLayer.layer.withIndex()) {
|
||||||
for ((column, tile) in columns.withIndex()) {
|
for ((column, tile) in columns.withIndex()) {
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderGrid(gc: GraphicsContext) {
|
private fun renderGrid(gc: GraphicsContext) {
|
||||||
if(!editorStateVM.showGrid) {
|
if(!editorStateVM.showGrid) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.lineWidth = 1.5
|
gc.lineWidth = 1.5
|
||||||
|
|
||||||
gc.strokeLine(0.0, 0.0, map.width, 0.0)
|
gc.strokeLine(0.0, 0.0, map.width, 0.0)
|
||||||
gc.strokeLine(0.0, 0.0, 0.0, map.height)
|
gc.strokeLine(0.0, 0.0, 0.0, map.height)
|
||||||
gc.strokeLine(map.width, 0.0, map.width, map.height)
|
gc.strokeLine(map.width, 0.0, map.width, map.height)
|
||||||
gc.strokeLine(0.0, map.height, map.width, map.height)
|
gc.strokeLine(0.0, map.height, map.width, map.height)
|
||||||
|
|
||||||
for (row in 0 until map.rows) {
|
for (row in 0 until map.rows) {
|
||||||
gc.strokeLine(0.0, row * tileHeight, map.width, row * tileHeight)
|
gc.strokeLine(0.0, row * tileHeight, map.width, row * tileHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (column in 0 until map.columns) {
|
for (column in 0 until map.columns) {
|
||||||
gc.strokeLine(column * tileWidth, 0.0, column * tileWidth, map.height)
|
gc.strokeLine(column * tileWidth, 0.0, column * tileWidth, map.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.0)
|
private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.0)
|
||||||
private val BACKGROUND_COLOR2 = Color.color(0.8, 0.8, 0.8, 1.0)
|
private val BACKGROUND_COLOR2 = Color.color(0.8, 0.8, 0.8, 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
186
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt
Executable file → Normal file
186
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt
Executable file → Normal file
@@ -1,94 +1,94 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.canvas
|
package com.bartlomiejpluta.base.editor.map.canvas
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
||||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
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 MapPainter(
|
class MapPainter(
|
||||||
private val mapVM: GameMapVM,
|
private val mapVM: GameMapVM,
|
||||||
private val brushVM: BrushVM,
|
private val brushVM: BrushVM,
|
||||||
private val editorStateVM: EditorStateVM,
|
private val editorStateVM: EditorStateVM,
|
||||||
private val paintingCallback: (MapPaintingTrace) -> Unit
|
private val paintingCallback: (MapPaintingTrace) -> Unit
|
||||||
) : Renderable, MapMouseEventHandler {
|
) : Renderable, MapMouseEventHandler {
|
||||||
private val tileWidth = mapVM.tileSet.tileWidth.toDouble()
|
private val tileWidth = mapVM.tileSet.tileWidth.toDouble()
|
||||||
private val tileHeight = mapVM.tileSet.tileHeight.toDouble()
|
private val tileHeight = mapVM.tileSet.tileHeight.toDouble()
|
||||||
|
|
||||||
private var currentTrace: MapPaintingTrace? = null
|
private var currentTrace: MapPaintingTrace? = null
|
||||||
|
|
||||||
override fun render(gc: GraphicsContext) {
|
override fun render(gc: GraphicsContext) {
|
||||||
val alpha = gc.globalAlpha
|
val alpha = gc.globalAlpha
|
||||||
gc.globalAlpha = 0.4
|
gc.globalAlpha = 0.4
|
||||||
|
|
||||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||||
renderTile(gc, row, column, centerRow, centerColumn, tile)
|
renderTile(gc, row, column, centerRow, centerColumn, tile)
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.globalAlpha = alpha
|
gc.globalAlpha = alpha
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTile(gc: GraphicsContext, row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) {
|
private fun renderTile(gc: GraphicsContext, row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) {
|
||||||
val x = tileWidth * (editorStateVM.cursorColumn - centerColumn + column)
|
val x = tileWidth * (editorStateVM.cursorColumn - centerColumn + column)
|
||||||
val y = tileHeight * (editorStateVM.cursorRow - centerRow + row)
|
val y = tileHeight * (editorStateVM.cursorRow - centerRow + row)
|
||||||
|
|
||||||
when {
|
when {
|
||||||
tile != null -> renderPaintingBrushTile(gc, tile, x, y)
|
tile != null -> renderPaintingBrushTile(gc, tile, x, y)
|
||||||
else -> renderEraserTile(gc, x, y)
|
else -> renderEraserTile(gc, x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderPaintingBrushTile(gc: GraphicsContext, tile: Tile, x: Double, y: Double) =
|
private fun renderPaintingBrushTile(gc: GraphicsContext, tile: Tile, x: Double, y: Double) =
|
||||||
gc.drawImage(tile.image, x, y)
|
gc.drawImage(tile.image, x, y)
|
||||||
|
|
||||||
private fun renderEraserTile(gc: GraphicsContext, x: Double, y: Double) {
|
private fun renderEraserTile(gc: GraphicsContext, x: Double, y: Double) {
|
||||||
gc.fill = Color.WHITE
|
gc.fill = Color.WHITE
|
||||||
gc.fillRect(x, y, tileWidth, tileHeight)
|
gc.fillRect(x, y, tileWidth, tileHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleMouseInput(event: MapMouseEvent) {
|
override fun handleMouseInput(event: MapMouseEvent) {
|
||||||
editorStateVM.cursorRowProperty.value = event.row
|
editorStateVM.cursorRowProperty.value = event.row
|
||||||
editorStateVM.cursorColumnProperty.value = event.column
|
editorStateVM.cursorColumnProperty.value = event.column
|
||||||
|
|
||||||
when (event.type) {
|
when (event.type) {
|
||||||
MouseEvent.MOUSE_PRESSED -> beginTrace(event)
|
MouseEvent.MOUSE_PRESSED -> beginTrace(event)
|
||||||
MouseEvent.MOUSE_DRAGGED -> proceedTrace(event)
|
MouseEvent.MOUSE_DRAGGED -> proceedTrace(event)
|
||||||
MouseEvent.MOUSE_RELEASED -> commitTrace(event)
|
MouseEvent.MOUSE_RELEASED -> commitTrace(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun beginTrace(event: MapMouseEvent) {
|
private fun beginTrace(event: MapMouseEvent) {
|
||||||
if (event.button == MouseButton.PRIMARY && editorStateVM.selectedLayer >= 0) {
|
if (event.button == MouseButton.PRIMARY && editorStateVM.selectedLayer >= 0) {
|
||||||
currentTrace = MapPaintingTrace(mapVM, "Paint trace").apply {
|
currentTrace = MapPaintingTrace(mapVM, "Paint trace").apply {
|
||||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||||
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun proceedTrace(event: MapMouseEvent) {
|
private fun proceedTrace(event: MapMouseEvent) {
|
||||||
if (event.button == MouseButton.PRIMARY) {
|
if (event.button == MouseButton.PRIMARY) {
|
||||||
currentTrace?.apply {
|
currentTrace?.apply {
|
||||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||||
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun commitTrace(event: MapMouseEvent) {
|
private fun commitTrace(event: MapMouseEvent) {
|
||||||
if (event.button == MouseButton.PRIMARY) {
|
if (event.button == MouseButton.PRIMARY) {
|
||||||
currentTrace?.let {
|
currentTrace?.let {
|
||||||
paintingCallback(it)
|
paintingCallback(it)
|
||||||
currentTrace = null
|
currentTrace = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
110
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPaintingTrace.kt
Executable file → Normal file
110
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPaintingTrace.kt
Executable file → Normal file
@@ -1,56 +1,56 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.canvas
|
package com.bartlomiejpluta.base.editor.map.canvas
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
|
|
||||||
|
|
||||||
data class MapPaintingTrace(val map: GameMapVM, override val commandName: String) : Undoable {
|
data class MapPaintingTrace(val map: GameMapVM, override val commandName: String) : Undoable {
|
||||||
private val trace = mutableListOf<Element>()
|
private val trace = mutableListOf<Element>()
|
||||||
|
|
||||||
fun paint(layerIndex: Int, row: Int, column: Int, tile: Tile?) {
|
fun paint(layerIndex: Int, row: Int, column: Int, tile: Tile?) {
|
||||||
if (row >= map.rows || column >= map.columns || row < 0 || column < 0 || layerIndex < 0) {
|
if (row >= map.rows || column >= map.columns || row < 0 || column < 0 || layerIndex < 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val layer = (map.layers[layerIndex] as TileLayer).layer
|
val layer = (map.layers[layerIndex] as TileLayer).layer
|
||||||
val formerTile = layer[row][column]
|
val formerTile = layer[row][column]
|
||||||
|
|
||||||
if (trace.isEmpty()) {
|
if (trace.isEmpty()) {
|
||||||
trace += Element(layerIndex, row, column, formerTile, tile)
|
trace += Element(layerIndex, row, column, formerTile, tile)
|
||||||
layer[row][column] = tile
|
layer[row][column] = tile
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val tileAlreadyPainted =
|
val tileAlreadyPainted =
|
||||||
trace.find { it.layerIndex == layerIndex && it.row == row && it.column == column } != null
|
trace.find { it.layerIndex == layerIndex && it.row == row && it.column == column } != null
|
||||||
|
|
||||||
if (!tileAlreadyPainted) {
|
if (!tileAlreadyPainted) {
|
||||||
trace += Element(layerIndex, row, column, formerTile, tile)
|
trace += Element(layerIndex, row, column, formerTile, tile)
|
||||||
layer[row][column] = tile
|
layer[row][column] = tile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun undo() {
|
override fun undo() {
|
||||||
trace.forEach {
|
trace.forEach {
|
||||||
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.formerTile
|
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.formerTile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun redo() {
|
override fun redo() {
|
||||||
trace.forEach {
|
trace.forEach {
|
||||||
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.tile
|
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.tile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private data class Element(
|
private data class Element(
|
||||||
val layerIndex: Int,
|
val layerIndex: Int,
|
||||||
val row: Int,
|
val row: Int,
|
||||||
val column: Int,
|
val column: Int,
|
||||||
val formerTile: Tile?,
|
val formerTile: Tile?,
|
||||||
val tile: Tile?
|
val tile: Tile?
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
104
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt
Executable file → Normal file
104
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt
Executable file → Normal file
@@ -1,53 +1,53 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.component
|
package com.bartlomiejpluta.base.editor.map.component
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.canvas.MapCanvas
|
import com.bartlomiejpluta.base.editor.map.canvas.MapCanvas
|
||||||
import com.bartlomiejpluta.base.editor.map.canvas.MapPainter
|
import com.bartlomiejpluta.base.editor.map.canvas.MapPainter
|
||||||
import com.bartlomiejpluta.base.editor.map.canvas.MapPaintingTrace
|
import com.bartlomiejpluta.base.editor.map.canvas.MapPaintingTrace
|
||||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
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(
|
class MapPane(
|
||||||
private val mapVM: GameMapVM,
|
private val mapVM: GameMapVM,
|
||||||
brushVM: BrushVM,
|
brushVM: BrushVM,
|
||||||
editorStateVM: EditorStateVM,
|
editorStateVM: EditorStateVM,
|
||||||
paintingCallback: (MapPaintingTrace) -> Unit
|
paintingCallback: (MapPaintingTrace) -> Unit
|
||||||
) : Canvas(), EventHandler<MouseEvent> {
|
) : Canvas(), EventHandler<MouseEvent> {
|
||||||
private val painter = MapPainter(mapVM, brushVM, editorStateVM, paintingCallback)
|
private val painter = MapPainter(mapVM, brushVM, editorStateVM, paintingCallback)
|
||||||
private val mapCanvas = MapCanvas(mapVM, editorStateVM, painter)
|
private val mapCanvas = MapCanvas(mapVM, editorStateVM, painter)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
onMouseMoved = this
|
onMouseMoved = this
|
||||||
onMouseDragged = this
|
onMouseDragged = this
|
||||||
onMousePressed = this
|
onMousePressed = this
|
||||||
onMouseReleased = this
|
onMouseReleased = this
|
||||||
|
|
||||||
widthProperty().bind(mapVM.widthProperty)
|
widthProperty().bind(mapVM.widthProperty)
|
||||||
heightProperty().bind(mapVM.heightProperty)
|
heightProperty().bind(mapVM.heightProperty)
|
||||||
|
|
||||||
mapVM.item.rowsProperty.addListener { _, _, _ -> render() }
|
mapVM.item.rowsProperty.addListener { _, _, _ -> render() }
|
||||||
mapVM.item.columnsProperty.addListener { _, _, _ -> render() }
|
mapVM.item.columnsProperty.addListener { _, _, _ -> render() }
|
||||||
|
|
||||||
editorStateVM.showGridProperty.addListener { _, _, _ -> render() }
|
editorStateVM.showGridProperty.addListener { _, _, _ -> render() }
|
||||||
editorStateVM.selectedLayerProperty.addListener { _, _, _ -> render() }
|
editorStateVM.selectedLayerProperty.addListener { _, _, _ -> render() }
|
||||||
editorStateVM.coverUnderlyingLayersProperty.addListener { _, _, _ -> render() }
|
editorStateVM.coverUnderlyingLayersProperty.addListener { _, _, _ -> render() }
|
||||||
|
|
||||||
render()
|
render()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render() {
|
fun render() {
|
||||||
mapCanvas.render(graphicsContext2D)
|
mapCanvas.render(graphicsContext2D)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(event: MouseEvent?) {
|
override fun handle(event: MouseEvent?) {
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
painter.handleMouseInput(MapMouseEvent.of(event, mapVM.tileSet))
|
painter.handleMouseInput(MapMouseEvent.of(event, mapVM.tileSet))
|
||||||
}
|
}
|
||||||
|
|
||||||
mapCanvas.render(graphicsContext2D)
|
mapCanvas.render(graphicsContext2D)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/Brush.kt
Executable file → Normal file
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/Brush.kt
Executable file → Normal file
@@ -1,97 +1,97 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.model.brush
|
package com.bartlomiejpluta.base.editor.map.model.brush
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
import tornadofx.asObservable
|
import tornadofx.asObservable
|
||||||
import tornadofx.getValue
|
import tornadofx.getValue
|
||||||
import tornadofx.observableListOf
|
import tornadofx.observableListOf
|
||||||
import tornadofx.setValue
|
import tornadofx.setValue
|
||||||
|
|
||||||
class Brush {
|
class Brush {
|
||||||
val brush: ObservableList<Tile>
|
val brush: ObservableList<Tile>
|
||||||
|
|
||||||
val rowsProperty = SimpleIntegerProperty(0)
|
val rowsProperty = SimpleIntegerProperty(0)
|
||||||
var rows by rowsProperty
|
var rows by rowsProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val columnsProperty = SimpleIntegerProperty(0)
|
val columnsProperty = SimpleIntegerProperty(0)
|
||||||
var columns by columnsProperty
|
var columns by columnsProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val rangeProperty = SimpleIntegerProperty(1)
|
val rangeProperty = SimpleIntegerProperty(1)
|
||||||
var range by rangeProperty
|
var range by rangeProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val modeProperty = SimpleObjectProperty(BrushMode.PAINTING_MODE)
|
val modeProperty = SimpleObjectProperty(BrushMode.PAINTING_MODE)
|
||||||
var mode by modeProperty
|
var mode by modeProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private constructor(brushArray: Array<Array<Tile>>) {
|
private constructor(brushArray: Array<Array<Tile>>) {
|
||||||
rowsProperty.value = brushArray.size
|
rowsProperty.value = brushArray.size
|
||||||
|
|
||||||
brush = observableListOf()
|
brush = observableListOf()
|
||||||
|
|
||||||
brushArray.forEach { brush.addAll(it) }
|
brushArray.forEach { brush.addAll(it) }
|
||||||
|
|
||||||
if (rowsProperty.value > 0) {
|
if (rowsProperty.value > 0) {
|
||||||
columns = brush.size / rowsProperty.value
|
columns = brush.size / rowsProperty.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor(brush: List<Tile>, rows: Int, columns: Int) {
|
private constructor(brush: List<Tile>, rows: Int, columns: Int) {
|
||||||
this.rows = rows
|
this.rows = rows
|
||||||
this.columns = columns
|
this.columns = columns
|
||||||
|
|
||||||
this.brush = brush.asObservable()
|
this.brush = brush.asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||||
return when {
|
return when {
|
||||||
range > 1 || mode == BrushMode.ERASING_MODE -> forEachInRangedBrush(consumer)
|
range > 1 || mode == BrushMode.ERASING_MODE -> forEachInRangedBrush(consumer)
|
||||||
else -> forEachInRegularBrush(consumer)
|
else -> forEachInRegularBrush(consumer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun forEachInRangedBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
private fun forEachInRangedBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||||
val center = range / 2
|
val center = range / 2
|
||||||
|
|
||||||
(0 until range).forEach { row ->
|
(0 until range).forEach { row ->
|
||||||
(0 until range).forEach { column ->
|
(0 until range).forEach { column ->
|
||||||
consumer(row, column, center, center, getTileByMode(brush[0]))
|
consumer(row, column, center, center, getTileByMode(brush[0]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTileByMode(tile: Tile) = when (mode) {
|
private fun getTileByMode(tile: Tile) = when (mode) {
|
||||||
BrushMode.PAINTING_MODE -> tile
|
BrushMode.PAINTING_MODE -> tile
|
||||||
BrushMode.ERASING_MODE -> null
|
BrushMode.ERASING_MODE -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun forEachInRegularBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
private fun forEachInRegularBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||||
val centerRow = rows / 2
|
val centerRow = rows / 2
|
||||||
val centerColumn = columns / 2
|
val centerColumn = columns / 2
|
||||||
|
|
||||||
brush.forEachIndexed { id, tile ->
|
brush.forEachIndexed { id, tile ->
|
||||||
consumer(id / columns, id % columns, centerRow, centerColumn, getTileByMode(tile))
|
consumer(id / columns, id % columns, centerRow, centerColumn, getTileByMode(tile))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clone() = Brush(brush, rows, columns).apply {
|
private fun clone() = Brush(brush, rows, columns).apply {
|
||||||
this.range = this@Brush.range
|
this.range = this@Brush.range
|
||||||
this.mode = this@Brush.mode
|
this.mode = this@Brush.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withRange(range: Int) = clone().apply {
|
fun withRange(range: Int) = clone().apply {
|
||||||
this.range = range
|
this.range = range
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withMode(mode: BrushMode) = clone().apply {
|
fun withMode(mode: BrushMode) = clone().apply {
|
||||||
this.mode = mode
|
this.mode = mode
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun of(brushArray: Array<Array<Tile>>) = Brush(brushArray)
|
fun of(brushArray: Array<Array<Tile>>) = Brush(brushArray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/BrushMode.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/BrushMode.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.model.brush
|
package com.bartlomiejpluta.base.editor.map.model.brush
|
||||||
|
|
||||||
enum class BrushMode {
|
enum class BrushMode {
|
||||||
PAINTING_MODE,
|
PAINTING_MODE,
|
||||||
ERASING_MODE
|
ERASING_MODE
|
||||||
}
|
}
|
||||||
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/Layer.kt
Executable file → Normal file
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/Layer.kt
Executable file → Normal file
@@ -1,12 +1,12 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.model.layer
|
package com.bartlomiejpluta.base.editor.map.model.layer
|
||||||
|
|
||||||
import javafx.beans.property.StringProperty
|
import javafx.beans.property.StringProperty
|
||||||
|
|
||||||
interface Layer {
|
interface Layer {
|
||||||
var name: String
|
var name: String
|
||||||
val nameProperty: StringProperty
|
val nameProperty: StringProperty
|
||||||
|
|
||||||
fun resize(rows: Int, columns: Int)
|
fun resize(rows: Int, columns: Int)
|
||||||
|
|
||||||
fun clone(): Layer
|
fun clone(): Layer
|
||||||
}
|
}
|
||||||
60
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt
Executable file → Normal file
60
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt
Executable file → Normal file
@@ -1,31 +1,31 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.model.layer
|
package com.bartlomiejpluta.base.editor.map.model.layer
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import tornadofx.getValue
|
import tornadofx.getValue
|
||||||
import tornadofx.setValue
|
import tornadofx.setValue
|
||||||
|
|
||||||
class TileLayer(
|
class TileLayer(
|
||||||
name: String,
|
name: String,
|
||||||
rows: Int,
|
rows: Int,
|
||||||
columns: Int,
|
columns: Int,
|
||||||
layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
||||||
) : Layer {
|
) : Layer {
|
||||||
var layer = layer
|
var layer = layer
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override val nameProperty = SimpleStringProperty(name)
|
override val nameProperty = SimpleStringProperty(name)
|
||||||
override var name: String by nameProperty
|
override var name: String by nameProperty
|
||||||
|
|
||||||
override fun resize(rows: Int, columns: Int) {
|
override fun resize(rows: Int, columns: Int) {
|
||||||
layer = Array(rows) { row ->
|
layer = Array(rows) { row ->
|
||||||
Array(columns) { column ->
|
Array(columns) { column ->
|
||||||
layer.getOrNull(row)?.getOrNull(column)
|
layer.getOrNull(row)?.getOrNull(column)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clone() = TileLayer(name, 0, 0).apply {
|
override fun clone() = TileLayer(name, 0, 0).apply {
|
||||||
layer = this@TileLayer.layer
|
layer = this@TileLayer.layer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt
Executable file → Normal file
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt
Executable file → Normal file
@@ -1,54 +1,54 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.model.map
|
package com.bartlomiejpluta.base.editor.map.model.map
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||||
import javafx.beans.property.SimpleDoubleProperty
|
import javafx.beans.property.SimpleDoubleProperty
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import tornadofx.getValue
|
import tornadofx.getValue
|
||||||
import tornadofx.observableListOf
|
import tornadofx.observableListOf
|
||||||
import tornadofx.setValue
|
import tornadofx.setValue
|
||||||
|
|
||||||
|
|
||||||
class GameMap(val tileSet: TileSet) {
|
class GameMap(val tileSet: TileSet) {
|
||||||
val layers = observableListOf<Layer>()
|
val layers = observableListOf<Layer>()
|
||||||
|
|
||||||
val nameProperty = SimpleStringProperty()
|
val nameProperty = SimpleStringProperty()
|
||||||
var name by nameProperty
|
var name by nameProperty
|
||||||
|
|
||||||
val tileWidth = tileSet.tileWidth.toDouble()
|
val tileWidth = tileSet.tileWidth.toDouble()
|
||||||
val tileHeight = tileSet.tileHeight.toDouble()
|
val tileHeight = tileSet.tileHeight.toDouble()
|
||||||
|
|
||||||
val rowsProperty = SimpleIntegerProperty(INITIAL_ROWS)
|
val rowsProperty = SimpleIntegerProperty(INITIAL_ROWS)
|
||||||
var rows by rowsProperty
|
var rows by rowsProperty
|
||||||
|
|
||||||
val columnsProperty = SimpleIntegerProperty(INITIAL_COLUMNS)
|
val columnsProperty = SimpleIntegerProperty(INITIAL_COLUMNS)
|
||||||
var columns by columnsProperty
|
var columns by columnsProperty
|
||||||
|
|
||||||
val widthProperty = SimpleDoubleProperty(INITIAL_COLUMNS * tileWidth)
|
val widthProperty = SimpleDoubleProperty(INITIAL_COLUMNS * tileWidth)
|
||||||
var width by widthProperty
|
var width by widthProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val heightProperty = SimpleDoubleProperty(INITIAL_ROWS * tileHeight)
|
val heightProperty = SimpleDoubleProperty(INITIAL_ROWS * tileHeight)
|
||||||
var height by heightProperty
|
var height by heightProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
rowsProperty.addListener { _, _, newValue ->
|
rowsProperty.addListener { _, _, newValue ->
|
||||||
val newRows = newValue.toInt()
|
val newRows = newValue.toInt()
|
||||||
height = newRows * tileWidth
|
height = newRows * tileWidth
|
||||||
layers.forEach { it.resize(newRows, columns) }
|
layers.forEach { it.resize(newRows, columns) }
|
||||||
}
|
}
|
||||||
|
|
||||||
columnsProperty.addListener { _, _, newValue ->
|
columnsProperty.addListener { _, _, newValue ->
|
||||||
val newColumns = newValue.toInt()
|
val newColumns = newValue.toInt()
|
||||||
width = newColumns * tileWidth
|
width = newColumns * tileWidth
|
||||||
layers.forEach { it.resize(rows, newColumns) }
|
layers.forEach { it.resize(rows, newColumns) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val INITIAL_ROWS = 20
|
private const val INITIAL_ROWS = 20
|
||||||
private const val INITIAL_COLUMNS = 20
|
private const val INITIAL_COLUMNS = 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.serial
|
package com.bartlomiejpluta.base.editor.map.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
|
|
||||||
interface MapDeserializer : Deserializer<GameMap>
|
interface MapDeserializer : Deserializer<GameMap>
|
||||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.serial
|
package com.bartlomiejpluta.base.editor.map.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
|
|
||||||
interface MapSerializer : Serializer<GameMap>
|
interface MapSerializer : Serializer<GameMap>
|
||||||
102
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt
Executable file → Normal file
102
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt
Executable file → Normal file
@@ -1,52 +1,52 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.serial
|
package com.bartlomiejpluta.base.editor.map.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||||
import com.bartlomiejpluta.base.proto.GameMapProto
|
import com.bartlomiejpluta.base.proto.GameMapProto
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import tornadofx.ResourceLookup
|
import tornadofx.ResourceLookup
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ProtobufMapDeserializer : MapDeserializer {
|
class ProtobufMapDeserializer : MapDeserializer {
|
||||||
private val resources = ResourceLookup(this)
|
private val resources = ResourceLookup(this)
|
||||||
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
||||||
|
|
||||||
override fun deserialize(input: InputStream): GameMap {
|
override fun deserialize(input: InputStream): GameMap {
|
||||||
val map = GameMap(tileset)
|
val map = GameMap(tileset)
|
||||||
val proto = GameMapProto.GameMap.parseFrom(input)
|
val proto = GameMapProto.GameMap.parseFrom(input)
|
||||||
map.name = proto.name
|
map.name = proto.name
|
||||||
map.rows = proto.rows
|
map.rows = proto.rows
|
||||||
map.columns = proto.columns
|
map.columns = proto.columns
|
||||||
|
|
||||||
proto.layersList.forEach {
|
proto.layersList.forEach {
|
||||||
map.layers.add(deserializeLayer(map.rows, map.columns, tileset, it))
|
map.layers.add(deserializeLayer(map.rows, map.columns, tileset, it))
|
||||||
}
|
}
|
||||||
|
|
||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deserializeLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
private fun deserializeLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
||||||
return when {
|
return when {
|
||||||
proto.hasTileLayer() -> deserializeTileLayer(rows, columns, tileSet, proto)
|
proto.hasTileLayer() -> deserializeTileLayer(rows, columns, tileSet, proto)
|
||||||
|
|
||||||
else -> throw IllegalStateException("Not supported layer type")
|
else -> throw IllegalStateException("Not supported layer type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deserializeTileLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
private fun deserializeTileLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
||||||
val layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
val layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
||||||
|
|
||||||
proto.tileLayer.tilesList.forEachIndexed { index, tile ->
|
proto.tileLayer.tilesList.forEachIndexed { index, tile ->
|
||||||
layer[index / columns][index % columns] = when(tile) {
|
layer[index / columns][index % columns] = when(tile) {
|
||||||
0 -> null
|
0 -> null
|
||||||
else -> tileSet.getTile(tile-1)
|
else -> tileSet.getTile(tile-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TileLayer(proto.name, rows, columns, layer)
|
return TileLayer(proto.name, rows, columns, layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt
Executable file → Normal file
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt
Executable file → Normal file
@@ -1,34 +1,34 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.serial
|
package com.bartlomiejpluta.base.editor.map.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
import com.bartlomiejpluta.base.proto.GameMapProto
|
import com.bartlomiejpluta.base.proto.GameMapProto
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ProtobufMapSerializer : MapSerializer {
|
class ProtobufMapSerializer : MapSerializer {
|
||||||
|
|
||||||
override fun serialize(item: GameMap, output: OutputStream) {
|
override fun serialize(item: GameMap, output: OutputStream) {
|
||||||
val protoMap = GameMapProto.GameMap.newBuilder()
|
val protoMap = GameMapProto.GameMap.newBuilder()
|
||||||
protoMap.name = item.name
|
protoMap.name = item.name
|
||||||
protoMap.rows = item.rows
|
protoMap.rows = item.rows
|
||||||
protoMap.columns = item.columns
|
protoMap.columns = item.columns
|
||||||
|
|
||||||
item.layers.forEach { layer -> protoMap.addLayers(serializeLayer(layer)) }
|
item.layers.forEach { layer -> protoMap.addLayers(serializeLayer(layer)) }
|
||||||
|
|
||||||
protoMap.build().writeTo(output)
|
protoMap.build().writeTo(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun serializeLayer(layer: Layer): GameMapProto.Layer {
|
private fun serializeLayer(layer: Layer): GameMapProto.Layer {
|
||||||
return when (layer) {
|
return when (layer) {
|
||||||
is TileLayer -> layer.layer.flatMap { it.asIterable() }
|
is TileLayer -> layer.layer.flatMap { it.asIterable() }
|
||||||
.fold(GameMapProto.TileLayer.newBuilder()) { acc, tile -> acc.addTiles((tile?.id?.plus(1)) ?: 0) }
|
.fold(GameMapProto.TileLayer.newBuilder()) { acc, tile -> acc.addTiles((tile?.id?.plus(1)) ?: 0) }
|
||||||
.build()
|
.build()
|
||||||
.let { GameMapProto.Layer.newBuilder().setName(layer.name).setTileLayer(it).build() }
|
.let { GameMapProto.Layer.newBuilder().setName(layer.name).setTileLayer(it).build() }
|
||||||
|
|
||||||
else -> throw IllegalStateException("Not supported layer type")
|
else -> throw IllegalStateException("Not supported layer type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
72
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapFragment.kt
Executable file → Normal file
72
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapFragment.kt
Executable file → Normal file
@@ -1,36 +1,36 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.view
|
package com.bartlomiejpluta.base.editor.map.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||||
import com.bartlomiejpluta.base.editor.tileset.view.TileSetView
|
import com.bartlomiejpluta.base.editor.tileset.view.TileSetView
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
|
|
||||||
class MapFragment : Fragment() {
|
class MapFragment : Fragment() {
|
||||||
override val scope = super.scope as UndoableScope
|
override val scope = super.scope as UndoableScope
|
||||||
|
|
||||||
private val mapView = find<MapView>()
|
private val mapView = find<MapView>()
|
||||||
private val layersView = find<MapLayersView>()
|
private val layersView = find<MapLayersView>()
|
||||||
private val tileSetView = find<TileSetView>()
|
private val tileSetView = find<TileSetView>()
|
||||||
private val toolbarView = find<MapToolbarView>()
|
private val toolbarView = find<MapToolbarView>()
|
||||||
private val statusBarView = find<MapStatusBarView>()
|
private val statusBarView = find<MapStatusBarView>()
|
||||||
|
|
||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
top = toolbarView.root
|
top = toolbarView.root
|
||||||
|
|
||||||
center = mapView.root
|
center = mapView.root
|
||||||
|
|
||||||
right = drawer(multiselect = true) {
|
right = drawer(multiselect = true) {
|
||||||
item("Layers", expanded = true) {
|
item("Layers", expanded = true) {
|
||||||
this += layersView.root
|
this += layersView.root
|
||||||
}
|
}
|
||||||
|
|
||||||
item("Tile Set", expanded = true) {
|
item("Tile Set", expanded = true) {
|
||||||
this += tileSetView.root.apply {
|
this += tileSetView.root.apply {
|
||||||
maxHeightProperty().bind(this@item.heightProperty())
|
maxHeightProperty().bind(this@item.heightProperty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bottom = statusBarView.root
|
bottom = statusBarView.root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
188
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapLayersView.kt
Executable file → Normal file
188
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapLayersView.kt
Executable file → Normal file
@@ -1,95 +1,95 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.view
|
package com.bartlomiejpluta.base.editor.map.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||||
import com.bartlomiejpluta.base.editor.command.model.map.CreateLayerCommand
|
import com.bartlomiejpluta.base.editor.command.model.map.CreateLayerCommand
|
||||||
import com.bartlomiejpluta.base.editor.command.model.map.MoveLayerCommand
|
import com.bartlomiejpluta.base.editor.command.model.map.MoveLayerCommand
|
||||||
import com.bartlomiejpluta.base.editor.command.model.map.RemoveLayerCommand
|
import com.bartlomiejpluta.base.editor.command.model.map.RemoveLayerCommand
|
||||||
import com.bartlomiejpluta.base.editor.command.model.map.RenameLayerCommand
|
import com.bartlomiejpluta.base.editor.command.model.map.RenameLayerCommand
|
||||||
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.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
import javafx.scene.control.TableView
|
import javafx.scene.control.TableView
|
||||||
import org.kordamp.ikonli.javafx.FontIcon
|
import org.kordamp.ikonli.javafx.FontIcon
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class MapLayersView : View() {
|
class MapLayersView : View() {
|
||||||
private val undoRedoService: UndoRedoService by di()
|
private val undoRedoService: UndoRedoService by di()
|
||||||
|
|
||||||
override val scope = super.scope as UndoableScope
|
override val scope = super.scope as UndoableScope
|
||||||
|
|
||||||
private val mapVM = find<GameMapVM>()
|
private val mapVM = find<GameMapVM>()
|
||||||
|
|
||||||
private val editorStateVM = find<EditorStateVM>()
|
private val editorStateVM = find<EditorStateVM>()
|
||||||
|
|
||||||
private var layersPane = TableView(mapVM.layers).apply {
|
private var layersPane = TableView(mapVM.layers).apply {
|
||||||
column("Layer Name", Layer::nameProperty).makeEditable().setOnEditCommit {
|
column("Layer Name", Layer::nameProperty).makeEditable().setOnEditCommit {
|
||||||
val command = RenameLayerCommand(it.rowValue, it.newValue)
|
val command = RenameLayerCommand(it.rowValue, it.newValue)
|
||||||
command.execute()
|
command.execute()
|
||||||
undoRedoService.push(command, scope)
|
undoRedoService.push(command, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
editorStateVM.selectedLayerProperty.bind(selectionModel.selectedIndexProperty())
|
editorStateVM.selectedLayerProperty.bind(selectionModel.selectedIndexProperty())
|
||||||
}
|
}
|
||||||
|
|
||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
center = layersPane
|
center = layersPane
|
||||||
|
|
||||||
bottom = toolbar {
|
bottom = toolbar {
|
||||||
button(graphic = FontIcon("fa-plus")) {
|
button(graphic = FontIcon("fa-plus")) {
|
||||||
action {
|
action {
|
||||||
val tileLayer = TileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns)
|
val tileLayer = TileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns)
|
||||||
val command = CreateLayerCommand(mapVM.item, tileLayer)
|
val command = CreateLayerCommand(mapVM.item, tileLayer)
|
||||||
command.execute()
|
command.execute()
|
||||||
layersPane.selectionModel.select(mapVM.layers.size - 1)
|
layersPane.selectionModel.select(mapVM.layers.size - 1)
|
||||||
undoRedoService.push(command, scope)
|
undoRedoService.push(command, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button(graphic = FontIcon("fa-chevron-up")) {
|
button(graphic = FontIcon("fa-chevron-up")) {
|
||||||
enableWhen(editorStateVM.selectedLayerProperty.greaterThan(0))
|
enableWhen(editorStateVM.selectedLayerProperty.greaterThan(0))
|
||||||
action {
|
action {
|
||||||
val newIndex = editorStateVM.selectedLayer - 1
|
val newIndex = editorStateVM.selectedLayer - 1
|
||||||
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
||||||
command.execute()
|
command.execute()
|
||||||
layersPane.selectionModel.select(newIndex)
|
layersPane.selectionModel.select(newIndex)
|
||||||
fire(RedrawMapRequestEvent)
|
fire(RedrawMapRequestEvent)
|
||||||
undoRedoService.push(command, scope)
|
undoRedoService.push(command, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button(graphic = FontIcon("fa-chevron-down")) {
|
button(graphic = FontIcon("fa-chevron-down")) {
|
||||||
enableWhen(
|
enableWhen(
|
||||||
editorStateVM.selectedLayerProperty.lessThan(mapVM.layers.sizeProperty().minus(1))
|
editorStateVM.selectedLayerProperty.lessThan(mapVM.layers.sizeProperty().minus(1))
|
||||||
.and(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
.and(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
||||||
)
|
)
|
||||||
action {
|
action {
|
||||||
val newIndex = editorStateVM.selectedLayer + 1
|
val newIndex = editorStateVM.selectedLayer + 1
|
||||||
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
||||||
command.execute()
|
command.execute()
|
||||||
layersPane.selectionModel.select(newIndex)
|
layersPane.selectionModel.select(newIndex)
|
||||||
fire(RedrawMapRequestEvent)
|
fire(RedrawMapRequestEvent)
|
||||||
undoRedoService.push(command, scope)
|
undoRedoService.push(command, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button(graphic = FontIcon("fa-trash")) {
|
button(graphic = FontIcon("fa-trash")) {
|
||||||
enableWhen(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
enableWhen(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
||||||
action {
|
action {
|
||||||
var index = editorStateVM.selectedLayer
|
var index = editorStateVM.selectedLayer
|
||||||
val command = RemoveLayerCommand(mapVM.item, index)
|
val command = RemoveLayerCommand(mapVM.item, index)
|
||||||
command.execute()
|
command.execute()
|
||||||
|
|
||||||
if (--index >= 0) {
|
if (--index >= 0) {
|
||||||
layersPane.selectionModel.select(index)
|
layersPane.selectionModel.select(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fire(RedrawMapRequestEvent)
|
fire(RedrawMapRequestEvent)
|
||||||
undoRedoService.push(command, scope)
|
undoRedoService.push(command, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
164
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapSettingsFragment.kt
Executable file → Normal file
164
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapSettingsFragment.kt
Executable file → Normal file
@@ -1,83 +1,83 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.view
|
package com.bartlomiejpluta.base.editor.map.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
import org.kordamp.ikonli.javafx.FontIcon
|
import org.kordamp.ikonli.javafx.FontIcon
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class MapSettingsFragment : Fragment("Map Settings") {
|
class MapSettingsFragment : Fragment("Map Settings") {
|
||||||
override val scope = super.scope as UndoableScope
|
override val scope = super.scope as UndoableScope
|
||||||
private val undoRedoService: UndoRedoService by di()
|
private val undoRedoService: UndoRedoService by di()
|
||||||
|
|
||||||
private val mapVM = find<GameMapVM>()
|
private val mapVM = find<GameMapVM>()
|
||||||
|
|
||||||
var result = false
|
var result = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override val root = form {
|
override val root = form {
|
||||||
icon = FontIcon("fa-map-o")
|
icon = FontIcon("fa-map-o")
|
||||||
|
|
||||||
fieldset("Map Settings") {
|
fieldset("Map Settings") {
|
||||||
field("Map name") {
|
field("Map name") {
|
||||||
textfield(mapVM.nameProperty) {
|
textfield(mapVM.nameProperty) {
|
||||||
required()
|
required()
|
||||||
whenDocked { requestFocus() }
|
whenDocked { requestFocus() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field("Rows") {
|
field("Rows") {
|
||||||
|
|
||||||
textfield(mapVM.rowsProperty) {
|
textfield(mapVM.rowsProperty) {
|
||||||
stripNonInteger()
|
stripNonInteger()
|
||||||
required()
|
required()
|
||||||
validator {
|
validator {
|
||||||
when (it?.toIntOrNull()) {
|
when (it?.toIntOrNull()) {
|
||||||
in 1..50 -> null
|
in 1..50 -> null
|
||||||
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
||||||
else -> error("The map size must be between 1 and 100")
|
else -> error("The map size must be between 1 and 100")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field("Columns") {
|
field("Columns") {
|
||||||
textfield(mapVM.columnsProperty) {
|
textfield(mapVM.columnsProperty) {
|
||||||
stripNonInteger()
|
stripNonInteger()
|
||||||
required()
|
required()
|
||||||
validator {
|
validator {
|
||||||
when (it?.toIntOrNull()) {
|
when (it?.toIntOrNull()) {
|
||||||
in 1..50 -> null
|
in 1..50 -> null
|
||||||
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
||||||
else -> error("The map size must be between 1 and 100")
|
else -> error("The map size must be between 1 and 100")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label("Warning: Submitting the form will clear related undo/redo stacks!")
|
label("Warning: Submitting the form will clear related undo/redo stacks!")
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonbar {
|
buttonbar {
|
||||||
button("Ok") {
|
button("Ok") {
|
||||||
shortcut("Enter")
|
shortcut("Enter")
|
||||||
|
|
||||||
action {
|
action {
|
||||||
mapVM.commit {
|
mapVM.commit {
|
||||||
result = true
|
result = true
|
||||||
undoRedoService.clear(scope)
|
undoRedoService.clear(scope)
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button("Reset") {
|
button("Reset") {
|
||||||
action { mapVM.rollback() }
|
action { mapVM.rollback() }
|
||||||
}
|
}
|
||||||
|
|
||||||
button("Cancel") {
|
button("Cancel") {
|
||||||
action { close() }
|
action { close() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapStatusBarView.kt
Executable file → Normal file
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapStatusBarView.kt
Executable file → Normal file
@@ -1,34 +1,34 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.view
|
package com.bartlomiejpluta.base.editor.map.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||||
import javafx.beans.binding.Bindings
|
import javafx.beans.binding.Bindings
|
||||||
import org.kordamp.ikonli.javafx.FontIcon
|
import org.kordamp.ikonli.javafx.FontIcon
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class MapStatusBarView : View() {
|
class MapStatusBarView : View() {
|
||||||
|
|
||||||
private val editorStateVM = find<EditorStateVM>()
|
private val editorStateVM = find<EditorStateVM>()
|
||||||
|
|
||||||
override val root = hbox {
|
override val root = hbox {
|
||||||
spacing = 50.0
|
spacing = 50.0
|
||||||
paddingAll = 5.0
|
paddingAll = 5.0
|
||||||
|
|
||||||
hbox {
|
hbox {
|
||||||
this += FontIcon("fa-search-minus")
|
this += FontIcon("fa-search-minus")
|
||||||
|
|
||||||
slider(0.5..5.0) {
|
slider(0.5..5.0) {
|
||||||
bind(editorStateVM.zoomProperty)
|
bind(editorStateVM.zoomProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
this += FontIcon("fa-search-plus")
|
this += FontIcon("fa-search-plus")
|
||||||
}
|
}
|
||||||
|
|
||||||
label(
|
label(
|
||||||
Bindings.format(
|
Bindings.format(
|
||||||
"Cursor: %d, %d",
|
"Cursor: %d, %d",
|
||||||
editorStateVM.cursorColumnProperty.add(1),
|
editorStateVM.cursorColumnProperty.add(1),
|
||||||
editorStateVM.cursorRowProperty.add(1)
|
editorStateVM.cursorRowProperty.add(1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
208
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapToolbarView.kt
Executable file → Normal file
208
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapToolbarView.kt
Executable file → Normal file
@@ -1,105 +1,105 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.view
|
package com.bartlomiejpluta.base.editor.map.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||||
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.map.model.brush.BrushMode
|
import com.bartlomiejpluta.base.editor.map.model.brush.BrushMode
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
import javafx.scene.control.ToggleGroup
|
import javafx.scene.control.ToggleGroup
|
||||||
import org.kordamp.ikonli.javafx.FontIcon
|
import org.kordamp.ikonli.javafx.FontIcon
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class MapToolbarView : View() {
|
class MapToolbarView : View() {
|
||||||
private val undoRedoService: UndoRedoService by di()
|
private val undoRedoService: UndoRedoService by di()
|
||||||
|
|
||||||
override val scope = super.scope as UndoableScope
|
override val scope = super.scope as UndoableScope
|
||||||
|
|
||||||
private val mapVM = find<GameMapVM>()
|
private val mapVM = find<GameMapVM>()
|
||||||
private val brushVM = find<BrushVM>()
|
private val brushVM = find<BrushVM>()
|
||||||
private val editorStateVM = find<EditorStateVM>()
|
private val editorStateVM = find<EditorStateVM>()
|
||||||
|
|
||||||
private val brushMode = ToggleGroup().apply {
|
private val brushMode = ToggleGroup().apply {
|
||||||
brushVM.itemProperty.addListener { _, _, brush ->
|
brushVM.itemProperty.addListener { _, _, brush ->
|
||||||
selectedValueProperty<BrushMode>().value = brush.mode
|
selectedValueProperty<BrushMode>().value = brush.mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val root = toolbar {
|
override val root = toolbar {
|
||||||
button(graphic = FontIcon("fa-undo")) {
|
button(graphic = FontIcon("fa-undo")) {
|
||||||
shortcut("Ctrl+Z")
|
shortcut("Ctrl+Z")
|
||||||
action {
|
action {
|
||||||
undoRedoService.undo(scope)
|
undoRedoService.undo(scope)
|
||||||
fire(RedrawMapRequestEvent)
|
fire(RedrawMapRequestEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button(graphic = FontIcon("fa-repeat")) {
|
button(graphic = FontIcon("fa-repeat")) {
|
||||||
shortcut("Ctrl+Shift+Z")
|
shortcut("Ctrl+Shift+Z")
|
||||||
action {
|
action {
|
||||||
undoRedoService.redo(scope)
|
undoRedoService.redo(scope)
|
||||||
fire(RedrawMapRequestEvent)
|
fire(RedrawMapRequestEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
togglebutton {
|
togglebutton {
|
||||||
graphic = FontIcon("fa-window-restore")
|
graphic = FontIcon("fa-window-restore")
|
||||||
|
|
||||||
action {
|
action {
|
||||||
editorStateVM.coverUnderlyingLayers = isSelected
|
editorStateVM.coverUnderlyingLayers = isSelected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
togglebutton {
|
togglebutton {
|
||||||
graphic = FontIcon("fa-th")
|
graphic = FontIcon("fa-th")
|
||||||
|
|
||||||
action {
|
action {
|
||||||
editorStateVM.showGrid = isSelected
|
editorStateVM.showGrid = isSelected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
togglebutton(value = BrushMode.PAINTING_MODE, group = brushMode) {
|
togglebutton(value = BrushMode.PAINTING_MODE, group = brushMode) {
|
||||||
graphic = FontIcon("fa-paint-brush")
|
graphic = FontIcon("fa-paint-brush")
|
||||||
|
|
||||||
action {
|
action {
|
||||||
brushVM.item = brushVM.withMode(BrushMode.PAINTING_MODE)
|
brushVM.item = brushVM.withMode(BrushMode.PAINTING_MODE)
|
||||||
brushVM.commit()
|
brushVM.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
togglebutton(value = BrushMode.ERASING_MODE, group = brushMode) {
|
togglebutton(value = BrushMode.ERASING_MODE, group = brushMode) {
|
||||||
graphic = FontIcon("fa-eraser")
|
graphic = FontIcon("fa-eraser")
|
||||||
|
|
||||||
action {
|
action {
|
||||||
brushVM.item = brushVM.withMode(BrushMode.ERASING_MODE)
|
brushVM.item = brushVM.withMode(BrushMode.ERASING_MODE)
|
||||||
brushVM.commit()
|
brushVM.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this += FontIcon("fa-paint-brush").apply { iconSize = 10 }
|
this += FontIcon("fa-paint-brush").apply { iconSize = 10 }
|
||||||
|
|
||||||
slider(1..5) {
|
slider(1..5) {
|
||||||
majorTickUnit = 1.0
|
majorTickUnit = 1.0
|
||||||
isSnapToTicks = true
|
isSnapToTicks = true
|
||||||
minorTickCount = 0
|
minorTickCount = 0
|
||||||
|
|
||||||
valueProperty().addListener { _, _, newValue ->
|
valueProperty().addListener { _, _, newValue ->
|
||||||
brushVM.item = brushVM.withRange(newValue.toInt())
|
brushVM.item = brushVM.withRange(newValue.toInt())
|
||||||
brushVM.commit()
|
brushVM.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
brushVM.itemProperty.addListener { _, _, brush ->
|
brushVM.itemProperty.addListener { _, _, brush ->
|
||||||
value = brush.range.toDouble()
|
value = brush.range.toDouble()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this += FontIcon("fa-paint-brush").apply { iconSize = 15 }
|
this += FontIcon("fa-paint-brush").apply { iconSize = 15 }
|
||||||
|
|
||||||
button(graphic = FontIcon("fa-sliders")) {
|
button(graphic = FontIcon("fa-sliders")) {
|
||||||
action {
|
action {
|
||||||
find<MapSettingsFragment>().openModal(block = true, resizable = false)
|
find<MapSettingsFragment>().openModal(block = true, resizable = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
126
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapView.kt
Executable file → Normal file
126
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapView.kt
Executable file → Normal file
@@ -1,64 +1,64 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.view
|
package com.bartlomiejpluta.base.editor.map.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||||
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.map.component.MapPane
|
import com.bartlomiejpluta.base.editor.map.component.MapPane
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
import javafx.scene.input.MouseButton
|
import javafx.scene.input.MouseButton
|
||||||
import javafx.scene.input.MouseEvent
|
import javafx.scene.input.MouseEvent
|
||||||
import javafx.scene.transform.Scale
|
import javafx.scene.transform.Scale
|
||||||
import tornadofx.View
|
import tornadofx.View
|
||||||
import tornadofx.group
|
import tornadofx.group
|
||||||
import tornadofx.plusAssign
|
import tornadofx.plusAssign
|
||||||
import tornadofx.scrollpane
|
import tornadofx.scrollpane
|
||||||
|
|
||||||
|
|
||||||
class MapView : View() {
|
class MapView : View() {
|
||||||
private val undoRedoService: UndoRedoService by di()
|
private val undoRedoService: UndoRedoService by di()
|
||||||
|
|
||||||
override val scope = super.scope as UndoableScope
|
override val scope = super.scope as UndoableScope
|
||||||
|
|
||||||
private val mapVM = find<GameMapVM>()
|
private val mapVM = find<GameMapVM>()
|
||||||
|
|
||||||
private val brushVM = find<BrushVM>()
|
private val brushVM = find<BrushVM>()
|
||||||
|
|
||||||
private val editorStateVM = find<EditorStateVM>()
|
private val editorStateVM = find<EditorStateVM>()
|
||||||
|
|
||||||
private val mapPane = MapPane(mapVM, brushVM, editorStateVM) { undoRedoService.push(it, scope) }
|
private val mapPane = MapPane(mapVM, brushVM, editorStateVM) { undoRedoService.push(it, scope) }
|
||||||
|
|
||||||
private val zoom = Scale(1.0, 1.0, 0.0, 0.0).apply {
|
private val zoom = Scale(1.0, 1.0, 0.0, 0.0).apply {
|
||||||
xProperty().bind(editorStateVM.zoomProperty)
|
xProperty().bind(editorStateVM.zoomProperty)
|
||||||
yProperty().bind(editorStateVM.zoomProperty)
|
yProperty().bind(editorStateVM.zoomProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
brushVM.item = mapVM.tileSet.baseBrush
|
brushVM.item = mapVM.tileSet.baseBrush
|
||||||
brushVM.commit()
|
brushVM.commit()
|
||||||
|
|
||||||
subscribe<RedrawMapRequestEvent> { mapPane.render() }
|
subscribe<RedrawMapRequestEvent> { mapPane.render() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val root = scrollpane {
|
override val root = scrollpane {
|
||||||
prefWidth = 640.0
|
prefWidth = 640.0
|
||||||
prefHeight = 480.0
|
prefHeight = 480.0
|
||||||
isPannable = true
|
isPannable = true
|
||||||
|
|
||||||
group {
|
group {
|
||||||
|
|
||||||
// Let the ScrollPane.viewRect only pan on middle button.
|
// Let the ScrollPane.viewRect only pan on middle button.
|
||||||
addEventHandler(MouseEvent.ANY) {
|
addEventHandler(MouseEvent.ANY) {
|
||||||
if (it.button != MouseButton.MIDDLE) {
|
if (it.button != MouseButton.MIDDLE) {
|
||||||
it.consume()
|
it.consume()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group {
|
group {
|
||||||
this += mapPane
|
this += mapPane
|
||||||
transforms += zoom
|
transforms += zoom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
56
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/BrushVM.kt
Executable file → Normal file
56
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/BrushVM.kt
Executable file → Normal file
@@ -1,29 +1,29 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||||
import com.bartlomiejpluta.base.editor.map.model.brush.BrushMode
|
import com.bartlomiejpluta.base.editor.map.model.brush.BrushMode
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||||
import tornadofx.ItemViewModel
|
import tornadofx.ItemViewModel
|
||||||
import tornadofx.getValue
|
import tornadofx.getValue
|
||||||
|
|
||||||
class BrushVM : ItemViewModel<Brush>(Brush.of(arrayOf(arrayOf()))) {
|
class BrushVM : ItemViewModel<Brush>(Brush.of(arrayOf(arrayOf()))) {
|
||||||
val brush = bind(Brush::brush)
|
val brush = bind(Brush::brush)
|
||||||
|
|
||||||
val rowsProperty = bind(Brush::rowsProperty)
|
val rowsProperty = bind(Brush::rowsProperty)
|
||||||
val rows by rowsProperty
|
val rows by rowsProperty
|
||||||
|
|
||||||
val columnsProperty = bind(Brush::columnsProperty)
|
val columnsProperty = bind(Brush::columnsProperty)
|
||||||
val columns by columnsProperty
|
val columns by columnsProperty
|
||||||
|
|
||||||
val rangeProperty = bind(Brush::rangeProperty)
|
val rangeProperty = bind(Brush::rangeProperty)
|
||||||
val range by rangeProperty
|
val range by rangeProperty
|
||||||
|
|
||||||
val modeProperty = bind(Brush::modeProperty)
|
val modeProperty = bind(Brush::modeProperty)
|
||||||
val mode by modeProperty
|
val mode by modeProperty
|
||||||
|
|
||||||
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) = item.forEach(consumer)
|
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) = item.forEach(consumer)
|
||||||
|
|
||||||
fun withRange(range: Int) = item.withRange(range)
|
fun withRange(range: Int) = item.withRange(range)
|
||||||
|
|
||||||
fun withMode(mode: BrushMode) = item.withMode(mode)
|
fun withMode(mode: BrushMode) = item.withMode(mode)
|
||||||
}
|
}
|
||||||
54
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/EditorStateVM.kt
Executable file → Normal file
54
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/EditorStateVM.kt
Executable file → Normal file
@@ -1,28 +1,28 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||||
|
|
||||||
import javafx.beans.property.SimpleBooleanProperty
|
import javafx.beans.property.SimpleBooleanProperty
|
||||||
import javafx.beans.property.SimpleDoubleProperty
|
import javafx.beans.property.SimpleDoubleProperty
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import tornadofx.ViewModel
|
import tornadofx.ViewModel
|
||||||
import tornadofx.getValue
|
import tornadofx.getValue
|
||||||
import tornadofx.setValue
|
import tornadofx.setValue
|
||||||
|
|
||||||
class EditorStateVM : ViewModel() {
|
class EditorStateVM : ViewModel() {
|
||||||
val selectedLayerProperty = SimpleIntegerProperty(0)
|
val selectedLayerProperty = SimpleIntegerProperty(0)
|
||||||
var selectedLayer by selectedLayerProperty
|
var selectedLayer by selectedLayerProperty
|
||||||
|
|
||||||
val showGridProperty = SimpleBooleanProperty(true)
|
val showGridProperty = SimpleBooleanProperty(true)
|
||||||
var showGrid by showGridProperty
|
var showGrid by showGridProperty
|
||||||
|
|
||||||
val coverUnderlyingLayersProperty = SimpleBooleanProperty(true)
|
val coverUnderlyingLayersProperty = SimpleBooleanProperty(true)
|
||||||
var coverUnderlyingLayers by coverUnderlyingLayersProperty
|
var coverUnderlyingLayers by coverUnderlyingLayersProperty
|
||||||
|
|
||||||
val zoomProperty = SimpleDoubleProperty(1.0)
|
val zoomProperty = SimpleDoubleProperty(1.0)
|
||||||
var zoom by zoomProperty
|
var zoom by zoomProperty
|
||||||
|
|
||||||
val cursorRowProperty = SimpleIntegerProperty(-1)
|
val cursorRowProperty = SimpleIntegerProperty(-1)
|
||||||
val cursorRow by cursorRowProperty
|
val cursorRow by cursorRowProperty
|
||||||
|
|
||||||
val cursorColumnProperty = SimpleIntegerProperty(-1)
|
val cursorColumnProperty = SimpleIntegerProperty(-1)
|
||||||
val cursorColumn by cursorColumnProperty
|
val cursorColumn by cursorColumnProperty
|
||||||
}
|
}
|
||||||
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt
Executable file → Normal file
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt
Executable file → Normal file
@@ -1,39 +1,39 @@
|
|||||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||||
import javafx.beans.property.SimpleListProperty
|
import javafx.beans.property.SimpleListProperty
|
||||||
import tornadofx.ItemViewModel
|
import tornadofx.ItemViewModel
|
||||||
import tornadofx.getValue
|
import tornadofx.getValue
|
||||||
import tornadofx.setValue
|
import tornadofx.setValue
|
||||||
|
|
||||||
class GameMapVM(map: GameMap) : ItemViewModel<GameMap>(map) {
|
class GameMapVM(map: GameMap) : ItemViewModel<GameMap>(map) {
|
||||||
val layers: SimpleListProperty<Layer> = bind(GameMap::layers)
|
val layers: SimpleListProperty<Layer> = bind(GameMap::layers)
|
||||||
|
|
||||||
val nameProperty = bind(GameMap::nameProperty)
|
val nameProperty = bind(GameMap::nameProperty)
|
||||||
var name by nameProperty
|
var name by nameProperty
|
||||||
|
|
||||||
val tileSetProperty = bind(GameMap::tileSet)
|
val tileSetProperty = bind(GameMap::tileSet)
|
||||||
val tileSet by tileSetProperty
|
val tileSet by tileSetProperty
|
||||||
|
|
||||||
val rowsProperty = bind(GameMap::rowsProperty)
|
val rowsProperty = bind(GameMap::rowsProperty)
|
||||||
var rows by rowsProperty
|
var rows by rowsProperty
|
||||||
|
|
||||||
val columnsProperty = bind(GameMap::columnsProperty)
|
val columnsProperty = bind(GameMap::columnsProperty)
|
||||||
var columns by columnsProperty
|
var columns by columnsProperty
|
||||||
|
|
||||||
val tileWidthProperty = bind(GameMap::tileWidth)
|
val tileWidthProperty = bind(GameMap::tileWidth)
|
||||||
val tileWidth by tileWidthProperty
|
val tileWidth by tileWidthProperty
|
||||||
|
|
||||||
val tileHeightProperty = bind(GameMap::tileHeight)
|
val tileHeightProperty = bind(GameMap::tileHeight)
|
||||||
val tileHeight by tileHeightProperty
|
val tileHeight by tileHeightProperty
|
||||||
|
|
||||||
val widthProperty = bind(GameMap::widthProperty)
|
val widthProperty = bind(GameMap::widthProperty)
|
||||||
val width by widthProperty
|
val width by widthProperty
|
||||||
|
|
||||||
val heightProperty = bind(GameMap::heightProperty)
|
val heightProperty = bind(GameMap::heightProperty)
|
||||||
val height by heightProperty
|
val height by heightProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
62
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/DefaultProjectManager.kt
Executable file → Normal file
62
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/DefaultProjectManager.kt
Executable file → Normal file
@@ -1,32 +1,32 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.manager
|
package com.bartlomiejpluta.base.editor.project.manager
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
import com.bartlomiejpluta.base.editor.project.serial.ProjectDeserializer
|
import com.bartlomiejpluta.base.editor.project.serial.ProjectDeserializer
|
||||||
import com.bartlomiejpluta.base.editor.project.serial.ProjectSerializer
|
import com.bartlomiejpluta.base.editor.project.serial.ProjectSerializer
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class DefaultProjectManager : ProjectManager {
|
class DefaultProjectManager : ProjectManager {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var projectSerializer: ProjectSerializer
|
private lateinit var projectSerializer: ProjectSerializer
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var projectDeserializer: ProjectDeserializer
|
private lateinit var projectDeserializer: ProjectDeserializer
|
||||||
|
|
||||||
override fun saveProject(project: Project) {
|
override fun saveProject(project: Project) {
|
||||||
project.sourceDirectory.mkdirs()
|
project.sourceDirectory.mkdirs()
|
||||||
|
|
||||||
FileOutputStream(File(project.sourceDirectory, "project.bep")).use {
|
FileOutputStream(File(project.sourceDirectory, "project.bep")).use {
|
||||||
projectSerializer.serialize(project, it)
|
projectSerializer.serialize(project, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openProject(file: File) = FileInputStream(file)
|
override fun openProject(file: File) = FileInputStream(file)
|
||||||
.use { projectDeserializer.deserialize(it) }
|
.use { projectDeserializer.deserialize(it) }
|
||||||
.apply { sourceDirectoryProperty.value = file.parentFile }
|
.apply { sourceDirectoryProperty.value = file.parentFile }
|
||||||
}
|
}
|
||||||
16
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/ProjectManager.kt
Executable file → Normal file
16
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/ProjectManager.kt
Executable file → Normal file
@@ -1,9 +1,9 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.manager
|
package com.bartlomiejpluta.base.editor.project.manager
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
interface ProjectManager {
|
interface ProjectManager {
|
||||||
fun saveProject(project: Project)
|
fun saveProject(project: Project)
|
||||||
fun openProject(file: File): Project
|
fun openProject(file: File): Project
|
||||||
}
|
}
|
||||||
28
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt
Executable file → Normal file
28
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt
Executable file → Normal file
@@ -1,14 +1,14 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.model
|
package com.bartlomiejpluta.base.editor.project.model
|
||||||
|
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class Project {
|
class Project {
|
||||||
val nameProperty = SimpleStringProperty()
|
val nameProperty = SimpleStringProperty()
|
||||||
var name by nameProperty
|
var name by nameProperty
|
||||||
|
|
||||||
val sourceDirectoryProperty = SimpleObjectProperty<File>()
|
val sourceDirectoryProperty = SimpleObjectProperty<File>()
|
||||||
val sourceDirectory by sourceDirectoryProperty
|
val sourceDirectory by sourceDirectoryProperty
|
||||||
}
|
}
|
||||||
|
|||||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectDeserializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectDeserializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.serial
|
package com.bartlomiejpluta.base.editor.project.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
|
|
||||||
interface ProjectDeserializer : Deserializer<Project>
|
interface ProjectDeserializer : Deserializer<Project>
|
||||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectSerializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectSerializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.serial
|
package com.bartlomiejpluta.base.editor.project.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
|
|
||||||
interface ProjectSerializer : Serializer<Project>
|
interface ProjectSerializer : Serializer<Project>
|
||||||
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt
Executable file → Normal file
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt
Executable file → Normal file
@@ -1,18 +1,18 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.serial
|
package com.bartlomiejpluta.base.editor.project.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
import com.bartlomiejpluta.base.proto.ProjectProto
|
import com.bartlomiejpluta.base.proto.ProjectProto
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ProtobufProjectDeserializer : ProjectDeserializer {
|
class ProtobufProjectDeserializer : ProjectDeserializer {
|
||||||
|
|
||||||
override fun deserialize(input: InputStream): Project {
|
override fun deserialize(input: InputStream): Project {
|
||||||
val proto = ProjectProto.Project.parseFrom(input)
|
val proto = ProjectProto.Project.parseFrom(input)
|
||||||
val project = Project()
|
val project = Project()
|
||||||
project.name = proto.name
|
project.name = proto.name
|
||||||
|
|
||||||
return project
|
return project
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
30
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt
Executable file → Normal file
30
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt
Executable file → Normal file
@@ -1,16 +1,16 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.serial
|
package com.bartlomiejpluta.base.editor.project.serial
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
import com.bartlomiejpluta.base.proto.ProjectProto
|
import com.bartlomiejpluta.base.proto.ProjectProto
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ProtobufProjectSerializer : ProjectSerializer {
|
class ProtobufProjectSerializer : ProjectSerializer {
|
||||||
|
|
||||||
override fun serialize(item: Project, output: OutputStream) {
|
override fun serialize(item: Project, output: OutputStream) {
|
||||||
val proto = ProjectProto.Project.newBuilder()
|
val proto = ProjectProto.Project.newBuilder()
|
||||||
proto.name = item.name
|
proto.name = item.name
|
||||||
proto.build().writeTo(output)
|
proto.build().writeTo(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
190
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/view/ProjectSettingsFragment.kt
Executable file → Normal file
190
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/view/ProjectSettingsFragment.kt
Executable file → Normal file
@@ -1,96 +1,96 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.view
|
package com.bartlomiejpluta.base.editor.project.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
||||||
import javafx.beans.binding.Bindings
|
import javafx.beans.binding.Bindings
|
||||||
import javafx.beans.binding.Bindings.createStringBinding
|
import javafx.beans.binding.Bindings.createStringBinding
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ProjectSettingsFragment : Fragment("Project Settings") {
|
class ProjectSettingsFragment : Fragment("Project Settings") {
|
||||||
private val projectVM = find<ProjectVM>(FX.defaultScope)
|
private val projectVM = find<ProjectVM>(FX.defaultScope)
|
||||||
|
|
||||||
private val rootDirectory = SimpleStringProperty("")
|
private val rootDirectory = SimpleStringProperty("")
|
||||||
private val projectDirectory = SimpleStringProperty("")
|
private val projectDirectory = SimpleStringProperty("")
|
||||||
private val directory = createStringBinding({
|
private val directory = createStringBinding({
|
||||||
File(rootDirectory.value, projectDirectory.value).absolutePath
|
File(rootDirectory.value, projectDirectory.value).absolutePath
|
||||||
}, rootDirectory, projectDirectory)
|
}, rootDirectory, projectDirectory)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
directory.addListener { _, _, path -> projectVM.sourceDirectoryProperty.value = File(path) }
|
directory.addListener { _, _, path -> projectVM.sourceDirectoryProperty.value = File(path) }
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = false
|
var result = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override val root = form {
|
override val root = form {
|
||||||
fieldset("Project Settings") {
|
fieldset("Project Settings") {
|
||||||
field("Project Name") {
|
field("Project Name") {
|
||||||
textfield(projectVM.nameProperty) {
|
textfield(projectVM.nameProperty) {
|
||||||
required()
|
required()
|
||||||
trimWhitespace()
|
trimWhitespace()
|
||||||
whenDocked { requestFocus() }
|
whenDocked { requestFocus() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field("Project Location") {
|
field("Project Location") {
|
||||||
hbox {
|
hbox {
|
||||||
textfield(rootDirectory) {
|
textfield(rootDirectory) {
|
||||||
trimWhitespace()
|
trimWhitespace()
|
||||||
|
|
||||||
projectVM.validationContext.addValidator(this, rootDirectory) {
|
projectVM.validationContext.addValidator(this, rootDirectory) {
|
||||||
when {
|
when {
|
||||||
it.isNullOrBlank() -> error("Field is required")
|
it.isNullOrBlank() -> error("Field is required")
|
||||||
!File(it).exists() -> error("Provide valid path to the direction")
|
!File(it).exists() -> error("Provide valid path to the direction")
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button("Choose") {
|
button("Choose") {
|
||||||
action {
|
action {
|
||||||
rootDirectory.value = chooseDirectory("Project Location")?.absolutePath
|
rootDirectory.value = chooseDirectory("Project Location")?.absolutePath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field("Project Directory Name") {
|
field("Project Directory Name") {
|
||||||
textfield(projectDirectory) {
|
textfield(projectDirectory) {
|
||||||
trimWhitespace()
|
trimWhitespace()
|
||||||
|
|
||||||
projectVM.validationContext.addValidator(this, projectDirectory) {
|
projectVM.validationContext.addValidator(this, projectDirectory) {
|
||||||
when {
|
when {
|
||||||
it.isNullOrBlank() -> error("Field is required")
|
it.isNullOrBlank() -> error("Field is required")
|
||||||
File(directory.value).exists() -> error("The directory ${directory.value} already exists")
|
File(directory.value).exists() -> error("The directory ${directory.value} already exists")
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label(Bindings.format("Directory:\n%s", directory))
|
label(Bindings.format("Directory:\n%s", directory))
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonbar {
|
buttonbar {
|
||||||
button("Ok") {
|
button("Ok") {
|
||||||
action {
|
action {
|
||||||
projectVM.commit {
|
projectVM.commit {
|
||||||
result = true
|
result = true
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shortcut("Enter")
|
shortcut("Enter")
|
||||||
}
|
}
|
||||||
|
|
||||||
button("Reset") {
|
button("Reset") {
|
||||||
action { projectVM.rollback() }
|
action { projectVM.rollback() }
|
||||||
}
|
}
|
||||||
|
|
||||||
button("Cancel") {
|
button("Cancel") {
|
||||||
action { close() }
|
action { close() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/viewmodel/ProjectVM.kt
Executable file → Normal file
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/viewmodel/ProjectVM.kt
Executable file → Normal file
@@ -1,12 +1,12 @@
|
|||||||
package com.bartlomiejpluta.base.editor.project.viewmodel
|
package com.bartlomiejpluta.base.editor.project.viewmodel
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class ProjectVM(project: Project) : ItemViewModel<Project>(project) {
|
class ProjectVM(project: Project) : ItemViewModel<Project>(project) {
|
||||||
val nameProperty = bind(Project::nameProperty)
|
val nameProperty = bind(Project::nameProperty)
|
||||||
val name by nameProperty
|
val name by nameProperty
|
||||||
|
|
||||||
val sourceDirectoryProperty = bind(Project::sourceDirectoryProperty)
|
val sourceDirectoryProperty = bind(Project::sourceDirectoryProperty)
|
||||||
val sourceDirectory by sourceDirectoryProperty
|
val sourceDirectory by sourceDirectoryProperty
|
||||||
}
|
}
|
||||||
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt
Executable file → Normal file
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt
Executable file → Normal file
@@ -1,18 +1,18 @@
|
|||||||
package com.bartlomiejpluta.base.editor.render.input
|
package com.bartlomiejpluta.base.editor.render.input
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||||
import javafx.event.EventType
|
import javafx.event.EventType
|
||||||
import javafx.scene.input.MouseButton
|
import javafx.scene.input.MouseButton
|
||||||
import javafx.scene.input.MouseEvent
|
import javafx.scene.input.MouseEvent
|
||||||
|
|
||||||
class MapMouseEvent(val row: Int, val column: Int, val type: EventType<out MouseEvent>, val button: MouseButton) {
|
class MapMouseEvent(val row: Int, val column: Int, val type: EventType<out MouseEvent>, val button: MouseButton) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun of(event: MouseEvent, tileSet: TileSet) = MapMouseEvent(
|
fun of(event: MouseEvent, tileSet: TileSet) = MapMouseEvent(
|
||||||
(event.y / tileSet.tileHeight).toInt(),
|
(event.y / tileSet.tileHeight).toInt(),
|
||||||
(event.x / tileSet.tileWidth).toInt(),
|
(event.x / tileSet.tileWidth).toInt(),
|
||||||
event.eventType,
|
event.eventType,
|
||||||
event.button
|
event.button
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEventHandler.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEventHandler.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.editor.render.input
|
package com.bartlomiejpluta.base.editor.render.input
|
||||||
|
|
||||||
interface MapMouseEventHandler {
|
interface MapMouseEventHandler {
|
||||||
fun handleMouseInput(event: MapMouseEvent)
|
fun handleMouseInput(event: MapMouseEvent)
|
||||||
}
|
}
|
||||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/model/Renderable.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/model/Renderable.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
package com.bartlomiejpluta.base.editor.render.model
|
package com.bartlomiejpluta.base.editor.render.model
|
||||||
|
|
||||||
import javafx.scene.canvas.GraphicsContext
|
import javafx.scene.canvas.GraphicsContext
|
||||||
|
|
||||||
interface Renderable {
|
interface Renderable {
|
||||||
fun render(gc: GraphicsContext)
|
fun render(gc: GraphicsContext)
|
||||||
}
|
}
|
||||||
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UIDManager.kt
Executable file → Normal file
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UIDManager.kt
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
||||||
|
|
||||||
interface UIDManager {
|
interface UIDManager {
|
||||||
fun nextUID(target: UIDTarget): String
|
fun nextUID(target: UIDTarget): String
|
||||||
fun loadData(target: UIDTarget, uids: Set<String>)
|
fun loadData(target: UIDTarget, uids: Set<String>)
|
||||||
}
|
}
|
||||||
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UUIDBasedUIDManager.kt
Executable file → Normal file
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UUIDBasedUIDManager.kt
Executable file → Normal file
@@ -1,26 +1,26 @@
|
|||||||
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class UUIDBasedUIDManager : UIDManager {
|
class UUIDBasedUIDManager : UIDManager {
|
||||||
private val registry = mutableMapOf<UIDTarget, Set<String>>()
|
private val registry = mutableMapOf<UIDTarget, Set<String>>()
|
||||||
|
|
||||||
override fun nextUID(target: UIDTarget): String {
|
override fun nextUID(target: UIDTarget): String {
|
||||||
val set = registry.putIfAbsent(target, mutableSetOf())!!
|
val set = registry.putIfAbsent(target, mutableSetOf())!!
|
||||||
|
|
||||||
var uid = ""
|
var uid = ""
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uid = UUID.randomUUID().toString()
|
uid = UUID.randomUUID().toString()
|
||||||
} while (uid !in set)
|
} while (uid !in set)
|
||||||
|
|
||||||
return uid
|
return uid
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadData(target: UIDTarget, uids: Set<String>) {
|
override fun loadData(target: UIDTarget, uids: Set<String>) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/model/UIDTarget.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/model/UIDTarget.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.editor.resource.uid.model
|
package com.bartlomiejpluta.base.editor.resource.uid.model
|
||||||
|
|
||||||
enum class UIDTarget {
|
enum class UIDTarget {
|
||||||
MAP
|
MAP
|
||||||
}
|
}
|
||||||
136
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt
Executable file → Normal file
136
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt
Executable file → Normal file
@@ -1,69 +1,69 @@
|
|||||||
package com.bartlomiejpluta.base.editor.tileset.canvas
|
package com.bartlomiejpluta.base.editor.tileset.canvas
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
||||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
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 gameMapVM: GameMapVM, private val selection: TileSetSelection) : Renderable, MapMouseEventHandler {
|
class TileSetCanvas(private val gameMapVM: GameMapVM, private val selection: TileSetSelection) : Renderable, MapMouseEventHandler {
|
||||||
private var mouseRow = -1
|
private var mouseRow = -1
|
||||||
private var mouseColumn = -1
|
private var mouseColumn = -1
|
||||||
|
|
||||||
override fun render(gc: GraphicsContext) {
|
override fun render(gc: GraphicsContext) {
|
||||||
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
||||||
|
|
||||||
renderTiles(gc)
|
renderTiles(gc)
|
||||||
selection.render(gc)
|
selection.render(gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTiles(gc: GraphicsContext) {
|
private fun renderTiles(gc: GraphicsContext) {
|
||||||
gameMapVM.tileSet.forEach { row, column, tile ->
|
gameMapVM.tileSet.forEach { row, column, tile ->
|
||||||
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
||||||
gc.fillRect(
|
gc.fillRect(
|
||||||
column * tile.image.width,
|
column * tile.image.width,
|
||||||
row * tile.image.height,
|
row * tile.image.height,
|
||||||
gameMapVM.tileSet.tileWidth.toDouble(),
|
gameMapVM.tileSet.tileWidth.toDouble(),
|
||||||
gameMapVM.tileSet.tileHeight.toDouble()
|
gameMapVM.tileSet.tileHeight.toDouble()
|
||||||
)
|
)
|
||||||
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleMouseInput(event: MapMouseEvent) {
|
override fun handleMouseInput(event: MapMouseEvent) {
|
||||||
mouseRow = event.row
|
mouseRow = event.row
|
||||||
mouseColumn = event.column
|
mouseColumn = event.column
|
||||||
|
|
||||||
when (event.type) {
|
when (event.type) {
|
||||||
MouseEvent.MOUSE_PRESSED -> beginSelection(event)
|
MouseEvent.MOUSE_PRESSED -> beginSelection(event)
|
||||||
MouseEvent.MOUSE_DRAGGED -> proceedSelection(event)
|
MouseEvent.MOUSE_DRAGGED -> proceedSelection(event)
|
||||||
MouseEvent.MOUSE_RELEASED -> finishSelection(event)
|
MouseEvent.MOUSE_RELEASED -> finishSelection(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun beginSelection(event: MapMouseEvent) {
|
private fun beginSelection(event: MapMouseEvent) {
|
||||||
if (event.button == MouseButton.PRIMARY) {
|
if (event.button == MouseButton.PRIMARY) {
|
||||||
selection.begin(event.row.toDouble(), event.column.toDouble())
|
selection.begin(event.row.toDouble(), event.column.toDouble())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun proceedSelection(event: MapMouseEvent) {
|
private fun proceedSelection(event: MapMouseEvent) {
|
||||||
if (event.button == MouseButton.PRIMARY) {
|
if (event.button == MouseButton.PRIMARY) {
|
||||||
selection.proceed(event.row.toDouble(), event.column.toDouble())
|
selection.proceed(event.row.toDouble(), event.column.toDouble())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun finishSelection(event: MapMouseEvent) {
|
private fun finishSelection(event: MapMouseEvent) {
|
||||||
if (event.button == MouseButton.PRIMARY) {
|
if (event.button == MouseButton.PRIMARY) {
|
||||||
selection.finish(event.row.toDouble(), event.column.toDouble())
|
selection.finish(event.row.toDouble(), event.column.toDouble())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.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, 0.95)
|
private val BACKGROUND_COLOR2 = Color.color(0.95, 0.95, 0.95, 0.95)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
158
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt
Executable file → Normal file
158
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt
Executable file → Normal file
@@ -1,80 +1,80 @@
|
|||||||
package com.bartlomiejpluta.base.editor.tileset.canvas
|
package com.bartlomiejpluta.base.editor.tileset.canvas
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
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
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
class TileSetSelection(private val gameMapVM: GameMapVM, private val brushVM: BrushVM) : Renderable {
|
class TileSetSelection(private val gameMapVM: GameMapVM, private val brushVM: BrushVM) : Renderable {
|
||||||
private var startRow = 0.0
|
private var startRow = 0.0
|
||||||
private var startColumn = 0.0
|
private var startColumn = 0.0
|
||||||
private var offsetRow = 0.0
|
private var offsetRow = 0.0
|
||||||
private var offsetColumn = 0.0
|
private var offsetColumn = 0.0
|
||||||
private var x = 0.0
|
private var x = 0.0
|
||||||
private var y = 0.0
|
private var y = 0.0
|
||||||
private var width = gameMapVM.tileSet.tileWidth.toDouble()
|
private var width = gameMapVM.tileSet.tileWidth.toDouble()
|
||||||
private var height = gameMapVM.tileSet.tileHeight.toDouble()
|
private var height = gameMapVM.tileSet.tileHeight.toDouble()
|
||||||
|
|
||||||
|
|
||||||
fun begin(row: Double, column: Double) {
|
fun begin(row: Double, column: Double) {
|
||||||
startRow = row
|
startRow = row
|
||||||
offsetRow = 0.0
|
offsetRow = 0.0
|
||||||
startColumn = column
|
startColumn = column
|
||||||
offsetColumn = 0.0
|
offsetColumn = 0.0
|
||||||
|
|
||||||
updateRect(row, column)
|
updateRect(row, column)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRect(row: Double, column: Double) {
|
private fun updateRect(row: Double, column: Double) {
|
||||||
x = min(column, startColumn) * gameMapVM.tileSet.tileWidth
|
x = min(column, startColumn) * gameMapVM.tileSet.tileWidth
|
||||||
y = min(row, startRow) * gameMapVM.tileSet.tileHeight
|
y = min(row, startRow) * gameMapVM.tileSet.tileHeight
|
||||||
width = (offsetColumn + 1) * gameMapVM.tileSet.tileWidth
|
width = (offsetColumn + 1) * gameMapVM.tileSet.tileWidth
|
||||||
height = (offsetRow + 1) * gameMapVM.tileSet.tileHeight
|
height = (offsetRow + 1) * gameMapVM.tileSet.tileHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
fun proceed(row: Double, column: Double) {
|
fun proceed(row: Double, column: Double) {
|
||||||
offsetRow = abs(row - startRow)
|
offsetRow = abs(row - startRow)
|
||||||
offsetColumn = abs(column - startColumn)
|
offsetColumn = abs(column - startColumn)
|
||||||
|
|
||||||
updateRect(row, column)
|
updateRect(row, column)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finish(row: Double, column: Double) {
|
fun finish(row: Double, column: Double) {
|
||||||
proceed(row, column)
|
proceed(row, column)
|
||||||
|
|
||||||
startRow = min(row, startRow)
|
startRow = min(row, startRow)
|
||||||
startColumn = min(column, startColumn)
|
startColumn = min(column, startColumn)
|
||||||
|
|
||||||
val firstRow = startRow.toInt()
|
val firstRow = startRow.toInt()
|
||||||
val firstColumn = startColumn.toInt()
|
val firstColumn = startColumn.toInt()
|
||||||
val rows = offsetRow.toInt() + 1
|
val rows = offsetRow.toInt() + 1
|
||||||
val columns = offsetColumn.toInt() + 1
|
val columns = offsetColumn.toInt() + 1
|
||||||
|
|
||||||
val brushArray = Array(rows) { rowIndex ->
|
val brushArray = Array(rows) { rowIndex ->
|
||||||
Array(columns) { columnIndex ->
|
Array(columns) { columnIndex ->
|
||||||
gameMapVM.tileSet.getTile(firstRow + rowIndex, firstColumn + columnIndex)
|
gameMapVM.tileSet.getTile(firstRow + rowIndex, firstColumn + columnIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
brushVM.item = Brush.of(brushArray)
|
brushVM.item = Brush.of(brushArray)
|
||||||
brushVM.commit()
|
brushVM.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(gc: GraphicsContext) {
|
override fun render(gc: GraphicsContext) {
|
||||||
gc.fill = SELECTION_FILL_COLOR
|
gc.fill = SELECTION_FILL_COLOR
|
||||||
gc.fillRect(x, y, width, height)
|
gc.fillRect(x, y, width, height)
|
||||||
|
|
||||||
gc.stroke = SELECTION_STROKE_COLOR
|
gc.stroke = SELECTION_STROKE_COLOR
|
||||||
gc.strokeRect(x, y, width, height)
|
gc.strokeRect(x, y, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val SELECTION_FILL_COLOR = Color.color(0.0, 0.7, 1.0, 0.4)
|
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)
|
private val SELECTION_STROKE_COLOR = Color.color(0.0, 0.7, 1.0, 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
82
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt
Executable file → Normal file
82
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt
Executable file → Normal file
@@ -1,42 +1,42 @@
|
|||||||
package com.bartlomiejpluta.base.editor.tileset.component
|
package com.bartlomiejpluta.base.editor.tileset.component
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||||
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetCanvas
|
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetCanvas
|
||||||
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetSelection
|
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetSelection
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
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 gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas(), EventHandler<MouseEvent> {
|
class TileSetPane(private val gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas(), EventHandler<MouseEvent> {
|
||||||
private val selection = TileSetSelection(gameMapVM, brushVM)
|
private val selection = TileSetSelection(gameMapVM, brushVM)
|
||||||
private val tileSetCanvas = TileSetCanvas(gameMapVM, selection)
|
private val tileSetCanvas = TileSetCanvas(gameMapVM, selection)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
onMouseMoved = this
|
onMouseMoved = this
|
||||||
onMouseDragged = this
|
onMouseDragged = this
|
||||||
onMousePressed = this
|
onMousePressed = this
|
||||||
onMouseReleased = this
|
onMouseReleased = this
|
||||||
|
|
||||||
width = gameMapVM.tileSet.width.toDouble()
|
width = gameMapVM.tileSet.width.toDouble()
|
||||||
height = gameMapVM.tileSet.height.toDouble()
|
height = gameMapVM.tileSet.height.toDouble()
|
||||||
|
|
||||||
|
|
||||||
brushVM.itemProperty.addListener { _, _, _ -> render() }
|
brushVM.itemProperty.addListener { _, _, _ -> render() }
|
||||||
|
|
||||||
render()
|
render()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun render() {
|
private fun render() {
|
||||||
tileSetCanvas.render(graphicsContext2D)
|
tileSetCanvas.render(graphicsContext2D)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(event: MouseEvent?) {
|
override fun handle(event: MouseEvent?) {
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
tileSetCanvas.handleMouseInput(MapMouseEvent.of(event, gameMapVM.tileSet))
|
tileSetCanvas.handleMouseInput(MapMouseEvent.of(event, gameMapVM.tileSet))
|
||||||
}
|
}
|
||||||
|
|
||||||
tileSetCanvas.render(graphicsContext2D)
|
tileSetCanvas.render(graphicsContext2D)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/Tile.kt
Executable file → Normal file
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/Tile.kt
Executable file → Normal file
@@ -1,55 +1,55 @@
|
|||||||
package com.bartlomiejpluta.base.editor.tileset.model
|
package com.bartlomiejpluta.base.editor.tileset.model
|
||||||
|
|
||||||
import javafx.scene.image.Image
|
import javafx.scene.image.Image
|
||||||
|
|
||||||
import javafx.scene.image.PixelReader
|
import javafx.scene.image.PixelReader
|
||||||
|
|
||||||
import javafx.scene.image.WritableImage
|
import javafx.scene.image.WritableImage
|
||||||
|
|
||||||
|
|
||||||
class Tile(
|
class Tile(
|
||||||
tileSet: TileSet,
|
tileSet: TileSet,
|
||||||
row: Int,
|
row: Int,
|
||||||
column: Int,
|
column: Int,
|
||||||
val image: Image,
|
val image: Image,
|
||||||
) {
|
) {
|
||||||
val id = row * tileSet.columns + column
|
val id = row * tileSet.columns + column
|
||||||
|
|
||||||
private fun cloneImage(image: Image): Image {
|
private fun cloneImage(image: Image): Image {
|
||||||
val height = image.height.toInt()
|
val height = image.height.toInt()
|
||||||
val width = image.width.toInt()
|
val width = image.width.toInt()
|
||||||
val pixelReader = image.pixelReader
|
val pixelReader = image.pixelReader
|
||||||
val writableImage = WritableImage(width, height)
|
val writableImage = WritableImage(width, height)
|
||||||
val pixelWriter = writableImage.pixelWriter
|
val pixelWriter = writableImage.pixelWriter
|
||||||
|
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
val color = pixelReader.getColor(x, y)
|
val color = pixelReader.getColor(x, y)
|
||||||
pixelWriter.setColor(x, y, color)
|
pixelWriter.setColor(x, y, color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return writableImage
|
return writableImage
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scale(image: Image, factor: Int): Image {
|
fun scale(image: Image, factor: Int): Image {
|
||||||
val width = image.width.toInt()
|
val width = image.width.toInt()
|
||||||
val height = image.height.toInt()
|
val height = image.height.toInt()
|
||||||
val output = WritableImage(width * factor, height * factor)
|
val output = WritableImage(width * factor, height * factor)
|
||||||
|
|
||||||
val reader: PixelReader = image.pixelReader
|
val reader: PixelReader = image.pixelReader
|
||||||
val writer = output.pixelWriter
|
val writer = output.pixelWriter
|
||||||
|
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
val argb = reader.getArgb(x, y)
|
val argb = reader.getArgb(x, y)
|
||||||
for (dy in 0 until factor) {
|
for (dy in 0 until factor) {
|
||||||
for (dx in 0 until factor) {
|
for (dx in 0 until factor) {
|
||||||
writer.setArgb(x * factor + dx, y * factor + dy, argb)
|
writer.setArgb(x * factor + dx, y * factor + dy, argb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
124
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/TileSet.kt
Executable file → Normal file
124
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/TileSet.kt
Executable file → Normal file
@@ -1,63 +1,63 @@
|
|||||||
package com.bartlomiejpluta.base.editor.tileset.model
|
package com.bartlomiejpluta.base.editor.tileset.model
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
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
|
||||||
import tornadofx.getValue
|
import tornadofx.getValue
|
||||||
import tornadofx.toObservable
|
import tornadofx.toObservable
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
|
||||||
class TileSet(private val image: Image, rows: Int, columns: Int) {
|
class TileSet(private val image: Image, rows: Int, columns: Int) {
|
||||||
val rowsProperty = SimpleIntegerProperty(rows)
|
val rowsProperty = SimpleIntegerProperty(rows)
|
||||||
val rows by rowsProperty
|
val rows by rowsProperty
|
||||||
|
|
||||||
val columnsProperty = SimpleIntegerProperty(columns)
|
val columnsProperty = SimpleIntegerProperty(columns)
|
||||||
val columns by columnsProperty
|
val columns by columnsProperty
|
||||||
|
|
||||||
val tileWidthProperty = SimpleIntegerProperty(image.width.toInt() / columns)
|
val tileWidthProperty = SimpleIntegerProperty(image.width.toInt() / columns)
|
||||||
val tileWidth by tileWidthProperty
|
val tileWidth by tileWidthProperty
|
||||||
|
|
||||||
val tileHeightProperty = SimpleIntegerProperty(image.height.toInt() / rows)
|
val tileHeightProperty = SimpleIntegerProperty(image.height.toInt() / rows)
|
||||||
val tileHeight by tileHeightProperty
|
val tileHeight by tileHeightProperty
|
||||||
|
|
||||||
val widthProperty = SimpleIntegerProperty(tileWidth * columns)
|
val widthProperty = SimpleIntegerProperty(tileWidth * columns)
|
||||||
val width by widthProperty
|
val width by widthProperty
|
||||||
|
|
||||||
val heightProperty = SimpleIntegerProperty(tileHeight * rows)
|
val heightProperty = SimpleIntegerProperty(tileHeight * rows)
|
||||||
val height by heightProperty
|
val height by heightProperty
|
||||||
|
|
||||||
val tiles = (0 until rows * columns).map { cropTile(it / columns, it % columns) }.toObservable()
|
val tiles = (0 until rows * columns).map { cropTile(it / columns, it % columns) }.toObservable()
|
||||||
|
|
||||||
val baseBrush: Brush
|
val baseBrush: Brush
|
||||||
get() = Brush.of(arrayOf(arrayOf(tiles[0])))
|
get() = Brush.of(arrayOf(arrayOf(tiles[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)
|
||||||
reader.getPixels(
|
reader.getPixels(
|
||||||
column * tileWidth,
|
column * tileWidth,
|
||||||
row * tileHeight,
|
row * tileHeight,
|
||||||
tileWidth,
|
tileWidth,
|
||||||
tileHeight,
|
tileHeight,
|
||||||
PixelFormat.getByteBgraInstance(),
|
PixelFormat.getByteBgraInstance(),
|
||||||
buffer,
|
buffer,
|
||||||
4 * tileWidth
|
4 * tileWidth
|
||||||
)
|
)
|
||||||
val tile = WritableImage(tileWidth, tileHeight)
|
val tile = WritableImage(tileWidth, tileHeight)
|
||||||
val writer = tile.pixelWriter
|
val writer = tile.pixelWriter
|
||||||
writer.setPixels(0, 0, tileWidth, tileHeight, PixelFormat.getByteBgraInstance(), buffer, 4 * tileWidth)
|
writer.setPixels(0, 0, tileWidth, tileHeight, PixelFormat.getByteBgraInstance(), buffer, 4 * tileWidth)
|
||||||
|
|
||||||
return Tile(this, row, column, tile)
|
return Tile(this, row, column, tile)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTile(row: Int, column: Int) = tiles[(row.coerceIn(0 until rows)) * columns + column.coerceIn(0 until columns)]
|
fun getTile(row: Int, column: Int) = tiles[(row.coerceIn(0 until rows)) * columns + column.coerceIn(0 until columns)]
|
||||||
|
|
||||||
fun getTile(id: Int) = tiles[id]
|
fun getTile(id: Int) = tiles[id]
|
||||||
|
|
||||||
fun forEach(consumer: (row: Int, column: Int, tile: Tile) -> Unit) = tiles.forEachIndexed { id, tile ->
|
fun forEach(consumer: (row: Int, column: Int, tile: Tile) -> Unit) = tiles.forEachIndexed { id, tile ->
|
||||||
consumer(id / columns, id % columns, tile)
|
consumer(id / columns, id % columns, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
36
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/TileSetView.kt
Executable file → Normal file
36
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/TileSetView.kt
Executable file → Normal file
@@ -1,19 +1,19 @@
|
|||||||
package com.bartlomiejpluta.base.editor.tileset.view
|
package com.bartlomiejpluta.base.editor.tileset.view
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.tileset.component.TileSetPane
|
import com.bartlomiejpluta.base.editor.tileset.component.TileSetPane
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||||
import tornadofx.View
|
import tornadofx.View
|
||||||
import tornadofx.plusAssign
|
import tornadofx.plusAssign
|
||||||
import tornadofx.scrollpane
|
import tornadofx.scrollpane
|
||||||
|
|
||||||
class TileSetView : View() {
|
class TileSetView : View() {
|
||||||
private val gameMapVM = find<GameMapVM>()
|
private val gameMapVM = find<GameMapVM>()
|
||||||
private val brushVM = find<BrushVM>()
|
private val brushVM = find<BrushVM>()
|
||||||
|
|
||||||
private val tileSetPane = TileSetPane(gameMapVM, brushVM)
|
private val tileSetPane = TileSetPane(gameMapVM, brushVM)
|
||||||
|
|
||||||
override val root = scrollpane {
|
override val root = scrollpane {
|
||||||
this += tileSetPane
|
this += tileSetPane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4
editor/src/main/resources/application.yml
Executable file → Normal file
4
editor/src/main/resources/application.yml
Executable file → Normal file
@@ -1,3 +1,3 @@
|
|||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
com.bartlomiejpluta.base.editor: DEBUG
|
com.bartlomiejpluta.base.editor: DEBUG
|
||||||
0
engine/build.gradle
Executable file → Normal file
0
engine/build.gradle
Executable file → Normal file
222
engine/src/main/java/com/bartlomiejpluta/base/core/engine/DefaultGameEngine.java
Executable file → Normal file
222
engine/src/main/java/com/bartlomiejpluta/base/core/engine/DefaultGameEngine.java
Executable file → Normal file
@@ -1,111 +1,111 @@
|
|||||||
package com.bartlomiejpluta.base.core.engine;
|
package com.bartlomiejpluta.base.core.engine;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gc.OffHeapGarbageCollector;
|
import com.bartlomiejpluta.base.core.gc.OffHeapGarbageCollector;
|
||||||
import com.bartlomiejpluta.base.core.logic.GameLogic;
|
import com.bartlomiejpluta.base.core.logic.GameLogic;
|
||||||
import com.bartlomiejpluta.base.core.thread.ThreadManager;
|
import com.bartlomiejpluta.base.core.thread.ThreadManager;
|
||||||
import com.bartlomiejpluta.base.core.time.ChronoMeter;
|
import com.bartlomiejpluta.base.core.time.ChronoMeter;
|
||||||
import com.bartlomiejpluta.base.core.ui.Window;
|
import com.bartlomiejpluta.base.core.ui.Window;
|
||||||
import com.bartlomiejpluta.base.core.ui.WindowManager;
|
import com.bartlomiejpluta.base.core.ui.WindowManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class DefaultGameEngine implements GameEngine {
|
public class DefaultGameEngine implements GameEngine {
|
||||||
private static final String THREAD_NAME = "Game Main Thread";
|
private static final String THREAD_NAME = "Game Main Thread";
|
||||||
|
|
||||||
private final WindowManager windowManager;
|
private final WindowManager windowManager;
|
||||||
private final ThreadManager threadManager;
|
private final ThreadManager threadManager;
|
||||||
private final GameLogic logic;
|
private final GameLogic logic;
|
||||||
private final OffHeapGarbageCollector garbageCollector;
|
private final OffHeapGarbageCollector garbageCollector;
|
||||||
|
|
||||||
private final Thread thread;
|
private final Thread thread;
|
||||||
private final Window window;
|
private final Window window;
|
||||||
private final ChronoMeter chrono;
|
private final ChronoMeter chrono;
|
||||||
private final int targetUps;
|
private final int targetUps;
|
||||||
|
|
||||||
private boolean running = false;
|
private boolean running = false;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public DefaultGameEngine(WindowManager windowManager,
|
public DefaultGameEngine(WindowManager windowManager,
|
||||||
ThreadManager threadManager,
|
ThreadManager threadManager,
|
||||||
GameLogic logic,
|
GameLogic logic,
|
||||||
OffHeapGarbageCollector garbageCollector,
|
OffHeapGarbageCollector garbageCollector,
|
||||||
@Value("${app.window.title}") String title,
|
@Value("${app.window.title}") String title,
|
||||||
@Value("${app.window.width}") int width,
|
@Value("${app.window.width}") int width,
|
||||||
@Value("${app.window.height}") int height,
|
@Value("${app.window.height}") int height,
|
||||||
@Value("${app.core.targetUps}") int targetUps) {
|
@Value("${app.core.targetUps}") int targetUps) {
|
||||||
this.windowManager = windowManager;
|
this.windowManager = windowManager;
|
||||||
this.threadManager = threadManager;
|
this.threadManager = threadManager;
|
||||||
this.logic = logic;
|
this.logic = logic;
|
||||||
this.garbageCollector = garbageCollector;
|
this.garbageCollector = garbageCollector;
|
||||||
|
|
||||||
this.window = windowManager.createWindow(title, width, height);
|
this.window = windowManager.createWindow(title, width, height);
|
||||||
this.thread = threadManager.createThread(THREAD_NAME, this::run);
|
this.thread = threadManager.createThread(THREAD_NAME, this::run);
|
||||||
this.chrono = new ChronoMeter();
|
this.chrono = new ChronoMeter();
|
||||||
this.targetUps = targetUps;
|
this.targetUps = targetUps;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void run() {
|
private void run() {
|
||||||
try {
|
try {
|
||||||
init();
|
init();
|
||||||
loop();
|
loop();
|
||||||
} finally {
|
} finally {
|
||||||
cleanUp();
|
cleanUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
log.info("Initializing game engine");
|
log.info("Initializing game engine");
|
||||||
window.init();
|
window.init();
|
||||||
chrono.init();
|
chrono.init();
|
||||||
logic.init(window);
|
logic.init(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loop() {
|
private void loop() {
|
||||||
log.info("Starting game loop");
|
log.info("Starting game loop");
|
||||||
running = true;
|
running = true;
|
||||||
var dt = 0.0f;
|
var dt = 0.0f;
|
||||||
var accumulator = 0.0f;
|
var accumulator = 0.0f;
|
||||||
var step = 1.0f / targetUps;
|
var step = 1.0f / targetUps;
|
||||||
|
|
||||||
while (running && !window.shouldClose()) {
|
while (running && !window.shouldClose()) {
|
||||||
dt = chrono.getElapsedTime();
|
dt = chrono.getElapsedTime();
|
||||||
accumulator += dt;
|
accumulator += dt;
|
||||||
|
|
||||||
input();
|
input();
|
||||||
|
|
||||||
while (accumulator >= step) {
|
while (accumulator >= step) {
|
||||||
update(dt);
|
update(dt);
|
||||||
accumulator -= step;
|
accumulator -= step;
|
||||||
}
|
}
|
||||||
|
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void input() {
|
private void input() {
|
||||||
logic.input(window);
|
logic.input(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update(float dt) {
|
private void update(float dt) {
|
||||||
logic.update(dt);
|
logic.update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void render() {
|
private void render() {
|
||||||
window.update();
|
window.update();
|
||||||
logic.render(window);
|
logic.render(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanUp() {
|
private void cleanUp() {
|
||||||
log.info("Performing off heap garbage collection");
|
log.info("Performing off heap garbage collection");
|
||||||
garbageCollector.cleanUp();
|
garbageCollector.cleanUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/engine/GameEngine.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/engine/GameEngine.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.core.engine;
|
package com.bartlomiejpluta.base.core.engine;
|
||||||
|
|
||||||
public interface GameEngine {
|
public interface GameEngine {
|
||||||
void start();
|
void start();
|
||||||
}
|
}
|
||||||
|
|||||||
44
engine/src/main/java/com/bartlomiejpluta/base/core/error/AppException.java
Executable file → Normal file
44
engine/src/main/java/com/bartlomiejpluta/base/core/error/AppException.java
Executable file → Normal file
@@ -1,22 +1,22 @@
|
|||||||
package com.bartlomiejpluta.base.core.error;
|
package com.bartlomiejpluta.base.core.error;
|
||||||
|
|
||||||
public class AppException extends RuntimeException {
|
public class AppException extends RuntimeException {
|
||||||
public AppException() {
|
public AppException() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AppException(String message, Object... args) {
|
public AppException(String message, Object... args) {
|
||||||
super(String.format(message, args));
|
super(String.format(message, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AppException(String message, Throwable cause) {
|
public AppException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AppException(Throwable cause) {
|
public AppException(Throwable cause) {
|
||||||
super(cause);
|
super(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AppException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
public AppException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Cleanable.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Cleanable.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.core.gc;
|
package com.bartlomiejpluta.base.core.gc;
|
||||||
|
|
||||||
public interface Cleanable {
|
public interface Cleanable {
|
||||||
void cleanUp();
|
void cleanUp();
|
||||||
}
|
}
|
||||||
|
|||||||
44
engine/src/main/java/com/bartlomiejpluta/base/core/gc/DefaultOffHeapGarbageCollector.java
Executable file → Normal file
44
engine/src/main/java/com/bartlomiejpluta/base/core/gc/DefaultOffHeapGarbageCollector.java
Executable file → Normal file
@@ -1,22 +1,22 @@
|
|||||||
package com.bartlomiejpluta.base.core.gc;
|
package com.bartlomiejpluta.base.core.gc;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class DefaultOffHeapGarbageCollector implements OffHeapGarbageCollector {
|
public class DefaultOffHeapGarbageCollector implements OffHeapGarbageCollector {
|
||||||
private final List<Cleanable> cleanables;
|
private final List<Cleanable> cleanables;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
cleanables.stream()
|
cleanables.stream()
|
||||||
.peek(cleanable -> log.info("Performing {} cleaning", cleanable.getClass().getSimpleName()))
|
.peek(cleanable -> log.info("Performing {} cleaning", cleanable.getClass().getSimpleName()))
|
||||||
.forEach(Cleanable::cleanUp);
|
.forEach(Cleanable::cleanUp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Disposable.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Disposable.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.core.gc;
|
package com.bartlomiejpluta.base.core.gc;
|
||||||
|
|
||||||
public interface Disposable {
|
public interface Disposable {
|
||||||
void dispose();
|
void dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/OffHeapGarbageCollector.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/OffHeapGarbageCollector.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.core.gc;
|
package com.bartlomiejpluta.base.core.gc;
|
||||||
|
|
||||||
public interface OffHeapGarbageCollector {
|
public interface OffHeapGarbageCollector {
|
||||||
void cleanUp();
|
void cleanUp();
|
||||||
}
|
}
|
||||||
|
|||||||
166
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/material/Material.java
Executable file → Normal file
166
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/material/Material.java
Executable file → Normal file
@@ -1,83 +1,83 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.object.material;
|
package com.bartlomiejpluta.base.core.gl.object.material;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gl.object.texture.Texture;
|
import com.bartlomiejpluta.base.core.gl.object.texture.Texture;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.joml.Vector2f;
|
import org.joml.Vector2f;
|
||||||
import org.joml.Vector4f;
|
import org.joml.Vector4f;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Material {
|
public class Material {
|
||||||
private final Vector4f color = new Vector4f();
|
private final Vector4f color = new Vector4f();
|
||||||
private final Vector2f spriteSize = new Vector2f(1, 1);
|
private final Vector2f spriteSize = new Vector2f(1, 1);
|
||||||
private final Vector2f spritePosition = new Vector2f(0, 0);
|
private final Vector2f spritePosition = new Vector2f(0, 0);
|
||||||
private final Texture texture;
|
private final Texture texture;
|
||||||
|
|
||||||
private Material(Texture texture, float r, float g, float b, float alpha) {
|
private Material(Texture texture, float r, float g, float b, float alpha) {
|
||||||
this.texture = texture;
|
this.texture = texture;
|
||||||
setColor(r, g, b, alpha);
|
setColor(r, g, b, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAlpha(float alpha) {
|
public void setAlpha(float alpha) {
|
||||||
this.color.w = alpha;
|
this.color.w = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColor(Vector4f color) {
|
public void setColor(Vector4f color) {
|
||||||
this.color.x = color.x;
|
this.color.x = color.x;
|
||||||
this.color.y = color.y;
|
this.color.y = color.y;
|
||||||
this.color.z = color.z;
|
this.color.z = color.z;
|
||||||
this.color.w = color.w;
|
this.color.w = color.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColor(float r, float g, float b, float alpha) {
|
public void setColor(float r, float g, float b, float alpha) {
|
||||||
color.x = r;
|
color.x = r;
|
||||||
color.y = g;
|
color.y = g;
|
||||||
color.z = b;
|
color.z = b;
|
||||||
color.w = alpha;
|
color.w = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSpriteSize(Vector2f spriteSize) {
|
public void setSpriteSize(Vector2f spriteSize) {
|
||||||
this.spriteSize.x = spriteSize.x;
|
this.spriteSize.x = spriteSize.x;
|
||||||
this.spriteSize.y = spriteSize.y;
|
this.spriteSize.y = spriteSize.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSpriteSize(float w, float h) {
|
public void setSpriteSize(float w, float h) {
|
||||||
this.spriteSize.x = w;
|
this.spriteSize.x = w;
|
||||||
this.spriteSize.y = h;
|
this.spriteSize.y = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSpritePosition(Vector2f spritePosition) {
|
public void setSpritePosition(Vector2f spritePosition) {
|
||||||
this.spritePosition.x = spritePosition.x;
|
this.spritePosition.x = spritePosition.x;
|
||||||
this.spritePosition.y = spritePosition.y;
|
this.spritePosition.y = spritePosition.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSpritePosition(float x, float y) {
|
public void setSpritePosition(float x, float y) {
|
||||||
this.spritePosition.x = x;
|
this.spritePosition.x = x;
|
||||||
this.spritePosition.y = y;
|
this.spritePosition.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTexture() {
|
public boolean hasTexture() {
|
||||||
return texture != null;
|
return texture != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void activateTextureIfExists() {
|
public void activateTextureIfExists() {
|
||||||
if(hasTexture()) {
|
if(hasTexture()) {
|
||||||
texture.activate();
|
texture.activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Material colored(float r, float g, float b, float alpha) {
|
public static Material colored(float r, float g, float b, float alpha) {
|
||||||
return new Material(null, r, g, b, alpha);
|
return new Material(null, r, g, b, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Material textured(Texture texture) {
|
public static Material textured(Texture texture) {
|
||||||
return new Material(texture, 1, 1, 1, 1);
|
return new Material(texture, 1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Material textured(Texture texture, float r, float g, float b, float alpha) {
|
public static Material textured(Texture texture, float r, float g, float b, float alpha) {
|
||||||
return new Material(texture, r, g, b, alpha);
|
return new Material(texture, r, g, b, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Material textured(Texture texture, float alpha) {
|
public static Material textured(Texture texture, float alpha) {
|
||||||
return new Material(texture, 1, 1, 1, alpha);
|
return new Material(texture, 1, 1, 1, alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
188
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/mesh/Mesh.java
Executable file → Normal file
188
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/mesh/Mesh.java
Executable file → Normal file
@@ -1,94 +1,94 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.object.mesh;
|
package com.bartlomiejpluta.base.core.gl.object.mesh;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||||
import com.bartlomiejpluta.base.core.ui.Window;
|
import com.bartlomiejpluta.base.core.ui.Window;
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL15.*;
|
import static org.lwjgl.opengl.GL15.*;
|
||||||
import static org.lwjgl.opengl.GL20.*;
|
import static org.lwjgl.opengl.GL20.*;
|
||||||
import static org.lwjgl.opengl.GL30.*;
|
import static org.lwjgl.opengl.GL30.*;
|
||||||
|
|
||||||
public class Mesh implements Renderable, Disposable {
|
public class Mesh implements Renderable, Disposable {
|
||||||
private final int vaoId;
|
private final int vaoId;
|
||||||
private final List<Integer> vboIds = new ArrayList<>(2);
|
private final List<Integer> vboIds = new ArrayList<>(2);
|
||||||
private final int elementsCount;
|
private final int elementsCount;
|
||||||
|
|
||||||
public Mesh(float[] vertices, float[] texCoords, int[] elements) {
|
public Mesh(float[] vertices, float[] texCoords, int[] elements) {
|
||||||
try(var stack = MemoryStack.stackPush()) {
|
try(var stack = MemoryStack.stackPush()) {
|
||||||
elementsCount = elements.length;
|
elementsCount = elements.length;
|
||||||
var verticesBuffer = stack.mallocFloat(vertices.length);
|
var verticesBuffer = stack.mallocFloat(vertices.length);
|
||||||
var texCoordsBuffer = stack.mallocFloat(texCoords.length);
|
var texCoordsBuffer = stack.mallocFloat(texCoords.length);
|
||||||
var elementsBuffer = stack.mallocInt(elementsCount);
|
var elementsBuffer = stack.mallocInt(elementsCount);
|
||||||
verticesBuffer.put(vertices).flip();
|
verticesBuffer.put(vertices).flip();
|
||||||
texCoordsBuffer.put(texCoords).flip();
|
texCoordsBuffer.put(texCoords).flip();
|
||||||
elementsBuffer.put(elements).flip();
|
elementsBuffer.put(elements).flip();
|
||||||
|
|
||||||
vaoId = glGenVertexArrays();
|
vaoId = glGenVertexArrays();
|
||||||
glBindVertexArray(vaoId);
|
glBindVertexArray(vaoId);
|
||||||
|
|
||||||
int vboId = glGenBuffers();
|
int vboId = glGenBuffers();
|
||||||
vboIds.add(vboId);
|
vboIds.add(vboId);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||||
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
|
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
|
||||||
|
|
||||||
vboId = glGenBuffers();
|
vboId = glGenBuffers();
|
||||||
vboIds.add(vboId);
|
vboIds.add(vboId);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||||
glBufferData(GL_ARRAY_BUFFER, texCoordsBuffer, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, texCoordsBuffer, GL_STATIC_DRAW);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
|
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
|
||||||
|
|
||||||
vboId = glGenBuffers();
|
vboId = glGenBuffers();
|
||||||
vboIds.add(vboId);
|
vboIds.add(vboId);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementsBuffer, GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementsBuffer, GL_STATIC_DRAW);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(Window window, ShaderManager shaderManager) {
|
public void render(Window window, ShaderManager shaderManager) {
|
||||||
glBindVertexArray(vaoId);
|
glBindVertexArray(vaoId);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_INT, 0);
|
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_INT, 0);
|
||||||
glDisableVertexAttribArray(0);
|
glDisableVertexAttribArray(0);
|
||||||
glDisableVertexAttribArray(1);
|
glDisableVertexAttribArray(1);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
glDisableVertexAttribArray(0);
|
glDisableVertexAttribArray(0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
vboIds.forEach(GL15::glDeleteBuffers);
|
vboIds.forEach(GL15::glDeleteBuffers);
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
glDeleteVertexArrays(vaoId);
|
glDeleteVertexArrays(vaoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mesh quad(float width, float height, float originX, float originY) {
|
public static Mesh quad(float width, float height, float originX, float originY) {
|
||||||
var vertices = new float[] {
|
var vertices = new float[] {
|
||||||
-originX, -originY,
|
-originX, -originY,
|
||||||
-originX, height - originY,
|
-originX, height - originY,
|
||||||
width - originX, height - originY,
|
width - originX, height - originY,
|
||||||
width - originX, - originY
|
width - originX, - originY
|
||||||
};
|
};
|
||||||
|
|
||||||
var texCoords = new float[] { 0, 0, 0, 1, 1, 1, 1, 0 };
|
var texCoords = new float[] { 0, 0, 0, 1, 1, 1, 1, 0 };
|
||||||
|
|
||||||
var elements = new int[] { 0, 1, 2, 2, 3, 0 };
|
var elements = new int[] { 0, 1, 2, 2, 3, 0 };
|
||||||
|
|
||||||
return new Mesh(vertices, texCoords, elements);
|
return new Mesh(vertices, texCoords, elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
78
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/DefaultTextureManager.java
Executable file → Normal file
78
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/DefaultTextureManager.java
Executable file → Normal file
@@ -1,39 +1,39 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class DefaultTextureManager implements TextureManager {
|
public class DefaultTextureManager implements TextureManager {
|
||||||
private final ResourcesManager resourcesManager;
|
private final ResourcesManager resourcesManager;
|
||||||
private final Map<String, Texture> loadedTextures = new HashMap<>();
|
private final Map<String, Texture> loadedTextures = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Texture loadTexture(String textureFileName) {
|
public Texture loadTexture(String textureFileName) {
|
||||||
var texture = loadedTextures.get(textureFileName);
|
var texture = loadedTextures.get(textureFileName);
|
||||||
|
|
||||||
if (texture == null) {
|
if (texture == null) {
|
||||||
log.info("Loading [{}] texture to cache", textureFileName);
|
log.info("Loading [{}] texture to cache", textureFileName);
|
||||||
var buffer = resourcesManager.loadResourceAsByteBuffer(textureFileName);
|
var buffer = resourcesManager.loadResourceAsByteBuffer(textureFileName);
|
||||||
texture = new Texture(textureFileName, buffer);
|
texture = new Texture(textureFileName, buffer);
|
||||||
loadedTextures.put(textureFileName, texture);
|
loadedTextures.put(textureFileName, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
log.info("Disposing textures");
|
log.info("Disposing textures");
|
||||||
loadedTextures.forEach((name, texture) -> texture.dispose());
|
loadedTextures.forEach((name, texture) -> texture.dispose());
|
||||||
log.info("{} textures has been disposed", loadedTextures.size());
|
log.info("{} textures has been disposed", loadedTextures.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
132
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/Texture.java
Executable file → Normal file
132
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/Texture.java
Executable file → Normal file
@@ -1,66 +1,66 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.error.AppException;
|
import com.bartlomiejpluta.base.core.error.AppException;
|
||||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
|
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
|
||||||
import static org.lwjgl.opengl.GL13.glActiveTexture;
|
import static org.lwjgl.opengl.GL13.glActiveTexture;
|
||||||
import static org.lwjgl.stb.STBImage.stbi_failure_reason;
|
import static org.lwjgl.stb.STBImage.stbi_failure_reason;
|
||||||
import static org.lwjgl.stb.STBImage.stbi_load_from_memory;
|
import static org.lwjgl.stb.STBImage.stbi_load_from_memory;
|
||||||
|
|
||||||
public class Texture implements Disposable {
|
public class Texture implements Disposable {
|
||||||
private static final int DESIRED_CHANNELS = 4;
|
private static final int DESIRED_CHANNELS = 4;
|
||||||
|
|
||||||
private final int textureId;
|
private final int textureId;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final String fileName;
|
private final String fileName;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final int width;
|
private final int width;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final int height;
|
private final int height;
|
||||||
|
|
||||||
Texture(String textureFilename, ByteBuffer buffer) {
|
Texture(String textureFilename, ByteBuffer buffer) {
|
||||||
try (var stack = MemoryStack.stackPush()) {
|
try (var stack = MemoryStack.stackPush()) {
|
||||||
var widthBuffer = stack.mallocInt(1);
|
var widthBuffer = stack.mallocInt(1);
|
||||||
var heightBuffer = stack.mallocInt(1);
|
var heightBuffer = stack.mallocInt(1);
|
||||||
var channelsBuffer = stack.mallocInt(1);
|
var channelsBuffer = stack.mallocInt(1);
|
||||||
|
|
||||||
buffer = stbi_load_from_memory(buffer, widthBuffer, heightBuffer, channelsBuffer, DESIRED_CHANNELS);
|
buffer = stbi_load_from_memory(buffer, widthBuffer, heightBuffer, channelsBuffer, DESIRED_CHANNELS);
|
||||||
if (buffer == null) {
|
if (buffer == null) {
|
||||||
throw new AppException("Image file [%s] could not be loaded: %s", textureFilename, stbi_failure_reason());
|
throw new AppException("Image file [%s] could not be loaded: %s", textureFilename, stbi_failure_reason());
|
||||||
}
|
}
|
||||||
|
|
||||||
width = widthBuffer.get();
|
width = widthBuffer.get();
|
||||||
height = heightBuffer.get();
|
height = heightBuffer.get();
|
||||||
|
|
||||||
textureId = glGenTextures();
|
textureId = glGenTextures();
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
fileName = textureFilename;
|
fileName = textureFilename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void activate() {
|
public void activate() {
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
glDeleteTextures(textureId);
|
glDeleteTextures(textureId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/TextureManager.java
Executable file → Normal file
14
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/TextureManager.java
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||||
|
|
||||||
public interface TextureManager extends Cleanable {
|
public interface TextureManager extends Cleanable {
|
||||||
Texture loadTexture(String textureFileName);
|
Texture loadTexture(String textureFileName);
|
||||||
}
|
}
|
||||||
|
|||||||
124
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/DefaultRenderer.java
Executable file → Normal file
124
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/DefaultRenderer.java
Executable file → Normal file
@@ -1,62 +1,62 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.render;
|
package com.bartlomiejpluta.base.core.gl.render;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||||
import com.bartlomiejpluta.base.core.ui.Window;
|
import com.bartlomiejpluta.base.core.ui.Window;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL15.*;
|
import static org.lwjgl.opengl.GL15.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class DefaultRenderer implements Renderer {
|
public class DefaultRenderer implements Renderer {
|
||||||
private final ShaderManager shaderManager;
|
private final ShaderManager shaderManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
log.info("Initializing renderer");
|
log.info("Initializing renderer");
|
||||||
shaderManager
|
shaderManager
|
||||||
.createShader("default", "/shaders/default.vs", "/shaders/default.fs")
|
.createShader("default", "/shaders/default.vs", "/shaders/default.fs")
|
||||||
.selectShader("default")
|
.selectShader("default")
|
||||||
.createUniform(UniformName.UNI_MODEL_MATRIX)
|
.createUniform(UniformName.UNI_MODEL_MATRIX)
|
||||||
.createUniform(UniformName.UNI_VIEW_MATRIX)
|
.createUniform(UniformName.UNI_VIEW_MATRIX)
|
||||||
.createUniform(UniformName.UNI_PROJECTION_MATRIX)
|
.createUniform(UniformName.UNI_PROJECTION_MATRIX)
|
||||||
.createUniform(UniformName.UNI_OBJECT_COLOR)
|
.createUniform(UniformName.UNI_OBJECT_COLOR)
|
||||||
.createUniform(UniformName.UNI_HAS_OBJECT_TEXTURE)
|
.createUniform(UniformName.UNI_HAS_OBJECT_TEXTURE)
|
||||||
.createUniform(UniformName.UNI_TEXTURE_SAMPLER)
|
.createUniform(UniformName.UNI_TEXTURE_SAMPLER)
|
||||||
.createUniform(UniformName.UNI_SPRITE_SIZE)
|
.createUniform(UniformName.UNI_SPRITE_SIZE)
|
||||||
.createUniform(UniformName.UNI_SPRITE_POSITION);
|
.createUniform(UniformName.UNI_SPRITE_POSITION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(Window window, Renderable renderable) {
|
public void render(Window window, Renderable renderable) {
|
||||||
clear();
|
clear();
|
||||||
updateViewport(window);
|
updateViewport(window);
|
||||||
|
|
||||||
shaderManager.selectShader("default").useSelectedShader();
|
shaderManager.selectShader("default").useSelectedShader();
|
||||||
|
|
||||||
renderable.render(window, shaderManager);
|
renderable.render(window, shaderManager);
|
||||||
|
|
||||||
shaderManager.detachCurrentShader();
|
shaderManager.detachCurrentShader();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clear() {
|
private void clear() {
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateViewport(Window window) {
|
private void updateViewport(Window window) {
|
||||||
if (window.isResized()) {
|
if (window.isResized()) {
|
||||||
glViewport(0, 0, window.getWidth(), window.getHeight());
|
glViewport(0, 0, window.getWidth(), window.getHeight());
|
||||||
window.setResized(false);
|
window.setResized(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
log.info("There is nothing to clean up here");
|
log.info("There is nothing to clean up here");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderable.java
Executable file → Normal file
16
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderable.java
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.render;
|
package com.bartlomiejpluta.base.core.gl.render;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||||
import com.bartlomiejpluta.base.core.ui.Window;
|
import com.bartlomiejpluta.base.core.ui.Window;
|
||||||
|
|
||||||
public interface Renderable {
|
public interface Renderable {
|
||||||
void render(Window window, ShaderManager shaderManager);
|
void render(Window window, ShaderManager shaderManager);
|
||||||
}
|
}
|
||||||
|
|||||||
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderer.java
Executable file → Normal file
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderer.java
Executable file → Normal file
@@ -1,9 +1,9 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.render;
|
package com.bartlomiejpluta.base.core.gl.render;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||||
import com.bartlomiejpluta.base.core.ui.Window;
|
import com.bartlomiejpluta.base.core.ui.Window;
|
||||||
|
|
||||||
public interface Renderer extends Cleanable {
|
public interface Renderer extends Cleanable {
|
||||||
void init();
|
void init();
|
||||||
void render(Window window, Renderable renderable);
|
void render(Window window, Renderable renderable);
|
||||||
}
|
}
|
||||||
|
|||||||
24
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/constant/UniformName.java
Executable file → Normal file
24
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/constant/UniformName.java
Executable file → Normal file
@@ -1,12 +1,12 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.shader.constant;
|
package com.bartlomiejpluta.base.core.gl.shader.constant;
|
||||||
|
|
||||||
public interface UniformName {
|
public interface UniformName {
|
||||||
String UNI_MODEL_MATRIX = "modelMatrix";
|
String UNI_MODEL_MATRIX = "modelMatrix";
|
||||||
String UNI_VIEW_MATRIX = "viewMatrix";
|
String UNI_VIEW_MATRIX = "viewMatrix";
|
||||||
String UNI_PROJECTION_MATRIX = "projectionMatrix";
|
String UNI_PROJECTION_MATRIX = "projectionMatrix";
|
||||||
String UNI_OBJECT_COLOR = "objectColor";
|
String UNI_OBJECT_COLOR = "objectColor";
|
||||||
String UNI_HAS_OBJECT_TEXTURE = "hasTexture";
|
String UNI_HAS_OBJECT_TEXTURE = "hasTexture";
|
||||||
String UNI_TEXTURE_SAMPLER = "sampler";
|
String UNI_TEXTURE_SAMPLER = "sampler";
|
||||||
String UNI_SPRITE_SIZE = "spriteSize";
|
String UNI_SPRITE_SIZE = "spriteSize";
|
||||||
String UNI_SPRITE_POSITION = "spritePosition";
|
String UNI_SPRITE_POSITION = "spritePosition";
|
||||||
}
|
}
|
||||||
|
|||||||
298
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/DefaultShaderManager.java
Executable file → Normal file
298
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/DefaultShaderManager.java
Executable file → Normal file
@@ -1,149 +1,149 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||||
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.joml.*;
|
import org.joml.*;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class DefaultShaderManager implements ShaderManager {
|
public class DefaultShaderManager implements ShaderManager {
|
||||||
private final ResourcesManager resourcesManager;
|
private final ResourcesManager resourcesManager;
|
||||||
private final Map<String, ShaderProgram> shaders = new HashMap<>();
|
private final Map<String, ShaderProgram> shaders = new HashMap<>();
|
||||||
private ShaderProgram current;
|
private ShaderProgram current;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename) {
|
public ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename) {
|
||||||
log.info("Creating {} shader", programName);
|
log.info("Creating {} shader", programName);
|
||||||
var vertexShaderCode = resourcesManager.loadResourceAsString(vertexShaderFilename);
|
var vertexShaderCode = resourcesManager.loadResourceAsString(vertexShaderFilename);
|
||||||
var fragmentShaderCode = resourcesManager.loadResourceAsString(fragmentShaderFilename);
|
var fragmentShaderCode = resourcesManager.loadResourceAsString(fragmentShaderFilename);
|
||||||
var program = ShaderProgram.compile(vertexShaderCode, fragmentShaderCode);
|
var program = ShaderProgram.compile(vertexShaderCode, fragmentShaderCode);
|
||||||
|
|
||||||
shaders.put(programName, program);
|
shaders.put(programName, program);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager selectShader(String programName) {
|
public ShaderManager selectShader(String programName) {
|
||||||
current = shaders.get(programName);
|
current = shaders.get(programName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager useSelectedShader() {
|
public ShaderManager useSelectedShader() {
|
||||||
current.use();
|
current.use();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager detachCurrentShader() {
|
public ShaderManager detachCurrentShader() {
|
||||||
current.detach();
|
current.detach();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager createUniform(String uniformName) {
|
public ShaderManager createUniform(String uniformName) {
|
||||||
current.createUniform(uniformName);
|
current.createUniform(uniformName);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager createUniform(String uniformName, Uniform uniform) {
|
public ShaderManager createUniform(String uniformName, Uniform uniform) {
|
||||||
current.createUniform(uniformName, uniform);
|
current.createUniform(uniformName, uniform);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager createUniforms(String uniformName, int size) {
|
public ShaderManager createUniforms(String uniformName, int size) {
|
||||||
current.createUniforms(uniformName, size);
|
current.createUniforms(uniformName, size);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager createUniforms(String uniformName, int size, Uniform uniform) {
|
public ShaderManager createUniforms(String uniformName, int size, Uniform uniform) {
|
||||||
current.createUniforms(uniformName, size, uniform);
|
current.createUniforms(uniformName, size, uniform);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, int value) {
|
public ShaderManager setUniform(String uniformName, int value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, boolean value) {
|
public ShaderManager setUniform(String uniformName, boolean value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, float value) {
|
public ShaderManager setUniform(String uniformName, float value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, Vector2f value) {
|
public ShaderManager setUniform(String uniformName, Vector2f value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, Vector3f value) {
|
public ShaderManager setUniform(String uniformName, Vector3f value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, Vector4f value) {
|
public ShaderManager setUniform(String uniformName, Vector4f value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, Matrix3f value) {
|
public ShaderManager setUniform(String uniformName, Matrix3f value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, Matrix4f value) {
|
public ShaderManager setUniform(String uniformName, Matrix4f value) {
|
||||||
current.setUniform(uniformName, value);
|
current.setUniform(uniformName, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, Uniform uniform) {
|
public ShaderManager setUniform(String uniformName, Uniform uniform) {
|
||||||
current.setUniform(uniformName, uniform);
|
current.setUniform(uniformName, uniform);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniform(String uniformName, int index, Uniform uniform) {
|
public ShaderManager setUniform(String uniformName, int index, Uniform uniform) {
|
||||||
current.setUniform(uniformName, index, uniform);
|
current.setUniform(uniformName, index, uniform);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShaderManager setUniforms(String uniformName, Uniform[] uniforms) {
|
public ShaderManager setUniforms(String uniformName, Uniform[] uniforms) {
|
||||||
current.setUniforms(uniformName, uniforms);
|
current.setUniforms(uniformName, uniforms);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
log.info("Disposing shaders");
|
log.info("Disposing shaders");
|
||||||
shaders.forEach((name, program) -> program.dispose());
|
shaders.forEach((name, program) -> program.dispose());
|
||||||
log.info("{} shaders has been disposed", shaders.size());
|
log.info("{} shaders has been disposed", shaders.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/ShaderManager.java
Executable file → Normal file
88
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/ShaderManager.java
Executable file → Normal file
@@ -1,45 +1,45 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||||
import org.joml.*;
|
import org.joml.*;
|
||||||
|
|
||||||
public interface ShaderManager extends Cleanable {
|
public interface ShaderManager extends Cleanable {
|
||||||
ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename);
|
ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename);
|
||||||
|
|
||||||
ShaderManager selectShader(String programName);
|
ShaderManager selectShader(String programName);
|
||||||
|
|
||||||
ShaderManager useSelectedShader();
|
ShaderManager useSelectedShader();
|
||||||
|
|
||||||
ShaderManager detachCurrentShader();
|
ShaderManager detachCurrentShader();
|
||||||
|
|
||||||
ShaderManager createUniform(String uniformName);
|
ShaderManager createUniform(String uniformName);
|
||||||
|
|
||||||
ShaderManager createUniform(String uniformName, Uniform uniform);
|
ShaderManager createUniform(String uniformName, Uniform uniform);
|
||||||
|
|
||||||
ShaderManager createUniforms(String uniformName, int size);
|
ShaderManager createUniforms(String uniformName, int size);
|
||||||
|
|
||||||
ShaderManager createUniforms(String uniformName, int size, Uniform uniform);
|
ShaderManager createUniforms(String uniformName, int size, Uniform uniform);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, int value);
|
ShaderManager setUniform(String uniformName, int value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, boolean value);
|
ShaderManager setUniform(String uniformName, boolean value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, float value);
|
ShaderManager setUniform(String uniformName, float value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, Vector2f value);
|
ShaderManager setUniform(String uniformName, Vector2f value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, Vector3f value);
|
ShaderManager setUniform(String uniformName, Vector3f value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, Vector4f value);
|
ShaderManager setUniform(String uniformName, Vector4f value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, Matrix3f value);
|
ShaderManager setUniform(String uniformName, Matrix3f value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, Matrix4f value);
|
ShaderManager setUniform(String uniformName, Matrix4f value);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, Uniform uniform);
|
ShaderManager setUniform(String uniformName, Uniform uniform);
|
||||||
|
|
||||||
ShaderManager setUniform(String uniformName, int index, Uniform uniform);
|
ShaderManager setUniform(String uniformName, int index, Uniform uniform);
|
||||||
|
|
||||||
ShaderManager setUniforms(String uniformName, Uniform[] uniforms);
|
ShaderManager setUniforms(String uniformName, Uniform[] uniforms);
|
||||||
}
|
}
|
||||||
350
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/program/ShaderProgram.java
Executable file → Normal file
350
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/program/ShaderProgram.java
Executable file → Normal file
@@ -1,175 +1,175 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.shader.program;
|
package com.bartlomiejpluta.base.core.gl.shader.program;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.error.AppException;
|
import com.bartlomiejpluta.base.core.error.AppException;
|
||||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.joml.*;
|
import org.joml.*;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static org.lwjgl.opengl.GL20.*;
|
import static org.lwjgl.opengl.GL20.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ShaderProgram implements Disposable {
|
public class ShaderProgram implements Disposable {
|
||||||
private final int programId;
|
private final int programId;
|
||||||
private final int vertexShaderId;
|
private final int vertexShaderId;
|
||||||
private final int fragmentShaderId;
|
private final int fragmentShaderId;
|
||||||
private final Map<String, Integer> uniforms = new HashMap<>();
|
private final Map<String, Integer> uniforms = new HashMap<>();
|
||||||
|
|
||||||
private ShaderProgram(String vertexShaderCode, String fragmentShaderCode) {
|
private ShaderProgram(String vertexShaderCode, String fragmentShaderCode) {
|
||||||
this.programId = glCreateProgram();
|
this.programId = glCreateProgram();
|
||||||
|
|
||||||
if(this.programId == 0) {
|
if(this.programId == 0) {
|
||||||
throw new AppException("Could not create shader program");
|
throw new AppException("Could not create shader program");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.vertexShaderId = createShader(vertexShaderCode, GL_VERTEX_SHADER);
|
this.vertexShaderId = createShader(vertexShaderCode, GL_VERTEX_SHADER);
|
||||||
this.fragmentShaderId = createShader(fragmentShaderCode, GL_FRAGMENT_SHADER);
|
this.fragmentShaderId = createShader(fragmentShaderCode, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
linkProgram();
|
linkProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int createShader(String shaderCode, int shaderType) {
|
private int createShader(String shaderCode, int shaderType) {
|
||||||
int shaderId = glCreateShader(shaderType);
|
int shaderId = glCreateShader(shaderType);
|
||||||
if(shaderId == 0) {
|
if(shaderId == 0) {
|
||||||
throw new AppException("Could not create shader of type: %s", shaderType);
|
throw new AppException("Could not create shader of type: %s", shaderType);
|
||||||
}
|
}
|
||||||
|
|
||||||
glShaderSource(shaderId, shaderCode);
|
glShaderSource(shaderId, shaderCode);
|
||||||
glCompileShader(shaderId);
|
glCompileShader(shaderId);
|
||||||
|
|
||||||
if(glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
|
if(glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
|
||||||
throw new AppException("Could not compile shader code: %s", glGetShaderInfoLog(shaderId, 1024));
|
throw new AppException("Could not compile shader code: %s", glGetShaderInfoLog(shaderId, 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
glAttachShader(programId, shaderId);
|
glAttachShader(programId, shaderId);
|
||||||
|
|
||||||
return shaderId;
|
return shaderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void linkProgram() {
|
private void linkProgram() {
|
||||||
glLinkProgram(programId);
|
glLinkProgram(programId);
|
||||||
if(glGetProgrami(programId, GL_LINK_STATUS) == 0) {
|
if(glGetProgrami(programId, GL_LINK_STATUS) == 0) {
|
||||||
throw new AppException("Could not link shader program: %s", glGetProgramInfoLog(programId, 1024));
|
throw new AppException("Could not link shader program: %s", glGetProgramInfoLog(programId, 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vertexShaderId != 0) {
|
if(vertexShaderId != 0) {
|
||||||
glDetachShader(programId, vertexShaderId);
|
glDetachShader(programId, vertexShaderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fragmentShaderId != 0) {
|
if(fragmentShaderId != 0) {
|
||||||
glDetachShader(programId, fragmentShaderId);
|
glDetachShader(programId, fragmentShaderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
glValidateProgram(programId);
|
glValidateProgram(programId);
|
||||||
if(glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
|
if(glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
|
||||||
log.warn("Program validation failed: {}", glGetProgramInfoLog(programId, 1024));
|
log.warn("Program validation failed: {}", glGetProgramInfoLog(programId, 1024));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createUniform(String uniformName) {
|
public void createUniform(String uniformName) {
|
||||||
int location = glGetUniformLocation(programId, uniformName);
|
int location = glGetUniformLocation(programId, uniformName);
|
||||||
|
|
||||||
if(location < 0) {
|
if(location < 0) {
|
||||||
throw new AppException("Could not find uniform: %s", uniformName);
|
throw new AppException("Could not find uniform: %s", uniformName);
|
||||||
}
|
}
|
||||||
|
|
||||||
uniforms.put(uniformName, location);
|
uniforms.put(uniformName, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createUniform(String uniformName, Uniform uniform) {
|
public void createUniform(String uniformName, Uniform uniform) {
|
||||||
uniform.createUniform(this, uniformName);
|
uniform.createUniform(this, uniformName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createUniforms(String uniformName, int size) {
|
public void createUniforms(String uniformName, int size) {
|
||||||
for(int i=0; i<size; ++i) {
|
for(int i=0; i<size; ++i) {
|
||||||
createUniform(format("%s[%d]", uniformName, i));
|
createUniform(format("%s[%d]", uniformName, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createUniforms(String uniformName, int size, Uniform uniform) {
|
public void createUniforms(String uniformName, int size, Uniform uniform) {
|
||||||
for(int i=0; i<size; ++i) {
|
for(int i=0; i<size; ++i) {
|
||||||
createUniform(format("%s[%d]", uniformName, i), uniform);
|
createUniform(format("%s[%d]", uniformName, i), uniform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, int value) {
|
public void setUniform(String uniformName, int value) {
|
||||||
glUniform1i(uniforms.get(uniformName), value);
|
glUniform1i(uniforms.get(uniformName), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, boolean value) {
|
public void setUniform(String uniformName, boolean value) {
|
||||||
glUniform1i(uniforms.get(uniformName), value ? 1 : 0);
|
glUniform1i(uniforms.get(uniformName), value ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, float value) {
|
public void setUniform(String uniformName, float value) {
|
||||||
glUniform1f(uniforms.get(uniformName), value);
|
glUniform1f(uniforms.get(uniformName), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, Vector2f value) {
|
public void setUniform(String uniformName, Vector2f value) {
|
||||||
glUniform2f(uniforms.get(uniformName), value.x, value.y);
|
glUniform2f(uniforms.get(uniformName), value.x, value.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, Vector3f value) {
|
public void setUniform(String uniformName, Vector3f value) {
|
||||||
glUniform3f(uniforms.get(uniformName), value.x, value.y, value.z);
|
glUniform3f(uniforms.get(uniformName), value.x, value.y, value.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, Vector4f value) {
|
public void setUniform(String uniformName, Vector4f value) {
|
||||||
glUniform4f(uniforms.get(uniformName), value.x, value.y, value.z, value.w);
|
glUniform4f(uniforms.get(uniformName), value.x, value.y, value.z, value.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, Matrix3f value) {
|
public void setUniform(String uniformName, Matrix3f value) {
|
||||||
try(var stack = MemoryStack.stackPush()) {
|
try(var stack = MemoryStack.stackPush()) {
|
||||||
var buffer = stack.mallocFloat(3 * 3);
|
var buffer = stack.mallocFloat(3 * 3);
|
||||||
value.get(buffer);
|
value.get(buffer);
|
||||||
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, Matrix4f value) {
|
public void setUniform(String uniformName, Matrix4f value) {
|
||||||
try(var stack = MemoryStack.stackPush()) {
|
try(var stack = MemoryStack.stackPush()) {
|
||||||
var buffer = stack.mallocFloat(4 * 4);
|
var buffer = stack.mallocFloat(4 * 4);
|
||||||
value.get(buffer);
|
value.get(buffer);
|
||||||
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, Uniform uniform) {
|
public void setUniform(String uniformName, Uniform uniform) {
|
||||||
uniform.setUniform(this, uniformName);
|
uniform.setUniform(this, uniformName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniform(String uniformName, int index, Uniform uniform) {
|
public void setUniform(String uniformName, int index, Uniform uniform) {
|
||||||
setUniform(format("%s[%d]", uniformName, index), uniform);
|
setUniform(format("%s[%d]", uniformName, index), uniform);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniforms(String uniformName, Uniform[] uniforms) {
|
public void setUniforms(String uniformName, Uniform[] uniforms) {
|
||||||
var size = uniforms != null ? uniforms.length : 0;
|
var size = uniforms != null ? uniforms.length : 0;
|
||||||
for(int i=0; i<size; ++i) {
|
for(int i=0; i<size; ++i) {
|
||||||
setUniform(format("%s[%d]", uniformName, i), uniforms[i]);
|
setUniform(format("%s[%d]", uniformName, i), uniforms[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void use() {
|
public void use() {
|
||||||
glUseProgram(programId);
|
glUseProgram(programId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void detach() {
|
public void detach() {
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
|
||||||
if(programId != 0) {
|
if(programId != 0) {
|
||||||
glDeleteProgram(programId);
|
glDeleteProgram(programId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderProgram compile(String vertexShaderCode, String fragmentShaderCode) {
|
public static ShaderProgram compile(String vertexShaderCode, String fragmentShaderCode) {
|
||||||
return new ShaderProgram(vertexShaderCode, fragmentShaderCode);
|
return new ShaderProgram(vertexShaderCode, fragmentShaderCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/uniform/Uniform.java
Executable file → Normal file
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/uniform/Uniform.java
Executable file → Normal file
@@ -1,9 +1,9 @@
|
|||||||
package com.bartlomiejpluta.base.core.gl.shader.uniform;
|
package com.bartlomiejpluta.base.core.gl.shader.uniform;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
||||||
|
|
||||||
public interface Uniform {
|
public interface Uniform {
|
||||||
void createUniform(ShaderProgram shaderProgram, String uniformName);
|
void createUniform(ShaderProgram shaderProgram, String uniformName);
|
||||||
|
|
||||||
void setUniform(ShaderProgram shaderProgram, String uniformName);
|
void setUniform(ShaderProgram shaderProgram, String uniformName);
|
||||||
}
|
}
|
||||||
|
|||||||
78
engine/src/main/java/com/bartlomiejpluta/base/core/image/DefaultImageManager.java
Executable file → Normal file
78
engine/src/main/java/com/bartlomiejpluta/base/core/image/DefaultImageManager.java
Executable file → Normal file
@@ -1,39 +1,39 @@
|
|||||||
package com.bartlomiejpluta.base.core.image;
|
package com.bartlomiejpluta.base.core.image;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||||
import com.bartlomiejpluta.base.core.gl.object.texture.TextureManager;
|
import com.bartlomiejpluta.base.core.gl.object.texture.TextureManager;
|
||||||
import com.bartlomiejpluta.base.core.util.math.MathUtil;
|
import com.bartlomiejpluta.base.core.util.math.MathUtil;
|
||||||
import com.bartlomiejpluta.base.core.util.mesh.MeshManager;
|
import com.bartlomiejpluta.base.core.util.mesh.MeshManager;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class DefaultImageManager implements ImageManager {
|
public class DefaultImageManager implements ImageManager {
|
||||||
private final MeshManager meshManager;
|
private final MeshManager meshManager;
|
||||||
private final TextureManager textureManager;
|
private final TextureManager textureManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Image createImage(String imageFileName) {
|
public Image createImage(String imageFileName) {
|
||||||
var texture = textureManager.loadTexture(imageFileName);
|
var texture = textureManager.loadTexture(imageFileName);
|
||||||
var width = texture.getWidth();
|
var width = texture.getWidth();
|
||||||
var height = texture.getHeight();
|
var height = texture.getHeight();
|
||||||
var gcd = MathUtil.gcdEuclidean(width, height);
|
var gcd = MathUtil.gcdEuclidean(width, height);
|
||||||
var initialWidth = width / gcd;
|
var initialWidth = width / gcd;
|
||||||
var initialHeight = height / gcd;
|
var initialHeight = height / gcd;
|
||||||
var mesh = meshManager.createQuad(initialWidth, initialHeight, 0, 0);
|
var mesh = meshManager.createQuad(initialWidth, initialHeight, 0, 0);
|
||||||
|
|
||||||
var image = new Image(mesh, Material.textured(texture), initialWidth, initialHeight);
|
var image = new Image(mesh, Material.textured(texture), initialWidth, initialHeight);
|
||||||
image.setScale(gcd);
|
image.setScale(gcd);
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
log.info("There is nothing to clean up here");
|
log.info("There is nothing to clean up here");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
engine/src/main/java/com/bartlomiejpluta/base/core/image/Image.java
Executable file → Normal file
38
engine/src/main/java/com/bartlomiejpluta/base/core/image/Image.java
Executable file → Normal file
@@ -1,19 +1,19 @@
|
|||||||
package com.bartlomiejpluta.base.core.image;
|
package com.bartlomiejpluta.base.core.image;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||||
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Image extends RenderableObject {
|
public class Image extends RenderableObject {
|
||||||
private final int initialWidth;
|
private final int initialWidth;
|
||||||
private final int initialHeight;
|
private final int initialHeight;
|
||||||
|
|
||||||
Image(Mesh mesh, Material texture, int initialWidth, int initialHeight) {
|
Image(Mesh mesh, Material texture, int initialWidth, int initialHeight) {
|
||||||
super(mesh);
|
super(mesh);
|
||||||
this.initialWidth = initialWidth;
|
this.initialWidth = initialWidth;
|
||||||
this.initialHeight = initialHeight;
|
this.initialHeight = initialHeight;
|
||||||
setMaterial(texture);
|
setMaterial(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
0
engine/src/main/java/com/bartlomiejpluta/base/core/image/ImageManager.java
Executable file → Normal file
0
engine/src/main/java/com/bartlomiejpluta/base/core/image/ImageManager.java
Executable file → Normal file
28
engine/src/main/java/com/bartlomiejpluta/base/core/logic/GameLogic.java
Executable file → Normal file
28
engine/src/main/java/com/bartlomiejpluta/base/core/logic/GameLogic.java
Executable file → Normal file
@@ -1,14 +1,14 @@
|
|||||||
package com.bartlomiejpluta.base.core.logic;
|
package com.bartlomiejpluta.base.core.logic;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||||
import com.bartlomiejpluta.base.core.ui.Window;
|
import com.bartlomiejpluta.base.core.ui.Window;
|
||||||
|
|
||||||
public interface GameLogic extends Cleanable {
|
public interface GameLogic extends Cleanable {
|
||||||
void init(Window window);
|
void init(Window window);
|
||||||
|
|
||||||
void input(Window window);
|
void input(Window window);
|
||||||
|
|
||||||
void update(float dt);
|
void update(float dt);
|
||||||
|
|
||||||
void render(Window window);
|
void render(Window window);
|
||||||
}
|
}
|
||||||
|
|||||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/logic/Updatable.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/logic/Updatable.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
package com.bartlomiejpluta.base.core.logic;
|
package com.bartlomiejpluta.base.core.logic;
|
||||||
|
|
||||||
public interface Updatable {
|
public interface Updatable {
|
||||||
void update(float dt);
|
void update(float dt);
|
||||||
}
|
}
|
||||||
|
|||||||
14
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/FPSMonitor.java
Executable file → Normal file
14
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/FPSMonitor.java
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
package com.bartlomiejpluta.base.core.profiling.fps;
|
package com.bartlomiejpluta.base.core.profiling.fps;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||||
|
|
||||||
public interface FPSMonitor extends Updatable, Cleanable {
|
public interface FPSMonitor extends Updatable, Cleanable {
|
||||||
}
|
}
|
||||||
|
|||||||
126
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/LogFPSMonitor.java
Executable file → Normal file
126
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/LogFPSMonitor.java
Executable file → Normal file
@@ -1,63 +1,63 @@
|
|||||||
package com.bartlomiejpluta.base.core.profiling.fps;
|
package com.bartlomiejpluta.base.core.profiling.fps;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static java.util.Comparator.comparingInt;
|
import static java.util.Comparator.comparingInt;
|
||||||
import static java.util.function.Function.identity;
|
import static java.util.function.Function.identity;
|
||||||
import static java.util.stream.Collectors.counting;
|
import static java.util.stream.Collectors.counting;
|
||||||
import static java.util.stream.Collectors.groupingBy;
|
import static java.util.stream.Collectors.groupingBy;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class LogFPSMonitor implements FPSMonitor {
|
public class LogFPSMonitor implements FPSMonitor {
|
||||||
private static final int MOD = 30;
|
private static final int MOD = 30;
|
||||||
private final List<Double> values = new LinkedList<>();
|
private final List<Double> values = new LinkedList<>();
|
||||||
private float fpsAccumulator = 0;
|
private float fpsAccumulator = 0;
|
||||||
private int pointer = 0;
|
private int pointer = 0;
|
||||||
private double fps = 0;
|
private double fps = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(float dt) {
|
public void update(float dt) {
|
||||||
fpsAccumulator += dt;
|
fpsAccumulator += dt;
|
||||||
|
|
||||||
if (++pointer % MOD == 0) {
|
if (++pointer % MOD == 0) {
|
||||||
fps = pointer / fpsAccumulator;
|
fps = pointer / fpsAccumulator;
|
||||||
fpsAccumulator = 0;
|
fpsAccumulator = 0;
|
||||||
pointer = 0;
|
pointer = 0;
|
||||||
|
|
||||||
values.add(fps);
|
values.add(fps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
log.info("Min FPS: {}, max FPS: {}, avg FPS: {}",
|
log.info("Min FPS: {}, max FPS: {}, avg FPS: {}",
|
||||||
values.stream().min(Double::compareTo).orElse(-1.0),
|
values.stream().min(Double::compareTo).orElse(-1.0),
|
||||||
values.stream().max(Double::compareTo).orElse(-1.0),
|
values.stream().max(Double::compareTo).orElse(-1.0),
|
||||||
totalAverage()
|
totalAverage()
|
||||||
);
|
);
|
||||||
|
|
||||||
printHistogram();
|
printHistogram();
|
||||||
}
|
}
|
||||||
|
|
||||||
private double totalAverage() {
|
private double totalAverage() {
|
||||||
return values.stream().reduce(0.0, Double::sum) / values.size();
|
return values.stream().reduce(0.0, Double::sum) / values.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printHistogram() {
|
private void printHistogram() {
|
||||||
values
|
values
|
||||||
.stream()
|
.stream()
|
||||||
.mapToInt(Double::intValue)
|
.mapToInt(Double::intValue)
|
||||||
.boxed()
|
.boxed()
|
||||||
.collect(groupingBy(identity(), counting()))
|
.collect(groupingBy(identity(), counting()))
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.sorted(comparingInt(Map.Entry::getKey))
|
.sorted(comparingInt(Map.Entry::getKey))
|
||||||
.forEach(e -> log.info("{} FPS: {}% ({} occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue()));
|
.forEach(e -> log.info("{} FPS: {}% ({} occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/annotation/MeasureExecutionTime.java
Executable file → Normal file
22
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/annotation/MeasureExecutionTime.java
Executable file → Normal file
@@ -1,11 +1,11 @@
|
|||||||
package com.bartlomiejpluta.base.core.profiling.time.annotation;
|
package com.bartlomiejpluta.base.core.profiling.time.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface MeasureExecutionTime {
|
public @interface MeasureExecutionTime {
|
||||||
}
|
}
|
||||||
|
|||||||
76
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/aspect/ExecutionTimeAspect.java
Executable file → Normal file
76
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/aspect/ExecutionTimeAspect.java
Executable file → Normal file
@@ -1,38 +1,38 @@
|
|||||||
package com.bartlomiejpluta.base.core.profiling.time.aspect;
|
package com.bartlomiejpluta.base.core.profiling.time.aspect;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Aspect
|
@Aspect
|
||||||
@Component
|
@Component
|
||||||
@ConditionalOnExpression("${app.profiling.aspects:false}")
|
@ConditionalOnExpression("${app.profiling.aspects:false}")
|
||||||
public class ExecutionTimeAspect {
|
public class ExecutionTimeAspect {
|
||||||
|
|
||||||
@Around("@annotation(com.bartlomiejpluta.base.core.stat.metrics.annotation.MeasureExecutionTime)")
|
@Around("@annotation(com.bartlomiejpluta.base.core.stat.metrics.annotation.MeasureExecutionTime)")
|
||||||
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
|
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
long start = 0;
|
long start = 0;
|
||||||
long end = 0;
|
long end = 0;
|
||||||
long elapsed;
|
long elapsed;
|
||||||
Object result;
|
Object result;
|
||||||
try {
|
try {
|
||||||
start = System.nanoTime();
|
start = System.nanoTime();
|
||||||
result = joinPoint.proceed();
|
result = joinPoint.proceed();
|
||||||
} finally {
|
} finally {
|
||||||
end = System.nanoTime();
|
end = System.nanoTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
elapsed = end - start;
|
elapsed = end - start;
|
||||||
log.debug("[{}.{}] = [{}s] [{}ms] [{}ns]",
|
log.debug("[{}.{}] = [{}s] [{}ms] [{}ns]",
|
||||||
joinPoint.getTarget().getClass().getSimpleName(),
|
joinPoint.getTarget().getClass().getSimpleName(),
|
||||||
joinPoint.getSignature().getName(),
|
joinPoint.getSignature().getName(),
|
||||||
elapsed / 1000000.0, elapsed / 1000.0, elapsed
|
elapsed / 1000000.0, elapsed / 1000.0, elapsed
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
engine/src/main/java/com/bartlomiejpluta/base/core/thread/ThreadManager.java
Executable file → Normal file
20
engine/src/main/java/com/bartlomiejpluta/base/core/thread/ThreadManager.java
Executable file → Normal file
@@ -1,10 +1,10 @@
|
|||||||
package com.bartlomiejpluta.base.core.thread;
|
package com.bartlomiejpluta.base.core.thread;
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class ThreadManager {
|
public class ThreadManager {
|
||||||
public Thread createThread(String name, Runnable runnable) {
|
public Thread createThread(String name, Runnable runnable) {
|
||||||
return new Thread(runnable, name);
|
return new Thread(runnable, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
engine/src/main/java/com/bartlomiejpluta/base/core/time/ChronoMeter.java
Executable file → Normal file
40
engine/src/main/java/com/bartlomiejpluta/base/core/time/ChronoMeter.java
Executable file → Normal file
@@ -1,20 +1,20 @@
|
|||||||
package com.bartlomiejpluta.base.core.time;
|
package com.bartlomiejpluta.base.core.time;
|
||||||
|
|
||||||
public class ChronoMeter {
|
public class ChronoMeter {
|
||||||
private double latchedTime;
|
private double latchedTime;
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
latchedTime = getTime();
|
latchedTime = getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getTime() {
|
private double getTime() {
|
||||||
return System.nanoTime() / 1_000_000_000.0;
|
return System.nanoTime() / 1_000_000_000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getElapsedTime() {
|
public float getElapsedTime() {
|
||||||
double time = getTime();
|
double time = getTime();
|
||||||
float elapsedTime = (float) (time - latchedTime);
|
float elapsedTime = (float) (time - latchedTime);
|
||||||
latchedTime = time;
|
latchedTime = time;
|
||||||
return elapsedTime;
|
return elapsedTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
238
engine/src/main/java/com/bartlomiejpluta/base/core/ui/Window.java
Executable file → Normal file
238
engine/src/main/java/com/bartlomiejpluta/base/core/ui/Window.java
Executable file → Normal file
@@ -1,119 +1,119 @@
|
|||||||
package com.bartlomiejpluta.base.core.ui;
|
package com.bartlomiejpluta.base.core.ui;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.core.error.AppException;
|
import com.bartlomiejpluta.base.core.error.AppException;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.joml.Vector2f;
|
import org.joml.Vector2f;
|
||||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||||
import org.lwjgl.glfw.GLFWVidMode;
|
import org.lwjgl.glfw.GLFWVidMode;
|
||||||
import org.lwjgl.opengl.GL;
|
import org.lwjgl.opengl.GL;
|
||||||
|
|
||||||
import static org.lwjgl.glfw.GLFW.*;
|
import static org.lwjgl.glfw.GLFW.*;
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||||
|
|
||||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class Window {
|
public class Window {
|
||||||
private final String title;
|
private final String title;
|
||||||
private long windowHandle;
|
private long windowHandle;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private int width;
|
private int width;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private int height;
|
private int height;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private boolean resized;
|
private boolean resized;
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
// Setup an error callback. The default implementation
|
// Setup an error callback. The default implementation
|
||||||
// will print the error message in System.err.
|
// will print the error message in System.err.
|
||||||
GLFWErrorCallback.createPrint(System.err).set();
|
GLFWErrorCallback.createPrint(System.err).set();
|
||||||
|
|
||||||
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
||||||
if (!glfwInit()) {
|
if (!glfwInit()) {
|
||||||
throw new AppException("Unable to initialize GLFW");
|
throw new AppException("Unable to initialize GLFW");
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
||||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
|
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
|
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||||
|
|
||||||
// Create the window
|
// Create the window
|
||||||
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
|
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||||
if (windowHandle == NULL) {
|
if (windowHandle == NULL) {
|
||||||
throw new AppException("Failed to create the GLFW window");
|
throw new AppException("Failed to create the GLFW window");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup resize callback
|
// Setup resize callback
|
||||||
glfwSetFramebufferSizeCallback(windowHandle, (window, width, height) -> {
|
glfwSetFramebufferSizeCallback(windowHandle, (window, width, height) -> {
|
||||||
Window.this.width = width;
|
Window.this.width = width;
|
||||||
Window.this.height = height;
|
Window.this.height = height;
|
||||||
Window.this.resized = true;
|
Window.this.resized = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
|
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
|
||||||
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
|
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
|
||||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
|
||||||
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
|
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get the resolution of the primary monitor
|
// Get the resolution of the primary monitor
|
||||||
GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||||
|
|
||||||
// Center our window
|
// Center our window
|
||||||
glfwSetWindowPos(windowHandle, (videoMode.width() - width) / 2, (videoMode.height() - height) / 2);
|
glfwSetWindowPos(windowHandle, (videoMode.width() - width) / 2, (videoMode.height() - height) / 2);
|
||||||
|
|
||||||
// Make the OpenGL context current
|
// Make the OpenGL context current
|
||||||
glfwMakeContextCurrent(windowHandle);
|
glfwMakeContextCurrent(windowHandle);
|
||||||
|
|
||||||
// Enable V-Sync
|
// Enable V-Sync
|
||||||
// glfwSwapInterval(1);
|
// glfwSwapInterval(1);
|
||||||
|
|
||||||
// Make the window visible
|
// Make the window visible
|
||||||
glfwShowWindow(windowHandle);
|
glfwShowWindow(windowHandle);
|
||||||
|
|
||||||
GL.createCapabilities();
|
GL.createCapabilities();
|
||||||
|
|
||||||
// Support for transparencies
|
// Support for transparencies
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
// Set the clear color
|
// Set the clear color
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
glfwSwapBuffers(windowHandle);
|
glfwSwapBuffers(windowHandle);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isKeyPressed(int keyCode) {
|
public boolean isKeyPressed(int keyCode) {
|
||||||
return glfwGetKey(windowHandle, keyCode) == GLFW_PRESS;
|
return glfwGetKey(windowHandle, keyCode) == GLFW_PRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear(float r, float g, float b, float alpha) {
|
public void clear(float r, float g, float b, float alpha) {
|
||||||
glClearColor(r, g, b, alpha);
|
glClearColor(r, g, b, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldClose() {
|
public boolean shouldClose() {
|
||||||
return glfwWindowShouldClose(windowHandle);
|
return glfwWindowShouldClose(windowHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2f getSize() {
|
public Vector2f getSize() {
|
||||||
return new Vector2f(width, height);
|
return new Vector2f(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Window create(String title, int width, int height) {
|
public static Window create(String title, int width, int height) {
|
||||||
return new Window(title, -1, width, height, false);
|
return new Window(title, -1, width, height, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
engine/src/main/java/com/bartlomiejpluta/base/core/ui/WindowManager.java
Executable file → Normal file
20
engine/src/main/java/com/bartlomiejpluta/base/core/ui/WindowManager.java
Executable file → Normal file
@@ -1,10 +1,10 @@
|
|||||||
package com.bartlomiejpluta.base.core.ui;
|
package com.bartlomiejpluta.base.core.ui;
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class WindowManager {
|
public class WindowManager {
|
||||||
public Window createWindow(String title, int width, int height) {
|
public Window createWindow(String title, int width, int height) {
|
||||||
return Window.create(title, width, height);
|
return Window.create(title, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
engine/src/main/java/com/bartlomiejpluta/base/core/util/math/MathUtil.java
Executable file → Normal file
64
engine/src/main/java/com/bartlomiejpluta/base/core/util/math/MathUtil.java
Executable file → Normal file
@@ -1,32 +1,32 @@
|
|||||||
package com.bartlomiejpluta.base.core.util.math;
|
package com.bartlomiejpluta.base.core.util.math;
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
public class MathUtil {
|
public class MathUtil {
|
||||||
public static int gcdEuclidean(int a, int b) {
|
public static int gcdEuclidean(int a, int b) {
|
||||||
int x = a;
|
int x = a;
|
||||||
int y = b;
|
int y = b;
|
||||||
int z;
|
int z;
|
||||||
|
|
||||||
while(y != 0) {
|
while(y != 0) {
|
||||||
z = x % y;
|
z = x % y;
|
||||||
x = y;
|
x = y;
|
||||||
y = z;
|
y = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int clamp(int value, int min, int max) {
|
public static int clamp(int value, int min, int max) {
|
||||||
return min(max, max(value, min));
|
return min(max, max(value, min));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float clamp(float value, float min, float max) {
|
public static float clamp(float value, float min, float max) {
|
||||||
return min(max, max(value, min));
|
return min(max, max(value, min));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double clamp(double value, double min, double max) {
|
public static double clamp(double value, double min, double max) {
|
||||||
return min(max, max(value, min));
|
return min(max, max(value, min));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user