← Back to team overview

kicad-developers team mailing list archive

patch to add some 3d-viewer features

 

Hi,

finally i found some time to package some additions for 3d-viewer
(board outline, solder mask and paste mask rendering)

Maybe somebody can check and commit it.

Thanks,
Thomas 

Attachment: 3d-viewer.png
Description: PNG image

diff -rup 3d-viewer.orig//3d_aux.cpp 3d-viewer//3d_aux.cpp
--- 3d-viewer.orig//3d_aux.cpp	2012-06-03 22:21:14.095611510 +0200
+++ 3d-viewer//3d_aux.cpp	2012-06-03 22:16:21.653545422 +0200
@@ -192,6 +192,9 @@ Info_3D_Visu::Info_3D_Visu()
     // default all special item layers Visible
     for (ii=0; ii< FL_LAST; ii++)
         m_DrawFlags[ii]=true;
+#ifdef TSP_20120603
+    m_DrawFlags[g_Parm_3D_Visu.FL_AXIS]=false;
+#endif // TSP_20120603
 }
 
 
diff -rup 3d-viewer.orig//3d_draw.cpp 3d-viewer//3d_draw.cpp
--- 3d-viewer.orig//3d_draw.cpp	2012-06-03 22:21:14.095611510 +0200
+++ 3d-viewer//3d_draw.cpp	2012-06-03 22:16:21.653545422 +0200
@@ -1,3 +1,5 @@
+#define TSP_20120407
+
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
@@ -25,7 +27,7 @@
 
 /**
  * @file 3d_draw.cpp
-*/
+ */
 
 #include <fctsys.h>
 #include <common.h>
@@ -53,26 +55,53 @@
 #error Please set wxUSE_GLCANVAS to 1 in setup.h.
 #endif
 
-extern void CheckGLError();
+extern void     CheckGLError();
 
-static void    Draw3D_FilledCircle( double posx, double posy, double rayon,
-                                    double hole_rayon, double zpos );
-static void    Draw3D_FilledSegment( double startx, double starty,
+static void     Draw3D_FilledCircle( double posx, double posy, double rayon,
+                                     double hole_rayon, double zpos );
+static void     Draw3D_FilledSegment( double startx, double starty,
+                                      double endx, double endy,
+                                      double width, double zpos );
+static void     Draw3D_FilledCylinder( double posx, double posy, double rayon,
+                                       double height, double zpos );
+static void     Draw3D_FilledSegmentWithHole( double startx, double starty,
+                                              double endx, double endy,
+                                              double width, double holex,
+                                              double holey, double holeradius,
+                                              double zpos, double offX, double offY );
+static void     Draw3D_ArcSegment( double startx, double starty, double centrex,
+                                   double centrey, double arc_angle, double width, double zpos );
+static void     Draw3D_CircleSegment( double startx, double starty, double endx,
+                                      double endy, double width, double zpos );
+static int      Get3DLayerEnable( int act_layer );
+static GLfloat  Get3DLayerSide( int act_layer );
+static void     Draw3D_FilledOblong( double startx, double starty,
                                      double endx, double endy,
-                                     double width, double zpos );
-static void    Draw3D_FilledCylinder( double posx, double posy, double rayon,
-                                      double height, double zpos );
-static void    Draw3D_FilledSegmentWithHole( double startx, double starty,
-                                             double endx, double endy,
-                                             double width, double holex,
-                                             double holey, double holeradius,
-                                             double zpos );
-static void    Draw3D_ArcSegment( double startx, double starty, double centrex,
-                                  double centrey, double arc_angle, double width, double zpos );
-static void    Draw3D_CircleSegment( double startx, double starty, double endx,
-                                     double endy, double width, double zpos );
-static int     Get3DLayerEnable( int act_layer );
-static GLfloat Get3DLayerSide( int act_layer );
+                                     double holex,
+                                     double holey, double holeradius,
+                                     double height, double zpos );
+static void     Draw3D_FilledOblongMask( double startx, double starty,
+                                         double endx, double endy,
+                                         double holex,
+                                         double holey, double holeradius,
+                                         double height, double zpos );
+static void     Draw3D_Mask( double startx, double starty, double endx,
+                             double endy, double width, double zpos );
+static void     Draw3D_ArcSegmentMask( double startx, double starty, double centrex,
+                                       double centrey, double arc_angle, double width,
+                                       double zpos );
+static void     Draw3D_CircleSegmentMask( double startx, double starty, double endx,
+                                          double endy, double width, double zpos );
+static void     Draw3D_FilledCircleMask( double posx, double posy, double rayon,
+                                         double hole_rayon, double zpos );
+static void     Draw3D_FilledSegmentWithHoleMask( double startx, double starty,
+                                                  double endx, double endy,
+                                                  double width, double holex,
+                                                  double holey, double holeradius,
+                                                  double zpos, double offX, double offY );
+static void     Draw3D_FilledCylinderMask( double posx, double posy, double rayon,
+                                           double height, double zpos );
+void            MySetGLColor( int color, int layer );
 
 
 #ifndef CALLBACK
@@ -80,16 +109,37 @@ static GLfloat Get3DLayerSide( int act_l
 #endif
 
 // CALLBACK functions for GLU_TESS
-static void CALLBACK tessBeginCB( GLenum which );
-static void CALLBACK tessEndCB();
-static void CALLBACK tessErrorCB( GLenum errorCode );
-static void CALLBACK tessCPolyPt2Vertex( const GLvoid* data );
-static void CALLBACK tesswxPoint2Vertex( const GLvoid* data );
+static void CALLBACK    tessBeginCB( GLenum which );
+static void CALLBACK    tessEndCB();
+static void CALLBACK    tessErrorCB( GLenum errorCode );
+static void CALLBACK    tessCPolyPt2Vertex( const GLvoid* data );
+static void CALLBACK    tesswxPoint2Vertex( const GLvoid* data );
+
+static void CALLBACK    mytessBeginCB( GLenum which );
+static void CALLBACK    mytessEndCB();
+static void CALLBACK    mytessErrorCB( GLenum errorCode );
+static void CALLBACK    mytessCPolyPt2Vertex( const GLvoid* data );
+
+static void CALLBACK mytessCombineCB( GLdouble coords[3],
+                                      void* vertex_data[4],
+                                      GLfloat weight[4],
+                                      void** outData );
+
+
+std::vector<CPolyPt>    e_data;
+std::vector<CPolyPt>    p_data;
+int eii     = 0;
+int pii     = 0;
+int tmonly  = 0;
+int do_values   = 0;
+int do_ref      = 0;
 
+#define Set_tmonly( x ) tmonly = x
+#define Get_tmonly()    tmonly
 
 void EDA_3D_CANVAS::Redraw( bool finish )
 {
-    // SwapBuffer requires the window to be shown before calling
+// SwapBuffer requires the window to be shown before calling
     if( !IsShown() )
         return;
 
@@ -99,12 +149,12 @@ void EDA_3D_CANVAS::Redraw( bool finish
     SetCurrent();
 #endif
 
-    // Set the OpenGL viewport according to the client size of this canvas.
-    // This is done here rather than in a wxSizeEvent handler because our
-    // OpenGL rendering context (and thus viewport setting) is used with
-    // multiple canvases: If we updated the viewport in the wxSizeEvent
-    // handler, changing the size of one canvas causes a viewport setting that
-    // is wrong when next another canvas is repainted.
+// Set the OpenGL viewport according to the client size of this canvas.
+// This is done here rather than in a wxSizeEvent handler because our
+// OpenGL rendering context (and thus viewport setting) is used with
+// multiple canvases: If we updated the viewport in the wxSizeEvent
+// handler, changing the size of one canvas causes a viewport setting that
+// is wrong when next another canvas is repainted.
     const wxSize ClientSize = GetClientSize();
 
     // *MUST* be called *after*  SetCurrent( ):
@@ -136,34 +186,106 @@ void EDA_3D_CANVAS::Redraw( bool finish
     }
 
     glFlush();
-    if( finish );
-        glFinish();
+
+    if( finish )
+        ;
+
+    glFinish();
 
     SwapBuffers();
 }
 
 
-GLuint EDA_3D_CANVAS::CreateDrawGL_List()
+int orient( int mini, int spii, int pii )
 {
-    PCB_BASE_FRAME* pcbframe = Parent()->Parent();
-    BOARD* pcb = pcbframe->GetBoard();
-    TRACK* track;
-    SEGZONE*             segzone;
-    int ii;
+    int qdx1, qdx2;
+    int qdy1, qdy2;
+
+    if( (pii - spii) < 2 )
+        return 0;
+
+    if( mini == spii )
+    {
+        qdy1    = (p_data[mini + 1].y - p_data[mini].y);
+        qdx1    = (p_data[mini + 1].x - p_data[mini].x);
+        qdy2    = (p_data[mini].y - p_data[pii - 1].y);
+        qdx2    = (p_data[mini].x - p_data[pii - 1].x);
+    }
+    else if( mini >= pii - 1 )
+    {
+        qdy1    = (p_data[spii].y - p_data[mini].y);
+        qdx1    = (p_data[spii].x - p_data[mini].x);
+        qdy2    = (p_data[mini].y - p_data[mini - 1].y);
+        qdx2    = (p_data[mini].x - p_data[mini - 1].x);
+    }
+    else
+    {
+        qdy1    = (p_data[mini + 1].y - p_data[mini].y);
+        qdx1    = (p_data[mini + 1].x - p_data[mini].x);
+        qdy2    = (p_data[mini].y - p_data[mini - 1].y);
+        qdx2    = (p_data[mini].x - p_data[mini - 1].x);
+    }
+
+    if( qdx1 | qdx2 )
+    {
+        if( qdx1 && qdx2 )
+        {
+            if( (double) qdy1 / (double) qdx1 > (double) qdy2 / (double) qdx2 )
+            {
+                return 1;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        if( qdx1 )
+        {
+            return -1;
+        }
+        else
+        {
+            return 1;
+        }
+    }
+    else
+    {
+        return 0;
+    }
+}
 
-    wxBusyCursor         dummy;
 
+GLuint EDA_3D_CANVAS::CreateDrawGL_List()
+{
+    PCB_BASE_FRAME* pcbframe = Parent()->Parent();
+    BOARD*          pcb = pcbframe->GetBoard();
+    TRACK*          track;
+    SEGZONE*        segzone;
+    int             ii;
+
+    wxBusyCursor    dummy;
+    int             bpii;
+
+    do_values   = pcb->IsElementVisible( MOD_VALUES_VISIBLE );
+    do_ref      = pcb->IsElementVisible( MOD_REFERENCES_VISIBLE );
+    Set_tmonly( 0 );
+    e_data.clear();
+    p_data.reserve( 1000000 );
+    p_data.clear();
+    eii = 0;
+    pii = 0;
     m_gllist = glGenLists( 1 );
 
-    EDA_RECT    bbbox = pcbframe->GetBoardBoundingBox();
+    EDA_RECT bbbox = pcbframe->GetBoardBoundingBox();
 
     g_Parm_3D_Visu.m_BoardSettings = &pcb->GetDesignSettings();
 
-    g_Parm_3D_Visu.m_BoardSize     = bbbox.GetSize();
-    g_Parm_3D_Visu.m_BoardPos      = bbbox.Centre();
+    g_Parm_3D_Visu.m_BoardSize  = bbbox.GetSize();
+    g_Parm_3D_Visu.m_BoardPos   = bbbox.Centre();
 
-    g_Parm_3D_Visu.m_BoardPos.y    = -g_Parm_3D_Visu.m_BoardPos.y;
-    g_Parm_3D_Visu.m_Layers        = pcb->GetCopperLayerCount();
+    g_Parm_3D_Visu.m_BoardPos.y = -g_Parm_3D_Visu.m_BoardPos.y;
+    g_Parm_3D_Visu.m_Layers     = pcb->GetCopperLayerCount();
 
     // Ensure the board has 2 sides for 3D views, because it is hard to find
     // a *really* single side board in the true life...
@@ -184,29 +306,41 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
     for( ii = 0; ii < 32; ii++ )
     {
         if( ii < g_Parm_3D_Visu.m_Layers )
+        {
             g_Parm_3D_Visu.m_LayerZcoord[ii] = g_Parm_3D_Visu.m_Epoxy_Width
                                                * ii / (g_Parm_3D_Visu.m_Layers - 1);
+        }
         else
-            g_Parm_3D_Visu.m_LayerZcoord[ii] = g_Parm_3D_Visu.m_Epoxy_Width;
+        {
+            if( ii <= SOLDERMASK_N_FRONT )
+            {
+                double offs = g_Parm_3D_Visu.m_Epoxy_Width * ( 4 - ( (ii >> 1) & 7 ) ) / 100.0;
+                g_Parm_3D_Visu.m_LayerZcoord[ii] =
+                    (ii & 1) ? (g_Parm_3D_Visu.m_Epoxy_Width + offs) : -offs;
+            }
+            else
+            {
+                g_Parm_3D_Visu.m_LayerZcoord[ii] = g_Parm_3D_Visu.m_Epoxy_Width;
+            }
+        }
     }
 
-    GLfloat zpos_cu  = 10 * g_Parm_3D_Visu.m_BoardScale;
-    GLfloat zpos_cmp = g_Parm_3D_Visu.m_Epoxy_Width + zpos_cu;
-    g_Parm_3D_Visu.m_LayerZcoord[ADHESIVE_N_BACK]    = -zpos_cu * 2;
-    g_Parm_3D_Visu.m_LayerZcoord[ADHESIVE_N_FRONT]   = zpos_cmp + zpos_cu;
-    g_Parm_3D_Visu.m_LayerZcoord[SILKSCREEN_N_BACK]  = -zpos_cu;
-    g_Parm_3D_Visu.m_LayerZcoord[SILKSCREEN_N_FRONT] = zpos_cmp;
+    GLfloat zpos_cu     = 10 * g_Parm_3D_Visu.m_BoardScale;
+    GLfloat zpos_cmp    = g_Parm_3D_Visu.m_Epoxy_Width + zpos_cu;
+    g_Parm_3D_Visu.m_LayerZcoord[ADHESIVE_N_BACK]   = -zpos_cu * 2;
+    g_Parm_3D_Visu.m_LayerZcoord[ADHESIVE_N_FRONT]  = zpos_cmp + zpos_cu;
+    g_Parm_3D_Visu.m_LayerZcoord[SILKSCREEN_N_BACK]     = -zpos_cu - 0.004;
+    g_Parm_3D_Visu.m_LayerZcoord[SILKSCREEN_N_FRONT]    = zpos_cmp * 1.07;
     g_Parm_3D_Visu.m_LayerZcoord[DRAW_N]    = zpos_cmp + zpos_cu;
     g_Parm_3D_Visu.m_LayerZcoord[COMMENT_N] = zpos_cmp + zpos_cu;
     g_Parm_3D_Visu.m_LayerZcoord[ECO1_N]    = zpos_cmp + zpos_cu;
     g_Parm_3D_Visu.m_LayerZcoord[ECO2_N]    = zpos_cmp + zpos_cu;
-
     glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
 
     glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
 
     // draw axis
-    if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_AXIS])
+    if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_AXIS] )
     {
         glEnable( GL_COLOR_MATERIAL );
         SetGLColor( WHITE );
@@ -223,14 +357,13 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
     }
 
     // Draw epoxy limits (do not use, works and test in progress)
-    // TODO
 
     // move the board in order to draw it with its center at 0,0 3D coordinates
     glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BoardScale,
                   -g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BoardScale,
                   0.0F );
 
-    glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
+    glNormal3f( 0.0, 0.0, 1.0 );    // Normal is Z axis
 
     // draw tracks and vias :
     for( track = pcb->m_Track; track != NULL; track = track->Next() )
@@ -241,13 +374,15 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
             Draw3D_Track( track );
     }
 
-    if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE])
+    if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE] )
     {
         // Draw segments used to fill copper areas. outdated!
         for( segzone = pcb->m_Zone; segzone != NULL; segzone = segzone->Next() )
         {
             if( segzone->Type() == PCB_ZONE_T )
+            {
                 Draw3D_Track( segzone );
+            }
         }
 
         // Draw new segments
@@ -272,10 +407,10 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
                     dummysegment.SetLayer( curr_zone->GetLayer() );
                     dummysegment.m_Width = curr_zone->m_ZoneMinThickness;
 
-                    dummysegment.m_Start.x = curr_zone->m_FillSegmList[iseg].m_Start.x;
-                    dummysegment.m_Start.y = curr_zone->m_FillSegmList[iseg].m_Start.y;
-                    dummysegment.m_End.x   = curr_zone->m_FillSegmList[iseg].m_End.x;
-                    dummysegment.m_End.y   = curr_zone->m_FillSegmList[iseg].m_End.y;
+                    dummysegment.m_Start.x  = curr_zone->m_FillSegmList[iseg].m_Start.x;
+                    dummysegment.m_Start.y  = curr_zone->m_FillSegmList[iseg].m_Start.y;
+                    dummysegment.m_End.x    = curr_zone->m_FillSegmList[iseg].m_End.x;
+                    dummysegment.m_End.y    = curr_zone->m_FillSegmList[iseg].m_End.y;
                     Draw3D_Track( &dummysegment );
                 }
             }
