commit 2e5d7bbff2ddd30b25d7e46a096c625dd68c49bf
parent 8602f12a2b64d4631b8b7b281440666c3da322d4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 21 Feb 2018 12:07:35 +0100
Implement and test the sdis_camera API
Diffstat:
5 files changed, 337 insertions(+), 4 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -45,6 +45,7 @@ set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SDIS_FILES_SRC
+ sdis_camera.c
sdis_data.c
sdis_device.c
sdis_estimator.c
@@ -57,6 +58,7 @@ set(SDIS_FILES_INC_API
sdis.h)
set(SDIS_FILES_INC
+ sdis_camera.h
sdis_device_c.h
sdis_estimator_c.h
sdis_interface_c.h
@@ -75,7 +77,10 @@ add_library(sdis SHARED
${SDIS_FILES_SRC}
${SDIS_FILES_INC}
${SDIS_FILES_INC_API})
-target_link_libraries(sdis RSys Star2D Star3D StarSP)
+target_link_libraries(sdis RSys Star2D Star3D StarSP m)
+if(CMAKE_COMPILER_IS_GNUCC)
+ target_link_libraries(sdis m)
+endif()
set_target_properties(sdis PROPERTIES
DEFINE_SYMBOL SDIS_SHARED_BUILD
@@ -111,6 +116,7 @@ if(NOT NO_TEST)
register_test(${_name} ${_name})
endfunction()
+ new_test(test_sdis_camera)
new_test(test_sdis_data)
new_test(test_sdis_device)
new_test(test_sdis_interface)
diff --git a/src/sdis.h b/src/sdis.h
@@ -51,6 +51,7 @@ struct mem_allocator;
* a reference on the data, i.e. they increment or decrement the reference
* counter, respectively. When this counter reaches 0, the object is silently
* destroyed and cannot be used anymore. */
+struct sdis_camera;
struct sdis_data;
struct sdis_device;
struct sdis_estimator;
@@ -124,7 +125,7 @@ struct sdis_solid_shader {
* unknown for the submitted random walk vertex. */
sdis_medium_getter_T temperature;
};
-#define SDIS_SOLID_SHADER_NULL__ {NULL}
+#define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL}
static const struct sdis_solid_shader SDIS_SOLID_SHADER_NULL =
SDIS_SOLID_SHADER_NULL__;
@@ -137,7 +138,7 @@ struct sdis_fluid_shader {
* unknown for the submitted position and time. */
sdis_medium_getter_T temperature;
};
-#define SDIS_FLUID_SHADER_NULL__ {NULL}
+#define SDIS_FLUID_SHADER_NULL__ {NULL, NULL, NULL}
static const struct sdis_fluid_shader SDIS_FLUID_SHADER_NULL =
SDIS_FLUID_SHADER_NULL__;
@@ -149,7 +150,7 @@ struct sdis_interface_shader {
sdis_interface_getter_T emissivity; /* Overall emissivity */
sdis_interface_getter_T specular_fraction; /* Specular fraction in [0, 1] */
};
-#define SDIS_INTERFACE_SHADER_NULL__ {NULL}
+#define SDIS_INTERFACE_SHADER_NULL__ {NULL, NULL, NULL, NULL}
static const struct sdis_interface_shader SDIS_INTERFACE_SHADER_NULL =
SDIS_INTERFACE_SHADER_NULL__;
@@ -204,6 +205,40 @@ sdis_data_cget
(const struct sdis_data* data);
/*******************************************************************************
+ * A camera describes a point of view
+ ******************************************************************************/
+SDIS_API res_T
+sdis_camera_create
+ (struct sdis_device* dev,
+ struct sdis_camera** cam);
+
+SDIS_API res_T
+sdis_camera_ref_get
+ (struct sdis_camera* cam);
+
+SDIS_API res_T
+sdis_camera_ref_put
+ (struct sdis_camera* cam);
+
+/* Width/height projection ratio */
+SDIS_API res_T
+sdis_camera_set_proj_ratio
+ (struct sdis_camera* cam,
+ const double proj_ratio);
+
+SDIS_API res_T
+sdis_camera_set_fov /* Horizontal field of view */
+ (struct sdis_camera* cam,
+ const double fov); /* In radian */
+
+SDIS_API res_T
+sdis_camera_look_at
+ (struct sdis_camera* cam,
+ const double position[3],
+ const double target[3],
+ const double up[3]);
+
+/*******************************************************************************
* A medium encapsulates the properties of either a fluid or a solid.
******************************************************************************/
SDIS_API res_T
diff --git a/src/sdis_camera.c b/src/sdis_camera.c
@@ -0,0 +1,138 @@
+/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
+ *
+ * This program 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.
+ *
+ * This program 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/>. */
+
+#include "sdis.h"
+#include "sdis_camera.h"
+#include "sdis_device_c.h"
+
+#include <rsys/mem_allocator.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+camera_release(ref_T* ref)
+{
+ struct sdis_camera* cam = CONTAINER_OF(ref, struct sdis_camera, ref);
+ struct sdis_device* dev;
+ ASSERT(ref);
+ dev = cam->dev;
+ MEM_RM(dev->allocator, cam);
+ SDIS(device_ref_put(dev));
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+sdis_camera_create(struct sdis_device* dev, struct sdis_camera** out_cam)
+{
+ const double pos[3] = {0, 0, 0};
+ const double tgt[3] = {0, 0,-1};
+ const double up[3] = {0, 1, 0};
+ struct sdis_camera* cam = NULL;
+ res_T res = RES_OK;
+
+ if(!dev || !out_cam) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ cam = MEM_CALLOC(dev->allocator, 1, sizeof(struct sdis_camera));
+ if(!cam) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ SDIS(device_ref_get(dev));
+ cam->dev = dev;
+ ref_init(&cam->ref);
+ cam->rcp_proj_ratio = 1.0;
+ cam->fov_x = PI/2.0;
+ SDIS(camera_look_at(cam, pos, tgt, up));
+
+exit:
+ if(out_cam) *out_cam = cam;
+ return res;
+error:
+ if(cam) {
+ SDIS(camera_ref_put(cam));
+ cam = NULL;
+ }
+ goto exit;
+}
+
+res_T
+sdis_camera_ref_get(struct sdis_camera* cam)
+{
+ if(!cam) return RES_BAD_ARG;
+ ref_get(&cam->ref);
+ return RES_OK;
+}
+
+res_T
+sdis_camera_ref_put(struct sdis_camera* cam)
+{
+ if(!cam) return RES_BAD_ARG;
+ ref_put(&cam->ref, camera_release);
+ return RES_OK;
+}
+
+res_T
+sdis_camera_set_proj_ratio(struct sdis_camera* cam, const double ratio)
+{
+ double y[3] = {0};
+ if(!cam || ratio <= 0) return RES_BAD_ARG;
+ if(d3_normalize(y, cam->axis_y) <= 0) return RES_BAD_ARG;
+ cam->rcp_proj_ratio = 1.0 / ratio;
+ d3_muld(cam->axis_y, y, cam->rcp_proj_ratio);
+ return RES_OK;
+}
+
+res_T
+sdis_camera_set_fov(struct sdis_camera* cam, const double fov_x)
+{
+ double z[3] = {0};
+ double img_plane_depth;
+ if(!cam || (float)fov_x <= 0) return RES_BAD_ARG;
+ if(d3_normalize(z, cam->axis_z) <= 0) return RES_BAD_ARG;
+ img_plane_depth = 1.0/tan(fov_x*0.5);
+ d3_muld(cam->axis_z, z, img_plane_depth);
+ cam->fov_x = fov_x;
+ return RES_OK;
+}
+
+res_T
+sdis_camera_look_at
+ (struct sdis_camera* cam,
+ const double pos[3],
+ const double tgt[3],
+ const double up[3])
+{
+ double x[3], y[3], z[3];
+ double img_plane_depth;
+ if(!cam || !pos || !tgt || !up) return RES_BAD_ARG;
+
+ if(d3_normalize(z, d3_sub(z, tgt, pos)) <= 0) return RES_BAD_ARG;
+ if(d3_normalize(x, d3_cross(x, z, up)) <= 0) return RES_BAD_ARG;
+ if(d3_normalize(y, d3_cross(y, z, x)) <= 0) return RES_BAD_ARG;
+ img_plane_depth = 1.0/tan(cam->fov_x*0.5);
+
+ d3_set(cam->axis_x, x);
+ d3_muld(cam->axis_y, y, cam->rcp_proj_ratio);
+ d3_muld(cam->axis_z, z, img_plane_depth);
+ d3_set(cam->position, pos);
+ return RES_OK;
+}
+
diff --git a/src/sdis_camera.h b/src/sdis_camera.h
@@ -0,0 +1,60 @@
+/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
+ *
+ * This program 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.
+ *
+ * This program 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/>. */
+
+#ifndef SDIS_CAMERA_H
+#define SDIS_CAMERA_H
+
+#include <rsys/double3.h>
+#include <rsys/ref_count.h>
+
+struct sdis_device;
+
+struct sdis_camera {
+ /* Orthogonal camera frame */
+ double axis_x[3];
+ double axis_y[3];
+ double axis_z[3];
+
+ double position[3];
+ double fov_x; /* Field of view in radians */
+ double rcp_proj_ratio; /* height / width */
+
+ ref_T ref;
+ struct sdis_device* dev;
+};
+
+static FINLINE void
+camera_ray
+ (const struct sdis_camera* cam,
+ const double sample[2], /* In [0, 1[ */
+ double org[3],
+ double dir[3])
+{
+ double x[3], y[3], len;
+ (void)len; /* Avoid warning in debug */
+ ASSERT(cam && sample && org && dir);
+ ASSERT(sample[0] >= 0.0 || sample[0] < 1.0);
+ ASSERT(sample[1] >= 0.0 || sample[1] < 1.0);
+
+ d3_muld(x, cam->axis_x, sample[0]*2.0 - 1.0);
+ d3_muld(y, cam->axis_y, sample[1]*2.0 - 1.0);
+ d3_add(dir, d3_add(dir, x, y), cam->axis_z);
+ len = d3_normalize(dir, dir);
+ ASSERT(len >= 1.e-6);
+ d3_set(org, cam->position);
+}
+
+#endif /* SDIS_CAMERA_H */
+
diff --git a/src/test_sdis_camera.c b/src/test_sdis_camera.c
@@ -0,0 +1,94 @@
+/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
+ *
+ * This program 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.
+ *
+ * This program 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/>. */
+
+#include "sdis.h"
+#include "test_sdis_utils.h"
+
+#include <rsys/math.h>
+
+int
+main(int argc, char** argv)
+{
+ struct sdis_device* dev;
+ struct sdis_camera* cam;
+ struct mem_allocator allocator;
+ double pos[3] = {0};
+ double tgt[3] = {0};
+ double up[3] = {0};
+ (void)argc, (void)argv;
+
+ CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
+
+ CHK(sdis_device_create
+ (NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev) == RES_OK);
+
+ CHK(sdis_camera_create(NULL, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_create(dev, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_create(NULL, &cam) == RES_BAD_ARG);
+ CHK(sdis_camera_create(dev, &cam) == RES_OK);
+
+ CHK(sdis_camera_ref_get(NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_ref_get(cam) == RES_OK);
+ CHK(sdis_camera_ref_put(NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_ref_put(cam) == RES_OK);
+ CHK(sdis_camera_ref_put(cam) == RES_OK);
+
+ CHK(sdis_camera_create(dev, &cam) == RES_OK);
+ CHK(sdis_camera_set_proj_ratio(NULL, 0) == RES_BAD_ARG);
+ CHK(sdis_camera_set_proj_ratio(cam, 0) == RES_BAD_ARG);
+ CHK(sdis_camera_set_proj_ratio(NULL, 4.0/3.0) == RES_BAD_ARG);
+ CHK(sdis_camera_set_proj_ratio(cam, 4.0/3.0) == RES_OK);
+ CHK(sdis_camera_set_proj_ratio(cam, -4.0/3.0) == RES_BAD_ARG);
+
+ CHK(sdis_camera_set_fov(NULL, 0) == RES_BAD_ARG);
+ CHK(sdis_camera_set_fov(cam, 0) == RES_BAD_ARG);
+ CHK(sdis_camera_set_fov(NULL, PI/4.0) == RES_BAD_ARG);
+ CHK(sdis_camera_set_fov(cam, PI/4.0) == RES_OK);
+ CHK(sdis_camera_set_fov(cam, -PI/4.0) == RES_BAD_ARG);
+
+ pos[0] = 0, pos[1] = 0, pos[2] = 0;
+ tgt[0] = 0, tgt[1] = 0, tgt[2] = -1;
+ up[0] = 0, up[1] = 1, up[2] = 0;
+ CHK(sdis_camera_look_at(NULL, NULL, NULL, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, NULL, NULL, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(NULL, pos, NULL, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, pos, NULL, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(NULL, NULL, tgt, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, NULL, tgt, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(NULL, pos, tgt, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, pos, tgt, NULL) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(NULL, NULL, NULL, up) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, NULL, NULL, up) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(NULL, pos, NULL, up) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, pos, NULL, up) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(NULL, NULL, tgt, up) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, NULL, tgt, up) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(NULL, pos, tgt, up) == RES_BAD_ARG);
+ CHK(sdis_camera_look_at(cam, pos, tgt, up) == RES_OK);
+ tgt[0] = 0, tgt[1] = 0, tgt[2] = 0;
+ CHK(sdis_camera_look_at(cam, pos, tgt, up) == RES_BAD_ARG);
+ tgt[0] = 0, tgt[1] = 0, tgt[2] = -1;
+ up[0] = 0, up[1] = 0, up[2] = 0;
+ CHK(sdis_camera_look_at(cam, pos, tgt, up) == RES_BAD_ARG);
+
+ CHK(sdis_device_ref_put(dev) == RES_OK);
+ CHK(sdis_camera_ref_put(cam) == RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
+