commit 939fa0923226953c5fef27cceecec4ac2dd87cdc
parent 6934852821e419ec9cfbb02ee02ae2a2051bb2d5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 21 Jul 2021 16:43:31 +0200
Add a test that draws a Cornell Box
Diffstat:
5 files changed, 364 insertions(+), 7 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -25,6 +25,7 @@ option(NO_TEST "Do not build tests" OFF)
################################################################################
find_package(RCMake 0.4 REQUIRED)
find_package(RSys 0.9 REQUIRED)
+find_package(Star3D 0.8 QUIET)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
@@ -81,6 +82,11 @@ if(NOT NO_TEST)
endfunction()
new_test(test_scam_pinhole)
+
+ if(Star3D_FOUND)
+ new_test(test_scam_cbox)
+ target_link_libraries(test_scam_cbox Star3D)
+ endif()
endif()
################################################################################
diff --git a/src/test_scam_cbox.c b/src/test_scam_cbox.c
@@ -0,0 +1,159 @@
+/* Copyright (C) 2021 |Meso|Star> (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 "scam.h"
+#include "test_scam_cbox.h"
+#include "test_scam_utils.h"
+
+#include <star/s3d.h>
+
+#include <rsys/double3.h>
+#include <rsys/float2.h>
+#include <rsys/float3.h>
+#include <rsys/image.h>
+#include <rsys/mem_allocator.h>
+
+#define IMG_WIDTH 640
+#define IMG_HEIGHT 480
+#define IMG_SPP 16
+
+static struct s3d_scene_view*
+create_s3d_scene_view(void)
+{
+ struct s3d_vertex_data vdata;
+ struct s3d_device* s3d = NULL;
+ struct s3d_scene* scn = NULL;
+ struct s3d_shape* shape = NULL;
+ struct s3d_scene_view* view = NULL;
+
+ CHK(s3d_device_create(NULL, NULL, 0, &s3d) == RES_OK);
+
+ vdata.usage = S3D_POSITION;
+ vdata.type = S3D_FLOAT3;
+ vdata.get = cbox_get_vtx;
+ CHK(s3d_shape_create_mesh(s3d, &shape) == RES_OK);
+ CHK(s3d_mesh_setup_indexed_vertices(shape, cbox_ntris, cbox_get_tri,
+ cbox_nvtxs, &vdata, 1, NULL) == RES_OK);
+
+ CHK(s3d_scene_create(s3d, &scn) == RES_OK);
+ CHK(s3d_scene_attach_shape(scn, shape) == RES_OK);
+ CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK);
+
+ CHK(s3d_device_ref_put(s3d) == RES_OK);
+ CHK(s3d_shape_ref_put(shape) == RES_OK);
+ CHK(s3d_scene_ref_put(scn) == RES_OK);
+
+ return view;
+}
+
+static void
+draw
+ (const struct scam* cam,
+ struct s3d_scene_view* view,
+ struct image* img)
+{
+ int x, y, s;
+ double pixsz[2];
+ CHK(img);
+
+ pixsz[0] = 1.0 / (double)IMG_WIDTH;
+ pixsz[1] = 1.0 / (double)IMG_HEIGHT;
+
+ FOR_EACH(y, 0, IMG_HEIGHT) {
+ FOR_EACH(x, 0, IMG_WIDTH) {
+ double sum[3] = {0,0,0};
+ double E[3] = {0,0,0};
+ int ipix;
+
+ FOR_EACH(s, 0, IMG_SPP) {
+ struct s3d_hit hit = S3D_HIT_NULL;
+ struct scam_sample sample = SCAM_SAMPLE_NULL;
+ struct scam_ray ray = SCAM_RAY_NULL;
+ double col[3];
+ float org[3];
+ float dir[3];
+ float range[2];
+ float N[3];
+ float cos_N_dir;
+
+ /* Generate the camera ray */
+ sample.film[0] = ((double)x + rand_canonical()) * pixsz[0];
+ sample.film[1] = ((double)y + rand_canonical()) * pixsz[1];
+ CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK);
+
+ /* Trace the ray */
+ f3_set_d3(org, ray.org);
+ f3_normalize(dir, f3_set_d3(dir, ray.dir));
+ f2(range, 0, (float)INF);
+ CHK(s3d_scene_view_trace_ray(view, org, dir, range, NULL, &hit) == RES_OK);
+
+ if(S3D_HIT_NONE(&hit)) continue;
+
+ /* Shade */
+ cbox_get_col(hit.prim.prim_id, col);
+ f3_normalize(N, hit.normal);
+ cos_N_dir = absf(f3_dot(N, dir));
+
+ sum[0] += (float)(cos_N_dir * col[0]);
+ sum[1] += (float)(cos_N_dir * col[1]);
+ sum[2] += (float)(cos_N_dir * col[2]);
+ }
+ /* Compute pixel color */
+ E[0] = sum[0] / (double)IMG_SPP;
+ E[1] = sum[1] / (double)IMG_SPP;
+ E[2] = sum[2] / (double)IMG_SPP;
+
+ /* Write pixel color */
+ ipix = (y*IMG_WIDTH + x) * 3/*RGB*/;
+ ((uint8_t*)img->pixels)[ipix+0] = (uint8_t)(E[0] * 255);
+ ((uint8_t*)img->pixels)[ipix+1] = (uint8_t)(E[1] * 255);
+ ((uint8_t*)img->pixels)[ipix+2] = (uint8_t)(E[2] * 255);
+ }
+ }
+}
+
+int
+main(int argc, char** argv)
+{
+ struct scam_pinhole_args args = SCAM_PINHOLE_ARGS_DEFAULT;
+ struct s3d_scene_view* view = NULL;
+ struct scam* cam = NULL;
+ struct image img;
+ (void)argc, (void)argv;
+
+ view = create_s3d_scene_view();
+
+ d3(args.position, 276.0, -700.0, 273.0);
+ d3(args.target, 276.0, 0.0, 273.0);
+ d3(args.up, 0, 0, 1);
+ args.aspect_ratio = (double)IMG_WIDTH/(double)IMG_HEIGHT;
+ args.field_of_view = PI*0.25;
+ CHK(scam_create_pinhole(NULL, NULL, 1, &args, &cam) == RES_OK);
+
+ image_init(NULL, &img);
+ CHK(image_setup
+ (&img, IMG_WIDTH, IMG_HEIGHT, IMG_WIDTH*3, IMAGE_RGB8, NULL) == RES_OK);
+
+ draw(cam, view, &img);
+
+ CHK(image_write_ppm_stream(&img, 0, stdout) == RES_OK);
+
+ CHK(s3d_scene_view_ref_put(view) == RES_OK);
+ CHK(scam_ref_put(cam) == RES_OK);
+ image_release(&img);
+
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_scam_cbox.h b/src/test_scam_cbox.h
@@ -0,0 +1,170 @@
+/* Copyright (C) 2021 |Meso|Star> (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 TEST_SCAM_CBOX_H
+#define TEST_SCAM_CBOX_H
+
+#include <rsys/rsys.h>
+
+/*******************************************************************************
+ * Mesh & properties
+ ******************************************************************************/
+static const float cbox_vtxs[] = {
+ /* Walls */
+ 552.f, 0.f, 0.f,
+ 0.f, 0.f, 0.f,
+ 0.f, 559.f, 0.f,
+ 552.f, 559.f, 0.f,
+ 552.f, 0.f, 548.f,
+ 0.f, 0.f, 548.f,
+ 0.f, 559.f, 548.f,
+ 552.f, 559.f, 548.f,
+
+ /* Short block */
+ 130.f, 65.f, 0.f,
+ 82.f, 225.f, 0.f,
+ 240.f, 272.f, 0.f,
+ 290.f, 114.f, 0.f,
+ 130.f, 65.f, 165.f,
+ 82.f, 225.f, 165.f,
+ 240.f, 272.f, 165.f,
+ 290.f, 114.f, 165.f,
+
+ /* Tall block */
+ 423.0f, 247.0f, 0.f,
+ 265.0f, 296.0f, 0.f,
+ 314.0f, 456.0f, 0.f,
+ 472.0f, 406.0f, 0.f,
+ 423.0f, 247.0f, 330.f,
+ 265.0f, 296.0f, 330.f,
+ 314.0f, 456.0f, 330.f,
+ 472.0f, 406.0f, 330.f
+};
+const unsigned cbox_tris[] = {
+ /* Walls */
+ 0, 1, 2, 2, 3, 0, /* Bottom */
+ 4, 5, 6, 6, 7, 4, /* Top */
+ 1, 2, 6, 6, 5, 1, /* Left */
+ 0, 3, 7, 7, 4, 0, /* Right */
+ 2, 3, 7, 7, 6, 2, /* Back */
+
+ /* Short block */
+ 12, 13, 14, 14, 15, 12,
+ 9, 10, 14, 14, 13, 9,
+ 8, 11, 15, 15, 12, 8,
+ 10, 11, 15, 15, 14, 10,
+ 8, 9, 13, 13, 12, 8,
+
+ /* Tall block */
+ 20, 21, 22, 22, 23, 20,
+ 17, 18, 22, 22, 21, 17,
+ 16, 19, 23, 23, 20, 16,
+ 18, 19, 23, 23, 22, 18,
+ 16, 17, 21, 21, 20, 16
+};
+
+#define WHITE 1.0,1.0,1.0
+#define RED 1.0,0.0,0.0
+#define GREEN 0.0,1.0,0.0
+
+const double cbox_cols[] = {
+ /* Walls */
+ WHITE, WHITE, /* Bottom */
+ WHITE, WHITE, /* Top */
+ RED, RED, /* Left */
+ GREEN, GREEN, /* Right */
+ WHITE, WHITE, /* Back */
+
+ /* Short block */
+ WHITE, WHITE,
+ WHITE, WHITE,
+ WHITE, WHITE,
+ WHITE, WHITE,
+ WHITE, WHITE,
+
+ /* Tall block */
+ WHITE, WHITE,
+ WHITE, WHITE,
+ WHITE, WHITE,
+ WHITE, WHITE,
+ WHITE, WHITE
+};
+
+#undef WHITE
+#undef RED
+#undef GREEN
+
+const unsigned cbox_nvtxs = sizeof(cbox_vtxs) / sizeof(float[3]);
+const unsigned cbox_ntris = sizeof(cbox_tris) / sizeof(unsigned[3]);
+STATIC_ASSERT
+ ( sizeof(cbox_tris)/sizeof(unsigned[3])
+ == sizeof(cbox_cols)/sizeof(double[3]), Unexpected_data_layout);
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+static INLINE void
+cbox_get_vtx(const unsigned ivtx, float vtx[3], void* data)
+{
+ const unsigned id = ivtx * 3;
+ (void)data;
+ CHK(ivtx < cbox_nvtxs);
+ vtx[0] = cbox_vtxs[id+0];
+ vtx[1] = cbox_vtxs[id+1];
+ vtx[2] = cbox_vtxs[id+2];
+}
+
+static INLINE void
+cbox_get_tri(const unsigned itri, unsigned tri[3], void* data)
+{
+ const unsigned id = itri * 3;
+ (void)data;
+ CHK(itri < cbox_ntris);
+ tri[0] = cbox_tris[id+0];
+ tri[1] = cbox_tris[id+1];
+ tri[2] = cbox_tris[id+2];
+}
+
+static INLINE void
+cbox_get_col(const unsigned itri, double col[3])
+{
+ const unsigned id = itri * 3;
+ CHK(itri < cbox_ntris);
+ col[0] = cbox_cols[id+0];
+ col[1] = cbox_cols[id+1];
+ col[2] = cbox_cols[id+2];
+}
+
+static INLINE void
+cbox_dump(FILE* stream)
+{
+ unsigned i;
+
+ FOR_EACH(i, 0, cbox_nvtxs) {
+ fprintf(stream, "v %g %g %g\n",
+ cbox_vtxs[i*3+0],
+ cbox_vtxs[i*3+1],
+ cbox_vtxs[i*3+2]);
+ }
+
+ FOR_EACH(i, 0, cbox_ntris) {
+ fprintf(stream, "f %u %u %u\n",
+ cbox_tris[i*3+0]+1,
+ cbox_tris[i*3+1]+1,
+ cbox_tris[i*3+2]+1);
+ }
+}
+
+#endif /* TEST_SCAM_CBOX_H */
diff --git a/src/test_scam_pinhole.c b/src/test_scam_pinhole.c
@@ -16,19 +16,13 @@
#define _POSIX_C_SOURCE 200112L /* nextafter */
#include "scam.h"
+#include "test_scam_utils.h"
#include <rsys/double3.h>
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
#include <math.h>
-#include <stdlib.h>
-
-static INLINE double
-rand_canonical(void)
-{
- return (double)rand() / (double)((int64_t)RAND_MAX + 1);
-}
static void
log_stream(const char* msg, void* ctx)
diff --git a/src/test_scam_utils.h b/src/test_scam_utils.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2021 |Meso|Star> (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 TEST_SCAM_UTILS_H
+#define TEST_SCAM_UTILS_H
+
+#include <rsys/rsys.h>
+#include <stdlib.h>
+
+static INLINE double
+rand_canonical(void)
+{
+ return (double)rand() / (double)((int64_t)RAND_MAX + 1);
+}
+
+#endif /* TEST_SCAM_UTILS_H */