solvespace/fltk/xFl_Gl_Window_Group.cxx

293 lines
6.8 KiB
C++
Raw Normal View History

Initial Autotools and FLTK support With this commit, SolveSpace gains an Autotools build system and a new platform-dependent backend implemented using the FLTK GUI toolkit. These will allow the application to be built and run on Linux and other Unix-like operating systems, and prospectively, MacOS X. A number of new files have been added: * Makefile.am: Automake makefile template; this contains some experimental support for MinGW and MSVC++ builds that needs further development * ac-aux/ax_fltk.m4: Autoconf M4 macro to locate and query the system's installation of FLTK; this will eventually be contributed to the GNU Autoconf Archive * autogen.sh: Script to bootstrap the Autotools build system, usually for a tree just checked out from source control * configure.ac: Source for the Autoconf configure script; note that this file specifies a version of 2.1, near the top * fltk/fltkmain.cpp: Main FLTK backend implementation * fltk/fltkutil.cpp: Utility functions for the FLTK backend * fltk/xFl_Gl_Window_Group.{H,cxx}: Implementation of a new Fl_Gl_Window_Group widget for FLTK, needed to facilitate drawing FLTK widgets on top of OpenGL graphics as SolveSpace does. This has been submitted to the FLTK project for (hopefully) eventual upstream inclusion: http://www.fltk.org/str.php?L2992 The following minor changes are also a part of this commit: * Makefile.msvc: Define PACKAGE_VERSION=2.1 for the benefit of solvespace.cpp in MSVC++ builds * solvespace.cpp: In the About dialog text, use PACKAGE_VERSION rather than hard-coding the version of the program * solvespace.h: Don't define the C99 integer types if HAVE_C99_INTEGER_TYPES is defined, to facilitate MinGW builds
2013-10-28 05:28:42 +00:00
//
// "$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:$".
//