61 (
"texture-quality-level", Texture::QL_normal,
62 PRC_DESC(
"This specifies a global quality level for all textures. You "
63 "may specify either fastest, normal, or best. This actually "
64 "affects the meaning of Texture::set_quality_level(QL_default), "
65 "so it may be overridden on a per-texture basis. This generally "
66 "only has an effect when using the tinydisplay software renderer; "
67 "it has little or no effect on normal, hardware-accelerated "
68 "renderers. See Texture::set_quality_level()."));
70 PStatCollector Texture::_texture_read_pcollector(
"*:Texture:Read");
73 AutoTextureScale Texture::_textures_power_2 = ATS_unspecified;
78 #define DDS_MAGIC 0x20534444
82 #define DDSD_CAPS 0x00000001
83 #define DDSD_HEIGHT 0x00000002
84 #define DDSD_WIDTH 0x00000004
85 #define DDSD_PITCH 0x00000008
86 #define DDSD_PIXELFORMAT 0x00001000
87 #define DDSD_MIPMAPCOUNT 0x00020000
88 #define DDSD_LINEARSIZE 0x00080000
89 #define DDSD_DEPTH 0x00800000
92 #define DDPF_ALPHAPIXELS 0x00000001
93 #define DDPF_FOURCC 0x00000004
94 #define DDPF_INDEXED 0x00000020
95 #define DDPF_RGB 0x00000040
98 #define DDSCAPS_COMPLEX 0x00000008
99 #define DDSCAPS_TEXTURE 0x00001000
100 #define DDSCAPS_MIPMAP 0x00400000
103 #define DDSCAPS2_CUBEMAP 0x00000200
104 #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
105 #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
106 #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
107 #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
108 #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
109 #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
110 #define DDSCAPS2_VOLUME 0x00200000
112 struct DDSPixelFormat {
113 unsigned int pf_size;
114 unsigned int pf_flags;
115 unsigned int four_cc;
116 unsigned int rgb_bitcount;
130 unsigned int dds_magic;
131 unsigned int dds_size;
132 unsigned int dds_flags;
137 unsigned int num_levels;
146 KTX_UNSIGNED_BYTE = 0x1401,
148 KTX_UNSIGNED_SHORT = 0x1403,
150 KTX_UNSIGNED_INT = 0x1405,
152 KTX_HALF_FLOAT = 0x140B,
153 KTX_UNSIGNED_BYTE_3_3_2 = 0x8032,
154 KTX_UNSIGNED_SHORT_4_4_4_4 = 0x8033,
155 KTX_UNSIGNED_SHORT_5_5_5_1 = 0x8034,
156 KTX_UNSIGNED_INT_8_8_8_8 = 0x8035,
157 KTX_UNSIGNED_INT_10_10_10_2 = 0x8036,
158 KTX_UNSIGNED_BYTE_2_3_3_REV = 0x8362,
159 KTX_UNSIGNED_SHORT_5_6_5 = 0x8363,
160 KTX_UNSIGNED_SHORT_5_6_5_REV = 0x8364,
161 KTX_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
162 KTX_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
163 KTX_UNSIGNED_INT_8_8_8_8_REV = 0x8367,
164 KTX_UNSIGNED_INT_2_10_10_10_REV = 0x8368,
165 KTX_UNSIGNED_INT_24_8 = 0x84FA,
166 KTX_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
167 KTX_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
168 KTX_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD,
173 KTX_ALPHA12 = 0x803D,
174 KTX_ALPHA16 = 0x803E,
175 KTX_ALPHA16_SNORM = 0x9018,
178 KTX_ALPHA8_SNORM = 0x9014,
179 KTX_ALPHA_SNORM = 0x9010,
181 KTX_BGR_INTEGER = 0x8D9A,
183 KTX_BGRA_INTEGER = 0x8D9B,
185 KTX_BLUE_INTEGER = 0x8D96,
186 KTX_COLOR_INDEX = 0x1900,
187 KTX_DEPTH24_STENCIL8 = 0x88F0,
188 KTX_DEPTH32F_STENCIL8 = 0x8CAD,
189 KTX_DEPTH_COMPONENT = 0x1902,
190 KTX_DEPTH_COMPONENT16 = 0x81A5,
191 KTX_DEPTH_COMPONENT24 = 0x81A6,
192 KTX_DEPTH_COMPONENT32 = 0x81A7,
193 KTX_DEPTH_COMPONENT32F = 0x8CAC,
194 KTX_DEPTH_STENCIL = 0x84F9,
196 KTX_GREEN_INTEGER = 0x8D95,
197 KTX_INTENSITY = 0x8049,
198 KTX_INTENSITY12 = 0x804C,
199 KTX_INTENSITY16 = 0x804D,
200 KTX_INTENSITY16_SNORM = 0x901B,
201 KTX_INTENSITY4 = 0x804A,
202 KTX_INTENSITY8 = 0x804B,
203 KTX_INTENSITY8_SNORM = 0x9017,
204 KTX_INTENSITY_SNORM = 0x9013,
205 KTX_LUMINANCE = 0x1909,
206 KTX_LUMINANCE12 = 0x8041,
207 KTX_LUMINANCE12_ALPHA12 = 0x8047,
208 KTX_LUMINANCE12_ALPHA4 = 0x8046,
209 KTX_LUMINANCE16 = 0x8042,
210 KTX_LUMINANCE16_ALPHA16 = 0x8048,
211 KTX_LUMINANCE16_ALPHA16_SNORM = 0x901A,
212 KTX_LUMINANCE16_SNORM = 0x9019,
213 KTX_LUMINANCE4 = 0x803F,
214 KTX_LUMINANCE4_ALPHA4 = 0x8043,
215 KTX_LUMINANCE6_ALPHA2 = 0x8044,
216 KTX_LUMINANCE8 = 0x8040,
217 KTX_LUMINANCE8_ALPHA8 = 0x8045,
218 KTX_LUMINANCE8_ALPHA8_SNORM = 0x9016,
219 KTX_LUMINANCE8_SNORM = 0x9015,
220 KTX_LUMINANCE_ALPHA = 0x190A,
221 KTX_LUMINANCE_ALPHA_SNORM = 0x9012,
222 KTX_LUMINANCE_SNORM = 0x9011,
223 KTX_R11F_G11F_B10F = 0x8C3A,
225 KTX_R16_SNORM = 0x8F98,
232 KTX_R3_G3_B2 = 0x2A10,
234 KTX_R8_SNORM = 0x8F94,
238 KTX_RED_INTEGER = 0x8D94,
239 KTX_RED_SNORM = 0x8F90,
242 KTX_RG16_SNORM = 0x8F99,
250 KTX_RG8_SNORM = 0x8F95,
253 KTX_RG_INTEGER = 0x8228,
254 KTX_RG_SNORM = 0x8F91,
257 KTX_RGB10_A2 = 0x8059,
260 KTX_RGB16_SNORM = 0x8F9A,
263 KTX_RGB16UI = 0x8D77,
267 KTX_RGB32UI = 0x8D71,
270 KTX_RGB5_A1 = 0x8057,
272 KTX_RGB8_SNORM = 0x8F96,
275 KTX_RGB9_E5 = 0x8C3D,
276 KTX_RGB_INTEGER = 0x8D98,
277 KTX_RGB_SNORM = 0x8F92,
281 KTX_RGBA16_SNORM = 0x8F9B,
282 KTX_RGBA16F = 0x881A,
283 KTX_RGBA16I = 0x8D88,
284 KTX_RGBA16UI = 0x8D76,
286 KTX_RGBA32F = 0x8814,
287 KTX_RGBA32I = 0x8D82,
288 KTX_RGBA32UI = 0x8D70,
291 KTX_RGBA8_SNORM = 0x8F97,
293 KTX_RGBA8UI = 0x8D7C,
294 KTX_RGBA_INTEGER = 0x8D99,
295 KTX_RGBA_SNORM = 0x8F93,
296 KTX_SLUMINANCE = 0x8C46,
297 KTX_SLUMINANCE8 = 0x8C47,
298 KTX_SLUMINANCE8_ALPHA8 = 0x8C45,
299 KTX_SLUMINANCE_ALPHA = 0x8C44,
302 KTX_SRGB8_ALPHA8 = 0x8C43,
303 KTX_SRGB_ALPHA = 0x8C42,
304 KTX_STENCIL_INDEX = 0x1901,
305 KTX_STENCIL_INDEX1 = 0x8D46,
306 KTX_STENCIL_INDEX16 = 0x8D49,
307 KTX_STENCIL_INDEX4 = 0x8D47,
308 KTX_STENCIL_INDEX8 = 0x8D48,
311 enum KTXCompressedFormat {
312 KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2 = 0x8C72,
313 KTX_COMPRESSED_LUMINANCE_LATC1 = 0x8C70,
314 KTX_COMPRESSED_R11_EAC = 0x9270,
315 KTX_COMPRESSED_RED = 0x8225,
316 KTX_COMPRESSED_RED_RGTC1 = 0x8DBB,
317 KTX_COMPRESSED_RG = 0x8226,
318 KTX_COMPRESSED_RG11_EAC = 0x9272,
319 KTX_COMPRESSED_RG_RGTC2 = 0x8DBD,
320 KTX_COMPRESSED_RGB = 0x84ED,
321 KTX_COMPRESSED_RGB8_ETC2 = 0x9274,
322 KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276,
323 KTX_COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E,
324 KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F,
325 KTX_COMPRESSED_RGB_FXT1_3DFX = 0x86B0,
326 KTX_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01,
327 KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00,
328 KTX_COMPRESSED_RGB_S3TC_DXT1 = 0x83F0,
329 KTX_COMPRESSED_RGBA = 0x84EE,
330 KTX_COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
331 KTX_COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C,
332 KTX_COMPRESSED_RGBA_FXT1_3DFX = 0x86B1,
333 KTX_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03,
334 KTX_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG = 0x9137,
335 KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02,
336 KTX_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG = 0x9138,
337 KTX_COMPRESSED_RGBA_S3TC_DXT1 = 0x83F1,
338 KTX_COMPRESSED_RGBA_S3TC_DXT3 = 0x83F2,
339 KTX_COMPRESSED_RGBA_S3TC_DXT5 = 0x83F3,
340 KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2 = 0x8C73,
341 KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1 = 0x8C71,
342 KTX_COMPRESSED_SIGNED_R11_EAC = 0x9271,
343 KTX_COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC,
344 KTX_COMPRESSED_SIGNED_RG11_EAC = 0x9273,
345 KTX_COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE,
346 KTX_COMPRESSED_SLUMINANCE = 0x8C4A,
347 KTX_COMPRESSED_SLUMINANCE_ALPHA = 0x8C4B,
348 KTX_COMPRESSED_SRGB = 0x8C48,
349 KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279,
350 KTX_COMPRESSED_SRGB8_ETC2 = 0x9275,
351 KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,
352 KTX_COMPRESSED_SRGB_ALPHA = 0x8C49,
353 KTX_COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D,
354 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1 = 0x8A56,
355 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2 = 0x93F0,
356 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1 = 0x8A57,
357 KTX_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2 = 0x93F1,
358 KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1 = 0x8C4D,
359 KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3 = 0x8C4E,
360 KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5 = 0x8C4F,
361 KTX_COMPRESSED_SRGB_PVRTC_2BPPV1 = 0x8A54,
362 KTX_COMPRESSED_SRGB_PVRTC_4BPPV1 = 0x8A55,
363 KTX_COMPRESSED_SRGB_S3TC_DXT1 = 0x8C4C,
364 KTX_ETC1_RGB8 = 0x8D64,
365 KTX_ETC1_SRGB8 = 0x88EE,
382 do_set_format(cdata, F_rgb);
383 do_set_component_type(cdata, T_unsigned_byte);
392 _cycler(copy._cycler),
393 _lock(copy.get_name()),
403 operator = (
const Texture ©) {
404 Namable::operator = (copy);
405 _cycler = copy._cycler;
414 nassertv(!_reloading);
426 do_setup_texture(cdata, TT_cube_map, size, size, 6, T_unsigned_byte, F_rgb);
427 PTA_uchar image = do_make_ram_image(cdata);
428 cdata->_keep_ram_image =
true;
430 cdata->inc_image_modified();
431 cdata->inc_properties_modified();
433 PN_stdfloat half_size = (PN_stdfloat)size * 0.5f;
434 PN_stdfloat center = half_size - 0.5f;
437 (127.5f, 0.0f, 0.0f, 0.0f,
438 0.0f, 127.5f, 0.0f, 0.0f,
439 0.0f, 0.0f, 127.5f, 0.0f,
440 127.5f, 127.5f, 127.5f, 1.0f);
442 unsigned char *p = image;
446 for (yi = 0; yi < size; ++yi) {
447 for (xi = 0; xi < size; ++xi) {
448 LVector3 vec(half_size, center - yi, center - xi);
450 vec = scale.xform_point(vec);
452 *p++ = (
unsigned char)vec[2];
453 *p++ = (
unsigned char)vec[1];
454 *p++ = (
unsigned char)vec[0];
459 for (yi = 0; yi < size; ++yi) {
460 for (xi = 0; xi < size; ++xi) {
461 LVector3 vec(-half_size, center - yi, xi - center);
463 vec = scale.xform_point(vec);
464 *p++ = (
unsigned char)vec[2];
465 *p++ = (
unsigned char)vec[1];
466 *p++ = (
unsigned char)vec[0];
471 for (yi = 0; yi < size; ++yi) {
472 for (xi = 0; xi < size; ++xi) {
473 LVector3 vec(xi - center, half_size, yi - center);
475 vec = scale.xform_point(vec);
476 *p++ = (
unsigned char)vec[2];
477 *p++ = (
unsigned char)vec[1];
478 *p++ = (
unsigned char)vec[0];
483 for (yi = 0; yi < size; ++yi) {
484 for (xi = 0; xi < size; ++xi) {
485 LVector3 vec(xi - center, -half_size, center - yi);
487 vec = scale.xform_point(vec);
488 *p++ = (
unsigned char)vec[2];
489 *p++ = (
unsigned char)vec[1];
490 *p++ = (
unsigned char)vec[0];
495 for (yi = 0; yi < size; ++yi) {
496 for (xi = 0; xi < size; ++xi) {
497 LVector3 vec(xi - center, center - yi, half_size);
499 vec = scale.xform_point(vec);
500 *p++ = (
unsigned char)vec[2];
501 *p++ = (
unsigned char)vec[1];
502 *p++ = (
unsigned char)vec[0];
507 for (yi = 0; yi < size; ++yi) {
508 for (xi = 0; xi < size; ++xi) {
509 LVector3 vec(center - xi, center - yi, -half_size);
511 vec = scale.xform_point(vec);
512 *p++ = (
unsigned char)vec[2];
513 *p++ = (
unsigned char)vec[1];
514 *p++ = (
unsigned char)vec[0];
528 do_setup_texture(cdata, TT_1d_texture, 256, 1, 1, T_unsigned_byte, F_alpha);
529 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
530 cdata->_default_sampler.set_minfilter(SamplerState::FT_nearest);
531 cdata->_default_sampler.set_magfilter(SamplerState::FT_nearest);
533 cdata->_compression = CM_off;
535 cdata->inc_image_modified();
536 cdata->inc_properties_modified();
538 PTA_uchar image = do_make_ram_image(cdata);
539 cdata->_keep_ram_image =
true;
541 unsigned char *p = image;
542 for (
int xi = 0; xi < 256; ++xi) {
554 cdata->inc_properties_modified();
555 cdata->inc_image_modified();
556 return do_read(cdata, fullpath,
Filename(), 0, 0, 0, 0,
false,
false,
569 int primary_file_num_channels,
int alpha_file_channel,
573 cdata->inc_properties_modified();
574 cdata->inc_image_modified();
575 return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
576 alpha_file_channel, 0, 0,
false,
false,
589 bool read_pages,
bool read_mipmaps,
592 cdata->inc_properties_modified();
593 cdata->inc_image_modified();
594 return do_read(cdata, fullpath,
Filename(), 0, 0, z, n, read_pages, read_mipmaps,
652 int primary_file_num_channels,
int alpha_file_channel,
653 int z,
int n,
bool read_pages,
bool read_mipmaps,
657 cdata->inc_properties_modified();
658 cdata->inc_image_modified();
659 return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
660 alpha_file_channel, z, n, read_pages, read_mipmaps,
677 size_t pixels = cdata->_x_size * cdata->_y_size * cdata->_z_size;
680 switch (cdata->_format) {
681 case Texture::F_rgb332:
685 case Texture::F_alpha:
687 case Texture::F_green:
688 case Texture::F_blue:
689 case Texture::F_luminance:
690 case Texture::F_sluminance:
695 case Texture::F_luminance_alpha:
696 case Texture::F_luminance_alphamask:
697 case Texture::F_sluminance_alpha:
698 case Texture::F_rgba4:
699 case Texture::F_rgb5:
700 case Texture::F_rgba5:
705 case Texture::F_rgba:
706 case Texture::F_rgbm:
708 case Texture::F_srgb:
714 case Texture::F_color_index:
715 case Texture::F_rgb8:
716 case Texture::F_rgba8:
717 case Texture::F_srgb_alpha:
718 case Texture::F_rgb8i:
719 case Texture::F_rgba8i:
723 case Texture::F_depth_stencil:
727 case Texture::F_depth_component:
728 case Texture::F_depth_component16:
732 case Texture::F_depth_component24:
733 case Texture::F_depth_component32:
737 case Texture::F_rgba12:
738 case Texture::F_rgb12:
742 case Texture::F_rgba32:
743 case Texture::F_rgba32i:
748 case Texture::F_r16i:
749 case Texture::F_rg8i:
752 case Texture::F_rg16:
753 case Texture::F_rg16i:
756 case Texture::F_rgb16:
757 case Texture::F_rgb16i:
758 case Texture::F_rgba16:
759 case Texture::F_rgba16i:
763 case Texture::F_r32i:
768 case Texture::F_rg32:
769 case Texture::F_rg32i:
773 case Texture::F_rgb32:
774 case Texture::F_rgb32i:
778 case Texture::F_r11_g11_b10:
779 case Texture::F_rgb9_e5:
780 case Texture::F_rgb10_a2:
787 gobj_cat.warning() <<
"Unhandled format in estimate_texture_memory(): "
788 << cdata->_format <<
"\n";
791 size_t bytes = pixels * bpp;
793 bytes = (bytes * 4) / 3;
809 _aux_data[key] = aux_data;
818 _aux_data.erase(key);
828 AuxData::const_iterator di;
829 di = _aux_data.find(key);
830 if (di != _aux_data.end()) {
845 read_txo(istream &in,
const string &filename) {
847 cdata->inc_properties_modified();
848 cdata->inc_image_modified();
849 return do_read_txo(cdata, in, filename);
860 make_from_txo(istream &in,
const string &filename) {
863 if (!din.
open(in, filename)) {
865 <<
"Could not read texture object: " << filename <<
"\n";
872 << filename <<
" is not a texture object file.\n";
876 if (head != _bam_header) {
878 << filename <<
" is not a texture object file.\n";
883 if (!reader.
init()) {
889 if (
object !=
nullptr &&
898 if (
object ==
nullptr) {
900 <<
"Texture object " << filename <<
" is empty.\n";
903 }
else if (!object->
is_of_type(Texture::get_class_type())) {
905 <<
"Texture object " << filename <<
" contains a "
906 <<
object->get_type() <<
", not a Texture.\n";
913 <<
"Unable to fully resolve texture object file.\n";
928 write_txo(ostream &out,
const string &filename)
const {
929 CDReader cdata(_cycler);
930 return do_write_txo(cdata, out, filename);
943 read_dds(istream &in,
const string &filename,
bool header_only) {
945 cdata->inc_properties_modified();
946 cdata->inc_image_modified();
947 return do_read_dds(cdata, in, filename, header_only);
960 read_ktx(istream &in,
const string &filename,
bool header_only) {
962 cdata->inc_properties_modified();
963 cdata->inc_image_modified();
964 return do_read_ktx(cdata, in, filename, header_only);
977 RelatedTextures::const_iterator ti;
978 ti = _related_textures.find(suffix);
979 if (ti != _related_textures.end()) {
982 if (cdata->_fullpath.empty()) {
986 main.set_basename_wo_extension(main.get_basename_wo_extension() +
989 if (!cdata->_alpha_fullpath.empty()) {
990 Filename alph = cdata->_alpha_fullpath;
998 cdata->_primary_file_num_channels,
999 cdata->_alpha_file_channel,
false);
1014 ((
Texture *)
this)->_related_textures.insert(RelatedTextures::value_type(suffix, res));
1028 string format =
upcase(supplied_format);
1031 size_t imgsize = (size_t)cdata->_x_size * (
size_t)cdata->_y_size *
1032 (size_t)cdata->_z_size * (
size_t)cdata->_num_views;
1033 nassertv(image.size() == (
size_t)(cdata->_component_width * format.size() * imgsize));
1036 if ((cdata->_num_components == 1 && format.size() == 1) ||
1037 (cdata->_num_components == 2 && format.size() == 2 && format.at(1) ==
'A' && format.at(0) !=
'A') ||
1038 (cdata->_num_components == 3 && format ==
"BGR") ||
1039 (cdata->_num_components == 4 && format ==
"BGRA")) {
1041 do_set_ram_image(cdata, image);
1046 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * cdata->_num_components * cdata->_component_width, get_class_type());
1049 if (cdata->_component_width == 1) {
1050 if (format ==
"RGBA" && cdata->_num_components == 4) {
1052 for (
int p = 0; p < imgsize; p += 4) {
1053 newdata[p + 2] = image[p ];
1054 newdata[p + 1] = image[p + 1];
1055 newdata[p ] = image[p + 2];
1056 newdata[p + 3] = image[p + 3];
1058 do_set_ram_image(cdata, newdata);
1061 if (format ==
"RGB" && cdata->_num_components == 3) {
1063 for (
int p = 0; p < imgsize; p += 3) {
1064 newdata[p + 2] = image[p ];
1065 newdata[p + 1] = image[p + 1];
1066 newdata[p ] = image[p + 2];
1068 do_set_ram_image(cdata, newdata);
1071 if (format ==
"A" && cdata->_num_components != 3) {
1073 int component = cdata->_num_components - 1;
1074 for (
int p = 0; p < imgsize; ++p) {
1075 newdata[component] = image[p];
1077 do_set_ram_image(cdata, newdata);
1080 for (
int p = 0; p < imgsize; ++p) {
1081 for (uchar s = 0; s < format.size(); ++s) {
1082 signed char component = -1;
1083 if (format.at(s) ==
'B' || (cdata->_num_components <= 2 && format.at(s) !=
'A')) {
1085 }
else if (format.at(s) ==
'G') {
1087 }
else if (format.at(s) ==
'R') {
1089 }
else if (format.at(s) ==
'A') {
1090 if (cdata->_num_components != 3) {
1091 component = cdata->_num_components - 1;
1095 }
else if (format.at(s) ==
'0') {
1097 }
else if (format.at(s) ==
'1') {
1100 gobj_cat.error() <<
"Unexpected component character '"
1101 << format.at(s) <<
"', expected one of RGBA!\n";
1104 if (component >= 0) {
1105 newdata[p * cdata->_num_components + component] = image[p * format.size() + s];
1109 do_set_ram_image(cdata, newdata);
1112 for (
int p = 0; p < imgsize; ++p) {
1113 for (uchar s = 0; s < format.size(); ++s) {
1114 signed char component = -1;
1115 if (format.at(s) ==
'B' || (cdata->_num_components <= 2 && format.at(s) !=
'A')) {
1117 }
else if (format.at(s) ==
'G') {
1119 }
else if (format.at(s) ==
'R') {
1121 }
else if (format.at(s) ==
'A') {
1122 if (cdata->_num_components != 3) {
1123 component = cdata->_num_components - 1;
1127 }
else if (format.at(s) ==
'0') {
1129 }
else if (format.at(s) ==
'1') {
1132 gobj_cat.error() <<
"Unexpected component character '"
1133 << format.at(s) <<
"', expected one of RGBA!\n";
1136 if (component >= 0) {
1137 memcpy((
void*)(newdata + (p * cdata->_num_components + component) * cdata->_component_width),
1138 (
void*)(image + (p * format.size() + s) * cdata->_component_width),
1139 cdata->_component_width);
1143 do_set_ram_image(cdata, newdata);
1154 CDReader cdata(_cycler);
1155 return cdata->_keep_ram_image;
1165 CDReader cdata(_cycler);
1166 return do_has_bam_rawdata(cdata);
1183 CDReader cdata(_cycler);
1184 if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty()) {
1194 int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
1200 if (n >= (
int)cdata->_ram_images.size() || cdata->_ram_images[n]._image.empty()) {
1216 if (n < (
int)cdata->_ram_images.size() && !cdata->_ram_images[n]._image.empty()) {
1217 return cdata->_ram_images[n]._image;
1230 if (n < (
int)cdata->_ram_images.size()) {
1231 return cdata->_ram_images[n]._pointer_image;
1249 nassertv(cdata->_ram_image_compression != CM_off || do_get_expected_ram_mipmap_image_size(cdata, n));
1251 while (n >= (
int)cdata->_ram_images.size()) {
1252 cdata->_ram_images.push_back(RamImage());
1255 cdata->_ram_images[n]._page_size = page_size;
1257 cdata->_ram_images[n]._pointer_image = image;
1258 cdata->inc_image_modified();
1279 if (n >= (
int)cdata->_ram_images.size()) {
1282 cdata->_ram_images[n]._page_size = 0;
1283 cdata->_ram_images[n]._image.clear();
1284 cdata->_ram_images[n]._pointer_image =
nullptr;
1294 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
1295 return cdata->_simple_ram_image._image;
1305 nassertr(cdata->_texture_type == TT_2d_texture, PTA_uchar());
1306 size_t expected_page_size = (size_t)(x_size * y_size * 4);
1308 cdata->_simple_x_size = x_size;
1309 cdata->_simple_y_size = y_size;
1310 cdata->_simple_ram_image._image = PTA_uchar::empty_array(expected_page_size);
1311 cdata->_simple_ram_image._page_size = expected_page_size;
1312 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
1313 cdata->inc_simple_image_modified();
1315 return cdata->_simple_ram_image._image;
1327 if (cdata->_texture_type != TT_2d_texture ||
1328 cdata->_ram_image_compression != CM_off) {
1333 if (!do_store_one(cdata, pnmimage, 0, 0)) {
1338 int x_size = simple_image_size.
get_word(0);
1339 int y_size = simple_image_size.
get_word(1);
1360 did_anything =
false;
1364 int new_x_size = (x_size >> 1);
1365 PNMImage smaller(new_x_size, y_size, 4);
1367 PNMImage bigger(x_size, y_size, 4);
1370 if (compare_images(scaled, bigger)) {
1372 x_size = new_x_size;
1373 did_anything =
true;
1379 int new_y_size = (y_size >> 1);
1380 PNMImage smaller(x_size, new_y_size, 4);
1382 PNMImage bigger(x_size, y_size, 4);
1385 if (compare_images(scaled, bigger)) {
1387 y_size = new_y_size;
1388 did_anything =
true;
1391 }
while (did_anything);
1393 size_t expected_page_size = (size_t)(x_size * y_size * 4);
1394 PTA_uchar image = PTA_uchar::empty_array(expected_page_size, get_class_type());
1395 convert_from_pnmimage(image, expected_page_size, x_size, 0, 0, 0, scaled, 4, 1);
1397 do_set_simple_ram_image(cdata, image, x_size, y_size);
1398 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
1415 CDWriter cdata(_cycler, unlocked_ensure_ram_image(
true));
1418 if (peeker->is_valid()) {
1436 return prepared_objects->enqueue_texture_future(
this);
1446 PreparedViews::const_iterator pvi;
1447 pvi = _prepared_views.find(prepared_objects);
1448 if (pvi != _prepared_views.end()) {
1464 PreparedViews::const_iterator pvi;
1465 pvi = _prepared_views.find(prepared_objects);
1466 if (pvi != _prepared_views.end()) {
1467 const Contexts &contexts = (*pvi).second;
1468 for (
int view = 0; view < cdata->_num_views; ++view) {
1469 Contexts::const_iterator ci;
1470 ci = contexts.find(view);
1471 if (ci == contexts.end()) {
1496 PreparedViews::const_iterator pvi;
1497 size_t total_size = 0;
1498 pvi = _prepared_views.find(prepared_objects);
1499 if (pvi != _prepared_views.end()) {
1500 const Contexts &contexts = (*pvi).second;
1501 for (
int view = 0; view < cdata->_num_views; ++view) {
1502 Contexts::const_iterator ci;
1503 ci = contexts.find(view);
1504 if (ci != contexts.end()) {
1523 PreparedViews::const_iterator pvi;
1524 pvi = _prepared_views.find(prepared_objects);
1525 if (pvi != _prepared_views.end()) {
1526 const Contexts &contexts = (*pvi).second;
1527 for (
int view = 0; view < cdata->_num_views; ++view) {
1528 Contexts::const_iterator ci;
1529 ci = contexts.find(view);
1530 if (ci != contexts.end()) {
1550 PreparedViews::const_iterator pvi;
1551 pvi = _prepared_views.find(prepared_objects);
1552 if (pvi != _prepared_views.end()) {
1553 const Contexts &contexts = (*pvi).second;
1554 for (
int view = 0; view < cdata->_num_views; ++view) {
1555 Contexts::const_iterator ci;
1556 ci = contexts.find(view);
1557 if (ci != contexts.end()) {
1575 PreparedViews::iterator pvi;
1576 pvi = _prepared_views.find(prepared_objects);
1577 if (pvi != _prepared_views.end()) {
1579 temp.swap((*pvi).second);
1580 Contexts::iterator ci;
1581 for (ci = temp.begin(); ci != temp.end(); ++ci) {
1583 if (tc !=
nullptr) {
1587 _prepared_views.erase(pvi);
1607 temp.swap(_prepared_views);
1608 int num_freed = (int)temp.size();
1610 PreparedViews::iterator pvi;
1611 for (pvi = temp.begin(); pvi != temp.end(); ++pvi) {
1614 temp.swap((*pvi).second);
1615 Contexts::iterator ci;
1616 for (ci = temp.begin(); ci != temp.end(); ++ci) {
1618 if (tc !=
nullptr) {
1632 write(ostream &out,
int indent_level)
const {
1634 indent(out, indent_level)
1635 << cdata->_texture_type <<
" " << get_name();
1636 if (!cdata->_filename.empty()) {
1637 out <<
" (from " << cdata->_filename <<
")";
1641 indent(out, indent_level + 2);
1643 switch (cdata->_texture_type) {
1645 out <<
"1-d, " << cdata->_x_size;
1649 out <<
"2-d, " << cdata->_x_size <<
" x " << cdata->_y_size;
1653 out <<
"3-d, " << cdata->_x_size <<
" x " << cdata->_y_size <<
" x " << cdata->_z_size;
1656 case TT_2d_texture_array:
1657 out <<
"2-d array, " << cdata->_x_size <<
" x " << cdata->_y_size <<
" x " << cdata->_z_size;
1661 out <<
"cube map, " << cdata->_x_size <<
" x " << cdata->_y_size;
1664 case TT_cube_map_array:
1665 out <<
"cube map array, " << cdata->_x_size <<
" x " << cdata->_y_size <<
" x " << cdata->_z_size;
1668 case TT_buffer_texture:
1669 out <<
"buffer, " << cdata->_x_size;
1672 case TT_1d_texture_array:
1673 out <<
"1-d array, " << cdata->_x_size <<
" x " << cdata->_y_size;
1677 if (cdata->_num_views > 1) {
1678 out <<
" (x " << cdata->_num_views <<
" views)";
1681 out <<
" pixels, each " << cdata->_num_components;
1683 switch (cdata->_component_type) {
1684 case T_unsigned_byte:
1689 case T_unsigned_short:
1700 case T_unsigned_int_24_8:
1702 case T_unsigned_int:
1711 switch (cdata->_format) {
1713 out <<
"color_index";
1715 case F_depth_stencil:
1716 out <<
"depth_stencil";
1718 case F_depth_component:
1719 out <<
"depth_component";
1721 case F_depth_component16:
1722 out <<
"depth_component16";
1724 case F_depth_component24:
1725 out <<
"depth_component24";
1727 case F_depth_component32:
1728 out <<
"depth_component32";
1787 case F_luminance_alpha:
1788 out <<
"luminance_alpha";
1790 case F_luminance_alphamask:
1791 out <<
"luminance_alphamask";
1808 out <<
"srgb_alpha";
1811 out <<
"sluminance";
1813 case F_sluminance_alpha:
1814 out <<
"sluminance_alpha";
1844 out <<
"r11_g11_b10";
1881 if (cdata->_compression != CM_default) {
1882 out <<
", compression " << cdata->_compression;
1886 indent(out, indent_level + 2);
1888 cdata->_default_sampler.output(out);
1890 if (do_has_ram_image(cdata)) {
1891 indent(out, indent_level + 2)
1892 << do_get_ram_image_size(cdata) <<
" bytes in ram, compression "
1893 << cdata->_ram_image_compression <<
"\n";
1895 if (cdata->_ram_images.size() > 1) {
1897 size_t total_size = 0;
1898 for (
size_t n = 1; n < cdata->_ram_images.size(); ++n) {
1899 if (!cdata->_ram_images[n]._image.empty()) {
1901 total_size += cdata->_ram_images[n]._image.size();
1907 indent(out, indent_level + 2)
1909 <<
" mipmap levels also present in ram (" << total_size
1914 indent(out, indent_level + 2)
1915 <<
"no ram image\n";
1918 if (!cdata->_simple_ram_image._image.empty()) {
1919 indent(out, indent_level + 2)
1920 <<
"simple image: " << cdata->_simple_x_size <<
" x "
1921 << cdata->_simple_y_size <<
", "
1922 << cdata->_simple_ram_image._image.size() <<
" bytes\n";
1934 if (do_get_auto_texture_scale(cdata) != ATS_none) {
1938 if (cdata->_texture_type == TT_3d_texture) {
1943 do_set_z_size(cdata, z);
1946 do_set_x_size(cdata, x);
1947 do_set_y_size(cdata, y);
1948 do_set_z_size(cdata, z);
1950 do_set_pad_size(cdata,
1953 cdata->_z_size - z);
1963 cdata->_orig_file_x_size = x;
1964 cdata->_orig_file_y_size = y;
1966 nassertv(z == cdata->_z_size);
1988 view = max(min(view, cdata->_num_views - 1), 0);
1991 Contexts &contexts = _prepared_views[prepared_objects];
1992 Contexts::const_iterator pvi;
1993 pvi = contexts.find(view);
1994 if (pvi != contexts.end()) {
1995 return (*pvi).second;
1999 contexts[view] = tc;
2057 if (
adjust_size(new_x_size, new_y_size, name,
false, auto_texture_scale)) {
2080 return "1d_texture";
2082 return "2d_texture";
2084 return "3d_texture";
2085 case TT_2d_texture_array:
2086 return "2d_texture_array";
2089 case TT_cube_map_array:
2090 return "cube_map_array";
2091 case TT_buffer_texture:
2092 return "buffer_texture";
2093 case TT_1d_texture_array:
2094 return "1d_texture_array";
2096 return "**invalid**";
2104 if (cmp_nocase(str,
"1d_texture") == 0) {
2105 return TT_1d_texture;
2106 }
else if (cmp_nocase(str,
"2d_texture") == 0) {
2107 return TT_2d_texture;
2108 }
else if (cmp_nocase(str,
"3d_texture") == 0) {
2109 return TT_3d_texture;
2110 }
else if (cmp_nocase(str,
"2d_texture_array") == 0) {
2111 return TT_2d_texture_array;
2112 }
else if (cmp_nocase(str,
"cube_map") == 0) {
2114 }
else if (cmp_nocase(str,
"cube_map_array") == 0) {
2115 return TT_cube_map_array;
2116 }
else if (cmp_nocase(str,
"buffer_texture") == 0) {
2117 return TT_buffer_texture;
2121 <<
"Invalid Texture::TextureType value: " << str <<
"\n";
2122 return TT_2d_texture;
2131 case T_unsigned_byte:
2132 return "unsigned_byte";
2133 case T_unsigned_short:
2134 return "unsigned_short";
2137 case T_unsigned_int_24_8:
2138 return "unsigned_int_24_8";
2142 return "unsigned_byte";
2146 return "half_float";
2147 case T_unsigned_int:
2148 return "unsigned_int";
2151 return "**invalid**";
2159 if (cmp_nocase(str,
"unsigned_byte") == 0) {
2160 return T_unsigned_byte;
2161 }
else if (cmp_nocase(str,
"unsigned_short") == 0) {
2162 return T_unsigned_short;
2163 }
else if (cmp_nocase(str,
"float") == 0) {
2165 }
else if (cmp_nocase(str,
"unsigned_int_24_8") == 0) {
2166 return T_unsigned_int_24_8;
2167 }
else if (cmp_nocase(str,
"int") == 0) {
2169 }
else if (cmp_nocase(str,
"byte") == 0) {
2171 }
else if (cmp_nocase(str,
"short") == 0) {
2173 }
else if (cmp_nocase(str,
"half_float") == 0) {
2174 return T_half_float;
2175 }
else if (cmp_nocase(str,
"unsigned_int") == 0) {
2176 return T_unsigned_int;
2180 <<
"Invalid Texture::ComponentType value: " << str <<
"\n";
2181 return T_unsigned_byte;
2190 case F_depth_stencil:
2191 return "depth_stencil";
2192 case F_depth_component:
2193 return "depth_component";
2194 case F_depth_component16:
2195 return "depth_component16";
2196 case F_depth_component24:
2197 return "depth_component24";
2198 case F_depth_component32:
2199 return "depth_component32";
2201 return "color_index";
2234 case F_luminance_alpha:
2235 return "luminance_alpha";
2236 case F_luminance_alphamask:
2237 return "luminance_alphamask";
2251 return "srgb_alpha";
2253 return "sluminance";
2254 case F_sluminance_alpha:
2255 return "sluminance_alpha";
2295 return "**invalid**";
2303 if (cmp_nocase(str,
"depth_stencil") == 0) {
2304 return F_depth_stencil;
2305 }
else if (cmp_nocase(str,
"depth_component") == 0) {
2306 return F_depth_component;
2307 }
else if (cmp_nocase(str,
"depth_component16") == 0 || cmp_nocase(str,
"d16") == 0) {
2308 return F_depth_component16;
2309 }
else if (cmp_nocase(str,
"depth_component24") == 0 || cmp_nocase(str,
"d24") == 0) {
2310 return F_depth_component24;
2311 }
else if (cmp_nocase(str,
"depth_component32") == 0 || cmp_nocase(str,
"d32") == 0) {
2312 return F_depth_component32;
2313 }
else if (cmp_nocase(str,
"color_index") == 0) {
2314 return F_color_index;
2315 }
else if (cmp_nocase(str,
"red") == 0) {
2317 }
else if (cmp_nocase(str,
"green") == 0) {
2319 }
else if (cmp_nocase(str,
"blue") == 0) {
2321 }
else if (cmp_nocase(str,
"alpha") == 0) {
2323 }
else if (cmp_nocase(str,
"rgb") == 0) {
2325 }
else if (cmp_nocase(str,
"rgb5") == 0) {
2327 }
else if (cmp_nocase(str,
"rgb8") == 0 || cmp_nocase(str,
"r8g8b8") == 0) {
2329 }
else if (cmp_nocase(str,
"rgb12") == 0) {
2331 }
else if (cmp_nocase(str,
"rgb332") == 0 || cmp_nocase(str,
"r3g3b2") == 0) {
2333 }
else if (cmp_nocase(str,
"rgba") == 0) {
2335 }
else if (cmp_nocase(str,
"rgbm") == 0) {
2337 }
else if (cmp_nocase(str,
"rgba4") == 0) {
2339 }
else if (cmp_nocase(str,
"rgba5") == 0) {
2341 }
else if (cmp_nocase(str,
"rgba8") == 0 || cmp_nocase(str,
"r8g8b8a8") == 0) {
2343 }
else if (cmp_nocase(str,
"rgba12") == 0) {
2345 }
else if (cmp_nocase(str,
"luminance") == 0) {
2347 }
else if (cmp_nocase(str,
"luminance_alpha") == 0) {
2348 return F_luminance_alpha;
2349 }
else if (cmp_nocase(str,
"luminance_alphamask") == 0) {
2350 return F_luminance_alphamask;
2351 }
else if (cmp_nocase(str,
"rgba16") == 0 || cmp_nocase(str,
"r16g16b16a16") == 0) {
2353 }
else if (cmp_nocase(str,
"rgba32") == 0 || cmp_nocase(str,
"r32g32b32a32") == 0) {
2355 }
else if (cmp_nocase(str,
"r16") == 0 || cmp_nocase(str,
"red16") == 0) {
2357 }
else if (cmp_nocase(str,
"r16i") == 0) {
2359 }
else if (cmp_nocase(str,
"rg16") == 0 || cmp_nocase(str,
"r16g16") == 0) {
2361 }
else if (cmp_nocase(str,
"rgb16") == 0 || cmp_nocase(str,
"r16g16b16") == 0) {
2363 }
else if (cmp_nocase(str,
"srgb") == 0) {
2365 }
else if (cmp_nocase(str,
"srgb_alpha") == 0) {
2366 return F_srgb_alpha;
2367 }
else if (cmp_nocase(str,
"sluminance") == 0) {
2368 return F_sluminance;
2369 }
else if (cmp_nocase(str,
"sluminance_alpha") == 0) {
2370 return F_sluminance_alpha;
2371 }
else if (cmp_nocase(str,
"r32i") == 0) {
2373 }
else if (cmp_nocase(str,
"r32") == 0 || cmp_nocase(str,
"red32") == 0) {
2375 }
else if (cmp_nocase(str,
"rg32") == 0 || cmp_nocase(str,
"r32g32") == 0) {
2377 }
else if (cmp_nocase(str,
"rgb32") == 0 || cmp_nocase(str,
"r32g32b32") == 0) {
2379 }
else if (cmp_nocase_uh(str,
"r8i") == 0) {
2381 }
else if (cmp_nocase_uh(str,
"rg8i") == 0 || cmp_nocase_uh(str,
"r8g8i") == 0) {
2383 }
else if (cmp_nocase_uh(str,
"rgb8i") == 0 || cmp_nocase_uh(str,
"r8g8b8i") == 0) {
2385 }
else if (cmp_nocase_uh(str,
"rgba8i") == 0 || cmp_nocase_uh(str,
"r8g8b8a8i") == 0) {
2387 }
else if (cmp_nocase(str,
"r11g11b10") == 0) {
2388 return F_r11_g11_b10;
2389 }
else if (cmp_nocase(str,
"rgb9_e5") == 0) {
2391 }
else if (cmp_nocase_uh(str,
"rgb10_a2") == 0 || cmp_nocase(str,
"r10g10b10a2") == 0) {
2393 }
else if (cmp_nocase_uh(str,
"rg") == 0) {
2395 }
else if (cmp_nocase_uh(str,
"r16i") == 0) {
2397 }
else if (cmp_nocase_uh(str,
"rg16i") == 0 || cmp_nocase_uh(str,
"r16g16i") == 0) {
2399 }
else if (cmp_nocase_uh(str,
"rgb16i") == 0 || cmp_nocase_uh(str,
"r16g16b16i") == 0) {
2401 }
else if (cmp_nocase_uh(str,
"rgba16i") == 0 || cmp_nocase_uh(str,
"r16g16b16a16i") == 0) {
2403 }
else if (cmp_nocase_uh(str,
"rg32i") == 0 || cmp_nocase_uh(str,
"r32g32i") == 0) {
2405 }
else if (cmp_nocase_uh(str,
"rgb32i") == 0 || cmp_nocase_uh(str,
"r32g32b32i") == 0) {
2407 }
else if (cmp_nocase_uh(str,
"rgba32i") == 0 || cmp_nocase_uh(str,
"r32g32b32a32i") == 0) {
2412 <<
"Invalid Texture::Format value: " << str <<
"\n";
2454 return "**invalid**";
2463 if (cmp_nocase_uh(str,
"default") == 0) {
2465 }
else if (cmp_nocase_uh(str,
"off") == 0) {
2467 }
else if (cmp_nocase_uh(str,
"on") == 0) {
2469 }
else if (cmp_nocase_uh(str,
"fxt1") == 0) {
2471 }
else if (cmp_nocase_uh(str,
"dxt1") == 0) {
2473 }
else if (cmp_nocase_uh(str,
"dxt2") == 0) {
2475 }
else if (cmp_nocase_uh(str,
"dxt3") == 0) {
2477 }
else if (cmp_nocase_uh(str,
"dxt4") == 0) {
2479 }
else if (cmp_nocase_uh(str,
"dxt5") == 0) {
2481 }
else if (cmp_nocase_uh(str,
"pvr1_2bpp") == 0) {
2482 return CM_pvr1_2bpp;
2483 }
else if (cmp_nocase_uh(str,
"pvr1_4bpp") == 0) {
2484 return CM_pvr1_4bpp;
2485 }
else if (cmp_nocase_uh(str,
"rgtc") == 0) {
2487 }
else if (cmp_nocase_uh(str,
"etc1") == 0) {
2489 }
else if (cmp_nocase_uh(str,
"etc2") == 0) {
2491 }
else if (cmp_nocase_uh(str,
"eac") == 0) {
2496 <<
"Invalid Texture::CompressionMode value: " << str <<
"\n";
2517 return "**invalid**";
2526 if (cmp_nocase(str,
"default") == 0) {
2528 }
else if (cmp_nocase(str,
"fastest") == 0) {
2530 }
else if (cmp_nocase(str,
"normal") == 0) {
2532 }
else if (cmp_nocase(str,
"best") == 0) {
2537 <<
"Invalid Texture::QualityLevel value: " << str <<
"\n";
2554 if (!keep_texture_ram && !cdata->_keep_ram_image) {
2559 CDWriter cdataw(_cycler, cdata,
false);
2560 if (gobj_cat.is_debug()) {
2562 <<
"Dumping RAM for texture " << get_name() <<
"\n";
2564 do_clear_ram_image(cdataw);
2605 return (ctype == T_unsigned_byte ||
2606 ctype == T_unsigned_short ||
2607 ctype == T_unsigned_int_24_8 ||
2608 ctype == T_unsigned_int);
2616 is_specific(Texture::CompressionMode compression) {
2617 switch (compression) {
2643 case F_luminance_alpha:
2644 case F_luminance_alphamask:
2646 case F_sluminance_alpha:
2683 case F_sluminance_alpha:
2726 adjust_size(
int &x_size,
int &y_size,
const string &name,
2727 bool for_padding, AutoTextureScale auto_texture_scale) {
2728 bool exclude =
false;
2730 for (
int i = 0; i < num_excludes && !exclude; ++i) {
2737 int new_x_size = x_size;
2738 int new_y_size = y_size;
2741 new_x_size = (int)cfloor(new_x_size * texture_scale + 0.5);
2742 new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5);
2746 new_x_size = min(max(new_x_size, (
int)texture_scale_limit), x_size);
2747 new_y_size = min(max(new_y_size, (
int)texture_scale_limit), y_size);
2750 AutoTextureScale ats = auto_texture_scale;
2751 if (ats == ATS_unspecified) {
2754 if (!for_padding && ats == ATS_pad) {
2774 case ATS_unspecified:
2778 ats = textures_square.get_value();
2779 if (!for_padding && ats == ATS_pad) {
2784 new_x_size = new_y_size = min(new_x_size, new_y_size);
2789 new_x_size = new_y_size = max(new_x_size, new_y_size);
2793 case ATS_unspecified:
2798 int max_dimension = max_texture_dimension;
2800 if (max_dimension < 0) {
2802 if (gsg !=
nullptr) {
2803 max_dimension = gsg->get_max_texture_dimension();
2807 if (max_dimension > 0) {
2808 new_x_size = min(new_x_size, (
int)max_dimension);
2809 new_y_size = min(new_y_size, (
int)max_dimension);
2813 if (x_size != new_x_size || y_size != new_y_size) {
2814 x_size = new_x_size;
2815 y_size = new_y_size;
2845 reconsider_dirty() {
2854 do_adjust_this_size(
const CData *cdata,
int &x_size,
int &y_size,
const string &name,
2855 bool for_padding)
const {
2856 return adjust_size(x_size, y_size, name, for_padding, cdata->_auto_texture_scale);
2863 do_read(CData *cdata,
const Filename &fullpath,
const Filename &alpha_fullpath,
2864 int primary_file_num_channels,
int alpha_file_channel,
2865 int z,
int n,
bool read_pages,
bool read_mipmaps,
2873 bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
2874 if (record !=
nullptr) {
2875 header_only =
false;
2878 if ((z == 0 || read_pages) && (n == 0 || read_mipmaps)) {
2881 do_clear_ram_image(cdata);
2884 if (is_txo_filename(fullpath)) {
2885 if (record !=
nullptr) {
2888 return do_read_txo_file(cdata, fullpath);
2891 if (is_dds_filename(fullpath)) {
2892 if (record !=
nullptr) {
2895 return do_read_dds_file(cdata, fullpath, header_only);
2898 if (is_ktx_filename(fullpath)) {
2899 if (record !=
nullptr) {
2902 return do_read_ktx_file(cdata, fullpath, header_only);
2914 switch (cdata->_texture_type) {
2917 case TT_buffer_texture:
2931 if (options.get_texture_flags() & LoaderOptions::TF_multiview) {
2936 do_set_num_views(cdata, num_views);
2942 if (read_pages && read_mipmaps) {
2946 do_set_z_size(cdata, z_size);
2954 z_size = do_get_expected_mipmap_z_size(cdata, n);
2964 <<
"Filename requires two different hash sequences: " << fullpath
2972 if ((n_size == 0 && (vfs->
exists(file) || n == 0)) ||
2973 (n_size != 0 && n < n_size)) {
2980 int num_pages = z_size * num_views;
2981 while ((num_pages == 0 && (vfs->
exists(file) || z == 0)) ||
2982 (num_pages != 0 && z < num_pages)) {
2983 if (!do_read_one(cdata, file, alpha_file, z, n, primary_file_num_channels,
2984 alpha_file_channel, options, header_only, record)) {
2994 if (n == 0 && n_size == 0) {
2997 n_size = do_get_expected_num_mipmap_levels(cdata);
3001 cdata->_fullpath = fullpath_pattern;
3002 cdata->_alpha_fullpath = alpha_fullpath_pattern;
3004 }
else if (read_pages) {
3008 if (!fullpath_pattern.
has_hash()) {
3010 <<
"Filename requires a hash mark: " << fullpath
3015 do_set_z_size(cdata, z_size);
3020 int num_pages = z_size * num_views;
3021 while ((num_pages == 0 && (vfs->
exists(file) || z == 0)) ||
3022 (num_pages != 0 && z < num_pages)) {
3023 if (!do_read_one(cdata, file, alpha_file, z, 0, primary_file_num_channels,
3024 alpha_file_channel, options, header_only, record)) {
3032 cdata->_fullpath = fullpath_pattern;
3033 cdata->_alpha_fullpath = alpha_fullpath_pattern;
3035 }
else if (read_mipmaps) {
3039 if (!fullpath_pattern.
has_hash()) {
3041 <<
"Filename requires a hash mark: " << fullpath
3050 while ((n_size == 0 && (vfs->
exists(file) || n == 0)) ||
3051 (n_size != 0 && n < n_size)) {
3052 if (!do_read_one(cdata, file, alpha_file, z, n,
3053 primary_file_num_channels, alpha_file_channel,
3054 options, header_only, record)) {
3059 if (n_size == 0 && n >= do_get_expected_num_mipmap_levels(cdata)) {
3068 cdata->_fullpath = fullpath_pattern;
3069 cdata->_alpha_fullpath = alpha_fullpath_pattern;
3073 if (!do_read_one(cdata, fullpath, alpha_fullpath, z, n,
3074 primary_file_num_channels, alpha_file_channel,
3075 options, header_only, record)) {
3080 cdata->_has_read_pages = read_pages;
3081 cdata->_has_read_mipmaps = read_mipmaps;
3082 cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
3087 do_clear_ram_image(cdata);
3089 if ((options.get_texture_flags() & LoaderOptions::TF_preload) != 0) {
3092 bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
3093 bool allow_compression = ((options.get_texture_flags() & LoaderOptions::TF_allow_compression) != 0);
3094 do_consider_auto_process_ram_image(cdata, generate_mipmaps ||
uses_mipmaps(), allow_compression);
3106 do_read_one(CData *cdata,
const Filename &fullpath,
const Filename &alpha_fullpath,
3107 int z,
int n,
int primary_file_num_channels,
int alpha_file_channel,
3109 if (record !=
nullptr) {
3110 nassertr(!header_only,
false);
3117 if (image_reader ==
nullptr) {
3119 <<
"Texture::read() - couldn't read: " << fullpath << endl;
3124 AutoTextureScale auto_texture_scale = do_get_auto_texture_scale(cdata);
3128 bool read_floating_point;
3129 int texture_load_type = (options.get_texture_flags() & (LoaderOptions::TF_integer | LoaderOptions::TF_float));
3130 switch (texture_load_type) {
3131 case LoaderOptions::TF_integer:
3132 read_floating_point =
false;
3135 case LoaderOptions::TF_float:
3136 read_floating_point =
true;
3143 if (!alpha_fullpath.empty()) {
3144 read_floating_point =
false;
3148 if (header_only || textures_header_only) {
3151 if (z == 0 && n == 0) {
3152 cdata->_orig_file_x_size = x_size;
3153 cdata->_orig_file_y_size = y_size;
3156 if (textures_header_only) {
3166 if (read_floating_point) {
3172 image.
fill(0.2, 0.3, 1.0);
3177 delete image_reader;
3180 if (z == 0 && n == 0) {
3184 cdata->_orig_file_x_size = x_size;
3185 cdata->_orig_file_y_size = y_size;
3191 image.
set_read_size(do_get_expected_mipmap_x_size(cdata, n),
3192 do_get_expected_mipmap_y_size(cdata, n));
3198 <<
"Implicitly rescaling " << fullpath.
get_basename() <<
" from "
3205 if (read_floating_point) {
3206 success = pfm.
read(image_reader);
3208 success = image.
read(image_reader);
3213 <<
"Texture::read() - couldn't read: " << fullpath << endl;
3220 if (!alpha_fullpath.empty()) {
3222 if (alpha_image_reader ==
nullptr) {
3224 <<
"Texture::read() - couldn't read: " << alpha_fullpath << endl;
3229 if (record !=
nullptr) {
3233 if (header_only || textures_header_only) {
3239 alpha_image.
fill(1.0);
3243 delete alpha_image_reader;
3249 <<
"Implicitly rescaling " << alpha_fullpath.
get_basename()
3250 <<
" from " << alpha_image.
get_x_size() <<
" by "
3256 if (!alpha_image.
read(alpha_image_reader)) {
3258 <<
"Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
3265 if (z == 0 && n == 0) {
3269 if (cdata->_filename.empty()) {
3270 cdata->_filename = fullpath;
3271 cdata->_alpha_filename = alpha_fullpath;
3276 cdata->_keep_ram_image =
false;
3279 cdata->_fullpath = fullpath;
3280 cdata->_alpha_fullpath = alpha_fullpath;
3283 if (!alpha_fullpath.empty()) {
3289 <<
"Automatically rescaling " << alpha_fullpath.
get_basename()
3290 <<
" from " << alpha_image.
get_x_size() <<
" by "
3298 scaled.quick_filter_from(alpha_image);
3300 alpha_image = scaled;
3305 consider_downgrade(image, primary_file_num_channels, get_name());
3307 cdata->_alpha_file_channel = 0;
3310 if (!alpha_fullpath.empty()) {
3315 if (alpha_file_channel == 4 ||
3320 << alpha_fullpath.
get_basename() <<
" has no channel " << alpha_file_channel <<
".\n";
3323 for (
int x = 0; x < image.
get_x_size(); x++) {
3324 for (
int y = 0; y < image.
get_y_size(); y++) {
3331 }
else if (alpha_file_channel >= 1 && alpha_file_channel <= 3 &&
3334 for (
int x = 0; x < image.
get_x_size(); x++) {
3335 for (
int y = 0; y < image.
get_y_size(); y++) {
3339 cdata->_alpha_file_channel = alpha_file_channel;
3343 for (
int x = 0; x < image.
get_x_size(); x++) {
3344 for (
int y = 0; y < image.
get_y_size(); y++) {
3348 cdata->_alpha_file_channel = 0;
3352 if (read_floating_point) {
3353 if (!do_load_one(cdata, pfm, fullpath.
get_basename(), z, n, options)) {
3360 if (do_get_auto_texture_scale(cdata) == ATS_pad) {
3363 if (do_adjust_this_size(cdata, new_x_size, new_y_size, fullpath.
get_basename(),
true)) {
3364 pad_x_size = new_x_size - image.
get_x_size();
3365 pad_y_size = new_y_size - image.
get_y_size();
3369 new_image.copy_sub_image(image, 0, new_y_size - image.
get_y_size());
3374 if (!do_load_one(cdata, image, fullpath.
get_basename(), z, n, options)) {
3378 do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
3387 do_load_one(CData *cdata,
const PNMImage &pnmimage,
const string &name,
int z,
int n,
3389 if (cdata->_ram_images.size() <= 1 && n == 0) {
3393 if (!do_reconsider_z_size(cdata, z, options)) {
3396 nassertr(z >= 0 && z < cdata->_z_size * cdata->_num_views,
false);
3399 ComponentType component_type = T_unsigned_byte;
3402 component_type = T_unsigned_short;
3412 do_modify_ram_image(cdata);
3413 cdata->_loaded_from_image =
true;
3416 do_modify_ram_mipmap_image(cdata, n);
3419 int x_size = do_get_expected_mipmap_x_size(cdata, n);
3420 int y_size = do_get_expected_mipmap_y_size(cdata, n);
3424 <<
"Automatically rescaling " << name;
3426 gobj_cat.info(
false)
3427 <<
" mipmap level " << n;
3429 gobj_cat.info(
false)
3430 <<
" from " << pnmimage.
get_x_size() <<
" by "
3431 << pnmimage.
get_y_size() <<
" to " << x_size <<
" by "
3437 scaled.quick_filter_from(pnmimage);
3440 convert_from_pnmimage(cdata->_ram_images[n]._image,
3441 do_get_expected_ram_mipmap_page_size(cdata, n),
3442 x_size, 0, 0, z, scaled,
3443 cdata->_num_components, cdata->_component_width);
3447 convert_from_pnmimage(cdata->_ram_images[n]._image,
3448 do_get_expected_ram_mipmap_page_size(cdata, n),
3449 x_size, 0, 0, z, pnmimage,
3450 cdata->_num_components, cdata->_component_width);
3461 do_load_one(CData *cdata,
const PfmFile &pfm,
const string &name,
int z,
int n,
3463 if (cdata->_ram_images.size() <= 1 && n == 0) {
3467 if (!do_reconsider_z_size(cdata, z, options)) {
3470 nassertr(z >= 0 && z < cdata->_z_size * cdata->_num_views,
false);
3473 ComponentType component_type = T_float;
3481 do_modify_ram_image(cdata);
3482 cdata->_loaded_from_image =
true;
3485 do_modify_ram_mipmap_image(cdata, n);
3488 int x_size = do_get_expected_mipmap_x_size(cdata, n);
3489 int y_size = do_get_expected_mipmap_y_size(cdata, n);
3493 <<
"Automatically rescaling " << name;
3495 gobj_cat.info(
false)
3496 <<
" mipmap level " << n;
3498 gobj_cat.info(
false)
3500 << pfm.
get_y_size() <<
" to " << x_size <<
" by "
3504 scaled.resize(x_size, y_size);
3507 convert_from_pfm(cdata->_ram_images[n]._image,
3508 do_get_expected_ram_mipmap_page_size(cdata, n), z,
3509 scaled, cdata->_num_components, cdata->_component_width);
3513 convert_from_pfm(cdata->_ram_images[n]._image,
3514 do_get_expected_ram_mipmap_page_size(cdata, n), z,
3515 pfm, cdata->_num_components, cdata->_component_width);
3527 do_load_sub_image(CData *cdata,
const PNMImage &image,
int x,
int y,
int z,
int n) {
3528 nassertr(n >= 0 && (
size_t)n < cdata->_ram_images.size(),
false);
3530 int tex_x_size = do_get_expected_mipmap_x_size(cdata, n);
3531 int tex_y_size = do_get_expected_mipmap_y_size(cdata, n);
3532 int tex_z_size = do_get_expected_mipmap_z_size(cdata, n);
3534 nassertr(x >= 0 && x < tex_x_size,
false);
3535 nassertr(y >= 0 && y < tex_y_size,
false);
3536 nassertr(z >= 0 && z < tex_z_size,
false);
3538 nassertr(image.
get_x_size() + x <= tex_x_size,
false);
3539 nassertr(image.
get_y_size() + y <= tex_y_size,
false);
3542 y = cdata->_y_size - (image.
get_y_size() + y);
3544 cdata->inc_image_modified();
3545 do_modify_ram_mipmap_image(cdata, n);
3546 convert_from_pnmimage(cdata->_ram_images[n]._image,
3547 do_get_expected_ram_mipmap_page_size(cdata, n),
3548 tex_x_size, x, y, z, image,
3549 cdata->_num_components, cdata->_component_width);
3559 do_read_txo_file(CData *cdata,
const Filename &fullpath) {
3562 Filename filename = Filename::binary_filename(fullpath);
3564 if (file ==
nullptr) {
3567 <<
"Could not find " << fullpath <<
"\n";
3571 if (gobj_cat.is_debug()) {
3573 <<
"Reading texture object " << filename <<
"\n";
3576 istream *in = file->open_read_file(
true);
3577 bool success = do_read_txo(cdata, *in, fullpath);
3580 cdata->_fullpath = fullpath;
3581 cdata->_alpha_fullpath =
Filename();
3582 cdata->_keep_ram_image =
false;
3591 do_read_txo(CData *cdata, istream &in,
const string &filename) {
3592 PT(
Texture) other = make_from_txo(in, filename);
3593 if (other ==
nullptr) {
3597 CDReader cdata_other(other->_cycler);
3598 Namable::operator = (*other);
3599 do_assign(cdata, other, cdata_other);
3601 cdata->_loaded_from_image =
true;
3602 cdata->_loaded_from_txo =
true;
3603 cdata->_has_read_pages =
false;
3604 cdata->_has_read_mipmaps =
false;
3605 cdata->_num_mipmap_levels_read = 0;
3614 do_read_dds_file(CData *cdata,
const Filename &fullpath,
bool header_only) {
3617 Filename filename = Filename::binary_filename(fullpath);
3619 if (file ==
nullptr) {
3622 <<
"Could not find " << fullpath <<
"\n";
3626 if (gobj_cat.is_debug()) {
3628 <<
"Reading DDS file " << filename <<
"\n";
3631 istream *in = file->open_read_file(
true);
3632 bool success = do_read_dds(cdata, *in, fullpath, header_only);
3639 cdata->_fullpath = fullpath;
3640 cdata->_alpha_fullpath =
Filename();
3641 cdata->_keep_ram_image =
false;
3650 do_read_dds(CData *cdata, istream &in,
const string &filename,
bool header_only) {
3655 header.dds_magic = dds.get_uint32();
3656 header.dds_size = dds.get_uint32();
3657 header.dds_flags = dds.get_uint32();
3658 header.height = dds.get_uint32();
3659 header.width = dds.get_uint32();
3660 header.pitch = dds.get_uint32();
3661 header.depth = dds.get_uint32();
3662 header.num_levels = dds.get_uint32();
3666 header.pf.pf_size = dds.get_uint32();
3667 header.pf.pf_flags = dds.get_uint32();
3668 header.pf.four_cc = dds.get_uint32();
3669 header.pf.rgb_bitcount = dds.get_uint32();
3670 header.pf.r_mask = dds.get_uint32();
3671 header.pf.g_mask = dds.get_uint32();
3672 header.pf.b_mask = dds.get_uint32();
3673 header.pf.a_mask = dds.get_uint32();
3676 header.caps.caps1 = dds.get_uint32();
3677 header.caps.caps2 = dds.get_uint32();
3678 header.caps.ddsx = dds.get_uint32();
3684 if (header.dds_magic != DDS_MAGIC || (in.fail() || in.eof())) {
3686 << filename <<
" is not a DDS file.\n";
3690 if ((header.dds_flags & DDSD_MIPMAPCOUNT) == 0) {
3692 header.num_levels = 1;
3694 }
else if (header.num_levels == 0) {
3697 header.num_levels = 1;
3700 TextureType texture_type;
3701 if (header.caps.caps2 & DDSCAPS2_CUBEMAP) {
3702 static const unsigned int all_faces =
3703 (DDSCAPS2_CUBEMAP_POSITIVEX |
3704 DDSCAPS2_CUBEMAP_POSITIVEY |
3705 DDSCAPS2_CUBEMAP_POSITIVEZ |
3706 DDSCAPS2_CUBEMAP_NEGATIVEX |
3707 DDSCAPS2_CUBEMAP_NEGATIVEY |
3708 DDSCAPS2_CUBEMAP_NEGATIVEZ);
3709 if ((header.caps.caps2 & all_faces) != all_faces) {
3711 << filename <<
" is missing some cube map faces; cannot load.\n";
3715 texture_type = TT_cube_map;
3717 }
else if (header.caps.caps2 & DDSCAPS2_VOLUME) {
3718 texture_type = TT_3d_texture;
3721 texture_type = TT_2d_texture;
3726 typedef PTA_uchar (*ReadDDSLevelFunc)(
Texture *tex, Texture::CData *cdata,
3727 const DDSHeader &header,
int n, istream &in);
3728 ReadDDSLevelFunc func =
nullptr;
3730 Format format = F_rgb;
3731 ComponentType component_type = T_unsigned_byte;
3733 do_clear_ram_image(cdata);
3734 CompressionMode compression = CM_off;
3736 if ((header.pf.pf_flags & DDPF_FOURCC) != 0 &&
3737 header.pf.four_cc == 0x30315844) {
3739 func = read_dds_level_generic_uncompressed;
3740 unsigned int dxgi_format = dds.get_uint32();
3741 unsigned int dimension = dds.get_uint32();
3742 unsigned int misc_flag = dds.get_uint32();
3743 unsigned int array_size = dds.get_uint32();
3746 switch (dxgi_format) {
3749 component_type = T_float;
3750 func = read_dds_level_abgr32;
3754 component_type = T_half_float;
3755 func = read_dds_level_abgr16;
3759 component_type = T_unsigned_short;
3760 func = read_dds_level_abgr16;
3764 component_type = T_unsigned_short;
3765 func = read_dds_level_abgr16;
3769 component_type = T_short;
3770 func = read_dds_level_abgr16;
3774 component_type = T_float;
3775 func = read_dds_level_raw;
3779 component_type = T_unsigned_int;
3780 func = read_dds_level_raw;
3784 component_type = T_int;
3785 func = read_dds_level_raw;
3790 func = read_dds_level_abgr8;
3793 format = F_srgb_alpha;
3794 func = read_dds_level_abgr8;
3798 func = read_dds_level_abgr8;
3802 component_type = T_byte;
3803 func = read_dds_level_abgr8;
3807 component_type = T_byte;
3808 func = read_dds_level_abgr8;
3812 component_type = T_half_float;
3813 func = read_dds_level_raw;
3817 component_type = T_unsigned_short;
3818 func = read_dds_level_raw;
3822 component_type = T_unsigned_short;
3823 func = read_dds_level_raw;
3827 component_type = T_short;
3828 func = read_dds_level_raw;
3832 component_type = T_short;
3833 func = read_dds_level_raw;
3836 format = F_depth_component32;
3837 component_type = T_float;
3838 func = read_dds_level_raw;
3842 component_type = T_float;
3843 func = read_dds_level_raw;
3847 component_type = T_unsigned_int;
3848 func = read_dds_level_raw;
3852 component_type = T_int;
3853 func = read_dds_level_raw;
3864 component_type = T_byte;
3868 component_type = T_byte;
3872 component_type = T_half_float;
3873 func = read_dds_level_raw;
3876 format = F_depth_component16;
3877 component_type = T_unsigned_short;
3878 func = read_dds_level_raw;
3882 component_type = T_unsigned_short;
3883 func = read_dds_level_raw;
3887 component_type = T_unsigned_short;
3888 func = read_dds_level_raw;
3892 component_type = T_short;
3893 func = read_dds_level_raw;
3897 component_type = T_short;
3898 func = read_dds_level_raw;
3909 component_type = T_byte;
3913 component_type = T_byte;
3921 compression = CM_dxt1;
3922 func = read_dds_level_bc1;
3926 compression = CM_dxt1;
3927 func = read_dds_level_bc1;
3932 compression = CM_dxt3;
3933 func = read_dds_level_bc2;
3936 format = F_srgb_alpha;
3937 compression = CM_dxt3;
3938 func = read_dds_level_bc2;
3943 compression = CM_dxt5;
3944 func = read_dds_level_bc3;
3947 format = F_srgb_alpha;
3948 compression = CM_dxt5;
3949 func = read_dds_level_bc3;
3954 compression = CM_rgtc;
3955 func = read_dds_level_bc4;
3960 compression = CM_rgtc;
3961 func = read_dds_level_bc5;
3972 format = F_srgb_alpha;
3982 << filename <<
": unsupported DXGI format " << dxgi_format <<
".\n";
3986 switch (dimension) {
3988 texture_type = TT_1d_texture;
3992 if (misc_flag & 0x4) {
3993 if (array_size > 1) {
3994 texture_type = TT_cube_map_array;
3995 header.depth = array_size * 6;
3997 texture_type = TT_cube_map;
4001 if (array_size > 1) {
4002 texture_type = TT_2d_texture_array;
4003 header.depth = array_size;
4005 texture_type = TT_2d_texture;
4011 texture_type = TT_3d_texture;
4015 << filename <<
": unsupported dimension.\n";
4019 }
else if (header.pf.pf_flags & DDPF_FOURCC) {
4021 if (texture_type == TT_3d_texture) {
4023 << filename <<
": unsupported compression on 3-d texture.\n";
4029 switch (header.pf.four_cc) {
4031 compression = CM_dxt1;
4032 func = read_dds_level_bc1;
4036 compression = CM_dxt2;
4037 func = read_dds_level_bc2;
4040 compression = CM_dxt3;
4041 func = read_dds_level_bc2;
4044 compression = CM_dxt4;
4045 func = read_dds_level_bc3;
4048 compression = CM_dxt5;
4049 func = read_dds_level_bc3;
4053 compression = CM_rgtc;
4054 func = read_dds_level_bc4;
4059 compression = CM_rgtc;
4060 func = read_dds_level_bc5;
4064 func = read_dds_level_abgr16;
4066 component_type = T_unsigned_short;
4069 func = read_dds_level_abgr16;
4071 component_type = T_short;
4074 func = read_dds_level_abgr16;
4076 component_type = T_half_float;
4079 func = read_dds_level_abgr32;
4081 component_type = T_float;
4085 << filename <<
": unsupported texture compression (FourCC: 0x"
4086 << std::hex << header.pf.four_cc << std::dec <<
").\n";
4092 func = read_dds_level_generic_uncompressed;
4094 if (header.pf.pf_flags & DDPF_ALPHAPIXELS) {
4097 if (header.pf.rgb_bitcount == 32 &&
4098 header.pf.r_mask == 0x000000ff &&
4099 header.pf.g_mask == 0x0000ff00 &&
4100 header.pf.b_mask == 0x00ff0000 &&
4101 header.pf.a_mask == 0xff000000U) {
4102 func = read_dds_level_abgr8;
4103 }
else if (header.pf.rgb_bitcount == 32 &&
4104 header.pf.r_mask == 0x00ff0000 &&
4105 header.pf.g_mask == 0x0000ff00 &&
4106 header.pf.b_mask == 0x000000ff &&
4107 header.pf.a_mask == 0xff000000U) {
4108 func = read_dds_level_rgba8;
4110 }
else if (header.pf.r_mask != 0 &&
4111 header.pf.g_mask == 0 &&
4112 header.pf.b_mask == 0) {
4113 func = read_dds_level_luminance_uncompressed;
4114 format = F_luminance_alpha;
4118 if (header.pf.rgb_bitcount == 24 &&
4119 header.pf.r_mask == 0x00ff0000 &&
4120 header.pf.g_mask == 0x0000ff00 &&
4121 header.pf.b_mask == 0x000000ff) {
4122 func = read_dds_level_bgr8;
4123 }
else if (header.pf.rgb_bitcount == 24 &&
4124 header.pf.r_mask == 0x000000ff &&
4125 header.pf.g_mask == 0x0000ff00 &&
4126 header.pf.b_mask == 0x00ff0000) {
4127 func = read_dds_level_rgb8;
4129 }
else if (header.pf.r_mask != 0 &&
4130 header.pf.g_mask == 0 &&
4131 header.pf.b_mask == 0) {
4132 func = read_dds_level_luminance_uncompressed;
4133 format = F_luminance;
4138 do_setup_texture(cdata, texture_type, header.width, header.height, header.depth,
4139 component_type, format);
4141 cdata->_orig_file_x_size = cdata->_x_size;
4142 cdata->_orig_file_y_size = cdata->_y_size;
4143 cdata->_compression = compression;
4144 cdata->_ram_image_compression = compression;
4147 switch (texture_type) {
4152 for (
int n = 0; n < (int)header.num_levels; ++n) {
4153 int z_size = do_get_expected_mipmap_z_size(cdata, n);
4155 size_t page_size = 0;
4157 for (z = 0; z < z_size; ++z) {
4158 PTA_uchar page = func(
this, cdata, header, n, in);
4159 if (page.is_null()) {
4162 nassertr(page_size == 0 || page_size == page.size(),
false);
4163 page_size = page.size();
4164 pages.push_back(page);
4169 PTA_uchar image = PTA_uchar::empty_array(page_size * z_size);
4170 unsigned char *imagep = (
unsigned char *)image.p();
4171 for (z = 0; z < z_size; ++z) {
4172 int fz = z_size - 1 - z;
4173 memcpy(imagep + z * page_size, pages[fz].p(), page_size);
4176 do_set_ram_mipmap_image(cdata, n, image, page_size);
4188 for (z = 0; z < 6; ++z) {
4191 levels.reserve(header.num_levels);
4193 for (n = 0; n < (int)header.num_levels; ++n) {
4194 PTA_uchar image = func(
this, cdata, header, n, in);
4195 if (image.is_null()) {
4198 levels.push_back(image);
4205 static const int level_remap[6] = {
4208 for (n = 0; n < (int)header.num_levels; ++n) {
4209 size_t page_size = pages[0][n].size();
4210 PTA_uchar image = PTA_uchar::empty_array(page_size * 6);
4211 unsigned char *imagep = (
unsigned char *)image.p();
4212 for (z = 0; z < 6; ++z) {
4213 int fz = level_remap[z];
4214 nassertr(pages[fz][n].size() == page_size,
false);
4215 memcpy(imagep + z * page_size, pages[fz][n].p(), page_size);
4218 do_set_ram_mipmap_image(cdata, n, image, page_size);
4223 case TT_2d_texture_array:
4224 case TT_cube_map_array:
4229 pages.reserve(header.depth);
4231 for (z = 0; z < (int)header.depth; ++z) {
4234 levels.reserve(header.num_levels);
4236 for (n = 0; n < (int)header.num_levels; ++n) {
4237 PTA_uchar image = func(
this, cdata, header, n, in);
4238 if (image.is_null()) {
4241 levels.push_back(image);
4246 for (n = 0; n < (int)header.num_levels; ++n) {
4247 size_t page_size = pages[0][n].size();
4248 PTA_uchar image = PTA_uchar::empty_array(page_size * header.depth);
4249 unsigned char *imagep = (
unsigned char *)image.p();
4250 for (z = 0; z < (int)header.depth; ++z) {
4251 nassertr(pages[z][n].size() == page_size,
false);
4252 memcpy(imagep + z * page_size, pages[z][n].p(), page_size);
4255 do_set_ram_mipmap_image(cdata, n, image, page_size);
4263 for (
int n = 0; n < (int)header.num_levels; ++n) {
4264 PTA_uchar image = func(
this, cdata, header, n, in);
4265 if (image.is_null()) {
4268 do_set_ram_mipmap_image(cdata, n, image, 0);
4272 cdata->_has_read_pages =
true;
4273 cdata->_has_read_mipmaps =
true;
4274 cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
4279 << filename <<
": truncated DDS file.\n";
4283 cdata->_loaded_from_image =
true;
4284 cdata->_loaded_from_txo =
true;
4294 do_read_ktx_file(CData *cdata,
const Filename &fullpath,
bool header_only) {
4297 Filename filename = Filename::binary_filename(fullpath);
4299 if (file ==
nullptr) {
4302 <<
"Could not find " << fullpath <<
"\n";
4306 if (gobj_cat.is_debug()) {
4308 <<
"Reading KTX file " << filename <<
"\n";
4311 istream *in = file->open_read_file(
true);
4312 bool success = do_read_ktx(cdata, *in, fullpath, header_only);
4319 cdata->_fullpath = fullpath;
4320 cdata->_alpha_fullpath =
Filename();
4321 cdata->_keep_ram_image =
false;
4330 do_read_ktx(CData *cdata, istream &in,
const string &filename,
bool header_only) {
4333 unsigned char magic[12];
4334 if (ktx.extract_bytes(magic, 12) != 12 ||
4335 memcmp(magic,
"\xABKTX 11\xBB\r\n\x1A\n", 12) != 0) {
4337 << filename <<
" is not a KTX file.\n";
4342 uint32_t gl_type, gl_format, internal_format, gl_base_format,
4343 width, height, depth, num_array_elements, num_faces, num_mipmap_levels,
4347 if (ktx.get_uint32() == 0x04030201) {
4349 gl_type = ktx.get_uint32();
4351 gl_format = ktx.get_uint32();
4352 internal_format = ktx.get_uint32();
4353 gl_base_format = ktx.get_uint32();
4354 width = ktx.get_uint32();
4355 height = ktx.get_uint32();
4356 depth = ktx.get_uint32();
4357 num_array_elements = ktx.get_uint32();
4358 num_faces = ktx.get_uint32();
4359 num_mipmap_levels = ktx.get_uint32();
4360 kvdata_size = ktx.get_uint32();
4363 gl_type = ktx.get_be_uint32();
4364 ktx.get_be_uint32();
4365 gl_format = ktx.get_be_uint32();
4366 internal_format = ktx.get_be_uint32();
4367 gl_base_format = ktx.get_be_uint32();
4368 width = ktx.get_be_uint32();
4369 height = ktx.get_be_uint32();
4370 depth = ktx.get_be_uint32();
4371 num_array_elements = ktx.get_be_uint32();
4372 num_faces = ktx.get_be_uint32();
4373 num_mipmap_levels = ktx.get_be_uint32();
4374 kvdata_size = ktx.get_be_uint32();
4378 ktx.skip_bytes(kvdata_size);
4381 CompressionMode compression;
4383 bool swap_bgr =
false;
4385 if (gl_type == 0 || gl_format == 0) {
4387 if (gl_type > 0 || gl_format > 0) {
4389 <<
"Compressed textures must have both type and format set to 0.\n";
4392 type = T_unsigned_byte;
4393 compression = CM_on;
4395 KTXFormat base_format;
4396 switch ((KTXCompressedFormat)internal_format) {
4397 case KTX_COMPRESSED_RED:
4399 base_format = KTX_RED;
4401 case KTX_COMPRESSED_RG:
4403 base_format = KTX_RG;
4405 case KTX_COMPRESSED_RGB:
4407 base_format = KTX_RGB;
4409 case KTX_COMPRESSED_RGBA:
4411 base_format = KTX_RGBA;
4413 case KTX_COMPRESSED_SRGB:
4415 base_format = KTX_SRGB;
4417 case KTX_COMPRESSED_SRGB_ALPHA:
4418 format = F_srgb_alpha;
4419 base_format = KTX_SRGB_ALPHA;
4421 case KTX_COMPRESSED_RGB_FXT1_3DFX:
4423 base_format = KTX_RGB;
4424 compression = CM_fxt1;
4426 case KTX_COMPRESSED_RGBA_FXT1_3DFX:
4428 base_format = KTX_RGBA;
4429 compression = CM_fxt1;
4431 case KTX_COMPRESSED_RGB_S3TC_DXT1:
4433 base_format = KTX_RGB;
4434 compression = CM_dxt1;
4436 case KTX_COMPRESSED_RGBA_S3TC_DXT1:
4438 base_format = KTX_RGB;
4439 compression = CM_dxt1;
4441 case KTX_COMPRESSED_RGBA_S3TC_DXT3:
4443 base_format = KTX_RGBA;
4444 compression = CM_dxt3;
4446 case KTX_COMPRESSED_RGBA_S3TC_DXT5:
4448 base_format = KTX_RGBA;
4449 compression = CM_dxt5;
4451 case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1:
4452 format = F_srgb_alpha;
4453 base_format = KTX_SRGB_ALPHA;
4454 compression = CM_dxt1;
4456 case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3:
4457 format = F_srgb_alpha;
4458 base_format = KTX_SRGB_ALPHA;
4459 compression = CM_dxt3;
4461 case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5:
4462 format = F_srgb_alpha;
4463 base_format = KTX_SRGB_ALPHA;
4464 compression = CM_dxt5;
4466 case KTX_COMPRESSED_SRGB_S3TC_DXT1:
4468 base_format = KTX_SRGB;
4469 compression = CM_dxt1;
4471 case KTX_COMPRESSED_RED_RGTC1:
4472 case KTX_COMPRESSED_SIGNED_RED_RGTC1:
4474 base_format = KTX_RED;
4475 compression = CM_rgtc;
4477 case KTX_COMPRESSED_RG_RGTC2:
4478 case KTX_COMPRESSED_SIGNED_RG_RGTC2:
4480 base_format = KTX_RG;
4481 compression = CM_rgtc;
4485 base_format = KTX_RGB;
4486 compression = CM_etc1;
4488 case KTX_ETC1_SRGB8:
4490 base_format = KTX_SRGB;
4491 compression = CM_etc1;
4493 case KTX_COMPRESSED_RGB8_ETC2:
4495 base_format = KTX_RGB;
4496 compression = CM_etc2;
4498 case KTX_COMPRESSED_SRGB8_ETC2:
4500 base_format = KTX_SRGB;
4501 compression = CM_etc2;
4503 case KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
4505 base_format = KTX_RGBA;
4506 compression = CM_etc2;
4508 case KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
4510 base_format = KTX_SRGB8_ALPHA8;
4511 compression = CM_etc2;
4513 case KTX_COMPRESSED_RGBA8_ETC2_EAC:
4515 base_format = KTX_RGBA;
4516 compression = CM_etc2;
4518 case KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
4519 format = F_srgb_alpha;
4520 base_format = KTX_SRGB8_ALPHA8;
4521 compression = CM_etc2;
4523 case KTX_COMPRESSED_R11_EAC:
4524 case KTX_COMPRESSED_SIGNED_R11_EAC:
4526 base_format = KTX_RED;
4527 compression = CM_eac;
4529 case KTX_COMPRESSED_RG11_EAC:
4530 case KTX_COMPRESSED_SIGNED_RG11_EAC:
4532 base_format = KTX_RG;
4533 compression = CM_eac;
4535 case KTX_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1:
4536 format = F_srgb_alpha;
4537 base_format = KTX_SRGB_ALPHA;
4538 compression = CM_pvr1_2bpp;
4540 case KTX_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1:
4541 format = F_srgb_alpha;
4542 base_format = KTX_SRGB_ALPHA;
4543 compression = CM_pvr1_4bpp;
4545 case KTX_COMPRESSED_RGBA_BPTC_UNORM:
4546 case KTX_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
4547 case KTX_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
4548 case KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
4551 << filename <<
" has unsupported compressed internal format " << internal_format <<
"\n";
4555 if (base_format != gl_base_format) {
4557 << filename <<
" has internal format that is incompatible with base "
4558 "format (0x" << std::hex << gl_base_format <<
", expected 0x"
4559 << base_format << std::dec <<
")\n";
4565 compression = CM_off;
4566 switch ((KTXType)gl_type) {
4570 case KTX_UNSIGNED_BYTE:
4571 type = T_unsigned_byte;
4576 case KTX_UNSIGNED_SHORT:
4577 type = T_unsigned_short;
4582 case KTX_UNSIGNED_INT:
4583 type = T_unsigned_int;
4588 case KTX_HALF_FLOAT:
4589 type = T_half_float;
4591 case KTX_UNSIGNED_INT_24_8:
4592 type = T_unsigned_int_24_8;
4596 << filename <<
" has unsupported component type " << gl_type <<
"\n";
4600 if (gl_format != gl_base_format) {
4602 << filename <<
" has mismatched formats: " << gl_format <<
" != "
4603 << gl_base_format <<
"\n";
4606 switch (gl_format) {
4607 case KTX_DEPTH_COMPONENT:
4608 switch (internal_format) {
4609 case KTX_DEPTH_COMPONENT:
4610 format = F_depth_component;
4612 case KTX_DEPTH_COMPONENT16:
4613 format = F_depth_component16;
4615 case KTX_DEPTH_COMPONENT24:
4616 format = F_depth_component24;
4618 case KTX_DEPTH_COMPONENT32:
4619 case KTX_DEPTH_COMPONENT32F:
4620 format = F_depth_component32;
4623 format = F_depth_component;
4625 << filename <<
" has unsupported depth component format " << internal_format <<
"\n";
4629 case KTX_DEPTH_STENCIL:
4630 format = F_depth_stencil;
4631 if (internal_format != KTX_DEPTH_STENCIL &&
4632 internal_format != KTX_DEPTH24_STENCIL8) {
4634 << filename <<
" has unsupported depth stencil format " << internal_format <<
"\n";
4639 switch (internal_format) {
4657 << filename <<
" has unsupported red format " << internal_format <<
"\n";
4661 case KTX_RED_INTEGER:
4662 switch (internal_format) {
4677 << filename <<
" has unsupported red integer format " << internal_format <<
"\n";
4684 if (internal_format != KTX_GREEN) {
4686 << filename <<
" has unsupported green format " << internal_format <<
"\n";
4692 if (internal_format != KTX_BLUE) {
4694 << filename <<
" has unsupported blue format " << internal_format <<
"\n";
4699 switch (internal_format) {
4707 case KTX_RG16_SNORM:
4717 << filename <<
" has unsupported RG format " << internal_format <<
"\n";
4721 case KTX_RG_INTEGER:
4722 switch (internal_format) {
4737 << filename <<
" has unsupported RG integer format " << internal_format <<
"\n";
4745 switch (internal_format) {
4762 case KTX_R11F_G11F_B10F:
4763 format = F_r11_g11_b10;
4766 case KTX_RGB8_SNORM:
4770 case KTX_RGB16_SNORM:
4784 << filename <<
" has unsupported RGB format " << internal_format <<
"\n";
4788 case KTX_RGB_INTEGER:
4790 case KTX_BGR_INTEGER:
4791 switch (internal_format) {
4806 << filename <<
" has unsupported RGB integer format " << internal_format <<
"\n";
4814 switch (internal_format) {
4816 case KTX_RGBA_SNORM:
4829 format = F_rgb10_a2;
4832 case KTX_RGBA8_SNORM:
4836 case KTX_RGBA16_SNORM:
4843 case KTX_SRGB_ALPHA:
4844 case KTX_SRGB8_ALPHA8:
4845 format = F_srgb_alpha;
4850 << filename <<
" has unsupported RGBA format " << internal_format <<
"\n";
4855 case KTX_RGBA_INTEGER:
4857 case KTX_BGRA_INTEGER:
4858 switch (internal_format) {
4873 << filename <<
" has unsupported RGBA integer format " << internal_format <<
"\n";
4879 format = F_luminance;
4882 case KTX_LUMINANCE_ALPHA:
4883 format = F_luminance_alpha;
4890 case KTX_STENCIL_INDEX:
4893 << filename <<
" has unsupported format " << gl_format <<
"\n";
4898 TextureType texture_type;
4900 texture_type = TT_3d_texture;
4902 }
else if (num_faces > 1) {
4903 if (num_faces != 6) {
4905 << filename <<
" has " << num_faces <<
" cube map faces, expected 6\n";
4908 if (width != height) {
4910 << filename <<
" is cube map, but does not have square dimensions\n";
4913 if (num_array_elements > 0) {
4914 depth = num_array_elements * 6;
4915 texture_type = TT_cube_map_array;
4918 texture_type = TT_cube_map;
4921 }
else if (height > 0) {
4922 if (num_array_elements > 0) {
4923 depth = num_array_elements;
4924 texture_type = TT_2d_texture_array;
4927 texture_type = TT_2d_texture;
4930 }
else if (width > 0) {
4932 if (num_array_elements > 0) {
4933 height = num_array_elements;
4934 texture_type = TT_1d_texture_array;
4937 texture_type = TT_1d_texture;
4942 << filename <<
" has zero size\n";
4946 do_setup_texture(cdata, texture_type, width, height, depth, type, format);
4948 cdata->_orig_file_x_size = cdata->_x_size;
4949 cdata->_orig_file_y_size = cdata->_y_size;
4950 cdata->_compression = compression;
4951 cdata->_ram_image_compression = compression;
4954 bool generate_mipmaps =
false;
4955 if (num_mipmap_levels == 0) {
4956 generate_mipmaps =
true;
4957 num_mipmap_levels = 1;
4960 for (uint32_t n = 0; n < num_mipmap_levels; ++n) {
4961 uint32_t image_size;
4963 image_size = ktx.get_be_uint32();
4965 image_size = ktx.get_uint32();
4969 if (compression == CM_off) {
4970 uint32_t row_size = do_get_expected_mipmap_x_size(cdata, (
int)n) * cdata->_num_components * cdata->_component_width;
4971 uint32_t num_rows = do_get_expected_mipmap_y_size(cdata, (
int)n) * do_get_expected_mipmap_z_size(cdata, (
int)n);
4972 uint32_t row_padded = (row_size + 3) & ~3;
4974 if (image_size == row_size * num_rows) {
4975 if (row_padded != row_size) {
4979 << filename <<
" does not have proper row padding for mipmap "
4980 "level " << n <<
"\n";
4982 image = PTA_uchar::empty_array(image_size);
4983 ktx.extract_bytes(image.p(), image_size);
4985 }
else if (image_size != row_padded * num_rows) {
4987 << filename <<
" has invalid image size " << image_size
4988 <<
" for mipmap level " << n <<
" (expected "
4989 << row_padded * num_rows <<
")\n";
4994 image = PTA_uchar::empty_array(row_size * num_rows);
4995 uint32_t skip = row_padded - row_size;
4996 unsigned char *p = image.p();
4997 for (uint32_t row = 0; row < num_rows; ++row) {
4998 ktx.extract_bytes(p, row_size);
4999 ktx.skip_bytes(skip);
5006 unsigned char *begin = image.p();
5007 const unsigned char *end = image.p() + image.size();
5008 size_t skip = cdata->_num_components;
5009 nassertr(skip == 3 || skip == 4,
false);
5011 switch (cdata->_component_width) {
5013 for (
unsigned char *p = begin; p < end; p += skip) {
5018 for (
short *p = (
short *)begin; p < (
short *)end; p += skip) {
5023 for (
int *p = (
int *)begin; p < (
int *)end; p += skip) {
5028 nassert_raise(
"unexpected channel count");
5033 do_set_ram_mipmap_image(cdata, (
int)n, std::move(image),
5034 row_size * do_get_expected_mipmap_y_size(cdata, (
int)n));
5038 image = PTA_uchar::empty_array(image_size);
5039 ktx.extract_bytes(image.p(), image_size);
5040 do_set_ram_mipmap_image(cdata, (
int)n, std::move(image), image_size / depth);
5043 ktx.skip_bytes(3 - ((image_size + 3) & 3));
5046 cdata->_has_read_pages =
true;
5047 cdata->_has_read_mipmaps =
true;
5048 cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
5050 if (generate_mipmaps) {
5051 do_generate_ram_mipmap_images(cdata,
false);
5057 << filename <<
": truncated KTX file.\n";
5061 cdata->_loaded_from_image =
true;
5062 cdata->_loaded_from_txo =
true;
5072 do_write(CData *cdata,
5073 const Filename &fullpath,
int z,
int n,
bool write_pages,
bool write_mipmaps) {
5074 if (is_txo_filename(fullpath)) {
5075 if (!do_has_bam_rawdata(cdata)) {
5076 do_get_bam_rawdata(cdata);
5078 nassertr(do_has_bam_rawdata(cdata),
false);
5079 return do_write_txo_file(cdata, fullpath);
5082 if (!do_has_uncompressed_ram_image(cdata)) {
5083 do_get_uncompressed_ram_image(cdata);
5086 nassertr(do_has_ram_mipmap_image(cdata, n),
false);
5087 nassertr(cdata->_ram_image_compression == CM_off,
false);
5089 if (write_pages && write_mipmaps) {
5092 int num_levels = cdata->_ram_images.size();
5094 for (
int n = 0; n < num_levels; ++n) {
5095 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
5097 for (z = 0; z < num_pages; ++z) {
5102 <<
"Filename requires two different hash sequences: " << fullpath
5113 }
else if (write_pages) {
5116 if (!fullpath_pattern.
has_hash()) {
5118 <<
"Filename requires a hash mark: " << fullpath
5123 int num_pages = cdata->_z_size * cdata->_num_views;
5124 for (z = 0; z < num_pages; ++z) {
5130 }
else if (write_mipmaps) {
5133 if (!fullpath_pattern.
has_hash()) {
5135 <<
"Filename requires a hash mark: " << fullpath
5140 int num_levels = cdata->_ram_images.size();
5141 for (
int n = 0; n < num_levels; ++n) {
5149 if (!do_write_one(cdata, fullpath, z, n)) {
5162 do_write_one(CData *cdata,
const Filename &fullpath,
int z,
int n) {
5163 if (!do_has_ram_mipmap_image(cdata, n)) {
5167 nassertr(cdata->_ram_image_compression == CM_off,
false);
5170 if (cdata->_component_type == T_float) {
5173 if (!do_store_one(cdata, pfm, z, n)) {
5176 success = pfm.
write(fullpath);
5180 if (!do_store_one(cdata, pnmimage, z, n)) {
5183 success = pnmimage.
write(fullpath);
5188 <<
"Texture::write() - couldn't write: " << fullpath << endl;
5199 do_store_one(CData *cdata,
PNMImage &pnmimage,
int z,
int n) {
5201 do_get_uncompressed_ram_image(cdata);
5203 if (!do_has_ram_mipmap_image(cdata, n)) {
5207 nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n),
false);
5208 nassertr(cdata->_ram_image_compression == CM_off,
false);
5210 if (cdata->_component_type == T_float) {
5213 bool success = convert_to_pfm(pfm,
5214 do_get_expected_mipmap_x_size(cdata, n),
5215 do_get_expected_mipmap_y_size(cdata, n),
5216 cdata->_num_components, cdata->_component_width,
5217 cdata->_ram_images[n]._image,
5218 do_get_ram_mipmap_page_size(cdata, n), z);
5222 return pfm.
store(pnmimage);
5225 return convert_to_pnmimage(pnmimage,
5226 do_get_expected_mipmap_x_size(cdata, n),
5227 do_get_expected_mipmap_y_size(cdata, n),
5228 cdata->_num_components, cdata->_component_type,
5230 cdata->_ram_images[n]._image,
5231 do_get_ram_mipmap_page_size(cdata, n), z);
5238 do_store_one(CData *cdata,
PfmFile &pfm,
int z,
int n) {
5240 do_get_uncompressed_ram_image(cdata);
5242 if (!do_has_ram_mipmap_image(cdata, n)) {
5246 nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n),
false);
5247 nassertr(cdata->_ram_image_compression == CM_off,
false);
5249 if (cdata->_component_type != T_float) {
5253 convert_to_pnmimage(pnmimage,
5254 do_get_expected_mipmap_x_size(cdata, n),
5255 do_get_expected_mipmap_y_size(cdata, n),
5256 cdata->_num_components, cdata->_component_type,
5258 cdata->_ram_images[n]._image,
5259 do_get_ram_mipmap_page_size(cdata, n), z);
5263 return pfm.
load(pnmimage);
5266 return convert_to_pfm(pfm,
5267 do_get_expected_mipmap_x_size(cdata, n),
5268 do_get_expected_mipmap_y_size(cdata, n),
5269 cdata->_num_components, cdata->_component_width,
5270 cdata->_ram_images[n]._image,
5271 do_get_ram_mipmap_page_size(cdata, n), z);
5278 do_write_txo_file(
const CData *cdata,
const Filename &fullpath)
const {
5280 Filename filename = Filename::binary_filename(fullpath);
5282 if (out ==
nullptr) {
5284 <<
"Unable to open " << filename <<
"\n";
5288 bool success = do_write_txo(cdata, *out, fullpath);
5297 do_write_txo(
const CData *cdata, ostream &out,
const string &filename)
const {
5300 if (!dout.
open(out, filename)) {
5302 <<
"Could not write texture object: " << filename <<
"\n";
5308 <<
"Unable to write to " << filename <<
"\n";
5313 if (!writer.init()) {
5317 writer.set_file_texture_mode(BamWriter::BTM_rawdata);
5319 if (!writer.write_object(
this)) {
5323 if (!do_has_bam_rawdata(cdata)) {
5325 << get_name() <<
" does not have ram image\n";
5346 Texture::CData *Texture::
5347 unlocked_ensure_ram_image(
bool allow_compression) {
5353 while (_reloading) {
5358 const CData *cdata = _cycler.
read(current_thread);
5360 if (
has_ram_image && !allow_compression && cdata->_ram_image_compression != Texture::CM_off) {
5372 nassertr(!_reloading,
nullptr);
5375 PT(
Texture) tex = do_make_copy(cdata);
5381 CDWriter cdata_tex(tex->_cycler,
true);
5382 tex->do_reload_ram_image(cdata_tex, allow_compression);
5393 cdataw->_orig_file_x_size = cdata_tex->_orig_file_x_size;
5394 cdataw->_orig_file_y_size = cdata_tex->_orig_file_y_size;
5398 if (cdata_tex->_x_size != cdataw->_x_size ||
5399 cdata_tex->_y_size != cdataw->_y_size ||
5400 cdata_tex->_z_size != cdataw->_z_size ||
5401 cdata_tex->_num_views != cdataw->_num_views ||
5402 cdata_tex->_num_components != cdataw->_num_components ||
5403 cdata_tex->_component_width != cdataw->_component_width ||
5404 cdata_tex->_texture_type != cdataw->_texture_type ||
5405 cdata_tex->_component_type != cdataw->_component_type) {
5407 cdataw->_x_size = cdata_tex->_x_size;
5408 cdataw->_y_size = cdata_tex->_y_size;
5409 cdataw->_z_size = cdata_tex->_z_size;
5410 cdataw->_num_views = cdata_tex->_num_views;
5412 cdataw->_num_components = cdata_tex->_num_components;
5413 cdataw->_component_width = cdata_tex->_component_width;
5414 cdataw->_texture_type = cdata_tex->_texture_type;
5415 cdataw->_format = cdata_tex->_format;
5416 cdataw->_component_type = cdata_tex->_component_type;
5418 cdataw->inc_properties_modified();
5419 cdataw->inc_image_modified();
5422 cdataw->_keep_ram_image = cdata_tex->_keep_ram_image;
5423 cdataw->_ram_image_compression = cdata_tex->_ram_image_compression;
5424 cdataw->_ram_images = cdata_tex->_ram_images;
5426 nassertr(_reloading,
nullptr);
5448 do_reload_ram_image(CData *cdata,
bool allow_compression) {
5452 if (!do_has_compression(cdata)) {
5453 allow_compression =
false;
5459 record = cache->lookup(cdata->_fullpath,
"txo");
5460 if (record !=
nullptr &&
5461 record->has_data()) {
5466 int x_size = cdata->_orig_file_x_size;
5467 int y_size = cdata->_orig_file_y_size;
5468 do_adjust_this_size(cdata, x_size, y_size, cdata->_filename.get_basename(),
true);
5469 if (x_size != tex->get_x_size() || y_size != tex->get_y_size()) {
5470 if (gobj_cat.is_debug()) {
5472 <<
"Cached texture " << *
this <<
" has size "
5473 << tex->get_x_size() <<
" x " << tex->get_y_size()
5474 <<
" instead of " << x_size <<
" x " << y_size
5475 <<
"; ignoring cache.\n";
5480 if (!allow_compression && tex->get_ram_image_compression() != Texture::CM_off) {
5481 if (gobj_cat.is_debug()) {
5483 <<
"Cached texture " << *
this
5484 <<
" is compressed in cache; ignoring cache.\n";
5488 <<
"Texture " << get_name() <<
" reloaded from disk cache\n";
5493 CDReader cdata_tex(tex->_cycler);
5494 cdata->_x_size = cdata_tex->_x_size;
5495 cdata->_y_size = cdata_tex->_y_size;
5496 if (cdata->_num_components != cdata_tex->_num_components) {
5497 cdata->_num_components = cdata_tex->_num_components;
5498 cdata->_format = cdata_tex->_format;
5500 cdata->_component_type = cdata_tex->_component_type;
5501 cdata->_compression = cdata_tex->_compression;
5502 cdata->_ram_image_compression = cdata_tex->_ram_image_compression;
5503 cdata->_ram_images = cdata_tex->_ram_images;
5504 cdata->_loaded_from_image =
true;
5506 bool was_compressed = (cdata->_ram_image_compression != CM_off);
5507 if (do_consider_auto_process_ram_image(cdata,
uses_mipmaps(), allow_compression)) {
5508 bool is_compressed = (cdata->_ram_image_compression != CM_off);
5509 if (!was_compressed && is_compressed &&
5515 cache->
store(record);
5526 <<
"Reloading texture " << get_name() <<
"\n";
5531 if (cdata->_has_read_pages) {
5534 if (cdata->_has_read_mipmaps) {
5535 n = cdata->_num_mipmap_levels_read;
5538 cdata->_loaded_from_image =
false;
5539 Format orig_format = cdata->_format;
5540 int orig_num_components = cdata->_num_components;
5543 if (allow_compression) {
5544 options.set_texture_flags(LoaderOptions::TF_preload |
5545 LoaderOptions::TF_allow_compression);
5547 options.set_texture_flags(LoaderOptions::TF_preload);
5549 do_read(cdata, cdata->_fullpath, cdata->_alpha_fullpath,
5550 cdata->_primary_file_num_channels, cdata->_alpha_file_channel,
5551 z, n, cdata->_has_read_pages, cdata->_has_read_mipmaps, options,
nullptr);
5553 if (orig_num_components == cdata->_num_components) {
5556 cdata->_format = orig_format;
5559 if (do_has_ram_image(cdata) && record !=
nullptr) {
5562 if (record !=
nullptr) {
5566 cache->
store(record);
5576 do_modify_ram_image(CData *cdata) {
5577 if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty() ||
5578 cdata->_ram_image_compression != CM_off) {
5579 do_make_ram_image(cdata);
5581 do_clear_ram_mipmap_images(cdata);
5583 return cdata->_ram_images[0]._image;
5591 do_make_ram_image(CData *cdata) {
5592 int image_size = do_get_expected_ram_image_size(cdata);
5593 cdata->_ram_images.clear();
5594 cdata->_ram_images.push_back(RamImage());
5595 cdata->_ram_images[0]._page_size = do_get_expected_ram_page_size(cdata);
5596 cdata->_ram_images[0]._image = PTA_uchar::empty_array(image_size, get_class_type());
5597 cdata->_ram_images[0]._pointer_image =
nullptr;
5598 cdata->_ram_image_compression = CM_off;
5600 if (cdata->_has_clear_color) {
5602 unsigned char pixel[16];
5603 const int pixel_size = do_get_clear_data(cdata,
pixel);
5604 nassertr(pixel_size > 0, cdata->_ram_images[0]._image);
5606 unsigned char *image_data = cdata->_ram_images[0]._image;
5607 for (
int i = 0; i < image_size; i += pixel_size) {
5608 memcpy(image_data + i,
pixel, pixel_size);
5612 return cdata->_ram_images[0]._image;
5623 do_set_ram_image(CData *cdata,
CPTA_uchar image, Texture::CompressionMode compression,
5625 nassertv(compression != CM_default);
5626 nassertv(compression != CM_off || image.size() == do_get_expected_ram_image_size(cdata));
5627 if (cdata->_ram_images.empty()) {
5628 cdata->_ram_images.push_back(RamImage());
5630 do_clear_ram_mipmap_images(cdata);
5632 if (page_size == 0) {
5633 page_size = image.size();
5635 if (cdata->_ram_images[0]._image != image ||
5636 cdata->_ram_images[0]._page_size != page_size ||
5637 cdata->_ram_image_compression != compression) {
5639 cdata->_ram_images[0]._page_size = page_size;
5640 cdata->_ram_images[0]._pointer_image =
nullptr;
5641 cdata->_ram_image_compression = compression;
5642 cdata->inc_image_modified();
5651 do_modify_ram_mipmap_image(CData *cdata,
int n) {
5652 nassertr(cdata->_ram_image_compression == CM_off, PTA_uchar());
5654 if (n >= (
int)cdata->_ram_images.size() ||
5655 cdata->_ram_images[n]._image.empty()) {
5656 do_make_ram_mipmap_image(cdata, n);
5658 return cdata->_ram_images[n]._image;
5665 do_make_ram_mipmap_image(CData *cdata,
int n) {
5666 nassertr(cdata->_ram_image_compression == CM_off, PTA_uchar(get_class_type()));
5668 while (n >= (
int)cdata->_ram_images.size()) {
5669 cdata->_ram_images.push_back(RamImage());
5672 size_t image_size = do_get_expected_ram_mipmap_image_size(cdata, n);
5673 cdata->_ram_images[n]._image = PTA_uchar::empty_array(image_size, get_class_type());
5674 cdata->_ram_images[n]._pointer_image =
nullptr;
5675 cdata->_ram_images[n]._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
5677 if (cdata->_has_clear_color) {
5679 unsigned char pixel[16];
5680 const size_t pixel_size = (size_t)do_get_clear_data(cdata,
pixel);
5681 nassertr(pixel_size > 0, cdata->_ram_images[n]._image);
5683 unsigned char *image_data = cdata->_ram_images[n]._image;
5684 for (
size_t i = 0; i < image_size; i += pixel_size) {
5685 memcpy(image_data + i,
pixel, pixel_size);
5689 return cdata->_ram_images[n]._image;
5696 do_set_ram_mipmap_image(CData *cdata,
int n,
CPTA_uchar image,
size_t page_size) {
5697 nassertv(cdata->_ram_image_compression != CM_off || image.size() == do_get_expected_ram_mipmap_image_size(cdata, n));
5699 while (n >= (
int)cdata->_ram_images.size()) {
5700 cdata->_ram_images.push_back(RamImage());
5702 if (page_size == 0) {
5703 page_size = image.size();
5706 if (cdata->_ram_images[n]._image != image ||
5707 cdata->_ram_images[n]._page_size != page_size) {
5709 cdata->_ram_images[n]._pointer_image =
nullptr;
5710 cdata->_ram_images[n]._page_size = page_size;
5711 cdata->inc_image_modified();
5723 do_get_clear_data(
const CData *cdata,
unsigned char *into)
const {
5724 nassertr(cdata->_has_clear_color, 0);
5726 int num_components = cdata->_num_components;
5727 nassertr(num_components > 0, 0);
5728 nassertr(num_components <= 4, 0);
5730 LVecBase4 clear_value = cdata->_clear_color;
5733 if (num_components >= 3) {
5734 std::swap(clear_value[0], clear_value[2]);
5737 switch (cdata->_component_type) {
5738 case T_unsigned_byte:
5739 if (
is_srgb(cdata->_format)) {
5743 switch (num_components) {
5744 case 4: into[3] = (
unsigned char)alpha;
5745 case 3: into[2] = (
unsigned char)color.b;
5746 case 2: into[1] = (
unsigned char)color.g;
5747 case 1: into[0] = (
unsigned char)color.r;
5750 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor::zero());
5752 for (
int i = 0; i < num_components; ++i) {
5753 into[i] = (
unsigned char)scaled[i];
5758 case T_unsigned_short:
5760 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor::zero());
5762 for (
int i = 0; i < num_components; ++i) {
5763 ((
unsigned short *)into)[i] = (
unsigned short)scaled[i];
5769 for (
int i = 0; i < num_components; ++i) {
5770 ((
float *)into)[i] = clear_value[i];
5774 case T_unsigned_int_24_8:
5775 nassertr(num_components == 1, 0);
5776 *((
unsigned int *)into) =
5777 ((
unsigned int)(clear_value[0] * 16777215) << 8) +
5778 (
unsigned int)max(min(clear_value[1], (PN_stdfloat)255), (PN_stdfloat)0);
5784 for (
int i = 0; i < num_components; ++i) {
5785 ((
int *)into)[i] = (int)clear_value[i];
5791 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor(-1));
5793 for (
int i = 0; i < num_components; ++i) {
5794 ((
signed char *)into)[i] = (
signed char)scaled[i];
5801 LColor scaled = clear_value.fmin(LColor(1)).fmax(LColor(-1));
5803 for (
int i = 0; i < num_components; ++i) {
5804 ((
short *)into)[i] = (short)scaled[i];
5810 for (
int i = 0; i < num_components; ++i) {
5815 v.uf = clear_value[i];
5816 uint16_t sign = ((v.ui & 0x80000000u) >> 16u);
5817 uint32_t mantissa = (v.ui & 0x007fffffu);
5818 uint16_t exponent = (uint16_t)std::min(std::max((
int)((v.ui & 0x7f800000u) >> 23u) - 112, 0), 31);
5819 mantissa += (mantissa & 0x00001000u) << 1u;
5820 ((uint16_t *)into)[i] = (uint16_t)(sign | ((exponent << 10u) | (mantissa >> 13u)));
5824 case T_unsigned_int:
5827 for (
int i = 0; i < num_components; ++i) {
5828 ((
unsigned int *)into)[i] = (
unsigned int)clear_value[i];
5832 return num_components * cdata->_component_width;
5843 consider_auto_process_ram_image(
bool generate_mipmaps,
bool allow_compression) {
5844 CDWriter cdata(_cycler,
false);
5845 return do_consider_auto_process_ram_image(cdata, generate_mipmaps, allow_compression);
5856 do_consider_auto_process_ram_image(CData *cdata,
bool generate_mipmaps,
5857 bool allow_compression) {
5858 bool modified =
false;
5860 if (generate_mipmaps && !driver_generate_mipmaps &&
5861 cdata->_ram_images.size() == 1) {
5862 do_generate_ram_mipmap_images(cdata,
false);
5866 if (allow_compression && !driver_compress_textures) {
5867 CompressionMode compression = cdata->_compression;
5868 if (compression == CM_default && compressed_textures) {
5869 if (cdata->_texture_type == Texture::TT_buffer_texture) {
5870 compression = CM_off;
5873 compression = CM_on;
5876 if (compression != CM_off && cdata->_ram_image_compression == CM_off) {
5878 if (do_compress_ram_image(cdata, compression, QL_default, gsg)) {
5879 if (gobj_cat.is_debug()) {
5881 <<
"Compressed " << get_name() <<
" with "
5882 << cdata->_ram_image_compression <<
"\n";
5896 do_compress_ram_image(CData *cdata, Texture::CompressionMode compression,
5897 Texture::QualityLevel quality_level,
5899 nassertr(compression != CM_off,
false);
5901 if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
5905 if (compression == CM_on) {
5907 switch (cdata->_format) {
5908 case Texture::F_rgbm:
5909 case Texture::F_rgb:
5910 case Texture::F_rgb5:
5911 case Texture::F_rgba5:
5912 case Texture::F_rgb8:
5913 case Texture::F_rgb12:
5914 case Texture::F_rgb332:
5915 case Texture::F_rgb16:
5916 case Texture::F_rgb32:
5917 case Texture::F_rgb10_a2:
5918 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt1)) {
5919 compression = CM_dxt1;
5920 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt3)) {
5921 compression = CM_dxt3;
5922 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5923 compression = CM_dxt5;
5924 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5925 compression = CM_etc2;
5926 }
else if (gsg->get_supports_compressed_texture_format(CM_etc1)) {
5927 compression = CM_etc1;
5931 case Texture::F_rgba4:
5932 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt3)) {
5933 compression = CM_dxt3;
5934 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5935 compression = CM_dxt5;
5936 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5937 compression = CM_etc2;
5941 case Texture::F_rgba:
5942 case Texture::F_rgba8:
5943 case Texture::F_rgba12:
5944 case Texture::F_rgba16:
5945 case Texture::F_rgba32:
5946 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5947 compression = CM_dxt5;
5948 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5949 compression = CM_etc2;
5953 case Texture::F_red:
5955 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_rgtc)) {
5956 compression = CM_rgtc;
5957 }
else if (gsg->get_supports_compressed_texture_format(CM_eac)) {
5958 compression = CM_eac;
5968 if (quality_level == Texture::QL_default) {
5969 quality_level = cdata->_quality_level;
5971 if (quality_level == Texture::QL_default) {
5972 quality_level = texture_quality_level;
5975 if (compression == CM_rgtc) {
5977 if (cdata->_component_type != T_unsigned_byte) {
5981 if (!do_has_all_ram_mipmap_images(cdata)) {
5984 do_generate_ram_mipmap_images(cdata,
false);
5987 RamImages compressed_ram_images;
5988 compressed_ram_images.resize(cdata->_ram_images.size());
5990 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
5991 const RamImage *uncompressed_image = &cdata->_ram_images[n];
5993 int x_size = do_get_expected_mipmap_x_size(cdata, n);
5994 int y_size = do_get_expected_mipmap_y_size(cdata, n);
5995 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
6000 RamImage temp_image;
6001 if ((x_size | y_size) & 0x3) {
6002 int virtual_x_size = x_size;
6003 int virtual_y_size = y_size;
6004 x_size = (x_size + 3) & ~0x3;
6005 y_size = (y_size + 3) & ~0x3;
6007 temp_image._page_size = x_size * y_size * cdata->_num_components;
6008 temp_image._image = PTA_uchar::empty_array(temp_image._page_size * num_pages);
6010 for (
int z = 0; z < num_pages; ++z) {
6011 unsigned char *dest = temp_image._image.p() + z * temp_image._page_size;
6012 unsigned const char *src = uncompressed_image->_image.p() + z * uncompressed_image->_page_size;
6014 for (
int y = 0; y < virtual_y_size; ++y) {
6015 memcpy(dest, src, virtual_x_size);
6016 src += virtual_x_size;
6021 uncompressed_image = &temp_image;
6025 RamImage &compressed_image = compressed_ram_images[n];
6026 compressed_image._page_size = (x_size * y_size * cdata->_num_components) >> 1;
6027 compressed_image._image = PTA_uchar::empty_array(compressed_image._page_size * num_pages);
6029 if (cdata->_num_components == 1) {
6030 do_compress_ram_image_bc4(*uncompressed_image, compressed_image,
6031 x_size, y_size, num_pages);
6032 }
else if (cdata->_num_components == 2) {
6033 do_compress_ram_image_bc5(*uncompressed_image, compressed_image,
6034 x_size, y_size, num_pages);
6041 cdata->_ram_images.swap(compressed_ram_images);
6042 cdata->_ram_image_compression = CM_rgtc;
6047 if (cdata->_texture_type != TT_3d_texture &&
6048 cdata->_texture_type != TT_2d_texture_array &&
6049 cdata->_component_type == T_unsigned_byte) {
6050 int squish_flags = 0;
6051 switch (compression) {
6053 squish_flags |= squish::kDxt1;
6057 squish_flags |= squish::kDxt3;
6061 squish_flags |= squish::kDxt5;
6068 if (squish_flags != 0) {
6070 switch (quality_level) {
6072 squish_flags |= squish::kColourRangeFit;
6077 squish_flags |= squish::kColourRangeFit;
6082 squish_flags |= squish::kColourIterativeClusterFit;
6089 if (do_squish(cdata, compression, squish_flags)) {
6103 do_uncompress_ram_image(CData *cdata) {
6104 nassertr(!cdata->_ram_images.empty(),
false);
6106 if (cdata->_ram_image_compression == CM_rgtc) {
6108 RamImages uncompressed_ram_images;
6109 uncompressed_ram_images.resize(cdata->_ram_images.size());
6111 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
6112 const RamImage &compressed_image = cdata->_ram_images[n];
6114 int x_size = do_get_expected_mipmap_x_size(cdata, n);
6115 int y_size = do_get_expected_mipmap_y_size(cdata, n);
6116 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
6118 RamImage &uncompressed_image = uncompressed_ram_images[n];
6119 uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
6120 uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * num_pages);
6122 if (cdata->_num_components == 1) {
6123 do_uncompress_ram_image_bc4(compressed_image, uncompressed_image,
6124 x_size, y_size, num_pages);
6125 }
else if (cdata->_num_components == 2) {
6126 do_uncompress_ram_image_bc5(compressed_image, uncompressed_image,
6127 x_size, y_size, num_pages);
6133 cdata->_ram_images.swap(uncompressed_ram_images);
6134 cdata->_ram_image_compression = CM_off;
6139 if (cdata->_texture_type != TT_3d_texture &&
6140 cdata->_texture_type != TT_2d_texture_array &&
6141 cdata->_component_type == T_unsigned_byte) {
6142 int squish_flags = 0;
6143 switch (cdata->_ram_image_compression) {
6145 squish_flags |= squish::kDxt1;
6149 squish_flags |= squish::kDxt3;
6153 squish_flags |= squish::kDxt5;
6160 if (squish_flags != 0) {
6162 if (do_unsquish(cdata, squish_flags)) {
6175 do_compress_ram_image_bc4(
const RamImage &uncompressed_image,
6176 RamImage &compressed_image,
6177 int x_size,
int y_size,
int num_pages) {
6178 int x_blocks = (x_size >> 2);
6179 int y_blocks = (y_size >> 2);
6185 nassertv((
size_t)x_blocks * (
size_t)y_blocks * 4 * 4 <= uncompressed_image._page_size);
6186 nassertv((
size_t)x_size * (
size_t)y_size == uncompressed_image._page_size);
6188 static const int remap[] = {1, 7, 6, 5, 4, 3, 2, 0};
6190 for (
int z = 0; z < num_pages; ++z) {
6191 unsigned char *dest = compressed_image._image.p() + z * compressed_image._page_size;
6192 unsigned const char *src = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6195 for (
int y = 0; y < y_blocks; ++y) {
6196 for (
int x = 0; x < x_blocks; ++x) {
6199 unsigned char minv, maxv;
6200 unsigned const char *blk = src;
6205 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6206 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6207 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6209 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6210 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6211 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6212 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6214 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6215 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6216 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6217 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6219 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6220 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6221 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6222 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6227 fac = 7.5f / (maxv - minv);
6232 a = (remap[(int)(blk[0] * fac + add)])
6233 | (remap[(
int)(blk[1] * fac + add)] << 3)
6234 | (remap[(int)(blk[2] * fac + add)] << 6)
6235 | (remap[(
int)(blk[3] * fac + add)] << 9);
6237 b = (remap[(int)(blk[0] * fac + add)] << 4)
6238 | (remap[(
int)(blk[1] * fac + add)] << 7)
6239 | (remap[(int)(blk[2] * fac + add)] << 10)
6240 | (remap[(
int)(blk[3] * fac + add)] << 13);
6242 c = (remap[(int)(blk[0] * fac + add)])
6243 | (remap[(
int)(blk[1] * fac + add)] << 3)
6244 | (remap[(int)(blk[2] * fac + add)] << 6)
6245 | (remap[(
int)(blk[3] * fac + add)] << 9);
6247 d = (remap[(int)(blk[0] * fac + add)] << 4)
6248 | (remap[(
int)(blk[1] * fac + add)] << 7)
6249 | (remap[(int)(blk[2] * fac + add)] << 10)
6250 | (remap[(
int)(blk[3] * fac + add)] << 13);
6254 *(dest++) = a & 0xff;
6255 *(dest++) = (a >> 8) | (b & 0xf0);
6257 *(dest++) = c & 0xff;
6258 *(dest++) = (c >> 8) | (d & 0xf0);
6274 do_compress_ram_image_bc5(
const RamImage &uncompressed_image,
6275 RamImage &compressed_image,
6276 int x_size,
int y_size,
int num_pages) {
6277 int x_blocks = (x_size >> 2);
6278 int y_blocks = (y_size >> 2);
6279 int stride = x_size * 2;
6284 nassertv((
size_t)x_blocks * (
size_t)y_blocks * 4 * 4 * 2 <= uncompressed_image._page_size);
6285 nassertv((
size_t)stride * (
size_t)y_size == uncompressed_image._page_size);
6287 static const int remap[] = {1, 7, 6, 5, 4, 3, 2, 0};
6289 for (
int z = 0; z < num_pages; ++z) {
6290 unsigned char *dest = compressed_image._image.p() + z * compressed_image._page_size;
6291 unsigned const char *src = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6294 for (
int y = 0; y < y_blocks; ++y) {
6295 for (
int x = 0; x < x_blocks; ++x) {
6298 unsigned char minv, maxv;
6299 unsigned const char *blk = src;
6304 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6305 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6306 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6308 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6309 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6310 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6311 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6313 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6314 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6315 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6316 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6318 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6319 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6320 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6321 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6325 fac = 7.5f / (maxv - minv);
6331 a = (remap[(int)(blk[0] * fac + add)])
6332 | (remap[(
int)(blk[2] * fac + add)] << 3)
6333 | (remap[(int)(blk[4] * fac + add)] << 6)
6334 | (remap[(
int)(blk[6] * fac + add)] << 9);
6336 b = (remap[(int)(blk[0] * fac + add)] << 4)
6337 | (remap[(
int)(blk[2] * fac + add)] << 7)
6338 | (remap[(int)(blk[4] * fac + add)] << 10)
6339 | (remap[(
int)(blk[6] * fac + add)] << 13);
6341 c = (remap[(int)(blk[0] * fac + add)])
6342 | (remap[(
int)(blk[2] * fac + add)] << 3)
6343 | (remap[(int)(blk[4] * fac + add)] << 6)
6344 | (remap[(
int)(blk[6] * fac + add)] << 9);
6346 d = (remap[(int)(blk[0] * fac + add)] << 4)
6347 | (remap[(
int)(blk[2] * fac + add)] << 7)
6348 | (remap[(int)(blk[4] * fac + add)] << 10)
6349 | (remap[(
int)(blk[6] * fac + add)] << 13);
6353 *(dest++) = a & 0xff;
6354 *(dest++) = (a >> 8) | (b & 0xf0);
6356 *(dest++) = c & 0xff;
6357 *(dest++) = (c >> 8) | (d & 0xf0);
6364 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6365 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6366 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6368 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6369 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6370 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6371 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6373 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6374 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6375 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6376 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6378 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
6379 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6380 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6381 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6385 fac = 7.5f / (maxv - minv);
6391 a = (remap[(int)(blk[0] * fac + add)])
6392 | (remap[(
int)(blk[2] * fac + add)] << 3)
6393 | (remap[(int)(blk[4] * fac + add)] << 6)
6394 | (remap[(
int)(blk[6] * fac + add)] << 9);
6396 b = (remap[(int)(blk[0] * fac + add)] << 4)
6397 | (remap[(
int)(blk[2] * fac + add)] << 7)
6398 | (remap[(int)(blk[4] * fac + add)] << 10)
6399 | (remap[(
int)(blk[6] * fac + add)] << 13);
6401 c = (remap[(int)(blk[0] * fac + add)])
6402 | (remap[(
int)(blk[2] * fac + add)] << 3)
6403 | (remap[(int)(blk[4] * fac + add)] << 6)
6404 | (remap[(
int)(blk[6] * fac + add)] << 9);
6406 d = (remap[(int)(blk[0] * fac + add)] << 4)
6407 | (remap[(
int)(blk[2] * fac + add)] << 7)
6408 | (remap[(int)(blk[4] * fac + add)] << 10)
6409 | (remap[(
int)(blk[6] * fac + add)] << 13);
6413 *(dest++) = a & 0xff;
6414 *(dest++) = (a >> 8) | (b & 0xf0);
6416 *(dest++) = c & 0xff;
6417 *(dest++) = (c >> 8) | (d & 0xf0);
6433 do_uncompress_ram_image_bc4(
const RamImage &compressed_image,
6434 RamImage &uncompressed_image,
6435 int x_size,
int y_size,
int num_pages) {
6436 int x_blocks = (x_size >> 2);
6437 int y_blocks = (y_size >> 2);
6439 for (
int z = 0; z < num_pages; ++z) {
6440 unsigned char *dest = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6441 unsigned const char *src = compressed_image._image.p() + z * compressed_image._page_size;
6445 for (
int y = 0; y < y_blocks; ++y) {
6446 for (
int x = 0; x < x_blocks; ++x) {
6447 unsigned char *blk = dest;
6450 if (tbl[0] > tbl[1]) {
6451 tbl[2] = (tbl[0] * 6 + tbl[1] * 1) / 7.0f;
6452 tbl[3] = (tbl[0] * 5 + tbl[1] * 2) / 7.0f;
6453 tbl[4] = (tbl[0] * 4 + tbl[1] * 3) / 7.0f;
6454 tbl[5] = (tbl[0] * 3 + tbl[1] * 4) / 7.0f;
6455 tbl[6] = (tbl[0] * 2 + tbl[1] * 5) / 7.0f;
6456 tbl[7] = (tbl[0] * 1 + tbl[1] * 6) / 7.0f;
6458 tbl[2] = (tbl[0] * 4 + tbl[1] * 1) / 5.0f;
6459 tbl[3] = (tbl[0] * 3 + tbl[1] * 2) / 5.0f;
6460 tbl[4] = (tbl[0] * 2 + tbl[1] * 3) / 5.0f;
6461 tbl[5] = (tbl[0] * 1 + tbl[1] * 4) / 5.0f;
6465 int v = src[2] + (src[3] << 8) + (src[4] << 16);
6466 blk[0] = tbl[v & 0x7];
6467 blk[1] = tbl[(v & 0x000038) >> 3];
6468 blk[2] = tbl[(v & 0x0001c0) >> 6];
6469 blk[3] = tbl[(v & 0x000e00) >> 9];
6471 blk[0] = tbl[(v & 0x007000) >> 12];
6472 blk[1] = tbl[(v & 0x038000) >> 15];
6473 blk[2] = tbl[(v & 0x1c0000) >> 18];
6474 blk[3] = tbl[(v & 0xe00000) >> 21];
6476 v = src[5] + (src[6] << 8) + (src[7] << 16);
6477 blk[0] = tbl[v & 0x7];
6478 blk[1] = tbl[(v & 0x000038) >> 3];
6479 blk[2] = tbl[(v & 0x0001c0) >> 6];
6480 blk[3] = tbl[(v & 0x000e00) >> 9];
6482 blk[0] = tbl[(v & 0x007000) >> 12];
6483 blk[1] = tbl[(v & 0x038000) >> 15];
6484 blk[2] = tbl[(v & 0x1c0000) >> 18];
6485 blk[3] = tbl[(v & 0xe00000) >> 21];
6499 do_uncompress_ram_image_bc5(
const RamImage &compressed_image,
6500 RamImage &uncompressed_image,
6501 int x_size,
int y_size,
int num_pages) {
6502 int x_blocks = (x_size >> 2);
6503 int y_blocks = (y_size >> 2);
6504 int stride = x_size * 2;
6506 for (
int z = 0; z < num_pages; ++z) {
6507 unsigned char *dest = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6508 unsigned const char *src = compressed_image._image.p() + z * compressed_image._page_size;
6513 for (
int y = 0; y < y_blocks; ++y) {
6514 for (
int x = 0; x < x_blocks; ++x) {
6515 unsigned char *blk = dest;
6518 if (red[0] > red[1]) {
6519 red[2] = (red[0] * 6 + red[1] * 1) / 7.0f;
6520 red[3] = (red[0] * 5 + red[1] * 2) / 7.0f;
6521 red[4] = (red[0] * 4 + red[1] * 3) / 7.0f;
6522 red[5] = (red[0] * 3 + red[1] * 4) / 7.0f;
6523 red[6] = (red[0] * 2 + red[1] * 5) / 7.0f;
6524 red[7] = (red[0] * 1 + red[1] * 6) / 7.0f;
6526 red[2] = (red[0] * 4 + red[1] * 1) / 5.0f;
6527 red[3] = (red[0] * 3 + red[1] * 2) / 5.0f;
6528 red[4] = (red[0] * 2 + red[1] * 3) / 5.0f;
6529 red[5] = (red[0] * 1 + red[1] * 4) / 5.0f;
6535 if (grn[0] > grn[1]) {
6536 grn[2] = (grn[0] * 6 + grn[1] * 1) / 7.0f;
6537 grn[3] = (grn[0] * 5 + grn[1] * 2) / 7.0f;
6538 grn[4] = (grn[0] * 4 + grn[1] * 3) / 7.0f;
6539 grn[5] = (grn[0] * 3 + grn[1] * 4) / 7.0f;
6540 grn[6] = (grn[0] * 2 + grn[1] * 5) / 7.0f;
6541 grn[7] = (grn[0] * 1 + grn[1] * 6) / 7.0f;
6543 grn[2] = (grn[0] * 4 + grn[1] * 1) / 5.0f;
6544 grn[3] = (grn[0] * 3 + grn[1] * 2) / 5.0f;
6545 grn[4] = (grn[0] * 2 + grn[1] * 3) / 5.0f;
6546 grn[5] = (grn[0] * 1 + grn[1] * 4) / 5.0f;
6550 int r = src[2] + (src[3] << 8) + (src[4] << 16);
6551 int g = src[10] + (src[11] << 8) + (src[12] << 16);
6552 blk[0] = red[r & 0x7];
6553 blk[1] = grn[g & 0x7];
6554 blk[2] = red[(r & 0x000038) >> 3];
6555 blk[3] = grn[(g & 0x000038) >> 3];
6556 blk[4] = red[(r & 0x0001c0) >> 6];
6557 blk[5] = grn[(g & 0x0001c0) >> 6];
6558 blk[6] = red[(r & 0x000e00) >> 9];
6559 blk[7] = grn[(g & 0x000e00) >> 9];
6561 blk[0] = red[(r & 0x007000) >> 12];
6562 blk[1] = grn[(g & 0x007000) >> 12];
6563 blk[2] = red[(r & 0x038000) >> 15];
6564 blk[3] = grn[(g & 0x038000) >> 15];
6565 blk[4] = red[(r & 0x1c0000) >> 18];
6566 blk[5] = grn[(g & 0x1c0000) >> 18];
6567 blk[6] = red[(r & 0xe00000) >> 21];
6568 blk[7] = grn[(g & 0xe00000) >> 21];
6570 r = src[5] + (src[6] << 8) + (src[7] << 16);
6571 g = src[13] + (src[14] << 8) + (src[15] << 16);
6572 blk[0] = red[r & 0x7];
6573 blk[1] = grn[g & 0x7];
6574 blk[2] = red[(r & 0x000038) >> 3];
6575 blk[3] = grn[(g & 0x000038) >> 3];
6576 blk[4] = red[(r & 0x0001c0) >> 6];
6577 blk[5] = grn[(g & 0x0001c0) >> 6];
6578 blk[6] = red[(r & 0x000e00) >> 9];
6579 blk[7] = grn[(g & 0x000e00) >> 9];
6581 blk[0] = red[(r & 0x007000) >> 12];
6582 blk[1] = grn[(g & 0x007000) >> 12];
6583 blk[2] = red[(r & 0x038000) >> 15];
6584 blk[3] = grn[(g & 0x038000) >> 15];
6585 blk[4] = red[(r & 0x1c0000) >> 18];
6586 blk[5] = grn[(g & 0x1c0000) >> 18];
6587 blk[6] = red[(r & 0xe00000) >> 21];
6588 blk[7] = grn[(g & 0xe00000) >> 21];
6602 do_has_all_ram_mipmap_images(
const CData *cdata)
const {
6603 if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty()) {
6614 int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
6620 if (n >= (
int)cdata->_ram_images.size() || cdata->_ram_images[n]._image.empty()) {
6636 do_reconsider_z_size(CData *cdata,
int z,
const LoaderOptions &options) {
6637 if (z >= cdata->_z_size * cdata->_num_views) {
6638 bool num_views_specified =
true;
6639 if (options.get_texture_flags() & LoaderOptions::TF_multiview) {
6646 if (num_views_specified &&
6647 (cdata->_texture_type == Texture::TT_3d_texture ||
6648 cdata->_texture_type == Texture::TT_2d_texture_array)) {
6653 nassertr(cdata->_num_views != 0,
false);
6654 cdata->_z_size = (z / cdata->_num_views) + 1;
6656 }
else if (cdata->_z_size != 0) {
6660 cdata->_num_views = (z / cdata->_z_size) + 1;
6669 do_allocate_pages(cdata);
6682 do_allocate_pages(CData *cdata) {
6683 size_t new_size = do_get_expected_ram_image_size(cdata);
6684 if (!cdata->_ram_images.empty() &&
6685 !cdata->_ram_images[0]._image.empty() &&
6686 new_size > cdata->_ram_images[0]._image.size()) {
6687 cdata->_ram_images[0]._image.insert(cdata->_ram_images[0]._image.end(), new_size - cdata->_ram_images[0]._image.size(), 0);
6688 nassertv(cdata->_ram_images[0]._image.size() == new_size);
6699 do_reconsider_image_properties(CData *cdata,
int x_size,
int y_size,
int num_components,
6700 Texture::ComponentType component_type,
int z,
6702 if (!cdata->_loaded_from_image || num_components != cdata->_num_components || component_type != cdata->_component_type) {
6708 switch (num_components) {
6710 cdata->_format = F_luminance;
6714 cdata->_format = F_luminance_alpha;
6718 cdata->_format = F_rgb;
6722 cdata->_format = F_rgba;
6727 nassert_raise(
"unexpected channel count");
6728 cdata->_format = F_rgb;
6733 if (!cdata->_loaded_from_image) {
6734 if ((options.get_texture_flags() & LoaderOptions::TF_allow_1d) &&
6735 cdata->_texture_type == TT_2d_texture && x_size != 1 && y_size == 1) {
6737 cdata->_texture_type = TT_1d_texture;
6741 switch (cdata->_texture_type) {
6743 case TT_buffer_texture:
6744 nassertr(y_size == 1,
false);
6747 case TT_cube_map_array:
6748 nassertr(x_size == y_size,
false);
6754 if ((cdata->_x_size != x_size)||(cdata->_y_size != y_size)) {
6755 do_set_pad_size(cdata, 0, 0, 0);
6757 cdata->_x_size = x_size;
6758 cdata->_y_size = y_size;
6759 cdata->_num_components = num_components;
6760 do_set_component_type(cdata, component_type);
6763 if (cdata->_x_size != x_size ||
6764 cdata->_y_size != y_size ||
6765 cdata->_num_components != num_components ||
6766 cdata->_component_type != component_type) {
6768 <<
"Texture properties have changed for texture " << get_name()
6769 <<
" page " << z <<
".\n";
6781 do_rescale_texture(CData *cdata) {
6782 int new_x_size = cdata->_x_size;
6783 int new_y_size = cdata->_y_size;
6784 if (cdata->_z_size * cdata->_num_views != 1) {
6785 nassert_raise(
"rescale_texture() doesn't support 3-d or multiview textures.");
6789 if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(),
false)) {
6792 if (!do_store_one(cdata, orig_image, 0, 0)) {
6794 <<
"Couldn't get image in rescale_texture()\n";
6799 <<
"Resizing " << get_name() <<
" to " << new_x_size <<
" x "
6800 << new_y_size <<
"\n";
6804 new_image.quick_filter_from(orig_image);
6806 do_clear_ram_image(cdata);
6807 cdata->inc_image_modified();
6808 cdata->_x_size = new_x_size;
6809 cdata->_y_size = new_y_size;
6810 if (!do_load_one(cdata, new_image, get_name(), 0, 0,
LoaderOptions())) {
6820 if (do_get_auto_texture_scale(cdata) == ATS_pad) {
6821 new_x_size = cdata->_x_size;
6822 new_y_size = cdata->_y_size;
6823 if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(),
true)) {
6824 pad_x_size = new_x_size - cdata->_x_size;
6825 pad_y_size = new_y_size - cdata->_y_size;
6828 if (!do_store_one(cdata, orig_image, 0, 0)) {
6830 <<
"Couldn't get image in rescale_texture()\n";
6836 new_image.copy_sub_image(orig_image, 0, new_y_size - orig_image.
get_y_size());
6838 do_clear_ram_image(cdata);
6839 cdata->_loaded_from_image =
false;
6840 cdata->inc_image_modified();
6841 if (!do_load_one(cdata, new_image, get_name(), 0, 0,
LoaderOptions())) {
6845 do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
6858 make_copy_impl()
const {
6859 CDReader cdata(_cycler);
6860 return do_make_copy(cdata);
6867 do_make_copy(
const CData *cdata)
const {
6869 CDWriter cdata_tex(tex->_cycler,
true);
6870 tex->do_assign(cdata_tex,
this, cdata);
6879 do_assign(CData *cdata,
const Texture *copy,
const CData *cdata_copy) {
6880 cdata->do_assign(cdata_copy);
6887 do_clear(CData *cdata) {
6890 CDReader cdata_tex(tex._cycler);
6891 do_assign(cdata, &tex, cdata_tex);
6893 cdata->inc_properties_modified();
6894 cdata->inc_image_modified();
6895 cdata->inc_simple_image_modified();
6902 do_setup_texture(CData *cdata, Texture::TextureType texture_type,
6903 int x_size,
int y_size,
int z_size,
6904 Texture::ComponentType component_type,
6905 Texture::Format format) {
6906 switch (texture_type) {
6908 nassertv(y_size == 1 && z_size == 1);
6912 nassertv(z_size == 1);
6918 case TT_2d_texture_array:
6923 nassertv(x_size == y_size && z_size == 6);
6928 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
6929 cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
6930 cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
6933 case TT_cube_map_array:
6935 nassertv(x_size == y_size && z_size % 6 == 0);
6937 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
6938 cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
6939 cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
6942 case TT_buffer_texture:
6943 nassertv(y_size == 1 && z_size == 1);
6946 case TT_1d_texture_array:
6947 nassertv(z_size == 1);
6951 if (texture_type != TT_2d_texture) {
6952 do_clear_simple_ram_image(cdata);
6955 cdata->_texture_type = texture_type;
6956 cdata->_x_size = x_size;
6957 cdata->_y_size = y_size;
6958 cdata->_z_size = z_size;
6959 cdata->_num_views = 1;
6960 do_set_component_type(cdata, component_type);
6961 do_set_format(cdata, format);
6963 do_clear_ram_image(cdata);
6964 do_set_pad_size(cdata, 0, 0, 0);
6965 cdata->_orig_file_x_size = 0;
6966 cdata->_orig_file_y_size = 0;
6967 cdata->_loaded_from_image =
false;
6968 cdata->_loaded_from_txo =
false;
6969 cdata->_has_read_pages =
false;
6970 cdata->_has_read_mipmaps =
false;
6977 do_set_format(CData *cdata, Texture::Format format) {
6978 if (format == cdata->_format) {
6981 cdata->_format = format;
6982 cdata->inc_properties_modified();
6984 switch (cdata->_format) {
6986 case F_depth_stencil:
6987 case F_depth_component:
6988 case F_depth_component16:
6989 case F_depth_component24:
6990 case F_depth_component32:
7002 cdata->_num_components = 1;
7005 case F_luminance_alpha:
7006 case F_luminance_alphamask:
7008 case F_sluminance_alpha:
7014 cdata->_num_components = 2;
7030 cdata->_num_components = 3;
7046 cdata->_num_components = 4;
7055 do_set_component_type(CData *cdata, Texture::ComponentType component_type) {
7056 cdata->_component_type = component_type;
7058 switch (component_type) {
7059 case T_unsigned_byte:
7061 cdata->_component_width = 1;
7064 case T_unsigned_short:
7067 cdata->_component_width = 2;
7071 case T_unsigned_int_24_8:
7073 case T_unsigned_int:
7074 cdata->_component_width = 4;
7083 do_set_x_size(CData *cdata,
int x_size) {
7084 if (cdata->_x_size != x_size) {
7085 cdata->_x_size = x_size;
7086 cdata->inc_image_modified();
7087 do_clear_ram_image(cdata);
7088 do_set_pad_size(cdata, 0, 0, 0);
7096 do_set_y_size(CData *cdata,
int y_size) {
7097 if (cdata->_y_size != y_size) {
7098 nassertv((cdata->_texture_type != Texture::TT_buffer_texture &&
7099 cdata->_texture_type != Texture::TT_1d_texture) || y_size == 1);
7100 cdata->_y_size = y_size;
7101 cdata->inc_image_modified();
7102 do_clear_ram_image(cdata);
7103 do_set_pad_size(cdata, 0, 0, 0);
7112 do_set_z_size(CData *cdata,
int z_size) {
7113 if (cdata->_z_size != z_size) {
7114 nassertv((cdata->_texture_type == Texture::TT_3d_texture) ||
7115 (cdata->_texture_type == Texture::TT_cube_map && z_size == 6) ||
7116 (cdata->_texture_type == Texture::TT_cube_map_array && z_size % 6 == 0) ||
7117 (cdata->_texture_type == Texture::TT_2d_texture_array) || (z_size == 1));
7118 cdata->_z_size = z_size;
7119 cdata->inc_image_modified();
7120 do_clear_ram_image(cdata);
7121 do_set_pad_size(cdata, 0, 0, 0);
7129 do_set_num_views(CData *cdata,
int num_views) {
7130 nassertv(num_views >= 1);
7131 if (cdata->_num_views != num_views) {
7132 cdata->_num_views = num_views;
7133 if (do_has_ram_image(cdata)) {
7134 cdata->inc_image_modified();
7135 do_clear_ram_image(cdata);
7137 do_set_pad_size(cdata, 0, 0, 0);
7145 do_set_wrap_u(CData *cdata, SamplerState::WrapMode wrap) {
7146 if (cdata->_default_sampler.get_wrap_u() != wrap) {
7147 cdata->inc_properties_modified();
7148 cdata->_default_sampler.set_wrap_u(wrap);
7156 do_set_wrap_v(CData *cdata, SamplerState::WrapMode wrap) {
7157 if (cdata->_default_sampler.get_wrap_v() != wrap) {
7158 cdata->inc_properties_modified();
7159 cdata->_default_sampler.set_wrap_v(wrap);
7167 do_set_wrap_w(CData *cdata, SamplerState::WrapMode wrap) {
7168 if (cdata->_default_sampler.get_wrap_w() != wrap) {
7169 cdata->inc_properties_modified();
7170 cdata->_default_sampler.set_wrap_w(wrap);
7178 do_set_minfilter(CData *cdata, SamplerState::FilterType filter) {
7179 if (cdata->_default_sampler.get_minfilter() != filter) {
7180 cdata->inc_properties_modified();
7181 cdata->_default_sampler.set_minfilter(filter);
7189 do_set_magfilter(CData *cdata, SamplerState::FilterType filter) {
7190 if (cdata->_default_sampler.get_magfilter() != filter) {
7191 cdata->inc_properties_modified();
7192 cdata->_default_sampler.set_magfilter(filter);
7200 do_set_anisotropic_degree(CData *cdata,
int anisotropic_degree) {
7201 if (cdata->_default_sampler.get_anisotropic_degree() != anisotropic_degree) {
7202 cdata->inc_properties_modified();
7203 cdata->_default_sampler.set_anisotropic_degree(anisotropic_degree);
7211 do_set_border_color(CData *cdata,
const LColor &color) {
7212 if (cdata->_default_sampler.get_border_color() != color) {
7213 cdata->inc_properties_modified();
7214 cdata->_default_sampler.set_border_color(color);
7222 do_set_compression(CData *cdata, Texture::CompressionMode compression) {
7223 if (cdata->_compression != compression) {
7224 cdata->inc_properties_modified();
7225 cdata->_compression = compression;
7227 if (do_has_ram_image(cdata)) {
7229 bool has_ram_image_compression = (cdata->_ram_image_compression != CM_off);
7244 do_set_quality_level(CData *cdata, Texture::QualityLevel quality_level) {
7245 if (cdata->_quality_level != quality_level) {
7246 cdata->inc_properties_modified();
7247 cdata->_quality_level = quality_level;
7255 do_has_compression(
const CData *cdata)
const {
7256 if (cdata->_compression == CM_default) {
7257 if (cdata->_texture_type != Texture::TT_buffer_texture) {
7258 return compressed_textures;
7263 return (cdata->_compression != CM_off);
7272 do_has_ram_image(
const CData *cdata)
const {
7273 return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty();
7281 do_has_uncompressed_ram_image(
const CData *cdata)
const {
7282 return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty() && cdata->_ram_image_compression == CM_off;
7289 do_get_ram_image(CData *cdata) {
7290 if (!do_has_ram_image(cdata) && do_can_reload(cdata)) {
7291 do_reload_ram_image(cdata,
true);
7293 if (do_has_ram_image(cdata)) {
7297 cdata->inc_image_modified();
7298 cdata->inc_properties_modified();
7302 if (cdata->_ram_images.empty()) {
7306 return cdata->_ram_images[0]._image;
7313 do_get_uncompressed_ram_image(CData *cdata) {
7314 if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
7317 if (do_uncompress_ram_image(cdata)) {
7318 if (gobj_cat.is_debug()) {
7320 <<
"Uncompressed " << get_name() <<
"\n";
7322 return cdata->_ram_images[0]._image;
7327 if ((!do_has_ram_image(cdata) || cdata->_ram_image_compression != CM_off) && do_can_reload(cdata)) {
7328 do_reload_ram_image(cdata,
false);
7331 if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
7333 if (do_uncompress_ram_image(cdata)) {
7335 <<
"Uncompressed " << get_name() <<
"\n";
7336 return cdata->_ram_images[0]._image;
7340 if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
7344 return cdata->_ram_images[0]._image;
7373 string format =
upcase(requested_format);
7376 CPTA_uchar data = do_get_uncompressed_ram_image(cdata);
7377 if (data ==
nullptr) {
7378 gobj_cat.error() <<
"Couldn't find an uncompressed RAM image!\n";
7381 int imgsize = cdata->_x_size * cdata->_y_size;
7382 nassertr(cdata->_num_components > 0 && cdata->_num_components <= 4,
CPTA_uchar(get_class_type()));
7383 nassertr(data.size() == (
size_t)(cdata->_component_width * cdata->_num_components * imgsize),
CPTA_uchar(get_class_type()));
7386 if ((cdata->_num_components == 1 && format.size() == 1) ||
7387 (cdata->_num_components == 2 && format.size() == 2 && format.at(1) ==
'A' && format.at(0) !=
'A') ||
7388 (cdata->_num_components == 3 && format ==
"BGR") ||
7389 (cdata->_num_components == 4 && format ==
"BGRA")) {
7397 alpha = cdata->_num_components - 1;
7401 for (
size_t i = 0; i < format.size(); ++i) {
7402 if (format[i] !=
'B' && format[i] !=
'G' && format[i] !=
'R' &&
7403 format[i] !=
'A' && format[i] !=
'0' && format[i] !=
'1') {
7404 gobj_cat.error() <<
"Unexpected component character '"
7405 << format[i] <<
"', expected one of RGBA01!\n";
7411 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * format.size() * cdata->_component_width, get_class_type());
7414 if (cdata->_component_width == 1) {
7415 if (format ==
"RGBA" && cdata->_num_components == 4) {
7416 const uint32_t *src = (
const uint32_t *)data.p();
7417 uint32_t *dst = (uint32_t *)newdata.p();
7419 for (
int p = 0; p < imgsize; ++p) {
7420 uint32_t v = *src++;
7421 *dst++ = ((v & 0xff00ff00u)) |
7422 ((v & 0x00ff0000u) >> 16) |
7423 ((v & 0x000000ffu) << 16);
7427 if (format ==
"RGB" && cdata->_num_components == 4) {
7428 const uint32_t *src = (
const uint32_t *)data.p();
7429 uint32_t *dst = (uint32_t *)newdata.p();
7433 int blocks = imgsize >> 2;
7434 for (
int i = 0; i < blocks; ++i) {
7435 uint32_t v0 = *src++;
7436 uint32_t v1 = *src++;
7437 uint32_t v2 = *src++;
7438 uint32_t v3 = *src++;
7439 *dst++ = ((v0 & 0x00ff0000u) >> 16) |
7440 ((v0 & 0x0000ff00u)) |
7441 ((v0 & 0x000000ffu) << 16) |
7442 ((v1 & 0x00ff0000u) << 8);
7443 *dst++ = ((v1 & 0x0000ff00u) >> 8) |
7444 ((v1 & 0x000000ffu) << 8) |
7445 ((v2 & 0x00ff0000u)) |
7446 ((v2 & 0x0000ff00u) << 16);
7447 *dst++ = ((v2 & 0x000000ffu)) |
7448 ((v3 & 0x00ff0000u) >> 8) |
7449 ((v3 & 0x0000ff00u) << 8) |
7450 ((v3 & 0x000000ffu) << 24);
7455 uint8_t *tail = (uint8_t *)dst;
7456 for (
int i = (imgsize & ~0x3); i < imgsize; ++i) {
7457 uint32_t v = *src++;
7458 *tail++ = (v & 0x00ff0000u) >> 16;
7459 *tail++ = (v & 0x0000ff00u) >> 8;
7460 *tail++ = (v & 0x000000ffu);
7464 if (format ==
"BGR" && cdata->_num_components == 4) {
7465 const uint32_t *src = (
const uint32_t *)data.p();
7466 uint32_t *dst = (uint32_t *)newdata.p();
7470 int blocks = imgsize >> 2;
7471 for (
int i = 0; i < blocks; ++i) {
7472 uint32_t v0 = *src++;
7473 uint32_t v1 = *src++;
7474 uint32_t v2 = *src++;
7475 uint32_t v3 = *src++;
7476 *dst++ = (v0 & 0x00ffffffu) | ((v1 & 0x000000ffu) << 24);
7477 *dst++ = ((v1 & 0x00ffff00u) >> 8) | ((v2 & 0x0000ffffu) << 16);
7478 *dst++ = ((v2 & 0x00ff0000u) >> 16) | ((v3 & 0x00ffffffu) << 8);
7483 uint8_t *tail = (uint8_t *)dst;
7484 for (
int i = (imgsize & ~0x3); i < imgsize; ++i) {
7485 uint32_t v = *src++;
7486 *tail++ = (v & 0x000000ffu);
7487 *tail++ = (v & 0x0000ff00u) >> 8;
7488 *tail++ = (v & 0x00ff0000u) >> 16;
7492 const uint8_t *src = (
const uint8_t *)data.p();
7493 uint8_t *dst = (uint8_t *)newdata.p();
7495 if (format ==
"RGB" && cdata->_num_components == 3) {
7496 for (
int i = 0; i < imgsize; ++i) {
7504 if (format ==
"A" && cdata->_num_components != 3) {
7506 for (
int p = 0; p < imgsize; ++p) {
7507 dst[p] = src[alpha];
7508 src += cdata->_num_components;
7513 for (
int p = 0; p < imgsize; ++p) {
7514 for (
size_t i = 0; i < format.size(); ++i) {
7515 if (format[i] ==
'B' || (cdata->_num_components <= 2 && format[i] !=
'A')) {
7517 }
else if (format[i] ==
'G') {
7519 }
else if (format[i] ==
'R') {
7521 }
else if (format[i] ==
'A') {
7523 *dst++ = src[alpha];
7527 }
else if (format[i] ==
'1') {
7533 src += cdata->_num_components;
7539 for (
int p = 0; p < imgsize; ++p) {
7540 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') {
7552 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), -1, cdata->_component_width);
7555 }
else if (format[i] ==
'1') {
7556 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), -1, cdata->_component_width);
7559 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), 0, cdata->_component_width);
7562 memcpy((
void*)(newdata + (p * format.size() + i) * cdata->_component_width),
7563 (
void*)(data + (p * cdata->_num_components + component) * cdata->_component_width),
7564 cdata->_component_width);
7574 do_set_simple_ram_image(CData *cdata,
CPTA_uchar image,
int x_size,
int y_size) {
7575 nassertv(cdata->_texture_type == TT_2d_texture);
7576 size_t expected_page_size = (size_t)(x_size * y_size * 4);
7577 nassertv(image.size() == expected_page_size);
7579 cdata->_simple_x_size = x_size;
7580 cdata->_simple_y_size = y_size;
7582 cdata->_simple_ram_image._page_size = image.size();
7583 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
7584 cdata->inc_simple_image_modified();
7591 do_get_expected_num_mipmap_levels(
const CData *cdata)
const {
7592 if (cdata->_texture_type == Texture::TT_buffer_texture) {
7595 int size = max(cdata->_x_size, cdata->_y_size);
7596 if (cdata->_texture_type == Texture::TT_3d_texture) {
7597 size = max(size, cdata->_z_size);
7611 do_get_ram_mipmap_page_size(
const CData *cdata,
int n)
const {
7612 if (cdata->_ram_image_compression != CM_off) {
7613 if (n >= 0 && n < (
int)cdata->_ram_images.size()) {
7614 return cdata->_ram_images[n]._page_size;
7618 return do_get_expected_ram_mipmap_page_size(cdata, n);
7626 do_get_expected_mipmap_x_size(
const CData *cdata,
int n)
const {
7627 int size = max(cdata->_x_size, 1);
7628 while (n > 0 && size > 1) {
7639 do_get_expected_mipmap_y_size(
const CData *cdata,
int n)
const {
7640 int size = max(cdata->_y_size, 1);
7641 while (n > 0 && size > 1) {
7652 do_get_expected_mipmap_z_size(
const CData *cdata,
int n)
const {
7656 if (cdata->_texture_type == Texture::TT_3d_texture) {
7657 int size = max(cdata->_z_size, 1);
7658 while (n > 0 && size > 1) {
7665 return cdata->_z_size;
7673 do_clear_simple_ram_image(CData *cdata) {
7674 cdata->_simple_x_size = 0;
7675 cdata->_simple_y_size = 0;
7676 cdata->_simple_ram_image._image.clear();
7677 cdata->_simple_ram_image._page_size = 0;
7678 cdata->_simple_image_date_generated = 0;
7683 cdata->inc_simple_image_modified();
7690 do_clear_ram_mipmap_images(CData *cdata) {
7691 if (!cdata->_ram_images.empty()) {
7692 cdata->_ram_images.erase(cdata->_ram_images.begin() + 1, cdata->_ram_images.end());
7702 do_generate_ram_mipmap_images(CData *cdata,
bool allow_recompress) {
7703 nassertv(do_has_ram_image(cdata));
7705 if (do_get_expected_num_mipmap_levels(cdata) == 1) {
7710 RamImage orig_compressed_image;
7711 CompressionMode orig_compression_mode = CM_off;
7713 if (cdata->_ram_image_compression != CM_off) {
7717 orig_compressed_image = cdata->_ram_images[0];
7718 orig_compression_mode = cdata->_ram_image_compression;
7721 do_get_uncompressed_ram_image(cdata);
7723 if (cdata->_ram_image_compression != CM_off) {
7725 <<
"Cannot generate mipmap levels for image with compression "
7726 << cdata->_ram_image_compression <<
"\n";
7731 do_clear_ram_mipmap_images(cdata);
7733 if (gobj_cat.is_debug()) {
7735 <<
"Generating mipmap levels for " << *
this <<
"\n";
7738 if (cdata->_texture_type == Texture::TT_3d_texture && cdata->_z_size != 1) {
7740 int x_size = cdata->_x_size;
7741 int y_size = cdata->_y_size;
7742 int z_size = cdata->_z_size;
7744 while (x_size > 1 || y_size > 1 || z_size > 1) {
7745 cdata->_ram_images.push_back(RamImage());
7746 do_filter_3d_mipmap_level(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
7747 x_size, y_size, z_size);
7748 x_size = max(x_size >> 1, 1);
7749 y_size = max(y_size >> 1, 1);
7750 z_size = max(z_size >> 1, 1);
7756 int x_size = cdata->_x_size;
7757 int y_size = cdata->_y_size;
7759 while (x_size > 1 || y_size > 1) {
7760 cdata->_ram_images.push_back(RamImage());
7761 do_filter_2d_mipmap_pages(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
7763 x_size = max(x_size >> 1, 1);
7764 y_size = max(y_size >> 1, 1);
7769 if (orig_compression_mode != CM_off && allow_recompress) {
7775 nassertv(cdata->_ram_images.size() > 1);
7776 int l0_x_size = cdata->_x_size;
7777 int l0_y_size = cdata->_y_size;
7778 int l0_z_size = cdata->_z_size;
7779 cdata->_x_size = do_get_expected_mipmap_x_size(cdata, 1);
7780 cdata->_y_size = do_get_expected_mipmap_y_size(cdata, 1);
7781 cdata->_z_size = do_get_expected_mipmap_z_size(cdata, 1);
7782 RamImage uncompressed_image = cdata->_ram_images[0];
7783 cdata->_ram_images.erase(cdata->_ram_images.begin());
7785 bool success = do_compress_ram_image(cdata, orig_compression_mode, QL_default,
nullptr);
7788 if (gobj_cat.is_debug()) {
7790 <<
"Compressed " << get_name() <<
" generated mipmaps with "
7791 << cdata->_ram_image_compression <<
"\n";
7793 cdata->_ram_images.insert(cdata->_ram_images.begin(), orig_compressed_image);
7795 cdata->_ram_images.insert(cdata->_ram_images.begin(), uncompressed_image);
7797 cdata->_x_size = l0_x_size;
7798 cdata->_y_size = l0_y_size;
7799 cdata->_z_size = l0_z_size;
7807 do_set_pad_size(CData *cdata,
int x,
int y,
int z) {
7808 if (x > cdata->_x_size) {
7811 if (y > cdata->_y_size) {
7814 if (z > cdata->_z_size) {
7818 cdata->_pad_x_size = x;
7819 cdata->_pad_y_size = y;
7820 cdata->_pad_z_size = z;
7829 do_can_reload(
const CData *cdata)
const {
7830 return (cdata->_loaded_from_image && !cdata->_fullpath.empty());
7837 do_reload(CData *cdata) {
7838 if (do_can_reload(cdata)) {
7839 do_clear_ram_image(cdata);
7840 do_reload_ram_image(cdata,
true);
7841 if (do_has_ram_image(cdata)) {
7843 cdata->inc_image_modified();
7859 do_has_bam_rawdata(
const CData *cdata)
const {
7860 return do_has_ram_image(cdata);
7868 do_get_bam_rawdata(CData *cdata) {
7869 do_get_ram_image(cdata);
7877 convert_from_pnmimage(PTA_uchar &image,
size_t page_size,
7878 int row_stride,
int x,
int y,
int z,
7879 const PNMImage &pnmimage,
int num_components,
7880 int component_width) {
7884 int pixel_size = num_components * component_width;
7887 if (row_stride == 0) {
7888 row_stride = x_size;
7890 row_skip = (row_stride - x_size) * pixel_size;
7891 nassertv(row_skip >= 0);
7894 bool is_grayscale = (num_components == 1 || num_components == 2);
7895 bool has_alpha = (num_components == 2 || num_components == 4);
7896 bool img_has_alpha = pnmimage.
has_alpha();
7898 int idx = page_size * z;
7899 nassertv(idx + page_size <= image.size());
7900 unsigned char *p = &image[idx];
7902 if (x != 0 || y != 0) {
7903 p += (row_stride * y + x) * pixel_size;
7906 if (maxval == 255 && component_width == 1) {
7911 switch (num_components) {
7913 for (
int j = y_size-1; j >= 0; j--) {
7914 const xel *row = array + j * x_size;
7915 for (
int i = 0; i < x_size; i++) {
7916 *p++ = (uchar)PPM_GETB(row[i]);
7923 if (img_has_alpha) {
7925 for (
int j = y_size-1; j >= 0; j--) {
7926 const xel *row = array + j * x_size;
7927 const xelval *alpha_row = alpha + j * x_size;
7928 for (
int i = 0; i < x_size; i++) {
7929 *p++ = (uchar)PPM_GETB(row[i]);
7930 *p++ = (uchar)alpha_row[i];
7935 for (
int j = y_size-1; j >= 0; j--) {
7936 const xel *row = array + j * x_size;
7937 for (
int i = 0; i < x_size; i++) {
7938 *p++ = (uchar)PPM_GETB(row[i]);
7947 for (
int j = y_size-1; j >= 0; j--) {
7948 const xel *row = array + j * x_size;
7949 for (
int i = 0; i < x_size; i++) {
7950 *p++ = (uchar)PPM_GETB(row[i]);
7951 *p++ = (uchar)PPM_GETG(row[i]);
7952 *p++ = (uchar)PPM_GETR(row[i]);
7959 if (img_has_alpha) {
7961 for (
int j = y_size-1; j >= 0; j--) {
7962 const xel *row = array + j * x_size;
7963 const xelval *alpha_row = alpha + j * x_size;
7964 for (
int i = 0; i < x_size; i++) {
7965 *p++ = (uchar)PPM_GETB(row[i]);
7966 *p++ = (uchar)PPM_GETG(row[i]);
7967 *p++ = (uchar)PPM_GETR(row[i]);
7968 *p++ = (uchar)alpha_row[i];
7973 for (
int j = y_size-1; j >= 0; j--) {
7974 const xel *row = array + j * x_size;
7975 for (
int i = 0; i < x_size; i++) {
7976 *p++ = (uchar)PPM_GETB(row[i]);
7977 *p++ = (uchar)PPM_GETG(row[i]);
7978 *p++ = (uchar)PPM_GETR(row[i]);
7987 nassertv(num_components >= 1 && num_components <= 4);
7991 }
else if (maxval == 65535 && component_width == 2) {
7994 for (
int j = y_size-1; j >= 0; j--) {
7995 for (
int i = 0; i < x_size; i++) {
8001 store_unscaled_short(p, pnmimage.
get_red_val(i, j));
8004 if (img_has_alpha) {
8007 store_unscaled_short(p, 65535);
8014 }
else if (component_width == 1) {
8018 double scale = 255.0 / (double)maxval;
8020 for (
int j = y_size-1; j >= 0; j--) {
8021 for (
int i = 0; i < x_size; i++) {
8023 store_scaled_byte(p, pnmimage.
get_gray_val(i, j), scale);
8025 store_scaled_byte(p, pnmimage.
get_blue_val(i, j), scale);
8027 store_scaled_byte(p, pnmimage.
get_red_val(i, j), scale);
8030 if (img_has_alpha) {
8033 store_unscaled_byte(p, 255);
8043 double scale = 65535.0 / (double)maxval;
8045 for (
int j = y_size-1; j >= 0; j--) {
8046 for (
int i = 0; i < x_size; i++) {
8048 store_scaled_short(p, pnmimage.
get_gray_val(i, j), scale);
8050 store_scaled_short(p, pnmimage.
get_blue_val(i, j), scale);
8052 store_scaled_short(p, pnmimage.
get_red_val(i, j), scale);
8055 if (img_has_alpha) {
8058 store_unscaled_short(p, 65535);
8072 convert_from_pfm(PTA_uchar &image,
size_t page_size,
int z,
8073 const PfmFile &pfm,
int num_components,
int component_width) {
8074 nassertv(component_width == 4);
8078 int idx = page_size * z;
8079 nassertv(idx + page_size <= image.size());
8080 PN_float32 *p = (PN_float32 *)&image[idx];
8082 switch (num_components) {
8085 for (
int j = y_size-1; j >= 0; j--) {
8086 for (
int i = 0; i < x_size; i++) {
8096 for (
int j = y_size-1; j >= 0; j--) {
8097 for (
int i = 0; i < x_size; i++) {
8109 for (
int j = y_size-1; j >= 0; j--) {
8110 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 nassert_raise(
"unexpected channel count");
8140 nassertv((
unsigned char *)p == &image[idx] + page_size);
8148 convert_to_pnmimage(
PNMImage &pnmimage,
int x_size,
int y_size,
8149 int num_components, ComponentType component_type,
8150 bool is_srgb,
CPTA_uchar image,
size_t page_size,
int z) {
8151 xelval maxval = 0xff;
8152 if (component_type != T_unsigned_byte && component_type != T_byte) {
8155 ColorSpace color_space =
is_srgb ? CS_sRGB : CS_linear;
8156 pnmimage.
clear(x_size, y_size, num_components, maxval,
nullptr, color_space);
8160 int idx = page_size * z;
8161 nassertr(idx + page_size <= image.size(),
false);
8166 switch (component_type) {
8167 case T_unsigned_byte:
8169 const unsigned char *p = &image[idx];
8171 for (
int j = y_size-1; j >= 0; j--) {
8172 xel *row = array + j * x_size;
8173 xelval *alpha_row = alpha + j * x_size;
8174 for (
int i = 0; i < x_size; i++) {
8175 PPM_PUTB(row[i], *p++);
8176 alpha_row[i] = *p++;
8180 for (
int j = y_size-1; j >= 0; j--) {
8181 xel *row = array + j * x_size;
8182 for (
int i = 0; i < x_size; i++) {
8183 PPM_PUTB(row[i], *p++);
8187 nassertr(p == &image[idx] + page_size,
false);
8189 const unsigned char *p = &image[idx];
8191 for (
int j = y_size-1; j >= 0; j--) {
8192 xel *row = array + j * x_size;
8193 xelval *alpha_row = alpha + j * x_size;
8194 for (
int i = 0; i < x_size; i++) {
8195 PPM_PUTB(row[i], *p++);
8196 PPM_PUTG(row[i], *p++);
8197 PPM_PUTR(row[i], *p++);
8198 alpha_row[i] = *p++;
8202 for (
int j = y_size-1; j >= 0; j--) {
8203 xel *row = array + j * x_size;
8204 for (
int i = 0; i < x_size; i++) {
8205 PPM_PUTB(row[i], *p++);
8206 PPM_PUTG(row[i], *p++);
8207 PPM_PUTR(row[i], *p++);
8211 nassertr(p == &image[idx] + page_size,
false);
8215 case T_unsigned_short:
8217 const uint16_t *p = (
const uint16_t *)&image[idx];
8219 for (
int j = y_size-1; j >= 0; j--) {
8220 xel *row = array + j * x_size;
8221 xelval *alpha_row = alpha + j * x_size;
8222 for (
int i = 0; i < x_size; i++) {
8223 PPM_PUTB(row[i], *p++);
8224 if (!is_grayscale) {
8225 PPM_PUTG(row[i], *p++);
8226 PPM_PUTR(row[i], *p++);
8229 alpha_row[i] = *p++;
8233 nassertr((
const unsigned char *)p == &image[idx] + page_size,
false);
8237 case T_unsigned_int:
8239 const uint32_t *p = (
const uint32_t *)&image[idx];
8241 for (
int j = y_size-1; j >= 0; j--) {
8242 xel *row = array + j * x_size;
8243 xelval *alpha_row = alpha + j * x_size;
8244 for (
int i = 0; i < x_size; i++) {
8245 PPM_PUTB(row[i], (*p++) >> 16u);
8246 if (!is_grayscale) {
8247 PPM_PUTG(row[i], (*p++) >> 16u);
8248 PPM_PUTR(row[i], (*p++) >> 16u);
8251 alpha_row[i] = (*p++) >> 16u;
8255 nassertr((
const unsigned char *)p == &image[idx] + page_size,
false);
8261 const unsigned char *p = &image[idx];
8263 for (
int j = y_size-1; j >= 0; j--) {
8264 for (
int i = 0; i < x_size; i++) {
8265 pnmimage.
set_blue(i, j, get_half_float(p));
8266 if (!is_grayscale) {
8267 pnmimage.
set_green(i, j, get_half_float(p));
8268 pnmimage.
set_red(i, j, get_half_float(p));
8271 pnmimage.
set_alpha(i, j, get_half_float(p));
8275 nassertr(p == &image[idx] + page_size,
false);
8291 convert_to_pfm(
PfmFile &pfm,
int x_size,
int y_size,
8292 int num_components,
int component_width,
8294 nassertr(component_width == 4,
false);
8295 pfm.
clear(x_size, y_size, num_components);
8297 int idx = page_size * z;
8298 nassertr(idx + page_size <= image.size(),
false);
8299 const PN_float32 *p = (
const PN_float32 *)&image[idx];
8301 switch (num_components) {
8303 for (
int j = y_size-1; j >= 0; j--) {
8304 for (
int i = 0; i < x_size; i++) {
8312 for (
int j = y_size-1; j >= 0; j--) {
8313 for (
int i = 0; i < x_size; i++) {
8323 for (
int j = y_size-1; j >= 0; j--) {
8324 for (
int i = 0; i < x_size; i++) {
8335 for (
int j = y_size-1; j >= 0; j--) {
8336 for (
int i = 0; i < x_size; i++) {
8347 nassert_raise(
"unexpected channel count");
8351 nassertr((
unsigned char *)p == &image[idx] + page_size,
false);
8359 read_dds_level_bgr8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8361 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8362 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8364 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8365 size_t row_bytes = x_size * 3;
8366 PTA_uchar image = PTA_uchar::empty_array(size);
8367 for (
int y = y_size - 1; y >= 0; --y) {
8368 unsigned char *p = image.p() + y * row_bytes;
8369 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8370 in.read((
char *)p, row_bytes);
8380 read_dds_level_rgb8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8382 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8383 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8385 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8386 size_t row_bytes = x_size * 3;
8387 PTA_uchar image = PTA_uchar::empty_array(size);
8388 for (
int y = y_size - 1; y >= 0; --y) {
8389 unsigned char *p = image.p() + y * row_bytes;
8390 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8391 in.read((
char *)p, row_bytes);
8394 for (
int x = 0; x < x_size; ++x) {
8395 unsigned char r = p[0];
8400 nassertr(p <= image.p() + size, PTA_uchar());
8410 read_dds_level_abgr8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8412 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8413 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8415 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8416 size_t row_bytes = x_size * 4;
8417 PTA_uchar image = PTA_uchar::empty_array(size);
8418 for (
int y = y_size - 1; y >= 0; --y) {
8419 unsigned char *p = image.p() + y * row_bytes;
8420 in.read((
char *)p, row_bytes);
8422 uint32_t *pw = (uint32_t *)p;
8423 for (
int x = 0; x < x_size; ++x) {
8425 #ifdef WORDS_BIGENDIAN
8427 w = ((w & 0xff00) << 16) | ((w & 0xff000000U) >> 16) | (w & 0xff00ff);
8430 w = ((w & 0xff) << 16) | ((w & 0xff0000) >> 16) | (w & 0xff00ff00U);
8435 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8445 read_dds_level_rgba8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8447 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8448 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8450 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8451 size_t row_bytes = x_size * 4;
8452 PTA_uchar image = PTA_uchar::empty_array(size);
8453 for (
int y = y_size - 1; y >= 0; --y) {
8454 unsigned char *p = image.p() + y * row_bytes;
8455 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8456 in.read((
char *)p, row_bytes);
8466 read_dds_level_abgr16(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8468 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8469 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8471 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8472 size_t row_bytes = x_size * 8;
8473 PTA_uchar image = PTA_uchar::empty_array(size);
8474 for (
int y = y_size - 1; y >= 0; --y) {
8475 unsigned char *p = image.p() + y * row_bytes;
8476 in.read((
char *)p, row_bytes);
8478 uint16_t *pw = (uint16_t *)p;
8479 for (
int x = 0; x < x_size; ++x) {
8483 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8493 read_dds_level_abgr32(
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 * 16;
8500 nassertr(row_bytes * y_size == size, PTA_uchar());
8501 PTA_uchar image = PTA_uchar::empty_array(size);
8502 for (
int y = y_size - 1; y >= 0; --y) {
8503 unsigned char *p = image.p() + y * row_bytes;
8504 in.read((
char *)p, row_bytes);
8506 uint32_t *pw = (uint32_t *)p;
8507 for (
int x = 0; x < x_size; ++x) {
8511 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8521 read_dds_level_raw(
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 * cdata->_num_components * cdata->_component_width;
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);
8542 read_dds_level_generic_uncompressed(
Texture *tex, CData *cdata,
const DDSHeader &header,
8543 int n, istream &in) {
8544 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8545 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8547 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
8554 pitch = ((pitch + 3) / 4) * 4;
8555 if (header.dds_flags & DDSD_PITCH) {
8556 pitch = header.pitch;
8560 int bpp = header.pf.rgb_bitcount / 8;
8561 int skip_bytes = pitch - (bpp * x_size);
8562 nassertr(skip_bytes >= 0, PTA_uchar());
8564 unsigned int r_mask = header.pf.r_mask;
8565 unsigned int g_mask = header.pf.g_mask;
8566 unsigned int b_mask = header.pf.b_mask;
8567 unsigned int a_mask = header.pf.a_mask;
8578 unsigned int r_scale = 0;
8580 r_scale = 0xff000000 / (r_mask >> r_shift);
8582 unsigned int g_scale = 0;
8584 g_scale = 0xff000000 / (g_mask >> g_shift);
8586 unsigned int b_scale = 0;
8588 b_scale = 0xff000000 / (b_mask >> b_shift);
8590 unsigned int a_scale = 0;
8592 a_scale = 0xff000000 / (a_mask >> a_shift);
8595 bool add_alpha =
has_alpha(cdata->_format);
8597 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8598 size_t row_bytes = x_size * cdata->_num_components;
8599 PTA_uchar image = PTA_uchar::empty_array(size);
8600 for (
int y = y_size - 1; y >= 0; --y) {
8601 unsigned char *p = image.p() + y * row_bytes;
8602 for (
int x = 0; x < x_size; ++x) {
8605 unsigned int pixel = 0;
8607 for (
int bi = 0; bi < bpp; ++bi) {
8608 unsigned int ch = (
unsigned char)in.get();
8609 pixel |= (ch << shift);
8614 unsigned int r = (((
pixel & r_mask) >> r_shift) * r_scale) >> 24;
8615 unsigned int g = (((
pixel & g_mask) >> g_shift) * g_scale) >> 24;
8616 unsigned int b = (((
pixel & b_mask) >> b_shift) * b_scale) >> 24;
8619 store_unscaled_byte(p, b);
8620 store_unscaled_byte(p, g);
8621 store_unscaled_byte(p, r);
8623 unsigned int a = (((
pixel & a_mask) >> a_shift) * a_scale) >> 24;
8624 store_unscaled_byte(p, a);
8627 nassertr(p <= image.p() + size, PTA_uchar());
8628 for (
int bi = 0; bi < skip_bytes; ++bi) {
8641 read_dds_level_luminance_uncompressed(
Texture *tex, CData *cdata,
const DDSHeader &header,
8642 int n, istream &in) {
8643 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8644 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8646 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
8653 pitch = ((pitch + 3) / 4) * 4;
8654 if (header.dds_flags & DDSD_PITCH) {
8655 pitch = header.pitch;
8659 int bpp = header.pf.rgb_bitcount / 8;
8660 int skip_bytes = pitch - (bpp * x_size);
8661 nassertr(skip_bytes >= 0, PTA_uchar());
8663 unsigned int r_mask = header.pf.r_mask;
8664 unsigned int a_mask = header.pf.a_mask;
8673 unsigned int r_scale = 0;
8675 r_scale = 0xff000000 / (r_mask >> r_shift);
8677 unsigned int a_scale = 0;
8679 a_scale = 0xff000000 / (a_mask >> a_shift);
8682 bool add_alpha =
has_alpha(cdata->_format);
8684 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8685 size_t row_bytes = x_size * cdata->_num_components;
8686 PTA_uchar image = PTA_uchar::empty_array(size);
8687 for (
int y = y_size - 1; y >= 0; --y) {
8688 unsigned char *p = image.p() + y * row_bytes;
8689 for (
int x = 0; x < x_size; ++x) {
8692 unsigned int pixel = 0;
8694 for (
int bi = 0; bi < bpp; ++bi) {
8695 unsigned int ch = (
unsigned char)in.get();
8696 pixel |= (ch << shift);
8700 unsigned int r = (((
pixel & r_mask) >> r_shift) * r_scale) >> 24;
8703 store_unscaled_byte(p, r);
8705 unsigned int a = (((
pixel & a_mask) >> a_shift) * a_scale) >> 24;
8706 store_unscaled_byte(p, a);
8709 nassertr(p <= image.p() + size, PTA_uchar());
8710 for (
int bi = 0; bi < skip_bytes; ++bi) {
8722 read_dds_level_bc1(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8723 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8724 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8726 static const int div = 4;
8727 static const int block_bytes = 8;
8731 int num_cols = max(div, x_size) / div;
8732 int num_rows = max(div, y_size) / div;
8733 int row_length = num_cols * block_bytes;
8734 int linear_size = row_length * num_rows;
8737 if (header.dds_flags & DDSD_LINEARSIZE) {
8738 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8742 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8748 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8749 unsigned char *p = image.p() + row_length * ri;
8750 in.read((
char *)p, row_length);
8752 for (
int ci = 0; ci < num_cols; ++ci) {
8755 uint32_t *cells = (uint32_t *)p;
8756 uint32_t w = cells[1];
8757 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8764 }
else if (y_size >= 2) {
8766 unsigned char *p = image.p();
8767 in.read((
char *)p, row_length);
8769 for (
int ci = 0; ci < num_cols; ++ci) {
8770 uint32_t *cells = (uint32_t *)p;
8771 uint32_t w = cells[1];
8772 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8778 }
else if (y_size >= 1) {
8780 unsigned char *p = image.p();
8781 in.read((
char *)p, row_length);
8791 read_dds_level_bc2(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8792 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8793 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8795 static const int div = 4;
8796 static const int block_bytes = 16;
8801 int num_cols = max(div, x_size) / div;
8802 int num_rows = max(div, y_size) / div;
8803 int row_length = num_cols * block_bytes;
8804 int linear_size = row_length * num_rows;
8807 if (header.dds_flags & DDSD_LINEARSIZE) {
8808 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8812 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8818 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8819 unsigned char *p = image.p() + row_length * ri;
8820 in.read((
char *)p, row_length);
8822 for (
int ci = 0; ci < num_cols; ++ci) {
8825 uint32_t *cells = (uint32_t *)p;
8828 uint32_t w0 = cells[0];
8829 uint32_t w1 = cells[1];
8830 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8831 w1 = ((w1 & 0xffff) << 16) | ((w1 & 0xffff0000U) >> 16);
8837 uint32_t w = cells[3];
8838 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8845 }
else if (y_size >= 2) {
8847 unsigned char *p = image.p();
8848 in.read((
char *)p, row_length);
8850 for (
int ci = 0; ci < num_cols; ++ci) {
8851 uint32_t *cells = (uint32_t *)p;
8853 uint32_t w0 = cells[0];
8854 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8857 uint32_t w = cells[3];
8858 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8864 }
else if (y_size >= 1) {
8866 unsigned char *p = image.p();
8867 in.read((
char *)p, row_length);
8877 read_dds_level_bc3(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8878 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8879 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8881 static const int div = 4;
8882 static const int block_bytes = 16;
8887 int num_cols = max(div, x_size) / div;
8888 int num_rows = max(div, y_size) / div;
8889 int row_length = num_cols * block_bytes;
8890 int linear_size = row_length * num_rows;
8893 if (header.dds_flags & DDSD_LINEARSIZE) {
8894 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8898 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8904 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8905 unsigned char *p = image.p() + row_length * ri;
8906 in.read((
char *)p, row_length);
8908 for (
int ci = 0; ci < num_cols; ++ci) {
8911 uint32_t *cells = (uint32_t *)p;
8915 unsigned char p2 = p[2];
8916 unsigned char p3 = p[3];
8917 unsigned char p4 = p[4];
8918 unsigned char p5 = p[5];
8919 unsigned char p6 = p[6];
8920 unsigned char p7 = p[7];
8922 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
8923 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
8924 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
8925 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
8926 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
8927 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
8931 uint32_t w = cells[3];
8932 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8939 }
else if (y_size >= 2) {
8941 unsigned char *p = image.p();
8942 in.read((
char *)p, row_length);
8944 for (
int ci = 0; ci < num_cols; ++ci) {
8945 uint32_t *cells = (uint32_t *)p;
8947 unsigned char p2 = p[2];
8948 unsigned char p3 = p[3];
8949 unsigned char p4 = p[4];
8951 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
8952 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
8953 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
8955 uint32_t w0 = cells[0];
8956 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8959 uint32_t w = cells[3];
8960 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8966 }
else if (y_size >= 1) {
8968 unsigned char *p = image.p();
8969 in.read((
char *)p, row_length);
8979 read_dds_level_bc4(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8980 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8981 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8983 static const int div = 4;
8984 static const int block_bytes = 8;
8988 int num_cols = max(div, x_size) / div;
8989 int num_rows = max(div, y_size) / div;
8990 int row_length = num_cols * block_bytes;
8991 int linear_size = row_length * num_rows;
8994 if (header.dds_flags & DDSD_LINEARSIZE) {
8995 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8999 PTA_uchar image = PTA_uchar::empty_array(linear_size);
9005 for (
int ri = num_rows - 1; ri >= 0; --ri) {
9006 unsigned char *p = image.p() + row_length * ri;
9007 in.read((
char *)p, row_length);
9009 for (
int ci = 0; ci < num_cols; ++ci) {
9014 unsigned char p2 = p[2];
9015 unsigned char p3 = p[3];
9016 unsigned char p4 = p[4];
9017 unsigned char p5 = p[5];
9018 unsigned char p6 = p[6];
9019 unsigned char p7 = p[7];
9021 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
9022 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
9023 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
9024 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9025 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9026 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9032 }
else if (y_size >= 2) {
9034 unsigned char *p = image.p();
9035 in.read((
char *)p, row_length);
9037 for (
int ci = 0; ci < num_cols; ++ci) {
9038 unsigned char p2 = p[2];
9039 unsigned char p3 = p[3];
9040 unsigned char p4 = p[4];
9042 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9043 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9044 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9049 }
else if (y_size >= 1) {
9051 unsigned char *p = image.p();
9052 in.read((
char *)p, row_length);
9062 read_dds_level_bc5(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
9063 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
9064 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
9068 int num_cols = max(4, x_size) / 2;
9069 int num_rows = max(4, y_size) / 4;
9070 int row_length = num_cols * 8;
9071 int linear_size = row_length * num_rows;
9074 if (header.dds_flags & DDSD_LINEARSIZE) {
9075 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
9079 PTA_uchar image = PTA_uchar::empty_array(linear_size);
9085 for (
int ri = num_rows - 1; ri >= 0; --ri) {
9086 unsigned char *p = image.p() + row_length * ri;
9087 in.read((
char *)p, row_length);
9089 for (
int ci = 0; ci < num_cols; ++ci) {
9094 unsigned char p2 = p[2];
9095 unsigned char p3 = p[3];
9096 unsigned char p4 = p[4];
9097 unsigned char p5 = p[5];
9098 unsigned char p6 = p[6];
9099 unsigned char p7 = p[7];
9101 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
9102 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
9103 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
9104 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9105 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9106 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9112 }
else if (y_size >= 2) {
9114 unsigned char *p = image.p();
9115 in.read((
char *)p, row_length);
9117 for (
int ci = 0; ci < num_cols; ++ci) {
9118 unsigned char p2 = p[2];
9119 unsigned char p3 = p[3];
9120 unsigned char p4 = p[4];
9122 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9123 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9124 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9129 }
else if (y_size >= 1) {
9131 unsigned char *p = image.p();
9132 in.read((
char *)p, row_length);
9146 PreparedViews::iterator pvi;
9147 pvi = _prepared_views.find(prepared_objects);
9148 if (pvi != _prepared_views.end()) {
9149 Contexts &contexts = (*pvi).second;
9150 Contexts::iterator ci;
9151 ci = contexts.find(view);
9152 if (ci != contexts.end()) {
9156 if (contexts.empty()) {
9157 _prepared_views.erase(pvi);
9167 consider_downgrade(
PNMImage &pnmimage,
int num_channels,
const string &name) {
9176 <<
"Downgrading " << name <<
" from "
9178 << num_channels <<
".\n";
9203 for (
int yi = 0; yi < a.
get_y_size(); ++yi) {
9204 const xel *a_row = a_array + yi * x_size;
9205 const xel *b_row = b_array + yi * x_size;
9206 const xelval *a_alpha_row = a_alpha + yi * x_size;
9207 const xelval *b_alpha_row = b_alpha + yi * x_size;
9208 for (
int xi = 0; xi < x_size; ++xi) {
9209 delta += abs(PPM_GETR(a_row[xi]) - PPM_GETR(b_row[xi]));
9210 delta += abs(PPM_GETG(a_row[xi]) - PPM_GETG(b_row[xi]));
9211 delta += abs(PPM_GETB(a_row[xi]) - PPM_GETB(b_row[xi]));
9212 delta += abs(a_alpha_row[xi] - b_alpha_row[xi]);
9217 return (average_delta <= simple_image_threshold);
9230 do_filter_2d_mipmap_pages(
const CData *cdata,
9231 Texture::RamImage &to,
const Texture::RamImage &from,
9232 int x_size,
int y_size)
const {
9233 Filter2DComponent *filter_component;
9234 Filter2DComponent *filter_alpha;
9236 if (
is_srgb(cdata->_format)) {
9239 nassertv(cdata->_component_type == T_unsigned_byte);
9241 if (has_sse2_sRGB_encode()) {
9242 filter_component = &filter_2d_unsigned_byte_srgb_sse2;
9244 filter_component = &filter_2d_unsigned_byte_srgb;
9248 filter_alpha = &filter_2d_unsigned_byte;
9251 switch (cdata->_component_type) {
9252 case T_unsigned_byte:
9253 filter_component = &filter_2d_unsigned_byte;
9256 case T_unsigned_short:
9257 filter_component = &filter_2d_unsigned_short;
9261 filter_component = &filter_2d_float;
9266 <<
"Unable to generate mipmaps for 2D texture with component type "
9267 << cdata->_component_type <<
"!";
9270 filter_alpha = filter_component;
9273 size_t pixel_size = cdata->_num_components * cdata->_component_width;
9274 size_t row_size = (size_t)x_size * pixel_size;
9276 int to_x_size = max(x_size >> 1, 1);
9277 int to_y_size = max(y_size >> 1, 1);
9279 size_t to_row_size = (size_t)to_x_size * pixel_size;
9280 to._page_size = (size_t)to_y_size * to_row_size;
9281 to._image = PTA_uchar::empty_array(to._page_size * cdata->_z_size * cdata->_num_views, get_class_type());
9284 int num_color_components = cdata->_num_components;
9286 --num_color_components;
9289 int num_pages = cdata->_z_size * cdata->_num_views;
9290 for (
int z = 0; z < num_pages; ++z) {
9292 unsigned char *p = to._image.p() + z * to._page_size;
9293 nassertv(p <= to._image.p() + to._image.size() + to._page_size);
9294 const unsigned char *q = from._image.p() + z * from._page_size;
9295 nassertv(q <= from._image.p() + from._image.size() + from._page_size);
9298 for (y = 0; y < y_size - 1; y += 2) {
9300 nassertv(p == to._image.p() + z * to._page_size + (y / 2) * to_row_size);
9301 nassertv(q == from._image.p() + z * from._page_size + y * row_size);
9304 for (x = 0; x < x_size - 1; x += 2) {
9306 for (
int c = 0; c < num_color_components; ++c) {
9308 filter_component(p, q, pixel_size, row_size);
9311 filter_alpha(p, q, pixel_size, row_size);
9321 for (
int c = 0; c < num_color_components; ++c) {
9323 filter_component(p, q, 0, row_size);
9326 filter_alpha(p, q, 0, row_size);
9340 for (x = 0; x < x_size - 1; x += 2) {
9342 for (
int c = 0; c < num_color_components; ++c) {
9344 filter_component(p, q, pixel_size, 0);
9347 filter_alpha(p, q, pixel_size, 0);
9357 for (
int c = 0; c < num_color_components; ++c) {
9359 filter_component(p, q, 0, 0);
9362 filter_alpha(p, q, pixel_size, 0);
9367 nassertv(p == to._image.p() + (z + 1) * to._page_size);
9368 nassertv(q == from._image.p() + (z + 1) * from._page_size);
9382 do_filter_3d_mipmap_level(
const CData *cdata,
9383 Texture::RamImage &to,
const Texture::RamImage &from,
9384 int x_size,
int y_size,
int z_size)
const {
9385 Filter3DComponent *filter_component;
9386 Filter3DComponent *filter_alpha;
9388 if (
is_srgb(cdata->_format)) {
9391 nassertv(cdata->_component_type == T_unsigned_byte);
9393 if (has_sse2_sRGB_encode()) {
9394 filter_component = &filter_3d_unsigned_byte_srgb_sse2;
9396 filter_component = &filter_3d_unsigned_byte_srgb;
9400 filter_alpha = &filter_3d_unsigned_byte;
9403 switch (cdata->_component_type) {
9404 case T_unsigned_byte:
9405 filter_component = &filter_3d_unsigned_byte;
9408 case T_unsigned_short:
9409 filter_component = &filter_3d_unsigned_short;
9413 filter_component = &filter_3d_float;
9418 <<
"Unable to generate mipmaps for 3D texture with component type "
9419 << cdata->_component_type <<
"!";
9422 filter_alpha = filter_component;
9425 size_t pixel_size = cdata->_num_components * cdata->_component_width;
9426 size_t row_size = (size_t)x_size * pixel_size;
9427 size_t page_size = (size_t)y_size * row_size;
9428 size_t view_size = (size_t)z_size * page_size;
9430 int to_x_size = max(x_size >> 1, 1);
9431 int to_y_size = max(y_size >> 1, 1);
9432 int to_z_size = max(z_size >> 1, 1);
9434 size_t to_row_size = (size_t)to_x_size * pixel_size;
9435 size_t to_page_size = (size_t)to_y_size * to_row_size;
9436 size_t to_view_size = (size_t)to_z_size * to_page_size;
9437 to._page_size = to_page_size;
9438 to._image = PTA_uchar::empty_array(to_page_size * to_z_size * cdata->_num_views, get_class_type());
9441 int num_color_components = cdata->_num_components;
9443 --num_color_components;
9446 for (
int view = 0; view < cdata->_num_views; ++view) {
9447 unsigned char *start_to = to._image.p() + view * to_view_size;
9448 const unsigned char *start_from = from._image.p() + view * view_size;
9449 nassertv(start_to + to_view_size <= to._image.p() + to._image.size());
9450 nassertv(start_from + view_size <= from._image.p() + from._image.size());
9451 unsigned char *p = start_to;
9452 const unsigned char *q = start_from;
9455 for (z = 0; z < z_size - 1; z += 2) {
9457 nassertv(p == start_to + (z / 2) * to_page_size);
9458 nassertv(q == start_from + z * page_size);
9461 for (y = 0; y < y_size - 1; y += 2) {
9463 nassertv(p == start_to + (z / 2) * to_page_size + (y / 2) * to_row_size);
9464 nassertv(q == start_from + z * page_size + y * row_size);
9467 for (x = 0; x < x_size - 1; x += 2) {
9469 for (
int c = 0; c < num_color_components; ++c) {
9471 filter_component(p, q, pixel_size, row_size, page_size);
9474 filter_alpha(p, q, pixel_size, row_size, page_size);
9484 for (
int c = 0; c < num_color_components; ++c) {
9486 filter_component(p, q, 0, row_size, page_size);
9489 filter_alpha(p, q, 0, row_size, page_size);
9503 for (x = 0; x < x_size - 1; x += 2) {
9505 for (
int c = 0; c < num_color_components; ++c) {
9507 filter_component(p, q, pixel_size, 0, page_size);
9510 filter_alpha(p, q, pixel_size, 0, page_size);
9520 for (
int c = 0; c < num_color_components; ++c) {
9522 filter_component(p, q, 0, 0, page_size);
9525 filter_alpha(p, q, 0, 0, page_size);
9539 for (y = 0; y < y_size - 1; y += 2) {
9541 nassertv(p == start_to + (y / 2) * to_row_size);
9542 nassertv(q == start_from + y * row_size);
9545 for (x = 0; x < x_size - 1; x += 2) {
9547 for (
int c = 0; c < num_color_components; ++c) {
9549 filter_component(p, q, pixel_size, row_size, 0);
9552 filter_alpha(p, q, pixel_size, row_size, 0);
9562 for (
int c = 0; c < num_color_components; ++c) {
9564 filter_component(p, q, 0, row_size, 0);
9567 filter_alpha(p, q, 0, row_size, 0);
9581 for (x = 0; x < x_size - 1; x += 2) {
9583 for (
int c = 0; c < num_color_components; ++c) {
9585 filter_component(p, q, pixel_size, 0, 0);
9588 filter_alpha(p, q, pixel_size, 0, 0);
9598 for (
int c = 0; c < num_color_components; ++c) {
9600 filter_component(p, q, 0, 0, 0);
9603 filter_alpha(p, q, 0, 0, 0);
9609 nassertv(p == start_to + to_z_size * to_page_size);
9610 nassertv(q == start_from + z_size * page_size);
9619 filter_2d_unsigned_byte(
unsigned char *&p,
const unsigned char *&q,
9620 size_t pixel_size,
size_t row_size) {
9621 unsigned int result = ((
unsigned int)q[0] +
9622 (
unsigned int)q[pixel_size] +
9623 (
unsigned int)q[row_size] +
9624 (
unsigned int)q[pixel_size + row_size]) >> 2;
9625 *p = (
unsigned char)result;
9635 filter_2d_unsigned_byte_srgb(
unsigned char *&p,
const unsigned char *&q,
9636 size_t pixel_size,
size_t row_size) {
9652 filter_2d_unsigned_byte_srgb_sse2(
unsigned char *&p,
const unsigned char *&q,
9653 size_t pixel_size,
size_t row_size) {
9659 *p = encode_sRGB_uchar_sse2(result * 0.25f);
9669 filter_2d_unsigned_short(
unsigned char *&p,
const unsigned char *&q,
9670 size_t pixel_size,
size_t row_size) {
9671 unsigned int result = ((
unsigned int)*(
unsigned short *)&q[0] +
9672 (
unsigned int)*(
unsigned short *)&q[pixel_size] +
9673 (
unsigned int)*(
unsigned short *)&q[row_size] +
9674 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size]) >> 2;
9675 store_unscaled_short(p, result);
9684 filter_2d_float(
unsigned char *&p,
const unsigned char *&q,
9685 size_t pixel_size,
size_t row_size) {
9686 *(
float *)p = (*(
float *)&q[0] +
9687 *(
float *)&q[pixel_size] +
9688 *(
float *)&q[row_size] +
9689 *(
float *)&q[pixel_size + row_size]) / 4.0f;
9700 filter_3d_unsigned_byte(
unsigned char *&p,
const unsigned char *&q,
9701 size_t pixel_size,
size_t row_size,
size_t page_size) {
9702 unsigned int result = ((
unsigned int)q[0] +
9703 (
unsigned int)q[pixel_size] +
9704 (
unsigned int)q[row_size] +
9705 (
unsigned int)q[pixel_size + row_size] +
9706 (
unsigned int)q[page_size] +
9707 (
unsigned int)q[pixel_size + page_size] +
9708 (
unsigned int)q[row_size + page_size] +
9709 (
unsigned int)q[pixel_size + row_size + page_size]) >> 3;
9710 *p = (
unsigned char)result;
9721 filter_3d_unsigned_byte_srgb(
unsigned char *&p,
const unsigned char *&q,
9722 size_t pixel_size,
size_t row_size,
size_t page_size) {
9743 filter_3d_unsigned_byte_srgb_sse2(
unsigned char *&p,
const unsigned char *&q,
9744 size_t pixel_size,
size_t row_size,
size_t page_size) {
9754 *p = encode_sRGB_uchar_sse2(result * 0.125f);
9765 filter_3d_unsigned_short(
unsigned char *&p,
const unsigned char *&q,
9766 size_t pixel_size,
size_t row_size,
9768 unsigned int result = ((
unsigned int)*(
unsigned short *)&q[0] +
9769 (
unsigned int)*(
unsigned short *)&q[pixel_size] +
9770 (
unsigned int)*(
unsigned short *)&q[row_size] +
9771 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size] +
9772 (
unsigned int)*(
unsigned short *)&q[page_size] +
9773 (
unsigned int)*(
unsigned short *)&q[pixel_size + page_size] +
9774 (
unsigned int)*(
unsigned short *)&q[row_size + page_size] +
9775 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size + page_size]) >> 3;
9776 store_unscaled_short(p, result);
9786 filter_3d_float(
unsigned char *&p,
const unsigned char *&q,
9787 size_t pixel_size,
size_t row_size,
size_t page_size) {
9788 *(
float *)p = (*(
float *)&q[0] +
9789 *(
float *)&q[pixel_size] +
9790 *(
float *)&q[row_size] +
9791 *(
float *)&q[pixel_size + row_size] +
9792 *(
float *)&q[page_size] +
9793 *(
float *)&q[pixel_size + page_size] +
9794 *(
float *)&q[row_size + page_size] +
9795 *(
float *)&q[pixel_size + row_size + page_size]) / 8.0f;
9804 do_squish(CData *cdata, Texture::CompressionMode compression,
int squish_flags) {
9806 if (!do_has_all_ram_mipmap_images(cdata)) {
9809 do_generate_ram_mipmap_images(cdata,
false);
9812 RamImages compressed_ram_images;
9813 compressed_ram_images.reserve(cdata->_ram_images.size());
9814 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
9815 RamImage compressed_image;
9816 int x_size = do_get_expected_mipmap_x_size(cdata, n);
9817 int y_size = do_get_expected_mipmap_y_size(cdata, n);
9818 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
9819 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
9820 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
9822 compressed_image._page_size = page_size;
9823 compressed_image._image = PTA_uchar::empty_array(page_size * num_pages);
9824 for (
int z = 0; z < num_pages; ++z) {
9825 unsigned char *dest_page = compressed_image._image.p() + z * page_size;
9826 unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * cdata->_ram_images[n]._page_size;
9827 unsigned const char *source_page_end = source_page + cdata->_ram_images[n]._page_size;
9829 unsigned char *d = dest_page;
9830 for (
int y = 0; y < y_size; y += 4) {
9831 for (
int x = 0; x < x_size; x += 4) {
9832 unsigned char tb[16 * 4];
9834 unsigned char *t = tb;
9835 for (
int i = 0; i < 16; ++i) {
9838 unsigned const char *s = source_page + (yi * x_size + xi) * cdata->_num_components;
9839 if (s < source_page_end) {
9840 switch (cdata->_num_components) {
9873 squish::CompressMasked(tb, mask, d, squish_flags);
9879 compressed_ram_images.push_back(compressed_image);
9881 cdata->_ram_images.swap(compressed_ram_images);
9882 cdata->_ram_image_compression = compression;
9895 do_unsquish(CData *cdata,
int squish_flags) {
9897 RamImages uncompressed_ram_images;
9898 uncompressed_ram_images.reserve(cdata->_ram_images.size());
9899 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
9900 RamImage uncompressed_image;
9901 int x_size = do_get_expected_mipmap_x_size(cdata, n);
9902 int y_size = do_get_expected_mipmap_y_size(cdata, n);
9903 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
9904 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
9905 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
9907 uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
9908 uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * num_pages);
9909 for (
int z = 0; z < num_pages; ++z) {
9910 unsigned char *dest_page = uncompressed_image._image.p() + z * uncompressed_image._page_size;
9911 unsigned char *dest_page_end = dest_page + uncompressed_image._page_size;
9912 unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * page_size;
9914 unsigned const char *s = source_page;
9915 for (
int y = 0; y < y_size; y += 4) {
9916 for (
int x = 0; x < x_size; x += 4) {
9917 unsigned char tb[16 * 4];
9918 squish::Decompress(tb, s, squish_flags);
9921 unsigned char *t = tb;
9922 for (
int i = 0; i < 16; ++i) {
9925 unsigned char *d = dest_page + (yi * x_size + xi) * cdata->_num_components;
9926 if (d < dest_page_end) {
9927 switch (cdata->_num_components) {
9957 uncompressed_ram_images.push_back(uncompressed_image);
9959 cdata->_ram_images.swap(uncompressed_ram_images);
9960 cdata->_ram_image_compression = CM_off;
9985 bool has_rawdata =
false;
9986 do_write_datagram_header(cdata, manager, me, has_rawdata);
9987 do_write_datagram_body(cdata, manager, me);
9991 do_write_datagram_rawdata(cdata, manager, me);
10029 do_write_datagram_header(CData *cdata,
BamWriter *manager,
Datagram &me,
bool &has_rawdata) {
10038 has_rawdata = (file_texture_mode == BamWriter::BTM_rawdata ||
10039 (cdata->_filename.empty() && do_has_bam_rawdata(cdata)));
10040 if (has_rawdata && !do_has_bam_rawdata(cdata)) {
10041 do_get_bam_rawdata(cdata);
10042 if (!do_has_bam_rawdata(cdata)) {
10044 has_rawdata =
false;
10050 Filename filename = cdata->_filename;
10051 Filename alpha_filename = cdata->_alpha_filename;
10055 switch (file_texture_mode) {
10056 case BamWriter::BTM_unchanged:
10057 case BamWriter::BTM_rawdata:
10060 case BamWriter::BTM_fullpath:
10061 filename = cdata->_fullpath;
10062 alpha_filename = cdata->_alpha_fullpath;
10065 case BamWriter::BTM_relative:
10066 filename = cdata->_fullpath;
10067 alpha_filename = cdata->_alpha_fullpath;
10072 if (gobj_cat.is_debug()) {
10074 <<
"Texture file " << cdata->_fullpath
10075 <<
" found as " << filename <<
"\n";
10080 if (gobj_cat.is_debug()) {
10082 <<
"Alpha image " << cdata->_alpha_fullpath
10083 <<
" found as " << alpha_filename <<
"\n";
10087 case BamWriter::BTM_basename:
10089 alpha_filename = cdata->_alpha_fullpath.
get_basename();
10094 <<
"Unsupported bam-texture-mode: " << (int)file_texture_mode <<
"\n";
10097 if (filename.empty()) {
10098 if (do_has_bam_rawdata(cdata) || cdata->_has_clear_color) {
10100 has_rawdata =
true;
10107 me.
add_uint8(cdata->_primary_file_num_channels);
10108 me.
add_uint8(cdata->_alpha_file_channel);
10112 cdata->_texture_type == TT_cube_map) {
10121 me.
add_bool(cdata->_has_read_mipmaps);
10132 cdata->_default_sampler.write_datagram(me);
10150 if (cdata->_texture_type == TT_buffer_texture) {
10155 me.
add_uint8(cdata->_auto_texture_scale);
10167 me.
add_int32(cdata->_simple_image_date_generated);
10168 me.
add_uint32(cdata->_simple_ram_image._image.size());
10169 me.
append_data(cdata->_simple_ram_image._image, cdata->_simple_ram_image._image.size());
10173 me.
add_bool(cdata->_has_clear_color);
10174 if (cdata->_has_clear_color) {
10175 cdata->_clear_color.write_datagram(me);
10200 me.
add_uint8(cdata->_ram_image_compression);
10202 if (cdata->_ram_images.empty() && cdata->_has_clear_color &&
10206 int image_size = do_get_expected_ram_image_size(cdata);
10208 me.
add_uint32(do_get_expected_ram_page_size(cdata));
10212 unsigned char pixel[16];
10213 const int pixel_size = do_get_clear_data(cdata,
pixel);
10214 nassertv(pixel_size > 0);
10216 for (
int i = 0; i < image_size; i += pixel_size) {
10220 me.
add_uint8(cdata->_ram_images.size());
10221 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
10222 me.
add_uint32(cdata->_ram_images[n]._page_size);
10223 me.
add_uint32(cdata->_ram_images[n]._image.size());
10224 me.
append_data(cdata->_ram_images[n]._image, cdata->_ram_images[n]._image.size());
10235 return dummy->make_this_from_bam(params);
10262 int primary_file_num_channels = scan.
get_uint8();
10263 int alpha_file_channel = scan.
get_uint8();
10264 bool has_rawdata = scan.
get_bool();
10265 TextureType texture_type = (TextureType)scan.
get_uint8();
10269 if (texture_type == TT_2d_texture_array) {
10270 texture_type = TT_cube_map;
10273 bool has_read_mipmaps =
false;
10275 has_read_mipmaps = scan.
get_bool();
10285 me->set_name(name);
10286 CDWriter cdata_me(me->_cycler,
true);
10287 cdata_me->_filename = filename;
10288 cdata_me->_alpha_filename = alpha_filename;
10289 cdata_me->_primary_file_num_channels = primary_file_num_channels;
10290 cdata_me->_alpha_file_channel = alpha_file_channel;
10291 cdata_me->_texture_type = texture_type;
10292 cdata_me->_has_read_mipmaps = has_read_mipmaps;
10295 me->do_fillin_body(cdata_me, scan, manager);
10296 me->do_fillin_rawdata(cdata_me, scan, manager);
10308 AutoTextureScale auto_texture_scale = ATS_unspecified;
10310 CDWriter cdata_dummy(dummy->_cycler,
true);
10311 dummy->do_fillin_body(cdata_dummy, scan, manager);
10312 auto_texture_scale = cdata_dummy->_auto_texture_scale;
10315 if (filename.empty()) {
10319 <<
"Cannot create texture '" << name <<
"' with no filename.\n";
10329 if (!alpha_filename.empty()) {
10336 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
10340 switch (texture_type) {
10341 case TT_buffer_texture:
10342 case TT_1d_texture:
10343 case TT_2d_texture:
10344 case TT_1d_texture_array:
10345 if (alpha_filename.empty()) {
10347 has_read_mipmaps, options);
10350 primary_file_num_channels,
10351 alpha_file_channel,
10352 has_read_mipmaps, options);
10356 case TT_3d_texture:
10360 case TT_2d_texture_array:
10361 case TT_cube_map_array:
10371 if (me !=
nullptr) {
10372 me->set_name(name);
10373 CDWriter cdata_me(me->_cycler,
true);
10374 me->do_fillin_from(cdata_me, dummy);
10391 cdata->_default_sampler.read_datagram(scan, manager);
10394 cdata->_compression = (CompressionMode)scan.
get_uint8();
10397 cdata->_quality_level = (QualityLevel)scan.
get_uint8();
10400 cdata->_format = (Format)scan.
get_uint8();
10401 cdata->_num_components = scan.
get_uint8();
10403 if (cdata->_texture_type == TT_buffer_texture) {
10404 cdata->_usage_hint = (GeomEnums::UsageHint)scan.
get_uint8();
10407 cdata->inc_properties_modified();
10409 cdata->_auto_texture_scale = ATS_unspecified;
10411 cdata->_auto_texture_scale = (AutoTextureScale)scan.
get_uint8();
10416 cdata->_orig_file_x_size = scan.
get_uint32();
10417 cdata->_orig_file_y_size = scan.
get_uint32();
10425 cdata->_simple_image_date_generated = scan.
get_int32();
10432 <<
"simple RAM image extends past end of datagram, is texture corrupt?\n";
10436 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
10439 cdata->_simple_ram_image._image = image;
10440 cdata->_simple_ram_image._page_size = u_size;
10441 cdata->inc_simple_image_modified();
10445 cdata->_has_clear_color = scan.
get_bool();
10446 if (cdata->_has_clear_color) {
10447 cdata->_clear_color.read_datagram(scan);
10467 do_set_pad_size(cdata, 0, 0, 0);
10470 cdata->_num_views = 1;
10474 cdata->_component_type = (ComponentType)scan.
get_uint8();
10475 cdata->_component_width = scan.
get_uint8();
10476 cdata->_ram_image_compression = CM_off;
10478 cdata->_ram_image_compression = (CompressionMode)scan.
get_uint8();
10481 int num_ram_images = 1;
10486 cdata->_ram_images.clear();
10487 cdata->_ram_images.reserve(num_ram_images);
10488 for (
int n = 0; n < num_ram_images; ++n) {
10489 cdata->_ram_images.push_back(RamImage());
10492 cdata->_ram_images[n]._page_size = scan.
get_uint32();
10501 <<
"RAM image " << n <<
" extends past end of datagram, is texture corrupt?\n";
10505 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
10508 cdata->_ram_images[n]._image = image;
10510 cdata->_loaded_from_image =
true;
10511 cdata->inc_image_modified();
10520 do_fillin_from(CData *cdata,
const Texture *dummy) {
10527 CDReader cdata_dummy(dummy->_cycler);
10529 do_set_wrap_u(cdata, cdata_dummy->_default_sampler.get_wrap_u());
10530 do_set_wrap_v(cdata, cdata_dummy->_default_sampler.get_wrap_v());
10531 do_set_wrap_w(cdata, cdata_dummy->_default_sampler.get_wrap_w());
10532 do_set_border_color(cdata, cdata_dummy->_default_sampler.get_border_color());
10534 if (cdata_dummy->_default_sampler.get_minfilter() != SamplerState::FT_default) {
10535 do_set_minfilter(cdata, cdata_dummy->_default_sampler.get_minfilter());
10537 if (cdata_dummy->_default_sampler.get_magfilter() != SamplerState::FT_default) {
10538 do_set_magfilter(cdata, cdata_dummy->_default_sampler.get_magfilter());
10540 if (cdata_dummy->_default_sampler.get_anisotropic_degree() != 0) {
10541 do_set_anisotropic_degree(cdata, cdata_dummy->_default_sampler.get_anisotropic_degree());
10543 if (cdata_dummy->_compression != CM_default) {
10544 do_set_compression(cdata, cdata_dummy->_compression);
10546 if (cdata_dummy->_quality_level != QL_default) {
10547 do_set_quality_level(cdata, cdata_dummy->_quality_level);
10550 Format format = cdata_dummy->_format;
10551 int num_components = cdata_dummy->_num_components;
10553 if (num_components == cdata->_num_components) {
10557 do_set_format(cdata, format);
10560 if (!cdata_dummy->_simple_ram_image._image.empty()) {
10563 if (cdata->_simple_ram_image._image.empty() ||
10564 cdata_dummy->_simple_image_date_generated > cdata->_simple_image_date_generated) {
10565 do_set_simple_ram_image(cdata,
10566 cdata_dummy->_simple_ram_image._image,
10567 cdata_dummy->_simple_x_size,
10568 cdata_dummy->_simple_y_size);
10569 cdata->_simple_image_date_generated = cdata_dummy->_simple_image_date_generated;
10579 _primary_file_num_channels = 0;
10580 _alpha_file_channel = 0;
10581 _keep_ram_image =
true;
10582 _compression = CM_default;
10583 _auto_texture_scale = ATS_unspecified;
10584 _ram_image_compression = CM_off;
10585 _render_to_texture =
false;
10586 _match_framebuffer_format =
false;
10587 _post_load_store_cache =
false;
10588 _quality_level = QL_default;
10590 _texture_type = TT_2d_texture;
10602 _usage_hint = GeomEnums::UH_unspecified;
10608 _orig_file_x_size = 0;
10609 _orig_file_y_size = 0;
10611 _loaded_from_image =
false;
10612 _loaded_from_txo =
false;
10613 _has_read_pages =
false;
10614 _has_read_mipmaps =
false;
10615 _num_mipmap_levels_read = 0;
10617 _simple_x_size = 0;
10618 _simple_y_size = 0;
10619 _simple_ram_image._page_size = 0;
10621 _has_clear_color =
false;
10628 CData(
const Texture::CData ©) {
10629 _num_mipmap_levels_read = 0;
10633 _properties_modified = copy._properties_modified;
10634 _image_modified = copy._image_modified;
10635 _simple_image_modified = copy._simple_image_modified;
10642 make_copy()
const {
10643 return new CData(*
this);
10649 void Texture::CData::
10650 do_assign(
const Texture::CData *copy) {
10651 _filename = copy->_filename;
10652 _alpha_filename = copy->_alpha_filename;
10653 if (!copy->_fullpath.empty()) {
10656 _fullpath = copy->_fullpath;
10657 _alpha_fullpath = copy->_alpha_fullpath;
10659 _primary_file_num_channels = copy->_primary_file_num_channels;
10660 _alpha_file_channel = copy->_alpha_file_channel;
10661 _x_size = copy->_x_size;
10662 _y_size = copy->_y_size;
10663 _z_size = copy->_z_size;
10664 _num_views = copy->_num_views;
10665 _pad_x_size = copy->_pad_x_size;
10666 _pad_y_size = copy->_pad_y_size;
10667 _pad_z_size = copy->_pad_z_size;
10668 _orig_file_x_size = copy->_orig_file_x_size;
10669 _orig_file_y_size = copy->_orig_file_y_size;
10670 _num_components = copy->_num_components;
10671 _component_width = copy->_component_width;
10672 _texture_type = copy->_texture_type;
10673 _format = copy->_format;
10674 _component_type = copy->_component_type;
10675 _loaded_from_image = copy->_loaded_from_image;
10676 _loaded_from_txo = copy->_loaded_from_txo;
10677 _has_read_pages = copy->_has_read_pages;
10678 _has_read_mipmaps = copy->_has_read_mipmaps;
10679 _num_mipmap_levels_read = copy->_num_mipmap_levels_read;
10680 _default_sampler = copy->_default_sampler;
10681 _keep_ram_image = copy->_keep_ram_image;
10682 _compression = copy->_compression;
10683 _match_framebuffer_format = copy->_match_framebuffer_format;
10684 _quality_level = copy->_quality_level;
10685 _auto_texture_scale = copy->_auto_texture_scale;
10686 _ram_image_compression = copy->_ram_image_compression;
10687 _ram_images = copy->_ram_images;
10688 _simple_x_size = copy->_simple_x_size;
10689 _simple_y_size = copy->_simple_y_size;
10690 _simple_ram_image = copy->_simple_ram_image;
10697 void Texture::CData::
10705 int Texture::CData::
10714 void Texture::CData::
10722 operator << (ostream &out, Texture::TextureType tt) {
10730 operator << (ostream &out, Texture::ComponentType ct) {
10738 operator << (ostream &out, Texture::Format f) {
10746 operator << (ostream &out, Texture::CompressionMode cm) {
10754 operator << (ostream &out, Texture::QualityLevel tql) {
10762 operator >> (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.
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.
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 * 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 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,...
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....
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.
string upcase(const string &s)
Returns the input string with all lowercase letters converted to uppercase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void release_read(const CycleData *pointer) const
Releases a pointer previously obtained via a call to read().
CycleDataType * write_upstream(bool force_to_0, Thread *current_thread)
See PipelineCyclerBase::write_upstream().
CycleDataType * elevate_read_upstream(const CycleDataType *pointer, bool force_to_0, Thread *current_thread)
See PipelineCyclerBase::elevate_read_upstream().
const CycleDataType * read(Thread *current_thread) const
See PipelineCyclerBase::read().
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.