Panda3D
texturePeeker.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file texturePeeker.cxx
10  * @author drose
11  * @date 2008-08-26
12  */
13 
14 #include "texturePeeker.h"
15 
16 
17 static double get_unsigned_byte_i(const unsigned char *&p) {
18  return *p++;
19 }
20 
21 static double get_signed_byte_i(const unsigned char *&p) {
22  return *(signed char *)p++;
23 }
24 
25 static double get_unsigned_short_i(const unsigned char *&p) {
26  union {
27  unsigned short us;
28  unsigned char uc[2];
29  } v;
30  v.uc[0] = (*p++);
31  v.uc[1] = (*p++);
32  return (double)v.us;
33 }
34 
35 static double get_signed_short_i(const unsigned char *&p) {
36  union {
37  signed short ss;
38  unsigned char uc[2];
39  } v;
40  v.uc[0] = (*p++);
41  v.uc[1] = (*p++);
42  return (double)v.ss;
43 }
44 
45 static double get_unsigned_int_i(const unsigned char *&p) {
46  union {
47  unsigned int ui;
48  unsigned char uc[4];
49  } v;
50  v.uc[0] = (*p++);
51  v.uc[1] = (*p++);
52  v.uc[2] = (*p++);
53  v.uc[3] = (*p++);
54  return (double)v.ui;
55 }
56 
57 static double get_signed_int_i(const unsigned char *&p) {
58  union {
59  signed int si;
60  unsigned char uc[4];
61  } v;
62  v.uc[0] = (*p++);
63  v.uc[1] = (*p++);
64  v.uc[2] = (*p++);
65  v.uc[3] = (*p++);
66  return (double)v.si;
67 }
68 
69 /**
70  * Use Texture::peek() to construct a TexturePeeker.
71  *
72  * This constructor is called only by Texture::peek(), and assumes the
73  * texture's lock is already held.
74  */
75 TexturePeeker::
76 TexturePeeker(Texture *tex, Texture::CData *cdata) {
77  // Simple ram images are possible if it is a 2-d texture.
78  if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
79  // Get the regular RAM image if it is available.
80  _image = tex->do_get_ram_image(cdata);
81  _x_size = cdata->_x_size;
82  _y_size = cdata->_y_size;
83  _z_size = cdata->_z_size;
84  _pixel_width = cdata->_component_width * cdata->_num_components;
85  _format = cdata->_format;
86  _component_type = cdata->_component_type;
87  }
88  else if (!cdata->_simple_ram_image._image.empty()) {
89  // Get the simple RAM image if *that* is available.
90  _image = cdata->_simple_ram_image._image;
91  _x_size = cdata->_simple_x_size;
92  _y_size = cdata->_simple_y_size;
93  _z_size = 1;
94 
95  _pixel_width = 4;
96  _format = Texture::F_rgba;
97  _component_type = Texture::T_unsigned_byte;
98  }
99  else {
100  // Failing that, reload and get the uncompressed RAM image.
101  _image = tex->do_get_uncompressed_ram_image(cdata);
102  _x_size = cdata->_x_size;
103  _y_size = cdata->_y_size;
104  _z_size = cdata->_z_size;
105  _pixel_width = cdata->_component_width * cdata->_num_components;
106  _format = cdata->_format;
107  _component_type = cdata->_component_type;
108  }
109 
110  if (_image.is_null()) {
111  return;
112  }
113 
114  if (Texture::is_integer(_format)) {
115  switch (_component_type) {
116  case Texture::T_unsigned_byte:
117  _get_component = get_unsigned_byte_i;
118  break;
119 
120  case Texture::T_unsigned_short:
121  _get_component = get_unsigned_short_i;
122  break;
123 
124  case Texture::T_unsigned_int:
125  _get_component = get_unsigned_int_i;
126  break;
127 
128  case Texture::T_byte:
129  _get_component = get_signed_byte_i;
130  break;
131 
132  case Texture::T_short:
133  _get_component = get_signed_short_i;
134  break;
135 
136  case Texture::T_int:
137  _get_component = get_signed_int_i;
138  break;
139 
140  default:
141  // Not supported.
142  _image.clear();
143  return;
144  }
145  }
146  else {
147  switch (_component_type) {
148  case Texture::T_unsigned_byte:
149  _get_component = Texture::get_unsigned_byte;
150  break;
151 
152  case Texture::T_unsigned_short:
153  _get_component = Texture::get_unsigned_short;
154  break;
155 
156  case Texture::T_unsigned_int:
157  _get_component = Texture::get_unsigned_int;
158  break;
159 
160  case Texture::T_float:
161  _get_component = Texture::get_float;
162  break;
163 
164  case Texture::T_half_float:
165  _get_component = Texture::get_half_float;
166  break;
167 
168  case Texture::T_unsigned_int_24_8:
169  _get_component = Texture::get_unsigned_int_24;
170  break;
171 
172  default:
173  // Not supported.
174  _image.clear();
175  return;
176  }
177  }
178 
179  switch (_format) {
180  case Texture::F_depth_stencil:
181  case Texture::F_depth_component:
182  case Texture::F_depth_component16:
183  case Texture::F_depth_component24:
184  case Texture::F_depth_component32:
185  case Texture::F_red:
186  case Texture::F_r16:
187  case Texture::F_r32:
188  case Texture::F_r32i:
189  case Texture::F_r16i:
190  _get_texel = get_texel_r;
191  break;
192 
193  case Texture::F_green:
194  _get_texel = get_texel_g;
195  break;
196 
197  case Texture::F_blue:
198  _get_texel = get_texel_b;
199  break;
200 
201  case Texture::F_alpha:
202  _get_texel = get_texel_a;
203  break;
204 
205  case Texture::F_luminance:
206  case Texture::F_sluminance:
207  _get_texel = get_texel_l;
208  break;
209 
210  case Texture::F_luminance_alpha:
211  case Texture::F_sluminance_alpha:
212  case Texture::F_luminance_alphamask:
213  _get_texel = get_texel_la;
214  break;
215 
216  case Texture::F_rg:
217  case Texture::F_rg8i:
218  case Texture::F_rg16:
219  case Texture::F_rg16i:
220  case Texture::F_rg32:
221  case Texture::F_rg32i:
222  _get_texel = get_texel_rg;
223  break;
224 
225  case Texture::F_rgb:
226  case Texture::F_rgb5:
227  case Texture::F_rgb8:
228  case Texture::F_rgb8i:
229  case Texture::F_rgb12:
230  case Texture::F_rgb16:
231  case Texture::F_rgb16i:
232  case Texture::F_rgb332:
233  case Texture::F_r11_g11_b10:
234  case Texture::F_rgb9_e5:
235  case Texture::F_rgb32:
236  case Texture::F_rgb32i:
237  _get_texel = get_texel_rgb;
238  break;
239 
240  case Texture::F_rgba:
241  case Texture::F_rgbm:
242  case Texture::F_rgba4:
243  case Texture::F_rgba5:
244  case Texture::F_rgba8:
245  case Texture::F_rgba8i:
246  case Texture::F_rgba12:
247  case Texture::F_rgba16:
248  case Texture::F_rgba16i:
249  case Texture::F_rgba32:
250  case Texture::F_rgba32i:
251  case Texture::F_rgb10_a2:
252  _get_texel = get_texel_rgba;
253  break;
254 
255  case Texture::F_srgb:
256  if (_component_type == Texture::T_unsigned_byte) {
257  _get_texel = get_texel_srgb;
258  } else {
259  gobj_cat.error()
260  << "sRGB texture should have component type T_unsigned_byte\n";
261  }
262  break;
263 
264  case Texture::F_srgb_alpha:
265  if (_component_type == Texture::T_unsigned_byte) {
266  _get_texel = get_texel_srgba;
267  } else {
268  gobj_cat.error()
269  << "sRGB texture should have component type T_unsigned_byte\n";
270  }
271  break;
272 
273  default:
274  // Not supported.
275  gobj_cat.error() << "Unsupported texture peeker format: "
276  << Texture::format_format(_format) << std::endl;
277  _image.clear();
278  return;
279  }
280 
281  _is_cube = (cdata->_texture_type == Texture::TT_cube_map ||
282  cdata->_texture_type == Texture::TT_cube_map_array);
283 }
284 
285 /**
286  * Fills "color" with the RGBA color of the texel at point (u, v).
287  *
288  * The texel color is determined via nearest-point sampling (no filtering of
289  * adjacent pixels), regardless of the filter type associated with the
290  * texture. u, v, and w will wrap around regardless of the texture's wrap
291  * mode.
292  */
294 lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
295  if (!_is_cube) {
296  int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
297  int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
298  fetch_pixel(color, x, y);
299  }
300  else {
301  lookup(color, u, v, 0);
302  }
303 }
304 
305 /**
306  * Fills "color" with the RGBA color of the texel at point (u, v, w).
307  *
308  * The texel color is determined via nearest-point sampling (no filtering of
309  * adjacent pixels), regardless of the filter type associated with the
310  * texture. u, v, and w will wrap around regardless of the texture's wrap
311  * mode.
312  */
314 lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const {
315  if (!_is_cube) {
316  int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
317  int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
318  int z = int((w - cfloor(w)) * (PN_stdfloat)_z_size) % _z_size;
319 
320  nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size &&
321  z >= 0 && z < _z_size);
322  const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
323 
324  (*_get_texel)(color, p, _get_component);
325  }
326  else {
327  PN_stdfloat absu = fabs(u),
328  absv = fabs(v),
329  absw = fabs(w);
330  PN_stdfloat magnitude;
331  PN_stdfloat u2d, v2d;
332  int z;
333 
334  // The following was pulled from:
335  // https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/
336  if (absw >= absu && absw >= absv) {
337  z = 4 + (w < 0.0);
338  magnitude = 0.5 / absw;
339  u2d = w < 0.0 ? -u : u;
340  v2d = -v;
341  }
342  else if (absv >= absu) {
343  z = 2 + (v < 0.0);
344  magnitude = 0.5 / absv;
345  u2d = u;
346  v2d = v < 0.0 ? -w : w;
347  }
348  else {
349  z = 0 + (u < 0.0);
350  magnitude = 0.5 / absu;
351  u2d = u < 0.0 ? w : -w;
352  v2d = -v;
353  }
354  u2d = u2d * magnitude + 0.5;
355  v2d = v2d * magnitude + 0.5;
356 
357  int x = int((u2d - cfloor(u2d)) * (PN_stdfloat)_x_size) % _x_size;
358  int y = int((v2d - cfloor(v2d)) * (PN_stdfloat)_y_size) % _y_size;
359  fetch_pixel(color, x, y, z);
360  }
361 }
362 
363 /**
364  * Works like TexturePeeker::lookup(), but instead uv-coordinates integer
365  * coordinates are used.
366  */
368 fetch_pixel(LColor &color, int x, int y) const {
369  nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
370  const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
371  (*_get_texel)(color, p, _get_component);
372 }
373 
374 /**
375  * Works like TexturePeeker::lookup(), but instead uv-coordinates integer
376  * coordinates are used.
377  */
379 fetch_pixel(LColor &color, int x, int y, int z) const {
380  nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size && z >= 0 && z < _z_size);
381  const unsigned char *p = _image.p() + ((z * _y_size + y) * _x_size + x) * _pixel_width;
382  (*_get_texel)(color, p, _get_component);
383 }
384 
385 /**
386  * Performs a bilinear lookup to retrieve the color value stored at the uv
387  * coordinate (u, v).
388  *
389  * In case the point is outside of the uv range, color is set to zero,
390  * and false is returned. Otherwise true is returned.
391  */
393 lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
394  color = LColor::zero();
395 
396  u = u * _x_size - 0.5;
397  v = v * _y_size - 0.5;
398 
399  int min_u = int(floor(u));
400  int min_v = int(floor(v));
401 
402  PN_stdfloat frac_u = u - min_u;
403  PN_stdfloat frac_v = v - min_v;
404 
405  LColor p00(LColor::zero()), p01(LColor::zero()), p10(LColor::zero()), p11(LColor::zero());
406  PN_stdfloat w00 = 0.0, w01 = 0.0, w10 = 0.0, w11 = 0.0;
407 
408  if (has_pixel(min_u, min_v)) {
409  w00 = (1.0 - frac_v) * (1.0 - frac_u);
410  fetch_pixel(p00, min_u, min_v);
411  }
412  if (has_pixel(min_u + 1, min_v)) {
413  w10 = (1.0 - frac_v) * frac_u;
414  fetch_pixel(p10, min_u + 1, min_v);
415  }
416  if (has_pixel(min_u, min_v + 1)) {
417  w01 = frac_v * (1.0 - frac_u);
418  fetch_pixel(p01, min_u, min_v + 1);
419  }
420  if (has_pixel(min_u + 1, min_v + 1)) {
421  w11 = frac_v * frac_u;
422  fetch_pixel(p11, min_u + 1, min_v + 1);
423  }
424 
425  PN_stdfloat net_w = w00 + w01 + w10 + w11;
426  if (net_w == 0.0) {
427  return false;
428  }
429 
430  color = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11) / net_w;
431  return true;
432 }
433 
434 /**
435  * Fills "color" with the average RGBA color of the texels within the
436  * rectangle defined by the specified coordinate range.
437  *
438  * The texel color is linearly filtered over the entire region. u, v, and w
439  * will wrap around regardless of the texture's wrap mode.
440  */
442 filter_rect(LColor &color,
443  PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat max_u, PN_stdfloat max_v) const {
444  int min_x, max_x;
445  init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
446 
447  int min_y, max_y;
448  init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
449 
450  color.set(0.0f, 0.0f, 0.0f, 0.0f);
451  PN_stdfloat net = 0.0f;
452  accum_filter_y(color, net, 0,
453  min_x, max_x, min_u, max_u,
454  min_y, max_y, min_v, max_v,
455  1.0f);
456 
457  if (net != 0.0f) {
458  color /= net;
459  }
460 }
461 
462 /**
463  * Fills "color" with the average RGBA color of the texels within the
464  * rectangle defined by the specified coordinate range.
465  *
466  * The texel color is linearly filtered over the entire region. u, v, and w
467  * will wrap around regardless of the texture's wrap mode.
468  */
470 filter_rect(LColor &color,
471  PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat min_w,
472  PN_stdfloat max_u, PN_stdfloat max_v, PN_stdfloat max_w) const {
473  int min_x, max_x;
474  init_rect_minmax(min_x, max_x, min_u, max_u, _x_size);
475 
476  int min_y, max_y;
477  init_rect_minmax(min_y, max_y, min_v, max_v, _y_size);
478 
479  int min_z, max_z;
480  init_rect_minmax(min_z, max_z, min_w, max_w, _z_size);
481 
482  color.set(0.0f, 0.0f, 0.0f, 0.0f);
483  PN_stdfloat net = 0.0f;
484  accum_filter_z(color, net,
485  min_x, max_x, min_u, max_u,
486  min_y, max_y, min_v, max_v,
487  min_z, max_z, min_w, max_w);
488 
489  if (net != 0.0f) {
490  color /= net;
491  }
492 }
493 
494 /**
495  * Sanity-checks min_u, max_u and computes min_x and min_y based on them.
496  * Also works for y and z.
497  */
498 void TexturePeeker::
499 init_rect_minmax(int &min_x, int &max_x, PN_stdfloat &min_u, PN_stdfloat &max_u,
500  int x_size) {
501  if (min_u > max_u) {
502  PN_stdfloat t = min_u;
503  min_u = max_u;
504  max_u = t;
505  }
506  if (max_u - min_u >= 1.0f) {
507  min_u = 0.0f;
508  max_u = 1.0f;
509  }
510  min_x = (int)cfloor(min_u * (PN_stdfloat)x_size);
511  max_x = (int)cceil(max_u * (PN_stdfloat)x_size);
512  nassertv(min_x <= max_x);
513 }
514 
515 /**
516  * Accumulates the range of pixels from min_z to max_z.
517  */
518 void TexturePeeker::
519 accum_filter_z(LColor &color, PN_stdfloat &net,
520  int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
521  int min_y, int max_y, PN_stdfloat min_v, PN_stdfloat max_v,
522  int min_z, int max_z, PN_stdfloat min_w, PN_stdfloat max_w) const {
523  nassertv(min_z >= 0 && min_z <= _z_size &&
524  max_z >= 0 && max_z <= _z_size);
525  int zi = min_z;
526 
527  if (min_z >= max_z - 1) {
528  // Within a single texel.
529  accum_filter_y(color, net, zi % _z_size,
530  min_x, max_x, min_u, max_u,
531  min_y, max_y, min_v, max_v,
532  1.0f);
533 
534  } else {
535  // First part-texel.
536  PN_stdfloat w = (min_z + 1) - min_w * _z_size;
537  accum_filter_y(color, net, zi % _z_size,
538  min_x, max_x, min_u, max_u,
539  min_y, max_y, min_v, max_v,
540  w);
541  int zs = max_z - 1;
542 
543  // Run of full texels.
544  zi = min_z + 1;
545  while (zi < zs) {
546  accum_filter_y(color, net, zi % _z_size,
547  min_x, max_x, min_u, max_u,
548  min_y, max_y, min_v, max_v,
549  1.0f);
550  ++zi;
551  }
552 
553  // Last part-texel.
554  w = max_w * _z_size - (max_z - 1);
555  accum_filter_y(color, net, zi % _z_size,
556  min_x, max_x, min_u, max_u,
557  min_y, max_y, min_v, max_v,
558  w);
559  }
560 }
561 
562 /**
563  * Accumulates the range of pixels from min_y to max_y.
564  */
565 void TexturePeeker::
566 accum_filter_y(LColor &color, PN_stdfloat &net, int zi,
567  int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
568  int min_y, int max_y, PN_stdfloat min_v, PN_stdfloat max_v,
569  PN_stdfloat weight) const {
570  nassertv(zi >= 0 && zi < _z_size);
571  nassertv(min_y >= 0 && min_y <= _y_size &&
572  max_y >= 0 && max_y <= _y_size);
573  int yi = min_y;
574 
575  if (min_y >= max_y - 1) {
576  // Within a single texel.
577  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
578 
579  } else {
580  // First part-texel.
581  PN_stdfloat w = (min_y + 1) - min_v * _y_size;
582  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
583  int ys = max_y - 1;
584 
585  // Run of full texels.
586  yi = min_y + 1;
587  while (yi < ys) {
588  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight);
589  ++yi;
590  }
591 
592  // Last part-texel.
593  w = max_v * _y_size - (max_y - 1);
594  accum_filter_x(color, net, yi % _y_size, zi, min_x, max_x, min_u, max_u, weight * w);
595  }
596 }
597 
598 /**
599  * Accumulates the range of pixels from min_x to max_x.
600  */
601 void TexturePeeker::
602 accum_filter_x(LColor &color, PN_stdfloat &net, int yi, int zi,
603  int min_x, int max_x, PN_stdfloat min_u, PN_stdfloat max_u,
604  PN_stdfloat weight) const {
605  nassertv(yi >= 0 && yi < _y_size && zi >= 0 && zi < _z_size);
606  nassertv(min_x >= 0 && min_x <= _x_size &&
607  max_x >= 0 && max_x <= _x_size);
608 
609  // Compute the p corresponding to min_x.
610  int xi = min_x % _x_size;
611  const unsigned char *p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
612 
613  if (min_x >= max_x - 1) {
614  // Within a single texel.
615  accum_texel(color, net, p, weight);
616 
617  } else {
618  // First part-texel.
619  PN_stdfloat w = (min_x + 1) - min_u * _x_size;
620  accum_texel(color, net, p, weight * w);
621  int xs = max_x - 1;
622 
623  // Run of full texels.
624  xi = min_x + 1;
625  while (xi < xs) {
626  if (xi == _x_size) {
627  xi = 0;
628  p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
629  xs -= _x_size;
630  }
631  accum_texel(color, net, p, weight);
632  ++xi;
633  }
634 
635  // Last part-texel.
636  if (xi == _x_size) {
637  xi = 0;
638  p = _image.p() + (zi * _x_size * _y_size + yi * _x_size + xi) * _pixel_width;
639  }
640  w = max_u * _x_size - (max_x - 1);
641  accum_texel(color, net, p, weight * w);
642  }
643 }
644 
645 /**
646  * Accumulates a single texel into the total computed by filter_rect().
647  */
648 void TexturePeeker::
649 accum_texel(LColor &color, PN_stdfloat &net, const unsigned char *&p, PN_stdfloat weight) const {
650  LColor c;
651  (*_get_texel)(c, p, _get_component);
652  color += c * weight;
653  net += weight;
654 }
655 
656 /**
657  * Gets the color of the texel at byte p, given that the texture is in format
658  * F_red.
659  */
660 void TexturePeeker::
661 get_texel_r(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
662  color[0] = (*get_component)(p);
663  color[1] = 0.0f;
664  color[2] = 0.0f;
665  color[3] = 1.0f;
666 }
667 
668 /**
669  * Gets the color of the texel at byte p, given that the texture is in format
670  * F_green.
671  */
672 void TexturePeeker::
673 get_texel_g(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
674  color[0] = 0.0f;
675  color[1] = (*get_component)(p);
676  color[2] = 0.0f;
677  color[3] = 1.0f;
678 }
679 
680 /**
681  * Gets the color of the texel at byte p, given that the texture is in format
682  * F_blue.
683  */
684 void TexturePeeker::
685 get_texel_b(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
686  color[0] = 0.0f;
687  color[1] = 0.0f;
688  color[2] = (*get_component)(p);
689  color[3] = 1.0f;
690 }
691 
692 /**
693  * Gets the color of the texel at byte p, given that the texture is in format
694  * F_alpha.
695  */
696 void TexturePeeker::
697 get_texel_a(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
698  color[0] = 0.0f;
699  color[1] = 0.0f;
700  color[2] = 1.0f;
701  color[3] = (*get_component)(p);
702 }
703 
704 /**
705  * Gets the color of the texel at byte p, given that the texture is in format
706  * F_luminance.
707  */
708 void TexturePeeker::
709 get_texel_l(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
710  color[0] = (*get_component)(p);
711  color[1] = color[0];
712  color[2] = color[0];
713  color[3] = 1.0f;
714 }
715 
716 /**
717  * Gets the color of the texel at byte p, given that the texture is in format
718  * F_luminance_alpha or similar.
719  */
720 void TexturePeeker::
721 get_texel_la(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
722  color[0] = (*get_component)(p);
723  color[1] = color[0];
724  color[2] = color[0];
725  color[3] = (*get_component)(p);
726 }
727 
728 /**
729  * Gets the color of the texel at byte p, given that the texture is in format
730  * F_rg or similar.
731  */
732 void TexturePeeker::
733 get_texel_rg(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
734  color[0] = (*get_component)(p);
735  color[1] = (*get_component)(p);
736  color[2] = 0.0f;
737  color[3] = 1.0f;
738 }
739 
740 /**
741  * Gets the color of the texel at byte p, given that the texture is in format
742  * F_rgb or similar.
743  */
744 void TexturePeeker::
745 get_texel_rgb(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
746  color[2] = (*get_component)(p);
747  color[1] = (*get_component)(p);
748  color[0] = (*get_component)(p);
749  color[3] = 1.0f;
750 }
751 
752 /**
753  * Gets the color of the texel at byte p, given that the texture is in format
754  * F_rgba or similar.
755  */
756 void TexturePeeker::
757 get_texel_rgba(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
758  color[2] = (*get_component)(p);
759  color[1] = (*get_component)(p);
760  color[0] = (*get_component)(p);
761  color[3] = (*get_component)(p);
762 }
763 
764 /**
765  * Gets the color of the texel at byte p, given that the texture is in format
766  * F_srgb or similar.
767  */
768 void TexturePeeker::
769 get_texel_srgb(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
770  color[2] = decode_sRGB_float(*p++);
771  color[1] = decode_sRGB_float(*p++);
772  color[0] = decode_sRGB_float(*p++);
773  color[3] = 1.0f;
774 }
775 
776 /**
777  * Gets the color of the texel at byte p, given that the texture is in format
778  * F_srgb_alpha or similar.
779  */
780 void TexturePeeker::
781 get_texel_srgba(LColor &color, const unsigned char *&p, GetComponentFunc *get_component) {
782  color[2] = decode_sRGB_float(*p++);
783  color[1] = decode_sRGB_float(*p++);
784  color[0] = decode_sRGB_float(*p++);
785  color[3] = (*get_component)(p);
786 }
const Element * p() const
Function p() is similar to the function from ConstPointerTo.
void clear()
To empty the PTA, use the clear() method, since assignment to NULL is problematic (given the ambiguit...
constexpr bool is_null() const
Returns true if the PointerTo is a NULL pointer, false otherwise.
Definition: pointerToVoid.I:27
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const
Fills "color" with the RGBA color of the texel at point (u, v).
void fetch_pixel(LColor &color, int x, int y) const
Works like TexturePeeker::lookup(), but instead uv-coordinates integer coordinates are used.
bool has_pixel(int x, int y) const
Returns whether a given coordinate is inside of the texture dimensions.
Definition: texturePeeker.I:56
bool lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const
Performs a bilinear lookup to retrieve the color value stored at the uv coordinate (u,...
void filter_rect(LColor &color, PN_stdfloat min_u, PN_stdfloat min_v, PN_stdfloat max_u, PN_stdfloat max_v) const
Fills "color" with the average RGBA color of the texels within the rectangle defined by the specified...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
static bool is_integer(Format format)
Returns true if the indicated format is an integer format, false otherwise.
Definition: texture.cxx:2695
static std::string format_format(Format f)
Returns the indicated Format converted to a string word.
Definition: texture.cxx:2188
BEGIN_PUBLISH EXPCL_PANDA_PNMIMAGE float decode_sRGB_float(unsigned char val)
Decodes the sRGB-encoded unsigned char value to a linearized float in the range 0-1.
Definition: convert_srgb.I:18
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.