# vBaseGLCanvasPane

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, which now seems to be a standard library. Unfortunately, the very latest versions of Linux (e.g., Redhat 7.x and Mandrake 8.x, late 2001) do not include the required `GLw libraries`. To get these, you must download the latest Mesa source files, and build the `GLw` libraries, which are found in the `widgets-mesa` subdirectory. After you build and install those, you will probably need to add symbolic links for `libGLw.a` to the default `libMesaGLw.a`.

Also, there might be some problems with where the sample makefiles expect to find the GL libs and includes. 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 <v/vbglcnv.h> 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 tessellation 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.

## See Also

vCanvasPane