Panda3D
Loading...
Searching...
No Matches
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
17static double get_unsigned_byte_i(const unsigned char *&p) {
18 return *p++;
19}
20
21static double get_signed_byte_i(const unsigned char *&p) {
22 return *(signed char *)p++;
23}
24
25static 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
35static 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
45static 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
57static 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 */
75TexturePeeker::
76TexturePeeker(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 */
294lookup(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 */
314lookup(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 of uv-coordinates, integer
365 * coordinates are used.
366 */
368fetch_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 of uv-coordinates, integer
376 * coordinates are used.
377 */
379fetch_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 */
393lookup_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 * must be in the range [0, 1].
440 */
442filter_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 * must be in the range [0, 1].
468 */
470filter_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 */
498void TexturePeeker::
499init_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 */
518void TexturePeeker::
519accum_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 */
565void TexturePeeker::
566accum_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 */
601void TexturePeeker::
602accum_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 */
648void TexturePeeker::
649accum_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 */
660void TexturePeeker::
661get_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 */
672void TexturePeeker::
673get_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 */
684void TexturePeeker::
685get_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 */
696void TexturePeeker::
697get_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 */
708void TexturePeeker::
709get_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 */
720void TexturePeeker::
721get_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 */
732void TexturePeeker::
733get_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 */
744void TexturePeeker::
745get_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 */
756void TexturePeeker::
757get_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 */
768void TexturePeeker::
769get_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 */
780void TexturePeeker::
781get_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.
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 of 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.
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:72
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.