// 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" float cameraYaw = 0; float cameraPitch = 0; 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)"; } int main(void) { // --- Screen setup --- const int screenWidth = 800; const int screenHeight = 600; InitWindow(screenWidth, screenHeight, "VoxelThing"); 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 = 45.0f; // Field of view camera.projection = CAMERA_PERSPECTIVE; // Use perspective projection SetTargetFPS(60); // --- Main game loop --- while (!WindowShouldClose()) { BeginDrawing(); ClearBackground(RAYWHITE); // --- 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) }; RaycastHit 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, RED); DrawFaceHighlight(hit.position, hit.normal); // Highlight the specific face hit } // Draw debug ray. camDir = Vector3Normalize(Vector3Subtract(camera.target, camera.position)); Vector3 rayEnd = Vector3Add(camera.position, Vector3Scale(camDir, 10.0f)); DrawLine3D(camera.position, rayEnd, PURPLE); Vector3 hitPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, hit.t)); DrawCubeWires(hitPoint, 0.05f, 0.05f, 0.05f, RED); EndMode3D(); Vector3 testPoint = Vector3Add(camera.position, Vector3Scale(camDir, 2.0f)); Vector2 projected = GetWorldToScreen(testPoint, camera); DrawCircleV(projected, 4, RED); // --- 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); 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 = BLOCK_SAND; 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; }