293 lines
6.8 KiB
C++
293 lines
6.8 KiB
C++
//
|
|
// "$Id$"
|
|
//
|
|
// OpenGL window group widget for the Fast Light Tool Kit (FLTK).
|
|
//
|
|
// Copyright 1998-2010 by Bill Spitzak and others.
|
|
//
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
// file is missing or damaged, see the license at:
|
|
//
|
|
// http://www.fltk.org/COPYING.php
|
|
//
|
|
// Please report all bugs and problems on the following page:
|
|
//
|
|
// http://www.fltk.org/str.php
|
|
//
|
|
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <FL/Fl.H>
|
|
#include <FL/Fl_Box.H>
|
|
//#include "Fl_Gl_Choice.H"
|
|
#if 1 //---------------- Extract from Fl_Gl_Choice.H
|
|
#ifdef WIN32
|
|
# include <FL/gl.h>
|
|
# define GLContext HGLRC
|
|
#elif defined(__APPLE_QUARTZ__)
|
|
# include <OpenGL/gl.h>
|
|
# include <AGL/agl.h>
|
|
# define GLContext AGLContext
|
|
#else
|
|
# include <GL/glx.h>
|
|
# define GLContext GLXContext
|
|
#endif
|
|
GLContext fl_create_gl_context(XVisualInfo*);
|
|
void fl_set_gl_context(Fl_Window*, GLContext);
|
|
void fl_delete_gl_context(GLContext);
|
|
#endif //----------------
|
|
#include <fltk/xFl_Gl_Window_Group.H> //#include <FL/Fl_Gl_Window_Group.H>
|
|
#include <FL/fl_draw.H>
|
|
#include <FL/gl.h>
|
|
|
|
#if 1 //HAVE_GL
|
|
|
|
#if !defined(GL_TEXTURE_RECTANGLE) && defined(WIN32)
|
|
# define GL_TEXTURE_RECTANGLE 0x84F5
|
|
#endif
|
|
|
|
#define Gl_Stand_In Fl_Gl_Window_Group_INTERNAL
|
|
|
|
#define RESET_FIELDS() \
|
|
imgbuf = NULL; \
|
|
offscr_w = -1; \
|
|
offscr_h = -1
|
|
|
|
class Gl_Stand_In : public Fl_Box {
|
|
|
|
Fl_Gl_Window_Group *glwg;
|
|
|
|
public:
|
|
|
|
Gl_Stand_In(int W, int H, Fl_Gl_Window_Group *w)
|
|
: Fl_Box(0, 0, W, H) {
|
|
glwg = w;
|
|
}
|
|
|
|
int handle(int event) { return glwg->handle_gl(event); }
|
|
|
|
protected:
|
|
|
|
void draw(void) { Fl::fatal("Never call this"); }
|
|
|
|
virtual void dummy(void);
|
|
};
|
|
|
|
void Gl_Stand_In::dummy(void) {}
|
|
|
|
void Fl_Gl_Window_Group::init(void) {
|
|
begin(); // Revert the end() in the Fl_Gl_Window constructor
|
|
glstandin = new Gl_Stand_In(w(), h(), this);
|
|
children_context = NULL;
|
|
texid = 0;
|
|
RESET_FIELDS();
|
|
}
|
|
|
|
Fl_Gl_Window_Group::~Fl_Gl_Window_Group(void) {
|
|
delete glstandin;
|
|
}
|
|
|
|
void Fl_Gl_Window_Group::adjust_offscr(int w, int h) {
|
|
if (imgbuf == NULL) {
|
|
// Find maximum width and height across all visible child widgets
|
|
// (except for the GL stand-in widget)
|
|
Fl_Widget*const* a = array();
|
|
for (int i = children(); i--;) {
|
|
Fl_Widget* o = a[i];
|
|
if (o == glstandin) continue;
|
|
if (!o->visible()) continue;
|
|
int cw = o->w();
|
|
int ch = o->h();
|
|
if (offscr_w < cw) offscr_w = cw;
|
|
if (offscr_h < ch) offscr_h = ch;
|
|
}
|
|
} else {
|
|
fl_delete_offscreen(offscr);
|
|
}
|
|
|
|
if (w > offscr_w) offscr_w = w;
|
|
if (h > offscr_h) offscr_h = h;
|
|
|
|
offscr = fl_create_offscreen(offscr_w, offscr_h);
|
|
|
|
int imgbuf_size = offscr_w * offscr_h * 3; // GL_RGB
|
|
imgbuf = (uchar *)realloc(imgbuf, (size_t)imgbuf_size);
|
|
}
|
|
|
|
void Fl_Gl_Window_Group::show() {
|
|
Fl_Gl_Window::show();
|
|
|
|
if (!children_context) {
|
|
children_context = fl_create_gl_context(fl_visual);
|
|
fl_set_gl_context(this, children_context);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
glEnable(GL_TEXTURE_RECTANGLE);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
glGenTextures(1, &texid);
|
|
glBindTexture(GL_TEXTURE_RECTANGLE, texid);
|
|
make_current();
|
|
}
|
|
}
|
|
|
|
void Fl_Gl_Window_Group::hide() {
|
|
if (children_context) {
|
|
fl_set_gl_context(this, children_context);
|
|
glDeleteTextures(1, &texid);
|
|
texid = 0;
|
|
make_current();
|
|
fl_delete_gl_context(children_context);
|
|
children_context = NULL;
|
|
}
|
|
|
|
Fl_Gl_Window::hide();
|
|
}
|
|
|
|
/**
|
|
Deletes all child widgets from memory recursively.
|
|
|
|
This method differs from the remove() method in that it
|
|
affects all child widgets and deletes them from memory.
|
|
*/
|
|
void Fl_Gl_Window_Group::clear(void) {
|
|
if (imgbuf != NULL) {
|
|
fl_delete_offscreen(offscr);
|
|
free(imgbuf);
|
|
RESET_FIELDS();
|
|
}
|
|
remove(glstandin);
|
|
Fl_Gl_Window::clear();
|
|
add(glstandin);
|
|
}
|
|
|
|
int Fl_Gl_Window_Group::handle_gl(int event) {
|
|
// Override me
|
|
return 0;
|
|
}
|
|
|
|
void Fl_Gl_Window_Group::flush(void) {
|
|
// Fl_Window::make_current() does this, but not
|
|
// Fl_Gl_Window::make_current(), and we can't override make_current()
|
|
// and have Fl_Gl_Window::flush() call us
|
|
|
|
Fl_Window::make_current();
|
|
Fl_Gl_Window::make_current();
|
|
|
|
Fl_Gl_Window::flush();
|
|
}
|
|
|
|
void Fl_Gl_Window_Group::draw(void) {
|
|
if (damage()) {
|
|
draw_gl();
|
|
draw_children();
|
|
}
|
|
}
|
|
|
|
/**
|
|
Draws all children of the group.
|
|
*/
|
|
void Fl_Gl_Window_Group::draw_children(void) {
|
|
fl_set_gl_context(this, children_context);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glOrtho(0, w(), 0, h(), -1.0, 1.0);
|
|
glTranslatef(0.0, h(), 0.0);
|
|
glScalef(1.0, -1.0, 1.0);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glViewport(0, 0, w(), h());
|
|
|
|
Fl_Widget*const* a = array();
|
|
for (int i = children(); i--;) draw_child(**a++);
|
|
|
|
#if 1
|
|
int err = glGetError();
|
|
if (err != GL_NO_ERROR) {
|
|
Fl::warning("OpenGL error after drawing Fl_Gl_Window_Group children: 0x0%X", err);
|
|
}
|
|
#endif
|
|
|
|
make_current();
|
|
}
|
|
|
|
/**
|
|
This draws a child widget, if it is not clipped.
|
|
The damage bits are cleared after drawing.
|
|
*/
|
|
void Fl_Gl_Window_Group::draw_child(Fl_Widget& widget) {
|
|
if (&widget == glstandin) return;
|
|
|
|
if (!widget.visible() || widget.type() >= FL_WINDOW ||
|
|
!fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) return;
|
|
|
|
if (widget.w() > offscr_w || widget.h() > offscr_h) {
|
|
adjust_offscr(widget.w(), widget.h());
|
|
}
|
|
|
|
int widget_x = widget.x();
|
|
int widget_y = widget.y();
|
|
int widget_w = widget.w();
|
|
int widget_h = widget.h();
|
|
|
|
widget.position(0, 0);
|
|
|
|
fl_begin_offscreen(offscr);
|
|
fl_rectf(0, 0, widget_w, widget_h, FL_MAGENTA);
|
|
widget.clear_damage(FL_DAMAGE_ALL);
|
|
widget.draw();
|
|
widget.clear_damage();
|
|
fl_read_image(imgbuf, 0, 0, widget_w, widget_h);
|
|
fl_end_offscreen();
|
|
|
|
widget.position(widget_x, widget_y);
|
|
|
|
#ifdef USE_GLDRAWPIXELS // Note: glDrawPixels() is deprecated
|
|
|
|
glRasterPos2i(widget_x, widget_y);
|
|
glPixelZoom(1.0, -1.0);
|
|
glDrawPixels(widget_w, widget_h, GL_RGB, GL_UNSIGNED_BYTE, imgbuf);
|
|
|
|
#else // ! USE_GLDRAWPIXELS
|
|
|
|
glTexImage2D(
|
|
GL_TEXTURE_RECTANGLE,
|
|
0,
|
|
GL_RGB,
|
|
widget_w, widget_h,
|
|
0,
|
|
GL_RGB,
|
|
GL_UNSIGNED_BYTE,
|
|
imgbuf);
|
|
|
|
#define CORNER(x,y) glTexCoord2f(x, y); glVertex2f(widget_x + x, widget_y + y)
|
|
glBegin(GL_QUADS);
|
|
CORNER(0, 0);
|
|
CORNER(widget_w, 0);
|
|
CORNER(widget_w, widget_h);
|
|
CORNER(0, widget_h);
|
|
glEnd();
|
|
#undef CORNER
|
|
|
|
#endif // ! USE_GLDRAWPIXELS
|
|
}
|
|
|
|
void Fl_Gl_Window_Group::draw_gl(void) {
|
|
Fl::fatal("Fl_Gl_Window_Group::draw_gl() *must* be overriden. Please refer to the documentation.");
|
|
}
|
|
|
|
#else // ! HAVE_GL
|
|
|
|
typedef int no_opengl_support;
|
|
|
|
#endif // ! HAVE_GL
|
|
|
|
//
|
|
// End of "$Id:$".
|
|
//
|