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