You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.7 KiB
C

#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);
}