From b1ca1a93514d1e31171f1927bb011dd67fd3dfd4 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 27 Jan 2024 03:21:26 +0900 Subject: [PATCH] glow/emissive for held items, even if the actor has no glow/emissive sprites --- .../sprites/fixtures/jukebox_emsv.tga | 2 +- .../metalworking_furnace_and_anvil_emsv.tga | 2 +- .../sprites/fixtures/smelter_basic_emsv.tga | 2 +- .../sprites/fixtures/smelter_tall_emsv.tga | 2 +- .../sprites/fixtures/tiki_torch_emsv.tga | 3 + .../basegame/sprites/taimu2_emsv.properties | 48 +++++++++++ .../test_werebeastf2/taimuglow_head.tga | 2 +- .../AssembledSpriteAnimation.kt | 39 +++++++-- .../spriteanimation/SpriteAnimation.kt | 6 +- .../terrarum/gameactors/ActorWithBody.kt | 18 ++-- .../torvald/terrarum/gameitems/GameItem.kt | 1 + .../terrarum/itemproperties/ItemCodex.kt | 34 ++++++++ .../gameactors/FixtureJukebox.kt | 19 ++++- .../modulebasegame/gameactors/IngamePlayer.kt | 3 +- .../gameactors/PlayerBuilder.kt | 2 +- .../gameactors/PlayerBuilderTestSubject1.kt | 17 ++-- .../gameactors/PlayerBuilderWerebeastTest.kt | 13 +-- .../gameitems/ItemFurnaceAndAnvil.kt | 2 + .../modulebasegame/gameitems/ItemJukebox.kt | 2 + .../gameitems/ItemSmelterBasic.kt | 2 + .../modulebasegame/serialise/WriteActor.kt | 60 ++++++++++++-- .../spriteassembler/AssembleSheetPixmap.kt | 47 +++++++---- .../spriteassembler/SpriteAssemblerApp.kt | 2 +- .../terrarum/tests/SpriteAssemblerTest.kt | 2 +- .../terrarum/worlddrawer/BlocksDrawer.kt | 39 ++++++--- .../terrarum/worlddrawer/CreateTileAtlas.kt | 82 ++++++++++++------- 26 files changed, 345 insertions(+), 106 deletions(-) create mode 100644 assets/mods/basegame/sprites/fixtures/tiki_torch_emsv.tga create mode 100644 assets/mods/basegame/sprites/taimu2_emsv.properties diff --git a/assets/mods/basegame/sprites/fixtures/jukebox_emsv.tga b/assets/mods/basegame/sprites/fixtures/jukebox_emsv.tga index 60cc894a5..7e51c4d67 100644 --- a/assets/mods/basegame/sprites/fixtures/jukebox_emsv.tga +++ b/assets/mods/basegame/sprites/fixtures/jukebox_emsv.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e913314693452a82dee1ff8f27a2f1d8773d6ae9c55e7a785d97925f236f321 +oid sha256:01f522bcf34135a58065931f235b4ddd555b7d02f7e5bb22e474223b1c78b854 size 6162 diff --git a/assets/mods/basegame/sprites/fixtures/metalworking_furnace_and_anvil_emsv.tga b/assets/mods/basegame/sprites/fixtures/metalworking_furnace_and_anvil_emsv.tga index 6ce7067ba..35748fe35 100644 --- a/assets/mods/basegame/sprites/fixtures/metalworking_furnace_and_anvil_emsv.tga +++ b/assets/mods/basegame/sprites/fixtures/metalworking_furnace_and_anvil_emsv.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8700c6a2e3d5f9a09995058d4088090dfe7a64327f75d89599fc530daad05dda +oid sha256:fbf3a08da43caa3647c4434712bb0b670a37fe9394dabc44af1f335c6fe74ea1 size 6162 diff --git a/assets/mods/basegame/sprites/fixtures/smelter_basic_emsv.tga b/assets/mods/basegame/sprites/fixtures/smelter_basic_emsv.tga index 2360c6004..2c136bc16 100644 --- a/assets/mods/basegame/sprites/fixtures/smelter_basic_emsv.tga +++ b/assets/mods/basegame/sprites/fixtures/smelter_basic_emsv.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e51232acb5fbe5f13aa73e1bace1e528653df28fba00b320bd1c40134e95e103 +oid sha256:2e3444efdee0f3728964d52651a8b28866cb24401629905db71fc6aa8b656c23 size 4114 diff --git a/assets/mods/basegame/sprites/fixtures/smelter_tall_emsv.tga b/assets/mods/basegame/sprites/fixtures/smelter_tall_emsv.tga index 58ac9d0ff..6e6674a35 100644 --- a/assets/mods/basegame/sprites/fixtures/smelter_tall_emsv.tga +++ b/assets/mods/basegame/sprites/fixtures/smelter_tall_emsv.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f035603054d9e70d57f7c8a2eae3aec11b5e32d618bee188ca8f7c7ebde1ca68 +oid sha256:0128ce2cada196e62959580aded29661487fd7a7d8dd4c15dfaa6d2044b6b638 size 12306 diff --git a/assets/mods/basegame/sprites/fixtures/tiki_torch_emsv.tga b/assets/mods/basegame/sprites/fixtures/tiki_torch_emsv.tga new file mode 100644 index 000000000..e3ffbaf2d --- /dev/null +++ b/assets/mods/basegame/sprites/fixtures/tiki_torch_emsv.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d41b74905d64ce0bdee5d5109f8bd15a6119745137e5481052367e440ea08b2 +size 4114 diff --git a/assets/mods/basegame/sprites/taimu2_emsv.properties b/assets/mods/basegame/sprites/taimu2_emsv.properties new file mode 100644 index 000000000..00bff47c0 --- /dev/null +++ b/assets/mods/basegame/sprites/taimu2_emsv.properties @@ -0,0 +1,48 @@ +# complete file name is: SPRITESHEET + bodypart name + EXTENSION +SPRITESHEET=mods/basegame/sprites/test_werebeastf2/taimuemsv_ +EXTENSION=.tga +# defines frame size and origin point. Origin point is given as: (originx, 0) +CONFIG=SIZE 64,98;ORIGINX 40 + +! 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 +! 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. +! Some keywords are considered special within the game, they are: +! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero) +BODYPARTS=HEADGEAR 13,14;\ + HEAD 13,14;\ + ARM_REST_RIGHT 10,4;\ + ARM_REST_LEFT 9,3;\ + LEG_REST_RIGHT 15,6;\ + LEG_REST_LEFT 8,6;\ + TORSO_0 18,19;\ + TORSO_1 18,19;\ + TAIL_0 30,2;\ + BUST_0 11,2;\ + HELD_ITEM 0,0 +SKELETON_STAND=HEADGEAR 0,78;\ + ARM_REST_RIGHT -16,66;\ + HELD_ITEM -11,33;\ + HEAD 0,78;\ + BUST_0 0,63;\ + LEG_REST_RIGHT -5,41;\ + TORSO_0 0,54;\ + TORSO_1 0,54;\ + LEG_REST_LEFT 3,41;\ + ARM_REST_LEFT 8,66;\ + TAIL_0 2,40 + +! When you move the arms/hands, make sure you move the HELD_ITEM as well + +# RUNNING might need its own skeleton... +ANIM_RUN=DELAY 0.18;ROW 2;SKELETON SKELETON_STAND +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;TORSO_1 0,-999 +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;TORSO_1 0,-999 + +ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND +ANIM_IDLE_1=TORSO_1 0,-999 +ANIM_IDLE_2=TORSO_0 0,-999;ARM_REST_LEFT 0,1;ARM_REST_RIGHT 0,1;HELD_ITEM 0,1;BUST_0 0,1;HEAD 0,1 diff --git a/assets/mods/basegame/sprites/test_werebeastf2/taimuglow_head.tga b/assets/mods/basegame/sprites/test_werebeastf2/taimuglow_head.tga index 1243079ca..98026b899 100644 --- a/assets/mods/basegame/sprites/test_werebeastf2/taimuglow_head.tga +++ b/assets/mods/basegame/sprites/test_werebeastf2/taimuglow_head.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9927a3e97a5e1a13df1aae039d0a6e2a930cfcb8a60a018d257fbc725be2b31 +oid sha256:6487cb6c674f6ae307831b95a73019b2e4c7386d79112539f6903dfd8034af25 size 1866 diff --git a/src/net/torvald/spriteanimation/AssembledSpriteAnimation.kt b/src/net/torvald/spriteanimation/AssembledSpriteAnimation.kt index 0eb5373d4..dd0c72787 100644 --- a/src/net/torvald/spriteanimation/AssembledSpriteAnimation.kt +++ b/src/net/torvald/spriteanimation/AssembledSpriteAnimation.kt @@ -1,5 +1,6 @@ package net.torvald.spriteanimation +import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.g2d.SpriteBatch @@ -31,10 +32,11 @@ class AssembledSpriteAnimation( parentActor: ActorWithBody, @Transient val disk: SimpleFileSystem?, // specify if the resources for the animation is contained in the disk archive @Transient val bodypartToFileMap: EntryID?, // which file in the disk contains bodypart-to-fileid mapping for this particular instance of sprite animation - @Transient val isGlow: Boolean + @Transient val isGlow: Boolean, + @Transient val isEmissive: Boolean ) : SpriteAnimation(parentActor) { - constructor(adp: ADProperties, parentActor: ActorWithBody, isGlow: Boolean) : this(adp, parentActor, null, null, isGlow) + constructor(adp: ADProperties, parentActor: ActorWithBody, isGlow: Boolean, isEmissive: Boolean) : this(adp, parentActor, null, null, isGlow, isEmissive) var currentFrame = 0 // while this number is zero-based, the frame number on the ADP is one-based private set @@ -112,9 +114,23 @@ class AssembledSpriteAnimation( } } - private fun fetchItemImage(item: GameItem) = if (isGlow) ItemCodex.getItemImageGlow(item) else ItemCodex.getItemImage(item) + private fun fetchItemImage(item: GameItem) = if (isEmissive) + ItemCodex.getItemImageEmissive(item) + else if (isGlow) + ItemCodex.getItemImageGlow(item) + else + ItemCodex.getItemImage(item) + + private fun fetchItemImage(mode: Int, item: GameItem) = when (mode) { + 0 -> ItemCodex.getItemImage(item) + 1 -> ItemCodex.getItemImageGlow(item) + 2 -> ItemCodex.getItemImageEmissive(item) + else -> throw IllegalArgumentException() + } + + fun renderThisAnimation(batch: SpriteBatch, posX: Float, posY: Float, scale: Float, animName: String, mode: Int = 0) { + val oldBatchColour = batch.color.cpy() - fun renderThisAnimation(batch: SpriteBatch, posX: Float, posY: Float, scale: Float, animName: String) { val animNameRoot = animName.substring(0, animName.indexOfLast { it == '_' }).ifBlank { return@renderThisAnimation } // quick fix for the temporary de-sync bug in which when the update-rate per frame is much greater than once, it attempts to load animation with blank name @@ -138,8 +154,9 @@ class AssembledSpriteAnimation( // draw held items/armours? if (name in jointNameToEquipPos) { + batch.color = if (mode > 0) Color.WHITE else oldBatchColour ItemCodex[(parentActor as? Pocketed)?.inventory?.itemEquipped?.get(jointNameToEquipPos[name]!!)]?.let { item -> - fetchItemImage(item)?.let { image -> + fetchItemImage(mode, item)?.let { image -> val drawPos = adp.origin + bodypartPos // imgCentre for held items are (0,0) val w = image.regionWidth * scale val h = image.regionHeight * scale @@ -159,6 +176,7 @@ class AssembledSpriteAnimation( } } else { + batch.color = oldBatchColour res[name]?.let { image -> var imgCentre = bodypartOrigins[name]!! if (flipVertical) imgCentre = imgCentre.invertY() @@ -185,10 +203,15 @@ class AssembledSpriteAnimation( } ?: throw NullPointerException("Animation with name '$animNameRoot' is not found") } - override fun render(frameDelta: Float, batch: SpriteBatch, posX: Float, posY: Float, scale: Float) { + /** + * Held items will ignore forcedColourFilter if mode > 0 + * + * @param mode specifies the mode for drawing the held item. 0=diffuse, 1=glow, 2=emissive + */ + override fun render(frameDelta: Float, batch: SpriteBatch, posX: Float, posY: Float, scale: Float, mode: Int, forcedColourFilter: Color?) { if (parentActor.isVisible) { - batch.color = colourFilter - renderThisAnimation(batch, posX, posY, scale, "${currentAnimation}_${1+currentFrame}") + batch.color = forcedColourFilter ?: colourFilter + renderThisAnimation(batch, posX, posY, scale, "${currentAnimation}_${1+currentFrame}", mode) } } diff --git a/src/net/torvald/spriteanimation/SpriteAnimation.kt b/src/net/torvald/spriteanimation/SpriteAnimation.kt index 65a66b474..ca1bb7edf 100644 --- a/src/net/torvald/spriteanimation/SpriteAnimation.kt +++ b/src/net/torvald/spriteanimation/SpriteAnimation.kt @@ -16,7 +16,7 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack abstract class SpriteAnimation(@Transient val parentActor: ActorWithBody) : Disposable { protected abstract val currentDelay: Second abstract fun update(delta: Float) - abstract fun render(frameDelta: Float, batch: SpriteBatch, posX: Float, posY: Float, scale: Float = 1f) + abstract fun render(frameDelta: Float, batch: SpriteBatch, posX: Float, posY: Float, scale: Float = 1f, mode: Int = 0, forcedColourFilter: Color? = null) var flipHorizontal = false var flipVertical = false @@ -143,14 +143,14 @@ class SheetSpriteAnimation(parentActor: ActorWithBody) : SpriteAnimation(parentA * * * @param scale */ - override fun render(frameDelta: Float, batch: SpriteBatch, posX: Float, posY: Float, scale: Float) { + override fun render(frameDelta: Float, batch: SpriteBatch, posX: Float, posY: Float, scale: Float, mode: Int, forcedColourFilter: Color?) { assert(cellWidth > 0 || cellHeight > 0) { "Sprite width or height is set to zero! ($cellWidth, $cellHeight); master: $parentActor" } if (visible) { val region = textureRegion.get(currentFrame, currentRow) - batch.color = colourFilter + batch.color = forcedColourFilter ?: colourFilter val tx = (parentActor.hitboxTranslateX) * scale val txF = (parentActor.hitboxTranslateX + parentActor.baseHitboxW) * scale diff --git a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt index 6e44dcae6..21054f422 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt @@ -1793,16 +1793,22 @@ open class ActorWithBody : Actor { } open fun drawGlow(frameDelta: Float, batch: SpriteBatch) { - if (isVisible && spriteGlow != null) { + if (isVisible) { blendNormalStraightAlpha(batch) - drawSpriteInGoodPosition(frameDelta, spriteGlow!!, batch) + if (spriteGlow != null) + drawSpriteInGoodPosition(frameDelta, spriteGlow!!, batch, 2) + else + drawSpriteInGoodPosition(frameDelta, sprite!!, batch, 1, Color.BLACK) } } open fun drawEmissive(frameDelta: Float, batch: SpriteBatch) { - if (isVisible && spriteEmissive != null) { + if (isVisible) { blendNormalStraightAlpha(batch) - drawSpriteInGoodPosition(frameDelta, spriteEmissive!!, batch) + if (spriteEmissive != null) + drawSpriteInGoodPosition(frameDelta, spriteEmissive!!, batch, 1) + else + drawSpriteInGoodPosition(frameDelta, sprite!!, batch, 2, Color.BLACK) } } @@ -1830,7 +1836,7 @@ open class ActorWithBody : Actor { } } - protected fun drawSpriteInGoodPosition(frameDelta: Float, sprite: SpriteAnimation, batch: SpriteBatch) { + protected fun drawSpriteInGoodPosition(frameDelta: Float, sprite: SpriteAnimation, batch: SpriteBatch, mode: Int = 0, forcedColourFilter: Color? = null) { if (world == null) return val offsetX = 0f @@ -1840,7 +1846,7 @@ open class ActorWithBody : Actor { val posY = hitbox.startY.plus(PHYS_EPSILON_DIST).toFloat() drawBodyInGoodPosition(posX, posY) { x, y -> - sprite.render(frameDelta, batch, x + offsetX, y + offsetY, scale.toFloat()) + sprite.render(frameDelta, batch, x + offsetX, y + offsetY, scale.toFloat(), mode, forcedColourFilter) } } diff --git a/src/net/torvald/terrarum/gameitems/GameItem.kt b/src/net/torvald/terrarum/gameitems/GameItem.kt index e556e418c..cd81a2e0b 100644 --- a/src/net/torvald/terrarum/gameitems/GameItem.kt +++ b/src/net/torvald/terrarum/gameitems/GameItem.kt @@ -137,6 +137,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl */ @Transient open val itemImage: TextureRegion? = null @Transient open val itemImageGlow: TextureRegion? = null + @Transient open val itemImageEmissive: TextureRegion? = null /** * Apparent mass of the item. (basemass * scale^3) diff --git a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt index 61e5824ae..51de7b146 100644 --- a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt +++ b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt @@ -135,6 +135,11 @@ class ItemCodex { return getItemImageGlow(item.originalID) } + fun getItemImageEmissive(item: GameItem?): TextureRegion? { + if (item == null) return null + return getItemImageEmissive(item.originalID) + } + fun getItemImage(itemID: ItemID?): TextureRegion? { if (itemID == null) return null @@ -193,6 +198,35 @@ class ItemCodex { } } + fun getItemImageEmissive(itemID: ItemID?): TextureRegion? { + if (itemID == null) return null + + if (itemID.isDynamic()) { + return getItemImageEmissive(dynamicToStaticID(itemID)) + } + else if (itemID.isItem()) { + return itemCodex[itemID]?.itemImageEmissive + } + else if (itemID.isWire()) { + return itemCodex[itemID]?.itemImageEmissive + } + else if (itemID.isWall()) { + val itemSheetNumber = App.tileMaker.tileIDtoItemSheetNumber(itemID.substring(5)) + return BlocksDrawer.tileItemWallEmissive.get( + itemSheetNumber % App.tileMaker.TILES_IN_X, + itemSheetNumber / App.tileMaker.TILES_IN_X + ) + } + // else: terrain + else { + val itemSheetNumber = App.tileMaker.tileIDtoItemSheetNumber(itemID) + return BlocksDrawer.tileItemTerrainEmissive.get( + itemSheetNumber % App.tileMaker.TILES_IN_X, + itemSheetNumber / App.tileMaker.TILES_IN_X + ) + } + } + fun hasItem(itemID: ItemID): Boolean = dynamicItemInventory.containsKey(itemID) fun isEmpty(): Boolean = itemCodex.isEmpty() } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt index 8fb01fcc1..1f6ec0f7c 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt @@ -53,6 +53,7 @@ class FixtureJukebox : Electric, PlaysMusic { (mainUI as UIJukebox).parent = this val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/jukebox.tga") + val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/jukebox_emsv.tga") density = 1400.0 setHitboxDimension(TILE_SIZE * 2, TILE_SIZE * 3, 0, 0) @@ -60,6 +61,9 @@ class FixtureJukebox : Electric, PlaysMusic { makeNewSprite(TextureRegionPack(itemImage.texture, TILE_SIZE * 2, TILE_SIZE * 3)).let { it.setRowsAndFrames(1,1) } + makeNewSpriteEmissive(TextureRegionPack(itemImage2.texture, TILE_SIZE * 2, TILE_SIZE * 3)).let { + it.setRowsAndFrames(1,1) + } actorValue[AVKey.BASEMASS] = 200.0 @@ -130,6 +134,7 @@ class FixtureJukebox : Electric, PlaysMusic { } @Transient private var lampDecay = 0f + @Transient private var lampIntensity = 0f /** * Try to stop the disc being played, and reset the background music cue @@ -146,15 +151,27 @@ class FixtureJukebox : Electric, PlaysMusic { if (isVisible && musicNowPlaying != null) { val vol0 = (musicTracks[musicNowPlaying]?.processor?.maxSigLevel?.average() ?: 0.0).toFloat() val vol = FastMath.interpolateLinear(0.8f, vol0, lampDecay) + lampIntensity = vol.coerceIn(0f, 1f) blendScreen(batch) - backLamp.colourFilter = Color(0f, vol.coerceIn(0f, 1f), 0f, 1f) + backLamp.colourFilter = Color(0f, lampIntensity, 0f, 1f) drawSpriteInGoodPosition(frameDelta, backLamp, batch) lampDecay = vol } } + override fun drawEmissive(frameDelta: Float, batch: SpriteBatch) { + blendNormalStraightAlpha(batch) + super.drawEmissive(frameDelta, batch) + + if (isVisible && musicNowPlaying != null) { + blendScreen(batch) + backLamp.colourFilter = Color(0f, lampIntensity / 2f, 0f, 1f) + drawSpriteInGoodPosition(frameDelta, backLamp, batch) + } + } + private fun stopDiscPlayback() { musicNowPlaying?.let { stopAudio(it) diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt index 88845bc71..1de094df8 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt @@ -45,9 +45,10 @@ class IngamePlayer : ActorHumanoid, HasAssembledSprite, NoSerialise { private constructor() - constructor(animDescPath: String, animDescPathGlow: String?, born: Long) : super(born) { + constructor(animDescPath: String, animDescPathGlow: String?, animDescPathEmissive: String?, born: Long) : super(born) { animDesc = ADProperties(Gdx.files.internal(animDescPath)) if (animDescPathGlow != null) animDescGlow = ADProperties(Gdx.files.internal(animDescPathGlow)) + if (animDescPathEmissive != null) animDescEmissive = ADProperties(Gdx.files.internal(animDescPathEmissive)) actorValue[AVKey.__HISTORICAL_BORNTIME] = born } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilder.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilder.kt index dacf7f549..1f2ba2c8e 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilder.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilder.kt @@ -13,7 +13,7 @@ object PlayerBuilder { operator fun invoke(): Actor { val world = (Terrarum.ingame!! as TerrarumIngame).world - val p: Actor = IngamePlayer("lol", "lol_glow", world.worldTime.TIME_T) + val p: Actor = IngamePlayer("lol", "lol_glow", "lol_emsv", world.worldTime.TIME_T) InjectCreatureRaw(p.actorValue, "basegame", "CreaturePlayer.json") // attach sprite diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt index 62d0af2ad..f23b831bd 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt @@ -10,9 +10,10 @@ import net.torvald.terrarum.gameactors.AVKey object PlayerBuilderTestSubject1 { operator fun invoke(): IngamePlayer { val p: IngamePlayer = IngamePlayer( - ModMgr.getGdxFile("basegame", "sprites/test_sprite.properties").path(), - ModMgr.getGdxFile("basegame", "sprites/test_sprite_glow.properties").path(), - -589141658L // random value thrown + ModMgr.getGdxFile("basegame", "sprites/test_sprite.properties").path(), + ModMgr.getGdxFile("basegame", "sprites/test_sprite_glow.properties").path(), + ModMgr.getGdxFile("basegame", "sprites/test_sprite_emsv.properties").path(), + 0L // random value thrown ) InjectCreatureRaw(p.actorValue, "basegame", "CreaturePlayer.json") @@ -23,13 +24,11 @@ object PlayerBuilderTestSubject1 { p.actorValue[AVKey.NAME] = "Test Subject 1" - /*p.makeNewSprite(TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/npc_template_anim_prototype.tga"), 48, 52)) - p.sprite!!.delays = floatArrayOf(2f, 1f/12f) // second value does nothing -- overridden by ActorHumanoid.updateSprite(float) - p.sprite!!.setRowsAndFrames(2, 4)*/ + // TODO make null animation if animDesc is null + p.animDesc?.let { p.sprite = AssembledSpriteAnimation(it, p, false, false) } + p.animDescGlow?.let { p.spriteGlow = AssembledSpriteAnimation(it, p, true, false) } + p.animDescEmissive?.let { p.spriteEmissive = AssembledSpriteAnimation(it, p, true, true) } - p.animDesc?.let { p.sprite = AssembledSpriteAnimation(it, p, false) } - p.animDescGlow?.let { p.spriteGlow = AssembledSpriteAnimation(it, p, true) } - //p.reassembleSprite(p.sprite, p.spriteGlow, null) p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT) ?: ActorHumanoid.BASE_HEIGHT, 21, 0) // ingame must teleport the player to the spawn point diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderWerebeastTest.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderWerebeastTest.kt index b95c5252a..3ed18a2e5 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderWerebeastTest.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderWerebeastTest.kt @@ -12,9 +12,10 @@ import net.torvald.terrarum.gameactors.AVKey object PlayerBuilderWerebeastTest { operator fun invoke(): IngamePlayer { val p: IngamePlayer = IngamePlayer( - ModMgr.getGdxFile("basegame", "sprites/taimu2.properties").path(), - ModMgr.getGdxFile("basegame", "sprites/taimu2_glow.properties").path(), - -589141658L // random value thrown + ModMgr.getGdxFile("basegame", "sprites/taimu2.properties").path(), + ModMgr.getGdxFile("basegame", "sprites/taimu2_glow.properties").path(), + ModMgr.getGdxFile("basegame", "sprites/taimu2_emsv.properties").path(), + -589141658L // random value thrown ) InjectCreatureRaw(p.actorValue, "basegame", "CreatureWerebeastBossBase.json") @@ -24,9 +25,9 @@ object PlayerBuilderWerebeastTest { p.actorValue[AVKey.ACTION_INTERVAL] = ActorHumanoid.BASE_ACTION_INTERVAL p.actorValue[AVKey.NAME] = "Taimu" - p.animDesc?.let { p.sprite = AssembledSpriteAnimation(it, p, false) } - p.animDescGlow?.let { p.spriteGlow = AssembledSpriteAnimation(it, p, true) } - p.animDescEmissive?.let { p.spriteEmissive = AssembledSpriteAnimation(it, p, true) } + p.animDesc?.let { p.sprite = AssembledSpriteAnimation(it, p, false, false) } + p.animDescGlow?.let { p.spriteGlow = AssembledSpriteAnimation(it, p, true, false) } + p.animDescEmissive?.let { p.spriteEmissive = AssembledSpriteAnimation(it, p, false, true) } p.setHitboxDimension(22, p.actorValue.getAsInt(AVKey.BASEHEIGHT)!!, 30, 0) p.setPosition(3.0 * TILE_SIZE, 3.0 * TILE_SIZE) diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemFurnaceAndAnvil.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemFurnaceAndAnvil.kt index 0dae70214..56e8f2f9b 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemFurnaceAndAnvil.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemFurnaceAndAnvil.kt @@ -14,6 +14,8 @@ class ItemFurnaceAndAnvil(originalID: ItemID) : FixtureItemBase(originalID, "net override val materialId = "" override val itemImage: TextureRegion get() = getItemImageFromSingleImage("basegame", "sprites/fixtures/metalworking_furnace_and_anvil.tga") + override val itemImageEmissive: TextureRegion + get() = getItemImageFromSingleImage("basegame", "sprites/fixtures/metalworking_furnace_and_anvil_emsv.tga") override var baseToolSize: Double? = baseMass override var originalName = "ITEM_FURNACE_AND_ANVIL" diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemJukebox.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemJukebox.kt index ffc14f72f..561ec5a01 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemJukebox.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemJukebox.kt @@ -14,6 +14,8 @@ class ItemJukebox(originalID: ItemID) : FixtureItemBase(originalID, "net.torvald override val materialId = "" override val itemImage: TextureRegion get() = getItemImageFromSingleImage("basegame", "sprites/fixtures/jukebox.tga") + override val itemImageEmissive: TextureRegion + get() = getItemImageFromSingleImage("basegame", "sprites/fixtures/jukebox_emsv.tga") override var baseToolSize: Double? = baseMass override var originalName = "ITEM_JUKEBOX" diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemSmelterBasic.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemSmelterBasic.kt index ba5933e42..41c6be570 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemSmelterBasic.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemSmelterBasic.kt @@ -14,6 +14,8 @@ class ItemSmelterBasic(originalID: ItemID) : FixtureItemBase(originalID, "net.to override val materialId = "" override val itemImage: TextureRegion get() = getItemImageFromSingleImage("basegame", "sprites/fixtures/smelter_tall.tga") + override val itemImageEmissive: TextureRegion + get() = getItemImageFromSingleImage("basegame", "sprites/fixtures/smelter_tall_emsv.tga") override var baseToolSize: Double? = baseMass override var originalName = "ITEM_SMELTER_SMALL" diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/WriteActor.kt b/src/net/torvald/terrarum/modulebasegame/serialise/WriteActor.kt index 9383bf1c9..aaf85ad84 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/WriteActor.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/WriteActor.kt @@ -180,8 +180,9 @@ object ReadActor { actor, if (bodypartsFile != null) disk else null, if (bodypartsFile != null) BODYPART_TO_ENTRY_MAP else null, - false + false, false ) + if (animFileGlow != null) { actor.animDescGlow = ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET)) actor.spriteGlow = AssembledSpriteAnimation( @@ -189,9 +190,10 @@ object ReadActor { actor, if (bodypartsFile != null) disk else null, if (bodypartsFile != null) BODYPARTGLOW_TO_ENTRY_MAP else null, - true + true, false ) } + if (animFileEmissive != null) { actor.animDescEmissive = ADProperties(ByteArray64Reader(animFileEmissive.bytes, Common.CHARSET)) actor.spriteEmissive = AssembledSpriteAnimation( @@ -199,7 +201,7 @@ object ReadActor { actor, if (bodypartsFile != null) disk else null, if (bodypartsFile != null) BODYPARTEMISSIVE_TO_ENTRY_MAP else null, - true + false, true ) } @@ -213,12 +215,58 @@ object ReadActor { actor.reassembleSprite(actor.sprite!!, actor.spriteGlow, heldItem)*/ } else if (actor is ActorWithBody && actor is HasAssembledSprite) { - if (actor.animDesc != null) actor.sprite = AssembledSpriteAnimation(actor.animDesc!!, actor, false) - if (actor.animDescGlow != null) actor.spriteGlow = AssembledSpriteAnimation(actor.animDescGlow!!, actor, true) - if (actor.animDescEmissive != null) actor.spriteEmissive = AssembledSpriteAnimation(actor.animDescEmissive!!, actor, true) + if (actor.animDesc != null) actor.sprite = AssembledSpriteAnimation(actor.animDesc!!, actor, false, false) + if (actor.animDescGlow != null) actor.spriteGlow = AssembledSpriteAnimation(actor.animDescGlow!!, actor, true, false) + if (actor.animDescEmissive != null) actor.spriteEmissive = AssembledSpriteAnimation(actor.animDescEmissive!!, actor, false, true) //actor.reassembleSprite(actor.sprite, actor.spriteGlow, null) } } + private fun makeSprite(mode: Int, actor: IngamePlayer, disk: SimpleFileSystem, file: EntryFile?, bodypartsFile: EntryFile?) { + val animDesc = when (mode) { + 0 -> actor.animDesc + 1 -> actor.animDescGlow + 2 -> actor.animDescEmissive + else -> throw IllegalArgumentException() + } + + if (file != null) { + when (mode) { + 0 -> { actor.animDesc = ADProperties(ByteArray64Reader(file.bytes, Common.CHARSET)) } + 1 -> { actor.animDescGlow = ADProperties(ByteArray64Reader(file.bytes, Common.CHARSET)) } + 2 -> { actor.animDescEmissive = ADProperties(ByteArray64Reader(file.bytes, Common.CHARSET)) } + else -> throw IllegalArgumentException() + } + + when (mode) { + 0 -> { actor.sprite = AssembledSpriteAnimation( + actor.animDesc!!, + actor, + if (bodypartsFile != null) disk else null, + if (bodypartsFile != null) BODYPART_TO_ENTRY_MAP else null, + false, false + ) } + 1 -> { actor.spriteGlow = AssembledSpriteAnimation( + actor.animDescGlow!!, + actor, + if (bodypartsFile != null) disk else null, + if (bodypartsFile != null) BODYPARTGLOW_TO_ENTRY_MAP else null, + true, false + ) } + 2 -> { actor.spriteEmissive = AssembledSpriteAnimation( + actor.animDescEmissive!!, + actor, + if (bodypartsFile != null) disk else null, + if (bodypartsFile != null) BODYPARTEMISSIVE_TO_ENTRY_MAP else null, + false, true + ) } + else -> throw IllegalArgumentException() + } + + } + else { + + } + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/spriteassembler/AssembleSheetPixmap.kt b/src/net/torvald/terrarum/spriteassembler/AssembleSheetPixmap.kt index 7895225c0..6ec882a1a 100644 --- a/src/net/torvald/terrarum/spriteassembler/AssembleSheetPixmap.kt +++ b/src/net/torvald/terrarum/spriteassembler/AssembleSheetPixmap.kt @@ -51,25 +51,26 @@ object AssembleSheetPixmap { } - private fun drawAndGetCanvas(properties: ADProperties, fileGetter: (String) -> InputStream?, injectedItem: GameItem?): Pixmap { + private fun drawAndGetCanvas(properties: ADProperties, fileGetter: (String) -> InputStream?, injectedItem: GameItem?, layerMode: Int): Pixmap { val canvas = Pixmap(properties.cols * (properties.frameWidth), properties.rows * (properties.frameHeight), Pixmap.Format.RGBA8888) canvas.blending = Pixmap.Blending.SourceOver // actually draw properties.transforms.forEach { (t, _) -> - drawThisFrame(t, canvas, properties, fileGetter, injectedItem) + drawThisFrame(t, canvas, properties, fileGetter, injectedItem, layerMode) } return canvas } - fun fromAssetsDir(properties: ADProperties, injectedItem: GameItem?) = drawAndGetCanvas(properties, getAssetsDirFileGetter(properties), injectedItem) + fun fromAssetsDir(properties: ADProperties, injectedItem: GameItem?, layerMode: Int) = + drawAndGetCanvas(properties, getAssetsDirFileGetter(properties), injectedItem, layerMode) - fun fromVirtualDisk(disk: SimpleFileSystem, entrynum: Long, properties: ADProperties, injectedItem: GameItem?): Pixmap { + fun fromVirtualDisk(disk: SimpleFileSystem, entrynum: Long, properties: ADProperties, injectedItem: GameItem?, layerMode: Int): Pixmap { val bodypartMapping = Properties() bodypartMapping.load(ByteArray64Reader(disk.getFile(entrynum)!!.bytes, Common.CHARSET)) - return drawAndGetCanvas(properties, getVirtualDiskFileGetter(bodypartMapping, disk), injectedItem) + return drawAndGetCanvas(properties, getVirtualDiskFileGetter(bodypartMapping, disk), injectedItem, layerMode) } fun getPartPixmap(getFile: (String) -> InputStream?, partName: String): Pixmap? { @@ -133,10 +134,11 @@ object AssembleSheetPixmap { } fun drawThisFrame(frameName: String, - canvas: Pixmap, - properties: ADProperties, - fileGetter: (String) -> InputStream?, - injectedItem: GameItem? + canvas: Pixmap, + properties: ADProperties, + fileGetter: (String) -> InputStream?, + injectedItem: GameItem?, + layerMode: Int ) { val theAnim = properties.getAnimByFrameName(frameName) val skeleton = theAnim.skeleton.joints.reversed() @@ -163,18 +165,29 @@ object AssembleSheetPixmap { // AppLoader.printdbg(this, "Frame to draw: $frameName (R$animRow C$animFrame)") - drawFrame(animRow, animFrame, canvas, properties, bodypartOrigins, bodypartImages, transformList, injectedItem) + drawFrame(animRow, animFrame, canvas, properties, bodypartOrigins, bodypartImages, transformList, injectedItem, layerMode) bodypartImages.values.forEach { it?.dispose() } } + private fun getItemImage(layerMode: Int, injectedItem: GameItem?): TextureRegion? { + return when (layerMode) { + 0 -> ItemCodex.getItemImage(injectedItem) + 1 -> ItemCodex.getItemImageGlow(injectedItem) + 2 -> ItemCodex.getItemImageEmissive(injectedItem) + else -> throw IllegalArgumentException() + } + } + + fun drawFrame(row: Int, column: Int, - canvas: Pixmap, - props: ADProperties, - bodypartOrigins: HashMap, - bodypartImages: Map, - transformList: List>, - injectedItem: GameItem? + canvas: Pixmap, + props: ADProperties, + bodypartOrigins: HashMap, + bodypartImages: Map, + transformList: List>, + injectedItem: GameItem?, + layerMode: Int ) { val tmpFrame = Pixmap(props.frameWidth, props.frameHeight, Pixmap.Format.RGBA8888) @@ -182,7 +195,7 @@ object AssembleSheetPixmap { if (name == "HELD_ITEM" && injectedItem != null) { // printdbg(this, "ID of the held item: ${injectedItem.originalID}") - ItemCodex.getItemImage(injectedItem)?.let { textureRegion -> + getItemImage(layerMode, injectedItem)?.let { textureRegion -> // printdbg(this, "and it did have a textureregion") val texdata = textureRegion.texture.textureData diff --git a/src/net/torvald/terrarum/spriteassembler/SpriteAssemblerApp.kt b/src/net/torvald/terrarum/spriteassembler/SpriteAssemblerApp.kt index c5ffc8a06..bea955a5a 100644 --- a/src/net/torvald/terrarum/spriteassembler/SpriteAssemblerApp.kt +++ b/src/net/torvald/terrarum/spriteassembler/SpriteAssemblerApp.kt @@ -299,7 +299,7 @@ class SpriteAssemblerPreview: Game() { } private fun assembleImage(prop: ADProperties) { - image = AssembleSheetPixmap.fromAssetsDir(prop, null) + image = AssembleSheetPixmap.fromAssetsDir(prop, null, 0) } // TODO rename to requestAssembly diff --git a/src/net/torvald/terrarum/tests/SpriteAssemblerTest.kt b/src/net/torvald/terrarum/tests/SpriteAssemblerTest.kt index 4ccb9a76c..52ba9e001 100644 --- a/src/net/torvald/terrarum/tests/SpriteAssemblerTest.kt +++ b/src/net/torvald/terrarum/tests/SpriteAssemblerTest.kt @@ -11,7 +11,7 @@ class SpriteAssemblerTest { operator fun invoke() { val properties = ADProperties(StringReader(ADLParsingTest().TEST_STR)) - AssembleSheetPixmap.fromAssetsDir(properties, null) + AssembleSheetPixmap.fromAssetsDir(properties, null, 0) } } diff --git a/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt b/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt index 230d9b146..0e7d8ae80 100644 --- a/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt +++ b/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt @@ -53,10 +53,13 @@ internal object BlocksDrawer { //val tilesWire: TextureRegionPack val tileItemTerrain: TextureRegionPack val tileItemTerrainGlow: TextureRegionPack + val tileItemTerrainEmissive: TextureRegionPack val tileItemWall: TextureRegionPack val tileItemWallGlow: TextureRegionPack + val tileItemWallEmissive: TextureRegionPack val tilesFluid: TextureRegionPack val tilesGlow: TextureRegionPack + val tilesEmissive: TextureRegionPack //val tileItemWall = Image(TILE_SIZE * 16, TILE_SIZE * GameWorld.TILES_SUPPORTED / 16) // 4 MB @@ -119,6 +122,7 @@ internal object BlocksDrawer { //tilesWire = TextureRegionPack(ModMgr.getGdxFile("basegame", "wires/wire.tga"), TILE_SIZE, TILE_SIZE) tilesFluid = TextureRegionPack(Texture(App.tileMaker.atlasFluid), TILE_SIZE, TILE_SIZE) tilesGlow = TextureRegionPack(Texture(App.tileMaker.atlasGlow), TILE_SIZE, TILE_SIZE) + tilesEmissive = TextureRegionPack(Texture(App.tileMaker.atlasEmissive), TILE_SIZE, TILE_SIZE) printdbg(this, "Making terrain and wall item textures...") @@ -129,8 +133,10 @@ internal object BlocksDrawer { tileItemTerrain = TextureRegionPack(App.tileMaker.itemTerrainTexture, TILE_SIZE, TILE_SIZE) tileItemTerrainGlow = TextureRegionPack(App.tileMaker.itemTerrainTextureGlow, TILE_SIZE, TILE_SIZE) + tileItemTerrainEmissive = TextureRegionPack(App.tileMaker.itemTerrainTextureEmissive, TILE_SIZE, TILE_SIZE) tileItemWall = TextureRegionPack(App.tileMaker.itemWallTexture, TILE_SIZE, TILE_SIZE) tileItemWallGlow = TextureRegionPack(App.tileMaker.itemWallTextureGlow, TILE_SIZE, TILE_SIZE) + tileItemWallEmissive = TextureRegionPack(App.tileMaker.itemWallTextureEmissive, TILE_SIZE, TILE_SIZE) // val texdata = tileItemTerrain.texture.textureData @@ -217,28 +223,28 @@ internal object BlocksDrawer { } } - internal fun drawWall(projectionMatrix: Matrix4, drawGlow: Boolean, drawBlack: Boolean = false) { + internal fun drawWall(projectionMatrix: Matrix4, drawGlow: Boolean, drawEmissive: Boolean = false) { gdxBlendNormalStraightAlpha() - renderUsingBuffer(WALL, projectionMatrix, drawGlow, drawBlack) + renderUsingBuffer(WALL, projectionMatrix, drawGlow, drawEmissive) gdxBlendMul() - renderUsingBuffer(OCCLUSION, projectionMatrix, false, drawBlack) + renderUsingBuffer(OCCLUSION, projectionMatrix, false, drawEmissive) } - internal fun drawTerrain(projectionMatrix: Matrix4, drawGlow: Boolean, drawBlack: Boolean = false) { + internal fun drawTerrain(projectionMatrix: Matrix4, drawGlow: Boolean, drawEmissive: Boolean = false) { gdxBlendNormalStraightAlpha() - renderUsingBuffer(TERRAIN, projectionMatrix, drawGlow, drawBlack) - renderUsingBuffer(ORES, projectionMatrix, drawGlow, drawBlack) - renderUsingBuffer(FLUID, projectionMatrix, drawGlow, drawBlack) + renderUsingBuffer(TERRAIN, projectionMatrix, drawGlow, drawEmissive) + renderUsingBuffer(ORES, projectionMatrix, drawGlow, drawEmissive) + renderUsingBuffer(FLUID, projectionMatrix, drawGlow, drawEmissive) } - internal fun drawFront(projectionMatrix: Matrix4, drawBlack: Boolean = false) { + internal fun drawFront(projectionMatrix: Matrix4, drawEmissive: Boolean = false) { gdxBlendMul() // let's just not MUL on terrain, make it FLUID only... - renderUsingBuffer(FLUID, projectionMatrix, false, drawBlack) + renderUsingBuffer(FLUID, projectionMatrix, false, drawEmissive) @@ -708,7 +714,7 @@ internal object BlocksDrawer { private var _tilesBufferAsTex: Texture = Texture(1, 1, Pixmap.Format.RGBA8888) private val occlusionIntensity = 0.22222222f // too low value and dark-coloured walls won't darken enough - private fun renderUsingBuffer(mode: Int, projectionMatrix: Matrix4, drawGlow: Boolean, drawBlack: Boolean) { + private fun renderUsingBuffer(mode: Int, projectionMatrix: Matrix4, drawGlow: Boolean, drawEmissive: Boolean) { //Gdx.gl.glClearColor(.094f, .094f, .094f, 0f) //Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) @@ -732,7 +738,7 @@ internal object BlocksDrawer { OCCLUSION -> occlusionBuffer else -> throw IllegalArgumentException() } - val vertexColour = if (drawBlack) Color.BLACK else when (mode) { + val vertexColour = when (mode) { TERRAIN, /*WIRE,*/ ORES, FLUID, OCCLUSION -> Color.WHITE WALL -> WALL_OVERLAY_COLOUR else -> throw IllegalArgumentException() @@ -754,7 +760,12 @@ internal object BlocksDrawer { _tilesBufferAsTex = Texture(tilesBuffer) _tilesBufferAsTex.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest) - if (drawGlow) { + if (drawEmissive) { + tilesEmissive.texture.bind(2) + _tilesBufferAsTex.bind(1) // trying 1 and 0... + tilesEmissive.texture.bind(0) // for some fuck reason, it must be bound as last + } + else if (drawGlow) { tilesGlow.texture.bind(2) _tilesBufferAsTex.bind(1) // trying 1 and 0... tilesGlow.texture.bind(0) // for some fuck reason, it must be bound as last @@ -880,11 +891,13 @@ internal object BlocksDrawer { weatherTerrains.forEach { it.dispose() } tilesGlow.dispose() - //tilesWire.dispose() + tilesEmissive.dispose() tileItemTerrain.dispose() tileItemTerrainGlow.dispose() + tileItemTerrainEmissive.dispose() tileItemWall.dispose() tileItemWallGlow.dispose() + tileItemWallEmissive.dispose() tilesFluid.dispose() tilesBuffer.dispose() _tilesBufferAsTex.dispose() diff --git a/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt b/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt index 88546aaf1..1b43a8567 100644 --- a/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt +++ b/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt @@ -11,13 +11,10 @@ import net.torvald.gdx.graphics.Cvec import net.torvald.terrarum.* import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE -import net.torvald.terrarum.blockproperties.Fluid import net.torvald.terrarum.gameitems.ItemID -import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.utils.HashArray import net.torvald.terrarum.worlddrawer.CreateTileAtlas.AtlasSource.* import net.torvald.terrarum.worlddrawer.CreateTileAtlas.RenderTag.Companion.MASK_47 -import kotlin.math.roundToInt import kotlin.math.sqrt /** @@ -51,10 +48,13 @@ class CreateTileAtlas { lateinit var atlasHibernal: Pixmap lateinit var atlasFluid: Pixmap lateinit var atlasGlow: Pixmap // glowing won't be affected by the season... for now + lateinit var atlasEmissive: Pixmap // glowing won't be affected by the season... for now lateinit var itemTerrainTexture: Texture lateinit var itemTerrainTextureGlow: Texture + lateinit var itemTerrainTextureEmissive: Texture lateinit var itemWallTexture: Texture lateinit var itemWallTextureGlow: Texture + lateinit var itemWallTextureEmissive: Texture lateinit var terrainTileColourMap: HashMap lateinit var tags: HashMap // TileID, RenderTag private set @@ -76,8 +76,10 @@ class CreateTileAtlas { internal lateinit var itemTerrainPixmap: Pixmap internal lateinit var itemTerrainPixmapGlow: Pixmap + internal lateinit var itemTerrainPixmapEmissive: Pixmap internal lateinit var itemWallPixmap: Pixmap internal lateinit var itemWallPixmapGlow: Pixmap + internal lateinit var itemWallPixmapEmissive: Pixmap val atlas: Pixmap get() = atlasVernal @@ -145,6 +147,7 @@ class CreateTileAtlas { atlasHibernal = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888).also { it.blending = Pixmap.Blending.None } atlasFluid = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888).also { it.blending = Pixmap.Blending.None } atlasGlow = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888).also { it.blending = Pixmap.Blending.None } + atlasEmissive = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888).also { it.blending = Pixmap.Blending.None } // populate the atlantes with atlasInit // this just directly copies the image to the atlantes :p @@ -203,7 +206,15 @@ class CreateTileAtlas { val glowFile = Gdx.files.internal( filehandle.path().dropLast(4) + "_glow.tga" ) // assuming strict ".tga" file for now... - fileToAtlantes(modname, filehandle, if (glowFile.exists()) glowFile else null, if (dirName == "blocks") null else dirName) + val emissiveFile = Gdx.files.internal( + filehandle.path().dropLast(4) + "_emsv.tga" + ) // assuming strict ".tga" file for now... + fileToAtlantes( + modname, filehandle, + if (glowFile.exists()) glowFile else null, + if (emissiveFile.exists()) emissiveFile else null, + if (dirName == "blocks") null else dirName + ) } catch (e: GdxRuntimeException) { System.err.println("Couldn't load file $filehandle from $modname, skipping...") @@ -240,8 +251,10 @@ class CreateTileAtlas { itemTerrainPixmap = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) itemTerrainPixmapGlow = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) + itemTerrainPixmapEmissive = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) itemWallPixmap = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) itemWallPixmapGlow = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) + itemWallPixmapEmissive = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) tags.toMap().forEach { id, tag -> val tilePosFromAtlas = tag.tileNumber + maskTypetoTileIDForItemImage(tag.maskType) @@ -252,8 +265,10 @@ class CreateTileAtlas { val destY = (t / TILES_IN_X) * TILE_SIZE itemTerrainPixmap.drawPixmap(atlas, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) itemTerrainPixmapGlow.drawPixmap(atlasGlow, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) + itemTerrainPixmapEmissive.drawPixmap(atlasEmissive, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) itemWallPixmap.drawPixmap(atlas, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) itemWallPixmapGlow.drawPixmap(atlasGlow, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) + itemWallPixmapEmissive.drawPixmap(atlasEmissive, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) } // darken things for the wall for (y in 0 until itemWallPixmap.height) { @@ -262,6 +277,8 @@ class CreateTileAtlas { itemWallPixmap.drawPixel(x, y, c1) val c2 = Color(itemWallPixmapGlow.getPixel(x, y)).mulAndAssign(WALL_OVERLAY_COLOUR).toRGBA() itemWallPixmapGlow.drawPixel(x, y, c2) + val c3 = Color(itemWallPixmapEmissive.getPixel(x, y)).mulAndAssign(WALL_OVERLAY_COLOUR).toRGBA() + itemWallPixmapEmissive.drawPixel(x, y, c3) } } @@ -295,8 +312,10 @@ class CreateTileAtlas { itemTerrainTexture = Texture(itemTerrainPixmap) itemTerrainTextureGlow = Texture(itemTerrainPixmapGlow) + itemTerrainTextureEmissive = Texture(itemTerrainPixmapEmissive) itemWallTexture = Texture(itemWallPixmap) itemWallTextureGlow = Texture(itemWallPixmapGlow) + itemWallTextureEmissive = Texture(itemWallPixmapEmissive) // itemTerrainPixmap.dispose() // itemWallPixmap.dispose() @@ -314,10 +333,11 @@ class CreateTileAtlas { val nullTile = Pixmap(TILE_SIZE * 16, TILE_SIZE * 16, Pixmap.Format.RGBA8888) - private fun fileToAtlantes(modname: String, matte: FileHandle, glow: FileHandle?, mode: String?) { - val tilesPixmap = Pixmap(matte) + private fun fileToAtlantes(modname: String, diffuse: FileHandle, glow: FileHandle?, emissive: FileHandle?, mode: String?) { + val tilesPixmap = Pixmap(diffuse) val tilesGlowPixmap = if (glow != null) Pixmap(glow) else nullTile - val blockName = matte.nameWithoutExtension().split('-').last().toInt() // basically a filename + val tilesEmissivePixmap = if (emissive != null) Pixmap(emissive) else nullTile + val blockName = diffuse.nameWithoutExtension().split('-').last().toInt() // basically a filename val blockID = if (mode != null) "$mode@$modname:$blockName" else "$modname:$blockName" @@ -325,37 +345,37 @@ class CreateTileAtlas { // predefined by the image dimension: 16x16 for (1,0) if (tilesPixmap.width == TILE_SIZE && tilesPixmap.height == TILE_SIZE) { addTag(blockID, RenderTag.CONNECT_SELF, RenderTag.MASK_NA) - drawToAtlantes(tilesPixmap, tilesGlowPixmap, RenderTag.MASK_NA) + drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, RenderTag.MASK_NA) } // predefined by the image dimension: 64x16 for (2,3) else if (tilesPixmap.width == TILE_SIZE * 4 && tilesPixmap.height == TILE_SIZE) { addTag(blockID, RenderTag.CONNECT_WALL_STICKER, RenderTag.MASK_TORCH) - drawToAtlantes(tilesPixmap, tilesGlowPixmap, RenderTag.MASK_TORCH) + drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, RenderTag.MASK_TORCH) } // predefined by the image dimension: 128x16 for (3,4) else if (tilesPixmap.width == TILE_SIZE * 8 && tilesPixmap.height == TILE_SIZE) { addTag(blockID, RenderTag.CONNECT_WALL_STICKER_CONNECT_SELF, RenderTag.MASK_PLATFORM) - drawToAtlantes(tilesPixmap, tilesGlowPixmap, RenderTag.MASK_PLATFORM) + drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, RenderTag.MASK_PLATFORM) } // predefined by the image dimension: 256x16 else if (tilesPixmap.width == TILE_SIZE * 16 && tilesPixmap.height == TILE_SIZE) { addTag(blockID, RenderTag.CONNECT_SELF, RenderTag.MASK_16) - drawToAtlantes(tilesPixmap, tilesGlowPixmap, RenderTag.MASK_16) + drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, RenderTag.MASK_16) } // predefined by the image dimension: 256x64 else if (tilesPixmap.width == TILE_SIZE * 16 && tilesPixmap.height == TILE_SIZE * 4) { addTag(blockID, RenderTag.CONNECT_SELF, RenderTag.MASK_16X4) - drawToAtlantes(tilesPixmap, tilesGlowPixmap, RenderTag.MASK_16X4) + drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, RenderTag.MASK_16X4) } // predefined by the image dimension: 256x256 else if (tilesPixmap.width == TILE_SIZE * 16 && tilesPixmap.height == TILE_SIZE * 16) { addTag(blockID, RenderTag.CONNECT_SELF, RenderTag.MASK_16X16) - drawToAtlantes(tilesPixmap, tilesGlowPixmap, RenderTag.MASK_16X16) + drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, RenderTag.MASK_16X16) } // 112x112 or 224x224 else { if (tilesPixmap.width != tilesPixmap.height && tilesPixmap.width % (7 * TILE_SIZE) >= 2) { - throw IllegalArgumentException("Unrecognized image dimension ${tilesPixmap.width}x${tilesPixmap.height} from $modname:${matte.name()}") + throw IllegalArgumentException("Unrecognized image dimension ${tilesPixmap.width}x${tilesPixmap.height} from $modname:${diffuse.name()}") } // figure out the tags var connectionType = 0 @@ -371,7 +391,7 @@ class CreateTileAtlas { } addTag(blockID, connectionType, maskType) - drawToAtlantes(tilesPixmap, tilesGlowPixmap, maskType) + drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, maskType) } itemSheetNumbers[blockID] = itemSheetCursor @@ -400,7 +420,7 @@ class CreateTileAtlas { printdbg(this, "tileName ${id} ->> tileNumber ${atlasCursor}") } - private fun drawToAtlantes(matte: Pixmap, glow: Pixmap, renderMask: Int) { + private fun drawToAtlantes(diffuse: Pixmap, glow: Pixmap, emissive: Pixmap, renderMask: Int) { val tilesCount = RenderTag.maskTypeToTileCount(renderMask) if (atlasCursor + tilesCount >= TOTAL_TILES) { // throw Error("Too much tiles for $MAX_TEX_SIZE texture size: $atlasCursor") @@ -408,30 +428,33 @@ class CreateTileAtlas { expandAtlantes() } - val sixSeasonal = matte.width == 21 * TILE_SIZE && matte.height == 14 * TILE_SIZE - val txOfPixmap = matte.width / TILE_SIZE + val sixSeasonal = diffuse.width == 21 * TILE_SIZE && diffuse.height == 14 * TILE_SIZE + val txOfPixmap = diffuse.width / TILE_SIZE val txOfPixmapGlow = glow.width / TILE_SIZE + val txOfPixmapEmissive = emissive.width / TILE_SIZE for (i in 0 until tilesCount) { //printdbg(this, "Rendering to atlas, tile# $atlasCursor, tilesCount = $tilesCount, seasonal = $seasonal") // different texture for different seasons (224x224) if (sixSeasonal) { val i = if (renderMask == MASK_47) (if (i < 41) i else i + 1) else i // to compensate the discontinuity between 40th and 41st tile - _drawToAtlantes(matte, atlasCursor, i % 7 , i / 7, PREVERNAL) - _drawToAtlantes(matte, atlasCursor, i % 7 + 7 , i / 7, VERNAL) - _drawToAtlantes(matte, atlasCursor, i % 7 + 14, i / 7, AESTIVAL) + _drawToAtlantes(diffuse, atlasCursor, i % 7 , i / 7, PREVERNAL) + _drawToAtlantes(diffuse, atlasCursor, i % 7 + 7 , i / 7, VERNAL) + _drawToAtlantes(diffuse, atlasCursor, i % 7 + 14, i / 7, AESTIVAL) - _drawToAtlantes(matte, atlasCursor, i % 7 + 14, i / 7 + 7, SEROTINAL) - _drawToAtlantes(matte, atlasCursor, i % 7 + 7 , i / 7 + 7, AUTUMNAL) - _drawToAtlantes(matte, atlasCursor, i % 7 , i / 7 + 7, HIBERNAL) + _drawToAtlantes(diffuse, atlasCursor, i % 7 + 14, i / 7 + 7, SEROTINAL) + _drawToAtlantes(diffuse, atlasCursor, i % 7 + 7 , i / 7 + 7, AUTUMNAL) + _drawToAtlantes(diffuse, atlasCursor, i % 7 , i / 7 + 7, HIBERNAL) _drawToAtlantes(glow, atlasCursor, i % 7, i / 7, GLOW) + _drawToAtlantes(emissive, atlasCursor, i % 7, i / 7, EMISSIVE) atlasCursor += 1 } else { val i = if (renderMask == MASK_47) (if (i < 41) i else i + 1) else i // to compensate the discontinuity between 40th and 41st tile - _drawToAtlantes(matte, atlasCursor, i % txOfPixmap, i / txOfPixmap, SIX_SEASONS) + _drawToAtlantes(diffuse, atlasCursor, i % txOfPixmap, i / txOfPixmap, SIX_SEASONS) _drawToAtlantes(glow, atlasCursor, i % txOfPixmapGlow, i / txOfPixmapGlow, GLOW) + _drawToAtlantes(emissive, atlasCursor, i % txOfPixmapGlow, i / txOfPixmapGlow, EMISSIVE) atlasCursor += 1 } } @@ -466,6 +489,7 @@ class CreateTileAtlas { HIBERNAL -> atlasHibernal.drawPixmap(pixmap, sourceX, sourceY, TILE_SIZE, TILE_SIZE, atlasX, atlasY, TILE_SIZE, TILE_SIZE) FLUID -> atlasFluid.drawPixmap(pixmap, sourceX, sourceY, TILE_SIZE, TILE_SIZE, atlasX, atlasY, TILE_SIZE, TILE_SIZE) GLOW -> atlasGlow.drawPixmap(pixmap, sourceX, sourceY, TILE_SIZE, TILE_SIZE, atlasX, atlasY, TILE_SIZE, TILE_SIZE) + EMISSIVE -> atlasEmissive.drawPixmap(pixmap, sourceX, sourceY, TILE_SIZE, TILE_SIZE, atlasX, atlasY, TILE_SIZE, TILE_SIZE) else -> throw IllegalArgumentException("Unknown draw source $source") } } @@ -511,6 +535,7 @@ class CreateTileAtlas { atlasHibernal.dispose() atlasFluid.dispose() atlasGlow.dispose() + atlasEmissive.dispose() //itemTerrainTexture.dispose() //BlocksDrawer will dispose of it as it disposes of 'tileItemTerrain (TextureRegionPack)' //itemTerrainTextureGlow.dispose() //BlocksDrawer will dispose of it as it disposes of 'tileItemTerrain (TextureRegionPack)' //itemWallTexture.dispose() //BlocksDrawer will dispose of it as it disposes of 'tileItemWall (TextureRegionPack)' @@ -522,7 +547,7 @@ class CreateTileAtlas { } private enum class AtlasSource { - /*FOUR_SEASONS, SUMMER, AUTUMN, WINTER, SPRING,*/ FLUID, GLOW, + /*FOUR_SEASONS, SUMMER, AUTUMN, WINTER, SPRING,*/ FLUID, GLOW, EMISSIVE, SIX_SEASONS, PREVERNAL, VERNAL, AESTIVAL, SEROTINAL, AUTUMNAL, HIBERNAL, } @@ -541,13 +566,13 @@ class CreateTileAtlas { TOTAL_TILES = TILES_IN_X * TILES_IN_X - val newAtlantes = Array(7) { + val newAtlantes = Array(8) { Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888).also { it.blending = Pixmap.Blending.None it.filter = Pixmap.Filter.NearestNeighbour } } - listOf(atlasPrevernal, atlasVernal, atlasAestival, atlasSerotinal, atlasAutumnal, atlasHibernal, atlasGlow).forEachIndexed { index, pixmap -> + listOf(atlasPrevernal, atlasVernal, atlasAestival, atlasSerotinal, atlasAutumnal, atlasHibernal, atlasGlow, atlasEmissive).forEachIndexed { index, pixmap -> /* How it works: @@ -579,6 +604,7 @@ class CreateTileAtlas { atlasAutumnal = newAtlantes[4] atlasHibernal = newAtlantes[5] atlasGlow = newAtlantes[6] + atlasEmissive = newAtlantes[7] App.setConfig("atlastexsize", newTexSize)