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