From f3757f6fbd378ef88e70e925cac6a3c84f298d8e Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 8 Aug 2024 16:02:05 +0300 Subject: [PATCH 01/20] Global toggle sounds --- .../lambda/gui/impl/clickgui/buttons/ModuleButton.kt | 12 ++++-------- common/src/main/kotlin/com/lambda/module/Module.kt | 10 ++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 86ec9933c..df80cf068 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -174,12 +174,11 @@ class ModuleButton( } override fun performClickAction(e: GuiEvent.MouseClick) { - val sound = when (e.button) { + when (e.button) { Mouse.Button.Left -> { module.toggle() - if (module.isEnabled) LambdaSound.MODULE_ON else LambdaSound.MODULE_OFF - } + } Mouse.Button.Right -> { // Don't let user spam val targetHeight = if (isOpen) settingsHeight else 0.0 @@ -189,13 +188,10 @@ class ModuleButton( if (isOpen) settingsLayer.onEvent(GuiEvent.Show()) updateHeight() - if (isOpen) LambdaSound.SETTINGS_OPEN else LambdaSound.SETTINGS_CLOSE + val sound = if (isOpen) LambdaSound.SETTINGS_OPEN else LambdaSound.SETTINGS_CLOSE + playSoundRandomly(sound.event) } - - else -> return } - - playSoundRandomly(sound.event) } override fun equals(other: Any?) = diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 4cca48a40..61545b980 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -18,6 +18,8 @@ import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.module.modules.client.ClickGui import com.lambda.module.tag.ModuleTag +import com.lambda.sound.LambdaSound +import com.lambda.sound.SoundManager.playSoundRandomly import com.lambda.util.KeyCode import com.lambda.util.Nameable @@ -119,6 +121,14 @@ abstract class Module( || screen is LambdaClickGui) ) toggle() } + + onEnable { + playSoundRandomly(LambdaSound.MODULE_ON.event) + } + + onDisable { + playSoundRandomly(LambdaSound.MODULE_OFF.event) + } } fun enable() { From 65751e3e0d84ae6c7d2c43bb16107c9383187f98 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 10 Aug 2024 13:37:37 +0300 Subject: [PATCH 02/20] Tickshift improvements --- .../lambda/mixin/MinecraftClientMixin.java | 10 ++++++++++ .../com/lambda/event/events/TickEvent.kt | 19 +++++++++++++++++-- .../lambda/module/modules/movement/Blink.kt | 18 ++++++++++++------ .../module/modules/movement/TickShift.kt | 11 +++++++---- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 9ffcd5c65..6c92d6558 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -35,6 +35,16 @@ void onTickPost(CallbackInfo ci) { EventFlow.post(new TickEvent.Post()); } + @Inject(method = "render", at = @At("HEAD")) + void onLoopTickPre(CallbackInfo ci) { + EventFlow.post(new TickEvent.GameLoop.Pre()); + } + + @Inject(method = "render", at = @At("RETURN")) + void onLoopTickPost(CallbackInfo ci) { + EventFlow.post(new TickEvent.GameLoop.Post()); + } + @Inject(at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;info(Ljava/lang/String;)V", shift = At.Shift.AFTER, remap = false), method = "stop") private void onShutdown(CallbackInfo ci) { EventFlow.post(new ClientEvent.Shutdown()); diff --git a/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt b/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt index 85f9b1a0a..d47597fdb 100644 --- a/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt @@ -18,15 +18,30 @@ import com.lambda.event.events.TickEvent.Pre */ abstract class TickEvent : Event { /** - * A class representing a [TickEvent] that is triggered before each tick of the game loop. + * A class representing a [TickEvent] that is triggered before each tick of the tick loop. */ class Pre : TickEvent() /** - * A class representing a [TickEvent] that is triggered after each tick of the game loop. + * A class representing a [TickEvent] that is triggered after each tick of the tick loop. */ class Post : TickEvent() + /** + * A class representing a [TickEvent] that is triggered on each tick of the game loop. + */ + abstract class GameLoop : TickEvent() { + /** + * A class representing a [TickEvent.Player] that is triggered before each tick of the game loop. + */ + class Pre : TickEvent() + + /** + * A class representing a [TickEvent.Player] that is triggered after each tick of the game loop. + */ + class Post : TickEvent() + } + /** * A class representing a [TickEvent] that is triggered when the player gets ticked. */ diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt index ddae9757b..702931923 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt @@ -14,10 +14,12 @@ import com.lambda.util.ClientPacket import com.lambda.util.PacketUtils.handlePacketSilently import com.lambda.util.PacketUtils.sendPacketSilently import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.VecUtils.minus import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d import java.util.concurrent.ConcurrentLinkedDeque object Blink : Module( @@ -61,6 +63,16 @@ object Blink : Module( return@listener } + listener { event -> + val packet = event.packet + if (packet !is PlayerMoveC2SPacket) return@listener + + val vec = Vec3d(packet.getX(0.0), packet.getY(0.0), packet.getZ(0.0)) + if (vec == Vec3d.ZERO) return@listener + + lastBox = player.boundingBox.offset(vec - player.pos) + } + listener { event -> if (!isActive || !shiftVelocity) return@listener @@ -81,12 +93,6 @@ object Blink : Module( while (packetPool.isNotEmpty()) { packetPool.poll().let { packet -> connection.sendPacketSilently(packet) - - if (packet is PlayerMoveC2SPacket && packet.changesPosition()) { - lastBox = player.boundingBox - .offset(player.pos.negate()) - .offset(packet.getX(0.0), packet.getY(0.0), packet.getZ(0.0)) - } } } diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt index 1f9d92f1c..893674986 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt @@ -26,10 +26,13 @@ object TickShift : Module( private val boostAmount by setting("Boost", 3.0, 1.1..20.0, 0.01) private val slowdown by setting("Slowdown", 0.35, 0.01..0.9, 0.01) private val delaySetting by setting("Delay", 0, 0..2000, 10) - private val strict by setting("Strict", true) - private val shiftVelocity by setting("Shift velocity", true) + private val grim by setting("Grim", true) + private val strictSetting by setting("Strict", true) { !grim } + private val shiftVelocity by setting("Shift velocity", true) { grim } private val requiresAura by setting("Requires Aura", false) + private val strict get() = grim || strictSetting + val isActive: Boolean get() { if (requiresAura && (!KillAura.isEnabled || KillAura.target == null)) return false return System.currentTimeMillis() - lastBoost > delaySetting @@ -90,7 +93,7 @@ object TickShift : Module( } listener { event -> - if (!isActive) return@listener + if (!isActive || !grim || event.isCanceled()) return@listener if (event.packet !is CommonPongC2SPacket) return@listener pingPool.add(event.packet) @@ -99,7 +102,7 @@ object TickShift : Module( } listener { event -> - if (!isActive || !shiftVelocity) return@listener + if (!isActive || !grim || !shiftVelocity || event.isCanceled()) return@listener if (event.packet !is EntityVelocityUpdateS2CPacket) return@listener if (event.packet.id != player.id) return@listener From 81a0c6324759ea41d7bb7bebbb313eae668cd26e Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:30:30 -0400 Subject: [PATCH 03/20] various performance tweaks (3x faster load time) --- common/build.gradle.kts | 1 + .../graphics/renderer/gui/font/LambdaEmoji.kt | 2 +- .../renderer/gui/font/glyph/EmojiGlyphs.kt | 31 ++++---- .../renderer/gui/font/glyph/FontGlyphs.kt | 66 +++++++++------- .../lambda/graphics/texture/MipmapTexture.kt | 8 +- .../lambda/graphics/texture/TextureUtils.kt | 30 +++----- .../main/kotlin/com/lambda/http/Request.kt | 23 ++++-- .../module/modules/client/RenderSettings.kt | 7 +- .../kotlin/com/lambda/util/FolderRegister.kt | 75 ++++++++++++++++++- fabric/build.gradle.kts | 1 + forge/build.gradle.kts | 10 +-- neoforge/build.gradle.kts | 1 + 12 files changed, 170 insertions(+), 85 deletions(-) diff --git a/common/build.gradle.kts b/common/build.gradle.kts index c918e1820..07481fb66 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { // Add dependencies on the required Kotlin modules. implementation("org.reflections:reflections:0.10.2") implementation("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") + implementation("com.pngencoder:pngencoder:0.15.0") // Add Kotlin implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt index 87cef41fd..8d8f85f48 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt @@ -17,7 +17,7 @@ enum class LambdaEmoji(private val zipUrl: String) { object Loader : Loadable { override fun load(): String { entries.forEach(LambdaEmoji::loadGlyphs) - return "Loaded ${entries.size} emoji pools" + return "Loaded ${entries.size} emoji sets" } } } diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt index d8f92e6e6..0405a0dcf 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt @@ -3,23 +3,22 @@ package com.lambda.graphics.renderer.gui.font.glyph import com.google.common.math.IntMath.pow import com.lambda.Lambda.LOG import com.lambda.graphics.texture.MipmapTexture +import com.lambda.http.Method +import com.lambda.http.request import com.lambda.module.modules.client.RenderSettings -import com.lambda.threading.runGameScheduled -import com.lambda.threading.runIO import com.lambda.util.math.Vec2d import java.awt.Color import java.awt.Graphics2D import java.awt.image.BufferedImage import java.io.File -import java.net.URL import java.util.zip.ZipFile import javax.imageio.ImageIO import kotlin.math.ceil import kotlin.math.log2 import kotlin.math.sqrt import kotlin.system.measureTimeMillis +import kotlin.time.Duration.Companion.days -// TODO: AbstractGlyphs to use for both Font & Emoji glyphs? class EmojiGlyphs(zipUrl: String) { private val emojiMap = mutableMapOf() private lateinit var fontTexture: MipmapTexture @@ -29,9 +28,7 @@ class EmojiGlyphs(zipUrl: String) { init { runCatching { - val time = measureTimeMillis { - downloadAndProcessZip(zipUrl) - } + val time = measureTimeMillis { downloadAndProcessZip(zipUrl) } LOG.info("Loaded ${emojiMap.size} emojis in $time ms") }.onFailure { LOG.error("Failed to load emojis: ${it.message}", it) @@ -40,14 +37,20 @@ class EmojiGlyphs(zipUrl: String) { } private fun downloadAndProcessZip(zipUrl: String) { - val file = File.createTempFile("emoji", ".zip").apply { deleteOnExit() } + val file = request(zipUrl) { + method(Method.GET) + }.maybeDownload("emojis.zip", maxAge = 30.days) - URL(zipUrl).openStream().use { input -> - file.outputStream().use { output -> - input.copyTo(output) - } - } + fontTexture = MipmapTexture(processZip(file)) + } + /** + * Processes the given zip file and loads the emojis into the texture. + * + * @param file The zip file containing the emojis. + * @return The texture containing the emojis. + */ + private fun processZip(file: File): BufferedImage { ZipFile(file).use { zip -> val firstImage = ImageIO.read(zip.getInputStream(zip.entries().nextElement())) val length = zip.size().toDouble() @@ -90,7 +93,7 @@ class EmojiGlyphs(zipUrl: String) { } } - fontTexture = MipmapTexture(image) + return image } fun bind() { diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt index e00cbb284..3c492b26b 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt @@ -1,6 +1,6 @@ package com.lambda.graphics.renderer.gui.font.glyph -import com.lambda.Lambda +import com.lambda.Lambda.LOG import com.lambda.graphics.texture.MipmapTexture import com.lambda.graphics.texture.TextureUtils.getCharImage import com.lambda.module.modules.client.RenderSettings @@ -13,52 +13,60 @@ import java.awt.image.BufferedImage import kotlin.math.max import kotlin.system.measureTimeMillis -class FontGlyphs(font: Font) { +class FontGlyphs( + private val font: Font +) { private val charMap = Int2ObjectOpenHashMap() - private val fontTexture: MipmapTexture + private lateinit var fontTexture: MipmapTexture var fontHeight = 0.0; private set init { - val time = measureTimeMillis { - val image = BufferedImage(TEXTURE_SIZE, TEXTURE_SIZE, BufferedImage.TYPE_INT_ARGB) + runCatching { + val time = measureTimeMillis { processGlyphs() } + LOG.info("Font ${font.fontName} loaded with ${charMap.size} characters in $time ms") + }.onFailure { + LOG.error("Failed to load font glyphs: ${it.message}", it) + fontTexture = MipmapTexture(BufferedImage(1024, 1024, BufferedImage.TYPE_INT_ARGB)) + } + } - val graphics = image.graphics as Graphics2D - graphics.background = Color(0, 0, 0, 0) + private fun processGlyphs() { + val image = BufferedImage(TEXTURE_SIZE, TEXTURE_SIZE, BufferedImage.TYPE_INT_ARGB) - var x = 0 - var y = 0 - var rowHeight = 0 + val graphics = image.graphics as Graphics2D + graphics.background = Color(0, 0, 0, 0) - (Char.MIN_VALUE.. - val charImage = getCharImage(font, char) ?: return@forEach + var x = 0 + var y = 0 + var rowHeight = 0 - rowHeight = max(rowHeight, charImage.height + STEP) + (Char.MIN_VALUE.. + val charImage = getCharImage(font, char) ?: return@forEach - if (x + charImage.width >= TEXTURE_SIZE) { - y += rowHeight - x = 0 - rowHeight = 0 - } + rowHeight = max(rowHeight, charImage.height + STEP) - check(y + charImage.height <= TEXTURE_SIZE) { "Can't load font glyphs. Texture size is too small" } + if (x + charImage.width >= TEXTURE_SIZE) { + y += rowHeight + x = 0 + rowHeight = 0 + } - graphics.drawImage(charImage, x, y, null) + check(y + charImage.height <= TEXTURE_SIZE) { "Can't load font glyphs. Texture size is too small" } - val size = Vec2d(charImage.width, charImage.height) - val uv1 = Vec2d(x, y) * ONE_TEXEL_SIZE - val uv2 = Vec2d(x, y).plus(size) * ONE_TEXEL_SIZE + graphics.drawImage(charImage, x, y, null) - charMap[char.code] = GlyphInfo(size, uv1, uv2) - fontHeight = max(fontHeight, size.y) + val size = Vec2d(charImage.width, charImage.height) + val uv1 = Vec2d(x, y) * ONE_TEXEL_SIZE + val uv2 = Vec2d(x, y).plus(size) * ONE_TEXEL_SIZE - x += charImage.width + STEP - } + charMap[char.code] = GlyphInfo(size, uv1, uv2) + fontHeight = max(fontHeight, size.y) - fontTexture = MipmapTexture(image) + x += charImage.width + STEP } - Lambda.LOG.info("Font ${font.fontName} loaded with ${charMap.size} characters in $time ms") + fontTexture = MipmapTexture(image) } fun bind() { diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/MipmapTexture.kt b/common/src/main/kotlin/com/lambda/graphics/texture/MipmapTexture.kt index f52906d64..ea918e92a 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/MipmapTexture.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/MipmapTexture.kt @@ -36,7 +36,13 @@ class MipmapTexture(image: BufferedImage, levels: Int = 4) : Texture() { } companion object { + /** + * Retrieves an image from the resources folder and generates a mipmap texture. + * + * @param path The path to the image. + * @param levels The number of mipmap levels. + */ fun fromResource(path: String, levels: Int = 4): MipmapTexture = MipmapTexture(ImageIO.read(LambdaResource(path).stream), levels) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt index 5bb814180..5ed6289cb 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt @@ -1,19 +1,22 @@ package com.lambda.graphics.texture +import com.lambda.module.modules.client.RenderSettings import com.mojang.blaze3d.systems.RenderSystem +import com.pngencoder.PngEncoder import net.minecraft.client.texture.NativeImage import org.lwjgl.BufferUtils -import org.lwjgl.opengl.GL13C.* +import org.lwjgl.opengl.GL45C.* import java.awt.* import java.awt.image.BufferedImage import java.io.ByteArrayOutputStream -import javax.imageio.ImageIO import kotlin.math.roundToInt import kotlin.math.sqrt object TextureUtils { private val metricCache = mutableMapOf() - + private val encoderPreset = PngEncoder() + .withCompressionLevel(RenderSettings.textureCompression) + .withMultiThreadedCompressionEnabled(RenderSettings.threadedCompression) fun bindTexture(id: Int, slot: Int = 0) { RenderSystem.activeTexture(GL_TEXTURE0 + slot) @@ -35,21 +38,6 @@ object TextureUtils { // Array of floats normalized to [0.0, 1.0] -> [R, G, B, A] glTexImage2D(GL_TEXTURE_2D, lod, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, readImage(bufferedImage)) - // I'd also like to use glTexSubImage2D, but we have an issue where the function - // would return an error about an invalid texture format. - // - // It would allow us to upload texture data asynchronously and is more efficient - // from testing we gain approximately 20% runtime performance. - // If someone with advanced OpenGL knowledge could help us out, that would be great. - // (Very unlikely to happen, but I can hope) - // - // I've also read online that glTexStorage2D can be used for the same purpose as - // glTexImage2D with NULL data. - // However, some users may have ancient hardware that does not support this function. - // as it was implemented in OpenGL 4.2 and ES 3.0. - // - // glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readImage(bufferedImage)) - setupTexture(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR) } @@ -73,10 +61,10 @@ object TextureUtils { } private fun readImage(bufferedImage: BufferedImage): Long { - val stream = ByteArrayOutputStream() - ImageIO.write(bufferedImage, "png", stream) + val bytes = encoderPreset + .withBufferedImage(bufferedImage) + .toBytes() - val bytes = stream.toByteArray() val buffer = BufferUtils .createByteBuffer(bytes.size) .put(bytes) diff --git a/common/src/main/kotlin/com/lambda/http/Request.kt b/common/src/main/kotlin/com/lambda/http/Request.kt index f975fa0ff..c3002601c 100644 --- a/common/src/main/kotlin/com/lambda/http/Request.kt +++ b/common/src/main/kotlin/com/lambda/http/Request.kt @@ -2,10 +2,12 @@ package com.lambda.http import com.lambda.Lambda import com.lambda.util.FolderRegister.cache +import com.lambda.util.FolderRegister.createFileIfNotExists +import com.lambda.util.FolderRegister.createIfNotExists import java.io.File +import java.io.OutputStream import java.net.HttpURLConnection import java.net.URL -import java.time.Instant import kotlin.time.Duration import kotlin.time.Duration.Companion.days @@ -33,14 +35,21 @@ data class Request( /** * Downloads the resource at the specified path and caches it for future use. * - * @param path The path to the resource. + * @param name The full name of the file to be cached. * @param maxAge The maximum age of the cached resource. Default is 4 days. + * + * @return A pair containing the cached file and a boolean indicating whether the file was downloaded. */ - fun maybeDownload(path: String, maxAge: Duration = 4.days): ByteArray { - val file = File("${cache}/${path.substringAfterLast("/").hashCode()}") + fun maybeDownload( + name: String, + maxAge: Duration = 7.days, + ): File { + val (file, wasCreated) = createFileIfNotExists(name, cache, true) - if (file.exists() && Instant.now().toEpochMilli() - file.lastModified() < maxAge.inWholeMilliseconds) - return file.readBytes() + if (System.currentTimeMillis() - file.lastModified() < maxAge.inWholeMilliseconds + && file.length() > 0 + && !wasCreated) + return file file.writeText("") // Clear the file before writing to it. @@ -64,7 +73,7 @@ data class Request( } } - return file.readBytes() + return file } /** diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt index c2726bd6f..ec29fad21 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt @@ -18,6 +18,10 @@ object RenderSettings : Module( val baselineOffset by setting("Vertical Offset", 0.0, -10.0..10.0, 0.5) { page == Page.Font } private val lodBiasSetting by setting("Smoothing", 0.0, -10.0..10.0, 0.5) { page == Page.Font } + // Texture + val textureCompression by setting("Compression", 1, 1..9, 1, description = "Texture compression level, higher is slower") { page == Page.TEXTURE } + val threadedCompression by setting("Threaded Compression", false, description = "Use multiple threads for texture compression") { page == Page.TEXTURE } + // ESP val uploadsPerTick by setting("Uploads", 16, 1..256, 1, unit = " chunk/tick") { page == Page.ESP } val rebuildsPerTick by setting("Rebuilds", 64, 1..256, 1, unit = " chunk/tick") { page == Page.ESP } @@ -28,6 +32,7 @@ object RenderSettings : Module( private enum class Page { Font, - ESP + TEXTURE, + ESP, } } diff --git a/common/src/main/kotlin/com/lambda/util/FolderRegister.kt b/common/src/main/kotlin/com/lambda/util/FolderRegister.kt index 26af87db9..86e698d57 100644 --- a/common/src/main/kotlin/com/lambda/util/FolderRegister.kt +++ b/common/src/main/kotlin/com/lambda/util/FolderRegister.kt @@ -8,8 +8,11 @@ import com.lambda.util.FolderRegister.mods import com.lambda.util.FolderRegister.packetLogs import com.lambda.util.FolderRegister.replay import com.lambda.util.StringUtils.sanitizeForFilename +import org.apache.commons.codec.digest.DigestUtils import java.io.File +import java.io.InputStream import java.net.InetSocketAddress +import java.security.MessageDigest /** * The [FolderRegister] object is responsible for managing the directory structure of the application. @@ -31,9 +34,7 @@ object FolderRegister { val cache: File = File(lambda, "cache") fun File.createIfNotExists() { - if (!exists()) { - mkdirs() - } + createFileIfNotExists(this.name, this.parentFile) } fun File.listRecursive(predicate: (File) -> Boolean = { true }) = walk().filter(predicate) @@ -48,4 +49,72 @@ object FolderRegister { path.createIfNotExists() return path } + + /** + * Returns a file with the given name in the specified directory, creating it if it does not exist. + * If the directory is not specified, it will try to parse it from the name. + * Otherwise, it will default to the Lambda directory. + * + * @param name The name of the file. + * @param directory The directory in which the file is located. Default is the Lambda directory. + * @param hash Whether to hash the name of the file. + * @return A pair containing the file and a boolean indicating whether the file was created. + */ + fun createFileIfNotExists(name: String, directory: File? = null, hash: Boolean = false): Pair { + var parsedDir: File = directory ?: lambda + + if (directory == null) { + parsedDir = name.substringAfterLast('/').substringBeforeLast('.') + .let { if (it.isEmpty()) lambda else File(it) } + } + + val compiledName = + if (hash) DigestUtils.sha256Hex(name) + else name + + val file = File(parsedDir, compiledName) + val created = !file.exists() + + if (created) { + file.parentFile.mkdirs() + file.createNewFile() + } + + return file to created + } + + + /** + * Returns a file with the given name in the specified directory, creating it if it does not exist. + * If the directory is not specified, it will try to parse it from the name. + * Otherwise, it will default to the Lambda directory. + * + * @param name The name of the file. + * @param directory The directory in which the file is located. Default is the Lambda directory. + * @param compute A lambda function to compute the file contents if it was created. + */ + @JvmName("getFileOrComputeByteArray") + inline fun getFileOrCompute(name: String, directory: File? = null, compute: () -> ByteArray): File { + val (file, wasCreated) = createFileIfNotExists(name, directory) + if (wasCreated) file.outputStream().use { it.write(compute()) } + + return file + } + + /** + * Returns a file with the given name in the specified directory, creating it if it does not exist. + * If the directory is not specified, it will try to parse it from the name. + * Otherwise, it will default to the Lambda directory. + * + * @param name The name of the file. + * @param directory The directory in which the file is located. Default is the Lambda directory. + * @param compute A lambda function to compute the file contents if it was created. + */ + @JvmName("getFileOrComputeInputStream") + inline fun getFileOrCompute(name: String, directory: File? = null, compute: () -> InputStream): File { + val (file, wasCreated) = createFileIfNotExists(name, directory) + if (wasCreated) file.outputStream().use { compute().copyTo(it) } + + return file + } } diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 2cbb32749..8844cc10f 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -67,6 +67,7 @@ dependencies { includeLib("org.javassist:javassist:3.28.0-GA") includeLib("dev.babbaj:nether-pathfinder:1.5") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") + includeLib("com.pngencoder:pngencoder:0.15.0") // Add mods to the mod jar includeMod("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion+$minecraftVersion") diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index 479861fa3..935fa55ed 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -80,14 +80,8 @@ dependencies { // Add dependencies on the required Kotlin modules. includeLib("org.reflections:reflections:0.10.2") includeLib("org.javassist:javassist:3.28.0-GA") - - // Temporary, only works for production - // See https://github.com/MinecraftForge/MinecraftForge/issues/8878 - includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") { - exclude(group = "org.jetbrains.kotlin") - exclude(group = "org.jetbrains.kotlinx") - exclude(group = "org.slf4j") - } + includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") + includeLib("com.pngencoder:pngencoder:0.15.0") // Add mods to the mod jar includeMod("thedarkcolour:kotlinforforge:$kotlinForgeVersion") diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 12c4af40c..9978da288 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -68,6 +68,7 @@ dependencies { includeLib("org.javassist:javassist:3.28.0-GA") includeLib("dev.babbaj:nether-pathfinder:1.5") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") + includeLib("com.pngencoder:pngencoder:0.15.0") // Add mods to the mod jar includeMod("thedarkcolour:kotlinforforge-neoforge:$kotlinForgeVersion") From ea972be77204e4f0e97fb2de1f95589b18ee54b3 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:16:07 -0400 Subject: [PATCH 04/20] todo: pixel buffer object --- .../com/lambda/graphics/buffer/PixelBuffer.kt | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt new file mode 100644 index 000000000..26e0e9828 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt @@ -0,0 +1,66 @@ +package com.lambda.graphics.buffer + +import org.lwjgl.opengl.GL45C.* +import java.nio.ByteBuffer + +// NOT TESTED +class PixelBuffer( + width: Int, + height: Int +) { + private val pboIds = IntArray(2) { 0 } + private var index = 0 + + fun upload(data: ByteBuffer, block: () -> Unit) { + // Bind the current PBO for writing + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]) + + // Map the buffer and copy data into it + val bufferData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY) as ByteBuffer + bufferData.put(data) + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER) + + // Process the data + block() + + // Unbind the buffer + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) + + // Switch to the other PBO + index = (index + 1) % 2 + } + + fun download(): ByteBuffer { + // Bind the current PBO for reading + glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[index]) + + // Map the buffer and copy data from it + val bufferData = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY) as ByteBuffer + val data = bufferData.slice() + + // Unbind the buffer + glUnmapBuffer(GL_PIXEL_PACK_BUFFER) + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0) + + return data + } + + fun finalize() { + // Delete the PBOs + glDeleteBuffers(pboIds) + } + + init { + // Generate the PBOs + glGenBuffers(pboIds) + + // Fill the buffers with null data to allocate the memory spaces + glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[0]) + glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4L, GL_DYNAMIC_READ) + glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[1]) + glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4L, GL_DYNAMIC_READ) + + // Unbind the buffer + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0) + } +} From c6328ca34cd436ab7c246578d39b9c575da54c66 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:25:45 -0400 Subject: [PATCH 05/20] pixel n-buffer object --- .../com/lambda/graphics/buffer/PixelBuffer.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt index 26e0e9828..97a53fbaf 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt @@ -6,9 +6,10 @@ import java.nio.ByteBuffer // NOT TESTED class PixelBuffer( width: Int, - height: Int + height: Int, + buffers: Int = 2 ) { - private val pboIds = IntArray(2) { 0 } + private val pboIds = IntArray(buffers) { 0 } private var index = 0 fun upload(data: ByteBuffer, block: () -> Unit) { @@ -27,7 +28,7 @@ class PixelBuffer( glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) // Switch to the other PBO - index = (index + 1) % 2 + index = (index + 1) % pboIds.size } fun download(): ByteBuffer { @@ -55,10 +56,10 @@ class PixelBuffer( glGenBuffers(pboIds) // Fill the buffers with null data to allocate the memory spaces - glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[0]) - glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4L, GL_DYNAMIC_READ) - glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[1]) - glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4L, GL_DYNAMIC_READ) + repeat(buffers) { + glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[it]) + glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4L, GL_DYNAMIC_READ) + } // Unbind the buffer glBindBuffer(GL_PIXEL_PACK_BUFFER, 0) From 7f35a62d8a5d92b16c92f5d721bc714b46014393 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:41:08 -0400 Subject: [PATCH 06/20] handle empty pbos --- .../com/lambda/graphics/buffer/PixelBuffer.kt | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt index 97a53fbaf..44b84a277 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt @@ -1,17 +1,31 @@ package com.lambda.graphics.buffer +import net.minecraft.client.texture.NativeImage import org.lwjgl.opengl.GL45C.* import java.nio.ByteBuffer -// NOT TESTED class PixelBuffer( - width: Int, - height: Int, - buffers: Int = 2 + private val width: Int, + private val height: Int, + private val buffers: Int = 2 ) { private val pboIds = IntArray(buffers) { 0 } private var index = 0 + fun mapTexture(id: Int, buffer: ByteBuffer) { + upload(buffer) { + // Bind the texture + glBindTexture(GL_TEXTURE_2D, id) + + if (buffers > 0) + // Copy the data from the PBO to the texture + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) + else + // Copy the data from the buffer to the texture + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NativeImage.read(buffer).pointer) + } + } + fun upload(data: ByteBuffer, block: () -> Unit) { // Bind the current PBO for writing glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]) @@ -28,7 +42,7 @@ class PixelBuffer( glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) // Switch to the other PBO - index = (index + 1) % pboIds.size + if (buffers > 0) index = (index + 1) % buffers } fun download(): ByteBuffer { From 1bba654d9f7f58f959a05d4114d29d43ea93324d Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:42:29 -0400 Subject: [PATCH 07/20] test: streaming to pbo --- common/build.gradle.kts | 1 + .../kotlin/com/lambda/graphics/RenderMain.kt | 2 +- .../buffer/{vao/vertex => }/BufferUsage.kt | 8 +- .../com/lambda/graphics/buffer/PixelBuffer.kt | 81 ---------------- .../graphics/buffer/{ => fbo}/FrameBuffer.kt | 4 +- .../lambda/graphics/buffer/pbo/PixelBuffer.kt | 97 +++++++++++++++++++ .../com/lambda/graphics/buffer/vao/VAO.kt | 2 +- .../graphics/renderer/esp/ChunkedESP.kt | 4 +- .../graphics/renderer/esp/global/StaticESP.kt | 4 +- .../renderer/esp/impl/DynamicESPRenderer.kt | 4 +- .../graphics/renderer/esp/impl/ESPRenderer.kt | 2 +- .../renderer/esp/impl/StaticESPRenderer.kt | 4 +- .../com/lambda/graphics/texture/Texture.kt | 6 +- .../com/lambda/graphics/video/JCodecUtils.kt | 74 ++++++++++++++ .../kotlin/com/lambda/graphics/video/Video.kt | 44 +++++++++ .../com/lambda/gui/impl/AbstractClickGui.kt | 8 +- .../kotlin/com/lambda/module/hud/VideoTest.kt | 22 +++++ fabric/build.gradle.kts | 28 ++++++ forge/build.gradle.kts | 1 + neoforge/build.gradle.kts | 1 + 20 files changed, 290 insertions(+), 107 deletions(-) rename common/src/main/kotlin/com/lambda/graphics/buffer/{vao/vertex => }/BufferUsage.kt (60%) delete mode 100644 common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt rename common/src/main/kotlin/com/lambda/graphics/buffer/{ => fbo}/FrameBuffer.kt (99%) create mode 100644 common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/video/Video.kt create mode 100644 common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 07481fb66..eb6433c76 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -24,6 +24,7 @@ dependencies { implementation("org.reflections:reflections:0.10.2") implementation("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") implementation("com.pngencoder:pngencoder:0.15.0") + implementation("org.jcodec:jcodec:0.2.3") // Add Kotlin implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") diff --git a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt index 998a21872..6eabe8442 100644 --- a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -7,7 +7,7 @@ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.animation.AnimationTicker -import com.lambda.graphics.buffer.FrameBuffer +import com.lambda.graphics.buffer.fbo.FrameBuffer import com.lambda.graphics.gl.GlStateUtils.setupGL import com.lambda.graphics.gl.Matrices import com.lambda.graphics.gl.Matrices.resetMatrices diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/BufferUsage.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/BufferUsage.kt similarity index 60% rename from common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/BufferUsage.kt rename to common/src/main/kotlin/com/lambda/graphics/buffer/BufferUsage.kt index 1cd56273d..7300d8e3f 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/BufferUsage.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/BufferUsage.kt @@ -1,10 +1,12 @@ -package com.lambda.graphics.buffer.vao.vertex +package com.lambda.graphics.buffer import com.lambda.graphics.gl.GLObject import org.lwjgl.opengl.GL30C.GL_DYNAMIC_DRAW import org.lwjgl.opengl.GL30C.GL_STATIC_DRAW +import org.lwjgl.opengl.GL30C.GL_STREAM_DRAW enum class BufferUsage(override val gl: Int) : GLObject { STATIC(GL_STATIC_DRAW), - DYNAMIC(GL_DYNAMIC_DRAW) -} \ No newline at end of file + DYNAMIC(GL_DYNAMIC_DRAW), + STREAM(GL_STREAM_DRAW); +} diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt deleted file mode 100644 index 44b84a277..000000000 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/PixelBuffer.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.lambda.graphics.buffer - -import net.minecraft.client.texture.NativeImage -import org.lwjgl.opengl.GL45C.* -import java.nio.ByteBuffer - -class PixelBuffer( - private val width: Int, - private val height: Int, - private val buffers: Int = 2 -) { - private val pboIds = IntArray(buffers) { 0 } - private var index = 0 - - fun mapTexture(id: Int, buffer: ByteBuffer) { - upload(buffer) { - // Bind the texture - glBindTexture(GL_TEXTURE_2D, id) - - if (buffers > 0) - // Copy the data from the PBO to the texture - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) - else - // Copy the data from the buffer to the texture - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NativeImage.read(buffer).pointer) - } - } - - fun upload(data: ByteBuffer, block: () -> Unit) { - // Bind the current PBO for writing - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]) - - // Map the buffer and copy data into it - val bufferData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY) as ByteBuffer - bufferData.put(data) - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER) - - // Process the data - block() - - // Unbind the buffer - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) - - // Switch to the other PBO - if (buffers > 0) index = (index + 1) % buffers - } - - fun download(): ByteBuffer { - // Bind the current PBO for reading - glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[index]) - - // Map the buffer and copy data from it - val bufferData = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY) as ByteBuffer - val data = bufferData.slice() - - // Unbind the buffer - glUnmapBuffer(GL_PIXEL_PACK_BUFFER) - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0) - - return data - } - - fun finalize() { - // Delete the PBOs - glDeleteBuffers(pboIds) - } - - init { - // Generate the PBOs - glGenBuffers(pboIds) - - // Fill the buffers with null data to allocate the memory spaces - repeat(buffers) { - glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[it]) - glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4L, GL_DYNAMIC_READ) - } - - // Unbind the buffer - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0) - } -} diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/FrameBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/fbo/FrameBuffer.kt similarity index 99% rename from common/src/main/kotlin/com/lambda/graphics/buffer/FrameBuffer.kt rename to common/src/main/kotlin/com/lambda/graphics/buffer/fbo/FrameBuffer.kt index e16e32891..25b3bd3bc 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/FrameBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/fbo/FrameBuffer.kt @@ -1,4 +1,4 @@ -package com.lambda.graphics.buffer +package com.lambda.graphics.buffer.fbo import com.lambda.Lambda.mc import com.lambda.graphics.RenderMain import com.lambda.graphics.buffer.vao.VAO @@ -124,4 +124,4 @@ class FrameBuffer(private val depth: Boolean = false) { private val vao = VAO(VertexMode.TRIANGLES, VertexAttrib.Group.POS_UV) private var lastFrameBuffer: Int? = null } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt new file mode 100644 index 000000000..0c5971dbe --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt @@ -0,0 +1,97 @@ +package com.lambda.graphics.buffer.pbo + +import com.lambda.graphics.buffer.BufferUsage +import com.lambda.graphics.texture.TextureUtils.setupTexture +import org.lwjgl.opengl.GL45C.* +import java.nio.ByteBuffer +import kotlin.system.measureNanoTime + +class PixelBuffer( + private val width: Int, + private val height: Int, + private val buffers: Int = 2, + private val bufferUsage: BufferUsage = BufferUsage.DYNAMIC, +) { + private val pboIds = IntArray(buffers) + private var writeIdx = 0 // Used to copy pixels from the PBO to the texture + private var uploadIdx = 0 // Used to upload data to the PBO + + fun mapTexture(id: Int, buffer: ByteBuffer) { + val time = measureNanoTime { + upload(buffer) { allocate -> + // Bind the texture + glBindTexture(GL_TEXTURE_2D, id) + + if (allocate) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + + // Allocate the texture memory + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0) + } + else { + // Update the texture + glTextureSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) + } + } + } + + println("PBO => texture $id took $time nanoseconds") + } + + fun upload(data: ByteBuffer, process: (Boolean) -> Unit) { + uploadIdx = (writeIdx + 1) % buffers + + // Bind the next PBO to update pixel values + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx]) + + // Allocate the memory for the buffer + process(true) + + // Map the buffer into the memory + val bufferData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY) + if (bufferData != null) { + bufferData.put(data) + + // Release the buffer + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER) + } else { + println("Failed to map the PBO") + } + + // Bind the current PBO for writing + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx]) + + // Copy the pixel values from the PBO to the texture + process(false) + + // Unbind the PBO + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) + + println("Uploaded data to PBO $uploadIdx at $bufferData") + + // Swap the indices + writeIdx = uploadIdx + } + + // Called when no references to the object exist + fun finalize() { + // Delete the PBOs + glDeleteBuffers(pboIds) + } + + init { + if (buffers < 1) throw IllegalArgumentException("Buffers must be greater than or equal to 1") + + // Generate the PBOs + glGenBuffers(pboIds) + + // Fill the buffers with null data to allocate the memory spaces + repeat(buffers) { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[it]) + glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4L, GL_STREAM_DRAW) + } + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) // Unbind the buffer + } +} diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt index b6cb584cc..ccec90409 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt @@ -1,6 +1,6 @@ package com.lambda.graphics.buffer.vao -import com.lambda.graphics.buffer.vao.vertex.BufferUsage +import com.lambda.graphics.buffer.BufferUsage import com.lambda.graphics.buffer.vao.vertex.VertexAttrib import com.lambda.graphics.buffer.vao.vertex.VertexMode import com.lambda.graphics.gl.Matrices diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt index 966fe139d..1d1f8ef2c 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt @@ -5,7 +5,7 @@ import com.lambda.event.events.TickEvent import com.lambda.event.events.WorldEvent import com.lambda.event.listener.SafeListener.Companion.concurrentListener import com.lambda.event.listener.SafeListener.Companion.listener -import com.lambda.graphics.buffer.vao.vertex.BufferUsage +import com.lambda.graphics.buffer.BufferUsage import com.lambda.graphics.renderer.esp.impl.ESPRenderer import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer import com.lambda.module.modules.client.RenderSettings @@ -126,4 +126,4 @@ class ChunkedESP private constructor( } } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt index 454d624b9..fa40ed0ca 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt @@ -4,7 +4,7 @@ import com.lambda.event.EventFlow.post import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener -import com.lambda.graphics.buffer.vao.vertex.BufferUsage +import com.lambda.graphics.buffer.BufferUsage import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer object StaticESP : StaticESPRenderer(BufferUsage.DYNAMIC, false) { @@ -15,4 +15,4 @@ object StaticESP : StaticESPRenderer(BufferUsage.DYNAMIC, false) { upload() } } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt index bf8f9a878..e9383f035 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt @@ -1,5 +1,5 @@ package com.lambda.graphics.renderer.esp.impl -import com.lambda.graphics.buffer.vao.vertex.BufferUsage +import com.lambda.graphics.buffer.BufferUsage -open class DynamicESPRenderer : ESPRenderer(BufferUsage.DYNAMIC, true) \ No newline at end of file +open class DynamicESPRenderer : ESPRenderer(BufferUsage.DYNAMIC, true) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/ESPRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/ESPRenderer.kt index c35a4a2e5..15d0977da 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/ESPRenderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/ESPRenderer.kt @@ -2,7 +2,7 @@ package com.lambda.graphics.renderer.esp.impl import com.lambda.Lambda.mc import com.lambda.graphics.buffer.vao.VAO -import com.lambda.graphics.buffer.vao.vertex.BufferUsage +import com.lambda.graphics.buffer.BufferUsage import com.lambda.graphics.buffer.vao.vertex.VertexAttrib import com.lambda.graphics.buffer.vao.vertex.VertexMode import com.lambda.graphics.gl.GlStateUtils.withFaceCulling diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt index 26c7c9140..592412dde 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt @@ -1,7 +1,7 @@ package com.lambda.graphics.renderer.esp.impl import com.lambda.graphics.buffer.vao.IRenderContext -import com.lambda.graphics.buffer.vao.vertex.BufferUsage +import com.lambda.graphics.buffer.BufferUsage import java.awt.Color import java.util.concurrent.ConcurrentHashMap @@ -45,4 +45,4 @@ open class StaticESPRenderer( } data class Vertex(val x: Double, val y: Double, val z: Double, val color: Color) -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/Texture.kt b/common/src/main/kotlin/com/lambda/graphics/texture/Texture.kt index 7512b523b..ff5990c87 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/Texture.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/Texture.kt @@ -1,12 +1,10 @@ package com.lambda.graphics.texture import com.lambda.graphics.texture.TextureUtils.bindTexture -import com.lambda.threading.mainThread -import com.lambda.threading.runGameScheduled import org.lwjgl.opengl.GL13.glGenTextures -abstract class Texture { - private val id = glGenTextures() +open class Texture { + val id = glGenTextures() fun bind(slot: Int = 0) = bindTexture(id, slot) } diff --git a/common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt b/common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt new file mode 100644 index 000000000..d95392d01 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt @@ -0,0 +1,74 @@ +package com.lambda.graphics.video + +import org.jcodec.api.FrameGrab +import org.jcodec.common.io.NIOUtils +import org.jcodec.common.model.ColorSpace +import org.jcodec.common.model.Picture +import org.jcodec.scale.ColorUtil +import org.jcodec.scale.RgbToBgr +import java.awt.image.BufferedImage +import java.awt.image.DataBufferByte +import java.io.File + +object JCodecUtils { + fun demuxVideo(path: String): FrameGrab = + FrameGrab.createFrameGrab(NIOUtils.readableChannel(File(path))) + + fun toBufferedImage(src: Picture): BufferedImage { + val processedSrc = convertToBGR(src) + val dst = BufferedImage(processedSrc.croppedWidth, processedSrc.croppedHeight, BufferedImage.TYPE_3BYTE_BGR) + + if (processedSrc.crop == null) { + copyImageData(processedSrc, dst) + } else { + copyCroppedImageData(processedSrc, dst) + } + + return dst + } + + private fun convertToBGR(src: Picture): Picture { + if (src.color == ColorSpace.BGR) return src + + val bgr = Picture.createCropped(src.width, src.height, ColorSpace.BGR, src.crop) + + if (src.color == ColorSpace.RGB) { + RgbToBgr().transform(src, bgr) + } else { + val transform = ColorUtil.getTransform(src.color, ColorSpace.RGB) + transform.transform(src, bgr) + RgbToBgr().transform(bgr, bgr) + } + + return bgr + } + + private fun copyImageData(src: Picture, dst: BufferedImage) { + val data = (dst.raster.dataBuffer as DataBufferByte).data + val srcData = src.getPlaneData(0) + + for (i in data.indices) { + data[i] = (srcData[i] + 128).toByte() + } + } + + private fun copyCroppedImageData(src: Picture, dst: BufferedImage) { + val data = (dst.raster.dataBuffer as DataBufferByte).data + val srcData = src.getPlaneData(0) + val dstStride = dst.width * 3 + val srcStride = src.width * 3 + + for (line in 0 until dst.height) { + var dstOffset = line * dstStride + var srcOffset = line * srcStride + + for (x in 0 until dstStride step 3) { + data[dstOffset] = (srcData[srcOffset] + 128).toByte() + data[dstOffset + 1] = (srcData[srcOffset + 1] + 128).toByte() + data[dstOffset + 2] = (srcData[srcOffset + 2] + 128).toByte() + dstOffset += 3 + srcOffset += 3 + } + } + } +} diff --git a/common/src/main/kotlin/com/lambda/graphics/video/Video.kt b/common/src/main/kotlin/com/lambda/graphics/video/Video.kt new file mode 100644 index 000000000..beff72f0e --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/video/Video.kt @@ -0,0 +1,44 @@ +package com.lambda.graphics.video + +import com.lambda.graphics.buffer.BufferUsage +import com.lambda.graphics.buffer.pbo.PixelBuffer +import com.lambda.graphics.texture.Texture +import com.lambda.graphics.video.JCodecUtils.toBufferedImage +import com.pngencoder.PngEncoder +import java.io.File +import java.nio.ByteBuffer +import javax.imageio.ImageIO + + +class Video( + private val input: String, +) { + private val decoderStream = JCodecUtils.demuxVideo(input) + + val width = decoderStream.mediaInfo.dim.width + val height = decoderStream.mediaInfo.dim.height + + private val pbo = PixelBuffer(width, height, buffers = 2, bufferUsage = BufferUsage.STREAM) + val texture = Texture() + + fun upload() { + val picture = decoderStream.nativeFrame + if (picture == null) { + decoderStream.seekToFramePrecise(0) + return + } + + val image = toBufferedImage(picture) + + val bytes = PngEncoder() + .withBufferedImage(image) + .toBytes() + + val buffer = + ByteBuffer.allocateDirect(bytes.size) + .put(bytes) + .flip() + + pbo.mapTexture(texture.id, buffer) + } +} diff --git a/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt index aca17d474..6170d4cfb 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt @@ -2,7 +2,7 @@ package com.lambda.gui.impl import com.lambda.Lambda.mc import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.graphics.buffer.FrameBuffer +import com.lambda.graphics.buffer.fbo.FrameBuffer import com.lambda.graphics.shader.Shader import com.lambda.gui.AbstractGuiConfigurable import com.lambda.gui.GuiConfigurable @@ -10,17 +10,13 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildLayer -import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.TagWindow -import com.lambda.gui.impl.hudgui.LambdaHudGui import com.lambda.module.Module import com.lambda.module.modules.client.ClickGui import com.lambda.util.Mouse -import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall -import kotlin.reflect.KMutableProperty import kotlin.reflect.KMutableProperty0 abstract class AbstractClickGui(name: String, owner: Module? = null) : LambdaGui(name, owner) { @@ -128,4 +124,4 @@ abstract class AbstractClickGui(name: String, owner: Module? = null) : LambdaGui if (!isOpen) return closing = true } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt b/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt new file mode 100644 index 000000000..cf3a7ac83 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt @@ -0,0 +1,22 @@ +package com.lambda.module.hud + +import com.lambda.graphics.renderer.gui.TextureRenderer.drawTexture +import com.lambda.graphics.video.Video +import com.lambda.module.HudModule + +object VideoTest : HudModule( + name = "VideoTest", + defaultTags = setOf(), +) { + override val width = 430.0 + override val height = 548.0 + + private val video = Video("C:\\Users\\Kamigen\\Documents\\weed.mp4") + + init { + onRender { + video.upload() + drawTexture(video.texture, rect) + } + } +} diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 8844cc10f..d0d60bf8e 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -1,3 +1,5 @@ +import org.gradle.internal.jvm.Jvm + val modVersion: String by project val minecraftVersion: String by project val fabricLoaderVersion: String by project @@ -68,6 +70,7 @@ dependencies { includeLib("dev.babbaj:nether-pathfinder:1.5") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") includeLib("com.pngencoder:pngencoder:0.15.0") + includeLib("org.jcodec:jcodec:0.2.3") // Add mods to the mod jar includeMod("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion+$minecraftVersion") @@ -100,4 +103,29 @@ tasks { // They allow you to make field, method, and class access public. injectAccessWidener = true } + + register("run + RenderDoc") { + val javaHome = Jvm.current().javaHome + + commandLine = listOf( + "C:\\Program Files\\RenderDoc\\renderdoccmd.exe", + "capture", + "--opt-api-validation", + "--opt-api-validation-unmute", + "--opt-hook-children", + "--wait-for-exit", + "--working-dir", + ".", + "$javaHome/bin/java.exe", + "-Xmx64m", + "-Xms64m", + //"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005", + "-Dorg.gradle.appname=gradlew", + "-Dorg.gradle.java.home=$javaHome", + "-classpath", + "C:\\Users\\Kamigen\\Desktop\\BetterElytraBot\\NeoLambda\\gradle\\wrapper\\gradle-wrapper.jar", + "org.gradle.wrapper.GradleWrapperMain", + ":fabric:runClient", + ) + } } diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index 935fa55ed..bf6133cdf 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -82,6 +82,7 @@ dependencies { includeLib("org.javassist:javassist:3.28.0-GA") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") includeLib("com.pngencoder:pngencoder:0.15.0") + includeLib("org.jcodec:jcodec:0.2.3") // Add mods to the mod jar includeMod("thedarkcolour:kotlinforforge:$kotlinForgeVersion") diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 9978da288..4693ae091 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -69,6 +69,7 @@ dependencies { includeLib("dev.babbaj:nether-pathfinder:1.5") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") includeLib("com.pngencoder:pngencoder:0.15.0") + includeLib("org.jcodec:jcodec:0.2.3") // Add mods to the mod jar includeMod("thedarkcolour:kotlinforforge-neoforge:$kotlinForgeVersion") From 06aba2d8aa6ea37cc2f37f906ca0136062eb1ff4 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:35:03 -0400 Subject: [PATCH 08/20] added upload record time --- .../lambda/graphics/buffer/pbo/PixelBuffer.kt | 88 +++++++++---------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt index 0c5971dbe..e10bf7cd5 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt @@ -1,10 +1,8 @@ package com.lambda.graphics.buffer.pbo import com.lambda.graphics.buffer.BufferUsage -import com.lambda.graphics.texture.TextureUtils.setupTexture import org.lwjgl.opengl.GL45C.* import java.nio.ByteBuffer -import kotlin.system.measureNanoTime class PixelBuffer( private val width: Int, @@ -16,62 +14,58 @@ class PixelBuffer( private var writeIdx = 0 // Used to copy pixels from the PBO to the texture private var uploadIdx = 0 // Used to upload data to the PBO - fun mapTexture(id: Int, buffer: ByteBuffer) { - val time = measureNanoTime { - upload(buffer) { allocate -> - // Bind the texture - glBindTexture(GL_TEXTURE_2D, id) - - if (allocate) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - // Allocate the texture memory - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0) - } - else { - // Update the texture - glTextureSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) - } - } + private val queryId = glGenQueries() // Used to measure the time taken to upload data to the PBO + val uploadTime get() = IntArray(1).also { glGetQueryObjectiv(queryId, GL_QUERY_RESULT, it) }[0] + + fun mapTexture(id: Int, buffer: ByteBuffer) = + upload(buffer) { + // Bind the texture + glBindTexture(GL_TEXTURE_2D, id) + + // Perform the actual data transfer to the GPU + glTextureSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) } - println("PBO => texture $id took $time nanoseconds") - } + fun upload(data: ByteBuffer, process: () -> Unit) = + recordTransfer { + uploadIdx = (writeIdx + 1) % buffers - fun upload(data: ByteBuffer, process: (Boolean) -> Unit) { - uploadIdx = (writeIdx + 1) % buffers + // Bind the next PBO to update pixel values + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx]) - // Bind the next PBO to update pixel values - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx]) + // Map the buffer into the memory + val bufferData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY) + if (bufferData != null) { + bufferData.put(data) - // Allocate the memory for the buffer - process(true) + // Release the buffer + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER) + } else { + println("Failed to map the PBO") + } - // Map the buffer into the memory - val bufferData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY) - if (bufferData != null) { - bufferData.put(data) + // Bind the current PBO for writing + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx]) - // Release the buffer - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER) - } else { - println("Failed to map the PBO") - } + // Copy the pixel values from the PBO to the texture + process() - // Bind the current PBO for writing - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx]) + // Unbind the PBO + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) - // Copy the pixel values from the PBO to the texture - process(false) + // Swap the indices + writeIdx = uploadIdx + } - // Unbind the PBO - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) + private fun recordTransfer(block: () -> Unit) { + // Start the timer + glBeginQuery(GL_TIME_ELAPSED, queryId) - println("Uploaded data to PBO $uploadIdx at $bufferData") + // Perform the transfer + block() - // Swap the indices - writeIdx = uploadIdx + // Stop the timer + glEndQuery(GL_TIME_ELAPSED) } // Called when no references to the object exist @@ -89,7 +83,7 @@ class PixelBuffer( // Fill the buffers with null data to allocate the memory spaces repeat(buffers) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[it]) - glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4L, GL_STREAM_DRAW) + glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4L, bufferUsage.gl) } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) // Unbind the buffer From 68b24da1629bf9eb621fec4cd2701bbd44eacd4a Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:45:25 -0400 Subject: [PATCH 09/20] added debug gremedy labels --- .../kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt index e10bf7cd5..7f7a8cd3b 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt @@ -2,6 +2,7 @@ package com.lambda.graphics.buffer.pbo import com.lambda.graphics.buffer.BufferUsage import org.lwjgl.opengl.GL45C.* +import org.lwjgl.opengl.GREMEDYStringMarker import java.nio.ByteBuffer class PixelBuffer( @@ -30,6 +31,8 @@ class PixelBuffer( recordTransfer { uploadIdx = (writeIdx + 1) % buffers + GREMEDYStringMarker.glStringMarkerGREMEDY("Data transfer to buffer") + // Bind the next PBO to update pixel values glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx]) @@ -47,6 +50,8 @@ class PixelBuffer( // Bind the current PBO for writing glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx]) + GREMEDYStringMarker.glStringMarkerGREMEDY("Data transfer to GPU") + // Copy the pixel values from the PBO to the texture process() From 12e2045b5697e6570ae84af4ed78a368e43f4614 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:40:26 -0400 Subject: [PATCH 10/20] better pbo --- .../lambda/graphics/buffer/pbo/PixelBuffer.kt | 73 ++++++++++++++----- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt index 7f7a8cd3b..c743e104f 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt @@ -1,8 +1,9 @@ package com.lambda.graphics.buffer.pbo +import com.lambda.Lambda.LOG import com.lambda.graphics.buffer.BufferUsage +import org.lwjgl.opengl.GL import org.lwjgl.opengl.GL45C.* -import org.lwjgl.opengl.GREMEDYStringMarker import java.nio.ByteBuffer class PixelBuffer( @@ -17,24 +18,51 @@ class PixelBuffer( private val queryId = glGenQueries() // Used to measure the time taken to upload data to the PBO val uploadTime get() = IntArray(1).also { glGetQueryObjectiv(queryId, GL_QUERY_RESULT, it) }[0] + var transferRate = 0L // The transfer rate in bytes per second + private set + + var pboSupported = false + private set fun mapTexture(id: Int, buffer: ByteBuffer) = upload(buffer) { // Bind the texture glBindTexture(GL_TEXTURE_2D, id) - // Perform the actual data transfer to the GPU - glTextureSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) + if (buffers > 0 && pboSupported) { + // Bind the next PBO to update pixel values + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx]) + + // Perform the actual data transfer to the GPU + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) + } + else { + // Perform the actual data transfer to the GPU + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer) + } } fun upload(data: ByteBuffer, process: () -> Unit) = recordTransfer { - uploadIdx = (writeIdx + 1) % buffers + if (buffers >= 2) + uploadIdx = (writeIdx + 1) % buffers - GREMEDYStringMarker.glStringMarkerGREMEDY("Data transfer to buffer") + // Copy the pixel values from the PBO to the texture + process() - // Bind the next PBO to update pixel values - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx]) + if (!pboSupported) return@recordTransfer + + // Bind the current PBO for writing + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx]) + + // Note that glMapBuffer() causes sync issue. + // If GPU is working with this buffer, glMapBuffer() will wait(stall) + // until GPU to finish its job. To avoid waiting (idle), you can call + // first glBufferData() with NULL pointer before glMapBuffer(). + // If you do that, the previous data in PBO will be discarded and + // glMapBuffer() returns a new allocated pointer immediately + // even if GPU is still working with the previous data. + glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4L, bufferUsage.gl) // Map the buffer into the memory val bufferData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY) @@ -43,17 +71,7 @@ class PixelBuffer( // Release the buffer glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER) - } else { - println("Failed to map the PBO") - } - - // Bind the current PBO for writing - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx]) - - GREMEDYStringMarker.glStringMarkerGREMEDY("Data transfer to GPU") - - // Copy the pixel values from the PBO to the texture - process() + } else throw IllegalStateException("Failed to map the buffer") // Unbind the PBO glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) @@ -63,6 +81,11 @@ class PixelBuffer( } private fun recordTransfer(block: () -> Unit) { + if (!pboSupported) { + block() + return + } + // Start the timer glBeginQuery(GL_TIME_ELAPSED, queryId) @@ -71,6 +94,12 @@ class PixelBuffer( // Stop the timer glEndQuery(GL_TIME_ELAPSED) + + // Calculate the transfer rate + val time = uploadTime + if (time > 0) { + transferRate = (width * height * 4L * 1_000_000_000) / time + } } // Called when no references to the object exist @@ -80,7 +109,13 @@ class PixelBuffer( } init { - if (buffers < 1) throw IllegalArgumentException("Buffers must be greater than or equal to 1") + // Check if the PBO is supported + GL.getCapabilities().let { pboSupported = it.OpenGL30 || it.GL_ARB_pixel_buffer_object } + + if (!pboSupported && buffers > 0) + LOG.warn("Client tried to utilize PBOs, but they are not supported on the machine, falling back to direct buffer upload") + + if (buffers < 0) throw IllegalArgumentException("Buffers must be greater than or equal to 0") // Generate the PBOs glGenBuffers(pboIds) From 7cbfd1443a92e8134fb10a98c1ca6d8fac63474c Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:56:18 -0400 Subject: [PATCH 11/20] better handling --- .../lambda/graphics/buffer/pbo/PixelBuffer.kt | 49 ++++++++++--------- .../kotlin/com/lambda/module/hud/VideoTest.kt | 4 +- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt index c743e104f..89b2bd345 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt @@ -17,14 +17,24 @@ class PixelBuffer( private var uploadIdx = 0 // Used to upload data to the PBO private val queryId = glGenQueries() // Used to measure the time taken to upload data to the PBO - val uploadTime get() = IntArray(1).also { glGetQueryObjectiv(queryId, GL_QUERY_RESULT, it) }[0] - var transferRate = 0L // The transfer rate in bytes per second - private set + private val uploadTime get() = IntArray(1).also { glGetQueryObjectiv(queryId, GL_QUERY_RESULT, it) }[0] + private var transferRate = 0L // The transfer rate in bytes per second - var pboSupported = false - private set + private val pboSupported = GL.getCapabilities().OpenGL30 || GL.getCapabilities().GL_ARB_pixel_buffer_object + + private var initialDataSent: Boolean = false + + fun mapTexture(id: Int, buffer: ByteBuffer) { + if (!initialDataSent) { + glBindTexture(GL_TEXTURE_2D, id) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0) + glBindTexture(GL_TEXTURE_2D, 0) + + initialDataSent = true + + return + } - fun mapTexture(id: Int, buffer: ByteBuffer) = upload(buffer) { // Bind the texture glBindTexture(GL_TEXTURE_2D, id) @@ -34,13 +44,20 @@ class PixelBuffer( glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx]) // Perform the actual data transfer to the GPU - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0) } else { // Perform the actual data transfer to the GPU - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer) } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + + // Unbind the texture + glBindTexture(GL_TEXTURE_2D, 0) } + } fun upload(data: ByteBuffer, process: () -> Unit) = recordTransfer { @@ -50,8 +67,6 @@ class PixelBuffer( // Copy the pixel values from the PBO to the texture process() - if (!pboSupported) return@recordTransfer - // Bind the current PBO for writing glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx]) @@ -81,11 +96,6 @@ class PixelBuffer( } private fun recordTransfer(block: () -> Unit) { - if (!pboSupported) { - block() - return - } - // Start the timer glBeginQuery(GL_TIME_ELAPSED, queryId) @@ -97,9 +107,7 @@ class PixelBuffer( // Calculate the transfer rate val time = uploadTime - if (time > 0) { - transferRate = (width * height * 4L * 1_000_000_000) / time - } + if (time > 0) transferRate = (width * height * 4L * 1_000_000_000) / time } // Called when no references to the object exist @@ -109,14 +117,11 @@ class PixelBuffer( } init { - // Check if the PBO is supported - GL.getCapabilities().let { pboSupported = it.OpenGL30 || it.GL_ARB_pixel_buffer_object } + if (buffers < 0) throw IllegalArgumentException("Buffers must be greater than or equal to 0") if (!pboSupported && buffers > 0) LOG.warn("Client tried to utilize PBOs, but they are not supported on the machine, falling back to direct buffer upload") - if (buffers < 0) throw IllegalArgumentException("Buffers must be greater than or equal to 0") - // Generate the PBOs glGenBuffers(pboIds) diff --git a/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt b/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt index cf3a7ac83..b0e25a88c 100644 --- a/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt +++ b/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt @@ -15,8 +15,8 @@ object VideoTest : HudModule( init { onRender { - video.upload() - drawTexture(video.texture, rect) + //video.upload() + //drawTexture(video.texture, rect) } } } From a130c8c34fa4c4aaff0d086696f0d38141f5da6d Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:59:35 -0400 Subject: [PATCH 12/20] removed videos --- common/build.gradle.kts | 1 - .../com/lambda/graphics/video/JCodecUtils.kt | 74 ------------------- .../kotlin/com/lambda/graphics/video/Video.kt | 44 ----------- .../kotlin/com/lambda/module/hud/VideoTest.kt | 22 ------ fabric/build.gradle.kts | 26 ------- forge/build.gradle.kts | 1 - neoforge/build.gradle.kts | 1 - 7 files changed, 169 deletions(-) delete mode 100644 common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt delete mode 100644 common/src/main/kotlin/com/lambda/graphics/video/Video.kt delete mode 100644 common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt diff --git a/common/build.gradle.kts b/common/build.gradle.kts index eb6433c76..07481fb66 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -24,7 +24,6 @@ dependencies { implementation("org.reflections:reflections:0.10.2") implementation("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") implementation("com.pngencoder:pngencoder:0.15.0") - implementation("org.jcodec:jcodec:0.2.3") // Add Kotlin implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") diff --git a/common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt b/common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt deleted file mode 100644 index d95392d01..000000000 --- a/common/src/main/kotlin/com/lambda/graphics/video/JCodecUtils.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.lambda.graphics.video - -import org.jcodec.api.FrameGrab -import org.jcodec.common.io.NIOUtils -import org.jcodec.common.model.ColorSpace -import org.jcodec.common.model.Picture -import org.jcodec.scale.ColorUtil -import org.jcodec.scale.RgbToBgr -import java.awt.image.BufferedImage -import java.awt.image.DataBufferByte -import java.io.File - -object JCodecUtils { - fun demuxVideo(path: String): FrameGrab = - FrameGrab.createFrameGrab(NIOUtils.readableChannel(File(path))) - - fun toBufferedImage(src: Picture): BufferedImage { - val processedSrc = convertToBGR(src) - val dst = BufferedImage(processedSrc.croppedWidth, processedSrc.croppedHeight, BufferedImage.TYPE_3BYTE_BGR) - - if (processedSrc.crop == null) { - copyImageData(processedSrc, dst) - } else { - copyCroppedImageData(processedSrc, dst) - } - - return dst - } - - private fun convertToBGR(src: Picture): Picture { - if (src.color == ColorSpace.BGR) return src - - val bgr = Picture.createCropped(src.width, src.height, ColorSpace.BGR, src.crop) - - if (src.color == ColorSpace.RGB) { - RgbToBgr().transform(src, bgr) - } else { - val transform = ColorUtil.getTransform(src.color, ColorSpace.RGB) - transform.transform(src, bgr) - RgbToBgr().transform(bgr, bgr) - } - - return bgr - } - - private fun copyImageData(src: Picture, dst: BufferedImage) { - val data = (dst.raster.dataBuffer as DataBufferByte).data - val srcData = src.getPlaneData(0) - - for (i in data.indices) { - data[i] = (srcData[i] + 128).toByte() - } - } - - private fun copyCroppedImageData(src: Picture, dst: BufferedImage) { - val data = (dst.raster.dataBuffer as DataBufferByte).data - val srcData = src.getPlaneData(0) - val dstStride = dst.width * 3 - val srcStride = src.width * 3 - - for (line in 0 until dst.height) { - var dstOffset = line * dstStride - var srcOffset = line * srcStride - - for (x in 0 until dstStride step 3) { - data[dstOffset] = (srcData[srcOffset] + 128).toByte() - data[dstOffset + 1] = (srcData[srcOffset + 1] + 128).toByte() - data[dstOffset + 2] = (srcData[srcOffset + 2] + 128).toByte() - dstOffset += 3 - srcOffset += 3 - } - } - } -} diff --git a/common/src/main/kotlin/com/lambda/graphics/video/Video.kt b/common/src/main/kotlin/com/lambda/graphics/video/Video.kt deleted file mode 100644 index beff72f0e..000000000 --- a/common/src/main/kotlin/com/lambda/graphics/video/Video.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.lambda.graphics.video - -import com.lambda.graphics.buffer.BufferUsage -import com.lambda.graphics.buffer.pbo.PixelBuffer -import com.lambda.graphics.texture.Texture -import com.lambda.graphics.video.JCodecUtils.toBufferedImage -import com.pngencoder.PngEncoder -import java.io.File -import java.nio.ByteBuffer -import javax.imageio.ImageIO - - -class Video( - private val input: String, -) { - private val decoderStream = JCodecUtils.demuxVideo(input) - - val width = decoderStream.mediaInfo.dim.width - val height = decoderStream.mediaInfo.dim.height - - private val pbo = PixelBuffer(width, height, buffers = 2, bufferUsage = BufferUsage.STREAM) - val texture = Texture() - - fun upload() { - val picture = decoderStream.nativeFrame - if (picture == null) { - decoderStream.seekToFramePrecise(0) - return - } - - val image = toBufferedImage(picture) - - val bytes = PngEncoder() - .withBufferedImage(image) - .toBytes() - - val buffer = - ByteBuffer.allocateDirect(bytes.size) - .put(bytes) - .flip() - - pbo.mapTexture(texture.id, buffer) - } -} diff --git a/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt b/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt deleted file mode 100644 index b0e25a88c..000000000 --- a/common/src/main/kotlin/com/lambda/module/hud/VideoTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.lambda.module.hud - -import com.lambda.graphics.renderer.gui.TextureRenderer.drawTexture -import com.lambda.graphics.video.Video -import com.lambda.module.HudModule - -object VideoTest : HudModule( - name = "VideoTest", - defaultTags = setOf(), -) { - override val width = 430.0 - override val height = 548.0 - - private val video = Video("C:\\Users\\Kamigen\\Documents\\weed.mp4") - - init { - onRender { - //video.upload() - //drawTexture(video.texture, rect) - } - } -} diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index d0d60bf8e..e34c7b297 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -70,7 +70,6 @@ dependencies { includeLib("dev.babbaj:nether-pathfinder:1.5") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") includeLib("com.pngencoder:pngencoder:0.15.0") - includeLib("org.jcodec:jcodec:0.2.3") // Add mods to the mod jar includeMod("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion+$minecraftVersion") @@ -103,29 +102,4 @@ tasks { // They allow you to make field, method, and class access public. injectAccessWidener = true } - - register("run + RenderDoc") { - val javaHome = Jvm.current().javaHome - - commandLine = listOf( - "C:\\Program Files\\RenderDoc\\renderdoccmd.exe", - "capture", - "--opt-api-validation", - "--opt-api-validation-unmute", - "--opt-hook-children", - "--wait-for-exit", - "--working-dir", - ".", - "$javaHome/bin/java.exe", - "-Xmx64m", - "-Xms64m", - //"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005", - "-Dorg.gradle.appname=gradlew", - "-Dorg.gradle.java.home=$javaHome", - "-classpath", - "C:\\Users\\Kamigen\\Desktop\\BetterElytraBot\\NeoLambda\\gradle\\wrapper\\gradle-wrapper.jar", - "org.gradle.wrapper.GradleWrapperMain", - ":fabric:runClient", - ) - } } diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index bf6133cdf..935fa55ed 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -82,7 +82,6 @@ dependencies { includeLib("org.javassist:javassist:3.28.0-GA") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") includeLib("com.pngencoder:pngencoder:0.15.0") - includeLib("org.jcodec:jcodec:0.2.3") // Add mods to the mod jar includeMod("thedarkcolour:kotlinforforge:$kotlinForgeVersion") diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 4693ae091..9978da288 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -69,7 +69,6 @@ dependencies { includeLib("dev.babbaj:nether-pathfinder:1.5") includeLib("com.github.Edouard127:KDiscordIPC:$discordIPCVersion") includeLib("com.pngencoder:pngencoder:0.15.0") - includeLib("org.jcodec:jcodec:0.2.3") // Add mods to the mod jar includeMod("thedarkcolour:kotlinforforge-neoforge:$kotlinForgeVersion") From bbd705f4a4d68bf97a4800e2e72fbef8cdb2d7b2 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:04:38 -0400 Subject: [PATCH 13/20] added documentation for pbo --- .../lambda/graphics/buffer/pbo/PixelBuffer.kt | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt index 89b2bd345..0dc03a38e 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt @@ -6,6 +6,15 @@ import org.lwjgl.opengl.GL import org.lwjgl.opengl.GL45C.* import java.nio.ByteBuffer +/** + * Represents a Pixel Buffer Object (PBO) that facilitates asynchronous data transfer to the GPU. + * This class manages the creation, usage, and cleanup of PBOs and provides methods to map textures and upload data efficiently. + * + * @property width The width of the texture in pixels. + * @property height The height of the texture in pixels. + * @property buffers The number of PBOs to be used. Default is 2, which allows double buffering. + * @property bufferUsage The usage pattern of the buffer, indicating how the buffer will be used (static, dynamic, etc.). + */ class PixelBuffer( private val width: Int, private val height: Int, @@ -24,6 +33,12 @@ class PixelBuffer( private var initialDataSent: Boolean = false + /** + * Maps the given texture ID to the buffer and performs the necessary operations to upload the texture data. + * + * @param id The texture ID to which the buffer will be mapped. + * @param buffer The [ByteBuffer] containing the pixel data to be uploaded to the texture. + */ fun mapTexture(id: Int, buffer: ByteBuffer) { if (!initialDataSent) { glBindTexture(GL_TEXTURE_2D, id) @@ -59,6 +74,12 @@ class PixelBuffer( } } + /** + * Uploads the given pixel data to the PBO and executes the provided processing function to manage the PBO's data transfer. + * + * @param data The [ByteBuffer] containing the pixel data to be uploaded. + * @param process A lambda function to execute after uploading the data to manage the PBO's data transfer. + */ fun upload(data: ByteBuffer, process: () -> Unit) = recordTransfer { if (buffers >= 2) @@ -95,6 +116,11 @@ class PixelBuffer( writeIdx = uploadIdx } + /** + * Measures and records the time taken to transfer data to the PBO, calculating the transfer rate in bytes per second. + * + * @param block A lambda function representing the block of code where the transfer occurs. + */ private fun recordTransfer(block: () -> Unit) { // Start the timer glBeginQuery(GL_TIME_ELAPSED, queryId) @@ -110,12 +136,19 @@ class PixelBuffer( if (time > 0) transferRate = (width * height * 4L * 1_000_000_000) / time } - // Called when no references to the object exist + /** + * Cleans up resources by deleting the PBOs when the object is no longer in use. + */ fun finalize() { // Delete the PBOs glDeleteBuffers(pboIds) } + /** + * Initializes the PBOs, allocates memory for them, and handles unsupported PBO scenarios. + * + * @throws IllegalArgumentException If the number of buffers is less than 0. + */ init { if (buffers < 0) throw IllegalArgumentException("Buffers must be greater than or equal to 0") From 4b965566af0a3841d873645462615bd9cfb08022 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:06:09 -0400 Subject: [PATCH 14/20] moved the fbo down one level --- common/src/main/kotlin/com/lambda/graphics/RenderMain.kt | 2 +- .../kotlin/com/lambda/graphics/buffer/{fbo => }/FrameBuffer.kt | 3 ++- common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) rename common/src/main/kotlin/com/lambda/graphics/buffer/{fbo => }/FrameBuffer.kt (99%) diff --git a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt index 6eabe8442..998a21872 100644 --- a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -7,7 +7,7 @@ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.animation.AnimationTicker -import com.lambda.graphics.buffer.fbo.FrameBuffer +import com.lambda.graphics.buffer.FrameBuffer import com.lambda.graphics.gl.GlStateUtils.setupGL import com.lambda.graphics.gl.Matrices import com.lambda.graphics.gl.Matrices.resetMatrices diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/fbo/FrameBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/FrameBuffer.kt similarity index 99% rename from common/src/main/kotlin/com/lambda/graphics/buffer/fbo/FrameBuffer.kt rename to common/src/main/kotlin/com/lambda/graphics/buffer/FrameBuffer.kt index 25b3bd3bc..db164955a 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/fbo/FrameBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/FrameBuffer.kt @@ -1,4 +1,5 @@ -package com.lambda.graphics.buffer.fbo +package com.lambda.graphics.buffer + import com.lambda.Lambda.mc import com.lambda.graphics.RenderMain import com.lambda.graphics.buffer.vao.VAO diff --git a/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt index 6170d4cfb..d2643785f 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt @@ -2,7 +2,7 @@ package com.lambda.gui.impl import com.lambda.Lambda.mc import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.graphics.buffer.fbo.FrameBuffer +import com.lambda.graphics.buffer.FrameBuffer import com.lambda.graphics.shader.Shader import com.lambda.gui.AbstractGuiConfigurable import com.lambda.gui.GuiConfigurable From 895a069cc203a038c01fafb76cca1cf96a6fe7a5 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:13:31 -0400 Subject: [PATCH 15/20] removed loader phase time measure --- common/src/main/kotlin/com/lambda/core/Loader.kt | 9 +-------- .../graphics/renderer/gui/font/glyph/EmojiGlyphs.kt | 5 ++--- .../graphics/renderer/gui/font/glyph/FontGlyphs.kt | 5 ++--- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/core/Loader.kt b/common/src/main/kotlin/com/lambda/core/Loader.kt index 271143d2c..f2bb399f4 100644 --- a/common/src/main/kotlin/com/lambda/core/Loader.kt +++ b/common/src/main/kotlin/com/lambda/core/Loader.kt @@ -45,14 +45,7 @@ object Loader { LOG.info("Initializing ${Lambda.MOD_NAME} ${Lambda.VERSION}") val initTime = measureTimeMillis { - loadables.forEach { loadable -> - val info: String - val phaseTime = measureTimeMillis { - info = loadable.load() - } - - LOG.info("$info in ${phaseTime}ms") - } + loadables.forEach { LOG.info(it.load()) } } LOG.info("${Lambda.MOD_NAME} ${Lambda.VERSION} was successfully initialized (${initTime}ms)") diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt index 0405a0dcf..aa07d686c 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt @@ -16,7 +16,6 @@ import javax.imageio.ImageIO import kotlin.math.ceil import kotlin.math.log2 import kotlin.math.sqrt -import kotlin.system.measureTimeMillis import kotlin.time.Duration.Companion.days class EmojiGlyphs(zipUrl: String) { @@ -28,8 +27,8 @@ class EmojiGlyphs(zipUrl: String) { init { runCatching { - val time = measureTimeMillis { downloadAndProcessZip(zipUrl) } - LOG.info("Loaded ${emojiMap.size} emojis in $time ms") + downloadAndProcessZip(zipUrl) + LOG.info("Loaded ${emojiMap.size} emojis") }.onFailure { LOG.error("Failed to load emojis: ${it.message}", it) fontTexture = MipmapTexture(BufferedImage(1024, 1024, BufferedImage.TYPE_INT_ARGB)) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt index 3c492b26b..3461ec2af 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt @@ -11,7 +11,6 @@ import java.awt.Font import java.awt.Graphics2D import java.awt.image.BufferedImage import kotlin.math.max -import kotlin.system.measureTimeMillis class FontGlyphs( private val font: Font @@ -23,8 +22,8 @@ class FontGlyphs( init { runCatching { - val time = measureTimeMillis { processGlyphs() } - LOG.info("Font ${font.fontName} loaded with ${charMap.size} characters in $time ms") + processGlyphs() + LOG.info("Font ${font.fontName} loaded with ${charMap.size} characters") }.onFailure { LOG.error("Failed to load font glyphs: ${it.message}", it) fontTexture = MipmapTexture(BufferedImage(1024, 1024, BufferedImage.TYPE_INT_ARGB)) From 0644c69868193a7027efc22396722fabddf7d9f6 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 24 Aug 2024 08:46:59 -0400 Subject: [PATCH 16/20] Update build.gradle.kts --- fabric/build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index e34c7b297..8844cc10f 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -1,5 +1,3 @@ -import org.gradle.internal.jvm.Jvm - val modVersion: String by project val minecraftVersion: String by project val fabricLoaderVersion: String by project From de3bb6e5651ca6b34603a508d3e7fd8c2e585ae4 Mon Sep 17 00:00:00 2001 From: Constructor Date: Sun, 25 Aug 2024 05:02:50 +0200 Subject: [PATCH 17/20] TickEvent KDocs --- .../lambda/mixin/MinecraftClientMixin.java | 4 +- .../com/lambda/event/events/TickEvent.kt | 86 ++++++++++++++----- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 6c92d6558..809a077c4 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -37,12 +37,12 @@ void onTickPost(CallbackInfo ci) { @Inject(method = "render", at = @At("HEAD")) void onLoopTickPre(CallbackInfo ci) { - EventFlow.post(new TickEvent.GameLoop.Pre()); + EventFlow.post(new TickEvent.Render.Pre()); } @Inject(method = "render", at = @At("RETURN")) void onLoopTickPost(CallbackInfo ci) { - EventFlow.post(new TickEvent.GameLoop.Post()); + EventFlow.post(new TickEvent.Render.Post()); } @Inject(at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;info(Ljava/lang/String;)V", shift = At.Shift.AFTER, remap = false), method = "stop") diff --git a/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt b/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt index d47597fdb..003f956d9 100644 --- a/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt @@ -1,58 +1,98 @@ package com.lambda.event.events import com.lambda.event.Event -import com.lambda.event.EventFlow -import com.lambda.event.events.TickEvent.Post -import com.lambda.event.events.TickEvent.Pre -/** - * An abstract class representing a [TickEvent] in the [EventFlow]. - * - * A [TickEvent] is a type of [Event] that is triggered at each tick of the game loop. - * It has two subclasses: [Pre] and [Post], which are triggered before and after the tick, respectively. - * - * The [TickEvent] class is designed to be extended by any class that needs to react to ticks. - * - * @see Pre - * @see Post - */ abstract class TickEvent : Event { /** - * A class representing a [TickEvent] that is triggered before each tick of the tick loop. + * Triggered before each iteration of the game loop. + * + * Phases: + * + * 1. **Pre-Tick**: Increments uptime, steps world tick manager, decrement item use cooldown. + * 2. **GUI Update**: Processes delayed messages, updates HUD. + * 3. **Game Mode Update**: Updates targeted entity, ticks tutorial, and interaction managers. + * 4. **Texture Update**: Ticks texture manager. + * 5. **Screen Handling**: Manages screen logic, ticks current screen. + * 6. **Debug HUD Update**: Resets debug HUD chunk. + * 7. **Input Handling**: Handles input events, decrements attack cooldown. + * 8. **World Update**: Ticks game and world renderers, world entities. + * 9. **Music and Sound Update**: Ticks music tracker and sound manager. + * 10. **Tutorial and Social Interactions**: Handles tutorial and social interactions, ticks world. + * 11. **Pending Connection**: Ticks integrated server connection. + * 12. **Keyboard Handling**: Polls for debug crash key presses. + * + * @see net.minecraft.client.MinecraftClient.tick */ class Pre : TickEvent() /** - * A class representing a [TickEvent] that is triggered after each tick of the tick loop. + * Triggered after each iteration of the game loop. + * Targeted at 20 ticks per second. + * + * Phases: + * + * 1. **Pre-Tick**: Increments uptime, steps world tick manager, decrement item use cooldown. + * 2. **GUI Update**: Processes delayed messages, updates HUD. + * 3. **Game Mode Update**: Updates targeted entity, ticks tutorial, and interaction managers. + * 4. **Texture Update**: Ticks texture manager. + * 5. **Screen Handling**: Manages screen logic, ticks current screen. + * 6. **Debug HUD Update**: Resets debug HUD chunk. + * 7. **Input Handling**: Handles input events, decrements attack cooldown. + * 8. **World Update**: Ticks game and world renderers, world entities (such as [TickEvent.Player]). + * 9. **Music and Sound Update**: Ticks music tracker and sound manager. + * 10. **Tutorial and Social Interactions**: Handles tutorial and social interactions, ticks world. + * 11. **Pending Connection**: Ticks integrated server connection. + * 12. **Keyboard Handling**: Polls for debug crash key presses. + * + * @see net.minecraft.client.MinecraftClient.tick */ class Post : TickEvent() /** - * A class representing a [TickEvent] that is triggered on each tick of the game loop. + * Triggered before ([Pre]) and after ([Post]) each render tick. + * + * Phases: + * + * 1. **Pre-Render**: Prepares the window for rendering, checks for window close, handles resource reloads. + * 2. **Task Execution**: Executes pending render tasks. + * 3. **Client Tick**: Ticks the client ([TickEvent.Pre] and [TickEvent.Post]) until tick target was met. + * 4. **Render**: Performs the actual rendering of the game. + * 5. **Post-Render**: Finalizes the rendering process, updates the window. + * + * @see net.minecraft.client.MinecraftClient.render */ - abstract class GameLoop : TickEvent() { + abstract class Render : TickEvent() { /** - * A class representing a [TickEvent.Player] that is triggered before each tick of the game loop. + * Triggered before each render tick ([TickEvent.Render]) of the game loop. */ class Pre : TickEvent() /** - * A class representing a [TickEvent.Player] that is triggered after each tick of the game loop. + * Triggered after each render tick ([TickEvent.Render]) of the game loop. */ class Post : TickEvent() } /** - * A class representing a [TickEvent] that is triggered when the player gets ticked. + * Triggered before ([Pre]) and after ([Post]) each player tick that is run during the game loop [TickEvent.Pre]. + * + * Phases: + * + * 1. **Pre-Tick**: Prepares player state before the tick. + * 2. **Movement**: Handles player movement and input. + * 3. **Action**: Processes player actions like swinging hand. + * 4. **Post-Tick**: Finalizes player state after the tick. + * + * @see net.minecraft.client.network.ClientPlayerEntity.tick */ abstract class Player : TickEvent() { /** - * A class representing a [TickEvent.Player] that is triggered before each player tick. + * Triggered before each player tick ([TickEvent.Player]). */ class Pre : Player() /** - * A class representing a [TickEvent.Player] that is triggered after each player tick. + * Triggered after each player tick ([TickEvent.Player]). */ class Post : Player() } From b40b1aef9d0f1aa12097d3478f5c8e4951a012fc Mon Sep 17 00:00:00 2001 From: Constructor Date: Sun, 25 Aug 2024 05:16:01 +0200 Subject: [PATCH 18/20] Smol refac --- .../kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt index 0dc03a38e..17e815600 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt @@ -26,7 +26,8 @@ class PixelBuffer( private var uploadIdx = 0 // Used to upload data to the PBO private val queryId = glGenQueries() // Used to measure the time taken to upload data to the PBO - private val uploadTime get() = IntArray(1).also { glGetQueryObjectiv(queryId, GL_QUERY_RESULT, it) }[0] + private val uploadTime get() = + IntArray(1).also { glGetQueryObjectiv(queryId, GL_QUERY_RESULT, it) }.first() private var transferRate = 0L // The transfer rate in bytes per second private val pboSupported = GL.getCapabilities().OpenGL30 || GL.getCapabilities().GL_ARB_pixel_buffer_object @@ -60,8 +61,7 @@ class PixelBuffer( // Perform the actual data transfer to the GPU glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0) - } - else { + } else { // Perform the actual data transfer to the GPU glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer) } From dcf244df4eafbf389aafb8917d883a5c1b44dce6 Mon Sep 17 00:00:00 2001 From: Constructor Date: Sun, 25 Aug 2024 05:28:26 +0200 Subject: [PATCH 19/20] Better logging and remove texture settings --- .../com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt | 2 +- .../lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt | 3 ++- .../kotlin/com/lambda/interaction/PlayerPacketManager.kt | 1 - .../com/lambda/module/modules/client/RenderSettings.kt | 5 ----- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt index 8d8f85f48..cfe21c3d5 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/LambdaEmoji.kt @@ -17,7 +17,7 @@ enum class LambdaEmoji(private val zipUrl: String) { object Loader : Loadable { override fun load(): String { entries.forEach(LambdaEmoji::loadGlyphs) - return "Loaded ${entries.size} emoji sets" + return "Loaded ${entries.size} emoji sets with a total of ${entries.sumOf { it.glyphs.count }} emojis" } } } diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt index aa07d686c..6e2dd4e05 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/EmojiGlyphs.kt @@ -25,10 +25,11 @@ class EmojiGlyphs(zipUrl: String) { private lateinit var image: BufferedImage private lateinit var graphics: Graphics2D + val count get() = emojiMap.size + init { runCatching { downloadAndProcessZip(zipUrl) - LOG.info("Loaded ${emojiMap.size} emojis") }.onFailure { LOG.error("Failed to load emojis: ${it.message}", it) fontTexture = MipmapTexture(BufferedImage(1024, 1024, BufferedImage.TYPE_INT_ARGB)) diff --git a/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt index 491ca07bb..1a6e95e6d 100644 --- a/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt @@ -5,7 +5,6 @@ import com.lambda.core.Loadable import com.lambda.event.EventFlow.post import com.lambda.event.EventFlow.postChecked import com.lambda.event.events.PlayerPacketEvent -import com.lambda.interaction.rotation.Rotation.Companion.fixSensitivity import com.lambda.threading.runSafe import com.lambda.util.collections.LimitedOrderedSet import com.lambda.util.math.VecUtils.approximate diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt index ec29fad21..099dbdafb 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt @@ -18,10 +18,6 @@ object RenderSettings : Module( val baselineOffset by setting("Vertical Offset", 0.0, -10.0..10.0, 0.5) { page == Page.Font } private val lodBiasSetting by setting("Smoothing", 0.0, -10.0..10.0, 0.5) { page == Page.Font } - // Texture - val textureCompression by setting("Compression", 1, 1..9, 1, description = "Texture compression level, higher is slower") { page == Page.TEXTURE } - val threadedCompression by setting("Threaded Compression", false, description = "Use multiple threads for texture compression") { page == Page.TEXTURE } - // ESP val uploadsPerTick by setting("Uploads", 16, 1..256, 1, unit = " chunk/tick") { page == Page.ESP } val rebuildsPerTick by setting("Rebuilds", 64, 1..256, 1, unit = " chunk/tick") { page == Page.ESP } @@ -32,7 +28,6 @@ object RenderSettings : Module( private enum class Page { Font, - TEXTURE, ESP, } } From c97a29c0c25f6c3cbe8cde2b4710a57802c32273 Mon Sep 17 00:00:00 2001 From: Constructor Date: Sun, 25 Aug 2024 05:39:07 +0200 Subject: [PATCH 20/20] Introduce constants for texture options --- .../com/lambda/graphics/texture/TextureUtils.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt index 5ed6289cb..d3a6f94e8 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt @@ -1,6 +1,5 @@ package com.lambda.graphics.texture -import com.lambda.module.modules.client.RenderSettings import com.mojang.blaze3d.systems.RenderSystem import com.pngencoder.PngEncoder import net.minecraft.client.texture.NativeImage @@ -8,15 +7,17 @@ import org.lwjgl.BufferUtils import org.lwjgl.opengl.GL45C.* import java.awt.* import java.awt.image.BufferedImage -import java.io.ByteArrayOutputStream import kotlin.math.roundToInt import kotlin.math.sqrt object TextureUtils { + private const val COMPRESSION_LEVEL = 1 + private const val THREADED_COMPRESSION = false + private val metricCache = mutableMapOf() private val encoderPreset = PngEncoder() - .withCompressionLevel(RenderSettings.textureCompression) - .withMultiThreadedCompressionEnabled(RenderSettings.threadedCompression) + .withCompressionLevel(COMPRESSION_LEVEL) + .withMultiThreadedCompressionEnabled(THREADED_COMPRESSION) fun bindTexture(id: Int, slot: Int = 0) { RenderSystem.activeTexture(GL_TEXTURE0 + slot) @@ -77,7 +78,7 @@ object TextureUtils { if (!font.canDisplay(codePoint)) return null val fontMetrics = metricCache.getOrPut(font) { - val image = BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB) + val image = BufferedImage(COMPRESSION_LEVEL, COMPRESSION_LEVEL, BufferedImage.TYPE_INT_ARGB) val graphics2D = image.createGraphics() graphics2D.font = font