@@ -284,9 +419,9 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
         // Draw copper areas outlines
         for( ii = 0; ii < pcb->GetAreaCount(); ii++ )
         {
-            ZONE_CONTAINER* zone = pcb->GetArea( ii );
+            ZONE_CONTAINER*         zone = pcb->GetArea( ii );
 
-            std::vector<CPolyPt> polysList = zone->GetFilledPolysList();
+            std::vector<CPolyPt>    polysList = zone->GetFilledPolysList();
 
             if( polysList.size() == 0 )
                 continue;
@@ -294,10 +429,10 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
             if( zone->m_ZoneMinThickness <= 1 )
                 continue;
 
-            int      imax = polysList.size() - 1;
-            CPolyPt* firstcorner = &polysList[0];
-            CPolyPt* begincorner = firstcorner;
-            SEGZONE  dummysegment( pcb );
+            int         imax = polysList.size() - 1;
+            CPolyPt*    firstcorner = &polysList[0];
+            CPolyPt*    begincorner = firstcorner;
+            SEGZONE     dummysegment( pcb );
             dummysegment.SetLayer( zone->GetLayer() );
             dummysegment.m_Width = zone->m_ZoneMinThickness;
 
@@ -308,10 +443,10 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
                 if( begincorner->utility == 0 )
                 {
                     // Draw only basic outlines, not extra segments
-                    dummysegment.m_Start.x = begincorner->x;
-                    dummysegment.m_Start.y = begincorner->y;
-                    dummysegment.m_End.x   = endcorner->x;
-                    dummysegment.m_End.y   = endcorner->y;
+                    dummysegment.m_Start.x  = begincorner->x;
+                    dummysegment.m_Start.y  = begincorner->y;
+                    dummysegment.m_End.x    = endcorner->x;
+                    dummysegment.m_End.y    = endcorner->y;
                     Draw3D_Track( &dummysegment );
                 }
 
@@ -321,10 +456,10 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
                     if( endcorner->utility == 0 )
                     {
                         // Draw only basic outlines, not extra segments
-                        dummysegment.m_Start.x = endcorner->x;
-                        dummysegment.m_Start.y = endcorner->y;
-                        dummysegment.m_End.x   = firstcorner->x;
-                        dummysegment.m_End.y   = firstcorner->y;
+                        dummysegment.m_Start.x  = endcorner->x;
+                        dummysegment.m_Start.y  = endcorner->y;
+                        dummysegment.m_End.x    = firstcorner->x;
+                        dummysegment.m_End.y    = firstcorner->y;
 
                         Draw3D_Track( &dummysegment );
                     }
@@ -345,7 +480,7 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
     // draw graphic items
     EDA_ITEM* PtStruct;
 
-    for( PtStruct = pcb->m_Drawings;  PtStruct != NULL;  PtStruct = PtStruct->Next() )
+    for( PtStruct = pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() )
     {
         switch( PtStruct->Type() )
         {
@@ -365,9 +500,537 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
     // draw footprints
     MODULE* Module = pcb->m_Modules;
 
-    for( ; Module != NULL; Module = Module->Next() )
+    if( eii )
     {
-        Module->Draw3D( this );
+        {
+            int ax, ay;
+            int ecnt = eii;
+            int need_cont;
+            int dlim = 100;
+
+            int gxmin   = 0x7fffffff;
+            int xmin    = 0x7fffffff;
+            int ymax    = 0x80000000;
+            int gmini   = -1;
+            int mini    = -1;
+            int spii    = 0;
+            int gspii   = 0;
+            int gpii    = 0;
+            pii = 0;
+            need_cont = 0;
+            p_data.clear();
+            p_data.push_back( CPolyPt( e_data[0].x, e_data[0].y ) );
+            e_data[0].x = 0x80000000;
+            ax  = p_data[pii].x;
+            ay  = p_data[pii].y;
+
+            if( ax < xmin )
+            {
+                xmin    = ax;
+                ymax    = ay;
+                mini    = pii;
+            }
+            else if( ax == xmin )
+            {
+                if( ymax < ay )
+                {
+                    ymax    = ay;
+                    mini    = pii;
+                }
+            }
+
+            pii++;
+
+            p_data.push_back( CPolyPt( e_data[1].x, e_data[1].y ) );
+            e_data[1].x = 0x80000000;
+            ax  = p_data[pii].x;
+            ay  = p_data[pii].y;
+
+            if( ax < xmin )
+            {
+                xmin    = ax;
+                ymax    = ay;
+                mini    = pii;
+            }
+            else if( ax == xmin )
+            {
+                if( ymax < ay )
+                {
+                    ymax    = ay;
+                    mini    = pii;
+                }
+            }
+
+            ecnt -= 1;
+            pii++;
+            ecnt -= 1;
+
+            while( ecnt > 2 )
+            {
+                int jj;
+                int lecnt = ecnt;
+
+                for( jj = 2; jj < eii; jj += 1 )
+                {
+                    if( e_data[jj].x != (int) 0x80000000 )
+                    {
+                        int d = abs( ax - e_data[jj].x ) + abs( ay - e_data[jj].y );
+
+                        if( d < dlim )
+                        {
+                            if( dlim > 100 )
+                            {
+                                dlim = 100;
+                                p_data.push_back( CPolyPt( e_data[jj].x, e_data[jj].y ) );
+                                e_data[jj].x = 0x80000000;
+                                ax  = p_data[pii].x;
+                                ay  = p_data[pii].y;
+
+                                if( ax < xmin )
+                                {
+                                    xmin    = ax;
+                                    ymax    = ay;
+                                    mini    = pii;
+                                }
+                                else if( ax == xmin )
+                                {
+                                    if( ymax < ay )
+                                    {
+                                        ymax    = ay;
+                                        mini    = pii;
+                                    }
+                                }
+
+                                if( need_cont )
+                                {
+                                    need_cont = 0;
+                                }
+
+                                pii++;
+                            }
+
+                            p_data.push_back( CPolyPt( e_data[jj ^ 1].x, e_data[jj ^ 1].y ) );
+                            e_data[jj ^ 1].x = 0x80000000;
+                            ax  = p_data[pii].x;
+                            ay  = p_data[pii].y;
+
+                            if( ax < xmin )
+                            {
+                                xmin    = ax;
+                                ymax    = ay;
+                                mini    = pii;
+                            }
+                            else if( ax == xmin )
+                            {
+                                if( ymax < ay )
+                                {
+                                    ymax    = ay;
+                                    mini    = pii;
+                                }
+                            }
+
+                            e_data[jj].x = 0x80000000;
+                            ecnt -= 2;
+
+                            if( need_cont )
+                            {
+                                need_cont = 0;
+                            }
+
+                            pii++;
+                            continue;
+                        }
+                    }
+                }
+
+                if( lecnt == ecnt )
+                {
+                    // close patch, open new...
+                    if( need_cont == 0 )
+                    {
+                        int d;
+                        pii--;
+                        d =
+                            abs( p_data[spii].x -
+                                 p_data[pii].x ) + abs( p_data[spii].y - p_data[pii].y );
+
+                        if( d > 100 )
+                        {
+                            pii++;
+                        }
+                        else
+                        {
+                            p_data.pop_back();
+                        }
+
+                        need_cont = 1;
+                        dlim = 0x7fffffff;
+                        p_data.push_back( CPolyPt( 0x80000000, mini ) );
+
+                        if( xmin < gxmin )
+                        {
+                            gpii    = pii;
+                            gspii   = spii;
+                            gmini   = mini;
+                            gxmin   = xmin;
+                        }
+
+                        pii++;
+                        spii    = pii;
+                        xmin    = 0x7fffffff;
+                        ymax    = 0x80000000;
+                        mini    = -1;
+                    }
+                }
+            }
+
+            if( need_cont == 0 )
+            {
+                int d;
+                pii--;
+                d = abs( p_data[spii].x - p_data[pii].x ) + abs( p_data[spii].y - p_data[pii].y );
+
+                if( d > 100 )
+                {
+                    pii++;
+                }
+                else
+                {
+                    p_data.pop_back();
+                }
+
+                if( gmini < 0 )
+                {
+                    int o = orient( mini, spii, pii );
+
+                    if( o > 0 )
+                    {
+                        int i;
+
+                        for( i = 0; i < (pii - spii) / 2; i++ )
+                        {
+                            CPolyPt h = p_data[spii + i];
+                            p_data[spii + i]    = p_data[pii - i - 1];
+                            p_data[pii - i - 1] = h;
+                        }
+                    }
+                }
+                else
+                {
+                    int o = orient( gmini, gspii, gpii );
+
+                    if( o > 0 )
+                    {
+                        int i;
+
+                        for( i = 0; i < (gpii - gspii) / 2; i++ )
+                        {
+                            CPolyPt h = p_data[gspii + i];
+                            p_data[gspii + i]       = p_data[gpii - i - 1];
+                            p_data[gpii - i - 1]    = h;
+                        }
+                    }
+                }
+
+                p_data.push_back( CPolyPt( 0x80000000, mini ) );
+                pii++;
+            }
+        }
+
+        GLUtesselator*  tess = gluNewTess();
+        GLdouble        v_data[3];
+        g_Parm_3D_Visu.m_ActZpos =
+            g_Parm_3D_Visu.m_LayerZcoord[(g_Parm_3D_Visu.m_Layers - 1)] * 0.95;
+        v_data[2] = g_Parm_3D_Visu.m_ActZpos;
+        glColor4f( 0, 0.4, 0,
+                   ( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible(
+                         SOLDERMASK_N_FRONT ) ) ? 1.0 : 0.5 );
+        glNormal3f( 0.0, 0.0, 1.0 );
+        gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )mytessBeginCB );
+        gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )mytessEndCB );
+        gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )mytessErrorCB );
+        gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )mytessCPolyPt2Vertex );
+        gluTessCallback( tess, GLU_TESS_COMBINE, ( void (CALLBACK*) () )mytessCombineCB );
+        gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD );
+
+        gluTessBeginPolygon( tess, NULL );
+
+        gluTessBeginContour( tess );
+
+        for( ii = 0; ii < pii; ii++ )
+        {
+            if( p_data[ii].x != (int) 0x80000000 )
+            {
+                v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                gluTessVertex( tess, v_data, &p_data[ii] );
+            }
+            else
+            {
+                gluTessEndContour( tess );
+                gluTessBeginContour( tess );
+            }
+        }
+
+        gluTessEndContour( tess );
+        bpii = pii;
+
+        // process holes & drills
+        Set_tmonly( 2 );
+
+        for( Module = pcb->m_Modules; Module != NULL; Module = Module->Next() )
+        {
+            D_PAD*  pad;
+            int     lpii;
+
+            for( pad = Module->m_Pads; pad != NULL; pad = pad->Next() )
+            {
+                lpii = pii;
+                pad->Draw3D( this );
+
+                if( pii > lpii )
+                {
+                    gluTessBeginContour( tess );
+
+                    for( ii = lpii; ii < pii; ii++ )
+                    {
+                        v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                        v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                        gluTessVertex( tess, v_data, &p_data[ii] );
+                    }
+
+                    gluTessEndContour( tess );
+                    p_data.push_back( CPolyPt( 0x80000000, 0 ) );
+                    pii++;
+                }
+            }
+        }
+
+        // draw tracks and vias :
+        for( track = pcb->m_Track; track != NULL; track = track->Next() )
+        {
+            int lpii;
+
+            if( track->Type() == PCB_VIA_T )
+            {
+                lpii = pii;
+                Draw3D_Via( (SEGVIA*) track );
+
+                if( pii > lpii )
+                {
+                    gluTessBeginContour( tess );
+
+                    for( ii = lpii; ii < pii; ii++ )
+                    {
+                        v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                        v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                        gluTessVertex( tess, v_data, &p_data[ii] );
+                    }
+
+                    gluTessEndContour( tess );
+                    p_data.push_back( CPolyPt( 0x80000000, 0 ) );
+                    pii++;
+                }
+            }
+        }
+
+        gluTessEndPolygon( tess );
+
+        gluDeleteTess( tess );
+
+        tess = gluNewTess();
+        g_Parm_3D_Visu.m_ActZpos = g_Parm_3D_Visu.m_Epoxy_Width * 0.05;
+        v_data[2] = g_Parm_3D_Visu.m_ActZpos;
+        glColor4f( 0, 0.4, 0,
+                   ( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible(
+                         SOLDERMASK_N_FRONT ) ) ? 1.0 : 0.5 );
+        glNormal3f( 0.0, 0.0, -1.0 );
+        gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )mytessBeginCB );
+        gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )mytessEndCB );
+        gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )mytessErrorCB );
+        gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )mytessCPolyPt2Vertex );
+        gluTessCallback( tess, GLU_TESS_COMBINE, ( void (CALLBACK*) () )mytessCombineCB );
+        gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD );
+        gluTessBeginPolygon( tess, NULL );
+
+        gluTessBeginContour( tess );
+
+        for( ii = 0; ii < pii; ii++ )
+        {
+            if( p_data[ii].x != (int) 0x80000000 )
+            {
+                v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                gluTessVertex( tess, v_data, &p_data[ii] );
+            }
+            else
+            {
+                gluTessEndContour( tess );
+                gluTessBeginContour( tess );
+            }
+        }
+
+        gluTessEndContour( tess );
+        gluTessEndPolygon( tess );
+        gluDeleteTess( tess );
+
+
+        Set_tmonly( 0 );
+
+        for( Module = pcb->m_Modules; Module != NULL; Module = Module->Next() )
+        {
+            TEXTE_MODULE*   ref = Module->m_Reference;
+            Module->Draw3D( this );
+            double          rot = Module->GetOrientation();
+
+            // Draw Reference...
+            if( do_ref )
+            {
+                for( ; ref != NULL; ref = ref->Next() )
+                {
+                    Draw3D_DrawText( ref, rot );
+                }
+            }
+        }
+
+        if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( SOLDERMASK_N_FRONT ) )
+        {
+            p_data.erase( p_data.begin() + bpii, p_data.end() );
+            pii     = bpii;
+            tess    = gluNewTess();
+            g_Parm_3D_Visu.m_ActZpos =
+                g_Parm_3D_Visu.m_LayerZcoord[(g_Parm_3D_Visu.m_Layers - 1)] * 1.05;
+            v_data[2] = g_Parm_3D_Visu.m_ActZpos;
+            glColor4f( 0.1, 0.25, 0.1, 0.75 );
+            glNormal3f( 0.0, 0.0, 1.0 );
+            gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )mytessBeginCB );
+            gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )mytessEndCB );
+            gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )mytessErrorCB );
+            gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )mytessCPolyPt2Vertex );
+            gluTessCallback( tess, GLU_TESS_COMBINE, ( void (CALLBACK*) () )mytessCombineCB );
+            gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
+            gluTessBeginPolygon( tess, NULL );
+            gluTessBeginContour( tess );
+
+            for( ii = 0; ii < pii; ii++ )
+            {
+                if( p_data[ii].x != (int) 0x80000000 )
+                {
+                    v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                    v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                    gluTessVertex( tess, v_data, &p_data[ii] );
+                }
+                else
+                {
+                    gluTessEndContour( tess );
+                    gluTessBeginContour( tess );
+                }
+            }
+
+            gluTessEndContour( tess );
+            // redo for top mask....
+            Set_tmonly( 1 );
+
+            for( Module = pcb->m_Modules; Module != NULL; Module = Module->Next() )
+            {
+                D_PAD*  pad;
+                int     lpii;
+
+                for( pad = Module->m_Pads; pad != NULL; pad = pad->Next() )
+                {
+                    lpii = pii;
+                    pad->Draw3D( this );
+
+                    if( pii > lpii )
+                    {
+                        gluTessBeginContour( tess );
+
+                        for( ii = lpii; ii < pii; ii++ )
+                        {
+                            v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                            v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                            gluTessVertex( tess, v_data, &p_data[ii] );
+                        }
+
+                        gluTessEndContour( tess );
+                    }
+                }
+            }
+
+            gluTessEndPolygon( tess );
+            gluDeleteTess( tess );
+        }
+
+        if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( SOLDERMASK_N_BACK ) )
+        {
+            p_data.erase( p_data.begin() + bpii, p_data.end() );
+            pii = bpii;
+            // bottom mask
+            tess = gluNewTess();
+            g_Parm_3D_Visu.m_ActZpos = -g_Parm_3D_Visu.m_Epoxy_Width * 0.05;
+            v_data[2] = g_Parm_3D_Visu.m_ActZpos;
+            glColor4f( 0.1, 0.25, 0.1, 0.75 );
+            glNormal3f( 0.0, 0.0, -1.0 );
+            gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )mytessBeginCB );
+            gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )mytessEndCB );
+            gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )mytessErrorCB );
+            gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )mytessCPolyPt2Vertex );
+            gluTessCallback( tess, GLU_TESS_COMBINE, ( void (CALLBACK*) () )mytessCombineCB );
+            gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
+            gluTessBeginPolygon( tess, NULL );
+            gluTessBeginContour( tess );
+
+            for( ii = 0; ii < pii; ii++ )
+            {
+                if( p_data[ii].x != (int) 0x80000000 )
+                {
+                    v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                    v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                    gluTessVertex( tess, v_data, &p_data[ii] );
+                }
+                else
+                {
+                    gluTessEndContour( tess );
+                    gluTessBeginContour( tess );
+                }
+            }
+
+            gluTessEndContour( tess );
+            // redo for top mask....
+            Set_tmonly( 3 );
+
+            for( Module = pcb->m_Modules; Module != NULL; Module = Module->Next() )
+            {
+                D_PAD*  pad;
+                int     lpii;
+
+                for( pad = Module->m_Pads; pad != NULL; pad = pad->Next() )
+                {
+                    lpii = pii;
+                    pad->Draw3D( this );
+
+                    if( pii > lpii )
+                    {
+                        gluTessBeginContour( tess );
+
+                        for( ii = lpii; ii < pii; ii++ )
+                        {
+                            v_data[0]   = p_data[ii].x * g_Parm_3D_Visu.m_BoardScale;
+                            v_data[1]   = -p_data[ii].y * g_Parm_3D_Visu.m_BoardScale;
+                            gluTessVertex( tess, v_data, &p_data[ii] );
+                        }
+
+                        gluTessEndContour( tess );
+                    }
+                }
+            }
+
+            gluTessEndPolygon( tess );
+            gluDeleteTess( tess );
+        }
+
+        p_data.clear();
+        pii = 0;
     }
 
     glEndList();
@@ -381,10 +1044,10 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List(
 
 void EDA_3D_CANVAS::Draw3D_Track( TRACK* track )
 {
-    double zpos;
-    int    layer = track->GetLayer();
-    double ox, oy, fx, fy;
-    double w;
+    double  zpos;
+    int     layer = track->GetLayer();
+    double  ox, oy, fx, fy;
+    double  w;
 
     if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
         return;
@@ -396,22 +1059,23 @@ void EDA_3D_CANVAS::Draw3D_Track( TRACK*
 
     zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
 
-    SetGLColor( color );
+    MySetGLColor( color, layer );
     glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
 
-    w  = track->m_Width * g_Parm_3D_Visu.m_BoardScale;
-    ox = track->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
-    oy = track->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
-    fx = track->m_End.x * g_Parm_3D_Visu.m_BoardScale;
-    fy = track->m_End.y * g_Parm_3D_Visu.m_BoardScale;
+    w   = track->m_Width * g_Parm_3D_Visu.m_BoardScale;
+    ox  = track->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
+    oy  = track->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
+    fx  = track->m_End.x * g_Parm_3D_Visu.m_BoardScale;
+    fy  = track->m_End.y * g_Parm_3D_Visu.m_BoardScale;
     Draw3D_FilledSegment( ox, -oy, fx, -fy, w, zpos );
 }
 
 
+/* XXX TSP */
 void EDA_3D_CANVAS::Draw3D_SolidPolygonsInZones( ZONE_CONTAINER* aZone )
 {
-    double zpos;
-    int    layer = aZone->GetLayer();
+    double  zpos;
+    int     layer = aZone->GetLayer();
 
     if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
         return;
@@ -425,24 +1089,23 @@ void EDA_3D_CANVAS::Draw3D_SolidPolygons
     g_Parm_3D_Visu.m_ActZpos = zpos;
 
 
-    SetGLColor( color );
+    MySetGLColor( color, layer );
     glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
 
     GLUtesselator* tess = gluNewTess();
-    gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*)() )tessBeginCB );
-    gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*)() )tessEndCB );
-    gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*)() )tessErrorCB );
-    gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*)() )tessCPolyPt2Vertex );
+    gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )tessBeginCB );
+    gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )tessEndCB );
+    gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )tessErrorCB );
+    gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tessCPolyPt2Vertex );
 
     GLdouble v_data[3];
     v_data[2] = zpos;
 
-    //gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
-
     // Draw solid areas contained in this zone
     int StartContour = 1;
 
     std::vector<CPolyPt> polysList = aZone->GetFilledPolysList();
+
     for( unsigned ii = 0; ii < polysList.size(); ii++ )
     {
         if( StartContour == 1 )
@@ -452,8 +1115,8 @@ void EDA_3D_CANVAS::Draw3D_SolidPolygons
             StartContour = 0;
         }
 
-        v_data[0] = polysList[ii].x * g_Parm_3D_Visu.m_BoardScale;
-        v_data[1] = -polysList[ii].y * g_Parm_3D_Visu.m_BoardScale;
+        v_data[0]   = polysList[ii].x * g_Parm_3D_Visu.m_BoardScale;
+        v_data[1]   = -polysList[ii].y * g_Parm_3D_Visu.m_BoardScale;
         gluTessVertex( tess, v_data, &polysList[ii] );
 
         if( polysList[ii].end_contour == 1 )
