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