Files
Terrarum/src/net/torvald/spriteassembler/SpriteAssemblerApp.kt
minjaesong 45f07c88b2 first successful sprite assembly
ALL kwd still not implemented
2019-01-07 04:13:38 +09:00

292 lines
12 KiB
Kotlin

package net.torvald.spriteassembler
import com.badlogic.gdx.Game
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.inUse
import java.awt.BorderLayout
import java.awt.Font
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.io.StringReader
import java.util.*
import javax.swing.*
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.DefaultTreeModel
/**
* Created by minjaesong on 2019-01-05.
*/
class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
private val panelProperties = JTree()
private val panelAnimationsList = JList<String>()
private val panelBodypartsList = JList<String>()
private val panelImageFilesList = JList<String>()
private val panelSkeletonsList = JList<String>()
private val panelTransformsList = JList<String>()
private val panelCode = JTextPane()
private val statBar = JTextArea("Null.")
private lateinit var adProperties: ADProperties
private val props = Properties()
private val lang = Properties()
private val captionProperties = "" + // dummy string to make IDE happy with the auto indent
"id=ID of this block\n" +
"drop=ID of the block this very block should drop when mined\n" +
"name=String identifier of the block\n" +
"shdr=Shade Red (light absorption). Valid range 0.0-4.0\n" +
"shdg=Shade Green (light absorption). Valid range 0.0-4.0\n" +
"shdb=Shade Blue (light absorption). Valid range 0.0-4.0\n" +
"shduv=Shade UV (light absorbtion). Valid range 0.0-4.0\n" +
"lumr=Luminosity Red (light intensity). Valid range 0.0-4.0\n" +
"lumg=Luminosity Green (light intensity). Valid range 0.0-4.0\n" +
"lumb=Luminosity Blue (light intensity). Valid range 0.0-4.0\n" +
"lumuv=Luminosity UV (light intensity). Valid range 0.0-4.0\n" +
"str=Strength of the block\n" +
"dsty=Density of the block. Water have 1000 in the in-game scale\n" +
"mate=Material of the block\n" +
"solid=Whether the file has full collision\n" +
"plat=Whether the block should behave like a platform\n" +
"wall=Whether the block can be used as a wall\n" +
"fall=Whether the block should fall through the empty space\n" +
"dlfn=Dynamic Light Function. 0=Static. Please see <strong>notes</strong>\n" +
"fv=Vertical friction when player slide on the cliff. 0 means not slide-able\n" +
"fr=Horizontal friction. &lt;16:slippery 16:regular &gt;16:sticky\n"
/**
* ¤ is used as a \n marker
*/
private val translations = "" +
"WARNING_CONTINUE=Continue?\n" +
"WARNING_YOUR_DATA_WILL_GONE=Existing edits will be lost.\n" +
"OPERATION_CANCELLED=Operation cancelled.\n" +
"NO_SUCH_FILE=No such file exists, operation cancelled.\n" +
"NEW_ROWS=Enter the number of rows to initialise the new CSV.¤Remember, you can always add or delete rows later.\n" +
"ADD_ROWS=Enter the number of rows to add:\n" +
"WRITE_FAIL=Writing to file has failed:\n" +
"STAT_INIT=Creating a new CSV. You can still open existing file.\n" +
"STAT_SAVE_SUCCESSFUL=File saved successfully.\n" +
"STAT_NEW_FILE=New CSV created.\n" +
"STAT_LOAD_SUCCESSFUL=File loaded successfully.\n" +
"ERROR_INTERNAL=Something went wrong.\n" +
"ERROR_PARSE_FAIL=Parsing failed\n" +
"SPRITE_DEF_LOAD_SUCCESSFUL=Sprite definition loaded.\n" +
"SPRITE_ASSEMBLE_SUCCESSFUL=Sprite assembled."
init {
// setup application properties //
try {
props.load(StringReader(captionProperties))
lang.load(StringReader(translations))
}
catch (e: Throwable) {
}
panelCode.font = Font(Font.MONOSPACED, Font.PLAIN, 11)
panelAnimationsList.model = DefaultListModel()
panelBodypartsList.model = DefaultListModel()
panelImageFilesList.model = DefaultListModel()
panelSkeletonsList.model = DefaultListModel()
panelTransformsList.model = DefaultListModel()
val panelPartsList = JTabbedPane(JTabbedPane.TOP)
panelPartsList.add("Animations", JScrollPane(panelAnimationsList))
panelPartsList.add("Bodyparts", JScrollPane(panelBodypartsList))
panelPartsList.add("Images", JScrollPane(panelImageFilesList))
panelPartsList.add("Skeletons", JScrollPane(panelSkeletonsList))
panelPartsList.add("Transforms", JScrollPane(panelTransformsList))
val panelDataView = JSplitPane(JSplitPane.VERTICAL_SPLIT, JScrollPane(panelProperties), panelPartsList)
panelDataView.resizeWeight = 0.333
// to disable text wrap
//val panelCodeNoWrap = JPanel(BorderLayout())
//panelCodeNoWrap.add(panelCode)
val panelMain = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(panelCode), panelDataView)
panelMain.resizeWeight = 0.666
val menu = JMenuBar()
menu.add(JMenu("File"))
menu.add(JMenu("Parse")).addMouseListener(object : MouseAdapter() {
override fun mousePressed(e: MouseEvent?) {
try {
adProperties = ADProperties(StringReader(panelCode.text))
statBar.text = lang.getProperty("SPRITE_DEF_LOAD_SUCCESSFUL")
val propRoot = DefaultMutableTreeNode("Properties")
adProperties.forEach { s, list ->
// build tree node for the properties display
val propNode = DefaultMutableTreeNode(s)
propRoot.add(propNode)
list.forEach {
propNode.add(DefaultMutableTreeNode(it.toString()))
}
}
panelProperties.model = DefaultTreeModel(propRoot)
// clean the data views
panelAnimationsList.model = DefaultListModel()
panelBodypartsList.model = DefaultListModel()
panelImageFilesList.model = DefaultListModel()
panelSkeletonsList.model = DefaultListModel()
panelTransformsList.model = DefaultListModel()
// populate animations view
adProperties.animations.forEach {
(panelAnimationsList.model as DefaultListModel).addElement("${it.value}")
}
// populate bodyparts view
adProperties.bodyparts.forEach { partName ->
(panelBodypartsList.model as DefaultListModel).addElement(partName)
}
// populate image file list view
adProperties.bodypartFiles.forEach { partName ->
(panelImageFilesList.model as DefaultListModel).addElement(partName)
}
// populate skeletons view
adProperties.skeletons.forEach {
(panelSkeletonsList.model as DefaultListModel).addElement("${it.value}")
}
// populate transforms view
adProperties.transforms.forEach {
(panelTransformsList.model as DefaultListModel).addElement("$it")
}
}
catch (fehler: Throwable) {
displayError("ERROR_PARSE_FAIL", fehler)
fehler.printStackTrace()
}
}
})
menu.add(JMenu("Run")).addMouseListener(object : MouseAdapter() {
override fun mousePressed(e: MouseEvent?) {
try {
gdxWindow.requestAssemblyTest(adProperties, "ANIM_IDLE_2")
statBar.text = lang.getProperty("SPRITE_ASSEMBLE_SUCCESSFUL")
}
catch (fehler: Throwable) {
displayError("ERROR_PARSE_FAIL", fehler)
fehler.printStackTrace()
}
}
})
this.layout = BorderLayout()
this.add(menu, BorderLayout.NORTH)
this.add(panelMain, BorderLayout.CENTER)
this.add(statBar, BorderLayout.SOUTH)
this.title = "Terrarum Sprite Assembler and Viewer"
this.isVisible = true
this.setSize(1154, 768)
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
}
private fun displayMessage(messageKey: String) {
JOptionPane.showOptionDialog(
null,
lang.getProperty(messageKey), null,
JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE, null,
arrayOf("OK", "Cancel"),
"Cancel"
)
}
private fun displayError(messageKey: String, cause: Throwable) {
JOptionPane.showOptionDialog(null,
lang.getProperty(messageKey) + "\n" + cause.toString(), null,
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE, null,
arrayOf("OK", "Cancel"),
"Cancel"
)
}
}
class SpriteAssemblerPreview: Game() {
private lateinit var batch: SpriteBatch
private lateinit var renderTexture: Texture
private var image: Pixmap? = null
set(value) {
renderTexture.dispose()
field?.dispose()
field = value
renderTexture = Texture(field)
}
override fun create() {
Gdx.graphics.setTitle("Sprite Assembler Preview")
batch = SpriteBatch()
renderTexture = Texture(1, 1, Pixmap.Format.RGBA8888)
}
private val bgCol = Color(.62f,.79f,1f,1f)
private var doAssemble = false
private lateinit var assembleProp: ADProperties
private lateinit var assembleFrameName: String
override fun render() {
if (doAssemble) {
// assembly requires GL context
doAssemble = false
assembleImageTest(assembleProp, assembleFrameName)
}
Gdx.gl.glClearColor(.62f,.79f,1f,1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D)
Gdx.gl.glEnable(GL20.GL_BLEND)
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
batch.inUse {
batch.color = Color.WHITE
batch.draw(renderTexture, 0f, 0f)
}
}
private fun assembleImageTest(prop: ADProperties, frameName: String) {
image = AssembleFramePixmap(prop, frameName)
}
fun requestAssemblyTest(prop: ADProperties, frameName: String) {
doAssemble = true
assembleProp = prop
assembleFrameName = frameName
}
}
fun main(args: Array<String>) {
val appConfig = LwjglApplicationConfiguration()
appConfig.resizable = true
appConfig.width = 512
appConfig.height = 512
appConfig.foregroundFPS = 5
appConfig.backgroundFPS = 5
val gdxWindow = SpriteAssemblerPreview()
LwjglApplication(gdxWindow, appConfig)
SpriteAssemblerApp(gdxWindow)
}