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