Untitled

mail@pastecode.io avatar
unknown
c_cpp
7 months ago
12 kB
2
Indexable
Never
#include "Chunk.h"

#include <vector>
#include <intrin.h>

#include "Engine.h"
#include "Config.h"

inline const int getBitPos(uint64_t& x) {
	unsigned long index;
	_BitScanForward64(&index, x);
	return (int) index;
}

inline const int getAxisIndex(int axis, int a, int b, int c) {
	if (axis == 0) return a * CS_P2 + c * CS_P + b;
	if (axis == 1) return c * CS_P2 + a * CS_P + b;
	return a * CS_P2 + b * CS_P + c;
}

inline const uint32_t getQuad(uint8_t x, uint8_t y, uint8_t z, uint8_t w, uint8_t l) {
	return x | y << 6 | z << 12 | w << 18 | l << 24;
}

inline void updateBounds(uint8_t* bounds, uint8_t x, uint8_t y, uint8_t z, uint8_t xW, uint8_t yW, uint8_t zW) {
	bounds[0] = x < bounds[0] ? x : bounds[0];
	bounds[3] = x + xW > bounds[3] ? x + xW : bounds[3];

	bounds[2] = y < bounds[2] ? y : bounds[2];
	bounds[5] = y + yW > bounds[5] ? y + yW : bounds[5];

	bounds[1] = z < bounds[1] ? z : bounds[1];
	bounds[4] = z + zW > bounds[4] ? z + zW : bounds[4];
}

struct TranslucentQuad {
	uint32_t data1;
	uint32_t data2;

	TranslucentQuad(uint32_t data1, uint32_t data2) : data1(data1), data2(data2) {}
};

struct MeshData {
	std::vector<uint32_t> allQuadData;
	int opaqueFaceSize[6] { 0 };

	std::vector<TranslucentQuad> translucentData;
	uint64_t translucentSplits[3] { 0 };
	int visibleTranslucentQuads = 0;

	std::vector<uint32_t> paletteData;

	uint8_t bounds[6] { CS, CS, CS, 0, 0, 0 };
};

inline uint8_t getQuadDepth(uint32_t data, glm::ivec3 cameraPos) {
	uint8_t axis = (data >> 9) & 3;
	uint8_t face = (data >> 8) & 1;

	int depths[3] {
		((data >> 11) & 63) - cameraPos.x,
		((data >> 23) & 63) - cameraPos.z,
		((data >> 17) & 63) - cameraPos.y
	};

	uint8_t totalDepth = abs(depths[0]) + abs(depths[1]) + abs(depths[2]) + 1;
	if (depths[axis] * ((1 - face) * 2 - 1) < 0) totalDepth = 0;

	return totalDepth;
}

void sortTranslucentQuads(MeshData& mesh, glm::ivec3 cameraPos) {
	int depthCounts[191] { 0 };

	for (int i = 0; i < mesh.translucentData.size(); i++) {
		uint8_t depth = getQuadDepth(mesh.translucentData[i].data2, cameraPos);
		depthCounts[depth]++;
	}

	for (int i = 189; i >= 0; i--) {
		depthCounts[i] += depthCounts[i + 1];
	}
	mesh.visibleTranslucentQuads = depthCounts[1];

	int baseIndex = mesh.allQuadData.size();
	mesh.allQuadData.resize(mesh.allQuadData.size() + mesh.translucentData.size() * 2);

	for (int i = 0; i < mesh.translucentData.size(); i++) {
		uint8_t depth = getQuadDepth(mesh.translucentData[i].data2, cameraPos);
		int relIndex = --depthCounts[depth];

		mesh.allQuadData[baseIndex + relIndex * 2] = mesh.translucentData[i].data1;
		mesh.allQuadData[baseIndex + relIndex * 2 + 1] = mesh.translucentData[i].data2;
	}
}

