From c150be9eb7e0d69def245d877bd66f6df87f58a1 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 21 Aug 2012 23:08:30 -0400 Subject: Get Dimension working on Android. --- .gitignore | 10 + AndroidManifest.xml | 28 ++ ant.properties | 17 + build.xml | 92 +++++ jni/Android.mk | 80 +++++ jni/Application.mk | 21 ++ jni/jni.c | 386 +++++++++++++++++++++ libdimension/error.c | 28 +- libdimension/future.c | 11 +- libdimension/platform.c | 4 +- libdimension/threads.c | 8 +- proguard-project.txt | 20 ++ project.properties | 14 + res/drawable-hdpi/ic_launcher.png | Bin 0 -> 9397 bytes res/drawable-ldpi/ic_launcher.png | Bin 0 -> 2729 bytes res/drawable-mdpi/ic_launcher.png | Bin 0 -> 5237 bytes res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 14383 bytes res/layout/main.xml | 11 + res/values/strings.xml | 4 + .../dimension/android/DimensionActivity.java | 36 ++ .../dimension/android/RaytracedView.java | 178 ++++++++++ 21 files changed, 921 insertions(+), 27 deletions(-) create mode 100644 AndroidManifest.xml create mode 100644 ant.properties create mode 100644 build.xml create mode 100644 jni/Android.mk create mode 100644 jni/Application.mk create mode 100644 jni/jni.c create mode 100644 proguard-project.txt create mode 100644 project.properties create mode 100644 res/drawable-hdpi/ic_launcher.png create mode 100644 res/drawable-ldpi/ic_launcher.png create mode 100644 res/drawable-mdpi/ic_launcher.png create mode 100644 res/drawable-xhdpi/ic_launcher.png create mode 100644 res/layout/main.xml create mode 100644 res/values/strings.xml create mode 100644 src/com/tavianator/dimension/android/DimensionActivity.java create mode 100644 src/com/tavianator/dimension/android/RaytracedView.java diff --git a/.gitignore b/.gitignore index ebb7df2..8cb96c0 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,13 @@ __pycache__ # Core dumps core vgcore.* + +# Android code +/bin/ +/gen/ +/libs/ +/obj/ +/local.properties +.classpath +.project +.settings diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..fd9aa04 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + diff --git a/ant.properties b/ant.properties new file mode 100644 index 0000000..b0971e8 --- /dev/null +++ b/ant.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked into Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..816253e --- /dev/null +++ b/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jni/Android.mk b/jni/Android.mk new file mode 100644 index 0000000..1adf510 --- /dev/null +++ b/jni/Android.mk @@ -0,0 +1,80 @@ +########################################################################### +## Copyright (C) 2009-2011 Tavian Barnes ## +## ## +## This file is part of The Dimension Build Suite. ## +## ## +## The Dimension Build Suite 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 Build Suite 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 . ## +########################################################################### + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := dimension +LOCAL_SRC_FILES := \ + jni.c \ + ../libdimension/camera.c \ + ../libdimension/canvas.c \ + ../libdimension/canvas_pigment.c \ + ../libdimension/checker.c \ + ../libdimension/cone.c \ + ../libdimension/cube.c \ + ../libdimension/csg.c \ + ../libdimension/dictionary.c \ + ../libdimension/error.c \ + ../libdimension/finish.c \ + ../libdimension/future.c \ + ../libdimension/geometry.c \ + ../libdimension/gradient.c \ + ../libdimension/inline.c \ + ../libdimension/interior.c \ + ../libdimension/lambertian.c \ + ../libdimension/leopard.c \ + ../libdimension/light.c \ + ../libdimension/malloc.c \ + ../libdimension/map.c \ + ../libdimension/object.c \ + ../libdimension/pattern.c \ + ../libdimension/perspective.c \ + ../libdimension/phong.c \ + ../libdimension/pigment.c \ + ../libdimension/pigment_map.c \ + ../libdimension/plane.c \ + ../libdimension/platform.c \ + ../libdimension/point_light.c \ + ../libdimension/polynomial.c \ + ../libdimension/prtree.c \ + ../libdimension/ray_trace.c \ + ../libdimension/reflection.c \ + ../libdimension/rgba16.c \ + ../libdimension/scene.c \ + ../libdimension/solid_pigment.c \ + ../libdimension/sphere.c \ + ../libdimension/texture.c \ + ../libdimension/threads.c \ + ../libdimension/timer.c \ + ../libdimension/torus.c \ + ../libdimension/triangle.c \ + ../libdimension/png-stubs.c \ + ../libdimension/gl-stubs.c +LOCAL_CFLAGS := \ + -Ilibdimension/ \ + -std=gnu99 \ + -DHAVE_UNISTD_H=1 \ + -DDMNSN_GETTID_DIRECT=1 \ + -DDMNSN_SC_NPROCESSORS_ONLN=1 \ + -DDMNSN_GETRUSAGE=1 +LOCAL_LDLIBS := -llog + +include $(BUILD_SHARED_LIBRARY) diff --git a/jni/Application.mk b/jni/Application.mk new file mode 100644 index 0000000..74fec4c --- /dev/null +++ b/jni/Application.mk @@ -0,0 +1,21 @@ +########################################################################### +## Copyright (C) 2009-2011 Tavian Barnes ## +## ## +## This file is part of The Dimension Build Suite. ## +## ## +## The Dimension Build Suite 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 Build Suite 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 . ## +########################################################################### + +APP_ABI := armeabi armeabi-v7a +APP_PLATFORM := android-16 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 * + * * + * 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 . * + *************************************************************************/ + +/** + * @file + * Java interface to libdimension used by Android. + */ + +#include "dimension-internal.h" +#include +#include +#include +#include + +#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); +} diff --git a/libdimension/error.c b/libdimension/error.c index 371c7cd..9fb116a 100644 --- a/libdimension/error.c +++ b/libdimension/error.c @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * + * Copyright (C) 2009-2012 Tavian Barnes * * * * This file is part of The Dimension Library. * * * @@ -28,13 +28,18 @@ #include #include #include +#include + +/** Android log tag. */ +#define TAG "libdimension" /** Report internal errors in this file. */ -#define DMNSN_LOCAL_ERROR(str) \ - do { \ - fprintf(stderr, "Dimension ERROR: %s, %s:%u: %s\n", \ - DMNSN_FUNC, __FILE__, __LINE__, (str)); \ - abort(); \ +#define DMNSN_LOCAL_ERROR(str) \ + do { \ + __android_log_print(ANDROID_LOG_ERROR, TAG, \ + "Dimension ERROR: %s, %s:%u: %s\n", \ + DMNSN_FUNC, __FILE__, __LINE__, (str)); \ + abort(); \ } while (0) /** dmnsn_local_lock_mutex implementation. */ @@ -89,18 +94,19 @@ dmnsn_report_error(bool die, const char *func, const char *file, dmnsn_local_unlock_mutex(&dmnsn_always_die_mutex); /* Print the diagnostic string */ - fprintf(stderr, "Dimension %s: %s, %s:%u: %s\n", - die ? "ERROR" : "WARNING", func, file, line, str); + __android_log_print(ANDROID_LOG_ERROR, TAG, + "Dimension %s: %s, %s:%u: %s\n", + die ? "ERROR" : "WARNING", func, file, line, str); /* Print the value of errno */ if (err != 0) { - fprintf(stderr, "Last error: %d", err); + __android_log_print(ANDROID_LOG_ERROR, TAG, "Last error: %d", err); #if DMNSN_SYS_ERRLIST if (err >= 0 && err < sys_nerr) { - fprintf(stderr, " (%s)", sys_errlist[err]); + __android_log_print(ANDROID_LOG_ERROR, TAG, " (%s)", sys_errlist[err]); } #endif - fprintf(stderr, "\n"); + __android_log_print(ANDROID_LOG_ERROR, TAG, "\n"); } /* Print a stack trace to standard error */ diff --git a/libdimension/future.c b/libdimension/future.c index c328815..437b490 100644 --- a/libdimension/future.c +++ b/libdimension/future.c @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * + * Copyright (C) 2009-2012 Tavian Barnes * * * * This file is part of The Dimension Library. * * * @@ -61,7 +61,7 @@ dmnsn_future_join(dmnsn_future *future) if (future) { /* Get the thread's return value */ dmnsn_join_thread(future->thread, &ptr); - if (ptr && ptr != PTHREAD_CANCELED) { + if (ptr) { retval = *(int *)ptr; dmnsn_free(ptr); } @@ -89,7 +89,7 @@ dmnsn_future_join(dmnsn_future *future) void dmnsn_future_cancel(dmnsn_future *future) { - pthread_cancel(future->thread); + dmnsn_error("Thread cancellation not supported on Android."); } /* Get the current progress of the worker thread, in [0.0, 1.0] */ @@ -133,11 +133,6 @@ dmnsn_future_set_total(dmnsn_future *future, size_t total) void dmnsn_future_increment(dmnsn_future *future) { - /* Allow a thread to be canceled whenever it increments a future object -- - this is close to PTHREAD_CANCEL_ASYNCHRONOUS but allows consistent state - on cancellation */ - pthread_testcancel(); - dmnsn_write_lock(future->rwlock); ++future->progress; dmnsn_unlock_rwlock(future->rwlock); diff --git a/libdimension/platform.c b/libdimension/platform.c index a27343d..b4efa09 100644 --- a/libdimension/platform.c +++ b/libdimension/platform.c @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 2010-2011 Tavian Barnes * + * Copyright (C) 2010-2012 Tavian Barnes * * * * This file is part of The Dimension Library. * * * @@ -67,6 +67,8 @@ dmnsn_is_main_thread(void) { #if DMNSN_GETTID return getpid() == syscall(SYS_gettid); +#elif DMNSN_GETTID_DIRECT + return getpid() == gettid(); #else return true; #endif diff --git a/libdimension/threads.c b/libdimension/threads.c index 0aed16d..5dce26c 100644 --- a/libdimension/threads.c +++ b/libdimension/threads.c @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 2010-2011 Tavian Barnes * + * Copyright (C) 2010-2012 Tavian Barnes * * * * This file is part of The Dimension Library. * * * @@ -100,12 +100,6 @@ dmnsn_ccthread_cleanup(void *ptr) { dmnsn_ccthread_cleanup_payload *payload = ptr; - for (unsigned int i = 0; i < payload->nthreads; ++i) { - if (payload->payloads[i].started) { - pthread_cancel(payload->threads[i]); - } - } - for (unsigned int i = 0; i < payload->nthreads; ++i) { if (payload->payloads[i].started) { dmnsn_join_thread(payload->threads[i], NULL); diff --git a/proguard-project.txt b/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..9b84a6b --- /dev/null +++ b/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-16 diff --git a/res/drawable-hdpi/ic_launcher.png b/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..96a442e Binary files /dev/null and b/res/drawable-hdpi/ic_launcher.png differ diff --git a/res/drawable-ldpi/ic_launcher.png b/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000..9923872 Binary files /dev/null and b/res/drawable-ldpi/ic_launcher.png differ diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..359047d Binary files /dev/null and b/res/drawable-mdpi/ic_launcher.png differ diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..71c6d76 Binary files /dev/null and b/res/drawable-xhdpi/ic_launcher.png differ diff --git a/res/layout/main.xml b/res/layout/main.xml new file mode 100644 index 0000000..00a3579 --- /dev/null +++ b/res/layout/main.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..0b689d1 --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Dimension + diff --git a/src/com/tavianator/dimension/android/DimensionActivity.java b/src/com/tavianator/dimension/android/DimensionActivity.java new file mode 100644 index 0000000..60a6f21 --- /dev/null +++ b/src/com/tavianator/dimension/android/DimensionActivity.java @@ -0,0 +1,36 @@ +/************************************************************************* + * Copyright (C) 2010-2011 Tavian Barnes * + * * + * 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 . * + *************************************************************************/ + +package com.tavianator.dimension.android; + +import android.app.Activity; +import android.os.Bundle; + +/** + * @author Tavian Barnes + * @version 1.0 + * @since 1.0 + */ +public class DimensionActivity extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } +} diff --git a/src/com/tavianator/dimension/android/RaytracedView.java b/src/com/tavianator/dimension/android/RaytracedView.java new file mode 100644 index 0000000..4a88793 --- /dev/null +++ b/src/com/tavianator/dimension/android/RaytracedView.java @@ -0,0 +1,178 @@ +/************************************************************************* + * Copyright (C) 2010-2011 Tavian Barnes * + * * + * 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 . * + *************************************************************************/ + +package com.tavianator.dimension.android; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +/** + * @author Tavian Barnes + * @version 1.0 + * @since 1.0 + */ +@SuppressLint("HandlerLeak") +public class RaytracedView extends SurfaceView implements + SurfaceHolder.Callback { + private static final String TAG = RaytracedView.class.getSimpleName(); + + private static final int NFRAMES = 64; + + static { + System.loadLibrary("dimension"); + Log.d(TAG, "libdimension loaded sucessfully!"); + } + + private static final int MSG_RENDER = 0; + private static final int MSG_QUIT = 1; + + private static class RenderPayload { + public int width; + public int height; + + public RenderPayload(int width, int height) { + this.width = width; + this.height = height; + } + } + + private class RenderHandler extends Handler { + public RenderHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_RENDER: + handleRender((RenderPayload) msg.obj); + break; + case MSG_QUIT: + handleQuit(); + break; + } + } + + private void handleRender(RenderPayload payload) { + render(payload.width, payload.height); + } + + private void handleQuit() { + getLooper().quit(); + } + } + + private RenderHandler m_Handler; + private int mWidth, mHeight; + private int[] mBitmap; + + public RaytracedView(Context context) { + super(context); + init(); + } + + public RaytracedView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public RaytracedView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + SurfaceHolder holder = getHolder(); + holder.addCallback(this); + holder.setFormat(PixelFormat.TRANSLUCENT); + } + + public void surfaceCreated(SurfaceHolder holder) { + HandlerThread thread = new HandlerThread("RenderThread"); + thread.start(); + + m_Handler = new RenderHandler(thread.getLooper()); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + m_Handler.obtainMessage(MSG_RENDER, new RenderPayload(width, height)) + .sendToTarget(); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + m_Handler.sendEmptyMessage(MSG_QUIT); + } + + private void render(int width, int height) { + mBitmap = new int[width * height]; + mWidth = width; + mHeight = height; + + renderNative(width, height); + + for (int i = 0; i < NFRAMES; ++i) { + waitNative(((double) i) / NFRAMES); + draw(); + } + + joinNative(); + draw(); + } + + private void draw() { + SurfaceHolder holder = getHolder(); + Canvas canvas = holder.lockCanvas(); + if (canvas == null) { + return; + } + + canvas.drawColor(0, PorterDuff.Mode.CLEAR); + canvas.drawBitmap(mBitmap, 0, mWidth, 0.0F, 0.0F, mWidth, mHeight, + true, null); + + holder.unlockCanvasAndPost(canvas); + } + + /** Start the render. */ + private native void renderNative(int width, int height); + + /** Wait for the render to reach a certain amount of progress. */ + private native void waitNative(double progress); + + /** Wait for the render to complete. */ + private native void joinNative(); + + /** Called by JNI code to set the pixel colors. */ + private void setPixel(int x, int y, int color) { + y = mHeight - y - 1; + mBitmap[y * mWidth + x] = color; + } +} -- cgit v1.2.3