diff --git a/code/projects/ao.cpp b/code/projects/ao.cpp
index 265a2780a1079d77bd299e88c7d00f0dacc99e88..cb1587f78081b6067138d475065d5920fccab59a 100644
--- a/code/projects/ao.cpp
+++ b/code/projects/ao.cpp
@@ -10,6 +10,7 @@
 #include "mat.h"
 
 #include "color.h"
+#include "framebuffer.h"
 #include "image.h"
 #include "image_io.h"
 
@@ -95,7 +96,6 @@ int main( const int argc, const char **argv )
     
     // transformations 
     Transform view;
-    Transform view_inv;
     Transform projection;
     float aspect= 1;
     
@@ -106,25 +106,26 @@ int main( const int argc, const char **argv )
             return 1;    // pas de camera, pas d'image
         
         view= camera.view();
-        view_inv= Inverse(view);
         projection= camera.projection();
         aspect= camera.aspect();
     }
     else if(scene.gltf.cameras.size())
     {
         view= scene.camera.view;
-        view_inv= Inverse(scene.camera.view);
         projection= scene.camera.projection;
         aspect= scene.camera.aspect;
     }
     else
-       return 1;   // pas de camera, pas d'image
+    {
+        printf("[error] no glTF camera...\n");
+        return 1;   // pas de camera, pas d'image
+    }
     
     // proportions largeur/hauteur de la camera gltf
     int samples= options.samples;
     int width= 1024;
     int height= width / aspect;
-    Image image(width, height);
+    Framebuffer image(width, height);
     Image aov_normal(width, height);
     Image aov_albedo(width, height);
     
@@ -132,10 +133,6 @@ int main( const int argc, const char **argv )
     read_textures(options.filename, scene, width, height);
     //~ read_textures(options.filename, scene, 256, 256);
     
-    // 
-    printf("glTF lights %d\n", int(scene.gltf.lights.size()));
-    
-
     // 
     Transform viewport= Viewport(image.width(), image.height());
     Transform inv= Inverse(viewport * projection * view);
@@ -162,7 +159,6 @@ int main( const int argc, const char **argv )
             Sampler rng( seed );
             FCRNG alpha_rng( seed );
             
-            Color color;
             Vector normal;
             Color albedo;
             
@@ -177,6 +173,8 @@ int main( const int argc, const char **argv )
                 Point extremite= inv(Point(px + x, py + y, 1));
                 Ray ray(origine, extremite);
                 
+                Color color;
+                
                 // calculer les intersections avec tous les triangles
                 if(Hit hit= scene.bvh.intersect(ray, alpha_filter(scene, alpha_rng)))                
                 {
@@ -231,9 +229,10 @@ int main( const int argc, const char **argv )
                     normal= normal + pn;
                     albedo= albedo + brdf.f(pn, normalize(ray.o - p));
                 }
+                
+                image.splat(px, py, color); // accumule l'echantillon
             }
             
-            image(px, py)= Color(color / float(samples), 1);    // force une couleur opaque...
             aov_normal(px, py)= Color(normal / float(samples), 1);    // force une couleur opaque...
             aov_albedo(px, py)= Color(albedo / float(samples), 1);    // force une couleur opaque...
         }
@@ -247,12 +246,12 @@ int main( const int argc, const char **argv )
     //~ sprintf(tmp, "%s-%05u-%04u.png", options.prefix, unsigned(cpu_time), samples);
     sprintf(tmp, "%s-%04u.png", options.prefix, samples);
     printf("writing '%s'...\n", tmp);
-    write_image_preview(image, tmp);
+    write_image_preview(image.flatten(), tmp);
     
     //~ sprintf(tmp, "%s-%05u-%04u.pfm", options.prefix, unsigned(cpu_time), samples);
     sprintf(tmp, "%s-%04u.pfm", options.prefix, samples);
     printf("writing '%s'...\n", tmp);
-    write_image_pfm(image, tmp);
+    write_image_pfm(image.flatten(), tmp);
     
     sprintf(tmp, "%s-normals-%04u.pfm", options.prefix, samples);
     write_image_pfm(aov_normal, tmp);
diff --git a/code/projects/options.h b/code/projects/options.h
index 42b04ca17072f467d6dd481b06b462ac1618f519..0b3da77beb3a8f399532c544dbdd89ed91c99256 100644
--- a/code/projects/options.h
+++ b/code/projects/options.h
@@ -27,7 +27,7 @@ struct Options
             
             prefix= value("--prefix", prefix);
             samples= value_int("-s", "32");
-            depth= value_int("--lenght", "1");
+            depth= value_int("--length", "1");
         }
         
         if(options.size() == 1 || flag("--help") || flag("-h") || flag("--verbose") || flag("-v"))
@@ -36,7 +36,7 @@ struct Options
             printf("camera: '%s'\n", orbiter_filename);
             printf("output prefix: '%s'\n", prefix);
             printf("samples: %u\n", samples);
-            printf("path lenght: %u\n", depth);
+            printf("path length: %u\n", depth);
         }
     }
     
