mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-12 14:51:51 +09:00
sprite and spriteassembler update
This commit is contained in:
@@ -1,37 +1,45 @@
|
|||||||
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
||||||
SPRITESHEET=mods/basegame/sprites/test_werebeastf/taimu_
|
SPRITESHEET=mods/basegame/sprites/test_werebeastf/taimu_
|
||||||
EXTENSION=.tga
|
EXTENSION=.tga
|
||||||
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
|
# defines frame size and origin point. Origin point is given as: (originx, 0)
|
||||||
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
|
|
||||||
CONFIG=SIZE 64,98;ORIGINX 40
|
CONFIG=SIZE 64,98;ORIGINX 40
|
||||||
|
|
||||||
# note to self: don't implement skeleton hierarchy: there's too many exceptions
|
! A skeleton also defines what body parts (images) be used.
|
||||||
# besides, you have "ALL" key.
|
! You can also write multiline text using reverse solidus; this is a feature of .properties
|
||||||
|
|
||||||
! a skeleton also defines what body parts (images) be used.
|
|
||||||
! you can also write multiline text using reverse solidus; this is a feature of .properties
|
|
||||||
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
||||||
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
||||||
! first reversed then being iterated.
|
! first reversed then being iterated.
|
||||||
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
|
! Some keywords are considered special within the game, they are:
|
||||||
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
|
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
|
||||||
SKELETON_STAND=HEADGEAR 0,32;\
|
BODYPARTS=HEADGEAR 13,14;\
|
||||||
ARM_REST_LEFT -9,49;HELD_ITEM -6,11;\
|
HEAD 13,14;\
|
||||||
HEAD 2,83;\
|
ARM_REST_RIGHT 5,3;\
|
||||||
BUST_0 4,60;\
|
ARM_REST_LEFT 6,3;\
|
||||||
TORSO_0 0,55;\
|
LEG_REST_RIGHT 12,6;\
|
||||||
TORSO_1 0,55;\
|
LEG_REST_LEFT 8,6;\
|
||||||
LEG_REST_RIGHT -6,22;\
|
TORSO_0 18,19;\
|
||||||
LEG_REST_LEFT 7,22;\
|
TORSO_1 18,19;\
|
||||||
ARM_REST_RIGHT 12,51;\
|
TAIL_0 30,2;\
|
||||||
TAIL_0 -11,27
|
BUST_0 11,2;\
|
||||||
|
HELD_ITEM 0,0
|
||||||
|
SKELETON_STAND=HEADGEAR 0,78;\
|
||||||
|
ARM_REST_RIGHT -15,66;\
|
||||||
|
HELD_ITEM -11,33;\
|
||||||
|
HEAD 0,78;\
|
||||||
|
BUST_0 0,63;\
|
||||||
|
TORSO_0 0,54;\
|
||||||
|
TORSO_1 0,54;\
|
||||||
|
LEG_REST_RIGHT -5,41;\
|
||||||
|
LEG_REST_LEFT 3,41;\
|
||||||
|
ARM_REST_LEFT 8,66;\
|
||||||
|
TAIL_0 2,40
|
||||||
|
|
||||||
# skeleton_stand is used for testing purpose
|
# skeleton_stand is used for testing purpose
|
||||||
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
|
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
|
||||||
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0
|
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0;TORSO_1 0,-999
|
||||||
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0
|
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0;TORSO_1 0,-999
|
||||||
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0
|
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0;TORSO_1 0,-999
|
||||||
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0
|
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0;TORSO_1 0,-999
|
||||||
|
|
||||||
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
|
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
|
||||||
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1
|
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1
|
||||||
|
|||||||
@@ -1,37 +1,45 @@
|
|||||||
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
||||||
SPRITESHEET=mods/basegame/sprites/test_werebeastf/taimuglow_
|
SPRITESHEET=mods/basegame/sprites/test_werebeastf/taimuglow_
|
||||||
EXTENSION=.tga
|
EXTENSION=.tga
|
||||||
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
|
# defines frame size and origin point. Origin point is given as: (originx, 0)
|
||||||
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
|
|
||||||
CONFIG=SIZE 64,98;ORIGINX 40
|
CONFIG=SIZE 64,98;ORIGINX 40
|
||||||
|
|
||||||
# note to self: don't implement skeleton hierarchy: there's too many exceptions
|
! A skeleton also defines what body parts (images) be used.
|
||||||
# besides, you have "ALL" key.
|
! You can also write multiline text using reverse solidus; this is a feature of .properties
|
||||||
|
|
||||||
! a skeleton also defines what body parts (images) be used.
|
|
||||||
! you can also write multiline text using reverse solidus; this is a feature of .properties
|
|
||||||
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
||||||
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
||||||
! first reversed then being iterated.
|
! first reversed then being iterated.
|
||||||
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
|
! Some keywords are considered special within the game, they are:
|
||||||
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
|
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
|
||||||
SKELETON_STAND=HEADGEAR 0,32;\
|
BODYPARTS=HEADGEAR 13,14;\
|
||||||
ARM_REST_LEFT -8,49;HELD_ITEM -6,11;\
|
HEAD 13,14;\
|
||||||
HEAD 2,83;\
|
ARM_REST_RIGHT 5,3;\
|
||||||
BUST_0 4,60;\
|
ARM_REST_LEFT 6,3;\
|
||||||
TORSO_0 0,55;\
|
LEG_REST_RIGHT 12,6;\
|
||||||
TORSO_1 0,55;\
|
LEG_REST_LEFT 8,6;\
|
||||||
LEG_REST_RIGHT -5,22;\
|
TORSO_0 18,19;\
|
||||||
LEG_REST_LEFT 6,22;\
|
TORSO_1 18,19;\
|
||||||
ARM_REST_RIGHT 11,51;\
|
TAIL_0 30,2;\
|
||||||
TAIL_0 -11,27
|
BUST_0 11,2;\
|
||||||
|
HELD_ITEM 0,0
|
||||||
|
SKELETON_STAND=HEADGEAR 0,78;\
|
||||||
|
ARM_REST_RIGHT -15,66;\
|
||||||
|
HELD_ITEM -11,33;\
|
||||||
|
HEAD 0,78;\
|
||||||
|
BUST_0 0,63;\
|
||||||
|
TORSO_0 0,54;\
|
||||||
|
TORSO_1 0,54;\
|
||||||
|
LEG_REST_RIGHT -5,41;\
|
||||||
|
LEG_REST_LEFT 3,41;\
|
||||||
|
ARM_REST_LEFT 8,66;\
|
||||||
|
TAIL_0 2,40
|
||||||
|
|
||||||
# skeleton_stand is used for testing purpose
|
# skeleton_stand is used for testing purpose
|
||||||
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
|
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
|
||||||
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0
|
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0;TORSO_1 0,-999
|
||||||
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0
|
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0;TORSO_1 0,-999
|
||||||
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0
|
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0;TORSO_1 0,-999
|
||||||
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0
|
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0;TORSO_1 0,-999
|
||||||
|
|
||||||
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
|
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
|
||||||
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1
|
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1
|
||||||
|
|||||||
@@ -1,20 +1,29 @@
|
|||||||
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
||||||
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/test_
|
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/test_
|
||||||
EXTENSION=.tga
|
EXTENSION=.tga
|
||||||
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
|
# defines frame size and origin point. Origin point is given as: (originx, 0)
|
||||||
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
|
|
||||||
CONFIG=SIZE 48,56;ORIGINX 29
|
CONFIG=SIZE 48,56;ORIGINX 29
|
||||||
|
|
||||||
# note to self: don't implement skeleton hierarchy: there's too many exceptions
|
! A skeleton also defines what body parts (images) be used.
|
||||||
# besides, you have "ALL" key.
|
! You can also write multiline text using reverse solidus; this is a feature of .properties
|
||||||
|
|
||||||
! a skeleton also defines what body parts (images) be used.
|
|
||||||
! you can also write multiline text using reverse solidus; this is a feature of .properties
|
|
||||||
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
||||||
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
||||||
! first reversed then being iterated.
|
! first reversed then being iterated.
|
||||||
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
|
! Some keywords are considered special within the game, they are:
|
||||||
# TODO right now accessory points are explicitly defined. Should they be injected in run-time? In that case, certain names (e.g. headgear, held_item) will act as an anchor.
|
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
|
||||||
|
BODYPARTS=ARM_REST_RIGHT 3,8;\
|
||||||
|
ARM_REST_LEFT 3,8;\
|
||||||
|
FOOT_LEFT 4,2;\
|
||||||
|
FOOT_RIGHT 4,2;\
|
||||||
|
UPPER_TORSO 9,4;\
|
||||||
|
LOWER_TORSO 7,4;\
|
||||||
|
LEG_REST_RIGHT 3,7;\
|
||||||
|
LEG_REST_LEFT 3,7;\
|
||||||
|
HEAD 8,7;\
|
||||||
|
HAND_REST_RIGHT 3,3;\
|
||||||
|
HAND_REST_LEFT 3,3;\
|
||||||
|
HAIR 20,12;\
|
||||||
|
HAIR_FORE 20,12
|
||||||
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
|
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
|
||||||
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
|
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
|
||||||
HAIR 0,32;HEAD 0,32;\
|
HAIR 0,32;HEAD 0,32;\
|
||||||
|
|||||||
@@ -1,20 +1,29 @@
|
|||||||
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
||||||
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/testglow_
|
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/testglow_
|
||||||
EXTENSION=.tga
|
EXTENSION=.tga
|
||||||
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
|
# defines frame size and origin point. Origin point is given as: (originx, 0)
|
||||||
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
|
|
||||||
CONFIG=SIZE 48,56;ORIGINX 29
|
CONFIG=SIZE 48,56;ORIGINX 29
|
||||||
|
|
||||||
# note to self: don't implement skeleton hierarchy: there's too many exceptions
|
! A skeleton also defines what body parts (images) be used.
|
||||||
# besides, you have "ALL" key.
|
! You can also write multiline text using reverse solidus; this is a feature of .properties
|
||||||
|
|
||||||
! a skeleton also defines what body parts (images) be used.
|
|
||||||
! you can also write multiline text using reverse solidus; this is a feature of .properties
|
|
||||||
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
||||||
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
||||||
! first reversed then being iterated.
|
! first reversed then being iterated.
|
||||||
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
|
! Some keywords are considered special within the game, they are:
|
||||||
# TODO right now accessory points are explicitly defined. Should they be injected in run-time? In that case, certain names (e.g. headgear, held_item) will act as an anchor.
|
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
|
||||||
|
BODYPARTS=ARM_REST_RIGHT 3,8;\
|
||||||
|
ARM_REST_LEFT 3,8;\
|
||||||
|
FOOT_LEFT 4,2;\
|
||||||
|
FOOT_RIGHT 4,2;\
|
||||||
|
UPPER_TORSO 9,4;\
|
||||||
|
LOWER_TORSO 7,4;\
|
||||||
|
LEG_REST_RIGHT 3,7;\
|
||||||
|
LEG_REST_LEFT 3,7;\
|
||||||
|
HEAD 8,7;\
|
||||||
|
HAND_REST_RIGHT 3,3;\
|
||||||
|
HAND_REST_LEFT 3,3;\
|
||||||
|
HAIR 20,12;\
|
||||||
|
HAIR_FORE 20,12
|
||||||
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
|
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
|
||||||
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
|
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
|
||||||
HAIR 0,32;HEAD 0,32;\
|
HAIR 0,32;HEAD 0,32;\
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -29,9 +29,9 @@ interface HasAssembledSprite {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
fun reassembleSprite(sprite: SpriteAnimation, spriteGlow: SpriteAnimation? = null) {
|
fun reassembleSprite(sprite: SpriteAnimation, spriteGlow: SpriteAnimation? = null) {
|
||||||
_rebuild(ADProperties(Gdx.files.internal(animDescPath).read()), sprite)
|
_rebuild(ADProperties(Gdx.files.internal(animDescPath)), sprite)
|
||||||
if (animDescPathGlow != null && spriteGlow != null)
|
if (animDescPathGlow != null && spriteGlow != null)
|
||||||
_rebuild(ADProperties(Gdx.files.internal(animDescPathGlow).read()), spriteGlow)
|
_rebuild(ADProperties(Gdx.files.internal(animDescPathGlow)), spriteGlow)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fun rebuild(animDescPath: String, spriteAnimation: SpriteAnimation) {
|
/*fun rebuild(animDescPath: String, spriteAnimation: SpriteAnimation) {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package net.torvald.spriteassembler
|
package net.torvald.spriteassembler
|
||||||
|
|
||||||
|
import com.badlogic.gdx.files.FileHandle
|
||||||
import net.torvald.terrarum.linearSearchBy
|
import net.torvald.terrarum.linearSearchBy
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.HashMap
|
|
||||||
import kotlin.collections.HashSet
|
|
||||||
|
|
||||||
internal data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
|
internal data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
|
||||||
override fun toString() = "$name $position"
|
override fun toString() = "$name $position"
|
||||||
@@ -15,6 +14,7 @@ internal data class Skeleton(val name: String, val joints: List<Joint>) {
|
|||||||
override fun toString() = "$name=$joints"
|
override fun toString() = "$name=$joints"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name You know it
|
* @param name You know it
|
||||||
* @param delay Delay between each frame in seconds
|
* @param delay Delay between each frame in seconds
|
||||||
@@ -32,22 +32,25 @@ internal data class Transform(val joint: Joint, val translate: ADPropertyObject.
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ADProperties {
|
class ADProperties {
|
||||||
|
private var fileFrom = ""
|
||||||
private val javaProp = Properties()
|
private val javaProp = Properties()
|
||||||
|
|
||||||
/** Every key is CAPITALISED */
|
/** Every key is CAPITALISED */
|
||||||
private val propTable = HashMap<String, List<ADPropertyObject>>()
|
private val propTable = HashMap<String, List<ADPropertyObject>>()
|
||||||
|
|
||||||
/** list of bodyparts used by all the skeletons (HEAD, UPPER_TORSO, LOWER_TORSO) */
|
/** list of bodyparts used by all the skeletons (HEAD, UPPER_TORSO, LOWER_TORSO) */
|
||||||
lateinit var bodyparts: List<String>; private set
|
// lateinit var bodyparts: List<String>; private set
|
||||||
lateinit var bodypartFiles: List<String>; private set
|
lateinit var bodypartFiles: List<String>; private set
|
||||||
/** properties that are being used as skeletons (SKELETON_STAND) */
|
/** properties that are being used as skeletons (SKELETON_STAND) */
|
||||||
internal lateinit var skeletons: HashMap<String, Skeleton>; private set
|
internal lateinit var skeletons: HashMap<String, Skeleton>; private set
|
||||||
|
/** properties that defines position of joint of the bodypart */
|
||||||
|
internal val bodyparts = HashMap<String, ADPropertyObject.Vector2i>()
|
||||||
/** properties that are recognised as animations (ANIM_RUN, ANIM)IDLE) */
|
/** properties that are recognised as animations (ANIM_RUN, ANIM)IDLE) */
|
||||||
internal lateinit var animations: HashMap<String, Animation>; private set
|
internal lateinit var animations: HashMap<String, Animation>; private set
|
||||||
/** an "animation frame" property (ANIM_RUN_1, ANIM_RUN_2) */
|
/** an "animation frame" property (ANIM_RUN_1, ANIM_RUN_2) */
|
||||||
internal lateinit var transforms: HashMap<String, List<Transform>>; private set
|
internal lateinit var transforms: HashMap<String, List<Transform>>; private set
|
||||||
|
|
||||||
private val reservedProps = listOf("SPRITESHEET", "EXTENSION")
|
private val reservedProps = listOf("SPRITESHEET", "EXTENSION", "CONFIG", "BODYPARTS")
|
||||||
private val animMustContain = listOf("DELAY", "ROW", "SKELETON")
|
private val animMustContain = listOf("DELAY", "ROW", "SKELETON")
|
||||||
|
|
||||||
lateinit var baseFilename: String; private set
|
lateinit var baseFilename: String; private set
|
||||||
@@ -55,9 +58,8 @@ class ADProperties {
|
|||||||
var frameWidth: Int = -1; private set
|
var frameWidth: Int = -1; private set
|
||||||
var frameHeight: Int = -1; private set
|
var frameHeight: Int = -1; private set
|
||||||
var originX: Int = -1; private set
|
var originX: Int = -1; private set
|
||||||
var originY: Int = -1; private set
|
|
||||||
internal val origin: ADPropertyObject.Vector2i
|
internal val origin: ADPropertyObject.Vector2i
|
||||||
get() = ADPropertyObject.Vector2i(originX, originY)
|
get() = ADPropertyObject.Vector2i(originX, 0)
|
||||||
|
|
||||||
private val animFrameSuffixRegex = Regex("""_[0-9]+""")
|
private val animFrameSuffixRegex = Regex("""_[0-9]+""")
|
||||||
|
|
||||||
@@ -70,6 +72,12 @@ class ADProperties {
|
|||||||
const val ALL_JOINT_SELECT_KEY = "ALL"
|
const val ALL_JOINT_SELECT_KEY = "ALL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(gdxFile: FileHandle) {
|
||||||
|
fileFrom = gdxFile.path()
|
||||||
|
javaProp.load(gdxFile.read())
|
||||||
|
continueLoad()
|
||||||
|
}
|
||||||
|
|
||||||
constructor(reader: Reader) {
|
constructor(reader: Reader) {
|
||||||
javaProp.load(reader)
|
javaProp.load(reader)
|
||||||
continueLoad()
|
continueLoad()
|
||||||
@@ -85,6 +93,16 @@ class ADProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun continueLoad() {
|
private fun continueLoad() {
|
||||||
|
// sanity check
|
||||||
|
reservedProps.forEach {
|
||||||
|
try {
|
||||||
|
javaProp[it]!!
|
||||||
|
}
|
||||||
|
catch (e: NullPointerException) {
|
||||||
|
throw IllegalArgumentException("Prop '$it' not found from ${fileFrom.ifBlank { "(path unavailable)" }}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
javaProp.keys.forEach { propName ->
|
javaProp.keys.forEach { propName ->
|
||||||
val propsStr = javaProp.getProperty(propName as String)
|
val propsStr = javaProp.getProperty(propName as String)
|
||||||
val propsList = propsStr.split(';').map { ADPropertyObject(it) }
|
val propsList = propsStr.split(';').map { ADPropertyObject(it) }
|
||||||
@@ -99,11 +117,9 @@ class ADProperties {
|
|||||||
frameWidth = frameSizeVec.x
|
frameWidth = frameSizeVec.x
|
||||||
frameHeight = frameSizeVec.y
|
frameHeight = frameSizeVec.y
|
||||||
originX = (get("CONFIG").linearSearchBy { it.name == "ORIGINX" }!!.input as Float).toInt()
|
originX = (get("CONFIG").linearSearchBy { it.name == "ORIGINX" }!!.input as Float).toInt()
|
||||||
originY = frameHeight - 1
|
|
||||||
|
|
||||||
var maxColFinder = -1
|
var maxColFinder = -1
|
||||||
var maxRowFinder = -1
|
var maxRowFinder = -1
|
||||||
val bodyparts = HashSet<String>()
|
|
||||||
val skeletons = HashMap<String, Skeleton>()
|
val skeletons = HashMap<String, Skeleton>()
|
||||||
val animations = HashMap<String, Animation>()
|
val animations = HashMap<String, Animation>()
|
||||||
val animFrames = HashMap<String, Int>()
|
val animFrames = HashMap<String, Int>()
|
||||||
@@ -153,13 +169,6 @@ class ADProperties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate the bodyparts using skeletons
|
|
||||||
skeletons.forEach { (_, prop: Skeleton) ->
|
|
||||||
prop.joints.forEach {
|
|
||||||
bodyparts.add(it.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// populate transforms
|
// populate transforms
|
||||||
animations.forEach { t, u ->
|
animations.forEach { t, u ->
|
||||||
for (fc in 1..u.frames) {
|
for (fc in 1..u.frames) {
|
||||||
@@ -190,17 +199,28 @@ class ADProperties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bodyparts = bodyparts.toList().sorted()
|
get("BODYPARTS").forEach {
|
||||||
|
try {
|
||||||
|
this.bodyparts[it.name] = (it.input as ADPropertyObject.Vector2i)
|
||||||
|
}
|
||||||
|
catch (e: NullPointerException) {
|
||||||
|
if (it.name.isBlank())
|
||||||
|
throw IllegalArgumentException("Empty Bodypart name on BODYPARTS; try removing trailing semicolon (';')?")
|
||||||
|
else
|
||||||
|
throw IllegalArgumentException("Bodyparts definition for '${it.name}' not found from ${fileFrom.ifBlank { "(path unavailable)" }}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.skeletons = skeletons
|
this.skeletons = skeletons
|
||||||
this.animations = animations
|
this.animations = animations
|
||||||
this.bodypartFiles = this.bodyparts.map { toFilename(it) }
|
this.bodypartFiles = this.bodyparts.keys.map { toFilename(it) }
|
||||||
this.transforms = transforms
|
this.transforms = transforms
|
||||||
|
|
||||||
cols = maxColFinder
|
cols = maxColFinder
|
||||||
rows = maxRowFinder
|
rows = maxRowFinder
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(identifier: String) = propTable[identifier.toUpperCase()]!!
|
operator fun get(identifier: String): List<ADPropertyObject> = propTable[identifier.toUpperCase()]!!
|
||||||
val keys
|
val keys
|
||||||
get() = propTable.keys
|
get() = propTable.keys
|
||||||
fun containsKey(key: String) = propTable.containsKey(key)
|
fun containsKey(key: String) = propTable.containsKey(key)
|
||||||
@@ -299,6 +319,8 @@ class ADPropertyObject(propertyRaw: String) {
|
|||||||
operator fun minus(other: Vector2i) = Vector2i(this.x - other.x, this.y - other.y)
|
operator fun minus(other: Vector2i) = Vector2i(this.x - other.x, this.y - other.y)
|
||||||
|
|
||||||
fun invertY() = Vector2i(this.x, -this.y)
|
fun invertY() = Vector2i(this.x, -this.y)
|
||||||
|
fun invertX() = Vector2i(-this.x, this.y)
|
||||||
|
fun invertXY() = Vector2i(-this.x, -this.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ADPropertyType {
|
enum class ADPropertyType {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package net.torvald.spriteassembler
|
|||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
import net.torvald.terrarum.linearSearch
|
import net.torvald.terrarum.linearSearch
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assembles the single frame of the animation, outputs GDX Pixmap.
|
* Assembles the single frame of the animation, outputs GDX Pixmap.
|
||||||
@@ -34,19 +33,11 @@ object AssembleSheetPixmap {
|
|||||||
val theAnim = properties.getAnimByFrameName(frameName)
|
val theAnim = properties.getAnimByFrameName(frameName)
|
||||||
val skeleton = theAnim.skeleton.joints.reversed()
|
val skeleton = theAnim.skeleton.joints.reversed()
|
||||||
val transforms = properties.getTransform(frameName)
|
val transforms = properties.getTransform(frameName)
|
||||||
val bodyparts = Array<Pixmap?>(skeleton.size) {
|
val bodypartOrigins = properties.bodyparts
|
||||||
// if file does not exist, null it
|
val bodypartImages = properties.bodyparts.keys.map {
|
||||||
val file = File("assets/" + properties.toFilename(skeleton[it].name))
|
val file = Gdx.files.internal("assets/${properties.toFilename(it)}")
|
||||||
|
it to (if (file.exists()) Pixmap(file) else null)
|
||||||
//printdbg(this, "Loading file ${file.absolutePath}, exists: ${file.exists()}")
|
}.toMap()
|
||||||
|
|
||||||
/*return*/if (file.exists()) {
|
|
||||||
Pixmap(Gdx.files.internal(file.path))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val transformList = AssembleFrameBase.makeTransformList(skeleton, transforms)
|
val transformList = AssembleFrameBase.makeTransformList(skeleton, transforms)
|
||||||
|
|
||||||
val animRow = theAnim.row
|
val animRow = theAnim.row
|
||||||
@@ -54,25 +45,26 @@ object AssembleSheetPixmap {
|
|||||||
|
|
||||||
// AppLoader.printdbg(this, "Frame to draw: $frameName (R$animRow C$animFrame)")
|
// AppLoader.printdbg(this, "Frame to draw: $frameName (R$animRow C$animFrame)")
|
||||||
|
|
||||||
drawFrame(animRow, animFrame, canvas, properties, bodyparts, transformList)
|
drawFrame(animRow, animFrame, canvas, properties, bodypartOrigins, bodypartImages, transformList)
|
||||||
|
|
||||||
bodyparts.forEach { it?.dispose() }
|
bodypartImages.values.forEach { it?.dispose() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawFrame(row: Int, column: Int,
|
private fun drawFrame(row: Int, column: Int,
|
||||||
canvas: Pixmap,
|
canvas: Pixmap,
|
||||||
props: ADProperties,
|
props: ADProperties,
|
||||||
bodyparts: Array<Pixmap?>,
|
bodypartOrigins: HashMap<String, ADPropertyObject.Vector2i>,
|
||||||
|
bodypartImages: Map<String, Pixmap?>,
|
||||||
transformList: List<Pair<String, ADPropertyObject.Vector2i>>
|
transformList: List<Pair<String, ADPropertyObject.Vector2i>>
|
||||||
) {
|
) {
|
||||||
val tmpFrame = Pixmap(props.frameWidth, props.frameHeight, Pixmap.Format.RGBA8888)
|
val tmpFrame = Pixmap(props.frameWidth, props.frameHeight, Pixmap.Format.RGBA8888)
|
||||||
|
|
||||||
bodyparts.forEachIndexed { index, image ->
|
transformList.forEach { (name, pos) ->
|
||||||
if (image != null) {
|
bodypartImages[name]?.let { image ->
|
||||||
val imgCentre = AssembleFrameBase.getCentreOf(image)
|
val imgCentre = bodypartOrigins[name]!!.invertX()
|
||||||
val drawPos = transformList[index].second.invertY() + props.origin - imgCentre
|
val drawPos = props.origin + pos + imgCentre
|
||||||
|
|
||||||
tmpFrame.drawPixmap(image, drawPos.x, drawPos.y)
|
tmpFrame.drawPixmap(image, drawPos.x, props.frameHeight - drawPos.y - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
|
|||||||
|GNU General Public License for more details.
|
|GNU General Public License for more details.
|
||||||
|
|
|
|
||||||
|You should have received a copy of the GNU General Public License
|
|You should have received a copy of the GNU General Public License
|
||||||
|along with this program. If not, see <https://www.gnu.org/licenses/>.""".trimMargin()
|
|along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
|
||||||
|
|Paste your Animation Description here and press 'Update'!""".trimMargin()
|
||||||
panelCode.addMouseListener(object : MouseAdapter() {
|
panelCode.addMouseListener(object : MouseAdapter() {
|
||||||
override fun mousePressed(e: MouseEvent?) {
|
override fun mousePressed(e: MouseEvent?) {
|
||||||
if (panelCodeInit) {
|
if (panelCodeInit) {
|
||||||
@@ -116,14 +118,14 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
|
|||||||
|
|
||||||
panelProperties.model = DefaultTreeModel(DefaultMutableTreeNode(lang.getProperty("PROPERTIES_GO_HERE")))
|
panelProperties.model = DefaultTreeModel(DefaultMutableTreeNode(lang.getProperty("PROPERTIES_GO_HERE")))
|
||||||
val panelDataView = JSplitPane(JSplitPane.VERTICAL_SPLIT, JScrollPane(panelProperties), panelPartsList)
|
val panelDataView = JSplitPane(JSplitPane.VERTICAL_SPLIT, JScrollPane(panelProperties), panelPartsList)
|
||||||
panelDataView.resizeWeight = 0.333
|
panelDataView.resizeWeight = 0.4
|
||||||
|
|
||||||
// to disable text wrap
|
// to disable text wrap
|
||||||
//val panelCodeNoWrap = JPanel(BorderLayout())
|
//val panelCodeNoWrap = JPanel(BorderLayout())
|
||||||
//panelCodeNoWrap.add(panelCode)
|
//panelCodeNoWrap.add(panelCode)
|
||||||
|
|
||||||
val panelMain = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(panelCode), panelDataView)
|
val panelMain = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(panelCode), panelDataView)
|
||||||
panelMain.resizeWeight = 0.666
|
panelMain.resizeWeight = 0.6
|
||||||
|
|
||||||
val menu = JMenuBar()
|
val menu = JMenuBar()
|
||||||
menu.add(JMenu("Update")).addMouseListener(object : MouseAdapter() {
|
menu.add(JMenu("Update")).addMouseListener(object : MouseAdapter() {
|
||||||
@@ -158,8 +160,8 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
|
|||||||
(panelAnimationsList.model as DefaultListModel).addElement("${it.value}")
|
(panelAnimationsList.model as DefaultListModel).addElement("${it.value}")
|
||||||
}
|
}
|
||||||
// populate bodyparts view
|
// populate bodyparts view
|
||||||
adProperties.bodyparts.forEach { partName ->
|
adProperties.bodyparts.toSortedMap().forEach { part ->
|
||||||
(panelBodypartsList.model as DefaultListModel).addElement(partName)
|
(panelBodypartsList.model as DefaultListModel).addElement("${part.key}: ${part.value}")
|
||||||
}
|
}
|
||||||
// populate image file list view
|
// populate image file list view
|
||||||
adProperties.bodypartFiles.forEach { partName ->
|
adProperties.bodypartFiles.forEach { partName ->
|
||||||
@@ -177,7 +179,7 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
|
|||||||
(panelStatList.model as DefaultListModel).addElement("Spritesheet rows: ${adProperties.rows}")
|
(panelStatList.model as DefaultListModel).addElement("Spritesheet rows: ${adProperties.rows}")
|
||||||
(panelStatList.model as DefaultListModel).addElement("Spritesheet columns: ${adProperties.cols}")
|
(panelStatList.model as DefaultListModel).addElement("Spritesheet columns: ${adProperties.cols}")
|
||||||
(panelStatList.model as DefaultListModel).addElement("Frame size: ${adProperties.frameWidth}, ${adProperties.frameHeight}")
|
(panelStatList.model as DefaultListModel).addElement("Frame size: ${adProperties.frameWidth}, ${adProperties.frameHeight}")
|
||||||
(panelStatList.model as DefaultListModel).addElement("Origin position: ${adProperties.originX}, ${adProperties.originY}")
|
(panelStatList.model as DefaultListModel).addElement("Origin position: ${adProperties.origin}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -218,7 +220,7 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
|
|||||||
this.add(statBar, BorderLayout.SOUTH)
|
this.add(statBar, BorderLayout.SOUTH)
|
||||||
this.title = "Terrarum Sprite Assembler and Viewer"
|
this.title = "Terrarum Sprite Assembler and Viewer"
|
||||||
this.isVisible = true
|
this.isVisible = true
|
||||||
this.setSize(1154, 768)
|
this.setSize(1120, 768)
|
||||||
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
|
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +319,7 @@ class SpriteAssemblerPreview: Game() {
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val appConfig = Lwjgl3ApplicationConfiguration()
|
val appConfig = Lwjgl3ApplicationConfiguration()
|
||||||
appConfig.setWindowedMode(800, 800)
|
appConfig.setWindowedMode(1024, 1024)
|
||||||
appConfig.setIdleFPS(5)
|
appConfig.setIdleFPS(5)
|
||||||
appConfig.setForegroundFPS(5)
|
appConfig.setForegroundFPS(5)
|
||||||
appConfig.setResizable(false)
|
appConfig.setResizable(false)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|||||||
import net.torvald.EMDASH
|
import net.torvald.EMDASH
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.*
|
import net.torvald.terrarum.App.*
|
||||||
|
import net.torvald.terrarum.Terrarum.PLAYER_REF_ID
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||||
import net.torvald.terrarum.blockproperties.BlockPropUtil
|
import net.torvald.terrarum.blockproperties.BlockPropUtil
|
||||||
@@ -293,7 +294,9 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
}
|
}
|
||||||
catch (e: NullPointerException) {
|
catch (e: NullPointerException) {
|
||||||
System.err.println("Could not read the actor ${it} from the disk")
|
System.err.println("Could not read the actor ${it} from the disk")
|
||||||
// throw e // TODO don't rethrow -- let players play the corrupted world if it loads, they'll be able to cope with their losses even though there will be buncha lone actorblocks lying around...
|
e.printStackTrace()
|
||||||
|
if (it == PLAYER_REF_ID) throw e
|
||||||
|
// throw e // if not player, don't rethrow -- let players play the corrupted world if it loads, they'll be able to cope with their losses even though there will be buncha lone actorblocks lying around...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ object ReadActor {
|
|||||||
if (actor is ActorWithBody && actor is HasAssembledSprite) {
|
if (actor is ActorWithBody && actor is HasAssembledSprite) {
|
||||||
actor.sprite = SpriteAnimation(actor)
|
actor.sprite = SpriteAnimation(actor)
|
||||||
if (actor.animDescPathGlow != null) actor.spriteGlow = SpriteAnimation(actor)
|
if (actor.animDescPathGlow != null) actor.spriteGlow = SpriteAnimation(actor)
|
||||||
actor.reassembleSprite(actor.sprite!!, actor.spriteGlow)
|
actor.reassembleSprite(actor.sprite ?: throw InternalError("actor.sprite (type: SpriteAnimation) is null"), actor.spriteGlow)
|
||||||
}
|
}
|
||||||
|
|
||||||
return actor
|
return actor
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user