KiCad PCB EDA Suite
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) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <cstdint>
26#include <gal/opengl/kiglew.h> // Must be included first
27
29#include "render_3d_opengl.h"
30#include "opengl_utils.h"
32#include <footprint.h>
33#include <3d_math.h>
34#include <glm/geometric.hpp>
35#include <math/util.h> // for KiROUND
36#include <utility>
37#include <vector>
38#include <wx/log.h>
39
40#include <base_units.h>
41
45#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
46
48 CAMERA& aCamera ) :
49 RENDER_3D_BASE( aCanvas, aAdapter, aCamera )
50{
51 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
52
53 m_layers.clear();
54 m_outerLayerHoles.clear();
55 m_innerLayerHoles.clear();
56 m_triangles.clear();
57 m_board = nullptr;
58 m_antiBoard = nullptr;
59
60 m_platedPadsFront = nullptr;
61 m_platedPadsBack = nullptr;
62
63 m_outerThroughHoles = nullptr;
65 m_outerViaThroughHoles = nullptr;
66 m_vias = nullptr;
67 m_padHoles = nullptr;
68
70 m_grid = 0;
72 m_currentRollOverItem = nullptr;
73 m_boardWithHoles = nullptr;
74
75 m_3dModelMap.clear();
76}
77
78
80{
81 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
82
84
85 glDeleteTextures( 1, &m_circleTexture );
86}
87
88
90{
91 return 50; // ms
92}
93
94
95void RENDER_3D_OPENGL::SetCurWindowSize( const wxSize& aSize )
96{
97 if( m_windowSize != aSize )
98 {
99 m_windowSize = aSize;
100 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
101
102 // Initialize here any screen dependent data here
103 }
104}
105
106
108{
109 if( enabled )
110 glEnable( GL_LIGHT0 );
111 else
112 glDisable( GL_LIGHT0 );
113}
114
115
117{
118 if( enabled )
119 glEnable( GL_LIGHT1 );
120 else
121 glDisable( GL_LIGHT1 );
122}
123
124
126{
127 if( enabled )
128 glEnable( GL_LIGHT2 );
129 else
130 glDisable( GL_LIGHT2 );
131}
132
133
135{
136 const float arrow_size = RANGE_SCALE_3D * 0.30f;
137
138 glDisable( GL_CULL_FACE );
139
140 // YxY squared view port, this is on propose
141 glViewport( 4, 4, m_windowSize.y / 8 , m_windowSize.y / 8 );
142 glClear( GL_DEPTH_BUFFER_BIT );
143
144 glMatrixMode( GL_PROJECTION );
145 glLoadIdentity();
146 gluPerspective( 45.0f, 1.0f, 0.001f, RANGE_SCALE_3D );
147
148 glMatrixMode( GL_MODELVIEW );
149 glLoadIdentity();
150
151 const glm::mat4 TranslationMatrix =
152 glm::translate( glm::mat4( 1.0f ), SFVEC3F( 0.0f, 0.0f, -( arrow_size * 2.75f ) ) );
153
154 const glm::mat4 ViewMatrix = TranslationMatrix * m_camera.GetRotationMatrix();
155
156 glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
157
159
160 glColor3f( 0.9f, 0.0f, 0.0f );
161 DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( arrow_size, 0.0f, 0.0f ), 0.275f );
162
163 glColor3f( 0.0f, 0.9f, 0.0f );
164 DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, arrow_size, 0.0f ), 0.275f );
165
166 glColor3f( 0.0f, 0.0f, 0.9f );
167 DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, 0.0f, arrow_size ), 0.275f );
168
169 glEnable( GL_CULL_FACE );
170}
171
172
174{
175 m_materials = {};
176
178 {
179 // http://devernay.free.fr/cours/opengl/materials.html
180
181 // Plated copper
182 // Copper material mixed with the copper color
183 m_materials.m_Copper.m_Ambient = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.1f,
186
187 m_materials.m_Copper.m_Specular = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.75f + 0.25f,
188 m_boardAdapter.m_CopperColor.g * 0.75f + 0.25f,
189 m_boardAdapter.m_CopperColor.b * 0.75f + 0.25f );
190
191 // This guess the material type(ex: copper vs gold) to determine the
192 // shininess factor between 0.1 and 0.4
193 float shininessfactor = 0.40f - mapf( fabs( m_boardAdapter.m_CopperColor.r -
195 0.15f, 1.00f,
196 0.00f, 0.30f );
197
198 m_materials.m_Copper.m_Shininess = shininessfactor * 128.0f;
199 m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
200
201
202 // Non plated copper (raw copper)
203 m_materials.m_NonPlatedCopper.m_Ambient = SFVEC3F( 0.191f, 0.073f, 0.022f );
204 m_materials.m_NonPlatedCopper.m_Diffuse = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f,
205 50.0f / 255.0f );
206 m_materials.m_NonPlatedCopper.m_Specular = SFVEC3F( 0.256f, 0.137f, 0.086f );
207 m_materials.m_NonPlatedCopper.m_Shininess = 0.1f * 128.0f;
208 m_materials.m_NonPlatedCopper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
209
210 // Paste material mixed with paste color
214
215 m_materials.m_Paste.m_Specular = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r *
221
222 m_materials.m_Paste.m_Shininess = 0.1f * 128.0f;
223 m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
224
225 // Silk screen material mixed with silk screen color
226 m_materials.m_SilkSTop.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorTop.r,
229
230 m_materials.m_SilkSTop.m_Specular = SFVEC3F(
232 0.10f,
234 0.10f,
236 0.10f );
237
238 m_materials.m_SilkSTop.m_Shininess = 0.078125f * 128.0f;
239 m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
240
241 // Silk screen material mixed with silk screen color
242 m_materials.m_SilkSBot.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorBot.r,
245
246 m_materials.m_SilkSBot.m_Specular = SFVEC3F(
248 0.10f,
250 0.10f,
252 0.10f );
253
254 m_materials.m_SilkSBot.m_Shininess = 0.078125f * 128.0f;
255 m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
256
257 m_materials.m_SolderMask.m_Shininess = 0.8f * 128.0f;
258 m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
259
260 // Epoxy material
261 m_materials.m_EpoxyBoard.m_Ambient = SFVEC3F( 117.0f / 255.0f, 97.0f / 255.0f,
262 47.0f / 255.0f );
263
264 m_materials.m_EpoxyBoard.m_Specular = SFVEC3F( 18.0f / 255.0f, 3.0f / 255.0f,
265 20.0f / 255.0f );
266
267 m_materials.m_EpoxyBoard.m_Shininess = 0.1f * 128.0f;
268 m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
269 }
270 else // Technical Mode
271 {
272 const SFVEC3F matAmbientColor = SFVEC3F( 0.10f );
273 const SFVEC3F matSpecularColor = SFVEC3F( 0.10f );
274 const float matShininess = 0.1f * 128.0f;
275
276 // Copper material
277 m_materials.m_Copper.m_Ambient = matAmbientColor;
278 m_materials.m_Copper.m_Specular = matSpecularColor;
279 m_materials.m_Copper.m_Shininess = matShininess;
280 m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
281
282 // Paste material
283 m_materials.m_Paste.m_Ambient = matAmbientColor;
284 m_materials.m_Paste.m_Specular = matSpecularColor;
285 m_materials.m_Paste.m_Shininess = matShininess;
286 m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
287
288 // Silk screen material
289 m_materials.m_SilkSTop.m_Ambient = matAmbientColor;
290 m_materials.m_SilkSTop.m_Specular = matSpecularColor;
291 m_materials.m_SilkSTop.m_Shininess = matShininess;
292 m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
293
294 // Silk screen material
295 m_materials.m_SilkSBot.m_Ambient = matAmbientColor;
296 m_materials.m_SilkSBot.m_Specular = matSpecularColor;
297 m_materials.m_SilkSBot.m_Shininess = matShininess;
298 m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
299
300 // Solder mask material
301 m_materials.m_SolderMask.m_Ambient = matAmbientColor;
302 m_materials.m_SolderMask.m_Specular = matSpecularColor;
303 m_materials.m_SolderMask.m_Shininess = matShininess;
304 m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
305
306 // Epoxy material
307 m_materials.m_EpoxyBoard.m_Ambient = matAmbientColor;
308 m_materials.m_EpoxyBoard.m_Specular = matSpecularColor;
309 m_materials.m_EpoxyBoard.m_Shininess = matShininess;
310 m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
311
312 // Gray material (used for example in technical vias and pad holes)
313 m_materials.m_GrayMaterial.m_Ambient = SFVEC3F( 0.8f, 0.8f, 0.8f );
314 m_materials.m_GrayMaterial.m_Diffuse = SFVEC3F( 0.3f, 0.3f, 0.3f );
315 m_materials.m_GrayMaterial.m_Specular = SFVEC3F( 0.4f, 0.4f, 0.4f );
316 m_materials.m_GrayMaterial.m_Shininess = 0.01f * 128.0f;
317 m_materials.m_GrayMaterial.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
318 }
319}
320
321
323{
324 switch( aLayerID )
325 {
326 case F_Mask:
327 case B_Mask:
328 {
329 const SFVEC4F layerColor = getLayerColor( aLayerID );
330
331 m_materials.m_SolderMask.m_Diffuse = layerColor;
332
333 // Convert Opacity to Transparency
334 m_materials.m_SolderMask.m_Transparency = 1.0f - layerColor.a;
335
337 {
338 m_materials.m_SolderMask.m_Ambient = m_materials.m_SolderMask.m_Diffuse * 0.3f;
339
340 m_materials.m_SolderMask.m_Specular =
341 m_materials.m_SolderMask.m_Diffuse * m_materials.m_SolderMask.m_Diffuse;
342 }
343
344 OglSetMaterial( m_materials.m_SolderMask, 1.0f );
345 break;
346 }
347
348 case B_Paste:
349 case F_Paste:
350 m_materials.m_Paste.m_Diffuse = getLayerColor( aLayerID );
351 OglSetMaterial( m_materials.m_Paste, 1.0f );
352 break;
353
354 case B_SilkS:
355 m_materials.m_SilkSBot.m_Diffuse = getLayerColor( aLayerID );
356 OglSetMaterial( m_materials.m_SilkSBot, 1.0f );
357 break;
358
359 case F_SilkS:
360 m_materials.m_SilkSTop.m_Diffuse = getLayerColor( aLayerID );
361 OglSetMaterial( m_materials.m_SilkSTop, 1.0f );
362 break;
363
364 case B_Adhes:
365 case F_Adhes:
366 case Dwgs_User:
367 case Cmts_User:
368 case Eco1_User:
369 case Eco2_User:
370 case Edge_Cuts:
371 case Margin:
372 case B_CrtYd:
373 case F_CrtYd:
374 case B_Fab:
375 case F_Fab:
376 m_materials.m_Plastic.m_Diffuse = getLayerColor( aLayerID );
377
378 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
379 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
380 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
381
382 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
383 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
384 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
385
386 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
387 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
388 OglSetMaterial( m_materials.m_Plastic, 1.0f );
389 break;
390
391 default:
392 m_materials.m_Copper.m_Diffuse = getLayerColor( aLayerID );
393 OglSetMaterial( m_materials.m_Copper, 1.0f );
394 break;
395 }
396}
397
398
400{
401 SFVEC4F layerColor = m_boardAdapter.GetLayerColor( aLayerID );
402
404 {
405 switch( aLayerID )
406 {
407 case B_Adhes:
408 case F_Adhes:
409 break;
410
411 case B_Mask:
413 break;
414 case F_Mask:
416 break;
417
418 case B_Paste:
419 case F_Paste:
421 break;
422
423 case B_SilkS:
425 break;
426 case F_SilkS:
428 break;
429
430 case Dwgs_User:
431 case Cmts_User:
432 case Eco1_User:
433 case Eco2_User:
434 case Edge_Cuts:
435 case Margin:
436 break;
437
438 case B_CrtYd:
439 case F_CrtYd:
440 break;
441
442 case B_Fab:
443 case F_Fab:
444 break;
445
446 default:
447 layerColor = m_boardAdapter.m_CopperColor;
448 break;
449 }
450 }
451
452 return layerColor;
453}
454
455
456void init_lights( void )
457{
458 // Setup light
459 // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
460 const GLfloat ambient[] = { 0.084f, 0.084f, 0.084f, 1.0f };
461 const GLfloat diffuse0[] = { 0.3f, 0.3f, 0.3f, 1.0f };
462 const GLfloat specular0[] = { 0.5f, 0.5f, 0.5f, 1.0f };
463
464 glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
465 glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse0 );
466 glLightfv( GL_LIGHT0, GL_SPECULAR, specular0 );
467
468 const GLfloat diffuse12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
469 const GLfloat specular12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
470
471 // defines a directional light that points along the negative z-axis
472 GLfloat position[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
473
474 // This makes a vector slight not perpendicular with XZ plane
475 const SFVEC3F vectorLight = SphericalToCartesian( glm::pi<float>() * 0.03f,
476 glm::pi<float>() * 0.25f );
477
478 position[0] = vectorLight.x;
479 position[1] = vectorLight.y;
480 position[2] = vectorLight.z;
481
482 glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
483 glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse12 );
484 glLightfv( GL_LIGHT1, GL_SPECULAR, specular12 );
485 glLightfv( GL_LIGHT1, GL_POSITION, position );
486
487 // defines a directional light that points along the positive z-axis
488 position[2] = -position[2];
489
490 glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
491 glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse12 );
492 glLightfv( GL_LIGHT2, GL_SPECULAR, specular12 );
493 glLightfv( GL_LIGHT2, GL_POSITION, position );
494
495 const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
496
497 glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
498
499 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
500}
501
502
504{
505 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
506}
507
508
510{
511 glEnable( GL_POLYGON_OFFSET_FILL );
512 glPolygonOffset( -0.1f, -2.0f );
513 setLayerMaterial( aLayer_id );
514}
515
516
518{
519 glDisable( GL_POLYGON_OFFSET_FILL );
520}
521
522
523void RENDER_3D_OPENGL::renderBoardBody( bool aSkipRenderHoles )
524{
525 m_materials.m_EpoxyBoard.m_Diffuse = m_boardAdapter.m_BoardBodyColor;
526
527 // opacity to transparency
528 m_materials.m_EpoxyBoard.m_Transparency = 1.0f - m_boardAdapter.m_BoardBodyColor.a;
529
530 OglSetMaterial( m_materials.m_EpoxyBoard, 1.0f );
531
532 OPENGL_RENDER_LIST* ogl_disp_list = nullptr;
533
534 if( aSkipRenderHoles )
535 ogl_disp_list = m_board;
536 else
537 ogl_disp_list = m_boardWithHoles;
538
539 if( ogl_disp_list )
540 {
543
544 ogl_disp_list->SetItIsTransparent( true );
545
546 ogl_disp_list->DrawAll();
547 }
548}
549
550
551bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
552 REPORTER* aWarningReporter )
553{
554 // Initialize OpenGL
556 {
557 if( !initializeOpenGL() )
558 return false;
559 }
560
562 {
563 std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
564
565 if( aStatusReporter )
566 aStatusReporter->Report( _( "Loading..." ) );
567
568 reload( aStatusReporter, aWarningReporter );
569
570 // generate a new 3D grid as the size of the board may had changed
573 }
574 else
575 {
576 // Check if grid was changed
578 {
579 // and generate a new one
582 }
583 }
584
586
587 // Initial setup
588 glDepthFunc( GL_LESS );
589 glEnable( GL_CULL_FACE );
590 glFrontFace( GL_CCW ); // This is the OpenGL default
591 glEnable( GL_NORMALIZE ); // This allow OpenGL to normalize the normals after transformations
592 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
593
595 glDisable( GL_MULTISAMPLE );
596 else
597 glEnable( GL_MULTISAMPLE );
598
599 // clear color and depth buffers
600 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
601 glClearDepth( 1.0f );
602 glClearStencil( 0x00 );
603 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
604
606
607 // Draw the background ( rectangle with color gradient)
610
611 glEnable( GL_DEPTH_TEST );
612
613 // Set projection and modelview matrixes
614 glMatrixMode( GL_PROJECTION );
615 glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
616 glMatrixMode( GL_MODELVIEW );
617 glLoadIdentity();
618 glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
619
620 // Position the headlight
621 setLightFront( true );
622 setLightTop( true );
623 setLightBottom( true );
624
625 glEnable( GL_LIGHTING );
626
627 {
628 const SFVEC3F& cameraPos = m_camera.GetPos();
629
630 // Place the light at a minimum Z so the diffuse factor will not drop
631 // and the board will still look with good light.
632 float zpos;
633
634 if( cameraPos.z > 0.0f )
635 zpos = glm::max( cameraPos.z, 0.5f ) + cameraPos.z * cameraPos.z;
636 else
637 zpos = glm::min( cameraPos.z,-0.5f ) - cameraPos.z * cameraPos.z;
638
639 // This is a point light.
640 const GLfloat headlight_pos[] = { cameraPos.x, cameraPos.y, zpos, 1.0f };
641
642 glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
643 }
644
645 bool skipThickness = aIsMoving && m_boardAdapter.m_Cfg->m_Render.opengl_thickness_disableOnMove;
646 bool skipRenderHoles = aIsMoving && m_boardAdapter.m_Cfg->m_Render.opengl_holes_disableOnMove;
647 bool skipRenderVias = aIsMoving && m_boardAdapter.m_Cfg->m_Render.opengl_vias_disableOnMove;
648
649 bool drawMiddleSegments = !skipThickness;
650
652 {
653 // Draw vias and pad holes with copper material
655 }
656 else
657 {
658 OglSetMaterial( m_materials.m_GrayMaterial, 1.0f );
659 }
660
661 if( !( skipRenderVias || skipRenderHoles ) && m_vias )
662 m_vias->DrawAll();
663
664 if( !skipRenderHoles && m_padHoles )
666
667 // Display copper and tech layers
668 for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
669 {
670 const PCB_LAYER_ID layer_id = ( PCB_LAYER_ID )( ii->first );
671
672 // Mask layers are not processed here because they are a special case
673 if( ( layer_id == B_Mask ) || ( layer_id == F_Mask ) )
674 continue;
675
676 // Do not show inner layers when it is displaying the board and board body is opaque
677 // enough: the time to create inner layers can be *really significant*.
678 // So avoid creating them is they are not very visible
679 const double opacity_min = 0.8;
680
682 && m_boardAdapter.m_BoardBodyColor.a > opacity_min )
683 {
684 if( ( layer_id > F_Cu ) && ( layer_id < B_Cu ) )
685 continue;
686 }
687
688 glPushMatrix();
689
690 OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
691
692 if( ( layer_id >= F_Cu ) && ( layer_id <= B_Cu ) )
693 {
696 {
698 }
699 else
700 {
701 setLayerMaterial( layer_id );
702 }
703
704 if( skipRenderHoles )
705 {
706 pLayerDispList->DrawAllCameraCulled( m_camera.GetPos().z, drawMiddleSegments );
707
708 // Draw plated pads
709 if( layer_id == F_Cu && m_platedPadsFront )
710 {
713 drawMiddleSegments );
714 }
715 else if( layer_id == B_Cu && m_platedPadsBack )
716 {
719 drawMiddleSegments );
720 }
721
723 }
724 else
725 {
727 {
729 pLayerDispList->GetZTop()
730 - pLayerDispList->GetZBot() );
731 }
732
733 if( m_antiBoard )
734 {
735 m_antiBoard->ApplyScalePosition( pLayerDispList->GetZBot(),
736 pLayerDispList->GetZTop()
737 - pLayerDispList->GetZBot() );
738 }
739
740 if( m_outerLayerHoles.find( layer_id ) != m_outerLayerHoles.end() )
741 {
742 const OPENGL_RENDER_LIST* viasHolesLayer = m_outerLayerHoles.at( layer_id );
743
744 wxASSERT( viasHolesLayer != nullptr );
745
746 if( viasHolesLayer != nullptr )
747 {
748 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
750 viasHolesLayer,
751 m_antiBoard );
752
753 // Draw plated pads
754 if( layer_id == F_Cu && m_platedPadsFront )
755 {
758 drawMiddleSegments,
760 viasHolesLayer,
761 m_antiBoard );
762 }
763 else if( layer_id == B_Cu && m_platedPadsBack )
764 {
767 drawMiddleSegments,
769 viasHolesLayer,
770 m_antiBoard );
771 }
772
774 }
775 }
776 else
777 {
778 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
780 m_antiBoard );
781
782 if( layer_id == F_Cu && m_platedPadsFront )
783 {
787 m_antiBoard );
788 }
789 else if( layer_id == B_Cu && m_platedPadsBack )
790 {
794 m_antiBoard );
795 }
796
798 }
799 }
800 }
801 else
802 {
803 setLayerMaterial( layer_id );
804
805 OPENGL_RENDER_LIST* throughHolesOuter =
808 && ( layer_id == B_SilkS || layer_id == F_SilkS ) ? m_outerThroughHoleRings
810
811 if( throughHolesOuter )
812 {
813 throughHolesOuter->ApplyScalePosition( pLayerDispList->GetZBot(),
814 pLayerDispList->GetZTop()
815 - pLayerDispList->GetZBot() );
816 }
817
818 OPENGL_RENDER_LIST* anti_board = m_antiBoard;
819
820 if( anti_board )
821 {
822 anti_board->ApplyScalePosition( pLayerDispList->GetZBot(),
823 pLayerDispList->GetZTop()
824 - pLayerDispList->GetZBot() );
825 }
826
827 if( !skipRenderHoles
830 && ( ( layer_id == B_SilkS && m_layers.find( B_Mask ) != m_layers.end() )
831 || ( layer_id == F_SilkS && m_layers.find( F_Mask ) != m_layers.end() ) ) )
832 {
833 const PCB_LAYER_ID layerMask_id = (layer_id == B_SilkS) ? B_Mask : F_Mask;
834
835 const OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( layerMask_id );
836
837 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
838 pLayerDispListMask,
839 throughHolesOuter, anti_board );
840 }
841 else
842 {
843 if( !skipRenderHoles && throughHolesOuter
844 && ( layer_id == B_SilkS || layer_id == F_SilkS ) )
845 {
846 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments, nullptr,
847 throughHolesOuter,
848 anti_board );
849 }
850 else
851 {
852 // Do not render Paste layers when skipRenderHoles is enabled
853 // otherwise it will cause z-fight issues
854 if( !( skipRenderHoles && ( layer_id == B_Paste || layer_id == F_Paste ) ) )
855 {
856 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
857 anti_board );
858 }
859 }
860 }
861 }
862
863 glPopMatrix();
864 }
865
866 glm::mat4 cameraViewMatrix;
867
868 glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
869
870 // Render 3D Models (Non-transparent)
871 renderOpaqueModels( cameraViewMatrix );
872
873 // Display board body
875 renderBoardBody( skipRenderHoles );
876
877 // Display transparent mask layers
879 {
880 // add a depth buffer offset, it will help to hide some artifacts
881 // on silkscreen where the SolderMask is removed
882 glEnable( GL_POLYGON_OFFSET_FILL );
883 glPolygonOffset( 0.0f, -2.0f );
884
885 if( m_camera.GetPos().z > 0 )
886 {
888 drawMiddleSegments, skipRenderHoles );
889
891 drawMiddleSegments, skipRenderHoles );
892 }
893 else
894 {
896 drawMiddleSegments, skipRenderHoles );
897
899 drawMiddleSegments, skipRenderHoles );
900 }
901
902 glDisable( GL_POLYGON_OFFSET_FILL );
903 glPolygonOffset( 0.0f, 0.0f );
904 }
905
906 // Render 3D Models (Transparent)
907 // !TODO: this can be optimized. If there are no transparent models (or no opacity),
908 // then there is no need to make this function call.
909 glDepthMask( GL_FALSE );
910 glEnable( GL_BLEND );
911 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
912
913 // Enables Texture Env so it can combine model transparency with each footprint opacity
914 glEnable( GL_TEXTURE_2D );
915 glActiveTexture( GL_TEXTURE0 );
916 glBindTexture( GL_TEXTURE_2D, m_circleTexture ); // Uses an existent texture so the glTexEnv operations will work
917
918 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
919 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
920 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
921
922 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
923 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
924
925 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
926 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
927
928 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
929 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
930 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
931 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
932
933 renderTransparentModels( cameraViewMatrix );
934
935 glDisable( GL_BLEND );
937
938 glDepthMask( GL_TRUE );
939
940 // Render Grid
942 {
943 glDisable( GL_LIGHTING );
944
945 if( glIsList( m_grid ) )
946 glCallList( m_grid );
947
948 glEnable( GL_LIGHTING );
949 }
950
951 // Render 3D arrows
954
955 // Return back to the original viewport (this is important if we want
956 // to take a screenshot after the render)
957 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
958
959 return false;
960}
961
962
964{
965 glEnable( GL_LINE_SMOOTH );
966 glShadeModel( GL_SMOOTH );
967
968 // 4-byte pixel alignment
969 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
970
971 // Initialize the open GL texture to draw the filled semi-circle of the segments
973
974 if( !circleImage )
975 return false;
976
977 unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
978
979 circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
980 ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
981 circleRadius,
982 0xFF );
983
984 IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
985
986 circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
987
988 m_circleTexture = OglLoadTexture( *circleImageBlured );
989
990 delete circleImageBlured;
991 circleImageBlured = nullptr;
992
993 delete circleImage;
994 circleImage = nullptr;
995
996 init_lights();
997
998 // Use this mode if you want see the triangle lines (debug proposes)
999 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1001
1002 return true;
1003}
1004
1005
1007{
1008 glEnable( GL_COLOR_MATERIAL );
1009 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1010
1011 const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1012 const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1013 const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1014 const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
1015
1016 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
1017 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
1018
1019 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
1020 glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
1021 glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
1022}
1023
1024
1026{
1027 if( glIsList( m_grid ) )
1028 glDeleteLists( m_grid, 1 );
1029
1030 m_grid = 0;
1031
1032 for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
1033 {
1034 OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1035 delete pLayerDispList;
1036 }
1037
1038 m_layers.clear();
1039
1040 delete m_platedPadsFront;
1041 m_platedPadsFront = nullptr;
1042
1043 delete m_platedPadsBack;
1044 m_platedPadsBack = nullptr;
1045
1046
1047 for( const std::pair<const PCB_LAYER_ID, OPENGL_RENDER_LIST*> entry : m_outerLayerHoles )
1048 delete entry.second;
1049
1050 m_outerLayerHoles.clear();
1051
1052 for( const std::pair<const PCB_LAYER_ID, OPENGL_RENDER_LIST*> entry : m_innerLayerHoles )
1053 delete entry.second;
1054
1055 m_innerLayerHoles.clear();
1056
1057 for( LIST_TRIANGLES::const_iterator ii = m_triangles.begin(); ii != m_triangles.end(); ++ii )
1058 delete *ii;
1059
1060 m_triangles.clear();
1061
1062 for( const std::pair<const wxString, MODEL_3D*>& entry : m_3dModelMap )
1063 delete entry.second;
1064
1065 m_3dModelMap.clear();
1066
1067 m_3dModelMatrixMap.clear();
1068
1069 delete m_board;
1070 m_board = nullptr;
1071
1072 delete m_boardWithHoles;
1073 m_boardWithHoles = nullptr;
1074
1075 delete m_antiBoard;
1076 m_antiBoard = nullptr;
1077
1078 delete m_outerThroughHoles;
1079 m_outerThroughHoles = nullptr;
1080
1082 m_outerViaThroughHoles = nullptr;
1083
1085 m_outerThroughHoleRings = nullptr;
1086
1087 delete m_vias;
1088 m_vias = nullptr;
1089
1090 delete m_padHoles;
1091 m_padHoles = nullptr;
1092}
1093
1094
1096 bool aDrawMiddleSegments, bool aSkipRenderHoles )
1097{
1098 wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
1099
1100 float nonCopperThickness = m_boardAdapter.GetNonCopperLayerThickness();
1101
1102 if( m_board )
1103 {
1104 if( m_layers.find( aLayerID ) != m_layers.end() )
1105 {
1106 OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( aLayerID );
1107
1109 m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1110
1111 m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1112
1113 setLayerMaterial( aLayerID );
1114
1115 m_board->SetItIsTransparent( true );
1116
1117 if( aSkipRenderHoles )
1118 {
1119 m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1120 }
1121 else
1122 {
1123 m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments, pLayerDispListMask,
1125 }
1126 }
1127 else
1128 {
1129 // This case there is no layer with mask, so we will render the full board as mask
1131 m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1132
1133 m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1134
1135 setLayerMaterial( aLayerID );
1136
1137 m_board->SetItIsTransparent( true );
1138
1139 if( aSkipRenderHoles )
1140 {
1141 m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1142 }
1143 else
1144 {
1145 m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments,
1147 }
1148 }
1149 }
1150}
1151
1152
1153void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
1154 bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
1155 bool aRenderSelectedOnly )
1156{
1157 wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
1158
1159 if( !m_boardAdapter.GetBoard() )
1160 return;
1161
1162 // Go for all footprints
1164 {
1165 bool highlight = false;
1166
1168 {
1169 if( fp->IsSelected() )
1170 highlight = true;
1171
1173 && fp == m_currentRollOverItem )
1174 {
1175 highlight = true;
1176 }
1177
1178 if( aRenderSelectedOnly != highlight )
1179 continue;
1180 }
1181
1182 if( !fp->Models().empty() )
1183 {
1184 if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1185 {
1186 const bool isFlipped = fp->IsFlipped();
1187
1188 if( ( aGetTop == !isFlipped ) ||
1189 ( aGetBot == isFlipped ) )
1190 get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly, highlight );
1191 }
1192 }
1193 }
1194}
1195
1196
1197void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
1198 const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
1199 bool aIsSelected )
1200{
1201 if( !aFootprint->Models().empty() )
1202 {
1203 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1204
1205 VECTOR2I pos = aFootprint->GetPosition();
1206
1207 glm::mat4 fpMatrix( 1.0f );
1208
1209 fpMatrix = glm::translate( fpMatrix,
1211 -pos.y * m_boardAdapter.BiuTo3dUnits(),
1212 zpos ) );
1213
1214 if( !aFootprint->GetOrientation().IsZero() )
1215 {
1216 fpMatrix = glm::rotate( fpMatrix,
1217 (float) aFootprint->GetOrientation().AsRadians(),
1218 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1219 }
1220
1221 if( aFootprint->IsFlipped() )
1222 {
1223 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1224 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1225 }
1226
1227 const double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() *
1229
1230 fpMatrix = glm::scale( fpMatrix,
1231 SFVEC3F( modelunit_to_3d_units_factor ) );
1232
1233 // Get the list of model files for this model
1234 for( const FP_3DMODEL& sM : aFootprint->Models() )
1235 {
1236 if( !sM.m_Show || sM.m_Filename.empty() )
1237 continue;
1238
1239 // Check if the model is present in our cache map
1240 auto cache_i = m_3dModelMap.find( sM.m_Filename );
1241
1242 if( cache_i == m_3dModelMap.end() )
1243 continue;
1244
1245 if( const MODEL_3D* modelPtr = cache_i->second )
1246 {
1247 bool opaque = sM.m_Opacity >= 1.0;
1248
1249 if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1250 ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1251 {
1252 glm::mat4 modelworldMatrix = fpMatrix;
1253
1254 const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
1255 const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z );
1256 const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
1257
1258 std::vector<float> key = { offset.x, offset.y, offset.z,
1259 rotation.x, rotation.y, rotation.z,
1260 scale.x, scale.y, scale.z };
1261
1262 auto it = m_3dModelMatrixMap.find( key );
1263
1264 if( it != m_3dModelMatrixMap.end() )
1265 {
1266 modelworldMatrix *= it->second;
1267 }
1268 else
1269 {
1270 glm::mat4 mtx( 1.0f );
1271 mtx = glm::translate( mtx, offset );
1272 mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
1273 mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
1274 mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
1275 mtx = glm::scale( mtx, scale );
1276 m_3dModelMatrixMap[ key ] = mtx;
1277
1278 modelworldMatrix *= mtx;
1279 }
1280
1281 if( aRenderTransparentOnly )
1282 {
1283 aDstRenderList.emplace_back( modelworldMatrix,
1284 modelPtr,
1285 sM.m_Opacity,
1286 true,
1287 aFootprint->IsSelected() || aIsSelected );
1288 }
1289 else
1290 {
1291 aDstRenderList.emplace_back( modelworldMatrix,
1292 modelPtr,
1293 1.0f,
1294 false,
1295 aFootprint->IsSelected() || aIsSelected );
1296 }
1297 }
1298 }
1299 }
1300 }
1301}
1302
1303
1304void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
1305{
1307
1308 glPushMatrix();
1309
1310 std::list<MODELTORENDER> renderList;
1311
1313 {
1314 renderList.clear();
1315
1316 get3dModelsSelected( renderList, true, true, false, true );
1317
1318 if( !renderList.empty() )
1319 {
1320 MODEL_3D::BeginDrawMulti( false );
1321
1322 for( const MODELTORENDER& mtr : renderList )
1323 {
1324 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1325 }
1326
1328 }
1329 }
1330
1331 renderList.clear();
1332 get3dModelsSelected( renderList, true, true, false, false );
1333
1334 if( !renderList.empty() )
1335 {
1337
1338 for( const MODELTORENDER& mtr : renderList )
1339 {
1340 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1341 }
1342
1344 }
1345
1346 glPopMatrix();
1347}
1348
1349
1350void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
1351{
1353
1354 std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
1355
1357 {
1358 // Get Transparent Selected
1359 get3dModelsSelected( renderListModels, true, true, true, true );
1360 }
1361
1362 // Get Transparent Not Selected
1363 get3dModelsSelected( renderListModels, true, true, true, false );
1364
1365 if( renderListModels.empty() )
1366 return;
1367
1368 std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
1369
1370 transparentModelList.reserve( renderListModels.size() );
1371
1372 // Calculate the distance to the camera for each model
1373 const SFVEC3F &cameraPos = m_camera.GetPos();
1374
1375 for( const MODELTORENDER& mtr : renderListModels )
1376 {
1377 const BBOX_3D& bBox = mtr.m_model->GetBBox();
1378 const SFVEC3F& bBoxCenter = bBox.GetCenter();
1379 const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
1380
1381 const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
1382
1383 transparentModelList.emplace_back( &mtr, distanceToCamera );
1384 }
1385
1386 // Sort from back to front
1387 std::sort( transparentModelList.begin(), transparentModelList.end(),
1388 [&]( std::pair<const MODELTORENDER *, float>& a,
1389 std::pair<const MODELTORENDER *, float>& b ) {
1390 return a.second > b.second;
1391 } );
1392
1393 // Start rendering calls
1394 glPushMatrix();
1395
1396 bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
1398
1399 MODEL_3D::BeginDrawMulti( isUsingColorInformation );
1400
1401 for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
1402 {
1404 {
1405 // Toggle between using model color or the select color
1406 if( !isUsingColorInformation && !mtr.first->m_isSelected )
1407 {
1408 isUsingColorInformation = true;
1409
1410 glEnableClientState( GL_COLOR_ARRAY );
1411 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1412 glEnable( GL_COLOR_MATERIAL );
1413 }
1414 else
1415 {
1416 if( isUsingColorInformation && mtr.first->m_isSelected )
1417 {
1418 isUsingColorInformation = false;
1419
1420 glDisableClientState( GL_COLOR_ARRAY );
1421 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1422 glDisable( GL_COLOR_MATERIAL );
1423 }
1424 }
1425 }
1426
1427 // Render model, sort each individuall material group
1428 // by passing cameraPos
1429 renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
1430 }
1431
1433
1434 glPopMatrix();
1435}
1436
1437
1438void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
1439 const MODELTORENDER &aModelToRender,
1440 const SFVEC3F &aSelColor,
1441 const SFVEC3F *aCameraWorldPos )
1442{
1443 const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
1444
1445 glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
1446
1447 aModelToRender.m_model->Draw( aModelToRender.m_isTransparent,
1448 aModelToRender.m_opacity,
1449 aModelToRender.m_isSelected,
1450 aSelColor,
1451 &aModelToRender.m_modelWorldMat,
1452 aCameraWorldPos );
1453
1455 {
1456 const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
1457
1458 if( !wasBlendEnabled )
1459 {
1460 glEnable( GL_BLEND );
1461 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1462 }
1463
1464 glDisable( GL_LIGHTING );
1465
1466 glLineWidth( 1 );
1467 aModelToRender.m_model->DrawBboxes();
1468
1469 glLineWidth( 4 );
1470 aModelToRender.m_model->DrawBbox();
1471
1472 glEnable( GL_LIGHTING );
1473
1474 if( !wasBlendEnabled )
1475 {
1476 glDisable( GL_BLEND );
1477 }
1478 }
1479}
1480
1481
1483{
1484 if( glIsList( m_grid ) )
1485 glDeleteLists( m_grid, 1 );
1486
1487 m_grid = 0;
1488
1489 if( aGridType == GRID3D_TYPE::NONE )
1490 return;
1491
1492 m_grid = glGenLists( 1 );
1493
1494 if( !glIsList( m_grid ) )
1495 return;
1496
1497 glNewList( m_grid, GL_COMPILE );
1498
1499 glEnable( GL_BLEND );
1500 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1501
1502 const double zpos = 0.0;
1503
1504 // Color of grid lines
1505 const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1506
1507 // Color of grid lines every 5 lines
1508 const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTBLUE );
1509 const double scale = m_boardAdapter.BiuTo3dUnits();
1510 const GLfloat transparency = 0.35f;
1511
1512 double griSizeMM = 0.0;
1513
1514 switch( aGridType )
1515 {
1516 default:
1517 case GRID3D_TYPE::NONE:
1518 return;
1520 griSizeMM = 1.0;
1521 break;
1523 griSizeMM = 2.5;
1524 break;
1526 griSizeMM = 5.0;
1527 break;
1529 griSizeMM = 10.0;
1530 break;
1531 }
1532
1533 glNormal3f( 0.0, 0.0, 1.0 );
1534
1535 const VECTOR2I brd_size = m_boardAdapter.GetBoardSize();
1536 VECTOR2I brd_center_pos = m_boardAdapter.GetBoardPos();
1537
1538 brd_center_pos.y = -brd_center_pos.y;
1539
1540 const int xsize = std::max( brd_size.x, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1541 const int ysize = std::max( brd_size.y, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1542
1543 // Grid limits, in 3D units
1544 double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1545 double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1546 double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1547 double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1548 double zmin = pcbIUScale.mmToIU( -50 ) * scale;
1549 double zmax = pcbIUScale.mmToIU( 100 ) * scale;
1550
1551 // Set rasterised line width (min value = 1)
1552 glLineWidth( 1 );
1553
1554 // Draw horizontal grid centered on 3D origin (center of the board)
1555 for( int ii = 0; ; ii++ )
1556 {
1557 if( (ii % 5) )
1558 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1559 else
1560 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1561 transparency );
1562
1563 const int delta = KiROUND( ii * griSizeMM * pcbIUScale.IU_PER_MM );
1564
1565 if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1566 {
1567 glBegin( GL_LINES );
1568 glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1569 glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1570 glEnd();
1571
1572 if( ii != 0 )
1573 {
1574 glBegin( GL_LINES );
1575 glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1576 glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1577 glEnd();
1578 }
1579 }
1580
1581 if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1582 {
1583 glBegin( GL_LINES );
1584 glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1585 glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1586 glEnd();
1587
1588 if( ii != 0 )
1589 {
1590 glBegin( GL_LINES );
1591 glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1592 glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1593 glEnd();
1594 }
1595 }
1596
1597 if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1598 break;
1599 }
1600
1601 // Draw vertical grid on Z axis
1602 glNormal3f( 0.0, -1.0, 0.0 );
1603
1604 // Draw vertical grid lines (parallel to Z axis)
1605 double posy = -brd_center_pos.y * scale;
1606
1607 for( int ii = 0; ; ii++ )
1608 {
1609 if( (ii % 5) )
1610 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1611 else
1612 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1613 transparency );
1614
1615 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM;
1616
1617 glBegin( GL_LINES );
1618 xmax = ( brd_center_pos.x + delta ) * scale;
1619
1620 glVertex3f( xmax, posy, zmin );
1621 glVertex3f( xmax, posy, zmax );
1622 glEnd();
1623
1624 if( ii != 0 )
1625 {
1626 glBegin( GL_LINES );
1627 xmin = ( brd_center_pos.x - delta ) * scale;
1628 glVertex3f( xmin, posy, zmin );
1629 glVertex3f( xmin, posy, zmax );
1630 glEnd();
1631 }
1632
1633 if( delta > xsize / 2.0f )
1634 break;
1635 }
1636
1637 // Draw horizontal grid lines on Z axis (parallel to X axis)
1638 for( int ii = 0; ; ii++ )
1639 {
1640 if( ii % 5 )
1641 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1642 else
1643 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1644
1645 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM * scale;
1646
1647 if( delta <= zmax )
1648 {
1649 // Draw grid lines on Z axis (positive Z axis coordinates)
1650 glBegin( GL_LINES );
1651 glVertex3f( xmin, posy, delta );
1652 glVertex3f( xmax, posy, delta );
1653 glEnd();
1654 }
1655
1656 if( delta <= -zmin && ( ii != 0 ) )
1657 {
1658 // Draw grid lines on Z axis (negative Z axis coordinates)
1659 glBegin( GL_LINES );
1660 glVertex3f( xmin, posy, -delta );
1661 glVertex3f( xmax, posy, -delta );
1662 glEnd();
1663 }
1664
1665 if( ( delta > zmax ) && ( delta > -zmin ) )
1666 break;
1667 }
1668
1669 glDisable( GL_BLEND );
1670
1671 glEndList();
1672}
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:109
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
Definition: board_adapter.h:62
Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:69
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
SFVEC4F m_BgColorTop
background top color
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.
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 GetLayerColor(PCB_LAYER_ID aLayerId) const
Get the technical color of a layer.
SFVEC4F m_BgColorBot
background bottom color
FOOTPRINTS & Footprints()
Definition: board.h:311
A class used to derive camera objects from.
Definition: camera.h:78
glm::mat4 GetRotationMatrix() const
Get the rotation matrix to be applied in a transformation camera.
Definition: camera.cpp:182
const glm::mat4 & GetProjectionMatrix() const
Definition: camera.cpp:414
const SFVEC3F & GetPos() const
Definition: camera.h:110
const glm::mat4 & GetViewMatrix() const
Definition: camera.cpp:450
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:49
bool IsZero() const
Definition: eda_angle.h:169
double AsRadians() const
Definition: eda_angle.h:153
bool IsSelected() const
Definition: eda_item.h:106
EDA_ANGLE GetOrientation() const
Definition: footprint.h:191
bool IsFlipped() const
Definition: footprint.h:324
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:184
VECTOR2I GetPosition() const override
Definition: footprint.h:188
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
void DrawBbox() const
Draw main bounding box of the model.
Definition: 3d_model.cpp:572
static void EndDrawMulti()
Cleanup render states after drawing multiple models.
Definition: 3d_model.cpp:405
void Draw(bool aTransparent, float aOpacity, bool aUseSelectedMaterial, const SFVEC3F &aSelectionColor, const glm::mat4 *aModelWorldMatrix, const SFVEC3F *aCameraWorldPos) const
Render the model into the current context.
Definition: 3d_model.cpp:418
static void BeginDrawMulti(bool aUseColorInformation)
Set some basic render states before drawing multiple models.
Definition: 3d_model.cpp:389
void DrawBboxes() const
Draw individual bounding boxes of each mesh.
Definition: 3d_model.cpp:591
Store the OpenGL display lists to related with a layer.
float GetZBot() const
float GetZTop() const
void DrawAllCameraCulledSubtractLayer(bool aDrawMiddle, const OPENGL_RENDER_LIST *aLayerToSubtractA=nullptr, const OPENGL_RENDER_LIST *aLayerToSubtractB=nullptr, const OPENGL_RENDER_LIST *aLayerToSubtractC=nullptr, const OPENGL_RENDER_LIST *aLayerToSubtractD=nullptr) const
void DrawAllCameraCulled(float zCameraPos, bool aDrawMiddle=true) const
Draw all layers if they are visible by the camera if camera position is above the layer.
void ApplyScalePosition(float aZposition, float aZscale)
void SetItIsTransparent(bool aSetTransparent)
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 opengl 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.
bool m_is_opengl_initialized
BOARD_ADAPTER & m_boardAdapter
OPENGL_RENDER_LIST * m_board
void reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
OPENGL_RENDER_LIST * m_vias
OPENGL_RENDER_LIST * m_outerThroughHoleRings
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
BOARD_ITEM * m_currentRollOverItem
void renderBoardBody(bool aSkipRenderHoles)
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)
std::map< wxString, MODEL_3D * > m_3dModelMap
OPENGL_RENDER_LIST * m_platedPadsFront
void renderSolderMaskLayer(PCB_LAYER_ID aLayerID, float aZPosition, bool aDrawMiddleSegments, bool aSkipRenderHoles)
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 renderTransparentModels(const glm::mat4 &aCameraViewMatrix)
std::map< std::vector< float >, glm::mat4 > m_3dModelMatrixMap
void get3dModelsSelected(std::list< MODELTORENDER > &aDstRenderList, bool aGetTop, bool aGetBot, bool aRenderTransparentOnly, bool aRenderSelectedOnly)
SFVEC4F getLayerColor(PCB_LAYER_ID aLayerID)
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.
@ LIGHTBLUE
Definition: color4d.h:60
@ DARKGRAY
Definition: color4d.h:44
#define _(s)
FOOTPRINT_ATTR_T
The set of attributes allowed within a FOOTPRINT, using FOOTPRINT::SetAttributes() and FOOTPRINT::Get...
Definition: footprint.h:67
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ 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:189
void OglDrawBackground(const SFVEC3F &aTopColor, const SFVEC3F &aBotColor)
Definition: ogl_utils.cpp:160
void OglSetMaterial(const SMATERIAL &aMaterial, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Set OpenGL materials.
Definition: ogl_utils.cpp:119
GLuint OglLoadTexture(const IMAGE &aImage)
Generate a new OpenGL texture.
Definition: ogl_utils.cpp:71
Define generic OpenGL functions that are common to any OpenGL target.
void DrawRoundArrow(SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize)
Draw a round arrow.
#define UNITS3D_TO_UNITSPCB
Scale conversion from 3d model units to pcb units.
void init_lights(void)
#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:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
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