Main MRPT website > C++ reference for MRPT 1.5.6
CMyGLCanvasBase.cpp
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +---------------------------------------------------------------------------+ */
9 
10 #include "gui-precomp.h" // Precompiled headers
11 
12 
14 #include <mrpt/gui/WxSubsystem.h>
15 #include <mrpt/utils/CTicTac.h>
16 
17 #if MRPT_HAS_WXWIDGETS && MRPT_HAS_OPENGL_GLUT
18 
19 using namespace mrpt;
20 using namespace mrpt::utils;
21 using namespace mrpt::gui;
22 using namespace mrpt::opengl;
23 using namespace std;
24 
25 float CMyGLCanvasBase::SENSIBILITY_DEG_PER_PIXEL = 0.1f;
26 
27 #if MRPT_HAS_OPENGL_GLUT
28  #ifdef MRPT_OS_WINDOWS
29  // Windows:
30  #include <windows.h>
31  #endif
32 
33  #ifdef MRPT_OS_APPLE
34  #include <OpenGL/gl.h>
35  #include <OpenGL/glu.h>
36  #include <GLUT/glut.h>
37  #else
38  #include <GL/gl.h>
39  #include <GL/glu.h>
40  #include <GL/glut.h>
41  #ifdef HAVE_FREEGLUT_EXT_H
42  #include <GL/freeglut_ext.h>
43  #endif
44  #endif
45 
46 #endif
47 
48 #if !wxUSE_GLCANVAS
49 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild wxWidgets"
50 #endif
51 
52 /*----------------------------------------------------------------
53  Implementation of Test-GLCanvas
54 -----------------------------------------------------------------*/
55 
56 BEGIN_EVENT_TABLE(CMyGLCanvasBase, wxGLCanvas)
57  EVT_SIZE(CMyGLCanvasBase::OnSize)
58  EVT_PAINT(CMyGLCanvasBase::OnPaint)
59  EVT_ERASE_BACKGROUND(CMyGLCanvasBase::OnEraseBackground)
60  EVT_ENTER_WINDOW( CMyGLCanvasBase::OnEnterWindow )
61  EVT_WINDOW_CREATE( CMyGLCanvasBase::OnWindowCreation )
62 END_EVENT_TABLE()
63 
64 void CMyGLCanvasBase::OnWindowCreation(wxWindowCreateEvent &ev)
65 {
66  if (!m_gl_context) m_gl_context=new wxGLContext(this);
67 }
68 
69 void CMyGLCanvasBase::OnMouseDown(wxMouseEvent& event)
70 {
71  mouseClickX = event.GetX();
72  mouseClickY = event.GetY();
73  mouseClicked = true;
74 }
75 void CMyGLCanvasBase::OnMouseUp(wxMouseEvent& event)
76 {
77  mouseClicked = false;
78 }
79 
80 void CMyGLCanvasBase::OnMouseMove(wxMouseEvent& event)
81 {
82  int X = m_mouseLastX = event.GetX();
83  int Y = m_mouseLastY = event.GetY();
84 
85  // Proxy variables to cache the changes:
86  float cameraPointingX = this->cameraPointingX;
87  float cameraPointingY = this->cameraPointingY;
88  float cameraPointingZ = this->cameraPointingZ;
89  float cameraZoomDistance = this->cameraZoomDistance;
90  float cameraElevationDeg = this->cameraElevationDeg;
91  float cameraAzimuthDeg = this->cameraAzimuthDeg;
92 
93  if (event.LeftIsDown() )
94  {
95  if ( event.ShiftDown() )
96  {
97  // Zoom:
98  cameraZoomDistance *= exp(0.01*(Y - mouseClickY));
99  if (cameraZoomDistance<0.01) cameraZoomDistance = 0.01f;
100 
101  float Az = -0.05*(X - mouseClickX);
102  float D = 0.001*cameraZoomDistance;
103  cameraPointingZ += D*Az;
104  }
105  else
106  if (event.ControlDown())
107  {
108  // Rotate camera pointing direction:
109  const float dis = max(0.01f,(cameraZoomDistance));
110  float eye_x = cameraPointingX + dis * cos(DEG2RAD(cameraAzimuthDeg))*cos(DEG2RAD(cameraElevationDeg));
111  float eye_y = cameraPointingY + dis * sin(DEG2RAD(cameraAzimuthDeg))*cos(DEG2RAD(cameraElevationDeg));
112  float eye_z = cameraPointingZ + dis * sin(DEG2RAD(cameraElevationDeg));
113 
114  float A_AzimuthDeg = -SENSIBILITY_DEG_PER_PIXEL*(X - mouseClickX);
115  float A_ElevationDeg = SENSIBILITY_DEG_PER_PIXEL*(Y - mouseClickY);
116 
117  // Orbit camera:
118  cameraAzimuthDeg += A_AzimuthDeg;
119  cameraElevationDeg += A_ElevationDeg;
120  if (cameraElevationDeg<-90) cameraElevationDeg = -90;
121  if (cameraElevationDeg>90) cameraElevationDeg = 90;
122 
123  // Move cameraPointing pos:
124  cameraPointingX = eye_x - dis * cos(DEG2RAD(cameraAzimuthDeg))*cos(DEG2RAD(cameraElevationDeg));
125  cameraPointingY = eye_y - dis * sin(DEG2RAD(cameraAzimuthDeg))*cos(DEG2RAD(cameraElevationDeg));
126  cameraPointingZ = eye_z - dis * sin(DEG2RAD(cameraElevationDeg));
127  }
128  else
129  {
130  // Orbit camera:
131  cameraAzimuthDeg -= 0.2*(X - mouseClickX);
132  cameraElevationDeg += 0.2*(Y - mouseClickY);
133  if (cameraElevationDeg<-90) cameraElevationDeg = -90;
134  if (cameraElevationDeg>90) cameraElevationDeg = 90;
135  }
136 
137  mouseClickX = X;
138  mouseClickY = Y;
139 
140  // Potential user filter:
141  OnUserManuallyMovesCamera(cameraPointingX, cameraPointingY, cameraPointingZ, cameraZoomDistance, cameraElevationDeg, cameraAzimuthDeg);
142 
143 #if wxCHECK_VERSION(2,9,5)
144  wxTheApp->SafeYieldFor(NULL,wxEVT_CATEGORY_TIMER);
145 #endif
146  Refresh(false);
147 
148  }
149  else
150  if ( event.RightIsDown() )
151  {
152  float Ay = -(X - mouseClickX);
153  float Ax = -(Y - mouseClickY);
154  float D = 0.001*cameraZoomDistance;
155  cameraPointingX += D*(Ax*cos(DEG2RAD(cameraAzimuthDeg)) - Ay*sin(DEG2RAD(cameraAzimuthDeg)));
156  cameraPointingY += D*(Ax*sin(DEG2RAD(cameraAzimuthDeg)) + Ay*cos(DEG2RAD(cameraAzimuthDeg)));
157 
158  mouseClickX = X;
159  mouseClickY = Y;
160 
161  // Potential user filter:
162  OnUserManuallyMovesCamera(cameraPointingX, cameraPointingY, cameraPointingZ, cameraZoomDistance, cameraElevationDeg, cameraAzimuthDeg);
163 
164 #if wxCHECK_VERSION(2,9,5)
165  wxTheApp->SafeYieldFor(NULL,wxEVT_CATEGORY_TIMER);
166 #endif
167  Refresh(false);
168  }
169 
170  // ensure we have the focus so we get keyboard events:
171  this->SetFocus();
172 }
173 
174 void CMyGLCanvasBase::OnMouseWheel(wxMouseEvent& event)
175 {
176  float cameraZoomDistance = this->cameraZoomDistance;
177 
178  cameraZoomDistance *= 1 - 0.03f*(event.GetWheelRotation()/120.0f);
179 
180  // Potential user filter:
181  OnUserManuallyMovesCamera(cameraPointingX, cameraPointingY, cameraPointingZ, cameraZoomDistance, cameraElevationDeg, cameraAzimuthDeg);
182 
183  Refresh(false);
184  // ensure we have the focus so we get keyboard events:
185  this->SetFocus();
186 }
187 
188 static int WX_GL_ATTR_LIST[] = { WX_GL_DOUBLEBUFFER, WX_GL_RGBA, WX_GL_DEPTH_SIZE, 24, 0 };
189 
190 CMyGLCanvasBase::CMyGLCanvasBase(wxWindow *parent, wxWindowID id,const wxPoint& pos, const wxSize& size, long style, const wxString& name) :
191  wxGLCanvas(parent, id, WX_GL_ATTR_LIST, pos, size, style|wxFULL_REPAINT_ON_RESIZE , name ),
192  m_gl_context(NULL),
193  m_init(false),
194  m_mouseLastX(0),m_mouseLastY(0)
195 {
196  m_openGLScene = COpenGLScene::Create();
197 
198  mouseClickX=0;
199  mouseClickY=0;
200  mouseClicked = false;
201 
202  // Initialize variables:
203  cameraPointingX = 0;
204  cameraPointingY = 0;
205  cameraPointingZ = 0;
206 
207  cameraIsProjective = true;
208 
209  useCameraFromScene = false;
210 
211  cameraZoomDistance = 40;
212  cameraFOV = 30;
213  cameraElevationDeg = 45;
214  cameraAzimuthDeg = 45;
215 
216  clearColorR = 0.4f;
217  clearColorG = 0.4f;
218  clearColorB = 0.4f;
219 
220 
221  Connect(wxID_ANY,wxEVT_LEFT_DOWN,(wxObjectEventFunction)&CMyGLCanvasBase::OnMouseDown);
222  Connect(wxID_ANY,wxEVT_RIGHT_DOWN,(wxObjectEventFunction)&CMyGLCanvasBase::OnMouseDown);
223  Connect(wxID_ANY,wxEVT_LEFT_UP,(wxObjectEventFunction)&CMyGLCanvasBase::OnMouseUp);
224  Connect(wxID_ANY,wxEVT_RIGHT_UP,(wxObjectEventFunction)&CMyGLCanvasBase::OnMouseUp);
225  Connect(wxID_ANY,wxEVT_MOTION,(wxObjectEventFunction)&CMyGLCanvasBase::OnMouseMove);
226  Connect(wxID_ANY,wxEVT_MOUSEWHEEL,(wxObjectEventFunction)&CMyGLCanvasBase::OnMouseWheel);
227 
228  Connect(wxID_ANY,wxEVT_CHAR,(wxObjectEventFunction)&CMyGLCanvasBase::OnChar);
229  Connect(wxID_ANY,wxEVT_CHAR_HOOK,(wxObjectEventFunction)&CMyGLCanvasBase::OnChar);
230 
231  Connect(wxEVT_CREATE,(wxObjectEventFunction)&CMyGLCanvasBase::OnWindowCreation);
232 
233  // JL: There seems to be a problem in MSW we don't receive this event, but
234  // in GTK we do and at the right moment to avoid an X server crash.
235 #ifdef _WIN32
236  wxWindowCreateEvent dum;
237  OnWindowCreation(dum);
238 #endif
239 }
240 
241 
242 CMyGLCanvasBase::~CMyGLCanvasBase()
243 {
244  m_openGLScene.clear_unique();
245  delete_safe(m_gl_context);
246 }
247 
248 void CMyGLCanvasBase::OnChar( wxKeyEvent& event )
249 {
250  OnCharCustom(event);
251 }
252 
253 void CMyGLCanvasBase::Render()
254 {
255  CTicTac tictac;
256  double At = 0.1;
257 
258  wxPaintDC dc(this);
259 
260  if (!m_gl_context) { /*cerr << "[CMyGLCanvasBase::Render] No GL Context!" << endl;*/ return; }
261  else SetCurrent(*m_gl_context);
262 
263  // Init OpenGL once, but after SetCurrent
264  if (!m_init)
265  {
266  InitGL();
267  m_init = true;
268  }
269 
270  try
271  {
272  // Call PreRender user code:
273  OnPreRender();
274 
275 
277 
278  // Set static configs:
282 
283 
284  // PART 1a: Set the viewport
285  // --------------------------------------
286  int width, height;
287  GetClientSize(&width, &height);
288  glViewport(
289  0,
290  0,
291  (GLsizei)width,
292  (GLsizei)height);
293 
294  // Set the background color:
295  glClearColor(clearColorR,clearColorG,clearColorB,1.0);
296 
297  if (m_openGLScene)
298  {
299  // Set the camera params in the scene:
300  if (!useCameraFromScene)
301  {
302  COpenGLViewportPtr view= m_openGLScene->getViewport("main");
303  if (!view)
304  {
305  THROW_EXCEPTION("Fatal error: there is no 'main' viewport in the 3D scene!");
306  }
307 
308  mrpt::opengl::CCamera & cam = view->getCamera();
309  cam.setPointingAt( cameraPointingX, cameraPointingY, cameraPointingZ );
310  cam.setZoomDistance(cameraZoomDistance);
311  cam.setAzimuthDegrees( cameraAzimuthDeg );
312  cam.setElevationDegrees(cameraElevationDeg);
313  cam.setProjectiveModel( cameraIsProjective );
314  cam.setProjectiveFOVdeg( cameraFOV );
315  }
316 
317  // PART 2: Set the MODELVIEW matrix
318  // --------------------------------------
320  glLoadIdentity();
321 
322  tictac.Tic();
323 
324  // PART 3: Draw primitives:
325  // --------------------------------------
326  m_openGLScene->render();
327 
328  } // end if "m_openGLScene!=NULL"
329 
330  OnPostRender();
331 
332  // Flush & swap buffers to disply new image:
333  glFlush();
334  SwapBuffers();
335 
336  At = tictac.Tac();
337 
338  glPopAttrib();
339  }
340  catch (std::exception &e)
341  {
342  glPopAttrib();
343  const std::string err_msg = std::string("[CMyGLCanvasBase::Render] Exception!: ") +std::string(e.what());
344  std::cerr << err_msg;
345  OnRenderError( _U(err_msg.c_str()) );
346  }
347  catch (...)
348  {
349  glPopAttrib();
350  std::cerr << "Runtime error!" << std::endl;
351  }
352 
353  OnPostRenderSwapBuffers( At, dc );
354 
355 }
356 
357 void CMyGLCanvasBase::OnEnterWindow( wxMouseEvent& WXUNUSED(event) )
358 {
359  SetFocus();
360 }
361 
362 void CMyGLCanvasBase::OnPaint( wxPaintEvent& WXUNUSED(event) )
363 {
364  Render();
365 }
366 
367 void CMyGLCanvasBase::OnSize(wxSizeEvent& event)
368 {
369  if (!m_parent->IsShown()) return;
370 
371  // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...)
372  int w, h;
373  GetClientSize(&w, &h);
374 
375  if (this->IsShownOnScreen())
376  {
377  if (!m_gl_context) { /*cerr << "[CMyGLCanvasBase::Render] No GL Context!" << endl;*/ return; }
378  else SetCurrent(*m_gl_context);
379 
380  glViewport(0, 0, (GLint) w, (GLint) h);
381  }
382 }
383 
384 void CMyGLCanvasBase::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
385 {
386  // Do nothing, to avoid flashing.
387 }
388 
389 void CMyGLCanvasBase::InitGL()
390 {
391  if (!m_gl_context) { /*cerr << "[CMyGLCanvasBase::Render] No GL Context!" << endl;*/ return; }
392  else SetCurrent(*m_gl_context);
393 
394  static bool GLUT_INIT_DONE = false;
395 
396  if (!GLUT_INIT_DONE)
397  {
398  GLUT_INIT_DONE = true;
399 
400  int argc=1;
401  char *argv[1] = { NULL };
402  glutInit( &argc, argv );
403  }
404 }
405 
406 void CMyGLCanvasBase::setCameraPose(const mrpt::poses::CPose3D &camPose)
407 {
408  THROW_EXCEPTION("todo")
409 }
410 
411 #endif // MRPT_HAS_WXWIDGETS
412 
GLAPI void GLAPIENTRY glFlush(void)
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
Definition: zip.h:16
GLAPI void GLAPIENTRY glMatrixMode(GLenum mode)
GLAPI void GLAPIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
GLAPI void GLAPIENTRY glEnable(GLenum cap)
#define _U(x)
Definition: WxSubsystem.h:470
#define GL_MODELVIEW
Definition: glew.h:606
#define THROW_EXCEPTION(msg)
void setProjectiveModel(bool v=true)
Enable/Disable projective mode (vs. orthogonal)
Definition: CCamera.h:73
STL namespace.
#define GL_DEPTH_TEST
Definition: glew.h:397
GLAPI void GLAPIENTRY glPopAttrib(void)
void Tic()
Starts the stopwatch.
Definition: CTicTac.cpp:77
GLAPI void GLAPIENTRY glLoadIdentity(void)
GLenum GLsizei width
Definition: glext.h:3513
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3962
void setZoomDistance(float z)
Definition: CCamera.h:64
void setAzimuthDegrees(float ang)
Definition: CCamera.h:70
void delete_safe(T *&ptr)
Calls "delete" to free an object only if the pointer is not NULL, then set the pointer to NULL...
Definition: bits.h:196
This class implements a high-performance stopwatch.
Definition: CTicTac.h:24
void setProjectiveFOVdeg(float ang)
Field-of-View in degs, only when projectiveModel=true (default=30 deg).
Definition: CCamera.h:87
double DEG2RAD(const double x)
Degrees to radians.
Definition: bits.h:82
GLsizei const GLchar ** string
Definition: glext.h:3919
#define GL_ALPHA_TEST
Definition: glew.h:422
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
GLAPI void GLAPIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
void setElevationDegrees(float ang)
Definition: CCamera.h:71
GLAPI void GLAPIENTRY glPushAttrib(GLbitfield mask)
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:72
GLuint id
Definition: glext.h:3770
The namespace for 3D scene representation and rendering.
GLuint const GLchar * name
Definition: glext.h:3891
double Tac()
Stops the stopwatch.
Definition: CTicTac.cpp:92
#define GL_ALL_ATTRIB_BITS
Definition: glew.h:267
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
Classes for creating GUI windows for 2D and 3D visualization.
int GLint
Definition: glew.h:205
GLsizeiptr size
Definition: glext.h:3779
A camera: if added to a scene, the viewpoint defined by this camera will be used instead of the camer...
Definition: CCamera.h:31
GLenum GLsizei GLsizei height
Definition: glext.h:3523
#define GL_TEXTURE_2D
Definition: glew.h:6074
int GLsizei
Definition: glew.h:206
void setPointingAt(float x, float y, float z)
Definition: CCamera.h:48



Page generated by Doxygen 1.8.14 for MRPT 1.5.6 Git: 4c65e8431 Tue Apr 24 08:18:17 2018 +0200 at lun oct 28 01:35:26 CET 2019