diff --git a/MANIFEST b/MANIFEST
index b3ae6257b..822802e62 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,25 +1,42 @@
 Build.PL
 lib/Slic3r.pm
+lib/Slic3r/Config.pm
+lib/Slic3r/ExPolygon.pm
 lib/Slic3r/Extruder.pm
 lib/Slic3r/ExtrusionLoop.pm
 lib/Slic3r/ExtrusionPath.pm
 lib/Slic3r/ExtrusionPath/Collection.pm
 lib/Slic3r/Fill.pm
+lib/Slic3r/Fill/Base.pm
 lib/Slic3r/Fill/Rectilinear.pm
+lib/Slic3r/Fill/Rectilinear2.pm
 lib/Slic3r/Geometry.pm
+lib/Slic3r/Geometry/Clipper.pm
 lib/Slic3r/Geometry/DouglasPeucker.pm
+lib/Slic3r/GUI.pm
+lib/Slic3r/GUI/OptionsGroup.pm
+lib/Slic3r/GUI/SkeinPanel.pm
 lib/Slic3r/Layer.pm
 lib/Slic3r/Line.pm
+lib/Slic3r/Line/FacetEdge.pm
+lib/Slic3r/Line/FacetEdge/Bottom.pm
+lib/Slic3r/Line/FacetEdge/Top.pm
 lib/Slic3r/Perimeter.pm
 lib/Slic3r/Point.pm
+lib/Slic3r/Polygon.pm
 lib/Slic3r/Polyline.pm
 lib/Slic3r/Polyline/Closed.pm
 lib/Slic3r/Print.pm
+lib/Slic3r/Skein.pm
 lib/Slic3r/STL.pm
 lib/Slic3r/Surface.pm
-lib/Slic3r/Surface/Collection.pm
+lib/Slic3r/Surface/Bridge.pm
 lib/Slic3r/SVG.pm
 MANIFEST			This list of files
 README.markdown
 slic3r.pl
 t/clean_polylines.t
+t/clipper.t
+t/geometry.t
+t/polyclip.t
+t/stl.t
diff --git a/README.markdown b/README.markdown
index a713a243c..4aea5df45 100644
--- a/README.markdown
+++ b/README.markdown
@@ -40,7 +40,7 @@ Slic3r current features are:
 * retraction;
 * skirt (with rounded corners);
 * use relative or absolute extrusion commands;
-* high-res perimeters (like the "Skin" plugin for Skeinforge);
+* infill every N layers (like the "Skin" plugin for Skeinforge);
 * detect optimal infill direction for bridges;
 * save configuration profiles;
 * center print around bed center point;
@@ -53,6 +53,7 @@ Roadmap includes the following goals:
 
 * output some statistics;
 * support material for internal perimeters;
+* new and better GUI;
 * cool;
 * other fill patterns.
 
@@ -111,9 +112,8 @@ The author is Alessandro Ranellucci (me).
         
       Accuracy options:
         --layer-height      Layer height in mm (default: 0.4)