MeshData doMeshing(VoxelData* vData) {
	MeshData mesh;
	uint8_t paletteRedirect[256] { 0 };

	constexpr uint64_t P_MASK = ~(1ull << 63 | 1);
	for (int axis = 0; axis < 3; axis++) {
		for (int a = 0; a < CS; a++) {
			for (int b = 0; b < CS; b++) {
				uint64_t currOpaqueAxis = vData->opaqueAxis[(b + 1) + (a + 1) * CS_P + axis * CS_P2];

				vData->rowFaceMasks[b + a * CS + (axis * 2) * CS_2] = (currOpaqueAxis & ~vData->opaqueAxis[(b + 1) + a * CS_P + axis * CS_P2] & P_MASK) >> 1;
				uint64_t prevTranslucentRow = (vData->translucentAxis[(b + 1) + (a + 1) * CS_P + axis * CS_P2] & P_MASK) >> 1;
				while (prevTranslucentRow) {
					int c = getBitPos(prevTranslucentRow);
					prevTranslucentRow &= ~(1ULL << c);

					uint8_t type = vData->typeData[getAxisIndex(axis, b + 1, c + 1, a + 1)];
					bool typeIsOpaque = type == 0 || ((vData->palette.data[type] >> 24) & 0xFF) == 0xFF;
					if (typeIsOpaque) continue;

					uint8_t prevType = vData->typeData[getAxisIndex(axis, b + 1, c + 1, a)];
					bool prevTypeIsOpaque = ((vData->palette.data[prevType] >> 24) & 0xFF) == 0xFF;
					if (prevTypeIsOpaque) continue;

					if (type == prevType) continue;

					vData->rowFaceMasks[b + a * CS + (axis * 2) * CS_2] |= 1ull << c;
					mesh.translucentSplits[axis] |= 1ull << a;
				}

				vData->rowFaceMasks[b + a * CS + (axis * 2 + 1) * CS_2] = (currOpaqueAxis & ~vData->opaqueAxis[(b + 1) + (a + 2) * CS_P + axis * CS_P2] & P_MASK) >> 1;
				uint64_t currTranslucentRow = (vData->translucentAxis[(b + 1) + (a + 2) * CS_P + axis * CS_P2] & P_MASK) >> 1;
				while (currTranslucentRow) {
					int c = getBitPos(currTranslucentRow);
					currTranslucentRow &= ~(1ULL << c);

					uint8_t type = vData->typeData[getAxisIndex(axis, b + 1, c + 1, a + 1)];
					bool typeIsOpaque = type == 0 || ((vData->palette.data[type] >> 24) & 0xFF) == 0xFF;
					if (typeIsOpaque) continue;

					uint8_t nextType = vData->typeData[getAxisIndex(axis, b + 1, c + 1, a + 2)];
					bool nextTypeIsOpaque = ((vData->palette.data[nextType] >> 24) & 0xFF) == 0xFF;
					if (nextTypeIsOpaque) continue;

					if (type == nextType) continue;

					vData->rowFaceMasks[b + a * CS + (axis * 2 + 1) * CS_2] |= 1ull << c;
					mesh.translucentSplits[axis] |= 1ull << (a + 1);
				}
			}
		}
	}

	uint8_t forwardMerged[CS];
	memset(forwardMerged, 1, CS);
	for (int face = 0; face < 6; face++) {
		int axis = face / 2;

		mesh.opaqueFaceSize[face] = mesh.allQuadData.size();
		int opaqueFaceCount = 0;

		uint64_t translucentForward = mesh.translucentSplits[~axis & 1];
		uint64_t translucentRight = mesh.translucentSplits[~axis & 2];
		for (int layer = 0; layer < CS; layer++) {
			int bitsLocation = layer * CS + face * CS_2;
			for (int forward = 0; forward < CS; forward++) {
				uint64_t bitsHere = vData->rowFaceMasks[forward + bitsLocation];
				uint64_t bitsNext = forward + 1 < CS ? vData->rowFaceMasks[(forward + 1) + bitsLocation] : 0;

				uint8_t rightMerged = 1;
				while (bitsHere) {
					unsigned long bitPos;
					_BitScanForward64(&bitPos, bitsHere);

					uint8_t type = vData->typeData[getAxisIndex(axis, forward + 1, bitPos + 1, layer + 1)];
					bool isOpaque = ((vData->palette.data[type] >> 24) & 0xFF) == 0xFF;

					if ((bitsNext >> bitPos & 1) && !(!isOpaque && (translucentForward >> (forward + 1) & 1)) && type == vData->typeData[getAxisIndex(axis, forward + 2, bitPos + 1, layer + 1)]) {
						forwardMerged[bitPos]++;
						bitsHere &= ~(1ull << bitPos);
						continue;
					}

					for (int right = bitPos + 1; right < CS; right++) {
						if (!(bitsHere >> right & 1) || forwardMerged[bitPos] != forwardMerged[right] || (!isOpaque && (translucentRight >> right & 1)) || type != vData->typeData[getAxisIndex(axis, forward + 1, right + 1, layer + 1)]) break;
						forwardMerged[right] = 1;
						rightMerged++;
					}
					bitsHere &= ~((1ull << (bitPos + rightMerged)) - 1);

					uint8_t meshFront = forward - forwardMerged[bitPos] + 1;
					uint8_t meshLeft = bitPos;
					uint8_t meshUp = layer + (face & 1);

					uint8_t meshWidth = rightMerged;
					uint8_t meshLength = forwardMerged[bitPos];

					forwardMerged[bitPos] = 1;
					rightMerged = 1;

					uint32_t quad;
					switch (face) {
					case 0:
					case 1:
						quad = getQuad(meshUp, meshLeft, meshFront, meshWidth, meshLength);
						updateBounds(mesh.bounds, meshUp, meshLeft, meshFront, 0, meshWidth, meshLength);
						break;
					case 2:
					case 3:
						quad = getQuad(meshFront, meshLeft, meshUp, meshLength, meshWidth);
						updateBounds(mesh.bounds, meshFront, meshLeft, meshUp, meshLength, meshWidth, 0);
						break;
					case 4:
					case 5:
						quad = getQuad(meshLeft, meshUp, meshFront, meshLength, meshWidth);
						updateBounds(mesh.bounds, meshLeft, meshUp, meshFront, meshWidth, 0, meshLength);
						break;
					}

					if (paletteRedirect[type] == 0) {
						mesh.paletteData.push_back(vData->palette.data[type]);
						paletteRedirect[type] = mesh.paletteData.size();
					}
					type = paletteRedirect[type] - 1;

					if (isOpaque) {
						int sharedIndex = (opaqueFaceCount / 4) * 5 + mesh.opaqueFaceSize[face];
						if (mesh.allQuadData.size() <= sharedIndex) mesh.allQuadData.push_back(0);

						mesh.allQuadData[sharedIndex] |= type << ((opaqueFaceCount & 3) * 8);
						mesh.allQuadData.push_back(quad);
						opaqueFaceCount++;
					} else {
						uint8_t quadX = (face < 2 ? meshUp : (face < 4 ? meshFront : meshLeft)) + (face != 0);
						uint8_t quadZ = ((face >= 2 && face < 4) ? meshUp : meshFront) + (face != 2);
						uint8_t quadY = (face < 4 ? meshLeft : meshUp) + (face != 4);

						uint8_t quadMappedX = __popcnt64(mesh.translucentSplits[0] & ((1ULL << quadX) - 1));
						uint8_t quadMappedZ = __popcnt64(mesh.translucentSplits[1] & ((1ULL << quadZ) - 1));
						uint8_t quadMappedY = __popcnt64(mesh.translucentSplits[2] & ((1ULL << quadY) - 1));

						mesh.translucentData.emplace_back(quad, quadMappedZ << 23 | quadMappedY << 17 | quadMappedX << 11 | face << 8 | type);
					}
				}
			}
		}

		mesh.opaqueFaceSize[face] = mesh.allQuadData.size() - mesh.opaqueFaceSize[face];
	}

	mesh.bounds[3] -= mesh.bounds[0];
	mesh.bounds[4] -= mesh.bounds[1];
	mesh.bounds[5] -= mesh.bounds[2];

	return mesh;
}

