KiCad PCB EDA Suite
render_3d_legacy.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <gal/opengl/kiglew.h> // Must be included first
26 
27 #include "render_3d_legacy.h"
28 #include "ogl_legacy_utils.h"
29 #include "common_ogl/ogl_utils.h"
30 #include <footprint.h>
31 #include <3d_math.h>
32 #include <math/util.h> // for KiROUND
33 #include <wx/log.h>
34 
35 #include <base_units.h>
36 
40 #define UNITS3D_TO_UNITSPCB (IU_PER_MM)
41 
43  RENDER_3D_BASE( aCanvas, aAdapter, aCamera )
44 {
45  wxLogTrace( m_logTrace, wxT( "RENDER_3D_LEGACY::RENDER_3D_LEGACY" ) );
46 
47  m_layers.clear();
48  m_outerLayerHoles.clear();
49  m_innerLayerHoles.clear();
50  m_triangles.clear();
51  m_board = nullptr;
52  m_antiBoard = nullptr;
53 
54  m_platedPadsFront = nullptr;
55  m_platedPadsBack = nullptr;
56 
57  m_outerThroughHoles = nullptr;
58  m_outerThroughHoleRings = nullptr;
59  m_outerViaThroughHoles = nullptr;
60  m_vias = nullptr;
61  m_padHoles = nullptr;
62 
63  m_circleTexture = 0;
64  m_grid = 0;
66  m_currentRollOverItem = nullptr;
67  m_boardWithHoles = nullptr;
68 
69  m_3dModelMap.clear();
70 }
71 
72 
74 {
75  wxLogTrace( m_logTrace, wxT( "RENDER_3D_LEGACY::~RENDER_3D_LEGACY" ) );
76 
77  freeAllLists();
78 
79  glDeleteTextures( 1, &m_circleTexture );
80 }
81 
82 
84 {
85  return 50; // ms
86 }
87 
88 
89 void RENDER_3D_LEGACY::SetCurWindowSize( const wxSize& aSize )
90 {
91  if( m_windowSize != aSize )
92  {
93  m_windowSize = aSize;
94  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
95 
96  // Initialize here any screen dependent data here
97  }
98 }
99 
100 
102 {
103  if( enabled )
104  glEnable( GL_LIGHT0 );
105  else
106  glDisable( GL_LIGHT0 );
107 }
108 
109 
110 void RENDER_3D_LEGACY::setLightTop( bool enabled )
111 {
112  if( enabled )
113  glEnable( GL_LIGHT1 );
114  else
115  glDisable( GL_LIGHT1 );
116 }
117 
118 
120 {
121  if( enabled )
122  glEnable( GL_LIGHT2 );
123  else
124  glDisable( GL_LIGHT2 );
125 }
126 
127 
129 {
130  const float arrow_size = RANGE_SCALE_3D * 0.30f;
131 
132  glDisable( GL_CULL_FACE );
133 
134  // YxY squared view port, this is on propose
135  glViewport( 4, 4, m_windowSize.y / 8 , m_windowSize.y / 8 );
136  glClear( GL_DEPTH_BUFFER_BIT );
137 
138  glMatrixMode( GL_PROJECTION );
139  glLoadIdentity();
140  gluPerspective( 45.0f, 1.0f, 0.001f, RANGE_SCALE_3D );
141 
142  glMatrixMode( GL_MODELVIEW );
143  glLoadIdentity();
144 
145  const glm::mat4 TranslationMatrix =
146  glm::translate( glm::mat4( 1.0f ), SFVEC3F( 0.0f, 0.0f, -( arrow_size * 2.75f ) ) );
147 
148  const glm::mat4 ViewMatrix = TranslationMatrix * m_camera.GetRotationMatrix();
149 
150  glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
151 
153 
154  glColor3f( 0.9f, 0.0f, 0.0f );
155  DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( arrow_size, 0.0f, 0.0f ), 0.275f );
156 
157  glColor3f( 0.0f, 0.9f, 0.0f );
158  DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, arrow_size, 0.0f ), 0.275f );
159 
160  glColor3f( 0.0f, 0.0f, 0.9f );
161  DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, 0.0f, arrow_size ), 0.275f );
162 
163  glEnable( GL_CULL_FACE );
164 }
165 
166 
168 {
169  m_materials = {};
170 
172  {
173  // http://devernay.free.fr/cours/opengl/materials.html
174 
175  // Plated copper
176  // Copper material mixed with the copper color
177  m_materials.m_Copper.m_Ambient = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.1f,
178  m_boardAdapter.m_CopperColor.g * 0.1f,
179  m_boardAdapter.m_CopperColor.b * 0.1f);
180 
181  m_materials.m_Copper.m_Specular = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.75f + 0.25f,
182  m_boardAdapter.m_CopperColor.g * 0.75f + 0.25f,
183  m_boardAdapter.m_CopperColor.b * 0.75f + 0.25f );
184 
185  // This guess the material type(ex: copper vs gold) to determine the
186  // shininess factor between 0.1 and 0.4
187  float shininessfactor = 0.40f - mapf( fabs( m_boardAdapter.m_CopperColor.r -
189  0.15f, 1.00f,
190  0.00f, 0.30f );
191 
192  m_materials.m_Copper.m_Shininess = shininessfactor * 128.0f;
193  m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
194 
195 
196  // Non plated copper (raw copper)
197  m_materials.m_NonPlatedCopper.m_Ambient = SFVEC3F( 0.191f, 0.073f, 0.022f );
198  m_materials.m_NonPlatedCopper.m_Diffuse = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f,
199  50.0f / 255.0f );
200  m_materials.m_NonPlatedCopper.m_Specular = SFVEC3F( 0.256f, 0.137f, 0.086f );
201  m_materials.m_NonPlatedCopper.m_Shininess = 0.1f * 128.0f;
202  m_materials.m_NonPlatedCopper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
203 
204  // Paste material mixed with paste color
205  m_materials.m_Paste.m_Ambient = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r,
208 
209  m_materials.m_Paste.m_Specular = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r *
215 
216  m_materials.m_Paste.m_Shininess = 0.1f * 128.0f;
217  m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
218 
219  // Silk screen material mixed with silk screen color
220  m_materials.m_SilkSTop.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorTop.r,
223 
224  m_materials.m_SilkSTop.m_Specular = SFVEC3F(
226  0.10f,
228  0.10f,
230  0.10f );
231 
232  m_materials.m_SilkSTop.m_Shininess = 0.078125f * 128.0f;
233  m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
234 
235  // Silk screen material mixed with silk screen color
236  m_materials.m_SilkSBot.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorBot.r,
239 
240  m_materials.m_SilkSBot.m_Specular = SFVEC3F(
242  0.10f,
244  0.10f,
246  0.10f );
247 
248  m_materials.m_SilkSBot.m_Shininess = 0.078125f * 128.0f;
249  m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
250 
251  m_materials.m_SolderMask.m_Shininess = 0.8f * 128.0f;
252  m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
253 
254  // Epoxy material
255  m_materials.m_EpoxyBoard.m_Ambient = SFVEC3F( 117.0f / 255.0f, 97.0f / 255.0f,
256  47.0f / 255.0f );
257 
258  m_materials.m_EpoxyBoard.m_Specular = SFVEC3F( 18.0f / 255.0f, 3.0f / 255.0f,
259  20.0f / 255.0f );
260 
261  m_materials.m_EpoxyBoard.m_Shininess = 0.1f * 128.0f;
262  m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
263  }
264  else // Technical Mode
265  {
266  const SFVEC3F matAmbientColor = SFVEC3F( 0.10f );
267  const SFVEC3F matSpecularColor = SFVEC3F( 0.10f );
268  const float matShininess = 0.1f * 128.0f;
269 
270  // Copper material
271  m_materials.m_Copper.m_Ambient = matAmbientColor;
272  m_materials.m_Copper.m_Specular = matSpecularColor;
273  m_materials.m_Copper.m_Shininess = matShininess;
274  m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
275 
276  // Paste material
277  m_materials.m_Paste.m_Ambient = matAmbientColor;
278  m_materials.m_Paste.m_Specular = matSpecularColor;
279  m_materials.m_Paste.m_Shininess = matShininess;
280  m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
281 
282  // Silk screen material
283  m_materials.m_SilkSTop.m_Ambient = matAmbientColor;
284  m_materials.m_SilkSTop.m_Specular = matSpecularColor;
285  m_materials.m_SilkSTop.m_Shininess = matShininess;
286  m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
287 
288  // Silk screen material
289  m_materials.m_SilkSBot.m_Ambient = matAmbientColor;
290  m_materials.m_SilkSBot.m_Specular = matSpecularColor;
291  m_materials.m_SilkSBot.m_Shininess = matShininess;
292  m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
293 
294  // Solder mask material
295  m_materials.m_SolderMask.m_Ambient = matAmbientColor;
296  m_materials.m_SolderMask.m_Specular = matSpecularColor;
297  m_materials.m_SolderMask.m_Shininess = matShininess;
298  m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
299 
300  // Epoxy material
301  m_materials.m_EpoxyBoard.m_Ambient = matAmbientColor;
302  m_materials.m_EpoxyBoard.m_Specular = matSpecularColor;
303  m_materials.m_EpoxyBoard.m_Shininess = matShininess;
304  m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
305 
306  // Gray material (used for example in technical vias and pad holes)
307  m_materials.m_GrayMaterial.m_Ambient = SFVEC3F( 0.8f, 0.8f, 0.8f );
308  m_materials.m_GrayMaterial.m_Diffuse = SFVEC3F( 0.3f, 0.3f, 0.3f );
309  m_materials.m_GrayMaterial.m_Specular = SFVEC3F( 0.4f, 0.4f, 0.4f );
310  m_materials.m_GrayMaterial.m_Shininess = 0.01f * 128.0f;
311  m_materials.m_GrayMaterial.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
312  }
313 }
314 
315 
317 {
318  switch( aLayerID )
319  {
320  case F_Mask:
321  case B_Mask:
322  {
323  const SFVEC4F layerColor = getLayerColor( aLayerID );
324 
325  m_materials.m_SolderMask.m_Diffuse = layerColor;
326 
327  // Convert Opacity to Transparency
328  m_materials.m_SolderMask.m_Transparency = 1.0f - layerColor.a;
329 
331  {
332  m_materials.m_SolderMask.m_Ambient = m_materials.m_SolderMask.m_Diffuse * 0.3f;
333 
334  m_materials.m_SolderMask.m_Specular =
335  m_materials.m_SolderMask.m_Diffuse * m_materials.m_SolderMask.m_Diffuse;
336  }
337 
338  OglSetMaterial( m_materials.m_SolderMask, 1.0f );
339  break;
340  }
341 
342  case B_Paste:
343  case F_Paste:
344  m_materials.m_Paste.m_Diffuse = getLayerColor( aLayerID );
345  OglSetMaterial( m_materials.m_Paste, 1.0f );
346  break;
347 
348  case B_SilkS:
349  m_materials.m_SilkSBot.m_Diffuse = getLayerColor( aLayerID );
350  OglSetMaterial( m_materials.m_SilkSBot, 1.0f );
351  break;
352 
353  case F_SilkS:
354  m_materials.m_SilkSTop.m_Diffuse = getLayerColor( aLayerID );
355  OglSetMaterial( m_materials.m_SilkSTop, 1.0f );
356  break;
357 
358  case B_Adhes:
359  case F_Adhes:
360  case Dwgs_User:
361  case Cmts_User:
362  case Eco1_User:
363  case Eco2_User:
364  case Edge_Cuts:
365  case Margin:
366  case B_CrtYd:
367  case F_CrtYd:
368  case B_Fab:
369  case F_Fab:
370  m_materials.m_Plastic.m_Diffuse = getLayerColor( aLayerID );
371 
372  m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
373  m_materials.m_Plastic.m_Diffuse.g * 0.05f,
374  m_materials.m_Plastic.m_Diffuse.b * 0.05f );
375 
376  m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
377  m_materials.m_Plastic.m_Diffuse.g * 0.7f,
378  m_materials.m_Plastic.m_Diffuse.b * 0.7f );
379 
380  m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
381  m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
382  OglSetMaterial( m_materials.m_Plastic, 1.0f );
383  break;
384 
385  default:
386  m_materials.m_Copper.m_Diffuse = getLayerColor( aLayerID );
387  OglSetMaterial( m_materials.m_Copper, 1.0f );
388  break;
389  }
390 }
391 
392 
394 {
395  SFVEC4F layerColor = m_boardAdapter.GetLayerColor( aLayerID );
396 
398  {
399  switch( aLayerID )
400  {
401  case B_Adhes:
402  case F_Adhes:
403  break;
404 
405  case B_Mask:
407  break;
408  case F_Mask:
410  break;
411 
412  case B_Paste:
413  case F_Paste:
414  layerColor = m_boardAdapter.m_SolderPasteColor;
415  break;
416 
417  case B_SilkS:
419  break;
420  case F_SilkS:
422  break;
423 
424  case Dwgs_User:
425  case Cmts_User:
426  case Eco1_User:
427  case Eco2_User:
428  case Edge_Cuts:
429  case Margin:
430  break;
431 
432  case B_CrtYd:
433  case F_CrtYd:
434  break;
435 
436  case B_Fab:
437  case F_Fab:
438  break;
439 
440  default:
441  layerColor = m_boardAdapter.m_CopperColor;
442  break;
443  }
444  }
445 
446  return layerColor;
447 }
448 
449 
450 void init_lights( void )
451 {
452  // Setup light
453  // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
454  const GLfloat ambient[] = { 0.084f, 0.084f, 0.084f, 1.0f };
455  const GLfloat diffuse0[] = { 0.3f, 0.3f, 0.3f, 1.0f };
456  const GLfloat specular0[] = { 0.5f, 0.5f, 0.5f, 1.0f };
457 
458  glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
459  glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse0 );
460  glLightfv( GL_LIGHT0, GL_SPECULAR, specular0 );
461 
462  const GLfloat diffuse12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
463  const GLfloat specular12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
464 
465  // defines a directional light that points along the negative z-axis
466  GLfloat position[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
467 
468  // This makes a vector slight not perpendicular with XZ plane
469  const SFVEC3F vectorLight = SphericalToCartesian( glm::pi<float>() * 0.03f,
470  glm::pi<float>() * 0.25f );
471 
472  position[0] = vectorLight.x;
473  position[1] = vectorLight.y;
474  position[2] = vectorLight.z;
475 
476  glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
477  glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse12 );
478  glLightfv( GL_LIGHT1, GL_SPECULAR, specular12 );
479  glLightfv( GL_LIGHT1, GL_POSITION, position );
480 
481  // defines a directional light that points along the positive z-axis
482  position[2] = -position[2];
483 
484  glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
485  glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse12 );
486  glLightfv( GL_LIGHT2, GL_SPECULAR, specular12 );
487  glLightfv( GL_LIGHT2, GL_POSITION, position );
488 
489  const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
490 
491  glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
492 
493  glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
494 }
495 
496 
498 {
499  OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
500 }
501 
502 
504 {
505  glEnable( GL_POLYGON_OFFSET_FILL );
506  glPolygonOffset(-0.1f, -2.0f );
507  setLayerMaterial( aLayer_id );
508 }
509 
510 
512 {
513  glDisable( GL_POLYGON_OFFSET_FILL );
514 }
515 
516 
517 void RENDER_3D_LEGACY::renderBoardBody( bool aSkipRenderHoles )
518 {
519  m_materials.m_EpoxyBoard.m_Diffuse = m_boardAdapter.m_BoardBodyColor;
520 
521  // opacity to transparency
522  m_materials.m_EpoxyBoard.m_Transparency = 1.0f - m_boardAdapter.m_BoardBodyColor.a;
523 
524  OglSetMaterial( m_materials.m_EpoxyBoard, 1.0f );
525 
526  OPENGL_RENDER_LIST* ogl_disp_list = nullptr;
527 
528  if( aSkipRenderHoles )
529  ogl_disp_list = m_board;
530  else
531  ogl_disp_list = m_boardWithHoles;
532 
533  if( ogl_disp_list )
534  {
535  ogl_disp_list->ApplyScalePosition( -m_boardAdapter.GetEpoxyThickness() / 2.0f,
537 
538  ogl_disp_list->SetItIsTransparent( true );
539 
540  ogl_disp_list->DrawAll();
541  }
542 }
543 
544 
545 bool RENDER_3D_LEGACY::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
546  REPORTER* aWarningReporter )
547 {
548  // Initialize OpenGL
550  {
551  if( !initializeOpenGL() )
552  return false;
553  }
554 
555  if( m_reloadRequested )
556  {
557  std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
558 
559  if( aStatusReporter )
560  aStatusReporter->Report( _( "Loading..." ) );
561 
562  reload( aStatusReporter, aWarningReporter );
563 
564  // generate a new 3D grid as the size of the board may had changed
567  }
568  else
569  {
570  // Check if grid was changed
572  {
573  // and generate a new one
576  }
577  }
578 
579  setupMaterials();
580 
581  // Initial setup
582  glDepthFunc( GL_LESS );
583  glEnable( GL_CULL_FACE );
584  glFrontFace( GL_CCW ); // This is the OpenGL default
585  glEnable( GL_NORMALIZE ); // This allow OpenGL to normalize the normals after transformations
586  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
587 
589  glDisable( GL_MULTISAMPLE );
590  else
591  glEnable( GL_MULTISAMPLE );
592 
593  // clear color and depth buffers
594  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
595  glClearDepth( 1.0f );
596  glClearStencil( 0x00 );
597  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
598 
600 
601  // Draw the background ( rectangle with color gradient)
604 
605  glEnable( GL_DEPTH_TEST );
606 
607  // Set projection and modelview matrixes
608  glMatrixMode( GL_PROJECTION );
609  glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
610  glMatrixMode( GL_MODELVIEW );
611  glLoadIdentity();
612  glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
613 
614  // Position the headlight
615  setLightFront( true );
616  setLightTop( true );
617  setLightBottom( true );
618 
619  glEnable( GL_LIGHTING );
620 
621  {
622  const SFVEC3F& cameraPos = m_camera.GetPos();
623 
624  // Place the light at a minimum Z so the diffuse factor will not drop
625  // and the board will still look with good light.
626  float zpos;
627 
628  if( cameraPos.z > 0.0f )
629  {
630  zpos = glm::max( cameraPos.z, 0.5f ) + cameraPos.z * cameraPos.z;
631  }
632  else
633  {
634  zpos = glm::min( cameraPos.z,-0.5f ) - cameraPos.z * cameraPos.z;
635  }
636 
637  // This is a point light.
638  const GLfloat headlight_pos[] = { cameraPos.x, cameraPos.y, zpos, 1.0f };
639 
640  glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
641  }
642 
643  const bool drawMiddleSegments = !( aIsMoving &&
645 
646  const bool skipRenderHoles = aIsMoving &&
648 
649  const bool skipRenderVias = aIsMoving &&
651 
653  {
654  // Draw vias and pad holes with copper material
656  }
657  else
658  {
659  OglSetMaterial( m_materials.m_GrayMaterial, 1.0f );
660  }
661 
662  if( !( skipRenderVias || skipRenderHoles ) && m_vias )
663  m_vias->DrawAll();
664 
665  if( !skipRenderHoles && m_padHoles )
666  m_padHoles->DrawAll();
667 
668  // Display copper and tech layers
669  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
670  {
671  const PCB_LAYER_ID layer_id = ( PCB_LAYER_ID )( ii->first );
672 
673  // Mask layers are not processed here because they are a special case
674  if( ( layer_id == B_Mask ) || ( layer_id == F_Mask ) )
675  continue;
676 
677  // Do not show inner layers when it is displaying the board and board body is opaque
678  // enough: the time to create inner layers can be *really significant*.
679  // So avoid creating them is they are not very visible
680  const double opacity_min = 0.8;
681 
683  ( m_boardAdapter.m_BoardBodyColor.a > opacity_min ) )
684  {
685  if( ( layer_id > F_Cu ) && ( layer_id < B_Cu ) )
686  continue;
687  }
688 
689  glPushMatrix();
690 
691  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
692 
693  if( ( layer_id >= F_Cu ) && ( layer_id <= B_Cu ) )
694  {
698  setLayerMaterial( layer_id );
699  else
701 
702  if( skipRenderHoles )
703  {
704  pLayerDispList->DrawAllCameraCulled( m_camera.GetPos().z, drawMiddleSegments );
705 
706  // Draw copper plated pads
707  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
709  setPlatedCopperAndDepthOffset( layer_id );
710 
711  if( layer_id == F_Cu && m_platedPadsFront )
712  {
714  drawMiddleSegments );
715  }
716  else if( layer_id == B_Cu && m_platedPadsBack )
717  {
719  drawMiddleSegments );
720  }
721 
723  }
724  else
725  {
726  if( m_outerThroughHoles )
727  {
728  m_outerThroughHoles->ApplyScalePosition( pLayerDispList->GetZBot(),
729  pLayerDispList->GetZTop()
730  - pLayerDispList->GetZBot() );
731  }
732 
733  if( m_antiBoard )
734  {
735  m_antiBoard->ApplyScalePosition( pLayerDispList->GetZBot(),
736  pLayerDispList->GetZTop()
737  - pLayerDispList->GetZBot() );
738  }
739 
740  if( m_outerLayerHoles.find( layer_id ) != m_outerLayerHoles.end() )
741  {
742  const OPENGL_RENDER_LIST* viasHolesLayer = m_outerLayerHoles.at( layer_id );
743 
744  wxASSERT( viasHolesLayer != nullptr );
745 
746  if( viasHolesLayer != nullptr )
747  {
748  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
750  viasHolesLayer,
751  m_antiBoard );
752 
753  // Draw copper plated pads
754 
755  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
757  {
758  setPlatedCopperAndDepthOffset( layer_id );
759  }
760 
761  if( layer_id == F_Cu && m_platedPadsFront )
762  {
764  drawMiddleSegments,
766  viasHolesLayer,
767  m_antiBoard );
768  }
769  else if( layer_id == B_Cu && m_platedPadsBack )
770  {
772  drawMiddleSegments,
774  viasHolesLayer,
775  m_antiBoard );
776  }
777 
779  }
780  }
781  else
782  {
783  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
785  m_antiBoard );
786 
787  // Draw copper plated pads
788  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
790  {
791  setPlatedCopperAndDepthOffset( layer_id );
792  }
793 
794  if( layer_id == F_Cu && m_platedPadsFront )
795  {
798  m_antiBoard );
799  }
800  else if( layer_id == B_Cu && m_platedPadsBack )
801  {
804  m_antiBoard );
805  }
806 
808  }
809  }
810  }
811  else
812  {
813  setLayerMaterial( layer_id );
814 
815  OPENGL_RENDER_LIST* throughHolesOuter =
818  && ( layer_id == B_SilkS || layer_id == F_SilkS )
821 
822  if( throughHolesOuter )
823  {
824  throughHolesOuter->ApplyScalePosition(
825  pLayerDispList->GetZBot(),
826  pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
827  }
828 
829  OPENGL_RENDER_LIST* anti_board = m_antiBoard;
830 
831  if( ( layer_id == B_Paste ) || ( layer_id == F_Paste ) )
832  anti_board = nullptr;
833 
834  if( anti_board )
835  {
836  anti_board->ApplyScalePosition(
837  pLayerDispList->GetZBot(),
838  pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
839  }
840 
841  if( !skipRenderHoles
844  && ( ( layer_id == B_SilkS && m_layers.find( B_Mask ) != m_layers.end() )
845  || ( layer_id == F_SilkS && m_layers.find( F_Mask ) != m_layers.end() ) ) )
846  {
847  const PCB_LAYER_ID layerMask_id = (layer_id == B_SilkS) ? B_Mask : F_Mask;
848 
849  const OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( layerMask_id );
850 
851  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
852  pLayerDispListMask,
853  throughHolesOuter, anti_board );
854  }
855  else
856  {
857  if( !skipRenderHoles && throughHolesOuter
858  && ( layer_id == B_SilkS || layer_id == F_SilkS ) )
859  {
860  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments, nullptr,
861  throughHolesOuter,
862  anti_board );
863  }
864  else
865  {
866  // Do not render Paste layers when skipRenderHoles is enabled
867  // otherwise it will cause z-fight issues
868  if( !( skipRenderHoles && ( layer_id == B_Paste || layer_id == F_Paste ) ) )
869  {
870  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
871  anti_board );
872  }
873  }
874  }
875  }
876 
877  glPopMatrix();
878  }
879 
880  // Render 3D Models (Non-transparent)
881  render3dModels( false, false );
882  render3dModels( true, false );
883 
884  // Display board body
886  {
887  renderBoardBody( skipRenderHoles );
888  }
889 
890  // Display transparent mask layers
892  {
893  // add a depth buffer offset, it will help to hide some artifacts
894  // on silkscreen where the SolderMask is removed
895  glEnable( GL_POLYGON_OFFSET_FILL );
896  glPolygonOffset( 0.0f, -2.0f );
897 
898  if( m_camera.GetPos().z > 0 )
899  {
901  drawMiddleSegments, skipRenderHoles );
902 
904  drawMiddleSegments, skipRenderHoles );
905  }
906  else
907  {
909  drawMiddleSegments, skipRenderHoles );
910 
912  drawMiddleSegments, skipRenderHoles );
913  }
914 
915  glDisable( GL_POLYGON_OFFSET_FILL );
916  glPolygonOffset( 0.0f, 0.0f );
917  }
918 
919  // Render 3D Models (Transparent)
920  // !TODO: this can be optimized. If there are no transparent models (or no opacity),
921  // then there is no need to make this function call.
922  glDepthMask( GL_FALSE );
923  glEnable( GL_BLEND );
924  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
925 
926  // Enables Texture Env so it can combine model transparency with each footprint opacity
927  glEnable( GL_TEXTURE_2D );
928  glActiveTexture( GL_TEXTURE0 );
929 
930  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
931  glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
932  glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
933 
934  glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
935  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
936 
937  glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
938  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
939 
940  glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
941  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
942  glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
943  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_CONSTANT );
944 
945  render3dModels( false, true );
946  render3dModels( true, true );
947 
948  glDisable( GL_BLEND );
950 
951  glDepthMask( GL_TRUE );
952 
953  // Render Grid
955  {
956  glDisable( GL_LIGHTING );
957 
958  if( glIsList( m_grid ) )
959  glCallList( m_grid );
960 
961  glEnable( GL_LIGHTING );
962  }
963 
964  // Render 3D arrows
966  render3dArrows();
967 
968  // Return back to the original viewport (this is important if we want
969  // to take a screenshot after the render)
970  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
971 
972  return false;
973 }
974 
975 
977 {
978  glEnable( GL_LINE_SMOOTH );
979  glShadeModel( GL_SMOOTH );
980 
981  // 4-byte pixel alignment
982  glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
983 
984  // Initialize the open GL texture to draw the filled semi-circle of the segments
986 
987  if( !circleImage )
988  return false;
989 
990  unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
991 
992  circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
993  ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
994  circleRadius,
995  0xFF );
996 
997  IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
998 
999  circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
1000 
1001  m_circleTexture = OglLoadTexture( *circleImageBlured );
1002 
1003  delete circleImageBlured;
1004  circleImageBlured = nullptr;
1005 
1006  delete circleImage;
1007  circleImage = nullptr;
1008 
1009  init_lights();
1010 
1011  // Use this mode if you want see the triangle lines (debug proposes)
1012  //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1013  m_is_opengl_initialized = true;
1014 
1015  return true;
1016 }
1017 
1018 
1020 {
1021  glEnable( GL_COLOR_MATERIAL );
1022  glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1023 
1024  const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1025  const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1026  const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1027  const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
1028 
1029  glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
1030  glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
1031 
1032  glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
1033  glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
1034  glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
1035 }
1036 
1037 
1039 {
1040  if( glIsList( m_grid ) )
1041  glDeleteLists( m_grid, 1 );
1042 
1043  m_grid = 0;
1044 
1045  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
1046  {
1047  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1048  delete pLayerDispList;
1049  }
1050 
1051  m_layers.clear();
1052 
1053  delete m_platedPadsFront;
1054  m_platedPadsFront = nullptr;
1055 
1056  delete m_platedPadsBack;
1057  m_platedPadsBack = nullptr;
1058 
1059  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_outerLayerHoles.begin();
1060  ii != m_outerLayerHoles.end();
1061  ++ii )
1062  {
1063  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1064  delete pLayerDispList;
1065  }
1066 
1067  m_outerLayerHoles.clear();
1068 
1069  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_innerLayerHoles.begin();
1070  ii != m_innerLayerHoles.end();
1071  ++ii )
1072  {
1073  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1074  delete pLayerDispList;
1075  }
1076 
1077  m_innerLayerHoles.clear();
1078 
1079  for( LIST_TRIANGLES::const_iterator ii = m_triangles.begin(); ii != m_triangles.end(); ++ii )
1080  {
1081  delete *ii;
1082  }
1083 
1084  m_triangles.clear();
1085 
1086  for( MAP_3DMODEL::const_iterator ii = m_3dModelMap.begin(); ii != m_3dModelMap.end(); ++ii )
1087  {
1088  MODEL_3D* pointer = static_cast<MODEL_3D*>(ii->second);
1089  delete pointer;
1090  }
1091 
1092  m_3dModelMap.clear();
1093 
1094  delete m_board;
1095  m_board = nullptr;
1096 
1097  delete m_boardWithHoles;
1098  m_boardWithHoles = nullptr;
1099 
1100  delete m_antiBoard;
1101  m_antiBoard = nullptr;
1102 
1103  delete m_outerThroughHoles;
1104  m_outerThroughHoles = nullptr;
1105 
1106  delete m_outerViaThroughHoles;
1107  m_outerViaThroughHoles = nullptr;
1108 
1109  delete m_outerThroughHoleRings;
1110  m_outerThroughHoleRings = nullptr;
1111 
1112  delete m_vias;
1113  m_vias = nullptr;
1114 
1115  delete m_padHoles;
1116  m_padHoles = nullptr;
1117 }
1118 
1119 
1121  bool aDrawMiddleSegments, bool aSkipRenderHoles )
1122 {
1123  wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
1124 
1125  float nonCopperThickness = m_boardAdapter.GetNonCopperLayerThickness();
1126 
1127  if( m_board )
1128  {
1129  if( m_layers.find( aLayerID ) != m_layers.end() )
1130  {
1131  OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( aLayerID );
1132 
1134  m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1135 
1136  m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1137 
1138  setLayerMaterial( aLayerID );
1139 
1140  m_board->SetItIsTransparent( true );
1141 
1142  if( aSkipRenderHoles )
1143  {
1144  m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1145  }
1146  else
1147  {
1148  m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments, pLayerDispListMask,
1150  }
1151  }
1152  else
1153  {
1154  // This case there is no layer with mask, so we will render the full board as mask
1156  m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1157 
1158  m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1159 
1160  setLayerMaterial( aLayerID );
1161 
1162  m_board->SetItIsTransparent( true );
1163 
1164  if( aSkipRenderHoles )
1165  {
1166  m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1167  }
1168  else
1169  {
1170  m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments,
1172  }
1173  }
1174  }
1175 }
1176 
1177 
1178 void RENDER_3D_LEGACY::render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
1179  bool aRenderSelectedOnly )
1180 {
1181  if( !m_boardAdapter.GetBoard() )
1182  return;
1183 
1184  MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly );
1185 
1186  // Go for all footprints
1187  for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
1188  {
1189  const bool isIntersected = fp == m_currentRollOverItem;
1190  bool highlight = false;
1191 
1193  {
1194  if( isIntersected )
1195  {
1196  if( aRenderSelectedOnly )
1198  }
1199  else if( ( aRenderSelectedOnly && !fp->IsSelected() )
1200  || ( !aRenderSelectedOnly && fp->IsSelected() ) )
1201  {
1202  continue;
1203  }
1204  }
1205 
1206  if( highlight )
1207  {
1208  glEnable( GL_POLYGON_OFFSET_LINE );
1209  glPolygonOffset( 8.0, 1.0 );
1210  glPolygonMode( GL_FRONT, GL_LINE );
1211  glLineWidth( 6 );
1212  }
1213 
1214  if( !fp->Models().empty() )
1215  {
1216  if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1217  {
1218  if( ( aRenderTopOrBot && !fp->IsFlipped() )
1219  || ( !aRenderTopOrBot && fp->IsFlipped() ) )
1220  {
1221  renderFootprint( fp, aRenderTransparentOnly, isIntersected );
1222  }
1223  }
1224  }
1225 
1226  if( highlight )
1227  {
1228  // Restore
1229  glDisable( GL_POLYGON_OFFSET_LINE );
1230  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1231  }
1232  }
1233 
1235 }
1236 
1237 
1238 void RENDER_3D_LEGACY::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly )
1239 {
1241  render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, true );
1242 
1243  render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, false );
1244 }
1245 
1246 
1247 void RENDER_3D_LEGACY::renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
1248  bool aIsSelected )
1249 {
1250  if( !aFootprint->Models().empty() )
1251  {
1252  const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1253 
1254  glPushMatrix();
1255 
1256  wxPoint pos = aFootprint->GetPosition();
1257 
1258  glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(),
1259  zpos );
1260 
1261  if( aFootprint->GetOrientation() )
1262  glRotated( (double) aFootprint->GetOrientation() / 10.0, 0.0, 0.0, 1.0 );
1263 
1264  if( aFootprint->IsFlipped() )
1265  {
1266  glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
1267  glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
1268  }
1269 
1270  double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1271 
1272  glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
1273  modelunit_to_3d_units_factor );
1274 
1275  // Get the list of model files for this model
1276  for( const FP_3DMODEL& sM : aFootprint->Models() )
1277  {
1278  if( !sM.m_Show || sM.m_Filename.empty() )
1279  continue;
1280 
1281  // Check if the model is present in our cache map
1282  auto cache_i = m_3dModelMap.find( sM.m_Filename );
1283 
1284  if( cache_i == m_3dModelMap.end() )
1285  continue;
1286 
1287  if( const MODEL_3D* modelPtr = cache_i->second )
1288  {
1289  bool opaque = sM.m_Opacity >= 1.0;
1290 
1291  if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1292  ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1293  {
1294  glPushMatrix();
1295 
1296  // FIXME: don't do this over and over again unless the
1297  // values have changed. cache the matrix somewhere.
1298  glm::mat4 mtx( 1 );
1299  mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
1300  mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ),
1301  { 0.0f, 0.0f, 1.0f } );
1302  mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.y ),
1303  { 0.0f, 1.0f, 0.0f } );
1304  mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.x ),
1305  { 1.0f, 0.0f, 0.0f } );
1306  mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } );
1307  glMultMatrixf( glm::value_ptr( mtx ) );
1308 
1309  if( aRenderTransparentOnly )
1310  {
1311  modelPtr->DrawTransparent( sM.m_Opacity,
1312  aFootprint->IsSelected() || aIsSelected,
1314  }
1315  else
1316  {
1317  modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected,
1319  }
1320 
1322  {
1323  glEnable( GL_BLEND );
1324  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1325 
1326  glDisable( GL_LIGHTING );
1327 
1328  glLineWidth( 1 );
1329  modelPtr->DrawBboxes();
1330 
1331  glLineWidth( 4 );
1332  modelPtr->DrawBbox();
1333 
1334  glEnable( GL_LIGHTING );
1335  glDisable( GL_BLEND );
1336  }
1337 
1338  glPopMatrix();
1339  }
1340  }
1341  }
1342 
1343  glPopMatrix();
1344  }
1345 }
1346 
1347 
1349 {
1350  if( glIsList( m_grid ) )
1351  glDeleteLists( m_grid, 1 );
1352 
1353  m_grid = 0;
1354 
1355  if( aGridType == GRID3D_TYPE::NONE )
1356  return;
1357 
1358  m_grid = glGenLists( 1 );
1359 
1360  if( !glIsList( m_grid ) )
1361  return;
1362 
1363  glNewList( m_grid, GL_COMPILE );
1364 
1365  glEnable( GL_BLEND );
1366  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1367 
1368  const double zpos = 0.0;
1369 
1370  // Color of grid lines
1371  const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1372 
1373  // Color of grid lines every 5 lines
1374  const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTBLUE );
1375  const double scale = m_boardAdapter.BiuTo3dUnits();
1376  const GLfloat transparency = 0.35f;
1377 
1378  double griSizeMM = 0.0;
1379 
1380  switch( aGridType )
1381  {
1382  default:
1383  case GRID3D_TYPE::NONE:
1384  return;
1385  case GRID3D_TYPE::GRID_1MM:
1386  griSizeMM = 1.0;
1387  break;
1389  griSizeMM = 2.5;
1390  break;
1391  case GRID3D_TYPE::GRID_5MM:
1392  griSizeMM = 5.0;
1393  break;
1395  griSizeMM = 10.0;
1396  break;
1397  }
1398 
1399  glNormal3f( 0.0, 0.0, 1.0 );
1400 
1401  const wxSize brd_size = m_boardAdapter.GetBoardSize();
1402  wxPoint brd_center_pos = m_boardAdapter.GetBoardPos();
1403 
1404  brd_center_pos.y = -brd_center_pos.y;
1405 
1406  const int xsize = std::max( brd_size.x, Millimeter2iu( 100 ) ) * 1.2;
1407  const int ysize = std::max( brd_size.y, Millimeter2iu( 100 ) ) * 1.2;
1408 
1409  // Grid limits, in 3D units
1410  double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1411  double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1412  double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1413  double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1414  double zmin = Millimeter2iu( -50 ) * scale;
1415  double zmax = Millimeter2iu( 100 ) * scale;
1416 
1417  // Set rasterised line width (min value = 1)
1418  glLineWidth( 1 );
1419 
1420  // Draw horizontal grid centered on 3D origin (center of the board)
1421  for( int ii = 0; ; ii++ )
1422  {
1423  if( (ii % 5) )
1424  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1425  else
1426  glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1427  transparency );
1428 
1429  const int delta = KiROUND( ii * griSizeMM * IU_PER_MM );
1430 
1431  if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1432  {
1433  glBegin( GL_LINES );
1434  glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1435  glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1436  glEnd();
1437 
1438  if( ii != 0 )
1439  {
1440  glBegin( GL_LINES );
1441  glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1442  glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1443  glEnd();
1444  }
1445  }
1446 
1447  if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1448  {
1449  glBegin( GL_LINES );
1450  glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1451  glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1452  glEnd();
1453 
1454  if( ii != 0 )
1455  {
1456  glBegin( GL_LINES );
1457  glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1458  glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1459  glEnd();
1460  }
1461  }
1462 
1463  if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1464  break;
1465  }
1466 
1467  // Draw vertical grid on Z axis
1468  glNormal3f( 0.0, -1.0, 0.0 );
1469 
1470  // Draw vertical grid lines (parallel to Z axis)
1471  double posy = -brd_center_pos.y * scale;
1472 
1473  for( int ii = 0; ; ii++ )
1474  {
1475  if( (ii % 5) )
1476  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1477  else
1478  glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1479  transparency );
1480 
1481  const double delta = ii * griSizeMM * IU_PER_MM;
1482 
1483  glBegin( GL_LINES );
1484  xmax = ( brd_center_pos.x + delta ) * scale;
1485 
1486  glVertex3f( xmax, posy, zmin );
1487  glVertex3f( xmax, posy, zmax );
1488  glEnd();
1489 
1490  if( ii != 0 )
1491  {
1492  glBegin( GL_LINES );
1493  xmin = ( brd_center_pos.x - delta ) * scale;
1494  glVertex3f( xmin, posy, zmin );
1495  glVertex3f( xmin, posy, zmax );
1496  glEnd();
1497  }
1498 
1499  if( delta > xsize / 2.0f )
1500  break;
1501  }
1502 
1503  // Draw horizontal grid lines on Z axis (parallel to X axis)
1504  for( int ii = 0; ; ii++ )
1505  {
1506  if( ii % 5 )
1507  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1508  else
1509  glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1510 
1511  const double delta = ii * griSizeMM * IU_PER_MM * scale;
1512 
1513  if( delta <= zmax )
1514  {
1515  // Draw grid lines on Z axis (positive Z axis coordinates)
1516  glBegin( GL_LINES );
1517  glVertex3f( xmin, posy, delta );
1518  glVertex3f( xmax, posy, delta );
1519  glEnd();
1520  }
1521 
1522  if( delta <= -zmin && ( ii != 0 ) )
1523  {
1524  // Draw grid lines on Z axis (negative Z axis coordinates)
1525  glBegin( GL_LINES );
1526  glVertex3f( xmin, posy, -delta );
1527  glVertex3f( xmax, posy, -delta );
1528  glEnd();
1529  }
1530 
1531  if( ( delta > zmax ) && ( delta > -zmin ) )
1532  break;
1533  }
1534 
1535  glDisable( GL_BLEND );
1536 
1537  glEndList();
1538 }
GRID3D_TYPE GetGridType() const noexcept
Get the current grid.
bool GetFlag(DISPLAY3D_FLG aFlag) const
Get a configuration status of a flag.
BOARD_ADAPTER & m_boardAdapter
int GetWaitForEditingTimeOut() override
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
void render3dModels(bool aRenderTopOrBot, bool aRenderTransparentOnly)
void reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
SFVEC4F m_SilkScreenColorBot
in realistic mode: SilkScreen color ( bot )
std::list< FP_3DMODEL > & Models()
Definition: footprint.h:182
void DrawRoundArrow(SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize)
Draw a round arrow.
bool IsSelected() const
Definition: eda_item.h:123
bool IsFootprintShown(FOOTPRINT_ATTR_T aFPAttributes) const
Test if footprint should be displayed in relation to attributes and the flags.
void OglSetMaterial(const SMATERIAL &aMaterial, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Set OpenGL materials.
Definition: ogl_utils.cpp:119
Implementation of conversion functions that require both schematic and board internal units.
LIST_TRIANGLES m_triangles
store pointers so can be deleted latter
static constexpr double IU_PER_MM
Mock up a conversion function.
SFVEC4F GetColor(const COLOR4D &aColor) const
void DrawAllCameraCulledSubtractLayer(bool aDrawMiddle, const OPENGL_RENDER_LIST *aLayerToSubtractA=nullptr, const OPENGL_RENDER_LIST *aLayerToSubtractB=nullptr, const OPENGL_RENDER_LIST *aLayerToSubtractC=nullptr, const OPENGL_RENDER_LIST *aLayerToSubtractD=nullptr) const
float GetZBot() const
void DrawAllCameraCulled(float zCameraPos, bool aDrawMiddle=true) const
Draw all layers if they are visible by the camera if camera position is above the layer.
MAP_OGL_DISP_LISTS m_layers
const glm::mat4 & GetProjectionMatrix() const
Definition: camera.cpp:377
glm::vec4 SFVEC4F
Definition: xv3d_types.h:46
SFVEC4F m_SolderMaskColorTop
in realistic mode: solder mask color ( top )
void init_lights(void)
void render3dModelsSelected(bool aRenderTopOrBot, bool aRenderTransparentOnly, bool aRenderSelectedOnly)
float GetNonCopperLayerThickness() const noexcept
Get the current non copper layers thickness.
const SFVEC3F & GetPos() const
Definition: camera.h:109
double GetOrientation() const
Definition: footprint.h:190
float mapf(float x, float in_min, float in_max, float out_min, float out_max)
Definition: 3d_math.h:133
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:48
SFVEC4F m_BoardBodyColor
in realistic mode: FR4 board color
SFVEC4F m_SolderPasteColor
in realistic mode: solder paste color
OPENGL_RENDER_LIST * m_platedPadsFront
void setLightBottom(bool enabled)
void generate3dGrid(GRID3D_TYPE aGridType)
Create a 3D grid to an OpenGL display list.
void renderFootprint(const FOOTPRINT *aFootprint, bool aRenderTransparentOnly, bool aIsSelected)
void setPlatedCopperAndDepthOffset(PCB_LAYER_ID aLayer_id)
SFVEC4F m_SolderMaskColorBot
in realistic mode: solder mask color ( bot )
void OglResetTextureState()
Reset to default state the texture settings.
Definition: ogl_utils.cpp:187
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:70
const glm::mat4 GetRotationMatrix() const
Get the rotation matrix to be applied in a transformation camera.
Definition: camera.cpp:152
MAP_3DMODEL m_3dModelMap
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
FOOTPRINT_ATTR_T
The set of attributes allowed within a FOOTPRINT, using FOOTPRINT::SetAttributes() and FOOTPRINT::Get...
Definition: footprint.h:66
void setLayerMaterial(PCB_LAYER_ID aLayerID)
OPENGL_RENDER_LIST * m_outerThroughHoles
#define UNITS3D_TO_UNITSPCB
Scale conversion from 3d model units to pcb units.
OPENGL_RENDER_LIST * m_outerThroughHoleRings
OPENGL_RENDER_LIST * m_boardWithHoles
A class used to derive camera objects from.
Definition: camera.h:77
void EfxFilter_SkipCenter(IMAGE *aInImg, IMAGE_FILTER aFilterType, unsigned int aRadius)
Apply a filter to the input image and store it in the image class.
Definition: image.cpp:527
SFVEC4F m_BgColorTop
background top color
#define SIZE_OF_CIRCLE_TEXTURE
void CircleFilled(int aCx, int aCy, int aRadius, unsigned char aValue)
Definition: image.cpp:173
MAP_OGL_DISP_LISTS m_outerLayerHoles
OPENGL_RENDER_LIST * m_antiBoard
wxPoint GetBoardPos() const noexcept
Get the board center.
float GetLayerTopZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the top z position.
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
FOOTPRINTS & Footprints()
Definition: board.h:233
float GetLayerBottomZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the bottom z position.
const glm::mat4 & GetViewMatrix() const
Definition: camera.cpp:407
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
OPENGL_RENDER_LIST * m_board
const BOARD * GetBoard() const noexcept
Get current board to be rendered.
#define _(s)
SFVEC4F m_BgColorBot
background bottom color
void ApplyScalePosition(float aZposition, float aZscale)
GRID3D_TYPE m_lastGridType
Stores the last grid type.
This is a base class to hold data and functions for render targets.
RENDER_3D_LEGACY(EDA_3D_CANVAS *aCanvas, BOARD_ADAPTER &aAdapter, CAMERA &aCamera)
GRID3D_TYPE
Grid types.
Definition: 3d_enums.h:99
void DrawAll(bool aDrawMiddle=true) const
Call to draw all the display lists.
bool m_is_opengl_initialized
float GetFootprintZPos(bool aIsFlipped) const
Get the position of the footprint in 3d integer units considering if it is flipped or not.
std::unique_ptr< BUSY_INDICATOR > CreateBusyIndicator() const
Return a created busy indicator, if a factory has been set, else a null pointer.
Store the OpenGL display lists to related with a layer.
bool m_reloadRequested
The window size that this camera is working.
bool IsFlipped() const
Definition: footprint.h:270
BOARD_ITEM * m_currentRollOverItem
void renderBoardBody(bool aSkipRenderHoles)
static void EndDrawMulti()
Cleanup render states after drawing multiple models.
Definition: 3d_model.cpp:390
SFVEC4F GetLayerColor(PCB_LAYER_ID aLayerId) const
Get the technical color of a layer.
const int scale
void OglDrawBackground(const SFVEC3F &aTopColor, const SFVEC3F &aBotColor)
Definition: ogl_utils.cpp:158
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:64
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
GLuint m_grid
oGL list that stores current grid
SFVEC4F m_CopperColor
in realistic mode: copper color
Definition: layer_ids.h:70
unsigned int GetHeight() const
Definition: image.h:214
void setLightFront(bool enabled)
SFVEC3F SphericalToCartesian(float aInclination, float aAzimuth)
https://en.wikipedia.org/wiki/Spherical_coordinate_system
Definition: 3d_math.h:43
void renderSolderMaskLayer(PCB_LAYER_ID aLayerID, float aZPosition, bool aDrawMiddleSegments, bool aSkipRenderHoles)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
Define generic OpenGL functions that are common to any OpenGL target.
Manage an 8-bit channel image.
Definition: image.h:89
wxPoint GetPosition() const override
Definition: footprint.h:186
CAMERA & m_camera
Flag if the opengl specific for this render was already initialized.
void SetItIsTransparent(bool aSetTransparent)
Defines math related functions.
float GetZTop() const
SFVEC3F m_OpenGlSelectionColor
SFVEC4F getLayerColor(PCB_LAYER_ID aLayerID)
constexpr int delta
SFVEC4F m_SilkScreenColorTop
in realistic mode: SilkScreen color ( top )
OPENGL_RENDER_LIST * m_platedPadsBack
MAP_OGL_DISP_LISTS m_innerLayerHoles
unsigned int GetWidth() const
Definition: image.h:213
float GetEpoxyThickness() const noexcept
Get the current epoxy thickness.
static void BeginDrawMulti(bool aUseColorInformation)
Set some basic render states before drawing multiple models.
Definition: 3d_model.cpp:374
GLuint OglLoadTexture(const IMAGE &aImage)
Generate a new OpenGL texture.
Definition: ogl_utils.cpp:71
OPENGL_RENDER_LIST * m_vias
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
static constexpr int Millimeter2iu(double mm)
void setLightTop(bool enabled)
wxSize GetBoardSize() const noexcept
Get the board size.
Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:68
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
Definition: board_adapter.h:62
OPENGL_RENDER_LIST * m_padHoles
OPENGL_RENDER_LIST * m_outerViaThroughHoles
struct RENDER_3D_LEGACY::@5 m_materials