KiCad PCB EDA Suite
c3d_render_ogl_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) 1992-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 "c3d_render_ogl_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  C3D_RENDER_BASE( aAdapter, aCamera )
43 {
44  wxLogTrace( m_logTrace, wxT( "C3D_RENDER_OGL_LEGACY::C3D_RENDER_OGL_LEGACY" ) );
45 
46  m_layers.clear();
47  m_layers_holes_outer.clear();
48  m_layers_holes_inner.clear();
49  m_triangles.clear();
50  m_board = NULL;
52 
53  m_platedPads_F_Cu = nullptr;
54  m_platedPads_B_Cu = nullptr;
55 
59  //m_through_holes_vias_inner = NULL;
60  m_vias = NULL;
61  m_pad_holes = NULL;
63 
65  m_grid = 0;
68  m_board_with_holes = nullptr;
69 
70  m_3dmodel_map.clear();
71 }
72 
73 
75 {
76  wxLogTrace( m_logTrace, wxT( "C3D_RENDER_OGL_LEGACY::~C3D_RENDER_OGL_LEGACY" ) );
77 
79 
80  glDeleteTextures( 1, &m_ogl_circle_texture );
81 }
82 
83 
85 {
86  return 50; // ms
87 }
88 
89 
90 void C3D_RENDER_OGL_LEGACY::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 
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 = glm::translate( glm::mat4(1.0f),
147  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  OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
157  SFVEC3F( arrow_size, 0.0f, 0.0f ),
158  0.275f );
159 
160  glColor3f( 0.0f, 0.9f, 0.0f );
161  OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
162  SFVEC3F( 0.0f, arrow_size, 0.0f ),
163  0.275f );
164 
165  glColor3f( 0.0f, 0.0f, 0.9f );
166  OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
167  SFVEC3F( 0.0f, 0.0f, arrow_size ),
168  0.275f );
169 
170  glEnable( GL_CULL_FACE );
171 }
172 
173 
175 {
176  m_materials = {};
177 
179  {
180  // http://devernay.free.fr/cours/opengl/materials.html
181 
182  // Plated copper
183  // Copper material mixed with the copper color
184  m_materials.m_Copper.m_Ambient = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.1f,
185  m_boardAdapter.m_CopperColor.g * 0.1f,
186  m_boardAdapter.m_CopperColor.b * 0.1f);
187 
188  m_materials.m_Copper.m_Specular = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.75f + 0.25f,
189  m_boardAdapter.m_CopperColor.g * 0.75f + 0.25f,
190  m_boardAdapter.m_CopperColor.b * 0.75f + 0.25f );
191 
192  // This guess the material type(ex: copper vs gold) to determine the
193  // shininess factor between 0.1 and 0.4
194  float shininessfactor = 0.40f - mapf( fabs( m_boardAdapter.m_CopperColor.r -
196  0.15f, 1.00f,
197  0.00f, 0.30f );
198 
199  m_materials.m_Copper.m_Shininess = shininessfactor * 128.0f;
200  m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
201 
202 
203  // Non plated copper (raw copper)
204  m_materials.m_NonPlatedCopper.m_Ambient = SFVEC3F( 0.191f, 0.073f, 0.022f );
205  m_materials.m_NonPlatedCopper.m_Diffuse = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f, 50.0f / 255.0f );
206  m_materials.m_NonPlatedCopper.m_Specular = SFVEC3F( 0.256f, 0.137f, 0.086f );
207  m_materials.m_NonPlatedCopper.m_Shininess = 0.1f * 128.0f;
208  m_materials.m_NonPlatedCopper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
209 
210  // Paste material mixed with paste color
211  m_materials.m_Paste.m_Ambient = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r,
214 
215  m_materials.m_Paste.m_Specular = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r *
221 
222  m_materials.m_Paste.m_Shininess = 0.1f * 128.0f;
223  m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
224 
225 
226  // Silk screen material mixed with silk screen color
227  m_materials.m_SilkSTop.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorTop.r,
230 
231  m_materials.m_SilkSTop.m_Specular = SFVEC3F(
235 
236  m_materials.m_SilkSTop.m_Shininess = 0.078125f * 128.0f;
237  m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
238 
239  // Silk screen material mixed with silk screen color
240  m_materials.m_SilkSBot.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorBot.r,
243 
244  m_materials.m_SilkSBot.m_Specular = SFVEC3F(
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,
257  97.0f / 255.0f,
258  47.0f / 255.0f );
259 
260  m_materials.m_EpoxyBoard.m_Specular = SFVEC3F( 18.0f / 255.0f,
261  3.0f / 255.0f,
262  20.0f / 255.0f );
263 
264  m_materials.m_EpoxyBoard.m_Shininess = 0.1f * 128.0f;
265  m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
266  }
267  else // Technical Mode
268  {
269  const SFVEC3F matAmbientColor = SFVEC3F( 0.10f );
270  const SFVEC3F matSpecularColor = SFVEC3F( 0.10f );
271  const float matShininess = 0.1f * 128.0f;
272 
273  // Copper material
274  m_materials.m_Copper.m_Ambient = matAmbientColor;
275  m_materials.m_Copper.m_Specular = matSpecularColor;
276  m_materials.m_Copper.m_Shininess = matShininess;
277  m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
278 
279  // Paste material
280  m_materials.m_Paste.m_Ambient = matAmbientColor;
281  m_materials.m_Paste.m_Specular = matSpecularColor;
282  m_materials.m_Paste.m_Shininess = matShininess;
283  m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
284 
285  // Silk screen material
286  m_materials.m_SilkSTop.m_Ambient = matAmbientColor;
287  m_materials.m_SilkSTop.m_Specular = matSpecularColor;
288  m_materials.m_SilkSTop.m_Shininess = matShininess;
289  m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
290 
291  // Silk screen material
292  m_materials.m_SilkSBot.m_Ambient = matAmbientColor;
293  m_materials.m_SilkSBot.m_Specular = matSpecularColor;
294  m_materials.m_SilkSBot.m_Shininess = matShininess;
295  m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
296 
297  // Solder mask material
298  m_materials.m_SolderMask.m_Ambient = matAmbientColor;
299  m_materials.m_SolderMask.m_Specular = matSpecularColor;
300  m_materials.m_SolderMask.m_Shininess = matShininess;
301  m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
302 
303  // Epoxy material
304  m_materials.m_EpoxyBoard.m_Ambient = matAmbientColor;
305  m_materials.m_EpoxyBoard.m_Specular = matSpecularColor;
306  m_materials.m_EpoxyBoard.m_Shininess = matShininess;
307  m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
308 
309  // Gray material (used for example in technical vias and pad holes)
310  m_materials.m_GrayMaterial.m_Ambient = SFVEC3F( 0.8f, 0.8f, 0.8f );
311  m_materials.m_GrayMaterial.m_Diffuse = SFVEC3F( 0.3f, 0.3f, 0.3f );
312  m_materials.m_GrayMaterial.m_Specular = SFVEC3F( 0.4f, 0.4f, 0.4f );
313  m_materials.m_GrayMaterial.m_Shininess = 0.01f * 128.0f;
314  m_materials.m_GrayMaterial.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
315  }
316 }
317 
318 
320 {
321  switch( aLayerID )
322  {
323  case F_Mask:
324  case B_Mask:
325  {
326  const SFVEC4F layerColor = get_layer_color( aLayerID );
327 
328  m_materials.m_SolderMask.m_Diffuse = layerColor;
329  m_materials.m_SolderMask.m_Transparency = 1.0f - layerColor.a; // Convert Opacity to Transparency
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 = m_materials.m_SolderMask.m_Diffuse *
336  m_materials.m_SolderMask.m_Diffuse;
337  }
338 
339  OGL_SetMaterial( 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 = get_layer_color( aLayerID );
346  OGL_SetMaterial( m_materials.m_Paste, 1.0f );
347  break;
348 
349  case B_SilkS:
350  m_materials.m_SilkSBot.m_Diffuse = get_layer_color( aLayerID );
351  OGL_SetMaterial( m_materials.m_SilkSBot, 1.0f );
352  break;
353 
354  case F_SilkS:
355  m_materials.m_SilkSTop.m_Diffuse = get_layer_color( aLayerID );
356  OGL_SetMaterial( 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 = get_layer_color( 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  OGL_SetMaterial( m_materials.m_Plastic, 1.0f );
384  break;
385 
386  default:
387  m_materials.m_Copper.m_Diffuse = get_layer_color( aLayerID );
388  OGL_SetMaterial( m_materials.m_Copper, 1.0f );
389 
390  break;
391  }
392 }
393 
394 
396 {
397  SFVEC4F layerColor = m_boardAdapter.GetLayerColor( aLayerID );
398 
400  {
401  switch( aLayerID )
402  {
403  case B_Adhes:
404  case F_Adhes:
405  break;
406 
407  case B_Mask:
409  break;
410  case F_Mask:
412  break;
413 
414  case B_Paste:
415  case F_Paste:
416  layerColor = m_boardAdapter.m_SolderPasteColor;
417  break;
418 
419  case B_SilkS:
421  break;
422  case F_SilkS:
424  break;
425 
426  case Dwgs_User:
427  case Cmts_User:
428  case Eco1_User:
429  case Eco2_User:
430  case Edge_Cuts:
431  case Margin:
432  break;
433 
434  case B_CrtYd:
435  case F_CrtYd:
436  break;
437 
438  case B_Fab:
439  case F_Fab:
440  break;
441 
442  default:
443  layerColor = m_boardAdapter.m_CopperColor;
444  break;
445  }
446  }
447 
448  return layerColor;
449 }
450 
451 
452 void init_lights(void)
453 {
454  // Setup light
455  // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
456  // /////////////////////////////////////////////////////////////////////////
457  const GLfloat ambient[] = { 0.084f, 0.084f, 0.084f, 1.0f };
458  const GLfloat diffuse0[] = { 0.3f, 0.3f, 0.3f, 1.0f };
459  const GLfloat specular0[] = { 0.5f, 0.5f, 0.5f, 1.0f };
460 
461  glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
462  glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse0 );
463  glLightfv( GL_LIGHT0, GL_SPECULAR, specular0 );
464 
465  const GLfloat diffuse12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
466  const GLfloat specular12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
467 
468  // defines a directional light that points along the negative z-axis
469  GLfloat position[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
470 
471  // This makes a vector slight not perpendicular with XZ plane
472  const SFVEC3F vectorLight = SphericalToCartesian( glm::pi<float>() * 0.03f,
473  glm::pi<float>() * 0.25f );
474 
475  position[0] = vectorLight.x;
476  position[1] = vectorLight.y;
477  position[2] = vectorLight.z;
478 
479  glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
480  glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse12 );
481  glLightfv( GL_LIGHT1, GL_SPECULAR, specular12 );
482  glLightfv( GL_LIGHT1, GL_POSITION, position );
483 
484 
485  // defines a directional light that points along the positive z-axis
486  position[2] = -position[2];
487 
488  glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
489  glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse12 );
490  glLightfv( GL_LIGHT2, GL_SPECULAR, specular12 );
491  glLightfv( GL_LIGHT2, GL_POSITION, position );
492 
493  const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
494 
495  glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
496 
497  glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
498 }
499 
500 
502 {
503  OGL_SetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
504 }
505 
506 
508 {
509  glEnable( GL_POLYGON_OFFSET_FILL );
510  glPolygonOffset(-0.1f, -2.0f );
511  set_layer_material( aLayer_id );
512 }
513 
514 
516 {
517  glDisable( GL_POLYGON_OFFSET_FILL );
518 }
519 
520 
521 void C3D_RENDER_OGL_LEGACY::render_board_body( bool aSkipRenderHoles )
522 {
523  m_materials.m_EpoxyBoard.m_Diffuse = m_boardAdapter.m_BoardBodyColor;
524  m_materials.m_EpoxyBoard.m_Transparency = 1.0f - m_boardAdapter.m_BoardBodyColor.a; // opacity to transparency
525 
526  OGL_SetMaterial( m_materials.m_EpoxyBoard, 1.0f );
527 
528  CLAYERS_OGL_DISP_LISTS* ogl_disp_list = nullptr;
529 
530  if( aSkipRenderHoles )
531  ogl_disp_list = m_board;
532  else
533  ogl_disp_list = m_board_with_holes;
534 
535  if( ogl_disp_list )
536  {
537  ogl_disp_list->ApplyScalePosition( -m_boardAdapter.GetEpoxyThickness3DU() / 2.0f,
539 
540  ogl_disp_list->SetItIsTransparent( true );
541 
542  ogl_disp_list->DrawAll();
543  }
544 }
545 
546 
547 bool C3D_RENDER_OGL_LEGACY::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
548  REPORTER* aWarningReporter )
549 {
550  // Initialize OpenGL
552  {
553  if( !initializeOpenGL() )
554  return false;
555  }
556 
557  if( m_reloadRequested )
558  {
559  std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
560 
561  if( aStatusReporter )
562  aStatusReporter->Report( _( "Loading..." ) );
563 
564  reload( aStatusReporter, aWarningReporter );
565 
566  // generate a new 3D grid as the size of the board may had changed
569  }
570  else
571  {
572  // Check if grid was changed
574  {
575  // and generate a new one
578  }
579  }
580 
581  setupMaterials();
582 
583  // Initial setup
584  // /////////////////////////////////////////////////////////////////////////
585  glDepthFunc( GL_LESS );
586  glEnable( GL_CULL_FACE );
587  glFrontFace( GL_CCW ); // This is the OpenGL default
588  glEnable( GL_NORMALIZE ); // This allow OpenGL to normalize the normals after transformations
589 
590  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
591 
593  glDisable( GL_MULTISAMPLE );
594  else
595  glEnable( GL_MULTISAMPLE );
596 
597  // clear color and depth buffers
598  // /////////////////////////////////////////////////////////////////////////
599  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
600  glClearDepth( 1.0f );
601  glClearStencil( 0x00 );
602  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
603 
605 
606  // Draw the background ( rectangle with color gradient)
607  // /////////////////////////////////////////////////////////////////////////
610 
611  glEnable( GL_DEPTH_TEST );
612 
613 
614  // Set projection and modelview matrixes
615  // /////////////////////////////////////////////////////////////////////////
616  glMatrixMode( GL_PROJECTION );
617  glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
618 
619  glMatrixMode( GL_MODELVIEW );
620  glLoadIdentity();
621  glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
622 
623 
624  // Position the headlight
625  // /////////////////////////////////////////////////////////////////////////
626 
627  setLight_Front( true );
628  setLight_Top( true );
629  setLight_Bottom( true );
630 
631  glEnable( GL_LIGHTING );
632 
633  {
634  const SFVEC3F &cameraPos = m_camera.GetPos();
635 
636  // Place the light at a minimum Z so the diffuse factor will not drop
637  // and the board will still look with good light.
638  float zpos;
639 
640  if( cameraPos.z > 0.0f )
641  {
642  zpos = glm::max( cameraPos.z, 0.5f ) + cameraPos.z * cameraPos.z;
643  }
644  else
645  {
646  zpos = glm::min( cameraPos.z,-0.5f ) - cameraPos.z * cameraPos.z;
647  }
648 
649  const GLfloat headlight_pos[] = { cameraPos.x,
650  cameraPos.y,
651  zpos,
652  1.0f }; // This is a point light
653 
654  glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
655  }
656 
657  const bool drawMiddleSegments = !( aIsMoving &&
659 
660  const bool skipRenderHoles = aIsMoving &&
662 
663  const bool skipRenderVias = aIsMoving &&
665 
667  {
668  // Draw vias and pad holes with copper material
670  }
671  else
672  {
673  OGL_SetMaterial( m_materials.m_GrayMaterial, 1.0f );
674  }
675 
676  if( !( skipRenderVias || skipRenderHoles ) && m_vias )
677  m_vias->DrawAll();
678 
679  if( !skipRenderHoles && m_pad_holes )
680  m_pad_holes->DrawAll();
681 
682  // Display copper and tech layers
683  // /////////////////////////////////////////////////////////////////////////
684  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
685  {
686  const PCB_LAYER_ID layer_id = (PCB_LAYER_ID)(ii->first);
687 
688  // Mask layers are not processed here because they are a special case
689  if( (layer_id == B_Mask) || (layer_id == F_Mask) )
690  continue;
691 
692  // Do not show inner layers when it is displaying the board
693  // and board body is full opaque
695  ( m_boardAdapter.m_BoardBodyColor.a > 0.99f ) )
696  {
697  if( (layer_id > F_Cu) && (layer_id < B_Cu) )
698  continue;
699  }
700 
701  glPushMatrix();
702 
703  // !TODO: if we want to increase the separation between layers
704  //glScalef( 1.0f, 1.0f, 3.0f );
705 
706 
707  CLAYERS_OGL_DISP_LISTS *pLayerDispList = static_cast<CLAYERS_OGL_DISP_LISTS*>(ii->second);
708 
709  if( (layer_id >= F_Cu) && (layer_id <= B_Cu) )
710  {
714  set_layer_material( layer_id );
715  else
717 
718  if( skipRenderHoles )
719  {
720  pLayerDispList->DrawAllCameraCulled( m_camera.GetPos().z, drawMiddleSegments );
721 
722  // Draw copper plated pads
723 
724  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
726  setPlatedCopperAndDepthOffset( layer_id );
727 
728  if( layer_id == F_Cu && m_platedPads_F_Cu )
729  {
731  drawMiddleSegments );
732  }
733  else if( layer_id == B_Cu && m_platedPads_B_Cu )
734  {
736  drawMiddleSegments );
737  }
738 
740  }
741  else
742  {
744  {
746  pLayerDispList->GetZTop()
747  - pLayerDispList->GetZBot() );
748  }
749 
750  if( m_anti_board )
751  {
752  m_anti_board->ApplyScalePosition( pLayerDispList->GetZBot(),
753  pLayerDispList->GetZTop()
754  - pLayerDispList->GetZBot() );
755  }
756 
757  if( m_layers_holes_outer.find( layer_id ) != m_layers_holes_outer.end() )
758  {
759  const CLAYERS_OGL_DISP_LISTS* viasHolesLayer = m_layers_holes_outer.at( layer_id );
760 
761  wxASSERT( viasHolesLayer != NULL );
762 
763  if( viasHolesLayer != NULL )
764  {
765  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
767  viasHolesLayer,
768  m_anti_board );
769 
770  // Draw copper plated pads
771 
772  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
774  {
775  setPlatedCopperAndDepthOffset( layer_id );
776  }
777 
778  if( layer_id == F_Cu && m_platedPads_F_Cu )
779  {
782  viasHolesLayer,
783  m_anti_board );
784  }
785  else if( layer_id == B_Cu && m_platedPads_B_Cu )
786  {
789  viasHolesLayer,
790  m_anti_board );
791  }
792 
794  }
795  }
796  else
797  {
798  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
800  m_anti_board );
801 
802  // Draw copper plated pads
803 
804  if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
806  {
807  setPlatedCopperAndDepthOffset( layer_id );
808  }
809 
810  if( layer_id == F_Cu && m_platedPads_F_Cu )
811  {
814  m_anti_board );
815  }
816  else if( layer_id == B_Cu && m_platedPads_B_Cu )
817  {
820  m_anti_board );
821  }
822 
824  }
825  }
826  }
827  else
828  {
829  set_layer_material( layer_id );
830 
831  CLAYERS_OGL_DISP_LISTS* throughHolesOuter =
834  && ( layer_id == B_SilkS || layer_id == F_SilkS )
837 
838  if( throughHolesOuter )
839  {
840  throughHolesOuter->ApplyScalePosition( pLayerDispList->GetZBot(),
841  pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
842  }
843 
844  CLAYERS_OGL_DISP_LISTS* anti_board = m_anti_board;
845 
846  if( ( layer_id == B_Paste ) || ( layer_id == F_Paste ) )
847  anti_board = nullptr;
848 
849  if( anti_board )
850  {
851  anti_board->ApplyScalePosition( pLayerDispList->GetZBot(),
852  pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
853  }
854 
855  if( !skipRenderHoles
858  && ( ( layer_id == B_SilkS && m_layers.find( B_Mask ) != m_layers.end() )
859  || ( layer_id == F_SilkS && m_layers.find( F_Mask ) != m_layers.end() ) ) )
860  {
861  const PCB_LAYER_ID layerMask_id = (layer_id == B_SilkS) ? B_Mask : F_Mask;
862 
863  const CLAYERS_OGL_DISP_LISTS *pLayerDispListMask = m_layers.at( layerMask_id );
864 
865  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
866  pLayerDispListMask,
867  throughHolesOuter, anti_board );
868  }
869  else
870  {
871  if( !skipRenderHoles
872  && throughHolesOuter
873  && ( layer_id == B_SilkS || layer_id == F_SilkS ) )
874  {
875  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments, nullptr,
876  throughHolesOuter, anti_board );
877  }
878  else
879  {
880  // Do not render Paste layers when skipRenderHoles is enabled
881  // otherwise it will cause z-fight issues
882  if( !( skipRenderHoles && ( layer_id == B_Paste || layer_id == F_Paste ) ) )
883  {
884  pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
885  anti_board );
886  }
887  }
888  }
889  }
890 
891  glPopMatrix();
892  }
893 
894  // Render 3D Models (Non-transparent)
895  // /////////////////////////////////////////////////////////////////////////
896  render_3D_models( false, false );
897  render_3D_models( true, false );
898 
899  // Display board body
900  // /////////////////////////////////////////////////////////////////////////
902  {
903  render_board_body( skipRenderHoles );
904  }
905 
906  // Display transparent mask layers
907  // /////////////////////////////////////////////////////////////////////////
909  {
910  //setLight_Top( true );
911  //setLight_Bottom( true );
912 
913  // add a depth buffer offset, it will help to hide some artifacts
914  // on silkscreen where the SolderMask is removed
915  glEnable( GL_POLYGON_OFFSET_FILL );
916  glPolygonOffset( 0.0f, -2.0f );
917 
918  if( m_camera.GetPos().z > 0 )
919  {
921  drawMiddleSegments, skipRenderHoles );
922 
924  drawMiddleSegments, skipRenderHoles );
925  }
926  else
927  {
929  drawMiddleSegments, skipRenderHoles );
930 
932  drawMiddleSegments, skipRenderHoles );
933  }
934 
935  glDisable( GL_POLYGON_OFFSET_FILL );
936  glPolygonOffset( 0.0f, 0.0f );
937  }
938 
939 
940  // Render 3D Models (Transparent)
941  // /////////////////////////////////////////////////////////////////////////
942  // !TODO: this can be optimized. If there are no transparent models (or no opacity),
943  // then there is no need to make this function call.
944 
945  glDepthMask( GL_FALSE );
946 
947  glEnable( GL_BLEND );
948  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
949 
950  // Enables Texture Env so it can combine model transparency with each footprint opacity
951  glEnable( GL_TEXTURE_2D );
952  glActiveTexture( GL_TEXTURE0 );
953 
954  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
955  glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
956  glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
957 
958  glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
959  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
960 
961  glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
962  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
963 
964  glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
965  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
966  glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
967  glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_CONSTANT );
968 
969  render_3D_models( false, true );
970  render_3D_models( true, true );
971 
972  glDisable( GL_BLEND );
974 
975  glDepthMask( GL_TRUE );
976 
977  // Render Grid
978  // /////////////////////////////////////////////////////////////////////////
979 
981  {
982  glDisable( GL_LIGHTING );
983 
984  if( glIsList( m_grid ) )
985  glCallList( m_grid );
986 
987  glEnable( GL_LIGHTING );
988  }
989 
990 
991  // Render 3D arrows
992  // /////////////////////////////////////////////////////////////////////////
995 
996  // Return back to the original viewport (this is important if we want
997  // to take a screenshot after the render)
998  // /////////////////////////////////////////////////////////////////////////
999  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
1000 
1001  return false;
1002 }
1003 
1004 
1006 {
1007  glEnable( GL_LINE_SMOOTH );
1008  glShadeModel( GL_SMOOTH );
1009 
1010  // 4-byte pixel alignment
1011  glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
1012 
1013  // Initialize the open GL texture to draw the filled semi-circle of the segments
1015 
1016  if( !circleImage )
1017  return false;
1018 
1019  circleImage->CircleFilled( (SIZE_OF_CIRCLE_TEXTURE / 2) - 0,
1020  (SIZE_OF_CIRCLE_TEXTURE / 2) - 0,
1021  (SIZE_OF_CIRCLE_TEXTURE / 2) - 4,
1022  0xFF );
1023 
1024  //circleImage->CircleFilled( (SIZE_OF_CIRCLE_TEXTURE / 4)*1.5f - 1,
1025  // (SIZE_OF_CIRCLE_TEXTURE / 4)*1.5f - 1,
1026  // (SIZE_OF_CIRCLE_TEXTURE / 4)*1.5f - 2, 0xFF );
1027 
1028  CIMAGE *circleImage_Copy = new CIMAGE( *circleImage );
1029 
1030  circleImage->EfxFilter( circleImage_Copy, IMAGE_FILTER::BLUR_3X3 );
1031 
1032  m_ogl_circle_texture = OGL_LoadTexture( *circleImage );
1033 
1034  //circleImage_Copy->SaveAsPNG("circleImage.png");
1035  delete circleImage_Copy;
1036  circleImage_Copy = 0;
1037 
1038  //circleImage->SaveAsPNG("circleImage_blured.png");
1039  delete circleImage;
1040  circleImage = 0;
1041 
1042  init_lights();
1043 
1044  // Use this mode if you want see the triangle lines (debug proposes)
1045  //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1046 
1047  m_is_opengl_initialized = true;
1048 
1049  return true;
1050 }
1051 
1052 
1054 {
1055  glEnable( GL_COLOR_MATERIAL );
1056  glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1057 
1058  const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1059  const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1060  const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1061  const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
1062 
1063  glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
1064  glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
1065 
1066  glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
1067  glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
1068  glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
1069 }
1070 
1071 
1073 {
1074  if( glIsList( m_grid ) )
1075  glDeleteLists( m_grid, 1 );
1076 
1077  m_grid = 0;
1078 
1079  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
1080  {
1081  CLAYERS_OGL_DISP_LISTS *pLayerDispList = static_cast<CLAYERS_OGL_DISP_LISTS*>(ii->second);
1082  delete pLayerDispList;
1083  }
1084 
1085  m_layers.clear();
1086 
1087  delete m_platedPads_F_Cu;
1088  m_platedPads_F_Cu = nullptr;
1089 
1090  delete m_platedPads_B_Cu;
1091  m_platedPads_B_Cu = nullptr;
1092 
1093 
1094  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers_holes_outer.begin();
1095  ii != m_layers_holes_outer.end();
1096  ++ii )
1097  {
1098  CLAYERS_OGL_DISP_LISTS *pLayerDispList = static_cast<CLAYERS_OGL_DISP_LISTS*>(ii->second);
1099  delete pLayerDispList;
1100  }
1101 
1102  m_layers_holes_outer.clear();
1103 
1104 
1105  for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers_holes_inner.begin();
1106  ii != m_layers_holes_inner.end();
1107  ++ii )
1108  {
1109  CLAYERS_OGL_DISP_LISTS *pLayerDispList = static_cast<CLAYERS_OGL_DISP_LISTS*>(ii->second);
1110  delete pLayerDispList;
1111  }
1112 
1113  m_layers_holes_inner.clear();
1114 
1115  for( LIST_TRIANGLES::const_iterator ii = m_triangles.begin(); ii != m_triangles.end(); ++ii )
1116  {
1117  delete *ii;
1118  }
1119 
1120  m_triangles.clear();
1121 
1122 
1123  for( MAP_3DMODEL::const_iterator ii = m_3dmodel_map.begin(); ii != m_3dmodel_map.end(); ++ii )
1124  {
1125  C_OGL_3DMODEL *pointer = static_cast<C_OGL_3DMODEL*>(ii->second);
1126  delete pointer;
1127  }
1128 
1129  m_3dmodel_map.clear();
1130 
1131 
1132  delete m_board;
1133  m_board = nullptr;
1134 
1135  delete m_anti_board;
1136  m_anti_board = nullptr;
1137 
1138  delete m_through_holes_outer;
1139  m_through_holes_outer = nullptr;
1140 
1142  m_through_holes_vias_outer = nullptr;
1143 
1145  m_through_holes_outer_ring = nullptr;
1146 
1147  delete m_vias;
1148  m_vias = nullptr;
1149 
1150  delete m_pad_holes;
1151  m_pad_holes = nullptr;
1152 
1155 }
1156 
1157 
1159  bool aDrawMiddleSegments,
1160  bool aSkipRenderHoles )
1161 {
1162  wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
1163 
1164  float nonCopperThickness = m_boardAdapter.GetNonCopperLayerThickness3DU();
1165 
1166  if( m_board )
1167  {
1168  if( m_layers.find( aLayerID ) != m_layers.end() )
1169  {
1170  CLAYERS_OGL_DISP_LISTS *pLayerDispListMask = m_layers.at( aLayerID );
1171 
1173  m_through_holes_vias_outer->ApplyScalePosition( aZPosition, nonCopperThickness );
1174 
1175  m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1176 
1177  set_layer_material( aLayerID );
1178 
1179  m_board->SetItIsTransparent( true );
1180 
1181  if( aSkipRenderHoles )
1182  {
1183  m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1184  }
1185  else
1186  {
1187  m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments, pLayerDispListMask,
1189  }
1190  }
1191  else
1192  {
1193  // This case there is no layer with mask, so we will render the full board as mask
1194 
1196  m_through_holes_vias_outer->ApplyScalePosition( aZPosition, nonCopperThickness );
1197 
1198  m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1199 
1200  set_layer_material( aLayerID );
1201 
1202  m_board->SetItIsTransparent( true );
1203 
1204  if( aSkipRenderHoles )
1205  {
1206  m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1207  }
1208  else
1209  {
1210  m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments,
1212  }
1213  }
1214  }
1215 }
1216 
1217 
1219  bool aRenderTransparentOnly,
1220  bool aRenderSelectedOnly )
1221 {
1222 
1223  C_OGL_3DMODEL::BeginDrawMulti( !aRenderSelectedOnly );
1224 
1225  // Go for all footprints
1226  for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
1227  {
1228  const bool isIntersected = ( fp == m_currentIntersectedBoardItem );
1229 
1230  if( m_boardAdapter.GetFlag( FL_USE_SELECTION ) && !isIntersected
1231  && ( ( aRenderSelectedOnly && !fp->IsSelected() )
1232  || ( !aRenderSelectedOnly && fp->IsSelected() ) ) )
1233  {
1234  continue;
1235  }
1236 
1237  if( isIntersected && aRenderSelectedOnly )
1238  {
1239  glEnable( GL_POLYGON_OFFSET_LINE );
1240  glPolygonOffset( 8.0, 1.0 );
1241 
1242  glPolygonMode( GL_FRONT, GL_LINE );
1243  glLineWidth( 6 );
1244  }
1245 
1246  if( !fp->Models().empty() )
1247  {
1248  if( m_boardAdapter.ShouldFPBeDisplayed( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1249  {
1250  if( ( aRenderTopOrBot && !fp->IsFlipped() )
1251  || ( !aRenderTopOrBot && fp->IsFlipped() ) )
1252  {
1253  render_3D_footprint( fp, aRenderTransparentOnly, isIntersected );
1254  }
1255  }
1256  }
1257 
1258  if( isIntersected && aRenderSelectedOnly )
1259  {
1260  // Restore
1261  glDisable( GL_POLYGON_OFFSET_LINE );
1262  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1263  }
1264  }
1265 
1267 }
1268 
1269 
1270 void C3D_RENDER_OGL_LEGACY::render_3D_models( bool aRenderTopOrBot,
1271  bool aRenderTransparentOnly )
1272 {
1274  render_3D_models_selected( aRenderTopOrBot, aRenderTransparentOnly, true );
1275 
1276  render_3D_models_selected( aRenderTopOrBot, aRenderTransparentOnly, false );
1277 }
1278 
1279 
1281  bool aRenderTransparentOnly,
1282  bool aIsSelected )
1283 {
1284  if( !aFootprint->Models().empty() )
1285  {
1286  const double zpos = m_boardAdapter.GetModulesZcoord3DIU( aFootprint->IsFlipped() );
1287 
1288  glPushMatrix();
1289 
1290  wxPoint pos = aFootprint->GetPosition();
1291 
1292  glTranslatef( pos.x * m_boardAdapter.BiuTo3Dunits(),
1293  -pos.y * m_boardAdapter.BiuTo3Dunits(),
1294  zpos );
1295 
1296  if( aFootprint->GetOrientation() )
1297  glRotated((double) aFootprint->GetOrientation() / 10.0, 0.0, 0.0, 1.0 );
1298 
1299  if( aFootprint->IsFlipped() )
1300  {
1301  glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
1302  glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
1303  }
1304 
1305  double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3Dunits() * UNITS3D_TO_UNITSPCB;
1306 
1307  glScaled( modelunit_to_3d_units_factor,
1308  modelunit_to_3d_units_factor,
1309  modelunit_to_3d_units_factor );
1310 
1311  // Get the list of model files for this model
1312  for( const FP_3DMODEL& sM : aFootprint->Models() )
1313  {
1314  if( !sM.m_Show || sM.m_Filename.empty() )
1315  continue;
1316 
1317  // Check if the model is present in our cache map
1318  auto cache_i = m_3dmodel_map.find( sM.m_Filename );
1319 
1320  if( cache_i == m_3dmodel_map.end() )
1321  continue;
1322 
1323  if( const C_OGL_3DMODEL *modelPtr = cache_i->second )
1324  {
1325  bool opaque = sM.m_Opacity >= 1.0;
1326 
1327  if( ( !aRenderTransparentOnly && modelPtr->Have_opaque() && opaque ) ||
1328  ( aRenderTransparentOnly && ( modelPtr->Have_transparent() || !opaque ) ) )
1329  {
1330  glPushMatrix();
1331 
1332  // FIXME: don't do this over and over again unless the
1333  // values have changed. cache the matrix somewhere.
1334  glm::mat4 mtx( 1 );
1335  mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
1336  mtx = glm::rotate(
1337  mtx, glm::radians( (float) -sM.m_Rotation.z ), { 0.0f, 0.0f, 1.0f } );
1338  mtx = glm::rotate(
1339  mtx, glm::radians( (float) -sM.m_Rotation.y ), { 0.0f, 1.0f, 0.0f } );
1340  mtx = glm::rotate(
1341  mtx, glm::radians( (float) -sM.m_Rotation.x ), { 1.0f, 0.0f, 0.0f } );
1342  mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } );
1343  glMultMatrixf( glm::value_ptr( mtx ) );
1344 
1345  if( aRenderTransparentOnly )
1346  {
1347  modelPtr->Draw_transparent( sM.m_Opacity,
1348  aFootprint->IsSelected() || aIsSelected,
1350  }
1351  else
1352  {
1353  modelPtr->Draw_opaque( aFootprint->IsSelected() || aIsSelected,
1355  }
1356 
1358  {
1359  glEnable( GL_BLEND );
1360  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1361 
1362  glDisable( GL_LIGHTING );
1363 
1364  glLineWidth( 1 );
1365  modelPtr->Draw_bboxes();
1366 
1367  glLineWidth( 4 );
1368  modelPtr->Draw_bbox();
1369 
1370  glEnable( GL_LIGHTING );
1371  glDisable( GL_BLEND );
1372  }
1373 
1374  glPopMatrix();
1375  }
1376  }
1377  }
1378 
1379  glPopMatrix();
1380  }
1381 }
1382 
1383 
1384 // create a 3D grid to an OpenGL display list: an horizontal grid (XY plane and Z = 0,
1385 // and a vertical grid (XZ plane and Y = 0)
1387 {
1388  if( glIsList( m_grid ) )
1389  glDeleteLists( m_grid, 1 );
1390 
1391  m_grid = 0;
1392 
1393  if( aGridType == GRID3D_TYPE::NONE )
1394  return;
1395 
1396  m_grid = glGenLists( 1 );
1397 
1398  if( !glIsList( m_grid ) )
1399  return;
1400 
1401  glNewList( m_grid, GL_COMPILE );
1402 
1403  glEnable( GL_BLEND );
1404  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1405 
1406  const double zpos = 0.0;
1407 
1408  // Color of grid lines
1409  const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1410 
1411  // Color of grid lines every 5 lines
1412  const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTGRAY );
1413  const double scale = m_boardAdapter.BiuTo3Dunits();
1414  const GLfloat transparency = 0.35f;
1415 
1416  double griSizeMM = 0.0;
1417 
1418  switch( aGridType )
1419  {
1420  default:
1421  case GRID3D_TYPE::NONE:
1422  return;
1423  case GRID3D_TYPE::GRID_1MM:
1424  griSizeMM = 1.0;
1425  break;
1427  griSizeMM = 2.5;
1428  break;
1429  case GRID3D_TYPE::GRID_5MM:
1430  griSizeMM = 5.0;
1431  break;
1433  griSizeMM = 10.0;
1434  break;
1435  }
1436 
1437  glNormal3f( 0.0, 0.0, 1.0 );
1438 
1439  const wxSize brd_size = m_boardAdapter.GetBoardSizeBIU();
1440  wxPoint brd_center_pos = m_boardAdapter.GetBoardPosBIU();
1441 
1442  brd_center_pos.y = -brd_center_pos.y;
1443 
1444  const int xsize = std::max( brd_size.x, Millimeter2iu( 100 ) ) * 1.2;
1445  const int ysize = std::max( brd_size.y, Millimeter2iu( 100 ) ) * 1.2;
1446 
1447  // Grid limits, in 3D units
1448  double xmin = (brd_center_pos.x - xsize / 2) * scale;
1449  double xmax = (brd_center_pos.x + xsize / 2) * scale;
1450  double ymin = (brd_center_pos.y - ysize / 2) * scale;
1451  double ymax = (brd_center_pos.y + ysize / 2) * scale;
1452  double zmin = Millimeter2iu( -50 ) * scale;
1453  double zmax = Millimeter2iu( 100 ) * scale;
1454 
1455  // Draw horizontal grid centered on 3D origin (center of the board)
1456  for( int ii = 0; ; ii++ )
1457  {
1458  if( (ii % 5) )
1459  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1460  else
1461  glColor4f( gridColor_marker.r,
1462  gridColor_marker.g,
1463  gridColor_marker.b,
1464  transparency );
1465 
1466  const int delta = KiROUND( ii * griSizeMM * IU_PER_MM );
1467 
1468  if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1469  {
1470  glBegin( GL_LINES );
1471  glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1472  glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1473  glEnd();
1474 
1475  if( ii != 0 )
1476  {
1477  glBegin( GL_LINES );
1478  glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1479  glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1480  glEnd();
1481  }
1482  }
1483 
1484  if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1485  {
1486  glBegin( GL_LINES );
1487  glVertex3f( xmin, -(brd_center_pos.y + delta) * scale, zpos );
1488  glVertex3f( xmax, -(brd_center_pos.y + delta) * scale, zpos );
1489  glEnd();
1490 
1491  if( ii != 0 )
1492  {
1493  glBegin( GL_LINES );
1494  glVertex3f( xmin, -(brd_center_pos.y - delta) * scale, zpos );
1495  glVertex3f( xmax, -(brd_center_pos.y - delta) * scale, zpos );
1496  glEnd();
1497  }
1498  }
1499 
1500  if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1501  break;
1502  }
1503 
1504  // Draw vertical grid on Z axis
1505  glNormal3f( 0.0, -1.0, 0.0 );
1506 
1507  // Draw vertical grid lines (parallel to Z axis)
1508  double posy = -brd_center_pos.y * scale;
1509 
1510  for( int ii = 0; ; ii++ )
1511  {
1512  if( (ii % 5) )
1513  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1514  else
1515  glColor4f( gridColor_marker.r,
1516  gridColor_marker.g,
1517  gridColor_marker.b,
1518  transparency );
1519 
1520  const double delta = ii * griSizeMM * IU_PER_MM;
1521 
1522  glBegin( GL_LINES );
1523  xmax = (brd_center_pos.x + delta) * scale;
1524 
1525  glVertex3f( xmax, posy, zmin );
1526  glVertex3f( xmax, posy, zmax );
1527  glEnd();
1528 
1529  if( ii != 0 )
1530  {
1531  glBegin( GL_LINES );
1532  xmin = (brd_center_pos.x - delta) * scale;
1533  glVertex3f( xmin, posy, zmin );
1534  glVertex3f( xmin, posy, zmax );
1535  glEnd();
1536  }
1537 
1538  if( delta > xsize / 2.0f )
1539  break;
1540  }
1541 
1542  // Draw horizontal grid lines on Z axis (parallel to X axis)
1543  for( int ii = 0; ; ii++ )
1544  {
1545  if( (ii % 5) )
1546  glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1547  else
1548  glColor4f( gridColor_marker.r,
1549  gridColor_marker.g,
1550  gridColor_marker.b,
1551  transparency );
1552 
1553  const double delta = ii * griSizeMM * IU_PER_MM * scale;
1554 
1555  if( delta <= zmax )
1556  {
1557  // Draw grid lines on Z axis (positive Z axis coordinates)
1558  glBegin( GL_LINES );
1559  glVertex3f( xmin, posy, delta );
1560  glVertex3f( xmax, posy, delta );
1561  glEnd();
1562  }
1563 
1564  if( delta <= -zmin && ( ii != 0 ) )
1565  {
1566  // Draw grid lines on Z axis (negative Z axis coordinates)
1567  glBegin( GL_LINES );
1568  glVertex3f( xmin, posy, -delta );
1569  glVertex3f( xmax, posy, -delta );
1570  glEnd();
1571  }
1572 
1573  if( ( delta > zmax ) && ( delta > -zmin ) )
1574  break;
1575  }
1576 
1577  glDisable( GL_BLEND );
1578 
1579  glEndList();
1580 }
LIST_TRIANGLES m_triangles
store pointers so can be deleted latter
static void EndDrawMulti()
EndDrawMulti - cleanup render states after drawing multiple models.
double BiuTo3Dunits() const noexcept
BiuTo3Dunits - Board integer units To 3D units.
bool GetFlag(DISPLAY3D_FLG aFlag) const
GetFlag - get a configuration status of a flag.
SFVEC4F GetColor(COLOR4D aColor) const
GetColor.
void generate_new_3DGrid(GRID3D_TYPE aGridType)
SFVEC4F m_SilkScreenColorBot
in realistic mode: SilkScreen color ( bot )
std::list< FP_3DMODEL > & Models()
Definition: footprint.h:196
bool IsSelected() const
Definition: eda_item.h:191
void render_3D_models_selected(bool aRenderTopOrBot, bool aRenderTransparentOnly, bool aRenderSelectedOnly)
Implementation of conversion functions that require both schematic and board internal units.
MAP_OGL_DISP_LISTS m_layers_holes_inner
static constexpr double IU_PER_MM
Mock up a conversion function.
void render_3D_models(bool aRenderTopOrBot, bool aRenderTransparentOnly)
render_3D_models
glm::vec4 SFVEC4F
Definition: xv3d_types.h:49
SFVEC4F m_SolderMaskColorTop
in realistic mode: solder mask color ( top )
Class CCAMERA is a virtual class used to derive CCAMERA objects from.
Definition: ccamera.h:79
void OGL_SetMaterial(const SMATERIAL &aMaterial, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
OGL_SetMaterial - Set OpenGL materials.
Definition: ogl_utils.cpp:145
float GetLayerTopZpos3DU(PCB_LAYER_ID aLayerId) const noexcept
GetLayerTopZpos3DU - Get the top z position.
double GetOrientation() const
Definition: footprint.h:204
float mapf(float x, float in_min, float in_max, float out_min, float out_max)
Definition: 3d_math.h:136
void render_3D_footprint(const FOOTPRINT *aFootprint, bool aRenderTransparentOnly, bool aIsSelected)
SFVEC4F m_BoardBodyColor
in realistic mode: FR4 board color
SFVEC4F m_SolderPasteColor
in realistic mode: solder paste color
void init_lights(void)
SFVEC4F m_SolderMaskColorBot
in realistic mode: solder mask color ( bot )
const SFVEC3F & GetPos() const
Definition: ccamera.h:113
REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
wxSize GetBoardSizeBIU() const noexcept
GetBoardSizeBIU - Get the board size.
void CircleFilled(int aCx, int aCy, int aRadius, unsigned char aValue)
CircleFilled.
Definition: cimage.cpp:173
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
void ApplyScalePosition(float aZposition, float aZscale)
FOOTPRINT_ATTR_T
Enum FOOTPRINT_ATTR_T is the set of attributes allowed within a FOOTPRINT, using FOOTPRINT::SetAttrib...
Definition: footprint.h:67
void setLight_Top(bool enabled)
GRID3D_TYPE m_last_grid_type
Stores the last grid computed.
GLuint OGL_LoadTexture(const CIMAGE &aImage)
OGL_LoadTexture - generate a new OpenGL texture.
Definition: ogl_utils.cpp:81
void render_solder_mask_layer(PCB_LAYER_ID aLayerID, float aZPosition, bool aDrawMiddleSegments, bool aSkipRenderHoles)
int GetWaitForEditingTimeOut() override
GetWaitForEditingTimeOut - Give the interface the time (in ms) that it should wait for editing or mov...
const glm::mat4 GetRotationMatrix() const
Function GetRotationMatrix Get the rotation matrix to be applied in a transformation camera.
Definition: ccamera.cpp:157
#define UNITS3D_TO_UNITSPCB
Scale conversion from 3d model units to pcb units.
void OGL_DrawBackground(const SFVEC3F &aTopColor, const SFVEC3F &aBotColor)
OGL_DrawBackground.
Definition: ogl_utils.cpp:184
CLAYERS_OGL_DISP_LISTS * m_pad_holes
void setPlatedCopperAndDepthOffset(PCB_LAYER_ID aLayer_id)
CLAYERS_OGL_DISP_LISTS * m_through_holes_vias_outer
PCB_LAYER_ID
A quick note on layer IDs:
CLAYERS_OGL_DISP_LISTS * m_vias_and_pad_holes_outer_contourn_and_caps
CLAYERS_OGL_DISP_LISTS * m_anti_board
SFVEC4F m_BgColorTop
background top color
void setLight_Front(bool enabled)
float GetLayerBottomZpos3DU(PCB_LAYER_ID aLayerId) const noexcept
GetLayerBottomZpos3DU - Get the bottom z position.
#define NULL
void DrawAllCameraCulledSubtractLayer(bool aDrawMiddle, const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractA=nullptr, const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractB=nullptr, const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractC=nullptr, const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractD=nullptr) const
void setLight_Bottom(bool enabled)
MAP_OGL_DISP_LISTS m_layers
bool m_is_opengl_initialized
flag if the opengl specific for this render was already initialized
void OGL_ResetTextureStateDefaults()
OGL_ResetTextureStateDefaults - resets to default state the texture settings.
Definition: ogl_utils.cpp:213
FOOTPRINTS & Footprints()
Definition: board.h:283
GLuint m_grid
oGL list that stores current grid
void SetCurWindowSize(const wxSize &aSize) override
SetCurWindowSize - Before each render, the canvas will tell the render what is the size of its window...
const BOARD * GetBoard() const noexcept
GetBoard - Get current board to be rendered.
SFVEC3F m_opengl_selectionColor
SFVEC4F m_BgColorBot
background bottom color
wxSize m_windowSize
The window size that this camera is working.
CLAYERS_OGL_DISP_LISTS * m_vias
BOARD_ITEM * m_currentIntersectedBoardItem
void DrawAllCameraCulled(float zCameraPos, bool aDrawMiddle=true) const
DrawAllCameraCulled - Draw all layers if they are visible by the camera.
struct C3D_RENDER_OGL_LEGACY::@0 m_materials
CLAYERS_OGL_DISP_LISTS * m_platedPads_B_Cu
std::unique_ptr< BUSY_INDICATOR > CreateBusyIndicator() const
Return a created busy indicator, if a factory has been set, else a null pointer.
void reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
GRID3D_TYPE
Grid types.
Definition: 3d_enums.h:98
CLAYERS_OGL_DISP_LISTS * m_platedPads_F_Cu
BOARD_ADAPTER & m_boardAdapter
settings refrence in use for this render
void DrawAll(bool aDrawMiddle=true) const
DrawAll - This function calls all the display lists.
CLAYERS_OGL_DISP_LISTS * m_board_with_holes
The CLAYERS_OGL_DISP_LISTS class stores the openGL display lists to related with a layer.
#define SIZE_OF_CIRCLE_TEXTURE
bool IsFlipped() const
function IsFlipped
Definition: footprint.h:282
SFVEC4F GetLayerColor(PCB_LAYER_ID aLayerId) const
GetLayerColor - get the technical color of a layer.
const int scale
bool ShouldFPBeDisplayed(FOOTPRINT_ATTR_T aFPAttributes) const
ShouldFPBeDisplayed - Test if footprint should be displayed in relation to attributes and the flags.
const glm::mat4 & GetViewMatrix() const
Definition: ccamera.cpp:423
bool m_reloadRequested
!TODO: this must be reviewed in order to flag change types
CLAYERS_OGL_DISP_LISTS * m_through_holes_outer
#define _(s)
Definition: 3d_actions.cpp:33
glm::vec3 SFVEC3F
Definition: xv3d_types.h:47
void SetItIsTransparent(bool aSetTransparent)
SFVEC4F m_CopperColor
in realistic mode: copper color
CLAYERS_OGL_DISP_LISTS * m_board
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw - Ask to redraw the view.
SFVEC3F SphericalToCartesian(float aInclination, float aAzimuth)
SphericalToCartesian.
Definition: 3d_math.h:43
float GetNonCopperLayerThickness3DU() const noexcept
GetNonCopperLayerThickness3DU - Get the current non copper layers thickness.
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
implements generic openGL functions that are common to any openGL target
static void BeginDrawMulti(bool aUseColorInformation)
BeginDrawMulti - set some basic render states before drawing multiple models.
float GetModulesZcoord3DIU(bool aIsFlipped) const
GetModulesZcoord3DIU - Get the position of the footprint in 3d integer units considering if it is fli...
wxPoint GetPosition() const override
Definition: footprint.h:200
const glm::mat4 & GetProjectionMatrix() const
Definition: ccamera.cpp:393
SFVEC4F get_layer_color(PCB_LAYER_ID aLayerID)
Defines math related functions.
CLAYERS_OGL_DISP_LISTS * m_through_holes_outer_ring
SFVEC4F m_SilkScreenColorTop
in realistic mode: SilkScreen color ( top )
wxPoint GetBoardPosBIU() const noexcept
GetBoardPosBIU - Get the board center.
CIMAGE manages a 8-bit channel image.
Definition: cimage.h:89
float GetEpoxyThickness3DU() const noexcept
GetEpoxyThickness3DU - Get the current epoxy thickness.
void set_layer_material(PCB_LAYER_ID aLayerID)
C3D_RENDER_OGL_LEGACY(BOARD_ADAPTER &aAdapter, CCAMERA &aCamera)
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
GRID3D_TYPE GridGet() const noexcept
GridGet - get the current grid.
static constexpr int Millimeter2iu(double mm)
Class BOARD_ADAPTER Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:68
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
Definition: board_adapter.h:61
void render_board_body(bool aSkipRenderHoles)
void EfxFilter(CIMAGE *aInImg, IMAGE_FILTER aFilterType)
Function EfxFilter apply a filter to the input image and stores it in the image class this <- FilterT...
Definition: cimage.cpp:472
MAP_OGL_DISP_LISTS m_layers_holes_outer
void OGL_draw_arrow(SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize)
OGL_draw_arrow - draw a round arrow.
This is a base class to hold data and functions for render targets.