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