|
|
|
#include "../marcher.h"
|
|
|
|
#include "../images/images.h"
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
static Image* current_image;
|
|
|
|
static Scene* current_scene;
|
|
|
|
static Camera* current_camera;
|
|
|
|
|
|
|
|
Color march_ray(Point origin, Point direction, Scene* scene);
|
|
|
|
void camera_iter_callback(Point direction, int x, int y);
|
|
|
|
|
|
|
|
|
|
|
|
Scene scene_new(unsigned int width, unsigned int height, int obj_count) {
|
|
|
|
Scene scene;
|
|
|
|
scene.height = height;
|
|
|
|
scene.width = width;
|
|
|
|
scene.max_steps = 32;
|
|
|
|
scene.threshold = 0.02;
|
|
|
|
scene.object_count = 0;
|
|
|
|
scene.objects = malloc(obj_count * sizeof(SceneObject));
|
|
|
|
scene.allocated_space = obj_count;
|
|
|
|
scene.background = color_new(0,0,0);
|
|
|
|
return scene;
|
|
|
|
}
|
|
|
|
|
|
|
|
void scene_add_obj(Scene* scene, SceneObject object) {
|
|
|
|
if (scene->object_count >= scene->allocated_space) return; // limit reached
|
|
|
|
// TODO realloc
|
|
|
|
|
|
|
|
|
|
|
|
scene->objects[scene->object_count] = object;
|
|
|
|
// link containing scene
|
|
|
|
scene->objects[scene->object_count].scene = scene;
|
|
|
|
|
|
|
|
scene->object_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
current_image = malloc(sizeof(Image));
|
|
|
|
current_scene = scene;
|
|
|
|
current_camera= camera;
|
|
|
|
|
|
|
|
// initialize shared pixel buffer
|
|
|
|
image_new_shared(scene->width, scene->height, current_image);
|
|
|
|
|
|
|
|
// iterate over the rays
|
|
|
|
camera_iterate_rays_const_dist(*camera, scene->width, scene->height, threads, camera_iter_callback);
|
|
|
|
// or camera_iterate_rays_const_angle for lense distortion (this might not work correctly tho)
|
|
|
|
|
|
|
|
// return the drawn image
|
|
|
|
return current_image;
|
|
|
|
}
|
|
|
|
|
|
|
|
// march the ray, set the color. repeated for each direction generated by the camera
|
|
|
|
void camera_iter_callback(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) {
|
|
|
|
// some local variables
|
|
|
|
Point pos = origin;
|
|
|
|
double closest_encounter = DBL_MAX;
|
|
|
|
double dist = closest_encounter;
|
|
|
|
// the closest object we have
|
|
|
|
SceneObject* closest_obj = scene->objects;
|
|
|
|
|
|
|
|
// get steps, threshold from scene
|
|
|
|
int steps = scene->max_steps;
|
|
|
|
double threshold = scene->threshold;
|
|
|
|
|
|
|
|
// as long as we did not max out steps, or got very close to an object
|
|
|
|
while (steps > 0 && dist > threshold) {
|
|
|
|
dist = 100;
|
|
|
|
|
|
|
|
// find distance to closest object
|
|
|
|
for(int i = 0; i < scene->object_count; i++) {
|
|
|
|
// get pointer to scene obj
|
|
|
|
SceneObject* obj = scene->objects + i;
|
|
|
|
double curr_dist = scene->objects[i].distance(pos, obj);
|
|
|
|
|
|
|
|
// if we are close
|
|
|
|
if (curr_dist < dist) {
|
|
|
|
dist = curr_dist;
|
|
|
|
closest_obj = obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// write down our closest encounter
|
|
|
|
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);
|
|
|
|
|
|
|
|
// one step taken...
|
|
|
|
steps--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for a hit
|
|
|
|
if (dist <= threshold) {
|
|
|
|
// a hit!
|
|
|
|
double f = (steps / (double) scene->max_steps);
|
|
|
|
f = f * f * f * f;
|
|
|
|
|
|
|
|
Color c = closest_obj->get_color(pos, direction, closest_obj);
|
|
|
|
return color_mix(c, color_new(0,0,0), f);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// a miss :(
|
|
|
|
// this should be 0!
|
|
|
|
return scene->background;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void scene_destroy(Scene scene) {
|
|
|
|
for (int i = 0; i < scene.object_count; i++) {
|
|
|
|
// free args memory
|
|
|
|
free(scene.objects[i].args);
|
|
|
|
}
|
|
|
|
free(scene.objects);
|
|
|
|
|
|
|
|
}
|