%------------------------------------------------------------------------

\Class{vBaseGLCanvasPane}
\Indextt{vBaseGLCanvasPane}\index{OpenGL}

A specialized base class to support OpenGL graphics.

\subsection* {Synopsis}

\begin{description}
	\item [Header:] \code{<v/vbglcnv.h>}
	\item [Class name:] vBaseGLCanvasPane
 	\item [Hierarchy:] vPane \rta vBaseGLCanvasPane
\end{description}

\subsection* {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 \code{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 \code{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 \code{vPane} for a general description of panes.

\subsection* {Constructor} %------------------------------------
\Meth{vBaseGLCanvasPane(unsigned int vGLmode)}
\Indextt{vBaseGLCanvasPane()}

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

\begin{description}

\item[vGL\_Default] Use the default visual, which includes
\code{vGL\_RGB} and \code{vGL\_DoubleBuffer}. \V\ will
use this default if you don't provide a value to the constructor.

\item[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 \code{vGL\_Alpha} property is also specified.

\item[vGL\_Alpha] Used to include an APLHA plane. Not all
machines support ALPHA planes.

\item[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.

\item[vGL\_DoubleBuffer] Use Double buffering if available.
Single buffering is assumed if \code{vGL\_DoubleBuffer} is not
specified.

\item[vGL\_Stereo] Use a Stereo buffer if available.

\item[vGL\_Stencil] Use Stencil mode if available.

\item[vGL\_Accum] Use accumulation buffers if available.

\item[vGL\_Depth] Use Depth mode if available.

\end{description}

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 \code{vGL\_Default} mode works well
for many OpenGL applications.

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

\subsection* {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\ \code{vCanvasPane} class.

%............................................................
\Meth{VCursor GetCursor()}
\Indextt{GetCursor}

Returns the id of the current cursor being used in the canvas.
See \code{SetCursor}.

%............................................................
\Meth{int GetHeight()}
\Indextt{GetHeight}

Returns the height of the current drawing canvas in pixels.

%............................................................
\Meth{virtual int GetHScroll(int\& Shown, int\& Top)}
\Indextt{GetHScroll}

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

%............................................................
\Meth{virtual int GetVScroll(int\& Shown, int\& Top)}
\Indextt{GetVScroll}

Get the status of the Vertical Scroll bar. See
\code{GetHScroll} for details.

%............................................................
\Meth{virtual int GetWidth()}
\Indextt{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.

%............................................................
\Meth{void SetCursor(VCursor id)}
\Indextt{SetCursor}

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

%............................................................
\Meth{void SetWidthHeight(int width, int height)}
\Indextt{SetWidthHeight}

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

%............................................................
\Meth{virtual void SetHScroll(int Shown, int Top)}
\Indextt{SetHScroll}

Set the horizontal scroll bar
See the description of \code{vCanvasPane} for details.

%............................................................
\Meth{virtual void SetVScroll(int Shown, int Top)}
\Indextt{SetVScroll}\index{scroll bars}

Set the vertical scroll bar. 
See the description of \code{vCanvasPane} for details.

%............................................................
\Meth{virtual void ShowHScroll(int OnOrOff)}
\Indextt{ShowHScroll}
\Meth{virtual void ShowVScroll(int OnOrOff)}
\Indextt{ShowVScroll}\index{scroll bars}

See the description of \code{vCanvasPane} for details.

\subsection* {Methods to Override} %------------------------

%............................................................
\Meth{virtual void HPage(int Shown, int Top)}
\Indextt{HPage}

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

%............................................................
\Meth{virtual void HScroll(int step)}
\Indextt{HScroll}

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

%............................................................
\Meth{virtual void MouseDown(int x, int y, int button)}
\Indextt{MouseDown}

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 \code{vCanvasPane} for details.

%............................................................
\Meth{virtual void MouseMotion(int x, int y)}
\Indextt{MouseMotion}

This is called when the mouse moves while a button is \emph{not}
pressed.
See the description of \code{vCanvasPane} for details.

%............................................................
\Meth{virtual void MouseMove(int x, int y, int button)}
\Indextt{MouseMove}

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

%............................................................
\Meth{virtual void MouseUp(int x, int y, int button)}
\Indextt{MouseUp}

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

%............................................................
\Meth{virtual void Redraw(int x, int y, int height, int width)}
\Indextt{Redraw}

\code{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 \code{Redraw} represent the rectangular area
that needs to be repainted. This areas is not always the whole
canvas, and it is possible that many \code{Redraw} events will
be generated in a row as the user drags a covering window off
the canvas.

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

%............................................................
\Meth{virtual void Resize(int newW, int newH)}
\Indextt{Resize}

A \code{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 \code{Resize} in \code{vBaseGLCanvasPane} is a
no-op, and your subclass needs to override \code{Redraw}.

%............................................................
\Meth{virtual void VPage(int Shown, int Top)}
\Indextt{VPage}

See the description of \code{vCanvasPane} for details.

%............................................................
\Meth{virtual void VScroll(int step)}
\Indextt{VScroll}

See the description of \code{vCanvasPane} for details.

\subsection* {Specific OpenGL methods} %----------------------

%............................................................
\Meth{virtual void graphicsInit(void)}
\Indextt{graphicsInit}

This method is called after the OpenGL drawing canvas has
been created, and \emph{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 \code{graphicsInit} method
in the base \code{vBaseGLCanvasPane} class \emph{first},
then whatever OpenGL calls you need.
See the example in the OpenGL tutorial section for more details.

%............................................................
\Meth{void vglMakeCurrent(void)}
\Indextt{vglMakeCurrent}

This method should be called by your program before you
call any OpenGL drawing code. Normally, this is called
first thing in \code{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.

%............................................................
\Meth{virtual void vglFlush(void)}
\Indextt{vglFlush}

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
\code{Redraw} method.
        
%............................................................
\Meth{virtual XVisualInfo* GetXVisualInfo()}
\Indextt{GetXVisualInfo()}

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

\subsection* {Tutorial} %---------------------------------------

A minimal V/OpenGL application will consist of a class derived
from \code{vApp}, a class derived from \code{vCmdWindow}, and
a canvas pane class derived from \code{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
\code{graphicsInit} method, and the \code{Redraw} method. The
following code fragment, adapted directly from the example code
in Mark J. Kilgard's book, \emph{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 \code{opengl/shapes} directory
in the \V\ distribution.

\footnotesize
\begin{verbatim}

  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
  }

  ....
\end{verbatim}
\normalfont\normalsize

Note that this example includes a method called \code{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 \code{v/opengl} directory for
a complete example of animation using the timer.

\subsection* {See Also} %---------------------------------------

vCanvasPane
