X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2db98bf520c835c29a9002dcf93adc11b15a76df..75a2c6a1ee034a5d866b4a121a97351603bce98b:/samples/opengl/penguin/penguin.cpp diff --git a/samples/opengl/penguin/penguin.cpp b/samples/opengl/penguin/penguin.cpp index b1e573bd9b..e18cb95adc 100644 --- a/samples/opengl/penguin/penguin.cpp +++ b/samples/opengl/penguin/penguin.cpp @@ -2,18 +2,13 @@ // Name: penguin.cpp // Purpose: wxGLCanvas demo program // Author: Robert Roebling -// Modified by: +// Modified by: Sandro Sigala // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Robert Roebling // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation -#pragma interface -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -25,76 +20,119 @@ #include "wx/wx.h" #endif +#if !wxUSE_GLCANVAS + #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" +#endif + #include "penguin.h" -#ifdef __WXMAC__ -# ifdef __DARWIN__ -# include -# else -# include -# endif +#ifdef __DARWIN__ + #include #else -# include + #include #endif -#define VIEW_ASPECT 1.3 +#include "../../sample.xpm" -/* `Main program' equivalent, creating windows and returning main app frame */ +// --------------------------------------------------------------------------- +// MyApp +// --------------------------------------------------------------------------- + +// `Main program' equivalent, creating windows and returning main app frame bool MyApp::OnInit() { + if ( !wxApp::OnInit() ) + return false; - /* Create the main frame window */ - MyFrame *frame = new MyFrame(NULL, wxT("wxWindows OpenGL Demo"), wxPoint(50, 50), wxSize(400, 300)); - - /* Make a menubar */ - wxMenu *fileMenu = new wxMenu; - - fileMenu->Append(wxID_EXIT, wxT("E&xit")); - wxMenuBar *menuBar = new wxMenuBar; - menuBar->Append(fileMenu, wxT("&File")); - frame->SetMenuBar(menuBar); - -#if wxUSE_GLCANVAS - frame->SetCanvas( new TestGLCanvas(frame, -1, wxPoint(0, 0), wxSize(200, 200), wxSUNKEN_BORDER) ); + // Create the main frame window + MyFrame *frame = new MyFrame(NULL, wxT("wxWidgets Penguin Sample"), + wxDefaultPosition, wxDefaultSize); - /* Load file wiht mesh data */ - frame->GetCanvas()->LoadLWO( wxT("penguin.lwo") ); - - /* Show the frame */ - frame->Show(TRUE); - - return TRUE; +#if wxUSE_ZLIB + if (wxFileExists(wxT("penguin.dxf.gz"))) + frame->GetCanvas()->LoadDXF(wxT("penguin.dxf.gz")); #else + if (wxFileExists(wxT("penguin.dxf"))) + frame->GetCanvas()->LoadDXF(wxT("penguin.dxf")); +#endif - wxMessageBox( _T("This sample has to be compiled with wxUSE_GLCANVAS"), _T("Building error"), wxOK); - - return FALSE; + /* Show the frame */ + frame->Show(true); -#endif + return true; } IMPLEMENT_APP(MyApp) +// --------------------------------------------------------------------------- +// MyFrame +// --------------------------------------------------------------------------- + BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(wxID_EXIT, MyFrame::OnExit) + EVT_MENU(wxID_OPEN, MyFrame::OnMenuFileOpen) + EVT_MENU(wxID_EXIT, MyFrame::OnMenuFileExit) + EVT_MENU(wxID_HELP, MyFrame::OnMenuHelpAbout) END_EVENT_TABLE() -/* My frame constructor */ +// MyFrame constructor MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, - const wxSize& size, long style): - wxFrame(frame, -1, title, pos, size, style) + const wxSize& size, long style) + : wxFrame(frame, wxID_ANY, title, pos, size, style) { -#if wxUSE_GLCANVAS - m_canvas = NULL; + SetIcon(wxIcon(sample_xpm)); + + // Make the "File" menu + wxMenu *fileMenu = new wxMenu; + fileMenu->Append(wxID_OPEN, wxT("&Open...")); + fileMenu->AppendSeparator(); + fileMenu->Append(wxID_EXIT, wxT("E&xit\tALT-X")); + // Make the "Help" menu + wxMenu *helpMenu = new wxMenu; + helpMenu->Append(wxID_HELP, wxT("&About...")); + + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(fileMenu, wxT("&File")); + menuBar->Append(helpMenu, wxT("&Help")); + SetMenuBar(menuBar); + + Show(true); + + m_canvas = new TestGLCanvas(this, wxID_ANY, wxDefaultPosition, + GetClientSize(), wxSUNKEN_BORDER); +} + +// File|Open... command +void MyFrame::OnMenuFileOpen( wxCommandEvent& WXUNUSED(event) ) +{ + wxString filename = wxFileSelector(wxT("Choose DXF Model"), wxT(""), wxT(""), wxT(""), +#if wxUSE_ZLIB + wxT("DXF Drawing (*.dxf;*.dxf.gz)|*.dxf;*.dxf.gz|All files (*.*)|*.*"), +#else + wxT("DXF Drawing (*.dxf)|*.dxf)|All files (*.*)|*.*"), #endif + wxFD_OPEN); + if (!filename.IsEmpty()) + { + m_canvas->LoadDXF(filename); + m_canvas->Refresh(false); + } +} + +// File|Exit command +void MyFrame::OnMenuFileExit( wxCommandEvent& WXUNUSED(event) ) +{ + // true is to force the frame to close + Close(true); } -/* Intercept menu commands */ -void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event)) +// Help|About... command +void MyFrame::OnMenuHelpAbout( wxCommandEvent& WXUNUSED(event) ) { - Destroy(); + wxMessageBox(wxT("OpenGL Penguin Sample (c) Robert Roebling, Sandro Sigala et al")); } -#if wxUSE_GLCANVAS +// --------------------------------------------------------------------------- +// TestGLCanvas +// --------------------------------------------------------------------------- BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) EVT_SIZE(TestGLCanvas::OnSize) @@ -103,140 +141,147 @@ BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) EVT_MOUSE_EVENTS(TestGLCanvas::OnMouse) END_EVENT_TABLE() -TestGLCanvas::TestGLCanvas(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, long style, const wxString& name): - wxGLCanvas(parent, id, pos, size, style, name) +TestGLCanvas::TestGLCanvas(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) + : wxGLCanvas(parent, id, NULL, pos, size, + style | wxFULL_REPAINT_ON_RESIZE, name) { - block = FALSE; + // 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); + + m_gldata.initialized = false; + + // initialize view matrix + m_gldata.beginx = 0.0f; + m_gldata.beginy = 0.0f; + m_gldata.zoom = 45.0f; + trackball(m_gldata.quat, 0.0f, 0.0f, 0.0f, 0.0f); } -TestGLCanvas::~TestGLCanvas(void) +TestGLCanvas::~TestGLCanvas() { - /* destroy mesh */ - lw_object_free(info.lwobject); + delete m_glRC; } void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) ) { - /* must always be here */ + // must always be here wxPaintDC dc(this); -#ifndef __WXMOTIF__ - if (!GetContext()) return; -#endif + SetCurrent(*m_glRC); - SetCurrent(); - - /* initialize OpenGL */ - if (info.do_init == TRUE) + // Initialize OpenGL + if (!m_gldata.initialized) { InitGL(); - info.do_init = FALSE; + ResetProjectionMode(); + m_gldata.initialized = true; } - - /* view */ - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - gluPerspective( info.zoom, VIEW_ASPECT, 1, 100 ); - glMatrixMode( GL_MODELVIEW ); - /* clear */ - glClearColor( .3, .4, .6, 1 ); + // Clear + glClearColor( 0.3f, 0.4f, 0.6f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - /* transformations */ - GLfloat m[4][4]; + // Transformations glLoadIdentity(); - glTranslatef( 0, 0, -30 ); - build_rotmatrix( m,info.quat ); + glTranslatef( 0.0f, 0.0f, -20.0f ); + GLfloat m[4][4]; + build_rotmatrix( m, m_gldata.quat ); glMultMatrixf( &m[0][0] ); - /* draw object */ - lw_object_show( info.lwobject ); - - /* flush */ + m_renderer.Render(); + + // Flush glFlush(); - /* swap */ + // Swap SwapBuffers(); } -void TestGLCanvas::OnSize(wxSizeEvent& event) +void TestGLCanvas::OnSize(wxSizeEvent& WXUNUSED(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); - } + // Reset the OpenGL view aspect. + // This is OK 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. + ResetProjectionMode(); } void TestGLCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { - /* Do nothing, to avoid flashing on MSW */ + // Do nothing, to avoid flashing on MSW } -void TestGLCanvas::LoadLWO(const wxString &filename) +// Load the DXF file. If the zlib support is compiled in wxWidgets, +// supports also the ".dxf.gz" gzip compressed files. +void TestGLCanvas::LoadDXF(const wxString& filename) { - /* test if lightwave object */ - if (!lw_is_lwobject(filename.mb_str())) return; - - /* read lightwave object */ - lwObject *lwobject = lw_object_read(filename.mb_str()); - - /* scale */ - lw_object_scale(lwobject, 10.0 / lw_object_radius(lwobject)); - - /* set up mesh info */ - info.do_init = TRUE; - info.lwobject = lwobject; - info.beginx = 0; - info.beginy = 0; - info.zoom = 45; - trackball( info.quat, 0.0, 0.0, 0.0, 0.0 ); + wxFileInputStream stream(filename); + if (stream.Ok()) +#if wxUSE_ZLIB + { + if (filename.Right(3).Lower() == wxT(".gz")) + { + wxZlibInputStream zstream(stream); + m_renderer.Load(zstream); + } else + { + m_renderer.Load(stream); + } + } +#else + { + m_renderer.Load(stream); + } +#endif } -void TestGLCanvas::OnMouse( wxMouseEvent& event ) +void TestGLCanvas::OnMouse(wxMouseEvent& event) { - wxSize sz(GetClientSize()); if (event.Dragging()) { + wxSize sz(GetClientSize()); + /* drag in progress, simulate trackball */ float spin_quat[4]; trackball(spin_quat, - (2.0*info.beginx - sz.x) / sz.x, - ( sz.y - 2.0*info.beginy) / sz.y, - ( 2.0*event.GetX() - sz.x) / sz.x, - ( sz.y - 2.0*event.GetY()) / sz.y); - - add_quats( spin_quat, info.quat, info.quat ); + (2.0*m_gldata.beginx - sz.x) / sz.x, + (sz.y - 2.0*m_gldata.beginy) / sz.y, + (2.0*event.GetX() - sz.x) / sz.x, + (sz.y - 2.0*event.GetY()) / sz.y); + + add_quats(spin_quat, m_gldata.quat, m_gldata.quat); /* orientation has changed, redraw mesh */ - Refresh(FALSE); + Refresh(false); } - info.beginx = event.GetX(); - info.beginy = event.GetY(); + m_gldata.beginx = event.GetX(); + m_gldata.beginy = event.GetY(); } -void TestGLCanvas::InitGL(void) +void TestGLCanvas::InitGL() { - GLfloat light0_pos[4] = { -50.0, 50.0, 0.0, 0.0 }; - GLfloat light0_color[4] = { .6, .6, .6, 1.0 }; /* white light */ - GLfloat light1_pos[4] = { 50.0, 50.0, 0.0, 0.0 }; - GLfloat light1_color[4] = { .4, .4, 1, 1.0 }; /* cold blue light */ + static const GLfloat light0_pos[4] = { -50.0f, 50.0f, 0.0f, 0.0f }; + + // white light + static const GLfloat light0_color[4] = { 0.6f, 0.6f, 0.6f, 1.0f }; + + static const GLfloat light1_pos[4] = { 50.0f, 50.0f, 0.0f, 0.0f }; + + // cold blue light + static const GLfloat light1_color[4] = { 0.4f, 0.4f, 1.0f, 1.0f }; /* remove back faces */ glDisable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); - + /* speedups */ glEnable(GL_DITHER); glShadeModel(GL_SMOOTH); @@ -245,16 +290,34 @@ void TestGLCanvas::InitGL(void) /* light */ glLightfv(GL_LIGHT0, GL_POSITION, light0_pos); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color); glLightfv(GL_LIGHT1, GL_POSITION, light1_pos); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_color); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); - - glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); } +void TestGLCanvas::ResetProjectionMode() +{ + // This is normally only necessary if there is more than one wxGLCanvas + // or more than one wxGLContext in the application. + SetCurrent(*m_glRC); -#endif + int w, h; + GetClientSize(&w, &h); + + // It's up to the application code to update the OpenGL viewport settings. + // In order to avoid extensive context switching, consider doing this in + // OnPaint() rather than here, though. + glViewport(0, 0, (GLint) w, (GLint) h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0f, (GLfloat)w/h, 1.0, 100.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +}