root/OpenSceneGraph/trunk/examples/osgviewerWX/osgviewerWX.cpp @ 8459

Revision 8459, 8.0 kB (checked in by robert, 7 years ago)

From Paul Melis, "Here is a reworked version of the osgviewerWX example. It changes the GraphicsWindowWX to only inherit from osgViewer::GraphicsWindow? and adds a standalone widget, called OSGCanvas, that derives from wxGLCanvas. This solves a problem with the GraphicsWindowWX instance being destructed twice (see "Crash in osgviewerWX" of June 12th on osg-users). At program exit, the main frame deletes all of its children widgets and therefore calls GraphicsWindowWX's destructor, bypassing OSG's reference counting. The GraphicsWindowWX instance is then later destructed a second time when the reference held by osg::Camera goes to zero. This bug isn't exposed by the example directly, but if people are going to use the example as a basis (like the poster in the mentioned thread) they very likely will run into this problem.
"

Line 
1// For compilers that support precompilation, includes "wx.h".
2#include "wx/wxprec.h"
3
4#ifdef __BORLANDC__
5#pragma hdrstop
6#endif
7
8#ifndef WX_PRECOMP
9#include "wx/wx.h"
10#endif
11
12// For wxCURSOR_BLANK below, but isn't used a.t.m.
13//#ifdef WIN32
14//#include "wx/msw/wx.rc"
15//#endif
16
17#include "osgviewerWX.h"
18
19
20#include <osgViewer/ViewerEventHandlers>
21#include <osgGA/TrackballManipulator>
22#include <osgDB/ReadFile>
23#include <wx/image.h>
24#include <wx/menu.h>
25
26#include <iostream>
27
28// `Main program' equivalent, creating windows and returning main app frame
29bool wxOsgApp::OnInit()
30{
31    if (argc<2)
32    {
33        std::cout << wxString(argv[0]).mb_str() <<": requires filename argument." << std::endl;
34        return false;
35    }
36
37    int width = 800;
38    int height = 600;
39
40    // Create the main frame window
41
42    MainFrame *frame = new MainFrame(NULL, wxT("wxWidgets OSG Sample"),
43        wxDefaultPosition, wxSize(width, height));
44
45    // create osg canvas
46    //    - initialize
47
48    int *attributes = new int[7];
49    attributes[0] = int(WX_GL_DOUBLEBUFFER);
50    attributes[1] = WX_GL_RGBA;
51    attributes[2] = WX_GL_DEPTH_SIZE;
52    attributes[3] = 8;
53    attributes[4] = WX_GL_STENCIL_SIZE;
54    attributes[5] = 8;
55    attributes[6] = 0;
56
57    OSGCanvas *canvas = new OSGCanvas(frame, wxID_ANY, wxDefaultPosition,
58        wxSize(width, height), wxSUNKEN_BORDER, wxT("osgviewerWX"), attributes);
59
60    GraphicsWindowWX* gw = new GraphicsWindowWX(canvas);
61
62    canvas->SetGraphicsWindow(gw);
63
64    osgViewer::Viewer *viewer = new osgViewer::Viewer;
65    viewer->getCamera()->setGraphicsContext(gw);
66    viewer->getCamera()->setViewport(0,0,width,height);
67    viewer->addEventHandler(new osgViewer::StatsHandler);
68    viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
69
70    // load the scene.
71    wxString fname(argv[1]);
72    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(std::string(fname.mb_str()));
73    if (!loadedModel)
74    {
75        std::cout << argv[0] <<": No data loaded." << std::endl;
76        return false;
77    }
78
79    viewer->setSceneData(loadedModel.get());
80    viewer->setCameraManipulator(new osgGA::TrackballManipulator);
81    frame->SetViewer(viewer);
82
83    /* Show the frame */
84    frame->Show(true);
85
86    return true;
87}
88
89IMPLEMENT_APP(wxOsgApp)
90
91BEGIN_EVENT_TABLE(MainFrame, wxFrame)
92    EVT_IDLE(MainFrame::OnIdle)
93END_EVENT_TABLE()
94
95/* My frame constructor */
96MainFrame::MainFrame(wxFrame *frame, const wxString& title, const wxPoint& pos,
97    const wxSize& size, long style)
98    : wxFrame(frame, wxID_ANY, title, pos, size, style)
99{
100}
101
102void MainFrame::SetViewer(osgViewer::Viewer *viewer)
103{
104    _viewer = viewer;
105}
106
107void MainFrame::OnIdle(wxIdleEvent &event)
108{
109    _viewer->frame();
110
111    event.RequestMore();
112}
113
114BEGIN_EVENT_TABLE(OSGCanvas, wxGLCanvas)
115    EVT_SIZE                (OSGCanvas::OnSize)
116    EVT_PAINT               (OSGCanvas::OnPaint)
117    EVT_ERASE_BACKGROUND    (OSGCanvas::OnEraseBackground)
118
119    EVT_CHAR                (OSGCanvas::OnChar)
120    EVT_KEY_UP              (OSGCanvas::OnKeyUp)
121
122    EVT_ENTER_WINDOW        (OSGCanvas::OnMouseEnter)
123    EVT_LEFT_DOWN           (OSGCanvas::OnMouseDown)
124    EVT_MIDDLE_DOWN         (OSGCanvas::OnMouseDown)
125    EVT_RIGHT_DOWN          (OSGCanvas::OnMouseDown)
126    EVT_LEFT_UP             (OSGCanvas::OnMouseUp)
127    EVT_MIDDLE_UP           (OSGCanvas::OnMouseUp)
128    EVT_RIGHT_UP            (OSGCanvas::OnMouseUp)
129    EVT_MOTION              (OSGCanvas::OnMouseMotion)
130END_EVENT_TABLE()
131
132OSGCanvas::OSGCanvas(wxWindow *parent, wxWindowID id,
133    const wxPoint& pos, const wxSize& size, long style, const wxString& name, int *attributes)
134    : wxGLCanvas(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE, name, attributes)
135{
136    // default cursor to standard
137    _oldCursor = *wxSTANDARD_CURSOR;
138}
139
140OSGCanvas::~OSGCanvas()
141{
142}
143
144void OSGCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
145{
146    /* must always be here */
147    wxPaintDC dc(this);
148}
149
150void OSGCanvas::OnSize(wxSizeEvent& event)
151{
152    // this is also necessary to update the context on some platforms
153    wxGLCanvas::OnSize(event);
154
155    // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...)
156    int width, height;
157    GetClientSize(&width, &height);
158
159    if (_graphics_window.valid())
160    {
161        // update the window dimensions, in case the window has been resized.
162        _graphics_window->getEventQueue()->windowResize(0, 0, width, height);
163        _graphics_window->resized(0,0,width,height);
164    }
165}
166
167void OSGCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
168{
169    /* Do nothing, to avoid flashing on MSW */
170}
171
172void OSGCanvas::OnChar(wxKeyEvent &event)
173{
174#if wxUSE_UNICODE
175    int key = event.GetUnicodeKey();
176#else
177    int key = event.GetKeyCode();
178#endif
179
180    if (_graphics_window.valid())
181        _graphics_window->getEventQueue()->keyPress(key);
182
183    // If this key event is not processed here, we should call
184    // event.Skip() to allow processing to continue.
185}
186
187void OSGCanvas::OnKeyUp(wxKeyEvent &event)
188{
189#if wxUSE_UNICODE
190    int key = event.GetUnicodeKey();
191#else
192    int key = event.GetKeyCode();
193#endif
194
195    if (_graphics_window.valid())
196        _graphics_window->getEventQueue()->keyRelease(key);
197
198    // If this key event is not processed here, we should call
199    // event.Skip() to allow processing to continue.
200}
201
202void OSGCanvas::OnMouseEnter(wxMouseEvent &event)
203{
204    // Set focus to ourselves, so keyboard events get directed to us
205    SetFocus();
206}
207
208void OSGCanvas::OnMouseDown(wxMouseEvent &event)
209{
210    if (_graphics_window.valid())
211    {
212        _graphics_window->getEventQueue()->mouseButtonPress(event.GetX(), event.GetY(),
213            event.GetButton());
214    }
215}
216
217void OSGCanvas::OnMouseUp(wxMouseEvent &event)
218{
219    if (_graphics_window.valid())
220    {
221        _graphics_window->getEventQueue()->mouseButtonRelease(event.GetX(), event.GetY(),
222            event.GetButton());
223    }
224}
225
226void OSGCanvas::OnMouseMotion(wxMouseEvent &event)
227{
228    if (_graphics_window.valid())
229        _graphics_window->getEventQueue()->mouseMotion(event.GetX(), event.GetY());
230}
231
232void OSGCanvas::UseCursor(bool value)
233{
234    if (value)
235    {
236        // show the old cursor
237        SetCursor(_oldCursor);
238    }
239    else
240    {
241        // remember the old cursor
242        _oldCursor = GetCursor();
243
244        // hide the cursor
245        //    - can't find a way to do this neatly, so create a 1x1, transparent image
246        wxImage image(1,1);
247        image.SetMask(true);
248        image.SetMaskColour(0, 0, 0);
249        wxCursor cursor(image);
250        SetCursor(cursor);
251
252        // On wxGTK, only works as of version 2.7.0
253        // (http://trac.wxwidgets.org/ticket/2946)
254        // SetCursor( wxStockCursor( wxCURSOR_BLANK ) );
255    }
256}
257
258GraphicsWindowWX::GraphicsWindowWX(OSGCanvas *canvas)
259{
260    _canvas = canvas;
261
262    _traits = new GraphicsContext::Traits;
263
264    wxPoint pos = _canvas->GetPosition();
265    wxSize  size = _canvas->GetSize();
266
267    _traits->x = pos.x;
268    _traits->y = pos.y;
269    _traits->width = size.x;
270    _traits->height = size.y;
271
272    init();
273}
274
275GraphicsWindowWX::~GraphicsWindowWX()
276{
277}
278
279void GraphicsWindowWX::init()
280{
281    if (valid())
282    {
283        setState( new osg::State );
284        getState()->setGraphicsContext(this);
285
286        if (_traits.valid() && _traits->sharedContext)
287        {
288            getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
289            incrementContextIDUsageCount( getState()->getContextID() );
290        }
291        else
292        {
293            getState()->setContextID( osg::GraphicsContext::createNewContextID() );
294        }
295    }
296}
297
298void GraphicsWindowWX::grabFocus()
299{
300    // focus the canvas
301    _canvas->SetFocus();
302}
303
304void GraphicsWindowWX::grabFocusIfPointerInWindow()
305{
306    // focus this window, if the pointer is in the window
307    wxPoint pos = wxGetMousePosition();
308    if (wxFindWindowAtPoint(pos) == _canvas)
309        _canvas->SetFocus();
310}
311
312void GraphicsWindowWX::useCursor(bool cursorOn)
313{
314    _canvas->UseCursor(cursorOn);
315}
316
317bool GraphicsWindowWX::makeCurrentImplementation()
318{
319    _canvas->SetCurrent();
320    return true;
321}
322
323void GraphicsWindowWX::swapBuffersImplementation()
324{
325    _canvas->SwapBuffers();
326}
Note: See TracBrowser for help on using the browser.