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