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 CAMERA& aCamera ) :
54 RENDER_3D_BASE( aAdapter, aCamera ),
55 m_canvas( aCanvas )
56{
57 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
58
59 m_layers.clear();
60 m_outerLayerHoles.clear();
61 m_innerLayerHoles.clear();
62 m_triangles.clear();
63 m_board = nullptr;
64 m_antiBoard = nullptr;
65
66 m_platedPadsFront = nullptr;
67 m_platedPadsBack = nullptr;
68 m_offboardPadsFront = nullptr;
69 m_offboardPadsBack = nullptr;
70
71 m_outerThroughHoles = nullptr;
73 m_outerViaThroughHoles = nullptr;
74 m_microviaHoles = nullptr;
75 m_padHoles = nullptr;
76
78 m_grid = 0;
79 m_lastGridType = GRID3D_TYPE::NONE;
80 m_currentRollOverItem = nullptr;
81 m_boardWithHoles = nullptr;
82
83 m_3dModelMap.clear();
84
85 m_spheres_gizmo = new SPHERES_GIZMO( 4, 4 );
86}
87
88
90{
91 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
92
94
95 glDeleteTextures( 1, &m_circleTexture );
96}
97
98
100{
101 return 50; // ms
102}
103
104
105void RENDER_3D_OPENGL::SetCurWindowSize( const wxSize& aSize )
106{
107 if( m_windowSize != aSize )
108 {
109 int viewport[4];
110 int fbWidth, fbHeight;
111 glGetIntegerv( GL_VIEWPORT, viewport );
112
113 m_windowSize = aSize;
114 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
116 // Initialize here any screen dependent data here
117 }
118}
119
120
122{
123 if( enabled )
124 glEnable( GL_LIGHT0 );
125 else
126 glDisable( GL_LIGHT0 );
127}
128
129
131{
132 if( enabled )
133 glEnable( GL_LIGHT1 );
134 else
135 glDisable( GL_LIGHT1 );
136}
137
138
140{
141 if( enabled )
142 glEnable( GL_LIGHT2 );
143 else
144 glDisable( GL_LIGHT2 );
145}
146
147
149{
151}
152
153
155{
157}
158
159
160void RENDER_3D_OPENGL::setGizmoViewport( int x, int y, int width, int height )
161{
162 m_spheres_gizmo->setViewport( x, y, width, height );
163}
164
165
166std::tuple<int, int, int, int> RENDER_3D_OPENGL::getGizmoViewport() const
167{
169}
170
171
172void RENDER_3D_OPENGL::handleGizmoMouseInput( int mouseX, int mouseY )
173{
174 m_spheres_gizmo->handleMouseInput( mouseX, mouseY );
175}
176
177
179{
180 m_materials = {};
181
182 // http://devernay.free.fr/cours/opengl/materials.html
183
184 // Plated copper
185 // Copper material mixed with the copper color
186 m_materials.m_Copper.m_Ambient = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.1f,
189
190 m_materials.m_Copper.m_Specular = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.75f + 0.25f,
191 m_boardAdapter.m_CopperColor.g * 0.75f + 0.25f,
192 m_boardAdapter.m_CopperColor.b * 0.75f + 0.25f );
193
194 // This guess the material type(ex: copper vs gold) to determine the
195 // shininess factor between 0.1 and 0.4
196 float shininessfactor = 0.40f - mapf( fabs( m_boardAdapter.m_CopperColor.r -
198 0.15f, 1.00f,
199 0.00f, 0.30f );
200
201 m_materials.m_Copper.m_Shininess = shininessfactor * 128.0f;
202 m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
203
204
205 // Non plated copper (raw copper)
206 m_materials.m_NonPlatedCopper.m_Ambient = SFVEC3F( 0.191f, 0.073f, 0.022f );
207 m_materials.m_NonPlatedCopper.m_Diffuse = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f,
208 50.0f / 255.0f );
209 m_materials.m_NonPlatedCopper.m_Specular = SFVEC3F( 0.256f, 0.137f, 0.086f );
210 m_materials.m_NonPlatedCopper.m_Shininess = 0.1f * 128.0f;
211 m_materials.m_NonPlatedCopper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
212
213 // Paste material mixed with paste color
217
218 m_materials.m_Paste.m_Specular = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r *
224
225 m_materials.m_Paste.m_Shininess = 0.1f * 128.0f;
226 m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
227
228 // Silk screen material mixed with silk screen color
229 m_materials.m_SilkSTop.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorTop.r,
232
233 m_materials.m_SilkSTop.m_Specular = SFVEC3F(
237
238 m_materials.m_SilkSTop.m_Shininess = 0.078125f * 128.0f;
239 m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
240
241 // Silk screen material mixed with silk screen color
242 m_materials.m_SilkSBot.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorBot.r,
245
246 m_materials.m_SilkSBot.m_Specular = SFVEC3F(
250
251 m_materials.m_SilkSBot.m_Shininess = 0.078125f * 128.0f;
252 m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
253
254 m_materials.m_SolderMask.m_Shininess = 0.8f * 128.0f;
255 m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
256
257 // Epoxy material
258 m_materials.m_EpoxyBoard.m_Ambient = SFVEC3F( 117.0f / 255.0f, 97.0f / 255.0f,
259 47.0f / 255.0f );
260
261 m_materials.m_EpoxyBoard.m_Specular = SFVEC3F( 18.0f / 255.0f, 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
268
270{
272 {
273 COLOR4D copper_color = m_boardAdapter.m_BoardEditorColors[aLayerID];
274 m_materials.m_Copper.m_Diffuse = SFVEC3F( copper_color.r, copper_color.g,
275 copper_color.b );
276 OglSetMaterial( m_materials.m_Copper, 1.0f );
277 m_materials.m_NonPlatedCopper.m_Diffuse = m_materials.m_Copper.m_Diffuse;
278 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
279
280 return;
281 }
282
283 switch( aLayerID )
284 {
285 case F_Mask:
286 case B_Mask:
287 {
288 const SFVEC4F layerColor = aLayerID == F_Mask ? m_boardAdapter.m_SolderMaskColorTop
290
291 m_materials.m_SolderMask.m_Diffuse = layerColor;
292
293 // Convert Opacity to Transparency
294 m_materials.m_SolderMask.m_Transparency = 1.0f - layerColor.a;
295
296 m_materials.m_SolderMask.m_Ambient = m_materials.m_SolderMask.m_Diffuse * 0.3f;
297
298 m_materials.m_SolderMask.m_Specular = m_materials.m_SolderMask.m_Diffuse
299 * m_materials.m_SolderMask.m_Diffuse;
300
301 OglSetMaterial( m_materials.m_SolderMask, 1.0f );
302 break;
303 }
304
305 case B_Paste:
306 case F_Paste:
308 OglSetMaterial( m_materials.m_Paste, 1.0f );
309 break;
310
311 case B_SilkS:
312 m_materials.m_SilkSBot.m_Diffuse = m_boardAdapter.m_SilkScreenColorBot;
313 OglSetMaterial( m_materials.m_SilkSBot, 1.0f );
314 break;
315
316 case F_SilkS:
317 m_materials.m_SilkSTop.m_Diffuse = m_boardAdapter.m_SilkScreenColorTop;
318 OglSetMaterial( m_materials.m_SilkSTop, 1.0f );
319 break;
320
321 case B_Adhes:
322 case F_Adhes:
323 case Dwgs_User:
324 case Cmts_User:
325 case Eco1_User:
326 case Eco2_User:
327 case Edge_Cuts:
328 case Margin:
329 case B_CrtYd:
330 case F_CrtYd:
331 case B_Fab:
332 case F_Fab:
333 switch( aLayerID )
334 {
335 case Dwgs_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
336 case Cmts_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserCommentsColor; break;
337 case Eco1_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_ECO1Color; break;
338 case Eco2_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_ECO2Color; break;
339 case Edge_Cuts: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
340 case Margin: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
341 default:
342 m_materials.m_Plastic.m_Diffuse = m_boardAdapter.GetLayerColor( aLayerID );
343 break;
344 }
345
346 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
347 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
348 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
349
350 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
351 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
352 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
353
354 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
355 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
356 OglSetMaterial( m_materials.m_Plastic, 1.0f );
357 break;
358
359 default:
360 {
361 int layer3D = MapPCBLayerTo3DLayer( aLayerID );
362
363 // Note: MUST do this in LAYER_3D space; User_1..User_45 are NOT contiguous
364 if( layer3D >= LAYER_3D_USER_1 && layer3D <= LAYER_3D_USER_45 )
365 {
366 int user_idx = layer3D - LAYER_3D_USER_1;
367
368 m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDefinedLayerColor[ user_idx ];
369 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
370 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
371 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
372
373 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
374 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
375 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
376
377 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
378 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
379 OglSetMaterial( m_materials.m_Plastic, 1.0f );
380 break;
381 }
382
383 m_materials.m_Copper.m_Diffuse = m_boardAdapter.m_CopperColor;
384 OglSetMaterial( m_materials.m_Copper, 1.0f );
385 break;
386 }
387 }
388}
389
390
392{
393 // Setup light
394 // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
395 const GLfloat ambient[] = { 0.084f, 0.084f, 0.084f, 1.0f };
396 const GLfloat diffuse0[] = { 0.3f, 0.3f, 0.3f, 1.0f };
397 const GLfloat specular0[] = { 0.5f, 0.5f, 0.5f, 1.0f };
398
399 glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
400 glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse0 );
401 glLightfv( GL_LIGHT0, GL_SPECULAR, specular0 );
402
403 const GLfloat diffuse12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
404 const GLfloat specular12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
405
406 // defines a directional light that points along the negative z-axis
407 GLfloat position[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
408
409 // This makes a vector slight not perpendicular with XZ plane
410 const SFVEC3F vectorLight = SphericalToCartesian( glm::pi<float>() * 0.03f,
411 glm::pi<float>() * 0.25f );
412
413 position[0] = vectorLight.x;
414 position[1] = vectorLight.y;
415 position[2] = vectorLight.z;
416
417 glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
418 glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse12 );
419 glLightfv( GL_LIGHT1, GL_SPECULAR, specular12 );
420 glLightfv( GL_LIGHT1, GL_POSITION, position );
421
422 // defines a directional light that points along the positive z-axis
423 position[2] = -position[2];
424
425 glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
426 glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse12 );
427 glLightfv( GL_LIGHT2, GL_SPECULAR, specular12 );
428 glLightfv( GL_LIGHT2, GL_POSITION, position );
429
430 const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
431
432 glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
433
434 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
435}
436
437
439{
440 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
441}
442
443
445{
446 glEnable( GL_POLYGON_OFFSET_FILL );
447 glPolygonOffset( -0.1f, -2.0f );
448 setLayerMaterial( aLayer_id );
449}
450
451
453{
454 glDisable( GL_POLYGON_OFFSET_FILL );
455}
456
457
458void RENDER_3D_OPENGL::renderBoardBody( bool aSkipRenderHoles )
459{
460 m_materials.m_EpoxyBoard.m_Diffuse = m_boardAdapter.m_BoardBodyColor;
461
462 // opacity to transparency
463 m_materials.m_EpoxyBoard.m_Transparency = 1.0f - m_boardAdapter.m_BoardBodyColor.a;
464
465 OglSetMaterial( m_materials.m_EpoxyBoard, 1.0f );
466
467 OPENGL_RENDER_LIST* ogl_disp_list = nullptr;
468
469 if( aSkipRenderHoles )
470 ogl_disp_list = m_board;
471 else
472 ogl_disp_list = m_boardWithHoles;
473
474 if( ogl_disp_list )
475 {
478
479 ogl_disp_list->SetItIsTransparent( true );
480 ogl_disp_list->DrawAll();
481 }
482}
483
484
485static inline SFVEC4F premultiplyAlpha( const SFVEC4F& aInput )
486{
487 return SFVEC4F( aInput.r * aInput.a, aInput.g * aInput.a, aInput.b * aInput.a, aInput.a );
488}
489
490
491bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
492 REPORTER* aWarningReporter )
493{
494 // Initialize OpenGL
496 {
497 if( !initializeOpenGL() )
498 return false;
499 }
500
502
504 {
505 std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
506
507 if( aStatusReporter )
508 aStatusReporter->Report( _( "Loading..." ) );
509
510 // Careful here!
511 // We are in the middle of rendering and the reload method may show
512 // a dialog box that requires the opengl context for a redraw
513 Pgm().GetGLContextManager()->RunWithoutCtxLock( [this, aStatusReporter, aWarningReporter]()
514 {
515 reload( aStatusReporter, aWarningReporter );
516 } );
517
518 // generate a new 3D grid as the size of the board may had changed
519 m_lastGridType = static_cast<GRID3D_TYPE>( cfg.grid_type );
521 }
522 else
523 {
524 // Check if grid was changed
525 if( cfg.grid_type != m_lastGridType )
526 {
527 // and generate a new one
528 m_lastGridType = static_cast<GRID3D_TYPE>( cfg.grid_type );
530 }
531 }
532
534
535 // Initial setup
536 glDepthFunc( GL_LESS );
537 glEnable( GL_CULL_FACE );
538 glFrontFace( GL_CCW ); // This is the OpenGL default
539 glEnable( GL_NORMALIZE ); // This allow OpenGL to normalize the normals after transformations
540 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
541
542 if( aIsMoving && cfg.opengl_AA_disableOnMove )
543 glDisable( GL_MULTISAMPLE );
544 else
545 glEnable( GL_MULTISAMPLE );
546
547 // clear color and depth buffers
548 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
549 glClearDepth( 1.0f );
550 glClearStencil( 0x00 );
551 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
552
554
555 // Draw the background ( rectangle with color gradient)
558
559 glEnable( GL_DEPTH_TEST );
560
561 // Set projection and modelview matrixes
562 glMatrixMode( GL_PROJECTION );
563 glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
564 glMatrixMode( GL_MODELVIEW );
565 glLoadIdentity();
566 glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
567
568 // Position the headlight
569 setLightFront( true );
570 setLightTop( true );
571 setLightBottom( true );
572
573 glEnable( GL_LIGHTING );
574
575 {
576 const SFVEC3F& cameraPos = m_camera.GetPos();
577
578 // Place the light at a minimum Z so the diffuse factor will not drop
579 // and the board will still look with good light.
580 float zpos;
581
582 if( cameraPos.z > 0.0f )
583 zpos = glm::max( cameraPos.z, 0.5f ) + cameraPos.z * cameraPos.z;
584 else
585 zpos = glm::min( cameraPos.z,-0.5f ) - cameraPos.z * cameraPos.z;
586
587 // This is a point light.
588 const GLfloat headlight_pos[] = { cameraPos.x, cameraPos.y, zpos, 1.0f };
589
590 glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
591 }
592
593 bool skipThickness = aIsMoving && cfg.opengl_thickness_disableOnMove;
594 bool skipRenderHoles = aIsMoving && cfg.opengl_holes_disableOnMove;
595 bool skipRenderMicroVias = aIsMoving && cfg.opengl_microvias_disableOnMove;
596 bool showThickness = !skipThickness;
597
598 std::bitset<LAYER_3D_END> layerFlags = m_boardAdapter.GetVisibleLayers();
599
601
602 if( !( skipRenderMicroVias || skipRenderHoles ) && m_microviaHoles )
604
605 if( !skipRenderHoles && m_padHoles )
607
608 // Display copper and tech layers
609 for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
610 {
611 const PCB_LAYER_ID layer = ( PCB_LAYER_ID )( ii->first );
612 bool isSilkLayer = layer == F_SilkS || layer == B_SilkS;
613 bool isMaskLayer = layer == F_Mask || layer == B_Mask;
614 bool isPasteLayer = layer == F_Paste || layer == B_Paste;
615
616 // Mask layers are not processed here because they are a special case
617 if( isMaskLayer )
618 continue;
619
620 // Do not show inner layers when it is displaying the board and board body is opaque
621 // enough: the time to create inner layers can be *really significant*.
622 // So avoid creating them is they are not very visible
623 const double opacity_min = 0.8;
624
625 if( layerFlags.test( LAYER_3D_BOARD ) && m_boardAdapter.m_BoardBodyColor.a > opacity_min )
626 {
627 // generating internal copper layers is time consuming. so skip them
628 // if the board body is masking them (i.e. if the opacity is near 1.0)
629 // B_Cu is layer 2 and all inner layers are higher values
630 if( layer > B_Cu && IsCopperLayer( layer ) )
631 continue;
632 }
633
634 glPushMatrix();
635
636 OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
637
638 if( IsCopperLayer( layer ) )
639 {
640 if( cfg.DifferentiatePlatedCopper() )
642 else
643 setLayerMaterial( layer );
644
645 OPENGL_RENDER_LIST* outerTH = nullptr;
646 OPENGL_RENDER_LIST* viaHoles = nullptr;
647
648 if( !skipRenderHoles )
649 {
650 outerTH = m_outerThroughHoles;
651 viaHoles = m_outerLayerHoles[layer];
652 }
653
654 if( m_antiBoard )
655 m_antiBoard->ApplyScalePosition( pLayerDispList );
656
657 if( outerTH )
658 outerTH->ApplyScalePosition( pLayerDispList );
659
660 pLayerDispList->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
661
662 // Draw plated & offboard pads
663 if( layer == F_Cu && ( m_platedPadsFront || m_offboardPadsFront ) )
664 {
666
668 m_platedPadsFront->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
669
671 m_offboardPadsFront->DrawCulled( showThickness, outerTH, viaHoles );
672 }
673 else if( layer == B_Cu && ( m_platedPadsBack || m_offboardPadsBack ) )
674 {
676
677 if( m_platedPadsBack )
678 m_platedPadsBack->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
679
681 m_offboardPadsBack->DrawCulled( showThickness, outerTH, viaHoles );
682 }
683
685 }
686 else
687 {
688 setLayerMaterial( layer );
689
690 OPENGL_RENDER_LIST* throughHolesOuter = nullptr;
691 OPENGL_RENDER_LIST* anti_board = nullptr;
692 OPENGL_RENDER_LIST* solder_mask = nullptr;
693
694 if( !skipRenderHoles )
695 {
696 if( isSilkLayer && cfg.clip_silk_on_via_annuli )
697 throughHolesOuter = m_outerThroughHoleRings;
698 else
699 throughHolesOuter = m_outerThroughHoles;
700 }
701
702 if( isSilkLayer && cfg.show_off_board_silk )
703 anti_board = nullptr;
704 else if( LSET::PhysicalLayersMask().test( layer ) )
705 anti_board = m_antiBoard;
706
707 if( isSilkLayer && cfg.subtract_mask_from_silk && !cfg.show_off_board_silk )
708 solder_mask = m_layers[ ( layer == B_SilkS) ? B_Mask : F_Mask ];
709
710 if( throughHolesOuter )
711 throughHolesOuter->ApplyScalePosition( pLayerDispList );
712
713 if( anti_board )
714 anti_board->ApplyScalePosition( pLayerDispList );
715
716 if( solder_mask )
717 solder_mask->ApplyScalePosition( pLayerDispList );
718
719 pLayerDispList->DrawCulled( showThickness, solder_mask, throughHolesOuter, anti_board );
720 }
721
722 glPopMatrix();
723 }
724
725 glm::mat4 cameraViewMatrix;
726
727 glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
728
729 // Render 3D Models (Non-transparent)
730 renderOpaqueModels( cameraViewMatrix );
731
732 // Display board body
733 if( layerFlags.test( LAYER_3D_BOARD ) )
734 renderBoardBody( skipRenderHoles );
735
736 // Display transparent mask layers
737 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP )
738 || layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
739 {
740 // add a depth buffer offset, it will help to hide some artifacts
741 // on silkscreen where the SolderMask is removed
742 glEnable( GL_POLYGON_OFFSET_FILL );
743 glPolygonOffset( 0.0f, -2.0f );
744
745 if( m_camera.GetPos().z > 0 )
746 {
747 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
748 {
750 showThickness, skipRenderHoles );
751 }
752
753 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
754 {
756 showThickness, skipRenderHoles );
757 }
758 }
759 else
760 {
761 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
762 {
764 showThickness, skipRenderHoles );
765 }
766
767 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
768 {
770 showThickness, skipRenderHoles );
771 }
772 }
773
774 glDisable( GL_POLYGON_OFFSET_FILL );
775 glPolygonOffset( 0.0f, 0.0f );
776 }
777
778 // Render 3D Models (Transparent)
779 // !TODO: this can be optimized. If there are no transparent models (or no opacity),
780 // then there is no need to make this function call.
781 glDepthMask( GL_FALSE );
782 glEnable( GL_BLEND );
783 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
784
785 // Enables Texture Env so it can combine model transparency with each footprint opacity
786 glEnable( GL_TEXTURE_2D );
787 glActiveTexture( GL_TEXTURE0 );
788
789 // Uses an existent texture so the glTexEnv operations will work.
790 glBindTexture( GL_TEXTURE_2D, m_circleTexture );
791
792 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
793 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
794 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
795
796 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
797 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
798
799 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
800 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
801
802 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
803 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
804 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
805 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
806
807 renderTransparentModels( cameraViewMatrix );
808
809 glDisable( GL_BLEND );
811
812 glDepthMask( GL_TRUE );
813
814 // Render Grid
815 if( cfg.grid_type != GRID3D_TYPE::NONE )
816 {
817 glDisable( GL_LIGHTING );
818
819 if( glIsList( m_grid ) )
820 glCallList( m_grid );
821
822 glEnable( GL_LIGHTING );
823 }
824
825 // Render 3D arrows
826 if( cfg.show_navigator )
828
829 // Return back to the original viewport (this is important if we want
830 // to take a screenshot after the render)
831 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
832
833 return false;
834}
835
836
838{
839 glEnable( GL_LINE_SMOOTH );
840 glShadeModel( GL_SMOOTH );
841
842 // 4-byte pixel alignment
843 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
844
845 // Initialize the open GL texture to draw the filled semi-circle of the segments
847
848 if( !circleImage )
849 return false;
850
851 unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
852
853 circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
854 ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
855 circleRadius,
856 0xFF );
857
858 IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
859
860 circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
861
862 m_circleTexture = OglLoadTexture( *circleImageBlured );
863
864 delete circleImageBlured;
865 circleImageBlured = nullptr;
866
867 delete circleImage;
868 circleImage = nullptr;
869
870 init_lights();
871
872 // Use this mode if you want see the triangle lines (debug proposes)
873 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
874 m_canvasInitialized = true;
875
876 return true;
877}
878
879
881{
882 glEnable( GL_COLOR_MATERIAL );
883 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
884
885 const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
886 const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
887 const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
888 const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
889
890 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
891 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
892
893 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
894 glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
895 glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
896}
897
898
900{
901#define DELETE_AND_FREE( ptr ) \
902 { \
903 delete ptr; \
904 ptr = nullptr; \
905 } \
906
907#define DELETE_AND_FREE_MAP( map ) \
908 { \
909 for( auto& [ layer, ptr ] : map ) \
910 delete ptr; \
911 \
912 map.clear(); \
913 }
914
915 if( glIsList( m_grid ) )
916 glDeleteLists( m_grid, 1 );
917
918 m_grid = 0;
919
921
926
929
931 delete list;
932
933 m_triangles.clear();
934
936
937 m_3dModelMatrixMap.clear();
938
942
946
949}
950
951
953 bool aShowThickness, bool aSkipRenderHoles )
954{
955 wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
956
957 if( m_board )
958 {
959 OPENGL_RENDER_LIST* solder_mask = m_layers[ aLayerID ];
960 OPENGL_RENDER_LIST* via_holes = aSkipRenderHoles ? nullptr : m_outerThroughHoles;
961
962 if( via_holes )
964
966
967 setLayerMaterial( aLayerID );
969 m_board->DrawCulled( aShowThickness, solder_mask, via_holes );
970 }
971}
972
973
974void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList, bool aGetTop,
975 bool aGetBot, bool aRenderTransparentOnly,
976 bool aRenderSelectedOnly )
977{
978 wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
979
980 if( !m_boardAdapter.GetBoard() )
981 return;
982
984
985 // Go for all footprints
987 {
988 bool highlight = false;
989
991 {
992 if( fp->IsSelected() )
993 highlight = true;
994
996 highlight = true;
997
998 if( aRenderSelectedOnly != highlight )
999 continue;
1000 }
1001
1002 if( !fp->Models().empty() )
1003 {
1004 if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1005 {
1006 const bool isFlipped = fp->IsFlipped();
1007
1008 if( aGetTop == !isFlipped || aGetBot == isFlipped )
1009 get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly,
1010 highlight );
1011 }
1012 }
1013 }
1014}
1015
1016
1017void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
1018 const FOOTPRINT* aFootprint,
1019 bool aRenderTransparentOnly, bool aIsSelected )
1020{
1021 if( !aFootprint->Models().empty() )
1022 {
1023 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1024
1025 VECTOR2I pos = aFootprint->GetPosition();
1026
1027 glm::mat4 fpMatrix( 1.0f );
1028
1029 fpMatrix = glm::translate( fpMatrix, SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1030 -pos.y * m_boardAdapter.BiuTo3dUnits(),
1031 zpos ) );
1032
1033 if( !aFootprint->GetOrientation().IsZero() )
1034 {
1035 fpMatrix = glm::rotate( fpMatrix, (float) aFootprint->GetOrientation().AsRadians(),
1036 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1037 }
1038
1039 if( aFootprint->IsFlipped() )
1040 {
1041 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1042 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1043 }
1044
1045 double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1046
1047 fpMatrix = glm::scale( fpMatrix, SFVEC3F( modelunit_to_3d_units_factor ) );
1048
1049 // Get the list of model files for this model
1050 for( const FP_3DMODEL& sM : aFootprint->Models() )
1051 {
1052 if( !sM.m_Show || sM.m_Filename.empty() )
1053 continue;
1054
1055 // Check if the model is present in our cache map
1056 auto cache_i = m_3dModelMap.find( sM.m_Filename );
1057
1058 if( cache_i == m_3dModelMap.end() )
1059 continue;
1060
1061 if( const MODEL_3D* modelPtr = cache_i->second )
1062 {
1063 bool opaque = sM.m_Opacity >= 1.0;
1064
1065 if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1066 ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1067 {
1068 glm::mat4 modelworldMatrix = fpMatrix;
1069
1070 const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
1071 const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y,
1072 sM.m_Rotation.z );
1073 const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
1074
1075 std::vector<float> key = { offset.x, offset.y, offset.z,
1076 rotation.x, rotation.y, rotation.z,
1077 scale.x, scale.y, scale.z };
1078
1079 auto it = m_3dModelMatrixMap.find( key );
1080
1081 if( it != m_3dModelMatrixMap.end() )
1082 {
1083 modelworldMatrix *= it->second;
1084 }
1085 else
1086 {
1087 glm::mat4 mtx( 1.0f );
1088 mtx = glm::translate( mtx, offset );
1089 mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
1090 mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
1091 mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
1092 mtx = glm::scale( mtx, scale );
1093 m_3dModelMatrixMap[ key ] = mtx;
1094
1095 modelworldMatrix *= mtx;
1096 }
1097
1098 aDstRenderList.emplace_back( modelworldMatrix, modelPtr,
1099 aRenderTransparentOnly ? sM.m_Opacity : 1.0f,
1100 aRenderTransparentOnly,
1101 aFootprint->IsSelected() || aIsSelected );
1102 }
1103 }
1104 }
1105 }
1106}
1107
1108
1109void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
1110{
1112
1113 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1114
1115 glPushMatrix();
1116
1117 std::list<MODELTORENDER> renderList;
1118
1120 {
1121 renderList.clear();
1122
1123 get3dModelsSelected( renderList, true, true, false, true );
1124
1125 if( !renderList.empty() )
1126 {
1127 MODEL_3D::BeginDrawMulti( false );
1128
1129 for( const MODELTORENDER& mtr : renderList )
1130 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1131
1133 }
1134 }
1135
1136 renderList.clear();
1137 get3dModelsSelected( renderList, true, true, false, false );
1138
1139 if( !renderList.empty() )
1140 {
1142
1143 for( const MODELTORENDER& mtr : renderList )
1144 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1145
1147 }
1148
1149 glPopMatrix();
1150}
1151
1152
1153void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
1154{
1156
1157 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1158
1159 std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
1160
1162 {
1163 // Get Transparent Selected
1164 get3dModelsSelected( renderListModels, true, true, true, true );
1165 }
1166
1167 // Get Transparent Not Selected
1168 get3dModelsSelected( renderListModels, true, true, true, false );
1169
1170 if( renderListModels.empty() )
1171 return;
1172
1173 std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
1174
1175 transparentModelList.reserve( renderListModels.size() );
1176
1177 // Calculate the distance to the camera for each model
1178 const SFVEC3F &cameraPos = m_camera.GetPos();
1179
1180 for( const MODELTORENDER& mtr : renderListModels )
1181 {
1182 const BBOX_3D& bBox = mtr.m_model->GetBBox();
1183 const SFVEC3F& bBoxCenter = bBox.GetCenter();
1184 const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
1185
1186 const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
1187
1188 transparentModelList.emplace_back( &mtr, distanceToCamera );
1189 }
1190
1191 // Sort from back to front
1192 std::sort( transparentModelList.begin(), transparentModelList.end(),
1193 [&]( std::pair<const MODELTORENDER *, float>& a,
1194 std::pair<const MODELTORENDER *, float>& b )
1195 {
1196 if( a.second != b.second )
1197 return a.second > b.second;
1198
1199 return a.first > b.first; // use pointers as a last resort
1200 } );
1201
1202 // Start rendering calls
1203 glPushMatrix();
1204
1205 bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
1207
1208 MODEL_3D::BeginDrawMulti( isUsingColorInformation );
1209
1210 for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
1211 {
1213 {
1214 // Toggle between using model color or the select color
1215 if( !isUsingColorInformation && !mtr.first->m_isSelected )
1216 {
1217 isUsingColorInformation = true;
1218
1219 glEnableClientState( GL_COLOR_ARRAY );
1220 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1221 glEnable( GL_COLOR_MATERIAL );
1222 }
1223 else if( isUsingColorInformation && mtr.first->m_isSelected )
1224 {
1225 isUsingColorInformation = false;
1226
1227 glDisableClientState( GL_COLOR_ARRAY );
1228 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1229 glDisable( GL_COLOR_MATERIAL );
1230 }
1231 }
1232
1233 // Render model, sort each individuall material group
1234 // by passing cameraPos
1235 renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
1236 }
1237
1239
1240 glPopMatrix();
1241}
1242
1243
1244void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
1245 const MODELTORENDER &aModelToRender,
1246 const SFVEC3F &aSelColor, const SFVEC3F *aCameraWorldPos )
1247{
1249
1250 const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
1251
1252 glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
1253
1254 aModelToRender.m_model->Draw( aModelToRender.m_isTransparent, aModelToRender.m_opacity,
1255 aModelToRender.m_isSelected, aSelColor,
1256 &aModelToRender.m_modelWorldMat, aCameraWorldPos );
1257
1258 if( cfg.show_model_bbox )
1259 {
1260 const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
1261
1262 if( !wasBlendEnabled )
1263 {
1264 glEnable( GL_BLEND );
1265 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1266 }
1267
1268 glDisable( GL_LIGHTING );
1269
1270 glLineWidth( 1 );
1271 aModelToRender.m_model->DrawBboxes();
1272
1273 glLineWidth( 4 );
1274 aModelToRender.m_model->DrawBbox();
1275
1276 glEnable( GL_LIGHTING );
1277
1278 if( !wasBlendEnabled )
1279 glDisable( GL_BLEND );
1280 }
1281}
1282
1283
1285{
1286 if( glIsList( m_grid ) )
1287 glDeleteLists( m_grid, 1 );
1288
1289 m_grid = 0;
1290
1291 if( aGridType == GRID3D_TYPE::NONE )
1292 return;
1293
1294 m_grid = glGenLists( 1 );
1295
1296 if( !glIsList( m_grid ) )
1297 return;
1298
1299 glNewList( m_grid, GL_COMPILE );
1300
1301 glEnable( GL_BLEND );
1302 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1303
1304 const double zpos = 0.0;
1305
1306 // Color of grid lines
1307 const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1308
1309 // Color of grid lines every 5 lines
1310 const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTBLUE );
1311 const double scale = m_boardAdapter.BiuTo3dUnits();
1312 const GLfloat transparency = 0.35f;
1313
1314 double griSizeMM = 0.0;
1315
1316 switch( aGridType )
1317 {
1318 case GRID3D_TYPE::GRID_1MM: griSizeMM = 1.0; break;
1319 case GRID3D_TYPE::GRID_2P5MM: griSizeMM = 2.5; break;
1320 case GRID3D_TYPE::GRID_5MM: griSizeMM = 5.0; break;
1321 case GRID3D_TYPE::GRID_10MM: griSizeMM = 10.0; break;
1322
1323 default:
1324 case GRID3D_TYPE::NONE: return;
1325 }
1326
1327 glNormal3f( 0.0, 0.0, 1.0 );
1328
1329 const VECTOR2I brd_size = m_boardAdapter.GetBoardSize();
1330 VECTOR2I brd_center_pos = m_boardAdapter.GetBoardPos();
1331
1332 brd_center_pos.y = -brd_center_pos.y;
1333
1334 const int xsize = std::max( brd_size.x, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1335 const int ysize = std::max( brd_size.y, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1336
1337 // Grid limits, in 3D units
1338 double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1339 double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1340 double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1341 double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1342 double zmin = pcbIUScale.mmToIU( -50 ) * scale;
1343 double zmax = pcbIUScale.mmToIU( 100 ) * scale;
1344
1345 // Set rasterised line width (min value = 1)
1346 glLineWidth( 1 );
1347
1348 // Draw horizontal grid centered on 3D origin (center of the board)
1349 for( int ii = 0; ; ii++ )
1350 {
1351 if( (ii % 5) )
1352 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1353 else
1354 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1355 transparency );
1356
1357 const int delta = KiROUND( ii * griSizeMM * pcbIUScale.IU_PER_MM );
1358
1359 if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1360 {
1361 glBegin( GL_LINES );
1362 glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1363 glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1364 glEnd();
1365
1366 if( ii != 0 )
1367 {
1368 glBegin( GL_LINES );
1369 glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1370 glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1371 glEnd();
1372 }
1373 }
1374
1375 if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1376 {
1377 glBegin( GL_LINES );
1378 glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1379 glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1380 glEnd();
1381
1382 if( ii != 0 )
1383 {
1384 glBegin( GL_LINES );
1385 glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1386 glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1387 glEnd();
1388 }
1389 }
1390
1391 if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1392 break;
1393 }
1394
1395 // Draw vertical grid on Z axis
1396 glNormal3f( 0.0, -1.0, 0.0 );
1397
1398 // Draw vertical grid lines (parallel to Z axis)
1399 double posy = -brd_center_pos.y * scale;
1400
1401 for( int ii = 0; ; ii++ )
1402 {
1403 if( (ii % 5) )
1404 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1405 else
1406 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1407 transparency );
1408
1409 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM;
1410
1411 glBegin( GL_LINES );
1412 xmax = ( brd_center_pos.x + delta ) * scale;
1413
1414 glVertex3f( xmax, posy, zmin );
1415 glVertex3f( xmax, posy, zmax );
1416 glEnd();
1417
1418 if( ii != 0 )
1419 {
1420 glBegin( GL_LINES );
1421 xmin = ( brd_center_pos.x - delta ) * scale;
1422 glVertex3f( xmin, posy, zmin );
1423 glVertex3f( xmin, posy, zmax );
1424 glEnd();
1425 }
1426
1427 if( delta > xsize / 2.0f )
1428 break;
1429 }
1430
1431 // Draw horizontal grid lines on Z axis (parallel to X axis)
1432 for( int ii = 0; ; ii++ )
1433 {
1434 if( ii % 5 )
1435 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1436 else
1437 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1438
1439 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM * scale;
1440
1441 if( delta <= zmax )
1442 {
1443 // Draw grid lines on Z axis (positive Z axis coordinates)
1444 glBegin( GL_LINES );
1445 glVertex3f( xmin, posy, delta );
1446 glVertex3f( xmax, posy, delta );
1447 glEnd();
1448 }
1449
1450 if( delta <= -zmin && ( ii != 0 ) )
1451 {
1452 // Draw grid lines on Z axis (negative Z axis coordinates)
1453 glBegin( GL_LINES );
1454 glVertex3f( xmin, posy, -delta );
1455 glVertex3f( xmax, posy, -delta );
1456 glEnd();
1457 }
1458
1459 if( ( delta > zmax ) && ( delta > -zmin ) )
1460 break;
1461 }
1462
1463 glDisable( GL_BLEND );
1464
1465 glEndList();
1466}
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:355
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:126
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:683
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:331
@ LAYER_3D_USER_1
Definition: layer_ids.h:554
@ LAYER_3D_SOLDERMASK_TOP
Definition: layer_ids.h:547
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition: layer_ids.h:546
@ LAYER_3D_BOARD
Definition: layer_ids.h:541
@ LAYER_3D_USER_45
Definition: layer_ids.h:598
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:663
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:893
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
constexpr int delta
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
glm::vec4 SFVEC4F
Definition: xv3d_types.h:46