rt4-client/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt
2024-10-28 12:43:29 -07:00

199 lines
No EOL
7.6 KiB
Kotlin

package KondoKit
import rt4.GlIndexedSprite
import rt4.GlSprite
import rt4.SoftwareIndexedSprite
import rt4.SoftwareSprite
import java.awt.Color
import java.awt.image.BufferedImage
// Define interfaces for common sprite types
interface BaseSprite {
val width: Int
val height: Int
}
interface IndexedSprite : BaseSprite {
val pixels: ByteArray
val palette: IntArray
}
interface NonIndexedSprite : BaseSprite {
val pixels: IntArray?
}
// Adapter functions for existing sprite types
fun adaptSoftwareSprite(sprite: SoftwareSprite): NonIndexedSprite {
return object : NonIndexedSprite {
override val width: Int = sprite.width
override val height: Int = sprite.height
override val pixels: IntArray? = sprite.pixels
}
}
fun adaptSoftwareIndexedSprite(sprite: SoftwareIndexedSprite): IndexedSprite {
return object : IndexedSprite {
override val width: Int = sprite.width
override val height: Int = sprite.height
override val pixels: ByteArray = sprite.pixels
override val palette: IntArray = sprite.pallet
}
}
fun adaptGlSprite(sprite: GlSprite): NonIndexedSprite {
return object : NonIndexedSprite {
override val width: Int = sprite.width
override val height: Int = sprite.height
override val pixels: IntArray? = sprite.pixels
}
}
fun adaptGlIndexedSprite(sprite: GlIndexedSprite): IndexedSprite {
return object : IndexedSprite {
override val width: Int = sprite.width
override val height: Int = sprite.height
override val pixels: ByteArray = sprite.pixels
override val palette: IntArray = sprite.pallet
}
}
object SpriteToBufferedImage {
/**
* Converts a BaseSprite into a BufferedImage.
*
* Handles both indexed and non-indexed sprites, with optional tinting and grayscale.
*
* @param sprite The sprite to be converted.
* @param tint An optional Color to tint the image.
* @param grayscale If true, converts the image to grayscale.
* @param brightnessBoost A multiplier to boost the brightness of the image.
* @return The BufferedImage created from the sprite.
*/
private fun convertToBufferedImage(
sprite: BaseSprite,
tint: Color? = null,
grayscale: Boolean = false,
brightnessBoost: Float = 1.0f
): BufferedImage {
val width = sprite.width
val height = sprite.height
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
when (sprite) {
is IndexedSprite -> {
val pixels = sprite.pixels
val palette = sprite.palette
// Manually set pixels using the palette
for (y in 0 until height) {
for (x in 0 until width) {
val index = pixels[y * width + x].toInt() and 0xFF
val color = palette[index]
// Apply grayscale or tint if provided
val finalColor = if (grayscale) {
applyGrayscale(Color(color, true), brightnessBoost)
} else if (tint != null) {
applyTint(Color(color, true), tint, brightnessBoost)
} else {
applyBrightness(Color(color, true), brightnessBoost)
}
image.setRGB(x, y, finalColor.rgb)
}
}
}
is NonIndexedSprite -> {
val pixels = sprite.pixels ?: return image // Handle null case for GlSprite
// Manually set pixels directly
for (y in 0 until height) {
for (x in 0 until width) {
val color = pixels[y * width + x]
// Apply grayscale or tint if provided
val finalColor = if (grayscale) {
applyGrayscale(Color(color, true), brightnessBoost)
} else if (tint != null) {
applyTint(Color(color, true), tint, brightnessBoost)
} else {
applyBrightness(Color(color, true), brightnessBoost)
}
image.setRGB(x, y, finalColor.rgb)
}
}
}
}
return image
}
/**
* Applies a tint to a given color using the tint's alpha value to control the intensity.
*
* @param original The original color.
* @param tint The tint color to be applied.
* @param brightnessBoost A multiplier to boost the brightness of the image.
* @return The tinted color.
*/
private fun applyTint(original: Color, tint: Color, brightnessBoost: Float): Color {
val boostedColor = applyBrightness(original, brightnessBoost)
val r = (boostedColor.red * tint.red / 255).coerceIn(0, 255)
val g = (boostedColor.green * tint.green / 255).coerceIn(0, 255)
val b = (boostedColor.blue * tint.blue / 255).coerceIn(0, 255)
return Color(r, g, b, boostedColor.alpha)
}
/**
* Boosts the brightness of a given color.
*
* @param original The original color.
* @param factor The multiplier to boost the brightness.
* @return The color with boosted brightness.
*/
private fun applyBrightness(original: Color, factor: Float): Color {
val r = (original.red * factor).coerceIn(0.0f, 255.0f).toInt()
val g = (original.green * factor).coerceIn(0.0f, 255.0f).toInt()
val b = (original.blue * factor).coerceIn(0.0f, 255.0f).toInt()
return Color(r, g, b, original.alpha)
}
/**
* Converts a color to grayscale and applies a brightness boost.
*
* @param original The original color.
* @param brightnessBoost A multiplier to boost the brightness.
* @return The grayscale version of the color with boosted brightness.
*/
private fun applyGrayscale(original: Color, brightnessBoost: Float): Color {
// Calculate the grayscale value using the luminosity method
val grayValue = (0.3 * original.red + 0.59 * original.green + 0.11 * original.blue).toInt()
val boostedGray = (grayValue * brightnessBoost).coerceIn(0.0f, 255.0f).toInt()
return Color(boostedGray, boostedGray, boostedGray, original.alpha)
}
/**
* Converts an unknown sprite object into a BufferedImage if it matches a known sprite type.
*
* @param sprite The sprite object to be converted.
* @param tint An optional Color to tint the image.
* @param grayscale If true, converts the image to grayscale.
* @param brightnessBoost A multiplier to boost the brightness of the image.
* @return The BufferedImage created from the sprite or a default image if unsupported.
*/
fun getBufferedImageFromSprite(
sprite: Any?,
tint: Color? = null,
grayscale: Boolean = false,
brightnessBoost: Float = 1.0f
): BufferedImage {
return when (sprite) {
is SoftwareSprite -> convertToBufferedImage(adaptSoftwareSprite(sprite), tint, grayscale, brightnessBoost)
is SoftwareIndexedSprite -> convertToBufferedImage(adaptSoftwareIndexedSprite(sprite), tint, grayscale, brightnessBoost)
is GlSprite -> convertToBufferedImage(adaptGlSprite(sprite), tint, grayscale, brightnessBoost)
is GlIndexedSprite -> convertToBufferedImage(adaptGlIndexedSprite(sprite), tint, grayscale, brightnessBoost)
else -> BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB) // Default empty image for unsupported types
}
}
}