Improve and simplify X line and rect 16-bit clipping.
Back to 16-bit coordinate limit clipping (actually +/- (2**15 - 8). The clipping range is now constant, symmetrical, and stored in the driver object. Also fixed a bug in Liang-Barsky line clipping algorithm. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12744 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
ac04494e91
commit
c023f26fb0
@ -59,8 +59,7 @@ private:
|
||||
int stack_x_[20], stack_y_[20]; // translation stack allowing cumulative translations
|
||||
int line_delta_;
|
||||
virtual void set_current_();
|
||||
protected:
|
||||
int xmin, ymin, xmax, ymax; // ranges of valid x/y coordinates, see set_clip_range()
|
||||
int clip_max_; // +/- x/y coordinate limit (16-bit coordinate space)
|
||||
protected:
|
||||
virtual void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
|
||||
virtual void draw_unscaled(Fl_Bitmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
|
||||
@ -155,9 +154,12 @@ protected:
|
||||
// --- clipped drawing (after scaling, with real screen coordinates)
|
||||
// --- currently specific to Fl_Xlib_Graphics_Driver (16-bit coordinate clipping)
|
||||
|
||||
// clip one coordinate (x or y) --- correct axis (x/y) is important !
|
||||
virtual int clip_x(int x);
|
||||
virtual int clip_y(int y);
|
||||
// clipping limits
|
||||
virtual int clip_max() { return clip_max_; }
|
||||
virtual int clip_min() { return -clip_max_; }
|
||||
|
||||
// clip one coordinate (x or y)
|
||||
virtual int clip_xy(int x);
|
||||
|
||||
// clip one line
|
||||
virtual int clip_line(int &x1, int &y1, int &x2, int &y2);
|
||||
@ -168,9 +170,6 @@ protected:
|
||||
// draw a line after clipping (if visible)
|
||||
virtual void draw_clipped_line(int x1, int y1, int x2, int y2);
|
||||
|
||||
// set_clip_range() - set valid coordinate range (16-bit or current window)
|
||||
virtual void set_clip_range();
|
||||
|
||||
// --- 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);
|
||||
|
@ -59,6 +59,7 @@ Fl_Xlib_Graphics_Driver::Fl_Xlib_Graphics_Driver(void) {
|
||||
#endif
|
||||
offset_x_ = 0; offset_y_ = 0;
|
||||
depth_ = 0;
|
||||
clip_max_ = 32760; // clipping limit (2**15 - 8)
|
||||
}
|
||||
|
||||
Fl_Xlib_Graphics_Driver::~Fl_Xlib_Graphics_Driver() {
|
||||
|
@ -41,58 +41,6 @@
|
||||
// Note: the current (default) approach is to clip to the current window
|
||||
// boundaries instead. This can avoid drawing unecessary (invisible) objects.
|
||||
|
||||
#define MAXK (32760) // 2 ** 15 - K (8)
|
||||
|
||||
#define CLIP_TO_WINDOW (0) // Default: 1 (clip to window), see below
|
||||
|
||||
/*
|
||||
Sets the coordinate space limits for clipping.
|
||||
|
||||
We have two choices:
|
||||
|
||||
- the entire 16-bit coordinate space (CLIP_TO_WINDOW = 0)
|
||||
- the current window (Default: CLIP_TO_WINDOW != 0)
|
||||
|
||||
The current approach is to use window coordinates. The macro CLIP_TO_WINDOW
|
||||
(above) can be set to 0 to clip to the entire 16-bit coordinate space
|
||||
instead. This can be done for testing purposes or if it turns out that
|
||||
window clipping doesn't work as expected.
|
||||
AlbrechtS, 09 Mar 2018
|
||||
|
||||
Implementation note: to optimize setting the clip area this could be done
|
||||
when drawing starts, maybe in make_current() or something like that.
|
||||
This is left for a later step.
|
||||
*/
|
||||
void Fl_Xlib_Graphics_Driver::set_clip_range() {
|
||||
|
||||
#if (CLIP_TO_WINDOW) // should be true (the default)
|
||||
|
||||
Fl_Window *win = Fl_Window::current(); // get current window
|
||||
|
||||
xmax = win->w() * scale_ + line_width_ + 1;
|
||||
ymax = win->h() * scale_ + line_width_ + 1;
|
||||
xmin = 0 - line_width_ - 1;
|
||||
ymin = 0 - line_width_ - 1;
|
||||
|
||||
// the following checks are likely unnecessary, but with large scaling
|
||||
// factors ... (a little paranoid)
|
||||
|
||||
if (xmax > MAXK) xmax = MAXK;
|
||||
if (ymax > MAXK) ymax = MAXK;
|
||||
if (xmin < -MAXK) xmin = -MAXK;
|
||||
if (ymin < -MAXK) ymin = -MAXK;
|
||||
|
||||
#else // use full X (16-bit) coordinate space
|
||||
|
||||
xmax = MAXK;
|
||||
ymax = xmax;
|
||||
xmin = -xmax;
|
||||
ymin = -xmax;
|
||||
|
||||
#endif // CLIP_TO_WINDOW
|
||||
|
||||
} // set_clip_range()
|
||||
|
||||
/*
|
||||
Liang-Barsky line clipping algorithm. For documentation see:
|
||||
https://en.wikipedia.org/wiki/Liang-Barsky_algorithm .
|
||||
@ -114,18 +62,16 @@ void Fl_Xlib_Graphics_Driver::set_clip_range() {
|
||||
|
||||
int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
|
||||
|
||||
set_clip_range();
|
||||
|
||||
// define variables
|
||||
float p1 = float(-(x2 - x1));
|
||||
float p2 = float(-p1);
|
||||
float p3 = float(-(y2 - y1));
|
||||
float p4 = float(-p3);
|
||||
|
||||
float q1 = float(x1 - xmin);
|
||||
float q2 = float(xmax - x1);
|
||||
float q3 = float(y1 - ymin);
|
||||
float q4 = float(ymax - y1);
|
||||
float q1 = float(x1 - clip_min());
|
||||
float q2 = float(clip_max() - x1);
|
||||
float q3 = float(y1 - clip_min());
|
||||
float q4 = float(clip_max() - y1);
|
||||
|
||||
float posmin = 1; // positive minimum
|
||||
float negmax = 0; // negative maximum
|
||||
@ -156,6 +102,9 @@ int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
|
||||
}
|
||||
}
|
||||
|
||||
if (negmax > posmin) // line outside clipping window
|
||||
return 1; // clipped
|
||||
|
||||
// compute new points (note: order is important!)
|
||||
|
||||
x2 = int(x1 + p2 * posmin);
|
||||
@ -208,12 +157,12 @@ int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
|
||||
/*
|
||||
clip_rect() returns 1 if the area is invisible (clipped) because ...
|
||||
|
||||
(a) w <= 0 or h <= 0 i.e. nothing is visible
|
||||
(b) x+w < xmin or y+h < ymin i.e. left of or above visible area
|
||||
(c) x > xmax or y > ymax i.e. right of or below visible area
|
||||
(a) w <= 0 or h <= 0 i.e. nothing is visible
|
||||
(b) x+w < clip_min() or y+h < clip_min() i.e. left of or above visible area
|
||||
(c) x > clip_max() or y > clip_max() i.e. right of or below visible area
|
||||
|
||||
xmin, ymin, xmax, and ymax are the minimal and maximal X coordinate
|
||||
values or the window bounds as defined above.
|
||||
clip_min() and clip_max() are the minimal and maximal x/y coordinate values
|
||||
used for clipping.
|
||||
In the above cases x, y, w, and h are not changed and the return
|
||||
value is 1 (clipped).
|
||||
|
||||
@ -223,69 +172,43 @@ int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
|
||||
|
||||
Use this for clipping rectangles as in fl_rect() and fl_rectf().
|
||||
It is fast and convenient.
|
||||
|
||||
Todo: Test for exact (filled) rectangle and border limits. If coordinates
|
||||
are modified (clipped) borders should not be visible if they would be
|
||||
outside the window, for instance:
|
||||
|
||||
fl_line_style(FL_SOLID, 5); // line width = 5
|
||||
fl_rect(-6, 0, 100, 100); // left border should not be visible
|
||||
fl_rect(-1, 0, 100, 100); // left border should be partially visible
|
||||
|
||||
This is no problem with 16-bit clipping but might be relevant with
|
||||
window clipping. The same applies to the bottom and right borders, resp..
|
||||
*/
|
||||
|
||||
int Fl_Xlib_Graphics_Driver::clip_rect(int &x, int &y, int &w, int &h) {
|
||||
|
||||
set_clip_range();
|
||||
if (w <= 0 || h <= 0) return 1; // (a)
|
||||
if (x+w < clip_min() || y+h < clip_min()) return 1; // (b)
|
||||
if (x > clip_max() || y > clip_max()) return 1; // (c)
|
||||
|
||||
if (w <= 0 || h <= 0) return 1; // (a)
|
||||
if (x+w < xmin || y+h < ymin) return 1; // (b)
|
||||
if (x > xmax || y > ymax) return 1; // (c)
|
||||
|
||||
if (x < xmin) { w -= (xmin-x); x = xmin; }
|
||||
if (y < ymin) { h -= (ymin-y); y = ymin; }
|
||||
if (x+w > xmax) w = xmax - x;
|
||||
if (y+h > ymax) h = ymax - y;
|
||||
if (x < clip_min()) { w -= (clip_min()-x); x = clip_min(); }
|
||||
if (y < clip_min()) { h -= (clip_min()-y); y = clip_min(); }
|
||||
if (x+w > clip_max()) w = clip_max() - x;
|
||||
if (y+h > clip_max()) h = clip_max() - y;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
clip_x() and clip_y() return a coordinate value clipped to the 16-bit
|
||||
coordinate space or the current window (see above).
|
||||
clip_xy() returns a single coordinate value clipped to the 16-bit
|
||||
coordinate space.
|
||||
|
||||
This can be used to draw horizontal and vertical lines that can be
|
||||
handled by X11. Each single coordinate value can be clipped individually
|
||||
handled by X. Each single coordinate value can be clipped individually
|
||||
and the result can be used directly, e.g. in fl_xyline() and fl_yxline().
|
||||
|
||||
Note 1: this can't be used for arbitrary lines (neither horizontal nor vertical).
|
||||
Note 2: may be changed since Fl_Xlib_Graphics_Driver::clip_line() exists.
|
||||
*/
|
||||
|
||||
int Fl_Xlib_Graphics_Driver::clip_x(int x) {
|
||||
int Fl_Xlib_Graphics_Driver::clip_xy(int x) {
|
||||
|
||||
set_clip_range();
|
||||
|
||||
if (x < xmin)
|
||||
x = xmin;
|
||||
else if (x > xmax)
|
||||
x = xmax;
|
||||
if (x < clip_min())
|
||||
x = clip_min();
|
||||
else if (x > clip_max())
|
||||
x = clip_max();
|
||||
return x;
|
||||
}
|
||||
|
||||
int Fl_Xlib_Graphics_Driver::clip_y(int y) {
|
||||
|
||||
set_clip_range();
|
||||
|
||||
if (y < ymin)
|
||||
y = ymin;
|
||||
else if (y > ymax)
|
||||
y = ymax;
|
||||
return y;
|
||||
}
|
||||
|
||||
// Missing X call: (is this the fastest way to init a 1-rectangle region?)
|
||||
// Windows equivalent exists, implemented inline in win32.H
|
||||
|
||||
@ -360,8 +283,8 @@ void Fl_Xlib_Graphics_Driver::xyline_unscaled(float x, float y, float x1) {
|
||||
x+=offset_x_*scale_; y+=offset_y_*scale_; x1 += offset_x_*scale_;
|
||||
int tw = line_width_ ? line_width_ : 1; // true line width
|
||||
if (x > x1) { float exch = x; x = x1; x1 = exch; }
|
||||
int ix = clip_x(x+line_delta_); if (scale_ >= 2) ix -= int(scale_/2);
|
||||
int iy = clip_y(y+line_delta_);
|
||||
int ix = clip_xy(x+line_delta_); if (scale_ >= 2) ix -= int(scale_/2);
|
||||
int iy = clip_xy(y+line_delta_);
|
||||
// make sure that line output by xyline(a,b,c) extends to pixel just at left of where xyline(c+1,b,d) begins
|
||||
int ix1 = int(x1/scale_+1.5)*scale_-1;
|
||||
ix1 += line_delta_; if (scale_ >= 4) ix1 -= 1;
|
||||
@ -375,8 +298,8 @@ void Fl_Xlib_Graphics_Driver::yxline_unscaled(float x, float y, float y1) {
|
||||
x+=offset_x_*scale_; y+=offset_y_*scale_; y1 += offset_y_*scale_;
|
||||
int tw = line_width_ ? line_width_ : 1; // true line width
|
||||
if (y > y1) { float exch = y; y = y1; y1 = exch; }
|
||||
int ix = clip_x(x+line_delta_);
|
||||
int iy = clip_y(y+line_delta_); if (scale_ >= 2) iy -= int(scale_/2);
|
||||
int ix = clip_xy(x+line_delta_);
|
||||
int iy = clip_xy(y+line_delta_); if (scale_ >= 2) iy -= int(scale_/2);
|
||||
int iy1 = int(y1/scale_+1.5)*scale_-1;
|
||||
// make sure that line output by yxline(a,b,c) extends to pixel just above where yxline(a,c+1,d) begins
|
||||
iy1 += line_delta_; if (scale_ >= 4) iy1 -= 1;
|
||||
|
Loading…
Reference in New Issue
Block a user