fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_vertex.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fl_vertex.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 // Portable drawing routines for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00034 // Portable drawing code for drawing arbitrary shapes with
00035 // simple 2D transformations.  See also fl_arc.cxx
00036 
00037 // matt: the Quartz implementation purposely doesn't use the Quartz matrix
00038 //       operations for reasons of compatibility and maintainability
00039 
00040 #include <config.h>
00041 #include <FL/fl_draw.H>
00042 #include <FL/x.H>
00043 #include <FL/Fl.H>
00044 #include <FL/math.h>
00045 #include <stdlib.h>
00046 
00047 struct matrix {double a, b, c, d, x, y;};
00048 
00049 static matrix m = {1, 0, 0, 1, 0, 0};
00050 
00051 static matrix stack[32];
00052 matrix * fl_matrix = &m;
00053 static int sptr = 0;
00054 
00059 void fl_push_matrix() {
00060   if (sptr==32)
00061     Fl::error("fl_push_matrix(): matrix stack overflow.");
00062   else
00063     stack[sptr++] = m;
00064 }
00065 
00069 void fl_pop_matrix() {
00070   if (sptr==0)
00071     Fl::error("fl_pop_matrix(): matrix stack underflow.");
00072   else 
00073     m = stack[--sptr];
00074 }
00075 
00082 void fl_mult_matrix(double a, double b, double c, double d, double x, double y) {
00083   matrix o;
00084   o.a = a*m.a + b*m.c;
00085   o.b = a*m.b + b*m.d;
00086   o.c = c*m.a + d*m.c;
00087   o.d = c*m.b + d*m.d;
00088   o.x = x*m.a + y*m.c + m.x;
00089   o.y = x*m.b + y*m.d + m.y;
00090   m = o;
00091 }
00092 
00097 void fl_scale(double x,double y) {fl_mult_matrix(x,0,0,y,0,0);}
00098 
00103 void fl_scale(double x) {fl_mult_matrix(x,0,0,x,0,0);}
00104 
00109 void fl_translate(double x,double y) {fl_mult_matrix(1,0,0,1,x,y);}
00110 
00115 void fl_rotate(double d) {
00116   if (d) {
00117     double s, c;
00118     if (d == 0) {s = 0; c = 1;}
00119     else if (d == 90) {s = 1; c = 0;}
00120     else if (d == 180) {s = 0; c = -1;}
00121     else if (d == 270 || d == -90) {s = -1; c = 0;}
00122     else {s = sin(d*M_PI/180); c = cos(d*M_PI/180);}
00123     fl_mult_matrix(c,-s,s,c,0,0);
00124   }
00125 }
00126 
00127 // typedef what the x,y fields in a point are:
00128 #ifdef WIN32
00129 typedef int COORD_T;
00130 #  define XPOINT XPoint
00131 #elif defined(__APPLE_QUARTZ__)
00132 typedef float COORD_T;
00133 typedef struct { float x; float y; } QPoint;
00134 #  define XPOINT QPoint
00135 extern float fl_quartz_line_width_;
00136 #else
00137 typedef short COORD_T;
00138 #  define XPOINT XPoint
00139 #endif
00140 
00141 static XPOINT *p = (XPOINT *)0;
00142 
00143 static int p_size;
00144 static int n;
00145 static int what;
00146 enum {LINE, LOOP, POLYGON, POINT_};
00147 
00148 void Fl_Graphics_Driver::begin_points() {n = 0; what = POINT_;}
00149 
00150 void Fl_Graphics_Driver::begin_line() {n = 0; what = LINE;}
00151 
00152 void Fl_Graphics_Driver::begin_loop() {n = 0; what = LOOP;}
00153 
00154 void Fl_Graphics_Driver::begin_polygon() {n = 0; what = POLYGON;}
00155 
00160 double fl_transform_x(double x, double y) {return x*m.a + y*m.c + m.x;}
00161 
00166 double fl_transform_y(double x, double y) {return x*m.b + y*m.d + m.y;}
00167 
00172 double fl_transform_dx(double x, double y) {return x*m.a + y*m.c;}
00173 
00178 double fl_transform_dy(double x, double y) {return x*m.b + y*m.d;}
00179 
00180 static void fl_transformed_vertex(COORD_T x, COORD_T y) {
00181   if (!n || x != p[n-1].x || y != p[n-1].y) {
00182     if (n >= p_size) {
00183       p_size = p ? 2*p_size : 16;
00184       p = (XPOINT*)realloc((void*)p, p_size*sizeof(*p));
00185     }
00186     p[n].x = x;
00187     p[n].y = y;
00188     n++;
00189   }
00190 }
00191 
00192 void Fl_Graphics_Driver::transformed_vertex(double xf, double yf) {
00193 #ifdef __APPLE_QUARTZ__
00194   fl_transformed_vertex(COORD_T(xf), COORD_T(yf));
00195 #else
00196   fl_transformed_vertex(COORD_T(rint(xf)), COORD_T(rint(yf)));
00197 #endif
00198 }
00199 
00200 void Fl_Graphics_Driver::vertex(double x,double y) {
00201   fl_transformed_vertex(x*m.a + y*m.c + m.x, x*m.b + y*m.d + m.y);
00202 }
00203 
00204 void Fl_Graphics_Driver::end_points() {
00205 #if defined(USE_X11)
00206   if (n>1) XDrawPoints(fl_display, fl_window, fl_gc, p, n, 0);
00207 #elif defined(WIN32)
00208   for (int i=0; i<n; i++) SetPixel(fl_gc, p[i].x, p[i].y, fl_RGB());
00209 #elif defined(__APPLE_QUARTZ__)
00210   if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
00211   for (int i=0; i<n; i++) { 
00212     CGContextMoveToPoint(fl_gc, p[i].x, p[i].y);
00213     CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
00214     CGContextStrokePath(fl_gc);
00215   }
00216   if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
00217 #else
00218 # error unsupported platform
00219 #endif
00220 }
00221 
00222 void Fl_Graphics_Driver::end_line() {
00223   if (n < 2) {
00224     fl_end_points();
00225     return;
00226   }
00227 #if defined(USE_X11)
00228   if (n>1) XDrawLines(fl_display, fl_window, fl_gc, p, n, 0);
00229 #elif defined(WIN32)
00230   if (n>1) Polyline(fl_gc, p, n);
00231 #elif defined(__APPLE_QUARTZ__)
00232   if (n<=1) return;
00233   CGContextSetShouldAntialias(fl_gc, true);
00234   CGContextMoveToPoint(fl_gc, p[0].x, p[0].y);
00235   for (int i=1; i<n; i++)
00236     CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
00237   CGContextStrokePath(fl_gc);
00238   CGContextSetShouldAntialias(fl_gc, false);
00239 #else
00240 # error unsupported platform
00241 #endif
00242 }
00243 
00244 static void fixloop() {  // remove equal points from closed path
00245   while (n>2 && p[n-1].x == p[0].x && p[n-1].y == p[0].y) n--;
00246 }
00247 
00248 void Fl_Graphics_Driver::end_loop() {
00249   fixloop();
00250   if (n>2) fl_transformed_vertex((COORD_T)p[0].x, (COORD_T)p[0].y);
00251   fl_end_line();
00252 }
00253 
00254 void Fl_Graphics_Driver::end_polygon() {
00255   fixloop();
00256   if (n < 3) {
00257     fl_end_line();
00258     return;
00259   }
00260 #if defined(USE_X11)
00261   if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, Convex, 0);
00262 #elif defined(WIN32)
00263   if (n>2) {
00264     SelectObject(fl_gc, fl_brush());
00265     Polygon(fl_gc, p, n);
00266   }
00267 #elif defined(__APPLE_QUARTZ__)
00268   if (n<=1) return;
00269   CGContextSetShouldAntialias(fl_gc, true);
00270   CGContextMoveToPoint(fl_gc, p[0].x, p[0].y);
00271   for (int i=1; i<n; i++) 
00272     CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
00273   CGContextClosePath(fl_gc);
00274   CGContextFillPath(fl_gc);
00275   CGContextSetShouldAntialias(fl_gc, false);
00276 #else
00277 # error unsupported platform
00278 #endif
00279 }
00280 
00281 static int gap_;
00282 #if defined(WIN32)
00283 static int counts[20];
00284 static int numcount;
00285 #endif
00286 
00287 void Fl_Graphics_Driver::begin_complex_polygon() {
00288   fl_begin_polygon();
00289   gap_ = 0;
00290 #if defined(WIN32)
00291   numcount = 0;
00292 #endif
00293 }
00294 
00295 void Fl_Graphics_Driver::gap() {
00296   while (n>gap_+2 && p[n-1].x == p[gap_].x && p[n-1].y == p[gap_].y) n--;
00297   if (n > gap_+2) {
00298     fl_transformed_vertex((COORD_T)p[gap_].x, (COORD_T)p[gap_].y);
00299 #if defined(WIN32)
00300     counts[numcount++] = n-gap_;
00301 #endif
00302     gap_ = n;
00303   } else {
00304     n = gap_;
00305   }
00306 }
00307 
00308 void Fl_Graphics_Driver::end_complex_polygon() {
00309   fl_gap();
00310   if (n < 3) {
00311     fl_end_line();
00312     return;
00313   }
00314 #if defined(USE_X11)
00315   if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, 0, 0);
00316 #elif defined(WIN32)
00317   if (n>2) {
00318     SelectObject(fl_gc, fl_brush());
00319     PolyPolygon(fl_gc, p, counts, numcount);
00320   }
00321 #elif defined(__APPLE_QUARTZ__)
00322   if (n<=1) return;
00323   CGContextSetShouldAntialias(fl_gc, true);
00324   CGContextMoveToPoint(fl_gc, p[0].x, p[0].y);
00325   for (int i=1; i<n; i++)
00326     CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
00327   CGContextClosePath(fl_gc);
00328   CGContextFillPath(fl_gc);
00329   CGContextSetShouldAntialias(fl_gc, false);
00330 #else
00331 # error unsupported platform
00332 #endif
00333 }
00334 
00335 // shortcut the closed circles so they use XDrawArc:
00336 // warning: these do not draw rotated ellipses correctly!
00337 // See fl_arc.c for portable version.
00338 
00339 void Fl_Graphics_Driver::circle(double x, double y,double r) {
00340   double xt = fl_transform_x(x,y);
00341   double yt = fl_transform_y(x,y);
00342   double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a));
00343   double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d));
00344   int llx = (int)rint(xt-rx);
00345   int w = (int)rint(xt+rx)-llx;
00346   int lly = (int)rint(yt-ry);
00347   int h = (int)rint(yt+ry)-lly;
00348 
00349 #if defined(USE_X11)
00350   (what == POLYGON ? XFillArc : XDrawArc)
00351     (fl_display, fl_window, fl_gc, llx, lly, w, h, 0, 360*64);
00352 #elif defined(WIN32)
00353   if (what==POLYGON) {
00354     SelectObject(fl_gc, fl_brush());
00355     Pie(fl_gc, llx, lly, llx+w, lly+h, 0,0, 0,0); 
00356   } else
00357     Arc(fl_gc, llx, lly, llx+w, lly+h, 0,0, 0,0); 
00358 #elif defined(__APPLE_QUARTZ__)
00359   // Quartz warning : circle won't scale to current matrix!
00360 //last argument must be 0 (counterclockwise) or it draws nothing under __LP64__ !!!!
00361   CGContextSetShouldAntialias(fl_gc, true);
00362   CGContextAddArc(fl_gc, xt, yt, (w+h)*0.25f, 0, 2.0f*M_PI, 0);
00363   (what == POLYGON ? CGContextFillPath : CGContextStrokePath)(fl_gc);
00364   CGContextSetShouldAntialias(fl_gc, false);
00365 #else
00366 # error unsupported platform
00367 #endif
00368 }
00369 
00370 //
00371 // End of "$Id: fl_vertex.cxx 7903 2010-11-28 21:06:39Z matt $".
00372 //