summaryrefslogtreecommitdiffstats
path: root/jni/jni.c
diff options
context:
space:
mode:
Diffstat (limited to 'jni/jni.c')
-rw-r--r--jni/jni.c386
1 files changed, 386 insertions, 0 deletions
diff --git a/jni/jni.c b/jni/jni.c
new file mode 100644
index 0000000..d12dd01
--- /dev/null
+++ b/jni/jni.c
@@ -0,0 +1,386 @@
+/*************************************************************************
+ * Copyright (C) 2010-2011 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This file is part of The Dimension Android Binding. *
+ * *
+ * The Dimension Android Binding is free software; you can redistribute *
+ * it and/or modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Android Binding is distributed in the hope that it will *
+ * be useful, but WITHOUT ANY WARRANTY; without even the implied *
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See *
+ * the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+/**
+ * @file
+ * Java interface to libdimension used by Android.
+ */
+
+#include "dimension-internal.h"
+#include <jni.h>
+#include <android/log.h>
+#include <stdint.h>
+#include <limits.h>
+
+#define TAG "libdimension_jni"
+
+static void
+dmnsn_test_scene_set_defaults(dmnsn_scene *scene)
+{
+ /* Default texture */
+ scene->default_texture->pigment =
+ dmnsn_new_solid_pigment(DMNSN_TCOLOR(dmnsn_black));
+ dmnsn_finish *default_finish = &scene->default_texture->finish;
+ default_finish->ambient = dmnsn_new_ambient(
+ dmnsn_color_from_sRGB(dmnsn_color_mul(0.1, dmnsn_white))
+ );
+ default_finish->diffuse = dmnsn_new_lambertian(dmnsn_sRGB_inverse_gamma(0.7));
+}
+
+static void
+dmnsn_test_scene_add_canvas(dmnsn_scene *scene, size_t width, size_t height)
+{
+ scene->canvas = dmnsn_new_canvas(width, height);
+}
+
+static void
+dmnsn_test_scene_add_camera(dmnsn_scene *scene)
+{
+ /* Set up the transformation matrix for the perspective camera */
+ dmnsn_matrix trans = dmnsn_scale_matrix(
+ dmnsn_new_vector(
+ ((double)scene->canvas->width)/scene->canvas->height, 1.0, 1.0
+ )
+ );
+ trans = dmnsn_matrix_mul(
+ dmnsn_rotation_matrix(dmnsn_new_vector(0.0624188099959577, 0.0, 0.0)),
+ trans
+ );
+ trans = dmnsn_matrix_mul(
+ dmnsn_translation_matrix(dmnsn_new_vector(0.0, 0.25, -4.0)),
+ trans
+ );
+ trans = dmnsn_matrix_mul(
+ dmnsn_rotation_matrix(dmnsn_new_vector(0.0, dmnsn_radians(53.0), 0.0)),
+ trans
+ );
+
+ /* Create a perspective camera */
+ scene->camera = dmnsn_new_perspective_camera();
+ scene->camera->trans = trans;
+}
+
+static void
+dmnsn_test_scene_add_background(dmnsn_scene *scene)
+{
+ scene->background = dmnsn_new_solid_pigment(dmnsn_clear);
+}
+
+static void
+dmnsn_test_scene_add_lights(dmnsn_scene *scene)
+{
+ dmnsn_light *light = dmnsn_new_point_light(
+ dmnsn_new_vector(-15.0, 20.0, 10.0),
+ dmnsn_white
+ );
+ dmnsn_array_push(scene->lights, &light);
+}
+
+static void
+dmnsn_test_scene_add_hollow_cube(dmnsn_scene *scene)
+{
+ dmnsn_object *cube = dmnsn_new_cube();
+ cube->trans = dmnsn_rotation_matrix(
+ dmnsn_new_vector(dmnsn_radians(45.0), 0.0, 0.0)
+ );
+
+ cube->texture = dmnsn_new_texture();
+ dmnsn_tcolor cube_color = dmnsn_new_tcolor(dmnsn_blue, 0.75, 1.0/3.0);
+ cube->texture->pigment = dmnsn_new_solid_pigment(cube_color);
+
+ dmnsn_color reflect =
+ dmnsn_color_from_sRGB(dmnsn_color_mul(0.5, dmnsn_white));
+ cube->texture->finish.reflection =
+ dmnsn_new_basic_reflection(dmnsn_black, reflect, 1.0);
+
+ cube->interior = dmnsn_new_interior();
+ cube->interior->ior = 1.1;
+
+ dmnsn_object *sphere = dmnsn_new_sphere();
+ sphere->texture = dmnsn_new_texture();
+ sphere->texture->pigment = dmnsn_new_solid_pigment(DMNSN_TCOLOR(dmnsn_green));
+ sphere->texture->finish.specular =
+ dmnsn_new_phong(dmnsn_sRGB_inverse_gamma(0.2), 40.0);
+ sphere->trans = dmnsn_scale_matrix(dmnsn_new_vector(1.25, 1.25, 1.25));
+
+ dmnsn_object *hollow_cube = dmnsn_new_csg_difference(cube, sphere);
+ dmnsn_array_push(scene->objects, &hollow_cube);
+}
+
+#define dmnsn_pigment_map_add_color(map, n, color) \
+ do { \
+ dmnsn_tcolor tcolor = DMNSN_TCOLOR(color); \
+ dmnsn_pigment *pigment = dmnsn_new_solid_pigment(tcolor); \
+ dmnsn_map_add_entry(map, n, &pigment); \
+ } while (0)
+
+static void
+dmnsn_test_scene_add_spike(dmnsn_scene *scene)
+{
+ dmnsn_array *arrow_array = dmnsn_new_array(sizeof(dmnsn_object *));
+
+ dmnsn_object *cylinder = dmnsn_new_cone(0.1, 0.1, false);
+ cylinder->trans = dmnsn_scale_matrix(dmnsn_new_vector(1.0, 1.25, 1.0));
+ dmnsn_array_push(arrow_array, &cylinder);
+
+ dmnsn_object *cone = dmnsn_new_cone(0.1, 0.0, true);
+ cone->trans = dmnsn_matrix_mul(
+ dmnsn_translation_matrix(dmnsn_new_vector(0.0, 1.375, 0.0)),
+ dmnsn_scale_matrix(dmnsn_new_vector(1.0, 0.125, 1.0))
+ );
+ dmnsn_array_push(arrow_array, &cone);
+
+ dmnsn_object *arrow = dmnsn_new_csg_union(arrow_array);
+ dmnsn_delete_array(arrow_array);
+ dmnsn_pattern *gradient = dmnsn_new_gradient_pattern(dmnsn_y);
+ dmnsn_map *gradient_pigment_map = dmnsn_new_pigment_map();
+ dmnsn_pigment_map_add_color(gradient_pigment_map, 0.0, dmnsn_red);
+ dmnsn_pigment_map_add_color(gradient_pigment_map, 1.0/6.0, dmnsn_orange);
+ dmnsn_pigment_map_add_color(gradient_pigment_map, 2.0/6.0, dmnsn_yellow);
+ dmnsn_pigment_map_add_color(gradient_pigment_map, 3.0/6.0, dmnsn_green);
+ dmnsn_pigment_map_add_color(gradient_pigment_map, 4.0/6.0, dmnsn_blue);
+ dmnsn_pigment_map_add_color(gradient_pigment_map, 5.0/6.0, dmnsn_magenta);
+ dmnsn_pigment_map_add_color(gradient_pigment_map, 1.0, dmnsn_red);
+ arrow->texture = dmnsn_new_texture();
+ arrow->texture->pigment =
+ dmnsn_new_pigment_map_pigment(gradient, gradient_pigment_map,
+ DMNSN_PIGMENT_MAP_SRGB);
+
+ arrow->texture->trans =
+ dmnsn_matrix_mul(
+ dmnsn_translation_matrix(dmnsn_new_vector(0.0, -1.25, 0.0)),
+ dmnsn_scale_matrix(dmnsn_new_vector(1.0, 2.75, 1.0))
+ );
+
+ dmnsn_array *torus_array = dmnsn_new_array(sizeof(dmnsn_object *));
+
+ dmnsn_object *torus1 = dmnsn_new_torus(0.15, 0.05);
+ torus1->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, -1.0, 0.0));
+ dmnsn_array_push(torus_array, &torus1);
+
+ dmnsn_object *torus2 = dmnsn_new_torus(0.15, 0.05);
+ dmnsn_array_push(torus_array, &torus2);
+
+ dmnsn_object *torus3 = dmnsn_new_torus(0.15, 0.05);
+ torus3->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, 1.0, 0.0));
+ dmnsn_array_push(torus_array, &torus3);
+
+ dmnsn_object *torii = dmnsn_new_csg_union(torus_array);
+ dmnsn_delete_array(torus_array);
+ torii->texture = dmnsn_new_texture();
+ torii->texture->pigment = dmnsn_new_solid_pigment(DMNSN_TCOLOR(dmnsn_blue));
+ torii->texture->finish.ambient = dmnsn_new_ambient(dmnsn_white);
+
+ dmnsn_array *spike_array = dmnsn_new_array(sizeof(dmnsn_object *));
+ dmnsn_array_push(spike_array, &arrow);
+ dmnsn_array_push(spike_array, &torii);
+ dmnsn_object *spike = dmnsn_new_csg_union(spike_array);
+ dmnsn_delete_array(spike_array);
+ spike->trans = dmnsn_rotation_matrix(
+ dmnsn_new_vector(dmnsn_radians(-45.0), 0.0, 0.0)
+ );
+ dmnsn_array_push(scene->objects, &spike);
+}
+
+static void
+dmnsn_test_scene_add_triangle_strip(dmnsn_scene *scene)
+{
+ dmnsn_array *strip_array = dmnsn_new_array(sizeof(dmnsn_object *));
+ dmnsn_vector a = dmnsn_zero;
+ dmnsn_vector b = dmnsn_new_vector(0.0, sqrt(3.0)/2.0, 0.5);
+ dmnsn_vector c = dmnsn_z;
+ dmnsn_texture *strip_textures[3] = {
+ dmnsn_new_texture(),
+ dmnsn_new_texture(),
+ dmnsn_new_texture(),
+ };
+ strip_textures[0]->pigment =
+ dmnsn_new_solid_pigment(DMNSN_TCOLOR(dmnsn_red));
+ strip_textures[1]->pigment =
+ dmnsn_new_solid_pigment(DMNSN_TCOLOR(dmnsn_orange));
+ strip_textures[2]->pigment =
+ dmnsn_new_solid_pigment(DMNSN_TCOLOR(dmnsn_yellow));
+ for (unsigned int i = 0; i < 128; ++i) {
+ dmnsn_object *triangle = dmnsn_new_flat_triangle(a, b, c);
+ triangle->texture = strip_textures[i%3];
+ DMNSN_INCREF(triangle->texture);
+ dmnsn_array_push(strip_array, &triangle);
+
+ a = b;
+ b = c;
+ c = dmnsn_vector_add(a, dmnsn_z);
+ }
+ for (unsigned int i = 0; i < 3; ++i) {
+ dmnsn_delete_texture(strip_textures[i]);
+ }
+
+ dmnsn_object *strip = dmnsn_new_csg_union(strip_array);
+ dmnsn_delete_array(strip_array);
+ strip->trans = dmnsn_translation_matrix(dmnsn_new_vector(5.0, -2.0, -4.0));
+ dmnsn_array_push(scene->objects, &strip);
+}
+
+static void
+dmnsn_test_scene_add_ground(dmnsn_scene *scene)
+{
+ dmnsn_object *plane = dmnsn_new_plane(dmnsn_new_vector(0.0, 1.0, 0.0));
+ plane->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, -2.0, 0.0));
+ dmnsn_pattern *checker1 = dmnsn_new_checker_pattern();
+ dmnsn_pattern *checker2 = dmnsn_new_checker_pattern();
+ dmnsn_map *small_map = dmnsn_new_pigment_map();
+ dmnsn_pigment_map_add_color(small_map, 0.0, dmnsn_black);
+ dmnsn_pigment_map_add_color(small_map, 1.0, dmnsn_white);
+ dmnsn_pigment *small_pigment =
+ dmnsn_new_pigment_map_pigment(checker1, small_map,
+ DMNSN_PIGMENT_MAP_REGULAR);
+ small_pigment->trans =
+ dmnsn_scale_matrix(dmnsn_new_vector(1.0/3.0, 1.0/3.0, 1.0/3.0));
+ dmnsn_map *big_map = dmnsn_new_pigment_map();
+ dmnsn_pigment_map_add_color(big_map, 0.0, dmnsn_white);
+ dmnsn_map_add_entry(big_map, 1.0, &small_pigment);
+ plane->texture = dmnsn_new_texture();
+ plane->texture->pigment =
+ dmnsn_new_pigment_map_pigment(checker2, big_map, DMNSN_PIGMENT_MAP_REGULAR);
+ plane->texture->pigment->quick_color = DMNSN_TCOLOR(
+ dmnsn_color_from_sRGB(
+ dmnsn_new_color(1.0, 0.5, 0.75)
+ )
+ );
+ dmnsn_array_push(scene->objects, &plane);
+}
+
+static void
+dmnsn_test_scene_add_objects(dmnsn_scene *scene)
+{
+ dmnsn_test_scene_add_hollow_cube(scene);
+ dmnsn_test_scene_add_spike(scene);
+ dmnsn_test_scene_add_triangle_strip(scene);
+ dmnsn_test_scene_add_ground(scene);
+}
+
+/*
+ * Test scene
+ */
+static dmnsn_scene *
+dmnsn_new_test_scene(size_t width, size_t height)
+{
+ dmnsn_scene *scene = dmnsn_new_scene();
+ dmnsn_test_scene_set_defaults(scene);
+ dmnsn_test_scene_add_canvas(scene, width, height);
+ dmnsn_test_scene_add_camera(scene);
+ dmnsn_test_scene_add_background(scene);
+ dmnsn_test_scene_add_lights(scene);
+ dmnsn_test_scene_add_objects(scene);
+ return scene;
+}
+
+static JavaVM *jvm;
+static jobject shared_obj;
+static jclass shared_cls;
+static jmethodID method;
+
+static dmnsn_scene *scene;
+static dmnsn_future *future;
+
+static pthread_key_t dmnsn_detach;
+static pthread_once_t dmnsn_detach_once = PTHREAD_ONCE_INIT;
+
+static void dmnsn_jni_optimizer_fn(const dmnsn_canvas *canvas,
+ dmnsn_canvas_optimizer optimizer,
+ size_t x, size_t y);
+
+JNIEXPORT void JNICALL Java_com_tavianator_dimension_android_RaytracedView_renderNative(JNIEnv *env, jobject obj, jint width, jint height)
+{
+ scene = dmnsn_new_test_scene(width, height);
+
+ (*env)->GetJavaVM(env, &jvm);
+ shared_obj = (*env)->NewGlobalRef(env, obj);
+ jclass cls = (*env)->GetObjectClass(env, shared_obj);
+ shared_cls = (*env)->NewGlobalRef(env, cls);
+ method = (*env)->GetMethodID(env, shared_cls, "setPixel", "(III)V");
+
+ /* Use a canvas optimizer to pass pixels back to the JVM */
+ dmnsn_canvas_optimizer optimizer;
+ optimizer.optimizer_fn = dmnsn_jni_optimizer_fn;
+ optimizer.free_fn = NULL;
+ dmnsn_canvas_optimize(scene->canvas, optimizer);
+
+ __android_log_print(ANDROID_LOG_INFO, TAG, "Rendering with %u threads ...", scene->nthreads);
+ future = dmnsn_ray_trace_async(scene);
+}
+
+JNIEXPORT void JNICALL Java_com_tavianator_dimension_android_RaytracedView_waitNative(JNIEnv *env, jobject obj, jdouble progress)
+{
+ dmnsn_future_wait(future, progress);
+}
+
+JNIEXPORT void JNICALL Java_com_tavianator_dimension_android_RaytracedView_joinNative(JNIEnv *env, jobject obj)
+{
+ dmnsn_future_join(future);
+ __android_log_print(ANDROID_LOG_INFO, TAG, "Rendered!");
+
+ dmnsn_delete_scene(scene);
+
+ (*env)->DeleteGlobalRef(env, shared_cls);
+ (*env)->DeleteGlobalRef(env, shared_obj);
+}
+
+static void
+dmnsn_do_detach(void *ptr)
+{
+ (*jvm)->DetachCurrentThread(jvm);
+}
+
+static void
+dmnsn_initialize_detach(void)
+{
+ dmnsn_key_create(&dmnsn_detach, dmnsn_do_detach);
+}
+
+static void
+dmnsn_jni_optimizer_fn(const dmnsn_canvas *canvas,
+ dmnsn_canvas_optimizer optimizer, size_t x, size_t y)
+{
+ dmnsn_tcolor tcolor = dmnsn_canvas_get_pixel(canvas, x, y);
+ tcolor = dmnsn_tcolor_remove_filter(tcolor);
+ tcolor.c = dmnsn_color_to_sRGB(tcolor.c);
+ tcolor = dmnsn_tcolor_saturate(tcolor);
+
+ uint32_t argb = 0;
+
+ unsigned char component = (unsigned char) ((1.0 - tcolor.T)*UCHAR_MAX);
+ argb |= component << UINT32_C(24);
+
+ component = (unsigned char) (tcolor.c.R*UCHAR_MAX);
+ argb |= component << UINT32_C(16);
+
+ component = (unsigned char) (tcolor.c.G*UCHAR_MAX);
+ argb |= component << UINT32_C(8);
+
+ component = (unsigned char) (tcolor.c.B*UCHAR_MAX);
+ argb |= component;
+
+ dmnsn_once(&dmnsn_detach_once, dmnsn_initialize_detach);
+ JNIEnv *env = pthread_getspecific(dmnsn_detach);
+ if (env == NULL) {
+ (*jvm)->AttachCurrentThread(jvm, &env, NULL);
+ pthread_setspecific(dmnsn_detach, env);
+ }
+ (*env)->CallVoidMethod(env, shared_obj, method, (jint) x, (jint) y, (jint) argb);
+}