]> git.saurik.com Git - wxWidgets.git/blame - samples/opengl/cube/cube.cpp
prevent explicitly set client size from being changed when frame extents become known
[wxWidgets.git] / samples / opengl / cube / cube.cpp
CommitLineData
43c742d0 1///////////////////////////////////////////////////////////////////////////////
8b089c5e
JS
2// Name: cube.cpp
3// Purpose: wxGLCanvas demo program
4// Author: Julian Smart
43c742d0 5// Modified by: Vadim Zeitlin to use new wxGLCanvas API (2007-04-09)
8b089c5e
JS
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
f4a7108f 9// Licence: wxWindows licence
43c742d0
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
8b089c5e 19
8b089c5e
JS
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
806e2f15
VZ
31#if !wxUSE_GLCANVAS
32 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
33#endif
34
8b089c5e 35#include "cube.h"
5cf036d0 36
43c742d0
VZ
37#if !defined(__WXMSW__) && !defined(__WXPM__)
38 #include "../../sample.xpm"
39#endif
8b089c5e 40
378a3872
VZ
41// ----------------------------------------------------------------------------
42// helper functions
43// ----------------------------------------------------------------------------
44
45static 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
71static 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
43c742d0
VZ
117// ============================================================================
118// implementation
119// ============================================================================
8b089c5e 120
43c742d0
VZ
121// ----------------------------------------------------------------------------
122// MyApp: the application object
123// ----------------------------------------------------------------------------
8b089c5e 124
43c742d0 125IMPLEMENT_APP(MyApp)
8b089c5e 126
43c742d0 127bool MyApp::OnInit()
8b089c5e 128{
43c742d0
VZ
129 if ( !wxApp::OnInit() )
130 return false;
5cf036d0 131
43c742d0
VZ
132 // Create the main window
133 new MyFrame();
8b089c5e 134
43c742d0 135 return true;
8b089c5e
JS
136}
137
43c742d0 138int MyApp::OnExit()
8b089c5e 139{
43c742d0
VZ
140 delete m_glContext;
141
142 return wxApp::OnExit();
8b089c5e
JS
143}
144
50f5d508 145TestGLContext& MyApp::GetContext(wxGLCanvas *canvas)
8b089c5e 146{
43c742d0 147 if ( !m_glContext )
50f5d508 148 m_glContext = new TestGLContext(canvas);
e559e76e
VZ
149 else
150 m_glContext->SetCurrent(*canvas);
f4a7108f 151
50f5d508 152 return *m_glContext;
8b089c5e
JS
153}
154
43c742d0 155// ----------------------------------------------------------------------------
50f5d508 156// TestGLContext
43c742d0 157// ----------------------------------------------------------------------------
8b089c5e 158
50f5d508
VZ
159TestGLContext::TestGLContext(wxGLCanvas *canvas)
160 : wxGLContext(canvas)
8b089c5e 161{
378a3872 162 SetCurrent(*canvas);
8b089c5e 163
378a3872 164 // set up the parameters we want to use
8b089c5e
JS
165 glEnable(GL_DEPTH_TEST);
166 glEnable(GL_LIGHTING);
167 glEnable(GL_LIGHT0);
378a3872 168 glEnable(GL_TEXTURE_2D);
8b089c5e 169
bc521497
VZ
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
378a3872
VZ
174 // set viewing projection
175 glMatrixMode(GL_PROJECTION);
176 glLoadIdentity();
177 glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 1.0f, 3.0f);
8b089c5e 178
378a3872
VZ
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);
8b089c5e 184
378a3872
VZ
185 for ( unsigned i = 0; i < WXSIZEOF(m_textures); i++ )
186 {
187 glBindTexture(GL_TEXTURE_2D, m_textures[i]);
8b089c5e 188
378a3872
VZ
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);
f4a7108f 194
378a3872 195 const wxImage img(DrawDice(256, i + 1));
8b089c5e 196
378a3872
VZ
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 }
8b089c5e 201
378a3872 202 CheckGLError();
8b089c5e
JS
203}
204
50f5d508
VZ
205void TestGLContext::DrawRotatedCube(float xangle, float yangle)
206{
50f5d508
VZ
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
378a3872
VZ
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();
50f5d508
VZ
269
270 glFlush();
378a3872
VZ
271
272 CheckGLError();
50f5d508
VZ
273}
274
275// ----------------------------------------------------------------------------
276// TestGLCanvas
277// ----------------------------------------------------------------------------
278
279BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
280 EVT_SIZE(TestGLCanvas::OnSize)
281 EVT_PAINT(TestGLCanvas::OnPaint)
282
283 EVT_KEY_DOWN(TestGLCanvas::OnKeyDown)
284END_EVENT_TABLE()
285
286TestGLCanvas::TestGLCanvas(wxWindow *parent)
287 : wxGLCanvas(parent, wxID_ANY, NULL /* attribs */)
288{
289 m_xangle =
290 m_yangle = 30;
291}
292
293void 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
302void TestGLCanvas::OnSize(wxSizeEvent& event)
303{
304 // don't prevent default processing from taking place
305 event.Skip();
306
0ce4fad6 307 if ( !IsShownOnScreen() )
50f5d508
VZ
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
8b089c5e
JS
318void TestGLCanvas::OnKeyDown( wxKeyEvent& event )
319{
50f5d508 320 float *p = NULL;
8b089c5e 321
43c742d0 322 bool inverse = false;
f4a7108f 323
43c742d0 324 switch ( event.GetKeyCode() )
8b089c5e 325 {
43c742d0
VZ
326 case WXK_RIGHT:
327 inverse = true;
328 // fall through
329
330 case WXK_LEFT:
50f5d508
VZ
331 // rotate around Y axis
332 p = &m_yangle;
43c742d0
VZ
333 break;
334
335 case WXK_DOWN:
336 inverse = true;
337 // fall through
338
339 case WXK_UP:
50f5d508
VZ
340 // rotate around X axis
341 p = &m_xangle;
43c742d0
VZ
342 break;
343
344 default:
345 event.Skip();
346 return;
8b089c5e
JS
347 }
348
43c742d0
VZ
349 float angle = 5;
350 if ( inverse )
351 angle = -angle;
8b089c5e 352
50f5d508 353 *p += angle;
8b089c5e 354
50f5d508 355 Refresh(false);
43c742d0 356}
8b089c5e 357
43c742d0
VZ
358// ----------------------------------------------------------------------------
359// MyFrame: main application window
360// ----------------------------------------------------------------------------
8b089c5e
JS
361
362BEGIN_EVENT_TABLE(MyFrame, wxFrame)
43c742d0 363 EVT_MENU(wxID_NEW, MyFrame::OnNewWindow)
1f602af6 364 EVT_MENU(wxID_CLOSE, MyFrame::OnClose)
8b089c5e
JS
365END_EVENT_TABLE()
366
43c742d0 367MyFrame::MyFrame()
50f5d508 368 : wxFrame(NULL, wxID_ANY, _T("wxWidgets OpenGL Cube Sample"))
8b089c5e 369{
50f5d508 370 new TestGLCanvas(this);
5cf036d0 371
43c742d0 372 SetIcon(wxICON(sample));
5cf036d0 373
5cf036d0 374 // Make a menubar
1f602af6
VZ
375 wxMenu *menu = new wxMenu;
376 menu->Append(wxID_NEW);
377 menu->AppendSeparator();
378 menu->Append(wxID_CLOSE);
5cf036d0 379 wxMenuBar *menuBar = new wxMenuBar;
1f602af6 380 menuBar->Append(menu, _T("&Cube"));
8b089c5e 381
43c742d0 382 SetMenuBar(menuBar);
5cf036d0 383
1f602af6
VZ
384 CreateStatusBar();
385
50f5d508 386 SetClientSize(400, 400);
43c742d0 387 Show();
8b089c5e
JS
388}
389
1f602af6 390void MyFrame::OnClose(wxCommandEvent& WXUNUSED(event))
8b089c5e 391{
43c742d0
VZ
392 // true is to force the frame to close
393 Close(true);
8b089c5e 394}
2db98bf5 395
43c742d0 396void MyFrame::OnNewWindow( wxCommandEvent& WXUNUSED(event) )
8b089c5e 397{
43c742d0 398 (void) new MyFrame();
8b089c5e
JS
399}
400