void C3D_RENDER_OGL_LEGACY::reload( REPORTER *aStatusTextReporter )
{
    m_reloadRequested = false;

    ogl_free_all_display_lists();

    COBJECT2D_STATS::Instance().ResetStats();

#ifdef PRINT_STATISTICS_3D_VIEWER
    printf("InitSettings...\n");
#endif

    unsigned stats_startReloadTime = GetRunningMicroSecs();

    m_settings.InitSettings( aStatusTextReporter );

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_endReloadTime = GetRunningMicroSecs();
#endif

    SFVEC3F camera_pos = m_settings.GetBoardCenter3DU();
    m_settings.CameraGet().SetBoardLookAtPos( camera_pos );

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_start_OpenGL_Load_Time = GetRunningMicroSecs();
#endif

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Load OpenGL: board" ) );

    // Create Board
    // /////////////////////////////////////////////////////////////////////////

    CCONTAINER2D boardContainer;
    Convert_shape_line_polygon_to_triangles( m_settings.GetBoardPoly(),
                                             boardContainer,
                                             m_settings.BiuTo3Dunits(),
                                             (const BOARD_ITEM &)*m_settings.GetBoard() );

    const LIST_OBJECT2D &listBoardObject2d = boardContainer.GetList();

    if( listBoardObject2d.size() > 0 )
    {
        // We will set a unitary Z so it will in future used with transformations
        // since the board poly will be used not only to draw itself but also the
        // solder mask layers.
        const float layer_z_top = 1.0f;
        const float layer_z_bot = 0.0f;

        CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listBoardObject2d.size() );

        // Convert the list of objects(triangles) to triangle layer structure
        for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin();
             itemOnLayer != listBoardObject2d.end();
             ++itemOnLayer )
        {
            const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);

            wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );

            const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;

            const SFVEC2F &v1 = tri->GetP1();
            const SFVEC2F &v2 = tri->GetP2();
            const SFVEC2F &v3 = tri->GetP3();

            add_triangle_top_bot( layerTriangles,
                                  v1,
                                  v2,
                                  v3,
                                  layer_z_top,
                                  layer_z_bot );
        }

        const SHAPE_POLY_SET &boardPoly = m_settings.GetBoardPoly();

        wxASSERT( boardPoly.OutlineCount() > 0 );

        if( boardPoly.OutlineCount() > 0 )
        {
            layerTriangles->AddToMiddleContourns( boardPoly,
                                                  layer_z_bot,
                                                  layer_z_top,
                                                  m_settings.BiuTo3Dunits(),
                                                  false );

            m_ogl_disp_list_board = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
                                                                m_ogl_circle_texture,
                                                                layer_z_top,
                                                                layer_z_top );
        }

        delete layerTriangles;
    }

    // Create Through Holes and vias
    // /////////////////////////////////////////////////////////////////////////

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Load OpenGL: holes and vias" ) );

    m_ogl_disp_list_through_holes_outer = generate_holes_display_list(
                m_settings.GetThroughHole_Outer().GetList(),
                m_settings.GetThroughHole_Outer_poly(),
                1.0f,
                0.0f,
                false );

    SHAPE_POLY_SET bodyHoles = m_settings.GetThroughHole_Outer_poly();

    bodyHoles.BooleanAdd( m_settings.GetThroughHole_Outer_poly_NPTH(),
                          SHAPE_POLY_SET::PM_FAST );

    m_ogl_disp_list_through_holes_outer_with_npth = generate_holes_display_list(
                m_settings.GetThroughHole_Outer().GetList(),
                bodyHoles,
                1.0f,
                0.0f,
                false );

    m_ogl_disp_list_through_holes_inner = generate_holes_display_list(
                m_settings.GetThroughHole_Inner().GetList(),
                m_settings.GetThroughHole_Inner_poly(),
                1.0f,
                0.0f,
                true );


    m_ogl_disp_list_through_holes_vias_outer = generate_holes_display_list(
                m_settings.GetThroughHole_Vias_Outer().GetList(),
                m_settings.GetThroughHole_Vias_Outer_poly(),
                1.0f,
                0.0f,
                false );

    // Not in use
    //m_ogl_disp_list_through_holes_vias_inner = generate_holes_display_list(
    //      m_settings.GetThroughHole_Vias_Inner().GetList(),
    //      m_settings.GetThroughHole_Vias_Inner_poly(),
    //      1.0f, 0.0f,
    //      false );

    const MAP_POLY & innerMapHoles = m_settings.GetPolyMapHoles_Inner();
    const MAP_POLY & outerMapHoles = m_settings.GetPolyMapHoles_Outer();

    wxASSERT( innerMapHoles.size() == outerMapHoles.size() );

    const MAP_CONTAINER_2D &map_holes = m_settings.GetMapLayersHoles();

    if( outerMapHoles.size() > 0 )
    {
        float layer_z_bot = 0.0f;
        float layer_z_top = 0.0f;

        for( MAP_POLY::const_iterator ii = outerMapHoles.begin();
             ii != outerMapHoles.end();
             ++ii )
        {
            LAYER_ID layer_id = static_cast<LAYER_ID>(ii->first);
            const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
            const CBVHCONTAINER2D *container = map_holes.at( layer_id );

            get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );

            m_ogl_disp_lists_layers_holes_outer[layer_id] = generate_holes_display_list(
                        container->GetList(),
                        *poly,
                        layer_z_top,
                        layer_z_bot,
                        false );
        }

        for( MAP_POLY::const_iterator ii = innerMapHoles.begin();
             ii != innerMapHoles.end();
             ++ii )
        {
            LAYER_ID layer_id = static_cast<LAYER_ID>(ii->first);
            const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
            const CBVHCONTAINER2D *container = map_holes.at( layer_id );

            get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );

            m_ogl_disp_lists_layers_holes_inner[layer_id] = generate_holes_display_list(
                        container->GetList(),
                        *poly,
                        layer_z_top,
                        layer_z_bot,
                        false );
        }
    }

    // Generate vertical cylinders of vias and pads (copper)
    generate_3D_Vias_and_Pads();

    // Add layers maps
    // /////////////////////////////////////////////////////////////////////////

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Load OpenGL: layers" ) );

    for( MAP_CONTAINER_2D::const_iterator ii = m_settings.GetMapLayers().begin();
         ii != m_settings.GetMapLayers().end();
         ++ii )
    {
        LAYER_ID layer_id = static_cast<LAYER_ID>(ii->first);

        if( !m_settings.Is3DLayerEnabled( layer_id ) )
            continue;

        const CBVHCONTAINER2D *container2d = static_cast<const CBVHCONTAINER2D *>(ii->second);
        const LIST_OBJECT2D &listObject2d = container2d->GetList();

        if( listObject2d.size() == 0 )
            continue;

        float layer_z_bot = 0.0f;
        float layer_z_top = 0.0f;

        get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );

        // Calculate an estimation for the nr of triangles based on the nr of objects
        unsigned int nrTrianglesEstimation = listObject2d.size() * 8;

        CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( nrTrianglesEstimation );

        m_triangles[layer_id] = layerTriangles;

        for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
             itemOnLayer != listObject2d.end();
             ++itemOnLayer )
        {
            const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);

            switch( object2d_A->GetObjectType() )
            {
                case OBJ2D_FILLED_CIRCLE:
                    add_object_to_triangle_layer( (const CFILLEDCIRCLE2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_POLYGON4PT:
                    add_object_to_triangle_layer( (const CPOLYGON4PTS2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_RING:
                    add_object_to_triangle_layer( (const CRING2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_TRIANGLE:
                    add_object_to_triangle_layer( (const CTRIANGLE2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_ROUNDSEG:
                    add_object_to_triangle_layer( (const CROUNDSEGMENT2D *) object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                default:
                    wxFAIL_MSG("C3D_RENDER_OGL_LEGACY: Object type is not implemented");
                break;
            }
        }

        const MAP_POLY &map_poly = m_settings.GetPolyMap();

        if( map_poly.find( layer_id ) != map_poly.end() )
        {
            const SHAPE_POLY_SET *polyList = map_poly.at( layer_id );

            layerTriangles->AddToMiddleContourns( *polyList,
                                                  layer_z_bot,
                                                  layer_z_top,
                                                  m_settings.BiuTo3Dunits(),
                                                  false );
        }

        // Create display list
        // /////////////////////////////////////////////////////////////////////
        m_ogl_disp_lists_layers[layer_id] = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
                                                                        m_ogl_circle_texture,
                                                                        layer_z_bot,
                                                                        layer_z_top );
    }// for each layer on map

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_end_OpenGL_Load_Time = GetRunningMicroSecs();
#endif

    // Load 3D models
    // /////////////////////////////////////////////////////////////////////////
#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_start_models_Load_Time = GetRunningMicroSecs();
#endif

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Loading 3D models" ) );

    load_3D_models();

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_end_models_Load_Time = GetRunningMicroSecs();


    printf( "C3D_RENDER_OGL_LEGACY::reload times:\n" );
    printf( "  Reload board:             %.3f ms\n",
            (float)( stats_endReloadTime        - stats_startReloadTime        ) / 1000.0f );
    printf( "  Loading to openGL:        %.3f ms\n",
            (float)( stats_end_OpenGL_Load_Time - stats_start_OpenGL_Load_Time ) / 1000.0f );
    printf( "  Loading 3D models:        %.3f ms\n",
            (float)( stats_end_models_Load_Time - stats_start_models_Load_Time ) / 1000.0f );
    COBJECT2D_STATS::Instance().PrintStats();
#endif

    if( aStatusTextReporter )
    {
        // Calculation time in seconds
        const double calculation_time = (double)( GetRunningMicroSecs() -
                                                  stats_startReloadTime) / 1e6;

        aStatusTextReporter->Report( wxString::Format( _( "Reload time %.3f s" ),
                                                       calculation_time ) );
    }
}
void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
{
    if( m_settings.GetStats_Nr_Vias() )
    {
        const unsigned int reserve_nr_triangles_estimation =
                m_settings.GetNrSegmentsCircle( m_settings.GetStats_Med_Via_Hole_Diameter3DU() ) *
                8 *
                m_settings.GetStats_Nr_Vias();

        CLAYER_TRIANGLES *layerTriangleVIA = new CLAYER_TRIANGLES( reserve_nr_triangles_estimation );

        // Insert plated vertical holes inside the board
        // /////////////////////////////////////////////////////////////////////////

        // Insert vias holes (vertical cylinders)
        for( const TRACK* track = m_settings.GetBoard()->m_Track;
             track;
             track = track->Next() )
        {
            if( track->Type() == PCB_VIA_T )
            {
                const VIA *via = static_cast<const VIA*>(track);

                const float holediameter = via->GetDrillValue() * m_settings.BiuTo3Dunits();
                const float thickness = m_settings.GetCopperThickness3DU();
                const float hole_inner_radius = ( holediameter / 2.0f );

                const SFVEC2F via_center(  via->GetStart().x * m_settings.BiuTo3Dunits(),
                                          -via->GetStart().y * m_settings.BiuTo3Dunits() );

                LAYER_ID top_layer, bottom_layer;
                via->LayerPair( &top_layer, &bottom_layer );

                float ztop, zbot, dummy;

                get_layer_z_pos( top_layer,    ztop,  dummy );
                get_layer_z_pos( bottom_layer, dummy, zbot );

                wxASSERT( zbot < ztop );

                generate_cylinder( via_center,
                                   hole_inner_radius,
                                   hole_inner_radius + thickness,
                                   ztop,
                                   zbot,
                                   m_settings.GetNrSegmentsCircle( via->GetDrillValue() ),
                                   layerTriangleVIA );
            }
        }

        m_ogl_disp_list_via = new CLAYERS_OGL_DISP_LISTS( *layerTriangleVIA,
                                                          0,
                                                          0.0f,
                                                          0.0f );

        delete layerTriangleVIA;
    }


    if( m_settings.GetStats_Nr_Holes() > 0 )
    {
        SHAPE_POLY_SET tht_outer_holes_poly; // Stores the outer poly of the copper holes (the pad)
        SHAPE_POLY_SET tht_inner_holes_poly; // Stores the inner poly of the copper holes (the hole)

        tht_outer_holes_poly.RemoveAllContours();
        tht_inner_holes_poly.RemoveAllContours();

        // Insert pads holes (vertical cylinders)
        for( const MODULE* module = m_settings.GetBoard()->m_Modules;
             module;
             module = module->Next() )
        {
            for( const D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
            {
                if( pad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
                {
                    const wxSize drillsize = pad->GetDrillSize();
                    const bool   hasHole   = drillsize.x && drillsize.y;

                    if( !hasHole )
                        continue;

                    // we use the hole diameter to calculate the seg count.
                    // for round holes, drillsize.x == drillsize.y
                    // for oblong holes, the diameter is the smaller of
                    // (drillsize.x, drillsize.y)
                    const int diam = std::min( drillsize.x, drillsize.y ) +
                                     m_settings.GetCopperThicknessBIU() * 2;

                    const int segmentsPerCircle = m_settings.GetNrSegmentsCircle( diam );

                    pad->BuildPadDrillShapePolygon( tht_outer_holes_poly,
                                                    m_settings.GetCopperThicknessBIU(),
                                                    segmentsPerCircle );

                    pad->BuildPadDrillShapePolygon( tht_inner_holes_poly,
                                                    0,
                                                    segmentsPerCircle );
                }
            }
        }

        // Subtract the holes
        tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly, SHAPE_POLY_SET::PM_FAST );


        CCONTAINER2D holesContainer;

        Convert_shape_line_polygon_to_triangles( tht_outer_holes_poly,
                                                 holesContainer,
                                                 m_settings.BiuTo3Dunits(),
                                                 (const BOARD_ITEM &)*m_settings.GetBoard() );

        const LIST_OBJECT2D &listHolesObject2d = holesContainer.GetList();

        if( listHolesObject2d.size() > 0 )
        {
            float layer_z_top, layer_z_bot, dummy;

            get_layer_z_pos( F_Cu, layer_z_top,  dummy );
            get_layer_z_pos( B_Cu, dummy, layer_z_bot );

            CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listHolesObject2d.size() );

            // Convert the list of objects(triangles) to triangle layer structure
            for( LIST_OBJECT2D::const_iterator itemOnLayer = listHolesObject2d.begin();
                 itemOnLayer != listHolesObject2d.end();
                 ++itemOnLayer )
            {
                const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);

                wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );

                const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;

                const SFVEC2F &v1 = tri->GetP1();
                const SFVEC2F &v2 = tri->GetP2();
                const SFVEC2F &v3 = tri->GetP3();

                add_triangle_top_bot( layerTriangles,
                                      v1,
                                      v2,
                                      v3,
                                      layer_z_top,
                                      layer_z_bot );
            }

            wxASSERT( tht_outer_holes_poly.OutlineCount() > 0 );

            if( tht_outer_holes_poly.OutlineCount() > 0 )
            {
                layerTriangles->AddToMiddleContourns( tht_outer_holes_poly,
                                                      layer_z_bot,
                                                      layer_z_top,
                                                      m_settings.BiuTo3Dunits(),
                                                      false );

                m_ogl_disp_list_pads_holes = new CLAYERS_OGL_DISP_LISTS(
                            *layerTriangles,
                            m_ogl_circle_texture, // not need
                            layer_z_top,
                            layer_z_top );
            }

            delete layerTriangles;
        }
    }
}
void C3D_RENDER_OGL_LEGACY::reload()
{
    m_reloadRequested = false;

    ogl_free_all_display_lists();

    COBJECT2D_STATS::Instance().ResetStats();

    m_settings.InitSettings();

    SFVEC3F camera_pos = m_settings.GetBoardCenter3DU();
    m_settings.CameraGet().SetBoardLookAtPos( camera_pos );

    // Create Board
    // /////////////////////////////////////////////////////////////////////////
    printf("Create board...\n");
    CCONTAINER2D boardContainer;
    Convert_shape_line_polygon_to_triangles( m_settings.GetBoardPoly(),
                                             boardContainer,
                                             m_settings.BiuTo3Dunits(),
                                             (const BOARD_ITEM &)*m_settings.GetBoard() );

    const LIST_OBJECT2D listBoardObject2d = boardContainer.GetList();

    if( listBoardObject2d.size() > 0 )
    {
        /*
        float layer_z_top = m_settings.GetLayerBottomZpos3DU( F_Cu );
        float layer_z_bot = m_settings.GetLayerBottomZpos3DU( B_Cu );
*/
        float layer_z_top = m_settings.GetLayerBottomZpos3DU( B_Mask );
        float layer_z_bot = m_settings.GetLayerTopZpos3DU( B_Mask );
        CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listBoardObject2d.size() );

        for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin();
             itemOnLayer != listBoardObject2d.end();
             itemOnLayer++ )
        {
            const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);

            wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );

            const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
            const SFVEC2F &v1 = tri->GetP1();
            const SFVEC2F &v2 = tri->GetP2();
            const SFVEC2F &v3 = tri->GetP3();

            add_triangle_top_bot( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
        }

        const SHAPE_POLY_SET boardPoly = m_settings.GetBoardPoly();
        SHAPE_POLY_SET boardPolyCopy = boardPoly;

        boardPolyCopy.Simplify( SHAPE_POLY_SET::PM_FAST );

        if( boardPolyCopy.OutlineCount() == 1 )
        {
            const SHAPE_LINE_CHAIN& outlinePath = boardPolyCopy.COutline( 0 );

            std::vector< SFVEC2F > contournPoints;
            contournPoints.clear();
            contournPoints.reserve( outlinePath.PointCount() + 2 );

            for( unsigned int i = 0; i < (unsigned int)outlinePath.PointCount(); ++i )
            {
                const VECTOR2I& v = outlinePath.CPoint( i );
                contournPoints.push_back( SFVEC2F( v.x * m_settings.BiuTo3Dunits(),
                                                  -v.y * m_settings.BiuTo3Dunits() ) );
            }
            contournPoints.push_back( contournPoints[0] );

            if( contournPoints.size() > 4 )
            {
                // Calculate normals of each segment of the contourn
                std::vector< SFVEC2F > contournNormals;
                contournNormals.clear();
                contournNormals.reserve( contournPoints.size() );
                for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i )
                {
                    const SFVEC2F &v0 = contournPoints[i + 0];
                    const SFVEC2F &v1 = contournPoints[i + 1];

                    SFVEC2F n = glm::normalize( v1 - v0 );
                    contournNormals.push_back( SFVEC2F( -n.y, n.x ) );
                }

                SFVEC2F lastNormal = contournNormals[contournPoints.size() - 2];
                for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i )
                {
                    const SFVEC2F &v0 = contournPoints[i + 0];
                    const SFVEC2F &v1 = contournPoints[i + 1];

                    layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_top ) ),
                                                                             SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_top ) ),
                                                                             SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_bot ) ),
                                                                             SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_bot ) ) );

                    SFVEC2F n0 = contournNormals[i];

                    if( glm::dot( n0, lastNormal ) > 0.5f )
                        n0 += lastNormal;
                    else
                        n0 += contournNormals[i];

                    const SFVEC2F &nextNormal = contournNormals[ (i + 1) % (contournPoints.size() - 1) ];
                    SFVEC2F n1 = contournNormals[i];

                    if( glm::dot( n1, nextNormal ) > 0.5f )
                        n1 += nextNormal;
                    else
                        n1 += contournNormals[i];

                    n0 = glm::normalize( n0 );
                    n1 = glm::normalize( n1 );

                    const SFVEC3F n3d0 = SFVEC3F( n0.x, n0.y, 0.0f );
                    const SFVEC3F n3d1 = SFVEC3F( n1.x, n1.y, 0.0f );

                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d0, n3d1, n3d1, n3d0 );

                    lastNormal = contournNormals[i];
