WxGLCanvas

From WxWiki

Jump to: navigation, search

Contents

[edit] Important note about EVT_SIZE

In linux, adding a handler for EVT_SIZE will mess up OpenGL somehow, and glGenLists(1) stops working. I don't know why ... this might be a bug, but this is the easy workaround! Hours of head-bashing ended!

[edit] SubClassing wxGLCanvas

This is a the smallest sample possible, it will subclass wxGLCanvas and do virtually "no setup", the default values will be used. For more elaborate code that does a proper OpenGL setup, which you will likely want to do in an application, see the other sample below.

subclasswxglcanvas.cpp
// NOTE: To run, it is recommended not to be in Compiz or Beryl, they have shown some instability.
 
#include "wx/wx.h"
#include "wx/glcanvas.h"
 
#ifdef __WXMAC__
#include "GLUT/glut.h"
#else
#include "GL/glut.h"
#endif
 
#ifndef WIN32
#include <unistd.h> // FIXME: ¿This work/necessary in Windows?
                    //Not necessary, but if it was, it needs to be replaced by process.h AND io.h
#endif
 
class wxGLCanvasSubClass: public wxGLCanvas {
        void Render();
public:
    wxGLCanvasSubClass(wxFrame* parent);
    void Paintit(wxPaintEvent& event);
protected:
    DECLARE_EVENT_TABLE()
};
 
BEGIN_EVENT_TABLE(wxGLCanvasSubClass, wxGLCanvas)
    EVT_PAINT    (wxGLCanvasSubClass::Paintit)
END_EVENT_TABLE()
 
wxGLCanvasSubClass::wxGLCanvasSubClass(wxFrame *parent)
:wxGLCanvas(parent, wxID_ANY,  wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas")){
    int argc = 0;
    char** argv = NULL;
 
/*
NOTE: this example uses GLUT in order to have a free teapot model
to display, to show 3D capabilities. GLUT, however, seems to cause problems
on some systems. If you meet problems, first try commenting out glutInit(),
then try comeenting out all glut code
*/
    glutInit(&argc, argv);
}
 
 
void wxGLCanvasSubClass::Paintit(wxPaintEvent& WXUNUSED(event)){
    Render();
}
 
void wxGLCanvasSubClass::Render()
{
    SetCurrent();
    wxPaintDC(this);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, (GLint)GetSize().x, (GLint)GetSize().y);
 
    glBegin(GL_POLYGON);
        glColor3f(1.0, 1.0, 1.0);
        glVertex2f(-0.5, -0.5);
        glVertex2f(-0.5, 0.5);
        glVertex2f(0.5, 0.5);
        glVertex2f(0.5, -0.5);
        glColor3f(0.4, 0.5, 0.4);
        glVertex2f(0.0, -0.8);
    glEnd();
 
    glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex2f(0.1, 0.1);
        glVertex2f(-0.1, 0.1);
        glVertex2f(-0.1, -0.1);
        glVertex2f(0.1, -0.1);
    glEnd();
 
// using a little of glut
    glColor4f(0,0,1,1);
    glutWireTeapot(0.4);
 
    glLoadIdentity();
    glColor4f(2,0,1,1);
    glutWireTeapot(0.6);
// done using glut
 
    glFlush();
    SwapBuffers();
}
 
class MyApp: public wxApp
{
    virtual bool OnInit();
    wxGLCanvas * MyGLCanvas;
};
 
 
IMPLEMENT_APP(MyApp)
 
  
bool MyApp::OnInit()
{
    wxFrame *frame = new wxFrame((wxFrame *)NULL, -1,  wxT("Hello GL World"), wxPoint(50,50), wxSize(200,200));
    new wxGLCanvasSubClass(frame);
 
    frame->Show(TRUE);
    return TRUE;
}

See that is added #include <GL/glut.h> and also to the linker remember add the glut library


What follow is a more elaborated source, with input for mouse and keyboard.

[edit] NOTE: about maximize, iconify, fullscreen operations

