// // "$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 #include #include #include #include //#include "Fl_Gl_Choice.H" #if 1 //---------------- Extract from Fl_Gl_Choice.H #ifdef WIN32 # include # define GLContext HGLRC #elif defined(__APPLE_QUARTZ__) # include # include # define GLContext AGLContext #else # include # 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 //#include #include #include #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:$". //