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( 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 full opaque
679  ( m_boardAdapter.m_BoardBodyColor.a > 0.99f ) )
680  {
681  if( ( layer_id > F_Cu ) && ( layer_id < B_Cu ) )
682  continue;
683  }
684 
685  glPushMatrix();
686 
687  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
688 
689  if( ( layer_id >= F_Cu ) && ( layer_id <= B_Cu ) )
690  {
694  setLayerMaterial( layer_id );
695  else
697 
698  if( skipRenderHoles )
699  {
700  pLayerDispList->DrawAllCameraCulled( m_camera.GetPos().z, drawMiddleSegments );
701 
702  // Draw copper plated pads
703  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
705  setPlatedCopperAndDepthOffset( layer_id );
706 
707  if( layer_id == F_Cu && m_platedPadsFront )
708  {
710  drawMiddleSegments );
711  }
712  else if( layer_id == B_Cu && m_platedPadsBack )
713  {
715  drawMiddleSegments );
716  }
717 
719  }
720  else
721  {
722  if( m_outerThroughHoles )
723  {
724  m_outerThroughHoles->ApplyScalePosition( pLayerDispList->GetZBot(),
725  pLayerDispList->GetZTop()
726  - pLayerDispList->GetZBot() );
727  }
728 
729  if( m_antiBoard )
730  {
731  m_antiBoard->ApplyScalePosition( pLayerDispList->GetZBot(),
732  pLayerDispList->GetZTop()
733  - pLayerDispList->GetZBot() );
734  }
735 
736  if( m_outerLayerHoles.find( layer_id ) != m_outerLayerHoles.end() )
737  {
738  const OPENGL_RENDER_LIST* viasHolesLayer = m_outerLayerHoles.at( layer_id );
739 
740  wxASSERT( viasHolesLayer != nullptr );
741 
742  if( viasHolesLayer != nullptr )
743  {
744  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
746  viasHolesLayer,
747  m_antiBoard );
748 
749  // Draw copper plated pads
750 
751  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
753  {
754  setPlatedCopperAndDepthOffset( layer_id );
755  }
756 
757  if( layer_id == F_Cu && m_platedPadsFront )
758  {
760  drawMiddleSegments,
762  viasHolesLayer,
763  m_antiBoard );
764  }
765  else if( layer_id == B_Cu && m_platedPadsBack )
766  {
768  drawMiddleSegments,
770  viasHolesLayer,
771  m_antiBoard );
772  }
773 
775  }
776  }
777  else
778  {
779  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
781  m_antiBoard );
782 
783  // Draw copper plated pads
784  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
786  {
787  setPlatedCopperAndDepthOffset( layer_id );
788  }
789 
790  if( layer_id == F_Cu && m_platedPadsFront )
791  {
794  m_antiBoard );
795  }
796  else if( layer_id == B_Cu && m_platedPadsBack )
797  {
800  m_antiBoard );
801  }
802 
804  }
805  }
806  }
807  else
808  {
809  setLayerMaterial( layer_id );
810 
811  OPENGL_RENDER_LIST* throughHolesOuter =
814  && ( layer_id == B_SilkS || layer_id == F_SilkS )
817 
818  if( throughHolesOuter )
819  {
820  throughHolesOuter->ApplyScalePosition(
821  pLayerDispList->GetZBot(),
822  pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
823  }
824 
825  OPENGL_RENDER_LIST* anti_board = m_antiBoard;
826 
827  if( ( layer_id == B_Paste ) || ( layer_id == F_Paste ) )
828  anti_board = nullptr;
829 
830  if( anti_board )
831  {
832  anti_board->ApplyScalePosition(
833  pLayerDispList->GetZBot(),
834  pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
835  }
836 
837  if( !skipRenderHoles
840  && ( ( layer_id == B_SilkS && m_layers.find( B_Mask ) != m_layers.end() )
841  || ( layer_id == F_SilkS && m_layers.find( F_Mask ) != m_layers.end() ) ) )
842  {
843  const PCB_LAYER_ID layerMask_id = (layer_id == B_SilkS) ? B_Mask : F_Mask;
844 
845  const OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( layerMask_id );
846 
847  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
848  pLayerDispListMask,
849  throughHolesOuter, anti_board );
850  }
851  else
852  {
853  if( !skipRenderHoles && throughHolesOuter
854  && ( layer_id == B_SilkS || layer_id == F_SilkS ) )
855  {
856  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments, nullptr,
857  throughHolesOuter,
858  anti_board );
859  }
860  else
861  {
862  // Do not render Paste layers when skipRenderHoles is enabled
863  // otherwise it will cause z-fight issues
864  if( !( skipRenderHoles && ( layer_id == B_Paste || layer_id == F_Paste ) ) )
865  {
866  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
867  anti_board );
868  }
869  }
870  }
871  }
872 
873  glPopMatrix();
874  }
875 
876  // Render 3D Models (Non-transparent)
877  render3dModels( false, false );
878  render3dModels( true, false );
879 
880  // Display board body
882  {
883  renderBoardBody( skipRenderHoles );
884  }
885 
886  // Display transparent mask layers
888  {
889  // add a depth buffer offset, it will help to hide some artifacts
890  // on silkscreen where the SolderMask is removed
891  glEnable( GL_POLYGON_OFFSET_FILL );
892  glPolygonOffset( 0.0f, -2.0f );
893 
894  if( m_camera.GetPos().z > 0 )
895  {
897  drawMiddleSegments, skipRenderHoles );
898 
900  drawMiddleSegments, skipRenderHoles );
901  }
902  else
903  {
905  drawMiddleSegments, skipRenderHoles );
906 
908  drawMiddleSegments, skipRenderHoles );
909  }
910 
911  glDisable( GL_POLYGON_OFFSET_FILL );
912  glPolygonOffset( 0.0f, 0.0f );
913  }
914 
915  // Render 3D Models (Transparent)
916  // !TODO: this can be optimized. If there are no transparent models (or no opacity),
917  // then there is no need to make this function call.
918  glDepthMask( GL_FALSE );
919  glEnable( GL_BLEND );
920  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
921 
922  // Enables Texture Env so it can combine model transparency with each footprint opacity
923  glEnable( GL_TEXTURE_2D );
924  glActiveTexture( GL_TEXTURE0 );
925 
926  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
927  glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
928  glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
929 
930  glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
931  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
932 
933  glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
934  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
935 
936  glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
937  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
938  glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
939  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_CONSTANT );
940 
941  render3dModels( false, true );
942  render3dModels( true, true );
943 
944  glDisable( GL_BLEND );
946 
947  glDepthMask( GL_TRUE );
948 
949  // Render Grid
951  {
952  glDisable( GL_LIGHTING );
953 
954  if( glIsList( m_grid ) )
955  glCallList( m_grid );
956 
957  glEnable( GL_LIGHTING );
958  }
959 
960  // Render 3D arrows
962  render3dArrows();
963 
964  // Return back to the original viewport (this is important if we want
965  // to take a screenshot after the render)
966  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
967 
968  return false;
969 }
970 
971 
973 {
974  glEnable( GL_LINE_SMOOTH );
975  glShadeModel( GL_SMOOTH );
976 
977  // 4-byte pixel alignment
978  glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
979 
980  // Initialize the open GL texture to draw the filled semi-circle of the segments
982 
983  if( !circleImage )
984  return false;
985 
986  unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
987 
988  circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
989  ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
990  circleRadius,
991  0xFF );
992 
993  IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
994 
995  circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
996 
997  m_circleTexture = OglLoadTexture( *circleImageBlured );
998 
999  delete circleImageBlured;
1000  circleImageBlured = nullptr;
1001 
1002  delete circleImage;
1003  circleImage = nullptr;
1004 
1005  init_lights();
1006 
1007  // Use this mode if you want see the triangle lines (debug proposes)
1008  //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1009  m_is_opengl_initialized = true;
1010 
1011  return true;
1012 }
1013 
1014 
1016 {
1017  glEnable( GL_COLOR_MATERIAL );
1018  glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1019 
1020  const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1021  const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1022  const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1023  const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
1024 
1025  glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
1026  glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
1027 
1028  glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
1029  glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
1030  glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
1031 }
1032 
1033 
1035 {
1036  if( glIsList( m_grid ) )
1037  glDeleteLists( m_grid, 1 );
1038 
1039  m_grid = 0;
1040 
1041  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
1042  {
1043  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1044  delete pLayerDispList;
1045  }
1046 
1047  m_layers.clear();
1048 
1049  delete m_platedPadsFront;
1050  m_platedPadsFront = nullptr;
1051 
1052  delete m_platedPadsBack;
1053  m_platedPadsBack = nullptr;
1054 
1055  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_outerLayerHoles.begin();
1056  ii != m_outerLayerHoles.end();
1057  ++ii )
1058  {
1059  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1060  delete pLayerDispList;
1061  }
1062 
1063  m_outerLayerHoles.clear();
1064 
1065  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_innerLayerHoles.begin();
1066  ii != m_innerLayerHoles.end();
1067  ++ii )
1068  {
1069  OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1070  delete pLayerDispList;
1071  }
1072 
1073  m_innerLayerHoles.clear();
1074 
1075  for( LIST_TRIANGLES::const_iterator ii = m_triangles.begin(); ii != m_triangles.end(); ++ii )
1076  {
1077  delete *ii;
1078  }
1079 
1080  m_triangles.clear();
1081 
1082  for( MAP_3DMODEL::const_iterator ii = m_3dModelMap.begin(); ii != m_3dModelMap.end(); ++ii )
1083  {
1084  MODEL_3D* pointer = static_cast<MODEL_3D*>(ii->second);
1085  delete pointer;
1086  }
1087 
1088  m_3dModelMap.clear();
1089 
1090  delete m_board;
1091  m_board = nullptr;
1092 
1093  delete m_boardWithHoles;
1094  m_boardWithHoles = nullptr;
1095 
1096  delete m_antiBoard;
1097  m_antiBoard = nullptr;
1098 
1099  delete m_outerThroughHoles;
1100  m_outerThroughHoles = nullptr;
1101 
1102  delete m_outerViaThroughHoles;
1103  m_outerViaThroughHoles = nullptr;
1104 
1105  delete m_outerThroughHoleRings;
1106  m_outerThroughHoleRings = nullptr;
1107 
1108  delete m_vias;
1109  m_vias = nullptr;
1110 
1111  delete m_padHoles;
1112  m_padHoles = nullptr;
1113 }
1114 
1115 
1117  bool aDrawMiddleSegments, bool aSkipRenderHoles )
1118 {
1119  wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
1120 
1121  float nonCopperThickness = m_boardAdapter.GetNonCopperLayerThickness();
1122 
1123  if( m_board )
1124  {
1125  if( m_layers.find( aLayerID ) != m_layers.end() )
1126  {
1127  OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( aLayerID );
1128 
1130  m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1131 
1132  m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1133 
1134  setLayerMaterial( aLayerID );
1135 
1136  m_board->SetItIsTransparent( true );
1137 
1138  if( aSkipRenderHoles )
1139  {
1140  m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1141  }
1142  else
1143  {
1144  m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments, pLayerDispListMask,
1146  }
1147  }
1148  else
1149  {
1150  // This case there is no layer with mask, so we will render the full board as mask
1152  m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1153 
1154  m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1155 
1156  setLayerMaterial( aLayerID );
1157 
1158  m_board->SetItIsTransparent( true );
1159 
1160  if( aSkipRenderHoles )
1161  {
1162  m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1163  }
1164  else
1165  {
1166  m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments,
1168  }
1169  }
1170  }
1171 }
1172 
1173 
1174 void RENDER_3D_LEGACY::render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
1175  bool aRenderSelectedOnly )
1176 {
1177 
1178  MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly );
1179 
1180  // Go for all footprints
1181  for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
1182  {
1183  const bool isIntersected = fp == m_currentRollOverItem;
1184  bool highlight = false;
1185 
1187  {
1188  if( isIntersected )
1189  {
1190  if( aRenderSelectedOnly )
1192  }
1193  else if( ( aRenderSelectedOnly && !fp->IsSelected() )
1194  || ( !aRenderSelectedOnly && fp->IsSelected() ) )
1195  {
1196  continue;
1197  }
1198  }
1199 
1200  if( highlight )
1201  {
1202  glEnable( GL_POLYGON_OFFSET_LINE );
1203  glPolygonOffset( 8.0, 1.0 );
1204  glPolygonMode( GL_FRONT, GL_LINE );
1205  glLineWidth( 6 );
1206  }
1207 
1208  if( !fp->Models().empty() )
1209  {
1210  if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1211  {
1212  if( ( aRenderTopOrBot && !fp->IsFlipped() )
1213  || ( !aRenderTopOrBot && fp->IsFlipped() ) )
1214  {
1215  renderFootprint( fp, aRenderTransparentOnly, isIntersected );
1216  }
1217  }
1218  }
1219 
1220  if( highlight )
1221  {
1222  // Restore
1223  glDisable( GL_POLYGON_OFFSET_LINE );
1224  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1225  }
1226  }
1227 
1229 }
1230 
1231 
1232 void RENDER_3D_LEGACY::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly )
1233 {
1235  render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, true );
1236 
1237  render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, false );
1238 }
1239 
1240 
1241 void RENDER_3D_LEGACY::renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
1242  bool aIsSelected )
1243 {
1244  if( !aFootprint->Models().empty() )
1245  {
1246  const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1247 
1248  glPushMatrix();
1249 
1250  wxPoint pos = aFootprint->GetPosition();
1251 
1252  glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(),
1253  zpos );
1254 
1255  if( aFootprint->GetOrientation() )
1256  glRotated( (double) aFootprint->GetOrientation() / 10.0, 0.0, 0.0, 1.0 );
1257 
1258  if( aFootprint->IsFlipped() )
1259  {
1260  glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
1261  glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
1262  }
1263 
1264  double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1265 
1266  glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
1267  modelunit_to_3d_units_factor );
1268 
1269  // Get the list of model files for this model
1270  for( const FP_3DMODEL& sM : aFootprint->Models() )
1271  {
1272  if( !sM.m_Show || sM.m_Filename.empty() )
1273  continue;
1274 
1275  // Check if the model is present in our cache map
1276  auto cache_i = m_3dModelMap.find( sM.m_Filename );
1277 
1278  if( cache_i == m_3dModelMap.end() )
1279  continue;
1280 
1281  if( const MODEL_3D* modelPtr = cache_i->second )
1282  {
1283  bool opaque = sM.m_Opacity >= 1.0;
1284 
1285  if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1286  ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1287  {
1288  glPushMatrix();
1289 
1290  // FIXME: don't do this over and over again unless the
1291  // values have changed. cache the matrix somewhere.
1292  glm::mat4 mtx( 1 );
1293  mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
1294  mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ),
1295  { 0.0f, 0.0f, 1.0f } );
1296  mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.y ),
1297  { 0.0f, 1.0f, 0.0f } );
1298  mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.x ),
1299  { 1.0f, 0.0f, 0.0f } );
1300  mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } );
1301  glMultMatrixf( glm::value_ptr( mtx ) );
1302 
1303  if( aRenderTransparentOnly )
1304  {
1305  modelPtr->DrawTransparent( sM.m_Opacity,
1306  aFootprint->IsSelected() || aIsSelected,
1308  }
1309  else
1310  {
1311  modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected,
1313  }
1314 
1316  {
1317  glEnable( GL_BLEND );
1318  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1319 
1320  glDisable( GL_LIGHTING );
1321 
1322  glLineWidth( 1 );
1323  modelPtr->DrawBboxes();
1324 
1325  glLineWidth( 4 );
1326  modelPtr->DrawBbox();
1327 
1328  glEnable( GL_LIGHTING );
1329  glDisable( GL_BLEND );
1330  }
1331 
1332  glPopMatrix();
1333  }
1334  }
1335  }
1336 
1337  glPopMatrix();
1338  }
1339 }
1340 
1341 
1343 {
1344  if( glIsList( m_grid ) )
1345  glDeleteLists( m_grid, 1 );
1346 
1347  m_grid = 0;
1348 
1349  if( aGridType == GRID3D_TYPE::NONE )
1350  return;
1351 
1352  m_grid = glGenLists( 1 );
1353 
1354  if( !glIsList( m_grid ) )
1355  return;
1356 
1357  glNewList( m_grid, GL_COMPILE );
1358 
1359  glEnable( GL_BLEND );
1360  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1361 
1362  const double zpos = 0.0;
1363 
1364  // Color of grid lines
1365  const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1366 
1367  // Color of grid lines every 5 lines
1368  const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTGRAY );
1369  const double scale = m_boardAdapter.BiuTo3dUnits();
1370  const GLfloat transparency = 0.35f;
1371 
1372  double griSizeMM = 0.0;
1373 
1374  switch( aGridType )
1375  {
1376  default:
1377  case GRID3D_TYPE::NONE:
1378  return;
1379  case GRID3D_TYPE::GRID_1MM:
1380  griSizeMM = 1.0;
1381  break;
1383  griSizeMM = 2.5;
1384  break;
1385  case GRID3D_TYPE::GRID_5MM:
1386  griSizeMM = 5.0;
1387  break;
1389  griSizeMM = 10.0;
1390  break;
1391  }
1392 
1393  glNormal3f( 0.0, 0.0, 1.0 );
1394 
1395  const wxSize brd_size = m_boardAdapter.GetBoardSize();
1396  wxPoint brd_center_pos = m_boardAdapter.GetBoardPos();
1397 
1398  brd_center_pos.y = -brd_center_pos.y;
1399 
1400  const int xsize = std::max( brd_size.x, Millimeter2iu( 100 ) ) * 1.2;
1401  const int ysize = std::max( brd_size.y, Millimeter2iu( 100 ) ) * 1.2;
1402 
1403  // Grid limits, in 3D units
1404  double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1405  double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1406  double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1407  double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1408  double zmin = Millimeter2iu( -50 ) * scale;
1409  double zmax = Millimeter2iu( 100 ) * scale;
1410 
1411  // Draw horizontal grid centered on 3D origin (center of the board)
1412  for( int ii = 0; ; ii++ )
1413  {
1414  if( (ii % 5) )
1415  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1416  else
1417  glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1418  transparency );
1419 
1420  const int delta = KiROUND( ii * griSizeMM * IU_PER_MM );
1421 
1422  if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1423  {
1424  glBegin( GL_LINES );
1425  glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1426  glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1427  glEnd();
1428 
1429  if( ii != 0 )
1430  {
1431  glBegin( GL_LINES );
1432  glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1433  glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1434  glEnd();
1435  }
1436  }
1437 
1438  if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1439  {
1440  glBegin( GL_LINES );
1441  glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1442  glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1443  glEnd();
1444 
1445  if( ii != 0 )
1446  {
1447  glBegin( GL_LINES );
1448  glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1449  glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1450  glEnd();
1451  }
1452  }
1453 
1454  if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1455  break;
1456  }
1457 
1458  // Draw vertical grid on Z axis
1459  glNormal3f( 0.0, -1.0, 0.0 );
1460 
1461  // Draw vertical grid lines (parallel to Z axis)
1462  double posy = -brd_center_pos.y * scale;
1463 
1464  for( int ii = 0; ; ii++ )
1465  {
1466  if( (ii % 5) )
1467  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1468  else
1469  glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1470  transparency );
1471 
1472  const double delta = ii * griSizeMM * IU_PER_MM;
1473 
1474  glBegin( GL_LINES );
1475  xmax = ( brd_center_pos.x + delta ) * scale;
1476 
1477  glVertex3f( xmax, posy, zmin );
1478  glVertex3f( xmax, posy, zmax );
1479  glEnd();
1480 
1481  if( ii != 0 )
1482  {
1483  glBegin( GL_LINES );
1484  xmin = ( brd_center_pos.x - delta ) * scale;
1485  glVertex3f( xmin, posy, zmin );
1486  glVertex3f( xmin, posy, zmax );
1487  glEnd();
1488  }
1489 
1490  if( delta > xsize / 2.0f )
1491  break;
1492  }
1493 
1494  // Draw horizontal grid lines on Z axis (parallel to X axis)
1495  for( int ii = 0; ; ii++ )
1496  {
1497  if( ii % 5 )
1498  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1499  else
1500  glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1501 
1502  const double delta = ii * griSizeMM * IU_PER_MM * scale;
1503 
1504  if( delta <= zmax )
1505  {
1506  // Draw grid lines on Z axis (positive Z axis coordinates)
1507  glBegin( GL_LINES );
1508  glVertex3f( xmin, posy, delta );
1509  glVertex3f( xmax, posy, delta );
1510  glEnd();
1511  }
1512 
1513  if( delta <= -zmin && ( ii != 0 ) )
1514  {
1515  // Draw grid lines on Z axis (negative Z axis coordinates)
1516  glBegin( GL_LINES );
1517  glVertex3f( xmin, posy, -delta );
1518  glVertex3f( xmax, posy, -delta );
1519  glEnd();
1520  }
1521 
1522  if( ( delta > zmax ) && ( delta > -zmin ) )
1523  break;
1524  }
1525 
1526  glDisable( GL_BLEND );
1527 
1528  glEndList();
1529 }
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...
SFVEC4F GetColor(COLOR4D aColor) const
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:173
RENDER_3D_LEGACY(BOARD_ADAPTER &aAdapter, CAMERA &aCamera)
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.
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:376
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:181
float mapf(float x, float in_min, float in_max, float out_min, float out_max)
Definition: 3d_math.h:133
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:64
const glm::mat4 GetRotationMatrix() const
Get the rotation matrix to be applied in a transformation camera.
Definition: camera.cpp:151
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
PCB_LAYER_ID
A quick note on layer IDs:
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:406
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.
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:261
BOARD_ITEM * m_currentRollOverItem
void renderBoardBody(bool aSkipRenderHoles)
static void EndDrawMulti()
Cleanup render states after drawing multiple models.
Definition: 3d_model.cpp:389
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
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
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:70
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:177
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)
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:373
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:67
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
Definition: board_adapter.h:61
OPENGL_RENDER_LIST * m_padHoles
OPENGL_RENDER_LIST * m_outerViaThroughHoles
struct RENDER_3D_LEGACY::@5 m_materials