feat: add support for arrays
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void print_number(int number) {
|
||||
printf("%d", number);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
foreign fn putchar(c: i32) -> i32;
|
||||
foreign fn print_number(n: i32);
|
||||
foreign fn sqrtf(num: f32) -> f32;
|
||||
|
||||
struct Vec3 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32
|
||||
}
|
||||
|
||||
struct Ray {
|
||||
origin: Vec3,
|
||||
dir: Vec3
|
||||
}
|
||||
|
||||
struct Sphere {
|
||||
center: Vec3,
|
||||
radius: f32,
|
||||
color: Vec3
|
||||
}
|
||||
|
||||
struct Hit {
|
||||
hit: bool,
|
||||
t: f32,
|
||||
normal: Vec3,
|
||||
color: Vec3
|
||||
}
|
||||
|
||||
fn vec3_add(a: Vec3, b: Vec3) -> Vec3 {
|
||||
return Vec3 { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
|
||||
}
|
||||
|
||||
fn vec3_sub(a: Vec3, b: Vec3) -> Vec3 {
|
||||
return Vec3 { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
||||
}
|
||||
|
||||
fn vec3_mul(a: Vec3, t: f32) -> Vec3 {
|
||||
return Vec3 { x: a.x * t, y: a.y * t, z: a.z * t };
|
||||
}
|
||||
|
||||
fn vec3_dot(a: Vec3, b: Vec3) -> f32 {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
fn vec3_normalize(v: Vec3) -> Vec3 {
|
||||
let len = sqrtf(vec3_dot(v, v));
|
||||
if len == 0.0 {
|
||||
return Vec3 { x: 0.0, y: 0.0, z: 0.0 };
|
||||
}
|
||||
return vec3_mul(v, 1.0 / len);
|
||||
}
|
||||
|
||||
fn intersect_sphere(ray: *Ray, sphere: *Sphere, t_min: f32, t_max: f32) -> Hit {
|
||||
let oc = vec3_sub((*ray).origin, (*sphere).center);
|
||||
let a = vec3_dot((*ray).dir, (*ray).dir);
|
||||
let half_b = vec3_dot(oc, (*ray).dir);
|
||||
let c = vec3_dot(oc, oc) - (*sphere).radius * (*sphere).radius;
|
||||
let discriminant = half_b * half_b - a * c;
|
||||
|
||||
let miss = Hit {
|
||||
hit: false,
|
||||
t: 0.0,
|
||||
normal: Vec3 { x: 0.0, y: 0.0, z: 0.0 },
|
||||
color: Vec3 { x: 0.0, y: 0.0, z: 0.0 }
|
||||
};
|
||||
|
||||
if discriminant < 0.0 {
|
||||
return miss;
|
||||
}
|
||||
|
||||
let sqrtd = sqrtf(discriminant);
|
||||
let root = (-half_b - sqrtd) / a;
|
||||
|
||||
if root < t_min {
|
||||
root = (-half_b + sqrtd) / a;
|
||||
if root < t_min {
|
||||
return miss;
|
||||
}
|
||||
}
|
||||
|
||||
if root > t_max {
|
||||
return miss;
|
||||
}
|
||||
|
||||
let hit_point = vec3_add((*ray).origin, vec3_mul((*ray).dir, root));
|
||||
let normal = vec3_mul(vec3_sub(hit_point, (*sphere).center), 1.0 / (*sphere).radius);
|
||||
|
||||
return Hit {
|
||||
hit: true,
|
||||
t: root,
|
||||
normal: normal,
|
||||
color: (*sphere).color
|
||||
};
|
||||
}
|
||||
|
||||
fn ray_color(ray: *Ray, spheres: *[Sphere; 2]) -> Vec3 {
|
||||
let closest_so_far = 1000.0;
|
||||
let hit_anything = false;
|
||||
let hit_color = Vec3 { x: 0.0, y: 0.0, z: 0.0 };
|
||||
let hit_normal = Vec3 { x: 0.0, y: 0.0, z: 0.0 };
|
||||
|
||||
let i = 0;
|
||||
while i < 2 {
|
||||
// Pointer arithmetic to array structs via the &[] index syntax
|
||||
let hit = intersect_sphere(ray, &(*spheres)[i], 0.001, closest_so_far);
|
||||
|
||||
if hit.hit {
|
||||
hit_anything = true;
|
||||
closest_so_far = hit.t;
|
||||
hit_color = hit.color;
|
||||
hit_normal = hit.normal;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
if hit_anything {
|
||||
// We remap the surface normal from [-1..1] to the [0..1] color space
|
||||
let mapped_normal = vec3_mul(vec3_add(hit_normal, Vec3 { x: 1.0, y: 1.0, z: 1.0 }), 0.5);
|
||||
|
||||
// Multiply the resulting surface map shading by the intrinsic color of the object
|
||||
return Vec3 {
|
||||
x: hit_color.x * mapped_normal.x,
|
||||
y: hit_color.y * mapped_normal.y,
|
||||
z: hit_color.z * mapped_normal.z
|
||||
};
|
||||
}
|
||||
|
||||
// Beautiful skybox blue to white linear gradient
|
||||
let unit_dir = vec3_normalize((*ray).dir);
|
||||
let t = 0.5 * (unit_dir.y + 1.0);
|
||||
return vec3_add(
|
||||
vec3_mul(Vec3 { x: 1.0, y: 1.0, z: 1.0 }, 1.0 - t),
|
||||
vec3_mul(Vec3 { x: 0.5, y: 0.7, z: 1.0 }, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn main() -> i32 {
|
||||
let image_width = 1024;
|
||||
let image_height = 1024;
|
||||
|
||||
let spheres: [Sphere; 2] = [
|
||||
Sphere {
|
||||
center: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
|
||||
radius: 0.5,
|
||||
color: Vec3 { x: 1.0, y: 0.2, z: 0.2 } // Red sphere
|
||||
},
|
||||
Sphere {
|
||||
center: Vec3 { x: 0.0, y: -100.5, z: -1.0 },
|
||||
radius: 100.0,
|
||||
color: Vec3 { x: 0.2, y: 0.8, z: 0.2 } // Green ground
|
||||
}
|
||||
];
|
||||
|
||||
// Print standard PPM Image File Header
|
||||
putchar(80); putchar(51); putchar(10); // "P3\n"
|
||||
|
||||
print_number(image_width);
|
||||
putchar(32); // " "
|
||||
print_number(image_height);
|
||||
putchar(10); // "\n"
|
||||
|
||||
print_number(255);
|
||||
putchar(10); // "255\n"
|
||||
|
||||
let j = image_height - 1;
|
||||
while j >= 0 {
|
||||
let i = 0;
|
||||
while i < image_width {
|
||||
let u = (i as f32) / (image_width as f32 - 1.0);
|
||||
let v = (j as f32) / (image_height as f32 - 1.0);
|
||||
|
||||
// Set up a classic look-at viewport layout
|
||||
let lower_left_corner = Vec3 { x: -2.0, y: -2.0, z: -1.0 };
|
||||
let horizontal = Vec3 { x: 4.0, y: 0.0, z: 0.0 };
|
||||
let vertical = Vec3 { x: 0.0, y: 4.0, z: 0.0 };
|
||||
let origin = Vec3 { x: 0.0, y: 0.0, z: 0.0 };
|
||||
|
||||
let dir = vec3_sub(
|
||||
vec3_add(lower_left_corner, vec3_add(vec3_mul(horizontal, u), vec3_mul(vertical, v))),
|
||||
origin
|
||||
);
|
||||
|
||||
let ray = Ray { origin: origin, dir: dir };
|
||||
let col = ray_color(&ray, &spheres);
|
||||
|
||||
// Precedence parser respects parenthesis grouping over multiplication
|
||||
let ir = (255.999 * col.x) as i32;
|
||||
let ig = (255.999 * col.y) as i32;
|
||||
let ib = (255.999 * col.z) as i32;
|
||||
|
||||
print_number(ir);
|
||||
putchar(32);
|
||||
print_number(ig);
|
||||
putchar(32);
|
||||
print_number(ib);
|
||||
putchar(10);
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
j = j - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user