-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
146 lines (107 loc) · 3.58 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <math.h>
#include "images/images.h"
#include "marcher.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(Point x, SceneObject *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;
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
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;
}
/*
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(Point pt, SceneObject *self) {
int iters = self->args[0];
double power = self->args[1];
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
z = pt_mult(pt_new(sin(theta)*cos(phi), sin(phi)*sin(theta), cos(theta)), zr);
pt_add(&z, pt);
}
return 0.5*log(r)*r/dr;
}
Color mandelbulb_color(Point hit, Point direction, SceneObject *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;
}
int main(int argc, char* argv[]) {
int threads = 12;
float pow = 1;
Camera cam;
cam.fov = 90;
float cam_position = 1.5;
camera_set_looking_at(&cam, pt_new(cam_position,cam_position,cam_position), pt_new(0,0,0));
// get thread count from command line
if (argc < 3) {
return 1;
}
pow = atof(argv[1]);
printf("threads: %d\n", threads);
printf("pow: %f\n", pow);
// create basic scene with up to 10 objects
Scene scene = scene_new(1080, 1080, 1);
scene.perf_opts.max_steps = 1000;
scene.perf_opts.threshold = 0.0001;
scene.perf_opts.speed_cutoff = 5;
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_new(1,1,1), 200, pow));
Image *img = render_scene(&scene, &cam, threads);
image_save_bmp(*img, argv[2]);
image_destroy_shared(*img);
scene_destroy(scene);
return 0;
}