mrumtl

Describe materials that vary spectrally
git clone git://git.meso-star.fr/mrumtl.git
Log | Files | Refs | README | LICENSE

commit fcb41f4ea7b072718c08c5ab37ed436a2628fd25
parent 118f07a5f8c4d75f26427d23dbccc841c69e70eb
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  8 Jul 2022 11:42:39 +0200

API update and in-depth code rewrite

Diffstat:
Mcmake/CMakeLists.txt | 18++++++++++++------
Msrc/mrumtl.c | 405+++++++++++++++++++++----------------------------------------------------------
Msrc/mrumtl.h | 95++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Asrc/mrumtl_brdf.h | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/mrumtl_c.h | 51++-------------------------------------------------
Asrc/mrumtl_fetch.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_mrumtl.c | 21---------------------
Dsrc/test_mrumtl_band.c | 336-------------------------------------------------------------------------------
Asrc/test_mrumtl_bands.c | 354+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/test_mrumtl_wlen.c | 265-------------------------------------------------------------------------------
Asrc/test_mrumtl_wlens.c | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 1026 insertions(+), 1010 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -40,8 +40,14 @@ set(VERSION_MINOR 0) set(VERSION_PATCH 1) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) -set(MRUMTL_FILES_SRC mrumtl.c mrumtl_log.c) -set(MRUMTL_FILES_INC mrumtl_c.h mrumtl_log.h) +set(MRUMTL_FILES_SRC + mrumtl.c + mrumtl_log.c + mrumtl_fetch.c) +set(MRUMTL_FILES_INC + mrumtl_brdf.h + mrumtl_c.h + mrumtl_log.h) set(MRUMTL_FILES_INC_API mrumtl.h) set(MRUMTL_FILES_DOC COPYING README.md) @@ -77,12 +83,12 @@ if(NOT NO_TEST) endfunction() new_test(test_mrumtl) - new_test(test_mrumtl_wlen) - new_test(test_mrumtl_band) + new_test(test_mrumtl_wlens) + new_test(test_mrumtl_bands) if(CMAKE_COMPILER_IS_GNUCC) - target_link_libraries(test_mrumtl_wlen m) - target_link_libraries(test_mrumtl_band m) + target_link_libraries(test_mrumtl_wlens m) + target_link_libraries(test_mrumtl_bands m) endif() endif() diff --git a/src/mrumtl.c b/src/mrumtl.c @@ -25,10 +25,6 @@ #include <string.h> -#define MSG_INFO_PREFIX "MruMtl:\x1b[1m\x1b[32minfo\x1b[0m: " -#define MSG_ERROR_PREFIX "MruMtl:\x1b[1m\x1b[31merror\x1b[0m: " -#define MSG_WARNING_PREFIX "MruMtl:\x1b[1m\x1b[33mwarning\x1b[0m: " - /******************************************************************************* * Helper functions ******************************************************************************/ @@ -67,7 +63,7 @@ parse_brdf_lambertian } if(brdf->reflectivity < 0 || brdf->reflectivity > 1) { - log_err(mrumtl, "%s:%lu: the lambertian reflectivity must lie in [0, 1] " + log_err(mrumtl, "%s:%lu: the lambertian reflectivity must be in [0, 1] " "while the submitted value is %g.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), brdf->reflectivity); @@ -75,6 +71,12 @@ parse_brdf_lambertian goto error; } + tk = strtok_r(NULL, " \t", tk_ctx); + if(tk) { + log_warn(mrumtl, "%s:%lu: unexpected text `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + } + exit: return res; error: @@ -109,7 +111,7 @@ parse_brdf_specular } if(brdf->reflectivity < 0 || brdf->reflectivity > 1) { - log_err(mrumtl, "%s:%lu: the specular reflectivity must lie in [0, 1] " + log_err(mrumtl, "%s:%lu: the specular reflectivity must be in [0, 1] " "while the submitted value is %g.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), brdf->reflectivity); @@ -117,6 +119,12 @@ parse_brdf_specular goto error; } + tk = strtok_r(NULL, " \t", tk_ctx); + if(tk) { + log_warn(mrumtl, "%s:%lu: unexpected text `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + } + exit: return res; error: @@ -136,20 +144,22 @@ parse_brdf tk = strtok_r(NULL, " \t", tk_ctx); if(!tk) { - log_err(mrumtl, "%s:%lu: no BRDF type is defined.\n", + log_err(mrumtl, "%s:%lu: missing BRDF type.\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->value.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->value.specular); + res = parse_brdf_lambertian(mrumtl, txtrdr, tk_ctx, &brdf->param.lambertian); if(res != RES_OK) goto error; + + } else if(!strcmp(tk, "specular")) { brdf->type = MRUMTL_BRDF_SPECULAR; + res = parse_brdf_specular(mrumtl, txtrdr, tk_ctx, &brdf->param.specular); + if(res != RES_OK) goto error; + } else { log_err(mrumtl, "%s:%lu: invalid BRDF type `%s'.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); @@ -167,10 +177,11 @@ static res_T parse_wlen_brdf (struct mrumtl* mrumtl, struct txtrdr* txtrdr, - struct brdf_wlen* brdf) + struct mrumtl_brdf* brdf) { char* tk = NULL; char* tk_ctx = NULL; + double wlen = 0; res_T res = RES_OK; ASSERT(mrumtl && txtrdr && brdf); @@ -183,11 +194,11 @@ parse_wlen_brdf } if(!txtrdr_get_cline(txtrdr)) { - const size_t nexpect = darray_brdf_wlen_size_get(&mrumtl->brdf_wlens); + const size_t nexpect = darray_brdf_size_get(&mrumtl->brdfs); const size_t nparsed = (size_t) - (brdf - darray_brdf_wlen_cdata_get(&mrumtl->brdf_wlens)); + (brdf - darray_brdf_cdata_get(&mrumtl->brdfs)); log_err(mrumtl, - "%s:%lu: missing a wavelength BRDF. " + "%s:%lu: missing BRDF. " "Expecting %lu BRDF%swhile %lu %s parsed.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), (unsigned long)nexpect, nexpect == 1 ? " " : "s ", @@ -199,24 +210,19 @@ parse_wlen_brdf tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); ASSERT(tk); - res = cstr_to_double(tk, &brdf->wlen); + res = cstr_to_double(tk, &wlen); + if(res == RES_OK && wlen < 0) res = RES_BAD_ARG; 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; } + brdf->wlen[0] = wlen; + brdf->wlen[1] = wlen; - res = parse_brdf(mrumtl, txtrdr, &tk_ctx, &brdf->brdf); + res = parse_brdf(mrumtl, txtrdr, &tk_ctx, brdf); if(res != RES_OK) goto error; - tk = strtok_r(NULL, " \t", &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); - res = RES_BAD_ARG; - goto error; - } - exit: return res; error: @@ -227,7 +233,7 @@ static res_T parse_band_brdf (struct mrumtl* mrumtl, struct txtrdr* txtrdr, - struct brdf_band* brdf) + struct mrumtl_brdf* brdf) { char* tk = NULL; char* tk_ctx = NULL; @@ -243,11 +249,11 @@ parse_band_brdf } if(!txtrdr_get_cline(txtrdr)) { - const size_t nexpect = darray_brdf_band_size_get(&mrumtl->brdf_bands); + const size_t nexpect = darray_brdf_size_get(&mrumtl->brdfs); const size_t nparsed = (size_t) - (brdf - darray_brdf_band_cdata_get(&mrumtl->brdf_bands)); + (brdf - darray_brdf_cdata_get(&mrumtl->brdfs)); log_err(mrumtl, - "%s:%lu: missing a band BRDF. " + "%s:%lu: missing BRDF. " "Expecting %lu BRDF%swhile %lu %s parsed.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), (unsigned long)nexpect, nexpect == 1 ? " " : "s ", @@ -259,7 +265,8 @@ parse_band_brdf tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); ASSERT(tk); - res = cstr_to_double(tk, &brdf->wlen_min); + res = cstr_to_double(tk, &brdf->wlen[0]); + if(res == RES_OK && brdf->wlen[0] < 0) res = RES_BAD_ARG; 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); @@ -274,32 +281,25 @@ parse_band_brdf goto error; } - res = cstr_to_double(tk, &brdf->wlen_max); + res = cstr_to_double(tk, &brdf->wlen[1]); + if(res == RES_OK && brdf->wlen[1] < 0) res = RES_BAD_ARG; 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", + if(brdf->wlen[0] > brdf->wlen[1]) { + log_err(mrumtl, "%s:%lu: band boundaries are degenerated -- [%g, %g].\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), - brdf->wlen_min, brdf->wlen_max); + brdf->wlen[0], brdf->wlen[1]); res = RES_BAD_ARG; goto error; } - res = parse_brdf(mrumtl, txtrdr, &tk_ctx, &brdf->brdf); + res = parse_brdf(mrumtl, txtrdr, &tk_ctx, brdf); if(res != RES_OK) goto error; - tk = strtok_r(NULL, " \t", &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); - res = RES_BAD_ARG; - goto error; - } - exit: return res; error: @@ -307,7 +307,7 @@ error: } static res_T -parse_wlens_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) +parse_per_wlen_brdf(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) { char* tk = NULL; unsigned long count = 0; @@ -315,8 +315,6 @@ parse_wlens_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) 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", @@ -327,7 +325,7 @@ parse_wlens_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) res = cstr_to_ulong(tk, &count); if(res != RES_OK) { - log_err(mrumtl, "%s:%lu: invalid wavelengths count `%s'.\n", + log_err(mrumtl, "%s:%lu: invalid number of wavelengths `%s'.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); res = RES_BAD_ARG; goto error; @@ -335,34 +333,35 @@ parse_wlens_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) tk = strtok_r(NULL, " \t", tk_ctx); if(tk) { - log_err(mrumtl, "%s:%lu: unexpected text `%s'.\n", + log_warn(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); + res = darray_brdf_resize(&mrumtl->brdfs, count); if(res != RES_OK) { log_err(mrumtl, - "%s:%lu: could not allocate the list of per wavelength BRDF -- %s.\n", + "%s:%lu: could not allocate the list of BRDFs -- %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; + struct mrumtl_brdf* brdf = NULL; - brdf = darray_brdf_wlen_data_get(&mrumtl->brdf_wlens) + i; + brdf = darray_brdf_data_get(&mrumtl->brdfs) + i; res = parse_wlen_brdf(mrumtl, txtrdr, brdf); if(res != RES_OK) goto error; + ASSERT(brdf->wlen[0] == brdf->wlen[1]); - if(i > 0 && brdf[0].wlen <= brdf[-1].wlen) { + if(i > 0 && brdf[0].wlen[0] <= brdf[-1].wlen[0]) { 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)); + "%s:%lu: the BRDFs must be sorted un ascending order of wavelengths " + "(brdf %lu at %g nm; brdf %lu at %g nm).\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + (unsigned long)(i-1), brdf[-1].wlen[0], + (unsigned long)(i), brdf[ 0].wlen[0]); res = RES_BAD_ARG; goto error; } @@ -371,12 +370,12 @@ parse_wlens_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) exit: return res; error: - darray_brdf_wlen_clear(&mrumtl->brdf_wlens); + darray_brdf_clear(&mrumtl->brdfs); goto exit; } static res_T -parse_bands_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) +parse_per_band_brdf(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) { char* tk = NULL; unsigned long count = 0; @@ -384,8 +383,6 @@ parse_bands_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) 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", @@ -396,7 +393,7 @@ parse_bands_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) res = cstr_to_ulong(tk, &count); if(res != RES_OK) { - log_err(mrumtl, "%s:%lu: invalid bands count `%s'.\n", + log_err(mrumtl, "%s:%lu: invalid number of bands `%s'.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); res = RES_BAD_ARG; goto error; @@ -404,36 +401,37 @@ parse_bands_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) tk = strtok_r(NULL, " \t", tk_ctx); if(tk) { - log_err(mrumtl, "%s:%lu: unexpected text `%s'.\n", + log_warn(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); + res = darray_brdf_resize(&mrumtl->brdfs, count); if(res != RES_OK) { log_err(mrumtl, - "%s:%lu: could not allocate the list of per band BRDF -- %s.\n", + "%s:%lu: could not allocate the list of BRDFs -- %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; + struct mrumtl_brdf* brdf = NULL; - brdf = darray_brdf_band_data_get(&mrumtl->brdf_bands) + i; + brdf = darray_brdf_data_get(&mrumtl->brdfs) + i; res = parse_band_brdf(mrumtl, txtrdr, brdf); if(res != RES_OK) goto error; if(i > 0) { - if(brdf[0].wlen_min < brdf[-1].wlen_max - || brdf[0].wlen_min == brdf[-1].wlen_min) { + if(brdf[0].wlen[0] < brdf[-1].wlen[1] + || brdf[0].wlen[0] == brdf[-1].wlen[0]) { 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)); + "%s:%lu: the BRDFs must be sorted in ascending order " + "of bands and must not overlap (BRDF %lu in [%g, %g] nm; " + "BRDF %lu in [%g %g] nm)\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + (unsigned long)(i-1), brdf[-1].wlen[0], brdf[-1].wlen[1], + (unsigned long)(i), brdf[ 0].wlen[0], brdf[ 0].wlen[1]); res = RES_BAD_ARG; goto error; } @@ -443,7 +441,7 @@ parse_bands_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) exit: return res; error: - darray_brdf_band_clear(&mrumtl->brdf_bands); + darray_brdf_clear(&mrumtl->brdfs); goto exit; } @@ -452,9 +450,7 @@ clear_mrumtl(struct mrumtl* mrumtl) { ASSERT(mrumtl); str_clear(&mrumtl->name); - darray_brdf_band_clear(&mrumtl->brdf_bands); - darray_brdf_wlen_clear(&mrumtl->brdf_wlens); - mrumtl->brdf_list_type = BRDF_LIST_NONE__; + darray_brdf_clear(&mrumtl->brdfs); } static res_T @@ -499,13 +495,13 @@ load_stream ASSERT(tk); if(!strcmp(tk, "wavelengths")) { - res = parse_wlens_list(mrumtl, txtrdr, &tk_ctx); + res = parse_per_wlen_brdf(mrumtl, txtrdr, &tk_ctx); if(res != RES_BAD_ARG) goto error; } else if(!strcmp(tk, "bands")) { - res = parse_bands_list(mrumtl, txtrdr, &tk_ctx); + res = parse_per_band_brdf(mrumtl, txtrdr, &tk_ctx); if(res != RES_BAD_ARG) goto error; } else { - log_err(mrumtl, "%s:%lu: unexpected directive `%s'.\n", + log_err(mrumtl, "%s:%lu: invalid directive `%s'.\n", txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); res = RES_BAD_ARG; goto error; @@ -518,151 +514,6 @@ error: goto exit; } -static FINLINE int -cmp_band(const void* key, const void* elmt) -{ - const double* wlen = key; - const struct brdf_band* brdf_band = elmt; - ASSERT(key && elmt); - - if(*wlen < brdf_band->wlen_min) { - return -1; - } else if(*wlen >= brdf_band->wlen_max) { - return 1; - } else { - /* The key is included in the bound */ - return 0; - } -} - -static INLINE res_T -fetch_brdf_band - (const struct mrumtl* mrumtl, - const char* func_name, - const double wavelength, - const struct mrumtl_brdf** out_brdf) -{ - const struct brdf_band* brdf_band = NULL; - const struct brdf_band* brdf_bands = NULL; - size_t nbrdf_bands = 0; - res_T res = RES_OK; - ASSERT(mrumtl && func_name && out_brdf); - - brdf_bands = darray_brdf_band_cdata_get(&mrumtl->brdf_bands); - nbrdf_bands = darray_brdf_band_size_get(&mrumtl->brdf_bands); - - if(!nbrdf_bands) { - log_err(mrumtl, "%s: no BRDF is defined in `%s'.\n", - func_name, str_cget(&mrumtl->name)); - res = RES_BAD_ARG; - goto error; - } - - brdf_band = search_lower_bound - (&wavelength, brdf_bands, nbrdf_bands, sizeof(*brdf_bands), cmp_band); - - if(!brdf_band) { - /* All BRDFs are included in a band whose upper boundary are lower than or - * equal to `wavelength'. `Clamp' the fetch query to the last BRDF */ - brdf_band = &brdf_bands[nbrdf_bands-1]; - ASSERT(brdf_band->wlen_max <= wavelength); - } else { - ASSERT(wavelength < brdf_band->wlen_max); - if(brdf_band != brdf_bands && brdf_band->wlen_min > wavelength) { - /* The found BRDF is not the first and its associated band does not - * overlap the wavelength. The BRDF to use can be the found BRDF or the - * previous one, wrt the distance of the wavelength to the boundaries of - * the bands */ - const double dst0 = wavelength - brdf_band[-1].wlen_max; - const double dst1 = brdf_band[0].wlen_min - wavelength; - ASSERT(dst0 >= 0 && dst1 > 0); - if(dst0 < dst1) { - brdf_band = brdf_band - 1; - } - } - } - - *out_brdf = &brdf_band->brdf; - -exit: - return res; -error: - goto exit; -} - -static FINLINE int -cmp_wlen(const void* key, const void* elmt) -{ - const double* wlen = key; - const struct brdf_wlen* brdf_wlen = elmt; - ASSERT(key && elmt); - - if(*wlen < brdf_wlen->wlen) { - return -1; - } else if(*wlen > brdf_wlen->wlen) { - return 1; - } else { - return 0; - } -} - -static INLINE res_T -fetch_brdf_wlen - (const struct mrumtl* mrumtl, - const char* func_name, - const double wavelength, - const double sample, /* < 0 <=> no sample */ - const struct mrumtl_brdf** out_brdf) -{ - const struct brdf_wlen* brdf_wlen = NULL; - const struct brdf_wlen* brdf_wlens = NULL; - size_t nbrdf_wlens = 0; - res_T res = RES_OK; - ASSERT(mrumtl && func_name && out_brdf); - ASSERT(sample < 0 || sample < 1); - - brdf_wlens = darray_brdf_wlen_cdata_get(&mrumtl->brdf_wlens); - nbrdf_wlens = darray_brdf_wlen_size_get(&mrumtl->brdf_wlens); - - if(!nbrdf_wlens) { - log_err(mrumtl, "%s: no BRDF is defined in `%s'.\n", - func_name, str_cget(&mrumtl->name)); - res = RES_BAD_ARG; - goto error; - } - - brdf_wlen = search_lower_bound - (&wavelength, brdf_wlens, nbrdf_wlens, sizeof(*brdf_wlens), cmp_wlen); - - if(!brdf_wlen) { - /* All BRDFs are defined for a wavelength less than the submitted - * `wavelength'. */ - brdf_wlen = &brdf_wlens[nbrdf_wlens-1]; - ASSERT(brdf_wlen->wlen <= wavelength); - } else if(brdf_wlen != brdf_wlens) { - /* The found BRDF is not the first one => the submitted wavelength lies in - * [brdf_wlen[-1].wlen, brdf_wlen[0].wlen[. Select the right BRDF wrt the - * distance from the submitted `wavelengths' and the wavelength of the - * found BRDF and the one of the previous BRDF. */ - const double u = - (brdf_wlen[0].wlen - wavelength) - / (brdf_wlen[0].wlen - brdf_wlen[-1].wlen); - - if(sample >= 0) { - if(sample < u) brdf_wlen = brdf_wlen - 1; - } else { - if(u > 0.5) brdf_wlen = brdf_wlen - 1; - } - } - - *out_brdf = &brdf_wlen->brdf; - -exit: - return res; -error: - goto exit; -} - static void release_mrumtl(ref_T* ref) { @@ -670,8 +521,7 @@ 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); + darray_brdf_release(&mrumtl->brdfs); str_release(&mrumtl->name); /* First release the programs that uses the libs array */ @@ -713,9 +563,7 @@ mrumtl_create ref_init(&mrumtl->ref); mrumtl->allocator = allocator; mrumtl->verbose = args->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__; + darray_brdf_init(mrumtl->allocator, &mrumtl->brdfs); str_init(mrumtl->allocator, &mrumtl->name); if(args->logger) { @@ -810,65 +658,18 @@ error: goto exit; } -res_T -mrumtl_fetch_brdf - (const struct mrumtl* mrumtl, - const double wlen, /* In nanometers */ - const struct mrumtl_brdf** out_brdf) +size_t +mrumtl_get_brdfs_count(const struct mrumtl* mrumtl) { - res_T res = RES_OK; - - if(!mrumtl || !out_brdf) { - res = RES_BAD_ARG; - goto error; - } - - switch(mrumtl->brdf_list_type) { - case BRDF_LIST_BAND: - res = fetch_brdf_band(mrumtl, FUNC_NAME, wlen, out_brdf); - break; - case BRDF_LIST_WLEN: - res = fetch_brdf_wlen(mrumtl, FUNC_NAME, wlen, -1, out_brdf); - break; - default: FATAL("Unreachable code.\n"); break; - } - if(res != RES_OK) goto error; - -exit: - return res; -error: - goto exit; + ASSERT(mrumtl); + return darray_brdf_size_get(&mrumtl->brdfs); } -res_T -mrumtl_fetch_brdf2 - (const struct mrumtl* mrumtl, - const double wlen, /* In nanometers */ - const double sample, /* in [0, 1) */ - const struct mrumtl_brdf** out_brdf) +const struct mrumtl_brdf* +mrumtl_get_brdf(const struct mrumtl* mrumtl, const size_t ibrdf) { - res_T res = RES_OK; - - if(!mrumtl || !out_brdf || sample < 0 || sample >= 1) { - res = RES_BAD_ARG; - goto error; - } - - switch(mrumtl->brdf_list_type) { - case BRDF_LIST_BAND: - res = fetch_brdf_band(mrumtl, FUNC_NAME, wlen, out_brdf); - break; - case BRDF_LIST_WLEN: - res = fetch_brdf_wlen(mrumtl, FUNC_NAME, wlen, sample, out_brdf); - break; - default: FATAL("Unreachable code.\n"); break; - } - if(res != RES_OK) goto error; - -exit: - return res; -error: - goto exit; + ASSERT(mrumtl && ibrdf < mrumtl_get_brdfs_count(mrumtl)); + return darray_brdf_cdata_get(&mrumtl->brdfs) + ibrdf; } enum mrumtl_brdf_type @@ -878,17 +679,29 @@ mrumtl_brdf_get_type(const struct mrumtl_brdf* brdf) return brdf->type; } -double -mrumtl_brdf_lambertian_get_reflectivity(const struct mrumtl_brdf* brdf) +res_T +mrumtl_brdf_get_lambertian + (const struct mrumtl_brdf* brdf, + struct mrumtl_brdf_lambertian* lambertian) { - ASSERT(brdf && mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - return brdf->value.lambertian.reflectivity; -} + if(!brdf || !lambertian) return RES_BAD_ARG; + if(brdf->type != MRUMTL_BRDF_LAMBERTIAN) return RES_BAD_ARG; + lambertian->wavelengths[0] = brdf->wlen[0]; + lambertian->wavelengths[1] = brdf->wlen[1]; + lambertian->reflectivity = brdf->param.lambertian.reflectivity; + return RES_OK; +} -double -mrumtl_brdf_specular_get_reflectivity(const struct mrumtl_brdf* brdf) +res_T +mrumtl_brdf_get_specular + (const struct mrumtl_brdf* brdf, + struct mrumtl_brdf_specular* specular) { - ASSERT(brdf && mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - return brdf->value.specular.reflectivity; + if(!brdf || !specular) return RES_BAD_ARG; + if(brdf->type != MRUMTL_BRDF_SPECULAR) return RES_BAD_ARG; + specular->wavelengths[0] = brdf->wlen[0]; + specular->wavelengths[1] = brdf->wlen[1]; + specular->reflectivity = brdf->param.specular.reflectivity; + return RES_OK; } diff --git a/src/mrumtl.h b/src/mrumtl.h @@ -55,6 +55,24 @@ struct mrumtl_create_args { static const struct mrumtl_create_args MRUMTL_CREATE_ARGS_DEFAULT = MRUMTL_CREATE_ARGS_DEFAULT__; +/* Specular BRDF */ +struct mrumtl_brdf_specular { + double wavelengths[2]; /* Inclusive wavelength range in nanometers */ + double reflectivity; +}; +#define MRUMTL_BRDF_SPECULAR_NULL__ {0} +static const struct mrumtl_brdf_specular MRUMTL_BRDF_SPECULAR_NULL = + MRUMTL_BRDF_SPECULAR_NULL__; + +/* Lambertian BRDF */ +struct mrumtl_brdf_lambertian { + double wavelengths[2]; /* Inclusive wavelength range in nanometers */ + double reflectivity; +}; +#define MRUMTL_BRDF_LAMBERTIAN_NULL__ {0} +static const struct mrumtl_brdf_lambertian MRUMTL_BRDF_LAMBERTIAN_NULL = + MRUMTL_BRDF_LAMBERTIAN_NULL__; + /* Forward declaration of opaque data types */ struct mrumtl; struct mrumtl_brdf; @@ -88,51 +106,54 @@ mrumtl_load_stream FILE* stream, const char* stream_name); /* May be NULL */ -/* Return the material BRDF for the submitted wavelength. If the material is - * defined per spectral band, the function returned the BRDF associated to the - * band into which the submitted wavelength lies. If no spectral band includes - * this wavelength, the returned BRDF is the one of the nearest spectral band. - * For per wavelength material, the function returns the BRDF associated to the - * nearest wavelength regarding the submitted wavelength. */ -MRUMTL_API res_T -mrumtl_fetch_brdf - (const struct mrumtl* mrumtl, - const double wavelength, /* In nanometers */ - const struct mrumtl_brdf** brdf); +MRUMTL_API size_t +mrumtl_get_brdfs_count + (const struct mrumtl* mrumtl); -/* For materials defined per spectral band, the sample function has the same - * comportment of the fetch function. For per wavelength material, the BRDF to - * return is selected according to the coefficient `alpha' in [0, 1] defined as - * bellow: - * - * alpha = (lambda1 - wavelength) / (lambda1 - lambda0) - * - * with lambda0 < lambda1, the wavelengths of the BRDFs surrounding the - * submitted wavelength. The returned BRDF is either the BRDF corresponding to - * lambda0 or lambda1 whether `sample' is less than or greater than `alpha', - * respectively. - * - * If `wavelength' lies outside the material domain, the returned BRDF is - * either the first or the last one whether `wavelength' is below or above the - * wavelength material domain, respectively. */ -MRUMTL_API res_T -mrumtl_fetch_brdf2 +MRUMTL_API const struct mrumtl_brdf* +mrumtl_get_brdf (const struct mrumtl* mrumtl, - const double wavelength, /* In nanometers */ - const double sample, /* In [0, 1[. Ignored with nearest filtering */ - const struct mrumtl_brdf** brdf); + const size_t ibrdf); MRUMTL_API enum mrumtl_brdf_type mrumtl_brdf_get_type (const struct mrumtl_brdf* brdf); -MRUMTL_API double -mrumtl_brdf_lambertian_get_reflectivity - (const struct mrumtl_brdf* brdf); +MRUMTL_API res_T +mrumtl_brdf_get_lambertian + (const struct mrumtl_brdf* brdf, + struct mrumtl_brdf_lambertian* lambertian); -MRUMTL_API double -mrumtl_brdf_specular_get_reflectivity - (const struct mrumtl_brdf* brdf); +MRUMTL_API res_T +mrumtl_brdf_get_specular + (const struct mrumtl_brdf* brdf, + struct mrumtl_brdf_specular* specular); + +/* Fetch a BRDF with respect to the submitted wavelength and the given sample. + * The BRDF is chosen according to the alpha coefficient between [0, 1] defined + * as below: + * + * alpha = (lambda1 - wavelength) / (lambda1 - lambda0) + * + * with lambda0 < lambda1, the BRDF wavelengths surrounding the submitted + * wavelength. The index returned refers to the BRDF corresponding to lambda0 + * or lambda1 depending on whether the given sample is less than or greater + * than alpha, respectively. + * + * If the BRDF are stored by spectral band, lambda0 and lambda1 are the upper + * boundary of the lower band and the lower boundary of the upper band, + * respectively, which surround the wavelength. If the wavelength is in a + * specific band, the index for that band is simply returned. + * + * If the wavelength is outside the domain, the index returned refers to either + * the first or the last BRDF depending on whether the wavelength is below or + * above the domain, respectively. */ +MRUMTL_API res_T +mrumtl_fetch_brdf + (const struct mrumtl* mrumtl, + const double wavelength, + const double sample, /* In [0, 1[ */ + size_t* ibrdf); END_DECLS diff --git a/src/mrumtl_brdf.h b/src/mrumtl_brdf.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2020, 2021, 2022 |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 MRUMTL_BRDF_H +#define MRUMTL_BRDF_H + +#include "mrumtl.h" +#include <rsys/dynamic_array.h> + +struct mem_allocator; + +struct brdf_lambertian { + double reflectivity; +}; + +struct brdf_specular { + double reflectivity; +}; + +struct mrumtl_brdf { + double wlen[2]; /* Inclusive spectral range in nanometers */ + enum mrumtl_brdf_type type; + union { + struct brdf_lambertian lambertian; + struct brdf_specular specular; + } param; +}; + +static INLINE res_T +brdf_init(struct mem_allocator* allocator, struct mrumtl_brdf* brdf) +{ + ASSERT(brdf); + (void)allocator; + brdf->wlen[0] = 0; + brdf->wlen[1] = 0; + brdf->type = MRUMTL_BRDF_NONE__; + return RES_OK; +} + +/* Generate the dynamic array of BRDF */ +#define DARRAY_NAME brdf +#define DARRAY_DATA struct mrumtl_brdf +#define DARRAY_FUNCTOR_INIT brdf_init +#include <rsys/dynamic_array.h> + +#endif /* MRUMTL_BRDF_H */ diff --git a/src/mrumtl_c.h b/src/mrumtl_c.h @@ -16,62 +16,15 @@ #ifndef MRUMTL_C_H #define MRUMTL_C_H -#include "mrumtl.h" +#include "mrumtl_brdf.h" -#include <rsys/dynamic_array.h> #include <rsys/mem_allocator.h> #include <rsys/logger.h> #include <rsys/ref_count.h> #include <rsys/str.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; - } value; -}; - -struct brdf_wlen { - double wlen; /* In nanometers */ - struct mrumtl_brdf brdf; -}; - -struct brdf_band { - double wlen_min; /* Inclusive bound in nanometers */ - double wlen_max; /* Exclusive bound 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; + struct darray_brdf brdfs; struct str name; /* Name of the loaded material */ int verbose; diff --git a/src/mrumtl_fetch.c b/src/mrumtl_fetch.c @@ -0,0 +1,125 @@ +/* Copyright (C) 2020, 2021, 2022 |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 "mrumtl.h" +#include "mrumtl_c.h" +#include "mrumtl_log.h" +#include "mrumtl_brdf.h" + +#include <rsys/algorithm.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE int +cmp_brdf(const void* key, const void* item) +{ + const double wavelength = (*(const double*)key); + const struct mrumtl_brdf* brdf = item; + if(wavelength < brdf->wlen[0]) { + return -1; + } else if(wavelength > brdf->wlen[1]) { + return 1; + } else { + return 0; + } +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +mrumtl_fetch_brdf + (const struct mrumtl* mrumtl, + const double wavelength, + const double sample, /* In [0, 1[ */ + size_t* out_ibrdf) +{ + const struct mrumtl_brdf* brdfs = NULL; + const struct mrumtl_brdf* brdf = NULL; + size_t nbrdfs = 0; + size_t ibrdf = 0; + res_T res = RES_OK; + + if(!mrumtl + || wavelength < 0 + || sample < 0 + || sample >= 1 + || !out_ibrdf) { + res = RES_BAD_ARG; + goto error; + } + + brdfs = darray_brdf_cdata_get(&mrumtl->brdfs); + nbrdfs = darray_brdf_size_get(&mrumtl->brdfs); + + if(!nbrdfs) { + log_warn(mrumtl, "%s: no BRDF to fetch.\n", FUNC_NAME); + *out_ibrdf = 0; + goto exit; + } + + brdf = search_lower_bound + (&wavelength, brdfs, nbrdfs, sizeof(*brdfs), cmp_brdf); + + /* All BRDFs are set for a wavelength greater or equal to the submitted + * wavelength */ + if(brdf == brdfs) { + ASSERT(brdfs[0].wlen[0] > wavelength + || (brdfs[0].wlen[0] <= wavelength && wavelength <= brdfs[0].wlen[1])); + ibrdf = 0; + } + + /* All BRDFs are set for a wavelength less than the submitted wavelength */ + else if(!brdf) { + ASSERT(brdfs[nbrdfs-1].wlen[1] < wavelength); + ibrdf = nbrdfs - 1; + } + + /* The wavelength range of the found brdf function overlaps the submitted + * wavelength */ + else if(wavelength >= brdf->wlen[0] && wavelength <= brdf->wlen[1]) { + ibrdf = (size_t)(brdf - brdfs); + } + + /* The found BRDF is defined for a wavelength greater or equal to the + * submitted wavelength */ + else { + /* Compute the linear interpolation parameter that defines the submitted + * wavelength wrt to the wavelenths boundaries of the BRDF surrounding it*/ + const struct mrumtl_brdf* brdf0 = brdf-1; + const struct mrumtl_brdf* brdf1 = brdf; + const double u = + (brdf1->wlen[0] - wavelength) + / (brdf1->wlen[0] - brdf0->wlen[1]); + + /* Consider the linear interplation parameter previously defined as a + * probability and use the submitted sample to select one of the BRDFs + * surrounding the submitted wavelength. */ + if(sample < u) { + ibrdf = (size_t)(brdf - brdfs - 1); + } else { + ibrdf = (size_t)(brdf - brdfs); + } + } + + ASSERT(ibrdf < nbrdfs); + *out_ibrdf = ibrdf; + +exit: + return res; +error: + goto exit; +} diff --git a/src/test_mrumtl.c b/src/test_mrumtl.c @@ -31,20 +31,8 @@ main(int argc, char** argv) struct logger logger; struct mrumtl_create_args args = MRUMTL_CREATE_ARGS_DEFAULT; struct mrumtl* mrumtl; - FILE* fp; (void)argc, (void)argv; - CHK(fp = fopen("my_mat.mrumtl", "w+")); - - fprintf(fp, "# Comment\n"); - fprintf(fp, "wavelengths 5 # Comment at the end of a line\n"); - fprintf(fp, "0 lambertian 1\n"); - fprintf(fp, "0.1 specular 0.4\n"); - fprintf(fp, "0.2 lambertian 0.2\n"); - fprintf(fp, "3 lambertian 0.314\n"); - fprintf(fp, "4 specular 0.01\n"); - rewind(fp); - CHK(mrumtl_create(NULL, &mrumtl) == RES_BAD_ARG); CHK(mrumtl_create(&args, NULL) == RES_BAD_ARG); CHK(mrumtl_create(&args, &mrumtl) == RES_OK); @@ -69,21 +57,12 @@ main(int argc, char** argv) args.logger = &logger; args.verbose = 0; CHK(mrumtl_create(&args, &mrumtl) == RES_OK); - CHK(mrumtl_load(NULL, "my_mat.mrumtl") == RES_BAD_ARG); - CHK(mrumtl_load(mrumtl, NULL) == RES_BAD_ARG); - CHK(mrumtl_load(mrumtl, "undefined_file") == RES_IO_ERR); - CHK(mrumtl_load(mrumtl, "my_mat.mrumtl") == RES_OK); CHK(mrumtl_ref_put(mrumtl) == RES_OK); - args.allocator = NULL; CHK(mrumtl_create(&args, &mrumtl) == RES_OK); - CHK(mrumtl_load_stream(NULL, fp, NULL) == RES_BAD_ARG); - CHK(mrumtl_load_stream(mrumtl, NULL, NULL) == RES_BAD_ARG); - CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); CHK(mrumtl_ref_put(mrumtl) == RES_OK); mem_shutdown_proxy_allocator(&allocator); - fclose(fp); logger_release(&logger); CHK(mem_allocated_size() == 0); return 0; diff --git a/src/test_mrumtl_band.c b/src/test_mrumtl_band.c @@ -1,336 +0,0 @@ -/* Copyright (C) 2020, 2021, 2022 |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/>. */ - -#define _POSIX_C_SOURCE 200112L /* nextafter */ - -#include "mrumtl.h" -#include <rsys/mem_allocator.h> - -#include <math.h> -#include <stdio.h> - -static void -check_load(struct mrumtl* mrumtl) -{ - const char* filename = "my_mat.mrumtl"; - FILE* fp = NULL; - - CHK(mrumtl); - - CHK(fp = fopen(filename, "w+")); - fprintf(fp, "bands\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200 100"); /* Degenerated */ - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200 200 bad_type"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200 200 lambertian"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200 200 lambertian -0.00001"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200 200 lambertian 1.00001"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200 200 lambertian 1 invalid_word"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 2\n"); - fprintf(fp, "200 200 lambertian 1"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 2\n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "100 200 specular 0"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 2\n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "200 200 specular 0"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 2\n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "200 201 specular 0"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 2 \n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "200.1 200.2 specular 0"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 2\n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "200.1 200.2 specular 0\n"); - fprintf(fp, "dummy line that is not parsed."); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 3\n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "200.1 200.2 specular 0 \n"); - fprintf(fp, "200.2 200.2 lambertian 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 3\n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "200.1 200.2 specular -0.0001\n"); - fprintf(fp, "200.2 200.2 lambertian 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 3\n"); - fprintf(fp, "200 200 lambertian 1\n"); - fprintf(fp, "200.1 200.2 specular 1.0001\n"); - fprintf(fp, "200.2 200.2 lambertian 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 4 \t \t \n"); - fprintf(fp, "200 200 lambertian 1 \n"); - fprintf(fp, "200.1 200.2 specular 0.01\n"); - fprintf(fp, "200.2 200.2 lambertian 0\t \n"); - fprintf(fp, "250.3 2300 lambertian 0 \n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 0"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - fclose(fp); -} - -static void -check_fetch(struct mrumtl* mrumtl) -{ - const struct mrumtl_brdf* brdf = NULL; - const char* filename = "my_mat.mrumtl"; - FILE* fp = NULL; - - CHK(mrumtl); - - CHK(fp = fopen(filename, "w+")); - fprintf(fp, "bands 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - CHK(mrumtl_fetch_brdf(mrumtl, 1, &brdf) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 1\n"); - fprintf(fp, "200 280 lambertian 0.314\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(mrumtl_fetch_brdf(NULL, 200, &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf(mrumtl, 200, NULL) == RES_BAD_ARG); - - CHK(mrumtl_fetch_brdf(mrumtl, 200, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(mrumtl_fetch_brdf2(NULL, 200, 0, &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf2(mrumtl, 200, nextafter(0,-1), &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf2(mrumtl, 200, 1, &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf2(mrumtl, 200, 0, NULL) == RES_BAD_ARG); - - CHK(mrumtl_fetch_brdf2(mrumtl, 200, 0, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(mrumtl_fetch_brdf(mrumtl, 0, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(mrumtl_fetch_brdf(mrumtl, 300, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 7\n"); - fprintf(fp, "200 280 lambertian 0.314\n"); - fprintf(fp, "280 300 specular 0\n"); - fprintf(fp, "350 400.12 specular 0.123\n"); - fprintf(fp, "400.12 400.12 lambertian 0.9\n"); - fprintf(fp, "500.11 500.11 lambertian 0.4\n"); - fprintf(fp, "500.21 512.40 specular 0.4\n"); - fprintf(fp, "521.125 530.40 lambertian 0.7\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(mrumtl_fetch_brdf2(mrumtl, 200.1, 0, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(mrumtl_fetch_brdf2(mrumtl, 200.1, 0.9, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(mrumtl_fetch_brdf(mrumtl, 200.1, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(mrumtl_fetch_brdf(mrumtl, nextafter(280, 0), &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(mrumtl_fetch_brdf(mrumtl, nextafter(280, 300), &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0); - - CHK(mrumtl_fetch_brdf(mrumtl, nextafter(280, 300), &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0); - - CHK(mrumtl_fetch_brdf(mrumtl, nextafter(325, 300), &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0); - - CHK(mrumtl_fetch_brdf(mrumtl, nextafter(325, 350), &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.123); - - CHK(mrumtl_fetch_brdf(mrumtl, 353, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.123); - - CHK(mrumtl_fetch_brdf(mrumtl, 400.12, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.9); - - CHK(mrumtl_fetch_brdf(mrumtl, 500, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.4); - - CHK(mrumtl_fetch_brdf(mrumtl, 501.123, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.4); - - CHK(mrumtl_fetch_brdf(mrumtl, 517, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.7); - - CHK(mrumtl_fetch_brdf(mrumtl, 530.40, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.7); - - CHK(mrumtl_fetch_brdf(mrumtl, 20000, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.7); - - CHK(mrumtl_fetch_brdf(mrumtl, 0, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "bands 2\n"); - fprintf(fp, "380 780 lambertian 0.3\n"); - fprintf(fp, "1000 100000 lambertian 9.e-2\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(mrumtl_fetch_brdf(mrumtl, 300, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.3); - - CHK(mrumtl_fetch_brdf(mrumtl, 500, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.3); - - CHK(mrumtl_fetch_brdf(mrumtl, 800, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.3); - - CHK(mrumtl_fetch_brdf(mrumtl, 900, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 9.e-2); - - CHK(mrumtl_fetch_brdf(mrumtl, 97810, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 9.e-2); - - fclose(fp); -} - -int -main(int argc, char** argv) -{ - struct mrumtl_create_args args = MRUMTL_CREATE_ARGS_DEFAULT; - struct mrumtl* mrumtl = NULL; - (void)argc, (void)argv; - - args.verbose = 1; - CHK(mrumtl_create(&args, &mrumtl) == RES_OK); - - check_load(mrumtl); - check_fetch(mrumtl); - - CHK(mrumtl_ref_put(mrumtl) == RES_OK); - - CHK(mem_allocated_size() == 0); - return 0; - -} diff --git a/src/test_mrumtl_bands.c b/src/test_mrumtl_bands.c @@ -0,0 +1,354 @@ +/* Copyright (C) 2020, 2021, 2022 |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 "mrumtl.h" +#include <rsys/mem_allocator.h> + +#include <stdio.h> + +static void +test_load1(struct mrumtl* mrumtl) +{ + FILE* fp = NULL; + const char* filename = "test_file_band.mrumtl"; + const struct mrumtl_brdf* brdf = NULL; + struct mrumtl_brdf_lambertian lambertian = MRUMTL_BRDF_LAMBERTIAN_NULL; + struct mrumtl_brdf_specular specular = MRUMTL_BRDF_SPECULAR_NULL; + + CHK(fp = fopen(filename, "w+")); + fprintf(fp, "# Comment\n"); + fprintf(fp, "bands 2 # Comment at the end of a line\n"); + fprintf(fp, "200.1 280.3 lambertian 1\n"); + fprintf(fp, "381 700.4 specular 0.4\n"); + rewind(fp); + + CHK(mrumtl_load_stream(NULL, fp, filename) == RES_BAD_ARG); + CHK(mrumtl_load_stream(mrumtl, NULL, filename) == RES_BAD_ARG); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); + + CHK(mrumtl_load(NULL, filename) == RES_BAD_ARG); + CHK(mrumtl_load(mrumtl, NULL) == RES_BAD_ARG); + CHK(mrumtl_load(mrumtl, "invalid") == RES_IO_ERR); + CHK(mrumtl_load(mrumtl, filename) == RES_OK); + + CHK(mrumtl_get_brdfs_count(mrumtl) == 2); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 0)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + + CHK(mrumtl_brdf_get_lambertian(NULL, &lambertian) == RES_BAD_ARG); + CHK(mrumtl_brdf_get_lambertian(brdf, NULL) == RES_BAD_ARG); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 200.1); + CHK(lambertian.wavelengths[1] == 280.3); + CHK(lambertian.reflectivity == 1); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 1)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + + CHK(mrumtl_brdf_get_specular(NULL, &specular) == RES_BAD_ARG); + CHK(mrumtl_brdf_get_specular(brdf, NULL) == RES_BAD_ARG); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 381); + CHK(specular.wavelengths[1] == 700.4); + CHK(specular.reflectivity == 0.4); + + CHK(fclose(fp) == 0); +} + +static void +test_load2(struct mrumtl* mrumtl) +{ + struct mrumtl_brdf_lambertian lambertian = MRUMTL_BRDF_LAMBERTIAN_NULL; + struct mrumtl_brdf_specular specular = MRUMTL_BRDF_SPECULAR_NULL; + const struct mrumtl_brdf* brdf = NULL; + FILE* fp = NULL; + + CHK(fp = tmpfile()); + fprintf(fp, "bands 6\n"); + fprintf(fp, "200.0 200.0 lambertian 1\n"); + fprintf(fp, "200.1 200.2 specular 0\n"); + fprintf(fp, "200.2 200.5 specular 0.3\n"); + fprintf(fp, "300.4 480.2 specular 0.6\n"); + fprintf(fp, "500.0 501.0 lambertian 0.5\n"); + fprintf(fp, "680.6 780.7 specular 0.63\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + + CHK(mrumtl_get_brdfs_count(mrumtl) == 6); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 0)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_BAD_ARG); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 200.0 && lambertian.wavelengths[1] == 200.0); + CHK(lambertian.reflectivity == 1); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 1)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_BAD_ARG); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 200.1 && specular.wavelengths[1] == 200.2); + CHK(specular.reflectivity == 0); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 2)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 200.2 && specular.wavelengths[1] == 200.5); + CHK(specular.reflectivity == 0.3); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 3)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 300.4 && specular.wavelengths[1] == 480.2); + CHK(specular.reflectivity == 0.6); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 4)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 500.0 && lambertian.wavelengths[1] == 501.0); + CHK(lambertian.reflectivity == 0.5); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 5)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 680.6 && specular.wavelengths[1] == 780.7); + CHK(specular.reflectivity == 0.63); + + fclose(fp); +} + +static void +test_fetch(struct mrumtl* mrumtl) +{ + FILE* fp = NULL; + size_t ibrdf = 0; + + CHK(fp = tmpfile()); + fprintf(fp, "bands 0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + CHK(mrumtl_fetch_brdf(NULL, 400, 0.5, &ibrdf) == RES_BAD_ARG); + CHK(mrumtl_fetch_brdf(mrumtl, -1, 0.5, &ibrdf) == RES_BAD_ARG); + CHK(mrumtl_fetch_brdf(mrumtl, 400, -0.1, &ibrdf) == RES_BAD_ARG); + CHK(mrumtl_fetch_brdf(mrumtl, 400, 1, &ibrdf) == RES_BAD_ARG); + CHK(mrumtl_fetch_brdf(mrumtl, 400, 0.5, NULL) == RES_BAD_ARG); + CHK(mrumtl_fetch_brdf(mrumtl, 400, 0.5, &ibrdf) == RES_OK); + CHK(ibrdf >= mrumtl_get_brdfs_count(mrumtl)); + + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "200 300 lambertian 0.0\n"); + fprintf(fp, "300 400 lambertian 0.1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + CHK(mrumtl_fetch_brdf(mrumtl, 100, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 450, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 300, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 300.1, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + + CHK(fp = tmpfile()); + fprintf(fp, "bands 4\n"); + fprintf(fp, "100 150 lambertian 0\n"); + fprintf(fp, "200 200 lambertian 1\n"); + fprintf(fp, "300 400 lambertian 0.1\n"); + fprintf(fp, "400 401 specular 0.5\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + CHK(mrumtl_fetch_brdf(mrumtl, 160, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 160, 0.5, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 160, 0.8, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 200, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 250, 0.49, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 250, 0.5, &ibrdf) == RES_OK); + CHK(ibrdf == 2); + CHK(mrumtl_fetch_brdf(mrumtl, 400.1, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 3); +} + +static void +test_load_fail(struct mrumtl* mrumtl) +{ + FILE* fp = NULL; + + /* Invalid keyword */ + CHK(fp = tmpfile()); + fprintf(fp, "bande 1\n"); + fprintf(fp, "200.0 200.1 lambertian 1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* No band count */ + CHK(fp = tmpfile()); + fprintf(fp, "bands\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing a band definition */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "200.0 200.1 lambertian 1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid wavelengths */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "-200.0 200.1 lambertian 1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing a band boundary */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200.0 lambertian 1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid BRDF */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200.0 200.1 Lambertian 1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid reflectivity */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200.0 200.1 lambertian -0.1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid reflectivity */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200.1 200.2 specular 1.1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + + /* Additional parameters. Print a warning */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1 additional_text\n"); + fprintf(fp, "200.0 200.1 lambertian 0.1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + /* Unsorted BRDFs */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "200.1 200.2 specular 0\n"); + fprintf(fp, "200.0 200.1 lambertian 0.1\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* BRDFs overlap */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "200.0 200.2 lambertian 0.1\n"); + fprintf(fp, "200.1 200.3 specular 0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing data */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing data */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200 300"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing data */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200 300 lambertian"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing data */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200 300 specular"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Additional parameters. Print a warning */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "200 300 specular 1 additional_text"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); +} + +int +main(int argc, char** argv) +{ + struct mrumtl_create_args args = MRUMTL_CREATE_ARGS_DEFAULT; + struct mrumtl* mrumtl = NULL; + (void)argc, (void)argv; + + args.verbose = 1; + CHK(mrumtl_create(&args, &mrumtl) == RES_OK); + CHK(mrumtl_get_brdfs_count(mrumtl) == 0); + + test_load1(mrumtl); + test_load2(mrumtl); + test_fetch(mrumtl); + test_load_fail(mrumtl); + + CHK(mrumtl_ref_put(mrumtl) == RES_OK); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_mrumtl_wlen.c b/src/test_mrumtl_wlen.c @@ -1,265 +0,0 @@ -/* Copyright (C) 2020, 2021, 2022 |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/>. */ - -#define _POSIX_C_SOURCE 200112L /* nextafter */ - -#include "mrumtl.h" -#include <rsys/mem_allocator.h> - -#include <math.h> -#include <stdio.h> - -static void -check_load(struct mrumtl* mrumtl) -{ - const char* filename = "my_mat.mrumtl"; - FILE* fp = NULL; - - CHK(mrumtl); - - CHK(fp = fopen(filename, "w+")); - fprintf(fp, "wavelengths\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - fprintf(fp, "290\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - fprintf(fp, "290 bad_type\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - fprintf(fp, "290 lambertian\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - fprintf(fp, "290 lambertian -0.00001"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - fprintf(fp, "290 lambertian 1.00001"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - fprintf(fp, "290 lambertian 1 invalid_word\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 2\n"); - fprintf(fp, "290 lambertian 1\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 2\n"); - fprintf(fp, "290 lambertian 1\n"); - fprintf(fp, "280 specular 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 2\n"); - fprintf(fp, "290 lambertian 1\n"); - fprintf(fp, "290 specular 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 2\n"); - fprintf(fp, "290 lambertian 1\n"); - fprintf(fp, "290.1 specular -0.0001\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 2\n"); - fprintf(fp, "290 lambertian 1\n"); - fprintf(fp, "290.1 specular 1.0001\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 2\n"); - fprintf(fp, "290 lambertian 1\n"); - fprintf(fp, "290.1 specular 0.5\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 2 \t\t\n"); - fprintf(fp, "290 lambertian 1 \t \n"); - fprintf(fp, "290.1 specular 0.5 \n"); - fprintf(fp, "dummy line that is not parsed.\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - fclose(fp); -} - -static void -check_fetch(struct mrumtl* mrumtl) -{ - const struct mrumtl_brdf* brdf = NULL; - const char* filename = "my_mat.mrumtl"; - FILE* fp = NULL; - - CHK(mrumtl); - - CHK(fp = fopen(filename, "w+")); - fprintf(fp, "wavelengths 0\n"); - rewind(fp); - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - CHK(mrumtl_fetch_brdf(mrumtl, 2.9, &brdf) == RES_BAD_ARG); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 1\n"); - fprintf(fp, "280 lambertian 0.3"); - rewind(fp); - - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - - CHK(mrumtl_fetch_brdf(NULL, 0, &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf(mrumtl, 0, NULL) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf(mrumtl, 0, &brdf) == RES_OK); - CHK(brdf != NULL); - - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.3); - - CHK(fp = freopen(filename, "w+", fp)); - fprintf(fp, "wavelengths 10\n"); - fprintf(fp, "0.1 lambertian 0.1\n"); - fprintf(fp, "0.2 specular 0.2\n"); - fprintf(fp, "3.0 lambertian 0.3\n"); - fprintf(fp, "4.1 lambertian 0.4\n"); - fprintf(fp, "4.5 specular 0.5\n"); - fprintf(fp, "4.6 lambertian 0.21\n"); - fprintf(fp, "7.0 lambertian 0.11\n"); - fprintf(fp, "7.08 specular 0.61\n"); - fprintf(fp, "8.9 specular 0.123\n"); - fprintf(fp, "9.31 lambertian 0.23"); - rewind(fp); - - CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK); - CHK(mrumtl_fetch_brdf(mrumtl, 0.11, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.1); - - CHK(mrumtl_fetch_brdf(mrumtl, 0.15, &brdf) == RES_OK); - if(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN) { - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.1); - } else { - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.2); - } - - CHK(mrumtl_fetch_brdf(mrumtl, nextafter(0.15, 0), &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.1); - - CHK(mrumtl_fetch_brdf(mrumtl, nextafter(0.15, 1), &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.2); - - CHK(mrumtl_fetch_brdf(mrumtl, 4.1, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.4); - - CHK(mrumtl_fetch_brdf(mrumtl, 0, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.1); - - CHK(mrumtl_fetch_brdf(mrumtl, 200, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.23); - - CHK(mrumtl_fetch_brdf(mrumtl, 8.91, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.123); - - CHK(mrumtl_fetch_brdf(mrumtl, 2.9, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.3); - - CHK(mrumtl_fetch_brdf2(NULL, 0, 0, &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf2(mrumtl, 0, nextafter(0, -1), &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf2(mrumtl, 0, 1, &brdf) == RES_BAD_ARG); - CHK(mrumtl_fetch_brdf2(mrumtl, 0, 0, NULL) == RES_BAD_ARG); - - CHK(mrumtl_fetch_brdf2(mrumtl, 0.15, 0.6, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.2); - - CHK(mrumtl_fetch_brdf2(mrumtl, 0.15, 0.4, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.1); - - CHK(mrumtl_fetch_brdf2(mrumtl, 4.4, 0, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.4); - - CHK(mrumtl_fetch_brdf2(mrumtl, 4.4, 0.24, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.4); - - CHK(mrumtl_fetch_brdf2(mrumtl, 4.4, 0.26, &brdf) == RES_OK); - CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.5); - - fclose(fp); -} - -int -main(int argc, char** argv) -{ - struct mrumtl_create_args args = MRUMTL_CREATE_ARGS_DEFAULT; - struct mrumtl* mrumtl = NULL; - (void)argc, (void)argv; - - args.verbose = 1; - CHK(mrumtl_create(&args, &mrumtl) == RES_OK); - - check_load(mrumtl); - check_fetch(mrumtl); - - CHK(mrumtl_ref_put(mrumtl) == RES_OK); - - CHK(mem_allocated_size() == 0); - return 0; -} diff --git a/src/test_mrumtl_wlens.c b/src/test_mrumtl_wlens.c @@ -0,0 +1,308 @@ +/* Copyright (C) 2020, 2021, 2022 |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 "mrumtl.h" +#include <rsys/mem_allocator.h> + +#include <stdio.h> + +static void +test_load(struct mrumtl* mrumtl) +{ + struct mrumtl_brdf_specular specular = MRUMTL_BRDF_SPECULAR_NULL; + struct mrumtl_brdf_lambertian lambertian = MRUMTL_BRDF_LAMBERTIAN_NULL; + const struct mrumtl_brdf* brdf = NULL; + FILE* fp = NULL; + + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(mrumtl_get_brdfs_count(mrumtl) == 0); + CHK(fclose(fp) == 0); + + CHK(fp = tmpfile()); + fprintf(fp, "# Comment\n"); + fprintf(fp, "wavelengths 1\n"); + fprintf(fp, "\n"); + fprintf(fp, "200.1 lambertian 0\n"); + rewind(fp); + + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + + CHK(mrumtl_get_brdfs_count(mrumtl) == 1); + CHK(brdf = mrumtl_get_brdf(mrumtl, 0)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 200.1); + CHK(lambertian.wavelengths[1] == 200.1); + CHK(lambertian.reflectivity == 0); + CHK(fclose(fp) == 0); + + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 10\n"); + fprintf(fp, "\n"); + fprintf(fp, "# Short waves\n"); + fprintf(fp, "430 specular 0.02\n"); + fprintf(fp, "450 specular 0.05\n"); + fprintf(fp, "750\t specular 0.9\n"); + fprintf(fp, "# Long waves\n"); + fprintf(fp, "1100 lambertian 0.1\n"); + fprintf(fp, "1300 lambertian 0.57\n"); + fprintf(fp, "1400 lambertian 0.4\n"); + fprintf(fp, "2100 lambertian 0.3\n"); + fprintf(fp, "2500 lambertian\t0.9\n"); + fprintf(fp, "2900 lambertian 0.4\n"); + fprintf(fp, "100000 lambertian 0.0\n"); + rewind(fp); + + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(mrumtl_get_brdfs_count(mrumtl) == 10); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 0)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 430); + CHK(specular.wavelengths[1] == 430); + CHK(specular.reflectivity == 0.02); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 1)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 450); + CHK(specular.wavelengths[1] == 450); + CHK(specular.reflectivity == 0.05); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 2)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK); + CHK(specular.wavelengths[0] == 750); + CHK(specular.wavelengths[1] == 750); + CHK(specular.reflectivity == 0.9); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 3)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 1100); + CHK(lambertian.wavelengths[1] == 1100); + CHK(lambertian.reflectivity == 0.1); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 4)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 1300); + CHK(lambertian.wavelengths[1] == 1300); + CHK(lambertian.reflectivity == 0.57); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 5)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 1400); + CHK(lambertian.wavelengths[1] == 1400); + CHK(lambertian.reflectivity == 0.4); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 6)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 2100); + CHK(lambertian.wavelengths[1] == 2100); + CHK(lambertian.reflectivity == 0.3); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 7)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 2500); + CHK(lambertian.wavelengths[1] == 2500); + CHK(lambertian.reflectivity == 0.9); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 8)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 2900); + CHK(lambertian.wavelengths[1] == 2900); + CHK(lambertian.reflectivity == 0.4); + + CHK(brdf = mrumtl_get_brdf(mrumtl, 9)); + CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK); + CHK(lambertian.wavelengths[0] == 100000); + CHK(lambertian.wavelengths[1] == 100000); + CHK(lambertian.reflectivity == 0); + + CHK(fclose(fp) == 0); +} + +static void +test_fetch(struct mrumtl* mrumtl) +{ + FILE* fp = NULL; + size_t ibrdf = 0; + + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 400, 0.5, &ibrdf) == RES_OK); + CHK(ibrdf >= mrumtl_get_brdfs_count(mrumtl)); + + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 2\n"); + fprintf(fp, "200 lambertian 0\n"); + fprintf(fp, "300 lambertian 0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + CHK(mrumtl_fetch_brdf(mrumtl, 299, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 301, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 200, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 300, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 280, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 280, 0.19, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 280, 0.20, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 4\n"); + fprintf(fp, "100 lambertian 0\n"); + fprintf(fp, "200 lambertian 1\n"); + fprintf(fp, "300 lambertian 0.5\n"); + fprintf(fp, "400 specular 0.4\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + CHK(mrumtl_fetch_brdf(mrumtl, 50, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 0); + CHK(mrumtl_fetch_brdf(mrumtl, 120, 0.8, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 270, 0.29, &ibrdf) == RES_OK); + CHK(ibrdf == 1); + CHK(mrumtl_fetch_brdf(mrumtl, 270, 0.3, &ibrdf) == RES_OK); + CHK(ibrdf == 2); + CHK(mrumtl_fetch_brdf(mrumtl, 350, 0.5, &ibrdf) == RES_OK); + CHK(ibrdf == 3); + CHK(mrumtl_fetch_brdf(mrumtl, 450, 0, &ibrdf) == RES_OK); + CHK(ibrdf == 3); +} + +static void +test_load_fail(struct mrumtl* mrumtl) +{ + FILE* fp = NULL; + + /* No wavelength count */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths\n"); + fprintf(fp, "380 lambertian 0.5\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing a phase function */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 2\n"); + fprintf(fp, "380 lambertian 0.5\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid wavelength */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 1\n"); + fprintf(fp, "-380 lambertian 0.5\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Unsorted phase functions */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 2\n"); + fprintf(fp, "380 lambertian 0.5\n"); + fprintf(fp, "280 lambertian 0.0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Phase functions overlap */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 2\n"); + fprintf(fp, "280 lambertian 0.5\n"); + fprintf(fp, "280 lambertian 0.0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Additional text. Print a warning */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 2 additional_text\n"); + fprintf(fp, "280 lambertian 0.5\n"); + fprintf(fp, "380 lambertian 0.0\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + /* Missing data */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 1\n"); + fprintf(fp, "280\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing data */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 1\n"); + fprintf(fp, "280 lambertian\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Additional text. Print a warning */ + CHK(fp = tmpfile()); + fprintf(fp, "wavelengths 1\n"); + fprintf(fp, "280 lambertian 1 additional_text\n"); + rewind(fp); + CHK(mrumtl_load_stream(mrumtl, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); +} + +int +main(int argc, char** argv) +{ + struct mrumtl_create_args args = MRUMTL_CREATE_ARGS_DEFAULT; + struct mrumtl* mrumtl = NULL; + (void)argc, (void)argv; + + args.verbose = 1; + CHK(mrumtl_create(&args, &mrumtl) == RES_OK); + CHK(mrumtl_get_brdfs_count(mrumtl) == RES_OK); + + test_load(mrumtl); + test_fetch(mrumtl); + test_load_fail(mrumtl); + + CHK(mrumtl_ref_put(mrumtl) == RES_OK); + CHK(mem_allocated_size() == 0); + return 0; +}