diff options
| -rw-r--r-- | src/main.zig | 42 | ||||
| -rw-r--r-- | src/rc.zig | 47 | ||||
| -rw-r--r-- | src/rtw/hittable.zig | 99 |
3 files changed, 110 insertions, 78 deletions
diff --git a/src/main.zig b/src/main.zig index ee899b7..ad2273b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,6 +3,8 @@ const debug = std.debug; const math = std.math; const ArrayList = std.ArrayList; +const Rc = @import("rc.zig").Rc; + const rtw = @import("rtw.zig"); const Ray = rtw.ray.Ray; @@ -269,9 +271,9 @@ fn generateSimpleLightScene(rng: Random, allocator: anytype) !Hittable { try hittable_objects.append(makeSphere(.{ .x = 0, .y = 2, .z = 0 }, 2, mat2)); const light = Texture.makeSolid(rgb(4, 4, 4)); - var mat3 = try allocator.create(Material); + var mat3 = try Rc(Material).init(allocator); - mat3.* = .{ .diffuse_light = .{ .emit = light } }; + mat3.get_mut().* = .{ .diffuse_light = .{ .emit = light } }; try hittable_objects.append(.{ .xyRect = .{ .x0 = 3.0, .x1 = 5.0, .y0 = 1.0, .y1 = 3.0, .k = -2.0, .material = mat3 } }); @@ -281,33 +283,25 @@ fn generateSimpleLightScene(rng: Random, allocator: anytype) !Hittable { fn generateCornellBox(allocator: anytype) !Hittable { var hittable_objects = ArrayList(Hittable).init(allocator); - var red = try allocator.create(Material); - var white = try allocator.create(Material); - var white2 = try allocator.create(Material); - var white3 = try allocator.create(Material); - var white4 = try allocator.create(Material); - var white5 = try allocator.create(Material); - var green = try allocator.create(Material); - var light = try allocator.create(Material); - - red.* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.65, 0.05, 0.05)) } }; - white.* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.73, 0.73, 0.73)) } }; - white2.* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.73, 0.73, 0.73)) } }; - white3.* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.73, 0.73, 0.73)) } }; - white4.* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.73, 0.73, 0.73)) } }; - white5.* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.73, 0.73, 0.73)) } }; - green.* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.12, 0.45, 0.15)) } }; - light.* = .{ .diffuse_light = .{ .emit = Texture.makeSolid(rgb(15, 15, 15)) } }; + var red = try Rc(Material).init(allocator); + var white = try Rc(Material).init(allocator); + var green = try Rc(Material).init(allocator); + var light = try Rc(Material).init(allocator); + + red.get_mut().* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.65, 0.05, 0.05)) } }; + white.get_mut().* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.73, 0.73, 0.73)) } }; + green.get_mut().* = .{ .diffuse = .{ .albedo = Texture.makeSolid(rgb(0.12, 0.45, 0.15)) } }; + light.get_mut().* = .{ .diffuse_light = .{ .emit = Texture.makeSolid(rgb(15, 15, 15)) } }; try hittable_objects.append(.{ .yzRect = .{ .y0 = 0, .y1 = 555, .z0 = 0, .z1 = 555, .k = 555, .material = green } }); try hittable_objects.append(.{ .yzRect = .{ .y0 = 0, .y1 = 555, .z0 = 0, .z1 = 555, .k = 0, .material = red } }); try hittable_objects.append(.{ .xzRect = .{ .x0 = 213, .x1 = 343, .z0 = 227, .z1 = 332, .k = 554, .material = light } }); try hittable_objects.append(.{ .xzRect = .{ .x0 = 0, .x1 = 555, .z0 = 0, .z1 = 555, .k = 0, .material = white } }); - try hittable_objects.append(.{ .xzRect = .{ .x0 = 0, .x1 = 555, .z0 = 0, .z1 = 555, .k = 555, .material = white2 } }); - try hittable_objects.append(.{ .xyRect = .{ .x0 = 0, .x1 = 555, .y0 = 0, .y1 = 555, .k = 555, .material = white3 } }); + try hittable_objects.append(.{ .xzRect = .{ .x0 = 0, .x1 = 555, .z0 = 0, .z1 = 555, .k = 555, .material = white.clone() } }); + try hittable_objects.append(.{ .xyRect = .{ .x0 = 0, .x1 = 555, .y0 = 0, .y1 = 555, .k = 555, .material = white.clone() } }); - try hittable_objects.append(try Hittable.makeBox(.{ .x = 130, .y = 0, .z = 65 }, .{ .x = 295, .y = 165, .z = 230 }, white4, allocator)); - try hittable_objects.append(try Hittable.makeBox(.{ .x = 265, .y = 0, .z = 295 }, .{ .x = 430, .y = 330, .z = 460 }, white5, allocator)); + try hittable_objects.append(try Hittable.makeBox(.{ .x = 130, .y = 0, .z = 65 }, .{ .x = 295, .y = 165, .z = 230 }, white.clone(), allocator)); + try hittable_objects.append(try Hittable.makeBox(.{ .x = 265, .y = 0, .z = 295 }, .{ .x = 430, .y = 330, .z = 460 }, white.clone(), allocator)); return .{ .list = .{ .objects = hittable_objects } }; } @@ -380,7 +374,7 @@ pub fn main() !void { image_height = 600; samples_per_pixel = 200; } - defer world.deinit(allocator); + defer world.deinit(); // Camera const camera = Camera.init( diff --git a/src/rc.zig b/src/rc.zig new file mode 100644 index 0000000..0c16023 --- /dev/null +++ b/src/rc.zig @@ -0,0 +1,47 @@ +const std = @import("std"); + +pub fn Rc(comptime T: type) type { + const Cell = struct { + value: T, + ref_count: usize, + }; + + return struct { + const Self = @This(); + + allocator: std.mem.Allocator, + ptr: *Cell, + + pub fn init(allocator: std.mem.Allocator) !Self { + const ptr = try allocator.create(Cell); + ptr.ref_count = 1; + return .{ + .allocator = allocator, + .ptr = ptr, + }; + } + + pub fn deinit(self: *const Self) void { + self.ptr.ref_count -= 1; + if (self.ptr.ref_count == 0) { + self.allocator.destroy(self.ptr); + } + } + + pub fn clone(self: *const Self) Self { + self.ptr.ref_count += 1; + return .{ + .allocator = self.allocator, + .ptr = self.ptr, + }; + } + + pub fn get(self: *const Self) *const T { + return &self.ptr.value; + } + + pub fn get_mut(self: *Self) *T { + return &self.ptr.value; + } + }; +} diff --git a/src/rtw/hittable.zig b/src/rtw/hittable.zig index 8c9f6f0..422f868 100644 --- a/src/rtw/hittable.zig +++ b/src/rtw/hittable.zig @@ -4,6 +4,8 @@ const math = std.math; const pi = math.pi; const ArrayList = std.ArrayList; +const Rc = @import("../rc.zig").Rc; + const Ray = @import("ray.zig").Ray; const Vec3 = @import("vec.zig").Vec3; const Point3 = @import("vec.zig").Point3; @@ -42,7 +44,7 @@ pub const Hittable = union(HittableTag) { yzRect: YzRect, box: Box, - pub fn makeBox(p0: Point3, p1: Point3, material: *const Material, allocator: anytype) !Hittable { + pub fn makeBox(p0: Point3, p1: Point3, material: Rc(Material), allocator: anytype) !Hittable { return .{ .box = try Box.init(p0, p1, material, allocator) }; } @@ -72,16 +74,16 @@ pub const Hittable = union(HittableTag) { }; } - pub fn deinit(h: *const Hittable, allocator: anytype) void { + pub fn deinit(h: *const Hittable) void { return switch (h.*) { - HittableTag.sphere => |sphere| sphere.deinit(allocator), - HittableTag.movingSphere => |movingSphere| movingSphere.deinit(allocator), - HittableTag.list => |list| list.deinit(allocator), - HittableTag.bvhNode => |node| node.deinit(allocator), - HittableTag.xyRect => |rect| rect.deinit(allocator), - HittableTag.xzRect => |rect| rect.deinit(allocator), - HittableTag.yzRect => |rect| rect.deinit(allocator), - HittableTag.box => |box| box.deinit(allocator), + HittableTag.sphere => |sphere| sphere.deinit(), + HittableTag.movingSphere => |movingSphere| movingSphere.deinit(), + HittableTag.list => |list| list.deinit(), + HittableTag.bvhNode => |node| node.deinit(), + HittableTag.xyRect => |rect| rect.deinit(), + HittableTag.xzRect => |rect| rect.deinit(), + HittableTag.yzRect => |rect| rect.deinit(), + HittableTag.box => |box| box.deinit(), }; } }; @@ -89,7 +91,7 @@ pub const Hittable = union(HittableTag) { const Sphere = struct { center: Point3, radius: f64, - material: *const Material, + material: Rc(Material), fn hit(sphere: Sphere, r: Ray, t_min: f64, t_max: f64, record: *HitRecord) bool { const oc = r.origin.sub(sphere.center); @@ -124,7 +126,7 @@ const Sphere = struct { record.normal = outward_normal.mul(-1.0); } Sphere.getSphereUv(outward_normal, &record.u, &record.v); - record.material = sphere.material; + record.material = sphere.material.get(); return true; } @@ -148,8 +150,8 @@ const Sphere = struct { v.* = theta / pi; } - fn deinit(sphere: *const Sphere, allocator: anytype) void { - allocator.destroy(sphere.material); + fn deinit(sphere: *const Sphere) void { + sphere.material.deinit(); } }; @@ -159,7 +161,7 @@ const MovingSphere = struct { time0: f64, time1: f64, radius: f64, - material: *const Material, + material: Rc(Material), fn hit(sphere: MovingSphere, r: Ray, t_min: f64, t_max: f64, record: *HitRecord) bool { const center_ = sphere.center(r.time); @@ -194,7 +196,7 @@ const MovingSphere = struct { } else { record.normal = outward_normal.mul(-1.0); } - record.material = sphere.material; + record.material = sphere.material.get(); return true; } @@ -219,8 +221,8 @@ const MovingSphere = struct { return sphere.center0.add(sphere.center1.sub(sphere.center0).mul((t - sphere.time0) / (sphere.time1 - sphere.time0))); } - fn deinit(sphere: *const MovingSphere, allocator: anytype) void { - allocator.destroy(sphere.material); + fn deinit(sphere: *const MovingSphere) void { + sphere.material.deinit(); } }; @@ -258,9 +260,9 @@ const HittableList = struct { return true; } - fn deinit(list: *const HittableList, allocator: anytype) void { + fn deinit(list: *const HittableList) void { for (list.objects.items) |object| { - object.deinit(allocator); + object.deinit(); } list.objects.deinit(); } @@ -345,9 +347,9 @@ const BvhNode = struct { return true; } - fn deinit(node: *const BvhNode, allocator: anytype) void { - _ = node; - _ = allocator; + fn deinit(node: *const BvhNode) void { + node.left.deinit(); + node.right.deinit(); } }; @@ -357,7 +359,7 @@ const XyRect = struct { y0: f64, y1: f64, k: f64, - material: *const Material, + material: Rc(Material), pub fn hit(rect: XyRect, r: Ray, t_min: f64, t_max: f64, record: *HitRecord) bool { const t = (rect.k - r.origin.z) / r.dir.z; @@ -373,7 +375,7 @@ const XyRect = struct { record.u = (x - rect.x0) / (rect.x1 - rect.x0); record.v = (y - rect.y0) / (rect.y1 - rect.y0); record.t = t; - record.material = rect.material; + record.material = rect.material.get(); record.p = r.at(t); const outward_normal = Vec3{ .x = 0, .y = 0, .z = 1 }; @@ -399,8 +401,8 @@ const XyRect = struct { return true; } - pub fn deinit(rect: *const XyRect, allocator: anytype) void { - allocator.destroy(rect.material); + pub fn deinit(rect: *const XyRect) void { + rect.material.deinit(); } }; @@ -410,7 +412,7 @@ const XzRect = struct { z0: f64, z1: f64, k: f64, - material: *const Material, + material: Rc(Material), pub fn hit(rect: XzRect, r: Ray, t_min: f64, t_max: f64, record: *HitRecord) bool { const t = (rect.k - r.origin.y) / r.dir.y; @@ -426,7 +428,7 @@ const XzRect = struct { record.u = (x - rect.x0) / (rect.x1 - rect.x0); record.v = (z - rect.z0) / (rect.z1 - rect.z0); record.t = t; - record.material = rect.material; + record.material = rect.material.get(); record.p = r.at(t); const outward_normal = Vec3{ .x = 0, .y = 1, .z = 0 }; @@ -452,8 +454,8 @@ const XzRect = struct { return true; } - pub fn deinit(rect: *const XzRect, allocator: anytype) void { - allocator.destroy(rect.material); + pub fn deinit(rect: *const XzRect) void { + rect.material.deinit(); } }; @@ -463,7 +465,7 @@ const YzRect = struct { z0: f64, z1: f64, k: f64, - material: *const Material, + material: Rc(Material), pub fn hit(rect: YzRect, r: Ray, t_min: f64, t_max: f64, record: *HitRecord) bool { const t = (rect.k - r.origin.x) / r.dir.x; @@ -479,7 +481,7 @@ const YzRect = struct { record.u = (y - rect.y0) / (rect.y1 - rect.y0); record.v = (z - rect.z0) / (rect.z1 - rect.z0); record.t = t; - record.material = rect.material; + record.material = rect.material.get(); record.p = r.at(t); const outward_normal = Vec3{ .x = 1, .y = 0, .z = 0 }; @@ -505,8 +507,8 @@ const YzRect = struct { return true; } - pub fn deinit(rect: *const YzRect, allocator: anytype) void { - allocator.destroy(rect.material); + pub fn deinit(rect: *const YzRect) void { + rect.material.deinit(); } }; @@ -515,26 +517,15 @@ const Box = struct { max: Point3, sides: HittableList, - pub fn init(p0: Point3, p1: Point3, material: *const Material, allocator: anytype) !Box { + pub fn init(p0: Point3, p1: Point3, material: Rc(Material), allocator: anytype) !Box { var sides = ArrayList(Hittable).init(allocator); - var mat2 = try allocator.create(Material); - var mat3 = try allocator.create(Material); - var mat4 = try allocator.create(Material); - var mat5 = try allocator.create(Material); - var mat6 = try allocator.create(Material); - mat2.* = material.*; - mat3.* = material.*; - mat4.* = material.*; - mat5.* = material.*; - mat6.* = material.*; - try sides.append(.{ .xyRect = .{ .x0 = p0.x, .x1 = p1.x, .y0 = p0.y, .y1 = p1.y, .k = p1.z, .material = material } }); - try sides.append(.{ .xyRect = .{ .x0 = p0.x, .x1 = p1.x, .y0 = p0.y, .y1 = p1.y, .k = p0.z, .material = mat2 } }); - try sides.append(.{ .xzRect = .{ .x0 = p0.x, .x1 = p1.x, .z0 = p0.z, .z1 = p1.z, .k = p1.y, .material = mat3 } }); - try sides.append(.{ .xzRect = .{ .x0 = p0.x, .x1 = p1.x, .z0 = p0.z, .z1 = p1.z, .k = p0.y, .material = mat4 } }); - try sides.append(.{ .yzRect = .{ .y0 = p0.y, .y1 = p1.y, .z0 = p0.z, .z1 = p1.z, .k = p1.x, .material = mat5 } }); - try sides.append(.{ .yzRect = .{ .y0 = p0.y, .y1 = p1.y, .z0 = p0.z, .z1 = p1.z, .k = p0.x, .material = mat6 } }); + try sides.append(.{ .xyRect = .{ .x0 = p0.x, .x1 = p1.x, .y0 = p0.y, .y1 = p1.y, .k = p0.z, .material = material.clone() } }); + try sides.append(.{ .xzRect = .{ .x0 = p0.x, .x1 = p1.x, .z0 = p0.z, .z1 = p1.z, .k = p1.y, .material = material.clone() } }); + try sides.append(.{ .xzRect = .{ .x0 = p0.x, .x1 = p1.x, .z0 = p0.z, .z1 = p1.z, .k = p0.y, .material = material.clone() } }); + try sides.append(.{ .yzRect = .{ .y0 = p0.y, .y1 = p1.y, .z0 = p0.z, .z1 = p1.z, .k = p1.x, .material = material.clone() } }); + try sides.append(.{ .yzRect = .{ .y0 = p0.y, .y1 = p1.y, .z0 = p0.z, .z1 = p1.z, .k = p0.x, .material = material.clone() } }); return .{ .min = p0, @@ -559,7 +550,7 @@ const Box = struct { return true; } - pub fn deinit(box: *const Box, allocator: anytype) void { - box.sides.deinit(allocator); + pub fn deinit(box: *const Box) void { + box.sides.deinit(); } }; |
