voxelThing/source/voxelThing.c

198 lines
7.4 KiB
C

// voxelThing.c
// A voxel chunk rendering doodad written in C with Raylib
// External libraries
#include "raylib.h"
#include "raymath.h"
#include "rlgl.h"
#include "stdio.h"
// Project files
#include "chunkStructures.h"
#include "chunkRenderer.h"
#include "blockTypes.h"
#include "playerController.h"
#include "chunkGenerator.h"
// Bunch of global variables to clean up later.
float cameraYaw = 0;
float cameraPitch = 0;
bool paused = false;
RaycastHit hit;
int blockSelection = BLOCK_SAND;
// Random helper function for returning what direction you're facing.'
const char* GetCompassDirection(float yaw) {
yaw = fmodf(yaw * RAD2DEG + 360.0f, 360.0f);
if (yaw < 22.5f || yaw >= 337.5f) return "South (+Z)";
if (yaw < 67.5f) return "Southwest (+X+Z)";
if (yaw < 112.5f) return "West (+X)";
if (yaw < 157.5f) return "Northwest (+X-Z)";
if (yaw < 202.5f) return "North (-Z)";
if (yaw < 247.5f) return "Northeast (-X-Z)";
if (yaw < 292.5f) return "East (-X)";
return "Southeast (-X+Z)";
}
// Another random helper function, this time for checking if a Vector3 is non-zero.
static inline bool Vector3IsNonZero(Vector3 v) {
return v.x != 0.0f || v.y != 0.0f || v.z != 0.0f;
}
int main(void) {
// --- Screen setup ---
int screenWidth = 800;
int screenHeight = 600;
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(screenWidth, screenHeight, "VoxelThing");
SetExitKey(-1);
DisableCursor(); // Lock mouse to window for FPS-style camera
// --- World generation ---
Chunk chunk;
GenerateFlatChunk(&chunk);
PlaceTreeAt(&chunk, 8, 7, 8);
Mesh chunkMesh = GenerateChunkMesh(&chunk);
// --- Load textures and materials ---
Texture2D atlas = LoadTexture("assets/TextureAtlas.png");
Material mat = LoadMaterialDefault();
mat.maps[MATERIAL_MAP_DIFFUSE].texture = atlas;
// --- Initialize camera ---
Camera3D camera = { 0 };
camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Initial camera position
camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Looking toward origin
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Y-up world
camera.fovy = 90.0f; // Field of view
camera.projection = CAMERA_PERSPECTIVE; // Use perspective projection
SetTargetFPS(60);
// --- Main game loop ---
while (!WindowShouldClose()) {
screenWidth = GetScreenWidth();
screenHeight = GetScreenHeight();
BeginDrawing();
ClearBackground(RAYWHITE);
// --- Handle jumping to fullscreen mode with F11 ---
if (IsKeyPressed(KEY_F11)) {
ToggleFullscreen();
Vector2 center = { GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f };
SetMousePosition(center.x, center.y);
}
// --- Handle pausing ---
if (IsKeyPressed(KEY_ESCAPE)) {
paused = !paused;
if (paused) EnableCursor();
else DisableCursor();
}
// --- Handle selecting blocks ---
if (IsKeyPressed(KEY_ONE)) blockSelection = BLOCK_STONE;
if (IsKeyPressed(KEY_TWO)) blockSelection = BLOCK_DIRT;
if (IsKeyPressed(KEY_THREE)) blockSelection = BLOCK_GRASS;
if (IsKeyPressed(KEY_FOUR)) blockSelection = BLOCK_SAND;
if (IsKeyPressed(KEY_FIVE)) blockSelection = BLOCK_GRAVEL;
if (IsKeyPressed(KEY_SIX)) blockSelection = BLOCK_LOG;
if (IsKeyPressed(KEY_SEVEN)) blockSelection = BLOCK_LEAF;
if (IsKeyPressed(KEY_EIGHT)) blockSelection = BLOCK_PLANK;
if (!paused) {
// --- Update camera and direction ---
UpdateFreeCamera(&camera, 10.0f, &cameraYaw, &cameraPitch); // Move camera with user input
// --- Raycasting from screen center ---
Vector2 screenCenter = { screenWidth / 2.0f, screenHeight / 2.0f };
// This is where we grab the ray...
// Ray ray = GetMouseRay(screenCenter, camera);
Vector3 camDir = {
cosf(cameraPitch) * sinf(cameraYaw),
sinf(cameraPitch),
cosf(cameraPitch) * cosf(cameraYaw)
};
Ray ray = {
.position = camera.position,
.direction = Vector3Normalize(camDir)
};
hit = RaycastChunk(&chunk, ray.position, ray.direction, 10.0f);
// --- Begin 3D rendering ---
BeginMode3D(camera);
DrawMesh(chunkMesh, mat, MatrixIdentity());
if (hit.hit) {
// Draw a wireframe cube where the ray hit
DrawCubeWires(Vector3Add(hit.position, (Vector3){0.5f, 0.5f, 0.5f}), 1.02f, 1.02f, 1.02f, BLACK);
//DrawFaceHighlight(hit.position, hit.normal); // Highlight the specific face hit
}
// Draw a lil debug cube where the player is looking.
//Vector3 hitPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, hit.t));
//DrawCubeWires(hitPoint, 0.05f, 0.05f, 0.05f, RED);
EndMode3D();
// --- Draw crosshair in screen center ---
DrawLine(screenWidth/2 - 5, screenHeight/2, screenWidth/2 + 5, screenHeight/2, DARKGRAY);
DrawLine(screenWidth/2, screenHeight/2 - 5, screenWidth/2, screenHeight/2 + 5, DARKGRAY);
// -- Draw debug info ---
DrawText(TextFormat("Facing: %s", GetCompassDirection(cameraYaw)), 10, 10, 20, DARKGRAY);
DrawText(TextFormat("Yaw: %.1f° Pitch: %.1f°", cameraYaw * RAD2DEG, cameraPitch * RAD2DEG), 10, 30, 20, GRAY);
}
// --- Draw pause menu if paused ---
if (paused) {
DrawRectangle(0, 0, screenWidth, screenHeight, Fade(DARKGRAY, 0.5f));
DrawText("Paused", screenWidth / 2 - MeasureText("Paused", 40) / 2, screenHeight / 2 - 20, 40, RAYWHITE);
DrawText("Press ESC to resume", screenWidth / 2 - MeasureText("Press ESC to resume", 20) / 2, screenHeight / 2 + 30, 20, LIGHTGRAY);
}
EndDrawing();
// TODO: Shoudn't all this block handling be handled in playerController.c?
// --- Handle block removal (left click) ---
if (hit.hit && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
chunk.blocks[(int)hit.position.x][(int)hit.position.y][(int)hit.position.z].type = BLOCK_AIR;
chunkMesh = GenerateChunkMesh(&chunk); // Rebuild mesh after change
}
// --- Handle block placement (right click) ---
if (hit.hit && IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
int px = (int)(hit.position.x + hit.normal.x);
int py = (int)(hit.position.y + hit.normal.y);
int pz = (int)(hit.position.z + hit.normal.z);
// Bounds check
if (px >= 0 && px < CHUNK_SIZE_X &&
py >= 0 && py < CHUNK_SIZE_Y &&
pz >= 0 && pz < CHUNK_SIZE_Z) {
chunk.blocks[px][py][pz].type = blockSelection;
chunkMesh = GenerateChunkMesh(&chunk);
printf("Hit at (%f %f %f), normal (%f %f %f), placing at (%d %d %d)\n",
hit.position.x, hit.position.y, hit.position.z,
hit.normal.x, hit.normal.y, hit.normal.z,
px, py, pz);
}
}
}
// --- Cleanup ---
UnloadTexture(atlas);
UnloadMesh(chunkMesh);
UnloadMaterial(mat);
CloseWindow();
return 0;
}