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/openGL_includes.h"
34 #include "../common_ogl/ogl_utils.h"
35 #include "eda_3d_canvas.h"
36 #include "../3d_viewer_id.h"
37 #include "../3d_rendering/3d_render_raytracing/c3d_render_raytracing.h"
38 #include "../3d_viewer/eda_3d_viewer.h"
39 #include "../3d_rendering/test_cases.h"
40 #include <class_board.h>
41 #include "status_text_reporter.h"
42 #include <gl_context_mgr.h>
43 #include <profile.h> // To use GetRunningMicroSecs or another profiling utility
44 #include <bitmaps.h>
45 #include <hotkeys_basic.h>
46 #include <menus_helpers.h>
47 
49 
50 
58 const wxChar * EDA_3D_CANVAS::m_logTrace = wxT( "KI_TRACE_EDA_3D_CANVAS" );
59 
61 
62 
63 BEGIN_EVENT_TABLE( EDA_3D_CANVAS, wxGLCanvas )
64  EVT_PAINT( EDA_3D_CANVAS::OnPaint )
65  EVT_CHAR( EDA_3D_CANVAS::OnKeyEvent )
66  EVT_CHAR_HOOK( EDA_3D_CANVAS::OnCharHook )
67 
68  // mouse events
69  EVT_LEFT_DOWN( EDA_3D_CANVAS::OnLeftDown )
70  EVT_LEFT_UP( EDA_3D_CANVAS::OnLeftUp )
71  EVT_MIDDLE_UP( EDA_3D_CANVAS::OnMiddleUp )
73  EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightClick )
74  EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
75  EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
76 
77 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
78  EVT_MAGNIFY( EDA_3D_CANVAS::OnMagnify )
79 #endif
80 
81  // other events
82  EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
84  ID_POPUP_3D_VIEW_END, EDA_3D_CANVAS::OnPopUpMenu )
85 
86  EVT_CLOSE( EDA_3D_CANVAS::OnCloseWindow )
87  EVT_SIZE( EDA_3D_CANVAS::OnResize )
88 END_EVENT_TABLE()
89 
90 
91 EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow *aParent,
92  const int *aAttribList,
93  BOARD *aBoard,
94  CINFO3D_VISU &aSettings , S3D_CACHE *a3DCachePointer ) :
95  HIDPI_GL_CANVAS( aParent,
96  wxID_ANY,
97  aAttribList,
98  wxDefaultPosition,
99  wxDefaultSize,
100  wxFULL_REPAINT_ON_RESIZE
101  ),
102  m_settings( aSettings )
103 {
104  // Run test cases in debug mode, once.
105 
106  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::EDA_3D_CANVAS" );
107 
108  m_editing_timeout_timer.SetOwner( this );
109  Connect( m_editing_timeout_timer.GetId(),
110  wxEVT_TIMER,
111  wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Editing ),
112  NULL,
113  this );
114 
115  m_redraw_trigger_timer.SetOwner( this );
116  Connect( m_redraw_trigger_timer.GetId(),
117  wxEVT_TIMER,
118  wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Redraw ),
119  NULL,
120  this );
121 
122  m_mouse_was_moved = false;
123  m_mouse_is_moving = false;
124  m_camera_is_moving = false;
125  m_render_pivot = false;
126  m_camera_moving_speed = 1.0f;
127 
128  m_strtime_camera_movement = 0;
129 
130  m_is_opengl_initialized = false;
131 
132  m_render_raytracing_was_requested = false;
133  m_opengl_supports_raytracing = false;
134 
135  m_parentStatusBar = NULL;
136  m_glRC = NULL;
137 
138  m_3d_render = NULL;
139 
140  m_3d_render_raytracing = new C3D_RENDER_RAYTRACING( aSettings );
141  m_3d_render_ogl_legacy = new C3D_RENDER_OGL_LEGACY( aSettings );
142 
143  wxASSERT( m_3d_render_raytracing != NULL );
144  wxASSERT( m_3d_render_ogl_legacy != NULL );
145 
146  auto busy_indicator_factory = []() { return std::make_unique<WX_BUSY_INDICATOR>(); };
147 
148  m_3d_render_raytracing->SetBusyIndicatorFactory( busy_indicator_factory );
149  m_3d_render_ogl_legacy->SetBusyIndicatorFactory( busy_indicator_factory );
150 
151  RenderEngineChanged();
152 
153  wxASSERT( aBoard != NULL );
154  m_settings.SetBoard( aBoard );
155 
156  wxASSERT( a3DCachePointer != NULL );
157  m_settings.Set3DCacheManager( a3DCachePointer );
158 }
159 
160 
162 {
163  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::~EDA_3D_CANVAS" );
164 
165  releaseOpenGL();
166 }
167 
168 
170 {
171  if( m_glRC )
172  {
174 
175  delete m_3d_render_raytracing;
176  m_3d_render_raytracing = NULL;
177 
178  delete m_3d_render_ogl_legacy;
179  m_3d_render_ogl_legacy = NULL;
180 
181  // This is just a copy of a pointer, can safely be set to NULL
182  m_3d_render = NULL;
183 
186  m_glRC = NULL;
187  }
188 }
189 
190 
191 void EDA_3D_CANVAS::OnCloseWindow( wxCloseEvent &event )
192 {
193  releaseOpenGL();
194 
195  event.Skip();
196 }
197 
198 
199 void EDA_3D_CANVAS::OnResize( wxSizeEvent &event )
200 {
201  this->Request_refresh();
202 }
203 
204 
206 {
207  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::initializeOpenGL" );
208 
209  const GLenum err = glewInit();
210 
211  if( GLEW_OK != err )
212  {
213  const wxString msgError = (const char*) glewGetErrorString( err );
214 
215  wxLogMessage( msgError );
216 
217  return false;
218  }
219  else
220  {
221  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::initializeOpenGL Using GLEW version %s",
222  FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
223  }
224 
225  wxString version = FROM_UTF8( (char *) glGetString( GL_VERSION ) );
226 
227  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::%s OpenGL version string %s.",
228  __WXFUNCTION__, version );
229 
230  // Extract OpenGL version from string. This method is used because prior to OpenGL 2,
231  // getting the OpenGL major and minor version as integers didn't exist.
232  wxString tmp;
233 
234  wxStringTokenizer tokenizer( version );
235 
237 
238  if( tokenizer.HasMoreTokens() )
239  {
240  long major = 0;
241  long minor = 0;
242 
243  tmp = tokenizer.GetNextToken();
244 
245  tokenizer.SetString( tmp, wxString( "." ) );
246 
247  if( tokenizer.HasMoreTokens() )
248  tokenizer.GetNextToken().ToLong( &major );
249 
250  if( tokenizer.HasMoreTokens() )
251  tokenizer.GetNextToken().ToLong( &minor );
252 
253  if( major < 2 || ( (major == 2 ) && (minor < 1) ) )
254  {
255  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::%s OpenGL ray tracing not supported.",
256  __WXFUNCTION__ );
257 
258  if( GetParent() )
259  {
260  wxCommandEvent evt( wxEVT_MENU, ID_DISABLE_RAY_TRACING );
261  GetParent()->ProcessWindowEvent( evt );
262  }
263 
265  }
266  }
267 
269 
270  return true;
271 }
272 
273 
274 void EDA_3D_CANVAS::GetScreenshot( wxImage &aDstImage )
275 {
276  OGL_GetScreenshot( aDstImage );
277 }
278 
279 
280 void EDA_3D_CANVAS::ReloadRequest( BOARD *aBoard , S3D_CACHE *aCachePointer )
281 {
282  if( aCachePointer != NULL )
283  m_settings.Set3DCacheManager( aCachePointer );
284 
285  if( aBoard != NULL )
286  m_settings.SetBoard( aBoard );
287 
288  if( m_3d_render )
290 }
291 
292 
294 {
296 
297  if( m_3d_render )
299 
301  //m_mouse_was_moved = true;
302 
303  Request_refresh();
304 }
305 
306 
308 {
309  if( m_parentStatusBar )
310  {
311  wxString msg;
312 
313  msg.Printf( "dx %3.2f", m_settings.CameraGet().GetCameraPos().x );
314  m_parentStatusBar->SetStatusText( msg, 1 );
315 
316  msg.Printf( "dy %3.2f", m_settings.CameraGet().GetCameraPos().y );
317  m_parentStatusBar->SetStatusText( msg, 2 );
318  }
319 }
320 
321 
322 void EDA_3D_CANVAS::OnPaint( wxPaintEvent &event )
323 {
324  // Please have a look at:
325  // https://lists.launchpad.net/kicad-developers/msg25149.html
326  // wxPaintDC( this );
327  // event.Skip( false );
328 
329  // SwapBuffer requires the window to be shown before calling
330  if( !IsShownOnScreen() )
331  {
332  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnPaint !IsShown" );
333  return;
334  }
335 
336  // Because the board to draw is handled by the parent viewer frame,
337  // ensure this parent is still alive. When it is closed before the viewer
338  // frame, a paint event can be generated after the parent is closed,
339  // therefore with invalid board.
340  // This is dependent of the platform.
341  // Especially on OSX, but also on Windows, it frequently happens
342  if( !GetParent()->GetParent()->IsShown() )
343  return; // The parent board editor frame is no more alive
344 
345  wxString err_messages;
346 
347  // !TODO: implement error reporter
348  //WX_STRING_REPORTER errorReporter( &err_messages );
349  STATUS_TEXT_REPORTER activityReporter( m_parentStatusBar, 0 );
350 
351  unsigned strtime = GetRunningMicroSecs();
352 
353  // "Makes the OpenGL state that is represented by the OpenGL rendering
354  // context context current, i.e. it will be used by all subsequent OpenGL calls.
355  // This function may only be called when the window is shown on screen"
356 
357  // Explicitly create a new rendering context instance for this canvas.
358  if( m_glRC == NULL )
360 
362 
363  // Set the OpenGL viewport according to the client size of this canvas.
364  // This is done here rather than in a wxSizeEvent handler because our
365  // OpenGL rendering context (and thus viewport setting) is used with
366  // multiple canvases: If we updated the viewport in the wxSizeEvent
367  // handler, changing the size of one canvas causes a viewport setting that
368  // is wrong when next another canvas is repainted.
369  wxSize clientSize = GetNativePixelSize();
370 
371  const bool windows_size_changed = m_settings.CameraGet().SetCurWindowSize( clientSize );
372 
373  // Initialize openGL if need
374  // /////////////////////////////////////////////////////////////////////////
376  {
377  if( !initializeOpenGL() )
378  {
380 
381  return;
382  }
383  }
384 
385  // Don't attend to ray trace if OpenGL doesn't support it.
387  {
391  }
392 
393  // Check if a raytacing was requested and need to switch to raytracing mode
395  {
396  const bool was_camera_changed = m_settings.CameraGet().ParametersChanged();
397 
398  // It reverts back to OpenGL mode if it was requested a raytracing
399  // render of the current scene. AND the mouse / camera is moving
400  if( ( m_mouse_is_moving ||
402  was_camera_changed ||
403  windows_size_changed ) &&
405  {
408  }
409  }
410 
411  float curtime_delta_s = 0.0f;
412 
413  if( m_camera_is_moving )
414  {
415  const unsigned curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
416  curtime_delta_s = (curtime_delta / 1e6) * m_camera_moving_speed;
417  m_settings.CameraGet().Interpolate( curtime_delta_s );
418 
419  if( curtime_delta_s > 1.0f )
420  {
421  m_render_pivot = false;
422  m_camera_is_moving = false;
423  m_mouse_was_moved = true;
424 
426  DisplayStatus();
427  }
428  else
429  {
430  Request_refresh();
431  }
432  }
433 
434  // It will return true if the render request a new redraw
435  bool requested_redraw = false;
436 
437  if( m_3d_render )
438  {
439  m_3d_render->SetCurWindowSize( clientSize );
440 
441  requested_redraw = m_3d_render->Redraw( m_mouse_was_moved || m_camera_is_moving,
442  &activityReporter );
443  }
444 
445  if( m_render_pivot )
446  {
447  const float scale = glm::min( m_settings.CameraGet().ZoomGet(), 1.0f );
448  render_pivot( curtime_delta_s, scale * scale );
449  }
450 
451  // "Swaps the double-buffer of this window, making the back-buffer the
452  // front-buffer and vice versa, so that the output of the previous OpenGL
453  // commands is displayed on the window."
454  SwapBuffers();
455 
457 
458  if( !activityReporter.HasMessage() )
459  {
461  {
462  // Calculation time in milliseconds
463  const double calculation_time = (double)( GetRunningMicroSecs() - strtime) / 1e3;
464 
465  activityReporter.Report( wxString::Format( _( "Render time %.0f ms ( %.1f fps)" ),
466  calculation_time, 1000.0 / calculation_time ) );
467  }
468  }
469 
470  // This will reset the flag of camera parameters changed
472 
473  if( !err_messages.IsEmpty() )
474  wxLogMessage( err_messages );
475 
476  if( (!m_camera_is_moving) && requested_redraw )
477  {
478  m_mouse_was_moved = false;
479  Request_refresh( false );
480  }
481 }
482 
483 
484 void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent &event )
485 {
486  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnEraseBackground" );
487  // Do nothing, to avoid flashing.
488 }
489 
490 
491 void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent &event )
492 {
493  bool mouseActivity = false;
494 
495  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnMouseWheel" );
496 
497  if( m_camera_is_moving )
498  return;
499 
500  float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
501 
503  delta_move *= (0.01f * event.GetWheelRotation());
504  else
505  if( event.GetWheelRotation() < 0 )
506  delta_move = -delta_move;
507 
508  // mousewheel_panning enabled:
509  // wheel -> pan;
510  // wheel + shift -> horizontal scrolling;
511  // wheel + ctrl -> zooming;
512  // mousewheel_panning disabled:
513  // wheel + shift -> vertical scrolling;
514  // wheel + ctrl -> horizontal scrolling;
515  // wheel -> zooming.
516 
517  if( m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) && !event.ControlDown() )
518  {
519  if( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL || event.ShiftDown() )
520  m_settings.CameraGet().Pan( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
521  else
522  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
523 
524  mouseActivity = true;
525  }
526  else if( event.ShiftDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
527  {
528  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
529  mouseActivity = true;
530  }
531  else if( event.ControlDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
532  {
533  m_settings.CameraGet().Pan( SFVEC3F( delta_move, 0.0f, 0.0f ) );
534  mouseActivity = true;
535  }
536  else
537  {
538  mouseActivity = m_settings.CameraGet().Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
539  }
540 
541  // If it results on a camera movement
542  if( mouseActivity )
543  {
544  DisplayStatus();
545  Request_refresh();
546 
547  m_mouse_is_moving = true;
548  m_mouse_was_moved = true;
549 
551  }
552 
553  // Update the cursor current mouse position on the camera
554  m_settings.CameraGet().SetCurMousePosition( event.GetPosition() );
555 }
556 
557 
558 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
559 void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
560 {
561  SetFocus();
562 
563  if( m_camera_is_moving )
564  return;
565 
566  //m_is_moving_mouse = true;
568 
569  float magnification = ( event.GetMagnification() + 1.0f );
570 
571  m_settings.CameraGet().Zoom( magnification );
572 
573  DisplayStatus();
574  Request_refresh();
575 }
576 #endif
577 
578 
579 void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent &event )
580 {
581  //wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnMouseMove" ) );
582 
583  if( m_camera_is_moving )
584  return;
585 
587 
588  if( event.Dragging() )
589  {
590  if( event.LeftIsDown() ) // Drag
591  m_settings.CameraGet().Drag( event.GetPosition() );
592  else if( event.MiddleIsDown() ) // Pan
593  m_settings.CameraGet().Pan( event.GetPosition() );
594 
595  m_mouse_is_moving = true;
596  m_mouse_was_moved = true;
597 
598  // orientation has changed, redraw mesh
599  DisplayStatus();
600  Request_refresh();
601  }
602 
603  const wxPoint eventPosition = event.GetPosition();
604  m_settings.CameraGet().SetCurMousePosition( eventPosition );
605 }
606 
607 
608 void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent &event )
609 {
610  SetFocus();
612 }
613 
614 
615 void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent &event )
616 {
617  if( m_camera_is_moving )
618  return;
619 
620  if( m_mouse_is_moving )
621  {
622  m_mouse_is_moving = false;
624  }
625 }
626 
627 
628 void EDA_3D_CANVAS::OnMiddleDown( wxMouseEvent &event )
629 {
630  SetFocus();
632 }
633 
634 
635 void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent &event )
636 {
637  if( m_camera_is_moving )
638  return;
639 
640  if( m_mouse_is_moving )
641  {
642  m_mouse_is_moving = false;
644  }
645  else
646  {
648  }
649 }
650 
651 
652 void EDA_3D_CANVAS::OnRightClick( wxMouseEvent &event )
653 {
654  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnRightClick" );
655 
656  SetFocus();
657 
658  if( m_camera_is_moving )
659  return;
660 
661  wxPoint pos;
662  wxMenu PopUpMenu;
663  wxString msg;
664 
665  pos.x = event.GetX();
666  pos.y = event.GetY();
667 
668  msg = AddHotkeyName( _( "Zoom +" ), GetHotkeyConfig(),
669  ID_POPUP_ZOOMIN );
670  AddMenuItem( &PopUpMenu, ID_POPUP_ZOOMIN,
671  msg, KiBitmap( zoom_in_xpm ) );
672 
673 
674  msg = AddHotkeyName( _( "Zoom -" ), GetHotkeyConfig(),
676  AddMenuItem( &PopUpMenu, ID_POPUP_ZOOMOUT,
677  msg, KiBitmap( zoom_out_xpm ) );
678 
679  PopUpMenu.AppendSeparator();
680 
681  msg = AddHotkeyName( _( "Top View" ), GetHotkeyConfig(),
683  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZPOS,
684  msg, KiBitmap( axis3d_top_xpm ) );
685 
686  msg = AddHotkeyName( _( "Bottom View" ), GetHotkeyConfig(),
688  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZNEG,
689  msg, KiBitmap( axis3d_bottom_xpm ) );
690 
691  PopUpMenu.AppendSeparator();
692 
693  msg = AddHotkeyName( _( "Right View" ), GetHotkeyConfig(),
695  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_XPOS,
696  msg, KiBitmap( axis3d_right_xpm ) );
697 
698  msg = AddHotkeyName( _( "Left View" ), GetHotkeyConfig(),
700  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_XNEG,
701  msg, KiBitmap( axis3d_left_xpm ) );
702 
703  PopUpMenu.AppendSeparator();
704 
705  msg = AddHotkeyName( _( "Front View" ), GetHotkeyConfig(),
707  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_YPOS,
708  msg, KiBitmap( axis3d_front_xpm ) );
709 
710  msg = AddHotkeyName( _( "Back View" ), GetHotkeyConfig(),
712  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_YNEG,
713  msg, KiBitmap( axis3d_back_xpm ) );
714 
715  PopUpMenu.AppendSeparator();
716 
717  msg = AddHotkeyName( _( "Move Left <-" ), GetHotkeyConfig(),
719  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_LEFT,
720  msg, KiBitmap( left_xpm ) );
721 
722  msg = AddHotkeyName( _( "Move Right ->" ), GetHotkeyConfig(),
724  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_RIGHT,
725  msg, KiBitmap( right_xpm ) );
726 
727  msg = AddHotkeyName( _( "Move Up ^" ), GetHotkeyConfig(),
729  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_UP,
730  msg, KiBitmap( up_xpm ) );
731 
732  msg = AddHotkeyName( _( "Move Down" ), GetHotkeyConfig(),
734  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_DOWN,
735  msg, KiBitmap( down_xpm ) );
736 
737  PopupMenu( &PopUpMenu, pos );
738 }
739 
740 
741 void EDA_3D_CANVAS::OnPopUpMenu( wxCommandEvent &event )
742 {
743  int id = event.GetId();
744 
745  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnPopUpMenu id:%d", id );
746 
747  int key = 0;
748 
749  switch( id )
750  {
751  case ID_POPUP_ZOOMIN:
752  key = WXK_F1;
753  break;
754 
755  case ID_POPUP_ZOOMOUT:
756  key = WXK_F2;
757  break;
758 
759  case ID_POPUP_VIEW_XPOS:
760  key = 'X';
761  break;
762 
763  case ID_POPUP_VIEW_XNEG:
764  key = GR_KB_SHIFT + 'X';
765  break;
766 
767  case ID_POPUP_VIEW_YPOS:
768  key = 'Y';
769  break;
770 
771  case ID_POPUP_VIEW_YNEG:
772  key = GR_KB_SHIFT + 'Y';
773  break;
774 
775  case ID_POPUP_VIEW_ZPOS:
776  key = 'Z';
777  break;
778 
779  case ID_POPUP_VIEW_ZNEG:
780  key = GR_KB_SHIFT + 'Z';
781  break;
782 
784  key = WXK_LEFT;
785  break;
786 
788  key = WXK_RIGHT;
789  break;
790 
791  case ID_POPUP_MOVE3D_UP:
792  key = WXK_UP;
793  break;
794 
796  key = WXK_DOWN;
797  break;
798 
799  default:
800  return;
801  }
802 
803  SetView3D( key );
804 }
805 
806 
807 void EDA_3D_CANVAS::OnCharHook( wxKeyEvent &event )
808 {
809  //wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnCharHook" );
810  event.Skip();
811 }
812 
813 
814 void EDA_3D_CANVAS::OnKeyEvent( wxKeyEvent& event )
815 {
816  //wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnKeyEvent" );
817  int localkey = event.GetKeyCode();
818 
819  // Use only upper char values in comparisons
820  // (the Shift modifier is a separate attribute)
821  if( (localkey >= 'a') && (localkey <= 'z') )
822  localkey += 'A' - 'a';
823 
824  if( m_camera_is_moving )
825  return;
826 
827  if( event.ShiftDown() )
828  localkey |= GR_KB_SHIFT;
829 
830  if( event.ControlDown() )
831  localkey |= GR_KB_CTRL;
832 
833  if( event.AltDown() )
834  localkey |= GR_KB_ALT;
835 
836  if( !SetView3D( localkey ) )
837  event.Skip();
838 }
839 
840 
841 void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent &event )
842 {
843  (void)event;
844 
845  m_mouse_is_moving = false;
846  m_mouse_was_moved = false;
847 
848  Request_refresh();
849 }
850 
851 
853 {
855 }
856 
857 
859 {
860  m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut() , wxTIMER_ONE_SHOT );
861 }
862 
863 
864 void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent &event )
865 {
866  (void)event;
867 
868  //Refresh();
869  //Update();
870 
871  wxPaintEvent redrawEvent;
872  wxPostEvent( this, redrawEvent );
873 }
874 
875 
876 void EDA_3D_CANVAS::Request_refresh( bool aRedrawImmediately )
877 {
878  if( aRedrawImmediately )
879  {
880  // On some systems, just calling Refresh does not work always
881  // (Issue experienced on Win7 MSYS2)
882  //Refresh();
883  //Update();
884 
885  // Using PostEvent will take priority to other events, like
886  // mouse movements, keys, etc.
887  wxPaintEvent redrawEvent;
888  wxPostEvent( this, redrawEvent );
889 
890  // This behaves the same
891  // wxQueueEvent( this,
892  // From wxWidget documentation: "The heap-allocated and
893  // non-NULL event to queue, the function takes ownership of it."
894  // new wxPaintEvent()
895  // );
896  }
897  else
898  {
899  // Schedule a timed redraw
900  m_redraw_trigger_timer.Start( 10 , wxTIMER_ONE_SHOT );
901  }
902 }
903 
904 
905 void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRenderPivot )
906 {
907  wxASSERT( aMovingSpeed > FLT_EPSILON );
908 
909  m_render_pivot = aRenderPivot;
910  m_camera_moving_speed = aMovingSpeed;
911 
913 
914  DisplayStatus();
915  Request_refresh();
916 
917  m_camera_is_moving = true;
918 
920 }
921 
922 
924 {
925  SFVEC3F rayOrigin;
926  SFVEC3F rayDir;
927 
928  // Generate a ray origin and direction based on current mouser position and camera
929  m_settings.CameraGet().MakeRayAtCurrrentMousePosition( rayOrigin, rayDir );
930 
931  RAY mouseRay;
932  mouseRay.Init( rayOrigin, rayDir );
933 
934  float hit_t;
935 
936  // Test it with the board bounding box
937  if( m_settings.GetBBox3DU().Intersect( mouseRay, &hit_t ) )
938  {
941  m_settings.CameraGet().SetLookAtPos_T1( mouseRay.at( hit_t ) );
943 
945  }
946 }
947 
948 
949 bool EDA_3D_CANVAS::SetView3D( int aKeycode )
950 {
951  if( m_camera_is_moving )
952  return false;
953 
954  const float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
955  const float arrow_moving_time_speed = 8.0f;
956  bool handled = false;
957 
958  switch( aKeycode )
959  {
960  case WXK_SPACE:
962  return true;
963 
964  case WXK_LEFT:
967  m_settings.CameraGet().Pan_T1( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
968  request_start_moving_camera( arrow_moving_time_speed, false );
969  return true;
970 
971  case WXK_RIGHT:
974  m_settings.CameraGet().Pan_T1( SFVEC3F( +delta_move, 0.0f, 0.0f ) );
975  request_start_moving_camera( arrow_moving_time_speed, false );
976  return true;
977 
978  case WXK_UP:
981  m_settings.CameraGet().Pan_T1( SFVEC3F( 0.0f, +delta_move, 0.0f ) );
982  request_start_moving_camera( arrow_moving_time_speed, false );
983  return true;
984 
985  case WXK_DOWN:
988  m_settings.CameraGet().Pan_T1( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
989  request_start_moving_camera( arrow_moving_time_speed, false );
990  return true;
991 
992  case WXK_HOME:
997  return true;
998 
999  case WXK_END:
1000  break;
1001 
1002  case WXK_TAB:
1005  m_settings.CameraGet().RotateZ_T1( glm::radians( 45.0f ) );
1007  handled = true;
1008  break;
1009 
1010  case WXK_F1:
1013 
1014  if( m_settings.CameraGet().Zoom_T1( 1.4f ) )
1016 
1017  return true;
1018 
1019  case WXK_F2:
1022 
1023  if( m_settings.CameraGet().Zoom_T1( 1/1.4f ) )
1025 
1026  return true;
1027 
1028  case '+':
1029  case '-':
1030  break;
1031 
1032  case 't':
1033  case 'T':
1036  ReloadRequest();
1037  handled = true;
1038  break;
1039 
1040  case 's':
1041  case 'S':
1044  ReloadRequest();
1045  handled = true;
1046  break;
1047 
1048  case 'v':
1049  case 'V':
1052  ReloadRequest();
1053  handled = true;
1054  break;
1055 
1056  case 'r':
1057  case 'R':
1062  return true;
1063 
1064  case 'X':
1068  m_settings.CameraGet().RotateZ_T1( glm::radians( -90.0f ) );
1069  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1071  return true;
1072 
1073  case GR_KB_SHIFT + 'X':
1077  m_settings.CameraGet().RotateZ_T1( glm::radians( 90.0f ) );
1078  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1080  return true;
1081 
1082  case 'Y':
1086  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1088  return true;
1089 
1090  case GR_KB_SHIFT + 'Y':
1094  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1095  m_settings.CameraGet().RotateZ_T1( glm::radians( -180.0f ) );
1097  return true;
1098 
1099  case 'Z':
1104  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
1105  return true;
1106 
1107  case GR_KB_SHIFT + 'Z':
1111  m_settings.CameraGet().RotateY_T1( glm::radians( 180.0f ) );
1113  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
1114  return true;
1115 
1116  default:
1117  return false;
1118  }
1119 
1120  m_mouse_was_moved = true;
1121 
1123 
1124  DisplayStatus();
1125  Request_refresh();
1126 
1127  return handled;
1128 }
1129 
1130 
1132 {
1133 
1134  switch( m_settings.RenderEngineGet() )
1135  {
1138  break;
1139 
1142  break;
1143 
1144  default:
1145  m_3d_render = NULL;
1146  break;
1147  }
1148 
1149  if( m_3d_render )
1151 
1152  m_mouse_was_moved = false;
1153 
1154  Request_refresh();
1155 }
C3D_RENDER_RAYTRACING * m_3d_render_raytracing
Raytracing render class.
#define GR_KB_ALT
void SetLookAtPos_T1(const SFVEC3F &aLookAtPos)
Definition: ccamera.h:125
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)
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:61
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:535
bool m_mouse_is_moving
true if mouse activity is on progress
CINFO3D_VISU & m_settings
Stores all pre-computed 3D information and visualization settings to render the board.
void ResetXYpos_T1()
Definition: ccamera.cpp:382
unsigned m_strtime_camera_movement
Stores the ticktime when the camera star its 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
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:251
wxStatusBar * m_parentStatusBar
Parent statusbar to report progress.
Class BOARD to handle a board.
wxGLContext * m_glRC
current OpenGL context
void OnCloseWindow(wxCloseEvent &event)
OnCloseWindow - called when the frame is closed.
wxGLCanvas wrapper for HiDPI/Retina support.
#define GR_KB_CTRL
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:52
wxTimer m_editing_timeout_timer
Time timeout will expires after some time sinalizing that the mouse / keyboard movements are over.
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
Definition: ray.h:43
void DisplayStatus()
DisplayStatus - Update the status bar with the position information.
C3D_RENDER_OGL_LEGACY * m_3d_render_ogl_legacy
OpenGL legacy render class.
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:65
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:401
bool Zoom(float aFactor)
Definition: ccamera.cpp:454
void OnLeftDown(wxMouseEvent &event)
float m_camera_moving_speed
1.0f will be 1:1
void RenderEngineSet(RENDER_ENGINE aRenderEngine)
RenderEngineSet.
Definition: cinfo3d_visu.h:228
static GL_CONTEXT_MANAGER & Get()
Function Get returns the GL_CONTEXT_MANAGER instance (singleton).
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
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:210
void RenderRaytracingRequest()
RenderRaytracingRequest - Request to render the current view in Raytracing mode.
void OnKeyEvent(wxKeyEvent &event)
float ZoomGet() const
Definition: ccamera.cpp:490
void OnMiddleDown(wxMouseEvent &event)
bool m_mouse_was_moved
true if there was some type of activity, it will be used to render in preview mode
void OnEraseBackground(wxEraseEvent &event)
void OnMouseWheel(wxMouseEvent &event)
void RenderEngineChanged()
RenderEngineChanged - Notify that the render engine was changed.
Class 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:70
bool m_camera_is_moving
true if camera animation is ongoing
const CBBOX & GetBBox3DU() const
GetBBox3DU - Get the bbox of the pcb board.
Definition: cinfo3d_visu.h:147
virtual void Interpolate(float t)
Interpolate - It will update the matrix to interpolate between T0 and T1 values.
Definition: ccamera.cpp:549
virtual void Drag(const wxPoint &aNewMousePosition)=0
Calculate a new mouse drag position.
EVT_MIDDLE_DOWN(mpWindow::OnMouseMiddleDown) EVT_MOUSEWHEEL(mpWindow
Definition: mathplot.cpp:1713
bool SetCurWindowSize(const wxSize &aSize)
SetCurWindowSize - update the windows size of the camera.
Definition: ccamera.cpp:428
void OnPopUpMenu(wxCommandEvent &event)
#define GR_KB_SHIFT
void OnTimerTimeout_Redraw(wxTimerEvent &event)
bool Zoom_T1(float aFactor)
Definition: ccamera.cpp:473
string & err
Definition: json11.cpp:598
virtual void Pan_T1(const SFVEC3F &aDeltaOffsetInc)=0
void RotateX_T1(float aAngleInRadians)
Definition: ccamera.cpp:517
virtual void Reset_T1()
Definition: ccamera.cpp:92
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Function LockCtx sets a context as current and prevents other canvases from switching it.
bool m_render_pivot
activated the render of pivot while camera moving
RENDER_ENGINE RenderEngineGet() const
RenderEngineGet.
Definition: cinfo3d_visu.h:234
bool m_is_opengl_initialized
Flag to store if opengl was initialized already.
C3D_RENDER_BASE * m_3d_render
The current render in used for this canvas.
void OnMiddleUp(wxMouseEvent &event)
The C3D_RENDER_OGL_LEGACY class render the board using openGL legacy mode.
void GetScreenshot(wxImage &aDstImage)
Request a screenshot and output it to the aDstImage.
virtual bool Redraw(bool aIsMoving, REPORTER *aStatusTextReporter=NULL)=0
Redraw - Ask to redraw the view.
void OnCharHook(wxKeyEvent &event)
const int scale
wxString AddHotkeyName(const wxString &aText, EDA_HOTKEY **aList, int aCommandId, HOTKEY_ACTION_TYPE aShortCutType)
Function AddHotkeyName Add the key name from the Command id value ( m_Idcommand member value)
bool initializeOpenGL()
initializeOpenGL
bool m_opengl_supports_raytracing
void RotateY_T1(float aAngleInRadians)
Definition: ccamera.cpp:523
void MakeRayAtCurrrentMousePosition(SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
MakeRayAtCurrrentMousePosition - Make a ray based on the latest mouse position.
Definition: ccamera.cpp:350
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
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:170
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)
EDA_HOTKEY_CONFIG * GetHotkeyConfig() const
Return a structure containing currently used hotkey mapping.
void OnRightClick(wxMouseEvent &event)
void OnTimerTimeout_Editing(wxTimerEvent &event)
const SFVEC3F & GetCameraPos() const
Definition: ccamera.h:131
void DestroyCtx(wxGLContext *aContext)
Function DestroyCtx destroys a managed OpenGL context.
Some functions to handle hotkeys in KiCad.
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...
EVT_MENU_RANGE(ID_POPUP_3D_VIEW_START, ID_POPUP_3D_VIEW_END, EDA_3D_CANVAS::OnPopUpMenu) EDA_3D_CANVAS
void ReloadRequest()
ReloadRequest - !TODO: this must be reviewed to add flags to improve specific render.
void RotateZ_T1(float aAngleInRadians)
Definition: ccamera.cpp:529
void SetBoard(BOARD *aBoard)
SetBoard - Set current board to be rendered.
Definition: cinfo3d_visu.h:122
wxTimer m_redraw_trigger_timer
This timer will be used to schedule a redraw event.
static const float m_delta_move_step_factor
Step factor to used with cursor on relation to the current zoom.
void render_pivot(float t, float aScale)
render_pivot - render the pivot cursor
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED) override
Function Report is a pure virtual function to override in the derived object.
void SetInterpolateMode(CAMERA_INTERPOLATION aInterpolateMode)
Definition: ccamera.h:198
#define min(a, b)
Definition: auxiliary.h:85
bool ParametersChanged()
Function ParametersChanged.
Definition: ccamera.cpp:567
void Set3DCacheManager(S3D_CACHE *aCachePointer)
Set3DCacheManager - Update the Cache manager pointer.
Definition: cinfo3d_visu.h:82
bool m_render_raytracing_was_requested
Flags that the user requested the current view to be render with raytracing.