refresh GL canvas itself, not the frame, when the GL context changes, otherwise it...
[wxWidgets.git] / samples / opengl / cube / cube.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: cube.cpp
3 // Purpose: wxGLCanvas demo program
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin to use new wxGLCanvas API (2007-04-09)
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/wx.h"
29 #endif
30
31 #if !wxUSE_GLCANVAS
32 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
33 #endif
34
35 #include "cube.h"
36
37 #if !defined(__WXMSW__) && !defined(__WXPM__)
38 #include "../../sample.xpm"
39 #endif
40
41 // ============================================================================
42 // implementation
43 // ============================================================================
44
45 // ----------------------------------------------------------------------------
46 // MyApp: the application object
47 // ----------------------------------------------------------------------------
48
49 IMPLEMENT_APP(MyApp)
50
51 bool MyApp::OnInit()
52 {
53 if ( !wxApp::OnInit() )
54 return false;
55
56 // Create the main window
57 new MyFrame();
58
59 return true;
60 }
61
62 int MyApp::OnExit()
63 {
64 delete m_glContext;
65
66 return wxApp::OnExit();
67 }
68
69 void MyApp::SetCurrent(wxGLCanvas *canvas)
70 {
71 wxCHECK_RET( canvas, _T("canvas can't be NULL") );
72
73 if ( !m_glContext )
74 m_glContext = new wxGLContext(canvas);
75
76 m_glContext->SetCurrent(*canvas);
77 }
78
79 // ----------------------------------------------------------------------------
80 // TestGLCanvas
81 // ----------------------------------------------------------------------------
82
83 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
84 EVT_SIZE(TestGLCanvas::OnSize)
85 EVT_PAINT(TestGLCanvas::OnPaint)
86
87 EVT_KEY_DOWN(TestGLCanvas::OnKeyDown)
88 END_EVENT_TABLE()
89
90 static /* const */ int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 };
91
92 TestGLCanvas::TestGLCanvas(wxWindow *parent)
93 : wxGLCanvas(parent, wxID_ANY, attribs)
94 {
95 m_gllist = 0;
96
97 // notice that we can't call InitGL() from here: we must wait until the
98 // window is shown on screen to be able to perform OpenGL calls
99 }
100
101 // this function is called on each repaint so it should be fast
102 void TestGLCanvas::Render()
103 {
104 wxGetApp().SetCurrent(this);
105
106 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
107 glCallList(m_gllist);
108
109 glFlush();
110 SwapBuffers();
111 }
112
113 void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
114 {
115 // initialize if not done yet
116 InitGL();
117
118 wxPaintDC dc(this);
119
120 Render();
121 }
122
123 void TestGLCanvas::OnSize(wxSizeEvent& event)
124 {
125 // don't prevent default processing from taking place
126 event.Skip();
127
128 if ( !IsInitialized() )
129 return;
130
131 // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...)
132 int w, h;
133 GetClientSize(&w, &h);
134
135 wxGetApp().SetCurrent(this);
136 glViewport(0, 0, w, h);
137 }
138
139 void TestGLCanvas::InitGL()
140 {
141 if ( IsInitialized() )
142 return;
143
144 wxGetApp().SetCurrent(this);
145
146 /* set viewing projection */
147 glMatrixMode(GL_PROJECTION);
148 glLoadIdentity();
149 glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 1.0f, 3.0f);
150
151 /* position viewer */
152 glMatrixMode(GL_MODELVIEW);
153 glLoadIdentity();
154 glTranslatef(0.0f, 0.0f, -2.0f);
155
156 /* position object */
157 glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
158 glRotatef(30.0f, 0.0f, 1.0f, 0.0f);
159
160 glEnable(GL_DEPTH_TEST);
161 glEnable(GL_LIGHTING);
162 glEnable(GL_LIGHT0);
163
164 // create the list of commands to draw the cube: then we can just (quickly)
165 // execute it in Render() later
166 m_gllist = glGenLists(1);
167 glNewList(m_gllist, GL_COMPILE);
168
169 /* draw six faces of a cube */
170 glBegin(GL_QUADS);
171 glNormal3f( 0.0f, 0.0f, 1.0f);
172 glVertex3f( 0.5f, 0.5f, 0.5f); glVertex3f(-0.5f, 0.5f, 0.5f);
173 glVertex3f(-0.5f,-0.5f, 0.5f); glVertex3f( 0.5f,-0.5f, 0.5f);
174
175 glNormal3f( 0.0f, 0.0f,-1.0f);
176 glVertex3f(-0.5f,-0.5f,-0.5f); glVertex3f(-0.5f, 0.5f,-0.5f);
177 glVertex3f( 0.5f, 0.5f,-0.5f); glVertex3f( 0.5f,-0.5f,-0.5f);
178
179 glNormal3f( 0.0f, 1.0f, 0.0f);
180 glVertex3f( 0.5f, 0.5f, 0.5f); glVertex3f( 0.5f, 0.5f,-0.5f);
181 glVertex3f(-0.5f, 0.5f,-0.5f); glVertex3f(-0.5f, 0.5f, 0.5f);
182
183 glNormal3f( 0.0f,-1.0f, 0.0f);
184 glVertex3f(-0.5f,-0.5f,-0.5f); glVertex3f( 0.5f,-0.5f,-0.5f);
185 glVertex3f( 0.5f,-0.5f, 0.5f); glVertex3f(-0.5f,-0.5f, 0.5f);
186
187 glNormal3f( 1.0f, 0.0f, 0.0f);
188 glVertex3f( 0.5f, 0.5f, 0.5f); glVertex3f( 0.5f,-0.5f, 0.5f);
189 glVertex3f( 0.5f,-0.5f,-0.5f); glVertex3f( 0.5f, 0.5f,-0.5f);
190
191 glNormal3f(-1.0f, 0.0f, 0.0f);
192 glVertex3f(-0.5f,-0.5f,-0.5f); glVertex3f(-0.5f,-0.5f, 0.5f);
193 glVertex3f(-0.5f, 0.5f, 0.5f); glVertex3f(-0.5f, 0.5f,-0.5f);
194 glEnd();
195
196 glEndList();
197 }
198
199 void TestGLCanvas::OnKeyDown( wxKeyEvent& event )
200 {
201 GLfloat x = 0,
202 y = 0,
203 z = 0;
204
205 bool inverse = false;
206
207 switch ( event.GetKeyCode() )
208 {
209 case WXK_RIGHT:
210 inverse = true;
211 // fall through
212
213 case WXK_LEFT:
214 // rotate around Z axis
215 z = 1;
216 break;
217
218 case WXK_DOWN:
219 inverse = true;
220 // fall through
221
222 case WXK_UP:
223 // rotate around Y axis
224 y = 1;
225 break;
226
227 default:
228 event.Skip();
229 return;
230 }
231
232 float angle = 5;
233 if ( inverse )
234 angle = -angle;
235
236 wxGetApp().SetCurrent(this);
237
238 glMatrixMode(GL_MODELVIEW);
239 glRotatef(angle, x, y, z);
240
241 // refresh all cubes
242 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin();
243 i != wxTopLevelWindows.end();
244 ++i )
245 {
246 MyFrame *frame = (MyFrame *)*i;
247 frame->RefreshCanvas();
248 }
249 }
250
251 // ----------------------------------------------------------------------------
252 // MyFrame: main application window
253 // ----------------------------------------------------------------------------
254
255 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
256 EVT_MENU(wxID_EXIT, MyFrame::OnExit)
257 EVT_MENU(wxID_NEW, MyFrame::OnNewWindow)
258 END_EVENT_TABLE()
259
260 MyFrame::MyFrame()
261 : wxFrame(NULL, wxID_ANY, _T("wxWidgets OpenGL Cube Sample"),
262 wxDefaultPosition, wxSize(400, 300))
263 {
264 m_canvas = new TestGLCanvas(this);
265
266 SetIcon(wxICON(sample));
267
268 // Make a menubar
269 wxMenu *winMenu = new wxMenu;
270 winMenu->Append(wxID_EXIT, _T("&Close"));
271 winMenu->Append(wxID_NEW, _T("&New") );
272 wxMenuBar *menuBar = new wxMenuBar;
273 menuBar->Append(winMenu, _T("&Window"));
274
275 SetMenuBar(menuBar);
276
277 Show();
278 }
279
280 void MyFrame::OnExit( wxCommandEvent& WXUNUSED(event) )
281 {
282 // true is to force the frame to close
283 Close(true);
284 }
285
286 void MyFrame::OnNewWindow( wxCommandEvent& WXUNUSED(event) )
287 {
288 (void) new MyFrame();
289 }
290
291 void MyFrame::RefreshCanvas()
292 {
293 m_canvas->Refresh(false);
294 }