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