62(
"texture-quality-level", Texture::QL_normal,
63 PRC_DESC(
"This specifies a global quality level for all textures. You "
64 "may specify either fastest, normal, or best. This actually "
65 "affects the meaning of Texture::set_quality_level(QL_default), "
66 "so it may be overridden on a per-texture basis. This generally "
67 "only has an effect when using the tinydisplay software renderer; "
68 "it has little or no effect on normal, hardware-accelerated "
69 "renderers. See Texture::set_quality_level()."));
74AutoTextureScale Texture::_textures_power_2 = ATS_unspecified;
79#define DDS_MAGIC 0x20534444
83#define DDSD_CAPS 0x00000001
84#define DDSD_HEIGHT 0x00000002
85#define DDSD_WIDTH 0x00000004
86#define DDSD_PITCH 0x00000008
87#define DDSD_PIXELFORMAT 0x00001000
88#define DDSD_MIPMAPCOUNT 0x00020000
89#define DDSD_LINEARSIZE 0x00080000
90#define DDSD_DEPTH 0x00800000
93#define DDPF_ALPHAPIXELS 0x00000001
94#define DDPF_FOURCC 0x00000004
95#define DDPF_INDEXED 0x00000020
96#define DDPF_RGB 0x00000040
99#define DDSCAPS_COMPLEX 0x00000008
100#define DDSCAPS_TEXTURE 0x00001000
101#define DDSCAPS_MIPMAP 0x00400000
104#define DDSCAPS2_CUBEMAP 0x00000200
105#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
106#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
107#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
108#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
109#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
110#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
111#define DDSCAPS2_VOLUME 0x00200000
113struct DDSPixelFormat {
114 unsigned int pf_size;
115 unsigned int pf_flags;
116 unsigned int four_cc;
117 unsigned int rgb_bitcount;
131 unsigned int dds_magic;
132 unsigned int dds_size;
133 unsigned int dds_flags;
138 unsigned int num_levels;
147 KTX_UNSIGNED_BYTE = 0x1401,
149 KTX_UNSIGNED_SHORT = 0x1403,
151 KTX_UNSIGNED_INT = 0x1405,
153 KTX_HALF_FLOAT = 0x140B,
154 KTX_UNSIGNED_BYTE_3_3_2 = 0x8032,
155 KTX_UNSIGNED_SHORT_4_4_4_4 = 0x8033,
156 KTX_UNSIGNED_SHORT_5_5_5_1 = 0x8034,
157 KTX_UNSIGNED_INT_8_8_8_8 = 0x8035,
158 KTX_UNSIGNED_INT_10_10_10_2 = 0x8036,
159 KTX_UNSIGNED_BYTE_2_3_3_REV = 0x8362,
160 KTX_UNSIGNED_SHORT_5_6_5 = 0x8363,
161 KTX_UNSIGNED_SHORT_5_6_5_REV = 0x8364,
162 KTX_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
163 KTX_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
164 KTX_UNSIGNED_INT_8_8_8_8_REV = 0x8367,
165 KTX_UNSIGNED_INT_2_10_10_10_REV = 0x8368,
166 KTX_UNSIGNED_INT_24_8 = 0x84FA,
167 KTX_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
168 KTX_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
169 KTX_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD,
174 KTX_ALPHA12 = 0x803D,
175 KTX_ALPHA16 = 0x803E,
176 KTX_ALPHA16_SNORM = 0x9018,
179 KTX_ALPHA8_SNORM = 0x9014,
180 KTX_ALPHA_SNORM = 0x9010,
182 KTX_BGR_INTEGER = 0x8D9A,
184 KTX_BGRA_INTEGER = 0x8D9B,
186 KTX_BLUE_INTEGER = 0x8D96,
187 KTX_COLOR_INDEX = 0x1900,
188 KTX_DEPTH24_STENCIL8 = 0x88F0,
189 KTX_DEPTH32F_STENCIL8 = 0x8CAD,
190 KTX_DEPTH_COMPONENT = 0x1902,
191 KTX_DEPTH_COMPONENT16 = 0x81A5,
192 KTX_DEPTH_COMPONENT24 = 0x81A6,
193 KTX_DEPTH_COMPONENT32 = 0x81A7,
194 KTX_DEPTH_COMPONENT32F = 0x8CAC,
195 KTX_DEPTH_STENCIL = 0x84F9,
197 KTX_GREEN_INTEGER = 0x8D95,
198 KTX_INTENSITY = 0x8049,
199 KTX_INTENSITY12 = 0x804C,
200 KTX_INTENSITY16 = 0x804D,
201 KTX_INTENSITY16_SNORM = 0x901B,
202 KTX_INTENSITY4 = 0x804A,
203 KTX_INTENSITY8 = 0x804B,
204 KTX_INTENSITY8_SNORM = 0x9017,
205 KTX_INTENSITY_SNORM = 0x9013,
206 KTX_LUMINANCE = 0x1909,
207 KTX_LUMINANCE12 = 0x8041,
208 KTX_LUMINANCE12_ALPHA12 = 0x8047,
209 KTX_LUMINANCE12_ALPHA4 = 0x8046,
210 KTX_LUMINANCE16 = 0x8042,
211 KTX_LUMINANCE16_ALPHA16 = 0x8048,
212 KTX_LUMINANCE16_ALPHA16_SNORM = 0x901A,
213 KTX_LUMINANCE16_SNORM = 0x9019,
214 KTX_LUMINANCE4 = 0x803F,
215 KTX_LUMINANCE4_ALPHA4 = 0x8043,
216 KTX_LUMINANCE6_ALPHA2 = 0x8044,
217 KTX_LUMINANCE8 = 0x8040,
218 KTX_LUMINANCE8_ALPHA8 = 0x8045,
219 KTX_LUMINANCE8_ALPHA8_SNORM = 0x9016,
220 KTX_LUMINANCE8_SNORM = 0x9015,
221 KTX_LUMINANCE_ALPHA = 0x190A,
222 KTX_LUMINANCE_ALPHA_SNORM = 0x9012,
223 KTX_LUMINANCE_SNORM = 0x9011,
224 KTX_R11F_G11F_B10F = 0x8C3A,
226 KTX_R16_SNORM = 0x8F98,
233 KTX_R3_G3_B2 = 0x2A10,
235 KTX_R8_SNORM = 0x8F94,
239 KTX_RED_INTEGER = 0x8D94,
240 KTX_RED_SNORM = 0x8F90,
243 KTX_RG16_SNORM = 0x8F99,
251 KTX_RG8_SNORM = 0x8F95,
254 KTX_RG_INTEGER = 0x8228,
255 KTX_RG_SNORM = 0x8F91,
258 KTX_RGB10_A2 = 0x8059,
261 KTX_RGB16_SNORM = 0x8F9A,
264 KTX_RGB16UI = 0x8D77,
268 KTX_RGB32UI = 0x8D71,
271 KTX_RGB5_A1 = 0x8057,
273 KTX_RGB8_SNORM = 0x8F96,
276 KTX_RGB9_E5 = 0x8C3D,
277 KTX_RGB_INTEGER = 0x8D98,
278 KTX_RGB_SNORM = 0x8F92,
282 KTX_RGBA16_SNORM = 0x8F9B,
283 KTX_RGBA16F = 0x881A,
284 KTX_RGBA16I = 0x8D88,
285 KTX_RGBA16UI = 0x8D76,
287 KTX_RGBA32F = 0x8814,
288 KTX_RGBA32I = 0x8D82,
289 KTX_RGBA32UI = 0x8D70,
292 KTX_RGBA8_SNORM = 0x8F97,
294 KTX_RGBA8UI = 0x8D7C,
295 KTX_RGBA_INTEGER = 0x8D99,
296 KTX_RGBA_SNORM = 0x8F93,
297 KTX_SLUMINANCE = 0x8C46,
298 KTX_SLUMINANCE8 = 0x8C47,
299 KTX_SLUMINANCE8_ALPHA8 = 0x8C45,
300 KTX_SLUMINANCE_ALPHA = 0x8C44,
303 KTX_SRGB8_ALPHA8 = 0x8C43,
304 KTX_SRGB_ALPHA = 0x8C42,
305 KTX_STENCIL_INDEX = 0x1901,
306 KTX_STENCIL_INDEX1 = 0x8D46,
307 KTX_STENCIL_INDEX16 = 0x8D49,
308 KTX_STENCIL_INDEX4 = 0x8D47,
309 KTX_STENCIL_INDEX8 = 0x8D48,
312enum KTXCompressedFormat {
313 KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2 = 0x8C72,
314 KTX_COMPRESSED_LUMINANCE_LATC1 = 0x8C70,
315 KTX_COMPRESSED_R11_EAC = 0x9270,
316 KTX_COMPRESSED_RED = 0x8225,
317 KTX_COMPRESSED_RED_RGTC1 = 0x8DBB,
318 KTX_COMPRESSED_RG = 0x8226,
319 KTX_COMPRESSED_RG11_EAC = 0x9272,
320 KTX_COMPRESSED_RG_RGTC2 = 0x8DBD,
321 KTX_COMPRESSED_RGB = 0x84ED,
322 KTX_COMPRESSED_RGB8_ETC2 = 0x9274,
323 KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276,
324 KTX_COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E,
325 KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F,
326 KTX_COMPRESSED_RGB_FXT1_3DFX = 0x86B0,
327 KTX_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01,
328 KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00,
329 KTX_COMPRESSED_RGB_S3TC_DXT1 = 0x83F0,
330 KTX_COMPRESSED_RGBA = 0x84EE,
331 KTX_COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
332 KTX_COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C,
333 KTX_COMPRESSED_RGBA_FXT1_3DFX = 0x86B1,
334 KTX_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03,
335 KTX_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG = 0x9137,
336 KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02,
337 KTX_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG = 0x9138,
338 KTX_COMPRESSED_RGBA_S3TC_DXT1 = 0x83F1,
339 KTX_COMPRESSED_RGBA_S3TC_DXT3 = 0x83F2,
340 KTX_COMPRESSED_RGBA_S3TC_DXT5 = 0x83F3,
341 KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2 = 0x8C73,
342 KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1 = 0x8C71,
343 KTX_COMPRESSED_SIGNED_R11_EAC = 0x9271,
344 KTX_COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC,
345 KTX_COMPRESSED_SIGNED_RG11_EAC = 0x9273,
346 KTX_COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE,
347 KTX_COMPRESSED_SLUMINANCE = 0x8C4A,
348 KTX_COMPRESSED_SLUMINANCE_ALPHA = 0x8C4B,
349 KTX_COMPRESSED_SRGB = 0x8C48,
350 KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279,
351 KTX_COMPRESSED_SRGB8_ETC2 = 0x9275,
352 KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,
353 KTX_COMPRESSED_SRGB_ALPHA = 0x8C49,
354 KTX_COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D,
355 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1 = 0x8A56,
356 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2 = 0x93F0,
357 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1 = 0x8A57,
358 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2 = 0x93F1,
359 KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1 = 0x8C4D,
360 KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3 = 0x8C4E,
361 KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5 = 0x8C4F,
362 KTX_COMPRESSED_SRGB_PVRTC_2BPPV1 = 0x8A54,
363 KTX_COMPRESSED_SRGB_PVRTC_4BPPV1 = 0x8A55,
364 KTX_COMPRESSED_SRGB_S3TC_DXT1 = 0x8C4C,
365 KTX_ETC1_RGB8 = 0x8D64,
366 KTX_ETC1_SRGB8 = 0x88EE,
383 do_set_format(cdata, F_rgb);
384 do_set_component_type(cdata, T_unsigned_byte);
393 _cycler(copy._cycler),
394 _lock(copy.get_name()),
404operator = (
const Texture ©) {
405 Namable::operator = (copy);
406 _cycler = copy._cycler;
415 nassertv(!_reloading);
427 do_setup_texture(cdata, TT_cube_map, size, size, 6, T_unsigned_byte, F_rgb);
428 PTA_uchar image = do_make_ram_image(cdata);
429 cdata->_keep_ram_image =
true;
431 cdata->inc_image_modified();
432 cdata->inc_properties_modified();
434 PN_stdfloat half_size = (PN_stdfloat)size * 0.5f;
435 PN_stdfloat center = half_size - 0.5f;
438 (127.5f, 0.0f, 0.0f, 0.0f,
439 0.0f, 127.5f, 0.0f, 0.0f,
440 0.0f, 0.0f, 127.5f, 0.0f,
441 127.5f, 127.5f, 127.5f, 1.0f);
443 unsigned char *p = image;
447 for (yi = 0; yi < size; ++yi) {
448 for (xi = 0; xi < size; ++xi) {
449 LVector3 vec(half_size, center - yi, center - xi);
451 vec = scale.xform_point(vec);
453 *p++ = (
unsigned char)vec[2];
454 *p++ = (
unsigned char)vec[1];
455 *p++ = (
unsigned char)vec[0];
460 for (yi = 0; yi < size; ++yi) {
461 for (xi = 0; xi < size; ++xi) {
462 LVector3 vec(-half_size, center - yi, xi - center);
464 vec = scale.xform_point(vec);
465 *p++ = (
unsigned char)vec[2];
466 *p++ = (
unsigned char)vec[1];
467 *p++ = (
unsigned char)vec[0];
472 for (yi = 0; yi < size; ++yi) {
473 for (xi = 0; xi < size; ++xi) {
474 LVector3 vec(xi - center, half_size, yi - center);
476 vec = scale.xform_point(vec);
477 *p++ = (
unsigned char)vec[2];
478 *p++ = (
unsigned char)vec[1];
479 *p++ = (
unsigned char)vec[0];
484 for (yi = 0; yi < size; ++yi) {
485 for (xi = 0; xi < size; ++xi) {
486 LVector3 vec(xi - center, -half_size, center - yi);
488 vec = scale.xform_point(vec);
489 *p++ = (
unsigned char)vec[2];
490 *p++ = (
unsigned char)vec[1];
491 *p++ = (
unsigned char)vec[0];
496 for (yi = 0; yi < size; ++yi) {
497 for (xi = 0; xi < size; ++xi) {
498 LVector3 vec(xi - center, center - yi, half_size);
500 vec = scale.xform_point(vec);
501 *p++ = (
unsigned char)vec[2];
502 *p++ = (
unsigned char)vec[1];
503 *p++ = (
unsigned char)vec[0];
508 for (yi = 0; yi < size; ++yi) {
509 for (xi = 0; xi < size; ++xi) {
510 LVector3 vec(center - xi, center - yi, -half_size);
512 vec = scale.xform_point(vec);
513 *p++ = (
unsigned char)vec[2];
514 *p++ = (
unsigned char)vec[1];
515 *p++ = (
unsigned char)vec[0];
529 do_setup_texture(cdata, TT_1d_texture, 256, 1, 1, T_unsigned_byte, F_alpha);
530 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
531 cdata->_default_sampler.set_minfilter(SamplerState::FT_nearest);
532 cdata->_default_sampler.set_magfilter(SamplerState::FT_nearest);
534 cdata->_compression = CM_off;
536 cdata->inc_image_modified();
537 cdata->inc_properties_modified();
539 PTA_uchar image = do_make_ram_image(cdata);
540 cdata->_keep_ram_image =
true;
542 unsigned char *p = image;
543 for (
int xi = 0; xi < 256; ++xi) {
555 cdata->inc_properties_modified();
556 cdata->inc_image_modified();
557 return do_read(cdata, fullpath,
Filename(), 0, 0, 0, 0,
false,
false,
570 int primary_file_num_channels,
int alpha_file_channel,
574 cdata->inc_properties_modified();
575 cdata->inc_image_modified();
576 return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
577 alpha_file_channel, 0, 0,
false,
false,
590 bool read_pages,
bool read_mipmaps,
593 cdata->inc_properties_modified();
594 cdata->inc_image_modified();
595 return do_read(cdata, fullpath,
Filename(), 0, 0, z, n, read_pages, read_mipmaps,
653 int primary_file_num_channels,
int alpha_file_channel,
654 int z,
int n,
bool read_pages,
bool read_mipmaps,
658 cdata->inc_properties_modified();
659 cdata->inc_image_modified();
660 return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
661 alpha_file_channel, z, n, read_pages, read_mipmaps,
678 size_t pixels = cdata->_x_size * cdata->_y_size * cdata->_z_size;
681 switch (cdata->_format) {
682 case Texture::F_rgb332:
686 case Texture::F_alpha:
688 case Texture::F_green:
689 case Texture::F_blue:
690 case Texture::F_luminance:
691 case Texture::F_sluminance:
696 case Texture::F_luminance_alpha:
697 case Texture::F_luminance_alphamask:
698 case Texture::F_sluminance_alpha:
699 case Texture::F_rgba4:
700 case Texture::F_rgb5:
701 case Texture::F_rgba5:
706 case Texture::F_rgba:
707 case Texture::F_rgbm:
709 case Texture::F_srgb:
715 case Texture::F_color_index:
716 case Texture::F_rgb8:
717 case Texture::F_rgba8:
718 case Texture::F_srgb_alpha:
719 case Texture::F_rgb8i:
720 case Texture::F_rgba8i:
724 case Texture::F_depth_stencil:
728 case Texture::F_depth_component:
729 case Texture::F_depth_component16:
733 case Texture::F_depth_component24:
734 case Texture::F_depth_component32:
738 case Texture::F_rgba12:
739 case Texture::F_rgb12:
743 case Texture::F_rgba32:
744 case Texture::F_rgba32i:
749 case Texture::F_r16i:
750 case Texture::F_rg8i:
753 case Texture::F_rg16:
754 case Texture::F_rg16i:
757 case Texture::F_rgb16:
758 case Texture::F_rgb16i:
759 case Texture::F_rgba16:
760 case Texture::F_rgba16i:
764 case Texture::F_r32i:
769 case Texture::F_rg32:
770 case Texture::F_rg32i:
774 case Texture::F_rgb32:
775 case Texture::F_rgb32i:
779 case Texture::F_r11_g11_b10:
780 case Texture::F_rgb9_e5:
781 case Texture::F_rgb10_a2:
788 gobj_cat.warning() <<
"Unhandled format in estimate_texture_memory(): "
789 << cdata->_format <<
"\n";
792 size_t bytes = pixels * bpp;
794 bytes = (bytes * 4) / 3;
810 _aux_data[key] = aux_data;
819 _aux_data.erase(key);
829 AuxData::const_iterator di;
830 di = _aux_data.find(key);
831 if (di != _aux_data.end()) {
846read_txo(istream &in,
const string &filename) {
848 cdata->inc_properties_modified();
849 cdata->inc_image_modified();
850 return do_read_txo(cdata, in, filename);
861make_from_txo(istream &in,
const string &filename) {
864 if (!din.
open(in, filename)) {
866 <<
"Could not read texture object: " << filename <<
"\n";
873 << filename <<
" is not a texture object file.\n";
877 if (head != _bam_header) {
879 << filename <<
" is not a texture object file.\n";
884 if (!reader.
init()) {
890 if (
object !=
nullptr &&
899 if (
object ==
nullptr) {
901 <<
"Texture object " << filename <<
" is empty.\n";
904 }
else if (!object->
is_of_type(Texture::get_class_type())) {
906 <<
"Texture object " << filename <<
" contains a "
907 <<
object->get_type() <<
", not a Texture.\n";
914 <<
"Unable to fully resolve texture object file.\n";
929write_txo(ostream &out,
const string &filename)
const {
931 return do_write_txo(cdata, out, filename);
944read_dds(istream &in,
const string &filename,
bool header_only) {
946 cdata->inc_properties_modified();
947 cdata->inc_image_modified();
948 return do_read_dds(cdata, in, filename, header_only);
961read_ktx(istream &in,
const string &filename,
bool header_only) {
963 cdata->inc_properties_modified();
964 cdata->inc_image_modified();
965 return do_read_ktx(cdata, in, filename, header_only);
978 RelatedTextures::const_iterator ti;
979 ti = _related_textures.find(suffix);
980 if (ti != _related_textures.end()) {
983 if (cdata->_fullpath.empty()) {
987 main.set_basename_wo_extension(main.get_basename_wo_extension() +
990 if (!cdata->_alpha_fullpath.empty()) {
991 Filename alph = cdata->_alpha_fullpath;
999 cdata->_primary_file_num_channels,
1000 cdata->_alpha_file_channel,
false);
1015 ((
Texture *)
this)->_related_textures.insert(RelatedTextures::value_type(suffix, res));
1029 string format =
upcase(supplied_format);
1032 size_t imgsize = (size_t)cdata->_x_size * (
size_t)cdata->_y_size *
1033 (size_t)cdata->_z_size * (
size_t)cdata->_num_views;
1034 nassertv(image.size() == (
size_t)(cdata->_component_width * format.size() * imgsize));
1037 if ((cdata->_num_components == 1 && format.size() == 1) ||
1038 (cdata->_num_components == 2 && format.size() == 2 && format.at(1) ==
'A' && format.at(0) !=
'A') ||
1039 (cdata->_num_components == 3 && format ==
"BGR") ||
1040 (cdata->_num_components == 4 && format ==
"BGRA")) {
1042 do_set_ram_image(cdata, image);
1047 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * cdata->_num_components * cdata->_component_width, get_class_type());
1050 if (cdata->_component_width == 1) {
1051 if (format ==
"RGBA" && cdata->_num_components == 4) {
1053 for (
int p = 0; p < imgsize; p += 4) {
1054 newdata[p + 2] = image[p ];
1055 newdata[p + 1] = image[p + 1];
1056 newdata[p ] = image[p + 2];
1057 newdata[p + 3] = image[p + 3];
1059 do_set_ram_image(cdata, newdata);
1062 if (format ==
"RGB" && cdata->_num_components == 3) {
1064 for (
int p = 0; p < imgsize; p += 3) {
1065 newdata[p + 2] = image[p ];
1066 newdata[p + 1] = image[p + 1];
1067 newdata[p ] = image[p + 2];
1069 do_set_ram_image(cdata, newdata);
1072 if (format ==
"A" && cdata->_num_components != 3) {
1074 int component = cdata->_num_components - 1;
1075 for (
int p = 0; p < imgsize; ++p) {
1076 newdata[component] = image[p];
1078 do_set_ram_image(cdata, newdata);
1081 for (
int p = 0; p < imgsize; ++p) {
1082 for (uchar s = 0; s < format.size(); ++s) {
1083 signed char component = -1;
1084 if (format.at(s) ==
'B' || (cdata->_num_components <= 2 && format.at(s) !=
'A')) {
1086 }
else if (format.at(s) ==
'G') {
1088 }
else if (format.at(s) ==
'R') {
1090 }
else if (format.at(s) ==
'A') {
1091 if (cdata->_num_components != 3) {
1092 component = cdata->_num_components - 1;
1096 }
else if (format.at(s) ==
'0') {
1098 }
else if (format.at(s) ==
'1') {
1101 gobj_cat.error() <<
"Unexpected component character '"
1102 << format.at(s) <<
"', expected one of RGBA!\n";
1105 if (component >= 0) {
1106 newdata[p * cdata->_num_components + component] = image[p * format.size() + s];
1110 do_set_ram_image(cdata, newdata);
1113 for (
int p = 0; p < imgsize; ++p) {
1114 for (uchar s = 0; s < format.size(); ++s) {
1115 signed char component = -1;
1116 if (format.at(s) ==
'B' || (cdata->_num_components <= 2 && format.at(s) !=
'A')) {
1118 }
else if (format.at(s) ==
'G') {
1120 }
else if (format.at(s) ==
'R') {
1122 }
else if (format.at(s) ==
'A') {
1123 if (cdata->_num_components != 3) {
1124 component = cdata->_num_components - 1;
1128 }
else if (format.at(s) ==
'0') {
1130 }
else if (format.at(s) ==
'1') {
1133 gobj_cat.error() <<
"Unexpected component character '"
1134 << format.at(s) <<
"', expected one of RGBA!\n";
1137 if (component >= 0) {
1138 memcpy((
void*)(newdata + (p * cdata->_num_components + component) * cdata->_component_width),
1139 (
void*)(image + (p * format.size() + s) * cdata->_component_width),
1140 cdata->_component_width);
1144 do_set_ram_image(cdata, newdata);
1155 CDReader cdata(_cycler);
1156 return cdata->_keep_ram_image;
1166 CDReader cdata(_cycler);
1167 return do_has_bam_rawdata(cdata);
1184 CDReader cdata(_cycler);
1185 if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty()) {
1195 int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
1201 if (n >= (
int)cdata->_ram_images.size() || cdata->_ram_images[n]._image.empty()) {
1217 if (n < (
int)cdata->_ram_images.size() && !cdata->_ram_images[n]._image.empty()) {
1218 return cdata->_ram_images[n]._image;
1231 if (n < (
int)cdata->_ram_images.size()) {
1232 return cdata->_ram_images[n]._pointer_image;
1250 nassertv(cdata->_ram_image_compression != CM_off || do_get_expected_ram_mipmap_image_size(cdata, n));
1252 while (n >= (
int)cdata->_ram_images.size()) {
1253 cdata->_ram_images.push_back(RamImage());
1256 cdata->_ram_images[n]._page_size = page_size;
1258 cdata->_ram_images[n]._pointer_image = image;
1259 cdata->inc_image_modified();
1280 if (n >= (
int)cdata->_ram_images.size()) {
1283 cdata->_ram_images[n]._page_size = 0;
1284 cdata->_ram_images[n]._image.clear();
1285 cdata->_ram_images[n]._pointer_image =
nullptr;
1295 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
1296 return cdata->_simple_ram_image._image;
1306 nassertr(cdata->_texture_type == TT_2d_texture, PTA_uchar());
1307 size_t expected_page_size = (size_t)(x_size * y_size * 4);
1309 cdata->_simple_x_size = x_size;
1310 cdata->_simple_y_size = y_size;
1311 cdata->_simple_ram_image._image = PTA_uchar::empty_array(expected_page_size);
1312 cdata->_simple_ram_image._page_size = expected_page_size;
1313 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
1314 cdata->inc_simple_image_modified();
1316 return cdata->_simple_ram_image._image;
1328 if (cdata->_texture_type != TT_2d_texture ||
1329 cdata->_ram_image_compression != CM_off) {
1334 if (!do_store_one(cdata, pnmimage, 0, 0)) {
1339 int x_size = simple_image_size.
get_word(0);
1340 int y_size = simple_image_size.
get_word(1);
1361 did_anything =
false;
1365 int new_x_size = (x_size >> 1);
1366 PNMImage smaller(new_x_size, y_size, 4);
1368 PNMImage bigger(x_size, y_size, 4);
1371 if (compare_images(scaled, bigger)) {
1373 x_size = new_x_size;
1374 did_anything =
true;
1380 int new_y_size = (y_size >> 1);
1381 PNMImage smaller(x_size, new_y_size, 4);
1383 PNMImage bigger(x_size, y_size, 4);
1386 if (compare_images(scaled, bigger)) {
1388 y_size = new_y_size;
1389 did_anything =
true;
1392 }
while (did_anything);
1394 size_t expected_page_size = (size_t)(x_size * y_size * 4);
1395 PTA_uchar image = PTA_uchar::empty_array(expected_page_size, get_class_type());
1396 convert_from_pnmimage(image, expected_page_size, x_size, 0, 0, 0, scaled, 4, 1);
1398 do_set_simple_ram_image(cdata, image, x_size, y_size);
1399 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
1416 CDWriter cdata(_cycler, unlocked_ensure_ram_image(
true));
1419 if (peeker->is_valid()) {
1437 return prepared_objects->enqueue_texture_future(
this);
1447 PreparedViews::const_iterator pvi;
1448 pvi = _prepared_views.find(prepared_objects);
1449 if (pvi != _prepared_views.end()) {
1465 PreparedViews::const_iterator pvi;
1466 pvi = _prepared_views.find(prepared_objects);
1467 if (pvi != _prepared_views.end()) {
1468 const Contexts &contexts = (*pvi).second;
1469 for (
int view = 0; view < cdata->_num_views; ++view) {
1470 Contexts::const_iterator ci;
1471 ci = contexts.find(view);
1472 if (ci == contexts.end()) {
1497 PreparedViews::const_iterator pvi;
1498 size_t total_size = 0;
1499 pvi = _prepared_views.find(prepared_objects);
1500 if (pvi != _prepared_views.end()) {
1501 const Contexts &contexts = (*pvi).second;
1502 for (
int view = 0; view < cdata->_num_views; ++view) {
1503 Contexts::const_iterator ci;
1504 ci = contexts.find(view);
1505 if (ci != contexts.end()) {
1524 PreparedViews::const_iterator pvi;
1525 pvi = _prepared_views.find(prepared_objects);
1526 if (pvi != _prepared_views.end()) {
1527 const Contexts &contexts = (*pvi).second;
1528 for (
int view = 0; view < cdata->_num_views; ++view) {
1529 Contexts::const_iterator ci;
1530 ci = contexts.find(view);
1531 if (ci != contexts.end()) {
1551 PreparedViews::const_iterator pvi;
1552 pvi = _prepared_views.find(prepared_objects);
1553 if (pvi != _prepared_views.end()) {
1554 const Contexts &contexts = (*pvi).second;
1555 for (
int view = 0; view < cdata->_num_views; ++view) {
1556 Contexts::const_iterator ci;
1557 ci = contexts.find(view);
1558 if (ci != contexts.end()) {
1576 PreparedViews::iterator pvi;
1577 pvi = _prepared_views.find(prepared_objects);
1578 if (pvi != _prepared_views.end()) {
1580 temp.swap((*pvi).second);
1581 Contexts::iterator ci;
1582 for (ci = temp.begin(); ci != temp.end(); ++ci) {
1584 if (tc !=
nullptr) {
1588 _prepared_views.erase(pvi);
1608 temp.swap(_prepared_views);
1609 int num_freed = (int)temp.size();
1611 PreparedViews::iterator pvi;
1612 for (pvi = temp.begin(); pvi != temp.end(); ++pvi) {
1615 temp.swap((*pvi).second);
1616 Contexts::iterator ci;
1617 for (ci = temp.begin(); ci != temp.end(); ++ci) {
1619 if (tc !=
nullptr) {
1633write(ostream &out,
int indent_level)
const {
1635 indent(out, indent_level)
1636 << cdata->_texture_type <<
" " << get_name();
1637 if (!cdata->_filename.empty()) {
1638 out <<
" (from " << cdata->_filename <<
")";
1642 indent(out, indent_level + 2);
1644 switch (cdata->_texture_type) {
1646 out <<
"1-d, " << cdata->_x_size;
1650 out <<
"2-d, " << cdata->_x_size <<
" x " << cdata->_y_size;
1654 out <<
"3-d, " << cdata->_x_size <<
" x " << cdata->_y_size <<
" x " << cdata->_z_size;
1657 case TT_2d_texture_array:
1658 out <<
"2-d array, " << cdata->_x_size <<
" x " << cdata->_y_size <<
" x " << cdata->_z_size;
1662 out <<
"cube map, " << cdata->_x_size <<
" x " << cdata->_y_size;
1665 case TT_cube_map_array:
1666 out <<
"cube map array, " << cdata->_x_size <<
" x " << cdata->_y_size <<
" x " << cdata->_z_size;
1669 case TT_buffer_texture:
1670 out <<
"buffer, " << cdata->_x_size;
1673 case TT_1d_texture_array:
1674 out <<
"1-d array, " << cdata->_x_size <<
" x " << cdata->_y_size;
1678 if (cdata->_num_views > 1) {
1679 out <<
" (x " << cdata->_num_views <<
" views)";
1682 out <<
" pixels, each " << cdata->_num_components;
1684 switch (cdata->_component_type) {
1685 case T_unsigned_byte:
1690 case T_unsigned_short:
1701 case T_unsigned_int_24_8:
1703 case T_unsigned_int:
1712 switch (cdata->_format) {
1714 out <<
"color_index";
1716 case F_depth_stencil:
1717 out <<
"depth_stencil";
1719 case F_depth_component:
1720 out <<
"depth_component";
1722 case F_depth_component16:
1723 out <<
"depth_component16";
1725 case F_depth_component24:
1726 out <<
"depth_component24";
1728 case F_depth_component32:
1729 out <<
"depth_component32";
1788 case F_luminance_alpha:
1789 out <<
"luminance_alpha";
1791 case F_luminance_alphamask:
1792 out <<
"luminance_alphamask";
1809 out <<
"srgb_alpha";
1812 out <<
"sluminance";
1814 case F_sluminance_alpha:
1815 out <<
"sluminance_alpha";
1845 out <<
"r11_g11_b10";
1882 if (cdata->_compression != CM_default) {
1883 out <<
", compression " << cdata->_compression;
1887 indent(out, indent_level + 2);
1889 cdata->_default_sampler.output(out);
1891 if (do_has_ram_image(cdata)) {
1892 indent(out, indent_level + 2)
1893 << do_get_ram_image_size(cdata) <<
" bytes in ram, compression "
1894 << cdata->_ram_image_compression <<
"\n";
1896 if (cdata->_ram_images.size() > 1) {
1898 size_t total_size = 0;
1899 for (
size_t n = 1; n < cdata->_ram_images.size(); ++n) {
1900 if (!cdata->_ram_images[n]._image.empty()) {
1902 total_size += cdata->_ram_images[n]._image.size();
1908 indent(out, indent_level + 2)
1910 <<
" mipmap levels also present in ram (" << total_size
1915 indent(out, indent_level + 2)
1916 <<
"no ram image\n";
1919 if (!cdata->_simple_ram_image._image.empty()) {
1920 indent(out, indent_level + 2)
1921 <<
"simple image: " << cdata->_simple_x_size <<
" x "
1922 << cdata->_simple_y_size <<
", "
1923 << cdata->_simple_ram_image._image.size() <<
" bytes\n";
1935 if (do_get_auto_texture_scale(cdata) != ATS_none) {
1939 if (cdata->_texture_type == TT_3d_texture) {
1944 do_set_z_size(cdata, z);
1947 do_set_x_size(cdata, x);
1948 do_set_y_size(cdata, y);
1949 do_set_z_size(cdata, z);
1951 do_set_pad_size(cdata,
1954 cdata->_z_size - z);
1964 cdata->_orig_file_x_size = x;
1965 cdata->_orig_file_y_size = y;
1967 nassertv(z == cdata->_z_size);
1989 view = max(min(view, cdata->_num_views - 1), 0);
1992 Contexts &contexts = _prepared_views[prepared_objects];
1993 Contexts::const_iterator pvi;
1994 pvi = contexts.find(view);
1995 if (pvi != contexts.end()) {
1996 return (*pvi).second;
2000 contexts[view] = tc;
2058 if (
adjust_size(new_x_size, new_y_size, name,
false, auto_texture_scale)) {
2081 return "1d_texture";
2083 return "2d_texture";
2085 return "3d_texture";
2086 case TT_2d_texture_array:
2087 return "2d_texture_array";
2090 case TT_cube_map_array:
2091 return "cube_map_array";
2092 case TT_buffer_texture:
2093 return "buffer_texture";
2094 case TT_1d_texture_array:
2095 return "1d_texture_array";
2097 return "**invalid**";
2105 if (cmp_nocase(str,
"1d_texture") == 0) {
2106 return TT_1d_texture;
2107 }
else if (cmp_nocase(str,
"2d_texture") == 0) {
2108 return TT_2d_texture;
2109 }
else if (cmp_nocase(str,
"3d_texture") == 0) {
2110 return TT_3d_texture;
2111 }
else if (cmp_nocase(str,
"2d_texture_array") == 0) {
2112 return TT_2d_texture_array;
2113 }
else if (cmp_nocase(str,
"cube_map") == 0) {
2115 }
else if (cmp_nocase(str,
"cube_map_array") == 0) {
2116 return TT_cube_map_array;
2117 }
else if (cmp_nocase(str,
"buffer_texture") == 0) {
2118 return TT_buffer_texture;
2122 <<
"Invalid Texture::TextureType value: " << str <<
"\n";
2123 return TT_2d_texture;
2132 case T_unsigned_byte:
2133 return "unsigned_byte";
2134 case T_unsigned_short:
2135 return "unsigned_short";
2138 case T_unsigned_int_24_8:
2139 return "unsigned_int_24_8";
2143 return "unsigned_byte";
2147 return "half_float";
2148 case T_unsigned_int:
2149 return "unsigned_int";
2152 return "**invalid**";
2160 if (cmp_nocase(str,
"unsigned_byte") == 0) {
2161 return T_unsigned_byte;
2162 }
else if (cmp_nocase(str,
"unsigned_short") == 0) {
2163 return T_unsigned_short;
2164 }
else if (cmp_nocase(str,
"float") == 0) {
2166 }
else if (cmp_nocase(str,
"unsigned_int_24_8") == 0) {
2167 return T_unsigned_int_24_8;
2168 }
else if (cmp_nocase(str,
"int") == 0) {
2170 }
else if (cmp_nocase(str,
"byte") == 0) {
2172 }
else if (cmp_nocase(str,
"short") == 0) {
2174 }
else if (cmp_nocase(str,
"half_float") == 0) {
2175 return T_half_float;
2176 }
else if (cmp_nocase(str,
"unsigned_int") == 0) {
2177 return T_unsigned_int;
2181 <<
"Invalid Texture::ComponentType value: " << str <<
"\n";
2182 return T_unsigned_byte;
2191 case F_depth_stencil:
2192 return "depth_stencil";
2193 case F_depth_component:
2194 return "depth_component";
2195 case F_depth_component16:
2196 return "depth_component16";
2197 case F_depth_component24:
2198 return "depth_component24";
2199 case F_depth_component32:
2200 return "depth_component32";
2202 return "color_index";
2235 case F_luminance_alpha:
2236 return "luminance_alpha";
2237 case F_luminance_alphamask:
2238 return "luminance_alphamask";
2252 return "srgb_alpha";
2254 return "sluminance";
2255 case F_sluminance_alpha:
2256 return "sluminance_alpha";
2296 return "**invalid**";
2304 if (cmp_nocase(str,
"depth_stencil") == 0) {
2305 return F_depth_stencil;
2306 }
else if (cmp_nocase(str,
"depth_component") == 0) {
2307 return F_depth_component;
2308 }
else if (cmp_nocase(str,
"depth_component16") == 0 || cmp_nocase(str,
"d16") == 0) {
2309 return F_depth_component16;
2310 }
else if (cmp_nocase(str,
"depth_component24") == 0 || cmp_nocase(str,
"d24") == 0) {
2311 return F_depth_component24;
2312 }
else if (cmp_nocase(str,
"depth_component32") == 0 || cmp_nocase(str,
"d32") == 0) {
2313 return F_depth_component32;
2314 }
else if (cmp_nocase(str,
"color_index") == 0) {
2315 return F_color_index;
2316 }
else if (cmp_nocase(str,
"red") == 0) {
2318 }
else if (cmp_nocase(str,
"green") == 0) {
2320 }
else if (cmp_nocase(str,
"blue") == 0) {
2322 }
else if (cmp_nocase(str,
"alpha") == 0) {
2324 }
else if (cmp_nocase(str,
"rgb") == 0) {
2326 }
else if (cmp_nocase(str,
"rgb5") == 0) {
2328 }
else if (cmp_nocase(str,
"rgb8") == 0 || cmp_nocase(str,
"r8g8b8") == 0) {
2330 }
else if (cmp_nocase(str,
"rgb12") == 0) {
2332 }
else if (cmp_nocase(str,
"rgb332") == 0 || cmp_nocase(str,
"r3g3b2") == 0) {
2334 }
else if (cmp_nocase(str,
"rgba") == 0) {
2336 }
else if (cmp_nocase(str,
"rgbm") == 0) {
2338 }
else if (cmp_nocase(str,
"rgba4") == 0) {
2340 }
else if (cmp_nocase(str,
"rgba5") == 0) {
2342 }
else if (cmp_nocase(str,
"rgba8") == 0 || cmp_nocase(str,
"r8g8b8a8") == 0) {
2344 }
else if (cmp_nocase(str,
"rgba12") == 0) {
2346 }
else if (cmp_nocase(str,
"luminance") == 0) {
2348 }
else if (cmp_nocase(str,
"luminance_alpha") == 0) {
2349 return F_luminance_alpha;
2350 }
else if (cmp_nocase(str,
"luminance_alphamask") == 0) {
2351 return F_luminance_alphamask;
2352 }
else if (cmp_nocase(str,
"rgba16") == 0 || cmp_nocase(str,
"r16g16b16a16") == 0) {
2354 }
else if (cmp_nocase(str,
"rgba32") == 0 || cmp_nocase(str,
"r32g32b32a32") == 0) {
2356 }
else if (cmp_nocase(str,
"r16") == 0 || cmp_nocase(str,
"red16") == 0) {
2358 }
else if (cmp_nocase(str,
"r16i") == 0) {
2360 }
else if (cmp_nocase(str,
"rg16") == 0 || cmp_nocase(str,
"r16g16") == 0) {
2362 }
else if (cmp_nocase(str,
"rgb16") == 0 || cmp_nocase(str,
"r16g16b16") == 0) {
2364 }
else if (cmp_nocase(str,
"srgb") == 0) {
2366 }
else if (cmp_nocase(str,
"srgb_alpha") == 0) {
2367 return F_srgb_alpha;
2368 }
else if (cmp_nocase(str,
"sluminance") == 0) {
2369 return F_sluminance;
2370 }
else if (cmp_nocase(str,
"sluminance_alpha") == 0) {
2371 return F_sluminance_alpha;
2372 }
else if (cmp_nocase(str,
"r32i") == 0) {
2374 }
else if (cmp_nocase(str,
"r32") == 0 || cmp_nocase(str,
"red32") == 0) {
2376 }
else if (cmp_nocase(str,
"rg32") == 0 || cmp_nocase(str,
"r32g32") == 0) {
2378 }
else if (cmp_nocase(str,
"rgb32") == 0 || cmp_nocase(str,
"r32g32b32") == 0) {
2380 }
else if (cmp_nocase_uh(str,
"r8i") == 0) {
2382 }
else if (cmp_nocase_uh(str,
"rg8i") == 0 || cmp_nocase_uh(str,
"r8g8i") == 0) {
2384 }
else if (cmp_nocase_uh(str,
"rgb8i") == 0 || cmp_nocase_uh(str,
"r8g8b8i") == 0) {
2386 }
else if (cmp_nocase_uh(str,
"rgba8i") == 0 || cmp_nocase_uh(str,
"r8g8b8a8i") == 0) {
2388 }
else if (cmp_nocase(str,
"r11g11b10") == 0) {
2389 return F_r11_g11_b10;
2390 }
else if (cmp_nocase(str,
"rgb9_e5") == 0) {
2392 }
else if (cmp_nocase_uh(str,
"rgb10_a2") == 0 || cmp_nocase(str,
"r10g10b10a2") == 0) {
2394 }
else if (cmp_nocase_uh(str,
"rg") == 0) {
2396 }
else if (cmp_nocase_uh(str,
"r16i") == 0) {
2398 }
else if (cmp_nocase_uh(str,
"rg16i") == 0 || cmp_nocase_uh(str,
"r16g16i") == 0) {
2400 }
else if (cmp_nocase_uh(str,
"rgb16i") == 0 || cmp_nocase_uh(str,
"r16g16b16i") == 0) {
2402 }
else if (cmp_nocase_uh(str,
"rgba16i") == 0 || cmp_nocase_uh(str,
"r16g16b16a16i") == 0) {
2404 }
else if (cmp_nocase_uh(str,
"rg32i") == 0 || cmp_nocase_uh(str,
"r32g32i") == 0) {
2406 }
else if (cmp_nocase_uh(str,
"rgb32i") == 0 || cmp_nocase_uh(str,
"r32g32b32i") == 0) {
2408 }
else if (cmp_nocase_uh(str,
"rgba32i") == 0 || cmp_nocase_uh(str,
"r32g32b32a32i") == 0) {
2413 <<
"Invalid Texture::Format value: " << str <<
"\n";
2455 return "**invalid**";
2464 if (cmp_nocase_uh(str,
"default") == 0) {
2466 }
else if (cmp_nocase_uh(str,
"off") == 0) {
2468 }
else if (cmp_nocase_uh(str,
"on") == 0) {
2470 }
else if (cmp_nocase_uh(str,
"fxt1") == 0) {
2472 }
else if (cmp_nocase_uh(str,
"dxt1") == 0) {
2474 }
else if (cmp_nocase_uh(str,
"dxt2") == 0) {
2476 }
else if (cmp_nocase_uh(str,
"dxt3") == 0) {
2478 }
else if (cmp_nocase_uh(str,
"dxt4") == 0) {
2480 }
else if (cmp_nocase_uh(str,
"dxt5") == 0) {
2482 }
else if (cmp_nocase_uh(str,
"pvr1_2bpp") == 0) {
2483 return CM_pvr1_2bpp;
2484 }
else if (cmp_nocase_uh(str,
"pvr1_4bpp") == 0) {
2485 return CM_pvr1_4bpp;
2486 }
else if (cmp_nocase_uh(str,
"rgtc") == 0) {
2488 }
else if (cmp_nocase_uh(str,
"etc1") == 0) {
2490 }
else if (cmp_nocase_uh(str,
"etc2") == 0) {
2492 }
else if (cmp_nocase_uh(str,
"eac") == 0) {
2497 <<
"Invalid Texture::CompressionMode value: " << str <<
"\n";
2518 return "**invalid**";
2527 if (cmp_nocase(str,
"default") == 0) {
2529 }
else if (cmp_nocase(str,
"fastest") == 0) {
2531 }
else if (cmp_nocase(str,
"normal") == 0) {
2533 }
else if (cmp_nocase(str,
"best") == 0) {
2538 <<
"Invalid Texture::QualityLevel value: " << str <<
"\n";
2555 if (!keep_texture_ram && !cdata->_keep_ram_image) {
2560 CDWriter cdataw(_cycler, cdata,
false);
2561 if (gobj_cat.is_debug()) {
2563 <<
"Dumping RAM for texture " << get_name() <<
"\n";
2565 do_clear_ram_image(cdataw);
2606 return (ctype == T_unsigned_byte ||
2607 ctype == T_unsigned_short ||
2608 ctype == T_unsigned_int_24_8 ||
2609 ctype == T_unsigned_int);
2617is_specific(Texture::CompressionMode compression) {
2618 switch (compression) {
2644 case F_luminance_alpha:
2645 case F_luminance_alphamask:
2647 case F_sluminance_alpha:
2684 case F_sluminance_alpha:
2727adjust_size(
int &x_size,
int &y_size,
const string &name,
2728 bool for_padding, AutoTextureScale auto_texture_scale) {
2729 bool exclude =
false;
2731 for (
int i = 0; i < num_excludes && !exclude; ++i) {
2738 int new_x_size = x_size;
2739 int new_y_size = y_size;
2742 new_x_size = (int)cfloor(new_x_size * texture_scale + 0.5);
2743 new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5);
2747 new_x_size = min(max(new_x_size, (
int)texture_scale_limit), x_size);
2748 new_y_size = min(max(new_y_size, (
int)texture_scale_limit), y_size);
2751 AutoTextureScale ats = auto_texture_scale;
2752 if (ats == ATS_unspecified) {
2755 if (!for_padding && ats == ATS_pad) {
2775 case ATS_unspecified:
2779 ats = textures_square.get_value();
2780 if (!for_padding && ats == ATS_pad) {
2785 new_x_size = new_y_size = min(new_x_size, new_y_size);
2790 new_x_size = new_y_size = max(new_x_size, new_y_size);
2794 case ATS_unspecified:
2799 int max_dimension = max_texture_dimension;
2801 if (max_dimension < 0) {
2803 if (gsg !=
nullptr) {
2804 max_dimension = gsg->get_max_texture_dimension();
2808 if (max_dimension > 0) {
2809 new_x_size = min(new_x_size, (
int)max_dimension);
2810 new_y_size = min(new_y_size, (
int)max_dimension);
2814 if (x_size != new_x_size || y_size != new_y_size) {
2815 x_size = new_x_size;
2816 y_size = new_y_size;
2855do_adjust_this_size(
const CData *cdata,
int &x_size,
int &y_size,
const string &name,
2856 bool for_padding)
const {
2857 return adjust_size(x_size, y_size, name, for_padding, cdata->_auto_texture_scale);
2864do_read(CData *cdata,
const Filename &fullpath,
const Filename &alpha_fullpath,
2865 int primary_file_num_channels,
int alpha_file_channel,
2866 int z,
int n,
bool read_pages,
bool read_mipmaps,
2874 bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
2875 if (record !=
nullptr) {
2876 header_only =
false;
2879 if ((z == 0 || read_pages) && (n == 0 || read_mipmaps)) {
2882 do_clear_ram_image(cdata);
2885 if (is_txo_filename(fullpath)) {
2886 if (record !=
nullptr) {
2889 return do_read_txo_file(cdata, fullpath);
2892 if (is_dds_filename(fullpath)) {
2893 if (record !=
nullptr) {
2896 return do_read_dds_file(cdata, fullpath, header_only);
2899 if (is_ktx_filename(fullpath)) {
2900 if (record !=
nullptr) {
2903 return do_read_ktx_file(cdata, fullpath, header_only);
2915 switch (cdata->_texture_type) {
2918 case TT_buffer_texture:
2932 if (options.get_texture_flags() & LoaderOptions::TF_multiview) {
2937 do_set_num_views(cdata, num_views);
2943 if (read_pages && read_mipmaps) {
2947 do_set_z_size(cdata, z_size);
2955 z_size = do_get_expected_mipmap_z_size(cdata, n);
2965 <<
"Filename requires two different hash sequences: " << fullpath
2973 if ((n_size == 0 && (vfs->
exists(file) || n == 0)) ||
2974 (n_size != 0 && n < n_size)) {
2981 int num_pages = z_size * num_views;
2982 while ((num_pages == 0 && (vfs->
exists(file) || z == 0)) ||
2983 (num_pages != 0 && z < num_pages)) {
2984 if (!do_read_one(cdata, file, alpha_file, z, n, primary_file_num_channels,
2985 alpha_file_channel, options, header_only, record)) {
2995 if (n == 0 && n_size == 0) {
2998 n_size = do_get_expected_num_mipmap_levels(cdata);
3002 cdata->_fullpath = fullpath_pattern;
3003 cdata->_alpha_fullpath = alpha_fullpath_pattern;
3005 }
else if (read_pages) {
3009 if (!fullpath_pattern.
has_hash()) {
3011 <<
"Filename requires a hash mark: " << fullpath
3016 do_set_z_size(cdata, z_size);
3021 int num_pages = z_size * num_views;
3022 while ((num_pages == 0 && (vfs->
exists(file) || z == 0)) ||
3023 (num_pages != 0 && z < num_pages)) {
3024 if (!do_read_one(cdata, file, alpha_file, z, 0, primary_file_num_channels,
3025 alpha_file_channel, options, header_only, record)) {
3033 cdata->_fullpath = fullpath_pattern;
3034 cdata->_alpha_fullpath = alpha_fullpath_pattern;
3036 }
else if (read_mipmaps) {
3040 if (!fullpath_pattern.
has_hash()) {
3042 <<
"Filename requires a hash mark: " << fullpath
3051 while ((n_size == 0 && (vfs->
exists(file) || n == 0)) ||
3052 (n_size != 0 && n < n_size)) {
3053 if (!do_read_one(cdata, file, alpha_file, z, n,
3054 primary_file_num_channels, alpha_file_channel,
3055 options, header_only, record)) {
3060 if (n_size == 0 && n >= do_get_expected_num_mipmap_levels(cdata)) {
3069 cdata->_fullpath = fullpath_pattern;
3070 cdata->_alpha_fullpath = alpha_fullpath_pattern;
3074 if (!do_read_one(cdata, fullpath, alpha_fullpath, z, n,
3075 primary_file_num_channels, alpha_file_channel,
3076 options, header_only, record)) {
3081 cdata->_has_read_pages = read_pages;
3082 cdata->_has_read_mipmaps = read_mipmaps;
3083 cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
3088 do_clear_ram_image(cdata);
3090 if ((options.get_texture_flags() & LoaderOptions::TF_preload) != 0) {
3093 bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
3094 bool allow_compression = ((options.get_texture_flags() & LoaderOptions::TF_allow_compression) != 0);
3095 do_consider_auto_process_ram_image(cdata, generate_mipmaps ||
uses_mipmaps(), allow_compression);
3107do_read_one(CData *cdata,
const Filename &fullpath,
const Filename &alpha_fullpath,
3108 int z,
int n,
int primary_file_num_channels,
int alpha_file_channel,
3110 if (record !=
nullptr) {
3111 nassertr(!header_only,
false);
3118 if (image_reader ==
nullptr) {
3120 <<
"Texture::read() - couldn't read: " << fullpath << endl;
3125 AutoTextureScale auto_texture_scale = do_get_auto_texture_scale(cdata);
3129 bool read_floating_point;
3130 int texture_load_type = (options.get_texture_flags() & (LoaderOptions::TF_integer | LoaderOptions::TF_float));
3131 switch (texture_load_type) {
3132 case LoaderOptions::TF_integer:
3133 read_floating_point =
false;
3136 case LoaderOptions::TF_float:
3137 read_floating_point =
true;
3144 if (!alpha_fullpath.empty()) {
3145 read_floating_point =
false;
3149 if (header_only || textures_header_only) {
3152 if (z == 0 && n == 0) {
3153 cdata->_orig_file_x_size = x_size;
3154 cdata->_orig_file_y_size = y_size;
3157 if (textures_header_only) {
3167 if (read_floating_point) {
3173 image.
fill(0.2, 0.3, 1.0);
3178 delete image_reader;
3181 if (z == 0 && n == 0) {
3185 cdata->_orig_file_x_size = x_size;
3186 cdata->_orig_file_y_size = y_size;
3192 image.
set_read_size(do_get_expected_mipmap_x_size(cdata, n),
3193 do_get_expected_mipmap_y_size(cdata, n));
3199 <<
"Implicitly rescaling " << fullpath.
get_basename() <<
" from "
3206 if (read_floating_point) {
3207 success = pfm.
read(image_reader);
3209 success = image.
read(image_reader);
3214 <<
"Texture::read() - couldn't read: " << fullpath << endl;
3221 if (!alpha_fullpath.empty()) {
3223 if (alpha_image_reader ==
nullptr) {
3225 <<
"Texture::read() - couldn't read: " << alpha_fullpath << endl;
3230 if (record !=
nullptr) {
3234 if (header_only || textures_header_only) {
3240 alpha_image.
fill(1.0);
3244 delete alpha_image_reader;
3250 <<
"Implicitly rescaling " << alpha_fullpath.
get_basename()
3251 <<
" from " << alpha_image.
get_x_size() <<
" by "
3257 if (!alpha_image.
read(alpha_image_reader)) {
3259 <<
"Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
3266 if (z == 0 && n == 0) {
3270 if (cdata->_filename.empty()) {
3271 cdata->_filename = fullpath;
3272 cdata->_alpha_filename = alpha_fullpath;
3277 cdata->_keep_ram_image =
false;
3280 cdata->_fullpath = fullpath;
3281 cdata->_alpha_fullpath = alpha_fullpath;
3284 if (!alpha_fullpath.empty()) {
3290 <<
"Automatically rescaling " << alpha_fullpath.
get_basename()
3291 <<
" from " << alpha_image.
get_x_size() <<
" by "
3299 scaled.quick_filter_from(alpha_image);
3301 alpha_image = scaled;
3306 consider_downgrade(image, primary_file_num_channels, get_name());
3308 cdata->_alpha_file_channel = 0;
3311 if (!alpha_fullpath.empty()) {
3316 if (alpha_file_channel == 4 ||
3321 << alpha_fullpath.
get_basename() <<
" has no channel " << alpha_file_channel <<
".\n";
3324 for (
int x = 0; x < image.
get_x_size(); x++) {
3325 for (
int y = 0; y < image.
get_y_size(); y++) {
3332 }
else if (alpha_file_channel >= 1 && alpha_file_channel <= 3 &&
3335 for (
int x = 0; x < image.
get_x_size(); x++) {
3336 for (
int y = 0; y < image.
get_y_size(); y++) {
3340 cdata->_alpha_file_channel = alpha_file_channel;
3344 for (
int x = 0; x < image.
get_x_size(); x++) {
3345 for (
int y = 0; y < image.
get_y_size(); y++) {
3349 cdata->_alpha_file_channel = 0;
3353 if (read_floating_point) {
3354 if (!do_load_one(cdata, pfm, fullpath.
get_basename(), z, n, options)) {
3361 if (do_get_auto_texture_scale(cdata) == ATS_pad) {
3364 if (do_adjust_this_size(cdata, new_x_size, new_y_size, fullpath.
get_basename(),
true)) {
3365 pad_x_size = new_x_size - image.
get_x_size();
3366 pad_y_size = new_y_size - image.
get_y_size();
3370 new_image.copy_sub_image(image, 0, new_y_size - image.
get_y_size());
3375 if (!do_load_one(cdata, image, fullpath.
get_basename(), z, n, options)) {
3379 do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
3388do_load_one(CData *cdata,
const PNMImage &pnmimage,
const string &name,
int z,
int n,
3390 if (cdata->_ram_images.size() <= 1 && n == 0) {
3394 if (!do_reconsider_z_size(cdata, z, options)) {
3397 nassertr(z >= 0 && z < cdata->_z_size * cdata->_num_views,
false);
3400 ComponentType component_type = T_unsigned_byte;
3403 component_type = T_unsigned_short;
3413 do_modify_ram_image(cdata);
3414 cdata->_loaded_from_image =
true;
3417 do_modify_ram_mipmap_image(cdata, n);
3420 int x_size = do_get_expected_mipmap_x_size(cdata, n);
3421 int y_size = do_get_expected_mipmap_y_size(cdata, n);
3425 <<
"Automatically rescaling " << name;
3427 gobj_cat.info(
false)
3428 <<
" mipmap level " << n;
3430 gobj_cat.info(
false)
3431 <<
" from " << pnmimage.
get_x_size() <<
" by "
3432 << pnmimage.
get_y_size() <<
" to " << x_size <<
" by "
3438 scaled.quick_filter_from(pnmimage);
3441 convert_from_pnmimage(cdata->_ram_images[n]._image,
3442 do_get_expected_ram_mipmap_page_size(cdata, n),
3443 x_size, 0, 0, z, scaled,
3444 cdata->_num_components, cdata->_component_width);
3448 convert_from_pnmimage(cdata->_ram_images[n]._image,
3449 do_get_expected_ram_mipmap_page_size(cdata, n),
3450 x_size, 0, 0, z, pnmimage,
3451 cdata->_num_components, cdata->_component_width);
3462do_load_one(CData *cdata,
const PfmFile &pfm,
const string &name,
int z,
int n,
3464 if (cdata->_ram_images.size() <= 1 && n == 0) {
3468 if (!do_reconsider_z_size(cdata, z, options)) {
3471 nassertr(z >= 0 && z < cdata->_z_size * cdata->_num_views,
false);
3474 ComponentType component_type = T_float;
3482 do_modify_ram_image(cdata);
3483 cdata->_loaded_from_image =
true;
3486 do_modify_ram_mipmap_image(cdata, n);
3489 int x_size = do_get_expected_mipmap_x_size(cdata, n);
3490 int y_size = do_get_expected_mipmap_y_size(cdata, n);
3494 <<
"Automatically rescaling " << name;
3496 gobj_cat.info(
false)
3497 <<
" mipmap level " << n;
3499 gobj_cat.info(
false)
3501 << pfm.
get_y_size() <<
" to " << x_size <<
" by "
3505 scaled.resize(x_size, y_size);
3508 convert_from_pfm(cdata->_ram_images[n]._image,
3509 do_get_expected_ram_mipmap_page_size(cdata, n), z,
3510 scaled, cdata->_num_components, cdata->_component_width);
3514 convert_from_pfm(cdata->_ram_images[n]._image,
3515 do_get_expected_ram_mipmap_page_size(cdata, n), z,
3516 pfm, cdata->_num_components, cdata->_component_width);
3528do_load_sub_image(CData *cdata,
const PNMImage &image,
int x,
int y,
int z,
int n) {
3529 nassertr(n >= 0 && (
size_t)n < cdata->_ram_images.size(),
false);
3531 int tex_x_size = do_get_expected_mipmap_x_size(cdata, n);
3532 int tex_y_size = do_get_expected_mipmap_y_size(cdata, n);
3533 int tex_z_size = do_get_expected_mipmap_z_size(cdata, n);
3535 nassertr(x >= 0 && x < tex_x_size,
false);
3536 nassertr(y >= 0 && y < tex_y_size,
false);
3537 nassertr(z >= 0 && z < tex_z_size,
false);
3539 nassertr(image.
get_x_size() + x <= tex_x_size,
false);
3540 nassertr(image.
get_y_size() + y <= tex_y_size,
false);
3543 y = cdata->_y_size - (image.
get_y_size() + y);
3545 cdata->inc_image_modified();
3546 do_modify_ram_mipmap_image(cdata, n);
3547 convert_from_pnmimage(cdata->_ram_images[n]._image,
3548 do_get_expected_ram_mipmap_page_size(cdata, n),
3549 tex_x_size, x, y, z, image,
3550 cdata->_num_components, cdata->_component_width);
3560do_read_txo_file(CData *cdata,
const Filename &fullpath) {
3563 Filename filename = Filename::binary_filename(fullpath);
3565 if (file ==
nullptr) {
3568 <<
"Could not find " << fullpath <<
"\n";
3572 if (gobj_cat.is_debug()) {
3574 <<
"Reading texture object " << filename <<
"\n";
3577 istream *in = file->open_read_file(
true);
3578 if (in ==
nullptr) {
3580 <<
"Failed to open " << filename <<
" for reading.\n";
3584 bool success = do_read_txo(cdata, *in, fullpath);
3587 cdata->_fullpath = fullpath;
3588 cdata->_alpha_fullpath =
Filename();
3589 cdata->_keep_ram_image =
false;
3598do_read_txo(CData *cdata, istream &in,
const string &filename) {
3599 PT(
Texture) other = make_from_txo(in, filename);
3600 if (other ==
nullptr) {
3604 CDReader cdata_other(other->_cycler);
3605 Namable::operator = (*other);
3606 do_assign(cdata, other, cdata_other);
3608 cdata->_loaded_from_image =
true;
3609 cdata->_loaded_from_txo =
true;
3610 cdata->_has_read_pages =
false;
3611 cdata->_has_read_mipmaps =
false;
3612 cdata->_num_mipmap_levels_read = 0;
3621do_read_dds_file(CData *cdata,
const Filename &fullpath,
bool header_only) {
3624 Filename filename = Filename::binary_filename(fullpath);
3626 if (file ==
nullptr) {
3629 <<
"Could not find " << fullpath <<
"\n";
3633 if (gobj_cat.is_debug()) {
3635 <<
"Reading DDS file " << filename <<
"\n";
3638 istream *in = file->open_read_file(
true);
3639 if (in ==
nullptr) {
3641 <<
"Failed to open " << filename <<
" for reading.\n";
3645 bool success = do_read_dds(cdata, *in, fullpath, header_only);
3652 cdata->_fullpath = fullpath;
3653 cdata->_alpha_fullpath =
Filename();
3654 cdata->_keep_ram_image =
false;
3663do_read_dds(CData *cdata, istream &in,
const string &filename,
bool header_only) {
3668 header.dds_magic = dds.get_uint32();
3669 header.dds_size = dds.get_uint32();
3670 header.dds_flags = dds.get_uint32();
3671 header.height = dds.get_uint32();
3672 header.width = dds.get_uint32();
3673 header.pitch = dds.get_uint32();
3674 header.depth = dds.get_uint32();
3675 header.num_levels = dds.get_uint32();
3679 header.pf.pf_size = dds.get_uint32();
3680 header.pf.pf_flags = dds.get_uint32();
3681 header.pf.four_cc = dds.get_uint32();
3682 header.pf.rgb_bitcount = dds.get_uint32();
3683 header.pf.r_mask = dds.get_uint32();
3684 header.pf.g_mask = dds.get_uint32();
3685 header.pf.b_mask = dds.get_uint32();
3686 header.pf.a_mask = dds.get_uint32();
3689 header.caps.caps1 = dds.get_uint32();
3690 header.caps.caps2 = dds.get_uint32();
3691 header.caps.ddsx = dds.get_uint32();
3697 if (header.dds_magic != DDS_MAGIC || (in.fail() || in.eof())) {
3699 << filename <<
" is not a DDS file.\n";
3703 if ((header.dds_flags & DDSD_MIPMAPCOUNT) == 0) {
3705 header.num_levels = 1;
3707 }
else if (header.num_levels == 0) {
3710 header.num_levels = 1;
3713 TextureType texture_type;
3714 if (header.caps.caps2 & DDSCAPS2_CUBEMAP) {
3715 static const unsigned int all_faces =
3716 (DDSCAPS2_CUBEMAP_POSITIVEX |
3717 DDSCAPS2_CUBEMAP_POSITIVEY |
3718 DDSCAPS2_CUBEMAP_POSITIVEZ |
3719 DDSCAPS2_CUBEMAP_NEGATIVEX |
3720 DDSCAPS2_CUBEMAP_NEGATIVEY |
3721 DDSCAPS2_CUBEMAP_NEGATIVEZ);
3722 if ((header.caps.caps2 & all_faces) != all_faces) {
3724 << filename <<
" is missing some cube map faces; cannot load.\n";
3728 texture_type = TT_cube_map;
3730 }
else if (header.caps.caps2 & DDSCAPS2_VOLUME) {
3731 texture_type = TT_3d_texture;
3734 texture_type = TT_2d_texture;
3739 typedef PTA_uchar (*ReadDDSLevelFunc)(
Texture *tex, Texture::CData *cdata,
3740 const DDSHeader &header,
int n, istream &in);
3741 ReadDDSLevelFunc func =
nullptr;
3743 Format format = F_rgb;
3744 ComponentType component_type = T_unsigned_byte;
3746 do_clear_ram_image(cdata);
3747 CompressionMode compression = CM_off;
3749 if ((header.pf.pf_flags & DDPF_FOURCC) != 0 &&
3750 header.pf.four_cc == 0x30315844) {
3752 func = read_dds_level_generic_uncompressed;
3753 unsigned int dxgi_format = dds.get_uint32();
3754 unsigned int dimension = dds.get_uint32();
3755 unsigned int misc_flag = dds.get_uint32();
3756 unsigned int array_size = dds.get_uint32();
3759 switch (dxgi_format) {
3762 component_type = T_float;
3763 func = read_dds_level_abgr32;
3767 component_type = T_half_float;
3768 func = read_dds_level_abgr16;
3772 component_type = T_unsigned_short;
3773 func = read_dds_level_abgr16;
3777 component_type = T_unsigned_short;
3778 func = read_dds_level_abgr16;
3782 component_type = T_short;
3783 func = read_dds_level_abgr16;
3787 component_type = T_float;
3788 func = read_dds_level_raw;
3792 component_type = T_unsigned_int;
3793 func = read_dds_level_raw;
3797 component_type = T_int;
3798 func = read_dds_level_raw;
3803 func = read_dds_level_abgr8;
3806 format = F_srgb_alpha;
3807 func = read_dds_level_abgr8;
3811 func = read_dds_level_abgr8;
3815 component_type = T_byte;
3816 func = read_dds_level_abgr8;
3820 component_type = T_byte;
3821 func = read_dds_level_abgr8;
3825 component_type = T_half_float;
3826 func = read_dds_level_raw;
3830 component_type = T_unsigned_short;
3831 func = read_dds_level_raw;
3835 component_type = T_unsigned_short;
3836 func = read_dds_level_raw;
3840 component_type = T_short;
3841 func = read_dds_level_raw;
3845 component_type = T_short;
3846 func = read_dds_level_raw;
3849 format = F_depth_component32;
3850 component_type = T_float;
3851 func = read_dds_level_raw;
3855 component_type = T_float;
3856 func = read_dds_level_raw;
3860 component_type = T_unsigned_int;
3861 func = read_dds_level_raw;
3865 component_type = T_int;
3866 func = read_dds_level_raw;
3877 component_type = T_byte;
3881 component_type = T_byte;
3885 component_type = T_half_float;
3886 func = read_dds_level_raw;
3889 format = F_depth_component16;
3890 component_type = T_unsigned_short;
3891 func = read_dds_level_raw;
3895 component_type = T_unsigned_short;
3896 func = read_dds_level_raw;
3900 component_type = T_unsigned_short;
3901 func = read_dds_level_raw;
3905 component_type = T_short;
3906 func = read_dds_level_raw;
3910 component_type = T_short;
3911 func = read_dds_level_raw;
3922 component_type = T_byte;
3926 component_type = T_byte;
3934 compression = CM_dxt1;
3935 func = read_dds_level_bc1;
3939 compression = CM_dxt1;
3940 func = read_dds_level_bc1;
3945 compression = CM_dxt3;
3946 func = read_dds_level_bc2;
3949 format = F_srgb_alpha;
3950 compression = CM_dxt3;
3951 func = read_dds_level_bc2;
3956 compression = CM_dxt5;
3957 func = read_dds_level_bc3;
3960 format = F_srgb_alpha;
3961 compression = CM_dxt5;
3962 func = read_dds_level_bc3;
3967 compression = CM_rgtc;
3968 func = read_dds_level_bc4;
3973 compression = CM_rgtc;
3974 func = read_dds_level_bc5;
3985 format = F_srgb_alpha;
3995 << filename <<
": unsupported DXGI format " << dxgi_format <<
".\n";
3999 switch (dimension) {
4001 texture_type = TT_1d_texture;
4005 if (misc_flag & 0x4) {
4006 if (array_size > 1) {
4007 texture_type = TT_cube_map_array;
4008 header.depth = array_size * 6;
4010 texture_type = TT_cube_map;
4014 if (array_size > 1) {
4015 texture_type = TT_2d_texture_array;
4016 header.depth = array_size;
4018 texture_type = TT_2d_texture;
4024 texture_type = TT_3d_texture;
4028 << filename <<
": unsupported dimension.\n";
4032 }
else if (header.pf.pf_flags & DDPF_FOURCC) {
4034 if (texture_type == TT_3d_texture) {
4036 << filename <<
": unsupported compression on 3-d texture.\n";
4042 switch (header.pf.four_cc) {
4044 compression = CM_dxt1;
4045 func = read_dds_level_bc1;
4049 compression = CM_dxt2;
4050 func = read_dds_level_bc2;
4053 compression = CM_dxt3;
4054 func = read_dds_level_bc2;
4057 compression = CM_dxt4;
4058 func = read_dds_level_bc3;
4061 compression = CM_dxt5;
4062 func = read_dds_level_bc3;
4066 compression = CM_rgtc;
4067 func = read_dds_level_bc4;
4072 compression = CM_rgtc;
4073 func = read_dds_level_bc5;
4077 func = read_dds_level_abgr16;
4079 component_type = T_unsigned_short;
4082 func = read_dds_level_abgr16;
4084 component_type = T_short;
4087 func = read_dds_level_abgr16;
4089 component_type = T_half_float;
4092 func = read_dds_level_abgr32;
4094 component_type = T_float;
4098 << filename <<
": unsupported texture compression (FourCC: 0x"
4099 << std::hex << header.pf.four_cc << std::dec <<
").\n";
4105 func = read_dds_level_generic_uncompressed;
4107 if (header.pf.pf_flags & DDPF_ALPHAPIXELS) {
4110 if (header.pf.rgb_bitcount == 32 &&
4111 header.pf.r_mask == 0x000000ff &&
4112 header.pf.g_mask == 0x0000ff00 &&
4113 header.pf.b_mask == 0x00ff0000 &&
4114 header.pf.a_mask == 0xff000000U) {
4115 func = read_dds_level_abgr8;
4116 }
else if (header.pf.rgb_bitcount == 32 &&
4117 header.pf.r_mask == 0x00ff0000 &&
4118 header.pf.g_mask == 0x0000ff00 &&
4119 header.pf.b_mask == 0x000000ff &&
4120 header.pf.a_mask == 0xff000000U) {
4121 func = read_dds_level_rgba8;
4123 }
else if (header.pf.r_mask != 0 &&
4124 header.pf.g_mask == 0 &&
4125 header.pf.b_mask == 0) {
4126 func = read_dds_level_luminance_uncompressed;
4127 format = F_luminance_alpha;
4131 if (header.pf.rgb_bitcount == 24 &&
4132 header.pf.r_mask == 0x00ff0000 &&
4133 header.pf.g_mask == 0x0000ff00 &&
4134 header.pf.b_mask == 0x000000ff) {
4135 func = read_dds_level_bgr8;
4136 }
else if (header.pf.rgb_bitcount == 24 &&
4137 header.pf.r_mask == 0x000000ff &&
4138 header.pf.g_mask == 0x0000ff00 &&
4139 header.pf.b_mask == 0x00ff0000) {
4140 func = read_dds_level_rgb8;
4142 }
else if (header.pf.r_mask != 0 &&
4143 header.pf.g_mask == 0 &&
4144 header.pf.b_mask == 0) {
4145 func = read_dds_level_luminance_uncompressed;
4146 format = F_luminance;
4151 do_setup_texture(cdata, texture_type, header.width, header.height, header.depth,
4152 component_type, format);
4154 cdata->_orig_file_x_size = cdata->_x_size;
4155 cdata->_orig_file_y_size = cdata->_y_size;
4156 cdata->_compression = compression;
4157 cdata->_ram_image_compression = compression;
4160 switch (texture_type) {
4165 for (
int n = 0; n < (int)header.num_levels; ++n) {
4166 int z_size = do_get_expected_mipmap_z_size(cdata, n);
4168 size_t page_size = 0;
4170 for (z = 0; z < z_size; ++z) {
4171 PTA_uchar page = func(
this, cdata, header, n, in);
4172 if (page.is_null()) {
4175 nassertr(page_size == 0 || page_size == page.size(),
false);
4176 page_size = page.size();
4177 pages.push_back(page);
4182 PTA_uchar image = PTA_uchar::empty_array(page_size * z_size);
4183 unsigned char *imagep = (
unsigned char *)image.p();
4184 for (z = 0; z < z_size; ++z) {
4185 int fz = z_size - 1 - z;
4186 memcpy(imagep + z * page_size, pages[fz].p(), page_size);
4189 do_set_ram_mipmap_image(cdata, n, image, page_size);
4201 for (z = 0; z < 6; ++z) {
4204 levels.reserve(header.num_levels);
4206 for (n = 0; n < (int)header.num_levels; ++n) {
4207 PTA_uchar image = func(
this, cdata, header, n, in);
4208 if (image.is_null()) {
4211 levels.push_back(image);
4218 static const int level_remap[6] = {
4221 for (n = 0; n < (int)header.num_levels; ++n) {
4222 size_t page_size = pages[0][n].size();
4223 PTA_uchar image = PTA_uchar::empty_array(page_size * 6);
4224 unsigned char *imagep = (
unsigned char *)image.p();
4225 for (z = 0; z < 6; ++z) {
4226 int fz = level_remap[z];
4227 nassertr(pages[fz][n].size() == page_size,
false);
4228 memcpy(imagep + z * page_size, pages[fz][n].p(), page_size);
4231 do_set_ram_mipmap_image(cdata, n, image, page_size);
4236 case TT_2d_texture_array:
4237 case TT_cube_map_array:
4242 pages.reserve(header.depth);
4244 for (z = 0; z < (int)header.depth; ++z) {
4247 levels.reserve(header.num_levels);
4249 for (n = 0; n < (int)header.num_levels; ++n) {
4250 PTA_uchar image = func(
this, cdata, header, n, in);
4251 if (image.is_null()) {
4254 levels.push_back(image);
4259 for (n = 0; n < (int)header.num_levels; ++n) {
4260 size_t page_size = pages[0][n].size();
4261 PTA_uchar image = PTA_uchar::empty_array(page_size * header.depth);
4262 unsigned char *imagep = (
unsigned char *)image.p();
4263 for (z = 0; z < (int)header.depth; ++z) {
4264 nassertr(pages[z][n].size() == page_size,
false);
4265 memcpy(imagep + z * page_size, pages[z][n].p(), page_size);
4268 do_set_ram_mipmap_image(cdata, n, image, page_size);
4276 for (
int n = 0; n < (int)header.num_levels; ++n) {
4277 PTA_uchar image = func(
this, cdata, header, n, in);
4278 if (image.is_null()) {
4281 do_set_ram_mipmap_image(cdata, n, image, 0);
4285 cdata->_has_read_pages =
true;
4286 cdata->_has_read_mipmaps =
true;
4287 cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
4292 << filename <<
": truncated DDS file.\n";
4296 cdata->_loaded_from_image =
true;
4297 cdata->_loaded_from_txo =
true;
4307do_read_ktx_file(CData *cdata,
const Filename &fullpath,
bool header_only) {
4310 Filename filename = Filename::binary_filename(fullpath);
4312 if (file ==
nullptr) {
4315 <<
"Could not find " << fullpath <<
"\n";
4319 if (gobj_cat.is_debug()) {
4321 <<
"Reading KTX file " << filename <<
"\n";
4324 istream *in = file->open_read_file(
true);
4325 if (in ==
nullptr) {
4327 <<
"Failed to open " << filename <<
" for reading.\n";
4331 bool success = do_read_ktx(cdata, *in, fullpath, header_only);
4338 cdata->_fullpath = fullpath;
4339 cdata->_alpha_fullpath =
Filename();
4340 cdata->_keep_ram_image =
false;
4349do_read_ktx(CData *cdata, istream &in,
const string &filename,
bool header_only) {
4352 unsigned char magic[12];
4353 if (ktx.extract_bytes(magic, 12) != 12 ||
4354 memcmp(magic,
"\xABKTX 11\xBB\r\n\x1A\n", 12) != 0) {
4356 << filename <<
" is not a KTX file.\n";
4361 uint32_t gl_type, gl_format, internal_format, gl_base_format,
4362 width, height, depth, num_array_elements, num_faces, num_mipmap_levels,
4366 if (ktx.get_uint32() == 0x04030201) {
4368 gl_type = ktx.get_uint32();
4370 gl_format = ktx.get_uint32();
4371 internal_format = ktx.get_uint32();
4372 gl_base_format = ktx.get_uint32();
4373 width = ktx.get_uint32();
4374 height = ktx.get_uint32();
4375 depth = ktx.get_uint32();
4376 num_array_elements = ktx.get_uint32();
4377 num_faces = ktx.get_uint32();
4378 num_mipmap_levels = ktx.get_uint32();
4379 kvdata_size = ktx.get_uint32();
4382 gl_type = ktx.get_be_uint32();
4383 ktx.get_be_uint32();
4384 gl_format = ktx.get_be_uint32();
4385 internal_format = ktx.get_be_uint32();
4386 gl_base_format = ktx.get_be_uint32();
4387 width = ktx.get_be_uint32();
4388 height = ktx.get_be_uint32();
4389 depth = ktx.get_be_uint32();
4390 num_array_elements = ktx.get_be_uint32();
4391 num_faces = ktx.get_be_uint32();
4392 num_mipmap_levels = ktx.get_be_uint32();
4393 kvdata_size = ktx.get_be_uint32();
4397 ktx.skip_bytes(kvdata_size);
4400 CompressionMode compression;
4402 bool swap_bgr =
false;
4404 if (gl_type == 0 || gl_format == 0) {
4406 if (gl_type > 0 || gl_format > 0) {
4408 <<
"Compressed textures must have both type and format set to 0.\n";
4411 type = T_unsigned_byte;
4412 compression = CM_on;
4414 KTXFormat base_format;
4415 switch ((KTXCompressedFormat)internal_format) {
4416 case KTX_COMPRESSED_RED:
4418 base_format = KTX_RED;
4420 case KTX_COMPRESSED_RG:
4422 base_format = KTX_RG;
4424 case KTX_COMPRESSED_RGB:
4426 base_format = KTX_RGB;
4428 case KTX_COMPRESSED_RGBA:
4430 base_format = KTX_RGBA;
4432 case KTX_COMPRESSED_SRGB:
4434 base_format = KTX_SRGB;
4436 case KTX_COMPRESSED_SRGB_ALPHA:
4437 format = F_srgb_alpha;
4438 base_format = KTX_SRGB_ALPHA;
4440 case KTX_COMPRESSED_RGB_FXT1_3DFX:
4442 base_format = KTX_RGB;
4443 compression = CM_fxt1;
4445 case KTX_COMPRESSED_RGBA_FXT1_3DFX:
4447 base_format = KTX_RGBA;
4448 compression = CM_fxt1;
4450 case KTX_COMPRESSED_RGB_S3TC_DXT1:
4452 base_format = KTX_RGB;
4453 compression = CM_dxt1;
4455 case KTX_COMPRESSED_RGBA_S3TC_DXT1:
4457 base_format = KTX_RGB;
4458 compression = CM_dxt1;
4460 case KTX_COMPRESSED_RGBA_S3TC_DXT3:
4462 base_format = KTX_RGBA;
4463 compression = CM_dxt3;
4465 case KTX_COMPRESSED_RGBA_S3TC_DXT5:
4467 base_format = KTX_RGBA;
4468 compression = CM_dxt5;
4470 case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1:
4471 format = F_srgb_alpha;
4472 base_format = KTX_SRGB_ALPHA;
4473 compression = CM_dxt1;
4475 case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3:
4476 format = F_srgb_alpha;
4477 base_format = KTX_SRGB_ALPHA;
4478 compression = CM_dxt3;
4480 case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5:
4481 format = F_srgb_alpha;
4482 base_format = KTX_SRGB_ALPHA;
4483 compression = CM_dxt5;
4485 case KTX_COMPRESSED_SRGB_S3TC_DXT1:
4487 base_format = KTX_SRGB;
4488 compression = CM_dxt1;
4490 case KTX_COMPRESSED_RED_RGTC1:
4491 case KTX_COMPRESSED_SIGNED_RED_RGTC1:
4493 base_format = KTX_RED;
4494 compression = CM_rgtc;
4496 case KTX_COMPRESSED_RG_RGTC2:
4497 case KTX_COMPRESSED_SIGNED_RG_RGTC2:
4499 base_format = KTX_RG;
4500 compression = CM_rgtc;
4504 base_format = KTX_RGB;
4505 compression = CM_etc1;
4507 case KTX_ETC1_SRGB8:
4509 base_format = KTX_SRGB;
4510 compression = CM_etc1;
4512 case KTX_COMPRESSED_RGB8_ETC2:
4514 base_format = KTX_RGB;
4515 compression = CM_etc2;
4517 case KTX_COMPRESSED_SRGB8_ETC2:
4519 base_format = KTX_SRGB;
4520 compression = CM_etc2;
4522 case KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
4524 base_format = KTX_RGBA;
4525 compression = CM_etc2;
4527 case KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
4529 base_format = KTX_SRGB8_ALPHA8;
4530 compression = CM_etc2;
4532 case KTX_COMPRESSED_RGBA8_ETC2_EAC:
4534 base_format = KTX_RGBA;
4535 compression = CM_etc2;
4537 case KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
4538 format = F_srgb_alpha;
4539 base_format = KTX_SRGB8_ALPHA8;
4540 compression = CM_etc2;
4542 case KTX_COMPRESSED_R11_EAC:
4543 case KTX_COMPRESSED_SIGNED_R11_EAC:
4545 base_format = KTX_RED;
4546 compression = CM_eac;
4548 case KTX_COMPRESSED_RG11_EAC:
4549 case KTX_COMPRESSED_SIGNED_RG11_EAC:
4551 base_format = KTX_RG;
4552 compression = CM_eac;
4554 case KTX_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1:
4555 format = F_srgb_alpha;
4556 base_format = KTX_SRGB_ALPHA;
4557 compression = CM_pvr1_2bpp;
4559 case KTX_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1:
4560 format = F_srgb_alpha;
4561 base_format = KTX_SRGB_ALPHA;
4562 compression = CM_pvr1_4bpp;
4564 case KTX_COMPRESSED_RGBA_BPTC_UNORM:
4565 case KTX_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
4566 case KTX_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
4567 case KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
4570 << filename <<
" has unsupported compressed internal format " << internal_format <<
"\n";
4574 if (base_format != gl_base_format) {
4576 << filename <<
" has internal format that is incompatible with base "
4577 "format (0x" << std::hex << gl_base_format <<
", expected 0x"
4578 << base_format << std::dec <<
")\n";
4584 compression = CM_off;
4585 switch ((KTXType)gl_type) {
4589 case KTX_UNSIGNED_BYTE:
4590 type = T_unsigned_byte;
4595 case KTX_UNSIGNED_SHORT:
4596 type = T_unsigned_short;
4601 case KTX_UNSIGNED_INT:
4602 type = T_unsigned_int;
4607 case KTX_HALF_FLOAT:
4608 type = T_half_float;
4610 case KTX_UNSIGNED_INT_24_8:
4611 type = T_unsigned_int_24_8;
4615 << filename <<
" has unsupported component type " << gl_type <<
"\n";
4619 if (gl_format != gl_base_format) {
4621 << filename <<
" has mismatched formats: " << gl_format <<
" != "
4622 << gl_base_format <<
"\n";
4625 switch (gl_format) {
4626 case KTX_DEPTH_COMPONENT:
4627 switch (internal_format) {
4628 case KTX_DEPTH_COMPONENT:
4629 format = F_depth_component;
4631 case KTX_DEPTH_COMPONENT16:
4632 format = F_depth_component16;
4634 case KTX_DEPTH_COMPONENT24:
4635 format = F_depth_component24;
4637 case KTX_DEPTH_COMPONENT32:
4638 case KTX_DEPTH_COMPONENT32F:
4639 format = F_depth_component32;
4642 format = F_depth_component;
4644 << filename <<
" has unsupported depth component format " << internal_format <<
"\n";
4648 case KTX_DEPTH_STENCIL:
4649 format = F_depth_stencil;
4650 if (internal_format != KTX_DEPTH_STENCIL &&
4651 internal_format != KTX_DEPTH24_STENCIL8) {
4653 << filename <<
" has unsupported depth stencil format " << internal_format <<
"\n";
4658 switch (internal_format) {
4676 << filename <<
" has unsupported red format " << internal_format <<
"\n";
4680 case KTX_RED_INTEGER:
4681 switch (internal_format) {
4696 << filename <<
" has unsupported red integer format " << internal_format <<
"\n";
4703 if (internal_format != KTX_GREEN) {
4705 << filename <<
" has unsupported green format " << internal_format <<
"\n";
4711 if (internal_format != KTX_BLUE) {
4713 << filename <<
" has unsupported blue format " << internal_format <<
"\n";
4718 switch (internal_format) {
4726 case KTX_RG16_SNORM:
4736 << filename <<
" has unsupported RG format " << internal_format <<
"\n";
4740 case KTX_RG_INTEGER:
4741 switch (internal_format) {
4756 << filename <<
" has unsupported RG integer format " << internal_format <<
"\n";
4764 switch (internal_format) {
4781 case KTX_R11F_G11F_B10F:
4782 format = F_r11_g11_b10;
4785 case KTX_RGB8_SNORM:
4789 case KTX_RGB16_SNORM:
4803 << filename <<
" has unsupported RGB format " << internal_format <<
"\n";
4807 case KTX_RGB_INTEGER:
4809 case KTX_BGR_INTEGER:
4810 switch (internal_format) {
4825 << filename <<
" has unsupported RGB integer format " << internal_format <<
"\n";
4833 switch (internal_format) {
4835 case KTX_RGBA_SNORM:
4848 format = F_rgb10_a2;
4851 case KTX_RGBA8_SNORM:
4855 case KTX_RGBA16_SNORM:
4862 case KTX_SRGB_ALPHA:
4863 case KTX_SRGB8_ALPHA8:
4864 format = F_srgb_alpha;
4869 << filename <<
" has unsupported RGBA format " << internal_format <<
"\n";
4874 case KTX_RGBA_INTEGER:
4876 case KTX_BGRA_INTEGER:
4877 switch (internal_format) {
4892 << filename <<
" has unsupported RGBA integer format " << internal_format <<
"\n";
4898 format = F_luminance;
4901 case KTX_LUMINANCE_ALPHA:
4902 format = F_luminance_alpha;
4909 case KTX_STENCIL_INDEX:
4912 << filename <<
" has unsupported format " << gl_format <<
"\n";
4917 TextureType texture_type;
4919 texture_type = TT_3d_texture;
4921 }
else if (num_faces > 1) {
4922 if (num_faces != 6) {
4924 << filename <<
" has " << num_faces <<
" cube map faces, expected 6\n";
4927 if (width != height) {
4929 << filename <<
" is cube map, but does not have square dimensions\n";
4932 if (num_array_elements > 0) {
4933 depth = num_array_elements * 6;
4934 texture_type = TT_cube_map_array;
4937 texture_type = TT_cube_map;
4940 }
else if (height > 0) {
4941 if (num_array_elements > 0) {
4942 depth = num_array_elements;
4943 texture_type = TT_2d_texture_array;
4946 texture_type = TT_2d_texture;
4949 }
else if (width > 0) {
4951 if (num_array_elements > 0) {
4952 height = num_array_elements;
4953 texture_type = TT_1d_texture_array;
4956 texture_type = TT_1d_texture;
4961 << filename <<
" has zero size\n";
4965 do_setup_texture(cdata, texture_type, width, height, depth, type, format);
4967 cdata->_orig_file_x_size = cdata->_x_size;
4968 cdata->_orig_file_y_size = cdata->_y_size;
4969 cdata->_compression = compression;
4970 cdata->_ram_image_compression = compression;
4973 bool generate_mipmaps =
false;
4974 if (num_mipmap_levels == 0) {
4975 generate_mipmaps =
true;
4976 num_mipmap_levels = 1;
4979 for (uint32_t n = 0; n < num_mipmap_levels; ++n) {
4980 uint32_t image_size;
4982 image_size = ktx.get_be_uint32();
4984 image_size = ktx.get_uint32();
4988 if (compression == CM_off) {
4989 uint32_t row_size = do_get_expected_mipmap_x_size(cdata, (
int)n) * cdata->_num_components * cdata->_component_width;
4990 uint32_t num_rows = do_get_expected_mipmap_y_size(cdata, (
int)n) * do_get_expected_mipmap_z_size(cdata, (
int)n);
4991 uint32_t row_padded = (row_size + 3) & ~3;
4993 if (image_size == row_size * num_rows) {
4994 if (row_padded != row_size) {
4998 << filename <<
" does not have proper row padding for mipmap "
4999 "level " << n <<
"\n";
5001 image = PTA_uchar::empty_array(image_size);
5002 ktx.extract_bytes(image.p(), image_size);
5004 }
else if (image_size != row_padded * num_rows) {
5006 << filename <<
" has invalid image size " << image_size
5007 <<
" for mipmap level " << n <<
" (expected "
5008 << row_padded * num_rows <<
")\n";
5013 image = PTA_uchar::empty_array(row_size * num_rows);
5014 uint32_t skip = row_padded - row_size;
5015 unsigned char *p = image.p();
5016 for (uint32_t row = 0; row < num_rows; ++row) {
5017 ktx.extract_bytes(p, row_size);
5018 ktx.skip_bytes(skip);
5025 unsigned char *begin = image.p();
5026 const unsigned char *end = image.p() + image.size();
5027 size_t skip = cdata->_num_components;
5028 nassertr(skip == 3 || skip == 4,
false);
5030 switch (cdata->_component_width) {
5032 for (
unsigned char *p = begin; p < end; p += skip) {
5037 for (
short *p = (
short *)begin; p < (
short *)end; p += skip) {
5042 for (
int *p = (
int *)begin; p < (
int *)end; p += skip) {
5047 nassert_raise(
"unexpected channel count");
5052 do_set_ram_mipmap_image(cdata, (
int)n, std::move(image),
5053 row_size * do_get_expected_mipmap_y_size(cdata, (
int)n));
5057 image = PTA_uchar::empty_array(image_size);
5058 ktx.extract_bytes(image.p(), image_size);
5059 do_set_ram_mipmap_image(cdata, (
int)n, std::move(image), image_size / depth);
5062 ktx.skip_bytes(3 - ((image_size + 3) & 3));
5065 cdata->_has_read_pages =
true;
5066 cdata->_has_read_mipmaps =
true;
5067 cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
5069 if (generate_mipmaps) {
5070 do_generate_ram_mipmap_images(cdata,
false);
5076 << filename <<
": truncated KTX file.\n";
5080 cdata->_loaded_from_image =
true;
5081 cdata->_loaded_from_txo =
true;
5091do_write(CData *cdata,
5092 const Filename &fullpath,
int z,
int n,
bool write_pages,
bool write_mipmaps) {
5093 if (is_txo_filename(fullpath)) {
5094 if (!do_has_bam_rawdata(cdata)) {
5095 do_get_bam_rawdata(cdata);
5097 nassertr(do_has_bam_rawdata(cdata),
false);
5098 return do_write_txo_file(cdata, fullpath);
5101 if (!do_has_uncompressed_ram_image(cdata)) {
5102 do_get_uncompressed_ram_image(cdata);
5105 nassertr(do_has_ram_mipmap_image(cdata, n),
false);
5106 nassertr(cdata->_ram_image_compression == CM_off,
false);
5108 if (write_pages && write_mipmaps) {
5111 int num_levels = cdata->_ram_images.size();
5113 for (
int n = 0; n < num_levels; ++n) {
5114 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
5116 for (z = 0; z < num_pages; ++z) {
5121 <<
"Filename requires two different hash sequences: " << fullpath
5132 }
else if (write_pages) {
5135 if (!fullpath_pattern.
has_hash()) {
5137 <<
"Filename requires a hash mark: " << fullpath
5142 int num_pages = cdata->_z_size * cdata->_num_views;
5143 for (z = 0; z < num_pages; ++z) {
5149 }
else if (write_mipmaps) {
5152 if (!fullpath_pattern.
has_hash()) {
5154 <<
"Filename requires a hash mark: " << fullpath
5159 int num_levels = cdata->_ram_images.size();
5160 for (
int n = 0; n < num_levels; ++n) {
5168 if (!do_write_one(cdata, fullpath, z, n)) {
5181do_write_one(CData *cdata,
const Filename &fullpath,
int z,
int n) {
5182 if (!do_has_ram_mipmap_image(cdata, n)) {
5186 nassertr(cdata->_ram_image_compression == CM_off,
false);
5189 if (cdata->_component_type == T_float) {
5192 if (!do_store_one(cdata, pfm, z, n)) {
5195 success = pfm.
write(fullpath);
5200 if (type ==
nullptr) {
5202 <<
"Texture::write() - couldn't determine type from extension: " << fullpath << endl;
5207 if (!do_store_one(cdata, pnmimage, z, n)) {
5210 success = pnmimage.
write(fullpath, type);
5215 <<
"Texture::write() - couldn't write: " << fullpath << endl;
5226do_store_one(CData *cdata,
PNMImage &pnmimage,
int z,
int n) {
5228 do_get_uncompressed_ram_image(cdata);
5230 if (!do_has_ram_mipmap_image(cdata, n)) {
5234 nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n),
false);
5235 nassertr(cdata->_ram_image_compression == CM_off,
false);
5237 if (cdata->_component_type == T_float) {
5240 bool success = convert_to_pfm(pfm,
5241 do_get_expected_mipmap_x_size(cdata, n),
5242 do_get_expected_mipmap_y_size(cdata, n),
5243 cdata->_num_components, cdata->_component_width,
5244 cdata->_ram_images[n]._image,
5245 do_get_ram_mipmap_page_size(cdata, n), z);
5249 return pfm.
store(pnmimage);
5252 return convert_to_pnmimage(pnmimage,
5253 do_get_expected_mipmap_x_size(cdata, n),
5254 do_get_expected_mipmap_y_size(cdata, n),
5255 cdata->_num_components, cdata->_component_type,
5257 cdata->_ram_images[n]._image,
5258 do_get_ram_mipmap_page_size(cdata, n), z);
5265do_store_one(CData *cdata,
PfmFile &pfm,
int z,
int n) {
5267 do_get_uncompressed_ram_image(cdata);
5269 if (!do_has_ram_mipmap_image(cdata, n)) {
5273 nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n),
false);
5274 nassertr(cdata->_ram_image_compression == CM_off,
false);
5276 if (cdata->_component_type != T_float) {
5280 convert_to_pnmimage(pnmimage,
5281 do_get_expected_mipmap_x_size(cdata, n),
5282 do_get_expected_mipmap_y_size(cdata, n),
5283 cdata->_num_components, cdata->_component_type,
5285 cdata->_ram_images[n]._image,
5286 do_get_ram_mipmap_page_size(cdata, n), z);
5290 return pfm.
load(pnmimage);
5293 return convert_to_pfm(pfm,
5294 do_get_expected_mipmap_x_size(cdata, n),
5295 do_get_expected_mipmap_y_size(cdata, n),
5296 cdata->_num_components, cdata->_component_width,
5297 cdata->_ram_images[n]._image,
5298 do_get_ram_mipmap_page_size(cdata, n), z);
5305do_write_txo_file(
const CData *cdata,
const Filename &fullpath)
const {
5307 Filename filename = Filename::binary_filename(fullpath);
5309 if (out ==
nullptr) {
5311 <<
"Unable to open " << filename <<
"\n";
5315 bool success = do_write_txo(cdata, *out, fullpath);
5324do_write_txo(
const CData *cdata, ostream &out,
const string &filename)
const {
5327 if (!dout.
open(out, filename)) {
5329 <<
"Could not write texture object: " << filename <<
"\n";
5335 <<
"Unable to write to " << filename <<
"\n";
5340 if (!writer.init()) {
5344 writer.set_file_texture_mode(BamWriter::BTM_rawdata);
5346 if (!writer.write_object(
this)) {
5350 if (!do_has_bam_rawdata(cdata)) {
5352 << get_name() <<
" does not have ram image\n";
5373Texture::CData *Texture::
5374unlocked_ensure_ram_image(
bool allow_compression) {
5380 while (_reloading) {
5385 const CData *cdata = _cycler.read(current_thread);
5387 if (
has_ram_image && !allow_compression && cdata->_ram_image_compression != Texture::CM_off) {
5395 return _cycler.elevate_read_upstream(cdata,
false, current_thread);
5399 nassertr(!_reloading,
nullptr);
5402 PT(
Texture) tex = do_make_copy(cdata);
5403 _cycler.release_read(cdata);
5408 CDWriter cdata_tex(tex->_cycler,
true);
5409 tex->do_reload_ram_image(cdata_tex, allow_compression);
5413 CData *cdataw = _cycler.write_upstream(
false, current_thread);
5420 cdataw->_orig_file_x_size = cdata_tex->_orig_file_x_size;
5421 cdataw->_orig_file_y_size = cdata_tex->_orig_file_y_size;
5425 if (cdata_tex->_x_size != cdataw->_x_size ||
5426 cdata_tex->_y_size != cdataw->_y_size ||
5427 cdata_tex->_z_size != cdataw->_z_size ||
5428 cdata_tex->_num_views != cdataw->_num_views ||
5429 cdata_tex->_num_components != cdataw->_num_components ||
5430 cdata_tex->_component_width != cdataw->_component_width ||
5431 cdata_tex->_texture_type != cdataw->_texture_type ||
5432 cdata_tex->_component_type != cdataw->_component_type) {
5434 cdataw->_x_size = cdata_tex->_x_size;
5435 cdataw->_y_size = cdata_tex->_y_size;
5436 cdataw->_z_size = cdata_tex->_z_size;
5437 cdataw->_num_views = cdata_tex->_num_views;
5439 cdataw->_num_components = cdata_tex->_num_components;
5440 cdataw->_component_width = cdata_tex->_component_width;
5441 cdataw->_texture_type = cdata_tex->_texture_type;
5442 cdataw->_format = cdata_tex->_format;
5443 cdataw->_component_type = cdata_tex->_component_type;
5445 cdataw->inc_properties_modified();
5446 cdataw->inc_image_modified();
5449 cdataw->_keep_ram_image = cdata_tex->_keep_ram_image;
5450 cdataw->_ram_image_compression = cdata_tex->_ram_image_compression;
5451 cdataw->_ram_images = cdata_tex->_ram_images;
5453 nassertr(_reloading,
nullptr);
5475do_reload_ram_image(CData *cdata,
bool allow_compression) {
5479 if (!do_has_compression(cdata)) {
5480 allow_compression =
false;
5486 record = cache->lookup(cdata->_fullpath,
"txo");
5487 if (record !=
nullptr &&
5488 record->has_data()) {
5493 int x_size = cdata->_orig_file_x_size;
5494 int y_size = cdata->_orig_file_y_size;
5495 do_adjust_this_size(cdata, x_size, y_size, cdata->_filename.get_basename(),
true);
5496 if (x_size != tex->get_x_size() || y_size != tex->get_y_size()) {
5497 if (gobj_cat.is_debug()) {
5499 <<
"Cached texture " << *
this <<
" has size "
5500 << tex->get_x_size() <<
" x " << tex->get_y_size()
5501 <<
" instead of " << x_size <<
" x " << y_size
5502 <<
"; ignoring cache.\n";
5507 if (!allow_compression && tex->get_ram_image_compression() != Texture::CM_off) {
5508 if (gobj_cat.is_debug()) {
5510 <<
"Cached texture " << *
this
5511 <<
" is compressed in cache; ignoring cache.\n";
5515 <<
"Texture " << get_name() <<
" reloaded from disk cache\n";
5520 CDReader cdata_tex(tex->_cycler);
5521 cdata->_x_size = cdata_tex->_x_size;
5522 cdata->_y_size = cdata_tex->_y_size;
5523 if (cdata->_num_components != cdata_tex->_num_components) {
5524 cdata->_num_components = cdata_tex->_num_components;
5525 cdata->_format = cdata_tex->_format;
5527 cdata->_component_type = cdata_tex->_component_type;
5528 cdata->_compression = cdata_tex->_compression;
5529 cdata->_ram_image_compression = cdata_tex->_ram_image_compression;
5530 cdata->_ram_images = cdata_tex->_ram_images;
5531 cdata->_loaded_from_image =
true;
5533 bool was_compressed = (cdata->_ram_image_compression != CM_off);
5534 if (do_consider_auto_process_ram_image(cdata,
uses_mipmaps(), allow_compression)) {
5535 bool is_compressed = (cdata->_ram_image_compression != CM_off);
5536 if (!was_compressed && is_compressed &&
5542 cache->
store(record);
5553 <<
"Reloading texture " << get_name() <<
"\n";
5558 if (cdata->_has_read_pages) {
5561 if (cdata->_has_read_mipmaps) {
5562 n = cdata->_num_mipmap_levels_read;
5565 cdata->_loaded_from_image =
false;
5566 Format orig_format = cdata->_format;
5567 int orig_num_components = cdata->_num_components;
5570 if (allow_compression) {
5571 options.set_texture_flags(LoaderOptions::TF_preload |
5572 LoaderOptions::TF_allow_compression);
5574 options.set_texture_flags(LoaderOptions::TF_preload);
5576 do_read(cdata, cdata->_fullpath, cdata->_alpha_fullpath,
5577 cdata->_primary_file_num_channels, cdata->_alpha_file_channel,
5578 z, n, cdata->_has_read_pages, cdata->_has_read_mipmaps, options,
nullptr);
5580 if (orig_num_components == cdata->_num_components) {
5583 cdata->_format = orig_format;
5586 if (do_has_ram_image(cdata) && record !=
nullptr) {
5589 if (record !=
nullptr) {
5593 cache->
store(record);
5603do_modify_ram_image(CData *cdata) {
5604 if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty() ||
5605 cdata->_ram_image_compression != CM_off) {
5606 do_make_ram_image(cdata);
5608 do_clear_ram_mipmap_images(cdata);
5610 return cdata->_ram_images[0]._image;
5618do_make_ram_image(CData *cdata) {
5619 int image_size = do_get_expected_ram_image_size(cdata);
5620 cdata->_ram_images.clear();
5621 cdata->_ram_images.push_back(RamImage());
5622 cdata->_ram_images[0]._page_size = do_get_expected_ram_page_size(cdata);
5623 cdata->_ram_images[0]._image = PTA_uchar::empty_array(image_size, get_class_type());
5624 cdata->_ram_images[0]._pointer_image =
nullptr;
5625 cdata->_ram_image_compression = CM_off;
5627 if (cdata->_has_clear_color) {
5629 unsigned char pixel[16];
5630 const int pixel_size = do_get_clear_data(cdata,
pixel);
5631 nassertr(pixel_size > 0, cdata->_ram_images[0]._image);
5633 unsigned char *image_data = cdata->_ram_images[0]._image;
5634 for (
int i = 0; i < image_size; i += pixel_size) {
5635 memcpy(image_data + i,
pixel, pixel_size);
5639 return cdata->_ram_images[0]._image;
5650do_set_ram_image(CData *cdata,
CPTA_uchar image, Texture::CompressionMode compression,
5652 nassertv(compression != CM_default);
5653 nassertv(compression != CM_off || image.size() == do_get_expected_ram_image_size(cdata));
5654 if (cdata->_ram_images.empty()) {
5655 cdata->_ram_images.push_back(RamImage());
5657 do_clear_ram_mipmap_images(cdata);
5659 if (page_size == 0) {
5660 page_size = image.size();
5662 if (cdata->_ram_images[0]._image != image ||
5663 cdata->_ram_images[0]._page_size != page_size ||
5664 cdata->_ram_image_compression != compression) {
5666 cdata->_ram_images[0]._page_size = page_size;
5667 cdata->_ram_images[0]._pointer_image =
nullptr;
5668 cdata->_ram_image_compression = compression;
5669 cdata->inc_image_modified();
5678do_modify_ram_mipmap_image(CData *cdata,
int n) {
5679 nassertr(cdata->_ram_image_compression == CM_off, PTA_uchar());
5681 if (n >= (
int)cdata->_ram_images.size() ||
5682 cdata->_ram_images[n]._image.empty()) {
5683 do_make_ram_mipmap_image(cdata, n);
5685 return cdata->_ram_images[n]._image;
5692do_make_ram_mipmap_image(CData *cdata,
int n) {
5693 nassertr(cdata->_ram_image_compression == CM_off, PTA_uchar(get_class_type()));
5695 while (n >= (
int)cdata->_ram_images.size()) {
5696 cdata->_ram_images.push_back(RamImage());
5699 size_t image_size = do_get_expected_ram_mipmap_image_size(cdata, n);
5700 cdata->_ram_images[n]._image = PTA_uchar::empty_array(image_size, get_class_type());
5701 cdata->_ram_images[n]._pointer_image =
nullptr;
5702 cdata->_ram_images[n]._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
5704 if (cdata->_has_clear_color) {
5706 unsigned char pixel[16];
5707 const size_t pixel_size = (size_t)do_get_clear_data(cdata,
pixel);
5708 nassertr(pixel_size > 0, cdata->_ram_images[n]._image);
5710 unsigned char *image_data = cdata->_ram_images[n]._image;
5711 for (
size_t i = 0; i < image_size; i += pixel_size) {
5712 memcpy(image_data + i,
pixel, pixel_size);
5716 return cdata->_ram_images[n]._image;
5723do_set_ram_mipmap_image(CData *cdata,
int n,
CPTA_uchar image,
size_t page_size) {
5724 nassertv(cdata->_ram_image_compression != CM_off || image.size() == do_get_expected_ram_mipmap_image_size(cdata, n));
5726 while (n >= (
int)cdata->_ram_images.size()) {
5727 cdata->_ram_images.push_back(RamImage());
5729 if (page_size == 0) {
5730 page_size = image.size();
5733 if (cdata->_ram_images[n]._image != image ||
5734 cdata->_ram_images[n]._page_size != page_size) {
5736 cdata->_ram_images[n]._pointer_image =
nullptr;
5737 cdata->_ram_images[n]._page_size = page_size;
5738 cdata->inc_image_modified();
5750do_get_clear_data(
const CData *cdata,
unsigned char *into)
const {
5751 nassertr(cdata->_has_clear_color, 0);
5753 int num_components = cdata->_num_components;
5754 nassertr(num_components > 0, 0);
5755 nassertr(num_components <= 4, 0);
5757 LVecBase4 clear_value = cdata->_clear_color;
5760 if (num_components >= 3) {
5761 std::swap(clear_value[0], clear_value[2]);
5764 switch (cdata->_component_type) {
5765 case T_unsigned_byte:
5766 if (
is_srgb(cdata->_format)) {
5770 switch (num_components) {
5771 case 4: into[3] = (
unsigned char)alpha;
5772 case 3: into[2] = (
unsigned char)color.b;
5773 case 2: into[1] = (
unsigned char)color.g;
5774 case 1: into[0] = (
unsigned char)color.r;
5777 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor::zero());
5779 for (
int i = 0; i < num_components; ++i) {
5780 into[i] = (
unsigned char)scaled[i];
5785 case T_unsigned_short:
5787 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor::zero());
5789 for (
int i = 0; i < num_components; ++i) {
5790 ((
unsigned short *)into)[i] = (
unsigned short)scaled[i];
5796 for (
int i = 0; i < num_components; ++i) {
5797 ((
float *)into)[i] = clear_value[i];
5801 case T_unsigned_int_24_8:
5802 nassertr(num_components == 1, 0);
5803 *((
unsigned int *)into) =
5804 ((
unsigned int)(clear_value[0] * 16777215) << 8) +
5805 (
unsigned int)max(min(clear_value[1], (PN_stdfloat)255), (PN_stdfloat)0);
5811 for (
int i = 0; i < num_components; ++i) {
5812 ((
int *)into)[i] = (int)clear_value[i];
5818 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor(-1));
5820 for (
int i = 0; i < num_components; ++i) {
5821 ((
signed char *)into)[i] = (
signed char)scaled[i];
5828 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor(-1));
5830 for (
int i = 0; i < num_components; ++i) {
5831 ((
short *)into)[i] = (short)scaled[i];
5837 for (
int i = 0; i < num_components; ++i) {
5842 v.uf = clear_value[i];
5843 uint16_t sign = ((v.ui & 0x80000000u) >> 16u);
5844 uint32_t mantissa = (v.ui & 0x007fffffu);
5845 uint16_t exponent = (uint16_t)std::min(std::max((
int)((v.ui & 0x7f800000u) >> 23u) - 112, 0), 31);
5846 mantissa += (mantissa & 0x00001000u) << 1u;
5847 ((uint16_t *)into)[i] = (uint16_t)(sign | ((exponent << 10u) | (mantissa >> 13u)));
5851 case T_unsigned_int:
5854 for (
int i = 0; i < num_components; ++i) {
5855 ((
unsigned int *)into)[i] = (
unsigned int)clear_value[i];
5859 return num_components * cdata->_component_width;
5870consider_auto_process_ram_image(
bool generate_mipmaps,
bool allow_compression) {
5871 CDWriter cdata(_cycler,
false);
5872 return do_consider_auto_process_ram_image(cdata, generate_mipmaps, allow_compression);
5883do_consider_auto_process_ram_image(CData *cdata,
bool generate_mipmaps,
5884 bool allow_compression) {
5885 bool modified =
false;
5887 if (generate_mipmaps && !driver_generate_mipmaps &&
5888 cdata->_ram_images.size() == 1) {
5889 do_generate_ram_mipmap_images(cdata,
false);
5893 if (allow_compression && !driver_compress_textures) {
5894 CompressionMode compression = cdata->_compression;
5895 if (compression == CM_default && compressed_textures) {
5896 if (cdata->_texture_type == Texture::TT_buffer_texture) {
5897 compression = CM_off;
5900 compression = CM_on;
5903 if (compression != CM_off && cdata->_ram_image_compression == CM_off) {
5905 if (do_compress_ram_image(cdata, compression, QL_default, gsg)) {
5906 if (gobj_cat.is_debug()) {
5908 <<
"Compressed " << get_name() <<
" with "
5909 << cdata->_ram_image_compression <<
"\n";
5923do_compress_ram_image(CData *cdata, Texture::CompressionMode compression,
5924 Texture::QualityLevel quality_level,
5926 nassertr(compression != CM_off,
false);
5928 if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
5932 if (compression == CM_on) {
5934 switch (cdata->_format) {
5935 case Texture::F_rgbm:
5936 case Texture::F_rgb:
5937 case Texture::F_rgb5:
5938 case Texture::F_rgba5:
5939 case Texture::F_rgb8:
5940 case Texture::F_rgb12:
5941 case Texture::F_rgb332:
5942 case Texture::F_rgb16:
5943 case Texture::F_rgb32:
5944 case Texture::F_rgb10_a2:
5945 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt1)) {
5946 compression = CM_dxt1;
5947 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt3)) {
5948 compression = CM_dxt3;
5949 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5950 compression = CM_dxt5;
5951 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5952 compression = CM_etc2;
5953 }
else if (gsg->get_supports_compressed_texture_format(CM_etc1)) {
5954 compression = CM_etc1;
5958 case Texture::F_rgba4:
5959 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt3)) {
5960 compression = CM_dxt3;
5961 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5962 compression = CM_dxt5;
5963 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5964 compression = CM_etc2;
5968 case Texture::F_rgba:
5969 case Texture::F_rgba8:
5970 case Texture::F_rgba12:
5971 case Texture::F_rgba16:
5972 case Texture::F_rgba32:
5973 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5974 compression = CM_dxt5;
5975 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5976 compression = CM_etc2;
5980 case Texture::F_red:
5982 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_rgtc)) {
5983 compression = CM_rgtc;
5984 }
else if (gsg->get_supports_compressed_texture_format(CM_eac)) {
5985 compression = CM_eac;
5995 if (quality_level == Texture::QL_default) {
5996 quality_level = cdata->_quality_level;
5998 if (quality_level == Texture::QL_default) {
5999 quality_level = texture_quality_level;
6002 if (compression == CM_rgtc) {
6004 if (cdata->_component_type != T_unsigned_byte) {
6008 if (!do_has_all_ram_mipmap_images(cdata)) {
6011 do_generate_ram_mipmap_images(cdata,
false);
6014 RamImages compressed_ram_images;
6015 compressed_ram_images.resize(cdata->_ram_images.size());
6017 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
6018 const RamImage *uncompressed_image = &cdata->_ram_images[n];
6020 int x_size = do_get_expected_mipmap_x_size(cdata, n);
6021 int y_size = do_get_expected_mipmap_y_size(cdata, n);
6022 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
6027 RamImage temp_image;
6028 if ((x_size | y_size) & 0x3) {
6029 int virtual_x_size = x_size;
6030 int virtual_y_size = y_size;
6031 x_size = (x_size + 3) & ~0x3;
6032 y_size = (y_size + 3) & ~0x3;
6034 temp_image._page_size = x_size * y_size * cdata->_num_components;
6035 temp_image._image = PTA_uchar::empty_array(temp_image._page_size * num_pages);
6037 for (
int z = 0; z < num_pages; ++z) {
6038 unsigned char *dest = temp_image._image.p() + z * temp_image._page_size;
6039 unsigned const char *src = uncompressed_image->_image.p() + z * uncompressed_image->_page_size;
6041 for (
int y = 0; y < virtual_y_size; ++y) {
6042 memcpy(dest, src, virtual_x_size);
6043 src += virtual_x_size;
6048 uncompressed_image = &temp_image;
6052 RamImage &compressed_image = compressed_ram_images[n];
6053 compressed_image._page_size = (x_size * y_size * cdata->_num_components) >> 1;
6054 compressed_image._image = PTA_uchar::empty_array(compressed_image._page_size * num_pages);
6056 if (cdata->_num_components == 1) {
6057 do_compress_ram_image_bc4(*uncompressed_image, compressed_image,
6058 x_size, y_size, num_pages);
6059 }
else if (cdata->_num_components == 2) {
6060 do_compress_ram_image_bc5(*uncompressed_image, compressed_image,
6061 x_size, y_size, num_pages);
6068 cdata->_ram_images.swap(compressed_ram_images);
6069 cdata->_ram_image_compression = CM_rgtc;
6074 if (cdata->_texture_type != TT_3d_texture &&
6075 cdata->_texture_type != TT_2d_texture_array &&
6076 cdata->_component_type == T_unsigned_byte) {
6077 int squish_flags = 0;
6078 switch (compression) {
6080 squish_flags |= squish::kDxt1;
6084 squish_flags |= squish::kDxt3;
6088 squish_flags |= squish::kDxt5;
6095 if (squish_flags != 0) {
6097 switch (quality_level) {
6099 squish_flags |= squish::kColourRangeFit;
6104 squish_flags |= squish::kColourRangeFit;
6109 squish_flags |= squish::kColourIterativeClusterFit;
6116 if (do_squish(cdata, compression, squish_flags)) {
6130do_uncompress_ram_image(CData *cdata) {
6131 nassertr(!cdata->_ram_images.empty(),
false);
6133 if (cdata->_ram_image_compression == CM_rgtc) {
6135 RamImages uncompressed_ram_images;
6136 uncompressed_ram_images.resize(cdata->_ram_images.size());
6138 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
6139 const RamImage &compressed_image = cdata->_ram_images[n];
6141 int x_size = do_get_expected_mipmap_x_size(cdata, n);
6142 int y_size = do_get_expected_mipmap_y_size(cdata, n);
6143 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
6145 RamImage &uncompressed_image = uncompressed_ram_images[n];
6146 uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
6147 uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * num_pages);
6149 if (cdata->_num_components == 1) {
6150 do_uncompress_ram_image_bc4(compressed_image, uncompressed_image,
6151 x_size, y_size, num_pages);
6152 }
else if (cdata->_num_components == 2) {
6153 do_uncompress_ram_image_bc5(compressed_image, uncompressed_image,
6154 x_size, y_size, num_pages);
6160 cdata->_ram_images.swap(uncompressed_ram_images);
6161 cdata->_ram_image_compression = CM_off;
6166 if (cdata->_texture_type != TT_3d_texture &&
6167 cdata->_texture_type != TT_2d_texture_array &&
6168 cdata->_component_type == T_unsigned_byte) {
6169 int squish_flags = 0;
6170 switch (cdata->_ram_image_compression) {
6172 squish_flags |= squish::kDxt1;
6176 squish_flags |= squish::kDxt3;
6180 squish_flags |= squish::kDxt5;
6187 if (squish_flags != 0) {
6189 if (do_unsquish(cdata, squish_flags)) {
6202do_compress_ram_image_bc4(
const RamImage &uncompressed_image,
6203 RamImage &compressed_image,
6204 int x_size,
int y_size,
int num_pages) {
6205 int x_blocks = (x_size >> 2);
6206 int y_blocks = (y_size >> 2);
6212 nassertv((
size_t)x_blocks * (
size_t)y_blocks * 4 * 4 <= uncompressed_image._page_size);
6213 nassertv((
size_t)x_size * (
size_t)y_size == uncompressed_image._page_size);
6215 static const int remap[] = {1, 7, 6, 5, 4, 3, 2, 0};
6217 for (
int z = 0; z < num_pages; ++z) {
6218 unsigned char *dest = compressed_image._image.p() + z * compressed_image._page_size;
6219 unsigned const char *src = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6222 for (
int y = 0; y < y_blocks; ++y) {
6223 for (
int x = 0; x < x_blocks; ++x) {
6226 unsigned char minv, maxv;
6227 unsigned const char *blk = src;
6232 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6233 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6234 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6236 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6237 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6238 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6239 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6241 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6242 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6243 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6244 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6246 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6247 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6248 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6249 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6254 fac = 7.5f / (maxv - minv);
6259 a = (remap[(int)(blk[0] * fac + add)])
6260 | (remap[(
int)(blk[1] * fac + add)] << 3)
6261 | (remap[(int)(blk[2] * fac + add)] << 6)
6262 | (remap[(
int)(blk[3] * fac + add)] << 9);
6264 b = (remap[(int)(blk[0] * fac + add)] << 4)
6265 | (remap[(
int)(blk[1] * fac + add)] << 7)
6266 | (remap[(int)(blk[2] * fac + add)] << 10)
6267 | (remap[(
int)(blk[3] * fac + add)] << 13);
6269 c = (remap[(int)(blk[0] * fac + add)])
6270 | (remap[(
int)(blk[1] * fac + add)] << 3)
6271 | (remap[(int)(blk[2] * fac + add)] << 6)
6272 | (remap[(
int)(blk[3] * fac + add)] << 9);
6274 d = (remap[(int)(blk[0] * fac + add)] << 4)
6275 | (remap[(
int)(blk[1] * fac + add)] << 7)
6276 | (remap[(int)(blk[2] * fac + add)] << 10)
6277 | (remap[(
int)(blk[3] * fac + add)] << 13);
6281 *(dest++) = a & 0xff;
6282 *(dest++) = (a >> 8) | (b & 0xf0);
6284 *(dest++) = c & 0xff;
6285 *(dest++) = (c >> 8) | (d & 0xf0);
6301do_compress_ram_image_bc5(
const RamImage &uncompressed_image,
6302 RamImage &compressed_image,
6303 int x_size,
int y_size,
int num_pages) {
6304 int x_blocks = (x_size >> 2);
6305 int y_blocks = (y_size >> 2);
6306 int stride = x_size * 2;
6311 nassertv((
size_t)x_blocks * (
size_t)y_blocks * 4 * 4 * 2 <= uncompressed_image._page_size);
6312 nassertv((
size_t)stride * (
size_t)y_size == uncompressed_image._page_size);
6314 static const int remap[] = {1, 7, 6, 5, 4, 3, 2, 0};
6316 for (
int z = 0; z < num_pages; ++z) {
6317 unsigned char *dest = compressed_image._image.p() + z * compressed_image._page_size;
6318 unsigned const char *src = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6321 for (
int y = 0; y < y_blocks; ++y) {
6322 for (
int x = 0; x < x_blocks; ++x) {
6325 unsigned char minv, maxv;
6326 unsigned const char *blk = src;
6331 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6332 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6333 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6335 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6336 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6337 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6338 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6340 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6341 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6342 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6343 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6345 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6346 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6347 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6348 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6352 fac = 7.5f / (maxv - minv);
6358 a = (remap[(int)(blk[0] * fac + add)])
6359 | (remap[(
int)(blk[2] * fac + add)] << 3)
6360 | (remap[(int)(blk[4] * fac + add)] << 6)
6361 | (remap[(
int)(blk[6] * fac + add)] << 9);
6363 b = (remap[(int)(blk[0] * fac + add)] << 4)
6364 | (remap[(
int)(blk[2] * fac + add)] << 7)
6365 | (remap[(int)(blk[4] * fac + add)] << 10)
6366 | (remap[(
int)(blk[6] * fac + add)] << 13);
6368 c = (remap[(int)(blk[0] * fac + add)])
6369 | (remap[(
int)(blk[2] * fac + add)] << 3)
6370 | (remap[(int)(blk[4] * fac + add)] << 6)
6371 | (remap[(
int)(blk[6] * fac + add)] << 9);
6373 d = (remap[(int)(blk[0] * fac + add)] << 4)
6374 | (remap[(
int)(blk[2] * fac + add)] << 7)
6375 | (remap[(int)(blk[4] * fac + add)] << 10)
6376 | (remap[(
int)(blk[6] * fac + add)] << 13);
6380 *(dest++) = a & 0xff;
6381 *(dest++) = (a >> 8) | (b & 0xf0);
6383 *(dest++) = c & 0xff;
6384 *(dest++) = (c >> 8) | (d & 0xf0);
6391 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6392 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6393 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6395 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6396 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6397 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6398 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6400 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6401 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6402 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6403 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6405 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6406 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6407 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6408 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6412 fac = 7.5f / (maxv - minv);
6418 a = (remap[(int)(blk[0] * fac + add)])
6419 | (remap[(
int)(blk[2] * fac + add)] << 3)
6420 | (remap[(int)(blk[4] * fac + add)] << 6)
6421 | (remap[(
int)(blk[6] * fac + add)] << 9);
6423 b = (remap[(int)(blk[0] * fac + add)] << 4)
6424 | (remap[(
int)(blk[2] * fac + add)] << 7)
6425 | (remap[(int)(blk[4] * fac + add)] << 10)
6426 | (remap[(
int)(blk[6] * fac + add)] << 13);
6428 c = (remap[(int)(blk[0] * fac + add)])
6429 | (remap[(
int)(blk[2] * fac + add)] << 3)
6430 | (remap[(int)(blk[4] * fac + add)] << 6)
6431 | (remap[(
int)(blk[6] * fac + add)] << 9);
6433 d = (remap[(int)(blk[0] * fac + add)] << 4)
6434 | (remap[(
int)(blk[2] * fac + add)] << 7)
6435 | (remap[(int)(blk[4] * fac + add)] << 10)
6436 | (remap[(
int)(blk[6] * fac + add)] << 13);
6440 *(dest++) = a & 0xff;
6441 *(dest++) = (a >> 8) | (b & 0xf0);
6443 *(dest++) = c & 0xff;
6444 *(dest++) = (c >> 8) | (d & 0xf0);
6460do_uncompress_ram_image_bc4(
const RamImage &compressed_image,
6461 RamImage &uncompressed_image,
6462 int x_size,
int y_size,
int num_pages) {
6463 int x_blocks = (x_size >> 2);
6464 int y_blocks = (y_size >> 2);
6466 for (
int z = 0; z < num_pages; ++z) {
6467 unsigned char *dest = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6468 unsigned const char *src = compressed_image._image.p() + z * compressed_image._page_size;
6472 for (
int y = 0; y < y_blocks; ++y) {
6473 for (
int x = 0; x < x_blocks; ++x) {
6474 unsigned char *blk = dest;
6477 if (tbl[0] > tbl[1]) {
6478 tbl[2] = (tbl[0] * 6 + tbl[1] * 1) / 7.0f;
6479 tbl[3] = (tbl[0] * 5 + tbl[1] * 2) / 7.0f;
6480 tbl[4] = (tbl[0] * 4 + tbl[1] * 3) / 7.0f;
6481 tbl[5] = (tbl[0] * 3 + tbl[1] * 4) / 7.0f;
6482 tbl[6] = (tbl[0] * 2 + tbl[1] * 5) / 7.0f;
6483 tbl[7] = (tbl[0] * 1 + tbl[1] * 6) / 7.0f;
6485 tbl[2] = (tbl[0] * 4 + tbl[1] * 1) / 5.0f;
6486 tbl[3] = (tbl[0] * 3 + tbl[1] * 2) / 5.0f;
6487 tbl[4] = (tbl[0] * 2 + tbl[1] * 3) / 5.0f;
6488 tbl[5] = (tbl[0] * 1 + tbl[1] * 4) / 5.0f;
6492 int v = src[2] + (src[3] << 8) + (src[4] << 16);
6493 blk[0] = tbl[v & 0x7];
6494 blk[1] = tbl[(v & 0x000038) >> 3];
6495 blk[2] = tbl[(v & 0x0001c0) >> 6];
6496 blk[3] = tbl[(v & 0x000e00) >> 9];
6498 blk[0] = tbl[(v & 0x007000) >> 12];
6499 blk[1] = tbl[(v & 0x038000) >> 15];
6500 blk[2] = tbl[(v & 0x1c0000) >> 18];
6501 blk[3] = tbl[(v & 0xe00000) >> 21];
6503 v = src[5] + (src[6] << 8) + (src[7] << 16);
6504 blk[0] = tbl[v & 0x7];
6505 blk[1] = tbl[(v & 0x000038) >> 3];
6506 blk[2] = tbl[(v & 0x0001c0) >> 6];
6507 blk[3] = tbl[(v & 0x000e00) >> 9];
6509 blk[0] = tbl[(v & 0x007000) >> 12];
6510 blk[1] = tbl[(v & 0x038000) >> 15];
6511 blk[2] = tbl[(v & 0x1c0000) >> 18];
6512 blk[3] = tbl[(v & 0xe00000) >> 21];
6526do_uncompress_ram_image_bc5(
const RamImage &compressed_image,
6527 RamImage &uncompressed_image,
6528 int x_size,
int y_size,
int num_pages) {
6529 int x_blocks = (x_size >> 2);
6530 int y_blocks = (y_size >> 2);
6531 int stride = x_size * 2;
6533 for (
int z = 0; z < num_pages; ++z) {
6534 unsigned char *dest = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6535 unsigned const char *src = compressed_image._image.p() + z * compressed_image._page_size;
6540 for (
int y = 0; y < y_blocks; ++y) {
6541 for (
int x = 0; x < x_blocks; ++x) {
6542 unsigned char *blk = dest;
6545 if (red[0] > red[1]) {
6546 red[2] = (red[0] * 6 + red[1] * 1) / 7.0f;
6547 red[3] = (red[0] * 5 + red[1] * 2) / 7.0f;
6548 red[4] = (red[0] * 4 + red[1] * 3) / 7.0f;
6549 red[5] = (red[0] * 3 + red[1] * 4) / 7.0f;
6550 red[6] = (red[0] * 2 + red[1] * 5) / 7.0f;
6551 red[7] = (red[0] * 1 + red[1] * 6) / 7.0f;
6553 red[2] = (red[0] * 4 + red[1] * 1) / 5.0f;
6554 red[3] = (red[0] * 3 + red[1] * 2) / 5.0f;
6555 red[4] = (red[0] * 2 + red[1] * 3) / 5.0f;
6556 red[5] = (red[0] * 1 + red[1] * 4) / 5.0f;
6562 if (grn[0] > grn[1]) {
6563 grn[2] = (grn[0] * 6 + grn[1] * 1) / 7.0f;
6564 grn[3] = (grn[0] * 5 + grn[1] * 2) / 7.0f;
6565 grn[4] = (grn[0] * 4 + grn[1] * 3) / 7.0f;
6566 grn[5] = (grn[0] * 3 + grn[1] * 4) / 7.0f;
6567 grn[6] = (grn[0] * 2 + grn[1] * 5) / 7.0f;
6568 grn[7] = (grn[0] * 1 + grn[1] * 6) / 7.0f;
6570 grn[2] = (grn[0] * 4 + grn[1] * 1) / 5.0f;
6571 grn[3] = (grn[0] * 3 + grn[1] * 2) / 5.0f;
6572 grn[4] = (grn[0] * 2 + grn[1] * 3) / 5.0f;
6573 grn[5] = (grn[0] * 1 + grn[1] * 4) / 5.0f;
6577 int r = src[2] + (src[3] << 8) + (src[4] << 16);
6578 int g = src[10] + (src[11] << 8) + (src[12] << 16);
6579 blk[0] = red[r & 0x7];
6580 blk[1] = grn[g & 0x7];
6581 blk[2] = red[(r & 0x000038) >> 3];
6582 blk[3] = grn[(g & 0x000038) >> 3];
6583 blk[4] = red[(r & 0x0001c0) >> 6];
6584 blk[5] = grn[(g & 0x0001c0) >> 6];
6585 blk[6] = red[(r & 0x000e00) >> 9];
6586 blk[7] = grn[(g & 0x000e00) >> 9];
6588 blk[0] = red[(r & 0x007000) >> 12];
6589 blk[1] = grn[(g & 0x007000) >> 12];
6590 blk[2] = red[(r & 0x038000) >> 15];
6591 blk[3] = grn[(g & 0x038000) >> 15];
6592 blk[4] = red[(r & 0x1c0000) >> 18];
6593 blk[5] = grn[(g & 0x1c0000) >> 18];
6594 blk[6] = red[(r & 0xe00000) >> 21];
6595 blk[7] = grn[(g & 0xe00000) >> 21];
6597 r = src[5] + (src[6] << 8) + (src[7] << 16);
6598 g = src[13] + (src[14] << 8) + (src[15] << 16);
6599 blk[0] = red[r & 0x7];
6600 blk[1] = grn[g & 0x7];
6601 blk[2] = red[(r & 0x000038) >> 3];
6602 blk[3] = grn[(g & 0x000038) >> 3];
6603 blk[4] = red[(r & 0x0001c0) >> 6];
6604 blk[5] = grn[(g & 0x0001c0) >> 6];
6605 blk[6] = red[(r & 0x000e00) >> 9];
6606 blk[7] = grn[(g & 0x000e00) >> 9];
6608 blk[0] = red[(r & 0x007000) >> 12];
6609 blk[1] = grn[(g & 0x007000) >> 12];
6610 blk[2] = red[(r & 0x038000) >> 15];
6611 blk[3] = grn[(g & 0x038000) >> 15];
6612 blk[4] = red[(r & 0x1c0000) >> 18];
6613 blk[5] = grn[(g & 0x1c0000) >> 18];
6614 blk[6] = red[(r & 0xe00000) >> 21];
6615 blk[7] = grn[(g & 0xe00000) >> 21];
6629do_has_all_ram_mipmap_images(
const CData *cdata)
const {
6630 if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty()) {
6641 int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
6647 if (n >= (
int)cdata->_ram_images.size() || cdata->_ram_images[n]._image.empty()) {
6663do_reconsider_z_size(CData *cdata,
int z,
const LoaderOptions &options) {
6664 if (z >= cdata->_z_size * cdata->_num_views) {
6665 bool num_views_specified =
true;
6666 if (options.get_texture_flags() & LoaderOptions::TF_multiview) {
6673 if (num_views_specified &&
6674 (cdata->_texture_type == Texture::TT_3d_texture ||
6675 cdata->_texture_type == Texture::TT_2d_texture_array)) {
6680 nassertr(cdata->_num_views != 0,
false);
6681 cdata->_z_size = (z / cdata->_num_views) + 1;
6683 }
else if (cdata->_z_size != 0) {
6687 cdata->_num_views = (z / cdata->_z_size) + 1;
6696 do_allocate_pages(cdata);
6709do_allocate_pages(CData *cdata) {
6710 size_t new_size = do_get_expected_ram_image_size(cdata);
6711 if (!cdata->_ram_images.empty() &&
6712 !cdata->_ram_images[0]._image.empty() &&
6713 new_size > cdata->_ram_images[0]._image.size()) {
6714 cdata->_ram_images[0]._image.insert(cdata->_ram_images[0]._image.end(), new_size - cdata->_ram_images[0]._image.size(), 0);
6715 nassertv(cdata->_ram_images[0]._image.size() == new_size);
6726do_reconsider_image_properties(CData *cdata,
int x_size,
int y_size,
int num_components,
6727 Texture::ComponentType component_type,
int z,
6729 if (!cdata->_loaded_from_image || num_components != cdata->_num_components || component_type != cdata->_component_type) {
6735 switch (num_components) {
6737 cdata->_format = F_luminance;
6741 cdata->_format = F_luminance_alpha;
6745 cdata->_format = F_rgb;
6749 cdata->_format = F_rgba;
6754 nassert_raise(
"unexpected channel count");
6755 cdata->_format = F_rgb;
6760 if (!cdata->_loaded_from_image) {
6761 if ((options.get_texture_flags() & LoaderOptions::TF_allow_1d) &&
6762 cdata->_texture_type == TT_2d_texture && x_size != 1 && y_size == 1) {
6764 cdata->_texture_type = TT_1d_texture;
6768 switch (cdata->_texture_type) {
6770 case TT_buffer_texture:
6771 nassertr(y_size == 1,
false);
6774 case TT_cube_map_array:
6775 nassertr(x_size == y_size,
false);
6781 if ((cdata->_x_size != x_size)||(cdata->_y_size != y_size)) {
6782 do_set_pad_size(cdata, 0, 0, 0);
6784 cdata->_x_size = x_size;
6785 cdata->_y_size = y_size;
6786 cdata->_num_components = num_components;
6787 do_set_component_type(cdata, component_type);
6790 if (cdata->_x_size != x_size ||
6791 cdata->_y_size != y_size ||
6792 cdata->_num_components != num_components ||
6793 cdata->_component_type != component_type) {
6795 <<
"Texture properties have changed for texture " << get_name()
6796 <<
" page " << z <<
".\n";
6808do_rescale_texture(CData *cdata) {
6809 int new_x_size = cdata->_x_size;
6810 int new_y_size = cdata->_y_size;
6811 if (cdata->_z_size * cdata->_num_views != 1) {
6812 nassert_raise(
"rescale_texture() doesn't support 3-d or multiview textures.");
6816 if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(),
false)) {
6819 if (!do_store_one(cdata, orig_image, 0, 0)) {
6821 <<
"Couldn't get image in rescale_texture()\n";
6826 <<
"Resizing " << get_name() <<
" to " << new_x_size <<
" x "
6827 << new_y_size <<
"\n";
6831 new_image.quick_filter_from(orig_image);
6833 do_clear_ram_image(cdata);
6834 cdata->inc_image_modified();
6835 cdata->_x_size = new_x_size;
6836 cdata->_y_size = new_y_size;
6837 if (!do_load_one(cdata, new_image, get_name(), 0, 0,
LoaderOptions())) {
6847 if (do_get_auto_texture_scale(cdata) == ATS_pad) {
6848 new_x_size = cdata->_x_size;
6849 new_y_size = cdata->_y_size;
6850 if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(),
true)) {
6851 pad_x_size = new_x_size - cdata->_x_size;
6852 pad_y_size = new_y_size - cdata->_y_size;
6855 if (!do_store_one(cdata, orig_image, 0, 0)) {
6857 <<
"Couldn't get image in rescale_texture()\n";
6863 new_image.copy_sub_image(orig_image, 0, new_y_size - orig_image.
get_y_size());
6865 do_clear_ram_image(cdata);
6866 cdata->_loaded_from_image =
false;
6867 cdata->inc_image_modified();
6868 if (!do_load_one(cdata, new_image, get_name(), 0, 0,
LoaderOptions())) {
6872 do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
6885make_copy_impl()
const {
6886 CDReader cdata(_cycler);
6887 return do_make_copy(cdata);
6894do_make_copy(
const CData *cdata)
const {
6896 CDWriter cdata_tex(tex->_cycler,
true);
6897 tex->do_assign(cdata_tex,
this, cdata);
6906do_assign(CData *cdata,
const Texture *copy,
const CData *cdata_copy) {
6907 cdata->do_assign(cdata_copy);
6914do_clear(CData *cdata) {
6917 CDReader cdata_tex(tex._cycler);
6918 do_assign(cdata, &tex, cdata_tex);
6920 cdata->inc_properties_modified();
6921 cdata->inc_image_modified();
6922 cdata->inc_simple_image_modified();
6929do_setup_texture(CData *cdata, Texture::TextureType texture_type,
6930 int x_size,
int y_size,
int z_size,
6931 Texture::ComponentType component_type,
6932 Texture::Format format) {
6933 switch (texture_type) {
6935 nassertv(y_size == 1 && z_size == 1);
6939 nassertv(z_size == 1);
6945 case TT_2d_texture_array:
6950 nassertv(x_size == y_size && z_size == 6);
6955 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
6956 cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
6957 cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
6960 case TT_cube_map_array:
6962 nassertv(x_size == y_size && z_size % 6 == 0);
6964 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
6965 cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
6966 cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
6969 case TT_buffer_texture:
6970 nassertv(y_size == 1 && z_size == 1);
6973 case TT_1d_texture_array:
6974 nassertv(z_size == 1);
6978 if (texture_type != TT_2d_texture) {
6979 do_clear_simple_ram_image(cdata);
6982 cdata->_texture_type = texture_type;
6983 cdata->_x_size = x_size;
6984 cdata->_y_size = y_size;
6985 cdata->_z_size = z_size;
6986 cdata->_num_views = 1;
6987 do_set_component_type(cdata, component_type);
6988 do_set_format(cdata, format);
6990 do_clear_ram_image(cdata);
6991 do_set_pad_size(cdata, 0, 0, 0);
6992 cdata->_orig_file_x_size = 0;
6993 cdata->_orig_file_y_size = 0;
6994 cdata->_loaded_from_image =
false;
6995 cdata->_loaded_from_txo =
false;
6996 cdata->_has_read_pages =
false;
6997 cdata->_has_read_mipmaps =
false;
7004do_set_format(CData *cdata, Texture::Format format) {
7005 if (format == cdata->_format) {
7008 cdata->_format = format;
7009 cdata->inc_properties_modified();
7011 switch (cdata->_format) {
7013 case F_depth_stencil:
7014 case F_depth_component:
7015 case F_depth_component16:
7016 case F_depth_component24:
7017 case F_depth_component32:
7029 cdata->_num_components = 1;
7032 case F_luminance_alpha:
7033 case F_luminance_alphamask:
7035 case F_sluminance_alpha:
7041 cdata->_num_components = 2;
7057 cdata->_num_components = 3;
7073 cdata->_num_components = 4;
7082do_set_component_type(CData *cdata, Texture::ComponentType component_type) {
7083 cdata->_component_type = component_type;
7085 switch (component_type) {
7086 case T_unsigned_byte:
7088 cdata->_component_width = 1;
7091 case T_unsigned_short:
7094 cdata->_component_width = 2;
7098 case T_unsigned_int_24_8:
7100 case T_unsigned_int:
7101 cdata->_component_width = 4;
7110do_set_x_size(CData *cdata,
int x_size) {
7111 if (cdata->_x_size != x_size) {
7112 cdata->_x_size = x_size;
7113 cdata->inc_image_modified();
7114 do_clear_ram_image(cdata);
7115 do_set_pad_size(cdata, 0, 0, 0);
7123do_set_y_size(CData *cdata,
int y_size) {
7124 if (cdata->_y_size != y_size) {
7125 nassertv((cdata->_texture_type != Texture::TT_buffer_texture &&
7126 cdata->_texture_type != Texture::TT_1d_texture) || y_size == 1);
7127 cdata->_y_size = y_size;
7128 cdata->inc_image_modified();
7129 do_clear_ram_image(cdata);
7130 do_set_pad_size(cdata, 0, 0, 0);
7139do_set_z_size(CData *cdata,
int z_size) {
7140 if (cdata->_z_size != z_size) {
7141 nassertv((cdata->_texture_type == Texture::TT_3d_texture) ||
7142 (cdata->_texture_type == Texture::TT_cube_map && z_size == 6) ||
7143 (cdata->_texture_type == Texture::TT_cube_map_array && z_size % 6 == 0) ||
7144 (cdata->_texture_type == Texture::TT_2d_texture_array) || (z_size == 1));
7145 cdata->_z_size = z_size;
7146 cdata->inc_image_modified();
7147 do_clear_ram_image(cdata);
7148 do_set_pad_size(cdata, 0, 0, 0);
7156do_set_num_views(CData *cdata,
int num_views) {
7157 nassertv(num_views >= 1);
7158 if (cdata->_num_views != num_views) {
7159 cdata->_num_views = num_views;
7160 if (do_has_ram_image(cdata)) {
7161 cdata->inc_image_modified();
7162 do_clear_ram_image(cdata);
7164 do_set_pad_size(cdata, 0, 0, 0);
7172do_set_wrap_u(CData *cdata, SamplerState::WrapMode wrap) {
7173 if (cdata->_default_sampler.get_wrap_u() != wrap) {
7174 cdata->inc_properties_modified();
7175 cdata->_default_sampler.set_wrap_u(wrap);
7183do_set_wrap_v(CData *cdata, SamplerState::WrapMode wrap) {
7184 if (cdata->_default_sampler.get_wrap_v() != wrap) {
7185 cdata->inc_properties_modified();
7186 cdata->_default_sampler.set_wrap_v(wrap);
7194do_set_wrap_w(CData *cdata, SamplerState::WrapMode wrap) {
7195 if (cdata->_default_sampler.get_wrap_w() != wrap) {
7196 cdata->inc_properties_modified();
7197 cdata->_default_sampler.set_wrap_w(wrap);
7205do_set_minfilter(CData *cdata, SamplerState::FilterType filter) {
7206 if (cdata->_default_sampler.get_minfilter() != filter) {
7207 cdata->inc_properties_modified();
7208 cdata->_default_sampler.set_minfilter(filter);
7216do_set_magfilter(CData *cdata, SamplerState::FilterType filter) {
7217 if (cdata->_default_sampler.get_magfilter() != filter) {
7218 cdata->inc_properties_modified();
7219 cdata->_default_sampler.set_magfilter(filter);
7227do_set_anisotropic_degree(CData *cdata,
int anisotropic_degree) {
7228 if (cdata->_default_sampler.get_anisotropic_degree() != anisotropic_degree) {
7229 cdata->inc_properties_modified();
7230 cdata->_default_sampler.set_anisotropic_degree(anisotropic_degree);
7238do_set_border_color(CData *cdata,
const LColor &color) {
7239 if (cdata->_default_sampler.get_border_color() != color) {
7240 cdata->inc_properties_modified();
7241 cdata->_default_sampler.set_border_color(color);
7249do_set_compression(CData *cdata, Texture::CompressionMode compression) {
7250 if (cdata->_compression != compression) {
7251 cdata->inc_properties_modified();
7252 cdata->_compression = compression;
7254 if (do_has_ram_image(cdata)) {
7256 bool has_ram_image_compression = (cdata->_ram_image_compression != CM_off);
7271do_set_quality_level(CData *cdata, Texture::QualityLevel quality_level) {
7272 if (cdata->_quality_level != quality_level) {
7273 cdata->inc_properties_modified();
7274 cdata->_quality_level = quality_level;
7282do_has_compression(
const CData *cdata)
const {
7283 if (cdata->_compression == CM_default) {
7284 if (cdata->_texture_type != Texture::TT_buffer_texture) {
7285 return compressed_textures;
7290 return (cdata->_compression != CM_off);
7299do_has_ram_image(
const CData *cdata)
const {
7300 return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty();
7308do_has_uncompressed_ram_image(
const CData *cdata)
const {
7309 return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty() && cdata->_ram_image_compression == CM_off;
7316do_get_ram_image(CData *cdata) {
7317 if (!do_has_ram_image(cdata) && do_can_reload(cdata)) {
7318 do_reload_ram_image(cdata,
true);
7320 if (do_has_ram_image(cdata)) {
7324 cdata->inc_image_modified();
7325 cdata->inc_properties_modified();
7329 if (cdata->_ram_images.empty()) {
7333 return cdata->_ram_images[0]._image;
7340do_get_uncompressed_ram_image(CData *cdata) {
7341 if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
7344 if (do_uncompress_ram_image(cdata)) {
7345 if (gobj_cat.is_debug()) {
7347 <<
"Uncompressed " << get_name() <<
"\n";
7349 return cdata->_ram_images[0]._image;
7354 if ((!do_has_ram_image(cdata) || cdata->_ram_image_compression != CM_off) && do_can_reload(cdata)) {
7355 do_reload_ram_image(cdata,
false);
7358 if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
7360 if (do_uncompress_ram_image(cdata)) {
7362 <<
"Uncompressed " << get_name() <<
"\n";
7363 return cdata->_ram_images[0]._image;
7367 if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
7371 return cdata->_ram_images[0]._image;
7400 string format =
upcase(requested_format);
7403 CPTA_uchar data = do_get_uncompressed_ram_image(cdata);
7404 if (data ==
nullptr) {
7405 gobj_cat.error() <<
"Couldn't find an uncompressed RAM image!\n";
7408 int imgsize = cdata->_x_size * cdata->_y_size;
7409 nassertr(cdata->_num_components > 0 && cdata->_num_components <= 4,
CPTA_uchar(get_class_type()));
7410 nassertr(data.size() == (
size_t)(cdata->_component_width * cdata->_num_components * imgsize),
CPTA_uchar(get_class_type()));
7413 if ((cdata->_num_components == 1 && format.size() == 1) ||
7414 (cdata->_num_components == 2 && format.size() == 2 && format.at(1) ==
'A' && format.at(0) !=
'A') ||
7415 (cdata->_num_components == 3 && format ==
"BGR") ||
7416 (cdata->_num_components == 4 && format ==
"BGRA")) {
7424 alpha = cdata->_num_components - 1;
7428 for (
size_t i = 0; i < format.size(); ++i) {
7429 if (format[i] !=
'B' && format[i] !=
'G' && format[i] !=
'R' &&
7430 format[i] !=
'A' && format[i] !=
'0' && format[i] !=
'1') {
7431 gobj_cat.error() <<
"Unexpected component character '"
7432 << format[i] <<
"', expected one of RGBA01!\n";
7438 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * format.size() * cdata->_component_width, get_class_type());
7441 if (cdata->_component_width == 1) {
7442 if (format ==
"RGBA" && cdata->_num_components == 4) {
7443 const uint32_t *src = (
const uint32_t *)data.p();
7444 uint32_t *dst = (uint32_t *)newdata.p();
7446 for (
int p = 0; p < imgsize; ++p) {
7447 uint32_t v = *src++;
7448 *dst++ = ((v & 0xff00ff00u)) |
7449 ((v & 0x00ff0000u) >> 16) |
7450 ((v & 0x000000ffu) << 16);
7454 if (format ==
"RGB" && cdata->_num_components == 4) {
7455 const uint32_t *src = (
const uint32_t *)data.p();
7456 uint32_t *dst = (uint32_t *)newdata.p();
7460 int blocks = imgsize >> 2;
7461 for (
int i = 0; i < blocks; ++i) {
7462 uint32_t v0 = *src++;
7463 uint32_t v1 = *src++;
7464 uint32_t v2 = *src++;
7465 uint32_t v3 = *src++;
7466 *dst++ = ((v0 & 0x00ff0000u) >> 16) |
7467 ((v0 & 0x0000ff00u)) |
7468 ((v0 & 0x000000ffu) << 16) |
7469 ((v1 & 0x00ff0000u) << 8);
7470 *dst++ = ((v1 & 0x0000ff00u) >> 8) |
7471 ((v1 & 0x000000ffu) << 8) |
7472 ((v2 & 0x00ff0000u)) |
7473 ((v2 & 0x0000ff00u) << 16);
7474 *dst++ = ((v2 & 0x000000ffu)) |
7475 ((v3 & 0x00ff0000u) >> 8) |
7476 ((v3 & 0x0000ff00u) << 8) |
7477 ((v3 & 0x000000ffu) << 24);
7482 uint8_t *tail = (uint8_t *)dst;
7483 for (
int i = (imgsize & ~0x3); i < imgsize; ++i) {
7484 uint32_t v = *src++;
7485 *tail++ = (v & 0x00ff0000u) >> 16;
7486 *tail++ = (v & 0x0000ff00u) >> 8;
7487 *tail++ = (v & 0x000000ffu);
7491 if (format ==
"BGR" && cdata->_num_components == 4) {
7492 const uint32_t *src = (
const uint32_t *)data.p();
7493 uint32_t *dst = (uint32_t *)newdata.p();
7497 int blocks = imgsize >> 2;
7498 for (
int i = 0; i < blocks; ++i) {
7499 uint32_t v0 = *src++;
7500 uint32_t v1 = *src++;
7501 uint32_t v2 = *src++;
7502 uint32_t v3 = *src++;
7503 *dst++ = (v0 & 0x00ffffffu) | ((v1 & 0x000000ffu) << 24);
7504 *dst++ = ((v1 & 0x00ffff00u) >> 8) | ((v2 & 0x0000ffffu) << 16);
7505 *dst++ = ((v2 & 0x00ff0000u) >> 16) | ((v3 & 0x00ffffffu) << 8);
7510 uint8_t *tail = (uint8_t *)dst;
7511 for (
int i = (imgsize & ~0x3); i < imgsize; ++i) {
7512 uint32_t v = *src++;
7513 *tail++ = (v & 0x000000ffu);
7514 *tail++ = (v & 0x0000ff00u) >> 8;
7515 *tail++ = (v & 0x00ff0000u) >> 16;
7519 const uint8_t *src = (
const uint8_t *)data.p();
7520 uint8_t *dst = (uint8_t *)newdata.p();
7522 if (format ==
"RGB" && cdata->_num_components == 3) {
7523 for (
int i = 0; i < imgsize; ++i) {
7531 if (format ==
"A" && cdata->_num_components != 3) {
7533 for (
int p = 0; p < imgsize; ++p) {
7534 dst[p] = src[alpha];
7535 src += cdata->_num_components;
7540 for (
int p = 0; p < imgsize; ++p) {
7541 for (
size_t i = 0; i < format.size(); ++i) {
7542 if (format[i] ==
'B' || (cdata->_num_components <= 2 && format[i] !=
'A')) {
7544 }
else if (format[i] ==
'G') {
7546 }
else if (format[i] ==
'R') {
7548 }
else if (format[i] ==
'A') {
7550 *dst++ = src[alpha];
7554 }
else if (format[i] ==
'1') {
7560 src += cdata->_num_components;
7566 for (
int p = 0; p < imgsize; ++p) {
7567 for (
size_t i = 0; i < format.size(); ++i) {
7569 if (format[i] ==
'B' || (cdata->_num_components <= 2 && format[i] !=
'A')) {
7571 }
else if (format[i] ==
'G') {
7573 }
else if (format[i] ==
'R') {
7575 }
else if (format[i] ==
'A') {
7579 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), -1, cdata->_component_width);
7582 }
else if (format[i] ==
'1') {
7583 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), -1, cdata->_component_width);
7586 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), 0, cdata->_component_width);
7589 memcpy((
void*)(newdata + (p * format.size() + i) * cdata->_component_width),
7590 (
void*)(data + (p * cdata->_num_components + component) * cdata->_component_width),
7591 cdata->_component_width);
7601do_set_simple_ram_image(CData *cdata,
CPTA_uchar image,
int x_size,
int y_size) {
7602 nassertv(cdata->_texture_type == TT_2d_texture);
7603 size_t expected_page_size = (size_t)(x_size * y_size * 4);
7604 nassertv(image.size() == expected_page_size);
7606 cdata->_simple_x_size = x_size;
7607 cdata->_simple_y_size = y_size;
7609 cdata->_simple_ram_image._page_size = image.size();
7610 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
7611 cdata->inc_simple_image_modified();
7618do_get_expected_num_mipmap_levels(
const CData *cdata)
const {
7619 if (cdata->_texture_type == Texture::TT_buffer_texture) {
7622 int size = max(cdata->_x_size, cdata->_y_size);
7623 if (cdata->_texture_type == Texture::TT_3d_texture) {
7624 size = max(size, cdata->_z_size);
7638do_get_ram_mipmap_page_size(
const CData *cdata,
int n)
const {
7639 if (cdata->_ram_image_compression != CM_off) {
7640 if (n >= 0 && n < (
int)cdata->_ram_images.size()) {
7641 return cdata->_ram_images[n]._page_size;
7645 return do_get_expected_ram_mipmap_page_size(cdata, n);
7653do_get_expected_mipmap_x_size(
const CData *cdata,
int n)
const {
7654 int size = max(cdata->_x_size, 1);
7655 while (n > 0 && size > 1) {
7666do_get_expected_mipmap_y_size(
const CData *cdata,
int n)
const {
7667 int size = max(cdata->_y_size, 1);
7668 while (n > 0 && size > 1) {
7679do_get_expected_mipmap_z_size(
const CData *cdata,
int n)
const {
7683 if (cdata->_texture_type == Texture::TT_3d_texture) {
7684 int size = max(cdata->_z_size, 1);
7685 while (n > 0 && size > 1) {
7692 return cdata->_z_size;
7700do_clear_simple_ram_image(CData *cdata) {
7701 cdata->_simple_x_size = 0;
7702 cdata->_simple_y_size = 0;
7703 cdata->_simple_ram_image._image.clear();
7704 cdata->_simple_ram_image._page_size = 0;
7705 cdata->_simple_image_date_generated = 0;
7710 cdata->inc_simple_image_modified();
7717do_clear_ram_mipmap_images(CData *cdata) {
7718 if (!cdata->_ram_images.empty()) {
7719 cdata->_ram_images.erase(cdata->_ram_images.begin() + 1, cdata->_ram_images.end());
7729do_generate_ram_mipmap_images(CData *cdata,
bool allow_recompress) {
7730 nassertv(do_has_ram_image(cdata));
7732 if (do_get_expected_num_mipmap_levels(cdata) == 1) {
7737 RamImage orig_compressed_image;
7738 CompressionMode orig_compression_mode = CM_off;
7740 if (cdata->_ram_image_compression != CM_off) {
7744 orig_compressed_image = cdata->_ram_images[0];
7745 orig_compression_mode = cdata->_ram_image_compression;
7748 do_get_uncompressed_ram_image(cdata);
7750 if (cdata->_ram_image_compression != CM_off) {
7752 <<
"Cannot generate mipmap levels for image with compression "
7753 << cdata->_ram_image_compression <<
"\n";
7758 do_clear_ram_mipmap_images(cdata);
7760 if (gobj_cat.is_debug()) {
7762 <<
"Generating mipmap levels for " << *
this <<
"\n";
7765 if (cdata->_texture_type == Texture::TT_3d_texture && cdata->_z_size != 1) {
7767 int x_size = cdata->_x_size;
7768 int y_size = cdata->_y_size;
7769 int z_size = cdata->_z_size;
7771 while (x_size > 1 || y_size > 1 || z_size > 1) {
7772 cdata->_ram_images.push_back(RamImage());
7773 do_filter_3d_mipmap_level(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
7774 x_size, y_size, z_size);
7775 x_size = max(x_size >> 1, 1);
7776 y_size = max(y_size >> 1, 1);
7777 z_size = max(z_size >> 1, 1);
7783 int x_size = cdata->_x_size;
7784 int y_size = cdata->_y_size;
7786 while (x_size > 1 || y_size > 1) {
7787 cdata->_ram_images.push_back(RamImage());
7788 do_filter_2d_mipmap_pages(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
7790 x_size = max(x_size >> 1, 1);
7791 y_size = max(y_size >> 1, 1);
7796 if (orig_compression_mode != CM_off && allow_recompress) {
7802 nassertv(cdata->_ram_images.size() > 1);
7803 int l0_x_size = cdata->_x_size;
7804 int l0_y_size = cdata->_y_size;
7805 int l0_z_size = cdata->_z_size;
7806 cdata->_x_size = do_get_expected_mipmap_x_size(cdata, 1);
7807 cdata->_y_size = do_get_expected_mipmap_y_size(cdata, 1);
7808 cdata->_z_size = do_get_expected_mipmap_z_size(cdata, 1);
7809 RamImage uncompressed_image = cdata->_ram_images[0];
7810 cdata->_ram_images.erase(cdata->_ram_images.begin());
7812 bool success = do_compress_ram_image(cdata, orig_compression_mode, QL_default,
nullptr);
7815 if (gobj_cat.is_debug()) {
7817 <<
"Compressed " << get_name() <<
" generated mipmaps with "
7818 << cdata->_ram_image_compression <<
"\n";
7820 cdata->_ram_images.insert(cdata->_ram_images.begin(), orig_compressed_image);
7822 cdata->_ram_images.insert(cdata->_ram_images.begin(), uncompressed_image);
7824 cdata->_x_size = l0_x_size;
7825 cdata->_y_size = l0_y_size;
7826 cdata->_z_size = l0_z_size;
7834do_set_pad_size(CData *cdata,
int x,
int y,
int z) {
7835 if (x > cdata->_x_size) {
7838 if (y > cdata->_y_size) {
7841 if (z > cdata->_z_size) {
7845 cdata->_pad_x_size = x;
7846 cdata->_pad_y_size = y;
7847 cdata->_pad_z_size = z;
7856do_can_reload(
const CData *cdata)
const {
7857 return (cdata->_loaded_from_image && !cdata->_fullpath.empty());
7864do_reload(CData *cdata) {
7865 if (do_can_reload(cdata)) {
7866 do_clear_ram_image(cdata);
7867 do_reload_ram_image(cdata,
true);
7868 if (do_has_ram_image(cdata)) {
7870 cdata->inc_image_modified();
7886do_has_bam_rawdata(
const CData *cdata)
const {
7887 return do_has_ram_image(cdata);
7895do_get_bam_rawdata(CData *cdata) {
7896 do_get_ram_image(cdata);
7904convert_from_pnmimage(PTA_uchar &image,
size_t page_size,
7905 int row_stride,
int x,
int y,
int z,
7906 const PNMImage &pnmimage,
int num_components,
7907 int component_width) {
7911 int pixel_size = num_components * component_width;
7914 if (row_stride == 0) {
7915 row_stride = x_size;
7917 row_skip = (row_stride - x_size) * pixel_size;
7918 nassertv(row_skip >= 0);
7921 bool is_grayscale = (num_components == 1 || num_components == 2);
7922 bool has_alpha = (num_components == 2 || num_components == 4);
7923 bool img_has_alpha = pnmimage.
has_alpha();
7925 int idx = page_size * z;
7926 nassertv(idx + page_size <= image.size());
7927 unsigned char *p = &image[idx];
7929 if (x != 0 || y != 0) {
7930 p += (row_stride * y + x) * pixel_size;
7933 if (maxval == 255 && component_width == 1) {
7938 switch (num_components) {
7940 for (
int j = y_size-1; j >= 0; j--) {
7941 const xel *row = array + j * x_size;
7942 for (
int i = 0; i < x_size; i++) {
7943 *p++ = (uchar)PPM_GETB(row[i]);
7950 if (img_has_alpha) {
7952 for (
int j = y_size-1; j >= 0; j--) {
7953 const xel *row = array + j * x_size;
7954 const xelval *alpha_row = alpha + j * x_size;
7955 for (
int i = 0; i < x_size; i++) {
7956 *p++ = (uchar)PPM_GETB(row[i]);
7957 *p++ = (uchar)alpha_row[i];
7962 for (
int j = y_size-1; j >= 0; j--) {
7963 const xel *row = array + j * x_size;
7964 for (
int i = 0; i < x_size; i++) {
7965 *p++ = (uchar)PPM_GETB(row[i]);
7974 for (
int j = y_size-1; j >= 0; j--) {
7975 const xel *row = array + j * x_size;
7976 for (
int i = 0; i < x_size; i++) {
7977 *p++ = (uchar)PPM_GETB(row[i]);
7978 *p++ = (uchar)PPM_GETG(row[i]);
7979 *p++ = (uchar)PPM_GETR(row[i]);
7986 if (img_has_alpha) {
7988 for (
int j = y_size-1; j >= 0; j--) {
7989 const xel *row = array + j * x_size;
7990 const xelval *alpha_row = alpha + j * x_size;
7991 for (
int i = 0; i < x_size; i++) {
7992 *p++ = (uchar)PPM_GETB(row[i]);
7993 *p++ = (uchar)PPM_GETG(row[i]);
7994 *p++ = (uchar)PPM_GETR(row[i]);
7995 *p++ = (uchar)alpha_row[i];
8000 for (
int j = y_size-1; j >= 0; j--) {
8001 const xel *row = array + j * x_size;
8002 for (
int i = 0; i < x_size; i++) {
8003 *p++ = (uchar)PPM_GETB(row[i]);
8004 *p++ = (uchar)PPM_GETG(row[i]);
8005 *p++ = (uchar)PPM_GETR(row[i]);
8014 nassertv(num_components >= 1 && num_components <= 4);
8018 }
else if (maxval == 65535 && component_width == 2) {
8021 for (
int j = y_size-1; j >= 0; j--) {
8022 for (
int i = 0; i < x_size; i++) {
8028 store_unscaled_short(p, pnmimage.
get_red_val(i, j));
8031 if (img_has_alpha) {
8034 store_unscaled_short(p, 65535);
8041 }
else if (component_width == 1) {
8045 double scale = 255.0 / (double)maxval;
8047 for (
int j = y_size-1; j >= 0; j--) {
8048 for (
int i = 0; i < x_size; i++) {
8050 store_scaled_byte(p, pnmimage.
get_gray_val(i, j), scale);
8052 store_scaled_byte(p, pnmimage.
get_blue_val(i, j), scale);
8054 store_scaled_byte(p, pnmimage.
get_red_val(i, j), scale);
8057 if (img_has_alpha) {
8060 store_unscaled_byte(p, 255);
8070 double scale = 65535.0 / (double)maxval;
8072 for (
int j = y_size-1; j >= 0; j--) {
8073 for (
int i = 0; i < x_size; i++) {
8075 store_scaled_short(p, pnmimage.
get_gray_val(i, j), scale);
8077 store_scaled_short(p, pnmimage.
get_blue_val(i, j), scale);
8079 store_scaled_short(p, pnmimage.
get_red_val(i, j), scale);
8082 if (img_has_alpha) {
8085 store_unscaled_short(p, 65535);
8099convert_from_pfm(PTA_uchar &image,
size_t page_size,
int z,
8100 const PfmFile &pfm,
int num_components,
int component_width) {
8101 nassertv(component_width == 4);
8105 int idx = page_size * z;
8106 nassertv(idx + page_size <= image.size());
8107 PN_float32 *p = (PN_float32 *)&image[idx];
8109 switch (num_components) {
8112 for (
int j = y_size-1; j >= 0; j--) {
8113 for (
int i = 0; i < x_size; i++) {
8123 for (
int j = y_size-1; j >= 0; j--) {
8124 for (
int i = 0; i < x_size; i++) {
8136 for (
int j = y_size-1; j >= 0; j--) {
8137 for (
int i = 0; i < x_size; i++) {
8150 for (
int j = y_size-1; j >= 0; j--) {
8151 for (
int i = 0; i < x_size; i++) {
8163 nassert_raise(
"unexpected channel count");
8167 nassertv((
unsigned char *)p == &image[idx] + page_size);
8175convert_to_pnmimage(
PNMImage &pnmimage,
int x_size,
int y_size,
8176 int num_components, ComponentType component_type,
8177 bool is_srgb,
CPTA_uchar image,
size_t page_size,
int z) {
8178 xelval maxval = 0xff;
8179 if (component_type != T_unsigned_byte && component_type != T_byte) {
8182 ColorSpace color_space =
is_srgb ? CS_sRGB : CS_linear;
8183 pnmimage.
clear(x_size, y_size, num_components, maxval,
nullptr, color_space);
8187 int idx = page_size * z;
8188 nassertr(idx + page_size <= image.size(),
false);
8193 switch (component_type) {
8194 case T_unsigned_byte:
8196 const unsigned char *p = &image[idx];
8198 for (
int j = y_size-1; j >= 0; j--) {
8199 xel *row = array + j * x_size;
8200 xelval *alpha_row = alpha + j * x_size;
8201 for (
int i = 0; i < x_size; i++) {
8202 PPM_PUTB(row[i], *p++);
8203 alpha_row[i] = *p++;
8207 for (
int j = y_size-1; j >= 0; j--) {
8208 xel *row = array + j * x_size;
8209 for (
int i = 0; i < x_size; i++) {
8210 PPM_PUTB(row[i], *p++);
8214 nassertr(p == &image[idx] + page_size,
false);
8216 const unsigned char *p = &image[idx];
8218 for (
int j = y_size-1; j >= 0; j--) {
8219 xel *row = array + j * x_size;
8220 xelval *alpha_row = alpha + j * x_size;
8221 for (
int i = 0; i < x_size; i++) {
8222 PPM_PUTB(row[i], *p++);
8223 PPM_PUTG(row[i], *p++);
8224 PPM_PUTR(row[i], *p++);
8225 alpha_row[i] = *p++;
8229 for (
int j = y_size-1; j >= 0; j--) {
8230 xel *row = array + j * x_size;
8231 for (
int i = 0; i < x_size; i++) {
8232 PPM_PUTB(row[i], *p++);
8233 PPM_PUTG(row[i], *p++);
8234 PPM_PUTR(row[i], *p++);
8238 nassertr(p == &image[idx] + page_size,
false);
8242 case T_unsigned_short:
8244 const uint16_t *p = (
const uint16_t *)&image[idx];
8246 for (
int j = y_size-1; j >= 0; j--) {
8247 xel *row = array + j * x_size;
8248 xelval *alpha_row = alpha + j * x_size;
8249 for (
int i = 0; i < x_size; i++) {
8250 PPM_PUTB(row[i], *p++);
8251 if (!is_grayscale) {
8252 PPM_PUTG(row[i], *p++);
8253 PPM_PUTR(row[i], *p++);
8256 alpha_row[i] = *p++;
8260 nassertr((
const unsigned char *)p == &image[idx] + page_size,
false);
8264 case T_unsigned_int:
8266 const uint32_t *p = (
const uint32_t *)&image[idx];
8268 for (
int j = y_size-1; j >= 0; j--) {
8269 xel *row = array + j * x_size;
8270 xelval *alpha_row = alpha + j * x_size;
8271 for (
int i = 0; i < x_size; i++) {
8272 PPM_PUTB(row[i], (*p++) >> 16u);
8273 if (!is_grayscale) {
8274 PPM_PUTG(row[i], (*p++) >> 16u);
8275 PPM_PUTR(row[i], (*p++) >> 16u);
8278 alpha_row[i] = (*p++) >> 16u;
8282 nassertr((
const unsigned char *)p == &image[idx] + page_size,
false);
8288 const unsigned char *p = &image[idx];
8290 for (
int j = y_size-1; j >= 0; j--) {
8291 for (
int i = 0; i < x_size; i++) {
8292 pnmimage.
set_blue(i, j, get_half_float(p));
8293 if (!is_grayscale) {
8294 pnmimage.
set_green(i, j, get_half_float(p));
8295 pnmimage.
set_red(i, j, get_half_float(p));
8298 pnmimage.
set_alpha(i, j, get_half_float(p));
8302 nassertr(p == &image[idx] + page_size,
false);
8318convert_to_pfm(
PfmFile &pfm,
int x_size,
int y_size,
8319 int num_components,
int component_width,
8321 nassertr(component_width == 4,
false);
8322 pfm.
clear(x_size, y_size, num_components);
8324 int idx = page_size * z;
8325 nassertr(idx + page_size <= image.size(),
false);
8326 const PN_float32 *p = (
const PN_float32 *)&image[idx];
8328 switch (num_components) {
8330 for (
int j = y_size-1; j >= 0; j--) {
8331 for (
int i = 0; i < x_size; i++) {
8339 for (
int j = y_size-1; j >= 0; j--) {
8340 for (
int i = 0; i < x_size; i++) {
8350 for (
int j = y_size-1; j >= 0; j--) {
8351 for (
int i = 0; i < x_size; i++) {
8362 for (
int j = y_size-1; j >= 0; j--) {
8363 for (
int i = 0; i < x_size; i++) {
8374 nassert_raise(
"unexpected channel count");
8378 nassertr((
unsigned char *)p == &image[idx] + page_size,
false);
8386read_dds_level_bgr8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8388 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8389 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8391 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8392 size_t row_bytes = x_size * 3;
8393 PTA_uchar image = PTA_uchar::empty_array(size);
8394 for (
int y = y_size - 1; y >= 0; --y) {
8395 unsigned char *p = image.p() + y * row_bytes;
8396 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8397 in.read((
char *)p, row_bytes);
8407read_dds_level_rgb8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8409 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8410 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8412 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8413 size_t row_bytes = x_size * 3;
8414 PTA_uchar image = PTA_uchar::empty_array(size);
8415 for (
int y = y_size - 1; y >= 0; --y) {
8416 unsigned char *p = image.p() + y * row_bytes;
8417 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8418 in.read((
char *)p, row_bytes);
8421 for (
int x = 0; x < x_size; ++x) {
8422 unsigned char r = p[0];
8427 nassertr(p <= image.p() + size, PTA_uchar());
8437read_dds_level_abgr8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8439 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8440 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8442 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8443 size_t row_bytes = x_size * 4;
8444 PTA_uchar image = PTA_uchar::empty_array(size);
8445 for (
int y = y_size - 1; y >= 0; --y) {
8446 unsigned char *p = image.p() + y * row_bytes;
8447 in.read((
char *)p, row_bytes);
8449 uint32_t *pw = (uint32_t *)p;
8450 for (
int x = 0; x < x_size; ++x) {
8452#ifdef WORDS_BIGENDIAN
8454 w = ((w & 0xff00) << 16) | ((w & 0xff000000U) >> 16) | (w & 0xff00ff);
8457 w = ((w & 0xff) << 16) | ((w & 0xff0000) >> 16) | (w & 0xff00ff00U);
8462 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8472read_dds_level_rgba8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8474 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8475 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8477 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8478 size_t row_bytes = x_size * 4;
8479 PTA_uchar image = PTA_uchar::empty_array(size);
8480 for (
int y = y_size - 1; y >= 0; --y) {
8481 unsigned char *p = image.p() + y * row_bytes;
8482 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8483 in.read((
char *)p, row_bytes);
8493read_dds_level_abgr16(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8495 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8496 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8498 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8499 size_t row_bytes = x_size * 8;
8500 PTA_uchar image = PTA_uchar::empty_array(size);
8501 for (
int y = y_size - 1; y >= 0; --y) {
8502 unsigned char *p = image.p() + y * row_bytes;
8503 in.read((
char *)p, row_bytes);
8505 uint16_t *pw = (uint16_t *)p;
8506 for (
int x = 0; x < x_size; ++x) {
8510 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8520read_dds_level_abgr32(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8522 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8523 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8525 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8526 size_t row_bytes = x_size * 16;
8527 nassertr(row_bytes * y_size == size, PTA_uchar());
8528 PTA_uchar image = PTA_uchar::empty_array(size);
8529 for (
int y = y_size - 1; y >= 0; --y) {
8530 unsigned char *p = image.p() + y * row_bytes;
8531 in.read((
char *)p, row_bytes);
8533 uint32_t *pw = (uint32_t *)p;
8534 for (
int x = 0; x < x_size; ++x) {
8538 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8548read_dds_level_raw(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8549 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8550 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8552 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8553 size_t row_bytes = x_size * cdata->_num_components * cdata->_component_width;
8554 nassertr(row_bytes * y_size == size, PTA_uchar());
8555 PTA_uchar image = PTA_uchar::empty_array(size);
8556 for (
int y = y_size - 1; y >= 0; --y) {
8557 unsigned char *p = image.p() + y * row_bytes;
8558 in.read((
char *)p, row_bytes);
8569read_dds_level_generic_uncompressed(
Texture *tex, CData *cdata,
const DDSHeader &header,
8570 int n, istream &in) {
8571 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8572 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8574 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
8581 pitch = ((pitch + 3) / 4) * 4;
8582 if (header.dds_flags & DDSD_PITCH) {
8583 pitch = header.pitch;
8587 int bpp = header.pf.rgb_bitcount / 8;
8588 int skip_bytes = pitch - (bpp * x_size);
8589 nassertr(skip_bytes >= 0, PTA_uchar());
8591 unsigned int r_mask = header.pf.r_mask;
8592 unsigned int g_mask = header.pf.g_mask;
8593 unsigned int b_mask = header.pf.b_mask;
8594 unsigned int a_mask = header.pf.a_mask;
8605 unsigned int r_scale = 0;
8607 r_scale = 0xff000000 / (r_mask >> r_shift);
8609 unsigned int g_scale = 0;
8611 g_scale = 0xff000000 / (g_mask >> g_shift);
8613 unsigned int b_scale = 0;
8615 b_scale = 0xff000000 / (b_mask >> b_shift);
8617 unsigned int a_scale = 0;
8619 a_scale = 0xff000000 / (a_mask >> a_shift);
8622 bool add_alpha =
has_alpha(cdata->_format);
8624 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8625 size_t row_bytes = x_size * cdata->_num_components;
8626 PTA_uchar image = PTA_uchar::empty_array(size);
8627 for (
int y = y_size - 1; y >= 0; --y) {
8628 unsigned char *p = image.p() + y * row_bytes;
8629 for (
int x = 0; x < x_size; ++x) {
8632 unsigned int pixel = 0;
8634 for (
int bi = 0; bi < bpp; ++bi) {
8635 unsigned int ch = (
unsigned char)in.get();
8636 pixel |= (ch << shift);
8641 unsigned int r = (((
pixel & r_mask) >> r_shift) * r_scale) >> 24;
8642 unsigned int g = (((
pixel & g_mask) >> g_shift) * g_scale) >> 24;
8643 unsigned int b = (((
pixel & b_mask) >> b_shift) * b_scale) >> 24;
8646 store_unscaled_byte(p, b);
8647 store_unscaled_byte(p, g);
8648 store_unscaled_byte(p, r);
8650 unsigned int a = (((
pixel & a_mask) >> a_shift) * a_scale) >> 24;
8651 store_unscaled_byte(p, a);
8654 nassertr(p <= image.p() + size, PTA_uchar());
8655 for (
int bi = 0; bi < skip_bytes; ++bi) {
8668read_dds_level_luminance_uncompressed(
Texture *tex, CData *cdata,
const DDSHeader &header,
8669 int n, istream &in) {
8670 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8671 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8673 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
8680 pitch = ((pitch + 3) / 4) * 4;
8681 if (header.dds_flags & DDSD_PITCH) {
8682 pitch = header.pitch;
8686 int bpp = header.pf.rgb_bitcount / 8;
8687 int skip_bytes = pitch - (bpp * x_size);
8688 nassertr(skip_bytes >= 0, PTA_uchar());
8690 unsigned int r_mask = header.pf.r_mask;
8691 unsigned int a_mask = header.pf.a_mask;
8700 unsigned int r_scale = 0;
8702 r_scale = 0xff000000 / (r_mask >> r_shift);
8704 unsigned int a_scale = 0;
8706 a_scale = 0xff000000 / (a_mask >> a_shift);
8709 bool add_alpha =
has_alpha(cdata->_format);
8711 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8712 size_t row_bytes = x_size * cdata->_num_components;
8713 PTA_uchar image = PTA_uchar::empty_array(size);
8714 for (
int y = y_size - 1; y >= 0; --y) {
8715 unsigned char *p = image.p() + y * row_bytes;
8716 for (
int x = 0; x < x_size; ++x) {
8719 unsigned int pixel = 0;
8721 for (
int bi = 0; bi < bpp; ++bi) {
8722 unsigned int ch = (
unsigned char)in.get();
8723 pixel |= (ch << shift);
8727 unsigned int r = (((
pixel & r_mask) >> r_shift) * r_scale) >> 24;
8730 store_unscaled_byte(p, r);
8732 unsigned int a = (((
pixel & a_mask) >> a_shift) * a_scale) >> 24;
8733 store_unscaled_byte(p, a);
8736 nassertr(p <= image.p() + size, PTA_uchar());
8737 for (
int bi = 0; bi < skip_bytes; ++bi) {
8749read_dds_level_bc1(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8750 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8751 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8753 static const int div = 4;
8754 static const int block_bytes = 8;
8758 int num_cols = max(div, x_size) / div;
8759 int num_rows = max(div, y_size) / div;
8760 int row_length = num_cols * block_bytes;
8761 int linear_size = row_length * num_rows;
8764 if (header.dds_flags & DDSD_LINEARSIZE) {
8765 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8769 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8775 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8776 unsigned char *p = image.p() + row_length * ri;
8777 in.read((
char *)p, row_length);
8779 for (
int ci = 0; ci < num_cols; ++ci) {
8782 uint32_t *cells = (uint32_t *)p;
8783 uint32_t w = cells[1];
8784 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8791 }
else if (y_size >= 2) {
8793 unsigned char *p = image.p();
8794 in.read((
char *)p, row_length);
8796 for (
int ci = 0; ci < num_cols; ++ci) {
8797 uint32_t *cells = (uint32_t *)p;
8798 uint32_t w = cells[1];
8799 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8805 }
else if (y_size >= 1) {
8807 unsigned char *p = image.p();
8808 in.read((
char *)p, row_length);
8818read_dds_level_bc2(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8819 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8820 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8822 static const int div = 4;
8823 static const int block_bytes = 16;
8828 int num_cols = max(div, x_size) / div;
8829 int num_rows = max(div, y_size) / div;
8830 int row_length = num_cols * block_bytes;
8831 int linear_size = row_length * num_rows;
8834 if (header.dds_flags & DDSD_LINEARSIZE) {
8835 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8839 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8845 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8846 unsigned char *p = image.p() + row_length * ri;
8847 in.read((
char *)p, row_length);
8849 for (
int ci = 0; ci < num_cols; ++ci) {
8852 uint32_t *cells = (uint32_t *)p;
8855 uint32_t w0 = cells[0];
8856 uint32_t w1 = cells[1];
8857 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8858 w1 = ((w1 & 0xffff) << 16) | ((w1 & 0xffff0000U) >> 16);
8864 uint32_t w = cells[3];
8865 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8872 }
else if (y_size >= 2) {
8874 unsigned char *p = image.p();
8875 in.read((
char *)p, row_length);
8877 for (
int ci = 0; ci < num_cols; ++ci) {
8878 uint32_t *cells = (uint32_t *)p;
8880 uint32_t w0 = cells[0];
8881 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8884 uint32_t w = cells[3];
8885 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8891 }
else if (y_size >= 1) {
8893 unsigned char *p = image.p();
8894 in.read((
char *)p, row_length);
8904read_dds_level_bc3(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8905 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8906 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8908 static const int div = 4;
8909 static const int block_bytes = 16;
8914 int num_cols = max(div, x_size) / div;
8915 int num_rows = max(div, y_size) / div;
8916 int row_length = num_cols * block_bytes;
8917 int linear_size = row_length * num_rows;
8920 if (header.dds_flags & DDSD_LINEARSIZE) {
8921 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8925 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8931 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8932 unsigned char *p = image.p() + row_length * ri;
8933 in.read((
char *)p, row_length);
8935 for (
int ci = 0; ci < num_cols; ++ci) {
8938 uint32_t *cells = (uint32_t *)p;
8942 unsigned char p2 = p[2];
8943 unsigned char p3 = p[3];
8944 unsigned char p4 = p[4];
8945 unsigned char p5 = p[5];
8946 unsigned char p6 = p[6];
8947 unsigned char p7 = p[7];
8949 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
8950 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
8951 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
8952 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
8953 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
8954 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
8958 uint32_t w = cells[3];
8959 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8966 }
else if (y_size >= 2) {
8968 unsigned char *p = image.p();
8969 in.read((
char *)p, row_length);
8971 for (
int ci = 0; ci < num_cols; ++ci) {
8972 uint32_t *cells = (uint32_t *)p;
8974 unsigned char p2 = p[2];
8975 unsigned char p3 = p[3];
8976 unsigned char p4 = p[4];
8978 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
8979 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
8980 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
8982 uint32_t w0 = cells[0];
8983 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8986 uint32_t w = cells[3];
8987 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8993 }
else if (y_size >= 1) {
8995 unsigned char *p = image.p();
8996 in.read((
char *)p, row_length);
9006read_dds_level_bc4(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
9007 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
9008 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
9010 static const int div = 4;
9011 static const int block_bytes = 8;
9015 int num_cols = max(div, x_size) / div;
9016 int num_rows = max(div, y_size) / div;
9017 int row_length = num_cols * block_bytes;
9018 int linear_size = row_length * num_rows;
9021 if (header.dds_flags & DDSD_LINEARSIZE) {
9022 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
9026 PTA_uchar image = PTA_uchar::empty_array(linear_size);
9032 for (
int ri = num_rows - 1; ri >= 0; --ri) {
9033 unsigned char *p = image.p() + row_length * ri;
9034 in.read((
char *)p, row_length);
9036 for (
int ci = 0; ci < num_cols; ++ci) {
9041 unsigned char p2 = p[2];
9042 unsigned char p3 = p[3];
9043 unsigned char p4 = p[4];
9044 unsigned char p5 = p[5];
9045 unsigned char p6 = p[6];
9046 unsigned char p7 = p[7];
9048 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
9049 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
9050 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
9051 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9052 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9053 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9059 }
else if (y_size >= 2) {
9061 unsigned char *p = image.p();
9062 in.read((
char *)p, row_length);
9064 for (
int ci = 0; ci < num_cols; ++ci) {
9065 unsigned char p2 = p[2];
9066 unsigned char p3 = p[3];
9067 unsigned char p4 = p[4];
9069 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9070 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9071 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9076 }
else if (y_size >= 1) {
9078 unsigned char *p = image.p();
9079 in.read((
char *)p, row_length);
9089read_dds_level_bc5(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
9090 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
9091 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
9095 int num_cols = max(4, x_size) / 2;
9096 int num_rows = max(4, y_size) / 4;
9097 int row_length = num_cols * 8;
9098 int linear_size = row_length * num_rows;
9101 if (header.dds_flags & DDSD_LINEARSIZE) {
9102 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
9106 PTA_uchar image = PTA_uchar::empty_array(linear_size);
9112 for (
int ri = num_rows - 1; ri >= 0; --ri) {
9113 unsigned char *p = image.p() + row_length * ri;
9114 in.read((
char *)p, row_length);
9116 for (
int ci = 0; ci < num_cols; ++ci) {
9121 unsigned char p2 = p[2];
9122 unsigned char p3 = p[3];
9123 unsigned char p4 = p[4];
9124 unsigned char p5 = p[5];
9125 unsigned char p6 = p[6];
9126 unsigned char p7 = p[7];
9128 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
9129 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
9130 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
9131 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9132 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9133 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9139 }
else if (y_size >= 2) {
9141 unsigned char *p = image.p();
9142 in.read((
char *)p, row_length);
9144 for (
int ci = 0; ci < num_cols; ++ci) {
9145 unsigned char p2 = p[2];
9146 unsigned char p3 = p[3];
9147 unsigned char p4 = p[4];
9149 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9150 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9151 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9156 }
else if (y_size >= 1) {
9158 unsigned char *p = image.p();
9159 in.read((
char *)p, row_length);
9173 PreparedViews::iterator pvi;
9174 pvi = _prepared_views.find(prepared_objects);
9175 if (pvi != _prepared_views.end()) {
9176 Contexts &contexts = (*pvi).second;
9177 Contexts::iterator ci;
9178 ci = contexts.find(view);
9179 if (ci != contexts.end()) {
9183 if (contexts.empty()) {
9184 _prepared_views.erase(pvi);
9194consider_downgrade(
PNMImage &pnmimage,
int num_channels,
const string &name) {
9203 <<
"Downgrading " << name <<
" from "
9205 << num_channels <<
".\n";
9230 for (
int yi = 0; yi < a.
get_y_size(); ++yi) {
9231 const xel *a_row = a_array + yi * x_size;
9232 const xel *b_row = b_array + yi * x_size;
9233 const xelval *a_alpha_row = a_alpha + yi * x_size;
9234 const xelval *b_alpha_row = b_alpha + yi * x_size;
9235 for (
int xi = 0; xi < x_size; ++xi) {
9236 delta += abs(PPM_GETR(a_row[xi]) - PPM_GETR(b_row[xi]));
9237 delta += abs(PPM_GETG(a_row[xi]) - PPM_GETG(b_row[xi]));
9238 delta += abs(PPM_GETB(a_row[xi]) - PPM_GETB(b_row[xi]));
9239 delta += abs(a_alpha_row[xi] - b_alpha_row[xi]);
9244 return (average_delta <= simple_image_threshold);
9257do_filter_2d_mipmap_pages(
const CData *cdata,
9258 Texture::RamImage &to,
const Texture::RamImage &from,
9259 int x_size,
int y_size)
const {
9260 Filter2DComponent *filter_component;
9261 Filter2DComponent *filter_alpha;
9263 if (
is_srgb(cdata->_format)) {
9266 nassertv(cdata->_component_type == T_unsigned_byte);
9268 if (has_sse2_sRGB_encode()) {
9269 filter_component = &filter_2d_unsigned_byte_srgb_sse2;
9271 filter_component = &filter_2d_unsigned_byte_srgb;
9275 filter_alpha = &filter_2d_unsigned_byte;
9278 switch (cdata->_component_type) {
9279 case T_unsigned_byte:
9280 filter_component = &filter_2d_unsigned_byte;
9283 case T_unsigned_short:
9284 filter_component = &filter_2d_unsigned_short;
9288 filter_component = &filter_2d_float;
9293 <<
"Unable to generate mipmaps for 2D texture with component type "
9294 << cdata->_component_type <<
"!";
9297 filter_alpha = filter_component;
9300 size_t pixel_size = cdata->_num_components * cdata->_component_width;
9301 size_t row_size = (size_t)x_size * pixel_size;
9303 int to_x_size = max(x_size >> 1, 1);
9304 int to_y_size = max(y_size >> 1, 1);
9306 size_t to_row_size = (size_t)to_x_size * pixel_size;
9307 to._page_size = (size_t)to_y_size * to_row_size;
9308 to._image = PTA_uchar::empty_array(to._page_size * cdata->_z_size * cdata->_num_views, get_class_type());
9311 int num_color_components = cdata->_num_components;
9313 --num_color_components;
9316 int num_pages = cdata->_z_size * cdata->_num_views;
9317 for (
int z = 0; z < num_pages; ++z) {
9319 unsigned char *p = to._image.p() + z * to._page_size;
9320 nassertv(p <= to._image.p() + to._image.size() + to._page_size);
9321 const unsigned char *q = from._image.p() + z * from._page_size;
9322 nassertv(q <= from._image.p() + from._image.size() + from._page_size);
9325 for (y = 0; y < y_size - 1; y += 2) {
9327 nassertv(p == to._image.p() + z * to._page_size + (y / 2) * to_row_size);
9328 nassertv(q == from._image.p() + z * from._page_size + y * row_size);
9331 for (x = 0; x < x_size - 1; x += 2) {
9333 for (
int c = 0; c < num_color_components; ++c) {
9335 filter_component(p, q, pixel_size, row_size);
9338 filter_alpha(p, q, pixel_size, row_size);
9348 for (
int c = 0; c < num_color_components; ++c) {
9350 filter_component(p, q, 0, row_size);
9353 filter_alpha(p, q, 0, row_size);
9367 for (x = 0; x < x_size - 1; x += 2) {
9369 for (
int c = 0; c < num_color_components; ++c) {
9371 filter_component(p, q, pixel_size, 0);
9374 filter_alpha(p, q, pixel_size, 0);
9384 for (
int c = 0; c < num_color_components; ++c) {
9386 filter_component(p, q, 0, 0);
9389 filter_alpha(p, q, pixel_size, 0);
9394 nassertv(p == to._image.p() + (z + 1) * to._page_size);
9395 nassertv(q == from._image.p() + (z + 1) * from._page_size);
9409do_filter_3d_mipmap_level(
const CData *cdata,
9410 Texture::RamImage &to,
const Texture::RamImage &from,
9411 int x_size,
int y_size,
int z_size)
const {
9412 Filter3DComponent *filter_component;
9413 Filter3DComponent *filter_alpha;
9415 if (
is_srgb(cdata->_format)) {
9418 nassertv(cdata->_component_type == T_unsigned_byte);
9420 if (has_sse2_sRGB_encode()) {
9421 filter_component = &filter_3d_unsigned_byte_srgb_sse2;
9423 filter_component = &filter_3d_unsigned_byte_srgb;
9427 filter_alpha = &filter_3d_unsigned_byte;
9430 switch (cdata->_component_type) {
9431 case T_unsigned_byte:
9432 filter_component = &filter_3d_unsigned_byte;
9435 case T_unsigned_short:
9436 filter_component = &filter_3d_unsigned_short;
9440 filter_component = &filter_3d_float;
9445 <<
"Unable to generate mipmaps for 3D texture with component type "
9446 << cdata->_component_type <<
"!";
9449 filter_alpha = filter_component;
9452 size_t pixel_size = cdata->_num_components * cdata->_component_width;
9453 size_t row_size = (size_t)x_size * pixel_size;
9454 size_t page_size = (size_t)y_size * row_size;
9455 size_t view_size = (size_t)z_size * page_size;
9457 int to_x_size = max(x_size >> 1, 1);
9458 int to_y_size = max(y_size >> 1, 1);
9459 int to_z_size = max(z_size >> 1, 1);
9461 size_t to_row_size = (size_t)to_x_size * pixel_size;
9462 size_t to_page_size = (size_t)to_y_size * to_row_size;
9463 size_t to_view_size = (size_t)to_z_size * to_page_size;
9464 to._page_size = to_page_size;
9465 to._image = PTA_uchar::empty_array(to_page_size * to_z_size * cdata->_num_views, get_class_type());
9468 int num_color_components = cdata->_num_components;
9470 --num_color_components;
9473 for (
int view = 0; view < cdata->_num_views; ++view) {
9474 unsigned char *start_to = to._image.p() + view * to_view_size;
9475 const unsigned char *start_from = from._image.p() + view * view_size;
9476 nassertv(start_to + to_view_size <= to._image.p() + to._image.size());
9477 nassertv(start_from + view_size <= from._image.p() + from._image.size());
9478 unsigned char *p = start_to;
9479 const unsigned char *q = start_from;
9482 for (z = 0; z < z_size - 1; z += 2) {
9484 nassertv(p == start_to + (z / 2) * to_page_size);
9485 nassertv(q == start_from + z * page_size);
9488 for (y = 0; y < y_size - 1; y += 2) {
9490 nassertv(p == start_to + (z / 2) * to_page_size + (y / 2) * to_row_size);
9491 nassertv(q == start_from + z * page_size + y * row_size);
9494 for (x = 0; x < x_size - 1; x += 2) {
9496 for (
int c = 0; c < num_color_components; ++c) {
9498 filter_component(p, q, pixel_size, row_size, page_size);
9501 filter_alpha(p, q, pixel_size, row_size, page_size);
9511 for (
int c = 0; c < num_color_components; ++c) {
9513 filter_component(p, q, 0, row_size, page_size);
9516 filter_alpha(p, q, 0, row_size, page_size);
9530 for (x = 0; x < x_size - 1; x += 2) {
9532 for (
int c = 0; c < num_color_components; ++c) {
9534 filter_component(p, q, pixel_size, 0, page_size);
9537 filter_alpha(p, q, pixel_size, 0, page_size);
9547 for (
int c = 0; c < num_color_components; ++c) {
9549 filter_component(p, q, 0, 0, page_size);
9552 filter_alpha(p, q, 0, 0, page_size);
9566 for (y = 0; y < y_size - 1; y += 2) {
9568 nassertv(p == start_to + (y / 2) * to_row_size);
9569 nassertv(q == start_from + y * row_size);
9572 for (x = 0; x < x_size - 1; x += 2) {
9574 for (
int c = 0; c < num_color_components; ++c) {
9576 filter_component(p, q, pixel_size, row_size, 0);
9579 filter_alpha(p, q, pixel_size, row_size, 0);
9589 for (
int c = 0; c < num_color_components; ++c) {
9591 filter_component(p, q, 0, row_size, 0);
9594 filter_alpha(p, q, 0, row_size, 0);
9608 for (x = 0; x < x_size - 1; x += 2) {
9610 for (
int c = 0; c < num_color_components; ++c) {
9612 filter_component(p, q, pixel_size, 0, 0);
9615 filter_alpha(p, q, pixel_size, 0, 0);
9625 for (
int c = 0; c < num_color_components; ++c) {
9627 filter_component(p, q, 0, 0, 0);
9630 filter_alpha(p, q, 0, 0, 0);
9636 nassertv(p == start_to + to_z_size * to_page_size);
9637 nassertv(q == start_from + z_size * page_size);
9646filter_2d_unsigned_byte(
unsigned char *&p,
const unsigned char *&q,
9647 size_t pixel_size,
size_t row_size) {
9648 unsigned int result = ((
unsigned int)q[0] +
9649 (
unsigned int)q[pixel_size] +
9650 (
unsigned int)q[row_size] +
9651 (
unsigned int)q[pixel_size + row_size]) >> 2;
9652 *p = (
unsigned char)result;
9662filter_2d_unsigned_byte_srgb(
unsigned char *&p,
const unsigned char *&q,
9663 size_t pixel_size,
size_t row_size) {
9679filter_2d_unsigned_byte_srgb_sse2(
unsigned char *&p,
const unsigned char *&q,
9680 size_t pixel_size,
size_t row_size) {
9686 *p = encode_sRGB_uchar_sse2(result * 0.25f);
9696filter_2d_unsigned_short(
unsigned char *&p,
const unsigned char *&q,
9697 size_t pixel_size,
size_t row_size) {
9698 unsigned int result = ((
unsigned int)*(
unsigned short *)&q[0] +
9699 (
unsigned int)*(
unsigned short *)&q[pixel_size] +
9700 (
unsigned int)*(
unsigned short *)&q[row_size] +
9701 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size]) >> 2;
9702 store_unscaled_short(p, result);
9711filter_2d_float(
unsigned char *&p,
const unsigned char *&q,
9712 size_t pixel_size,
size_t row_size) {
9713 *(
float *)p = (*(
float *)&q[0] +
9714 *(
float *)&q[pixel_size] +
9715 *(
float *)&q[row_size] +
9716 *(
float *)&q[pixel_size + row_size]) / 4.0f;
9727filter_3d_unsigned_byte(
unsigned char *&p,
const unsigned char *&q,
9728 size_t pixel_size,
size_t row_size,
size_t page_size) {
9729 unsigned int result = ((
unsigned int)q[0] +
9730 (
unsigned int)q[pixel_size] +
9731 (
unsigned int)q[row_size] +
9732 (
unsigned int)q[pixel_size + row_size] +
9733 (
unsigned int)q[page_size] +
9734 (
unsigned int)q[pixel_size + page_size] +
9735 (
unsigned int)q[row_size + page_size] +
9736 (
unsigned int)q[pixel_size + row_size + page_size]) >> 3;
9737 *p = (
unsigned char)result;
9748filter_3d_unsigned_byte_srgb(
unsigned char *&p,
const unsigned char *&q,
9749 size_t pixel_size,
size_t row_size,
size_t page_size) {
9770filter_3d_unsigned_byte_srgb_sse2(
unsigned char *&p,
const unsigned char *&q,
9771 size_t pixel_size,
size_t row_size,
size_t page_size) {
9781 *p = encode_sRGB_uchar_sse2(result * 0.125f);
9792filter_3d_unsigned_short(
unsigned char *&p,
const unsigned char *&q,
9793 size_t pixel_size,
size_t row_size,
9795 unsigned int result = ((
unsigned int)*(
unsigned short *)&q[0] +
9796 (
unsigned int)*(
unsigned short *)&q[pixel_size] +
9797 (
unsigned int)*(
unsigned short *)&q[row_size] +
9798 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size] +
9799 (
unsigned int)*(
unsigned short *)&q[page_size] +
9800 (
unsigned int)*(
unsigned short *)&q[pixel_size + page_size] +
9801 (
unsigned int)*(
unsigned short *)&q[row_size + page_size] +
9802 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size + page_size]) >> 3;
9803 store_unscaled_short(p, result);
9813filter_3d_float(
unsigned char *&p,
const unsigned char *&q,
9814 size_t pixel_size,
size_t row_size,
size_t page_size) {
9815 *(
float *)p = (*(
float *)&q[0] +
9816 *(
float *)&q[pixel_size] +
9817 *(
float *)&q[row_size] +
9818 *(
float *)&q[pixel_size + row_size] +
9819 *(
float *)&q[page_size] +
9820 *(
float *)&q[pixel_size + page_size] +
9821 *(
float *)&q[row_size + page_size] +
9822 *(
float *)&q[pixel_size + row_size + page_size]) / 8.0f;
9831do_squish(CData *cdata, Texture::CompressionMode compression,
int squish_flags) {
9833 if (!do_has_all_ram_mipmap_images(cdata)) {
9836 do_generate_ram_mipmap_images(cdata,
false);
9839 RamImages compressed_ram_images;
9840 compressed_ram_images.reserve(cdata->_ram_images.size());
9841 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
9842 RamImage compressed_image;
9843 int x_size = do_get_expected_mipmap_x_size(cdata, n);
9844 int y_size = do_get_expected_mipmap_y_size(cdata, n);
9845 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
9846 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
9847 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
9849 compressed_image._page_size = page_size;
9850 compressed_image._image = PTA_uchar::empty_array(page_size * num_pages);
9851 for (
int z = 0; z < num_pages; ++z) {
9852 unsigned char *dest_page = compressed_image._image.p() + z * page_size;
9853 unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * cdata->_ram_images[n]._page_size;
9854 unsigned const char *source_page_end = source_page + cdata->_ram_images[n]._page_size;
9856 unsigned char *d = dest_page;
9857 for (
int y = 0; y < y_size; y += 4) {
9858 for (
int x = 0; x < x_size; x += 4) {
9859 unsigned char tb[16 * 4];
9861 unsigned char *t = tb;
9862 for (
int i = 0; i < 16; ++i) {
9865 unsigned const char *s = source_page + (yi * x_size + xi) * cdata->_num_components;
9866 if (s < source_page_end) {
9867 switch (cdata->_num_components) {
9900 squish::CompressMasked(tb, mask, d, squish_flags);
9906 compressed_ram_images.push_back(compressed_image);
9908 cdata->_ram_images.swap(compressed_ram_images);
9909 cdata->_ram_image_compression = compression;
9922do_unsquish(CData *cdata,
int squish_flags) {
9924 RamImages uncompressed_ram_images;
9925 uncompressed_ram_images.reserve(cdata->_ram_images.size());
9926 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
9927 RamImage uncompressed_image;
9928 int x_size = do_get_expected_mipmap_x_size(cdata, n);
9929 int y_size = do_get_expected_mipmap_y_size(cdata, n);
9930 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
9931 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
9932 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
9934 uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
9935 uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * num_pages);
9936 for (
int z = 0; z < num_pages; ++z) {
9937 unsigned char *dest_page = uncompressed_image._image.p() + z * uncompressed_image._page_size;
9938 unsigned char *dest_page_end = dest_page + uncompressed_image._page_size;
9939 unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * page_size;
9941 unsigned const char *s = source_page;
9942 for (
int y = 0; y < y_size; y += 4) {
9943 for (
int x = 0; x < x_size; x += 4) {
9944 unsigned char tb[16 * 4];
9945 squish::Decompress(tb, s, squish_flags);
9948 unsigned char *t = tb;
9949 for (
int i = 0; i < 16; ++i) {
9952 unsigned char *d = dest_page + (yi * x_size + xi) * cdata->_num_components;
9953 if (d < dest_page_end) {
9954 switch (cdata->_num_components) {
9984 uncompressed_ram_images.push_back(uncompressed_image);
9986 cdata->_ram_images.swap(uncompressed_ram_images);
9987 cdata->_ram_image_compression = CM_off;
10012 bool has_rawdata =
false;
10013 do_write_datagram_header(cdata, manager, me, has_rawdata);
10014 do_write_datagram_body(cdata, manager, me);
10018 do_write_datagram_rawdata(cdata, manager, me);
10056do_write_datagram_header(CData *cdata,
BamWriter *manager,
Datagram &me,
bool &has_rawdata) {
10065 has_rawdata = (file_texture_mode == BamWriter::BTM_rawdata ||
10066 (cdata->_filename.empty() && do_has_bam_rawdata(cdata)));
10067 if (has_rawdata && !do_has_bam_rawdata(cdata)) {
10068 do_get_bam_rawdata(cdata);
10069 if (!do_has_bam_rawdata(cdata)) {
10071 has_rawdata =
false;
10077 Filename filename = cdata->_filename;
10078 Filename alpha_filename = cdata->_alpha_filename;
10082 switch (file_texture_mode) {
10083 case BamWriter::BTM_unchanged:
10084 case BamWriter::BTM_rawdata:
10087 case BamWriter::BTM_fullpath:
10088 filename = cdata->_fullpath;
10089 alpha_filename = cdata->_alpha_fullpath;
10092 case BamWriter::BTM_relative:
10093 filename = cdata->_fullpath;
10094 alpha_filename = cdata->_alpha_fullpath;
10099 if (gobj_cat.is_debug()) {
10101 <<
"Texture file " << cdata->_fullpath
10102 <<
" found as " << filename <<
"\n";
10107 if (gobj_cat.is_debug()) {
10109 <<
"Alpha image " << cdata->_alpha_fullpath
10110 <<
" found as " << alpha_filename <<
"\n";
10114 case BamWriter::BTM_basename:
10116 alpha_filename = cdata->_alpha_fullpath.
get_basename();
10121 <<
"Unsupported bam-texture-mode: " << (int)file_texture_mode <<
"\n";
10124 if (filename.empty()) {
10125 if (do_has_bam_rawdata(cdata) || cdata->_has_clear_color) {
10127 has_rawdata =
true;
10134 me.
add_uint8(cdata->_primary_file_num_channels);
10135 me.
add_uint8(cdata->_alpha_file_channel);
10139 cdata->_texture_type == TT_cube_map) {
10148 me.
add_bool(cdata->_has_read_mipmaps);
10159 cdata->_default_sampler.write_datagram(me);
10177 if (cdata->_texture_type == TT_buffer_texture) {
10182 me.
add_uint8(cdata->_auto_texture_scale);
10194 me.
add_int32(cdata->_simple_image_date_generated);
10195 me.
add_uint32(cdata->_simple_ram_image._image.size());
10196 me.
append_data(cdata->_simple_ram_image._image, cdata->_simple_ram_image._image.size());
10200 me.
add_bool(cdata->_has_clear_color);
10201 if (cdata->_has_clear_color) {
10202 cdata->_clear_color.write_datagram(me);
10227 me.
add_uint8(cdata->_ram_image_compression);
10229 if (cdata->_ram_images.empty() && cdata->_has_clear_color &&
10233 int image_size = do_get_expected_ram_image_size(cdata);
10235 me.
add_uint32(do_get_expected_ram_page_size(cdata));
10239 unsigned char pixel[16];
10240 const int pixel_size = do_get_clear_data(cdata,
pixel);
10241 nassertv(pixel_size > 0);
10243 for (
int i = 0; i < image_size; i += pixel_size) {
10247 me.
add_uint8(cdata->_ram_images.size());
10248 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
10249 me.
add_uint32(cdata->_ram_images[n]._page_size);
10250 me.
add_uint32(cdata->_ram_images[n]._image.size());
10251 me.
append_data(cdata->_ram_images[n]._image, cdata->_ram_images[n]._image.size());
10262 return dummy->make_this_from_bam(params);
10289 int primary_file_num_channels = scan.
get_uint8();
10290 int alpha_file_channel = scan.
get_uint8();
10291 bool has_rawdata = scan.
get_bool();
10292 TextureType texture_type = (TextureType)scan.
get_uint8();
10296 if (texture_type == TT_2d_texture_array) {
10297 texture_type = TT_cube_map;
10300 bool has_read_mipmaps =
false;
10302 has_read_mipmaps = scan.
get_bool();
10312 me->set_name(name);
10313 CDWriter cdata_me(me->_cycler,
true);
10314 cdata_me->_filename = filename;
10315 cdata_me->_alpha_filename = alpha_filename;
10316 cdata_me->_primary_file_num_channels = primary_file_num_channels;
10317 cdata_me->_alpha_file_channel = alpha_file_channel;
10318 cdata_me->_texture_type = texture_type;
10319 cdata_me->_has_read_mipmaps = has_read_mipmaps;
10322 me->do_fillin_body(cdata_me, scan, manager);
10323 me->do_fillin_rawdata(cdata_me, scan, manager);
10335 AutoTextureScale auto_texture_scale = ATS_unspecified;
10338 CDWriter cdata_dummy(dummy->_cycler,
true);
10339 dummy->do_fillin_body(cdata_dummy, scan, manager);
10340 auto_texture_scale = cdata_dummy->_auto_texture_scale;
10344 if (filename.empty()) {
10348 <<
"Cannot create texture '" << name <<
"' with no filename.\n";
10358 if (!alpha_filename.empty()) {
10365 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
10369 switch (texture_type) {
10370 case TT_buffer_texture:
10371 case TT_1d_texture:
10372 case TT_2d_texture:
10373 case TT_1d_texture_array:
10378 if ((options.get_texture_flags() & LoaderOptions::TF_preload) == 0 &&
10379 (
has_simple_ram_image || (options.get_texture_flags() & LoaderOptions::TF_preload_simple) == 0)) {
10380 if (alpha_filename.empty()) {
10385 primary_file_num_channels,
10386 alpha_file_channel,
10398 Filename alpha_fullpath = alpha_filename;
10399 const DSearchPath &model_path = get_model_path();
10401 (alpha_fullpath.empty() || vfs->
resolve_filename(alpha_fullpath, model_path))) {
10403 me->set_name(name);
10406 CDWriter cdata_me(me->_cycler,
true);
10407 cdata_me->_filename = filename;
10408 cdata_me->_alpha_filename = alpha_filename;
10409 cdata_me->_fullpath = fullpath;
10410 cdata_me->_alpha_fullpath = alpha_fullpath;
10411 cdata_me->_primary_file_num_channels = primary_file_num_channels;
10412 cdata_me->_alpha_file_channel = alpha_file_channel;
10413 cdata_me->_texture_type = texture_type;
10414 cdata_me->_loaded_from_image =
true;
10415 cdata_me->_has_read_mipmaps = has_read_mipmaps;
10429 if (alpha_filename.empty()) {
10431 has_read_mipmaps, options);
10434 primary_file_num_channels,
10435 alpha_file_channel,
10436 has_read_mipmaps, options);
10440 case TT_3d_texture:
10444 case TT_2d_texture_array:
10445 case TT_cube_map_array:
10455 if (me !=
nullptr) {
10456 me->set_name(name);
10457 CDWriter cdata_me(me->_cycler,
true);
10458 me->do_fillin_from(cdata_me, dummy);
10475 cdata->_default_sampler.read_datagram(scan, manager);
10478 cdata->_compression = (CompressionMode)scan.
get_uint8();
10481 cdata->_quality_level = (QualityLevel)scan.
get_uint8();
10484 cdata->_format = (Format)scan.
get_uint8();
10485 cdata->_num_components = scan.
get_uint8();
10487 if (cdata->_texture_type == TT_buffer_texture) {
10488 cdata->_usage_hint = (GeomEnums::UsageHint)scan.
get_uint8();
10491 cdata->inc_properties_modified();
10493 cdata->_auto_texture_scale = ATS_unspecified;
10495 cdata->_auto_texture_scale = (AutoTextureScale)scan.
get_uint8();
10500 cdata->_orig_file_x_size = scan.
get_uint32();
10501 cdata->_orig_file_y_size = scan.
get_uint32();
10509 cdata->_simple_image_date_generated = scan.
get_int32();
10516 <<
"simple RAM image extends past end of datagram, is texture corrupt?\n";
10520 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
10523 cdata->_simple_ram_image._image = image;
10524 cdata->_simple_ram_image._page_size = u_size;
10525 cdata->inc_simple_image_modified();
10529 cdata->_has_clear_color = scan.
get_bool();
10530 if (cdata->_has_clear_color) {
10531 cdata->_clear_color.read_datagram(scan);
10551 do_set_pad_size(cdata, 0, 0, 0);
10554 cdata->_num_views = 1;
10558 cdata->_component_type = (ComponentType)scan.
get_uint8();
10559 cdata->_component_width = scan.
get_uint8();
10560 cdata->_ram_image_compression = CM_off;
10562 cdata->_ram_image_compression = (CompressionMode)scan.
get_uint8();
10565 int num_ram_images = 1;
10570 cdata->_ram_images.clear();
10571 cdata->_ram_images.reserve(num_ram_images);
10572 for (
int n = 0; n < num_ram_images; ++n) {
10573 cdata->_ram_images.push_back(RamImage());
10576 cdata->_ram_images[n]._page_size = scan.
get_uint32();
10585 <<
"RAM image " << n <<
" extends past end of datagram, is texture corrupt?\n";
10589 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
10592 cdata->_ram_images[n]._image = image;
10594 cdata->_loaded_from_image =
true;
10595 cdata->inc_image_modified();
10604do_fillin_from(CData *cdata,
const Texture *dummy) {
10611 CDReader cdata_dummy(dummy->_cycler);
10613 do_set_wrap_u(cdata, cdata_dummy->_default_sampler.get_wrap_u());
10614 do_set_wrap_v(cdata, cdata_dummy->_default_sampler.get_wrap_v());
10615 do_set_wrap_w(cdata, cdata_dummy->_default_sampler.get_wrap_w());
10616 do_set_border_color(cdata, cdata_dummy->_default_sampler.get_border_color());
10618 if (cdata_dummy->_default_sampler.get_minfilter() != SamplerState::FT_default) {
10619 do_set_minfilter(cdata, cdata_dummy->_default_sampler.get_minfilter());
10621 if (cdata_dummy->_default_sampler.get_magfilter() != SamplerState::FT_default) {
10622 do_set_magfilter(cdata, cdata_dummy->_default_sampler.get_magfilter());
10624 if (cdata_dummy->_default_sampler.get_anisotropic_degree() != 0) {
10625 do_set_anisotropic_degree(cdata, cdata_dummy->_default_sampler.get_anisotropic_degree());
10627 if (cdata_dummy->_compression != CM_default) {
10628 do_set_compression(cdata, cdata_dummy->_compression);
10630 if (cdata_dummy->_quality_level != QL_default) {
10631 do_set_quality_level(cdata, cdata_dummy->_quality_level);
10634 Format format = cdata_dummy->_format;
10635 int num_components = cdata_dummy->_num_components;
10637 if (num_components == cdata->_num_components) {
10641 do_set_format(cdata, format);
10644 if (!cdata_dummy->_simple_ram_image._image.empty()) {
10647 if (cdata->_simple_ram_image._image.empty() ||
10648 cdata_dummy->_simple_image_date_generated > cdata->_simple_image_date_generated) {
10649 do_set_simple_ram_image(cdata,
10650 cdata_dummy->_simple_ram_image._image,
10651 cdata_dummy->_simple_x_size,
10652 cdata_dummy->_simple_y_size);
10653 cdata->_simple_image_date_generated = cdata_dummy->_simple_image_date_generated;
10663 _primary_file_num_channels = 0;
10664 _alpha_file_channel = 0;
10665 _keep_ram_image =
true;
10666 _compression = CM_default;
10667 _auto_texture_scale = ATS_unspecified;
10668 _ram_image_compression = CM_off;
10669 _render_to_texture =
false;
10670 _match_framebuffer_format =
false;
10671 _post_load_store_cache =
false;
10672 _quality_level = QL_default;
10674 _texture_type = TT_2d_texture;
10686 _usage_hint = GeomEnums::UH_unspecified;
10692 _orig_file_x_size = 0;
10693 _orig_file_y_size = 0;
10695 _loaded_from_image =
false;
10696 _loaded_from_txo =
false;
10697 _has_read_pages =
false;
10698 _has_read_mipmaps =
false;
10699 _num_mipmap_levels_read = 0;
10701 _simple_x_size = 0;
10702 _simple_y_size = 0;
10703 _simple_ram_image._page_size = 0;
10705 _has_clear_color =
false;
10712CData(
const Texture::CData ©) {
10713 _num_mipmap_levels_read = 0;
10717 _properties_modified = copy._properties_modified;
10718 _image_modified = copy._image_modified;
10719 _simple_image_modified = copy._simple_image_modified;
10727 return new CData(*
this);
10733void Texture::CData::
10734do_assign(
const Texture::CData *copy) {
10735 _filename = copy->_filename;
10736 _alpha_filename = copy->_alpha_filename;
10737 if (!copy->_fullpath.empty()) {
10740 _fullpath = copy->_fullpath;
10741 _alpha_fullpath = copy->_alpha_fullpath;
10743 _primary_file_num_channels = copy->_primary_file_num_channels;
10744 _alpha_file_channel = copy->_alpha_file_channel;
10745 _x_size = copy->_x_size;
10746 _y_size = copy->_y_size;
10747 _z_size = copy->_z_size;
10748 _num_views = copy->_num_views;
10749 _pad_x_size = copy->_pad_x_size;
10750 _pad_y_size = copy->_pad_y_size;
10751 _pad_z_size = copy->_pad_z_size;
10752 _orig_file_x_size = copy->_orig_file_x_size;
10753 _orig_file_y_size = copy->_orig_file_y_size;
10754 _num_components = copy->_num_components;
10755 _component_width = copy->_component_width;
10756 _texture_type = copy->_texture_type;
10757 _format = copy->_format;
10758 _component_type = copy->_component_type;
10759 _loaded_from_image = copy->_loaded_from_image;
10760 _loaded_from_txo = copy->_loaded_from_txo;
10761 _has_read_pages = copy->_has_read_pages;
10762 _has_read_mipmaps = copy->_has_read_mipmaps;
10763 _num_mipmap_levels_read = copy->_num_mipmap_levels_read;
10764 _default_sampler = copy->_default_sampler;
10765 _keep_ram_image = copy->_keep_ram_image;
10766 _compression = copy->_compression;
10767 _match_framebuffer_format = copy->_match_framebuffer_format;
10768 _quality_level = copy->_quality_level;
10769 _auto_texture_scale = copy->_auto_texture_scale;
10770 _ram_image_compression = copy->_ram_image_compression;
10771 _ram_images = copy->_ram_images;
10772 _simple_x_size = copy->_simple_x_size;
10773 _simple_y_size = copy->_simple_y_size;
10774 _simple_ram_image = copy->_simple_ram_image;
10781void Texture::CData::
10789int Texture::CData::
10798void Texture::CData::
10806operator << (ostream &out, Texture::TextureType tt) {
10814operator << (ostream &out, Texture::ComponentType ct) {
10822operator << (ostream &out, Texture::Format f) {
10830operator << (ostream &out, Texture::CompressionMode cm) {
10838operator << (ostream &out, Texture::QualityLevel tql) {
10846operator >> (istream &in, Texture::QualityLevel &tql) {
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record.
get_data
Returns a pointer to the data stored in the record, or NULL if there is no data.
set_data
Stores a new data object on the record.
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
get_cache_textures
Returns whether texture files (e.g.
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...
get_cache_compressed_textures
Returns whether compressed texture files will be stored in the cache, as compressed txo files.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
bool resolve()
This may be called at any time during processing of the Bam file to resolve all the known pointers so...
bool init()
Initializes the BamReader prior to reading any objects from its source.
get_filename
If a BAM is a file, then the BamReader should contain the name of the file.
TypedWritable * read_object()
Reads a single object from the Bam file.
get_loader_options
Returns the LoaderOptions passed to the loader when the model was requested, if any.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
get_file_texture_mode
Returns the BamTextureMode preference indicated by the Bam file currently being written.
get_filename
If a BAM is a file, then the BamWriter should contain the name of the file.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
get_active
Returns the active flag associated with this object.
get_resident
Returns the resident flag associated with this object.
get_data_size_bytes
Returns the number of bytes previously reported for the data object.
void notify_all()
Informs all of the other threads who are currently blocked on wait() that the relevant condition has ...
void wait()
Waits on the condition.
This class specializes ConfigVariable as an enumerated type.
int get_word(size_t n) const
Returns the variable's nth value.
std::string get_unique_value(size_t n) const
Returns the nth unique value of the variable.
size_t get_num_unique_values() const
Returns the number of unique values in the variable.
PointerToArray< Element > cast_non_const() const
Casts away the constness of the CPTA(Element), and returns an equivalent PTA(Element).
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A single page of data maintained by a PipelineCycler.
This class stores a list of directories that can be searched, in order, to locate a particular file.
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
vector_uchar extract_bytes(size_t size)
Extracts the indicated number of bytes in the datagram and returns them as a string.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
bool get_bool()
Extracts a boolean value.
std::string get_string()
Extracts a variable-length string.
int32_t get_int32()
Extracts a signed 32-bit integer.
size_t get_remaining_size() const
Return the bytes left in the datagram.
This class can be used to write a binary file that consists of an arbitrary header followed by a numb...
bool open(const FileReference *file)
Opens the indicated filename for writing.
bool write_header(const std::string &header)
Writes a sequence of bytes to the beginning of the datagram file.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
void add_int16(int16_t value)
Adds a signed 16-bit integer to the datagram.
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
void add_bool(bool value)
Adds a boolean value to the datagram.
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
The name of a file, such as a texture file or an Egg file.
std::string get_basename() const
Returns the basename part of the filename.
Filename get_filename_index(int index) const
If the pattern flag is set for this Filename and the filename string actually includes a sequence of ...
bool has_hash() const
Returns true if the filename is indicated to be a filename pattern (that is, set_pattern(true) was ca...
void set_basename_wo_extension(const std::string &s)
Replaces the basename part of the filename, without the file extension.
int find_on_searchpath(const DSearchPath &searchpath)
Performs the reverse of the resolve_filename() operation: assuming that the current filename is fully...
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash,...
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname),...
static Filename pattern_filename(const std::string &filename)
Constructs a filename that represents a sequence of numbered files.
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
static GraphicsStateGuardianBase * get_default_gsg()
Returns a pointer to the "default" GSG.
Encodes a string name in a hash table, mapping it to a pointer.
get_name
Returns the complete name represented by the InternalName and all of its parents.
Specifies parameters that may be passed to the loader.
set_auto_texture_scale
Set this flag to ATS_none, ATS_up, ATS_down, or ATS_pad to control how a texture is scaled from disk ...
get_auto_texture_scale
See set_auto_texture_scale().
get_texture_num_views
See set_texture_num_views().
void unlock()
Alias for release() to match C++11 semantics.
void lock()
Alias for acquire() to match C++11 semantics.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
A base class for all things which can have a name.
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
PNMFileType * get_type_from_extension(const std::string &filename) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its exte...
This is the base class of a family of classes that represent particular image file types that PNMImag...
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color,...
void set_read_size(int x_size, int y_size)
Specifies the size to we'd like to scale the image upon reading it.
xelval get_channel_val(int x, int y, int channel) const
Returns the nth component color at the indicated pixel.
void set_blue(int x, int y, float b)
Sets the blue component color only at the indicated pixel.
void alpha_fill(float alpha=0.0)
Sets the entire alpha channel to the given level.
xelval get_green_val(int x, int y) const
Returns the green component color at the indicated pixel.
void set_green(int x, int y, float g)
Sets the green component color only at the indicated pixel.
float get_alpha(int x, int y) const
Returns the alpha component color at the indicated pixel.
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
void quick_filter_from(const PNMImage ©, int xborder=0, int yborder=0)
Resizes from the given image, with a fixed radius of 0.5.
void fill(float red, float green, float blue)
Sets the entire image (except the alpha channel) to the given color.
void set_num_channels(int num_channels)
Changes the number of channels associated with the image.
xelval get_alpha_val(int x, int y) const
Returns the alpha component color at the indicated pixel.
void set_red(int x, int y, float r)
Sets the red component color only at the indicated pixel.
void copy_header_from(const PNMImageHeader &header)
Copies just the header information into this image.
void take_from(PNMImage &orig)
Move the contents of the other image into this one, and empty the other image.
bool is_valid() const
Returns true if the image has been read in or correctly initialized with a height and width.
xelval get_blue_val(int x, int y) const
Returns the blue component color at the indicated pixel.
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
xel * get_array()
Directly access the underlying PNMImage array.
xelval get_red_val(int x, int y) const
Returns the red component color at the indicated pixel.
int get_read_y_size() const
Returns the requested y_size of the image if set_read_size() has been called, or the image y_size oth...
xelval get_gray_val(int x, int y) const
Returns the gray component color at the indicated pixel.
void set_alpha(int x, int y, float a)
Sets the alpha component color only at the indicated pixel.
ColorSpace get_color_space() const
Returns the color space in which the image is encoded.
void add_alpha()
Adds an alpha channel to the image, if it does not already have one.
xelval * get_alpha_array()
Directly access the underlying PNMImage array of alpha values.
bool write(const Filename &filename, PNMFileType *type=nullptr) const
Writes the image to the indicated filename.
int get_read_x_size() const
Returns the requested x_size of the image if set_read_size() has been called, or the image x_size oth...
This is an abstract base class that defines the interface for reading image files of various types.
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal,...
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
bool read(const Filename &fullpath)
Reads the PFM data from the indicated file, returning true on success, false on failure.
bool write(const Filename &fullpath)
Writes the PFM data to the indicated file, returning true on success, false on failure.
bool store(PNMImage &pnmimage) const
Copies the data to the indicated PNMImage, converting to RGB values.
void set_channel(int x, int y, int c, PN_float32 value)
Replaces the cth channel of the point value at the indicated point.
bool load(const PNMImage &pnmimage)
Fills the PfmFile with the data from the indicated PNMImage, converted to floating-point values.
PN_float32 get_channel(int x, int y, int c) const
Returns the cth channel of the point value at the indicated point.
void clear()
Eliminates all data in the file.
A table of objects that are saved within the graphics context for reference by handle later.
bool is_texture_queued(const Texture *tex) const
Returns true if the texture has been queued on this GSG, false otherwise.
TextureContext * prepare_texture_now(Texture *tex, int view, GraphicsStateGuardianBase *gsg)
Immediately creates a new TextureContext for the indicated texture and returns it.
bool dequeue_texture(Texture *tex)
Removes a texture from the queued list of textures to be prepared.
void release_texture(TextureContext *tc)
Indicates that a texture context, created by a previous call to prepare_texture(),...
void ref() const
Explicitly increments the reference count.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
get_ref_count
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
Represents a set of settings that indicate how a texture is sampled.
get_minfilter
Returns the filter mode of the texture for minification.
get_wrap_v
Returns the wrap mode of the texture in the V direction.
get_anisotropic_degree
Returns the degree of anisotropic filtering that should be applied to the texture.
get_magfilter
Returns the filter mode of the texture for magnification.
get_wrap_w
Returns the wrap mode of the texture in the W direction.
get_wrap_u
Returns the wrap mode of the texture in the U direction.
get_border_color
Returns the solid color of the texture's border.
A class to read sequential binary data directly from an istream.
This is a special class object that holds all the information returned by a particular GSG to indicat...
bool was_image_modified() const
Returns true if the texture image has been modified since the last time mark_loaded() was called.
An instance of this object is returned by Texture::peek().
static Texture * load_texture(const Filename &filename, int primary_file_num_channels=0, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads the given filename up into a texture, if it has not already been loaded, and returns the new te...
static Texture * get_texture(const Filename &filename, int primary_file_num_channels=0, bool read_mipmaps=false)
Returns the texture that has already been previously loaded, or NULL otherwise.
static Texture * load_2d_texture_array(const Filename &filename_pattern, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads a 2-D texture array that is specified with a series of n pages, all numbered in sequence,...
static void add_texture(Texture *texture)
Adds the indicated already-loaded texture to the pool.
static Texture * load_cube_map(const Filename &filename_pattern, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads a cube map texture that is specified with a series of 6 pages, numbered 0 through 5.
static Texture * load_3d_texture(const Filename &filename_pattern, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads a 3-D texture that is specified with a series of n pages, all numbered in sequence,...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
CPTA_uchar get_ram_image_as(const std::string &requested_format)
Returns the uncompressed system-RAM image data associated with the texture.
static TextureType string_texture_type(const std::string &str)
Returns the TextureType corresponding to the indicated string word.
virtual void ensure_loader_type(const Filename &filename)
May be called prior to calling read_txo() or any bam-related Texture- creating callback,...
static PT(Texture) make_from_txo(std bool write_txo(std::ostream &out, const std::string &filename="") const
Writes the texture to a Panda texture object.
TextureContext * prepare_now(int view, PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the texture on the particular GSG, if it does not already exist.
static std::string format_component_type(ComponentType ct)
Returns the indicated ComponentType converted to a string word.
Texture(const std::string &name=std::string())
Constructs an empty texture.
bool get_resident(PreparedGraphicsObjects *prepared_objects) const
Returns true if this Texture is reported to be resident within graphics memory for the indicated GSG.
Texture * load_related(const InternalName *suffix) const
Loads a texture whose filename is derived by concatenating a suffix to the filename of this texture.
static CompressionMode string_compression_mode(const std::string &str)
Returns the CompressionMode value associated with the given string representation.
PTA_uchar new_simple_ram_image(int x_size, int y_size)
Creates an empty array for the simple ram image of the indicated size, and returns a modifiable point...
static bool is_specific(CompressionMode compression)
Returns true if the indicated compression mode is one of the specific compression types,...
bool has_ram_image() const
Returns true if the Texture has its image contents available in main RAM, false if it exists only in ...
static std::string format_quality_level(QualityLevel tql)
Returns the indicated QualityLevel converted to a string word.
size_t estimate_texture_memory() const
Estimates the amount of texture memory that will be consumed by loading this texture.
bool read(const Filename &fullpath, const LoaderOptions &options=LoaderOptions())
Reads the named filename into the texture.
void consider_rescale(PNMImage &pnmimage)
Asks the PNMImage to change its scale when it reads the image, according to the whims of the Config....
get_texture_type
Returns the overall interpretation of the texture.
bool write(const Filename &fullpath)
Writes the texture to the named filename.
static bool has_binary_alpha(Format format)
Returns true if the indicated format includes a binary alpha only, false otherwise.
void * get_ram_mipmap_pointer(int n) const
Similiar to get_ram_mipmap_image(), however, in this case the void pointer for the given ram image is...
static std::string format_compression_mode(CompressionMode cm)
Returns the indicated CompressionMode converted to a string word.
get_aux_data
Returns a record previously recorded via set_aux_data().
static bool is_srgb(Format format)
Returns true if the indicated format is in the sRGB color space, false otherwise.
void set_orig_file_size(int x, int y, int z=1)
Specifies the size of the texture as it exists in its original disk file, before any Panda scaling.
bool get_active(PreparedGraphicsObjects *prepared_objects) const
Returns true if this Texture was rendered in the most recent frame within the indicated GSG.
get_keep_ram_image
Returns the flag that indicates whether this Texture is eligible to have its main RAM copy of the tex...
bool read_dds(std::istream &in, const std::string &filename="", bool header_only=false)
Reads the texture from a DDS file object.
void generate_normalization_cube_map(int size)
Generates a special cube map image in the texture that can be used to apply bump mapping effects: for...
bool has_compression() const
Returns true if the texture indicates it wants to be compressed, either with CM_on or higher,...
static QualityLevel string_quality_level(const std::string &str)
Returns the QualityLevel value associated with the given string representation.
void generate_alpha_scale_map()
Generates a special 256x1 1-d texture that can be used to apply an arbitrary alpha scale to objects b...
bool read_txo(std::istream &in, const std::string &filename="")
Reads the texture from a Panda texture object.
static ComponentType string_component_type(const std::string &str)
Returns the ComponentType corresponding to the indicated string word.
static void register_with_read_factory()
Factory method to generate a Texture object.
static bool adjust_size(int &x_size, int &y_size, const std::string &name, bool for_padding, AutoTextureScale auto_texture_scale=ATS_unspecified)
Computes the proper size of the texture, based on the original size, the filename,...
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
static int up_to_power_2(int value)
Returns the smallest power of 2 greater than or equal to value.
static AutoTextureScale get_textures_power_2()
This flag returns ATS_none, ATS_up, or ATS_down and controls the scaling of textures in general.
get_auto_texture_scale
Returns the power-of-2 texture-scaling mode that will be applied to this particular texture when it i...
void set_ram_mipmap_pointer_from_int(long long pointer, int n, int page_size)
Accepts a raw pointer cast as an int, which is then passed to set_ram_mipmap_pointer(); see the docum...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
static int down_to_power_2(int value)
Returns the largest power of 2 less than or equal to value.
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
virtual bool has_cull_callback() const
Should be overridden by derived classes to return true if cull_callback() has been defined.
bool uses_mipmaps() const
Returns true if the minfilter settings on this texture indicate the use of mipmapping,...
static std::string format_texture_type(TextureType tt)
Returns the indicated TextureType converted to a string word.
has_simple_ram_image
Returns true if the Texture has a "simple" image available in main RAM.
static bool is_integer(Format format)
Returns true if the indicated format is an integer format, false otherwise.
PTA_uchar modify_simple_ram_image()
Returns a modifiable pointer to the internal "simple" texture image.
void clear_ram_mipmap_image(int n)
Discards the current system-RAM image for the nth mipmap level.
bool was_image_modified(PreparedGraphicsObjects *prepared_objects) const
Returns true if the texture needs to be re-loaded onto the indicated GSG, either because its image da...
bool read_ktx(std::istream &in, const std::string &filename="", bool header_only=false)
Reads the texture from a KTX file object.
size_t get_data_size_bytes(PreparedGraphicsObjects *prepared_objects) const
Returns the number of bytes which the texture is reported to consume within graphics memory,...
get_expected_ram_page_size
Returns the number of bytes that should be used per each Z page of the 3-d texture.
virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const
If has_cull_callback() returns true, this function will be called during the cull traversal to perfor...
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the texture has already been prepared or enqueued for preparation on the indicated GS...
void set_ram_image_as(CPTA_uchar image, const std::string &provided_format)
Replaces the current system-RAM image with the new data, converting it first if necessary from the in...
void set_ram_mipmap_pointer(int n, void *image, size_t page_size=0)
Sets an explicit void pointer as the texture's mipmap image for the indicated level.
set_aux_data
Records an arbitrary object in the Texture, associated with a specified key.
void texture_uploaded()
This method is called by the GraphicsEngine at the beginning of the frame *after* a texture has been ...
void set_size_padded(int x=1, int y=1, int z=1)
Changes the size of the texture, padding if necessary, and setting the pad region as well.
static bool has_alpha(Format format)
Returns true if the indicated format includes alpha, false otherwise.
get_num_loadable_ram_mipmap_images
Returns the number of contiguous mipmap levels that exist in RAM, up until the first gap in the seque...
void generate_simple_ram_image()
Computes the "simple" ram image by loading the main RAM image, if it is not already available,...
static Format string_format(const std::string &str)
Returns the Format corresponding to the indicated string word.
clear_aux_data
Removes a record previously recorded via set_aux_data().
int release_all()
Frees the context allocated on all objects for which the texture has been declared.
CPTA_uchar get_ram_mipmap_image(int n) const
Returns the system-RAM image data associated with the nth mipmap level, if present.
static std::string format_format(Format f)
Returns the indicated Format converted to a string word.
is_cacheable
Returns true if there is enough information in this Texture object to write it to the bam cache succe...
static bool is_unsigned(ComponentType ctype)
Returns true if the indicated component type is unsigned, false otherwise.
A thread; that is, a lightweight process.
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
get_current_thread
Returns a pointer to the currently-executing Thread object.
TypeHandle is the identifier used to differentiate C++ class types.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
Base class for objects that can be written to and read from Bam files.
A hierarchy of directories and files that appears to be one continuous file system,...
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
Filename get_cwd() const
Returns the current directory name.
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
std::ostream * open_write_file(const Filename &filename, bool auto_wrap, bool truncate)
Convenience function; returns a newly allocated ostream if the file exists and can be written,...
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
This is our own Panda specialization on the default STL map.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
EXPCL_PANDA_PNMIMAGE unsigned char encode_sRGB_uchar(unsigned char val)
Encodes the linearized unsigned char value to an sRGB-encoded unsigned char value.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_lowest_on_bit(unsigned short x)
Returns the index of the lowest 1 bit in the word.
int get_next_higher_bit(unsigned short x)
Returns the smallest power of 2 greater than x.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string upcase(const string &s)
Returns the input string with all lowercase letters converted to uppercase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(Texture) Texture
Constructs a new Texture object from the txo file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.