@@ -470,84 +1133,93 @@ void EDA_3D_CANVAS::Draw3D_SolidPolygons
 
 void EDA_3D_CANVAS::Draw3D_Via( SEGVIA* via )
 {
-    double x, y, r, hole;
-    int    layer, top_layer, bottom_layer;
-    double zpos, height;
-    int    color;
-
-    r     = via->m_Width * g_Parm_3D_Visu.m_BoardScale / 2;
-    hole  = via->GetDrillValue();
-    hole *= g_Parm_3D_Visu.m_BoardScale / 2;
-    x     = via->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
-    y     = via->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
+    double  x, y, r, hole;
+    int     layer, top_layer, bottom_layer;
+    double  zpos, height = 0;
+    int     color;
 
-    via->ReturnLayerPair( &top_layer, &bottom_layer );
+    r = via->m_Width * g_Parm_3D_Visu.m_BoardScale / 2;
+    hole    = via->GetDrillValue();
+    hole    *= g_Parm_3D_Visu.m_BoardScale / 2;
+    x       = via->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
+    y       = via->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
 
-    // Drawing filled circles:
-    for( layer = bottom_layer; layer < g_Parm_3D_Visu.m_Layers; layer++ )
+    if( Get_tmonly() == 0 )
     {
-        zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
-
-        if( layer < g_Parm_3D_Visu.m_Layers - 1 )
-        {
-            if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
-                continue;
+        via->ReturnLayerPair( &top_layer, &bottom_layer );
 
-            color = g_ColorsSettings.GetLayerColor( layer );
-        }
-        else
+        // Drawing filled circles:
+        for( layer = bottom_layer; layer < g_Parm_3D_Visu.m_Layers; layer++ )
         {
-            if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( LAYER_N_FRONT ) == false )
-                continue;
+            zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
 
-            color = g_ColorsSettings.GetLayerColor( LAYER_N_FRONT );
-        }
+            if( layer < g_Parm_3D_Visu.m_Layers - 1 )
+            {
+                if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
+                    continue;
 
-        SetGLColor( color );
+                color = g_ColorsSettings.GetLayerColor( layer );
+            }
+            else
+            {
+                if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( LAYER_N_FRONT ) == false )
+                    continue;
 
-        // SetGLColor( LIGHTGRAY );
-        glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
+                color = g_ColorsSettings.GetLayerColor( LAYER_N_FRONT );
+            }
 
-        if( layer == LAYER_N_BACK )
-            zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
-        else
-            zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
+            MySetGLColor( color, layer );
 
-        Draw3D_FilledCircle( x, -y, r, hole, zpos );
+            glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
 
-        if( layer >= top_layer )
-            break;
-    }
+            if( layer == LAYER_N_BACK )
+                zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
+            else
+                zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
+
+            Draw3D_FilledCircle( x, -y, r, hole, zpos );
+
+            if( layer >= top_layer )
+                break;
+        }
 
-    // Drawing hole:
-    color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + via->m_Shape );
-    SetGLColor( color );
-    height = g_Parm_3D_Visu.m_LayerZcoord[top_layer] - g_Parm_3D_Visu.m_LayerZcoord[bottom_layer];
-    Draw3D_FilledCylinder( x, -y, hole, height, g_Parm_3D_Visu.m_LayerZcoord[bottom_layer] );
+        // Drawing hole:
+        color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + via->m_Shape );
+        MySetGLColor( color, layer );
+        height = g_Parm_3D_Visu.m_LayerZcoord[top_layer] -
+                 g_Parm_3D_Visu.m_LayerZcoord[bottom_layer];
+        Draw3D_FilledCylinder( x, -y, hole, height, g_Parm_3D_Visu.m_LayerZcoord[bottom_layer] );
+    }
+    else
+    {
+        bottom_layer = 0;
+        Draw3D_FilledCylinderMask( x, -y, hole, height,
+                                   g_Parm_3D_Visu.m_LayerZcoord[bottom_layer] );
+    }
 }
 
 
 void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment )
 {
-    double x, y, xf, yf;
-    double zpos, w;
+    double  x, y, xf, yf;
+    double  zpos, w;
 
-    int    layer = segment->GetLayer();
+    int     layer = segment->GetLayer();
 
     if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
         return;
 
     int color = g_ColorsSettings.GetLayerColor( layer );
 
-    SetGLColor( color );
+    MySetGLColor( color, layer );
 
-    w  = segment->GetWidth() * g_Parm_3D_Visu.m_BoardScale;
+    w = segment->GetWidth() * g_Parm_3D_Visu.m_BoardScale;
 
-    x  = segment->GetStart().x * g_Parm_3D_Visu.m_BoardScale;
-    y  = segment->GetStart().y * g_Parm_3D_Visu.m_BoardScale;
+    x   = segment->GetStart().x * g_Parm_3D_Visu.m_BoardScale;
+    y   = segment->GetStart().y * g_Parm_3D_Visu.m_BoardScale;
 
-    xf = segment->GetEnd().x * g_Parm_3D_Visu.m_BoardScale;
-    yf = segment->GetEnd().y * g_Parm_3D_Visu.m_BoardScale;
+    xf  = segment->GetEnd().x * g_Parm_3D_Visu.m_BoardScale;
+    yf  = segment->GetEnd().y * g_Parm_3D_Visu.m_BoardScale;
 
     if( layer == EDGE_N )
     {
@@ -560,14 +1232,32 @@ void EDA_3D_CANVAS::Draw3D_DrawSegment(
             {
             case S_ARC:
                 Draw3D_ArcSegment( x, -y, xf, -yf, segment->GetAngle(), w, zpos );
+
+                if( layer == 1 )
+                {
+                    Draw3D_ArcSegmentMask( x, -y, xf, -yf, segment->GetAngle(), w, zpos );
+                }
+
                 break;
 
             case S_CIRCLE:
                 Draw3D_CircleSegment( x, -y, xf, -yf, w, zpos );
+
+                if( layer == 1 )
+                {
+                    Draw3D_CircleSegmentMask( x, y, xf, yf, w, zpos );
+                }
+
                 break;
 
             default:
                 Draw3D_FilledSegment( x, -y, xf, -yf, w, zpos );
+
+                if( layer == 1 )
+                {
+                    Draw3D_Mask( x, y, xf, yf, w, zpos );
+                }
+
                 break;
             }
         }
@@ -601,10 +1291,10 @@ void EDA_3D_CANVAS::Draw3D_DrawSegment(
 static double s_Text3DWidth, s_Text3DZPos;
 static void Draw3dTextSegm( int x0, int y0, int xf, int yf )
 {
-    double startx = x0 * g_Parm_3D_Visu.m_BoardScale;
-    double starty = y0 * g_Parm_3D_Visu.m_BoardScale;
-    double endx   = xf * g_Parm_3D_Visu.m_BoardScale;
-    double endy   = yf * g_Parm_3D_Visu.m_BoardScale;
+    double  startx  = x0 * g_Parm_3D_Visu.m_BoardScale;
+    double  starty  = y0 * g_Parm_3D_Visu.m_BoardScale;
+    double  endx    = xf * g_Parm_3D_Visu.m_BoardScale;
+    double  endy    = yf * g_Parm_3D_Visu.m_BoardScale;
 
     Draw3D_FilledSegment( startx, -starty, endx, -endy, s_Text3DWidth, s_Text3DZPos );
 }
@@ -618,10 +1308,9 @@ void EDA_3D_CANVAS::Draw3D_DrawText( TEX
         return;
 
     int color = g_ColorsSettings.GetLayerColor( layer );
-
-    SetGLColor( color );
-    s_Text3DZPos  = g_Parm_3D_Visu.m_LayerZcoord[layer];
-    s_Text3DWidth = text->GetThickness() * g_Parm_3D_Visu.m_BoardScale;
+    MySetGLColor( color, layer );
+    s_Text3DZPos    = g_Parm_3D_Visu.m_LayerZcoord[layer];
+    s_Text3DWidth   = text->GetThickness() * g_Parm_3D_Visu.m_BoardScale;
     glNormal3f( 0.0, 0.0, Get3DLayerSide( layer ) );
     wxSize size = text->m_Size;
 
@@ -630,9 +1319,9 @@ void EDA_3D_CANVAS::Draw3D_DrawText( TEX
 
     if( text->m_MultilineAllowed )
     {
-        wxPoint        pos  = text->m_Pos;
-        wxArrayString* list = wxStringSplit( text->m_Text, '\n' );
-        wxPoint        offset;
+        wxPoint         pos     = text->m_Pos;
+        wxArrayString*  list    = wxStringSplit( text->m_Text, '\n' );
+        wxPoint         offset;
 
         offset.y = text->GetInterline();
 
@@ -663,24 +1352,93 @@ void EDA_3D_CANVAS::Draw3D_DrawText( TEX
 }
 
 
+void EDA_3D_CANVAS::Draw3D_DrawText( TEXTE_MODULE* text, double rot )
+{
+    int layer = text->GetLayer();
+
+    int color = g_ColorsSettings.GetLayerColor( layer );
+
+    MySetGLColor( color, layer );
+    s_Text3DZPos    = g_Parm_3D_Visu.m_LayerZcoord[layer];
+    s_Text3DWidth   = text->GetThickness() * g_Parm_3D_Visu.m_BoardScale;
+    glNormal3f( 0.0, 0.0, Get3DLayerSide( layer ) );
+    wxSize size = text->m_Size;
+
+    if( text->m_Mirror )
+        NEGATE( size.x );
+
+    if( text->m_MultilineAllowed )
+    {
+        wxPoint         pos     = text->m_Pos;
+        wxArrayString*  list    = wxStringSplit( text->m_Text, '\n' );
+        wxPoint         offset;
+        double          newrot = text->GetOrientation() + rot;
+
+        while( newrot < -900.0 )
+            newrot += 1800.0;
+
+        while( newrot > 900.0 )
+            newrot -= 1800.0;
+
+        offset.y = text->GetInterline();
+
+        RotatePoint( &offset, text->GetOrientation() + rot );
+
+        for( unsigned i = 0; i<list->Count(); i++ )
+        {
+            wxString txt = list->Item( i );
+            DrawGraphicText( NULL, NULL, pos, (EDA_COLOR_T) color,
+                             txt, newrot, size,
+                             text->m_HJustify, text->m_VJustify,
+                             text->GetThickness(), text->m_Italic,
+                             true, Draw3dTextSegm );
+            pos += offset;
+        }
+
+        delete list;
+    }
+    else
+    {
+        double newrot = text->GetOrientation() + rot;
+
+        while( newrot < -900.0 )
+            newrot += 1800.0;
+
+        while( newrot > 900.0 )
+            newrot -= 1800.0;
+
+        DrawGraphicText( NULL, NULL, text->m_Pos, (EDA_COLOR_T) color,
+                         text->m_Text, newrot, size,
+                         text->m_HJustify, text->m_VJustify,
+                         text->GetThickness(), text->m_Italic,
+                         true,
+                         Draw3dTextSegm );
+    }
+}
+
+
 void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
 {
     D_PAD* pad = m_Pads;
 
     // Draw pads
     glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
-    glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
+    glNormal3f( 0.0, 0.0, 1.0 );    // Normal is Z axis
+
 
     for( ; pad != NULL; pad = pad->Next() )
     {
         pad->Draw3D( glcanvas );
     }
 
+    if( Get_tmonly() )
+        return;
+
     // Draw module shape: 3D shape if exists (or module outlines if not exists)
-    S3D_MASTER* Struct3D  = m_3D_Drawings;
-    bool        As3dShape = false;
+    S3D_MASTER* Struct3D    = m_3D_Drawings;
+    bool        As3dShape   = false;
 
-    if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_MODULE])
+    if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_MODULE] )
     {
         glPushMatrix();
 
@@ -705,8 +1463,109 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glca
         {
             if( !Struct3D->m_Shape3DName.IsEmpty() )
             {
+                std::vector<S3D_Vertex> minmax;
+                Struct3D->m_MinPos.x    = Struct3D->m_MinPos.y = Struct3D->m_MinPos.z = 1E30;
+                Struct3D->m_MaxPos.x    = Struct3D->m_MaxPos.y = Struct3D->m_MaxPos.z = -1E30;
                 As3dShape = true;
                 Struct3D->ReadData();
+                minmax.push_back( Struct3D->m_MinPos );
+                minmax.push_back( Struct3D->m_MaxPos );
+                Struct3D->Set_Object_Coords( minmax );
+                double  hi  = minmax[1].y - minmax[0].y;
+                double  hix = minmax[1].x - minmax[0].x;
+
+                if( hi < 0 )
+                    hi = -hi;
+
+                if( hix < 0 )
+                    hix = -hix;
+
+                if( do_values )
+                {
+                    wxString    txt = m_Value->m_Text;
+                    wxPoint     pos;
+                    wxSize      size;
+                    pos.x   = 0;
+                    pos.y   = 0;
+
+                    if( hi > 0.5 )
+                        hi = 0.5;
+
+                    size.x  = (int) (hi * 300);
+                    size.y  = (int) (hi * 300);
+                    glPushMatrix();
+                    glTranslatef( 0,
+                                  0,
+                                  g_Parm_3D_Visu.m_BoardScale * minmax[1].z * 1000.0 - 0 *
+                                  g_Parm_3D_Visu.m_LayerZcoord[m_Layer] );
+                    glColor4f( 0.2, 0.2, 0.2, 0.7 );
+                    s_Text3DWidth   = 100 * g_Parm_3D_Visu.m_BoardScale;
+                    s_Text3DZPos    = g_Parm_3D_Visu.m_BoardScale * 9;
+                    glTranslatef(
+                        g_Parm_3D_Visu.m_BoardScale * 1000 * (minmax[1].x + minmax[0].x) / 2,
+                        g_Parm_3D_Visu.m_BoardScale * 1000 * (minmax[1].y + minmax[0].y) / 2,
+                        0 );
+                    double  o   = m_Orient;
+                    double  ro  = 0;
+
+                    while( o < -900.0 )
+                    {
+                        o += 1800.0; ro += 180;
+                    }
+
+                    while( o > 900.0 )
+                    {
+                        o -= 1800.0; ro -= 180;
+                    }
+
+                    glRotatef( -ro, 0.0, 0.0, 1.0 );
+                    double  bscf    = g_Parm_3D_Visu.m_BoardScale;
+                    double  scf     = 1e-4;
+                    double  pw      = scf * 1000 * fabs( minmax[1].x - minmax[0].x );
+                    double  ph      = scf * 1000 * fabs( minmax[1].y - minmax[0].y );
+                    double  slen    = NegableTextLength( txt );
+
+                    if( slen > 0 )
+                    {
+                        size.x = (int) ( (10000 * pw) / (slen + 1) );
+
+                        if( size.x < 100 )
+                            size.x = 100;
+
+                        if( size.x > 400 )
+                            size.x = 400;
+
+                        size.y = (size.x * 120) / 100;
+
+                        if( size.y > 10000.0 * ph / 1.8 )
+                        {
+                            size.y  = (int) ( (10000.0 * ph / 1.8) );
+                            size.x  = (size.y * 100) / 120;
+                        }
+
+                        pw = size.x * (slen) * bscf;
+                        double ph = 1.5 * size.y * bscf;
+                        {
+                            glBegin( GL_POLYGON );
+                            glVertex3f( pw / 2, ph / 2, s_Text3DZPos );
+                            glVertex3f( pw / 2, -ph / 2, s_Text3DZPos );
+                            glVertex3f( -pw / 2, -ph / 2, s_Text3DZPos );
+                            glVertex3f( -pw / 2, ph / 2, s_Text3DZPos );
+                            glEnd();
+                        }
+                        glColor3f( 0.8, 0.8, 0.8 );
+                        glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
+                        s_Text3DZPos    = g_Parm_3D_Visu.m_BoardScale * 10;
+                        s_Text3DWidth   = 20 * g_Parm_3D_Visu.m_BoardScale;
+                        DrawGraphicText( NULL, NULL, pos, RED,
+                                         txt, 0, size,
+                                         GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER,
+                                         20, 0, true,
+                                         Draw3dTextSegm );
+                    }
+
+                    glPopMatrix();
+                }
             }
         }
 
@@ -714,7 +1573,7 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glca
     }
 
     EDA_ITEM* Struct = m_Drawings;
-    glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
+    glNormal3f( 0.0, 0.0, 1.0 );    // Normal is Z axis
 
     for( ; Struct != NULL; Struct = Struct->Next() )
     {
@@ -724,15 +1583,16 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glca
             break;
 
         case PCB_MODULE_EDGE_T:
-        {
-            EDGE_MODULE* edge = (EDGE_MODULE*) Struct;
+            {
+                EDGE_MODULE* edge = (EDGE_MODULE*) Struct;
 
-            // Draw module edges when no 3d shape exists.
-            // Always draw pcb edges.
-            if( !As3dShape || edge->GetLayer() == EDGE_N )
-                edge->Draw3D( glcanvas );
-        }
-        break;
+                // Draw module edges when no 3d shape exists.
+                // Always draw pcb edges.
+                /* if( !As3dShape || edge->GetLayer() == EDGE_N ) */ {
+                    edge->Draw3D( glcanvas );
+                }
+            }
+            break;
 
         default:
             break;
@@ -743,24 +1603,24 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glca
 
 void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
 {
-    wxString s;
-    int      dx, dy;
-    double   x, y, fx, fy, w, zpos;
+    wxString    s;
+    int         dx, dy;
+    double      x, y, fx, fy, w, zpos;
 
     if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( m_Layer ) == false )
         return;
 
     int color = g_ColorsSettings.GetLayerColor( m_Layer );
 
-    SetGLColor( color );
+    MySetGLColor( color, m_Layer );
 
-    dx   = m_End.x;
-    dy   = m_End.y;
-    w    = m_Width * g_Parm_3D_Visu.m_BoardScale;
-    x    = m_Start.x * g_Parm_3D_Visu.m_BoardScale;
-    y    = m_Start.y * g_Parm_3D_Visu.m_BoardScale;
-    fx   = dx * g_Parm_3D_Visu.m_BoardScale;
-    fy   = dy * g_Parm_3D_Visu.m_BoardScale;
+    dx  = m_End.x;
+    dy  = m_End.y;
+    w   = m_Width * g_Parm_3D_Visu.m_BoardScale;
+    x   = m_Start.x * g_Parm_3D_Visu.m_BoardScale;
+    y   = m_Start.y * g_Parm_3D_Visu.m_BoardScale;
+    fx  = dx * g_Parm_3D_Visu.m_BoardScale;
+    fy  = dy * g_Parm_3D_Visu.m_BoardScale;
 
 
     if( m_Layer == EDGE_N )
@@ -785,26 +1645,26 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS*
                 break;
 
             case S_POLYGON:
-            {
-                // We must compute true coordinates from m_PolyPoints
-                // which are relative to module position and module orientation = 0
-                std::vector<wxPoint> points = m_PolyPoints;
-                MODULE* module = (MODULE*) m_Parent;
+                {
+                    // We must compute true coordinates from m_PolyPoints
+                    // which are relative to module position and module orientation = 0
+                    std::vector<wxPoint> points = m_PolyPoints;
+                    MODULE* module = (MODULE*) m_Parent;
 
-                if( module == NULL )
-                    break;
+                    if( module == NULL )
+                        break;
 
-                for( unsigned ii = 0; ii < points.size(); ii++ )
-                {
-                    wxPoint& pt = points[ii];
+                    for( unsigned ii = 0; ii < points.size(); ii++ )
+                    {
+                        wxPoint& pt = points[ii];
 
-                    RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
-                    pt += module->m_Pos;
-                }
+                        RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
+                        pt += module->m_Pos;
+                    }
 
-                glcanvas->Draw3D_Polygon( points, zpos );
-            }
-            break;
+                    glcanvas->Draw3D_Polygon( points, zpos );
+                }
+                break;
 
             default:
                 s.Printf( wxT( "Error: Shape nr %d not implemented!\n" ), m_Shape );
@@ -815,7 +1675,9 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS*
     }
     else
     {
-        glNormal3f( 0.0, 0.0, (m_Layer == LAYER_N_BACK) ? -1.0 : 1.0 );
+        glNormal3f( 0.0,
+                    0.0,
+                    ( (m_Layer == LAYER_N_BACK) || (m_Layer == SILKSCREEN_N_BACK) ) ? -1.0 : 1.0 );
         zpos = g_Parm_3D_Visu.m_LayerZcoord[m_Layer];
 
         switch( m_Shape )
@@ -833,26 +1695,26 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS*
             break;
 
         case S_POLYGON:
-        {
-            // We must compute true coordinates from m_PolyPoints
-            // which are relative to module position and module orientation = 0
-            std::vector<wxPoint> points = m_PolyPoints;
-            MODULE* module = (MODULE*) m_Parent;
+            {
+                // We must compute true coordinates from m_PolyPoints
+                // which are relative to module position and module orientation = 0
+                std::vector<wxPoint> points = m_PolyPoints;
+                MODULE* module = (MODULE*) m_Parent;
 
-            if( module == NULL )
-                break;
+                if( module == NULL )
+                    break;
 
-            for( unsigned ii = 0; ii < points.size(); ii++ )
-            {
-                wxPoint& pt = points[ii];
+                for( unsigned ii = 0; ii < points.size(); ii++ )
+                {
+                    wxPoint& pt = points[ii];
 
-                RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
-                pt += module->m_Pos;
-            }
+                    RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
+                    pt += module->m_Pos;
+                }
 
-            glcanvas->Draw3D_Polygon( points, zpos );
-        }
-        break;
+                glcanvas->Draw3D_Polygon( points, zpos );
+            }
+            break;
 
         default:
             s.Printf( wxT( "Error: Shape nr %d not implemented!\n" ), m_Shape );
@@ -879,46 +1741,258 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcan
     double  drillx, drilly;
     bool    Oncu, Oncmp, Both;
     int     color;
-
-    scale = g_Parm_3D_Visu.m_BoardScale;
-    holeX = (double) m_Drill.x * scale / 2;
-    holeY = (double) m_Drill.y * scale / 2;
-    hole  = fmin( holeX, holeY );
+    double  rm  = GetSolderMaskMargin();
+    wxSize  rp  = GetSolderPasteMargin();
+    double  offX, offY;
+
+    scale   = g_Parm_3D_Visu.m_BoardScale;
+    holeX   = (double) m_Drill.x * scale / 2;
+    holeY   = (double) m_Drill.y * scale / 2;
+    offX    = (double) m_Offset.x * scale;
+    offY    = (double) m_Offset.y * scale;
+    hole    = fmin( holeX, holeY );
 
     // Calculate the center of the pad.
-    shape_pos = ReturnShapePos();
+    // shape_pos = ReturnShapePos();
+    shape_pos = m_Pos;
     ux0 = shape_pos.x;
     uy0 = shape_pos.y;
     xc  = ux0;
     yc  = uy0;
 
-    dx = dx0 = m_Size.x >> 1;
-    dy = dy0 = m_Size.y >> 1;
+    dx  = dx0 = m_Size.x / 2;
+    dy  = dy0 = m_Size.y / 2;
+
+    angle   = m_Orient;
+    drillx  = m_Pos.x * scale;
+    drilly  = m_Pos.y * scale;
+
+    if( (tmonly & 1) == 1 )
+    {
+        // glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
+        nlmax   = g_Parm_3D_Visu.m_Layers - 1;
+        Oncu    = (m_layerMask & LAYER_BACK) ? true : false;
+        Oncmp   = (m_layerMask & LAYER_FRONT) ? true : false;
+        Both    = Oncu && Oncmp;
+
+        switch( m_PadShape & 0x7F )
+        {
+        case PAD_CIRCLE:
+            x   = xc * scale;
+            y   = yc * scale;
+            r   = (double) dx * scale;
+            rm  *= scale;
+
+            layer = (tmonly & 2) ? SOLDERMASK_N_BACK : SOLDERMASK_N_FRONT;
+
+            if( ( (1 << layer) & m_layerMask ) != 0 )
+            {
+    #define ZLO ( 9 - ( (layer & 6) >> 1 ) )
+                Draw3D_FilledCircleMask( x, -y, r + rm, hole, zpos );
+            }
+            break;
+
+        case PAD_OVAL:
+            rm *= scale;
+
+            if( dx > dy )    // Horizontal ellipse
+            {
+                delta_cx    = dx - dy;
+                delta_cy    = 0;
+                w = m_Size.y * scale;
+            }
+            else    // Vertical ellipse
+            {
+                delta_cx    = 0;
+                delta_cy    = dy - dx;
+                w = m_Size.x * scale;
+            }
+
+            RotatePoint( &delta_cx, &delta_cy, angle );
+
+            {
+                double ox, oy, fx, fy;
+                ox  = (double) ( ux0 + delta_cx ) * scale;
+                oy  = (double) ( uy0 + delta_cy ) * scale;
+                fx  = (double) ( ux0 - delta_cx ) * scale;
+                fy  = (double) ( uy0 - delta_cy ) * scale;
+
+                layer = (tmonly & 2) ? SOLDERMASK_N_BACK : SOLDERMASK_N_FRONT;
+
+                if( ( (1 << layer) & m_layerMask ) != 0 )
+                {
+                    RotatePoint( &offX, &offY, angle );
+                    Draw3D_FilledSegmentWithHoleMask( ox,
+                                                      -oy,
+                                                      fx,
+                                                      -fy,
+                                                      w + rm,
+                                                      drillx,
+                                                      -drilly,
+                                                      hole,
+                                                      zpos,
+                                                      offX,
+                                                      offY );
+                }
+            }
+            break;
+
+        case PAD_RECT:
+        case PAD_TRAPEZOID:
+            {
+                wxPoint     coord[5];
+                wxRealPoint fcoord[8], f_hole_coord[8];
+                layer = (tmonly & 2) ? SOLDERMASK_N_BACK : SOLDERMASK_N_FRONT;
+
+                if( ( (1 << layer) & m_layerMask ) != 0 )
+                {
+                    wxSize lrp;
+                    lrp.x   = rm;
+                    lrp.y   = rm;
+                    BuildPadPolygon( coord, lrp, angle );
+
+                    for( ii = 0; ii < 4; ii++ )
+                    {
+                        coord[ii].x += ux0;
+                        coord[ii].y += uy0;
+                        ll = ii * 2;
+                        fcoord[ll].x    = coord[ii].x * scale;
+                        fcoord[ll].y    = coord[ii].y * scale;
+                    }
+
+                    for( ii = 0; ii < 7; ii += 2 )
+                    {
+                        ll = ll + 2;
+
+                        if( ll > 7 )
+                            ll -= 8;
+
+                        fcoord[ii + 1].x    = (fcoord[ii].x + fcoord[ll].x) / 2;
+                        fcoord[ii + 1].y    = (fcoord[ii].y + fcoord[ll].y) / 2;
+                    }
+
+                    for( ii = 0; ii < 8; ii++ )
+                    {
+                        f_hole_coord[ii].x  = -hole * 0.707;
+                        f_hole_coord[ii].y  = hole * 0.707;
+                        RotatePoint( &f_hole_coord[ii].x, &f_hole_coord[ii].y, angle -
+                                     (ii * 450) );
+                        f_hole_coord[ii].x  += drillx;
+                        f_hole_coord[ii].y  += drilly;
+                    }
+
+                    for( ii = 0; ii < 4; ii++ )
+                    {
+                        p_data.push_back( CPolyPt( coord[ii].x, coord[ii].y ) );
+                        pii++;
+                    }
+                }
+            }
+            break;
+
+        default:
+            break;
+        }
+        return;
+    }
+    else if( tmonly == 2 )
+    {
+        // Draw the pad hole
+        if( holeX && holeY )
+        {
+            if( holeX == holeY )
+            {
+                Draw3D_FilledCylinderMask( drillx, -drilly, hole,
+                                           g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_FRONT], 0.0 );
+            }
+            else
+            {
+                if( dx > dy )    // Horizontal oval
+                {
+                    delta_cx    = dx - dy;
+                    delta_cy    = 0;
+                    w = m_Size.y * scale;
+                }
+                else    // Vertical oval
+                {
+                    delta_cx    = 0;
+                    delta_cy    = dy - dx;
+                    w = m_Size.x * scale;
+                }
+
+                RotatePoint( &delta_cx, &delta_cy, angle );
+
+                {
+                    double ox, oy, fx, fy;
+                    ox  = (double) ( ux0 + delta_cx ) * scale;
+                    oy  = (double) ( uy0 + delta_cy ) * scale;
+                    fx  = (double) ( ux0 - delta_cx ) * scale;
+                    fy  = (double) ( uy0 - delta_cy ) * scale;
+
+                    double height = g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_FRONT];
+                    Draw3D_FilledOblongMask( ox, -oy, fx, -fy, drillx, -drilly, hole, height,
+                                             0.0 );
+                }
+            }
+        }
 
-    angle  = m_Orient;
-    drillx = m_Pos.x * scale;
-    drilly = m_Pos.y * scale;
+        return;
+    }
 
-    // Draw the pad hole (TODO: draw OBLONG hole)
+    // Draw the pad hole
     if( holeX && holeY )
     {
         SetGLColor( DARKGRAY );
-        Draw3D_FilledCylinder( drillx, -drilly, hole,
-                               g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_FRONT], 0.0 );
+
+        if( holeX == holeY )
+        {
+            Draw3D_FilledCylinder( drillx, -drilly, hole,
+                                   g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_FRONT], 0.0 );
+        }
+        else
+        {
+            if( dx > dy )    // Horizontal oval
+            {
+                delta_cx    = dx - dy;
+                delta_cy    = 0;
+                w = m_Size.y * scale;
+            }
+            else    // Vertical oval
+            {
+                delta_cx    = 0;
+                delta_cy    = dy - dx;
+                w = m_Size.x * scale;
+            }
+
+            RotatePoint( &delta_cx, &delta_cy, angle );
+
+            {
+                double ox, oy, fx, fy;
+                ox  = (double) ( ux0 + delta_cx ) * scale;
+                oy  = (double) ( uy0 + delta_cy ) * scale;
+                fx  = (double) ( ux0 - delta_cx ) * scale;
+                fy  = (double) ( uy0 - delta_cy ) * scale;
+
+                double height = g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_FRONT];
+                Draw3D_FilledOblong( ox, -oy, fx, -fy, drillx, -drilly, hole, height, 0.0 );
+            }
+        }
     }
 
