From a9651189ac52139c374f97a311d090a8d95b957e Mon Sep 17 00:00:00 2001
From: Julian T <julian@jtle.dk>
Date: Thu, 26 Mar 2020 21:47:51 +0100
Subject: MOved hemisphere transformation stuff out of ray.c

---
 ctranslate.c | 41 ++++++++++++++++++++++++++++++++++++
 ctranslate.h | 30 ++++++++++++++++++++++++++
 ray.c        | 69 +++++++++++++++++++++++++++++++++++-------------------------
 3 files changed, 111 insertions(+), 29 deletions(-)
 create mode 100644 ctranslate.c
 create mode 100644 ctranslate.h

diff --git a/ctranslate.c b/ctranslate.c
new file mode 100644
index 0000000..f7dfe64
--- /dev/null
+++ b/ctranslate.c
@@ -0,0 +1,41 @@
+#include "ctranslate.h"
+
+#include <math.h>
+
+// TODO remove dublicate pi definitions
+#define PI 3.14159265359
+
+void csystem_init(csystem_t *cs, vector_t *up)
+{
+	cs->up = up;
+
+	// Create new coordinate system where N is up. To do this we need two more vectors for the other axises.
+	// Create the 2. by setting x or y to 0
+	if (up->x > up->y) {
+		vector_set(&cs->ax, up->z, 0, -up->x);
+	} else {
+		vector_set(&cs->ax, 0, -up->z, up->y);
+	}
+	// Normalice
+	vector_scale_inv(&cs->ax, &cs->ax, vector_len(&cs->ax));
+
+	// Create the 3. axis by taking the cross of the other
+	vector_cross(&cs->az, up, &cs->ax);
+}
+
+void csystem_calc_real(csystem_t *cs, vector_t *inside, vector_t *real)
+{
+	vector_set(real, inside->x * cs->ax.x + inside->y * cs->up->x + inside->z * cs->az.x,
+			         inside->x * cs->ax.y + inside->y * cs->up->y + inside->z * cs->az.y,
+					 inside->x * cs->ax.z + inside->y * cs->up->z + inside->z * cs->az.z);
+}
+
+void csystem_hemisphere_random(csystem_t *cs, COORD_T r1, COORD_T r2, vector_t *out)
+{
+	COORD_T sinTheta = sqrt(1 - r1 * r1);
+	COORD_T phi = 2 * PI * r2;
+
+	// Calculate the random direction vector
+	vector_set(out, sinTheta * cos(phi), r1, sinTheta * sin(phi));
+}
+
diff --git a/ctranslate.h b/ctranslate.h
new file mode 100644
index 0000000..a2cc9b2
--- /dev/null
+++ b/ctranslate.h
@@ -0,0 +1,30 @@
+#ifndef CTRANS_H
+#define CTRANS_H
+
+#include "vector.h"
+
+// Used to create a sort of "virtual" coordinate system where up is defined by a given vector
+// Implemented from https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/global-illumination-path-tracing-practical-implementation
+// These methods assume y is up
+
+typedef struct {
+	vector_t *up;
+
+	// These are calculated from the given up vector
+	vector_t ax;
+	vector_t az;
+} csystem_t;
+
+// Inits the given csystem_t with a given up vector.
+// Will overwrite everything in cs
+void csystem_init(csystem_t *cs, vector_t *up);
+
+// Translates the inside coordinates to real and saves them in real.
+// Will overwrite real
+void csystem_calc_real(csystem_t *cs, vector_t *inside, vector_t *real);
+
+// Writes the inside coordinates of a random direction in the upper hemisphere, and saves in out
+// One must provide random numbers r1 and r2 between 0 and 1
+void csystem_hemisphere_random(csystem_t *cs, COORD_T r1, COORD_T r2, vector_t *out);
+
+#endif
diff --git a/ray.c b/ray.c
index 465b154..3932f23 100644
--- a/ray.c
+++ b/ray.c
@@ -1,7 +1,9 @@
 #include <stdio.h>
 #include <math.h>
 #include <stdlib.h>
+#include <assert.h>
 #include "vector.h"
+#include "ctranslate.h"
 
 #include "ray.h"
 
@@ -186,7 +188,35 @@ static void contribution_from_pointlight(space_t *s, color_t *dest, object_t *o,
 	reflected_at(o, dest, light, d, point, &l, V, N);
 }
 
