示例#1
0
wxPoint EDA_3D_CANVAS::getBoardCenter() const
{
    // return the position of the board center in pcb units
    return GetPrm3DVisu().m_BoardPos;
}
示例#2
0
// draw a 3D grid: an horizontal grid (XY plane and Z = 0,
// and a vertical grid (XZ plane and Y = 0)
void EDA_3D_CANVAS::Draw3DGrid( double aGriSizeMM )
{
    double      zpos = 0.0;
    EDA_COLOR_T gridcolor = DARKGRAY;           // Color of grid lines
    EDA_COLOR_T gridcolor_marker = LIGHTGRAY;   // Color of grid lines every 5 lines
    const double scale = GetPrm3DVisu().m_BiuTo3Dunits;
    const double transparency = 0.3;

    glNormal3f( 0.0, 0.0, 1.0 );

    wxSize  brd_size = getBoardSize();
    wxPoint brd_center_pos = getBoardCenter();
    NEGATE( brd_center_pos.y );

    int     xsize   = std::max( brd_size.x, Millimeter2iu( 100 ) );
    int     ysize   = std::max( brd_size.y, Millimeter2iu( 100 ) );

    // Grid limits, in 3D units
    double  xmin    = (brd_center_pos.x - xsize / 2) * scale;
    double  xmax    = (brd_center_pos.x + xsize / 2) * scale;
    double  ymin    = (brd_center_pos.y - ysize / 2) * scale;
    double  ymax    = (brd_center_pos.y + ysize / 2) * scale;
    double  zmin    = Millimeter2iu( -50 ) * scale;
    double  zmax    = Millimeter2iu( 100 ) * scale;

    // Draw horizontal grid centered on 3D origin (center of the board)
    for( int ii = 0; ; ii++ )
    {
        if( (ii % 5) )
            SetGLColor( gridcolor, transparency );
        else
            SetGLColor( gridcolor_marker, transparency );

        int delta = KiROUND( ii * aGriSizeMM * IU_PER_MM );

        if( delta <= xsize / 2 )    // Draw grid lines parallel to X axis
        {
            glBegin( GL_LINES );
            glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
            glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
            glEnd();

            if( ii != 0 )
            {
                glBegin( GL_LINES );
                glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
                glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
                glEnd();
            }
        }

        if( delta <= ysize / 2 )    // Draw grid lines parallel to Y axis
        {
            glBegin( GL_LINES );
            glVertex3f( xmin, -(brd_center_pos.y + delta) * scale, zpos );
            glVertex3f( xmax, -(brd_center_pos.y + delta) * scale, zpos );
            glEnd();

            if( ii != 0 )
            {
                glBegin( GL_LINES );
                glVertex3f( xmin, -(brd_center_pos.y - delta) * scale, zpos );
                glVertex3f( xmax, -(brd_center_pos.y - delta) * scale, zpos );
                glEnd();
            }
        }

        if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
            break;
    }

    // Draw vertical grid n Z axis
    glNormal3f( 0.0, -1.0, 0.0 );

    // Draw vertical grid lines (parallel to Z axis)
    for( int ii = 0; ; ii++ )
    {
        if( (ii % 5) )
            SetGLColor( gridcolor, transparency );
        else
            SetGLColor( gridcolor_marker, transparency );

        double delta = ii * aGriSizeMM * IU_PER_MM;

        glBegin( GL_LINES );
        glVertex3f( (brd_center_pos.x + delta) * scale, -brd_center_pos.y * scale, zmin );
        glVertex3f( (brd_center_pos.x + delta) * scale, -brd_center_pos.y * scale, zmax );
        glEnd();

        if( ii != 0 )
        {
            glBegin( GL_LINES );
            glVertex3f( (brd_center_pos.x - delta) * scale, -brd_center_pos.y * scale, zmin );
            glVertex3f( (brd_center_pos.x - delta) * scale, -brd_center_pos.y * scale, zmax );
            glEnd();
        }

        if( delta > xsize / 2.0f )
            break;
    }

    // Draw horizontal grid lines on Z axis
    for( int ii = 0; ; ii++ )
    {
        if( (ii % 5) )
            SetGLColor( gridcolor, transparency);
        else
            SetGLColor( gridcolor_marker, transparency );

        double delta = ii * aGriSizeMM * IU_PER_MM * scale;

        if( delta <= zmax )
        {
            // Draw grid lines on Z axis (positive Z axis coordinates)
            glBegin( GL_LINES );
            glVertex3f( xmin, -brd_center_pos.y * scale, delta );
            glVertex3f( xmax, -brd_center_pos.y * scale, delta );
            glEnd();
        }

        if( delta <= -zmin && ( ii != 0 ) )
        {
            // Draw grid lines on Z axis (negative Z axis coordinates)
            glBegin( GL_LINES );
            glVertex3f( xmin, -brd_center_pos.y * scale, -delta );
            glVertex3f( xmax, -brd_center_pos.y * scale, -delta );
            glEnd();
        }

        if( ( delta > zmax ) && ( delta > -zmin ) )
            break;
    }
}
示例#3
0
wxSize EDA_3D_CANVAS::getBoardSize() const
{
    // return the size of the board in pcb units
    return GetPrm3DVisu().m_BoardSize;
}
示例#4
0
void EDA_3D_CANVAS::SetView3D( int keycode )
{
    int    ii;
    double delta_move = 0.7 * GetPrm3DVisu().m_Zoom;

    switch( keycode )
    {
    case WXK_LEFT:
        m_draw3dOffset.x -= delta_move;
        break;

    case WXK_RIGHT:
        m_draw3dOffset.x += delta_move;
        break;

    case WXK_UP:
        m_draw3dOffset.y += delta_move;
        break;

    case WXK_DOWN:
        m_draw3dOffset.y -= delta_move;
        break;

    case WXK_HOME:
        GetPrm3DVisu().m_Zoom = 1.0;
        m_draw3dOffset.x = m_draw3dOffset.y = 0;
        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        break;

    case WXK_END:
        break;

    case WXK_F1:
        GetPrm3DVisu().m_Zoom /= 1.4;
        if( GetPrm3DVisu().m_Zoom <= 0.01 )
            GetPrm3DVisu().m_Zoom = 0.01;
        break;

    case WXK_F2:
        GetPrm3DVisu().m_Zoom *= 1.4;
        break;

    case '+':
        break;

    case '-':
        break;

    case 'r':
    case 'R':
        m_draw3dOffset.x = m_draw3dOffset.y = 0;
        for( ii = 0; ii < 4; ii++ )
            GetPrm3DVisu().m_Rot[ii] = 0.0;

        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        break;

    case 'x':
        for( ii = 0; ii < 4; ii++ )
            GetPrm3DVisu().m_Rot[ii] = 0.0;

        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        GetPrm3DVisu().m_ROTZ = -90;
        GetPrm3DVisu().m_ROTX = -90;
        break;

    case 'X':
        for( ii = 0; ii < 4; ii++ )
            GetPrm3DVisu().m_Rot[ii] = 0.0;

        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        GetPrm3DVisu().m_ROTZ = 90;
        GetPrm3DVisu().m_ROTX = -90;
        break;

    case 'y':
        for( ii = 0; ii < 4; ii++ )
            GetPrm3DVisu().m_Rot[ii] = 0.0;

        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        GetPrm3DVisu().m_ROTX = -90;
        break;

    case 'Y':
        for( ii = 0; ii < 4; ii++ )
            GetPrm3DVisu().m_Rot[ii] = 0.0;

        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        GetPrm3DVisu().m_ROTX = -90;
        GetPrm3DVisu().m_ROTZ = -180;
        break;

    case 'z':
        for( ii = 0; ii < 4; ii++ )
            GetPrm3DVisu().m_Rot[ii] = 0.0;

        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        break;

    case 'Z':
        for( ii = 0; ii < 4; ii++ )
            GetPrm3DVisu().m_Rot[ii] = 0.0;

        trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
        GetPrm3DVisu().m_ROTX = -180;
        break;

    default:
        return;
    }

    DisplayStatus();
    Refresh( false );
}
示例#5
0
// Helper function: initialize the copper color to draw the board
// in realistic mode.
void EDA_3D_CANVAS::setGLCopperColor()
{
    glDisable( GL_TEXTURE_2D );
    SetGLColor( GetPrm3DVisu().m_CopperColor, 1.0 );
}
示例#6
0
bool EDA_3D_CANVAS::is3DLayerEnabled( LAYER_ID aLayer ) const
{
    DISPLAY3D_FLG flg;

    // see if layer needs to be shown
    // check the flags
    switch( aLayer )
    {
    case B_Adhes:
    case F_Adhes:
        flg = FL_ADHESIVE;
        break;

    case B_Paste:
    case F_Paste:
        flg = FL_SOLDERPASTE;
        break;

    case B_SilkS:
    case F_SilkS:
        flg = FL_SILKSCREEN;
        break;

    case B_Mask:
    case F_Mask:
        flg = FL_SOLDERMASK;
        break;

    case Dwgs_User:
    case Cmts_User:
        if( isRealisticMode() )
            return false;

        flg = FL_COMMENTS;
        break;

    case Eco1_User:
    case Eco2_User:
        if( isRealisticMode() )
            return false;

        flg = FL_ECO;
        break;

    case B_Cu:
    case F_Cu:
        return GetPrm3DVisu().m_BoardSettings->IsLayerVisible( aLayer )
               || isRealisticMode();
        break;

    default:
        // the layer is an internal copper layer, used the visibility
        //
        if( isRealisticMode() )
            return false;

        return GetPrm3DVisu().m_BoardSettings->IsLayerVisible( aLayer );
    }

    // The layer has a flag, return the flag
    return isEnabled( flg );
}
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
                                      REPORTER* aErrorMessages, REPORTER* aActivity  )
{
    BOARD* pcb = GetBoard();

    // If FL_RENDER_SHOW_HOLES_IN_ZONES is true, holes are correctly removed from copper zones areas.
    // If FL_RENDER_SHOW_HOLES_IN_ZONES is false, holes are not removed from copper zones areas,
    // but the calculation time is twice shorter.
    bool remove_Holes = isEnabled( FL_RENDER_SHOW_HOLES_IN_ZONES );

    bool realistic_mode = isRealisticMode();
    bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );

    // Number of segments to convert a circle to polygon
    // We use 2 values: the first gives a good shape (for instanes rond pads)
    // the second is used to speed up calculations, when a poor approximation is acceptable (holes)
    const int       segcountforcircle   = 18;
    double          correctionFactor    = 1.0 / cos( M_PI / (segcountforcircle * 2.0) );
    const int       segcountLowQuality  = 12;   // segments to draw a circle with low quality
    // to reduce time calculations
    // for holes and items which do not need
    // a fine representation
    double          correctionFactorLQ  = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) );

    SHAPE_POLY_SET  bufferPolys;        // copper areas: tracks, pads and filled zones areas
    // when holes are removed from zones
    SHAPE_POLY_SET  bufferPcbOutlines;  // stores the board main outlines
    SHAPE_POLY_SET  bufferZonesPolys;   // copper filled zones areas
    // when holes are not removed from zones
    SHAPE_POLY_SET  currLayerHoles;     // Contains holes for the current layer
    SHAPE_POLY_SET  allLayerHoles;      // Contains holes for all layers

    // Build a polygon from edge cut items
    wxString msg;

    if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
    {
        if( aErrorMessages )
        {
            msg << wxT("\n") << _("Unable to calculate the board outlines.\n"
                                  "Therefore use the board boundary box.") << wxT("\n\n");

            aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
        }
    }

    // Build board holes, with optimization of large holes shape.
    buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, true );

    LSET            cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount );

    glNewList( aBoardList, GL_COMPILE );

    for( LSEQ cu = cu_set.CuStack();  cu;  ++cu )
    {
        LAYER_ID layer = *cu;

        // Skip non enabled layers in normal mode,
        // and internal layers in realistic mode
        if( !is3DLayerEnabled( layer ) )
            continue;

        if( aActivity )
            aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );

        bufferPolys.RemoveAllContours();
        bufferZonesPolys.RemoveAllContours();
        currLayerHoles.RemoveAllContours();

        // Draw track shapes:
        for( TRACK* track = pcb->m_Track;  track;  track = track->Next() )
        {
            if( !track->IsOnLayer( layer ) )
                continue;

            track->TransformShapeWithClearanceToPolygon( bufferPolys,
                    0, segcountforcircle,
                    correctionFactor );

            // Add blind/buried via holes
            if( track->Type() == PCB_VIA_T )
            {
                VIA *via = static_cast<VIA*>( track );

                if( via->GetViaType() == VIA_THROUGH )
                    continue;   // already done

                int holediameter = via->GetDrillValue();
                int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
                int hole_outer_radius = (holediameter + thickness) / 2;

                TransformCircleToPolygon( currLayerHoles,
                                          via->GetStart(), hole_outer_radius,
                                          segcountLowQuality );
            }
        }

        // draw pad shapes
        for( MODULE* module = pcb->m_Modules;  module;  module = module->Next() )
        {
            // Note: NPTH pads are not drawn on copper layers when the pad
            // has same shape as its hole
            module->TransformPadsShapesWithClearanceToPolygon( layer,
                    bufferPolys,
                    0,
                    segcountforcircle,
                    correctionFactor, true );

            // Micro-wave modules may have items on copper layers
            module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
                    bufferPolys,
                    0,
                    segcountforcircle,
                    correctionFactor );

            // pad holes are already in list.
        }

        // Draw copper zones. Note:
        // * if the holes are removed from copper zones
        // the polygons are stored in bufferPolys (which contains all other polygons)
        // * if the holes are NOT removed from copper zones
        // the polygons are stored in bufferZonesPolys
        if( isEnabled( FL_ZONE ) )
        {
            for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
            {
                ZONE_CONTAINER* zone = pcb->GetArea( ii );
                LAYER_NUM       zonelayer = zone->GetLayer();

                if( zonelayer == layer )
                {
                    zone->TransformSolidAreasShapesToPolygonSet(
                        remove_Holes ? bufferPolys : bufferZonesPolys,
                        segcountLowQuality, correctionFactorLQ );
                }
            }
        }

        // draw graphic items on copper layers (texts)
        for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
        {
            if( !item->IsOnLayer( layer ) )
                continue;

            switch( item->Type() )
            {
            case PCB_LINE_T:    // should not exist on copper layers
                ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                    bufferPolys, 0, segcountforcircle, correctionFactor );
                break;

            case PCB_TEXT_T:
                ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
                    bufferPolys, 0, segcountLowQuality, correctionFactor );
                break;

            default:
                break;
            }
        }

        // bufferPolys contains polygons to merge. Many overlaps .
        // Calculate merged polygons
        if( bufferPolys.IsEmpty() )
            continue;

        // Use Clipper lib to subtract holes to copper areas
        if( currLayerHoles.OutlineCount() )
        {
            currLayerHoles.Append(allLayerHoles);
            currLayerHoles.Simplify( polygonsCalcMode );
            bufferPolys.BooleanSubtract( currLayerHoles, polygonsCalcMode );
        }
        else
            bufferPolys.BooleanSubtract( allLayerHoles, polygonsCalcMode );

        int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
        int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );

        float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)

        // If we are not using thickness, then the z-normal has to match the layer direction
        // because just one plane will be drawn
        if( !thickness )
            zNormal = Get3DLayer_Z_Orientation( layer );

        if( realistic_mode )
        {
            setGLCopperColor();
        }
        else
        {
            EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
            SetGLColor( color );
        }

        // If holes are removed from copper zones, bufferPolys contains all polygons
        // to draw (tracks+zones+texts).
        Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness,
                                            GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
                                            zNormal );

        // If holes are not removed from copper zones (for calculation time reasons,
        // the zone polygons are stored in bufferZonesPolys and have to be drawn now:
        if( !bufferZonesPolys.IsEmpty() )
        {
            Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness,
                                                GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
                                                zNormal );
        }
    }

    if( aActivity )
        aActivity->Report( _( "Build board body" ) );

    // Draw plated vertical holes inside the board, but not always. They are drawn:
    // - if the board body is not shown, to show the holes.
    // - or if the copper thickness is shown
    if( !isEnabled( FL_SHOW_BOARD_BODY ) || isEnabled( FL_USE_COPPER_THICKNESS ) )
    {
        // Draw vias holes (vertical cylinders)
        for( const TRACK* track = pcb->m_Track;  track;  track = track->Next() )
        {
            if( track->Type() == PCB_VIA_T )
            {
                const VIA *via = static_cast<const VIA*>(track);
                draw3DViaHole( via );
            }
        }

        // Draw pads holes (vertical cylinders)
        for( const MODULE* module = pcb->m_Modules;  module;  module = module->Next() )
        {
            for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
                if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED )
                    draw3DPadHole( pad );
        }
    }

    glEndList();

    // Build the body board:
    glNewList( aBodyOnlyList, GL_COMPILE );

    if( isRealisticMode() )
    {
        setGLEpoxyColor( 1.00 );
    }
    else
    {
        EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
        SetGLColor( color, 0.7 );
    }

    float copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();

    // a small offset between substrate and external copper layer to avoid artifacts
    // when drawing copper items on board
    float epsilon = Millimeter2iu( 0.01 );
    float zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
    float board_thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
                            - GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );

    // items on copper layers and having a thickness = copper_thickness
    // are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
    // therefore substrate position is copper_thickness/2 to
    // substrate_height - copper_thickness/2
    zpos += (copper_thickness + epsilon) / 2.0f;
    board_thickness -= copper_thickness + epsilon;

    bufferPcbOutlines.BooleanSubtract( allLayerHoles, polygonsCalcMode );

    if( !bufferPcbOutlines.IsEmpty() )
    {
        Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0,
                                            board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
                                            1.0f );
    }

    glEndList();
}
void EDA_3D_CANVAS::CreateDrawGL_List( REPORTER* aErrorMessages, REPORTER* aActivity )
{
    BOARD* pcb = GetBoard();

    wxBusyCursor    dummy;

    // Build 3D board parameters:
    GetPrm3DVisu().InitSettings( pcb );

    glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );

    // Create axis gl list (if it is not shown, the list will be not called
    draw3DAxis();

    // Create Board full gl lists:

    if( ! m_glLists[GL_ID_BOARD] )
    {
        DBG( unsigned strtime = GetRunningMicroSecs() );

        m_glLists[GL_ID_BOARD] = glGenLists( 1 );
        m_glLists[GL_ID_BODY] = glGenLists( 1 );
        buildBoard3DView(m_glLists[GL_ID_BOARD], m_glLists[GL_ID_BODY], aErrorMessages, aActivity );
        CheckGLError( __FILE__, __LINE__ );

        DBG( printf( "  buildBoard3DView total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
    }

    if( ! m_glLists[GL_ID_TECH_LAYERS] )
    {
        DBG( unsigned strtime = GetRunningMicroSecs() );

        m_glLists[GL_ID_TECH_LAYERS] = glGenLists( 1 );
        glNewList( m_glLists[GL_ID_TECH_LAYERS], GL_COMPILE );
        // when calling BuildTechLayers3DView,
        // do not show warnings, which are the same as buildBoard3DView
        buildTechLayers3DView( aErrorMessages, aActivity );
        glEndList();
        CheckGLError( __FILE__, __LINE__ );

        DBG( printf( "  buildTechLayers3DView total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
    }

    if( ! m_glLists[GL_ID_AUX_LAYERS] )
    {
        DBG( unsigned strtime = GetRunningMicroSecs() );

        m_glLists[GL_ID_AUX_LAYERS] = glGenLists( 1 );
        glNewList( m_glLists[GL_ID_AUX_LAYERS], GL_COMPILE );
        buildBoard3DAuxLayers( aErrorMessages, aActivity );
        glEndList();
        CheckGLError( __FILE__, __LINE__ );

        DBG( printf( "  buildBoard3DAuxLayers total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
    }

    // draw modules 3D shapes
    if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] && isEnabled( FL_MODULE ) )
    {
        m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] = glGenLists( 1 );

        // GL_ID_3DSHAPES_TRANSP_FRONT is an auxiliary list for 3D shapes;
        // Ensure it is cleared before rebuilding it
        if( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] )
            glDeleteLists( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT], 1 );

        bool useMaterial = g_Parm_3D_Visu.GetFlag( FL_RENDER_MATERIAL );

        if( useMaterial )
            m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] = glGenLists( 1 );
        else
            m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] = 0;

        buildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT],
                                   m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT],
                                   aErrorMessages, aActivity );

        CheckGLError( __FILE__, __LINE__ );
    }

    calcBBox();

    // Create grid gl list
    if( ! m_glLists[GL_ID_GRID] )
    {
        m_glLists[GL_ID_GRID] = glGenLists( 1 );
        glNewList( m_glLists[GL_ID_GRID], GL_COMPILE );

        draw3DGrid( GetPrm3DVisu().m_3D_Grid );

        glEndList();
    }

    if( !m_glLists[GL_ID_SHADOW_FRONT] )
        m_glLists[GL_ID_SHADOW_FRONT] = glGenLists( 1 );

    if( !m_glLists[GL_ID_SHADOW_BACK] )
        m_glLists[GL_ID_SHADOW_BACK]  = glGenLists( 1 );

    if( !m_glLists[GL_ID_SHADOW_BOARD] )
        m_glLists[GL_ID_SHADOW_BOARD] = glGenLists( 1 );

    buildShadowList( m_glLists[GL_ID_SHADOW_FRONT],
                     m_glLists[GL_ID_SHADOW_BACK],
                     m_glLists[GL_ID_SHADOW_BOARD] );

    CheckGLError( __FILE__, __LINE__ );
}
void EDA_3D_CANVAS::calcBBox()
{
    BOARD* pcb = GetBoard();

    m_fastAABBox.Reset();

    for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
    {
        CBBOX tmpFastAABBox;

        // Compute the transformation matrix for this module based on translation, rotation and orientation.
        float  zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() );
        wxPoint pos = module->GetPosition();

        glm::mat4 fullTransformMatrix;
        fullTransformMatrix = glm::translate( glm::mat4(),  S3D_VERTEX( (float)(pos.x * GetPrm3DVisu().m_BiuTo3Dunits),
                                                                        (float)(-pos.y * GetPrm3DVisu().m_BiuTo3Dunits),
                                                                        zpos ) );

        if( module->GetOrientation() )
            fullTransformMatrix = glm::rotate( fullTransformMatrix,
                                               glm::radians( (float)(module->GetOrientation() / 10.0f) ),
                                               S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );

        if( module->IsFlipped() )
        {
            fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 1.0f, 0.0f ) );
            fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );
        }

        // Compute a union bounding box for all the shapes of the model

        S3D_MASTER* shape3D = module->Models();

        for( ; shape3D; shape3D = shape3D->Next() )
        {
            if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) )
                tmpFastAABBox.Union( shape3D->getFastAABBox() );
        }

        tmpFastAABBox.ApplyTransformationAA( fullTransformMatrix );

        m_fastAABBox.Union( tmpFastAABBox );
    }

    // Create a board bounding box based on board size
    wxSize  brd_size = getBoardSize();
    wxPoint brd_center_pos = getBoardCenter();

    float xsize   = brd_size.x;
    float ysize   = brd_size.y;

    float scale   = GetPrm3DVisu().m_BiuTo3Dunits;
    float xmin    = (brd_center_pos.x - xsize / 2.0) * scale;
    float xmax    = (brd_center_pos.x + xsize / 2.0) * scale;
    float ymin    = (brd_center_pos.y - ysize / 2.0) * scale;
    float ymax    = (brd_center_pos.y + ysize / 2.0) * scale;

    float zmin = GetPrm3DVisu().GetLayerZcoordBIU( B_Adhes ) * scale;
    float zmax = GetPrm3DVisu().GetLayerZcoordBIU( F_Adhes ) * scale;

    m_boardAABBox = CBBOX(  S3D_VERTEX(xmin, ymin, zmin),
                            S3D_VERTEX(xmax, ymax, zmax) );

    // Add BB board with BB models and scale it a bit
    m_fastAABBox.Union( m_boardAABBox );
    m_fastAABBox_Shadow = m_fastAABBox;
    m_fastAABBox_Shadow.Scale( SHADOW_BOUNDING_BOX_SCALE );
}
/**
 * Function buildBoard3DAuxLayers
 * Called by CreateDrawGL_List()
 * Fills the OpenGL GL_ID_BOARD draw list with items
 * on aux layers only
 */