-    glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
-    nlmax = g_Parm_3D_Visu.m_Layers - 1;
-    Oncu  = (m_layerMask & LAYER_BACK) ? true : false;
-    Oncmp = (m_layerMask & LAYER_FRONT) ? true : false;
-    Both  = Oncu && Oncmp;
+    glNormal3f( 0.0, 0.0, 1.0 );    // Normal is Z axis
+    nlmax   = g_Parm_3D_Visu.m_Layers - 1;
+    Oncu    = (m_layerMask & LAYER_BACK) ? true : false;
+    Oncmp   = (m_layerMask & LAYER_FRONT) ? true : false;
+    Both    = Oncu && Oncmp;
 
     switch( m_PadShape & 0x7F )
     {
     case PAD_CIRCLE:
-        x = xc * scale;
-        y = yc * scale;
-        r = (double) dx * scale;
+        x   = xc * scale;
+        y   = yc * scale;
+        r   = (double) dx * scale;
+        rp  *= scale;
+        rm  *= scale;
 
         for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
         {
@@ -939,31 +2013,65 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcan
             if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
                 continue;
 
-            SetGLColor( color );
+            MySetGLColor( color, layer );
             glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
             zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
+            Draw3D_FilledCircle( x, -y, r, hole, zpos );
+        }
 
-            if( layer == LAYER_N_BACK )
-                zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
+#ifdef TSP_20120407
+
+        for( layer = FIRST_NO_COPPER_LAYER; layer <= SILKSCREEN_N_FRONT; layer++ )
+        {
+            if( ( (1 << layer) & m_layerMask ) == 0 )
+                continue;
+
+            color = g_ColorsSettings.GetLayerColor( layer );
+
+
+            if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
+                continue;
+
+            MySetGLColor( color, layer );
+            glNormal3f( 0.0, 0.0, (layer & 1) ? 1.0 : -1.0 );
+            zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
+
+            if( (layer & 1) == 0 )
+                zpos = zpos - ZLO * g_Parm_3D_Visu.m_BoardScale;
             else
-                zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
+                zpos = zpos + ZLO * g_Parm_3D_Visu.m_BoardScale;
 
-            Draw3D_FilledCircle( x, -y, r, hole, zpos );
+            if( (layer == SOLDERPASTE_N_BACK) || (layer == SOLDERPASTE_N_FRONT) )
+            {
+                Draw3D_FilledCircle( x, -y, r + rp.x, hole, zpos );
+            }
+            else if( (layer == SILKSCREEN_N_BACK) || (layer == SILKSCREEN_N_FRONT) )
+            {
+            }
+            else
+            {
+                Draw3D_FilledCircle( x, -y, r, hole, zpos );
+            }
         }
 
+#endif    // TSP_20120407
+
         break;
 
     case PAD_OVAL:
-        if( dx > dy ) // Horizontal ellipse
+        rp  *= scale;
+        rm  *= scale;
+
+        if( dx > dy )    // Horizontal ellipse
         {
-            delta_cx = dx - dy;
-            delta_cy = 0;
+            delta_cx    = dx - dy;
+            delta_cy    = 0;
             w = m_Size.y * scale;
         }
-        else // Vertical ellipse
+        else    // Vertical ellipse
         {
-            delta_cx = 0;
-            delta_cy = dy - dx;
+            delta_cx    = 0;
+            delta_cy    = dy - dx;
             w = m_Size.x * scale;
         }
 
@@ -971,10 +2079,10 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcan
 
         {
             double ox, oy, fx, fy;
-            ox = (double) ( ux0 + delta_cx ) * scale;
-            oy = (double) ( uy0 + delta_cy ) * scale;
-            fx = (double) ( ux0 - delta_cx ) * scale;
-            fy = (double) ( uy0 - delta_cy ) * scale;
+            ox  = (double) ( ux0 + delta_cx ) * scale;
+            oy  = (double) ( uy0 + delta_cy ) * scale;
+            fx  = (double) ( ux0 - delta_cx ) * scale;
+            fy  = (double) ( uy0 - delta_cy ) * scale;
 
             for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
             {
@@ -996,7 +2104,7 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcan
                 if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
                     continue;
 
-                SetGLColor( color );
+                MySetGLColor( color, layer );
                 zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
 
                 if( layer == LAYER_N_BACK )
@@ -1004,90 +2112,292 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcan
                 else
                     zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
 
-                Draw3D_FilledSegmentWithHole( ox, -oy, fx, -fy, w, drillx, -drilly, hole, zpos );
+                RotatePoint( &offX, &offY, angle );
+
+                if( holeX == holeY )
+                {
+                    Draw3D_FilledSegmentWithHole( ox,
+                                                  -oy,
+                                                  fx,
+                                                  -fy,
+                                                  w,
+                                                  drillx,
+                                                  -drilly,
+                                                  hole,
+                                                  zpos,
+                                                  offX,
+                                                  offY );
+                }
+                else
+                {
+                    if( dx > dy )    // Horizontal oval
+                    {
+                        delta_cx    = dx - dy;
+                        delta_cy    = 0;
+                        w = m_Size.y * scale;
+                    }
+                    else    // Vertical oval
+                    {
+                        delta_cx    = 0;
+                        delta_cy    = dy - dx;
+                        w = m_Size.x * scale;
+                    }
+
+                    RotatePoint( &delta_cx, &delta_cy, angle );
+
+                    {
+                        double ox, oy, fx, fy;
+                        ox  = (double) ( ux0 + delta_cx ) * scale;
+                        oy  = (double) ( uy0 + delta_cy ) * scale;
+                        fx  = (double) ( ux0 - delta_cx ) * scale;
+                        fy  = (double) ( uy0 - delta_cy ) * scale;
+
+                        Draw3D_FilledSegmentWithHole( ox,
+                                                      -oy,
+                                                      fx,
+                                                      -fy,
+                                                      w,
+                                                      drillx,
+                                                      -drilly,
+                                                      hole,
+                                                      zpos,
+                                                      offX,
+                                                      offY );
+                    }
+                }
+            }
+
+#ifdef TSP_20120407
+
+            for( layer = FIRST_NO_COPPER_LAYER; layer <= SILKSCREEN_N_FRONT; layer++ )
+            {
+                if( ( (1 << layer) & m_layerMask ) == 0 )
+                    continue;
+
+                if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
+                    continue;
+
+                color = g_ColorsSettings.GetLayerColor( layer );
+                glNormal3f( 0.0, 0.0, (layer & 1) ? 1.0 : -1.0 );
+
+                SetGLColor( color );
+                zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
+
+                if( layer & 1 )
+                    zpos = zpos + ZLO * g_Parm_3D_Visu.m_BoardScale;
+                else
+                    zpos = zpos - ZLO * g_Parm_3D_Visu.m_BoardScale;
+
+                RotatePoint( &offX, &offY, angle );
+
+                if( (layer == SOLDERPASTE_N_BACK) || (layer == SOLDERPASTE_N_FRONT) )
+                {
+                    Draw3D_FilledSegmentWithHole( ox,
+                                                  -oy,
+                                                  fx,
+                                                  -fy,
+                                                  w + rp.x,
+                                                  drillx,
+                                                  -drilly,
+                                                  hole,
+                                                  zpos,
+                                                  offX,
+                                                  offY );
+                }
+                else if( (layer == SILKSCREEN_N_BACK) || (layer == SILKSCREEN_N_FRONT) )
+                {
+                }
+                else
+                {
+                    Draw3D_FilledSegmentWithHole( ox,
+                                                  -oy,
+                                                  fx,
+                                                  -fy,
+                                                  w,
+                                                  drillx,
+                                                  -drilly,
+                                                  hole,
+                                                  zpos,
+                                                  offX,
+                                                  offY );
+                }
             }
+
+#endif      // TSP_20120407
         }
 
         break;
 
     case PAD_RECT:
     case PAD_TRAPEZOID:
-    {
-        wxPoint  coord[5];
-        wxRealPoint  fcoord[8], f_hole_coord[8];
-        BuildPadPolygon( coord, wxSize(0,0), angle );
-
-        for( ii = 0; ii < 4; ii++ )
         {
-            coord[ii].x += ux0;
-            coord[ii].y += uy0;
-            ll = ii * 2;
-            fcoord[ll].x = coord[ii].x *scale;
-            fcoord[ll].y = coord[ii].y *scale;
-        }
+            wxPoint coord[5];
+            wxRealPoint fcoord[8], f_hole_coord[8];
+            {
+                BuildPadPolygon( coord, wxSize( 0, 0 ), angle );
 
-        for( ii = 0; ii < 7; ii += 2 )
-        {
-            ll = ii + 2;
+                for( ii = 0; ii < 4; ii++ )
+                {
+                    coord[ii].x += ux0;
+                    coord[ii].y += uy0;
+                    ll = ii * 2;
+                    fcoord[ll].x    = coord[ii].x * scale;
+                    fcoord[ll].y    = coord[ii].y * scale;
+                }
+
+                for( ii = 0; ii < 7; ii += 2 )
+                {
+                    ll = ll + 2;
 
-            if( ll > 7 )
-                ll -= 8;
+                    if( ll > 7 )
+                        ll -= 8;
 
-            fcoord[ii + 1].x = (fcoord[ii].x + fcoord[ll].x) / 2;
-            fcoord[ii + 1].y = (fcoord[ii].y + fcoord[ll].y) / 2;
-        }
+                    fcoord[ii + 1].x    = (fcoord[ii].x + fcoord[ll].x) / 2;
+                    fcoord[ii + 1].y    = (fcoord[ii].y + fcoord[ll].y) / 2;
+                }
 
-        for( ii = 0; ii < 8; ii++ )
-        {
-            f_hole_coord[ii].x = -hole * 0.707;
-            f_hole_coord[ii].y = hole * 0.707;
-            RotatePoint( &f_hole_coord[ii].x, &f_hole_coord[ii].y, angle - (ii * 450) );
-            f_hole_coord[ii].x += drillx;
-            f_hole_coord[ii].y += drilly;
-        }
+                for( ii = 0; ii < 8; ii++ )
+                {
+                    f_hole_coord[ii].x  = -hole * 0.707;
+                    f_hole_coord[ii].y  = hole * 0.707;
+                    RotatePoint( &f_hole_coord[ii].x, &f_hole_coord[ii].y, angle - (ii * 450) );
+                    f_hole_coord[ii].x  += drillx;
+                    f_hole_coord[ii].y  += drilly;
+                }
+            }
 
-        for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
-        {
-            if( layer && (layer == nlmax) )
-                layer = LAYER_N_FRONT;
+            for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
+            {
+                if( layer && (layer == nlmax) )
+                    layer = LAYER_N_FRONT;
 
-            if( (layer == LAYER_N_FRONT) && !Oncmp )
-                continue;
+                if( (layer == LAYER_N_FRONT) && !Oncmp )
+                    continue;
 
-            if( (layer == LAYER_N_BACK) && !Oncu )
-                continue;
+                if( (layer == LAYER_N_BACK) && !Oncu )
+                    continue;
 
-            if( (layer > FIRST_COPPER_LAYER) && (layer < LAST_COPPER_LAYER) && !Both )
-                continue;
+                if( (layer > FIRST_COPPER_LAYER) && (layer < LAST_COPPER_LAYER) && !Both )
+                    continue;
 
-            color = g_ColorsSettings.GetLayerColor( layer );
-            glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
+                color = g_ColorsSettings.GetLayerColor( layer );
+                glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
 
-            if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
-                continue;
+                if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
+                    continue;
 
-            SetGLColor( color );
-            zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
+                MySetGLColor( color, layer );
+                zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
 
-            if( layer == LAYER_N_BACK )
-                zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
-            else
-                zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
+                if( layer == LAYER_N_BACK )
+                    zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
+                else
+                    zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
+
+                glBegin( GL_QUAD_STRIP );
+
+                for( ii = 0; ii < 8; ii++ )
+                {
+                    glVertex3f( f_hole_coord[ii].x, -f_hole_coord[ii].y, zpos );
+                    glVertex3f( fcoord[ii].x, -fcoord[ii].y, zpos );
+                }
+
+                glVertex3f( f_hole_coord[0].x, -f_hole_coord[0].y, zpos );
+                glVertex3f( fcoord[0].x, -fcoord[0].y, zpos );
+                glEnd();
+            }
 
-            glBegin( GL_QUAD_STRIP );
+#ifdef TSP_20120407
 
-            for( ii = 0; ii < 8; ii++ )
+            for( layer = FIRST_NO_COPPER_LAYER; layer <= SILKSCREEN_N_FRONT; layer++ )
             {
-                glVertex3f( f_hole_coord[ii].x, -f_hole_coord[ii].y, zpos );
-                glVertex3f( fcoord[ii].x, -fcoord[ii].y, zpos );
+                if( ( (1 << layer) & m_layerMask ) == 0 )
+                    continue;
+
+                color = g_ColorsSettings.GetLayerColor( layer );
+
+                glNormal3f( 0.0, 0.0, (layer & 1) ? 1.0 : -1.0 );
+
+                if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
+                    continue;
+
+                {
+                    wxSize lrp;
+
+                    if( (layer == SOLDERPASTE_N_BACK) || (layer == SOLDERPASTE_N_FRONT) )
+                    {
+                        lrp = rp;
+                    }
+                    else
+                    {
+                        lrp.x   = 0;
+                        lrp.y   = 0;
+                    }
+
+                    BuildPadPolygon( coord, lrp, angle );
+
+                    for( ii = 0; ii < 4; ii++ )
+                    {
+                        coord[ii].x += ux0;
+                        coord[ii].y += uy0;
+                        ll = ii * 2;
+                        fcoord[ll].x    = coord[ii].x * scale;
+                        fcoord[ll].y    = coord[ii].y * scale;
+                    }
+
+                    for( ii = 0; ii < 7; ii += 2 )
+                    {
+                        ll = ll + 2;
+
+                        if( ll > 7 )
+                            ll -= 8;
+
+                        fcoord[ii + 1].x    = (fcoord[ii].x + fcoord[ll].x) / 2;
+                        fcoord[ii + 1].y    = (fcoord[ii].y + fcoord[ll].y) / 2;
+                    }
+
+                    for( ii = 0; ii < 8; ii++ )
+                    {
+                        f_hole_coord[ii].x  = -hole * 0.707;
+                        f_hole_coord[ii].y  = hole * 0.707;
+                        RotatePoint( &f_hole_coord[ii].x, &f_hole_coord[ii].y, angle -
+                                     (ii * 450) );
+                        f_hole_coord[ii].x  += drillx;
+                        f_hole_coord[ii].y  += drilly;
+                    }
+                }
+
+                SetGLColor( color );
+                zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
+
+                if( layer & 1 )
+                    zpos = zpos + ZLO * g_Parm_3D_Visu.m_BoardScale;
+                else
+                    zpos = zpos - ZLO * g_Parm_3D_Visu.m_BoardScale;
+
+                if( (layer == SILKSCREEN_N_BACK) || (layer == SILKSCREEN_N_FRONT) )
+                {
+                }
+                else
+                {
+                    glBegin( GL_QUAD_STRIP );
+                    {
+                        for( ii = 0; ii < 8; ii++ )
+                        {
+                            glVertex3f( f_hole_coord[ii].x, -f_hole_coord[ii].y, zpos );
+                            glVertex3f( fcoord[ii].x, -fcoord[ii].y, zpos );
+                        }
+
+                        glVertex3f( f_hole_coord[0].x, -f_hole_coord[0].y, zpos );
+                        glVertex3f( fcoord[0].x, -fcoord[0].y, zpos );
+                    }
+                    glEnd();
+                }
             }
 
-            glVertex3f( f_hole_coord[0].x, -f_hole_coord[0].y, zpos );
-            glVertex3f( fcoord[0].x, -fcoord[0].y, zpos );
-            glEnd();
+#endif      // TSP_20120407
         }
-    }
-    break;
+        break;
 
     default:
         break;
@@ -1097,32 +2407,53 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcan
 
 void SetGLColor( int color )
 {
-    double       red, green, blue;
+    double red, green, blue;
     StructColors colordata = ColorRefs[color & MASKCOLOR];
 
-    red   = colordata.m_Red / 255.0;
-    blue  = colordata.m_Blue / 255.0;
-    green = colordata.m_Green / 255.0;
+    red     = colordata.m_Red / 255.0;
+    blue    = colordata.m_Blue / 255.0;
+    green   = colordata.m_Green / 255.0;
     glColor3f( red, green, blue );
 }
 
 
+void MySetGLColor( int color, int layer )
+{
+    double red, green, blue;
+    StructColors colordata = ColorRefs[color & MASKCOLOR];
+
+    if( ( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( SOLDERMASK_N_FRONT )
+          || g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( SOLDERMASK_N_FRONT ) )
+        && (layer < 16) )
+    {
+        glColor3f( 0.6, 0.55, 0.2 );
+    }
+    else
+    {
+        red     = colordata.m_Red / 255.0;
+        blue    = colordata.m_Blue / 255.0;
+        green   = colordata.m_Green / 255.0;
+        glColor3f( red, green, blue );
+    }
+}
+
+
 static void Draw3D_FilledCircle( double posx, double posy,
                                  double rayon, double hole, double zpos )
 {
-    int    ii, slice = 16;
+    int ii, slice = 16;
     double x, y;
 
     glBegin( GL_QUAD_STRIP );
 
     for( ii = 0; ii <= slice; ii++ )
     {
-        x = hole;
-        y = 0.0;
+        x   = hole;
+        y   = 0.0;
         RotatePoint( &x, &y, ii * 225 );
         glVertex3f( x + posx, y + posy, zpos );
-        x = rayon;
-        y = 0.0;
+        x   = rayon;
+        y   = 0.0;
         RotatePoint( &x, &y, ii * 225 );
         glVertex3f( x + posx, y + posy, zpos );
     }
@@ -1131,19 +2462,39 @@ static void Draw3D_FilledCircle( double
 }
 
 
+static void Draw3D_FilledCircleMask( double posx, double posy,
+                                     double rayon, double hole, double zpos )
+{
+    int ii, slice = 16;
+    double x, y;
+
+    for( ii = 0; ii <= slice; ii++ )
+    {
+        x   = rayon;
+        y   = 0.0;
+        RotatePoint( &x, &y, ii * 225.0 );
+        x   = (x + posx) / g_Parm_3D_Visu.m_BoardScale;
+        y   = -( (y + posy) / g_Parm_3D_Visu.m_BoardScale );
+
+        p_data.push_back( CPolyPt( (int) x, (int) y ) );
+        pii++;
+    }
+}
+
+
 static void Draw3D_FilledCylinder( double posx, double posy, double rayon,
                                    double height, double zpos )
 {
-    int        ii;
-    double     x, y;
+    int ii;
+    double x, y;
 
 #define NB_SEGM 12
-    std::vector< S3D_Vertex > coords;
+    std::vector<S3D_Vertex> coords;
     coords.resize( 4 );
 
-    double     tmp = DataScale3D;
+    double tmp = DataScale3D;
 
-    DataScale3D = 1.0; // Coordinate is already in range for Set_Object_Data();
+    DataScale3D = 1.0;    // Coordinate is already in range for Set_Object_Data();
     coords[0].x = coords[1].x = posx + rayon;
     coords[0].y = coords[1].y = posy;
     coords[0].z = coords[3].z = zpos;
@@ -1151,8 +2502,8 @@ static void Draw3D_FilledCylinder( doubl
 
     for( ii = 0; ii <= NB_SEGM; ii++ )
     {
-        x = rayon;
-        y = 0.0;
+        x   = rayon;
+        y   = 0.0;
         RotatePoint( &x, &y, ii * (3600 / NB_SEGM) );
         coords[2].x = coords[3].x = posx + x;
         coords[2].y = coords[3].y = posy + y;
@@ -1163,23 +2514,175 @@ static void Draw3D_FilledCylinder( doubl
         coords[1].y = coords[3].y;
     }
 
-    glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
+    glNormal3f( 0.0, 0.0, 1.0 );    // Normal is Z axis
+    DataScale3D = tmp;
+}
+
+
+static void    Draw3D_FilledOblong( double startx, double starty,
+                                    double endx, double endy,
+                                    double holex,
+                                    double holey, double holeradius,
+                                    double height, double zpos )
+{
+    double ddx, ddy, dx, dy;
+    int ii, angle;
+    std::vector<S3D_Vertex> coords;
+
+    coords.resize( 4 );
+
+    double tmp = DataScale3D;
+
+    DataScale3D = 1.0;    // Coordinate is already in range for Set_Object_Data();
+
+    dx  = endx - startx;
+    dy  = endy - starty;
+    angle   = (int) ( ( atan2( dy, dx ) * 1800 / M_PI ) + 0.5 );
+    dx      = 0;
+    dy      = holeradius;
+    RotatePoint( &dx, &dy, angle );
+    coords[0].x = coords[1].x = startx + dx;
+    coords[0].y = coords[1].y = starty - dy;
+    coords[2].x = coords[3].x = endx + dx;
+    coords[2].y = coords[3].y = endy - dy;
+    coords[0].z = coords[3].z = zpos;
+    coords[1].z = coords[2].z = zpos + height;
+    Set_Object_Data( coords );
+
+    for( ii = 1; ii <= 9; ii++ )
+    {
+        ddx = dx;
+        ddy = -dy;
+        RotatePoint( &ddx, &ddy, -ii * 200 );
+        coords[0].x = coords[2].x;
+        coords[0].y = coords[2].y;
+        coords[1].x = coords[3].x;
+        coords[1].y = coords[3].y;
+        coords[2].x = coords[3].x = endx + ddx;
+        coords[2].y = coords[3].y = endy + ddy;
+        Set_Object_Data( coords );
+    }
+
+    coords[0].x = coords[1].x = endx - dx;
+    coords[0].y = coords[1].y = endy + dy;
+    coords[2].x = coords[3].x = startx - dx;
+    coords[2].y = coords[3].y = starty + dy;
+    coords[0].z = coords[3].z = zpos;
+    coords[1].z = coords[2].z = zpos + height;
+    Set_Object_Data( coords );
+
+    for( ii = 1; ii <= 9; ii++ )
+    {
+        ddx = -dx;
+        ddy = dy;
+        RotatePoint( &ddx, &ddy, -ii * 200 );
+        coords[0].x = coords[2].x;
+        coords[0].y = coords[2].y;
+        coords[1].x = coords[3].x;
+        coords[1].y = coords[3].y;
+        coords[2].x = coords[3].x = startx + ddx;
+        coords[2].y = coords[3].y = starty + ddy;
+        Set_Object_Data( coords );
+    }
+
+    // Calculate the coordinates of the segment assumed horizontal.
+    // Then turn the strips of the desired angle.
+
+    glNormal3f( 0.0, 0.0, 1.0 );    // Normal is Z axis
     DataScale3D = tmp;
 }
 
 
+static void    Draw3D_FilledOblongMask( double startx, double starty,
+                                        double endx, double endy,
+                                        double holex,
+                                        double holey, double holeradius,
+                                        double height, double zpos )
+{
+    double ddx, ddy, dx, dy;
+    int spii = pii, ii, angle;
+
+    dx  = endx - startx;
+    dy  = endy - starty;
+    angle   = (int) ( ( atan2( dy, dx ) * 1800 / M_PI ) + 0.5 );
+    dx      = 0;
+    dy      = holeradius;
+    RotatePoint( &dx, &dy, angle );
+
+    for( ii = 0; ii <= 9; ii++ )
+    {
+        ddx = dx;
+        ddy = -dy;
+        RotatePoint( &ddx, &ddy, -ii * 200 );
+        p_data.push_back( CPolyPt( (int) ( (endx + ddx) / g_Parm_3D_Visu.m_BoardScale ),
+                                   (int) (-(endy + ddy) / g_Parm_3D_Visu.m_BoardScale) ) );
+        pii++;
+    }
+
+    for( ii = 0; ii <= 9; ii++ )
+    {
+        ddx = -dx;
+        ddy = dy;
+        RotatePoint( &ddx, &ddy, -ii * 200 );
+        p_data.push_back( CPolyPt( (int) ( (startx + ddx) / g_Parm_3D_Visu.m_BoardScale ),
+                                   (int) (-(starty + ddy) / g_Parm_3D_Visu.m_BoardScale) ) );
+        pii++;
+    }
+
+    for( ii = 0; ii < (pii - spii) / 2; ii++ )
+    {
+        CPolyPt h = p_data[spii + ii];
+        p_data[spii + ii]       = p_data[pii - ii - 1];
+        p_data[pii - ii - 1]    = h;
+    }
+}
+
+
+static void Draw3D_FilledCylinderMask( double posx, double posy, double rayon,
+                                       double height, double zpos )
+{
+    int ii, slice = 16;
+    double x, y;
+
+    for( ii = 0; ii <= slice; ii++ )
+    {
+        x   = rayon;
+        y   = 0.0;
+        RotatePoint( &x, &y, ii * 225.0 );
+        x   = (x + posx) / g_Parm_3D_Visu.m_BoardScale;
+        y   = -( (y + posy) / g_Parm_3D_Visu.m_BoardScale );
+
+        p_data.push_back( CPolyPt( (int) x, (int) y ) );
+        pii++;
+    }
+}
+
+
+static void Draw3D_Mask( double startx, double starty, double endx,
+                         double endy, double width, double zpos )
+{
+    startx  /= g_Parm_3D_Visu.m_BoardScale;
+    starty  /= g_Parm_3D_Visu.m_BoardScale;
+    endx    /= g_Parm_3D_Visu.m_BoardScale;
+    endy    /= g_Parm_3D_Visu.m_BoardScale;
+    e_data.push_back( CPolyPt( (int) startx, (int) starty ) );
+    e_data.push_back( CPolyPt( (int) endx, (int) endy ) );
+    eii += 2;
+}
+
+
 // Draw a polygon similar to a segment has rounded tips
 static void Draw3D_FilledSegment( double startx, double starty, double endx,
                                   double endy, double width, double zpos )
 {
     double dx, dy, x, y, firstx = 0, firsty = 0;
-    int    ii, angle;
+    int ii, angle;
 
     // Calculate the coordinates of the segment assumed horizontal.
     // Then turn the strips of the desired angle.
-    dx    = endx - startx;
-    dy    = endy - starty;
-    angle = (int) ( ( atan2( dy, dx ) * 1800 / M_PI ) + 0.5 );
+    dx      = endx - startx;
+    dy      = endy - starty;
+    angle   = (int) ( ( atan2( dy, dx ) * 1800 / M_PI ) + 0.5 );
 
     RotatePoint( &dx, &dy, angle );
     width /= 2;
@@ -1189,8 +2692,8 @@ static void Draw3D_FilledSegment( double
     // Trace the flare to right (1st half polygon at the end of the segment)
     for( ii = 0; ii <= 8; ii++ )
     {
-        x = 0.0;
-        y = -width;
+        x   = 0.0;
+        y   = -width;
         RotatePoint( &x, &y, -ii * 225 );
         x += dx;
         RotatePoint( &x, &y, -angle );
@@ -1198,8 +2701,8 @@ static void Draw3D_FilledSegment( double
 
         if( ii == 0 )
         {
-            firstx = startx + x;
-            firsty = starty + y;
+            firstx  = startx + x;
+            firsty  = starty + y;
         }
     }
 
@@ -1207,8 +2710,8 @@ static void Draw3D_FilledSegment( double
     for( ii = 0; ii <= 8; ii++ )
     {
         int jj = ii * 225;
-        x = 0.0;
-        y = width;
+        x   = 0.0;
+        y   = width;
         RotatePoint( &x, &y, -angle - jj );
         glVertex3f( startx + x, starty + y, zpos );
     }
@@ -1224,20 +2727,20 @@ static void Draw3D_FilledSegmentWithHole
                                           double endx, double endy,
                                           double width, double holex,
                                           double holey, double holeradius,
-                                          double zpos )
+                                          double zpos, double offX, double offY )
 {
     double x, y, xin, yin;
     double firstx = 0, firsty = 0, firstxin = 0, firstyin = 0;
-    int    ii, angle, theta;
+    int ii, angle, theta;
 
     // Calculate the coordinates of the segment assumed horizontal
     // Then turn the strips of the desired angle
     // All calculations are done with startx, starty as the origin of the route
-    endx  -= startx;
-    endy  -= starty;
-    holex -= startx;
-    holey -= starty;
-    angle  = (int) ( ( atan2( endy, endx ) * 1800 / M_PI ) + 0.5 );
+    endx    -= startx;
+    endy    -= starty;
+    holex   -= startx;
+    holey   -= starty;
+    angle   = (int) ( ( atan2( endy, endx ) * 1800 / M_PI ) + 0.5 );
 
     RotatePoint( &endx, &endy, angle );
     RotatePoint( &holex, &holey, angle );
@@ -1249,26 +2752,26 @@ static void Draw3D_FilledSegmentWithHole
     // around the half-hole drilling
     for( ii = 0; ii <= 8; ii++ )
     {
-        x     = 0.0;
-        y     = -width;
-        xin   = 0.0;
-        yin   = -holeradius;
-        theta = -ii * 225;
+        x   = 0.0;
+        y   = -width;
+        xin     = 0.0;
+        yin     = -holeradius;
+        theta   = -ii * 225;
         RotatePoint( &x, &y, theta );
         RotatePoint( &xin, &yin, theta );
         x += endx;
         RotatePoint( &x, &y, -angle );
-        xin += holex;
+        xin += endx;
         RotatePoint( &xin, &yin, -angle );
         glVertex3f( startx + xin, starty + yin, zpos );
-        glVertex3f( startx + x, starty + y, zpos );
+        glVertex3f( startx + x + offX, starty + y - offY, zpos );
 
         if( ii == 0 )
         {
-            firstx   = startx + x;
-            firsty   = starty + y;
-            firstxin = startx + xin;
-            firstyin = starty + yin;
+            firstx  = startx + x + offX;
+            firsty  = starty + y - offY;
+            firstxin    = startx + xin;
+            firstyin    = starty + yin;
         }
     }
 
@@ -1276,17 +2779,16 @@ static void Draw3D_FilledSegmentWithHole
     // segment)
     for( ii = 0; ii <= 8; ii++ )
     {
-        theta = -ii * 225;
-        x     = 0.0;
-        y     = width;
+        theta   = -ii * 225;
+        x       = 0.0;
+        y       = width;
         RotatePoint( &x, &y, -angle + theta );
         xin = 0.0;
         yin = holeradius;
         RotatePoint( &xin, &yin, theta );
-        xin += holex;
         RotatePoint( &xin, &yin, -angle );
         glVertex3f( startx + xin, starty + yin, zpos );
-        glVertex3f( startx + x, starty + y, zpos );
+        glVertex3f( startx + x + offX, starty + y - offY, zpos );
     }
 
     glVertex3f( firstxin, firstyin, zpos );
@@ -1295,17 +2797,99 @@ static void Draw3D_FilledSegmentWithHole
 }
 
 
+static void Draw3D_FilledSegmentWithHoleMask( double startx, double starty,
+                                              double endx, double endy,
+                                              double width, double holex,
+                                              double holey, double holeradius,
+                                              double zpos, double offX, double offY )
+{
+    double x, y, xin, yin;
+    double firstx = 0, firsty = 0, firstxin = 0, firstyin = 0;
+    int ii, angle, theta;
+
+    int spii = pii;
+
+    // Calculate the coordinates of the segment assumed horizontal
+    // Then turn the strips of the desired angle
+    // All calculations are done with startx, starty as the origin of the route
+    endx    -= startx;
+    endy    -= starty;
+    holex   -= startx;
+    holey   -= starty;
+    angle   = (int) ( ( atan2( endy, endx ) * 1800 / M_PI ) + 0.5 );
+
+    RotatePoint( &endx, &endy, angle );
+    RotatePoint( &holex, &holey, angle );
+    width /= 2;
+
+    // Path of the flare to right (1st half polygon at the end of the segment)
+    // around the half-hole drilling
+    for( ii = 0; ii <= 8; ii++ )
+    {
+        x   = 0.0;
+        y   = -width;
+        xin     = 0.0;
+        yin     = -holeradius;
+        theta   = -ii * 225;
+        RotatePoint( &x, &y, theta );
+        RotatePoint( &xin, &yin, theta );
+        x += endx;
+        RotatePoint( &x, &y, -angle );
+        xin += holex;
+        RotatePoint( &xin, &yin, -angle );
+        p_data.push_back( CPolyPt( (int) ( (startx + x + offX) / g_Parm_3D_Visu.m_BoardScale ),
+                                   -(int) ( (starty + y -
+                                             offY) / g_Parm_3D_Visu.m_BoardScale ) ) );
+        pii++;
+
+        if( ii == 0 )
+        {
+            firstx  = startx + x;
+            firsty  = starty + y;
+            firstxin    = startx + xin;
+            firstyin    = starty + yin;
+        }
+    }
+
+    // Layout of the rounded left (2nd half polygon is the origin of the
+    // segment)
+    for( ii = 0; ii <= 8; ii++ )
+    {
+        theta   = -ii * 225;
+        x       = 0.0;
+        y       = width;
+        RotatePoint( &x, &y, -angle + theta );
+        xin = 0.0;
+        yin = holeradius;
+        RotatePoint( &xin, &yin, theta );
+        xin += holex;
+        RotatePoint( &xin, &yin, -angle );
+        p_data.push_back( CPolyPt( (int) ( (startx + x + offX) / g_Parm_3D_Visu.m_BoardScale ),
+                                   -(int) ( (starty + y -
+                                             offY) / g_Parm_3D_Visu.m_BoardScale ) ) );
+        pii++;
+    }
+
+    for( ii = 0; ii < (pii - spii) / 2; ii++ )
+    {
+        CPolyPt h = p_data[spii + ii];
+        p_data[spii + ii]       = p_data[pii - ii - 1];
+        p_data[pii - ii - 1]    = h;
+    }
+}
+
+
 static void Draw3D_ArcSegment( double startx, double starty, double centrex,
                                double centrey, double arc_angle, double width, double zpos )
 {
-    int    ii;
-    int    slice = 36;             // Number of segments to approximate a circle by segments
+    int ii;
+    int slice = 36;             // Number of segments to approximate a circle by segments
     double hole, rayon;
     double arcStart_Angle;
 
     arcStart_Angle = (atan2( startx - centrex, starty - centrey ) * 1800 / M_PI );
-    rayon = hypot( startx - centrex, starty - centrey ) + ( width / 2);
-    hole  = rayon - width;
+    rayon   = hypot( startx - centrex, starty - centrey ) + ( width / 2);
+    hole    = rayon - width;
 
     // Calculate the number of segments to approximate this arc
     int imax = (int) ( (double) arc_angle * slice / 3600.0 );
@@ -1326,12 +2910,12 @@ static void Draw3D_ArcSegment( double st
     {
         double angle = (double) ii * delta_angle;
         angle += arcStart_Angle + 900;
-        double dx = hole;
-        double dy = 0.0;
+        double dx   = hole;
+        double dy   = 0.0;
         RotatePoint( &dx, &dy, (int) angle );
         glVertex3f( dx + startx, dy + starty, zpos );
-        dx = rayon;
-        dy = 0.0;
+        dx  = rayon;
+        dy  = 0.0;
         RotatePoint( &dx, &dy, (int) angle );
         glVertex3f( dx + startx, dy + starty, zpos );
     }
@@ -1340,14 +2924,65 @@ static void Draw3D_ArcSegment( double st
 }
 
 
+static void Draw3D_ArcSegmentMask( double startx, double starty, double centrex,
+                                   double centrey, double arc_angle, double width, double zpos )
+{
+    int ii;
+    int slice = 36;             // Number of segments to approximate a circle by segments
+    double rayon;
+    double arcStart_Angle;
+    double lx, ly;
+
+    arcStart_Angle = (atan2( startx - centrex, starty - centrey ) * 1800 / M_PI );
+    rayon = hypot( startx - centrex, starty - centrey );
+
+    // Calculate the number of segments to approximate this arc
+    int imax = (int) ( (double) arc_angle * slice / 3600.0 );
+
+    if( imax < 0 )
+        imax = -imax;
+
+    if( imax == 0 )
+        imax = 1;
+
+    // Adjust delta_angle to have exactly imax segments in arc_angle
+    // i.e. arc_angle = imax delta_agnle.
+    double delta_angle = (double) arc_angle / imax;
+
+    for( ii = 0; ii <= imax; ii++ )
+    {
+        double angle = (double) ii * delta_angle;
+        angle += arcStart_Angle + 900;
+        double dx   = rayon;
+        double dy   = 0.0;
+        dy = 0.0;
+        RotatePoint( &dx, &dy, (int) angle );
+        dx  += startx;
+        dy  += starty;
+        dx  /= g_Parm_3D_Visu.m_BoardScale;
+        dy  /= g_Parm_3D_Visu.m_BoardScale;
+
+        if( ii > 0 )
+        {
+            e_data.push_back( CPolyPt( (int) lx, (int) (-ly) ) );
+            e_data.push_back( CPolyPt( (int) dx, (int) (-dy) ) );
+            eii += 2;
+        }
+
+        lx  = dx;
+        ly  = dy;
+    }
+}
+
+
 static void Draw3D_CircleSegment( double startx, double starty, double endx,
                                   double endy, double width, double zpos )
 {
-    int    ii, slice = 36;
+    int ii, slice = 36;
     double x, y, hole, rayon;
 
-    rayon = hypot( startx - endx, starty - endy ) + ( width / 2);
-    hole  = rayon - width;
+    rayon   = hypot( startx - endx, starty - endy ) + ( width / 2);
+    hole    = rayon - width;
 
     glBegin( GL_QUAD_STRIP );
 
@@ -1365,29 +3000,66 @@ static void Draw3D_CircleSegment( double
 }
 
 
+static void Draw3D_CircleSegmentMask( double startx, double starty, double endx,
+                                      double endy, double width, double zpos )
+{
+    int ii, slice = 36;
+    double lx, ly, x, y, rayon;
+
+    int seii = eii;
+
+    rayon = hypot( startx - endx, starty - endy );
+
+    for( ii = 0; ii <= slice; ii++ )
+    {
+        x = rayon; y = 0.0;
+        RotatePoint( &x, &y, ii * 3600 / slice );
+        x   += startx;
+        y   += starty;
+        x   /= g_Parm_3D_Visu.m_BoardScale;
+        y   /= g_Parm_3D_Visu.m_BoardScale;
+
+        if( ii > 0 )
+        {
+            e_data.push_back( CPolyPt( (int) lx, (int) ly ) );
+            e_data.push_back( CPolyPt( (int) x, (int) y ) );
+            eii += 2;
+        }
+
+        lx  = x;
+        ly  = y;
+    }
+
+    for( ii = 0; ii < (eii - seii) / 2; ii++ )
+    {
+        CPolyPt h = e_data[seii + ii];
+        e_data[seii + ii]       = e_data[eii - ii - 1];
+        e_data[eii - ii - 1]    = h;
+    }
+}
+
+
 void EDA_3D_CANVAS::Draw3D_Polygon( std::vector<wxPoint>& aCornersList, double aZpos )
 {
     g_Parm_3D_Visu.m_ActZpos = aZpos;
 
     GLUtesselator* tess = gluNewTess();
-    gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*)() )tessBeginCB );
-    gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*)() )tessEndCB );
-    gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*)() )tessErrorCB );
-    gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*)() )tesswxPoint2Vertex );
+    gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )tessBeginCB );
+    gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )tessEndCB );
+    gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )tessErrorCB );
+    gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tesswxPoint2Vertex );
 
     GLdouble v_data[3];
     v_data[2] = aZpos;
 
