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.

1389 lines
43 KiB

18 years ago
18 years ago
18 years ago
18 years ago
17 years ago
  1. //////////////////////////////////////
  2. // Name: 3d_draw.cpp
  3. //////////////////////////////////////
  4. #include "fctsys.h"
  5. #include "common.h"
  6. #include "trigo.h"
  7. #include "pcbstruct.h"
  8. #include "macros.h"
  9. #include "drawtxt.h"
  10. #include "confirm.h"
  11. #include "class_board_design_settings.h"
  12. #include "colors_selection.h"
  13. #include "3d_viewer.h"
  14. #include "trackball.h"
  15. #if !wxUSE_GLCANVAS
  16. #error Please set wxUSE_GLCANVAS to 1 in setup.h.
  17. #endif
  18. static void Draw3D_FilledCircle( double posx, double posy, double rayon,
  19. double hole_rayon, double zpos );
  20. static void Draw3D_FilledSegment( double startx, double starty,
  21. double endx, double endy,
  22. double width, double zpos );
  23. static void Draw3D_FilledCylinder( double posx, double posy, double rayon,
  24. double height, double zpos );
  25. static void Draw3D_FilledSegmentWithHole( double startx, double starty,
  26. double endx, double endy,
  27. double width, double holex,
  28. double holey, double holeradius,
  29. double zpos );
  30. static void Draw3D_ArcSegment( double startx, double starty, double centrex,
  31. double centrey, double arc_angle, double width, double zpos );
  32. static void Draw3D_CircleSegment( double startx, double starty, double endx,
  33. double endy, double width, double zpos );
  34. static int Get3DLayerEnable( int act_layer );
  35. static GLfloat Get3DLayerSide( int act_layer );
  36. #ifndef CALLBACK
  37. #define CALLBACK
  38. #endif
  39. // CALLBACK functions for GLU_TESS
  40. static void CALLBACK tessBeginCB( GLenum which );
  41. static void CALLBACK tessEndCB();
  42. static void CALLBACK tessErrorCB( GLenum errorCode );
  43. static void CALLBACK tessCPolyPt2Vertex( const GLvoid* data );
  44. static void CALLBACK tesswxPoint2Vertex( const GLvoid* data );
  45. void Pcb3D_GLCanvas::Redraw( bool finish )
  46. {
  47. #if wxCHECK_VERSION( 2, 9, 0 )
  48. SetCurrent( *m_glRC );
  49. #else
  50. SetCurrent();
  51. #endif
  52. // Set the OpenGL viewport according to the client size of this canvas.
  53. // This is done here rather than in a wxSizeEvent handler because our
  54. // OpenGL rendering context (and thus viewport setting) is used with
  55. // multiple canvases: If we updated the viewport in the wxSizeEvent
  56. // handler, changing the size of one canvas causes a viewport setting that
  57. // is wrong when next another canvas is repainted.
  58. const wxSize ClientSize = GetClientSize();
  59. // *MUST* be called *after* SetCurrent( ):
  60. glViewport( 0, 0, ClientSize.x, ClientSize.y );
  61. InitGL();
  62. glMatrixMode( GL_MODELVIEW ); /* position viewer */
  63. /* transformations */
  64. GLfloat mat[4][4];
  65. // Translate motion first, so rotations don't mess up the orientation...
  66. glTranslatef( g_Draw3d_dx, g_Draw3d_dy, 0.0F );
  67. build_rotmatrix( mat, g_Parm_3D_Visu.m_Quat );
  68. glMultMatrixf( &mat[0][0] );
  69. glRotatef( g_Parm_3D_Visu.m_Rot[0], 1.0, 0.0, 0.0 );
  70. glRotatef( g_Parm_3D_Visu.m_Rot[1], 0.0, 1.0, 0.0 );
  71. glRotatef( g_Parm_3D_Visu.m_Rot[2], 0.0, 0.0, 1.0 );
  72. if( m_gllist )
  73. glCallList( m_gllist );
  74. else
  75. {
  76. CreateDrawGL_List();
  77. }
  78. glFlush();
  79. if( finish )
  80. glFinish();
  81. SwapBuffers();
  82. }
  83. /* Create the draw list items
  84. */
  85. GLuint Pcb3D_GLCanvas::CreateDrawGL_List()
  86. {
  87. WinEDA_BasePcbFrame* pcbframe = m_Parent->m_Parent;
  88. BOARD* pcb = pcbframe->GetBoard();
  89. TRACK* track;
  90. SEGZONE* segzone;
  91. int ii;
  92. wxBusyCursor dummy;
  93. m_gllist = glGenLists( 1 );
  94. pcb->ComputeBoundaryBox();
  95. g_Parm_3D_Visu.m_BoardSettings = pcb->GetBoardDesignSettings();
  96. g_Parm_3D_Visu.m_BoardSize = pcb->m_BoundaryBox.GetSize();
  97. g_Parm_3D_Visu.m_BoardPos = pcb->m_BoundaryBox.Centre();
  98. g_Parm_3D_Visu.m_BoardPos.y = -g_Parm_3D_Visu.m_BoardPos.y;
  99. g_Parm_3D_Visu.m_Layers = pcb->GetCopperLayerCount();
  100. // Ensure the board has 2 sides for 3D views, because it is hard to find
  101. // a *really* single side board in the true life...
  102. if( g_Parm_3D_Visu.m_Layers < 2 )
  103. g_Parm_3D_Visu.m_Layers = 2;
  104. g_Parm_3D_Visu.m_BoardScale = 2.0 / MAX( g_Parm_3D_Visu.m_BoardSize.x,
  105. g_Parm_3D_Visu.m_BoardSize.y );
  106. // @TODO: epoxy_width (board thickness) must be set by user,
  107. // because all boards thickness no not match with this setup:
  108. // double epoxy_width = 1.6; // epoxy width in mm
  109. g_Parm_3D_Visu.m_Epoxy_Width = pcb->GetBoardDesignSettings()->m_BoardThickness
  110. * g_Parm_3D_Visu.m_BoardScale;
  111. /* calculate z position for each layer */
  112. for( ii = 0; ii < 32; ii++ )
  113. {
  114. if( ii < g_Parm_3D_Visu.m_Layers )
  115. g_Parm_3D_Visu.m_LayerZcoord[ii] =
  116. g_Parm_3D_Visu.m_Epoxy_Width
  117. * ii / (g_Parm_3D_Visu.m_Layers - 1);
  118. else
  119. g_Parm_3D_Visu.m_LayerZcoord[ii] = g_Parm_3D_Visu.m_Epoxy_Width;
  120. }
  121. GLfloat zpos_cu = 10 * g_Parm_3D_Visu.m_BoardScale;
  122. GLfloat zpos_cmp = g_Parm_3D_Visu.m_Epoxy_Width + zpos_cu;
  123. g_Parm_3D_Visu.m_LayerZcoord[ADHESIVE_N_BACK] = -zpos_cu * 2;
  124. g_Parm_3D_Visu.m_LayerZcoord[ADHESIVE_N_FRONT] = zpos_cmp + zpos_cu;
  125. g_Parm_3D_Visu.m_LayerZcoord[SILKSCREEN_N_BACK] = -zpos_cu;
  126. g_Parm_3D_Visu.m_LayerZcoord[SILKSCREEN_N_FRONT] = zpos_cmp;
  127. g_Parm_3D_Visu.m_LayerZcoord[DRAW_N] = zpos_cmp + zpos_cu;
  128. g_Parm_3D_Visu.m_LayerZcoord[COMMENT_N] = zpos_cmp + zpos_cu;
  129. g_Parm_3D_Visu.m_LayerZcoord[ECO1_N] = zpos_cmp + zpos_cu;
  130. g_Parm_3D_Visu.m_LayerZcoord[ECO2_N] = zpos_cmp + zpos_cu;
  131. glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
  132. glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
  133. /* draw axis */
  134. if( g_Parm_3D_Visu.m_Draw3DAxis )
  135. {
  136. glEnable( GL_COLOR_MATERIAL );
  137. SetGLColor( WHITE );
  138. glBegin( GL_LINES );
  139. glNormal3f( 0.0f, 0.0f, 1.0f ); // Normal is Z axis
  140. glVertex3f( 0.0f, 0.0f, 0.0f );
  141. glVertex3f( 1.0f, 0.0f, 0.0f ); // X axis
  142. glVertex3f( 0.0f, 0.0f, 0.0f );
  143. glVertex3f( 0.0f, -1.0f, 0.0f ); // Y axis
  144. glNormal3f( 1.0f, 0.0f, 0.0f ); // Normal is Y axis
  145. glVertex3f( 0.0f, 0.0f, 0.0f );
  146. glVertex3f( 0.0f, 0.0f, 0.3f ); // Z axis
  147. glEnd();
  148. }
  149. /* Draw epoxy limits (do not use, works and test in progress) */
  150. #if 0
  151. glEnable( GL_FOG );
  152. GLfloat param;
  153. // param = GL_LINEAR;
  154. // glFogfv(GL_FOG_MODE, & param);
  155. param = 0.2;
  156. glFogfv( GL_FOG_DENSITY, &param );
  157. param = g_Parm_3D_Visu.m_LayerZcoord[15];
  158. glFogfv( GL_FOG_END, &param );
  159. glBegin( GL_QUADS );
  160. SetGLColor( g_Parm_3D_Visu.m_BoardSettings->m_LayerColor[LAYER_N_FRONT] );
  161. double sx = DataScale3D * g_Parm_3D_Visu.m_BoardSize.x / 2;
  162. double sy = DataScale3D * g_Parm_3D_Visu.m_BoardSize.y / 2;
  163. double zpos = g_Parm_3D_Visu.m_LayerZcoord[15];
  164. glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
  165. sx = sy = 0.5;
  166. glVertex3f( -sx, -sy, zpos );
  167. glVertex3f( -sx, sy, zpos );
  168. glVertex3f( sx, sy, zpos );
  169. glVertex3f( sx, -sy, zpos );
  170. glEnd();
  171. glBegin( GL_QUADS );
  172. SetGLColor( g_Parm_3D_Visu.m_BoardSettings->m_LayerColor[LAYER_N_BACK] );
  173. glNormal3f( 0.0, 0.0, -1.0 ); // Normal is -Z axis
  174. glVertex3f( -sx, -sy, 0 );
  175. glVertex3f( -sx, sy, 0 );
  176. glVertex3f( sx, sy, 0 );
  177. glVertex3f( sx, -sy, 0 );
  178. glEnd();
  179. #endif
  180. /* move the board in order to draw it with its center at 0,0 3D
  181. * coordinates */
  182. glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BoardScale,
  183. -g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BoardScale,
  184. 0.0F );
  185. glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
  186. /* draw tracks and vias : */
  187. for( track = pcb->m_Track; track != NULL; track = track->Next() )
  188. {
  189. if( track->Type() == TYPE_VIA )
  190. Draw3D_Via( (SEGVIA*) track );
  191. else
  192. Draw3D_Track( track );
  193. }
  194. if( g_Parm_3D_Visu.m_Draw3DZone )
  195. {
  196. // Draw segments used to fill copper areas. outdated!
  197. for( segzone = pcb->m_Zone; segzone != NULL; segzone = segzone->Next() )
  198. {
  199. if( segzone->Type() == TYPE_ZONE )
  200. Draw3D_Track( segzone );
  201. }
  202. // Draw new segments
  203. for( ii = 0; ii < pcb->GetAreaCount(); ii++ )
  204. {
  205. ZONE_CONTAINER* curr_zone = pcb->GetArea( ii );
  206. if( curr_zone->m_FillMode == 0 )
  207. {
  208. // solid polygons only are used to fill areas
  209. if( curr_zone->m_FilledPolysList.size() > 3 )
  210. {
  211. Draw3D_SolidPolygonsInZones( curr_zone );
  212. }
  213. }
  214. else
  215. {
  216. // segments are used to fill areas
  217. for( unsigned iseg = 0; iseg < curr_zone->m_FillSegmList.size(); iseg++ )
  218. {
  219. SEGZONE dummysegment( pcb );
  220. dummysegment.SetLayer( curr_zone->GetLayer() );
  221. dummysegment.m_Width = curr_zone->m_ZoneMinThickness;
  222. dummysegment.m_Start.x = curr_zone->m_FillSegmList[iseg].m_Start.x;
  223. dummysegment.m_Start.y = curr_zone->m_FillSegmList[iseg].m_Start.y;
  224. dummysegment.m_End.x = curr_zone->m_FillSegmList[iseg].m_End.x;
  225. dummysegment.m_End.y = curr_zone->m_FillSegmList[iseg].m_End.y;
  226. Draw3D_Track( &dummysegment );
  227. }
  228. }
  229. }
  230. // Draw copper areas outlines
  231. for( ii = 0; ii < pcb->GetAreaCount(); ii++ )
  232. {
  233. ZONE_CONTAINER* zone = pcb->GetArea( ii );
  234. if( zone->m_FilledPolysList.size() == 0 )
  235. continue;
  236. if( zone->m_ZoneMinThickness <= 1 )
  237. continue;
  238. int imax = zone->m_FilledPolysList.size() - 1;
  239. CPolyPt* firstcorner = &zone->m_FilledPolysList[0];
  240. CPolyPt* begincorner = firstcorner;
  241. SEGZONE dummysegment( pcb );
  242. dummysegment.SetLayer( zone->GetLayer() );
  243. dummysegment.m_Width = zone->m_ZoneMinThickness;
  244. for( int ic = 1; ic <= imax; ic++ )
  245. {
  246. CPolyPt* endcorner = &zone->m_FilledPolysList[ic];
  247. if( begincorner->utility == 0 )
  248. {
  249. // Draw only basic outlines, not extra segments
  250. dummysegment.m_Start.x = begincorner->x;
  251. dummysegment.m_Start.y = begincorner->y;
  252. dummysegment.m_End.x = endcorner->x;
  253. dummysegment.m_End.y = endcorner->y;
  254. Draw3D_Track( &dummysegment );
  255. }
  256. if( (endcorner->end_contour) || (ic == imax) )
  257. {
  258. // the last corner of a filled area is found: draw it
  259. if( endcorner->utility == 0 )
  260. {
  261. // Draw only basic outlines, not extra segments
  262. dummysegment.m_Start.x = endcorner->x;
  263. dummysegment.m_Start.y = endcorner->y;
  264. dummysegment.m_End.x = firstcorner->x;
  265. dummysegment.m_End.y = firstcorner->y;
  266. Draw3D_Track( &dummysegment );
  267. }
  268. ic++;
  269. if( ic < imax - 1 )
  270. begincorner = firstcorner =
  271. &zone->m_FilledPolysList[ic];
  272. }
  273. else
  274. begincorner = endcorner;
  275. }
  276. }
  277. }
  278. /* draw graphic items */
  279. EDA_BaseStruct* PtStruct;
  280. for( PtStruct = pcb->m_Drawings;
  281. PtStruct != NULL;
  282. PtStruct = PtStruct->Next() )
  283. {
  284. switch( PtStruct->Type() )
  285. {
  286. case TYPE_DRAWSEGMENT:
  287. Draw3D_DrawSegment( (DRAWSEGMENT*) PtStruct );
  288. break;
  289. case TYPE_TEXTE:
  290. Draw3D_DrawText( (TEXTE_PCB*) PtStruct );
  291. break;
  292. default:
  293. break;
  294. }
  295. }
  296. /* draw footprints */
  297. MODULE* Module = pcb->m_Modules;
  298. for( ; Module != NULL; Module = Module->Next() )
  299. {
  300. Module->Draw3D( this );
  301. }
  302. glEndList();
  303. /* Test for errors */
  304. GLenum err = glGetError();
  305. if( err != GL_NO_ERROR )
  306. DisplayError( this, wxT( "Error in GL commands" ) );
  307. return m_gllist;
  308. }
  309. void Pcb3D_GLCanvas::Draw3D_Track( TRACK* track )
  310. {
  311. double zpos;
  312. int layer = track->GetLayer();
  313. double ox, oy, fx, fy;
  314. double w;
  315. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
  316. return;
  317. int color = g_ColorsSettings.GetLayerColor( layer );
  318. if( layer == LAST_COPPER_LAYER )
  319. layer = g_Parm_3D_Visu.m_Layers - 1;
  320. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  321. SetGLColor( color );
  322. glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  323. w = track->m_Width * g_Parm_3D_Visu.m_BoardScale;
  324. ox = track->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
  325. oy = track->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
  326. fx = track->m_End.x * g_Parm_3D_Visu.m_BoardScale;
  327. fy = track->m_End.y * g_Parm_3D_Visu.m_BoardScale;
  328. Draw3D_FilledSegment( ox, -oy, fx, -fy, w, zpos );
  329. }
  330. /** Function Draw3D_SolidPolygonsInZones
  331. * draw all solid polygons used as filles areas in a zone
  332. * @param aZone_c = the zone to draw
  333. */
  334. void Pcb3D_GLCanvas::Draw3D_SolidPolygonsInZones( ZONE_CONTAINER* zone_c )
  335. {
  336. double zpos;
  337. int layer = zone_c->GetLayer();
  338. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
  339. return;
  340. int color = g_ColorsSettings.GetLayerColor( layer );
  341. if( layer == LAST_COPPER_LAYER )
  342. layer = g_Parm_3D_Visu.m_Layers - 1;
  343. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  344. g_Parm_3D_Visu.m_ActZpos = zpos;
  345. SetGLColor( color );
  346. glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  347. GLUtesselator* tess = gluNewTess();
  348. gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*)() )tessBeginCB );
  349. gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*)() )tessEndCB );
  350. gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*)() )tessErrorCB );
  351. gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*)() )tessCPolyPt2Vertex );
  352. GLdouble v_data[3];
  353. v_data[2] = zpos;
  354. //gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
  355. // Draw solid areas contained in this zone
  356. int StartContour = 1;
  357. for( unsigned ii = 0; ii < zone_c->m_FilledPolysList.size(); ii++ )
  358. {
  359. if( StartContour == 1 )
  360. {
  361. gluTessBeginPolygon( tess, NULL );
  362. gluTessBeginContour( tess );
  363. StartContour = 0;
  364. }
  365. v_data[0] = zone_c->m_FilledPolysList[ii].x * g_Parm_3D_Visu.m_BoardScale;
  366. v_data[1] = -zone_c->m_FilledPolysList[ii].y * g_Parm_3D_Visu.m_BoardScale;
  367. gluTessVertex( tess, v_data, &zone_c->m_FilledPolysList[ii] );
  368. if( zone_c->m_FilledPolysList[ii].end_contour == 1 )
  369. {
  370. gluTessEndContour( tess );
  371. gluTessEndPolygon( tess );
  372. StartContour = 1;
  373. }
  374. }
  375. gluDeleteTess( tess );
  376. }
  377. /* 3D drawing for a VIA (cylinder + filled circles)
  378. */
  379. void Pcb3D_GLCanvas::Draw3D_Via( SEGVIA* via )
  380. {
  381. double x, y, r, hole;
  382. int layer, top_layer, bottom_layer;
  383. double zpos, height;
  384. int color;
  385. r = via->m_Width * g_Parm_3D_Visu.m_BoardScale / 2;
  386. hole = via->GetDrillValue();
  387. hole *= g_Parm_3D_Visu.m_BoardScale / 2;
  388. x = via->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
  389. y = via->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
  390. via->ReturnLayerPair( &top_layer, &bottom_layer );
  391. // Drawing filled circles:
  392. for( layer = bottom_layer; layer < g_Parm_3D_Visu.m_Layers; layer++ )
  393. {
  394. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  395. if( layer < g_Parm_3D_Visu.m_Layers - 1 )
  396. {
  397. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) ==
  398. false )
  399. continue;
  400. color = g_ColorsSettings.GetLayerColor( layer );
  401. }
  402. else
  403. {
  404. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( LAYER_N_FRONT ) ==
  405. false )
  406. continue;
  407. color = g_ColorsSettings.GetLayerColor( LAYER_N_FRONT );
  408. }
  409. SetGLColor( color );
  410. // SetGLColor( LIGHTGRAY );
  411. glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  412. if( layer == LAYER_N_BACK )
  413. zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
  414. else
  415. zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
  416. Draw3D_FilledCircle( x, -y, r, hole, zpos );
  417. if( layer >= top_layer )
  418. break;
  419. }
  420. // Drawing hole:
  421. color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + via->m_Shape );
  422. SetGLColor( color );
  423. height = g_Parm_3D_Visu.m_LayerZcoord[top_layer] -
  424. g_Parm_3D_Visu.m_LayerZcoord[bottom_layer];
  425. Draw3D_FilledCylinder( x, -y, hole, height,
  426. g_Parm_3D_Visu.m_LayerZcoord[bottom_layer] );
  427. }
  428. void Pcb3D_GLCanvas::Draw3D_DrawSegment( DRAWSEGMENT* segment )
  429. {
  430. double x, y, xf, yf;
  431. double zpos, w;
  432. int layer = segment->GetLayer();
  433. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
  434. return;
  435. int color = g_ColorsSettings.GetLayerColor( layer );
  436. SetGLColor( color );
  437. w = segment->m_Width * g_Parm_3D_Visu.m_BoardScale;
  438. x = segment->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
  439. y = segment->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
  440. xf = segment->m_End.x * g_Parm_3D_Visu.m_BoardScale;
  441. yf = segment->m_End.y * g_Parm_3D_Visu.m_BoardScale;
  442. if( layer == EDGE_N )
  443. {
  444. for( layer = 0; layer < g_Parm_3D_Visu.m_Layers; layer++ )
  445. {
  446. glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  447. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  448. switch( segment->m_Shape )
  449. {
  450. case S_ARC:
  451. Draw3D_ArcSegment( x, -y, xf, -yf, (double) segment->m_Angle, w, zpos );
  452. break;
  453. case S_CIRCLE:
  454. Draw3D_CircleSegment( x, -y, xf, -yf, w, zpos );
  455. break;
  456. default:
  457. Draw3D_FilledSegment( x, -y, xf, -yf, w, zpos );
  458. break;
  459. }
  460. }
  461. }
  462. else
  463. {
  464. glNormal3f( 0.0, 0.0, Get3DLayerSide( layer ) );
  465. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  466. if( Get3DLayerEnable( layer ) )
  467. {
  468. switch( segment->m_Shape )
  469. {
  470. case S_ARC:
  471. Draw3D_ArcSegment( x, -y, xf, -yf, (double) segment->m_Angle, w, zpos );
  472. break;
  473. case S_CIRCLE:
  474. Draw3D_CircleSegment( x, -y, xf, -yf, w, zpos );
  475. break;
  476. default:
  477. Draw3D_FilledSegment( x, -y, xf, -yf, w, zpos );
  478. break;
  479. }
  480. }
  481. }
  482. }
  483. /* function to draw 3D segments, called by DrawGraphicText
  484. * When DrawGraphicText is called to draw a text to an OpenGL DC
  485. * it calls Draw3dTextSegm to each segment to draw.
  486. * 2 parameters used by Draw3D_FilledSegment are not handled by DrawGraphicText
  487. * but are used in Draw3D_FilledSegment().
  488. * they are 2 local variables. This is an ugly, but trivial code.
  489. * Using DrawGraphicText to draw all texts ensure texts have the same shape
  490. * in all contexts
  491. */
  492. static double s_Text3DWidth, s_Text3DZPos;
  493. static void Draw3dTextSegm( int x0, int y0, int xf, int yf )
  494. {
  495. double startx = x0 * g_Parm_3D_Visu.m_BoardScale;
  496. double starty = y0 * g_Parm_3D_Visu.m_BoardScale;
  497. double endx = xf * g_Parm_3D_Visu.m_BoardScale;
  498. double endy = yf * g_Parm_3D_Visu.m_BoardScale;
  499. Draw3D_FilledSegment( startx, -starty, endx, -endy,
  500. s_Text3DWidth, s_Text3DZPos );
  501. }
  502. void Pcb3D_GLCanvas::Draw3D_DrawText( TEXTE_PCB* text )
  503. {
  504. int layer = text->GetLayer();
  505. if( !Get3DLayerEnable( layer ) )
  506. return;
  507. int color = g_ColorsSettings.GetLayerColor( layer );
  508. SetGLColor( color );
  509. s_Text3DZPos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  510. s_Text3DWidth = text->m_Width * g_Parm_3D_Visu.m_BoardScale;
  511. glNormal3f( 0.0, 0.0, Get3DLayerSide( layer ) );
  512. wxSize size = text->m_Size;
  513. if( text->m_Mirror )
  514. NEGATE( size.x );
  515. if( text->m_MultilineAllowed )
  516. {
  517. wxPoint pos = text->m_Pos;
  518. wxArrayString* list = wxStringSplit( text->m_Text, '\n' );
  519. wxPoint offset;
  520. offset.y = text->GetInterline();
  521. RotatePoint( &offset, text->m_Orient );
  522. for( unsigned i = 0; i<list->Count(); i++ )
  523. {
  524. wxString txt = list->Item( i );
  525. DrawGraphicText( NULL, NULL, pos, (EDA_Colors) color,
  526. txt, text->m_Orient, size,
  527. text->m_HJustify, text->m_VJustify,
  528. text->m_Width, text->m_Italic,
  529. true, Draw3dTextSegm );
  530. pos += offset;
  531. }
  532. delete (list);
  533. }
  534. else
  535. DrawGraphicText( NULL, NULL, text->m_Pos, (EDA_Colors) color,
  536. text->m_Text, text->m_Orient, size,
  537. text->m_HJustify, text->m_VJustify,
  538. text->m_Width, text->m_Italic,
  539. true,
  540. Draw3dTextSegm );
  541. }
  542. void MODULE::Draw3D( Pcb3D_GLCanvas* glcanvas )
  543. {
  544. D_PAD* pad = m_Pads;
  545. /* Draw pads */
  546. glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
  547. glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
  548. for( ; pad != NULL; pad = pad->Next() )
  549. {
  550. pad->Draw3D( glcanvas );
  551. }
  552. /* Draw module shape: 3D shape if exists (or module edge if not exists) */
  553. S3D_MASTER* Struct3D = m_3D_Drawings;
  554. bool As3dShape = FALSE;
  555. if( g_Parm_3D_Visu.m_Draw3DModule )
  556. {
  557. glPushMatrix();
  558. glTranslatef( m_Pos.x * g_Parm_3D_Visu.m_BoardScale,
  559. -m_Pos.y * g_Parm_3D_Visu.m_BoardScale,
  560. g_Parm_3D_Visu.m_LayerZcoord[m_Layer] );
  561. if( m_Orient )
  562. {
  563. glRotatef( (double) m_Orient / 10, 0.0, 0.0, 1.0 );
  564. }
  565. if( m_Layer == LAYER_N_BACK )
  566. {
  567. glRotatef( 180.0, 0.0, 1.0, 0.0 );
  568. glRotatef( 180.0, 0.0, 0.0, 1.0 );
  569. }
  570. DataScale3D = g_Parm_3D_Visu.m_BoardScale * UNITS3D_TO_UNITSPCB;
  571. for( ; Struct3D != NULL; Struct3D = Struct3D->Next() )
  572. {
  573. if( !Struct3D->m_Shape3DName.IsEmpty() )
  574. {
  575. As3dShape = TRUE;
  576. Struct3D->ReadData();
  577. }
  578. }
  579. glPopMatrix();
  580. }
  581. if( !As3dShape )
  582. {
  583. // The footprint does not have a 3D shape, draw its 2D shape instead
  584. EDA_BaseStruct* Struct = m_Drawings;
  585. glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
  586. for( ; Struct != NULL; Struct = Struct->Next() )
  587. {
  588. switch( Struct->Type() )
  589. {
  590. case TYPE_TEXTE_MODULE:
  591. break;
  592. case TYPE_EDGE_MODULE:
  593. ( (EDGE_MODULE*) Struct )->Draw3D( glcanvas );
  594. break;
  595. default:
  596. break;
  597. }
  598. }
  599. }
  600. }
  601. void EDGE_MODULE::Draw3D( Pcb3D_GLCanvas* glcanvas )
  602. {
  603. wxString s;
  604. int dx, dy;
  605. double x, y, fx, fy, w, zpos;
  606. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( m_Layer ) == false )
  607. return;
  608. int color = g_ColorsSettings.GetLayerColor( m_Layer );
  609. SetGLColor( color );
  610. glNormal3f( 0.0, 0.0, (m_Layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  611. dx = m_End.x;
  612. dy = m_End.y;
  613. zpos = g_Parm_3D_Visu.m_LayerZcoord[m_Layer];
  614. w = m_Width * g_Parm_3D_Visu.m_BoardScale;
  615. x = m_Start.x * g_Parm_3D_Visu.m_BoardScale;
  616. y = m_Start.y * g_Parm_3D_Visu.m_BoardScale;
  617. fx = dx * g_Parm_3D_Visu.m_BoardScale;
  618. fy = dy * g_Parm_3D_Visu.m_BoardScale;
  619. switch( m_Shape )
  620. {
  621. case S_SEGMENT:
  622. Draw3D_FilledSegment( x, -y, fx, -fy, w, zpos );
  623. break;
  624. case S_CIRCLE:
  625. Draw3D_CircleSegment( x, -y, fx, -fy, w, zpos );
  626. break;
  627. case S_ARC:
  628. Draw3D_ArcSegment( x, -y, fx, -fy, (double) m_Angle, w, zpos );
  629. break;
  630. case S_POLYGON:
  631. {
  632. // We must compute true coordinates from m_PolyPoints
  633. // which are relative to module position and module orientation = 0
  634. std::vector<wxPoint> points = m_PolyPoints;
  635. MODULE* module = (MODULE*) m_Parent;
  636. if( module == NULL )
  637. break;
  638. for( unsigned ii = 0; ii < points.size(); ii++ )
  639. {
  640. wxPoint& pt = points[ii];
  641. RotatePoint( &pt.x, &pt.y, module->m_Orient );
  642. pt += module->m_Pos;
  643. }
  644. glcanvas->Draw3D_Polygon( points, zpos );
  645. }
  646. break;
  647. default:
  648. s.Printf( wxT( "Error: Shape nr %d not implemented!\n" ), m_Shape );
  649. D( printf( "%s", CONV_TO_UTF8( s ) ); )
  650. break;
  651. }
  652. }
  653. /* Draw 3D pads. */
  654. void D_PAD::Draw3D( Pcb3D_GLCanvas* glcanvas )
  655. {
  656. int ii, ll, layer, nlmax;
  657. int ux0, uy0,
  658. dx, dx0, dy, dy0,
  659. delta_cx, delta_cy,
  660. xc, yc;
  661. int angle, delta_angle;
  662. int coord[4][2];
  663. double fcoord[8][2], f_hole_coord[8][2];
  664. double scale;
  665. double zpos;
  666. wxPoint shape_pos;
  667. double x, y, r, w, hole, holeX, holeY;
  668. double drillx, drilly;
  669. bool Oncu, Oncmp, Both;
  670. int color;
  671. scale = g_Parm_3D_Visu.m_BoardScale;
  672. holeX = (double) m_Drill.x * scale / 2;
  673. holeY = (double) m_Drill.y * scale / 2;
  674. hole = MIN( holeX, holeY );
  675. /* Calculate the center of the pad. */
  676. shape_pos = ReturnShapePos();
  677. ux0 = shape_pos.x;
  678. uy0 = shape_pos.y;
  679. xc = ux0;
  680. yc = uy0;
  681. dx = dx0 = m_Size.x >> 1;
  682. dy = dy0 = m_Size.y >> 1;
  683. angle = m_Orient;
  684. drillx = m_Pos.x * scale;
  685. drilly = m_Pos.y * scale;
  686. /* Draw the pad hole (TODO: draw OBLONG hole) */
  687. if( holeX && holeY )
  688. {
  689. SetGLColor( DARKGRAY );
  690. Draw3D_FilledCylinder( drillx, -drilly, hole,
  691. g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_FRONT], 0.0 );
  692. }
  693. glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
  694. nlmax = g_Parm_3D_Visu.m_Layers - 1;
  695. Oncu = (m_Masque_Layer & LAYER_BACK) ? TRUE : FALSE;
  696. Oncmp = (m_Masque_Layer & LAYER_FRONT) ? TRUE : FALSE;
  697. Both = Oncu && Oncmp;
  698. switch( m_PadShape & 0x7F )
  699. {
  700. case PAD_CIRCLE:
  701. x = xc * scale;
  702. y = yc * scale;
  703. r = (double) dx * scale;
  704. for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
  705. {
  706. if( layer && (layer == nlmax) )
  707. layer = LAYER_N_FRONT;
  708. if( (layer == LAYER_N_FRONT) && !Oncmp )
  709. continue;
  710. if( (layer == LAYER_N_BACK) && !Oncu )
  711. continue;
  712. if( (layer > FIRST_COPPER_LAYER) && (layer < LAST_COPPER_LAYER)
  713. && !Both )
  714. continue;
  715. color = g_ColorsSettings.GetLayerColor( layer );
  716. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) ==
  717. false )
  718. continue;
  719. SetGLColor( color );
  720. glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  721. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  722. if( layer == LAYER_N_BACK )
  723. zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
  724. else
  725. zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
  726. Draw3D_FilledCircle( x, -y, r, hole, zpos );
  727. }
  728. break;
  729. case PAD_OVAL:
  730. if( dx > dy ) /* Horizontal ellipse */
  731. {
  732. delta_cx = dx - dy;
  733. delta_cy = 0;
  734. w = m_Size.y * scale;
  735. delta_angle = angle + 900;
  736. }
  737. else /* Vertical ellipse */
  738. {
  739. delta_cx = 0;
  740. delta_cy = dy - dx;
  741. w = m_Size.x * scale;
  742. delta_angle = angle;
  743. }
  744. RotatePoint( &delta_cx, &delta_cy, angle );
  745. {
  746. double ox, oy, fx, fy;
  747. ox = (double) ( ux0 + delta_cx ) * scale;
  748. oy = (double) ( uy0 + delta_cy ) * scale;
  749. fx = (double) ( ux0 - delta_cx ) * scale;
  750. fy = (double) ( uy0 - delta_cy ) * scale;
  751. for( layer = FIRST_COPPER_LAYER;
  752. layer <= LAST_COPPER_LAYER;
  753. layer++ )
  754. {
  755. if( layer && (layer == nlmax) )
  756. layer = LAYER_N_FRONT;
  757. if( (layer == LAYER_N_FRONT) && !Oncmp )
  758. continue;
  759. if( (layer == LAYER_N_BACK) && !Oncu )
  760. continue;
  761. if( (layer > FIRST_COPPER_LAYER)
  762. && (layer < LAST_COPPER_LAYER) && !Both )
  763. continue;
  764. color = g_ColorsSettings.GetLayerColor( layer );
  765. glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  766. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) ==
  767. false )
  768. continue;
  769. SetGLColor( color );
  770. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  771. if( layer == LAYER_N_BACK )
  772. zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
  773. else
  774. zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
  775. Draw3D_FilledSegmentWithHole( ox, -oy, fx, -fy, w, drillx,
  776. -drilly, hole, zpos );
  777. }
  778. }
  779. break;
  780. case PAD_RECT:
  781. case PAD_TRAPEZOID:
  782. {
  783. int ddx, ddy;
  784. ddx = m_DeltaSize.x >> 1;
  785. ddy = m_DeltaSize.y >> 1;
  786. coord[0][0] = -dx - ddy;
  787. coord[0][1] = +dy + ddx;
  788. coord[1][0] = -dx + ddy;
  789. coord[1][1] = -dy - ddx;
  790. coord[2][0] = +dx - ddy;
  791. coord[2][1] = -dy + ddx;
  792. coord[3][0] = +dx + ddy;
  793. coord[3][1] = +dy - ddx;
  794. for( ii = 0; ii < 4; ii++ )
  795. {
  796. RotatePoint( &coord[ii][0], &coord[ii][1], angle );
  797. coord[ii][0] += ux0;
  798. coord[ii][1] += uy0;
  799. ll = ii * 2;
  800. fcoord[ll][0] = coord[ii][0] *scale;
  801. fcoord[ll][1] = coord[ii][1] *scale;
  802. }
  803. for( ii = 0; ii < 7; ii += 2 )
  804. {
  805. ll = ii + 2;
  806. if( ll > 7 )
  807. ll -= 8;
  808. fcoord[ii + 1][0] = (fcoord[ii][0] + fcoord[ll][0]) / 2;
  809. fcoord[ii + 1][1] = (fcoord[ii][1] + fcoord[ll][1]) / 2;
  810. }
  811. for( ii = 0; ii < 8; ii++ )
  812. {
  813. f_hole_coord[ii][0] = -hole * 0.707;
  814. f_hole_coord[ii][1] = hole * 0.707;
  815. RotatePoint( &f_hole_coord[ii][0], &f_hole_coord[ii][1],
  816. angle - (ii * 450) );
  817. f_hole_coord[ii][0] += drillx;
  818. f_hole_coord[ii][1] += drilly;
  819. }
  820. for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
  821. {
  822. if( layer && (layer == nlmax) )
  823. layer = LAYER_N_FRONT;
  824. if( (layer == LAYER_N_FRONT) && !Oncmp )
  825. continue;
  826. if( (layer == LAYER_N_BACK) && !Oncu )
  827. continue;
  828. if( (layer > FIRST_COPPER_LAYER) && (layer < LAST_COPPER_LAYER)
  829. && !Both )
  830. continue;
  831. color = g_ColorsSettings.GetLayerColor( layer );
  832. glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
  833. if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) ==
  834. false )
  835. continue;
  836. SetGLColor( color );
  837. zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
  838. if( layer == LAYER_N_BACK )
  839. zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
  840. else
  841. zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
  842. glBegin( GL_QUAD_STRIP );
  843. for( ii = 0; ii < 8; ii++ )
  844. {
  845. glVertex3f( f_hole_coord[ii][0], -f_hole_coord[ii][1], zpos );
  846. glVertex3f( fcoord[ii][0], -fcoord[ii][1], zpos );
  847. }
  848. glVertex3f( f_hole_coord[0][0], -f_hole_coord[0][1], zpos );
  849. glVertex3f( fcoord[0][0], -fcoord[0][1], zpos );
  850. glEnd();
  851. }
  852. }
  853. break;
  854. default:
  855. break;
  856. }
  857. }
  858. void SetGLColor( int color )
  859. {
  860. double red, green, blue;
  861. StructColors colordata = ColorRefs[color & MASKCOLOR];
  862. red = colordata.m_Red / 255.0;
  863. blue = colordata.m_Blue / 255.0;
  864. green = colordata.m_Green / 255.0;
  865. glColor3f( red, green, blue );
  866. }
  867. static void Draw3D_FilledCircle( double posx, double posy,
  868. double rayon, double hole, double zpos )
  869. {
  870. int ii, slice = 16;
  871. double x, y;
  872. glBegin( GL_QUAD_STRIP );
  873. for( ii = 0; ii <= slice; ii++ )
  874. {
  875. x = hole;
  876. y = 0.0;
  877. RotatePoint( &x, &y, ii * 225 );
  878. glVertex3f( x + posx, y + posy, zpos );
  879. x = rayon;
  880. y = 0.0;
  881. RotatePoint( &x, &y, ii * 225 );
  882. glVertex3f( x + posx, y + posy, zpos );
  883. }
  884. glEnd();
  885. }
  886. static void Draw3D_FilledCylinder( double posx, double posy, double rayon,
  887. double height, double zpos )
  888. {
  889. int ii;
  890. double x, y;
  891. #define NB_SEGM 12
  892. S3D_Vertex coords[4];
  893. double tmp = DataScale3D;
  894. DataScale3D = 1.0; // Coordinate is already in range for Set_Object_Data();
  895. coords[0].x = coords[1].x = posx + rayon;
  896. coords[0].y = coords[1].y = posy;
  897. coords[0].z = coords[3].z = zpos;
  898. coords[1].z = coords[2].z = zpos + height;
  899. for( ii = 0; ii <= NB_SEGM; ii++ )
  900. {
  901. x = rayon;
  902. y = 0.0;
  903. RotatePoint( &x, &y, ii * (3600 / NB_SEGM) );
  904. coords[2].x = coords[3].x = posx + x;
  905. coords[2].y = coords[3].y = posy + y;
  906. Set_Object_Data( coords, 4 );
  907. coords[0].x = coords[2].x;
  908. coords[0].y = coords[2].y;
  909. coords[1].x = coords[3].x;
  910. coords[1].y = coords[3].y;
  911. }
  912. glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
  913. DataScale3D = tmp;
  914. }
  915. /* Draw a polygon similar to a segment has rounded tips */
  916. static void Draw3D_FilledSegment( double startx, double starty, double endx,
  917. double endy, double width, double zpos )
  918. {
  919. double dx, dy, x, y, firstx = 0, firsty = 0;
  920. int ii, angle;
  921. // Calculate the coordinates of the segment assumed horizontal.
  922. // Then turn the strips of the desired angle.
  923. dx = endx - startx;
  924. dy = endy - starty;
  925. angle = (int) ( ( atan2( dy, dx ) * 1800 / M_PI ) + 0.5 );
  926. RotatePoint( &dx, &dy, angle );
  927. width /= 2;
  928. glBegin( GL_POLYGON );
  929. // Trace the flare to right (1st half polygon at the end of the segment)
  930. for( ii = 0; ii <= 8; ii++ )
  931. {
  932. x = 0.0;
  933. y = -width;
  934. RotatePoint( &x, &y, -ii * 225 );
  935. x += dx;
  936. RotatePoint( &x, &y, -angle );
  937. glVertex3f( startx + x, starty + y, zpos );
  938. if( ii == 0 )
  939. {
  940. firstx = startx + x;
  941. firsty = starty + y;
  942. }
  943. }
  944. // Rounding the left (2nd half polygon is the origin of the segment)
  945. for( ii = 0; ii <= 8; ii++ )
  946. {
  947. int jj = ii * 225;
  948. x = 0.0;
  949. y = width;
  950. RotatePoint( &x, &y, -angle - jj );
  951. glVertex3f( startx + x, starty + y, zpos );
  952. }
  953. glVertex3f( firstx, firsty, zpos );
  954. glEnd();
  955. }
  956. /* Draw a polygon similar to a segment ends with round hole
  957. */
  958. static void Draw3D_FilledSegmentWithHole( double startx, double starty,
  959. double endx, double endy,
  960. double width, double holex,
  961. double holey, double holeradius,
  962. double zpos )
  963. {
  964. double x, y, xin, yin;
  965. double firstx = 0, firsty = 0, firstxin = 0, firstyin = 0;
  966. int ii, angle, theta;
  967. // Calculate the coordinates of the segment assumed horizontal
  968. // Then turn the strips of the desired angle
  969. // All calculations are done with startx, starty as the origin of the route
  970. endx -= startx;
  971. endy -= starty;
  972. holex -= startx;
  973. holey -= starty;
  974. angle = (int) ( ( atan2( endy, endx ) * 1800 / M_PI ) + 0.5 );
  975. RotatePoint( &endx, &endy, angle );
  976. RotatePoint( &holex, &holey, angle );
  977. width /= 2;
  978. glBegin( GL_QUAD_STRIP );
  979. // Path of the flare to right (1st half polygon at the end of the segment)
  980. // around the half-hole drilling
  981. for( ii = 0; ii <= 8; ii++ )
  982. {
  983. x = 0.0;
  984. y = -width;
  985. xin = 0.0;
  986. yin = -holeradius;
  987. theta = -ii * 225;
  988. RotatePoint( &x, &y, theta );
  989. RotatePoint( &xin, &yin, theta );
  990. x += endx;
  991. RotatePoint( &x, &y, -angle );
  992. xin += holex;
  993. RotatePoint( &xin, &yin, -angle );
  994. glVertex3f( startx + xin, starty + yin, zpos );
  995. glVertex3f( startx + x, starty + y, zpos );
  996. if( ii == 0 )
  997. {
  998. firstx = startx + x;
  999. firsty = starty + y;
  1000. firstxin = startx + xin;
  1001. firstyin = starty + yin;
  1002. }
  1003. }
  1004. // Layout of the rounded left (2nd half polygon is the origin of the
  1005. // segment)
  1006. for( ii = 0; ii <= 8; ii++ )
  1007. {
  1008. theta = -ii * 225;
  1009. x = 0.0;
  1010. y = width;
  1011. RotatePoint( &x, &y, -angle + theta );
  1012. xin = 0.0;
  1013. yin = holeradius;
  1014. RotatePoint( &xin, &yin, theta );
  1015. xin += holex;
  1016. RotatePoint( &xin, &yin, -angle );
  1017. glVertex3f( startx + xin, starty + yin, zpos );
  1018. glVertex3f( startx + x, starty + y, zpos );
  1019. }
  1020. glVertex3f( firstxin, firstyin, zpos );
  1021. glVertex3f( firstx, firsty, zpos );
  1022. glEnd();
  1023. }
  1024. static void Draw3D_ArcSegment( double startx, double starty, double centrex,
  1025. double centrey, double arc_angle, double width, double zpos )
  1026. {
  1027. int ii;
  1028. int slice = 36; // Number of segments to approximate a circle by segments
  1029. double hole, rayon;
  1030. double arcStart_Angle;
  1031. arcStart_Angle = (atan2( startx - centrex, starty - centrey ) * 1800 / M_PI );
  1032. rayon = hypot( startx - centrex, starty - centrey ) + ( width / 2);
  1033. hole = rayon - width;
  1034. // Calculate the number of segments to approximate this arc
  1035. int imax = (int) ( (double) arc_angle * slice / 3600.0 );
  1036. if( imax < 0 )
  1037. imax = -imax;
  1038. if( imax == 0 )
  1039. imax = 1;
  1040. // Adjust delta_angle to have exactly imax segments in arc_angle
  1041. // i.e. arc_angle = imax delta_agnle.
  1042. double delta_angle = (double) arc_angle / imax;
  1043. glBegin( GL_QUAD_STRIP );
  1044. for( ii = 0; ii <= imax; ii++ )
  1045. {
  1046. double angle = (double) ii * delta_angle;
  1047. angle += arcStart_Angle + 900;
  1048. double dx = hole;
  1049. double dy = 0.0;
  1050. RotatePoint( &dx, &dy, (int) angle );
  1051. glVertex3f( dx + startx, dy + starty, zpos );
  1052. dx = rayon;
  1053. dy = 0.0;
  1054. RotatePoint( &dx, &dy, (int) angle );
  1055. glVertex3f( dx + startx, dy + starty, zpos );
  1056. }
  1057. glEnd();
  1058. }
  1059. static void Draw3D_CircleSegment( double startx, double starty, double endx,
  1060. double endy, double width, double zpos )
  1061. {
  1062. int ii, slice = 36;
  1063. double x, y, hole, rayon;
  1064. rayon = hypot( startx - endx, starty - endy ) + ( width / 2);
  1065. hole = rayon - width;
  1066. glBegin( GL_QUAD_STRIP );
  1067. for( ii = 0; ii <= slice; ii++ )
  1068. {
  1069. x = hole; y = 0.0;
  1070. RotatePoint( &x, &y, ii * 3600 / slice );
  1071. glVertex3f( x + startx, y + starty, zpos );
  1072. x = rayon; y = 0.0;
  1073. RotatePoint( &x, &y, ii * 3600 / slice );
  1074. glVertex3f( x + startx, y + starty, zpos );
  1075. }
  1076. glEnd();
  1077. }
  1078. /** Function Pcb3D_GLCanvas::Draw3D_Polygon
  1079. * draw one solid polygon
  1080. * @param aCornersList = a std::vector<wxPoint> liste of corners, in physical coordinates
  1081. * @param aZpos = the z position in 3D units
  1082. */
  1083. void Pcb3D_GLCanvas::Draw3D_Polygon( std::vector<wxPoint>& aCornersList, double aZpos )
  1084. {
  1085. g_Parm_3D_Visu.m_ActZpos = aZpos;
  1086. GLUtesselator* tess = gluNewTess();
  1087. gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*)() )tessBeginCB );
  1088. gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*)() )tessEndCB );
  1089. gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*)() )tessErrorCB );
  1090. gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*)() )tesswxPoint2Vertex );
  1091. GLdouble v_data[3];
  1092. v_data[2] = aZpos;
  1093. //gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
  1094. // Draw solid polygon
  1095. gluTessBeginPolygon( tess, NULL );
  1096. gluTessBeginContour( tess );
  1097. for( unsigned ii = 0; ii < aCornersList.size(); ii++ )
  1098. {
  1099. v_data[0] = aCornersList[ii].x * g_Parm_3D_Visu.m_BoardScale;
  1100. v_data[1] = -aCornersList[ii].y * g_Parm_3D_Visu.m_BoardScale;
  1101. // gluTessVertex store pointers on data, not data, so do not store
  1102. // different corners values in a temporary variable
  1103. // but send pointer on each corner value in aCornersList
  1104. gluTessVertex( tess, v_data, &aCornersList[ii] );
  1105. }
  1106. gluTessEndContour( tess );
  1107. gluTessEndPolygon( tess );
  1108. gluDeleteTess( tess );
  1109. }
  1110. static int Get3DLayerEnable( int act_layer )
  1111. {
  1112. bool enablelayer;
  1113. enablelayer = TRUE;
  1114. if( act_layer == DRAW_N && !g_Parm_3D_Visu.m_Draw3DDrawings )
  1115. enablelayer = FALSE;
  1116. if( act_layer == COMMENT_N && !g_Parm_3D_Visu.m_Draw3DComments )
  1117. enablelayer = FALSE;
  1118. if( act_layer == ECO1_N && !g_Parm_3D_Visu.m_Draw3DEco1 )
  1119. enablelayer = FALSE;
  1120. if( act_layer == ECO2_N && !g_Parm_3D_Visu.m_Draw3DEco2 )
  1121. enablelayer = FALSE;
  1122. return enablelayer;
  1123. }
  1124. static GLfloat Get3DLayerSide( int act_layer )
  1125. {
  1126. GLfloat nZ;
  1127. nZ = 1.0;
  1128. if( ( act_layer <= LAST_COPPER_LAYER - 1 )
  1129. || ( act_layer == ADHESIVE_N_BACK )
  1130. || ( act_layer == SOLDERPASTE_N_BACK )
  1131. || ( act_layer == SILKSCREEN_N_BACK )
  1132. || ( act_layer == SOLDERMASK_N_BACK ) )
  1133. nZ = -1.0;
  1134. return nZ;
  1135. }
  1136. ///////////////////////////////////////////////////////////////////////////////
  1137. // GLU_TESS CALLBACKS
  1138. ///////////////////////////////////////////////////////////////////////////////
  1139. void CALLBACK tessBeginCB( GLenum which )
  1140. {
  1141. glBegin( which );
  1142. }
  1143. void CALLBACK tessEndCB()
  1144. {
  1145. glEnd();
  1146. }
  1147. void CALLBACK tessCPolyPt2Vertex( const GLvoid* data )
  1148. {
  1149. // cast back to double type
  1150. const CPolyPt* ptr = (const CPolyPt*) data;
  1151. glVertex3f( ptr->x * g_Parm_3D_Visu.m_BoardScale,
  1152. -ptr->y * g_Parm_3D_Visu.m_BoardScale,
  1153. g_Parm_3D_Visu.m_ActZpos );
  1154. }
  1155. void CALLBACK tesswxPoint2Vertex( const GLvoid* data )
  1156. {
  1157. const wxPoint* ptr = (const wxPoint*) data;
  1158. glVertex3f( ptr->x * g_Parm_3D_Visu.m_BoardScale,
  1159. -ptr->y * g_Parm_3D_Visu.m_BoardScale,
  1160. g_Parm_3D_Visu.m_ActZpos );
  1161. }
  1162. void CALLBACK tessErrorCB( GLenum errorCode )
  1163. {
  1164. const GLubyte* errorStr;
  1165. errorStr = gluErrorString( errorCode );
  1166. // DEBUG //
  1167. D( printf( "Tess ERROR: %s\n", errorStr ); )
  1168. }