166 lines
8.4 KiB
Kotlin
166 lines
8.4 KiB
Kotlin
package mods.betterfoliage.render.column
|
|
|
|
import mods.betterfoliage.config.Config
|
|
import mods.betterfoliage.model.Quad
|
|
import mods.betterfoliage.model.UV
|
|
import mods.betterfoliage.model.Vertex
|
|
import mods.betterfoliage.model.bake
|
|
import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType
|
|
import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.INVISIBLE
|
|
import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.LARGE_RADIUS
|
|
import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.SMALL_RADIUS
|
|
import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.SQUARE
|
|
import mods.betterfoliage.util.Double3
|
|
import mods.betterfoliage.util.Rotation
|
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
|
import net.minecraft.util.Direction.Axis
|
|
import net.minecraft.util.Direction.EAST
|
|
import net.minecraft.util.Direction.SOUTH
|
|
import net.minecraft.util.Direction.UP
|
|
|
|
/**
|
|
* Collection of dynamically generated meshes used to render rounded columns.
|
|
*/
|
|
class ColumnMeshSet(
|
|
radiusSmall: Double,
|
|
radiusLarge: Double,
|
|
zProtection: Double,
|
|
val axis: Axis,
|
|
val spriteLeft: TextureAtlasSprite,
|
|
val spriteRight: TextureAtlasSprite,
|
|
val spriteTop: TextureAtlasSprite,
|
|
val spriteBottom: TextureAtlasSprite
|
|
) {
|
|
protected fun sideRounded(radius: Double, yBottom: Double, yTop: Double): List<Quad> {
|
|
val halfRadius = radius * 0.5
|
|
return listOf(
|
|
// left side of the diagonal
|
|
Quad.verticalRectangle(0.0, 0.5, 0.5 - radius, 0.5, yBottom, yTop).clampUV(minU = 0.0, maxU = 0.5 - radius),
|
|
Quad.verticalRectangle(0.5 - radius, 0.5, 0.5 - halfRadius, 0.5 - halfRadius, yBottom, yTop).clampUV(minU = 0.5 - radius),
|
|
// right side of the diagonal
|
|
Quad.verticalRectangle(0.5 - halfRadius, 0.5 - halfRadius, 0.5, 0.5 - radius, yBottom, yTop).clampUV(maxU = radius - 0.5),
|
|
Quad.verticalRectangle(0.5, 0.5 - radius, 0.5, 0.0, yBottom, yTop).clampUV(minU = radius - 0.5, maxU = 0.0)
|
|
)
|
|
}
|
|
|
|
protected fun sideRoundedTransition(radiusBottom: Double, radiusTop: Double, yBottom: Double, yTop: Double): List<Quad> {
|
|
val ySplit = 0.5 * (yBottom + yTop)
|
|
val modelTop = sideRounded(radiusTop, yBottom, yTop)
|
|
val modelBottom = sideRounded(radiusBottom, yBottom, yTop)
|
|
return (modelBottom zip modelTop).map { (quadBottom, quadTop) ->
|
|
Quad.mix(quadBottom, quadTop) { vBottom, vTop -> if (vBottom.xyz.y < ySplit) vBottom.copy() else vTop.copy() }
|
|
}
|
|
}
|
|
|
|
protected fun sideSquare(yBottom: Double, yTop: Double) = listOf(
|
|
Quad.verticalRectangle(0.0, 0.5, 0.5, 0.5, yBottom, yTop).clampUV(minU = 0.0),
|
|
Quad.verticalRectangle(0.5, 0.5, 0.5, 0.0, yBottom, yTop).clampUV(maxU = 0.0)
|
|
)
|
|
|
|
protected fun lidRounded(radius: Double, y: Double, isBottom: Boolean) = Array(4) { quadrant ->
|
|
val rotation = baseRotation(axis) + quadrantRotations[quadrant]
|
|
val v1 = Vertex(Double3(0.0, y, 0.0), UV(0.0, 0.0))
|
|
val v2 = Vertex(Double3(0.0, y, 0.5), UV(0.0, 0.5))
|
|
val v3 = Vertex(Double3(0.5 - radius, y, 0.5), UV(0.5 - radius, 0.5))
|
|
val v4 = Vertex(Double3(0.5 - radius * 0.5, y, 0.5 - radius * 0.5), UV(0.5, 0.5))
|
|
val v5 = Vertex(Double3(0.5, y, 0.5 - radius), UV(0.5, 0.5 - radius))
|
|
val v6 = Vertex(Double3(0.5, y, 0.0), UV(0.5, 0.0))
|
|
listOf(Quad(v1, v2, v3, v4), Quad(v1, v4, v5, v6))
|
|
.map { it.cycleVertices(if (isBottom xor Config.nVidia) 0 else 1) }
|
|
.map { it.rotate(rotation).rotateUV(quadrant) }
|
|
.map { it.sprite(if (isBottom) spriteBottom else spriteTop) }
|
|
.map { if (isBottom) it.flipped else it }
|
|
}
|
|
|
|
protected fun lidSquare(y: Double, isBottom: Boolean) = Array(4) { quadrant ->
|
|
val rotation = baseRotation(axis) + quadrantRotations[quadrant]
|
|
listOf(
|
|
Quad.horizontalRectangle(x1 = 0.0, x2 = 0.5, z1 = 0.0, z2 = 0.5, y = y).clampUV(minU = 0.0, minV = 0.0)
|
|
.rotate(rotation).rotateUV(quadrant)
|
|
.sprite(if (isBottom) spriteBottom else spriteTop)
|
|
.let { if (isBottom) it.flipped else it }
|
|
)
|
|
}
|
|
|
|
protected val zProtectionScale = zProtection.let { Double3(it, 1.0, it) }
|
|
|
|
protected fun List<Quad>.extendTop(size: Double) = map { q -> q.clampUV(minV = 0.5 - size).transformV { v ->
|
|
if (v.xyz.y > 0.501) v.copy(xyz = v.xyz * zProtectionScale) else v }
|
|
}
|
|
protected fun List<Quad>.extendBottom(size: Double) = map { q -> q.clampUV(maxV = -0.5 + size).transformV { v ->
|
|
if (v.xyz.y < -0.501) v.copy(xyz = v.xyz * zProtectionScale) else v }
|
|
}
|
|
protected fun List<Quad>.buildSides(quadsPerSprite: Int) = Array(4) { quadrant ->
|
|
val rotation = baseRotation(axis) + quadrantRotations[quadrant]
|
|
this.map { it.rotate(rotation) }
|
|
.mapIndexed { idx, q -> if (idx % (2 * quadsPerSprite) >= quadsPerSprite) q.sprite(spriteRight) else q.sprite(spriteLeft) }
|
|
.bake(false)
|
|
}
|
|
|
|
companion object {
|
|
fun baseRotation(axis: Axis) = when(axis) {
|
|
Axis.X -> Rotation.fromUp[EAST.ordinal]
|
|
Axis.Y -> Rotation.fromUp[UP.ordinal]
|
|
Axis.Z -> Rotation.fromUp[SOUTH.ordinal]
|
|
}
|
|
val quadrantRotations = Array(4) { Rotation.rot90[UP.ordinal] * it }
|
|
}
|
|
|
|
//
|
|
// Mesh definitions
|
|
// 4-element arrays hold prebuild meshes for each of the rotations around the axis
|
|
//
|
|
val sideSquare = sideSquare(-0.5, 0.5).buildSides(quadsPerSprite = 1)
|
|
val sideRoundSmall = sideRounded(radiusSmall, -0.5, 0.5).buildSides(quadsPerSprite = 2)
|
|
val sideRoundLarge = sideRounded(radiusLarge, -0.5, 0.5).buildSides(quadsPerSprite = 2)
|
|
|
|
val sideExtendTopSquare = sideSquare(0.5, 0.5 + radiusLarge).extendTop(radiusLarge).buildSides(quadsPerSprite = 1)
|
|
val sideExtendTopRoundSmall = sideRounded(radiusSmall, 0.5, 0.5 + radiusLarge).extendTop(radiusLarge).buildSides(quadsPerSprite = 2)
|
|
val sideExtendTopRoundLarge = sideRounded(radiusLarge, 0.5, 0.5 + radiusLarge).extendTop(radiusLarge).buildSides(quadsPerSprite = 2)
|
|
|
|
val sideExtendBottomSquare = sideSquare(-0.5 - radiusLarge, -0.5).extendBottom(radiusLarge).buildSides(quadsPerSprite = 1)
|
|
val sideExtendBottomRoundSmall = sideRounded(radiusSmall, -0.5 - radiusLarge, -0.5).extendBottom(radiusLarge).buildSides(quadsPerSprite = 2)
|
|
val sideExtendBottomRoundLarge = sideRounded(radiusLarge, -0.5 - radiusLarge, -0.5).extendBottom(radiusLarge).buildSides(quadsPerSprite = 2)
|
|
|
|
val lidTopSquare = lidSquare(0.5, false).bake(false)
|
|
val lidTopRoundSmall = lidRounded(radiusSmall, 0.5, false).bake(false)
|
|
val lidTopRoundLarge = lidRounded(radiusLarge, 0.5, false).bake(false)
|
|
|
|
val lidBottomSquare = lidSquare(-0.5, true).bake(false)
|
|
val lidBottomRoundSmall = lidRounded(radiusSmall, -0.5, true).bake(false)
|
|
val lidBottomRoundLarge = lidRounded(radiusLarge, -0.5, true).bake(false)
|
|
|
|
val transitionTop = sideRoundedTransition(radiusLarge, radiusSmall, -0.5, 0.5).buildSides(quadsPerSprite = 2)
|
|
val transitionBottom = sideRoundedTransition(radiusSmall, radiusLarge, -0.5, 0.5).buildSides(quadsPerSprite = 2)
|
|
|
|
//
|
|
// Helper fuctions for lids (block ends)
|
|
//
|
|
fun flatTop(quadrantTypes: Array<QuadrantType>, quadrant: Int) = when(quadrantTypes[quadrant]) {
|
|
SMALL_RADIUS -> lidTopRoundSmall[quadrant]
|
|
LARGE_RADIUS -> lidTopRoundLarge[quadrant]
|
|
SQUARE -> lidTopSquare[quadrant]
|
|
INVISIBLE -> lidTopSquare[quadrant]
|
|
}
|
|
|
|
fun flatBottom(quadrantTypes: Array<QuadrantType>, quadrant: Int) = when(quadrantTypes[quadrant]) {
|
|
SMALL_RADIUS -> lidBottomRoundSmall[quadrant]
|
|
LARGE_RADIUS -> lidBottomRoundLarge[quadrant]
|
|
SQUARE -> lidBottomSquare[quadrant]
|
|
INVISIBLE -> lidBottomSquare[quadrant]
|
|
}
|
|
|
|
fun extendTop(quadrantTypes: Array<QuadrantType>, quadrant: Int) = when(quadrantTypes[quadrant]) {
|
|
SMALL_RADIUS -> sideExtendTopRoundSmall[quadrant]
|
|
LARGE_RADIUS -> sideExtendTopRoundLarge[quadrant]
|
|
SQUARE -> sideExtendTopSquare[quadrant]
|
|
INVISIBLE -> sideExtendTopSquare[quadrant]
|
|
}
|
|
|
|
fun extendBottom(quadrantTypes: Array<QuadrantType>, quadrant: Int) = when(quadrantTypes[quadrant]) {
|
|
SMALL_RADIUS -> sideExtendBottomRoundSmall[quadrant]
|
|
LARGE_RADIUS -> sideExtendBottomRoundLarge[quadrant]
|
|
SQUARE -> sideExtendBottomSquare[quadrant]
|
|
INVISIBLE -> sideExtendBottomSquare[quadrant]
|
|
}
|
|
} |