The V C++ GUI Framework:vBaseGLCanvasPane

From EDM2
Jump to: navigation, search

A specialized base class to support OpenGL graphics.

Synopsis

Header:
<v/vbglcnv.h>
Class name:
vBaseGLCanvasPane
Hierarchy:
vPane ->vBaseGLCanvasPane

Description

This is a specialized class to provide very basic support for the OpenGL graphics package. Unlike other V canvas panes, this class does not use a vDC class. Instead, it has a few features designed to support OpenGL.

This is a basic class. It does not provide many convenience methods to support OpenGL at a high level, but it does hide all the messy details of interfacing with the host GUI environment, and provides the first really easy way to generate sophisticated interfaces for OpenGL applications. A more sophisticated class called vGLCanvasPane that will provide a number of convenience operations is under development, but the base class is still very useful.

By following a standard convention to structure V/OpenGL code, it is relatively easy to generate applications. The details of this convention are explained in the tutorial section of this description.

See the section vPane for a general description of panes.

Constructor

vBaseGLCanvasPane(unsigned int vGLmode)

The vBaseGLCanvasPane constructor allows you to specify certain attributes of the visual used by OpenGL. The options, which can be ORed together, include:

vGL_Default
Use the default visual, which includes vGL_RGB and vGL_DoubleBuffer. V will use this default if you don't provide a value to the constructor.
vGL_RGB
This is the standard RGBA mode used by most OpenGL programs. The size of the RED, GREEN, and BLUE planes are maximized according to the capabilities of the host machine. An ALPHA plane is not included unless the vGL_Alpha property is also specified.
vGL_Alpha
Used to include an APLHA plane. Not all machines support ALPHA planes.
vGL_Indexed
Use indexed rather than RGB mode. V will attempt to maximize the usefulness of the palette. You should not specify both RGB and Indexed.
vGL_DoubleBuffer
Use Double buffering if available. Single buffering is assumed if vGL_DoubleBuffer is not specified.
vGL_Stereo
Use a Stereo buffer if available.
vGL_Stencil
Use Stencil mode if available.
vGL_Accum
Use accumulation buffers if available.
vGL_Depth
Use Depth mode if available.

Not all of these attributes are available on all OpenGL implementations, and V will attempt to get a reasonable visual based on your specifications. For now, the vGL_Default mode works well for many OpenGL applications.

V supports only one visual per application, and the first vBaseGLCanvasPane created determines the attributes of the visual used.

Utility Methods

The following methods provide useful service without modification. Sometimes you will want to override some of these, but you will then usually call these methods from your derived class. Most of these methods are the equivalent of the normal V vCanvasPane class.

VCursor GetCursor()

Returns the id of the current cursor being used in the canvas. See SetCursor.

virtual int GetHeight()

Returns the height of the current drawing canvas in pixels.

virtual int GetHScroll(int& Shown, int& Top)

Get the status of the Horizontal Scroll bar. Returns 1 if the scroll bar is displayed, 0 if not. Returns in Shown and Top the current values of the scroll bar. See SetVScroll for a description of the meanings of parameters.

virtual int GetVScroll(int& Shown, int& Top)

Get the status of the Vertical Scroll bar. See GetHScroll for details.

virtual int GetWidth()

Returns the width of the current drawing canvas in pixels. This is either the initial size of the window, or the size after the user has resized the window.

void SetCursor(VCursor id)

This method sets the cursor displayed while the mouse in in the current canvas area. See the description of vCanvasPane for details.

void SetWidthHeight(int width, int height)

This will set the size of the drawing canvas to height and width in pixels. It will also cause a Resize event message to be sent to the window.

virtual void SetHScroll(int Shown, int Top)

Set the horizontal scroll bar See the description of vCanvasPane for details.

virtual void SetVScroll(int Shown, int Top)

Set the vertical scroll bar. See the description of vCanvasPane for details.

virtual void ShowHScroll(int OnOrOff)

virtual void ShowVScroll(int OnOrOff)

See the description of vCanvasPane for details.

Methods to Override

virtual void HPage(int Shown, int Top)

When the user moves the horizontal scroll bar, it generates an HPage event. See the description of vCanvasPane for details.

virtual void HScroll(int step)

This method is called when the user enters a single step command to the scroll bar. See the description of vCanvasPane for details.

