145 lines
6.0 KiB
C
145 lines
6.0 KiB
C
// chunkRenderer.c
|
||
// Rendering and meshing functions for voxelThing
|
||
|
||
#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 (0–3),
|
||
// 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, true); // True here tells the function to free the CPU side allocated memory.
|
||
return mesh;
|
||
}
|
||
|