diff --git a/code/projects/path.cpp b/code/projects/path.cpp
index 8b4cc7692e6b66bcc823604f227a8f61f86fe68d..4ccec65abf50e31ad31b67f9c9ba42732cf76807 100644
--- a/code/projects/path.cpp
+++ b/code/projects/path.cpp
@@ -11,6 +11,7 @@
 #include "mat.h"
 
 #include "color.h"
+#include "framebuffer.h"
 #include "image.h"
 #include "image_io.h"
 
@@ -22,8 +23,8 @@
 #include "sampler_sobol.h"
 
 //~ typedef Squares Sampler;
-typedef LCG Sampler;
-//~ typedef Sobol Sampler;
+//~ typedef LCG Sampler;
+typedef Sobol Sampler;
 //~ typedef SobolGray Sampler;
 //~ typedef Owen Sampler;
 //~ typedef OwenFast Sampler;
@@ -225,7 +226,6 @@ int main( const int argc, const char **argv )
     
     // transformations 
     Transform view;
-    Transform view_inv;
     Transform projection;
     float aspect= 1;
     
@@ -236,25 +236,33 @@ int main( const int argc, const char **argv )
             return 1;    // pas de camera, pas d'image
         
         view= camera.view();
-        view_inv= Inverse(view);
         projection= camera.projection();
         aspect= camera.aspect();
     }
     else if(scene.gltf.cameras.size())
     {
         view= scene.camera.view;
-        view_inv= Inverse(scene.camera.view);
         projection= scene.camera.projection;
         aspect= scene.camera.aspect;
     }
     else
-       return 1;   // pas de camera, pas d'image
+    {
+        printf("[error] no glTF camera...\n");
+        return 1;   // pas de camera, pas d'image
+    }
+    
+    if(scene.sources.size() == 0)
+    {
+        printf("[error] no emissive triangles / light sources...\n");
+        return 1;
+    }
+    
     
     // proportions largeur/hauteur de la camera gltf
     int samples= options.samples;
     int width= 1024;
     int height= width / aspect;
-    Image image(width, height);
+    Framebuffer image(width, height);
     Image aov_normal(width, height);
     Image aov_albedo(width, height);
     
@@ -262,9 +270,6 @@ int main( const int argc, const char **argv )
     read_textures(options.filename, scene, width, height);
     //~ read_textures(options.filename, scene, 256, 256);
     
-    // 
-    printf("glTF lights %d\n", int(scene.gltf.lights.size()));
-    
 
     // 
     Transform viewport= Viewport(image.width(), image.height());
@@ -293,7 +298,6 @@ int main( const int argc, const char **argv )
             Sampler rng( seed );
             FCRNG alpha_rng( seed );
             
-            Color color;
             Vector normal;
             Color albedo;
             
@@ -308,6 +312,8 @@ int main( const int argc, const char **argv )
                 Point extremite= inv(Point(px + x, py + y, 1));
                 Ray ray(origine, extremite);
                 
+                Color color;
+                
                 // calculer les intersections avec tous les triangles
                 //~ if(Hit hit= scene.bvh.intersect(ray))
                 if(Hit hit= scene.bvh.intersect(ray, alpha_filter(scene, alpha_rng)))                
@@ -334,12 +340,14 @@ int main( const int argc, const char **argv )
                     normal= normal + pn;
                     albedo= albedo + brdf.f(pn, normalize(ray.o - p));
                 }
+                
+                image.splat(px, py, color); // accumule l'echantillon
             }
             
-            image(px, py)= Color(color / float(samples), 1);    // force une couleur opaque...
             aov_normal(px, py)= Color(normal / float(samples), 1);    // force une couleur opaque...
             aov_albedo(px, py)= Color(albedo / float(samples), 1);    // force une couleur opaque...
             
+            // #pragma omp compare // ne marche pas sur visual...
             maxdims= std::max(rng.d, maxdims);
         }
     }
@@ -354,12 +362,12 @@ int main( const int argc, const char **argv )
     //~ sprintf(tmp, "%s-%05u-%04u.png", options.prefix, unsigned(cpu_time), samples);
     sprintf(tmp, "%s-%04u.png", options.prefix, samples);
     printf("writing '%s'...\n", tmp);
-    write_image_preview(image, tmp);
+    write_image_preview(image.flatten(), tmp);
     
     //~ sprintf(tmp, "%s-%05u-%04u.pfm", options.prefix, unsigned(cpu_time), samples);
     sprintf(tmp, "%s-%04u.pfm", options.prefix, samples);
     printf("writing '%s'...\n", tmp);
-    write_image_pfm(image, tmp);
+    write_image_pfm(image.flatten(), tmp);
     
     sprintf(tmp, "%s-normals-%04u.pfm", options.prefix, samples);
     write_image_pfm(aov_normal, tmp);
diff --git a/code/projects/sampler.h b/code/projects/sampler.h
index 9f0444262c1bf188fc7d2afb637fb5184ba5b4ef..ac98fb86a4e4515fcb597ca4380f4777ed460bd0 100644
--- a/code/projects/sampler.h
+++ b/code/projects/sampler.h
@@ -80,17 +80,14 @@ struct FCRNG
     unsigned n;
     unsigned key;
     
