KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eda_3d_canvas.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-2016 Mario Luzeiro <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <gal/opengl/kiglew.h> // Must be included first
26#include <gal/opengl/gl_utils.h>
27#include <wx/tokenzr.h>
28
30#include "eda_3d_canvas.h"
31#include <eda_3d_viewer_frame.h>
34#include <3d_viewer_id.h>
35#include <advanced_config.h>
36#include <build_version.h>
37#include <board.h>
38#include <pad.h>
39#include <pcb_field.h>
40#include <reporter.h>
42#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
43#include <bitmaps.h>
44#include <kiway_holder.h>
45#include <kiway.h>
46#include <macros.h>
47#include <pgm_base.h>
50#include <string_utils.h>
51#include <mail_type.h>
52#include <kiway_express.h>
53#include <fmt/format.h>
54
56
57
65const wxChar* EDA_3D_CANVAS::m_logTrace = wxT( "KI_TRACE_EDA_3D_CANVAS" );
66
67
68// A custom event, used to call DoRePaint during an idle time
69wxDEFINE_EVENT( wxEVT_REFRESH_CUSTOM_COMMAND, wxEvent );
70
71
72BEGIN_EVENT_TABLE( EDA_3D_CANVAS, HIDPI_GL_3D_CANVAS )
73 EVT_PAINT( EDA_3D_CANVAS::OnPaint )
74
75 // mouse events
76 EVT_LEFT_DOWN( EDA_3D_CANVAS::OnLeftDown )
77 EVT_LEFT_UP( EDA_3D_CANVAS::OnLeftUp )
78 EVT_MIDDLE_UP( EDA_3D_CANVAS::OnMiddleUp )
79 EVT_MIDDLE_DOWN( EDA_3D_CANVAS::OnMiddleDown)
80 EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightDown )
81 EVT_RIGHT_UP( EDA_3D_CANVAS::OnRightUp )
82 EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
83 EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
84 EVT_MAGNIFY( EDA_3D_CANVAS::OnMagnify )
85
86 // touch gesture events
87 EVT_GESTURE_ZOOM( wxID_ANY, EDA_3D_CANVAS::OnZoomGesture )
88 EVT_GESTURE_PAN( wxID_ANY, EDA_3D_CANVAS::OnPanGesture )
89 EVT_GESTURE_ROTATE( wxID_ANY, EDA_3D_CANVAS::OnRotateGesture )
90
91 // other events
92 EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
93 EVT_CUSTOM(wxEVT_REFRESH_CUSTOM_COMMAND, ID_CUSTOM_EVENT_1, EDA_3D_CANVAS::OnRefreshRequest )
94
96 EVT_SIZE( EDA_3D_CANVAS::OnResize )
97END_EVENT_TABLE()
98
99
100EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
101 BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera,
102 S3D_CACHE* a3DCachePointer ) :
103 HIDPI_GL_3D_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aCamera, aParent, aGLAttribs,
104 EDA_3D_CANVAS_ID, wxDefaultPosition,
105 wxDefaultSize, wxFULL_REPAINT_ON_RESIZE ),
106 m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
107 m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
108 m_boardAdapter( aBoardAdapter )
109{
110 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::EDA_3D_CANVAS" ) );
111
112 m_editing_timeout_timer.SetOwner( this );
113 Connect( m_editing_timeout_timer.GetId(), wxEVT_TIMER,
114 wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Editing ), nullptr, this );
115
116 m_redraw_trigger_timer.SetOwner( this );
117 Connect( m_redraw_trigger_timer.GetId(), wxEVT_TIMER,
118 wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Redraw ), nullptr, this );
119
121
124
125 wxASSERT( m_3d_render_raytracing != nullptr );
126 wxASSERT( m_3d_render_opengl != nullptr );
127
128 auto busy_indicator_factory =
129 []()
130 {
131 return std::make_unique<WX_BUSY_INDICATOR>();
132 };
133
134 m_3d_render_raytracing->SetBusyIndicatorFactory( busy_indicator_factory );
135 m_3d_render_opengl->SetBusyIndicatorFactory( busy_indicator_factory );
136
137 // We always start with the opengl engine (raytracing is avoided due to very
138 // long calculation time)
140
141 m_boardAdapter.ReloadColorSettings();
142
143 wxASSERT( a3DCachePointer != nullptr );
144 m_boardAdapter.Set3dCacheManager( a3DCachePointer );
145
146#if defined( __WXMSW__ )
147 EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_ROTATE_GESTURE | wxTOUCH_PAN_GESTURES );
148#elif defined( __WXGTK__ )
149 EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_ROTATE_GESTURE );
150#endif
151
152 const wxEventType events[] =
153 {
154 // Binding both EVT_CHAR and EVT_CHAR_HOOK ensures that all key events,
155 // especially special key like arrow keys, are handled by the GAL event dispatcher,
156 // and not sent to GUI without filtering, because they have a default action (scroll)
157 // that must not be called.
158 wxEVT_LEFT_UP, wxEVT_LEFT_DOWN, wxEVT_LEFT_DCLICK,
159 wxEVT_RIGHT_UP, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_DCLICK,
160 wxEVT_MIDDLE_UP, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_DCLICK,
161 wxEVT_MOTION, wxEVT_MOUSEWHEEL, wxEVT_CHAR, wxEVT_CHAR_HOOK,
162 wxEVT_MAGNIFY,
163 wxEVT_MENU_OPEN, wxEVT_MENU_CLOSE, wxEVT_MENU_HIGHLIGHT
164 };
165
166 for( wxEventType eventType : events )
167 Connect( eventType, wxEventHandler( EDA_3D_CANVAS::OnEvent ), nullptr, m_eventDispatcher );
168}
169
170
172{
173 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::~EDA_3D_CANVAS" ) );
174
176 m_accelerator3DShapes = nullptr;
177
179}
180
181
183{
184 if( m_glRC )
185 {
187 gl_mgr->LockCtx( m_glRC, this );
188
190 m_3d_render_raytracing = nullptr;
191
192 delete m_3d_render_opengl;
193 m_3d_render_opengl = nullptr;
194
195 // This is just a copy of a pointer, can safely be set to NULL.
196 m_3d_render = nullptr;
197
198 gl_mgr->UnlockCtx( m_glRC );
199 gl_mgr->DestroyCtx( m_glRC );
200 m_glRC = nullptr;
201 }
202}
203
204
205void EDA_3D_CANVAS::OnCloseWindow( wxCloseEvent& event )
206{
208
209 event.Skip();
210}
211
212
213void EDA_3D_CANVAS::OnResize( wxSizeEvent& event )
214{
216}
217
218
220{
221 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::initializeOpenGL" ) );
222
223 const GLenum err = glewInit();
224
225 if( GLEW_OK != err )
226 {
227 const wxString msgError = (const char*) glewGetErrorString( err );
228
229 wxLogMessage( msgError );
230
231 return false;
232 }
233 else
234 {
235 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::initializeOpenGL Using GLEW version %s" ),
236 From_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
237 }
238
239 SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
240 (const char*) glGetString( GL_VERSION ) );
241
242 wxString version = From_UTF8( (char *) glGetString( GL_VERSION ) );
243
244 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::%s OpenGL version string %s." ),
245 __WXFUNCTION__, version );
246
247 // Extract OpenGL version from string. This method is used because prior to OpenGL 2,
248 // getting the OpenGL major and minor version as integers didn't exist.
249 wxString tmp;
250
251 wxStringTokenizer tokenizer( version, " \t\r\n" );
252
253 if( tokenizer.HasMoreTokens() )
254 {
255 long major = 0;
256 long minor = 0;
257
258 tmp = tokenizer.GetNextToken();
259
260 tokenizer.SetString( tmp, wxString( wxT( "." ) ) );
261
262 if( tokenizer.HasMoreTokens() )
263 tokenizer.GetNextToken().ToLong( &major );
264
265 if( tokenizer.HasMoreTokens() )
266 tokenizer.GetNextToken().ToLong( &minor );
267
268 if( major < 2 || ( ( major == 2 ) && ( minor < 1 ) ) )
269 {
270 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::%s OpenGL ray tracing not supported." ),
271 __WXFUNCTION__ );
272
273 if( GetParent() )
274 {
275 wxCommandEvent evt( wxEVT_MENU, ID_DISABLE_RAY_TRACING );
276 GetParent()->ProcessWindowEvent( evt );
277 }
278
280 }
281
282 if( ( major == 1 ) && ( minor < 5 ) )
283 {
284 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::%s OpenGL not supported." ),
285 __WXFUNCTION__ );
286
288 }
289 }
290
293
294 return true;
295}
296
297
298void EDA_3D_CANVAS::GetScreenshot( wxImage& aDstImage )
299{
300 OglGetScreenshot( aDstImage );
301}
302
303
304void EDA_3D_CANVAS::ReloadRequest( BOARD* aBoard , S3D_CACHE* aCachePointer )
305{
306 if( aCachePointer != nullptr )
307 m_boardAdapter.Set3dCacheManager( aCachePointer );
308
309 if( aBoard != nullptr )
310 m_boardAdapter.SetBoard( aBoard );
311
312 m_boardAdapter.ReloadColorSettings();
313
314 if( m_3d_render )
315 m_3d_render->ReloadRequest();
316}
317
318
330
331
333{
335 {
336 wxString msg;
337
338 msg.Printf( wxT( "dx %3.2f" ), m_camera.GetCameraPos().x );
339 m_parentStatusBar->SetStatusText( msg, static_cast<int>( EDA_3D_VIEWER_STATUSBAR::X_POS ) );
340
341 msg.Printf( wxT( "dy %3.2f" ), m_camera.GetCameraPos().y );
342 m_parentStatusBar->SetStatusText( msg, static_cast<int>( EDA_3D_VIEWER_STATUSBAR::Y_POS ) );
343
344 msg.Printf( wxT( "zoom %3.2f" ), 1 / m_camera.GetZoom() );
345 m_parentStatusBar->SetStatusText( msg,
346 static_cast<int>( EDA_3D_VIEWER_STATUSBAR::ZOOM_LEVEL ) );
347 }
348}
349
350
351void EDA_3D_CANVAS::OnPaint( wxPaintEvent& aEvent )
352{
353 // Please have a look at: https://lists.launchpad.net/kicad-developers/msg25149.html
354 DoRePaint();
355}
356
357
359{
360 if( m_is_currently_painting.test_and_set() )
361 return;
362
363 // SwapBuffer requires the window to be shown before calling
364 if( !IsShownOnScreen() )
365 {
366 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::DoRePaint !IsShown" ) );
368 return;
369 }
370
371 // Because the board to draw is handled by the parent viewer frame,
372 // ensure this parent is still alive. When it is closed before the viewer
373 // frame, a paint event can be generated after the parent is closed,
374 // therefore with invalid board.
375 // This is dependent of the platform.
376 // Especially on OSX, but also on Windows, it frequently happens
377 if( !GetParent()->GetParent()->IsShownOnScreen() )
378 return; // The parent board editor frame is no more alive
379
380 wxString err_messages;
381 INFOBAR_REPORTER warningReporter( m_parentInfoBar );
383 int64_t start_time = GetRunningMicroSecs();
385
386 // "Makes the OpenGL state that is represented by the OpenGL rendering
387 // context context current, i.e. it will be used by all subsequent OpenGL calls.
388 // This function may only be called when the window is shown on screen"
389
390 // Explicitly create a new rendering context instance for this canvas.
391 if( m_glRC == nullptr )
392 m_glRC = gl_mgr->CreateCtx( this );
393
394 // CreateCtx could and does fail per sentry crash events, lets be graceful
395 if( m_glRC == nullptr )
396 {
397 warningReporter.Report( _( "OpenGL context creation error" ), RPT_SEVERITY_ERROR );
398 warningReporter.Finalize();
400 return;
401 }
402
403 gl_mgr->LockCtx( m_glRC, this );
404
405 // Set the OpenGL viewport according to the client size of this canvas.
406 // This is done here rather than in a wxSizeEvent handler because our
407 // OpenGL rendering context (and thus viewport setting) is used with
408 // multiple canvases: If we updated the viewport in the wxSizeEvent
409 // handler, changing the size of one canvas causes a viewport setting that
410 // is wrong when next another canvas is repainted.
411 wxSize clientSize = GetNativePixelSize();
412
413 const bool windows_size_changed = m_camera.SetCurWindowSize( clientSize );
414
415 // Initialize openGL if need
417 {
418 if( !initializeOpenGL() )
419 {
420 gl_mgr->UnlockCtx( m_glRC );
422
423 return;
424 }
425
427 {
428 warningReporter.Report( _( "Your OpenGL version is not supported. Minimum required "
429 "is 1.5." ), RPT_SEVERITY_ERROR );
430
431 warningReporter.Finalize();
432 }
433 }
434
436 {
437 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
438 glClear( GL_COLOR_BUFFER_BIT );
439
440 SwapBuffers();
441
442 gl_mgr->UnlockCtx( m_glRC );
444
445 return;
446 }
447
448 // Don't attempt to ray trace if OpenGL doesn't support it.
450 {
453 m_boardAdapter.m_Cfg->m_Render.engine = RENDER_ENGINE::OPENGL;
454 }
455
456 // Check if a raytracing was requested and need to switch to raytracing mode
457 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
458 {
459 const bool was_camera_changed = m_camera.ParametersChanged();
460
461 // It reverts back to OpenGL mode if it was requested a raytracing
462 // render of the current scene. AND the mouse / camera is moving
463 if( ( m_mouse_is_moving || m_camera_is_moving || was_camera_changed
464 || windows_size_changed )
466 {
469 }
470 }
471
472 float curtime_delta_s = 0.0f;
473
475 {
476 const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
477 // Convert microseconds to seconds as float and apply speed multiplier
478 curtime_delta_s = static_cast<float>( static_cast<double>( curtime_delta ) / 1e6 )
480 m_camera.Interpolate( curtime_delta_s );
481
482 if( curtime_delta_s > 1.0f )
483 {
484 m_render_pivot = false;
485 m_camera_is_moving = false;
486 m_mouse_was_moved = true;
487
490 }
491 else
492 {
494 }
495 }
496
497 // It will return true if the render request a new redraw
498 bool requested_redraw = false;
499
500 if( m_3d_render )
501 {
502 try
503 {
504 m_3d_render->SetCurWindowSize( clientSize );
505
506 bool reloadRaytracingForCalculations = false;
507
508 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL
509 && m_3d_render_opengl->IsReloadRequestPending() )
510 {
511 reloadRaytracingForCalculations = true;
512 }
513
514 requested_redraw = m_3d_render->Redraw( m_mouse_was_moved || m_camera_is_moving,
515 &activityReporter, &warningReporter );
516
517 // Raytracer renderer is responsible for some features also used by the OpenGL
518 // renderer.
519 // FIXME: Presumably because raytracing renderer reload is called only after current
520 // renderer redraw, the old zoom value stays for a single frame. This is ugly, but only
521 // cosmetic, so I'm not fixing that for now: I don't know how to do this without
522 // reloading twice (maybe it's not too bad of an idea?) or doing a complicated
523 // refactor.
524 if( reloadRaytracingForCalculations )
525 m_3d_render_raytracing->Reload( nullptr, nullptr, true );
526 }
527 catch( std::runtime_error& )
528 {
532 gl_mgr->UnlockCtx( m_glRC );
534 return;
535 }
536 }
537
538 if( m_render_pivot )
539 {
540 const float scale = glm::min( m_camera.GetZoom(), 1.0f );
541 render_pivot( curtime_delta_s, scale );
542 }
543
544 // This will only be enabled by the 3d mouse plugin, so we can leave
545 // it as a simple if statement
547 {
548 const float scale = glm::min( m_camera.GetZoom(), 1.0f );
550 }
551
552 // "Swaps the double-buffer of this window, making the back-buffer the
553 // front-buffer and vice versa, so that the output of the previous OpenGL
554 // commands is displayed on the window."
555 SwapBuffers();
556
557 gl_mgr->UnlockCtx( m_glRC );
558
560 {
561 // Calculation time in milliseconds
562 const double calculation_time = (double)( GetRunningMicroSecs() - start_time ) / 1e3;
563
564 activityReporter.Report( wxString::Format( _( "Last render time %.0f ms" ),
565 calculation_time ) );
566 }
567
568 // This will reset the flag of camera parameters changed
569 m_camera.ParametersChanged();
570
571 warningReporter.Finalize();
572
573 if( !err_messages.IsEmpty() )
574 wxLogMessage( err_messages );
575
576 if( ( !m_camera_is_moving ) && requested_redraw )
577 {
578 m_mouse_was_moved = false;
579 Request_refresh( false );
580 }
581
582 static constexpr std::array<VIEW3D_TYPE, static_cast<int>( SPHERES_GIZMO::GizmoSphereSelection::Count )>
585
586 SPHERES_GIZMO::GizmoSphereSelection selectedGizmoSphere = m_3d_render_opengl->getSelectedGizmoSphere();
587 int index = static_cast<int>( selectedGizmoSphere );
588 if( index >= 0 && index < static_cast<int>( viewTable.size() ) )
589 {
590 SetView3D( viewTable[index] );
591 }
592
593 m_3d_render_opengl->resetSelectedGizmoSphere();
594
596}
597
598
599void EDA_3D_CANVAS::RenderToFrameBuffer( unsigned char* buffer, int width, int height )
600{
601 if( m_is_currently_painting.test_and_set() )
602 return;
603
604 // Validate input parameters
605 if( !buffer || width <= 0 || height <= 0 )
606 {
608 return;
609 }
610
611 // Because the board to draw is handled by the parent viewer frame,
612 // ensure this parent is still alive
613 if( !GetParent() || !GetParent()->GetParent() || !GetParent()->GetParent()->IsShownOnScreen() )
614 {
616 return;
617 }
618
619 wxString err_messages;
620 int64_t start_time = GetRunningMicroSecs();
622
623 // Create OpenGL context if needed
624 if( m_glRC == nullptr )
625 m_glRC = gl_mgr->CreateCtx( this );
626
627 if( m_glRC == nullptr )
628 {
629 wxLogError( _( "OpenGL context creation error" ) );
631 return;
632 }
633
634 gl_mgr->LockCtx( m_glRC, this );
635
636 // Set up framebuffer objects for off-screen rendering
637 GLuint framebuffer = 0;
638 GLuint colorTexture = 0;
639 GLuint depthBuffer = 0;
640 GLint oldFramebuffer = 0;
641 GLint oldViewport[4];
642
643 // Save current state
644 glGetIntegerv( GL_FRAMEBUFFER_BINDING, &oldFramebuffer );
645 glGetIntegerv( GL_VIEWPORT, oldViewport );
646
647 // Create and bind framebuffer
648 glGenFramebuffers( 1, &framebuffer );
649 glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
650
651 // Create color texture attachment
652 glGenTextures( 1, &colorTexture );
653 glBindTexture( GL_TEXTURE_2D, colorTexture );
654 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
655 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
656 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
657 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
658 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
659 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0 );
660
661 // Create depth renderbuffer attachment
662 glGenRenderbuffers( 1, &depthBuffer );
663 glBindRenderbuffer( GL_RENDERBUFFER, depthBuffer );
664 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height );
665 glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer );
666
667 auto resetState = std::unique_ptr<void, std::function<void(void*)>>(
668 reinterpret_cast<void*>(1),
669 [&](void*) {
670 glBindFramebuffer( GL_FRAMEBUFFER, oldFramebuffer );
671 glViewport( oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3] );
672 glDeleteFramebuffers( 1, &framebuffer );
673 glDeleteTextures( 1, &colorTexture );
674 glDeleteRenderbuffers( 1, &depthBuffer );
675 gl_mgr->UnlockCtx( m_glRC );
677 }
678 );
679
680 // Check framebuffer completeness
681 GLenum framebufferStatus = glCheckFramebufferStatus( GL_FRAMEBUFFER );
682
683 if( framebufferStatus != GL_FRAMEBUFFER_COMPLETE )
684 {
685 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer Framebuffer incomplete: 0x%04X" ),
686 framebufferStatus );
687
688 return;
689 }
690
691 // Set viewport for off-screen rendering
692 glViewport( 0, 0, width, height );
693
694 // Set window size for camera and rendering
695 wxSize clientSize( width, height );
696 const bool windows_size_changed = m_camera.SetCurWindowSize( clientSize );
697
698 // Initialize OpenGL if needed
700 {
701 if( !initializeOpenGL() )
702 {
703 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer OpenGL initialization failed." ) );
704 return;
705 }
706
708 {
709 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer OpenGL version not supported." ) );
710 }
711 }
712
714 {
715 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
716 glClear( GL_COLOR_BUFFER_BIT );
717
718 // Read black screen to buffer
719 glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
720 return;
721 }
722
723 // Handle raytracing/OpenGL renderer selection
725 {
728 m_boardAdapter.m_Cfg->m_Render.engine = RENDER_ENGINE::OPENGL;
729 }
730
731 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
732 {
733 const bool was_camera_changed = m_camera.ParametersChanged();
734
735 if( ( m_mouse_is_moving || m_camera_is_moving || was_camera_changed || windows_size_changed )
737 {
740 }
741 }
742
743 // Handle camera animation (simplified for off-screen rendering)
744 float curtime_delta_s = 0.0f;
746 {
747 const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
748 curtime_delta_s = static_cast<float>( static_cast<double>( curtime_delta ) / 1e6 )
750 m_camera.Interpolate( curtime_delta_s );
751
752 if( curtime_delta_s > 1.0f )
753 {
754 m_render_pivot = false;
755 m_camera_is_moving = false;
756 m_mouse_was_moved = true;
757 }
758 }
759
760 // Perform the actual rendering
761 bool requested_redraw = false;
762 if( m_3d_render )
763 {
764 try
765 {
766 m_3d_render->SetCurWindowSize( clientSize );
767
768 bool reloadRaytracingForCalculations = false;
769 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL
770 && m_3d_render_opengl->IsReloadRequestPending() )
771 {
772 reloadRaytracingForCalculations = true;
773 }
774
775 requested_redraw = m_3d_render->Redraw( false, nullptr, nullptr );
776
777 if( reloadRaytracingForCalculations )
778 m_3d_render_raytracing->Reload( nullptr, nullptr, true );
779 }
780 catch( std::runtime_error& )
781 {
785 return;
786 }
787 }
788
789 // Read pixels from framebuffer to the provided buffer
790 // Note: This reads RGB format. Adjust format as needed.
791 glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
792
793 // Check for OpenGL errors
794 GLenum error = glGetError();
795 if( error != GL_NO_ERROR )
796 {
797 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer OpenGL error: 0x%04X" ), error );
798 err_messages += wxString::Format( _( "OpenGL error during off-screen rendering: 0x%04X\n" ), error );
799 }
800
801 // Reset camera parameters changed flag
802 m_camera.ParametersChanged();
803
804 if( !err_messages.IsEmpty() )
805 wxLogMessage( err_messages );
806}
807
808
810{
811 m_eventDispatcher = aEventDispatcher;
812}
813
814
815void EDA_3D_CANVAS::OnEvent( wxEvent& aEvent )
816{
817 if( !m_eventDispatcher )
818 aEvent.Skip();
819 else
820 m_eventDispatcher->DispatchWxEvent( aEvent );
821
822 Refresh();
823}
824
825
826void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent& event )
827{
828 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnEraseBackground" ) );
829 // Do nothing, to avoid flashing.
830}
831
832
833void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event )
834{
835 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnMouseWheel" ) );
836
837 OnMouseWheelCamera( event, m_boardAdapter.m_MousewheelPanning );
838
840 {
844 }
845}
846
847
848void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
849{
850 SetFocus();
851
853 return;
854
855 //m_is_moving_mouse = true;
857
858 float magnification = ( event.GetMagnification() + 1.0f );
859
860 m_camera.Zoom( magnification );
861
864}
865
866
867void EDA_3D_CANVAS::OnZoomGesture( wxZoomGestureEvent& aEvent )
868{
869 SetFocus();
870
871 if( aEvent.IsGestureStart() )
872 {
874 m_camera.SetCurMousePosition( aEvent.GetPosition() );
875 }
876
878 return;
879
881
882 m_camera.Pan( aEvent.GetPosition() );
883 m_camera.SetCurMousePosition( aEvent.GetPosition() );
884
885 m_camera.Zoom( static_cast<float>( aEvent.GetZoomFactor() / m_gestureLastZoomFactor ) );
886
887 m_gestureLastZoomFactor = aEvent.GetZoomFactor();
888
891}
892
893
894void EDA_3D_CANVAS::OnPanGesture( wxPanGestureEvent& aEvent )
895{
896 SetFocus();
897
898 if( aEvent.IsGestureStart() )
899 m_camera.SetCurMousePosition( aEvent.GetPosition() );
900
902 return;
903
904 m_camera.Pan( aEvent.GetPosition() );
905 m_camera.SetCurMousePosition( aEvent.GetPosition() );
906
909}
910
911
912void EDA_3D_CANVAS::OnRotateGesture( wxRotateGestureEvent& aEvent )
913{
914 SetFocus();
915
916 if( aEvent.IsGestureStart() )
917 {
919 m_camera.SetCurMousePosition( aEvent.GetPosition() );
920
921 // We don't want to process the first angle
922 return;
923 }
924
926 return;
927
928 m_camera.RotateScreen( static_cast<float>( m_gestureLastAngle - aEvent.GetRotationAngle() ) );
929 m_gestureLastAngle = aEvent.GetRotationAngle();
930
933}
934
935
936void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
937{
938 if( m_3d_render && m_3d_render->IsReloadRequestPending() )
939 return; // Prevents using invalid m_3d_render_raytracing data
940
942 return;
943
944 OnMouseMoveCamera( event );
945
947 {
950 // *Do not* reactivate the timer here during the mouse move command:
951 // OnMiddleUp() will do it at the end of mouse drag/move command
952 }
953
954 if( !event.Dragging() && m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
955 {
958 BOARD_ITEM* rollOverItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
959
960 auto printNetInfo = []( BOARD_CONNECTED_ITEM* aItem )
961 {
962 return wxString::Format( _( "Net %s\tNet class %s" ), aItem->GetNet()->GetNetname(),
963 aItem->GetNet()->GetNetClass()->GetHumanReadableName() );
964 };
965
966 if( rollOverItem )
967 {
968 wxString msg;
969
970 if( rollOverItem != m_currentRollOverItem )
971 {
972 m_3d_render_opengl->SetCurrentRollOverItem( rollOverItem );
973 m_currentRollOverItem = rollOverItem;
974
976 }
977
978 switch( rollOverItem->Type() )
979 {
980 case PCB_PAD_T:
981 {
982 PAD* pad = static_cast<PAD*>( rollOverItem );
983
984 if( !pad->GetNumber().IsEmpty() )
985 msg += wxString::Format( _( "Pad %s\t" ), pad->GetNumber() );
986
987 if( pad->IsOnCopperLayer() )
988 msg += printNetInfo( pad );
989
990 break;
991 }
992
993 case PCB_FOOTPRINT_T:
994 {
995 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( rollOverItem );
996 msg += footprint->GetReference();
997 break;
998 }
999
1000 case PCB_TRACE_T:
1001 case PCB_VIA_T:
1002 case PCB_ARC_T:
1003 {
1004 PCB_TRACK* track = static_cast<PCB_TRACK*>( rollOverItem );
1005 msg += printNetInfo( track );
1006 break;
1007 }
1008
1009 case PCB_ZONE_T:
1010 {
1011 ZONE* zone = static_cast<ZONE*>( rollOverItem );
1012
1013 if( !zone->GetZoneName().IsEmpty() )
1014 {
1015 if( zone->GetIsRuleArea() )
1016 msg += wxString::Format( _( "Rule area %s\t" ), zone->GetZoneName() );
1017 else
1018 msg += wxString::Format( _( "Zone %s\t" ), zone->GetZoneName() );
1019 }
1020
1021 if( zone->IsOnCopperLayer() )
1022 msg += printNetInfo( zone );
1023
1024 break;
1025 }
1026
1027 default:
1028 break;
1029 }
1030
1031 reporter.Report( msg );
1032 }
1033 else
1034 {
1036 && m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
1037 {
1038 m_3d_render_opengl->SetCurrentRollOverItem( nullptr );
1040
1041 reporter.Report( wxEmptyString );
1042 }
1043
1044 m_currentRollOverItem = nullptr;
1045 }
1046 }
1047}
1048
1049
1050void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent& event )
1051{
1052 SetFocus();
1054
1055 // Ensure m_camera.m_lastPosition (current mouse position) is up to date for
1056 // future drag events (can be not the case when left clicking after
1057 // opening a context menu)
1058 OnMouseMoveCamera( event );
1059
1060 if( !event.Dragging() && ( m_3d_render_raytracing != nullptr ) )
1061 {
1062 RAY mouseRay = getRayAtCurrentMousePosition();
1063
1064 BOARD_ITEM* intersectedBoardItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
1065
1066 if( intersectedBoardItem )
1067 {
1068 FOOTPRINT* footprint = nullptr;
1069
1070 switch( intersectedBoardItem->Type() )
1071 {
1072 case PCB_FOOTPRINT_T:
1073 footprint = static_cast<FOOTPRINT*>( intersectedBoardItem );
1074 break;
1075
1076 case PCB_PAD_T:
1077 footprint = static_cast<PAD*>( intersectedBoardItem )->GetParentFootprint();
1078 break;
1079
1080 case PCB_FIELD_T:
1081 footprint = static_cast<PCB_FIELD*>( intersectedBoardItem )->GetParentFootprint();
1082 break;
1083
1084 default:
1085 break;
1086 }
1087
1088 if( footprint )
1089 {
1090 // We send a message (by ExpressMail) to the board and schematic editor, but only
1091 // if the manager of this canvas is a EDA_3D_VIEWER_FRAME, because only this
1092 // kind of frame has ExpressMail stuff
1093 EDA_3D_VIEWER_FRAME* frame = dynamic_cast<EDA_3D_VIEWER_FRAME*>( GetParent() );
1094
1095 if( frame )
1096 {
1097 std::string command = fmt::format( "$SELECT: 0,F{}",
1098 EscapeString( footprint->GetReference(), CTX_IPC ).ToStdString() );
1099
1100 frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_SELECTION, command, frame );
1101 frame->Kiway().ExpressMail( FRAME_SCH, MAIL_SELECTION, command, frame );
1102 }
1103 }
1104 }
1105 }
1106}
1107
1108
1109void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent& event )
1110{
1111 if( m_camera_is_moving )
1112 return;
1113
1114 if( m_mouse_is_moving )
1115 {
1116 m_mouse_is_moving = false;
1118 }
1119
1120 wxSize logicalSize = GetClientSize();
1121 int logicalW = logicalSize.GetWidth();
1122 int logicalH = logicalSize.GetHeight();
1123
1124 int gizmo_x = 0, gizmo_y = 0, gizmo_width = 0, gizmo_height = 0;
1125 std::tie( gizmo_x, gizmo_y, gizmo_width, gizmo_height ) = m_3d_render_opengl->getGizmoViewport();
1126
1127 float scaleX = static_cast<float>( static_cast<double>( gizmo_width ) / static_cast<double>( logicalW ) );
1128 float scaleY = static_cast<float>( static_cast<double>( gizmo_height ) / static_cast<double>( logicalH ) );
1129
1130 int scaledMouseX = static_cast<int>( static_cast<float>( event.GetX() ) * scaleX );
1131 int scaledMouseY = static_cast<int>( static_cast<float>( logicalH - event.GetY() ) * scaleY );
1132
1133 m_3d_render_opengl->handleGizmoMouseInput( scaledMouseX, scaledMouseY );
1134 Refresh();
1135}
1136
1137
1138void EDA_3D_CANVAS::OnRightDown( wxMouseEvent& event )
1139{
1140 SetFocus();
1142
1143 // Ensure m_camera.m_lastPosition is up to date for future drag events.
1144 OnMouseMoveCamera( event );
1145}
1146
1147
1148void EDA_3D_CANVAS::OnRightUp( wxMouseEvent& event )
1149{
1150 if( m_camera_is_moving )
1151 return;
1152
1153 if( m_mouse_is_moving )
1154 {
1155 m_mouse_is_moving = false;
1157 }
1158}
1159
1160
1161void EDA_3D_CANVAS::OnMiddleDown( wxMouseEvent& event )
1162{
1163 SetFocus();
1165}
1166
1167
1168void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent& event )
1169{
1170 if( m_camera_is_moving )
1171 return;
1172
1173 if( m_mouse_is_moving )
1174 {
1175 m_mouse_is_moving = false;
1177 }
1178 else
1179 {
1181 }
1182}
1183
1184
1185void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent& aEvent )
1186{
1187 if( aEvent.GetId() != m_editing_timeout_timer.GetId() )
1188 {
1189 aEvent.Skip();
1190 return;
1191 }
1192
1193 m_mouse_is_moving = false;
1194 m_mouse_was_moved = false;
1195
1197}
1198
1199
1204
1205
1207{
1208 if( m_3d_render )
1209 m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut(), wxTIMER_ONE_SHOT );
1210}
1211
1212
1213void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent& aEvent )
1214{
1215 if( aEvent.GetId() != m_redraw_trigger_timer.GetId() )
1216 {
1217 aEvent.Skip();
1218 return;
1219 }
1220
1221 Request_refresh( true );
1222}
1223
1224
1225void EDA_3D_CANVAS::OnRefreshRequest( wxEvent& aEvent )
1226{
1227 Refresh();
1228}
1229
1230
1231void EDA_3D_CANVAS::Request_refresh( bool aRedrawImmediately )
1232{
1233 if( aRedrawImmediately )
1234 {
1235 // Just calling Refresh() does not work always
1236 // Using an event to call DoRepaint ensure the repaint code will be executed,
1237 // and PostEvent will take priority to other events like mouse movements, keys, etc.
1238 // and is executed during the next idle time
1239 wxCommandEvent redrawEvent( wxEVT_REFRESH_CUSTOM_COMMAND, ID_CUSTOM_EVENT_1 );
1240 wxPostEvent( this, redrawEvent );
1241 }
1242 else
1243 {
1244 // Schedule a timed redraw
1245 m_redraw_trigger_timer.Start( 10 , wxTIMER_ONE_SHOT );
1246 }
1247}
1248
1249
1250void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRenderPivot )
1251{
1252 wxASSERT( aMovingSpeed > FLT_EPSILON );
1253
1254 // Fast forward the animation if the animation is disabled
1255 if( !m_animation_enabled )
1256 {
1257 m_camera.Interpolate( 1.0f );
1258 DisplayStatus();
1260 return;
1261 }
1262
1263 // Map speed multiplier option to actual multiplier value
1264 // [1,2,3,4,5] -> [0.25, 0.5, 1, 2, 4]
1265 aMovingSpeed *= static_cast<float>( ( 1 << m_moving_speed_multiplier ) ) / 8.0f;
1266
1267 m_render_pivot = aRenderPivot;
1268 m_camera_moving_speed = aMovingSpeed;
1269
1271
1272 DisplayStatus();
1274
1275 m_camera_is_moving = true;
1276
1278}
1279
1280
1282{
1283 RAY mouseRay = getRayAtCurrentMousePosition();
1284
1285 float hit_t = 0.0f;
1286
1287 // Test it with the board bounding box
1288 if( m_boardAdapter.GetBBox().Intersect( mouseRay, &hit_t ) )
1289 {
1290 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1291 m_camera.SetT0_and_T1_current_T();
1292 m_camera.SetLookAtPos_T1( mouseRay.at( hit_t ) );
1293 m_camera.ResetXYpos_T1();
1294
1296 }
1297}
1298
1299
1301{
1302 if( m_camera_is_moving )
1303 return false;
1304
1305 const float delta_move = m_delta_move_step_factor * m_camera.GetZoom();
1306 const float arrow_moving_time_speed = 8.0f;
1307
1308 switch( aRequestedView )
1309 {
1312 return true;
1313
1315 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1316 m_camera.SetT0_and_T1_current_T();
1317 m_camera.Pan_T1( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
1318 request_start_moving_camera( arrow_moving_time_speed, false );
1319 return true;
1320
1322 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1323 m_camera.SetT0_and_T1_current_T();
1324 m_camera.Pan_T1( SFVEC3F( +delta_move, 0.0f, 0.0f ) );
1325 request_start_moving_camera( arrow_moving_time_speed, false );
1326 return true;
1327
1329 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1330 m_camera.SetT0_and_T1_current_T();
1331 m_camera.Pan_T1( SFVEC3F( 0.0f, +delta_move, 0.0f ) );
1332 request_start_moving_camera( arrow_moving_time_speed, false );
1333 return true;
1334
1336 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1337 m_camera.SetT0_and_T1_current_T();
1338 m_camera.Pan_T1( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
1339 request_start_moving_camera( arrow_moving_time_speed, false );
1340 return true;
1341
1343 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1344 m_camera.SetT0_and_T1_current_T();
1345 m_camera.Reset_T1();
1346 request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 1 / 1.26f ), 1.26f ) );
1347 return true;
1348
1350 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1351 m_camera.SetT0_and_T1_current_T();
1352
1353 if( m_camera.Zoom_T1( 1.26f ) ) // 3 steps per doubling
1355
1356 return true;
1357
1359 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1360 m_camera.SetT0_and_T1_current_T();
1361
1362 if( m_camera.Zoom_T1( 1/1.26f ) ) // 3 steps per halving
1364
1365 return true;
1366
1372 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1373 m_camera.SetT0_and_T1_current_T();
1374 m_camera.ViewCommand_T1( aRequestedView );
1376 return true;
1377
1380 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1381 m_camera.SetT0_and_T1_current_T();
1382 m_camera.ViewCommand_T1( aRequestedView );
1383 request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 0.5f ), 1.125f ) );
1384 return true;
1385
1386 default:
1387 return false;
1388 }
1389}
1390
1391
1393{
1395 {
1396 switch( cfg->m_Render.engine )
1397 {
1400 default: m_3d_render = nullptr; break;
1401 }
1402 }
1403
1404 if( m_3d_render )
1405 m_3d_render->ReloadRequest();
1406
1407 m_mouse_was_moved = false;
1408
1410}
1411
1412
1414{
1415 SFVEC3F rayOrigin;
1416 SFVEC3F rayDir;
1417
1418 // Generate a ray origin and direction based on current mouser position and camera
1419 m_camera.MakeRayAtCurrentMousePosition( rayOrigin, rayDir );
1420
1421 RAY mouseRay;
1422 mouseRay.Init( rayOrigin, rayDir );
1423
1424 return mouseRay;
1425}
VIEW3D_TYPE
Definition 3d_enums.h:78
@ VIEW3D_ZOOM_OUT
Definition 3d_enums.h:94
@ VIEW3D_PAN_LEFT
Definition 3d_enums.h:91
@ VIEW3D_FIT_SCREEN
Definition 3d_enums.h:98
@ VIEW3D_ZOOM_IN
Definition 3d_enums.h:93
@ VIEW3D_PIVOT_CENTER
Definition 3d_enums.h:95
@ VIEW3D_BOTTOM
Definition 3d_enums.h:81
@ VIEW3D_PAN_UP
Definition 3d_enums.h:89
@ VIEW3D_PAN_DOWN
Definition 3d_enums.h:90
@ VIEW3D_PAN_RIGHT
Definition 3d_enums.h:92
@ ID_CUSTOM_EVENT_1
@ ID_DISABLE_RAY_TRACING
void SetOpenGLInfo(const char *aVendor, const char *aRenderer, const char *aVersion)
A setter for OpenGL info when it's initialized.
Helper class to handle information needed to display 3D board.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:317
A class used to derive camera objects from.
Definition camera.h:103
Implement a canvas based on a wxGLCanvas.
RENDER_3D_OPENGL * m_3d_render_opengl
TOOL_DISPATCHER * m_eventDispatcher
void OnEvent(wxEvent &aEvent)
Used to forward events to the canvas from popups, etc.
void OnMagnify(wxMouseEvent &event)
void restart_editingTimeOut_Timer()
Reset the editing timer.
void RenderToFrameBuffer(unsigned char *aBuffer, int aWidth, int aHeight)
BOARD_ITEM * m_currentRollOverItem
RENDER_3D_BASE * m_3d_render
bool m_is_opengl_initialized
void OnResize(wxSizeEvent &event)
bool m_render3dmousePivot
void OnMouseWheel(wxMouseEvent &event)
WX_INFOBAR * m_parentInfoBar
wxTimer m_editing_timeout_timer
int64_t m_strtime_camera_movement
void OnLeftDown(wxMouseEvent &event)
void OnPanGesture(wxPanGestureEvent &event)
void OnRightUp(wxMouseEvent &event)
wxGLContext * m_glRC
ACCELERATOR_3D * m_accelerator3DShapes
void OnTimerTimeout_Redraw(wxTimerEvent &event)
wxStatusBar * m_parentStatusBar
void DoRePaint()
The actual function to repaint the canvas.
void OnRightDown(wxMouseEvent &event)
int m_moving_speed_multiplier
bool m_is_opengl_version_supported
wxTimer m_redraw_trigger_timer
BOARD_ADAPTER & m_boardAdapter
void DisplayStatus()
Update the status bar with the position information.
void render3dmousePivot(float aScale)
Render the 3dmouse pivot cursor.
void OnPaint(wxPaintEvent &aEvent)
void RenderRaytracingRequest()
Request to render the current view in Raytracing mode.
void SetEventDispatcher(TOOL_DISPATCHER *aEventDispatcher)
Set a dispatcher that processes events and forwards them to tools.
bool m_render_raytracing_was_requested
float m_camera_moving_speed
void OnLeftUp(wxMouseEvent &event)
void ReloadRequest(BOARD *aBoard=nullptr, S3D_CACHE *aCachePointer=nullptr)
RAY getRayAtCurrentMousePosition()
double m_gestureLastZoomFactor
Used to track gesture events.
void OnCloseWindow(wxCloseEvent &event)
bool SetView3D(VIEW3D_TYPE aRequestedView)
Select a specific 3D view or operation.
void OnMiddleDown(wxMouseEvent &event)
void GetScreenshot(wxImage &aDstImage)
Request a screenshot and output it to the aDstImage.
RENDER_3D_RAYTRACE_GL * m_3d_render_raytracing
void OnZoomGesture(wxZoomGestureEvent &event)
void OnMiddleUp(wxMouseEvent &event)
void render_pivot(float t, float aScale)
Render the pivot cursor.
void request_start_moving_camera(float aMovingSpeed=2.0f, bool aRenderPivot=true)
Start a camera movement.
void RenderEngineChanged()
Notify that the render engine was changed.
std::atomic_flag m_is_currently_painting
void OnRefreshRequest(wxEvent &aEvent)
void OnEraseBackground(wxEraseEvent &event)
void releaseOpenGL()
Free created targets and openGL context.
void Request_refresh(bool aRedrawImmediately=true)
Schedule a refresh update of the canvas.
bool m_opengl_supports_raytracing
~EDA_3D_CANVAS() override
void OnMouseMove(wxMouseEvent &event)
void OnRotateGesture(wxRotateGestureEvent &event)
EDA_3D_CANVAS(wxWindow *aParent, const wxGLAttributes &aGLAttribs, BOARD_ADAPTER &aSettings, CAMERA &aCamera, S3D_CACHE *a3DCachePointer)
Create a new 3D Canvas with an attribute list.
void move_pivot_based_on_cur_mouse_position()
This function hits a ray to the board and start a movement.
double m_gestureLastAngle
void OnTimerTimeout_Editing(wxTimerEvent &event)
void stop_editingTimeOut_Timer()
Stop the editing time so it will not timeout.
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard.
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
const wxString & GetReference() const
Definition footprint.h:661
void UnlockCtx(wxGLContext *aContext)
Allow other canvases to bind an OpenGL context.
void DestroyCtx(wxGLContext *aContext)
Destroy a managed OpenGL context.
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Set a context as current and prevents other canvases from switching it.
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=nullptr)
Create a managed OpenGL context.
static int SetSwapInterval(int aVal)
Attempt to set the OpenGL swap interval.
Definition gl_utils.h:49
Provides basic 3D controls ( zoom, rotate, translate, ... )
static const float m_delta_move_step_factor
HIDPI_GL_3D_CANVAS(const KIGFX::VC_SETTINGS &aVcSettings, CAMERA &aCamera, wxWindow *parent, const wxGLAttributes &aGLAttribs, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0, const wxString &name=wxGLCanvasName, const wxPalette &palette=wxNullPalette)
void OnMouseWheelCamera(wxMouseEvent &event, bool aPan)
void OnMouseMoveCamera(wxMouseEvent &event)
virtual wxSize GetNativePixelSize() const
A wrapper for reporting to a WX_INFOBAR UI element.
Definition wx_infobar.h:327
void Finalize()
Update the infobar with the reported text.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:499
Definition pad.h:54
GL_CONTEXT_MANAGER * GetGLContextManager()
Definition pgm_base.h:115
Object to render the board using openGL.
Cache for storing the 3D shapes.
Definition 3d_cache.h:55
GizmoSphereSelection
Enum to indicate which sphere (direction) is selected.
@ Count
Number of selectable spheres.
A wrapper for reporting to a specific text location in a statusbar.
Definition reporter.h:297
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition reporter.cpp:213
Handle a list of polygons defining a copper zone.
Definition zone.h:74
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:704
const wxString & GetZoneName() const
Definition zone.h:163
bool IsOnCopperLayer() const override
Definition zone.cpp:499
#define _(s)
wxDEFINE_EVENT(wxEVT_REFRESH_CUSTOM_COMMAND, wxEvent)
#define EDA_3D_CANVAS_ID
Declaration of the eda_3d_viewer class.
@ ZOOM_LEVEL
@ HOVERED_ITEM
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_SCH
Definition frame_type.h:34
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
This file contains miscellaneous commonly used macros and functions.
@ MAIL_SELECTION
Definition mail_type.h:40
void OglGetScreenshot(wxImage &aDstImage)
Get the pixel data of current OpenGL image.
Definition ogl_utils.cpp:37
Define generic OpenGL functions that are common to any OpenGL target.
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:913
see class PGM_BASE
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
@ RPT_SEVERITY_ERROR
T * GetAppSettings(const char *aFilename)
const int scale
wxString From_UTF8(const char *cstring)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_IPC
Definition ray.h:63
void Init(const SFVEC3F &o, const SFVEC3F &d)
Definition ray.cpp:35
SFVEC3F at(float t) const
Definition ray.h:84
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:107
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:90
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
glm::vec3 SFVEC3F
Definition xv3d_types.h:44