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