solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

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:
Msrc/ssol.h | 50+++++++++++++++++++++++++++++++++++++++-----------
Msrc/ssol_draw_draft.c | 40+++++++++++++++++++++++++++++-----------
Msrc/ssol_draw_pt.c | 39+++++++++++++++++++++++++++++----------
Msrc/ssol_image.c | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/ssol_material.c | 217+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/ssol_material_c.h | 51+++++++++++++++++++++++++++------------------------
Msrc/ssol_param_buffer.c | 43+++++++++++++++++++++++++++++++++----------
Msrc/ssol_shape.c | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/ssol_solver.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/ssol_spectrum.c | 5++---
Msrc/ssol_sun.c | 35++++++++++++++++-------------------
Msrc/test_ssol_draw.c | 14+++++++++-----
Msrc/test_ssol_image.c | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/test_ssol_materials.h | 64+++++++++++++++-------------------------------------------------
Msrc/test_ssol_param_buffer.c | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
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, &param); + 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, &param_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, &param_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, &param_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, &param_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);