]> git.saurik.com Git - wxWidgets.git/blame - samples/opengl/isosurf/isosurf.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / samples / opengl / isosurf / isosurf.cpp
CommitLineData
8b089c5e
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: isosurf.cpp
3// Purpose: wxGLCanvas demo program
4// Author: Brian Paul (original gltk version), Wolfram Gloger
0c1c1c71 5// Modified by: Julian Smart, Francesco Montorsi
8b089c5e 6// Created: 04/01/98
8b089c5e 7// Copyright: (c) Julian Smart
2f6c54eb 8// Licence: wxWindows licence
8b089c5e
JS
9/////////////////////////////////////////////////////////////////////////////
10
8b089c5e
JS
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
806e2f15
VZ
22#if !wxUSE_GLCANVAS
23 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
24#endif
25
8b089c5e
JS
26#include "wx/timer.h"
27#include "wx/glcanvas.h"
b713f891 28#include "wx/math.h"
6c7f0949
FM
29#include "wx/log.h"
30#include "wx/cmdline.h"
6c7f0949
FM
31#include "wx/wfstream.h"
32#include "wx/zstream.h"
0c1c1c71 33#include "wx/txtstrm.h"
8b089c5e 34
451c13c8 35#include "isosurf.h"
3a992940
JS
36#include "../../sample.xpm"
37
8b089c5e 38
6c7f0949 39// global options which can be set through command-line options
6c7f0949
FM
40GLboolean g_use_vertex_arrays = GL_FALSE;
41GLboolean g_doubleBuffer = GL_TRUE;
42GLboolean g_smooth = GL_TRUE;
43GLboolean g_lighting = GL_TRUE;
8b089c5e 44
8b089c5e
JS
45
46
6c7f0949
FM
47//---------------------------------------------------------------------------
48// MyApp
49//---------------------------------------------------------------------------
8b089c5e 50
6c7f0949 51IMPLEMENT_APP(MyApp)
8b089c5e 52
6c7f0949 53bool MyApp::OnInit()
8b089c5e 54{
6c7f0949
FM
55 if ( !wxApp::OnInit() )
56 return false;
5cf036d0 57
6c7f0949 58 // Create the main frame window
e2250d64 59 new MyFrame(NULL, wxT("wxWidgets OpenGL Isosurf Sample"));
5cf036d0 60
6c7f0949 61 return true;
8b089c5e
JS
62}
63
6c7f0949 64void MyApp::OnInitCmdLine(wxCmdLineParser& parser)
8b089c5e 65{
7881f83b
FM
66 parser.AddSwitch("", "sb", "Do not use double buffering");
67 parser.AddSwitch("", "db", "Use double buffering");
68 parser.AddSwitch("", "va", "Use vertex arrays");
8b089c5e 69
6c7f0949 70 wxApp::OnInitCmdLine(parser);
8b089c5e
JS
71}
72
6c7f0949 73bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser)
8b089c5e 74{
7881f83b 75 if (parser.Found("sb"))
6c7f0949 76 g_doubleBuffer = GL_FALSE;
7881f83b 77 else if (parser.Found("db"))
6c7f0949 78 g_doubleBuffer = GL_TRUE;
8b089c5e 79
7881f83b 80 if (parser.Found("va"))
6c7f0949 81 g_use_vertex_arrays = GL_TRUE;
5cf036d0 82
6c7f0949 83 return wxApp::OnCmdLineParsed(parser);
8b089c5e
JS
84}
85
6c7f0949
FM
86//---------------------------------------------------------------------------
87// MyFrame
88//---------------------------------------------------------------------------
451c13c8
VZ
89
90BEGIN_EVENT_TABLE(MyFrame, wxFrame)
91 EVT_MENU(wxID_EXIT, MyFrame::OnExit)
92END_EVENT_TABLE()
93
451c13c8 94MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
df344ba9 95 const wxSize& size, long style)
451c13c8
VZ
96 : wxFrame(frame, wxID_ANY, title, pos, size, style),
97 m_canvas(NULL)
98{
99 SetIcon(wxICON(sample));
100
101
5cf036d0
DS
102 // Make a menubar
103 wxMenu *fileMenu = new wxMenu;
8b089c5e 104
9a83f860 105 fileMenu->Append(wxID_EXIT, wxT("E&xit"));
5cf036d0 106 wxMenuBar *menuBar = new wxMenuBar;
9a83f860 107 menuBar->Append(fileMenu, wxT("&File"));
451c13c8
VZ
108 SetMenuBar(menuBar);
109
8b089c5e
JS
110
111 // Make a TestGLCanvas
112
113 // JACS
114#ifdef __WXMSW__
5cf036d0 115 int *gl_attrib = NULL;
8b089c5e 116#else
6c7f0949
FM
117 int gl_attrib[20] =
118 { WX_GL_RGBA, WX_GL_MIN_RED, 1, WX_GL_MIN_GREEN, 1,
5cf036d0
DS
119 WX_GL_MIN_BLUE, 1, WX_GL_DEPTH_SIZE, 1,
120 WX_GL_DOUBLEBUFFER,
6716fce4 121# if defined(__WXMAC__) || defined(__WXCOCOA__)
5cf036d0 122 GL_NONE };
cb712074 123# else
5cf036d0 124 None };
cb712074 125# endif
8b089c5e
JS
126#endif
127
6c7f0949 128 if (!g_doubleBuffer)
5cf036d0 129 {
0c1c1c71 130 wxLogWarning("Disabling double buffering");
6c7f0949 131
8b089c5e 132#ifdef __WXGTK__
5cf036d0 133 gl_attrib[9] = None;
8b089c5e 134#endif
6c7f0949 135 g_doubleBuffer = GL_FALSE;
5cf036d0
DS
136 }
137
97f85100
VZ
138 m_canvas = new TestGLCanvas(this, wxID_ANY, gl_attrib);
139
451c13c8
VZ
140 // Show the frame
141 Show(true);
97f85100 142 Raise();
8b089c5e 143
97f85100 144 m_canvas->InitGL();
8b089c5e
JS
145}
146
5cf036d0
DS
147MyFrame::~MyFrame()
148{
806e2f15 149 delete m_canvas;
5cf036d0
DS
150}
151
8b089c5e 152// Intercept menu commands
5cf036d0 153void MyFrame::OnExit( wxCommandEvent& WXUNUSED(event) )
8b089c5e 154{
5cf036d0
DS
155 // true is to force the frame to close
156 Close(true);
8b089c5e
JS
157}
158
6c7f0949
FM
159
160//---------------------------------------------------------------------------
161// TestGLCanvas
162//---------------------------------------------------------------------------
8b089c5e
JS
163
164BEGIN_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)
8b089c5e
JS
169END_EVENT_TABLE()
170
451c13c8
VZ
171TestGLCanvas::TestGLCanvas(wxWindow *parent,
172 wxWindowID id,
451c13c8 173 int* gl_attrib)
0c1c1c71 174 : wxGLCanvas(parent, id, gl_attrib)
8b089c5e 175{
0c1c1c71
FM
176 m_xrot = 0;
177 m_yrot = 0;
178 m_numverts = 0;
179
451c13c8
VZ
180 // Explicitly create a new rendering context instance for this canvas.
181 m_glRC = new wxGLContext(this);
8b089c5e
JS
182}
183
451c13c8
VZ
184TestGLCanvas::~TestGLCanvas()
185{
186 delete m_glRC;
187}
8b089c5e 188
6c7f0949
FM
189void TestGLCanvas::LoadSurface(const wxString& filename)
190{
0c1c1c71
FM
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
6c7f0949
FM
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
6c7f0949 206 {
0c1c1c71 207 // we suppose to have in input a text file containing floating numbers
4c51a665 208 // space/newline-separated... first 3 numbers are the coordinates of a
0c1c1c71
FM
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--;
6c7f0949
FM
224 }
225
226 delete stream;
227
9a83f860 228 wxLogMessage(wxT("Loaded %d vertices, %d triangles from '%s'"),
6c7f0949 229 m_numverts, m_numverts-2, filename.c_str());
ce00f59b 230
df344ba9
FM
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();
6c7f0949
FM
234}
235
2db98bf5 236void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
8b089c5e
JS
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
451c13c8
VZ
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);
919ae91a 245
6c7f0949
FM
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
0c1c1c71 252 if (g_use_vertex_arrays)
6c7f0949
FM
253 {
254 glDrawArrays( GL_TRIANGLE_STRIP, 0, m_numverts );
255 }
0c1c1c71 256 else
6c7f0949
FM
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
8b089c5e
JS
272 SwapBuffers();
273}
274
275void TestGLCanvas::OnSize(wxSizeEvent& event)
276{
97f85100
VZ
277 if ( !IsShownOnScreen() )
278 return;
451c13c8
VZ
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);
8b089c5e
JS
288}
289
290void TestGLCanvas::OnChar(wxKeyEvent& event)
291{
5cf036d0
DS
292 switch( event.GetKeyCode() )
293 {
8b089c5e 294 case WXK_ESCAPE:
5cf036d0
DS
295 wxTheApp->ExitMainLoop();
296 return;
297
8b089c5e 298 case WXK_LEFT:
6c7f0949 299 m_yrot -= 15.0;
5cf036d0
DS
300 break;
301
8b089c5e 302 case WXK_RIGHT:
6c7f0949 303 m_yrot += 15.0;
5cf036d0
DS
304 break;
305
8b089c5e 306 case WXK_UP:
6c7f0949 307 m_xrot += 15.0;
5cf036d0
DS
308 break;
309
8b089c5e 310 case WXK_DOWN:
6c7f0949 311 m_xrot -= 15.0;
5cf036d0
DS
312 break;
313
8b089c5e 314 case 's': case 'S':
6c7f0949
FM
315 g_smooth = !g_smooth;
316 if (g_smooth)
5cf036d0 317 glShadeModel(GL_SMOOTH);
5cf036d0 318 else
5cf036d0 319 glShadeModel(GL_FLAT);
5cf036d0
DS
320 break;
321
8b089c5e 322 case 'l': case 'L':
6c7f0949
FM
323 g_lighting = !g_lighting;
324 if (g_lighting)
5cf036d0 325 glEnable(GL_LIGHTING);
5cf036d0 326 else
5cf036d0 327 glDisable(GL_LIGHTING);
5cf036d0
DS
328 break;
329
330 default:
8b089c5e 331 event.Skip();
5cf036d0 332 return;
8b089c5e
JS
333 }
334
5cf036d0 335 Refresh(false);
8b089c5e
JS
336}
337
338void TestGLCanvas::OnMouseEvent(wxMouseEvent& event)
339{
340 static int dragging = 0;
341 static float last_x, last_y;
342
451c13c8
VZ
343 // Allow default processing to happen, or else the canvas cannot gain focus
344 // (for key events).
345 event.Skip();
346
df344ba9 347 if (event.LeftIsDown())
5cf036d0 348 {
df344ba9 349 if (!dragging)
5cf036d0
DS
350 {
351 dragging = 1;
352 }
353 else
354 {
6c7f0949
FM
355 m_yrot += (event.GetX() - last_x)*1.0;
356 m_xrot += (event.GetY() - last_y)*1.0;
5cf036d0
DS
357 Refresh(false);
358 }
359 last_x = event.GetX();
360 last_y = event.GetY();
2f6c54eb 361 }
5cf036d0 362 else
451c13c8 363 {
5cf036d0 364 dragging = 0;
451c13c8 365 }
8b089c5e
JS
366}
367
6c7f0949
FM
368void 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
404void TestGLCanvas::InitGL()
405{
97f85100
VZ
406 // Make the new context current (activate it for use) with this canvas.
407 SetCurrent(*m_glRC);
408
6c7f0949
FM
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 );
0c1c1c71
FM
428 glEnable( GL_VERTEX_ARRAY );
429 glEnable( GL_NORMAL_ARRAY );
6c7f0949 430 }
97f85100
VZ
431
432 InitMaterials();
433 LoadSurface("isosurf.dat.gz");
6c7f0949
FM
434}
435