Panda3D
|
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 }