commit bc27763de2137ee5ad2e83e8affe98a66ca10f5d
parent 3519ceab269d0cb68477b7cbda120100faf1394d
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 18 Apr 2017 14:21:13 +0200
Merge branch 'feature_normal_map' into develop
Diffstat:
16 files changed, 1041 insertions(+), 103 deletions(-)
diff --git a/cmake/parser/CMakeLists.txt b/cmake/parser/CMakeLists.txt
@@ -32,6 +32,7 @@ include_directories(
set(SOLPARSER_FILES_SRC
solparser.c
solparser_entity.c
+ solparser_image.c
solparser_geometry.c
solparser_material.c
solparser_pivot.c
@@ -42,6 +43,7 @@ set(SOLPARSER_FILES_INC
solparser_c.h
solparser_entity.h
solparser_geometry.h
+ solparser_image.h
solparser_material.h
solparser_pivot.h
solparser_shape.h
@@ -103,6 +105,7 @@ if(NOT NO_TEST)
new_test(test_solparser6)
new_test(test_solparser7)
new_test(test_solparser8)
+ new_test(test_solparser_normal_map)
rcmake_copy_runtime_libraries(test_solparser)
endif()
diff --git a/doc/input b/doc/input
@@ -225,15 +225,18 @@
dielectric:
medium_i: <dielectric-medium>
medium_t: <dielectric-medium>
+[ <normal-map> ]
<matte> ::=
matte:
reflectivity: REAL # in [0, 1]
+[ <normal-map> ]
<mirror> ::=
mirror:
reflectivity: REAL # in [0, 1]
roughness: REAL # in [0, 1]
+[ <normal-map> ]
<virtual> ::=
virtual: EMPTY-STRING
@@ -243,10 +246,14 @@
thickness: REAL # in [0, INF)
medium_i: <dielectric-medium>
medium_t: <dielectric-medium>
+[ <normal-map> ]
<dielectric-medium> ::=
- refractive_index: REAL # in ]0, INF)
- absorptivity: REAL # in [0, INF)
+ refractive_index: REAL # in ]0, INF)
+ absorptivity: REAL # in [0, INF)
+
+<normal-map> ::=
+ normal_map: { path: PATH }
#----------------------------------------
<entity> ::=
diff --git a/src/parser/solparser.c b/src/parser/solparser.c
@@ -186,6 +186,7 @@ parser_clear(struct solparser* parser)
/* Materials */
htable_yaml2sols_clear(&parser->yaml2mtls);
+ darray_image_clear(&parser->images);
darray_material_clear(&parser->mtls);
darray_material2_clear(&parser->mtls2);
darray_medium_clear(&parser->mediums);
@@ -240,6 +241,7 @@ parser_release(ref_T* ref)
/* Materials */
htable_yaml2sols_release(&parser->yaml2mtls);
+ darray_image_release(&parser->images);
darray_material_release(&parser->mtls);
darray_material2_release(&parser->mtls2);
darray_medium_release(&parser->mediums);
@@ -568,6 +570,7 @@ solparser_create
/* Materials */
htable_yaml2sols_init(mem_allocator, &parser->yaml2mtls);
+ darray_image_init(mem_allocator, &parser->images);
darray_material_init(mem_allocator, &parser->mtls);
darray_material2_init(mem_allocator, &parser->mtls2);
darray_medium_init(mem_allocator, &parser->mediums);
@@ -882,6 +885,15 @@ solparser_get_entity
return darray_entity_cdata_get(&parser->entities) + entity.i;
}
+const struct solparser_image*
+solparser_get_image
+ (const struct solparser* parser,
+ const struct solparser_image_id image)
+{
+ ASSERT(parser && image.i < darray_image_size_get(&parser->images));
+ return darray_image_cdata_get(&parser->images) + image.i;
+}
+
const struct solparser_geometry*
solparser_get_geometry
(const struct solparser* parser,
diff --git a/src/parser/solparser.h b/src/parser/solparser.h
@@ -18,10 +18,13 @@
#include "solparser_entity.h"
#include <rsys/rsys.h>
+#include <stddef.h>
struct mem_allocator;
struct solparser;
+#define SOLPARSER_ID_IS_VALID(Id) ((Id).i != SIZE_MAX)
+
struct solparser_entity_iterator {
struct htable_str2sols_iterator it__; /* Internal data */
};
@@ -87,16 +90,16 @@ solparser_get_entity
(const struct solparser* parser,
const struct solparser_entity_id entity);
+extern LOCAL_SYM const struct solparser_image*
+solparser_get_image
+ (const struct solparser* parser,
+ const struct solparser_image_id image);
+
extern LOCAL_SYM const struct solparser_geometry*
solparser_get_geometry
(const struct solparser* parser,
const struct solparser_geometry_id geom);
-extern LOCAL_SYM const struct solparser_medium*
-solparser_get_medium
- (const struct solparser* parser,
- const struct solparser_medium_id medium);
-
extern LOCAL_SYM const struct solparser_material*
solparser_get_material
(const struct solparser* parser,
@@ -127,21 +130,16 @@ solparser_get_material_thin_dielectric
(const struct solparser* parser,
const struct solparser_material_thin_dielectric_id thin_dielectric);
+extern LOCAL_SYM const struct solparser_medium*
+solparser_get_medium
+ (const struct solparser* parser,
+ const struct solparser_medium_id medium);
+
extern LOCAL_SYM const struct solparser_object*
solparser_get_object
(const struct solparser* parser,
const struct solparser_object_id obj);
-extern LOCAL_SYM const struct solparser_x_pivot*
-solparser_get_x_pivot
- (const struct solparser* parser,
- const struct solparser_pivot_id x_pivot);
-
-extern LOCAL_SYM const struct solparser_zx_pivot*
-solparser_get_zx_pivot
- (const struct solparser* parser,
- const struct solparser_pivot_id zx_pivot);
-
extern LOCAL_SYM const struct solparser_shape*
solparser_get_shape
(const struct solparser* parser,
@@ -196,6 +194,16 @@ extern LOCAL_SYM const struct solparser_sun*
solparser_get_sun
(const struct solparser* parser);
+extern LOCAL_SYM const struct solparser_x_pivot*
+solparser_get_x_pivot
+ (const struct solparser* parser,
+ const struct solparser_pivot_id x_pivot);
+
+extern LOCAL_SYM const struct solparser_zx_pivot*
+solparser_get_zx_pivot
+ (const struct solparser* parser,
+ const struct solparser_pivot_id zx_pivot);
+
/*******************************************************************************
* Entity interator
******************************************************************************/
diff --git a/src/parser/solparser_c.h b/src/parser/solparser_c.h
@@ -18,6 +18,7 @@
#include "solparser.h"
#include "solparser_entity.h"
+#include "solparser_image.h"
#include "solparser_material.h"
#include "solparser_pivot.h"
#include "solparser_shape.h"
@@ -48,21 +49,25 @@ struct target_alias {
/* Declare the array of dielectric materials */
#define DARRAY_NAME dielectric
#define DARRAY_DATA struct solparser_material_dielectric
+#define DARRAY_FUNCTOR_INIT solparser_material_dielectric_init
#include <rsys/dynamic_array.h>
/* Declare the array of matte materials */
#define DARRAY_NAME matte
#define DARRAY_DATA struct solparser_material_matte
+#define DARRAY_FUNCTOR_INIT solparser_material_matte_init
#include <rsys/dynamic_array.h>
/* Declare the array of mirror materials */
#define DARRAY_NAME mirror
#define DARRAY_DATA struct solparser_material_mirror
+#define DARRAY_FUNCTOR_INIT solparser_material_mirror_init
#include <rsys/dynamic_array.h>
/* Declare the array of thin_dielectric materials */
#define DARRAY_NAME thin_dielectric
#define DARRAY_DATA struct solparser_material_thin_dielectric
+#define DARRAY_FUNCTOR_INIT solparser_material_thin_dielectric_init
#include <rsys/dynamic_array.h>
/* Declare the array of materials */
@@ -90,6 +95,15 @@ struct target_alias {
#define DARRAY_DATA struct solparser_shape_cylinder
#include <rsys/dynamic_array.h>
+/* Declare the array of images */
+#define DARRAY_NAME image
+#define DARRAY_DATA struct solparser_image
+#define DARRAY_FUNCTOR_INIT solparser_image_init
+#define DARRAY_FUNCTOR_RELEASE solparser_image_release
+#define DARRAY_FUNCTOR_COPY solparser_image_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_image_copy_and_release
+#include <rsys/dynamic_array.h>
+
/* Declare the array of imported geometries */
#define DARRAY_NAME impgeom
#define DARRAY_DATA struct solparser_shape_imported_geometry
@@ -192,6 +206,7 @@ struct solparser {
/* Materia data */
struct htable_yaml2sols yaml2mtls; /* Cache of materials */
+ struct darray_image images;
struct darray_material mtls;
struct darray_material2 mtls2; /* Double sided materials */
struct darray_medium mediums;
@@ -328,13 +343,6 @@ parse_transform
* Main parsing functions
******************************************************************************/
extern LOCAL_SYM res_T
-parse_material
- (struct solparser* parser,
- yaml_document_t* doc,
- yaml_node_t* mtl,
- struct solparser_material_double_sided_id* out_imtl2);
-
-extern LOCAL_SYM res_T
parse_entity
(struct solparser* parser,
yaml_document_t* doc,
@@ -343,6 +351,13 @@ parse_entity
struct solparser_entity_id* out_isolent);
extern LOCAL_SYM res_T
+parse_image
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* image,
+ struct solparser_image_id* out_img);
+
+extern LOCAL_SYM res_T
parse_focals_description
(struct solparser* parser,
yaml_document_t* doc,
@@ -357,18 +372,18 @@ parse_geometry
struct solparser_geometry_id* out_isolgeom);
extern LOCAL_SYM res_T
-parse_x_pivot
+parse_material
(struct solparser* parser,
yaml_document_t* doc,
- const yaml_node_t* x_pivot,
- struct solparser_pivot_id* out_isolpivot);
+ yaml_node_t* mtl,
+ struct solparser_material_double_sided_id* out_imtl2);
extern LOCAL_SYM res_T
-parse_zx_pivot
+parse_spectrum
(struct solparser* parser,
yaml_document_t* doc,
- const yaml_node_t* zx_pivot,
- struct solparser_pivot_id* out_isolpivot);
+ const yaml_node_t* spectrum,
+ struct darray_spectrum_data* data);
extern LOCAL_SYM res_T
parse_sun
@@ -378,10 +393,17 @@ parse_sun
struct solparser_sun** out_solsun);
extern LOCAL_SYM res_T
-parse_spectrum
+parse_x_pivot
(struct solparser* parser,
yaml_document_t* doc,
- const yaml_node_t* spectrum,
- struct darray_spectrum_data* data);
+ const yaml_node_t* x_pivot,
+ struct solparser_pivot_id* out_isolpivot);
+
+extern LOCAL_SYM res_T
+parse_zx_pivot
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* zx_pivot,
+ struct solparser_pivot_id* out_isolpivot);
#endif /* SOLPARSER_C_H */
diff --git a/src/parser/solparser_image.c b/src/parser/solparser_image.c
@@ -0,0 +1,107 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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 "solparser_c.h"
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+parse_image
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* img,
+ struct solparser_image_id* out_iimg)
+{
+ enum { PATH };
+ struct solparser_image* solimg = NULL;
+ size_t isolimg = SIZE_MAX;
+ intptr_t i, n;
+ int mask = 0; /* Register the parsed attributes */
+ res_T res = RES_OK;
+ ASSERT(parser && doc && img &&out_iimg);
+
+ if(img->type != YAML_MAPPING_NODE) {
+ log_err(parser, img, "expect a mapping of image parameters.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Allocate an image */
+ isolimg = darray_image_size_get(&parser->images);
+ res = darray_image_resize(&parser->images, isolimg + 1);
+ if(res != RES_OK) {
+ log_err(parser, img, "could not allocate the image.\n");
+ goto error;
+ }
+ solimg = darray_image_data_get(&parser->images) + isolimg;
+
+ n = img->data.mapping.pairs.top - img->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, img->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(doc, img->data.mapping.pairs.start[i].value);
+ if(key->type != YAML_SCALAR_NODE) {
+ log_err(parser, key, "expect image parameters.\n");
+ goto error;
+ }
+ #define SETUP_MASK(Flag, Name) { \
+ if(mask & BIT(Flag)) { \
+ log_err(parser, key, \
+ "the image parameter `"Name"' is already defined.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ mask |= BIT(Flag); \
+ } (void)0
+ if(!strcmp((char*)key->data.scalar.value, "path")) {
+ SETUP_MASK(PATH, "path");
+ res = parse_string(parser, val, &solimg->filename);
+ } else {
+ log_err(parser, key, "unknown image parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, img, \
+ "the image parameter `"Name"' is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(PATH, "path");
+ #undef CHECK_PARAM
+
+exit:
+ out_iimg->i = isolimg;
+ return res;
+error:
+ if(solimg) {
+ darray_image_pop_back(&parser->images);
+ isolimg = SIZE_MAX;
+ }
+ goto exit;
+}
+
diff --git a/src/parser/solparser_image.h b/src/parser/solparser_image.h
@@ -0,0 +1,62 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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 SOLPARSER_IMAGE_H
+#define SOLPARSER_IMAGE_H
+
+#include <rsys/str.h>
+
+struct solparser_image {
+ struct str filename;
+};
+
+struct solparser_image_id { size_t i; };
+
+static INLINE void
+solparser_image_init
+ (struct mem_allocator* allocator,
+ struct solparser_image* img)
+{
+ ASSERT(img);
+ str_init(allocator, &img->filename);
+}
+
+static INLINE void
+solparser_image_release(struct solparser_image* img)
+{
+ ASSERT(img);
+ str_release(&img->filename);
+}
+
+static INLINE res_T
+solparser_image_copy
+ (struct solparser_image* dst,
+ const struct solparser_image* src)
+{
+ ASSERT(dst && src);
+ return str_copy(&dst->filename, &src->filename);
+}
+
+static INLINE res_T
+solparser_image_copy_and_release
+ (struct solparser_image* dst,
+ struct solparser_image* src)
+{
+ ASSERT(dst && src);
+ return str_copy_and_release(&dst->filename, &src->filename);
+}
+
+#endif /* SOLPARSER_IMAGE_H */
+
diff --git a/src/parser/solparser_material.c b/src/parser/solparser_material.c
@@ -120,7 +120,7 @@ parse_material_dielectric
const yaml_node_t* dielec,
struct solparser_material_dielectric_id* out_imtl)
{
- enum { MEDIUM_I, MEDIUM_T };
+ enum { MEDIUM_I, MEDIUM_T, NORMAL_MAP };
struct solparser_material_dielectric* mtl = NULL;
size_t imtl = SIZE_MAX;
int mask = 0; /* Register the parsed attributes */
@@ -166,7 +166,10 @@ parse_material_dielectric
} \
mask |= BIT(Flag); \
} (void)0
- if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
+ if(!strcmp((char*)key->data.scalar.value, "normal_map")) {
+ SETUP_MASK(NORMAL_MAP, "normal_map");
+ res = parse_image(parser, doc, val, &mtl->normal_map);
+ } else if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
SETUP_MASK(MEDIUM_I, "medium_i");
res = parse_medium(parser, doc, val, &mtl->medium_i);
} else if(!strcmp((char*)key->data.scalar.value, "medium_t")) {
@@ -214,7 +217,7 @@ parse_material_matte
const yaml_node_t* matte,
struct solparser_material_matte_id* out_imtl)
{
- enum { REFLECTIVITY };
+ enum { NORMAL_MAP, REFLECTIVITY };
struct solparser_material_matte* mtl = NULL;
size_t imtl = SIZE_MAX;
intptr_t i, n;
@@ -250,13 +253,20 @@ parse_material_matte
goto error;
}
- if(!strcmp((char*)key->data.scalar.value, "reflectivity")) {
- if(mask & BIT(REFLECTIVITY)) {
- log_err(parser, key, "the matte reflectivity is already defined.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- mask |= BIT(REFLECTIVITY);
+ #define SETUP_MASK(Flag, Name) { \
+ if(mask & BIT(Flag)) { \
+ log_err(parser, key, \
+ "the "Name" of the matte material is already defined.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ mask |= BIT(Flag); \
+ } (void)0
+ if(!strcmp((char*)key->data.scalar.value, "normal_map")) {
+ SETUP_MASK(NORMAL_MAP, "normal_map");
+ res = parse_image(parser, doc, val, &mtl->normal_map);
+ } else if(!strcmp((char*)key->data.scalar.value, "reflectivity")) {
+ SETUP_MASK(REFLECTIVITY, "reflectivity");
res = parse_real(parser, val, 0, 1, &mtl->reflectivity);
} else {
log_err(parser, key, "unknown matte parameter `%s'.\n",
@@ -268,6 +278,7 @@ parse_material_matte
log_node(parser, key);
goto error;
}
+ #undef SETUP_MASK
}
if(!(mask & BIT(REFLECTIVITY))) {
@@ -294,7 +305,7 @@ parse_material_mirror
const yaml_node_t* mirror,
struct solparser_material_mirror_id* out_imtl)
{
- enum { REFLECTIVITY, ROUGHNESS };
+ enum { NORMAL_MAP, REFLECTIVITY, ROUGHNESS };
struct solparser_material_mirror* mtl = NULL;
size_t imtl = SIZE_MAX;
int mask = 0; /* Register the parsed attributes */
@@ -340,7 +351,10 @@ parse_material_mirror
} \
mask |= BIT(Flag); \
} (void)0
- if(!strcmp((char*)key->data.scalar.value, "reflectivity")) {
+ if(!strcmp((char*)key->data.scalar.value, "normal_map")) {
+ SETUP_MASK(NORMAL_MAP, "normal_map");
+ res = parse_image(parser, doc, val, &mtl->normal_map);
+ } else if(!strcmp((char*)key->data.scalar.value, "reflectivity")) {
SETUP_MASK(REFLECTIVITY, "reflectivity");
res = parse_real(parser, val, 0, 1, &mtl->reflectivity);
} else if(!strcmp((char*)key->data.scalar.value, "roughness")) {
@@ -387,7 +401,7 @@ parse_material_thin_dielectric
yaml_node_t* thin,
struct solparser_material_thin_dielectric_id* out_imtl)
{
- enum { MEDIUM_I, MEDIUM_T, THICKNESS };
+ enum { MEDIUM_I, MEDIUM_T, NORMAL_MAP, THICKNESS };
struct solparser_material_thin_dielectric* mtl = NULL;
size_t imtl = SIZE_MAX;
int mask = 0; /* Register the parsed attributes */
@@ -434,7 +448,10 @@ parse_material_thin_dielectric
} \
mask |= BIT(Flag); \
} (void)0
- if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
+ if(!strcmp((char*)key->data.scalar.value, "normal_map")) {
+ SETUP_MASK(NORMAL_MAP, "normal_map");
+ res = parse_image(parser, doc, val, &mtl->normal_map);
+ } else if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
SETUP_MASK(MEDIUM_I, "medium_i");
res = parse_medium(parser, doc, val, &mtl->medium_i);
} else if(!strcmp((char*)key->data.scalar.value, "medium_t")) {
diff --git a/src/parser/solparser_material.h b/src/parser/solparser_material.h
@@ -16,6 +16,7 @@
#ifndef SOLPARSER_MATERIAL_H
#define SOLPARSER_MATERIAL_H
+#include "solparser_image.h"
#include <stddef.h>
enum solparser_material_type {
@@ -36,31 +37,75 @@ struct solparser_medium_id { size_t i; };
struct solparser_material_dielectric {
struct solparser_medium_id medium_i; /* Medium the material "looks at" */
struct solparser_medium_id medium_t; /* Opposite medium */
+ struct solparser_image_id normal_map;
};
struct solparser_material_dielectric_id { size_t i; };
+static INLINE void
+solparser_material_dielectric_init
+ (struct mem_allocator* allocator,
+ struct solparser_material_dielectric* dielectric)
+{
+ ASSERT(dielectric);
+ (void)allocator;
+ dielectric->normal_map.i = SIZE_MAX;
+}
+
struct solparser_material_matte {
double reflectivity; /* In [0, 1] */
+ struct solparser_image_id normal_map;
};
struct solparser_material_matte_id { size_t i; };
+static INLINE void
+solparser_material_matte_init
+ (struct mem_allocator* allocator,
+ struct solparser_material_matte* matte)
+{
+ ASSERT(matte);
+ (void)allocator;
+ matte->normal_map.i = SIZE_MAX;
+}
+
struct solparser_material_mirror {
double roughness; /* In [0, 1] */
double reflectivity; /* In [0, 1] */
+ struct solparser_image_id normal_map;
};
struct solparser_material_mirror_id { size_t i; };
+static INLINE void
+solparser_material_mirror_init
+ (struct mem_allocator* allocator,
+ struct solparser_material_mirror* mirror)
+{
+ ASSERT(mirror);
+ (void)allocator;
+ mirror->normal_map.i = SIZE_MAX;
+}
+
struct solparser_material_thin_dielectric {
struct solparser_medium_id medium_i; /* Outside medium */
struct solparser_medium_id medium_t; /* Medium of the slab */
+ struct solparser_image_id normal_map;
double thickness;
};
struct solparser_material_thin_dielectric_id { size_t i; };
+static INLINE void
+solparser_material_thin_dielectric_init
+ (struct mem_allocator* allocator,
+ struct solparser_material_thin_dielectric* thin)
+{
+ ASSERT(thin);
+ (void)allocator;
+ thin->normal_map.i = SIZE_MAX;
+}
+
struct solparser_material {
enum solparser_material_type type;
union {
diff --git a/src/parser/test_solparser8.c b/src/parser/test_solparser8.c
@@ -37,7 +37,7 @@ main(int argc, char** argv)
(void)argc, (void)argv;
CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK);
- solparser_create(&allocator, &parser);
+ CHECK(solparser_create(&allocator, &parser), RES_OK);
stream = tmpfile();
NCHECK(stream, NULL);
diff --git a/src/parser/test_solparser_normal_map.c b/src/parser/test_solparser_normal_map.c
@@ -0,0 +1,335 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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 "solparser.h"
+#include "test_solstice_utils.h"
+
+static void
+test_dielectric(struct solparser* parser)
+{
+ struct solparser_entity_iterator it, end;
+ struct solparser_entity_id entity_id;
+ struct solparser_object_id obj_id;
+ const struct solparser_entity* entity;
+ const struct solparser_image* img;
+ const struct solparser_geometry* geom;
+ const struct solparser_material_double_sided* mtl2;
+ const struct solparser_material* mtl;
+ const struct solparser_material_dielectric* dielectric;
+ const struct solparser_object* obj;
+ const struct solparser_shape* shape;
+ FILE* stream;
+
+ stream = tmpfile();
+ NCHECK(stream, NULL);
+
+ fprintf(stream, "- sun: {dni: 1, spectrum: [{wavelength: 1, data: 1} ]}\n");
+ fprintf(stream, "\n");
+ fprintf(stream, "- material: &glass\n");
+ fprintf(stream, " front:\n");
+ fprintf(stream, " dielectric:\n");
+ fprintf(stream, " medium_i: &out {refractive_index: 1, absorptivity: 0}\n");
+ fprintf(stream, " medium_t: &in {refractive_index: 1.5, absorptivity: 20}\n");
+ fprintf(stream, " normal_map: {path: my_normal_map}\n");
+ fprintf(stream, " back: {dielectric: {medium_i: *in, medium_t: *out}}\n");
+ fprintf(stream, "\n");
+ fprintf(stream, "- entity:\n");
+ fprintf(stream, " name: foo\n");
+ fprintf(stream, " primary: 1\n");
+ fprintf(stream, " geometry:\n");
+ fprintf(stream, " - cylinder: { radius: 2, height: 2 }\n");
+ fprintf(stream, " material: *glass\n");
+ rewind(stream);
+
+ CHECK(solparser_setup(parser, NULL, stream), RES_OK);
+ CHECK(solparser_load(parser), RES_OK);
+
+ solparser_entity_iterator_begin(parser, &it);
+ solparser_entity_iterator_end(parser, &end);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 0);
+
+ entity_id = solparser_entity_iterator_get(&it);
+ entity = solparser_get_entity(parser, entity_id);
+
+ CHECK(strcmp("foo", str_cget(&entity->name)), 0);
+ CHECK(solparser_entity_get_children_count(entity), 0);
+ CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY);
+ CHECK(entity->primary, 1);
+ geom = solparser_get_geometry(parser, entity->data.geometry);
+ CHECK(solparser_geometry_get_objects_count(geom), 1);
+ obj_id = solparser_geometry_get_object(geom, 0);
+ obj = solparser_get_object(parser, obj_id);
+ shape = solparser_get_shape(parser, obj->shape);
+ CHECK(shape->type, SOLPARSER_SHAPE_CYLINDER);
+ mtl2 = solparser_get_material_double_sided(parser, obj->mtl2);
+ NCHECK(mtl2->front.i, mtl2->back.i);
+
+ mtl = solparser_get_material(parser, mtl2->front);
+ CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC);
+ dielectric = solparser_get_material_dielectric(parser, mtl->data.dielectric);
+ CHECK(SOLPARSER_ID_IS_VALID(dielectric->normal_map), 1);
+ img = solparser_get_image(parser, dielectric->normal_map);
+ CHECK(strcmp(str_cget(&img->filename), "my_normal_map"), 0);
+
+ mtl = solparser_get_material(parser, mtl2->back);
+ CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC);
+ dielectric = solparser_get_material_dielectric(parser, mtl->data.dielectric);
+ CHECK(SOLPARSER_ID_IS_VALID(dielectric->normal_map), 0);
+
+ solparser_entity_iterator_next(&it);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 1);
+
+ CHECK(solparser_load(parser), RES_BAD_OP);
+ fclose(stream);
+}
+
+static void
+test_matte(struct solparser* parser)
+{
+ struct solparser_entity_iterator it, end;
+ struct solparser_entity_id entity_id;
+ struct solparser_object_id obj_id;
+ const struct solparser_entity* entity;
+ const struct solparser_image* img;
+ const struct solparser_geometry* geom;
+ const struct solparser_material_double_sided* mtl2;
+ const struct solparser_material* mtl;
+ const struct solparser_material_matte* matte;
+ const struct solparser_object* obj;
+ const struct solparser_shape* shape;
+ FILE* stream;
+
+ stream = tmpfile();
+ NCHECK(stream, NULL);
+
+ fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1} ] }\n");
+ fprintf(stream, "- entity:\n");
+ fprintf(stream, " name: test\n");
+ fprintf(stream, " primary: 0\n");
+ fprintf(stream, " geometry:\n");
+ fprintf(stream, " - sphere: { radius: 1 }\n");
+ fprintf(stream, " material:\n");
+ fprintf(stream, " matte:\n");
+ fprintf(stream, " reflectivity: 0.123\n");
+ fprintf(stream, " normal_map: { path: \"path to normal map\" }\n");
+ rewind(stream);
+
+ CHECK(solparser_setup(parser, NULL, stream), RES_OK);
+ CHECK(solparser_load(parser), RES_OK);
+
+ solparser_entity_iterator_begin(parser, &it);
+ solparser_entity_iterator_end(parser, &end);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 0);
+
+ entity_id = solparser_entity_iterator_get(&it);
+ entity = solparser_get_entity(parser, entity_id);
+
+ CHECK(strcmp("test", str_cget(&entity->name)), 0);
+ CHECK(solparser_entity_get_children_count(entity), 0);
+ CHECK(entity->primary, 0);
+ CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY);
+ geom = solparser_get_geometry(parser, entity->data.geometry);
+ CHECK(solparser_geometry_get_objects_count(geom), 1);
+ obj_id = solparser_geometry_get_object(geom, 0);
+ obj = solparser_get_object(parser, obj_id);
+ shape = solparser_get_shape(parser, obj->shape);
+ CHECK(shape->type, SOLPARSER_SHAPE_SPHERE);
+ mtl2 = solparser_get_material_double_sided(parser, obj->mtl2);
+ CHECK(mtl2->front.i, mtl2->back.i);
+
+ mtl = solparser_get_material(parser, mtl2->front);
+ CHECK(mtl->type, SOLPARSER_MATERIAL_MATTE);
+ matte = solparser_get_material_matte(parser, mtl->data.matte);
+ CHECK(matte->reflectivity, 0.123);
+ CHECK(SOLPARSER_ID_IS_VALID(matte->normal_map), 1);
+ img = solparser_get_image(parser, matte->normal_map);
+ CHECK(strcmp(str_cget(&img->filename), "path to normal map"), 0);
+
+ solparser_entity_iterator_next(&it);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 1);
+
+ CHECK(solparser_load(parser), RES_BAD_OP);
+ fclose(stream);
+}
+
+static void
+test_mirror(struct solparser* parser)
+{
+ struct solparser_entity_iterator it, end;
+ struct solparser_entity_id entity_id;
+ struct solparser_object_id obj_id;
+ const struct solparser_entity* entity;
+ const struct solparser_image* img;
+ const struct solparser_geometry* geom;
+ const struct solparser_material_double_sided* mtl2;
+ const struct solparser_material* mtl;
+ const struct solparser_material_mirror* mirror;
+ const struct solparser_object* obj;
+ const struct solparser_shape* shape;
+ FILE* stream;
+
+ stream = tmpfile();
+ NCHECK(stream, NULL);
+
+ fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1} ] }\n");
+ fprintf(stream, "- entity: \n");
+ fprintf(stream, " name: my entity\n");
+ fprintf(stream, " primary: 0\n");
+ fprintf(stream, " geometry: \n");
+ fprintf(stream, " - cuboid: { size: [1, 1, 1] }\n");
+ fprintf(stream, " material: \n");
+ fprintf(stream, " mirror:\n");
+ fprintf(stream, " reflectivity: 1\n");
+ fprintf(stream, " roughness: 0.1\n");
+ fprintf(stream, " normal_map: { path: Normal map } \n");
+ rewind(stream);
+
+ CHECK(solparser_setup(parser, NULL, stream), RES_OK);
+ CHECK(solparser_load(parser), RES_OK);
+
+ solparser_entity_iterator_begin(parser, &it);
+ solparser_entity_iterator_end(parser, &end);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 0);
+
+ entity_id = solparser_entity_iterator_get(&it);
+ entity = solparser_get_entity(parser, entity_id);
+
+ CHECK(strcmp("my entity", str_cget(&entity->name)), 0);
+ CHECK(solparser_entity_get_children_count(entity), 0);
+ CHECK(entity->primary, 0);
+ CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY);
+ geom = solparser_get_geometry(parser, entity->data.geometry);
+ CHECK(solparser_geometry_get_objects_count(geom), 1);
+ obj_id = solparser_geometry_get_object(geom, 0);
+ obj = solparser_get_object(parser, obj_id);
+ shape = solparser_get_shape(parser, obj->shape);
+ CHECK(shape->type, SOLPARSER_SHAPE_CUBOID);
+ mtl2 = solparser_get_material_double_sided(parser, obj->mtl2);
+ CHECK(mtl2->front.i, mtl2->back.i);
+
+ mtl = solparser_get_material(parser, mtl2->front);
+ CHECK(mtl->type, SOLPARSER_MATERIAL_MIRROR);
+ mirror = solparser_get_material_mirror(parser, mtl->data.mirror);
+ CHECK(mirror->reflectivity, 1);
+ CHECK(mirror->roughness, 0.1);
+ CHECK(SOLPARSER_ID_IS_VALID(mirror->normal_map), 1);
+ img = solparser_get_image(parser, mirror->normal_map);
+ CHECK(strcmp(str_cget(&img->filename), "Normal map"), 0);
+
+ solparser_entity_iterator_next(&it);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 1);
+
+ CHECK(solparser_load(parser), RES_BAD_OP);
+ fclose(stream);
+}
+
+static void
+test_thin_dielectric(struct solparser* parser)
+{
+ struct solparser_entity_iterator it, end;
+ struct solparser_entity_id entity_id;
+ struct solparser_object_id obj_id;
+ const struct solparser_entity* entity;
+ const struct solparser_image* img;
+ const struct solparser_geometry* geom;
+ const struct solparser_material_double_sided* mtl2;
+ const struct solparser_material* mtl;
+ const struct solparser_material_thin_dielectric* thin;
+ const struct solparser_object* obj;
+ const struct solparser_shape* shape;
+ FILE* stream;
+
+ stream = tmpfile();
+ NCHECK(stream, NULL);
+ fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1} ] }\n");
+ fprintf(stream, "- entity:\n");
+ fprintf(stream, " name: test\n");
+ fprintf(stream, " primary: 0\n");
+ fprintf(stream, " geometry:\n");
+ fprintf(stream, " - sphere: { radius: 1 }\n");
+ fprintf(stream, " material:\n");
+ fprintf(stream, " thin_dielectric:\n");
+ fprintf(stream, " thickness: 0.1\n");
+ fprintf(stream, " medium_i:\n");
+ fprintf(stream, " refractive_index: 1\n");
+ fprintf(stream, " absorptivity: 0\n");
+ fprintf(stream, " medium_t:\n");
+ fprintf(stream, " refractive_index: 1.5\n");
+ fprintf(stream, " absorptivity: 20\n");
+ fprintf(stream, " normal_map: { path: Bump }\n");
+ rewind(stream);
+
+ CHECK(solparser_setup(parser, NULL, stream), RES_OK);
+ CHECK(solparser_load(parser), RES_OK);
+
+ solparser_entity_iterator_begin(parser, &it);
+ solparser_entity_iterator_end(parser, &end);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 0);
+
+ entity_id = solparser_entity_iterator_get(&it);
+ entity = solparser_get_entity(parser, entity_id);
+
+ CHECK(strcmp("test", str_cget(&entity->name)), 0);
+ CHECK(solparser_entity_get_children_count(entity), 0);
+ CHECK(entity->primary, 0);
+ CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY);
+ geom = solparser_get_geometry(parser, entity->data.geometry);
+ CHECK(solparser_geometry_get_objects_count(geom), 1);
+ obj_id = solparser_geometry_get_object(geom, 0);
+ obj = solparser_get_object(parser, obj_id);
+ shape = solparser_get_shape(parser, obj->shape);
+ CHECK(shape->type, SOLPARSER_SHAPE_SPHERE);
+ mtl2 = solparser_get_material_double_sided(parser, obj->mtl2);
+ CHECK(mtl2->front.i, mtl2->back.i);
+
+ mtl = solparser_get_material(parser, mtl2->front);
+ CHECK(mtl->type, SOLPARSER_MATERIAL_THIN_DIELECTRIC);
+ thin = solparser_get_material_thin_dielectric(parser, mtl->data.thin_dielectric);
+ CHECK(thin->thickness, 0.1);
+ NCHECK(thin->medium_i.i, thin->medium_t.i);
+ CHECK(SOLPARSER_ID_IS_VALID(thin->normal_map), 1);
+ img = solparser_get_image(parser, thin->normal_map);
+ CHECK(strcmp(str_cget(&img->filename), "Bump"), 0);
+
+ solparser_entity_iterator_next(&it);
+ CHECK(solparser_entity_iterator_eq(&it, &end), 1);
+
+ CHECK(solparser_load(parser), RES_BAD_OP);
+ fclose(stream);
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct solparser* parser;
+ (void)argc, (void)argv;
+
+ CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK);
+ CHECK(solparser_create(&allocator, &parser), RES_OK);
+
+ test_dielectric(parser);
+ test_matte(parser);
+ test_mirror(parser);
+ test_thin_dielectric(parser);
+
+ solparser_ref_put(parser);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+ return 0;
+}
+
diff --git a/src/parser/yaml/test_ko_0.yaml b/src/parser/yaml/test_ko_0.yaml
@@ -204,6 +204,7 @@
# <matte> ::=
# matte:
# reflectivity: REAL # in [0, 1]
+# [ normal_map: { path: PATH } ]
#
# missing matte parameters
@@ -224,7 +225,25 @@
# 2x reflectivity
- material: { matte: { reflectivity: 1, reflectivity: 1 } }
---
-
+# bad normal map
+- material:
+ matte: { reflectivity: 1, normal_map: map }
+---
+# bad normal map
+- material:
+ matte: { reflectivity: 1, normal_map: { path: } }
+---
+# Missing reflectivity
+- material:
+ matte: { normal_map: { path: test } }
+---
+# 2x normal map
+- material:
+ matte:
+ reflectivity: 1
+ normal_map: { path: test }
+ normal_map: { path: test2}
+#
#
# <thin-dielectric> ::=
# thin_dielectric:
diff --git a/src/parser/yaml/test_ok_2.yaml b/src/parser/yaml/test_ok_2.yaml
@@ -39,3 +39,16 @@
geometry:
- material: { matte: { reflectivity: 1 } }
stl: { path: "path/path/path" }
+---
+- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] }
+- material: &lambertian
+ matte:
+ reflectivity: 0.123
+ normal_map: { path: "path/to my normal map" }
+- entity:
+ name: hop
+ primary: 1
+ geometry:
+ - material: *lambertian
+ stl: { path: "path/path/path" }
+
diff --git a/src/solstice_draw.c b/src/solstice_draw.c
@@ -23,27 +23,32 @@
/*******************************************************************************
* Helper function
******************************************************************************/
-/* Assume that the pixel format of the src is DOUBLE3 in gray scale while the
- * pixel format of dst is UBYTE */
+/* Assume that the pixel format of the src is DOUBLE3 and dst is UBYTE3 */
static void
-tone_map(const double* src, unsigned char* dst, const size_t count)
+tone_map(const double* src, uint8_t* dst, const size_t count)
{
size_t i;
ASSERT(src && dst && count);
FOR_EACH(i, 0, count) {
- double val;
- val = pow(src[i*3/*#channels*/], 1/SCREEN_GAMMA);/* Gamma correction */
- val = CLAMP(val, 0, 1);
- dst[i] = (unsigned char)((val * 255) + 0.5/*round*/);
+ double val[3];
+ val[0] = pow(src[i*3/*#channels*/+0], 1/SCREEN_GAMMA);/* Gamma correction */
+ val[1] = pow(src[i*3/*#channels*/+1], 1/SCREEN_GAMMA);/* Gamma correction */
+ val[2] = pow(src[i*3/*#channels*/+2], 1/SCREEN_GAMMA);/* Gamma correction */
+ val[0] = CLAMP(val[0], 0, 1);
+ val[1] = CLAMP(val[1], 0, 1);
+ val[2] = CLAMP(val[2], 0, 1);
+ dst[i*3/*#channels*/ + 0] = (uint8_t)((val[0]*255) + 0.5/*round*/);
+ dst[i*3/*#channels*/ + 1] = (uint8_t)((val[1]*255) + 0.5/*round*/);
+ dst[i*3/*#channels*/ + 2] = (uint8_t)((val[2]*255) + 0.5/*round*/);
}
}
static void
-tone_map_image(const struct ssol_image* img, unsigned char* dst)
+tone_map_image(const struct ssol_image* img, uint8_t* dst)
{
struct ssol_image_layout layout;
size_t irow = 0;
- void* mem;
+ char* mem;
ASSERT(img && dst);
SSOL(image_get_layout(img, &layout));
@@ -52,7 +57,7 @@ tone_map_image(const struct ssol_image* img, unsigned char* dst)
SSOL(image_map(img, &mem));
FOR_EACH(irow, 0, layout.height) {
const void* src_row = ((char*)mem) + layout.offset + irow * layout.row_pitch;
- unsigned char* dst_row = dst + irow * layout.width;
+ uint8_t* dst_row = dst + irow * layout.width * 3/*#channels*/;
tone_map(src_row, dst_row, layout.width);
}
}
@@ -64,13 +69,17 @@ res_T
solstice_draw(struct solstice* solstice)
{
struct ssol_image_layout layout;
- unsigned char* ubytes = NULL;
+ struct image img;
+ size_t pitch;
res_T res = RES_OK;
ASSERT(solstice);
SSOL(image_get_layout(solstice->framebuffer, &layout));
- ubytes = MEM_ALLOC(solstice->allocator, layout.width*layout.height);
- if(!ubytes) {
+
+ pitch = layout.width * sizeof_image_format(IMAGE_RGB8);
+ image_init(solstice->allocator, &img);
+ res = image_setup(&img, layout.width, layout.height, pitch, IMAGE_RGB8, NULL);
+ if(res != RES_OK) {
fprintf(stderr, "Could not allocate the 8-bits image buffer.\n");
res = RES_MEM_ERR;
goto error;
@@ -92,9 +101,9 @@ solstice_draw(struct solstice* solstice)
goto error;
}
- tone_map_image(solstice->framebuffer, ubytes);
- res = image_ppm_write_stream(solstice->output, (int)layout.width,
- (int)layout.height, 1, ubytes);
+ tone_map_image(solstice->framebuffer, (uint8_t*)img.pixels);
+
+ res = image_write_ppm_stream(&img, 0, solstice->output);
if(res != RES_OK) {
fprintf(stderr,
"Could not write the rendered image to the output stream.\n");
@@ -102,7 +111,7 @@ solstice_draw(struct solstice* solstice)
}
exit:
- if(ubytes) MEM_RM(solstice->allocator, ubytes);
+ image_release(&img);
return res;
error:
goto exit;
diff --git a/src/solstice_material.c b/src/solstice_material.c
@@ -16,36 +16,87 @@
#include "solstice.h"
#include "solstice_c.h"
+#include <rsys/double33.h>
+#include <rsys/image.h>
#include <solstice/ssol.h>
+struct dielectric_param {
+ struct ssol_image* normal_map;
+};
+
struct matte_param {
double reflectivity;
+ struct ssol_image* normal_map;
};
struct mirror_param {
double reflectivity;
double roughness;
+ struct ssol_image* normal_map;
+};
+
+struct thin_dielectric_param {
+ struct ssol_image* normal_map;
};
/*******************************************************************************
* Helper functions
******************************************************************************/
static void
+perturb_normal
+ (const struct ssol_surface_fragment* frag,
+ const struct ssol_image* normal_map,
+ double normal[3])
+{
+ double basis[9];
+ double N[3];
+ ASSERT(frag && normal_map && normal);
+
+ SSOL(image_sample(normal_map, SSOL_FILTER_LINEAR, SSOL_ADDRESS_CLAMP,
+ SSOL_ADDRESS_CLAMP, frag->uv, N));
+
+ d3_set(basis+0, frag->dPdu);
+ d3_set(basis+3, frag->dPdv);
+ d3_set(basis+6, frag->Ng);
+ d3_normalize(basis + 0, basis + 0);
+ d3_normalize(basis + 3, basis + 3);
+
+ d3_subd(N, d3_muld(N, N, 2), 1);
+ d33_muld3(N, basis, N);
+ d3_normalize(normal, N);
+}
+
+static void
mtl_get_normal
(struct ssol_device* dev,
struct ssol_param_buffer* buf,
const double wavelength,
- const double P[3],
- const double Ng[3],
- const double Ns[3],
- const double uv[2],
- const double w[3],
+ const struct ssol_surface_fragment* frag,
double* val)
{
- (void)dev, (void)buf, (void)wavelength, (void)P, (void)Ng, (void)uv, (void)w;
- val[0] = Ns[0];
- val[1] = Ns[1];
- val[2] = Ns[2];
+ (void)dev, (void)buf, (void)wavelength;
+ d3_set(val, frag->Ns);
+}
+
+static void
+dielectric_get_normal
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wavelength,
+ const struct ssol_surface_fragment* frag,
+ double* val)
+{
+ const struct dielectric_param* param = ssol_param_buffer_get(buf);
+ (void)dev, (void)buf, (void)wavelength;
+ perturb_normal(frag, param->normal_map, val);
+}
+
+static void
+dielectric_param_release(void* mem)
+{
+ struct dielectric_param* param = mem;
+ ASSERT(param);
+ if(param->normal_map) SSOL(image_ref_put(param->normal_map));
}
static void
@@ -53,32 +104,45 @@ matte_get_reflectivity
(struct ssol_device* dev,
struct ssol_param_buffer* buf,
const double wavelength,
- const double P[3],
- const double Ng[3],
- const double Ns[3],
- const double uv[2],
- const double w[3],
+ const struct ssol_surface_fragment* frag,
double* val)
{
const struct matte_param* param = ssol_param_buffer_get(buf);
- (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w;
+ (void)dev, (void)wavelength, (void)frag;
*val = param->reflectivity;
}
static void
+matte_get_normal
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wavelength,
+ const struct ssol_surface_fragment* frag,
+ double* val)
+{
+ const struct matte_param* param = ssol_param_buffer_get(buf);
+ (void)dev, (void)wavelength;
+ perturb_normal(frag, param->normal_map, val);
+}
+
+static void
+matte_param_release(void* mem)
+{
+ struct matte_param* param = mem;
+ ASSERT(param);
+ if(param->normal_map) SSOL(image_ref_put(param->normal_map));
+}
+
+static void
mirror_get_reflectivity
(struct ssol_device* dev,
struct ssol_param_buffer* buf,
const double wavelength,
- const double P[3],
- const double Ng[3],
- const double Ns[3],
- const double uv[2],
- const double w[3],
+ const struct ssol_surface_fragment* frag,
double* val)
{
const struct mirror_param* param = ssol_param_buffer_get(buf);
- (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w;
+ (void)dev, (void)wavelength, (void)frag;
*val = param->reflectivity;
}
@@ -87,18 +151,125 @@ mirror_get_roughness
(struct ssol_device* dev,
struct ssol_param_buffer* buf,
const double wavelength,
- const double P[3],
- const double Ng[3],
- const double Ns[3],
- const double uv[2],
- const double w[3],
+ const struct ssol_surface_fragment* frag,
double* val)
{
const struct mirror_param* param = ssol_param_buffer_get(buf);
- (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w;
+ (void)dev, (void)wavelength, (void)frag;
*val = param->roughness;
}
+static void
+mirror_get_normal
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wavelength,
+ const struct ssol_surface_fragment* frag,
+ double* val)
+{
+ const struct mirror_param* param = ssol_param_buffer_get(buf);
+ (void)dev, (void)wavelength;
+ perturb_normal(frag, param->normal_map, val);
+}
+
+static void
+mirror_param_release(void* mem)
+{
+ struct mirror_param* param = mem;
+ ASSERT(param);
+ if(param->normal_map) SSOL(image_ref_put(param->normal_map));
+}
+
+static void
+thin_dielectric_get_normal
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wavelength,
+ const struct ssol_surface_fragment* frag,
+ double* val)
+{
+ const struct thin_dielectric_param* param = ssol_param_buffer_get(buf);
+ (void)dev, (void)buf, (void)wavelength;
+ perturb_normal(frag, param->normal_map, val);
+}
+
+static void
+thin_dielectric_param_release(void* mem)
+{
+ struct thin_dielectric_param* param = mem;
+ ASSERT(param);
+ if(param->normal_map) SSOL(image_ref_put(param->normal_map));
+}
+
+static res_T
+load_image
+ (struct solstice* solstice,
+ const char* filename,
+ struct ssol_image** out_ssol_img)
+{
+ struct ssol_image* ssol_img = NULL;
+ struct ssol_image_layout layout;
+ struct image img;
+ char* mem;
+ size_t x, y;
+ res_T res = RES_OK;
+ ASSERT(solstice && filename && out_ssol_img);
+
+ image_init(solstice->allocator, &img);
+
+ res = image_read_ppm(&img, filename);
+ if(res != RES_OK) {
+ fprintf(stderr, "Could not load the PPM image `%s'.\n", filename);
+ goto error;
+ }
+
+ res = ssol_image_create(solstice->ssol, &ssol_img);
+ if(res != RES_OK) {
+ fprintf(stderr, "Could not create the Solstice Solver image.\n");
+ goto error;
+ }
+
+ res = ssol_image_setup(ssol_img, img.width, img.height, SSOL_PIXEL_DOUBLE3);
+ if(res != RES_OK) {
+ fprintf(stderr, "Could not setup the Solstice Solver image.\n");
+ goto error;
+ }
+
+ SSOL(image_get_layout(ssol_img, &layout));
+ SSOL(image_map(ssol_img, &mem));
+
+ FOR_EACH(y, 0, layout.height) {
+ char* dst_row = mem + layout.offset + y * layout.row_pitch;
+ const char* src_row = img.pixels + y * img.pitch;
+
+ FOR_EACH(x, 0, layout.width) {
+ char* dst = dst_row + x*ssol_sizeof_pixel_format(layout.pixel_format);
+ const char* src = src_row + x*sizeof_image_format(img.format);
+ switch(img.format) {
+ case IMAGE_RGB8:
+ ((double*)dst)[0] = ((double)((uint8_t*)src)[0] + 0.5) / UINT8_MAX;
+ ((double*)dst)[1] = ((double)((uint8_t*)src)[1] + 0.5) / UINT8_MAX;
+ ((double*)dst)[2] = ((double)((uint8_t*)src)[2] + 0.5) / UINT8_MAX;
+ break;
+ case IMAGE_RGB16:
+ ((double*)dst)[0] = ((double)((uint16_t*)src)[0] + 0.5) / UINT16_MAX;
+ ((double*)dst)[1] = ((double)((uint16_t*)src)[1] + 0.5) / UINT16_MAX;
+ ((double*)dst)[2] = ((double)((uint16_t*)src)[2] + 0.5) / UINT16_MAX;
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ }
+ }
+
+exit:
+ image_release(&img);
+ *out_ssol_img = ssol_img;
+ return res;
+error:
+ if(ssol_img) SSOL(image_ref_put(ssol_img));
+ goto exit;
+}
+
static res_T
create_material_dielectric
(struct solstice* solstice,
@@ -110,7 +281,9 @@ create_material_dielectric
struct ssol_medium ssol_medium_i;
struct ssol_medium ssol_medium_t;
struct ssol_dielectric_shader shader = SSOL_DIELECTRIC_SHADER_NULL;
+ struct ssol_image* img = NULL;
struct ssol_material* mtl = NULL;
+ struct ssol_param_buffer* pbuf = NULL;
res_T res = RES_OK;
ASSERT(solstice && dielectric && out_mtl);
@@ -123,7 +296,36 @@ create_material_dielectric
medium_i = solparser_get_medium(solstice->parser, dielectric->medium_i);
medium_t = solparser_get_medium(solstice->parser, dielectric->medium_t);
- shader.normal = mtl_get_normal;
+
+ if(!SOLPARSER_ID_IS_VALID(dielectric->normal_map)) {
+ shader.normal = mtl_get_normal;
+ } else {
+ const struct solparser_image* image;
+ struct dielectric_param* param = NULL;
+
+ image = solparser_get_image(solstice->parser, dielectric->normal_map);
+ res = load_image(solstice, str_cget(&image->filename), &img);
+ if(res != RES_OK) goto error;
+
+ res = ssol_param_buffer_create
+ (solstice->ssol, sizeof(struct dielectric_param), &pbuf);
+ if(res != RES_OK) {
+ fprintf(stderr, "Could not create the Solstice Solver parameter buffer.\n");
+ goto error;
+ }
+
+ param = ssol_param_buffer_allocate(pbuf, sizeof(struct dielectric_param),
+ ALIGNOF(struct dielectric_param), dielectric_param_release);
+ if(!param) {
+ fprintf(stderr, "Could not allocate the dielectric parameter.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ param->normal_map = img;
+ shader.normal = dielectric_get_normal;
+ SSOL(material_set_param_buffer(mtl, pbuf));
+ }
+
ssol_medium_i.refractive_index = medium_i->refractive_index;
ssol_medium_i.absorptivity = medium_i->absorptivity;
ssol_medium_t.refractive_index = medium_t->refractive_index;
@@ -131,10 +333,12 @@ create_material_dielectric
SSOL(dielectric_setup(mtl, &shader, &ssol_medium_i, &ssol_medium_t));
exit:
+ if(pbuf) SSOL(param_buffer_ref_put(pbuf));
*out_mtl = mtl;
return res;
error:
if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL;
+ if(img) SSOL(image_ref_put(img));
goto exit;
}
@@ -145,6 +349,7 @@ create_material_matte
struct ssol_material** out_mtl)
{
struct ssol_matte_shader shader = SSOL_MATTE_SHADER_NULL;
+ struct ssol_image* img = NULL;
struct ssol_material* mtl = NULL;
struct ssol_param_buffer* pbuf = NULL;
struct matte_param* param;
@@ -164,16 +369,27 @@ create_material_matte
goto error;
}
- param = ssol_param_buffer_allocate
- (pbuf, sizeof(struct matte_param), ALIGNOF(struct matte_param));
+ param = ssol_param_buffer_allocate(pbuf, sizeof(struct matte_param),
+ ALIGNOF(struct matte_param), matte_param_release);
if(!param) {
fprintf(stderr, "Could not allocate the matte parameter.\n");
res = RES_MEM_ERR;
goto error;
}
+ memset(param, 0, sizeof(struct matte_param));
+
param->reflectivity = matte->reflectivity;
+ if(!SOLPARSER_ID_IS_VALID(matte->normal_map)) {
+ shader.normal = mtl_get_normal;
+ } else {
+ const struct solparser_image* image;
+ image = solparser_get_image(solstice->parser, matte->normal_map);
+ res = load_image(solstice, str_cget(&image->filename), &img);
+ if(res != RES_OK) goto error;
+ param->normal_map = img;
+ shader.normal = matte_get_normal;
+ }
- shader.normal = mtl_get_normal;
shader.reflectivity = matte_get_reflectivity;
SSOL(matte_setup(mtl, &shader));
SSOL(material_set_param_buffer(mtl, pbuf));
@@ -184,6 +400,7 @@ exit:
return res;
error:
if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL;
+ if(img) SSOL(image_ref_put(img));
goto exit;
}
@@ -193,6 +410,7 @@ create_material_mirror
const struct solparser_material_mirror* mirror,
struct ssol_material** out_mtl)
{
+ struct ssol_image* img = NULL;
struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL;
struct ssol_material* mtl = NULL;
struct ssol_param_buffer* pbuf = NULL;
@@ -213,17 +431,28 @@ create_material_mirror
goto error;
}
- param = ssol_param_buffer_allocate
- (pbuf, sizeof(struct mirror_param), ALIGNOF(struct mirror_param));
+ param = ssol_param_buffer_allocate(pbuf, sizeof(struct mirror_param),
+ ALIGNOF(struct mirror_param), mirror_param_release);
if(!param) {
fprintf(stderr, "Could not allocate the mirror parameters.\n");
res = RES_MEM_ERR;
goto error;
}
+ memset(param, 0, sizeof(struct mirror_param));
param->reflectivity = mirror->reflectivity;
param->roughness = mirror->roughness;
- shader.normal = mtl_get_normal;
+ if(!SOLPARSER_ID_IS_VALID(mirror->normal_map)) {
+ shader.normal = mtl_get_normal;
+ } else {
+ const struct solparser_image* image;
+ image = solparser_get_image(solstice->parser, mirror->normal_map);
+ res = load_image(solstice, str_cget(&image->filename), &img);
+ if(res != RES_OK) goto error;
+ param->normal_map = img;
+ shader.normal = mirror_get_normal;
+ }
+
shader.reflectivity = mirror_get_reflectivity;
shader.roughness = mirror_get_roughness;
SSOL(mirror_setup(mtl, &shader));
@@ -235,6 +464,7 @@ exit:
return res;
error:
if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL;
+ if(img) SSOL(image_ref_put(img));
goto exit;
}
@@ -244,12 +474,14 @@ create_material_thin_dielectric
const struct solparser_material_thin_dielectric* thin,
struct ssol_material** out_mtl)
{
+ struct ssol_image* img = NULL;
struct ssol_thin_dielectric_shader shader = SSOL_THIN_DIELECTRIC_SHADER_NULL;
const struct solparser_medium* medium_i;
const struct solparser_medium* medium_t;
struct ssol_medium ssol_medium_i;
struct ssol_medium ssol_medium_t;
struct ssol_material* mtl = NULL;
+ struct ssol_param_buffer* pbuf = NULL;
res_T res = RES_OK;
ASSERT(solstice && thin && out_mtl);
@@ -260,9 +492,40 @@ create_material_thin_dielectric
goto error;
}
- shader.normal = mtl_get_normal;
medium_i = solparser_get_medium(solstice->parser, thin->medium_i);
medium_t = solparser_get_medium(solstice->parser, thin->medium_t);
+
+ if(!SOLPARSER_ID_IS_VALID(thin->normal_map)) {
+ shader.normal = mtl_get_normal;
+ } else {
+ const struct solparser_image* image;
+ struct dielectric_param* param = NULL;
+
+ image = solparser_get_image(solstice->parser, thin->normal_map);
+ res = load_image(solstice, str_cget(&image->filename), &img);
+ if(res != RES_OK) goto error;
+
+ res = ssol_param_buffer_create
+ (solstice->ssol, sizeof(struct thin_dielectric_param), &pbuf);
+ if(res != RES_OK) {
+ fprintf(stderr, "Could not create the Solsitce Solver parameter buffer.\n");
+ goto error;
+ }
+
+ param = ssol_param_buffer_allocate(pbuf,
+ sizeof(struct thin_dielectric_param),
+ ALIGNOF(struct thin_dielectric_param),
+ thin_dielectric_param_release);
+ if(!param) {
+ fprintf(stderr, "Could not allocate the thin dielectric parameter.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ param->normal_map = img;
+ shader.normal = thin_dielectric_get_normal;
+ SSOL(material_set_param_buffer(mtl, pbuf));
+ }
+
ssol_medium_i.refractive_index = medium_i->refractive_index;
ssol_medium_t.refractive_index = medium_t->refractive_index;
ssol_medium_i.absorptivity = medium_i->absorptivity;
@@ -271,10 +534,12 @@ create_material_thin_dielectric
(mtl, &shader, &ssol_medium_i, &ssol_medium_t, thin->thickness));
exit:
+ if(pbuf) SSOL(param_buffer_ref_put(pbuf));
*out_mtl = mtl;
return res;
error:
if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL;
+ if(img) SSOL(image_ref_put(img));
goto exit;
}
diff --git a/src/solstice_object.c b/src/solstice_object.c
@@ -500,11 +500,17 @@ create_shaded_shape
res_T res = RES_OK;
ASSERT(solstice && ssol_front && ssol_back && ssol_shape);
+ *ssol_front = NULL;
+ *ssol_back = NULL;
+ *ssol_shape = NULL;
+
obj = solparser_get_object(solstice->parser, obj_id);
mtl2 = solparser_get_material_double_sided(solstice->parser, obj->mtl2);
- solstice_create_ssol_material(solstice, mtl2->front, ssol_front);
- solstice_create_ssol_material(solstice, mtl2->back, ssol_back);
+ res = solstice_create_ssol_material(solstice, mtl2->front, ssol_front);
+ if(res != RES_OK) goto error;
+ res = solstice_create_ssol_material(solstice, mtl2->back, ssol_back);
+ if(res != RES_OK) goto error;
/* Define the shape transformation */
rotation[0] = MDEG2RAD(obj->rotation[0]);
@@ -547,7 +553,15 @@ create_shaded_shape
break;
default: FATAL("Unreachable code.\n"); break;
}
+ if(res != RES_OK) goto error;
+
+exit:
return res;
+error:
+ if(*ssol_front) SSOL(material_ref_put(*ssol_front));
+ if(*ssol_back) SSOL(material_ref_put(*ssol_back));
+ if(*ssol_shape) SSOL(shape_ref_put(*ssol_shape));
+ goto exit;
}
/*******************************************************************************