mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
Compare commits
3 Commits
b547914865
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ad352d8cf | ||
|
|
426f0b0aab | ||
|
|
b01d1683b7 |
@@ -1,4 +1,4 @@
|
||||
Copyright (C) 2013-2024 Minjae Song ("CuriousTorvald")
|
||||
Copyright (C) 2013-2026 Minjae Song ("CuriousTorvald")
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -8,8 +8,10 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.badlogic.gdx.utils.BufferUtils
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.jme3.math.FastMath
|
||||
import java.nio.ByteBuffer
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.*
|
||||
@@ -87,12 +89,21 @@ object IngameRenderer : Disposable {
|
||||
|
||||
private lateinit var fboRGBwall: Float16FrameBuffer // for masking away the shadows
|
||||
|
||||
private lateinit var fboUI: Float16FrameBuffer // UI composite target for scene-aware dimming
|
||||
private lateinit var fboSceneAvg: Float16FrameBuffer // tiny target for brightness readback
|
||||
|
||||
private lateinit var rgbTex: TextureRegion
|
||||
private lateinit var aTex: TextureRegion
|
||||
private lateinit var mixedOutTex: TextureRegion
|
||||
private lateinit var uiTex: TextureRegion
|
||||
private lateinit var lightTex: TextureRegion
|
||||
private lateinit var blurTex: TextureRegion
|
||||
|
||||
// Contextual UI dimming: dim slightly when the world scene is dark.
|
||||
private val sceneAvgBuf: ByteBuffer = BufferUtils.newByteBuffer(SCENE_AVG_SIZE * SCENE_AVG_SIZE * 4)
|
||||
@Volatile private var smoothedSceneLuma = 1f
|
||||
private var uiDimFactor = 1f
|
||||
|
||||
private lateinit var fboBlurHalf: Float16FrameBuffer
|
||||
// private lateinit var fboBlurQuarter: Float16FrameBuffer
|
||||
|
||||
@@ -136,6 +147,14 @@ object IngameRenderer : Disposable {
|
||||
/** lower value = greater lozenge artefact from linear intp */
|
||||
const val lightmapDownsample = 2f // still has choppy look when the camera moves but unnoticeable when blurred
|
||||
|
||||
// Contextual UI dimming parameters.
|
||||
private const val SCENE_AVG_SIZE = 16 // side of the small RGBA8 FBO used for brightness readback
|
||||
private const val SCENE_AVG_INTERVAL = 6L // sample every N frames; smoothing fills the gaps
|
||||
private const val UI_DIM_DARK_FACTOR = 0.8f // 80% brightness when the scene is dark
|
||||
private const val UI_DIM_DARK_LUMA = 0.08f // luma at/below this -> fully dimmed
|
||||
private const val UI_DIM_BRIGHT_LUMA = 0.22f // luma at/above this -> no dimming
|
||||
private const val UI_DIM_SMOOTHING = 0.12f // per-sample EMA factor for luma
|
||||
|
||||
private var debugMode = 0
|
||||
|
||||
var renderingActorsCount = 0
|
||||
@@ -444,20 +463,38 @@ object IngameRenderer : Disposable {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
// draw UI
|
||||
setCameraPosition(0f, 0f)
|
||||
// contextual UI dimming: keep uiDimFactor in sync with the rendered scene's brightness
|
||||
sampleSceneBrightness()
|
||||
|
||||
batch.inUse {
|
||||
batch.shader = null
|
||||
batch.color = Color.WHITE
|
||||
// draw UI into its own FBO so individual UIs can keep using batch.color freely
|
||||
fboUI.inAction(camera, batch) {
|
||||
gdxClearAndEnableBlend(0f, 0f, 0f, 0f)
|
||||
blendNormalStraightAlpha(batch)
|
||||
|
||||
if (!KeyToggler.isOn(Input.Keys.F4)) {
|
||||
uiContainer?.forEach {
|
||||
it?.render(frameDelta, batch, camera)
|
||||
batch.inUse {
|
||||
batch.shader = null
|
||||
batch.color = Color.WHITE
|
||||
|
||||
if (!KeyToggler.isOn(Input.Keys.F4)) {
|
||||
uiContainer?.forEach {
|
||||
it?.render(frameDelta, batch, camera)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// composite UI on top of the world with the contextual dim tint
|
||||
setCameraPosition(0f, 0f)
|
||||
blendNormalPremultAlpha(batch)
|
||||
|
||||
uiTex.texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||
batch.inUse {
|
||||
batch.shader = null
|
||||
batch.color = Color(uiDimFactor, uiDimFactor, uiDimFactor, 1f)
|
||||
batch.drawFlipped(uiTex, 0f, 0f, fboUI.width.toFloat(), fboUI.height.toFloat())
|
||||
batch.color = Color.WHITE
|
||||
}
|
||||
|
||||
// works but some UI elements have wrong transparency -> should be fixed with Terrarum.gdxCleanAndSetBlend -- Torvald 2019-01-12
|
||||
blendNormalStraightAlpha(batch)
|
||||
batch.color = Color.WHITE
|
||||
@@ -466,6 +503,48 @@ object IngameRenderer : Disposable {
|
||||
if (newWorldLoadedLatch) newWorldLoadedLatch = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Downsamples [fboMixedOut] into [fboSceneAvg], reads it back, and updates [smoothedSceneLuma]
|
||||
* and [uiDimFactor]. Sampling is throttled to every [SCENE_AVG_INTERVAL] frames; the EMA fills gaps.
|
||||
*/
|
||||
private fun sampleSceneBrightness() {
|
||||
if (App.GLOBAL_RENDER_TIMER % SCENE_AVG_INTERVAL == 0L) {
|
||||
mixedOutTex.texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
||||
|
||||
fboSceneAvg.inAction(camera, batch) {
|
||||
gdxClearAndEnableBlend(0f, 0f, 0f, 1f)
|
||||
batch.inUse {
|
||||
batch.shader = null
|
||||
batch.color = Color.WHITE
|
||||
batch.draw(mixedOutTex, 0f, 0f, fboSceneAvg.width.toFloat(), fboSceneAvg.height.toFloat())
|
||||
}
|
||||
|
||||
sceneAvgBuf.rewind()
|
||||
Gdx.gl.glReadPixels(0, 0, fboSceneAvg.width, fboSceneAvg.height,
|
||||
GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, sceneAvgBuf)
|
||||
}
|
||||
|
||||
sceneAvgBuf.rewind()
|
||||
var sumR = 0L
|
||||
var sumG = 0L
|
||||
var sumB = 0L
|
||||
val count = fboSceneAvg.width * fboSceneAvg.height
|
||||
for (i in 0 until count) {
|
||||
sumR += (sceneAvgBuf.get().toInt() and 0xFF)
|
||||
sumG += (sceneAvgBuf.get().toInt() and 0xFF)
|
||||
sumB += (sceneAvgBuf.get().toInt() and 0xFF)
|
||||
sceneAvgBuf.get() // alpha discarded
|
||||
}
|
||||
val inv = 1f / (count * 255f)
|
||||
val luma = 0.2126f * (sumR * inv) + 0.7152f * (sumG * inv) + 0.0722f * (sumB * inv)
|
||||
smoothedSceneLuma += (luma - smoothedSceneLuma) * UI_DIM_SMOOTHING
|
||||
}
|
||||
|
||||
val t = ((smoothedSceneLuma - UI_DIM_DARK_LUMA) / (UI_DIM_BRIGHT_LUMA - UI_DIM_DARK_LUMA))
|
||||
.coerceIn(0f, 1f)
|
||||
uiDimFactor = UI_DIM_DARK_FACTOR + (1f - UI_DIM_DARK_FACTOR) * t
|
||||
}
|
||||
|
||||
|
||||
private fun prepLightmapRGBA() {
|
||||
lightmapFbo.inAction(null, null) {
|
||||
@@ -1305,6 +1384,9 @@ object IngameRenderer : Disposable {
|
||||
|
||||
fboBlurHalf.dispose()
|
||||
//fboBlurQuarter.dispose()
|
||||
|
||||
if (::fboUI.isInitialized) fboUI.dispose()
|
||||
if (::fboSceneAvg.isInitialized) fboSceneAvg.dispose()
|
||||
}
|
||||
|
||||
// BlocksDrawer and LightmapRenderer must be resized before lightmapFbo is created,
|
||||
@@ -1332,11 +1414,15 @@ object IngameRenderer : Disposable {
|
||||
LightmapRenderer.lightBuffer.height * LightmapRenderer.DRAW_TILE_SIZE.toInt(),
|
||||
false
|
||||
)
|
||||
fboUI = Float16FrameBuffer(width, height, false)
|
||||
fboSceneAvg = Float16FrameBuffer(SCENE_AVG_SIZE, SCENE_AVG_SIZE, false)
|
||||
|
||||
rgbTex = TextureRegion(fboRGB_lightMixed.colorBufferTexture)
|
||||
aTex = TextureRegion(fboA_lightMixed.colorBufferTexture)
|
||||
lightTex = TextureRegion(lightmapFbo.colorBufferTexture)
|
||||
blurTex = TextureRegion()
|
||||
mixedOutTex = TextureRegion(fboMixedOut.colorBufferTexture)
|
||||
uiTex = TextureRegion(fboUI.colorBufferTexture)
|
||||
|
||||
fboBlurHalf = Float16FrameBuffer(
|
||||
LightmapRenderer.lightBuffer.width * LightmapRenderer.DRAW_TILE_SIZE.toInt() / 2,
|
||||
@@ -1394,6 +1480,8 @@ object IngameRenderer : Disposable {
|
||||
if (::fboRGBactorsMiddleShadow.isInitialized) fboRGBactorsMiddleShadow.tryDispose()
|
||||
if (::fboRGBterrainShadow.isInitialized) fboRGBterrainShadow.tryDispose()
|
||||
if (::fboRGBwall.isInitialized) fboRGBwall.tryDispose()
|
||||
if (::fboUI.isInitialized) fboUI.tryDispose()
|
||||
if (::fboSceneAvg.isInitialized) fboSceneAvg.tryDispose()
|
||||
|
||||
blurtex0.tryDispose()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user