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