KiCad PCB EDA Suite
Loading...
Searching...
No Matches
render_3d_opengl.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015-2020 Mario Luzeiro <[email protected]>
5 * Copyright (C) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <cstdint>
27#include <gal/opengl/kiglew.h> // Must be included first
28
30#include "render_3d_opengl.h"
31#include "opengl_utils.h"
33#include <board.h>
34#include <footprint.h>
36#include <3d_math.h>
37#include <glm/geometric.hpp>
38#include <lset.h>
39#include <pgm_base.h>
40#include <math/util.h> // for KiROUND
41#include <utility>
42#include <vector>
43#include <wx/log.h>
44
45#include <base_units.h>
46
50#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
51
53 RENDER_3D_BASE( aAdapter, aCamera ),
54 m_canvas( aCanvas )
55{
56 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
57
58 m_layers.clear();
59 m_outerLayerHoles.clear();
60 m_innerLayerHoles.clear();
61 m_triangles.clear();
62 m_board = nullptr;
63 m_antiBoard = nullptr;
64
65 m_platedPadsFront = nullptr;
66 m_platedPadsBack = nullptr;
67 m_offboardPadsFront = nullptr;
68 m_offboardPadsBack = nullptr;
69
70 m_outerThroughHoles = nullptr;
72 m_outerViaThroughHoles = nullptr;
73 m_microviaHoles = nullptr;
74 m_padHoles = nullptr;
75
77 m_grid = 0;
78 m_lastGridType = GRID3D_TYPE::NONE;
79 m_currentRollOverItem = nullptr;
80 m_boardWithHoles = nullptr;
81
82 m_3dModelMap.clear();
83
84 m_spheres_gizmo = new SPHERES_GIZMO( 4, 4 );
85}
86
87
89{
90 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
91
93
94 glDeleteTextures( 1, &m_circleTexture );
95
96 delete m_spheres_gizmo;
97}
98
99
101{
102 return 50; // ms
103}
104
105
106void RENDER_3D_OPENGL::SetCurWindowSize( const wxSize& aSize )
107{
108 if( m_windowSize != aSize )
109 {
110 int viewport[4];
111 int fbWidth, fbHeight;
112 glGetIntegerv( GL_VIEWPORT, viewport );
113
114 m_windowSize = aSize;
115 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
117 // Initialize here any screen dependent data here
118 }
119}
120
121
123{
124 if( enabled )
125 glEnable( GL_LIGHT0 );
126 else
127 glDisable( GL_LIGHT0 );
128}
129
130
132{
133 if( enabled )
134 glEnable( GL_LIGHT1 );
135 else
136 glDisable( GL_LIGHT1 );
137}
138
139
141{
142 if( enabled )
143 glEnable( GL_LIGHT2 );
144 else
145 glDisable( GL_LIGHT2 );
146}
147
148
150{
152}
153
154
156{
158}
159
160
161void RENDER_3D_OPENGL::setGizmoViewport( int x, int y, int width, int height )
162{
163 m_spheres_gizmo->setViewport( x, y, width, height );
164}
165
166
167std::tuple<int, int, int, int> RENDER_3D_OPENGL::getGizmoViewport() const
168{
170}
171
172
173void RENDER_3D_OPENGL::handleGizmoMouseInput( int mouseX, int mouseY )
174{
175 m_spheres_gizmo->handleMouseInput( mouseX, mouseY );
176}
177
178
180{
181 m_materials = {};
182
183 // http://devernay.free.fr/cours/opengl/materials.html
184
185 // Plated copper
186 // Copper material mixed with the copper color
187 m_materials.m_Copper.m_Ambient = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.1f,
190
191 m_materials.m_Copper.m_Specular = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.75f + 0.25f,
192 m_boardAdapter.m_CopperColor.g * 0.75f + 0.25f,
193 m_boardAdapter.m_CopperColor.b * 0.75f + 0.25f );
194
195 // This guess the material type(ex: copper vs gold) to determine the
196 // shininess factor between 0.1 and 0.4
197 float shininessfactor = 0.40f - mapf( fabs( m_boardAdapter.m_CopperColor.r -
199 0.15f, 1.00f,
200 0.00f, 0.30f );
201
202 m_materials.m_Copper.m_Shininess = shininessfactor * 128.0f;
203 m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
204
205
206 // Non plated copper (raw copper)
207 m_materials.m_NonPlatedCopper.m_Ambient = SFVEC3F( 0.191f, 0.073f, 0.022f );
208 m_materials.m_NonPlatedCopper.m_Diffuse = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f,
209 50.0f / 255.0f );
210 m_materials.m_NonPlatedCopper.m_Specular = SFVEC3F( 0.256f, 0.137f, 0.086f );
211 m_materials.m_NonPlatedCopper.m_Shininess = 0.1f * 128.0f;
212 m_materials.m_NonPlatedCopper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
213
214 // Paste material mixed with paste color
218
219 m_materials.m_Paste.m_Specular = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r *
225
226 m_materials.m_Paste.m_Shininess = 0.1f * 128.0f;
227 m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
228
229 // Silk screen material mixed with silk screen color
230 m_materials.m_SilkSTop.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorTop.r,
233
234 m_materials.m_SilkSTop.m_Specular = SFVEC3F(
238
239 m_materials.m_SilkSTop.m_Shininess = 0.078125f * 128.0f;
240 m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
241
242 // Silk screen material mixed with silk screen color
243 m_materials.m_SilkSBot.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorBot.r,
246
247 m_materials.m_SilkSBot.m_Specular = SFVEC3F(
251
252 m_materials.m_SilkSBot.m_Shininess = 0.078125f * 128.0f;
253 m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
254
255 m_materials.m_SolderMask.m_Shininess = 0.8f * 128.0f;
256 m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
257
258 // Epoxy material
259 m_materials.m_EpoxyBoard.m_Ambient = SFVEC3F( 117.0f / 255.0f, 97.0f / 255.0f,
260 47.0f / 255.0f );
261
262 m_materials.m_EpoxyBoard.m_Specular = SFVEC3F( 18.0f / 255.0f, 3.0f / 255.0f,
263 20.0f / 255.0f );
264
265 m_materials.m_EpoxyBoard.m_Shininess = 0.1f * 128.0f;
266 m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
267}
268
269
271{
273 {
274 COLOR4D copper_color = m_boardAdapter.m_BoardEditorColors[aLayerID];
275 m_materials.m_Copper.m_Diffuse = SFVEC3F( copper_color.r, copper_color.g,
276 copper_color.b );
277 OglSetMaterial( m_materials.m_Copper, 1.0f );
278 m_materials.m_NonPlatedCopper.m_Diffuse = m_materials.m_Copper.m_Diffuse;
279 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
280
281 return;
282 }
283
284 switch( aLayerID )
285 {
286 case F_Mask:
287 case B_Mask:
288 {
289 const SFVEC4F layerColor = aLayerID == F_Mask ? m_boardAdapter.m_SolderMaskColorTop
291
292 m_materials.m_SolderMask.m_Diffuse = layerColor;
293
294 // Convert Opacity to Transparency
295 m_materials.m_SolderMask.m_Transparency = 1.0f - layerColor.a;
296
297 m_materials.m_SolderMask.m_Ambient = m_materials.m_SolderMask.m_Diffuse * 0.3f;
298
299 m_materials.m_SolderMask.m_Specular = m_materials.m_SolderMask.m_Diffuse
300 * m_materials.m_SolderMask.m_Diffuse;
301
302 OglSetMaterial( m_materials.m_SolderMask, 1.0f );
303 break;
304 }
305
306 case B_Paste:
307 case F_Paste:
309 OglSetMaterial( m_materials.m_Paste, 1.0f );
310 break;
311
312 case B_SilkS:
313 m_materials.m_SilkSBot.m_Diffuse = m_boardAdapter.m_SilkScreenColorBot;
314 OglSetMaterial( m_materials.m_SilkSBot, 1.0f );
315 break;
316
317 case F_SilkS:
318 m_materials.m_SilkSTop.m_Diffuse = m_boardAdapter.m_SilkScreenColorTop;
319 OglSetMaterial( m_materials.m_SilkSTop, 1.0f );
320 break;
321
322 case B_Adhes:
323 case F_Adhes:
324 case Dwgs_User:
325 case Cmts_User:
326 case Eco1_User:
327 case Eco2_User:
328 case Edge_Cuts:
329 case Margin:
330 case B_CrtYd:
331 case F_CrtYd:
332 case B_Fab:
333 case F_Fab:
334 switch( aLayerID )
335 {
336 case Dwgs_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
337 case Cmts_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserCommentsColor; break;
338 case Eco1_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_ECO1Color; break;
339 case Eco2_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_ECO2Color; break;
340 case Edge_Cuts: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
341 case Margin: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
342 default:
343 m_materials.m_Plastic.m_Diffuse = m_boardAdapter.GetLayerColor( aLayerID );
344 break;
345 }
346
347 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
348 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
349 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
350
351 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
352 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
353 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
354
355 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
356 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
357 OglSetMaterial( m_materials.m_Plastic, 1.0f );
358 break;
359
360 default:
361 {
362 int layer3D = MapPCBLayerTo3DLayer( aLayerID );
363
364 // Note: MUST do this in LAYER_3D space; User_1..User_45 are NOT contiguous
365 if( layer3D >= LAYER_3D_USER_1 && layer3D <= LAYER_3D_USER_45 )
366 {
367 int user_idx = layer3D - LAYER_3D_USER_1;
368
369 m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDefinedLayerColor[ user_idx ];
370 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
371 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
372 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
373
374 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
375 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
376 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
377
378 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
379 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
380 OglSetMaterial( m_materials.m_Plastic, 1.0f );
381 break;
382 }
383
384 m_materials.m_Copper.m_Diffuse = m_boardAdapter.m_CopperColor;
385 OglSetMaterial( m_materials.m_Copper, 1.0f );
386 break;
387 }
388 }
389}
390
391
393{
394 // Setup light
395 // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
396 const GLfloat ambient[] = { 0.084f, 0.084f, 0.084f, 1.0f };
397 const GLfloat diffuse0[] = { 0.3f, 0.3f, 0.3f, 1.0f };
398 const GLfloat specular0[] = { 0.5f, 0.5f, 0.5f, 1.0f };
399
400 glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
401 glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse0 );
402 glLightfv( GL_LIGHT0, GL_SPECULAR, specular0 );
403
404 const GLfloat diffuse12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
405 const GLfloat specular12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
406
407 // defines a directional light that points along the negative z-axis
408 GLfloat position[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
409
410 // This makes a vector slight not perpendicular with XZ plane
411 const SFVEC3F vectorLight = SphericalToCartesian( glm::pi<float>() * 0.03f,
412 glm::pi<float>() * 0.25f );
413
414 position[0] = vectorLight.x;
415 position[1] = vectorLight.y;
416 position[2] = vectorLight.z;
417
418 glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
419 glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse12 );
420 glLightfv( GL_LIGHT1, GL_SPECULAR, specular12 );
421 glLightfv( GL_LIGHT1, GL_POSITION, position );
422
423 // defines a directional light that points along the positive z-axis
424 position[2] = -position[2];
425
426 glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
427 glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse12 );
428 glLightfv( GL_LIGHT2, GL_SPECULAR, specular12 );
429 glLightfv( GL_LIGHT2, GL_POSITION, position );
430
431 const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
432
433 glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
434
435 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
436}
437
438
440{
441 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
442}
443
444
446{
447 glEnable( GL_POLYGON_OFFSET_FILL );
448 glPolygonOffset( -0.1f, -2.0f );
449 setLayerMaterial( aLayer_id );
450}
451
452
454{
455 glDisable( GL_POLYGON_OFFSET_FILL );
456}
457
458
459void RENDER_3D_OPENGL::renderBoardBody( bool aSkipRenderHoles )
460{
461 m_materials.m_EpoxyBoard.m_Diffuse = m_boardAdapter.m_BoardBodyColor;
462
463 // opacity to transparency
464 m_materials.m_EpoxyBoard.m_Transparency = 1.0f - m_boardAdapter.m_BoardBodyColor.a;
465
466 OglSetMaterial( m_materials.m_EpoxyBoard, 1.0f );
467
468 OPENGL_RENDER_LIST* ogl_disp_list = nullptr;
469
470 if( aSkipRenderHoles )
471 ogl_disp_list = m_board;
472 else
473 ogl_disp_list = m_boardWithHoles;
474
475 if( ogl_disp_list )
476 {
479
480 ogl_disp_list->SetItIsTransparent( true );
481 ogl_disp_list->DrawAll();
482 }
483}
484
485
486static inline SFVEC4F premultiplyAlpha( const SFVEC4F& aInput )
487{
488 return SFVEC4F( aInput.r * aInput.a, aInput.g * aInput.a, aInput.b * aInput.a, aInput.a );
489}
490
491
492bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
493 REPORTER* aWarningReporter )
494{
495 // Initialize OpenGL
497 {
498 if( !initializeOpenGL() )
499 return false;
500 }
501
503
505 {
506 std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
507
508 if( aStatusReporter )
509 aStatusReporter->Report( _( "Loading..." ) );
510
511 // Careful here!
512 // We are in the middle of rendering and the reload method may show
513 // a dialog box that requires the opengl context for a redraw
514 Pgm().GetGLContextManager()->RunWithoutCtxLock( [this, aStatusReporter, aWarningReporter]()
515 {
516 reload( aStatusReporter, aWarningReporter );
517 } );
518
519 // generate a new 3D grid as the size of the board may had changed
520 m_lastGridType = static_cast<GRID3D_TYPE>( cfg.grid_type );
522 }
523 else
524 {
525 // Check if grid was changed
526 if( cfg.grid_type != m_lastGridType )
527 {
528 // and generate a new one
529 m_lastGridType = static_cast<GRID3D_TYPE>( cfg.grid_type );
531 }
532 }
533
535
536 // Initial setup
537 glDepthFunc( GL_LESS );
538 glEnable( GL_CULL_FACE );
539 glFrontFace( GL_CCW ); // This is the OpenGL default
540 glEnable( GL_NORMALIZE ); // This allow OpenGL to normalize the normals after transformations
541 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
542
543 if( aIsMoving && cfg.opengl_AA_disableOnMove )
544 glDisable( GL_MULTISAMPLE );
545 else
546 glEnable( GL_MULTISAMPLE );
547
548 // clear color and depth buffers
549 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
550 glClearDepth( 1.0f );
551 glClearStencil( 0x00 );
552 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
553
555
556 // Draw the background ( rectangle with color gradient)
559
560 glEnable( GL_DEPTH_TEST );
561
562 // Set projection and modelview matrixes
563 glMatrixMode( GL_PROJECTION );
564 glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
565 glMatrixMode( GL_MODELVIEW );
566 glLoadIdentity();
567 glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
568
569 // Position the headlight
570 setLightFront( true );
571 setLightTop( true );
572 setLightBottom( true );
573
574 glEnable( GL_LIGHTING );
575
576 {
577 const SFVEC3F& cameraPos = m_camera.GetPos();
578
579 // Place the light at a minimum Z so the diffuse factor will not drop
580 // and the board will still look with good light.
581 float zpos;
582
583 if( cameraPos.z > 0.0f )
584 zpos = glm::max( cameraPos.z, 0.5f ) + cameraPos.z * cameraPos.z;
585 else
586 zpos = glm::min( cameraPos.z,-0.5f ) - cameraPos.z * cameraPos.z;
587
588 // This is a point light.
589 const GLfloat headlight_pos[] = { cameraPos.x, cameraPos.y, zpos, 1.0f };
590
591 glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
592 }
593
594 bool skipThickness = aIsMoving && cfg.opengl_thickness_disableOnMove;
595 bool skipRenderHoles = aIsMoving && cfg.opengl_holes_disableOnMove;
596 bool skipRenderMicroVias = aIsMoving && cfg.opengl_microvias_disableOnMove;
597 bool showThickness = !skipThickness;
598
599 std::bitset<LAYER_3D_END> layerFlags = m_boardAdapter.GetVisibleLayers();
600
602
603 if( !( skipRenderMicroVias || skipRenderHoles ) && m_microviaHoles )
605
606 if( !skipRenderHoles && m_padHoles )
608
609 // Display copper and tech layers
610 for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
611 {
612 const PCB_LAYER_ID layer = ( PCB_LAYER_ID )( ii->first );
613 bool isSilkLayer = layer == F_SilkS || layer == B_SilkS;
614 bool isMaskLayer = layer == F_Mask || layer == B_Mask;
615 bool isPasteLayer = layer == F_Paste || layer == B_Paste;
616
617 // Mask layers are not processed here because they are a special case
618 if( isMaskLayer )
619 continue;
620
621 // Do not show inner layers when it is displaying the board and board body is opaque
622 // enough: the time to create inner layers can be *really significant*.
623 // So avoid creating them is they are not very visible
624 const double opacity_min = 0.8;
625
626 if( layerFlags.test( LAYER_3D_BOARD ) && m_boardAdapter.m_BoardBodyColor.a > opacity_min )
627 {
628 // generating internal copper layers is time consuming. so skip them
629 // if the board body is masking them (i.e. if the opacity is near 1.0)
630 // B_Cu is layer 2 and all inner layers are higher values
631 if( layer > B_Cu && IsCopperLayer( layer ) )
632 continue;
633 }
634
635 glPushMatrix();
636
637 OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
638
639 if( IsCopperLayer( layer ) )
640 {
641 if( cfg.DifferentiatePlatedCopper() )
643 else
644 setLayerMaterial( layer );
645
646 OPENGL_RENDER_LIST* outerTH = nullptr;
647 OPENGL_RENDER_LIST* viaHoles = nullptr;
648
649 if( !skipRenderHoles )
650 {
651 outerTH = m_outerThroughHoles;
652 viaHoles = m_outerLayerHoles[layer];
653 }
654
655 if( m_antiBoard )
656 m_antiBoard->ApplyScalePosition( pLayerDispList );
657
658 if( outerTH )
659 outerTH->ApplyScalePosition( pLayerDispList );
660
661 pLayerDispList->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
662
663 // Draw plated & offboard pads
664 if( layer == F_Cu && ( m_platedPadsFront || m_offboardPadsFront ) )
665 {
667
669 m_platedPadsFront->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
670
672 m_offboardPadsFront->DrawCulled( showThickness, outerTH, viaHoles );
673 }
674 else if( layer == B_Cu && ( m_platedPadsBack || m_offboardPadsBack ) )
675 {
677
678 if( m_platedPadsBack )
679 m_platedPadsBack->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
680
682 m_offboardPadsBack->DrawCulled( showThickness, outerTH, viaHoles );
683 }
684
686 }
687 else
688 {
689 setLayerMaterial( layer );
690
691 OPENGL_RENDER_LIST* throughHolesOuter = nullptr;
692 OPENGL_RENDER_LIST* anti_board = nullptr;
693 OPENGL_RENDER_LIST* solder_mask = nullptr;
694
695 if( !skipRenderHoles )
696 {
697 if( isSilkLayer && cfg.clip_silk_on_via_annuli )
698 throughHolesOuter = m_outerThroughHoleRings;
699 else
700 throughHolesOuter = m_outerThroughHoles;
701 }
702
703 if( isSilkLayer && cfg.show_off_board_silk )
704 anti_board = nullptr;
705 else if( LSET::PhysicalLayersMask().test( layer ) )
706 anti_board = m_antiBoard;
707
708 if( isSilkLayer && cfg.subtract_mask_from_silk && !cfg.show_off_board_silk )
709 solder_mask = m_layers[ ( layer == B_SilkS) ? B_Mask : F_Mask ];
710
711 if( throughHolesOuter )
712 throughHolesOuter->ApplyScalePosition( pLayerDispList );
713
714 if( anti_board )
715 anti_board->ApplyScalePosition( pLayerDispList );
716
717 if( solder_mask )
718 solder_mask->ApplyScalePosition( pLayerDispList );
719
720 pLayerDispList->DrawCulled( showThickness, solder_mask, throughHolesOuter, anti_board );
721 }
722
723 glPopMatrix();
724 }
725
726 glm::mat4 cameraViewMatrix;
727
728 glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
729
730 // Render 3D Models (Non-transparent)
731 renderOpaqueModels( cameraViewMatrix );
732
733 // Display board body
734 if( layerFlags.test( LAYER_3D_BOARD ) )
735 renderBoardBody( skipRenderHoles );
736
737 // Display transparent mask layers
738 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP )
739 || layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
740 {
741 // add a depth buffer offset, it will help to hide some artifacts
742 // on silkscreen where the SolderMask is removed
743 glEnable( GL_POLYGON_OFFSET_FILL );
744 glPolygonOffset( 0.0f, -2.0f );
745
746 if( m_camera.GetPos().z > 0 )
747 {
748 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
749 {
751 showThickness, skipRenderHoles );
752 }
753
754 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
755 {
757 showThickness, skipRenderHoles );
758 }
759 }
760 else
761 {
762 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
763 {
765 showThickness, skipRenderHoles );
766 }
767
768 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
769 {
771 showThickness, skipRenderHoles );
772 }
773 }
774
775 glDisable( GL_POLYGON_OFFSET_FILL );
776 glPolygonOffset( 0.0f, 0.0f );
777 }
778
779 // Render 3D Models (Transparent)
780 // !TODO: this can be optimized. If there are no transparent models (or no opacity),
781 // then there is no need to make this function call.
782 glDepthMask( GL_FALSE );
783 glEnable( GL_BLEND );
784 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
785
786 // Enables Texture Env so it can combine model transparency with each footprint opacity
787 glEnable( GL_TEXTURE_2D );
788 glActiveTexture( GL_TEXTURE0 );
789
790 // Uses an existent texture so the glTexEnv operations will work.
791 glBindTexture( GL_TEXTURE_2D, m_circleTexture );
792
793 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
794 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
795 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
796
797 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
798 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
799
800 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
801 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
802
803 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
804 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
805 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
806 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
807
808 renderTransparentModels( cameraViewMatrix );
809
810 glDisable( GL_BLEND );
812
813 glDepthMask( GL_TRUE );
814
815 // Render Grid
816 if( cfg.grid_type != GRID3D_TYPE::NONE )
817 {
818 glDisable( GL_LIGHTING );
819
820 if( glIsList( m_grid ) )
821 glCallList( m_grid );
822
823 glEnable( GL_LIGHTING );
824 }
825
826 // Render 3D arrows
827 if( cfg.show_navigator )
829
830 // Return back to the original viewport (this is important if we want
831 // to take a screenshot after the render)
832 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
833
834 return false;
835}
836
837
839{
840 glEnable( GL_LINE_SMOOTH );
841 glShadeModel( GL_SMOOTH );
842
843 // 4-byte pixel alignment
844 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
845
846 // Initialize the open GL texture to draw the filled semi-circle of the segments
848
849 if( !circleImage )
850 return false;
851
852 unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
853
854 circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
855 ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
856 circleRadius,
857 0xFF );
858
859 IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
860
861 circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
862
863 m_circleTexture = OglLoadTexture( *circleImageBlured );
864
865 delete circleImageBlured;
866 circleImageBlured = nullptr;
867
868 delete circleImage;
869 circleImage = nullptr;
870
871 init_lights();
872
873 // Use this mode if you want see the triangle lines (debug proposes)
874 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
875 m_canvasInitialized = true;
876
877 return true;
878}
879
880
882{
883 glEnable( GL_COLOR_MATERIAL );
884 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
885
886 const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
887 const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
888 const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
889 const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
890
891 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
892 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
893
894 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
895 glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
896 glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
897}
898
899
901{
902#define DELETE_AND_FREE( ptr ) \
903 { \
904 delete ptr; \
905 ptr = nullptr; \
906 } \
907
908#define DELETE_AND_FREE_MAP( map ) \
909 { \
910 for( auto& [ layer, ptr ] : map ) \
911 delete ptr; \
912 \
913 map.clear(); \
914 }
915
916 if( glIsList( m_grid ) )
917 glDeleteLists( m_grid, 1 );
918
919 m_grid = 0;
920
922
927
930
932 delete list;
933
934 m_triangles.clear();
935
937
938 m_3dModelMatrixMap.clear();
939
943
947
950}
951
952
954 bool aShowThickness, bool aSkipRenderHoles )
955{
956 wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
957
958 if( m_board )
959 {
960 OPENGL_RENDER_LIST* solder_mask = m_layers[ aLayerID ];
961 OPENGL_RENDER_LIST* via_holes = aSkipRenderHoles ? nullptr : m_outerThroughHoles;
962
963 if( via_holes )
965
967
968 setLayerMaterial( aLayerID );
970 m_board->DrawCulled( aShowThickness, solder_mask, via_holes );
971 }
972}
973
974
975void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList, bool aGetTop,
976 bool aGetBot, bool aRenderTransparentOnly,
977 bool aRenderSelectedOnly )
978{
979 wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
980
981 if( !m_boardAdapter.GetBoard() )
982 return;
983
985
986 // Go for all footprints
988 {
989 bool highlight = false;
990
992 {
993 if( fp->IsSelected() )
994 highlight = true;
995
997 highlight = true;
998
999 if( aRenderSelectedOnly != highlight )
1000 continue;
1001 }
1002
1003 if( !fp->Models().empty() )
1004 {
1005 if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1006 {
1007 const bool isFlipped = fp->IsFlipped();
1008
1009 if( aGetTop == !isFlipped || aGetBot == isFlipped )
1010 get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly,
1011 highlight );
1012 }
1013 }
1014 }
1015}
1016
1017
1018void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
1019 const FOOTPRINT* aFootprint,
1020 bool aRenderTransparentOnly, bool aIsSelected )
1021{
1022 if( !aFootprint->Models().empty() )
1023 {
1024 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1025
1026 VECTOR2I pos = aFootprint->GetPosition();
1027
1028 glm::mat4 fpMatrix( 1.0f );
1029
1030 fpMatrix = glm::translate( fpMatrix, SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1031 -pos.y * m_boardAdapter.BiuTo3dUnits(),
1032 zpos ) );
1033
1034 if( !aFootprint->GetOrientation().IsZero() )
1035 {
1036 fpMatrix = glm::rotate( fpMatrix, (float) aFootprint->GetOrientation().AsRadians(),
1037 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1038 }
1039
1040 if( aFootprint->IsFlipped() )
1041 {
1042 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1043 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1044 }
1045
1046 double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1047
1048 fpMatrix = glm::scale( fpMatrix, SFVEC3F( modelunit_to_3d_units_factor ) );
1049
1050 // Get the list of model files for this model
1051 for( const FP_3DMODEL& sM : aFootprint->Models() )
1052 {
1053 if( !sM.m_Show || sM.m_Filename.empty() )
1054 continue;
1055
1056 // Check if the model is present in our cache map
1057 auto cache_i = m_3dModelMap.find( sM.m_Filename );
1058
1059 if( cache_i == m_3dModelMap.end() )
1060 continue;
1061
1062 if( const MODEL_3D* modelPtr = cache_i->second )
1063 {
1064 bool opaque = sM.m_Opacity >= 1.0;
1065
1066 if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1067 ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1068 {
1069 glm::mat4 modelworldMatrix = fpMatrix;
1070
1071 const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
1072 const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y,
1073 sM.m_Rotation.z );
1074 const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
1075
1076 std::vector<float> key = { offset.x, offset.y, offset.z,
1077 rotation.x, rotation.y, rotation.z,
1078 scale.x, scale.y, scale.z };
1079
1080 auto it = m_3dModelMatrixMap.find( key );
1081
1082 if( it != m_3dModelMatrixMap.end() )
1083 {
1084 modelworldMatrix *= it->second;
1085 }
1086 else
1087 {
1088 glm::mat4 mtx( 1.0f );
1089 mtx = glm::translate( mtx, offset );
1090 mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
1091 mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
1092 mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
1093 mtx = glm::scale( mtx, scale );
1094 m_3dModelMatrixMap[ key ] = mtx;
1095
1096 modelworldMatrix *= mtx;
1097 }
1098
1099 aDstRenderList.emplace_back( modelworldMatrix, modelPtr,
1100 aRenderTransparentOnly ? sM.m_Opacity : 1.0f,
1101 aRenderTransparentOnly,
1102 aFootprint->IsSelected() || aIsSelected );
1103 }
1104 }
1105 }
1106 }
1107}
1108
1109
1110void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
1111{
1113
1114 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1115
1116 glPushMatrix();
1117
1118 std::list<MODELTORENDER> renderList;
1119
1121 {
1122 renderList.clear();
1123
1124 get3dModelsSelected( renderList, true, true, false, true );
1125
1126 if( !renderList.empty() )
1127 {
1128 MODEL_3D::BeginDrawMulti( false );
1129
1130 for( const MODELTORENDER& mtr : renderList )
1131 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1132
1134 }
1135 }
1136
1137 renderList.clear();
1138 get3dModelsSelected( renderList, true, true, false, false );
1139
1140 if( !renderList.empty() )
1141 {
1143
1144 for( const MODELTORENDER& mtr : renderList )
1145 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1146
1148 }
1149
1150 glPopMatrix();
1151}
1152
1153
1154void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
1155{
1157
1158 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1159
1160 std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
1161
1163 {
1164 // Get Transparent Selected
1165 get3dModelsSelected( renderListModels, true, true, true, true );
1166 }
1167
1168 // Get Transparent Not Selected
1169 get3dModelsSelected( renderListModels, true, true, true, false );
1170
1171 if( renderListModels.empty() )
1172 return;
1173
1174 std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
1175
1176 transparentModelList.reserve( renderListModels.size() );
1177
1178 // Calculate the distance to the camera for each model
1179 const SFVEC3F &cameraPos = m_camera.GetPos();
1180
1181 for( const MODELTORENDER& mtr : renderListModels )
1182 {
1183 const BBOX_3D& bBox = mtr.m_model->GetBBox();
1184 const SFVEC3F& bBoxCenter = bBox.GetCenter();
1185 const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
1186
1187 const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
1188
1189 transparentModelList.emplace_back( &mtr, distanceToCamera );
1190 }
1191
1192 // Sort from back to front
1193 std::sort( transparentModelList.begin(), transparentModelList.end(),
1194 [&]( std::pair<const MODELTORENDER *, float>& a,
1195 std::pair<const MODELTORENDER *, float>& b )
1196 {
1197 if( a.second != b.second )
1198 return a.second > b.second;
1199
1200 return a.first > b.first; // use pointers as a last resort
1201 } );
1202
1203 // Start rendering calls
1204 glPushMatrix();
1205
1206 bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
1208
1209 MODEL_3D::BeginDrawMulti( isUsingColorInformation );
1210
1211 for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
1212 {
1214 {
1215 // Toggle between using model color or the select color
1216 if( !isUsingColorInformation && !mtr.first->m_isSelected )
1217 {
1218 isUsingColorInformation = true;
1219
1220 glEnableClientState( GL_COLOR_ARRAY );
1221 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1222 glEnable( GL_COLOR_MATERIAL );
1223 }
1224 else if( isUsingColorInformation && mtr.first->m_isSelected )
1225 {
1226 isUsingColorInformation = false;
1227
1228 glDisableClientState( GL_COLOR_ARRAY );
1229 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1230 glDisable( GL_COLOR_MATERIAL );
1231 }
1232 }
1233
1234 // Render model, sort each individuall material group
1235 // by passing cameraPos
1236 renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
1237 }
1238
1240
1241 glPopMatrix();
1242}
1243
1244
1245void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
1246 const MODELTORENDER &aModelToRender,
1247 const SFVEC3F &aSelColor, const SFVEC3F *aCameraWorldPos )
1248{
1250
1251 const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
1252
1253 glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
1254
1255 aModelToRender.m_model->Draw( aModelToRender.m_isTransparent, aModelToRender.m_opacity,
1256 aModelToRender.m_isSelected, aSelColor,
1257 &aModelToRender.m_modelWorldMat, aCameraWorldPos );
1258
1259 if( cfg.show_model_bbox )
1260 {
1261 const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
1262
1263 if( !wasBlendEnabled )
1264 {
1265 glEnable( GL_BLEND );
1266 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1267 }
1268
1269 glDisable( GL_LIGHTING );
1270
1271 glLineWidth( 1 );
1272 aModelToRender.m_model->DrawBboxes();
1273
1274 glLineWidth( 4 );
1275 aModelToRender.m_model->DrawBbox();
1276
1277 glEnable( GL_LIGHTING );
1278
1279 if( !wasBlendEnabled )
1280 glDisable( GL_BLEND );
1281 }
1282}
1283
1284
1286{
1287 if( glIsList( m_grid ) )
1288 glDeleteLists( m_grid, 1 );
1289
1290 m_grid = 0;
1291
1292 if( aGridType == GRID3D_TYPE::NONE )
1293 return;
1294
1295 m_grid = glGenLists( 1 );
1296
1297 if( !glIsList( m_grid ) )
1298 return;
1299
1300 glNewList( m_grid, GL_COMPILE );
1301
1302 glEnable( GL_BLEND );
1303 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1304
1305 const double zpos = 0.0;
1306
1307 // Color of grid lines
1308 const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1309
1310 // Color of grid lines every 5 lines
1311 const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTBLUE );
1312 const double scale = m_boardAdapter.BiuTo3dUnits();
1313 const GLfloat transparency = 0.35f;
1314
1315 double griSizeMM = 0.0;
1316
1317 switch( aGridType )
1318 {
1319 case GRID3D_TYPE::GRID_1MM: griSizeMM = 1.0; break;
1320 case GRID3D_TYPE::GRID_2P5MM: griSizeMM = 2.5; break;
1321 case GRID3D_TYPE::GRID_5MM: griSizeMM = 5.0; break;
1322 case GRID3D_TYPE::GRID_10MM: griSizeMM = 10.0; break;
1323
1324 default:
1325 case GRID3D_TYPE::NONE: return;
1326 }
1327
1328 glNormal3f( 0.0, 0.0, 1.0 );
1329
1330 const VECTOR2I brd_size = m_boardAdapter.GetBoardSize();
1331 VECTOR2I brd_center_pos = m_boardAdapter.GetBoardPos();
1332
1333 brd_center_pos.y = -brd_center_pos.y;
1334
1335 const int xsize = std::max( brd_size.x, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1336 const int ysize = std::max( brd_size.y, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1337
1338 // Grid limits, in 3D units
1339 double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1340 double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1341 double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1342 double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1343 double zmin = pcbIUScale.mmToIU( -50 ) * scale;
1344 double zmax = pcbIUScale.mmToIU( 100 ) * scale;
1345
1346 // Set rasterised line width (min value = 1)
1347 glLineWidth( 1 );
1348
1349 // Draw horizontal grid centered on 3D origin (center of the board)
1350 for( int ii = 0; ; ii++ )
1351 {
1352 if( (ii % 5) )
1353 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1354 else
1355 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1356 transparency );
1357
1358 const int delta = KiROUND( ii * griSizeMM * pcbIUScale.IU_PER_MM );
1359
1360 if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1361 {
1362 glBegin( GL_LINES );
1363 glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1364 glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1365 glEnd();
1366
1367 if( ii != 0 )
1368 {
1369 glBegin( GL_LINES );
1370 glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1371 glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1372 glEnd();
1373 }
1374 }
1375
1376 if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1377 {
1378 glBegin( GL_LINES );
1379 glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1380 glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1381 glEnd();
1382
1383 if( ii != 0 )
1384 {
1385 glBegin( GL_LINES );
1386 glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1387 glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1388 glEnd();
1389 }
1390 }
1391
1392 if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1393 break;
1394 }
1395
1396 // Draw vertical grid on Z axis
1397 glNormal3f( 0.0, -1.0, 0.0 );
1398
1399 // Draw vertical grid lines (parallel to Z axis)
1400 double posy = -brd_center_pos.y * scale;
1401
1402 for( int ii = 0; ; ii++ )
1403 {
1404 if( (ii % 5) )
1405 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1406 else
1407 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1408 transparency );
1409
1410 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM;
1411
1412 glBegin( GL_LINES );
1413 xmax = ( brd_center_pos.x + delta ) * scale;
1414
1415 glVertex3f( xmax, posy, zmin );
1416 glVertex3f( xmax, posy, zmax );
1417 glEnd();
1418
1419 if( ii != 0 )
1420 {
1421 glBegin( GL_LINES );
1422 xmin = ( brd_center_pos.x - delta ) * scale;
1423 glVertex3f( xmin, posy, zmin );
1424 glVertex3f( xmin, posy, zmax );
1425 glEnd();
1426 }
1427
1428 if( delta > xsize / 2.0f )
1429 break;
1430 }
1431
1432 // Draw horizontal grid lines on Z axis (parallel to X axis)
1433 for( int ii = 0; ; ii++ )
1434 {
1435 if( ii % 5 )
1436 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1437 else
1438 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1439
1440 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM * scale;
1441
1442 if( delta <= zmax )
1443 {
1444 // Draw grid lines on Z axis (positive Z axis coordinates)
1445 glBegin( GL_LINES );
1446 glVertex3f( xmin, posy, delta );
1447 glVertex3f( xmax, posy, delta );
1448 glEnd();
1449 }
1450
1451 if( delta <= -zmin && ( ii != 0 ) )
1452 {
1453 // Draw grid lines on Z axis (negative Z axis coordinates)
1454 glBegin( GL_LINES );
1455 glVertex3f( xmin, posy, -delta );
1456 glVertex3f( xmax, posy, -delta );
1457 glEnd();
1458 }
1459
1460 if( ( delta > zmax ) && ( delta > -zmin ) )
1461 break;
1462 }
1463
1464 glDisable( GL_BLEND );
1465
1466 glEndList();
1467}
GRID3D_TYPE
Grid types.
Definition: 3d_enums.h:54
Defines math related functions.
float mapf(float x, float in_min, float in_max, float out_min, float out_max)
Definition: 3d_math.h:133
SFVEC3F SphericalToCartesian(float aInclination, float aAzimuth)
https://en.wikipedia.org/wiki/Spherical_coordinate_system
Definition: 3d_math.h:43
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:73
std::map< int, COLOR4D > m_BoardEditorColors
list of colors used by the board editor
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
SFVEC4F m_BgColorTop
background top color
SFVEC4F m_ECO2Color
SFVEC4F GetLayerColor(int aLayerId) const
Get the technical color of a layer.
bool GetUseBoardEditorCopperLayerColors() const
SFVEC4F m_SolderPasteColor
in realistic mode: solder paste color
SFVEC4F m_UserDefinedLayerColor[45]
bool IsFootprintShown(FOOTPRINT_ATTR_T aFPAttributes) const
Test if footprint should be displayed in relation to attributes and the flags.
VECTOR2I GetBoardSize() const noexcept
Get the board size.
std::bitset< LAYER_3D_END > GetVisibleLayers() const
SFVEC4F m_SolderMaskColorBot
in realistic mode: solder mask color ( bot )
VECTOR2I GetBoardPos() const noexcept
Get the board center.
float GetLayerBottomZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the bottom z position.
SFVEC4F m_SolderMaskColorTop
in realistic mode: solder mask color ( top )
SFVEC4F GetColor(const COLOR4D &aColor) const
SFVEC4F m_CopperColor
in realistic mode: copper color
const BOARD * GetBoard() const noexcept
float GetFootprintZPos(bool aIsFlipped) const
Get the position of the footprint in 3d integer units considering if it is flipped or not.
float GetNonCopperLayerThickness() const noexcept
Get the non copper layers thickness (in 3D units).
float GetLayerTopZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the top z position.
EDA_3D_VIEWER_SETTINGS * m_Cfg
SFVEC4F m_SilkScreenColorTop
in realistic mode: SilkScreen color ( top )
SFVEC4F m_SilkScreenColorBot
in realistic mode: SilkScreen color ( bot )
float GetBoardBodyThickness() const noexcept
Get the board body thickness, including internal copper layers (in 3D units).
SFVEC4F m_BoardBodyColor
in realistic mode: FR4 board color
SFVEC4F m_UserCommentsColor
SFVEC4F m_ECO1Color
SFVEC4F m_UserDrawingsColor
SFVEC4F m_BgColorBot
background bottom color
const FOOTPRINTS & Footprints() const
Definition: board.h:358
A class used to derive camera objects from.
Definition: camera.h:103
glm::mat4 GetRotationMatrix() const
Get the rotation matrix to be applied in a transformation camera.
Definition: camera.cpp:241
const glm::mat4 & GetProjectionMatrix() const
Definition: camera.cpp:474
const SFVEC3F & GetPos() const
Definition: camera.h:136
const glm::mat4 & GetViewMatrix() const
Definition: camera.cpp:510
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:51
bool IsZero() const
Definition: eda_angle.h:136
double AsRadians() const
Definition: eda_angle.h:120
bool IsSelected() const
Definition: eda_item.h:127
EDA_ANGLE GetOrientation() const
Definition: footprint.h:230
bool IsFlipped() const
Definition: footprint.h:400
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:223
VECTOR2I GetPosition() const override
Definition: footprint.h:227
auto RunWithoutCtxLock(Func &&aFunction, Args &&... args)
Run the given function first releasing the GL context lock, then restoring it.
Manage an 8-bit channel image.
Definition: image.h:90
void CircleFilled(int aCx, int aCy, int aRadius, unsigned char aValue)
Definition: image.cpp:173
void EfxFilter_SkipCenter(IMAGE *aInImg, IMAGE_FILTER aFilterType, unsigned int aRadius)
Apply a filter to the input image and store it in the image class.
Definition: image.cpp:527
unsigned int GetHeight() const
Definition: image.h:214
unsigned int GetWidth() const
Definition: image.h:213
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
double r
Red component.
Definition: color4d.h:392
double g
Green component.
Definition: color4d.h:393
double b
Blue component.
Definition: color4d.h:394
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:680
void DrawBbox() const
Draw main bounding box of the model.
Definition: 3d_model.cpp:571
static void EndDrawMulti()
Cleanup render states after drawing multiple models.
Definition: 3d_model.cpp:405
void Draw(bool aTransparent, float aOpacity, bool aUseSelectedMaterial, const SFVEC3F &aSelectionColor, const glm::mat4 *aModelWorldMatrix, const SFVEC3F *aCameraWorldPos) const
Render the model into the current context.
Definition: 3d_model.cpp:418
static void BeginDrawMulti(bool aUseColorInformation)
Set some basic render states before drawing multiple models.
Definition: 3d_model.cpp:389
void DrawBboxes() const
Draw individual bounding boxes of each mesh.
Definition: 3d_model.cpp:590
Store the OpenGL display lists to related with a layer.
void ApplyScalePosition(float aZposition, float aZscale)
void SetItIsTransparent(bool aSetTransparent)
void DrawCulled(bool aDrawMiddle, const OPENGL_RENDER_LIST *aSubtractList=nullptr, const OPENGL_RENDER_LIST *bSubtractList=nullptr, const OPENGL_RENDER_LIST *cSubtractList=nullptr, const OPENGL_RENDER_LIST *dSubtractList=nullptr) const
Draw all layers if they are visible by the camera if camera position is above the layer.
void DrawAll(bool aDrawMiddle=true) const
Call to draw all the display lists.
GL_CONTEXT_MANAGER * GetGLContextManager()
Definition: pgm_base.h:115
This is a base class to hold data and functions for render targets.
std::unique_ptr< BUSY_INDICATOR > CreateBusyIndicator() const
Return a created busy indicator, if a factory has been set, else a null pointer.
bool m_canvasInitialized
Flag if the canvas specific for this render was already initialized.
wxSize m_windowSize
The window size that this camera is working.
BOARD_ADAPTER & m_boardAdapter
Settings reference in use for this render.
OPENGL_RENDER_LIST * m_board
OPENGL_RENDER_LIST * m_outerThroughHoleRings
OPENGL_RENDER_LIST * m_offboardPadsFront
SPHERES_GIZMO::GizmoSphereSelection getSelectedGizmoSphere() const
GRID3D_TYPE m_lastGridType
Stores the last grid type.
std::tuple< int, int, int, int > getGizmoViewport() const
OPENGL_RENDER_LIST * m_microviaHoles
void renderOpaqueModels(const glm::mat4 &aCameraViewMatrix)
void generate3dGrid(GRID3D_TYPE aGridType)
Create a 3D grid to an OpenGL display list.
void setLightFront(bool enabled)
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
MAP_OGL_DISP_LISTS m_layers
MAP_OGL_DISP_LISTS m_innerLayerHoles
OPENGL_RENDER_LIST * m_boardWithHoles
RENDER_3D_OPENGL(EDA_3D_CANVAS *aCanvas, BOARD_ADAPTER &aAdapter, CAMERA &aCamera)
MAP_OGL_DISP_LISTS m_outerLayerHoles
OPENGL_RENDER_LIST * m_offboardPadsBack
BOARD_ITEM * m_currentRollOverItem
void renderBoardBody(bool aSkipRenderHoles)
std::map< std::vector< float >, glm::mat4 > m_3dModelMatrixMap
std::map< wxString, MODEL_3D * > m_3dModelMap
LIST_TRIANGLES m_triangles
store pointers so can be deleted latter
OPENGL_RENDER_LIST * m_outerViaThroughHoles
OPENGL_RENDER_LIST * m_outerThroughHoles
void setLayerMaterial(PCB_LAYER_ID aLayerID)
OPENGL_RENDER_LIST * m_platedPadsFront
void renderModel(const glm::mat4 &aCameraViewMatrix, const MODELTORENDER &aModelToRender, const SFVEC3F &aSelColor, const SFVEC3F *aCameraWorldPos)
int GetWaitForEditingTimeOut() override
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
void renderSolderMaskLayer(PCB_LAYER_ID aLayerID, float aZPos, bool aShowThickness, bool aSkipRenderHoles)
void renderTransparentModels(const glm::mat4 &aCameraViewMatrix)
void get3dModelsSelected(std::list< MODELTORENDER > &aDstRenderList, bool aGetTop, bool aGetBot, bool aRenderTransparentOnly, bool aRenderSelectedOnly)
void setPlatedCopperAndDepthOffset(PCB_LAYER_ID aLayer_id)
OPENGL_RENDER_LIST * m_antiBoard
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
OPENGL_RENDER_LIST * m_padHoles
SPHERES_GIZMO * m_spheres_gizmo
GLuint m_grid
oGL list that stores current grid
OPENGL_RENDER_LIST * m_platedPadsBack
void get3dModelsFromFootprint(std::list< MODELTORENDER > &aDstRenderList, const FOOTPRINT *aFootprint, bool aRenderTransparentOnly, bool aIsSelected)
struct RENDER_3D_OPENGL::@2 m_materials
void handleGizmoMouseInput(int mouseX, int mouseY)
void setLightBottom(bool enabled)
void setGizmoViewport(int x, int y, int width, int height)
void setLightTop(bool enabled)
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition: reporter.h:102
Renders a set of colored spheres in 3D space that act as a directional orientation gizmo.
GizmoSphereSelection
Enum to indicate which sphere (direction) is selected.
void handleMouseInput(int aMouseX, int aMouseY)
void render3dSpheresGizmo(glm::mat4 aCameraRotationMatrix)
GizmoSphereSelection getSelectedGizmoSphere() const
std::tuple< int, int, int, int > getViewport() const
void setViewport(int ax, int ay, int aWidth, int aHeight)
void resetSelectedGizmoSphere()
Store arrays of triangles to be used to create display lists.
@ LIGHTBLUE
Definition: color4d.h:62
@ DARKGRAY
Definition: color4d.h:46
#define DELETE_AND_FREE_MAP(map)
#define DELETE_AND_FREE(ptr)
#define _(s)
#define UNITS3D_TO_UNITSPCB
Implements a model viewer canvas.
FOOTPRINT_ATTR_T
The set of attributes allowed within a FOOTPRINT, using FOOTPRINT::SetAttributes() and FOOTPRINT::Get...
Definition: footprint.h:79
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
int MapPCBLayerTo3DLayer(PCB_LAYER_ID aLayer)
Definition: layer_id.cpp:332
@ LAYER_3D_USER_1
Definition: layer_ids.h:555
@ LAYER_3D_SOLDERMASK_TOP
Definition: layer_ids.h:548
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition: layer_ids.h:547
@ LAYER_3D_BOARD
Definition: layer_ids.h:542
@ LAYER_3D_USER_45
Definition: layer_ids.h:599
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:665
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ B_Adhes
Definition: layer_ids.h:103
@ Edge_Cuts
Definition: layer_ids.h:112
@ Dwgs_User
Definition: layer_ids.h:107
@ F_Paste
Definition: layer_ids.h:104
@ Cmts_User
Definition: layer_ids.h:108
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ Eco1_User
Definition: layer_ids.h:109
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ F_Fab
Definition: layer_ids.h:119
@ Margin
Definition: layer_ids.h:113
@ F_SilkS
Definition: layer_ids.h:100
@ B_CrtYd
Definition: layer_ids.h:115
@ Eco2_User
Definition: layer_ids.h:110
@ B_SilkS
Definition: layer_ids.h:101
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:118
void OglResetTextureState()
Reset to default state the texture settings.
Definition: ogl_utils.cpp:214
void OglSetMaterial(const SMATERIAL &aMaterial, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Set OpenGL materials.
Definition: ogl_utils.cpp:144
GLuint OglLoadTexture(const IMAGE &aImage)
Generate a new OpenGL texture.
Definition: ogl_utils.cpp:96
void OglDrawBackground(const SFVEC4F &aTopColor, const SFVEC4F &aBotColor)
Definition: ogl_utils.cpp:185
Define generic OpenGL functions that are common to any OpenGL target.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:902
see class PGM_BASE
void init_lights()
static SFVEC4F premultiplyAlpha(const SFVEC4F &aInput)
#define SIZE_OF_CIRCLE_TEXTURE
const int scale
Manage a bounding box defined by two SFVEC3F min max points.
Definition: bbox_3d.h:43
SFVEC3F GetCenter() const
Return the center point of the bounding box.
Definition: bbox_3d.cpp:132
bool DifferentiatePlatedCopper()
return true if platted copper aeras and non platted copper areas must be drawn using a different colo...
const double IU_PER_MM
Definition: base_units.h:76
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
int delta
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
glm::vec4 SFVEC4F
Definition: xv3d_types.h:46