virtual void MouseDown(int x, int y, int button)

This is called when the user clicks a button on the mouse.

It is important to remember that all mouse coordinates are in screen pixels, and use 0,0 as the upper left corner. You will probably have to map them to the actual coordinates in use by your OpenGL graphic.

See the description of vCanvasPane for details.

virtual void MouseMotion(int x, int y)

This is called when the mouse moves while a button is not pressed. See the description of vCanvasPane for details.

virtual void MouseMove(int x, int y, int button)

This is called when the mouse moves while a button is pressed. See the description of vCanvasPane for details.

virtual void MouseUp(int x, int y, int button)

This is called when the user releases the mouse button. See the description of vCanvasPane for details.

virtual void Redraw(int x, int y, int width, int height)

Redraw is called when the canvas needs to be redrawn. The first redraw is generated when the canvas is first created. Other redraws are generated when the canvas is covered or uncovered by another window, and means the contents of the canvas must be repainted. Normally, you will put a call to the code that redraws your OpenGl picture here.

The parameters of Redraw represent the rectangular area that needs to be repainted. This areas is not always the whole canvas, and it is possible that many Redraw events will be generated in a row as the user drags a covering window off the canvas.

The default Redraw in vBaseGLCanvasPane is a no-op, and your subclass needs to override Redraw.

virtual void Resize(int newW, int newH)

A Resize event is generated when the user changes the size of the canvas using the resize window command provided by the host windowing system.

The default Resize in vBaseGLCanvasPane is a no-op, and your subclass needs to override Redraw.

virtual void VPage(int Shown, int Top)

See the description of vCanvasPane for details.

virtual void VScroll(int step)

See the description of vCanvasPane for details.

Specific OpenGL methods

virtual void graphicsInit(void)

This method is called after the OpenGL drawing canvas has been created, and must be overridden by your code. You use this method to set up whatever you would usually do to initialize OpenGL. In practice, this is a very convenient way to get things started.

It is critical that you call the graphicsInit method in the base vBaseGLCanvasPane class first, then whatever OpenGL calls you need. See the example in the OpenGL tutorial section for more details.

void vglMakeCurrent(void)

This method should be called by your program before you call any OpenGL drawing code. Normally, this is called first thing in Redraw, or whatever code you use to draw with. It is essential to call this, and since it is cheap to call this for an already current drawing canvas, it is better to be safe.

virtual void vglFlush(void)

Call this method after you are finished calling OpenGL to draw a picture. It automatically handles the details of displaying your picture in the window, including double buffering and synchronization. It is normally found in your Redraw method.

virtual XVisualInfo* GetXVisualInfo()

This method is specific to X, and will return a pointer to the XVisualInfo structure currently being used. There will be an equivalent method available for MS-Windows.

Tutorial

A minimal V/OpenGL application will consist of a class derived from vApp, a class derived from vCmdWindow, and a canvas pane class derived from vBaseGLCanvasPane. Most of your drawing code will be in or called from your derived canvas pane.

Within that class, you will minimally need to override the graphicsInit method, and the Redraw method. The following code fragment, adapted directly from the example code in Mark J. Kilgard's book, OpenGL, Programming for the X Window System, shows how simple it can be to draw a picture. The full code can be found in the opengl/shapes directory in the V distribution.

  static int initDone = 0;

  ......

//==========>>> testGLCanvasPane::graphicsInit <<<=================
  void testGLCanvasPane::graphicsInit(void)
  {
    // Always call the superclass first!
    vBaseGLCanvasPane::graphicsInit();

    // Example from Mark Kilgard
    glEnable(GL_DEPTH_TEST);
    glClearDepth(1.0);
    glClearColor(0.0, 0.0, 0.0, 0.0);  /* clear to black */
    glMatrixMode(GL_PROJECTION);
    gluPerspective(40.0, 1.0, 10.0, 200.0);
    glMatrixMode(GL_MODELVIEW);
    glTranslatef(0.0, 0.0, -50.0);
    glRotatef(-58.0, 0.0, 1.0, 0.0);

    initDone = 1;
  }

