wxPoint EDA_3D_CANVAS::getBoardCenter() const { // return the position of the board center in pcb units return GetPrm3DVisu().m_BoardPos; }
// 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; } }
wxSize EDA_3D_CANVAS::getBoardSize() const { // return the size of the board in pcb units return GetPrm3DVisu().m_BoardSize; }
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 ); }
// 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 ); }
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 ); } }
// 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(); }
// 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 )); }
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(); }