/*
                    const SFVEC2F n0 = glm::normalize( v0 - center );
                    const SFVEC2F n1 = glm::normalize( v1 - center );
                    const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
                    const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );*/
                }
            }
            contournPoints.clear();
        }

        m_ogl_disp_list_board = new CLAYERS_OGL_DISP_LISTS( *layerTriangles, m_ogl_circle_texture, SFVEC3F(0.65f,0.55f,0.05f) );

        delete layerTriangles;
    }


    float calc_sides_min_factor = (float)(   10.0 * IU_PER_MILS * m_settings.BiuTo3Dunits() );
    float calc_sides_max_factor = (float)( 1000.0 * IU_PER_MILS * m_settings.BiuTo3Dunits() );


    // Add layers maps (except B_Mask and F_Mask)
    // /////////////////////////////////////////////////////////////////////////
    printf("Add layers maps...\n");
    for( MAP_CONTAINER_2D::const_iterator it = m_settings.GetMapLayers().begin();
         it != m_settings.GetMapLayers().end(); it++ )
    {
        LAYER_ID layer_id = static_cast<LAYER_ID>(it->first);

        if( !m_settings.Is3DLayerEnabled( layer_id ) )
            continue;

        const CBVHCONTAINER2D *container2d = static_cast<const CBVHCONTAINER2D *>(it->second);
        const LIST_OBJECT2D listObject2d = container2d->GetList();

        if( listObject2d.size() == 0 )
            continue;

        //CMATERIAL *materialLayer = &m_materials.m_SilkS;
        SFVEC3F layerColor = SFVEC3F( 0.3f, 0.4f, 0.5f );

        float layer_z_bot = m_settings.GetLayerBottomZpos3DU( layer_id );
        float layer_z_top = m_settings.GetLayerTopZpos3DU( layer_id );

        if( layer_z_top < layer_z_bot )
        {
            float tmpFloat = layer_z_bot;
            layer_z_bot = layer_z_top;
            layer_z_top = tmpFloat;
        }

        layer_z_bot -= m_settings.GetNonCopperLayerThickness3DU();
        layer_z_top += m_settings.GetNonCopperLayerThickness3DU();

        if( m_settings.GetFlag( FL_USE_REALISTIC_MODE ) )
        {
            switch( layer_id )
            {
                case B_Adhes:
                case F_Adhes:

                break;

                case B_Paste:
                case F_Paste:
    //                materialLayer = &m_materials.m_Paste;
                break;

                case B_SilkS:
                case F_SilkS:

    //                materialLayer = &m_materials.m_SilkS;
    //                layerColor = g_silkscreenColor;
                break;

                case Dwgs_User:
                case Cmts_User:
                case Eco1_User:
                case Eco2_User:
                case Edge_Cuts:
                case Margin:
                break;

                case B_CrtYd:
                case F_CrtYd:
                break;

                case B_Fab:
                case F_Fab:
                break;

                default:
                    //materialLayer = &m_materials.m_Copper;

                        //layerColor = g_copperColor;


                break;
            }
        }
        else
        {
            layerColor = m_settings.GetLayerColor( layer_id );

        }


        // Calculate an estiation for then nr of triangles based on the nr of objects
        unsigned int nrTrianglesEstimation = listObject2d.size() * 8;

        CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( nrTrianglesEstimation );

        m_triangles[layer_id] = layerTriangles;

        for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
             itemOnLayer != listObject2d.end(); itemOnLayer++ )
        {
            const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);

            switch( object2d_A->GetObjectType() )
            {

                case OBJ2D_FILLED_CIRCLE:
                {
                    const CFILLEDCIRCLE2D *filledCircle = (const CFILLEDCIRCLE2D *)object2d_A;
                    const SFVEC2F &center = filledCircle->GetCenter();
                    float radius = filledCircle->GetRadius() * 2.0f;            // Double because the render triangle
                    float radiusSquared = radius * radius;

                    const float f = (sqrtf(2.0f) / 2.0f) * radius * 0.9;// * texture_factor;

                    layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, layer_z_top ),
                                                                           SFVEC3F( center.x - f, center.y, layer_z_top ),
                                                                           SFVEC3F( center.x,
                                                                                    center.y - f, layer_z_top ) );

                    layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, layer_z_top ),
                                                                           SFVEC3F( center.x + f, center.y, layer_z_top ),
                                                                           SFVEC3F( center.x,
                                                                                    center.y + f, layer_z_top ) );

                    layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, layer_z_bot ),
                                                                           SFVEC3F( center.x + f, center.y, layer_z_bot ),
                                                                           SFVEC3F( center.x,
                                                                                    center.y - f, layer_z_bot ) );

                    layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, layer_z_bot ),
                                                                           SFVEC3F( center.x - f, center.y, layer_z_bot ),
                                                                           SFVEC3F( center.x,
                                                                                    center.y + f, layer_z_bot ) );

                    unsigned int nr_sides_per_circle = (unsigned int)mapf( radiusSquared,
                                                                           calc_sides_min_factor, calc_sides_max_factor,
                                                                           24.0f, 256.0f );

                    wxASSERT( nr_sides_per_circle >= 24 );

                    // Normal radius for the circle
                    radius = filledCircle->GetRadius();

                    std::vector< SFVEC2F > contournPoints;

                    contournPoints.clear();
                    contournPoints.reserve( nr_sides_per_circle + 2 );
                    int    delta       = 3600 / nr_sides_per_circle;
                    for( int ii = 0; ii < 3600; ii += delta )
                    {
                        const SFVEC2F rotatedDir = glm::rotate( SFVEC2F( 0.0f, 1.0f ),  (float)ii  * 2.0f * 3.14f / 3600.0f );
                        contournPoints.push_back(   SFVEC2F( center.x - rotatedDir.y * radius, center.y + rotatedDir.x * radius ) );
                    }
                    contournPoints.push_back( contournPoints[0] );

                    if( contournPoints.size() > 1 )
                    {
                        for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i )
                        {
                            const SFVEC2F &v0 = contournPoints[i + 0];
                            const SFVEC2F &v1 = contournPoints[i + 1];

                            layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ),
                                                                                     SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ),
                                                                                     SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ),
                                                                                     SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ) );


                            const SFVEC2F n0 = glm::normalize( v0 - center );
                            const SFVEC2F n1 = glm::normalize( v1 - center );
                            const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
                            const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
                            layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
                        }
                    }
                    contournPoints.clear();

                }
                break;

                case OBJ2D_DUMMYBLOCK:
                {
                }
                break;

                case OBJ2D_POLYGON4PT:
                {
                    const CPOLYGON4PTS2D *poly = (const CPOLYGON4PTS2D *)object2d_A;
                    const SFVEC2F &v0 = poly->GetV0();
                    const SFVEC2F &v1 = poly->GetV1();
                    const SFVEC2F &v2 = poly->GetV2();
                    const SFVEC2F &v3 = poly->GetV3();

                    add_triangle_top_bot( layerTriangles, v0, v2, v1, layer_z_top, layer_z_bot );
                    add_triangle_top_bot( layerTriangles, v2, v0, v3, layer_z_top, layer_z_bot );

                    const SFVEC2F &n0 = poly->GetN0();
                    const SFVEC2F &n1 = poly->GetN1();
                    const SFVEC2F &n2 = poly->GetN2();
                    const SFVEC2F &n3 = poly->GetN3();

                    const SFVEC3F n3d0 = SFVEC3F(-n0.y, n0.x, 0.0f );
                    const SFVEC3F n3d1 = SFVEC3F(-n1.y, n1.x, 0.0f );
                    const SFVEC3F n3d2 = SFVEC3F(-n2.y, n2.x, 0.0f );
                    const SFVEC3F n3d3 = SFVEC3F(-n3.y, n3.x, 0.0f );

                    layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_bot ),
                                                                             SFVEC3F( v1.x, v1.y, layer_z_bot ),
                                                                             SFVEC3F( v1.x, v1.y, layer_z_top ),
                                                                             SFVEC3F( v0.x, v0.y, layer_z_top ) );
                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d0, n3d0, n3d0, n3d0 );


                    layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v2.x, v2.y, layer_z_top ),
                                                                             SFVEC3F( v1.x, v1.y, layer_z_top ),
                                                                             SFVEC3F( v1.x, v1.y, layer_z_bot ),
                                                                             SFVEC3F( v2.x, v2.y, layer_z_bot ) );
                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d1, n3d1, n3d1, n3d1 );


                    layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v3.x, v3.y, layer_z_top ),
                                                                             SFVEC3F( v2.x, v2.y, layer_z_top ),
                                                                             SFVEC3F( v2.x, v2.y, layer_z_bot ),
                                                                             SFVEC3F( v3.x, v3.y, layer_z_bot ) );
                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d2, n3d2, n3d2, n3d2 );


                    layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_top ),
                                                                             SFVEC3F( v3.x, v3.y, layer_z_top ),
                                                                             SFVEC3F( v3.x, v3.y, layer_z_bot ),
                                                                             SFVEC3F( v0.x, v0.y, layer_z_bot ) );
                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d3, n3d3, n3d3, n3d3 );
                }
                break;


                case OBJ2D_RING:
                {
                    const CRING2D *ring = (const CRING2D *)object2d_A;
                    const SFVEC2F &center = ring->GetCenter();
                    float inner = ring->GetInnerRadius();
                    float outer = ring->GetOuterRadius();

                    unsigned int nr_sides_per_circle = (unsigned int)mapf( outer,
                                                                           calc_sides_min_factor, calc_sides_max_factor,
                                                                           24.0f, 256.0f );

                    wxASSERT( nr_sides_per_circle >= 24 );


                    std::vector< SFVEC2F > innerContour;
                    std::vector< SFVEC2F > outerContour;
                    innerContour.clear();
                    innerContour.reserve( nr_sides_per_circle + 2 );

                    outerContour.clear();
                    outerContour.reserve( nr_sides_per_circle + 2 );

                    int    delta       = 3600 / nr_sides_per_circle;
                    for( int ii = 0; ii < 3600; ii += delta )
                    {
                        const SFVEC2F rotatedDir = glm::rotate( SFVEC2F( 0.0f, 1.0f),  (float)        ii  * 2.0f * 3.14f / 3600.0f );

                        innerContour.push_back( SFVEC2F( center.x - rotatedDir.y * inner, center.y + rotatedDir.x * inner ) );
                        outerContour.push_back( SFVEC2F( center.x - rotatedDir.y * outer, center.y + rotatedDir.x * outer ) );
                    }

                    innerContour.push_back( innerContour[0] );
                    outerContour.push_back( outerContour[0] );

                    wxASSERT( innerContour.size() == outerContour.size() );

                    for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
                    {
                        const SFVEC2F &vi0 = innerContour[i + 0];
                        const SFVEC2F &vi1 = innerContour[i + 1];
                        const SFVEC2F &vo0 = outerContour[i + 0];
                        const SFVEC2F &vo1 = outerContour[i + 1];

                        layerTriangles->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, layer_z_top ),
                                                                        SFVEC3F( vi0.x, vi0.y, layer_z_top ),
                                                                        SFVEC3F( vo0.x, vo0.y, layer_z_top ),
                                                                        SFVEC3F( vo1.x, vo1.y, layer_z_top ) );

                        layerTriangles->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, layer_z_bot ),
                                                                        SFVEC3F( vo1.x, vo1.y, layer_z_bot ),
                                                                        SFVEC3F( vo0.x, vo0.y, layer_z_bot ),
                                                                        SFVEC3F( vi0.x, vi0.y, layer_z_bot ) );
                    }

                    for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
                    {
                        const SFVEC2F &v0 = innerContour[i + 0];
                        const SFVEC2F &v1 = innerContour[i + 1];

                        layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ),
                                                                                 SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ),
                                                                                 SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ),
                                                                                 SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ) );


                        const SFVEC2F n0 = glm::normalize( v0 - center );
                        const SFVEC2F n1 = glm::normalize( v1 - center );
                        const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
                        const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
                        layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
                    }


                    for( unsigned int i = 0; i < ( outerContour.size() - 1 ); ++i )
                    {
                        const SFVEC2F &v0 = outerContour[i + 0];
                        const SFVEC2F &v1 = outerContour[i + 1];

                        layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ),
                                                                                 SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ),
                                                                                 SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ),
                                                                                 SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ) );


                        const SFVEC2F n0 = glm::normalize( v0 - center );
                        const SFVEC2F n1 = glm::normalize( v1 - center );
                        const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
                        const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
                        layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
                    }

                }
                break;


                case OBJ2D_TRIANGLE:
                {
                    const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
                    const SFVEC2F &v1 = tri->GetP1();
                    const SFVEC2F &v2 = tri->GetP2();
                    const SFVEC2F &v3 = tri->GetP3();

                    add_triangle_top_bot( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
                }
                break;

                case OBJ2D_ROUNDSEG:
                {
                    const CROUNDSEGMENT2D &roundSeg = (const CROUNDSEGMENT2D &) *object2d_A;
                    unsigned int nr_sides_per_circle = (unsigned int)mapf( roundSeg.GetWidth(),
                                                                           calc_sides_min_factor, calc_sides_max_factor,
                                                                           24.0f, 256.0f );

                    wxASSERT( nr_sides_per_circle >= 24 );

                    SFVEC2F leftStart   = roundSeg.GetLeftStar();
                    SFVEC2F leftEnd     = roundSeg.GetLeftEnd();
                    SFVEC2F leftDir     = roundSeg.GetLeftDir();

                    SFVEC2F rightStart  = roundSeg.GetRightStar();
                    SFVEC2F rightEnd    = roundSeg.GetRightEnd();
                    SFVEC2F rightDir    = roundSeg.GetRightDir();
                    float   radius      = roundSeg.GetRadius();

                    SFVEC2F start       = roundSeg.GetStart();
                    SFVEC2F end         = roundSeg.GetEnd();

                    float texture_factor = (12.0f/(float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
                    float texture_factorF= ( 4.0f/(float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;

                    const float radius_of_the_square = sqrtf( roundSeg.GetRadiusSquared() * 2.0f );
                    const float radius_triangle_factor = (radius_of_the_square - radius) / radius;

                    const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor, rightDir.x * radius * radius_triangle_factor );
                    const SFVEC2F factorE = SFVEC2F( -leftDir.y  * radius * radius_triangle_factor, leftDir.x  * radius * radius_triangle_factor );

                    // Top end segment triangles
                    layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( rightEnd.x   + texture_factor * factorS.x, rightEnd.y  + texture_factor * factorS.y, layer_z_top ),
                                                                           SFVEC3F( leftStart.x  + texture_factor * factorE.x, leftStart.y + texture_factor * factorE.y, layer_z_top ),
                                                                           SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf(2.0f),
                                                                                    start.y - texture_factorF * leftDir.y * radius * sqrtf(2.0f), layer_z_top ) );

                    layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( leftEnd.x    + texture_factor * factorE.x, leftEnd.y    + texture_factor * factorE.y, layer_z_top ),
                                                                           SFVEC3F( rightStart.x + texture_factor * factorS.x, rightStart.y + texture_factor * factorS.y, layer_z_top ),
                                                                           SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf(2.0f),
                                                                                    end.y - texture_factorF * rightDir.y * radius * sqrtf(2.0f), layer_z_top ) );

                    // Bot end segment triangles
                    layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( leftStart.x  + texture_factor * factorE.x, leftStart.y + texture_factor * factorE.y, layer_z_bot ),
                                                                           SFVEC3F( rightEnd.x   + texture_factor * factorS.x, rightEnd.y  + texture_factor * factorS.y, layer_z_bot ),
                                                                           SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf(2.0f),
                                                                                    start.y - texture_factorF * leftDir.y * radius * sqrtf(2.0f), layer_z_bot ) );

                    layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( rightStart.x + texture_factor * factorS.x, rightStart.y + texture_factor * factorS.y, layer_z_bot ),
                                                                           SFVEC3F( leftEnd.x    + texture_factor * factorE.x, leftEnd.y    + texture_factor * factorE.y, layer_z_bot ),
                                                                           SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf(2.0f),
                                                                                    end.y - texture_factorF * rightDir.y * radius * sqrtf(2.0f), layer_z_bot ) );

                    // Segment top and bot planes
                    layerTriangles->m_layer_top_triangles->AddQuad( SFVEC3F( rightEnd.x,   rightEnd.y,   layer_z_top ),
                                                                    SFVEC3F( rightStart.x, rightStart.y, layer_z_top ),
                                                                    SFVEC3F( leftEnd.x,    leftEnd.y,    layer_z_top ),
                                                                    SFVEC3F( leftStart.x,  leftStart.y,  layer_z_top ) );

                    layerTriangles->m_layer_bot_triangles->AddQuad( SFVEC3F( rightEnd.x,   rightEnd.y,   layer_z_bot ),
                                                                    SFVEC3F( leftStart.x,  leftStart.y,  layer_z_bot ),
                                                                    SFVEC3F( leftEnd.x,    leftEnd.y,    layer_z_bot ),
                                                                    SFVEC3F( rightStart.x, rightStart.y, layer_z_bot ) );

                    // Middle contourns (two sides of the segment)
                    layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( leftStart.x, leftStart.y, layer_z_top ),
                                                                             SFVEC3F( leftEnd.x,   leftEnd.y,   layer_z_top ),
                                                                             SFVEC3F( leftEnd.x,   leftEnd.y,   layer_z_bot ),
                                                                             SFVEC3F( leftStart.x, leftStart.y, layer_z_bot ) );
                    const SFVEC3F leftNormal = SFVEC3F( -leftDir.y, leftDir.x, 0.0f );
                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( leftNormal, leftNormal, leftNormal, leftNormal );


                    layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( rightStart.x, rightStart.y, layer_z_top ),
                                                                             SFVEC3F( rightEnd.x,   rightEnd.y,   layer_z_top ),
                                                                             SFVEC3F( rightEnd.x,   rightEnd.y,   layer_z_bot ),
                                                                             SFVEC3F( rightStart.x, rightStart.y, layer_z_bot ) );
                    const SFVEC3F rightNormal = SFVEC3F( -rightDir.y, rightDir.x, 0.0f );
                    layerTriangles->m_layer_middle_contourns_quads->AddNormal( rightNormal, rightNormal, rightNormal, rightNormal );


                    // Compute the outlines of the segment, and creates a polygon
                    // add right rounded end:

                    std::vector< SFVEC2F > roundedEndPointsStart;
                    std::vector< SFVEC2F > roundedEndPointsEnd;
                    roundedEndPointsStart.clear();
                    roundedEndPointsStart.reserve( nr_sides_per_circle + 2 );

                    roundedEndPointsEnd.clear();
                    roundedEndPointsEnd.reserve( nr_sides_per_circle + 2 );

                    roundedEndPointsStart.push_back( SFVEC2F( leftStart.x, leftStart.y ) );
                    roundedEndPointsEnd.push_back(   SFVEC2F( leftEnd.x,   leftEnd.y ) );

                    int    delta       = 3600 / nr_sides_per_circle;
                    for( int ii = delta; ii < 1800; ii += delta )
                    {
                        const SFVEC2F rotatedDirL = glm::rotate( leftDir,  (float)        ii  * 2.0f * 3.14f / 3600.0f );
                        const SFVEC2F rotatedDirR = glm::rotate( rightDir, (float)(1800 - ii) * 2.0f * 3.14f / 3600.0f );
                        roundedEndPointsStart.push_back( SFVEC2F( start.x - rotatedDirL.y * radius, start.y + rotatedDirL.x * radius ) );
                        roundedEndPointsEnd.push_back(   SFVEC2F( end.x   - rotatedDirR.y * radius, end.y   + rotatedDirR.x * radius ) );
                    }
                    roundedEndPointsStart.push_back( SFVEC2F( rightEnd.x, rightEnd.y ) );
                    roundedEndPointsEnd.push_back(   SFVEC2F( rightStart.x, rightStart.y ) );

                    if( roundedEndPointsStart.size() > 1 )
                    {
                        for( unsigned int i = 0; i < ( roundedEndPointsStart.size() - 1 ); ++i )
                        {
                            const SFVEC2F &v0 = roundedEndPointsStart[i + 0];
                            const SFVEC2F &v1 = roundedEndPointsStart[i + 1];

                            layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_bot ),
                                                                                     SFVEC3F( v1.x, v1.y, layer_z_bot ),
                                                                                     SFVEC3F( v1.x, v1.y, layer_z_top ),
                                                                                     SFVEC3F( v0.x, v0.y, layer_z_top ) );


                            const SFVEC2F n0 = glm::normalize( v0 - start );
                            const SFVEC2F n1 = glm::normalize( v1 - start );
                            const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
                            const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
                            layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
                        }
                    }
                    roundedEndPointsStart.clear();

                    if( roundedEndPointsEnd.size() > 1 )
                    {
                        for( unsigned int i = 0; i < ( roundedEndPointsEnd.size() - 1 ); ++i )
                        {
                            const SFVEC2F &v0 = roundedEndPointsEnd[i + 0];
                            const SFVEC2F &v1 = roundedEndPointsEnd[i + 1];

                            layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_top ),
                                                                                     SFVEC3F( v1.x, v1.y, layer_z_top ),
                                                                                     SFVEC3F( v1.x, v1.y, layer_z_bot ),
                                                                                     SFVEC3F( v0.x, v0.y, layer_z_bot ) );


                            const SFVEC2F n0 = glm::normalize( v0 - end );
                            const SFVEC2F n1 = glm::normalize( v1 - end );
                            const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
                            const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
                            layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
                        }
                    }
                    roundedEndPointsEnd.clear();
                }
                break;

                default:
                {
                }
                break;
            }
