added back SetCurrent() call accidentally removed in one of recent commits
[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 // helper functions
43 // ----------------------------------------------------------------------------
44
45 static void CheckGLError()
46 {
47 GLenum errLast = GL_NO_ERROR;
48
49 for ( ;; )
50 {
51 GLenum err = glGetError();
52 if ( err == GL_NO_ERROR )
53 return;
54
55 // normally the error is reset by the call to glGetError() but if
56 // glGetError() itself returns an error, we risk looping forever here
57 // so check that we get a different error than the last time
58 if ( err == errLast )
59 {
60 wxLogError(_T("OpenGL error state couldn't be reset."));
61 return;
62 }
63
64 errLast = err;
65
66 wxLogError(_T("OpenGL error %d"), err);
67 }
68 }
69
70 // function to draw the texture for cube faces
71 static wxImage DrawDice(int size, unsigned num)
72 {
73 wxASSERT_MSG( num >= 1 && num <= 6, _T("invalid dice index") );
74
75 const int dot = size/16; // radius of a single dot
76 const int gap = 5*size/32; // gap between dots
77
78 wxBitmap bmp(size, size);
79 wxMemoryDC dc;
80 dc.SelectObject(bmp);
81 dc.SetBackground(*wxWHITE_BRUSH);
82 dc.Clear();
83 dc.SetBrush(*wxBLACK_BRUSH);
84
85 // the upper left and lower right points
86 if ( num != 1 )
87 {
88 dc.DrawCircle(gap + dot, gap + dot, dot);
89 dc.DrawCircle(size - gap - dot, size - gap - dot, dot);
90 }
91
92 // draw the central point for odd dices
93 if ( num % 2 )
94 {
95 dc.DrawCircle(size/2, size/2, dot);
96 }
97
98 // the upper right and lower left points
99 if ( num > 3 )
100 {
101 dc.DrawCircle(size - gap - dot, gap + dot, dot);
102 dc.DrawCircle(gap + dot, size - gap - dot, dot);
103 }
104
105 // finally those 2 are only for the last dice
106 if ( num == 6 )
107 {
108 dc.DrawCircle(gap + dot, size/2, dot);
109 dc.DrawCircle(size - gap - dot, size/2, dot);
110 }
111
112 dc.SelectObject(wxNullBitmap);
113
114 return bmp.ConvertToImage();
115 }
116
117 // ============================================================================
118 // implementation
119 // ============================================================================
120
121 // ----------------------------------------------------------------------------
122 // MyApp: the application object
123 // ----------------------------------------------------------------------------
124
125 IMPLEMENT_APP(MyApp)
126
127 bool MyApp::OnInit()
128 {
129 if ( !wxApp::OnInit() )
130 return false;
131
132 // Create the main window
133 new MyFrame();
134
135 return true;
136 }
137
138 int MyApp::OnExit()
139 {
140 delete m_glContext;
141
142 return wxApp::OnExit();
143 }
144
145 TestGLContext& MyApp::GetContext(wxGLCanvas *canvas)
146 {
147 if ( !m_glContext )
148 m_glContext = new TestGLContext(canvas);
149 else
150 m_glContext->SetCurrent(*canvas);
151
152 return *m_glContext;
153 }
154
155 // ----------------------------------------------------------------------------
156 // TestGLContext
157 // ----------------------------------------------------------------------------
158
159 TestGLContext::TestGLContext(wxGLCanvas *canvas)
160 : wxGLContext(canvas)
161 {
162 SetCurrent(*canvas);
163
164 // set up the parameters we want to use
165 glEnable(GL_DEPTH_TEST);
166 glEnable(GL_LIGHTING);
167 glEnable(GL_LIGHT0);
168 glEnable(GL_TEXTURE_2D);
169
170 // add slightly more light, the default lightning is rather dark
171 GLfloat ambient[] = { 0.5, 0.5, 0.5, 0.5 };
172 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
173
174 // set viewing projection
175 glMatrixMode(GL_PROJECTION);
176 glLoadIdentity();
177 glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 1.0f, 3.0f);
178
179 // create the textures to use for cube sides: they will be reused by all
180 // canvases (which is probably not critical in the case of simple textures
181 // we use here but could be really important for a real application where
182 // each texture could take many megabytes)
183 glGenTextures(WXSIZEOF(m_textures), m_textures);
184
185 for ( unsigned i = 0; i < WXSIZEOF(m_textures); i++ )
186 {
187 glBindTexture(GL_TEXTURE_2D, m_textures[i]);
188
189 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
190 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
191 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
192 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
194
195 const wxImage img(DrawDice(256, i + 1));
196
197 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
198 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(),
199 0, GL_RGB, GL_UNSIGNED_BYTE, img.GetData());
200 }
201
202 CheckGLError();
203 }
204
205 void TestGLContext::DrawRotatedCube(float xangle, float yangle)
206 {
207 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
208
209 glMatrixMode(GL_MODELVIEW);
210 glLoadIdentity();
211 glTranslatef(0.0f, 0.0f, -2.0f);
212 glRotatef(xangle, 1.0f, 0.0f, 0.0f);
213 glRotatef(yangle, 0.0f, 1.0f, 0.0f);
214
215 // draw six faces of a cube of size 1 centered at (0, 0, 0)
216 glBindTexture(GL_TEXTURE_2D, m_textures[0]);
217 glBegin(GL_QUADS);
218 glNormal3f( 0.0f, 0.0f, 1.0f);
219 glTexCoord2f(0, 0); glVertex3f( 0.5f, 0.5f, 0.5f);
220 glTexCoord2f(1, 0); glVertex3f(-0.5f, 0.5f, 0.5f);
221 glTexCoord2f(1, 1); glVertex3f(-0.5f,-0.5f, 0.5f);
222 glTexCoord2f(0, 1); glVertex3f( 0.5f,-0.5f, 0.5f);
223 glEnd();
224
225 glBindTexture(GL_TEXTURE_2D, m_textures[1]);
226 glBegin(GL_QUADS);
227 glNormal3f( 0.0f, 0.0f,-1.0f);
228 glTexCoord2f(0, 0); glVertex3f(-0.5f,-0.5f,-0.5f);
229 glTexCoord2f(1, 0); glVertex3f(-0.5f, 0.5f,-0.5f);
230 glTexCoord2f(1, 1); glVertex3f( 0.5f, 0.5f,-0.5f);
231 glTexCoord2f(0, 1); glVertex3f( 0.5f,-0.5f,-0.5f);
232 glEnd();
233
234 glBindTexture(GL_TEXTURE_2D, m_textures[2]);
235 glBegin(GL_QUADS);
236 glNormal3f( 0.0f, 1.0f, 0.0f);
237 glTexCoord2f(0, 0); glVertex3f( 0.5f, 0.5f, 0.5f);
238 glTexCoord2f(1, 0); glVertex3f( 0.5f, 0.5f,-0.5f);
239 glTexCoord2f(1, 1); glVertex3f(-0.5f, 0.5f,-0.5f);
240 glTexCoord2f(0, 1); glVertex3f(-0.5f, 0.5f, 0.5f);
241 glEnd();
242
243 glBindTexture(GL_TEXTURE_2D, m_textures[3]);
244 glBegin(GL_QUADS);
245 glNormal3f( 0.0f,-1.0f, 0.0f);
246 glTexCoord2f(0, 0); glVertex3f(-0.5f,-0.5f,-0.5f);
247 glTexCoord2f(1, 0); glVertex3f( 0.5f,-0.5f,-0.5f);
248 glTexCoord2f(1, 1); glVertex3f( 0.5f,-0.5f, 0.5f);
249 glTexCoord2f(0, 1); glVertex3f(-0.5f,-0.5f, 0.5f);
250 glEnd();
251
252 glBindTexture(GL_TEXTURE_2D, m_textures[4]);
253 glBegin(GL_QUADS);
254 glNormal3f( 1.0f, 0.0f, 0.0f);
255 glTexCoord2f(0, 0); glVertex3f( 0.5f, 0.5f, 0.5f);
256 glTexCoord2f(1, 0); glVertex3f( 0.5f,-0.5f, 0.5f);
257 glTexCoord2f(1, 1); glVertex3f( 0.5f,-0.5f,-0.5f);
258 glTexCoord2f(0, 1); glVertex3f( 0.5f, 0.5f,-0.5f);
259 glEnd();
260
261 glBindTexture(GL_TEXTURE_2D, m_textures[5]);
262 glBegin(GL_QUADS);
263 glNormal3f(-1.0f, 0.0f, 0.0f);
264 glTexCoord2f(0, 0); glVertex3f(-0.5f,-0.5f,-0.5f);
265 glTexCoord2f(1, 0); glVertex3f(-0.5f,-0.5f, 0.5f);
266 glTexCoord2f(1, 1); glVertex3f(-0.5f, 0.5f, 0.5f);
267 glTexCoord2f(0, 1); glVertex3f(-0.5f, 0.5f,-0.5f);
268 glEnd();
269
270 glFlush();
271
272 CheckGLError();
273 }
274
275 // ----------------------------------------------------------------------------
276 // TestGLCanvas
277 // ----------------------------------------------------------------------------
278
279 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
280 EVT_SIZE(TestGLCanvas::OnSize)
281 EVT_PAINT(TestGLCanvas::OnPaint)
282
283 EVT_KEY_DOWN(TestGLCanvas::OnKeyDown)
284 END_EVENT_TABLE()
285
286 TestGLCanvas::TestGLCanvas(wxWindow *parent)
287 : wxGLCanvas(parent, wxID_ANY, NULL /* attribs */)
288 {
289 m_xangle =
290 m_yangle = 30;
291 }
292
293 void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
294 {
295 wxPaintDC dc(this);
296
297 wxGetApp().GetContext(this).DrawRotatedCube(m_xangle, m_yangle);
298
299 SwapBuffers();
300 }
301
302 void TestGLCanvas::OnSize(wxSizeEvent& event)
303 {
304 // don't prevent default processing from taking place
305 event.Skip();
306
307 if ( !IsShown() )
308 return;
309
310 // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...)
311 int w, h;
312 GetClientSize(&w, &h);
313
314 wxGetApp().GetContext(this);
315 glViewport(0, 0, w, h);
316 }
317
318 void TestGLCanvas::OnKeyDown( wxKeyEvent& event )
319 {
320 float *p = NULL;
321
322 bool inverse = false;
323
324 switch ( event.GetKeyCode() )
325 {
326 case WXK_RIGHT:
327 inverse = true;
328 // fall through
329
330 case WXK_LEFT:
331 // rotate around Y axis
332 p = &m_yangle;
333 break;
334
335 case WXK_DOWN:
336 inverse = true;
337 // fall through
338
339 case WXK_UP:
340 // rotate around X axis
341 p = &m_xangle;
342 break;
343
344 default:
345 event.Skip();
346 return;
347 }
348
349 float angle = 5;
350 if ( inverse )
351 angle = -angle;
352
353 *p += angle;
354
355 Refresh(false);
356 }
357
358 // ----------------------------------------------------------------------------
359 // MyFrame: main application window
360 // ----------------------------------------------------------------------------
361
362 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
363 EVT_MENU(wxID_NEW, MyFrame::OnNewWindow)
364 EVT_MENU(wxID_CLOSE, MyFrame::OnClose)
365 END_EVENT_TABLE()
366
367 MyFrame::MyFrame()
368 : wxFrame(NULL, wxID_ANY, _T("wxWidgets OpenGL Cube Sample"))
369 {
370 new TestGLCanvas(this);
371
372 SetIcon(wxICON(sample));
373
374 // Make a menubar
375 wxMenu *menu = new wxMenu;
376 menu->Append(wxID_NEW);
377 menu->AppendSeparator();
378 menu->Append(wxID_CLOSE);
379 wxMenuBar *menuBar = new wxMenuBar;
380 menuBar->Append(menu, _T("&Cube"));
381
382 SetMenuBar(menuBar);
383
384 CreateStatusBar();
385
386 SetClientSize(400, 400);
387 Show();
388 }
389
390 void MyFrame::OnClose(wxCommandEvent& WXUNUSED(event))
391 {
392 // true is to force the frame to close
393 Close(true);
394 }
395
396 void MyFrame::OnNewWindow( wxCommandEvent& WXUNUSED(event) )
397 {
398 (void) new MyFrame();
399 }
400