star-gs

Literate program for a geometric sensitivity calculation
git clone git://git.meso-star.fr/star-gs.git
Log | Files | Refs | README | LICENSE

commit 3bc3487ebd717b1bddd90babeae5de74adc18b85
parent 1a8529bb096a8c9f3e833caadb2c6ebb77dbf7d6
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Sun, 18 Apr 2021 19:33:02 +0200

First draft of the sgs command

Diffstat:
Acmake/CMakeLists.txt | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs.c | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_args.c | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_args.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_c.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_geometry.c | 353+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_geometry.h | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_log.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_log.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sgs_main.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 1314 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -0,0 +1,86 @@ +# Copyright (C) 2021 +# CNRS/RAPSODEE, +# CNRS/LMAP, +# |Meso|Star> (contact@meso-star.com), +# UPS/Laplace. +# +# 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/>. + +cmake_minimum_required(VERSION 3.1) +project(atrstm C) +enable_testing() + +set(SGS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) +option(NO_TEST "Do not build tests" OFF) + +################################################################################ +# Check dependencies +################################################################################ +find_package(RCMake 0.4 REQUIRED) +find_package(RSys 0.12 REQUIRED) +find_package(Star3D 0.7 REQUIRED) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) +include(rcmake) +include(rcmake_runtime) + +include_directories( + ${RSys_INCLUDE_DIR} + ${Star3D_INCLUDE_DIR}) + +################################################################################ +# Configure and define targets +################################################################################ +set(VERSION_MAJOR 0) +set(VERSION_MINOR 0) +set(VERSION_PATCH 0) +set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) + +set(SGS_FILES_SRC + sgs_args.c + sgs.c + sgs_geometry.c + sgs_log.c + sgs_main.c) + +set(SGS_FILES_INC + sgs_args.h + sgs_c.h + sgs_geometry.h + sgs.h + sgs_log.h) + +set(SGS_FILES_DOC COPYING README.md) + +# Prepend each file in the `SGS_FILES_<SRC|INC>' list by `SGS_SOURCE_DIR' +rcmake_prepend_path(SGS_FILES_SRC ${SGS_SOURCE_DIR}) +rcmake_prepend_path(SGS_FILES_INC ${SGS_SOURCE_DIR}) +rcmake_prepend_path(SGS_FILES_DOC ${PROJECT_SOURCE_DIR}/../) + +add_executable(sgs ${SGS_FILES_SRC} ${SGS_FILES_INC}) +target_link_libraries(sgs RSys Star3D m) + +set_target_properties(sgs PROPERTIES + VERSION ${VERSION} + SOVERSION ${VERSION_MAJOR}) + +################################################################################ +# Define output & install directories +################################################################################ +install(TARGETS sgs + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(FILES ${SGS_FILES_DOC} DESTINATION share/doc/sgs) + diff --git a/src/sgs.c b/src/sgs.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 "sgs.h" +#include "sgs_args.h" +#include "sgs_c.h" +#include "sgs_log.h" + +#include <star/s3d.h> + +#include <rsys/cstr.h> +#include <rsys/mem_allocator.h> + +/******************************************************************************* + * sgs API + ******************************************************************************/ +res_T +sgs_create + (struct mem_allocator* mem_allocator, + const struct sgs_args* args, + struct sgs** out_sgs) +{ + struct sgs* sgs = NULL; + struct mem_allocator* allocator = NULL; + res_T res = RES_OK; + ASSERT(args && out_sgs); + + allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + sgs = MEM_CALLOC(allocator, 1, sizeof(struct sgs)); + if(!sgs) { + fprintf(stderr, SGS_LOG_ERROR_PREFIX + "Could not allocate the sgs data structure.\n"); + res = RES_MEM_ERR; + goto error; + } + sgs->allocator = allocator; + sgs->nthreads = args->nthreads; + sgs->verbose = args->verbose; + sgs->dump_geometry = args->dump_geometry; + + setup_logger(sgs); + + res = s3d_device_create(&sgs->logger, sgs->allocator, 0, &sgs->s3d); + if(res != RES_OK) { + sgs_log_err(sgs, "Error creating the Star-3D device -- %s.\n", + res_to_cstr(res)); + goto error; + } + + switch(args->geom.type) { + case SGS_GEOMETRY_BOX: + res = sgs_geometry_box_create(sgs, &args->geom.args.box, &sgs->geom); + if(res != RES_OK) goto error; + break; + case SGS_GEOMETRY_SLOPE: + sgs_log_warn(sgs, "Slope geometry is not supported yet.\n"); + res = RES_BAD_OP; + goto error; + break; + case SGS_GEOMETRY_STEP: + sgs_log_warn(sgs, "Step geometry is not supported yet.\n"); + res = RES_BAD_OP; + goto error; + break; + default: FATAL(SGS_LOG_ERROR_PREFIX"Unreachable code.\n"); break; + } + +exit: + *out_sgs = sgs; + return res; +error: + if(sgs) { + sgs_release(sgs); + sgs = NULL; + } + goto exit; +} + +void +sgs_release(struct sgs* sgs) +{ + ASSERT(sgs); + + if(sgs->s3d) S3D(device_ref_put(sgs->s3d)); + if(sgs->geom) sgs_geometry_ref_put(sgs->geom); + logger_release(&sgs->logger); + MEM_RM(sgs->allocator, sgs); +} + +struct mem_allocator* +sgs_get_allocator(struct sgs* sgs) +{ + ASSERT(sgs); + return sgs->allocator; +} + +void +sgs_fprint_copyright(FILE* stream) +{ + ASSERT(stream); + fprintf(stream, +"Copyright (C) 2021 CNRS/RAPSODEE, CNRS/LMAP, |Meso|Star>, UPS/Laplace.\n"); +} + +void +sgs_fprint_license(FILE* stream) +{ + ASSERT(stream); + fprintf(stream, +"Star Geometric Sensitivity is free software released under the GNU GPL\n" +"license, version 3 or later. You are free to change or redistribute it\n" +"under certain conditions <http://gnu.org/licenses/gpl.html>.\n"); +} + +res_T +sgs_run(struct sgs* sgs) +{ + res_T res = RES_OK; + ASSERT(sgs); + + if(sgs->dump_geometry) { + res = sgs_geometry_dump_vtk(sgs->geom, stdout); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + diff --git a/src/sgs.h b/src/sgs.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 SGS_H +#define SGS_H + +#include <rsys/rsys.h> + +/* Forward declarations */ +struct mem_allocator; +struct sgs; +struct sgs_args; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +extern LOCAL_SYM void +sgs_fprint_copyright + (FILE* stream); + +extern LOCAL_SYM void +sgs_fprint_license + (FILE* stream); + +/******************************************************************************* + * sgs API + ******************************************************************************/ +extern LOCAL_SYM res_T +sgs_create + (struct mem_allocator* allocator, /* NULL <=> Use default allocator */ + const struct sgs_args* args, + struct sgs** sgs); + +extern LOCAL_SYM void +sgs_release + (struct sgs* sgs); + +extern LOCAL_SYM res_T +sgs_run + (struct sgs* sgs); + +extern LOCAL_SYM struct mem_allocator* +sgs_get_allocator + (struct sgs* sgs); + +#endif /* SGS_H */ diff --git a/src/sgs_args.c b/src/sgs_args.c @@ -0,0 +1,175 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE + * CNRS/LMAP + * |Meso|Star> (contact@meso-star.com) + * UPS/Laplace + * + * 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/>. */ + +#define _POSIX_C_SOURCE 200112L /* strtok_r support */ + +#include "sgs.h" +#include "sgs_args.h" +#include "sgs_log.h" + +#include <rsys/cstr.h> + +#include <getopt.h> +#include <string.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +print_help(void) +{ + printf("Usage: sgs [<options>]\n"); + printf("Test geometric sensitivities on predefined 3D scenes.\n"); + printf("\n"); + + printf( +" -b <box-parameters:...>\n" +" define an axis aligned bounding box. Available box\n" +" parameters are:\n"); + printf( +" low=x,y,z\n" +" defines the lower bound of the box\n" +" (default: %g,%g,%g).\n", + SGS_GEOMETRY_BOX_ARGS_DEFAULT.lower[0], + SGS_GEOMETRY_BOX_ARGS_DEFAULT.lower[1], + SGS_GEOMETRY_BOX_ARGS_DEFAULT.lower[2]); + printf( +" upp=x,y,z\n" +" defines the upper bound of the box\n" +" (default: %g,%g,%g).\n", + SGS_GEOMETRY_BOX_ARGS_DEFAULT.upper[0], + SGS_GEOMETRY_BOX_ARGS_DEFAULT.upper[1], + SGS_GEOMETRY_BOX_ARGS_DEFAULT.upper[2]); + printf( +" -d dump geometry following the VTK file format.\n"); + printf( +" -h display this help and exit.\n"); + printf( +" -t nthreads hint on the number of threads to use. By default use\n" +" as many threads as CPU cores.\n"); + printf( +" -v make the command verbose.\n"); + printf("\n"); + + sgs_fprint_copyright(stdout); + sgs_fprint_license(stdout); +} + +static res_T +parse_box_parameters(const char* str, void* ptr) +{ + char buf[128]; + struct sgs_args_geometry* geom = ptr; + char* key; + char* val; + char* ctx; + size_t len; + res_T res = RES_OK; + ASSERT(ptr && str); + + if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { + fprintf(stderr, SGS_LOG_ERROR_PREFIX + "Could not duplicate the box option string `%s'.\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + + key = strtok_r(buf, "=", &ctx); + val = strtok_r(NULL, "", &ctx); + + geom->type = SGS_GEOMETRY_BOX; + + if(!strcmp(key, "low")) { + res = cstr_to_list_double(val, ',', geom->args.box.lower, &len, 3); + if(res == RES_OK && len != 3) res = RES_BAD_ARG; + } else if(!strcmp(key, "upp")) { + res = cstr_to_list_double(val, ',', geom->args.box.upper, &len, 3); + if(res == RES_OK && len != 3) res = RES_BAD_ARG; + } else { + fprintf(stderr, SGS_LOG_ERROR_PREFIX + "Invalid box parameter `%s'.\n", key); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) { + fprintf(stderr, SGS_LOG_ERROR_PREFIX + "Error parsing the value of the `%s' box parameter: %s -- %s.\n", + key, val, res_to_cstr(res)); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * sgs_args API + ******************************************************************************/ +res_T +sgs_args_init(struct sgs_args* args, int argc, char** argv) +{ + int opt; + res_T res = RES_OK; + ASSERT(args && argc && argv); + + *args = SGS_ARGS_DEFAULT; + + while((opt = getopt(argc, argv, "b:dht:v")) != -1) { + switch(opt) { + case 'b': + res = cstr_parse_list(optarg, ':', parse_box_parameters, &args->geom); + break; + case 'd': args->dump_geometry = 1; break; + case 'h': + print_help(); + sgs_args_release(args); + args->quit = 1; + break; + case 't': + res = cstr_to_uint(optarg, &args->nthreads); + if(res == RES_OK && !args->nthreads) res = RES_BAD_ARG; + break; + case 'v': args->verbose = 1; break; + default: res = RES_BAD_ARG; break; + } + if(res != RES_OK) { + if(optarg) { + fprintf(stderr, SGS_LOG_ERROR_PREFIX + "%s: invalid option argument '%s' -- '%c'\n", + argv[0], optarg, opt); + } + goto error; + } + } +exit: + return res; +error: + sgs_args_release(args); + goto exit; +} + +void +sgs_args_release(struct sgs_args* args) +{ + ASSERT(args); + *args = SGS_ARGS_DEFAULT; +} diff --git a/src/sgs_args.h b/src/sgs_args.h @@ -0,0 +1,72 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE + * CNRS/LMAP + * |Meso|Star> (contact@meso-star.com) + * UPS/Laplace + * + * 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 SGS_ARGS_H +#define SGS_ARGS_H + +#include "sgs_geometry.h" +#include <limits.h> + +struct sgs_args_geometry { + enum sgs_geometry_type type; + union { + struct sgs_geometry_box_args box; + struct sgs_geometry_slope_args slope; + struct sgs_geometry_step_args step; + } args; +}; + +#define SGS_ARGS_GEOMETRY_DEFAULT__ { \ + SGS_GEOMETRY_BOX, \ + {SGS_GEOMETRY_BOX_ARGS_DEFAULT__} \ +} +static const struct sgs_args_geometry SGS_ARGS_GEOMETRY_DEFAULT = + SGS_ARGS_GEOMETRY_DEFAULT__; + +struct sgs_args { + struct sgs_args_geometry geom; /* The scene geometry */ + + /* Miscellaneous parameters */ + unsigned nthreads; + int dump_geometry; + int verbose; /* Verbosity level */ + int quit; /* Stop the command */ +}; + +#define SGS_ARGS_DEFAULT__ { \ + SGS_ARGS_GEOMETRY_DEFAULT__, /* Scene geometry */ \ + \ + UINT_MAX, /* #threads */ \ + 0, /* Dump geometry */ \ + 0, /* Verbose flag */ \ + 0 /* Stop the command */ \ +} +static const struct sgs_args SGS_ARGS_DEFAULT = SGS_ARGS_DEFAULT__; + +extern LOCAL_SYM res_T +sgs_args_init + (struct sgs_args* args, + int argc, + char** argv); + +extern LOCAL_SYM void +sgs_args_release + (struct sgs_args* args); + +#endif /* SGS_ARGS_H */ diff --git a/src/sgs_c.h b/src/sgs_c.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 SGS_C_H +#define SGS_C_H + +#include <rsys/logger.h> +#include <rsys/rsys.h> + +struct sgs { + struct s3d_device* s3d; + struct sgs_geometry* geom; + + unsigned int nthreads; /* #threads */ + + int verbose; + int dump_geometry; + + struct logger logger; + struct mem_allocator* allocator; +}; + +extern LOCAL_SYM void +setup_logger + (struct sgs* sgs); + +#endif /* SGS_C_H */ diff --git a/src/sgs_geometry.c b/src/sgs_geometry.c @@ -0,0 +1,353 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 "sgs.h" +#include "sgs_c.h" +#include "sgs_geometry.h" +#include "sgs_log.h" + +#include <star/s3d.h> + +#include <rsys/dynamic_array_double.h> +#include <rsys/dynamic_array_int.h> +#include <rsys/dynamic_array_size_t.h> +#include <rsys/ref_count.h> + +struct sgs_geometry { + struct darray_double verts; + struct darray_size_t tris; + struct darray_int tris_type; /* List of enum sgs_surface_type */ + + struct s3d_scene_view* view_sp; + struct s3d_scene_view* view_rt; + + enum sgs_geometry_type type; + + struct sgs* sgs; + ref_T ref; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +geometry_create + (struct sgs* sgs, + struct sgs_geometry** out_geom) +{ + struct sgs_geometry* geom = NULL; + struct mem_allocator* allocator = NULL; + res_T res = RES_OK; + ASSERT(sgs && out_geom); + + allocator = sgs_get_allocator(sgs); + geom = MEM_CALLOC(allocator, 1, sizeof(struct sgs_geometry)); + if(!geom) { + sgs_log_err(sgs, "Could not allocate the geometry.\n"); + res = RES_MEM_ERR; + goto error; + } + ref_init(&geom->ref); + geom->sgs = sgs; + darray_double_init(allocator, &geom->verts); + darray_size_t_init(allocator, &geom->tris); + darray_int_init(allocator, &geom->tris_type); + geom->type = SGS_GEOMETRY_NONE; + +exit: + *out_geom = geom; + return res; +error: + if(geom) { + sgs_geometry_ref_put(geom); + geom = NULL; + } + goto exit; +} + +/* Return the number of vertices */ +static FINLINE size_t +geometry_get_nvertices(const struct sgs_geometry* geom) +{ + ASSERT(geom); + return darray_double_size_get(&geom->verts) / 3/*#coords per vertex*/; +} + +/* Return the number of triangles */ +static FINLINE size_t +geometry_get_ntriangles(const struct sgs_geometry* geom) +{ + ASSERT(geom); + return darray_size_t_size_get(&geom->tris) / 3/*#ids per triangles*/; +} + +static void +geometry_get_vertex(const unsigned ivert, float pos[3], void* ctx) +{ + struct sgs_geometry* geom = ctx; + ASSERT(pos && ctx && ivert < geometry_get_nvertices(geom)); + pos[0] = (float)darray_double_cdata_get(&geom->verts)[ivert*3+0]; + pos[1] = (float)darray_double_cdata_get(&geom->verts)[ivert*3+1]; + pos[2] = (float)darray_double_cdata_get(&geom->verts)[ivert*3+2]; +} +static void +geometry_get_triangle(const unsigned itri, unsigned ids[3], void* ctx) +{ + struct sgs_geometry* geom = ctx; + ASSERT(ids && ctx && itri < geometry_get_ntriangles(geom)); + ids[0] = (unsigned)darray_size_t_cdata_get(&geom->tris)[itri*3+0]; + ids[1] = (unsigned)darray_size_t_cdata_get(&geom->tris)[itri*3+1]; + ids[2] = (unsigned)darray_size_t_cdata_get(&geom->tris)[itri*3+2]; +} + +static res_T +setup_view_rt(struct sgs_geometry* geom) +{ + struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; + struct s3d_shape* shape = NULL; + struct s3d_scene* scene = NULL; + unsigned ntris = 0; + unsigned nverts = 0; + res_T res = RES_OK; + ASSERT(geom); + + nverts = (unsigned)geometry_get_nvertices(geom); + ntris = (unsigned)geometry_get_ntriangles(geom); + + /* Setup the Star-3D vertex data */ + vdata.usage = S3D_POSITION; + vdata.type = S3D_FLOAT3; + vdata.get = geometry_get_vertex; + + /* Setup the Star-3D ray-tracing scene */ + res = s3d_shape_create_mesh(geom->sgs->s3d, &shape); + if(res != RES_OK) goto error; + res = s3d_mesh_setup_indexed_vertices + (shape, ntris, geometry_get_triangle, nverts, &vdata, 1, geom); + if(res != RES_OK) goto error; + res = s3d_scene_create(geom->sgs->s3d, &scene); + if(res != RES_OK) goto error; + res = s3d_scene_attach_shape(scene, shape); + if(res != RES_OK) goto error; + + /* Create the scene view */ + res = s3d_scene_view_create(scene, S3D_TRACE, &geom->view_rt); + if(res != RES_OK) goto error; + +exit: + if(shape) S3D(shape_ref_put(shape)); + if(scene) S3D(scene_ref_put(scene)); + return res; +error: + goto exit; +} + + +static res_T +setup_box_mesh + (struct sgs_geometry* geom, + const struct sgs_geometry_box_args* args) +{ + const double* low = NULL; + const double* upp = NULL; + double* vtx = NULL; + size_t* ids = NULL; + int* types = NULL; + res_T res = RES_OK; + ASSERT(geom && args); + + /* Allocate memory space */ + res = darray_double_resize(&geom->verts, 8/*#vertices*/*3/*#coords per vertex*/); + if(res != RES_OK) goto error; + res = darray_size_t_resize(&geom->tris, 12/*#triangles*/*3/*#ids per triangle*/); + if(res != RES_OK) goto error; + res = darray_int_resize(&geom->tris_type, 12/*#triangles*/); + if(res != RES_OK) goto error; + + /* Fetch allocated memory space */ + vtx = darray_double_data_get(&geom->verts); + ids = darray_size_t_data_get(&geom->tris); + types = darray_int_data_get(&geom->tris_type); + + /* Fetch input args */ + low = args->lower; + upp = args->upper; + + /* Setup the vertices */ + vtx[0*3+0] = low[0]; vtx[0*3+1] = low[1]; vtx[0*3+2] = low[2]; + vtx[1*3+0] = upp[0]; vtx[1*3+1] = low[1]; vtx[1*3+2] = low[2]; + vtx[2*3+0] = low[0]; vtx[2*3+1] = upp[1]; vtx[2*3+2] = low[2]; + vtx[3*3+0] = upp[0]; vtx[3*3+1] = upp[1]; vtx[3*3+2] = low[2]; + vtx[4*3+0] = low[0]; vtx[4*3+1] = low[1]; vtx[4*3+2] = upp[2]; + vtx[5*3+0] = upp[0]; vtx[5*3+1] = low[1]; vtx[5*3+2] = upp[2]; + vtx[6*3+0] = low[0]; vtx[6*3+1] = upp[1]; vtx[6*3+2] = upp[2]; + vtx[7*3+0] = upp[0]; vtx[7*3+1] = upp[1]; vtx[7*3+2] = upp[2]; + + /* Setup the triangles */ + ids[0*3+0] = 0; ids[0*3+1] = 4; ids[0*3+2] = 2; /* -X */ + ids[1*3+0] = 2; ids[1*3+1] = 4; ids[1*3+2] = 6; /* -X */ + ids[2*3+0] = 3; ids[2*3+1] = 7; ids[2*3+2] = 5; /* +X */ + ids[3*3+0] = 5; ids[3*3+1] = 1; ids[3*3+2] = 3; /* +X */ + ids[4*3+0] = 0; ids[4*3+1] = 1; ids[4*3+2] = 5; /* -Y */ + ids[5*3+0] = 5; ids[5*3+1] = 4; ids[5*3+2] = 0; /* -Y */ + ids[6*3+0] = 2; ids[6*3+1] = 6; ids[6*3+2] = 7; /* +Y */ + ids[7*3+0] = 7; ids[7*3+1] = 3; ids[7*3+2] = 2; /* +Y */ + ids[8*3+0] = 0; ids[8*3+1] = 2; ids[8*3+2] = 1; /* -Z */ + ids[9*3+0] = 1; ids[9*3+1] = 2; ids[9*3+2] = 3; /* -Z */ + ids[10*3+0] = 4; ids[10*3+1] = 5; ids[10*3+2] = 6; /* +Z */ + ids[11*3+0] = 6; ids[11*3+1] = 5; ids[11*3+2] = 7; /* +Z */ + + /* Setup the type of the triangles */ + types[0] = types[1] = SGS_SURFACE_X_NEG; + types[2] = types[3] = SGS_SURFACE_X_POS; + types[4] = types[5] = SGS_SURFACE_Y_NEG; + types[6] = types[7] = SGS_SURFACE_Y_POS; + types[8] = types[9] = SGS_SURFACE_Z_NEG; + types[10] = types[11] = SGS_SURFACE_Z_POS; + +exit: + return res; +error: + darray_double_clear(&geom->verts); + darray_size_t_clear(&geom->tris); + darray_int_clear(&geom->tris_type); + goto exit; +} + +static void +release_geometry(ref_T* ref) +{ + struct sgs_geometry* geom = CONTAINER_OF(ref, struct sgs_geometry, ref); + struct sgs* sgs = NULL; + ASSERT(ref); + + if(geom->view_sp) S3D(scene_view_ref_put(geom->view_sp)); + if(geom->view_rt) S3D(scene_view_ref_put(geom->view_rt)); + darray_double_release(&geom->verts); + darray_size_t_release(&geom->tris); + darray_int_release(&geom->tris_type); + + sgs = geom->sgs; + MEM_RM(sgs_get_allocator(sgs), geom); +} + +/******************************************************************************* + * API functions + ******************************************************************************/ +res_T +sgs_geometry_box_create + (struct sgs* sgs, + const struct sgs_geometry_box_args* args, + struct sgs_geometry** out_geom) +{ + struct sgs_geometry* geom = NULL; + res_T res = RES_OK; + ASSERT(sgs && args && out_geom); + + res = geometry_create(sgs, &geom); + if(res != RES_OK) goto error; + res = setup_box_mesh(geom, args); + if(res != RES_OK) goto error; + res = setup_view_rt(geom); + if(res != RES_OK) goto error; + +exit: + *out_geom = geom; + return res; +error: + if(geom) { + sgs_geometry_ref_put(geom); + geom = NULL; + } + goto exit; +} + +void +sgs_geometry_ref_get(struct sgs_geometry* geom) +{ + ASSERT(geom); + ref_get(&geom->ref); +} + +void +sgs_geometry_ref_put(struct sgs_geometry* geom) +{ + ASSERT(geom); + ref_put(&geom->ref, release_geometry); +} + +res_T +sgs_geometry_dump_vtk(const struct sgs_geometry* geom, FILE* stream) +{ + size_t i = 0; + size_t nverts = 0; + size_t ntris = 0; + res_T res = RES_OK; + int err = 0; + ASSERT(geom); + + nverts = geometry_get_nvertices(geom); + ntris = geometry_get_ntriangles(geom); + + #define FPRINTF(Fmt, Args) { \ + err = fprintf(stream, Fmt COMMA_##Args LIST_##Args); \ + if(err < 0) { \ + sgs_log_err(geom->sgs, "Error writing data.\n"); \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + + /* Write header */ + FPRINTF("# vtk DataFile Version 2.0\n", ARG0()); + FPRINTF("Geometry\n", ARG0()); + FPRINTF("ASCII\n", ARG0()); + FPRINTF("DATASET POLYDATA\n", ARG0()); + + /* Write the vertices */ + FPRINTF("POINTS %lu float\n", ARG1((unsigned long)nverts)); + FOR_EACH(i, 0, nverts) { + const double* pos = darray_double_cdata_get(&geom->verts) + i*3; + FPRINTF("%g %g %g\n", ARG3(pos[0], pos[1], pos[2])); + } + + /* Write the triangles */ + FPRINTF("POLYGONS %lu %lu\n", + ARG2((unsigned long)ntris, (unsigned long)ntris*4)); + FOR_EACH(i, 0, ntris) { + const size_t* ids = darray_size_t_cdata_get(&geom->tris) + i*3; + FPRINTF("3 %lu %lu %lu\n", ARG3(ids[0], ids[1], ids[2])); + } + + /* Write the triangle type */ + FPRINTF("CELL_DATA %lu\n", ARG1((unsigned long)ntris)); + FPRINTF("SCALARS Triangle_Type integer 1\n", ARG0()); + FPRINTF("LOOKUP_TABLE default\n", ARG0()); + FOR_EACH(i, 0, ntris) { + const enum sgs_surface_type type = darray_int_cdata_get(&geom->tris_type)[i]; + FPRINTF("%i\n", ARG1(type)); + } + + #undef FPRINTF + +exit: + return res; +error: + goto exit; +} diff --git a/src/sgs_geometry.h b/src/sgs_geometry.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 SGS_GEOMETRY_H +#define SGS_GEOMETRY_H + +#include <rsys/rsys.h> + +enum sgs_geometry_type { + SGS_GEOMETRY_BOX, + SGS_GEOMETRY_SLOPE, + SGS_GEOMETRY_STEP, + SGS_GEOMETRY_NONE, + SGS_GEOMETRY_TYPES_COUNT__ = SGS_GEOMETRY_NONE +}; + +enum sgs_surface_type { + SGS_SURFACE_X_NEG, /* -X face */ + SGS_SURFACE_X_POS, /* +X face */ + SGS_SURFACE_Y_NEG, /* -Y face */ + SGS_SURFACE_Y_POS, /* +Y face */ + SGS_SURFACE_Z_NEG, /* -Z face */ + SGS_SURFACE_Z_POS, /* +Z face */ + SGS_SURFACE_Z_SLOPE, /* +Z face representing a slope */ + SGS_SURFACE_Z_LVL0, /* +Z face representing the 1st level along X */ + SGS_SURFACE_Z_LVL1, /* +Z face representing the 2nd level along X */ + SGS_SURFACE_Z_STEP /* +Z face representing the step between the 2 levels */ +}; + +/* A simple axis aligned bounding box + * Z o--------u upper + * ^ Y /' /| + * |/ o--------o | + * o--> X | ' | | + * | o......|.o + * |. |/ + * lower l--------o */ +struct sgs_geometry_box_args { + double lower[3]; /* Lower bound */ + double upper[3]; /* Upper bound */ +}; +#define SGS_GEOMETRY_BOX_ARGS_DEFAULT__ {{0,0,0}, {1,1,1}} +static const struct sgs_geometry_box_args SGS_GEOMETRY_BOX_ARGS_DEFAULT = + SGS_GEOMETRY_BOX_ARGS_DEFAULT__; + +/* A "box" whose +Z face forms a slope along the X axis + * ,o + * ,'/| + * ,',o.| . . . . . + * Z ,',' | | ^ + * ^ Y o',' | | | + * |/ /,' | | elevation[1] + * o--> X . . . . o'' | | | + * ^ | ' | | | + * elevation[0] | o......|.u upper | + * | |. |/ | + * . . . . l--------o . . . . . . + * lower */ +struct sgs_geometry_slope_args { + double lower[2]; /* 2D lower bound in the XY plane */ + double upper[2]; /* 2D upper bound in the XY plane */ + double elevation[2]; /* The slope elevations in Z along the X axis */ +}; +#define SGS_GEOMETRY_SLOPE_ARGS_DEFAULT__ {{0,0}, {1,1}, {0.5,1}} +static const struct sgs_geometry_slope_args SGS_GEOMETRY_SLOPE_ARGS_DEFAULT = + SGS_GEOMETRY_SLOPE_ARGS_DEFAULT__; + + +/* A "box" whose +Z face forms a step along the X axis + * o---o + * /' /| + * o---o.| . . . . . + * Z | ' | | ^ + * ^ Y o--|.o | | | + * |/ / | | | elevation[1] + * o--> X . . . . o----o | | | + * ^ | ' ' | | | + * elevation[0] | o....s.|.u upper | + * | |, , |/ | + * . . . . l----s---o . . . . . . + * lower step */ +struct sgs_geometry_step_args { + double lower[2]; /* 2D lower bound in the XY plane */ + double upper[2]; /* 2D upper bound in the XY plane */ + double elevation[2]; /* The slope elevations in Z along the X axis */ + double step; /* X coordinate of the step */ +}; +#define SGS_GEOMETRY_STEP_ARGS_DEFAULT__ {{0,0}, {1,1}, {0.5,1}, 0.5} +static const struct sgs_geometry_step_args SGS_GEOMETRY_STEP_ARGS_DEFAULT = + SGS_GEOMETRY_STEP_ARGS_DEFAULT__; + +/* Forward declaration */ +struct sgs; +struct sgs_geometry; + +/******************************************************************************* + * Geometry API + ******************************************************************************/ +extern LOCAL_SYM res_T +sgs_geometry_box_create + (struct sgs* sgs, + const struct sgs_geometry_box_args* args, + struct sgs_geometry** geom); + +extern LOCAL_SYM res_T +sgs_geometry_slope_create + (struct sgs* sgs, + const struct sgs_geometry_slope_args* args, + struct sgs_geometry** geom); + +extern LOCAL_SYM res_T +sgs_geometry_step_create + (struct sgs* sgs, + const struct sgs_geometry_step_args* args, + struct sgs_geometry** geom); + +extern LOCAL_SYM void +sgs_geometry_ref_get + (struct sgs_geometry* geom); + +extern LOCAL_SYM void +sgs_geometry_ref_put + (struct sgs_geometry* geom); + +extern LOCAL_SYM res_T +sgs_geometry_dump_vtk + (const struct sgs_geometry* geom, + FILE* stream); + +#endif /* SGS_GEOMETRY_H */ diff --git a/src/sgs_log.c b/src/sgs_log.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 "sgs_c.h" +#include "sgs_log.h" + +#include <rsys/logger.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +print_out(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + fprintf(stderr, SGS_LOG_INFO_PREFIX"%s", msg); +} + +static void +print_err(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + fprintf(stderr, SGS_LOG_ERROR_PREFIX"%s", msg); +} + +static void +print_warn(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + fprintf(stderr, SGS_LOG_WARNING_PREFIX"%s", msg); +} + +static void +log_msg + (struct sgs* sgs, + const enum log_type stream, + const char* msg, + va_list vargs) +{ + ASSERT(sgs && msg); + if(sgs->verbose) { + CHK(logger_vprint(&sgs->logger, stream, msg, vargs) == RES_OK); + } +} + +/******************************************************************************* + * sgs log API + ******************************************************************************/ +void +sgs_log(struct sgs* sgs, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(sgs && msg); + va_start(vargs_list, msg); + log_msg(sgs, LOG_OUTPUT, msg, vargs_list); + va_end(vargs_list); +} + +void +sgs_log_err(struct sgs* sgs, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(sgs && msg); + va_start(vargs_list, msg); + log_msg(sgs, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +void +sgs_log_warn(struct sgs* sgs, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(sgs && msg); + va_start(vargs_list, msg); + log_msg(sgs, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); +} + +/******************************************************************************* + * Local function + ******************************************************************************/ +void +setup_logger(struct sgs* sgs) +{ + logger_init(sgs->allocator, &sgs->logger); + logger_set_stream(&sgs->logger, LOG_OUTPUT, print_out, NULL); + logger_set_stream(&sgs->logger, LOG_ERROR, print_err, NULL); + logger_set_stream(&sgs->logger, LOG_WARNING, print_warn, NULL); +} diff --git a/src/sgs_log.h b/src/sgs_log.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 SGS_LOG_H +#define SGS_LOG_H + +#include <rsys/rsys.h> + +#define SGS_LOG_INFO_PREFIX "\x1b[1m\x1b[32m>\x1b[0m " +#define SGS_LOG_ERROR_PREFIX "\x1b[31merror:\x1b[0m " +#define SGS_LOG_WARNING_PREFIX "\x1b[33mwarning:\x1b[0m " + +/* Forward declaration */ +struct sgs; + +extern LOCAL_SYM void +sgs_log + (struct sgs* sgs, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif + ; + +extern LOCAL_SYM void +sgs_log_err + (struct sgs* sgs, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif + ; + +extern LOCAL_SYM void +sgs_log_warn + (struct sgs* sgs, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif + ; + +#endif /* SGS_LOG_H */ diff --git a/src/sgs_main.c b/src/sgs_main.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 "sgs.h" +#include "sgs_args.h" +#include "sgs_log.h" + +#include <rsys/mem_allocator.h> + +int +main(int argc, char** argv) +{ + struct sgs_args args = SGS_ARGS_DEFAULT; + struct sgs* sgs = NULL; + size_t memsz = 0; + int err = 0; + res_T res = RES_OK; + + res = sgs_args_init(&args, argc, argv); + if(res != RES_OK) goto error; + if(args.quit) goto exit; + + res = sgs_create(NULL, &args, &sgs); + if(res != RES_OK) goto error; + + res = sgs_run(sgs); + if(res != RES_OK) goto error; + +exit: + sgs_args_release(&args); + if(sgs) sgs_release(sgs); + + /* Check memory leaks */ + memsz = mem_allocated_size(); + if(memsz) { + fprintf(stderr, SGS_LOG_WARNING_PREFIX"Memory leaks: %lu Bytes\n", + (unsigned long)memsz); + err = -1; + } + return err; +error: + err = -1; + goto exit; +}