-    //gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
-
     // Draw solid polygon
     gluTessBeginPolygon( tess, NULL );
     gluTessBeginContour( tess );
 
     for( unsigned ii = 0; ii < aCornersList.size(); ii++ )
     {
-        v_data[0] = aCornersList[ii].x * g_Parm_3D_Visu.m_BoardScale;
-        v_data[1] = -aCornersList[ii].y * g_Parm_3D_Visu.m_BoardScale;
+        v_data[0]   = aCornersList[ii].x * g_Parm_3D_Visu.m_BoardScale;
+        v_data[1]   = -aCornersList[ii].y * g_Parm_3D_Visu.m_BoardScale;
         // gluTessVertex store pointers on data, not data, so do not store
         // different corners values in a temporary variable
         // but send pointer on each corner value in aCornersList
@@ -1404,28 +3076,41 @@ void EDA_3D_CANVAS::Draw3D_Polygon( std:
 static int Get3DLayerEnable( int act_layer )
 {
     int i = -1;
+
     // see if layer needs to be shown
     // check the flags
-    switch (act_layer)
+    switch( act_layer )
     {
-        case DRAW_N:
-            i=g_Parm_3D_Visu.FL_DRAWINGS;
-            break;
+    case ADHESIVE_N_FRONT:
+    case ADHESIVE_N_BACK:
+    case SOLDERMASK_N_FRONT:
+    case SOLDERMASK_N_BACK:
+    case SOLDERPASTE_N_FRONT:
+    case SOLDERPASTE_N_BACK:
+    case SILKSCREEN_N_FRONT:
+    case SILKSCREEN_N_BACK:
+        return g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( act_layer );
+        break;
 
-        case COMMENT_N:
-            i=g_Parm_3D_Visu.FL_COMMENTS;
-            break;
+    case DRAW_N:
+        i = g_Parm_3D_Visu.FL_DRAWINGS;
+        break;
 
-        case ECO1_N:
-            i=g_Parm_3D_Visu.FL_ECO1;
-            break;
+    case COMMENT_N:
+        i = g_Parm_3D_Visu.FL_COMMENTS;
+        break;
 
-        case ECO2_N:
-            i=g_Parm_3D_Visu.FL_ECO2;
-            break;
+    case ECO1_N:
+        i = g_Parm_3D_Visu.FL_ECO1;
+        break;
+
+    case ECO2_N:
+        i = g_Parm_3D_Visu.FL_ECO2;
+        break;
     }
+
     // the layer was not a layer with a flag, so show it
-    if (i < 0)
+    if( i < 0 )
         return true;
 
     // if the layer has a flag, return the flag
@@ -1440,18 +3125,19 @@ static GLfloat Get3DLayerSide( int act_l
     nZ = 1.0;
 
     if( ( act_layer <= LAST_COPPER_LAYER - 1 )
-       || ( act_layer == ADHESIVE_N_BACK )
-       || ( act_layer == SOLDERPASTE_N_BACK )
-       || ( act_layer == SILKSCREEN_N_BACK )
-       || ( act_layer == SOLDERMASK_N_BACK ) )
+        || ( act_layer == ADHESIVE_N_BACK )
+        || ( act_layer == SOLDERPASTE_N_BACK )
+        || ( act_layer == SILKSCREEN_N_BACK )
+        || ( act_layer == SOLDERMASK_N_BACK ) )
         nZ = -1.0;
+
     return nZ;
 }
 
 
-///////////////////////////////////////////////////////////////////////////////
+// /////////////////////////////////////////////////////////////////////////////
 // GLU_TESS CALLBACKS
-///////////////////////////////////////////////////////////////////////////////
+// /////////////////////////////////////////////////////////////////////////////
 
 void CALLBACK tessBeginCB( GLenum which )
 {
@@ -1475,6 +3161,7 @@ void CALLBACK tessCPolyPt2Vertex( const
                 g_Parm_3D_Visu.m_ActZpos );
 }
 
+
 void CALLBACK tesswxPoint2Vertex( const GLvoid* data )
 {
     const wxPoint* ptr = (const wxPoint*) data;
@@ -1496,3 +3183,56 @@ void CALLBACK tessErrorCB( GLenum errorC
     D( printf( "Tess ERROR: %s\n", errorStr ); )
 #endif
 }
+
+
+// /////////////////////////////////////////////////////////////////////////////
+// MY GLU_TESS CALLBACKS
+// /////////////////////////////////////////////////////////////////////////////
+
+void CALLBACK mytessBeginCB( GLenum which )
+{
+    glBegin( which );
+}
+
+
+void CALLBACK mytessEndCB()
+{
+    glEnd();
+}
+
+
+void CALLBACK mytessCPolyPt2Vertex( const GLvoid* data )
+{
+    // cast back to double type
+    const CPolyPt* ptr = (const CPolyPt*) data;
+
+    glVertex3f( ptr->x * g_Parm_3D_Visu.m_BoardScale,
+                -ptr->y * g_Parm_3D_Visu.m_BoardScale,
+                g_Parm_3D_Visu.m_ActZpos );
+}
+
+
+void CALLBACK mytessCombineCB( GLdouble coords[3],
+                               void*    vertex_data[4],
+                               GLfloat  weight[4],
+                               void**   outData )
+{
+    CPolyPt* n =
+        new CPolyPt( (int) (coords[0] / g_Parm_3D_Visu.m_BoardScale),
+                     -(int) (coords[1] / g_Parm_3D_Visu.m_BoardScale) );
+
+    *outData = n;
+}
+
+
+void CALLBACK mytessErrorCB( GLenum errorCode )
+{
+#if defined(DEBUG)
+    const GLubyte* errorStr;
+
+    errorStr = gluErrorString( errorCode );
+
+    // DEBUG //
+    fprintf( stderr, "Tess ERROR: %s\n", errorStr );
+#endif
+}
Only in 3d-viewer/: 3d_draw.cpp_20120521
Only in 3d-viewer/: 3d_draw.cpp_20120530
Only in 3d-viewer/: 3d_draw.cpp_20120603
Only in 3d-viewer/: 3d_draw.cpp.BASE
Only in 3d-viewer/: 3d_draw.cpp.BASE.moved
Only in 3d-viewer/: 3d_draw.cpp.OTHER
Only in 3d-viewer/: 3d_draw.cpp.OTHER.moved
Only in 3d-viewer/: 3d_draw.cpp.THIS
Only in 3d-viewer/: 3d_draw.cpp.THIS.moved
diff -rup 3d-viewer.orig//3d_read_mesh.cpp 3d-viewer//3d_read_mesh.cpp
--- 3d-viewer.orig//3d_read_mesh.cpp	2012-06-03 22:21:14.095611510 +0200
+++ 3d-viewer//3d_read_mesh.cpp	2012-06-03 22:16:21.654545402 +0200
@@ -35,14 +35,19 @@
 
 #include <3d_viewer.h>
 
-
+#ifdef TSP_20120603
+wxString FullFilename;
+#endif    // TSP_20120603
 int S3D_MASTER::ReadData()
 {
-    char       line[1024], * text;
-    wxFileName fn;
-    wxString   FullFilename;
-    FILE*      file;
-    int        LineNum = 0;
+    char        line[1024], * text;
+    wxFileName  fn;
+
+#ifndef TSP_20120603
+    wxString    FullFilename;
+#endif    // TSP_20120603
+    FILE*       file;
+    int         LineNum = 0;
 
     if( m_Shape3DName.IsEmpty() )
     {
@@ -51,9 +56,9 @@ int S3D_MASTER::ReadData()
 
     wxString shape3DNname = m_Shape3DName;
 #ifdef __WINDOWS__
-    shape3DNname.Replace( wxT("/"), wxT("\\") );
+    shape3DNname.Replace( wxT( "/" ), wxT( "\\" ) );
 #else
-    shape3DNname.Replace( wxT("\\"), wxT("/") );
+    shape3DNname.Replace( wxT( "\\" ), wxT( "/" ) );
 #endif
 
     if( wxFileName::FileExists( shape3DNname ) )
@@ -115,13 +120,13 @@ int S3D_MASTER::ReadData()
 
 int S3D_MASTER::ReadMaterial( FILE* file, int* LineNum )
 {
-    char          line[512], * text, * command;
-    wxString      mat_name;
-    S3D_MATERIAL* material = NULL;
-
-    command  = strtok( NULL, " \t\n\r" );
-    text     = strtok( NULL, " \t\n\r" );
-    mat_name = FROM_UTF8( text );
+    char            line[512], * text, * command;
+    wxString        mat_name;
+    S3D_MATERIAL*   material = NULL;
+
+    command     = strtok( NULL, " \t\n\r" );
+    text        = strtok( NULL, " \t\n\r" );
+    mat_name    = FROM_UTF8( text );
 
     if( stricmp( command, "USE" ) == 0 )
     {
@@ -134,7 +139,11 @@ int S3D_MASTER::ReadMaterial( FILE* file
             }
         }
 
+#ifdef TSP_20120603
+        printf( "ReadMaterial error: material not found %s\n", FullFilename.mb_str().data() );
+#else
         printf( "ReadMaterial error: material not found\n" );
+#endif    // TSP_20120603
         return 0;
     }
 
@@ -226,7 +235,12 @@ int S3D_MASTER::ReadChildren( FILE* file
         }
         else
         {
+#ifdef TSP_20120603
+            printf( "ReadChildren error line %d <%s> %s\n", *LineNum, text,
+                    FullFilename.mb_str().data() );
+#else
             printf( "ReadChildren error line %d <%s> \n", *LineNum, text );
+#endif      // TSP_20120603
             break;
         }
     }
@@ -237,8 +251,8 @@ int S3D_MASTER::ReadChildren( FILE* file
 
 int S3D_MASTER::ReadShape( FILE* file, int* LineNum )
 {
-    char line[1024], * text;
-    int  err = 1;
+    char    line[1024], * text;
+    int     err = 1;
 
     while( GetLine( file, line, LineNum, 512 ) )
     {
@@ -260,7 +274,12 @@ int S3D_MASTER::ReadShape( FILE* file, i
         }
         else
         {
-            printf( "ReadShape error line %d <%s> \n", *LineNum, text );
+#ifdef TSP_20120603
+            printf( "ReadShape error line %d <%s> \n", *LineNum, text,
+                    FullFilename.mb_str().data() );
+#else
+            printf( "ReadShape error line %d \n", *LineNum, text );
+#endif      // TSP_20120603
             break;
         }
     }
@@ -271,8 +290,8 @@ int S3D_MASTER::ReadShape( FILE* file, i
 
 int S3D_MASTER::ReadAppearance( FILE* file, int* LineNum )
 {
-    char line[1024], * text;
-    int  err = 1;
+    char    line[1024], * text;
+    int     err = 1;
 
     while( GetLine( file, line, LineNum, 512 ) )
     {
@@ -287,9 +306,30 @@ int S3D_MASTER::ReadAppearance( FILE* fi
         {
             ReadMaterial( file, LineNum );
         }
+
+#ifdef TSP_20120603
+        else if( stricmp( text, "texture" ) == 0 )
+        {
+            char line[512], * text, * command;
+            command = strtok( NULL, " \t\n\r" );
+            printf( "ReadTexture: %s", command );
+
+            while( text = strtok( NULL, " \t\n\r" ) )
+            {
+                printf( " %s", text );
+            }
+
+            printf( "\n" );
+        }
+#endif    // TSP_20120603
         else
         {
+#ifdef TSP_20120603
+            printf( "ReadAppearance error line %d <%s> %s\n", *LineNum, text,
+                    FullFilename.mb_str().data() );
+#else
             printf( "ReadAppearance error line %d <%s> \n", *LineNum, text );
+#endif      // TSP_20120603
             break;
         }
     }
@@ -317,20 +357,20 @@ int S3D_MASTER::ReadAppearance( FILE* fi
  *  text_buffer contains the first line of this node :
  *     "coord Coordinate { point ["
  */
-void ReadCoordsList( FILE* file, char* text_buffer, std::vector< double >& aList, int* LineNum )
+void ReadCoordsList( FILE* file, char* text_buffer, std::vector<double>& aList, int* LineNum )
 {
-    unsigned int ii = 0, jj = 0;
-    char*        text;
-    bool         HasData   = false;
-    bool         StartData = false;
-    bool         EndNode   = false;
-    char         string_num[512];
+    unsigned int    ii = 0, jj = 0;
+    char*           text;
+    bool            HasData     = false;
+    bool            StartData   = false;
+    bool            EndNode     = false;
+    char            string_num[512];
 
     text = text_buffer;
 
     while( !EndNode )
     {
-        if( *text == 0 )  // Needs data !
+        if( *text == 0 )    // Needs data !
         {
             text = text_buffer;
             GetLine( file, text_buffer, LineNum, 512 );
@@ -373,6 +413,7 @@ void ReadCoordsList( FILE* file, char* t
                 break;
 
             default:
+
                 if( !StartData )
                     break;
 
@@ -395,9 +436,9 @@ void ReadCoordsList( FILE* file, char* t
 int S3D_MASTER::ReadGeometry( FILE* file, int* LineNum )
 {
     char    line[1024], buffer[1024], * text;
-    int     err    = 1;
-    std::vector< double > points;
-    std::vector< double > list;
+    int     err = 1;
+    std::vector<double> points;
+    std::vector<double> list;
 
     while( GetLine( file, line, LineNum, 512 ) )
     {
@@ -420,6 +461,7 @@ int S3D_MASTER::ReadGeometry( FILE* file
             else
             {
             }
+
             continue;
         }
 
@@ -433,6 +475,7 @@ int S3D_MASTER::ReadGeometry( FILE* file
             else
             {
             }
+
             continue;
         }
 
@@ -506,8 +549,8 @@ int S3D_MASTER::ReadGeometry( FILE* file
                 break;
             }
 
-            std::vector< int > coordIndex;
-            std::vector< S3D_Vertex > vertices;
+            std::vector<int>        coordIndex;
+            std::vector<S3D_Vertex> vertices;
 
             while( GetLine( file, line, LineNum, 512 ) )
             {
@@ -527,7 +570,7 @@ int S3D_MASTER::ReadGeometry( FILE* file
                         {
                             int kk = coordIndex[jj] * 3;
 
-                            if( (kk < 0) || ((kk + 3) > (int)points.size()) )
+                            if( (kk < 0) || ( (kk + 3) > (int) points.size() ) )
                             {
                                 wxLogError( wxT( "3D geometry index read error <%s> at line %d." ),
                                             GetChars( FROM_UTF8( text ) ), *LineNum );
@@ -536,10 +579,29 @@ int S3D_MASTER::ReadGeometry( FILE* file
                             }
 
                             S3D_Vertex vertex;
-                            vertex.x = points[kk];
-                            vertex.y = points[kk + 1];
-                            vertex.z = points[kk + 2];
+                            vertex.x    = points[kk];
+                            vertex.y    = points[kk + 1];
+                            vertex.z    = points[kk + 2];
                             vertices.push_back( vertex );
+
+// fprintf(stderr, "V: %lf,%lf,%lf\n", vertex.x, vertex.y, vertex.z);
+                            if( vertex.x < m_MinPos.x )
+                                m_MinPos.x = vertex.x;
+
+                            if( vertex.y < m_MinPos.y )
+                                m_MinPos.y = vertex.y;
+
+                            if( vertex.z < m_MinPos.z )
+                                m_MinPos.z = vertex.z;
+
+                            if( vertex.x > m_MaxPos.x )
+                                m_MaxPos.x = vertex.x;
+
+                            if( vertex.y > m_MaxPos.y )
+                                m_MaxPos.y = vertex.y;
+
+                            if( vertex.z > m_MaxPos.z )
+                                m_MaxPos.z = vertex.z;
                         }
 
                         Set_Object_Coords( vertices );
diff -rup 3d-viewer.orig//3d_struct.h 3d-viewer//3d_struct.h
--- 3d-viewer.orig//3d_struct.h	2012-06-03 22:21:14.096611489 +0200
+++ 3d-viewer//3d_struct.h	2012-06-03 22:16:21.654545402 +0200
@@ -97,6 +97,8 @@ public:
     S3D_Vertex      m_MatPosition;
     Struct3D_Shape* m_3D_Drawings;
     S3D_MATERIAL*   m_Materials;
+    S3D_Vertex      m_MinPos;
+    S3D_Vertex      m_MaxPos;
 
 public:
     S3D_MASTER( EDA_ITEM* aParent );
diff -rup 3d-viewer.orig//3d_toolbar.cpp 3d-viewer//3d_toolbar.cpp
--- 3d-viewer.orig//3d_toolbar.cpp	2012-06-03 22:21:14.096611489 +0200
+++ 3d-viewer//3d_toolbar.cpp	2012-06-03 22:16:21.654545402 +0200
@@ -133,13 +133,14 @@ void EDA_3D_FRAME::ReCreateMenuBar()
     bool full_options = true;
 
     // If called from the display frame of CvPcb, only some options are relevant
-    if( Parent()->GetName() == wxT( "CmpFrame" ) ) {
+    if( Parent()->GetName() == wxT( "CmpFrame" ) )
+    {
         full_options = false;
     }
 
-    wxMenuBar* menuBar   = new wxMenuBar;
-    wxMenu*    fileMenu  = new wxMenu;
-    wxMenu*    prefsMenu = new wxMenu;
+    wxMenuBar*  menuBar     = new wxMenuBar;
+    wxMenu*     fileMenu    = new wxMenu;
+    wxMenu*     prefsMenu   = new wxMenu;
 
     menuBar->Append( fileMenu, _( "&File" ) );
 
@@ -161,36 +162,37 @@ void EDA_3D_FRAME::ReCreateMenuBar()
 
     wxMenuItem* item;
     item = AddMenuItem( prefsMenu, ID_MENU3D_AXIS_ONOFF,
-            _( "Show 3D &Axis" ), KiBitmap( axis3d_front_xpm ), wxITEM_CHECK );
-    item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_AXIS]);
+                        _( "Show 3D &Axis" ), KiBitmap( axis3d_front_xpm ), wxITEM_CHECK );
+    item->Check( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_AXIS] );
 
 
     if( full_options )
     {
-       item = AddMenuItem( prefsMenu, ID_MENU3D_MODULE_ONOFF,
-               _( "Show 3D F&ootprints" ), KiBitmap( shape_3d_xpm ), wxITEM_CHECK );
-       item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_MODULE]);
-
-       item = AddMenuItem( prefsMenu, ID_MENU3D_ZONE_ONOFF,
-               _( "Show Zone &Filling" ), KiBitmap( add_zone_xpm ), wxITEM_CHECK );
-       item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE]);
-
-       item = AddMenuItem( prefsMenu, ID_MENU3D_COMMENTS_ONOFF,
-               _( "Show &Comments Layer" ), KiBitmap( edit_sheet_xpm ), wxITEM_CHECK );
-       item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_COMMENTS]);
-
-       item = AddMenuItem( prefsMenu, ID_MENU3D_DRAWINGS_ONOFF,
-               _( "Show &Drawings Layer" ), KiBitmap( add_polygon_xpm ), wxITEM_CHECK );
-       item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_DRAWINGS]);
-
-       item = AddMenuItem( prefsMenu, ID_MENU3D_ECO1_ONOFF,
-               _( "Show Eco&1 Layer" ), KiBitmap( tools_xpm ), wxITEM_CHECK );
-       item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ECO1]);
-
-       item = AddMenuItem( prefsMenu, ID_MENU3D_ECO2_ONOFF,
-               _( "Show Eco&2 Layer" ), KiBitmap( tools_xpm ), wxITEM_CHECK );
-       item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ECO2]);
-
+        item = AddMenuItem( prefsMenu, ID_MENU3D_MODULE_ONOFF,
+                            _( "Show 3D F&ootprints" ), KiBitmap( shape_3d_xpm ), wxITEM_CHECK );
+        item->Check( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_MODULE] );
+
+        item = AddMenuItem( prefsMenu, ID_MENU3D_ZONE_ONOFF,
+                            _( "Show Zone &Filling" ), KiBitmap( add_zone_xpm ), wxITEM_CHECK );
+        item->Check( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE] );
+
+        item = AddMenuItem( prefsMenu, ID_MENU3D_COMMENTS_ONOFF,
+                            _( "Show &Comments Layer" ), KiBitmap( edit_sheet_xpm ),
+                            wxITEM_CHECK );
+        item->Check( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_COMMENTS] );
+
+        item = AddMenuItem( prefsMenu, ID_MENU3D_DRAWINGS_ONOFF,
+                            _( "Show &Drawings Layer" ), KiBitmap( add_polygon_xpm ),
+                            wxITEM_CHECK );
+        item->Check( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_DRAWINGS] );
+
+        item = AddMenuItem( prefsMenu, ID_MENU3D_ECO1_ONOFF,
+                            _( "Show Eco&1 Layer" ), KiBitmap( tools_xpm ), wxITEM_CHECK );
+        item->Check( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ECO1] );
+
+        item = AddMenuItem( prefsMenu, ID_MENU3D_ECO2_ONOFF,
+                            _( "Show Eco&2 Layer" ), KiBitmap( tools_xpm ), wxITEM_CHECK );
+        item->Check( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ECO2] );
     }
 
     SetMenuBar( menuBar );
