KiCad PCB EDA Suite
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 <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2019 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 
30 #include <GL/glew.h> // Must be included first
31 #include <wx/tokenzr.h>
32 
33 #include "../common_ogl/ogl_utils.h"
34 #include "eda_3d_canvas.h"
35 #include <eda_3d_viewer.h>
38 #include <3d_viewer_id.h>
39 #include <class_board.h>
40 #include <status_text_reporter.h>
41 #include <gl_context_mgr.h>
42 #include <profile.h> // To use GetRunningMicroSecs or another profiling utility
43 #include <bitmaps.h>
44 #include <menus_helpers.h>
45 #include <pgm_base.h>
47 #include <tool/tool_dispatcher.h>
48 
50 
51 
59 const wxChar * EDA_3D_CANVAS::m_logTrace = wxT( "KI_TRACE_EDA_3D_CANVAS" );
60 
62 
63 
64 BEGIN_EVENT_TABLE( EDA_3D_CANVAS, wxGLCanvas )
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 )
72  EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
73  EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
74 
75 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
76  EVT_MAGNIFY( EDA_3D_CANVAS::OnMagnify )
77 #endif
78 
79  // other events
80  EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
81 
82  EVT_CLOSE( EDA_3D_CANVAS::OnCloseWindow )
83  EVT_SIZE( EDA_3D_CANVAS::OnResize )
84 END_EVENT_TABLE()
85 
86 
87 EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow *aParent, const int *aAttribList, BOARD *aBoard,
88  CINFO3D_VISU &aSettings , S3D_CACHE *a3DCachePointer ) :
89  HIDPI_GL_CANVAS( aParent, wxID_ANY, aAttribList, wxDefaultPosition, wxDefaultSize,
90  wxFULL_REPAINT_ON_RESIZE ),
91  m_eventDispatcher( nullptr ),
92  m_parentStatusBar( nullptr ),
93  m_glRC( nullptr ),
94  m_settings( aSettings ),
95  m_3d_render( nullptr )
96 {
97  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::EDA_3D_CANVAS" );
98 
99  m_editing_timeout_timer.SetOwner( this );
100  Connect( m_editing_timeout_timer.GetId(),
101  wxEVT_TIMER,
102  wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Editing ),
103  NULL,
104  this );
105 
106  m_redraw_trigger_timer.SetOwner( this );
107  Connect( m_redraw_trigger_timer.GetId(),
108  wxEVT_TIMER,
109  wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Redraw ),
110  NULL,
111  this );
112 
113  m_mouse_was_moved = false;
114  m_mouse_is_moving = false;
115  m_camera_is_moving = false;
116  m_render_pivot = false;
117  m_camera_moving_speed = 1.0f;
118 
119  m_strtime_camera_movement = 0;
120 
121  m_is_opengl_initialized = false;
122 
123  m_render_raytracing_was_requested = false;
124  m_opengl_supports_raytracing = false;
125 
126  m_3d_render_raytracing = new C3D_RENDER_RAYTRACING( aSettings );
127  m_3d_render_ogl_legacy = new C3D_RENDER_OGL_LEGACY( aSettings );
128 
129  wxASSERT( m_3d_render_raytracing != NULL );
130  wxASSERT( m_3d_render_ogl_legacy != NULL );
131 
132  auto busy_indicator_factory = []() { return std::make_unique<WX_BUSY_INDICATOR>(); };
133 
134  m_3d_render_raytracing->SetBusyIndicatorFactory( busy_indicator_factory );
135  m_3d_render_ogl_legacy->SetBusyIndicatorFactory( busy_indicator_factory );
136 
137  RenderEngineChanged();
138 
139  wxASSERT( aBoard != NULL );
140  m_settings.SetBoard( aBoard );
141 
142  m_settings.SetColorSettings( Pgm().GetSettingsManager().GetColorSettings() );
143 
144  wxASSERT( a3DCachePointer != NULL );
145  m_settings.Set3DCacheManager( a3DCachePointer );
146 
147  const wxEventType events[] =
148  {
149  // Binding both EVT_CHAR and EVT_CHAR_HOOK ensures that all key events,
150  // especially special key like arrow keys, are handled by the GAL event dispatcher,
151  // and not sent to GUI without filtering, because they have a default action (scroll)
152  // that must not be called.
153  wxEVT_LEFT_UP, wxEVT_LEFT_DOWN, wxEVT_LEFT_DCLICK,
154  wxEVT_RIGHT_UP, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_DCLICK,
155  wxEVT_MIDDLE_UP, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_DCLICK,
156  wxEVT_MOTION, wxEVT_MOUSEWHEEL, wxEVT_CHAR, wxEVT_CHAR_HOOK
157 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
158  , wxEVT_MAGNIFY
159 #endif
160  };
161 
162  for( wxEventType eventType : events )
163  Connect( eventType, wxEventHandler( EDA_3D_CANVAS::OnEvent ), NULL, m_eventDispatcher );
164 }
165 
166 
168 {
169  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::~EDA_3D_CANVAS" );
170 
171  releaseOpenGL();
172 }
173 
174 
176 {
177  if( m_glRC )
178  {
180 
181  delete m_3d_render_raytracing;
183 
184  delete m_3d_render_ogl_legacy;
186 
187  // This is just a copy of a pointer, can safely be set to NULL
188  m_3d_render = NULL;
189 
192  m_glRC = NULL;
193  }
194 }
195 
196 
197 void EDA_3D_CANVAS::OnCloseWindow( wxCloseEvent &event )
198 {
199  releaseOpenGL();
200 
201  event.Skip();
202 }
203 
204 
205 void EDA_3D_CANVAS::OnResize( wxSizeEvent &event )
206 {
207  this->Request_refresh();
208 }
209 
210 
212 {
213  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::initializeOpenGL" );
214 
215  const GLenum err = glewInit();
216 
217  if( GLEW_OK != err )
218  {
219  const wxString msgError = (const char*) glewGetErrorString( err );
220 
221  wxLogMessage( msgError );
222 
223  return false;
224  }
225  else
226  {
227  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::initializeOpenGL Using GLEW version %s",
228  FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
229  }
230 
231  wxString version = FROM_UTF8( (char *) glGetString( GL_VERSION ) );
232 
233  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::%s OpenGL version string %s.",
234  __WXFUNCTION__, version );
235 
236  // Extract OpenGL version from string. This method is used because prior to OpenGL 2,
237  // getting the OpenGL major and minor version as integers didn't exist.
238  wxString tmp;
239 
240  wxStringTokenizer tokenizer( version );
241 
243 
244  if( tokenizer.HasMoreTokens() )
245  {
246  long major = 0;
247  long minor = 0;
248 
249  tmp = tokenizer.GetNextToken();
250 
251  tokenizer.SetString( tmp, wxString( "." ) );
252 
253  if( tokenizer.HasMoreTokens() )
254  tokenizer.GetNextToken().ToLong( &major );
255 
256  if( tokenizer.HasMoreTokens() )
257  tokenizer.GetNextToken().ToLong( &minor );
258 
259  if( major < 2 || ( (major == 2 ) && (minor < 1) ) )
260  {
261  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::%s OpenGL ray tracing not supported.",
262  __WXFUNCTION__ );
263 
264  if( GetParent() )
265  {
266  wxCommandEvent evt( wxEVT_MENU, ID_DISABLE_RAY_TRACING );
267  GetParent()->ProcessWindowEvent( evt );
268  }
269 
271  }
272  }
273 
275 
276  return true;
277 }
278 
279 
280 void EDA_3D_CANVAS::GetScreenshot( wxImage &aDstImage )
281 {
282  OGL_GetScreenshot( aDstImage );
283 }
284 
285 
286 void EDA_3D_CANVAS::ReloadRequest( BOARD *aBoard , S3D_CACHE *aCachePointer )
287 {
288  if( aCachePointer != NULL )
289  m_settings.Set3DCacheManager( aCachePointer );
290 
291  if( aBoard != NULL )
292  m_settings.SetBoard( aBoard );
293 
294  m_settings.SetColorSettings( Pgm().GetSettingsManager().GetColorSettings() );
295 
296  if( m_3d_render )
298 }
299 
300 
302 {
304 
305  if( m_3d_render )
307 
309  //m_mouse_was_moved = true;
310 
311  Request_refresh();
312 }
313 
314 
316 {
317  if( m_parentStatusBar )
318  {
319  wxString msg;
320 
321  msg.Printf( "dx %3.2f", m_settings.CameraGet().GetCameraPos().x );
322  m_parentStatusBar->SetStatusText( msg, static_cast<int>( EDA_3D_VIEWER_STATUSBAR::X_POS ) );
323 
324  msg.Printf( "dy %3.2f", m_settings.CameraGet().GetCameraPos().y );
325  m_parentStatusBar->SetStatusText( msg, static_cast<int>( EDA_3D_VIEWER_STATUSBAR::Y_POS ) );
326  }
327 }
328 
329 
330 void EDA_3D_CANVAS::OnPaint( wxPaintEvent &event )
331 {
332  // Please have a look at:
333  // https://lists.launchpad.net/kicad-developers/msg25149.html
334  // wxPaintDC( this );
335  // event.Skip( false );
336 
337  // SwapBuffer requires the window to be shown before calling
338  if( !IsShownOnScreen() )
339  {
340  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnPaint !IsShown" );
341  return;
342  }
343 
344  // Because the board to draw is handled by the parent viewer frame,
345  // ensure this parent is still alive. When it is closed before the viewer
346  // frame, a paint event can be generated after the parent is closed,
347  // therefore with invalid board.
348  // This is dependent of the platform.
349  // Especially on OSX, but also on Windows, it frequently happens
350  if( !GetParent()->GetParent()->IsShown() )
351  return; // The parent board editor frame is no more alive
352 
353  wxString err_messages;
354 
355  // !TODO: implement error reporter
356  //WX_STRING_REPORTER errorReporter( &err_messages );
357  STATUS_TEXT_REPORTER activityReporter(
359  STATUS_TEXT_REPORTER warningReporter(
361 
362  unsigned strtime = GetRunningMicroSecs();
363 
364  // "Makes the OpenGL state that is represented by the OpenGL rendering
365  // context context current, i.e. it will be used by all subsequent OpenGL calls.
366  // This function may only be called when the window is shown on screen"
367 
368  // Explicitly create a new rendering context instance for this canvas.
369  if( m_glRC == NULL )
371 
373 
374  // Set the OpenGL viewport according to the client size of this canvas.
375  // This is done here rather than in a wxSizeEvent handler because our
376  // OpenGL rendering context (and thus viewport setting) is used with
377  // multiple canvases: If we updated the viewport in the wxSizeEvent
378  // handler, changing the size of one canvas causes a viewport setting that
379  // is wrong when next another canvas is repainted.
380  wxSize clientSize = GetNativePixelSize();
381 
382  const bool windows_size_changed = m_settings.CameraGet().SetCurWindowSize( clientSize );
383 
384  // Initialize openGL if need
385  // /////////////////////////////////////////////////////////////////////////
387  {
388  if( !initializeOpenGL() )
389  {
391 
392  return;
393  }
394  }
395 
396  // Don't attend to ray trace if OpenGL doesn't support it.
398  {
402  }
403 
404  // Check if a raytacing was requested and need to switch to raytracing mode
406  {
407  const bool was_camera_changed = m_settings.CameraGet().ParametersChanged();
408 
409  // It reverts back to OpenGL mode if it was requested a raytracing
410  // render of the current scene. AND the mouse / camera is moving
411  if( ( m_mouse_is_moving ||
413  was_camera_changed ||
414  windows_size_changed ) &&
416  {
419  }
420  }
421 
422  float curtime_delta_s = 0.0f;
423 
424  if( m_camera_is_moving )
425  {
426  const unsigned curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
427  curtime_delta_s = (curtime_delta / 1e6) * m_camera_moving_speed;
428  m_settings.CameraGet().Interpolate( curtime_delta_s );
429 
430  if( curtime_delta_s > 1.0f )
431  {
432  m_render_pivot = false;
433  m_camera_is_moving = false;
434  m_mouse_was_moved = true;
435 
437  DisplayStatus();
438  }
439  else
440  {
441  Request_refresh();
442  }
443  }
444 
445  // It will return true if the render request a new redraw
446  bool requested_redraw = false;
447 
448  if( m_3d_render )
449  {
450  m_3d_render->SetCurWindowSize( clientSize );
451 
452  requested_redraw = m_3d_render->Redraw( m_mouse_was_moved || m_camera_is_moving,
453  &activityReporter, &warningReporter );
454  }
455 
456  if( m_render_pivot )
457  {
458  const float scale = glm::min( m_settings.CameraGet().ZoomGet(), 1.0f );
459  render_pivot( curtime_delta_s, scale * scale );
460  }
461 
462  // "Swaps the double-buffer of this window, making the back-buffer the
463  // front-buffer and vice versa, so that the output of the previous OpenGL
464  // commands is displayed on the window."
465  SwapBuffers();
466 
468 
469  if( !activityReporter.HasMessage() )
470  {
472  {
473  // Calculation time in milliseconds
474  const double calculation_time = (double)( GetRunningMicroSecs() - strtime) / 1e3;
475 
476  activityReporter.Report( wxString::Format( _( "Render time %.0f ms ( %.1f fps)" ),
477  calculation_time, 1000.0 / calculation_time ) );
478  }
479  }
480 
481  // This will reset the flag of camera parameters changed
483 
484  if( !err_messages.IsEmpty() )
485  wxLogMessage( err_messages );
486 
487  if( (!m_camera_is_moving) && requested_redraw )
488  {
489  m_mouse_was_moved = false;
490  Request_refresh( false );
491  }
492 }
493 
494 
496 {
497  m_eventDispatcher = aEventDispatcher;
498 
499  if( m_eventDispatcher )
500  {
501  m_parent->Connect( wxEVT_TOOL,
502  wxCommandEventHandler( TOOL_DISPATCHER::DispatchWxCommand ),
504  }
505  else
506  {
507  // While loop is used to be sure that all event handlers are removed.
508  while( m_parent->Disconnect( wxEVT_TOOL,
509  wxCommandEventHandler( TOOL_DISPATCHER::DispatchWxCommand ),
510  NULL, m_eventDispatcher ) );
511  }
512 }
513 
514 
515 void EDA_3D_CANVAS::OnEvent( wxEvent& aEvent )
516 {
517  if( !m_eventDispatcher )
518  aEvent.Skip();
519  else
521 
522  Refresh();
523 }
524 
525 
526 void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent &event )
527 {
528  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnEraseBackground" );
529  // Do nothing, to avoid flashing.
530 }
531 
532 
533 void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent &event )
534 {
535  bool mouseActivity = false;
536 
537  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnMouseWheel" );
538 
539  if( m_camera_is_moving )
540  return;
541 
542  float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
543 
545  delta_move *= (0.01f * event.GetWheelRotation());
546  else
547  if( event.GetWheelRotation() < 0 )
548  delta_move = -delta_move;
549 
550  // mousewheel_panning enabled:
551  // wheel -> pan;
552  // wheel + shift -> horizontal scrolling;
553  // wheel + ctrl -> zooming;
554  // mousewheel_panning disabled:
555  // wheel + shift -> vertical scrolling;
556  // wheel + ctrl -> horizontal scrolling;
557  // wheel -> zooming.
558 
559  if( m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) && !event.ControlDown() )
560  {
561  if( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL || event.ShiftDown() )
562  m_settings.CameraGet().Pan( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
563  else
564  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
565 
566  mouseActivity = true;
567  }
568  else if( event.ShiftDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
569  {
570  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
571  mouseActivity = true;
572  }
573  else if( event.ControlDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
574  {
575  m_settings.CameraGet().Pan( SFVEC3F( delta_move, 0.0f, 0.0f ) );
576  mouseActivity = true;
577  }
578  else
579  {
580  mouseActivity = m_settings.CameraGet().Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
581  }
582 
583  // If it results on a camera movement
584  if( mouseActivity )
585  {
586  DisplayStatus();
587  Request_refresh();
588 
589  m_mouse_is_moving = true;
590  m_mouse_was_moved = true;
591 
593  }
594 
595  // Update the cursor current mouse position on the camera
596  m_settings.CameraGet().SetCurMousePosition( event.GetPosition() );
597 }
598 
599 
600 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
601 void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
602 {
603  SetFocus();
604 
605  if( m_camera_is_moving )
606  return;
607 
608  //m_is_moving_mouse = true;
610 
611  float magnification = ( event.GetMagnification() + 1.0f );
612 
613  m_settings.CameraGet().Zoom( magnification );
614 
615  DisplayStatus();
616  Request_refresh();
617 }
618 #endif
619 
620 
621 void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent &event )
622 {
623  //wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnMouseMove" ) );
624 
625  if( m_camera_is_moving )
626  return;
627 
629 
630  if( event.Dragging() )
631  {
632  if( event.LeftIsDown() ) // Drag
633  m_settings.CameraGet().Drag( event.GetPosition() );
634  else if( event.MiddleIsDown() ) // Pan
635  m_settings.CameraGet().Pan( event.GetPosition() );
636 
637  m_mouse_is_moving = true;
638  m_mouse_was_moved = true;
639 
640  // orientation has changed, redraw mesh
641  DisplayStatus();
642  Request_refresh();
643  }
644 
645  const wxPoint eventPosition = event.GetPosition();
646  m_settings.CameraGet().SetCurMousePosition( eventPosition );
647 }
648 
649 
650 void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent &event )
651 {
652  SetFocus();
654 }
655 
656 
657 void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent &event )
658 {
659  if( m_camera_is_moving )
660  return;
661 
662  if( m_mouse_is_moving )
663  {
664  m_mouse_is_moving = false;
666  }
667 }
668 
669 
670 void EDA_3D_CANVAS::OnMiddleDown( wxMouseEvent &event )
671 {
672  SetFocus();
674 }
675 
676 
677 void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent &event )
678 {
679  if( m_camera_is_moving )
680  return;
681 
682  if( m_mouse_is_moving )
683  {
684  m_mouse_is_moving = false;
686  }
687  else
688  {
690  }
691 }
692 
693 
694 void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent &event )
695 {
696  (void)event;
697 
698  m_mouse_is_moving = false;
699  m_mouse_was_moved = false;
700 
701  Request_refresh();
702 }
703 
704 
706 {
708 }
709 
710 
712 {
713  m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut() , wxTIMER_ONE_SHOT );
714 }
715 
716 
717 void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent &event )
718 {
719  wxPaintEvent redrawEvent;
720  wxPostEvent( this, redrawEvent );
721 }
722 
723 
724 void EDA_3D_CANVAS::Request_refresh( bool aRedrawImmediately )
725 {
726  if( aRedrawImmediately )
727  {
728  // On some systems, just calling Refresh does not work always
729  // (Issue experienced on Win7 MSYS2)
730  //Refresh();
731  //Update();
732 
733  // Using PostEvent will take priority to other events like mouse movements, keys, etc.
734  wxPaintEvent redrawEvent;
735  wxPostEvent( this, redrawEvent );
736 
737  // This behaves the same
738  // wxQueueEvent( this,
739  // From wxWidget documentation: "The heap-allocated and
740  // non-NULL event to queue, the function takes ownership of it."
741  // new wxPaintEvent()
742  // );
743  }
744  else
745  {
746  // Schedule a timed redraw
747  m_redraw_trigger_timer.Start( 10 , wxTIMER_ONE_SHOT );
748  }
749 }
750 
751 
752 void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRenderPivot )
753 {
754  wxASSERT( aMovingSpeed > FLT_EPSILON );
755 
756  m_render_pivot = aRenderPivot;
757  m_camera_moving_speed = aMovingSpeed;
758 
760 
761  DisplayStatus();
762  Request_refresh();
763 
764  m_camera_is_moving = true;
765 
767 }
768 
769 
771 {
772  SFVEC3F rayOrigin;
773  SFVEC3F rayDir;
774 
775  // Generate a ray origin and direction based on current mouser position and camera
776  m_settings.CameraGet().MakeRayAtCurrrentMousePosition( rayOrigin, rayDir );
777 
778  RAY mouseRay;
779  mouseRay.Init( rayOrigin, rayDir );
780 
781  float hit_t;
782 
783  // Test it with the board bounding box
784  if( m_settings.GetBBox3DU().Intersect( mouseRay, &hit_t ) )
785  {
788  m_settings.CameraGet().SetLookAtPos_T1( mouseRay.at( hit_t ) );
790 
792  }
793 }
794 
795 
796 bool EDA_3D_CANVAS::SetView3D( int aKeycode )
797 {
798  if( m_camera_is_moving )
799  return false;
800 
801  const float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
802  const float arrow_moving_time_speed = 8.0f;
803  bool handled = false;
804 
805  switch( aKeycode )
806  {
807  case WXK_SPACE:
809  return true;
810 
811  case WXK_LEFT:
814  m_settings.CameraGet().Pan_T1( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
815  request_start_moving_camera( arrow_moving_time_speed, false );
816  return true;
817 
818  case WXK_RIGHT:
821  m_settings.CameraGet().Pan_T1( SFVEC3F( +delta_move, 0.0f, 0.0f ) );
822  request_start_moving_camera( arrow_moving_time_speed, false );
823  return true;
824 
825  case WXK_UP:
828  m_settings.CameraGet().Pan_T1( SFVEC3F( 0.0f, +delta_move, 0.0f ) );
829  request_start_moving_camera( arrow_moving_time_speed, false );
830  return true;
831 
832  case WXK_DOWN:
835  m_settings.CameraGet().Pan_T1( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
836  request_start_moving_camera( arrow_moving_time_speed, false );
837  return true;
838 
839  case WXK_HOME:
843  request_start_moving_camera( glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 1/1.26f ), 1.26f ) );
844  return true;
845 
846  case WXK_END:
847  break;
848 
849  case WXK_TAB:
852  m_settings.CameraGet().RotateZ_T1( glm::radians( 45.0f ) );
854  handled = true;
855  break;
856 
857  case WXK_F1:
860 
861  if( m_settings.CameraGet().Zoom_T1( 1.26f ) ) // 3 steps per doubling
863 
864  return true;
865 
866  case WXK_F2:
869 
870  if( m_settings.CameraGet().Zoom_T1( 1/1.26f ) ) // 3 steps per halving
872 
873  return true;
874 
875  case '+':
876  case '-':
877  break;
878 
879  case 't':
880  case 'T':
883  ReloadRequest();
884  handled = true;
885  break;
886 
887  case 's':
888  case 'S':
891  ReloadRequest();
892  handled = true;
893  break;
894 
895  case 'v':
896  case 'V':
899  ReloadRequest();
900  handled = true;
901  break;
902 
903  case 'r':
904  case 'R':
908  request_start_moving_camera( glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
909  return true;
910 
911  case ID_VIEW3D_RIGHT:
915  m_settings.CameraGet().RotateZ_T1( glm::radians( -90.0f ) );
916  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
918  return true;
919 
920  case ID_VIEW3D_LEFT:
924  m_settings.CameraGet().RotateZ_T1( glm::radians( 90.0f ) );
925  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
927  return true;
928 
929  case ID_VIEW3D_FRONT:
933  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
935  return true;
936 
937  case ID_VIEW3D_BACK:
941  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
942  m_settings.CameraGet().RotateZ_T1( glm::radians( -180.0f ) );
944  return true;
945 
946  case ID_VIEW3D_TOP:
951  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
952  return true;
953 
954  case ID_VIEW3D_BOTTOM:
958  m_settings.CameraGet().RotateY_T1( glm::radians( 180.0f ) );
960  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
961  return true;
962 
963  default:
964  return false;
965  }
966 
967  m_mouse_was_moved = true;
968 
970 
971  DisplayStatus();
972  Request_refresh();
973 
974  return handled;
975 }
976 
977 
979 {
980  switch( m_settings.RenderEngineGet() )
981  {
984  default: m_3d_render = NULL; break;
985  }
986 
987  if( m_3d_render )
989 
990  m_mouse_was_moved = false;
991 
992  Request_refresh();
993 }
C3D_RENDER_RAYTRACING * m_3d_render_raytracing
void SetLookAtPos_T1(const SFVEC3F &aLookAtPos)
Definition: ccamera.h:128
virtual wxSize GetNativePixelSize() const
void OGL_GetScreenshot(wxImage &aDstImage)
OGL_GetScreenshot - got the pixel data of current OpenGL image.
Definition: ogl_utils.cpp:35
void OnMouseMove(wxMouseEvent &event)
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:103
void OnResize(wxSizeEvent &event)
void request_start_moving_camera(float aMovingSpeed=2.0f, bool aRenderPivot=true)
request_start_moving_camera - start a camera movement
void releaseOpenGL()
releaseOpenGL - free created targets and openGL context
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:62
virtual void SetT0_and_T1_current_T()
SetT0_and_T1_current_T - This will set T0 and T1 with the current values.
Definition: ccamera.cpp:555
bool m_mouse_is_moving
CINFO3D_VISU & m_settings
void ResetXYpos_T1()
Definition: ccamera.cpp:412
unsigned m_strtime_camera_movement
void stop_editingTimeOut_Timer()
stop_editingTimeOut_Timer - stop the editing time, so it will not timeout
void Init(const SFVEC3F &o, const SFVEC3F &d)
Definition: ray.cpp:40
wxStatusBar * m_parentStatusBar
virtual bool Redraw(bool aIsMoving, REPORTER *aStatusTextReporter=NULL, REPORTER *aWarningTextReporter=NULL)=0
Redraw - Ask to redraw the view.
wxGLContext * m_glRC
void OnCloseWindow(wxCloseEvent &event)
wxGLCanvas wrapper for HiDPI/Retina support.
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:46
wxTimer m_editing_timeout_timer
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
void SetColorSettings(COLOR_SETTINGS *aSettings)
Definition: cinfo3d_visu.h:133
Definition: ray.h:67
void DisplayStatus()
DisplayStatus - Update the status bar with the position information.
C3D_RENDER_OGL_LEGACY * m_3d_render_ogl_legacy
S3D_CACHE.
Definition: 3d_cache.h:54
void Request_refresh(bool aRedrawImmediately=true)
Request_refresh - Schedule a refresh update of the canvas.
void ReloadRequest(BOARD *aBoard=NULL, S3D_CACHE *aCachePointer=NULL)
virtual int GetWaitForEditingTimeOut()=0
GetWaitForEditingTimeOut - Give the interface the time (in ms) that it should wait for editing or mov...
void UnlockCtx(wxGLContext *aContext)
Function UnlockCtx allows other canvases to bind an OpenGL context.
SFVEC3F at(float t) const
Definition: ray.h:89
bool GetFlag(DISPLAY3D_FLG aFlag) const
GetFlag - get a configuration status of a flag.
void SetCurMousePosition(const wxPoint &aPosition)
It updates the current mouse position without make any new recalculations on camera.
Definition: ccamera.cpp:431
bool Zoom(float aFactor)
Definition: ccamera.cpp:474
void OnLeftDown(wxMouseEvent &event)
float m_camera_moving_speed
void RenderEngineSet(RENDER_ENGINE aRenderEngine)
RenderEngineSet.
Definition: cinfo3d_visu.h:234
static GL_CONTEXT_MANAGER & Get()
Function Get returns the GL_CONTEXT_MANAGER instance (singleton).
bool HasMessage() const override
Function HasMessage Returns true if the reporter client is non-empty.
void OnLeftUp(wxMouseEvent &event)
void restart_editingTimeOut_Timer()
restart_editingTimeOut_Timer - reset the editing timer
CCAMERA & CameraGet() const
CameraGet - get current camera in use.
Definition: cinfo3d_visu.h:216
void RenderRaytracingRequest()
RenderRaytracingRequest - Request to render the current view in Raytracing mode.
void SetEventDispatcher(TOOL_DISPATCHER *aEventDispatcher)
Function SetEventDispatcher() Sets a dispatcher that processes events and forwards them to tools.
float ZoomGet() const
Definition: ccamera.cpp:510
#define NULL
void OnMiddleDown(wxMouseEvent &event)
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
bool m_mouse_was_moved
void OnEraseBackground(wxEraseEvent &event)
void OnMouseWheel(wxMouseEvent &event)
void RenderEngineChanged()
RenderEngineChanged - Notify that the render engine was changed.
virtual void DispatchWxEvent(wxEvent &aEvent)
Function DispatchWxEvent() Processes wxEvents (mostly UI events), translates them to TOOL_EVENTs,...
STATUS_TEXT_REPORTER is a wrapper for reporting to a wxString in a wxFrame status text.
Class CINFO3D_VISU Helper class to handle information needed to display 3D board.
Definition: cinfo3d_visu.h:73
bool m_camera_is_moving
const CBBOX & GetBBox3DU() const
GetBBox3DU - Get the bbox of the pcb board.
Definition: cinfo3d_visu.h:153
virtual void Interpolate(float t)
Interpolate - It will update the matrix to interpolate between T0 and T1 values.
Definition: ccamera.cpp:569
virtual void Drag(const wxPoint &aNewMousePosition)=0
Calculate a new mouse drag position.
EVT_MIDDLE_DOWN(mpWindow::OnMouseMiddleDown) EVT_MOUSEWHEEL(mpWindow
Definition: mathplot.cpp:1699
bool SetCurWindowSize(const wxSize &aSize)
SetCurWindowSize - update the windows size of the camera.
Definition: ccamera.cpp:448
void OnTimerTimeout_Redraw(wxTimerEvent &event)
bool Zoom_T1(float aFactor)
Definition: ccamera.cpp:493
virtual void Pan_T1(const SFVEC3F &aDeltaOffsetInc)=0
void RotateX_T1(float aAngleInRadians)
Definition: ccamera.cpp:537
virtual void Reset_T1()
Definition: ccamera.cpp:103
TOOL_DISPATCHER.
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Function LockCtx sets a context as current and prevents other canvases from switching it.
RENDER_ENGINE RenderEngineGet() const
RenderEngineGet.
Definition: cinfo3d_visu.h:240
bool m_is_opengl_initialized
C3D_RENDER_BASE * m_3d_render
void OnMiddleUp(wxMouseEvent &event)
The C3D_RENDER_OGL_LEGACY class render the board using openGL legacy mode.
TOOL_DISPATCHER * m_eventDispatcher
void GetScreenshot(wxImage &aDstImage)
Request a screenshot and output it to the aDstImage.
const int scale
see class PGM_BASE
bool initializeOpenGL()
initializeOpenGL
void OnEvent(wxEvent &aEvent)
Used to forward events to the canvas from popups, etc.
bool m_opengl_supports_raytracing
Declaration of the eda_3d_viewer class.
void RotateY_T1(float aAngleInRadians)
Definition: ccamera.cpp:543
void MakeRayAtCurrrentMousePosition(SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
MakeRayAtCurrrentMousePosition - Make a ray based on the latest mouse position.
Definition: ccamera.cpp:380
void move_pivot_based_on_cur_mouse_position()
move_pivot_based_on_cur_mouse_position - This function hits a ray to the board and start a moviment
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:163
virtual void DispatchWxCommand(wxCommandEvent &aEvent)
Function DispatchWxCommand() Processes wxCommands (mostly menu related events) and runs appropriate a...
#define _(s)
Definition: 3d_actions.cpp:33
bool Intersect(const RAY &aRay, float *t) const
Function Intersect.
Definition: cbbox_ray.cpp:46
unsigned GetRunningMicroSecs()
Function GetRunningMicroSecs An alternate way to calculate an elapset time (in microsecondes) to clas...
virtual void Pan(const wxPoint &aNewMousePosition)=0
glm::vec3 SFVEC3F
Definition: xv3d_types.h:47
bool SetView3D(int aKeycode)
SetView3D - Helper function to call view commands.
void OnPaint(wxPaintEvent &event)
void OnTimerTimeout_Editing(wxTimerEvent &event)
const SFVEC3F & GetCameraPos() const
Definition: ccamera.h:134
void DestroyCtx(wxGLContext *aContext)
Function DestroyCtx destroys a managed OpenGL context.
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=NULL)
Function CreateCtx creates a managed OpenGL context.
void SetFlag(DISPLAY3D_FLG aFlag, bool aState)
SetFlag - set the status of a flag.
virtual void SetCurWindowSize(const wxSize &aSize)=0
SetCurWindowSize - Before each render, the canvas will tell the render what is the size of its window...
void ReloadRequest()
ReloadRequest - !TODO: this must be reviewed to add flags to improve specific render.
void RotateZ_T1(float aAngleInRadians)
Definition: ccamera.cpp:549
void SetBoard(BOARD *aBoard)
SetBoard - Set current board to be rendered.
Definition: cinfo3d_visu.h:125
wxTimer m_redraw_trigger_timer
static const float m_delta_move_step_factor
void render_pivot(float t, float aScale)
render_pivot - render the pivot cursor
void SetInterpolateMode(CAMERA_INTERPOLATION aInterpolateMode)
Definition: ccamera.h:200
bool ParametersChanged()
Function ParametersChanged.
Definition: ccamera.cpp:587
void Set3DCacheManager(S3D_CACHE *aCachePointer)
Set3DCacheManager - Update the Cache manager pointer.
Definition: cinfo3d_visu.h:85
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Function Report is a pure virtual function to override in the derived object.
bool m_render_raytracing_was_requested