diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt index f0c2988e9..07aa1d2cf 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt @@ -34,7 +34,7 @@ class Camera(private var fov: Float, private val windowId: Long) { } else if (this.pitch < -89.0) { this.pitch = -89.0 } - cameraFront = Vec3((cos(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat(), sin(glm.radians(pitch)).toFloat(), (sin(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat()).normalize() + setRotation(yaw, pitch) } fun handleInput(deltaTime: Double) { @@ -56,7 +56,7 @@ class Camera(private var fov: Float, private val windowId: Long) { if (GLFW.glfwGetKey(windowId, GLFW.GLFW_KEY_D) == GLFW.GLFW_PRESS) { cameraPosition = cameraPosition + (cameraFront.cross(CAMERA_UP_VEC3).normalize()) * cameraSpeed } - this.cameraPosition.y = currentY // stay on xz line when moving (aka. no clip) + this.cameraPosition.y = currentY // stay on xz line when moving (aka. no clip): ToDo: make movement not slower when you look up if (GLFW.glfwGetKey(windowId, GLFW.GLFW_KEY_LEFT_SHIFT) == GLFW.GLFW_PRESS) { cameraPosition = cameraPosition - CAMERA_UP_VEC3 * cameraSpeed } @@ -89,6 +89,10 @@ class Camera(private var fov: Float, private val windowId: Long) { cameraPosition = position } + fun setRotation(yaw: Double, pitch: Double) { + cameraFront = Vec3((cos(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat(), sin(glm.radians(pitch)).toFloat(), (sin(glm.radians(yaw)) * cos(glm.radians(pitch))).toFloat()).normalize() + } + companion object { private val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/ChunkPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/ChunkPreparer.kt index d3d7d1960..2c34c693f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/ChunkPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/ChunkPreparer.kt @@ -25,78 +25,41 @@ object ChunkPreparer { val east = world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight) for ((position, block) in section.blocks) { - for (direction in Directions.DIRECTIONS) { - var blockToCheck: Block? = null - when (direction) { - Directions.DOWN -> { - if (position.y == 0) { - below?.let { - blockToCheck = it.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z) - } - } - } - Directions.UP -> { - if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1) { - above?.let { - blockToCheck = it.getBlock(position.x, 0, position.z) - } - } - } - Directions.NORTH -> { - if (position.z == 0) { - north?.let { - blockToCheck = it.getBlock(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1) - } - } - } - Directions.SOUTH -> { - if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1) { - south?.let { - blockToCheck = it.getBlock(position.x, position.y, 0) - } - } - } - Directions.WEST -> { - if (position.x == 0) { - west?.let { - blockToCheck = it.getBlock(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.z) - } - } - } - Directions.EAST -> { - if (position.x == ProtocolDefinition.SECTION_WIDTH_X - 1) { - east?.let { - blockToCheck = it.getBlock(0, position.y, position.z) - } - } - } - } - - fun drawFace() { - block.blockModel.render(position, direction, data) - } - - if (blockToCheck == null) { - blockToCheck = section.getBlock(position.getLocationByDirection(direction)) - } - if (blockToCheck != null) { - val blockTransparent = block.blockModel.isTransparent(direction) - val checkTransparent = blockToCheck!!.blockModel.isTransparent(direction) - if (blockTransparent && checkTransparent) { - continue - } - if (checkTransparent) { - drawFace() - continue - } - if (block.blockModel.isCullFace(direction) && blockToCheck!!.blockModel.isCullFace(direction.inverse())) { - continue - } - // ToDo: Block rotations (this is buggy) - } - drawFace() - + val blockBelow: Block? = if (position.y == 0 && below != null) { + below.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z) + } else { + section.getBlock(position.getLocationByDirection(Directions.DOWN)) } + val blockAbove: Block? = if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1 && above != null) { + above.getBlock(position.x, 0, position.z) + } else { + section.getBlock(position.getLocationByDirection(Directions.UP)) + } + val blockNorth: Block? = if (position.z == 0 && north != null) { + north.getBlock(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1) + } else { + section.getBlock(position.getLocationByDirection(Directions.NORTH)) + } + val blockSouth: Block? = if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1 && south != null) { + south.getBlock(position.x, position.y, 0) + } else { + section.getBlock(position.getLocationByDirection(Directions.SOUTH)) + } + val blockWest: Block? = if (position.x == 0 && west != null) { + west.getBlock(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.x) + } else { + section.getBlock(position.getLocationByDirection(Directions.WEST)) + } + val blockEast: Block? = if (position.x == ProtocolDefinition.SECTION_WIDTH_X - 1 && east != null) { + east.getBlock(0, position.y, position.x) + } else { + section.getBlock(position.getLocationByDirection(Directions.EAST)) + } + + fun drawBlock() { + block.blockModel.render(position, data, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast)) + } + drawBlock() } return data.toFloatArray() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index 186bd1c21..78accb164 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -60,15 +60,6 @@ class RenderWindow(private val connection: Connection) { } camera = Camera(60f, windowId) - glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() { - override fun invoke(window: Long, width: Int, height: Int) { - glViewport(0, 0, width, height) - screenWidth = width - screenHeight = height - camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader) - } - }) - glfwSetKeyCallback(this.windowId) { windowId: Long, key: Int, scanCode: Int, action: Int, mods: Int -> run { if (action != GLFW_RELEASE) { @@ -126,6 +117,16 @@ class RenderWindow(private val connection: Connection) { camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader) camera.calculateViewMatrix(chunkShader) + + glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() { + override fun invoke(window: Long, width: Int, height: Int) { + glViewport(0, 0, width, height) + screenWidth = width + screenHeight = height + camera.calculateProjectionMatrix(screenWidth, screenHeight, chunkShader) + } + }) + latch?.countDown() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/Renderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/Renderer.kt index cf78fb53a..f630f4a41 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/Renderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/Renderer.kt @@ -1,5 +1,6 @@ package de.bixilon.minosoft.gui.rendering +import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.entities.Location import de.bixilon.minosoft.data.world.Chunk import de.bixilon.minosoft.data.world.ChunkLocation @@ -67,4 +68,10 @@ class Renderer(private val connection: Connection) { } } + fun rotate(rotation: EntityRotation) { + renderWindow.renderQueue.add { + renderWindow.camera.setRotation(rotation.yaw.toDouble(), rotation.pitch.toDouble()) + } + } + } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModel.kt index 72e3f6a15..a9f3cc6f4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModel.kt @@ -2,6 +2,7 @@ package de.bixilon.minosoft.gui.rendering.models import com.google.gson.JsonObject import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.mappings.blocks.Block import de.bixilon.minosoft.data.world.InChunkSectionLocation import de.bixilon.minosoft.gui.rendering.textures.Texture import glm_.glm @@ -12,6 +13,7 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) { private val textures: MutableMap = parent?.textures?.toMutableMap() ?: mutableMapOf() private val textureMapping: MutableMap = mutableMapOf() private var elements: MutableList = parent?.elements?.toMutableList() ?: mutableListOf() + private val fullFaceDirections: MutableSet = parent?.fullFaceDirections?.toMutableSet() ?: mutableSetOf() private var rotation: Vec3 private var uvLock = false // ToDo @@ -28,41 +30,54 @@ open class BlockModel(val parent: BlockModel? = null, json: JsonObject) { } json["elements"]?.let { it -> elements.clear() + fullFaceDirections.clear() for (element in it.asJsonArray) { - elements.add(BlockModelElement(element.asJsonObject)) + val blockModelElement = BlockModelElement(element.asJsonObject) + elements.add(blockModelElement) + fullFaceDirections.addAll(blockModelElement.fullFaceDirections) } } - var rotateX = parent?.rotation?.x ?: 0 - var rotateY = parent?.rotation?.y ?: 0 - var rotateZ = parent?.rotation?.z ?: 0 + var rotateX = parent?.rotation?.x ?: 0f + var rotateY = parent?.rotation?.y ?: 0f + var rotateZ = parent?.rotation?.z ?: 0f json["x"]?.let { - rotateX = it.asInt + rotateX = it.asFloat } json["y"]?.let { - rotateY = it.asInt + rotateY = it.asFloat } json["z"]?.let { - rotateZ = it.asInt + rotateZ = it.asFloat } json["uvlock"]?.let { uvLock = it.asBoolean } - rotation = Vec3(rotateX, rotateY, rotateZ) + rotation = glm.radians(Vec3(rotateX, rotateY, rotateZ)) } - open fun render(position: InChunkSectionLocation, direction: Directions, data: MutableList) { - var model = Mat4().translate(Vec3(position.x, position.y, position.z)) + open fun render(position: InChunkSectionLocation, data: MutableList, neighbourBlocks: Array) { + var modelMatrix = Mat4().translate(Vec3(position.x, position.y, position.z)) if (rotation.x > 0 || rotation.y > 0 || rotation.z > 0) { - model = model.rotate(glm.radians(rotation.x), Vec3(-1, 0, 0)) - .rotate(glm.radians(rotation.y), Vec3(0, -1, 0)) - .rotate(glm.radians(rotation.z), Vec3(0, 0, -1)) - // ToDo: this should be made easier/effizienter + modelMatrix = modelMatrix.rotate(rotation.x, Vec3(-1, 0, 0)) + .rotate(rotation.y, Vec3(0, -1, 0)) + .rotate(rotation.z, Vec3(0, 0, -1)) + // ToDo: this should be made easier/more efficient } - for (element in elements) { - element.render(textureMapping, model, direction, rotation, data) + for (direction in Directions.DIRECTIONS) { + for (element in elements) { + val blockFullFace = fullFaceDirections.contains(direction) + val neighbourBlockFullFace = neighbourBlocks[direction.ordinal]?.blockModel?.fullFaceDirections?.contains(direction.inverse()) == true + if (blockFullFace && neighbourBlockFullFace) { + continue + } + if (!blockFullFace && neighbourBlockFullFace) { + continue + } + element.render(textureMapping, modelMatrix, direction, rotation, data) + } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModelElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModelElement.kt index f2910ccbb..a7cc51ddb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModelElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/BlockModelElement.kt @@ -13,6 +13,8 @@ open class BlockModelElement(data: JsonObject) { private var from: Vec3 = Vec3(0, 0, 0) private var to: Vec3 = Vec3(16, 16, 16) private val faces: MutableMap = mutableMapOf() + val fullFaceDirections: MutableSet = mutableSetOf() + var fullFace = false init { data["from"]?.let { @@ -24,10 +26,47 @@ open class BlockModelElement(data: JsonObject) { to = Vec3(array[0].asFloat, array[1].asFloat, array[2].asFloat) } data["faces"]?.let { - for ((direction, json) in it.asJsonObject.entrySet()) { - faces[Directions.valueOf(direction.toUpperCase())] = BlockModelFace(json.asJsonObject) + for ((directionName, json) in it.asJsonObject.entrySet()) { + val direction = Directions.valueOf(directionName.toUpperCase()) + when (direction) { + Directions.DOWN -> { + if ((from.y == 0f || to.y == 0f) && ((from.x == 0f && to.z == 16f) || (from.z == 16f && to.x == 0f))) { + fullFace = true + } + } + Directions.UP -> { + if ((from.y == 16f || to.y == 16f) && ((from.x == 0f && to.z == 16f) || (from.z == 16f && to.x == 0f))) { + fullFace = true + } + } + Directions.NORTH -> { + if ((from.x == 0f || to.x == 0f) && ((from.y == 0f && to.y == 16f) || (from.z == 16f && to.z == 0f))) { + fullFace = true + } + } + Directions.SOUTH -> { + if ((from.x == 16f || to.x == 16f) && ((from.y == 0f && to.y == 16f) || (from.z == 16f && to.z == 0f))) { + fullFace = true + } + } + Directions.EAST -> { + if ((from.z == 0f || to.z == 0f) && ((from.y == 0f && to.y == 16f) || (from.x == 16f && to.x == 0f))) { + fullFace = true + } + } + Directions.WEST -> { + if ((from.z == 16f || to.z == 16f) && ((from.y == 0f && to.y == 16f) || (from.x == 16f && to.x == 0f))) { + fullFace = true + } + } + } + faces[direction] = BlockModelFace(json.asJsonObject) + if (fullFace) { + fullFaceDirections.add(direction) + } } } + } private val positionUpLeftFront = Vec3(BlockModel.positionToFloat(from.x), BlockModel.positionToFloat(to.y), BlockModel.positionToFloat(from.z)) @@ -40,20 +79,24 @@ open class BlockModelElement(data: JsonObject) { private val positionDownRightFront = Vec3(BlockModel.positionToFloat(to.x), BlockModel.positionToFloat(from.y), BlockModel.positionToFloat(from.z)) private val positionDownRightBack = Vec3(BlockModel.positionToFloat(to.x), BlockModel.positionToFloat(from.y), BlockModel.positionToFloat(to.z)) - open fun render(textureMapping: MutableMap, model: Mat4, direction: Directions, rotation: Vec3, data: MutableList) { + open fun render(textureMapping: MutableMap, modelMatrix: Mat4, direction: Directions, rotation: Vec3, data: MutableList) { val face = faces[direction] ?: return // Not our face - val texture = textureMapping[face.textureName]?.id ?: TextureArray.DEBUG_TEXTURE.id + val texture = textureMapping[face.textureName] ?: TextureArray.DEBUG_TEXTURE + if (texture.isTransparent) { + return + } + fun addToData(vec3: Vec3, textureCoordinates: Vec2) { val input = Vec4(vec3, 1.0f) - val output = model * input + val output = modelMatrix * input data.add(output.x) data.add(output.y) data.add(output.z) data.add(textureCoordinates.x) data.add(textureCoordinates.y) - data.add(texture.toFloat()) // ToDo: Compact this + data.add(texture.id.toFloat()) // ToDo: Compact this } fun createQuad(vertexPosition1: Vec3, vertexPosition2: Vec3, vertexPosition3: Vec3, vertexPosition4: Vec3, texturePosition1: Vec2, texturePosition2: Vec2, texturePosition3: Vec2, texturePosition4: Vec2) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketPlayerPositionAndRotation.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketPlayerPositionAndRotation.java index 0f4eb1e75..0d71d65d0 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketPlayerPositionAndRotation.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketPlayerPositionAndRotation.java @@ -59,6 +59,7 @@ public class PacketPlayerPositionAndRotation extends ClientboundPacket { connection.sendPacket(new PacketPlayerPositionAndRotationSending(getLocation(), getRotation(), isOnGround())); } connection.getRenderer().teleport(this.location); + connection.getRenderer().rotate(this.rotation); } @Override