Moved wxGLCanvas to more normal positions
[wxWidgets.git] / samples / opengl / cube / cube.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: cube.cpp
3 // Purpose: wxGLCanvas demo program
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #pragma interface
15 #endif
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27
28 #include "wx/log.h"
29
30 #include "cube.h"
31
32 #ifndef __WXMSW__ // for wxStopWatch, see remark below
33 #include <sys/time.h>
34 #include <sys/unistd.h>
35 #else
36 #include <sys/timeb.h>
37 #endif
38
39 #define ID_NEW_WINDOW 10000
40 #define ID_DEF_ROTATE_LEFT_KEY 10001
41 #define ID_DEF_ROTATE_RIGHT_KEY 10002
42
43 /*----------------------------------------------------------
44 Control to get a keycode
45 ----------------------------------------------------------*/
46 class ScanCodeCtrl : public wxTextCtrl
47 {
48 public:
49 ScanCodeCtrl( wxWindow* parent, wxWindowID id, int code,
50 const wxPoint& pos, const wxSize& size );
51 void OnChar( wxKeyEvent& event ) { } /* do nothing */
52 void OnKeyDown(wxKeyEvent& event);
53 private:
54 // any class wishing to process wxWindows events must use this macro
55 DECLARE_EVENT_TABLE()
56 };
57 BEGIN_EVENT_TABLE( ScanCodeCtrl, wxTextCtrl )
58 EVT_CHAR( ScanCodeCtrl::OnChar )
59 EVT_KEY_DOWN( ScanCodeCtrl::OnKeyDown )
60 END_EVENT_TABLE()
61
62 ScanCodeCtrl::ScanCodeCtrl( wxWindow* parent, wxWindowID id, int code,
63 const wxPoint& pos, const wxSize& size )
64 : wxTextCtrl( parent, id, "", pos, size )
65 { wxString buf;
66 buf.Printf( "0x%04x", code );
67 SetValue( buf );
68 }
69
70 void ScanCodeCtrl::OnKeyDown( wxKeyEvent& event )
71 { wxString buf;
72 buf.Printf( "0x%04x", event.KeyCode() );
73 SetValue( buf );
74 }
75
76 /*------------------------------------------------------------------
77 Dialog for defining a keypress
78 -------------------------------------------------------------------*/
79
80 class ScanCodeDialog : public wxDialog
81 {
82 public:
83 ScanCodeDialog( wxWindow* parent, wxWindowID id, const int code,
84 const wxString &descr, const wxString& title );
85 int GetValue();
86 private:
87 ScanCodeCtrl *m_ScanCode;
88 wxTextCtrl *m_Description;
89 };
90
91 ScanCodeDialog::ScanCodeDialog( wxWindow* parent, wxWindowID id,
92 const int code, const wxString &descr, const wxString& title )
93 : wxDialog( parent, id, title, wxPoint(-1, -1), wxSize(96*2,76*2) )
94 {
95 new wxStaticText( this, -1, "Scancode", wxPoint(4*2,3*2),
96 wxSize(31*2,12*2) );
97 m_ScanCode = new ScanCodeCtrl( this, -1, code, wxPoint(37*2,6*2),
98 wxSize(53*2,14*2) );
99
100 new wxStaticText( this, -1, "Description", wxPoint(4*2,24*2),
101 wxSize(32*2,12*2) );
102 m_Description = new wxTextCtrl( this, -1, descr, wxPoint(37*2,27*2),
103 wxSize(53*2,14*2) );
104
105 new wxButton( this, wxID_OK, "Ok", wxPoint(20*2,50*2), wxSize(20*2,13*2) );
106 new wxButton( this, wxID_CANCEL, "Cancel", wxPoint(44*2,50*2),
107 wxSize(25*2,13*2) );
108 }
109
110 int ScanCodeDialog::GetValue()
111 {
112 int code;
113 wxString buf = m_ScanCode->GetValue();
114 sscanf( buf.c_str(), "%i", &code );
115 return( code );
116 }
117
118 /*----------------------------------------------------------------------
119 Utility function to get the elapsed time (in msec) since a given point
120 in time (in sec) (because current version of wxGetElapsedTime doesn´t
121 works right with glibc-2.1 and linux, at least for me)
122 -----------------------------------------------------------------------*/
123 unsigned long wxStopWatch( unsigned long *sec_base )
124 {
125 unsigned long secs,msec;
126
127 #ifndef __WXMSW__ // think every unice has gettimeofday
128 struct timeval tv;
129 gettimeofday( &tv, (struct timezone *)NULL );
130 secs = tv.tv_sec;
131 msec = tv.tv_usec/1000;
132 #else
133 struct timeb tb;
134
135 ftime( &tb );
136
137 secs = tb.time;
138
139 msec = tb.millitm;
140
141 #endif
142
143 if( *sec_base == 0 )
144 *sec_base = secs;
145
146 return( (secs-*sec_base)*1000 + msec );
147 }
148
149 /*----------------------------------------------------------------
150 Implementation of Test-GLCanvas
151 -----------------------------------------------------------------*/
152
153 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
154 EVT_SIZE(TestGLCanvas::OnSize)
155 EVT_PAINT(TestGLCanvas::OnPaint)
156 EVT_ERASE_BACKGROUND(TestGLCanvas::OnEraseBackground)
157 EVT_KEY_DOWN( TestGLCanvas::OnKeyDown )
158 EVT_KEY_UP( TestGLCanvas::OnKeyUp )
159 EVT_ENTER_WINDOW( TestGLCanvas::OnEnterWindow )
160 END_EVENT_TABLE()
161
162 unsigned long TestGLCanvas::m_secbase = 0;
163 int TestGLCanvas::m_TimeInitialized = 0;
164 unsigned long TestGLCanvas::m_xsynct;
165 unsigned long TestGLCanvas::m_gsynct;
166
167 TestGLCanvas::TestGLCanvas(wxWindow *parent, wxWindowID id,
168 const wxPoint& pos, const wxSize& size, long style, const wxString& name):
169 wxGLCanvas(parent, (wxGLCanvas*) NULL, id, pos, size, style, name )
170 {
171 m_init = FALSE;
172 m_gllist = 0;
173 m_rleft = WXK_LEFT;
174 m_rright = WXK_RIGHT;
175 }
176
177 TestGLCanvas::TestGLCanvas(wxWindow *parent, const TestGLCanvas &other,
178 wxWindowID id, const wxPoint& pos, const wxSize& size, long style,
179 const wxString& name ) :
180 wxGLCanvas(parent, other.GetContext(), id, pos, size, style, name )
181 {
182 m_init = FALSE;
183 m_gllist = other.m_gllist; /* share display list */
184 m_rleft = WXK_LEFT;
185 m_rright = WXK_RIGHT;
186 }
187
188 TestGLCanvas::~TestGLCanvas()
189 {
190 }
191
192 void TestGLCanvas::Render()
193 {
194 wxPaintDC dc(this);
195
196 #ifndef __WXMOTIF__
197 if (!GetContext()) return;
198 #endif
199
200 SetCurrent();
201 /* init OpenGL once, but after SetCurrent */
202 if (!m_init)
203 {
204 InitGL();
205 m_init = TRUE;
206 }
207
208 /* clear color and depth buffers */
209 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
210
211 if( m_gllist == 0 )
212 {
213 m_gllist = glGenLists( 1 );
214 glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
215 /* draw six faces of a cube */
216 glBegin(GL_QUADS);
217 glNormal3f( 0.0F, 0.0F, 1.0F);
218 glVertex3f( 0.5F, 0.5F, 0.5F); glVertex3f(-0.5F, 0.5F, 0.5F);
219 glVertex3f(-0.5F,-0.5F, 0.5F); glVertex3f( 0.5F,-0.5F, 0.5F);
220
221 glNormal3f( 0.0F, 0.0F,-1.0F);
222 glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f(-0.5F, 0.5F,-0.5F);
223 glVertex3f( 0.5F, 0.5F,-0.5F); glVertex3f( 0.5F,-0.5F,-0.5F);
224
225 glNormal3f( 0.0F, 1.0F, 0.0F);
226 glVertex3f( 0.5F, 0.5F, 0.5F); glVertex3f( 0.5F, 0.5F,-0.5F);
227 glVertex3f(-0.5F, 0.5F,-0.5F); glVertex3f(-0.5F, 0.5F, 0.5F);
228
229 glNormal3f( 0.0F,-1.0F, 0.0F);
230 glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f( 0.5F,-0.5F,-0.5F);
231 glVertex3f( 0.5F,-0.5F, 0.5F); glVertex3f(-0.5F,-0.5F, 0.5F);
232
233 glNormal3f( 1.0F, 0.0F, 0.0F);
234 glVertex3f( 0.5F, 0.5F, 0.5F); glVertex3f( 0.5F,-0.5F, 0.5F);
235 glVertex3f( 0.5F,-0.5F,-0.5F); glVertex3f( 0.5F, 0.5F,-0.5F);
236
237 glNormal3f(-1.0F, 0.0F, 0.0F);
238 glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f(-0.5F,-0.5F, 0.5F);
239 glVertex3f(-0.5F, 0.5F, 0.5F); glVertex3f(-0.5F, 0.5F,-0.5F);
240 glEnd();
241
242 glEndList();
243 }
244 else
245 glCallList( m_gllist );
246
247 glFlush();
248 SwapBuffers();
249 }
250
251 void TestGLCanvas::OnEnterWindow( wxMouseEvent& event )
252 {
253 SetFocus();
254 }
255
256 void TestGLCanvas::OnPaint( wxPaintEvent& event )
257 {
258 Render();
259 }
260
261 void TestGLCanvas::OnSize(wxSizeEvent& event)
262 {
263 int width, height;
264 GetClientSize(& width, & height);
265
266 #ifndef __WXMOTIF__
267 if (GetContext())
268 #endif
269 {
270 SetCurrent();
271 glViewport(0, 0, width, height);
272 }
273 }
274
275 void TestGLCanvas::OnEraseBackground(wxEraseEvent& event)
276 {
277 // Do nothing, to avoid flashing.
278 }
279
280 void TestGLCanvas::InitGL()
281 {
282 SetCurrent();
283
284 /* set viewing projection */
285 glMatrixMode(GL_PROJECTION);
286 glFrustum(-0.5F, 0.5F, -0.5F, 0.5F, 1.0F, 3.0F);
287
288 /* position viewer */
289 glMatrixMode(GL_MODELVIEW);
290 glTranslatef(0.0F, 0.0F, -2.0F);
291
292 /* position object */
293 glRotatef(30.0F, 1.0F, 0.0F, 0.0F);
294 glRotatef(30.0F, 0.0F, 1.0F, 0.0F);
295
296 glEnable(GL_DEPTH_TEST);
297 glEnable(GL_LIGHTING);
298 glEnable(GL_LIGHT0);
299 }
300
301 GLfloat TestGLCanvas::CalcRotateSpeed( unsigned long acceltime )
302 {
303 GLfloat t,v;
304
305 t = ((GLfloat)acceltime) / 1000.0f;
306
307 if( t < 0.5f )
308 v = t;
309 else if( t < 1.0f )
310 v = t * (2.0f - t);
311 else
312 v = 0.75f;
313
314 return(v);
315 }
316
317 GLfloat TestGLCanvas::CalcRotateAngle( unsigned long lasttime,
318 unsigned long acceltime )
319 {
320 GLfloat t,s1,s2;
321
322 t = ((GLfloat)(acceltime - lasttime)) / 1000.0f;
323 s1 = CalcRotateSpeed( lasttime );
324 s2 = CalcRotateSpeed( acceltime );
325
326 return( t * (s1 + s2) * 135.0f );
327 }
328
329 void TestGLCanvas::Action( long code, unsigned long lasttime,
330 unsigned long acceltime )
331 {
332 GLfloat angle = CalcRotateAngle( lasttime, acceltime );
333
334 if (code == m_rleft)
335 Rotate( angle );
336 else if (code == m_rright)
337 Rotate( -angle );
338 }
339
340 void TestGLCanvas::OnKeyDown( wxKeyEvent& event )
341 {
342 long evkey = event.KeyCode();
343 if (evkey == 0) return;
344
345 if (!m_TimeInitialized)
346 {
347 m_TimeInitialized = 1;
348 m_xsynct = event.m_timeStamp;
349 m_gsynct = wxStopWatch(&m_secbase);
350
351 m_Key = evkey;
352 m_StartTime = 0;
353 m_LastTime = 0;
354 m_LastRedraw = 0;
355 }
356
357 unsigned long currTime = event.m_timeStamp - m_xsynct;
358
359 if (evkey != m_Key)
360 {
361 m_Key = evkey;
362 m_LastRedraw = m_StartTime = m_LastTime = currTime;
363 }
364
365 if (currTime >= m_LastRedraw) // Redraw:
366 {
367 Action( m_Key, m_LastTime-m_StartTime, currTime-m_StartTime );
368
369 m_LastRedraw = wxStopWatch(&m_secbase) - m_gsynct;
370 m_LastTime = currTime;
371 }
372
373 event.Skip();
374 }
375
376 void TestGLCanvas::OnKeyUp( wxKeyEvent& event )
377 {
378 m_Key = 0;
379 m_StartTime = 0;
380 m_LastTime = 0;
381 m_LastRedraw = 0;
382
383 event.Skip();
384 }
385
386 void TestGLCanvas::Rotate( GLfloat deg )
387 {
388 SetCurrent();
389
390 glMatrixMode(GL_MODELVIEW);
391 glRotatef((GLfloat)deg, 0.0F, 0.0F, 1.0F);
392 Refresh(FALSE);
393 }
394
395
396 /* -----------------------------------------------------------------------
397 Main Window
398 -------------------------------------------------------------------------*/
399
400 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
401 EVT_MENU(wxID_EXIT, MyFrame::OnExit)
402 EVT_MENU( ID_NEW_WINDOW, MyFrame::OnNewWindow)
403 EVT_MENU( ID_DEF_ROTATE_LEFT_KEY, MyFrame::OnDefRotateLeftKey)
404 EVT_MENU( ID_DEF_ROTATE_RIGHT_KEY, MyFrame::OnDefRotateRightKey)
405 END_EVENT_TABLE()
406
407 // My frame constructor
408 MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
409 const wxSize& size, long style)
410 : wxFrame(frame, -1, title, pos, size, style)
411 {
412 m_canvas = NULL;
413 }
414
415 // Intercept menu commands
416 void MyFrame::OnExit(wxCommandEvent& event)
417 {
418 Destroy();
419 }
420
421 void MyFrame::OnNewWindow()
422 {
423 MyFrame *frame = new MyFrame(NULL, "Cube OpenGL Demo Clone",
424 wxPoint(50, 50), wxSize(400, 300));
425 // Give it an icon
426 #ifdef wx_msw
427 frame->SetIcon(wxIcon("mondrian"));
428 #endif
429
430 // Make a menubar
431 wxMenu *winMenu = new wxMenu;
432
433 winMenu->Append(wxID_EXIT, "&Close");
434 winMenu->Append(ID_NEW_WINDOW, "&New" );
435 wxMenuBar *menuBar = new wxMenuBar;
436 menuBar->Append(winMenu, "&Window");
437
438 winMenu = new wxMenu;
439 winMenu->Append(ID_DEF_ROTATE_LEFT_KEY, "Rotate &left");
440 winMenu->Append(ID_DEF_ROTATE_RIGHT_KEY, "Rotate &right");
441 menuBar->Append(winMenu, "&Key");
442
443 frame->SetMenuBar(menuBar);
444
445 frame->m_canvas = new TestGLCanvas( frame, *m_canvas, -1,
446 wxPoint(0, 0), wxSize(200, 200) );
447
448 // Show the frame
449 frame->Show(TRUE);
450 }
451
452 void MyFrame::OnDefRotateLeftKey()
453 {
454 ScanCodeDialog dial( this, -1, m_canvas->m_rleft,
455 wxString("Left"), "Define key" );
456 int result = dial.ShowModal();
457 if( result == wxID_OK )
458 m_canvas->m_rleft = dial.GetValue();
459 }
460 void MyFrame::OnDefRotateRightKey()
461 {
462 ScanCodeDialog dial( this, -1, m_canvas->m_rright,
463 wxString("Right"), "Define key" );
464 int result = dial.ShowModal();
465 if( result == wxID_OK )
466 m_canvas->m_rright = dial.GetValue();
467 }
468
469 /*------------------------------------------------------------------
470 Application object ( equivalent to main() )
471 ------------------------------------------------------------------ */
472
473 IMPLEMENT_APP(MyApp)
474
475 bool MyApp::OnInit(void)
476 {
477 wxLog::SetTraceMask(wxTraceMessages);
478
479 // Create the main frame window
480 MyFrame *frame = new MyFrame(NULL, "Cube OpenGL Demo", wxPoint(50, 50),
481 wxSize(400, 300));
482 // Give it an icon
483 #ifdef wx_msw
484 frame->SetIcon(wxIcon("mondrian"));
485 #endif
486
487 // Make a menubar
488 wxMenu *winMenu = new wxMenu;
489
490 winMenu->Append(wxID_EXIT, "&Close");
491 winMenu->Append(ID_NEW_WINDOW, "&New" );
492 wxMenuBar *menuBar = new wxMenuBar;
493 menuBar->Append(winMenu, "&Window");
494
495 winMenu = new wxMenu;
496 winMenu->Append(ID_DEF_ROTATE_LEFT_KEY, "Rotate &left");
497 winMenu->Append(ID_DEF_ROTATE_RIGHT_KEY, "Rotate &right");
498 menuBar->Append(winMenu, "&Key");
499
500 frame->SetMenuBar(menuBar);
501
502 frame->m_canvas = new TestGLCanvas(frame, -1, wxPoint(0, 0), wxSize(200, 200));
503
504 // Show the frame
505 frame->Show(TRUE);
506
507 return TRUE;
508 }