You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1093 lines
34 KiB

18 years ago
18 years ago
18 years ago
18 years ago
14 years ago
14 years ago
14 years ago
17 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. /**
  24. * @file 3d_draw.cpp
  25. */
  26. #include <fctsys.h>
  27. #include <common.h>
  28. #include <trigo.h>
  29. #include <pcbstruct.h>
  30. #include <drawtxt.h>
  31. #include <layers_id_colors_and_visibility.h>
  32. #include <class_board.h>
  33. #include <class_module.h>
  34. #include <class_track.h>
  35. #include <class_edge_mod.h>
  36. #include <class_zone.h>
  37. #include <class_drawsegment.h>
  38. #include <class_pcb_text.h>
  39. #include <colors_selection.h>
  40. #include <convert_basic_shapes_to_polygon.h>
  41. #include <3d_viewer.h>
  42. #include <3d_canvas.h>
  43. #include <info3d_visu.h>
  44. #include <trackball.h>
  45. #include <3d_draw_basic_functions.h>
  46. // Imported function:
  47. extern void SetGLColor( int color );
  48. extern void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
  49. extern void CheckGLError();
  50. /* returns true if aLayer should be displayed, false otherwise
  51. */
  52. static bool Is3DLayerEnabled( int aLayer );
  53. /* returns the Z orientation parmeter 1.0 or -1.0 for aLayer
  54. * Z orientation is 1.0 for all layers but "back" layers:
  55. * LAYER_N_BACK , ADHESIVE_N_BACK, SOLDERPASTE_N_BACK ), SILKSCREEN_N_BACK
  56. * used to calculate the Z orientation parmeter for glNormal3f
  57. */
  58. static GLfloat Get3DLayer_Z_Orientation( int aLayer );
  59. void EDA_3D_CANVAS::Redraw( bool finish )
  60. {
  61. // SwapBuffer requires the window to be shown before calling
  62. if( !IsShown() )
  63. return;
  64. SetCurrent( *m_glRC );
  65. // Set the OpenGL viewport according to the client size of this canvas.
  66. // This is done here rather than in a wxSizeEvent handler because our
  67. // OpenGL rendering context (and thus viewport setting) is used with
  68. // multiple canvases: If we updated the viewport in the wxSizeEvent
  69. // handler, changing the size of one canvas causes a viewport setting that
  70. // is wrong when next another canvas is repainted.
  71. const wxSize ClientSize = GetClientSize();
  72. // *MUST* be called *after* SetCurrent( ):
  73. glViewport( 0, 0, ClientSize.x, ClientSize.y );
  74. InitGL();
  75. glMatrixMode( GL_MODELVIEW ); // position viewer
  76. // transformations
  77. GLfloat mat[4][4];
  78. // Translate motion first, so rotations don't mess up the orientation...
  79. glTranslatef( m_draw3dOffset.x, m_draw3dOffset.y, 0.0F );
  80. build_rotmatrix( mat, g_Parm_3D_Visu.m_Quat );
  81. glMultMatrixf( &mat[0][0] );
  82. glRotatef( g_Parm_3D_Visu.m_Rot[0], 1.0, 0.0, 0.0 );
  83. glRotatef( g_Parm_3D_Visu.m_Rot[1], 0.0, 1.0, 0.0 );
  84. glRotatef( g_Parm_3D_Visu.m_Rot[2], 0.0, 0.0, 1.0 );
  85. if( m_gllist )
  86. {
  87. glCallList( m_gllist );
  88. }
  89. else
  90. {
  91. CreateDrawGL_List();
  92. }
  93. glFlush();
  94. if( finish )
  95. glFinish();
  96. SwapBuffers();
  97. }
  98. GLuint EDA_3D_CANVAS::CreateDrawGL_List()
  99. {
  100. PCB_BASE_FRAME* pcbframe = Parent()->Parent();
  101. BOARD* pcb = pcbframe->GetBoard();
  102. wxBusyCursor dummy;
  103. m_gllist = glGenLists( 1 );
  104. // Build 3D board parameters:
  105. g_Parm_3D_Visu.InitSettings( pcb );
  106. glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
  107. glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
  108. // draw axis
  109. if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_AXIS])
  110. {
  111. glEnable( GL_COLOR_MATERIAL );
  112. SetGLColor( WHITE );
  113. glBegin( GL_LINES );
  114. glNormal3f( 0.0f, 0.0f, 1.0f ); // Normal is Z axis
  115. glVertex3f( 0.0f, 0.0f, 0.0f );
  116. glVertex3f( 1.0f, 0.0f, 0.0f ); // X axis
  117. glVertex3f( 0.0f, 0.0f, 0.0f );
  118. glVertex3f( 0.0f, -1.0f, 0.0f ); // Y axis
  119. glNormal3f( 1.0f, 0.0f, 0.0f ); // Normal is Y axis
  120. glVertex3f( 0.0f, 0.0f, 0.0f );
  121. glVertex3f( 0.0f, 0.0f, 0.3f ); // Z axis
  122. glEnd();
  123. }
  124. // move the board in order to draw it with its center at 0,0 3D coordinates
  125. glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BiuTo3Dunits,
  126. -g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits,
  127. 0.0F );
  128. // draw tracks and vias :
  129. for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() )
  130. {
  131. if( track->Type() == PCB_VIA_T )
  132. Draw3D_Via( (SEGVIA*) track );
  133. else
  134. {
  135. int layer = track->GetLayer();
  136. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) )
  137. Draw3D_Track( track );
  138. }
  139. }
  140. if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE])
  141. {
  142. for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
  143. {
  144. int layer = pcb->GetArea( ii )->GetLayer();
  145. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) )
  146. Draw3D_Zone( pcb->GetArea( ii ) );
  147. }
  148. }
  149. // Draw epoxy limits: TODO
  150. // draw graphic items
  151. EDA_ITEM* PtStruct;
  152. for( PtStruct = pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() )
  153. {
  154. switch( PtStruct->Type() )
  155. {
  156. case PCB_LINE_T:
  157. {
  158. DRAWSEGMENT* segment = (DRAWSEGMENT*) PtStruct;
  159. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( segment->GetLayer() ) )
  160. Draw3D_DrawSegment( segment );
  161. }
  162. break;
  163. case PCB_TEXT_T:
  164. {
  165. TEXTE_PCB* text = (TEXTE_PCB*) PtStruct;
  166. if( Is3DLayerEnabled( text->GetLayer() ) )
  167. Draw3D_DrawText( text );
  168. }
  169. break;
  170. default:
  171. break;
  172. }
  173. }
  174. // draw footprints
  175. MODULE* Module = pcb->m_Modules;
  176. for( ; Module != NULL; Module = Module->Next() )
  177. Module->Draw3D( this );
  178. // Draw grid
  179. if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_GRID] )
  180. DrawGrid( g_Parm_3D_Visu.m_3D_Grid );
  181. glEndList();
  182. // Test for errors
  183. CheckGLError();
  184. return m_gllist;
  185. }
  186. /* Draw a zone (solid copper areas in aZone)
  187. */
  188. void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
  189. {
  190. int layer = aZone->GetLayer();
  191. int color = g_ColorsSettings.GetLayerColor( layer );
  192. int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
  193. if( layer == LAST_COPPER_LAYER )
  194. layer = g_Parm_3D_Visu.m_CopperLayersCount - 1;
  195. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
  196. SetGLColor( color );
  197. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  198. if( aZone->m_FillMode == 0 )
  199. {
  200. // solid polygons only are used to fill areas
  201. if( aZone->GetFilledPolysList().size() > 3 )
  202. {
  203. Draw3D_SolidHorizontalPolyPolygons( aZone->GetFilledPolysList(),
  204. g_Parm_3D_Visu.GetLayerZcoordBIU( layer ),
  205. thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
  206. }
  207. }
  208. else
  209. {
  210. // segments are used to fill areas
  211. for( unsigned iseg = 0; iseg < aZone->m_FillSegmList.size(); iseg++ )
  212. Draw3D_SolidSegment( aZone->m_FillSegmList[iseg].m_Start,
  213. aZone->m_FillSegmList[iseg].m_End,
  214. aZone->m_ZoneMinThickness, thickness, zpos,
  215. g_Parm_3D_Visu.m_BiuTo3Dunits );
  216. }
  217. // Draw copper area outlines
  218. std::vector<CPolyPt> polysList = aZone->GetFilledPolysList();
  219. if( polysList.size() == 0 )
  220. return;
  221. if( aZone->m_ZoneMinThickness <= 1 )
  222. return;
  223. int imax = polysList.size() - 1;
  224. CPolyPt* firstcorner = &polysList[0];
  225. CPolyPt* begincorner = firstcorner;
  226. for( int ic = 1; ic <= imax; ic++ )
  227. {
  228. CPolyPt* endcorner = &polysList[ic];
  229. if( begincorner->m_utility == 0 )
  230. {
  231. // Draw only basic outlines, not extra segments
  232. wxPoint start( begincorner->x, begincorner->y );
  233. wxPoint end( endcorner->x, endcorner->y );
  234. Draw3D_SolidSegment( start, end,
  235. aZone->m_ZoneMinThickness, thickness, zpos,
  236. g_Parm_3D_Visu.m_BiuTo3Dunits );
  237. }
  238. if( (endcorner->end_contour) || (ic == imax) )
  239. {
  240. // the last corner of a filled area is found: draw it
  241. if( endcorner->m_utility == 0 )
  242. {
  243. // Draw only basic outlines, not extra segments
  244. wxPoint start( endcorner->x, endcorner->y );
  245. wxPoint end( firstcorner->x, firstcorner->y );
  246. Draw3D_SolidSegment( start, end,
  247. aZone->m_ZoneMinThickness, thickness, zpos,
  248. g_Parm_3D_Visu.m_BiuTo3Dunits );
  249. }
  250. ic++;
  251. if( ic < imax - 1 )
  252. begincorner = firstcorner = &polysList[ic];
  253. }
  254. else
  255. {
  256. begincorner = endcorner;
  257. }
  258. }
  259. }
  260. // draw a 3D grid: an horizontal grid (XY plane and Z = 0,
  261. // and a vertical grid (XZ plane and Y = 0)
  262. void EDA_3D_CANVAS::DrawGrid( double aGriSizeMM )
  263. {
  264. double zpos = 0.0;
  265. int gridcolor = DARKGRAY; // Color of grid lines
  266. int gridcolor_marker = LIGHTGRAY; // Color of grid lines every 5 lines
  267. double scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
  268. glNormal3f( 0.0, 0.0, 1.0 );
  269. wxSize brd_size = g_Parm_3D_Visu.m_BoardSize;
  270. wxPoint brd_center_pos = g_Parm_3D_Visu.m_BoardPos;
  271. NEGATE( brd_center_pos.y );
  272. int xsize = std::max( brd_size.x, Millimeter2iu( 100 ) );
  273. int ysize = std::max( brd_size.y, Millimeter2iu( 100 ) );
  274. // Grid limits, in 3D units
  275. double xmin = (brd_center_pos.x - xsize/2) * scale;
  276. double xmax = (brd_center_pos.x + xsize/2) * scale;
  277. double ymin = (brd_center_pos.y - ysize/2) * scale;
  278. double ymax = (brd_center_pos.y + ysize/2) * scale;
  279. double zmin = Millimeter2iu( -50 ) * scale;
  280. double zmax = Millimeter2iu( 100 ) * scale;
  281. // Draw horizontal grid centered on 3D origin (center of the board)
  282. for( int ii = 0; ; ii++ )
  283. {
  284. if( (ii % 5) )
  285. SetGLColor( gridcolor );
  286. else
  287. SetGLColor( gridcolor_marker );
  288. int delta = KiROUND( ii * aGriSizeMM * IU_PER_MM );
  289. if( delta <= xsize/2 ) // Draw grid lines parallel to X axis
  290. {
  291. glBegin(GL_LINES);
  292. glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
  293. glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
  294. glEnd();
  295. if( ii != 0 )
  296. {
  297. glBegin(GL_LINES);
  298. glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
  299. glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
  300. glEnd();
  301. }
  302. }
  303. if( delta <= ysize/2 ) // Draw grid lines parallel to Y axis
  304. {
  305. glBegin(GL_LINES);
  306. glVertex3f( xmin, -(brd_center_pos.y + delta) * scale, zpos );
  307. glVertex3f( xmax, -(brd_center_pos.y + delta) * scale, zpos );
  308. glEnd();
  309. if( ii != 0 )
  310. {
  311. glBegin(GL_LINES);
  312. glVertex3f( xmin, -(brd_center_pos.y - delta) * scale, zpos );
  313. glVertex3f( xmax, -(brd_center_pos.y - delta) * scale, zpos );
  314. glEnd();
  315. }
  316. }
  317. if( ( delta > ysize/2 ) && ( delta > xsize/2 ) )
  318. break;
  319. }
  320. // Draw vertical grid n Z axis
  321. glNormal3f( 0.0, -1.0, 0.0 );
  322. // Draw vertical grid lines (parallel to Z axis)
  323. for( int ii = 0; ; ii++ )
  324. {
  325. if( (ii % 5) )
  326. SetGLColor( gridcolor );
  327. else
  328. SetGLColor( gridcolor_marker );
  329. double delta = ii * aGriSizeMM * IU_PER_MM;
  330. glBegin(GL_LINES);
  331. glVertex3f( (brd_center_pos.x + delta) * scale, -brd_center_pos.y * scale, zmin );
  332. glVertex3f( (brd_center_pos.x + delta) * scale, -brd_center_pos.y * scale, zmax );
  333. glEnd();
  334. if( ii != 0 )
  335. {
  336. glBegin(GL_LINES);
  337. glVertex3f( (brd_center_pos.x - delta) * scale, -brd_center_pos.y * scale, zmin );
  338. glVertex3f( (brd_center_pos.x - delta) * scale, -brd_center_pos.y * scale, zmax );
  339. glEnd();
  340. }
  341. if( delta > xsize/2 )
  342. break;
  343. }
  344. // Draw horizontal grid lines on Z axis
  345. for( int ii = 0; ; ii++ )
  346. {
  347. if( (ii % 5) )
  348. SetGLColor( gridcolor );
  349. else
  350. SetGLColor( gridcolor_marker );
  351. double delta = ii * aGriSizeMM * IU_PER_MM * scale;
  352. if( delta <= zmax )
  353. { // Draw grid lines on Z axis (positive Z axis coordinates)
  354. glBegin(GL_LINES);
  355. glVertex3f(xmin, -brd_center_pos.y * scale, delta);
  356. glVertex3f(xmax, -brd_center_pos.y * scale, delta);
  357. glEnd();
  358. }
  359. if( delta <= -zmin && ( ii != 0 ) )
  360. { // Draw grid lines on Z axis (negative Z axis coordinates)
  361. glBegin(GL_LINES);
  362. glVertex3f(xmin, -brd_center_pos.y * scale, -delta);
  363. glVertex3f(xmax, -brd_center_pos.y * scale, -delta);
  364. glEnd();
  365. }
  366. if( ( delta > zmax ) && ( delta > -zmin ) )
  367. break;
  368. }
  369. }
  370. void EDA_3D_CANVAS::Draw3D_Track( TRACK* aTrack )
  371. {
  372. int layer = aTrack->GetLayer();
  373. int color = g_ColorsSettings.GetLayerColor( layer );
  374. int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
  375. if( layer == LAST_COPPER_LAYER )
  376. layer = g_Parm_3D_Visu.m_CopperLayersCount - 1;
  377. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
  378. SetGLColor( color );
  379. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  380. Draw3D_SolidSegment( aTrack->GetStart(), aTrack->GetEnd(),
  381. aTrack->GetWidth(), thickness, zpos,
  382. g_Parm_3D_Visu.m_BiuTo3Dunits );
  383. }
  384. void EDA_3D_CANVAS::Draw3D_Via( SEGVIA* via )
  385. {
  386. int layer, top_layer, bottom_layer;
  387. int color;
  388. double biu_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits ;
  389. int outer_radius = via->GetWidth() / 2;
  390. int inner_radius = via->GetDrillValue() / 2;
  391. int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
  392. via->ReturnLayerPair( &top_layer, &bottom_layer );
  393. // Drawing horizontal thick rings:
  394. for( layer = bottom_layer; layer < g_Parm_3D_Visu.m_CopperLayersCount; layer++ )
  395. {
  396. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
  397. if( layer < g_Parm_3D_Visu.m_CopperLayersCount - 1 )
  398. {
  399. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
  400. continue;
  401. color = g_ColorsSettings.GetLayerColor( layer );
  402. }
  403. else
  404. {
  405. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( LAYER_N_FRONT ) == false )
  406. continue;
  407. color = g_ColorsSettings.GetLayerColor( LAYER_N_FRONT );
  408. }
  409. SetGLColor( color );
  410. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  411. Draw3D_ZaxisCylinder( via->GetStart(), (outer_radius + inner_radius)/2,
  412. thickness, outer_radius - inner_radius,
  413. zpos, biu_to_3Dunits );
  414. if( layer >= top_layer )
  415. break;
  416. }
  417. // Drawing via hole:
  418. color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + via->GetShape() );
  419. SetGLColor( color );
  420. int height = g_Parm_3D_Visu.GetLayerZcoordBIU(top_layer) -
  421. g_Parm_3D_Visu.GetLayerZcoordBIU( bottom_layer );
  422. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(bottom_layer) + thickness/2;
  423. Draw3D_ZaxisCylinder( via->GetStart(), inner_radius + thickness/2, height,
  424. thickness, zpos, biu_to_3Dunits );
  425. }
  426. void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment )
  427. {
  428. int layer = segment->GetLayer();
  429. int color = g_ColorsSettings.GetLayerColor( layer );
  430. int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
  431. SetGLColor( color );
  432. if( layer == EDGE_N )
  433. {
  434. for( layer = 0; layer < g_Parm_3D_Visu.m_CopperLayersCount; layer++ )
  435. {
  436. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  437. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(layer);
  438. switch( segment->GetShape() )
  439. {
  440. case S_ARC:
  441. Draw3D_ArcSegment( segment->GetCenter(), segment->GetArcStart(),
  442. segment->GetAngle(), segment->GetWidth(), thickness,
  443. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  444. break;
  445. case S_CIRCLE:
  446. {
  447. int radius = KiROUND( hypot( double(segment->GetStart().x - segment->GetEnd().x),
  448. double(segment->GetStart().y - segment->GetEnd().y) )
  449. );
  450. Draw3D_ZaxisCylinder( segment->GetStart(), radius,
  451. thickness, segment->GetWidth(),
  452. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  453. }
  454. break;
  455. default:
  456. Draw3D_SolidSegment( segment->GetStart(), segment->GetEnd(),
  457. segment->GetWidth(), thickness,
  458. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  459. break;
  460. }
  461. }
  462. }
  463. else
  464. {
  465. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  466. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(layer);
  467. if( Is3DLayerEnabled( layer ) )
  468. {
  469. switch( segment->GetShape() )
  470. {
  471. case S_ARC:
  472. Draw3D_ArcSegment( segment->GetCenter(), segment->GetArcStart(),
  473. segment->GetAngle(), segment->GetWidth(), thickness,
  474. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  475. break;
  476. case S_CIRCLE:
  477. {
  478. int radius = KiROUND( hypot( double(segment->GetStart().x - segment->GetEnd().x),
  479. double(segment->GetStart().y - segment->GetEnd().y) )
  480. );
  481. Draw3D_ZaxisCylinder( segment->GetStart(), radius,
  482. thickness, segment->GetWidth(),
  483. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  484. }
  485. break;
  486. default:
  487. Draw3D_SolidSegment( segment->GetStart(), segment->GetEnd(),
  488. segment->GetWidth(), thickness,
  489. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  490. break;
  491. }
  492. }
  493. }
  494. }
  495. // These variables are used in Draw3dTextSegm.
  496. // But Draw3dTextSegm is a call back function, so we cannot send them as arguments,
  497. // so they are static.
  498. int s_Text3DWidth, s_Text3DZPos, s_thickness;
  499. // This is a call back function, used by DrawGraphicText to draw the 3D text shape:
  500. static void Draw3dTextSegm( int x0, int y0, int xf, int yf )
  501. {
  502. Draw3D_SolidSegment( wxPoint( x0, y0), wxPoint( xf, yf ),
  503. s_Text3DWidth, s_thickness, s_Text3DZPos,
  504. g_Parm_3D_Visu.m_BiuTo3Dunits );
  505. }
  506. void EDA_3D_CANVAS::Draw3D_DrawText( TEXTE_PCB* text )
  507. {
  508. int layer = text->GetLayer();
  509. int color = g_ColorsSettings.GetLayerColor( layer );
  510. SetGLColor( color );
  511. s_Text3DZPos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
  512. s_Text3DWidth = text->GetThickness();
  513. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  514. wxSize size = text->m_Size;
  515. s_thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
  516. if( text->m_Mirror )
  517. NEGATE( size.x );
  518. if( text->m_MultilineAllowed )
  519. {
  520. wxPoint pos = text->m_Pos;
  521. wxArrayString* list = wxStringSplit( text->GetText(), '\n' );
  522. wxPoint offset;
  523. offset.y = text->GetInterline();
  524. RotatePoint( &offset, text->GetOrientation() );
  525. for( unsigned i = 0; i<list->Count(); i++ )
  526. {
  527. wxString txt = list->Item( i );
  528. DrawGraphicText( NULL, NULL, pos, (EDA_COLOR_T) color,
  529. txt, text->GetOrientation(), size,
  530. text->m_HJustify, text->m_VJustify,
  531. text->GetThickness(), text->m_Italic,
  532. true, Draw3dTextSegm );
  533. pos += offset;
  534. }
  535. delete list;
  536. }
  537. else
  538. {
  539. DrawGraphicText( NULL, NULL, text->m_Pos, (EDA_COLOR_T) color,
  540. text->GetText(), text->GetOrientation(), size,
  541. text->m_HJustify, text->m_VJustify,
  542. text->GetThickness(), text->m_Italic,
  543. true,
  544. Draw3dTextSegm );
  545. }
  546. }
  547. void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
  548. {
  549. D_PAD* pad = m_Pads;
  550. // Draw pads
  551. for( ; pad != NULL; pad = pad->Next() )
  552. pad->Draw3D( glcanvas );
  553. // Draw module shape: 3D shape if exists (or module outlines if not exists)
  554. S3D_MASTER* Struct3D = m_3D_Drawings;
  555. bool As3dShape = false;
  556. if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_MODULE] )
  557. {
  558. double zpos;
  559. if( IsFlipped() )
  560. zpos = g_Parm_3D_Visu.GetModulesZcoord3DIU( true );
  561. else
  562. zpos = g_Parm_3D_Visu.GetModulesZcoord3DIU( false );
  563. glPushMatrix();
  564. glTranslatef( m_Pos.x * g_Parm_3D_Visu.m_BiuTo3Dunits,
  565. -m_Pos.y * g_Parm_3D_Visu.m_BiuTo3Dunits,
  566. zpos );
  567. if( m_Orient )
  568. {
  569. glRotatef( (double) m_Orient / 10, 0.0, 0.0, 1.0 );
  570. }
  571. if( IsFlipped() )
  572. {
  573. glRotatef( 180.0, 0.0, 1.0, 0.0 );
  574. glRotatef( 180.0, 0.0, 0.0, 1.0 );
  575. }
  576. for( ; Struct3D != NULL; Struct3D = Struct3D->Next() )
  577. {
  578. if( !Struct3D->m_Shape3DName.IsEmpty() )
  579. {
  580. As3dShape = true;
  581. Struct3D->ReadData();
  582. }
  583. }
  584. glPopMatrix();
  585. }
  586. EDA_ITEM* Struct = m_Drawings;
  587. for( ; Struct != NULL; Struct = Struct->Next() )
  588. {
  589. switch( Struct->Type() )
  590. {
  591. case PCB_MODULE_TEXT_T:
  592. break;
  593. case PCB_MODULE_EDGE_T:
  594. {
  595. EDGE_MODULE* edge = (EDGE_MODULE*) Struct;
  596. // Draw module edges when no 3d shape exists.
  597. // Always draw pcb edges.
  598. if( !As3dShape || edge->GetLayer() == EDGE_N )
  599. edge->Draw3D( glcanvas );
  600. }
  601. break;
  602. default:
  603. break;
  604. }
  605. }
  606. }
  607. void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
  608. {
  609. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( m_Layer ) == false )
  610. return;
  611. int color = g_ColorsSettings.GetLayerColor( m_Layer );
  612. SetGLColor( color );
  613. // for outline shape = S_POLYGON:
  614. // We must compute true coordinates from m_PolyPoints
  615. // which are relative to module position and module orientation = 0
  616. std::vector<CPolyPt> polycorners;
  617. if( m_Shape == S_POLYGON )
  618. {
  619. polycorners.reserve( m_PolyPoints.size() );
  620. MODULE* module = (MODULE*) m_Parent;
  621. CPolyPt corner;
  622. for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
  623. {
  624. corner.x = m_PolyPoints[ii].x;
  625. corner.y = m_PolyPoints[ii].y;
  626. RotatePoint( &corner.x, &corner.y, module->GetOrientation() );
  627. if( module )
  628. {
  629. corner.x += module->GetPosition().x;
  630. corner.y += module->GetPosition().y;
  631. }
  632. polycorners.push_back( corner );
  633. }
  634. polycorners.back().end_contour = true;
  635. }
  636. if( m_Layer == EDGE_N )
  637. {
  638. for( int layer = 0; layer < g_Parm_3D_Visu.m_CopperLayersCount; layer++ )
  639. {
  640. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  641. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
  642. int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( m_Layer );
  643. switch( m_Shape )
  644. {
  645. case S_SEGMENT:
  646. Draw3D_SolidSegment( m_Start, m_End, m_Width,
  647. thickness, zpos,
  648. g_Parm_3D_Visu.m_BiuTo3Dunits );
  649. break;
  650. case S_CIRCLE:
  651. {
  652. int radius = KiROUND( hypot( double(m_Start.x - m_End.x),
  653. double(m_Start.y - m_End.y) )
  654. );
  655. Draw3D_ZaxisCylinder( m_Start, radius,
  656. thickness, GetWidth(),
  657. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  658. }
  659. break;
  660. case S_ARC:
  661. Draw3D_ArcSegment( GetCenter(), GetArcStart(),
  662. GetAngle(), GetWidth(), thickness,
  663. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  664. break;
  665. case S_POLYGON:
  666. Draw3D_SolidHorizontalPolyPolygons( polycorners, zpos, thickness,
  667. g_Parm_3D_Visu.m_BiuTo3Dunits);
  668. break;
  669. default:
  670. D( printf( "Error: Shape nr %d not implemented!\n", m_Shape ); )
  671. break;
  672. }
  673. }
  674. }
  675. else
  676. {
  677. int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( m_Layer );
  678. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( m_Layer ) );
  679. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(m_Layer);
  680. switch( m_Shape )
  681. {
  682. case S_SEGMENT:
  683. Draw3D_SolidSegment( m_Start, m_End, m_Width,
  684. thickness, zpos,
  685. g_Parm_3D_Visu.m_BiuTo3Dunits );
  686. break;
  687. case S_CIRCLE:
  688. {
  689. int radius = KiROUND( hypot( double(m_Start.x - m_End.x),
  690. double(m_Start.y - m_End.y) )
  691. );
  692. Draw3D_ZaxisCylinder( m_Start, radius,
  693. thickness, GetWidth(),
  694. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  695. }
  696. break;
  697. case S_ARC:
  698. Draw3D_ArcSegment( GetCenter(), GetArcStart(),
  699. GetAngle(), GetWidth(), thickness,
  700. zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
  701. break;
  702. case S_POLYGON:
  703. Draw3D_SolidHorizontalPolyPolygons( polycorners, zpos, thickness,
  704. g_Parm_3D_Visu.m_BiuTo3Dunits );
  705. break;
  706. default:
  707. D( printf( "Error: Shape nr %d not implemented!\n", m_Shape ); )
  708. break;
  709. }
  710. }
  711. }
  712. // Draw 3D pads.
  713. void D_PAD::Draw3D( EDA_3D_CANVAS* glcanvas )
  714. {
  715. double scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
  716. // Calculate the center of the pad shape.
  717. wxPoint shape_pos = ReturnShapePos();
  718. int height = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_FRONT) -
  719. g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK);
  720. int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
  721. // Store here the points to approximate hole by segments
  722. std::vector <CPolyPt> holecornersBuffer;
  723. const int slice = 12; // number of segments to approximate a circle
  724. // Draw the pad hole
  725. bool hasHole = m_Drill.x && m_Drill.y;
  726. if( hasHole )
  727. {
  728. SetGLColor( DARKGRAY );
  729. int holeZpoz = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK) + thickness/2;
  730. int holeHeight = height - thickness;
  731. if( m_Drill.x == m_Drill.y ) // usual round hole
  732. {
  733. Draw3D_ZaxisCylinder( m_Pos, (m_Drill.x + thickness) / 2, holeHeight,
  734. thickness, holeZpoz, scale );
  735. TransformCircleToPolygon( holecornersBuffer, m_Pos, m_Drill.x/2, slice );
  736. }
  737. else // Oblong hole
  738. {
  739. wxPoint ends_offset;
  740. int width;
  741. if( m_Drill.x > m_Drill.y ) // Horizontal oval
  742. {
  743. ends_offset.x = ( m_Drill.x - m_Drill.y ) / 2;
  744. width = m_Drill.y;
  745. }
  746. else // Vertical oval
  747. {
  748. ends_offset.y = ( m_Drill.y - m_Drill.x ) / 2;
  749. width = m_Drill.x;
  750. }
  751. RotatePoint( &ends_offset, m_Orient );
  752. wxPoint start = m_Pos + ends_offset;
  753. wxPoint end = m_Pos - ends_offset;
  754. int hole_radius = ( width + thickness ) / 2;
  755. // Prepare the shape creation
  756. TransformRoundedEndsSegmentToPolygon( holecornersBuffer, start, end, slice, width );
  757. // Draw the hole
  758. Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight,
  759. thickness, holeZpoz, scale );
  760. }
  761. }
  762. glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
  763. int nlmax = g_Parm_3D_Visu.m_CopperLayersCount - 1;
  764. // Store here the points to approximate pad shape by segments
  765. std::vector<CPolyPt> polyPadShape;
  766. switch( GetShape() )
  767. {
  768. case PAD_CIRCLE:
  769. for( int layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
  770. {
  771. if( layer && (layer == nlmax) )
  772. layer = LAYER_N_FRONT;
  773. if( !IsOnLayer( layer ) )
  774. continue;
  775. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
  776. continue;
  777. SetGLColor( g_ColorsSettings.GetLayerColor( layer ) );
  778. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
  779. int ring_radius = (m_Size.x + m_Drill.x) / 4;
  780. if( thickness == 0 )
  781. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  782. Draw3D_ZaxisCylinder(shape_pos, ring_radius,
  783. thickness, ( m_Size.x - m_Drill.x) / 2,
  784. zpos - (thickness/2), scale );
  785. }
  786. break;
  787. case PAD_OVAL:
  788. {
  789. wxPoint ends_offset;
  790. int width;
  791. if( m_Size.x > m_Size.y ) // Horizontal ellipse
  792. {
  793. ends_offset.x = ( m_Size.x - m_Size.y ) / 2;
  794. width = m_Size.y;
  795. }
  796. else // Vertical ellipse
  797. {
  798. ends_offset.y = ( m_Size.y - m_Size.x ) / 2;
  799. width = m_Size.x;
  800. }
  801. RotatePoint( &ends_offset, m_Orient );
  802. wxPoint start = shape_pos + ends_offset;
  803. wxPoint end = shape_pos - ends_offset;
  804. TransformRoundedEndsSegmentToPolygon( polyPadShape, start, end, slice, width );
  805. if( hasHole )
  806. polyPadShape.insert( polyPadShape.end(), holecornersBuffer.begin(), holecornersBuffer.end() );
  807. }
  808. break;
  809. case PAD_RECT:
  810. case PAD_TRAPEZOID:
  811. {
  812. wxPoint coord[5];
  813. BuildPadPolygon( coord, wxSize(0,0), m_Orient );
  814. for( int ii = 0; ii < 4; ii ++ )
  815. {
  816. CPolyPt pt( coord[ii].x + shape_pos.x, coord[ii].y+ shape_pos.y );
  817. polyPadShape.push_back( pt );
  818. }
  819. polyPadShape.back().end_contour = true;
  820. if( hasHole )
  821. polyPadShape.insert( polyPadShape.end(), holecornersBuffer.begin(), holecornersBuffer.end() );
  822. }
  823. break;
  824. default:
  825. break;
  826. }
  827. if( polyPadShape.size() )
  828. {
  829. for( int layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
  830. {
  831. if( layer && (layer == nlmax) )
  832. layer = LAYER_N_FRONT;
  833. if( !IsOnLayer( layer ) )
  834. continue;
  835. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
  836. continue;
  837. SetGLColor( g_ColorsSettings.GetLayerColor( layer ) );
  838. if( thickness == 0 )
  839. glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
  840. // If not hole: draw a single polygon
  841. int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
  842. if( hasHole )
  843. {
  844. Draw3D_SolidHorizontalPolygonWithHoles( polyPadShape, zpos,
  845. thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
  846. }
  847. else
  848. {
  849. Draw3D_SolidHorizontalPolyPolygons( polyPadShape, zpos,
  850. thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
  851. }
  852. }
  853. }
  854. }
  855. bool Is3DLayerEnabled( int aLayer )
  856. {
  857. int flg = -1;
  858. // see if layer needs to be shown
  859. // check the flags
  860. switch (aLayer)
  861. {
  862. case DRAW_N:
  863. flg=g_Parm_3D_Visu.FL_DRAWINGS;
  864. break;
  865. case COMMENT_N:
  866. flg=g_Parm_3D_Visu.FL_COMMENTS;
  867. break;
  868. case ECO1_N:
  869. flg=g_Parm_3D_Visu.FL_ECO1;
  870. break;
  871. case ECO2_N:
  872. flg=g_Parm_3D_Visu.FL_ECO2;
  873. break;
  874. }
  875. // the layer was not a layer with a flag, so show it
  876. if( flg < 0 )
  877. return true;
  878. // if the layer has a flag, return the flag
  879. return g_Parm_3D_Visu.m_DrawFlags[flg];
  880. }
  881. GLfloat Get3DLayer_Z_Orientation( int aLayer )
  882. {
  883. double nZ;
  884. nZ = 1.0;
  885. if( ( aLayer == LAYER_N_BACK )
  886. || ( aLayer == ADHESIVE_N_BACK )
  887. || ( aLayer == SOLDERPASTE_N_BACK )
  888. || ( aLayer == SILKSCREEN_N_BACK )
  889. || ( aLayer == SOLDERMASK_N_BACK ) )
  890. nZ = -1.0;
  891. return nZ;
  892. }