// 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"
#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 <OpenGL/glu.h>
-# else
-# include <glu.h>
-# endif
+#ifdef __DARWIN__
+ #include <OpenGL/glu.h>
#else
-# include <GL/glu.h>
+ #include <GL/glu.h>
#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)
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);
/* 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();
+}