00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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
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
00092
00093
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
00122
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
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
00178
00179
00180
00181
00182
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
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
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
00395
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
00430
00431 const_cast<GxPixmapImpl*>(rep)->purge();
00432 }
00433 }
00434
00436
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
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
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
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