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-2017 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 
32 #include "../common_ogl/openGL_includes.h"
33 #include "../common_ogl/ogl_utils.h"
34 #include "eda_3d_canvas.h"
35 #include "../3d_viewer_id.h"
36 #include "../3d_rendering/3d_render_raytracing/c3d_render_raytracing.h"
37 #include "../3d_viewer/eda_3d_viewer.h"
38 #include "../3d_rendering/test_cases.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 <hotkeys_basic.h>
45 #include <menus_helpers.h>
46 
48 
49 
56 const wxChar * EDA_3D_CANVAS::m_logTrace = wxT( "KI_TRACE_EDA_3D_CANVAS" );
57 
59 
60 
61 BEGIN_EVENT_TABLE( EDA_3D_CANVAS, wxGLCanvas )
62  EVT_PAINT( EDA_3D_CANVAS::OnPaint )
63  EVT_CHAR( EDA_3D_CANVAS::OnKeyEvent )
64  EVT_CHAR_HOOK( EDA_3D_CANVAS::OnCharHook )
65 
66  // mouse events
67  EVT_LEFT_DOWN( EDA_3D_CANVAS::OnLeftDown )
68  EVT_LEFT_UP( EDA_3D_CANVAS::OnLeftUp )
69  EVT_MIDDLE_UP( EDA_3D_CANVAS::OnMiddleUp )
70  EVT_MIDDLE_DOWN( EDA_3D_CANVAS::OnMiddleDown)
71  EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightClick )
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 )
82  ID_POPUP_3D_VIEW_END, EDA_3D_CANVAS::OnPopUpMenu )
83 
84  EVT_CLOSE( EDA_3D_CANVAS::OnCloseWindow )
85  EVT_SIZE( EDA_3D_CANVAS::OnResize )
86 END_EVENT_TABLE()
87 
88 
89 EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow *aParent,
90  const int *aAttribList,
91  BOARD *aBoard,
92  CINFO3D_VISU &aSettings , S3D_CACHE *a3DCachePointer ) :
93 
94  HIDPI_GL_CANVAS( aParent,
95  wxID_ANY,
96  aAttribList,
97  wxDefaultPosition,
98  wxDefaultSize,
99  wxFULL_REPAINT_ON_RESIZE
100  ),
101  m_settings( aSettings )
102 {
103  // Run test cases in debug mode, once.
104  //DBG( Run_3d_viewer_test_cases() );
105 
106  wxLogTrace( m_logTrace, wxT( "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 
134  m_parentStatusBar = NULL;
135  m_glRC = NULL;
136 
137  m_3d_render = NULL;
138 
139  m_3d_render_raytracing = new C3D_RENDER_RAYTRACING( aSettings );
140  m_3d_render_ogl_legacy = new C3D_RENDER_OGL_LEGACY( aSettings );
141 
142  wxASSERT( m_3d_render_raytracing != NULL );
143  wxASSERT( m_3d_render_ogl_legacy != NULL );
144 
145  RenderEngineChanged();
146 
147  wxASSERT( aBoard != NULL );
148  m_settings.SetBoard( aBoard );
149 
150  wxASSERT( a3DCachePointer != NULL );
151  m_settings.Set3DCacheManager( a3DCachePointer );
152 }
153 
154 
156 {
157  wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::~EDA_3D_CANVAS" ) );
158 
159  releaseOpenGL();
160 }
161 
162 
164 {
165  if( m_glRC )
166  {
168 
169  delete m_3d_render_raytracing;
170  m_3d_render_raytracing = NULL;
171 
172  delete m_3d_render_ogl_legacy;
173  m_3d_render_ogl_legacy = NULL;
174 
175  // This is just a copy of a pointer, can safelly be set to NULL
176  m_3d_render = NULL;
177 
180  m_glRC = NULL;
181  }
182 }
183 
184 
185 void EDA_3D_CANVAS::OnCloseWindow( wxCloseEvent &event )
186 {
187  releaseOpenGL();
188 
189  event.Skip();
190 }
191 
192 void EDA_3D_CANVAS::OnResize( wxSizeEvent &event )
193 {
194  this->Request_refresh();
195 }
196 
198 {
199  wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::initializeOpenGL" ) );
200 
201  const GLenum err = glewInit();
202 
203  if( GLEW_OK != err )
204  {
205  const wxString msgError = (const char*) glewGetErrorString( err );
206 
207  wxLogMessage( msgError );
208 
209  return false;
210  }
211  else
212  {
213  wxLogTrace( m_logTrace,
214  wxString( wxT( "EDA_3D_CANVAS::initializeOpenGL Using GLEW " ) ) +
215  FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
216  }
217 
219 
220  return true;
221 }
222 
223 
224 void EDA_3D_CANVAS::GetScreenshot( wxImage &aDstImage )
225 {
226  OGL_GetScreenshot( aDstImage );
227 }
228 
229 
230 void EDA_3D_CANVAS::ReloadRequest( BOARD *aBoard , S3D_CACHE *aCachePointer )
231 {
232  if( aCachePointer != NULL )
233  m_settings.Set3DCacheManager( aCachePointer );
234 
235  if( aBoard != NULL )
236  m_settings.SetBoard( aBoard );
237 
238  if( m_3d_render )
240 }
241 
242 
244 {
246 
247  if( m_3d_render )
249 
251  //m_mouse_was_moved = true;
252 
253  Request_refresh();
254 }
255 
256 
258 {
259  if( m_parentStatusBar )
260  {
261  wxString msg;
262 
263  msg.Printf( wxT( "dx %3.2f" ), m_settings.CameraGet().GetCameraPos().x );
264  m_parentStatusBar->SetStatusText( msg, 1 );
265 
266  msg.Printf( wxT( "dy %3.2f" ), m_settings.CameraGet().GetCameraPos().y );
267  m_parentStatusBar->SetStatusText( msg, 2 );
268 
269  //msg.Printf( _( "Zoom: %3.1f" ), 50 * m_settings.CameraGet().ZoomGet() );
270  //m_parentStatusBar->SetStatusText( msg, 3 );
271  }
272 }
273 
274 
275 void EDA_3D_CANVAS::OnPaint( wxPaintEvent &event )
276 {
277  // Please have a look at:
278  // https://lists.launchpad.net/kicad-developers/msg25149.html
279  // wxPaintDC( this );
280  // event.Skip( false );
281 
282  // SwapBuffer requires the window to be shown before calling
283  if( !IsShownOnScreen() )
284  {
285  wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnPaint !IsShown" ) );
286  return;
287  }
288 
289  // Because the board to draw is handled by the parent viewer frame,
290  // ensure this parent is still alive. When it is closed before the viewer
291  // frame, a paint event can be generated after the parent is closed,
292  // therefore with invalid board.
293  // This is dependant of the platform.
294  // Especially on OSX, but also on Windows, it frequently happens
295  if( !GetParent()->GetParent()->IsShown() )
296  return; // The parent board editor frame is no more alive
297 
298  wxString err_messages;
299 
300  // !TODO: implement error reporter
301  //WX_STRING_REPORTER errorReporter( &err_messages );
302  STATUS_TEXT_REPORTER activityReporter( m_parentStatusBar, 0 );
303 
304 
305  unsigned strtime = GetRunningMicroSecs();
306 
307  // "Makes the OpenGL state that is represented by the OpenGL rendering
308  // context context current, i.e. it will be used by all subsequent OpenGL calls.
309  // This function may only be called when the window is shown on screen"
310 
311  // Explicitly create a new rendering context instance for this canvas.
312  if( m_glRC == NULL )
314 
316 
317  // Set the OpenGL viewport according to the client size of this canvas.
318  // This is done here rather than in a wxSizeEvent handler because our
319  // OpenGL rendering context (and thus viewport setting) is used with
320  // multiple canvases: If we updated the viewport in the wxSizeEvent
321  // handler, changing the size of one canvas causes a viewport setting that
322  // is wrong when next another canvas is repainted.
323  wxSize clientSize = GetClientSize();
324 
325  const bool windows_size_changed = m_settings.CameraGet().SetCurWindowSize( clientSize );
326 
327 
328  // Initialize openGL if need
329  // /////////////////////////////////////////////////////////////////////////
331  {
332  if( !initializeOpenGL() )
333  {
335 
336  return;
337  }
338  }
339 
340 
341  // Check if a raytacing was requented and need to switch to raytracing mode
343  {
344  const bool was_camera_changed = m_settings.CameraGet().ParametersChanged();
345 
346  // It reverts back to OpenGL mode if it was requested a raytracing
347  // render of the current scene. AND the mouse / camera is moving
348  if( ( m_mouse_is_moving ||
350  was_camera_changed ||
351  windows_size_changed ) &&
353  {
356  }
357  }
358 
359 
360  float curtime_delta_s = 0.0f;
361 
362  if( m_camera_is_moving )
363  {
364  const unsigned curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
365  curtime_delta_s = (curtime_delta / 1e6) * m_camera_moving_speed;
366  m_settings.CameraGet().Interpolate( curtime_delta_s );
367 
368  if( curtime_delta_s > 1.0f )
369  {
370  m_render_pivot = false;
371  m_camera_is_moving = false;
372  m_mouse_was_moved = true;
373 
375  DisplayStatus();
376  }
377  else
378  {
379  Request_refresh();
380  }
381  }
382 
383 
384  // It will return true if the render request a new redraw
385  bool requested_redraw = false;
386 
387  if( m_3d_render )
388  {
389  m_3d_render->SetCurWindowSize( clientSize );
390 
391  requested_redraw = m_3d_render->Redraw( m_mouse_was_moved || m_camera_is_moving,
392  &activityReporter );
393  }
394 
395  if( m_render_pivot )
396  {
397  const float scale = glm::min( m_settings.CameraGet().ZoomGet(), 1.0f );
398  render_pivot( curtime_delta_s, scale * scale );
399  }
400 
401  // "Swaps the double-buffer of this window, making the back-buffer the
402  // front-buffer and vice versa, so that the output of the previous OpenGL
403  // commands is displayed on the window."
404  SwapBuffers();
405 
407 
408  if( !activityReporter.HasMessage() )
409  {
411  {
412  // Calculation time in miliseconds
413  const double calculation_time = (double)( GetRunningMicroSecs() - strtime) / 1e3;
414 
415  activityReporter.Report( wxString::Format( _( "Render time %.0f ms ( %.1f fps)" ),
416  calculation_time, 1000.0 / calculation_time ) );
417  }
418  }
419 
420  // This will reset the flag of camera parameters changed
422 
423  if( !err_messages.IsEmpty() )
424  wxLogMessage( err_messages );
425 
426  if( (!m_camera_is_moving) && requested_redraw )
427  {
428  m_mouse_was_moved = false;
429  Request_refresh( false );
430  }
431 }
432 
433 
434 void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent &event )
435 {
436  wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnEraseBackground" ) );
437  // Do nothing, to avoid flashing.
438 }
439 
440 
441 void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent &event )
442 {
443  bool mouseActivity = false;
444 
445  wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnMouseWheel" ) );
446 
447  if( m_camera_is_moving )
448  return;
449 
450  float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
451 
453  delta_move *= (0.01f * event.GetWheelRotation());
454  else
455  if( event.GetWheelRotation() < 0 )
456  delta_move = -delta_move;
457 
458  // mousewheel_panning enabled:
459  // wheel -> pan;
460  // wheel + shift -> horizontal scrolling;
461  // wheel + ctrl -> zooming;
462  // mousewheel_panning disabled:
463  // wheel + shift -> vertical scrolling;
464  // wheel + ctrl -> horizontal scrolling;
465  // wheel -> zooming.
466 
467  if( m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) && !event.ControlDown() )
468  {
469  if( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL || event.ShiftDown() )
470  m_settings.CameraGet().Pan( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
471  else
472  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
473 
474  mouseActivity = true;
475  }
476  else if( event.ShiftDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
477  {
478  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
479  mouseActivity = true;
480  }
481  else if( event.ControlDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
482  {
483  m_settings.CameraGet().Pan( SFVEC3F( delta_move, 0.0f, 0.0f ) );
484  mouseActivity = true;
485  }
486  else
487  {
488  mouseActivity = m_settings.CameraGet().Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
489  }
490 
491  // If it results on a camera movement
492  if( mouseActivity )
493  {
494  DisplayStatus();
495  Request_refresh();
496 
497  m_mouse_is_moving = true;
498  m_mouse_was_moved = true;
499 
501  }
502 
503  // Update the cursor current mouse position on the camera
504  m_settings.CameraGet().SetCurMousePosition( event.GetPosition() );
505 }
506 
507 
508 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
509 void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
510 {
511  SetFocus();
512 
513  if( m_camera_is_moving )
514  return;
515 
516  //m_is_moving_mouse = true;
518 
519  float magnification = ( event.GetMagnification() + 1.0f );
520 
521  m_settings.CameraGet().Zoom( magnification );
522 
523  DisplayStatus();
524  Request_refresh();
525 }
526 #endif
527 
528 
529 void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent &event )
530 {
531  //wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnMouseMove" ) );
532 
533  if( m_camera_is_moving )
534  return;
535 
537 
538  if( event.Dragging() )
539  {
540  if( event.LeftIsDown() ) // Drag
541  m_settings.CameraGet().Drag( event.GetPosition() );
542  else if( event.MiddleIsDown() ) // Pan
543  m_settings.CameraGet().Pan( event.GetPosition() );
544 
545  m_mouse_is_moving = true;
546  m_mouse_was_moved = true;
547 
548  // orientation has changed, redraw mesh
549  DisplayStatus();
550  Request_refresh();
551  }
552 
553  const wxPoint eventPosition = event.GetPosition();
554  m_settings.CameraGet().SetCurMousePosition( eventPosition );
555 }
556 
557 
558 void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent &event )
559 {
560  SetFocus();
562 }
563 
564 
565 void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent &event )
566 {
567  if( m_camera_is_moving )
568  return;
569 
570  if( m_mouse_is_moving )
571  {
572  m_mouse_is_moving = false;
574  }
575 }
576 
577 
578 void EDA_3D_CANVAS::OnMiddleDown( wxMouseEvent &event )
579 {
580  SetFocus();
582 }
583 
584 
585 void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent &event )
586 {
587  if( m_camera_is_moving )
588  return;
589 
590  if( m_mouse_is_moving )
591  {
592  m_mouse_is_moving = false;
594  }
595  else
596  {
598  }
599 }
600 
601 
602 void EDA_3D_CANVAS::OnRightClick( wxMouseEvent &event )
603 {
604  wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnRightClick" ) );
605 
606  SetFocus();
607 
608  if( m_camera_is_moving )
609  return;
610 
611  wxPoint pos;
612  wxMenu PopUpMenu;
613  wxString msg;
614 
615  pos.x = event.GetX();
616  pos.y = event.GetY();
617 
618  msg = AddHotkeyName( _( "Zoom +" ), g_3DViewer_Hokeys_Descr,
619  ID_POPUP_ZOOMIN );
620  AddMenuItem( &PopUpMenu, ID_POPUP_ZOOMIN,
621  msg, KiBitmap( zoom_in_xpm ) );
622 
623 
624  msg = AddHotkeyName( _( "Zoom -" ), g_3DViewer_Hokeys_Descr,
626  AddMenuItem( &PopUpMenu, ID_POPUP_ZOOMOUT,
627  msg, KiBitmap( zoom_out_xpm ) );
628 
629  PopUpMenu.AppendSeparator();
630 
631  msg = AddHotkeyName( _( "Top View" ), g_3DViewer_Hokeys_Descr,
633  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZPOS,
634  msg, KiBitmap( axis3d_top_xpm ) );
635 
636  msg = AddHotkeyName( _( "Bottom View" ), g_3DViewer_Hokeys_Descr,
638  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZNEG,
639  msg, KiBitmap( axis3d_bottom_xpm ) );
640 
641  PopUpMenu.AppendSeparator();
642 
643  msg = AddHotkeyName( _( "Right View" ), g_3DViewer_Hokeys_Descr,
645  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_XPOS,
646  msg, KiBitmap( axis3d_right_xpm ) );
647 
648  msg = AddHotkeyName( _( "Left View" ), g_3DViewer_Hokeys_Descr,
650  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_XNEG,
651  msg, KiBitmap( axis3d_left_xpm ) );
652 
653  PopUpMenu.AppendSeparator();
654 
655  msg = AddHotkeyName( _( "Front View" ), g_3DViewer_Hokeys_Descr,
657  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_YPOS,
658  msg, KiBitmap( axis3d_front_xpm ) );
659 
660  msg = AddHotkeyName( _( "Back View" ), g_3DViewer_Hokeys_Descr,
662  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_YNEG,
663  msg, KiBitmap( axis3d_back_xpm ) );
664 
665  PopUpMenu.AppendSeparator();
666 
667  msg = AddHotkeyName( _( "Move Left <-" ), g_3DViewer_Hokeys_Descr,
669  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_LEFT,
670  msg, KiBitmap( left_xpm ) );
671 
672  msg = AddHotkeyName( _( "Move Right ->" ), g_3DViewer_Hokeys_Descr,
674  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_RIGHT,
675  msg, KiBitmap( right_xpm ) );
676 
677  msg = AddHotkeyName( _( "Move Up ^" ), g_3DViewer_Hokeys_Descr,
679  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_UP,
680  msg, KiBitmap( up_xpm ) );
681 
682  msg = AddHotkeyName( _( "Move Down" ), g_3DViewer_Hokeys_Descr,
684  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_DOWN,
685  msg, KiBitmap( down_xpm ) );
686 
687  PopupMenu( &PopUpMenu, pos );
688 }
689 
690 
691 void EDA_3D_CANVAS::OnPopUpMenu( wxCommandEvent &event )
692 {
693  int id = event.GetId();
694 
695  wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnPopUpMenu id:%d" ), id );
696 
697  int key = 0;
698 
699  switch( id )
700  {
701  case ID_POPUP_ZOOMIN:
702  key = WXK_F1;
703  break;
704 
705  case ID_POPUP_ZOOMOUT:
706  key = WXK_F2;
707  break;
708 
709  case ID_POPUP_VIEW_XPOS:
710  key = 'X';
711  break;
712 
713  case ID_POPUP_VIEW_XNEG:
714  key = GR_KB_SHIFT + 'X';
715  break;
716 
717  case ID_POPUP_VIEW_YPOS:
718  key = 'Y';
719  break;
720 
721  case ID_POPUP_VIEW_YNEG:
722  key = GR_KB_SHIFT + 'Y';
723  break;
724 
725  case ID_POPUP_VIEW_ZPOS:
726  key = 'Z';
727  break;
728 
729  case ID_POPUP_VIEW_ZNEG:
730  key = GR_KB_SHIFT + 'Z';
731  break;
732 
734  key = WXK_LEFT;
735  break;
736 
738  key = WXK_RIGHT;
739  break;
740 
741  case ID_POPUP_MOVE3D_UP:
742  key = WXK_UP;
743  break;
744 
746  key = WXK_DOWN;
747  break;
748 
749  default:
750  return;
751  }
752 
753  SetView3D( key );
754 }
755 
756 
757 void EDA_3D_CANVAS::OnCharHook( wxKeyEvent &event )
758 {
759  //wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnCharHook" ) );
760  event.Skip();
761 }
762 
763 
764 void EDA_3D_CANVAS::OnKeyEvent( wxKeyEvent& event )
765 {
766  //wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnKeyEvent" ) );
767  int localkey = event.GetKeyCode();
768 
769  // Use only upper char values in comparisons
770  // (the Shift modifier is a separate attribute)
771  if( (localkey >= 'a') && (localkey <= 'z') )
772  localkey += 'A' - 'a';
773 
774  if( m_camera_is_moving )
775  return;
776 
777  if( event.ShiftDown() )
778  localkey |= GR_KB_SHIFT;
779 
780  if( event.ControlDown() )
781  localkey |= GR_KB_CTRL;
782 
783  if( event.AltDown() )
784  localkey |= GR_KB_ALT;
785 
786  if( !SetView3D( localkey ) )
787  event.Skip();
788 }
789 
790 
791 void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent &event )
792 {
793  (void)event;
794 
795  m_mouse_is_moving = false;
796  m_mouse_was_moved = false;
797 
798  Request_refresh();
799 }
800 
801 
803 {
805 }
806 
807 
809 {
810  m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut() , wxTIMER_ONE_SHOT );
811 }
812 
813 
814 void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent &event )
815 {
816  (void)event;
817 
818  //Refresh();
819  //Update();
820 
821  wxPaintEvent redrawEvent;
822  wxPostEvent( this, redrawEvent );
823 }
824 
825 
826 void EDA_3D_CANVAS::Request_refresh( bool aRedrawImmediately )
827 {
828  if( aRedrawImmediately )
829  {
830  // On some systems, just calling Refresh does not work always
831  // (Issue experienced on Win7 MSYS2)
832  //Refresh();
833  //Update();
834 
835  // Using PostEvent will take priority to other events, like
836  // mouse movements, keys, etc.
837  wxPaintEvent redrawEvent;
838  wxPostEvent( this, redrawEvent );
839 
840  // This behaves the same
841  // wxQueueEvent( this,
842  // From wxWidget documentation: "The heap-allocated and
843  // non-NULL event to queue, the function takes ownership of it."
844  // new wxPaintEvent()
845  // );
846  }
847  else
848  {
849  // Schedule a timed redraw
850  m_redraw_trigger_timer.Start( 10 , wxTIMER_ONE_SHOT );
851  }
852 }
853 
854 
855 void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRenderPivot )
856 {
857  wxASSERT( aMovingSpeed > FLT_EPSILON );
858 
859  m_render_pivot = aRenderPivot;
860  m_camera_moving_speed = aMovingSpeed;
861 
863 
864  DisplayStatus();
865  Request_refresh();
866 
867  m_camera_is_moving = true;
868 
870 }
871 
872 
874 {
875  SFVEC3F rayOrigin;
876  SFVEC3F rayDir;
877 
878  // Generate a ray origin and direction based on current mouser position and camera
879  m_settings.CameraGet().MakeRayAtCurrrentMousePosition( rayOrigin, rayDir );
880 
881  RAY mouseRay;
882  mouseRay.Init( rayOrigin, rayDir );
883 
884  float hit_t;
885 
886  // Test it with the board bounding box
887  if( m_settings.GetBBox3DU().Intersect( mouseRay, &hit_t ) )
888  {
891  m_settings.CameraGet().SetLookAtPos_T1( mouseRay.at( hit_t ) );
893 
895  }
896 }
897 
898 
899 bool EDA_3D_CANVAS::SetView3D( int aKeycode )
900 {
901  if( m_camera_is_moving )
902  return false;
903 
904  const float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
905  const float arrow_moving_time_speed = 8.0f;
906  bool handled = false;
907 
908  switch( aKeycode )
909  {
910  case WXK_SPACE:
912  return true;
913 
914  case WXK_LEFT:
917  m_settings.CameraGet().Pan_T1( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
918  request_start_moving_camera( arrow_moving_time_speed, false );
919  return true;
920 
921  case WXK_RIGHT:
924  m_settings.CameraGet().Pan_T1( SFVEC3F( +delta_move, 0.0f, 0.0f ) );
925  request_start_moving_camera( arrow_moving_time_speed, false );
926  return true;
927 
928  case WXK_UP:
931  m_settings.CameraGet().Pan_T1( SFVEC3F( 0.0f, +delta_move, 0.0f ) );
932  request_start_moving_camera( arrow_moving_time_speed, false );
933  return true;
934 
935  case WXK_DOWN:
938  m_settings.CameraGet().Pan_T1( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
939  request_start_moving_camera( arrow_moving_time_speed, false );
940  return true;
941 
942  case WXK_HOME:
947  return true;
948 
949  case WXK_END:
950  break;
951 
952  case WXK_TAB:
955  m_settings.CameraGet().RotateZ_T1( glm::radians( 45.0f ) );
957  handled = true;
958  break;
959 
960  case WXK_F1:
963 
964  if( m_settings.CameraGet().Zoom_T1( 1.4f ) )
966 
967  return true;
968 
969  case WXK_F2:
972 
973  if( m_settings.CameraGet().Zoom_T1( 1/1.4f ) )
975 
976  return true;
977 
978  case '+':
979  case '-':
980  break;
981 
982  case 't':
983  case 'T':
986  ReloadRequest();
987  handled = true;
988  break;
989 
990  case 's':
991  case 'S':
994  ReloadRequest();
995  handled = true;
996  break;
997 
998  case 'v':
999  case 'V':
1002  ReloadRequest();
1003  handled = true;
1004  break;
1005 
1006  case 'r':
1007  case 'R':
1012  return true;
1013 
1014  case 'X':
1018  m_settings.CameraGet().RotateZ_T1( glm::radians( -90.0f ) );
1019  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1021  return true;
1022 
1023  case GR_KB_SHIFT + 'X':
1027  m_settings.CameraGet().RotateZ_T1( glm::radians( 90.0f ) );
1028  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1030  return true;
1031 
1032  case 'Y':
1036  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1038  return true;
1039 
1040  case GR_KB_SHIFT + 'Y':
1044  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1045  m_settings.CameraGet().RotateZ_T1( glm::radians( -180.0f ) );
1047  return true;
1048 
1049  case 'Z':
1054  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
1055  return true;
1056 
1057  case GR_KB_SHIFT + 'Z':
1061  m_settings.CameraGet().RotateY_T1( glm::radians( 180.0f ) );
1063  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
1064  return true;
1065 
1066  default:
1067  return false;
1068  }
1069 
1070  m_mouse_was_moved = true;
1071 
1073 
1074  DisplayStatus();
1075  Request_refresh();
1076 
1077  return handled;
1078 }
1079 
1080 
1082 {
1083 
1084  switch( m_settings.RenderEngineGet() )
1085  {
1088  break;
1089 
1092  break;
1093 
1094  default:
1095  m_3d_render = NULL;
1096  break;
1097  }
1098 
1099  if( m_3d_render )
1101 
1102  m_mouse_was_moved = false;
1103 
1104  Request_refresh();
1105 }
C3D_RENDER_RAYTRACING * m_3d_render_raytracing
Raytracing render class.
#define GR_KB_ALT
void SetLookAtPos_T1(const SFVEC3F &aLookAtPos)
Definition: ccamera.h:125
void OGL_GetScreenshot(wxImage &aDstImage)
OGL_GetScreenshot - got the pixel data of current OpenGL image.
Definition: ogl_utils.cpp:35
float ZoomGet() const
Definition: ccamera.cpp:490
void OnMouseMove(wxMouseEvent &event)
Structure EDA_HOTKEY_CONFIG contains the information required to save hot key information to a config...
Definition: hotkeys_basic.h:94
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:53
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:223
wxStatusBar * m_parentStatusBar
Parent statusbar to report progress.
Class BOARD to handle a board.
wxGLContext * m_glRC
current OpenGL context
SFVEC3F at(float t) const
Definition: ray.h:65
void OnCloseWindow(wxCloseEvent &event)
OnCloseWindow - called when the frame is closed.
wxGLCanvas wrapper for HiDPI/Retina support.
#define GR_KB_CTRL
Class EDA_3D_CANVAS Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:53
wxTimer m_editing_timeout_timer
Time timeout will expires after some time sinalizing that the mouse / keyboard movements are over...
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.
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
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
void RenderRaytracingRequest()
RenderRaytracingRequest - Request to render the current view in Raytracing mode.
void OnKeyEvent(wxKeyEvent &event)
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 ...
virtual wxSize GetClientSize() const
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
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:1751
const SFVEC3F & GetCameraPos() const
Definition: ccamera.h:131
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
bool Intersect(const RAY &aRay, float *t) const
Function Intersect.
Definition: cbbox_ray.cpp:46
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
RENDER_ENGINE RenderEngineGet() const
RenderEngineGet.
Definition: cinfo3d_visu.h:234
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
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.
bool GetFlag(DISPLAY3D_FLG aFlag) const
GetFlag - get a configuration status of a flag.
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
void MakeRayAtCurrrentMousePosition(SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
MakeRayAtCurrrentMousePosition - Make a ray based on the latest mouse position.
Definition: ccamera.cpp:350
void RotateY_T1(float aAngleInRadians)
Definition: ccamera.cpp:523
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
CCAMERA & CameraGet() const
CameraGet - get current camera in use.
Definition: cinfo3d_visu.h:210
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)
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
void OnRightClick(wxMouseEvent &event)
void OnTimerTimeout_Editing(wxTimerEvent &event)
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...
struct EDA_HOTKEY_CONFIG g_3DViewer_Hokeys_Descr[]
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
const CBBOX & GetBBox3DU() const
GetBBox3DU - Get the bbox of the pcb board.
Definition: cinfo3d_visu.h:147
bool m_render_raytracing_was_requested
Flags that the user requested the current view to be render with raytracing.