summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-12-06 00:56:37 -0500
committerTavian Barnes <tavianator@gmail.com>2011-12-06 15:48:25 -0500
commit5eac8b795c5a44469b749ecb4cf7a68038055b5b (patch)
treebb1f7dd640884f3eb1fa6d1377478536371fb99a
parent7db5342a36341b061a8785a3b349cf0fcad69ebf (diff)
downloaddimension-5eac8b795c5a44469b749ecb4cf7a68038055b5b.tar.xz
Add physics test.
-rw-r--r--libdimension/gl.c18
-rw-r--r--libdimension/png.c18
-rw-r--r--libdimension/rgba16.c10
-rw-r--r--libdimension/tests/Makefile.am6
-rw-r--r--libdimension/tests/physics.c247
-rwxr-xr-xlibdimension/tests/physics.sh4
6 files changed, 279 insertions, 24 deletions
diff --git a/libdimension/gl.c b/libdimension/gl.c
index 1250307..396205b 100644
--- a/libdimension/gl.c
+++ b/libdimension/gl.c
@@ -40,8 +40,8 @@ dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas)
int
dmnsn_gl_write_canvas(const dmnsn_canvas *canvas)
{
- GLushort *pixels; /* Array of 16-bit ints in RGBA order */
- GLushort *pixel;
+ GLubyte *pixels; /* Array of 8-bit ints in RGBA order */
+ GLubyte *pixel;
dmnsn_color color;
size_t width = canvas->width;
@@ -50,13 +50,13 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas)
/* Check if we can optimize this */
DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) {
if (i->optimizer_fn == dmnsn_rgba16_optimizer_fn) {
- glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_SHORT, i->ptr);
+ glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, i->ptr);
return glGetError() == GL_NO_ERROR ? 0 : 1;
}
}
/* We couldn't, so transform the canvas to RGB now */
- pixels = dmnsn_malloc(4*width*height*sizeof(GLushort));
+ pixels = dmnsn_malloc(4*width*height*sizeof(GLubyte));
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
@@ -67,14 +67,14 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas)
color = dmnsn_color_to_sRGB(color);
color = dmnsn_color_saturate(color);
- pixel[0] = lround(color.R*UINT16_MAX);
- pixel[1] = lround(color.G*UINT16_MAX);
- pixel[2] = lround(color.B*UINT16_MAX);
- pixel[3] = lround(color.trans*UINT16_MAX);
+ pixel[0] = lround(color.R*UINT8_MAX);
+ pixel[1] = lround(color.G*UINT8_MAX);
+ pixel[2] = lround(color.B*UINT8_MAX);
+ pixel[3] = lround(color.trans*UINT8_MAX);
}
}
- glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_SHORT, pixels);
+ glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
dmnsn_free(pixels);
return glGetError() == GL_NO_ERROR ? 0 : 1;
diff --git a/libdimension/png.c b/libdimension/png.c
index 7631804..44bf978 100644
--- a/libdimension/png.c
+++ b/libdimension/png.c
@@ -145,7 +145,7 @@ dmnsn_png_write_canvas_thread(void *ptr)
}
/* libpng will longjmp here if it encounters an error from here on */
- uint16_t *row = NULL;
+ uint8_t *row = NULL;
if (setjmp(png_jmpbuf(png_ptr))) {
/* libpng error */
dmnsn_free(row);
@@ -157,8 +157,8 @@ dmnsn_png_write_canvas_thread(void *ptr)
/* Associate file with the libpng write struct */
png_init_io(png_ptr, payload->file);
- /* Set header correctly for 16-bit sRGB image */
- png_set_IHDR(png_ptr, info_ptr, width, height, 16,
+ /* Set header correctly for 8-bit sRGB image */
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
@@ -181,7 +181,7 @@ dmnsn_png_write_canvas_thread(void *ptr)
if (i->optimizer_fn == dmnsn_rgba16_optimizer_fn) {
for (size_t y = 0; y < height; ++y) {
/* Invert the rows. PNG coordinates are fourth quadrant. */
- uint16_t *row = (uint16_t *)i->ptr + 4*(height - y - 1)*width;
+ uint8_t *row = (uint8_t *)i->ptr + 4*(height - y - 1)*width;
png_write_row(png_ptr, (png_bytep)row);
dmnsn_future_increment(payload->future);
}
@@ -195,7 +195,7 @@ dmnsn_png_write_canvas_thread(void *ptr)
}
/* Allocate the temporary row of RGBA values */
- row = dmnsn_malloc(4*sizeof(uint16_t)*width);
+ row = dmnsn_malloc(4*sizeof(uint8_t)*width);
/* Write the pixels */
for (size_t y = 0; y < height; ++y) {
@@ -207,10 +207,10 @@ dmnsn_png_write_canvas_thread(void *ptr)
color = dmnsn_color_to_sRGB(color);
color = dmnsn_color_saturate(color);
- row[4*x] = lround(color.R*UINT16_MAX);
- row[4*x + 1] = lround(color.G*UINT16_MAX);
- row[4*x + 2] = lround(color.B*UINT16_MAX);
- row[4*x + 3] = lround(color.trans*UINT16_MAX);
+ row[4*x] = lround(color.R*UINT8_MAX);
+ row[4*x + 1] = lround(color.G*UINT8_MAX);
+ row[4*x + 2] = lround(color.B*UINT8_MAX);
+ row[4*x + 3] = lround(color.trans*UINT8_MAX);
}
/* Write the row */
diff --git a/libdimension/rgba16.c b/libdimension/rgba16.c
index 980a2d3..5dee049 100644
--- a/libdimension/rgba16.c
+++ b/libdimension/rgba16.c
@@ -49,15 +49,15 @@ void
dmnsn_rgba16_optimizer_fn(const dmnsn_canvas *canvas,
dmnsn_canvas_optimizer optimizer, size_t x, size_t y)
{
- uint16_t *pixel = (uint16_t *)optimizer.ptr + 4*(y*canvas->width + x);
+ uint8_t *pixel = (uint8_t *)optimizer.ptr + 4*(y*canvas->width + x);
dmnsn_color color;
color = dmnsn_canvas_get_pixel(canvas, x, y);
color = dmnsn_remove_filter(color);
color = dmnsn_color_to_sRGB(color);
color = dmnsn_color_saturate(color);
- pixel[0] = lround(color.R*UINT16_MAX);
- pixel[1] = lround(color.G*UINT16_MAX);
- pixel[2] = lround(color.B*UINT16_MAX);
- pixel[3] = lround(color.trans*UINT16_MAX);
+ pixel[0] = lround(color.R*UINT8_MAX);
+ pixel[1] = lround(color.G*UINT8_MAX);
+ pixel[2] = lround(color.B*UINT8_MAX);
+ pixel[3] = lround(color.trans*UINT8_MAX);
}
diff --git a/libdimension/tests/Makefile.am b/libdimension/tests/Makefile.am
index f44cdd6..f4ec515 100644
--- a/libdimension/tests/Makefile.am
+++ b/libdimension/tests/Makefile.am
@@ -28,7 +28,8 @@ check_PROGRAMS = warning.test \
png.test \
gl.test \
render.test \
- cxx.test
+ cxx.test \
+ physics.test
TESTS = $(check_PROGRAMS)
XFAIL_TESTS = warning-as-error.test error.test
@@ -80,5 +81,8 @@ render_test_LDADD = libdimension-tests.la
cxx_test_SOURCES = cxx.cpp
cxx_test_LDADD = libdimension-tests.la
+physics_test_SOURCES = physics.c
+physics_test_LDADD = libdimension-tests.la
+
clean-local:
rm -f *.png
diff --git a/libdimension/tests/physics.c b/libdimension/tests/physics.c
new file mode 100644
index 0000000..14eeb07
--- /dev/null
+++ b/libdimension/tests/physics.c
@@ -0,0 +1,247 @@
+#include "dimension.h"
+#include <math.h>
+
+typedef struct sphere {
+ dmnsn_vector center;
+ dmnsn_vector velocity;
+ double radius;
+ dmnsn_color color;
+} sphere;
+
+sphere
+make_sphere(size_t x, size_t y, size_t z, size_t size)
+{
+ --size;
+
+ double dx = sin(2*M_PI*x/size);
+ double dy = sin(2*M_PI*y/size);
+ double dz = sin(2*M_PI*z/size);
+ dmnsn_vector c = dmnsn_vector_sub(
+ dmnsn_vector_add(
+ dmnsn_vector_mul(
+ 5.0/size,
+ dmnsn_new_vector(x, y, z)
+ ),
+ dmnsn_vector_div(
+ dmnsn_new_vector(dy + dz, dx + dz, dx + dy),
+ 4.0
+ )
+ ),
+ dmnsn_new_vector(2.5, 2.5, 2.5)
+ );
+
+ double r = 2.0/size;
+
+ dmnsn_color color = dmnsn_color_from_sRGB(
+ dmnsn_new_color((double)x/size, (double)y/size, (double)z/size)
+ );
+
+ sphere s = {
+ .center = c,
+ .velocity = dmnsn_zero,
+ .radius = r,
+ .color = color,
+ };
+ return s;
+}
+
+dmnsn_array *
+make_spheres()
+{
+ const size_t size = 10;
+ dmnsn_array *spheres = dmnsn_new_array(sizeof(sphere));
+ for (size_t x = 0; x < size; ++x) {
+ for (size_t y = 0; y < size; ++y) {
+ for (size_t z = 0; z < size; ++z) {
+ sphere s = make_sphere(x, y, z, size);
+ dmnsn_array_push(spheres, &s);
+ }
+ }
+ }
+
+ return spheres;
+}
+
+dmnsn_scene *
+make_scene(dmnsn_array *spheres, dmnsn_canvas *canvas, dmnsn_camera *camera)
+{
+ dmnsn_scene *scene = dmnsn_new_scene();
+ DMNSN_INCREF(canvas);
+ scene->canvas = canvas;
+ DMNSN_INCREF(camera);
+ scene->camera = camera;
+
+ scene->default_texture->pigment = dmnsn_new_solid_pigment(dmnsn_black);
+ scene->default_texture->finish.ambient = dmnsn_new_basic_ambient(
+ dmnsn_color_from_sRGB(dmnsn_color_mul(0.25, dmnsn_white))
+ );
+ scene->default_texture->finish.diffuse = dmnsn_new_lambertian(
+ dmnsn_sRGB_inverse_gamma(0.8)
+ );
+
+ scene->background = dmnsn_new_solid_pigment(
+ dmnsn_color_from_sRGB(
+ dmnsn_color_mul(0.5, dmnsn_new_color(0.73, 0.90, 0.97))
+ )
+ );
+
+ DMNSN_ARRAY_FOREACH (sphere *, s, spheres) {
+ dmnsn_object *sph = dmnsn_new_sphere();
+
+ sph->texture = dmnsn_new_texture();
+ sph->texture->pigment = dmnsn_new_solid_pigment(s->color);
+ double maxcomponent = dmnsn_max(
+ dmnsn_max(s->color.R, s->color.G),
+ s->color.B
+ );
+ dmnsn_color reflcolor;
+ if (maxcomponent >= dmnsn_epsilon) {
+ reflcolor = dmnsn_color_mul(0.5/maxcomponent, s->color);
+ } else {
+ reflcolor = dmnsn_color_mul(0.25, dmnsn_white);
+ }
+ sph->texture->finish.reflection = dmnsn_new_basic_reflection(
+ dmnsn_black, reflcolor, 1.0
+ );
+
+ sph->trans = dmnsn_matrix_mul(
+ dmnsn_translation_matrix(s->center),
+ dmnsn_scale_matrix(dmnsn_new_vector(s->radius, s->radius, s->radius))
+ );
+
+ dmnsn_array_push(scene->objects, &sph);
+ }
+
+ dmnsn_object *plane = dmnsn_new_plane(dmnsn_y);
+ plane->trans = dmnsn_translation_matrix(dmnsn_vector_mul(-4.0, dmnsn_y));
+ plane->texture = dmnsn_new_texture();
+ plane->texture->pigment = dmnsn_new_solid_pigment(
+ dmnsn_color_from_sRGB(dmnsn_new_color(0.73, 0.90, 0.97))
+ );
+ plane->texture->finish.ambient = dmnsn_new_basic_ambient(
+ dmnsn_color_from_sRGB(dmnsn_color_mul(0.5, dmnsn_white))
+ );
+ plane->texture->finish.diffuse = dmnsn_new_lambertian(
+ dmnsn_sRGB_inverse_gamma(0.7)
+ );
+ dmnsn_array_push(scene->objects, &plane);
+
+ dmnsn_color lcolor = dmnsn_color_mul(1.0/4.0, dmnsn_white);
+ dmnsn_light *light;
+ light = dmnsn_new_point_light(dmnsn_new_vector(-3.0, 0.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+ light = dmnsn_new_point_light(dmnsn_new_vector(-1.0, 0.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+ light = dmnsn_new_point_light(dmnsn_new_vector(+1.0, 0.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+ light = dmnsn_new_point_light(dmnsn_new_vector(+3.0, 0.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+ light = dmnsn_new_point_light(dmnsn_new_vector(-3.0, 5.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+ light = dmnsn_new_point_light(dmnsn_new_vector(-1.0, 5.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+ light = dmnsn_new_point_light(dmnsn_new_vector(+1.0, 5.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+ light = dmnsn_new_point_light(dmnsn_new_vector(+3.0, 5.0, -5.0), lcolor);
+ dmnsn_array_push(scene->lights, &light);
+
+ scene->nthreads = 12; /* XXX */
+ return scene;
+}
+
+void
+integrate_spheres(dmnsn_array *spheres, double h)
+{
+ static const double g = 5.0;
+
+ /* Inter-object collision detection */
+ DMNSN_ARRAY_FOREACH (sphere *, s1, spheres) {
+ DMNSN_ARRAY_FOREACH (sphere *, s2, spheres) {
+ if (s1 == s2) continue;
+
+ dmnsn_vector deltar = dmnsn_vector_sub(s1->center, s2->center);
+ dmnsn_vector deltav = dmnsn_vector_sub(s1->velocity, s2->velocity);
+ if (dmnsn_vector_norm(deltar) <= s1->radius + s2->radius
+ && dmnsn_vector_dot(deltar, deltav) < 0.0)
+ {
+ dmnsn_vector x = dmnsn_vector_normalized(deltar);
+ dmnsn_vector v1 = s1->velocity;
+ double x1 = dmnsn_vector_dot(x, v1);
+ dmnsn_vector v1x = dmnsn_vector_mul(x1, x);
+ dmnsn_vector v1y = dmnsn_vector_sub(v1, v1x);
+
+ x = dmnsn_vector_negate(x);
+ dmnsn_vector v2 = s2->velocity;
+ double x2 = dmnsn_vector_dot(x, v2);
+ dmnsn_vector v2x = dmnsn_vector_mul(x2, x);
+ dmnsn_vector v2y = dmnsn_vector_sub(v2, v2x);
+
+ s1->velocity = dmnsn_vector_add(v2x, v1y);
+ s2->velocity = dmnsn_vector_add(v1x, v2y);
+ }
+ }
+ }
+
+ /* Floor collision detection */
+ DMNSN_ARRAY_FOREACH (sphere *, s, spheres) {
+ if (s->center.y - s->radius <= -4.0) {
+ s->velocity.y = fabs(s->velocity.y);
+ }
+ }
+
+ /* Advance by the timestep */
+ DMNSN_ARRAY_FOREACH (sphere *, s, spheres) {
+ s->center = dmnsn_vector_add(s->center, dmnsn_vector_mul(h, s->velocity));
+ s->center.y -= g*h*h/2.0;
+ s->velocity.y -= g*h;
+ }
+}
+
+int
+main()
+{
+ dmnsn_die_on_warnings(true);
+
+ const double h = 1.0/25.0;
+ const int nframes = 401;
+ const size_t width = 1920, height = 1080;
+
+ dmnsn_array *spheres = make_spheres();
+
+ dmnsn_canvas *canvas = dmnsn_new_canvas(width, height);
+ dmnsn_png_optimize_canvas(canvas);
+
+ dmnsn_camera *camera = dmnsn_new_perspective_camera();
+ camera->trans = dmnsn_new_matrix(
+ 1.7151356822004125, -0.12253122769681897, -0.2328451577118997, 3.0,
+ 0.0, 0.8849477555881373, -0.4656903154237999, 6.0,
+ 0.46776427696374845, 0.4492811682216699, 0.8537655782769662, -11.0
+ );
+
+ for (int i = 0; i < nframes; ++i) {
+ if (i > 0) {
+ printf("Frame %d:\t Integrating\n", i);
+ static const int precision = 100;
+ for (int j = 0; j < precision; ++j)
+ integrate_spheres(spheres, h/precision);
+ }
+
+ printf("Frame %d:\t Rendering\n", i);
+ dmnsn_scene *scene = make_scene(spheres, canvas, camera);
+ dmnsn_ray_trace(scene);
+
+ printf("Frame %d:\t Exporting\n", i);
+ char fname[] = "physics00000.png";
+ sprintf(fname, "physics%05d.png", i);
+ FILE *image = fopen(fname, "wb");
+ dmnsn_png_write_canvas(canvas, image);
+ fclose(image);
+
+ dmnsn_delete_scene(scene);
+ }
+
+ dmnsn_delete_camera(camera);
+ dmnsn_delete_canvas(canvas);
+ dmnsn_delete_array(spheres);
+ return 0;
+}
diff --git a/libdimension/tests/physics.sh b/libdimension/tests/physics.sh
new file mode 100755
index 0000000..da07873
--- /dev/null
+++ b/libdimension/tests/physics.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+ffmpeg -f image2 -i libdimension/tests/physics%05d.png -vcodec libx264 -preset medium -qp 0 -threads 12 physics.mkv
+ffmpeg -i physics.mkv -s 1920x1080 -sameq -threads 12 physics1080.mkv