KiCad PCB EDA Suite
Loading...
Searching...
No Matches
render_3d_opengl.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015-2020 Mario Luzeiro <[email protected]>
5 * Copyright (C) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <cstdint>
27#include <kicad_gl/kiglad.h> // Must be included first
28
30#include "render_3d_opengl.h"
31#include "opengl_utils.h"
34#include <board.h>
35#include <footprint.h>
37#include <3d_math.h>
38#include <glm/geometric.hpp>
39#include <lset.h>
40#include <pgm_base.h>
41#include <math/util.h> // for KiROUND
42#include <utility>
43#include <vector>
44#include <wx/log.h>
45
46#include <base_units.h>
47
48#include <glm/gtc/type_ptr.hpp>
49
59static float TransparencyControl( float aGrayColorValue, float aTransparency )
60{
61 const float aaa = aTransparency * aTransparency * aTransparency;
62
63 // 1.00-1.05*(1.0-x)^3
64 float ca = 1.0f - aTransparency;
65 ca = 1.00f - 1.05f * ca * ca * ca;
66
67 return glm::clamp( aGrayColorValue * ca + aaa, 0.0f, 1.0f );
68}
69
73#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
74
76 RENDER_3D_BASE( aAdapter, aCamera ),
77 m_canvas( aCanvas )
78{
79 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
80
81 m_layers.clear();
82 m_outerLayerHoles.clear();
83 m_innerLayerHoles.clear();
84 m_triangles.clear();
85 m_board = nullptr;
86 m_antiBoard = nullptr;
87
88 m_platedPadsFront = nullptr;
89 m_platedPadsBack = nullptr;
90 m_offboardPadsFront = nullptr;
91 m_offboardPadsBack = nullptr;
92
93 m_outerThroughHoles = nullptr;
95 m_outerViaThroughHoles = nullptr;
96 m_microviaHoles = nullptr;
97 m_padHoles = nullptr;
98 m_viaFrontCover = nullptr;
99 m_viaBackCover = nullptr;
100
101 m_circleTexture = 0;
102 m_grid = 0;
104 m_currentRollOverItem = nullptr;
105 m_boardWithHoles = nullptr;
106 m_postMachinePlugs = nullptr;
107
108 m_3dModelMap.clear();
109
110 m_spheres_gizmo = new SPHERES_GIZMO( 4, 4 );
111}
112
113
115{
116 wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
117
118 freeAllLists();
119
120 delete m_placeholderModel;
121
122 glDeleteTextures( 1, &m_circleTexture );
123
124 delete m_spheres_gizmo;
125}
126
127
129{
130 return 50; // ms
131}
132
133
134void RENDER_3D_OPENGL::SetCurWindowSize( const wxSize& aSize )
135{
136 if( m_windowSize != aSize )
137 {
138 int viewport[4];
139 int fbWidth, fbHeight;
140 glGetIntegerv( GL_VIEWPORT, viewport );
141
142 m_windowSize = aSize;
143 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
145 // Initialize here any screen dependent data here
146 }
147}
148
149
151{
152 if( enabled )
153 glEnable( GL_LIGHT0 );
154 else
155 glDisable( GL_LIGHT0 );
156}
157
158
160{
161 if( enabled )
162 glEnable( GL_LIGHT1 );
163 else
164 glDisable( GL_LIGHT1 );
165}
166
167
169{
170 if( enabled )
171 glEnable( GL_LIGHT2 );
172 else
173 glDisable( GL_LIGHT2 );
174}
175
176
178{
179 m_spheres_gizmo->resetSelectedGizmoSphere();
180}
181
182
187
188
189void RENDER_3D_OPENGL::setGizmoViewport( int x, int y, int width, int height )
190{
191 m_spheres_gizmo->setViewport( x, y, width, height );
192}
193
194
195std::tuple<int, int, int, int> RENDER_3D_OPENGL::getGizmoViewport() const
196{
197 return m_spheres_gizmo->getViewport();
198}
199
200
201void RENDER_3D_OPENGL::handleGizmoMouseInput( int mouseX, int mouseY )
202{
203 m_spheres_gizmo->handleMouseInput( mouseX, mouseY );
204}
205
206
207void RENDER_3D_OPENGL::updateGizmoSelection( glm::mat4 aCameraRotationMatrix )
208{
209 m_spheres_gizmo->updateSelection( aCameraRotationMatrix );
210}
211
212
214{
215 m_materials = {};
216
217 // http://devernay.free.fr/cours/opengl/materials.html
218
219 // Plated copper
220 // Copper material mixed with the copper color
221 m_materials.m_Copper.m_Ambient = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.1f,
222 m_boardAdapter.m_CopperColor.g * 0.1f,
223 m_boardAdapter.m_CopperColor.b * 0.1f);
224
225 m_materials.m_Copper.m_Specular = SFVEC3F( m_boardAdapter.m_CopperColor.r * 0.75f + 0.25f,
226 m_boardAdapter.m_CopperColor.g * 0.75f + 0.25f,
227 m_boardAdapter.m_CopperColor.b * 0.75f + 0.25f );
228
229 // This guess the material type(ex: copper vs gold) to determine the
230 // shininess factor between 0.1 and 0.4
231 float shininessfactor = 0.40f - mapf( fabs( m_boardAdapter.m_CopperColor.r -
232 m_boardAdapter.m_CopperColor.g ),
233 0.15f, 1.00f,
234 0.00f, 0.30f );
235
236 m_materials.m_Copper.m_Shininess = shininessfactor * 128.0f;
237 m_materials.m_Copper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
238
239
240 // Non plated copper (raw copper)
241 m_materials.m_NonPlatedCopper.m_Ambient = SFVEC3F( 0.191f, 0.073f, 0.022f );
242 m_materials.m_NonPlatedCopper.m_Diffuse = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f,
243 50.0f / 255.0f );
244 m_materials.m_NonPlatedCopper.m_Specular = SFVEC3F( 0.256f, 0.137f, 0.086f );
245 m_materials.m_NonPlatedCopper.m_Shininess = 0.1f * 128.0f;
246 m_materials.m_NonPlatedCopper.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
247
248 // Paste material mixed with paste color
249 m_materials.m_Paste.m_Ambient = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r,
250 m_boardAdapter.m_SolderPasteColor.g,
251 m_boardAdapter.m_SolderPasteColor.b );
252
253 m_materials.m_Paste.m_Specular = SFVEC3F( m_boardAdapter.m_SolderPasteColor.r *
254 m_boardAdapter.m_SolderPasteColor.r,
255 m_boardAdapter.m_SolderPasteColor.g *
256 m_boardAdapter.m_SolderPasteColor.g,
257 m_boardAdapter.m_SolderPasteColor.b *
258 m_boardAdapter.m_SolderPasteColor.b );
259
260 m_materials.m_Paste.m_Shininess = 0.1f * 128.0f;
261 m_materials.m_Paste.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
262
263 // Silk screen material mixed with silk screen color
264 m_materials.m_SilkSTop.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorTop.r,
265 m_boardAdapter.m_SilkScreenColorTop.g,
266 m_boardAdapter.m_SilkScreenColorTop.b );
267
268 m_materials.m_SilkSTop.m_Specular = SFVEC3F(
269 m_boardAdapter.m_SilkScreenColorTop.r * m_boardAdapter.m_SilkScreenColorTop.r + 0.10f,
270 m_boardAdapter.m_SilkScreenColorTop.g * m_boardAdapter.m_SilkScreenColorTop.g + 0.10f,
271 m_boardAdapter.m_SilkScreenColorTop.b * m_boardAdapter.m_SilkScreenColorTop.b + 0.10f );
272
273 m_materials.m_SilkSTop.m_Shininess = 0.078125f * 128.0f;
274 m_materials.m_SilkSTop.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
275
276 // Silk screen material mixed with silk screen color
277 m_materials.m_SilkSBot.m_Ambient = SFVEC3F( m_boardAdapter.m_SilkScreenColorBot.r,
278 m_boardAdapter.m_SilkScreenColorBot.g,
279 m_boardAdapter.m_SilkScreenColorBot.b );
280
281 m_materials.m_SilkSBot.m_Specular = SFVEC3F(
282 m_boardAdapter.m_SilkScreenColorBot.r * m_boardAdapter.m_SilkScreenColorBot.r + 0.10f,
283 m_boardAdapter.m_SilkScreenColorBot.g * m_boardAdapter.m_SilkScreenColorBot.g + 0.10f,
284 m_boardAdapter.m_SilkScreenColorBot.b * m_boardAdapter.m_SilkScreenColorBot.b + 0.10f );
285
286 m_materials.m_SilkSBot.m_Shininess = 0.078125f * 128.0f;
287 m_materials.m_SilkSBot.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
288
289 // Shininess is computed dynamically in setLayerMaterial() based on color darkness
290 m_materials.m_SolderMask.m_Shininess = 0.85f * 128.0f;
291 m_materials.m_SolderMask.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
292
293 // Epoxy material
294 m_materials.m_EpoxyBoard.m_Ambient = SFVEC3F( 117.0f / 255.0f, 97.0f / 255.0f,
295 47.0f / 255.0f );
296
297 m_materials.m_EpoxyBoard.m_Specular = SFVEC3F( 18.0f / 255.0f, 3.0f / 255.0f,
298 20.0f / 255.0f );
299
300 m_materials.m_EpoxyBoard.m_Shininess = 0.1f * 128.0f;
301 m_materials.m_EpoxyBoard.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
302}
303
304
306{
307 if( m_boardAdapter.GetUseBoardEditorCopperLayerColors() && IsCopperLayer( aLayerID ) )
308 {
309 COLOR4D copper_color = m_boardAdapter.m_BoardEditorColors[aLayerID];
310 m_materials.m_Copper.m_Diffuse = SFVEC3F( copper_color.r, copper_color.g,
311 copper_color.b );
312 OglSetMaterial( m_materials.m_Copper, 1.0f );
313 m_materials.m_NonPlatedCopper.m_Diffuse = m_materials.m_Copper.m_Diffuse;
314 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
315
316 return;
317 }
318
319 switch( aLayerID )
320 {
321 case F_Mask:
322 case B_Mask:
323 {
324 const SFVEC4F layerColor = aLayerID == F_Mask ? m_boardAdapter.m_SolderMaskColorTop
325 : m_boardAdapter.m_SolderMaskColorBot;
326
327 m_materials.m_SolderMask.m_Diffuse = layerColor;
328
329 // Compute gray value for material property adjustments based on color darkness
330 const float solderMask_gray = ( layerColor.r + layerColor.g + layerColor.b ) / 3.0f;
331
332 // Use TransparencyControl to make darker colors more opaque, preventing copper
333 // show-through on dark solder masks
334 const float baseTransparency = 1.0f - layerColor.a;
335 m_materials.m_SolderMask.m_Transparency = TransparencyControl( solderMask_gray,
336 baseTransparency );
337
338 m_materials.m_SolderMask.m_Ambient = m_materials.m_SolderMask.m_Diffuse * 0.3f;
339
340 // Darker solder masks need a higher specular floor to avoid washed-out appearance
341 const SFVEC3F baseSpecular = m_materials.m_SolderMask.m_Diffuse
342 * m_materials.m_SolderMask.m_Diffuse;
343 m_materials.m_SolderMask.m_Specular = glm::max( baseSpecular, SFVEC3F( 0.30f ) );
344
345 // Darker colors get higher shininess for a tighter specular highlight, matching
346 // how dark solder masks appear in real life
347 const float minSolderMaskShininess = 0.85f * 128.0f;
348 const float maxSolderMaskShininess = 512.0f;
349 m_materials.m_SolderMask.m_Shininess = minSolderMaskShininess
350 + ( maxSolderMaskShininess - minSolderMaskShininess ) * ( 1.0f - solderMask_gray );
351
352 OglSetMaterial( m_materials.m_SolderMask, 1.0f );
353 break;
354 }
355
356 case B_Paste:
357 case F_Paste:
358 m_materials.m_Paste.m_Diffuse = m_boardAdapter.m_SolderPasteColor;
359 OglSetMaterial( m_materials.m_Paste, 1.0f );
360 break;
361
362 case B_SilkS:
363 m_materials.m_SilkSBot.m_Diffuse = m_boardAdapter.m_SilkScreenColorBot;
364 OglSetMaterial( m_materials.m_SilkSBot, 1.0f );
365 break;
366
367 case F_SilkS:
368 m_materials.m_SilkSTop.m_Diffuse = m_boardAdapter.m_SilkScreenColorTop;
369 OglSetMaterial( m_materials.m_SilkSTop, 1.0f );
370 break;
371
372 case B_Adhes:
373 case F_Adhes:
374 case Dwgs_User:
375 case Cmts_User:
376 case Eco1_User:
377 case Eco2_User:
378 case Edge_Cuts:
379 case Margin:
380 case B_CrtYd:
381 case F_CrtYd:
382 case B_Fab:
383 case F_Fab:
384 switch( aLayerID )
385 {
386 case Dwgs_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
387 case Cmts_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserCommentsColor; break;
388 case Eco1_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_ECO1Color; break;
389 case Eco2_User: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_ECO2Color; break;
390 case Edge_Cuts: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
391 case Margin: m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDrawingsColor; break;
392 default:
393 m_materials.m_Plastic.m_Diffuse = m_boardAdapter.GetLayerColor( aLayerID );
394 break;
395 }
396
397 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
398 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
399 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
400
401 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
402 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
403 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
404
405 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
406 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
407 OglSetMaterial( m_materials.m_Plastic, 1.0f );
408 break;
409
410 default:
411 {
412 int layer3D = MapPCBLayerTo3DLayer( aLayerID );
413
414 // Note: MUST do this in LAYER_3D space; User_1..User_45 are NOT contiguous
415 if( layer3D >= LAYER_3D_USER_1 && layer3D <= LAYER_3D_USER_45 )
416 {
417 int user_idx = layer3D - LAYER_3D_USER_1;
418
419 m_materials.m_Plastic.m_Diffuse = m_boardAdapter.m_UserDefinedLayerColor[ user_idx ];
420 m_materials.m_Plastic.m_Ambient = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.05f,
421 m_materials.m_Plastic.m_Diffuse.g * 0.05f,
422 m_materials.m_Plastic.m_Diffuse.b * 0.05f );
423
424 m_materials.m_Plastic.m_Specular = SFVEC3F( m_materials.m_Plastic.m_Diffuse.r * 0.7f,
425 m_materials.m_Plastic.m_Diffuse.g * 0.7f,
426 m_materials.m_Plastic.m_Diffuse.b * 0.7f );
427
428 m_materials.m_Plastic.m_Shininess = 0.078125f * 128.0f;
429 m_materials.m_Plastic.m_Emissive = SFVEC3F( 0.0f, 0.0f, 0.0f );
430 OglSetMaterial( m_materials.m_Plastic, 1.0f );
431 break;
432 }
433
434 m_materials.m_Copper.m_Diffuse = m_boardAdapter.m_CopperColor;
435 OglSetMaterial( m_materials.m_Copper, 1.0f );
436 break;
437 }
438 }
439}
440
441
443{
444 // Setup light
445 // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
446 const GLfloat ambient[] = { 0.084f, 0.084f, 0.084f, 1.0f };
447 const GLfloat diffuse0[] = { 0.3f, 0.3f, 0.3f, 1.0f };
448 const GLfloat specular0[] = { 0.5f, 0.5f, 0.5f, 1.0f };
449
450 glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
451 glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse0 );
452 glLightfv( GL_LIGHT0, GL_SPECULAR, specular0 );
453
454 const GLfloat diffuse12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
455 const GLfloat specular12[] = { 0.7f, 0.7f, 0.7f, 1.0f };
456
457 // defines a directional light that points along the negative z-axis
458 GLfloat position[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
459
460 // This makes a vector slight not perpendicular with XZ plane
461 const SFVEC3F vectorLight = SphericalToCartesian( glm::pi<float>() * 0.03f,
462 glm::pi<float>() * 0.25f );
463
464 position[0] = vectorLight.x;
465 position[1] = vectorLight.y;
466 position[2] = vectorLight.z;
467
468 glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
469 glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse12 );
470 glLightfv( GL_LIGHT1, GL_SPECULAR, specular12 );
471 glLightfv( GL_LIGHT1, GL_POSITION, position );
472
473 // defines a directional light that points along the positive z-axis
474 position[2] = -position[2];
475
476 glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
477 glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse12 );
478 glLightfv( GL_LIGHT2, GL_SPECULAR, specular12 );
479 glLightfv( GL_LIGHT2, GL_POSITION, position );
480
481 const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
482
483 glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
484
485 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
486}
487
488
490{
491 OglSetMaterial( m_materials.m_NonPlatedCopper, 1.0f );
492}
493
494
496{
497 glEnable( GL_POLYGON_OFFSET_FILL );
498 glPolygonOffset( -0.1f, -2.0f );
499 setLayerMaterial( aLayer_id );
500}
501
502
504{
505 glDisable( GL_POLYGON_OFFSET_FILL );
506}
507
508
509void RENDER_3D_OPENGL::renderBoardBody( bool aSkipRenderHoles )
510{
511 m_materials.m_EpoxyBoard.m_Diffuse = m_boardAdapter.m_BoardBodyColor;
512
513 // opacity to transparency
514 m_materials.m_EpoxyBoard.m_Transparency = 1.0f - m_boardAdapter.m_BoardBodyColor.a;
515
516 OglSetMaterial( m_materials.m_EpoxyBoard, 1.0f );
517
518 OPENGL_RENDER_LIST* ogl_disp_list = nullptr;
519
520 if( aSkipRenderHoles )
521 ogl_disp_list = m_board;
522 else
523 ogl_disp_list = m_boardWithHoles;
524
525 if( ogl_disp_list )
526 {
527 ogl_disp_list->ApplyScalePosition( -m_boardAdapter.GetBoardBodyThickness() / 2.0f,
528 m_boardAdapter.GetBoardBodyThickness() );
529
530 ogl_disp_list->SetItIsTransparent( true );
531 ogl_disp_list->DrawAll();
532 }
533
534 // Also render post-machining plugs (board material that remains after backdrill/counterbore/countersink)
535 if( !aSkipRenderHoles && m_postMachinePlugs )
536 {
537 m_postMachinePlugs->ApplyScalePosition( -m_boardAdapter.GetBoardBodyThickness() / 2.0f,
538 m_boardAdapter.GetBoardBodyThickness() );
539
540 m_postMachinePlugs->SetItIsTransparent( true );
541 m_postMachinePlugs->DrawAll();
542 }
543}
544
545
546static inline SFVEC4F premultiplyAlpha( const SFVEC4F& aInput )
547{
548 return SFVEC4F( aInput.r * aInput.a, aInput.g * aInput.a, aInput.b * aInput.a, aInput.a );
549}
550
551
552bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
553 REPORTER* aWarningReporter )
554{
555 // Initialize OpenGL
557 {
558 if( !initializeOpenGL() )
559 return false;
560 }
561
563
565 {
566 std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
567
568 if( aStatusReporter )
569 aStatusReporter->Report( _( "Loading..." ) );
570
571 // Careful here!
572 // We are in the middle of rendering and the reload method may show
573 // a dialog box that requires the opengl context for a redraw
574 Pgm().GetGLContextManager()->RunWithoutCtxLock( [this, aStatusReporter, aWarningReporter]()
575 {
576 reload( aStatusReporter, aWarningReporter );
577 } );
578
579 // generate a new 3D grid as the size of the board may had changed
580 m_lastGridType = static_cast<GRID3D_TYPE>( cfg.grid_type );
582 }
583 else
584 {
585 // Check if grid was changed
586 if( cfg.grid_type != m_lastGridType )
587 {
588 // and generate a new one
589 m_lastGridType = static_cast<GRID3D_TYPE>( cfg.grid_type );
591 }
592 }
593
595
596 // Initial setup
597 glDepthFunc( GL_LESS );
598 glEnable( GL_CULL_FACE );
599 glFrontFace( GL_CCW ); // This is the OpenGL default
600 glEnable( GL_NORMALIZE ); // This allow OpenGL to normalize the normals after transformations
601 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
602
603 if( aIsMoving && cfg.opengl_AA_disableOnMove )
604 glDisable( GL_MULTISAMPLE );
605 else
606 glEnable( GL_MULTISAMPLE );
607
608 // clear color and depth buffers
609 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
610 glClearDepth( 1.0f );
611 glClearStencil( 0x00 );
612 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
613
615
616 // Draw the background ( rectangle with color gradient)
618 premultiplyAlpha( m_boardAdapter.m_BgColorBot ) );
619
620 glEnable( GL_DEPTH_TEST );
621
622 // Set projection and modelview matrixes
623 glMatrixMode( GL_PROJECTION );
624 glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
625 glMatrixMode( GL_MODELVIEW );
626 glLoadIdentity();
627 glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
628
629 // Position the headlight
630 setLightFront( true );
631 setLightTop( true );
632 setLightBottom( true );
633
634 glEnable( GL_LIGHTING );
635
636 {
637 const SFVEC3F& cameraPos = m_camera.GetPos();
638
639 // Place the light at a minimum Z so the diffuse factor will not drop
640 // and the board will still look with good light.
641 float zpos;
642
643 if( cameraPos.z > 0.0f )
644 zpos = glm::max( cameraPos.z, 0.5f ) + cameraPos.z * cameraPos.z;
645 else
646 zpos = glm::min( cameraPos.z,-0.5f ) - cameraPos.z * cameraPos.z;
647
648 // This is a point light.
649 const GLfloat headlight_pos[] = { cameraPos.x, cameraPos.y, zpos, 1.0f };
650
651 glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
652 }
653
654 bool skipThickness = aIsMoving && cfg.opengl_thickness_disableOnMove;
655 bool skipRenderHoles = aIsMoving && cfg.opengl_holes_disableOnMove;
656 bool skipRenderMicroVias = aIsMoving && cfg.opengl_microvias_disableOnMove;
657 bool showThickness = !skipThickness;
658
659 std::bitset<LAYER_3D_END> layerFlags = m_boardAdapter.GetVisibleLayers();
660
662
663 if( !( skipRenderMicroVias || skipRenderHoles ) && m_microviaHoles )
664 m_microviaHoles->DrawAll();
665
666 if( !skipRenderHoles && m_padHoles )
667 m_padHoles->DrawAll();
668
669 // Display copper and tech layers
670 for( MAP_OGL_DISP_LISTS::const_iterator ii = m_layers.begin(); ii != m_layers.end(); ++ii )
671 {
672 const PCB_LAYER_ID layer = ( PCB_LAYER_ID )( ii->first );
673 bool isSilkLayer = layer == F_SilkS || layer == B_SilkS;
674 bool isMaskLayer = layer == F_Mask || layer == B_Mask;
675 bool isPasteLayer = layer == F_Paste || layer == B_Paste;
676
677 // Mask layers are not processed here because they are a special case
678 if( isMaskLayer )
679 continue;
680
681 // Do not show inner layers when it is displaying the board and board body is opaque
682 // enough: the time to create inner layers can be *really significant*.
683 // So avoid creating them is they are not very visible
684 const double opacity_min = 0.8;
685
686 if( layerFlags.test( LAYER_3D_BOARD ) && m_boardAdapter.m_BoardBodyColor.a > opacity_min )
687 {
688 // generating internal copper layers is time consuming. so skip them
689 // if the board body is masking them (i.e. if the opacity is near 1.0)
690 // B_Cu is layer 2 and all inner layers are higher values
691 if( layer > B_Cu && IsCopperLayer( layer ) )
692 continue;
693 }
694
695 glPushMatrix();
696
697 OPENGL_RENDER_LIST* pLayerDispList = static_cast<OPENGL_RENDER_LIST*>( ii->second );
698
699 if( IsCopperLayer( layer ) )
700 {
701 if( cfg.DifferentiatePlatedCopper() )
703 else
704 setLayerMaterial( layer );
705
706 OPENGL_RENDER_LIST* outerTH = nullptr;
707 OPENGL_RENDER_LIST* viaHoles = nullptr;
708
709 if( !skipRenderHoles )
710 {
711 outerTH = m_outerThroughHoles;
712 viaHoles = m_outerLayerHoles[layer];
713 }
714
715 if( m_antiBoard )
716 m_antiBoard->ApplyScalePosition( pLayerDispList );
717
718 if( outerTH )
719 outerTH->ApplyScalePosition( pLayerDispList );
720
721 pLayerDispList->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
722
723 // Draw plated & offboard pads
724 if( layer == F_Cu && ( m_platedPadsFront || m_offboardPadsFront ) )
725 {
727
729 m_platedPadsFront->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
730
732 m_offboardPadsFront->DrawCulled( showThickness, outerTH, viaHoles );
733 }
734 else if( layer == B_Cu && ( m_platedPadsBack || m_offboardPadsBack ) )
735 {
737
738 if( m_platedPadsBack )
739 m_platedPadsBack->DrawCulled( showThickness, outerTH, viaHoles, m_antiBoard );
740
742 m_offboardPadsBack->DrawCulled( showThickness, outerTH, viaHoles );
743 }
744
746 }
747 else
748 {
749 setLayerMaterial( layer );
750
751 OPENGL_RENDER_LIST* throughHolesOuter = nullptr;
752 OPENGL_RENDER_LIST* anti_board = nullptr;
753 OPENGL_RENDER_LIST* solder_mask = nullptr;
754
755 if( !skipRenderHoles )
756 {
757 if( isSilkLayer && cfg.clip_silk_on_via_annuli )
758 throughHolesOuter = m_outerThroughHoleRings;
759 else
760 throughHolesOuter = m_outerThroughHoles;
761 }
762
763 if( isSilkLayer && cfg.show_off_board_silk )
764 anti_board = nullptr;
765 else if( LSET::PhysicalLayersMask().test( layer ) )
766 anti_board = m_antiBoard;
767
768 if( isSilkLayer && cfg.subtract_mask_from_silk && !cfg.show_off_board_silk )
769 solder_mask = m_layers[ ( layer == B_SilkS) ? B_Mask : F_Mask ];
770
771 if( throughHolesOuter )
772 throughHolesOuter->ApplyScalePosition( pLayerDispList );
773
774 if( anti_board )
775 anti_board->ApplyScalePosition( pLayerDispList );
776
777 if( solder_mask )
778 solder_mask->ApplyScalePosition( pLayerDispList );
779
780 pLayerDispList->DrawCulled( showThickness, solder_mask, throughHolesOuter, anti_board );
781 }
782
783 glPopMatrix();
784 }
785
786 glm::mat4 cameraViewMatrix;
787
788 glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
789
790 // Render 3D Models (Non-transparent)
791 renderOpaqueModels( cameraViewMatrix );
792
793 // Render extruded 3D bodies
794 {
796 const SFVEC3F extSelColor = m_boardAdapter.GetColor( extCfg.opengl_selection_color );
797
798 // Render extruded pad standoffs (metallic pins)
799 for( auto& [fp, renderList] : m_extrudedPadLists )
800 {
801 if( renderList )
802 {
803 bool highlight = false;
804
805 if( m_boardAdapter.m_IsBoardView )
806 {
807 if( fp->IsSelected() )
808 highlight = true;
809
810 if( extCfg.highlight_on_rollover && fp == m_currentRollOverItem )
811 highlight = true;
812 }
813
814 SMATERIAL mat = m_materials.m_Copper;
815 mat.m_Diffuse = SFVEC3F( 0.75f, 0.75f, 0.75f );
816 mat.m_Specular = SFVEC3F( 0.85f, 0.85f, 0.85f );
817 mat.m_Shininess = 0.6f * 128.0f;
818 mat.m_Transparency = 0.0f;
819
820 OglSetMaterial( mat, 1.0f, highlight, extSelColor );
821 renderList->DrawAll();
822 }
823 }
824
825 for( auto& [fp, renderList] : m_extrudedBodyLists )
826 {
827 const EXTRUDED_3D_BODY* body = fp->GetExtrudedBody();
828
829 if( !body )
830 continue;
831
832 if( renderList )
833 {
834 bool highlight = false;
835
836 if( m_boardAdapter.m_IsBoardView )
837 {
838 if( fp->IsSelected() )
839 highlight = true;
840
841 if( extCfg.highlight_on_rollover && fp == m_currentRollOverItem )
842 highlight = true;
843 }
844
845 KIGFX::COLOR4D c = body->m_color;
846
849
850 SMATERIAL mat;
851
852 SFVEC3F diffuse( c.r, c.g, c.b );
853 EXTRUSION_MATERIAL_PROPS props = GetMaterialProps( body->m_material, diffuse );
854
855 mat.m_Diffuse = diffuse;
856 mat.m_Ambient = props.m_Ambient;
857 mat.m_Specular = props.m_Specular;
858 mat.m_Shininess = props.m_Shininess;
859 mat.m_Emissive = SFVEC3F( 0.0f );
860 mat.m_Transparency = 1.0f - c.a;
861
862 OglSetMaterial( mat, 1.0f, highlight, extSelColor );
863 renderList->DrawAll();
864 }
865 }
866 }
867
868 // Display board body
869 if( layerFlags.test( LAYER_3D_BOARD ) )
870 renderBoardBody( skipRenderHoles );
871
872 // Display transparent mask layers
873 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP )
874 || layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
875 {
876 // add a depth buffer offset, it will help to hide some artifacts
877 // on silkscreen where the SolderMask is removed
878 glEnable( GL_POLYGON_OFFSET_FILL );
879 glPolygonOffset( 0.0f, -2.0f );
880
881 if( m_camera.GetPos().z > 0 )
882 {
883 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
884 {
886 showThickness, skipRenderHoles );
887 }
888
889 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
890 {
891 renderSolderMaskLayer( F_Mask, m_boardAdapter.GetLayerBottomZPos( F_Mask ),
892 showThickness, skipRenderHoles );
893 }
894 }
895 else
896 {
897 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
898 {
899 renderSolderMaskLayer( F_Mask, m_boardAdapter.GetLayerBottomZPos( F_Mask ),
900 showThickness, skipRenderHoles );
901 }
902
903 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
904 {
906 showThickness, skipRenderHoles );
907 }
908 }
909
910 glDisable( GL_POLYGON_OFFSET_FILL );
911 glPolygonOffset( 0.0f, 0.0f );
912 }
913
914 // Render 3D Models (Transparent)
915 // !TODO: this can be optimized. If there are no transparent models (or no opacity),
916 // then there is no need to make this function call.
917 glDepthMask( GL_FALSE );
918 glEnable( GL_BLEND );
919 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
920
921 // Enables Texture Env so it can combine model transparency with each footprint opacity
922 glEnable( GL_TEXTURE_2D );
923 glActiveTexture( GL_TEXTURE0 );
924
925 // Uses an existent texture so the glTexEnv operations will work.
926 glBindTexture( GL_TEXTURE_2D, m_circleTexture );
927
928 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
929 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
930 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
931
932 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
933 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
934
935 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
936 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
937
938 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
939 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
940 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
941 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
942
943 renderTransparentModels( cameraViewMatrix );
944
945 glDisable( GL_BLEND );
947
948 glDepthMask( GL_TRUE );
949
950 // Render Grid
951 if( cfg.grid_type != GRID3D_TYPE::NONE )
952 {
953 glDisable( GL_LIGHTING );
954
955 if( glIsList( m_grid ) )
956 glCallList( m_grid );
957
958 glEnable( GL_LIGHTING );
959 }
960
961 // Render 3D arrows
962 if( cfg.show_navigator )
963 m_spheres_gizmo->render3dSpheresGizmo( m_camera.GetRotationMatrix() );
964
965 // Return back to the original viewport (this is important if we want
966 // to take a screenshot after the render)
967 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
968
969 return false;
970}
971
972
974{
975 glEnable( GL_LINE_SMOOTH );
976 glShadeModel( GL_SMOOTH );
977
978 // 4-byte pixel alignment
979 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
980
981 // Initialize the open GL texture to draw the filled semi-circle of the segments
983
984 if( !circleImage )
985 return false;
986
987 unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
988
989 circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
990 ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
991 circleRadius,
992 0xFF );
993
994 IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
995
996 circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
997
998 m_circleTexture = OglLoadTexture( *circleImageBlured );
999
1000 delete circleImageBlured;
1001 circleImageBlured = nullptr;
1002
1003 delete circleImage;
1004 circleImage = nullptr;
1005
1006 init_lights();
1007
1008 // Use this mode if you want see the triangle lines (debug proposes)
1009 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1010 m_canvasInitialized = true;
1011
1012 return true;
1013}
1014
1015
1017{
1018 glEnable( GL_COLOR_MATERIAL );
1019 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1020
1021 const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1022 const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1023 const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
1024 const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
1025
1026 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
1027 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
1028
1029 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
1030 glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
1031 glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
1032}
1033
1034
1036{
1037#define DELETE_AND_FREE( ptr ) \
1038 { \
1039 delete ptr; \
1040 ptr = nullptr; \
1041 } \
1042
1043#define DELETE_AND_FREE_MAP( map ) \
1044 { \
1045 for( auto& [ layer, ptr ] : map ) \
1046 delete ptr; \
1047 \
1048 map.clear(); \
1049 }
1050
1051 if( glIsList( m_grid ) )
1052 glDeleteLists( m_grid, 1 );
1053
1054 m_grid = 0;
1055
1057
1062
1065
1066 for( TRIANGLE_DISPLAY_LIST* list : m_triangles )
1067 delete list;
1068
1069 m_triangles.clear();
1070
1072
1073 m_3dModelMatrixMap.clear();
1074
1079
1083
1089
1092}
1093
1094
1096 bool aShowThickness, bool aSkipRenderHoles )
1097{
1098 wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
1099
1100 if( m_board )
1101 {
1102 OPENGL_RENDER_LIST* solder_mask = m_layers[ aLayerID ];
1103 OPENGL_RENDER_LIST* via_holes = aSkipRenderHoles ? nullptr : m_outerThroughHoles;
1104
1105 if( via_holes )
1106 via_holes->ApplyScalePosition( aZPos, m_boardAdapter.GetNonCopperLayerThickness() );
1107
1108 m_board->ApplyScalePosition( aZPos, m_boardAdapter.GetNonCopperLayerThickness() );
1109
1110 setLayerMaterial( aLayerID );
1111 m_board->SetItIsTransparent( true );
1112 m_board->DrawCulled( aShowThickness, solder_mask, via_holes );
1113
1114 if( aLayerID == F_Mask && m_viaFrontCover )
1115 {
1116 m_viaFrontCover->ApplyScalePosition( aZPos, 4 * m_boardAdapter.GetNonCopperLayerThickness() );
1117 m_viaFrontCover->DrawTop();
1118 }
1119 else if( aLayerID == B_Mask && m_viaBackCover )
1120 {
1121 m_viaBackCover->ApplyScalePosition( aZPos, 4 * m_boardAdapter.GetNonCopperLayerThickness() );
1122 m_viaBackCover->DrawBot();
1123 }
1124 }
1125}
1126
1127
1128void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList, bool aGetTop,
1129 bool aGetBot, bool aRenderTransparentOnly,
1130 bool aRenderSelectedOnly )
1131{
1132 wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
1133
1134 if( !m_boardAdapter.GetBoard() )
1135 return;
1136
1138
1139 // Go for all footprints
1140 for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
1141 {
1142 bool highlight = false;
1143
1144 if( m_boardAdapter.m_IsBoardView )
1145 {
1146 if( fp->IsSelected() )
1147 highlight = true;
1148
1150 highlight = true;
1151
1152 if( aRenderSelectedOnly != highlight )
1153 continue;
1154 }
1155
1156 bool hasModels = !fp->Models().empty();
1157 bool showMissing = m_boardAdapter.m_Cfg->m_Render.show_missing_models;
1158
1159 if( hasModels || showMissing )
1160 {
1161 if( m_boardAdapter.IsFootprintShown( fp ) )
1162 {
1163 const bool isFlipped = fp->IsFlipped();
1164
1165 if( aGetTop == !isFlipped || aGetBot == isFlipped )
1166 get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly,
1167 highlight );
1168 }
1169 }
1170 }
1171}
1172
1173
1174void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
1175 const FOOTPRINT* aFootprint,
1176 bool aRenderTransparentOnly, bool aIsSelected )
1177{
1178 if( !aFootprint->Models().empty() )
1179 {
1180 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1181
1182 VECTOR2I pos = aFootprint->GetPosition();
1183
1184 glm::mat4 fpMatrix( 1.0f );
1185
1186 fpMatrix = glm::translate( fpMatrix, SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1187 -pos.y * m_boardAdapter.BiuTo3dUnits(), zpos ) );
1188
1189 if( !aFootprint->GetOrientation().IsZero() )
1190 {
1191 fpMatrix = glm::rotate( fpMatrix, (float) aFootprint->GetOrientation().AsRadians(),
1192 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1193 }
1194
1195 if( aFootprint->IsFlipped() )
1196 {
1197 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1198 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1199 }
1200
1201 double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1202
1203 fpMatrix = glm::scale( fpMatrix, SFVEC3F( modelunit_to_3d_units_factor ) );
1204
1205 // Get the list of model files for this model
1206 for( const FP_3DMODEL& sM : aFootprint->Models() )
1207 {
1208 if( !sM.m_Show || sM.m_Filename.empty() )
1209 continue;
1210
1211 // Check if the model is present in our cache map
1212 auto cache_i = m_3dModelMap.find( sM.m_Filename );
1213
1214 if( cache_i == m_3dModelMap.end() )
1215 {
1216 renderPlaceholderForFootprint( aDstRenderList, fpMatrix, aFootprint, aRenderTransparentOnly,
1217 aIsSelected, aRenderTransparentOnly ? sM.m_Opacity : 1.0f );
1218 continue;
1219 }
1220
1221 if( const MODEL_3D* modelPtr = cache_i->second )
1222 {
1223 bool opaque = sM.m_Opacity >= 1.0;
1224
1225 if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1226 ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1227 {
1228 glm::mat4 modelworldMatrix = fpMatrix;
1229
1230 const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
1231 const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y,
1232 sM.m_Rotation.z );
1233 const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
1234
1235 std::vector<float> key = { offset.x, offset.y, offset.z,
1236 rotation.x, rotation.y, rotation.z,
1237 scale.x, scale.y, scale.z };
1238
1239 auto it = m_3dModelMatrixMap.find( key );
1240
1241 if( it != m_3dModelMatrixMap.end() )
1242 {
1243 modelworldMatrix *= it->second;
1244 }
1245 else
1246 {
1247 glm::mat4 mtx( 1.0f );
1248 mtx = glm::translate( mtx, offset );
1249 mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
1250 mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
1251 mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
1252 mtx = glm::scale( mtx, scale );
1253 m_3dModelMatrixMap[ key ] = mtx;
1254
1255 modelworldMatrix *= mtx;
1256 }
1257
1258 aDstRenderList.emplace_back( modelworldMatrix, modelPtr,
1259 aRenderTransparentOnly ? sM.m_Opacity : 1.0f,
1260 aRenderTransparentOnly,
1261 aFootprint->IsSelected() || aIsSelected );
1262 }
1263 }
1264 }
1265 }
1266 else
1267 {
1268 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1269
1270 VECTOR2I pos = aFootprint->GetPosition();
1271
1272 glm::mat4 fpMatrix( 1.0f );
1273
1274 fpMatrix = glm::translate( fpMatrix, SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1275 -pos.y * m_boardAdapter.BiuTo3dUnits(), zpos ) );
1276
1277 if( !aFootprint->GetOrientation().IsZero() )
1278 {
1279 fpMatrix = glm::rotate( fpMatrix, (float) aFootprint->GetOrientation().AsRadians(),
1280 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1281 }
1282
1283 if( aFootprint->IsFlipped() )
1284 {
1285 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1286 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1287 }
1288
1289 double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1290
1291 fpMatrix = glm::scale( fpMatrix, SFVEC3F( modelunit_to_3d_units_factor ) );
1292
1293 renderPlaceholderForFootprint( aDstRenderList, fpMatrix, aFootprint, aRenderTransparentOnly, aIsSelected,
1294 1.0f );
1295 }
1296}
1297
1298
1299void RENDER_3D_OPENGL::renderPlaceholderForFootprint( std::list<MODELTORENDER>& aDstRenderList,
1300 const glm::mat4& aFpMatrix, const FOOTPRINT* aFootprint,
1301 bool aRenderTransparentOnly, bool aIsSelected, float aOpacity )
1302{
1303 if( !m_boardAdapter.m_Cfg->m_Render.show_missing_models || !m_placeholderModel )
1304 return;
1305
1306 // Suppress placeholder if a valid extruded body was built
1307 if( m_extrudedBodyLists.count( aFootprint ) )
1308 return;
1309
1310 BOX2I localBox = CalcPlaceholderLocalBox( aFootprint );
1311
1312 float bboxW = std::abs( localBox.GetWidth() ) / pcbIUScale.IU_PER_MM * 0.9f;
1313 float bboxH = std::abs( localBox.GetHeight() ) / pcbIUScale.IU_PER_MM * 0.9f;
1314
1315 float scaleX = bboxW;
1316 float scaleY = bboxH;
1317 float scaleZ = std::min( bboxW, bboxH ) * 0.5f;
1318
1319 VECTOR2I localCenter = localBox.GetCenter();
1320 float offsetX = localCenter.x / pcbIUScale.IU_PER_MM;
1321 float offsetY = -localCenter.y / pcbIUScale.IU_PER_MM;
1322 float offsetZ = scaleZ * 0.5f;
1323
1324 if( aFootprint->IsFlipped() )
1325 offsetY = -offsetY;
1326
1327 glm::mat4 mtx = aFpMatrix;
1328 mtx = glm::translate( mtx, SFVEC3F( offsetX, offsetY, offsetZ ) );
1329 mtx = glm::scale( mtx, SFVEC3F( scaleX, scaleY, scaleZ ) );
1330
1331 bool placeholderOpaque = aOpacity >= 1.0;
1332
1333 if( ( !aRenderTransparentOnly && m_placeholderModel->HasOpaqueMeshes() && placeholderOpaque )
1334 || ( aRenderTransparentOnly && ( m_placeholderModel->HasTransparentMeshes() || !placeholderOpaque ) ) )
1335 {
1336 aDstRenderList.emplace_back( mtx, m_placeholderModel, aOpacity, aRenderTransparentOnly,
1337 aFootprint->IsSelected() || aIsSelected );
1338 }
1339}
1340
1341
1342void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
1343{
1345
1346 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1347
1348 glPushMatrix();
1349
1350 std::list<MODELTORENDER> renderList;
1351
1352 if( m_boardAdapter.m_IsBoardView )
1353 {
1354 renderList.clear();
1355
1356 get3dModelsSelected( renderList, true, true, false, true );
1357
1358 if( !renderList.empty() )
1359 {
1360 MODEL_3D::BeginDrawMulti( false );
1361
1362 for( const MODELTORENDER& mtr : renderList )
1363 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1364
1366 }
1367 }
1368
1369 renderList.clear();
1370 get3dModelsSelected( renderList, true, true, false, false );
1371
1372 if( !renderList.empty() )
1373 {
1375
1376 for( const MODELTORENDER& mtr : renderList )
1377 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1378
1380 }
1381
1382 glPopMatrix();
1383}
1384
1385
1386void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
1387{
1389
1390 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1391
1392 std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
1393
1394 if( m_boardAdapter.m_IsBoardView )
1395 {
1396 // Get Transparent Selected
1397 get3dModelsSelected( renderListModels, true, true, true, true );
1398 }
1399
1400 // Get Transparent Not Selected
1401 get3dModelsSelected( renderListModels, true, true, true, false );
1402
1403 if( renderListModels.empty() )
1404 return;
1405
1406 std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
1407
1408 transparentModelList.reserve( renderListModels.size() );
1409
1410 // Calculate the distance to the camera for each model
1411 const SFVEC3F &cameraPos = m_camera.GetPos();
1412
1413 for( const MODELTORENDER& mtr : renderListModels )
1414 {
1415 const BBOX_3D& bBox = mtr.m_model->GetBBox();
1416 const SFVEC3F& bBoxCenter = bBox.GetCenter();
1417 const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
1418
1419 const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
1420
1421 transparentModelList.emplace_back( &mtr, distanceToCamera );
1422 }
1423
1424 // Sort from back to front
1425 std::sort( transparentModelList.begin(), transparentModelList.end(),
1426 [&]( std::pair<const MODELTORENDER *, float>& a,
1427 std::pair<const MODELTORENDER *, float>& b )
1428 {
1429 if( a.second != b.second )
1430 return a.second > b.second;
1431
1432 return a.first > b.first; // use pointers as a last resort
1433 } );
1434
1435 // Start rendering calls
1436 glPushMatrix();
1437
1438 bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
1439 m_boardAdapter.m_IsBoardView );
1440
1441 MODEL_3D::BeginDrawMulti( isUsingColorInformation );
1442
1443 for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
1444 {
1445 if( m_boardAdapter.m_IsBoardView )
1446 {
1447 // Toggle between using model color or the select color
1448 if( !isUsingColorInformation && !mtr.first->m_isSelected )
1449 {
1450 isUsingColorInformation = true;
1451
1452 glEnableClientState( GL_COLOR_ARRAY );
1453 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1454 glEnable( GL_COLOR_MATERIAL );
1455 }
1456 else if( isUsingColorInformation && mtr.first->m_isSelected )
1457 {
1458 isUsingColorInformation = false;
1459
1460 glDisableClientState( GL_COLOR_ARRAY );
1461 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1462 glDisable( GL_COLOR_MATERIAL );
1463 }
1464 }
1465
1466 // Render model, sort each individuall material group
1467 // by passing cameraPos
1468 renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
1469 }
1470
1472
1473 glPopMatrix();
1474}
1475
1476
1477void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
1478 const MODELTORENDER &aModelToRender,
1479 const SFVEC3F &aSelColor, const SFVEC3F *aCameraWorldPos )
1480{
1482
1483 const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
1484
1485 glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
1486
1487 aModelToRender.m_model->Draw( aModelToRender.m_isTransparent, aModelToRender.m_opacity,
1488 aModelToRender.m_isSelected, aSelColor,
1489 &aModelToRender.m_modelWorldMat, aCameraWorldPos );
1490
1491 if( cfg.show_model_bbox )
1492 {
1493 const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
1494
1495 if( !wasBlendEnabled )
1496 {
1497 glEnable( GL_BLEND );
1498 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1499 }
1500
1501 glDisable( GL_LIGHTING );
1502
1503 glLineWidth( 1 );
1504 aModelToRender.m_model->DrawBboxes();
1505
1506 glLineWidth( 4 );
1507 aModelToRender.m_model->DrawBbox();
1508
1509 glEnable( GL_LIGHTING );
1510
1511 if( !wasBlendEnabled )
1512 glDisable( GL_BLEND );
1513 }
1514}
1515
1516
1518{
1519 if( glIsList( m_grid ) )
1520 glDeleteLists( m_grid, 1 );
1521
1522 m_grid = 0;
1523
1524 if( aGridType == GRID3D_TYPE::NONE )
1525 return;
1526
1527 m_grid = glGenLists( 1 );
1528
1529 if( !glIsList( m_grid ) )
1530 return;
1531
1532 glNewList( m_grid, GL_COMPILE );
1533
1534 glEnable( GL_BLEND );
1535 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1536
1537 const double zpos = 0.0;
1538
1539 // Color of grid lines
1540 const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1541
1542 // Color of grid lines every 5 lines
1543 const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTBLUE );
1544 const double scale = m_boardAdapter.BiuTo3dUnits();
1545 const GLfloat transparency = 0.35f;
1546
1547 double griSizeMM = 0.0;
1548
1549 switch( aGridType )
1550 {
1551 case GRID3D_TYPE::GRID_1MM: griSizeMM = 1.0; break;
1552 case GRID3D_TYPE::GRID_2P5MM: griSizeMM = 2.5; break;
1553 case GRID3D_TYPE::GRID_5MM: griSizeMM = 5.0; break;
1554 case GRID3D_TYPE::GRID_10MM: griSizeMM = 10.0; break;
1555
1556 default:
1557 case GRID3D_TYPE::NONE: return;
1558 }
1559
1560 glNormal3f( 0.0, 0.0, 1.0 );
1561
1562 const VECTOR2I brd_size = m_boardAdapter.GetBoardSize();
1563 VECTOR2I brd_center_pos = m_boardAdapter.GetBoardPos();
1564
1565 brd_center_pos.y = -brd_center_pos.y;
1566
1567 const int xsize = std::max( brd_size.x, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1568 const int ysize = std::max( brd_size.y, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1569
1570 // Grid limits, in 3D units
1571 double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1572 double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1573 double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1574 double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1575 double zmin = pcbIUScale.mmToIU( -50 ) * scale;
1576 double zmax = pcbIUScale.mmToIU( 100 ) * scale;
1577
1578 // Set rasterised line width (min value = 1)
1579 glLineWidth( 1 );
1580
1581 // Draw horizontal grid centered on 3D origin (center of the board)
1582 for( int ii = 0; ; ii++ )
1583 {
1584 if( (ii % 5) )
1585 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1586 else
1587 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1588 transparency );
1589
1590 const int delta = KiROUND( ii * griSizeMM * pcbIUScale.IU_PER_MM );
1591
1592 if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1593 {
1594 glBegin( GL_LINES );
1595 glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1596 glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1597 glEnd();
1598
1599 if( ii != 0 )
1600 {
1601 glBegin( GL_LINES );
1602 glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1603 glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1604 glEnd();
1605 }
1606 }
1607
1608 if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1609 {
1610 glBegin( GL_LINES );
1611 glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1612 glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1613 glEnd();
1614
1615 if( ii != 0 )
1616 {
1617 glBegin( GL_LINES );
1618 glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1619 glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1620 glEnd();
1621 }
1622 }
1623
1624 if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1625 break;
1626 }
1627
1628 // Draw vertical grid on Z axis
1629 glNormal3f( 0.0, -1.0, 0.0 );
1630
1631 // Draw vertical grid lines (parallel to Z axis)
1632 double posy = -brd_center_pos.y * scale;
1633
1634 for( int ii = 0; ; ii++ )
1635 {
1636 if( (ii % 5) )
1637 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1638 else
1639 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1640 transparency );
1641
1642 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM;
1643
1644 glBegin( GL_LINES );
1645 xmax = ( brd_center_pos.x + delta ) * scale;
1646
1647 glVertex3f( xmax, posy, zmin );
1648 glVertex3f( xmax, posy, zmax );
1649 glEnd();
1650
1651 if( ii != 0 )
1652 {
1653 glBegin( GL_LINES );
1654 xmin = ( brd_center_pos.x - delta ) * scale;
1655 glVertex3f( xmin, posy, zmin );
1656 glVertex3f( xmin, posy, zmax );
1657 glEnd();
1658 }
1659
1660 if( delta > xsize / 2.0f )
1661 break;
1662 }
1663
1664 // Draw horizontal grid lines on Z axis (parallel to X axis)
1665 for( int ii = 0; ; ii++ )
1666 {
1667 if( ii % 5 )
1668 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1669 else
1670 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1671
1672 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM * scale;
1673
1674 if( delta <= zmax )
1675 {
1676 // Draw grid lines on Z axis (positive Z axis coordinates)
1677 glBegin( GL_LINES );
1678 glVertex3f( xmin, posy, delta );
1679 glVertex3f( xmax, posy, delta );
1680 glEnd();
1681 }
1682
1683 if( delta <= -zmin && ( ii != 0 ) )
1684 {
1685 // Draw grid lines on Z axis (negative Z axis coordinates)
1686 glBegin( GL_LINES );
1687 glVertex3f( xmin, posy, -delta );
1688 glVertex3f( xmax, posy, -delta );
1689 glEnd();
1690 }
1691
1692 if( ( delta > zmax ) && ( delta > -zmin ) )
1693 break;
1694 }
1695
1696 glDisable( GL_BLEND );
1697
1698 glEndList();
1699}
1700
1701
1703{
1704 // Unit cube: 1mm × 1mm × 1mm, centered at origin
1705 static SFVEC3F positions[24] = { // +Z (top)
1706 { -0.5f, -0.5f, 0.5f },
1707 { 0.5f, -0.5f, 0.5f },
1708 { 0.5f, 0.5f, 0.5f },
1709 { -0.5f, 0.5f, 0.5f },
1710
1711 // -Z (bottom)
1712 { -0.5f, 0.5f, -0.5f },
1713 { 0.5f, 0.5f, -0.5f },
1714 { 0.5f, -0.5f, -0.5f },
1715 { -0.5f, -0.5f, -0.5f },
1716
1717 // +X
1718 { 0.5f, -0.5f, -0.5f },
1719 { 0.5f, 0.5f, -0.5f },
1720 { 0.5f, 0.5f, 0.5f },
1721 { 0.5f, -0.5f, 0.5f },
1722
1723 // -X
1724 { -0.5f, -0.5f, 0.5f },
1725 { -0.5f, 0.5f, 0.5f },
1726 { -0.5f, 0.5f, -0.5f },
1727 { -0.5f, -0.5f, -0.5f },
1728
1729 // +Y
1730 { -0.5f, 0.5f, 0.5f },
1731 { 0.5f, 0.5f, 0.5f },
1732 { 0.5f, 0.5f, -0.5f },
1733 { -0.5f, 0.5f, -0.5f },
1734
1735 // -Y
1736 { -0.5f, -0.5f, -0.5f },
1737 { 0.5f, -0.5f, -0.5f },
1738 { 0.5f, -0.5f, 0.5f },
1739 { -0.5f, -0.5f, 0.5f }
1740 };
1741
1742 static SFVEC3F normals[24] = { // +Z
1743 { 0, 0, 1 },
1744 { 0, 0, 1 },
1745 { 0, 0, 1 },
1746 { 0, 0, 1 },
1747 // -Z
1748 { 0, 0, -1 },
1749 { 0, 0, -1 },
1750 { 0, 0, -1 },
1751 { 0, 0, -1 },
1752 // +X
1753 { 1, 0, 0 },
1754 { 1, 0, 0 },
1755 { 1, 0, 0 },
1756 { 1, 0, 0 },
1757 // -X
1758 { -1, 0, 0 },
1759 { -1, 0, 0 },
1760 { -1, 0, 0 },
1761 { -1, 0, 0 },
1762 // +Y
1763 { 0, 1, 0 },
1764 { 0, 1, 0 },
1765 { 0, 1, 0 },
1766 { 0, 1, 0 },
1767 // -Y
1768 { 0, -1, 0 },
1769 { 0, -1, 0 },
1770 { 0, -1, 0 },
1771 { 0, -1, 0 }
1772 };
1773
1774 static unsigned int indices[36] = {
1775 0, 1, 2, 0, 2, 3, // +Z
1776 4, 5, 6, 4, 6, 7, // -Z
1777 8, 9, 10, 8, 10, 11, // +X
1778 12, 13, 14, 12, 14, 15, // -X
1779 16, 17, 18, 16, 18, 19, // +Y
1780 20, 21, 22, 20, 22, 23 // -Y
1781 };
1782
1783 static SMATERIAL material = {
1784 SFVEC3F( 0.2f, 0.1f, 0.0f ), // ambient
1785 SFVEC3F( 1.0f, 0.5f, 0.0f ), // diffuse
1786 SFVEC3F( 0.0f, 0.0f, 0.0f ), // emissive
1787 SFVEC3F( 0.1f, 0.1f, 0.1f ), // specular
1788 0.1f, // shininess
1789 0.4f // transparency
1790 };
1791
1792 static SMESH mesh = { 24, positions, normals, nullptr, nullptr, 36, indices, 0 };
1793
1794 static S3DMODEL model = { 1, &mesh, 1, &material };
1795
1797}
GRID3D_TYPE
Grid types.
Definition 3d_enums.h:54
@ NORMAL
Use all material properties from model file.
Definition 3d_enums.h:72
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
EXTRUSION_MATERIAL_PROPS GetMaterialProps(EXTRUSION_MATERIAL aMaterial, const SFVEC3F &aDiffuse)
BOX2I CalcPlaceholderLocalBox(const FOOTPRINT *aFootprint)
Calculate a local space bounding box for a placeholder 3D model.
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
Helper class to handle information needed to display 3D board.
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr size_type GetHeight() const
Definition box2.h:215
A class used to derive camera objects from.
Definition camera.h:103
Implement a canvas based on a wxGLCanvas.
bool IsZero() const
Definition eda_angle.h:136
double AsRadians() const
Definition eda_angle.h:120
bool IsSelected() const
Definition eda_item.h:129
KIGFX::COLOR4D m_color
Definition footprint.h:110
static KIGFX::COLOR4D GetDefaultColor(EXTRUSION_MATERIAL aMaterial)
Definition footprint.h:118
EXTRUSION_MATERIAL m_material
Definition footprint.h:111
EDA_ANGLE GetOrientation() const
Definition footprint.h:408
bool IsFlipped() const
Definition footprint.h:602
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:394
VECTOR2I GetPosition() const override
Definition footprint.h:405
auto RunWithoutCtxLock(Func &&aFunction, Args &&... args)
Run the given function first releasing the GL context lock, then restoring it.
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
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
double r
Red component.
Definition color4d.h:393
double g
Green component.
Definition color4d.h:394
double a
Alpha component.
Definition color4d.h:396
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
double b
Blue component.
Definition color4d.h:395
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:697
void DrawBbox() const
Draw main bounding box of the model.
Definition 3d_model.cpp:571
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:590
Store the OpenGL display lists to related with a layer.
void ApplyScalePosition(float aZposition, float aZscale)
void SetItIsTransparent(bool aSetTransparent)
void DrawCulled(bool aDrawMiddle, const OPENGL_RENDER_LIST *aSubtractList=nullptr, const OPENGL_RENDER_LIST *bSubtractList=nullptr, const OPENGL_RENDER_LIST *cSubtractList=nullptr, const OPENGL_RENDER_LIST *dSubtractList=nullptr) const
Draw all layers if they are visible by the camera if camera position is above the layer.
void DrawAll(bool aDrawMiddle=true) const
Call to draw all the display lists.
GL_CONTEXT_MANAGER * GetGLContextManager()
Definition pgm_base.h:120
std::unique_ptr< BUSY_INDICATOR > CreateBusyIndicator() const
Return a created busy indicator, if a factory has been set, else a null pointer.
RENDER_3D_BASE(BOARD_ADAPTER &aBoardAdapter, CAMERA &aCamera)
bool m_canvasInitialized
Flag if the canvas specific for this render was already initialized.
wxSize m_windowSize
The window size that this camera is working.
BOARD_ADAPTER & m_boardAdapter
Settings reference in use for this render.
OPENGL_RENDER_LIST * m_board
OPENGL_RENDER_LIST * m_outerThroughHoleRings
OPENGL_RENDER_LIST * m_offboardPadsFront
SPHERES_GIZMO::GizmoSphereSelection getSelectedGizmoSphere() const
GRID3D_TYPE m_lastGridType
Stores the last grid type.
std::tuple< int, int, int, int > getGizmoViewport() const
OPENGL_RENDER_LIST * m_microviaHoles
void renderOpaqueModels(const glm::mat4 &aCameraViewMatrix)
void generate3dGrid(GRID3D_TYPE aGridType)
Create a 3D grid to an OpenGL display list.
void setLightFront(bool enabled)
std::map< const FOOTPRINT *, OPENGL_RENDER_LIST * > m_extrudedPadLists
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
MAP_OGL_DISP_LISTS m_layers
MAP_OGL_DISP_LISTS m_innerLayerHoles
OPENGL_RENDER_LIST * m_boardWithHoles
RENDER_3D_OPENGL(EDA_3D_CANVAS *aCanvas, BOARD_ADAPTER &aAdapter, CAMERA &aCamera)
MAP_OGL_DISP_LISTS m_outerLayerHoles
OPENGL_RENDER_LIST * m_offboardPadsBack
BOARD_ITEM * m_currentRollOverItem
void renderBoardBody(bool aSkipRenderHoles)
std::map< std::vector< float >, glm::mat4 > m_3dModelMatrixMap
std::map< wxString, MODEL_3D * > m_3dModelMap
OPENGL_RENDER_LIST * m_viaBackCover
OPENGL_RENDER_LIST * m_viaFrontCover
LIST_TRIANGLES m_triangles
store pointers so can be deleted latter
OPENGL_RENDER_LIST * m_outerViaThroughHoles
MODEL_3D * m_placeholderModel
OPENGL_RENDER_LIST * m_outerThroughHoles
void setLayerMaterial(PCB_LAYER_ID aLayerID)
OPENGL_RENDER_LIST * m_platedPadsFront
struct RENDER_3D_OPENGL::@136145154067207014164113243162246125147361200233 m_materials
void renderModel(const glm::mat4 &aCameraViewMatrix, const MODELTORENDER &aModelToRender, const SFVEC3F &aSelColor, const SFVEC3F *aCameraWorldPos)
int GetWaitForEditingTimeOut() override
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
void renderSolderMaskLayer(PCB_LAYER_ID aLayerID, float aZPos, bool aShowThickness, bool aSkipRenderHoles)
void renderTransparentModels(const glm::mat4 &aCameraViewMatrix)
std::map< const FOOTPRINT *, OPENGL_RENDER_LIST * > m_extrudedBodyLists
void get3dModelsSelected(std::list< MODELTORENDER > &aDstRenderList, bool aGetTop, bool aGetBot, bool aRenderTransparentOnly, bool aRenderSelectedOnly)
OPENGL_RENDER_LIST * m_postMachinePlugs
Board material plugs for backdrill/counterbore/countersink.
void setPlatedCopperAndDepthOffset(PCB_LAYER_ID aLayer_id)
void updateGizmoSelection(glm::mat4 aCameraRotationMatrix)
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,...
EDA_3D_CANVAS * m_canvas
void renderPlaceholderForFootprint(std::list< MODELTORENDER > &aDstRenderList, const glm::mat4 &aFpMatrix, const FOOTPRINT *aFootprint, bool aRenderTransparentOnly, bool aIsSelected, float aOpacity)
OPENGL_RENDER_LIST * m_padHoles
SPHERES_GIZMO * m_spheres_gizmo
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)
void handleGizmoMouseInput(int mouseX, int mouseY)
void setLightBottom(bool enabled)
void setGizmoViewport(int x, int y, int width, int height)
void setLightTop(bool enabled)
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:75
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:104
Renders a set of colored spheres in 3D space that act as a directional orientation gizmo.
GizmoSphereSelection
Enum to indicate which sphere (direction) is selected.
Store arrays of triangles to be used to create display lists.
@ LIGHTBLUE
Definition color4d.h:62
@ DARKGRAY
Definition color4d.h:46
#define DELETE_AND_FREE_MAP(map)
#define DELETE_AND_FREE(ptr)
#define _(s)
#define UNITS3D_TO_UNITSPCB
Implements a model viewer canvas.
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
@ GAUSSIAN_BLUR
Definition image.h:65
int MapPCBLayerTo3DLayer(PCB_LAYER_ID aLayer)
Definition layer_id.cpp:337
@ LAYER_3D_USER_1
Definition layer_ids.h:569
@ LAYER_3D_SOLDERMASK_TOP
Definition layer_ids.h:562
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition layer_ids.h:561
@ LAYER_3D_BOARD
Definition layer_ids.h:556
@ LAYER_3D_USER_45
Definition layer_ids.h:613
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:679
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ B_Adhes
Definition layer_ids.h:103
@ Edge_Cuts
Definition layer_ids.h:112
@ Dwgs_User
Definition layer_ids.h:107
@ F_Paste
Definition layer_ids.h:104
@ Cmts_User
Definition layer_ids.h:108
@ F_Adhes
Definition layer_ids.h:102
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ Eco1_User
Definition layer_ids.h:109
@ F_Mask
Definition layer_ids.h:97
@ B_Paste
Definition layer_ids.h:105
@ F_Fab
Definition layer_ids.h:119
@ Margin
Definition layer_ids.h:113
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ Eco2_User
Definition layer_ids.h:110
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ B_Fab
Definition layer_ids.h:118
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
void OglResetTextureState()
Reset to default state the texture settings.
void OglSetMaterial(const SMATERIAL &aMaterial, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Set OpenGL materials.
GLuint OglLoadTexture(const IMAGE &aImage)
Generate a new OpenGL texture.
Definition ogl_utils.cpp:95
void OglDrawBackground(const SFVEC4F &aTopColor, const SFVEC4F &aBotColor)
Define generic OpenGL functions that are common to any OpenGL target.
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
void init_lights()
static SFVEC4F premultiplyAlpha(const SFVEC4F &aInput)
static float TransparencyControl(float aGrayColorValue, float aTransparency)
Attempt to control the transparency based on the gray value of the color.
#define SIZE_OF_CIRCLE_TEXTURE
const int scale
Manage a bounding box defined by two SFVEC3F min max points.
Definition bbox_3d.h:43
SFVEC3F GetCenter() const
Return the center point of the bounding box.
Definition bbox_3d.cpp:132
bool DifferentiatePlatedCopper()
return true if platted copper aeras and non platted copper areas must be drawn using a different colo...
Store the a model based on meshes and materials.
Definition c3dmodel.h:95
float m_Shininess
Definition c3dmodel.h:43
SFVEC3F m_Specular
Definition c3dmodel.h:42
SFVEC3F m_Ambient
Definition c3dmodel.h:39
float m_Transparency
1.0 is completely transparent, 0.0 completely opaque
Definition c3dmodel.h:44
SFVEC3F m_Emissive
Definition c3dmodel.h:41
SFVEC3F m_Diffuse
Default diffuse color if m_Color is NULL.
Definition c3dmodel.h:40
Per-vertex normal/color/texcoors structure.
Definition c3dmodel.h:81
KIBIS_MODEL * model
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
glm::vec3 SFVEC3F
Definition xv3d_types.h:44
glm::vec4 SFVEC4F
Definition xv3d_types.h:46