void EDA_3D_CANVAS::buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* aActivity )
{
    const int   segcountforcircle   = 18;
    double      correctionFactor    = 1.0 / cos( M_PI / (segcountforcircle * 2) );
    BOARD*      pcb = GetBoard();

    CPOLYGONS_LIST  bufferPolys;

    bufferPolys.reserve( 5000 );    // Reserve for items not on board

    static const LAYER_ID sequence[] = {
        Dwgs_User,
        Cmts_User,
        Eco1_User,
        Eco2_User,
        Edge_Cuts,
        Margin
    };

    for( LSEQ aux( sequence, sequence+DIM(sequence) );  aux;  ++aux )
    {
        LAYER_ID layer = *aux;

        if( !is3DLayerEnabled( layer ) )
            continue;

        if( aActivity )
            aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );

        bufferPolys.RemoveAllContours();

        for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
        {
            if( !item->IsOnLayer( layer ) )
                continue;

            switch( item->Type() )
            {
            case PCB_LINE_T:
                ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                    bufferPolys, 0, segcountforcircle, correctionFactor );
                break;

            case PCB_TEXT_T:
                ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
                    bufferPolys, 0, segcountforcircle, correctionFactor );
                break;

            default:
                break;
            }
        }

        for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
        {
            module->TransformPadsShapesWithClearanceToPolygon( layer,
                                                               bufferPolys,
                                                               0,
                                                               segcountforcircle,
                                                               correctionFactor );

            module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
                                                                     bufferPolys,
                                                                     0,
                                                                     segcountforcircle,
                                                                     correctionFactor );
        }

        // bufferPolys contains polygons to merge. Many overlaps .
        // Calculate merged polygons and remove pads and vias holes
        if( bufferPolys.GetCornersCount() == 0 )
            continue;
        KI_POLYGON_SET  currLayerPolyset;
        KI_POLYGON_SET  polyset;
        bufferPolys.ExportTo( polyset );
        currLayerPolyset += polyset;

        int         thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
        int         zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
        // for Draw3D_SolidHorizontalPolyPolygons,
        // zpos it the middle between bottom and top sides.
        // However for top layers, zpos should be the bottom layer pos,
        // and for bottom layers, zpos should be the top layer pos.
        if( Get3DLayer_Z_Orientation( layer ) > 0 )
            zpos += thickness/2;
        else
            zpos -= thickness/2 ;

        bufferPolys.RemoveAllContours();
        bufferPolys.ImportFrom( currLayerPolyset );

        float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)

        // If we are not using thickness, then the znormal must face the layer direction
        // because it will draw just one plane
        if( !thickness )
            zNormal = Get3DLayer_Z_Orientation( layer );

        setGLTechLayersColor( layer );
        Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
                                            thickness, GetPrm3DVisu().m_BiuTo3Dunits, false,
                                            zNormal );
    }
}
void EDA_3D_CANVAS::buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList )
{
    // Board shadows are based on board dimension.

    float xmin    = m_boardAABBox.Min().x;
    float xmax    = m_boardAABBox.Max().x;
    float ymin    = m_boardAABBox.Min().y;
    float ymax    = m_boardAABBox.Max().y;

    float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;

    // Shadow FRONT
    glNewList( aFrontList, GL_COMPILE );

    glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );

    glBegin (GL_QUADS);
    glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
    glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
    glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
    glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
    glEnd();

    glEndList();


    // Shadow BACK
    zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;

    glNewList( aBacklist, GL_COMPILE );

    glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( B_Paste ) );

    glBegin (GL_QUADS);
    glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
    glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
    glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
    glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
    glEnd();

    glEndList();

    // Shadow BOARD

    // Floor shadow is based on axis alighned bounding box dimension
    xmin = m_fastAABBox_Shadow.Min().x;
    xmax = m_fastAABBox_Shadow.Max().x;
    ymin = m_fastAABBox_Shadow.Min().y;
    ymax = m_fastAABBox_Shadow.Max().y;

    glNewList( aBoardList, GL_COMPILE );
    glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );

    glBegin (GL_QUADS);
    glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, m_fastAABBox_Shadow.Min().z );
    glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, m_fastAABBox_Shadow.Min().z );
    glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, m_fastAABBox_Shadow.Min().z );
    glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, m_fastAABBox_Shadow.Min().z );
    glEnd();

    glEndList();
}
void EDA_3D_CANVAS::Redraw()
{
    // SwapBuffer requires the window to be shown before calling
    if( !IsShown() )
        return;

    wxString err_messages;
    WX_STRING_REPORTER errorReporter( &err_messages );
    STATUS_TEXT_REPORTER activityReporter( Parent(), 0 );

    // Display build time at the end of build
    unsigned strtime = GetRunningMicroSecs();

    SetCurrent( *m_glRC );

    // 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.
    wxSize size = GetClientSize();

    InitGL();

    if( isRealisticMode() && isEnabled( FL_RENDER_SHADOWS ) )
    {
        generateFakeShadowsTextures( &errorReporter, &activityReporter );
    }

    // *MUST* be called *after*  SetCurrent( ):
    glViewport( 0, 0, size.x, size.y );

    // clear color and depth buffers
    glClearColor( 0.95, 0.95, 1.0, 1.0 );
    glClearStencil( 0 );
    glClearDepth( 1.0 );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

    glShadeModel( GL_SMOOTH );

    // Draw background
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glDisable( GL_LIGHTING );
    glDisable( GL_COLOR_MATERIAL );
    glDisable( GL_DEPTH_TEST );
    glDisable( GL_TEXTURE_2D );

    // Draw the background ( rectangle with color gradient)
    glBegin( GL_QUADS );
    SetGLColor( GetPrm3DVisu().m_BgColor_Top, 1.0 );
    glVertex2f( -1.0, 1.0 );    // Top left corner

    SetGLColor( GetPrm3DVisu().m_BgColor, 1.0 );
    glVertex2f( -1.0,-1.0 );    // bottom left corner
    glVertex2f( 1.0,-1.0 );     // bottom right corner

    SetGLColor( GetPrm3DVisu().m_BgColor_Top, 1.0 );
    glVertex2f( 1.0, 1.0 );     // top right corner

    glEnd();
    glEnable( GL_DEPTH_TEST );


    // set viewing projection
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

#define MAX_VIEW_ANGLE 160.0 / 45.0

    if( GetPrm3DVisu().m_Zoom > MAX_VIEW_ANGLE )
        GetPrm3DVisu().m_Zoom = MAX_VIEW_ANGLE;

     if( Parent()->ModeIsOrtho() )
     {
         // OrthoReductionFactor is chosen to provide roughly the same size as
         // Perspective View
         const double orthoReductionFactor = 400 / GetPrm3DVisu().m_Zoom;

         // Initialize Projection Matrix for Ortographic View
         glOrtho( -size.x / orthoReductionFactor, size.x / orthoReductionFactor,
                  -size.y / orthoReductionFactor, size.y / orthoReductionFactor, 1, 100 );
     }
     else
     {
         // Ratio width / height of the window display
         double ratio_HV = (double) size.x / size.y;

         // Initialize Projection Matrix for Perspective View
         gluPerspective( 45.0f * GetPrm3DVisu().m_Zoom, ratio_HV, 1, 100 );
     }

    // position viewer
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glTranslatef( 0.0f, 0.0f, -(m_ZBottom + m_ZTop) / 2.0f );

    // Setup light sources:
    SetLights();

    CheckGLError( __FILE__, __LINE__ );

    glMatrixMode( GL_MODELVIEW );    // position viewer

    // transformations
    GLfloat mat[4][4];

    // Translate motion first, so rotations don't mess up the orientation...
    glTranslatef( m_draw3dOffset.x, m_draw3dOffset.y, 0.0F );

    build_rotmatrix( mat, GetPrm3DVisu().m_Quat );
    glMultMatrixf( &mat[0][0] );

    glRotatef( GetPrm3DVisu().m_Rot[0], 1.0, 0.0, 0.0 );
    glRotatef( GetPrm3DVisu().m_Rot[1], 0.0, 1.0, 0.0 );
    glRotatef( GetPrm3DVisu().m_Rot[2], 0.0, 0.0, 1.0 );


    if( ! m_glLists[GL_ID_BOARD] || ! m_glLists[GL_ID_TECH_LAYERS] )
        CreateDrawGL_List( &errorReporter, &activityReporter );

    if( isEnabled( FL_AXIS ) && m_glLists[GL_ID_AXIS] )
        glCallList( m_glLists[GL_ID_AXIS] );

    // move the board in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits,
                  -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits,
                  0.0f );

    if( isEnabled( FL_MODULE ) )
    {
        if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] )
            CreateDrawGL_List( &errorReporter, &activityReporter );
    }

    glEnable( GL_LIGHTING );

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    if( isRealisticMode() && isEnabled( FL_RENDER_TEXTURES ) )
        glEnable( GL_TEXTURE_2D );
    else
        glDisable( GL_TEXTURE_2D );

    // Set material for the board
    glEnable( GL_COLOR_MATERIAL );
    SetOpenGlDefaultMaterial();

    //glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, FALSE );

    // Board Body

    GLint shininess_value = 32;
    glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );

    if( isEnabled( FL_SHOW_BOARD_BODY ) )
    {
        if( m_glLists[GL_ID_BODY] )
        {
            glCallList( m_glLists[GL_ID_BODY] );
        }
    }


    // Board

    shininess_value = 52;
    glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );

    glm::vec4 specular( GetPrm3DVisu().m_CopperColor.m_Red   * 0.20f,
                        GetPrm3DVisu().m_CopperColor.m_Green * 0.20f,
                        GetPrm3DVisu().m_CopperColor.m_Blue  * 0.20f, 1.0f );
    glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );

    if( m_glLists[GL_ID_BOARD] )
    {
        glCallList( m_glLists[GL_ID_BOARD] );
    }


    // Tech layers

    shininess_value = 32;
    glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );

    glm::vec4 specularTech( 0.0f, 0.0f, 0.0f, 1.0f );
    glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specularTech.x );

    if( m_glLists[GL_ID_TECH_LAYERS] )
    {
        glCallList( m_glLists[GL_ID_TECH_LAYERS] );
    }

    if( isEnabled( FL_COMMENTS ) || isEnabled( FL_ECO )  )
    {
        if( ! m_glLists[GL_ID_AUX_LAYERS] )
            CreateDrawGL_List( &errorReporter, &activityReporter );

        glCallList( m_glLists[GL_ID_AUX_LAYERS] );
    }

    //glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, TRUE );

    // Draw Component Shadow

    if( isEnabled( FL_MODULE )  && isRealisticMode() &&
        isEnabled( FL_RENDER_SHADOWS ) )
    {
        glEnable( GL_CULL_FACE );
        glDisable( GL_DEPTH_TEST );

        glEnable( GL_COLOR_MATERIAL ) ;
        SetOpenGlDefaultMaterial();
        glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );

        glEnable( GL_TEXTURE_2D );

        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

        if( m_glLists[GL_ID_SHADOW_FRONT] )
        {
            glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_front );
            glCallList( m_glLists[GL_ID_SHADOW_FRONT] );
        }

        if( m_glLists[GL_ID_SHADOW_BACK] )
        {
            glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_back );
            glCallList( m_glLists[GL_ID_SHADOW_BACK] );
        }
        glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );

        glEnable( GL_DEPTH_TEST );
        glDisable( GL_TEXTURE_2D );
        glDisable( GL_CULL_FACE );
    }

    glEnable( GL_COLOR_MATERIAL );
    SetOpenGlDefaultMaterial();

    glDisable( GL_BLEND );


    // Draw Solid Shapes

    if( isEnabled( FL_MODULE ) )
    {
        if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] )
            CreateDrawGL_List( &errorReporter, &activityReporter );

        glCallList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] );
    }

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );


    // Grid uses transparency: draw it after all objects

    if( isEnabled( FL_GRID ) )
    {
        if( ! m_glLists[GL_ID_GRID] )
            CreateDrawGL_List( &errorReporter, &activityReporter );

        glCallList( m_glLists[GL_ID_GRID] );
    }


    // Draw Board Shadow

    if( isRealisticMode() && isEnabled( FL_RENDER_SHADOWS ) )
    {
        if( m_glLists[GL_ID_SHADOW_BOARD] )
        {
            glEnable( GL_BLEND );
            glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
            glColor4f( 1.0, 1.0, 1.0, 0.75f );
            glEnable( GL_CULL_FACE );
            glDisable( GL_COLOR_MATERIAL );
            glEnable( GL_TEXTURE_2D );
            glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_board );
            glCallList( m_glLists[GL_ID_SHADOW_BOARD] );
            glDisable( GL_CULL_FACE );
            glDisable( GL_TEXTURE_2D );
        }
    }

    // This list must be drawn last, because it contains the
    // transparent gl objects, which should be drawn after all
    // non transparent objects
    if(  isEnabled( FL_MODULE ) && m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] )
    {
        glEnable( GL_COLOR_MATERIAL );
        SetOpenGlDefaultMaterial();
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
        glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] );
    }

    // Debug bounding boxes
    /*
    glDisable( GL_BLEND );
    glDisable( GL_COLOR_MATERIAL );
    glDisable( GL_LIGHTING );
    glColor4f( 1.0f, 0.0f, 1.0f, 1.0f );
    m_fastAABBox_Shadow.GLdebug();

    glColor4f( 0.0f, 1.0f, 1.0f, 1.0f );
    m_boardAABBox.GLdebug();
    */

    SwapBuffers();

    // Show calculation time if some activity was reported
    if( activityReporter.HasMessage() )
    {
        // Calculation time in seconds
        double calculation_time = (double)( GetRunningMicroSecs() - strtime) / 1e6;

        activityReporter.Report( wxString::Format( _( "Build time %.3f s" ),
                                 calculation_time ) );
    }
    else
        activityReporter.Report( wxEmptyString );

    if( !err_messages.IsEmpty() )
        wxLogMessage( err_messages );

}
void EDA_3D_CANVAS::buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
        int aSegCountPerCircle, bool aOptimizeLargeCircles )
{
    // hole diameter value to change seg count by circle:
    int small_hole_limit = Millimeter2iu( 1.0 );
    int copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();

    BOARD* pcb = GetBoard();

    // Build holes of through vias:
    for( TRACK* track = pcb->m_Track;  track;  track = track->Next() )
    {
        if( track->Type() != PCB_VIA_T )
            continue;

        VIA *via = static_cast<VIA*>( track );

        if( via->GetViaType() != VIA_THROUGH )
            continue;

        int holediameter = via->GetDrillValue();
        int hole_outer_radius = (holediameter + copper_thickness) / 2;

        TransformCircleToPolygon( allBoardHoles,
                                  via->GetStart(), hole_outer_radius,
                                  aSegCountPerCircle );
    }

    // Build holes of through pads:
    for( MODULE* footprint = pcb->m_Modules; footprint; footprint = footprint->Next() )
    {
        for( D_PAD* pad = footprint->Pads(); pad; pad = pad->Next() )
        {
            // Calculate a factor to apply to segcount for large holes ( > 1 mm)
            // (bigger pad drill size -> more segments) because holes in pads can have
            // very different sizes and optimizing this segcount gives a better look
            // Mainly mounting holes have a size bigger than small_hole_limit
            wxSize padHole = pad->GetDrillSize();

            if( ! padHole.x )       // Not drilled pad like SMD pad
                continue;

            // we use the hole diameter to calculate the seg count.
            // for round holes, padHole.x == padHole.y
            // for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
            int diam = std::min( padHole.x, padHole.y );
            int segcount = aSegCountPerCircle;

            if( diam > small_hole_limit )
            {
                double segFactor = (double)diam / small_hole_limit;
                segcount = (int)(aSegCountPerCircle * segFactor);

                // limit segcount to 48. For a circle this is a very good approx.
                if( segcount > 48 )
                    segcount = 48;
            }

            // The hole in the body is inflated by copper thickness.
            int inflate = copper_thickness;

            // If not plated, no copper.
            if( pad->GetAttribute () == PAD_ATTRIB_HOLE_NOT_PLATED )
                inflate = 0;

            pad->BuildPadDrillShapePolygon( allBoardHoles, inflate, segcount );
        }
    }

    allBoardHoles.Simplify( polygonsCalcMode );
}
void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity )
{
    BOARD* pcb = GetBoard();
    bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );

    // Number of segments to draw a circle using segments
    const int       segcountforcircle   = 18;
    double          correctionFactor    = 1.0 / cos( M_PI / (segcountforcircle * 2) );
    const int       segcountLowQuality  = 12;   // segments to draw a circle with low quality
    // to reduce time calculations
    // for holes and items which do not need
    // a fine representation

    double          correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );

    // segments to draw a circle to build texts. Is is used only to build
    // the shape of each segment of the stroke font, therefore no need to have
    // many segments per circle.
    const int       segcountInStrokeFont = 8;

    SHAPE_POLY_SET bufferPolys;
    SHAPE_POLY_SET allLayerHoles;              // Contains through holes, calculated only once
    SHAPE_POLY_SET bufferPcbOutlines;          // stores the board main outlines

    // Build a polygon from edge cut items
    wxString msg;

    if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
    {
        if( aErrorMessages )
        {
            msg << wxT("\n") <<
                _("Unable to calculate the board outlines.\n"
                  "Therefore use the board boundary box.") << wxT("\n\n");
            aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
        }
    }

    // Build board holes, with no optimization of large holes shape.
    buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, false );

    // draw graphic items, on technical layers

    static const LAYER_ID teckLayerList[] = {
        B_Adhes,
        F_Adhes,
        B_Paste,
        F_Paste,
        B_SilkS,
        F_SilkS,
        B_Mask,
        F_Mask,
    };

    // User layers are not drawn here, only technical layers
    for( LSEQ seq = LSET::AllTechMask().Seq( teckLayerList, DIM( teckLayerList ) );  seq;  ++seq )
    {
        LAYER_ID layer = *seq;

        if( !is3DLayerEnabled( layer ) )
            continue;

        if( layer == Edge_Cuts && isEnabled( FL_SHOW_BOARD_BODY )  )
            continue;

        if( aActivity )
            aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );

        bufferPolys.RemoveAllContours();

        for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
        {
            if( !item->IsOnLayer( layer ) )
                continue;

            switch( item->Type() )
            {
            case PCB_LINE_T:
                ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                    bufferPolys, 0, segcountforcircle, correctionFactor );
                break;

            case PCB_TEXT_T:
                ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
                    bufferPolys, 0, segcountLowQuality, 1.0 );
                break;

            default:
                break;
            }
        }

        for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
        {
            if( layer == F_SilkS || layer == B_SilkS )
            {
                // On silk screen layers, the pad shape is only the pad outline
                // never a filled shape
                D_PAD*  pad = module->Pads();
                int     linewidth = g_DrawDefaultLineThickness;

                for( ; pad; pad = pad->Next() )
                {
                    if( !pad->IsOnLayer( layer ) )
                        continue;

                    buildPadShapeThickOutlineAsPolygon( pad, bufferPolys,
                                                        linewidth, segcountforcircle, correctionFactor );
                }
            }
            else
                module->TransformPadsShapesWithClearanceToPolygon( layer,
                        bufferPolys, 0, segcountforcircle, correctionFactor );

            // On tech layers, use a poor circle approximation, only for texts (stroke font)
            module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
                    bufferPolys, 0, segcountforcircle, correctionFactor, segcountInStrokeFont );
        }

        // Draw non copper zones
        if( isEnabled( FL_ZONE ) )
        {
            for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
            {
                ZONE_CONTAINER* zone = pcb->GetArea( ii );

                if( !zone->IsOnLayer( layer ) )
                    continue;

                zone->TransformSolidAreasShapesToPolygonSet(
                    bufferPolys, segcountLowQuality, correctionFactorLQ );
            }
        }

        // bufferPolys contains polygons to merge. Many overlaps .
        // Calculate merged polygons and remove pads and vias holes
        if( layer != B_Mask && layer != F_Mask && bufferPolys.IsEmpty() )
            // if a layer has no item to draw, skip it
            // However solder mask layers are negative layers, so no item
            // means only a full layer mask
            continue;

        // Solder mask layers are "negative" layers.
        // Shapes should be removed from the full board area.
        if( layer == B_Mask || layer == F_Mask )
        {
            SHAPE_POLY_SET cuts = bufferPolys;
            bufferPolys = bufferPcbOutlines;

            cuts.Append(allLayerHoles);
            cuts.Simplify( polygonsCalcMode );

            bufferPolys.BooleanSubtract( cuts, polygonsCalcMode );
        }
        // Remove holes from Solder paste layers and silkscreen
        else if( layer == B_Paste || layer == F_Paste
                 || layer == B_SilkS || layer == F_SilkS  )
        {
            bufferPolys.BooleanSubtract( allLayerHoles, polygonsCalcMode );
        }

        int thickness = 0;

        if( layer != B_Mask && layer != F_Mask )
            thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );

        int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );

        if( layer == Edge_Cuts )
        {
            thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
                        - GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
            zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu )
                   + (thickness / 2);
        }
        else
        {
            // for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
            // sides.
            // However for top layers, zpos should be the bottom layer pos,
            // and for bottom layers, zpos should be the top layer pos.
            if( Get3DLayer_Z_Orientation( layer ) > 0 )
                zpos += thickness/2;
            else
                zpos -= thickness/2 ;
        }


        float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)

        // If we are not using thickness, then the znormal must face the layer direction
        // because it will draw just one plane
        if( !thickness )
            zNormal = Get3DLayer_Z_Orientation( layer );


        setGLTechLayersColor( layer );
        Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
                                            thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
                                            zNormal );
    }
}
示例#15
0
// return true if we are in realistic mode render
bool EDA_3D_CANVAS::isRealisticMode() const
{
    return GetPrm3DVisu().IsRealisticMode();
}
void EDA_3D_FRAME::CreateMenuBar()
{
    wxMenuBar* menuBar   = new wxMenuBar;
    wxMenu*    fileMenu  = new wxMenu;
    wxMenu*    prefsMenu = new wxMenu;

    menuBar->Append( fileMenu, _( "&File" ) );

    AddMenuItem( fileMenu, ID_MENU_SCREENCOPY_PNG,
                 _( "Create Image (png format)" ),
                 KiBitmap( export_xpm ) );
    AddMenuItem( fileMenu, ID_MENU_SCREENCOPY_JPEG,
                 _( "Create Image (jpeg format)" ),
                 KiBitmap( export_xpm ) );

    fileMenu->AppendSeparator();
    AddMenuItem( fileMenu, ID_TOOL_SCREENCOPY_TOCLIBBOARD,
                 _( "Copy 3D Image to Clipboard" ),
                 KiBitmap( copy_button_xpm ) );

    fileMenu->AppendSeparator();
    AddMenuItem( fileMenu, wxID_EXIT,
                 _( "&Exit" ),
                 KiBitmap( exit_xpm ) );

    menuBar->Append( prefsMenu, _( "&Preferences" ) );

    AddMenuItem( prefsMenu, ID_MENU3D_REALISTIC_MODE,
                 _( "Realistic Mode" ),
                 KiBitmap( use_3D_copper_thickness_xpm ), wxITEM_CHECK );

    wxMenu * renderOptionsMenu = new wxMenu;
    AddMenuItem( prefsMenu, renderOptionsMenu, ID_MENU3D_COLOR,
           _( "Render Options" ), KiBitmap( tools_xpm ) );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SHADOWS,
        _( "Render Shadows" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SHOW_HOLES_IN_ZONES,
        _( "Show Holes in Zones" ),
        _( "Holes inside a copper layer copper zones are shown, "
            "but the calculation time is longer" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_TEXTURES,
        _( "Render Textures" ),
        _( "Apply a grid/cloud textures to Board, Solder Mask and Silkscreen" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SMOOTH_NORMALS,
        _( "Render Smooth Normals" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS,
        _( "Use Model Normals" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_MATERIAL,
        _( "Render Material Properties" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX,
        _( "Show Model Bounding Boxes" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    prefsMenu->AppendSeparator();

    // Add submenu set Colors
    wxMenu * setColorMenu = new wxMenu;
    AddMenuItem( prefsMenu, setColorMenu, ID_MENU3D_COLOR,
                 _( "Choose Colors" ), KiBitmap( palette_xpm ) );

    wxMenu * setBgColorMenu = new wxMenu;
    AddMenuItem( setColorMenu, setBgColorMenu, ID_MENU3D_BGCOLOR,
                 _( "Background Color" ), KiBitmap( palette_xpm ) );

    AddMenuItem( setBgColorMenu, ID_MENU3D_BGCOLOR_TOP_SELECTION,
                 _( "Background Top Color" ), KiBitmap( setcolor_3d_bg_xpm ) );

    AddMenuItem( setBgColorMenu, ID_MENU3D_BGCOLOR_BOTTOM_SELECTION,
                 _( "Background Bottom Color" ), KiBitmap( setcolor_3d_bg_xpm ) );

    AddMenuItem( setColorMenu, ID_MENU3D_SILKSCREEN_COLOR_SELECTION,
                 _( "Silkscreen Color" ), KiBitmap( setcolor_silkscreen_xpm ) );

    AddMenuItem( setColorMenu, ID_MENU3D_SOLDERMASK_COLOR_SELECTION,
                 _( "Solder Mask Color" ), KiBitmap( setcolor_soldermask_xpm ) );

    AddMenuItem( setColorMenu, ID_MENU3D_SOLDERPASTE_COLOR_SELECTION,
                 _( "Solder Paste Color" ), KiBitmap( setcolor_solderpaste_xpm ) );

    AddMenuItem( setColorMenu, ID_MENU3D_COPPER_COLOR_SELECTION,
                 _( "Copper/Surface Finish Color" ), KiBitmap( setcolor_copper_xpm ) );

    AddMenuItem( setColorMenu, ID_MENU3D_PCB_BODY_COLOR_SELECTION,
                 _( "Board Body Color" ), KiBitmap( setcolor_board_body_xpm ) );

    AddMenuItem( prefsMenu, ID_MENU3D_AXIS_ONOFF,
                 _( "Show 3D &Axis" ), KiBitmap( axis3d_front_xpm ), wxITEM_CHECK );

    // Creates grid menu
    wxMenu * gridlistMenu = new wxMenu;
    AddMenuItem( prefsMenu, gridlistMenu, ID_MENU3D_GRID,
           _( "3D Grid" ), KiBitmap( grid_xpm ) );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_NOGRID, _( "No 3D Grid" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_10_MM, _( "3D Grid 10 mm" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_5_MM, _( "3D Grid 5 mm" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_2P5_MM, _( "3D Grid 2.5 mm" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_1_MM, _( "3D Grid 1 mm" ), wxEmptyString );

    // If the grid is on, check the corresponding menuitem showing the grid  size
    if( IsEnabled( FL_GRID ) )
    {
        gridlistMenu->Check( ID_MENU3D_GRID_10_MM, GetPrm3DVisu().m_3D_Grid == 10.0 );
        gridlistMenu->Check( ID_MENU3D_GRID_5_MM, GetPrm3DVisu().m_3D_Grid == 5.0 );
        gridlistMenu->Check( ID_MENU3D_GRID_2P5_MM, GetPrm3DVisu().m_3D_Grid == 2.5 );
        gridlistMenu->Check( ID_MENU3D_GRID_1_MM, GetPrm3DVisu().m_3D_Grid == 1.0 );
    }
    else
        gridlistMenu->Check( ID_MENU3D_GRID_NOGRID, true );

    prefsMenu->AppendSeparator();

    AddMenuItem( prefsMenu, ID_MENU3D_SHOW_BOARD_BODY,
           _( "Show Board Bod&y" ), KiBitmap( use_3D_copper_thickness_xpm ), wxITEM_CHECK );

    AddMenuItem( prefsMenu, ID_MENU3D_USE_COPPER_THICKNESS,
           _( "Show Copper &Thickness" ), KiBitmap( use_3D_copper_thickness_xpm ), wxITEM_CHECK );

    AddMenuItem( prefsMenu, ID_MENU3D_MODULE_ONOFF,
           _( "Show 3D F&ootprints" ), KiBitmap( shape_3d_xpm ), wxITEM_CHECK );

    AddMenuItem( prefsMenu, ID_MENU3D_ZONE_ONOFF,
           _( "Show Zone &Filling" ), KiBitmap( add_zone_xpm ), wxITEM_CHECK );

    prefsMenu->AppendSeparator();

    wxMenu * layersMenu = new wxMenu;
    AddMenuItem( prefsMenu, layersMenu, ID_MENU3D_LAYERS,
           _( "Show &Layers" ), KiBitmap( tools_xpm ) );

    AddMenuItem( layersMenu, ID_MENU3D_ADHESIVE_ONOFF,
           _( "Show &Adhesive Layers" ), KiBitmap( tools_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_SILKSCREEN_ONOFF,
           _( "Show &Silkscreen Layer" ), KiBitmap( add_text_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_SOLDER_MASK_ONOFF,
           _( "Show Solder &Mask Layers" ), KiBitmap( pads_mask_layers_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_SOLDER_PASTE_ONOFF,
           _( "Show Solder &Paste Layers" ), KiBitmap( pads_mask_layers_xpm ), wxITEM_CHECK );

    // Other layers are not "board" layers, and are not shown in realistic mode
    // These menus will be disabled in in realistic mode
    AddMenuItem( layersMenu, ID_MENU3D_COMMENTS_ONOFF,
           _( "Show &Comments and Drawings Layer" ), KiBitmap( edit_sheet_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_ECO_ONOFF,
           _( "Show &Eco Layers" ), KiBitmap( edit_sheet_xpm ), wxITEM_CHECK );

    SetMenuBar( menuBar );
    SetMenuBarOptionsState();
}
示例#17
0
// return true if aItem should be displayed
bool EDA_3D_CANVAS::isEnabled( DISPLAY3D_FLG aItem ) const
{
    return GetPrm3DVisu().GetFlag( aItem );
}
void EDA_3D_FRAME::SetMenuBarOptionsState()
{
    wxMenuBar* menuBar = GetMenuBar();

    if( menuBar == NULL )
        return;

    wxMenuItem* item;
    // Set the state of toggle menus according to the current display options
    item = menuBar->FindItem( ID_MENU3D_REALISTIC_MODE );
    item->Check( GetPrm3DVisu().IsRealisticMode() );
    item = menuBar->FindItem( ID_MENU3D_COMMENTS_ONOFF );
    item->Enable( !GetPrm3DVisu().IsRealisticMode() );
    item = menuBar->FindItem( ID_MENU3D_ECO_ONOFF );
    item->Enable( !GetPrm3DVisu().IsRealisticMode() );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SHADOWS );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SHADOWS ) );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SHADOWS );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SHADOWS ) );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SHOW_HOLES_IN_ZONES );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_TEXTURES );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_TEXTURES ) );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SMOOTH_NORMALS );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SMOOTH_NORMALS ) );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_USE_MODEL_NORMALS ) );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_MATERIAL );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_MATERIAL ) );

    item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX );
    item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SHOW_MODEL_BBOX ) );

    item = menuBar->FindItem( ID_MENU3D_SHOW_BOARD_BODY );
    item->Check( GetPrm3DVisu().GetFlag( FL_SHOW_BOARD_BODY ) );

    item = menuBar->FindItem( ID_MENU3D_USE_COPPER_THICKNESS );
    item->Check( GetPrm3DVisu().GetFlag( FL_USE_COPPER_THICKNESS ) );

    item = menuBar->FindItem( ID_MENU3D_MODULE_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_MODULE ) );

    item = menuBar->FindItem( ID_MENU3D_ZONE_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_ZONE ) );

    item = menuBar->FindItem( ID_MENU3D_AXIS_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_AXIS ) );

    item = menuBar->FindItem( ID_MENU3D_ADHESIVE_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_ADHESIVE ) );

    item = menuBar->FindItem( ID_MENU3D_SILKSCREEN_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_SILKSCREEN ) );

    item = menuBar->FindItem( ID_MENU3D_SOLDER_MASK_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_SOLDERMASK ) );

    item = menuBar->FindItem( ID_MENU3D_SOLDER_PASTE_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_SOLDERPASTE ) );

    item = menuBar->FindItem( ID_MENU3D_COMMENTS_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_COMMENTS ) );

    item = menuBar->FindItem( ID_MENU3D_ECO_ONOFF );
    item->Check( GetPrm3DVisu().GetFlag( FL_ECO ));
}
示例#19
0
void EDA_3D_CANVAS::generateFakeShadowsTextures( REPORTER* aErrorMessages, REPORTER* aActivity )
{
    if( m_shadow_init == true )
    {
        return;
    }

    // Init info 3d parameters and create gl lists:
    CreateDrawGL_List( aErrorMessages, aActivity );

    DBG( unsigned strtime = GetRunningMicroSecs() );

    m_shadow_init = true;

    glClearColor( 0, 0, 0, 1 );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    const float zDistMax = Millimeter2iu( 3.5 ) * GetPrm3DVisu().m_BiuTo3Dunits;

    glOrtho( -GetPrm3DVisu().m_BoardSize.x * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             GetPrm3DVisu().m_BoardSize.x * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             -GetPrm3DVisu().m_BoardSize.y * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             GetPrm3DVisu().m_BoardSize.y * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             0.0, zDistMax );

    float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;

    // Render FRONT shadow
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glTranslatef( 0.0f, 0.0f, zpos );
    glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );

    // move the board in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits,
                  -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits,
                  0.0f );

    create_and_render_shadow_buffer( &m_text_fake_shadow_front, 512, false, 1 );

    zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;

    // Render BACK shadow
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glTranslatef( 0.0f, 0.0f, fabs( zpos ) );


    // move the board in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits,
                  -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits,
                  0.0f );

    create_and_render_shadow_buffer( &m_text_fake_shadow_back, 512, false, 1 );


    // Render ALL BOARD shadow
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    // Normalization scale to convert bouding box
    // to normalize 3D units between -1.0 and +1.0

    S3D_VERTEX v = m_fastAABBox_Shadow.Max() - m_fastAABBox_Shadow.Min();
    float BoundingBoxBoardiuTo3Dunits = 2.0f / glm::max( v.x, v.y );

    //float zDistance = (m_lightPos.z * zDistMax) / sqrt( (m_lightPos.z - m_fastAABBox_Shadow.Min().z) );
    float zDistance = (m_lightPos.z - m_fastAABBox_Shadow.Min().z) / 3.0f;

    glOrtho( -v.x * BoundingBoxBoardiuTo3Dunits / 2.0f,
              v.x * BoundingBoxBoardiuTo3Dunits / 2.0f,
             -v.y * BoundingBoxBoardiuTo3Dunits / 2.0f,
              v.y * BoundingBoxBoardiuTo3Dunits / 2.0f,
             0.0f, zDistance );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    // fits the bouding box to scale this size
    glScalef( BoundingBoxBoardiuTo3Dunits, BoundingBoxBoardiuTo3Dunits, 1.0f );

    // Place the eye in the lowerpoint of boudingbox and turn arround and look up to the model
    glTranslatef( 0.0f, 0.0f, m_fastAABBox_Shadow.Min().z );
    glRotatef( 180.0, 0.0f, 1.0f, 0.0f );

    // move the bouding box in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -(m_fastAABBox_Shadow.Min().x + v.x / 2.0f), -(m_fastAABBox_Shadow.Min().y + v.y / 2.0f), 0.0f );

    create_and_render_shadow_buffer( &m_text_fake_shadow_board, 512, true, 10 );

    DBG( printf( "  generateFakeShadowsTextures total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
}
void EDA_3D_FRAME::CreateMenuBar()
{
    wxMenuBar* menuBar   = new wxMenuBar;
    wxMenu*    fileMenu  = new wxMenu;
    wxMenu*    prefsMenu = new wxMenu;

    menuBar->Append( fileMenu, _( "&File" ) );

    fileMenu->Append( ID_MENU_SCREENCOPY_PNG, _( "Create Image (png format)" ) );
    fileMenu->Append( ID_MENU_SCREENCOPY_JPEG, _( "Create Image (jpeg format)" ) );

#if (defined(__WINDOWS__) || defined(__APPLE__ ) )
    // Does not work properly under linux
    fileMenu->AppendSeparator();
    fileMenu->Append( ID_TOOL_SCREENCOPY_TOCLIBBOARD, _( "Copy 3D Image to Clipboard" ) );
#endif

    fileMenu->AppendSeparator();
    fileMenu->Append( wxID_EXIT, _( "&Exit" ) );

    menuBar->Append( prefsMenu, _( "&Preferences" ) );

    AddMenuItem( prefsMenu, ID_MENU3D_REALISTIC_MODE,
                 _( "Realistic Mode" ),
                 KiBitmap( use_3D_copper_thickness_xpm ), wxITEM_CHECK );

    wxMenu * renderOptionsMenu = new wxMenu;
    AddMenuItem( prefsMenu, renderOptionsMenu, ID_MENU3D_COLOR,
           _( "Render options" ), KiBitmap( tools_xpm ) );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SHADOWS,
        _( "Render Shadows" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SHOW_HOLES_IN_ZONES,
        _( "Show Holes in Zones" ),
        _( "Holes inside a copper layer copper zones are shown, "
            "but the calculation time is longer" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_TEXTURES,
        _( "Render Textures" ),
        _( "Apply a grid/cloud textures to Board, Solder Mask and Silkscreen" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SMOOTH,
        _( "Render Smooth Normals" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_MATERIAL,
        _( "Render Material properties" ),
        KiBitmap( green_xpm ), wxITEM_CHECK );

    prefsMenu->AppendSeparator();

    wxMenu * backgrounColorMenu = new wxMenu;

    // Add submenu Choose Colors
    AddMenuItem( prefsMenu, backgrounColorMenu, ID_MENU3D_COLOR,
           _( "Choose Colors" ), KiBitmap( palette_xpm ) );

    AddMenuItem( backgrounColorMenu, ID_MENU3D_BGCOLOR_TOP_SELECTION,
                 _( "Background Top Color" ), KiBitmap( palette_xpm ) );

    AddMenuItem( backgrounColorMenu, ID_MENU3D_BGCOLOR_SELECTION,
                 _( "Background Bottom Color" ), KiBitmap( palette_xpm ) );

    AddMenuItem( prefsMenu, ID_MENU3D_AXIS_ONOFF,
                 _( "Show 3D &Axis" ), KiBitmap( axis3d_front_xpm ), wxITEM_CHECK );

    // Creates grid menu
    wxMenu * gridlistMenu = new wxMenu;
    AddMenuItem( prefsMenu, gridlistMenu, ID_MENU3D_GRID,
           _( "3D Grid" ), KiBitmap( grid_xpm ) );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_NOGRID, _( "No 3D Grid" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_10_MM, _( "3D Grid 10 mm" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_5_MM, _( "3D Grid 5 mm" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_2P5_MM, _( "3D Grid 2.5 mm" ), wxEmptyString );
    gridlistMenu->AppendCheckItem( ID_MENU3D_GRID_1_MM, _( "3D Grid 1 mm" ), wxEmptyString );

    // If the grid is on, check the corresponding menuitem showing the grid  size
    if( IsEnabled( FL_GRID ) )
    {
        gridlistMenu->Check( ID_MENU3D_GRID_10_MM, GetPrm3DVisu().m_3D_Grid == 10.0 );
        gridlistMenu->Check( ID_MENU3D_GRID_5_MM, GetPrm3DVisu().m_3D_Grid == 5.0 );
        gridlistMenu->Check( ID_MENU3D_GRID_2P5_MM, GetPrm3DVisu().m_3D_Grid == 2.5 );
        gridlistMenu->Check( ID_MENU3D_GRID_1_MM, GetPrm3DVisu().m_3D_Grid == 1.0 );
    }
    else
        gridlistMenu->Check( ID_MENU3D_GRID_NOGRID, true );

    prefsMenu->AppendSeparator();

    AddMenuItem( prefsMenu, ID_MENU3D_SHOW_BOARD_BODY,
           _( "Show Board Body" ), KiBitmap( use_3D_copper_thickness_xpm ), wxITEM_CHECK );

    AddMenuItem( prefsMenu, ID_MENU3D_USE_COPPER_THICKNESS,
           _( "Show Copper Thickness" ), KiBitmap( use_3D_copper_thickness_xpm ), wxITEM_CHECK );

    AddMenuItem( prefsMenu, ID_MENU3D_MODULE_ONOFF,
           _( "Show 3D F&ootprints" ), KiBitmap( shape_3d_xpm ), wxITEM_CHECK );

    AddMenuItem( prefsMenu, ID_MENU3D_ZONE_ONOFF,
           _( "Show Zone &Filling" ), KiBitmap( add_zone_xpm ), wxITEM_CHECK );

    prefsMenu->AppendSeparator();

    wxMenu * layersMenu = new wxMenu;
    AddMenuItem( prefsMenu, layersMenu, ID_MENU3D_LAYERS,
           _( "Show Layers" ), KiBitmap( tools_xpm ) );

    AddMenuItem( layersMenu, ID_MENU3D_ADHESIVE_ONOFF,
           _( "Show &Adhesive Layers" ), KiBitmap( tools_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_SILKSCREEN_ONOFF,
           _( "Show &Silkscreen Layer" ), KiBitmap( add_text_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_SOLDER_MASK_ONOFF,
           _( "Show Solder &Mask Layers" ), KiBitmap( pads_mask_layers_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_SOLDER_PASTE_ONOFF,
           _( "Show Solder &Paste Layers" ), KiBitmap( pads_mask_layers_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_COMMENTS_ONOFF,
           _( "Show &Comments and Drawings Layer" ), KiBitmap( edit_sheet_xpm ), wxITEM_CHECK );

    AddMenuItem( layersMenu, ID_MENU3D_ECO_ONOFF,
           _( "Show &Eco Layers" ), KiBitmap( edit_sheet_xpm ), wxITEM_CHECK );

    SetMenuBar( menuBar );
    SetMenuBarOptionsState();
}