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_MEDIA_BMAPDATA_CC_UTC20050626084018_DEFINED
00035 #define GROOVX_MEDIA_BMAPDATA_CC_UTC20050626084018_DEFINED
00036
00037 #include "bmapdata.h"
00038
00039 #include "geom/vec2.h"
00040
00041 #include "rutz/algo.h"
00042 #include "rutz/arrays.h"
00043 #include "rutz/error.h"
00044 #include "rutz/rand.h"
00045 #include "rutz/sfmt.h"
00046 #include "rutz/shared_ptr.h"
00047
00048 #include <algorithm>
00049 #include <cstring>
00050
00051 #include "rutz/trace.h"
00052 #include "rutz/debug.h"
00053 GVX_DBG_REGISTER
00054
00055 using rutz::shared_ptr;
00056
00058
00059
00060
00062
00063 class media::bmap_data::impl
00064 {
00065 public:
00066 impl(const geom::vec2<int>& ex, int bits_per_pixel, int byte_alignment) :
00067 m_size(ex),
00068 m_bits_per_pixel(bits_per_pixel),
00069 m_byte_alignment(byte_alignment),
00070 m_bytes(),
00071 m_row_order(TOP_FIRST),
00072 m_updater()
00073 {
00074 GVX_PRECONDITION(m_size.x() >= 0);
00075 GVX_PRECONDITION(m_size.y() >= 0);
00076
00077
00078
00079 int bytes_per_row = (m_size.x()*bits_per_pixel - 1)/8 + 1;
00080
00081 GVX_ASSERT(bytes_per_row >= 0);
00082
00083 unsigned int num_bytes = bytes_per_row * m_size.y();
00084
00085 m_bytes.resize( num_bytes );
00086 }
00087
00088
00089
00090
00091
00092
00093
00094 unsigned char* bytes_ptr() { return &(m_bytes[0]); }
00095
00096 unsigned int bytes_per_row() const
00097 { return ( (m_size.x()*m_bits_per_pixel - 1)/8 + 1 ); }
00098
00099 unsigned char* row_ptr(unsigned int row)
00100 {
00101 const unsigned int offset =
00102 (m_row_order == TOP_FIRST)
00103 ?
00104 row
00105 :
00106 m_size.y() - row - 1;
00107
00108 return bytes_ptr() + offset * bytes_per_row();
00109 }
00110
00111 unsigned int byte_count() const { return m_bytes.size(); }
00112
00113 geom::vec2<int> m_size;
00114 int m_bits_per_pixel;
00115 int m_byte_alignment;
00116 rutz::dynamic_block<unsigned char> m_bytes;
00117 row_order m_row_order;
00118 mutable shared_ptr<update_func> m_updater;
00119 };
00120
00122
00123
00124
00126
00127 media::bmap_data::update_func::~update_func() {}
00128
00129 media::bmap_data::bmap_data() :
00130 rep(new impl(geom::vec2<int>(0, 0), 1, 1))
00131 {
00132 GVX_TRACE("media::bmap_data::bmap_data");
00133 }
00134
00135 media::bmap_data::bmap_data(const geom::vec2<int>& m_size,
00136 int bits_per_pixel, int byte_alignment) :
00137 rep(new impl(m_size, bits_per_pixel, byte_alignment))
00138 {
00139 GVX_TRACE("media::bmap_data::bmap_data");
00140 }
00141
00142 media::bmap_data::bmap_data(const media::bmap_data& other) :
00143 rep(new impl(*(other.rep)))
00144 {
00145 GVX_TRACE("media::bmap_data::bmap_data(copy)");
00146 }
00147
00148 media::bmap_data::~bmap_data()
00149 {
00150 delete rep;
00151 }
00152
00153 unsigned char* media::bmap_data::bytes_ptr() const
00154 {
00155 GVX_TRACE("media::bmap_data::bytes_ptr");
00156 update_if_needed();
00157 return rep->bytes_ptr();
00158 }
00159
00160 unsigned char* media::bmap_data::row_ptr(unsigned int row) const
00161 {
00162 GVX_TRACE("media::bmap_data::row_ptr");
00163
00164 update_if_needed();
00165
00166 return rep->row_ptr(row);
00167 }
00168
00169 long int media::bmap_data::bytes_sum() const
00170 {
00171 GVX_TRACE("media::bmap_data::bytes_sum");
00172
00173 update_if_needed();
00174 long int sum = 0;
00175 unsigned int c = byte_count();
00176 unsigned char* m_bytes = rep->bytes_ptr();
00177 while (c > 0)
00178 {
00179 sum += m_bytes[--c];
00180 }
00181 return sum;
00182 }
00183
00184 int media::bmap_data::width() const
00185 {
00186 GVX_TRACE("media::bmap_data::width");
00187 update_if_needed();
00188 return rep->m_size.x();
00189 }
00190
00191 int media::bmap_data::height() const
00192 {
00193 GVX_TRACE("media::bmap_data::height");
00194 update_if_needed();
00195 return rep->m_size.y();
00196 }
00197
00198 geom::vec2<int> media::bmap_data::size() const
00199 {
00200 GVX_TRACE("media::bmap_data::size");
00201 update_if_needed();
00202 return rep->m_size;
00203 }
00204
00205 int media::bmap_data::bits_per_pixel() const
00206 {
00207 GVX_TRACE("media::bmap_data::bits_per_pixel");
00208 update_if_needed();
00209 return rep->m_bits_per_pixel;
00210 }
00211
00212 int media::bmap_data::bits_per_component() const
00213 {
00214 GVX_TRACE("media::bmap_data::bits_per_component");
00215 update_if_needed();
00216 return rep->m_bits_per_pixel > 1
00217 ? 8
00218 : 1;
00219 }
00220
00221 int media::bmap_data::byte_alignment() const
00222 {
00223 GVX_TRACE("media::bmap_data::byte_alignment");
00224 update_if_needed();
00225 return rep->m_byte_alignment;
00226 }
00227
00228 unsigned int media::bmap_data::byte_count() const
00229 {
00230 GVX_TRACE("media::bmap_data::byte_count");
00231 update_if_needed();
00232
00233 GVX_ASSERT(rep->m_bytes.size() == rep->bytes_per_row() * rep->m_size.y());
00234
00235 return rep->byte_count();
00236 }
00237
00238 unsigned int media::bmap_data::bytes_per_row() const
00239 {
00240 GVX_TRACE("media::bmap_data::bytes_per_row");
00241 update_if_needed();
00242 return rep->bytes_per_row();
00243 }
00244
00245 media::bmap_data::row_order
00246 media::bmap_data::get_row_order() const
00247 {
00248 return rep->m_row_order;
00249 }
00250
00251 void media::bmap_data::flip_contrast()
00252 {
00253 GVX_TRACE("media::bmap_data::flip_contrast");
00254 update_if_needed();
00255
00256 unsigned int num_bytes = rep->m_bytes.size();
00257
00258
00259 if (rep->m_bits_per_pixel == 1)
00260 {
00261 for (unsigned int i = 0; i < num_bytes; ++i)
00262 {
00263 rep->m_bytes[i] =
00264 static_cast<unsigned char>(0xff ^ rep->m_bytes[i]);
00265 }
00266 }
00267
00268
00269 else
00270 {
00271 for (unsigned int i = 0; i < num_bytes; ++i)
00272 {
00273 rep->m_bytes[i] =
00274 static_cast<unsigned char>(0xff - rep->m_bytes[i]);
00275 }
00276 }
00277 }
00278
00279 void media::bmap_data::flip_vertical()
00280 {
00281 GVX_TRACE("media::bmap_data::flip_vertical");
00282 update_if_needed();
00283
00284 int bytes_per_row = rep->bytes_per_row();
00285 int num_bytes = rep->byte_count();
00286
00287 rutz::dynamic_block<unsigned char> new_bytes(num_bytes);
00288
00289 for (int row = 0; row < rep->m_size.y(); ++row)
00290 {
00291 int new_row = (rep->m_size.y()-1)-row;
00292 memcpy(static_cast<void*> (&(new_bytes [new_row * bytes_per_row])),
00293 static_cast<void*> (&(rep->m_bytes[row * bytes_per_row])),
00294 bytes_per_row);
00295 }
00296
00297 rep->m_bytes.swap(new_bytes);
00298 }
00299
00300 void media::bmap_data::clear()
00301 {
00302 GVX_TRACE("media::bmap_data::clear");
00303
00304 media::bmap_data empty;
00305 swap(empty);
00306 }
00307
00308 void media::bmap_data::swap(media::bmap_data& other)
00309 {
00310 GVX_TRACE("media::bmap_data::swap");
00311
00312 rutz::swap2(rep, other.rep);
00313 }
00314
00315 void media::bmap_data::queue_update(shared_ptr<update_func> updater) const
00316 {
00317 GVX_TRACE("media::bmap_data::queue_update");
00318 rep->m_updater = updater;
00319 }
00320
00321 void media::bmap_data::update_if_needed() const
00322 {
00323 GVX_TRACE("media::bmap_data::update_if_needed");
00324 if (rep->m_updater.get() != 0)
00325 {
00326 shared_ptr<update_func> tmp_updater(rep->m_updater);
00327
00328
00329
00330
00331 rep->m_updater.reset();
00332
00333 tmp_updater->update(const_cast<media::bmap_data&>(*this));
00334 }
00335 }
00336
00337 void media::bmap_data::clear_queued_update() const
00338 {
00339 GVX_TRACE("media::bmap_data::clear_queued_update");
00340 rep->m_updater.reset();
00341 }
00342
00343 void media::bmap_data::set_row_order(row_order order) const
00344 {
00345 if (order != rep->m_row_order)
00346 {
00347 const_cast<bmap_data*>(this)->flip_vertical();
00348 rep->m_row_order = order;
00349 }
00350 }
00351
00352 void media::bmap_data::specify_row_order(row_order order) const
00353 {
00354 rep->m_row_order = order;
00355 }
00356
00357 shared_ptr<media::bmap_data>
00358 media::bmap_data::make_scrambled(int nsubimg_x, int nsubimg_y, int seed,
00359 bool allow_move_subparts,
00360 bool allow_flip_left_right,
00361 bool allow_flip_top_bottom) const
00362 {
00363 GVX_TRACE("media::bmap_data::make_scrambled");
00364
00365 update_if_needed();
00366
00367 if ( width() % nsubimg_x != 0 )
00368 {
00369 throw rutz::error("not an evenly divisible width", SRC_POS);
00370 }
00371
00372 if ( height() % nsubimg_y != 0 )
00373 {
00374 throw rutz::error("not an evenly divisible width", SRC_POS);
00375 }
00376
00377 shared_ptr<media::bmap_data> result
00378 (new media::bmap_data(this->size(),
00379 this->bits_per_pixel(),
00380 this->byte_alignment()));
00381
00382 const int npos = nsubimg_x * nsubimg_y;
00383
00384 rutz::fixed_block<int> newpos(npos);
00385 for (int i = 0; i < npos; ++i)
00386 {
00387 newpos[i] = i;
00388 }
00389
00390 rutz::urand generator(seed);
00391
00392 if (allow_move_subparts)
00393 {
00394 std::random_shuffle(newpos.begin(), newpos.end(), generator);
00395 }
00396
00397 if (rep->m_bits_per_pixel != 8 && rep->m_bits_per_pixel != 24)
00398 {
00399 throw rutz::error(rutz::sfmt("unknown bits-per-pixel value: %d",
00400 rep->m_bits_per_pixel), SRC_POS);
00401 }
00402
00403 const int bytes_per_pixel = rep->m_bits_per_pixel/8;
00404
00405 const int size_subimg_x = result->width() / nsubimg_x * bytes_per_pixel;
00406 const int size_subimg_y = result->height() / nsubimg_y;
00407
00408 for (int i = 0; i < npos; ++i)
00409 {
00410 const bool fliplr = allow_flip_left_right && generator.booldraw();
00411 const bool fliptb = allow_flip_top_bottom && generator.booldraw();
00412
00413 const int src_subimg_y = i / nsubimg_x;
00414 const int src_subimg_x = i % nsubimg_x;
00415
00416 const int src_fullimg_y = src_subimg_y * size_subimg_y;
00417 const int src_fullimg_x = src_subimg_x * size_subimg_x;
00418
00419 const int dst_subimg_y = newpos[i] / nsubimg_x;
00420 const int dst_subimg_x = newpos[i] % nsubimg_x;
00421
00422 const int dst_fullimg_y = dst_subimg_y * size_subimg_y;
00423 const int dst_fullimg_x = dst_subimg_x * size_subimg_x;
00424
00425 for (int y = 0; y < size_subimg_y; ++y)
00426 {
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 const unsigned char* src =
00440 rep->row_ptr(src_fullimg_y+y) + src_fullimg_x;
00441
00442 const unsigned int dst_row =
00443 fliptb
00444 ? dst_fullimg_y+size_subimg_y-1-y
00445 : dst_fullimg_y+y;
00446
00447 unsigned char* dst =
00448 result->rep->row_ptr(dst_row) + dst_fullimg_x;
00449
00450 unsigned char* dst_end = dst + size_subimg_x;
00451
00452 if (fliplr)
00453 {
00454 if (bytes_per_pixel == 1)
00455 while (dst_end != dst) { *--dst_end = *src++; }
00456 else if (bytes_per_pixel == 3)
00457 while (dst_end != dst)
00458 {
00459 *(dst_end-3) = *src++;
00460 *(dst_end-2) = *src++;
00461 *(dst_end-1) = *src++;
00462 dst_end -= 3;
00463 }
00464 else
00465 {
00466 GVX_ASSERT(0);
00467 }
00468 }
00469 else
00470 {
00471 while (dst != dst_end) { *dst++ = *src++; }
00472 }
00473 }
00474 }
00475
00476 return result;
00477 }
00478
00479 static const char __attribute__((used)) vcid_groovx_media_bmapdata_cc_utc20050626084018[] = "$Id: bmapdata.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00480 #endif // !GROOVX_MEDIA_BMAPDATA_CC_UTC20050626084018_DEFINED