package net.minecraft.client.renderer; import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.blaze3d.systems.GpuDevice; import com.mojang.blaze3d.systems.RenderPass; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.FilterMode; import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.textures.TextureFormat; import com.mojang.blaze3d.vertex.VertexFormat; import java.util.OptionalInt; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.util.Mth; import net.minecraft.util.profiling.Profiler; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.dimension.DimensionType; import org.joml.Vector3f; @Environment(EnvType.CLIENT) public class LightTexture implements AutoCloseable { public static final int FULL_BRIGHT = 15728880; public static final int FULL_SKY = 15728640; public static final int FULL_BLOCK = 240; private static final int TEXTURE_SIZE = 16; private final GpuTexture texture; private boolean updateLightTexture; private float blockLightRedFlicker; private final GameRenderer renderer; private final Minecraft minecraft; public LightTexture(GameRenderer renderer, Minecraft minecraft) { this.renderer = renderer; this.minecraft = minecraft; GpuDevice gpuDevice = RenderSystem.getDevice(); this.texture = gpuDevice.createTexture("Light Texture", TextureFormat.RGBA8, 16, 16, 1); this.texture.setTextureFilter(FilterMode.LINEAR, false); gpuDevice.createCommandEncoder().clearColorTexture(this.texture, -1); } public GpuTexture getTarget() { return this.texture; } public void close() { this.texture.close(); } public void tick() { this.blockLightRedFlicker = this.blockLightRedFlicker + (float)((Math.random() - Math.random()) * Math.random() * Math.random() * 0.1); this.blockLightRedFlicker *= 0.9F; this.updateLightTexture = true; } public void turnOffLightLayer() { RenderSystem.setShaderTexture(2, null); } public void turnOnLightLayer() { RenderSystem.setShaderTexture(2, this.texture); } private float calculateDarknessScale(LivingEntity entity, float gamma, float partialTick) { float f = 0.45F * gamma; return Math.max(0.0F, Mth.cos((entity.tickCount - partialTick) * (float) Math.PI * 0.025F) * f); } public void updateLightTexture(float partialTicks) { if (this.updateLightTexture) { this.updateLightTexture = false; ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("lightTex"); ClientLevel clientLevel = this.minecraft.level; if (clientLevel != null) { float f = clientLevel.getSkyDarken(1.0F); float g; if (clientLevel.getSkyFlashTime() > 0) { g = 1.0F; } else { g = f * 0.95F + 0.05F; } float h = this.minecraft.options.darknessEffectScale().get().floatValue(); float i = this.minecraft.player.getEffectBlendFactor(MobEffects.DARKNESS, partialTicks) * h; float j = this.calculateDarknessScale(this.minecraft.player, i, partialTicks) * h; float k = this.minecraft.player.getWaterVision(); float l; if (this.minecraft.player.hasEffect(MobEffects.NIGHT_VISION)) { l = GameRenderer.getNightVisionScale(this.minecraft.player, partialTicks); } else if (k > 0.0F && this.minecraft.player.hasEffect(MobEffects.CONDUIT_POWER)) { l = k; } else { l = 0.0F; } Vector3f vector3f = new Vector3f(f, f, 1.0F).lerp(new Vector3f(1.0F, 1.0F, 1.0F), 0.35F); float m = this.blockLightRedFlicker + 1.5F; float n = clientLevel.dimensionType().ambientLight(); boolean bl = clientLevel.effects().forceBrightLightmap(); float o = this.minecraft.options.gamma().get().floatValue(); RenderSystem.AutoStorageIndexBuffer autoStorageIndexBuffer = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS); GpuBuffer gpuBuffer = autoStorageIndexBuffer.getBuffer(6); try (RenderPass renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(this.texture, OptionalInt.empty())) { renderPass.setPipeline(RenderPipelines.LIGHTMAP); renderPass.setUniform("AmbientLightFactor", n); renderPass.setUniform("SkyFactor", g); renderPass.setUniform("BlockFactor", m); renderPass.setUniform("UseBrightLightmap", bl ? 1 : 0); renderPass.setUniform("SkyLightColor", vector3f.x, vector3f.y, vector3f.z); renderPass.setUniform("NightVisionFactor", l); renderPass.setUniform("DarknessScale", j); renderPass.setUniform("DarkenWorldFactor", this.renderer.getDarkenWorldAmount(partialTicks)); renderPass.setUniform("BrightnessFactor", Math.max(0.0F, o - i)); renderPass.setVertexBuffer(0, RenderSystem.getQuadVertexBuffer()); renderPass.setIndexBuffer(gpuBuffer, autoStorageIndexBuffer.type()); renderPass.drawIndexed(0, 6); } profilerFiller.pop(); } } } public static float getBrightness(DimensionType dimensionType, int lightLevel) { return getBrightness(dimensionType.ambientLight(), lightLevel); } public static float getBrightness(float ambientLight, int lightLevel) { float f = lightLevel / 15.0F; float g = f / (4.0F - 3.0F * f); return Mth.lerp(ambientLight, g, 1.0F); } public static int pack(int blockLight, int skyLight) { return blockLight << 4 | skyLight << 20; } public static int block(int packedLight) { return packedLight >>> 4 & 15; } public static int sky(int packedLight) { return packedLight >>> 20 & 15; } public static int lightCoordsWithEmission(int packedLight, int emmision) { if (emmision == 0) { return packedLight; } else { int i = Math.max(sky(packedLight), emmision); int j = Math.max(block(packedLight), emmision); return pack(j, i); } } }