// implementation
// ============================================================================
-// ----------------------------------------------------------------------------
-// MyApp: the application object
-// ----------------------------------------------------------------------------
-
-IMPLEMENT_APP(MyApp)
-
-bool MyApp::OnInit()
-{
- if ( !wxApp::OnInit() )
- return false;
-
- // Create the main window
- new MyFrame();
-
- return true;
-}
-
-int MyApp::OnExit()
-{
- delete m_glContext;
-
- return wxApp::OnExit();
-}
-
-TestGLContext& MyApp::GetContext(wxGLCanvas *canvas)
-{
- if ( !m_glContext )
- m_glContext = new TestGLContext(canvas);
- else
- m_glContext->SetCurrent(*canvas);
-
- return *m_glContext;
-}
-
// ----------------------------------------------------------------------------
// TestGLContext
// ----------------------------------------------------------------------------
glEnable(GL_LIGHT0);
glEnable(GL_TEXTURE_2D);
- // add slightly more light, the default lightning is rather dark
+ // add slightly more light, the default lighting is rather dark
GLfloat ambient[] = { 0.5, 0.5, 0.5, 0.5 };
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
CheckGLError();
}
+
+// ----------------------------------------------------------------------------
+// MyApp: the application object
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_APP(MyApp)
+
+bool MyApp::OnInit()
+{
+ if ( !wxApp::OnInit() )
+ return false;
+
+ new MyFrame();
+
+ return true;
+}
+
+int MyApp::OnExit()
+{
+ delete m_glContext;
+
+ return wxApp::OnExit();
+}
+
+TestGLContext& MyApp::GetContext(wxGLCanvas *canvas)
+{
+ if ( !m_glContext )
+ {
+ // Create the OpenGL context for the first window which needs it:
+ // subsequently created windows will all share the same context.
+ m_glContext = new TestGLContext(canvas);
+ }
+
+ m_glContext->SetCurrent(*canvas);
+
+ return *m_glContext;
+}
+
// ----------------------------------------------------------------------------
// TestGLCanvas
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas)
- EVT_SIZE(TestGLCanvas::OnSize)
EVT_PAINT(TestGLCanvas::OnPaint)
-
EVT_KEY_DOWN(TestGLCanvas::OnKeyDown)
END_EVENT_TABLE()
TestGLCanvas::TestGLCanvas(wxWindow *parent)
- : wxGLCanvas(parent, wxID_ANY, NULL /* attribs */)
+ // With perspective OpenGL graphics, the wxFULL_REPAINT_ON_RESIZE style
+ // flag should always be set, because even making the canvas smaller should
+ // be followed by a paint event that updates the entire canvas with new
+ // viewport settings.
+ : wxGLCanvas(parent, wxID_ANY, NULL /* attribs */,
+ wxDefaultPosition, wxDefaultSize,
+ wxFULL_REPAINT_ON_RESIZE)
{
m_xangle =
m_yangle = 30;
void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
{
+ // This is required even though dc is not used otherwise.
wxPaintDC dc(this);
- wxGetApp().GetContext(this).DrawRotatedCube(m_xangle, m_yangle);
+ // Set the OpenGL viewport according to the client size of this canvas.
+ // This is done here rather than in a wxSizeEvent handler because our
+ // OpenGL rendering context (and thus viewport setting) is used with
+ // multiple canvases: If we updated the viewport in the wxSizeEvent
+ // handler, changing the size of one canvas causes a viewport setting that
+ // is wrong when next another canvas is repainted.
+ const wxSize ClientSize = GetClientSize();
- SwapBuffers();
-}
-
-void TestGLCanvas::OnSize(wxSizeEvent& event)
-{
- // don't prevent default processing from taking place
- event.Skip();
-
- if ( !IsShownOnScreen() )
- return;
-
- // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...)
- int w, h;
- GetClientSize(&w, &h);
+ glViewport(0, 0, ClientSize.x, ClientSize.y);
- wxGetApp().GetContext(this);
- glViewport(0, 0, w, h);
+ // Render the graphics and swap the buffers.
+ wxGetApp().GetContext(this).DrawRotatedCube(m_xangle, m_yangle);
+ SwapBuffers();
}
void TestGLCanvas::OnKeyDown( wxKeyEvent& event )
Refresh(false);
}
+
// ----------------------------------------------------------------------------
// MyFrame: main application window
// ----------------------------------------------------------------------------
void MyFrame::OnNewWindow( wxCommandEvent& WXUNUSED(event) )
{
- (void) new MyFrame();
+ new MyFrame();
}
};
// Define a new application type
-class MyApp: public wxApp
+class MyApp : public wxApp
{
public:
MyApp() { m_glContext = NULL; }
- // get the context we use creating it on demand (and set it as current)
+ // Returns the shared context used by all frames and sets it as current for
+ // the given canvas.
TestGLContext& GetContext(wxGLCanvas *canvas);
// virtual wxApp methods
};
// Define a new frame type
-class MyFrame: public wxFrame
+class MyFrame : public wxFrame
{
public:
MyFrame();
private:
void OnClose(wxCommandEvent& event);
void OnNewWindow(wxCommandEvent& event);
- void OnDefRotateLeftKey(wxCommandEvent& event);
- void OnDefRotateRightKey(wxCommandEvent& event);
DECLARE_EVENT_TABLE()
};
private:
void OnPaint(wxPaintEvent& event);
- void OnSize(wxSizeEvent& event);
void OnKeyDown(wxKeyEvent& event);
// angles of rotation around x- and y- axis
};
#endif // _WX_CUBE_H_
-
#undef GL_EXT_vertex_array
#endif
-#include "isosurf.h"
+#include <fstream>
+#include "isosurf.h"
#include "../../sample.xpm"
// The following part is taken largely unchanged from the original C Version
static GLfloat yrot;
-static void read_surface( const wxChar *filename )
+static void read_surface(const char *filename)
{
- FILE *f = wxFopen(filename,_T("r"));
- if (!f)
+ std::ifstream inFile(filename);
+ numverts = 0;
+
+ if ( !inFile )
{
- wxString msg = _T("Couldn't read ");
- msg += filename;
- wxMessageBox(msg);
+ wxLogError("Couldn't read \"%s\"", filename);
return;
}
- numverts = 0;
- while (!feof(f) && numverts<MAXVERTS)
+ while ((inFile >> verts[numverts][0] >> verts[numverts][1] >> verts[numverts][2]
+ >> norms[numverts][0] >> norms[numverts][1] >> norms[numverts][2]) && 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--;
-
wxPrintf(_T("%d vertices, %d triangles\n"), numverts, numverts-2);
-
- fclose(f);
}
glPopMatrix();
- glFlush();
+ glFlush(); // Not really necessary: buffer swapping below implies glFlush()
}
return GL_TRUE;
}
-// The following part was written for wxWidgets 1.66
-MyFrame *frame = NULL;
IMPLEMENT_APP(MyApp)
Args(argc, argv);
// Create the main frame window
- frame = new MyFrame(NULL, wxT("wxWidgets OpenGL Isosurf Sample"),
+ new MyFrame(NULL, wxT("wxWidgets OpenGL Isosurf Sample"),
wxDefaultPosition, wxDefaultSize);
+ read_surface("isosurf.dat");
+
+ Init();
+
+ return true;
+}
+
+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, wxID_ANY, title, pos, size, style),
+ m_canvas(NULL)
+{
+ SetIcon(wxICON(sample));
+
+
// Make a menubar
wxMenu *fileMenu = new wxMenu;
fileMenu->Append(wxID_EXIT, _T("E&xit"));
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(fileMenu, _T("&File"));
- frame->SetMenuBar(menuBar);
+ SetMenuBar(menuBar);
+
// Make a TestGLCanvas
doubleBuffer = GL_FALSE;
}
- frame->m_canvas = new TestGLCanvas(frame, wxID_ANY, wxDefaultPosition,
- wxDefaultSize, 0, _T("TestGLCanvas"), gl_attrib );
-
- // Show the frame
- frame->Show(true);
-
- frame->m_canvas->SetCurrent();
- read_surface( _T("isosurf.dat") );
-
- Init();
-
- return true;
-}
-
-BEGIN_EVENT_TABLE(MyFrame, wxFrame)
- EVT_MENU(wxID_EXIT, MyFrame::OnExit)
-END_EVENT_TABLE()
+ // Show the frame
+ Show(true);
-// My frame constructor
-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;
- SetIcon(wxICON(sample));
+ m_canvas = new TestGLCanvas(this, wxID_ANY, wxDefaultPosition,
+ GetClientSize(), 0, _T("TestGLCanvas"), gl_attrib );
}
MyFrame::~MyFrame()
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|wxFULL_REPAINT_ON_RESIZE, name, gl_attrib)
+TestGLCanvas::TestGLCanvas(wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxString& name,
+ int* gl_attrib)
+ : wxGLCanvas(parent, id, gl_attrib, pos, size,
+ style | wxFULL_REPAINT_ON_RESIZE, name)
{
- parent->Show(true);
- SetCurrent();
+ // 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);
/* Make sure server supports the vertex array extension */
char* extensions = (char *) glGetString( GL_EXTENSIONS );
}
}
+TestGLCanvas::~TestGLCanvas()
+{
+ delete m_glRC;
+}
void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
{
// OnPaint handlers must always create a wxPaintDC.
wxPaintDC dc(this);
-#ifndef __WXMOTIF__
- if (!GetContext()) return;
-#endif
-
- SetCurrent();
+ // This is normally only necessary if there is more than one wxGLCanvas
+ // or more than one wxGLContext in the application.
+ SetCurrent(*m_glRC);
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)
static int dragging = 0;
static float last_x, last_y;
- //printf("%f %f %d\n", event.GetX(), event.GetY(), (int)event.LeftIsDown());
+ // Allow default processing to happen, or else the canvas cannot gain focus
+ // (for key events).
+ event.Skip();
+
if(event.LeftIsDown())
{
if(!dragging)
last_y = event.GetY();
}
else
+ {
dragging = 0;
-
-}
-
-void TestGLCanvas::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
-{
- // Do nothing, to avoid flashing.
+ }
}
#define _WX_ISOSURF_H_
// Define a new application type
-class MyApp: public wxApp
+class MyApp : public wxApp
{
public:
- bool OnInit();
+ virtual bool OnInit();
};
-#if wxUSE_GLCANVAS
-class TestGLCanvas: public wxGLCanvas
+class TestGLCanvas : public wxGLCanvas
{
public:
- TestGLCanvas(wxWindow *parent, wxWindowID id = wxID_ANY,
- const wxPoint& pos = wxDefaultPosition,
- const wxSize& size = wxDefaultSize, long style = 0,
- const wxString& name = _T("TestGLCanvas"), int *gl_attrib = NULL);
+ TestGLCanvas(wxWindow *parent,
+ wxWindowID id = wxID_ANY,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString& name = _T("TestGLCanvas"),
+ int *gl_attrib = NULL);
- ~TestGLCanvas(){};
+ virtual ~TestGLCanvas();
void OnPaint(wxPaintEvent& event);
void OnSize(wxSizeEvent& event);
- void OnEraseBackground(wxEraseEvent& event);
void OnChar(wxKeyEvent& event);
void OnMouseEvent(wxMouseEvent& event);
+
+private:
+ wxGLContext* m_glRC;
+
+ DECLARE_NO_COPY_CLASS(TestGLCanvas)
DECLARE_EVENT_TABLE()
};
-#endif // #if wxUSE_GLCANVAS
-
-class MyFrame: public wxFrame
+class MyFrame : public wxFrame
{
public:
- MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
- const wxSize& size, long style = wxDEFAULT_FRAME_STYLE);
+ MyFrame(wxFrame *frame,
+ const wxString& title,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style = wxDEFAULT_FRAME_STYLE);
virtual ~MyFrame();
-#if wxUSE_GLCANVAS
TestGLCanvas *m_canvas;
-#endif
private :
-
void OnExit(wxCommandEvent& event);
-DECLARE_EVENT_TABLE()
+ DECLARE_EVENT_TABLE()
};
-#endif // #ifndef _WX_ISOSURF_H_
+#endif // _WX_ISOSURF_H_
#include <GL/glu.h>
#endif
+#include <sstream>
+
#include "dxfrenderer.h"
#include "wx/listimpl.cpp"
return false;
}
+// This method is used instead of numStr.ToDouble(d) because the latter
+// (wxString::ToDouble()) takes the systems proper locale into account,
+// whereas the implementation below works with the default locale.
+// (Converting numbers that are formatted in the default locale can fail
+// with system locales that use e.g. the comma as the decimal separator.)
+static double ToDouble(const wxString& numStr)
+{
+ double d;
+ std::string numStr_(numStr.c_str());
+ std::istringstream iss(numStr_);
+
+ iss >> d;
+
+ return d;
+}
+
// parse entities section: save 3DFACE and LINE entities
bool DXFRenderer::ParseEntities(wxInputStream& stream)
{
state = 2;
else if (state > 0)
{
- double d;
- line2.ToDouble(&d);
+ const double d=ToDouble(line2);
+
if (line1 == wxT("10"))
v[0].x = d;
else if (line1 == wxT("20"))
menuBar->Append(helpMenu, wxT("&Help"));
SetMenuBar(menuBar);
+ Show(true);
+
m_canvas = new TestGLCanvas(this, wxID_ANY, wxDefaultPosition,
- wxSize(300, 300), wxSUNKEN_BORDER);
+ GetClientSize(), wxSUNKEN_BORDER);
}
// File|Open... command
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|wxFULL_REPAINT_ON_RESIZE, 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)
{
+ // 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
TestGLCanvas::~TestGLCanvas()
{
+ delete m_glRC;
}
void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
// must always be here
wxPaintDC dc(this);
-#ifndef __WXMOTIF__
- if (!GetContext()) return;
-#endif
-
- SetCurrent();
+ SetCurrent(*m_glRC);
// Initialize OpenGL
if (!m_gldata.initialized)
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);
- // Reset the OpenGL view aspect
+ // 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::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);
-#ifndef __WXMOTIF__
- if ( GetContext() )
-#endif
- {
- SetCurrent();
- 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();
- }
+
+ // 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();
}
#include "dxfrenderer.h"
+
// OpenGL view data
struct GLData
{
float zoom; // field of view in degrees
};
+
// Define a new application type
-class MyApp: public wxApp
+class MyApp : public wxApp
{
public:
- bool OnInit();
+ virtual bool OnInit();
};
+
// Define a new frame type
class TestGLCanvas;
-class MyFrame: public wxFrame
+
+class MyFrame : public wxFrame
{
public:
MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
- const wxSize& size, long style = wxDEFAULT_FRAME_STYLE);
+ const wxSize& size, long style = wxDEFAULT_FRAME_STYLE);
void OnMenuFileOpen(wxCommandEvent& event);
void OnMenuFileExit(wxCommandEvent& event);
void OnMenuHelpAbout(wxCommandEvent& event);
-#if wxUSE_GLCANVAS
- void SetCanvas( TestGLCanvas *canvas ) { m_canvas = canvas; }
+ void SetCanvas(TestGLCanvas *canvas) { m_canvas = canvas; }
TestGLCanvas *GetCanvas() { return m_canvas; }
private:
TestGLCanvas *m_canvas;
-#endif
DECLARE_EVENT_TABLE()
};
-#if wxUSE_GLCANVAS
-class TestGLCanvas: public wxGLCanvas
+class TestGLCanvas : public wxGLCanvas
{
public:
TestGLCanvas(wxWindow *parent, wxWindowID id = wxID_ANY,
const wxSize& size = wxDefaultSize, long style = 0,
const wxString& name = wxT("TestGLCanvas"));
- ~TestGLCanvas();
+ virtual ~TestGLCanvas();
void LoadDXF(const wxString& filename);
void InitGL();
void ResetProjectionMode();
- GLData m_gldata;
- DXFRenderer m_renderer;
+ wxGLContext* m_glRC;
+ GLData m_gldata;
+ DXFRenderer m_renderer;
+ DECLARE_NO_COPY_CLASS(TestGLCanvas)
DECLARE_EVENT_TABLE()
};
-#endif // #if wxUSE_GLCANVAS
-
#endif // #ifndef _WX_PENGUIN_H_
-