Began major engineering on texturing
This commit is contained in:
@@ -46,7 +46,9 @@ dependencies {
|
|||||||
|
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
|
||||||
modImplementation "maven.modrinth:sodium:mc1.20.3-0.5.5"
|
//TODO: this is to eventually not need sodium installed as atm its just used for parsing shaders
|
||||||
|
modRuntimeOnly "maven.modrinth:sodium:mc1.20.3-0.5.5"
|
||||||
|
modCompileOnly "maven.modrinth:sodium:mc1.20.3-0.5.5"
|
||||||
|
|
||||||
modImplementation("maven.modrinth:cloth-config:13.0.121+fabric")
|
modImplementation("maven.modrinth:cloth-config:13.0.121+fabric")
|
||||||
modImplementation("maven.modrinth:modmenu:9.0.0")
|
modImplementation("maven.modrinth:modmenu:9.0.0")
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
package me.cortex.zenith.client.core;
|
package me.cortex.zenith.client.core;
|
||||||
|
|
||||||
import me.cortex.zenith.client.Zenith;
|
|
||||||
import me.cortex.zenith.client.config.ZenithConfig;
|
import me.cortex.zenith.client.config.ZenithConfig;
|
||||||
|
import me.cortex.zenith.client.core.model.ModelTextureBakery;
|
||||||
|
import me.cortex.zenith.client.core.model.TextureUtils;
|
||||||
import me.cortex.zenith.client.core.rendering.*;
|
import me.cortex.zenith.client.core.rendering.*;
|
||||||
import me.cortex.zenith.client.core.rendering.building.RenderGenerationService;
|
import me.cortex.zenith.client.core.rendering.building.RenderGenerationService;
|
||||||
import me.cortex.zenith.client.core.util.DebugUtil;
|
import me.cortex.zenith.client.core.util.DebugUtil;
|
||||||
import me.cortex.zenith.common.world.WorldEngine;
|
import me.cortex.zenith.common.world.WorldEngine;
|
||||||
import me.cortex.zenith.client.core.other.BiomeColour;
|
|
||||||
import me.cortex.zenith.client.core.other.BlockStateColour;
|
|
||||||
import me.cortex.zenith.client.core.other.ColourResolver;
|
|
||||||
import me.cortex.zenith.common.world.other.Mapper;
|
|
||||||
import me.cortex.zenith.client.importers.WorldImporter;
|
import me.cortex.zenith.client.importers.WorldImporter;
|
||||||
import me.cortex.zenith.common.world.storage.FragmentedStorageBackendAdaptor;
|
import me.cortex.zenith.common.world.storage.FragmentedStorageBackendAdaptor;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.block.CropBlock;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.Camera;
|
||||||
import net.minecraft.client.render.Frustum;
|
import net.minecraft.client.render.Frustum;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.chunk.WorldChunk;
|
import net.minecraft.world.chunk.WorldChunk;
|
||||||
|
|
||||||
@@ -83,39 +80,11 @@ public class VoxelCore {
|
|||||||
|
|
||||||
this.postProcessing = null;//new PostProcessing();
|
this.postProcessing = null;//new PostProcessing();
|
||||||
|
|
||||||
this.world.getMapper().setCallbacks(this::stateUpdate, this::biomeUpdate);
|
this.world.getMapper().setCallbacks(a->{}, a->{});
|
||||||
|
|
||||||
for (var state : this.world.getMapper().getStateEntries()) {
|
|
||||||
this.stateUpdate(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var biome : this.world.getMapper().getBiomeEntries()) {
|
|
||||||
this.biomeUpdate(biome);
|
|
||||||
}
|
|
||||||
System.out.println("Entry updates applied");
|
|
||||||
|
|
||||||
System.out.println("Voxel core initialized");
|
System.out.println("Voxel core initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stateUpdate(Mapper.StateEntry entry) {
|
|
||||||
var state = entry.state;
|
|
||||||
int tintMsk = 0;
|
|
||||||
if (biomeTintableAllFaces.contains(state.getBlock())) {
|
|
||||||
tintMsk |= (1<<6)-1;
|
|
||||||
}
|
|
||||||
if (biomeTintableUpFace.contains(state.getBlock())) {
|
|
||||||
tintMsk |= 1<<Direction.UP.getId();
|
|
||||||
}
|
|
||||||
if (waterTint.contains(state.getBlock())) {
|
|
||||||
tintMsk |= 1<<6;
|
|
||||||
}
|
|
||||||
this.renderer.enqueueUpdate(new BlockStateColour(entry.id, tintMsk, ColourResolver.resolveColour(state)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void biomeUpdate(Mapper.BiomeEntry entry) {
|
|
||||||
long dualColour = ColourResolver.resolveBiomeColour(entry.biome);
|
|
||||||
this.renderer.enqueueUpdate(new BiomeColour(entry.id, (int) dualColour, (int) (dualColour>>32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void enqueueIngest(WorldChunk worldChunk) {
|
public void enqueueIngest(WorldChunk worldChunk) {
|
||||||
@@ -129,7 +98,7 @@ public class VoxelCore {
|
|||||||
this.firstTime = false;
|
this.firstTime = false;
|
||||||
}
|
}
|
||||||
this.distanceTracker.setCenter(camera.getBlockPos().getX(), camera.getBlockPos().getY(), camera.getBlockPos().getZ());
|
this.distanceTracker.setCenter(camera.getBlockPos().getX(), camera.getBlockPos().getY(), camera.getBlockPos().getZ());
|
||||||
this.renderer.setupRender(frustum, camera);
|
//this.renderer.setupRender(frustum, camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderOpaque(MatrixStack matrices, double cameraX, double cameraY, double cameraZ) {
|
public void renderOpaque(MatrixStack matrices, double cameraX, double cameraY, double cameraZ) {
|
||||||
@@ -138,6 +107,8 @@ public class VoxelCore {
|
|||||||
DebugUtil.setPositionMatrix(matrices);
|
DebugUtil.setPositionMatrix(matrices);
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
|
|
||||||
|
renderer.getModelManager().updateEntry(0, Blocks.FERN.getDefaultState());
|
||||||
|
|
||||||
//int boundFB = GlStateManager.getBoundFramebuffer();
|
//int boundFB = GlStateManager.getBoundFramebuffer();
|
||||||
//this.postProcessing.setSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
|
//this.postProcessing.setSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
|
||||||
//this.postProcessing.bindClearFramebuffer();
|
//this.postProcessing.bindClearFramebuffer();
|
||||||
@@ -150,7 +121,8 @@ public class VoxelCore {
|
|||||||
//TODO: have the renderer also render a bounding full face just like black boarders around lvl 0
|
//TODO: have the renderer also render a bounding full face just like black boarders around lvl 0
|
||||||
// this is cause the terrain might not exist and so all the caves are visible causing hell for the
|
// this is cause the terrain might not exist and so all the caves are visible causing hell for the
|
||||||
// occlusion culler
|
// occlusion culler
|
||||||
this.renderer.renderFarAwayOpaque(matrices, cameraX, cameraY, cameraZ);
|
if (false)
|
||||||
|
this.renderer.renderFarAwayOpaque(matrices, cameraX, cameraY, cameraZ);
|
||||||
|
|
||||||
|
|
||||||
//glBindFramebuffer(GL_FRAMEBUFFER, boundFB);
|
//glBindFramebuffer(GL_FRAMEBUFFER, boundFB);
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ import static org.lwjgl.opengl.GL45C.glNamedBufferStorage;
|
|||||||
public class GlBuffer extends TrackedObject {
|
public class GlBuffer extends TrackedObject {
|
||||||
public final int id;
|
public final int id;
|
||||||
private final long size;
|
private final long size;
|
||||||
|
|
||||||
|
public GlBuffer(long size) {
|
||||||
|
this(size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public GlBuffer(long size, int flags) {
|
public GlBuffer(long size, int flags) {
|
||||||
this.id = glCreateBuffers();
|
this.id = glCreateBuffers();
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
|||||||
@@ -21,10 +21,11 @@ public class GlFramebuffer extends TrackedObject {
|
|||||||
glDeleteFramebuffers(this.id);
|
glDeleteFramebuffers(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verify() {
|
public GlFramebuffer verify() {
|
||||||
int code;
|
int code;
|
||||||
if ((code = glCheckNamedFramebufferStatus(this.id, GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
|
if ((code = glCheckNamedFramebufferStatus(this.id, GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
throw new IllegalStateException("Framebuffer incomplete with error code: " + code);
|
throw new IllegalStateException("Framebuffer incomplete with error code: " + code);
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package me.cortex.zenith.client.core.model;
|
||||||
|
|
||||||
|
public record ColourDepthTextureData(int[] colour, int[] depth) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package me.cortex.zenith.client.core.model;
|
||||||
|
|
||||||
|
import me.cortex.zenith.client.core.gl.GlBuffer;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
|
||||||
|
//Manages the storage and updating of model states, textures and colours
|
||||||
|
|
||||||
|
//Also has a fast long[] based metadata lookup for when the terrain mesher needs to look up the face occlusion data
|
||||||
|
public class ModelManager {
|
||||||
|
public static final int MODEL_SIZE = 64;
|
||||||
|
private final ModelTextureBakery bakery = new ModelTextureBakery(16, 16);
|
||||||
|
private final GlBuffer modelBuffer;
|
||||||
|
private final long[] metadataCache;
|
||||||
|
|
||||||
|
public ModelManager() {
|
||||||
|
this.modelBuffer = new GlBuffer(MODEL_SIZE * (1<<16));
|
||||||
|
this.metadataCache = new long[1<<16];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateEntry(int id, BlockState blockState) {
|
||||||
|
//This also checks if there is a block colour resolver for the given blockstate and marks that the block has a resolver
|
||||||
|
var textureData = this.bakery.renderFaces(blockState, 123456);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getModelMetadata(int id) {
|
||||||
|
return this.metadataCache[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBufferId() {
|
||||||
|
return this.modelBuffer.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
this.bakery.free();
|
||||||
|
this.modelBuffer.free();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package me.cortex.zenith.client.core.model;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.systems.VertexSorter;
|
||||||
|
import me.cortex.zenith.client.core.gl.GlFramebuffer;
|
||||||
|
import me.cortex.zenith.client.core.gl.GlTexture;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.render.*;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.RotationAxis;
|
||||||
|
import net.minecraft.util.math.random.LocalRandom;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.lwjgl.opengl.GL11C;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.ARBFramebufferObject.*;
|
||||||
|
import static org.lwjgl.opengl.ARBShaderImageLoadStore.GL_FRAMEBUFFER_BARRIER_BIT;
|
||||||
|
import static org.lwjgl.opengl.ARBShaderImageLoadStore.glMemoryBarrier;
|
||||||
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
|
import static org.lwjgl.opengl.GL14C.glBlendFuncSeparate;
|
||||||
|
import static org.lwjgl.opengl.GL45C.glBlitNamedFramebuffer;
|
||||||
|
import static org.lwjgl.opengl.GL45C.glGetTextureImage;
|
||||||
|
|
||||||
|
//Builds a texture for each face of a model
|
||||||
|
public class ModelTextureBakery {
|
||||||
|
private final int width;
|
||||||
|
private final int height;
|
||||||
|
private final GlTexture colourTex;
|
||||||
|
private final GlTexture depthTex;
|
||||||
|
private final GlFramebuffer framebuffer;
|
||||||
|
|
||||||
|
private static final List<MatrixStack> FACE_VIEWS = new ArrayList<>();
|
||||||
|
static {
|
||||||
|
addView(-90,0);//Direction.DOWN
|
||||||
|
addView(90,0);//Direction.UP
|
||||||
|
addView(0,180);//Direction.NORTH
|
||||||
|
addView(0,0);//Direction.SOUTH
|
||||||
|
//TODO: check these arnt the wrong way round
|
||||||
|
addView(0,90);//Direction.EAST
|
||||||
|
addView(0,270);//Direction.WEST
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelTextureBakery(int width, int height) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.colourTex = new GlTexture().store(GL_RGBA8, 1, width, height);
|
||||||
|
this.depthTex = new GlTexture().store(GL_DEPTH24_STENCIL8, 1, width, height);
|
||||||
|
this.framebuffer = new GlFramebuffer().bind(GL_COLOR_ATTACHMENT0, this.colourTex).bind(GL_DEPTH_STENCIL_ATTACHMENT, this.depthTex).verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addView(float pitch, float yaw) {
|
||||||
|
var stack = new MatrixStack();
|
||||||
|
stack.translate(0.5f,0.5f,0);
|
||||||
|
stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
|
||||||
|
stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
|
||||||
|
stack.translate(-0.5f,-0.5f,-0.5f);
|
||||||
|
FACE_VIEWS.add(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColourDepthTextureData[] renderFaces(BlockState state, long randomValue) {
|
||||||
|
var model = MinecraftClient.getInstance()
|
||||||
|
.getBakedModelManager()
|
||||||
|
.getBlockModels()
|
||||||
|
.getModel(state);
|
||||||
|
|
||||||
|
int oldFB = GlStateManager.getBoundFramebuffer();
|
||||||
|
var oldProjection = new Matrix4f(RenderSystem.getProjectionMatrix());
|
||||||
|
GL11C.glViewport(0, 0, this.width, this.height);
|
||||||
|
|
||||||
|
RenderSystem.setProjectionMatrix(new Matrix4f().identity().scale(2,2,-1f).translate(-0.5f, -0.5f, 0.0f), VertexSorter.BY_Z);
|
||||||
|
|
||||||
|
glClearColor(0,0,0,0);
|
||||||
|
glClearDepth(1);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, this.framebuffer.id);
|
||||||
|
|
||||||
|
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
RenderSystem.enableCull();
|
||||||
|
RenderSystem.depthFunc(GL_LESS);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
|
||||||
|
|
||||||
|
|
||||||
|
if (!state.getFluidState().isEmpty()) {
|
||||||
|
//TODO: render fluid
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderLayer = RenderLayers.getBlockLayer(state);
|
||||||
|
if (renderLayer == RenderLayer.getTranslucent()) {
|
||||||
|
//TODO: TRANSLUCENT, must sort the quad first
|
||||||
|
}
|
||||||
|
|
||||||
|
var faces = new ColourDepthTextureData[FACE_VIEWS.size()];
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
faces[i] = captureView(state, model, FACE_VIEWS.get(i), randomValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.setProjectionMatrix(oldProjection, VertexSorter.BY_DISTANCE);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, oldFB);
|
||||||
|
GL11C.glViewport(GlStateManager.Viewport.getX(), GlStateManager.Viewport.getY(), GlStateManager.Viewport.getWidth(), GlStateManager.Viewport.getHeight());
|
||||||
|
|
||||||
|
return faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColourDepthTextureData captureView(BlockState state, BakedModel model, MatrixStack stack, long randomValue) {
|
||||||
|
var vc = Tessellator.getInstance().getBuffer();
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
|
||||||
|
renderQuads(vc, state, model, stack, randomValue);
|
||||||
|
BufferRenderer.drawWithGlobalProgram(vc.end());
|
||||||
|
|
||||||
|
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
|
||||||
|
int[] colourData = new int[this.width*this.height];
|
||||||
|
int[] depthData = new int[this.width*this.height];
|
||||||
|
glGetTextureImage(this.colourTex.id, 0, GL_RGBA, GL_UNSIGNED_BYTE, colourData);
|
||||||
|
glGetTextureImage(this.depthTex.id, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depthData);
|
||||||
|
return new ColourDepthTextureData(colourData, depthData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void renderQuads(BufferBuilder builder, BlockState state, BakedModel model, MatrixStack stack, long randomValue) {
|
||||||
|
for (Direction direction : new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, null}) {
|
||||||
|
var quads = model.getQuads(state, direction, new LocalRandom(randomValue));
|
||||||
|
for (var quad : quads) {
|
||||||
|
builder.quad(stack.peek(), quad, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
this.framebuffer.free();
|
||||||
|
this.colourTex.free();
|
||||||
|
this.depthTex.free();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package me.cortex.zenith.client.core.model;
|
||||||
|
|
||||||
|
//Texturing utils to manipulate data from the model bakery
|
||||||
|
public class TextureUtils {
|
||||||
|
//Returns if any pixels are not fully transparent or fully translucent
|
||||||
|
public static boolean hasAlpha(ColourDepthTextureData texture) {
|
||||||
|
for (int pixel : texture.colour()) {
|
||||||
|
int alpha = (pixel>>24)&0xFF;
|
||||||
|
if (alpha != 0 && alpha != 255) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSolid(ColourDepthTextureData texture) {
|
||||||
|
for (int pixel : texture.colour()) {
|
||||||
|
if (((pixel>>24)&0xFF) != 255) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFullyCovered(ColourDepthTextureData texture) {
|
||||||
|
for (int pixel : texture.colour()) {
|
||||||
|
if (((pixel>>24)&0xFF) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static int computeDepth(ColourDepthTextureData texture, int mode) {
|
||||||
|
final var colourData = texture.colour();
|
||||||
|
final var depthData = texture.depth();
|
||||||
|
for (int i = 0; i < colourData.length; i++) {
|
||||||
|
if ((colourData[0]&0xFF)==0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int depth = depthData[0]&0xffffff;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
package me.cortex.zenith.client.core.other;
|
|
||||||
|
|
||||||
public record BiomeColour(int id, int foliageColour, int waterColour) {
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
package me.cortex.zenith.client.core.other;
|
|
||||||
|
|
||||||
public record BlockStateColour(int id, int biomeTintMsk, int[] faceColours) {
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
package me.cortex.zenith.client.core.other;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.block.Blocks;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.render.model.BakedQuad;
|
|
||||||
import net.minecraft.client.texture.NativeImage;
|
|
||||||
import net.minecraft.registry.RegistryKeys;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.math.random.LocalRandom;
|
|
||||||
|
|
||||||
public class ColourResolver {
|
|
||||||
//TODO: sample from multiple random values and avg it
|
|
||||||
public static int[] resolveColour(BlockState state) {
|
|
||||||
return resolveColour(state, 1234567890L);
|
|
||||||
}
|
|
||||||
|
|
||||||
//The way this works is it takes the and computes its colour, it then computes the area of the quad and the normal direction
|
|
||||||
// it adds each area and colour to a per direcition colour
|
|
||||||
// for non specific axis dimensions it takes the normal of each quad computes the dot between it and each of the directions
|
|
||||||
// and averages that
|
|
||||||
// if the colour doesnt exist for a specific axis set it to the average of the other axis and or make it translucent
|
|
||||||
|
|
||||||
//TODO: fixme: finish
|
|
||||||
public static int[] resolveColour(BlockState state, long randomValue) {
|
|
||||||
if (state == Blocks.AIR.getDefaultState()) {
|
|
||||||
return new int[6];
|
|
||||||
}
|
|
||||||
int[][] builder = new int[6][5];
|
|
||||||
var random = new LocalRandom(randomValue);
|
|
||||||
if (state.getFluidState().isEmpty()) {
|
|
||||||
for (Direction direction : new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, null}) {
|
|
||||||
var quads = MinecraftClient.getInstance()
|
|
||||||
.getBakedModelManager()
|
|
||||||
.getBlockModels()
|
|
||||||
.getModel(state)
|
|
||||||
.getQuads(state, direction, random);
|
|
||||||
for (var quad : quads) {
|
|
||||||
long weightColour = resolveQuadColour(quad);
|
|
||||||
int colour = (int) weightColour;
|
|
||||||
int weight = (int) (weightColour>>32);
|
|
||||||
if (direction == null) {
|
|
||||||
//TODO: apply normal multiplication to weight
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
builder[i][0] += weight;
|
|
||||||
builder[i][4] += weight * ((colour>>>24)&0xFF);
|
|
||||||
builder[i][3] += weight * ((colour>>>16)&0xFF);
|
|
||||||
builder[i][2] += weight * ((colour>>>8)&0xFF);
|
|
||||||
builder[i][1] += weight * ((colour>>>0)&0xFF);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
builder[direction.getId()][0] += weight;
|
|
||||||
builder[direction.getId()][4] += weight*((colour>>>24)&0xFF);
|
|
||||||
builder[direction.getId()][3] += weight*((colour>>>16)&0xFF);
|
|
||||||
builder[direction.getId()][2] += weight*((colour>>>8)&0xFF);
|
|
||||||
builder[direction.getId()][1] += weight*((colour>>>0)&0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//TODO FIXME: need to account for both the fluid and block state at the same time
|
|
||||||
//FIXME: make it not hacky and use the fluid handler thing from fabric
|
|
||||||
|
|
||||||
long weightColour = resolveNI(MinecraftClient.getInstance().getBakedModelManager().getBlockModels().getModelParticleSprite(state).getContents().image);
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
builder[i][0] = 1;
|
|
||||||
builder[i][1] += (weightColour>>0)&0xFF;
|
|
||||||
builder[i][2] += (weightColour>>8)&0xFF;
|
|
||||||
builder[i][3] += (weightColour>>16)&0xFF;
|
|
||||||
builder[i][4] += (weightColour>>24)&0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] out = new int[6];
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
int c = builder[i][0];
|
|
||||||
if (c == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int r = builder[i][4]/c;
|
|
||||||
int g = builder[i][3]/c;
|
|
||||||
int b = builder[i][2]/c;
|
|
||||||
int a = builder[i][1]/c;
|
|
||||||
out[i] = (r<<24)|(g<<16)|(b<<8)|a;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long resolveQuadColour(BakedQuad quad) {
|
|
||||||
return resolveNI(quad.getSprite().getContents().image);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long resolveNI(NativeImage image) {
|
|
||||||
int r = 0;
|
|
||||||
int g = 0;
|
|
||||||
int b = 0;
|
|
||||||
int a = 0;
|
|
||||||
int count = 0;
|
|
||||||
for (int y = 0; y < image.getHeight(); y++) {
|
|
||||||
for (int x = 0; x < image.getWidth(); x++) {
|
|
||||||
int colour = image.getColor(x, y);
|
|
||||||
if (((colour >>> 24)&0xFF) == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
r += (colour >>> 0) & 0xFF;
|
|
||||||
g += (colour >>> 8) & 0xFF;
|
|
||||||
b += (colour >>> 16) & 0xFF;
|
|
||||||
a += (colour >>> 24) & 0xFF;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r /= count;
|
|
||||||
g /= count;
|
|
||||||
b /= count;
|
|
||||||
a /= count;
|
|
||||||
|
|
||||||
int colour = (r<<24)|(g<<16)|(b<<8)|a;
|
|
||||||
|
|
||||||
return Integer.toUnsignedLong(colour)|(((long)count)<<32);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static long resolveBiomeColour(String biomeId) {
|
|
||||||
var biome = MinecraftClient.getInstance().world.getRegistryManager().get(RegistryKeys.BIOME).get(new Identifier(biomeId));
|
|
||||||
if (biome == null) {
|
|
||||||
System.err.println("Biome: " + biomeId + " doesnt exist in registry!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int ARGBFoliage = biome.getFoliageColor();
|
|
||||||
int ARGBWater = biome.getWaterColor();
|
|
||||||
return Integer.toUnsignedLong(((ARGBFoliage&0xFFFFFF)<<8)|(ARGBFoliage>>>24)) | (Integer.toUnsignedLong(((ARGBWater&0xFFFFFF)<<8)|(ARGBWater>>>24))<<32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,10 +4,9 @@ package me.cortex.zenith.client.core.rendering;
|
|||||||
// could maybe tosomething else
|
// could maybe tosomething else
|
||||||
|
|
||||||
import me.cortex.zenith.client.core.gl.GlBuffer;
|
import me.cortex.zenith.client.core.gl.GlBuffer;
|
||||||
|
import me.cortex.zenith.client.core.model.ModelManager;
|
||||||
import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry;
|
import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry;
|
||||||
import me.cortex.zenith.client.core.rendering.util.UploadStream;
|
import me.cortex.zenith.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.zenith.client.core.other.BiomeColour;
|
|
||||||
import me.cortex.zenith.client.core.other.BlockStateColour;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.Camera;
|
||||||
import net.minecraft.client.render.Frustum;
|
import net.minecraft.client.render.Frustum;
|
||||||
@@ -16,7 +15,6 @@ import org.joml.FrustumIntersection;
|
|||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.ARBMultiDrawIndirect.glMultiDrawElementsIndirect;
|
import static org.lwjgl.opengl.ARBMultiDrawIndirect.glMultiDrawElementsIndirect;
|
||||||
import static org.lwjgl.opengl.GL30.*;
|
import static org.lwjgl.opengl.GL30.*;
|
||||||
@@ -35,14 +33,9 @@ public abstract class AbstractFarWorldRenderer {
|
|||||||
|
|
||||||
protected final GlBuffer uniformBuffer;
|
protected final GlBuffer uniformBuffer;
|
||||||
protected final GeometryManager geometry;
|
protected final GeometryManager geometry;
|
||||||
|
protected final ModelManager models;
|
||||||
private final ConcurrentLinkedDeque<BlockStateColour> stateUpdateQueue = new ConcurrentLinkedDeque<>();
|
|
||||||
private final ConcurrentLinkedDeque<BiomeColour> biomeUpdateQueue = new ConcurrentLinkedDeque<>();
|
|
||||||
protected final GlBuffer stateDataBuffer;
|
|
||||||
protected final GlBuffer biomeDataBuffer;
|
|
||||||
protected final GlBuffer lightDataBuffer;
|
protected final GlBuffer lightDataBuffer;
|
||||||
|
|
||||||
|
|
||||||
//Current camera base level section position
|
//Current camera base level section position
|
||||||
protected int sx;
|
protected int sx;
|
||||||
protected int sy;
|
protected int sy;
|
||||||
@@ -51,12 +44,10 @@ public abstract class AbstractFarWorldRenderer {
|
|||||||
protected FrustumIntersection frustum;
|
protected FrustumIntersection frustum;
|
||||||
|
|
||||||
public AbstractFarWorldRenderer(int geometrySize, int maxSections) {
|
public AbstractFarWorldRenderer(int geometrySize, int maxSections) {
|
||||||
this.uniformBuffer = new GlBuffer(1024, 0);
|
this.uniformBuffer = new GlBuffer(1024);
|
||||||
//TODO: make these both dynamically sized
|
this.lightDataBuffer = new GlBuffer(256*4);//256 of uint
|
||||||
this.stateDataBuffer = new GlBuffer((1<<16)*28, 0);//Capacity for 1<<16 entries
|
|
||||||
this.biomeDataBuffer = new GlBuffer(512*4*2, 0);//capacity for 1<<9 entries
|
|
||||||
this.lightDataBuffer = new GlBuffer(256*4, 0);//256 of uint
|
|
||||||
this.geometry = new GeometryManager(geometrySize*8L, maxSections);
|
this.geometry = new GeometryManager(geometrySize*8L, maxSections);
|
||||||
|
this.models = new ModelManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void setupVao();
|
protected abstract void setupVao();
|
||||||
@@ -89,36 +80,10 @@ public abstract class AbstractFarWorldRenderer {
|
|||||||
|
|
||||||
//Upload any new geometry
|
//Upload any new geometry
|
||||||
this.geometry.uploadResults();
|
this.geometry.uploadResults();
|
||||||
|
|
||||||
//Upload any block state changes
|
|
||||||
while (!this.stateUpdateQueue.isEmpty()) {
|
|
||||||
var stateUpdate = this.stateUpdateQueue.pop();
|
|
||||||
long ptr = UploadStream.INSTANCE.upload(this.stateDataBuffer, stateUpdate.id()*28L, 28);
|
|
||||||
MemoryUtil.memPutInt(ptr, stateUpdate.biomeTintMsk()); ptr+=4;
|
|
||||||
for (int faceColour : stateUpdate.faceColours()) {
|
|
||||||
MemoryUtil.memPutInt(ptr, faceColour); ptr+=4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Upload any biome changes
|
|
||||||
while (!this.biomeUpdateQueue.isEmpty()) {
|
|
||||||
var biomeUpdate = this.biomeUpdateQueue.pop();
|
|
||||||
long ptr = UploadStream.INSTANCE.upload(this.biomeDataBuffer, biomeUpdate.id()*8L, 8);
|
|
||||||
MemoryUtil.memPutInt(ptr, biomeUpdate.foliageColour()); ptr+=4;
|
|
||||||
MemoryUtil.memPutInt(ptr, biomeUpdate.waterColour()); ptr+=4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz);
|
public abstract void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz);
|
||||||
|
|
||||||
public void enqueueUpdate(BlockStateColour stateColour) {
|
|
||||||
this.stateUpdateQueue.add(stateColour);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enqueueUpdate(BiomeColour biomeColour) {
|
|
||||||
this.biomeUpdateQueue.add(biomeColour);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enqueueResult(BuiltSectionGeometry result) {
|
public void enqueueResult(BuiltSectionGeometry result) {
|
||||||
this.geometry.enqueueResult(result);
|
this.geometry.enqueueResult(result);
|
||||||
}
|
}
|
||||||
@@ -129,10 +94,13 @@ public abstract class AbstractFarWorldRenderer {
|
|||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
glDeleteVertexArrays(this.vao);
|
glDeleteVertexArrays(this.vao);
|
||||||
|
this.models.free();
|
||||||
this.geometry.free();
|
this.geometry.free();
|
||||||
this.uniformBuffer.free();
|
this.uniformBuffer.free();
|
||||||
this.stateDataBuffer.free();
|
|
||||||
this.biomeDataBuffer.free();
|
|
||||||
this.lightDataBuffer.free();
|
this.lightDataBuffer.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ModelManager getModelManager() {
|
||||||
|
return this.models;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class GeometryManager {
|
|||||||
|
|
||||||
|
|
||||||
public GeometryManager(long geometryBufferSize, int maxSections) {
|
public GeometryManager(long geometryBufferSize, int maxSections) {
|
||||||
this.sectionMetaBuffer = new GlBuffer(((long) maxSections) * SECTION_METADATA_SIZE, 0);
|
this.sectionMetaBuffer = new GlBuffer(((long) maxSections) * SECTION_METADATA_SIZE);
|
||||||
this.geometryBuffer = new BufferArena(geometryBufferSize, 8);
|
this.geometryBuffer = new BufferArena(geometryBufferSize, 8);
|
||||||
this.pos2id.defaultReturnValue(-1);
|
this.pos2id.defaultReturnValue(-1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer {
|
|||||||
|
|
||||||
public Gl46FarWorldRenderer(int geometryBuffer, int maxSections) {
|
public Gl46FarWorldRenderer(int geometryBuffer, int maxSections) {
|
||||||
super(geometryBuffer, maxSections);
|
super(geometryBuffer, maxSections);
|
||||||
glCommandBuffer = new GlBuffer(maxSections*5L*4, 0);
|
this.glCommandBuffer = new GlBuffer(maxSections*5L*4);
|
||||||
glVisibilityBuffer = new GlBuffer(maxSections*4L, 0);
|
this.glVisibilityBuffer = new GlBuffer(maxSections*4L);
|
||||||
glClearNamedBufferData(glCommandBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
|
glClearNamedBufferData(this.glCommandBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
|
||||||
glClearNamedBufferData(glVisibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
|
glClearNamedBufferData(this.glVisibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
|
||||||
setupVao();
|
setupVao();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,9 +67,8 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer {
|
|||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.glCommandBuffer.id);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.glCommandBuffer.id);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.geometry.metaId());
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.geometry.metaId());
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, this.glVisibilityBuffer.id);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, this.glVisibilityBuffer.id);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, this.stateDataBuffer.id);//State LUT
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, this.models.getBufferId());
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.biomeDataBuffer.id);//Biome LUT
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.lightDataBuffer.id);//Lighting LUT
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, this.lightDataBuffer.id);//Lighting LUT
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package me.cortex.zenith.client.core.rendering;
|
|
||||||
|
|
||||||
//Manages the storage and updating of model states, textures and colours
|
|
||||||
public class ModelManager {
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package me.cortex.zenith.client.core.rendering;
|
|
||||||
|
|
||||||
import me.cortex.zenith.client.core.gl.shader.Shader;
|
|
||||||
import me.cortex.zenith.client.core.gl.shader.ShaderType;
|
|
||||||
import me.cortex.zenith.client.core.rendering.util.UploadStream;
|
|
||||||
import net.minecraft.client.render.RenderLayer;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.ARBMultiDrawIndirect.glMultiDrawElementsIndirect;
|
|
||||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
|
||||||
import static org.lwjgl.opengl.NVMeshShader.glDrawMeshTasksNV;
|
|
||||||
|
|
||||||
//TODO: make this a 2 phase culling system
|
|
||||||
// first phase renders the terrain, in the terrain task shader it also checks if the section was not visible in the frustum but now is
|
|
||||||
// and then renders it and marks it as being in the frustum
|
|
||||||
public class NvFarWorldRenderer extends AbstractFarWorldRenderer {
|
|
||||||
private final Shader primaryTerrainRaster = Shader.make()
|
|
||||||
.add(ShaderType.TASK, "voxelmon:lod/nvmesh/primary.task")
|
|
||||||
.add(ShaderType.MESH, "voxelmon:lod/nvmesh/primary.mesh")
|
|
||||||
.add(ShaderType.FRAGMENT, "voxelmon:lod/nvmesh/primary.frag")
|
|
||||||
.compile();
|
|
||||||
|
|
||||||
public NvFarWorldRenderer(int geometrySize, int maxSections) {
|
|
||||||
super(geometrySize, maxSections);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupVao() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz) {
|
|
||||||
if (this.geometry.getSectionCount() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RenderLayer.getCutoutMipped().startDrawing();
|
|
||||||
|
|
||||||
UploadStream.INSTANCE.commit();
|
|
||||||
|
|
||||||
glBindVertexArray(this.vao);
|
|
||||||
this.primaryTerrainRaster.bind();
|
|
||||||
glDrawMeshTasksNV(0, this.geometry.getSectionCount());
|
|
||||||
glBindVertexArray(0);
|
|
||||||
|
|
||||||
|
|
||||||
RenderLayer.getCutoutMipped().endDrawing();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown() {
|
|
||||||
super.shutdown();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ public class SharedIndexBuffer {
|
|||||||
private final GlBuffer indexBuffer;
|
private final GlBuffer indexBuffer;
|
||||||
|
|
||||||
public SharedIndexBuffer() {
|
public SharedIndexBuffer() {
|
||||||
this.indexBuffer = new GlBuffer((1<<16)*6*2 + 6*2*3, 0);
|
this.indexBuffer = new GlBuffer((1<<16)*6*2 + 6*2*3);
|
||||||
var quadIndexBuff = IndexUtil.generateQuadIndicesShort(16380);
|
var quadIndexBuff = IndexUtil.generateQuadIndicesShort(16380);
|
||||||
var cubeBuff = generateCubeIndexBuffer();
|
var cubeBuff = generateCubeIndexBuffer();
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class BufferArena {
|
|||||||
}
|
}
|
||||||
this.size = capacity;
|
this.size = capacity;
|
||||||
this.elementSize = elementSize;
|
this.elementSize = elementSize;
|
||||||
this.buffer = new GlBuffer(capacity, 0);
|
this.buffer = new GlBuffer(capacity);
|
||||||
this.allocationMap.setLimit(capacity/elementSize);
|
this.allocationMap.setLimit(capacity/elementSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import net.minecraft.util.math.Box;
|
|||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
public class DebugUtil {
|
public class DebugUtil {
|
||||||
private static Matrix4f positionMatrix = new Matrix4f().identity();
|
public static Matrix4f positionMatrix = new Matrix4f().identity();
|
||||||
public static void setPositionMatrix(MatrixStack stack) {
|
public static void setPositionMatrix(MatrixStack stack) {
|
||||||
positionMatrix = new Matrix4f(stack.peek().getPositionMatrix());
|
positionMatrix = new Matrix4f(stack.peek().getPositionMatrix());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,16 +11,10 @@ layout(binding = 0, std140) uniform SceneUniform {
|
|||||||
uint frameId;
|
uint frameId;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct State {
|
struct BlockModel {
|
||||||
uint biomeTintMsk;
|
|
||||||
uint faceColours[6];
|
uint faceColours[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Biome {
|
|
||||||
uint foliage;
|
|
||||||
uint water;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SectionMeta {
|
struct SectionMeta {
|
||||||
uvec4 header;
|
uvec4 header;
|
||||||
uvec4 drawdata;
|
uvec4 drawdata;
|
||||||
@@ -57,15 +51,11 @@ layout(binding = 4, std430) VISIBILITY_ACCESS restrict buffer VisibilityBuffer {
|
|||||||
uint visibilityData[];
|
uint visibilityData[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(binding = 5, std430) readonly restrict buffer StateBuffer {
|
layout(binding = 5, std430) readonly restrict buffer ModelBuffer {
|
||||||
State stateData[];
|
BlockModel modelData[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(binding = 6, std430) readonly restrict buffer BiomeBuffer {
|
layout(binding = 6, std430) readonly restrict buffer LightingBuffer {
|
||||||
Biome biomeData[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(binding = 7, std430) readonly restrict buffer LightingBuffer {
|
|
||||||
uint lightData[];
|
uint lightData[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -63,20 +63,11 @@ void main() {
|
|||||||
|
|
||||||
uint stateId = extractStateId(quad);
|
uint stateId = extractStateId(quad);
|
||||||
uint biomeId = extractBiomeId(quad);
|
uint biomeId = extractBiomeId(quad);
|
||||||
State stateInfo = stateData[stateId];
|
BlockModel stateInfo = modelData[stateId];
|
||||||
colour = uint2vec4RGBA(stateInfo.faceColours[face]);
|
colour = uint2vec4RGBA(stateInfo.faceColours[face]);
|
||||||
|
|
||||||
colour *= getLighting(extractLightId(quad));
|
colour *= getLighting(extractLightId(quad));
|
||||||
|
|
||||||
if (((stateInfo.biomeTintMsk>>face)&1) == 1) {
|
|
||||||
vec4 biomeColour = uint2vec4RGBA(biomeData[biomeId].foliage);
|
|
||||||
colour *= biomeColour;
|
|
||||||
}
|
|
||||||
//Apply water tint
|
|
||||||
if (((stateInfo.biomeTintMsk>>6)&1) == 1) {
|
|
||||||
colour *= vec4(0.247, 0.463, 0.894, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Apply face tint
|
//Apply face tint
|
||||||
if (face == 0) {
|
if (face == 0) {
|
||||||
colour.xyz *= vec3(0.75, 0.75, 0.75);
|
colour.xyz *= vec3(0.75, 0.75, 0.75);
|
||||||
|
|||||||
Reference in New Issue
Block a user