diff -rup 3d-viewer.orig//3d_viewer.h 3d-viewer//3d_viewer.h
--- 3d-viewer.orig//3d_viewer.h	2012-06-03 22:21:14.096611489 +0200
+++ 3d-viewer//3d_viewer.h	2012-06-03 22:16:21.655545382 +0200
@@ -72,8 +72,7 @@ class ZONE_CONTAINER;
  * id.h file.  This will prevent the entire project from being rebuilt when
  * adding new commands to the 3D viewer.
  */
-enum id_3dview_frm
-{
+enum id_3dview_frm {
     ID_START_COMMAND_3D = ID_END_LIST,
     ID_ROTATE3D_X_NEG,
     ID_ROTATE3D_X_POS,
@@ -127,40 +126,38 @@ class S3D_Vertex;
 class SEGVIA;
 
 
-#define m_ROTX m_Rot[0]
-#define m_ROTY m_Rot[1]
-#define m_ROTZ m_Rot[2]
+#define m_ROTX  m_Rot[0]
+#define m_ROTY  m_Rot[1]
+#define m_ROTZ  m_Rot[2]
 
 /* information needed to display 3D board */
 class Info_3D_Visu
 {
-
 public:
     enum {
-        FL_AXIS=0,        FL_MODULE,        FL_ZONE,
-        FL_COMMENTS,      FL_DRAWINGS,      FL_ECO1,          FL_ECO2,
+        FL_AXIS=0, FL_MODULE, FL_ZONE,
+        FL_COMMENTS, FL_DRAWINGS, FL_ECO1, FL_ECO2,
         FL_LAST
     };
 
-    double    m_Beginx, m_Beginy;   /* position of mouse */
-    double    m_Quat[4];            /* orientation of object */
-    double    m_Rot[4];             /* man rotation of object */
-    double    m_Zoom;               /* field of view in degrees */
-    S3D_Color m_BgColor;
-    bool      m_DrawFlags[FL_LAST]; /* show these special items */
-    wxPoint   m_BoardPos;
-    wxSize    m_BoardSize;
-    int       m_Layers;
-
-    const BOARD_DESIGN_SETTINGS*    m_BoardSettings;   // Link to current board design settings
-
-    double    m_Epoxy_Width;    // Epoxy thickness (normalized)
-
-    double    m_BoardScale;     /* Normalization scale for coordinates:
-                                 * when scaled between -1.0 and +1.0 */
-    double    m_LayerZcoord[32];
-    double    m_ActZpos;
-
+    double      m_Beginx, m_Beginy;     /* position of mouse */
+    double      m_Quat[4];              /* orientation of object */
+    double      m_Rot[4];               /* man rotation of object */
+    double      m_Zoom;                 /* field of view in degrees */
+    S3D_Color   m_BgColor;
+    bool        m_DrawFlags[FL_LAST];   /* show these special items */
+    wxPoint     m_BoardPos;
+    wxSize      m_BoardSize;
+    int         m_Layers;
+
+    const BOARD_DESIGN_SETTINGS* m_BoardSettings;   // Link to current board design settings
+
+    double  m_Epoxy_Width;                          // Epoxy thickness (normalized)
+
+    double  m_BoardScale;                           /* Normalization scale for coordinates:
+                                                     * when scaled between -1.0 and +1.0 */
+    double  m_LayerZcoord[32];
+    double  m_ActZpos;
 public: Info_3D_Visu();
     ~Info_3D_Visu();
 };
@@ -171,76 +168,76 @@ class EDA_3D_CANVAS : public wxGLCanvas
 private:
     bool            m_init;
     GLuint          m_gllist;
-    /// Tracks whether to use Orthographic or Perspective projection
-    //  TODO: Does this belong here, or in  EDA_3D_FRAME ???
+    // / Tracks whether to use Orthographic or Perspective projection
+    // TODO: Does this belong here, or in  EDA_3D_FRAME ???
     bool            m_ortho;
     wxGLContext*    m_glRC;
     wxRealPoint     m_draw3dOffset;     // offset to draw the 3 mesh.
     double          m_ZBottom;          // position of the back layer
     double          m_ZTop;             // position of the front layer
-
-
 public:
     EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList = 0 );
     ~EDA_3D_CANVAS();
 
-    EDA_3D_FRAME*   Parent() { return (EDA_3D_FRAME*)GetParent(); }
+    EDA_3D_FRAME* Parent() { return (EDA_3D_FRAME*) GetParent(); }
 
-    void   ClearLists();
+    void    ClearLists();
 
     // Event functions:
-    void   OnPaint( wxPaintEvent& event );
-    void   OnEraseBackground( wxEraseEvent& event );
-    void   OnChar( wxKeyEvent& event );
-    void   OnMouseWheel( wxMouseEvent& event );
-    void   OnMouseMove( wxMouseEvent& event );
-    void   OnRightClick( wxMouseEvent& event );
-    void   OnPopUpMenu( wxCommandEvent& event );
-    void   TakeScreenshot( wxCommandEvent& event );
-    void   OnEnterWindow( wxMouseEvent& event );
+    void    OnPaint( wxPaintEvent& event );
+    void    OnEraseBackground( wxEraseEvent& event );
+    void    OnChar( wxKeyEvent& event );
+    void    OnMouseWheel( wxMouseEvent& event );
+    void    OnMouseMove( wxMouseEvent& event );
+    void    OnRightClick( wxMouseEvent& event );
+    void    OnPopUpMenu( wxCommandEvent& event );
+    void    TakeScreenshot( wxCommandEvent& event );
+    void    OnEnterWindow( wxMouseEvent& event );
 
     // Display functions
-    GLuint DisplayCubeforTest();        // Just a test function
-    void   SetView3D( int keycode );
-    void   DisplayStatus();
-    void   Redraw( bool finish = false );
-    void   Render();
+    GLuint  DisplayCubeforTest();       // Just a test function
+    void    SetView3D( int keycode );
+    void    DisplayStatus();
+    void    Redraw( bool finish = false );
+    void    Render();
 
     /**
      * Function CreateDrawGL_List
      * creates the OpenGL draw list items.
      */
-    GLuint CreateDrawGL_List();
-    void   InitGL();
-    void   SetLights();
-    void   SetOffset(double aPosX, double aPosY)
+    GLuint  CreateDrawGL_List();
+    void    InitGL();
+    void    SetLights();
+
+    void   SetOffset( double aPosX, double aPosY )
     {
-        m_draw3dOffset.x = aPosX;
-        m_draw3dOffset.y = aPosY;
+        m_draw3dOffset.x    = aPosX;
+        m_draw3dOffset.y    = aPosY;
     }
-    void   Draw3D_Track( TRACK* track );
+
+    void    Draw3D_Track( TRACK* track );
 
     /**
      * Function Draw3D_SolidPolygonsInZones
      * draw all solid polygons used as filled areas in a zone
      * @param aZone = the zone to draw
-    */
-    void   Draw3D_SolidPolygonsInZones( ZONE_CONTAINER* aZone );
+     */
+    void    Draw3D_SolidPolygonsInZones( ZONE_CONTAINER* aZone );
 
     /**
      * Function Draw3D_Polygon
      * draw one solid polygon
      * @param aCornersList = a std::vector<wxPoint> list of corners, in physical coordinates
      * @param aZpos = the z position in 3D units
-    */
-    void   Draw3D_Polygon( std::vector<wxPoint>& aCornersList, double aZpos );
+     */
+    void    Draw3D_Polygon( std::vector<wxPoint>& aCornersList, double aZpos );
 
     /**
      * Function Draw3D_Via
      * draws 3D via as a cylinder and filled circles.
      */
-    void   Draw3D_Via( SEGVIA* via );
-    void   Draw3D_DrawSegment( DRAWSEGMENT* segment );
+    void    Draw3D_Via( SEGVIA* via );
+    void    Draw3D_DrawSegment( DRAWSEGMENT* segment );
 
     /**
      * Function Draw3D_DrawText
@@ -253,16 +250,23 @@ public:
      * Using DrawGraphicText to draw all texts ensure texts have the same shape
      * in all contexts
      */
-    void   Draw3D_DrawText( TEXTE_PCB* text );
+    void    Draw3D_DrawText( TEXTE_PCB* text );
+    void    Draw3D_DrawText( TEXTE_MODULE* text, double rot );
 
-    /// Toggles orthographic projection on and off
-    void ToggleOrtho(){ m_ortho = !m_ortho ; Refresh(true);};
+    // / Toggles orthographic projection on and off
+    void ToggleOrtho() { m_ortho = !m_ortho; Refresh( true ); };
 
-    /// Returns the orthographic projection flag
-    bool ModeIsOrtho() { return m_ortho ;};
+    // / Returns the orthographic projection flag
+    bool ModeIsOrtho() { return m_ortho; };
 
 
-    //int Get3DLayerEnable(int act_layer);
+    // int Get3DLayerEnable(int act_layer);
+    // GLUtesselator* Get_mftess() { return mftess; };
+    // GLUtesselator* Get_mbtess() { return mbtess; };
+    // int Get_tmonly() { return tmonly; };
+    // void Set_mftess(GLUtesselator* tess) { mftess = tess; };
+    // void Set_mbtess(GLUtesselator* tess) { mbtess = tess; };
+    // void Set_tmonly(int i) { tmonly = i; };
 
     DECLARE_EVENT_TABLE()
 };
