Panda3D
 All Classes Functions Variables Enumerations
texturePeeker.cxx
00001 // Filename: texturePeeker.cxx
00002 // Created by:  drose (26Aug08)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "texturePeeker.h"
00016 
00017 
00018 ////////////////////////////////////////////////////////////////////
00019 //     Function: TexturePeeker::Constructor
00020 //       Access: Private
00021 //  Description: Use Texture::peek() to construct a TexturePeeker.
00022 //
00023 //               This constructor is called only by Texture::peek(),
00024 //               and assumes the texture's lock is already held.
00025 ////////////////////////////////////////////////////////////////////
00026 TexturePeeker::
00027 TexturePeeker(Texture *tex, Texture::CData *cdata) {
00028   if (cdata->_texture_type == Texture::TT_cube_map) {
00029     // Cube map texture.  We'll need to map from (u, v, w) to (u, v)
00030     // within the appropriate page, where w indicates the page.
00031 
00032     // TODO: handle cube maps.
00033     return;
00034 
00035   } else {
00036     // Regular 1-d, 2-d, or 3-d texture.  The coordinates map
00037     // directly.  Simple ram images are possible if it is a 2-d
00038     // texture.
00039     if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
00040       // Get the regular RAM image if it is available.
00041       _image = tex->do_get_ram_image(cdata);
00042       _x_size = cdata->_x_size;
00043       _y_size = cdata->_y_size;
00044       _z_size = cdata->_z_size;
00045       _component_width = cdata->_component_width;
00046       _num_components = cdata->_num_components;
00047       _format = cdata->_format;
00048       _component_type = cdata->_component_type;
00049 
00050     } else if (!cdata->_simple_ram_image._image.empty()) {
00051       // Get the simple RAM image if *that* is available.
00052       _image = cdata->_simple_ram_image._image;
00053       _x_size = cdata->_simple_x_size;
00054       _y_size = cdata->_simple_y_size;
00055       _z_size = 1;
00056 
00057       _component_width = 1;
00058       _num_components = 4;
00059       _format = Texture::F_rgba;
00060       _component_type = Texture::T_unsigned_byte;
00061 
00062     } else {
00063       // Failing that, reload and get the uncompressed RAM image.
00064       _image = tex->do_get_uncompressed_ram_image(cdata);
00065       _x_size = cdata->_x_size;
00066       _y_size = cdata->_y_size;
00067       _z_size = cdata->_z_size;
00068       _component_width = cdata->_component_width;
00069       _num_components = cdata->_num_components;
00070       _format = cdata->_format;
00071       _component_type = cdata->_component_type;
00072     }
00073   }
00074 
00075   if (_image.is_null()) {
00076     return;
00077   }
00078   _pixel_width = _component_width * _num_components;
00079 
00080   switch (_component_type) {
00081   case Texture::T_unsigned_byte:
00082     _get_component = Texture::get_unsigned_byte;
00083     break;
00084 
00085   case Texture::T_unsigned_short:
00086     _get_component = Texture::get_unsigned_short;
00087     break;
00088 
00089   default:
00090     // Not supported.
00091     _image.clear();
00092     return;
00093   }
00094 
00095   switch (_format) {
00096   case Texture::F_depth_stencil:
00097   case Texture::F_depth_component:
00098 
00099   case Texture::F_red:
00100     _get_texel = get_texel_r;
00101     break;
00102 
00103   case Texture::F_green:
00104     _get_texel = get_texel_g;
00105     break;
00106 
00107   case Texture::F_blue:
00108     _get_texel = get_texel_b;
00109     break;
00110 
00111   case Texture::F_alpha:
00112     _get_texel = get_texel_a;
00113     break;
00114 
00115   case Texture::F_luminance:
00116     _get_texel = get_texel_l;
00117     break;
00118 
00119   case Texture::F_luminance_alpha:
00120   case Texture::F_luminance_alphamask:
00121     _get_texel = get_texel_la;
00122     break;
00123 
00124   case Texture::F_rgb:
00125   case Texture::F_rgb5:
00126   case Texture::F_rgb8:
00127   case Texture::F_rgb12:
00128   case Texture::F_rgb332:
00129     _get_texel = get_texel_rgb;
00130     break;
00131 
00132   case Texture::F_rgba:
00133   case Texture::F_rgbm:
00134   case Texture::F_rgba4:
00135   case Texture::F_rgba5:
00136   case Texture::F_rgba8:
00137   case Texture::F_rgba12:
00138   case Texture::F_rgba16:
00139   case Texture::F_rgba32:
00140     _get_texel = get_texel_rgba;
00141     break;
00142   default:
00143     // Not supported.
00144     _image.clear();
00145     return;
00146   }
00147 }
00148 
00149 
00150 ////////////////////////////////////////////////////////////////////
00151 //     Function: TexturePeeker::lookup
00152 //       Access: Published
00153 //  Description: Fills "color" with the RGBA color of the texel at
00154 //               point (u, v).
00155 //
00156 //               The texel color is determined via nearest-point
00157 //               sampling (no filtering of adjacent pixels),
00158 //               regardless of the filter type associated with the
00159 //               texture.  u, v, and w will wrap around regardless of
00160 //               the texture's wrap mode.
00161 ////////////////////////////////////////////////////////////////////
00162 void TexturePeeker::
00163 lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
00164   int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
00165   int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
00166 
00167   nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
00168   const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
00169 
00170   (*_get_texel)(color, p, _get_component);
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: TexturePeeker::lookup
00175 //       Access: Published
00176 //  Description: Fills "color" with the RGBA color of the texel at
00177 //               point (u, v, w).
00178 //
00179 //               The texel color is determined via nearest-point
00180 //               sampling (no filtering of adjacent pixels),
00181 //               regardless of the filter type associated with the
00182 //               texture.  u, v, and w will wrap around regardless of
00183 //               the texture's wrap mode.
00184 ////////////////////////////////////////////////////////////////////
00185 void TexturePeeker::
00186 lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const {
00187   int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
00188   int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
00189   int z = int((w - cfloor(w)) * (PN_stdfloat)_z_size) % _z_size;
00190 
00191   nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size && 
00192            z >= 0 && z < _z_size);
00193   const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
00194 
00195   (*_get_texel)(color, p, _get_component);
00196 }
00197 
00198 ////////////////////////////////////////////////////////////////////
00199 //     Function: TexturePeeker::filter_rect
00200 //       Access: Published
00201 //  Description: Fills "color" with the average RGBA color of the
00202 //               texels within the rectangle defined by the specified
00203 //               coordinate range.
00204 //
00205 //               The texel color is linearly filtered over the entire
00206 //               region.  u, v, and w will wrap around regardless of
00207 //               the texture's wrap mode.
00208 ////////////////////////////////////////////////////////////////////
00209 void TexturePeeker::
00210 filter_rect(LColor &color, 
00211             PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat max_u, PN_stdfloat max_v) const {
00212   int min_x, max_x;
00213   init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
00214 
00215   int min_y, max_y;
00216   init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
00217 
00218   color.set(0.0f, 0.0f, 0.0f, 0.0f);
00219   PN_stdfloat net = 0.0f;
00220   accum_filter_y(color, net, 0,
00221                  min_x, max_x, min_u, max_u,
00222                  min_y, max_y, min_v, max_v, 
00223                  1.0f);
00224 
00225   if (net != 0.0f) {
00226     color /= net;
00227   }
00228 }
00229 
00230 ////////////////////////////////////////////////////////////////////
00231 //     Function: TexturePeeker::filter_rect
00232 //       Access: Published
00233 //  Description: Fills "color" with the average RGBA color of the
00234 //               texels within the rectangle defined by the specified
00235 //               coordinate range.
00236 //
00237 //               The texel color is linearly filtered over the entire
00238 //               region.  u, v, and w will wrap around regardless of
00239 //               the texture's wrap mode.
00240 ////////////////////////////////////////////////////////////////////
00241 void TexturePeeker::
00242 filter_rect(LColor &color, 
00243             PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat min_w,
00244             PN_stdfloat max_u, PN_stdfloat max_v, PN_stdfloat max_w) const {
00245   int min_x, max_x;
00246   init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
00247 
00248   int min_y, max_y;
00249   init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
00250 
00251   int min_z, max_z;
00252   init_rect_minmax(min_z, max_z, min_w, max_w, _z_size);
00253 
00254   color.set(0.0f, 0.0f, 0.0f, 0.0f);
00255   PN_stdfloat net = 0.0f;
00256   accum_filter_z(color, net,
00257                  min_x, max_x, min_u, max_u,
00258                  min_y, max_y, min_v, max_v,
00259                  min_z, max_z, min_w, max_w);
00260 
00261   if (net != 0.0f) {
00262     color /= net;
00263   }
00264 }
00265 
00266 ////////////////////////////////////////////////////////////////////
00267 //     Function: TexturePeeker::init_rect_minmax
00268 //       Access: Private, Static
00269 //  Description: Sanity-checks min_u, max_u and computes min_x and
00270 //               min_y based on them.  Also works for y and z.
00271 ////////////////////////////////////////////////////////////////////
00272 void TexturePeeker::
00273 init_rect_minmax(int &min_x, int &max_x, PN_stdfloat &min_u, PN_stdfloat &max_u,
00274                  int x_size) {
00275   if (min_u > max_u) {
00276     PN_stdfloat t = min_u;
00277     min_u = max_u;
00278     max_u = t;
00279   }
00280   if (max_u - min_u >= 1.0f) {
00281     min_u = 0.0f;
00282     max_u = 1.0f;
00283   }
00284   min_x = (int)cfloor(min_u * (PN_stdfloat)x_size);
00285   max_x = (int)cceil(max_u * (PN_stdfloat)x_size);
00286   nassertv(min_x <= max_x);
00287 }
00288 
00289 ////////////////////////////////////////////////////////////////////
00290 //     Function: TexturePeeker::accum_filter_z
00291 //       Access: Private
00292 //  Description: Accumulates the range of pixels from min_z to max_z.
00293 ////////////////////////////////////////////////////////////////////
00294 void TexturePeeker::
00295 accum_filter_z(LColor &color, PN_stdfloat &net,
00296                int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
00297                int min_y, int max_y, PN_stdfloat min_v, PN_stdfloat max_v,
00298                int min_z, int max_z, PN_stdfloat min_w, PN_stdfloat max_w) const {
00299   nassertv(min_z >= 0 && min_z <= _z_size && 
00300            max_z >= 0 && max_z <= _z_size);
00301   int zi = min_z;
00302 
00303   if (min_z >= max_z - 1) {
00304     // Within a single texel.
00305     accum_filter_y(color, net, zi % _z_size, 
00306                    min_x, max_x, min_u, max_u,
00307                    min_y, max_y, min_v, max_v,
00308                    1.0f);
00309 
00310   } else {
00311     // First part-texel.
00312     PN_stdfloat w = (min_z + 1) - min_w * _z_size;
00313     accum_filter_y(color, net, zi % _z_size, 
00314                    min_x, max_x, min_u, max_u,
00315                    min_y, max_y, min_v, max_v,
00316                    w);
00317     int zs = max_z - 1;
00318     
00319     // Run of full texels.
00320     zi = min_z + 1;
00321     while (zi < zs) {
00322       accum_filter_y(color, net, zi % _z_size, 
00323                      min_x, max_x, min_u, max_u,
00324                      min_y, max_y, min_v, max_v,
00325                      1.0f);
00326       ++zi;
00327     }
00328     
00329     // Last part-texel.
00330     w = max_w * _z_size - (max_z - 1);
00331     accum_filter_y(color, net, zi % _z_size, 
00332                    min_x, max_x, min_u, max_u,
00333                    min_y, max_y, min_v, max_v,
00334                    w);
00335   }
00336 }
00337 
00338 ////////////////////////////////////////////////////////////////////
00339 //     Function: TexturePeeker::accum_filter_y
00340 //       Access: Private
00341 //  Description: Accumulates the range of pixels from min_y to max_y.
00342 ////////////////////////////////////////////////////////////////////
00343 void TexturePeeker::
00344 accum_filter_y(LColor &color, PN_stdfloat &net, int zi,
00345                int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
00346                int min_y, int max_y, PN_stdfloat min_v, PN_stdfloat max_v,
00347                PN_stdfloat weight) const {
00348   nassertv(zi >= 0 && zi < _z_size);
00349   nassertv(min_y >= 0 && min_y <= _y_size && 
00350            max_y >= 0 && max_y <= _y_size);
00351   int yi = min_y;
00352 
00353   if (min_y >= max_y - 1) {
00354     // Within a single texel.
00355     accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
00356 
00357   } else {
00358     // First part-texel.
00359     PN_stdfloat w = (min_y + 1) - min_v * _y_size;
00360     accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
00361     int ys = max_y - 1;
00362     
00363     // Run of full texels.
00364     yi = min_y + 1;
00365     while (yi < ys) {
00366       accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
00367       ++yi;
00368     }
00369     
00370     // Last part-texel.
00371     w = max_v * _y_size - (max_y - 1);
00372     accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
00373   }
00374 }
00375 
00376 ////////////////////////////////////////////////////////////////////
00377 //     Function: TexturePeeker::accum_filter_x
00378 //       Access: Private
00379 //  Description: Accumulates the range of pixels from min_x to max_x.
00380 ////////////////////////////////////////////////////////////////////
00381 void TexturePeeker::
00382 accum_filter_x(LColor &color, PN_stdfloat &net, int yi, int zi,
00383                int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
00384                PN_stdfloat weight) const {
00385   nassertv(yi >= 0 && yi < _y_size && zi >= 0 && zi < _z_size);
00386   nassertv(min_x >= 0 && min_x <= _x_size && 
00387            max_x >= 0 && max_x <= _x_size);
00388 
00389   // Compute the p corresponding to min_x.
00390   int xi = min_x % _x_size;
00391   const unsigned char *p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
00392 
00393   if (min_x >= max_x - 1) {
00394     // Within a single texel.
00395     accum_texel(color, net, p, weight);
00396 
00397   } else {
00398     // First part-texel.
00399     PN_stdfloat w = (min_x + 1) - min_u * _x_size;
00400     accum_texel(color, net, p, weight * w);
00401     int xs = max_x - 1;
00402     
00403     // Run of full texels.
00404     xi = min_x + 1;
00405     while (xi < xs) {
00406       if (xi == _x_size) {
00407         xi = 0;
00408         p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
00409         xs -= _x_size;
00410       }
00411       accum_texel(color, net, p, weight);
00412       ++xi;
00413     }
00414     
00415     // Last part-texel.
00416     if (xi == _x_size) {
00417       xi = 0;
00418       p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
00419     }
00420     w = max_u * _x_size - (max_x - 1);
00421     accum_texel(color, net, p, weight * w);
00422   }
00423 }
00424 
00425 ////////////////////////////////////////////////////////////////////
00426 //     Function: TexturePeeker::accum_texel
00427 //       Access: Private
00428 //  Description: Accumulates a single texel into the total computed by
00429 //               filter_rect().
00430 ////////////////////////////////////////////////////////////////////
00431 void TexturePeeker::
00432 accum_texel(LColor &color, PN_stdfloat &net, const unsigned char *&p, PN_stdfloat weight) const {
00433   LColor c;
00434   (*_get_texel)(c, p, _get_component);
00435   color += c * weight;
00436   net += weight;
00437 }
00438 
00439 ////////////////////////////////////////////////////////////////////
00440 //     Function: TexturePeeker::get_texel_r
00441 //       Access: Private, Static
00442 //  Description: Gets the color of the texel at byte p, given that the
00443 //               texture is in format F_red.
00444 ////////////////////////////////////////////////////////////////////
00445 void TexturePeeker::
00446 get_texel_r(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00447   color[0] = (*get_component)(p);
00448   color[1] = 0.0f;
00449   color[2] = 0.0f;
00450   color[3] = 1.0f;
00451 }
00452 
00453 ////////////////////////////////////////////////////////////////////
00454 //     Function: TexturePeeker::get_texel_g
00455 //       Access: Private, Static
00456 //  Description: Gets the color of the texel at byte p, given that the
00457 //               texture is in format F_green.
00458 ////////////////////////////////////////////////////////////////////
00459 void TexturePeeker::
00460 get_texel_g(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00461   color[0] = 0.0f;
00462   color[1] = (*get_component)(p);
00463   color[2] = 0.0f;
00464   color[3] = 1.0f;
00465 }
00466 
00467 ////////////////////////////////////////////////////////////////////
00468 //     Function: TexturePeeker::get_texel_b
00469 //       Access: Private, Static
00470 //  Description: Gets the color of the texel at byte p, given that the
00471 //               texture is in format F_blue.
00472 ////////////////////////////////////////////////////////////////////
00473 void TexturePeeker::
00474 get_texel_b(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00475   color[0] = 0.0f;
00476   color[1] = 0.0f;
00477   color[2] = (*get_component)(p);
00478   color[3] = 1.0f;
00479 }
00480 
00481 ////////////////////////////////////////////////////////////////////
00482 //     Function: TexturePeeker::get_texel_a
00483 //       Access: Private, Static
00484 //  Description: Gets the color of the texel at byte p, given that the
00485 //               texture is in format F_alpha.
00486 ////////////////////////////////////////////////////////////////////
00487 void TexturePeeker::
00488 get_texel_a(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00489   color[0] = 0.0f;
00490   color[1] = 0.0f;
00491   color[2] = 1.0f;
00492   color[3] = (*get_component)(p);
00493 }
00494 
00495 ////////////////////////////////////////////////////////////////////
00496 //     Function: TexturePeeker::get_texel_l
00497 //       Access: Private, Static
00498 //  Description: Gets the color of the texel at byte p, given that the
00499 //               texture is in format F_luminance.
00500 ////////////////////////////////////////////////////////////////////
00501 void TexturePeeker::
00502 get_texel_l(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00503   color[0] = (*get_component)(p);
00504   color[1] = color[0];
00505   color[2] = color[0];
00506   color[3] = 1.0f;
00507 }
00508 
00509 ////////////////////////////////////////////////////////////////////
00510 //     Function: TexturePeeker::get_texel_la
00511 //       Access: Private, Static
00512 //  Description: Gets the color of the texel at byte p, given that the
00513 //               texture is in format F_luminance_alpha or similar.
00514 ////////////////////////////////////////////////////////////////////
00515 void TexturePeeker::
00516 get_texel_la(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00517   color[0] = (*get_component)(p);
00518   color[1] = color[0];
00519   color[2] = color[0];
00520   color[3] = (*get_component)(p);
00521 }
00522 
00523 ////////////////////////////////////////////////////////////////////
00524 //     Function: TexturePeeker::get_texel_rgb
00525 //       Access: Private, Static
00526 //  Description: Gets the color of the texel at byte p, given that the
00527 //               texture is in format F_rgb or similar.
00528 ////////////////////////////////////////////////////////////////////
00529 void TexturePeeker::
00530 get_texel_rgb(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00531   color[2] = (*get_component)(p);
00532   color[1] = (*get_component)(p);
00533   color[0] = (*get_component)(p);
00534   color[3] = 1.0f;
00535 }
00536 
00537 ////////////////////////////////////////////////////////////////////
00538 //     Function: TexturePeeker::get_texel_rgba
00539 //       Access: Private, Static
00540 //  Description: Gets the color of the texel at byte p, given that the
00541 //               texture is in format F_rgba or similar.
00542 ////////////////////////////////////////////////////////////////////
00543 void TexturePeeker::
00544 get_texel_rgba(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
00545   color[2] = (*get_component)(p);
00546   color[1] = (*get_component)(p);
00547   color[0] = (*get_component)(p);
00548   color[3] = (*get_component)(p);
00549 }
 All Classes Functions Variables Enumerations