update the samples to use new (non-deprecated) wxGLCanvas API; added more comments...
[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
31 #if defined(__WXMAC__) || defined(__WXCOCOA__)
32 # ifdef __DARWIN__
33 # include <OpenGL/gl.h>
34 # include <OpenGL/glu.h>
35 # else
36 # include <gl.h>
37 # include <glu.h>
38 # endif
39 #else
40 # include <GL/gl.h>
41 # include <GL/glu.h>
42 #endif
43
44 // disabled because this has apparently changed in OpenGL 1.2, so doesn't link
45 // correctly if this is on...
46 #ifdef GL_EXT_vertex_array
47 #undef GL_EXT_vertex_array
48 #endif
49
50 #include <fstream>
51
52 #include "isosurf.h"
53 #include "../../sample.xpm"
54
55 // The following part is taken largely unchanged from the original C Version
56
57 GLboolean speed_test = GL_FALSE;
58 GLboolean use_vertex_arrays = GL_FALSE;
59
60 GLboolean doubleBuffer = GL_TRUE;
61
62 GLboolean smooth = GL_TRUE;
63 GLboolean lighting = GL_TRUE;
64
65
66 #define MAXVERTS 10000
67
68 static GLfloat verts[MAXVERTS][3];
69 static GLfloat norms[MAXVERTS][3];
70 static GLint numverts;
71
72 static GLfloat xrot;
73 static GLfloat yrot;
74
75
76 static void read_surface(const char *filename)
77 {
78 std::ifstream inFile(filename);
79 numverts = 0;
80
81 if ( !inFile )
82 {
83 wxLogError("Couldn't read \"%s\"", filename);
84 return;
85 }
86
87 while ((inFile >> verts[numverts][0] >> verts[numverts][1] >> verts[numverts][2]
88 >> norms[numverts][0] >> norms[numverts][1] >> norms[numverts][2]) && numverts<MAXVERTS)
89 {
90 numverts++;
91 }
92
93 wxPrintf(_T("%d vertices, %d triangles\n"), numverts, numverts-2);
94 }
95
96
97 static void draw_surface()
98 {
99 GLint i;
100
101 #ifdef GL_EXT_vertex_array
102 if (use_vertex_arrays)
103 {
104 glDrawArraysEXT( GL_TRIANGLE_STRIP, 0, numverts );
105 }
106 else
107 #endif
108 {
109 glBegin( GL_TRIANGLE_STRIP );
110 for (i=0;i<numverts;i++)
111 {
112 glNormal3fv( norms[i] );
113 glVertex3fv( verts[i] );
114 }
115 glEnd();
116 }
117 }
118
119
120 static void draw1()
121 {
122 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
123 glPushMatrix();
124 glRotatef( yrot, 0.0f, 1.0f, 0.0f );
125 glRotatef( xrot, 1.0f, 0.0f, 0.0f );
126
127 draw_surface();
128
129 glPopMatrix();
130
131 glFlush(); // Not really necessary: buffer swapping below implies glFlush()
132 }
133
134
135 static void InitMaterials()
136 {
137 static const GLfloat ambient[4] = {0.1f, 0.1f, 0.1f, 1.0f};
138 static const GLfloat diffuse[4] = {0.5f, 1.0f, 1.0f, 1.0f};
139 static const GLfloat position0[4] = {0.0f, 0.0f, 20.0f, 0.0f};
140 static const GLfloat position1[4] = {0.0f, 0.0f, -20.0f, 0.0f};
141 static const GLfloat front_mat_shininess[1] = {60.0f};
142 static const GLfloat front_mat_specular[4] = {0.2f, 0.2f, 0.2f, 1.0f};
143 static const GLfloat front_mat_diffuse[4] = {0.5f, 0.28f, 0.38f, 1.0f};
144 /*
145 static const GLfloat back_mat_shininess[1] = {60.0f};
146 static const GLfloat back_mat_specular[4] = {0.5f, 0.5f, 0.2f, 1.0f};
147 static const GLfloat back_mat_diffuse[4] = {1.0f, 1.0f, 0.2f, 1.0f};
148 */
149 static const GLfloat lmodel_ambient[4] = {1.0f, 1.0f, 1.0f, 1.0f};
150 static const GLfloat lmodel_twoside[1] = {GL_FALSE};
151
152 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
153 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
154 glLightfv(GL_LIGHT0, GL_POSITION, position0);
155 glEnable(GL_LIGHT0);
156
157 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
158 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
159 glLightfv(GL_LIGHT1, GL_POSITION, position1);
160 glEnable(GL_LIGHT1);
161
162 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
163 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
164 glEnable(GL_LIGHTING);
165
166 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess);
167 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular);
168 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse);
169 }
170
171
172 static void Init(void)
173 {
174 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
175
176 glShadeModel(GL_SMOOTH);
177 glEnable(GL_DEPTH_TEST);
178
179 InitMaterials();
180
181 glMatrixMode(GL_PROJECTION);
182 glLoadIdentity();
183 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
184
185 glMatrixMode(GL_MODELVIEW);
186 glLoadIdentity();
187 glTranslatef( 0.0, 0.0, -6.0 );
188
189 #ifdef GL_EXT_vertex_array
190 if (use_vertex_arrays)
191 {
192 glVertexPointerEXT( 3, GL_FLOAT, 0, numverts, verts );
193 glNormalPointerEXT( GL_FLOAT, 0, numverts, norms );
194 glEnable( GL_VERTEX_ARRAY_EXT );
195 glEnable( GL_NORMAL_ARRAY_EXT );
196 }
197 #endif
198 }
199
200 static GLenum Args(int argc, wxChar **argv)
201 {
202 GLint i;
203
204 for (i = 1; i < argc; i++)
205 {
206 if (wxStrcmp(argv[i], _T("-sb")) == 0)
207 {
208 doubleBuffer = GL_FALSE;
209 }
210 else if (wxStrcmp(argv[i], _T("-db")) == 0)
211 {
212 doubleBuffer = GL_TRUE;
213 }
214 else if (wxStrcmp(argv[i], _T("-speed")) == 0)
215 {
216 speed_test = GL_TRUE;
217 doubleBuffer = GL_TRUE;
218 }
219 else if (wxStrcmp(argv[i], _T("-va")) == 0)
220 {
221 use_vertex_arrays = GL_TRUE;
222 }
223 else
224 {
225 wxString msg = _T("Bad option: ");
226 msg += argv[i];
227 wxMessageBox(msg);
228 return GL_FALSE;
229 }
230 }
231
232 return GL_TRUE;
233 }
234
235
236 IMPLEMENT_APP(MyApp)
237
238 // `Main program' equivalent, creating windows and returning main app frame
239 bool MyApp::OnInit()
240 {
241 if ( !wxApp::OnInit() )
242 return false;
243
244 Args(argc, argv);
245
246 // Create the main frame window
247 new MyFrame(NULL, wxT("wxWidgets OpenGL Isosurf Sample"),
248 wxDefaultPosition, wxDefaultSize);
249
250 read_surface("isosurf.dat");
251
252 Init();
253
254 return true;
255 }
256
257 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
258 EVT_MENU(wxID_EXIT, MyFrame::OnExit)
259 END_EVENT_TABLE()
260
261 // My frame constructor
262 MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
263 const wxSize& size, long style)
264 : wxFrame(frame, wxID_ANY, title, pos, size, style),
265 m_canvas(NULL)
266 {
267 SetIcon(wxICON(sample));
268
269
270 // Make a menubar
271 wxMenu *fileMenu = new wxMenu;
272
273 fileMenu->Append(wxID_EXIT, _T("E&xit"));
274 wxMenuBar *menuBar = new wxMenuBar;
275 menuBar->Append(fileMenu, _T("&File"));
276 SetMenuBar(menuBar);
277
278
279 // Make a TestGLCanvas
280
281 // JACS
282 #ifdef __WXMSW__
283 int *gl_attrib = NULL;
284 #else
285 int gl_attrib[20] = { WX_GL_RGBA, WX_GL_MIN_RED, 1, WX_GL_MIN_GREEN, 1,
286 WX_GL_MIN_BLUE, 1, WX_GL_DEPTH_SIZE, 1,
287 WX_GL_DOUBLEBUFFER,
288 # if defined(__WXMAC__) || defined(__WXCOCOA__)
289 GL_NONE };
290 # else
291 None };
292 # endif
293 #endif
294
295 if(!doubleBuffer)
296 {
297 printf("don't have double buffer, disabling\n");
298 #ifdef __WXGTK__
299 gl_attrib[9] = None;
300 #endif
301 doubleBuffer = GL_FALSE;
302 }
303
304 // Show the frame
305 Show(true);
306
307 m_canvas = new TestGLCanvas(this, wxID_ANY, wxDefaultPosition,
308 GetClientSize(), 0, _T("TestGLCanvas"), gl_attrib );
309 }
310
311 MyFrame::~MyFrame()
312 {
313 delete m_canvas;
314 }
315
316 // Intercept menu commands
317 void MyFrame::OnExit( wxCommandEvent& WXUNUSED(event) )
318 {
319 // true is to force the frame to close
320 Close(true);
321 }
322
323 /*
324 * TestGLCanvas implementation
325 */
326
327 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
328 EVT_SIZE(TestGLCanvas::OnSize)
329 EVT_PAINT(TestGLCanvas::OnPaint)
330 EVT_CHAR(TestGLCanvas::OnChar)
331 EVT_MOUSE_EVENTS(TestGLCanvas::OnMouseEvent)
332 END_EVENT_TABLE()
333
334 TestGLCanvas::TestGLCanvas(wxWindow *parent,
335 wxWindowID id,
336 const wxPoint& pos,
337 const wxSize& size,
338 long style,
339 const wxString& name,
340 int* gl_attrib)
341 : wxGLCanvas(parent, id, gl_attrib, pos, size,
342 style | wxFULL_REPAINT_ON_RESIZE, name)
343 {
344 // Explicitly create a new rendering context instance for this canvas.
345 m_glRC = new wxGLContext(this);
346
347 // Make the new context current (activate it for use) with this canvas.
348 SetCurrent(*m_glRC);
349
350 /* Make sure server supports the vertex array extension */
351 char* extensions = (char *) glGetString( GL_EXTENSIONS );
352 if (!extensions || !strstr( extensions, "GL_EXT_vertex_array" ))
353 {
354 use_vertex_arrays = GL_FALSE;
355 }
356 }
357
358 TestGLCanvas::~TestGLCanvas()
359 {
360 delete m_glRC;
361 }
362
363 void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
364 {
365 // This is a dummy, to avoid an endless succession of paint messages.
366 // OnPaint handlers must always create a wxPaintDC.
367 wxPaintDC dc(this);
368
369 // This is normally only necessary if there is more than one wxGLCanvas
370 // or more than one wxGLContext in the application.
371 SetCurrent(*m_glRC);
372
373 draw1();
374 SwapBuffers();
375 }
376
377 void TestGLCanvas::OnSize(wxSizeEvent& event)
378 {
379 // This is normally only necessary if there is more than one wxGLCanvas
380 // or more than one wxGLContext in the application.
381 SetCurrent(*m_glRC);
382
383 // It's up to the application code to update the OpenGL viewport settings.
384 // This is OK here only because there is only one canvas that uses the
385 // context. See the cube sample for that case that multiple canvases are
386 // made current with one context.
387 glViewport(0, 0, event.GetSize().x, event.GetSize().y);
388 }
389
390 void TestGLCanvas::OnChar(wxKeyEvent& event)
391 {
392 switch( event.GetKeyCode() )
393 {
394 case WXK_ESCAPE:
395 wxTheApp->ExitMainLoop();
396 return;
397
398 case WXK_LEFT:
399 yrot -= 15.0;
400 break;
401
402 case WXK_RIGHT:
403 yrot += 15.0;
404 break;
405
406 case WXK_UP:
407 xrot += 15.0;
408 break;
409
410 case WXK_DOWN:
411 xrot -= 15.0;
412 break;
413
414 case 's': case 'S':
415 smooth = !smooth;
416 if (smooth)
417 {
418 glShadeModel(GL_SMOOTH);
419 }
420 else
421 {
422 glShadeModel(GL_FLAT);
423 }
424 break;
425
426 case 'l': case 'L':
427 lighting = !lighting;
428 if (lighting)
429 {
430 glEnable(GL_LIGHTING);
431 }
432 else
433 {
434 glDisable(GL_LIGHTING);
435 }
436 break;
437
438 default:
439 event.Skip();
440 return;
441 }
442
443 Refresh(false);
444 }
445
446 void TestGLCanvas::OnMouseEvent(wxMouseEvent& event)
447 {
448 static int dragging = 0;
449 static float last_x, last_y;
450
451 // Allow default processing to happen, or else the canvas cannot gain focus
452 // (for key events).
453 event.Skip();
454
455 if(event.LeftIsDown())
456 {
457 if(!dragging)
458 {
459 dragging = 1;
460 }
461 else
462 {
463 yrot += (event.GetX() - last_x)*1.0;
464 xrot += (event.GetY() - last_y)*1.0;
465 Refresh(false);
466 }
467 last_x = event.GetX();
468 last_y = event.GetY();
469 }
470 else
471 {
472 dragging = 0;
473 }
474 }
475