-static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *eye, vector_t *point)
+// Many of these can maybe be put in a context struct
+static void contribution_from_arealight(space_t *s, color_t *dest, object_t *o, light_t *light, vector_t *point, vector_t *V, vector_t *N, void *seed)
+{
+	// This only works with spheres
+	assert(o->type == TYPE_SPHERE);
+
+	// Color to collect temporary results in
+	color_t c;
+
+	ray_t ray;
+	ray.start = point;
+
+	// Do the same monte carlo as with environment but the starting point is the center of the circle.
+	// And the result is a point on the circle
+	for (int i = 0; i < 16; i++) {
+		// Do the monte carlo random distribution thing from the article
+		COORD_T r1 = ray_rand(seed);
+		COORD_T r2 = ray_rand(seed);
+
+		COORD_T sinTheta = sqrt(1 - r1 * r1);
+		COORD_T phi = 2 * PI * r2;
+
+		// Cast a ray
+
+	}
+
+}
+
+static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *eye, vector_t *point, void *seed)
 {
 	// And vector towards viewer
 	vector_t V;
@@ -209,21 +239,9 @@ static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, ve
 // https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/global-illumination-path-tracing-practical-implementation
 static void env_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *point, void *seed) 
 {
-	// Create new coordinate system where N is up. To do this we need two more vectors for the other axises.
-	// Create the 2. by setting x or y to 0
-	vector_t Nt;
-	if (N->x > N->y) {
-		vector_set(&Nt, N->z, 0, -N->x);
-	} else {
-		vector_set(&Nt, 0, -N->z, N->y);
-	}
-	// Normalice
-	vector_scale_inv(&Nt, &Nt, vector_len(&Nt));
-
-	// Create the 3. axis by taking the cross of the other
-	vector_t Nb;
-	vector_cross(&Nb, N, &Nt);
-
+	csystem_t cs;
+	csystem_init(&cs, N);
+	
 	// Prepare ray
 	ray_t r;
 	r.start = point;
@@ -233,21 +251,14 @@ static void env_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vecto
 	color_set(&acc, 0, 0, 0);
 
 	for (unsigned i = 0; i < s->env_samples; i++) {
-		// Do the monte carlo random distribution thing from the article
 		COORD_T r1 = ray_rand(seed);
-		COORD_T r2 = ray_rand(seed);
-
-		COORD_T sinTheta = sqrt(1 - r1 * r1);
-		COORD_T phi = 2 * PI * r2;
-
+		//
 		// Calculate the random direction vector
 		vector_t randdir;
-		vector_set(&randdir, sinTheta * cos(phi), r1, sinTheta * sin(phi));
+		csystem_hemisphere_random(&cs, r1, ray_rand(seed), &randdir);
 
 		// Convert to world cordinates using the calculated N vectors. 
-		vector_set(&randdir, randdir.x * Nb.x + randdir.y * N->x + randdir.z * Nt.x,
-				         randdir.x * Nb.y + randdir.y * N->y + randdir.z * Nt.y,
-						 randdir.x * Nb.z + randdir.y * N->z + randdir.z * Nt.z);
+		csystem_calc_real(&cs, &randdir, &randdir);
 
 		// Check the direction for obstacles
 		r.direction = &randdir;
@@ -261,7 +272,7 @@ static void env_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vecto
 		color_t tmp;
 		color_scale(&tmp, &s->env_color, r1);
 
-		acc.r += tmp.r; acc.g += tmp.g; acc.b += tmp.b;
+		color_add(&acc, &acc, &tmp);
 	}
 
 	// Devide by number of samples and pdf
@@ -285,7 +296,7 @@ int ray_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T
 	}
 
 	vector_t rdir, rstart;
-	ray_t r = {start: &rstart, direction: &rdir};
+	ray_t r = {.start = &rstart, .direction = &rdir};
 
 	vector_scale(r.start, ray->direction, dist);
 	vector_add(r.start, r.start, ray->start);
@@ -302,7 +313,7 @@ int ray_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T
 	// Check if we should calculate light
 	if (o->m->defuse + o->m->specular > ZERO_APROX) {
 		// Add all light hitting o at r.start to c
-		direct_light(s, &c, o, &N, ray->start, r.start);
+		direct_light(s, &c, o, &N, ray->start, r.start, seed);
 	}
 	
 	// Calculate environmental light
-- 
cgit v1.2.3