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