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