Commit 7fe1a40f authored by Lukas's avatar Lukas

rendering: chunk culling behind the player

parents 54df8f73 a39fabcb
Pipeline #791 passed with stage
in 3 minutes and 3 seconds
......@@ -20,7 +20,7 @@ import java.io.File;
public class StaticConfiguration {
public static final boolean DEBUG_MODE = true; // if true, additional checks will be made to validate data, ... Decreases performance
public static final boolean BIOME_DEBUG_MODE = true; // colors all biomes according to the biome hashCode
public static final boolean BIOME_DEBUG_MODE = false; // colors all biomes according to the biome hashCode
public static final boolean DEBUG_SLOW_LOADING = false; // if true, many Thread.sleep will be executed and the start will be delayed (by a lot)
public static String CONFIG_FILENAME = "minosoft.json"; // Filename of minosoft's base configuration (located in AppData/Minosoft/config)
public static boolean SKIP_MOJANG_AUTHENTICATION; // disables all connections to mojang
......
......@@ -20,12 +20,16 @@ import com.google.gson.JsonParser;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.config.StaticConfiguration;
import de.bixilon.minosoft.data.mappings.ResourceLocation;
import de.bixilon.minosoft.data.text.RGBColor;
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
import de.bixilon.minosoft.util.CountUpAndDownLatch;
import de.bixilon.minosoft.util.Util;
import de.bixilon.minosoft.util.logging.Log;
import de.matthiasmann.twl.utils.PNGDecoder;
import org.lwjgl.BufferUtils;
import java.io.*;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
......@@ -337,4 +341,18 @@ public class AssetsManager {
public AssetVersion getAssetVersion() {
return this.assetVersion;
}
public RGBColor[] readPixelArray(String name) throws IOException {
PNGDecoder decoder = new PNGDecoder(readAssetAsStream(name));
ByteBuffer buffer = BufferUtils.createByteBuffer(decoder.getWidth() * decoder.getHeight() * PNGDecoder.Format.RGBA.getNumComponents());
decoder.decode(buffer, decoder.getWidth() * PNGDecoder.Format.RGBA.getNumComponents(), PNGDecoder.Format.RGBA);
buffer.rewind();
RGBColor[] colors = new RGBColor[decoder.getWidth() * decoder.getHeight()];
for (int pixel = 0; pixel < buffer.limit(); pixel += PNGDecoder.Format.RGBA.getNumComponents()) {
colors[pixel / 4] = new RGBColor(buffer.get(), buffer.get(), buffer.get(), buffer.get());
}
return colors;
}
}
......@@ -93,7 +93,7 @@ data class Dimension(
ambientLight = data.get("ambient_light")?.asFloat ?: 0f,
infiniBurn = ResourceLocation(data.get("ambient_light")?.asString ?: "infiniburn_overworld"),
respawnAnchorWorks = data.get("respawn_anchor_works")?.asBoolean == true,
hasSkyLight = data.get("has_skylight")?.asBoolean == true,
hasSkyLight = data.get("has_sky_light")?.asBoolean == true,
bedWorks = data.get("bed_works")?.asBoolean == true,
effects = ResourceLocation(data.get("effects")?.asString ?: "overworld"),
hasRaids = data.get("has_raids")?.asBoolean == true,
......
......@@ -31,8 +31,8 @@ open class Registry<T : RegistryItem>(
return resourceLocationMap[resourceLocation] ?: parentRegistry?.get(resourceLocation)
}
open fun get(id: Int): T? {
return idMap[id] ?: parentRegistry?.get(id)
open fun get(id: Int): T {
return idMap[id] ?: parentRegistry?.get(id)!!
}
open fun getId(value: T): Int {
......
......@@ -18,6 +18,10 @@ import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.ResourceLocationDeserializer
import de.bixilon.minosoft.data.mappings.versions.VersionMapping
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.TintColorCalculator
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.MMath
data class Biome(
val resourceLocation: ResourceLocation,
......@@ -25,19 +29,32 @@ data class Biome(
val scale: Float,
val temperature: Float,
val downfall: Float,
val water_color: RGBColor,
val water_fog_color: RGBColor,
val waterColor: RGBColor?,
val waterFogColor: RGBColor?,
val category: BiomeCategory,
val precipation: BiomePrecipation,
val skyColor: RGBColor,
val foliageColor: RGBColor?,
val grassColor: RGBColor?,
val descriptionId: String?,
val grassColorModifier: GrassColorModifiers = GrassColorModifiers.NONE,
) : RegistryItem {
val temperatureColorMapCoordinate = getColorMapCoordinate(temperature)
val downfallColorMapCoordinate = getColorMapCoordinate(downfall * temperature)
override fun toString(): String {
return resourceLocation.toString()
}
private fun getColorMapCoordinate(value: Float): Int {
return ((1.0 - MMath.clamp(value, 0.0f, 1.0f)) * RenderConstants.COLORMAP_SIZE).toInt()
}
fun getClampedTemperature(height: Int): Int {
return getColorMapCoordinate(MMath.clamp(temperature + (MMath.clamp(height - ProtocolDefinition.SEA_LEVEL_HEIGHT, 1, Int.MAX_VALUE) * ProtocolDefinition.HEIGHT_SEA_LEVEL_MODIFIER), 0f, 1f))
}
companion object : ResourceLocationDeserializer<Biome> {
override fun deserialize(mappings: VersionMapping, resourceLocation: ResourceLocation, data: JsonObject): Biome {
return Biome(
......@@ -46,13 +63,20 @@ data class Biome(
scale = data["scale"]?.asFloat ?: 0f,
temperature = data["temperature"]?.asFloat ?: 0f,
downfall = data["downfall"]?.asFloat ?: 0f,
water_color = RGBColor(data["water_color"]?.asInt ?: 0),
water_fog_color = RGBColor(data["water_fog_color"]?.asInt ?: 0),
waterColor = TintColorCalculator.getJsonColor(data["water_color"]?.asInt ?: 0),
waterFogColor = TintColorCalculator.getJsonColor(data["water_fog_color"]?.asInt ?: 0),
category = mappings.biomeCategoryRegistry.get(data["category"]?.asInt ?: -1) ?: DEFAULT_CATEGORY,
precipation = mappings.biomePrecipationRegistry.get(data["precipitation"]?.asInt ?: -1) ?: DEFAULT_PRECIPATION,
skyColor = RGBColor(data["sky_color"]?.asInt ?: 0),
foliageColor = RGBColor(data["foliage_color"]?.asInt ?: 0),
skyColor = data["sky_color"]?.asInt?.let { RGBColor.noAlpha(it) } ?: RenderConstants.GRASS_FAILOVER_COLOR,
foliageColor = TintColorCalculator.getJsonColor(data["foliage_color_override"]?.asInt ?: data["foliage_color"]?.asInt ?: 0),
grassColor = TintColorCalculator.getJsonColor(data["grass_color_override"]?.asInt ?: 0),
descriptionId = data["water_fog_color"]?.asString,
grassColorModifier = data["grass_color_modifier"]?.asString?.toUpperCase()?.let { GrassColorModifiers.valueOf(it) } ?: when (resourceLocation) {
ResourceLocation("minecraft:swamp"), ResourceLocation("minecraft:swamp_hills") -> GrassColorModifiers.SWAMP
ResourceLocation("minecraft:dark_forest"), ResourceLocation("minecraft:dark_forest_hills") -> GrassColorModifiers.DARK_FORREST
else -> GrassColorModifiers.NONE
}
)
}
......@@ -60,4 +84,14 @@ data class Biome(
private val DEFAULT_CATEGORY = BiomeCategory("NONE")
}
enum class GrassColorModifiers(val modifier: (color: RGBColor) -> RGBColor) {
NONE({ color: RGBColor -> color }),
DARK_FORREST({ color: RGBColor -> RGBColor(color.color + 2634762 shl 8) }),
SWAMP({
// ToDo: Minecraft uses PerlinSimplexNoise here
RGBColor("#6A7039")
}),
}
}
......@@ -28,12 +28,13 @@ data class Block(
val hasDynamicShape: Boolean = false,
val tintColor: RGBColor? = null,
private val itemId: Int = 0,
val tint: ResourceLocation? = null,
) : RegistryItem {
lateinit var item: Item
val states: MutableSet<BlockState> = mutableSetOf()
override fun postInit(versionMapping: VersionMapping) {
item = versionMapping.itemRegistry.get(itemId)!!
item = versionMapping.itemRegistry.get(itemId)
}
companion object : ResourceLocationDeserializer<Block> {
......@@ -44,8 +45,9 @@ data class Block(
explosionResistance = data["explosion_resistance"]?.asFloat ?: 0.0f,
hasCollision = data["has_collision"]?.asBoolean ?: false,
hasDynamicShape = data["has_dynamic_shape"]?.asBoolean ?: false,
tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getColor(it) },
tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) },
itemId = data["item"]?.asInt ?: 0,
tint = data["tint"]?.asString?.let { ResourceLocation(it) }
)
// block states
......
......@@ -168,7 +168,7 @@ data class BlockState(
}
}
val tintColor: RGBColor? = data["tint_color"]?.asInt?.let { TintColorCalculator.getColor(it) } ?: owner.tintColor
val tintColor: RGBColor? = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) } ?: owner.tintColor
return BlockState(
......
......@@ -26,7 +26,7 @@ class ItemRegistry(
) : Registry<Item>(parentRegistry = parentRegistry, initialSize = initialSize) {
private var flattened = false
override fun get(id: Int): Item? {
override fun get(id: Int): Item {
return if (!flattened) {
val itemId = id ushr 16
val itemMeta = id and 0xFFFF
......@@ -35,7 +35,11 @@ class ItemRegistry(
if (itemMeta > 0 && itemMeta < Short.MAX_VALUE) {
versionItemId = versionItemId or itemMeta
}
return super.get(versionItemId) ?: super.get(itemId shl 16) // ignore meta data ?
return try {
super.get(versionItemId)
} catch (exception: NullPointerException) {
super.get(itemId shl 16) // ignore meta data ?
}
} else {
super.get(id)
}
......
......@@ -21,6 +21,7 @@ import de.bixilon.minosoft.data.locale.minecraft.MinecraftLocaleManager;
import de.bixilon.minosoft.gui.rendering.font.Font;
import de.bixilon.minosoft.gui.rendering.font.FontBindings;
import de.bixilon.minosoft.gui.rendering.hud.HUDScale;
import de.bixilon.minosoft.gui.rendering.hud.elements.text.HUDFontMesh;
import de.bixilon.minosoft.modding.event.events.annotations.Unsafe;
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
import de.bixilon.minosoft.util.hash.BetterHashSet;
......@@ -33,7 +34,6 @@ import javax.annotation.Nullable;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.List;
public class BaseComponent extends ChatComponent {
private static final String LEGACY_RESET_SUFFIX = String.valueOf(ProtocolDefinition.TEXT_COMPONENT_SPECIAL_PREFIX_CHAR) + PostChatFormattingCodes.RESET.getChar();
......@@ -215,14 +215,14 @@ public class BaseComponent extends ChatComponent {
}
@Override
public void addVerticies(Vec2 startPosition, Vec2 offset, Mat4 perspectiveMatrix, FontBindings binding, Font font, HUDScale hudScale, List<Float> meshData, Vec2 maxSize) {
public void addVerticies(Vec2 startPosition, Vec2 offset, Mat4 perspectiveMatrix, FontBindings binding, Font font, HUDScale hudScale, HUDFontMesh mesh, Vec2 maxSize) {
if (binding == FontBindings.RIGHT_DOWN || binding == FontBindings.RIGHT_UP) {
for (int i = this.parts.size() - 1; i >= 0; i--) {
this.parts.get(i).addVerticies(startPosition, offset, perspectiveMatrix, binding, font, hudScale, meshData, maxSize);
this.parts.get(i).addVerticies(startPosition, offset, perspectiveMatrix, binding, font, hudScale, mesh, maxSize);
}
} else {
for (var chatPart : this.parts) {
chatPart.addVerticies(startPosition, offset, perspectiveMatrix, binding, font, hudScale, meshData, maxSize);
chatPart.addVerticies(startPosition, offset, perspectiveMatrix, binding, font, hudScale, mesh, maxSize);
}
}
}
......
......@@ -21,6 +21,7 @@ import de.bixilon.minosoft.data.locale.minecraft.MinecraftLocaleManager;
import de.bixilon.minosoft.gui.rendering.font.Font;
import de.bixilon.minosoft.gui.rendering.font.FontBindings;
import de.bixilon.minosoft.gui.rendering.hud.HUDScale;
import de.bixilon.minosoft.gui.rendering.hud.elements.text.HUDFontMesh;
import glm_.mat4x4.Mat4;
import glm_.vec2.Vec2;
import javafx.collections.FXCollections;
......@@ -28,7 +29,6 @@ import javafx.collections.ObservableList;
import javafx.scene.Node;
import javax.annotation.Nullable;
import java.util.List;
public abstract class ChatComponent {
public static ChatComponent valueOf(Object raw) {
......@@ -96,5 +96,5 @@ public abstract class ChatComponent {
/**
* @return Adds all verticies to the array (used in opengl)
*/
public abstract void addVerticies(Vec2 startPosition, Vec2 offset, Mat4 perspectiveMatrix, FontBindings binding, Font font, HUDScale hudScale, List<Float> meshData, Vec2 maxSize);
public abstract void addVerticies(Vec2 startPosition, Vec2 offset, Mat4 perspectiveMatrix, FontBindings binding, Font font, HUDScale hudScale, HUDFontMesh mesh, Vec2 maxSize);
}
......@@ -17,11 +17,13 @@ import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.font.FontBindings
import de.bixilon.minosoft.gui.rendering.font.FontChar
import de.bixilon.minosoft.gui.rendering.hud.HUDScale
import de.bixilon.minosoft.gui.rendering.hud.elements.text.HUDFontMesh
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.Util
import de.bixilon.minosoft.util.hash.BetterHashSet
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import glm_.vec3.Vec3
import glm_.vec4.Vec4
import javafx.animation.Animation
import javafx.animation.KeyFrame
......@@ -201,25 +203,20 @@ open class TextComponent : ChatComponent {
return nodes
}
override fun addVerticies(startPosition: Vec2, offset: Vec2, perspectiveMatrix: Mat4, binding: FontBindings, font: Font, hudScale: HUDScale, meshData: MutableList<Float>, maxSize: Vec2) {
fun drawLetterVertex(position: Vec2, uv: Vec2, atlasPage: Int, color: RGBColor, meshData: MutableList<Float>) {
override fun addVerticies(startPosition: Vec2, offset: Vec2, perspectiveMatrix: Mat4, binding: FontBindings, font: Font, hudScale: HUDScale, mesh: HUDFontMesh, maxSize: Vec2) {
fun drawLetterVertex(position: Vec3, uv: Vec2, atlasPage: Int) {
val matrixPosition = perspectiveMatrix * Vec4(position.x, position.y, 0f, 1f)
meshData.add(matrixPosition.x)
meshData.add(matrixPosition.y)
meshData.add(-0.997f)
meshData.add(uv.x)
meshData.add(uv.y)
meshData.add(Float.fromBits(atlasPage))
meshData.add(Float.fromBits(color.color))
mesh.addVertex(Vec3(matrixPosition.x, matrixPosition.y, position.z), uv, atlasPage, color)
}
fun drawLetter(position: Vec2, scaledWidth: Float, scaledHeight: Float, fontChar: FontChar, color: RGBColor, meshData: MutableList<Float>) {
drawLetterVertex(Vec2(position.x, position.y), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][0]], fontChar.atlasTextureIndex, color, meshData)
drawLetterVertex(Vec2(position.x, position.y + scaledHeight), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][3]], fontChar.atlasTextureIndex, color, meshData)
drawLetterVertex(Vec2(position.x + scaledWidth, position.y), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][1]], fontChar.atlasTextureIndex, color, meshData)
drawLetterVertex(Vec2(position.x + scaledWidth, position.y), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][1]], fontChar.atlasTextureIndex, color, meshData)
drawLetterVertex(Vec2(position.x, position.y + scaledHeight), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][3]], fontChar.atlasTextureIndex, color, meshData)
drawLetterVertex(Vec2(position.x + scaledWidth, position.y + scaledHeight), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][2]], fontChar.atlasTextureIndex, color, meshData)
fun drawLetter(position: Vec2, scaledWidth: Float, scaledHeight: Float, fontChar: FontChar) {
drawLetterVertex(Vec3(position.x, position.y, HUD_Z_COORDINATE), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][0]], fontChar.atlasTextureIndex)
drawLetterVertex(Vec3(position.x, position.y + scaledHeight, HUD_Z_COORDINATE), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][3]], fontChar.atlasTextureIndex)
drawLetterVertex(Vec3(position.x + scaledWidth, position.y, HUD_Z_COORDINATE), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][1]], fontChar.atlasTextureIndex)
drawLetterVertex(Vec3(position.x + scaledWidth, position.y, HUD_Z_COORDINATE), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][1]], fontChar.atlasTextureIndex)
drawLetterVertex(Vec3(position.x, position.y + scaledHeight, HUD_Z_COORDINATE), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][3]], fontChar.atlasTextureIndex)
drawLetterVertex(Vec3(position.x + scaledWidth, position.y + scaledHeight, HUD_Z_COORDINATE), fontChar.texturePosition[texturePositionCoordinates[binding.ordinal][2]], fontChar.atlasTextureIndex)
}
// reverse text if right bound
val charArray = when (binding) {
......@@ -260,7 +257,7 @@ open class TextComponent : ChatComponent {
}
val fontChar = font.getChar(char)
val scaledX = fontChar.width * (font.charHeight / fontChar.height.toFloat()) * hudScale.scale
drawLetter(startPosition + offset, scaledX, scaledHeight, fontChar, color, meshData)
drawLetter(startPosition + offset, scaledX, scaledHeight, fontChar)
offset += Vec2(scaledX + (hudScale.scale / 2), 0f)
if (offset.x >= maxSize.x) {
maxSize.x += scaledX + (hudScale.scale / 2)
......@@ -280,5 +277,7 @@ open class TextComponent : ChatComponent {
listOf(2, 3, 0, 1),
listOf(3, 2, 1, 0),
) // matches FontBindings::ordinal
const val HUD_Z_COORDINATE = -0.997f
}
}
......@@ -18,5 +18,5 @@ import de.bixilon.minosoft.data.world.BlockPosition
interface BiomeAccessor {
fun getBiome(position: BlockPosition): Biome
fun getBiome(position: BlockPosition): Biome?
}
......@@ -15,14 +15,20 @@ package de.bixilon.minosoft.data.world.biome
import de.bixilon.minosoft.data.mappings.biomes.Biome
import de.bixilon.minosoft.data.world.BlockPosition
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class NoiseBiomeAccessor(
private val biomes: Array<Biome>,
) : BiomeAccessor {
override fun getBiome(position: BlockPosition): Biome {
override fun getBiome(position: BlockPosition): Biome? {
val inChunk = position.getInChunkSectionLocation()
return biomes[(inChunk.y * 16 + ((inChunk.z / 4) * 4 + (inChunk.x / 4)))]
val index = inChunk.y * ProtocolDefinition.SECTION_HEIGHT_Y + ((inChunk.z / 4) * 4 + (inChunk.x / 4))
if (index < 0 || index > biomes.size) {
return null
}
return biomes[index]
// ToDo: This value is pseudo randomly generated. It depends on the seed of the world (received in join game).
}
......
......@@ -19,6 +19,10 @@ import de.bixilon.minosoft.config.key.KeyAction
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.Location
import de.bixilon.minosoft.data.mappings.biomes.Biome
import de.bixilon.minosoft.data.world.BlockPosition
import de.bixilon.minosoft.data.world.ChunkLocation
import de.bixilon.minosoft.data.world.InChunkSectionLocation
import de.bixilon.minosoft.gui.rendering.chunk.Frustum
import de.bixilon.minosoft.gui.rendering.shader.Shader
import de.bixilon.minosoft.protocol.network.Connection
......@@ -35,7 +39,6 @@ class Camera(
var fov: Float,
private val renderWindow: RenderWindow,
) {
lateinit var viewProjectionMatrix: Mat4
private var mouseSensitivity = Minosoft.getConfig().config.game.camera.moseSensitivity
private var movementSpeed = 7
var cameraPosition = Vec3(0.0f, 0.0f, 0.0f)
......@@ -52,6 +55,21 @@ class Camera(
var cameraRight = Vec3(0.0f, 0.0f, -1.0f)
private var cameraUp = Vec3(0.0f, 1.0f, 0.0f)
var feetLocation: Location = Location(0.0, 0.0, 0.0)
private set
var headLocation: Location = Location(0.0, 0.0, 0.0)
private set
var blockPosition: BlockPosition = BlockPosition(0, 0, 0)
private set
var currentBiome: Biome? = null
private set
var chunkLocation: ChunkLocation = ChunkLocation(0, 0)
private set
var sectionHeight: Int = 0
private set
var inChunkSectionLocation: InChunkSectionLocation = InChunkSectionLocation(0, 0, 0)
private set
private var screenHeight = 0
private var screenWidth = 0
private val shaders: MutableSet<Shader> = mutableSetOf()
......@@ -176,10 +194,30 @@ class Camera(
for (shader in shaders) {
shader.use().setMat4("viewProjectionMatrix", matrix)
}
positionChangeCallback()
}
private fun positionChangeCallback() {
headLocation = Location(cameraPosition)
feetLocation = Location(headLocation.x, headLocation.y - PLAYER_HEIGHT, headLocation.z)
blockPosition = feetLocation.toBlockPosition()
currentBiome = connection.player.world.getChunk(blockPosition.getChunkLocation())?.biomeAccessor?.getBiome(blockPosition)
chunkLocation = blockPosition.getChunkLocation()
sectionHeight = blockPosition.getSectionHeight()
inChunkSectionLocation = blockPosition.getInChunkSectionLocation()
// recalculate sky color for current biome
val blockPosition = Location(cameraPosition).toBlockPosition()
renderWindow.setSkyColor(connection.player.world.getChunk(blockPosition.getChunkLocation())?.biomeAccessor?.getBiome(blockPosition)?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR)
connection.renderer.renderWindow.worldRenderer.recalculateFrustum(Frustum(this))
connection.player.world.dimension?.hasSkyLight?.let {
if (it) {
renderWindow.setSkyColor(currentBiome?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR)
} else {
renderWindow.setSkyColor(RenderConstants.BLACK_COLOR)
}
} ?: renderWindow.setSkyColor(RenderConstants.DEFAULT_SKY_COLOR)
}
private fun calculateProjectionMatrix(screenWidth: Int, screenHeight: Int): Mat4 {
......@@ -216,7 +254,7 @@ class Camera(
private fun sendPositionToServer() {
if (System.currentTimeMillis() - lastPositionChange > ProtocolDefinition.TICK_TIME) {
// ToDo: Replace this with proper movement and only send it, when our position changed
connection.sendPacket(PacketPlayerPositionAndRotationSending(Location(cameraPosition), EntityRotation(yaw, pitch), false))
connection.sendPacket(PacketPlayerPositionAndRotationSending(feetLocation, EntityRotation(yaw, pitch), false))
lastPositionChange = System.currentTimeMillis()
currentPositionSent = true
return
......@@ -224,7 +262,14 @@ class Camera(
currentPositionSent = false
}
fun setPosition(location: Location) {
feetLocation = location
headLocation = Location(location.x, location.y + PLAYER_HEIGHT, location.z)
cameraPosition = headLocation.toVec3()
}
companion object {
private val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f)
private const val PLAYER_HEIGHT = 1.3 // player is 1.8 blocks high, the camera is normally at 0.5. 1.8 - 0.5 = 1.13
}
}
......@@ -17,4 +17,15 @@ import de.bixilon.minosoft.data.text.RGBColor
object RenderConstants {
val DEFAULT_SKY_COLOR = RGBColor("#ecff89")
val WHITE_COLOR = RGBColor("#ffffff")
val BLACK_COLOR = RGBColor("#000000")
val GRASS_FAILOVER_COLOR = RGBColor("#48B518")
val GRASS_OUT_OF_BOUNDS_COLOR = RGBColor(-65281)
val LILY_PAD_INVENTORY_COLOR = RGBColor("#71C35C")
val LILY_PAD_BLOCK_COLOR = RGBColor("#208030")
const val COLORMAP_SIZE = 255
}
......@@ -51,7 +51,7 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
private var deltaTime = 0.0 // time between current frame and last frame
private var lastFrame = 0.0
lateinit var camera: Camera
val camera: Camera = Camera(connection, Minosoft.getConfig().config.game.camera.fov, this)
private val latch = CountUpAndDownLatch(1)
private var renderingStatus = RenderingStates.RUNNING
......@@ -59,6 +59,8 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
private var polygonEnabled = false
private var mouseCatch = !StaticConfiguration.DEBUG_MODE
val tintColorCalculator = TintColorCalculator()
// all renderers
val worldRenderer: WorldRenderer = WorldRenderer(connection, connection.player.world, this)
val hudRenderer: HUDRenderer = HUDRenderer(connection, this)
......@@ -82,7 +84,7 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
latch.countDown()
}
renderQueue.add {
camera.cameraPosition = packet.location.toVec3()
camera.setPosition(packet.location)
camera.setRotation(packet.rotation.yaw.toDouble(), packet.rotation.pitch.toDouble())
}
})
......@@ -111,9 +113,10 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering)
glfwTerminate()
throw RuntimeException("Failed to create the GLFW window")
}
camera = Camera(connection, Minosoft.getConfig().config.game.camera.fov, this)
camera.init(this)
tintColorCalculator.init(connection.version.assetsManager)
glfwSetKeyCallback(this.windowId) { _: Long, key: Int, _: Int, action: Int, _: Int ->
val keyCode = KeyCodes.KEY_CODE_GLFW_ID_MAP[key] ?: KeyCodes.KEY_UNKNOWN
......
......@@ -13,13 +13,51 @@
package de.bixilon.minosoft.gui.rendering
import de.bixilon.minosoft.data.assets.AssetsManager
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.biomes.Biome
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.world.BlockPosition
object TintColorCalculator {
fun getColor(color: Int): RGBColor? {
if (color == 0) {
return null
class TintColorCalculator {
private lateinit var grassColorMap: Array<RGBColor>
private lateinit var foliageColorMap: Array<RGBColor>
fun init(assetsManager: AssetsManager) {
grassColorMap = assetsManager.readPixelArray("minecraft/textures/colormap/grass.png")
foliageColorMap = assetsManager.readPixelArray("minecraft/textures/colormap/foliage.png")
}
fun calculateTint(tint: ResourceLocation, biome: Biome, position: BlockPosition): RGBColor? {
return when (tint) {
ResourceLocation("water_tint") -> biome.waterColor
ResourceLocation("grass_tint"), ResourceLocation("sugar_cane_tint"), ResourceLocation("shearing_double_plant_tint") -> {
val colorMapPixelIndex = biome.downfallColorMapCoordinate shl 8 or biome.temperatureColorMapCoordinate
var color = if (colorMapPixelIndex > grassColorMap.size) {
RenderConstants.GRASS_OUT_OF_BOUNDS_COLOR
} else {
grassColorMap[colorMapPixelIndex]
}
if (color == RenderConstants.WHITE_COLOR) {
color = RenderConstants.GRASS_FAILOVER_COLOR
}
biome.grassColorModifier.modifier.invoke(color)
}