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 pLayerDispList->DrawCulled( showThickness, solder_mask, throughHolesOuter, anti_board );
739 }
740
741 glPopMatrix();
742 }
743
744 glm::mat4 cameraViewMatrix;
745
746 glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
747
748 // Render 3D Models (Non-transparent)
749 renderOpaqueModels( cameraViewMatrix );
750
751 // Render extruded 3D bodies
752 {
754 const SFVEC3F extSelColor = m_boardAdapter.GetColor( extCfg.opengl_selection_color );
755
756 // Render extruded pad standoffs (metallic pins)
757 for( auto& [fp, renderList] : m_extrudedPadLists )
758 {
759 if( renderList )
760 {
761 bool highlight = false;
762
763 if( m_boardAdapter.m_IsBoardView )
764 {
765 if( fp->IsSelected() )
766 highlight = true;
767
768 if( extCfg.highlight_on_rollover && fp == m_currentRollOverItem )
769 highlight = true;
770 }
771
772 SMATERIAL mat = m_materials.m_Copper;
773 mat.m_Diffuse = SFVEC3F( 0.75f, 0.75f, 0.75f );
774 mat.m_Specular = SFVEC3F( 0.85f, 0.85f, 0.85f );
775 mat.m_Shininess = 0.6f * 128.0f;
776 mat.m_Transparency = 0.0f;
777
778 OglSetMaterial( mat, 1.0f, highlight, extSelColor );
779 renderList->DrawAll();
780 }
781 }
782
783 for( auto& [fp, renderList] : m_extrudedBodyLists )
784 {
785 const EXTRUDED_3D_BODY* body = fp->GetExtrudedBody();
786
787 if( !body )
788 continue;
789
790 if( renderList )
791 {
792 bool highlight = false;
793
794 if( m_boardAdapter.m_IsBoardView )
795 {
796 if( fp->IsSelected() )
797 highlight = true;
798
799 if( extCfg.highlight_on_rollover && fp == m_currentRollOverItem )
800 highlight = true;
801 }
802
803 KIGFX::COLOR4D c = body->m_color;
804
807
808 SMATERIAL mat;
809
810 SFVEC3F diffuse( c.r, c.g, c.b );
811 EXTRUSION_MATERIAL_PROPS props = GetMaterialProps( body->m_material, diffuse );
812
813 mat.m_Diffuse = diffuse;
814 mat.m_Ambient = props.m_Ambient;
815 mat.m_Specular = props.m_Specular;
816 mat.m_Shininess = props.m_Shininess;
817 mat.m_Emissive = SFVEC3F( 0.0f );
818 mat.m_Transparency = 1.0f - c.a;
819
820 OglSetMaterial( mat, 1.0f, highlight, extSelColor );
821 renderList->DrawAll();
822 }
823 }
824 }
825
826 // Display board body
827 if( layerFlags.test( LAYER_3D_BOARD ) )
828 renderBoardBody( skipRenderHoles );
829
830 // Display transparent mask layers
831 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP )
832 || layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
833 {
834 // add a depth buffer offset, it will help to hide some artifacts
835 // on silkscreen where the SolderMask is removed
836 glEnable( GL_POLYGON_OFFSET_FILL );
837 glPolygonOffset( 0.0f, -2.0f );
838
839 if( m_camera.GetPos().z > 0 )
840 {
841 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
842 {
844 showThickness, skipRenderHoles );
845 }
846
847 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
848 {
849 renderSolderMaskLayer( F_Mask, m_boardAdapter.GetLayerBottomZPos( F_Mask ),
850 showThickness, skipRenderHoles );
851 }
852 }
853 else
854 {
855 if( layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
856 {
857 renderSolderMaskLayer( F_Mask, m_boardAdapter.GetLayerBottomZPos( F_Mask ),
858 showThickness, skipRenderHoles );
859 }
860
861 if( layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
862 {
864 showThickness, skipRenderHoles );
865 }
866 }
867
868 glDisable( GL_POLYGON_OFFSET_FILL );
869 glPolygonOffset( 0.0f, 0.0f );
870 }
871
872 // Render 3D Models (Transparent)
873 // !TODO: this can be optimized. If there are no transparent models (or no opacity),
874 // then there is no need to make this function call.
875 glDepthMask( GL_FALSE );
876 glEnable( GL_BLEND );
877 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
878
879 // Enables Texture Env so it can combine model transparency with each footprint opacity
880 glEnable( GL_TEXTURE_2D );
881 glActiveTexture( GL_TEXTURE0 );
882
883 // Uses an existent texture so the glTexEnv operations will work.
884 glBindTexture( GL_TEXTURE_2D, m_circleTexture );
885
886 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
887 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
888 glTexEnvf( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
889
890 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR );
891 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
892
893 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
894 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
895
896 glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR );
897 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
898 glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
899 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
900
901 renderTransparentModels( cameraViewMatrix );
902
903 glDisable( GL_BLEND );
905
906 glDepthMask( GL_TRUE );
907
908 // Render Grid
909 if( cfg.grid_type != GRID3D_TYPE::NONE )
910 {
911 glDisable( GL_LIGHTING );
912
913 if( glIsList( m_grid ) )
914 glCallList( m_grid );
915
916 glEnable( GL_LIGHTING );
917 }
918
919 // Render 3D arrows
920 if( cfg.show_navigator )
921 m_spheres_gizmo->render3dSpheresGizmo( m_camera.GetRotationMatrix() );
922
923 // Return back to the original viewport (this is important if we want
924 // to take a screenshot after the render)
925 glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
926
927 return false;
928}
929
930
932{
933 glEnable( GL_LINE_SMOOTH );
934 glShadeModel( GL_SMOOTH );
935
936 // 4-byte pixel alignment
937 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
938
939 // Initialize the open GL texture to draw the filled semi-circle of the segments
941
942 if( !circleImage )
943 return false;
944
945 unsigned int circleRadius = ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 4;
946
947 circleImage->CircleFilled( ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
948 ( SIZE_OF_CIRCLE_TEXTURE / 2 ) - 0,
949 circleRadius,
950 0xFF );
951
952 IMAGE* circleImageBlured = new IMAGE( circleImage->GetWidth(), circleImage->GetHeight() );
953
954 circleImageBlured->EfxFilter_SkipCenter( circleImage, IMAGE_FILTER::GAUSSIAN_BLUR, circleRadius - 8 );
955
956 m_circleTexture = OglLoadTexture( *circleImageBlured );
957
958 delete circleImageBlured;
959 circleImageBlured = nullptr;
960
961 delete circleImage;
962 circleImage = nullptr;
963
964 init_lights();
965
966 // Use this mode if you want see the triangle lines (debug proposes)
967 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
968 m_canvasInitialized = true;
969
970 return true;
971}
972
973
975{
976 glEnable( GL_COLOR_MATERIAL );
977 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
978
979 const SFVEC4F ambient = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
980 const SFVEC4F diffuse = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
981 const SFVEC4F emissive = SFVEC4F( 0.0f, 0.0f, 0.0f, 1.0f );
982 const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
983
984 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
985 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
986
987 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
988 glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
989 glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
990}
991
992
994{
995#define DELETE_AND_FREE( ptr ) \
996 { \
997 delete ptr; \
998 ptr = nullptr; \
999 } \
1000
1001#define DELETE_AND_FREE_MAP( map ) \
1002 { \
1003 for( auto& [ layer, ptr ] : map ) \
1004 delete ptr; \
1005 \
1006 map.clear(); \
1007 }
1008
1009 if( glIsList( m_grid ) )
1010 glDeleteLists( m_grid, 1 );
1011
1012 m_grid = 0;
1013
1015
1020
1023
1024 for( TRIANGLE_DISPLAY_LIST* list : m_triangles )
1025 delete list;
1026
1027 m_triangles.clear();
1028
1030
1031 m_3dModelMatrixMap.clear();
1032
1037
1041
1047
1050}
1051
1052
1054 bool aShowThickness, bool aSkipRenderHoles )
1055{
1056 wxASSERT( (aLayerID == B_Mask) || (aLayerID == F_Mask) );
1057
1058 if( m_board )
1059 {
1060 OPENGL_RENDER_LIST* solder_mask = m_layers[ aLayerID ];
1061 OPENGL_RENDER_LIST* via_holes = aSkipRenderHoles ? nullptr : m_outerThroughHoles;
1062
1063 if( via_holes )
1064 via_holes->ApplyScalePosition( aZPos, m_boardAdapter.GetNonCopperLayerThickness() );
1065
1066 m_board->ApplyScalePosition( aZPos, m_boardAdapter.GetNonCopperLayerThickness() );
1067
1068 setLayerMaterial( aLayerID );
1069 m_board->SetItIsTransparent( true );
1070 m_board->DrawCulled( aShowThickness, solder_mask, via_holes );
1071
1072 if( aLayerID == F_Mask && m_viaFrontCover )
1073 {
1074 m_viaFrontCover->ApplyScalePosition( aZPos, 4 * m_boardAdapter.GetNonCopperLayerThickness() );
1075 m_viaFrontCover->DrawTop();
1076 }
1077 else if( aLayerID == B_Mask && m_viaBackCover )
1078 {
1079 m_viaBackCover->ApplyScalePosition( aZPos, 4 * m_boardAdapter.GetNonCopperLayerThickness() );
1080 m_viaBackCover->DrawBot();
1081 }
1082 }
1083}
1084
1085
1086void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList, bool aGetTop,
1087 bool aGetBot, bool aRenderTransparentOnly,
1088 bool aRenderSelectedOnly )
1089{
1090 wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
1091
1092 if( !m_boardAdapter.GetBoard() )
1093 return;
1094
1096
1097 // Go for all footprints
1098 for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
1099 {
1100 bool highlight = false;
1101
1102 if( m_boardAdapter.m_IsBoardView )
1103 {
1104 if( fp->IsSelected() )
1105 highlight = true;
1106
1108 highlight = true;
1109
1110 if( aRenderSelectedOnly != highlight )
1111 continue;
1112 }
1113
1114 bool hasModels = !fp->Models().empty();
1115 bool showMissing = m_boardAdapter.m_Cfg->m_Render.show_missing_models;
1116
1117 if( hasModels || showMissing )
1118 {
1119 if( m_boardAdapter.IsFootprintShown( fp ) )
1120 {
1121 const bool isFlipped = fp->IsFlipped();
1122
1123 if( aGetTop == !isFlipped || aGetBot == isFlipped )
1124 get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly,
1125 highlight );
1126 }
1127 }
1128 }
1129}
1130
1131
1132void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
1133 const FOOTPRINT* aFootprint,
1134 bool aRenderTransparentOnly, bool aIsSelected )
1135{
1136 if( !aFootprint->Models().empty() )
1137 {
1138 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1139
1140 VECTOR2I pos = aFootprint->GetPosition();
1141
1142 glm::mat4 fpMatrix( 1.0f );
1143
1144 fpMatrix = glm::translate( fpMatrix, SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1145 -pos.y * m_boardAdapter.BiuTo3dUnits(), zpos ) );
1146
1147 if( !aFootprint->GetOrientation().IsZero() )
1148 {
1149 fpMatrix = glm::rotate( fpMatrix, (float) aFootprint->GetOrientation().AsRadians(),
1150 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1151 }
1152
1153 if( aFootprint->IsFlipped() )
1154 {
1155 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1156 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1157 }
1158
1159 double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1160
1161 fpMatrix = glm::scale( fpMatrix, SFVEC3F( modelunit_to_3d_units_factor ) );
1162
1163 // Get the list of model files for this model
1164 for( const FP_3DMODEL& sM : aFootprint->Models() )
1165 {
1166 if( !sM.m_Show || sM.m_Filename.empty() )
1167 continue;
1168
1169 // Check if the model is present in our cache map
1170 auto cache_i = m_3dModelMap.find( sM.m_Filename );
1171
1172 if( cache_i == m_3dModelMap.end() )
1173 {
1174 renderPlaceholderForFootprint( aDstRenderList, fpMatrix, aFootprint, aRenderTransparentOnly,
1175 aIsSelected, aRenderTransparentOnly ? sM.m_Opacity : 1.0f );
1176 continue;
1177 }
1178
1179 if( const MODEL_3D* modelPtr = cache_i->second )
1180 {
1181 bool opaque = sM.m_Opacity >= 1.0;
1182
1183 if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
1184 ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
1185 {
1186 glm::mat4 modelworldMatrix = fpMatrix;
1187
1188 const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
1189 const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y,
1190 sM.m_Rotation.z );
1191 const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
1192
1193 std::vector<float> key = { offset.x, offset.y, offset.z,
1194 rotation.x, rotation.y, rotation.z,
1195 scale.x, scale.y, scale.z };
1196
1197 auto it = m_3dModelMatrixMap.find( key );
1198
1199 if( it != m_3dModelMatrixMap.end() )
1200 {
1201 modelworldMatrix *= it->second;
1202 }
1203 else
1204 {
1205 glm::mat4 mtx( 1.0f );
1206 mtx = glm::translate( mtx, offset );
1207 mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
1208 mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
1209 mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
1210 mtx = glm::scale( mtx, scale );
1211 m_3dModelMatrixMap[ key ] = mtx;
1212
1213 modelworldMatrix *= mtx;
1214 }
1215
1216 aDstRenderList.emplace_back( modelworldMatrix, modelPtr,
1217 aRenderTransparentOnly ? sM.m_Opacity : 1.0f,
1218 aRenderTransparentOnly,
1219 aFootprint->IsSelected() || aIsSelected );
1220 }
1221 }
1222 }
1223 }
1224 else
1225 {
1226 const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
1227
1228 VECTOR2I pos = aFootprint->GetPosition();
1229
1230 glm::mat4 fpMatrix( 1.0f );
1231
1232 fpMatrix = glm::translate( fpMatrix, SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1233 -pos.y * m_boardAdapter.BiuTo3dUnits(), zpos ) );
1234
1235 if( !aFootprint->GetOrientation().IsZero() )
1236 {
1237 fpMatrix = glm::rotate( fpMatrix, (float) aFootprint->GetOrientation().AsRadians(),
1238 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1239 }
1240
1241 if( aFootprint->IsFlipped() )
1242 {
1243 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1244 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1245 }
1246
1247 double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1248
1249 fpMatrix = glm::scale( fpMatrix, SFVEC3F( modelunit_to_3d_units_factor ) );
1250
1251 renderPlaceholderForFootprint( aDstRenderList, fpMatrix, aFootprint, aRenderTransparentOnly, aIsSelected,
1252 1.0f );
1253 }
1254}
1255
1256
1257void RENDER_3D_OPENGL::renderPlaceholderForFootprint( std::list<MODELTORENDER>& aDstRenderList,
1258 const glm::mat4& aFpMatrix, const FOOTPRINT* aFootprint,
1259 bool aRenderTransparentOnly, bool aIsSelected, float aOpacity )
1260{
1261 if( !m_boardAdapter.m_Cfg->m_Render.show_missing_models || !m_placeholderModel )
1262 return;
1263
1264 // Suppress placeholder if a valid extruded body was built
1265 if( m_extrudedBodyLists.count( aFootprint ) )
1266 return;
1267
1268 BOX2I localBox = CalcPlaceholderLocalBox( aFootprint );
1269
1270 float bboxW = std::abs( localBox.GetWidth() ) / pcbIUScale.IU_PER_MM * 0.9f;
1271 float bboxH = std::abs( localBox.GetHeight() ) / pcbIUScale.IU_PER_MM * 0.9f;
1272
1273 float scaleX = bboxW;
1274 float scaleY = bboxH;
1275 float scaleZ = std::min( bboxW, bboxH ) * 0.5f;
1276
1277 VECTOR2I localCenter = localBox.GetCenter();
1278 float offsetX = localCenter.x / pcbIUScale.IU_PER_MM;
1279 float offsetY = -localCenter.y / pcbIUScale.IU_PER_MM;
1280 float offsetZ = scaleZ * 0.5f;
1281
1282 if( aFootprint->IsFlipped() )
1283 offsetY = -offsetY;
1284
1285 glm::mat4 mtx = aFpMatrix;
1286 mtx = glm::translate( mtx, SFVEC3F( offsetX, offsetY, offsetZ ) );
1287 mtx = glm::scale( mtx, SFVEC3F( scaleX, scaleY, scaleZ ) );
1288
1289 bool placeholderOpaque = aOpacity >= 1.0;
1290
1291 if( ( !aRenderTransparentOnly && m_placeholderModel->HasOpaqueMeshes() && placeholderOpaque )
1292 || ( aRenderTransparentOnly && ( m_placeholderModel->HasTransparentMeshes() || !placeholderOpaque ) ) )
1293 {
1294 aDstRenderList.emplace_back( mtx, m_placeholderModel, aOpacity, aRenderTransparentOnly,
1295 aFootprint->IsSelected() || aIsSelected );
1296 }
1297}
1298
1299
1300void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
1301{
1303
1304 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1305
1306 glPushMatrix();
1307
1308 std::list<MODELTORENDER> renderList;
1309
1310 if( m_boardAdapter.m_IsBoardView )
1311 {
1312 renderList.clear();
1313
1314 get3dModelsSelected( renderList, true, true, false, true );
1315
1316 if( !renderList.empty() )
1317 {
1318 MODEL_3D::BeginDrawMulti( false );
1319
1320 for( const MODELTORENDER& mtr : renderList )
1321 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1322
1324 }
1325 }
1326
1327 renderList.clear();
1328 get3dModelsSelected( renderList, true, true, false, false );
1329
1330 if( !renderList.empty() )
1331 {
1333
1334 for( const MODELTORENDER& mtr : renderList )
1335 renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
1336
1338 }
1339
1340 glPopMatrix();
1341}
1342
1343
1344void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
1345{
1347
1348 const SFVEC3F selColor = m_boardAdapter.GetColor( cfg.opengl_selection_color );
1349
1350 std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
1351
1352 if( m_boardAdapter.m_IsBoardView )
1353 {
1354 // Get Transparent Selected
1355 get3dModelsSelected( renderListModels, true, true, true, true );
1356 }
1357
1358 // Get Transparent Not Selected
1359 get3dModelsSelected( renderListModels, true, true, true, false );
1360
1361 if( renderListModels.empty() )
1362 return;
1363
1364 std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
1365
1366 transparentModelList.reserve( renderListModels.size() );
1367
1368 // Calculate the distance to the camera for each model
1369 const SFVEC3F &cameraPos = m_camera.GetPos();
1370
1371 for( const MODELTORENDER& mtr : renderListModels )
1372 {
1373 const BBOX_3D& bBox = mtr.m_model->GetBBox();
1374 const SFVEC3F& bBoxCenter = bBox.GetCenter();
1375 const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
1376
1377 const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
1378
1379 transparentModelList.emplace_back( &mtr, distanceToCamera );
1380 }
1381
1382 // Sort from back to front
1383 std::sort( transparentModelList.begin(), transparentModelList.end(),
1384 [&]( std::pair<const MODELTORENDER *, float>& a,
1385 std::pair<const MODELTORENDER *, float>& b )
1386 {
1387 if( a.second != b.second )
1388 return a.second > b.second;
1389
1390 return a.first > b.first; // use pointers as a last resort
1391 } );
1392
1393 // Start rendering calls
1394 glPushMatrix();
1395
1396 bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
1397 m_boardAdapter.m_IsBoardView );
1398
1399 MODEL_3D::BeginDrawMulti( isUsingColorInformation );
1400
1401 for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
1402 {
1403 if( m_boardAdapter.m_IsBoardView )
1404 {
1405 // Toggle between using model color or the select color
1406 if( !isUsingColorInformation && !mtr.first->m_isSelected )
1407 {
1408 isUsingColorInformation = true;
1409
1410 glEnableClientState( GL_COLOR_ARRAY );
1411 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1412 glEnable( GL_COLOR_MATERIAL );
1413 }
1414 else if( isUsingColorInformation && mtr.first->m_isSelected )
1415 {
1416 isUsingColorInformation = false;
1417
1418 glDisableClientState( GL_COLOR_ARRAY );
1419 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1420 glDisable( GL_COLOR_MATERIAL );
1421 }
1422 }
1423
1424 // Render model, sort each individuall material group
1425 // by passing cameraPos
1426 renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
1427 }
1428
1430
1431 glPopMatrix();
1432}
1433
1434
1435void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
1436 const MODELTORENDER &aModelToRender,
1437 const SFVEC3F &aSelColor, const SFVEC3F *aCameraWorldPos )
1438{
1440
1441 const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
1442
1443 glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
1444
1445 aModelToRender.m_model->Draw( aModelToRender.m_isTransparent, aModelToRender.m_opacity,
1446 aModelToRender.m_isSelected, aSelColor,
1447 &aModelToRender.m_modelWorldMat, aCameraWorldPos );
1448
1449 if( cfg.show_model_bbox )
1450 {
1451 const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
1452
1453 if( !wasBlendEnabled )
1454 {
1455 glEnable( GL_BLEND );
1456 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1457 }
1458
1459 glDisable( GL_LIGHTING );
1460
1461 glLineWidth( 1 );
1462 aModelToRender.m_model->DrawBboxes();
1463
1464 glLineWidth( 4 );
1465 aModelToRender.m_model->DrawBbox();
1466
1467 glEnable( GL_LIGHTING );
1468
1469 if( !wasBlendEnabled )
1470 glDisable( GL_BLEND );
1471 }
1472}
1473
1474
1476{
1477 if( glIsList( m_grid ) )
1478 glDeleteLists( m_grid, 1 );
1479
1480 m_grid = 0;
1481
1482 if( aGridType == GRID3D_TYPE::NONE )
1483 return;
1484
1485 m_grid = glGenLists( 1 );
1486
1487 if( !glIsList( m_grid ) )
1488 return;
1489
1490 glNewList( m_grid, GL_COMPILE );
1491
1492 glEnable( GL_BLEND );
1493 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1494
1495 const double zpos = 0.0;
1496
1497 // Color of grid lines
1498 const SFVEC3F gridColor = m_boardAdapter.GetColor( DARKGRAY );
1499
1500 // Color of grid lines every 5 lines
1501 const SFVEC3F gridColor_marker = m_boardAdapter.GetColor( LIGHTBLUE );
1502 const double scale = m_boardAdapter.BiuTo3dUnits();
1503 const GLfloat transparency = 0.35f;
1504
1505 double griSizeMM = 0.0;
1506
1507 switch( aGridType )
1508 {
1509 case GRID3D_TYPE::GRID_1MM: griSizeMM = 1.0; break;
1510 case GRID3D_TYPE::GRID_2P5MM: griSizeMM = 2.5; break;
1511 case GRID3D_TYPE::GRID_5MM: griSizeMM = 5.0; break;
1512 case GRID3D_TYPE::GRID_10MM: griSizeMM = 10.0; break;
1513
1514 default:
1515 case GRID3D_TYPE::NONE: return;
1516 }
1517
1518 glNormal3f( 0.0, 0.0, 1.0 );
1519
1520 const VECTOR2I brd_size = m_boardAdapter.GetBoardSize();
1521 VECTOR2I brd_center_pos = m_boardAdapter.GetBoardPos();
1522
1523 brd_center_pos.y = -brd_center_pos.y;
1524
1525 const int xsize = std::max( brd_size.x, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1526 const int ysize = std::max( brd_size.y, pcbIUScale.mmToIU( 100 ) ) * 1.2;
1527
1528 // Grid limits, in 3D units
1529 double xmin = ( brd_center_pos.x - xsize / 2 ) * scale;
1530 double xmax = ( brd_center_pos.x + xsize / 2 ) * scale;
1531 double ymin = ( brd_center_pos.y - ysize / 2 ) * scale;
1532 double ymax = ( brd_center_pos.y + ysize / 2 ) * scale;
1533 double zmin = pcbIUScale.mmToIU( -50 ) * scale;
1534 double zmax = pcbIUScale.mmToIU( 100 ) * scale;
1535
1536 // Set rasterised line width (min value = 1)
1537 glLineWidth( 1 );
1538
1539 // Draw horizontal grid centered on 3D origin (center of the board)
1540 for( int ii = 0; ; ii++ )
1541 {
1542 if( (ii % 5) )
1543 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1544 else
1545 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1546 transparency );
1547
1548 const int delta = KiROUND( ii * griSizeMM * pcbIUScale.IU_PER_MM );
1549
1550 if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
1551 {
1552 glBegin( GL_LINES );
1553 glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
1554 glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
1555 glEnd();
1556
1557 if( ii != 0 )
1558 {
1559 glBegin( GL_LINES );
1560 glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
1561 glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
1562 glEnd();
1563 }
1564 }
1565
1566 if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
1567 {
1568 glBegin( GL_LINES );
1569 glVertex3f( xmin, -( brd_center_pos.y + delta ) * scale, zpos );
1570 glVertex3f( xmax, -( brd_center_pos.y + delta ) * scale, zpos );
1571 glEnd();
1572
1573 if( ii != 0 )
1574 {
1575 glBegin( GL_LINES );
1576 glVertex3f( xmin, -( brd_center_pos.y - delta ) * scale, zpos );
1577 glVertex3f( xmax, -( brd_center_pos.y - delta ) * scale, zpos );
1578 glEnd();
1579 }
1580 }
1581
1582 if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
1583 break;
1584 }
1585
1586 // Draw vertical grid on Z axis
1587 glNormal3f( 0.0, -1.0, 0.0 );
1588
1589 // Draw vertical grid lines (parallel to Z axis)
1590 double posy = -brd_center_pos.y * scale;
1591
1592 for( int ii = 0; ; ii++ )
1593 {
1594 if( (ii % 5) )
1595 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1596 else
1597 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b,
1598 transparency );
1599
1600 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM;
1601
1602 glBegin( GL_LINES );
1603 xmax = ( brd_center_pos.x + delta ) * scale;
1604
1605 glVertex3f( xmax, posy, zmin );
1606 glVertex3f( xmax, posy, zmax );
1607 glEnd();
1608
1609 if( ii != 0 )
1610 {
1611 glBegin( GL_LINES );
1612 xmin = ( brd_center_pos.x - delta ) * scale;
1613 glVertex3f( xmin, posy, zmin );
1614 glVertex3f( xmin, posy, zmax );
1615 glEnd();
1616 }
1617
1618 if( delta > xsize / 2.0f )
1619 break;
1620 }
1621
1622 // Draw horizontal grid lines on Z axis (parallel to X axis)
1623 for( int ii = 0; ; ii++ )
1624 {
1625 if( ii % 5 )
1626 glColor4f( gridColor.r, gridColor.g, gridColor.b, transparency );
1627 else
1628 glColor4f( gridColor_marker.r, gridColor_marker.g, gridColor_marker.b, transparency );
1629
1630 const double delta = ii * griSizeMM * pcbIUScale.IU_PER_MM * scale;
1631
1632 if( delta <= zmax )
1633 {
1634 // Draw grid lines on Z axis (positive Z axis coordinates)
1635 glBegin( GL_LINES );
1636 glVertex3f( xmin, posy, delta );
1637 glVertex3f( xmax, posy, delta );
1638 glEnd();
1639 }
1640
1641 if( delta <= -zmin && ( ii != 0 ) )
1642 {
1643 // Draw grid lines on Z axis (negative Z axis coordinates)
1644 glBegin( GL_LINES );
1645 glVertex3f( xmin, posy, -delta );
1646 glVertex3f( xmax, posy, -delta );
1647 glEnd();
1648 }
1649
1650 if( ( delta > zmax ) && ( delta > -zmin ) )
1651 break;
1652 }
1653
1654 glDisable( GL_BLEND );
1655
1656 glEndList();
1657}
1658
1659
1661{
1662 // Unit cube: 1mm × 1mm × 1mm, centered at origin
1663 static SFVEC3F positions[24] = { // +Z (top)
1664 { -0.5f, -0.5f, 0.5f },
1665 { 0.5f, -0.5f, 0.5f },
1666 { 0.5f, 0.5f, 0.5f },
1667 { -0.5f, 0.5f, 0.5f },
1668
1669 // -Z (bottom)
1670 { -0.5f, 0.5f, -0.5f },
1671 { 0.5f, 0.5f, -0.5f },
1672 { 0.5f, -0.5f, -0.5f },
1673 { -0.5f, -0.5f, -0.5f },
1674
1675 // +X
1676 { 0.5f, -0.5f, -0.5f },
1677 { 0.5f, 0.5f, -0.5f },
1678 { 0.5f, 0.5f, 0.5f },
1679 { 0.5f, -0.5f, 0.5f },
1680
1681 // -X
1682 { -0.5f, -0.5f, 0.5f },
1683 { -0.5f, 0.5f, 0.5f },
1684 { -0.5f, 0.5f, -0.5f },
1685 { -0.5f, -0.5f, -0.5f },
1686
1687 // +Y
1688 { -0.5f, 0.5f, 0.5f },
1689 { 0.5f, 0.5f, 0.5f },
1690 { 0.5f, 0.5f, -0.5f },
1691 { -0.5f, 0.5f, -0.5f },
1692
1693 // -Y
1694 { -0.5f, -0.5f, -0.5f },
1695 { 0.5f, -0.5f, -0.5f },
1696 { 0.5f, -0.5f, 0.5f },
1697 { -0.5f, -0.5f, 0.5f }
1698 };
1699
1700 static SFVEC3F normals[24] = { // +Z
1701 { 0, 0, 1 },
1702 { 0, 0, 1 },
1703 { 0, 0, 1 },
1704 { 0, 0, 1 },
1705 // -Z
1706 { 0, 0, -1 },
1707 { 0, 0, -1 },
1708 { 0, 0, -1 },
1709 { 0, 0, -1 },
1710 // +X
1711 { 1, 0, 0 },
1712 { 1, 0, 0 },
1713 { 1, 0, 0 },
1714 { 1, 0, 0 },
1715 // -X
1716 { -1, 0, 0 },
1717 { -1, 0, 0 },
1718 { -1, 0, 0 },
1719 { -1, 0, 0 },
1720 // +Y
1721 { 0, 1, 0 },
1722 { 0, 1, 0 },
1723 { 0, 1, 0 },
1724 { 0, 1, 0 },
1725 // -Y
1726 { 0, -1, 0 },
1727 { 0, -1, 0 },
1728 { 0, -1, 0 },
1729 { 0, -1, 0 }
1730 };
1731
1732 static unsigned int indices[36] = {
1733 0, 1, 2, 0, 2, 3, // +Z
1734 4, 5, 6, 4, 6, 7, // -Z
1735 8, 9, 10, 8, 10, 11, // +X
1736 12, 13, 14, 12, 14, 15, // -X
1737 16, 17, 18, 16, 18, 19, // +Y
1738 20, 21, 22, 20, 22, 23 // -Y
1739 };
1740
1741 static SMATERIAL material = {
1742 SFVEC3F( 0.2f, 0.1f, 0.0f ), // ambient
1743 SFVEC3F( 1.0f, 0.5f, 0.0f ), // diffuse
1744 SFVEC3F( 0.0f, 0.0f, 0.0f ), // emissive
1745 SFVEC3F( 0.1f, 0.1f, 0.1f ), // specular
1746 0.1f, // shininess
1747 0.4f // transparency
1748 };
1749
1750 static SMESH mesh = { 24, positions, normals, nullptr, nullptr, 36, indices, 0 };
1751
1752 static S3DMODEL model = { 1, &mesh, 1, &material };
1753
1755}
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:406
bool IsFlipped() const
Definition footprint.h:614
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:392
VECTOR2I GetPosition() const override
Definition footprint.h:403
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: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
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:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:100
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:337
@ LAYER_3D_USER_1
Definition layer_ids.h:565
@ LAYER_3D_SOLDERMASK_TOP
Definition layer_ids.h:558
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition layer_ids.h:557
@ LAYER_3D_BOARD
Definition layer_ids.h:552
@ LAYER_3D_USER_45
Definition layer_ids.h:609
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
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:91
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