-        --high-res-perimeters
-                            Print perimeters at half layer height to get surface accuracy
-                            (default: disabled)
+        --infill-every-layers
+                            Infill every N layers (default: 1)
       
       Print options:
         --perimeters        Number of perimeters/horizontal skins (range: 1+, 
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index 3310e9ed9..03deb859e 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -50,7 +50,7 @@ our $bottom_layer_speed_ratio   = 0.3;
 # accuracy options
 our $resolution             = 0.00000001;
 our $layer_height           = 0.4;
-our $high_res_perimeters    = 0;
+our $infill_every_layers    = 1;
 our $thickness_ratio        = 1;
 our $flow_width;
 
diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index 05363b2a0..79e3a764e 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -64,9 +64,9 @@ our $Options = {
         label   => 'Layer height (mm)',
         type    => 'f',
     },
-    'high_res_perimeters' => {
-        label   => 'High-res perimeters',
-        type    => 'bool',
+    'infill_every_layers' => {
+        label   => 'Infill every N layers',
+        type    => 'i',
     },
     
     # print options
@@ -262,6 +262,12 @@ sub validate {
     die "Invalid value for --fill-density\n"
         if $Slic3r::fill_density < 0 || $Slic3r::fill_density > 1;
     
+    # --infill-every-layers
+    die "Invalid value for --infill-every-layers\n"
+        if $Slic3r::infill_every_layers !~ /^\d+$/ || $Slic3r::infill_every_layers < 1;
+    die "Maximum infill thickness can't exceed nozzle diameter\n"
+        if $Slic3r::infill_every_layers * $Slic3r::layer_height > $Slic3r::nozzle_diameter;
+    
     # --scale
     die "Invalid value for --scale\n"
         if $Slic3r::scale <= 0;
diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm
index 31a25243c..a03880f04 100644
--- a/lib/Slic3r/Extruder.pm
+++ b/lib/Slic3r/Extruder.pm
@@ -84,7 +84,7 @@ sub extrude {
     
     # compensate retraction
     $gcode .= $self->unretract if $self->retracted;
-    
+    XXX "yes!\n" if $path->depth_layers > 1;
     # extrude while going to next points
     foreach my $line ($path->lines) {
         # calculate how much filament to drive into the extruder
@@ -93,7 +93,8 @@ sub extrude {
             * (($Slic3r::nozzle_diameter**2) / ($Slic3r::filament_diameter ** 2))
             * $Slic3r::thickness_ratio 
             * $self->flow_ratio
-            * $Slic3r::filament_packing_density;
+            * $Slic3r::filament_packing_density
+            * $path->depth_layers;
         
         $gcode .= $self->G1($line->b, undef, $e, $description);
     }
diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm
index 975167e29..dfc5a83f2 100644
--- a/lib/Slic3r/ExtrusionPath.pm
+++ b/lib/Slic3r/ExtrusionPath.pm
@@ -3,6 +3,10 @@ use Moo;
 
 extends 'Slic3r::Polyline';
 
+# this integer represents the vertical thickness of the extrusion
+# expressed in layers
+has 'depth_layers' => (is => 'ro', default => sub {1});
+
 use constant PI => 4 * atan2(1, 1);
 
 sub clip_end {
diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm
index 1f52bbbab..0703fff6a 100644
--- a/lib/Slic3r/Fill.pm
+++ b/lib/Slic3r/Fill.pm
@@ -48,14 +48,20 @@ sub make_fill {
                 $filler = 'rectilinear';
             }
             
-            push @path_collection, $self->fillers->{$filler}->fill_surface($surface,
+            my @paths = $self->fillers->{$filler}->fill_surface(
+                $surface,
                 density => $density,
             );
+            
+            push @path_collection, map Slic3r::ExtrusionPath->cast(
+                [ @$_ ],
+                depth_layers => $surface->depth_layers,
+            ), @paths;
         }
         
         # save into layer
         push @{ $layer->fills }, Slic3r::ExtrusionPath::Collection->new(
-            paths => [ map Slic3r::ExtrusionPath->cast([ @$_ ]), @path_collection ],
+            paths => [ @path_collection ],
         );
         $layer->fills->[-1]->cleanup;
     }
diff --git a/lib/Slic3r/Fill/Base.pm b/lib/Slic3r/Fill/Base.pm
index da71d4e57..30b49e6e9 100644
--- a/lib/Slic3r/Fill/Base.pm
+++ b/lib/Slic3r/Fill/Base.pm
@@ -19,7 +19,7 @@ sub infill_direction {
     @shift = @{$rotate[1]};
     
     # alternate fill direction
-    if ($self->layer->id % 2) {
+    if (($self->layer->id / $surface->depth_layers) % 2) {
         $rotate[0] = Slic3r::Geometry::deg2rad($Slic3r::fill_angle) + PI/2;
     }
     
diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm
index 8b68ae32d..53a7a7c22 100644
--- a/lib/Slic3r/GUI/SkeinPanel.pm
+++ b/lib/Slic3r/GUI/SkeinPanel.pm
@@ -29,7 +29,7 @@ sub new {
         ),
         accuracy => Slic3r::GUI::OptionsGroup->new($self,
             title => 'Accuracy',
-            options => [qw(layer_height high_res_perimeters)],
+            options => [qw(layer_height infill_every_layers)],
         ),
         print => Slic3r::GUI::OptionsGroup->new($self,
             title => 'Print settings',
diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm
index 374b64d83..ec1f312a1 100644
--- a/lib/Slic3r/Geometry/Clipper.pm
+++ b/lib/Slic3r/Geometry/Clipper.pm
@@ -4,11 +4,27 @@ use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
-our @EXPORT_OK = qw(diff_ex diff union_ex);
+our @EXPORT_OK = qw(explode_expolygon explode_expolygons safety_offset
+    diff_ex diff union_ex intersection_ex);
 
 use Math::Clipper 1.02 ':all';
 our $clipper = Math::Clipper->new;
 
+sub explode_expolygon {
+    my ($expolygon) = @_;
+    return ($expolygon->{outer}, @{ $expolygon->{holes} });
+}
+
+sub explode_expolygons {
+    my ($expolygons) = @_;
+    return map explode_expolygon($_), @$expolygons;
+}
+
+sub safety_offset {
+    my ($polygons) = @_;
+    return Math::Clipper::offset($polygons, 100, 100, JT_MITER, 2);
+}
+
 sub diff_ex {
     my ($subject, $clip) = @_;
     
@@ -29,4 +45,13 @@ sub union_ex {
     return $clipper->ex_execute(CT_UNION, PFT_NONZERO, PFT_NONZERO);
 }
 
+sub intersection_ex {
+    my ($subject, $clip) = @_;
+    
+    $clipper->clear;
+    $clipper->add_subject_polygons($subject);
+    $clipper->add_clip_polygons($clip);
+    return $clipper->ex_execute(CT_INTERSECTION, PFT_NONZERO, PFT_NONZERO);
+}
+
 1;
diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm
index ad5a3dcd5..aa0448dda 100644
--- a/lib/Slic3r/Layer.pm
+++ b/lib/Slic3r/Layer.pm
@@ -4,7 +4,7 @@ use Moo;
 use Math::Clipper ':all';
 use Slic3r::Geometry qw(polygon_lines points_coincide angle3points polyline_lines nearest_point
     line_length);
-use Slic3r::Geometry::Clipper qw(union_ex);
+use Slic3r::Geometry::Clipper qw(safety_offset union_ex);
 use XXX;
 
 use constant PI => 4 * atan2(1, 1);
@@ -184,7 +184,7 @@ sub make_surfaces {
             #) if !$next_lines;
             
             $next_lines
-                or die sprintf("No lines start at point %s. This shouldn't happen", $get_point_id->($points[-1]));
+                or die sprintf("No lines start at point %s. This shouldn't happen. Please check the model for manifoldness.", $get_point_id->($points[-1]));
             last CYCLE if !@$next_lines;
             
             my @ordered_next_lines = sort 
@@ -284,10 +284,7 @@ sub process_bridges {
         # offset the surface a bit to avoid approximation issues when doing the
         # intersection below (this is to make sure we overlap with supporting
         # surfaces, otherwise a little gap will result from intersection)
-        {
-            my $offset = offset([$surface_p], 100, 100, JT_MITER, 2);
-            $surface_p = $offset->[0];
-        }
+        $surface_p = safety_offset([$surface_p])->[0];
         
             #use Slic3r::SVG;
             #Slic3r::SVG::output(undef, "bridge.svg",
diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm
index 5d8e46f27..a0b381132 100644
--- a/lib/Slic3r/Polyline.pm
+++ b/lib/Slic3r/Polyline.pm
@@ -22,10 +22,10 @@ sub id {
 
 sub cast {
     my $class = shift;
-    my ($points) = @_;
+    my ($points, %args) = @_;
     
     $points = [ map { ref $_ eq 'ARRAY' ? Slic3r::Point->new($_) : $_ } @$points ];
-    return $class->new(points => $points);
+    return $class->new(points => $points, %args);
 }
 
 sub lines {
diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index f6e230495..f05e5eef2 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -2,7 +2,7 @@ package Slic3r::Print;
 use Moo;
 
 use Math::Clipper ':all';
-use Slic3r::Geometry::Clipper qw(diff_ex union_ex);
+use Slic3r::Geometry::Clipper qw(explode_expolygons safety_offset diff_ex union_ex intersection_ex);
 use XXX;
 
 use constant X => 0;
@@ -145,7 +145,7 @@ sub detect_surfaces_type {
         
                 # okay, this is an Ugly Hack(tm) to avoid floating point math problems
                 # with diagonal bridges. will find a nicer solution, promised.
-                my $offset = offset([$surface->contour->p], 100, 100, JT_MITER, 2);
+                my $offset = safety_offset([$surface->contour->p]);
                 @{$surface->contour->points} = map Slic3r::Point->new($_), @{ $offset->[0] };
             }
             
@@ -301,6 +301,91 @@ sub split_bridges_fills {
     $_->split_bridges_fills for @{$self->layers};
 }
 
+# combine fill surfaces across layers
+sub infill_every_layers {
+    my $self = shift;
+    return unless $Slic3r::infill_every_layers > 1;
+    
+    printf "==> COMBINING INFILL\n";
+    
+    # start from bottom, skip first layer
+    for (my $i = 1; $i < $self->layer_count; $i++) {
+        my $layer = $self->layer($i);
+        
+        # skip layer if no internal fill surfaces
+        next if !grep $_->surface_type eq 'internal', map @$_, @{$layer->fill_surfaces};
+        
+        # for each possible depth, look for intersections with the lower layer
+        # we do this from the greater depth to the smaller
+        for (my $d = $Slic3r::infill_every_layers - 1; $d >= 1; $d--) {
+            next if ($i - $d) < 0;
+            my $lower_layer = $self->layer($i - 1);
+            
+            # select surfaces of the lower layer having the depth we're looking for
+            my @lower_surfaces = grep $_->depth_layers == $d && $_->surface_type eq 'internal',
+                map @$_, @{$lower_layer->fill_surfaces};
+            next if !@lower_surfaces;
+            # process each group of surfaces separately
+            foreach my $surfaces (@{$layer->fill_surfaces}) {
+                # calculate intersection between our surfaces and theirs
+                my $intersection = intersection_ex(
+                    [ map $_->p, grep $_->depth_layers <= $d, @lower_surfaces ],
+                    [ map $_->p, grep $_->surface_type eq 'internal', @$surfaces ],
+                );
+                next if !@$intersection;
+                
+                # new fill surfaces of the current layer are:
+                # - any non-internal surface
+                # - intersections found (with a $d + 1 depth)
+                # - any internal surface not belonging to the intersection (with its original depth)
+                {
+                    my @new_surfaces = ();
+                    push @new_surfaces, grep $_->surface_type ne 'internal', @$surfaces;
+                    push @new_surfaces, map Slic3r::Surface->cast_from_expolygon
+                        ($_, surface_type => 'internal', depth_layers => $d + 1), @$intersection;
+                    
+                    foreach my $depth (reverse $d..$Slic3r::infill_every_layers) {
+                        push @new_surfaces, map Slic3r::Surface->cast_from_expolygon
+                            ($_, surface_type => 'internal', depth_layers => $depth),
+                            
+                            # difference between our internal layers with depth == $depth
+                            # and the intersection found
+                            @{diff_ex(
+                                [
+                                    map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth, 
+                                        @$surfaces,
+                                ],
+                                safety_offset([ explode_expolygons($intersection) ]),
+                            )};
+                    }
+                    @$surfaces = @new_surfaces;
+                }
+                
+                # now we remove the intersections from lower layer
+                foreach my $lower_surfaces (@{$lower_layer->fill_surfaces}) {
+                    my @new_surfaces = ();
+                    push @new_surfaces, grep $_->surface_type ne 'internal', @$lower_surfaces;
+                    foreach my $depth (1..$Slic3r::infill_every_layers) {
+                        push @new_surfaces, map Slic3r::Surface->cast_from_expolygon
+                            ($_, surface_type => 'internal', depth_layers => $depth),
+                            
+                            # difference between internal layers with depth == $depth
+                            # and the intersection found
+                            @{diff_ex(
+                                [
+                                    map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth, 
+                                        @$lower_surfaces,
+                                ],
+                                safety_offset([ explode_expolygons($intersection) ]),
+                            )};
+                    }
+                    @$lower_surfaces = @new_surfaces;
+                }
+            }
+        }
+    }
+}
+
 sub extrude_fills {
     my $self = shift;
     
@@ -345,19 +430,6 @@ sub export_gcode {
     
     # write gcode commands layer by layer
     foreach my $layer (@{ $self->layers }) {
-        
-        # with the --high-res-perimeters options enabled we extrude perimeters for
-        # each layer twice at half height
-        if ($Slic3r::high_res_perimeters && $layer->id > 0) {
-            # go to half-layer
-            printf $fh $extruder->move_z($Slic3r::z_offset + $layer->z * $Slic3r::resolution - $Slic3r::layer_height/2);
-            
-            # extrude perimeters
-            $extruder->flow_ratio(0.5);
-            printf $fh $extruder->extrude_loop($_, 'perimeter') for @{ $layer->perimeters };
-            $extruder->flow_ratio(1);
-        }
-        
         # go to layer
         printf $fh $extruder->move_z($Slic3r::z_offset + $layer->z * $Slic3r::resolution);
         
diff --git a/lib/Slic3r/Skein.pm b/lib/Slic3r/Skein.pm
index 887260624..a9790ce32 100644
--- a/lib/Slic3r/Skein.pm
+++ b/lib/Slic3r/Skein.pm
@@ -47,6 +47,9 @@ sub go {
     # they will be split in internal and internal-solid surfaces
     $print->discover_horizontal_shells;
     
+    # combine fill surfaces to honor the "infill every N layers" option
+    $print->infill_every_layers;
+    
     # this will generate extrusion paths for each layer
     $print->extrude_fills;
     
diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm
index c487b0863..f43903984 100644
--- a/lib/Slic3r/Surface.pm
+++ b/lib/Slic3r/Surface.pm
@@ -19,6 +19,9 @@ has 'surface_type' => (
     #isa     => enum([qw(internal internal-solid bottom top)]),
 );
 
+# this integer represents the thickness of the surface expressed in layers
+has 'depth_layers' => (is => 'ro', default => sub {1});
+
 sub cast_from_polygon {
     my $class = shift;
     my ($polygon, %args) = @_;
@@ -34,6 +37,7 @@ sub cast_from_expolygon {
     my ($expolygon, %args) = @_;
     
     if (ref $expolygon ne 'HASH') {
+        use XXX; ZZZ $expolygon if ref $expolygon eq 'ARRAY';
         $expolygon = $expolygon->clipper_expolygon;
     }
     
diff --git a/slic3r.pl b/slic3r.pl
index d434a4e0e..75f64f3a3 100755
--- a/slic3r.pl
+++ b/slic3r.pl
@@ -41,7 +41,7 @@ GetOptions(
     
     # accuracy options
     'layer-height=f'        => \$Slic3r::layer_height,
-    'high-res-perimeters'   => \$Slic3r::high_res_perimeters,
+    'infill-every-layers=i' => \$Slic3r::infill_every_layers,
     
     # print options
     'perimeters=i'          => \$Slic3r::perimeter_offsets,
@@ -147,9 +147,8 @@ Usage: slic3r.pl [ OPTIONS ] file.stl
     
   Accuracy options:
     --layer-height      Layer height in mm (default: $Slic3r::layer_height)
-    --high-res-perimeters
-                        Print perimeters at half layer height to get surface accuracy
-                        (default: disabled)
+    --infill-every-layers
+                        Infill every N layers (default: $Slic3r::infill_every_layers)
   
   Print options:
     --perimeters        Number of perimeters/horizontal skins (range: 1+,