const std = @import("std"); const print = std.debug.print; const sdl = @import("sdl.zig"); const vec3 = @import("vec3.zig"); const Vec3 = vec3.Vec3; const Color = vec3.Color; const Point3 = vec3.Point3; const Ray = @import("ray.zig").Ray; // From: https://github.com/Nelarius/weekend-raytracer-zig/blob/master/src/main.zig // See https://github.com/zig-lang/zig/issues/565 // SDL_video.h:#define SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED_DISPLAY(0) // SDL_video.h:#define SDL_WINDOWPOS_UNDEFINED_DISPLAY(X) (SDL_WINDOWPOS_UNDEFINED_MASK|(X)) // SDL_video.h:#define SDL_WINDOWPOS_UNDEFINED_MASK 0x1FFF0000u const SDL_WINDOWPOS_UNDEFINED = @bitCast(c_int, sdl.c.SDL_WINDOWPOS_UNDEFINED_MASK); const fps = 60; fn hitSphere(center: Point3, radius: f32, ray: Ray) bool { const ssr = ray.origin.sub(center); // Sphere-space ray, (A - C) in book const a = Vec3.dot(ray.direction, ray.direction); const b = 2.0 * Vec3.dot(ssr, ray.direction); const c = Vec3.dot(ssr, ssr) - (radius * radius); const discriminant = b * b - 4 * a * c; return discriminant > 0; } fn rayColor(ray: Ray) Color { if (hitSphere(Point3{ .x = 0, .y = 0, .z = -1 }, 0.5, ray)) { return Color{ .x = 1, .y = 0, .z = 0 }; } const unitDirection = vec3.unitVector(ray.direction); const t = 0.5 * (unitDirection.y + 1.0); const white = Color{ .x = 1.0, .y = 1.0, .z = 1.0 }; const blue = Color{ .x = 0.5, .y = 0.7, .z = 1.0 }; return white.mul(1.0 - t).add(blue.mul(t)); } pub fn main() anyerror!void { if (sdl.c.SDL_Init(sdl.c.SDL_INIT_VIDEO) != 0) { std.log.err("Unable to initialize SDL: {}", .{sdl.c.SDL_GetError()}); return error.SDLInitializationFailed; } defer sdl.c.SDL_Quit(); // Image const aspectRatio: f32 = 16.0 / 9.0; const imageWidth = 400; const imageHeight = @floatToInt(usize, imageWidth / aspectRatio); // Camera const viewportHeight = 2.0; const viewportWidth = @floatToInt(usize, viewportHeight * aspectRatio); const focalLength = 1.0; const origin = Vec3{}; const horizontal = Vec3{ .x = viewportWidth }; const vertical = Vec3{ .y = viewportHeight }; const lowerLeftCorner = origin.sub(horizontal.div(2)).sub(vertical.div(2)).sub(Vec3{ .z = focalLength }); const window = sdl.c.SDL_CreateWindow( "Raytracing in One Weekend", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, imageWidth, imageHeight, sdl.c.SDL_WINDOW_OPENGL ) orelse { std.log.err("Unable to create window: {}", .{sdl.c.SDL_GetError()}); return error.SDLInitializationFailed; }; const surface = sdl.c.SDL_GetWindowSurface(window) orelse { std.log.err("Unable to get window surface: {}", .{sdl.c.SDL_GetError()}); return error.SDLInitializationFailed; }; { _ = sdl.c.SDL_LockSurface(surface); var j: usize = 0; while (j < imageHeight) { var i: usize = 0; while (i < imageWidth) { const u = @intToFloat(f32, i) / @intToFloat(f32, (imageWidth - 1)); // SDL coordinate system is flipped compared to the raytracer const v = @intToFloat(f32, (imageHeight - 1) - j) / @intToFloat(f32, (imageHeight - 1)); const r = Ray{ .origin = origin, .direction = lowerLeftCorner.add(horizontal.mul(u).add(vertical.mul(v).sub(origin))), }; const pixelColor = rayColor(r); sdl.setSurfacePixel(surface, i, j, pixelColor); i += 1; } j += 1; } defer sdl.c.SDL_UnlockSurface(surface); } if (sdl.c.SDL_UpdateWindowSurface(window) != 0) { std.log.err("Error updating window surface: {}", .{sdl.c.SDL_GetError()}); return error.SDLUpdateWindowFailed; } var running = true; while (running) { var event: sdl.c.SDL_Event = undefined; while (sdl.c.SDL_PollEvent(&event) != 0) { switch (event.@"type") { sdl.c.SDL_QUIT => { running = false; }, else => {}, } } sdl.c.SDL_Delay(1000 / fps); } }