The examples in wxWidgets react to EVT_SIZE and at the end they use Refresh(); at the en of the function, the problem with this aproach is that it will not handle correctly this 3 "special" events, you will get at screen something that you don't want to see until a paint event is called.

That is why it is pointed out that you need to call Update(); instead of Refresh(); because it will paint immediately the area where the new size is manipulated by iconify, maximize or full screen operations.

[edit] wxGLCanvas sample

Here is a minimal sample with setup to get you started :

main.h
#ifndef _glpane_
#define _glpane_
 
#include "wx/wx.h"
#include "wx/glcanvas.h"
 
class BasicGLPane : public wxGLCanvas
{
    
public:
	BasicGLPane(wxFrame* parent, int* args);
    
	void resized(wxSizeEvent& evt);
    
	int getWidth();
	int getHeight();
    
	void render(wxPaintEvent& evt);
	void prepare3DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y);
	void prepare2DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y);
    
	// events
	void mouseMoved(wxMouseEvent& event);
	void mouseDown(wxMouseEvent& event);
	void mouseWheelMoved(wxMouseEvent& event);
	void mouseReleased(wxMouseEvent& event);
	void rightClick(wxMouseEvent& event);
	void mouseLeftWindow(wxMouseEvent& event);
	void keyPressed(wxKeyEvent& event);
	void keyReleased(wxKeyEvent& event);
    
	DECLARE_EVENT_TABLE()
};
 
#endif 
main.cpp
#include "wx/wx.h"
#include "wx/sizer.h"
#include "wx/glcanvas.h"
#include "main.h"
 
// include OpenGL
#ifdef __WXMAC__
#include "OpenGL/glu.h"
#include "OpenGL/gl.h"
#include "GLUT/glut.h"
#else
#include <GL/glu.h>
#include <GL/gl.h>
#include <GL/glut.h>
#endif
 
class MyApp: public wxApp
{
    virtual bool OnInit();
 
    wxFrame *frame;
    BasicGLPane * glPane;
public:
      
};
 
IMPLEMENT_APP(MyApp)
 
 
bool MyApp::OnInit()
{
    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    frame = new wxFrame((wxFrame *)NULL, -1,  wxT("Hello GL World"), wxPoint(50,50), wxSize(400,200));
	
    int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0};
    
    glPane = new BasicGLPane( (wxFrame*) frame, args);
    sizer->Add(glPane, 1, wxEXPAND);
	
    frame->SetSizer(sizer);
    frame->SetAutoLayout(true);
	
    frame->Show();
    return true;
} 
 
BEGIN_EVENT_TABLE(BasicGLPane, wxGLCanvas)
EVT_MOTION(BasicGLPane::mouseMoved)
EVT_LEFT_DOWN(BasicGLPane::mouseDown)
EVT_LEFT_UP(BasicGLPane::mouseReleased)
EVT_RIGHT_DOWN(BasicGLPane::rightClick)
EVT_LEAVE_WINDOW(BasicGLPane::mouseLeftWindow)
EVT_SIZE(BasicGLPane::resized)
EVT_KEY_DOWN(BasicGLPane::keyPressed)
EVT_KEY_UP(BasicGLPane::keyReleased)
EVT_MOUSEWHEEL(BasicGLPane::mouseWheelMoved)
EVT_PAINT(BasicGLPane::render)
END_EVENT_TABLE()
 
 
// some useful events to use
void BasicGLPane::mouseMoved(wxMouseEvent& event) {}
void BasicGLPane::mouseDown(wxMouseEvent& event) {}
void BasicGLPane::mouseWheelMoved(wxMouseEvent& event) {}
void BasicGLPane::mouseReleased(wxMouseEvent& event) {}
void BasicGLPane::rightClick(wxMouseEvent& event) {}
void BasicGLPane::mouseLeftWindow(wxMouseEvent& event) {}
void BasicGLPane::keyPressed(wxKeyEvent& event) {}
void BasicGLPane::keyReleased(wxKeyEvent& event) {}
 
