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