← Back to team overview

kicad-developers team mailing list archive

Re: [PATCH] Option to subtract soldermask from silkscreen in gerber output

 

Drawing the negative layer last is not correct, since it erases
everything below the negative objects in all layers. The attached
patch seems to do the trick right. All layers (=layers as they are
seen in gerbview, not individual layers in a gerber file) are first
drawn into a bitmap and negative objects are drawn in background
color. Then the bitmap itself is used as a mask in blitting the bitmap
onto the screen.

marco

On Tue, Dec 7, 2010 at 4:41 PM, Dick Hollenbeck <dick@xxxxxxxxxxx> wrote:

> Just having a single bitmap will not change anything that I can see.
> You did not mention having multiple layer specific bitmaps and then
> doing combinational logic on their bits into a final destination.  What
> if you just draw the negative layer last onto the screen?  Or is the
> problem a matter of "looking ahead" to detect the negative layer before
> beginning drawing?  Is gerbview losing the "sequence" of operations
> established in the gerber file?  If so, the way the gerber file loading
> takes place could be an issue, and the container that holds the drawing
> primitives.
>
=== modified file 'gerbview/draw_gerber_screen.cpp'
--- gerbview/draw_gerber_screen.cpp	2010-11-20 19:53:00 +0000
+++ gerbview/draw_gerber_screen.cpp	2010-12-09 23:37:14 +0000
@@ -103,6 +103,13 @@
 {
     // Because Images can be negative (i.e with background filled in color) items are drawn
     // graphic layer per graphic layer, after the background is filled
+    int        bitmapWidth, bitmapHeight;
+    wxMemoryDC memoryDC;
+    wxColour   bgColor = MakeColour( g_DrawBgColor );
+    wxBrush    bgBrush( bgColor, wxSOLID );
+    aPanel->GetClientSize( &bitmapWidth, &bitmapHeight );
+    wxBitmap   layerBitmap( bitmapWidth, bitmapHeight );
+    memoryDC.SelectObject( layerBitmap );
     for( int layer = 0; layer < 32; layer++ )
     {
         if( !GetBoard()->IsLayerVisible( layer ) )
@@ -111,6 +118,11 @@
         if( gerber == NULL )    // Graphic layer not yet used
             continue;
 
+        // Draw each layer into a bitmap first. Negative Gerber
+        // layers are drawn in background color.
+        memoryDC.SetBackground( bgBrush );
+        memoryDC.Clear();
+
         /* Draw background negative (i.e. in graphic layer color) for negative images:
          *  Background is drawn here in GR_OR mode because in COPY mode
          *  all previous graphics will be erased
@@ -120,12 +132,12 @@
         if( gerber->m_ImageNegative )
         {
             int       color = GetBoard()->GetLayerColor( layer );
-            GRSetDrawMode( aDC, GR_OR );
+            GRSetDrawMode( (wxDC*)&memoryDC, GR_OR );
             EDA_Rect* cbox = &aPanel->m_ClipBox;
-            GRSFilledRect( cbox, aDC, cbox->GetX(), cbox->GetY(),
+            GRSFilledRect( cbox, (wxDC*)&memoryDC, cbox->GetX(), cbox->GetY(),
                            cbox->GetRight(), cbox->GetBottom(),
                            0, color, color );
-            GRSetDrawMode( aDC, aDrawMode );
+            GRSetDrawMode( (wxDC*)&memoryDC, aDrawMode );
         }
 
         int         dcode_hightlight = 0;
@@ -135,13 +147,22 @@
         for( ; item; item = item->Next() )
         {
             GERBER_DRAW_ITEM* gerb_item = (GERBER_DRAW_ITEM*) item;
-            if( gerb_item->GetLayer()!= layer )
+            if( gerb_item->GetLayer() != layer )
                 continue;
             int drawMode = aDrawMode;
             if( dcode_hightlight == gerb_item->m_DCode )
                 drawMode |= GR_SURBRILL;
-            gerb_item->Draw( aPanel, aDC, drawMode );
+            gerb_item->Draw( aPanel, (wxDC*)&memoryDC, drawMode );
         }
+
+        // Use the layer bitmap itself as a mask when blitting.
+        // The bitmap cannot be referenced by a device context
+        // when setting the mask.
+        memoryDC.SelectObject( wxNullBitmap );
+        layerBitmap.SetMask( new wxMask( layerBitmap, bgColor ) );
+        memoryDC.SelectObject( layerBitmap );
+        aDC->Blit( 0, 0, bitmapWidth, bitmapHeight,
+                   (wxDC*)&memoryDC, 0, 0, wxCOPY, true );
     }
 
     m_PcbFrame->GetScreen()->ClrRefreshReq();


Follow ups

References