*/
#include <cerrno>
+#include <cmath>
+#include "contact.hh"
#include "light.hh"
-#include "list.hh"
+#include "plane.hh"
+#include "sphere.hh"
+#include "triangle.hh"
#include "vec.hh"
#include "scene.hh"
static int _scene_add_light(scene_t* s, FILE* file);
static int _scene_add_sphere(scene_t* s, FILE* file);
static int _scene_add_plane(scene_t* s, FILE* file);
+static int _scene_add_triangle(scene_t* s, FILE* file);
struct scene
{
int w, h;
vec_t eye;
- vec_t spot;
- vec_t up;
+ vec_t screenCenter;
+ vec_t screenU;
+ vec_t screenV;
list_t* lights;
- list_t* spheres;
- list_t* planes;
+ list_t* objects;
color_t ambient;
};
return NULL;
}
+ vec_t eye = vec_new(eyeX, eyeY, eyeZ);
+ vec_t spot = vec_new(spotX, spotY, spotZ);
+ vec_t up = vec_new(upX, upY, upZ);
+ scal_t d = S(1.0) / scal_tan((scal_t)fovy * S(0.5));
+
+ vec_t look = vec_normalize(vec_sub(spot, eye));
+ vec_t screenCenter = vec_scale(look, d);
+ vec_t screenU = vec_normalize(vec_cross(look, up));
+ vec_t screenV = vec_cross(screenU, look);
+ screenU = vec_scale(screenU, (scal_t)aspect);
+
scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t));
s->w = w;
s->h = h;
- s->eye = vec_new(eyeX, eyeY, eyeZ);
- s->spot = vec_new(spotX, spotY, spotZ);
- s->up = vec_new(upX, upY, upZ);
- // what to do with fovy and aspect...
+ s->eye = eye;
+ s->screenCenter = screenCenter;
+ s->screenU = screenU;
+ s->screenV = screenV;
s->lights = NULL;
- s->spheres = NULL;
- s->planes = NULL;
+ s->objects = NULL;
s->ambient = color_new((scal_t)aR, (scal_t)aG, (scal_t)aB, S(1.0));
char type;
}
break;
+ case 't':
+ if (_scene_add_triangle(s, file) != 0) {
+ goto fail;
+ }
+ break;
+
case 'X':
goto done;
fprintf(stderr, "Unknown identifier: %c\n", type);
}
}
-#undef _ASSERT_G
done:
- if (s->spheres) list_reverse(&s->spheres);
- if (s->planes) list_reverse(&s->planes);
+ if (s->objects) list_reverse(&s->objects);
return s;
fail:
void scene_destroy(scene_t* s)
{
if (s->lights) list_destroy(&s->lights);
- if (s->spheres) list_destroy(&s->spheres);
- if (s->planes) list_destroy(&s->planes);
+ if (s->objects) list_destroy(&s->objects);
mem_free(s);
}
}
light_t* l = light_alloc(
vec_new(lx, ly, lz),
- color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)),
color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
);
list_push2(&s->lights, l, mem_free);
fprintf(stderr, "Cannot read sphere values from scene.\n");
return -1;
}
- /*list_push2(&s->spheres, s, mem_free);*/
+ rt::element* sphere = new rt::sphere(
+ vec_new((scal_t)x, (scal_t)y, (scal_t)z),
+ (scal_t)radius,
+ color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
+ );
+ list_push2(&s->objects, sphere, DTOR(rt::sphere_destroy));
return 0;
}
fprintf(stderr, "Cannot read plane values from scene.\n");
return -1;
}
- /*list_push2(&s->planes, s, mem_free);*/
+ rt::element* plane = new rt::plane(
+ vec_new((scal_t)x, (scal_t)y, (scal_t)z),
+ vec_new((scal_t)nx, (scal_t)ny, (scal_t)nz),
+ color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
+ );
+ list_push2(&s->objects, plane, DTOR(rt::plane_destroy));
+ return 0;
+}
+
+static int _scene_add_triangle(scene_t* s, FILE* file)
+{
+ double x1, y1, z1, x2, y2, z2, x3, y3, z3, r, g, b;
+ if (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
+ &x1, &y1, &z1, &x2, &y2, &z2, &x3, &y3, &z3, &r, &g, &b) != 12) {
+ fprintf(stderr, "Cannot read triangle values from scene.\n");
+ return -1;
+ }
+ rt::element* triangle = new rt::triangle(
+ vec_new((scal_t)x1, (scal_t)y1, (scal_t)z1),
+ vec_new((scal_t)x2, (scal_t)y2, (scal_t)z2),
+ vec_new((scal_t)x3, (scal_t)y3, (scal_t)z3),
+ color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
+ );
+ list_push2(&s->objects, triangle, DTOR(rt::triangle_destroy));
return 0;
}
-raster_t* scene_render(scene_t* s)
+list_t* scene_elements(const scene_t* s)
+{
+ return s->objects;
+}
+
+list_t* scene_lights(const scene_t* s)
+{
+ return s->lights;
+}
+
+color_t scene_ambient(const scene_t* s)
+{
+ return s->ambient;
+}
+
+
+raster_t* scene_render(const scene_t* s)
{
#if VERBOSITY >= 3
timer_start();
printf("rendering scene...\n");
#endif
- // RENDER IT
+ scal_t wh = S(2.0) / (scal_t)s->w;
+ scal_t hh = S(2.0) / (scal_t)s->h;
+
+ for (int y = 0; y < s->h; ++y) {
+ for (int x = 0; x < s->w; ++x) {
+ color_t* pixel = raster_color(p, x, y);
+ scal_t u = (scal_t)x * wh - S(1.0);
+ scal_t v = (scal_t)y * hh - S(1.0);
+ vec_t rayDirection = vec_add2(s->screenCenter,
+ vec_scale(s->screenU, u), vec_scale(s->screenV, v));
+
+ ray_t ray = ray_normalize(ray_new(s->eye, rayDirection));
+
+ rt::element* nearestObj = 0;
+ contact_t nearestHit;
+
+ // find the nearest object along the ray
+ for (list_t* i = s->objects; i; i = i->link) {
+ rt::element* obj = (rt::element*)i->val;
+ contact_t hit;
+ if (obj->intersect(ray, hit) && (!nearestObj || hit.d < nearestHit.d)) {
+ nearestObj = obj;
+ nearestHit = hit;
+ }
+ }
+
+ if (nearestObj) {
+ *pixel = nearestObj->cast(nearestHit, s);
+ }
+ }
+ }
#if VERBOSITY >= 3
long dt = timer_stop();