Panda3D
 All Classes Functions Variables Enumerations
texturePeeker.cxx
1 // Filename: texturePeeker.cxx
2 // Created by: drose (26Aug08)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "texturePeeker.h"
16 
17 
18 ////////////////////////////////////////////////////////////////////
19 // Function: TexturePeeker::Constructor
20 // Access: Private
21 // Description: Use Texture::peek() to construct a TexturePeeker.
22 //
23 // This constructor is called only by Texture::peek(),
24 // and assumes the texture's lock is already held.
25 ////////////////////////////////////////////////////////////////////
26 TexturePeeker::
27 TexturePeeker(Texture *tex, Texture::CData *cdata) {
28  if (cdata->_texture_type == Texture::TT_cube_map) {
29  // Cube map texture. We'll need to map from (u, v, w) to (u, v)
30  // within the appropriate page, where w indicates the page.
31 
32  // TODO: handle cube maps.
33  return;
34 
35  } else {
36  // Regular 1-d, 2-d, or 3-d texture. The coordinates map
37  // directly. Simple ram images are possible if it is a 2-d
38  // texture.
39  if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
40  // Get the regular RAM image if it is available.
41  _image = tex->do_get_ram_image(cdata);
42  _x_size = cdata->_x_size;
43  _y_size = cdata->_y_size;
44  _z_size = cdata->_z_size;
45  _component_width = cdata->_component_width;
46  _num_components = cdata->_num_components;
47  _format = cdata->_format;
48  _component_type = cdata->_component_type;
49 
50  } else if (!cdata->_simple_ram_image._image.empty()) {
51  // Get the simple RAM image if *that* is available.
52  _image = cdata->_simple_ram_image._image;
53  _x_size = cdata->_simple_x_size;
54  _y_size = cdata->_simple_y_size;
55  _z_size = 1;
56 
57  _component_width = 1;
58  _num_components = 4;
59  _format = Texture::F_rgba;
60  _component_type = Texture::T_unsigned_byte;
61 
62  } else {
63  // Failing that, reload and get the uncompressed RAM image.
64  _image = tex->do_get_uncompressed_ram_image(cdata);
65  _x_size = cdata->_x_size;
66  _y_size = cdata->_y_size;
67  _z_size = cdata->_z_size;
68  _component_width = cdata->_component_width;
69  _num_components = cdata->_num_components;
70  _format = cdata->_format;
71  _component_type = cdata->_component_type;
72  }
73  }
74 
75  if (_image.is_null()) {
76  return;
77  }
78  _pixel_width = _component_width * _num_components;
79 
80  switch (_component_type) {
81  case Texture::T_unsigned_byte:
82  _get_component = Texture::get_unsigned_byte;
83  break;
84 
85  case Texture::T_unsigned_short:
86  _get_component = Texture::get_unsigned_short;
87  break;
88 
89  default:
90  // Not supported.
91  _image.clear();
92  return;
93  }
94 
95  switch (_format) {
96  case Texture::F_depth_stencil:
97  case Texture::F_depth_component:
98 
99  case Texture::F_red:
100  _get_texel = get_texel_r;
101  break;
102 
103  case Texture::F_green:
104  _get_texel = get_texel_g;
105  break;
106 
107  case Texture::F_blue:
108  _get_texel = get_texel_b;
109  break;
110 
111  case Texture::F_alpha:
112  _get_texel = get_texel_a;
113  break;
114 
115  case Texture::F_luminance:
116  _get_texel = get_texel_l;
117  break;
118 
119  case Texture::F_luminance_alpha:
120  case Texture::F_luminance_alphamask:
121  _get_texel = get_texel_la;
122  break;
123 
124  case Texture::F_rgb:
125  case Texture::F_rgb5:
126  case Texture::F_rgb8:
127  case Texture::F_rgb12:
128  case Texture::F_rgb332:
129  _get_texel = get_texel_rgb;
130  break;
131 
132  case Texture::F_rgba:
133  case Texture::F_rgbm:
134  case Texture::F_rgba4:
135  case Texture::F_rgba5:
136  case Texture::F_rgba8:
137  case Texture::F_rgba12:
138  case Texture::F_rgba16:
139  case Texture::F_rgba32:
140  _get_texel = get_texel_rgba;
141  break;
142  default:
143  // Not supported.
144  _image.clear();
145  return;
146  }
147 }
148 
149 
150 ////////////////////////////////////////////////////////////////////
151 // Function: TexturePeeker::lookup
152 // Access: Published
153 // Description: Fills "color" with the RGBA color of the texel at
154 // point (u, v).
155 //
156 // The texel color is determined via nearest-point
157 // sampling (no filtering of adjacent pixels),
158 // regardless of the filter type associated with the
159 // texture. u, v, and w will wrap around regardless of
160 // the texture's wrap mode.
161 ////////////////////////////////////////////////////////////////////
162 void TexturePeeker::
163 lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
164  int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
165  int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
166 
167  nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
168  const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
169 
170  (*_get_texel)(color, p, _get_component);
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: TexturePeeker::lookup
175 // Access: Published
176 // Description: Fills "color" with the RGBA color of the texel at
177 // point (u, v, w).
178 //
179 // The texel color is determined via nearest-point
180 // sampling (no filtering of adjacent pixels),
181 // regardless of the filter type associated with the
182 // texture. u, v, and w will wrap around regardless of
183 // the texture's wrap mode.
184 ////////////////////////////////////////////////////////////////////
185 void TexturePeeker::
186 lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const {
187  int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
188  int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
189  int z = int((w - cfloor(w)) * (PN_stdfloat)_z_size) % _z_size;
190 
191  nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size &&
192  z >= 0 && z < _z_size);
193  const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
194 
195  (*_get_texel)(color, p, _get_component);
196 }
197 
198 ////////////////////////////////////////////////////////////////////
199 // Function: TexturePeeker::filter_rect
200 // Access: Published
201 // Description: Fills "color" with the average RGBA color of the
202 // texels within the rectangle defined by the specified
203 // coordinate range.
204 //
205 // The texel color is linearly filtered over the entire
206 // region. u, v, and w will wrap around regardless of
207 // the texture's wrap mode.
208 ////////////////////////////////////////////////////////////////////
209 void TexturePeeker::
211  PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat max_u, PN_stdfloat max_v) const {
212  int min_x, max_x;
213  init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
214 
215  int min_y, max_y;
216  init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
217 
218  color.set(0.0f, 0.0f, 0.0f, 0.0f);
219  PN_stdfloat net = 0.0f;
220  accum_filter_y(color, net, 0,
221  min_x, max_x, min_u, max_u,
222  min_y, max_y, min_v, max_v,
223  1.0f);
224 
225  if (net != 0.0f) {
226  color /= net;
227  }
228 }
229 
230 ////////////////////////////////////////////////////////////////////
231 // Function: TexturePeeker::filter_rect
232 // Access: Published
233 // Description: Fills "color" with the average RGBA color of the
234 // texels within the rectangle defined by the specified
235 // coordinate range.
236 //
237 // The texel color is linearly filtered over the entire
238 // region. u, v, and w will wrap around regardless of
239 // the texture's wrap mode.
240 ////////////////////////////////////////////////////////////////////
241 void TexturePeeker::
243  PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat min_w,
244  PN_stdfloat max_u, PN_stdfloat max_v, PN_stdfloat max_w) const {
245  int min_x, max_x;
246  init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
247 
248  int min_y, max_y;
249  init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
250 
251  int min_z, max_z;
252  init_rect_minmax(min_z, max_z, min_w, max_w, _z_size);
253 
254  color.set(0.0f, 0.0f, 0.0f, 0.0f);
255  PN_stdfloat net = 0.0f;
256  accum_filter_z(color, net,
257  min_x, max_x, min_u, max_u,
258  min_y, max_y, min_v, max_v,
259  min_z, max_z, min_w, max_w);
260 
261  if (net != 0.0f) {
262  color /= net;
263  }
264 }
265 
266 ////////////////////////////////////////////////////////////////////
267 // Function: TexturePeeker::init_rect_minmax
268 // Access: Private, Static
269 // Description: Sanity-checks min_u, max_u and computes min_x and
270 // min_y based on them. Also works for y and z.
271 ////////////////////////////////////////////////////////////////////
272 void TexturePeeker::
273 init_rect_minmax(int &min_x, int &max_x, PN_stdfloat &min_u, PN_stdfloat &max_u,
274  int x_size) {
275  if (min_u > max_u) {
276  PN_stdfloat t = min_u;
277  min_u = max_u;
278  max_u = t;
279  }
280  if (max_u - min_u >= 1.0f) {
281  min_u = 0.0f;
282  max_u = 1.0f;
283  }
284  min_x = (int)cfloor(min_u * (PN_stdfloat)x_size);
285  max_x = (int)cceil(max_u * (PN_stdfloat)x_size);
286  nassertv(min_x <= max_x);
287 }
288 
289 ////////////////////////////////////////////////////////////////////
290 // Function: TexturePeeker::accum_filter_z
291 // Access: Private
292 // Description: Accumulates the range of pixels from min_z to max_z.
293 ////////////////////////////////////////////////////////////////////
294 void TexturePeeker::
295 accum_filter_z(LColor &color, PN_stdfloat &net,
296  int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
297  int min_y, int max_y, PN_stdfloat min_v, PN_stdfloat max_v,
298  int min_z, int max_z, PN_stdfloat min_w, PN_stdfloat max_w) const {
299  nassertv(min_z >= 0 && min_z <= _z_size &&
300  max_z >= 0 && max_z <= _z_size);
301  int zi = min_z;
302 
303  if (min_z >= max_z - 1) {
304  // Within a single texel.
305  accum_filter_y(color, net, zi % _z_size,
306  min_x, max_x, min_u, max_u,
307  min_y, max_y, min_v, max_v,
308  1.0f);
309 
310  } else {
311  // First part-texel.
312  PN_stdfloat w = (min_z + 1) - min_w * _z_size;
313  accum_filter_y(color, net, zi % _z_size,
314  min_x, max_x, min_u, max_u,
315  min_y, max_y, min_v, max_v,
316  w);
317  int zs = max_z - 1;
318 
319  // Run of full texels.
320  zi = min_z + 1;
321  while (zi < zs) {
322  accum_filter_y(color, net, zi % _z_size,
323  min_x, max_x, min_u, max_u,
324  min_y, max_y, min_v, max_v,
325  1.0f);
326  ++zi;
327  }
328 
329  // Last part-texel.
330  w = max_w * _z_size - (max_z - 1);
331  accum_filter_y(color, net, zi % _z_size,
332  min_x, max_x, min_u, max_u,
333  min_y, max_y, min_v, max_v,
334  w);
335  }
336 }
337 
338 ////////////////////////////////////////////////////////////////////
339 // Function: TexturePeeker::accum_filter_y
340 // Access: Private
341 // Description: Accumulates the range of pixels from min_y to max_y.
342 ////////////////////////////////////////////////////////////////////
343 void TexturePeeker::
344 accum_filter_y(LColor &color, PN_stdfloat &net, int zi,
345  int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
346  int min_y, int max_y, PN_stdfloat min_v, PN_stdfloat max_v,
347  PN_stdfloat weight) const {
348  nassertv(zi >= 0 && zi < _z_size);
349  nassertv(min_y >= 0 && min_y <= _y_size &&
350  max_y >= 0 && max_y <= _y_size);
351  int yi = min_y;
352 
353  if (min_y >= max_y - 1) {
354  // Within a single texel.
355  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
356 
357  } else {
358  // First part-texel.
359  PN_stdfloat w = (min_y + 1) - min_v * _y_size;
360  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
361  int ys = max_y - 1;
362 
363  // Run of full texels.
364  yi = min_y + 1;
365  while (yi < ys) {
366  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
367  ++yi;
368  }
369 
370  // Last part-texel.
371  w = max_v * _y_size - (max_y - 1);
372  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
373  }
374 }
375 
376 ////////////////////////////////////////////////////////////////////
377 // Function: TexturePeeker::accum_filter_x
378 // Access: Private
379 // Description: Accumulates the range of pixels from min_x to max_x.
380 ////////////////////////////////////////////////////////////////////
381 void TexturePeeker::
382 accum_filter_x(LColor &color, PN_stdfloat &net, int yi, int zi,
383  int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
384  PN_stdfloat weight) const {
385  nassertv(yi >= 0 && yi < _y_size && zi >= 0 && zi < _z_size);
386  nassertv(min_x >= 0 && min_x <= _x_size &&
387  max_x >= 0 && max_x <= _x_size);
388 
389  // Compute the p corresponding to min_x.
390  int xi = min_x % _x_size;
391  const unsigned char *p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
392 
393  if (min_x >= max_x - 1) {
394  // Within a single texel.
395  accum_texel(color, net, p, weight);
396 
397  } else {
398  // First part-texel.
399  PN_stdfloat w = (min_x + 1) - min_u * _x_size;
400  accum_texel(color, net, p, weight * w);
401  int xs = max_x - 1;
402 
403  // Run of full texels.
404  xi = min_x + 1;
405  while (xi < xs) {
406  if (xi == _x_size) {
407  xi = 0;
408  p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
409  xs -= _x_size;
410  }
411  accum_texel(color, net, p, weight);
412  ++xi;
413  }
414 
415  // Last part-texel.
416  if (xi == _x_size) {
417  xi = 0;
418  p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
419  }
420  w = max_u * _x_size - (max_x - 1);
421  accum_texel(color, net, p, weight * w);
422  }
423 }
424 
425 ////////////////////////////////////////////////////////////////////
426 // Function: TexturePeeker::accum_texel
427 // Access: Private
428 // Description: Accumulates a single texel into the total computed by
429 // filter_rect().
430 ////////////////////////////////////////////////////////////////////
431 void TexturePeeker::
432 accum_texel(LColor &color, PN_stdfloat &net, const unsigned char *&p, PN_stdfloat weight) const {
433  LColor c;
434  (*_get_texel)(c, p, _get_component);
435  color += c * weight;
436  net += weight;
437 }
438 
439 ////////////////////////////////////////////////////////////////////
440 // Function: TexturePeeker::get_texel_r
441 // Access: Private, Static
442 // Description: Gets the color of the texel at byte p, given that the
443 // texture is in format F_red.
444 ////////////////////////////////////////////////////////////////////
445 void TexturePeeker::
446 get_texel_r(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
447  color[0] = (*get_component)(p);
448  color[1] = 0.0f;
449  color[2] = 0.0f;
450  color[3] = 1.0f;
451 }
452 
453 ////////////////////////////////////////////////////////////////////
454 // Function: TexturePeeker::get_texel_g
455 // Access: Private, Static
456 // Description: Gets the color of the texel at byte p, given that the
457 // texture is in format F_green.
458 ////////////////////////////////////////////////////////////////////
459 void TexturePeeker::
460 get_texel_g(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
461  color[0] = 0.0f;
462  color[1] = (*get_component)(p);
463  color[2] = 0.0f;
464  color[3] = 1.0f;
465 }
466 
467 ////////////////////////////////////////////////////////////////////
468 // Function: TexturePeeker::get_texel_b
469 // Access: Private, Static
470 // Description: Gets the color of the texel at byte p, given that the
471 // texture is in format F_blue.
472 ////////////////////////////////////////////////////////////////////
473 void TexturePeeker::
474 get_texel_b(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
475  color[0] = 0.0f;
476  color[1] = 0.0f;
477  color[2] = (*get_component)(p);
478  color[3] = 1.0f;
479 }
480 
481 ////////////////////////////////////////////////////////////////////
482 // Function: TexturePeeker::get_texel_a
483 // Access: Private, Static
484 // Description: Gets the color of the texel at byte p, given that the
485 // texture is in format F_alpha.
486 ////////////////////////////////////////////////////////////////////
487 void TexturePeeker::
488 get_texel_a(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
489  color[0] = 0.0f;
490  color[1] = 0.0f;
491  color[2] = 1.0f;
492  color[3] = (*get_component)(p);
493 }
494 
495 ////////////////////////////////////////////////////////////////////
496 // Function: TexturePeeker::get_texel_l
497 // Access: Private, Static
498 // Description: Gets the color of the texel at byte p, given that the
499 // texture is in format F_luminance.
500 ////////////////////////////////////////////////////////////////////
501 void TexturePeeker::
502 get_texel_l(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
503  color[0] = (*get_component)(p);
504  color[1] = color[0];
505  color[2] = color[0];
506  color[3] = 1.0f;
507 }
508 
509 ////////////////////////////////////////////////////////////////////
510 // Function: TexturePeeker::get_texel_la
511 // Access: Private, Static
512 // Description: Gets the color of the texel at byte p, given that the
513 // texture is in format F_luminance_alpha or similar.
514 ////////////////////////////////////////////////////////////////////
515 void TexturePeeker::
516 get_texel_la(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
517  color[0] = (*get_component)(p);
518  color[1] = color[0];
519  color[2] = color[0];
520  color[3] = (*get_component)(p);
521 }
522 
523 ////////////////////////////////////////////////////////////////////
524 // Function: TexturePeeker::get_texel_rgb
525 // Access: Private, Static
526 // Description: Gets the color of the texel at byte p, given that the
527 // texture is in format F_rgb or similar.
528 ////////////////////////////////////////////////////////////////////
529 void TexturePeeker::
530 get_texel_rgb(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
531  color[2] = (*get_component)(p);
532  color[1] = (*get_component)(p);
533  color[0] = (*get_component)(p);
534  color[3] = 1.0f;
535 }
536 
537 ////////////////////////////////////////////////////////////////////
538 // Function: TexturePeeker::get_texel_rgba
539 // Access: Private, Static
540 // Description: Gets the color of the texel at byte p, given that the
541 // texture is in format F_rgba or similar.
542 ////////////////////////////////////////////////////////////////////
543 void TexturePeeker::
544 get_texel_rgba(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
545  color[2] = (*get_component)(p);
546  color[1] = (*get_component)(p);
547  color[0] = (*get_component)(p);
548  color[3] = (*get_component)(p);
549 }
const Element * p() const
Function p() is similar to the function from ConstPointerTo.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
void clear()
To empty the PTA, use the clear() method, since assignment to NULL is problematic (given the ambiguit...
void filter_rect(LColor &color, PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat max_u, PN_stdfloat max_v) const
Fills &quot;color&quot; with the average RGBA color of the texels within the rectangle defined by the specified...
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
bool is_null() const
Returns true if the PointerTo is a NULL pointer, false otherwise.
Definition: pointerToVoid.I:54
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const
Fills &quot;color&quot; with the RGBA color of the texel at point (u, v).