]> git.saurik.com Git - wxWidgets.git/blob - samples/opengl/cube/cube.cpp
as after recent change wxID_SEPARATOR is now -2, it is better for idMenuTitle to...
[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 #include "cube.h"
29
30 #ifndef __WXMSW__ // for wxStopWatch, 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 wxWindows 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 wxStopWatch( 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 #if wxUSE_GLCANVAS
166
167 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
168 EVT_SIZE(TestGLCanvas::OnSize)
169 EVT_PAINT(TestGLCanvas::OnPaint)
170 EVT_ERASE_BACKGROUND(TestGLCanvas::OnEraseBackground)
171 EVT_KEY_DOWN( TestGLCanvas::OnKeyDown )
172 EVT_KEY_UP( TestGLCanvas::OnKeyUp )
173 EVT_ENTER_WINDOW( TestGLCanvas::OnEnterWindow )
174 END_EVENT_TABLE()
175
176 unsigned long TestGLCanvas::m_secbase = 0;
177 int TestGLCanvas::m_TimeInitialized = 0;
178 unsigned long TestGLCanvas::m_xsynct;
179 unsigned long TestGLCanvas::m_gsynct;
180
181 TestGLCanvas::TestGLCanvas(wxWindow *parent, wxWindowID id,
182 const wxPoint& pos, const wxSize& size, long style, const wxString& name)
183 : wxGLCanvas(parent, (wxGLCanvas*) NULL, id, pos, size, style, name )
184 {
185 m_init = false;
186 m_gllist = 0;
187 m_rleft = WXK_LEFT;
188 m_rright = WXK_RIGHT;
189 }
190
191 TestGLCanvas::TestGLCanvas(wxWindow *parent, const TestGLCanvas &other,
192 wxWindowID id, const wxPoint& pos, const wxSize& size, long style,
193 const wxString& name )
194 : wxGLCanvas(parent, other.GetContext(), id, pos, size, style, name)
195 {
196 m_init = false;
197 m_gllist = other.m_gllist; // share display list
198 m_rleft = WXK_LEFT;
199 m_rright = WXK_RIGHT;
200 }
201
202 TestGLCanvas::~TestGLCanvas()
203 {
204 }
205
206 void TestGLCanvas::Render()
207 {
208 wxPaintDC dc(this);
209
210 #ifndef __WXMOTIF__
211 if (!GetContext()) return;
212 #endif
213
214 SetCurrent();
215 // Init OpenGL once, but after SetCurrent
216 if (!m_init)
217 {
218 InitGL();
219 m_init = true;
220 }
221
222 glMatrixMode(GL_PROJECTION);
223 glLoadIdentity();
224 glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 1.0f, 3.0f);
225 glMatrixMode(GL_MODELVIEW);
226
227 /* clear color and depth buffers */
228 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
229
230 if( m_gllist == 0 )
231 {
232 m_gllist = glGenLists( 1 );
233 glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
234 /* draw six faces of a cube */
235 glBegin(GL_QUADS);
236 glNormal3f( 0.0f, 0.0f, 1.0f);
237 glVertex3f( 0.5f, 0.5f, 0.5f); glVertex3f(-0.5f, 0.5f, 0.5f);
238 glVertex3f(-0.5f,-0.5f, 0.5f); glVertex3f( 0.5f,-0.5f, 0.5f);
239
240 glNormal3f( 0.0f, 0.0f,-1.0f);
241 glVertex3f(-0.5f,-0.5f,-0.5f); glVertex3f(-0.5f, 0.5f,-0.5f);
242 glVertex3f( 0.5f, 0.5f,-0.5f); glVertex3f( 0.5f,-0.5f,-0.5f);
243
244 glNormal3f( 0.0f, 1.0f, 0.0f);
245 glVertex3f( 0.5f, 0.5f, 0.5f); glVertex3f( 0.5f, 0.5f,-0.5f);
246 glVertex3f(-0.5f, 0.5f,-0.5f); glVertex3f(-0.5f, 0.5f, 0.5f);
247
248 glNormal3f( 0.0f,-1.0f, 0.0f);
249 glVertex3f(-0.5f,-0.5f,-0.5f); glVertex3f( 0.5f,-0.5f,-0.5f);
250 glVertex3f( 0.5f,-0.5f, 0.5f); glVertex3f(-0.5f,-0.5f, 0.5f);
251
252 glNormal3f( 1.0f, 0.0f, 0.0f);
253 glVertex3f( 0.5f, 0.5f, 0.5f); glVertex3f( 0.5f,-0.5f, 0.5f);
254 glVertex3f( 0.5f,-0.5f,-0.5f); glVertex3f( 0.5f, 0.5f,-0.5f);
255
256 glNormal3f(-1.0f, 0.0f, 0.0f);
257 glVertex3f(-0.5f,-0.5f,-0.5f); glVertex3f(-0.5f,-0.5f, 0.5f);
258 glVertex3f(-0.5f, 0.5f, 0.5f); glVertex3f(-0.5f, 0.5f,-0.5f);
259 glEnd();
260
261 glEndList();
262 }
263 else
264 {
265 glCallList(m_gllist);
266 }
267
268 glFlush();
269 SwapBuffers();
270 }
271
272 void TestGLCanvas::OnEnterWindow( wxMouseEvent& WXUNUSED(event) )
273 {
274 SetFocus();
275 }
276
277 void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
278 {
279 Render();
280 }
281
282 void TestGLCanvas::OnSize(wxSizeEvent& event)
283 {
284 // this is also necessary to update the context on some platforms
285 wxGLCanvas::OnSize(event);
286
287 // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...)
288 int w, h;
289 GetClientSize(&w, &h);
290 #ifndef __WXMOTIF__
291 if (GetContext())
292 #endif
293 {
294 SetCurrent();
295 glViewport(0, 0, (GLint) w, (GLint) h);
296 }
297 }
298
299 void TestGLCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
300 {
301 // Do nothing, to avoid flashing.
302 }
303
304 void TestGLCanvas::InitGL()
305 {
306 SetCurrent();
307
308 /* set viewing projection */
309 glMatrixMode(GL_PROJECTION);
310 glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 1.0f, 3.0f);
311
312 /* position viewer */
313 glMatrixMode(GL_MODELVIEW);
314 glTranslatef(0.0f, 0.0f, -2.0f);
315
316 /* position object */
317 glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
318 glRotatef(30.0f, 0.0f, 1.0f, 0.0f);
319
320 glEnable(GL_DEPTH_TEST);
321 glEnable(GL_LIGHTING);
322 glEnable(GL_LIGHT0);
323 }
324
325 GLfloat TestGLCanvas::CalcRotateSpeed( unsigned long acceltime )
326 {
327 GLfloat t,v;
328
329 t = ((GLfloat)acceltime) / 1000.0f;
330
331 if( t < 0.5f )
332 v = t;
333 else if( t < 1.0f )
334 v = t * (2.0f - t);
335 else
336 v = 0.75f;
337
338 return(v);
339 }
340
341 GLfloat TestGLCanvas::CalcRotateAngle( unsigned long lasttime,
342 unsigned long acceltime )
343 {
344 GLfloat t,s1,s2;
345
346 t = ((GLfloat)(acceltime - lasttime)) / 1000.0f;
347 s1 = CalcRotateSpeed( lasttime );
348 s2 = CalcRotateSpeed( acceltime );
349
350 return( t * (s1 + s2) * 135.0f );
351 }
352
353 void TestGLCanvas::Action( long code, unsigned long lasttime,
354 unsigned long acceltime )
355 {
356 GLfloat angle = CalcRotateAngle( lasttime, acceltime );
357
358 if (code == m_rleft)
359 Rotate( angle );
360 else if (code == m_rright)
361 Rotate( -angle );
362 }
363
364 void TestGLCanvas::OnKeyDown( wxKeyEvent& event )
365 {
366 long evkey = event.GetKeyCode();
367 if (evkey == 0) return;
368
369 if (!m_TimeInitialized)
370 {
371 m_TimeInitialized = 1;
372 m_xsynct = event.m_timeStamp;
373 m_gsynct = wxStopWatch(&m_secbase);
374
375 m_Key = evkey;
376 m_StartTime = 0;
377 m_LastTime = 0;
378 m_LastRedraw = 0;
379 }
380
381 unsigned long currTime = event.m_timeStamp - m_xsynct;
382
383 if (evkey != m_Key)
384 {
385 m_Key = evkey;
386 m_LastRedraw = m_StartTime = m_LastTime = currTime;
387 }
388
389 if (currTime >= m_LastRedraw) // Redraw:
390 {
391 Action( m_Key, m_LastTime-m_StartTime, currTime-m_StartTime );
392
393 #if defined(__WXMAC__) && !defined(__DARWIN__)
394 m_LastRedraw = currTime; // wxStopWatch() doesn't work on Mac...
395 #else
396 m_LastRedraw = wxStopWatch(&m_secbase) - m_gsynct;
397 #endif
398 m_LastTime = currTime;
399 }
400
401 event.Skip();
402 }
403
404 void TestGLCanvas::OnKeyUp( wxKeyEvent& event )
405 {
406 m_Key = 0;
407 m_StartTime = 0;
408 m_LastTime = 0;
409 m_LastRedraw = 0;
410
411 event.Skip();
412 }
413
414 void TestGLCanvas::Rotate( GLfloat deg )
415 {
416 SetCurrent();
417
418 glMatrixMode(GL_MODELVIEW);
419 glRotatef((GLfloat)deg, 0.0f, 0.0f, 1.0f);
420 Refresh(false);
421 }
422
423
424 #endif // wxUSE_GLCANVAS
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("wxWindows 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 wxUSE_GLCANVAS
481 if (parentFrame)
482 {
483 frame->m_canvas = new TestGLCanvas( frame, parentFrame->m_canvas,
484 wxID_ANY, wxDefaultPosition, wxDefaultSize );
485 }
486 else
487 {
488 frame->m_canvas = new TestGLCanvas(frame, wxID_ANY,
489 wxDefaultPosition, wxDefaultSize);
490 }
491 #endif
492
493 // Show the frame
494 frame->Show(true);
495
496 return frame;
497 }
498
499 void MyFrame::OnNewWindow( wxCommandEvent& WXUNUSED(event) )
500 {
501 (void) Create(this, true);
502 }
503
504 void MyFrame::OnDefRotateLeftKey( wxCommandEvent& WXUNUSED(event) )
505 {
506 #if wxUSE_GLCANVAS
507 ScanCodeDialog dial( this, wxID_ANY, m_canvas->m_rleft,
508 wxString(_T("Left")), _T("Define key") );
509
510 int result = dial.ShowModal();
511
512 if( result == wxID_OK )
513 m_canvas->m_rleft = dial.GetValue();
514 #endif
515 }
516
517 void MyFrame::OnDefRotateRightKey( wxCommandEvent& WXUNUSED(event) )
518 {
519 #if wxUSE_GLCANVAS
520 ScanCodeDialog dial( this, wxID_ANY, m_canvas->m_rright,
521 wxString(_T("Right")), _T("Define key") );
522
523 int result = dial.ShowModal();
524
525 if( result == wxID_OK )
526 m_canvas->m_rright = dial.GetValue();
527 #endif
528 }
529
530 /*------------------------------------------------------------------
531 Application object ( equivalent to main() )
532 ------------------------------------------------------------------ */
533
534 IMPLEMENT_APP(MyApp)
535
536 bool MyApp::OnInit()
537 {
538 #if wxUSE_LOG
539 wxLog::SetTraceMask(wxTraceMessages);
540 #endif
541
542 // Create the main frame window
543 (void) MyFrame::Create(NULL);
544
545 #if wxUSE_GLCANVAS
546
547 return true;
548
549 #else
550
551 wxMessageBox( _T("This sample has to be compiled with wxUSE_GLCANVAS"),
552 _T("Building error"), wxOK);
553
554 return false;
555
556 #endif
557
558 }