summaryrefslogtreecommitdiff
path: root/src/Fl_Graphics_Driver.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fl_Graphics_Driver.cxx')
-rw-r--r--src/Fl_Graphics_Driver.cxx346
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$".
//