void uploadChunkRenderData(GenerationChunk* chunk, MeshData& mesh, glm::ivec3& prevCamPosition) {
	chunk->renderMemID = gEngine.graphics.chunkPool.allocate();
	uint32_t* chunkRenderMem = gEngine.graphics.chunkPool.getIDAddress(chunk->renderMemID);

	chunkRenderMem[0] = chunk->getX() * CS;
	chunkRenderMem[1] = chunk->getY() * CS;
	chunkRenderMem[2] = chunk->getZ() * CS;
	chunkRenderMem[3] = chunk->getLayer();

	chunkRenderMem[4] = chunk->bounds[0] | chunk->bounds[1] << 6 | chunk->bounds[2] << 12;
	chunkRenderMem[5] = chunk->bounds[3] | chunk->bounds[5] << 6 | chunk->bounds[4] << 12;

	chunkRenderMem[6] = -1;

	chunkRenderMem[7] = mesh.opaqueFaceSize[0] | mesh.opaqueFaceSize[1] << 16;
	chunkRenderMem[8] = mesh.opaqueFaceSize[2] | mesh.opaqueFaceSize[3] << 16;
	chunkRenderMem[9] = mesh.opaqueFaceSize[4] | mesh.opaqueFaceSize[5] << 16;

	chunkRenderMem[10] = mesh.allQuadData.size() - mesh.translucentData.size() * 2 - mesh.paletteData.size();
	chunkRenderMem[11] = mesh.visibleTranslucentQuads;
	chunkRenderMem[12] = mesh.translucentData.size();

	chunkRenderMem[13] = mesh.translucentSplits[0];
	chunkRenderMem[14] = mesh.translucentSplits[0] >> 32;
	chunkRenderMem[15] = mesh.translucentSplits[1];
	chunkRenderMem[16] = mesh.translucentSplits[1] >> 32;
	chunkRenderMem[17] = mesh.translucentSplits[2];
	chunkRenderMem[18] = mesh.translucentSplits[2] >> 32;

	chunkRenderMem[19] = prevCamPosition.x | (prevCamPosition.y << 6) | (prevCamPosition.z << 12);

	chunkRenderMem[20] = mesh.allQuadData.size() - mesh.paletteData.size();
}

