gxpixmap.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 1999-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Tue Jun 15 11:30:24 1999 (as bitmap.cc)
00010 // commit: $Id: gxpixmap.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/gfx/gxpixmap.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_GFX_GXPIXMAP_CC_UTC20050626084023_DEFINED
00035 #define GROOVX_GFX_GXPIXMAP_CC_UTC20050626084023_DEFINED
00036 
00037 #include "gxpixmap.h"
00038 
00039 #include "geom/rect.h"
00040 #include "geom/vec3.h"
00041 
00042 #include "gfx/bbox.h"
00043 #include "gfx/canvas.h"
00044 #include "gfx/gxaligner.h"
00045 
00046 #include "io/ioproxy.h"
00047 #include "io/reader.h"
00048 #include "io/writer.h"
00049 
00050 #include "media/bmapdata.h"
00051 #include "media/imgfile.h"
00052 #include "media/pnmparser.h"
00053 
00054 #include "rutz/bytearray.h"
00055 #include "rutz/cstrstream.h"
00056 #include "rutz/fstring.h"
00057 #include "rutz/mappedfile.h"
00058 #include "rutz/shared_ptr.h"
00059 
00060 #include "rutz/trace.h"
00061 
00062 using geom::recti;
00063 using geom::rectd;
00064 using geom::vec3d;
00065 using rutz::fstring;
00066 
00067 namespace
00068 {
00069   const geom::vec2<double> defaultZoom(1.0, 1.0);
00070 
00071   const io::version_id BITMAP_SVID = 5;
00072 }
00073 
00075 //
00076 // ImageUpdater class definition
00077 //
00079 
00080 class ImageUpdater : public media::bmap_data::update_func
00081 {
00082 public:
00083   ImageUpdater(const fstring& filename,
00084                fstring& owner_filename,
00085                bool contrast, bool vertical) :
00086     itsFilename(filename),
00087     itsOwnerFilename(owner_filename),
00088     itsFlipContrast(contrast),
00089     itsFlipVertical(vertical)
00090   {
00091     // If the first character of the new filename is '.', then we
00092     // assume it is a temp file, and therefore we don't save this
00093     // filename in itsOwnerFilename.
00094     if ( itsFilename.c_str()[0] != '.' )
00095       {
00096         itsOwnerFilename = itsFilename;
00097       }
00098     else
00099       {
00100         itsOwnerFilename = "";
00101       }
00102   }
00103 
00104   virtual void update(media::bmap_data& update_me);
00105 
00106 private:
00107   fstring itsFilename;
00108   fstring& itsOwnerFilename;
00109   bool itsFlipContrast;
00110   bool itsFlipVertical;
00111 };
00112 
00113 void ImageUpdater::update(media::bmap_data& update_me)
00114 {
00115 GVX_TRACE("ImageUpdater::update");
00116 
00117   try
00118     {
00119       media::load_image(itsFilename.c_str(), update_me);
00120     }
00121   // If there was an error while reading the file, it means we should
00122   // forget about itsOwnerFilename
00123   catch (...)
00124     {
00125       itsOwnerFilename = "";
00126       throw;
00127     }
00128 
00129   if (itsFlipContrast) { update_me.flip_contrast(); }
00130   if (itsFlipVertical) { update_me.flip_vertical(); }
00131 }
00132 
00134 //
00135 // GxPixmapImpl class definition
00136 //
00138 
00139 class GxPixmapImpl
00140 {
00141 public:
00142   GxPixmapImpl() :
00143     itsFilename(),
00144     itsZoom(1.0, 1.0),
00145     itsData(),
00146     itsUsingZoom(false),
00147     itsContrastFlip(false),
00148     itsVerticalFlip(false),
00149     itsPurgeable(false),
00150     itsAsBitmap(false)
00151   {}
00152 
00153   fstring itsFilename;
00154   geom::vec2<double> itsZoom;
00155   mutable media::bmap_data itsData;
00156   bool itsUsingZoom;
00157   bool itsContrastFlip;
00158   bool itsVerticalFlip;
00159   bool itsPurgeable;
00160   bool itsAsBitmap;
00161 
00162   void queueImage(const char* filename)
00163   {
00164     rutz::shared_ptr<media::bmap_data::update_func> updater
00165       (new ImageUpdater(filename,
00166                         itsFilename,
00167                         itsContrastFlip,
00168                         itsVerticalFlip));
00169 
00170     itsData.queue_update(updater);
00171   }
00172 
00173   void purge()
00174   {
00175     if (!itsFilename.is_empty())
00176       {
00177         // NOTE: it's important that this functionality be separate
00178         // from GxPixmap's own version of queueImage(), since that
00179         // function immediately calls sigNodeChanged, which means that
00180         // we notify everyone else that the data have been purged, so
00181         // the bitmap might never have a chance to be drawn on the
00182         // screen
00183 
00184         itsData.clear();
00185 
00186         queueImage(itsFilename.c_str());
00187       }
00188   }
00189 
00190 private:
00191   GxPixmapImpl(const GxPixmapImpl&);
00192   GxPixmapImpl& operator=(const GxPixmapImpl&);
00193 };
00194 
00196 //
00197 // GxPixmap member definitions
00198 //
00200 
00201 GxPixmap::GxPixmap() :
00202   GxShapeKit(),
00203   rep(new GxPixmapImpl)
00204 {
00205 GVX_TRACE("GxPixmap::GxPixmap");
00206   setAlignmentMode(GxAligner::CENTER_ON_CENTER);
00207   setPercentBorder(0);
00208 }
00209 
00210 GxPixmap* GxPixmap::make()
00211 {
00212 GVX_TRACE("GxPixmap::make");
00213   return new GxPixmap;
00214 }
00215 
00216 GxPixmap::~GxPixmap() throw()
00217 {
00218 GVX_TRACE("GxPixmap::~GxPixmap");
00219   delete rep;
00220 }
00221 
00222 io::version_id GxPixmap::class_version_id() const
00223 {
00224 GVX_TRACE("GxPixmap::class_version_id");
00225   return BITMAP_SVID;
00226 }
00227 
00228 void GxPixmap::read_from(io::reader& reader)
00229 {
00230 GVX_TRACE("GxPixmap::read_from");
00231 
00232   int svid = reader.ensure_version_id("GxPixmap", 4,
00233                                       "Try cvs tag xml_conversion_20040526",
00234                                       SRC_POS);
00235 
00236   reader.read_value("filename", rep->itsFilename);
00237   reader.read_value("zoomX", rep->itsZoom.x());
00238   reader.read_value("zoomY", rep->itsZoom.y());
00239   reader.read_value("usingZoom", rep->itsUsingZoom);
00240   reader.read_value("contrastFlip", rep->itsContrastFlip);
00241   reader.read_value("verticalFlip", rep->itsVerticalFlip);
00242   reader.read_value("purgeable", rep->itsPurgeable);
00243   reader.read_value("asBitmap", rep->itsAsBitmap);
00244 
00245   if ( rep->itsFilename.is_empty() )
00246     {
00247       rep->itsData.clear();
00248     }
00249   else
00250     {
00251       queueImage(rep->itsFilename.c_str());
00252     }
00253 
00254   if (svid >= 5)
00255     {
00256 #if 0
00257       rutz::byte_array imgdata;
00258       reader.read_byte_array("image", imgdata);
00259       if (imgdata.vec.size() > 0)
00260         {
00261           rutz::imemstream s(reinterpret_cast<const char*>(&imgdata.vec[0]),
00262                              imgdata.vec.size());
00263           media::load_pnm(s, rep->itsData);
00264         }
00265 #endif
00266     }
00267 
00268   reader.read_base_class("GxShapeKit", io::make_proxy<GxShapeKit>(this));
00269 }
00270 
00271 void GxPixmap::write_to(io::writer& writer) const
00272 {
00273 GVX_TRACE("GxPixmap::write_to");
00274 
00275   writer.ensure_output_version_id("GxPixmap", BITMAP_SVID, 5,
00276                               "Try groovx0.8a7", SRC_POS);
00277 
00278   writer.write_value("filename", rep->itsFilename);
00279   writer.write_value("zoomX", rep->itsZoom.x());
00280   writer.write_value("zoomY", rep->itsZoom.y());
00281   writer.write_value("usingZoom", rep->itsUsingZoom);
00282   writer.write_value("contrastFlip", rep->itsContrastFlip);
00283   writer.write_value("verticalFlip", rep->itsVerticalFlip);
00284   writer.write_value("purgeable", rep->itsPurgeable);
00285   writer.write_value("asBitmap", rep->itsAsBitmap);
00286 
00287 #if 0
00288   if ( !rep->itsFilename.is_empty() )
00289     {
00290       rutz::mapped_file m(rep->itsFilename.c_str());
00291       writer.write_byte_array("image",
00292                           static_cast<const unsigned char*>(m.memory()),
00293                           m.length());
00294     }
00295   else
00296     {
00297       writer.write_byte_array("image", 0, 0);
00298     }
00299 #endif
00300 
00301   writer.write_base_class("GxShapeKit", io::make_const_proxy<GxShapeKit>(this));
00302 }
00303 
00305 // actions //
00307 
00308 void GxPixmap::loadImage(const char* filename)
00309 {
00310 GVX_TRACE("GxPixmap::loadImage");
00311 
00312   media::load_image(filename, rep->itsData);
00313 
00314   rep->itsFilename = filename;
00315 
00316   this->sigNodeChanged.emit();
00317 }
00318 
00319 void GxPixmap::loadImageStream(std::istream& ist)
00320 {
00321 GVX_TRACE("GxPixmap::loadImageStream");
00322 
00323   media::load_pnm(ist, rep->itsData);
00324   rep->itsFilename = "";
00325   this->sigNodeChanged.emit();
00326 }
00327 
00328 void GxPixmap::reload()
00329 {
00330 GVX_TRACE("GxPixmap::reload");
00331 
00332   media::load_image(rep->itsFilename.c_str(), rep->itsData);
00333 
00334   this->sigNodeChanged.emit();
00335 }
00336 
00337 void GxPixmap::queueImage(const char* filename)
00338 {
00339 GVX_TRACE("GxPixmap::queueImage");
00340 
00341   rep->queueImage(filename);
00342 
00343   this->sigNodeChanged.emit();
00344 }
00345 
00346 void GxPixmap::saveImage(const char* filename) const
00347 {
00348 GVX_TRACE("GxPixmap::saveImage");
00349 
00350   media::save_image(filename, rep->itsData);
00351 }
00352 
00353 void GxPixmap::grabScreenRect(nub::soft_ref<Gfx::Canvas> canvas,
00354                               const recti& rect)
00355 {
00356 GVX_TRACE("GxPixmap::grabScreenRect");
00357 
00358   canvas->grabPixels(rect, rep->itsData);
00359 
00360   rep->itsFilename = "";
00361 
00362   rep->itsContrastFlip = false;
00363   rep->itsVerticalFlip = false;
00364   rep->itsZoom = defaultZoom;
00365 
00366   this->sigNodeChanged.emit();
00367 }
00368 
00369 void GxPixmap::grabScreen(nub::soft_ref<Gfx::Canvas> canvas)
00370 {
00371 GVX_TRACE("GxPixmap::grabScreen");
00372 
00373   recti bounds = canvas->getScreenViewport();
00374 
00375   grabScreenRect(canvas, bounds);
00376 }
00377 
00378 void GxPixmap::grabWorldRect(nub::soft_ref<Gfx::Canvas> canvas,
00379                              const rectd& world_rect)
00380 {
00381 GVX_TRACE("GxPixmap::grabWorldRect");
00382 
00383   recti screen_rect = canvas->screenBoundsFromWorldRect(world_rect);
00384 
00385   grabScreenRect(canvas, screen_rect);
00386 
00387   this->sigNodeChanged.emit();
00388 }
00389 
00390 void GxPixmap::flipContrast()
00391 {
00392 GVX_TRACE("GxPixmap::flipContrast");
00393 
00394   // Toggle itsContrastFlip so we keep track of whether the number of
00395   // flips has been even or odd.
00396   rep->itsContrastFlip = !(rep->itsContrastFlip);
00397   rep->itsData.flip_contrast();
00398 
00399   this->sigNodeChanged.emit();
00400 }
00401 
00402 void GxPixmap::flipVertical()
00403 {
00404 GVX_TRACE("GxPixmap::flipVertical");
00405 
00406   rep->itsVerticalFlip = !(rep->itsVerticalFlip);
00407   rep->itsData.flip_vertical();
00408 
00409   this->sigNodeChanged.emit();
00410 }
00411 
00412 void GxPixmap::grRender(Gfx::Canvas& canvas) const
00413 {
00414 GVX_TRACE("GxPixmap::grRender");
00415 
00416   const vec3d world_pos = vec3d::zeros();
00417 
00418   if (rep->itsData.bits_per_pixel() == 1 && rep->itsAsBitmap)
00419     {
00420       canvas.drawBitmap(rep->itsData, world_pos);
00421     }
00422   else
00423     {
00424       canvas.drawPixels(rep->itsData, world_pos, getZoom());
00425     }
00426 
00427   if (isPurgeable())
00428     {
00429       // This const_cast is OK because we aren't changing the
00430       // observable state; we're just re-queuing the current filename
00431       const_cast<GxPixmapImpl*>(rep)->purge();
00432     }
00433 }
00434 
00436 // accessors //
00438 
00439 void GxPixmap::grGetBoundingBox(Gfx::Bbox& bbox) const
00440 {
00441 GVX_TRACE("GxPixmap::grGetBoundingBox");
00442 
00443   bbox.drawScreenRect(vec3d::zeros(),
00444                       this->size(),
00445                       getZoom());
00446 }
00447 
00448 geom::vec2<int> GxPixmap::size() const
00449   { return rep->itsData.size(); }
00450 
00451 geom::vec2<double> GxPixmap::getZoom() const
00452   { return rep->itsUsingZoom ? rep->itsZoom : defaultZoom; }
00453 
00454 bool GxPixmap::getUsingZoom() const
00455   { return rep->itsUsingZoom; }
00456 
00457 bool GxPixmap::isPurgeable() const
00458   { return rep->itsPurgeable; }
00459 
00460 const char* GxPixmap::filename() const
00461   { return rep->itsFilename.c_str(); }
00462 
00463 bool GxPixmap::getAsBitmap() const
00464 {
00465 GVX_TRACE("GxPixmap::getAsBitmap");
00466   return rep->itsAsBitmap;
00467 }
00468 
00469 long int GxPixmap::checkSum() const
00470   { return rep->itsData.bytes_sum(); }
00471 
00473 // manipulators //
00475 
00476 media::bmap_data& GxPixmap::data()
00477 {
00478 GVX_TRACE("GxPixmap::data");
00479   return rep->itsData;
00480 }
00481 
00482 void GxPixmap::setZoom(geom::vec2<double> zoom)
00483 {
00484 GVX_TRACE("GxPixmap::setZoom");
00485   rep->itsZoom = zoom; this->sigNodeChanged.emit();
00486 }
00487 
00488 void GxPixmap::zoomTo(geom::vec2<int> sz)
00489 {
00490 GVX_TRACE("GxPixmap::zoomTo");
00491   double x_ratio = double(sz.x()) / rep->itsData.width();
00492   double y_ratio = double(sz.y()) / rep->itsData.height();
00493   double ratio = rutz::min(x_ratio, y_ratio);
00494   setUsingZoom(true);
00495   setZoom(geom::vec2<double>(ratio, ratio));
00496 }
00497 
00498 void GxPixmap::setUsingZoom(bool val)
00499 {
00500 GVX_TRACE("GxPixmap::setUsingZoom");
00501   rep->itsUsingZoom = val;
00502 
00503   // glPixelZoom() does not work with glBitmap()
00504   if (rep->itsUsingZoom)
00505     rep->itsAsBitmap = false;
00506 
00507   this->sigNodeChanged.emit();
00508 }
00509 
00510 void GxPixmap::setPurgeable(bool val)
00511 {
00512 GVX_TRACE("GxPixmap::setPurgeable");
00513   rep->itsPurgeable = val; this->sigNodeChanged.emit();
00514 }
00515 
00516 void GxPixmap::setAsBitmap(bool val)
00517 {
00518 GVX_TRACE("GxPixmap::setAsBitmap");
00519   rep->itsAsBitmap = val;
00520 
00521   // glPixelZoom() does not work with glBitmap()
00522   if (rep->itsAsBitmap)
00523     rep->itsUsingZoom = false;
00524 
00525   this->sigNodeChanged.emit();
00526 }
00527 
00528 void GxPixmap::scramble(int numsubcols, int numsubrows, int seed,
00529                         bool allowMoveSubparts,
00530                         bool allowFlipLeftRight,
00531                         bool allowFlipTopBottom)
00532 {
00533 GVX_TRACE("GxPixmap::scramble");
00534 
00535   rutz::shared_ptr<media::bmap_data> newdata =
00536     rep->itsData.make_scrambled(numsubcols, numsubrows, seed,
00537                                 allowMoveSubparts,
00538                                 allowFlipLeftRight,
00539                                 allowFlipTopBottom);
00540 
00541   rep->itsData.swap(*newdata);
00542 
00543   this->sigNodeChanged.emit();
00544 }
00545 
00546 static const char __attribute__((used)) vcid_groovx_gfx_gxpixmap_cc_utc20050626084023[] = "$Id: gxpixmap.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00547 #endif // !GROOVX_GFX_GXPIXMAP_CC_UTC20050626084023_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:38 2008 by Doxygen version 1.5.5.