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