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 
48 
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 )
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  HIDPI_GL_CANVAS( aParent,
94  wxID_ANY,
95  aAttribList,
96  wxDefaultPosition,
97  wxDefaultSize,
98  wxFULL_REPAINT_ON_RESIZE
99  ),
100  m_settings( aSettings )
101 {
102  // Run test cases in debug mode, once.
103 
104  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::EDA_3D_CANVAS" );
105 
106  m_editing_timeout_timer.SetOwner( this );
107  Connect( m_editing_timeout_timer.GetId(),
108  wxEVT_TIMER,
109  wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Editing ),
110  NULL,
111  this );
112 
113  m_redraw_trigger_timer.SetOwner( this );
114  Connect( m_redraw_trigger_timer.GetId(),
115  wxEVT_TIMER,
116  wxTimerEventHandler( EDA_3D_CANVAS::OnTimerTimeout_Redraw ),
117  NULL,
118  this );
119 
120  m_mouse_was_moved = false;
121  m_mouse_is_moving = false;
122  m_camera_is_moving = false;
123  m_render_pivot = false;
124  m_camera_moving_speed = 1.0f;
125 
126  m_strtime_camera_movement = 0;
127 
128  m_is_opengl_initialized = false;
129 
130  m_render_raytracing_was_requested = false;
131  m_opengl_supports_raytracing = false;
132 
133  m_parentStatusBar = NULL;
134  m_glRC = NULL;
135 
136  m_3d_render = NULL;
137 
138  m_3d_render_raytracing = new C3D_RENDER_RAYTRACING( aSettings );
139  m_3d_render_ogl_legacy = new C3D_RENDER_OGL_LEGACY( aSettings );
140 
141  wxASSERT( m_3d_render_raytracing != NULL );
142  wxASSERT( m_3d_render_ogl_legacy != NULL );
143 
144  RenderEngineChanged();
145 
146  wxASSERT( aBoard != NULL );
147  m_settings.SetBoard( aBoard );
148 
149  wxASSERT( a3DCachePointer != NULL );
150  m_settings.Set3DCacheManager( a3DCachePointer );
151 }
152 
153 
155 {
156  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::~EDA_3D_CANVAS" );
157 
158  releaseOpenGL();
159 }
160 
161 
163 {
164  if( m_glRC )
165  {
167 
168  delete m_3d_render_raytracing;
169  m_3d_render_raytracing = NULL;
170 
171  delete m_3d_render_ogl_legacy;
172  m_3d_render_ogl_legacy = NULL;
173 
174  // This is just a copy of a pointer, can safely be set to NULL
175  m_3d_render = NULL;
176 
179  m_glRC = NULL;
180  }
181 }
182 
183 
184 void EDA_3D_CANVAS::OnCloseWindow( wxCloseEvent &event )
185 {
186  releaseOpenGL();
187 
188  event.Skip();
189 }
190 
191 
192 void EDA_3D_CANVAS::OnResize( wxSizeEvent &event )
193 {
194  this->Request_refresh();
195 }
196 
197 
199 {
200  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::initializeOpenGL" );
201 
202  const GLenum err = glewInit();
203 
204  if( GLEW_OK != err )
205  {
206  const wxString msgError = (const char*) glewGetErrorString( err );
207 
208  wxLogMessage( msgError );
209 
210  return false;
211  }
212  else
213  {
214  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::initializeOpenGL Using GLEW version %s",
215  FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
216  }
217 
218  wxString version = FROM_UTF8( (char *) glGetString( GL_VERSION ) );
219 
220  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::%s OpenGL version string %s.",
221  __WXFUNCTION__, version );
222 
223  // Extract OpenGL version from string. This method is used because prior to OpenGL 2,
224  // getting the OpenGL major and minor version as integers didn't exist.
225  wxString tmp;
226 
227  wxStringTokenizer tokenizer( version );
228 
230 
231  if( tokenizer.HasMoreTokens() )
232  {
233  long major = 0;
234  long minor = 0;
235 
236  tmp = tokenizer.GetNextToken();
237 
238  tokenizer.SetString( tmp, wxString( "." ) );
239 
240  if( tokenizer.HasMoreTokens() )
241  tokenizer.GetNextToken().ToLong( &major );
242 
243  if( tokenizer.HasMoreTokens() )
244  tokenizer.GetNextToken().ToLong( &minor );
245 
246  if( major < 2 || ( (major == 2 ) && (minor < 1) ) )
247  {
248  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::%s OpenGL ray tracing not supported.",
249  __WXFUNCTION__ );
250 
251  if( GetParent() )
252  {
253  wxCommandEvent evt( wxEVT_MENU, ID_DISABLE_RAY_TRACING );
254  GetParent()->ProcessWindowEvent( evt );
255  }
256 
258  }
259  }
260 
262 
263  return true;
264 }
265 
266 
267 void EDA_3D_CANVAS::GetScreenshot( wxImage &aDstImage )
268 {
269  OGL_GetScreenshot( aDstImage );
270 }
271 
272 
273 void EDA_3D_CANVAS::ReloadRequest( BOARD *aBoard , S3D_CACHE *aCachePointer )
274 {
275  if( aCachePointer != NULL )
276  m_settings.Set3DCacheManager( aCachePointer );
277 
278  if( aBoard != NULL )
279  m_settings.SetBoard( aBoard );
280 
281  if( m_3d_render )
283 }
284 
285 
287 {
289 
290  if( m_3d_render )
292 
294  //m_mouse_was_moved = true;
295 
296  Request_refresh();
297 }
298 
299 
301 {
302  if( m_parentStatusBar )
303  {
304  wxString msg;
305 
306  msg.Printf( "dx %3.2f", m_settings.CameraGet().GetCameraPos().x );
307  m_parentStatusBar->SetStatusText( msg, 1 );
308 
309  msg.Printf( "dy %3.2f", m_settings.CameraGet().GetCameraPos().y );
310  m_parentStatusBar->SetStatusText( msg, 2 );
311  }
312 }
313 
314 
315 void EDA_3D_CANVAS::OnPaint( wxPaintEvent &event )
316 {
317  // Please have a look at:
318  // https://lists.launchpad.net/kicad-developers/msg25149.html
319  // wxPaintDC( this );
320  // event.Skip( false );
321 
322  // SwapBuffer requires the window to be shown before calling
323  if( !IsShownOnScreen() )
324  {
325  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnPaint !IsShown" );
326  return;
327  }
328 
329  // Because the board to draw is handled by the parent viewer frame,
330  // ensure this parent is still alive. When it is closed before the viewer
331  // frame, a paint event can be generated after the parent is closed,
332  // therefore with invalid board.
333  // This is dependent of the platform.
334  // Especially on OSX, but also on Windows, it frequently happens
335  if( !GetParent()->GetParent()->IsShown() )
336  return; // The parent board editor frame is no more alive
337 
338  wxString err_messages;
339 
340  // !TODO: implement error reporter
341  //WX_STRING_REPORTER errorReporter( &err_messages );
342  STATUS_TEXT_REPORTER activityReporter( m_parentStatusBar, 0 );
343 
344  unsigned strtime = GetRunningMicroSecs();
345 
346  // "Makes the OpenGL state that is represented by the OpenGL rendering
347  // context context current, i.e. it will be used by all subsequent OpenGL calls.
348  // This function may only be called when the window is shown on screen"
349 
350  // Explicitly create a new rendering context instance for this canvas.
351  if( m_glRC == NULL )
353 
355 
356  // Set the OpenGL viewport according to the client size of this canvas.
357  // This is done here rather than in a wxSizeEvent handler because our
358  // OpenGL rendering context (and thus viewport setting) is used with
359  // multiple canvases: If we updated the viewport in the wxSizeEvent
360  // handler, changing the size of one canvas causes a viewport setting that
361  // is wrong when next another canvas is repainted.
362  wxSize clientSize = GetNativePixelSize();
363 
364  const bool windows_size_changed = m_settings.CameraGet().SetCurWindowSize( clientSize );
365 
366  // Initialize openGL if need
367  // /////////////////////////////////////////////////////////////////////////
369  {
370  if( !initializeOpenGL() )
371  {
373 
374  return;
375  }
376  }
377 
378  // Don't attend to ray trace if OpenGL doesn't support it.
380  {
384  }
385 
386  // Check if a raytacing was requested and need to switch to raytracing mode
388  {
389  const bool was_camera_changed = m_settings.CameraGet().ParametersChanged();
390 
391  // It reverts back to OpenGL mode if it was requested a raytracing
392  // render of the current scene. AND the mouse / camera is moving
393  if( ( m_mouse_is_moving ||
395  was_camera_changed ||
396  windows_size_changed ) &&
398  {
401  }
402  }
403 
404  float curtime_delta_s = 0.0f;
405 
406  if( m_camera_is_moving )
407  {
408  const unsigned curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
409  curtime_delta_s = (curtime_delta / 1e6) * m_camera_moving_speed;
410  m_settings.CameraGet().Interpolate( curtime_delta_s );
411 
412  if( curtime_delta_s > 1.0f )
413  {
414  m_render_pivot = false;
415  m_camera_is_moving = false;
416  m_mouse_was_moved = true;
417 
419  DisplayStatus();
420  }
421  else
422  {
423  Request_refresh();
424  }
425  }
426 
427  // It will return true if the render request a new redraw
428  bool requested_redraw = false;
429 
430  if( m_3d_render )
431  {
432  m_3d_render->SetCurWindowSize( clientSize );
433 
434  requested_redraw = m_3d_render->Redraw( m_mouse_was_moved || m_camera_is_moving,
435  &activityReporter );
436  }
437 
438  if( m_render_pivot )
439  {
440  const float scale = glm::min( m_settings.CameraGet().ZoomGet(), 1.0f );
441  render_pivot( curtime_delta_s, scale * scale );
442  }
443 
444  // "Swaps the double-buffer of this window, making the back-buffer the
445  // front-buffer and vice versa, so that the output of the previous OpenGL
446  // commands is displayed on the window."
447  SwapBuffers();
448 
450 
451  if( !activityReporter.HasMessage() )
452  {
454  {
455  // Calculation time in milliseconds
456  const double calculation_time = (double)( GetRunningMicroSecs() - strtime) / 1e3;
457 
458  activityReporter.Report( wxString::Format( _( "Render time %.0f ms ( %.1f fps)" ),
459  calculation_time, 1000.0 / calculation_time ) );
460  }
461  }
462 
463  // This will reset the flag of camera parameters changed
465 
466  if( !err_messages.IsEmpty() )
467  wxLogMessage( err_messages );
468 
469  if( (!m_camera_is_moving) && requested_redraw )
470  {
471  m_mouse_was_moved = false;
472  Request_refresh( false );
473  }
474 }
475 
476 
477 void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent &event )
478 {
479  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnEraseBackground" );
480  // Do nothing, to avoid flashing.
481 }
482 
483 
484 void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent &event )
485 {
486  bool mouseActivity = false;
487 
488  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnMouseWheel" );
489 
490  if( m_camera_is_moving )
491  return;
492 
493  float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
494 
496  delta_move *= (0.01f * event.GetWheelRotation());
497  else
498  if( event.GetWheelRotation() < 0 )
499  delta_move = -delta_move;
500 
501  // mousewheel_panning enabled:
502  // wheel -> pan;
503  // wheel + shift -> horizontal scrolling;
504  // wheel + ctrl -> zooming;
505  // mousewheel_panning disabled:
506  // wheel + shift -> vertical scrolling;
507  // wheel + ctrl -> horizontal scrolling;
508  // wheel -> zooming.
509 
510  if( m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) && !event.ControlDown() )
511  {
512  if( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL || event.ShiftDown() )
513  m_settings.CameraGet().Pan( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
514  else
515  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
516 
517  mouseActivity = true;
518  }
519  else if( event.ShiftDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
520  {
521  m_settings.CameraGet().Pan( SFVEC3F( 0.0f, -delta_move, 0.0f ) );
522  mouseActivity = true;
523  }
524  else if( event.ControlDown() && !m_settings.GetFlag( FL_MOUSEWHEEL_PANNING ) )
525  {
526  m_settings.CameraGet().Pan( SFVEC3F( delta_move, 0.0f, 0.0f ) );
527  mouseActivity = true;
528  }
529  else
530  {
531  mouseActivity = m_settings.CameraGet().Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
532  }
533 
534  // If it results on a camera movement
535  if( mouseActivity )
536  {
537  DisplayStatus();
538  Request_refresh();
539 
540  m_mouse_is_moving = true;
541  m_mouse_was_moved = true;
542 
544  }
545 
546  // Update the cursor current mouse position on the camera
547  m_settings.CameraGet().SetCurMousePosition( event.GetPosition() );
548 }
549 
550 
551 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
552 void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
553 {
554  SetFocus();
555 
556  if( m_camera_is_moving )
557  return;
558 
559  //m_is_moving_mouse = true;
561 
562  float magnification = ( event.GetMagnification() + 1.0f );
563 
564  m_settings.CameraGet().Zoom( magnification );
565 
566  DisplayStatus();
567  Request_refresh();
568 }
569 #endif
570 
571 
572 void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent &event )
573 {
574  //wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::OnMouseMove" ) );
575 
576  if( m_camera_is_moving )
577  return;
578 
580 
581  if( event.Dragging() )
582  {
583  if( event.LeftIsDown() ) // Drag
584  m_settings.CameraGet().Drag( event.GetPosition() );
585  else if( event.MiddleIsDown() ) // Pan
586  m_settings.CameraGet().Pan( event.GetPosition() );
587 
588  m_mouse_is_moving = true;
589  m_mouse_was_moved = true;
590 
591  // orientation has changed, redraw mesh
592  DisplayStatus();
593  Request_refresh();
594  }
595 
596  const wxPoint eventPosition = event.GetPosition();
597  m_settings.CameraGet().SetCurMousePosition( eventPosition );
598 }
599 
600 
601 void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent &event )
602 {
603  SetFocus();
605 }
606 
607 
608 void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent &event )
609 {
610  if( m_camera_is_moving )
611  return;
612 
613  if( m_mouse_is_moving )
614  {
615  m_mouse_is_moving = false;
617  }
618 }
619 
620 
621 void EDA_3D_CANVAS::OnMiddleDown( wxMouseEvent &event )
622 {
623  SetFocus();
625 }
626 
627 
628 void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent &event )
629 {
630  if( m_camera_is_moving )
631  return;
632 
633  if( m_mouse_is_moving )
634  {
635  m_mouse_is_moving = false;
637  }
638  else
639  {
641  }
642 }
643 
644 
645 void EDA_3D_CANVAS::OnRightClick( wxMouseEvent &event )
646 {
647  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnRightClick" );
648 
649  SetFocus();
650 
651  if( m_camera_is_moving )
652  return;
653 
654  wxPoint pos;
655  wxMenu PopUpMenu;
656  wxString msg;
657 
658  pos.x = event.GetX();
659  pos.y = event.GetY();
660 
661  msg = AddHotkeyName( _( "Zoom +" ), GetHotkeyConfig(),
662  ID_POPUP_ZOOMIN );
663  AddMenuItem( &PopUpMenu, ID_POPUP_ZOOMIN,
664  msg, KiBitmap( zoom_in_xpm ) );
665 
666 
667  msg = AddHotkeyName( _( "Zoom -" ), GetHotkeyConfig(),
669  AddMenuItem( &PopUpMenu, ID_POPUP_ZOOMOUT,
670  msg, KiBitmap( zoom_out_xpm ) );
671 
672  PopUpMenu.AppendSeparator();
673 
674  msg = AddHotkeyName( _( "Top View" ), GetHotkeyConfig(),
676  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZPOS,
677  msg, KiBitmap( axis3d_top_xpm ) );
678 
679  msg = AddHotkeyName( _( "Bottom View" ), GetHotkeyConfig(),
681  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZNEG,
682  msg, KiBitmap( axis3d_bottom_xpm ) );
683 
684  PopUpMenu.AppendSeparator();
685 
686  msg = AddHotkeyName( _( "Right View" ), GetHotkeyConfig(),
688  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_XPOS,
689  msg, KiBitmap( axis3d_right_xpm ) );
690 
691  msg = AddHotkeyName( _( "Left View" ), GetHotkeyConfig(),
693  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_XNEG,
694  msg, KiBitmap( axis3d_left_xpm ) );
695 
696  PopUpMenu.AppendSeparator();
697 
698  msg = AddHotkeyName( _( "Front View" ), GetHotkeyConfig(),
700  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_YPOS,
701  msg, KiBitmap( axis3d_front_xpm ) );
702 
703  msg = AddHotkeyName( _( "Back View" ), GetHotkeyConfig(),
705  AddMenuItem( &PopUpMenu, ID_POPUP_VIEW_YNEG,
706  msg, KiBitmap( axis3d_back_xpm ) );
707 
708  PopUpMenu.AppendSeparator();
709 
710  msg = AddHotkeyName( _( "Move Left <-" ), GetHotkeyConfig(),
712  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_LEFT,
713  msg, KiBitmap( left_xpm ) );
714 
715  msg = AddHotkeyName( _( "Move Right ->" ), GetHotkeyConfig(),
717  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_RIGHT,
718  msg, KiBitmap( right_xpm ) );
719 
720  msg = AddHotkeyName( _( "Move Up ^" ), GetHotkeyConfig(),
722  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_UP,
723  msg, KiBitmap( up_xpm ) );
724 
725  msg = AddHotkeyName( _( "Move Down" ), GetHotkeyConfig(),
727  AddMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_DOWN,
728  msg, KiBitmap( down_xpm ) );
729 
730  PopupMenu( &PopUpMenu, pos );
731 }
732 
733 
734 void EDA_3D_CANVAS::OnPopUpMenu( wxCommandEvent &event )
735 {
736  int id = event.GetId();
737 
738  wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnPopUpMenu id:%d", id );
739 
740  int key = 0;
741 
742  switch( id )
743  {
744  case ID_POPUP_ZOOMIN:
745  key = WXK_F1;
746  break;
747 
748  case ID_POPUP_ZOOMOUT:
749  key = WXK_F2;
750  break;
751 
752  case ID_POPUP_VIEW_XPOS:
753  key = 'X';
754  break;
755 
756  case ID_POPUP_VIEW_XNEG:
757  key = GR_KB_SHIFT + 'X';
758  break;
759 
760  case ID_POPUP_VIEW_YPOS:
761  key = 'Y';
762  break;
763 
764  case ID_POPUP_VIEW_YNEG:
765  key = GR_KB_SHIFT + 'Y';
766  break;
767 
768  case ID_POPUP_VIEW_ZPOS:
769  key = 'Z';
770  break;
771 
772  case ID_POPUP_VIEW_ZNEG:
773  key = GR_KB_SHIFT + 'Z';
774  break;
775 
777  key = WXK_LEFT;
778  break;
779 
781  key = WXK_RIGHT;
782  break;
783 
784  case ID_POPUP_MOVE3D_UP:
785  key = WXK_UP;
786  break;
787 
789  key = WXK_DOWN;
790  break;
791 
792  default:
793  return;
794  }
795 
796  SetView3D( key );
797 }
798 
799 
800 void EDA_3D_CANVAS::OnCharHook( wxKeyEvent &event )
801 {
802  //wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnCharHook" );
803  event.Skip();
804 }
805 
806 
807 void EDA_3D_CANVAS::OnKeyEvent( wxKeyEvent& event )
808 {
809  //wxLogTrace( m_logTrace, "EDA_3D_CANVAS::OnKeyEvent" );
810  int localkey = event.GetKeyCode();
811 
812  // Use only upper char values in comparisons
813  // (the Shift modifier is a separate attribute)
814  if( (localkey >= 'a') && (localkey <= 'z') )
815  localkey += 'A' - 'a';
816 
817  if( m_camera_is_moving )
818  return;
819 
820  if( event.ShiftDown() )
821  localkey |= GR_KB_SHIFT;
822 
823  if( event.ControlDown() )
824  localkey |= GR_KB_CTRL;
825 
826  if( event.AltDown() )
827  localkey |= GR_KB_ALT;
828 
829  if( !SetView3D( localkey ) )
830  event.Skip();
831 }
832 
833 
834 void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent &event )
835 {
836  (void)event;
837 
838  m_mouse_is_moving = false;
839  m_mouse_was_moved = false;
840 
841  Request_refresh();
842 }
843 
844 
846 {
848 }
849 
850 
852 {
853  m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut() , wxTIMER_ONE_SHOT );
854 }
855 
856 
857 void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent &event )
858 {
859  (void)event;
860 
861  //Refresh();
862  //Update();
863 
864  wxPaintEvent redrawEvent;
865  wxPostEvent( this, redrawEvent );
866 }
867 
868 
869 void EDA_3D_CANVAS::Request_refresh( bool aRedrawImmediately )
870 {
871  if( aRedrawImmediately )
872  {
873  // On some systems, just calling Refresh does not work always
874  // (Issue experienced on Win7 MSYS2)
875  //Refresh();
876  //Update();
877 
878  // Using PostEvent will take priority to other events, like
879  // mouse movements, keys, etc.
880  wxPaintEvent redrawEvent;
881  wxPostEvent( this, redrawEvent );
882 
883  // This behaves the same
884  // wxQueueEvent( this,
885  // From wxWidget documentation: "The heap-allocated and
886  // non-NULL event to queue, the function takes ownership of it."
887  // new wxPaintEvent()
888  // );
889  }
890  else
891  {
892  // Schedule a timed redraw
893  m_redraw_trigger_timer.Start( 10 , wxTIMER_ONE_SHOT );
894  }
895 }
896 
897 
898 void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRenderPivot )
899 {
900  wxASSERT( aMovingSpeed > FLT_EPSILON );
901 
902  m_render_pivot = aRenderPivot;
903  m_camera_moving_speed = aMovingSpeed;
904 
906 
907  DisplayStatus();
908  Request_refresh();
909 
910  m_camera_is_moving = true;
911 
913 }
914 
915 
917 {
918  SFVEC3F rayOrigin;
919  SFVEC3F rayDir;
920 
921  // Generate a ray origin and direction based on current mouser position and camera
922  m_settings.CameraGet().MakeRayAtCurrrentMousePosition( rayOrigin, rayDir );
923 
924  RAY mouseRay;
925  mouseRay.Init( rayOrigin, rayDir );
926 
927  float hit_t;
928 
929  // Test it with the board bounding box
930  if( m_settings.GetBBox3DU().Intersect( mouseRay, &hit_t ) )
931  {
934  m_settings.CameraGet().SetLookAtPos_T1( mouseRay.at( hit_t ) );
936 
938  }
939 }
940 
941 
942 bool EDA_3D_CANVAS::SetView3D( int aKeycode )
943 {
944  if( m_camera_is_moving )
945  return false;
946 
947  const float delta_move = m_delta_move_step_factor * m_settings.CameraGet().ZoomGet();
948  const float arrow_moving_time_speed = 8.0f;
949  bool handled = false;
950 
951  switch( aKeycode )
952  {
953  case WXK_SPACE:
955  return true;
956 
957  case WXK_LEFT:
960  m_settings.CameraGet().Pan_T1( SFVEC3F( -delta_move, 0.0f, 0.0f ) );
961  request_start_moving_camera( arrow_moving_time_speed, false );
962  return true;
963 
964  case WXK_RIGHT:
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_UP:
974  m_settings.CameraGet().Pan_T1( SFVEC3F( 0.0f, +delta_move, 0.0f ) );
975  request_start_moving_camera( arrow_moving_time_speed, false );
976  return true;
977 
978  case WXK_DOWN:
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_HOME:
990  return true;
991 
992  case WXK_END:
993  break;
994 
995  case WXK_TAB:
998  m_settings.CameraGet().RotateZ_T1( glm::radians( 45.0f ) );
1000  handled = true;
1001  break;
1002 
1003  case WXK_F1:
1006 
1007  if( m_settings.CameraGet().Zoom_T1( 1.4f ) )
1009 
1010  return true;
1011 
1012  case WXK_F2:
1015 
1016  if( m_settings.CameraGet().Zoom_T1( 1/1.4f ) )
1018 
1019  return true;
1020 
1021  case '+':
1022  case '-':
1023  break;
1024 
1025  case 't':
1026  case 'T':
1029  ReloadRequest();
1030  handled = true;
1031  break;
1032 
1033  case 's':
1034  case 'S':
1037  ReloadRequest();
1038  handled = true;
1039  break;
1040 
1041  case 'v':
1042  case 'V':
1045  ReloadRequest();
1046  handled = true;
1047  break;
1048 
1049  case 'r':
1050  case 'R':
1055  return true;
1056 
1057  case 'X':
1061  m_settings.CameraGet().RotateZ_T1( glm::radians( -90.0f ) );
1062  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1064  return true;
1065 
1066  case GR_KB_SHIFT + 'X':
1070  m_settings.CameraGet().RotateZ_T1( glm::radians( 90.0f ) );
1071  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1073  return true;
1074 
1075  case 'Y':
1079  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1081  return true;
1082 
1083  case GR_KB_SHIFT + 'Y':
1087  m_settings.CameraGet().RotateX_T1( glm::radians( -90.0f ) );
1088  m_settings.CameraGet().RotateZ_T1( glm::radians( -180.0f ) );
1090  return true;
1091 
1092  case 'Z':
1097  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
1098  return true;
1099 
1100  case GR_KB_SHIFT + 'Z':
1104  m_settings.CameraGet().RotateY_T1( glm::radians( 180.0f ) );
1106  glm::min( glm::max( m_settings.CameraGet().ZoomGet(), 0.5f ), 1.125f ) );
1107  return true;
1108 
1109  default:
1110  return false;
1111  }
1112 
1113  m_mouse_was_moved = true;
1114 
1116 
1117  DisplayStatus();
1118  Request_refresh();
1119 
1120  return handled;
1121 }
1122 
1123 
1125 {
1126 
1127  switch( m_settings.RenderEngineGet() )
1128  {
1131  break;
1132 
1135  break;
1136 
1137  default:
1138  m_3d_render = NULL;
1139  break;
1140  }
1141 
1142  if( m_3d_render )
1144 
1145  m_mouse_was_moved = false;
1146 
1147  Request_refresh();
1148 }
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: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
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:1751
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:171
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.