Allowing the animation naming to be customized
This commit is contained in:
parent
ce54ba60a7
commit
5db03da56f
|
@ -12,7 +12,7 @@ import tornadofx.observable
|
||||||
import tornadofx.setValue
|
import tornadofx.setValue
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
|
|
||||||
class AnimationFileModel(animationFilePath: Path, private val executor: ExecutorService) {
|
class AnimationFileModel(val parentModel: MainModel, animationFilePath: Path, private val executor: ExecutorService) {
|
||||||
val spineJson = SpineJson(animationFilePath)
|
val spineJson = SpineJson(animationFilePath)
|
||||||
|
|
||||||
val slotsProperty = SimpleObjectProperty<ObservableList<String>>()
|
val slotsProperty = SimpleObjectProperty<ObservableList<String>>()
|
||||||
|
@ -55,7 +55,11 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor
|
||||||
val audioFileModelsProperty = SimpleListProperty<AudioFileModel>(
|
val audioFileModelsProperty = SimpleListProperty<AudioFileModel>(
|
||||||
spineJson.audioEvents
|
spineJson.audioEvents
|
||||||
.map { event ->
|
.map { event ->
|
||||||
AudioFileModel(event, this, executor, { result -> saveAnimation(result, event.name) })
|
var audioFileModel: AudioFileModel? = null
|
||||||
|
val reportResult: (List<MouthCue>) -> Unit =
|
||||||
|
{ result -> saveAnimation(audioFileModel!!.animationName, event.name, result) }
|
||||||
|
audioFileModel = AudioFileModel(event, this, executor, reportResult)
|
||||||
|
return@map audioFileModel
|
||||||
}
|
}
|
||||||
.observable()
|
.observable()
|
||||||
)
|
)
|
||||||
|
@ -88,14 +92,11 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor
|
||||||
}
|
}
|
||||||
val valid by validProperty
|
val valid by validProperty
|
||||||
|
|
||||||
private fun saveAnimation(mouthCues: List<MouthCue>, audioEventName: String) {
|
private fun saveAnimation(animationName: String, audioEventName: String, mouthCues: List<MouthCue>) {
|
||||||
val animationName = getAnimationName(audioEventName)
|
|
||||||
spineJson.createOrUpdateAnimation(mouthCues, audioEventName, animationName, mouthSlot, mouthNaming)
|
spineJson.createOrUpdateAnimation(mouthCues, audioEventName, animationName, mouthSlot, mouthNaming)
|
||||||
spineJson.save()
|
spineJson.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAnimationName(audioEventName: String): String = "say_$audioEventName"
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
slots = spineJson.slots.observable()
|
slots = spineJson.slots.observable()
|
||||||
mouthSlot = spineJson.guessMouthSlot()
|
mouthSlot = spineJson.guessMouthSlot()
|
||||||
|
|
|
@ -29,6 +29,23 @@ class AudioFileModel(
|
||||||
val displayFilePathProperty = SimpleStringProperty(audioEvent.relativeAudioFilePath)
|
val displayFilePathProperty = SimpleStringProperty(audioEvent.relativeAudioFilePath)
|
||||||
val displayFilePath by displayFilePathProperty
|
val displayFilePath by displayFilePathProperty
|
||||||
|
|
||||||
|
val animationNameProperty = SimpleStringProperty().apply {
|
||||||
|
val mainModel = parentModel.parentModel
|
||||||
|
bind(object : ObjectBinding<String>() {
|
||||||
|
init {
|
||||||
|
super.bind(
|
||||||
|
mainModel.animationPrefixProperty,
|
||||||
|
eventNameProperty,
|
||||||
|
mainModel.animationSuffixProperty
|
||||||
|
)
|
||||||
|
}
|
||||||
|
override fun computeValue(): String {
|
||||||
|
return mainModel.animationPrefix + eventName + mainModel.animationSuffix
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
val animationName by animationNameProperty
|
||||||
|
|
||||||
val dialogProperty = SimpleStringProperty(audioEvent.dialog)
|
val dialogProperty = SimpleStringProperty(audioEvent.dialog)
|
||||||
val dialog: String? by dialogProperty
|
val dialog: String? by dialogProperty
|
||||||
|
|
||||||
|
@ -36,8 +53,17 @@ class AudioFileModel(
|
||||||
var animationProgress by animationProgressProperty
|
var animationProgress by animationProgressProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private val animatedPreviouslyProperty = SimpleBooleanProperty(false) // TODO: Initial value
|
private val animatedProperty = SimpleBooleanProperty().apply {
|
||||||
private var animatedPreviously by animatedPreviouslyProperty
|
bind(object : ObjectBinding<Boolean>() {
|
||||||
|
init {
|
||||||
|
super.bind(animationNameProperty, parentModel.spineJson.animationNames)
|
||||||
|
}
|
||||||
|
override fun computeValue(): Boolean {
|
||||||
|
return parentModel.spineJson.animationNames.contains(animationName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
private var animated by animatedProperty
|
||||||
|
|
||||||
private val futureProperty = SimpleObjectProperty<Future<*>?>()
|
private val futureProperty = SimpleObjectProperty<Future<*>?>()
|
||||||
private var future by futureProperty
|
private var future by futureProperty
|
||||||
|
@ -45,7 +71,7 @@ class AudioFileModel(
|
||||||
private val audioFileStateProperty = SimpleObjectProperty<AudioFileState>().apply {
|
private val audioFileStateProperty = SimpleObjectProperty<AudioFileState>().apply {
|
||||||
bind(object : ObjectBinding<AudioFileState>() {
|
bind(object : ObjectBinding<AudioFileState>() {
|
||||||
init {
|
init {
|
||||||
super.bind(animatedPreviouslyProperty, futureProperty, animationProgressProperty)
|
super.bind(animatedProperty, futureProperty, animationProgressProperty)
|
||||||
}
|
}
|
||||||
override fun computeValue(): AudioFileState {
|
override fun computeValue(): AudioFileState {
|
||||||
return if (future != null) {
|
return if (future != null) {
|
||||||
|
@ -57,7 +83,7 @@ class AudioFileModel(
|
||||||
else
|
else
|
||||||
AudioFileState(AudioFileStatus.Pending)
|
AudioFileState(AudioFileStatus.Pending)
|
||||||
} else {
|
} else {
|
||||||
if (animatedPreviously)
|
if (animated)
|
||||||
AudioFileState(AudioFileStatus.Done)
|
AudioFileState(AudioFileStatus.Done)
|
||||||
else
|
else
|
||||||
AudioFileState(AudioFileStatus.NotAnimated)
|
AudioFileState(AudioFileStatus.NotAnimated)
|
||||||
|
@ -133,7 +159,6 @@ class AudioFileModel(
|
||||||
val result = rhubarbTask.call()
|
val result = rhubarbTask.call()
|
||||||
runAndWait {
|
runAndWait {
|
||||||
reportResult(result)
|
reportResult(result)
|
||||||
animatedPreviously = true
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
runAndWait {
|
runAndWait {
|
||||||
|
|
|
@ -29,7 +29,7 @@ class MainModel(private val executor: ExecutorService) {
|
||||||
throw Exception("File does not exist.")
|
throw Exception("File does not exist.")
|
||||||
}
|
}
|
||||||
|
|
||||||
animationFileModel = AnimationFileModel(path, executor)
|
animationFileModel = AnimationFileModel(this, path, executor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var filePathString by filePathStringProperty
|
var filePathString by filePathStringProperty
|
||||||
|
@ -42,5 +42,11 @@ class MainModel(private val executor: ExecutorService) {
|
||||||
var animationFileModel by animationFileModelProperty
|
var animationFileModel by animationFileModelProperty
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
val animationPrefixProperty = SimpleStringProperty("say_")
|
||||||
|
var animationPrefix by animationPrefixProperty
|
||||||
|
|
||||||
|
val animationSuffixProperty = SimpleStringProperty("")
|
||||||
|
var animationSuffix by animationSuffixProperty
|
||||||
|
|
||||||
private fun getDefaultPathString() = FX.application.parameters.raw.firstOrNull()
|
private fun getDefaultPathString() = FX.application.parameters.raw.firstOrNull()
|
||||||
}
|
}
|
|
@ -71,6 +71,17 @@ class MainView : View() {
|
||||||
errorProperty().bind(fileModelProperty.select { it!!.mouthShapesErrorProperty })
|
errorProperty().bind(fileModelProperty.select { it!!.mouthShapesErrorProperty })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
field("Animation naming") {
|
||||||
|
textfield {
|
||||||
|
maxWidth = 100.0
|
||||||
|
textProperty().bindBidirectional(mainModel.animationPrefixProperty)
|
||||||
|
}
|
||||||
|
label("<audio event name>")
|
||||||
|
textfield {
|
||||||
|
maxWidth = 100.0
|
||||||
|
textProperty().bindBidirectional(mainModel.animationSuffixProperty)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fieldset("Audio events") {
|
fieldset("Audio events") {
|
||||||
tableview<AudioFileModel> {
|
tableview<AudioFileModel> {
|
||||||
|
@ -78,6 +89,8 @@ class MainView : View() {
|
||||||
columnResizePolicy = SmartResize.POLICY
|
columnResizePolicy = SmartResize.POLICY
|
||||||
column("Event", AudioFileModel::eventNameProperty)
|
column("Event", AudioFileModel::eventNameProperty)
|
||||||
.weigthedWidth(1.0)
|
.weigthedWidth(1.0)
|
||||||
|
column("Animation name", AudioFileModel::animationNameProperty)
|
||||||
|
.weigthedWidth(1.0)
|
||||||
column("Audio file", AudioFileModel::displayFilePathProperty)
|
column("Audio file", AudioFileModel::displayFilePathProperty)
|
||||||
.weigthedWidth(1.0)
|
.weigthedWidth(1.0)
|
||||||
column("Dialog", AudioFileModel::dialogProperty).apply {
|
column("Dialog", AudioFileModel::dialogProperty).apply {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.rhubarb_lip_sync.rhubarb_for_spine
|
package com.rhubarb_lip_sync.rhubarb_for_spine
|
||||||
|
|
||||||
import com.beust.klaxon.*
|
import com.beust.klaxon.*
|
||||||
|
import javafx.collections.FXCollections.observableSet
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
@ -94,10 +95,9 @@ class SpineJson(val filePath: Path) {
|
||||||
return attachments.map { it.key }
|
return attachments.map { it.key }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasAnimation(animationName: String): Boolean {
|
val animationNames = observableSet<String>(
|
||||||
val animations = json.obj("animations") ?: return false
|
json.obj("animations")?.map{ it.key }?.toSet() ?: setOf()
|
||||||
return animations.any { it.key == animationName }
|
)
|
||||||
}
|
|
||||||
|
|
||||||
fun createOrUpdateAnimation(mouthCues: List<MouthCue>, eventName: String, animationName: String,
|
fun createOrUpdateAnimation(mouthCues: List<MouthCue>, eventName: String, animationName: String,
|
||||||
mouthSlot: String, mouthNaming: MouthNaming
|
mouthSlot: String, mouthNaming: MouthNaming
|
||||||
|
@ -138,6 +138,8 @@ class SpineJson(val filePath: Path) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
animationNames.add(animationName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
|
|
Loading…
Reference in New Issue