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