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
29#include "../common_ogl/ogl_utils.h"
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 <reporter.h>
40#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
41#include <bitmaps.h>
42#include <macros.h>
43#include <pgm_base.h>
46
48
49
57const wxChar* EDA_3D_CANVAS::m_logTrace = wxT( "KI_TRACE_EDA_3D_CANVAS" );
58
59
60// A custom event, used to call DoRePaint during an idle time
61wxDEFINE_EVENT( wxEVT_REFRESH_CUSTOM_COMMAND, wxEvent );
62
63
64BEGIN_EVENT_TABLE( EDA_3D_CANVAS, HIDPI_GL_3D_CANVAS )
65 EVT_PAINT( EDA_3D_CANVAS::OnPaint )
66
67 // mouse events
68 EVT_LEFT_DOWN( EDA_3D_CANVAS::OnLeftDown )
69 EVT_LEFT_UP( EDA_3D_CANVAS::OnLeftUp )
70 EVT_MIDDLE_UP( EDA_3D_CANVAS::OnMiddleUp )
71 EVT_MIDDLE_DOWN( EDA_3D_CANVAS::OnMiddleDown)
72 EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightDown )
73 EVT_RIGHT_UP( EDA_3D_CANVAS::OnRightUp )
74 EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
75 EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
76 EVT_MAGNIFY( EDA_3D_CANVAS::OnMagnify )
77
78 // touch gesture events
79 EVT_GESTURE_ZOOM( wxID_ANY, EDA_3D_CANVAS::OnZoomGesture )
80 EVT_GESTURE_PAN( wxID_ANY, EDA_3D_CANVAS::OnPanGesture )
81 EVT_GESTURE_ROTATE( wxID_ANY, EDA_3D_CANVAS::OnRotateGesture )
82
83 // other events
84 EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
85 EVT_CUSTOM(wxEVT_REFRESH_CUSTOM_COMMAND, ID_CUSTOM_EVENT_1, EDA_3D_CANVAS::OnRefreshRequest )
86
88 EVT_SIZE( EDA_3D_CANVAS::OnResize )
89END_EVENT_TABLE()
90
91
92EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
93 BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera,
94 S3D_CACHE* a3DCachePointer ) :
95 HIDPI_GL_3D_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aCamera, aParent, aGLAttribs,
96 EDA_3D_CANVAS_ID, wxDefaultPosition,
97 wxDefaultSize, wxFULL_REPAINT_ON_RESIZE ),
98 m_eventDispatcher( nullptr ),
99 m_parentStatusBar( nullptr ),
100 m_parentInfoBar( nullptr ),
101 m_glRC( nullptr ),
102 m_is_opengl_initialized( false ),
103 m_is_opengl_version_supported( true ),
104 m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
105 m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
106 m_render_pivot( false ),
107 m_camera_moving_speed( 1.0f ),
108 m_strtime_camera_movement( 0 ),
109 m_animation_enabled( true ),
110 m_moving_speed_multiplier( 3 ),
111 m_boardAdapter( aBoardAdapter ),
112 m_3d_render( nullptr ),
113 m_opengl_supports_raytracing( true ),
114 m_render_raytracing_was_requested( false ),
115 m_accelerator3DShapes( nullptr ),
116 m_currentRollOverItem( nullptr )
117{
118 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::EDA_3D_CANVAS" ) );
119
120 m_editing_timeout_timer.SetOwner( this );
121 Connect( m_editing_timeout_timer.GetId(), wxEVT_TIMER,
122 wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Editing ), nullptr, this );
123
124 m_redraw_trigger_timer.SetOwner( this );
125 Connect( m_redraw_trigger_timer.GetId(), wxEVT_TIMER,
126 wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Redraw ), nullptr, this );
127
128 m_is_currently_painting.clear();
129
130 m_3d_render_raytracing = new RENDER_3D_RAYTRACE_GL( this, m_boardAdapter, m_camera );
131 m_3d_render_opengl = new RENDER_3D_OPENGL( this, m_boardAdapter, m_camera );
132
133 wxASSERT( m_3d_render_raytracing != nullptr );
134 wxASSERT( m_3d_render_opengl != nullptr );
135
136 auto busy_indicator_factory =
137 []()
138 {
139 return std::make_unique<WX_BUSY_INDICATOR>();
140 };
141
142 m_3d_render_raytracing->SetBusyIndicatorFactory( busy_indicator_factory );
143 m_3d_render_opengl->SetBusyIndicatorFactory( busy_indicator_factory );
144
145 // We always start with the opengl engine (raytracing is avoided due to very
146 // long calculation time)
147 m_3d_render = m_3d_render_opengl;
148
149 m_boardAdapter.ReloadColorSettings();
150
151 wxASSERT( a3DCachePointer != nullptr );
152 m_boardAdapter.Set3dCacheManager( a3DCachePointer );
153
154#if defined( __WXMSW__ )
155 EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_ROTATE_GESTURE | wxTOUCH_PAN_GESTURES );
156#elif defined( __WXGTK__ )
157 EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_ROTATE_GESTURE );
158#endif
159
160 const wxEventType events[] =
161 {
162 // Binding both EVT_CHAR and EVT_CHAR_HOOK ensures that all key events,
163 // especially special key like arrow keys, are handled by the GAL event dispatcher,
164 // and not sent to GUI without filtering, because they have a default action (scroll)
165 // that must not be called.
166 wxEVT_LEFT_UP, wxEVT_LEFT_DOWN, wxEVT_LEFT_DCLICK,
167 wxEVT_RIGHT_UP, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_DCLICK,
168 wxEVT_MIDDLE_UP, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_DCLICK,
169 wxEVT_MOTION, wxEVT_MOUSEWHEEL, wxEVT_CHAR, wxEVT_CHAR_HOOK,
170 wxEVT_MAGNIFY,
171 wxEVT_MENU_OPEN, wxEVT_MENU_CLOSE, wxEVT_MENU_HIGHLIGHT
172 };
173
174 for( wxEventType eventType : events )
175 Connect( eventType, wxEventHandler( EDA_3D_CANVAS::OnEvent ), nullptr, m_eventDispatcher );
176}
177
178
180{
181 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::~EDA_3D_CANVAS" ) );
182
184 m_accelerator3DShapes = nullptr;
185
187}
188
189
191{
192 if( m_glRC )
193 {
195 gl_mgr->LockCtx( m_glRC, this );
196
198 m_3d_render_raytracing = nullptr;
199
200 delete m_3d_render_opengl;
201 m_3d_render_opengl = nullptr;
202
203 // This is just a copy of a pointer, can safely be set to NULL.
204 m_3d_render = nullptr;
205
206 gl_mgr->UnlockCtx( m_glRC );
207 gl_mgr->DestroyCtx( m_glRC );
208 m_glRC = nullptr;
209 }
210}
211
212
213void EDA_3D_CANVAS::OnCloseWindow( wxCloseEvent& event )
214{
216
217 event.Skip();
218}
219
220
221void EDA_3D_CANVAS::OnResize( wxSizeEvent& event )
222{
224}
225
226
228{
229 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::initializeOpenGL" ) );
230
231 const GLenum err = glewInit();
232
233 if( GLEW_OK != err )
234 {
235 const wxString msgError = (const char*) glewGetErrorString( err );
236
237 wxLogMessage( msgError );
238
239 return false;
240 }
241 else
242 {
243 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::initializeOpenGL Using GLEW version %s" ),
244 From_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
245 }
246
247 SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
248 (const char*) glGetString( GL_VERSION ) );
249
250 wxString version = From_UTF8( (char *) glGetString( GL_VERSION ) );
251
252 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::%s OpenGL version string %s." ),
253 __WXFUNCTION__, version );
254
255 // Extract OpenGL version from string. This method is used because prior to OpenGL 2,
256 // getting the OpenGL major and minor version as integers didn't exist.
257 wxString tmp;
258
259 wxStringTokenizer tokenizer( version );
260
261 if( tokenizer.HasMoreTokens() )
262 {
263 long major = 0;
264 long minor = 0;
265
266 tmp = tokenizer.GetNextToken();
267
268 tokenizer.SetString( tmp, wxString( wxT( "." ) ) );
269
270 if( tokenizer.HasMoreTokens() )
271 tokenizer.GetNextToken().ToLong( &major );
272
273 if( tokenizer.HasMoreTokens() )
274 tokenizer.GetNextToken().ToLong( &minor );
275
276 if( major < 2 || ( ( major == 2 ) && ( minor < 1 ) ) )
277 {
278 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::%s OpenGL ray tracing not supported." ),
279 __WXFUNCTION__ );
280
281 if( GetParent() )
282 {
283 wxCommandEvent evt( wxEVT_MENU, ID_DISABLE_RAY_TRACING );
284 GetParent()->ProcessWindowEvent( evt );
285 }
286
288 }
289
290 if( ( major == 1 ) && ( minor < 5 ) )
291 {
292 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::%s OpenGL not supported." ),
293 __WXFUNCTION__ );
294
296 }
297 }
298
301
302 return true;
303}
304
305
306void EDA_3D_CANVAS::GetScreenshot( wxImage& aDstImage )
307{
308 OglGetScreenshot( aDstImage );
309}
310
311
312void EDA_3D_CANVAS::ReloadRequest( BOARD* aBoard , S3D_CACHE* aCachePointer )
313{
314 if( aCachePointer != nullptr )
315 m_boardAdapter.Set3dCacheManager( aCachePointer );
316
317 if( aBoard != nullptr )
318 m_boardAdapter.SetBoard( aBoard );
319
321
322 if( m_3d_render )
324}
325
326
328{
330
331 if( m_3d_render )
333
335
337}
338
339
341{
343 {
344 wxString msg;
345
346 msg.Printf( wxT( "dx %3.2f" ), m_camera.GetCameraPos().x );
347 m_parentStatusBar->SetStatusText( msg, static_cast<int>( EDA_3D_VIEWER_STATUSBAR::X_POS ) );
348
349 msg.Printf( wxT( "dy %3.2f" ), m_camera.GetCameraPos().y );
350 m_parentStatusBar->SetStatusText( msg, static_cast<int>( EDA_3D_VIEWER_STATUSBAR::Y_POS ) );
351
352 msg.Printf( wxT( "zoom %3.2f" ), 1 / m_camera.GetZoom() );
353 m_parentStatusBar->SetStatusText( msg,
354 static_cast<int>( EDA_3D_VIEWER_STATUSBAR::ZOOM_LEVEL ) );
355 }
356}
357
358
359void EDA_3D_CANVAS::OnPaint( wxPaintEvent& aEvent )
360{
361 // Please have a look at: https://lists.launchpad.net/kicad-developers/msg25149.html
362 DoRePaint();
363}
364
365
367{
368 if( m_is_currently_painting.test_and_set() )
369 return;
370
371 // SwapBuffer requires the window to be shown before calling
372 if( !IsShownOnScreen() )
373 {
374 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::DoRePaint !IsShown" ) );
376 return;
377 }
378
379 // Because the board to draw is handled by the parent viewer frame,
380 // ensure this parent is still alive. When it is closed before the viewer
381 // frame, a paint event can be generated after the parent is closed,
382 // therefore with invalid board.
383 // This is dependent of the platform.
384 // Especially on OSX, but also on Windows, it frequently happens
385 if( !GetParent()->GetParent()->IsShownOnScreen() )
386 return; // The parent board editor frame is no more alive
387
388 wxString err_messages;
389 INFOBAR_REPORTER warningReporter( m_parentInfoBar );
390 STATUSBAR_REPORTER activityReporter( m_parentStatusBar, EDA_3D_VIEWER_STATUSBAR::ACTIVITY );
391 int64_t start_time = GetRunningMicroSecs();
393
394 // "Makes the OpenGL state that is represented by the OpenGL rendering
395 // context context current, i.e. it will be used by all subsequent OpenGL calls.
396 // This function may only be called when the window is shown on screen"
397
398 // Explicitly create a new rendering context instance for this canvas.
399 if( m_glRC == nullptr )
400 m_glRC = gl_mgr->CreateCtx( this );
401
402 // CreateCtx could and does fail per sentry crash events, lets be graceful
403 if( m_glRC == nullptr )
404 {
405 warningReporter.Report( _( "OpenGL context creation error" ), RPT_SEVERITY_ERROR );
406 warningReporter.Finalize();
408 return;
409 }
410
411 gl_mgr->LockCtx( m_glRC, this );
412
413 // Set the OpenGL viewport according to the client size of this canvas.
414 // This is done here rather than in a wxSizeEvent handler because our
415 // OpenGL rendering context (and thus viewport setting) is used with
416 // multiple canvases: If we updated the viewport in the wxSizeEvent
417 // handler, changing the size of one canvas causes a viewport setting that
418 // is wrong when next another canvas is repainted.
419 wxSize clientSize = GetNativePixelSize();
420
421 const bool windows_size_changed = m_camera.SetCurWindowSize( clientSize );
422
423 // Initialize openGL if need
425 {
426 if( !initializeOpenGL() )
427 {
428 gl_mgr->UnlockCtx( m_glRC );
430
431 return;
432 }
433
435 {
436 warningReporter.Report( _( "Your OpenGL version is not supported. Minimum required "
437 "is 1.5." ), RPT_SEVERITY_ERROR );
438
439 warningReporter.Finalize();
440 }
441 }
442
444 {
445 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
446 glClear( GL_COLOR_BUFFER_BIT );
447
448 SwapBuffers();
449
450 gl_mgr->UnlockCtx( m_glRC );
452
453 return;
454 }
455
456 // Don't attempt to ray trace if OpenGL doesn't support it.
458 {
461 m_boardAdapter.m_Cfg->m_Render.engine = RENDER_ENGINE::OPENGL;
462 }
463
464 // Check if a raytracing was requested and need to switch to raytracing mode
465 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
466 {
467 const bool was_camera_changed = m_camera.ParametersChanged();
468
469 // It reverts back to OpenGL mode if it was requested a raytracing
470 // render of the current scene. AND the mouse / camera is moving
471 if( ( m_mouse_is_moving || m_camera_is_moving || was_camera_changed
472 || windows_size_changed )
474 {
477 }
478 }
479
480 float curtime_delta_s = 0.0f;
481
483 {
484 const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
485 curtime_delta_s = ( curtime_delta / 1e6 ) * m_camera_moving_speed;
486 m_camera.Interpolate( curtime_delta_s );
487
488 if( curtime_delta_s > 1.0f )
489 {
490 m_render_pivot = false;
491 m_camera_is_moving = false;
492 m_mouse_was_moved = true;
493
496 }
497 else
498 {
500 }
501 }
502
503 // It will return true if the render request a new redraw
504 bool requested_redraw = false;
505
506 if( m_3d_render )
507 {
508 try
509 {
510 m_3d_render->SetCurWindowSize( clientSize );
511
512 bool reloadRaytracingForCalculations = false;
513
514 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL
516 {
517 reloadRaytracingForCalculations = true;
518 }
519
521 &activityReporter, &warningReporter );
522
523 // Raytracer renderer is responsible for some features also used by the OpenGL
524 // renderer.
525 // FIXME: Presumably because raytracing renderer reload is called only after current
526 // renderer redraw, the old zoom value stays for a single frame. This is ugly, but only
527 // cosmetic, so I'm not fixing that for now: I don't know how to do this without
528 // reloading twice (maybe it's not too bad of an idea?) or doing a complicated
529 // refactor.
530 if( reloadRaytracingForCalculations )
531 m_3d_render_raytracing->Reload( nullptr, nullptr, true );
532 }
533 catch( std::runtime_error& )
534 {
538 gl_mgr->UnlockCtx( m_glRC );
540 return;
541 }
542 }
543
544 if( m_render_pivot )
545 {
546 const float scale = glm::min( m_camera.GetZoom(), 1.0f );
547 render_pivot( curtime_delta_s, scale );
548 }
549
550 // This will only be enabled by the 3d mouse plugin, so we can leave
551 // it as a simple if statement
553 {
554 const float scale = glm::min( m_camera.GetZoom(), 1.0f );
556 }
557
558 // "Swaps the double-buffer of this window, making the back-buffer the
559 // front-buffer and vice versa, so that the output of the previous OpenGL
560 // commands is displayed on the window."
561 SwapBuffers();
562
563 gl_mgr->UnlockCtx( m_glRC );
564
566 {
567 // Calculation time in milliseconds
568 const double calculation_time = (double)( GetRunningMicroSecs() - start_time ) / 1e3;
569
570 activityReporter.Report( wxString::Format( _( "Last render time %.0f ms" ),
571 calculation_time ) );
572 }
573
574 // This will reset the flag of camera parameters changed
576
577 warningReporter.Finalize();
578
579 if( !err_messages.IsEmpty() )
580 wxLogMessage( err_messages );
581
582 if( ( !m_camera_is_moving ) && requested_redraw )
583 {
584 m_mouse_was_moved = false;
585 Request_refresh( false );
586 }
587
588 static constexpr std::array<VIEW3D_TYPE, static_cast<int>( SPHERES_GIZMO::GizmoSphereSelection::Count )>
589 viewTable = { VIEW3D_TYPE::VIEW3D_RIGHT, VIEW3D_TYPE::VIEW3D_LEFT, VIEW3D_TYPE::VIEW3D_BACK,
590 VIEW3D_TYPE::VIEW3D_FRONT, VIEW3D_TYPE::VIEW3D_TOP, VIEW3D_TYPE::VIEW3D_BOTTOM };
591
593 int index = static_cast<int>( selectedGizmoSphere );
594 if( index >= 0 && index < static_cast<int>( viewTable.size() ) )
595 {
596 SetView3D( viewTable[index] );
597 }
598
600
602}
603
604
605void EDA_3D_CANVAS::RenderToFrameBuffer( unsigned char* buffer, int width, int height )
606{
607 if( m_is_currently_painting.test_and_set() )
608 return;
609
610 // Validate input parameters
611 if( !buffer || width <= 0 || height <= 0 )
612 {
614 return;
615 }
616
617 // Because the board to draw is handled by the parent viewer frame,
618 // ensure this parent is still alive
619 if( !GetParent() || !GetParent()->GetParent() || !GetParent()->GetParent()->IsShownOnScreen() )
620 {
622 return;
623 }
624
625 wxString err_messages;
626 int64_t start_time = GetRunningMicroSecs();
628
629 // Create OpenGL context if needed
630 if( m_glRC == nullptr )
631 m_glRC = gl_mgr->CreateCtx( this );
632
633 if( m_glRC == nullptr )
634 {
635 wxLogError( _( "OpenGL context creation error" ) );
637 return;
638 }
639
640 gl_mgr->LockCtx( m_glRC, this );
641
642 // Set up framebuffer objects for off-screen rendering
643 GLuint framebuffer = 0;
644 GLuint colorTexture = 0;
645 GLuint depthBuffer = 0;
646 GLint oldFramebuffer = 0;
647 GLint oldViewport[4];
648
649 // Save current state
650 glGetIntegerv( GL_FRAMEBUFFER_BINDING, &oldFramebuffer );
651 glGetIntegerv( GL_VIEWPORT, oldViewport );
652
653 // Create and bind framebuffer
654 glGenFramebuffers( 1, &framebuffer );
655 glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
656
657 // Create color texture attachment
658 glGenTextures( 1, &colorTexture );
659 glBindTexture( GL_TEXTURE_2D, colorTexture );
660 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
661 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
662 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
663 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
664 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
665 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0 );
666
667 // Create depth renderbuffer attachment
668 glGenRenderbuffers( 1, &depthBuffer );
669 glBindRenderbuffer( GL_RENDERBUFFER, depthBuffer );
670 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height );
671 glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer );
672
673 auto resetState = std::unique_ptr<void, std::function<void(void*)>>(
674 reinterpret_cast<void*>(1),
675 [&](void*) {
676 glBindFramebuffer( GL_FRAMEBUFFER, oldFramebuffer );
677 glViewport( oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3] );
678 glDeleteFramebuffers( 1, &framebuffer );
679 glDeleteTextures( 1, &colorTexture );
680 glDeleteRenderbuffers( 1, &depthBuffer );
681 gl_mgr->UnlockCtx( m_glRC );
683 }
684 );
685
686 // Check framebuffer completeness
687 GLenum framebufferStatus = glCheckFramebufferStatus( GL_FRAMEBUFFER );
688
689 if( framebufferStatus != GL_FRAMEBUFFER_COMPLETE )
690 {
691 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer Framebuffer incomplete: 0x%04X" ),
692 framebufferStatus );
693
694 return;
695 }
696
697 // Set viewport for off-screen rendering
698 glViewport( 0, 0, width, height );
699
700 // Set window size for camera and rendering
701 wxSize clientSize( width, height );
702 const bool windows_size_changed = m_camera.SetCurWindowSize( clientSize );
703
704 // Initialize OpenGL if needed
706 {
707 if( !initializeOpenGL() )
708 {
709 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer OpenGL initialization failed." ) );
710 return;
711 }
712
714 {
715 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer OpenGL version not supported." ) );
716 }
717 }
718
720 {
721 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
722 glClear( GL_COLOR_BUFFER_BIT );
723
724 // Read black screen to buffer
725 glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
726 return;
727 }
728
729 // Handle raytracing/OpenGL renderer selection
731 {
734 m_boardAdapter.m_Cfg->m_Render.engine = RENDER_ENGINE::OPENGL;
735 }
736
737 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
738 {
739 const bool was_camera_changed = m_camera.ParametersChanged();
740
741 if( ( m_mouse_is_moving || m_camera_is_moving || was_camera_changed || windows_size_changed )
743 {
746 }
747 }
748
749 // Handle camera animation (simplified for off-screen rendering)
750 float curtime_delta_s = 0.0f;
752 {
753 const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
754 curtime_delta_s = ( curtime_delta / 1e6 ) * m_camera_moving_speed;
755 m_camera.Interpolate( curtime_delta_s );
756
757 if( curtime_delta_s > 1.0f )
758 {
759 m_render_pivot = false;
760 m_camera_is_moving = false;
761 m_mouse_was_moved = true;
762 }
763 }
764
765 // Perform the actual rendering
766 bool requested_redraw = false;
767 if( m_3d_render )
768 {
769 try
770 {
771 m_3d_render->SetCurWindowSize( clientSize );
772
773 bool reloadRaytracingForCalculations = false;
774 if( m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL
776 {
777 reloadRaytracingForCalculations = true;
778 }
779
780 requested_redraw = m_3d_render->Redraw( false, nullptr, nullptr );
781
782 if( reloadRaytracingForCalculations )
783 m_3d_render_raytracing->Reload( nullptr, nullptr, true );
784 }
785 catch( std::runtime_error& )
786 {
790 return;
791 }
792 }
793
794 // Read pixels from framebuffer to the provided buffer
795 // Note: This reads RGB format. Adjust format as needed.
796 glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
797
798 // Check for OpenGL errors
799 GLenum error = glGetError();
800 if( error != GL_NO_ERROR )
801 {
802 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::RenderToFrameBuffer OpenGL error: 0x%04X" ), error );
803 err_messages += wxString::Format( _( "OpenGL error during off-screen rendering: 0x%04X\n" ), error );
804 }
805
806 // Reset camera parameters changed flag
808
809 if( !err_messages.IsEmpty() )
810 wxLogMessage( err_messages );
811}
812
813
815{
816 m_eventDispatcher = aEventDispatcher;
817}
818
819
820void EDA_3D_CANVAS::OnEvent( wxEvent& aEvent )
821{
822 if( !m_eventDispatcher )
823 aEvent.Skip();
824 else
826
827 Refresh();
828}
829
830
831void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent& event )
832{
833 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnEraseBackground" ) );
834 // Do nothing, to avoid flashing.
835}
836
837
838void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event )
839{
840 wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnMouseWheel" ) );
841
843
845 {
849 }
850}
851
852
853void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
854{
855 SetFocus();
856
858 return;
859
860 //m_is_moving_mouse = true;
862
863 float magnification = ( event.GetMagnification() + 1.0f );
864
865 m_camera.Zoom( magnification );
866
869}
870
871
872void EDA_3D_CANVAS::OnZoomGesture( wxZoomGestureEvent& aEvent )
873{
874 SetFocus();
875
876 if( aEvent.IsGestureStart() )
877 {
879 m_camera.SetCurMousePosition( aEvent.GetPosition() );
880 }
881
883 return;
884
886
887 m_camera.Pan( aEvent.GetPosition() );
888 m_camera.SetCurMousePosition( aEvent.GetPosition() );
889
890 m_camera.Zoom( aEvent.GetZoomFactor() / m_gestureLastZoomFactor );
891
892 m_gestureLastZoomFactor = aEvent.GetZoomFactor();
893
896}
897
898
899void EDA_3D_CANVAS::OnPanGesture( wxPanGestureEvent& aEvent )
900{
901 SetFocus();
902
903 if( aEvent.IsGestureStart() )
904 m_camera.SetCurMousePosition( aEvent.GetPosition() );
905
907 return;
908
909 m_camera.Pan( aEvent.GetPosition() );
910 m_camera.SetCurMousePosition( aEvent.GetPosition() );
911
914}
915
916
917void EDA_3D_CANVAS::OnRotateGesture( wxRotateGestureEvent& aEvent )
918{
919 SetFocus();
920
921 if( aEvent.IsGestureStart() )
922 {
924 m_camera.SetCurMousePosition( aEvent.GetPosition() );
925
926 // We don't want to process the first angle
927 return;
928 }
929
931 return;
932
933 m_camera.RotateScreen( m_gestureLastAngle - aEvent.GetRotationAngle() );
934 m_gestureLastAngle = aEvent.GetRotationAngle();
935
938}
939
940
941void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
942{
944 return; // Prevents using invalid m_3d_render_raytracing data
945
947 return;
948
949 OnMouseMoveCamera( event );
950
952 {
955 // *Do not* reactivate the timer here during the mouse move command:
956 // OnMiddleUp() will do it at the end of mouse drag/move command
957 }
958
959 if( !event.Dragging() && m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
960 {
961 STATUSBAR_REPORTER reporter( m_parentStatusBar, EDA_3D_VIEWER_STATUSBAR::HOVERED_ITEM );
963 BOARD_ITEM* rollOverItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
964
965 auto printNetInfo = []( BOARD_CONNECTED_ITEM* aItem )
966 {
967 return wxString::Format( _( "Net %s\tNet class %s" ), aItem->GetNet()->GetNetname(),
968 aItem->GetNet()->GetNetClass()->GetHumanReadableName() );
969 };
970
971 if( rollOverItem )
972 {
973 wxString msg;
974
975 if( rollOverItem != m_currentRollOverItem )
976 {
978 m_currentRollOverItem = rollOverItem;
979
981 }
982
983 switch( rollOverItem->Type() )
984 {
985 case PCB_PAD_T:
986 {
987 PAD* pad = static_cast<PAD*>( rollOverItem );
988
989 if( !pad->GetNumber().IsEmpty() )
990 msg += wxString::Format( _( "Pad %s\t" ), pad->GetNumber() );
991
992 if( pad->IsOnCopperLayer() )
993 msg += printNetInfo( pad );
994
995 break;
996 }
997
998 case PCB_FOOTPRINT_T:
999 {
1000 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( rollOverItem );
1001 msg += footprint->GetReference();
1002 break;
1003 }
1004
1005 case PCB_TRACE_T:
1006 case PCB_VIA_T:
1007 case PCB_ARC_T:
1008 {
1009 PCB_TRACK* track = static_cast<PCB_TRACK*>( rollOverItem );
1010 msg += printNetInfo( track );
1011 break;
1012 }
1013
1014 case PCB_ZONE_T:
1015 {
1016 ZONE* zone = static_cast<ZONE*>( rollOverItem );
1017
1018 if( !zone->GetZoneName().IsEmpty() )
1019 {
1020 if( zone->GetIsRuleArea() )
1021 msg += wxString::Format( _( "Rule area %s\t" ), zone->GetZoneName() );
1022 else
1023 msg += wxString::Format( _( "Zone %s\t" ), zone->GetZoneName() );
1024 }
1025
1026 if( zone->IsOnCopperLayer() )
1027 msg += printNetInfo( zone );
1028
1029 break;
1030 }
1031
1032 default:
1033 break;
1034 }
1035
1036 reporter.Report( msg );
1037 }
1038 else
1039 {
1041 && m_boardAdapter.m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
1042 {
1045
1046 reporter.Report( wxEmptyString );
1047 }
1048
1049 m_currentRollOverItem = nullptr;
1050 }
1051 }
1052}
1053
1054
1055void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent& event )
1056{
1057 SetFocus();
1059
1060 // Ensure m_camera.m_lastPosition (current mouse position) is up to date for
1061 // future drag events (can be not the case when left clicking after
1062 // opening a context menu)
1063 OnMouseMoveCamera( event );
1064
1065 if( !event.Dragging() && ( m_3d_render_raytracing != nullptr ) )
1066 {
1067 RAY mouseRay = getRayAtCurrentMousePosition();
1068
1069 BOARD_ITEM *intersectedBoardItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
1070
1071 // !TODO: send a selection item to pcbnew, eg: via kiway?
1072 }
1073}
1074
1075
1076void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent& event )
1077{
1078 if( m_camera_is_moving )
1079 return;
1080
1081 if( m_mouse_is_moving )
1082 {
1083 m_mouse_is_moving = false;
1085 }
1086
1087 wxSize logicalSize = GetClientSize();
1088 int logicalW = logicalSize.GetWidth();
1089 int logicalH = logicalSize.GetHeight();
1090
1091 int gizmo_x, gizmo_y, gizmo_width, gizmo_height;
1092 std::tie( gizmo_x, gizmo_y, gizmo_width, gizmo_height ) = m_3d_render_opengl->getGizmoViewport();
1093
1094 float scaleX = static_cast<float>( gizmo_width ) / logicalW;
1095 float scaleY = static_cast<float>( gizmo_height ) / logicalH;
1096
1097 int scaledMouseX = static_cast<int>( event.GetX() * scaleX );
1098 int scaledMouseY = static_cast<int>( ( logicalH - event.GetY() ) * scaleY );
1099
1100 m_3d_render_opengl->handleGizmoMouseInput( scaledMouseX, scaledMouseY );
1101 Refresh();
1102}
1103
1104
1105void EDA_3D_CANVAS::OnRightDown( wxMouseEvent& event )
1106{
1107 SetFocus();
1109
1110 // Ensure m_camera.m_lastPosition is up to date for future drag events.
1111 OnMouseMoveCamera( event );
1112}
1113
1114
1115void EDA_3D_CANVAS::OnRightUp( wxMouseEvent& event )
1116{
1117 if( m_camera_is_moving )
1118 return;
1119
1120 if( m_mouse_is_moving )
1121 {
1122 m_mouse_is_moving = false;
1124 }
1125}
1126
1127
1128void EDA_3D_CANVAS::OnMiddleDown( wxMouseEvent& event )
1129{
1130 SetFocus();
1132}
1133
1134
1135void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent& event )
1136{
1137 if( m_camera_is_moving )
1138 return;
1139
1140 if( m_mouse_is_moving )
1141 {
1142 m_mouse_is_moving = false;
1144 }
1145 else
1146 {
1148 }
1149}
1150
1151
1152void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent& aEvent )
1153{
1154 if( aEvent.GetId() != m_editing_timeout_timer.GetId() )
1155 {
1156 aEvent.Skip();
1157 return;
1158 }
1159
1160 m_mouse_is_moving = false;
1161 m_mouse_was_moved = false;
1162
1164}
1165
1166
1168{
1170}
1171
1172
1174{
1175 if( m_3d_render )
1176 m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut(), wxTIMER_ONE_SHOT );
1177}
1178
1179
1180void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent& aEvent )
1181{
1182 if( aEvent.GetId() != m_redraw_trigger_timer.GetId() )
1183 {
1184 aEvent.Skip();
1185 return;
1186 }
1187
1188 Request_refresh( true );
1189}
1190
1191
1192void EDA_3D_CANVAS::OnRefreshRequest( wxEvent& aEvent )
1193{
1194 Refresh();
1195}
1196
1197
1198void EDA_3D_CANVAS::Request_refresh( bool aRedrawImmediately )
1199{
1200 if( aRedrawImmediately )
1201 {
1202 // Just calling Refresh() does not work always
1203 // Using an event to call DoRepaint ensure the repaint code will be executed,
1204 // and PostEvent will take priority to other events like mouse movements, keys, etc.
1205 // and is executed during the next idle time
1206 wxCommandEvent redrawEvent( wxEVT_REFRESH_CUSTOM_COMMAND, ID_CUSTOM_EVENT_1 );
1207 wxPostEvent( this, redrawEvent );
1208 }
1209 else
1210 {
1211 // Schedule a timed redraw
1212 m_redraw_trigger_timer.Start( 10 , wxTIMER_ONE_SHOT );
1213 }
1214}
1215
1216
1217void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRenderPivot )
1218{
1219 wxASSERT( aMovingSpeed > FLT_EPSILON );
1220
1221 // Fast forward the animation if the animation is disabled
1222 if( !m_animation_enabled )
1223 {
1224 m_camera.Interpolate( 1.0f );
1225 DisplayStatus();
1227 return;
1228 }
1229
1230 // Map speed multiplier option to actual multiplier value
1231 // [1,2,3,4,5] -> [0.25, 0.5, 1, 2, 4]
1232 aMovingSpeed *= ( 1 << m_moving_speed_multiplier ) / 8.0f;
1233
1234 m_render_pivot = aRenderPivot;
1235 m_camera_moving_speed = aMovingSpeed;
1236
1238
1239 DisplayStatus();
1241
1242 m_camera_is_moving = true;
1243
1245}
1246
1247
1249{
1250 RAY mouseRay = getRayAtCurrentMousePosition();
1251
1252 float hit_t;
1253
1254 // Test it with the board bounding box
1255 if( m_boardAdapter.GetBBox().Intersect( mouseRay, &hit_t ) )
1256 {
1257 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1259 m_camera.SetLookAtPos_T1( mouseRay.at( hit_t ) );
1261
1263 }
1264}
1265
1266
1268{
1269 if( m_camera_is_moving )
1270 return false;
1271
1272 const float delta_move = m_delta_move_step_factor * m_camera.GetZoom();
1273 const float arrow_moving_time_speed = 8.0f;
1274
1275 switch( aRequestedView )
1276 {
1277 case VIEW3D_TYPE::VIEW3D_PIVOT_CENTER:
1279 return true;
1280
1281 case VIEW3D_TYPE::VIEW3D_PAN_LEFT:
1282 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1284 m_camera.Pan_T1( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
1285 request_start_moving_camera( arrow_moving_time_speed, false );
1286 return true;
1287
1288 case VIEW3D_TYPE::VIEW3D_PAN_RIGHT:
1289 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1291 m_camera.Pan_T1( SFVEC3F( +delta_move, 0.0f, 0.0f ) );
1292 request_start_moving_camera( arrow_moving_time_speed, false );
1293 return true;
1294
1295 case VIEW3D_TYPE::VIEW3D_PAN_UP:
1296 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1298 m_camera.Pan_T1( SFVEC3F( 0.0f, +delta_move, 0.0f ) );
1299 request_start_moving_camera( arrow_moving_time_speed, false );
1300 return true;
1301
1302 case VIEW3D_TYPE::VIEW3D_PAN_DOWN:
1303 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::LINEAR );
1305 m_camera.Pan_T1( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
1306 request_start_moving_camera( arrow_moving_time_speed, false );
1307 return true;
1308
1309 case VIEW3D_TYPE::VIEW3D_FIT_SCREEN:
1310 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1313 request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 1 / 1.26f ), 1.26f ) );
1314 return true;
1315
1316 case VIEW3D_TYPE::VIEW3D_ZOOM_IN:
1317 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1319
1320 if( m_camera.Zoom_T1( 1.26f ) ) // 3 steps per doubling
1322
1323 return true;
1324
1325 case VIEW3D_TYPE::VIEW3D_ZOOM_OUT:
1326 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1328
1329 if( m_camera.Zoom_T1( 1/1.26f ) ) // 3 steps per halving
1331
1332 return true;
1333
1334 case VIEW3D_TYPE::VIEW3D_RIGHT:
1335 case VIEW3D_TYPE::VIEW3D_LEFT:
1336 case VIEW3D_TYPE::VIEW3D_FRONT:
1337 case VIEW3D_TYPE::VIEW3D_BACK:
1338 case VIEW3D_TYPE::VIEW3D_FLIP:
1339 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1341 m_camera.ViewCommand_T1( aRequestedView );
1343 return true;
1344
1345 case VIEW3D_TYPE::VIEW3D_TOP:
1346 case VIEW3D_TYPE::VIEW3D_BOTTOM:
1347 m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
1349 m_camera.ViewCommand_T1( aRequestedView );
1350 request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 0.5f ), 1.125f ) );
1351 return true;
1352
1353 default:
1354 return false;
1355 }
1356}
1357
1358
1360{
1361 if( EDA_3D_VIEWER_SETTINGS* cfg = GetAppSettings<EDA_3D_VIEWER_SETTINGS>( "3d_viewer" ) )
1362 {
1363 switch( cfg->m_Render.engine )
1364 {
1365 case RENDER_ENGINE::OPENGL: m_3d_render = m_3d_render_opengl; break;
1366 case RENDER_ENGINE::RAYTRACING: m_3d_render = m_3d_render_raytracing; break;
1367 default: m_3d_render = nullptr; break;
1368 }
1369 }
1370
1371 if( m_3d_render )
1373
1374 m_mouse_was_moved = false;
1375
1377}
1378
1379
1381{
1382 SFVEC3F rayOrigin;
1383 SFVEC3F rayDir;
1384
1385 // Generate a ray origin and direction based on current mouser position and camera
1386 m_camera.MakeRayAtCurrentMousePosition( rayOrigin, rayDir );
1387
1388 RAY mouseRay;
1389 mouseRay.Init( rayOrigin, rayDir );
1390
1391 return mouseRay;
1392}
VIEW3D_TYPE
Definition: 3d_enums.h:78
@ ID_CUSTOM_EVENT_1
Definition: 3d_viewer_id.h:45
@ ID_DISABLE_RAY_TRACING
Definition: 3d_viewer_id.h:43
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.
Definition: board_adapter.h:73
const BBOX_3D & GetBBox() const noexcept
Get the board outline bounding box.
void ReloadColorSettings() noexcept
void SetBoard(BOARD *aBoard) noexcept
Set current board to be rendered.
EDA_3D_VIEWER_SETTINGS * m_Cfg
bool m_MousewheelPanning
void Set3dCacheManager(S3D_CACHE *aCacheMgr) noexcept
Update the cache manager pointer.
Definition: board_adapter.h:84
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
bool Zoom(float aFactor)
Definition: camera.cpp:598
virtual void Pan(const wxPoint &aNewMousePosition)=0
void RotateScreen(float aAngleInRadians)
Rotates the camera in screen plane.
Definition: camera.cpp:651
bool Zoom_T1(float aFactor)
Definition: camera.cpp:629
virtual void Reset_T1()
Definition: camera.cpp:161
virtual void Pan_T1(const SFVEC3F &aDeltaOffsetInc)=0
virtual void Interpolate(float t)
It will update the matrix to interpolate between T0 and T1 values.
Definition: camera.cpp:712
bool SetCurWindowSize(const wxSize &aSize)
Update the windows size of the camera.
Definition: camera.cpp:571
void SetInterpolateMode(CAMERA_INTERPOLATION aInterpolateMode)
Definition: camera.h:264
float GetZoom() const
Definition: camera.h:221
void ResetXYpos_T1()
Definition: camera.cpp:503
bool ViewCommand_T1(VIEW3D_TYPE aRequestedView)
Definition: camera.cpp:110
virtual void SetT0_and_T1_current_T()
This will set T0 and T1 with the current values.
Definition: camera.cpp:698
void MakeRayAtCurrentMousePosition(SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
Make a ray based on the latest mouse position.
Definition: camera.cpp:462
void SetLookAtPos_T1(const SFVEC3F &aLookAtPos)
Definition: camera.h:162
const SFVEC3F & GetCameraPos() const
Definition: camera.h:169
bool ParametersChanged()
Definition: camera.cpp:730
void SetCurMousePosition(const wxPoint &aPosition)
Update the current mouse position without make any new calculations on camera.
Definition: camera.cpp:554
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:51
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
bool initializeOpenGL()
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
bool m_animation_enabled
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
void OnMouseMove(wxMouseEvent &event)
void OnRotateGesture(wxRotateGestureEvent &event)
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.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
const wxString & GetReference() const
Definition: footprint.h:627
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
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.
Definition: wx_infobar.cpp:504
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition: wx_infobar.cpp:488
Definition: pad.h:54
GL_CONTEXT_MANAGER * GetGLContextManager()
Definition: pgm_base.h:115
virtual bool Redraw(bool aIsMoving, REPORTER *aStatusReporter=nullptr, REPORTER *aWarningReporter=nullptr)=0
Redraw the view.
virtual int GetWaitForEditingTimeOut()=0
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
void ReloadRequest()
virtual void SetCurWindowSize(const wxSize &aSize)=0
Before each render, the canvas will tell the render what is the size of its windows,...
bool IsReloadRequestPending() const
Query if there is a pending reload request.
Object to render the board using openGL.
SPHERES_GIZMO::GizmoSphereSelection getSelectedGizmoSphere() const
std::tuple< int, int, int, int > getGizmoViewport() const
void SetCurrentRollOverItem(BOARD_ITEM *aRollOverItem)
void handleGizmoMouseInput(int mouseX, int mouseY)
void Reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter, bool aOnlyLoadCopperAndShapes)
BOARD_ITEM * IntersectBoardItem(const RAY &aRay)
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:295
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition: reporter.cpp:214
virtual void DispatchWxEvent(wxEvent &aEvent)
Process wxEvents (mostly UI events), translate them to TOOL_EVENTs, and make tools handle those.
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
Definition: eda_3d_canvas.h:45
Declaration of the eda_3d_viewer class.
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.
void OglGetScreenshot(wxImage &aDstImage)
Get the pixel data of current OpenGL image.
Definition: ogl_utils.cpp:37
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:902
see class PGM_BASE
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
@ RPT_SEVERITY_ERROR
const int scale
wxString From_UTF8(const char *cstring)
bool Intersect(const RAY &aRay, float *t) const
Definition: bbox_3d_ray.cpp:46
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_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