#if 0
            // not yet used / implemented (can be used in future to clip the objects in the board borders
            COBJECT2D *object2d_C = CSGITEM_FULL;

            std::vector<const COBJECT2D *> *object2d_B = CSGITEM_EMPTY;

            if( m_settings.GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) )
            {
                object2d_B = new std::vector<const COBJECT2D *>();

                // Check if there are any layerhole that intersects this object
                // Eg: a segment is cutted by a via hole or THT hole.
                // /////////////////////////////////////////////////////////////
                const MAP_CONTAINER_2D &layerHolesMap = m_settings.GetMapLayersHoles();
                if( layerHolesMap.find(layer_id) != layerHolesMap.end() )
                {
                    MAP_CONTAINER_2D::const_iterator ii_hole = layerHolesMap.find(layer_id);
                    const CBVHCONTAINER2D *containerLayerHoles2d = static_cast<const CBVHCONTAINER2D *>(ii_hole->second);


                    CONST_LIST_OBJECT2D intersectionList;
                    containerLayerHoles2d->GetListObjectsIntersects( object2d_A->GetBBox(), intersectionList );

                    if( !intersectionList.empty() )
                    {
                        for( CONST_LIST_OBJECT2D::const_iterator holeOnLayer = intersectionList.begin();
                             holeOnLayer != intersectionList.end();
                             holeOnLayer++ )
                        {
                            const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*holeOnLayer);

                            //if( object2d_A->Intersects( hole2d->GetBBox() ) )
                                //if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) )
                                    object2d_B->push_back( hole2d );
                        }
                    }
                }

                // Check if there are any THT that intersects this object
                // /////////////////////////////////////////////////////////////
                if( !m_settings.GetThroughHole_Inflated().GetList().empty() )
                {
                    CONST_LIST_OBJECT2D intersectionList;
                    m_settings.GetThroughHole_Inflated().GetListObjectsIntersects( object2d_A->GetBBox(), intersectionList );

                    if( !intersectionList.empty() )
                    {
                        for( CONST_LIST_OBJECT2D::const_iterator hole = intersectionList.begin();
                             hole != intersectionList.end();
                             hole++ )
                        {
                            const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*hole);

                            //if( object2d_A->Intersects( hole2d->GetBBox() ) )
                                //if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) )
                                    object2d_B->push_back( hole2d );
                        }
                    }
                }

                if( object2d_B->empty() )
                {
                    delete object2d_B;
                    object2d_B = CSGITEM_EMPTY;
                }
            }

            if( (object2d_B == CSGITEM_EMPTY) &&
                (object2d_C == CSGITEM_FULL) )
            {
#if 0
               create_3d_object_from( m_object_container, object2d_A, m_settings.GetLayerBottomZpos3DU( layer_id ),
                                                                       m_settings.GetLayerTopZpos3DU( layer_id ),
                                       materialLayer,
                                       layerColor );
#else
                CLAYERITEM *objPtr = new CLAYERITEM( object2d_A, m_settings.GetLayerBottomZpos3DU( layer_id ),
                                                                 m_settings.GetLayerTopZpos3DU( layer_id ) );
                objPtr->SetMaterial( materialLayer );
                objPtr->SetColor( layerColor );
                m_object_container.Add( objPtr );
#endif
            }
            else
            {
#if 1
                CITEMLAYERCSG2D *itemCSG2d = new CITEMLAYERCSG2D( object2d_A, object2d_B, object2d_C,
                                                                  object2d_A->GetBoardItem() );
                m_containerWithObjectsToDelete.Add( itemCSG2d );

                CLAYERITEM *objPtr = new CLAYERITEM( itemCSG2d, m_settings.GetLayerBottomZpos3DU( layer_id ),
                                                     m_settings.GetLayerTopZpos3DU( layer_id ) );

                objPtr->SetMaterial( materialLayer );
                objPtr->SetColor( layerColor );
                m_object_container.Add( objPtr );
#endif
            }
#endif
        }

        // Create display list
        // /////////////////////////////////////////////////////////////////////
        m_ogl_disp_lists_layers[layer_id] = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
                                                                        m_ogl_circle_texture,
                                                                        layerColor );
    }// for each layer on map

}