// chunkRenderer.c // Rendering and meshing functions for voxelThing #include #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; }