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 <gal/opengl/kiglew.h> // Must be included first
26
27#include "render_3d_opengl.h"
28#include "opengl_utils.h"
30#include <footprint.h>
31#include <3d_math.h>
32#include <math/util.h> // for KiROUND
33#include <wx/log.h>
34
35#include <base_units.h>
36
40#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
41
43 CAMERA& aCamera ) :
44 RENDER_3D_BASE( aCanvas, aAdapter, aCamera )
45{
46 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
47
48 m_layers.clear();
49 m_outerLayerHoles.clear();
50 m_innerLayerHoles.clear();
51 m_triangles.clear();
52 m_board = nullptr;
53 m_antiBoard = nullptr;
54
55 m_platedPadsFront = nullptr;
56 m_platedPadsBack = nullptr;
57
58 m_outerThroughHoles = nullptr;
60 m_outerViaThroughHoles = nullptr;
61 m_vias = nullptr;
62 m_padHoles = nullptr;
63
65 m_grid = 0;
67 m_currentRollOverItem = nullptr;
68 m_boardWithHoles = nullptr;
69
70 m_3dModelMap.clear();
71}
72
73
75{
76 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
77
79
80 glDeleteTextures( 1, &m_circleTexture );
81}
82
83
85{
86 return 50; // ms
87}
88
89
90void RENDER_3D_OPENGL::SetCurWindowSize( const wxSize& aSize )
91{
92 if( m_windowSize != aSize )
93 {
94 m_windowSize = aSize;
95 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
96
97 // Initialize here any screen dependent data here
98 }
99}
100
101
103{
104 if( enabled )
105 glEnable( GL_LIGHT0 );
106 else
107 glDisable( GL_LIGHT0 );
108}
109
110
112{
113 if( enabled )
114 glEnable( GL_LIGHT1 );
115 else
116 glDisable( GL_LIGHT1 );
117}
118
119
121{
122 if( enabled )
123 glEnable( GL_LIGHT2 );
124 else
125 glDisable( GL_LIGHT2 );
126}
127
128
130{
131 const float arrow_size = RANGE_SCALE_3D * 0.30f;
132
133 glDisable( GL_CULL_FACE );
134
135 // YxY squared view port, this is on propose
136 glViewport( 4, 4, m_windowSize.y / 8 , m_windowSize.y / 8 );
137 glClear( GL_DEPTH_BUFFER_BIT );
138
139 glMatrixMode( GL_PROJECTION );
140 glLoadIdentity();
141 gluPerspective( 45.0f, 1.0f, 0.001f, RANGE_SCALE_3D );
142
143 glMatrixMode( GL_MODELVIEW );
144 glLoadIdentity();
145
146 const glm::mat4 TranslationMatrix =
147 glm::translate( glm::mat4( 1.0f ), SFVEC3F( 0.0f, 0.0f, -( arrow_size * 2.75f ) ) );
148
149 const glm::mat4 ViewMatrix = TranslationMatrix * m_camera.GetRotationMatrix();
150
151 glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
152
154
155 glColor3f( 0.9f, 0.0f, 0.0f );
156 DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( arrow_size, 0.0f, 0.0f ), 0.275f );
157
158 glColor3f( 0.0f, 0.9f, 0.0f );
159 DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, arrow_size, 0.0f ), 0.275f );
160
161 glColor3f( 0.0f, 0.0f, 0.9f );
162 DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, 0.0f, arrow_size ), 0.275f );
163
164 glEnable( GL_CULL_FACE );
165}
166
167
169{
170 m_materials = {};
171
173 {
174 // http://devernay.free.fr/cours/opengl/materials.html
175
176 // Plated copper
177 // Copper material mixed with the copper color
178 m_materials.m_Copper.m_Ambient = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.1f,
181
182 m_materials.m_Copper.m_Specular = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.75f + 0.25f,
183 m_boardAdapter.m_CopperColor.g * 0.75f + 0.25f,
184 m_boardAdapter.m_CopperColor.b * 0.75f + 0.25f );
185
186 // This guess the material type(ex: copper vs gold) to determine the
187 // shininess factor between 0.1 and 0.4
188 float shininessfactor = 0.40f - mapf( fabs( m_boardAdapter.m_CopperColor.r -
190 0.15f, 1.00f,
191 0.00f, 0.30f );
192
193 m_materials.m_Copper.m_Shininess = shininessfactor * 128.0f;
194 m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
195
196
197 // Non plated copper (raw copper)
198 m_materials.m_NonPlatedCopper.m_Ambient = SFVEC3F( 0.191f, 0.073f, 0.022f );
199 m_materials.m_NonPlatedCopper.m_Diffuse = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f,
200 50.0f / 255.0f );
201 m_materials.m_NonPlatedCopper.m_Specular = SFVEC3F( 0.256f, 0.137f, 0.086f );
202 m_materials.m_NonPlatedCopper.m_Shininess = 0.1f * 128.0f;
203 m_materials.m_NonPlatedCopper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
204
205 // Paste material mixed with paste color
209
210 m_materials.m_Paste.m_Specular = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r *
216
217 m_materials.m_Paste.m_Shininess = 0.1f * 128.0f;
218 m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
219
220 // Silk screen material mixed with silk screen color
221 m_materials.m_SilkSTop.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorTop.r,
224
225 m_materials.m_SilkSTop.m_Specular = SFVEC3F(
227 0.10f,
229 0.10f,
231 0.10f );
232
233 m_materials.m_SilkSTop.m_Shininess = 0.078125f * 128.0f;
234 m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
235
236 // Silk screen material mixed with silk screen color
237 m_materials.m_SilkSBot.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorBot.r,
240
241 m_materials.m_SilkSBot.m_Specular = SFVEC3F(
243 0.10f,
245 0.10f,
247 0.10f );
248
249 m_materials.m_SilkSBot.m_Shininess = 0.078125f * 128.0f;
250 m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
251
252 m_materials.m_SolderMask.m_Shininess = 0.8f * 128.0f;
253 m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
254
255 // Epoxy material
256 m_materials.m_EpoxyBoard.m_Ambient = SFVEC3F( 117.0f / 255.0f, 97.0f / 255.0f,
257 47.0f / 255.0f );
258
259 m_materials.m_EpoxyBoard.m_Specular = SFVEC3F( 18.0f / 255.0f, 3.0f / 255.0f,
260 20.0f / 255.0f );
261
262 m_materials.m_EpoxyBoard.m_Shininess = 0.1f * 128.0f;
263 m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
264 }
265 else // Technical Mode
266 {
267 const SFVEC3F matAmbientColor = SFVEC3F( 0.10f );
268 const SFVEC3F matSpecularColor = SFVEC3F( 0.10f );
269 const float matShininess = 0.1f * 128.0f;
270
271 // Copper material
272 m_materials.m_Copper.m_Ambient = matAmbientColor;
273 m_materials.m_Copper.m_Specular = matSpecularColor;
274 m_materials.m_Copper.m_Shininess = matShininess;
275 m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
276
277 // Paste material
278 m_materials.m_Paste.m_Ambient = matAmbientColor;
279 m_materials.m_Paste.m_Specular = matSpecularColor;
280 m_materials.m_Paste.m_Shininess = matShininess;
281 m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
282
283 // Silk screen material
284 m_materials.m_SilkSTop.m_Ambient = matAmbientColor;
285 m_materials.m_SilkSTop.m_Specular = matSpecularColor;
286 m_materials.m_SilkSTop.m_Shininess = matShininess;
287 m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
288
289 // Silk screen material
290 m_materials.m_SilkSBot.m_Ambient = matAmbientColor;
291 m_materials.m_SilkSBot.m_Specular = matSpecularColor;
292 m_materials.m_SilkSBot.m_Shininess = matShininess;
293 m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
294
295 // Solder mask material
296 m_materials.m_SolderMask.m_Ambient = matAmbientColor;
297 m_materials.m_SolderMask.m_Specular = matSpecularColor;
298 m_materials.m_SolderMask.m_Shininess = matShininess;
299 m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
300
301 // Epoxy material
302 m_materials.m_EpoxyBoard.m_Ambient = matAmbientColor;
303 m_materials.m_EpoxyBoard.m_Specular = matSpecularColor;
304 m_materials.m_EpoxyBoard.m_Shininess = matShininess;
305 m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
306
307 // Gray material (used for example in technical vias and pad holes)
308 m_materials.m_GrayMaterial.m_Ambient = SFVEC3F( 0.8f, 0.8f, 0.8f );
309 m_materials.m_GrayMaterial.m_Diffuse = SFVEC3F( 0.3f, 0.3f, 0.3f );
310 m_materials.m_GrayMaterial.m_Specular = SFVEC3F( 0.4f, 0.4f, 0.4f );
311 m_materials.m_GrayMaterial.m_Shininess = 0.01f * 128.0f;
312 m_materials.m_GrayMaterial.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
313 }
314}
315
316
318{
319 switch( aLayerID )
320 {
321 case F_Mask:
322 case B_Mask:
323 {
324 const SFVEC4F layerColor = getLayerColor( aLayerID );
325
326 m_materials.m_SolderMask.m_Diffuse = layerColor;
327
328 // Convert Opacity to Transparency
329 m_materials.m_SolderMask.m_Transparency = 1.0f - layerColor.a;
330
332 {
333 m_materials.m_SolderMask.m_Ambient = m_materials.m_SolderMask.m_Diffuse * 0.3f;
334
335 m_materials.m_SolderMask.m_Specular =
336 m_materials.m_SolderMask.m_Diffuse * m_materials.m_SolderMask.m_Diffuse;
337 }
338
339 OglSetMaterial( m_materials.m_SolderMask, 1.0f );
340 break;
341 }
342
343 case B_Paste:
344 case F_Paste:
345 m_materials.m_Paste.m_Diffuse = getLayerColor( aLayerID );
346 OglSetMaterial( m_materials.m_Paste, 1.0f );
347 break;
348
349 case B_SilkS:
350 m_materials.m_SilkSBot.m_Diffuse = getLayerColor( aLayerID );
351 OglSetMaterial( m_materials.m_SilkSBot, 1.0f );
352 break;
353
354 case F_SilkS:
355 m_materials.m_SilkSTop.m_Diffuse = getLayerColor( aLayerID );
356 OglSetMaterial( m_materials.m_SilkSTop, 1.0f );
357 break;
358
359 case B_Adhes:
360 case F_Adhes:
361 case Dwgs_User:
362 case Cmts_User:
363 case Eco1_User:
364 case Eco2_User:
365 case Edge_Cuts:
366 case Margin:
367 case B_CrtYd:
368 case F_CrtYd:
369 case B_Fab:
370 case F_Fab:
371 m_materials.m_Plastic.m_Diffuse = getLayerColor( aLayerID );
372
373 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
374 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
375 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
376
377 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
378 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
379 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
380
381 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
382 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
383 OglSetMaterial( m_materials.m_Plastic, 1.0f );
384 break;
385
386 default:
387 m_materials.m_Copper.m_Diffuse = getLayerColor( aLayerID );
388 OglSetMaterial( m_materials.m_Copper, 1.0f );
389 break;
390 }
391}
392
393
395{
396 SFVEC4F layerColor = m_boardAdapter.GetLayerColor( aLayerID );
397
399 {
400 switch( aLayerID )
401 {
402 case B_Adhes:
403 case F_Adhes:
404 break;
405
406 case B_Mask:
408 break;
409 case F_Mask:
411 break;
412
413 case B_Paste:
414 case F_Paste:
416 break;
417
418 case B_SilkS:
420 break;
421 case F_SilkS:
423 break;
424
425 case Dwgs_User:
426 case Cmts_User:
427 case Eco1_User:
428 case Eco2_User:
429 case Edge_Cuts:
430 case Margin:
431 break;
432
433 case B_CrtYd:
434 case F_CrtYd:
435 break;
436
437 case B_Fab:
438 case F_Fab:
439 break;
440
441 default:
442 layerColor = m_boardAdapter.m_CopperColor;
443 break;
444 }
445 }
446
447 return layerColor;
448}
449
450
451void init_lights( void )
452{
453 // Setup light
454 // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
455 const GLfloat ambient[] = { 0.084f, 0.084f, 0.084f, 1.0f };
456 const GLfloat diffuse0[] = { 0.3f, 0.3f, 0.3f, 1.0f };
457 const GLfloat specular0[] = { 0.5f, 0.5f, 0.5f, 1.0f };
458
459 glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
460 glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse0 );
461 glLightfv( GL_LIGHT0, GL_SPECULAR, specular0 );
462
463 const GLfloat diffuse12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
464 const GLfloat specular12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
465
466 // defines a directional light that points along the negative z-axis
467 GLfloat position[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
468
469 // This makes a vector slight not perpendicular with XZ plane
470 const SFVEC3F vectorLight = SphericalToCartesian( glm::pi<float>() * 0.03f,
471 glm::pi<float>() * 0.25f );
472
473 position[0] = vectorLight.x;
474 position[1] = vectorLight.y;
475 position[2] = vectorLight.z;
476
477 glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
478 glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse12 );
479 glLightfv( GL_LIGHT1, GL_SPECULAR, specular12 );
480 glLightfv( GL_LIGHT1, GL_POSITION, position );
481
482 // defines a directional light that points along the positive z-axis
483 position[2] = -position[2];
484
485 glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
486 glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse12 );
487 glLightfv( GL_LIGHT2, GL_SPECULAR, specular12 );
488 glLightfv( GL_LIGHT2, GL_POSITION, position );
489
490 const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
491
492 glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
493
494 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
495}
496
497
499{
500 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
501}
502
503
505{
506 glEnable( GL_POLYGON_OFFSET_FILL );
507 glPolygonOffset( -0.1f, -2.0f );
508 setLayerMaterial( aLayer_id );
509}
510
511
513{
514 glDisable( GL_POLYGON_OFFSET_FILL );
515}
516
517
518void RENDER_3D_OPENGL::renderBoardBody( bool aSkipRenderHoles )
519{
520 m_materials.m_EpoxyBoard.m_Diffuse = m_boardAdapter.m_BoardBodyColor;
521
522 // opacity to transparency
523 m_materials.m_EpoxyBoard.m_Transparency = 1.0f - m_boardAdapter.m_BoardBodyColor.a;
524
525 OglSetMaterial( m_materials.m_EpoxyBoard, 1.0f );
526
527 OPENGL_RENDER_LIST* ogl_disp_list = nullptr;
528
529 if( aSkipRenderHoles )
530 ogl_disp_list = m_board;
531 else
532 ogl_disp_list = m_boardWithHoles;
533
534 if( ogl_disp_list )
535 {
538
539 ogl_disp_list->SetItIsTransparent( true );
540
541 ogl_disp_list->DrawAll();
542 }
543}
544
545
546bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
547 REPORTER* aWarningReporter )
548{
549 // Initialize OpenGL
551 {
552 if( !initializeOpenGL() )
553 return false;
554 }
555
557 {
558 std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
559
560 if( aStatusReporter )
561 aStatusReporter->Report( _( "Loading..." ) );
562
563 reload( aStatusReporter, aWarningReporter );
564
565 // generate a new 3D grid as the size of the board may had changed
568 }
569 else
570 {
571 // Check if grid was changed
573 {
574 // and generate a new one
577 }
578 }
579
581
582 // Initial setup
583 glDepthFunc( GL_LESS );
584 glEnable( GL_CULL_FACE );
585 glFrontFace( GL_CCW ); // This is the OpenGL default
586 glEnable( GL_NORMALIZE ); // This allow OpenGL to normalize the normals after transformations
587 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
588
590 glDisable( GL_MULTISAMPLE );
591 else
592 glEnable( GL_MULTISAMPLE );
593
594 // clear color and depth buffers
595 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
596 glClearDepth( 1.0f );
597 glClearStencil( 0x00 );
598 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
599
601
602 // Draw the background ( rectangle with color gradient)
605
606 glEnable( GL_DEPTH_TEST );
607
608 // Set projection and modelview matrixes
609 glMatrixMode( GL_PROJECTION );
610 glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
611 glMatrixMode( GL_MODELVIEW );
612 glLoadIdentity();
613 glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
614
615 // Position the headlight
616 setLightFront( true );
617 setLightTop( true );
618 setLightBottom( true );
619
620 glEnable( GL_LIGHTING );
621
622 {
623 const SFVEC3F& cameraPos = m_camera.GetPos();
624
625 // Place the light at a minimum Z so the diffuse factor will not drop
626 // and the board will still look with good light.
627 float zpos;
628
629 if( cameraPos.z > 0.0f )
630 zpos = glm::max( cameraPos.z, 0.5f ) + cameraPos.z * cameraPos.z;
631 else
632 zpos = glm::min( cameraPos.z,-0.5f ) - cameraPos.z * cameraPos.z;
633
634 // This is a point light.
635 const GLfloat headlight_pos[] = { cameraPos.x, cameraPos.y, zpos, 1.0f };
636
637 glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
638 }
639
640 bool skipThickness = aIsMoving && m_boardAdapter.m_Cfg->m_Render.opengl_thickness_disableOnMove;
641 bool skipRenderHoles = aIsMoving && m_boardAdapter.m_Cfg->m_Render.opengl_holes_disableOnMove;
642 bool skipRenderVias = aIsMoving && m_boardAdapter.m_Cfg->m_Render.opengl_vias_disableOnMove;
643
644 bool drawMiddleSegments = !skipThickness;
645
647 {
648 // Draw vias and pad holes with copper material
650 }
651 else
652 {
653 OglSetMaterial( m_materials.m_GrayMaterial, 1.0f );
654 }
655
656 if( !( skipRenderVias || skipRenderHoles ) && m_vias )
657 m_vias->DrawAll();
658
659 if( !skipRenderHoles && m_padHoles )
661
662 // Display copper and tech layers
663 for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
664 {
665 const PCB_LAYER_ID layer_id = ( PCB_LAYER_ID )( ii->first );
666
667 // Mask layers are not processed here because they are a special case
668 if( ( layer_id == B_Mask ) || ( layer_id == F_Mask ) )
669 continue;
670
671 // Do not show inner layers when it is displaying the board and board body is opaque
672 // enough: the time to create inner layers can be *really significant*.
673 // So avoid creating them is they are not very visible
674 const double opacity_min = 0.8;
675
677 && m_boardAdapter.m_BoardBodyColor.a > opacity_min )
678 {
679 if( ( layer_id > F_Cu ) && ( layer_id < B_Cu ) )
680 continue;
681 }
682
683 glPushMatrix();
684
685 OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
686
687 if( ( layer_id >= F_Cu ) && ( layer_id <= B_Cu ) )
688 {
691 {
693 }
694 else
695 {
696 setLayerMaterial( layer_id );
697 }
698
699 if( skipRenderHoles )
700 {
701 pLayerDispList->DrawAllCameraCulled( m_camera.GetPos().z, drawMiddleSegments );
702
703 // Draw plated pads
704 if( layer_id == F_Cu && m_platedPadsFront )
705 {
708 drawMiddleSegments );
709 }
710 else if( layer_id == B_Cu && m_platedPadsBack )
711 {
714 drawMiddleSegments );
715 }
716
718 }
719 else
720 {
722 {
724 pLayerDispList->GetZTop()
725 - pLayerDispList->GetZBot() );
726 }
727
728 if( m_antiBoard )
729 {
730 m_antiBoard->ApplyScalePosition( pLayerDispList->GetZBot(),
731 pLayerDispList->GetZTop()
732 - pLayerDispList->GetZBot() );
733 }
734
735 if( m_outerLayerHoles.find( layer_id ) != m_outerLayerHoles.end() )
736 {
737 const OPENGL_RENDER_LIST* viasHolesLayer = m_outerLayerHoles.at( layer_id );
738
739 wxASSERT( viasHolesLayer != nullptr );
740
741 if( viasHolesLayer != nullptr )
742 {
743 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
745 viasHolesLayer,
746 m_antiBoard );
747
748 // Draw plated pads
749 if( layer_id == F_Cu && m_platedPadsFront )
750 {
753 drawMiddleSegments,
755 viasHolesLayer,
756 m_antiBoard );
757 }
758 else if( layer_id == B_Cu && m_platedPadsBack )
759 {
762 drawMiddleSegments,
764 viasHolesLayer,
765 m_antiBoard );
766 }
767
769 }
770 }
771 else
772 {
773 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
775 m_antiBoard );
776
777 if( layer_id == F_Cu && m_platedPadsFront )
778 {
782 m_antiBoard );
783 }
784 else if( layer_id == B_Cu && m_platedPadsBack )
785 {
789 m_antiBoard );
790 }
791
793 }
794 }
795 }
796 else
797 {
798 setLayerMaterial( layer_id );
799
800 OPENGL_RENDER_LIST* throughHolesOuter =
803 && ( layer_id == B_SilkS || layer_id == F_SilkS ) ? m_outerThroughHoleRings
805
806 if( throughHolesOuter )
807 {
808 throughHolesOuter->ApplyScalePosition( pLayerDispList->GetZBot(),
809 pLayerDispList->GetZTop()
810 - pLayerDispList->GetZBot() );
811 }
812
813 OPENGL_RENDER_LIST* anti_board = m_antiBoard;
814
815 if( anti_board )
816 {
817 anti_board->ApplyScalePosition( pLayerDispList->GetZBot(),
818 pLayerDispList->GetZTop()
819 - pLayerDispList->GetZBot() );
820 }
821
822 if( !skipRenderHoles
825 && ( ( layer_id == B_SilkS && m_layers.find( B_Mask ) != m_layers.end() )
826 || ( layer_id == F_SilkS && m_layers.find( F_Mask ) != m_layers.end() ) ) )
827 {
828 const PCB_LAYER_ID layerMask_id = (layer_id == B_SilkS) ? B_Mask : F_Mask;
829
830 const OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( layerMask_id );
831
832 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
833 pLayerDispListMask,
834 throughHolesOuter, anti_board );
835 }
836 else
837 {
838 if( !skipRenderHoles && throughHolesOuter
839 && ( layer_id == B_SilkS || layer_id == F_SilkS ) )
840 {
841 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments, nullptr,
842 throughHolesOuter,
843 anti_board );
844 }
845 else
846 {
847 // Do not render Paste layers when skipRenderHoles is enabled
848 // otherwise it will cause z-fight issues
849 if( !( skipRenderHoles && ( layer_id == B_Paste || layer_id == F_Paste ) ) )
850 {
851 pLayerDispList->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
852 anti_board );
853 }
854 }
855 }
856 }
857
858 glPopMatrix();
859 }
860
861 // Render 3D Models (Non-transparent)
862 render3dModels( false, false );
863 render3dModels( true, false );
864
865 // Display board body
867 renderBoardBody( skipRenderHoles );
868
869 // Display transparent mask layers
871 {
872 // add a depth buffer offset, it will help to hide some artifacts
873 // on silkscreen where the SolderMask is removed
874 glEnable( GL_POLYGON_OFFSET_FILL );
875 glPolygonOffset( 0.0f, -2.0f );
876
877 if( m_camera.GetPos().z > 0 )
878 {
880 drawMiddleSegments, skipRenderHoles );
881
883 drawMiddleSegments, skipRenderHoles );
884 }
885 else
886 {
888 drawMiddleSegments, skipRenderHoles );
889
891 drawMiddleSegments, skipRenderHoles );
892 }
893
894 glDisable( GL_POLYGON_OFFSET_FILL );
895 glPolygonOffset( 0.0f, 0.0f );
896 }
897
898 // Render 3D Models (Transparent)
899 // !TODO: this can be optimized. If there are no transparent models (or no opacity),
900 // then there is no need to make this function call.
901 glDepthMask( GL_FALSE );
902 glEnable( GL_BLEND );
903 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
904
905 // Enables Texture Env so it can combine model transparency with each footprint opacity
906 glEnable( GL_TEXTURE_2D );
907 glActiveTexture( GL_TEXTURE0 );
908
909 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
910 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
911 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
912
913 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
914 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
915
916 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
917 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
918
919 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
920 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
921 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
922 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
923
924 render3dModels( false, true );
925 render3dModels( true, true );
926
927 glDisable( GL_BLEND );
929
930 glDepthMask( GL_TRUE );
931
932 // Render Grid
934 {
935 glDisable( GL_LIGHTING );
936
937 if( glIsList( m_grid ) )
938 glCallList( m_grid );
939
940 glEnable( GL_LIGHTING );
941 }
942
943 // Render 3D arrows
946
947 // Return back to the original viewport (this is important if we want
948 // to take a screenshot after the render)
949 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
950
951 return false;
952}
953
954
956{
957 glEnable( GL_LINE_SMOOTH );
958 glShadeModel( GL_SMOOTH );
959
960 // 4-byte pixel alignment
961 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
962
963 // Initialize the open GL texture to draw the filled semi-circle of the segments
965
966 if( !circleImage )
967 return false;
968
969 unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
970
971 circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
972 ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
973 circleRadius,
974 0xFF );
975
976 IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
977
978 circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
979
980 m_circleTexture = OglLoadTexture( *circleImageBlured );
981
982 delete circleImageBlured;
983 circleImageBlured = nullptr;
984
985 delete circleImage;
986 circleImage = nullptr;
987
988 init_lights();
989
990 // Use this mode if you want see the triangle lines (debug proposes)
991 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
993
994 return true;
995}
996
997
999{
1000 glEnable( GL_COLOR_MATERIAL );
1001 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1002
1003 const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1004 const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1005 const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1006 const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
1007
1008 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
1009 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
1010
1011 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
1012 glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
1013 glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
1014}
1015
1016
1018{
1019 if( glIsList( m_grid ) )
1020 glDeleteLists( m_grid, 1 );
1021
1022 m_grid = 0;
1023
1024 for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
1025 {
1026 OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
1027 delete pLayerDispList;
1028 }
1029
1030 m_layers.clear();
1031
1032 delete m_platedPadsFront;
1033 m_platedPadsFront = nullptr;
1034
1035 delete m_platedPadsBack;
1036 m_platedPadsBack = nullptr;
1037
1038
1039 for( const std::pair<const PCB_LAYER_ID, OPENGL_RENDER_LIST*> entry : m_outerLayerHoles )
1040 delete entry.second;
1041
1042 m_outerLayerHoles.clear();
1043
1044 for( const std::pair<const PCB_LAYER_ID, OPENGL_RENDER_LIST*> entry : m_innerLayerHoles )
1045 delete entry.second;
1046
1047 m_innerLayerHoles.clear();
1048
1049 for( LIST_TRIANGLES::const_iterator ii = m_triangles.begin(); ii != m_triangles.end(); ++ii )
1050 delete *ii;
1051
1052 m_triangles.clear();
1053
1054 for( const std::pair<const wxString, MODEL_3D*>& entry : m_3dModelMap )
1055 delete entry.second;
1056
1057 m_3dModelMap.clear();
1058
1059 m_3dModelMatrixMap.clear();
1060
1061 delete m_board;
1062 m_board = nullptr;
1063
1064 delete m_boardWithHoles;
1065 m_boardWithHoles = nullptr;
1066
1067 delete m_antiBoard;
1068 m_antiBoard = nullptr;
1069
1070 delete m_outerThroughHoles;
1071 m_outerThroughHoles = nullptr;
1072
1074 m_outerViaThroughHoles = nullptr;
1075
1077 m_outerThroughHoleRings = nullptr;
1078
1079 delete m_vias;
1080 m_vias = nullptr;
1081
1082 delete m_padHoles;
1083 m_padHoles = nullptr;
1084}
1085
1086
1088 bool aDrawMiddleSegments, bool aSkipRenderHoles )
1089{
1090 wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
1091
1092 float nonCopperThickness = m_boardAdapter.GetNonCopperLayerThickness();
1093
1094 if( m_board )
1095 {
1096 if( m_layers.find( aLayerID ) != m_layers.end() )
1097 {
1098 OPENGL_RENDER_LIST* pLayerDispListMask = m_layers.at( aLayerID );
1099
1101 m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1102
1103 m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1104
1105 setLayerMaterial( aLayerID );
1106
1107 m_board->SetItIsTransparent( true );
1108
1109 if( aSkipRenderHoles )
1110 {
1111 m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1112 }
1113 else
1114 {
1115 m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments, pLayerDispListMask,
1117 }
1118 }
1119 else
1120 {
1121 // This case there is no layer with mask, so we will render the full board as mask
1123 m_outerViaThroughHoles->ApplyScalePosition( aZPosition, nonCopperThickness );
1124
1125 m_board->ApplyScalePosition( aZPosition, nonCopperThickness );
1126
1127 setLayerMaterial( aLayerID );
1128
1129 m_board->SetItIsTransparent( true );
1130
1131 if( aSkipRenderHoles )
1132 {
1133 m_board->DrawAllCameraCulled( m_camera.GetPos().z, aDrawMiddleSegments );
1134 }
1135 else
1136 {
1137 m_board->DrawAllCameraCulledSubtractLayer( aDrawMiddleSegments,
1139 }
1140 }
1141 }
1142}
1143
1144
1145void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
1146 bool aRenderSelectedOnly )
1147{
1148 if( !m_boardAdapter.GetBoard() )
1149 return;
1150
1151 MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly );
1152
1153 // Go for all footprints
1155 {
1156 bool highlight = false;
1157
1159 {
1160 if( fp->IsSelected() )
1161 highlight = true;
1162
1164 && fp == m_currentRollOverItem )
1165 {
1166 highlight = true;
1167 }
1168
1169 if( aRenderSelectedOnly != highlight )
1170 continue;
1171 }
1172
1173 if( !fp->Models().empty() )
1174 {
1175 if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1176 {
1177 if( aRenderTopOrBot == !fp->IsFlipped() )
1178 renderFootprint( fp, aRenderTransparentOnly, highlight );
1179 }
1180 }
1181 }
1182
1184}
1185
1186
1187void RENDER_3D_OPENGL::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly )
1188{
1190 render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, true );
1191
1192 render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, false );
1193}
1194
1195
1196void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
1197 bool aIsSelected )
1198{
1199 if( !aFootprint->Models().empty() )
1200 {
1201 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1203
1204
1205 glPushMatrix();
1206
1207 VECTOR2I pos = aFootprint->GetPosition();
1208
1209 glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(),
1210 zpos );
1211
1212 if( !aFootprint->GetOrientation().IsZero() )
1213 glRotated( aFootprint->GetOrientation().AsDegrees(), 0.0, 0.0, 1.0 );
1214
1215 if( aFootprint->IsFlipped() )
1216 {
1217 glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
1218 glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
1219 }
1220
1221 double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1222
1223 glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
1224 modelunit_to_3d_units_factor );
1225
1226 // Get the list of model files for this model
1227 for( const FP_3DMODEL& sM : aFootprint->Models() )
1228 {
1229 if( !sM.m_Show || sM.m_Filename.empty() )
1230 continue;
1231
1232 // Check if the model is present in our cache map
1233 auto cache_i = m_3dModelMap.find( sM.m_Filename );
1234
1235 if( cache_i == m_3dModelMap.end() )
1236 continue;
1237
1238 if( const MODEL_3D* modelPtr = cache_i->second )
1239 {
1240 bool opaque = sM.m_Opacity >= 1.0;
1241
1242 if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1243 ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1244 {
1245 glPushMatrix();
1246
1247 std::vector<double> key = { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z,
1248 sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z,
1249 sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z };
1250
1251 auto it = m_3dModelMatrixMap.find( key );
1252
1253 if( it != m_3dModelMatrixMap.end() )
1254 {
1255 glMultMatrixf( glm::value_ptr( it->second ) );
1256 }
1257 else
1258 {
1259 glm::mat4 mtx( 1 );
1260 mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
1261 mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ), { 0.0f, 0.0f, 1.0f } );
1262 mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.y ), { 0.0f, 1.0f, 0.0f } );
1263 mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.x ), { 1.0f, 0.0f, 0.0f } );
1264 mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } );
1265 m_3dModelMatrixMap[ key ] = mtx;
1266
1267 glMultMatrixf( glm::value_ptr( mtx ) );
1268 }
1269
1270
1271 if( aRenderTransparentOnly )
1272 {
1273 modelPtr->DrawTransparent( sM.m_Opacity,
1274 aFootprint->IsSelected() || aIsSelected,
1275 selColor );
1276 }
1277 else
1278 {
1279 modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected, selColor );
1280 }
1281
1283 {
1284 glEnable( GL_BLEND );
1285 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1286
1287 glDisable( GL_LIGHTING );
1288
1289 glLineWidth( 1 );
1290 modelPtr->DrawBboxes();
1291
1292 glLineWidth( 4 );
1293 modelPtr->DrawBbox();
1294
1295 glEnable( GL_LIGHTING );
1296 glDisable( GL_BLEND );
1297 }
1298
1299 glPopMatrix();
1300 }
1301 }
1302 }
1303
1304 glPopMatrix();
1305 }
1306}
1307
1308
1310{
1311 if( glIsList( m_grid ) )
1312 glDeleteLists( m_grid, 1 );
1313
1314 m_grid = 0;
1315
1316 if( aGridType == GRID3D_TYPE::NONE )
1317 return;
1318
1319 m_grid = glGenLists( 1 );
1320
1321 if( !glIsList( m_grid ) )
1322 return;
1323
1324 glNewList( m_grid, GL_COMPILE );
1325
1326 glEnable( GL_BLEND );
1327 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1328
1329 const double zpos = 0.0;
1330
1331 // Color of grid lines
1332 const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1333
1334 // Color of grid lines every 5 lines
1335 const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTBLUE );
1336 const double scale = m_boardAdapter.BiuTo3dUnits();
1337 const GLfloat transparency = 0.35f;
1338
1339 double griSizeMM = 0.0;
1340
1341 switch( aGridType )
1342 {
1343 default:
1344 case GRID3D_TYPE::NONE:
1345 return;
1347 griSizeMM = 1.0;
1348 break;
1350 griSizeMM = 2.5;
1351 break;
1353 griSizeMM = 5.0;
1354 break;
1356 griSizeMM = 10.0;
1357 break;
1358 }
1359
1360 glNormal3f( 0.0, 0.0, 1.0 );
1361
1362 const VECTOR2I brd_size = m_boardAdapter.GetBoardSize();
1363 VECTOR2I brd_center_pos = m_boardAdapter.GetBoardPos();
1364
1365 brd_center_pos.y = -brd_center_pos.y;
1366
1367 const int xsize = std::max( brd_size.x, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1368 const int ysize = std::max( brd_size.y, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1369
1370 // Grid limits, in 3D units
1371 double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1372 double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1373 double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1374 double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1375 double zmin = pcbIUScale.mmToIU( -50 ) * scale;
1376 double zmax = pcbIUScale.mmToIU( 100 ) * scale;
1377
1378 // Set rasterised line width (min value = 1)
1379 glLineWidth( 1 );
1380
1381 // Draw horizontal grid centered on 3D origin (center of the board)
1382 for( int ii = 0; ; ii++ )
1383 {
1384 if( (ii % 5) )
1385 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1386 else
1387 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1388 transparency );
1389
1390 const int delta = KiROUND( ii * griSizeMM * pcbIUScale.IU_PER_MM );
1391
1392 if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1393 {
1394 glBegin( GL_LINES );
1395 glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1396 glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1397 glEnd();
1398
1399 if( ii != 0 )
1400 {
1401 glBegin( GL_LINES );
1402 glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1403 glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1404 glEnd();
1405 }
1406 }
1407
1408 if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1409 {
1410 glBegin( GL_LINES );
1411 glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1412 glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1413 glEnd();
1414
1415 if( ii != 0 )
1416 {
1417 glBegin( GL_LINES );
1418 glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1419 glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1420 glEnd();
1421 }
1422 }
1423
1424 if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1425 break;
1426 }
1427
1428 // Draw vertical grid on Z axis
1429 glNormal3f( 0.0, -1.0, 0.0 );
1430
1431 // Draw vertical grid lines (parallel to Z axis)
1432 double posy = -brd_center_pos.y * scale;
1433
1434 for( int ii = 0; ; ii++ )
1435 {
1436 if( (ii % 5) )
1437 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1438 else
1439 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1440 transparency );
1441
1442 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM;
1443
1444 glBegin( GL_LINES );
1445 xmax = ( brd_center_pos.x + delta ) * scale;
1446
1447 glVertex3f( xmax, posy, zmin );
1448 glVertex3f( xmax, posy, zmax );
1449 glEnd();
1450
1451 if( ii != 0 )
1452 {
1453 glBegin( GL_LINES );
1454 xmin = ( brd_center_pos.x - delta ) * scale;
1455 glVertex3f( xmin, posy, zmin );
1456 glVertex3f( xmin, posy, zmax );
1457 glEnd();
1458 }
1459
1460 if( delta > xsize / 2.0f )
1461 break;
1462 }
1463
1464 // Draw horizontal grid lines on Z axis (parallel to X axis)
1465 for( int ii = 0; ; ii++ )
1466 {
1467 if( ii % 5 )
1468 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1469 else
1470 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1471
1472 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM * scale;
1473
1474 if( delta <= zmax )
1475 {
1476 // Draw grid lines on Z axis (positive Z axis coordinates)
1477 glBegin( GL_LINES );
1478 glVertex3f( xmin, posy, delta );
1479 glVertex3f( xmax, posy, delta );
1480 glEnd();
1481 }
1482
1483 if( delta <= -zmin && ( ii != 0 ) )
1484 {
1485 // Draw grid lines on Z axis (negative Z axis coordinates)
1486 glBegin( GL_LINES );
1487 glVertex3f( xmin, posy, -delta );
1488 glVertex3f( xmax, posy, -delta );
1489 glEnd();
1490 }
1491
1492 if( ( delta > zmax ) && ( delta > -zmin ) )
1493 break;
1494 }
1495
1496 glDisable( GL_BLEND );
1497
1498 glEndList();
1499}
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:307
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:183
const glm::mat4 & GetProjectionMatrix() const
Definition: camera.cpp:415
const SFVEC3F & GetPos() const
Definition: camera.h:107
const glm::mat4 & GetViewMatrix() const
Definition: camera.cpp:451
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:49
double AsDegrees() const
Definition: eda_angle.h:149
bool IsZero() const
Definition: eda_angle.h:169
bool IsSelected() const
Definition: eda_item.h:107
EDA_ANGLE GetOrientation() const
Definition: footprint.h:191
bool IsFlipped() const
Definition: footprint.h:315
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
static void EndDrawMulti()
Cleanup render states after drawing multiple models.
Definition: 3d_model.cpp:399
static void BeginDrawMulti(bool aUseColorInformation)
Set some basic render states before drawing multiple models.
Definition: 3d_model.cpp:383
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.
std::map< std::vector< double >, glm::mat4 > m_3dModelMatrixMap
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)
void renderFootprint(const FOOTPRINT *aFootprint, bool aRenderTransparentOnly, bool aIsSelected)
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)
int GetWaitForEditingTimeOut() override
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
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,...
void render3dModelsSelected(bool aRenderTopOrBot, bool aRenderTransparentOnly, bool aRenderSelectedOnly)
OPENGL_RENDER_LIST * m_padHoles
GLuint m_grid
oGL list that stores current grid
void render3dModels(bool aRenderTopOrBot, bool aRenderTransparentOnly)
OPENGL_RENDER_LIST * m_platedPadsBack
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:62
@ DARKGRAY
Definition: color4d.h:46
#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
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