working deblocking

This commit is contained in:
minjaesong
2024-08-29 03:00:39 +09:00
parent d02282a64d
commit 43e8d1a8d0
12 changed files with 118 additions and 61 deletions

View File

@@ -277,7 +277,7 @@ object IngameRenderer : Disposable {
if ((!gamePaused && !App.isScreenshotRequested()) || newWorldLoadedLatch) {
measureDebugTime("Renderer.LightRun*") {
// recalculate for even frames, or if the sign of the cam-x changed
// recalculate for every three frame, or if the sign of the cam-x changed
if (App.GLOBAL_RENDER_TIMER % 3 == 0L || Math.abs(WorldCamera.x - oldCamX) >= world.width * 0.85f * TILE_SIZEF || newWorldLoadedLatch) {
LightmapRenderer.recalculate(actorsRenderFarBehind + actorsRenderBehind + actorsRenderFront + actorsRenderMidTop + actorsRenderMiddle + actorsRenderOverlay)
}

View File

@@ -75,7 +75,9 @@ internal object BlocksDrawer {
val ORES = GameWorld.ORES
val FLUID = -2
val OCCLUSION = 31337
val BLURMAP = 31338
val BLURMAP_BASE = 31338
val BLURMAP_TERR = BLURMAP_BASE + TERRAIN
val BLURMAP_WALL = BLURMAP_BASE + WALL
private const val OCCLUSION_TILE_NUM_BASE = 16
@@ -98,7 +100,8 @@ internal object BlocksDrawer {
private lateinit var oreTilesBuffer: UnsafeLong2D // stores subtiles (dimension is doubled)
private lateinit var fluidTilesBuffer: UnsafeLong2D // stores subtiles (dimension is doubled)
private lateinit var occlusionBuffer: UnsafeLong2D // stores subtiles (dimension is doubled)
private lateinit var blurMap: UnsafeLong2D // stores subtiles (dimension is doubled)
private lateinit var blurMapTerr: UnsafeLong2D // stores subtiles (dimension is doubled)
private lateinit var blurMapWall: UnsafeLong2D // stores subtiles (dimension is doubled)
private lateinit var tempRenderTypeBuffer: UnsafeLong2D // this one is NOT dimension doubled; 0x tttt 00 ii where t=rawTileNum, i=nearbyTilesInfo
private var tilesBuffer: Pixmap = Pixmap(1, 1, Pixmap.Format.RGBA8888)
private var tilesBuffer2: Pixmap = Pixmap(1, 1, Pixmap.Format.RGBA8888)
@@ -257,8 +260,9 @@ internal object BlocksDrawer {
}
catch (e: ClassCastException) { }
if (!world.layerTerrain.ptrDestroyed) {
measureDebugTime("Renderer.Tiling") {
if (doTilemapUpdate) {
// rendering tilemap only updates every three frame
measureDebugTime("Renderer.Tiling*") {
drawTiles(WALL)
drawTiles(TERRAIN) // regular tiles
drawTiles(ORES)
@@ -334,7 +338,7 @@ internal object BlocksDrawer {
}
private val occlusionRenderTag = CreateTileAtlas.RenderTag(
OCCLUSION_TILE_NUM_BASE, CreateTileAtlas.RenderTag.CONNECT_SELF, CreateTileAtlas.RenderTag.MASK_47, 0
OCCLUSION_TILE_NUM_BASE, CreateTileAtlas.RenderTag.CONNECT_SELF, CreateTileAtlas.RenderTag.MASK_47, 0, 0
)
private lateinit var renderOnF3Only: Array<Int>
@@ -583,19 +587,21 @@ internal object BlocksDrawer {
else 0
if (mode == TERRAIN || mode == WALL) {
// TODO translate nearbyTilesInfo into proper subtile number
// translate nearbyTilesInfo into proper subtile number
val nearbyTilesInfo = getNearbyTilesInfoDeblocking(mode, x, y)
val subtiles = if (nearbyTilesInfo == null)
listOf(
Point2i(130, 1), Point2i(130, 1), Point2i(130, 1), Point2i(130, 1)
)
else
(0..3).map {
Point2i(126, 0) + deblockerNearbyTilesToSubtile[it][nearbyTilesInfo]
}
// TEST CODE
val subtiles = arrayOf(
Point2i(130, 0),
Point2i(131, 0),
Point2i(131, 1),
Point2i(130, 1),
)
/*TL*/writeToBufferSubtile(BLURMAP, bufferBaseX * 2 + 0, bufferBaseY * 2 + 0, subtiles[0].x, subtiles[0].y, 0, 0)
/*TR*/writeToBufferSubtile(BLURMAP, bufferBaseX * 2 + 1, bufferBaseY * 2 + 0, subtiles[1].x, subtiles[1].y, 0, 0)
/*BR*/writeToBufferSubtile(BLURMAP, bufferBaseX * 2 + 1, bufferBaseY * 2 + 1, subtiles[2].x, subtiles[2].y, 0, 0)
/*BL*/writeToBufferSubtile(BLURMAP, bufferBaseX * 2 + 0, bufferBaseY * 2 + 1, subtiles[3].x, subtiles[3].y, 0, 0)
/*TL*/writeToBufferSubtile(BLURMAP_BASE + mode, bufferBaseX * 2 + 0, bufferBaseY * 2 + 0, subtiles[0].x, subtiles[0].y, 0, 0)
/*TR*/writeToBufferSubtile(BLURMAP_BASE + mode, bufferBaseX * 2 + 1, bufferBaseY * 2 + 0, subtiles[1].x, subtiles[1].y, 0, 0)
/*BR*/writeToBufferSubtile(BLURMAP_BASE + mode, bufferBaseX * 2 + 1, bufferBaseY * 2 + 1, subtiles[2].x, subtiles[2].y, 0, 0)
/*BL*/writeToBufferSubtile(BLURMAP_BASE + mode, bufferBaseX * 2 + 0, bufferBaseY * 2 + 1, subtiles[3].x, subtiles[3].y, 0, 0)
}
if (renderTag.maskType >= CreateTileAtlas.RenderTag.MASK_SUBTILE_GENERIC) {
@@ -796,6 +802,48 @@ internal object BlocksDrawer {
return ret
}
private fun getNearbyTilesInfoDeblocking(mode: Int, x: Int, y: Int): Int? {
val tileThis = world.getTileFrom(mode, x, y)
val nearbyTiles = getNearbyTilesPos4(x, y).map { world.getTileFrom(mode, it.x, it.y) }
val renderTagThis = App.tileMaker.getRenderTag(tileThis)
if (renderTagThis.postProcessing != CreateTileAtlas.RenderTag.POSTPROCESS_DEBLOCKING) return null
when (renderTagThis.connectionType) {
CreateTileAtlas.RenderTag.CONNECT_SELF -> {
var ret = 0
for (i in nearbyTiles.indices) {
if (nearbyTiles[i] == tileThis) {
ret += (1 shl i) // add 1, 2, 4, 8 for i = 0, 1, 2, 3
}
}
return ret
}
CreateTileAtlas.RenderTag.CONNECT_MUTUAL -> {
// make sure to not connect to tiles with no deblocking
var ret = 0
for (i in nearbyTiles.indices) {
if (BlockCodex[nearbyTiles[i]].isSolidForTileCnx && isConnectMutual(nearbyTiles[i]) &&
App.tileMaker.getRenderTag(nearbyTiles[i]).postProcessing == CreateTileAtlas.RenderTag.POSTPROCESS_DEBLOCKING
) {
ret += (1 shl i) // add 1, 2, 4, 8 for i = 0, 1, 2, 3
}
}
return ret
}
else -> return null
}
}
private val deblockerNearbyTilesToSubtile: Array<Array<Point2i>> = arrayOf(
arrayOf(Point2i(0,0),Point2i(0,0),Point2i(0,0),Point2i(0,0),Point2i(3,0),Point2i(3,0),Point2i(3,0),Point2i(3,0),Point2i(2,0),Point2i(2,0),Point2i(2,0),Point2i(2,0),Point2i(4,0),Point2i(4,0),Point2i(4,0),Point2i(4,0)), /*TL*/
arrayOf(Point2i(1,0),Point2i(3,0),Point2i(1,0),Point2i(3,0),Point2i(1,0),Point2i(3,0),Point2i(1,0),Point2i(3,0),Point2i(3,1),Point2i(4,0),Point2i(3,1),Point2i(4,0),Point2i(3,1),Point2i(4,0),Point2i(3,1),Point2i(4,0)), /*TR*/
arrayOf(Point2i(1,1),Point2i(2,1),Point2i(3,1),Point2i(4,0),Point2i(1,1),Point2i(2,1),Point2i(3,1),Point2i(4,0),Point2i(1,1),Point2i(2,1),Point2i(3,1),Point2i(4,0),Point2i(1,1),Point2i(2,1),Point2i(3,1),Point2i(4,0)), /*BR*/
arrayOf(Point2i(0,1),Point2i(0,1),Point2i(2,0),Point2i(2,0),Point2i(2,1),Point2i(2,1),Point2i(4,0),Point2i(4,0),Point2i(0,1),Point2i(0,1),Point2i(2,0),Point2i(2,0),Point2i(2,1),Point2i(2,1),Point2i(4,0),Point2i(4,0)), /*BL*/
)
private fun getNearbyTilesInfoConMutual(x: Int, y: Int, mode: Int): Int {
val nearbyTiles: List<ItemID> = getNearbyTilesPos(x, y).map { world.getTileFrom(mode, it.x, it.y) }
@@ -1075,7 +1123,6 @@ internal object BlocksDrawer {
ORES -> oreTilesBuffer
FLUID -> fluidTilesBuffer
OCCLUSION -> occlusionBuffer
BLURMAP -> blurMap
else -> throw IllegalArgumentException()
}
@@ -1092,7 +1139,8 @@ internal object BlocksDrawer {
ORES -> oreTilesBuffer
FLUID -> fluidTilesBuffer
OCCLUSION -> occlusionBuffer
BLURMAP -> blurMap
BLURMAP_TERR -> blurMapTerr
BLURMAP_WALL -> blurMapWall
else -> throw IllegalArgumentException()
}
@@ -1107,6 +1155,9 @@ internal object BlocksDrawer {
private var _blurTilesBuffer: Texture = Texture(1, 1, Pixmap.Format.RGBA8888)
private val occlusionIntensity = 0.25f // too low value and dark-coloured walls won't darken enough
private val doTilemapUpdate: Boolean
get() = (!world.layerTerrain.ptrDestroyed && App.GLOBAL_RENDER_TIMER % 3 == 0L)
private fun renderUsingBuffer(mode: Int, projectionMatrix: Matrix4, drawGlow: Boolean, drawEmissive: Boolean) {
//Gdx.gl.glClearColor(.094f, .094f, .094f, 0f)
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
@@ -1117,7 +1168,7 @@ internal object BlocksDrawer {
val tileAtlas = when (mode) {
TERRAIN, ORES, WALL, OCCLUSION, FLUID, BLURMAP -> tilesTerrain
TERRAIN, ORES, WALL, OCCLUSION, FLUID, BLURMAP_TERR, BLURMAP_WALL -> tilesTerrain
else -> throw IllegalArgumentException()
}
val sourceBuffer = when(mode) {
@@ -1133,35 +1184,33 @@ internal object BlocksDrawer {
else -> Color.WHITE
}
// write to colour buffer
// As the texture size is very small, multithreading it would be less effective
for (y in 0 until tilesBuffer.height) {
for (x in 0 until tilesBuffer.width) {
val colRaw = sourceBuffer[y, x]
val colMain = colRaw.toInt()
val colSub = colRaw.ushr(32).toInt()
tilesBuffer.setColor(colMain)
tilesBuffer.drawPixel(x, y)
tilesBuffer2.setColor(colSub)
tilesBuffer2.drawPixel(x, y)
}
}
// write blurmap to its own buffer for TERRAIN and WALL
if (mode == TERRAIN || mode == WALL) {
// TODO making it run sporadically without graphical issue would improve the tiling performance
// if (doTilemapUpdate) {
for (y in 0 until tilesBuffer.height) {
for (x in 0 until tilesBuffer.width) {
val colRaw = blurMap[y, x]
val colRaw = sourceBuffer[y, x]
val colMain = colRaw.toInt()
val colSub = colRaw.ushr(32).toInt()
blurTilesBuffer.setColor(colMain)
blurTilesBuffer.drawPixel(x, y)
tilesBuffer.setColor(colMain)
tilesBuffer.drawPixel(x, y)
tilesBuffer2.setColor(colSub)
tilesBuffer2.drawPixel(x, y)
// write blurmap to its own buffer for TERRAIN and WALL
if (mode == TERRAIN || mode == WALL) {
val colRaw = (if (mode == TERRAIN) blurMapTerr else blurMapWall)[y, x]
val colMain = colRaw.toInt()
blurTilesBuffer.setColor(colMain)
blurTilesBuffer.drawPixel(x, y)
}
}
}
}
// }
_tilesBufferAsTex.dispose()
@@ -1256,7 +1305,8 @@ internal object BlocksDrawer {
oreTilesBuffer = UnsafeLong2D(tilesInHorizontal, tilesInVertical)
fluidTilesBuffer = UnsafeLong2D(tilesInHorizontal, tilesInVertical)
occlusionBuffer = UnsafeLong2D(tilesInHorizontal, tilesInVertical)
blurMap = UnsafeLong2D(tilesInHorizontal, tilesInVertical)
blurMapTerr = UnsafeLong2D(tilesInHorizontal, tilesInVertical)
blurMapWall = UnsafeLong2D(tilesInHorizontal, tilesInVertical)
tempRenderTypeBuffer = UnsafeLong2D(hTilesInHorizontal, hTilesInVertical)
tilesBuffer.dispose()
@@ -1346,7 +1396,8 @@ internal object BlocksDrawer {
if (::oreTilesBuffer.isInitialized) oreTilesBuffer.destroy()
if (::fluidTilesBuffer.isInitialized) fluidTilesBuffer.destroy()
if (::occlusionBuffer.isInitialized) occlusionBuffer.destroy()
if (::blurMap.isInitialized) blurMap.destroy()
if (::blurMapTerr.isInitialized) blurMapTerr.destroy()
if (::blurMapWall.isInitialized) blurMapWall.destroy()
if (::tempRenderTypeBuffer.isInitialized) tempRenderTypeBuffer.destroy()
if (::batch.isInitialized) batch.tryDispose()

View File

@@ -87,7 +87,7 @@ class CreateTileAtlas {
lateinit var tagsByTileNum: HashArray<RenderTag>; private set
lateinit var itemSheetNumbers: HashMap<ItemID, Int> // TileID, Int
private set
private val defaultRenderTag = RenderTag(3, RenderTag.CONNECT_SELF, RenderTag.MASK_NA, 0) // 'update' block
private val defaultRenderTag = RenderTag(3, RenderTag.CONNECT_SELF, RenderTag.MASK_NA, 0, 0) // 'update' block
var initialised = false
private set
@@ -478,20 +478,23 @@ class CreateTileAtlas {
val maskType = if (tilesPixmap.width >= 3*W_SUBTILE_GENERIC) MASK_SUBTILE_GRASS else MASK_SUBTILE_GENERIC
var connectionType0 = 0
var tilingMode = 0
var postProcessing = 0
for (x in 0 until 4) {
// val pixelY0 = (tilesPixmap.getPixel(x, 0).and(255) >= 128).toInt(x)
val pixelY1 = (tilesPixmap.getPixel(x, 1).and(255) >= 128).toInt(x)
val pixelY2 = (tilesPixmap.getPixel(x, 2).and(255) >= 128).toInt(x)
val pixelY3 = (tilesPixmap.getPixel(x, 3).and(255) >= 128).toInt(x)
tilingMode += pixelY1
connectionType0 += pixelY2
postProcessing += pixelY3
}
val connectionType = when (connectionType0) {
1 -> CONNECT_MUTUAL
2 -> CONNECT_SELF
else -> throw IllegalArgumentException("$connectionType0")
}
addTag(blockID, connectionType, maskType, tilingMode)
addTag(blockID, connectionType, maskType, tilingMode, postProcessing)
// println("drawToAtlantes tile: $blockID with mode $tilingMode")
drawToAtlantes(tilesPixmap, tilesGlowPixmap, tilesEmissivePixmap, maskType)
}
@@ -541,13 +544,13 @@ class CreateTileAtlas {
* This function must precede the drawToAtlantes() function, as the marking requires the variable
* 'atlasCursor' and the draw function modifies it!
*/
private fun addTag(id: ItemID, connectionType: Int, maskType: Int, tilingMode: Int = TILING_FULL) {
private fun addTag(id: ItemID, connectionType: Int, maskType: Int, tilingMode: Int = TILING_FULL, postProcessing: Int = 0) {
if (tags.containsKey(id)) {
throw Error("Block $id already exists")
}
tags[id] = RenderTag(atlasCursor, connectionType, maskType, tilingMode)
tagsByTileNum[atlasCursor.toLong()] = RenderTag(atlasCursor, connectionType, maskType, tilingMode)
tags[id] = RenderTag(atlasCursor, connectionType, maskType, tilingMode, postProcessing)
tagsByTileNum[atlasCursor.toLong()] = RenderTag(atlasCursor, connectionType, maskType, tilingMode, postProcessing)
printdbg(this, "tileName ${id} ->> tileNumber ${atlasCursor}")
}
@@ -714,7 +717,7 @@ class CreateTileAtlas {
/**
* @param tileNumber ordinal number of a tile in the texture atlas
*/
data class RenderTag(val tileNumber: Int, val connectionType: Int, val maskType: Int, val tilingMode: Int) {
data class RenderTag(val tileNumber: Int, val connectionType: Int, val maskType: Int, val tilingMode: Int, val postProcessing: Int) {
companion object {
const val CONNECT_MUTUAL = 0
const val CONNECT_SELF = 1
@@ -740,6 +743,9 @@ class CreateTileAtlas {
const val TILING_BRICK_LARGE = 4
const val TILING_BRICK_LARGE_NOFLIP = 5
const val POSTPROCESS_NONE = 0
const val POSTPROCESS_DEBLOCKING = 1
fun maskTypeToTileCount(maskType: Int) = when (maskType) {
MASK_NA -> 1
MASK_16 -> 16

View File

@@ -191,8 +191,8 @@ void main() {
vec4 tileU = getFragColorForOnscreenCoord1(fragCoord + blurU);
vec4 tileD = getFragColorForOnscreenCoord1(fragCoord + blurD);
vec4 blurH = (tileC + tileC + tileL + tileR) * _four;
vec4 blurV = (tileC + tileC + tileU + tileD) * _four;
vec4 blurH = (tileC + tileL + tileR) * _three;
vec4 blurV = (tileC + tileU + tileD) * _three;
vec4 blurPower = tile_breakage_blur[2];
vec4 finalTile = mix(
@@ -206,5 +206,5 @@ void main() {
vec4 finalColor = fma(mix(finalTile, finalBreakage, finalBreakage.a), bc.xxxy, finalTile * bc.yyyx);
fragColor = mix(colourFilter, colourFilter * finalColor, mulBlendIntensity);
// fragColor = blurPower;
// fragColor = mix(fragColor, blurPower, 0.18); // debug overlay
}