commit 31f7fcb545f961828792a7ad8d887d759e0daa38
parent b979f617e787ff2e3a9a77fcedd5296d08f60ff1
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 5 Jan 2023 15:01:20 +0100
Merge branch 'release_0.1'
Diffstat:
| M | README.md | | | 28 | ++++++++++++++++++++++++++-- |
| M | cmake/CMakeLists.txt | | | 38 | ++++++++++++++++++++------------------ |
| A | doc/mrumtl.5.scd | | | 108 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | doc/mrumtl.5.txt | | | 114 | ------------------------------------------------------------------------------- |
| M | src/mrumtl.c | | | 594 | ++++++++++++++++++------------------------------------------------------------- |
| M | src/mrumtl.h | | | 120 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
| A | src/mrumtl_brdf.h | | | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/mrumtl_c.h | | | 37 | +++++++++++++++++++++++++++++++++++++ |
| A | src/mrumtl_fetch.c | | | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/mrumtl_log.c | | | 124 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/mrumtl_log.h | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | src/test_mrumtl.c | | | 44 | ++++++++++++++++---------------------------- |
| D | src/test_mrumtl_band.c | | | 334 | ------------------------------------------------------------------------------- |
| A | src/test_mrumtl_bands.c | | | 354 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/test_mrumtl_load.c | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | src/test_mrumtl_wlen.c | | | 263 | ------------------------------------------------------------------------------- |
| A | src/test_mrumtl_wlens.c | | | 308 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
17 files changed, 1537 insertions(+), 1268 deletions(-)
diff --git a/README.md b/README.md
@@ -8,7 +8,9 @@ and provide a library to load these data.
The `mrumtl` library is compatible GNU/Linux 64-bits. It relies on the
[CMake](http://www.cmake.org) and the
[RCMake](https://gitlab.com/vaplv/rcmake/) packages to build. They also depend
-on the [RSys](https://gitlab.com/vaplv/rsys/) library.
+on the [RSys](https://gitlab.com/vaplv/rsys/) library. It optionally depends
+on [scdoc](https://sr.ht/~sircmpwn/scdoc/) which, if available, is used to
+generate the man page of the file format.
To build the library, first ensure that CMake is installed on your system. Then
install the RCMake package as well as the aforementioned prerequisites. Finally
@@ -18,9 +20,31 @@ resulting project can be edited, built, tested and installed as any CMake
project. Refer to the [CMake documentation](https://cmake.org/documentation)
for further informations on CMake.
+
+## Release notes
+
+### Version 0.1
+
+- Complete rewrite of BRDF accessors. A BRDF is now represented by a single
+ integer and not directly by a generic data structure. Thus, the
+ `mrumtl_fetch_brdf` function returns an integer and not a pointer to the BRDF
+ which is now returned by the new function `mrumtl_get_brdf`. In addition,
+ data from a specific BRDF is now returned to a data structure that can
+ therefore store more than one scalar.
+- Update of the signature of the `mrumtl_create` function: the input arguments
+ are now grouped into a variable of type `struct mrumtl_create_args`. Thanks
+ to this structure and its default value, updating the input parameters should
+ now marginally affect the calling code.
+- Use scdoc rather than asciidoc as file format for man sources.
+
+### Version 0.0.1
+
+- Bump the CMake minimum version to 3.1. Previously it was set to 2.8 which is
+ deprecated.
+
## Licenses
-Copyright (C) 2020, 2021 [|Meso|Star>](http://www.meso-star.com)
+Copyright (C) 2020-2023 [|Méso|Star>](http://www.meso-star.com)
<contact@meso-star.com>. MruMtl is free software released under the GPL v3+
license: GNU GPL version 3 or later. You are welcome to redistribute them under
certain conditions; refer to the COPYING file for details.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+# Copyright (C) 2020-2023 |Méso|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
@@ -36,12 +36,18 @@ include_directories(${RSys_INCLUDE_DIR})
# Configure and define targets
################################################################################
set(VERSION_MAJOR 0)
-set(VERSION_MINOR 0)
-set(VERSION_PATCH 1)
+set(VERSION_MINOR 1)
+set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-set(MRUMTL_FILES_SRC mrumtl.c)
-set(MRUMTL_FILES_INC )
+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,30 +83,25 @@ 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)
- endif()
+ build_test(test_mrumtl_load)
endif()
################################################################################
# Man pages
###############################################################################
-find_program(A2X NAMES a2x a2x.py)
-if(NOT A2X)
+find_program(SCDOC NAMES scdoc)
+if(NOT SCDOC)
message(WARNING
- "The `a2x' program is missing. "
+ "The `scdoc' program is missing. "
"The mrumtl man page cannot be generated.")
else()
- set(_src ${PROJECT_SOURCE_DIR}/../doc/mrumtl.5.txt)
- set(_txt ${CMAKE_CURRENT_BINARY_DIR}/mrumtl.5.txt)
+ set(_src ${PROJECT_SOURCE_DIR}/../doc/mrumtl.5.scd)
add_custom_command(
OUTPUT mrumtl.5
- COMMAND ${CMAKE_COMMAND} -E copy ${_src} ${_txt}
- COMMAND ${A2X} -dmanpage -fmanpage ${_txt}
+ COMMAND ${SCDOC} < ${_src} > mrumtl.5
DEPENDS ${_src}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Buid ROFF man page mrumtl.5"
@@ -109,6 +110,7 @@ else()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mrumtl.5 DESTINATION share/man/man5)
endif()
+
################################################################################
# Define output & install directories
################################################################################
diff --git a/doc/mrumtl.5.scd b/doc/mrumtl.5.scd
@@ -0,0 +1,108 @@
+mrumtl(5)
+
+; Copyright (C) 2020-2023 |Méso|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/>.
+
+# NAME
+
+mrumtl - ModRadUrb MaTeriaL file format
+
+# DESCRIPTION
+
+*mrumtl* is a text file format that describes a Bidirectional Reflectance
+Distribution Function (BRDF) whose type and parameters can vary spectrally. Its
+data are described for a set of wavelengths or spectral bands that must be
+listed in ascending order.
+
+Characters behind the hash mark (#) are considered comments and are therefore
+ignored, as well as empty lines, i.e. lines without any characters or composed
+only of spaces and tabs.
+
+# GRAMMAR
+
+```
+<mrumtl> ::= <per-wlen-BRDF>
+ | <per-band-BRDF>
+
+---
+
+<per-wlen-BRDF> ::= wavelengths <wavelengths-count>
+ <wlen-BRDF>
+ [ <wlen-BRDF> ... ]
+
+<wlen-BRDF> ::= <wavelength> <BRDF>
+<wavelengths-count> ::= INTEGER
+<wavelength> ::= REAL # in nanometer
+
+---
+
+<per-band-BRDF> ::= bands <bands-count>
+ <band-BRDF>
+ [ <band-BRDF> ... ]
+
+<band-BRDF> ::= <wavelength-min> <wavelength-max> <BRDF>
+
+<bands-count> ::= INTEGER
+<wavelength-min> ::= REAL # Inclusive bound in nanometers
+<wavelength-max> ::= REAL # Inclusive bound in nanometers
+
+---
+
+<BRDF> ::= <BRDF-lambertian>
+ | <BRDF-specular>
+
+<BRDF-lambertian> ::= lambertian <reflectivity>
+<BRDF-specular> ::= specular <reflectivity>
+<reflectivity> ::= REAL # In [0, 1]
+```
+
+# EXAMPLES
+
+Describe a material with only two bands: one for the visible part of the
+spectrum and one for the long waves. In both cases use a diffuse reflectivity:
+
+```
+bands 2
+380 780 lambertian 0.9 # Visible part
+1000 100000 lambertian 0.1 # Infrared
+```
+
+Setup a material for a list of 17 wavelengths. This material is diffuse in
+short waves and specular in long waves:
+
+```
+wavelengths 17
+
+# Short waves
+430 lambertian 5.2e-2
+450 lambertian 6.2e-2
+500 lambertian 6.5e-002
+600 lambertian 0.165
+750 lambertian 0.175
+
+# Long waves
+1100 specular 0.1
+1300 specular 0.17
+1400 specular 0.1
+2000 specular 0.1
+2100 specular 0.4
+2300 specular 0.18
+2500 specular 0.9
+2600 specular 0.95
+2900 specular 0.4
+3000 specular 0.3
+4000 specular 0.0
+100000 specular 0.0
+```
diff --git a/doc/mrumtl.5.txt b/doc/mrumtl.5.txt
@@ -1,114 +0,0 @@
-// Copyright (C) 2020 |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/>.
-:toc:
-
-mrumtl(5)
-=========
-
-NAME
-----
-mrumtl - ModRadUrb MaTeriaL file format
-
-DESCRIPTION
------------
-
-A *mrumtl* file defines a spectral varying Bidirectional Reflectance
-Distribution Function (BRDF). Both the parameters and the type of the function
-can vary over the spectrum. These data can be defined for a list of
-wavelengths or for a set a spectral bands. In both cases, the wavelengths or
-the band boundaries are given in nanometers and must be listed in ascending
-orders. In addition the spectral bands must not overlapped.
-
-Characters behind the hash mark (#) are considered as comments and are thus
-ignored. Empty lines, i.e. lines without any characters or composed only of
-spaces and tabulations, are simply skipped.
-
-GRAMMAR
--------
-
-[verse]
--------
-<mrumtl> ::= <BRDF-list-wlen>
- | <BRDF-list-band>
-
-<BRDF-list-wlen> ::= wavelengths <wavelengths-count>
- <BRDF-wlen>
- [ <BRDF-wlen> ... ]
-
-<BRDF-list-band> ::= bands <bands-count>
- <BRDF-band>
- [ <BRDF-band> ... ]
-
-<wavelengths-count> ::= INTEGER
-<bands-count> ::= INTEGER
-
-<BRDF-wlen> ::= <wavelength> <BRDF>
-
-<BRDF-band> ::= <band-bound-min> <band-bound-max> <BRDF>
-<bound-bound-min> ::= <wavelength>
-<bound-bound-max> ::= <wavelength>
-
-<wavelength> ::= DOUBLE # in nanometer
-
-<BRDF> ::= <BRDF-lambertian>
- | <BRDF-specular>
-
-<BRDF-lambertian> ::= lambertian <reflectivity>
-<BRDF-specular> ::= specular <reflectivity>
-<reflectivity> ::= DOUBLE
--------
-
-EXAMPLES
---------
-
-Describe a material with only two bands: one for the visible part of the
-spectrum and one for the long waves. In both cases use a diffuse reflectivity:
-
-[verse]
--------
-bands 2
-380 780 lambertian 0.9 # Visible part
-1000 100000 lambertian 0.1 # Infrared
--------
-
-Setup a material for a list of 17 wavelengths. This material is diffuse in
-short waves and specular in long waves:
-
-[verse]
--------
-wavelengths 17
-
-# Short waves
-430 lambertian 5.2e-2
-450 lambertian 6.2e-2
-500 lambertian 6.5e-002
-600 lambertian 0.165
-750 lambertian 0.175
-
-# Long waves
-1100 specular 0.1
-1300 specular 0.17
-1400 specular 0.1
-2000 specular 0.1
-2100 specular 0.4
-2300 specular 0.18
-2500 specular 0.9
-2600 specular 0.95
-2900 specular 0.4
-3000 specular 0.3
-4000 specular 0.0
-100000 specular 0.0
--------
-
diff --git a/src/mrumtl.c b/src/mrumtl.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|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
@@ -16,169 +16,23 @@
#define _POSIX_C_SOURCE 200112L /* strtok_r support */
#include "mrumtl.h"
+#include "mrumtl_c.h"
+#include "mrumtl_log.h"
#include <rsys/algorithm.h>
#include <rsys/cstr.h>
-#include <rsys/dynamic_array.h>
-#include <rsys/logger.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/ref_count.h>
-#include <rsys/str.h>
#include <rsys/text_reader.h>
#include <string.h>
-enum brdf_list_type {
- BRDF_LIST_BAND,
- BRDF_LIST_WLEN,
- BRDF_LIST_NONE__
-};
-
-struct brdf_lambertian {
- double reflectivity;
-};
-
-struct brdf_specular {
- double reflectivity;
-};
-
-struct mrumtl_brdf {
- enum mrumtl_brdf_type type;
- union {
- struct brdf_lambertian lambertian;
- struct brdf_specular specular;
- } 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 str name; /* Name of the loaded material */
-
- int verbose;
- struct logger* logger;
- struct logger logger__;
- struct mem_allocator* allocator;
- ref_T ref;
-};
-
-#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
******************************************************************************/
-static void
-print_info(const char* msg, void* ctx)
-{
- (void)ctx;
- fprintf(stderr, MSG_INFO_PREFIX"%s", msg);
-}
-
-static void
-print_err(const char* msg, void* ctx)
-{
- (void)ctx;
- fprintf(stderr, MSG_ERROR_PREFIX"%s", msg);
-}
-
-static void
-print_warn(const char* msg, void* ctx)
-{
- (void)ctx;
- fprintf(stderr, MSG_WARNING_PREFIX"%s", msg);
-}
-
-static res_T
-setup_default_logger(struct mem_allocator* allocator, struct logger* logger)
-{
- res_T res = RES_OK;
- ASSERT(logger);
- res = logger_init(allocator, logger);
- if(res != RES_OK) return res;
- logger_set_stream(logger, LOG_OUTPUT, print_info, NULL);
- logger_set_stream(logger, LOG_ERROR, print_err, NULL);
- logger_set_stream(logger, LOG_WARNING, print_warn, NULL);
- return RES_OK;
-}
-
-static INLINE void
-log_msg
- (const struct mrumtl* mrumtl,
- const enum log_type stream,
- const char* msg,
- va_list vargs)
-{
- ASSERT(mrumtl && msg);
- if(mrumtl->verbose) {
- res_T res; (void)res;
- res = logger_vprint(mrumtl->logger, stream, msg, vargs);
- ASSERT(res == RES_OK);
- }
-}
-
-static INLINE void
-log_err
- (const struct mrumtl* mrumtl,
- const char* msg, ...)
-#ifdef COMPILER_GCC
- __attribute((format(printf, 2, 3)))
-#endif
-;
-
-static INLINE void
-log_warn
- (const struct mrumtl* mrumtl,
- const char* msg, ...)
-#ifdef COMPILER_GCC
- __attribute((format(printf, 2, 3)))
-#endif
-;
-
-void
-log_err(const struct mrumtl* mrumtl, const char* msg, ...)
-{
- va_list vargs_list;
- ASSERT(mrumtl && msg);
-
- va_start(vargs_list, msg);
- log_msg(mrumtl, LOG_ERROR, msg, vargs_list);
- va_end(vargs_list);
-}
-
-void
-log_warn(const struct mrumtl* mrumtl, const char* msg, ...)
+static INLINE res_T
+check_mrumtl_create_args(const struct mrumtl_create_args* args)
{
- va_list vargs_list;
- ASSERT(mrumtl && msg);
-
- va_start(vargs_list, msg);
- log_msg(mrumtl, LOG_WARNING, msg, vargs_list);
-
- va_end(vargs_list);
+ /* Nothing to check. Only return RES_BAD_ARG if args is NULL */
+ return args ? RES_OK : RES_BAD_ARG;
}
static res_T
@@ -209,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);
@@ -217,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:
@@ -251,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);
@@ -259,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:
@@ -278,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);
@@ -309,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);
@@ -325,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 ",
@@ -341,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:
@@ -369,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;
@@ -385,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 ",
@@ -401,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);
@@ -416,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:
@@ -449,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;
@@ -457,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",
@@ -469,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;
@@ -477,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;
}
@@ -513,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;
@@ -526,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",
@@ -538,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;
@@ -546,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;
}
@@ -585,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;
}
@@ -594,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
@@ -641,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;
@@ -660,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)
{
@@ -812,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 */
@@ -826,27 +534,24 @@ release_mrumtl(ref_T* ref)
******************************************************************************/
res_T
mrumtl_create
- (struct logger* logger, /* NULL <=> use default logger */
- struct mem_allocator* mem_allocator,
- const int verbose, /* Verbosity level */
+ (const struct mrumtl_create_args* args,
struct mrumtl** out_mrumtl)
{
struct mrumtl* mrumtl = NULL;
struct mem_allocator* allocator = NULL;
res_T res = RES_OK;
- if(!out_mrumtl) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!out_mrumtl) { res = RES_BAD_ARG; goto error; }
+ res = check_mrumtl_create_args(args);
+ if(res != RES_OK) goto error;
- allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
+ allocator = args->allocator ? args->allocator : &mem_default_allocator;
mrumtl = MEM_CALLOC(allocator, 1, sizeof(*mrumtl));
if(!mrumtl) {
- if(verbose) {
- #define ERR_STR "Could not allocate the MRUMTL handler.\n"
- if(logger) {
- logger_print(logger, LOG_ERROR, ERR_STR);
+ if(args->verbose) {
+ #define ERR_STR "Could not allocate the MruMtl handler.\n"
+ if(args->logger) {
+ logger_print(args->logger, LOG_ERROR, ERR_STR);
} else {
fprintf(stderr, MSG_ERROR_PREFIX ERR_STR);
}
@@ -857,20 +562,18 @@ mrumtl_create
}
ref_init(&mrumtl->ref);
mrumtl->allocator = allocator;
- mrumtl->verbose = verbose;
- darray_brdf_band_init(mrumtl->allocator, &mrumtl->brdf_bands);
- darray_brdf_wlen_init(mrumtl->allocator, &mrumtl->brdf_wlens);
- mrumtl->brdf_list_type = BRDF_LIST_NONE__;
+ mrumtl->verbose = args->verbose;
+ darray_brdf_init(mrumtl->allocator, &mrumtl->brdfs);
str_init(mrumtl->allocator, &mrumtl->name);
- if(logger) {
- mrumtl->logger = logger;
+ if(args->logger) {
+ mrumtl->logger = args->logger;
} else {
- res = setup_default_logger(mrumtl->allocator, &mrumtl->logger__);
+ res = setup_log_default(mrumtl);
if(res != RES_OK) {
- if(verbose) {
+ if(args->verbose) {
fprintf(stderr, MSG_ERROR_PREFIX
- "Could not setup the MRUMTL logger.\n");
+ "Could not setup the MruMtl logger.\n");
}
goto error;
}
@@ -955,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
@@ -1023,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
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|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
@@ -27,8 +27,8 @@
#define MRUMTL_API extern IMPORT_SYM
#endif
-/* Helper macro that asserts if the invocation of the htcp function `Func'
- * returns an error. One should use this macro on htcp function calls for
+/* Helper macro that asserts if the invocation of the mrumtl function `Func'
+ * returns an error. One should use this macro on mrumtl function calls for
* which no explicit error checking is performed */
#ifndef NDEBUG
#define MRUMTL(Func) ASSERT(mrumtl_ ## Func == RES_OK)
@@ -36,15 +36,42 @@
#define MRUMTL(Func) mrumtl_ ## Func
#endif
+/* Forward declaration of external data types */
+struct logger;
+struct mem_allocator;
+
enum mrumtl_brdf_type {
MRUMTL_BRDF_LAMBERTIAN,
MRUMTL_BRDF_SPECULAR,
MRUMTL_BRDF_NONE__
};
-/* Forward declaration of external data types */
-struct logger;
-struct mem_allocator;
+struct mrumtl_create_args {
+ struct logger* logger; /* NULL <=> use default logger */
+ struct mem_allocator* allocator; /* NULL <=> use default allocator */
+ int verbose; /* Verbosity level */
+};
+#define MRUMTL_CREATE_ARGS_DEFAULT__ {NULL, NULL, 0}
+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;
@@ -57,9 +84,7 @@ BEGIN_DECLS
******************************************************************************/
MRUMTL_API res_T
mrumtl_create
- (struct logger* logger, /* NULL <=> use default logger */
- struct mem_allocator* allocator, /* NULL <=> use default allocator */
- const int verbose, /* Verbosity level */
+ (const struct mrumtl_create_args* args,
struct mrumtl** mrumtl);
MRUMTL_API res_T
@@ -81,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-2023 |Méso|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
@@ -0,0 +1,37 @@
+/* Copyright (C) 2020-2023 |Méso|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_C_H
+#define MRUMTL_C_H
+
+#include "mrumtl_brdf.h"
+
+#include <rsys/mem_allocator.h>
+#include <rsys/logger.h>
+#include <rsys/ref_count.h>
+#include <rsys/str.h>
+
+struct mrumtl {
+ struct darray_brdf brdfs;
+ struct str name; /* Name of the loaded material */
+
+ int verbose;
+ struct logger* logger;
+ struct logger logger__;
+ struct mem_allocator* allocator;
+ ref_T ref;
+};
+
+#endif /* MRUMTL_C_H */
diff --git a/src/mrumtl_fetch.c b/src/mrumtl_fetch.c
@@ -0,0 +1,125 @@
+/* Copyright (C) 2020-2023 |Méso|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/mrumtl_log.c b/src/mrumtl_log.c
@@ -0,0 +1,124 @@
+/* Copyright (C) 2020-2023 |Méso|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_c.h"
+#include "mrumtl_log.h"
+
+#include <rsys/cstr.h>
+#include <rsys/logger.h>
+
+#include <stdarg.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE void
+log_msg
+ (const struct mrumtl* mrumtl,
+ const enum log_type stream,
+ const char* msg,
+ va_list vargs)
+{
+ ASSERT(mrumtl && msg);
+ if(mrumtl->verbose) {
+ res_T res; (void)res;
+ res = logger_vprint(mrumtl->logger, stream, msg, vargs);
+ ASSERT(res == RES_OK);
+ }
+}
+
+static void
+print_info(const char* msg, void* ctx)
+{
+ (void)ctx;
+ fprintf(stderr, MSG_INFO_PREFIX"%s", msg);
+}
+
+static void
+print_err(const char* msg, void* ctx)
+{
+ (void)ctx;
+ fprintf(stderr, MSG_ERROR_PREFIX"%s", msg);
+}
+
+static void
+print_warn(const char* msg, void* ctx)
+{
+ (void)ctx;
+ fprintf(stderr, MSG_WARNING_PREFIX"%s", msg);
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+setup_log_default(struct mrumtl* mrumtl)
+{
+ res_T res = RES_OK;
+ ASSERT(mrumtl);
+
+ res = logger_init(mrumtl->allocator, &mrumtl->logger__);
+ if(res != RES_OK) {
+ if(mrumtl->verbose) {
+ fprintf(stderr,
+ MSG_ERROR_PREFIX
+ "Could not setup the default logger -- %s.\n",
+ res_to_cstr(res));
+ }
+ goto error;
+ }
+ logger_set_stream(&mrumtl->logger__, LOG_OUTPUT, print_info, NULL);
+ logger_set_stream(&mrumtl->logger__, LOG_ERROR, print_err, NULL);
+ logger_set_stream(&mrumtl->logger__, LOG_WARNING, print_warn, NULL);
+ mrumtl->logger = &mrumtl->logger__;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+void
+log_info(const struct mrumtl* mrumtl, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(mrumtl && msg);
+
+ va_start(vargs_list, msg);
+ log_msg(mrumtl, LOG_OUTPUT, msg, vargs_list);
+ va_end(vargs_list);
+}
+
+void
+log_err(const struct mrumtl* mrumtl, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(mrumtl && msg);
+
+ va_start(vargs_list, msg);
+ log_msg(mrumtl, LOG_ERROR, msg, vargs_list);
+ va_end(vargs_list);
+}
+
+void
+log_warn(const struct mrumtl* mrumtl, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(mrumtl && msg);
+
+ va_start(vargs_list, msg);
+ log_msg(mrumtl, LOG_WARNING, msg, vargs_list);
+ va_end(vargs_list);
+}
diff --git a/src/mrumtl_log.h b/src/mrumtl_log.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2020-2023 |Méso|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_LOG_H
+#define MRUMTL_LOG_H
+
+#include <rsys/rsys.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: "
+
+struct mrumtl;
+struct logger;
+
+extern LOCAL_SYM res_T
+setup_log_default
+ (struct mrumtl* mrumtl);
+
+/* Conditionally log a message on the LOG_OUTPUT stream of the mrumtl logger,
+ * with respect to its verbose flag */
+extern LOCAL_SYM void
+log_info
+ (const struct mrumtl* mrumtl,
+ const char* msg,
+ ...)
+#ifdef COMPILER_GCC
+ __attribute((format(printf, 2, 3)))
+#endif
+;
+
+/* Conditionally log a message on the LOG_ERROR stream of the mrumtl logger,
+ * with respect to its verbose flag */
+extern LOCAL_SYM void
+log_err
+ (const struct mrumtl* mrumtl,
+ const char* msg,
+ ...)
+#ifdef COMPILER_GCC
+ __attribute((format(printf, 2, 3)))
+#endif
+;
+
+/* Conditionally log a message on the LOG_WARNING stream of the mrumtl logger,
+ * with respect to its verbose flag */
+extern LOCAL_SYM void
+log_warn
+ (const struct mrumtl* mrumtl,
+ const char* msg,
+ ...)
+#ifdef COMPILER_GCC
+ __attribute((format(printf, 2, 3)))
+#endif
+;
+
+#endif /* MRUMTL_LOG_H */
diff --git a/src/test_mrumtl.c b/src/test_mrumtl.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|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
@@ -27,23 +27,15 @@ log_stream(const char* msg, void* ctx)
int
main(int argc, char** argv)
{
+ struct mem_allocator allocator;
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");
-
- CHK(mrumtl_create(NULL, NULL, 0, NULL) == RES_BAD_ARG);
- CHK(mrumtl_create(NULL, NULL, 0, &mrumtl) == RES_OK);
+ CHK(mrumtl_create(NULL, &mrumtl) == RES_BAD_ARG);
+ CHK(mrumtl_create(&args, NULL) == RES_BAD_ARG);
+ CHK(mrumtl_create(&args, &mrumtl) == RES_OK);
CHK(mrumtl_ref_get(NULL) == RES_BAD_ARG);
CHK(mrumtl_ref_get(mrumtl) == RES_OK);
@@ -51,7 +43,10 @@ main(int argc, char** argv)
CHK(mrumtl_ref_put(mrumtl) == RES_OK);
CHK(mrumtl_ref_put(mrumtl) == RES_OK);
- CHK(mrumtl_create(NULL, &mem_default_allocator, 1, &mrumtl) == RES_OK);
+ CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
+ args.allocator = &allocator;
+ args.verbose = 1;
+ CHK(mrumtl_create(&args, &mrumtl) == RES_OK);
CHK(mrumtl_ref_put(mrumtl) == RES_OK);
CHK(logger_init(&mem_default_allocator, &logger) == RES_OK);
@@ -59,22 +54,15 @@ main(int argc, char** argv)
logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
- CHK(mrumtl_create(&logger, &mem_default_allocator, 0, &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);
+ args.logger = &logger;
+ args.verbose = 0;
+ CHK(mrumtl_create(&args, &mrumtl) == RES_OK);
CHK(mrumtl_ref_put(mrumtl) == RES_OK);
-
- rewind(fp);
- CHK(mrumtl_create(NULL, &mem_default_allocator, 1, &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);
-
+ args.allocator = NULL;
+ CHK(mrumtl_create(&args, &mrumtl) == RES_OK);
CHK(mrumtl_ref_put(mrumtl) == RES_OK);
- fclose(fp);
+ mem_shutdown_proxy_allocator(&allocator);
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,334 +0,0 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#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* mrumtl = NULL;
- (void)argc, (void)argv;
-
- CHK(mrumtl_create(NULL, NULL, 1, &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-2023 |Méso|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_load.c b/src/test_mrumtl_load.c
@@ -0,0 +1,88 @@
+/* Copyright (C) 2020-2023 |Méso|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>
+
+static void
+check_brdf_lambertian(const struct mrumtl_brdf* brdf)
+{
+ struct mrumtl_brdf_lambertian lambertian = MRUMTL_BRDF_LAMBERTIAN_NULL;
+
+ CHK(mrumtl_brdf_get_lambertian(brdf, &lambertian) == RES_OK);
+
+ /* !NaN */
+ CHK(lambertian.wavelengths[0] == lambertian.wavelengths[0]);
+ CHK(lambertian.wavelengths[1] == lambertian.wavelengths[1]);
+ CHK(lambertian.reflectivity == lambertian.reflectivity);
+
+ CHK(lambertian.wavelengths[0] <= lambertian.wavelengths[1]);
+ CHK(0 <= lambertian.reflectivity && lambertian.reflectivity <= 1);
+}
+
+
+static void
+check_brdf_specular(const struct mrumtl_brdf* brdf)
+{
+ struct mrumtl_brdf_specular specular = MRUMTL_BRDF_SPECULAR_NULL;
+
+ CHK(mrumtl_brdf_get_specular(brdf, &specular) == RES_OK);
+
+ /* !NaN */
+ CHK(specular.wavelengths[0] == specular.wavelengths[0]);
+ CHK(specular.wavelengths[1] == specular.wavelengths[1]);
+ CHK(specular.reflectivity == specular.reflectivity);
+
+ CHK(specular.wavelengths[0] <= specular.wavelengths[1]);
+ CHK(0 <= specular.reflectivity && specular.reflectivity <= 1);
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mrumtl_create_args args = MRUMTL_CREATE_ARGS_DEFAULT;
+ struct mrumtl* mrumtl = NULL;
+ int i;
+ (void)argc, (void)argv;
+
+ args.verbose = 1;
+ CHK(mrumtl_create(&args, &mrumtl) == RES_OK);
+
+ FOR_EACH(i, 1, argc) {
+ size_t ibrdf;
+ size_t nbrdfs;
+
+ printf("Load %s\n", argv[i]);
+ CHK(mrumtl_load(mrumtl, argv[i]) == RES_OK);
+
+ nbrdfs = mrumtl_get_brdfs_count(mrumtl);
+ FOR_EACH(ibrdf, 0, nbrdfs) {
+ const struct mrumtl_brdf* brdf = mrumtl_get_brdf(mrumtl, ibrdf);
+
+ switch(mrumtl_brdf_get_type(brdf)) {
+ case MRUMTL_BRDF_LAMBERTIAN:
+ check_brdf_lambertian(brdf);
+ break;
+ case MRUMTL_BRDF_SPECULAR:
+ check_brdf_specular(brdf);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ }
+ }
+ 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,263 +0,0 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#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* mrumtl = NULL;
- (void)argc, (void)argv;
-
- CHK(mrumtl_create(NULL, NULL, 1, &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-2023 |Méso|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;
+}