painter.cpp

Go to the documentation of this file.
00001 /*
00002   libwt - Vassilis Virvilis Toolkit - a widget library
00003   Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm>
00004   Copyright (C) 2002 Malcolm Walker <malcolm@worldforge.org>
00005   Based on code copyright  (C) 1999-2002  Karsten Laux
00006  
00007   This library is free software; you can redistribute it and/or
00008   modify it under the terms of the GNU Lesser General Public
00009   License as published by the Free Software Foundation; either
00010   version 2.1 of the License, or (at your option) any later version.
00011   
00012   This library is distributed in the hope that it will be useful,
00013   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015   Lesser General Public License for more details.
00016   
00017   You should have received a copy of the GNU Lesser General Public
00018   License along with this library; if not, write to the
00019   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020   Boston, MA  02111-1307, SA.
00021 */
00022 // originally written by Karsten Laux, June 1999
00023 
00024 #include <wt/painter.h>
00025 #include <wt/pixmap.h>
00026 #include <wt/color.h>
00027 #include <wt/rect.h>
00028 #include <wt/region.h>
00029 #include <wt/rootwindow.h>
00030 #include <wt/trace.h>
00031 
00032 namespace Wt {
00033 
00034 Painter::Painter(const Pixmap* pixmap, bool clipping) :
00035         active_(false),
00036 pixmap_(const_cast<Pixmap *>(pixmap)) {
00037     begin(pixmap_, clipping);
00038 }
00039 
00040 Painter::~Painter() {
00041     end();
00042 }
00043 
00044 bool Painter::begin(const Pixmap* pixmap, bool clipping) {
00045     bool status = false;
00046     if (!active_) {
00047         pixmap_ = const_cast<Pixmap *>(pixmap);
00048         if (pixmap_ && *pixmap_) {
00049             setClipping(clipping);
00050             active_ = true;
00051             status = true;
00052         }
00053     }
00054     return status;
00055 }
00056 
00057 bool Painter::begin() {
00058     return begin(pixmap_);
00059 }
00060 
00061 bool Painter::end() {
00062     bool status = false;
00063     if (active_) {
00064         while (!state_stack.empty()) {
00065             restore();
00066         }
00067         active_ = false;
00068         status = true;
00069     }
00070     return status;
00071 }
00072 
00073 bool Painter::isActive () const {
00074     return active_;
00075 }
00076 
00077 bool Painter::isClipped(int x, int y) const {
00078     return !isActive() || (state.clipping && !pixmap_->rect().contains(x, y));
00079 }
00080 
00081 bool Painter::isClipped(const Point& p) const {
00082     return isClipped(p.x(), p.y());
00083 }
00084 
00085 void Painter::rop(int pixel_offset, int pixel) {
00086     switch(state.raster_op) {
00087     case CopyROP:
00088         pixmap_->setPixel(pixel_offset, pixel);
00089         break;
00090     case XorROP:
00091         pixel = pixel ^ pixmap_->pixel(pixel_offset);
00092         pixmap_->setPixel(pixel_offset, pixel);
00093         break;
00094     case AndROP:
00095         pixel = pixel & pixmap_->pixel(pixel_offset);
00096         pixmap_->setPixel(pixel_offset, pixel);
00097         break;
00098     case OrROP:
00099         pixel = pixel | pixmap_->pixel(pixel_offset);
00100         pixmap_->setPixel(pixel_offset, pixel);
00101         break;
00102     default:
00103         Warn("Unknown Raster Operation %d\n", state.raster_op);
00104         pixmap_->setPixel(pixel_offset, pixel);
00105         break;
00106     }
00107 }
00108 
00109 void Painter::drawPoint(int x, int y) {
00110     if (!isClipped(x, y)) {
00111         int pixel_offset = pixmap_->pixelOffset(x, y);
00112         int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color());
00113 
00114         pixmap_->lock()
00115         ;
00116         rop(pixel_offset, pixel);
00117         pixmap_->unlock();
00118     }
00119 }
00120 
00121 void Painter::drawPoint(const Point& p) {
00122     drawPoint(p.x(), p.y());
00123 }
00124 
00125 void Painter::drawPoints(const PointArray& points, int start, int end) {
00126     int i;
00127     int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color());
00128 
00129     end = (end > 0) ? end : points.size();
00130 
00131     pixmap_->lock()
00132     ;
00133     for (i = start; i < end; i++) {
00134         const Point& p = points[i];
00135         if (!isClipped(p)) {
00136             int pixel_offset = pixmap_->pixelOffset(p.x(), p.y());
00137             rop(pixel_offset, pixel);
00138         }
00139     }
00140     pixmap_->unlock();
00141 }
00142 
00143 void Painter::drawHorizontalLine(int x1, int x2, int y) {
00144     if(!isActive() || y < 0 || y >= pixmap_->height())
00145         return;
00146 
00147     int w = pixmap_->width();
00148 
00149     if (state.clipping) {
00150         x1 = std::max(0, x1);
00151         x1 = std::min(x1, w - 1);
00152         x2 = std::max(0, x2);
00153         x2 = std::min(x2, w - 1);
00154     }
00155 
00156     if (x1 > x2)
00157         std::swap(x1, x2);
00158 
00159     int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color());
00160     int pixel_offset = pixmap_->pixelOffset(x1, y);
00161     int skip = pixmap_->pixelFormat().bytesPerPixel();
00162 
00163     pixmap_->lock()
00164     ;
00165     while(x1 <= x2) {
00166         rop(pixel_offset, pixel);
00167         x1++;
00168         pixel_offset += skip;
00169     }
00170     pixmap_->unlock();
00171 
00172 }
00173 
00174 void Painter::drawVerticalLine(int x, int y1, int y2) {
00175     if(!isActive() || x < 0 || x >= pixmap_->width())
00176         return;
00177 
00178     int h = pixmap_->height();
00179 
00180     if (state.clipping) {
00181         y1 = std::max(0, y1);
00182         y1 = std::min(y1, h - 1);
00183         y2 = std::max(0, y2);
00184         y2 = std::min(y2, h - 1);
00185     }
00186 
00187     if (y1 > y2)
00188         std::swap(y1, y2);
00189 
00190     int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color());
00191     int pixel_offset = pixmap_->pixelOffset(x, y1);
00192     int skip = pixmap_->bytesPerLine();
00193 
00194     pixmap_->lock()
00195     ;
00196     while(y1 <= y2) {
00197         rop(pixel_offset, pixel);
00198         y1++;
00199         pixel_offset += skip;
00200     }
00201     pixmap_->unlock();
00202 }
00203 
00204 void Painter::drawLine(int x1, int y1, int x2, int y2) {
00205     if(!isActive())
00206         return;
00207 
00208     int dx, dy, sdx, sdy, x, y, px, py;
00209 
00210     dx = x2 - x1;
00211     dy = y2 - y1;
00212 
00213     //check if we may optimize to either vLine or hLine ...
00214     if(dx == 0) {
00215         //this is a vertical line, call vLine and return
00216         drawVerticalLine(x1, y1, y2);
00217         return;
00218     }
00219     if(dy == 0) {
00220         //this is a horizontal line, call hLine and return
00221         drawHorizontalLine(x1, x2, y1);
00222         return;
00223     }
00224 
00225     // if clipping is enabled x1, y1, x2, y2 are the clipped values
00226     if (state.clipping && !pixmap_->rect().clipLine(x1, y1, x2, y2)) {
00227         dx = x2 - x1;
00228         dy = y2 - y1;
00229         return;
00230     }
00231 
00232     // here comes the hard job ... bresenham:
00233 
00234     sdx = (dx < 0) ? -1 : 1;
00235     sdy = (dy < 0) ? -1 : 1;
00236 
00237     dx = sdx * dx + 1;
00238     dy = sdy * dy + 1;
00239 
00240     x = y = 0;
00241 
00242     px = x1;
00243     py = y1;
00244 
00245     // map the color to the appropriate bit pattern to write ...
00246     int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color());
00247     int pixel_offset;
00248 
00249     /// \todo the calculation of the pixel_offset could be reduced to addings ...
00250     /// no multiplies are needed in fact
00251     pixmap_->lock()
00252     ;
00253     if (dx >= dy) {
00254         for (x = 0; x < dx; x++) {
00255             pixel_offset = pixmap_->pixelOffset(px, py);
00256             rop(pixel_offset, pixel);
00257 
00258             y += dy;
00259             if (y >= dx) {
00260                 y -= dx;
00261                 py += sdy;
00262             }
00263             px += sdx;
00264         }
00265     } else {
00266         for (y = 0; y < dy; y++) {
00267             pixel_offset = pixmap_->pixelOffset(px, py);
00268             rop(pixel_offset, pixel);
00269 
00270             x += dx;
00271             if (x >= dy) {
00272                 x -= dy;
00273                 px += sdx;
00274             }
00275             py += sdy;
00276         }
00277     }
00278     pixmap_->unlock();
00279 }
00280 
00281 void Painter::drawLine(const Point& p1, const Point& p2) {
00282     drawLine(p1.x(), p1.y(), p2.x(), p2.y());
00283 }
00284 
00285 void Painter::fillRect(const Rect& r, const Brush& brush) {
00286     if (brush.style() == Brush::NoBrush)
00287         return;
00288 
00289     pixmap_->fill(r, brush.color());
00290 }
00291 
00292 void Painter::fillRect(int x, int y, int w, int h, const Brush& brush) {
00293     fillRect(Rect(x, y, w, h), brush);
00294 }
00295 
00296 void Painter::fillRegion(const Region& r, const Brush& brush) {
00297     if (brush.style() == Brush::NoBrush)
00298         return;
00299 
00300     pixmap_->fill(r, brush.color());
00301 }
00302 
00303 void Painter::blendRect(const Rect& r, const Brush& brush) {
00304     if (brush.style() == Brush::NoBrush)
00305         return;
00306 
00307     pixmap_->blend(r, brush.color());
00308 }
00309 
00310 void Painter::blendRect(int x, int y, int w, int h, const Brush& brush) {
00311     blendRect(Rect(x, y, w, h), brush);
00312 }
00313 
00314 void Painter::blendRegion(const Region& r, const Brush& brush) {
00315     if (brush.style() == Brush::NoBrush)
00316         return;
00317 
00318     pixmap_->blend(r, brush.color());
00319 }
00320 
00321 void Painter::eraseRect(const Rect& r) {
00322     fillRect(r, state.bg_color);
00323 }
00324 
00325 void Painter::eraseRect(int x, int y, int w, int h) {
00326     eraseRect(Rect(x, y, w, h));
00327 }
00328 
00329 void Painter::eraseRegion(const Region& r) {
00330     fillRegion(r, state.bg_color);
00331 }
00332 
00333 void Painter::drawRect(int x, int y, int w, int h) {
00334     int x2 = x + w - 1;
00335     int y2 = y + h - 1;
00336 
00337     drawHorizontalLine(x, x2, y);
00338     drawVerticalLine(x, y, y2);
00339     drawHorizontalLine(x, x2, y2);
00340     drawVerticalLine(x2, y, y2);
00341 
00342     if (state.brush.style() != Brush::NoBrush) {
00343         fillRect(x + 1, y + 1, w - 1, h - 1, state.brush);
00344     }
00345 }
00346 
00347 void Painter::drawRect(const Rect& r)  {
00348     drawRect(r.left(), r.top(), r.width(), r.height());
00349 }
00350 
00351 void Painter::drawLineSegments(const PointArray& points, int start, int end) {
00352     int i;
00353     end = (end > 0) ? end : points.size();
00354 
00355     for (i = start; i < end - 1; i += 2) {
00356         drawLine(points[i], points[i + 1]);
00357     }
00358 }
00359 
00360 void Painter::drawPolyline(const PointArray& points, int start, int end) {
00361     int i;
00362     end = (end > 0) ? end : points.size();
00363 
00364     for (i = start; i < end; i++) {
00365         drawLine(points[i], points[i + 1]);
00366     }
00367 }
00368 
00369 void Painter::drawPolygon(const PointArray& points, int start, int end) {
00370     int i;
00371     end = (end > 0) ? end : points.size();
00372 
00373     for (i = start; i < end; i++) {
00374         drawLine(points[i], points[i + 1 % end]);
00375     }
00376 
00377     if (state.brush.style() != Brush::NoBrush) {
00378         /// \todo we have to actually fill the damn thing
00379     }
00380 }
00381 
00382 void Painter::drawPixmap(const Point& p, const Pixmap& src, const Rect& sr) {
00383     pixmap_->blit(p.x(), p.y(), src, sr);
00384 }
00385 
00386 void Painter::drawPixmap(const Point& p, const Pixmap& src) {
00387     pixmap_->blit(p.x(), p.y(), src);
00388 }
00389 
00390 void Painter::drawPixmap(int x, int y, const Pixmap& src, int sx, int sy, int sw, int sh) {
00391     pixmap_->blit(x, y, src, Rect(sx, sy, sw, sh));
00392 }
00393 
00394 void Painter::drawPixmap(const Rect& r, const Pixmap& src) {
00395     pixmap_->blit(r.topLeft(), src.scale(r.size()));
00396 }
00397 
00398 void Painter::drawTiledPixmap(const Rect& r,
00399                               const Pixmap& src, const Point& sp) {
00400 
00401     int src_w = src.width();
00402     int src_h = src.height();
00403     int dst_w = r.width();
00404     int dst_h = r.height();
00405     int x, y, w;
00406     int h = src_h - sp.y();
00407     Rect dst_rect(0, 0, 0, h);
00408     Rect src_rect(sp, Size(0, h));
00409 
00410     trace("painter") << "Tiling a " << Size(src_w, src_h)
00411     << " background onto a " << Size(dst_w, dst_h) << " surface" << std::endl;
00412 
00413     for(y = r.top(); y <= r.bottom(); y += h) {
00414         dst_rect.setY(y);
00415         w = src_w - sp.x();
00416         dst_rect.setWidth(w);
00417         src_rect.setWidth(w);
00418         for(x = r.left(); x <= r.right(); x += w) {
00419             dst_rect.setX(x);
00420             trace("painter")  << "Blitting tile at " << dst_rect.topLeft() << std::endl;
00421             pixmap_->blit(dst_rect.topLeft(), src, src_rect);
00422             w = src_w;
00423             dst_rect.setWidth(w);
00424             src_rect.setWidth(w);
00425         }
00426         h = src_h;
00427         dst_rect.setHeight(h);
00428         src_rect.setHeight(h);
00429     }
00430 }
00431 
00432 void Painter::drawTiledPixmap(const Rect& r, const Pixmap& src) {
00433     drawTiledPixmap(r, src, Point(0, 0));
00434 }
00435 
00436 void Painter::drawTiledPixmap(int x, int y, int w, int h,
00437                               const Pixmap& src, int sx, int sy) {
00438     drawTiledPixmap(Rect(x, y, w, h), src, Point(sx, sy));
00439 }
00440 
00441 void Painter::drawText(const Point& p, const std::string& text, int len) {
00442     const std::string& t = (len == -1) ? text : text.substr(0, len);
00443     const Point p1 = p - Point(0, state.font.ascent());
00444 
00445     if (state.bg_color.alpha() != Color::Transparent) {
00446         pixmap_->blit(p1, state.font.blitText(t));
00447     } else {
00448         pixmap_->blitAlphaCopy(p1, state.font.blitText(t));
00449     }
00450 }
00451 
00452 void Painter::drawText(int x, int y, const std::string& text, int len) {
00453     drawText(Point(x, y), text, len);
00454 }
00455 
00456 void Painter::drawText(const Point& p,
00457                        const std::string& text, int pos, int len) {
00458     len = (len - 1) ? text.length() : len;
00459     const std::string& t = text.substr(pos, len);
00460     drawText(p, t);
00461 }
00462 
00463 void Painter::drawText(int x, int y,
00464                        const std::string& text, int pos, int len) {
00465     drawText(Point(x, y), text, pos, len);
00466 }
00467 
00468 Rect Painter::boundingRect(const std::string& text, int pos, int len) {
00469     len = (len - 1) ? text.length() : len;
00470     return state.font.boundingRect(text.substr(pos, len));
00471 }
00472 
00473 #if 0
00474 
00475 void
00476 Painter::circle(const Point& c, unsigned int r, unsigned int t) {
00477     if(fill_)
00478         ellipseFill(c,r,r);
00479     else
00480         ellipse(c,r,r,t);
00481 }
00482 
00483 void
00484 Painter::ellipse(const Point& c,
00485                  unsigned int rx, unsigned int ry, unsigned int t) {
00486     if(!pixmap_ || pixmap_->empty())
00487         return;
00488     if(rx == 0 || ry == 0)
00489         return;
00490 
00491     if(fill_) {
00492         ellipseFill(c,rx,ry);
00493         return;
00494     }
00495 
00496     int steps = 3 * (rx > ry) ? rx : ry;
00497 
00498     float alpha = 0;
00499     float delta = M_PI/2/steps;
00500 
00501     Point p;
00502     Point v;
00503     int pixel_offset;
00504 
00505     int pixel = pixmap_->pixelformat().mapToPixel(color_);
00506 
00507     pixmap_->lock()
00508     ;
00509 
00510     while(steps > 0) {
00511         v.x = (int)(rx * cos(alpha));
00512         v.y = (int)(ry * sin(alpha));
00513 
00514         p.x = c.x + v.x;
00515         p.y = c.y + v.y;
00516 
00517         if(Rect(0,0, pixmap_->width(), pixmap_->height()).contains(p)) {
00518             pixel_offset=pixmap_->pixelformat().bpp()*p.x +pixmap_->pitch()*p.y;
00519             for(unsigned int i=0; i < t; i++) {
00520                 writePixel(pixel_offset, pixel);
00521                 pixel_offset++;
00522             }
00523         }
00524 
00525         v.x = -v.x;
00526         p.x = c.x + v.x;
00527 
00528         if(Rect(0,0, pixmap_->width(), pixmap_->height()).contains(p)) {
00529             pixel_offset=pixmap_->pixelformat().bpp()*p.x +surface_->pitch()*p.y;
00530             for(unsigned int i=0; i < t; i++) {
00531                 writePixel(pixel_offset, pixel);
00532                 pixel_offset++;
00533             }
00534         }
00535 
00536         v.y = -v.y;
00537         p.y = c.y + v.y;
00538         if(Rect(0,0, surface_->width(), surface_->height()).contains(p)) {
00539             pixel_offset=surface_->pixelformat().bpp()*p.x +surface_->pitch()*p.y;
00540             for(unsigned int i=0; i < t; i++) {
00541                 writePixel(pixel_offset, pixel);
00542                 pixel_offset++;
00543             }
00544         }
00545 
00546         v.x = -v.x;
00547         p.x = c.x + v.x;
00548         if(Rect(0,0, surface_->width(), surface_->height()).contains(p)) {
00549             pixel_offset=surface_->pixelformat().bpp()*p.x +surface_->pitch()*p.y;
00550             for(unsigned int i=0; i < t; i++) {
00551                 writePixel(pixel_offset, pixel);
00552                 pixel_offset++;
00553             }
00554         }
00555 
00556         alpha = alpha + delta;
00557         steps--;
00558     }
00559 
00560 
00561     surface_->unlock();
00562 }
00563 
00564 
00565 void
00566 Painter::ellipseFill(const Point& c,
00567                      unsigned int rx, unsigned int ry) {
00568     if(!surface_ || surface_->empty())
00569         return;
00570     if(rx == 0 || ry == 0)
00571         return;
00572     unsigned int steps = 0;
00573 
00574     Point p1;
00575     Point p2;
00576     Point v;
00577 
00578     while(steps < ry) {
00579 
00580         v.x = (int)(rx * cos(asin((double)steps/ry)));
00581 
00582         p1.x = c.x - v.x;
00583         p1.y = c.y - steps;
00584 
00585         p2.x = c.x + v.x;
00586         p2.y = c.y - steps;
00587 
00588         hLine(p1,p2,color_);
00589 
00590 
00591         p1.x = c.x - v.x;
00592         p1.y = c.y + steps;
00593 
00594         p2.x = c.x + v.x;
00595         p2.y = c.y + steps;
00596 
00597         hLine(p1,p2,color_);
00598 
00599         steps++;
00600     }
00601 }
00602 
00603 #endif
00604 
00605 } //namespace Wt

Generated Fri Jul 28 19:23:00 2006.
Copyright © 1998-2003 by the respective authors.

This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.