]> git.saurik.com Git - wxWidgets.git/blob - samples/opengl/isosurf/isosurf.cpp
37e3bb0cc1b9ca37c3e7ccc4b02c20ddac92b726
[wxWidgets.git] / samples / opengl / isosurf / isosurf.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: isosurf.cpp
3 // Purpose: wxGLCanvas demo program
4 // Author: Brian Paul (original gltk version), Wolfram Gloger
5 // Modified by: Julian Smart
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22
23 #if !wxUSE_GLCANVAS
24 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
25 #endif
26
27 #include "wx/timer.h"
28 #include "wx/glcanvas.h"
29 #include "wx/math.h"
30 #include "wx/log.h"
31 #include "wx/cmdline.h"
32 #include "wx/archive.h"
33 #include "wx/wfstream.h"
34 #include "wx/zstream.h"
35
36 #include "isosurf.h"
37 #include "../../sample.xpm"
38
39
40 // global options which can be set through command-line options
41 GLboolean g_use_vertex_arrays = GL_FALSE;
42 GLboolean g_doubleBuffer = GL_TRUE;
43 GLboolean g_smooth = GL_TRUE;
44 GLboolean g_lighting = GL_TRUE;
45
46
47
48 //---------------------------------------------------------------------------
49 // MyApp
50 //---------------------------------------------------------------------------
51
52 IMPLEMENT_APP(MyApp)
53
54 // `Main program' equivalent, creating windows and returning main app frame
55 bool MyApp::OnInit()
56 {
57 if ( !wxApp::OnInit() )
58 return false;
59
60 // Create the main frame window
61 SetTopWindow(new MyFrame(NULL, wxT("wxWidgets OpenGL Isosurf Sample"),
62 wxDefaultPosition, wxDefaultSize));
63
64 return true;
65 }
66
67 void MyApp::OnInitCmdLine(wxCmdLineParser& parser)
68 {
69 parser.AddSwitch("", "sb", "Do not use double buffering");
70 parser.AddSwitch("", "db", "Use double buffering");
71 parser.AddSwitch("", "va", "Use vertex arrays");
72
73 wxApp::OnInitCmdLine(parser);
74 }
75
76 bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser)
77 {
78 if (parser.Found("sb"))
79 g_doubleBuffer = GL_FALSE;
80 else if (parser.Found("db"))
81 g_doubleBuffer = GL_TRUE;
82
83 if (parser.Found("va"))
84 g_use_vertex_arrays = GL_TRUE;
85
86 return wxApp::OnCmdLineParsed(parser);
87 }
88
89 //---------------------------------------------------------------------------
90 // MyFrame
91 //---------------------------------------------------------------------------
92
93 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
94 EVT_MENU(wxID_EXIT, MyFrame::OnExit)
95 END_EVENT_TABLE()
96
97 // My frame constructor
98 MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
99 const wxSize& size, long style)
100 : wxFrame(frame, wxID_ANY, title, pos, size, style),
101 m_canvas(NULL)
102 {
103 SetIcon(wxICON(sample));
104
105
106 // Make a menubar
107 wxMenu *fileMenu = new wxMenu;
108
109 fileMenu->Append(wxID_EXIT, _T("E&xit"));
110 wxMenuBar *menuBar = new wxMenuBar;
111 menuBar->Append(fileMenu, _T("&File"));
112 SetMenuBar(menuBar);
113
114
115 // Make a TestGLCanvas
116
117 // JACS
118 #ifdef __WXMSW__
119 int *gl_attrib = NULL;
120 #else
121 int gl_attrib[20] =
122 { WX_GL_RGBA, WX_GL_MIN_RED, 1, WX_GL_MIN_GREEN, 1,
123 WX_GL_MIN_BLUE, 1, WX_GL_DEPTH_SIZE, 1,
124 WX_GL_DOUBLEBUFFER,
125 # if defined(__WXMAC__) || defined(__WXCOCOA__)
126 GL_NONE };
127 # else
128 None };
129 # endif
130 #endif
131
132 if (!g_doubleBuffer)
133 {
134 wxLogWarning("don't have double buffer, disabling\n");
135
136 #ifdef __WXGTK__
137 gl_attrib[9] = None;
138 #endif
139 g_doubleBuffer = GL_FALSE;
140 }
141
142 // Show the frame
143 Show(true);
144
145 m_canvas = new TestGLCanvas(this, wxID_ANY, wxDefaultPosition,
146 GetClientSize(), 0, _T("TestGLCanvas"), gl_attrib);
147 }
148
149 MyFrame::~MyFrame()
150 {
151 delete m_canvas;
152 }
153
154 // Intercept menu commands
155 void MyFrame::OnExit( wxCommandEvent& WXUNUSED(event) )
156 {
157 // true is to force the frame to close
158 Close(true);
159 }
160
161
162 //---------------------------------------------------------------------------
163 // TestGLCanvas
164 //---------------------------------------------------------------------------
165
166 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
167 EVT_SIZE(TestGLCanvas::OnSize)
168 EVT_PAINT(TestGLCanvas::OnPaint)
169 EVT_CHAR(TestGLCanvas::OnChar)
170 EVT_MOUSE_EVENTS(TestGLCanvas::OnMouseEvent)
171 END_EVENT_TABLE()
172
173 TestGLCanvas::TestGLCanvas(wxWindow *parent,
174 wxWindowID id,
175 const wxPoint& pos,
176 const wxSize& size,
177 long style,
178 const wxString& name,
179 int* gl_attrib)
180 : wxGLCanvas(parent, id, gl_attrib, pos, size,
181 style | wxFULL_REPAINT_ON_RESIZE, name)
182 {
183 // Explicitly create a new rendering context instance for this canvas.
184 m_glRC = new wxGLContext(this);
185
186 // Make the new context current (activate it for use) with this canvas.
187 SetCurrent(*m_glRC);
188
189 InitGL();
190 InitMaterials();
191 LoadSurface("isosurf.dat.gz");
192 }
193
194 TestGLCanvas::~TestGLCanvas()
195 {
196 delete m_glRC;
197 }
198
199 void TestGLCanvas::LoadSurface(const wxString& filename)
200 {
201 wxZlibInputStream* stream =
202 new wxZlibInputStream(new wxFFileInputStream(filename));
203 if (!stream || !stream->IsOk())
204 {
205 wxLogError("Cannot load '%s' type of files!", filename.c_str());
206 delete stream;
207 return;
208 }
209
210 m_numverts = 0;
211
212 const size_t sz = sizeof(GLfloat);
213 while (!stream->Eof() && m_numverts < MAXVERTS)
214 {
215 // read a vertex
216 for (int i=0; i<3; i++)
217 if (stream->Read(&m_verts[m_numverts][i], sz).LastRead() != sz)
218 {
219 wxLogError("Cannot read the %d-th vertex in '%s'!",
220 m_numverts, filename.c_str());
221 delete stream;
222 return;
223 }
224
225 // read its normal
226 for (int i=0; i<3; i++)
227 if (stream->Read(&m_norms[m_numverts][i], sz).LastRead() != sz)
228 {
229 wxLogError("Cannot read the %d-th vertex in '%s'!",
230 m_numverts, filename.c_str());
231 delete stream;
232 return;
233 }
234
235 m_numverts++;
236 }
237
238 delete stream;
239
240 wxLogMessage(_T("Loaded %d vertices, %d triangles from '%s'"),
241 m_numverts, m_numverts-2, filename.c_str());
242 }
243
244 void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
245 {
246 // This is a dummy, to avoid an endless succession of paint messages.
247 // OnPaint handlers must always create a wxPaintDC.
248 wxPaintDC dc(this);
249
250 // This is normally only necessary if there is more than one wxGLCanvas
251 // or more than one wxGLContext in the application.
252 SetCurrent(*m_glRC);
253
254 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
255 glPushMatrix();
256 glRotatef( m_yrot, 0.0f, 1.0f, 0.0f );
257 glRotatef( m_xrot, 1.0f, 0.0f, 0.0f );
258
259 // draw the surface
260 /* if (g_use_vertex_arrays)
261 {
262 glDrawArrays( GL_TRIANGLE_STRIP, 0, m_numverts );
263 }
264 else*/
265 {
266 glBegin( GL_TRIANGLE_STRIP );
267
268 for (int i=0;i<m_numverts;i++)
269 {
270 glNormal3fv( m_norms[i] );
271 glVertex3fv( m_verts[i] );
272 }
273
274 glEnd();
275 }
276
277 glPopMatrix();
278 glFlush(); // Not really necessary: buffer swapping below implies glFlush()
279
280 SwapBuffers();
281 }
282
283 void TestGLCanvas::OnSize(wxSizeEvent& event)
284 {
285 // This is normally only necessary if there is more than one wxGLCanvas
286 // or more than one wxGLContext in the application.
287 SetCurrent(*m_glRC);
288
289 // It's up to the application code to update the OpenGL viewport settings.
290 // This is OK here only because there is only one canvas that uses the
291 // context. See the cube sample for that case that multiple canvases are
292 // made current with one context.
293 glViewport(0, 0, event.GetSize().x, event.GetSize().y);
294 }
295
296 void TestGLCanvas::OnChar(wxKeyEvent& event)
297 {
298 switch( event.GetKeyCode() )
299 {
300 case WXK_ESCAPE:
301 wxTheApp->ExitMainLoop();
302 return;
303
304 case WXK_LEFT:
305 m_yrot -= 15.0;
306 break;
307
308 case WXK_RIGHT:
309 m_yrot += 15.0;
310 break;
311
312 case WXK_UP:
313 m_xrot += 15.0;
314 break;
315
316 case WXK_DOWN:
317 m_xrot -= 15.0;
318 break;
319
320 case 's': case 'S':
321 g_smooth = !g_smooth;
322 if (g_smooth)
323 {
324 glShadeModel(GL_SMOOTH);
325 }
326 else
327 {
328 glShadeModel(GL_FLAT);
329 }
330 break;
331
332 case 'l': case 'L':
333 g_lighting = !g_lighting;
334 if (g_lighting)
335 {
336 glEnable(GL_LIGHTING);
337 }
338 else
339 {
340 glDisable(GL_LIGHTING);
341 }
342 break;
343
344 default:
345 event.Skip();
346 return;
347 }
348
349 Refresh(false);
350 }
351
352 void TestGLCanvas::OnMouseEvent(wxMouseEvent& event)
353 {
354 static int dragging = 0;
355 static float last_x, last_y;
356
357 // Allow default processing to happen, or else the canvas cannot gain focus
358 // (for key events).
359 event.Skip();
360
361 if(event.LeftIsDown())
362 {
363 if(!dragging)
364 {
365 dragging = 1;
366 }
367 else
368 {
369 m_yrot += (event.GetX() - last_x)*1.0;
370 m_xrot += (event.GetY() - last_y)*1.0;
371 Refresh(false);
372 }
373 last_x = event.GetX();
374 last_y = event.GetY();
375 }
376 else
377 {
378 dragging = 0;
379 }
380 }
381
382 void TestGLCanvas::InitMaterials()
383 {
384 static const GLfloat ambient[4] = {0.1f, 0.1f, 0.1f, 1.0f};
385 static const GLfloat diffuse[4] = {0.5f, 1.0f, 1.0f, 1.0f};
386 static const GLfloat position0[4] = {0.0f, 0.0f, 20.0f, 0.0f};
387 static const GLfloat position1[4] = {0.0f, 0.0f, -20.0f, 0.0f};
388 static const GLfloat front_mat_shininess[1] = {60.0f};
389 static const GLfloat front_mat_specular[4] = {0.2f, 0.2f, 0.2f, 1.0f};
390 static const GLfloat front_mat_diffuse[4] = {0.5f, 0.28f, 0.38f, 1.0f};
391 /*
392 static const GLfloat back_mat_shininess[1] = {60.0f};
393 static const GLfloat back_mat_specular[4] = {0.5f, 0.5f, 0.2f, 1.0f};
394 static const GLfloat back_mat_diffuse[4] = {1.0f, 1.0f, 0.2f, 1.0f};
395 */
396 static const GLfloat lmodel_ambient[4] = {1.0f, 1.0f, 1.0f, 1.0f};
397 static const GLfloat lmodel_twoside[1] = {GL_FALSE};
398
399 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
400 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
401 glLightfv(GL_LIGHT0, GL_POSITION, position0);
402 glEnable(GL_LIGHT0);
403
404 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
405 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
406 glLightfv(GL_LIGHT1, GL_POSITION, position1);
407 glEnable(GL_LIGHT1);
408
409 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
410 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
411 glEnable(GL_LIGHTING);
412
413 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess);
414 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular);
415 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse);
416 }
417
418 void TestGLCanvas::InitGL()
419 {
420 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
421
422 glShadeModel(GL_SMOOTH);
423 glEnable(GL_DEPTH_TEST);
424
425 InitMaterials();
426
427 glMatrixMode(GL_PROJECTION);
428 glLoadIdentity();
429 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
430
431 glMatrixMode(GL_MODELVIEW);
432 glLoadIdentity();
433 glTranslatef( 0.0, 0.0, -6.0 );
434
435 if (g_use_vertex_arrays)
436 {
437 glVertexPointer( 3, GL_FLOAT, 0, m_verts );
438 glNormalPointer( GL_FLOAT, 0, m_norms );
439 glEnable( GL_VERTEX_ARRAY_EXT );
440 glEnable( GL_NORMAL_ARRAY_EXT );
441 }
442 }
443