commit 02322401dcbd4d8624c1a758668a65293e77c8da
parent c029956a0a6269abe8a4a981ffcc1888470d13b7
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 21 Apr 2017 14:55:34 +0200
Merge remote-tracking branch 'origin/develop' into feature_new_shapes
Diffstat:
15 files changed, 687 insertions(+), 321 deletions(-)
diff --git a/src/ssol.h b/src/ssol.h
@@ -92,9 +92,14 @@ enum ssol_pixel_format {
SSOL_PIXEL_FORMATS_COUNT__
};
-enum ssol_parametrization_type {
- SSOL_PARAMETRIZATION_TEXCOORD, /* Map from 3D to 2D with texcoord */
- SSOL_PARAMETRIZATION_PRIMITIVE_ID /* Map from 3D to 1D with primitive id */
+enum ssol_filter_mode {
+ SSOL_FILTER_LINEAR,
+ SSOL_FILTER_NEAREST
+};
+
+enum ssol_address_mode {
+ SSOL_ADDRESS_CLAMP,
+ SSOL_ADDRESS_REPEAT
};
enum ssol_quadric_type {
@@ -244,16 +249,27 @@ struct ssol_medium {
#define SSOL_MEDIUM_VACUUM__ { 0, 1 }
static const struct ssol_medium SSOL_MEDIUM_VACUUM = SSOL_MEDIUM_VACUUM__;
+struct ssol_surface_fragment {
+ double dir[3]; /* World space incoming direction. Point forward the surface */
+ double P[3]; /* World space position */
+ double Ng[3]; /* Normalized world space geometry normal */
+ double Ns[3]; /* Normalized world space shading normal */
+ double uv[2]; /* Texture coordinates */
+ double dPdu[3]; /* Partial derivative of the position in u */
+ double dPdv[3]; /* Partial derivative of the position in v */
+};
+
+#define SSOL_SURFACE_FRAGMENT_NULL__ \
+ {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0}, {0,0,0}, {0,0,0}}
+static const struct ssol_surface_fragment SSOL_SURFACE_FRAGMENT_NULL =
+ SSOL_SURFACE_FRAGMENT_NULL__;
+
typedef void
(*ssol_shader_getter_T)
(struct ssol_device* dev,
struct ssol_param_buffer* buf,
- const double wavelength, /* In nanometer */
- const double P[3], /* World space position */
- const double Ng[3], /* World space geometry normal */
- const double Ns[3], /* World space shading normal */
- const double uv[2], /* Texture coordinates */
- const double w[3], /* Incoming direction. Point toward the surface */
+ const double wavelength,
+ const struct ssol_surface_fragment* fragment,
double* val); /* Returned value */
/* Dielectric material shader */
@@ -546,12 +562,21 @@ ssol_image_get_layout
SSOL_API res_T
ssol_image_map
(const struct ssol_image* image,
- void** memory);
+ char** memory);
SSOL_API res_T
ssol_image_unmap
(const struct ssol_image* image);
+SSOL_API res_T
+ssol_image_sample
+ (const struct ssol_image* image,
+ const enum ssol_filter_mode filter,
+ const enum ssol_address_mode address_u,
+ const enum ssol_address_mode address_v,
+ const double uv[2],
+ void* val);
+
/* Helper function that matches the `ssol_write_pixels_T' functor type */
SSOL_API res_T
ssol_image_write
@@ -893,7 +918,10 @@ SSOL_API void*
ssol_param_buffer_allocate
(struct ssol_param_buffer* buf,
const size_t size,
- const size_t alignment); /* Power of 2 in [1, 64] */
+ const size_t alignment, /* Power of 2 in [1, 64] */
+ /* Functor to invoke on the allocated memory priorly to its destruction.
+ * May be NULL */
+ void (*release)(void*));
/* Retrieve the address of the first allocated parameter */
SSOL_API void*
diff --git a/src/ssol_draw_draft.c b/src/ssol_draw_draft.c
@@ -17,6 +17,7 @@
#include "ssol_camera.h"
#include "ssol_device_c.h"
#include "ssol_draw.h"
+#include "ssol_material_c.h"
#include "ssol_object_c.h"
#include "ssol_scene_c.h"
#include "ssol_shape_c.h"
@@ -41,6 +42,7 @@ Li
double val[3])
{
const float range[2] = {0, FLT_MAX};
+ struct ssol_surface_fragment frag;
struct ray_data ray_data = RAY_DATA_NULL;
struct s3d_hit hit;
ASSERT(scn && view && org && dir && val);
@@ -52,9 +54,12 @@ Li
d3_splat(val, 0);
} else {
struct ssol_instance* inst;
+ struct ssol_material* mtl;
const struct shaded_shape* sshape;
size_t isshape;
- float N[3]={0};
+ double o[3], wi[3];
+ double N[3]={0};
+ double cos_N_wi;
/* Retrieve the hit shaded shape */
inst = *htable_instance_find(&scn->instances_rt, &hit.prim.inst_id);
@@ -65,16 +70,28 @@ Li
/* Retrieve and normalized the hit normal */
switch(sshape->shape->type) {
- case SHAPE_MESH:
- f3_normalize(N, hit.normal);
- break;
- case SHAPE_PUNCHED:
- f3_normalize(N, f3_set_d3(N, ray_data.N));
+ case SHAPE_MESH: d3_normalize(N, d3_set_f3(N, hit.normal)); break;
+ case SHAPE_PUNCHED: d3_normalize(N, ray_data.N); break;
break;
default: FATAL("Unreachable code"); break;
}
- ASSERT(f3_is_normalized(N));
- d3_splat(val, fabs(f3_dot(N, dir)));
+
+ d3_set_f3(o, org);
+ d3_set_f3(wi, dir);
+ d3_normalize(wi, wi);
+ if(d3_dot(N, wi) < 0) {
+ mtl = sshape->mtl_front;
+ } else {
+ mtl = sshape->mtl_back;
+ d3_minus(N, N);
+ }
+
+ surface_fragment_setup(&frag, o, wi, N, &hit.prim, hit.uv);
+ material_shade_normal(mtl, &frag, 1/*TODO wavelength*/, N);
+
+ ASSERT(d3_is_normalized(N));
+ cos_N_wi = d3_dot(N, d3_minus(wi, wi));
+ d3_splat(val, MMAX(cos_N_wi, 0));
}
}
@@ -88,14 +105,14 @@ draw_pixel
const float pix_sz[2], /* Normalized pixel size */
const size_t nsamples,
double pixel[3],
- void* ctx)
+ void* data)
{
- struct darray_float* samples = ctx;
+ struct darray_float* samples = data;
float samp[2];
float ray_org[3], ray_dir[3];
double sum[3] = {0, 0, 0};
size_t i;
- ASSERT(scn && cam && view && pix_coords && pix_sz && nsamples && pixel && ctx);
+ ASSERT(scn && cam && view && pix_coords && pix_sz && nsamples && pixel && data);
(void)ithread;
FOR_EACH(i, 0, nsamples) {
@@ -139,6 +156,7 @@ ssol_draw_draft
if(!scn || !spp) return RES_BAD_ARG;
darray_float_init(scn->dev->allocator, &samples);
+
res = darray_float_reserve(&samples, spp * 2/*#dimensions*/);
if(res != RES_OK) goto error;
diff --git a/src/ssol_draw_pt.c b/src/ssol_draw_pt.c
@@ -108,13 +108,12 @@ sun_lighting
d3_minus(wi, sun->direction);
/* The point look backward the sun */
- if(d3_dot(wi, N) < 0) return 0.0;
+ cos_wi_N = d3_dot(wi, N);
+ if(cos_wi_N < 0 || eq_eps(cos_wi_N, 0, 1.e-6)) return 0.0;
R = ssf_bsdf_eval(bsdf, wo, N, wi);
if(R <= 0) return 0.0;
- cos_wi_N = d3_dot(wi, N);
-
f3_set_d3(ray_dir, wi);
S3D(scene_view_trace_ray(view, ray_org, ray_dir, ray_range, ray_data, &hit));
if(S3D_HIT_NONE(&hit)) return R * cos_wi_N;
@@ -135,7 +134,7 @@ Li(struct ssol_scene* scn,
struct ssol_instance* inst;
struct ssol_material* mtl;
const struct shaded_shape* sshape;
- struct surface_fragment frag;
+ struct ssol_surface_fragment frag;
size_t isshape;
double throughput = 1.0;
double wi[3], o[3], uv[3];
@@ -144,6 +143,7 @@ Li(struct ssol_scene* scn,
double L = 0;
double R;
double pdf;
+ double cos_wi_Ng;
const float ray_range[2] = {0, FLT_MAX};
float ray_org[3];
float ray_dir[3];
@@ -207,16 +207,25 @@ Li(struct ssol_scene* scn,
}
surface_fragment_setup(&frag, o, wo, N, &hit.prim, hit.uv);
+ material_shade_normal(mtl, &frag, 1/*TODO wlen*/, N);
+
+ /* Shaded normal may look backward the outgoing direction */
+ if(d3_dot(N, wo) > 0) break;
+
SSF(bsdf_clear(ctx->bsdf));
- res = material_shade_rendering
- (mtl, &frag, 1/*TODO wavelength*/, &medium, ctx->bsdf);
+ res = material_setup_bsdf
+ (mtl, &frag, 1/*TODO wavelength*/, &medium, 1/*Rendering*/, ctx->bsdf);
if(res != RES_OK) goto error;
/* Update the ray */
ray_data.prim_from = hit.prim;
ray_data.inst_from = inst;
ray_data.side_from = side;
- f3_mulf(ray_dir, ray_dir, hit.distance);
+ switch(sshape->shape->type) {
+ case SHAPE_MESH: f3_mulf(ray_dir, ray_dir, hit.distance); break;
+ case SHAPE_PUNCHED: f3_mulf(ray_dir, ray_dir, (float)ray_data.dst); break;
+ default: FATAL("Unreachable code"); break;
+ }
f3_add(ray_org, ray_org, ray_dir);
d3_minus(wo, wo);
@@ -225,8 +234,18 @@ Li(struct ssol_scene* scn,
(scn->sun, view, &ray_data, ctx->bsdf, wo, N, ray_org);
}
- R = ssf_bsdf_sample(ctx->bsdf, ctx->rng, wo, frag.Ns, wi, &type, &pdf);
+ /* Sampling a bounce direction */
+ R = ssf_bsdf_sample(ctx->bsdf, ctx->rng, wo, N, wi, &type, &pdf);
ASSERT(0 <= R && R <= 1);
+
+ /* Due to the shading normal, the sampled direction may point in the wrong
+ * direction wrt the sampled BSDF component. */
+ cos_wi_Ng = d3_dot(frag.Ng, wi);
+ if((cos_wi_Ng > 0 && (type & SSF_TRANSMISSION))
+ || (cos_wi_Ng < 0 && (type & SSF_REFLECTION))) {
+ R = 0;
+ }
+
f3_set_d3(ray_dir, wi);
if(type & SSF_TRANSMISSION) material_get_next_medium(mtl, &medium, &medium);
@@ -234,7 +253,7 @@ Li(struct ssol_scene* scn,
throughput *= fabs(d3_dot(wi, N)) * R;
} else {
if(ssp_rng_canonical(ctx->rng) >= R) break;
- throughput *= d3_dot(wi, N);
+ throughput *= fabs(d3_dot(wi, N));
}
if(throughput <= 0) break;
@@ -275,7 +294,7 @@ draw_pixel
ctx = darray_thread_context_data_get(thread_ctxs) + ithread;
FOR_EACH(isample, 0, nsamples) {
- const int MAX_NFAILURES = 10;
+ const int MAX_NFAILURES = 100;
double weight[3];
float samp[2]; /* Pixel sample */
float ray_org[3], ray_dir[3];
diff --git a/src/ssol_image.c b/src/ssol_image.c
@@ -13,6 +13,8 @@
* 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 support */
+
#include "ssol.h"
#include "ssol_image_c.h"
#include "ssol_device_c.h"
@@ -21,11 +23,35 @@
#include <rsys/ref_count.h>
#include <rsys/rsys.h>
+#include <math.h>
#include <string.h>
/*******************************************************************************
* Helper functions
******************************************************************************/
+static INLINE double
+map_address(const double address, const enum ssol_address_mode mode)
+{
+ double dbl;
+ double i;
+ switch(mode) {
+ case SSOL_ADDRESS_CLAMP: dbl = CLAMP(address, 0, nextafter(1,0)); break;
+ case SSOL_ADDRESS_REPEAT:
+ dbl = modf(address, &i);
+ if(dbl < 0) dbl = 1.0+dbl;
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ return dbl;
+}
+
+static INLINE const char*
+get_pixel(const struct ssol_image* img, const size_t x, const size_t y)
+{
+ ASSERT(img && x < img->size[0] && y < img->size[1]);
+ return img->mem + y*img->pitch + x*ssol_sizeof_pixel_format(img->format);
+}
+
static void
image_release(ref_T* ref)
{
@@ -136,7 +162,7 @@ ssol_image_get_layout
}
res_T
-ssol_image_map(const struct ssol_image* img, void** mem)
+ssol_image_map(const struct ssol_image* img, char** mem)
{
if(!img || !mem) return RES_BAD_ARG;
*mem = img->mem;
@@ -151,6 +177,57 @@ res_T ssol_image_unmap(const struct ssol_image* img)
}
res_T
+ssol_image_sample
+ (const struct ssol_image* img,
+ const enum ssol_filter_mode filter,
+ const enum ssol_address_mode address_u,
+ const enum ssol_address_mode address_v,
+ const double uv[2],
+ void* val)
+{
+ double* z00, *z01, *z10, *z11;
+ double x0, y0, x1, y1;
+ double texsz[2];
+ double s, t;
+ double* pix = val;
+ double integer;
+
+ if(!img || !uv || !val) return RES_BAD_ARG;
+
+ /* Only double3 pixel format is currently supported */
+ if(img->format != SSOL_PIXEL_DOUBLE3) return RES_BAD_ARG;
+
+ x0 = map_address(uv[0], address_u) * (double)img->size[0];
+ y0 = map_address(uv[1], address_v) * (double)img->size[1];
+
+ switch(filter) {
+ case SSOL_FILTER_NEAREST:
+ z00 = (double*)get_pixel(img, (size_t)x0, (size_t)y0);
+ pix[0] = z00[0];
+ pix[1] = z00[1];
+ pix[2] = z00[2];
+ break;
+ case SSOL_FILTER_LINEAR:
+ texsz[0] = 1.0/(double)img->size[0];
+ texsz[1] = 1.0/(double)img->size[1];
+ x1 = map_address(uv[0] + texsz[0], address_u) * (double)img->size[0];
+ y1 = map_address(uv[1] + texsz[1], address_v) * (double)img->size[1];
+ z00 = (double*)get_pixel(img, (size_t)x0, (size_t)y0);
+ z01 = (double*)get_pixel(img, (size_t)x0, (size_t)y1);
+ z10 = (double*)get_pixel(img, (size_t)x1, (size_t)y0);
+ z11 = (double*)get_pixel(img, (size_t)x1, (size_t)y1);
+ s = modf(x0, &integer);
+ t = modf(y0, &integer);
+ pix[0] = (1-s)*((1-t)*z00[0] + t*z01[0]) + s*((1-t)*z10[0] + t*z11[0]);
+ pix[1] = (1-s)*((1-t)*z00[1] + t*z01[1]) + s*((1-t)*z10[1] + t*z11[1]);
+ pix[2] = (1-s)*((1-t)*z00[2] + t*z01[2]) + s*((1-t)*z10[2] + t*z11[2]);
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ return RES_OK;
+}
+
+res_T
ssol_image_write
(void* image,
const size_t origin[2],
diff --git a/src/ssol_material.c b/src/ssol_material.c
@@ -18,8 +18,10 @@
#include "ssol_material_c.h"
#include "ssol_device_c.h"
-#include <rsys/double3.h>
#include <rsys/double2.h>
+#include <rsys/double3.h>
+#include <rsys/double33.h>
+#include <rsys/float2.h>
#include <rsys/float3.h>
#include <rsys/float33.h>
#include <rsys/ref_count.h>
@@ -33,10 +35,23 @@
/*******************************************************************************
* Helper functions
******************************************************************************/
+static void
+shade_normal_default
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wlen,
+ const struct ssol_surface_fragment* frag,
+ double* val) /* Returned value */
+{
+ ASSERT(frag && val);
+ (void)dev, (void)buf, (void)wlen;
+ d3_set(val, frag->Ns);
+}
+
static res_T
-dielectric_shade
+setup_dielectric_bsdf
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
+ const struct ssol_surface_fragment* fragment,
const double wavelength, /* In nanometer */
const struct ssol_medium* medium,
struct ssf_bsdf* bsdf)
@@ -44,18 +59,11 @@ dielectric_shade
struct ssf_bxdf* brdf = NULL;
struct ssf_bxdf* btdf = NULL;
struct ssf_fresnel* fresnel = NULL;
- const struct ssol_dielectric_shader* shader;
double eta_i, eta_t;
- double N[3];
res_T res = RES_OK;
ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_DIELECTRIC);
ASSERT(medium && bsdf);
-
- shader = &mtl->data.dielectric;
-
- /* Fetch material attribs */
- shader->normal(mtl->dev, mtl->buf, wavelength, fragment->pos, fragment->Ng,
- fragment->Ns, fragment->uv, fragment->dir, N);
+ (void)wavelength, (void)fragment;
if(!MEDIA_EQ(medium, &mtl->out_medium)) {
log_error(mtl->dev, "Inconsistent medium description.\n");
@@ -91,27 +99,21 @@ error:
}
static res_T
-matte_shade
+setup_matte_bsdf
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
+ const struct ssol_surface_fragment* fragment,
const double wavelength, /* In nanometer */
struct ssf_bsdf* bsdf)
{
struct ssf_bxdf* brdf = NULL;
- const struct ssol_matte_shader* shader;
- double normal[3];
double reflectivity;
res_T res;
ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_MATTE);
ASSERT(bsdf);
- shader = &mtl->data.matte;
-
/* Fetch material attribs */
- shader->normal(mtl->dev, mtl->buf, wavelength, fragment->pos,
- fragment->Ng, fragment->Ns, fragment->uv, fragment->dir, normal);
- shader->reflectivity(mtl->dev, mtl->buf, wavelength, fragment->pos,
- fragment->Ng, fragment->Ns, fragment->uv, fragment->dir, &reflectivity);
+ mtl->data.matte.reflectivity
+ (mtl->dev, mtl->buf, wavelength, fragment, &reflectivity);
/* Setup the BRDF */
res = ssf_bxdf_create(mtl->dev->allocator, &ssf_lambertian_reflection, &brdf);
@@ -131,9 +133,9 @@ error:
}
static res_T
-mirror_shade
+setup_mirror_bsdf
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
+ const struct ssol_surface_fragment* fragment,
const double wavelength, /* In nanometer */
const int rendering,
struct ssf_bsdf* bsdf)
@@ -141,23 +143,17 @@ mirror_shade
struct ssf_bxdf* brdf = NULL;
struct ssf_fresnel* fresnel = NULL;
struct ssf_microfacet_distribution* distrib = NULL;
- const struct ssol_mirror_shader* shader;
- double normal[3];
double roughness;
double reflectivity;
res_T res;
ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_MIRROR);
ASSERT(bsdf);
- shader = &mtl->data.mirror;
-
/* Fetch material attribs */
- shader->normal(mtl->dev, mtl->buf, wavelength, fragment->pos,
- fragment->Ng, fragment->Ns, fragment->uv, fragment->dir, normal);
- shader->reflectivity(mtl->dev, mtl->buf, wavelength, fragment->pos,
- fragment->Ng, fragment->Ns, fragment->uv, fragment->dir, &reflectivity);
- shader->roughness(mtl->dev, mtl->buf, wavelength, fragment->pos,
- fragment->Ng, fragment->Ns, fragment->uv, fragment->dir, &roughness);
+ mtl->data.mirror.reflectivity
+ (mtl->dev, mtl->buf, wavelength, fragment, &reflectivity);
+ mtl->data.mirror.roughness
+ (mtl->dev, mtl->buf, wavelength, fragment, &roughness);
/* Setup the fresnel term */
res = ssf_fresnel_create(mtl->dev->allocator, &ssf_fresnel_constant, &fresnel);
@@ -207,15 +203,13 @@ error:
}
static res_T
-thin_dielectric_shade
+setup_thin_dielectric_bsdf
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
+ const struct ssol_surface_fragment* fragment,
const double wavelength, /* In nanometer */
struct ssf_bsdf* bsdf)
{
struct ssf_bxdf* bxdf = NULL;
- const struct ssol_thin_dielectric_shader* shader;
- double N[3];
double thickness;
double absorptivity;
double eta_i;
@@ -223,12 +217,8 @@ thin_dielectric_shade
res_T res = RES_OK;
ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_THIN_DIELECTRIC);
ASSERT(bsdf);
+ (void)wavelength, (void)fragment;
- shader = &mtl->data.thin_dielectric.shader;
-
- /* Fetch material attribs */
- shader->normal(mtl->dev, mtl->buf, wavelength, fragment->pos,
- fragment->Ng, fragment->Ns, fragment->uv, fragment->dir, N);
eta_i = mtl->out_medium.refractive_index;
eta_t = mtl->data.thin_dielectric.slab_medium.refractive_index;
absorptivity = mtl->data.thin_dielectric.slab_medium.absorptivity;
@@ -253,39 +243,6 @@ error:
goto exit;
}
-static INLINE res_T
-shade
- (const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
- const double wavelength, /* In nanometer */
- const int rendering, /* Is material used for rendering */
- const struct ssol_medium* medium,
- struct ssf_bsdf* bsdf)
-{
- res_T res = RES_OK;
- ASSERT(mtl);
-
- /* Specific material shading */
- switch(mtl->type) {
- case SSOL_MATERIAL_DIELECTRIC:
- res = dielectric_shade
- (mtl, fragment, wavelength, medium, bsdf);
- break;
- case SSOL_MATERIAL_MATTE:
- res = matte_shade(mtl, fragment, wavelength, bsdf);
- break;
- case SSOL_MATERIAL_MIRROR:
- res = mirror_shade(mtl, fragment, wavelength, rendering, bsdf);
- break;
- case SSOL_MATERIAL_THIN_DIELECTRIC:
- res = thin_dielectric_shade(mtl, fragment, wavelength, bsdf);
- break;
- case SSOL_MATERIAL_VIRTUAL: /* Nothing to shade */ break;
- default: FATAL("Unreachable code\n"); break;
- }
- return res;
-}
-
static INLINE int
check_shader_dielectric(const struct ssol_dielectric_shader* shader)
{
@@ -366,6 +323,7 @@ ssol_material_create
material->type = type;
material->in_medium = SSOL_MEDIUM_VACUUM;
material->out_medium = SSOL_MEDIUM_VACUUM;
+ material->normal = shade_normal_default;
exit:
if (out_material) *out_material = material;
@@ -461,9 +419,10 @@ ssol_dielectric_setup
|| !check_medium(outside_medium)
|| !check_medium(inside_medium))
return RES_BAD_ARG;
- material->data.dielectric = *shader;
+ material->data.dielectric.dummy = 1;
material->out_medium = *outside_medium;
material->in_medium = *inside_medium;
+ material->normal = shader->normal;
return RES_OK;
}
@@ -475,7 +434,9 @@ ssol_mirror_setup
|| material->type != SSOL_MATERIAL_MIRROR
|| !check_shader_mirror(shader))
return RES_BAD_ARG;
- material->data.mirror = *shader;
+ material->normal = shader->normal;
+ material->data.mirror.reflectivity = shader->reflectivity;
+ material->data.mirror.roughness = shader->roughness;
return RES_OK;
}
@@ -487,7 +448,8 @@ ssol_matte_setup
|| material->type != SSOL_MATERIAL_MATTE
|| !check_shader_matte(shader))
return RES_BAD_ARG;
- material->data.matte = *shader;
+ material->normal = shader->normal;
+ material->data.matte.reflectivity = shader->reflectivity;
return RES_OK;
}
@@ -506,11 +468,11 @@ ssol_thin_dielectric_setup
|| !check_medium(slab_medium)
|| thickness < 0)
return RES_BAD_ARG;
- material->data.thin_dielectric.shader = *shader;
material->data.thin_dielectric.slab_medium = *slab_medium;
material->data.thin_dielectric.thickness = thickness;
material->out_medium = *outside_medium;
material->in_medium = *outside_medium;
+ material->normal = shader->normal;
return RES_OK;
}
@@ -526,7 +488,7 @@ ssol_material_create_virtual
******************************************************************************/
void
surface_fragment_setup
- (struct surface_fragment* fragment,
+ (struct ssol_surface_fragment* fragment,
const double pos[3],
const double dir[3],
const double normal[3],
@@ -535,31 +497,68 @@ surface_fragment_setup
{
struct s3d_attrib attr;
char has_texcoord, has_normal;
+ struct s3d_attrib uvs[3];
+ struct s3d_attrib P[3];
+ double duv1[2], duv2[2];
+ double dP1[3], dP2[3];
+ double det;
ASSERT(fragment && pos && dir && primitive && uv);
/* Assume that the submitted normal look forward the incoming dir */
ASSERT(d3_dot(normal, dir) <= 0);
- /* Setup the incoming direction */
- d3_set(fragment->dir, dir);
-
- /* Setup the surface position */
- d3_set(fragment->pos, pos);
+ d3_set(fragment->dir, dir); /* Setup the incoming direction */
+ d3_set(fragment->P, pos); /* Setup the surface position */
+ d3_normalize(fragment->Ng, normal); /* Normalize the geometry normal */
- /* Normalize the geometry normal */
- d3_set(fragment->Ng, normal);
- d3_normalize(fragment->Ng, fragment->Ng);
+ /* Retrieve the position of the triangle vertices */
+ S3D(triangle_get_vertex_attrib(primitive, 0, S3D_POSITION, &P[0]));
+ S3D(triangle_get_vertex_attrib(primitive, 1, S3D_POSITION, &P[1]));
+ S3D(triangle_get_vertex_attrib(primitive, 2, S3D_POSITION, &P[2]));
/* Retrieve the tex coord */
S3D(primitive_has_attrib(primitive, SSOL_TO_S3D_TEXCOORD, &has_texcoord));
if (!has_texcoord) {
d2_set_f2(fragment->uv, uv);
+ uvs[0].type = uvs[1].type = uvs[2].type = S3D_FLOAT2;
+ uvs[0].usage = uvs[1].usage = uvs[2].usage = SSOL_TO_S3D_TEXCOORD;
+ f2(uvs[0].value, 1, 0);
+ f2(uvs[1].value, 0, 1);
+ f2(uvs[2].value, 0, 0);
} else {
S3D(primitive_get_attrib(primitive, SSOL_TO_S3D_TEXCOORD, uv, &attr));
+ S3D(triangle_get_vertex_attrib(primitive, 0, SSOL_TO_S3D_TEXCOORD, &uvs[0]));
+ S3D(triangle_get_vertex_attrib(primitive, 1, SSOL_TO_S3D_TEXCOORD, &uvs[1]));
+ S3D(triangle_get_vertex_attrib(primitive, 2, SSOL_TO_S3D_TEXCOORD, &uvs[2]));
ASSERT(attr.type == S3D_FLOAT2);
d2_set_f2(fragment->uv, attr.value);
}
+ /* Compute the partial derivatives. */
+ duv1[0] = uvs[1].value[0] - uvs[0].value[0];
+ duv1[1] = uvs[1].value[1] - uvs[0].value[1];
+ duv2[0] = uvs[2].value[0] - uvs[0].value[0];
+ duv2[1] = uvs[2].value[1] - uvs[0].value[1];
+ dP1[0] = P[1].value[0] - P[0].value[0];
+ dP1[1] = P[1].value[1] - P[0].value[1];
+ dP1[2] = P[1].value[2] - P[0].value[2];
+ dP2[0] = P[2].value[0] - P[0].value[0];
+ dP2[1] = P[2].value[1] - P[0].value[1];
+ dP2[2] = P[2].value[2] - P[0].value[2];
+ det = duv1[0]*duv2[1] - duv1[1]*duv2[0];
+ if(det == 0) { /* Handle zero determinant */
+ double basis[9];
+ d33_basis(basis, fragment->Ng);
+ d3_set(fragment->dPdu, basis + 0);
+ d3_set(fragment->dPdv, basis + 3);
+ } else {
+ double a[3], b[3];
+ d3_sub(fragment->dPdu, d3_muld(a, dP1, duv2[1]), d3_muld(b, dP2, duv1[1]));
+ d3_sub(fragment->dPdv, d3_muld(a, dP2, duv1[0]), d3_muld(b, dP1, duv2[0]));
+ d3_divd(fragment->dPdu, fragment->dPdu, det);
+ d3_divd(fragment->dPdv, fragment->dPdv, det);
+ }
+
/* Retrieve and normalize the shading normal in world space */
S3D(primitive_has_attrib(primitive, SSOL_TO_S3D_NORMAL, &has_normal));
if (!has_normal) {
@@ -593,28 +592,50 @@ surface_fragment_setup
}
}
-res_T
-material_shade
+void
+material_shade_normal
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
- const double wavelength, /* In nanometer */
- const struct ssol_medium* medium,
- struct ssf_bsdf* bsdf)
+ const struct ssol_surface_fragment* frag,
+ const double wavelength,
+ double N[3])
{
- return shade(mtl, fragment, wavelength, 0, medium, bsdf);
+ ASSERT(mtl && frag && N);
+ mtl->normal(mtl->dev, mtl->buf, wavelength, frag, N);
}
res_T
-material_shade_rendering
+material_setup_bsdf
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
+ const struct ssol_surface_fragment* fragment,
const double wavelength, /* In nanometer */
const struct ssol_medium* medium,
+ const int rendering, /* Is BSDF used for rendering */
struct ssf_bsdf* bsdf)
{
- return shade(mtl, fragment, wavelength, 1, medium, bsdf);
+ res_T res = RES_OK;
+ ASSERT(mtl);
+
+ switch(mtl->type) {
+ case SSOL_MATERIAL_DIELECTRIC:
+ res = setup_dielectric_bsdf
+ (mtl, fragment, wavelength, medium, bsdf);
+ break;
+ case SSOL_MATERIAL_MATTE:
+ res = setup_matte_bsdf(mtl, fragment, wavelength, bsdf);
+ break;
+ case SSOL_MATERIAL_MIRROR:
+ res = setup_mirror_bsdf(mtl, fragment, wavelength, rendering, bsdf);
+ break;
+ case SSOL_MATERIAL_THIN_DIELECTRIC:
+ res = setup_thin_dielectric_bsdf(mtl, fragment, wavelength, bsdf);
+ break;
+ case SSOL_MATERIAL_VIRTUAL: /* Nothing to shade */ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ return res;
}
+
res_T
material_get_next_medium
(const struct ssol_material* mtl,
diff --git a/src/ssol_material_c.h b/src/ssol_material_c.h
@@ -27,19 +27,20 @@ struct ssol_device;
( ((A)->refractive_index == (B)->refractive_index) \
&& ((A)->absorptivity == (B)->absorptivity))
-struct surface_fragment {
- double dir[3]; /* World space incoming direction */
- double pos[3]; /* World space position */
- double Ng[3]; /* Normalized world space primitive normal */
- double Ns[3]; /* Normalized world space shading normal */
- double uv[2]; /* Texture coordinates */
+struct dielectric {
+ int dummy;
+};
+
+struct matte {
+ ssol_shader_getter_T reflectivity;
+};
+
+struct mirror {
+ ssol_shader_getter_T reflectivity;
+ ssol_shader_getter_T roughness;
};
-#define SURFACE_FRAGMENT_NULL__ {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0}}
-static const struct surface_fragment SURFACE_FRAGMENT_NULL =
- SURFACE_FRAGMENT_NULL__;
struct thin_dielectric {
- struct ssol_thin_dielectric_shader shader;
struct ssol_medium slab_medium;
double thickness;
};
@@ -47,10 +48,12 @@ struct thin_dielectric {
struct ssol_material {
enum ssol_material_type type;
+ ssol_shader_getter_T normal;
+
union {
- struct ssol_dielectric_shader dielectric;
- struct ssol_matte_shader matte;
- struct ssol_mirror_shader mirror;
+ struct dielectric dielectric;
+ struct matte matte;
+ struct mirror mirror;
struct thin_dielectric thin_dielectric;
} data;
@@ -64,28 +67,27 @@ struct ssol_material {
extern LOCAL_SYM void
surface_fragment_setup
- (struct surface_fragment* fragment,
+ (struct ssol_surface_fragment* fragment,
const double pos[3],
const double dir[3],
const double normal[3],
const struct s3d_primitive* primitive,
const float uv[2]);
-extern LOCAL_SYM res_T
-material_shade
+extern LOCAL_SYM void
+material_shade_normal
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
- const double wavelength, /* In nanometer */
- const struct ssol_medium* medium, /* Current medium */
- struct ssf_bsdf* bsdf); /* Bidirectional Scattering Distribution Function */
+ const struct ssol_surface_fragment* fragment,
+ const double wavelength,
+ double N[3]);
-/* Material shading for rendering purposes */
extern LOCAL_SYM res_T
-material_shade_rendering
+material_setup_bsdf
(const struct ssol_material* mtl,
- const struct surface_fragment* fragment,
+ const struct ssol_surface_fragment* fragment,
const double wavelength, /* In nanometer */
- const struct ssol_medium* medium,
+ const struct ssol_medium* medium, /* Current medium */
+ const int rendering, /* Is material used for rendering purposes */
struct ssf_bsdf* bsdf); /* Bidirectional Scattering Distribution Function */
extern LOCAL_SYM res_T
@@ -95,3 +97,4 @@ material_get_next_medium
struct ssol_medium* next_medium);
#endif /* SSOL_MATERIAL_C_H */
+
diff --git a/src/ssol_param_buffer.c b/src/ssol_param_buffer.c
@@ -22,15 +22,19 @@
#define DEFAULT_ALIGNMENT 64
struct param {
- size_t size; /* In Bytes */
- size_t offset; /* In Bytes */
+ void* mem;
+ void (*release)(void*);
};
+#define DARRAY_NAME param
+#define DARRAY_DATA struct param
+#include <rsys/dynamic_array.h>
+
struct ssol_param_buffer {
char* pool;
size_t capacity;
size_t size;
-
+ struct darray_param params;
ref_T ref;
struct ssol_device* dev;
};
@@ -45,8 +49,10 @@ param_buffer_release(ref_T* ref)
struct ssol_device* dev;
ASSERT(ref);
buf = CONTAINER_OF(ref, struct ssol_param_buffer, ref);
+ SSOL(param_buffer_clear(buf));
dev = buf->dev;
if(buf->pool) MEM_RM(dev->allocator, buf->pool);
+ darray_param_release(&buf->params);
MEM_RM(dev->allocator, buf);
SSOL(device_ref_put(dev));
}
@@ -78,6 +84,8 @@ ssol_param_buffer_create
ref_init(&buf->ref);
buf->capacity = capacity;
buf->size = 0;
+ darray_param_init(dev->allocator, &buf->params);
+
buf->pool = MEM_ALLOC_ALIGNED(dev->allocator, capacity, DEFAULT_ALIGNMENT);
if(!buf->pool) {
res = RES_MEM_ERR;
@@ -115,25 +123,32 @@ void*
ssol_param_buffer_allocate
(struct ssol_param_buffer* buf,
const size_t size, /* In Bytes */
- const size_t align) /* Must be a power of 2 in [1, 64] */
+ const size_t align, /* Must be a power of 2 in [1, 64] */
+ void (*release)(void*)) /* May be NULL */
{
+ struct param param = { NULL, NULL };
size_t offset;
- void* mem = NULL;
+ res_T res = RES_OK;
if(!buf || !size || !IS_POW2(align) || align > DEFAULT_ALIGNMENT)
goto error;
offset = ALIGN_SIZE(buf->size, align);
if(offset + size > buf->capacity) goto error;
-
- mem = buf->pool + offset;
- ASSERT(IS_ALIGNED(mem, align));
+
+ param.mem = buf->pool + offset;
+ param.release = release;
+ ASSERT(IS_ALIGNED(param.mem, align));
+
+ res = darray_param_push_back(&buf->params, ¶m);
+ if(res != RES_OK) goto error;
+
buf->size = offset + size;
exit:
- return mem;
+ return param.mem;
error:
- mem = NULL;
+ param.mem = NULL;
goto exit;
}
@@ -147,7 +162,15 @@ ssol_param_buffer_get(struct ssol_param_buffer* buf)
res_T
ssol_param_buffer_clear(struct ssol_param_buffer* buf)
{
+ size_t i;
if(!buf) return RES_BAD_ARG;
+
+ /* Release the parameter */
+ FOR_EACH(i, 0, darray_param_size_get(&buf->params)) {
+ struct param* param = darray_param_data_get(&buf->params)+i;
+ if(param->release) param->release(param->mem);
+ }
+ darray_param_clear(&buf->params);
buf->size = 0;
return RES_OK;
}
diff --git a/src/ssol_shape.c b/src/ssol_shape.c
@@ -53,6 +53,8 @@ struct quadric_mesh_context {
const union private_data* data;
union private_type private_type;
const double* transform; /* 3x4 column major matrix */
+ double lower[2];
+ double upper[2];
};
struct get_ctx {
@@ -185,6 +187,20 @@ mesh_get_pos(const size_t ivert, double pos[2], void* ctx)
}
static void
+quadric_mesh_get_uv(const unsigned ivert, float uv[2], void* ctx)
+{
+ const size_t i = ivert*2/*#coords per vertex*/;
+ const struct quadric_mesh_context* msh = ctx;
+ double tmp[2];
+ ASSERT(uv && ctx);
+ tmp[0] = (msh->coords[i+0] - msh->lower[0]) / (msh->upper[0] - msh->lower[0]);
+ tmp[1] = (msh->coords[i+1] - msh->lower[1]) / (msh->upper[1] - msh->lower[1]);
+
+ uv[0] = (float)tmp[0];
+ uv[1] = (float)tmp[1];
+}
+
+static void
quadric_mesh_get_ids(const unsigned itri, unsigned ids[3], void* ctx)
{
const size_t i = itri*3/*#ids per triangle*/;
@@ -653,57 +669,66 @@ quadric_setup_s3d_shape_rt
(const struct ssol_shape* shape,
const struct darray_double* coords,
const struct darray_size_t* ids,
+ const double lower[2],
+ const double upper[2],
struct s3d_shape* s3dshape,
double* rt_area)
{
struct quadric_mesh_context ctx;
- struct s3d_vertex_data vdata;
+ struct s3d_vertex_data vdata[2];
unsigned nverts;
unsigned ntris;
res_T res;
- ASSERT(shape && coords && ids && s3dshape && rt_area);
+ ASSERT(shape && coords && ids && lower && upper && s3dshape && rt_area);
ASSERT(darray_double_size_get(coords)%2 == 0);
ASSERT(darray_size_t_size_get(ids)%3 == 0);
ASSERT(darray_double_size_get(coords)/2 <= UINT_MAX);
ASSERT(darray_size_t_size_get(ids)/3 <= UINT_MAX);
+ ASSERT(!aabb_is_degenerated(lower, upper));
nverts = (unsigned)darray_double_size_get(coords) / 2/*#coords per vertex*/;
ntris = (unsigned)darray_size_t_size_get(ids) / 3/*#ids per triangle*/;
ctx.coords = darray_double_cdata_get(coords);
ctx.ids = darray_size_t_cdata_get(ids);
ctx.transform = shape->transform;
+ d2_set(ctx.lower, lower);
+ d2_set(ctx.upper, upper);
+
+ vdata[0].usage = S3D_POSITION;
+ vdata[0].type = S3D_FLOAT3;
+ vdata[0].get = NULL;
+
+ vdata[1].usage = SSOL_TO_S3D_TEXCOORD;
+ vdata[1].type = S3D_FLOAT2;
+ vdata[1].get = quadric_mesh_get_uv;
- vdata.usage = S3D_POSITION;
- vdata.type = S3D_FLOAT3;
- vdata.get = NULL;
ctx.data = &shape->private_data;
ctx.private_type = shape->private_type;
switch (shape->private_type.quadric) {
case SSOL_QUADRIC_PARABOL:
- vdata.get = quadric_mesh_parabol_get_pos;
+ vdata[0].get = quadric_mesh_parabol_get_pos;
break;
case SSOL_QUADRIC_HYPERBOL:
- vdata.get = quadric_mesh_hyperbol_get_pos;
+ vdata[0].get = quadric_mesh_hyperbol_get_pos;
break;
case SSOL_QUADRIC_PARABOLIC_CYLINDER:
- vdata.get = quadric_mesh_parabolic_cylinder_get_pos;
+ vdata[0].get = quadric_mesh_parabolic_cylinder_get_pos;
break;
case SSOL_QUADRIC_PLANE:
- vdata.get = quadric_mesh_plane_get_pos;
+ vdata[0].get = quadric_mesh_plane_get_pos;
break;
case SSOL_QUADRIC_HEMISPHERE:
- vdata.get = quadric_mesh_hemisphere_get_pos;
+ vdata[0].get = quadric_mesh_hemisphere_get_pos;
break;
default: FATAL("Unreachable code.\n"); break;
}
res = s3d_mesh_setup_indexed_vertices
- (s3dshape, ntris, quadric_mesh_get_ids, nverts, &vdata, 1, &ctx);
+ (s3dshape, ntris, quadric_mesh_get_ids, nverts, vdata, 2, &ctx);
if(res != RES_OK) return res;
- ASSERT(vdata.get);
*rt_area = mesh_compute_area
- (ntris, quadric_mesh_get_ids, nverts, vdata.get, &ctx);
+ (ntris, quadric_mesh_get_ids, nverts, vdata[0].get, &ctx);
return RES_OK;
}
@@ -714,31 +739,41 @@ quadric_setup_s3d_shape_samp
(const struct ssol_quadric* quadric,
const struct darray_double* coords,
const struct darray_size_t* ids,
+ const double lower[2],
+ const double upper[2],
struct s3d_shape* shape,
double *samp_area)
{
struct quadric_mesh_context ctx;
- struct s3d_vertex_data vdata;
+ struct s3d_vertex_data vdata[2];
unsigned nverts;
unsigned ntris;
res_T res;
- ASSERT(coords && ids && shape);
+ ASSERT(coords && ids && shape && ids && lower && samp_area);
ASSERT(darray_double_size_get(coords)%2 == 0);
ASSERT(darray_size_t_size_get(ids)%3 == 0);
ASSERT(darray_double_size_get(coords)/2 <= UINT_MAX);
ASSERT(darray_size_t_size_get(ids)/3 <= UINT_MAX);
+ ASSERT(!aabb_is_degenerated(lower, upper));
nverts = (unsigned)darray_double_size_get(coords) / 2/*#coords per vertex*/;
ntris = (unsigned)darray_size_t_size_get(ids) / 3/*#ids per triangle*/;
ctx.coords = darray_double_cdata_get(coords);
ctx.ids = darray_size_t_cdata_get(ids);
ctx.transform = quadric->transform;
+ d2_set(ctx.lower, lower);
+ d2_set(ctx.upper, upper);
+
+ vdata[0].usage = S3D_POSITION;
+ vdata[0].type = S3D_FLOAT3;
+ vdata[0].get = quadric_mesh_plane_get_pos;
+
+ vdata[1].usage = SSOL_TO_S3D_TEXCOORD;
+ vdata[1].type = S3D_FLOAT2;
+ vdata[1].get = quadric_mesh_get_uv;
- vdata.usage = S3D_POSITION;
- vdata.type = S3D_FLOAT3;
- vdata.get = quadric_mesh_plane_get_pos;
res = s3d_mesh_setup_indexed_vertices
- (shape, ntris, quadric_mesh_get_ids, nverts, &vdata, 1, &ctx);
+ (shape, ntris, quadric_mesh_get_ids, nverts, vdata, 2, &ctx);
if(res != RES_OK) return res;
*samp_area = mesh_compute_area
(ntris, quadric_mesh_get_ids, nverts, quadric_mesh_plane_get_pos, &ctx);
@@ -1357,7 +1392,7 @@ shape_trace_ray
double N_local[3];
double dst; /* Hit distance */
int valid;
- ASSERT(shape && transform && org && shape);
+ ASSERT(shape && transform && org && N_shape);
/* Compute world<->quadric space transformations */
d33_muld33(R, transform, shape->transform);
@@ -1529,6 +1564,8 @@ ssol_punched_surface_setup
if(psurf->quadric->type == SSOL_QUADRIC_HEMISPHERE) {
carvings_compute_radius(psurf->carvings, psurf->nb_carvings, &radius);
radius = MMIN(radius, psurf->quadric->data.hemisphere.radius);
+ lower[0] = lower[1] = -radius;
+ upper[0] = upper[1] = +radius;
} else {
carvings_compute_aabb(psurf->carvings, psurf->nb_carvings, lower, upper);
if(aabb_is_degenerated(lower, upper)) {
@@ -1571,13 +1608,13 @@ ssol_punched_surface_setup
}
/* Setup the Star-3D shape to ray-trace */
- res = quadric_setup_s3d_shape_rt
- (shape, &coords, &ids, shape->shape_rt, &shape->shape_rt_area);
+ res = quadric_setup_s3d_shape_rt(shape, &coords, &ids, lower, upper,
+ shape->shape_rt, &shape->shape_rt_area);
if(res != RES_OK) goto error;
/* Setup the Star-3D shape to sample */
- res = quadric_setup_s3d_shape_samp
- (psurf->quadric, &coords, &ids, shape->shape_samp, &shape->shape_samp_area);
+ res = quadric_setup_s3d_shape_samp(psurf->quadric, &coords, &ids, lower,
+ upper, shape->shape_samp, &shape->shape_samp_area);
if(res != RES_OK) goto error;
exit:
diff --git a/src/ssol_solver.c b/src/ssol_solver.c
@@ -191,6 +191,12 @@ struct point {
}
static const struct point POINT_NULL = POINT_NULL__;
+static FINLINE struct ssol_material*
+point_get_material(const struct point* pt)
+{
+ return pt->side == SSOL_FRONT ? pt->sshape->mtl_front : pt->sshape->mtl_back;
+}
+
static res_T
point_init
(struct point* pt,
@@ -204,9 +210,12 @@ point_init
struct ssp_rng* rng,
int* is_lit)
{
+ struct ssol_surface_fragment frag;
struct s3d_attrib attr;
struct s3d_hit hit;
struct ray_data ray_data = RAY_DATA_NULL;
+ struct ssol_material* mtl;
+ double N[3], Np[3];
float dir[3], pos[3], range[2] = { 0, FLT_MAX };
size_t id;
res_T res = RES_OK;
@@ -240,39 +249,50 @@ point_init
/* Sample a sun direction */
ranst_sun_dir_get(ran_sun_dir, rng, pt->dir);
- /* Initialise the Monte Carlo weight */
if(pt->sshape->shape->type != SHAPE_PUNCHED) {
- double surface_sun_cos = fabs(d3_dot(pt->N, pt->dir));
- pt->weight = scn->sun->dni * sampled_area_proxy * surface_sun_cos;
- pt->cos_factor = surface_sun_cos;
+ d3_set(N, pt->N);
} else {
- double cos_ratio, surface_proxy_cos, surface_sun_cos, tmp_n[3];
/* For punched surface, retrieve the sampled position and normal onto the
* quadric surface */
punched_shape_project_point
- (pt->sshape->shape, pt->inst->transform, pt->pos, pt->pos, tmp_n);
- surface_proxy_cos = fabs(d3_dot(pt->N, tmp_n));
- surface_sun_cos = fabs(d3_dot(tmp_n, pt->dir));
+ (pt->sshape->shape, pt->inst->transform, pt->pos, pt->pos, N);
+ }
+
+ /* Define the primitive side on which the point lies */
+ if(d3_dot(N, pt->dir) < 0) {
+ pt->side = SSOL_FRONT;
+ } else {
+ pt->side = SSOL_BACK;
+ d3_minus(N, N); /* Force the normal to look forward dir */
+ }
+
+ /* Perturb the normal */
+ surface_fragment_setup(&frag, pt->pos, pt->dir, N, &pt->prim, pt->uv);
+ mtl = point_get_material(pt);
+ material_shade_normal(mtl, &frag, pt->wl, Np);
+
+ /* Initialise the Monte Carlo weight */
+ if(pt->sshape->shape->type != SHAPE_PUNCHED) {
+ double surface_sun_cos = fabs(d3_dot(Np, pt->dir));
+ pt->weight = scn->sun->dni * sampled_area_proxy * surface_sun_cos;
+ pt->cos_factor = surface_sun_cos;
+ } else {
+ double cos_ratio, surface_proxy_cos, surface_sun_cos;
+ surface_proxy_cos = fabs(d3_dot(pt->N, Np));
+ surface_sun_cos = fabs(d3_dot(Np, pt->dir));
cos_ratio = surface_sun_cos / surface_proxy_cos;
- d3_set(pt->N, tmp_n);
pt->weight = scn->sun->dni * sampled_area_proxy * cos_ratio;
pt->cos_factor = surface_sun_cos;
}
+ d3_set(pt->N, N);
pt->absorptivity_loss = pt->reflectivity_loss = 0;
+ ASSERT(d3_dot(pt->N, pt->dir) <= 0);
/* Store sampled entity related weights */
res = get_mc_sampled(sampled, pt->inst, &pt->mc_samp);
if(res != RES_OK) goto error;
pt->mc_samp->nb_samples++;
- /* Define the primitive side on which the point lies */
- if(d3_dot(pt->N, pt->dir) < 0) {
- pt->side = SSOL_FRONT;
- } else {
- pt->side = SSOL_BACK;
- d3_minus(pt->N, pt->N); /* Force the normal to look forward dir */
- }
-
/* Initialise the ray data to avoid self intersection */
ray_data.scn = scn;
ray_data.prim_from = pt->prim;
@@ -345,12 +365,6 @@ point_update_from_hit
}
}
-static FINLINE struct ssol_material*
-point_get_material(const struct point* pt)
-{
- return pt->side == SSOL_FRONT ? pt->sshape->mtl_front : pt->sshape->mtl_back;
-}
-
static FINLINE res_T
point_shade
(struct point* pt,
@@ -360,9 +374,9 @@ point_shade
double dir[3])
{
struct ssol_material* mtl;
- struct surface_fragment frag;
+ struct ssol_surface_fragment frag;
double r = 1;
- double wi[3], pdf;
+ double wi[3], N[3], pdf;
int type;
res_T res;
ASSERT(pt && bsdf && medium && rng && dir);
@@ -383,18 +397,30 @@ point_shade
/* Shade the surface fragment */
mtl = point_get_material(pt);
SSF(bsdf_clear(bsdf));
- res = material_shade(mtl, &frag, pt->wl, medium, bsdf);
+ res = material_setup_bsdf(mtl, &frag, pt->wl, medium, 0, bsdf);
if(res != RES_OK) return res;
+ /* Perturbe the normal */
+ material_shade_normal(mtl, &frag, pt->wl, N);
+
/* By convention, Star-SF assumes that incoming and reflected
* directions point outward the surface => negate incoming dir */
d3_minus(wi, pt->dir);
- if(d3_dot(wi, frag.Ns) <= 0) {
+ if(d3_dot(wi, N) <= 0) {
r = 0;
} else {
- r = ssf_bsdf_sample(bsdf, rng, wi, frag.Ns, dir, &type, &pdf);
+ double cos_dir_Ng;
+ r = ssf_bsdf_sample(bsdf, rng, wi, N, dir, &type, &pdf);
ASSERT(0 <= r && r <= 1);
+
+ /* Due to the perturbed normal, the sampled direction may point in the
+ * wrong direction wrt the sampled BSDF component. */
+ cos_dir_Ng = d3_dot(frag.Ng, dir);
+ if((cos_dir_Ng > 0 && (type & SSF_TRANSMISSION))
+ || (cos_dir_Ng < 0 && (type & SSF_REFLECTION))) {
+ r = 0;
+ }
}
pt->incoming_weight = pt->weight;
pt->absorptivity_loss_before = pt->absorptivity_loss;
@@ -646,7 +672,7 @@ update_mc
struct mc_receiver_1side* mc_samp_x_rcv1 = NULL;
res_T res = RES_OK;
ASSERT(pt && thread_ctx && point_is_receiver(pt));
-
+
res = point_dump(pt, irealisation, ibounce, output);
if(res != RES_OK) goto error;
@@ -735,6 +761,7 @@ trace_radiative_path
float org[3], dir[3], range[2] = { 0, FLT_MAX };
size_t depth = 0;
int is_lit = 0;
+ int hit_a_receiver = 0;
res_T res = RES_OK;
ASSERT(thread_ctx && scn && view_samp && view_rt && ran_sun_dir && ran_sun_wl);
@@ -766,7 +793,7 @@ trace_radiative_path
res = path_add_vertex(&path, pt.pos, pt.weight);
if(res != RES_OK) goto error;
}
-
+
#define ACCUM_WEIGHT(Res, W) { \
Res.weight += (W); \
Res.sqr_weight += (W)*(W); \
@@ -794,13 +821,14 @@ trace_radiative_path
if(mtl->type == SSOL_MATERIAL_VIRTUAL) {
point_hit_virtual(&pt);
} else {
- /* Modulate the point weight wrt to its scattering functions and
- * generate an outgoing direction */
+ /* Modulate the point weight wrt its scattering functions and generate
+ * an outgoing direction */
res = point_shade(&pt, thread_ctx->bsdf, &medium, thread_ctx->rng, pt.dir);
if(res != RES_OK) goto error;
}
if(point_is_receiver(&pt)) {
+ hit_a_receiver = 1;
res = update_mc(&pt, path_id, depth, thread_ctx, output);
if(res != RES_OK) goto error;
}
@@ -867,7 +895,7 @@ trace_radiative_path
#undef ACCUM_WEIGHT
if(tracker) {
- path.type = pt.absorbed_irradiance ? SSOL_PATH_SUCCESS : SSOL_PATH_MISSING;
+ path.type = hit_a_receiver ? SSOL_PATH_SUCCESS : SSOL_PATH_MISSING;
}
}
diff --git a/src/ssol_spectrum.c b/src/ssol_spectrum.c
@@ -84,8 +84,7 @@ spectrum_includes
double
spectrum_interpolate
- (const struct ssol_spectrum* spectrum,
- const double wavelength)
+ (const struct ssol_spectrum* spectrum, const double wavelength)
{
const double* wls;
const double* ints;
@@ -193,7 +192,7 @@ ssol_spectrum_setup
intensities = darray_double_data_get(&spectrum->intensities);
FOR_EACH(i, 0, nwlens) {
get(i, wavelengths + i, intensities + i, ctx);
- if(*(wavelengths + i) <= current_wl || *(intensities + i) < 0) {
+ if(wavelengths[i] <= current_wl || intensities[i] < 0) {
res = RES_BAD_ARG;
goto error;
}
diff --git a/src/ssol_sun.c b/src/ssol_sun.c
@@ -39,7 +39,7 @@ sun_release(ref_T* ref)
ASSERT(ref);
dev = sun->dev;
ASSERT(dev && dev->allocator);
- if (sun->spectrum) SSOL(spectrum_ref_put(sun->spectrum));
+ if(sun->spectrum) SSOL(spectrum_ref_put(sun->spectrum));
MEM_RM(dev->allocator, sun);
SSOL(device_ref_put(dev));
}
@@ -50,13 +50,13 @@ sun_create
{
struct ssol_sun* sun = NULL;
res_T res = RES_OK;
- if (!dev || !out_sun || type >= SUN_TYPES_COUNT__) {
+ if(!dev || !out_sun || type >= SUN_TYPES_COUNT__) {
return RES_BAD_ARG;
}
sun = (struct ssol_sun*)MEM_CALLOC
(dev->allocator, 1, sizeof(struct ssol_sun));
- if (!sun) {
+ if(!sun) {
res = RES_MEM_ERR;
goto error;
}
@@ -67,10 +67,10 @@ sun_create
ref_init(&sun->ref);
exit:
- if (out_sun) *out_sun = sun;
+ if(out_sun) *out_sun = sun;
return res;
error:
- if (sun) {
+ if(sun) {
SSOL(sun_ref_put(sun));
sun = NULL;
}
@@ -102,7 +102,7 @@ ssol_sun_create_buie
res_T
ssol_sun_ref_get(struct ssol_sun* sun)
{
- if (!sun)
+ if(!sun)
return RES_BAD_ARG;
ref_get(&sun->ref);
return RES_OK;
@@ -111,7 +111,7 @@ ssol_sun_ref_get(struct ssol_sun* sun)
res_T
ssol_sun_ref_put(struct ssol_sun* sun)
{
- if (!sun)
+ if(!sun)
return RES_BAD_ARG;
ref_put(&sun->ref, sun_release);
return RES_OK;
@@ -120,9 +120,9 @@ ssol_sun_ref_put(struct ssol_sun* sun)
res_T
ssol_sun_set_direction(struct ssol_sun* sun, const double direction[3])
{
- if (!sun || !direction)
+ if(!sun || !direction)
return RES_BAD_ARG;
- if (0 == d3_normalize(sun->direction, direction))
+ if(0 == d3_normalize(sun->direction, direction))
/* zero vector */
return RES_BAD_ARG;
return RES_OK;
@@ -131,7 +131,7 @@ ssol_sun_set_direction(struct ssol_sun* sun, const double direction[3])
res_T
ssol_sun_get_direction(const struct ssol_sun* sun, double direction[3])
{
- if (!sun || !direction)
+ if(!sun || !direction)
return RES_BAD_ARG;
d3_set(direction, sun->direction);
return RES_OK;
@@ -140,7 +140,7 @@ ssol_sun_get_direction(const struct ssol_sun* sun, double direction[3])
res_T
ssol_sun_set_dni(struct ssol_sun* sun, const double dni)
{
- if (!sun || dni <= 0)
+ if(!sun || dni <= 0)
return RES_BAD_ARG;
sun->dni = dni;
return RES_OK;
@@ -149,7 +149,7 @@ ssol_sun_set_dni(struct ssol_sun* sun, const double dni)
res_T
ssol_sun_get_dni(const struct ssol_sun* sun, double* dni)
{
- if (!sun || !dni)
+ if(!sun || !dni)
return RES_BAD_ARG;
*dni = sun->dni;
return RES_OK;
@@ -158,11 +158,11 @@ ssol_sun_get_dni(const struct ssol_sun* sun, double* dni)
res_T
ssol_sun_set_spectrum(struct ssol_sun* sun, struct ssol_spectrum* spectrum)
{
- if (!sun || !spectrum)
+ if(!sun || !spectrum)
return RES_BAD_ARG;
- if (spectrum == sun->spectrum) /* no change */
+ if(spectrum == sun->spectrum) /* no change */
return RES_OK;
- if (sun->spectrum)
+ if(sun->spectrum)
SSOL(spectrum_ref_put(sun->spectrum));
SSOL(spectrum_ref_get(spectrum));
sun->spectrum = spectrum;
@@ -170,9 +170,7 @@ ssol_sun_set_spectrum(struct ssol_sun* sun, struct ssol_spectrum* spectrum)
}
res_T
-ssol_sun_set_pillbox_aperture
- (struct ssol_sun* sun,
- const double angle)
+ssol_sun_set_pillbox_aperture(struct ssol_sun* sun, const double angle)
{
if(!sun
|| angle <= 0
@@ -259,4 +257,3 @@ error:
goto exit;
}
-
diff --git a/src/test_ssol_draw.c b/src/test_ssol_draw.c
@@ -183,11 +183,13 @@ main(int argc, char** argv)
struct ssol_camera* cam;
struct ssol_scene* scn;
struct ssol_sun* sun;
- unsigned char* pixels = NULL;
+ struct image img;
+ uint8_t* pixels;
const double pos[3] = {278.0, -1000.0, 273.0};
const double tgt[3] = {278.0, 0.0, 273.0};
const double up[3] = {0.0, 0.0, 1.0};
double dir[3];
+ size_t pitch;
res_T (*draw_func)
(struct ssol_scene* scn,
struct ssol_camera* cam,
@@ -233,8 +235,10 @@ main(int argc, char** argv)
CHECK(ssol_sun_set_dni(sun, 1000), RES_OK);
CHECK(ssol_scene_attach_sun(scn, sun), RES_OK);
- pixels = MEM_CALLOC(&allocator, HEIGHT, PITCH);
- NCHECK(pixels, NULL);
+ pitch = WIDTH * sizeof_image_format(IMAGE_RGB8);
+ image_init(&allocator, &img);
+ image_setup(&img, WIDTH, HEIGHT, pitch, IMAGE_RGB8, NULL);
+ pixels = (uint8_t*)img.pixels;
CHECK(draw_func(NULL, NULL, 0, 0, 0, NULL, pixels), RES_BAD_ARG);
CHECK(draw_func(scn, NULL, 0, 0, 0, NULL, pixels), RES_BAD_ARG);
@@ -301,9 +305,9 @@ main(int argc, char** argv)
CHECK(draw_func(NULL, cam, WIDTH, WIDTH, 4, write_RGB8, pixels), RES_BAD_ARG);
CHECK(draw_func(scn, cam, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_OK);
- CHECK(image_ppm_write_stream(stdout, WIDTH, HEIGHT, 3, pixels), RES_OK);
+ CHECK(image_write_ppm_stream(&img, 0, stdout), RES_OK);
- MEM_RM(&allocator, pixels);
+ CHECK(image_release(&img), RES_OK);
CHECK(ssol_device_ref_put(dev), RES_OK);
CHECK(ssol_camera_ref_put(cam), RES_OK);
CHECK(ssol_scene_ref_put(scn), RES_OK);
diff --git a/src/test_ssol_image.c b/src/test_ssol_image.c
@@ -16,6 +16,94 @@
#include "ssol.h"
#include "test_ssol_utils.h"
+
+#include <rsys/double2.h>
+#include <rsys/double3.h>
+
+static void
+check_sampling(struct ssol_device* dev)
+{
+ struct ssol_image_layout layout;
+ struct ssol_image* img;
+ size_t pixsz;
+ char* mem;
+ double uv[2];
+ double pix[3];
+ double tmp[3];
+
+ CHECK(ssol_image_create(dev, &img), RES_OK);
+ CHECK(ssol_image_setup(img, 4, 2, SSOL_PIXEL_DOUBLE3), RES_OK);
+ CHECK(ssol_image_get_layout(img, &layout), RES_OK);
+
+ pixsz = ssol_sizeof_pixel_format(layout.pixel_format);
+
+ CHECK(ssol_image_map(img, &mem), RES_OK);
+ d3((double*)(mem + layout.offset + 0*pixsz + 0*layout.row_pitch), 1, 0, 0);
+ d3((double*)(mem + layout.offset + 1*pixsz + 0*layout.row_pitch), 1, 0, 0);
+ d3((double*)(mem + layout.offset + 2*pixsz + 0*layout.row_pitch), 1, 1, 0);
+ d3((double*)(mem + layout.offset + 3*pixsz + 0*layout.row_pitch), 1, 1, 0);
+ d3((double*)(mem + layout.offset + 0*pixsz + 1*layout.row_pitch), 1, 0, 1);
+ d3((double*)(mem + layout.offset + 1*pixsz + 1*layout.row_pitch), 1, 0, 1);
+ d3((double*)(mem + layout.offset + 2*pixsz + 1*layout.row_pitch), 0, 1, 1);
+ d3((double*)(mem + layout.offset + 3*pixsz + 1*layout.row_pitch), 0, 1, 1);
+ CHECK(ssol_image_unmap(img), RES_OK);
+
+ #define CLAMPED SSOL_ADDRESS_CLAMP
+ #define REPEAT SSOL_ADDRESS_REPEAT
+ #define NEAREST SSOL_FILTER_NEAREST
+ #define LINEAR SSOL_FILTER_LINEAR
+
+ d2_splat(uv, 0);
+ CHECK(ssol_image_sample(NULL, NEAREST, CLAMPED, CLAMPED, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_image_sample(NULL, NEAREST, CLAMPED, CLAMPED, uv, NULL), RES_BAD_ARG);
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, NULL), RES_BAD_ARG);
+ CHECK(ssol_image_sample(NULL, NEAREST, CLAMPED, CLAMPED, NULL, pix), RES_BAD_ARG);
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, NULL, pix), RES_BAD_ARG);
+ CHECK(ssol_image_sample(NULL, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_BAD_ARG);
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,0,0)), 1);
+
+ uv[0] = 1.0/4.0;
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,0,0)), 1);
+ uv[0] = 2.0/4.0;
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,1,0)), 1);
+ uv[0] = 3.0/4.0;
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,1,0)), 1);
+
+ uv[0] = -1.0/4.0;
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,0,0)), 1);
+ CHECK(ssol_image_sample(img, NEAREST, REPEAT, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,1,0)), 1);
+ uv[0] = 4.0/4.0;
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,1,0)), 1);
+ CHECK(ssol_image_sample(img, NEAREST, REPEAT, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,0,0)), 1);
+
+ uv[1] = 1.0/2.0;
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,0,1,1)), 1);
+ uv[1] = 2.0/2.0;
+ CHECK(ssol_image_sample(img, NEAREST, REPEAT, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,0,1)), 1);
+ CHECK(ssol_image_sample(img, NEAREST, REPEAT, REPEAT, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,0,0)), 1);
+ CHECK(ssol_image_sample(img, NEAREST, CLAMPED, REPEAT, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,1,1,0)), 1);
+
+ uv[0] = 1.0/4.0 + 1.0/8.0;
+ uv[1] = 0.0/2.0 + 1.0/4.0;
+ CHECK(ssol_image_sample(img, LINEAR, CLAMPED, CLAMPED, uv, pix), RES_OK);
+ CHECK(d3_eq(pix, d3(tmp,0.75,0.5,0.5)), 1);
+
+ CHECK(ssol_image_ref_put(img), RES_OK);
+}
+
int
main(int argc, char** argv)
{
@@ -26,7 +114,7 @@ main(int argc, char** argv)
struct ssol_image_layout layout = SSOL_IMAGE_LAYOUT_NULL;
size_t org[2];
size_t sz[2];
- void* mem;
+ char* mem;
size_t i, x, y;
(void) argc, (void) argv;
@@ -103,7 +191,7 @@ main(int argc, char** argv)
FOR_EACH(y, 0, layout.height) {
const double* row = (const double*)
- (((char*)mem + layout.offset) + y * layout.row_pitch);
+ ((mem + layout.offset) + y * layout.row_pitch);
FOR_EACH(x, 0, layout.width) {
const double* pixel = row + x*3;
if(y < 8) {
@@ -117,7 +205,7 @@ main(int argc, char** argv)
CHECK(pixel[2], 2);
}
} else {
- if(x < 8) {
+ if(x < 8) {
CHECK(pixel[0], 3);
CHECK(pixel[1], 3);
CHECK(pixel[2], 3);
@@ -129,8 +217,12 @@ main(int argc, char** argv)
}
}
}
+ CHECK(ssol_image_unmap(NULL), RES_BAD_ARG);
+ CHECK(ssol_image_unmap(img), RES_OK);
CHECK(ssol_image_ref_put(img), RES_OK);
+
+ check_sampling(dev);
CHECK(ssol_device_ref_put(dev), RES_OK);
check_memory_allocator(&allocator);
diff --git a/src/test_ssol_materials.h b/src/test_ssol_materials.h
@@ -25,16 +25,12 @@ get_shader_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)
{
int i;
- (void)dev, (void)buf, (void)wavelength, (void)P, (void)Ng, (void)uv, (void)w;
- FOR_EACH(i, 0, 3) val[i] = Ns[i];
+ (void)dev, (void)buf, (void)wavelength;
+ FOR_EACH(i, 0, 3) val[i] = frag->Ns[i];
}
static INLINE void
@@ -42,15 +38,10 @@ get_shader_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)
{
- (void)dev, (void)buf, (void)wavelength;
- (void)P, (void)Ng, (void)Ns, (void)uv, (void) w;
+ (void)dev, (void)buf, (void)wavelength, (void)frag;
*val = 1;
}
@@ -60,15 +51,10 @@ get_shader_reflectivity_2
(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) Ns, (void) uv, (void) w;
+ (void)dev, (void)buf, (void)wavelength, (void)frag;
*val = REFLECTIVITY;
}
#endif
@@ -78,15 +64,10 @@ get_shader_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)
{
- (void)dev, (void)buf, (void)wavelength;
- (void)P, (void)Ng, (void)Ns, (void)uv, (void) w;
+ (void)dev, (void)buf, (void)wavelength, (void)frag;
*val = 0;
}
@@ -95,15 +76,10 @@ get_shader_absorption
(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)Ns, (void)uv, (void) w;
+ (void)dev, (void)buf, (void)wavelength, (void)frag;
*val = 0;
}
@@ -112,15 +88,10 @@ get_shader_thickness
(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)Ns, (void)uv, (void) w;
+ (void)dev, (void)buf, (void)wavelength, (void)frag;
*val = 1;
}
@@ -129,15 +100,10 @@ get_shader_refractive_index
(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)Ns, (void)uv, (void) w;
+ (void)dev, (void)buf, (void)wavelength, (void)frag;
*val = 1.5;
}
diff --git a/src/test_ssol_param_buffer.c b/src/test_ssol_param_buffer.c
@@ -19,18 +19,30 @@
#include <rsys/logger.h>
#include <limits.h>
+struct param {
+ char* name;
+ double d;
+ int i;
+ void* ptr;
+ struct ssol_image* img;
+};
+
+static void
+param_release(void* mem)
+{
+ struct param* param = mem;
+ ASSERT(param);
+ if(param->img) SSOL(image_ref_put(param->img));
+}
+
int
main(int argc, char** argv)
{
- struct param {
- char* name;
- double d;
- int i;
- void* ptr;
- }* param;
+ struct param* param;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_param_buffer* pbuf;
+ struct ssol_image* img;
size_t sz, al;
void* mem;
(void)argc, (void)argv;
@@ -53,14 +65,14 @@ main(int argc, char** argv)
sz = sizeof(intptr_t);
al = ALIGNOF(intptr_t);
- CHECK(mem = ssol_param_buffer_allocate(NULL, 0, 0), NULL);
- CHECK(mem = ssol_param_buffer_allocate(pbuf, 0, 0), NULL);
- CHECK(mem = ssol_param_buffer_allocate(NULL, sz, 0), NULL);
- CHECK(mem = ssol_param_buffer_allocate(pbuf, sz, 0), NULL);
- CHECK(mem = ssol_param_buffer_allocate(NULL, 0, al), NULL);
- CHECK(mem = ssol_param_buffer_allocate(pbuf, 0, al), NULL);
- CHECK(mem = ssol_param_buffer_allocate(NULL, sz, al), NULL);
- NCHECK(mem = ssol_param_buffer_allocate(pbuf, sz, al), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(NULL, 0, 0, NULL), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(pbuf, 0, 0, NULL), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(NULL, sz, 0, NULL), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(pbuf, sz, 0, NULL), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(NULL, 0, al, NULL), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(pbuf, 0, al, NULL), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(NULL, sz, al, NULL), NULL);
+ NCHECK(mem = ssol_param_buffer_allocate(pbuf, sz, al, NULL), NULL);
*(intptr_t*)mem = 0xDECAFBAD;
CHECK(*(intptr_t*)ssol_param_buffer_get(pbuf), 0xDECAFBAD);
@@ -74,7 +86,7 @@ main(int argc, char** argv)
sz = strlen("Foo") + 1;
al = 4;
- NCHECK(mem = ssol_param_buffer_allocate(pbuf, sz, al), NULL);
+ NCHECK(mem = ssol_param_buffer_allocate(pbuf, sz, al, NULL), NULL);
strcpy(mem, "Foo");
CHECK(strcmp(ssol_param_buffer_get(pbuf), "Foo"), 0);
strcpy(mem, "Bar");
@@ -85,12 +97,13 @@ main(int argc, char** argv)
sz = sizeof(struct param);
al = ALIGNOF(struct param);
- NCHECK(param = ssol_param_buffer_allocate(pbuf, sz, al), NULL);
- NCHECK(param->name = ssol_param_buffer_allocate(pbuf, 7, 64), NULL);
+ NCHECK(param = ssol_param_buffer_allocate(pbuf, sz, al, NULL), NULL);
+ NCHECK(param->name = ssol_param_buffer_allocate(pbuf, 7, 64, NULL), NULL);
strcpy(param->name, "0123456");
- NCHECK(param->ptr = ssol_param_buffer_allocate(pbuf, 4, 16), NULL);
+ NCHECK(param->ptr = ssol_param_buffer_allocate(pbuf, 4, 16, NULL), NULL);
param->d = PI;
param->i = -123;
+ param->img = NULL;
strcpy(param->ptr, "abc");
NCHECK(param = ssol_param_buffer_get(pbuf), NULL);
@@ -102,6 +115,46 @@ main(int argc, char** argv)
CHECK(strcmp(param->name, "0123456"), 0);
CHECK(strcmp(param->ptr, "abc"), 0);
+ CHECK(ssol_param_buffer_clear(pbuf), RES_OK);
+
+ sz = sizeof(struct param);
+ al = ALIGNOF(struct param);
+ CHECK(ssol_image_create(dev, &img), RES_OK);
+ CHECK(ssol_image_setup(img, 1280, 720, SSOL_PIXEL_DOUBLE3), RES_OK);
+ NCHECK(param = ssol_param_buffer_allocate(pbuf, sz, al, ¶m_release), NULL);
+ param->d = PI;
+ param->i = -123;
+ param->name = NULL;
+ param->ptr = NULL;
+ param->img = img;
+ CHECK(ssol_image_ref_get(img), RES_OK);
+
+ NCHECK(param = ssol_param_buffer_allocate(pbuf, sz, al, ¶m_release), NULL);
+ param->d = 123.456;
+ param->i = -1;
+ param->name = NULL;
+ param->ptr = NULL;
+ param->img = img;
+ CHECK(ssol_image_ref_get(img), RES_OK);
+
+ NCHECK(param = ssol_param_buffer_allocate(pbuf, sz, al, ¶m_release), NULL);
+ param->d = 0.1;
+ param->i = 789;
+ param->name = NULL;
+ param->ptr = NULL;
+ param->img = img;
+ CHECK(ssol_image_ref_get(img), RES_OK);
+
+ CHECK(ssol_param_buffer_clear(pbuf), RES_OK);
+
+ NCHECK(param = ssol_param_buffer_allocate(pbuf, sz, al, ¶m_release), NULL);
+ param->d = 0.1;
+ param->i = 789;
+ param->name = NULL;
+ param->ptr = NULL;
+ param->img = img;
+ CHECK(ssol_image_ref_get(img), RES_OK);
+
CHECK(ssol_param_buffer_ref_get(NULL), RES_BAD_ARG);
CHECK(ssol_param_buffer_ref_get(pbuf), RES_OK);
CHECK(ssol_param_buffer_ref_put(NULL), RES_BAD_ARG);
@@ -109,9 +162,10 @@ main(int argc, char** argv)
CHECK(ssol_param_buffer_ref_put(pbuf), RES_OK);
CHECK(ssol_param_buffer_create(dev, 8, &pbuf), RES_OK);
- NCHECK(mem = ssol_param_buffer_allocate(pbuf, 2, 1), NULL);
- CHECK(mem = ssol_param_buffer_allocate(pbuf, 1, 16), NULL);
+ NCHECK(mem = ssol_param_buffer_allocate(pbuf, 2, 1, NULL), NULL);
+ CHECK(mem = ssol_param_buffer_allocate(pbuf, 1, 16, NULL), NULL);
+ CHECK(ssol_image_ref_put(img), RES_OK);
CHECK(ssol_param_buffer_ref_put(pbuf), RES_OK);
CHECK(ssol_device_ref_put(dev), RES_OK);