commonMain.ru.casperix.multiplatform.util.PixelMapDrawer.kt Maven / Gradle / Ivy
The newest version!
package ru.casperix.multiplatform.util
import ru.casperix.math.color.float32.Color4f
import ru.casperix.math.color.uint8.Color4b
import ru.casperix.math.vector.int32.Vector2i
import ru.casperix.math.vector.vectorOf
import ru.casperix.misc.max
import ru.casperix.renderer.pixel_map.PixelMap
object PixelMapDrawer {
val bytesPerPixel = 4
fun drawImage(
receiverImage: PixelMap,
receiverPosition: Vector2i,
sourceImage: PixelMap,
sourcePosition: Vector2i,
areaSize: Vector2i,
alphaBlending: Boolean
) {
for (y in 0 until areaSize.y) {
val targetOffset = Vector2i(0, y)
val sourceOffset = sourcePosition + targetOffset
blitRow(
receiverImage,
receiverPosition + targetOffset,
sourceImage,
sourceOffset,
areaSize.x,
alphaBlending
)
}
}
fun fillColor(
receiverImage: PixelMap,
receiverPosition: Vector2i,
sourceColor: Color4b,
receiverSize: Vector2i,
alphaBlending: Boolean
) {
for (y in 0 until receiverSize.y) {
val targetOffset = Vector2i(0, y)
blitRow(receiverImage, receiverPosition + targetOffset, sourceColor, receiverSize.x, alphaBlending)
}
}
fun blitRow(
receiverImage: PixelMap,
receiverPosition: Vector2i,
sourceImage: PixelMap,
sourcePosition: Vector2i,
width: Int,
alphaBlending: Boolean
) {
if (width <= 0) {
} else if (sourcePosition.y < 0 || sourcePosition.y >= sourceImage.height || receiverPosition.y < 0 || receiverPosition.y >= receiverImage.height) {
} else if (sourcePosition.x < 0) {
val offset = -sourcePosition.x
blitRow(
receiverImage,
receiverPosition,
sourceImage,
Vector2i(0, sourcePosition.y),
width - offset,
alphaBlending
)
} else if (sourcePosition.x + width > sourceImage.width) {
val widthNext = sourceImage.width - sourcePosition.x
blitRow(receiverImage, receiverPosition, sourceImage, sourcePosition, widthNext, alphaBlending)
} else if (receiverPosition.x < 0) {
val offset = -receiverPosition.x
blitRow(
receiverImage,
Vector2i(0, receiverPosition.y),
sourceImage,
sourcePosition,
width - offset,
alphaBlending
)
} else if (receiverPosition.x + width > receiverImage.width) {
val widthNext = receiverImage.width - receiverPosition.x
blitRow(receiverImage, receiverPosition, sourceImage, sourcePosition, widthNext, alphaBlending)
} else {
val sourceColorOffset = (sourcePosition.x + sourcePosition.y * sourceImage.width)
val sourceOffset = bytesPerPixel * sourceColorOffset
val sourceLength = bytesPerPixel * width
val sourceBytes = sourceImage.bytes.data.sliceArray(sourceOffset until (sourceOffset + sourceLength))
val receiverColorOffset = (receiverPosition.x + receiverPosition.y * receiverImage.width)
if (alphaBlending) {
val sourceMap = sourceImage.RGBA() ?: return
val receiverMap = receiverImage.RGBA() ?: return
(0 until width).forEach { offset ->
val sourceColor = sourceMap.get(sourcePosition + vectorOf(offset, 0))
val receiverColor = receiverMap.get(receiverPosition + vectorOf(offset, 0))
val outputColor = blend(receiverColor, sourceColor)
receiverMap.set(receiverPosition + vectorOf(offset, 0), outputColor)
}
} else {
val receiverOffset = bytesPerPixel * receiverColorOffset
sourceBytes.copyInto(receiverImage.bytes.data, receiverOffset, 0, sourceLength)
// receiverImage.bytes.data.put(receiverOffset, sourceBytes, 0, sourceLength)
}
}
}
fun blitRow(
targetImage: PixelMap,
targetPosition: Vector2i,
sourceColor: Color4b,
width: Int,
alphaBlending: Boolean
) {
if (width <= 0) {
} else if (targetPosition.y < 0 || targetPosition.y >= targetImage.height) {
} else if (targetPosition.x < 0) {
val offset = -targetPosition.x
blitRow(targetImage, Vector2i(0, targetPosition.y), sourceColor, width - offset, alphaBlending)
} else if (targetPosition.x + width >= targetImage.width) {
val widthNext = targetImage.width - targetPosition.x - 1
blitRow(targetImage, targetPosition, sourceColor, widthNext, alphaBlending)
} else {
val RGBA = targetImage.RGBA() ?: return
val targetOffset = bytesPerPixel * (targetPosition.x + targetPosition.y * targetImage.width)
(0 until width).forEach { byteOffset ->
val byteIndex = targetOffset + byteOffset * 4
RGBA.set(targetPosition + Vector2i(byteOffset, 0), sourceColor)
if (alphaBlending) {
TODO()// blend(targetImage.data.getInt(byteIndex), sourceColor.value)
}
}
}
}
fun blend(lastValue: Color4b, nextValue: Color4b): Color4b {
val last = lastValue.toColor4f()
val next = nextValue.toColor4f()
val W1 = 1f - next.alpha
val W2 = next.alpha
val output = Color4f(
last.red * W1 + next.red * W2,
last.green * W1 + next.green * W2,
last.blue * W1 + next.blue * W2,
max(last.alpha, next.alpha),
)
return output.toColorCode().toColor4b()
}
}