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