new debug cmd ExportFBO

This commit is contained in:
minjaesong
2024-11-24 12:53:44 +09:00
parent f5846d9bae
commit 89b12aabb4
6 changed files with 129 additions and 19 deletions

View File

@@ -3,6 +3,7 @@ CheatWarnTest
CodexEdictis CodexEdictis
ExportAtlas ExportAtlas
ExportCodices ExportCodices
ExportFBO
ExportMap ExportMap
ExportMap2 ExportMap2
ExportWorld ExportWorld
1 CatStdout
3 CodexEdictis
4 ExportAtlas
5 ExportCodices
6 ExportFBO
7 ExportMap
8 ExportMap2
9 ExportWorld

View File

@@ -60,6 +60,7 @@ import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.*; import java.util.*;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.zip.Deflater;
import static java.lang.Thread.MAX_PRIORITY; import static java.lang.Thread.MAX_PRIORITY;
import static net.torvald.terrarum.TerrarumKt.*; import static net.torvald.terrarum.TerrarumKt.*;
@@ -766,7 +767,7 @@ public class App implements ApplicationListener {
FrameBufferManager.begin(fb); FrameBufferManager.begin(fb);
try { try {
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, fb.getWidth(), fb.getHeight()); Pixmap p = Pixmap.createFromFrameBuffer(0, 0, fb.getWidth(), fb.getHeight());
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true); PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, Deflater.DEFAULT_COMPRESSION, true);
p.dispose(); p.dispose();
} }
catch (Throwable e) { catch (Throwable e) {

View File

@@ -67,7 +67,7 @@ class SavegameCracker(
private val cmds: HashMap<String, KFunction<*>> = HashMap() private val cmds: HashMap<String, KFunction<*>> = HashMap()
init { init {
SavegameCracker::class.declaredFunctions SavegameCracker::class.declaredFunctions
.filter { it.findAnnotation<Command>() != null } .filter { it.findAnnotation<SavegameCrackerCommand>() != null }
// .forEach { it.isAccessible = true; cmds[it.name] = it } // .forEach { it.isAccessible = true; cmds[it.name] = it }
.forEach { cmds[it.name] = it } .forEach { cmds[it.name] = it }
} }
@@ -100,7 +100,7 @@ class SavegameCracker(
printerrln("${args[0]}: command not found") printerrln("${args[0]}: command not found")
else { else {
try { try {
val annot = it.findAnnotation<Command>()!! val annot = it.findAnnotation<SavegameCrackerCommand>()!!
// check arguments // check arguments
val synopsis = annot.synopsis.split(' ').filter { it.isNotBlank() } val synopsis = annot.synopsis.split(' ').filter { it.isNotBlank() }
// print out synopsis // print out synopsis
@@ -185,14 +185,14 @@ class SavegameCracker(
return this + sb.toString() return this + sb.toString()
} }
@Command("Loads a disk archive", "path-to-file") @SavegameCrackerCommand("Loads a disk archive", "path-to-file")
fun load(args: List<String>) { fun load(args: List<String>) {
file = File(args[1]) file = File(args[1])
disk = VDUtil.readDiskArchive(file!!, Level.INFO) { printerrln("# Warning: $it") } disk = VDUtil.readDiskArchive(file!!, Level.INFO) { printerrln("# Warning: $it") }
file!!.copyTo(File(file!!.absolutePath + ".bak"), true) file!!.copyTo(File(file!!.absolutePath + ".bak"), true)
} }
@Command("Lists contents of the disk") @SavegameCrackerCommand("Lists contents of the disk")
fun ls(args: List<String>) { fun ls(args: List<String>) {
letdisk { letdisk {
it.entries.toSortedMap().forEach { (i, entry) -> it.entries.toSortedMap().forEach { (i, entry) ->
@@ -207,19 +207,19 @@ class SavegameCracker(
} }
} }
@Command("Prints out available commands and their usage") @SavegameCrackerCommand("Prints out available commands and their usage")
fun help(args: List<String>) { fun help(args: List<String>) {
cmds.forEach { name, it -> cmds.forEach { name, it ->
println("$ccNoun${name.padStart(8)}$cc0 - ${it.findAnnotation<Command>()!!.help}") println("$ccNoun${name.padStart(8)}$cc0 - ${it.findAnnotation<SavegameCrackerCommand>()!!.help}")
} }
} }
@Command("Exits the program") @SavegameCrackerCommand("Exits the program")
fun exit(args: List<String>) { this.exit = true } fun exit(args: List<String>) { this.exit = true }
@Command("Exits the program") @SavegameCrackerCommand("Exits the program")
fun quit(args: List<String>) = exit(args) fun quit(args: List<String>) = exit(args)
@Command("Exports contents of the entry into a real file", "entry-id output-file") @SavegameCrackerCommand("Exports contents of the entry into a real file", "entry-id output-file")
fun export(args: List<String>) { fun export(args: List<String>) {
letdisk { letdisk {
val entryID = args[1].toLong(10) val entryID = args[1].toLong(10)
@@ -228,7 +228,7 @@ class SavegameCracker(
} }
} }
@Command("Changes one entry-ID into another", "change-from change-to") @SavegameCrackerCommand("Changes one entry-ID into another", "change-from change-to")
fun renum(args: List<String>) { fun renum(args: List<String>) {
letdisk { letdisk {
val id0 = args[1].toLong(10) val id0 = args[1].toLong(10)
@@ -244,7 +244,7 @@ class SavegameCracker(
} }
} }
@Command("Imports a real file onto the savefile", "input-file entry-id") @SavegameCrackerCommand("Imports a real file onto the savefile", "input-file entry-id")
fun import(args: List<String>) { fun import(args: List<String>) {
letdisk { letdisk {
val file = File(args[1]) val file = File(args[1])
@@ -257,7 +257,7 @@ class SavegameCracker(
} }
} }
@Command("Removes a file within the savefile", "entry-id") @SavegameCrackerCommand("Removes a file within the savefile", "entry-id")
fun rm(args: List<String>) { fun rm(args: List<String>) {
letdisk { letdisk {
val id = args[1].toLong(10) val id = args[1].toLong(10)
@@ -266,14 +266,14 @@ class SavegameCracker(
} }
} }
@Command("Saves changes onto the savefile") @SavegameCrackerCommand("Saves changes onto the savefile")
fun save(args: List<String>) { fun save(args: List<String>) {
letdisk { letdisk {
VDUtil.dumpToRealMachine(it, file!!) VDUtil.dumpToRealMachine(it, file!!)
} }
} }
@Command("Retrieves all UUIDs found (player UUID, current world UUID, etc.") @SavegameCrackerCommand("Retrieves all UUIDs found (player UUID, current world UUID, etc.")
fun uuid(args: List<String>) { fun uuid(args: List<String>) {
letdisk { letdisk {
val jsonFile = it.getFile(-1) ?: throw FileNotFoundException("savegameinfo.json (entry ID -1) not found") val jsonFile = it.getFile(-1) ?: throw FileNotFoundException("savegameinfo.json (entry ID -1) not found")
@@ -294,7 +294,7 @@ class SavegameCracker(
} }
} }
@Command("Removes the specified chunk(s) completely", "IDs") @SavegameCrackerCommand("Removes the specified chunk(s) completely", "IDs")
fun discardchunk(args: List<String>) { fun discardchunk(args: List<String>) {
letdisk { disk -> letdisk { disk ->
val ids = args[1] val ids = args[1]
@@ -320,7 +320,7 @@ class SavegameCracker(
} }
} }
internal annotation class Command(val help: String = "", val synopsis: String = "") internal annotation class SavegameCrackerCommand(val help: String = "", val synopsis: String = "")
fun main(args: Array<String>) { fun main(args: Array<String>) {
SavegameCracker(args).invoke() SavegameCracker(args).invoke()

View File

@@ -75,6 +75,7 @@ object IngameRenderer : Disposable {
private lateinit var fboA_lightMixed: Float16FrameBuffer private lateinit var fboA_lightMixed: Float16FrameBuffer
private lateinit var fboEmissive: Float16FrameBuffer private lateinit var fboEmissive: Float16FrameBuffer
private lateinit var fboMixedOut: Float16FrameBuffer private lateinit var fboMixedOut: Float16FrameBuffer
private lateinit var rgbTex: TextureRegion private lateinit var rgbTex: TextureRegion
private lateinit var aTex: TextureRegion private lateinit var aTex: TextureRegion
private lateinit var mixedOutTex: TextureRegion private lateinit var mixedOutTex: TextureRegion

View File

@@ -0,0 +1,107 @@
package net.torvald.terrarum.modulebasegame.console
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.GL30
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.PixmapIO
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.utils.BufferUtils
import net.torvald.reflection.extortField
import net.torvald.terrarum.App
import net.torvald.terrarum.ccG
import net.torvald.terrarum.ccO
import net.torvald.terrarum.ccW
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.console.EchoError
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.unicode.BULLET
import net.torvald.unicode.EMDASH
import java.nio.ByteBuffer
import java.util.zip.Deflater
import kotlin.reflect.KFunction
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.hasAnnotation
/**
* Created by minjaesong on 2024-11-24.
*/
internal object ExportFBO : ConsoleCommand {
private val cmds: HashMap<String, KFunction<*>> = HashMap()
private val helpMessages: List<Pair<String, String>>
init {
val helpMsgs: HashMap<String, String> = HashMap()
ExportFBO::class.declaredFunctions.filter { it.hasAnnotation<ExportFBOCmd>() }.forEach {
cmds[it.name.lowercase()] = it
helpMsgs[it.name.lowercase()] = it.findAnnotation<ExportFBOCmd>()!!.description
}
helpMessages = helpMsgs.keys.toList().sorted().map {
it to helpMsgs[it]!!
}
}
override fun execute(args: Array<String>) {
if (args.size != 3) { printUsage(); return }
val fn = cmds[args[1].lowercase()]
if (fn == null) { printUsage(); return }
try {
val filename = "${args[2]}-${args[1]}.png"
val fileHandle = Gdx.files.absolute("${App.defaultDir}/Exports/$filename")
val fbo = fn.call(this) as FrameBuffer
// cannot use createFromFrameBuffer because the specific FBO must be bound in a way we can control
val pixels: ByteBuffer = BufferUtils.newByteBuffer(fbo.width * fbo.height * 4)
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fbo.framebufferHandle)
Gdx.gl.glReadPixels(0, 0, fbo.width, fbo.height, GL30.GL_RGBA, GL30.GL_UNSIGNED_BYTE, pixels)
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, 0)
val pixmap: Pixmap = Pixmap(fbo.width, fbo.height, Pixmap.Format.RGBA8888)
BufferUtils.copy(pixels, pixmap.pixels, pixels.capacity())
PixmapIO.writePNG(fileHandle, pixmap, Deflater.DEFAULT_COMPRESSION, true)
Echo("Framebuffer exported to$ccG Exports/$filename")
}
catch (e: Throwable) {
EchoError("Could not retrieve the framebuffer: ${e.message}")
System.err.println(e)
return
}
}
override fun printUsage() {
Echo("Usage: exportfbo <identifier> <filename without extension>")
Echo("Available identifiers are:")
helpMessages.forEach { (name, desc) ->
Echo(" $BULLET $ccG$name $ccW$EMDASH $ccO$desc")
}
}
@ExportFBOCmd("Main RGB channel of the IngameRenderer without lighting")
fun fborgb(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboRGB")!!
}
@ExportFBOCmd("Main A channel of the IngameRenderer without lighting")
fun fboa(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboA")!!
}
@ExportFBOCmd("Main Emissive channel of the IngameRenderer without lighting")
fun fboemissive(): FrameBuffer {
return IngameRenderer.extortField<Float16FrameBuffer>("fboEmissive")!!
}
}
internal annotation class ExportFBOCmd(val description: String)

View File

@@ -40,12 +40,12 @@ class ConsoleWindow : UICanvas() {
private var commandHistory = CircularArray<String>(COMMAND_HISTORY_MAX, true) private var commandHistory = CircularArray<String>(COMMAND_HISTORY_MAX, true)
private val LINE_HEIGHT = 20 private val LINE_HEIGHT = 20
private val MESSAGES_DISPLAY_COUNT = 11 private val MESSAGES_DISPLAY_COUNT = 12
private val inputToMsgboxGap = 3 private val inputToMsgboxGap = 3
override var width: Int = App.scr.width override var width: Int = App.scr.width
override var height: Int = LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT + 1) + inputToMsgboxGap override var height: Int = LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT + 1) + inputToMsgboxGap + 4
override var openCloseTime = 0f override var openCloseTime = 0f