Files
BetterFoliage/src/main/kotlin/mods/betterfoliage/model/HalfBaked.kt
octarine-noise 8f82fefbb7 Port to 1.16.5
Kottle -> KotlinForForge
2021-05-14 14:44:29 +02:00

119 lines
5.0 KiB
Kotlin

package mods.betterfoliage.model
import mods.betterfoliage.render.pipeline.RenderCtxBase
import mods.betterfoliage.resource.discovery.ModelBakingContext
import mods.betterfoliage.resource.discovery.ModelBakingKey
import mods.betterfoliage.util.Double3
import mods.betterfoliage.util.HasLogger
import mods.betterfoliage.util.directionsAndNull
import mods.betterfoliage.util.mapArray
import net.minecraft.client.renderer.model.BakedQuad
import net.minecraft.client.renderer.model.IBakedModel
import net.minecraft.client.renderer.model.SimpleBakedModel
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.client.renderer.vertex.VertexFormatElement
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder
import java.util.Random
/**
* Hybrid baked quad implementation, carrying both baked and unbaked information.
* Used to do advanced vertex lighting without unbaking vertex data at lighting time.
*/
data class HalfBakedQuad(
val raw: Quad,
val baked: BakedQuad
)
open class HalfBakedSimpleModelWrapper(baseModel: SimpleBakedModel): IBakedModel by baseModel, SpecialRenderModel {
val baseQuads = baseModel.unbakeQuads()
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
ctx.renderQuads(baseQuads)
}
}
open class HalfBakedSpecialWrapper(val baseModel: SpecialRenderModel): IBakedModel by baseModel, SpecialRenderModel {
override fun render(ctx: RenderCtxBase, noDecorations: Boolean) {
baseModel.render(ctx, noDecorations)
}
}
abstract class HalfBakedWrapperKey : ModelBakingKey, HasLogger() {
override fun bake(ctx: ModelBakingContext): IBakedModel? {
val baseModel = super.bake(ctx)
val halfBaked = when(baseModel) {
is SimpleBakedModel -> HalfBakedSimpleModelWrapper(baseModel)
else -> null
}
return if (halfBaked == null) baseModel else bake(ctx, halfBaked)
}
abstract fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel): SpecialRenderModel
}
fun List<Quad>.bake(applyDiffuseLighting: Boolean) = map { quad ->
if (quad.sprite == null) throw IllegalStateException("Quad must have a texture assigned before baking")
val builder = BakedQuadBuilder(quad.sprite)
builder.setApplyDiffuseLighting(applyDiffuseLighting)
builder.setQuadOrientation(quad.face())
builder.setQuadTint(quad.colorIndex)
quad.verts.forEach { vertex ->
DefaultVertexFormats.BLOCK.elements.forEachIndexed { idx, element ->
when {
element.usage == VertexFormatElement.Usage.POSITION -> builder.put(idx,
(vertex.xyz.x + 0.5).toFloat(),
(vertex.xyz.y + 0.5).toFloat(),
(vertex.xyz.z + 0.5).toFloat(),
1.0f
)
// don't fill lightmap UV coords
element.usage == VertexFormatElement.Usage.UV && element.type == VertexFormatElement.Type.FLOAT -> builder.put(idx,
quad.sprite.u0 + (quad.sprite.u1 - quad.sprite.u0) * (vertex.uv.u + 0.5).toFloat(),
quad.sprite.v0 + (quad.sprite.v1 - quad.sprite.v0) * (vertex.uv.v + 0.5).toFloat(),
0.0f, 1.0f
)
element.usage == VertexFormatElement.Usage.COLOR -> builder.put(idx,
(vertex.color.red and 255).toFloat() / 255.0f,
(vertex.color.green and 255).toFloat() / 255.0f,
(vertex.color.blue and 255).toFloat() / 255.0f,
(vertex.color.alpha and 255).toFloat() / 255.0f
)
element.usage == VertexFormatElement.Usage.NORMAL -> builder.put(idx,
(vertex.normal ?: quad.normal).x.toFloat(),
(vertex.normal ?: quad.normal).y.toFloat(),
(vertex.normal ?: quad.normal).z.toFloat(),
0.0f
)
else -> builder.put(idx)
}
}
}
HalfBakedQuad(quad, builder.build())
}
fun Array<List<Quad>>.bake(applyDiffuseLighting: Boolean) = mapArray { it.bake(applyDiffuseLighting) }
fun BakedQuad.unbake(): HalfBakedQuad {
val size = DefaultVertexFormats.BLOCK.integerSize
val verts = Array(4) { vIdx ->
val x = java.lang.Float.intBitsToFloat(vertices[vIdx * size + 0])
val y = java.lang.Float.intBitsToFloat(vertices[vIdx * size + 1])
val z = java.lang.Float.intBitsToFloat(vertices[vIdx * size + 2])
val color = vertices[vIdx * size + 3]
val u = java.lang.Float.intBitsToFloat(vertices[vIdx * size + 4])
val v = java.lang.Float.intBitsToFloat(vertices[vIdx * size + 5])
Vertex(Double3(x, y, z), UV(u.toDouble(), v.toDouble()), Color(color))
}
val unbaked = Quad(
verts[0], verts[1], verts[2], verts[3],
colorIndex = if (isTinted) tintIndex else -1,
face = direction
)
return HalfBakedQuad(unbaked, this)
}
fun SimpleBakedModel.unbakeQuads() = directionsAndNull.flatMap { face ->
getQuads(null, face, Random()).map { it.unbake() }
}