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:
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;
+}