@@ -280,7 +284,6 @@ private:
     wxSize          m_FrameSize;
     wxAuiManager    m_auimgr;
     bool            m_reloadRequest;
-
 public:
     EDA_3D_FRAME( PCB_BASE_FRAME* parent, const wxString& title,
                   long style = KICAD_DEFAULT_3D_DRAWFRAME_STYLE );
@@ -289,15 +292,15 @@ public:
         m_auimgr.UnInit();
     };
 
-    PCB_BASE_FRAME* Parent() { return (PCB_BASE_FRAME*)GetParent(); }
-    void Exit3DFrame( wxCommandEvent& event );
-    void OnCloseWindow( wxCloseEvent& Event );
-    void ReCreateMenuBar();
-    void ReCreateHToolbar();
-    void ReCreateVToolbar();
-    void SetToolbars();
-    void GetSettings();
-    void SaveSettings();
+    PCB_BASE_FRAME* Parent() { return (PCB_BASE_FRAME*) GetParent(); }
+    void    Exit3DFrame( wxCommandEvent& event );
+    void    OnCloseWindow( wxCloseEvent& Event );
+    void    ReCreateMenuBar();
+    void    ReCreateHToolbar();
+    void    ReCreateVToolbar();
+    void    SetToolbars();
+    void    GetSettings();
+    void    SaveSettings();
 
     /**
      * Function ReloadRequest
@@ -305,30 +308,30 @@ public:
      * mainly after edition of the board or footprint being displayed.
      * mainly for the module editor.
      */