bool GenerationChunk::setupRenderData() {
	MeshData mesh = doMeshing(vData);

	glm::ivec3 prevCamPosition = glm::ivec3(0, 0, 0);
	if (mesh.translucentData.size() > 0) {
		glm::ivec3 cameraPos = getBoundPos(gEngine.camera.getAtomicPos());

		prevCamPosition.x = __popcnt64(mesh.translucentSplits[0] & ((1ULL << (cameraPos.x + 1)) - 1));
		prevCamPosition.z = __popcnt64(mesh.translucentSplits[1] & ((1ULL << (cameraPos.z + 1)) - 1));
		prevCamPosition.y = __popcnt64(mesh.translucentSplits[2] & ((1ULL << (cameraPos.y + 1)) - 1));

		sortTranslucentQuads(mesh, prevCamPosition);
	}

	if (mesh.allQuadData.size() == 0) return false;

	mesh.allQuadData.insert(mesh.allQuadData.end(), mesh.paletteData.begin(), mesh.paletteData.end());

	for (int face = 0; face < 6; face++) {
		bounds[face] = mesh.bounds[face];
		renderFlags |= ((mesh.opaqueFaceSize[face] > 0) << face);
	}

	renderFlags |= (mesh.translucentData.size() > 0) << 6;
	quadCount = mesh.allQuadData.size();

	uploadChunkRenderData(this, mesh, prevCamPosition);

	gEngine.graphics.quadPool.allocate(renderMemID, mesh.allQuadData.data(), mesh.allQuadData.size());

	return true;
}
Leave a Comment