From 367f908d8ed5a3464b9676223a26ddf4e11bdb5b Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 7 Jan 1999 16:36:11 +0000 Subject: "Final" changes for first draft of 1.0 documentation. git-svn-id: file:///fltk/svn/fltk/trunk@187 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- documentation/opengl.html | 666 +++++++++++++++++++--------------------------- 1 file changed, 270 insertions(+), 396 deletions(-) (limited to 'documentation/opengl.html') diff --git a/documentation/opengl.html b/documentation/opengl.html index e26895a2c..f566d30ad 100644 --- a/documentation/opengl.html +++ b/documentation/opengl.html @@ -1,486 +1,360 @@ -

7 - Using OpenGL

+

9 - Using OpenGL

This chapter discusses using FLTK for your OpenGL applications. -

The OpenGL Widget

+

Using OpenGL in FLTK

-

Making a Simple OpenGL Wrapper Widget

+The easiest way to make an OpenGL display is to subclass Fl_Gl_Window. Your subclass must +implement a draw() method which uses OpenGL calls to draw the +display. Your main program should call redraw() when the +display needs to change, and (somewhat later) FLTK will call +draw(). -

A Simple Flight Simulator

+

With a bit of care you can also use OpenGL to draw into normal FLTK +windows. This is mostly useful because you can use Gourand shading for +drawing your widgets. To do this you use the gl_start() and gl_finish() functions around your OpenGL +code. -

Using FLTK with OpenGL Optimizer

+

You must include FLTK's <FL/gl.h> header file. It will include +the file <GL/gl.h>, define some extra drawing functions +provided by FLTK, and include the <windows.h> header file needed +by WIN32 applications. -

Using OpenGL Optimizer for the Flight Simulator

+

Making a Subclass of Fl_Gl_Window

- - -Using OpenGL in Fltk - -

Using OpenGL in Fltk
#include <FL/gl.h>

- -The easiest way to make an OpenGL display is to subclass Fl_Gl_Window. -Your subclass should implement a draw() method which uses OpenGL calls -to draw the display. Your main program should call w->redraw() when -the display needs to change, and (somewhat later) fltk will call -draw(). - -

With a bit of care you can also use OpenGL to draw into normal fltk -windows. This is mostly useful because you can access Gourand shading -for drawing your widgets. To do this you use the gl_start() and gl_finish() functions around your -OpenGL code. - -

You must include fltk's <FL/gl.h> header file. It will include -the file <GL/gl.h>, plus it defines some extra drawing functions -provided by fltk, and also gets around a horrid screwup by our friends -in Seattle. - -

Sample code for subclassing Fl_Gl_Window

+To make a subclass of Fl_Gl_Window, you must provide: -

-  class MyWindow : public Fl_Gl_Window {
-    void draw();
-    int handle(int);
-  public:
-    MyWindow(int X, int Y, int W, int H, const char* L)
-      : Fl_Gl_Window(X,Y,W,H,L) {}
-  };
+
 
-  int MyWindow::handle(int event) {
-    switch(event) {
-    case FL_PUSH:
-      ... mouse down event ...
-      ... position in Fl::event_x() and Fl::event_y()
-      return 1;
-    case FL_DRAG:
-      ... mouse moved while down event ...
-      return 1;
-    case FL_RELEASE:    
-      ... mouse up event ...
-      return 1;
-    case FL_KEYBOARD:
-      ... keypress, key is in Fl::event_key(), ascii in Fl::event_text()
-      return 1;
-    default:
-      // tell fltk that I don't understand other events
-      return 0;
-    }
-  }
-
+

Defining the Subclass

-

When handle() is called, the glx context is not set up! If your -display changes, you should call redraw() and let draw() do the work. -Don't call any gl functions from inside handle()! +To define the subclass you just subclass Fl_Gl_Window class: -

This may mean you cannot call some OpenGl stuff like hit detection. -You can fix this by doing: +

-

Your main program can now create one of your windows by doing "new -MyWindow(...)". You can also use fluid: +The draw() and handle() methods are described below. Like +any widget, you can include additional private and public data in your class +(such as scene graph information, etc.) -

    -
  1. Put your class definition in a MyWindow.H file. -
  2. In fluid create a box object, resize & place where you want. -
  3. In the control panel, fill in the "class" field with MyWindow.H. -This will make fluid produce constructors for your new class. -
  4. In the "extra code" put "#include "MyWindow.H"", so that the fluid -output file will compile. -
+

The draw() Method

-

You must put glwindow->show() in your main code after calling -show() on the window containing the gl window. - -


-

class Fl_Gl_Window : public Fl_Window

- -

An Fl_Gl_Window sets things up so OpenGL works, and also keeps an -OpenGL "context" for that window, so that changes to the lighting and -projection may be reused between redraws. Fl_Gl_Window also flushes -the OpenGL streams and swaps buffers after draw() returns. - -