//============>>> testGLCanvasPane::Spin <<<=======================
  void testGLCanvasPane::Spin()
  {
    // Called from the parent CmdWindow for animation
    vglMakeCurrent();              // Call this FIRST!
    glRotatef(2.5, 1.0, 0.0, 0.0);
    Redraw(0,0,0,0);
  }

//============>>> testGLCanvasPane::Redraw <<<=====================
  void testGLCanvasPane::Redraw(int x, int y, int w, int h)
  {
    static int inRedraw = 0;

    if (inRedraw || !initDone)  // Don't draw until initialized
 	return;

    inRedraw = 1;               // Don't allow recursive redraws.

    vglMakeCurrent();           // Call this to make current

    // Code taken directly from Mark J. Kilgard's example
    // Draws 3 intersecting triangular planes
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBegin(GL_POLYGON);
    glColor3f(0.0, 0.0, 0.0); glVertex3f(-10.0, -10.0, 0.0);
    glColor3f(0.7, 0.7, 0.7); glVertex3f(10.0, -10.0, 0.0);
    glColor3f(1.0, 1.0, 1.0); glVertex3f(-10.0, 10.0, 0.0);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(1.0, 1.0, 0.0); glVertex3f(0.0, -10.0, -10.0);
    glColor3f(0.0, 1.0, 0.7); glVertex3f(0.0, -10.0, 10.0);
    glColor3f(0.0, 0.0, 1.0); glVertex3f(0.0, 5.0, -10.0);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(1.0, 1.0, 0.0); glVertex3f(-10.0, 6.0, 4.0);
    glColor3f(1.0, 0.0, 1.0); glVertex3f(-10.0, 3.0, 4.0);
    glColor3f(0.0, 0.0, 1.0); glVertex3f(4.0, -9.0, -10.0);
    glColor3f(1.0, 0.0, 1.0); glVertex3f(4.0, -6.0, -10.0);
    glEnd();

    vglFlush();    // Call when done drawing to display

    inRedraw = 0;  // Not in here any more
  }
  ....

Note that this example includes a method called Spin. It is used to animate the intersecting planes. In a V OpenGL application, the easiest way to implement animation is with the timer. Create a timer in the Command Window class, and then call the animation code in the canvas in response to timer events. You should keep code to prevent recursive redraws if the timer events end up occurring faster than the picture can be rendered, which might happen for complex pictures or heavily loaded systems. See the example code in the v/opengl directory for a complete example of animation using the timer.

Comments

You should be able to include regular V Canvases in your application, as well as OpenGL canvases. In versions before 1.20, the OpenGl canvas was a replacement for the standard vCanvasPane. It is now properly derived from vCanvasPane.

I've tried to make the OpenGL canvas easy to use. The best way (for now) to learn how to use the class is to look at the sample programs included here. To use it, compile your code, and link it with the V library and the V OpenGL library.

This version has been tested on Linux with Mesa 2.6. It used to run on Silicon Graphics machines, and there is no reason to assume that has changed.

When I installed Mesa, I had to add some symbolic links to have it link like standard OpenGL, but you could also change the library switches in the Makefiles.

There are a several of samples, some derived from GLUT, others from the Mesa distribution. Each sample is included in a separate directory. There are mingw32 makefiles for MS-Windows for all examples, and Linux makefiles for many.

This documentation for vBaseGLCanvasPane is still incomplete. The best way to use it is to look at and the examples. I've only been able to get the Windows version to work correctly under mingw32 and Borland C++ 5.0. Microsoft C++ 4.0 couldn't find the proper link libraries. If someone knows how to get this problem solved, please let me know.

The Mingw32 distribution requires proper .h files. They are included in the gnuwin32 directory. The OpenGL header files I provide are edited to remove references to CALLBACK parameters, which means the tesselation stuff doesn't work.

The Windows version doesn't seem to support Indexed color mode, even though the definitions are there, and some code looks like it generates a correct graphics context. The problem for now seems to be there is no equivalent of glutSetColor to set a color index. Does ANYONE in the whole world actually use Indexed color? If so, then I'll look at glut and see if I can add indexed color support.

I am working on developing a new vOpenGLCanvasPane class with a V user. The new class will have built in support for some vector stuff and some lighting stuff. Would anyone like some of the glut shapes: spheres, cubes, etc? They shouldn't be too hard to add, but I don't know if they really get used.

See Also

vCanvasPane