]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/opengl/penguin/penguin.cpp
focus propagation, fixes #10047
[wxWidgets.git] / samples / opengl / penguin / penguin.cpp
index 21e8b28c2531886841981a3d169fb80357b011cf..e18cb95adc1c5cdea3c349c7e131c43e7e94bdee 100644 (file)
@@ -2,18 +2,13 @@
 // Name:        penguin.cpp
 // Purpose:     wxGLCanvas demo program
 // Author:      Robert Roebling
 // 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
 /////////////////////////////////////////////////////////////////////////////
 
 // 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"
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #include "wx/wx.h"
 #endif
 
 #include "wx/wx.h"
 #endif
 
+#if !wxUSE_GLCANVAS
+    #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
+#endif
+
 #include "penguin.h"
 #include "penguin.h"
-#ifdef __WXMAC__
-#  ifdef __DARWIN__
-#    include <OpenGL/glu.h>
-#  else
-#    include <glu.h>
-#  endif
+#ifdef __DARWIN__
+    #include <OpenGL/glu.h>
 #else
 #else
-#  include <GL/glu.h>
+    #include <GL/glu.h>
 #endif
 
 #endif
 
-#define VIEW_ASPECT 1.3
+#include "../../sample.xpm"
+
+// ---------------------------------------------------------------------------
+// MyApp
+// ---------------------------------------------------------------------------
 
 // `Main program' equivalent, creating windows and returning main app frame
 bool MyApp::OnInit()
 {
 
 // `Main program' equivalent, creating windows and returning main app frame
 bool MyApp::OnInit()
 {
+    if ( !wxApp::OnInit() )
+        return false;
 
     // Create the main frame window
 
     // Create the main frame window
-    MyFrame *frame = new MyFrame(NULL, wxT("wxWindows OpenGL Penguin Sample"),
+    MyFrame *frame = new MyFrame(NULL, wxT("wxWidgets Penguin Sample"),
         wxDefaultPosition, wxDefaultSize);
 
         wxDefaultPosition, wxDefaultSize);
 
-    /* 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, wxID_ANY, wxDefaultPosition,
-        wxSize(200, 200), wxSUNKEN_BORDER) );
-
-    /* Load file wiht mesh data */
-    frame->GetCanvas()->LoadLWO( wxT("penguin.lwo") );
+#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
 
     /* Show the frame */
     frame->Show(true);
 
     return true;
 
     /* Show the frame */
     frame->Show(true);
 
     return true;
-#else
-
-    wxMessageBox( _T("This sample has to be compiled with wxUSE_GLCANVAS"),
-        _T("Building error"), wxOK);
-
-    return false;
-
-#endif
 }
 
 IMPLEMENT_APP(MyApp)
 
 }
 
 IMPLEMENT_APP(MyApp)
 
+// ---------------------------------------------------------------------------
+// MyFrame
+// ---------------------------------------------------------------------------
+
 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
 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()
 
 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, wxID_ANY, title, pos, size, style)
 {
 MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
     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
 #endif
+        wxFD_OPEN);
+    if (!filename.IsEmpty())
+    {
+        m_canvas->LoadDXF(filename);
+        m_canvas->Refresh(false);
+    }
 }
 
 }
 
-/* Intercept menu commands */
-void MyFrame::OnExit( wxCommandEvent& WXUNUSED(event) )
+// File|Exit command
+void MyFrame::OnMenuFileExit( wxCommandEvent& WXUNUSED(event) )
 {
     // true is to force the frame to close
     Close(true);
 }
 
 {
     // true is to force the frame to close
     Close(true);
 }
 
-#if wxUSE_GLCANVAS
+// Help|About... command
+void MyFrame::OnMenuHelpAbout( wxCommandEvent& WXUNUSED(event) )
+{
+    wxMessageBox(wxT("OpenGL Penguin Sample (c) Robert Roebling, Sandro Sigala et al"));
+}
+
+// ---------------------------------------------------------------------------
+// TestGLCanvas
+// ---------------------------------------------------------------------------
 
 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
     EVT_SIZE(TestGLCanvas::OnSize)
 
 BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
     EVT_SIZE(TestGLCanvas::OnSize)
@@ -107,56 +141,62 @@ BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
     EVT_MOUSE_EVENTS(TestGLCanvas::OnMouse)
 END_EVENT_TABLE()
 
     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()
 {
 }
 
 TestGLCanvas::~TestGLCanvas()
 {
-    /* destroy mesh */
-    lw_object_free(info.lwobject);
+    delete m_glRC;
 }
 
 void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
 {
 }
 
 void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
 {
-    /* must always be here */
+    // must always be here
     wxPaintDC dc(this);
 
     wxPaintDC dc(this);
 
-#ifndef __WXMOTIF__
-    if (!GetContext()) return;
-#endif
-
-    SetCurrent();
+    SetCurrent(*m_glRC);
 
     // Initialize OpenGL
 
     // Initialize OpenGL
-    if (info.do_init)
+    if (!m_gldata.initialized)
     {
         InitGL();
     {
         InitGL();
-        info.do_init = false;
+        ResetProjectionMode();
+        m_gldata.initialized = true;
     }
 
     }
 
-    // View
-    glMatrixMode( GL_PROJECTION );
-    glLoadIdentity();
-    gluPerspective( info.zoom, VIEW_ASPECT, 1.0, 100.0 );
-    glMatrixMode( GL_MODELVIEW );
-
     // Clear
     glClearColor( 0.3f, 0.4f, 0.6f, 1.0f );
     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
     // Transformations
     // Clear
     glClearColor( 0.3f, 0.4f, 0.6f, 1.0f );
     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
     // Transformations
-    GLfloat m[4][4];
     glLoadIdentity();
     glLoadIdentity();
-    glTranslatef( 0.0f, 0.0f, -30.0f );
-    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] );
 
     glMultMatrixf( &m[0][0] );
 
-    // Draw object
-    lw_object_show( info.lwobject );
+    m_renderer.Render();
 
     // Flush
     glFlush();
 
     // Flush
     glFlush();
@@ -165,71 +205,65 @@ void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
     SwapBuffers();
 }
 
     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))
 {
 }
 
 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.0f;
-    info.beginy = 0.0f;
-    info.zoom   = 45.0f;
-    trackball( info.quat, 0.0f, 0.0f, 0.0f, 0.0f );
+    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)
 {
 {
-
-    if ( event.Dragging() )
+    if (event.Dragging())
     {
     {
-        wxSize sz( GetClientSize() );
+        wxSize sz(GetClientSize());
 
         /* drag in progress, simulate trackball */
         float spin_quat[4];
         trackball(spin_quat,
 
         /* 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);
+            (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, info.quat, info.quat );
+        add_quats(spin_quat, m_gldata.quat, m_gldata.quat);
 
         /* orientation has changed, redraw mesh */
         Refresh(false);
     }
 
 
         /* orientation has changed, redraw mesh */
         Refresh(false);
     }
 
-    info.beginx = event.GetX();
-    info.beginy = event.GetY();
+    m_gldata.beginx = event.GetX();
+    m_gldata.beginy = event.GetY();
 }
 
 void TestGLCanvas::InitGL()
 }
 
 void TestGLCanvas::InitGL()
@@ -267,5 +301,23 @@ void TestGLCanvas::InitGL()
     glEnable(GL_COLOR_MATERIAL);
 }
 
     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);
+
+    int w, h;
+    GetClientSize(&w, &h);
 
 
-#endif // #if wxUSE_GLCANVAS
+    // 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();
+}