diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2016-01-21 16:14:01 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2016-01-21 16:14:01 +0000 |
| commit | 84e9be966d40bd6d74b5165987049051127f3a04 (patch) | |
| tree | 00d6a8313eb15f9beacf3277a8368f3d78857424 /src | |
| parent | 3b3ed8d79c0886fe0fb025104da02e685f4f6eef (diff) | |
Remove Quartz graphics driver from public view.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11020 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src')
| -rw-r--r-- | src/cfg_gfx/gdi.H | 731 | ||||
| -rw-r--r-- | src/cfg_gfx/gdi_rect.cxx | 860 | ||||
| -rw-r--r-- | src/cfg_gfx/opengl.H | 783 | ||||
| -rw-r--r-- | src/cfg_gfx/opengl_rect.cxx | 783 | ||||
| -rw-r--r-- | src/cfg_gfx/quartz.H | 103 | ||||
| -rw-r--r-- | src/cfg_gfx/quartz_rect.cxx | 289 | ||||
| -rw-r--r-- | src/cfg_gfx/xlib.H | 731 | ||||
| -rw-r--r-- | src/cfg_gfx/xlib_rect.cxx | 860 | ||||
| -rw-r--r-- | src/fl_rect.cxx | 247 |
9 files changed, 5141 insertions, 246 deletions
diff --git a/src/cfg_gfx/gdi.H b/src/cfg_gfx/gdi.H new file mode 100644 index 000000000..222a7c71f --- /dev/null +++ b/src/cfg_gfx/gdi.H @@ -0,0 +1,731 @@ +// +// "$Id$" +// +// Definition of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device +// for the Fast Light Tool Kit (FLTK). +// +// Copyright 2010-2014 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 +// + +/** \file Fl_Device.H + \brief declaration of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, + Fl_Display_Device, Fl_Device_Plugin. +*/ + +#ifndef Fl_Device_H +#define Fl_Device_H + +#include <FL/x.H> +#include <FL/Fl_Plugin.H> +#include <FL/Fl_Image.H> +#include <FL/Fl_Bitmap.H> +#include <FL/Fl_Pixmap.H> +#include <FL/Fl_RGB_Image.H> +#include <stdlib.h> + +class Fl_Graphics_Driver; +class Fl_Font_Descriptor; +/** \brief Points to the driver that currently receives all graphics requests */ +FL_EXPORT extern Fl_Graphics_Driver *fl_graphics_driver; + +/** + signature of image generation callback function. + \param[in] data user data passed to function + \param[in] x,y,w position and width of scan line in image + \param[out] buf buffer for generated image data. You must copy \p w + pixels from scanline \p y, starting at pixel \p x + to this buffer. + */ +typedef void (*Fl_Draw_Image_Cb)(void* data,int x,int y,int w,uchar* buf); + +// typedef what the x,y fields in a point are: +#ifdef WIN32 +typedef int COORD_T; +# define XPOINT XPoint +#elif defined(__APPLE__) +typedef float COORD_T; +typedef struct { float x; float y; } QPoint; +# define XPOINT QPoint +extern float fl_quartz_line_width_; +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: define types for COORD_T and XPOINT" +typedef int COORD_T; // default if not ported +typedef struct { int x; int y; } QPoint; +# define XPOINT QPoint +#else +typedef short COORD_T; +# define XPOINT XPoint +#endif + +/** + All graphical output devices and all graphics systems. + This class supports a rudimentary system of run-time type information. + */ +class FL_EXPORT Fl_Device { +public: + /** A string that identifies each subclass of Fl_Device. + Function class_name() applied to a device of this class returns this string. + */ + static const char *class_id; + /** + Returns the name of the class of this object. + Use of the class_name() function is discouraged because it will be removed from future FLTK versions. + + The class of an instance of an Fl_Device subclass can be checked with code such as: + \code + if ( instance->class_name() == Fl_Printer::class_id ) { ... } + \endcode + */ + virtual const char *class_name() {return class_id;}; + /** + Virtual destructor. + + The destructor of Fl_Device must be virtual to make the destructors of + derived classes being called correctly on destruction. + */ + virtual ~Fl_Device() {}; +}; + +#define FL_REGION_STACK_SIZE 10 +#define FL_MATRIX_STACK_SIZE 32 +/** + \brief A virtual class subclassed for each graphics driver FLTK uses. + Typically, FLTK applications do not use directly objects from this class. Rather, they perform + drawing operations (e.g., fl_rectf()) that operate on the current drawing surface (see Fl_Surface_Device). + Drawing operations are functionally presented in \ref drawing and as function lists + in the \ref fl_drawings and \ref fl_attributes modules. The \ref fl_graphics_driver global variable + gives at any time the graphics driver used by all drawing operations. Its value changes when + drawing operations are directed to another drawing surface by Fl_Surface_Device::set_current(). + + \p The Fl_Graphics_Driver class is of interest if one wants to perform new kinds of drawing operations. + An example would be to draw to a PDF file. This would involve creating a new Fl_Graphics_Driver derived + class. This new class should implement all virtual methods of the Fl_Graphics_Driver class + to support all FLTK drawing functions. + */ +class FL_EXPORT Fl_Graphics_Driver : public Fl_Device { +public: + /** A 2D coordinate transformation matrix + */ + struct matrix {double a, b, c, d, x, y;}; +protected: + static const matrix m0; + Fl_Font font_; // current font + Fl_Fontsize size_; // current font size + Fl_Color color_; // current color + int sptr; + static const int matrix_stack_size = FL_MATRIX_STACK_SIZE; + matrix stack[FL_MATRIX_STACK_SIZE]; + matrix m; + int n, p_size, gap_; + XPOINT *p; + int what; + int fl_clip_state_number; + int rstackptr; + static const int region_stack_max = FL_REGION_STACK_SIZE - 1; + Fl_Region rstack[FL_REGION_STACK_SIZE]; +#ifdef WIN32 + int numcount; + int counts[20]; +#elif defined(__APPLE__) + // not needed +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: define variables for Fl_Graphics_Driver if needed." + // not needed +#else + // not needed in X11 +#endif + Fl_Font_Descriptor *font_descriptor_; + void transformed_vertex0(COORD_T x, COORD_T y); + void fixloop(); + +protected: +#ifndef FL_DOXYGEN + enum {LINE, LOOP, POLYGON, POINT_}; + inline int vertex_no() { return n; } + inline XPOINT *vertices() {return p;} + inline int vertex_kind() {return what;} +#endif +/* ** \brief red color for background and/or mixing if device does not support masking or alpha * + uchar bg_r_; + ** \brief green color for background and/or mixing if device does not support masking or alpha * + uchar bg_g_; + ** \brief blue color for background and/or mixing if device does not support masking or alpha * + uchar bg_b_; */ + friend class Fl_Pixmap; + friend class Fl_Bitmap; + friend class Fl_RGB_Image; + friend void fl_line_style(int style, int width, char* dashes); + friend void fl_draw(const char *str, int n, int x, int y); +#ifdef __APPLE__ + friend void fl_draw(const char *str, int n, float x, float y); +#elif defined(WIN32) + // not needed +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: add floating point text positioning if your platform supports it" +#else + // not needed +#endif + friend void fl_draw(int angle, const char *str, int n, int x, int y); + friend void fl_rtl_draw(const char *str, int n, int x, int y); + friend void fl_font(Fl_Font face, Fl_Fontsize size); + friend void fl_color(Fl_Color c); + friend void fl_color(uchar r, uchar g, uchar b); + friend void fl_begin_points(); + friend void fl_begin_line(); + friend void fl_begin_loop(); + friend void fl_begin_polygon(); + friend void fl_vertex(double x, double y); + friend void fl_curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3); + friend void fl_circle(double x, double y, double r); + friend void fl_arc(double x, double y, double r, double start, double end); + friend void fl_arc(int x, int y, int w, int h, double a1, double a2); + friend void fl_pie(int x, int y, int w, int h, double a1, double a2); + friend void fl_end_points(); + friend void fl_end_line(); + friend void fl_end_loop(); + friend void fl_end_polygon(); + friend void fl_transformed_vertex(double xf, double yf); + friend void fl_begin_complex_polygon(); + friend void fl_gap(); + friend void fl_end_complex_polygon(); + friend void fl_push_matrix(); + friend void fl_pop_matrix(); + friend void fl_mult_matrix(double a, double b, double c, double d, double x, double y); + friend void fl_scale(double x, double y); + friend void fl_scale(double x); + friend void fl_translate(double x, double y); + friend void fl_rotate(double d); + friend double fl_transform_x(double x, double y); + friend double fl_transform_y(double x, double y); + friend double fl_transform_dx(double x, double y); + friend double fl_transform_dy(double x, double y); + + friend void fl_draw_image(const uchar* buf, int X,int Y,int W,int H, int D, int L); + friend void fl_draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D, int L); + friend void fl_draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D); + friend FL_EXPORT void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D); + friend FL_EXPORT void gl_start(); + friend void fl_copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); + matrix *fl_matrix; /**< Points to the current coordinate transformation matrix */ + + /** \brief The constructor. */ + Fl_Graphics_Driver(); + /** \brief see fl_line_style(int style, int width, char* dashes). */ + virtual void line_style(int style, int width=0, char* dashes=0); + /** \brief see fl_draw(const char *str, int n, int x, int y). */ + virtual void draw(const char *str, int n, int x, int y) {} +#ifdef __APPLE__ + virtual void draw(const char *str, int n, float x, float y) { draw(str, n, (int)(x+0.5), (int)(y+0.5));} +#elif defined(WIN32) + // not needed +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: add floating point text positioning if your platform supports it" +#else + // not needed +#endif + /** \brief see fl_draw(int angle, const char *str, int n, int x, int y). */ + virtual void draw(int angle, const char *str, int n, int x, int y) {} + /** \brief see fl_rtl_draw(const char *str, int n, int x, int y). */ + virtual void rtl_draw(const char *str, int n, int x, int y) {}; + /** \brief see fl_color(Fl_Color c). */ + virtual void color(Fl_Color c) {color_ = c;} + /** \brief see fl_color(uchar r, uchar g, uchar b). */ + virtual void color(uchar r, uchar g, uchar b) {} + /** \brief see fl_begin_points(). */ + virtual void begin_points(); + /** \brief see fl_begin_line(). */ + virtual void begin_line(); + /** \brief see fl_begin_loop(). */ + virtual void begin_loop(); + /** \brief see fl_begin_polygon(). */ + virtual void begin_polygon(); + /** \brief see fl_vertex(double x, double y). */ + virtual void vertex(double x, double y); + /** \brief see fl_curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3). */ + virtual void curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3); + /** \brief see fl_circle(double x, double y, double r). */ + virtual void circle(double x, double y, double r); + /** \brief see fl_arc(double x, double y, double r, double start, double end). */ + virtual void arc(double x, double y, double r, double start, double end); + /** \brief see fl_arc(int x, int y, int w, int h, double a1, double a2). */ + virtual void arc(int x, int y, int w, int h, double a1, double a2); + /** \brief see fl_pie(int x, int y, int w, int h, double a1, double a2). */ + virtual void pie(int x, int y, int w, int h, double a1, double a2); + /** \brief see fl_end_points(). */ + virtual void end_points(); + /** \brief see fl_end_line(). */ + virtual void end_line(); + /** \brief see fl_end_loop(). */ + virtual void end_loop(); + /** \brief see fl_end_polygon(). */ + virtual void end_polygon(); + /** \brief see fl_begin_complex_polygon(). */ + virtual void begin_complex_polygon(); + /** \brief see fl_gap(). */ + virtual void gap(); + /** \brief see fl_end_complex_polygon(). */ + virtual void end_complex_polygon(); + /** \brief see fl_transformed_vertex(double xf, double yf). */ + virtual void transformed_vertex(double xf, double yf); + + /** \brief see fl_push_matrix(). */ + void push_matrix(); + /** \brief see fl_pop_matrix(). */ + void pop_matrix(); + /** \brief see fl_mult_matrix(double a, double b, double c, double d, double x, double y). */ + void mult_matrix(double a, double b, double c, double d, double x, double y); + /** \brief see fl_scale(double x, double y). */ + inline void scale(double x, double y) { mult_matrix(x,0,0,y,0,0); } + /** \brief see fl_scale(double x). */ + inline void scale(double x) { mult_matrix(x,0,0,x,0,0); } + /** \brief see fl_translate(double x, double y). */ + inline void translate(double x,double y) { mult_matrix(1,0,0,1,x,y); } + /** \brief see fl_rotate(double d). */ + void rotate(double d); + /** \brief see fl_transform_x(double x, double y). */ + double transform_x(double x, double y); + /** \brief see fl_transform_y(double x, double y). */ + double transform_y(double x, double y); + /** \brief see fl_transform_dx(double x, double y). */ + double transform_dx(double x, double y); + /** \brief see fl_transform_dy(double x, double y). */ + double transform_dy(double x, double y); + + // Images + /** \brief see fl_draw_image(const uchar* buf, int X,int Y,int W,int H, int D, int L). */ + virtual void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) {} + /** \brief see fl_draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D, int L). */ + virtual void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) {} + /** \brief see fl_draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D). */ + virtual void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) {} + /** \brief see fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D). */ + virtual void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) {} + // Image classes + /** \brief Draws an Fl_RGB_Image object to the device. + * + Specifies a bounding box for the image, with the origin (upper left-hand corner) of + the image offset by the cx and cy arguments. + */ + virtual void draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy) {} + /** \brief Draws an Fl_Pixmap object to the device. + * + Specifies a bounding box for the image, with the origin (upper left-hand corner) of + the image offset by the cx and cy arguments. + */ + virtual void draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy) {} + /** \brief Draws an Fl_Bitmap object to the device. + * + Specifies a bounding box for the image, with the origin (upper left-hand corner) of + the image offset by the cx and cy arguments. + */ + virtual void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {} +#if FLTK_ABI_VERSION >= 10301 + virtual +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); + +public: + static const char *class_id; + virtual const char *class_name() {return class_id;}; + /** \brief see fl_font(Fl_Font face, Fl_Fontsize size). */ + virtual void font(Fl_Font face, Fl_Fontsize fsize) {font_ = face; size_ = fsize;} + /** \brief see fl_font(void). */ + Fl_Font font() {return font_; } + /** \brief see fl_size(). */ + Fl_Fontsize size() {return size_; } + /** \brief see fl_width(const char *str, int n). */ + virtual double width(const char *str, int n) {return 0;} + /** \brief see fl_width(unsigned int n). */ + virtual inline double width(unsigned int c) { char ch = (char)c; return width(&ch, 1); } + /** \brief see fl_text_extents(const char*, int n, int& dx, int& dy, int& w, int& h). */ + virtual void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + /** \brief see fl_height(). */ + virtual int height() {return size();} + /** \brief see fl_descent(). */ + virtual int descent() {return 0;} + /** \brief see fl_color(void). */ + Fl_Color color() {return color_;} + /** Returns a pointer to the current Fl_Font_Descriptor for the graphics driver */ + inline Fl_Font_Descriptor *font_descriptor() { return font_descriptor_;} + /** Sets the current Fl_Font_Descriptor for the graphics driver */ + inline void font_descriptor(Fl_Font_Descriptor *d) { font_descriptor_ = d;} +#if FLTK_ABI_VERSION >= 10304 || defined(FL_DOXYGEN) + virtual +#endif + int draw_scaled(Fl_Image *img, int X, int Y, int W, int H); + /** \brief The destructor */ + virtual ~Fl_Graphics_Driver() { if (p) free(p); } + + // === all code below in this class has been to the reorganisation FL_PORTING process +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/quartz_rect.cxx + friend void fl_point(int x, int y); + virtual void point(int x, int y) = 0; + friend void fl_rect(int x, int y, int w, int h); + virtual void rect(int x, int y, int w, int h) = 0; + friend void fl_rectf(int x, int y, int w, int h); + virtual void rectf(int x, int y, int w, int h) = 0; + friend void fl_line(int x, int y, int x1, int y1); + virtual void line(int x, int y, int x1, int y1) = 0; + friend void fl_line(int x, int y, int x1, int y1, int x2, int y2); + virtual void line(int x, int y, int x1, int y1, int x2, int y2) = 0; + friend void fl_xyline(int x, int y, int x1); + virtual void xyline(int x, int y, int x1) = 0; + friend void fl_xyline(int x, int y, int x1, int y2); + virtual void xyline(int x, int y, int x1, int y2) = 0; + friend void fl_xyline(int x, int y, int x1, int y2, int x3); + virtual void xyline(int x, int y, int x1, int y2, int x3) = 0; + friend void fl_yxline(int x, int y, int y1); + virtual void yxline(int x, int y, int y1) = 0; + friend void fl_yxline(int x, int y, int y1, int x2); + virtual void yxline(int x, int y, int y1, int x2) = 0; + friend void fl_yxline(int x, int y, int y1, int x2, int y3); + virtual void yxline(int x, int y, int y1, int x2, int y3) = 0; + friend void fl_loop(int x0, int y0, int x1, int y1, int x2, int y2); + virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2) = 0; + friend void fl_loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) = 0; + friend void fl_polygon(int x0, int y0, int x1, int y1, int x2, int y2); + virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2) = 0; + friend void fl_polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) = 0; + // --- clipping + friend void fl_push_clip(int x, int y, int w, int h); + virtual void push_clip(int x, int y, int w, int h) = 0; + friend int fl_clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + virtual int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) = 0; + friend int fl_not_clipped(int x, int y, int w, int h); + virtual int not_clipped(int x, int y, int w, int h) = 0; + friend void fl_push_no_clip(); + virtual void push_no_clip() = 0; + friend void fl_pop_clip(); + virtual void pop_clip() = 0; + friend Fl_Region fl_clip_region(); + virtual Fl_Region clip_region(); // has default implementation + friend void fl_clip_region(Fl_Region r); + virtual void clip_region(Fl_Region r); // has default implementation + friend void fl_restore_clip(); + virtual void restore_clip(); +}; + + +#if defined(__APPLE__) + +/** + \brief The Mac OS X-specific graphics class. + * + This class is implemented only on the Mac OS X platform. + */ +class FL_EXPORT Fl_Quartz_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void color(Fl_Color c); + void color(uchar r, uchar g, uchar b); + void draw(const char* str, int n, int x, int y); +#ifdef __APPLE__ + void draw(const char *str, int n, float x, float y); +#endif + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); +#if ! defined(FL_DOXYGEN) + static Fl_Offscreen create_offscreen_with_alpha(int w, int h); +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/quartz_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + void xyline(int x, int y, int x1); + void xyline(int x, int y, int x1, int y2); + void xyline(int x, int y, int x1, int y2, int x3); + void yxline(int x, int y, int y1); + void yxline(int x, int y, int y1, int x2); + void yxline(int x, int y, int y1, int x2, int y3); + void loop(int x0, int y0, int x1, int y1, int x2, int y2); + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + // --- clipping + void push_clip(int x, int y, int w, int h); + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + int not_clipped(int x, int y, int w, int h); + void push_no_clip(); + void pop_clip(); + void restore_clip(); +}; + +// FIXME: add Fl_Quartz_Printer_Graphics_Driver + +#elif defined(WIN32) || defined(FL_DOXYGEN) + +/** + \brief The MSWindows-specific graphics class. + * + This class is implemented only on the MSWindows platform. + */ +class FL_EXPORT Fl_GDI_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void color(Fl_Color c); + void color(uchar r, uchar g, uchar b); + void draw(const char* str, int n, int x, int y); + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); +#if ! defined(FL_DOXYGEN) + void copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy); +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/gdi_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + void xyline(int x, int y, int x1); + void xyline(int x, int y, int x1, int y2); + void xyline(int x, int y, int x1, int y2, int x3); + void yxline(int x, int y, int y1); + void yxline(int x, int y, int y1, int x2); + void yxline(int x, int y, int y1, int x2, int y3); + void loop(int x0, int y0, int x1, int y1, int x2, int y2); + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + // --- clipping + void push_clip(int x, int y, int w, int h); + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + int not_clipped(int x, int y, int w, int h); + void push_no_clip(); + void pop_clip(); + void restore_clip(); +}; + +/** + The graphics driver used when printing on MSWindows. + * + This class is implemented only on the MSWindows platform. It 's extremely similar to Fl_GDI_Graphics_Driver. + */ +class FL_EXPORT Fl_GDI_Printer_Graphics_Driver : public Fl_GDI_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy); + int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); +}; + +#elif defined(FL_PORTING) + +# pragma message "FL_PORTING: define a native graphics driver Fl_xxx_Graphics_Driver" +class FL_EXPORT Fl_XXX_Graphics_Driver : public Fl_Graphics_Driver { +protected: + // --- recently moved implementations (see FL_PORTING efforts) + void point(int x, int y) { } + void rect(int x, int y, int w, int h) { } +}; + +#else // X11 + +/** + \brief The Xlib-specific graphics class. + * + This class is implemented only on the Xlib platform. + */ +class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void color(Fl_Color c); + void color(uchar r, uchar g, uchar b); + void draw(const char* str, int n, int x, int y); + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +#if ! defined(FL_DOXYGEN) + void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +#endif +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + void xyline(int x, int y, int x1); + void xyline(int x, int y, int x1, int y2); + void xyline(int x, int y, int x1, int y2, int x3); + void yxline(int x, int y, int y1); + void yxline(int x, int y, int y1, int x2); + void yxline(int x, int y, int y1, int x2, int y3); + void loop(int x0, int y0, int x1, int y1, int x2, int y2); + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + // --- clipping + void push_clip(int x, int y, int w, int h); + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + int not_clipped(int x, int y, int w, int h); + void push_no_clip(); + void pop_clip(); + void restore_clip(); +}; + +#endif + +/** + A drawing surface that's susceptible to receive graphical output. + Any FLTK application has at any time a current drawing surface to which all drawing requests are directed. + The current surface is given by Fl_Surface_Device::surface(). + When main() begins running, the current drawing surface has been set to the computer's display, + an instance of the Fl_Display_Device class. + + A drawing surface other than the computer's display, is typically used as follows: + <ol><li> Create \c surface, an object from a particular Fl_Surface_Device derived class (e.g., Fl_Copy_Surface, Fl_Printer). + <li> Memorize what is the current drawing surface with <tt> Fl_Surface_Device *old_current = Fl_Surface_Device::surface();</tt> + <li> Call \c surface->set_current(); to redirect all graphics requests to \c surface which becomes the new + current drawing surface (not necessary with class Fl_Printer because it is done by Fl_Printer::start_job()). + <li> At this point any of the \ref fl_drawings (e.g., fl_rect()) or the \ref fl_attributes or \ref drawing_images functions + (e.g., fl_draw_image(), Fl_Image::draw()) operates on the new current drawing surface. + Certain drawing surfaces allow additional ways to draw to them (e.g., Fl_Printer::print_widget(), Fl_Image_Surface::draw()). + <li> After all drawing requests have been performed, redirect graphics requests back to their previous destination + with \c old_current->set_current();. + <li> Delete \c surface. + </ol> + */ +class FL_EXPORT Fl_Surface_Device : public Fl_Device { + /** \brief The graphics driver in use by this surface. */ + Fl_Graphics_Driver *_driver; + static Fl_Surface_Device *_surface; // the surface that currently receives graphics output + static Fl_Surface_Device *default_surface(); // create surface is none exists yet +protected: + /** \brief Constructor that sets the graphics driver to use for the created surface. */ + Fl_Surface_Device(Fl_Graphics_Driver *graphics_driver) {_driver = graphics_driver; }; +public: + static const char *class_id; + const char *class_name() {return class_id;}; + virtual void set_current(void); + /** \brief Sets the graphics driver of this drawing surface. */ + inline void driver(Fl_Graphics_Driver *graphics_driver) {_driver = graphics_driver;}; + /** \brief Returns the graphics driver of this drawing surface. */ + inline Fl_Graphics_Driver *driver() {return _driver; }; + /** The current drawing surface. + In other words, the Fl_Surface_Device object that currently receives all graphics output */ + static inline Fl_Surface_Device *surface() { + return _surface ? _surface : default_surface(); + }; + /** \brief The destructor. */ + virtual ~Fl_Surface_Device() {} +}; + +/** + A display to which the computer can draw. + When the program begins running, an Fl_Display_Device instance has been created and made the current drawing surface. + There is no need to create any other object of this class. + */ +class FL_EXPORT Fl_Display_Device : public Fl_Surface_Device { + friend class Fl_Quartz_Graphics_Driver; + static Fl_Display_Device *_display; // the platform display device +#ifdef __APPLE__ + friend class Fl_X; + friend class Fl_Graphics_Driver; + static bool high_res_window_; //< true when drawing to a window of a retina display (Mac OS X only) + static bool high_resolution() {return high_res_window_;} +#elif defined(WIN32) +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: implement functions for extra high res drawing if your platform supports it" +#else +#endif +public: + static const char *class_id; + const char *class_name() {return class_id;}; + Fl_Display_Device(Fl_Graphics_Driver *graphics_driver); + static Fl_Display_Device *display_device(); +}; + +/** + This plugin socket allows the integration of new device drivers for special + window or screen types. It is currently used to provide an automated printing + service and screen capture for OpenGL windows, if linked with fltk_gl. + */ +class FL_EXPORT Fl_Device_Plugin : public Fl_Plugin { +public: + /** \brief The constructor */ + Fl_Device_Plugin(const char *pluginName) + : Fl_Plugin(klass(), pluginName) { } + /** \brief Returns the class name */ + virtual const char *klass() { return "fltk:device"; } + /** \brief Returns the plugin name */ + virtual const char *name() = 0; + /** \brief Prints a widget + \param w the widget + \param x,y offsets where to print relatively to coordinates origin + \param height height of the current drawing area + */ + virtual int print(Fl_Widget* w, int x, int y, int height) = 0; + /** captures a rectangle of a widget as an image + \return The captured pixels as an RGB image + */ + virtual Fl_RGB_Image* rectangle_capture(Fl_Widget *widget, int x, int y, int w, int h) = 0; +}; + +#endif // Fl_Device_H + +// +// End of "$Id$". +// diff --git a/src/cfg_gfx/gdi_rect.cxx b/src/cfg_gfx/gdi_rect.cxx new file mode 100644 index 000000000..771cc6a8b --- /dev/null +++ b/src/cfg_gfx/gdi_rect.cxx @@ -0,0 +1,860 @@ +// +// "$Id$" +// +// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2012 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 +// + +/** + \file fl_rect.cxx + \brief Drawing and clipping routines for rectangles. +*/ + +// These routines from fl_draw.H are used by the standard boxtypes +// and thus are always linked into an fltk program. +// Also all fl_clip routines, since they are always linked in so +// that minimal update works. + +#include <config.h> +#include "config_lib.h" +#include <FL/Fl.H> +#include <FL/Fl_Widget.H> +#include <FL/Fl_Printer.H> +#include <FL/fl_draw.H> +#include <FL/x.H> + +#if defined(WIN32) || defined(__APPLE__) +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: implement all the line drawing functions below" +#else +#endif + +// fl_line_width_ must contain the absolute value of the current +// line width to be used for X11 clipping (see below). +// This is defined in src/fl_line_style.cxx +extern int fl_line_width_; + + +void Fl_Graphics_Driver::restore_clip() { + fl_clip_state_number++; +} + +void Fl_Graphics_Driver::clip_region(Fl_Region r) { + Fl_Region oldr = rstack[rstackptr]; + if (oldr) XDestroyRegion(oldr); + rstack[rstackptr] = r; + fl_restore_clip(); +} + +Fl_Region Fl_Graphics_Driver::clip_region() { + return rstack[rstackptr]; +} + + + +//////////////////////////////////////////////////////////////// + +/* + Matt: I wrote individual methods for every class. They are virtual, so the + correct function is called, depending on the active driver. + + By having individual methods, multiple drivers can co-exist, for example + Quartz, OpenGL, and a printer driver. + + The individual implementations should eventually go into files that are + included into this file, based on the configuration, for example: + + src/cfg_gfx/quartz_rect.cxx + src/cfg_gfx/gdi_rect.cxx + src/cfg_gfx/xlib_rect.cxx + + Porting the graphics system to a new platform then requires to copy one of + these files and implement the virtual functions. point() is the only function + that *must* be implemented when deriving from 'Fl_Minimal_Graphics_Driver" + (which is still to be written) + */ + +//////////////////////////////////////////////////////////////// + +#ifdef FL_CFG_GFX_QUARTZ + +extern float fl_quartz_line_width_; +#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) + +// --- line and polygon drawing with integer coordinates + +void Fl_Quartz_Graphics_Driver::point(int x, int y) { + CGContextFillRect(fl_gc, CGRectMake(x - 0.5, y - 0.5, 1, 1) ); +} + +void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + // FIXME: there should be a quartz graphics driver for the printer device that makes the USINGQUARTZPRINTER obsolete + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGRect rect = CGRectMake(x, y, w-1, h-1); + CGContextStrokeRect(fl_gc, rect); + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + CGRect rect = CGRectMake(x - 0.5, y - 0.5, w , h); + CGContextFillRect(fl_gc, rect); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit + (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles + of size one unit by line-width. + */ + CGContextFillRect(fl_gc, CGRectMake(x-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1 - fl_quartz_line_width_/2, y2-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextAddLineToPoint(fl_gc, x3, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x3-0.5, y2 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y1-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2-0.5, y1 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextAddLineToPoint(fl_gc, x2, y3); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2 - fl_quartz_line_width_/2, y3-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +// --- clipping + +void Fl_Quartz_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + XDestroyRegion(r); + r = Fl_X::intersect_region_and_rect(current, x,y,w,h); + } + } else { // make empty clip region: + r = XRectangleRegion(0,0,0,0); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_Quartz_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + CGRect u = CGRectMake(0,0,0,0); + CGRect test; + for (int i = 0; i < r->count; i++) { + test = CGRectIntersection(r->rects[i], arg); + if ( !CGRectIsEmpty(test) ) { + if(CGRectIsEmpty(u)) u = test; + else u = CGRectUnion(u, test); + } + } + X = int(u.origin.x + 0.5); // reverse offset introduced by fl_cgrectmake_cocoa() + Y = int(u.origin.y + 0.5); + W = int(u.size.width + 0.5); // round to nearest integer + H = int(u.size.height + 0.5); + if (CGRectIsEmpty(u)) W = H = 0; + return !CGRectEqualToRect(arg, u); +} + +int Fl_Quartz_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + for (int i = 0; i < r->count; i++) { + CGRect test = CGRectIntersection(r->rects[i], arg); + if (!CGRectIsEmpty(test)) return 1; + } + return 0; +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_Quartz_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_Quartz_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_Quartz_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_Quartz_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + if ( fl_window || fl_gc ) { // clipping for a true window or an offscreen buffer + Fl_X::q_clear_clipping(); + Fl_X::q_fill_context();//flip coords if bitmap context + //apply program clip + if (r) { + CGContextClipToRects(fl_gc, r->rects, r->count); + } + } +} + +#endif + +// ----------------------------------------------------------------------------- + +#ifdef FL_CFG_GFX_GDI + +// --- line and polygon drawing with integer coordinates + +void Fl_GDI_Graphics_Driver::point(int x, int y) { + SetPixel(fl_gc, x, y, fl_RGB()); +} + +void Fl_GDI_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x+w-1, y); + LineTo(fl_gc, x+w-1, y+h-1); + LineTo(fl_gc, x, y+h-1); + LineTo(fl_gc, x, y); +} + +void Fl_GDI_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + RECT rect; + rect.left = x; rect.top = y; + rect.right = x + w; rect.bottom = y + h; + FillRect(fl_gc, &rect, fl_brush()); +} + +void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + SetPixel(fl_gc, x1, y1, fl_RGB()); +} + +void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + LineTo(fl_gc, x2, y2); + SetPixel(fl_gc, x2, y2, fl_RGB()); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1) { + MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + if (y2 < y) y2--; + else y2++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y); + LineTo(fl_gc, x1, y2); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + if(x3 < x1) x3--; + else x3++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y); + LineTo(fl_gc, x1, y2); + LineTo(fl_gc, x3, y2); +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1) { + if (y1 < y) y1--; + else y1++; + MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x, y1); +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + if (x2 > x) x2++; + else x2--; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x, y1); + LineTo(fl_gc, x2, y1); +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + if(y3<y1) y3--; + else y3++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x, y1); + LineTo(fl_gc, x2, y1); + LineTo(fl_gc, x2, y3); +} + +void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + LineTo(fl_gc, x2, y2); + LineTo(fl_gc, x, y); +} + +void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + LineTo(fl_gc, x2, y2); + LineTo(fl_gc, x3, y3); + LineTo(fl_gc, x, y); +} + +void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[3]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + SelectObject(fl_gc, fl_brush()); + Polygon(fl_gc, p, 3); +} + +void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + SelectObject(fl_gc, fl_brush()); + Polygon(fl_gc, p, 4); +} + +// --- clipping + +void Fl_GDI_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + CombineRgn(r,r,current,RGN_AND); + } + } else { // make empty clip region: + r = CreateRectRgn(0,0,0,0); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_GDI_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_GDI_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + // The win32 API makes no distinction between partial and complete + // intersection, so we have to check for partial intersection ourselves. + // However, given that the regions may be composite, we have to do + // some voodoo stuff... + Fl_Region rr = XRectangleRegion(x,y,w,h); + Fl_Region temp = CreateRectRgn(0,0,0,0); + int ret; + if (CombineRgn(temp, rr, r, RGN_AND) == NULLREGION) { // disjoint + W = H = 0; + ret = 2; + } else if (EqualRgn(temp, rr)) { // complete + ret = 0; + } else { // partial intersection + RECT rect; + GetRgnBox(temp, &rect); + if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // if print context, convert coords from device to logical + POINT pt[2] = { {rect.left, rect.top}, {rect.right, rect.bottom} }; + DPtoLP(fl_gc, pt, 2); + X = pt[0].x; Y = pt[0].y; W = pt[1].x - X; H = pt[1].y - Y; + } + else { + X = rect.left; Y = rect.top; W = rect.right - X; H = rect.bottom - Y; + } + ret = 1; + } + DeleteObject(temp); + DeleteObject(rr); + return ret; +} + +int Fl_GDI_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + RECT rect; + if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // in case of print context, convert coords from logical to device + POINT pt[2] = { {x, y}, {x + w, y + h} }; + LPtoDP(fl_gc, pt, 2); + rect.left = pt[0].x; rect.top = pt[0].y; rect.right = pt[1].x; rect.bottom = pt[1].y; + } else { + rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h; + } + return RectInRegion(r,&rect); +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_GDI_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_GDI_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_GDI_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_GDI_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_GDI_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + SelectClipRgn(fl_gc, r); //if r is NULL, clip is automatically cleared +} + +#endif + +// ----------------------------------------------------------------------------- + +#ifdef FL_CFG_GFX_XLIB + +#ifndef SHRT_MAX +#define SHRT_MAX (32767) +#endif + +/* + We need to check some coordinates for areas for clipping before we + use X functions, because X can't handle coordinates outside the 16-bit + range. Since all windows use relative coordinates > 0, we do also + check for negative values. X11 only, see also STR #2304. + + Note that this is only necessary for large objects, where only a + part of the object is visible. The draw() functions (e.g. box + drawing) must be clipped correctly. This is usually only a matter + for large container widgets. The individual child widgets will be + clipped completely. + + We define the usable X coordinate space as [ -LW : SHRT_MAX - LW ] + where LW = current line width for drawing. This is done so that + horizontal and vertical line drawing works correctly, even in real + border cases, e.g. drawing a rectangle slightly outside the top left + window corner, but with a line width so that a part of the line should + be visible (in this case 2 of 5 pixels): + + fl_line_style (FL_SOLID,5); // line width = 5 + fl_rect (-1,-1,100,100); // top/left: 2 pixels visible + + In this example case, no clipping would be done, because X can + handle it and clip unneeded pixels. + + Note that we must also take care of the case where fl_line_width_ + is zero (maybe unitialized). If this is the case, we assume a line + width of 1. + + Todo: Arbitrary line drawings (e.g. polygons) and clip regions + are not yet done. + + Note: + + We could use max. screen coordinates instead of SHRT_MAX, but that + would need more work and would probably be slower. We assume that + all window coordinates are >= 0 and that no window extends up to + 32767 - LW (where LW = current line width). Thus it is safe to clip + all coordinates to this range before calling X functions. If this + is not true, then clip_to_short() and clip_x() must be redefined. + + It would be somewhat easier if we had fl_clip_w and fl_clip_h, as + defined in FLTK 2.0 (for the upper clipping bounds)... + */ + +/* + clip_to_short() returns 1, if the area is invisible (clipped), + because ... + + (a) w or h are <= 0 i.e. nothing is visible + (b) x+w or y+h are < kmin i.e. left of or above visible area + (c) x or y are > kmax i.e. right of or below visible area + + kmin and kmax are the minimal and maximal X coordinate values, + as defined above. In this case x, y, w, and h are not changed. + + It returns 0, if the area is potentially visible and X can handle + clipping. x, y, w, and h may have been adjusted to fit into the + X coordinate space. + + Use this for clipping rectangles, as used in fl_rect() and + fl_rectf(). + */ +static int clip_to_short(int &x, int &y, int &w, int &h) { + + int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; + int kmin = -lw; + int kmax = SHRT_MAX - lw; + + if (w <= 0 || h <= 0) return 1; // (a) + if (x+w < kmin || y+h < kmin) return 1; // (b) + if (x > kmax || y > kmax) return 1; // (c) + + if (x < kmin) { w -= (kmin-x); x = kmin; } + if (y < kmin) { h -= (kmin-y); y = kmin; } + if (x+w > kmax) w = kmax - x; + if (y+h > kmax) h = kmax - y; + + return 0; +} + +/* + clip_x() returns a coordinate value clipped to the 16-bit coordinate + space (see above). This can be used to draw horizontal and vertical + lines that can be handled by X11. Each single coordinate value can + be clipped individually, and the result can be used directly, e.g. + in fl_xyline() and fl_yxline(). Note that this can't be used for + arbitrary lines (not horizontal or vertical). + */ +static int clip_x (int x) { + + int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; + int kmin = -lw; + int kmax = SHRT_MAX - lw; + + if (x < kmin) + x = kmin; + else if (x > kmax) + x = kmax; + return x; +} + +// Missing X call: (is this the fastest way to init a 1-rectangle region?) +// MSWindows equivalent exists, implemented inline in win32.H +Fl_Region XRectangleRegion(int x, int y, int w, int h) { + XRectangle R; + clip_to_short(x, y, w, h); + R.x = x; R.y = y; R.width = w; R.height = h; + Fl_Region r = XCreateRegion(); + XUnionRectWithRegion(&R, r, r); + return r; +} + +// --- line and polygon drawing with integer coordinates + +void Fl_Xlib_Graphics_Driver::point(int x, int y) { + XDrawPoint(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y)); +} + +void Fl_Xlib_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + if (!clip_to_short(x, y, w, h)) + XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1); +} + +void Fl_Xlib_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + if (!clip_to_short(x, y, w, h)) + XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h); +} + +void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1) { + XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1); +} + +void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[3]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1) { + XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x1), clip_x(y)); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + XPoint p[3]; + p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); + p[1].x = p[2].x = clip_x(x1); p[2].y = clip_x(y2); + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + XPoint p[4]; + p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); + p[1].x = p[2].x = clip_x(x1); p[2].y = p[3].y = clip_x(y2); + p[3].x = clip_x(x3); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1) { + XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x), clip_x(y1)); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + XPoint p[3]; + p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); + p[1].y = p[2].y = clip_x(y1); p[2].x = clip_x(x2); + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + XPoint p[4]; + p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); + p[1].y = p[2].y = clip_x(y1); p[2].x = p[3].x = clip_x(x2); + p[3].y = clip_x(y3); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x; p[3].y = y; + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[5]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + p[4].x = x; p[4].y = y; + XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); +} + +void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x; p[3].y = y; + XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[5]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + p[4].x = x; p[4].y = y; + XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0); + XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); +} + +// --- clipping + +void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + Fl_Region temp = XCreateRegion(); + XIntersectRegion(current, r, temp); + XDestroyRegion(r); + r = temp; + } + } else { // make empty clip region: + r = XCreateRegion(); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_Xlib_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + switch (XRectInRegion(r, x, y, w, h)) { + case 0: // completely outside + W = H = 0; + return 2; + case 1: // completely inside: + return 0; + default: // partial: + break; + } + Fl_Region rr = XRectangleRegion(x,y,w,h); + Fl_Region temp = XCreateRegion(); + XIntersectRegion(r, rr, temp); + XRectangle rect; + XClipBox(temp, &rect); + X = rect.x; Y = rect.y; W = rect.width; H = rect.height; + XDestroyRegion(temp); + XDestroyRegion(rr); + return 1; +} + +int Fl_Xlib_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + // get rid of coordinates outside the 16-bit range the X calls take. + if (clip_to_short(x,y,w,h)) return 0; // clipped + return XRectInRegion(r, x, y, w, h); +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_Xlib_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("fl_push_no_cFl_Xlib_Graphics_Driver::push_no_cliplip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_Xlib_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_Xlib_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_Xlib_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + if (r) XSetRegion(fl_display, fl_gc, r); + else XSetClipMask(fl_display, fl_gc, 0); +} + +#endif + +// +// End of "$Id$". +// diff --git a/src/cfg_gfx/opengl.H b/src/cfg_gfx/opengl.H new file mode 100644 index 000000000..82b38fd14 --- /dev/null +++ b/src/cfg_gfx/opengl.H @@ -0,0 +1,783 @@ +// +// "$Id$" +// +// OpenGL window code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2015 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 "flstring.h" +#include "config_lib.h" +#if HAVE_GL + +extern int fl_gl_load_plugin; + +#include <FL/Fl.H> +#include <FL/x.H> +#include "Fl_Gl_Choice.H" +#ifdef __APPLE__ +#include <FL/gl.h> +#include <OpenGL/OpenGL.h> +#endif +#include <FL/Fl_Gl_Window.H> +#include <FL/Fl_Device.H> +#include <stdlib.h> +#include <FL/fl_utf8.h> + +#if defined(WIN32) || defined(__APPLE__) +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: implement the creation and destruction of OpenGL surfaces" +#else +#endif + + +// ------ this should be in a separate file! ----------------------------------- +#ifdef FL_CFG_GFX_OPENGL + +#include <FL/Fl_Device.H> +#include <FL/gl.h> + +/** + \brief OpenGL pecific graphics class. + * + This class is implemented only on the Mac OS X platform. + */ +class FL_EXPORT Fl_OpenGL_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void draw(const char* str, int n, int x, int y) { + gl_draw(str, n, x, y); + } + void color(Fl_Color c) { + gl_color(c); + } + void color(uchar r, uchar g, uchar b) { + unsigned int c = (r<<24)|(g<<16)|(b<<8); + gl_color(c); + } + // --- implementation will eventually be in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx + // --- line and polygon drawing with integer coordinates + void point(int x, int y) { + glBegin(GL_POINTS); + glVertex2i(x, y); + glEnd(); + } + void rect(int x, int y, int w, int h) { + glBegin(GL_LINE_LOOP); + glVertex2i(x, y); + glVertex2i(x+w, y); + glVertex2i(x+w, y+h); + glVertex2i(x, y+h); + glEnd(); + } + void rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + // OpenGL has the natural origin at the bottom left. Drawing in FLTK + // coordinates requires that we shift the rectangle one pixel up. + glBegin(GL_POLYGON); + glVertex2i(x, y-1); + glVertex2i(x+w, y-1); + glVertex2i(x+w, y+h-1); + glVertex2i(x, y+h-1); + glEnd(); + } + void line(int x, int y, int x1, int y1) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y1); + glEnd(); + point(x1, y1); + } + void line(int x, int y, int x1, int y1, int x2, int y2) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); + point(x2, y2); + } + void xyline(int x, int y, int x1) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y); + glEnd(); + point(x1, y); + } + void xyline(int x, int y, int x1, int y2) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y); + glVertex2i(x1, y2); + glEnd(); + point(x1, y2); + } + void xyline(int x, int y, int x1, int y2, int x3) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y); + glVertex2i(x1, y2); + glVertex2i(x3, y2); + glEnd(); + point(x3, y2); + } + void yxline(int x, int y, int y1) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x, y1); + glEnd(); + point(x, y1); + } + void yxline(int x, int y, int y1, int x2) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x, y1); + glVertex2i(x2, y1); + glEnd(); + point(x2, y1); + } + void yxline(int x, int y, int y1, int x2, int y3) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x, y1); + glVertex2i(x2, y1); + glVertex2i(x2, y3); + glEnd(); + point(x2, y3); + } + void loop(int x0, int y0, int x1, int y1, int x2, int y2) { + glBegin(GL_LINE_LOOP); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); + } + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { + glBegin(GL_LINE_LOOP); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glVertex2i(x3, y3); + glEnd(); + } + void polygon(int x0, int y0, int x1, int y1, int x2, int y2) { + glBegin(GL_POLYGON); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); + } + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { + glBegin(GL_POLYGON); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glVertex2i(x3, y3); + glEnd(); + } + void push_clip(int x, int y, int w, int h) { + // TODO: implement OpenGL clipping + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0L; + else Fl::warning("Fl_OpenGL_Graphics_Driver::push_clip: clip stack overflow!\n"); + } + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) { + // TODO: implement OpenGL clipping + X = x; Y = y; W = w, H = h; + return 0; + } + int not_clipped(int x, int y, int w, int h) { + // TODO: implement OpenGL clipping + return 1; + } + void push_no_clip() { + // TODO: implement OpenGL clipping + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_OpenGL_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + restore_clip(); + } + void pop_clip() { + // TODO: implement OpenGL clipping + if (rstackptr > 0) { + rstackptr--; + } else Fl::warning("Fl_OpenGL_Graphics_Driver::pop_clip: clip stack underflow!\n"); + restore_clip(); + } + void restore_clip() { + // TODO: implement OpenGL clipping + fl_clip_state_number++; + } +}; + +const char *Fl_OpenGL_Graphics_Driver::class_id = "Fl_OpenGL_Graphics_Driver"; + +Fl_OpenGL_Display_Device *Fl_OpenGL_Display_Device::display_device() { + static Fl_OpenGL_Display_Device *display = new Fl_OpenGL_Display_Device(new Fl_OpenGL_Graphics_Driver()); + return display; +}; + + +Fl_OpenGL_Display_Device::Fl_OpenGL_Display_Device(Fl_OpenGL_Graphics_Driver *graphics_driver) +: Fl_Surface_Device(graphics_driver) +{ +} + + +const char *Fl_OpenGL_Display_Device::class_id = "Fl_OpenGL_Display_Device"; + + + +#endif +// ------ end of separate file! ------------------------------------------------ + + +//////////////////////////////////////////////////////////////// + +// The symbol SWAP_TYPE defines what is in the back buffer after doing +// a glXSwapBuffers(). + +// The OpenGl documentation says that the contents of the backbuffer +// are "undefined" after glXSwapBuffers(). However, if we know what +// is in the backbuffers then we can save a good deal of time. For +// this reason you can define some symbols to describe what is left in +// the back buffer. + +// Having not found any way to determine this from glx (or wgl) I have +// resorted to letting the user specify it with an environment variable, +// GL_SWAP_TYPE, it should be equal to one of these symbols: + +// contents of back buffer after glXSwapBuffers(): +#define UNDEFINED 1 // anything +#define SWAP 2 // former front buffer (same as unknown) +#define COPY 3 // unchanged +#define NODAMAGE 4 // unchanged even by X expose() events + +static char SWAP_TYPE = 0 ; // 0 = determine it from environment variable + +//////////////////////////////////////////////////////////////// + +/** Returns non-zero if the hardware supports the given or current OpenGL mode. */ +int Fl_Gl_Window::can_do(int a, const int *b) { + return Fl_Gl_Choice::find(a,b) != 0; +} + +void Fl_Gl_Window::show() { +#if defined(__APPLE__) + int need_redraw = 0; +#endif + if (!shown()) { + if (!g) { + g = Fl_Gl_Choice::find(mode_,alist); + if (!g && (mode_ & FL_DOUBLE) == FL_SINGLE) { + g = Fl_Gl_Choice::find(mode_ | FL_DOUBLE,alist); + if (g) mode_ |= FL_FAKE_SINGLE; + } + + if (!g) { + Fl::error("Insufficient GL support"); + return; + } + } +#if !defined(WIN32) && !defined(__APPLE__) + Fl_X::make_xid(this, g->vis, g->colormap); + if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show(); +#elif defined(__APPLE__) + if( ! parent() ) need_redraw=1; +#endif + } + Fl_Window::show(); + +#ifdef __APPLE__ + set_visible(); + if(need_redraw) redraw();//necessary only after creation of a top-level GL window +#endif /* __APPLE__ */ +} + +#if defined(__APPLE__) + +int Fl_Gl_Window::pixels_per_unit() +{ + return (fl_mac_os_version >= 100700 && Fl::use_high_res_GL() && Fl_X::i(this) && Fl_X::i(this)->mapped_to_retina()) ? 2 : 1; +} + +#endif // __APPLE__ + +/** + The invalidate() method turns off valid() and is + equivalent to calling value(0). +*/ +void Fl_Gl_Window::invalidate() { + valid(0); + context_valid(0); +#ifndef WIN32 + if (overlay) { + ((Fl_Gl_Window*)overlay)->valid(0); + ((Fl_Gl_Window*)overlay)->context_valid(0); + } +#endif +} + +int Fl_Gl_Window::mode(int m, const int *a) { + if (m == mode_ && a == alist) return 0; +#ifndef __APPLE__ + int oldmode = mode_; +#endif +#if defined(__APPLE__) || defined(USE_X11) + if (a) { // when the mode is set using the a array of system-dependent values, and if asking for double buffer, + // the FL_DOUBLE flag must be set in the mode_ member variable + const int *aa = a; + while (*aa) { + if (*(aa++) == +# if defined(__APPLE__) + kCGLPFADoubleBuffer +# else + GLX_DOUBLEBUFFER +# endif + ) { m |= FL_DOUBLE; break; } + } + } +#endif // !__APPLE__ +#if !defined(WIN32) && !defined(__APPLE__) + Fl_Gl_Choice* oldg = g; +#endif // !WIN32 && !__APPLE__ + context(0); + mode_ = m; alist = a; + if (shown()) { + g = Fl_Gl_Choice::find(m, a); + +#if defined(USE_X11) + // under X, if the visual changes we must make a new X window (yuck!): + if (!g || g->vis->visualid!=oldg->vis->visualid || (oldmode^m)&FL_DOUBLE) { + hide(); + show(); + } +#elif defined(WIN32) + if (!g || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) { + hide(); + show(); + } +#elif defined(__APPLE_QUARTZ__) + redraw(); +#else +# error unsupported platform +#endif + } else { + g = 0; + } + return 1; +} + +#define NON_LOCAL_CONTEXT 0x80000000 + +/** + The make_current() method selects the OpenGL context for the + widget. It is called automatically prior to the draw() method + being called and can also be used to implement feedback and/or + selection within the handle() method. +*/ + +void Fl_Gl_Window::make_current() { +// puts("Fl_Gl_Window::make_current()"); +// printf("make_current: context_=%p\n", context_); +#if defined(__APPLE__) + // detect if the window was moved between low and high resolution displays + if (Fl_X::i(this)->changed_resolution()){ + Fl_X::i(this)->changed_resolution(false); + invalidate(); + Fl_X::GLcontext_update(context_); + } +#endif + if (!context_) { + mode_ &= ~NON_LOCAL_CONTEXT; + context_ = fl_create_gl_context(this, g); + valid(0); + context_valid(0); + } + fl_set_gl_context(this, context_); + +#if defined(WIN32) && USE_COLORMAP + if (fl_palette) { + fl_GetDC(fl_xid(this)); + SelectPalette(fl_gc, fl_palette, FALSE); + RealizePalette(fl_gc); + } +#endif // USE_COLORMAP + if (mode_ & FL_FAKE_SINGLE) { + glDrawBuffer(GL_FRONT); + glReadBuffer(GL_FRONT); + } + current_ = this; +} + +/** + Sets the projection so 0,0 is in the lower left of the window and each + pixel is 1 unit wide/tall. If you are drawing 2D images, your + draw() method may want to call this if valid() is false. +*/ +void Fl_Gl_Window::ortho() { +// Alpha NT seems to have a broken OpenGL that does not like negative coords: +#ifdef _M_ALPHA + glLoadIdentity(); + glViewport(0, 0, w(), h()); + glOrtho(0, w(), 0, h(), -1, 1); +#else + GLint v[2]; + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, v); + glLoadIdentity(); + glViewport(pixel_w()-v[0], pixel_h()-v[1], v[0], v[1]); + glOrtho(pixel_w()-v[0], pixel_w(), pixel_h()-v[1], pixel_h(), -1, 1); +#endif +} + +/** + The swap_buffers() method swaps the back and front buffers. + It is called automatically after the draw() method is called. +*/ +void Fl_Gl_Window::swap_buffers() { +#if defined(USE_X11) + glXSwapBuffers(fl_display, fl_xid(this)); +#elif defined(WIN32) +# if HAVE_GL_OVERLAY + // Do not swap the overlay, to match GLX: + BOOL ret = wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_MAIN_PLANE); + DWORD err = GetLastError();; +# else + SwapBuffers(Fl_X::i(this)->private_dc); +# endif +#elif defined(__APPLE_QUARTZ__) + if(overlay != NULL) { + // STR# 2944 [1] + // Save matrixmode/proj/modelview/rasterpos before doing overlay. + // + int wo=pixel_w(), ho=pixel_h(); + GLint matrixmode; + GLfloat pos[4]; + glGetIntegerv(GL_MATRIX_MODE, &matrixmode); + glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos + glMatrixMode(GL_PROJECTION); // save proj/model matrices + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glScalef(2.0f/wo, 2.0f/ho, 1.0f); + glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of Gl_Window + glRasterPos2i(0,0); // set glRasterPos to bottom left corner + { + // Emulate overlay by doing copypixels + glReadBuffer(GL_BACK); + glDrawBuffer(GL_FRONT); + glCopyPixels(0, 0, wo, ho, GL_COLOR); // copy GL_BACK to GL_FRONT + } + glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(matrixmode); + glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos + } + /* // nothing to do here under Cocoa because [NSOpenGLContext -flushBuffer] done later replaces it + else + aglSwapBuffers((AGLContext)context_); + */ +#else +# error unsupported platform +#endif +} + +#if HAVE_GL_OVERLAY && defined(WIN32) +uchar fl_overlay; // changes how fl_color() works +int fl_overlay_depth = 0; +#endif + + +void Fl_Gl_Window::flush() { + if (!shown()) return; + uchar save_valid = valid_f_ & 1; +#if HAVE_GL_OVERLAY && defined(WIN32) + uchar save_valid_f = valid_f_; +#endif + +#if HAVE_GL_OVERLAY && defined(WIN32) + + // Draw into hardware overlay planes if they are damaged: + if (overlay && overlay != this + && (damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid)) { + fl_set_gl_context(this, (GLContext)overlay); + if (fl_overlay_depth) + wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT); + fl_overlay = 1; + draw_overlay(); + fl_overlay = 0; + valid_f_ = save_valid_f; + wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_OVERLAY1); + // if only the overlay was damaged we are done, leave main layer alone: + if (damage() == FL_DAMAGE_OVERLAY) { + return; + } + } +#endif + + make_current(); + + if (mode_ & FL_DOUBLE) { + + glDrawBuffer(GL_BACK); + + if (!SWAP_TYPE) { +#if defined (__APPLE_QUARTZ__) || defined (USE_X11) + SWAP_TYPE = COPY; +#else + SWAP_TYPE = UNDEFINED; +#endif + const char* c = fl_getenv("GL_SWAP_TYPE"); + if (c) { + if (!strcmp(c,"COPY")) SWAP_TYPE = COPY; + else if (!strcmp(c, "NODAMAGE")) SWAP_TYPE = NODAMAGE; + else if (!strcmp(c, "SWAP")) SWAP_TYPE = SWAP; + else SWAP_TYPE = UNDEFINED; + } + } + + if (SWAP_TYPE == NODAMAGE) { + + // don't draw if only overlay damage or expose events: + if ((damage()&~(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE)) || !save_valid) + draw(); + swap_buffers(); + + } else if (SWAP_TYPE == COPY) { + + // don't draw if only the overlay is damaged: + if (damage() != FL_DAMAGE_OVERLAY || !save_valid) draw(); + swap_buffers(); + + } else if (SWAP_TYPE == SWAP){ + damage(FL_DAMAGE_ALL); + draw(); + if (overlay == this) draw_overlay(); + swap_buffers(); + } else if (SWAP_TYPE == UNDEFINED){ // SWAP_TYPE == UNDEFINED + + // If we are faking the overlay, use CopyPixels to act like + // SWAP_TYPE == COPY. Otherwise overlay redraw is way too slow. + if (overlay == this) { + // don't draw if only the overlay is damaged: + if (damage1_ || damage() != FL_DAMAGE_OVERLAY || !save_valid) draw(); + // we use a separate context for the copy because rasterpos must be 0 + // and depth test needs to be off: + static GLContext ortho_context = 0; + static Fl_Gl_Window* ortho_window = 0; + int orthoinit = !ortho_context; + if (orthoinit) ortho_context = fl_create_gl_context(this, g); + fl_set_gl_context(this, ortho_context); + if (orthoinit || !save_valid || ortho_window != this) { + glDisable(GL_DEPTH_TEST); + glReadBuffer(GL_BACK); + glDrawBuffer(GL_FRONT); + glLoadIdentity(); + glViewport(0, 0, pixel_w(), pixel_h()); + glOrtho(0, pixel_w(), 0, pixel_h(), -1, 1); + glRasterPos2i(0,0); + ortho_window = this; + } + glCopyPixels(0,0,pixel_w(),pixel_h(),GL_COLOR); + make_current(); // set current context back to draw overlay + damage1_ = 0; + + } else { + damage1_ = damage(); + clear_damage(0xff); draw(); + swap_buffers(); + } + + } +#ifdef __APPLE__ + Fl_X::GLcontext_flushbuffer(context_); +#endif + + if (overlay==this && SWAP_TYPE != SWAP) { // fake overlay in front buffer + glDrawBuffer(GL_FRONT); + draw_overlay(); + glDrawBuffer(GL_BACK); + glFlush(); + } + + } else { // single-buffered context is simpler: + + draw(); + if (overlay == this) draw_overlay(); + glFlush(); + + } + + valid(1); + context_valid(1); +} + +void Fl_Gl_Window::resize(int X,int Y,int W,int H) { +// printf("Fl_Gl_Window::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H); +// printf("current: x()=%d, y()=%d, w()=%d, h()=%d\n", x(), y(), w(), h()); + + int is_a_resize = (W != Fl_Widget::w() || H != Fl_Widget::h()); + if (is_a_resize) valid(0); + +#ifdef __APPLE__ + Fl_X *flx = Fl_X::i(this); + if (flx && flx->in_windowDidResize()) Fl_X::GLcontext_update(context_); +#endif + +#if ! ( defined(__APPLE__) || defined(WIN32) ) + if (is_a_resize && !resizable() && overlay && overlay != this) { + ((Fl_Gl_Window*)overlay)->resize(0,0,W,H); + } +#endif + + Fl_Window::resize(X,Y,W,H); +} + +/** + Sets a pointer to the GLContext that this window is using. + This is a system-dependent structure, but it is portable to copy + the context from one window to another. You can also set it to NULL, + which will force FLTK to recreate the context the next time make_current() + is called, this is useful for getting around bugs in OpenGL implementations. + + If <i>destroy_flag</i> is true the context will be destroyed by + fltk when the window is destroyed, or when the mode() is changed, + or the next time context(x) is called. +*/ +void Fl_Gl_Window::context(void* v, int destroy_flag) { + if (context_ && !(mode_&NON_LOCAL_CONTEXT)) fl_delete_gl_context(context_); + context_ = (GLContext)v; + if (destroy_flag) mode_ &= ~NON_LOCAL_CONTEXT; + else mode_ |= NON_LOCAL_CONTEXT; +} + +/** + Hides the window and destroys the OpenGL context. +*/ +void Fl_Gl_Window::hide() { + context(0); +#if HAVE_GL_OVERLAY && defined(WIN32) + if (overlay && overlay != this) { + fl_delete_gl_context((GLContext)overlay); + overlay = 0; + } +#endif + Fl_Window::hide(); +} + +/** + The destructor removes the widget and destroys the OpenGL context + associated with it. +*/ +Fl_Gl_Window::~Fl_Gl_Window() { + hide(); +// delete overlay; this is done by ~Fl_Group +} + +void Fl_Gl_Window::init() { + end(); // we probably don't want any children + box(FL_NO_BOX); + + mode_ = FL_RGB | FL_DEPTH | FL_DOUBLE; + alist = 0; + context_ = 0; + g = 0; + overlay = 0; + valid_f_ = 0; + damage1_ = 0; + +#if 0 // This breaks resizing on Linux/X11 + int H = h(); + h(1); // Make sure we actually do something in resize()... + resize(x(), y(), w(), H); +#endif // 0 +} + +/** + You must implement this virtual function if you want to draw into the + overlay. The overlay is cleared before this is called. You should + draw anything that is not clear using OpenGL. You must use + gl_color(i) to choose colors (it allocates them from the colormap + using system-specific calls), and remember that you are in an indexed + OpenGL mode and drawing anything other than flat-shaded will probably + not work. + + Both this function and Fl_Gl_Window::draw() should check + Fl_Gl_Window::valid() and set the same transformation. If you + don't your code may not work on other systems. Depending on the OS, + and on whether overlays are real or simulated, the OpenGL context may + be the same or different between the overlay and main window. +*/ +void Fl_Gl_Window::draw_overlay() {} + +#endif + + /** + You \e \b 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 <I>only</I> 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(). + + If double-buffering is enabled in the window, the back and front + buffers are swapped after this function is completed. +*/ +void Fl_Gl_Window::draw() { +#ifdef FL_CFG_GFX_OPENGL + Fl_Surface_Device *prev_device = Fl_Surface_Device::surface(); + Fl_OpenGL_Display_Device::display_device()->set_current(); + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glPushMatrix(); + glLoadIdentity(); + glOrtho(-0.5, w()-0.5, h()-0.5, -0.5, -1, 1); +// glOrtho(0, w(), h(), 0, -1, 1); + glLineWidth(pixels_per_unit()); // should be 1 or 2 (2 if highres OpenGL) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // FIXME: push on state stack + glEnable(GL_BLEND); // FIXME: push on state stack + + Fl_Window::draw(); + + glPopMatrix(); + glPushAttrib(GL_ENABLE_BIT); + prev_device->set_current(); +#else + Fl::fatal("Fl_Gl_Window::draw() *must* be overriden. Please refer to the documentation."); +#endif +} + + +/** + Handle some FLTK events as needed. + */ +int Fl_Gl_Window::handle(int event) +{ + return Fl_Window::handle(event); +} + +// don't remove me! this serves only to force linking of Fl_Gl_Device_Plugin.o +int Fl_Gl_Window::gl_plugin_linkage() { + return fl_gl_load_plugin; +} + +// +// End of "$Id$". +// diff --git a/src/cfg_gfx/opengl_rect.cxx b/src/cfg_gfx/opengl_rect.cxx new file mode 100644 index 000000000..82b38fd14 --- /dev/null +++ b/src/cfg_gfx/opengl_rect.cxx @@ -0,0 +1,783 @@ +// +// "$Id$" +// +// OpenGL window code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2015 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 "flstring.h" +#include "config_lib.h" +#if HAVE_GL + +extern int fl_gl_load_plugin; + +#include <FL/Fl.H> +#include <FL/x.H> +#include "Fl_Gl_Choice.H" +#ifdef __APPLE__ +#include <FL/gl.h> +#include <OpenGL/OpenGL.h> +#endif +#include <FL/Fl_Gl_Window.H> +#include <FL/Fl_Device.H> +#include <stdlib.h> +#include <FL/fl_utf8.h> + +#if defined(WIN32) || defined(__APPLE__) +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: implement the creation and destruction of OpenGL surfaces" +#else +#endif + + +// ------ this should be in a separate file! ----------------------------------- +#ifdef FL_CFG_GFX_OPENGL + +#include <FL/Fl_Device.H> +#include <FL/gl.h> + +/** + \brief OpenGL pecific graphics class. + * + This class is implemented only on the Mac OS X platform. + */ +class FL_EXPORT Fl_OpenGL_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void draw(const char* str, int n, int x, int y) { + gl_draw(str, n, x, y); + } + void color(Fl_Color c) { + gl_color(c); + } + void color(uchar r, uchar g, uchar b) { + unsigned int c = (r<<24)|(g<<16)|(b<<8); + gl_color(c); + } + // --- implementation will eventually be in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx + // --- line and polygon drawing with integer coordinates + void point(int x, int y) { + glBegin(GL_POINTS); + glVertex2i(x, y); + glEnd(); + } + void rect(int x, int y, int w, int h) { + glBegin(GL_LINE_LOOP); + glVertex2i(x, y); + glVertex2i(x+w, y); + glVertex2i(x+w, y+h); + glVertex2i(x, y+h); + glEnd(); + } + void rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + // OpenGL has the natural origin at the bottom left. Drawing in FLTK + // coordinates requires that we shift the rectangle one pixel up. + glBegin(GL_POLYGON); + glVertex2i(x, y-1); + glVertex2i(x+w, y-1); + glVertex2i(x+w, y+h-1); + glVertex2i(x, y+h-1); + glEnd(); + } + void line(int x, int y, int x1, int y1) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y1); + glEnd(); + point(x1, y1); + } + void line(int x, int y, int x1, int y1, int x2, int y2) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); + point(x2, y2); + } + void xyline(int x, int y, int x1) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y); + glEnd(); + point(x1, y); + } + void xyline(int x, int y, int x1, int y2) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y); + glVertex2i(x1, y2); + glEnd(); + point(x1, y2); + } + void xyline(int x, int y, int x1, int y2, int x3) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x1, y); + glVertex2i(x1, y2); + glVertex2i(x3, y2); + glEnd(); + point(x3, y2); + } + void yxline(int x, int y, int y1) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x, y1); + glEnd(); + point(x, y1); + } + void yxline(int x, int y, int y1, int x2) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x, y1); + glVertex2i(x2, y1); + glEnd(); + point(x2, y1); + } + void yxline(int x, int y, int y1, int x2, int y3) { + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x, y1); + glVertex2i(x2, y1); + glVertex2i(x2, y3); + glEnd(); + point(x2, y3); + } + void loop(int x0, int y0, int x1, int y1, int x2, int y2) { + glBegin(GL_LINE_LOOP); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); + } + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { + glBegin(GL_LINE_LOOP); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glVertex2i(x3, y3); + glEnd(); + } + void polygon(int x0, int y0, int x1, int y1, int x2, int y2) { + glBegin(GL_POLYGON); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); + } + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { + glBegin(GL_POLYGON); + glVertex2i(x0, y0); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glVertex2i(x3, y3); + glEnd(); + } + void push_clip(int x, int y, int w, int h) { + // TODO: implement OpenGL clipping + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0L; + else Fl::warning("Fl_OpenGL_Graphics_Driver::push_clip: clip stack overflow!\n"); + } + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) { + // TODO: implement OpenGL clipping + X = x; Y = y; W = w, H = h; + return 0; + } + int not_clipped(int x, int y, int w, int h) { + // TODO: implement OpenGL clipping + return 1; + } + void push_no_clip() { + // TODO: implement OpenGL clipping + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_OpenGL_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + restore_clip(); + } + void pop_clip() { + // TODO: implement OpenGL clipping + if (rstackptr > 0) { + rstackptr--; + } else Fl::warning("Fl_OpenGL_Graphics_Driver::pop_clip: clip stack underflow!\n"); + restore_clip(); + } + void restore_clip() { + // TODO: implement OpenGL clipping + fl_clip_state_number++; + } +}; + +const char *Fl_OpenGL_Graphics_Driver::class_id = "Fl_OpenGL_Graphics_Driver"; + +Fl_OpenGL_Display_Device *Fl_OpenGL_Display_Device::display_device() { + static Fl_OpenGL_Display_Device *display = new Fl_OpenGL_Display_Device(new Fl_OpenGL_Graphics_Driver()); + return display; +}; + + +Fl_OpenGL_Display_Device::Fl_OpenGL_Display_Device(Fl_OpenGL_Graphics_Driver *graphics_driver) +: Fl_Surface_Device(graphics_driver) +{ +} + + +const char *Fl_OpenGL_Display_Device::class_id = "Fl_OpenGL_Display_Device"; + + + +#endif +// ------ end of separate file! ------------------------------------------------ + + +//////////////////////////////////////////////////////////////// + +// The symbol SWAP_TYPE defines what is in the back buffer after doing +// a glXSwapBuffers(). + +// The OpenGl documentation says that the contents of the backbuffer +// are "undefined" after glXSwapBuffers(). However, if we know what +// is in the backbuffers then we can save a good deal of time. For +// this reason you can define some symbols to describe what is left in +// the back buffer. + +// Having not found any way to determine this from glx (or wgl) I have +// resorted to letting the user specify it with an environment variable, +// GL_SWAP_TYPE, it should be equal to one of these symbols: + +// contents of back buffer after glXSwapBuffers(): +#define UNDEFINED 1 // anything +#define SWAP 2 // former front buffer (same as unknown) +#define COPY 3 // unchanged +#define NODAMAGE 4 // unchanged even by X expose() events + +static char SWAP_TYPE = 0 ; // 0 = determine it from environment variable + +//////////////////////////////////////////////////////////////// + +/** Returns non-zero if the hardware supports the given or current OpenGL mode. */ +int Fl_Gl_Window::can_do(int a, const int *b) { + return Fl_Gl_Choice::find(a,b) != 0; +} + +void Fl_Gl_Window::show() { +#if defined(__APPLE__) + int need_redraw = 0; +#endif + if (!shown()) { + if (!g) { + g = Fl_Gl_Choice::find(mode_,alist); + if (!g && (mode_ & FL_DOUBLE) == FL_SINGLE) { + g = Fl_Gl_Choice::find(mode_ | FL_DOUBLE,alist); + if (g) mode_ |= FL_FAKE_SINGLE; + } + + if (!g) { + Fl::error("Insufficient GL support"); + return; + } + } +#if !defined(WIN32) && !defined(__APPLE__) + Fl_X::make_xid(this, g->vis, g->colormap); + if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show(); +#elif defined(__APPLE__) + if( ! parent() ) need_redraw=1; +#endif + } + Fl_Window::show(); + +#ifdef __APPLE__ + set_visible(); + if(need_redraw) redraw();//necessary only after creation of a top-level GL window +#endif /* __APPLE__ */ +} + +#if defined(__APPLE__) + +int Fl_Gl_Window::pixels_per_unit() +{ + return (fl_mac_os_version >= 100700 && Fl::use_high_res_GL() && Fl_X::i(this) && Fl_X::i(this)->mapped_to_retina()) ? 2 : 1; +} + +#endif // __APPLE__ + +/** + The invalidate() method turns off valid() and is + equivalent to calling value(0). +*/ +void Fl_Gl_Window::invalidate() { + valid(0); + context_valid(0); +#ifndef WIN32 + if (overlay) { + ((Fl_Gl_Window*)overlay)->valid(0); + ((Fl_Gl_Window*)overlay)->context_valid(0); + } +#endif +} + +int Fl_Gl_Window::mode(int m, const int *a) { + if (m == mode_ && a == alist) return 0; +#ifndef __APPLE__ + int oldmode = mode_; +#endif +#if defined(__APPLE__) || defined(USE_X11) + if (a) { // when the mode is set using the a array of system-dependent values, and if asking for double buffer, + // the FL_DOUBLE flag must be set in the mode_ member variable + const int *aa = a; + while (*aa) { + if (*(aa++) == +# if defined(__APPLE__) + kCGLPFADoubleBuffer +# else + GLX_DOUBLEBUFFER +# endif + ) { m |= FL_DOUBLE; break; } + } + } +#endif // !__APPLE__ +#if !defined(WIN32) && !defined(__APPLE__) + Fl_Gl_Choice* oldg = g; +#endif // !WIN32 && !__APPLE__ + context(0); + mode_ = m; alist = a; + if (shown()) { + g = Fl_Gl_Choice::find(m, a); + +#if defined(USE_X11) + // under X, if the visual changes we must make a new X window (yuck!): + if (!g || g->vis->visualid!=oldg->vis->visualid || (oldmode^m)&FL_DOUBLE) { + hide(); + show(); + } +#elif defined(WIN32) + if (!g || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) { + hide(); + show(); + } +#elif defined(__APPLE_QUARTZ__) + redraw(); +#else +# error unsupported platform +#endif + } else { + g = 0; + } + return 1; +} + +#define NON_LOCAL_CONTEXT 0x80000000 + +/** + The make_current() method selects the OpenGL context for the + widget. It is called automatically prior to the draw() method + being called and can also be used to implement feedback and/or + selection within the handle() method. +*/ + +void Fl_Gl_Window::make_current() { +// puts("Fl_Gl_Window::make_current()"); +// printf("make_current: context_=%p\n", context_); +#if defined(__APPLE__) + // detect if the window was moved between low and high resolution displays + if (Fl_X::i(this)->changed_resolution()){ + Fl_X::i(this)->changed_resolution(false); + invalidate(); + Fl_X::GLcontext_update(context_); + } +#endif + if (!context_) { + mode_ &= ~NON_LOCAL_CONTEXT; + context_ = fl_create_gl_context(this, g); + valid(0); + context_valid(0); + } + fl_set_gl_context(this, context_); + +#if defined(WIN32) && USE_COLORMAP + if (fl_palette) { + fl_GetDC(fl_xid(this)); + SelectPalette(fl_gc, fl_palette, FALSE); + RealizePalette(fl_gc); + } +#endif // USE_COLORMAP + if (mode_ & FL_FAKE_SINGLE) { + glDrawBuffer(GL_FRONT); + glReadBuffer(GL_FRONT); + } + current_ = this; +} + +/** + Sets the projection so 0,0 is in the lower left of the window and each + pixel is 1 unit wide/tall. If you are drawing 2D images, your + draw() method may want to call this if valid() is false. +*/ +void Fl_Gl_Window::ortho() { +// Alpha NT seems to have a broken OpenGL that does not like negative coords: +#ifdef _M_ALPHA + glLoadIdentity(); + glViewport(0, 0, w(), h()); + glOrtho(0, w(), 0, h(), -1, 1); +#else + GLint v[2]; + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, v); + glLoadIdentity(); + glViewport(pixel_w()-v[0], pixel_h()-v[1], v[0], v[1]); + glOrtho(pixel_w()-v[0], pixel_w(), pixel_h()-v[1], pixel_h(), -1, 1); +#endif +} + +/** + The swap_buffers() method swaps the back and front buffers. + It is called automatically after the draw() method is called. +*/ +void Fl_Gl_Window::swap_buffers() { +#if defined(USE_X11) + glXSwapBuffers(fl_display, fl_xid(this)); +#elif defined(WIN32) +# if HAVE_GL_OVERLAY + // Do not swap the overlay, to match GLX: + BOOL ret = wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_MAIN_PLANE); + DWORD err = GetLastError();; +# else + SwapBuffers(Fl_X::i(this)->private_dc); +# endif +#elif defined(__APPLE_QUARTZ__) + if(overlay != NULL) { + // STR# 2944 [1] + // Save matrixmode/proj/modelview/rasterpos before doing overlay. + // + int wo=pixel_w(), ho=pixel_h(); + GLint matrixmode; + GLfloat pos[4]; + glGetIntegerv(GL_MATRIX_MODE, &matrixmode); + glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos + glMatrixMode(GL_PROJECTION); // save proj/model matrices + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glScalef(2.0f/wo, 2.0f/ho, 1.0f); + glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of Gl_Window + glRasterPos2i(0,0); // set glRasterPos to bottom left corner + { + // Emulate overlay by doing copypixels + glReadBuffer(GL_BACK); + glDrawBuffer(GL_FRONT); + glCopyPixels(0, 0, wo, ho, GL_COLOR); // copy GL_BACK to GL_FRONT + } + glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(matrixmode); + glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos + } + /* // nothing to do here under Cocoa because [NSOpenGLContext -flushBuffer] done later replaces it + else + aglSwapBuffers((AGLContext)context_); + */ +#else +# error unsupported platform +#endif +} + +#if HAVE_GL_OVERLAY && defined(WIN32) +uchar fl_overlay; // changes how fl_color() works +int fl_overlay_depth = 0; +#endif + + +void Fl_Gl_Window::flush() { + if (!shown()) return; + uchar save_valid = valid_f_ & 1; +#if HAVE_GL_OVERLAY && defined(WIN32) + uchar save_valid_f = valid_f_; +#endif + +#if HAVE_GL_OVERLAY && defined(WIN32) + + // Draw into hardware overlay planes if they are damaged: + if (overlay && overlay != this + && (damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid)) { + fl_set_gl_context(this, (GLContext)overlay); + if (fl_overlay_depth) + wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT); + fl_overlay = 1; + draw_overlay(); + fl_overlay = 0; + valid_f_ = save_valid_f; + wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_OVERLAY1); + // if only the overlay was damaged we are done, leave main layer alone: + if (damage() == FL_DAMAGE_OVERLAY) { + return; + } + } +#endif + + make_current(); + + if (mode_ & FL_DOUBLE) { + + glDrawBuffer(GL_BACK); + + if (!SWAP_TYPE) { +#if defined (__APPLE_QUARTZ__) || defined (USE_X11) + SWAP_TYPE = COPY; +#else + SWAP_TYPE = UNDEFINED; +#endif + const char* c = fl_getenv("GL_SWAP_TYPE"); + if (c) { + if (!strcmp(c,"COPY")) SWAP_TYPE = COPY; + else if (!strcmp(c, "NODAMAGE")) SWAP_TYPE = NODAMAGE; + else if (!strcmp(c, "SWAP")) SWAP_TYPE = SWAP; + else SWAP_TYPE = UNDEFINED; + } + } + + if (SWAP_TYPE == NODAMAGE) { + + // don't draw if only overlay damage or expose events: + if ((damage()&~(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE)) || !save_valid) + draw(); + swap_buffers(); + + } else if (SWAP_TYPE == COPY) { + + // don't draw if only the overlay is damaged: + if (damage() != FL_DAMAGE_OVERLAY || !save_valid) draw(); + swap_buffers(); + + } else if (SWAP_TYPE == SWAP){ + damage(FL_DAMAGE_ALL); + draw(); + if (overlay == this) draw_overlay(); + swap_buffers(); + } else if (SWAP_TYPE == UNDEFINED){ // SWAP_TYPE == UNDEFINED + + // If we are faking the overlay, use CopyPixels to act like + // SWAP_TYPE == COPY. Otherwise overlay redraw is way too slow. + if (overlay == this) { + // don't draw if only the overlay is damaged: + if (damage1_ || damage() != FL_DAMAGE_OVERLAY || !save_valid) draw(); + // we use a separate context for the copy because rasterpos must be 0 + // and depth test needs to be off: + static GLContext ortho_context = 0; + static Fl_Gl_Window* ortho_window = 0; + int orthoinit = !ortho_context; + if (orthoinit) ortho_context = fl_create_gl_context(this, g); + fl_set_gl_context(this, ortho_context); + if (orthoinit || !save_valid || ortho_window != this) { + glDisable(GL_DEPTH_TEST); + glReadBuffer(GL_BACK); + glDrawBuffer(GL_FRONT); + glLoadIdentity(); + glViewport(0, 0, pixel_w(), pixel_h()); + glOrtho(0, pixel_w(), 0, pixel_h(), -1, 1); + glRasterPos2i(0,0); + ortho_window = this; + } + glCopyPixels(0,0,pixel_w(),pixel_h(),GL_COLOR); + make_current(); // set current context back to draw overlay + damage1_ = 0; + + } else { + damage1_ = damage(); + clear_damage(0xff); draw(); + swap_buffers(); + } + + } +#ifdef __APPLE__ + Fl_X::GLcontext_flushbuffer(context_); +#endif + + if (overlay==this && SWAP_TYPE != SWAP) { // fake overlay in front buffer + glDrawBuffer(GL_FRONT); + draw_overlay(); + glDrawBuffer(GL_BACK); + glFlush(); + } + + } else { // single-buffered context is simpler: + + draw(); + if (overlay == this) draw_overlay(); + glFlush(); + + } + + valid(1); + context_valid(1); +} + +void Fl_Gl_Window::resize(int X,int Y,int W,int H) { +// printf("Fl_Gl_Window::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H); +// printf("current: x()=%d, y()=%d, w()=%d, h()=%d\n", x(), y(), w(), h()); + + int is_a_resize = (W != Fl_Widget::w() || H != Fl_Widget::h()); + if (is_a_resize) valid(0); + +#ifdef __APPLE__ + Fl_X *flx = Fl_X::i(this); + if (flx && flx->in_windowDidResize()) Fl_X::GLcontext_update(context_); +#endif + +#if ! ( defined(__APPLE__) || defined(WIN32) ) + if (is_a_resize && !resizable() && overlay && overlay != this) { + ((Fl_Gl_Window*)overlay)->resize(0,0,W,H); + } +#endif + + Fl_Window::resize(X,Y,W,H); +} + +/** + Sets a pointer to the GLContext that this window is using. + This is a system-dependent structure, but it is portable to copy + the context from one window to another. You can also set it to NULL, + which will force FLTK to recreate the context the next time make_current() + is called, this is useful for getting around bugs in OpenGL implementations. + + If <i>destroy_flag</i> is true the context will be destroyed by + fltk when the window is destroyed, or when the mode() is changed, + or the next time context(x) is called. +*/ +void Fl_Gl_Window::context(void* v, int destroy_flag) { + if (context_ && !(mode_&NON_LOCAL_CONTEXT)) fl_delete_gl_context(context_); + context_ = (GLContext)v; + if (destroy_flag) mode_ &= ~NON_LOCAL_CONTEXT; + else mode_ |= NON_LOCAL_CONTEXT; +} + +/** + Hides the window and destroys the OpenGL context. +*/ +void Fl_Gl_Window::hide() { + context(0); +#if HAVE_GL_OVERLAY && defined(WIN32) + if (overlay && overlay != this) { + fl_delete_gl_context((GLContext)overlay); + overlay = 0; + } +#endif + Fl_Window::hide(); +} + +/** + The destructor removes the widget and destroys the OpenGL context + associated with it. +*/ +Fl_Gl_Window::~Fl_Gl_Window() { + hide(); +// delete overlay; this is done by ~Fl_Group +} + +void Fl_Gl_Window::init() { + end(); // we probably don't want any children + box(FL_NO_BOX); + + mode_ = FL_RGB | FL_DEPTH | FL_DOUBLE; + alist = 0; + context_ = 0; + g = 0; + overlay = 0; + valid_f_ = 0; + damage1_ = 0; + +#if 0 // This breaks resizing on Linux/X11 + int H = h(); + h(1); // Make sure we actually do something in resize()... + resize(x(), y(), w(), H); +#endif // 0 +} + +/** + You must implement this virtual function if you want to draw into the + overlay. The overlay is cleared before this is called. You should + draw anything that is not clear using OpenGL. You must use + gl_color(i) to choose colors (it allocates them from the colormap + using system-specific calls), and remember that you are in an indexed + OpenGL mode and drawing anything other than flat-shaded will probably + not work. + + Both this function and Fl_Gl_Window::draw() should check + Fl_Gl_Window::valid() and set the same transformation. If you + don't your code may not work on other systems. Depending on the OS, + and on whether overlays are real or simulated, the OpenGL context may + be the same or different between the overlay and main window. +*/ +void Fl_Gl_Window::draw_overlay() {} + +#endif + + /** + You \e \b 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 <I>only</I> 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(). + + If double-buffering is enabled in the window, the back and front + buffers are swapped after this function is completed. +*/ +void Fl_Gl_Window::draw() { +#ifdef FL_CFG_GFX_OPENGL + Fl_Surface_Device *prev_device = Fl_Surface_Device::surface(); + Fl_OpenGL_Display_Device::display_device()->set_current(); + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glPushMatrix(); + glLoadIdentity(); + glOrtho(-0.5, w()-0.5, h()-0.5, -0.5, -1, 1); +// glOrtho(0, w(), h(), 0, -1, 1); + glLineWidth(pixels_per_unit()); // should be 1 or 2 (2 if highres OpenGL) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // FIXME: push on state stack + glEnable(GL_BLEND); // FIXME: push on state stack + + Fl_Window::draw(); + + glPopMatrix(); + glPushAttrib(GL_ENABLE_BIT); + prev_device->set_current(); +#else + Fl::fatal("Fl_Gl_Window::draw() *must* be overriden. Please refer to the documentation."); +#endif +} + + +/** + Handle some FLTK events as needed. + */ +int Fl_Gl_Window::handle(int event) +{ + return Fl_Window::handle(event); +} + +// don't remove me! this serves only to force linking of Fl_Gl_Device_Plugin.o +int Fl_Gl_Window::gl_plugin_linkage() { + return fl_gl_load_plugin; +} + +// +// End of "$Id$". +// diff --git a/src/cfg_gfx/quartz.H b/src/cfg_gfx/quartz.H new file mode 100644 index 000000000..6d0f36d50 --- /dev/null +++ b/src/cfg_gfx/quartz.H @@ -0,0 +1,103 @@ +// +// "$Id: quartz.H 11017 2016-01-20 21:40:12Z matt $" +// +// Definition of Apple Quartz graphics driver +// for the Fast Light Tool Kit (FLTK). +// +// Copyright 2010-2016 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 +// + +/** + \file quartz.h + \brief Definition of Apple Quartz graphics driver. + */ + +#ifndef FL_CFG_GFX_QUARTZ_H +#define FL_CFG_GFX_QUARTZ_H + +#include <FL/Fl_Device.H> + + +// typedef what the x,y fields in a point are: +// FIXME: this is still defined in Fl_Device.H, but should be invisible to the user +//typedef float COORD_T; +//typedef struct { float x; float y; } QPoint; + + +/** + \brief The Mac OS X-specific graphics class. + * + This class is implemented only on the Mac OS X platform. + */ +class FL_EXPORT Fl_Quartz_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void color(Fl_Color c); + void color(uchar r, uchar g, uchar b); + void draw(const char* str, int n, int x, int y); +#ifdef __APPLE__ + void draw(const char *str, int n, float x, float y); +#endif + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); +#if ! defined(FL_DOXYGEN) + static Fl_Offscreen create_offscreen_with_alpha(int w, int h); +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/quartz_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + void xyline(int x, int y, int x1); + void xyline(int x, int y, int x1, int y2); + void xyline(int x, int y, int x1, int y2, int x3); + void yxline(int x, int y, int y1); + void yxline(int x, int y, int y1, int x2); + void yxline(int x, int y, int y1, int x2, int y3); + void loop(int x0, int y0, int x1, int y1, int x2, int y2); + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + // --- clipping + void push_clip(int x, int y, int w, int h); + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + int not_clipped(int x, int y, int w, int h); + void push_no_clip(); + void pop_clip(); + void restore_clip(); +}; + + +#endif // FL_CFG_GFX_QUARTZ_H + +// +// End of "$Id: quartz.H 11017 2016-01-20 21:40:12Z matt $". +// diff --git a/src/cfg_gfx/quartz_rect.cxx b/src/cfg_gfx/quartz_rect.cxx new file mode 100644 index 000000000..dd72e6532 --- /dev/null +++ b/src/cfg_gfx/quartz_rect.cxx @@ -0,0 +1,289 @@ +// +// "$Id$" +// +// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2016 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 +// + + +#ifndef FL_CFG_GFX_QUARTZ_CXX +#define FL_CFG_GFX_QUARTZ_CXX + + +/** + \file quartz_rect.cxx + \brief Apple Quartz specific line and polygon drawing with integer coordinates. +*/ + + +#include "quartz.h" + + +extern float fl_quartz_line_width_; + +// FIXME: the use of the macro below can be avoided by adding a specific class +// for drawing to the prinitng context +#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) + + +// --- line and polygon drawing with integer coordinates + +void Fl_Quartz_Graphics_Driver::point(int x, int y) { + CGContextFillRect(fl_gc, CGRectMake(x - 0.5, y - 0.5, 1, 1) ); +} + +void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + // FIXME: there should be a quartz graphics driver for the printer device that makes the USINGQUARTZPRINTER obsolete + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGRect rect = CGRectMake(x, y, w-1, h-1); + CGContextStrokeRect(fl_gc, rect); + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + CGRect rect = CGRectMake(x - 0.5, y - 0.5, w , h); + CGContextFillRect(fl_gc, rect); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit + (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles + of size one unit by line-width. + */ + CGContextFillRect(fl_gc, CGRectMake(x-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1 - fl_quartz_line_width_/2, y2-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextAddLineToPoint(fl_gc, x3, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x3-0.5, y2 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y1-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2-0.5, y1 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextAddLineToPoint(fl_gc, x2, y3); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2 - fl_quartz_line_width_/2, y3-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +// --- clipping + +void Fl_Quartz_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + XDestroyRegion(r); + r = Fl_X::intersect_region_and_rect(current, x,y,w,h); + } + } else { // make empty clip region: + r = XRectangleRegion(0,0,0,0); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_Quartz_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + CGRect u = CGRectMake(0,0,0,0); + CGRect test; + for (int i = 0; i < r->count; i++) { + test = CGRectIntersection(r->rects[i], arg); + if ( !CGRectIsEmpty(test) ) { + if(CGRectIsEmpty(u)) u = test; + else u = CGRectUnion(u, test); + } + } + X = int(u.origin.x + 0.5); // reverse offset introduced by fl_cgrectmake_cocoa() + Y = int(u.origin.y + 0.5); + W = int(u.size.width + 0.5); // round to nearest integer + H = int(u.size.height + 0.5); + if (CGRectIsEmpty(u)) W = H = 0; + return !CGRectEqualToRect(arg, u); +} + +int Fl_Quartz_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + for (int i = 0; i < r->count; i++) { + CGRect test = CGRectIntersection(r->rects[i], arg); + if (!CGRectIsEmpty(test)) return 1; + } + return 0; +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_Quartz_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_Quartz_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_Quartz_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_Quartz_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + if ( fl_window || fl_gc ) { // clipping for a true window or an offscreen buffer + Fl_X::q_clear_clipping(); + Fl_X::q_fill_context();//flip coords if bitmap context + //apply program clip + if (r) { + CGContextClipToRects(fl_gc, r->rects, r->count); + } + } +} + + +#endif + +// +// End of "$Id$". +// diff --git a/src/cfg_gfx/xlib.H b/src/cfg_gfx/xlib.H new file mode 100644 index 000000000..222a7c71f --- /dev/null +++ b/src/cfg_gfx/xlib.H @@ -0,0 +1,731 @@ +// +// "$Id$" +// +// Definition of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device +// for the Fast Light Tool Kit (FLTK). +// +// Copyright 2010-2014 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 +// + +/** \file Fl_Device.H + \brief declaration of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, + Fl_Display_Device, Fl_Device_Plugin. +*/ + +#ifndef Fl_Device_H +#define Fl_Device_H + +#include <FL/x.H> +#include <FL/Fl_Plugin.H> +#include <FL/Fl_Image.H> +#include <FL/Fl_Bitmap.H> +#include <FL/Fl_Pixmap.H> +#include <FL/Fl_RGB_Image.H> +#include <stdlib.h> + +class Fl_Graphics_Driver; +class Fl_Font_Descriptor; +/** \brief Points to the driver that currently receives all graphics requests */ +FL_EXPORT extern Fl_Graphics_Driver *fl_graphics_driver; + +/** + signature of image generation callback function. + \param[in] data user data passed to function + \param[in] x,y,w position and width of scan line in image + \param[out] buf buffer for generated image data. You must copy \p w + pixels from scanline \p y, starting at pixel \p x + to this buffer. + */ +typedef void (*Fl_Draw_Image_Cb)(void* data,int x,int y,int w,uchar* buf); + +// typedef what the x,y fields in a point are: +#ifdef WIN32 +typedef int COORD_T; +# define XPOINT XPoint +#elif defined(__APPLE__) +typedef float COORD_T; +typedef struct { float x; float y; } QPoint; +# define XPOINT QPoint +extern float fl_quartz_line_width_; +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: define types for COORD_T and XPOINT" +typedef int COORD_T; // default if not ported +typedef struct { int x; int y; } QPoint; +# define XPOINT QPoint +#else +typedef short COORD_T; +# define XPOINT XPoint +#endif + +/** + All graphical output devices and all graphics systems. + This class supports a rudimentary system of run-time type information. + */ +class FL_EXPORT Fl_Device { +public: + /** A string that identifies each subclass of Fl_Device. + Function class_name() applied to a device of this class returns this string. + */ + static const char *class_id; + /** + Returns the name of the class of this object. + Use of the class_name() function is discouraged because it will be removed from future FLTK versions. + + The class of an instance of an Fl_Device subclass can be checked with code such as: + \code + if ( instance->class_name() == Fl_Printer::class_id ) { ... } + \endcode + */ + virtual const char *class_name() {return class_id;}; + /** + Virtual destructor. + + The destructor of Fl_Device must be virtual to make the destructors of + derived classes being called correctly on destruction. + */ + virtual ~Fl_Device() {}; +}; + +#define FL_REGION_STACK_SIZE 10 +#define FL_MATRIX_STACK_SIZE 32 +/** + \brief A virtual class subclassed for each graphics driver FLTK uses. + Typically, FLTK applications do not use directly objects from this class. Rather, they perform + drawing operations (e.g., fl_rectf()) that operate on the current drawing surface (see Fl_Surface_Device). + Drawing operations are functionally presented in \ref drawing and as function lists + in the \ref fl_drawings and \ref fl_attributes modules. The \ref fl_graphics_driver global variable + gives at any time the graphics driver used by all drawing operations. Its value changes when + drawing operations are directed to another drawing surface by Fl_Surface_Device::set_current(). + + \p The Fl_Graphics_Driver class is of interest if one wants to perform new kinds of drawing operations. + An example would be to draw to a PDF file. This would involve creating a new Fl_Graphics_Driver derived + class. This new class should implement all virtual methods of the Fl_Graphics_Driver class + to support all FLTK drawing functions. + */ +class FL_EXPORT Fl_Graphics_Driver : public Fl_Device { +public: + /** A 2D coordinate transformation matrix + */ + struct matrix {double a, b, c, d, x, y;}; +protected: + static const matrix m0; + Fl_Font font_; // current font + Fl_Fontsize size_; // current font size + Fl_Color color_; // current color + int sptr; + static const int matrix_stack_size = FL_MATRIX_STACK_SIZE; + matrix stack[FL_MATRIX_STACK_SIZE]; + matrix m; + int n, p_size, gap_; + XPOINT *p; + int what; + int fl_clip_state_number; + int rstackptr; + static const int region_stack_max = FL_REGION_STACK_SIZE - 1; + Fl_Region rstack[FL_REGION_STACK_SIZE]; +#ifdef WIN32 + int numcount; + int counts[20]; +#elif defined(__APPLE__) + // not needed +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: define variables for Fl_Graphics_Driver if needed." + // not needed +#else + // not needed in X11 +#endif + Fl_Font_Descriptor *font_descriptor_; + void transformed_vertex0(COORD_T x, COORD_T y); + void fixloop(); + +protected: +#ifndef FL_DOXYGEN + enum {LINE, LOOP, POLYGON, POINT_}; + inline int vertex_no() { return n; } + inline XPOINT *vertices() {return p;} + inline int vertex_kind() {return what;} +#endif +/* ** \brief red color for background and/or mixing if device does not support masking or alpha * + uchar bg_r_; + ** \brief green color for background and/or mixing if device does not support masking or alpha * + uchar bg_g_; + ** \brief blue color for background and/or mixing if device does not support masking or alpha * + uchar bg_b_; */ + friend class Fl_Pixmap; + friend class Fl_Bitmap; + friend class Fl_RGB_Image; + friend void fl_line_style(int style, int width, char* dashes); + friend void fl_draw(const char *str, int n, int x, int y); +#ifdef __APPLE__ + friend void fl_draw(const char *str, int n, float x, float y); +#elif defined(WIN32) + // not needed +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: add floating point text positioning if your platform supports it" +#else + // not needed +#endif + friend void fl_draw(int angle, const char *str, int n, int x, int y); + friend void fl_rtl_draw(const char *str, int n, int x, int y); + friend void fl_font(Fl_Font face, Fl_Fontsize size); + friend void fl_color(Fl_Color c); + friend void fl_color(uchar r, uchar g, uchar b); + friend void fl_begin_points(); + friend void fl_begin_line(); + friend void fl_begin_loop(); + friend void fl_begin_polygon(); + friend void fl_vertex(double x, double y); + friend void fl_curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3); + friend void fl_circle(double x, double y, double r); + friend void fl_arc(double x, double y, double r, double start, double end); + friend void fl_arc(int x, int y, int w, int h, double a1, double a2); + friend void fl_pie(int x, int y, int w, int h, double a1, double a2); + friend void fl_end_points(); + friend void fl_end_line(); + friend void fl_end_loop(); + friend void fl_end_polygon(); + friend void fl_transformed_vertex(double xf, double yf); + friend void fl_begin_complex_polygon(); + friend void fl_gap(); + friend void fl_end_complex_polygon(); + friend void fl_push_matrix(); + friend void fl_pop_matrix(); + friend void fl_mult_matrix(double a, double b, double c, double d, double x, double y); + friend void fl_scale(double x, double y); + friend void fl_scale(double x); + friend void fl_translate(double x, double y); + friend void fl_rotate(double d); + friend double fl_transform_x(double x, double y); + friend double fl_transform_y(double x, double y); + friend double fl_transform_dx(double x, double y); + friend double fl_transform_dy(double x, double y); + + friend void fl_draw_image(const uchar* buf, int X,int Y,int W,int H, int D, int L); + friend void fl_draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D, int L); + friend void fl_draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D); + friend FL_EXPORT void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D); + friend FL_EXPORT void gl_start(); + friend void fl_copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); + matrix *fl_matrix; /**< Points to the current coordinate transformation matrix */ + + /** \brief The constructor. */ + Fl_Graphics_Driver(); + /** \brief see fl_line_style(int style, int width, char* dashes). */ + virtual void line_style(int style, int width=0, char* dashes=0); + /** \brief see fl_draw(const char *str, int n, int x, int y). */ + virtual void draw(const char *str, int n, int x, int y) {} +#ifdef __APPLE__ + virtual void draw(const char *str, int n, float x, float y) { draw(str, n, (int)(x+0.5), (int)(y+0.5));} +#elif defined(WIN32) + // not needed +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: add floating point text positioning if your platform supports it" +#else + // not needed +#endif + /** \brief see fl_draw(int angle, const char *str, int n, int x, int y). */ + virtual void draw(int angle, const char *str, int n, int x, int y) {} + /** \brief see fl_rtl_draw(const char *str, int n, int x, int y). */ + virtual void rtl_draw(const char *str, int n, int x, int y) {}; + /** \brief see fl_color(Fl_Color c). */ + virtual void color(Fl_Color c) {color_ = c;} + /** \brief see fl_color(uchar r, uchar g, uchar b). */ + virtual void color(uchar r, uchar g, uchar b) {} + /** \brief see fl_begin_points(). */ + virtual void begin_points(); + /** \brief see fl_begin_line(). */ + virtual void begin_line(); + /** \brief see fl_begin_loop(). */ + virtual void begin_loop(); + /** \brief see fl_begin_polygon(). */ + virtual void begin_polygon(); + /** \brief see fl_vertex(double x, double y). */ + virtual void vertex(double x, double y); + /** \brief see fl_curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3). */ + virtual void curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3); + /** \brief see fl_circle(double x, double y, double r). */ + virtual void circle(double x, double y, double r); + /** \brief see fl_arc(double x, double y, double r, double start, double end). */ + virtual void arc(double x, double y, double r, double start, double end); + /** \brief see fl_arc(int x, int y, int w, int h, double a1, double a2). */ + virtual void arc(int x, int y, int w, int h, double a1, double a2); + /** \brief see fl_pie(int x, int y, int w, int h, double a1, double a2). */ + virtual void pie(int x, int y, int w, int h, double a1, double a2); + /** \brief see fl_end_points(). */ + virtual void end_points(); + /** \brief see fl_end_line(). */ + virtual void end_line(); + /** \brief see fl_end_loop(). */ + virtual void end_loop(); + /** \brief see fl_end_polygon(). */ + virtual void end_polygon(); + /** \brief see fl_begin_complex_polygon(). */ + virtual void begin_complex_polygon(); + /** \brief see fl_gap(). */ + virtual void gap(); + /** \brief see fl_end_complex_polygon(). */ + virtual void end_complex_polygon(); + /** \brief see fl_transformed_vertex(double xf, double yf). */ + virtual void transformed_vertex(double xf, double yf); + + /** \brief see fl_push_matrix(). */ + void push_matrix(); + /** \brief see fl_pop_matrix(). */ + void pop_matrix(); + /** \brief see fl_mult_matrix(double a, double b, double c, double d, double x, double y). */ + void mult_matrix(double a, double b, double c, double d, double x, double y); + /** \brief see fl_scale(double x, double y). */ + inline void scale(double x, double y) { mult_matrix(x,0,0,y,0,0); } + /** \brief see fl_scale(double x). */ + inline void scale(double x) { mult_matrix(x,0,0,x,0,0); } + /** \brief see fl_translate(double x, double y). */ + inline void translate(double x,double y) { mult_matrix(1,0,0,1,x,y); } + /** \brief see fl_rotate(double d). */ + void rotate(double d); + /** \brief see fl_transform_x(double x, double y). */ + double transform_x(double x, double y); + /** \brief see fl_transform_y(double x, double y). */ + double transform_y(double x, double y); + /** \brief see fl_transform_dx(double x, double y). */ + double transform_dx(double x, double y); + /** \brief see fl_transform_dy(double x, double y). */ + double transform_dy(double x, double y); + + // Images + /** \brief see fl_draw_image(const uchar* buf, int X,int Y,int W,int H, int D, int L). */ + virtual void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) {} + /** \brief see fl_draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D, int L). */ + virtual void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) {} + /** \brief see fl_draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D). */ + virtual void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) {} + /** \brief see fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D). */ + virtual void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) {} + // Image classes + /** \brief Draws an Fl_RGB_Image object to the device. + * + Specifies a bounding box for the image, with the origin (upper left-hand corner) of + the image offset by the cx and cy arguments. + */ + virtual void draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy) {} + /** \brief Draws an Fl_Pixmap object to the device. + * + Specifies a bounding box for the image, with the origin (upper left-hand corner) of + the image offset by the cx and cy arguments. + */ + virtual void draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy) {} + /** \brief Draws an Fl_Bitmap object to the device. + * + Specifies a bounding box for the image, with the origin (upper left-hand corner) of + the image offset by the cx and cy arguments. + */ + virtual void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {} +#if FLTK_ABI_VERSION >= 10301 + virtual +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); + +public: + static const char *class_id; + virtual const char *class_name() {return class_id;}; + /** \brief see fl_font(Fl_Font face, Fl_Fontsize size). */ + virtual void font(Fl_Font face, Fl_Fontsize fsize) {font_ = face; size_ = fsize;} + /** \brief see fl_font(void). */ + Fl_Font font() {return font_; } + /** \brief see fl_size(). */ + Fl_Fontsize size() {return size_; } + /** \brief see fl_width(const char *str, int n). */ + virtual double width(const char *str, int n) {return 0;} + /** \brief see fl_width(unsigned int n). */ + virtual inline double width(unsigned int c) { char ch = (char)c; return width(&ch, 1); } + /** \brief see fl_text_extents(const char*, int n, int& dx, int& dy, int& w, int& h). */ + virtual void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + /** \brief see fl_height(). */ + virtual int height() {return size();} + /** \brief see fl_descent(). */ + virtual int descent() {return 0;} + /** \brief see fl_color(void). */ + Fl_Color color() {return color_;} + /** Returns a pointer to the current Fl_Font_Descriptor for the graphics driver */ + inline Fl_Font_Descriptor *font_descriptor() { return font_descriptor_;} + /** Sets the current Fl_Font_Descriptor for the graphics driver */ + inline void font_descriptor(Fl_Font_Descriptor *d) { font_descriptor_ = d;} +#if FLTK_ABI_VERSION >= 10304 || defined(FL_DOXYGEN) + virtual +#endif + int draw_scaled(Fl_Image *img, int X, int Y, int W, int H); + /** \brief The destructor */ + virtual ~Fl_Graphics_Driver() { if (p) free(p); } + + // === all code below in this class has been to the reorganisation FL_PORTING process +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/quartz_rect.cxx + friend void fl_point(int x, int y); + virtual void point(int x, int y) = 0; + friend void fl_rect(int x, int y, int w, int h); + virtual void rect(int x, int y, int w, int h) = 0; + friend void fl_rectf(int x, int y, int w, int h); + virtual void rectf(int x, int y, int w, int h) = 0; + friend void fl_line(int x, int y, int x1, int y1); + virtual void line(int x, int y, int x1, int y1) = 0; + friend void fl_line(int x, int y, int x1, int y1, int x2, int y2); + virtual void line(int x, int y, int x1, int y1, int x2, int y2) = 0; + friend void fl_xyline(int x, int y, int x1); + virtual void xyline(int x, int y, int x1) = 0; + friend void fl_xyline(int x, int y, int x1, int y2); + virtual void xyline(int x, int y, int x1, int y2) = 0; + friend void fl_xyline(int x, int y, int x1, int y2, int x3); + virtual void xyline(int x, int y, int x1, int y2, int x3) = 0; + friend void fl_yxline(int x, int y, int y1); + virtual void yxline(int x, int y, int y1) = 0; + friend void fl_yxline(int x, int y, int y1, int x2); + virtual void yxline(int x, int y, int y1, int x2) = 0; + friend void fl_yxline(int x, int y, int y1, int x2, int y3); + virtual void yxline(int x, int y, int y1, int x2, int y3) = 0; + friend void fl_loop(int x0, int y0, int x1, int y1, int x2, int y2); + virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2) = 0; + friend void fl_loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) = 0; + friend void fl_polygon(int x0, int y0, int x1, int y1, int x2, int y2); + virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2) = 0; + friend void fl_polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) = 0; + // --- clipping + friend void fl_push_clip(int x, int y, int w, int h); + virtual void push_clip(int x, int y, int w, int h) = 0; + friend int fl_clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + virtual int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) = 0; + friend int fl_not_clipped(int x, int y, int w, int h); + virtual int not_clipped(int x, int y, int w, int h) = 0; + friend void fl_push_no_clip(); + virtual void push_no_clip() = 0; + friend void fl_pop_clip(); + virtual void pop_clip() = 0; + friend Fl_Region fl_clip_region(); + virtual Fl_Region clip_region(); // has default implementation + friend void fl_clip_region(Fl_Region r); + virtual void clip_region(Fl_Region r); // has default implementation + friend void fl_restore_clip(); + virtual void restore_clip(); +}; + + +#if defined(__APPLE__) + +/** + \brief The Mac OS X-specific graphics class. + * + This class is implemented only on the Mac OS X platform. + */ +class FL_EXPORT Fl_Quartz_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void color(Fl_Color c); + void color(uchar r, uchar g, uchar b); + void draw(const char* str, int n, int x, int y); +#ifdef __APPLE__ + void draw(const char *str, int n, float x, float y); +#endif + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); +#if ! defined(FL_DOXYGEN) + static Fl_Offscreen create_offscreen_with_alpha(int w, int h); +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/quartz_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + void xyline(int x, int y, int x1); + void xyline(int x, int y, int x1, int y2); + void xyline(int x, int y, int x1, int y2, int x3); + void yxline(int x, int y, int y1); + void yxline(int x, int y, int y1, int x2); + void yxline(int x, int y, int y1, int x2, int y3); + void loop(int x0, int y0, int x1, int y1, int x2, int y2); + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + // --- clipping + void push_clip(int x, int y, int w, int h); + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + int not_clipped(int x, int y, int w, int h); + void push_no_clip(); + void pop_clip(); + void restore_clip(); +}; + +// FIXME: add Fl_Quartz_Printer_Graphics_Driver + +#elif defined(WIN32) || defined(FL_DOXYGEN) + +/** + \brief The MSWindows-specific graphics class. + * + This class is implemented only on the MSWindows platform. + */ +class FL_EXPORT Fl_GDI_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void color(Fl_Color c); + void color(uchar r, uchar g, uchar b); + void draw(const char* str, int n, int x, int y); + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); +#if ! defined(FL_DOXYGEN) + void copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy); +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/gdi_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + void xyline(int x, int y, int x1); + void xyline(int x, int y, int x1, int y2); + void xyline(int x, int y, int x1, int y2, int x3); + void yxline(int x, int y, int y1); + void yxline(int x, int y, int y1, int x2); + void yxline(int x, int y, int y1, int x2, int y3); + void loop(int x0, int y0, int x1, int y1, int x2, int y2); + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + // --- clipping + void push_clip(int x, int y, int w, int h); + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + int not_clipped(int x, int y, int w, int h); + void push_no_clip(); + void pop_clip(); + void restore_clip(); +}; + +/** + The graphics driver used when printing on MSWindows. + * + This class is implemented only on the MSWindows platform. It 's extremely similar to Fl_GDI_Graphics_Driver. + */ +class FL_EXPORT Fl_GDI_Printer_Graphics_Driver : public Fl_GDI_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy); + int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); +}; + +#elif defined(FL_PORTING) + +# pragma message "FL_PORTING: define a native graphics driver Fl_xxx_Graphics_Driver" +class FL_EXPORT Fl_XXX_Graphics_Driver : public Fl_Graphics_Driver { +protected: + // --- recently moved implementations (see FL_PORTING efforts) + void point(int x, int y) { } + void rect(int x, int y, int w, int h) { } +}; + +#else // X11 + +/** + \brief The Xlib-specific graphics class. + * + This class is implemented only on the Xlib platform. + */ +class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void color(Fl_Color c); + void color(uchar r, uchar g, uchar b); + void draw(const char* str, int n, int x, int y); + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +#if ! defined(FL_DOXYGEN) + void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +#endif +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + void xyline(int x, int y, int x1); + void xyline(int x, int y, int x1, int y2); + void xyline(int x, int y, int x1, int y2, int x3); + void yxline(int x, int y, int y1); + void yxline(int x, int y, int y1, int x2); + void yxline(int x, int y, int y1, int x2, int y3); + void loop(int x0, int y0, int x1, int y1, int x2, int y2); + void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2); + void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + // --- clipping + void push_clip(int x, int y, int w, int h); + int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); + int not_clipped(int x, int y, int w, int h); + void push_no_clip(); + void pop_clip(); + void restore_clip(); +}; + +#endif + +/** + A drawing surface that's susceptible to receive graphical output. + Any FLTK application has at any time a current drawing surface to which all drawing requests are directed. + The current surface is given by Fl_Surface_Device::surface(). + When main() begins running, the current drawing surface has been set to the computer's display, + an instance of the Fl_Display_Device class. + + A drawing surface other than the computer's display, is typically used as follows: + <ol><li> Create \c surface, an object from a particular Fl_Surface_Device derived class (e.g., Fl_Copy_Surface, Fl_Printer). + <li> Memorize what is the current drawing surface with <tt> Fl_Surface_Device *old_current = Fl_Surface_Device::surface();</tt> + <li> Call \c surface->set_current(); to redirect all graphics requests to \c surface which becomes the new + current drawing surface (not necessary with class Fl_Printer because it is done by Fl_Printer::start_job()). + <li> At this point any of the \ref fl_drawings (e.g., fl_rect()) or the \ref fl_attributes or \ref drawing_images functions + (e.g., fl_draw_image(), Fl_Image::draw()) operates on the new current drawing surface. + Certain drawing surfaces allow additional ways to draw to them (e.g., Fl_Printer::print_widget(), Fl_Image_Surface::draw()). + <li> After all drawing requests have been performed, redirect graphics requests back to their previous destination + with \c old_current->set_current();. + <li> Delete \c surface. + </ol> + */ +class FL_EXPORT Fl_Surface_Device : public Fl_Device { + /** \brief The graphics driver in use by this surface. */ + Fl_Graphics_Driver *_driver; + static Fl_Surface_Device *_surface; // the surface that currently receives graphics output + static Fl_Surface_Device *default_surface(); // create surface is none exists yet +protected: + /** \brief Constructor that sets the graphics driver to use for the created surface. */ + Fl_Surface_Device(Fl_Graphics_Driver *graphics_driver) {_driver = graphics_driver; }; +public: + static const char *class_id; + const char *class_name() {return class_id;}; + virtual void set_current(void); + /** \brief Sets the graphics driver of this drawing surface. */ + inline void driver(Fl_Graphics_Driver *graphics_driver) {_driver = graphics_driver;}; + /** \brief Returns the graphics driver of this drawing surface. */ + inline Fl_Graphics_Driver *driver() {return _driver; }; + /** The current drawing surface. + In other words, the Fl_Surface_Device object that currently receives all graphics output */ + static inline Fl_Surface_Device *surface() { + return _surface ? _surface : default_surface(); + }; + /** \brief The destructor. */ + virtual ~Fl_Surface_Device() {} +}; + +/** + A display to which the computer can draw. + When the program begins running, an Fl_Display_Device instance has been created and made the current drawing surface. + There is no need to create any other object of this class. + */ +class FL_EXPORT Fl_Display_Device : public Fl_Surface_Device { + friend class Fl_Quartz_Graphics_Driver; + static Fl_Display_Device *_display; // the platform display device +#ifdef __APPLE__ + friend class Fl_X; + friend class Fl_Graphics_Driver; + static bool high_res_window_; //< true when drawing to a window of a retina display (Mac OS X only) + static bool high_resolution() {return high_res_window_;} +#elif defined(WIN32) +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: implement functions for extra high res drawing if your platform supports it" +#else +#endif +public: + static const char *class_id; + const char *class_name() {return class_id;}; + Fl_Display_Device(Fl_Graphics_Driver *graphics_driver); + static Fl_Display_Device *display_device(); +}; + +/** + This plugin socket allows the integration of new device drivers for special + window or screen types. It is currently used to provide an automated printing + service and screen capture for OpenGL windows, if linked with fltk_gl. + */ +class FL_EXPORT Fl_Device_Plugin : public Fl_Plugin { +public: + /** \brief The constructor */ + Fl_Device_Plugin(const char *pluginName) + : Fl_Plugin(klass(), pluginName) { } + /** \brief Returns the class name */ + virtual const char *klass() { return "fltk:device"; } + /** \brief Returns the plugin name */ + virtual const char *name() = 0; + /** \brief Prints a widget + \param w the widget + \param x,y offsets where to print relatively to coordinates origin + \param height height of the current drawing area + */ + virtual int print(Fl_Widget* w, int x, int y, int height) = 0; + /** captures a rectangle of a widget as an image + \return The captured pixels as an RGB image + */ + virtual Fl_RGB_Image* rectangle_capture(Fl_Widget *widget, int x, int y, int w, int h) = 0; +}; + +#endif // Fl_Device_H + +// +// End of "$Id$". +// diff --git a/src/cfg_gfx/xlib_rect.cxx b/src/cfg_gfx/xlib_rect.cxx new file mode 100644 index 000000000..771cc6a8b --- /dev/null +++ b/src/cfg_gfx/xlib_rect.cxx @@ -0,0 +1,860 @@ +// +// "$Id$" +// +// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2012 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 +// + +/** + \file fl_rect.cxx + \brief Drawing and clipping routines for rectangles. +*/ + +// These routines from fl_draw.H are used by the standard boxtypes +// and thus are always linked into an fltk program. +// Also all fl_clip routines, since they are always linked in so +// that minimal update works. + +#include <config.h> +#include "config_lib.h" +#include <FL/Fl.H> +#include <FL/Fl_Widget.H> +#include <FL/Fl_Printer.H> +#include <FL/fl_draw.H> +#include <FL/x.H> + +#if defined(WIN32) || defined(__APPLE__) +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: implement all the line drawing functions below" +#else +#endif + +// fl_line_width_ must contain the absolute value of the current +// line width to be used for X11 clipping (see below). +// This is defined in src/fl_line_style.cxx +extern int fl_line_width_; + + +void Fl_Graphics_Driver::restore_clip() { + fl_clip_state_number++; +} + +void Fl_Graphics_Driver::clip_region(Fl_Region r) { + Fl_Region oldr = rstack[rstackptr]; + if (oldr) XDestroyRegion(oldr); + rstack[rstackptr] = r; + fl_restore_clip(); +} + +Fl_Region Fl_Graphics_Driver::clip_region() { + return rstack[rstackptr]; +} + + + +//////////////////////////////////////////////////////////////// + +/* + Matt: I wrote individual methods for every class. They are virtual, so the + correct function is called, depending on the active driver. + + By having individual methods, multiple drivers can co-exist, for example + Quartz, OpenGL, and a printer driver. + + The individual implementations should eventually go into files that are + included into this file, based on the configuration, for example: + + src/cfg_gfx/quartz_rect.cxx + src/cfg_gfx/gdi_rect.cxx + src/cfg_gfx/xlib_rect.cxx + + Porting the graphics system to a new platform then requires to copy one of + these files and implement the virtual functions. point() is the only function + that *must* be implemented when deriving from 'Fl_Minimal_Graphics_Driver" + (which is still to be written) + */ + +//////////////////////////////////////////////////////////////// + +#ifdef FL_CFG_GFX_QUARTZ + +extern float fl_quartz_line_width_; +#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) + +// --- line and polygon drawing with integer coordinates + +void Fl_Quartz_Graphics_Driver::point(int x, int y) { + CGContextFillRect(fl_gc, CGRectMake(x - 0.5, y - 0.5, 1, 1) ); +} + +void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + // FIXME: there should be a quartz graphics driver for the printer device that makes the USINGQUARTZPRINTER obsolete + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGRect rect = CGRectMake(x, y, w-1, h-1); + CGContextStrokeRect(fl_gc, rect); + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + CGRect rect = CGRectMake(x - 0.5, y - 0.5, w , h); + CGContextFillRect(fl_gc, rect); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit + (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles + of size one unit by line-width. + */ + CGContextFillRect(fl_gc, CGRectMake(x-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1 - fl_quartz_line_width_/2, y2-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextAddLineToPoint(fl_gc, x3, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x3-0.5, y2 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y1-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2-0.5, y1 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextAddLineToPoint(fl_gc, x2, y3); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2 - fl_quartz_line_width_/2, y3-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +// --- clipping + +void Fl_Quartz_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + XDestroyRegion(r); + r = Fl_X::intersect_region_and_rect(current, x,y,w,h); + } + } else { // make empty clip region: + r = XRectangleRegion(0,0,0,0); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_Quartz_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + CGRect u = CGRectMake(0,0,0,0); + CGRect test; + for (int i = 0; i < r->count; i++) { + test = CGRectIntersection(r->rects[i], arg); + if ( !CGRectIsEmpty(test) ) { + if(CGRectIsEmpty(u)) u = test; + else u = CGRectUnion(u, test); + } + } + X = int(u.origin.x + 0.5); // reverse offset introduced by fl_cgrectmake_cocoa() + Y = int(u.origin.y + 0.5); + W = int(u.size.width + 0.5); // round to nearest integer + H = int(u.size.height + 0.5); + if (CGRectIsEmpty(u)) W = H = 0; + return !CGRectEqualToRect(arg, u); +} + +int Fl_Quartz_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + for (int i = 0; i < r->count; i++) { + CGRect test = CGRectIntersection(r->rects[i], arg); + if (!CGRectIsEmpty(test)) return 1; + } + return 0; +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_Quartz_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_Quartz_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_Quartz_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_Quartz_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + if ( fl_window || fl_gc ) { // clipping for a true window or an offscreen buffer + Fl_X::q_clear_clipping(); + Fl_X::q_fill_context();//flip coords if bitmap context + //apply program clip + if (r) { + CGContextClipToRects(fl_gc, r->rects, r->count); + } + } +} + +#endif + +// ----------------------------------------------------------------------------- + +#ifdef FL_CFG_GFX_GDI + +// --- line and polygon drawing with integer coordinates + +void Fl_GDI_Graphics_Driver::point(int x, int y) { + SetPixel(fl_gc, x, y, fl_RGB()); +} + +void Fl_GDI_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x+w-1, y); + LineTo(fl_gc, x+w-1, y+h-1); + LineTo(fl_gc, x, y+h-1); + LineTo(fl_gc, x, y); +} + +void Fl_GDI_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + RECT rect; + rect.left = x; rect.top = y; + rect.right = x + w; rect.bottom = y + h; + FillRect(fl_gc, &rect, fl_brush()); +} + +void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + SetPixel(fl_gc, x1, y1, fl_RGB()); +} + +void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + LineTo(fl_gc, x2, y2); + SetPixel(fl_gc, x2, y2, fl_RGB()); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1) { + MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + if (y2 < y) y2--; + else y2++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y); + LineTo(fl_gc, x1, y2); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + if(x3 < x1) x3--; + else x3++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y); + LineTo(fl_gc, x1, y2); + LineTo(fl_gc, x3, y2); +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1) { + if (y1 < y) y1--; + else y1++; + MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x, y1); +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + if (x2 > x) x2++; + else x2--; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x, y1); + LineTo(fl_gc, x2, y1); +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + if(y3<y1) y3--; + else y3++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x, y1); + LineTo(fl_gc, x2, y1); + LineTo(fl_gc, x2, y3); +} + +void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + LineTo(fl_gc, x2, y2); + LineTo(fl_gc, x, y); +} + +void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y1); + LineTo(fl_gc, x2, y2); + LineTo(fl_gc, x3, y3); + LineTo(fl_gc, x, y); +} + +void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[3]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + SelectObject(fl_gc, fl_brush()); + Polygon(fl_gc, p, 3); +} + +void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + SelectObject(fl_gc, fl_brush()); + Polygon(fl_gc, p, 4); +} + +// --- clipping + +void Fl_GDI_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + CombineRgn(r,r,current,RGN_AND); + } + } else { // make empty clip region: + r = CreateRectRgn(0,0,0,0); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_GDI_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_GDI_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + // The win32 API makes no distinction between partial and complete + // intersection, so we have to check for partial intersection ourselves. + // However, given that the regions may be composite, we have to do + // some voodoo stuff... + Fl_Region rr = XRectangleRegion(x,y,w,h); + Fl_Region temp = CreateRectRgn(0,0,0,0); + int ret; + if (CombineRgn(temp, rr, r, RGN_AND) == NULLREGION) { // disjoint + W = H = 0; + ret = 2; + } else if (EqualRgn(temp, rr)) { // complete + ret = 0; + } else { // partial intersection + RECT rect; + GetRgnBox(temp, &rect); + if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // if print context, convert coords from device to logical + POINT pt[2] = { {rect.left, rect.top}, {rect.right, rect.bottom} }; + DPtoLP(fl_gc, pt, 2); + X = pt[0].x; Y = pt[0].y; W = pt[1].x - X; H = pt[1].y - Y; + } + else { + X = rect.left; Y = rect.top; W = rect.right - X; H = rect.bottom - Y; + } + ret = 1; + } + DeleteObject(temp); + DeleteObject(rr); + return ret; +} + +int Fl_GDI_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + RECT rect; + if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) { // in case of print context, convert coords from logical to device + POINT pt[2] = { {x, y}, {x + w, y + h} }; + LPtoDP(fl_gc, pt, 2); + rect.left = pt[0].x; rect.top = pt[0].y; rect.right = pt[1].x; rect.bottom = pt[1].y; + } else { + rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h; + } + return RectInRegion(r,&rect); +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_GDI_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_GDI_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_GDI_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_GDI_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_GDI_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + SelectClipRgn(fl_gc, r); //if r is NULL, clip is automatically cleared +} + +#endif + +// ----------------------------------------------------------------------------- + +#ifdef FL_CFG_GFX_XLIB + +#ifndef SHRT_MAX +#define SHRT_MAX (32767) +#endif + +/* + We need to check some coordinates for areas for clipping before we + use X functions, because X can't handle coordinates outside the 16-bit + range. Since all windows use relative coordinates > 0, we do also + check for negative values. X11 only, see also STR #2304. + + Note that this is only necessary for large objects, where only a + part of the object is visible. The draw() functions (e.g. box + drawing) must be clipped correctly. This is usually only a matter + for large container widgets. The individual child widgets will be + clipped completely. + + We define the usable X coordinate space as [ -LW : SHRT_MAX - LW ] + where LW = current line width for drawing. This is done so that + horizontal and vertical line drawing works correctly, even in real + border cases, e.g. drawing a rectangle slightly outside the top left + window corner, but with a line width so that a part of the line should + be visible (in this case 2 of 5 pixels): + + fl_line_style (FL_SOLID,5); // line width = 5 + fl_rect (-1,-1,100,100); // top/left: 2 pixels visible + + In this example case, no clipping would be done, because X can + handle it and clip unneeded pixels. + + Note that we must also take care of the case where fl_line_width_ + is zero (maybe unitialized). If this is the case, we assume a line + width of 1. + + Todo: Arbitrary line drawings (e.g. polygons) and clip regions + are not yet done. + + Note: + + We could use max. screen coordinates instead of SHRT_MAX, but that + would need more work and would probably be slower. We assume that + all window coordinates are >= 0 and that no window extends up to + 32767 - LW (where LW = current line width). Thus it is safe to clip + all coordinates to this range before calling X functions. If this + is not true, then clip_to_short() and clip_x() must be redefined. + + It would be somewhat easier if we had fl_clip_w and fl_clip_h, as + defined in FLTK 2.0 (for the upper clipping bounds)... + */ + +/* + clip_to_short() returns 1, if the area is invisible (clipped), + because ... + + (a) w or h are <= 0 i.e. nothing is visible + (b) x+w or y+h are < kmin i.e. left of or above visible area + (c) x or y are > kmax i.e. right of or below visible area + + kmin and kmax are the minimal and maximal X coordinate values, + as defined above. In this case x, y, w, and h are not changed. + + It returns 0, if the area is potentially visible and X can handle + clipping. x, y, w, and h may have been adjusted to fit into the + X coordinate space. + + Use this for clipping rectangles, as used in fl_rect() and + fl_rectf(). + */ +static int clip_to_short(int &x, int &y, int &w, int &h) { + + int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; + int kmin = -lw; + int kmax = SHRT_MAX - lw; + + if (w <= 0 || h <= 0) return 1; // (a) + if (x+w < kmin || y+h < kmin) return 1; // (b) + if (x > kmax || y > kmax) return 1; // (c) + + if (x < kmin) { w -= (kmin-x); x = kmin; } + if (y < kmin) { h -= (kmin-y); y = kmin; } + if (x+w > kmax) w = kmax - x; + if (y+h > kmax) h = kmax - y; + + return 0; +} + +/* + clip_x() returns a coordinate value clipped to the 16-bit coordinate + space (see above). This can be used to draw horizontal and vertical + lines that can be handled by X11. Each single coordinate value can + be clipped individually, and the result can be used directly, e.g. + in fl_xyline() and fl_yxline(). Note that this can't be used for + arbitrary lines (not horizontal or vertical). + */ +static int clip_x (int x) { + + int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; + int kmin = -lw; + int kmax = SHRT_MAX - lw; + + if (x < kmin) + x = kmin; + else if (x > kmax) + x = kmax; + return x; +} + +// Missing X call: (is this the fastest way to init a 1-rectangle region?) +// MSWindows equivalent exists, implemented inline in win32.H +Fl_Region XRectangleRegion(int x, int y, int w, int h) { + XRectangle R; + clip_to_short(x, y, w, h); + R.x = x; R.y = y; R.width = w; R.height = h; + Fl_Region r = XCreateRegion(); + XUnionRectWithRegion(&R, r, r); + return r; +} + +// --- line and polygon drawing with integer coordinates + +void Fl_Xlib_Graphics_Driver::point(int x, int y) { + XDrawPoint(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y)); +} + +void Fl_Xlib_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + if (!clip_to_short(x, y, w, h)) + XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1); +} + +void Fl_Xlib_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + if (!clip_to_short(x, y, w, h)) + XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h); +} + +void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1) { + XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1); +} + +void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[3]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1) { + XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x1), clip_x(y)); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + XPoint p[3]; + p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); + p[1].x = p[2].x = clip_x(x1); p[2].y = clip_x(y2); + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + XPoint p[4]; + p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); + p[1].x = p[2].x = clip_x(x1); p[2].y = p[3].y = clip_x(y2); + p[3].x = clip_x(x3); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1) { + XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x), clip_x(y1)); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + XPoint p[3]; + p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); + p[1].y = p[2].y = clip_x(y1); p[2].x = clip_x(x2); + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + XPoint p[4]; + p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); + p[1].y = p[2].y = clip_x(y1); p[2].x = p[3].x = clip_x(x2); + p[3].y = clip_x(y3); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x; p[3].y = y; + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[5]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + p[4].x = x; p[4].y = y; + XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); +} + +void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x; p[3].y = y; + XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[5]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + p[4].x = x; p[4].y = y; + XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0); + XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); +} + +// --- clipping + +void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + Fl_Region temp = XCreateRegion(); + XIntersectRegion(current, r, temp); + XDestroyRegion(r); + r = temp; + } + } else { // make empty clip region: + r = XCreateRegion(); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_Xlib_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + switch (XRectInRegion(r, x, y, w, h)) { + case 0: // completely outside + W = H = 0; + return 2; + case 1: // completely inside: + return 0; + default: // partial: + break; + } + Fl_Region rr = XRectangleRegion(x,y,w,h); + Fl_Region temp = XCreateRegion(); + XIntersectRegion(r, rr, temp); + XRectangle rect; + XClipBox(temp, &rect); + X = rect.x; Y = rect.y; W = rect.width; H = rect.height; + XDestroyRegion(temp); + XDestroyRegion(rr); + return 1; +} + +int Fl_Xlib_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + // get rid of coordinates outside the 16-bit range the X calls take. + if (clip_to_short(x,y,w,h)) return 0; // clipped + return XRectInRegion(r, x, y, w, h); +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_Xlib_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("fl_push_no_cFl_Xlib_Graphics_Driver::push_no_cliplip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_Xlib_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_Xlib_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_Xlib_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + if (r) XSetRegion(fl_display, fl_gc, r); + else XSetClipMask(fl_display, fl_gc, 0); +} + +#endif + +// +// End of "$Id$". +// diff --git a/src/fl_rect.cxx b/src/fl_rect.cxx index 771cc6a8b..060e2600c 100644 --- a/src/fl_rect.cxx +++ b/src/fl_rect.cxx @@ -89,252 +89,7 @@ Fl_Region Fl_Graphics_Driver::clip_region() { #ifdef FL_CFG_GFX_QUARTZ -extern float fl_quartz_line_width_; -#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) - -// --- line and polygon drawing with integer coordinates - -void Fl_Quartz_Graphics_Driver::point(int x, int y) { - CGContextFillRect(fl_gc, CGRectMake(x - 0.5, y - 0.5, 1, 1) ); -} - -void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - // FIXME: there should be a quartz graphics driver for the printer device that makes the USINGQUARTZPRINTER obsolete - if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGRect rect = CGRectMake(x, y, w-1, h-1); - CGContextStrokeRect(fl_gc, rect); - if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::rectf(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - CGRect rect = CGRectMake(x - 0.5, y - 0.5, w , h); - CGContextFillRect(fl_gc, rect); -} - -void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1) { - if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y1); - CGContextStrokePath(fl_gc); - if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { - if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y1); - CGContextAddLineToPoint(fl_gc, x2, y2); - CGContextStrokePath(fl_gc); - if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) { - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y); - CGContextStrokePath(fl_gc); - if (Fl_Display_Device::high_resolution()) { - /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit - (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles - of size one unit by line-width. - */ - CGContextFillRect(fl_gc, CGRectMake(x-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); - CGContextFillRect(fl_gc, CGRectMake(x1-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); - } - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) { - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y); - CGContextAddLineToPoint(fl_gc, x1, y2); - CGContextStrokePath(fl_gc); - if (Fl_Display_Device::high_resolution()) { - CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); - CGContextFillRect(fl_gc, CGRectMake(x1 - fl_quartz_line_width_/2, y2-0.5, fl_quartz_line_width_, 1)); - } - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y); - CGContextAddLineToPoint(fl_gc, x1, y2); - CGContextAddLineToPoint(fl_gc, x3, y2); - CGContextStrokePath(fl_gc); - if (Fl_Display_Device::high_resolution()) { - CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); - CGContextFillRect(fl_gc, CGRectMake(x3-0.5, y2 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); - } - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) { - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x, y1); - CGContextStrokePath(fl_gc); - if (Fl_Display_Device::high_resolution()) { - CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); - CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y1-0.5, fl_quartz_line_width_, 1)); - } - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) { - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x, y1); - CGContextAddLineToPoint(fl_gc, x2, y1); - CGContextStrokePath(fl_gc); - if (Fl_Display_Device::high_resolution()) { - CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); - CGContextFillRect(fl_gc, CGRectMake(x2-0.5, y1 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); - } - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x, y1); - CGContextAddLineToPoint(fl_gc, x2, y1); - CGContextAddLineToPoint(fl_gc, x2, y3); - CGContextStrokePath(fl_gc); - if (Fl_Display_Device::high_resolution()) { - CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); - CGContextFillRect(fl_gc, CGRectMake(x2 - fl_quartz_line_width_/2, y3-0.5, fl_quartz_line_width_, 1)); - } - if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { - CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y1); - CGContextAddLineToPoint(fl_gc, x2, y2); - CGContextClosePath(fl_gc); - CGContextStrokePath(fl_gc); - CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y1); - CGContextAddLineToPoint(fl_gc, x2, y2); - CGContextAddLineToPoint(fl_gc, x3, y3); - CGContextClosePath(fl_gc); - CGContextStrokePath(fl_gc); - CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { - CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y1); - CGContextAddLineToPoint(fl_gc, x2, y2); - CGContextClosePath(fl_gc); - CGContextFillPath(fl_gc); - CGContextSetShouldAntialias(fl_gc, false); -} - -void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - CGContextSetShouldAntialias(fl_gc, true); - CGContextMoveToPoint(fl_gc, x, y); - CGContextAddLineToPoint(fl_gc, x1, y1); - CGContextAddLineToPoint(fl_gc, x2, y2); - CGContextAddLineToPoint(fl_gc, x3, y3); - CGContextClosePath(fl_gc); - CGContextFillPath(fl_gc); - CGContextSetShouldAntialias(fl_gc, false); -} - -// --- clipping - -void Fl_Quartz_Graphics_Driver::push_clip(int x, int y, int w, int h) { - Fl_Region r; - if (w > 0 && h > 0) { - r = XRectangleRegion(x,y,w,h); - Fl_Region current = rstack[rstackptr]; - if (current) { - XDestroyRegion(r); - r = Fl_X::intersect_region_and_rect(current, x,y,w,h); - } - } else { // make empty clip region: - r = XRectangleRegion(0,0,0,0); - } - if (rstackptr < region_stack_max) rstack[++rstackptr] = r; - else Fl::warning("Fl_Quartz_Graphics_Driver::push_clip: clip stack overflow!\n"); - fl_restore_clip(); -} - -int Fl_Quartz_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - Fl_Region r = rstack[rstackptr]; - if (!r) return 0; - CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); - CGRect u = CGRectMake(0,0,0,0); - CGRect test; - for (int i = 0; i < r->count; i++) { - test = CGRectIntersection(r->rects[i], arg); - if ( !CGRectIsEmpty(test) ) { - if(CGRectIsEmpty(u)) u = test; - else u = CGRectUnion(u, test); - } - } - X = int(u.origin.x + 0.5); // reverse offset introduced by fl_cgrectmake_cocoa() - Y = int(u.origin.y + 0.5); - W = int(u.size.width + 0.5); // round to nearest integer - H = int(u.size.height + 0.5); - if (CGRectIsEmpty(u)) W = H = 0; - return !CGRectEqualToRect(arg, u); -} - -int Fl_Quartz_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - if (x+w <= 0 || y+h <= 0) return 0; - Fl_Region r = rstack[rstackptr]; - if (!r) return 1; - CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); - for (int i = 0; i < r->count; i++) { - CGRect test = CGRectIntersection(r->rects[i], arg); - if (!CGRectIsEmpty(test)) return 1; - } - return 0; -} - -// make there be no clip (used by fl_begin_offscreen() only!) -void Fl_Quartz_Graphics_Driver::push_no_clip() { - if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; - else Fl::warning("Fl_Quartz_Graphics_Driver::push_no_clip: clip stack overflow!\n"); - fl_restore_clip(); -} - -// pop back to previous clip: -void Fl_Quartz_Graphics_Driver::pop_clip() { - if (rstackptr > 0) { - Fl_Region oldr = rstack[rstackptr--]; - if (oldr) XDestroyRegion(oldr); - } else Fl::warning("Fl_Quartz_Graphics_Driver::pop_clip: clip stack underflow!\n"); - fl_restore_clip(); -} - -void Fl_Quartz_Graphics_Driver::restore_clip() { - fl_clip_state_number++; - Fl_Region r = rstack[rstackptr]; - if ( fl_window || fl_gc ) { // clipping for a true window or an offscreen buffer - Fl_X::q_clear_clipping(); - Fl_X::q_fill_context();//flip coords if bitmap context - //apply program clip - if (r) { - CGContextClipToRects(fl_gc, r->rects, r->count); - } - } -} +# include "cfg_gfx/quartz_rect.cxx" #endif |
