176 lines
6.2 KiB
Kotlin
176 lines
6.2 KiB
Kotlin
package ru.dbotthepony.kstarbound.defs
|
|
|
|
import com.google.common.collect.ImmutableList
|
|
import com.google.gson.Gson
|
|
import com.google.gson.JsonObject
|
|
import com.google.gson.TypeAdapter
|
|
import com.google.gson.reflect.TypeToken
|
|
import com.google.gson.stream.JsonReader
|
|
import com.google.gson.stream.JsonWriter
|
|
import org.apache.logging.log4j.LogManager
|
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
|
import ru.dbotthepony.kstarbound.Starbound
|
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
|
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
|
import ru.dbotthepony.kstarbound.defs.image.ImageReference
|
|
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
|
import ru.dbotthepony.kstarbound.math.LineF
|
|
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
|
import ru.dbotthepony.kstarbound.util.contains
|
|
import ru.dbotthepony.kvector.arrays.Matrix3f
|
|
import ru.dbotthepony.kvector.arrays.Matrix4fStack
|
|
import ru.dbotthepony.kvector.vector.RGBAColor
|
|
import ru.dbotthepony.kvector.vector.Vector2f
|
|
import ru.dbotthepony.kvector.vector.Vector3f
|
|
|
|
sealed class Drawable(val position: Vector2f, val color: RGBAColor, val fullbright: Boolean) {
|
|
class Line(
|
|
val line: LineF,
|
|
val width: Float,
|
|
position: Vector2f = Vector2f.ZERO,
|
|
color: RGBAColor = RGBAColor.WHITE,
|
|
fullbright: Boolean = false
|
|
) : Drawable(position, color, fullbright) {
|
|
override fun render(gl: GLStateTracker, stack: Matrix4fStack, x: Float, y: Float) {
|
|
TODO("Not yet implemented")
|
|
}
|
|
}
|
|
|
|
class Poly(
|
|
val vertices: ImmutableList<Vector2f>,
|
|
position: Vector2f = Vector2f.ZERO,
|
|
color: RGBAColor = RGBAColor.WHITE,
|
|
fullbright: Boolean = false
|
|
) : Drawable(position, color, fullbright) {
|
|
override fun render(gl: GLStateTracker, stack: Matrix4fStack, x: Float, y: Float) {
|
|
TODO("Not yet implemented")
|
|
}
|
|
}
|
|
|
|
class Image(
|
|
val path: ImageReference,
|
|
val transform: Matrix3f,
|
|
val centered: Boolean,
|
|
position: Vector2f = Vector2f.ZERO,
|
|
color: RGBAColor = RGBAColor.WHITE,
|
|
fullbright: Boolean = false
|
|
) : Drawable(position, color, fullbright) {
|
|
override fun with(values: (String) -> String?): Image {
|
|
val newPath = path.with(values)
|
|
|
|
if (newPath == path) {
|
|
return this
|
|
}
|
|
|
|
return Image(newPath, transform, centered, position, color, fullbright)
|
|
}
|
|
|
|
override fun render(gl: GLStateTracker, stack: Matrix4fStack, x: Float, y: Float) {
|
|
val sprite = path.sprite ?: return
|
|
val texture = gl.loadTexture(path.imagePath.value!!)
|
|
|
|
if (centered) {
|
|
gl.quadTexture(texture) {
|
|
it.quad(x - (sprite.width(texture.width) / PIXELS_IN_STARBOUND_UNITf) * 0.5f, y - (sprite.height(texture.height) / PIXELS_IN_STARBOUND_UNITf) * 0.5f, x + sprite.width(texture.width) / PIXELS_IN_STARBOUND_UNITf * 0.5f, y + sprite.height(texture.height) / PIXELS_IN_STARBOUND_UNITf * 0.5f, QuadTransformers.uv(sprite.compute(texture)))
|
|
}
|
|
} else {
|
|
gl.quadTexture(texture) {
|
|
it.quad(x, y, x + sprite.width(texture.width) / PIXELS_IN_STARBOUND_UNITf, y + sprite.height(texture.height) / PIXELS_IN_STARBOUND_UNITf, QuadTransformers.uv(sprite.compute(texture)))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class Empty(position: Vector2f = Vector2f.ZERO, color: RGBAColor = RGBAColor.WHITE, fullbright: Boolean = false) : Drawable(position, color, fullbright) {
|
|
override fun render(gl: GLStateTracker, stack: Matrix4fStack, x: Float, y: Float) {}
|
|
}
|
|
|
|
open fun with(values: (String) -> String?): Drawable {
|
|
return this
|
|
}
|
|
|
|
abstract fun render(gl: GLStateTracker = GLStateTracker.current(), stack: Matrix4fStack = gl.matrixStack, x: Float = 0f, y: Float = 0f)
|
|
|
|
companion object {
|
|
val EMPTY = Empty()
|
|
private val LOGGER = LogManager.getLogger()
|
|
}
|
|
|
|
class Adapter(gson: Gson) : TypeAdapter<Drawable>() {
|
|
private val lines = gson.getAdapter(LineF::class.java)
|
|
private val objects = gson.getAdapter(JsonObject::class.java)
|
|
private val vectors = gson.getAdapter(Vector2f::class.java)
|
|
private val vectors3 = gson.getAdapter(Vector3f::class.java)
|
|
private val colors = gson.getAdapter(RGBAColor::class.java)
|
|
private val images = gson.getAdapter(ImageReference::class.java)
|
|
private val vertices = gson.getAdapter(TypeToken.getParameterized(ImmutableList::class.java, Vector2f::class.java)) as TypeAdapter<ImmutableList<Vector2f>>
|
|
|
|
override fun write(out: JsonWriter?, value: Drawable?) {
|
|
TODO("Not yet implemented")
|
|
}
|
|
|
|
override fun read(`in`: JsonReader): Drawable {
|
|
if (`in`.consumeNull()) {
|
|
return EMPTY
|
|
} else {
|
|
val value = objects.read(`in`)!!
|
|
|
|
val position = value["position"]?.let { vectors.fromJsonTree(it) } ?: Vector2f.ZERO
|
|
val color = value["color"]?.let { colors.fromJsonTree(it) } ?: RGBAColor.WHITE
|
|
val fullbright = value["fullbright"]?.asBoolean ?: false
|
|
|
|
if ("line" in value) {
|
|
return Line(lines.fromJsonTree(value["line"]), value["width"].asFloat, position, color, fullbright)
|
|
} else if ("poly" in value) {
|
|
return Poly(vertices.fromJsonTree(value["poly"]), position, color, fullbright)
|
|
} else if ("image" in value) {
|
|
val image = images.fromJsonTree(value["image"])
|
|
val mat = Matrix3f.identity()
|
|
|
|
if ("transformation" in value) {
|
|
val array = value["transformation"].asJsonArray
|
|
|
|
// original starbound use GLM, which reflects OpenGL, which in turn make matrices row-major
|
|
val row0 = vectors3.fromJsonTree(array[0])
|
|
val row1 = vectors3.fromJsonTree(array[1])
|
|
val row2 = vectors3.fromJsonTree(array[2])
|
|
|
|
mat.r00 = row0.x
|
|
mat.r01 = row0.y
|
|
mat.r02 = row0.z
|
|
|
|
mat.r10 = row1.x
|
|
mat.r11 = row1.y
|
|
mat.r12 = row1.z
|
|
|
|
mat.r20 = row2.x
|
|
mat.r21 = row2.y
|
|
mat.r22 = row2.z
|
|
} else {
|
|
if ("rotation" in value) {
|
|
LOGGER.warn("Rotation is not supported yet (required by ${image.raw})")
|
|
}
|
|
|
|
if ("mirrored" in value && value["mirrored"].asBoolean) {
|
|
mat.scale(-1f, -1f)
|
|
}
|
|
|
|
if ("scale" in value) {
|
|
if (value["scale"].isJsonArray) {
|
|
mat.scale(vectors.fromJsonTree(value["scale"]))
|
|
} else {
|
|
val scale = value["scale"].asFloat
|
|
mat.scale(scale, scale)
|
|
}
|
|
}
|
|
}
|
|
|
|
return Image(image, mat, value["centered"]?.asBoolean ?: false, position, color, fullbright)
|
|
} else {
|
|
return Empty(position, color, fullbright)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|