BasicGLPane::BasicGLPane(wxFrame* parent, int* args) :
wxGLCanvas(parent, wxID_ANY,  wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas"),  args)
{
    int argc = 0;
    char** argv = NULL;
/*
NOTE: this example uses GLUT in order to have a free teapot model
to display, to show 3D capabilities. GLUT, however, seems to cause problems
on some systems. If you meet problems, first try commenting out glutInit(),
then try comeenting out all glut code
*/
    glutInit(&argc, argv);
	
}
 
void BasicGLPane::resized(wxSizeEvent& evt)
{
    wxGLCanvas::OnSize(evt);
	
    Refresh();
}
 
void BasicGLPane::prepare3DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y)
{
    /*
     *  Inits the OpenGL viewport for drawing in 3D.
     */
	
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black Background
    glClearDepth(1.0f);	// Depth Buffer Setup
    glEnable(GL_DEPTH_TEST); // Enables Depth Testing
    glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	
    glEnable(GL_COLOR_MATERIAL);
	
    glViewport(topleft_x, topleft_y, bottomrigth_x-topleft_x, bottomrigth_y-topleft_y);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	
    float ratio_w_h = (float)(bottomrigth_x-topleft_x)/(float)(bottomrigth_y-topleft_y);
    gluPerspective(45 /*view angle*/, ratio_w_h, 0.1 /*clip close*/, 200 /*clip far*/);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
	
}
 