Fl_Gl_Window::draw() is a pure virtual method. You must subclass -Fl_Gl_Window and provide an implementation for draw(). You may also -provide an implementation of draw_overlay() if you want to draw into -the overlay planes. You can avoid reinitializing the viewport and -lights and other things by checking valid() at the start of draw() and -only doing the initialization if it is false. - -

The draw() method can only use OpenGL calls. Do not attempt to -call X, any of the functions in <FL/fl_draw.H>, or glX directly. Do -not call gl_start() or gl_finish(). - -

Methods:

- -

Fl_Gl_Window::Fl_Gl_Window(int W, int H, const char *l=0); -
Fl_Gl_Window::Fl_Gl_Window(int X, int Y, int W, int H, const char -*l=0)

const int Fl_Gl_Window::mode() const; -
int Fl_Gl_Window::mode(int);

int Fl_Gl_Window::mode(const int *);

static int Fl_Gl_Window::can_do(int); -
static int Fl_Gl_Window::can_do(const int *mode); -
int Fl_Gl_Window::can_do() const;

char Fl_Gl_Window::valid() const; -
void Fl_Gl_Window::invalidate(); -
void Fl_Gl_Window::valid(char i);

Fl_Gl_Window overlay

+

You can call some OpenGL stuff like hit detection and texture loading +functions by doing: -GL hardware typically provides some overlay bit planes, which are very -useful for drawing UI controls atop your 3D graphics. If the overlay -hardware is not provided, fltk tries to simulate the overlay, this works -pretty well if your graphics are double buffered, but not very well -for single-buffered. +

-

int Fl_Gl_Window::can_do_overlay();

void Fl_Gl_Window::redraw_overlay();

virtual void Fl_Gl_Window::draw_overlay();


- -

Using OpenGL in normal Fltk windows

+

Using OpenGL in Normal FLTK Windows

-

You can put OpenGL code into an Fl_Widget::draw() method or into the code -for a boxtype or other places, with some care. +You can put OpenGL code into an Fl_Widget::draw() method or into the code for +a boxtype or other places with some care.

Most important, before you show any windows (including those -that don't have OpenGL drawing) you must initialize fltk/X so that it +that don't have OpenGL drawing) you must initialize FLTK so that it knows it is going to use OpenGL. You may use any of the symbols -described for Fl_Gl_Window::mode() to describe how -you intend to use OpenGL: +described for Fl_Gl_Window::mode() to describe +how you intend to use OpenGL: -

+ -

You can then put OpenGL drawing code anywhere you can draw normally +You can then put OpenGL drawing code anywhere you can draw normally by surrounding it with: -

+ -

gl_start() and gl_finish() set up a GL context with an orthographic -projection so that 0,0 is the lower-left corner of the window and each -pixel is one unit. The current clipping is reproduced with OpenGL -scissor commands. These also synchronize the OpenGL graphics stream -with the drawing done by other X or fltk functions. +gl_start() and gl_finish() set up an OpenGL context with +an orthographic projection so that 0,0 is the lower-left corner of the +window and each pixel is one unit. The current clipping is reproduced +with OpenGL glScissor() commands. These also synchronize the +OpenGL graphics stream with the drawing done by other X, WIN32, or FLTK +functions.

The same context is reused each time. If your code changes the -projection transformation or anything else you should use glPush/glPop -to put the state back before calling gl_finish(). +projection transformation or anything else you should use +glPushMatrix() and glPopMatrix() functions to put the +state back before calling gl_finish(). -

You may want to use Fl_Window::current()->h() to get -the drawable height so you can flip the coordinate system. +

You may want to use Fl_Window::current()->h() to get +the drawable height so you can flip the Y coordinates. -

Unfortunately there are a bunch of limitations you must adhere to for -maximum portability:


- -

OpenGL drawing functions -
#include <FL/gl_draw.H>

+

OpenGL drawing functions

-Fltk provides some useful gl drawing functions. They can be freely -mixed with any OpenGL calls, and are defined by including <FL/gl.H> -(which you should include instead of the OpenGL header <GL/gl.h>). +FLTK provides some useful OpenGL drawing functions. They can be freely +mixed with any OpenGL calls, and are defined by including +<FL/gl.H> (which you should include instead of the OpenGL +header <GL/gl.h>). -

void gl_color(Fl_Color);

void gl_rect(int x,int y,int w,int h); -
void gl_rectf(int x,int y,int w,int h);

void gl_font(Fl_Font fontid, int size);

int gl_height(); -
int gl_descent(); -
float gl_width(const char *); -
float gl_width(const char *, int n); -
float gl_width(uchar);

void gl_draw(const char *); -
void gl_draw(const char *, int n);

void gl_draw(const char *, int x, int y); -
void gl_draw(const char *, int n, int x, int y);

