From 87dd7f0d23eba5c09e71ec6efeb34c6844f5e95f Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Tue, 29 Dec 1998 14:21:17 +0000 Subject: Revised documentation files. git-svn-id: file:///fltk/svn/fltk/trunk@177 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- documentation/opengl.html | 486 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 486 insertions(+) create mode 100644 documentation/opengl.html (limited to 'documentation/opengl.html') diff --git a/documentation/opengl.html b/documentation/opengl.html new file mode 100644 index 000000000..e26895a2c --- /dev/null +++ b/documentation/opengl.html @@ -0,0 +1,486 @@ + + + +

7 - Using OpenGL

+ +This chapter discusses using FLTK for your OpenGL applications. + +

The OpenGL Widget

+ +

Making a Simple OpenGL Wrapper Widget

+ +

A Simple Flight Simulator

+ +

Using FLTK with OpenGL Optimizer

+ +

Using OpenGL Optimizer for the Flight Simulator

+ + + +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

+ +

+  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) {}
+  };
+
+  void MyWindow::draw() {
+    if (!valid()) {
+      ... set up projection, viewport, etc ...
+      ... window size is in w() and h().
+      ... valid() is turned on by fltk after draw() returns
+    }
+    ... draw ...
+  }
+
+  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;
+    }
+  }
+
+ +

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()! + +

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

+    case FL_PUSH:
+      make_current(); // make glx context current
+      if (!valid()) {
+        ... set up projection exactly the same as draw ...
+        valid(1); // stop it from doing this next time
+      }
+      ... ok to call NON-DRAWING OpenGL code here, such as hit
+      detection ...
+
+ +

Your main program can now create one of your windows by doing "new +MyWindow(...)". You can also use fluid: + +

    +
  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. +
+ +

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);

void Fl_Gl_Window::ortho();

void Fl_Gl_Window::make_current(); +
void Fl_Gl_Window::make_overlay_current(); +
void Fl_Gl_Window::swap_buffers();

void Fl_Gl_Window::hide(); +
Fl_Gl_Window::~Fl_Gl_Window();

Fl_Gl_Window overlay

+ +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

+ +

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 +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: + +

+ +

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. + +

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(). + +

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

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

+ +

Do not call gl_start()/gl_finish() when drawing an +Fl_Gl_Window! + +


+ +

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

+ +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>). + +

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

+ +

Of course GL is no fun unless you can draw your own graphics. This +is done with a subclass that you create: + +

+ +

+#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>
+
+class shape_window : public Fl_Gl_Window {
+  void draw();
+public:
+  int sides;
+  shape_window(int x,int y,int w,int h,const char *l=0);
+};
+
+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;
+}
+
+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());
+  }
+  // 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);
+  }
+  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();
+}
+
+int main(int argc, char **argv) {
+
+  Fl_Window window(300, 330);
+
+  shape_window sw(10, 10, 280, 280);
+  window.resizable(&sw);
+
+  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);
+
+  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] -- cgit v1.2.3