-    FCRNG( ) : n(0), key(123451) {}
+    FCRNG( ) : n(0), key() { seed(123451); }
     FCRNG( const unsigned s ) : n(), key() { seed(s); }
     
     void seed( const unsigned s ) { n= 0; key= (s << 1) | 1u; }
     
     FCRNG& index( const unsigned i ) { n= i; return *this;}
     
-    unsigned sample_int( ) { return hash(n++ * key); }  
-    // \todo pour le premier point n= 0 et 0*key == 0 aussi, marche pas tres bien avant d'avoir quelques bits a 1 dans n...
-    // cf utilisation dans owen...
-    
+    unsigned sample_int( ) { return hash(++n * key); }
     float sample( ) { return uint_to_float( sample_int() ); }
     
     unsigned sample_range( const unsigned range )
diff --git a/code/projects/sobol_matrices.h b/code/projects/sobol_matrices.h
index 1868a79d7322d7ef3a81853a32454e6e548bafef..bbd4d8bc2d2b29c54048a36cc089c6bea4dfc91b 100644
--- a/code/projects/sobol_matrices.h
+++ b/code/projects/sobol_matrices.h
@@ -4,7 +4,6 @@
 #include <cassert>
 #include <cstdint>
 #include <array>
-#include <intrin.h>
 
 
 unsigned sobol_sample( const std::array<unsigned, 32>& m, unsigned n )
@@ -23,15 +22,26 @@ unsigned graycode( const unsigned i )
 {
     return i ^ (i >> 1);
 }
+
+#ifdef _MSC_VER
+#include <intrin.h>
+
 unsigned trailing_zeroes( const unsigned i )
 {
-    assert(i > 0);
-    // return __builtin_ctz(i); // gcc
-
     unsigned long b = 0;
     _BitScanForward(&b, i); // vs 2022
     return b;
 }
+#else
+
+unsigned trailing_zeroes( const unsigned i )
+{
+    assert(i > 0);
+    return __builtin_ctz(i); // gcc
+}
+
+// todo et les pour les mac ?
+#endif
 
 unsigned sobol_sample_graycode( const std::array<unsigned, 32>& m, unsigned n, const unsigned prev )
 {
diff --git a/code/src/gltf/brdf.h b/code/src/gltf/brdf.h
index 39de72f12c89469f7c033311fdf8479115e07251..3252d6720b018ada68f6f35fad7e622465adcdf4 100644
--- a/code/src/gltf/brdf.h
+++ b/code/src/gltf/brdf.h
@@ -87,7 +87,7 @@ struct Brdf
         
         // evalue le fresnel dans la direction miroir pour choisir le lobe....
         //~ float f= schlick_fresnel(F0, ndoto).max();
-        float f= 0;
+        float f= 0.5;
         if(u1 < f)
         {
             // genere une direction ~ cos theta / pi
@@ -125,7 +125,7 @@ struct Brdf
             return 0;
             
         //~ float f= schlick_fresnel(F0, ndoto).max();
-        float f= 0;
+        float f= 0.5;
         float d= 1 / float(2*M_PI); // ndotl / float(M_PI);
         //~ float m= ggx_d(alpha, ndoth) * ndoth / hdoto / 4;   // walter weight, cf ggx_sample()
         float m= ggx_d(alpha, ndoth) * smith_g1(alpha, ndoth) / (4 * ndoto);    // dupuy weight, cd vndf_sample()
diff --git a/code/src/gltf/scene.cpp b/code/src/gltf/scene.cpp
index f82c2aec5a99546ca89bbf693dea6b45e79b908e..724b81741da6693c555701a34e69681730b205db 100644
--- a/code/src/gltf/scene.cpp
+++ b/code/src/gltf/scene.cpp
@@ -133,12 +133,9 @@ Brdf Scene::brdf( const Hit& hit, const Vector& n ) const
     assert(bool(hit));
     
     const GLTFMaterial& m= material(hit);
-    //~ Color color= White();
     Color color= m.color;
     float roughness= m.roughness;
     float metallic= m.metallic;
-    //~ float roughness= 1;
-    //~ float metallic= 1;
     
     // ajuste les parametres en fonction des textures...
     if(m.color_texture != -1 || m.metallic_roughness_texture != -1)
diff --git a/code/src/gltf/sources.h b/code/src/gltf/sources.h
index 7777ae23f61dd7c1514c1e6587b95ba1891d1f7f..cfcba76238e03ca8b482eb6bc0e74d877c203be7 100644
--- a/code/src/gltf/sources.h
+++ b/code/src/gltf/sources.h
@@ -90,7 +90,7 @@ struct Sources
         printf("%d emissive triangles...\n", int(sources.size()));
     }
     
-    int count( ) const { return int(sources.size()); }
+    int size( ) const { return int(sources.size()); }
     const Source& operator() ( const int id ) const { assert(id >= 0); assert(id < int(sources.size())); return sources[id]; }
     
     const Source& sample( const float& u1 ) const