void gl_draw(const char *, int x, int y, int w, int h, Fl_Align);

-

(back to contents) -Fltk example: shape.C -

shape.C

+

Using OpenGL Optimizer with FLTK

-

Of course GL is no fun unless you can draw your own graphics. This -is done with a subclass that you create: +OpenGL Optimizer is +a scene graph toolkit for OpenGL available from Silicon Graphics for +IRIX and Microsoft Windows. Versions are in the works for Solaris and +HP-UX. It allows you to view large scenes without writing a lot of +OpenGL code. + +

OptimizerWindow Class Definition

-

+To use OpenGL Optimizer with FLTK you'll need to create a subclass of +Fl_Gl_Widget that includes several state variables: -

-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include <FL/Fl_Hor_Slider.H>
-#include <FL/math.h>
-#include <FL/gl.h>
-#include <FL/Fl_Gl_Window.H>
+
 
-shape_window::shape_window(int x,int y,int w,int h,const char *l) :
-Fl_Gl_Window(x,y,w,h,l) {
-  sides = 3;
-}
+

The camera() Method

-void shape_window::draw() { - // the valid() property may be used to avoid reinitializing your - // GL transformation for each redraw: - if (!valid()) { - valid(1); - glLoadIdentity(); - glViewport(0,0,w(),h()); +The camera() method sets the camera (projection and viewpoint) +to use when drawing the scene. The scene is redrawn after this call. + +

The draw() Method

+ +The draw() method performs the needed initialization +and does the actual drawing: + +
    +void OptimizerWindow::draw() {
    +  if (!context_) {
    +    // This is the first time we've been asked to draw; create the
    +    // Optimizer context for the scene...
    +
    +    context_ = new csContext(fl_display, fl_visual);
    +    context_->ref();
    +    context_->makeCurrent(fl_display, fl_window);
    +
    +    ... perform other context setup as desired ...    
    +
    +    // Then create the draw action to handle drawing things...
    +
    +    draw_action_ = new csDrawAction;
    +    if (camera_) {
    +      draw_action_->setCamera(camera_);
    +      camera_->draw(draw_action_);
    +    }
       }
    -  // draw an amazing graphic:
    -  glClear(GL_COLOR_BUFFER_BIT);
    -  glColor3f(.5,.6,.7);
    -  glBegin(GL_POLYGON);
    -  for (int i=0; i<sides; i++) {
    -    double ang = i*2*M_PI/sides;
    -    glVertex3f(cos(ang),sin(ang),0);
    +
    +  if (!valid()) {
    +    // Update the viewport for this context...
    +    context_->setViewport(0, 0, w(), h());
       }
    -  glEnd();
    -}
     
    -// when you change the data, as in this callback, you must call redraw():
    -void sides_cb(Fl_Widget *o, void *p) {
    -  shape_window *sw = (shape_window *)p;
    -  sw->sides = int(((Fl_Slider *)o)->value());
    -  sw->redraw();
    -}
    +  // Clear the window...
     
    -int main(int argc, char **argv) {
    +  context_->clear(csContext::COLOR_CLEAR | csContext::DEPTH_CLEAR,
    +                  0.0f,		// Red
    +		  0.0f,		// Green
    +		  0.0f,		// Blue
    +		  1.0f);	// Alpha
     
    -  Fl_Window window(300, 330);
    +  // Then draw the scene (if any)...
     
    -  shape_window sw(10, 10, 280, 280);
    -  window.resizable(&sw);
    +  if (scene_)
    +    draw_action_->apply(scene_);
    +}
    +
- Fl_Hor_Slider slider(50, 295, window.w()-60, 30, "Sides:"); - slider.align(FL_ALIGN_LEFT); - slider.callback(sides_cb,&sw); - slider.value(sw.sides); - slider.step(1); - slider.bounds(3,40); +

The scene() Method

- window.show(argc,argv); - - return Fl::run(); -} -
- -

To do your own drawing, you must subclass Fl_Gl_Window. The virtual method draw() is called when the window should -update. You can only draw into the window inside a draw() method. -You call the method redraw() on the -window to indicate that draw() needs to be called. It won't actually -be called until Fl::wait() is called. - -

The window may be made a child of another window, as it is here. -This is done by add()ing it to a parent before you show() it. If -you don't want to make a child window, be sure to end() the previous -window! The Fl_Gl_Window constructor automatically does end() so -you don't accidentally add children to it. - -

The files <FL/math.h> and <FL/gl.h> are wrappers for the -normal header files. You should use them to port to MSWindows because -the MicroSoft header files have errors or ommisions in them. - -

[back to contents] +The scene() method sets the scene to be drawn. The scene is +a collection of 3D objects in a csGroup. The scene is redrawn +after this call. + + + -- cgit v1.2.3