X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2f6c54eb076d760cbb6fb15e899f15fbbd575850..8584b0e64b273273bad122d28b10176bd5a3bc84:/samples/opengl/isosurf/isosurf.cpp diff --git a/samples/opengl/isosurf/isosurf.cpp b/samples/opengl/isosurf/isosurf.cpp index 895c3d44e3..a2ea654f91 100644 --- a/samples/opengl/isosurf/isosurf.cpp +++ b/samples/opengl/isosurf/isosurf.cpp @@ -2,18 +2,13 @@ // Name: isosurf.cpp // Purpose: wxGLCanvas demo program // Author: Brian Paul (original gltk version), Wolfram Gloger -// Modified by: Julian Smart +// Modified by: Julian Smart, Francesco Montorsi // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation -#pragma interface -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -26,398 +21,321 @@ #endif #if !wxUSE_GLCANVAS -#error Please set wxUSE_GLCANVAS to 1 in setup.h. + #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" #endif #include "wx/timer.h" #include "wx/glcanvas.h" - -#ifdef __WXMAC__ -# ifdef __DARWIN__ -# include <OpenGL/gl.h> -# include <OpenGL/glu.h> -# else -# include <gl.h> -# include <glu.h> -# endif -#else -# include <GL/gl.h> -# include <GL/glu.h> -#endif - -// disabled because this has apparently changed in OpenGL 1.2, so doesn't link -// correctly if this is on... -#ifdef GL_EXT_vertex_array -#undef GL_EXT_vertex_array -#endif +#include "wx/math.h" +#include "wx/log.h" +#include "wx/cmdline.h" +#include "wx/wfstream.h" +#include "wx/zstream.h" +#include "wx/txtstrm.h" #include "isosurf.h" +#include "../../sample.xpm" -// The following part is taken largely unchanged from the original C Version - -#include <math.h> -GLboolean speed_test = GL_FALSE; -GLboolean use_vertex_arrays = GL_FALSE; +// global options which can be set through command-line options +GLboolean g_use_vertex_arrays = GL_FALSE; +GLboolean g_doubleBuffer = GL_TRUE; +GLboolean g_smooth = GL_TRUE; +GLboolean g_lighting = GL_TRUE; -GLboolean doubleBuffer = GL_TRUE; -GLboolean smooth = GL_TRUE; -GLboolean lighting = GL_TRUE; +//--------------------------------------------------------------------------- +// MyApp +//--------------------------------------------------------------------------- -#define MAXVERTS 10000 - -static GLfloat verts[MAXVERTS][3]; -static GLfloat norms[MAXVERTS][3]; -static GLint numverts; - -static GLfloat xrot; -static GLfloat yrot; - +IMPLEMENT_APP(MyApp) -static void read_surface( char *filename ) +bool MyApp::OnInit() { - FILE *f; - - f = fopen(filename,"r"); - if (!f) { - wxString msg("Couldn't read "); - msg += filename; - wxMessageBox(msg); - return; - } - - numverts = 0; - while (!feof(f) && numverts<MAXVERTS) { - fscanf( f, "%f %f %f %f %f %f", - &verts[numverts][0], &verts[numverts][1], &verts[numverts][2], - &norms[numverts][0], &norms[numverts][1], &norms[numverts][2] ); - numverts++; - } - numverts--; - - printf("%d vertices, %d triangles\n", numverts, numverts-2); - fclose(f); -} + if ( !wxApp::OnInit() ) + return false; + // Create the main frame window + MyFrame *frame = new MyFrame(NULL, wxT("wxWidgets OpenGL Isosurf Sample")); -static void draw_surface( void ) -{ - GLint i; - -#ifdef GL_EXT_vertex_array - if (use_vertex_arrays) { - glDrawArraysEXT( GL_TRIANGLE_STRIP, 0, numverts ); - } - else { -#endif - glBegin( GL_TRIANGLE_STRIP ); - for (i=0;i<numverts;i++) { - glNormal3fv( norms[i] ); - glVertex3fv( verts[i] ); - } - glEnd(); -#ifdef GL_EXT_vertex_array - } -#endif + return true; } - -static void draw1(void) +void MyApp::OnInitCmdLine(wxCmdLineParser& parser) { - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glPushMatrix(); - glRotatef( yrot, 0.0, 1.0, 0.0 ); - glRotatef( xrot, 1.0, 0.0, 0.0 ); + parser.AddSwitch("", "sb", "Do not use double buffering"); + parser.AddSwitch("", "db", "Use double buffering"); + parser.AddSwitch("", "va", "Use vertex arrays"); - draw_surface(); - - glPopMatrix(); - - glFlush(); + wxApp::OnInitCmdLine(parser); } - -static void InitMaterials(void) +bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser) { - static float ambient[] = {0.1, 0.1, 0.1, 1.0}; - static float diffuse[] = {0.5, 1.0, 1.0, 1.0}; - static float position0[] = {0.0, 0.0, 20.0, 0.0}; - static float position1[] = {0.0, 0.0, -20.0, 0.0}; - static float front_mat_shininess[] = {60.0}; - static float front_mat_specular[] = {0.2, 0.2, 0.2, 1.0}; - static float front_mat_diffuse[] = {0.5, 0.28, 0.38, 1.0}; - /* - static float back_mat_shininess[] = {60.0}; - static float back_mat_specular[] = {0.5, 0.5, 0.2, 1.0}; - static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0}; - */ - static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0}; - static float lmodel_twoside[] = {GL_FALSE}; + if (parser.Found("sb")) + g_doubleBuffer = GL_FALSE; + else if (parser.Found("db")) + g_doubleBuffer = GL_TRUE; - glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); - glLightfv(GL_LIGHT0, GL_POSITION, position0); - glEnable(GL_LIGHT0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse); - glLightfv(GL_LIGHT1, GL_POSITION, position1); - glEnable(GL_LIGHT1); - - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); - glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside); - glEnable(GL_LIGHTING); - - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse); -} - - -static void Init(void) -{ - glClearColor(0.0, 0.0, 0.0, 0.0); - - glShadeModel(GL_SMOOTH); - glEnable(GL_DEPTH_TEST); - - InitMaterials(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum( -1.0, 1.0, -1.0, 1.0, 5, 25 ); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef( 0.0, 0.0, -6.0 ); + if (parser.Found("va")) + g_use_vertex_arrays = GL_TRUE; -#ifdef GL_EXT_vertex_array - if (use_vertex_arrays) { - glVertexPointerEXT( 3, GL_FLOAT, 0, numverts, verts ); - glNormalPointerEXT( GL_FLOAT, 0, numverts, norms ); - glEnable( GL_VERTEX_ARRAY_EXT ); - glEnable( GL_NORMAL_ARRAY_EXT ); - } -#endif -} - -static GLenum Args(int argc, char **argv) -{ - GLint i; - - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-sb") == 0) { - doubleBuffer = GL_FALSE; - } - else if (strcmp(argv[i], "-db") == 0) { - doubleBuffer = GL_TRUE; - } - else if (strcmp(argv[i], "-speed") == 0) { - speed_test = GL_TRUE; - doubleBuffer = GL_TRUE; - } - else if (strcmp(argv[i], "-va") == 0) { - use_vertex_arrays = GL_TRUE; - } - else { - wxString msg("Bad option: "); - msg += argv[i]; - wxMessageBox(msg); - return GL_FALSE; - } - } - - return GL_TRUE; + return wxApp::OnCmdLineParsed(parser); } -// The following part was written for wxWindows 1.66 -MyFrame *frame = NULL; +//--------------------------------------------------------------------------- +// MyFrame +//--------------------------------------------------------------------------- -IMPLEMENT_APP(MyApp) +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(wxID_EXIT, MyFrame::OnExit) +END_EVENT_TABLE() -// `Main program' equivalent, creating windows and returning main app frame -bool MyApp::OnInit(void) +MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, + const wxSize& size, long style) + : wxFrame(frame, wxID_ANY, title, pos, size, style), + m_canvas(NULL) { - Args(argc, argv); + SetIcon(wxICON(sample)); - // Create the main frame window - frame = new MyFrame(NULL, "Isosurf GL Sample", wxPoint(50, 50), wxSize(200, 200)); - // Give it an icon - frame->SetIcon(wxIcon("mondrian")); + // Make a menubar + wxMenu *fileMenu = new wxMenu; - // Make a menubar - wxMenu *fileMenu = new wxMenu; + fileMenu->Append(wxID_EXIT, wxT("E&xit")); + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(fileMenu, wxT("&File")); + SetMenuBar(menuBar); - fileMenu->Append(wxID_EXIT, "E&xit"); - wxMenuBar *menuBar = new wxMenuBar; - menuBar->Append(fileMenu, "&File"); - frame->SetMenuBar(menuBar); // Make a TestGLCanvas // JACS #ifdef __WXMSW__ - int *gl_attrib = NULL; + int *gl_attrib = NULL; #else - int gl_attrib[20] = { WX_GL_RGBA, WX_GL_MIN_RED, 1, WX_GL_MIN_GREEN, 1, - WX_GL_MIN_BLUE, 1, WX_GL_DEPTH_SIZE, 1, - WX_GL_DOUBLEBUFFER, -# ifdef __WXMAC__ - GL_NONE }; + int gl_attrib[20] = + { WX_GL_RGBA, WX_GL_MIN_RED, 1, WX_GL_MIN_GREEN, 1, + WX_GL_MIN_BLUE, 1, WX_GL_DEPTH_SIZE, 1, + WX_GL_DOUBLEBUFFER, +# if defined(__WXMAC__) || defined(__WXCOCOA__) + GL_NONE }; # else - None }; + None }; # endif #endif - if(!doubleBuffer) - { - printf("don't have double buffer, disabling\n"); + if (!g_doubleBuffer) + { + wxLogWarning("Disabling double buffering"); + #ifdef __WXGTK__ - gl_attrib[9] = None; + gl_attrib[9] = None; #endif - doubleBuffer = GL_FALSE; - } - - frame->m_canvas = new TestGLCanvas(frame, -1, wxDefaultPosition, wxDefaultSize, - 0, "TestGLCanvas", gl_attrib ); - - // Show the frame - frame->Show(TRUE); - - frame->m_canvas->SetCurrent(); - read_surface( "isosurf.dat" ); + g_doubleBuffer = GL_FALSE; + } - Init(); + // Show the frame + Show(true); - return TRUE; + m_canvas = new TestGLCanvas(this, wxID_ANY, gl_attrib); } -BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(wxID_EXIT, MyFrame::OnExit) -END_EVENT_TABLE() - -// My frame constructor -MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, - const wxSize& size, long style): - wxFrame(frame, -1, title, pos, size, style) +MyFrame::~MyFrame() { - m_canvas = NULL; + delete m_canvas; } // Intercept menu commands -void MyFrame::OnExit(wxCommandEvent& event) +void MyFrame::OnExit( wxCommandEvent& WXUNUSED(event) ) { - Destroy(); + // true is to force the frame to close + Close(true); } -/* - * TestGLCanvas implementation - */ + +//--------------------------------------------------------------------------- +// TestGLCanvas +//--------------------------------------------------------------------------- BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) EVT_SIZE(TestGLCanvas::OnSize) EVT_PAINT(TestGLCanvas::OnPaint) EVT_CHAR(TestGLCanvas::OnChar) EVT_MOUSE_EVENTS(TestGLCanvas::OnMouseEvent) - EVT_ERASE_BACKGROUND(TestGLCanvas::OnEraseBackground) END_EVENT_TABLE() -TestGLCanvas::TestGLCanvas(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, long style, const wxString& name, int* gl_attrib): - wxGLCanvas(parent, id, pos, size, style, name, gl_attrib) +TestGLCanvas::TestGLCanvas(wxWindow *parent, + wxWindowID id, + int* gl_attrib) + : wxGLCanvas(parent, id, gl_attrib) { - parent->Show(TRUE); - SetCurrent(); - - /* Make sure server supports the vertex array extension */ - char* extensions = (char *) glGetString( GL_EXTENSIONS ); - if (!extensions || !strstr( extensions, "GL_EXT_vertex_array" )) { - use_vertex_arrays = GL_FALSE; - } + m_xrot = 0; + m_yrot = 0; + m_numverts = 0; + + // Explicitly create a new rendering context instance for this canvas. + m_glRC = new wxGLContext(this); + + // Make the new context current (activate it for use) with this canvas. + SetCurrent(*m_glRC); + + InitGL(); + InitMaterials(); + LoadSurface("isosurf.dat.gz"); } +TestGLCanvas::~TestGLCanvas() +{ + delete m_glRC; +} -TestGLCanvas::~TestGLCanvas(void) +void TestGLCanvas::LoadSurface(const wxString& filename) { + // FIXME + // we need to set english locale to force wxTextInputStream's calls to + // wxStrtod to use the point and not the comma as decimal separator... + // (the isosurf.dat contains points and not commas)... + wxLocale l(wxLANGUAGE_ENGLISH); + + wxZlibInputStream* stream = + new wxZlibInputStream(new wxFFileInputStream(filename)); + if (!stream || !stream->IsOk()) + { + wxLogError("Cannot load '%s' type of files!", filename.c_str()); + delete stream; + return; + } + + { + // we suppose to have in input a text file containing floating numbers + // space/newline-separed... first 3 numbers are the coordinates of a + // vertex and the following 3 are the relative vertex normal and so on... + + wxTextInputStream inFile(*stream); + m_numverts = 0; + + while (!stream->Eof() && m_numverts < MAXVERTS)// && m_numverts<MAXVERTS) + { + inFile >> m_verts[m_numverts][0] >> m_verts[m_numverts][1] >> m_verts[m_numverts][2]; + inFile >> m_norms[m_numverts][0] >> m_norms[m_numverts][1] >> m_norms[m_numverts][2]; + + m_numverts++; + } + + // discard last vertex; it is a zero caused by the EOF + m_numverts--; + } + + delete stream; + + wxLogMessage(wxT("Loaded %d vertices, %d triangles from '%s'"), + m_numverts, m_numverts-2, filename.c_str()); + + // NOTE: for some reason under wxGTK the following is required to avoid that + // the surface gets rendered in a small rectangle in the top-left corner of the frame + PostSizeEventToParent(); } -void TestGLCanvas::OnPaint( wxPaintEvent& event ) +void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) ) { // This is a dummy, to avoid an endless succession of paint messages. // OnPaint handlers must always create a wxPaintDC. wxPaintDC dc(this); -#ifndef __WXMOTIF__ - if (!GetContext()) return; -#endif + // This is normally only necessary if there is more than one wxGLCanvas + // or more than one wxGLContext in the application. + SetCurrent(*m_glRC); - SetCurrent(); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glPushMatrix(); + glRotatef( m_yrot, 0.0f, 1.0f, 0.0f ); + glRotatef( m_xrot, 1.0f, 0.0f, 0.0f ); + + // draw the surface + if (g_use_vertex_arrays) + { + glDrawArrays( GL_TRIANGLE_STRIP, 0, m_numverts ); + } + else + { + glBegin( GL_TRIANGLE_STRIP ); + + for (int i=0;i<m_numverts;i++) + { + glNormal3fv( m_norms[i] ); + glVertex3fv( m_verts[i] ); + } + + glEnd(); + } + + glPopMatrix(); + glFlush(); // Not really necessary: buffer swapping below implies glFlush() - draw1(); SwapBuffers(); } void TestGLCanvas::OnSize(wxSizeEvent& event) { - // this is also necessary to update the context on some platforms - wxGLCanvas::OnSize(event); - - // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...) - int w, h; - GetClientSize(&w, &h); -#ifndef __WXMOTIF__ - if (GetContext()) -#endif - { - SetCurrent(); - glViewport(0, 0, (GLint) w, (GLint) h); - } + // This is normally only necessary if there is more than one wxGLCanvas + // or more than one wxGLContext in the application. + SetCurrent(*m_glRC); + + // It's up to the application code to update the OpenGL viewport settings. + // This is OK here only because there is only one canvas that uses the + // context. See the cube sample for that case that multiple canvases are + // made current with one context. + glViewport(0, 0, event.GetSize().x, event.GetSize().y); } void TestGLCanvas::OnChar(wxKeyEvent& event) { - switch(event.KeyCode()) { + switch( event.GetKeyCode() ) + { case WXK_ESCAPE: - exit(0); + wxTheApp->ExitMainLoop(); + return; + case WXK_LEFT: - yrot -= 15.0; - break; + m_yrot -= 15.0; + break; + case WXK_RIGHT: - yrot += 15.0; - break; + m_yrot += 15.0; + break; + case WXK_UP: - xrot += 15.0; - break; + m_xrot += 15.0; + break; + case WXK_DOWN: - xrot -= 15.0; - break; + m_xrot -= 15.0; + break; + case 's': case 'S': - smooth = !smooth; - if (smooth) { - glShadeModel(GL_SMOOTH); - } else { - glShadeModel(GL_FLAT); - } - break; + g_smooth = !g_smooth; + if (g_smooth) + glShadeModel(GL_SMOOTH); + else + glShadeModel(GL_FLAT); + break; + case 'l': case 'L': - lighting = !lighting; - if (lighting) { - glEnable(GL_LIGHTING); - } else { - glDisable(GL_LIGHTING); - } - break; - default: - { + g_lighting = !g_lighting; + if (g_lighting) + glEnable(GL_LIGHTING); + else + glDisable(GL_LIGHTING); + break; + + default: event.Skip(); - return; - } + return; } - Refresh(FALSE); + Refresh(false); } void TestGLCanvas::OnMouseEvent(wxMouseEvent& event) @@ -425,23 +343,90 @@ void TestGLCanvas::OnMouseEvent(wxMouseEvent& event) static int dragging = 0; static float last_x, last_y; - //printf("%f %f %d\n", event.GetX(), event.GetY(), (int)event.LeftIsDown()); - if(event.LeftIsDown()) { - if(!dragging) { - dragging = 1; - } else { - yrot += (event.GetX() - last_x)*1.0; - xrot += (event.GetY() - last_y)*1.0; - Refresh(FALSE); + // Allow default processing to happen, or else the canvas cannot gain focus + // (for key events). + event.Skip(); + + if (event.LeftIsDown()) + { + if (!dragging) + { + dragging = 1; + } + else + { + m_yrot += (event.GetX() - last_x)*1.0; + m_xrot += (event.GetY() - last_y)*1.0; + Refresh(false); + } + last_x = event.GetX(); + last_y = event.GetY(); } - last_x = event.GetX(); - last_y = event.GetY(); - } else - dragging = 0; + else + { + dragging = 0; + } +} + +void TestGLCanvas::InitMaterials() +{ + static const GLfloat ambient[4] = {0.1f, 0.1f, 0.1f, 1.0f}; + static const GLfloat diffuse[4] = {0.5f, 1.0f, 1.0f, 1.0f}; + static const GLfloat position0[4] = {0.0f, 0.0f, 20.0f, 0.0f}; + static const GLfloat position1[4] = {0.0f, 0.0f, -20.0f, 0.0f}; + static const GLfloat front_mat_shininess[1] = {60.0f}; + static const GLfloat front_mat_specular[4] = {0.2f, 0.2f, 0.2f, 1.0f}; + static const GLfloat front_mat_diffuse[4] = {0.5f, 0.28f, 0.38f, 1.0f}; + /* + static const GLfloat back_mat_shininess[1] = {60.0f}; + static const GLfloat back_mat_specular[4] = {0.5f, 0.5f, 0.2f, 1.0f}; + static const GLfloat back_mat_diffuse[4] = {1.0f, 1.0f, 0.2f, 1.0f}; + */ + static const GLfloat lmodel_ambient[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + static const GLfloat lmodel_twoside[1] = {GL_FALSE}; + + glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); + glLightfv(GL_LIGHT0, GL_POSITION, position0); + glEnable(GL_LIGHT0); + + glLightfv(GL_LIGHT1, GL_AMBIENT, ambient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse); + glLightfv(GL_LIGHT1, GL_POSITION, position1); + glEnable(GL_LIGHT1); + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); + glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside); + glEnable(GL_LIGHTING); + + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse); } -void TestGLCanvas::OnEraseBackground(wxEraseEvent& event) +void TestGLCanvas::InitGL() { - // Do nothing, to avoid flashing. + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + glShadeModel(GL_SMOOTH); + glEnable(GL_DEPTH_TEST); + + InitMaterials(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 ); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -6.0 ); + + if (g_use_vertex_arrays) + { + glVertexPointer( 3, GL_FLOAT, 0, m_verts ); + glNormalPointer( GL_FLOAT, 0, m_norms ); + glEnable( GL_VERTEX_ARRAY ); + glEnable( GL_NORMAL_ARRAY ); + } }