Normalise indentation (spaces vs tabs)

This commit is contained in:
Matthew Jakeman 2020-11-20 02:02:48 +13:00
parent c02be0fa2f
commit e00649fc05

506
tinyray.c
View file

@ -18,61 +18,61 @@ typedef unsigned char byte;
/* Minimal Floating Point Vector Maths - Author: Matthew Jakeman */ /* Minimal Floating Point Vector Maths - Author: Matthew Jakeman */
typedef struct { typedef struct {
float x; float x;
float y; float y;
float z; float z;
} Vec3; } Vec3;
Vec3 vec3_new(float x, float y, float z) { Vec3 vec3_new(float x, float y, float z) {
Vec3 vec; Vec3 vec;
vec.x = x; vec.x = x;
vec.y = y; vec.y = y;
vec.z = z; vec.z = z;
return vec; return vec;
} }
Vec3 vec3_add(Vec3 a, Vec3 b) { Vec3 vec3_add(Vec3 a, Vec3 b) {
return vec3_new(a.x + b.x, a.y + b.y, a.z + b.z); return vec3_new(a.x + b.x, a.y + b.y, a.z + b.z);
} }
Vec3 vec3_subtract(Vec3 a, Vec3 b) { Vec3 vec3_subtract(Vec3 a, Vec3 b) {
return vec3_new(a.x - b.x, a.y - b.y, a.z - b.z); return vec3_new(a.x - b.x, a.y - b.y, a.z - b.z);
} }
Vec3 vec3_subtract_scalar(Vec3 a, float b) { Vec3 vec3_subtract_scalar(Vec3 a, float b) {
return vec3_new(a.x - b, a.y - b, a.z - b); return vec3_new(a.x - b, a.y - b, a.z - b);
} }
Vec3 vec3_divide_scalar(Vec3 a, float b) { Vec3 vec3_divide_scalar(Vec3 a, float b) {
return vec3_new(a.x/b, a.y/b, a.z/b); return vec3_new(a.x/b, a.y/b, a.z/b);
} }
Vec3 vec3_multiply(Vec3 a, Vec3 b) { Vec3 vec3_multiply(Vec3 a, Vec3 b) {
return vec3_new(a.x*b.x, a.y*b.y, a.z*b.z); return vec3_new(a.x*b.x, a.y*b.y, a.z*b.z);
} }
Vec3 vec3_multiply_scalar(Vec3 a, float b) { Vec3 vec3_multiply_scalar(Vec3 a, float b) {
return vec3_new(a.x*b, a.y*b, a.z*b); return vec3_new(a.x*b, a.y*b, a.z*b);
} }
float vec3_dot(Vec3 a, Vec3 b) { float vec3_dot(Vec3 a, Vec3 b) {
return a.x*b.x + a.y*b.y + a.z*b.z; return a.x*b.x + a.y*b.y + a.z*b.z;
} }
float vec3_len(Vec3 v) { float vec3_len(Vec3 v) {
return (float)sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z)); return (float)sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
} }
Vec3 vec3_normalise(Vec3 v) { Vec3 vec3_normalise(Vec3 v) {
return vec3_divide_scalar(v, vec3_len(v)); // Calculate unit vector return vec3_divide_scalar(v, vec3_len(v)); // Calculate unit vector
} }
Vec3 vec3_clamp(Vec3 v, float min_value, float max_value) { Vec3 vec3_clamp(Vec3 v, float min_value, float max_value) {
return vec3_new( return vec3_new(
fmin(fmax(v.x, min_value), max_value), fmin(fmax(v.x, min_value), max_value),
fmin(fmax(v.y, min_value), max_value), fmin(fmax(v.y, min_value), max_value),
fmin(fmax(v.z, min_value), max_value) fmin(fmax(v.z, min_value), max_value)
); );
} }
// END - vectors // END - vectors
@ -80,32 +80,32 @@ Vec3 vec3_clamp(Vec3 v, float min_value, float max_value) {
typedef Vec3 RgbColour; typedef Vec3 RgbColour;
typedef struct { typedef struct {
RgbColour diffuse; RgbColour diffuse;
float specular; float specular;
} Material; } Material;
typedef struct { typedef struct {
Vec3 centre; Vec3 centre;
float radius; float radius;
Material material; Material material;
} Sphere; } Sphere;
typedef struct { typedef struct {
Vec3 origin; Vec3 origin;
Vec3 direction; Vec3 direction;
} Ray; } Ray;
typedef enum { typedef enum {
PointLight, PointLight,
DirectionalLight, DirectionalLight,
AmbientLight AmbientLight
} LightType; } LightType;
typedef struct { typedef struct {
LightType type; LightType type;
Vec3 position; // point only Vec3 position; // point only
Vec3 direction; // directional only Vec3 direction; // directional only
float intensity; float intensity;
} Light; } Light;
/* Globals */ /* Globals */
@ -118,48 +118,48 @@ const static unsigned int HEIGHT = 600;
/* Constructors */ /* Constructors */
Sphere sphere_new(Vec3 centre, float radius, Material material) { Sphere sphere_new(Vec3 centre, float radius, Material material) {
Sphere sphere = {0}; Sphere sphere = {0};
sphere.centre = centre; sphere.centre = centre;
sphere.radius = radius; sphere.radius = radius;
sphere.material = material; sphere.material = material;
return sphere; return sphere;
} }
Light light_point_new(float intensity, Vec3 position) { Light light_point_new(float intensity, Vec3 position) {
Light light = {0}; Light light = {0};
light.type = PointLight; light.type = PointLight;
light.position = position; light.position = position;
light.intensity = intensity; light.intensity = intensity;
return light; return light;
} }
Light light_ambient_new(float intensity) { Light light_ambient_new(float intensity) {
Light light = {0}; Light light = {0};
light.type = AmbientLight; light.type = AmbientLight;
light.intensity = intensity; light.intensity = intensity;
return light; return light;
} }
Light light_directional_new(float intensity, Vec3 direction) { Light light_directional_new(float intensity, Vec3 direction) {
Light light = {0}; Light light = {0};
light.type = DirectionalLight; light.type = DirectionalLight;
light.direction = direction; light.direction = direction;
light.intensity = intensity; light.intensity = intensity;
return light; return light;
} }
Material material_new(Vec3 diffuse, float specular) { Material material_new(Vec3 diffuse, float specular) {
Material material = {0}; Material material = {0};
material.diffuse = diffuse; material.diffuse = diffuse;
material.specular = specular; material.specular = specular;
return material; return material;
} }
Ray ray_new(Vec3 origin, Vec3 direction) { Ray ray_new(Vec3 origin, Vec3 direction) {
Ray ray; Ray ray;
ray.origin = origin; ray.origin = origin;
ray.direction = direction; ray.direction = direction;
return ray; return ray;
} }
// Lighting Compute Algorithm // Lighting Compute Algorithm
@ -171,50 +171,50 @@ Ray ray_new(Vec3 origin, Vec3 direction) {
// RETURNS: // RETURNS:
// - intensity of light // - intensity of light
float lighting_compute(Vec3 point, Vec3 normal, float lighting_compute(Vec3 point, Vec3 normal,
Vec3 view, float specular, Vec3 view, float specular,
Light *lights, int num_lights) { Light *lights, int num_lights) {
// Intensity of light for the given pixel // Intensity of light for the given pixel
float intensity = 0.0f; float intensity = 0.0f;
// Iterate over lights // Iterate over lights
for (int i = 0; i < num_lights; i++) for (int i = 0; i < num_lights; i++)
{ {
Light *light = &lights[i]; Light *light = &lights[i];
if (light->type == AmbientLight) if (light->type == AmbientLight)
{ {
// Simply add ambient light to total // Simply add ambient light to total
intensity += light->intensity; intensity += light->intensity;
} }
else else
{ {
Vec3 light_ray; Vec3 light_ray;
if (light->type == PointLight) if (light->type == PointLight)
// Point Light: Direction of ray from light to point // Point Light: Direction of ray from light to point
light_ray = vec3_subtract(light->position, point); light_ray = vec3_subtract(light->position, point);
else else
// Directional Light: Direction // Directional Light: Direction
light_ray = light->direction; light_ray = light->direction;
// Diffuse // Diffuse
float reflect = vec3_dot(normal, light_ray); float reflect = vec3_dot(normal, light_ray);
intensity += (light->intensity * reflect)/(vec3_len(normal) * vec3_len(light_ray)); intensity += (light->intensity * reflect)/(vec3_len(normal) * vec3_len(light_ray));
// Specular // Specular
if (specular != -1) if (specular != -1)
{ {
Vec3 r = vec3_subtract(vec3_multiply_scalar(normal, 2 * vec3_dot(normal, light_ray)), light_ray); Vec3 r = vec3_subtract(vec3_multiply_scalar(normal, 2 * vec3_dot(normal, light_ray)), light_ray);
float reflect_view_proj = vec3_dot(r, view); float reflect_view_proj = vec3_dot(r, view);
if (reflect_view_proj > 0) if (reflect_view_proj > 0)
{ {
float cosine = reflect_view_proj/(vec3_len(r) * vec3_len(view)); float cosine = reflect_view_proj/(vec3_len(r) * vec3_len(view));
intensity += light->intensity * powf(cosine, specular); intensity += light->intensity * powf(cosine, specular);
} }
} }
} }
} }
return intensity; return intensity;
} }
// Sphere-Ray Intersection // Sphere-Ray Intersection
@ -227,40 +227,40 @@ float lighting_compute(Vec3 point, Vec3 normal,
// - boolean of whether ray intersected a sphere // - boolean of whether ray intersected a sphere
// - [out] dist0, dist 1 = perpendicular distances to points of intersection // - [out] dist0, dist 1 = perpendicular distances to points of intersection
int do_sphere_raycast(Sphere sphere, Ray ray, float *dist0, float *dist1) { int do_sphere_raycast(Sphere sphere, Ray ray, float *dist0, float *dist1) {
// Please see sphere_ray_intersection.bmp // Please see sphere_ray_intersection.bmp
*dist0 = 0; *dist0 = 0;
*dist1 = 0; *dist1 = 0;
// Find L and tca // Find L and tca
Vec3 L = vec3_subtract(sphere.centre, ray.origin); Vec3 L = vec3_subtract(sphere.centre, ray.origin);
float tca = vec3_dot(L, ray.direction); float tca = vec3_dot(L, ray.direction);
// Discard if intersection is behind origin // Discard if intersection is behind origin
if (tca < 0) if (tca < 0)
return 0; return 0;
// Find d // Find d
float d = sqrtf(vec3_dot(L, L) - tca * tca); float d = sqrtf(vec3_dot(L, L) - tca * tca);
if (d > sphere.radius) if (d > sphere.radius)
return 0; return 0;
// Calculate thc using pythagoras // Calculate thc using pythagoras
float thc = sqrtf(sphere.radius * sphere.radius - d * d); float thc = sqrtf(sphere.radius * sphere.radius - d * d);
// Calculate t0 and t1 (perpendicular distance to // Calculate t0 and t1 (perpendicular distance to
// the 0th and 1st intersection) // the 0th and 1st intersection)
float t0 = tca - thc; float t0 = tca - thc;
float t1 = tca + thc; float t1 = tca + thc;
// Ensure at least one of t0 and t1 is greater than zero // Ensure at least one of t0 and t1 is greater than zero
if (t0 < 0 && t1 < 0) if (t0 < 0 && t1 < 0)
return 0; return 0;
*dist0 = t0; *dist0 = t0;
*dist1 = t1; *dist1 = t1;
return 1; // Intersection found return 1; // Intersection found
} }
// Raytrace Scene at Point // Raytrace Scene at Point
@ -274,64 +274,64 @@ int do_sphere_raycast(Sphere sphere, Ray ray, float *dist0, float *dist1) {
// RETURNS: // RETURNS:
// - rgb colour of pixel being raytraced // - rgb colour of pixel being raytraced
RgbColour raytrace(Vec3 origin, Vec3 dir, float min_t, float max_t, RgbColour raytrace(Vec3 origin, Vec3 dir, float min_t, float max_t,
Sphere *spheres, int num_spheres, Sphere *spheres, int num_spheres,
Light *lights, int num_lights) { Light *lights, int num_lights) {
// Closest sphere to screen (for depth-testing) // Closest sphere to screen (for depth-testing)
Sphere *closest = 0; Sphere *closest = 0;
// We use t_comp to store the t-depth of the closest // We use t_comp to store the t-depth of the closest
// sphere and compare it with other spheres to perform // sphere and compare it with other spheres to perform
// primitive depth testing (where 't' is perpendicular // primitive depth testing (where 't' is perpendicular
// distance to the point of intersection) // distance to the point of intersection)
float t_comp = (float)MAX_DIST; float t_comp = (float)MAX_DIST;
// Ray to test // Ray to test
Ray ray = ray_new(origin, dir); Ray ray = ray_new(origin, dir);
// Cycle through all spheres and depth-test // Cycle through all spheres and depth-test
for (int i = 0; i < num_spheres; i++) for (int i = 0; i < num_spheres; i++)
{ {
float dist0, dist1; float dist0, dist1;
if (do_sphere_raycast(spheres[i], ray, &dist0, &dist1)) if (do_sphere_raycast(spheres[i], ray, &dist0, &dist1))
{ {
// Check dist0 // Check dist0
if ((min_t < dist0 && dist0 < max_t) && if ((min_t < dist0 && dist0 < max_t) &&
dist0 < t_comp) dist0 < t_comp)
{ {
t_comp = dist0; t_comp = dist0;
closest = &spheres[i]; closest = &spheres[i];
} }
// Now check dist1 // Now check dist1
if ((min_t < dist1 && dist1 < max_t) && if ((min_t < dist1 && dist1 < max_t) &&
dist1 < t_comp) dist1 < t_comp)
{ {
t_comp = dist1; t_comp = dist1;
closest = &spheres[i]; closest = &spheres[i];
} }
} }
} }
if (!closest) if (!closest)
return Invalid; return Invalid;
Vec3 point = vec3_add(origin, vec3_multiply_scalar(dir, t_comp)); Vec3 point = vec3_add(origin, vec3_multiply_scalar(dir, t_comp));
Vec3 normal = vec3_normalise(vec3_subtract(point, closest->centre)); Vec3 normal = vec3_normalise(vec3_subtract(point, closest->centre));
Material material = closest->material; Material material = closest->material;
return vec3_clamp( return vec3_clamp(
vec3_multiply_scalar( vec3_multiply_scalar(
material.diffuse, material.diffuse,
lighting_compute( lighting_compute(
point, normal, point, normal,
vec3_multiply_scalar(dir, -1), vec3_multiply_scalar(dir, -1),
material.specular, material.specular,
lights, num_lights lights, num_lights
) )
), ),
0.0f, 255.0f // Clamp between 0 and 255 0.0f, 255.0f // Clamp between 0 and 255
); );
} }
// Watermark: Says "MATT J" // Watermark: Says "MATT J"
@ -339,12 +339,12 @@ RgbColour raytrace(Vec3 origin, Vec3 dir, float min_t, float max_t,
#define MARK_ROWS 7 #define MARK_ROWS 7
int mark[MARK_ROWS][MARK_COLS] = { int mark[MARK_ROWS][MARK_COLS] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0}, {0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0},
{0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0}, {0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}; };
// Draws a watermark on the screen using the above array // Draws a watermark on the screen using the above array
@ -357,94 +357,94 @@ void DrawWatermark(byte *data) {
for (int i = 0; i < MARK_COLS; i++) { for (int i = 0; i < MARK_COLS; i++) {
for (int j = 0; j < MARK_ROWS; j++) { for (int j = 0; j < MARK_ROWS; j++) {
int y_corner = start_y + j*(size*2 + stride); int y_corner = start_y + j*(size*2 + stride);
int x_corner = start_x + i*(size*2 + stride); int x_corner = start_x + i*(size*2 + stride);
// Draw Square // Draw Square
for (int x = x_corner; x < (x_corner + size); x++) { for (int x = x_corner; x < (x_corner + size); x++) {
for (int y = y_corner; y < (y_corner + size); y++) { for (int y = y_corner; y < (y_corner + size); y++) {
if (mark[j][i] == 0) { if (mark[j][i] == 0) {
data[(y*WIDTH + x) * 3 + 0] = (byte)(i/(float)MARK_COLS * 255) % 180; data[(y*WIDTH + x) * 3 + 0] = (byte)(i/(float)MARK_COLS * 255) % 180;
data[(y*WIDTH + x) * 3 + 1] = (byte)(j/(float)MARK_ROWS * 255) % 180; data[(y*WIDTH + x) * 3 + 1] = (byte)(j/(float)MARK_ROWS * 255) % 180;
data[(y*WIDTH + x) * 3 + 2] = (byte)240; data[(y*WIDTH + x) * 3 + 2] = (byte)240;
} }
else { else {
data[(y*WIDTH + x) * 3 + 0] = (byte)255; data[(y*WIDTH + x) * 3 + 0] = (byte)255;
data[(y*WIDTH + x) * 3 + 1] = (byte)255; data[(y*WIDTH + x) * 3 + 1] = (byte)255;
data[(y*WIDTH + x) * 3 + 2] = (byte)255; data[(y*WIDTH + x) * 3 + 2] = (byte)255;
} }
} }
} }
} }
} }
} }
int main(void) int main(void)
{ {
byte *data = malloc(sizeof(byte) * 3 * WIDTH * HEIGHT); byte *data = malloc(sizeof(byte) * 3 * WIDTH * HEIGHT);
// Materials // Materials
Material blue = material_new(vec3_new(69, 161, 255), 500); Material blue = material_new(vec3_new(69, 161, 255), 500);
Material white = material_new(vec3_new(240, 240, 240), 180); Material white = material_new(vec3_new(240, 240, 240), 180);
Material red = material_new(vec3_new(255, 0, 57), 10); Material red = material_new(vec3_new(255, 0, 57), 10);
Material ground = material_new(vec3_new(0, 57, 89), 1000); Material ground = material_new(vec3_new(0, 57, 89), 1000);
// Scene // Scene
#define NUM_SPHERES 4 #define NUM_SPHERES 4
Sphere spheres[NUM_SPHERES]; Sphere spheres[NUM_SPHERES];
spheres[0] = sphere_new(vec3_new(-0.75f, -0.2f, 6.5f), 1.5f, red); spheres[0] = sphere_new(vec3_new(-0.75f, -0.2f, 6.5f), 1.5f, red);
spheres[1] = sphere_new(vec3_new(0, -1, 5), 1.0f, blue); spheres[1] = sphere_new(vec3_new(0, -1, 5), 1.0f, blue);
spheres[2] = sphere_new(vec3_new(2, -0.5, 8), 3.0f, white); spheres[2] = sphere_new(vec3_new(2, -0.5, 8), 3.0f, white);
spheres[3] = sphere_new(vec3_new(0, -4001, 0), 4000, ground); spheres[3] = sphere_new(vec3_new(0, -4001, 0), 4000, ground);
// Lights // Lights
#define NUM_LIGHTS 3 #define NUM_LIGHTS 3
Light lights[NUM_LIGHTS]; Light lights[NUM_LIGHTS];
lights[0] = light_ambient_new(0.2f); lights[0] = light_ambient_new(0.2f);
lights[1] = light_point_new(0.6f, vec3_new(-8, 1, 0)); lights[1] = light_point_new(0.6f, vec3_new(-8, 1, 0));
lights[2] = light_directional_new(0.2f, vec3_new(1, 4, -8)); lights[2] = light_directional_new(0.2f, vec3_new(1, 4, -8));
// For non-square images (future-proofing?) // For non-square images (future-proofing?)
float aspect_ratio = (float)WIDTH/(float)HEIGHT; float aspect_ratio = (float)WIDTH/(float)HEIGHT;
float screen_dim = tanf(FOV / (float)2); float screen_dim = tanf(FOV / (float)2);
Vec3 origin = Zero; Vec3 origin = Zero;
// Render // Render
for (int x = 0; x < WIDTH; x++) { for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) { for (int y = 0; y < HEIGHT; y++) {
// Background // Background
data[(y*WIDTH + x) * 3 + 0] = (byte)(y/(float)WIDTH * 255); data[(y*WIDTH + x) * 3 + 0] = (byte)(y/(float)WIDTH * 255);
data[(y*WIDTH + x) * 3 + 1] = (byte)(x/(float)HEIGHT * 255); data[(y*WIDTH + x) * 3 + 1] = (byte)(x/(float)HEIGHT * 255);
data[(y*WIDTH + x) * 3 + 2] = (byte)160; data[(y*WIDTH + x) * 3 + 2] = (byte)160;
// Get Pixel in World Coords // Get Pixel in World Coords
float x_world_coord = (2*(x + 0.5f)/(float)HEIGHT - 1) * screen_dim * aspect_ratio; float x_world_coord = (2*(x + 0.5f)/(float)HEIGHT - 1) * screen_dim * aspect_ratio;
float y_world_coord = -(2*(y + 0.5f)/(float)WIDTH - 1) * screen_dim; float y_world_coord = -(2*(y + 0.5f)/(float)WIDTH - 1) * screen_dim;
Vec3 dir = vec3_normalise(vec3_new(x_world_coord, y_world_coord, 1)); Vec3 dir = vec3_normalise(vec3_new(x_world_coord, y_world_coord, 1));
// Raytrace Pixel // Raytrace Pixel
RgbColour colour = raytrace(origin, dir, 1.0f, (float)MAX_DIST, RgbColour colour = raytrace(origin, dir, 1.0f, (float)MAX_DIST,
spheres, NUM_SPHERES, spheres, NUM_SPHERES,
lights, NUM_LIGHTS); lights, NUM_LIGHTS);
// Draw Geometry // Draw Geometry
if (colour.x != -1) { if (colour.x != -1) {
data[(y*WIDTH + x) * 3 + 0] = (byte)colour.x; data[(y*WIDTH + x) * 3 + 0] = (byte)colour.x;
data[(y*WIDTH + x) * 3 + 1] = (byte)colour.y; data[(y*WIDTH + x) * 3 + 1] = (byte)colour.y;
data[(y*WIDTH + x) * 3 + 2] = (byte)colour.z; data[(y*WIDTH + x) * 3 + 2] = (byte)colour.z;
} }
} }
} }
// Output // Output
DrawWatermark(data); DrawWatermark(data);
// Write to file // Write to file
printf("tinyray: writing to file!"); printf("tinyray: writing to file!");
if (!stbi_write_bmp("output.bmp", WIDTH, HEIGHT, 3, data)) if (!stbi_write_bmp("output.bmp", WIDTH, HEIGHT, 3, data))
printf("tinyray: failed to write image!"); printf("tinyray: failed to write image!");
return 0; return 0;
} }