diff --git a/.gitignore b/.gitignore index 877906e..bf48f6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.bmp *.png *.out -out/ \ No newline at end of file +obj +out diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..7a8cdab --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/raymarcher.iml b/.idea/raymarcher.iml new file mode 100644 index 0000000..bc2cd87 --- /dev/null +++ b/.idea/raymarcher.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..46bff8d --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..57b4a0b --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ + + +OPTIMIZATION=-O3 +CC=gcc +CFLAGS=-Isrc/ -lm -Wall -Wextra -pedantic-errors $(OPTIMIZATION) + +.PHONY: directories + +directories: + mkdir -p obj out + +obj/point.o: src/point.c src/point.h + $(CC) $(CFLAGS) -c -o $@ src/point.c + +obj/scene.o: src/scene.c src/scene.h + $(CC) $(CFLAGS) -c -o $@ src/scene.c + +obj/camera.o: src/camera.c src/camera.h + $(CC) $(CFLAGS) -c -o $@ src/camera.c + +obj/images.o: images/src/images.c images/src/images.h + $(CC) $(CFLAGS) -c -o $@ images/src/images.c + + +march: obj/camera.o obj/scene.o obj/point.o obj/images.o + $(CC) $(CFLAGS) -o out/march $^ marcher.c + diff --git a/main.c b/marcher.c similarity index 56% rename from main.c rename to marcher.c index 685501d..c32562b 100644 --- a/main.c +++ b/marcher.c @@ -1,6 +1,10 @@ #include -#include "images/images.h" -#include "marcher.h" +#include +#include +#include "images/src/images.h" +#include "src/scene.h" +#include "src/camera.h" +#include "src/point.h" #define SCENE_MOD 2 @@ -15,15 +19,15 @@ */ -double circle_dist(Point x, SceneObject *self) { +double circle_dist(struct point x, struct scene_object *self) { double r = self->args[0]; return pt_dist(pt_mod(x, SCENE_MOD), self->location) - r; } -Color circle_color(Point hit, Point direction, SceneObject *self) { - Point obj_direction = self->location; +Color circle_color(struct point hit, struct point direction, struct scene_object *self) { + struct point obj_direction = self->location; - pt_sub(&obj_direction, pt_mod(hit, SCENE_MOD)); + obj_direction = pt_sub(obj_direction, pt_mod(hit, SCENE_MOD)); double angle = pt_angle(direction, obj_direction) / M_PI * 180; Color color = self->color; @@ -34,15 +38,16 @@ Color circle_color(Point hit, Point direction, SceneObject *self) { return color; } // constructs the scene object -SceneObject circle_new(Point loc, double radius) { - SceneObject so; - so.location = loc; - so.args = malloc(sizeof(double) * 2); - so.args[0] = radius; - so.distance = circle_dist; - so.get_color = circle_color; - so.color = color_new(255,255,255); - return so; +struct scene_object circle_new(struct point loc, double radius) { + double * args = malloc(sizeof (double) * 2); + args[0] = radius; + return (struct scene_object) { + .location = loc, + .args = args, + .distance = circle_dist, + .get_color = circle_color, + .color = color_new(255, 255, 255), + }; } @@ -55,11 +60,11 @@ SceneObject circle_new(Point loc, double radius) { Color function is just a flat shader, detail is displayed with ambient occlusion */ -double mandelbulb_dist(Point pt, SceneObject *self) { +double mandelbulb_dist(struct point pt, struct scene_object *self) { int iters = self->args[0]; double power = self->args[1]; - Point z = pt; + struct point z = pt; float dr = 1.0; float r = 0.0; for (int i = 0; i < iters ; i++) { @@ -79,39 +84,43 @@ double mandelbulb_dist(Point pt, SceneObject *self) { theta = theta*power; phi = phi*power; - // convert back to cartesian coordinates - z = pt_mult(pt_new(sin(theta)*cos(phi), sin(phi)*sin(theta), cos(theta)), zr); - pt_add(&z, pt); + // convert back to cartesian coordinates, add zr and the old pt + z = (struct point) { + .x = sin(theta)*cos(phi) * zr + pt.x, + .y = sin(phi)*sin(theta) * zr + pt.y, + .z = cos(theta) * zr + pt.z + }; } return 0.5*log(r)*r/dr; - } -Color mandelbulb_color(Point hit, Point direction, SceneObject *self) { +Color mandelbulb_color(struct point hit, struct point direction, struct scene_object *self) { return self->color; } // constructs the scene object -SceneObject mandelbulb_new(Point location, int iters, double power) { - SceneObject so; - so.location = location; - so.args = malloc(sizeof(double) * 3); - so.args[0] = iters; // iterations - so.args[1] = power; // power - so.args[2] = -1; // reserved for color calculations - so.distance = mandelbulb_dist; - so.get_color = mandelbulb_color; - so.color = color_new(255,255,255); - return so; +struct scene_object mandelbulb_new(struct point location, int iters, double power) { + double * args = malloc(sizeof(double) * 3); + args[0] = iters; + args[1] = power; + args[2] = -1; + + return (struct scene_object) { + .location= location, + .args= args, + .distance= mandelbulb_dist, + .get_color= mandelbulb_color, + .color= color_new(255,255,255), + }; } int main(int argc, char* argv[]) { - float dpi = 800; + float dpi = 200; int threads = 32; int size = dpi * 27.56f; // 400dpi by 70cm size float pow = 3; - float cam_position = 1.15; + float cam_position = 1.35; int steps = 1000; int iters = 500; float threshold = 0.001; @@ -131,15 +140,13 @@ int main(int argc, char* argv[]) { printf("Rendering to %s\n", path); - Camera cam; + struct camera cam; cam.fov = 90; - camera_set_looking_at(&cam, pt_new(cam_position, cam_position, cam_position), pt_new(0,0,0)); - - + camera_set_looking_at(&cam, (struct point){.x=cam_position, .y= 0, .z = cam_position}, PT_ZERO); // create basic scene with up to 10 objects - Scene scene = scene_new(size, size, 1); + struct scene scene = scene_new(size, size, 1); scene.perf_opts.max_steps = steps; scene.perf_opts.threshold = threshold; scene.perf_opts.speed_cutoff = 10; @@ -147,7 +154,7 @@ int main(int argc, char* argv[]) { //scene_add_obj(&scene, circle_new(pt_new(SCENE_MOD / 2.0, SCENE_MOD/ 2.0, SCENE_MOD / 2.0), .2)); - scene_add_obj(&scene, mandelbulb_new(pt_new(0,0,0), iters, pow)); + scene_add_obj(&scene, mandelbulb_new(PT_ZERO, iters, pow)); Image *img = render_scene(&scene, &cam, threads); diff --git a/marcher.h b/marcher.h deleted file mode 100644 index acc539a..0000000 --- a/marcher.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef __MARCHER_H__ -#define __MARCHER_H__ - -#include "images/images.h" - -// define pi if not available -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -struct __myvec; -struct __mymtrx; -struct __mycam; -struct __myobject; -struct __myscene; - -typedef struct __myvec { - double x; - double y; - double z; -} Point; - -typedef struct __mymtrx { - double entries[9]; -} Matrix; - -inline Point pt_new(double x, double y, double z); -inline Point pt_scale(Point pt, double length); -inline Point pt_normalize(Point pt); -inline double pt_length(Point pt); -inline void pt_add(Point* pt, Point add); -inline void pt_sub(Point* pt, Point sub); -inline double pt_dist(Point p1, Point p2); -inline Point pt_mod(Point pt, double mod); -inline double pt_dot(Point a, Point b); -inline Point pt_cross(Point a, Point b); -inline double pt_angle(Point a, Point b); -inline void pt_print(Point pt); -inline void pt_print_n(const char* name, Point pt); - - -typedef struct __mycam { - Point location; - Point direction; - unsigned int fov; -} Camera; - -Camera camera_new(Point direction, unsigned int fov); -void camera_set_looking_at(Camera *cam, Point origin, Point thing); - -// Scene objects have a position, some args, and a distance calculation function -// the distance calc function has the following signature: -// double distanceTo(Point myLocation, double * myArgs, Point externalPoint) -// where myLocation is this.location, myArgs is this.args and externalPoint is the point from wich we want to know the distance -// the get_color function takes args: point_hit, direction_hit, myArgs, MyLocation, MyColor -typedef struct __myobject { - Point location; - double * args; - double (*distance)(Point, struct __myobject *); - Color (*get_color)(Point, Point, struct __myobject *); - Color color; - struct __myscene* scene; -} SceneObject; - - -typedef struct __perfopts { - int speed_cutoff; - int max_steps; - double threshold; -} PerformanceOptimizations; - - -typedef struct __myscene { - unsigned int width; - unsigned int height; - SceneObject * objects; - int object_count; - int allocated_space; - // performance opts - PerformanceOptimizations perf_opts; - // colors etc - Color background; -} Scene; - -Image* render_scene(Scene *scene, Camera *camera, unsigned int threads); - -Scene scene_new(unsigned int width, unsigned int height, int obj_count); - -void scene_add_obj(Scene* scene, SceneObject object); - -void scene_destroy(Scene scene); - -#include "src/point.c" -#include "src/camera.c" -#include "src/scene.c" - -#endif \ No newline at end of file diff --git a/src/camera.c b/src/camera.c index 33a24f2..54a493b 100644 --- a/src/camera.c +++ b/src/camera.c @@ -1,10 +1,18 @@ #include #include #include - -Camera camera_new(Point direction, unsigned int fov) { - Camera camera; - camera.location = pt_new(0,0,0); +#include +#include +#include "point.h" +#include "camera.h" + +struct camera camera_new(struct point direction, unsigned int fov) { + struct camera camera; + camera.location = (struct point) { + .x = 0, + .y = 0, + .z = 0 + }; camera.fov = fov; // normalize camera direction @@ -13,92 +21,17 @@ Camera camera_new(Point direction, unsigned int fov) { return camera; } -void camera_set_looking_at(Camera *cam, Point origin, Point thing) { +void camera_set_looking_at(struct camera *cam, struct point origin, struct point thing) { cam->location = origin; - pt_sub(&thing, origin); - cam->direction = pt_normalize(thing); + cam->direction = pt_normalize(pt_sub(thing, origin)); } -void camera_iterate_rays_const_angle(Camera camera, int width, int height, int threads, void (*callback)(Point, int, int)) { - // negative threads => single threaded. - if (threads < 0) threads = 0; - - Point span_z, span_xy; - - // get rotation axis - pt_orthogonal_plane(camera.direction, &span_z, &span_xy); - - printf("rendering %ix%i px", width, height); - - pt_print_n("span_xy", span_xy); - pt_print_n("span_z", span_z); - - // angle between rays - double angle_step = camera.fov / (double) (width - 1); - - // rotation applied to reach the outmost end of the view - double angle_start_h = - (camera.fov / 2.0); - double angle_start_v = ((angle_step * (height - 1)) / 2) ; - - printf("step: %f\nstart_h: %f\nstart_v: %f\n", angle_step, angle_start_h, angle_start_v); - - // calculate both rotation matrices (expensive!) - Matrix rot_z = mtrx_rotation(span_z, angle_step); - Matrix rot_xy = mtrx_rotation(span_xy, -angle_step); - - // rotate vector to starting location (bot left of screen) - // (very expensive!) - Point starting_point = mtrx_mult( - mtrx_rotation(span_xy, angle_start_v), - mtrx_mult( - mtrx_rotation(span_z, angle_start_h), - camera.direction - ) - ); - - // initialize threads - int thread_id = 0; - for (int i = 0; i < threads - 1; i++) { - if (fork() == 0) { - thread_id = i + 1; - break; - } - } - - // this point is rotated for every pixel - Point curr_pt = starting_point; - // (0,0) screenspace is bottom left corner - for (int y = 0; y < height; y++) { - curr_pt = mtrx_mult(rot_xy, starting_point); - // move starting point one row down - starting_point = curr_pt; - - if (y % threads != thread_id) continue; - - for (int x = 0; x < width; x++) { - callback(curr_pt, x, y); - curr_pt = mtrx_mult(rot_z, curr_pt); // rotate point - } - } - - if (thread_id != 0) { - printf("Thread %i is finished\n", thread_id); - exit(0); - } - - int status; - for (int i = 0; i < threads - 1; i++) { - while(wait(&status) > 0) {} - } - - printf("got threads\n"); -} -void camera_iterate_rays_const_dist(Camera camera, int width, int height, int threads, void (*callback)(Point, int, int)) { +void camera_iterate_rays_const_dist(struct camera camera, int width, int height, int threads, void (*callback)(struct point, int, int)) { // negative threads => single threaded. if (threads < 0) threads = 0; - Point span_z, span_xy; + struct point span_z, span_xy; // get rotation axis pt_orthogonal_plane(camera.direction, &span_z, &span_xy); @@ -109,15 +42,15 @@ void camera_iterate_rays_const_dist(Camera camera, int width, int height, int th double step_dist = 2 / (double) (width - 1); // vectors to move on the projection plane - Point move_right = pt_scale(span_xy, step_dist); - Point move_up = pt_scale(span_z, step_dist);; + struct point move_right = pt_scale(span_xy, step_dist); + struct point move_up = pt_scale(span_z, step_dist);; // set starting point - Point starting_point = pt_normalize(camera.direction); + struct point starting_point = pt_normalize(camera.direction); // rotate starting point to (0,0) - pt_add(&starting_point, pt_mult(move_right, - width / (double) 2)); - pt_add(&starting_point, pt_mult(move_up, - height / (double) 2)); + starting_point = pt_add(starting_point, pt_mult(move_right, - width / (double) 2)); + starting_point = pt_add(starting_point, pt_mult(move_up, - height / (double) 2)); // initialize threads int thread_id = 0; @@ -129,12 +62,12 @@ void camera_iterate_rays_const_dist(Camera camera, int width, int height, int th } // this point is moved for every pixel - Point curr_pt = starting_point; + struct point curr_pt = starting_point; // (0,0) screenspace is bottom left corner for (int y = 0; y < height; y++) { // move one row up (this has to be done in every thread!) - pt_add(&starting_point, move_up); + starting_point = pt_add(starting_point, move_up); // only render the lines this thread is responsible for if (y % threads != thread_id) continue; @@ -149,7 +82,7 @@ void camera_iterate_rays_const_dist(Camera camera, int width, int height, int th curr_pt = starting_point; for (int x = 0; x < width; x++) { callback(curr_pt, x, y); - pt_add(&curr_pt, move_right); // move pt right to next pt + curr_pt = pt_add(curr_pt, move_right); // move pt right to next pt } } diff --git a/src/camera.h b/src/camera.h new file mode 100644 index 0000000..b766c3f --- /dev/null +++ b/src/camera.h @@ -0,0 +1,11 @@ +#pragma once + +struct camera { + struct point location; + struct point direction; + unsigned int fov; +}; + +struct camera camera_new(struct point direction, unsigned int fov); +void camera_set_looking_at(struct camera *cam, struct point origin, struct point thing); +void camera_iterate_rays_const_dist(struct camera camera, int width, int height, int threads, void (*callback)(struct point, int, int)); \ No newline at end of file diff --git a/src/point.c b/src/point.c index 1324312..219a70c 100644 --- a/src/point.c +++ b/src/point.c @@ -1,35 +1,27 @@ #include #include - -// basically a vector3 -inline Point pt_new(double x, double y, double z) { - Point pt; - pt.x = x; - pt.y = y; - pt.z = z; - return pt; -} +#include "point.h" // scale vector to length -inline Point pt_scale(Point pt, double length) { +struct point pt_scale(struct point pt, double length) { double f = length / pt_length(pt); - return pt_new( - pt.x * f, - pt.y * f, - pt.z * f - ); + return (struct point) { + .x = pt.x * f, + .y = pt.y * f, + .z = pt.z * f + }; } -inline Point pt_mult(Point pt, double scalar) { - return pt_new( - pt.x * scalar, - pt.y * scalar, - pt.z * scalar - ); +struct point pt_mult(struct point pt, double scalar) { + return (struct point) { + .x = pt.x * scalar, + .y = pt.y * scalar, + .z = pt.z * scalar + }; } // return internal angle between a and b -inline double pt_angle(Point a, Point b) { +double pt_angle(struct point a, struct point b) { return acos(pt_dot( pt_normalize(a), pt_normalize(b) @@ -37,144 +29,77 @@ inline double pt_angle(Point a, Point b) { } // get the length of vector -inline double pt_length(Point pt) { +double pt_length(struct point pt) { return sqrt((pt.x * pt.x) + (pt.y * pt.y) + (pt.z * pt.z)); } // add the vector add to the vector pt -inline void pt_add(Point* pt, Point add) { - pt->x = pt->x + add.x; - pt->y = pt->y + add.y; - pt->z = pt->z + add.z; +struct point pt_add(struct point pt, struct point add) { + return (struct point) { + .x = pt.x + add.x, + .y = pt.y + add.y, + .z = pt.z + add.z, + }; } // add the vector add to the vector pt -inline void pt_sub(Point* pt, Point sub) { - pt->x -= sub.x; - pt->y -= sub.y; - pt->z -= sub.z; +struct point pt_sub(struct point pt, struct point sub) { + return (struct point) { + .x = pt.x - sub.x, + .y = pt.y - sub.y, + .z = pt.z - sub.z, + }; } -inline double pt_dist(Point p1, Point p2) { - pt_sub(&p1, p2); - return pt_length(p1); +double pt_dist(struct point p1, struct point p2) { + return pt_length(pt_sub(p1, p2)); } // normalize a vector -inline Point pt_normalize(Point pt) { +struct point pt_normalize(struct point pt) { return pt_scale(pt, 1); } // dot product of two vectors -inline double pt_dot(Point a, Point b) { +double pt_dot(struct point a, struct point b) { return a.x*b.x + a.y*b.y + a.z*b.z; } // cross product of two vectors -inline Point pt_cross(Point a, Point b) { - return pt_new( - a.y*b.z - a.z*b.y, - a.z*b.x - a.x*b.z, - a.x*b.y - a.y*b.x - ); +struct point pt_cross(struct point a, struct point b) { + return (struct point) { + .x = a.y*b.z - a.z*b.y, + .y = a.z*b.x - a.x*b.z, + .z = a.x*b.y - a.y*b.x + }; } -inline void pt_print(Point pt) { +void pt_print(struct point pt) { printf("(%f, %f, %f)\n", pt.x, pt.y, pt.z); } -inline void pt_print_n(const char* name, Point pt) { +void pt_print_n(const char* name, struct point pt) { printf("%s: (%f, %f, %f)\n", name, pt.x, pt.y, pt.z); } // find two vectors that span the orthogonal plane, where // span_xy is a vector lying on the xy-plane (and pointing left) // and span_z is orthogonal to span_xy pointing "upwards" -void pt_orthogonal_plane(Point pt, Point *span_z, Point *span_xy) { +void pt_orthogonal_plane(struct point pt, struct point *span_z, struct point *span_xy) { pt = pt_normalize(pt); // get the vector lying on the xy axis // this is done by - *span_xy = pt_normalize(pt_cross(pt_new(0,0,1), pt)); // points to the "left" (of the viewing direction) + *span_xy = pt_normalize(pt_cross((struct point){.x = 0, .y = 0, .z = 1}, pt)); // points to the "left" (of the viewing direction) // now use this, to find the vector *span_z = pt_normalize(pt_cross(pt, *span_xy)); } -inline Point pt_mod(Point pt, double mod) { - return pt_new( - fabs(fmod(pt.x, mod)), - fabs(fmod(pt.y, mod)), - fabs(fmod(pt.z, mod)) - ); -} - - -/////////////////////////////// -////// Matrix operations ////// -/////////////////////////////// - - -/* create a new matrix with entries: - x1 x2 x3 - y1 y2 y3 - z1 z2 z3 -*/ -inline Matrix mtrx_new(double x1, double x2, double x3, - double y1, double y2, double y3, - double z1, double z2, double z3) -{ - Matrix m; - m.entries[0] = x1; - m.entries[1] = y1; - m.entries[2] = z1; - m.entries[3] = x2; - m.entries[4] = y2; - m.entries[5] = z2; - m.entries[6] = x3; - m.entries[7] = y3; - m.entries[8] = z3; - return m; -} - -inline Point mtrx_mult(Matrix mtrx, Point pt) { - Point result; - - double *m = mtrx.entries; - - result.x = m[0] * pt.x + m[3] * pt.y + m[6] * pt.z; - result.y = m[1] * pt.x + m[4] * pt.y + m[7] * pt.z; - result.z = m[2] * pt.x + m[5] * pt.y + m[8] * pt.z; - - return result; -} - -// create a rotation matrix around an axis given by the normalized axis vector (u) -// taken from https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle -Matrix mtrx_rotation(Point u, double theta) { - double theta_rad = theta * (M_PI / 180); - double cost = cos(theta_rad); - double sint = sin(theta_rad); - - return mtrx_new( - cost+u.x*u.x*(1-cost), u.x*u.y*(1-cost)-u.z*sint, u.x*u.z*(1-cost)+u.y*sint, - u.y*u.x*(1-cost)+u.z*sint, cost+u.y*u.y*(1-cost), u.y*u.z*(1-cost)-u.x*sint, - u.z*u.x*(1-cost)-u.y*sint, u.z*u.y*(1-cost)+u.x*sint, cost+u.z*u.z*(1-cost) - ); -} - -void mtrx_print(Matrix mtrx) { - printf(" %8.2f %8.2f %8.2f\n %8.2f %8.2f %8.2f\n %8.2f %8.2f %8.2f\n", - mtrx.entries[0], mtrx.entries[3], mtrx.entries[6], - mtrx.entries[1], mtrx.entries[4], mtrx.entries[7], - mtrx.entries[2], mtrx.entries[5], mtrx.entries[8] - ); -} - -inline Matrix mtrx_outer_prod(Point a, Point b) { - return mtrx_new( - a.x*b.x, a.x*b.y, a.x*b.z, - a.y*b.x, a.y*b.y, a.y*b.z, - a.z*b.x, a.z*b.y, a.z*b.z - ); +struct point pt_mod(struct point pt, double mod) { + return (struct point) { + .x = fabs(fmod(pt.x, mod)), + .y = fabs(fmod(pt.y, mod)), + .z = fabs(fmod(pt.z, mod)) + }; } \ No newline at end of file diff --git a/src/point.h b/src/point.h new file mode 100644 index 0000000..69cb378 --- /dev/null +++ b/src/point.h @@ -0,0 +1,25 @@ +#pragma once + + +struct point { + double x; + double y; + double z; +}; + +#define PT_ZERO ((struct point) {.x=0, .y=0, .z=0}) + +struct point pt_scale(struct point pt, double length); +struct point pt_normalize(struct point pt); +struct point pt_mult(struct point pt, double scalar); +double pt_length(struct point pt); +struct point pt_add(struct point pt, struct point add); +struct point pt_sub(struct point pt, struct point sub); +double pt_dist(struct point p1, struct point p2); +struct point pt_mod(struct point pt, double mod); +double pt_dot(struct point a, struct point b); +struct point pt_cross(struct point a, struct point b); +double pt_angle(struct point a, struct point b); +void pt_print(struct point pt); +void pt_print_n(const char* name, struct point pt); +void pt_orthogonal_plane(struct point pt, struct point *span_z, struct point *span_xy); diff --git a/src/scene.c b/src/scene.c index d5525fa..bad4222 100644 --- a/src/scene.c +++ b/src/scene.c @@ -1,34 +1,37 @@ -#include "../images/images.h" +#include "../images/src/images.h" +#include "scene.h" +#include "camera.h" +#include "point.h" #include +#include static Image* current_image; -static Scene* current_scene; -static Camera* current_camera; +static struct scene* current_scene; +static struct camera* current_camera; -Color march_ray(Point origin, Point direction, Scene* scene); -void camera_iter_callback(Point direction, int x, int y); +Color march_ray(struct point origin, struct point direction, struct scene* scene); +void camera_iter_callback(struct point direction, int x, int y); -Scene scene_new(unsigned int width, unsigned int height, int obj_count) { - Scene scene; +struct scene scene_new(unsigned int width, unsigned int height, int obj_count) { + struct scene scene; scene.height = height; scene.width = width; scene.object_count = 0; - scene.objects = malloc(obj_count * sizeof(SceneObject)); + scene.objects = malloc(obj_count * sizeof(struct scene_object)); scene.allocated_space = obj_count; scene.background = color_new(0,0,0); - PerformanceOptimizations perf_opts; - perf_opts.speed_cutoff = 0; - perf_opts.max_steps = 32; - perf_opts.threshold = 0.02; - - scene.perf_opts = perf_opts; + scene.perf_opts = (struct performance_optimization) { + .speed_cutoff = 0, + .max_steps = 32, + .threshold = 0.02 + }; return scene; } -void scene_add_obj(Scene* scene, SceneObject object) { +void scene_add_obj(struct scene * scene, struct scene_object object) { if (scene->object_count >= scene->allocated_space) return; // limit reached // TODO realloc @@ -42,7 +45,7 @@ void scene_add_obj(Scene* scene, SceneObject object) { // render out the scene with threads // creates a shared image, so destroy with image_destroy_shared then free struct with free_shared_memory -Image* render_scene(Scene *scene, Camera *camera, unsigned int threads) { +Image* render_scene(struct scene *scene, struct camera *camera, unsigned int threads) { current_image = malloc(sizeof(Image)); current_scene = scene; current_camera= camera; @@ -59,20 +62,20 @@ Image* render_scene(Scene *scene, Camera *camera, unsigned int threads) { } // march the ray, set the color. repeated for each direction generated by the camera -void camera_iter_callback(Point direction, int x, int y) { +void camera_iter_callback(struct point direction, int x, int y) { Color c = march_ray(current_camera->location, direction, current_scene); image_set_px_c(*current_image, x, y, c); } -Color march_ray(Point origin, Point direction, Scene* scene) { +Color march_ray(struct point origin, struct point direction, struct scene* scene) { // some local variables - Point pos = origin; + struct point pos = origin; double closest_encounter = DBL_MAX; double dist = closest_encounter; // the closest object we have - SceneObject* closest_obj = scene->objects; + struct scene_object* closest_obj = scene->objects; // get steps, threshold from scene int steps = scene->perf_opts.max_steps; @@ -86,7 +89,7 @@ Color march_ray(Point origin, Point direction, Scene* scene) { // find distance to closest object for(int i = 0; i < scene->object_count; i++) { // get pointer to scene obj - SceneObject* obj = scene->objects + i; + struct scene_object* obj = scene->objects + i; double curr_dist = scene->objects[i].distance(pos, obj); // if we are close @@ -104,8 +107,8 @@ Color march_ray(Point origin, Point direction, Scene* scene) { if (dist < closest_encounter) closest_encounter = dist; // scale direction vector to distance, then add it to our position - Point step_vector = pt_scale(direction, dist); - pt_add(&pos, step_vector); + struct point step_vector = pt_scale(direction, dist); + pos = pt_add(pos, step_vector); // one step taken... steps--; @@ -135,7 +138,7 @@ Color march_ray(Point origin, Point direction, Scene* scene) { } } -void scene_destroy(Scene scene) { +void scene_destroy(struct scene scene) { for (int i = 0; i < scene.object_count; i++) { // free args memory free(scene.objects[i].args); diff --git a/src/scene.h b/src/scene.h new file mode 100644 index 0000000..eacad6c --- /dev/null +++ b/src/scene.h @@ -0,0 +1,52 @@ +#pragma once + +#include "point.h" +#include "camera.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +struct scene; + +// Scene objects have a position, some args, and a distance calculation function +// the distance calc function has the following signature: +// double distanceTo(struct point myLocation, double * myArgs, struct point externalPoint) +// where myLocation is this.location, myArgs is this.args and externalPoint is the point from wich we want to know the distance +// the get_color function takes args: point_hit, direction_hit, myArgs, MyLocation, MyColor +struct scene_object { + struct point location; + double * args; + double (*distance)(struct point, struct scene_object *); + Color (*get_color)(struct point, struct point, struct scene_object *); + Color color; + struct scene* scene; +}; + + +struct performance_optimization { + int speed_cutoff; + int max_steps; + double threshold; +}; + + +struct scene { + unsigned int width; + unsigned int height; + struct scene_object * objects; + int object_count; + int allocated_space; + // performance opts + struct performance_optimization perf_opts; + // colors etc + Color background; +}; + +Image* render_scene(struct scene *scene, struct camera *camera, unsigned int threads); + +struct scene scene_new(unsigned int width, unsigned int height, int obj_count); + +void scene_add_obj(struct scene* scene, struct scene_object object); + +void scene_destroy(struct scene scene); \ No newline at end of file