#include #include #include #include "images/src/images.h" #include "src/scene.h" #include "src/camera.h" #include "src/point.h" #define SCENE_MOD 2 /* Infinite circle scene object This circle repeats every SCENE_MOD units in all directions It has some basic shading, calculation the hit angle and making shallower impacts darker */ 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(struct point hit, struct point direction, struct scene_object *self) { struct point obj_direction = self->location; 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; if (angle > 90) angle = 180 - angle ; // clamp angle to 0-90 color = color_mix(color, color_new(0,0,0), 1 - (angle / (double) 120)); return color; } // constructs the scene object 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), }; } /* Mandelbulb scene object Currently cannot be set at a specific location, always resides at origin (0,0,0) Color function is just a flat shader, detail is displayed with ambient occlusion */ double mandelbulb_dist(struct point pt, struct scene_object *self) { int iters = self->args[0]; double power = self->args[1]; struct point z = pt; float dr = 1.0; float r = 0.0; for (int i = 0; i < iters ; i++) { r = pt_length(z); if (r>2) { break; } // convert to polar coordinates float theta = acos(z.z/r); float phi = atan2(z.y,z.x); dr = pow(r, power-1.0)*power*dr + 1.0; // scale and rotate the point float zr = pow(r, power); theta = theta*power; phi = phi*power; // 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(struct point hit, struct point direction, struct scene_object *self) { return self->color; } // constructs the scene object 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 = 200; int threads = 32; int size = dpi * 27.56f; // 400dpi by 70cm size float pow = 3; float cam_position = 1.35; int steps = 1000; int iters = 500; float threshold = 0.001; char path[80]; // get params from cli if (argc < 5) { return 1; } pow = atof(argv[1]); steps = atoi(argv[2]); iters = atoi(argv[3]); threshold = atof(argv[4]); sprintf(path, "tries/pow%.2f-%ist-%iit-%.5fth-%.0fdpi.bmp", pow, steps, iters, threshold, dpi); printf("Rendering to %s\n", path); struct camera cam; cam.fov = 90; 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 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; scene.background = color_new(0,0,0); //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_ZERO, iters, pow)); Image *img = render_scene(&scene, &cam, threads); image_save_bmp(*img, path); image_destroy(*img); scene_destroy(scene); return 0; }