Mostly finish non-opaque model support

This commit is contained in:
mcrcortex
2025-05-06 22:07:22 +10:00
parent 6087dba91b
commit d072f474a4

View File

@@ -179,7 +179,6 @@ public class RenderDataFactory45 {
}
}
private final Mesher blockMesher = new Mesher();
private final Mesher seondaryblockMesher = new Mesher();//Used for dual non-opaque geometry
@@ -214,6 +213,7 @@ public class RenderDataFactory45 {
private int prepareSectionData() {
final var sectionData = this.sectionData;
final var rawModelIds = this.modelMan._unsafeRawAccess();
int opaque = 0;
int notEmpty = 0;
int pureFluid = 0;
@@ -226,7 +226,10 @@ public class RenderDataFactory45 {
sectionData[i * 2] = (block&(0xFFL<<56))>>1;
sectionData[i * 2 + 1] = 0;
} else {
int modelId = this.modelMan.getModelId(Mapper.getBlockId(block));
int modelId = rawModelIds[Mapper.getBlockId(block)];
if (modelId == -1) {//Failed, so just return error
return Mapper.getBlockId(block)|(1<<31);
}
long modelMetadata = this.modelMan.getModelMetadataFromClientId(modelId);
sectionData[i * 2] = packPartialQuadData(modelId, block, modelMetadata);
@@ -239,8 +242,6 @@ public class RenderDataFactory45 {
partialFluid |= ModelQueries.containsFluid(modelMetadata) ? msk : 0;
}
//TODO: here also do bitmask of what neighboring sections are needed to compute (may be getting rid of this in future)
//Do increment here
i++;
@@ -332,7 +333,24 @@ public class RenderDataFactory45 {
}
}
//TODO: add neighbor face culling
private static boolean shouldMeshNonOpaqueBlockFace(int face, long quad, long meta, long neighborQuad, long neighborMeta) {
if (((quad^neighborQuad)&(0xFFFFL<<26))==0) return false;//This is a hack, if the neigbor and this are the same, dont mesh the face
if (!ModelQueries.faceExists(meta, face)) return false;//Dont mesh if no face
//if (ModelQueries.faceCanBeOccluded(meta, face)) //TODO: maybe enable this
if (ModelQueries.faceOccludes(neighborMeta, face^1)) return false;
return true;
}
private static void meshNonOpaqueFace(int face, long quad, long meta, long neighborQuad, long neighborMeta, Mesher mesher) {
if (shouldMeshNonOpaqueBlockFace(face, quad, meta, neighborQuad, neighborMeta)) {
mesher.putNext((long) (face&1) |
quad |
((ModelQueries.faceUsesSelfLighting(meta, face)?quad:neighborQuad) & (0xFFL << 55)));
} else {
mesher.skip(1);
}
}
private void generateYZOpaqueInnerGeometry(int axis) {
for (int layer = 0; layer < 31; layer++) {
this.blockMesher.auxiliaryPosition = layer;
@@ -668,35 +686,8 @@ public class RenderDataFactory45 {
long A = this.sectionData[idx * 2];
long B = this.sectionData[idx * 2+1];
long nA = this.sectionData[(idx+skipAmount)*2];
long nB = this.sectionData[(idx+skipAmount)*2 + 1];
//TODO: filtering
if (ModelQueries.faceExists(B, (axis<<1)|0) && (nA&(0xFFFFL<<26)) != (A&(0xFFFFL<<26))&& (!ModelQueries.faceOccludes(nB, (axis<<1)|0))) {
//ModelQueries.faceCanBeOccluded(B, (axis<<1)|(1))&&
//Example thing thats just wrong but as example
this.blockMesher.putNext((long) (false ? 0L : 1L) |
A |
((ModelQueries.faceUsesSelfLighting(B, (axis<<1)|1)?A:nA) & (0xFFL << 55))//(((0xFFL) & 0xFF) << 55)
);
} else {
this.blockMesher.skip(1);
}
nA = this.sectionData[(idx-skipAmount)*2];
nB = this.sectionData[(idx-skipAmount)*2 + 1];
if (ModelQueries.faceExists(B, (axis<<1)|1) && (nA&(0xFFFFL<<26)) != (A&(0xFFFFL<<26)) && (!ModelQueries.faceOccludes(nB, (axis<<1)|1))) {
//ModelQueries.faceCanBeOccluded(B, (axis<<1)|(0))&&
this.seondaryblockMesher.putNext((long) (true ? 0L : 1L) |
A |
((ModelQueries.faceUsesSelfLighting(B, (axis<<1)|0)?A:nA) & (0xFFL << 55))//(((0xFFL) & 0xFF) << 55)
);
} else {
this.seondaryblockMesher.skip(1);
}
meshNonOpaqueFace((axis<<1)|0, A, B, this.sectionData[(idx-skipAmount)*2], this.sectionData[(idx-skipAmount)*2+1], this.seondaryblockMesher);//-
meshNonOpaqueFace((axis<<1)|1, A, B, this.sectionData[(idx+skipAmount)*2], this.sectionData[(idx+skipAmount)*2+1], this.blockMesher);//+
}
}
this.blockMesher.endRow();
@@ -822,6 +813,7 @@ public class RenderDataFactory45 {
private final Mesher[] xAxisMeshers = new Mesher[32];
private final Mesher[] secondaryXAxisMeshers = new Mesher[32];
{
for (int i = 0; i < 32; i++) {
var mesher = new Mesher();
@@ -829,6 +821,15 @@ public class RenderDataFactory45 {
mesher.axis = 2;//X axis
this.xAxisMeshers[i] = mesher;
}
if (CHECK_NEIGHBOR_FACE_OCCLUSION) {
for (int i = 0; i < 32; i++) {
var mesher = new Mesher();
mesher.auxiliaryPosition = i;
mesher.axis = 2;//X axis
mesher.doAuxiliaryFaceOffset = false;
this.secondaryXAxisMeshers[i] = mesher;
}
}
}
private static final long X_I_MSK = 0x4210842108421L;
@@ -1318,7 +1319,191 @@ public class RenderDataFactory45 {
}
private void generateXNonOpaqueInnerGeometry() {
for (int y = 0; y < 32; y++) {
long sumA = 0;
long sumB = 0;
long sumC = 0;
int partialHasCount = -1;
int msk = 0;
for (int z = 0; z < 32; z++) {
msk = this.nonOpaqueMasks[y*32+z]&(~0x80000001);//Dont mesh the outer layer
//Always increment cause can do funny trick (i.e. -1 on skip amount)
sumA += X_I_MSK;
sumB += X_I_MSK;
sumC += X_I_MSK;
partialHasCount &= ~msk;
if (z == 30 && partialHasCount != 0) {//Hackfix for incremental count overflow issue
int cmsk = partialHasCount;
while (cmsk!=0) {
int index = Integer.numberOfTrailingZeros(cmsk);
cmsk &= ~Integer.lowestOneBit(cmsk);
this.xAxisMeshers[index].skip(31);
this.secondaryXAxisMeshers[index].skip(31);
}
//Clear the sum
sumA &= ~(Long.expand(Integer.toUnsignedLong(partialHasCount), X_I_MSK)*0x1F);
sumB &= ~(Long.expand(Integer.toUnsignedLong(partialHasCount)>>11, X_I_MSK)*0x1F);
sumC &= ~(Long.expand(Integer.toUnsignedLong(partialHasCount)>>22, X_I_MSK)*0x1F);
}
if (msk == 0) {
continue;
}
int iter = msk;
while (iter!=0) {
int index = Integer.numberOfTrailingZeros(iter);
iter &= ~Integer.lowestOneBit(iter);
int skipCount;//Compute the skip count
{//TODO: Branch-less
//Compute skip and clear
if (index<11) {
skipCount = (int) (sumA>>(index*5));
sumA &= ~(0x1FL<<(index*5));
} else if (index<22) {
skipCount = (int) (sumB>>((index-11)*5));
sumB &= ~(0x1FL<<((index-11)*5));
} else {
skipCount = (int) (sumC>>((index-22)*5));
sumC &= ~(0x1FL<<((index-22)*5));
}
skipCount &= 0x1F;
skipCount--;
}
var mesherA = this.xAxisMeshers[index];
var mesherB = this.secondaryXAxisMeshers[index];
if (skipCount != 0) {
mesherA.skip(skipCount);
mesherB.skip(skipCount);
}
{
int idx = index + (z * 32) + (y * 32 * 32);
long A = this.sectionData[idx*2];
long Am = this.sectionData[idx*2+1];
//Check and generate the mesh for both + and - faces
meshNonOpaqueFace(2<<1, A, Am, this.sectionData[(idx-1)*2], this.sectionData[(idx-1)*2+1], mesherB);//-
meshNonOpaqueFace((2<<1)|1, A, Am, this.sectionData[(idx+1)*2], this.sectionData[(idx+1)*2+1], mesherA);//+
}
}
}
//Need to skip the remaining entries in the skip array
{
msk = ~msk;//Invert the mask as we only need to set stuff that isnt 0
while (msk!=0) {
int index = Integer.numberOfTrailingZeros(msk);
msk &= ~Integer.lowestOneBit(msk);
int skipCount;
if (index < 11) {
skipCount = (int) (sumA>>(index*5));
} else if (index<22) {
skipCount = (int) (sumB>>((index-11)*5));
} else {
skipCount = (int) (sumC>>((index-22)*5));
}
skipCount &= 0x1F;
if (skipCount != 0) {
this.xAxisMeshers[index].skip(skipCount);
this.secondaryXAxisMeshers[index].skip(skipCount);
}
}
}
}
}
private static void dualMeshNonOpaqueOuterX(int side, long quad, long meta, int neighborAId, int neighborLight, long neighborAMeta, long neighborBQuad, long neighborBMeta, Mesher ma, Mesher mb) {
//side == 0 if is on 0 side and 1 if on 31 side
//TODO: Check (neighborAId!=0) && works oki
if ((neighborAId==0 && ModelQueries.faceExists(meta, ((2<<1)|0)^side))||(neighborAId!=0&&shouldMeshNonOpaqueBlockFace(((2<<1)|0)^side, quad, meta, ((long)neighborAId)<<26, neighborAMeta))) {
ma.putNext(((long)side)|
quad |
(ModelQueries.faceUsesSelfLighting(meta, ((2<<1)|0)^side)?quad:(((long)neighborLight)<<55))
);
} else {
ma.skip(1);
}
if (shouldMeshNonOpaqueBlockFace(((2<<1)|1)^side, quad, meta, neighborBQuad, neighborBMeta)) {
mb.putNext(((long)(side^1))|
quad |
((ModelQueries.faceUsesSelfLighting(meta, ((2<<1)|1)^side)?quad:neighborBQuad)&(0xFFL<<55))
);
} else {
mb.skip(1);
}
}
private void generateXNonOpaqueOuterGeometry() {
var npx = this.xAxisMeshers[0]; npx.finish();
var nnx = this.secondaryXAxisMeshers[0]; nnx.finish();
var ppx = this.xAxisMeshers[31]; ppx.finish();
var pnx = this.secondaryXAxisMeshers[31]; pnx.finish();
for (int y = 0; y < 32; y++) {
int skipA = 0;
int skipB = 0;
for (int z = 0; z < 32; z++) {
int i = y*32+z;
int msk = this.nonOpaqueMasks[i];
if ((msk & 1) != 0) {//-x
long neighborId = this.neighboringFaces[i];
int sidx = (i<<5) * 2;
long A = this.sectionData[sidx];
long Am = this.sectionData[sidx + 1];
int modelId = 0;
long nM = 0;
if (Mapper.getBlockId(neighborId) != 0) {//Not air
modelId = this.modelMan.getModelId(Mapper.getBlockId(neighborId));
nM = this.modelMan.getModelMetadataFromClientId(modelId);
}
nnx.skip(skipA);
npx.skip(skipA); skipA = 0;
dualMeshNonOpaqueOuterX(0, A, Am, modelId, Mapper.getLightId(neighborId), nM, this.sectionData[sidx+2], this.sectionData[sidx+3], nnx, npx);
} else {skipA++;}
if ((msk & (1<<31)) != 0) {//+x
long neighborId = this.neighboringFaces[i+32*32];
int sidx = (i*32+31) * 2;
long A = this.sectionData[sidx];
long Am = this.sectionData[sidx + 1];
int modelId = 0;
long nM = 0;
if (Mapper.getBlockId(neighborId) != 0) {//Not air
modelId = this.modelMan.getModelId(Mapper.getBlockId(neighborId));
nM = this.modelMan.getModelMetadataFromClientId(modelId);
}
pnx.skip(skipB);
ppx.skip(skipB); skipB = 0;
dualMeshNonOpaqueOuterX(1, A, Am, modelId, Mapper.getLightId(neighborId), nM, this.sectionData[sidx-2], this.sectionData[sidx-1], ppx, pnx);
} else {skipB++;}
}
nnx.skip(skipA);
npx.skip(skipA);
pnx.skip(skipB);
ppx.skip(skipB);
}
}
private void generateXFaces() {
@@ -1335,6 +1520,17 @@ public class RenderDataFactory45 {
for (var mesher : this.xAxisMeshers) {
mesher.finish();
}
if (CHECK_NEIGHBOR_FACE_OCCLUSION) {
this.generateXNonOpaqueInnerGeometry();
this.generateXNonOpaqueOuterGeometry();
for (var mesher : this.xAxisMeshers) {
mesher.finish();
}
for (var mesher : this.secondaryXAxisMeshers) {
mesher.finish();
}
}
}
//section is already acquired and gets released by the parent
@@ -1359,6 +1555,12 @@ public class RenderDataFactory45 {
mesher.reset();
mesher.doAuxiliaryFaceOffset = true;
}
if (CHECK_NEIGHBOR_FACE_OCCLUSION) {
for (var mesher : this.secondaryXAxisMeshers) {
mesher.reset();
mesher.doAuxiliaryFaceOffset = false;
}
}
}
this.minX = Integer.MAX_VALUE;
@@ -1375,6 +1577,9 @@ public class RenderDataFactory45 {
//Prepare everything
int neighborMsk = this.prepareSectionData();
if (neighborMsk>>31!=0) {//We failed to get everything so throw exception
throw new IdNotYetComputedException(neighborMsk&(~(1<<31)), true);
}
this.acquireNeighborData(section, neighborMsk);
try {