voxelThing/source/chunkRenderer.c
2025-05-26 20:59:26 -04:00

148 lines
6.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// chunkRenderer.c
// Rendering and meshing functions for voxelThing
// TODO: Memory is allocated dynamically in here but never freed.
// TODO: Chunk meshes need to be unloaded from the VRAM with UnloadMesh() when chunks are updated.
// For now new meshes are just added to the VRAM after each update...
#include <stdlib.h>
#include "raylib.h"
#include "blockTypes.h"
#include "atlasDefinitions.h"
#include "chunkRenderer.h"
#define TILE_SIZE 16
#define ATLAS_SIZE 256
#define ATLAS_TILES_PER_ROW (ATLAS_SIZE / TILE_SIZE)
/// Returns the UV coordinate for a given tile index and corner index (03),
/// assuming tiles are arranged in a grid in the texture atlas.
Vector2 GetTileUV(int tile, int corner) {
int tileX = tile % ATLAS_TILES_PER_ROW;
int tileY = tile / ATLAS_TILES_PER_ROW;
float u = (float)(tileX * TILE_SIZE) / ATLAS_SIZE;
float v = (float)(tileY * TILE_SIZE) / ATLAS_SIZE;
float duv = (float)TILE_SIZE / ATLAS_SIZE;
switch (corner) {
case 0: return (Vector2){ u, v };
case 1: return (Vector2){ u + duv, v };
case 2: return (Vector2){ u + duv, v + duv };
case 3: return (Vector2){ u, v + duv };
default: return (Vector2){ 0.0f, 0.0f }; // Should not happen
}
}
/// Generates a mesh for the given chunk by stitching together visible block faces.
Mesh GenerateChunkMesh(Chunk *chunk) {
const int maxFaces = CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z * 6;
const int maxVerts = maxFaces * 4; // 4 verts per face
const int maxIndices = maxFaces * 6; // 2 triangles per face
Vector3 *vertices = malloc(sizeof(Vector3) * maxVerts);
Vector3 *normals = malloc(sizeof(Vector3) * maxVerts);
Vector2 *texcoords = malloc(sizeof(Vector2) * maxVerts);
unsigned short *indices = malloc(sizeof(unsigned short) * maxIndices);
int vertCount = 0;
int indexCount = 0;
for (int x = 0; x < CHUNK_SIZE_X; x++) {
for (int y = 0; y < CHUNK_SIZE_Y; y++) {
for (int z = 0; z < CHUNK_SIZE_Z; z++) {
Block block = chunk->blocks[x][y][z];
if (block.type == 0) continue; // Skip air blocks
Vector3 min = { x, y, z };
Vector3 max = { x + 1.0f, y + 1.0f, z + 1.0f };
for (int dir = 0; dir < 6; dir++) {
if (!IsBlockFaceExposed(chunk, x, y, z, dir)) continue;
Vector3 face[4];
switch (dir) {
case 0: // -X
face[0] = (Vector3){ min.x, max.y, min.z };
face[1] = (Vector3){ min.x, max.y, max.z };
face[2] = (Vector3){ min.x, min.y, max.z };
face[3] = (Vector3){ min.x, min.y, min.z };
break;
case 1: // +X
face[0] = (Vector3){ max.x, max.y, max.z };
face[1] = (Vector3){ max.x, max.y, min.z };
face[2] = (Vector3){ max.x, min.y, min.z };
face[3] = (Vector3){ max.x, min.y, max.z };
break;
case 2: // -Y
face[0] = (Vector3){ min.x, min.y, max.z };
face[1] = (Vector3){ max.x, min.y, max.z };
face[2] = (Vector3){ max.x, min.y, min.z };
face[3] = (Vector3){ min.x, min.y, min.z };
break;
case 3: // +Y
face[0] = (Vector3){ min.x, max.y, min.z };
face[1] = (Vector3){ max.x, max.y, min.z };
face[2] = (Vector3){ max.x, max.y, max.z };
face[3] = (Vector3){ min.x, max.y, max.z };
break;
case 4: // -Z
face[0] = (Vector3){ max.x, max.y, min.z };
face[1] = (Vector3){ min.x, max.y, min.z };
face[2] = (Vector3){ min.x, min.y, min.z };
face[3] = (Vector3){ max.x, min.y, min.z };
break;
case 5: // +Z
face[0] = (Vector3){ min.x, max.y, max.z };
face[1] = (Vector3){ max.x, max.y, max.z };
face[2] = (Vector3){ max.x, min.y, max.z };
face[3] = (Vector3){ min.x, min.y, max.z };
break;
}
const BlockType *bt = GetBlockType(block.type);
int tileIndex = bt->faceTiles[dir];
Vector3 normal = {0};
switch (dir) {
case 0: normal = (Vector3){ -1.0f, 0.0f, 0.0f }; break;
case 1: normal = (Vector3){ 1.0f, 0.0f, 0.0f }; break;
case 2: normal = (Vector3){ 0.0f, -1.0f, 0.0f }; break;
case 3: normal = (Vector3){ 0.0f, 1.0f, 0.0f }; break;
case 4: normal = (Vector3){ 0.0f, 0.0f, -1.0f }; break;
case 5: normal = (Vector3){ 0.0f, 0.0f, 1.0f }; break;
}
for (int i = 0; i < 4; i++) {
vertices[vertCount] = face[i];
texcoords[vertCount] = GetTileUV(tileIndex, i);
normals[vertCount] = normal;
vertCount++;
}
indices[indexCount++] = vertCount - 4;
indices[indexCount++] = vertCount - 2;
indices[indexCount++] = vertCount - 3;
indices[indexCount++] = vertCount - 4;
indices[indexCount++] = vertCount - 1;
indices[indexCount++] = vertCount - 2;
}
}
}
}
Mesh mesh = {0};
mesh.vertexCount = vertCount;
mesh.triangleCount = indexCount / 3;
mesh.vertices = (float *)vertices;
mesh.texcoords = (float *)texcoords;
mesh.normals = (float *)normals;
mesh.indices = indices;
UploadMesh(&mesh, false);
return mesh;
}