code cleanup

This commit is contained in:
minjaesong
2025-09-16 10:26:03 +09:00
parent a5da200507
commit 3011c73168
2 changed files with 3 additions and 768 deletions

View File

@@ -25,78 +25,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
private val idct8TempBuffer = FloatArray(64)
private val idct16TempBuffer = FloatArray(256) // For 16x16 IDCT
private val idct16SeparableBuffer = FloatArray(256) // For separable 16x16 IDCT
// Lossless IDCT functions for float16 coefficients (no quantization)
private fun tevIdct8x8_lossless(coeffs: FloatArray): IntArray {
val result = IntArray(64)
// Fast separable IDCT (row-column decomposition) for lossless coefficients
// First pass: Process rows (8 1D IDCTs)
for (row in 0 until 8) {
for (col in 0 until 8) {
var sum = 0f
for (u in 0 until 8) {
sum += dctBasis8[u][col] * coeffs[row * 8 + u]
}
idct8TempBuffer[row * 8 + col] = sum * 0.5f
}
}
// Second pass: Process columns (8 1D IDCTs)
for (col in 0 until 8) {
for (row in 0 until 8) {
var sum = 0f
for (v in 0 until 8) {
sum += dctBasis8[v][row] * idct8TempBuffer[v * 8 + col]
}
val finalValue = sum * 0.5f + 128f
result[row * 8 + col] = if (finalValue.isNaN() || finalValue.isInfinite()) {
println("NaN/Inf detected in 8x8 IDCT at ($row,$col): sum=$sum, finalValue=$finalValue")
128 // Default to middle gray
} else {
finalValue.roundToInt().coerceIn(0, 255)
}
}
}
return result
}
private fun tevIdct16x16_lossless(coeffs: FloatArray): IntArray {
val result = IntArray(256)
// Fast separable IDCT (row-column decomposition) for 16x16 lossless coefficients
// First pass: Process rows (16 1D IDCTs)
for (row in 0 until 16) {
for (col in 0 until 16) {
var sum = 0f
for (u in 0 until 16) {
sum += dctBasis16[u][col] * coeffs[row * 16 + u]
}
idct16TempBuffer[row * 16 + col] = sum * 0.25f
}
}
// Second pass: Process columns (16 1D IDCTs)
for (col in 0 until 16) {
for (row in 0 until 16) {
var sum = 0f
for (v in 0 until 16) {
sum += dctBasis16[v][row] * idct16TempBuffer[v * 16 + col]
}
val finalValue = sum * 0.25f + 128f
result[row * 16 + col] = if (finalValue.isNaN() || finalValue.isInfinite()) {
println("NaN/Inf detected in 16x16 IDCT at ($row,$col): sum=$sum, finalValue=$finalValue")
128 // Default to middle gray
} else {
finalValue.roundToInt().coerceIn(0, 255)
}
}
}
return result
}
private fun getFirstGPU(): GraphicsAdapter? {
return vm.findPeribyType(VM.PERITYPE_GPU_AND_TERM)?.peripheral as? GraphicsAdapter
@@ -3665,52 +3593,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
}
}
private fun convertAndDoNothing(
blocks: Array<ShortArray?>, quantTable: IntArray, qScale: Int, rateControlFactors: FloatArray,
blocksX: Int, blocksY: Int,
kLinearGradient: IntArray, kAlphaSqrt2: IntArray, kHalfSqrt2: Int
): Array<FloatArray?> {
val coeffsSize = 16 * 16
val numBlocks = blocksX * blocksY
val blocksMid = Array(numBlocks) { IntArray(coeffsSize) }
for (blockIndex in 0 until numBlocks) {
val block = blocks[blockIndex]
if (block != null) {
val rateControlFactor = rateControlFactors[blockIndex]
for (i in 0 until coeffsSize) {
val quantIdx = i.coerceIn(0, quantTable.size - 1)
if (i == 0) {
// DC coefficient: lossless (no quantization)
val dcValue = block[i].toInt()
blocksMid[blockIndex][i] = dcValue
} else {
// AC coefficients: use quantization intervals
val quant = (quantTable[quantIdx] * jpeg_quality_to_mult(qScale * rateControlFactor)).coerceIn(1f, 255f).toInt()
// Standard dequantized value (midpoint)
blocksMid[blockIndex][i] = block[i].toInt() * quant
}
}
}
}
val result = Array<FloatArray?>(blocks.size) { null }
for (blockIndex in 0 until numBlocks) {
val block = blocks[blockIndex]
if (block != null) {
result[blockIndex] = FloatArray(coeffsSize) { i ->
blocksMid[blockIndex][i].toFloat()
}
}
}
return result
}
private fun convertAndOptimize8x8Blocks(
blocks: Array<ShortArray?>, quantTable: IntArray, qScale: Int, rateControlFactors: FloatArray,
blocksX: Int, blocksY: Int,
@@ -3982,10 +3864,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
} catch (e: Exception) {
println("TAV decode error: ${e.message}")
}
// if (enableDeblocking) {
// tavAdaptiveDeblockingFilter(currentRGBAddr, width, height)
// }
}
private fun decodeDWTIntraTileRGB(readPtr: Long, tileX: Int, tileY: Int, currentRGBAddr: Long,
@@ -4310,51 +4188,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
)
}
private fun applyDWT53Forward(data: FloatArray, width: Int, height: Int) {
// TODO: Implement 5/3 forward DWT
// Lifting scheme implementation for 5/3 reversible filter
}
private fun applyDWT53Inverse(data: FloatArray, width: Int, height: Int) {
// 5/3 reversible DWT inverse using lifting scheme
// First apply horizontal inverse DWT on all rows
val tempRow = FloatArray(width)
for (y in 0 until height) {
for (x in 0 until width) {
tempRow[x] = data[y * width + x]
}
applyLift53InverseHorizontal(tempRow, width)
for (x in 0 until width) {
data[y * width + x] = tempRow[x]
}
}
// Then apply vertical inverse DWT on all columns
val tempCol = FloatArray(height)
for (x in 0 until width) {
for (y in 0 until height) {
tempCol[y] = data[y * width + x]
}
applyLift53InverseVertical(tempCol, height)
for (y in 0 until height) {
data[y * width + x] = tempCol[y]
}
}
}
private fun applyDWT97Forward(data: FloatArray, width: Int, height: Int) {
// TODO: Implement 9/7 forward DWT
// Lifting scheme implementation for 9/7 irreversible filter
}
private fun generateWindowFunction(window: FloatArray, size: Int) {
// Raised cosine (Hann) window for smooth blending
for (i in 0 until size) {
val t = i.toFloat() / (size - 1)
window[i] = 0.5f * (1.0f - kotlin.math.cos(PI * t))
}
}
private fun applyDWTInverseMultiLevel(data: FloatArray, width: Int, height: Int, levels: Int, filterType: Int) {
// Multi-level inverse DWT - reconstruct from smallest to largest (reverse of encoder)
val size = width // Full tile size (112 for TAV)
@@ -4411,84 +4244,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
}
}
private fun applyDWT97Inverse(data: FloatArray, width: Int, height: Int) {
// 9/7 irreversible DWT inverse using lifting scheme
// First apply horizontal inverse DWT on all rows
val tempRow = FloatArray(width)
for (y in 0 until height) {
for (x in 0 until width) {
tempRow[x] = data[y * width + x]
}
applyLift97InverseHorizontal(tempRow, width)
for (x in 0 until width) {
data[y * width + x] = tempRow[x]
}
}
// Then apply vertical inverse DWT on all columns
val tempCol = FloatArray(height)
for (x in 0 until width) {
for (y in 0 until height) {
tempCol[y] = data[y * width + x]
}
applyLift97InverseVertical(tempCol, height)
for (y in 0 until height) {
data[y * width + x] = tempCol[y]
}
}
}
private fun applyLift97InverseHorizontal(row: FloatArray, width: Int) { TODO() }
private fun applyLift97InverseVertical(col: FloatArray, height: Int) { TODO() }
// 1D lifting scheme implementations for 5/3 filter
private fun applyLift53InverseHorizontal(data: FloatArray, length: Int) {
if (length < 2) return
val temp = FloatArray(length)
val half = (length + 1) / 2
// Separate even and odd samples (inverse interleaving)
for (i in 0 until half) {
temp[i] = data[2 * i] // Even samples (low-pass)
}
for (i in 0 until length / 2) {
temp[half + i] = data[2 * i + 1] // Odd samples (high-pass)
}
// Inverse lifting steps for 5/3 filter
// Step 2: Undo update step - even[i] -= (odd[i-1] + odd[i] + 2) >> 2
for (i in 1 until half) {
val oddPrev = if (i - 1 >= 0) temp[half + i - 1] else 0.0f
val oddCurr = if (i < length / 2) temp[half + i] else 0.0f
temp[i] += (oddPrev + oddCurr + 2.0f) / 4.0f
}
if (half > 0) {
val oddCurr = if (0 < length / 2) temp[half] else 0.0f
temp[0] += oddCurr / 2.0f
}
// Step 1: Undo predict step - odd[i] += (even[i] + even[i+1]) >> 1
for (i in 0 until length / 2) {
val evenCurr = temp[i]
val evenNext = if (i + 1 < half) temp[i + 1] else temp[half - 1]
temp[half + i] -= (evenCurr + evenNext) / 2.0f
}
// Interleave back
for (i in 0 until half) {
data[2 * i] = temp[i]
}
for (i in 0 until length / 2) {
data[2 * i + 1] = temp[half + i]
}
}
private fun applyLift53InverseVertical(data: FloatArray, length: Int) {
// Same as horizontal but for vertical direction
applyLift53InverseHorizontal(data, length)
}
// 1D lifting scheme implementations for 9/7 irreversible filter
private fun applyDWT97Inverse1D(data: FloatArray, length: Int) {
if (length < 2) return
@@ -4643,426 +4398,4 @@ class GraphicsJSR223Delegate(private val vm: VM) {
}
}
private fun tavAdaptiveDeblockingFilter(rgbAddr: Long, width: Int, height: Int) {
val tileSize = 112
val tilesX = (width + tileSize - 1) / tileSize
val tilesY = (height + tileSize - 1) / tileSize
// Process vertical seams (between horizontally adjacent tiles)
for (tileY in 0 until tilesY) {
for (tileX in 0 until tilesX - 1) {
val seamX = (tileX + 1) * tileSize // Actual boundary between tiles
deblockVerticalSeamStrong(rgbAddr, width, height, seamX, tileY * tileSize, tileSize)
}
}
// Process horizontal seams (between vertically adjacent tiles)
for (tileY in 0 until tilesY - 1) {
for (tileX in 0 until tilesX) {
val seamY = (tileY + 1) * tileSize // Actual boundary between tiles
deblockHorizontalSeamStrong(rgbAddr, width, height, tileX * tileSize, seamY, tileSize)
}
}
}
private fun deblockVerticalSeamStrong(rgbAddr: Long, width: Int, height: Int, seamX: Int, startY: Int, tileHeight: Int) {
if (seamX >= width) return
val endY = minOf(startY + tileHeight, height)
for (y in startY until endY) {
if (y >= height) break
// Check for discontinuity across the seam
val leftX = seamX - 1
val rightX = seamX
if (leftX >= 0 && rightX < width) {
val leftOffset = (y * width + leftX) * 3L
val rightOffset = (y * width + rightX) * 3L
val leftR = vm.peek(rgbAddr + leftOffset).toInt() and 0xFF
val leftG = vm.peek(rgbAddr + leftOffset + 1).toInt() and 0xFF
val leftB = vm.peek(rgbAddr + leftOffset + 2).toInt() and 0xFF
val rightR = vm.peek(rgbAddr + rightOffset).toInt() and 0xFF
val rightG = vm.peek(rgbAddr + rightOffset + 1).toInt() and 0xFF
val rightB = vm.peek(rgbAddr + rightOffset + 2).toInt() and 0xFF
// Calculate discontinuity strength
val diffR = abs(leftR - rightR)
val diffG = abs(leftG - rightG)
val diffB = abs(leftB - rightB)
val maxDiff = maxOf(diffR, diffG, diffB)
// Only apply deblocking if there's a significant discontinuity
if (maxDiff in 2 until 120) {
// Adaptive filter radius: wider for smooth gradients, narrower for sharp edges
val filterRadius = when {
maxDiff <= 15 -> 6 // Very smooth gradients: wide filter (13 pixels)
maxDiff <= 30 -> 4 // Moderate gradients: medium filter (9 pixels)
maxDiff <= 60 -> 3 // Sharp transitions: narrow filter (7 pixels)
else -> 2 // Very sharp edges: minimal filter (5 pixels)
}
for (dx in -filterRadius..filterRadius) {
val x = seamX + dx
if (x in 0 until width) {
val offset = (y * width + x) * 3L
val currentR = vm.peek(rgbAddr + offset).toInt() and 0xFF
val currentG = vm.peek(rgbAddr + offset + 1).toInt() and 0xFF
val currentB = vm.peek(rgbAddr + offset + 2).toInt() and 0xFF
var sumR = 0.0f
var sumG = 0.0f
var sumB = 0.0f
var weightSum = 0.0f
// Bilateral filtering with spatial and intensity weights
for (sx in maxOf(0, x-filterRadius)..minOf(width-1, x+filterRadius)) {
val sOffset = (y * width + sx) * 3L
val sR = vm.peek(rgbAddr + sOffset).toInt() and 0xFF
val sG = vm.peek(rgbAddr + sOffset + 1).toInt() and 0xFF
val sB = vm.peek(rgbAddr + sOffset + 2).toInt() and 0xFF
// Spatial weight (distance from current pixel)
val spatialWeight = 1.0f / (1.0f + abs(sx - x))
// Intensity weight (color similarity)
val colorDiff = sqrt(((sR - currentR) * (sR - currentR) +
(sG - currentG) * (sG - currentG) +
(sB - currentB) * (sB - currentB)).toFloat())
val intensityWeight = exp(-colorDiff / 30.0f)
val totalWeight = spatialWeight * intensityWeight
sumR += sR * totalWeight
sumG += sG * totalWeight
sumB += sB * totalWeight
weightSum += totalWeight
}
if (weightSum > 0) {
val filteredR = (sumR / weightSum).toInt()
val filteredG = (sumG / weightSum).toInt()
val filteredB = (sumB / weightSum).toInt()
// Concentrate blur heavily at the seam boundary
val distance = abs(dx).toFloat()
val blendWeight = when {
distance == 0.0f -> 0.95f // Maximum blur at exact seam
distance == 1.0f -> 0.8f // Strong blur adjacent to seam
distance == 2.0f -> 0.5f // Medium blur 2 pixels away
else -> exp(-distance * distance / 1.5f) * 0.3f // Gentle falloff beyond
}
val finalR = (currentR * (1 - blendWeight) + filteredR * blendWeight).toInt().coerceIn(0, 255)
val finalG = (currentG * (1 - blendWeight) + filteredG * blendWeight).toInt().coerceIn(0, 255)
val finalB = (currentB * (1 - blendWeight) + filteredB * blendWeight).toInt().coerceIn(0, 255)
vm.poke(rgbAddr + offset, finalR.toByte())
vm.poke(rgbAddr + offset + 1, finalG.toByte())
vm.poke(rgbAddr + offset + 2, finalB.toByte())
}
}
}
}
}
}
}
private fun deblockHorizontalSeamStrong(rgbAddr: Long, width: Int, height: Int, startX: Int, seamY: Int, tileWidth: Int) {
if (seamY >= height) return
val endX = minOf(startX + tileWidth, width)
for (x in startX until endX) {
if (x >= width) break
// Check for discontinuity across the seam
val topY = seamY - 1
val bottomY = seamY
if (topY >= 0 && bottomY < height) {
val topOffset = (topY * width + x) * 3L
val bottomOffset = (bottomY * width + x) * 3L
val topR = vm.peek(rgbAddr + topOffset).toInt() and 0xFF
val topG = vm.peek(rgbAddr + topOffset + 1).toInt() and 0xFF
val topB = vm.peek(rgbAddr + topOffset + 2).toInt() and 0xFF
val bottomR = vm.peek(rgbAddr + bottomOffset).toInt() and 0xFF
val bottomG = vm.peek(rgbAddr + bottomOffset + 1).toInt() and 0xFF
val bottomB = vm.peek(rgbAddr + bottomOffset + 2).toInt() and 0xFF
// Calculate discontinuity strength
val diffR = abs(topR - bottomR)
val diffG = abs(topG - bottomG)
val diffB = abs(topB - bottomB)
val maxDiff = maxOf(diffR, diffG, diffB)
// Only apply deblocking if there's a significant discontinuity
if (maxDiff in 2 until 120) {
// Adaptive filter radius: wider for smooth gradients, narrower for sharp edges
val filterRadius = when {
maxDiff <= 15 -> 6 // Very smooth gradients: wide filter (13 pixels)
maxDiff <= 30 -> 4 // Moderate gradients: medium filter (9 pixels)
maxDiff <= 60 -> 3 // Sharp transitions: narrow filter (7 pixels)
else -> 2 // Very sharp edges: minimal filter (5 pixels)
}
for (dy in -filterRadius..filterRadius) {
val y = seamY + dy
if (y in 0 until height) {
val offset = (y * width + x) * 3L
val currentR = vm.peek(rgbAddr + offset).toInt() and 0xFF
val currentG = vm.peek(rgbAddr + offset + 1).toInt() and 0xFF
val currentB = vm.peek(rgbAddr + offset + 2).toInt() and 0xFF
var sumR = 0.0f
var sumG = 0.0f
var sumB = 0.0f
var weightSum = 0.0f
// Bilateral filtering with spatial and intensity weights
for (sy in maxOf(0, y-filterRadius)..minOf(height-1, y+filterRadius)) {
val sOffset = (sy * width + x) * 3L
val sR = vm.peek(rgbAddr + sOffset).toInt() and 0xFF
val sG = vm.peek(rgbAddr + sOffset + 1).toInt() and 0xFF
val sB = vm.peek(rgbAddr + sOffset + 2).toInt() and 0xFF
// Spatial weight (distance from current pixel)
val spatialWeight = 1.0f / (1.0f + abs(sy - y))
// Intensity weight (color similarity)
val colorDiff = sqrt(((sR - currentR) * (sR - currentR) +
(sG - currentG) * (sG - currentG) +
(sB - currentB) * (sB - currentB)).toFloat())
val intensityWeight = exp(-colorDiff / 30.0f)
val totalWeight = spatialWeight * intensityWeight
sumR += sR * totalWeight
sumG += sG * totalWeight
sumB += sB * totalWeight
weightSum += totalWeight
}
if (weightSum > 0) {
val filteredR = (sumR / weightSum).toInt()
val filteredG = (sumG / weightSum).toInt()
val filteredB = (sumB / weightSum).toInt()
// Concentrate blur heavily at the seam boundary
val distance = abs(dy).toFloat()
val blendWeight = when {
distance == 0.0f -> 0.95f // Maximum blur at exact seam
distance == 1.0f -> 0.8f // Strong blur adjacent to seam
distance == 2.0f -> 0.5f // Medium blur 2 pixels away
else -> exp(-distance * distance / 1.5f) * 0.3f // Gentle falloff beyond
}
val finalR = (currentR * (1 - blendWeight) + filteredR * blendWeight).toInt().coerceIn(0, 255)
val finalG = (currentG * (1 - blendWeight) + filteredG * blendWeight).toInt().coerceIn(0, 255)
val finalB = (currentB * (1 - blendWeight) + filteredB * blendWeight).toInt().coerceIn(0, 255)
vm.poke(rgbAddr + offset, finalR.toByte())
vm.poke(rgbAddr + offset + 1, finalG.toByte())
vm.poke(rgbAddr + offset + 2, finalB.toByte())
}
}
}
}
}
}
}
private fun analyzeTextureComplexity(rgbAddr: Long, width: Int, height: Int, centerX: Int, centerY: Int, isVerticalSeam: Boolean): Float {
val radius = 4
var totalVariance = 0.0f
var count = 0
// Calculate variance in a small window around the seam
for (dy in -radius..radius) {
for (dx in -radius..radius) {
val x = centerX + dx
val y = centerY + dy
if (x >= 0 && x < width && y >= 0 && y < height) {
val offset = (y * width + x) * 3L
val r = vm.peek(rgbAddr + offset).toInt() and 0xFF
val g = vm.peek(rgbAddr + offset + 1).toInt() and 0xFF
val b = vm.peek(rgbAddr + offset + 2).toInt() and 0xFF
val luma = 0.299f * r + 0.587f * g + 0.114f * b
// Compare with adjacent pixels to measure local variance
if (x > 0) {
val leftOffset = (y * width + (x-1)) * 3L
val leftR = vm.peek(rgbAddr + leftOffset).toInt() and 0xFF
val leftG = vm.peek(rgbAddr + leftOffset + 1).toInt() and 0xFF
val leftB = vm.peek(rgbAddr + leftOffset + 2).toInt() and 0xFF
val leftLuma = 0.299f * leftR + 0.587f * leftG + 0.114f * leftB
totalVariance += abs(luma - leftLuma)
count++
}
if (y > 0) {
val topOffset = ((y-1) * width + x) * 3L
val topR = vm.peek(rgbAddr + topOffset).toInt() and 0xFF
val topG = vm.peek(rgbAddr + topOffset + 1).toInt() and 0xFF
val topB = vm.peek(rgbAddr + topOffset + 2).toInt() and 0xFF
val topLuma = 0.299f * topR + 0.587f * topG + 0.114f * topB
totalVariance += abs(luma - topLuma)
count++
}
}
}
}
return if (count > 0) totalVariance / count else 0.0f
}
private fun bilinearInterpolate(
dataPtr: Long, width: Int, height: Int,
x: Float, y: Float
): Float {
val x0 = floor(x).toInt()
val y0 = floor(y).toInt()
val x1 = x0 + 1
val y1 = y0 + 1
if (x0 < 0 || y0 < 0 || x1 >= width || y1 >= height) {
return 0.0f // Out of bounds
}
val fx = x - x0
val fy = y - y0
val p00 = vm.peekFloat(dataPtr + (y0 * width + x0) * 4L)!!
val p10 = vm.peekFloat(dataPtr + (y0 * width + x1) * 4L)!!
val p01 = vm.peekFloat(dataPtr + (y1 * width + x0) * 4L)!!
val p11 = vm.peekFloat(dataPtr + (y1 * width + x1) * 4L)!!
return p00 * (1 - fx) * (1 - fy) +
p10 * fx * (1 - fy) +
p01 * (1 - fx) * fy +
p11 * fx * fy
}
/**
* TAV deblocking filter - reduces DWT quantization artifacts and tile boundary artifacts
* Applies a gentle smoothing filter across tile boundaries and high-frequency areas
*/
private fun tavDeblockingFilter(rgbAddr: Long, width: Int, height: Int) {
val tileSize = 112 // TAV uses 112x112 tiles
val tilesX = (width + tileSize - 1) / tileSize
val tilesY = (height + tileSize - 1) / tileSize
val thisAddrIncVec: Long = if (rgbAddr < 0) -1 else 1
// Process tile boundaries (horizontal and vertical)
for (tileY in 0 until tilesY) {
for (tileX in 0 until tilesX) {
val startX = tileX * tileSize
val startY = tileY * tileSize
val endX = kotlin.math.min(startX + tileSize, width)
val endY = kotlin.math.min(startY + tileSize, height)
// Smooth vertical tile boundaries
if (tileX > 0 && startX < width) {
for (y in startY until endY) {
smoothVerticalBoundary(rgbAddr, width, height, startX - 1, y, thisAddrIncVec)
}
}
// Smooth horizontal tile boundaries
if (tileY > 0 && startY < height) {
for (x in startX until endX) {
smoothHorizontalBoundary(rgbAddr, width, height, x, startY - 1, thisAddrIncVec)
}
}
}
}
// Apply gentle smoothing to reduce DWT quantization artifacts
applyDWTSmoothing(rgbAddr, width, height, thisAddrIncVec)
}
private fun smoothVerticalBoundary(rgbAddr: Long, width: Int, height: Int, x: Int, y: Int, addrInc: Long) {
if (x < 1 || x >= width - 1 || y < 0 || y >= height) return
for (channel in 0 until 3) {
val leftOffset = (y.toLong() * width + (x - 1)) * 3 + channel
val centerOffset = (y.toLong() * width + x) * 3 + channel
val rightOffset = (y.toLong() * width + (x + 1)) * 3 + channel
val left = vm.peek(rgbAddr + leftOffset * addrInc)?.toUint()?.toInt() ?: 0
val center = vm.peek(rgbAddr + centerOffset * addrInc)?.toUint()?.toInt() ?: 0
val right = vm.peek(rgbAddr + rightOffset * addrInc)?.toUint()?.toInt() ?: 0
// Apply gentle 3-tap filter: [0.25, 0.5, 0.25]
val smoothed = ((left + 2 * center + right) / 4).coerceIn(0, 255)
vm.poke(rgbAddr + centerOffset * addrInc, smoothed.toByte())
}
}
private fun smoothHorizontalBoundary(rgbAddr: Long, width: Int, height: Int, x: Int, y: Int, addrInc: Long) {
if (x < 0 || x >= width || y < 1 || y >= height - 1) return
for (channel in 0 until 3) {
val topOffset = ((y - 1).toLong() * width + x) * 3 + channel
val centerOffset = (y.toLong() * width + x) * 3 + channel
val bottomOffset = ((y + 1).toLong() * width + x) * 3 + channel
val top = vm.peek(rgbAddr + topOffset * addrInc)?.toUint()?.toInt() ?: 0
val center = vm.peek(rgbAddr + centerOffset * addrInc)?.toUint()?.toInt() ?: 0
val bottom = vm.peek(rgbAddr + bottomOffset * addrInc)?.toUint()?.toInt() ?: 0
// Apply gentle 3-tap filter: [0.25, 0.5, 0.25]
val smoothed = ((top + 2 * center + bottom) / 4).coerceIn(0, 255)
vm.poke(rgbAddr + centerOffset * addrInc, smoothed.toByte())
}
}
private fun applyDWTSmoothing(rgbAddr: Long, width: Int, height: Int, addrInc: Long) {
// Apply very gentle smoothing to reduce DWT quantization artifacts
// Uses a 3x3 Gaussian-like kernel with low strength
val kernel = arrayOf(
arrayOf(1, 2, 1),
arrayOf(2, 4, 2),
arrayOf(1, 2, 1)
)
val kernelSum = 16
// Process inner pixels only to avoid boundary issues
for (y in 1 until height - 1) {
for (x in 1 until width - 1) {
for (channel in 0 until 3) {
var sum = 0
for (ky in -1..1) {
for (kx in -1..1) {
val pixelOffset = ((y + ky).toLong() * width + (x + kx)) * 3 + channel
val pixelValue = vm.peek(rgbAddr + pixelOffset * addrInc)?.toUint()?.toInt() ?: 0
sum += pixelValue * kernel[ky + 1][kx + 1]
}
}
val centerOffset = (y.toLong() * width + x) * 3 + channel
val originalValue = vm.peek(rgbAddr + centerOffset * addrInc)?.toUint()?.toInt() ?: 0
// Blend original with smoothed (low strength: 75% original, 25% smoothed)
val smoothedValue = sum / kernelSum
val blendedValue = ((originalValue * 3 + smoothedValue) / 4).coerceIn(0, 255)
vm.poke(rgbAddr + centerOffset * addrInc, blendedValue.toByte())
}
}
}
}
}