commit 3b91a936e1b113f3c3eb2c6246fc199bd2f136b6
parent 500541ee420d6c9be4bb385708e22a2de712a310
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 28 Feb 2020 15:54:04 +0100
Write the mrumtl_load function
Write the while parsing process
Diffstat:
3 files changed, 584 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
@@ -21,6 +21,6 @@ for further informations on CMake.
## Licenses
Copyright (C) 2020 [|Meso|Star>](http://www.meso-star.com)
-<contact@meso-star.com>. They are released under the GPL v3+ license: GNU GPL
-version 3 or later. You are welcome to redistribute them under certain
-conditions; refer to the COPYING file for details.
+<contact@meso-star.com>. MRUMTL is free software released under the GPL v3+
+license: GNU GPL version 3 or later. You are welcome to redistribute them under
+certain conditions; refer to the COPYING file for details.
diff --git a/src/mrumtl.c b/src/mrumtl.c
@@ -13,13 +13,67 @@
* 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 "mrumtl.h"
+#include <rsys/cstr.h>
+#include <rsys/dynamic_array.h>
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
#include <rsys/ref_count.h>
+#include <rsys/text_reader.h>
+
+#include <string.h>
+
+enum brdf_list_type {
+ BRDF_LIST_BAND,
+ BRDF_LIST_WLEN,
+ BRDF_LIST_NONE__
+};
+
+struct brdf_lambertian {
+ double reflectivity;
+};
+
+struct brdf_specular {
+ double reflectivity;
+};
+
+struct mrumtl_brdf {
+ enum mrumtl_brdf_type type;
+ union {
+ struct brdf_lambertian lambertian;
+ struct brdf_specular specular;
+ } data;
+};
+
+struct brdf_wlen {
+ double wlen; /* In nanometers */
+ struct mrumtl_brdf brdf;
+};
+
+struct brdf_band {
+ double wlen_min; /* In nanometers */
+ double wlen_max; /* In nanometers */
+ struct mrumtl_brdf brdf;
+};
+
+/* Define the dynamic array of per wavelength BRDF */
+#define DARRAY_NAME brdf_wlen
+#define DARRAY_DATA struct brdf_wlen
+#include <rsys/dynamic_array.h>
+
+/* Define the dynamic array of per band BRDF */
+#define DARRAY_NAME brdf_band
+#define DARRAY_DATA struct brdf_band
+#include <rsys/dynamic_array.h>
struct mrumtl {
+ enum brdf_list_type brdf_list_type;
+ struct darray_brdf_wlen brdf_wlens;
+ struct darray_brdf_band brdf_bands;
+
int verbose;
struct logger* logger;
struct logger logger__;
@@ -83,6 +137,492 @@ log_msg
}
}
+static INLINE void
+log_err(const struct mrumtl* mrumtl, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(mrumtl && msg);
+
+ va_start(vargs_list, msg);
+ log_msg(mrumtl, LOG_ERROR, msg, vargs_list);
+ va_end(vargs_list);
+}
+
+static INLINE void
+log_warn(const struct mrumtl* mrumtl, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(mrumtl && msg);
+
+ va_start(vargs_list, msg);
+ log_msg(mrumtl, LOG_WARNING, msg, vargs_list);
+
+ va_end(vargs_list);
+}
+
+static res_T
+parse_brdf_lambertian
+ (struct mrumtl* mrumtl,
+ struct txtrdr* txtrdr,
+ char** tk_ctx,
+ struct brdf_lambertian* brdf)
+{
+ char* tk = NULL;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr && tk_ctx && brdf);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(mrumtl, "%s:%lu: missing lambertian reflectivity.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_double(tk, &brdf->reflectivity);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s:%lu: invalid lambertian reflectivity `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(brdf->reflectivity < 0 || brdf->reflectivity > 1) {
+ log_err(mrumtl, "%s:%lu: the lambertian reflectivity must lie in [0, 1] "
+ "while the submitted value is %g.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ brdf->reflectivity);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_brdf_specular
+ (struct mrumtl* mrumtl,
+ struct txtrdr* txtrdr,
+ char** tk_ctx,
+ struct brdf_specular* brdf)
+{
+ char* tk = NULL;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr && tk_ctx && brdf);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(mrumtl, "%s:%lu: missing specular reflectivity.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_double(tk, &brdf->reflectivity);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s:%lu: invalid specular reflectivity `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), &tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(brdf->reflectivity < 0 || brdf->reflectivity > 1) {
+ log_err(mrumtl, "%s:%lu: the specular reflectivity must lie in [0, 1] "
+ "while the submitted value is %g.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ brdf->reflectivity);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_brdf
+ (struct mrumtl* mrumtl,
+ struct txtrdr* txtrdr,
+ char** tk_ctx,
+ struct mrumtl_brdf* brdf)
+{
+ char* tk = NULL;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr && tk_ctx && brdf);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(mrumtl, "%s:%lu: no BRDF type is defined.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!strcmp(tk, "lambertian")) {
+ res = parse_brdf_lambertian(mrumtl, txtrdr, tk_ctx, &brdf->data.lambertian);
+ if(res != RES_OK) goto error;
+ brdf->type = MRUMTL_BRDF_LAMBERTIAN;
+ } else if(!strcmp(tk, "specular")) {
+ res = parse_brdf_specular(mrumtl, txtrdr, tk_ctx, &brdf->data.specular);
+ if(res != RES_OK) goto error;
+ brdf->type = MRUMTL_BRDF_SPECULAR;
+ } else {
+ log_err(mrumtl, "%s:%lu: invalid BRDF type `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_wlen_brdf
+ (struct mrumtl* mrumtl,
+ struct txtrdr* txtrdr,
+ struct brdf_wlen* brdf)
+{
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr && brdf);
+
+ res = txtrdr_read_line(txtrdr);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ if(!txtrdr_get_cline(txtrdr)) {
+ log_err(mrumtl,
+ "%s:%lu: missing a wavelength BRDF. "
+ "Expecting %lu BRDFs while only %lu was parsed.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ (unsigned long)darray_brdf_wlen_size_get(&mrumtl->brdf_wlens),
+ (unsigned long)(brdf - darray_brdf_wlen_cdata_get(&mrumtl->brdf_wlens)));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ ASSERT(tk);
+
+ res = cstr_to_double(tk, &brdf->wlen);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s:%lu: invalid wavelength `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ res = parse_brdf(mrumtl, txtrdr, &tk_ctx, &brdf->brdf);
+ if(res != RES_OK) goto error;
+
+ tk = strtok_r(NULL, "", &tk_ctx);
+ if(tk) {
+ log_err(mrumtl, "%s:%lu: unexpected directive `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_band_brdf
+ (struct mrumtl* mrumtl,
+ struct txtrdr* txtrdr,
+ struct brdf_band* brdf)
+{
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr && brdf);
+
+ res = txtrdr_read_line(txtrdr);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ if(!txtrdr_get_cline(txtrdr)) {
+ log_err(mrumtl,
+ "%s:%lu: missing a band BRDF. "
+ "Expecting %lu BRDFs while only %lu was parsed.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ (unsigned long)darray_brdf_band_size_get(&mrumtl->brdf_bands),
+ (unsigned long)(brdf - darray_brdf_band_cdata_get(&mrumtl->brdf_bands)));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ ASSERT(tk);
+
+ res = cstr_to_double(tk, &brdf->wlen_min);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s:%lu: invalid band min boundary `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ if(!tk) {
+ log_err(mrumtl, "%s:%lu: missing band max boundary.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_double(tk, &brdf->wlen_max);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s:%lu: invalid band max boundary `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ if(brdf->wlen_min > brdf->wlen_max) {
+ log_err(mrumtl, "%s:%lu: the band boundaries are degenerated -- [%g, %g].\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ brdf->wlen_min, brdf->wlen_max);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = parse_brdf(mrumtl, txtrdr, &tk_ctx, &brdf->brdf);
+ if(res != RES_OK) goto error;
+
+ tk = strtok_r(NULL, "", &tk_ctx);
+ if(tk) {
+ log_err(mrumtl, "%s:%lu: unexpected directive `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_wlens_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx)
+{
+ char* tk = NULL;
+ unsigned long count = 0;
+ unsigned long i;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr && tk_ctx);
+
+ mrumtl->brdf_list_type = BRDF_LIST_WLEN;
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(mrumtl, "%s:%lu: the number of wavelengths is missing.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_ulong(tk, &count);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s:%lu: invalid wavelengths count `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(NULL, "", tk_ctx);
+ if(tk) {
+ log_err(mrumtl, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = darray_brdf_wlen_resize(&mrumtl->brdf_wlens, count);
+ if(res != RES_OK) {
+ log_err(mrumtl,
+ "%s:%lu: could not allocate the list of per wavelength BRDF -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ FOR_EACH(i, 0, count) {
+ struct brdf_wlen* brdf = NULL;
+
+ brdf = darray_brdf_wlen_data_get(&mrumtl->brdf_wlens) + i;
+
+ res = parse_wlen_brdf(mrumtl, txtrdr, brdf);
+ if(res != RES_OK) goto error;
+
+ if(i > 0 && brdf[0].wlen <= brdf[-1].wlen) {
+ log_err(mrumtl,
+ "%s:%lu: the BRDF must be sorted un ascending order "
+ "wrt their wavelength.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ darray_brdf_wlen_clear(&mrumtl->brdf_wlens);
+ goto exit;
+}
+
+static res_T
+parse_bands_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx)
+{
+ char* tk = NULL;
+ unsigned long count = 0;
+ unsigned long i = 0;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr && tk_ctx);
+
+ mrumtl->brdf_list_type = BRDF_LIST_BAND;
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(mrumtl, "%s:%lu: the number of bands is missing.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_ulong(tk, &count);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s:%lu: invalid bands count `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(NULL, "", tk_ctx);
+ if(tk) {
+ log_err(mrumtl, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = darray_brdf_band_resize(&mrumtl->brdf_bands, count);
+ if(res != RES_OK) {
+ log_err(mrumtl,
+ "%s:%lu: could not allocate the list of per band BRDF -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ FOR_EACH(i, 0, count) {
+ struct brdf_band* brdf = NULL;
+
+ brdf = darray_brdf_band_data_get(&mrumtl->brdf_bands) + i;
+
+ res = parse_band_brdf(mrumtl, txtrdr, brdf);
+ if(res != RES_OK) goto error;
+
+ if(i > 0 && brdf[0].wlen_min < brdf[-1].wlen_max) {
+ log_err(mrumtl,
+ "%s:%lu: the BRDF must be sorted un ascending order "
+ "wrt their band and the bands must not overlapped.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ darray_brdf_band_clear(&mrumtl->brdf_bands);
+ goto exit;
+}
+
+static res_T
+parse_data(struct mrumtl* mrumtl, struct txtrdr* txtrdr)
+{
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && txtrdr);
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ ASSERT(tk);
+
+ if(!strcmp(tk, "wavelengths")) {
+ res = parse_wlens_list(mrumtl, txtrdr, &tk_ctx);
+ if(res != RES_BAD_ARG) goto error;
+ } else if(!strcmp(tk, "bands")) {
+ res = parse_bands_list(mrumtl, txtrdr, &tk_ctx);
+ if(res != RES_BAD_ARG) goto error;
+ } else {
+ log_err(mrumtl, "%s:%lu: unexpected directive `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+load_stream(struct mrumtl* mrumtl, FILE* stream, const char* stream_name)
+{
+ struct txtrdr* txtrdr = NULL;
+ res_T res = RES_OK;
+ ASSERT(mrumtl && stream && stream_name);
+
+ res = txtrdr_stream(mrumtl->allocator, stream, stream_name, '#', &txtrdr);
+ if(res != RES_OK) {
+ log_err(mrumtl, "Could not create the text reader to parse `%s' -- %s.\n",
+ stream_name, res_to_cstr(res));
+ goto error;
+ }
+
+ for(;;) {
+ res = txtrdr_read_line(txtrdr);
+ if(res != RES_OK) {
+ log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */
+
+ res = parse_data(mrumtl, txtrdr);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ if(txtrdr) txtrdr_ref_put(txtrdr);
+ return res;
+error:
+ goto exit;
+}
+
static void
release_mrumtl(ref_T* ref)
{
@@ -90,6 +630,9 @@ release_mrumtl(ref_T* ref)
ASSERT(ref);
mrumtl = CONTAINER_OF(ref, struct mrumtl, ref);
+ darray_brdf_band_release(&mrumtl->brdf_bands);
+ darray_brdf_wlen_release(&mrumtl->brdf_wlens);
+
/* First release the programs that uses the libs array */
if(mrumtl->logger == &mrumtl->logger__) logger_release(&mrumtl->logger__);
MEM_RM(mrumtl->allocator, mrumtl);
@@ -132,6 +675,9 @@ mrumtl_create
ref_init(&mrumtl->ref);
mrumtl->allocator = allocator;
mrumtl->verbose = verbose;
+ darray_brdf_band_init(mrumtl->allocator, &mrumtl->brdf_bands);
+ darray_brdf_wlen_init(mrumtl->allocator, &mrumtl->brdf_wlens);
+ mrumtl->brdf_list_type = BRDF_LIST_NONE__;
if(logger) {
mrumtl->logger = logger;
@@ -174,3 +720,32 @@ mrumtl_ref_put(struct mrumtl* mrumtl)
return RES_OK;
}
+res_T
+mrumtl_load(struct mrumtl* mrumtl, const char* filename)
+{
+ FILE* fp = NULL;
+ res_T res = RES_OK;
+
+ if(!mrumtl || filename) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ fp = fopen(filename, "r");
+ if(!fp) {
+ log_err(mrumtl, "%s: error opening file `%s' -- %s.\n",
+ FUNC_NAME, strerror(errno));
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ res = load_stream(mrumtl, fp, filename);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(fp) fclose(fp);
+ return res;
+error:
+ goto exit;
+}
+
diff --git a/src/mrumtl.h b/src/mrumtl.h
@@ -36,6 +36,12 @@
#define MRUMTL(Func) mrumtl_ ## Func
#endif
+enum mrumtl_brdf_type {
+ MRUMTL_BRDF_LAMBERTIAN,
+ MRUMTL_BRDF_SPECULAR,
+ MRUMTL_BRDF_NONE__
+};
+
/* Forward declaration of external data types */
struct logger;
struct mem_allocator;