]>
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 #ifndef wxHAS_IMAGES_IN_RESOURCES
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_CULL_FACE
);
142 glEnable(GL_DEPTH_TEST
);
143 glEnable(GL_LIGHTING
);
145 glEnable(GL_TEXTURE_2D
);
147 // add slightly more light, the default lighting is rather dark
148 GLfloat ambient
[] = { 0.5, 0.5, 0.5, 0.5 };
149 glLightfv(GL_LIGHT0
, GL_AMBIENT
, ambient
);
151 // set viewing projection
152 glMatrixMode(GL_PROJECTION
);
154 glFrustum(-0.5f
, 0.5f
, -0.5f
, 0.5f
, 1.0f
, 3.0f
);
156 // create the textures to use for cube sides: they will be reused by all
157 // canvases (which is probably not critical in the case of simple textures
158 // we use here but could be really important for a real application where
159 // each texture could take many megabytes)
160 glGenTextures(WXSIZEOF(m_textures
), m_textures
);
162 for ( unsigned i
= 0; i
< WXSIZEOF(m_textures
); i
++ )
164 glBindTexture(GL_TEXTURE_2D
, m_textures
[i
]);
166 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
167 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
168 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
169 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
170 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
172 const wxImage
img(DrawDice(256, i
+ 1));
174 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
175 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, img
.GetWidth(), img
.GetHeight(),
176 0, GL_RGB
, GL_UNSIGNED_BYTE
, img
.GetData());
182 void TestGLContext::DrawRotatedCube(float xangle
, float yangle
)
184 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
186 glMatrixMode(GL_MODELVIEW
);
188 glTranslatef(0.0f
, 0.0f
, -2.0f
);
189 glRotatef(xangle
, 1.0f
, 0.0f
, 0.0f
);
190 glRotatef(yangle
, 0.0f
, 1.0f
, 0.0f
);
192 // draw six faces of a cube of size 1 centered at (0, 0, 0)
193 glBindTexture(GL_TEXTURE_2D
, m_textures
[0]);
195 glNormal3f( 0.0f
, 0.0f
, 1.0f
);
196 glTexCoord2f(0, 0); glVertex3f( 0.5f
, 0.5f
, 0.5f
);
197 glTexCoord2f(1, 0); glVertex3f(-0.5f
, 0.5f
, 0.5f
);
198 glTexCoord2f(1, 1); glVertex3f(-0.5f
,-0.5f
, 0.5f
);
199 glTexCoord2f(0, 1); glVertex3f( 0.5f
,-0.5f
, 0.5f
);
202 glBindTexture(GL_TEXTURE_2D
, m_textures
[1]);
204 glNormal3f( 0.0f
, 0.0f
,-1.0f
);
205 glTexCoord2f(0, 0); glVertex3f(-0.5f
,-0.5f
,-0.5f
);
206 glTexCoord2f(1, 0); glVertex3f(-0.5f
, 0.5f
,-0.5f
);
207 glTexCoord2f(1, 1); glVertex3f( 0.5f
, 0.5f
,-0.5f
);
208 glTexCoord2f(0, 1); glVertex3f( 0.5f
,-0.5f
,-0.5f
);
211 glBindTexture(GL_TEXTURE_2D
, m_textures
[2]);
213 glNormal3f( 0.0f
, 1.0f
, 0.0f
);
214 glTexCoord2f(0, 0); glVertex3f( 0.5f
, 0.5f
, 0.5f
);
215 glTexCoord2f(1, 0); glVertex3f( 0.5f
, 0.5f
,-0.5f
);
216 glTexCoord2f(1, 1); glVertex3f(-0.5f
, 0.5f
,-0.5f
);
217 glTexCoord2f(0, 1); glVertex3f(-0.5f
, 0.5f
, 0.5f
);
220 glBindTexture(GL_TEXTURE_2D
, m_textures
[3]);
222 glNormal3f( 0.0f
,-1.0f
, 0.0f
);
223 glTexCoord2f(0, 0); glVertex3f(-0.5f
,-0.5f
,-0.5f
);
224 glTexCoord2f(1, 0); glVertex3f( 0.5f
,-0.5f
,-0.5f
);
225 glTexCoord2f(1, 1); glVertex3f( 0.5f
,-0.5f
, 0.5f
);
226 glTexCoord2f(0, 1); glVertex3f(-0.5f
,-0.5f
, 0.5f
);
229 glBindTexture(GL_TEXTURE_2D
, m_textures
[4]);
231 glNormal3f( 1.0f
, 0.0f
, 0.0f
);
232 glTexCoord2f(0, 0); glVertex3f( 0.5f
, 0.5f
, 0.5f
);
233 glTexCoord2f(1, 0); glVertex3f( 0.5f
,-0.5f
, 0.5f
);
234 glTexCoord2f(1, 1); glVertex3f( 0.5f
,-0.5f
,-0.5f
);
235 glTexCoord2f(0, 1); glVertex3f( 0.5f
, 0.5f
,-0.5f
);
238 glBindTexture(GL_TEXTURE_2D
, m_textures
[5]);
240 glNormal3f(-1.0f
, 0.0f
, 0.0f
);
241 glTexCoord2f(0, 0); glVertex3f(-0.5f
,-0.5f
,-0.5f
);
242 glTexCoord2f(1, 0); glVertex3f(-0.5f
,-0.5f
, 0.5f
);
243 glTexCoord2f(1, 1); glVertex3f(-0.5f
, 0.5f
, 0.5f
);
244 glTexCoord2f(0, 1); glVertex3f(-0.5f
, 0.5f
,-0.5f
);
253 // ----------------------------------------------------------------------------
254 // MyApp: the application object
255 // ----------------------------------------------------------------------------
261 if ( !wxApp::OnInit() )
273 return wxApp::OnExit();
276 TestGLContext
& MyApp::GetContext(wxGLCanvas
*canvas
)
280 // Create the OpenGL context for the first window which needs it:
281 // subsequently created windows will all share the same context.
282 m_glContext
= new TestGLContext(canvas
);
285 m_glContext
->SetCurrent(*canvas
);
290 // ----------------------------------------------------------------------------
292 // ----------------------------------------------------------------------------
294 BEGIN_EVENT_TABLE(TestGLCanvas
, wxGLCanvas
)
295 EVT_PAINT(TestGLCanvas::OnPaint
)
296 EVT_KEY_DOWN(TestGLCanvas::OnKeyDown
)
297 EVT_TIMER(SpinTimer
, TestGLCanvas::OnSpinTimer
)
300 TestGLCanvas::TestGLCanvas(wxWindow
*parent
)
301 // With perspective OpenGL graphics, the wxFULL_REPAINT_ON_RESIZE style
302 // flag should always be set, because even making the canvas smaller should
303 // be followed by a paint event that updates the entire canvas with new
304 // viewport settings.
305 : wxGLCanvas(parent
, wxID_ANY
, NULL
/* attribs */,
306 wxDefaultPosition
, wxDefaultSize
,
307 wxFULL_REPAINT_ON_RESIZE
),
310 m_spinTimer(this,SpinTimer
)
314 void TestGLCanvas::OnPaint(wxPaintEvent
& WXUNUSED(event
))
316 // This is required even though dc is not used otherwise.
319 // Set the OpenGL viewport according to the client size of this canvas.
320 // This is done here rather than in a wxSizeEvent handler because our
321 // OpenGL rendering context (and thus viewport setting) is used with
322 // multiple canvases: If we updated the viewport in the wxSizeEvent
323 // handler, changing the size of one canvas causes a viewport setting that
324 // is wrong when next another canvas is repainted.
325 const wxSize ClientSize
= GetClientSize();
327 TestGLContext
& canvas
= wxGetApp().GetContext(this);
328 glViewport(0, 0, ClientSize
.x
, ClientSize
.y
);
330 // Render the graphics and swap the buffers.
331 canvas
.DrawRotatedCube(m_xangle
, m_yangle
);
335 void TestGLCanvas::Spin(float xSpin
, float ySpin
)
343 void TestGLCanvas::OnKeyDown(wxKeyEvent
& event
)
347 switch ( event
.GetKeyCode() )
366 if ( m_spinTimer
.IsRunning() )
369 m_spinTimer
.Start( 25 );
378 void TestGLCanvas::OnSpinTimer(wxTimerEvent
& WXUNUSED(event
))
384 // ----------------------------------------------------------------------------
385 // MyFrame: main application window
386 // ----------------------------------------------------------------------------
388 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
389 EVT_MENU(wxID_NEW
, MyFrame::OnNewWindow
)
390 EVT_MENU(wxID_CLOSE
, MyFrame::OnClose
)
394 : wxFrame(NULL
, wxID_ANY
, wxT("wxWidgets OpenGL Cube Sample"))
396 new TestGLCanvas(this);
398 SetIcon(wxICON(sample
));
401 wxMenu
*menu
= new wxMenu
;
402 menu
->Append(wxID_NEW
);
403 menu
->AppendSeparator();
404 menu
->Append(wxID_CLOSE
);
405 wxMenuBar
*menuBar
= new wxMenuBar
;
406 menuBar
->Append(menu
, wxT("&Cube"));
412 SetClientSize(400, 400);
415 // test IsDisplaySupported() function:
416 static const int attribs
[] = { WX_GL_RGBA
, WX_GL_DOUBLEBUFFER
, 0 };
417 wxLogStatus("Double-buffered display %s supported",
418 wxGLCanvas::IsDisplaySupported(attribs
) ? "is" : "not");
421 void MyFrame::OnClose(wxCommandEvent
& WXUNUSED(event
))
423 // true is to force the frame to close
427 void MyFrame::OnNewWindow( wxCommandEvent
& WXUNUSED(event
) )