mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -04:00
wip element rotation
This commit is contained in:
parent
17f7c96a2b
commit
e858e6a1d9
@ -25,6 +25,7 @@ import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import org.testng.Assert
|
||||
import kotlin.math.abs
|
||||
|
||||
object BakedModelTestUtil {
|
||||
private val texture = Minosoft::class.java.getResourceAsStream("/assets/minosoft/textures/debug.png")!!.readAllBytes()
|
||||
@ -56,9 +57,18 @@ object BakedModelTestUtil {
|
||||
if (faces.size != 1) throw IllegalArgumentException("Model has more/less than once face: ${faces.size}!")
|
||||
val face = faces.first()
|
||||
|
||||
vertices?.let { Assert.assertEquals(face.positions, it, "Vertices mismatch") }
|
||||
vertices?.let { assertMatches(face.positions, it, "Vertices mismatch") }
|
||||
uv?.let { if (!face.uv.contentEquals(it)) throw AssertionError("UV mismatch, expected [${uv[0]}|${uv[1]}], but got [${face.uv[0]}|${face.uv[1]}]") } // printing the first element is fine, it is always clockwise
|
||||
shade?.let { Assert.assertEquals(face.shade, it, "Shade mismatch") }
|
||||
texture?.toResourceLocation()?.texture()?.let { Assert.assertEquals(face.texture, it, "Texture mismatch") }
|
||||
}
|
||||
|
||||
private fun assertMatches(actual: FloatArray, expected: FloatArray, message: String) {
|
||||
if (actual.size != expected.size) throw AssertionError("Size mismatch!")
|
||||
|
||||
for (i in actual.indices) {
|
||||
val delta = abs(actual[i] - expected[i])
|
||||
if (delta > 0.01f) throw AssertionError("$message: Delta is too high at index $i: ${actual[i]}, expected ${expected[i]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.models.baked.rotation
|
||||
|
||||
import de.bixilon.kotlinglm.vec3.Vec3
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
|
||||
import de.bixilon.minosoft.gui.rendering.models.ModelTestUtil.bake
|
||||
import de.bixilon.minosoft.gui.rendering.models.ModelTestUtil.rbgy
|
||||
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModelTestUtil.assertFace
|
||||
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModelTestUtil.createFaces
|
||||
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModelTestUtil.createTextureManager
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.BlockModel
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.element.ElementRotation
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.element.ModelElement
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.state.apply.SingleBlockStateApply
|
||||
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
|
||||
import org.testng.annotations.Test
|
||||
|
||||
@Test(groups = ["models"])
|
||||
class ElementRotationTest {
|
||||
|
||||
private fun block(rotation: ElementRotation): SingleBlockStateApply {
|
||||
val from = Vec3(0.0f)
|
||||
val to = Vec3(1.0f)
|
||||
return SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces(), rotation = rotation)), textures = mapOf("test" to minecraft("block/test").texture())))
|
||||
}
|
||||
|
||||
fun `rotate block around origin 45 degree on the y axis`() {
|
||||
val model = block(ElementRotation(axis = Axes.Y, angle = 45.0f))
|
||||
|
||||
val baked = model.bake(createTextureManager("block/test"))!!
|
||||
|
||||
|
||||
baked.assertFace(Directions.UP, floatArrayOf(-0.2f, 1.0f, 0.5f, 0.5f, 1.0f, -0.2f, 1.2f, 1.0f, 0.5f, 0.5f, 1.0f, 1.2f), rbgy, 1.0f)
|
||||
}
|
||||
|
||||
fun `rotate block around origin -45 degree on the y axis`() {
|
||||
val model = block(ElementRotation(axis = Axes.Y, angle = -45.0f))
|
||||
|
||||
val baked = model.bake(createTextureManager("block/test"))!!
|
||||
|
||||
|
||||
baked.assertFace(Directions.UP, floatArrayOf(0.5f, 1.0f, -0.2f, 1.2f, 1.0f, 0.5f, 0.5f, 1.0f, 1.2f, -0.2f, 1.0f, 0.5f), rbgy, 1.0f)
|
||||
}
|
||||
|
||||
// TODO: a,z axis
|
||||
}
|
@ -14,20 +14,16 @@
|
||||
package de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.kutil.exception.Broken
|
||||
import de.bixilon.minosoft.data.direction.Directions
|
||||
import de.bixilon.minosoft.data.registries.blocks.settings.BlockSettings
|
||||
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
|
||||
import de.bixilon.minosoft.data.registries.blocks.types.Block
|
||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedFace
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedModel
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.FaceProperties
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.SideProperties
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.memory.MemoryTexture
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
|
||||
import org.testng.Assert.assertFalse
|
||||
import org.testng.Assert.assertTrue
|
||||
import org.testng.annotations.Test
|
||||
@ -35,8 +31,8 @@ import org.testng.annotations.Test
|
||||
@Test(groups = ["models", "culling"])
|
||||
class FaceCullingTest {
|
||||
|
||||
private fun createFace(transparency: TextureTransparencies = TextureTransparencies.OPAQUE, properties: FaceProperties? = FaceProperties(Vec2(0), Vec2(1), transparency)): BakedFace {
|
||||
return BakedFace(floatArrayOf(), floatArrayOf(), 1.0f, -1, null, MemoryTexture(Vec2i.EMPTY), properties)
|
||||
private fun createFace(transparency: TextureTransparencies = TextureTransparencies.OPAQUE, properties: FaceProperties? = FaceProperties(Vec2(0), Vec2(1), transparency)): FaceProperties? {
|
||||
return properties
|
||||
}
|
||||
|
||||
private fun createBlock(transparency: TextureTransparencies = TextureTransparencies.OPAQUE, properties: SideProperties? = SideProperties(arrayOf(FaceProperties(Vec2(0), Vec2(1), transparency)), transparency), type: Int = 0): BlockState {
|
||||
@ -228,7 +224,7 @@ class FaceCullingTest {
|
||||
val block = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling {
|
||||
override val hardness get() = Broken()
|
||||
|
||||
override fun shouldCull(state: BlockState, face: BakedFace, directions: Directions, neighbour: BlockState): Boolean {
|
||||
override fun shouldCull(state: BlockState, properties: FaceProperties, directions: Directions, neighbour: BlockState): Boolean {
|
||||
throw AssertionError("shouldCall invoked!")
|
||||
}
|
||||
}
|
||||
@ -244,7 +240,7 @@ class FaceCullingTest {
|
||||
private fun forceNoCull() = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling {
|
||||
override val hardness get() = Broken()
|
||||
|
||||
override fun shouldCull(state: BlockState, face: BakedFace, directions: Directions, neighbour: BlockState): Boolean {
|
||||
override fun shouldCull(state: BlockState, properties: FaceProperties, directions: Directions, neighbour: BlockState): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -13,23 +13,30 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.models.block.element
|
||||
|
||||
import de.bixilon.kotlinglm.func.rad
|
||||
import de.bixilon.kotlinglm.vec3.Vec3
|
||||
import de.bixilon.kutil.json.JsonObject
|
||||
import de.bixilon.kutil.primitive.BooleanUtil.toBoolean
|
||||
import de.bixilon.kutil.primitive.FloatUtil.toFloat
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.data.entities.EntityRotation.Companion.CIRCLE_DEGREE
|
||||
import de.bixilon.minosoft.gui.rendering.models.block.element.ModelElement.Companion.BLOCK_SIZE
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotateAssign
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3
|
||||
|
||||
data class ElementRotation(
|
||||
val origin: Vec3,
|
||||
val origin: Vec3 = ORIGIN,
|
||||
val axis: Axes,
|
||||
val angle: Float,
|
||||
val rescale: Boolean = false,
|
||||
) {
|
||||
|
||||
fun apply(positions: FloatArray) {
|
||||
// TODO("Can not rotate yet!")
|
||||
val angle = -angle.rad
|
||||
Vec3(0, positions).rotateAssign(angle, axis, origin, rescale)
|
||||
Vec3(3, positions).rotateAssign(angle, axis, origin, rescale)
|
||||
Vec3(6, positions).rotateAssign(angle, axis, origin, rescale)
|
||||
Vec3(9, positions).rotateAssign(angle, axis, origin, rescale)
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +44,7 @@ data class ElementRotation(
|
||||
private val ORIGIN = Vec3(0.5f)
|
||||
|
||||
fun deserialize(data: JsonObject): ElementRotation? {
|
||||
val angle = data["angle"]?.toFloat() ?: return null
|
||||
val angle = data["angle"]?.toFloat()?.mod(CIRCLE_DEGREE.toFloat()) ?: return null
|
||||
if (angle == 0.0f) return null
|
||||
|
||||
val rescale = data["rescale"]?.toBoolean() ?: false
|
||||
|
@ -47,7 +47,7 @@ class BakedModel(
|
||||
val direction = Directions.VALUES[directionIndex].inverted
|
||||
|
||||
for (face in faces) {
|
||||
if (FaceCulling.canCull(state, face, direction, neighbour)) {
|
||||
if (FaceCulling.canCull(state, face.properties, direction, neighbour)) {
|
||||
continue
|
||||
}
|
||||
face.render(offset, mesh, light, tints)
|
||||
|
@ -22,10 +22,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparenci
|
||||
|
||||
object FaceCulling {
|
||||
|
||||
inline fun canCull(state: BlockState, face: BakedFace, direction: Directions, neighbour: BlockState?): Boolean {
|
||||
return canCull(state, face.properties, direction, neighbour)
|
||||
}
|
||||
|
||||
fun canCull(state: BlockState, properties: FaceProperties?, direction: Directions, neighbour: BlockState?): Boolean {
|
||||
if (neighbour == null) return false
|
||||
if (properties == null) return false
|
||||
|
@ -61,7 +61,7 @@ object Vec3Util {
|
||||
fun rotate(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 {
|
||||
val result = Vec2(x * cos - y * sin, x * sin + y * cos)
|
||||
if (rescale) {
|
||||
return result / cos
|
||||
result /= cos
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -78,19 +78,6 @@ object Vec3Util {
|
||||
}
|
||||
}
|
||||
|
||||
fun Vec3.rotateAssign(rotation: Vec2, centerBlock: Boolean = false) {
|
||||
if (centerBlock) {
|
||||
this -= 0.5f
|
||||
}
|
||||
|
||||
rotateAssign(-rotation.x, Axes.X)
|
||||
rotateAssign(rotation.y, Axes.Y)
|
||||
|
||||
if (centerBlock) {
|
||||
this += 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
fun Vec3.rotateAssign(angle: Float, axis: Axes, origin: Vec3, rescale: Boolean) {
|
||||
this -= origin
|
||||
rotateAssign(angle, axis, rescale)
|
||||
|
Loading…
x
Reference in New Issue
Block a user