Multi thread
This commit is contained in:
parent
1f5e37de40
commit
62e4438b7d
226
src/camera.zig
226
src/camera.zig
@ -17,16 +17,77 @@ const unit_vector = mat_math.unit_vector;
|
|||||||
const length = mat_math.length;
|
const length = mat_math.length;
|
||||||
const cross = mat_math.cross;
|
const cross = mat_math.cross;
|
||||||
|
|
||||||
|
const AtomicOrder = @import("std").builtin.AtomicOrder;
|
||||||
|
const Thread = std.Thread;
|
||||||
|
const Semaphore = std.Thread.Semaphore;
|
||||||
|
|
||||||
|
const Pixel = struct {
|
||||||
|
w: usize,
|
||||||
|
h: usize,
|
||||||
|
color: vec3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ThreadInfo = struct {
|
||||||
|
thread_index: usize,
|
||||||
|
semaphore_ptr: *Semaphore,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolution parameters
|
||||||
|
const aspect_ratio: f64 = 16.0 / 9.0;
|
||||||
|
const image_width: usize = 2560; // Possible 128, 256, 512, 1024, 1280, 1920, 2560, 3840, 7680
|
||||||
|
const image_height: usize = image_width / aspect_ratio;
|
||||||
|
const samples_per_pixel = 500;
|
||||||
|
const max_depth = 50;
|
||||||
|
|
||||||
|
const n_threads_to_spawn = 100;
|
||||||
|
|
||||||
|
var completion_count: usize = 0;
|
||||||
|
var next_entry_to_do: usize = 0;
|
||||||
|
var entry_count: usize = 0;
|
||||||
|
var entry_buffer: [image_width * image_height]Pixel = undefined;
|
||||||
|
|
||||||
|
var _camera: *const Camera = undefined;
|
||||||
|
|
||||||
|
fn addWork(semaphore_ptr: *Semaphore) void {
|
||||||
|
const entry_index = @atomicLoad(usize, &entry_count, AtomicOrder.seq_cst);
|
||||||
|
|
||||||
|
// SeqCst guarantees that the msg write above is visible before the entry_count write below can be seen.
|
||||||
|
@atomicStore(usize, &entry_count, entry_index + 1, AtomicOrder.seq_cst);
|
||||||
|
|
||||||
|
semaphore_ptr.post(); // Wake up all threads
|
||||||
|
}
|
||||||
|
|
||||||
|
fn doWork(info: *ThreadInfo) void {
|
||||||
|
while (true) {
|
||||||
|
if (@atomicLoad(usize, &next_entry_to_do, AtomicOrder.seq_cst) < @atomicLoad(usize, &entry_count, AtomicOrder.seq_cst)) {
|
||||||
|
const entry_index = @atomicRmw(usize, &next_entry_to_do, .Add, 1, AtomicOrder.seq_cst);
|
||||||
|
const pixel = entry_buffer[entry_index];
|
||||||
|
|
||||||
|
var pixel_color = vec3{ 0, 0, 0 };
|
||||||
|
for (0.._camera.samples_per_pixel) |_| {
|
||||||
|
const r = _camera.get_ray(pixel.h, pixel.w);
|
||||||
|
pixel_color += ray_color(r, _camera.max_depth, _camera.world);
|
||||||
|
}
|
||||||
|
entry_buffer[entry_index].color = pixel_color;
|
||||||
|
|
||||||
|
_ = @atomicRmw(usize, &completion_count, .Add, 1, AtomicOrder.seq_cst);
|
||||||
|
} else {
|
||||||
|
info.semaphore_ptr.wait(); // Put all threads to sleep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const Camera = struct {
|
pub const Camera = struct {
|
||||||
aspect_ratio: f64,
|
aspect_ratio: f64,
|
||||||
image_width: i64,
|
image_width: usize,
|
||||||
samples_per_pixel: i64,
|
samples_per_pixel: usize,
|
||||||
max_depth: i64,
|
max_depth: usize,
|
||||||
vfov: f64,
|
vfov: f64,
|
||||||
defocus_angle: f64,
|
defocus_angle: f64,
|
||||||
focus_dist: f64,
|
focus_dist: f64,
|
||||||
|
world: *const HittableList,
|
||||||
|
|
||||||
image_height: i64,
|
image_height: usize,
|
||||||
center: vec3,
|
center: vec3,
|
||||||
pixel_samples_scale: f64,
|
pixel_samples_scale: f64,
|
||||||
pixel00_loc: vec3,
|
pixel00_loc: vec3,
|
||||||
@ -39,11 +100,72 @@ pub const Camera = struct {
|
|||||||
v: vec3,
|
v: vec3,
|
||||||
w: vec3,
|
w: vec3,
|
||||||
|
|
||||||
pub fn new() Camera {
|
pub fn render(self: Camera, writer: anytype) !void {
|
||||||
const aspect_ratio: f64 = 16.0 / 9.0;
|
_camera = &self;
|
||||||
const image_width: i64 = 512; // Possible 128, 256, 512, 1024, 1280, 1920, 2560, 3840, 7680
|
|
||||||
const samples_per_pixel = 50;
|
var semaphore = Semaphore{};
|
||||||
const max_depth = 10;
|
var infos: [n_threads_to_spawn]ThreadInfo = undefined;
|
||||||
|
for (&infos, 0..) |*info, thread_index| {
|
||||||
|
info.thread_index = thread_index;
|
||||||
|
info.semaphore_ptr = &semaphore;
|
||||||
|
const handle = try Thread.spawn(.{}, doWork, .{info});
|
||||||
|
handle.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the PPM header
|
||||||
|
try writer.print("P3\n{} {}\n255\n", .{ self.image_width, self.image_height });
|
||||||
|
|
||||||
|
for (0..self.image_width) |w| {
|
||||||
|
for (0..self.image_height) |h| {
|
||||||
|
entry_buffer[w * self.image_height + h] = Pixel{ .w = w, .h = h, .color = vec3{ -1, -1, -1 } };
|
||||||
|
addWork(&semaphore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print("\nStarting rendering using {d} threads\n", .{n_threads_to_spawn});
|
||||||
|
while (entry_count != @atomicLoad(usize, &completion_count, AtomicOrder.seq_cst)) {
|
||||||
|
pbar(@atomicLoad(usize, &completion_count, AtomicOrder.seq_cst), self.image_height * self.image_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pbar(100, 100);
|
||||||
|
|
||||||
|
for (0..self.image_height) |h| {
|
||||||
|
for (0..self.image_width) |w| {
|
||||||
|
try writeColor(self.get_pixel_color(w, h) * toVec3(self.pixel_samples_scale), writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pixel_color(self: Camera, w: usize, h: usize) vec3 {
|
||||||
|
const pixel = entry_buffer[w * self.image_height + h];
|
||||||
|
if ((pixel.w == w) and (pixel.h == h)) {
|
||||||
|
return pixel.color;
|
||||||
|
}
|
||||||
|
print("Pixel with different coordinates w: {}, h: {}, pixel.w: {}, pixel.h: {}", .{ w, h, pixel.w, pixel.h });
|
||||||
|
return vec3{ 0, 0, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ray(self: Camera, h: usize, w: usize) Ray {
|
||||||
|
// Construct a camera ray originating from the origin and directed at randomly sampled
|
||||||
|
// point around the pixel location i, j.
|
||||||
|
|
||||||
|
const offset = sample_square();
|
||||||
|
const pixel_sample = self.pixel00_loc +
|
||||||
|
(toVec3(h) + toVec3(offset[0])) * self.pixel_delta_v +
|
||||||
|
(toVec3(w) + toVec3(offset[1])) * self.pixel_delta_u;
|
||||||
|
|
||||||
|
const ray_origin = if (self.defocus_angle <= 0) self.center else self.defocus_disk_sample();
|
||||||
|
const ray_direction = pixel_sample - ray_origin;
|
||||||
|
|
||||||
|
return Ray{ .orig = ray_origin, .dir = ray_direction };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn defocus_disk_sample(self: Camera) vec3 {
|
||||||
|
const p = random_in_unit_disk();
|
||||||
|
return self.center + (toVec3(p[0]) * self.defocus_disk_u) + (toVec3(p[1]) * self.defocus_disk_v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(world: *const HittableList) Camera {
|
||||||
const vfov = 20;
|
const vfov = 20;
|
||||||
const lookfrom = vec3{ 13, 2, 3 };
|
const lookfrom = vec3{ 13, 2, 3 };
|
||||||
const lookat = vec3{ 0, 0, 0 };
|
const lookat = vec3{ 0, 0, 0 };
|
||||||
@ -53,7 +175,6 @@ pub const Camera = struct {
|
|||||||
const focus_dist = 10;
|
const focus_dist = 10;
|
||||||
|
|
||||||
const camera_center = lookfrom;
|
const camera_center = lookfrom;
|
||||||
const image_height: i64 = image_width / aspect_ratio;
|
|
||||||
const pixel_samples_scale = 1.0 / @as(f64, @floatFromInt(samples_per_pixel));
|
const pixel_samples_scale = 1.0 / @as(f64, @floatFromInt(samples_per_pixel));
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
@ -76,7 +197,7 @@ pub const Camera = struct {
|
|||||||
const viewport_upper_left = camera_center - toVec3(focus_dist) * w - viewport_u / toVec3(2) - viewport_v / toVec3(2);
|
const viewport_upper_left = camera_center - toVec3(focus_dist) * w - viewport_u / toVec3(2) - viewport_v / toVec3(2);
|
||||||
const pixel00_loc = viewport_upper_left + toVec3(0.5) * (pixel_delta_u + pixel_delta_v);
|
const pixel00_loc = viewport_upper_left + toVec3(0.5) * (pixel_delta_u + pixel_delta_v);
|
||||||
|
|
||||||
const defocus_radius = focus_dist * @tan(utils.degrees_to_radians(defocus_angle / 2));
|
const defocus_radius = focus_dist * @tan(utils.degrees_to_radians(defocus_angle / 2.0));
|
||||||
const defocus_disk_u = u * toVec3(defocus_radius);
|
const defocus_disk_u = u * toVec3(defocus_radius);
|
||||||
const defocus_disk_v = v * toVec3(defocus_radius);
|
const defocus_disk_v = v * toVec3(defocus_radius);
|
||||||
|
|
||||||
@ -88,6 +209,7 @@ pub const Camera = struct {
|
|||||||
.vfov = vfov,
|
.vfov = vfov,
|
||||||
.focus_dist = focus_dist,
|
.focus_dist = focus_dist,
|
||||||
.defocus_angle = defocus_angle,
|
.defocus_angle = defocus_angle,
|
||||||
|
.world = world,
|
||||||
|
|
||||||
.u = u,
|
.u = u,
|
||||||
.v = v,
|
.v = v,
|
||||||
@ -103,50 +225,32 @@ pub const Camera = struct {
|
|||||||
.pixel_delta_v = pixel_delta_v,
|
.pixel_delta_v = pixel_delta_v,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: Camera, world: HittableList, writer: anytype) !void {
|
|
||||||
// Write the PPM header
|
|
||||||
try writer.print("P3\n{} {}\n255\n", .{ self.image_width, self.image_height });
|
|
||||||
|
|
||||||
// Write the pixel data
|
|
||||||
for (0..@as(usize, @intCast(self.image_height))) |i| {
|
|
||||||
const h = @as(i64, @intCast(i));
|
|
||||||
pbar(h, self.image_height);
|
|
||||||
for (0..@as(usize, @intCast(self.image_width))) |j| {
|
|
||||||
const w = @as(i64, @intCast(j));
|
|
||||||
|
|
||||||
var pixel_color = vec3{ 0, 0, 0 };
|
|
||||||
for (0..@as(usize, @intCast(self.samples_per_pixel))) |_| {
|
|
||||||
const r = self.get_ray(h, w);
|
|
||||||
pixel_color += ray_color(r, self.max_depth, world);
|
|
||||||
}
|
|
||||||
|
|
||||||
try writeColor(pixel_color * toVec3(self.pixel_samples_scale), writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_ray(self: Camera, h: i64, w: i64) Ray {
|
|
||||||
// Construct a camera ray originating from the origin and directed at randomly sampled
|
|
||||||
// point around the pixel location i, j.
|
|
||||||
|
|
||||||
const offset = sample_square();
|
|
||||||
const pixel_sample = self.pixel00_loc +
|
|
||||||
(toVec3((@as(f64, @floatFromInt(h))) + offset[0]) * self.pixel_delta_v) +
|
|
||||||
(toVec3((@as(f64, @floatFromInt(w))) + offset[1]) * self.pixel_delta_u);
|
|
||||||
|
|
||||||
const ray_origin = if (self.defocus_angle <= 0) self.center else self.defocus_disk_sample();
|
|
||||||
const ray_direction = pixel_sample - ray_origin;
|
|
||||||
|
|
||||||
return Ray{ .orig = ray_origin, .dir = ray_direction };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn defocus_disk_sample(self: Camera) vec3 {
|
|
||||||
const p = random_in_unit_disk();
|
|
||||||
return self.center + (toVec3(p[0]) * self.defocus_disk_u) + (toVec3(p[1]) * self.defocus_disk_v);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn splitPixels(allocator: std.mem.Allocator, pixels: []Pixel, num_sublists: usize) ![][]Pixel {
|
||||||
|
const len = pixels.len;
|
||||||
|
if (num_sublists == 0 or num_sublists > len) {
|
||||||
|
return error.InvalidNumberOfSublists;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sublist_size = len / num_sublists;
|
||||||
|
const remainder = len % num_sublists;
|
||||||
|
|
||||||
|
var result = try allocator.alloc([]Pixel, num_sublists);
|
||||||
|
var start: usize = 0;
|
||||||
|
|
||||||
|
for (0..num_sublists) |i| {
|
||||||
|
var end = start + sublist_size;
|
||||||
|
if (i < remainder) {
|
||||||
|
end += 1;
|
||||||
|
}
|
||||||
|
result[i] = pixels[start..end];
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
fn random_in_unit_disk() vec3 {
|
fn random_in_unit_disk() vec3 {
|
||||||
while (true) {
|
while (true) {
|
||||||
const p = vec3{ utils.rand_mm(-1, 1), utils.rand_mm(-1, 1), 0 };
|
const p = vec3{ utils.rand_mm(-1, 1), utils.rand_mm(-1, 1), 0 };
|
||||||
@ -155,7 +259,7 @@ fn random_in_unit_disk() vec3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ray_color(ray: Ray, depth: i64, world: HittableList) vec3 {
|
fn ray_color(ray: Ray, depth: usize, world: *const HittableList) vec3 {
|
||||||
if (depth <= 0) {
|
if (depth <= 0) {
|
||||||
return vec3{ 0, 0, 0 };
|
return vec3{ 0, 0, 0 };
|
||||||
}
|
}
|
||||||
@ -186,6 +290,10 @@ fn writeColor(color: vec3, writer: anytype) !void {
|
|||||||
var g_float = color[1];
|
var g_float = color[1];
|
||||||
var b_float = color[2];
|
var b_float = color[2];
|
||||||
|
|
||||||
|
if ((r_float < -0.999) or (g_float < -0.999) or (b_float < -0.999)) {
|
||||||
|
@panic("-1 color detected");
|
||||||
|
}
|
||||||
|
|
||||||
r_float = utils.linear_to_gamma(r_float);
|
r_float = utils.linear_to_gamma(r_float);
|
||||||
g_float = utils.linear_to_gamma(g_float);
|
g_float = utils.linear_to_gamma(g_float);
|
||||||
b_float = utils.linear_to_gamma(b_float);
|
b_float = utils.linear_to_gamma(b_float);
|
||||||
@ -198,11 +306,11 @@ fn writeColor(color: vec3, writer: anytype) !void {
|
|||||||
try writer.print("{} {} {}\n", .{ r, g, b });
|
try writer.print("{} {} {}\n", .{ r, g, b });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pbar(value: i64, max: i64) void {
|
fn pbar(value: usize, max: usize) void {
|
||||||
const used_char = "-";
|
const used_char = "-";
|
||||||
const number_of_char = 60;
|
const number_of_char = 60;
|
||||||
const percent_done: i64 = if (value == max - 1) 100 else @divFloor(value * 100, max);
|
const percent_done: usize = if (value == max - 1) 100 else @divFloor(value * 100, max);
|
||||||
const full_char: i64 = @divFloor(number_of_char * percent_done, 100);
|
const full_char: usize = @divFloor(number_of_char * percent_done, 100);
|
||||||
|
|
||||||
print("\r|", .{});
|
print("\r|", .{});
|
||||||
|
|
||||||
@ -215,7 +323,9 @@ fn pbar(value: i64, max: i64) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print("| {}%", .{percent_done});
|
print("| {}% |", .{percent_done});
|
||||||
|
print(" {} ", .{value});
|
||||||
|
print("/ {}", .{max});
|
||||||
|
|
||||||
if (percent_done == 100) {
|
if (percent_done == 100) {
|
||||||
print("\n", .{});
|
print("\n", .{});
|
||||||
|
57
src/main.zig
57
src/main.zig
@ -32,21 +32,20 @@ pub fn main() !void {
|
|||||||
defer file.close();
|
defer file.close();
|
||||||
var buffered_writer = std.io.bufferedWriter(file.writer());
|
var buffered_writer = std.io.bufferedWriter(file.writer());
|
||||||
const writer = buffered_writer.writer();
|
const writer = buffered_writer.writer();
|
||||||
const camera = Camera.new();
|
|
||||||
|
|
||||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
defer arena.deinit();
|
errdefer arena.deinit();
|
||||||
const alloc = arena.allocator();
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
const world = try generateRandomScene(alloc);
|
const world = try generateRandomScene(alloc);
|
||||||
|
const camera = Camera.new(&world);
|
||||||
|
|
||||||
const start_time: i64 = std.time.milliTimestamp();
|
const start_time: i64 = std.time.milliTimestamp();
|
||||||
try camera.render(world, &writer);
|
try camera.render(&writer);
|
||||||
const end_time: i64 = std.time.milliTimestamp();
|
const end_time: i64 = std.time.milliTimestamp();
|
||||||
const total_time: f64 = @as(f64, @floatFromInt(end_time - start_time)) / 1000;
|
const total_time: f64 = @as(f64, @floatFromInt(end_time - start_time)) / 1000;
|
||||||
|
|
||||||
print("Rendering took {} s\n", .{total_time});
|
print("Rendering took {d} s\n\n", .{total_time});
|
||||||
print("Potential FPS: {}\n", .{1 / total_time});
|
|
||||||
|
|
||||||
// Flush the buffered writer to ensure all data is written to the file
|
// Flush the buffered writer to ensure all data is written to the file
|
||||||
try buffered_writer.flush();
|
try buffered_writer.flush();
|
||||||
@ -98,6 +97,45 @@ pub fn run_open_image() !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generateSameScene(alloc: std.mem.Allocator) !HittableList {
|
||||||
|
var spheres = std.ArrayList(Hittable).init(alloc);
|
||||||
|
|
||||||
|
// Ground sphere
|
||||||
|
try spheres.append(.{
|
||||||
|
.sphere = Sphere{
|
||||||
|
.center = vec3{ 0, -1000, 0 },
|
||||||
|
.radius = 1000,
|
||||||
|
.material = Material{ .lambertian = Lambertian{ .albedo = vec3{ 0.5, 0.5, 0.5 } } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Three large spheres
|
||||||
|
try spheres.append(.{
|
||||||
|
.sphere = Sphere{
|
||||||
|
.center = vec3{ 0, 1, 0 },
|
||||||
|
.radius = 1.0,
|
||||||
|
.material = Material{ .dielectric = Dielectric{ .refraction_index = 1.5 } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try spheres.append(.{
|
||||||
|
.sphere = Sphere{
|
||||||
|
.center = vec3{ -4, 1, 0 },
|
||||||
|
.radius = 1.0,
|
||||||
|
.material = Material{ .lambertian = Lambertian{ .albedo = vec3{ 0.4, 0.2, 0.1 } } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try spheres.append(.{
|
||||||
|
.sphere = Sphere{
|
||||||
|
.center = vec3{ 4, 1, 0 },
|
||||||
|
.radius = 1.0,
|
||||||
|
.material = Material{ .metal = Metal{ .albedo = vec3{ 0.7, 0.6, 0.5 }, .fuzz = 0.0 } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert ArrayList to a slice and create HittableList
|
||||||
|
return HittableList{ .list = spheres.items };
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generateRandomScene(alloc: std.mem.Allocator) !HittableList {
|
pub fn generateRandomScene(alloc: std.mem.Allocator) !HittableList {
|
||||||
var spheres = std.ArrayList(Hittable).init(alloc);
|
var spheres = std.ArrayList(Hittable).init(alloc);
|
||||||
|
|
||||||
@ -111,10 +149,13 @@ pub fn generateRandomScene(alloc: std.mem.Allocator) !HittableList {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Smaller spheres
|
// Smaller spheres
|
||||||
var a: i32 = -11;
|
var a: i32 = -6;
|
||||||
while (a < 11) : (a += 1) {
|
while (a < 11) : (a += 1) {
|
||||||
var b: i32 = -11;
|
var b: i32 = -6;
|
||||||
while (b < 11) : (b += 1) {
|
while (b < 6) : (b += 1) {
|
||||||
|
if ((-1 < a) and (a < 1) or ((-1 < b) and (b < 1))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const choose_mat = utils.rand_01();
|
const choose_mat = utils.rand_01();
|
||||||
const center = vec3{
|
const center = vec3{
|
||||||
@as(f64, @floatFromInt(a)) + 0.9 * utils.rand_01(),
|
@as(f64, @floatFromInt(a)) + 0.9 * utils.rand_01(),
|
||||||
|
@ -45,6 +45,10 @@ pub const Interval = struct {
|
|||||||
|
|
||||||
pub fn toVec3(x: anytype) vec3 {
|
pub fn toVec3(x: anytype) vec3 {
|
||||||
switch (@TypeOf(x)) {
|
switch (@TypeOf(x)) {
|
||||||
|
usize => {
|
||||||
|
const x_float = @as(f64, @floatFromInt(x));
|
||||||
|
return vec3{ x_float, x_float, x_float };
|
||||||
|
},
|
||||||
comptime_float => {
|
comptime_float => {
|
||||||
const x_float = @as(f64, x);
|
const x_float = @as(f64, x);
|
||||||
return vec3{ x_float, x_float, x_float };
|
return vec3{ x_float, x_float, x_float };
|
||||||
@ -63,10 +67,7 @@ pub fn toVec3(x: anytype) vec3 {
|
|||||||
@Vector(3, f64) => {
|
@Vector(3, f64) => {
|
||||||
return x;
|
return x;
|
||||||
},
|
},
|
||||||
usize => {
|
|
||||||
const x_float = @as(f64, @floatFromInt(@as(i64, @intCast(x))));
|
|
||||||
return vec3{ x_float, x_float, x_float };
|
|
||||||
},
|
|
||||||
else => {
|
else => {
|
||||||
@panic("Unknow type passed through toVec3\n\n");
|
@panic("Unknow type passed through toVec3\n\n");
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user