From b0d648547b0c5754f9079e5110aea8ed628a8f97 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 12 Dec 2021 16:25:42 +0900 Subject: [PATCH] new module info ui --- assets/mods/basegame/gui/modwitherror.tga | 3 + assets/shaders/4096_bayer.frag | 2 +- src/net/torvald/terrarum/ModMgr.kt | 9 +- .../modulebasegame/ui/UITitleModules.kt | 268 +++++++++++++++--- .../terrarum/ui/UIItemModuleInfoCell.kt | 109 +++---- 5 files changed, 291 insertions(+), 100 deletions(-) create mode 100644 assets/mods/basegame/gui/modwitherror.tga diff --git a/assets/mods/basegame/gui/modwitherror.tga b/assets/mods/basegame/gui/modwitherror.tga new file mode 100644 index 000000000..5ab968fc4 --- /dev/null +++ b/assets/mods/basegame/gui/modwitherror.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:22cd8cbfbf597a45c8bca6b525287a0fba89210215dcde35257c29f7d0cf1277 +size 4114 diff --git a/assets/shaders/4096_bayer.frag b/assets/shaders/4096_bayer.frag index 09e314ece..956d6ae79 100644 --- a/assets/shaders/4096_bayer.frag +++ b/assets/shaders/4096_bayer.frag @@ -23,7 +23,7 @@ uniform sampler2D u_texture; uniform sampler2D u_pattern; uniform ivec2 rnd = ivec2(0,0); -float quant = 127.0; // 64 steps -> 63.0; 256 steps -> 255.0 +float quant = 255.0; // 64 steps -> 63.0; 256 steps -> 255.0 vec4 quantiser = vec4(quant); vec4 quantiserDivider = vec4(1.0 / quant); diff --git a/src/net/torvald/terrarum/ModMgr.kt b/src/net/torvald/terrarum/ModMgr.kt index ee89e0ce4..3c663f754 100644 --- a/src/net/torvald/terrarum/ModMgr.kt +++ b/src/net/torvald/terrarum/ModMgr.kt @@ -83,6 +83,7 @@ object ModMgr { /** Module name (directory name), ModuleMetadata */ val moduleInfo = HashMap() + val moduleInfoErrored = HashMap() val entryPointClasses = ArrayList() val moduleClassloader = HashMap() @@ -169,7 +170,7 @@ object ModMgr { logError(LoadErrorType.YOUR_FAULT, moduleName, e) - moduleInfo.remove(moduleName) + moduleInfo.remove(moduleName)?.let { moduleInfoErrored[moduleName] = it } } if (newClass != null) { @@ -182,7 +183,7 @@ object ModMgr { printdbg(this, "$moduleName loaded successfully") } else { - moduleInfo.remove(moduleName) + moduleInfo.remove(moduleName)?.let { moduleInfoErrored[moduleName] = it } printdbg(this, "$moduleName did not load...") } @@ -195,7 +196,7 @@ object ModMgr { logError(LoadErrorType.NOT_EVEN_THERE, moduleName) - moduleInfo.remove(moduleName) + moduleInfo.remove(moduleName)?.let { moduleInfoErrored[moduleName] = it } } catch (e: Throwable) { printdbgerr(this, "There was an error while loading module $moduleName") @@ -204,7 +205,7 @@ object ModMgr { logError(LoadErrorType.YOUR_FAULT, moduleName, e) - moduleInfo.remove(moduleName) + moduleInfo.remove(moduleName)?.let { moduleInfoErrored[moduleName] = it } } finally { diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UITitleModules.kt b/src/net/torvald/terrarum/modulebasegame/ui/UITitleModules.kt index 391e6fa4b..be76e8836 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UITitleModules.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UITitleModules.kt @@ -1,72 +1,235 @@ package net.torvald.terrarum.modulebasegame.ui -import com.badlogic.gdx.graphics.Camera -import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.Input +import com.badlogic.gdx.graphics.* import com.badlogic.gdx.graphics.g2d.SpriteBatch -import net.torvald.terrarum.App -import net.torvald.terrarum.ModMgr -import net.torvald.terrarum.Second -import net.torvald.terrarum.blendNormal +import com.badlogic.gdx.graphics.glutils.FrameBuffer +import com.badlogic.gdx.graphics.glutils.ShapeRenderer +import net.torvald.getKeycapConsole +import net.torvald.getKeycapPC +import net.torvald.terrarum.* +import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.ui.Movement import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.ui.UICanvas -import net.torvald.terrarum.ui.UIItemList import net.torvald.terrarum.ui.UIItemModuleInfoCell +import kotlin.math.roundToInt + +val MODULEINFO_CELL_WIDTH = 480 +val MODULEINFO_CELL_HEIGHT = 48 /** * Created by minjaesong on 2017-08-01. */ class UITitleModules(val remoCon: UIRemoCon) : UICanvas() { + override var width: Int + get() = Toolkit.drawWidth + set(value) {} + override var height: Int + get() = App.scr.height + set(value) {} override var openCloseTime: Second = 0f - private val moduleAreaHMargin = 48 - private val moduleAreaBorder = 8 - override var width = 600//App.scr.width - UIRemoCon.remoConWidth - moduleAreaHMargin - override var height = App.scr.height - moduleAreaHMargin * 2 + private val shapeRenderer = ShapeRenderer() - private val moduleInfoCells = ArrayList() - // build module list + internal val uiWidth = MODULEINFO_CELL_WIDTH + internal val uiX = (width - uiWidth) / 2 + + internal val textH = App.fontGame.lineHeight.toInt() + + internal val cellGap = 20 + internal val cellInterval = cellGap + MODULEINFO_CELL_HEIGHT + internal val gradAreaHeight = 32 + + internal val titleTextPosY: Int = App.scr.tvSafeGraphicsHeight + 10 + internal val titleTopGradStart: Int = titleTextPosY + textH + internal val titleTopGradEnd: Int = titleTopGradStart + gradAreaHeight + internal val titleBottomGradStart: Int = height - App.scr.tvSafeGraphicsHeight - gradAreaHeight + internal val titleBottomGradEnd: Int = titleBottomGradStart + gradAreaHeight + internal val controlHelperY: Int = titleBottomGradStart + gradAreaHeight - textH + + + private val controlHelp: String + get() = if (App.environment == RunningEnvironment.PC) + "${getKeycapPC(App.getConfigInt("control_key_up"))}${getKeycapPC(App.getConfigInt("control_key_down"))}" + + " ${Lang["MENU_CONTROLS_SCROLL"]}" + else + "${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}" + + + private var scrollAreaHeight = height - 2 * App.scr.tvSafeGraphicsHeight - 64 + private var listScroll = 0 // only update when animation is finished + private var savesVisible = (scrollAreaHeight + cellGap) / cellInterval + + private var uiScroll = 0f + private var scrollFrom = 0 + private var scrollTarget = 0 + private var scrollAnimCounter = 0f + private val scrollAnimLen = 0.1f + + private var sliderFBO = FrameBuffer(Pixmap.Format.RGBA8888, uiWidth + 10, height, true) + + private val moduleCells = ArrayList() + + + private var showSpinner = false + init { - ModMgr.moduleInfo.toList().sortedBy { it.second.order }.forEachIndexed { index, it -> - moduleInfoCells.add(UIItemModuleInfoCell( - this, - it.first, - width - 2 * moduleAreaBorder, - 0, 0 // placeholder - )) + try { + // read savegames + var savegamesCount = 0 + ModMgr.loadOrder.forEachIndexed { index, s -> + val x = uiX + if (App.getConfigBoolean("fx_streamerslayout")) App.scr.chatWidth / 2 else 0 + val y = titleTopGradEnd + cellInterval * savegamesCount + try { + moduleCells.add(UIItemModuleInfoCell(this, index, x, y)) + savegamesCount += 1 + } + catch (e: Throwable) { + System.err.println("[UILoadDemoSavefiles] Error while loading module info for '$s'") + e.printStackTrace() + } + } } - } - - private val moduleArea = UIItemList( - this, - moduleInfoCells, - (App.scr.width - this.width) / 2, moduleAreaHMargin, - width, - height, - inactiveCol = Color.WHITE, - border = moduleAreaBorder - ) - - - init { - uiItems.add(moduleArea) + catch (e: UninitializedPropertyAccessException) {} } override fun updateUI(delta: Float) { - moduleArea.update(delta) + if (scrollTarget != listScroll) { + if (scrollAnimCounter < scrollAnimLen) { + scrollAnimCounter += delta + uiScroll = Movement.fastPullOut( + scrollAnimCounter / scrollAnimLen, + listScroll * cellInterval.toFloat(), + scrollTarget * cellInterval.toFloat() + ) + } + else { + scrollAnimCounter = 0f + listScroll = scrollTarget + uiScroll = cellInterval.toFloat() * scrollTarget + } + } + + for (index in 0 until moduleCells.size) { + val it = moduleCells[index] + if (index in listScroll - 2 until listScroll + savesVisible + 2) { + // re-position + it.posY = (it.initialY - uiScroll).roundToInt() + it.update(delta) + } + } + } + + override fun hide() { + moduleCells.forEach { it.dispose() } + moduleCells.clear() } override fun renderUI(batch: SpriteBatch, camera: Camera) { - batch.color = Color.WHITE - blendNormal(batch) - Toolkit.drawBoxBorder(batch, moduleArea.posX, moduleArea.posY, width, height) - moduleArea.render(batch, camera) + batch.end() + + lateinit var savePixmap: Pixmap + sliderFBO.inAction(camera as OrthographicCamera, batch) { + gdxClearAndSetBlend(0f, 0f, 0f, 0f) + + setCameraPosition(batch, camera, 0f, 0f) + batch.color = Color.WHITE + batch.inUse { + for (index in 0 until moduleCells.size) { + val it = moduleCells[index] + if (index in listScroll - 2 until listScroll + savesVisible + 2) { + it.render(batch, camera) + } + } + } + savePixmap = Pixmap.createFromFrameBuffer(0, 0, sliderFBO.width, sliderFBO.height) + savePixmap.blending = Pixmap.Blending.None + } + + + // implement "wipe-out" by CPU-rendering (*deep exhale*) + //savePixmap.setColor(1f,1f,1f,0f) + savePixmap.setColor(0f, 0f, 0f, 0f) + savePixmap.fillRectangle(0, savePixmap.height - titleTopGradStart, savePixmap.width, titleTopGradStart) + // top grad + for (y in titleTopGradStart until titleTopGradEnd) { + val alpha = (y - titleTopGradStart).toFloat() / gradAreaHeight + for (x in 0 until savePixmap.width) { + val col = savePixmap.getPixel(x, savePixmap.height - y) + val blendAlpha = (col.and(0xFF) * alpha).roundToInt() + savePixmap.drawPixel(x, savePixmap.height - y, col.and(0xFFFFFF00.toInt()) or blendAlpha) + } + } + // bottom grad + for (y in titleBottomGradStart until titleBottomGradEnd) { + val alpha = 1f - ((y - titleBottomGradStart).toFloat() / gradAreaHeight) + for (x in 0 until savePixmap.width) { + val col = savePixmap.getPixel(x, savePixmap.height - y) + val blendAlpha = (col.and(0xFF) * alpha).roundToInt() + savePixmap.drawPixel(x, savePixmap.height - y, col.and(0xFFFFFF00.toInt()) or blendAlpha) + } + } + savePixmap.setColor(0f, 0f, 0f, 0f) + savePixmap.fillRectangle(0, 0, savePixmap.width, height - titleBottomGradEnd + 1) + + + + setCameraPosition(batch, camera, 0f, 0f) + val saveTex = Texture(savePixmap) + batch.inUse { + batch.color = Color.WHITE + batch.draw(saveTex, (width - uiWidth - 10) / 2f, 0f) + // draw texts + val loadGameTitleStr = Lang["MENU_MODULES"]// + "$EMDASH$hash" + // "Game Load" + App.fontUITitle.draw(batch, loadGameTitleStr, (width - App.fontGame.getWidth(loadGameTitleStr)).div(2).toFloat(), titleTextPosY.toFloat()) + // Control help + App.fontGame.draw(batch, controlHelp, uiX.toFloat(), controlHelperY.toFloat()) + } + + saveTex.dispose() + savePixmap.dispose() + + batch.begin() + } - override fun doOpening(delta: Float) { + override fun keyDown(keycode: Int): Boolean { + if (this.isVisible) { + if ((keycode == Input.Keys.UP || keycode == App.getConfigInt("control_key_up")) && scrollTarget > 0) { + scrollFrom = listScroll + scrollTarget -= 1 + scrollAnimCounter = 0f + } + else if ((keycode == Input.Keys.DOWN || keycode == App.getConfigInt("control_key_down")) && scrollTarget < moduleCells.size - savesVisible) { + scrollFrom = listScroll + scrollTarget += 1 + scrollAnimCounter = 0f + } + } + return true + } + override fun scrolled(amountX: Float, amountY: Float): Boolean { + if (this.isVisible) { + if (amountY <= -1f && scrollTarget > 0) { + scrollFrom = listScroll + scrollTarget -= 1 + scrollAnimCounter = 0f + } + else if (amountY >= 1f && scrollTarget < moduleCells.size - savesVisible) { + scrollFrom = listScroll + scrollTarget += 1 + scrollAnimCounter = 0f + } + } + return true + } + override fun doOpening(delta: Float) { } override fun doClosing(delta: Float) { @@ -76,9 +239,32 @@ class UITitleModules(val remoCon: UIRemoCon) : UICanvas() { } override fun endClosing(delta: Float) { + listScroll = 0 + scrollTarget = 0 + uiScroll = 0f } override fun dispose() { + try { shapeRenderer.dispose() } catch (e: IllegalArgumentException) {} + try { sliderFBO.dispose() } catch (e: IllegalArgumentException) {} } + override fun resize(width: Int, height: Int) { + super.resize(width, height) + scrollAreaHeight = height - 2 * App.scr.tvSafeGraphicsHeight - 64 + savesVisible = (scrollAreaHeight + cellInterval) / (cellInterval + MODULEINFO_CELL_HEIGHT) + + listScroll = 0 + scrollTarget = 0 + uiScroll = 0f + + sliderFBO.dispose() + sliderFBO = FrameBuffer(Pixmap.Format.RGBA8888, uiWidth + 10, height, true) + } + + private fun setCameraPosition(batch: SpriteBatch, camera: Camera, newX: Float, newY: Float) { + camera.position.set((-newX + App.scr.halfw).round(), (-newY + App.scr.halfh).round(), 0f) + camera.update() + batch.projectionMatrix = camera.combined + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/ui/UIItemModuleInfoCell.kt b/src/net/torvald/terrarum/ui/UIItemModuleInfoCell.kt index aeb15e746..061889717 100644 --- a/src/net/torvald/terrarum/ui/UIItemModuleInfoCell.kt +++ b/src/net/torvald/terrarum/ui/UIItemModuleInfoCell.kt @@ -2,83 +2,84 @@ package net.torvald.terrarum.ui import com.badlogic.gdx.graphics.Camera import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.g2d.SpriteBatch +import com.badlogic.gdx.graphics.g2d.TextureRegion import net.torvald.terrarum.App +import net.torvald.terrarum.CommonResourcePool import net.torvald.terrarum.ModMgr import net.torvald.terrarum.blendNormal -import net.torvald.terrarum.floor +import net.torvald.terrarum.modulebasegame.ui.MODULEINFO_CELL_HEIGHT +import net.torvald.terrarum.modulebasegame.ui.MODULEINFO_CELL_WIDTH class UIItemModuleInfoCell( parent: UICanvas, - var moduleName: String, - override val width: Int, + var order: Int, initialX: Int, initialY: Int ) : UIItem(parent, initialX, initialY) { - override val height: Int = App.fontGame.lineHeight.toInt() * 2 + override val width = MODULEINFO_CELL_WIDTH + override val height = MODULEINFO_CELL_HEIGHT - private val numberAreaWidth = App.fontSmallNumbers.W * 3 + 4 + private val modName = ModMgr.loadOrder[order] + + private val modProp = ModMgr.moduleInfo[modName] ?: ModMgr.moduleInfoErrored[modName]!! + + private val modErrored = (ModMgr.moduleInfo[modName] == null) + + private val modIcon = TextureRegion(Texture(modProp.iconFile)) + private val modVer = modProp.version + private val modDate = modProp.releaseDate + private val modAuthor = modProp.author + + init { + modIcon.flip(false, true) + + CommonResourcePool.addToLoadingList("basegame_errored_icon32") { + val t = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/modwitherror.tga"))) + t.flip(false, true) + t + } + CommonResourcePool.loadAll() + } + + private val ccZero = App.fontGame.toColorCode(15,15,15) + private val ccZero2 = App.fontGame.toColorCode(12,12,12) + private val ccNum = App.fontGame.toColorCode(15,14,6) + private val ccNum2 = App.fontGame.toColorCode(12,11,4) override fun render(batch: SpriteBatch, camera: Camera) { blendNormal(batch) - if (ModMgr.moduleInfo.containsKey(moduleName)) { - val modInfo = ModMgr.moduleInfo[moduleName]!! + batch.color = Toolkit.Theme.COL_CELL_FILL + Toolkit.fillArea(batch, initialX, initialY, 32, 48) + Toolkit.fillArea(batch, initialX + 35, initialY, 48, 48) + Toolkit.fillArea(batch, initialX + 86, initialY, width - 86, 48) - // print load order index - batch.color = Color(0xccccccff.toInt()) - var strlen = App.fontSmallNumbers.getWidth(modInfo.order.toString()) - App.fontSmallNumbers.draw(batch, - modInfo.order.toString(), - posX + (numberAreaWidth - strlen).div(2f).floor(), - posY + (height - App.fontSmallNumbers.H).div(2f).floor() - ) + batch.color = Toolkit.Theme.COL_INACTIVE + Toolkit.drawBoxBorder(batch, initialX - 1, initialY - 1, width + 2, height + 2) + Toolkit.fillArea(batch, initialX + 33, initialY, 1, 48) + Toolkit.fillArea(batch, initialX + 84, initialY, 1, 48) - // print module name - batch.color = Color.WHITE - App.fontGame.draw(batch, - "${modInfo.properName} (${modInfo.version})", - posX + numberAreaWidth.toFloat(), - posY.toFloat() - ) + if (order < 9) + App.fontSmallNumbers.draw(batch, "${order+1}", initialX + 13f, initialY + 18f) + else if (order < 99) + App.fontSmallNumbers.draw(batch, "${order+1}", initialX + 9f, initialY + 18f) + else + App.fontSmallNumbers.draw(batch, "${order+1}", initialX + 6f, initialY + 18f) - // print author name - strlen = App.fontGame.getWidth(modInfo.author) - App.fontGame.draw(batch, - modInfo.author, - posX + width - strlen.toFloat(), - posY.toFloat() - ) + batch.color = Color.WHITE + batch.draw(modIcon, initialX + 35f, initialY.toFloat()) + App.fontGame.draw(batch, "$ccZero${modName.toUpperCase()}$ccNum $modVer", initialX + 86f + 6f, initialY + 2f) + App.fontGame.draw(batch, "$ccZero2$modAuthor$ccNum2 $modDate", initialX + 86f + 6f, initialY + 26f) - // print description - App.fontGame.draw(batch, - modInfo.description, - posX + numberAreaWidth.toFloat(), - posY + App.fontGame.lineHeight - ) - - // print releasedate - strlen = App.fontGame.getWidth(modInfo.releaseDate) - App.fontGame.draw(batch, - modInfo.releaseDate, - posX + width - strlen.toFloat(), - posY + App.fontGame.lineHeight - ) - - } - else { - batch.color = Color(0xff8080_ff.toInt()) - val str = "InternalError: no such module: '$moduleName'" - val strlen = App.fontSmallNumbers.getWidth(str) - App.fontSmallNumbers.draw(batch, - str, - posX + (width - numberAreaWidth - strlen).div(2f).floor() + numberAreaWidth, - posY + (height - App.fontSmallNumbers.H).div(2f).floor() - ) + if (modErrored) { + batch.draw(CommonResourcePool.getAsTextureRegion("basegame_errored_icon32"), initialX + width - 40f, initialY + 8f) } } override fun dispose() { + modIcon.texture.dispose() } } \ No newline at end of file