Fixed directional culling and added AABB raster
This commit is contained in:
@@ -277,9 +277,12 @@ public class ModelManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDoubleSided(long metadata) {
|
||||||
|
return ((metadata>>(8*6))&4) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isTranslucent(long metadata) {
|
public static boolean isTranslucent(long metadata) {
|
||||||
//TODO: THIS
|
return ((metadata>>(8*6))&2) != 0;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,19 +7,32 @@ import me.cortex.zenith.common.util.MemoryBuffer;
|
|||||||
import me.cortex.zenith.common.world.WorldEngine;
|
import me.cortex.zenith.common.world.WorldEngine;
|
||||||
import me.cortex.zenith.common.world.WorldSection;
|
import me.cortex.zenith.common.world.WorldSection;
|
||||||
import me.cortex.zenith.common.world.other.Mapper;
|
import me.cortex.zenith.common.world.other.Mapper;
|
||||||
import net.minecraft.block.Blocks;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
public class RenderDataFactory {
|
public class RenderDataFactory {
|
||||||
private final WorldEngine world;
|
private final WorldEngine world;
|
||||||
private final ModelManager modelMan;
|
private final ModelManager modelMan;
|
||||||
private final QuadEncoder encoder;
|
private final QuadEncoder encoder;
|
||||||
|
|
||||||
|
private final Mesher2D negativeMesher = new Mesher2D(5, 15);
|
||||||
|
private final Mesher2D positiveMesher = new Mesher2D(5, 15);
|
||||||
|
|
||||||
private final long[] sectionCache = new long[32*32*32];
|
private final long[] sectionCache = new long[32*32*32];
|
||||||
private final long[] connectedSectionCache = new long[32*32*32];
|
private final long[] connectedSectionCache = new long[32*32*32];
|
||||||
|
|
||||||
|
private final LongArrayList doubleSidedQuadCollector = new LongArrayList();
|
||||||
|
private final LongArrayList translucentQuadCollector = new LongArrayList();
|
||||||
|
private final LongArrayList[] directionalQuadCollectors = new LongArrayList[]{new LongArrayList(), new LongArrayList(), new LongArrayList(), new LongArrayList(), new LongArrayList(), new LongArrayList()};
|
||||||
|
|
||||||
|
|
||||||
|
private int minX;
|
||||||
|
private int minY;
|
||||||
|
private int minZ;
|
||||||
|
private int maxX;
|
||||||
|
private int maxY;
|
||||||
|
private int maxZ;
|
||||||
public RenderDataFactory(WorldEngine world, ModelManager modelManager) {
|
public RenderDataFactory(WorldEngine world, ModelManager modelManager) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.modelMan = modelManager;
|
this.modelMan = modelManager;
|
||||||
@@ -37,12 +50,234 @@ public class RenderDataFactory {
|
|||||||
// its neigbor or not (0 if it does 1 if it doesnt (0 is default behavior))
|
// its neigbor or not (0 if it does 1 if it doesnt (0 is default behavior))
|
||||||
public BuiltSection generateMesh(WorldSection section, int buildMask) {
|
public BuiltSection generateMesh(WorldSection section, int buildMask) {
|
||||||
section.copyDataTo(this.sectionCache);
|
section.copyDataTo(this.sectionCache);
|
||||||
|
this.translucentQuadCollector.clear();
|
||||||
|
this.doubleSidedQuadCollector.clear();
|
||||||
|
for (var collector : this.directionalQuadCollectors) {
|
||||||
|
collector.clear();
|
||||||
|
}
|
||||||
|
this.minX = Integer.MAX_VALUE;
|
||||||
|
this.minY = Integer.MAX_VALUE;
|
||||||
|
this.minZ = Integer.MAX_VALUE;
|
||||||
|
this.maxX = Integer.MIN_VALUE;
|
||||||
|
this.maxY = Integer.MIN_VALUE;
|
||||||
|
this.maxZ = Integer.MIN_VALUE;
|
||||||
|
|
||||||
//TODO:NOTE! when doing face culling of translucent blocks,
|
//TODO:NOTE! when doing face culling of translucent blocks,
|
||||||
// if the connecting type of the translucent block is the same AND the face is full, discard it
|
// if the connecting type of the translucent block is the same AND the face is full, discard it
|
||||||
// this stops e.g. multiple layers of glass (and ocean) from having 3000 layers of quads etc
|
// this stops e.g. multiple layers of glass (and ocean) from having 3000 layers of quads etc
|
||||||
|
|
||||||
|
|
||||||
|
this.generateMeshForAxis(section, 0);//Direction.Axis.Y
|
||||||
|
this.generateMeshForAxis(section, 1);//Direction.Axis.Z
|
||||||
|
this.generateMeshForAxis(section, 2);//Direction.Axis.X
|
||||||
|
|
||||||
|
int quadCount = this.doubleSidedQuadCollector.size() + this.translucentQuadCollector.size();
|
||||||
|
for (var collector : this.directionalQuadCollectors) {
|
||||||
|
quadCount += collector.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quadCount == 0) {
|
||||||
|
return new BuiltSection(section.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
var buff = new MemoryBuffer(quadCount*8L);
|
||||||
|
long ptr = buff.address;
|
||||||
|
int[] offsets = new int[8];
|
||||||
|
int coff = 0;
|
||||||
|
|
||||||
|
//Ordering is: translucent, double sided quads, directional quads
|
||||||
|
offsets[0] = coff;
|
||||||
|
for (long data : this.translucentQuadCollector) {
|
||||||
|
MemoryUtil.memPutLong(ptr + ((coff++)*8L), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
offsets[1] = coff;
|
||||||
|
for (long data : this.doubleSidedQuadCollector) {
|
||||||
|
MemoryUtil.memPutLong(ptr + ((coff++)*8L), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int face = 0; face < 6; face++) {
|
||||||
|
offsets[face+2] = coff;
|
||||||
|
for (long data : this.directionalQuadCollectors[face]) {
|
||||||
|
MemoryUtil.memPutLong(ptr + ((coff++) * 8L), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int aabb = 0;
|
||||||
|
aabb |= this.minX;
|
||||||
|
aabb |= this.minY<<5;
|
||||||
|
aabb |= this.minZ<<10;
|
||||||
|
aabb |= (this.maxX-this.minX)<<15;
|
||||||
|
aabb |= (this.maxY-this.minY)<<20;
|
||||||
|
aabb |= (this.maxZ-this.minZ)<<25;
|
||||||
|
|
||||||
|
return new BuiltSection(section.getKey(), aabb, buff, offsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void generateMeshForAxis(WorldSection section, int axisId) {
|
||||||
|
int aX = axisId==2?1:0;
|
||||||
|
int aY = axisId==0?1:0;
|
||||||
|
int aZ = axisId==1?1:0;
|
||||||
|
|
||||||
|
//Note the way the connectedSectionCache works is that it reuses the section cache because we know we dont need the connectedSection
|
||||||
|
// when we are on the other direction
|
||||||
|
boolean obtainedOppositeSection0 = false;
|
||||||
|
boolean obtainedOppositeSection31 = false;
|
||||||
|
|
||||||
|
|
||||||
|
for (int primary = 0; primary < 32; primary++) {
|
||||||
|
this.negativeMesher.reset();
|
||||||
|
this.positiveMesher.reset();
|
||||||
|
|
||||||
|
for (int a = 0; a < 32; a++) {
|
||||||
|
for (int b = 0; b < 32; b++) {
|
||||||
|
int x = axisId==2?primary:a;
|
||||||
|
int y = axisId==0?primary:(axisId==1?b:a);
|
||||||
|
int z = axisId==1?primary:b;
|
||||||
|
long self = this.sectionCache[WorldSection.getIndex(x,y,z)];
|
||||||
|
if (Mapper.isAir(self)) continue;
|
||||||
|
|
||||||
|
int selfBlockId = Mapper.getBlockId(self);
|
||||||
|
long selfMetadata = this.modelMan.getModelMetadata(selfBlockId);
|
||||||
|
|
||||||
|
boolean putFace = false;
|
||||||
|
|
||||||
|
//Branch into 2 paths, the + direction and -direction, doing it at once makes it much faster as it halves the number of loops
|
||||||
|
|
||||||
|
if (ModelManager.faceExists(selfMetadata, axisId<<1)) {//- direction
|
||||||
|
long facingState = Mapper.AIR;
|
||||||
|
//Need to access the other connecting section
|
||||||
|
if (primary == 0) {
|
||||||
|
if (!obtainedOppositeSection0) {
|
||||||
|
var connectedSection = this.world.acquire(section.lvl, section.x - aX, section.y - aY, section.z - aZ);
|
||||||
|
connectedSection.copyDataTo(this.connectedSectionCache);
|
||||||
|
connectedSection.release();
|
||||||
|
obtainedOppositeSection0 = true;
|
||||||
|
}
|
||||||
|
facingState = this.connectedSectionCache[WorldSection.getIndex(x*(1-aX)+(31*aX), y*(1-aY)+(31*aY), z*(1-aZ)+(31*aZ))];
|
||||||
|
} else {
|
||||||
|
facingState = this.sectionCache[WorldSection.getIndex(x-aX, y-aY, z-aZ)];
|
||||||
|
}
|
||||||
|
|
||||||
|
putFace |= this.putFaceIfCan(this.negativeMesher, (axisId<<1), (axisId<<1)|1, self, selfMetadata, selfBlockId, facingState, a, b);
|
||||||
|
}
|
||||||
|
if (ModelManager.faceExists(selfMetadata, axisId<<1)) {//+ direction
|
||||||
|
long facingState = Mapper.AIR;
|
||||||
|
//Need to access the other connecting section
|
||||||
|
if (primary == 31) {
|
||||||
|
if (!obtainedOppositeSection31) {
|
||||||
|
var connectedSection = this.world.acquire(section.lvl, section.x + aX, section.y + aY, section.z + aZ);
|
||||||
|
connectedSection.copyDataTo(this.connectedSectionCache);
|
||||||
|
connectedSection.release();
|
||||||
|
obtainedOppositeSection31 = true;
|
||||||
|
}
|
||||||
|
facingState = this.connectedSectionCache[WorldSection.getIndex(x*(1-aX), y*(1-aY), z*(1-aZ))];
|
||||||
|
} else {
|
||||||
|
facingState = this.sectionCache[WorldSection.getIndex(x+aX, y+aY, z+aZ)];
|
||||||
|
}
|
||||||
|
|
||||||
|
putFace |= this.putFaceIfCan(this.positiveMesher, (axisId<<1)|1, (axisId<<1), self, selfMetadata, selfBlockId, facingState, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (putFace) {
|
||||||
|
this.minX = Math.min(this.minX, x);
|
||||||
|
this.minY = Math.min(this.minY, y);
|
||||||
|
this.minZ = Math.min(this.minZ, z);
|
||||||
|
this.maxX = Math.max(this.maxX, x);
|
||||||
|
this.maxY = Math.max(this.maxY, y);
|
||||||
|
this.maxZ = Math.max(this.maxZ, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processMeshedFace(this.negativeMesher, axisId<<1, primary, this.directionalQuadCollectors[(axisId<<1)]);
|
||||||
|
processMeshedFace(this.positiveMesher, (axisId<<1)|1, primary, this.directionalQuadCollectors[(axisId<<1)|1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns true if a face was placed
|
||||||
|
private boolean putFaceIfCan(Mesher2D mesher, int face, int opposingFace, long self, long metadata, int selfBlockId, long facingState, int a, int b) {
|
||||||
|
long facingMetadata = this.modelMan.getModelMetadata(Mapper.getBlockId(facingState));
|
||||||
|
|
||||||
|
//If face can be occluded and is occluded from the facing block, then dont render the face
|
||||||
|
if (ModelManager.faceCanBeOccluded(metadata, face) && ModelManager.faceOccludes(facingMetadata, opposingFace)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ModelManager.isTranslucent(metadata) && selfBlockId == Mapper.getBlockId(facingState)) {
|
||||||
|
//If we are facing a block, and are translucent and it is the same block as us, cull the quad
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int clientModelId = this.modelMan.getModelId(selfBlockId);
|
||||||
|
long otherFlags = 0;
|
||||||
|
otherFlags |= ModelManager.isTranslucent(metadata)?1L<<33:0;
|
||||||
|
otherFlags |= ModelManager.isDoubleSided(metadata)?1L<<34:0;
|
||||||
|
mesher.put(a, b, ((long)clientModelId) | (((long) Mapper.getLightId(facingState))<<16) | (((long) Mapper.getBiomeId(self))<<24) | otherFlags);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMeshedFace(Mesher2D mesher, int face, int otherAxis, LongArrayList axisOutputGeometry) {
|
||||||
|
//TODO: encode translucents and double sided quads to different global buffers
|
||||||
|
|
||||||
|
int count = mesher.process();
|
||||||
|
var array = mesher.getArray();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
int quad = array[i];
|
||||||
|
long data = mesher.getDataFromQuad(quad);
|
||||||
|
long encodedQuad = Integer.toUnsignedLong(QuadEncoder.encodePosition(face, otherAxis, quad)) | ((data&0xFFFF)<<26) | (((data>>16)&0xFF)<<55) | (((data>>24)&0x1FF)<<46);
|
||||||
|
|
||||||
|
|
||||||
|
if ((data&(1L<<33))!=0) {
|
||||||
|
this.translucentQuadCollector.add(encodedQuad);
|
||||||
|
} else if ((data&(1L<<34))!=0) {
|
||||||
|
this.doubleSidedQuadCollector.add(encodedQuad);
|
||||||
|
} else {
|
||||||
|
axisOutputGeometry.add(encodedQuad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
private static long encodeRaw(int face, int width, int height, int x, int y, int z, int blockId, int biomeId, int lightId) {
|
||||||
|
return ((long)face) | (((long) width)<<3) | (((long) height)<<7) | (((long) z)<<11) | (((long) y)<<16) | (((long) x)<<21) | (((long) blockId)<<26) | (((long) biomeId)<<46) | (((long) lightId)<<55);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
//outData.clear();
|
||||||
|
|
||||||
|
//var buff = new MemoryBuffer(8*8);
|
||||||
|
//MemoryUtil.memPutLong(buff.address, encodeRaw(2, 0,1,0,0,0,159,0, 0));//92 515
|
||||||
|
//MemoryUtil.memPutLong(buff.address+8, encodeRaw(3, 0,1,0,0,0,159,0, 0));//92 515
|
||||||
|
//MemoryUtil.memPutLong(buff.address+16, encodeRaw(4, 1,2,0,0,0,159,0, 0));//92 515
|
||||||
|
//MemoryUtil.memPutLong(buff.address+24, encodeRaw(5, 1,2,0,0,0,159,0, 0));//92 515
|
||||||
|
//MemoryUtil.memPutLong(buff.address+32, encodeRaw(2, 0,1,0,0,1,159,0, 0));//92 515
|
||||||
|
//MemoryUtil.memPutLong(buff.address+40, encodeRaw(3, 0,1,0,0,1,159,0, 0));//92 515
|
||||||
|
//MemoryUtil.memPutLong(buff.address+48, encodeRaw(2, 0,1,0,0,2,159,0, 0));//92 515
|
||||||
|
//MemoryUtil.memPutLong(buff.address+56, encodeRaw(3, 0,1,0,0,2,159,0, 0));//92 515
|
||||||
|
|
||||||
|
//int modelId = this.modelMan.getModelId(this.world.getMapper().getIdFromBlockState(Blocks.OAK_FENCE.getDefaultState()));
|
||||||
|
//int modelId = this.modelMan.getModelId(this.world.getMapper().getIdFromBlockState(Blocks.OAK_FENCE.getDefaultState()));
|
||||||
|
|
||||||
|
//outData.add(encodeRaw(0, 0,0,0,0,0, modelId,0, 0));
|
||||||
|
//outData.add(encodeRaw(1, 0,0,0,0,0, modelId,0, 0));
|
||||||
|
//outData.add(encodeRaw(2, 0,0,0,0,0, modelId,0, 0));
|
||||||
|
//outData.add(encodeRaw(3, 0,0,0,0,0, modelId,0, 0));
|
||||||
|
//outData.add(encodeRaw(4, 0,0,0,0,0, modelId,0, 0));
|
||||||
|
//outData.add(encodeRaw(5, 0,0,0,0,0, modelId,0, 0));
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
Mesher2D mesher = new Mesher2D(5,15);
|
Mesher2D mesher = new Mesher2D(5,15);
|
||||||
|
|
||||||
LongArrayList outData = new LongArrayList(1000);
|
LongArrayList outData = new LongArrayList(1000);
|
||||||
@@ -282,99 +517,4 @@ public class RenderDataFactory {
|
|||||||
outData.add(Integer.toUnsignedLong(QuadEncoder.encodePosition(5, x, quad)) | ((data&0xFFFF)<<26) | (((data>>16)&0xFF)<<55) | (((data>>24)&0x1FF)<<46));
|
outData.add(Integer.toUnsignedLong(QuadEncoder.encodePosition(5, x, quad)) | ((data&0xFFFF)<<26) | (((data>>16)&0xFF)<<55) | (((data>>24)&0x1FF)<<46));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//var buff = new MemoryBuffer(8*8);
|
|
||||||
//MemoryUtil.memPutLong(buff.address, encodeRaw(2, 0,1,0,0,0,159,0, 0));//92 515
|
|
||||||
//MemoryUtil.memPutLong(buff.address+8, encodeRaw(3, 0,1,0,0,0,159,0, 0));//92 515
|
|
||||||
//MemoryUtil.memPutLong(buff.address+16, encodeRaw(4, 1,2,0,0,0,159,0, 0));//92 515
|
|
||||||
//MemoryUtil.memPutLong(buff.address+24, encodeRaw(5, 1,2,0,0,0,159,0, 0));//92 515
|
|
||||||
//MemoryUtil.memPutLong(buff.address+32, encodeRaw(2, 0,1,0,0,1,159,0, 0));//92 515
|
|
||||||
//MemoryUtil.memPutLong(buff.address+40, encodeRaw(3, 0,1,0,0,1,159,0, 0));//92 515
|
|
||||||
//MemoryUtil.memPutLong(buff.address+48, encodeRaw(2, 0,1,0,0,2,159,0, 0));//92 515
|
|
||||||
//MemoryUtil.memPutLong(buff.address+56, encodeRaw(3, 0,1,0,0,2,159,0, 0));//92 515
|
|
||||||
if (outData.isEmpty()) {
|
|
||||||
return new BuiltSection(section.getKey());
|
|
||||||
}
|
|
||||||
//outData.clear();
|
|
||||||
|
|
||||||
//int modelId = this.modelMan.getModelId(this.world.getMapper().getIdFromBlockState(Blocks.OAK_FENCE.getDefaultState()));
|
|
||||||
int modelId = this.modelMan.getModelId(this.world.getMapper().getIdFromBlockState(Blocks.OAK_FENCE.getDefaultState()));
|
|
||||||
|
|
||||||
//outData.add(encodeRaw(0, 0,0,0,0,0, modelId,0, 0));
|
|
||||||
//outData.add(encodeRaw(1, 0,0,0,0,0, modelId,0, 0));
|
|
||||||
//outData.add(encodeRaw(2, 0,0,0,0,0, modelId,0, 0));
|
|
||||||
//outData.add(encodeRaw(3, 0,0,0,0,0, modelId,0, 0));
|
|
||||||
//outData.add(encodeRaw(4, 0,0,0,0,0, modelId,0, 0));
|
|
||||||
//outData.add(encodeRaw(5, 0,0,0,0,0, modelId,0, 0));
|
|
||||||
|
|
||||||
var buff = new MemoryBuffer(outData.size()*8L);
|
|
||||||
long ptr = buff.address;
|
|
||||||
for (long data : outData) {
|
|
||||||
MemoryUtil.memPutLong(ptr, data); ptr+=8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BuiltSection(section.getKey(), (31<<15)|(31<<20)|(31<<25), buff, new int[]{0, outData.size(), outData.size(), outData.size(), outData.size(), outData.size(), outData.size(), outData.size()});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static long encodeRaw(int face, int width, int height, int x, int y, int z, int blockId, int biomeId, int lightId) {
|
|
||||||
return ((long)face) | (((long) width)<<3) | (((long) height)<<7) | (((long) z)<<11) | (((long) y)<<16) | (((long) x)<<21) | (((long) blockId)<<26) | (((long) biomeId)<<46) | (((long) lightId)<<55);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
private void generateMeshForAxis() {
|
|
||||||
|
|
||||||
//Up direction
|
|
||||||
for (int y = 0; y < 32; y++) {
|
|
||||||
mesher.reset();
|
|
||||||
for (int x = 0; x < 32; x++) {
|
|
||||||
for (int z = 0; z < 32; z++) {
|
|
||||||
long self = this.sectionCache[WorldSection.getIndex(x, y, z)];
|
|
||||||
if (Mapper.isAir(self)) continue;
|
|
||||||
|
|
||||||
int selfBlockId = Mapper.getBlockId(self);
|
|
||||||
long metadata = this.modelMan.getModelMetadata(selfBlockId);
|
|
||||||
|
|
||||||
//If the model doesnt have a face, then just skip it
|
|
||||||
if (!ModelManager.faceExists(metadata, 1)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
long facingState = Mapper.AIR;
|
|
||||||
//Need to access the other connecting section
|
|
||||||
if (y == 31) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
facingState = this.sectionCache[WorldSection.getIndex(x, y+1, z)];
|
|
||||||
}
|
|
||||||
|
|
||||||
long facingMetadata = this.modelMan.getModelMetadata(Mapper.getBlockId(facingState));
|
|
||||||
|
|
||||||
//If face can be occluded and is occluded from the facing block, then dont render the face
|
|
||||||
if (ModelManager.faceCanBeOccluded(metadata, 1) && ModelManager.faceOccludes(facingMetadata, 0)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int clientModelId = this.modelMan.getModelId(selfBlockId);
|
|
||||||
|
|
||||||
mesher.put(x, z, ((long)clientModelId) | (((long) Mapper.getLightId(facingState))<<16) | (((long) Mapper.getBiomeId(self))<<24));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: encode translucents and double sided quads to different global buffers
|
|
||||||
int count = mesher.process();
|
|
||||||
var array = mesher.getArray();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
int quad = array[i];
|
|
||||||
long data = mesher.getDataFromQuad(quad);
|
|
||||||
outData.add(Integer.toUnsignedLong(QuadEncoder.encodePosition(1, y, quad)) | ((data&0xFFFF)<<26) | (((data>>16)&0xFF)<<55) | (((data>>24)&0x1FF)<<46));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,7 @@ layout(local_size_x = 128, local_size_y = 1, local_size_x = 1) in;
|
|||||||
#import <zenith:lod/gl46/bindings.glsl>
|
#import <zenith:lod/gl46/bindings.glsl>
|
||||||
#import <zenith:lod/gl46/frustum.glsl>
|
#import <zenith:lod/gl46/frustum.glsl>
|
||||||
#import <zenith:lod/gl46/section.glsl>
|
#import <zenith:lod/gl46/section.glsl>
|
||||||
|
#line 11
|
||||||
|
|
||||||
//https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_shader_16bit_storage.txt
|
//https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_shader_16bit_storage.txt
|
||||||
// adds support for uint8_t which can use for compact visibility buffer
|
// adds support for uint8_t which can use for compact visibility buffer
|
||||||
@@ -27,7 +28,16 @@ uint encodeLocalLodPos(uint detail, ivec3 pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//TODO: swap to a multidraw indirect counted
|
//Note: if i want reverse indexing i need to use the index buffer offset to offset
|
||||||
|
void writeCmd(uint idx, uint encodedPos, uint offset, uint quadCount) {
|
||||||
|
DrawCommand cmd;
|
||||||
|
cmd.count = quadCount * 6;
|
||||||
|
cmd.instanceCount = 1;
|
||||||
|
cmd.firstIndex = 0;
|
||||||
|
cmd.baseVertex = int(offset)<<2;
|
||||||
|
cmd.baseInstance = encodedPos;
|
||||||
|
cmdBuffer[idx] = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
if (gl_GlobalInvocationID.x >= sectionCount) {
|
if (gl_GlobalInvocationID.x >= sectionCount) {
|
||||||
@@ -55,14 +65,76 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
uint basePtr = extractQuadStart(meta);
|
uint encodedPos = encodeLocalLodPos(detail, ipos);
|
||||||
|
uint ptr = extractQuadStart(meta);
|
||||||
|
ivec3 relative = ipos-(baseSectionPos>>detail);
|
||||||
|
|
||||||
DrawCommand cmd;
|
|
||||||
cmd.count = (meta.cntA&0xFFFF) * 6;
|
|
||||||
cmd.instanceCount = 1;
|
//TODO:FIXME: Figure out why these are in such a weird order
|
||||||
cmd.firstIndex = 0;
|
uint msk = 0;
|
||||||
cmd.baseVertex = int(basePtr)<<2;
|
msk |= uint(relative.y>-1)<<0;
|
||||||
cmd.baseInstance = encodeLocalLodPos(detail, ipos);
|
msk |= uint(relative.y<1 )<<1;
|
||||||
cmdBuffer[atomicAdd(opaqueDrawCount, 1)] = cmd;
|
msk |= uint(relative.z>-1)<<2;
|
||||||
|
msk |= uint(relative.z<1 )<<3;
|
||||||
|
msk |= uint(relative.x>-1)<<4;
|
||||||
|
msk |= uint(relative.x<1 )<<5;
|
||||||
|
|
||||||
|
|
||||||
|
uint cmdPtr = atomicAdd(opaqueDrawCount, bitCount(msk)+1);
|
||||||
|
|
||||||
|
|
||||||
|
uint count = 0;
|
||||||
|
//Translucency
|
||||||
|
count = meta.cntA&0xFFFF;
|
||||||
|
|
||||||
|
ptr += count;
|
||||||
|
|
||||||
|
//Double sided quads
|
||||||
|
count = (meta.cntA>>16)&0xFFFF;
|
||||||
|
writeCmd(cmdPtr++, encodedPos, ptr, count);
|
||||||
|
ptr += count;
|
||||||
|
|
||||||
|
//Down
|
||||||
|
count = (meta.cntB)&0xFFFF;
|
||||||
|
if ((msk&(1<<0))!=0) {
|
||||||
|
writeCmd(cmdPtr++, encodedPos, ptr, count);
|
||||||
|
}
|
||||||
|
ptr += count;
|
||||||
|
|
||||||
|
//Up
|
||||||
|
count = (meta.cntB>>16)&0xFFFF;
|
||||||
|
if ((msk&(1<<1))!=0) {
|
||||||
|
writeCmd(cmdPtr++, encodedPos, ptr, count);
|
||||||
|
}
|
||||||
|
ptr += count;
|
||||||
|
|
||||||
|
//North
|
||||||
|
count = (meta.cntC)&0xFFFF;
|
||||||
|
if ((msk&(1<<2))!=0) {
|
||||||
|
writeCmd(cmdPtr++, encodedPos, ptr, count);
|
||||||
|
}
|
||||||
|
ptr += count;
|
||||||
|
|
||||||
|
//South
|
||||||
|
count = (meta.cntC>>16)&0xFFFF;
|
||||||
|
if ((msk&(1<<3))!=0) {
|
||||||
|
writeCmd(cmdPtr++, encodedPos, ptr, count);
|
||||||
|
}
|
||||||
|
ptr += count;
|
||||||
|
|
||||||
|
//West
|
||||||
|
count = (meta.cntD)&0xFFFF;
|
||||||
|
if ((msk&(1<<4))!=0) {
|
||||||
|
writeCmd(cmdPtr++, encodedPos, ptr, count);
|
||||||
|
}
|
||||||
|
ptr += count;
|
||||||
|
|
||||||
|
//East
|
||||||
|
count = (meta.cntD>>16)&0xFFFF;
|
||||||
|
if ((msk&(1<<5))!=0) {
|
||||||
|
writeCmd(cmdPtr++, encodedPos, ptr, count);
|
||||||
|
}
|
||||||
|
ptr += count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user