Skip to content

Commit

Permalink
Inherit materials when parsing groups
Browse files Browse the repository at this point in the history
  • Loading branch information
SinclaM committed Jul 18, 2023
1 parent 2ca21a4 commit 182d9b9
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub fn main() !void {
inline for (scenes_to_render) |scene| {
// Use an arena for the scene building, because I'm too lazy
// to individually free the (relatively few) allocations that will
// be made (e.g. for `Pattern`s) in `parseScene`.
// be made (e.g. for `Pattern`s and `Group`s) in `parseScene`.
//
// Don't use an arena for the main rendering allocator, though,
// since there are many small allocs and frees made for intersections
Expand Down
58 changes: 37 additions & 21 deletions src/parser/parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ fn PatternConfig(comptime T: type) type {
fn MaterialConfig(comptime T: type) type {
return struct {
pattern: PatternConfig(T),
ambient: T = 0.1,
diffuse: T = 0.9,
specular: T = 0.9,
shininess: T = 200.0,
reflective: T = 0.0,
transparency: T = 0.0,
@"refractive-index": T = 1.0,
ambient: ?T = null,
diffuse: ?T = null,
specular: ?T = null,
shininess: ?T = null,
reflective: ?T = null,
transparency: ?T = null,
@"refractive-index": ?T = null,
};
}

Expand Down Expand Up @@ -206,24 +206,36 @@ fn parsePattern(comptime T: type, allocator: Allocator, pattern: PatternConfig(T
return pat;
}

fn parseMaterial(comptime T: type, allocator: Allocator, material: MaterialConfig(T)) !Material(T) {
var mat = Material(T).new();
fn parseMaterial(
comptime T: type, allocator: Allocator, material: MaterialConfig(T), inherited_material: ?Material(T)
) !Material(T) {
var mat = inherited_material orelse Material(T).new();
mat.pattern = try parsePattern(T, allocator, material.pattern);
mat.ambient = material.ambient;
mat.diffuse = material.diffuse;
mat.specular = material.specular;
mat.shininess = material.shininess;
mat.reflective = material.reflective;
mat.transparency = material.transparency;
mat.refractive_index = material.@"refractive-index";

mat.ambient = material.ambient orelse mat.ambient;
mat.diffuse = material.diffuse orelse mat.diffuse;
mat.specular = material.specular orelse mat.specular;
mat.shininess = material.shininess orelse mat.shininess;
mat.reflective = material.reflective orelse mat.reflective;
mat.transparency = material.transparency orelse mat.transparency;
mat.refractive_index = material.@"refractive-index" orelse mat.refractive_index;

return mat;
}

// `parseObject` must return `!*Shape(T)` instead of `!Shape(T)` so that internal
// pointers in groups are not invalidated by moving the struct.
fn parseObject(comptime T: type, allocator: Allocator, object: ObjectConfig(T)) !*Shape(T) {
fn parseObject(
comptime T: type, allocator: Allocator, object: ObjectConfig(T), inherited_material: ?Material(T)
) !*Shape(T) {
const material = if (object.material) |mat| blk: {
break :blk try parseMaterial(T, allocator, mat, inherited_material);
} else blk: {
break :blk inherited_material;
};

var shape = try allocator.create(Shape(T));

switch (object.@"type") {
.sphere => shape.* = Shape(T).sphere(),
.plane => shape.* = Shape(T).plane(),
Expand All @@ -243,8 +255,12 @@ fn parseObject(comptime T: type, allocator: Allocator, object: ObjectConfig(T))
.group => |children| {
shape.* = Shape(T).group(allocator);

if (material) |mat| {
shape.material = mat;
}

for (children) |child| {
var s = try parseObject(T, allocator, child);
var s = try parseObject(T, allocator, child, shape.material);
try shape.addChild(s);
}
}
Expand All @@ -256,8 +272,8 @@ fn parseObject(comptime T: type, allocator: Allocator, object: ObjectConfig(T))
try shape.setTransform(parseTransform(T, transform));
}

if (object.material) |material| {
shape.material = try parseMaterial(T, allocator, material);
if (material) |mat| {
shape.material = mat;
}

return shape;
Expand Down Expand Up @@ -309,7 +325,7 @@ pub fn parseScene(
var world = World(T).new(allocator);

for (parsed.value.objects) |object| {
try world.objects.append((try parseObject(T, allocator, object)).*);
try world.objects.append((try parseObject(T, allocator, object, null)).*);
}

for (parsed.value.lights) |light| {
Expand Down
3 changes: 2 additions & 1 deletion src/raytracer/shapes/shape.zig
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ pub fn Shape(comptime T: type) type {
/// Adds `child` to a group.
///
/// Assumes `self.variant` is a group.
pub fn addChild(self: *Shape(T), child: *Shape(T)) !void {
pub fn addChild(self: *Self, child: *Self) !void {
child.parent = self;

try self.variant.group.children.append(child);
}

Expand Down

0 comments on commit 182d9b9

Please sign in to comment.