diff options
Diffstat (limited to 'src/Fl_Graphics_Driver.cxx')
| -rw-r--r-- | src/Fl_Graphics_Driver.cxx | 346 |
1 files changed, 345 insertions, 1 deletions
diff --git a/src/Fl_Graphics_Driver.cxx b/src/Fl_Graphics_Driver.cxx index b47b8fd88..806862bb8 100644 --- a/src/Fl_Graphics_Driver.cxx +++ b/src/Fl_Graphics_Driver.cxx @@ -3,7 +3,7 @@ // // implementation of Fl_Graphics_Driver class for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2016 by Bill Spitzak and others. +// Copyright 2010-2017 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 @@ -23,6 +23,7 @@ #include <FL/Fl_Image.H> #include <FL/fl_draw.H> #include <FL/Fl_Image_Surface.H> +#include <FL/math.h> FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver; // the current driver of graphics operations @@ -181,6 +182,349 @@ void Fl_Graphics_Driver::uncache_pixmap(fl_uintptr_t p) { fl_delete_offscreen((Fl_Offscreen)p); } + +#ifndef FL_DOXYGEN +Fl_Scalable_Graphics_Driver::Fl_Scalable_Graphics_Driver() : Fl_Graphics_Driver() { + scale_ = 1; +} + +void Fl_Scalable_Graphics_Driver::rect(int x, int y, int w, int h) +{ + rect_unscaled(x * scale_, y * scale_, w * scale_, h * scale_); +} + +void Fl_Scalable_Graphics_Driver::rectf(int x, int y, int w, int h) +{ + rectf_unscaled(x * scale_, y * scale_, w * scale_, h * scale_); +} + +void Fl_Scalable_Graphics_Driver::point(int x, int y) { + point_unscaled(x * scale_, y * scale_); +} + +void Fl_Scalable_Graphics_Driver::line(int x, int y, int x1, int y1) { + line_unscaled( x*scale_, y*scale_, x1*scale_, y1*scale_); +} + +void Fl_Scalable_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + line_unscaled( x*scale_, y*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_); +} + +void Fl_Scalable_Graphics_Driver::xyline(int x, int y, int x1) { + xyline_unscaled(x*scale_, y*scale_, x1*scale_); +} +void Fl_Scalable_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + xyline_unscaled(x*scale_, y*scale_, x1*scale_, y2*scale_); +} +void Fl_Scalable_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + xyline_unscaled(x*scale_, y*scale_, x1*scale_, y2*scale_, x3*scale_); +} + +void Fl_Scalable_Graphics_Driver::yxline(int x, int y, int y1) { + yxline_unscaled(x*scale_, y*scale_, y1*scale_); +} +void Fl_Scalable_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + yxline_unscaled(x*scale_, y*scale_, y1*scale_, x2*scale_); +} +void Fl_Scalable_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + yxline_unscaled(x*scale_, y*scale_, y1*scale_, x2*scale_, y3*scale_); +} + +void Fl_Scalable_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) { + loop_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_); +} + +void Fl_Scalable_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { + loop_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_, x3*scale_, y3*scale_); +} + +void Fl_Scalable_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) { + polygon_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_); +} + +void Fl_Scalable_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { + polygon_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_, x3*scale_, y3*scale_); +} + +void Fl_Scalable_Graphics_Driver::circle(double x, double y, double r) { + double xt = transform_x(x,y); + double yt = transform_y(x,y); + double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); + double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); + ellipse_unscaled(xt*scale_, yt*scale_, rx*scale_, ry*scale_); +} + +// compute width & height of cached image so it can be tiled without undrawn gaps when scaling output +void Fl_Scalable_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) +{ + if ( int(scale_) == scale_ ) { + width = width * scale_; + height = height * scale_; + } else { + width = (width+1) * scale_; + height = (height+1) * scale_; + } +} + + +void Fl_Scalable_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + if (Fl_Graphics_Driver::start_image(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { + return; + } + // to allow rescale at runtime + if (*id(pxm)) { + if (*cache_scale(pxm) != scale_) { + pxm->uncache(); + } + } + if (!*id(pxm)) { + if (scale_ != 1) { // build a scaled id_ & pixmap_ for pxm + int w2=pxm->w(), h2=pxm->h(); + cache_size(pxm, w2, h2); + Fl_Pixmap *pxm2 = (Fl_Pixmap*)pxm->copy(w2, h2); + float s = scale_; scale_ = 1; + *id(pxm) = cache(pxm2, pxm2->w(), pxm2->h(), pxm2->data()); + scale_ = s; + *cache_scale(pxm) = scale_; + *mask(pxm) = *mask(pxm2); + *mask(pxm2) = 0; + delete pxm2; + } else *id(pxm) = cache(pxm, pxm->w(), pxm->h(), pxm->data()); + } + // draw pxm using its scaled id_ & pixmap_ + draw_unscaled(pxm, scale_, X, Y, W, H, cx, cy); +} + + +void Fl_Scalable_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + if (Fl_Graphics_Driver::start_image(bm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { + return; + } + if (*id(bm)) { + if (*cache_scale(bm) != scale_) { + bm->uncache(); + } + } + if (!*id(bm)) { + if (scale_ != 1) { // build a scaled id_ for bm + int w2 = bm->w(), h2 = bm->h(); + cache_size(bm, w2, h2); + Fl_Bitmap *bm2 = (Fl_Bitmap*)bm->copy(w2, h2); + *id(bm) = cache(bm2, bm2->w(), bm2->h(), bm2->array); + *cache_scale(bm) = scale_; + delete bm2; + } else *id(bm) = cache(bm, bm->w(), bm->h(), bm->array); + } + // draw bm using its scaled id_ + draw_unscaled(bm, scale_, X, Y, W, H, cx, cy); +} + + +void Fl_Scalable_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { + // Don't draw an empty image... + if (!img->d() || !img->array) { + Fl_Graphics_Driver::draw_empty(img, XP, YP); + return; + } + if (start_image(img, XP, YP, WP, HP, cx, cy, XP, YP, WP, HP)) { + return; + } + if (scale() != 1 && can_do_alpha_blending()) { // try and use the system's scaled image drawing + push_clip(XP, YP, WP, HP); + Fl_Region r = scale_clip(scale_); + int done = draw_scaled(img, XP-cx, YP-cy, img->w(), img->h()); + unscale_clip(r); + pop_clip(); + if (done) return; + } + // to allow rescale at runtime + if (*id(img) && *cache_scale(img) != scale_) { + img->uncache(); + } + if (!*id(img) && scale_ != 1) { // build and draw a scaled id_ for img + int w2=img->w(), h2=img->h(); + cache_size(img, w2, h2); + Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w2, h2); + draw_unscaled(img2, scale_, XP, YP, WP, HP, cx, cy); + *id(img) = *id(img2); + *id(img2) = 0; + *cache_scale(img) = scale_; + delete img2; + } + else { // draw img using its scaled id_ + draw_unscaled(img, scale_, XP, YP, WP, HP, cx, cy); + } +} + + +void Fl_Scalable_Graphics_Driver::draw(Fl_Shared_Image *shared, int X, int Y) { + if (scale_ == 1) { + Fl_Graphics_Driver::draw(shared, X, Y); + return; + } + float s = scale_; scale_ = 1; + Fl_Region r2 = scale_clip(s); + int oldw=shared->w(); + int oldh=shared->h(); + change_image_size(shared, (oldw*s < 1 ? 1: int(oldw*s)), (oldh*s < 1 ? 1: int(oldh*s))); + Fl_Graphics_Driver::draw(shared, X*s, Y*s); + change_image_size(shared, oldw, oldh); + unscale_clip(r2); + scale_ = s; +} + + +void Fl_Scalable_Graphics_Driver::font(Fl_Font face, Fl_Fontsize size) { + font_unscaled(face, size * scale_); +} + +double Fl_Scalable_Graphics_Driver::width(const char *str, int n) { + return width_unscaled(str, n)/scale_; +} + +double Fl_Scalable_Graphics_Driver::width(unsigned int c) { + return width_unscaled(c)/scale_; +} + +Fl_Fontsize Fl_Scalable_Graphics_Driver::size() { + if (!font_descriptor() ) return -1; + return size_unscaled()/scale_; +} + +void Fl_Scalable_Graphics_Driver::text_extents(const char *str, int n, int &dx, int &dy, int &w, int &h) { + text_extents_unscaled(str, n, dx, dy, w, h); + dx /= scale_; + dy /= scale_; + w /= scale_; + h /= scale_; +} + +int Fl_Scalable_Graphics_Driver::height() { + return int(height_unscaled()/scale_); +} + +int Fl_Scalable_Graphics_Driver::descent() { + return descent_unscaled()/scale_; +} + +void Fl_Scalable_Graphics_Driver::draw(const char *str, int n, int x, int y) { + if (!size_ || !font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + Fl_Region r2 = scale_clip(scale_); + draw_unscaled(str, n, x*scale_, y*scale_); + unscale_clip(r2); +} + +void Fl_Scalable_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { + if (!size_ || !font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + Fl_Region r2 = scale_clip(scale_); + draw_unscaled(angle, str, n, x*scale_, y*scale_); + unscale_clip(r2); +} + +void Fl_Scalable_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) { + rtl_draw_unscaled(str, n, x * scale_, y * scale_); +} + +void Fl_Scalable_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { + arc_unscaled(x * scale_, y * scale_, w * scale_, h * scale_, a1, a2); +} + +void Fl_Scalable_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { + pie_unscaled(x * scale_, y * scale_, w * scale_, h * scale_, a1, a2); +} + +void Fl_Scalable_Graphics_Driver::line_style(int style, int width, char* dashes) { + line_style_unscaled(style, width * scale_, dashes); +} + +void Fl_Scalable_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) { + copy_offscreen_unscaled(x * scale_, y * scale_, w * scale_, h * scale_, pixmap, srcx * scale_, srcy * scale_); +} + +/* read the image data from a pointer or with a callback, scale it, and draw it */ +void Fl_Scalable_Graphics_Driver::draw_image_rescale(void *buf, Fl_Draw_Image_Cb cb, + int X, int Y, int W, int H, int D, int L, bool mono, float s) { + int aD = abs(D); + if (L == 0) L = W*aD; + int depth = mono ? (aD%2==0?2:1) : aD; + uchar *tmp_buf = new uchar[W*H*depth]; + if (cb) { + for (int i = 0; i < H; i++) { + cb(buf, 0, i, W, tmp_buf + i * W * depth); + } + } else { + uchar *q, *p = tmp_buf; + for (int i = 0; i < H; i++) { + q = (uchar*)buf + i * L; + for (int j = 0; j < W; j++) { + memcpy(p, q, depth); + p += depth; q += D; + } + } + } + Fl_RGB_Image *rgb = new Fl_RGB_Image(tmp_buf, W, H, depth); + rgb->alloc_array = 1; + Fl_RGB_Image *scaled_rgb = (Fl_RGB_Image*)rgb->copy(ceil(W * s), ceil(H * s)); + delete rgb; + if (scaled_rgb) { + Fl_Region r2 = scale_clip(s); + draw_image_unscaled(scaled_rgb->array, X * s, Y * s, scaled_rgb->w(), scaled_rgb->h(), depth); + unscale_clip(r2); + delete scaled_rgb; + } +} + +void Fl_Scalable_Graphics_Driver::draw_image(const uchar* buf, int X,int Y,int W,int H, int D, int L) { + if (scale_ == 1) { + draw_image_unscaled(buf, X,Y,W,H,D,L); + } else { + draw_image_rescale((void*)buf, NULL, X, Y, W, H, D, L, false, scale_); + } +} + +void Fl_Scalable_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D) { + if (scale_ == 1) { + draw_image_unscaled(cb, data, X,Y,W,H,D); + } else { + draw_image_rescale(data, cb, X, Y, W, H, D, 0, false, scale_); + } +} + +void Fl_Scalable_Graphics_Driver::draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D, int L) { + if (scale_ == 1) { + draw_image_mono_unscaled(buf, X,Y,W,H,D,L); + } else { + draw_image_rescale((void*)buf, NULL, X, Y, W, H, D, L, true, scale_); + } +} + +void Fl_Scalable_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D) { + if (scale_ == 1) { + draw_image_mono_unscaled(cb, data, X,Y,W,H,D); + } else { + draw_image_rescale(data, cb, X, Y, W, H, D, 0, true, scale_); + } +} + +void Fl_Scalable_Graphics_Driver::transformed_vertex(double xf, double yf) { + transformed_vertex0(xf * scale_, yf * scale_); +} + +void Fl_Scalable_Graphics_Driver::vertex(double x,double y) { + transformed_vertex0((x*m.a + y*m.c + m.x) * scale_, (x*m.b + y*m.d + m.y) * scale_); +} + +void Fl_Scalable_Graphics_Driver::unscale_clip(Fl_Region r) { + if (r) { + if (rstack[rstackptr]) XDestroyRegion(rstack[rstackptr]); + rstack[rstackptr] = r; + } +} + +#endif // !FL_DOXYGEN + // // End of "$Id$". // |