-    void ReloadRequest( )
+    void ReloadRequest()
     {
         m_reloadRequest = true;
     }
 
-    void OnLeftClick( wxDC* DC, const wxPoint& MousePos );
-    void OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu );
-    void OnKeyEvent( wxKeyEvent& event );
-    double BestZoom();
-    void RedrawActiveWindow( wxDC* DC, bool EraseBg );
-    void Process_Special_Functions( wxCommandEvent& event );
-    void Process_Zoom( wxCommandEvent& event );
-    void OnActivate( wxActivateEvent& event );
+    void    OnLeftClick( wxDC* DC, const wxPoint& MousePos );
+    void    OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu );
+    void    OnKeyEvent( wxKeyEvent& event );
+    double  BestZoom();
+    void    RedrawActiveWindow( wxDC* DC, bool EraseBg );
+    void    Process_Special_Functions( wxCommandEvent& event );
+    void    Process_Zoom( wxCommandEvent& event );
+    void    OnActivate( wxActivateEvent& event );
 
-    void NewDisplay();
-    void Set3DBgColor();
+    void    NewDisplay();
+    void    Set3DBgColor();
 
     DECLARE_EVENT_TABLE()
 };
 
-void SetGLColor( int color );
-void Set_Object_Data( std::vector< S3D_Vertex >& aVertices );
+void        SetGLColor( int color );
+void        Set_Object_Data( std::vector<S3D_Vertex>& aVertices );
 
 extern Info_3D_Visu g_Parm_3D_Visu;
 extern double       DataScale3D; // 3D scale units.
 
-#endif  /*  __3D_VIEWER_H__ */
+#endif /*  __3D_VIEWER_H__ */
Only in 3d-viewer/: ORIG
diff -rup 3d-viewer.orig//trackball.cpp 3d-viewer//trackball.cpp
--- 3d-viewer.orig//trackball.cpp	2012-06-03 22:21:14.097611468 +0200
+++ 3d-viewer//trackball.cpp	2012-06-03 22:16:21.655545382 +0200
@@ -60,91 +60,92 @@
  * simple example, though, so that is left as an Exercise for the
  * Programmer.
  */
-#define TRACKBALLSIZE  (0.8f)
+#define TRACKBALLSIZE (0.8f)
 
 /*
  * Local function prototypes (not defined in trackball.h)
  */
-static double tb_project_to_sphere(double, double, double);
-static void normalize_quat(double [4]);
+static double   tb_project_to_sphere( double, double, double );
+static void     normalize_quat( double[4] );
 
-void
-vzero(double *v)
+void vzero( double* v )
 {
-    v[0] = 0.0;
-    v[1] = 0.0;
-    v[2] = 0.0;
+    v[0]    = 0.0;
+    v[1]    = 0.0;
+    v[2]    = 0.0;
 }
 
-void
-vset(double *v, double x, double y, double z)
+
+void vset( double* v, double x, double y, double z )
 {
-    v[0] = x;
-    v[1] = y;
-    v[2] = z;
+    v[0]    = x;
+    v[1]    = y;
+    v[2]    = z;
 }
 
-void
-vsub(const double *src1, const double *src2, double *dst)
+
+void vsub( const double* src1, const double* src2, double* dst )
 {
-    dst[0] = src1[0] - src2[0];
-    dst[1] = src1[1] - src2[1];
-    dst[2] = src1[2] - src2[2];
+    dst[0]  = src1[0] - src2[0];
+    dst[1]  = src1[1] - src2[1];
+    dst[2]  = src1[2] - src2[2];
 }
 
-void
-vcopy(const double *v1, double *v2)
+
+void vcopy( const double* v1, double* v2 )
 {
     register int i;
-    for (i = 0 ; i < 3 ; i++)
+
+    for( i = 0; i < 3; i++ )
         v2[i] = v1[i];
 }
 
-void
-vcross(const double *v1, const double *v2, double *cross)
+
+void vcross( const double* v1, const double* v2, double* cross )
 {
     double temp[3];
 
     temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
     temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
     temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
-    vcopy(temp, cross);
+    vcopy( temp, cross );
 }
 
-double
-vlength(const double *v)
+
+double vlength( const double* v )
 {
-    return (double) sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+    return (double) sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
 }
 
-void
-vscale(double *v, double div)
+
+void vscale( double* v, double div )
 {
-    v[0] *= div;
-    v[1] *= div;
-    v[2] *= div;
+    v[0]    *= div;
+    v[1]    *= div;
+    v[2]    *= div;
 }
 
-void
-vnormal(double *v)
+
+void vnormal( double* v )
 {
-    vscale(v, 1.0f/vlength(v));
+    vscale( v, 1.0f / vlength( v ) );
 }
 
-double
-vdot(const double *v1, const double *v2)
+
+double vdot( const double* v1, const double* v2 )
 {
-    return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+    return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
 }
 
-void
-vadd(const double *src1, const double *src2, double *dst)
+
+void vadd( const double* src1, const double* src2, double* dst )
 {
-    dst[0] = src1[0] + src2[0];
-    dst[1] = src1[1] + src2[1];
-    dst[2] = src1[2] + src2[2];
+    dst[0]  = src1[0] + src2[0];
+    dst[1]  = src1[1] + src2[1];
+    dst[2]  = src1[2] + src2[2];
 }
 
+
 /*
  * Ok, simulate a track-ball.  Project the points onto the virtual
  * trackball, then figure out the axis of rotation, which is the cross
@@ -157,17 +158,17 @@ vadd(const double *src1, const double *s
  * It is assumed that the arguments to this routine are in the range
  * (-1.0 ... 1.0)
  */
-void
-trackball(double q[4], double p1x, double p1y, double p2x, double p2y)
+void trackball( double q[4], double p1x, double p1y, double p2x, double p2y )
 {
-    double a[3]; /* Axis of rotation */
-    double phi;  /* how much to rotate about axis */
-    double p1[3], p2[3], d[3];
-    double t;
+    double  a[3];   /* Axis of rotation */
+    double  phi;    /* how much to rotate about axis */
+    double  p1[3], p2[3], d[3];
+    double  t;
 
-    if (p1x == p2x && p1y == p2y) {
+    if( p1x == p2x && p1y == p2y )
+    {
         /* Zero rotation */
-        vzero(q);
+        vzero( q );
         q[3] = 1.0;
         return;
     }
@@ -176,61 +177,71 @@ trackball(double q[4], double p1x, doubl
      * First, figure out z-coordinates for projection of P1 and P2 to
      * deformed sphere
      */
-    vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y));
-    vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y));
+    vset( p1, p1x, p1y, tb_project_to_sphere( TRACKBALLSIZE, p1x, p1y ) );
+    vset( p2, p2x, p2y, tb_project_to_sphere( TRACKBALLSIZE, p2x, p2y ) );
 
     /*
      *  Now, we want the cross product of P1 and P2
      */
-    vcross(p2,p1,a);
+    vcross( p2, p1, a );
 
     /*
      *  Figure out how much to rotate around that axis.
      */
-    vsub(p1, p2, d);
-    t = vlength(d) / (2.0f*TRACKBALLSIZE);
+    vsub( p1, p2, d );
+    t = vlength( d ) / (2.0f * TRACKBALLSIZE);
 
     /*
      * Avoid problems with out-of-control values...
      */
-    if (t > 1.0) t = 1.0;
-    if (t < -1.0) t = -1.0;
-    phi = 2.0f * (double) asin(t);
+    if( t > 1.0 )
+        t = 1.0;
+
+    if( t < -1.0 )
+        t = -1.0;
 
-    axis_to_quat(a,phi,q);
+    phi = 2.0f * (double) asin( t );
+
+    axis_to_quat( a, phi, q );
 }
 
+
 /*
  *  Given an axis and angle, compute quaternion.
  */
-void
-axis_to_quat(double a[3], double phi, double q[4])
+void axis_to_quat( double a[3], double phi, double q[4] )
 {
-    vnormal(a);
-    vcopy(a, q);
-    vscale(q, (double) sin(phi/2.0));
-    q[3] = (double) cos(phi/2.0);
+    vnormal( a );
+    vcopy( a, q );
+    vscale( q, (double) sin( phi / 2.0 ) );
+    q[3] = (double) cos( phi / 2.0 );
 }
 
+
 /*
  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
  * if we are away from the center of the sphere.
  */
-static double
-tb_project_to_sphere(double r, double x, double y)
+static double tb_project_to_sphere( double r, double x, double y )
 {
     double d, t, z;
 
-    d = (double) sqrt(x*x + y*y);
-    if (d < r * 0.70710678118654752440) {    /* Inside sphere */
-        z = (double) sqrt(r*r - d*d);
-    } else {           /* On hyperbola */
-        t = r / 1.41421356237309504880f;
-        z = t*t / d;
+    d = (double) sqrt( x * x + y * y );
+
+    if( d < r * 0.70710678118654752440 )      /* Inside sphere */
+    {
+        z = (double) sqrt( r * r - d * d );
+    }
+    else               /* On hyperbola */
+    {
+        t   = r / 1.41421356237309504880f;
+        z   = t * t / d;
     }
+
     return z;
 }
 
+
 /*
  * Given two rotations, e1 and e2, expressed as quaternion rotations,
  * figure out the equivalent single rotation and stuff it into dest.
@@ -244,35 +255,36 @@ tb_project_to_sphere(double r, double x,
 
 #define RENORMCOUNT 97
 
-void
-add_quats(double q1[4], double q2[4], double dest[4])
+void add_quats( double q1[4], double q2[4], double dest[4] )
 {
-    static int count=0;
-    double t1[4], t2[4], t3[4];
-    double tf[4];
-
-    vcopy(q1,t1);
-    vscale(t1,q2[3]);
-
-    vcopy(q2,t2);
-    vscale(t2,q1[3]);
-
-    vcross(q2,q1,t3);
-    vadd(t1,t2,tf);
-    vadd(t3,tf,tf);
-    tf[3] = q1[3] * q2[3] - vdot(q1,q2);
+    static int  count = 0;
+    double      t1[4], t2[4], t3[4];
+    double      tf[4];
+
+    vcopy( q1, t1 );
+    vscale( t1, q2[3] );
+
+    vcopy( q2, t2 );
+    vscale( t2, q1[3] );
+
+    vcross( q2, q1, t3 );
+    vadd( t1, t2, tf );
+    vadd( t3, tf, tf );
+    tf[3] = q1[3] * q2[3] - vdot( q1, q2 );
 
     dest[0] = tf[0];
     dest[1] = tf[1];
     dest[2] = tf[2];
     dest[3] = tf[3];
 
-    if (++count > RENORMCOUNT) {
+    if( ++count > RENORMCOUNT )
+    {
         count = 0;
-        normalize_quat(dest);
+        normalize_quat( dest );
     }
 }
 
+
 /*
  * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
  * If they don't add up to 1.0, dividing by their magnitued will
@@ -285,20 +297,23 @@ add_quats(double q1[4], double q2[4], do
  * - Pletinckx, D., Quaternion calculus as a basic tool in computer
  *   graphics, The Visual Computer 5, 2-13, 1989.
  */
-static void normalize_quat(double q[4])
+static void normalize_quat( double q[4] )
 {
-    int i;
-    double mag;
+    int     i;
+    double  mag;
+
+    mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
 
-    mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
-    for (i = 0; i < 4; i++) q[i] /= mag;
+    for( i = 0; i < 4; i++ )
+        q[i] /= mag;
 }
 
+
 /*
  * Build a rotation matrix, given a quaternion rotation.
  *
  */
-void build_rotmatrix(GLfloat m[4][4], double q[4])
+void build_rotmatrix( GLfloat m[4][4], double q[4] )
 {
     m[0][0] = 1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]);
     m[0][1] = 2.0f * (q[0] * q[1] - q[2] * q[3]);
@@ -306,7 +321,7 @@ void build_rotmatrix(GLfloat m[4][4], do
     m[0][3] = 0.0f;
 
     m[1][0] = 2.0f * (q[0] * q[1] + q[2] * q[3]);
-    m[1][1]= 1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]);
+    m[1][1] = 1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]);
     m[1][2] = 2.0f * (q[1] * q[2] - q[0] * q[3]);
     m[1][3] = 0.0f;
 
@@ -320,4 +335,3 @@ void build_rotmatrix(GLfloat m[4][4], do
     m[3][2] = 0.0f;
     m[3][3] = 1.0f;
 }
-
diff -rup 3d-viewer.orig//trackball.h 3d-viewer//trackball.h
--- 3d-viewer.orig//trackball.h	2012-06-03 22:21:14.097611468 +0200
+++ 3d-viewer//trackball.h	2012-06-03 22:16:21.655545382 +0200
@@ -47,7 +47,7 @@
  * The resulting rotation is returned as a quaternion rotation in the
  * first paramater.
  */
-void trackball(double q[4], double p1x, double p1y, double p2x, double p2y);
+void trackball( double q[4], double p1x, double p1y, double p2x, double p2y );
 
 /*
  * Given two quaternions, add them together to get a third quaternion.
@@ -57,18 +57,17 @@ void trackball(double q[4], double p1x,
  * rotation, the second and third the total rotation (which will be
  * over-written with the resulting new total rotation).
  */
-void add_quats(double *q1, double *q2, double *dest);
+void add_quats( double* q1, double* q2, double* dest );
 
 /*
  * A useful function, builds a rotation matrix in Matrix based on
  * given quaternion.
  */
-void build_rotmatrix(GLfloat m[4][4], double q[4]);
+void build_rotmatrix( GLfloat m[4][4], double q[4] );
 
 /*
  * This function computes a quaternion based on an axis (defined by
  * the given vector) and an angle about which to rotate.  The angle is
  * expressed in radians.  The result is put into the third argument.
  */
-void axis_to_quat(double a[3], double phi, double q[4]);
-
+void axis_to_quat( double a[3], double phi, double q[4] );
Only in 3d-viewer/: xxxx

Follow ups