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 importantly, before you show any windows (including those 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:
Fl::gl_visual(FL_RGB);
You can then put OpenGL drawing code anywhere you can draw normally by surrounding it with:
gl_start(); ... put your OpenGL code here ... gl_finish();
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 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 that you can flip the Y coordinates.
Unfortunately, there are a bunch of limitations you must adhere to for maximum portability:
You must choose a default visual with Fl::gl_visual()
You cannot pass FL_DOUBLE to Fl::gl_visual()
You cannot use Fl_Double_Window or Fl_Overlay_Window
Do not call gl_start() or gl_finish() when drawing into an Fl_Gl_Window!