]>
git.saurik.com Git - wxWidgets.git/blob - samples/opengl/cube/cube.cpp
1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxGLCanvas demo program
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin to use new wxGLCanvas API (2007-04-09)
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
32 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
37 #if !defined(__WXMSW__) && !defined(__WXPM__)
38 #include "../../sample.xpm"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
48 SpinTimer
= wxID_HIGHEST
+ 1
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 static void CheckGLError()
57 GLenum errLast
= GL_NO_ERROR
;
61 GLenum err
= glGetError();
62 if ( err
== GL_NO_ERROR
)
65 // normally the error is reset by the call to glGetError() but if
66 // glGetError() itself returns an error, we risk looping forever here
67 // so check that we get a different error than the last time
70 wxLogError(wxT("OpenGL error state couldn't be reset."));
76 wxLogError(wxT("OpenGL error %d"), err
);
80 // function to draw the texture for cube faces
81 static wxImage
DrawDice(int size
, unsigned num
)
83 wxASSERT_MSG( num
>= 1 && num
<= 6, wxT("invalid dice index") );
85 const int dot
= size
/16; // radius of a single dot
86 const int gap
= 5*size
/32; // gap between dots
88 wxBitmap
bmp(size
, size
);
91 dc
.SetBackground(*wxWHITE_BRUSH
);
93 dc
.SetBrush(*wxBLACK_BRUSH
);
95 // the upper left and lower right points
98 dc
.DrawCircle(gap
+ dot
, gap
+ dot
, dot
);
99 dc
.DrawCircle(size
- gap
- dot
, size
- gap
- dot
, dot
);
102 // draw the central point for odd dices
105 dc
.DrawCircle(size
/2, size
/2, dot
);
108 // the upper right and lower left points
111 dc
.DrawCircle(size
- gap
- dot
, gap
+ dot
, dot
);
112 dc
.DrawCircle(gap
+ dot
, size
- gap
- dot
, dot
);
115 // finally those 2 are only for the last dice
118 dc
.DrawCircle(gap
+ dot
, size
/2, dot
);
119 dc
.DrawCircle(size
- gap
- dot
, size
/2, dot
);
122 dc
.SelectObject(wxNullBitmap
);
124 return bmp
.ConvertToImage();
127 // ============================================================================
129 // ============================================================================
131 // ----------------------------------------------------------------------------
133 // ----------------------------------------------------------------------------
135 TestGLContext::TestGLContext(wxGLCanvas
*canvas
)
136 : wxGLContext(canvas
)
140 // set up the parameters we want to use
141 glEnable(GL_DEPTH_TEST
);
142 glEnable(GL_LIGHTING
);
144 glEnable(GL_TEXTURE_2D
);
146 // add slightly more light, the default lighting is rather dark
147 GLfloat ambient
[] = { 0.5, 0.5, 0.5, 0.5 };
148 glLightfv(GL_LIGHT0
, GL_AMBIENT
, ambient
);
150 // set viewing projection
151 glMatrixMode(GL_PROJECTION
);
153 glFrustum(-0.5f
, 0.5f
, -0.5f
, 0.5f
, 1.0f
, 3.0f
);
155 // create the textures to use for cube sides: they will be reused by all
156 // canvases (which is probably not critical in the case of simple textures
157 // we use here but could be really important for a real application where
158 // each texture could take many megabytes)
159 glGenTextures(WXSIZEOF(m_textures
), m_textures
);
161 for ( unsigned i
= 0; i
< WXSIZEOF(m_textures
); i
++ )
163 glBindTexture(GL_TEXTURE_2D
, m_textures
[i
]);
165 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
166 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
167 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
168 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
169 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
171 const wxImage
img(DrawDice(256, i
+ 1));
173 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
174 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, img
.GetWidth(), img
.GetHeight(),
175 0, GL_RGB
, GL_UNSIGNED_BYTE
, img
.GetData());
181 void TestGLContext::DrawRotatedCube(float xangle
, float yangle
)
183 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
185 glMatrixMode(GL_MODELVIEW
);
187 glTranslatef(0.0f
, 0.0f
, -2.0f
);
188 glRotatef(xangle
, 1.0f
, 0.0f
, 0.0f
);
189 glRotatef(yangle
, 0.0f
, 1.0f
, 0.0f
);
191 // draw six faces of a cube of size 1 centered at (0, 0, 0)
192 glBindTexture(GL_TEXTURE_2D
, m_textures
[0]);
194 glNormal3f( 0.0f
, 0.0f
, 1.0f
);
195 glTexCoord2f(0, 0); glVertex3f( 0.5f
, 0.5f
, 0.5f
);
196 glTexCoord2f(1, 0); glVertex3f(-0.5f
, 0.5f
, 0.5f
);
197 glTexCoord2f(1, 1); glVertex3f(-0.5f
,-0.5f
, 0.5f
);
198 glTexCoord2f(0, 1); glVertex3f( 0.5f
,-0.5f
, 0.5f
);
201 glBindTexture(GL_TEXTURE_2D
, m_textures
[1]);
203 glNormal3f( 0.0f
, 0.0f
,-1.0f
);
204 glTexCoord2f(0, 0); glVertex3f(-0.5f
,-0.5f
,-0.5f
);
205 glTexCoord2f(1, 0); glVertex3f(-0.5f
, 0.5f
,-0.5f
);
206 glTexCoord2f(1, 1); glVertex3f( 0.5f
, 0.5f
,-0.5f
);
207 glTexCoord2f(0, 1); glVertex3f( 0.5f
,-0.5f
,-0.5f
);
210 glBindTexture(GL_TEXTURE_2D
, m_textures
[2]);
212 glNormal3f( 0.0f
, 1.0f
, 0.0f
);
213 glTexCoord2f(0, 0); glVertex3f( 0.5f
, 0.5f
, 0.5f
);
214 glTexCoord2f(1, 0); glVertex3f( 0.5f
, 0.5f
,-0.5f
);
215 glTexCoord2f(1, 1); glVertex3f(-0.5f
, 0.5f
,-0.5f
);
216 glTexCoord2f(0, 1); glVertex3f(-0.5f
, 0.5f
, 0.5f
);
219 glBindTexture(GL_TEXTURE_2D
, m_textures
[3]);
221 glNormal3f( 0.0f
,-1.0f
, 0.0f
);
222 glTexCoord2f(0, 0); glVertex3f(-0.5f
,-0.5f
,-0.5f
);
223 glTexCoord2f(1, 0); glVertex3f( 0.5f
,-0.5f
,-0.5f
);
224 glTexCoord2f(1, 1); glVertex3f( 0.5f
,-0.5f
, 0.5f
);
225 glTexCoord2f(0, 1); glVertex3f(-0.5f
,-0.5f
, 0.5f
);
228 glBindTexture(GL_TEXTURE_2D
, m_textures
[4]);
230 glNormal3f( 1.0f
, 0.0f
, 0.0f
);
231 glTexCoord2f(0, 0); glVertex3f( 0.5f
, 0.5f
, 0.5f
);
232 glTexCoord2f(1, 0); glVertex3f( 0.5f
,-0.5f
, 0.5f
);
233 glTexCoord2f(1, 1); glVertex3f( 0.5f
,-0.5f
,-0.5f
);
234 glTexCoord2f(0, 1); glVertex3f( 0.5f
, 0.5f
,-0.5f
);
237 glBindTexture(GL_TEXTURE_2D
, m_textures
[5]);
239 glNormal3f(-1.0f
, 0.0f
, 0.0f
);
240 glTexCoord2f(0, 0); glVertex3f(-0.5f
,-0.5f
,-0.5f
);
241 glTexCoord2f(1, 0); glVertex3f(-0.5f
,-0.5f
, 0.5f
);
242 glTexCoord2f(1, 1); glVertex3f(-0.5f
, 0.5f
, 0.5f
);
243 glTexCoord2f(0, 1); glVertex3f(-0.5f
, 0.5f
,-0.5f
);
252 // ----------------------------------------------------------------------------
253 // MyApp: the application object
254 // ----------------------------------------------------------------------------
260 if ( !wxApp::OnInit() )
272 return wxApp::OnExit();
275 TestGLContext
& MyApp::GetContext(wxGLCanvas
*canvas
)
279 // Create the OpenGL context for the first window which needs it:
280 // subsequently created windows will all share the same context.
281 m_glContext
= new TestGLContext(canvas
);
284 m_glContext
->SetCurrent(*canvas
);
289 // ----------------------------------------------------------------------------
291 // ----------------------------------------------------------------------------
293 BEGIN_EVENT_TABLE(TestGLCanvas
, wxGLCanvas
)
294 EVT_PAINT(TestGLCanvas::OnPaint
)
295 EVT_KEY_DOWN(TestGLCanvas::OnKeyDown
)
296 EVT_TIMER(SpinTimer
, TestGLCanvas::OnSpinTimer
)
299 TestGLCanvas::TestGLCanvas(wxWindow
*parent
)
300 // With perspective OpenGL graphics, the wxFULL_REPAINT_ON_RESIZE style
301 // flag should always be set, because even making the canvas smaller should
302 // be followed by a paint event that updates the entire canvas with new
303 // viewport settings.
304 : wxGLCanvas(parent
, wxID_ANY
, NULL
/* attribs */,
305 wxDefaultPosition
, wxDefaultSize
,
306 wxFULL_REPAINT_ON_RESIZE
),
309 m_spinTimer(this,SpinTimer
)
313 void TestGLCanvas::OnPaint(wxPaintEvent
& WXUNUSED(event
))
315 // This is required even though dc is not used otherwise.
318 // Set the OpenGL viewport according to the client size of this canvas.
319 // This is done here rather than in a wxSizeEvent handler because our
320 // OpenGL rendering context (and thus viewport setting) is used with
321 // multiple canvases: If we updated the viewport in the wxSizeEvent
322 // handler, changing the size of one canvas causes a viewport setting that
323 // is wrong when next another canvas is repainted.
324 const wxSize ClientSize
= GetClientSize();
326 TestGLContext
& canvas
= wxGetApp().GetContext(this);
327 glViewport(0, 0, ClientSize
.x
, ClientSize
.y
);
329 // Render the graphics and swap the buffers.
330 canvas
.DrawRotatedCube(m_xangle
, m_yangle
);
334 void TestGLCanvas::Spin(float xSpin
, float ySpin
)
342 void TestGLCanvas::OnKeyDown(wxKeyEvent
& event
)
346 switch ( event
.GetKeyCode() )
365 if ( m_spinTimer
.IsRunning() )
368 m_spinTimer
.Start( 25 );
377 void TestGLCanvas::OnSpinTimer(wxTimerEvent
& WXUNUSED(event
))
383 // ----------------------------------------------------------------------------
384 // MyFrame: main application window
385 // ----------------------------------------------------------------------------
387 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
388 EVT_MENU(wxID_NEW
, MyFrame::OnNewWindow
)
389 EVT_MENU(wxID_CLOSE
, MyFrame::OnClose
)
393 : wxFrame(NULL
, wxID_ANY
, wxT("wxWidgets OpenGL Cube Sample"))
395 new TestGLCanvas(this);
397 SetIcon(wxICON(sample
));
400 wxMenu
*menu
= new wxMenu
;
401 menu
->Append(wxID_NEW
);
402 menu
->AppendSeparator();
403 menu
->Append(wxID_CLOSE
);
404 wxMenuBar
*menuBar
= new wxMenuBar
;
405 menuBar
->Append(menu
, wxT("&Cube"));
411 SetClientSize(400, 400);
414 // test IsDisplaySupported() function:
415 static const int attribs
[] = { WX_GL_RGBA
, WX_GL_DOUBLEBUFFER
, 0 };
416 wxLogStatus("Double-buffered display %s supported",
417 wxGLCanvas::IsDisplaySupported(attribs
) ? "is" : "not");
420 void MyFrame::OnClose(wxCommandEvent
& WXUNUSED(event
))
422 // true is to force the frame to close
426 void MyFrame::OnNewWindow( wxCommandEvent
& WXUNUSED(event
) )