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: cube.cpp 35650 2005-09-23 12:56:45Z MR $ 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 ----------------------------------------------------------*/ 49class ScanCodeCtrl : public wxTextCtrl 50{ 51public: 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 62private: 63 64 // Any class wishing to process wxWidgets events must use this macro 65 DECLARE_EVENT_TABLE() 66}; 67 68BEGIN_EVENT_TABLE( ScanCodeCtrl, wxTextCtrl ) 69 EVT_CHAR( ScanCodeCtrl::OnChar ) 70 EVT_KEY_DOWN( ScanCodeCtrl::OnKeyDown ) 71END_EVENT_TABLE() 72 73ScanCodeCtrl::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 80void 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 89class ScanCodeDialog : public wxDialog 90{ 91public: 92 ScanCodeDialog( wxWindow* parent, wxWindowID id, const int code, 93 const wxString &descr, const wxString& title ); 94 int GetValue(); 95 96private: 97 98 ScanCodeCtrl *m_ScanCode; 99 wxTextCtrl *m_Description; 100}; 101 102ScanCodeDialog::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 121int 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-----------------------------------------------------------------------*/ 134unsigned 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 165BEGIN_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 ) 172END_EVENT_TABLE() 173 174unsigned long TestGLCanvas::m_secbase = 0; 175int TestGLCanvas::m_TimeInitialized = 0; 176unsigned long TestGLCanvas::m_xsynct; 177unsigned long TestGLCanvas::m_gsynct; 178 179TestGLCanvas::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 189TestGLCanvas::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 200TestGLCanvas::~TestGLCanvas() 201{ 202} 203 204void 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 270void TestGLCanvas::OnEnterWindow( wxMouseEvent& WXUNUSED(event) ) 271{ 272 SetFocus(); 273} 274 275void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) ) 276{ 277 Render(); 278} 279 280void 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 297void TestGLCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) 298{ 299 // Do nothing, to avoid flashing. 300} 301 302void 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 323GLfloat 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 339GLfloat 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 351void 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 362void 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 402void 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 412void 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 426BEGIN_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) 431END_EVENT_TABLE() 432 433// My frame constructor 434MyFrame::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 443void 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 489void MyFrame::OnNewWindow( wxCommandEvent& WXUNUSED(event) ) 490{ 491 (void) Create(this, true); 492} 493 494void 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 505void 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 520IMPLEMENT_APP(MyApp) 521 522bool MyApp::OnInit() 523{ 524 // Create the main frame window 525 (void) MyFrame::Create(NULL); 526 527 return true; 528} 529