void BasicGLPane::prepare2DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y)
{
	
    /*
     *  Inits the OpenGL viewport for drawing in 2D
     */
	
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black Background
    glEnable(GL_TEXTURE_2D);   // textures
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	
    glViewport(topleft_x, topleft_y, bottomrigth_x-topleft_x, bottomrigth_y-topleft_y);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    gluOrtho2D(topleft_x, bottomrigth_x, bottomrigth_y, topleft_y);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int BasicGLPane::getWidth()
{
    return GetSize().x;
}
 
int BasicGLPane::getHeight()
{
    return GetSize().y;
}
 
void BasicGLPane::render( wxPaintEvent& evt )
{
    if(!IsShown()) return;
    
    wxGLCanvas::SetCurrent();
    wxPaintDC(this); // only to be used in paint events. use wxClientDC to paint outside the paint event
	
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
    // ------------- draw some 2D ----------------
    prepare2DViewport(0,0,getWidth()/2, getHeight());
    glLoadIdentity();
	
    // white background
    glColor4f(1, 1, 1, 1);
    glBegin(GL_QUADS);
    glVertex3f(0,0,0);
    glVertex3f(getWidth(),0,0);
    glVertex3f(getWidth(),getHeight(),0);
    glVertex3f(0,getHeight(),0);
    glEnd();
	
    // red square
    glColor4f(1, 0, 0, 1);
    glBegin(GL_QUADS);
    glVertex3f(getWidth()/8, getHeight()/3, 0);
    glVertex3f(getWidth()*3/8, getHeight()/3, 0);
    glVertex3f(getWidth()*3/8, getHeight()*2/3, 0);
    glVertex3f(getWidth()/8, getHeight()*2/3, 0);
    glEnd();
    
    // ------------- draw some 3D ----------------
    prepare3DViewport(getWidth()/2,0,getWidth(), getHeight());
    glLoadIdentity();
	
    glColor4f(0,0,1,1);
    glTranslatef(0,0,-5);
    glutWireTeapot(1.0);
	
    glFlush();
    SwapBuffers();
}

This compiled and worked with 'g++ main.cpp -o gl `Wx-Config --libs --cxxflags --gl-libs`' (note the extra flag for Wx-Config) plus your platform's flags to link against OpenGL and GLUT.

[edit] Loading OpenGL textures with wxImage

See article Using wxImage to load textures for OpenGL

[edit] wxGLCanvas support for Win32's MSVC

  • C&C++ / Codegeneration / Release Multithreaded DLL
  • Link :
opengl32.lib wxmsw.lib
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib  odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib  
/nologo /subsystem:windows /incremental:no /pdb:"Release/wxgltest.pdb" /machine:I386 /out:"Release/wxgltest.exe" 

else you'll get this error :

MSVCRT.lib(crtexe.obj) : error LNK2001: unresolved external symbol [_main]

-- RzR 20040613

[edit] wxGLCanvas support for Win32's Cygwin

$ g++ wxgltest.cpp `wx-config --libs --cxxflags --gl-libs` /usr/lib/gcc-lib/i686-pc-cygwin/3.3.1/../../../../i686-pc-cygwin/bin/ld: cannot find -lwxmsw_gl242 collect2: ld returned 1 exit status

WX should be compiled w/ : ./configure --with-opengl

... [TODO] ...

-- RzR 20040613


[edit] Using wxGLCanvas in KDevelop 3 / Gideon

You need to have wxWidgets compiled with OpenGL / GLCanvas support. Once this is done, create a wxWidgets Project, then open a console and type `wx-config --libs --gl-libs` . Copy the output and paste it into the Project->Project Options -> Configure Options -> Linker Flags (LDFLAGS) textfield.

For KDevelop, it is preferred to edit configure.in.in or configure.in (only if configure.in.in isn't present). You should have a line like : WX_LIBS="`$WXCONFIG --libs`". Just add --gl-libs so it becomes WX_LIBS="`$WXCONFIG --libs --gl-libs`". This way tags will be include in your configure script and make your code more portable (between *nix system).

The previous change sometimes doesn't work for KDevelop 3 or later. If it doesn't, try changing the WX_LIBS line to WX_LIBS="`$WXCONFIG --libs` `$WXCONFIG --gl-libs`".

If that still does not work, then follow the direction below: 1. Create a wxWidgets Project 2. Open a console and type `wx-config --gl-libs` 3. Copy the output and paste it into the Project -> Project Options -> Configure Options -> Linker Flags (LDFLAGS) textfield. 4. Build Project (this will re-run the configure)

[edit] Sharing wxGLCanvas context

In order to share OpenGL resources when creating several views of the same objects (display lists, textures, VBOs, ...), you use only one shared wxGLContext. Just create the first wxGLCanvas or inherited object, and then extract its context with wxGLCanvas::GetContext() Then you have to create the rest of the wxGLCanvas using that context.

In wxGTK, the frame upon the wxGLCanvas must be shown before getting the context, because the latter is not created until this happens, so we would be getting an invalid ( not yet created) context:

/* Inside the frame constructor */
 
canvas1 = new wxGLCanvas( this, wxID_ANY); /* Places the window, but does not create it yet, at least in wxGTK */
 
Show(); /* Now the OpenGL window is created, so the context is valid */
commonContext = canvas1->GetContext();
 
canvas2 = new wxGLCanvas( this, commonContext, wxID_ANY); /* Use the same context for the second window. Now you can share textures, display lists, ...*/

[edit] Multiple wxGLCanvases

I had some trouble getting two wxGLCanvases working at the same time, so when I finally did I thought I would share it with world, so here it is. It is simply meant as an example of how you can make multiple wxGLCanvases with some animation. -- PGP

#include <iostream>
#include <string>
#include <cassert>
#include <cmath>
 
#include <wx/wx.h>
#include <wx/glcanvas.h>
#include <wx/notebook.h>
 
class GL_Window : public wxGLCanvas
{
public:
 
	GL_Window(float c, wxWindow * parent, wxWindowID id,
	          const wxPoint & pos, const wxSize& size, long style=0,
	          const wxString & name = _("GLCanvas"), int * attribList = 0,
	          const wxPalette & palette = wxNullPalette)
	: wxGLCanvas(parent, id, pos, size, style, name, attribList, palette),
	  c_(c), rotate_(c) { }
 
	virtual ~GL_Window() { }
 
	void draw() {
		rotate_ += 0.01;
 
		SetCurrent();
		glClearColor(0.0, 0.0, 0.0, 0.0);
		glClear(GL_COLOR_BUFFER_BIT);
		glViewport(0, 0, (GLint)200, (GLint)200);
		glColor3f(1.0, c_, c_);
		
		glBegin(GL_POLYGON);
		glVertex3f(-0.5, -0.5, 5 * cos(rotate_));
		glVertex3f(-0.5, 0.5, 5 * cos(rotate_));
		glVertex3f(0.5, 0.5, -5 * cos(rotate_));
		glVertex3f(0.5, -0.5, -5 * cos(rotate_));
		glEnd();
 
		SwapBuffers();
	}
 
	void OnIdle(wxIdleEvent & event)	{
		draw();
		event.RequestMore();
	}
 
private:
 
	float c_;
	float rotate_;
	
	DECLARE_EVENT_TABLE();
};
 
class MyApp: public wxApp
{
	virtual bool OnInit();
};
 
IMPLEMENT_APP(MyApp)
 
bool MyApp::OnInit()
{
	wxFrame* frame = new wxFrame((wxFrame *) NULL, -1,
		_("Hello GL World"), wxPoint(50, 50), wxSize(450, 340) );
 
	wxNotebook* book = new wxNotebook(frame, -1,
		wxPoint(-1, -1), wxSize(200, 200));
 
	GL_Window* MyGLCanvas = new GL_Window(1, book, -1, wxPoint(-1, -1),
		wxSize(200, 200), wxSUNKEN_BORDER, _("some text"));
	book->AddPage(MyGLCanvas, _("One"));
 
	MyGLCanvas = new GL_Window(0, book, -1, wxPoint(-1,-1),
		wxSize(200,200), wxSUNKEN_BORDER, _("some text"));
	book->AddPage(MyGLCanvas, _("Two"));
 
	frame->Show(true);	
	return true;
}
 
BEGIN_EVENT_TABLE(GL_Window, wxGLCanvas)
    EVT_IDLE(GL_Window::OnIdle)
END_EVENT_TABLE()

[edit] wxGLCanvas on a wxPanel

No matter what I tried I could not get the wxGLCanvas to work as child of a wxPanel. My goal was to have the same base class for all my visualization classes (2D variants are derived from a wxPanel). As such I wanted the wxGLCanvas to cover the entire wxPanel surface area.

The inheritance scheme is as follows: wxPanel <- PlotBase <- PlotBaseGL

PlotBaseGL would create a wxGLCanvas on top of the wxPanel. After having tried various methods I finally found one that works:

void PlotBaseGL::SetCanvas( void )
{
	delete canvas;
 
	int attributelist[ 5 ] = { WX_GL_RGBA         ,
	                           WX_GL_BUFFER_SIZE  ,
	                           _colordepth        ,
	                           0                  ,
	                           0                  };
 
	if ( GetDoubleBuffering() ) attributelist[ 3 ] = WX_GL_DOUBLEBUFFER; 
 
	Show( false );
	canvas = new wxGLCanvas( this, -1, GetPosition(), GetSize(),
	                         GetWindowStyleFlag(), _T("GLCanvas"),
	                         attributelist, wxNullPalette );
 
	canvas->Reparent( pwindow ); 
	canvas->SetCurrent();
	canvas->Show( true );                  
 
	/* some other setup code here */ 
}

It may not be the conventional method but this works fine for me. For some reason creating the wxGLCanvas as a child of the wxPanel and then reparenting to the parent frame solves the problem.

[edit] Animation flicker: wxGLCanvas-as-member vs subclass-as-member

My test OpenGL app exhibited no flicker when resizing (after adding the wxPaintDC local), but when I added animation via a wxTimer, I had horrible flicker at every timer event. I had overridden my main wxFrame EVT_ERASE_BACKGROUND to do nothing, but this wasn't enough. So I'd to subclass the wxGLCanvas just to override its EVT_ERASE_BACKGROUND with an empty function.

Probably in a serious app you'd be subclassing wxGLCanvas anyway, but to facilitate simpler stuff... perhaps wxGLCanvas should have an empty OnEraseBackground? Or a method that sets a member bool, that causes wxGLCanvas::OnEraseBackground to return immediately when set? Perhaps such a thing exists in one of the base classes, but I didn't see it.

Note that EVT_ERASE_BACKGROUND is undocumented in the main wxWidgets manual, but for the current version at the time of writing (2.8.4) this is still necessary. See the penguin opengl sample in the wxWidgets package for details.

[edit] Tooltips from upper widgets disappearing or cut when drawn over wxGLCanvas on Windows

If your wxToolBar tooltips are being painted over right after they appear, is probably because you are calling SwapBuffers from inside the wxGLCanvas OnPaint event handler, this seems to cause a clash between GDI and OpenGL ownership of the buffers.

Creating wxPaintDC on the heap (dc = new wxPaintDC(this); delete dc;) so the call to SwapBuffers is inside OnPaint but after EndPaint does nothing, the solution is to create a separate function to update the OpenGL context and place it wherever you call Refresh/Update.

This is a working example, although is missing proper OpenGL initialization (Viewport,etc):

tooltipfix.cpp
#include "wx/wx.h"
#include "wx/glcanvas.h"
 
/* XPM */
static char * tooltip_xpm[] = {
"16 16 2 1",
" 	c None",
".	c #000000",
"                ",
" .....       .  ",
" . . .       .  ",
"   .         .  ",
"   . ... ... .  ",
"   . . . . . .  ",
"   . ... ... .. ",
"                ",
"   .....        ",
"   . . .        ",
"     .          ",
"     . . ...    ",
"     . . . .    ",
"     . . ...    ",
"         .      ",
"                "};
 
class TooltipFix: public wxApp
{
 public:
  virtual bool OnInit();
 private:
  wxFrame* frame;
};
 
class wxGL: public wxGLCanvas
{
public:
  wxGL(wxWindow *parent, wxWindowID id = wxID_ANY,
        const wxPoint& pos = wxDefaultPosition,
        const wxSize& size = wxDefaultSize, long style = 0,
        const wxString& name = wxGLCanvasName, int *attribList = 0,
        const wxPalette& palette = wxNullPalette)
        : wxGLCanvas(parent,id,pos,size,style,
        name,attribList,palette)
  {
  }
  void Render();
  DECLARE_EVENT_TABLE();
  void OnSize(wxSizeEvent&);
  void OnPaint(wxPaintEvent&);
};
 
BEGIN_EVENT_TABLE(wxGL, wxGLCanvas)
  EVT_SIZE(wxGL::OnSize)
  EVT_PAINT(wxGL::OnPaint)
END_EVENT_TABLE()
 
void wxGL::OnSize(wxSizeEvent& event)
{
  Render();
}
 
void wxGL::OnPaint(wxPaintEvent& event)
{
  wxPaintDC dc(this);
}
 
void wxGL::Render()
{
  SetCurrent();
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  //.. Add More gl calls here
  SwapBuffers();
}
 
IMPLEMENT_APP(TooltipFix)
 
bool TooltipFix::OnInit()
{
  frame = new wxFrame(NULL,-1,_T("OpenGL Tooltip Fix"), wxPoint(0,0),
    wxSize(640,480),
    (long)wxDEFAULT_FRAME_STYLE|wxMAXIMIZE);
  frame->CreateToolBar();
  wxBitmap tooltip_bmp=wxBitmap(wxImage(tooltip_xpm));
  frame->GetToolBar()->AddTool(1,_T("Tool"),tooltip_bmp,_T("Tooltip"));
  frame->GetToolBar()->Realize();
  wxGLCanvas* wxglcanvas = new wxGL(frame,wxID_ANY);
  frame->Show();
  SetTopWindow(frame);
  return true;
}
Personal tools