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 compression = CM_on;
5871 if (compression != CM_off && cdata->_ram_image_compression == CM_off) {
5873 if (do_compress_ram_image(cdata, compression, QL_default, gsg)) {
5874 if (gobj_cat.is_debug()) {
5876 <<
"Compressed " << get_name() <<
" with "
5877 << cdata->_ram_image_compression <<
"\n";
5891 do_compress_ram_image(CData *cdata, Texture::CompressionMode compression,
5892 Texture::QualityLevel quality_level,
5894 nassertr(compression != CM_off,
false);
5896 if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
5900 if (compression == CM_on) {
5902 switch (cdata->_format) {
5903 case Texture::F_rgbm:
5904 case Texture::F_rgb:
5905 case Texture::F_rgb5:
5906 case Texture::F_rgba5:
5907 case Texture::F_rgb8:
5908 case Texture::F_rgb12:
5909 case Texture::F_rgb332:
5910 case Texture::F_rgb16:
5911 case Texture::F_rgb32:
5912 case Texture::F_rgb10_a2:
5913 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt1)) {
5914 compression = CM_dxt1;
5915 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt3)) {
5916 compression = CM_dxt3;
5917 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5918 compression = CM_dxt5;
5919 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5920 compression = CM_etc2;
5921 }
else if (gsg->get_supports_compressed_texture_format(CM_etc1)) {
5922 compression = CM_etc1;
5926 case Texture::F_rgba4:
5927 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt3)) {
5928 compression = CM_dxt3;
5929 }
else if (gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5930 compression = CM_dxt5;
5931 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5932 compression = CM_etc2;
5936 case Texture::F_rgba:
5937 case Texture::F_rgba8:
5938 case Texture::F_rgba12:
5939 case Texture::F_rgba16:
5940 case Texture::F_rgba32:
5941 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
5942 compression = CM_dxt5;
5943 }
else if (gsg->get_supports_compressed_texture_format(CM_etc2)) {
5944 compression = CM_etc2;
5948 case Texture::F_red:
5950 if (gsg ==
nullptr || gsg->get_supports_compressed_texture_format(CM_rgtc)) {
5951 compression = CM_rgtc;
5952 }
else if (gsg->get_supports_compressed_texture_format(CM_eac)) {
5953 compression = CM_eac;
5963 if (quality_level == Texture::QL_default) {
5964 quality_level = cdata->_quality_level;
5966 if (quality_level == Texture::QL_default) {
5967 quality_level = texture_quality_level;
5970 if (compression == CM_rgtc) {
5972 if (cdata->_component_type != T_unsigned_byte) {
5976 if (!do_has_all_ram_mipmap_images(cdata)) {
5979 do_generate_ram_mipmap_images(cdata,
false);
5982 RamImages compressed_ram_images;
5983 compressed_ram_images.resize(cdata->_ram_images.size());
5985 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
5986 const RamImage *uncompressed_image = &cdata->_ram_images[n];
5988 int x_size = do_get_expected_mipmap_x_size(cdata, n);
5989 int y_size = do_get_expected_mipmap_y_size(cdata, n);
5990 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
5995 RamImage temp_image;
5996 if ((x_size | y_size) & 0x3) {
5997 int virtual_x_size = x_size;
5998 int virtual_y_size = y_size;
5999 x_size = (x_size + 3) & ~0x3;
6000 y_size = (y_size + 3) & ~0x3;
6002 temp_image._page_size = x_size * y_size * cdata->_num_components;
6003 temp_image._image = PTA_uchar::empty_array(temp_image._page_size * num_pages);
6005 for (
int z = 0; z < num_pages; ++z) {
6006 unsigned char *dest = temp_image._image.p() + z * temp_image._page_size;
6007 unsigned const char *src = uncompressed_image->_image.p() + z * uncompressed_image->_page_size;
6009 for (
int y = 0; y < virtual_y_size; ++y) {
6010 memcpy(dest, src, virtual_x_size);
6011 src += virtual_x_size;
6016 uncompressed_image = &temp_image;
6020 RamImage &compressed_image = compressed_ram_images[n];
6021 compressed_image._page_size = (x_size * y_size * cdata->_num_components) >> 1;
6022 compressed_image._image = PTA_uchar::empty_array(compressed_image._page_size * num_pages);
6024 if (cdata->_num_components == 1) {
6025 do_compress_ram_image_bc4(*uncompressed_image, compressed_image,
6026 x_size, y_size, num_pages);
6027 }
else if (cdata->_num_components == 2) {
6028 do_compress_ram_image_bc5(*uncompressed_image, compressed_image,
6029 x_size, y_size, num_pages);
6036 cdata->_ram_images.swap(compressed_ram_images);
6037 cdata->_ram_image_compression = CM_rgtc;
6042 if (cdata->_texture_type != TT_3d_texture &&
6043 cdata->_texture_type != TT_2d_texture_array &&
6044 cdata->_component_type == T_unsigned_byte) {
6045 int squish_flags = 0;
6046 switch (compression) {
6048 squish_flags |= squish::kDxt1;
6052 squish_flags |= squish::kDxt3;
6056 squish_flags |= squish::kDxt5;
6063 if (squish_flags != 0) {
6065 switch (quality_level) {
6067 squish_flags |= squish::kColourRangeFit;
6072 squish_flags |= squish::kColourRangeFit;
6077 squish_flags |= squish::kColourIterativeClusterFit;
6084 if (do_squish(cdata, compression, squish_flags)) {
6098 do_uncompress_ram_image(CData *cdata) {
6099 nassertr(!cdata->_ram_images.empty(),
false);
6101 if (cdata->_ram_image_compression == CM_rgtc) {
6103 RamImages uncompressed_ram_images;
6104 uncompressed_ram_images.resize(cdata->_ram_images.size());
6106 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
6107 const RamImage &compressed_image = cdata->_ram_images[n];
6109 int x_size = do_get_expected_mipmap_x_size(cdata, n);
6110 int y_size = do_get_expected_mipmap_y_size(cdata, n);
6111 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
6113 RamImage &uncompressed_image = uncompressed_ram_images[n];
6114 uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
6115 uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * num_pages);
6117 if (cdata->_num_components == 1) {
6118 do_uncompress_ram_image_bc4(compressed_image, uncompressed_image,
6119 x_size, y_size, num_pages);
6120 }
else if (cdata->_num_components == 2) {
6121 do_uncompress_ram_image_bc5(compressed_image, uncompressed_image,
6122 x_size, y_size, num_pages);
6128 cdata->_ram_images.swap(uncompressed_ram_images);
6129 cdata->_ram_image_compression = CM_off;
6134 if (cdata->_texture_type != TT_3d_texture &&
6135 cdata->_texture_type != TT_2d_texture_array &&
6136 cdata->_component_type == T_unsigned_byte) {
6137 int squish_flags = 0;
6138 switch (cdata->_ram_image_compression) {
6140 squish_flags |= squish::kDxt1;
6144 squish_flags |= squish::kDxt3;
6148 squish_flags |= squish::kDxt5;
6155 if (squish_flags != 0) {
6157 if (do_unsquish(cdata, squish_flags)) {
6170 do_compress_ram_image_bc4(
const RamImage &uncompressed_image,
6171 RamImage &compressed_image,
6172 int x_size,
int y_size,
int num_pages) {
6173 int x_blocks = (x_size >> 2);
6174 int y_blocks = (y_size >> 2);
6180 nassertv((
size_t)x_blocks * (
size_t)y_blocks * 4 * 4 <= uncompressed_image._page_size);
6181 nassertv((
size_t)x_size * (
size_t)y_size == uncompressed_image._page_size);
6183 static const int remap[] = {1, 7, 6, 5, 4, 3, 2, 0};
6185 for (
int z = 0; z < num_pages; ++z) {
6186 unsigned char *dest = compressed_image._image.p() + z * compressed_image._page_size;
6187 unsigned const char *src = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6190 for (
int y = 0; y < y_blocks; ++y) {
6191 for (
int x = 0; x < x_blocks; ++x) {
6194 unsigned char minv, maxv;
6195 unsigned const char *blk = src;
6200 minv = min(blk[1], minv); maxv = max(blk[1], maxv);
6201 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6202 minv = min(blk[3], minv); maxv = max(blk[3], maxv);
6204 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
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);
6222 fac = 7.5f / (maxv - minv);
6227 a = (remap[(int)(blk[0] * fac + add)])
6228 | (remap[(
int)(blk[1] * fac + add)] << 3)
6229 | (remap[(int)(blk[2] * fac + add)] << 6)
6230 | (remap[(
int)(blk[3] * fac + add)] << 9);
6232 b = (remap[(int)(blk[0] * fac + add)] << 4)
6233 | (remap[(
int)(blk[1] * fac + add)] << 7)
6234 | (remap[(int)(blk[2] * fac + add)] << 10)
6235 | (remap[(
int)(blk[3] * fac + add)] << 13);
6237 c = (remap[(int)(blk[0] * fac + add)])
6238 | (remap[(
int)(blk[1] * fac + add)] << 3)
6239 | (remap[(int)(blk[2] * fac + add)] << 6)
6240 | (remap[(
int)(blk[3] * fac + add)] << 9);
6242 d = (remap[(int)(blk[0] * fac + add)] << 4)
6243 | (remap[(
int)(blk[1] * fac + add)] << 7)
6244 | (remap[(int)(blk[2] * fac + add)] << 10)
6245 | (remap[(
int)(blk[3] * fac + add)] << 13);
6249 *(dest++) = a & 0xff;
6250 *(dest++) = (a >> 8) | (b & 0xf0);
6252 *(dest++) = c & 0xff;
6253 *(dest++) = (c >> 8) | (d & 0xf0);
6269 do_compress_ram_image_bc5(
const RamImage &uncompressed_image,
6270 RamImage &compressed_image,
6271 int x_size,
int y_size,
int num_pages) {
6272 int x_blocks = (x_size >> 2);
6273 int y_blocks = (y_size >> 2);
6274 int stride = x_size * 2;
6279 nassertv((
size_t)x_blocks * (
size_t)y_blocks * 4 * 4 * 2 <= uncompressed_image._page_size);
6280 nassertv((
size_t)stride * (
size_t)y_size == uncompressed_image._page_size);
6282 static const int remap[] = {1, 7, 6, 5, 4, 3, 2, 0};
6284 for (
int z = 0; z < num_pages; ++z) {
6285 unsigned char *dest = compressed_image._image.p() + z * compressed_image._page_size;
6286 unsigned const char *src = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6289 for (
int y = 0; y < y_blocks; ++y) {
6290 for (
int x = 0; x < x_blocks; ++x) {
6293 unsigned char minv, maxv;
6294 unsigned const char *blk = src;
6299 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6300 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6301 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6303 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
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);
6320 fac = 7.5f / (maxv - minv);
6326 a = (remap[(int)(blk[0] * fac + add)])
6327 | (remap[(
int)(blk[2] * fac + add)] << 3)
6328 | (remap[(int)(blk[4] * fac + add)] << 6)
6329 | (remap[(
int)(blk[6] * fac + add)] << 9);
6331 b = (remap[(int)(blk[0] * fac + add)] << 4)
6332 | (remap[(
int)(blk[2] * fac + add)] << 7)
6333 | (remap[(int)(blk[4] * fac + add)] << 10)
6334 | (remap[(
int)(blk[6] * fac + add)] << 13);
6336 c = (remap[(int)(blk[0] * fac + add)])
6337 | (remap[(
int)(blk[2] * fac + add)] << 3)
6338 | (remap[(int)(blk[4] * fac + add)] << 6)
6339 | (remap[(
int)(blk[6] * fac + add)] << 9);
6341 d = (remap[(int)(blk[0] * fac + add)] << 4)
6342 | (remap[(
int)(blk[2] * fac + add)] << 7)
6343 | (remap[(int)(blk[4] * fac + add)] << 10)
6344 | (remap[(
int)(blk[6] * fac + add)] << 13);
6348 *(dest++) = a & 0xff;
6349 *(dest++) = (a >> 8) | (b & 0xf0);
6351 *(dest++) = c & 0xff;
6352 *(dest++) = (c >> 8) | (d & 0xf0);
6359 minv = min(blk[2], minv); maxv = max(blk[2], maxv);
6360 minv = min(blk[4], minv); maxv = max(blk[4], maxv);
6361 minv = min(blk[6], minv); maxv = max(blk[6], maxv);
6363 minv = min(blk[0], minv); maxv = max(blk[0], maxv);
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);
6380 fac = 7.5f / (maxv - minv);
6386 a = (remap[(int)(blk[0] * fac + add)])
6387 | (remap[(
int)(blk[2] * fac + add)] << 3)
6388 | (remap[(int)(blk[4] * fac + add)] << 6)
6389 | (remap[(
int)(blk[6] * fac + add)] << 9);
6391 b = (remap[(int)(blk[0] * fac + add)] << 4)
6392 | (remap[(
int)(blk[2] * fac + add)] << 7)
6393 | (remap[(int)(blk[4] * fac + add)] << 10)
6394 | (remap[(
int)(blk[6] * fac + add)] << 13);
6396 c = (remap[(int)(blk[0] * fac + add)])
6397 | (remap[(
int)(blk[2] * fac + add)] << 3)
6398 | (remap[(int)(blk[4] * fac + add)] << 6)
6399 | (remap[(
int)(blk[6] * fac + add)] << 9);
6401 d = (remap[(int)(blk[0] * fac + add)] << 4)
6402 | (remap[(
int)(blk[2] * fac + add)] << 7)
6403 | (remap[(int)(blk[4] * fac + add)] << 10)
6404 | (remap[(
int)(blk[6] * fac + add)] << 13);
6408 *(dest++) = a & 0xff;
6409 *(dest++) = (a >> 8) | (b & 0xf0);
6411 *(dest++) = c & 0xff;
6412 *(dest++) = (c >> 8) | (d & 0xf0);
6428 do_uncompress_ram_image_bc4(
const RamImage &compressed_image,
6429 RamImage &uncompressed_image,
6430 int x_size,
int y_size,
int num_pages) {
6431 int x_blocks = (x_size >> 2);
6432 int y_blocks = (y_size >> 2);
6434 for (
int z = 0; z < num_pages; ++z) {
6435 unsigned char *dest = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6436 unsigned const char *src = compressed_image._image.p() + z * compressed_image._page_size;
6440 for (
int y = 0; y < y_blocks; ++y) {
6441 for (
int x = 0; x < x_blocks; ++x) {
6442 unsigned char *blk = dest;
6445 if (tbl[0] > tbl[1]) {
6446 tbl[2] = (tbl[0] * 6 + tbl[1] * 1) / 7.0f;
6447 tbl[3] = (tbl[0] * 5 + tbl[1] * 2) / 7.0f;
6448 tbl[4] = (tbl[0] * 4 + tbl[1] * 3) / 7.0f;
6449 tbl[5] = (tbl[0] * 3 + tbl[1] * 4) / 7.0f;
6450 tbl[6] = (tbl[0] * 2 + tbl[1] * 5) / 7.0f;
6451 tbl[7] = (tbl[0] * 1 + tbl[1] * 6) / 7.0f;
6453 tbl[2] = (tbl[0] * 4 + tbl[1] * 1) / 5.0f;
6454 tbl[3] = (tbl[0] * 3 + tbl[1] * 2) / 5.0f;
6455 tbl[4] = (tbl[0] * 2 + tbl[1] * 3) / 5.0f;
6456 tbl[5] = (tbl[0] * 1 + tbl[1] * 4) / 5.0f;
6460 int v = src[2] + (src[3] << 8) + (src[4] << 16);
6461 blk[0] = tbl[v & 0x7];
6462 blk[1] = tbl[(v & 0x000038) >> 3];
6463 blk[2] = tbl[(v & 0x0001c0) >> 6];
6464 blk[3] = tbl[(v & 0x000e00) >> 9];
6466 blk[0] = tbl[(v & 0x007000) >> 12];
6467 blk[1] = tbl[(v & 0x038000) >> 15];
6468 blk[2] = tbl[(v & 0x1c0000) >> 18];
6469 blk[3] = tbl[(v & 0xe00000) >> 21];
6471 v = src[5] + (src[6] << 8) + (src[7] << 16);
6472 blk[0] = tbl[v & 0x7];
6473 blk[1] = tbl[(v & 0x000038) >> 3];
6474 blk[2] = tbl[(v & 0x0001c0) >> 6];
6475 blk[3] = tbl[(v & 0x000e00) >> 9];
6477 blk[0] = tbl[(v & 0x007000) >> 12];
6478 blk[1] = tbl[(v & 0x038000) >> 15];
6479 blk[2] = tbl[(v & 0x1c0000) >> 18];
6480 blk[3] = tbl[(v & 0xe00000) >> 21];
6494 do_uncompress_ram_image_bc5(
const RamImage &compressed_image,
6495 RamImage &uncompressed_image,
6496 int x_size,
int y_size,
int num_pages) {
6497 int x_blocks = (x_size >> 2);
6498 int y_blocks = (y_size >> 2);
6499 int stride = x_size * 2;
6501 for (
int z = 0; z < num_pages; ++z) {
6502 unsigned char *dest = uncompressed_image._image.p() + z * uncompressed_image._page_size;
6503 unsigned const char *src = compressed_image._image.p() + z * compressed_image._page_size;
6508 for (
int y = 0; y < y_blocks; ++y) {
6509 for (
int x = 0; x < x_blocks; ++x) {
6510 unsigned char *blk = dest;
6513 if (red[0] > red[1]) {
6514 red[2] = (red[0] * 6 + red[1] * 1) / 7.0f;
6515 red[3] = (red[0] * 5 + red[1] * 2) / 7.0f;
6516 red[4] = (red[0] * 4 + red[1] * 3) / 7.0f;
6517 red[5] = (red[0] * 3 + red[1] * 4) / 7.0f;
6518 red[6] = (red[0] * 2 + red[1] * 5) / 7.0f;
6519 red[7] = (red[0] * 1 + red[1] * 6) / 7.0f;
6521 red[2] = (red[0] * 4 + red[1] * 1) / 5.0f;
6522 red[3] = (red[0] * 3 + red[1] * 2) / 5.0f;
6523 red[4] = (red[0] * 2 + red[1] * 3) / 5.0f;
6524 red[5] = (red[0] * 1 + red[1] * 4) / 5.0f;
6530 if (grn[0] > grn[1]) {
6531 grn[2] = (grn[0] * 6 + grn[1] * 1) / 7.0f;
6532 grn[3] = (grn[0] * 5 + grn[1] * 2) / 7.0f;
6533 grn[4] = (grn[0] * 4 + grn[1] * 3) / 7.0f;
6534 grn[5] = (grn[0] * 3 + grn[1] * 4) / 7.0f;
6535 grn[6] = (grn[0] * 2 + grn[1] * 5) / 7.0f;
6536 grn[7] = (grn[0] * 1 + grn[1] * 6) / 7.0f;
6538 grn[2] = (grn[0] * 4 + grn[1] * 1) / 5.0f;
6539 grn[3] = (grn[0] * 3 + grn[1] * 2) / 5.0f;
6540 grn[4] = (grn[0] * 2 + grn[1] * 3) / 5.0f;
6541 grn[5] = (grn[0] * 1 + grn[1] * 4) / 5.0f;
6545 int r = src[2] + (src[3] << 8) + (src[4] << 16);
6546 int g = src[10] + (src[11] << 8) + (src[12] << 16);
6547 blk[0] = red[r & 0x7];
6548 blk[1] = grn[g & 0x7];
6549 blk[2] = red[(r & 0x000038) >> 3];
6550 blk[3] = grn[(g & 0x000038) >> 3];
6551 blk[4] = red[(r & 0x0001c0) >> 6];
6552 blk[5] = grn[(g & 0x0001c0) >> 6];
6553 blk[6] = red[(r & 0x000e00) >> 9];
6554 blk[7] = grn[(g & 0x000e00) >> 9];
6556 blk[0] = red[(r & 0x007000) >> 12];
6557 blk[1] = grn[(g & 0x007000) >> 12];
6558 blk[2] = red[(r & 0x038000) >> 15];
6559 blk[3] = grn[(g & 0x038000) >> 15];
6560 blk[4] = red[(r & 0x1c0000) >> 18];
6561 blk[5] = grn[(g & 0x1c0000) >> 18];
6562 blk[6] = red[(r & 0xe00000) >> 21];
6563 blk[7] = grn[(g & 0xe00000) >> 21];
6565 r = src[5] + (src[6] << 8) + (src[7] << 16);
6566 g = src[13] + (src[14] << 8) + (src[15] << 16);
6567 blk[0] = red[r & 0x7];
6568 blk[1] = grn[g & 0x7];
6569 blk[2] = red[(r & 0x000038) >> 3];
6570 blk[3] = grn[(g & 0x000038) >> 3];
6571 blk[4] = red[(r & 0x0001c0) >> 6];
6572 blk[5] = grn[(g & 0x0001c0) >> 6];
6573 blk[6] = red[(r & 0x000e00) >> 9];
6574 blk[7] = grn[(g & 0x000e00) >> 9];
6576 blk[0] = red[(r & 0x007000) >> 12];
6577 blk[1] = grn[(g & 0x007000) >> 12];
6578 blk[2] = red[(r & 0x038000) >> 15];
6579 blk[3] = grn[(g & 0x038000) >> 15];
6580 blk[4] = red[(r & 0x1c0000) >> 18];
6581 blk[5] = grn[(g & 0x1c0000) >> 18];
6582 blk[6] = red[(r & 0xe00000) >> 21];
6583 blk[7] = grn[(g & 0xe00000) >> 21];
6597 do_has_all_ram_mipmap_images(
const CData *cdata)
const {
6598 if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty()) {
6609 int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
6615 if (n >= (
int)cdata->_ram_images.size() || cdata->_ram_images[n]._image.empty()) {
6631 do_reconsider_z_size(CData *cdata,
int z,
const LoaderOptions &options) {
6632 if (z >= cdata->_z_size * cdata->_num_views) {
6633 bool num_views_specified =
true;
6634 if (options.get_texture_flags() & LoaderOptions::TF_multiview) {
6641 if (num_views_specified &&
6642 (cdata->_texture_type == Texture::TT_3d_texture ||
6643 cdata->_texture_type == Texture::TT_2d_texture_array)) {
6648 nassertr(cdata->_num_views != 0,
false);
6649 cdata->_z_size = (z / cdata->_num_views) + 1;
6651 }
else if (cdata->_z_size != 0) {
6655 cdata->_num_views = (z / cdata->_z_size) + 1;
6664 do_allocate_pages(cdata);
6677 do_allocate_pages(CData *cdata) {
6678 size_t new_size = do_get_expected_ram_image_size(cdata);
6679 if (!cdata->_ram_images.empty() &&
6680 !cdata->_ram_images[0]._image.empty() &&
6681 new_size > cdata->_ram_images[0]._image.size()) {
6682 cdata->_ram_images[0]._image.insert(cdata->_ram_images[0]._image.end(), new_size - cdata->_ram_images[0]._image.size(), 0);
6683 nassertv(cdata->_ram_images[0]._image.size() == new_size);
6694 do_reconsider_image_properties(CData *cdata,
int x_size,
int y_size,
int num_components,
6695 Texture::ComponentType component_type,
int z,
6697 if (!cdata->_loaded_from_image || num_components != cdata->_num_components || component_type != cdata->_component_type) {
6703 switch (num_components) {
6705 cdata->_format = F_luminance;
6709 cdata->_format = F_luminance_alpha;
6713 cdata->_format = F_rgb;
6717 cdata->_format = F_rgba;
6722 nassert_raise(
"unexpected channel count");
6723 cdata->_format = F_rgb;
6728 if (!cdata->_loaded_from_image) {
6729 if ((options.get_texture_flags() & LoaderOptions::TF_allow_1d) &&
6730 cdata->_texture_type == TT_2d_texture && x_size != 1 && y_size == 1) {
6732 cdata->_texture_type = TT_1d_texture;
6736 switch (cdata->_texture_type) {
6738 case TT_buffer_texture:
6739 nassertr(y_size == 1,
false);
6742 case TT_cube_map_array:
6743 nassertr(x_size == y_size,
false);
6749 if ((cdata->_x_size != x_size)||(cdata->_y_size != y_size)) {
6750 do_set_pad_size(cdata, 0, 0, 0);
6752 cdata->_x_size = x_size;
6753 cdata->_y_size = y_size;
6754 cdata->_num_components = num_components;
6755 do_set_component_type(cdata, component_type);
6758 if (cdata->_x_size != x_size ||
6759 cdata->_y_size != y_size ||
6760 cdata->_num_components != num_components ||
6761 cdata->_component_type != component_type) {
6763 <<
"Texture properties have changed for texture " << get_name()
6764 <<
" page " << z <<
".\n";
6776 do_rescale_texture(CData *cdata) {
6777 int new_x_size = cdata->_x_size;
6778 int new_y_size = cdata->_y_size;
6779 if (cdata->_z_size * cdata->_num_views != 1) {
6780 nassert_raise(
"rescale_texture() doesn't support 3-d or multiview textures.");
6784 if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(),
false)) {
6787 if (!do_store_one(cdata, orig_image, 0, 0)) {
6789 <<
"Couldn't get image in rescale_texture()\n";
6794 <<
"Resizing " << get_name() <<
" to " << new_x_size <<
" x "
6795 << new_y_size <<
"\n";
6799 new_image.quick_filter_from(orig_image);
6801 do_clear_ram_image(cdata);
6802 cdata->inc_image_modified();
6803 cdata->_x_size = new_x_size;
6804 cdata->_y_size = new_y_size;
6805 if (!do_load_one(cdata, new_image, get_name(), 0, 0,
LoaderOptions())) {
6815 if (do_get_auto_texture_scale(cdata) == ATS_pad) {
6816 new_x_size = cdata->_x_size;
6817 new_y_size = cdata->_y_size;
6818 if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(),
true)) {
6819 pad_x_size = new_x_size - cdata->_x_size;
6820 pad_y_size = new_y_size - cdata->_y_size;
6823 if (!do_store_one(cdata, orig_image, 0, 0)) {
6825 <<
"Couldn't get image in rescale_texture()\n";
6831 new_image.copy_sub_image(orig_image, 0, new_y_size - orig_image.
get_y_size());
6833 do_clear_ram_image(cdata);
6834 cdata->_loaded_from_image =
false;
6835 cdata->inc_image_modified();
6836 if (!do_load_one(cdata, new_image, get_name(), 0, 0,
LoaderOptions())) {
6840 do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
6853 make_copy_impl()
const {
6854 CDReader cdata(_cycler);
6855 return do_make_copy(cdata);
6862 do_make_copy(
const CData *cdata)
const {
6864 CDWriter cdata_tex(tex->_cycler,
true);
6865 tex->do_assign(cdata_tex,
this, cdata);
6874 do_assign(CData *cdata,
const Texture *copy,
const CData *cdata_copy) {
6875 cdata->do_assign(cdata_copy);
6882 do_clear(CData *cdata) {
6885 CDReader cdata_tex(tex._cycler);
6886 do_assign(cdata, &tex, cdata_tex);
6888 cdata->inc_properties_modified();
6889 cdata->inc_image_modified();
6890 cdata->inc_simple_image_modified();
6897 do_setup_texture(CData *cdata, Texture::TextureType texture_type,
6898 int x_size,
int y_size,
int z_size,
6899 Texture::ComponentType component_type,
6900 Texture::Format format) {
6901 switch (texture_type) {
6903 nassertv(y_size == 1 && z_size == 1);
6907 nassertv(z_size == 1);
6913 case TT_2d_texture_array:
6918 nassertv(x_size == y_size && z_size == 6);
6923 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
6924 cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
6925 cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
6928 case TT_cube_map_array:
6930 nassertv(x_size == y_size && z_size % 6 == 0);
6932 cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
6933 cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
6934 cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
6937 case TT_buffer_texture:
6938 nassertv(y_size == 1 && z_size == 1);
6941 case TT_1d_texture_array:
6942 nassertv(z_size == 1);
6946 if (texture_type != TT_2d_texture) {
6947 do_clear_simple_ram_image(cdata);
6950 cdata->_texture_type = texture_type;
6951 cdata->_x_size = x_size;
6952 cdata->_y_size = y_size;
6953 cdata->_z_size = z_size;
6954 cdata->_num_views = 1;
6955 do_set_component_type(cdata, component_type);
6956 do_set_format(cdata, format);
6958 do_clear_ram_image(cdata);
6959 do_set_pad_size(cdata, 0, 0, 0);
6960 cdata->_orig_file_x_size = 0;
6961 cdata->_orig_file_y_size = 0;
6962 cdata->_loaded_from_image =
false;
6963 cdata->_loaded_from_txo =
false;
6964 cdata->_has_read_pages =
false;
6965 cdata->_has_read_mipmaps =
false;
6972 do_set_format(CData *cdata, Texture::Format format) {
6973 if (format == cdata->_format) {
6976 cdata->_format = format;
6977 cdata->inc_properties_modified();
6979 switch (cdata->_format) {
6981 case F_depth_stencil:
6982 case F_depth_component:
6983 case F_depth_component16:
6984 case F_depth_component24:
6985 case F_depth_component32:
6997 cdata->_num_components = 1;
7000 case F_luminance_alpha:
7001 case F_luminance_alphamask:
7003 case F_sluminance_alpha:
7009 cdata->_num_components = 2;
7025 cdata->_num_components = 3;
7041 cdata->_num_components = 4;
7050 do_set_component_type(CData *cdata, Texture::ComponentType component_type) {
7051 cdata->_component_type = component_type;
7053 switch (component_type) {
7054 case T_unsigned_byte:
7056 cdata->_component_width = 1;
7059 case T_unsigned_short:
7062 cdata->_component_width = 2;
7066 case T_unsigned_int_24_8:
7068 case T_unsigned_int:
7069 cdata->_component_width = 4;
7078 do_set_x_size(CData *cdata,
int x_size) {
7079 if (cdata->_x_size != x_size) {
7080 cdata->_x_size = x_size;
7081 cdata->inc_image_modified();
7082 do_clear_ram_image(cdata);
7083 do_set_pad_size(cdata, 0, 0, 0);
7091 do_set_y_size(CData *cdata,
int y_size) {
7092 if (cdata->_y_size != y_size) {
7093 nassertv((cdata->_texture_type != Texture::TT_buffer_texture &&
7094 cdata->_texture_type != Texture::TT_1d_texture) || y_size == 1);
7095 cdata->_y_size = y_size;
7096 cdata->inc_image_modified();
7097 do_clear_ram_image(cdata);
7098 do_set_pad_size(cdata, 0, 0, 0);
7107 do_set_z_size(CData *cdata,
int z_size) {
7108 if (cdata->_z_size != z_size) {
7109 nassertv((cdata->_texture_type == Texture::TT_3d_texture) ||
7110 (cdata->_texture_type == Texture::TT_cube_map && z_size == 6) ||
7111 (cdata->_texture_type == Texture::TT_cube_map_array && z_size % 6 == 0) ||
7112 (cdata->_texture_type == Texture::TT_2d_texture_array) || (z_size == 1));
7113 cdata->_z_size = z_size;
7114 cdata->inc_image_modified();
7115 do_clear_ram_image(cdata);
7116 do_set_pad_size(cdata, 0, 0, 0);
7124 do_set_num_views(CData *cdata,
int num_views) {
7125 nassertv(num_views >= 1);
7126 if (cdata->_num_views != num_views) {
7127 cdata->_num_views = num_views;
7128 if (do_has_ram_image(cdata)) {
7129 cdata->inc_image_modified();
7130 do_clear_ram_image(cdata);
7132 do_set_pad_size(cdata, 0, 0, 0);
7140 do_set_wrap_u(CData *cdata, SamplerState::WrapMode wrap) {
7141 if (cdata->_default_sampler.get_wrap_u() != wrap) {
7142 cdata->inc_properties_modified();
7143 cdata->_default_sampler.set_wrap_u(wrap);
7151 do_set_wrap_v(CData *cdata, SamplerState::WrapMode wrap) {
7152 if (cdata->_default_sampler.get_wrap_v() != wrap) {
7153 cdata->inc_properties_modified();
7154 cdata->_default_sampler.set_wrap_v(wrap);
7162 do_set_wrap_w(CData *cdata, SamplerState::WrapMode wrap) {
7163 if (cdata->_default_sampler.get_wrap_w() != wrap) {
7164 cdata->inc_properties_modified();
7165 cdata->_default_sampler.set_wrap_w(wrap);
7173 do_set_minfilter(CData *cdata, SamplerState::FilterType filter) {
7174 if (cdata->_default_sampler.get_minfilter() != filter) {
7175 cdata->inc_properties_modified();
7176 cdata->_default_sampler.set_minfilter(filter);
7184 do_set_magfilter(CData *cdata, SamplerState::FilterType filter) {
7185 if (cdata->_default_sampler.get_magfilter() != filter) {
7186 cdata->inc_properties_modified();
7187 cdata->_default_sampler.set_magfilter(filter);
7195 do_set_anisotropic_degree(CData *cdata,
int anisotropic_degree) {
7196 if (cdata->_default_sampler.get_anisotropic_degree() != anisotropic_degree) {
7197 cdata->inc_properties_modified();
7198 cdata->_default_sampler.set_anisotropic_degree(anisotropic_degree);
7206 do_set_border_color(CData *cdata,
const LColor &color) {
7207 if (cdata->_default_sampler.get_border_color() != color) {
7208 cdata->inc_properties_modified();
7209 cdata->_default_sampler.set_border_color(color);
7217 do_set_compression(CData *cdata, Texture::CompressionMode compression) {
7218 if (cdata->_compression != compression) {
7219 cdata->inc_properties_modified();
7220 cdata->_compression = compression;
7222 if (do_has_ram_image(cdata)) {
7224 bool has_ram_image_compression = (cdata->_ram_image_compression != CM_off);
7239 do_set_quality_level(CData *cdata, Texture::QualityLevel quality_level) {
7240 if (cdata->_quality_level != quality_level) {
7241 cdata->inc_properties_modified();
7242 cdata->_quality_level = quality_level;
7250 do_has_compression(
const CData *cdata)
const {
7251 if (cdata->_compression == CM_default) {
7252 return compressed_textures;
7254 return (cdata->_compression != CM_off);
7263 do_has_ram_image(
const CData *cdata)
const {
7264 return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty();
7272 do_has_uncompressed_ram_image(
const CData *cdata)
const {
7273 return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty() && cdata->_ram_image_compression == CM_off;
7280 do_get_ram_image(CData *cdata) {
7281 if (!do_has_ram_image(cdata) && do_can_reload(cdata)) {
7282 do_reload_ram_image(cdata,
true);
7284 if (do_has_ram_image(cdata)) {
7288 cdata->inc_image_modified();
7289 cdata->inc_properties_modified();
7293 if (cdata->_ram_images.empty()) {
7297 return cdata->_ram_images[0]._image;
7304 do_get_uncompressed_ram_image(CData *cdata) {
7305 if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
7308 if (do_uncompress_ram_image(cdata)) {
7309 if (gobj_cat.is_debug()) {
7311 <<
"Uncompressed " << get_name() <<
"\n";
7313 return cdata->_ram_images[0]._image;
7318 if ((!do_has_ram_image(cdata) || cdata->_ram_image_compression != CM_off) && do_can_reload(cdata)) {
7319 do_reload_ram_image(cdata,
false);
7322 if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
7324 if (do_uncompress_ram_image(cdata)) {
7326 <<
"Uncompressed " << get_name() <<
"\n";
7327 return cdata->_ram_images[0]._image;
7331 if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
7335 return cdata->_ram_images[0]._image;
7364 string format =
upcase(requested_format);
7367 CPTA_uchar data = do_get_uncompressed_ram_image(cdata);
7368 if (data ==
nullptr) {
7369 gobj_cat.error() <<
"Couldn't find an uncompressed RAM image!\n";
7372 int imgsize = cdata->_x_size * cdata->_y_size;
7373 nassertr(cdata->_num_components > 0 && cdata->_num_components <= 4,
CPTA_uchar(get_class_type()));
7374 nassertr(data.size() == (
size_t)(cdata->_component_width * cdata->_num_components * imgsize),
CPTA_uchar(get_class_type()));
7377 if ((cdata->_num_components == 1 && format.size() == 1) ||
7378 (cdata->_num_components == 2 && format.size() == 2 && format.at(1) ==
'A' && format.at(0) !=
'A') ||
7379 (cdata->_num_components == 3 && format ==
"BGR") ||
7380 (cdata->_num_components == 4 && format ==
"BGRA")) {
7388 alpha = cdata->_num_components - 1;
7392 for (
size_t i = 0; i < format.size(); ++i) {
7393 if (format[i] !=
'B' && format[i] !=
'G' && format[i] !=
'R' &&
7394 format[i] !=
'A' && format[i] !=
'0' && format[i] !=
'1') {
7395 gobj_cat.error() <<
"Unexpected component character '"
7396 << format[i] <<
"', expected one of RGBA01!\n";
7402 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * format.size() * cdata->_component_width, get_class_type());
7405 if (cdata->_component_width == 1) {
7406 if (format ==
"RGBA" && cdata->_num_components == 4) {
7407 const uint32_t *src = (
const uint32_t *)data.p();
7408 uint32_t *dst = (uint32_t *)newdata.p();
7410 for (
int p = 0; p < imgsize; ++p) {
7411 uint32_t v = *src++;
7412 *dst++ = ((v & 0xff00ff00u)) |
7413 ((v & 0x00ff0000u) >> 16) |
7414 ((v & 0x000000ffu) << 16);
7418 if (format ==
"RGB" && cdata->_num_components == 4) {
7419 const uint32_t *src = (
const uint32_t *)data.p();
7420 uint32_t *dst = (uint32_t *)newdata.p();
7424 int blocks = imgsize >> 2;
7425 for (
int i = 0; i < blocks; ++i) {
7426 uint32_t v0 = *src++;
7427 uint32_t v1 = *src++;
7428 uint32_t v2 = *src++;
7429 uint32_t v3 = *src++;
7430 *dst++ = ((v0 & 0x00ff0000u) >> 16) |
7431 ((v0 & 0x0000ff00u)) |
7432 ((v0 & 0x000000ffu) << 16) |
7433 ((v1 & 0x00ff0000u) << 8);
7434 *dst++ = ((v1 & 0x0000ff00u) >> 8) |
7435 ((v1 & 0x000000ffu) << 8) |
7436 ((v2 & 0x00ff0000u)) |
7437 ((v2 & 0x0000ff00u) << 16);
7438 *dst++ = ((v2 & 0x000000ffu)) |
7439 ((v3 & 0x00ff0000u) >> 8) |
7440 ((v3 & 0x0000ff00u) << 8) |
7441 ((v3 & 0x000000ffu) << 24);
7446 uint8_t *tail = (uint8_t *)dst;
7447 for (
int i = (imgsize & ~0x3); i < imgsize; ++i) {
7448 uint32_t v = *src++;
7449 *tail++ = (v & 0x00ff0000u) >> 16;
7450 *tail++ = (v & 0x0000ff00u) >> 8;
7451 *tail++ = (v & 0x000000ffu);
7455 if (format ==
"BGR" && cdata->_num_components == 4) {
7456 const uint32_t *src = (
const uint32_t *)data.p();
7457 uint32_t *dst = (uint32_t *)newdata.p();
7461 int blocks = imgsize >> 2;
7462 for (
int i = 0; i < blocks; ++i) {
7463 uint32_t v0 = *src++;
7464 uint32_t v1 = *src++;
7465 uint32_t v2 = *src++;
7466 uint32_t v3 = *src++;
7467 *dst++ = (v0 & 0x00ffffffu) | ((v1 & 0x000000ffu) << 24);
7468 *dst++ = ((v1 & 0x00ffff00u) >> 8) | ((v2 & 0x0000ffffu) << 16);
7469 *dst++ = ((v2 & 0x00ff0000u) >> 16) | ((v3 & 0x00ffffffu) << 8);
7474 uint8_t *tail = (uint8_t *)dst;
7475 for (
int i = (imgsize & ~0x3); i < imgsize; ++i) {
7476 uint32_t v = *src++;
7477 *tail++ = (v & 0x000000ffu);
7478 *tail++ = (v & 0x0000ff00u) >> 8;
7479 *tail++ = (v & 0x00ff0000u) >> 16;
7483 const uint8_t *src = (
const uint8_t *)data.p();
7484 uint8_t *dst = (uint8_t *)newdata.p();
7486 if (format ==
"RGB" && cdata->_num_components == 3) {
7487 for (
int i = 0; i < imgsize; ++i) {
7495 if (format ==
"A" && cdata->_num_components != 3) {
7497 for (
int p = 0; p < imgsize; ++p) {
7498 dst[p] = src[alpha];
7499 src += cdata->_num_components;
7504 for (
int p = 0; p < imgsize; ++p) {
7505 for (
size_t i = 0; i < format.size(); ++i) {
7506 if (format[i] ==
'B' || (cdata->_num_components <= 2 && format[i] !=
'A')) {
7508 }
else if (format[i] ==
'G') {
7510 }
else if (format[i] ==
'R') {
7512 }
else if (format[i] ==
'A') {
7514 *dst++ = src[alpha];
7518 }
else if (format[i] ==
'1') {
7524 src += cdata->_num_components;
7530 for (
int p = 0; p < imgsize; ++p) {
7531 for (
size_t i = 0; i < format.size(); ++i) {
7533 if (format[i] ==
'B' || (cdata->_num_components <= 2 && format[i] !=
'A')) {
7535 }
else if (format[i] ==
'G') {
7537 }
else if (format[i] ==
'R') {
7539 }
else if (format[i] ==
'A') {
7543 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), -1, cdata->_component_width);
7546 }
else if (format[i] ==
'1') {
7547 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), -1, cdata->_component_width);
7550 memset((
void*)(newdata + (p * format.size() + i) * cdata->_component_width), 0, cdata->_component_width);
7553 memcpy((
void*)(newdata + (p * format.size() + i) * cdata->_component_width),
7554 (
void*)(data + (p * cdata->_num_components + component) * cdata->_component_width),
7555 cdata->_component_width);
7565 do_set_simple_ram_image(CData *cdata,
CPTA_uchar image,
int x_size,
int y_size) {
7566 nassertv(cdata->_texture_type == TT_2d_texture);
7567 size_t expected_page_size = (size_t)(x_size * y_size * 4);
7568 nassertv(image.size() == expected_page_size);
7570 cdata->_simple_x_size = x_size;
7571 cdata->_simple_y_size = y_size;
7573 cdata->_simple_ram_image._page_size = image.size();
7574 cdata->_simple_image_date_generated = (int32_t)time(
nullptr);
7575 cdata->inc_simple_image_modified();
7582 do_get_expected_num_mipmap_levels(
const CData *cdata)
const {
7583 if (cdata->_texture_type == Texture::TT_buffer_texture) {
7586 int size = max(cdata->_x_size, cdata->_y_size);
7587 if (cdata->_texture_type == Texture::TT_3d_texture) {
7588 size = max(size, cdata->_z_size);
7602 do_get_ram_mipmap_page_size(
const CData *cdata,
int n)
const {
7603 if (cdata->_ram_image_compression != CM_off) {
7604 if (n >= 0 && n < (
int)cdata->_ram_images.size()) {
7605 return cdata->_ram_images[n]._page_size;
7609 return do_get_expected_ram_mipmap_page_size(cdata, n);
7617 do_get_expected_mipmap_x_size(
const CData *cdata,
int n)
const {
7618 int size = max(cdata->_x_size, 1);
7619 while (n > 0 && size > 1) {
7630 do_get_expected_mipmap_y_size(
const CData *cdata,
int n)
const {
7631 int size = max(cdata->_y_size, 1);
7632 while (n > 0 && size > 1) {
7643 do_get_expected_mipmap_z_size(
const CData *cdata,
int n)
const {
7647 if (cdata->_texture_type == Texture::TT_3d_texture) {
7648 int size = max(cdata->_z_size, 1);
7649 while (n > 0 && size > 1) {
7656 return cdata->_z_size;
7664 do_clear_simple_ram_image(CData *cdata) {
7665 cdata->_simple_x_size = 0;
7666 cdata->_simple_y_size = 0;
7667 cdata->_simple_ram_image._image.clear();
7668 cdata->_simple_ram_image._page_size = 0;
7669 cdata->_simple_image_date_generated = 0;
7674 cdata->inc_simple_image_modified();
7681 do_clear_ram_mipmap_images(CData *cdata) {
7682 if (!cdata->_ram_images.empty()) {
7683 cdata->_ram_images.erase(cdata->_ram_images.begin() + 1, cdata->_ram_images.end());
7693 do_generate_ram_mipmap_images(CData *cdata,
bool allow_recompress) {
7694 nassertv(do_has_ram_image(cdata));
7696 if (do_get_expected_num_mipmap_levels(cdata) == 1) {
7701 RamImage orig_compressed_image;
7702 CompressionMode orig_compression_mode = CM_off;
7704 if (cdata->_ram_image_compression != CM_off) {
7708 orig_compressed_image = cdata->_ram_images[0];
7709 orig_compression_mode = cdata->_ram_image_compression;
7712 do_get_uncompressed_ram_image(cdata);
7714 if (cdata->_ram_image_compression != CM_off) {
7716 <<
"Cannot generate mipmap levels for image with compression "
7717 << cdata->_ram_image_compression <<
"\n";
7722 do_clear_ram_mipmap_images(cdata);
7724 if (gobj_cat.is_debug()) {
7726 <<
"Generating mipmap levels for " << *
this <<
"\n";
7729 if (cdata->_texture_type == Texture::TT_3d_texture && cdata->_z_size != 1) {
7731 int x_size = cdata->_x_size;
7732 int y_size = cdata->_y_size;
7733 int z_size = cdata->_z_size;
7735 while (x_size > 1 || y_size > 1 || z_size > 1) {
7736 cdata->_ram_images.push_back(RamImage());
7737 do_filter_3d_mipmap_level(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
7738 x_size, y_size, z_size);
7739 x_size = max(x_size >> 1, 1);
7740 y_size = max(y_size >> 1, 1);
7741 z_size = max(z_size >> 1, 1);
7747 int x_size = cdata->_x_size;
7748 int y_size = cdata->_y_size;
7750 while (x_size > 1 || y_size > 1) {
7751 cdata->_ram_images.push_back(RamImage());
7752 do_filter_2d_mipmap_pages(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
7754 x_size = max(x_size >> 1, 1);
7755 y_size = max(y_size >> 1, 1);
7760 if (orig_compression_mode != CM_off && allow_recompress) {
7766 nassertv(cdata->_ram_images.size() > 1);
7767 int l0_x_size = cdata->_x_size;
7768 int l0_y_size = cdata->_y_size;
7769 int l0_z_size = cdata->_z_size;
7770 cdata->_x_size = do_get_expected_mipmap_x_size(cdata, 1);
7771 cdata->_y_size = do_get_expected_mipmap_y_size(cdata, 1);
7772 cdata->_z_size = do_get_expected_mipmap_z_size(cdata, 1);
7773 RamImage uncompressed_image = cdata->_ram_images[0];
7774 cdata->_ram_images.erase(cdata->_ram_images.begin());
7776 bool success = do_compress_ram_image(cdata, orig_compression_mode, QL_default,
nullptr);
7779 if (gobj_cat.is_debug()) {
7781 <<
"Compressed " << get_name() <<
" generated mipmaps with "
7782 << cdata->_ram_image_compression <<
"\n";
7784 cdata->_ram_images.insert(cdata->_ram_images.begin(), orig_compressed_image);
7786 cdata->_ram_images.insert(cdata->_ram_images.begin(), uncompressed_image);
7788 cdata->_x_size = l0_x_size;
7789 cdata->_y_size = l0_y_size;
7790 cdata->_z_size = l0_z_size;
7798 do_set_pad_size(CData *cdata,
int x,
int y,
int z) {
7799 if (x > cdata->_x_size) {
7802 if (y > cdata->_y_size) {
7805 if (z > cdata->_z_size) {
7809 cdata->_pad_x_size = x;
7810 cdata->_pad_y_size = y;
7811 cdata->_pad_z_size = z;
7820 do_can_reload(
const CData *cdata)
const {
7821 return (cdata->_loaded_from_image && !cdata->_fullpath.empty());
7828 do_reload(CData *cdata) {
7829 if (do_can_reload(cdata)) {
7830 do_clear_ram_image(cdata);
7831 do_reload_ram_image(cdata,
true);
7832 if (do_has_ram_image(cdata)) {
7834 cdata->inc_image_modified();
7850 do_has_bam_rawdata(
const CData *cdata)
const {
7851 return do_has_ram_image(cdata);
7859 do_get_bam_rawdata(CData *cdata) {
7860 do_get_ram_image(cdata);
7868 convert_from_pnmimage(PTA_uchar &image,
size_t page_size,
7869 int row_stride,
int x,
int y,
int z,
7870 const PNMImage &pnmimage,
int num_components,
7871 int component_width) {
7875 int pixel_size = num_components * component_width;
7878 if (row_stride == 0) {
7879 row_stride = x_size;
7881 row_skip = (row_stride - x_size) * pixel_size;
7882 nassertv(row_skip >= 0);
7885 bool is_grayscale = (num_components == 1 || num_components == 2);
7886 bool has_alpha = (num_components == 2 || num_components == 4);
7887 bool img_has_alpha = pnmimage.
has_alpha();
7889 int idx = page_size * z;
7890 nassertv(idx + page_size <= image.size());
7891 unsigned char *p = &image[idx];
7893 if (x != 0 || y != 0) {
7894 p += (row_stride * y + x) * pixel_size;
7897 if (maxval == 255 && component_width == 1) {
7902 switch (num_components) {
7904 for (
int j = y_size-1; j >= 0; j--) {
7905 const xel *row = array + j * x_size;
7906 for (
int i = 0; i < x_size; i++) {
7907 *p++ = (uchar)PPM_GETB(row[i]);
7914 if (img_has_alpha) {
7916 for (
int j = y_size-1; j >= 0; j--) {
7917 const xel *row = array + j * x_size;
7918 const xelval *alpha_row = alpha + j * x_size;
7919 for (
int i = 0; i < x_size; i++) {
7920 *p++ = (uchar)PPM_GETB(row[i]);
7921 *p++ = (uchar)alpha_row[i];
7926 for (
int j = y_size-1; j >= 0; j--) {
7927 const xel *row = array + j * x_size;
7928 for (
int i = 0; i < x_size; i++) {
7929 *p++ = (uchar)PPM_GETB(row[i]);
7938 for (
int j = y_size-1; j >= 0; j--) {
7939 const xel *row = array + j * x_size;
7940 for (
int i = 0; i < x_size; i++) {
7941 *p++ = (uchar)PPM_GETB(row[i]);
7942 *p++ = (uchar)PPM_GETG(row[i]);
7943 *p++ = (uchar)PPM_GETR(row[i]);
7950 if (img_has_alpha) {
7952 for (
int j = y_size-1; j >= 0; j--) {
7953 const xel *row = array + j * x_size;
7954 const xelval *alpha_row = alpha + j * x_size;
7955 for (
int i = 0; i < x_size; i++) {
7956 *p++ = (uchar)PPM_GETB(row[i]);
7957 *p++ = (uchar)PPM_GETG(row[i]);
7958 *p++ = (uchar)PPM_GETR(row[i]);
7959 *p++ = (uchar)alpha_row[i];
7964 for (
int j = y_size-1; j >= 0; j--) {
7965 const xel *row = array + j * x_size;
7966 for (
int i = 0; i < x_size; i++) {
7967 *p++ = (uchar)PPM_GETB(row[i]);
7968 *p++ = (uchar)PPM_GETG(row[i]);
7969 *p++ = (uchar)PPM_GETR(row[i]);
7978 nassertv(num_components >= 1 && num_components <= 4);
7982 }
else if (maxval == 65535 && component_width == 2) {
7985 for (
int j = y_size-1; j >= 0; j--) {
7986 for (
int i = 0; i < x_size; i++) {
7992 store_unscaled_short(p, pnmimage.
get_red_val(i, j));
7995 if (img_has_alpha) {
7998 store_unscaled_short(p, 65535);
8005 }
else if (component_width == 1) {
8009 double scale = 255.0 / (double)maxval;
8011 for (
int j = y_size-1; j >= 0; j--) {
8012 for (
int i = 0; i < x_size; i++) {
8014 store_scaled_byte(p, pnmimage.
get_gray_val(i, j), scale);
8016 store_scaled_byte(p, pnmimage.
get_blue_val(i, j), scale);
8018 store_scaled_byte(p, pnmimage.
get_red_val(i, j), scale);
8021 if (img_has_alpha) {
8024 store_unscaled_byte(p, 255);
8034 double scale = 65535.0 / (double)maxval;
8036 for (
int j = y_size-1; j >= 0; j--) {
8037 for (
int i = 0; i < x_size; i++) {
8039 store_scaled_short(p, pnmimage.
get_gray_val(i, j), scale);
8041 store_scaled_short(p, pnmimage.
get_blue_val(i, j), scale);
8043 store_scaled_short(p, pnmimage.
get_red_val(i, j), scale);
8046 if (img_has_alpha) {
8049 store_unscaled_short(p, 65535);
8063 convert_from_pfm(PTA_uchar &image,
size_t page_size,
int z,
8064 const PfmFile &pfm,
int num_components,
int component_width) {
8065 nassertv(component_width == 4);
8069 int idx = page_size * z;
8070 nassertv(idx + page_size <= image.size());
8071 PN_float32 *p = (PN_float32 *)&image[idx];
8073 switch (num_components) {
8076 for (
int j = y_size-1; j >= 0; j--) {
8077 for (
int i = 0; i < x_size; i++) {
8087 for (
int j = y_size-1; j >= 0; j--) {
8088 for (
int i = 0; i < x_size; i++) {
8100 for (
int j = y_size-1; j >= 0; j--) {
8101 for (
int i = 0; i < x_size; i++) {
8114 for (
int j = y_size-1; j >= 0; j--) {
8115 for (
int i = 0; i < x_size; i++) {
8127 nassert_raise(
"unexpected channel count");
8131 nassertv((
unsigned char *)p == &image[idx] + page_size);
8139 convert_to_pnmimage(
PNMImage &pnmimage,
int x_size,
int y_size,
8140 int num_components, ComponentType component_type,
8141 bool is_srgb,
CPTA_uchar image,
size_t page_size,
int z) {
8142 xelval maxval = 0xff;
8143 if (component_type != T_unsigned_byte && component_type != T_byte) {
8146 ColorSpace color_space =
is_srgb ? CS_sRGB : CS_linear;
8147 pnmimage.
clear(x_size, y_size, num_components, maxval,
nullptr, color_space);
8151 int idx = page_size * z;
8152 nassertr(idx + page_size <= image.size(),
false);
8157 switch (component_type) {
8158 case T_unsigned_byte:
8160 const unsigned char *p = &image[idx];
8162 for (
int j = y_size-1; j >= 0; j--) {
8163 xel *row = array + j * x_size;
8164 xelval *alpha_row = alpha + j * x_size;
8165 for (
int i = 0; i < x_size; i++) {
8166 PPM_PUTB(row[i], *p++);
8167 alpha_row[i] = *p++;
8171 for (
int j = y_size-1; j >= 0; j--) {
8172 xel *row = array + j * x_size;
8173 for (
int i = 0; i < x_size; i++) {
8174 PPM_PUTB(row[i], *p++);
8178 nassertr(p == &image[idx] + page_size,
false);
8180 const unsigned char *p = &image[idx];
8182 for (
int j = y_size-1; j >= 0; j--) {
8183 xel *row = array + j * x_size;
8184 xelval *alpha_row = alpha + j * x_size;
8185 for (
int i = 0; i < x_size; i++) {
8186 PPM_PUTB(row[i], *p++);
8187 PPM_PUTG(row[i], *p++);
8188 PPM_PUTR(row[i], *p++);
8189 alpha_row[i] = *p++;
8193 for (
int j = y_size-1; j >= 0; j--) {
8194 xel *row = array + j * x_size;
8195 for (
int i = 0; i < x_size; i++) {
8196 PPM_PUTB(row[i], *p++);
8197 PPM_PUTG(row[i], *p++);
8198 PPM_PUTR(row[i], *p++);
8202 nassertr(p == &image[idx] + page_size,
false);
8206 case T_unsigned_short:
8208 const uint16_t *p = (
const uint16_t *)&image[idx];
8210 for (
int j = y_size-1; j >= 0; j--) {
8211 xel *row = array + j * x_size;
8212 xelval *alpha_row = alpha + j * x_size;
8213 for (
int i = 0; i < x_size; i++) {
8214 PPM_PUTB(row[i], *p++);
8215 if (!is_grayscale) {
8216 PPM_PUTG(row[i], *p++);
8217 PPM_PUTR(row[i], *p++);
8220 alpha_row[i] = *p++;
8224 nassertr((
const unsigned char *)p == &image[idx] + page_size,
false);
8228 case T_unsigned_int:
8230 const uint32_t *p = (
const uint32_t *)&image[idx];
8232 for (
int j = y_size-1; j >= 0; j--) {
8233 xel *row = array + j * x_size;
8234 xelval *alpha_row = alpha + j * x_size;
8235 for (
int i = 0; i < x_size; i++) {
8236 PPM_PUTB(row[i], (*p++) >> 16u);
8237 if (!is_grayscale) {
8238 PPM_PUTG(row[i], (*p++) >> 16u);
8239 PPM_PUTR(row[i], (*p++) >> 16u);
8242 alpha_row[i] = (*p++) >> 16u;
8246 nassertr((
const unsigned char *)p == &image[idx] + page_size,
false);
8252 const unsigned char *p = &image[idx];
8254 for (
int j = y_size-1; j >= 0; j--) {
8255 for (
int i = 0; i < x_size; i++) {
8256 pnmimage.
set_blue(i, j, get_half_float(p));
8257 if (!is_grayscale) {
8258 pnmimage.
set_green(i, j, get_half_float(p));
8259 pnmimage.
set_red(i, j, get_half_float(p));
8262 pnmimage.
set_alpha(i, j, get_half_float(p));
8266 nassertr(p == &image[idx] + page_size,
false);
8282 convert_to_pfm(
PfmFile &pfm,
int x_size,
int y_size,
8283 int num_components,
int component_width,
8285 nassertr(component_width == 4,
false);
8286 pfm.
clear(x_size, y_size, num_components);
8288 int idx = page_size * z;
8289 nassertr(idx + page_size <= image.size(),
false);
8290 const PN_float32 *p = (
const PN_float32 *)&image[idx];
8292 switch (num_components) {
8294 for (
int j = y_size-1; j >= 0; j--) {
8295 for (
int i = 0; i < x_size; i++) {
8303 for (
int j = y_size-1; j >= 0; j--) {
8304 for (
int i = 0; i < x_size; i++) {
8314 for (
int j = y_size-1; j >= 0; j--) {
8315 for (
int i = 0; i < x_size; i++) {
8326 for (
int j = y_size-1; j >= 0; j--) {
8327 for (
int i = 0; i < x_size; i++) {
8338 nassert_raise(
"unexpected channel count");
8342 nassertr((
unsigned char *)p == &image[idx] + page_size,
false);
8350 read_dds_level_bgr8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8352 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8353 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8355 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8356 size_t row_bytes = x_size * 3;
8357 PTA_uchar image = PTA_uchar::empty_array(size);
8358 for (
int y = y_size - 1; y >= 0; --y) {
8359 unsigned char *p = image.p() + y * row_bytes;
8360 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8361 in.read((
char *)p, row_bytes);
8371 read_dds_level_rgb8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8373 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8374 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8376 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8377 size_t row_bytes = x_size * 3;
8378 PTA_uchar image = PTA_uchar::empty_array(size);
8379 for (
int y = y_size - 1; y >= 0; --y) {
8380 unsigned char *p = image.p() + y * row_bytes;
8381 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8382 in.read((
char *)p, row_bytes);
8385 for (
int x = 0; x < x_size; ++x) {
8386 unsigned char r = p[0];
8391 nassertr(p <= image.p() + size, PTA_uchar());
8401 read_dds_level_abgr8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8403 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8404 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8406 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8407 size_t row_bytes = x_size * 4;
8408 PTA_uchar image = PTA_uchar::empty_array(size);
8409 for (
int y = y_size - 1; y >= 0; --y) {
8410 unsigned char *p = image.p() + y * row_bytes;
8411 in.read((
char *)p, row_bytes);
8413 uint32_t *pw = (uint32_t *)p;
8414 for (
int x = 0; x < x_size; ++x) {
8416 #ifdef WORDS_BIGENDIAN
8418 w = ((w & 0xff00) << 16) | ((w & 0xff000000U) >> 16) | (w & 0xff00ff);
8421 w = ((w & 0xff) << 16) | ((w & 0xff0000) >> 16) | (w & 0xff00ff00U);
8426 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8436 read_dds_level_rgba8(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8438 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8439 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8441 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8442 size_t row_bytes = x_size * 4;
8443 PTA_uchar image = PTA_uchar::empty_array(size);
8444 for (
int y = y_size - 1; y >= 0; --y) {
8445 unsigned char *p = image.p() + y * row_bytes;
8446 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
8447 in.read((
char *)p, row_bytes);
8457 read_dds_level_abgr16(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8459 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8460 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8462 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8463 size_t row_bytes = x_size * 8;
8464 PTA_uchar image = PTA_uchar::empty_array(size);
8465 for (
int y = y_size - 1; y >= 0; --y) {
8466 unsigned char *p = image.p() + y * row_bytes;
8467 in.read((
char *)p, row_bytes);
8469 uint16_t *pw = (uint16_t *)p;
8470 for (
int x = 0; x < x_size; ++x) {
8474 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8484 read_dds_level_abgr32(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8486 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8487 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8489 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8490 size_t row_bytes = x_size * 16;
8491 nassertr(row_bytes * y_size == size, PTA_uchar());
8492 PTA_uchar image = PTA_uchar::empty_array(size);
8493 for (
int y = y_size - 1; y >= 0; --y) {
8494 unsigned char *p = image.p() + y * row_bytes;
8495 in.read((
char *)p, row_bytes);
8497 uint32_t *pw = (uint32_t *)p;
8498 for (
int x = 0; x < x_size; ++x) {
8502 nassertr((
unsigned char *)pw <= image.p() + size, PTA_uchar());
8512 read_dds_level_raw(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8513 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8514 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8516 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8517 size_t row_bytes = x_size * cdata->_num_components * cdata->_component_width;
8518 nassertr(row_bytes * y_size == size, PTA_uchar());
8519 PTA_uchar image = PTA_uchar::empty_array(size);
8520 for (
int y = y_size - 1; y >= 0; --y) {
8521 unsigned char *p = image.p() + y * row_bytes;
8522 in.read((
char *)p, row_bytes);
8533 read_dds_level_generic_uncompressed(
Texture *tex, CData *cdata,
const DDSHeader &header,
8534 int n, istream &in) {
8535 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8536 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8538 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
8545 pitch = ((pitch + 3) / 4) * 4;
8546 if (header.dds_flags & DDSD_PITCH) {
8547 pitch = header.pitch;
8551 int bpp = header.pf.rgb_bitcount / 8;
8552 int skip_bytes = pitch - (bpp * x_size);
8553 nassertr(skip_bytes >= 0, PTA_uchar());
8555 unsigned int r_mask = header.pf.r_mask;
8556 unsigned int g_mask = header.pf.g_mask;
8557 unsigned int b_mask = header.pf.b_mask;
8558 unsigned int a_mask = header.pf.a_mask;
8569 unsigned int r_scale = 0;
8571 r_scale = 0xff000000 / (r_mask >> r_shift);
8573 unsigned int g_scale = 0;
8575 g_scale = 0xff000000 / (g_mask >> g_shift);
8577 unsigned int b_scale = 0;
8579 b_scale = 0xff000000 / (b_mask >> b_shift);
8581 unsigned int a_scale = 0;
8583 a_scale = 0xff000000 / (a_mask >> a_shift);
8586 bool add_alpha =
has_alpha(cdata->_format);
8588 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8589 size_t row_bytes = x_size * cdata->_num_components;
8590 PTA_uchar image = PTA_uchar::empty_array(size);
8591 for (
int y = y_size - 1; y >= 0; --y) {
8592 unsigned char *p = image.p() + y * row_bytes;
8593 for (
int x = 0; x < x_size; ++x) {
8596 unsigned int pixel = 0;
8598 for (
int bi = 0; bi < bpp; ++bi) {
8599 unsigned int ch = (
unsigned char)in.get();
8600 pixel |= (ch << shift);
8605 unsigned int r = (((
pixel & r_mask) >> r_shift) * r_scale) >> 24;
8606 unsigned int g = (((
pixel & g_mask) >> g_shift) * g_scale) >> 24;
8607 unsigned int b = (((
pixel & b_mask) >> b_shift) * b_scale) >> 24;
8610 store_unscaled_byte(p, b);
8611 store_unscaled_byte(p, g);
8612 store_unscaled_byte(p, r);
8614 unsigned int a = (((
pixel & a_mask) >> a_shift) * a_scale) >> 24;
8615 store_unscaled_byte(p, a);
8618 nassertr(p <= image.p() + size, PTA_uchar());
8619 for (
int bi = 0; bi < skip_bytes; ++bi) {
8632 read_dds_level_luminance_uncompressed(
Texture *tex, CData *cdata,
const DDSHeader &header,
8633 int n, istream &in) {
8634 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8635 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8637 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
8644 pitch = ((pitch + 3) / 4) * 4;
8645 if (header.dds_flags & DDSD_PITCH) {
8646 pitch = header.pitch;
8650 int bpp = header.pf.rgb_bitcount / 8;
8651 int skip_bytes = pitch - (bpp * x_size);
8652 nassertr(skip_bytes >= 0, PTA_uchar());
8654 unsigned int r_mask = header.pf.r_mask;
8655 unsigned int a_mask = header.pf.a_mask;
8664 unsigned int r_scale = 0;
8666 r_scale = 0xff000000 / (r_mask >> r_shift);
8668 unsigned int a_scale = 0;
8670 a_scale = 0xff000000 / (a_mask >> a_shift);
8673 bool add_alpha =
has_alpha(cdata->_format);
8675 size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
8676 size_t row_bytes = x_size * cdata->_num_components;
8677 PTA_uchar image = PTA_uchar::empty_array(size);
8678 for (
int y = y_size - 1; y >= 0; --y) {
8679 unsigned char *p = image.p() + y * row_bytes;
8680 for (
int x = 0; x < x_size; ++x) {
8683 unsigned int pixel = 0;
8685 for (
int bi = 0; bi < bpp; ++bi) {
8686 unsigned int ch = (
unsigned char)in.get();
8687 pixel |= (ch << shift);
8691 unsigned int r = (((
pixel & r_mask) >> r_shift) * r_scale) >> 24;
8694 store_unscaled_byte(p, r);
8696 unsigned int a = (((
pixel & a_mask) >> a_shift) * a_scale) >> 24;
8697 store_unscaled_byte(p, a);
8700 nassertr(p <= image.p() + size, PTA_uchar());
8701 for (
int bi = 0; bi < skip_bytes; ++bi) {
8713 read_dds_level_bc1(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8714 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8715 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8717 static const int div = 4;
8718 static const int block_bytes = 8;
8722 int num_cols = max(div, x_size) / div;
8723 int num_rows = max(div, y_size) / div;
8724 int row_length = num_cols * block_bytes;
8725 int linear_size = row_length * num_rows;
8728 if (header.dds_flags & DDSD_LINEARSIZE) {
8729 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8733 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8739 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8740 unsigned char *p = image.p() + row_length * ri;
8741 in.read((
char *)p, row_length);
8743 for (
int ci = 0; ci < num_cols; ++ci) {
8746 uint32_t *cells = (uint32_t *)p;
8747 uint32_t w = cells[1];
8748 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8755 }
else if (y_size >= 2) {
8757 unsigned char *p = image.p();
8758 in.read((
char *)p, row_length);
8760 for (
int ci = 0; ci < num_cols; ++ci) {
8761 uint32_t *cells = (uint32_t *)p;
8762 uint32_t w = cells[1];
8763 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8769 }
else if (y_size >= 1) {
8771 unsigned char *p = image.p();
8772 in.read((
char *)p, row_length);
8782 read_dds_level_bc2(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8783 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8784 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8786 static const int div = 4;
8787 static const int block_bytes = 16;
8792 int num_cols = max(div, x_size) / div;
8793 int num_rows = max(div, y_size) / div;
8794 int row_length = num_cols * block_bytes;
8795 int linear_size = row_length * num_rows;
8798 if (header.dds_flags & DDSD_LINEARSIZE) {
8799 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8803 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8809 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8810 unsigned char *p = image.p() + row_length * ri;
8811 in.read((
char *)p, row_length);
8813 for (
int ci = 0; ci < num_cols; ++ci) {
8816 uint32_t *cells = (uint32_t *)p;
8819 uint32_t w0 = cells[0];
8820 uint32_t w1 = cells[1];
8821 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8822 w1 = ((w1 & 0xffff) << 16) | ((w1 & 0xffff0000U) >> 16);
8828 uint32_t w = cells[3];
8829 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8836 }
else if (y_size >= 2) {
8838 unsigned char *p = image.p();
8839 in.read((
char *)p, row_length);
8841 for (
int ci = 0; ci < num_cols; ++ci) {
8842 uint32_t *cells = (uint32_t *)p;
8844 uint32_t w0 = cells[0];
8845 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8848 uint32_t w = cells[3];
8849 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8855 }
else if (y_size >= 1) {
8857 unsigned char *p = image.p();
8858 in.read((
char *)p, row_length);
8868 read_dds_level_bc3(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8869 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8870 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8872 static const int div = 4;
8873 static const int block_bytes = 16;
8878 int num_cols = max(div, x_size) / div;
8879 int num_rows = max(div, y_size) / div;
8880 int row_length = num_cols * block_bytes;
8881 int linear_size = row_length * num_rows;
8884 if (header.dds_flags & DDSD_LINEARSIZE) {
8885 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8889 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8895 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8896 unsigned char *p = image.p() + row_length * ri;
8897 in.read((
char *)p, row_length);
8899 for (
int ci = 0; ci < num_cols; ++ci) {
8902 uint32_t *cells = (uint32_t *)p;
8906 unsigned char p2 = p[2];
8907 unsigned char p3 = p[3];
8908 unsigned char p4 = p[4];
8909 unsigned char p5 = p[5];
8910 unsigned char p6 = p[6];
8911 unsigned char p7 = p[7];
8913 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
8914 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
8915 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
8916 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
8917 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
8918 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
8922 uint32_t w = cells[3];
8923 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
8930 }
else if (y_size >= 2) {
8932 unsigned char *p = image.p();
8933 in.read((
char *)p, row_length);
8935 for (
int ci = 0; ci < num_cols; ++ci) {
8936 uint32_t *cells = (uint32_t *)p;
8938 unsigned char p2 = p[2];
8939 unsigned char p3 = p[3];
8940 unsigned char p4 = p[4];
8942 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
8943 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
8944 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
8946 uint32_t w0 = cells[0];
8947 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
8950 uint32_t w = cells[3];
8951 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
8957 }
else if (y_size >= 1) {
8959 unsigned char *p = image.p();
8960 in.read((
char *)p, row_length);
8970 read_dds_level_bc4(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
8971 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
8972 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
8974 static const int div = 4;
8975 static const int block_bytes = 8;
8979 int num_cols = max(div, x_size) / div;
8980 int num_rows = max(div, y_size) / div;
8981 int row_length = num_cols * block_bytes;
8982 int linear_size = row_length * num_rows;
8985 if (header.dds_flags & DDSD_LINEARSIZE) {
8986 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
8990 PTA_uchar image = PTA_uchar::empty_array(linear_size);
8996 for (
int ri = num_rows - 1; ri >= 0; --ri) {
8997 unsigned char *p = image.p() + row_length * ri;
8998 in.read((
char *)p, row_length);
9000 for (
int ci = 0; ci < num_cols; ++ci) {
9005 unsigned char p2 = p[2];
9006 unsigned char p3 = p[3];
9007 unsigned char p4 = p[4];
9008 unsigned char p5 = p[5];
9009 unsigned char p6 = p[6];
9010 unsigned char p7 = p[7];
9012 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
9013 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
9014 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
9015 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9016 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9017 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9023 }
else if (y_size >= 2) {
9025 unsigned char *p = image.p();
9026 in.read((
char *)p, row_length);
9028 for (
int ci = 0; ci < num_cols; ++ci) {
9029 unsigned char p2 = p[2];
9030 unsigned char p3 = p[3];
9031 unsigned char p4 = p[4];
9033 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9034 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9035 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9040 }
else if (y_size >= 1) {
9042 unsigned char *p = image.p();
9043 in.read((
char *)p, row_length);
9053 read_dds_level_bc5(
Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in) {
9054 int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
9055 int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
9059 int num_cols = max(4, x_size) / 2;
9060 int num_rows = max(4, y_size) / 4;
9061 int row_length = num_cols * 8;
9062 int linear_size = row_length * num_rows;
9065 if (header.dds_flags & DDSD_LINEARSIZE) {
9066 nassertr(linear_size == (
int)header.pitch, PTA_uchar());
9070 PTA_uchar image = PTA_uchar::empty_array(linear_size);
9076 for (
int ri = num_rows - 1; ri >= 0; --ri) {
9077 unsigned char *p = image.p() + row_length * ri;
9078 in.read((
char *)p, row_length);
9080 for (
int ci = 0; ci < num_cols; ++ci) {
9085 unsigned char p2 = p[2];
9086 unsigned char p3 = p[3];
9087 unsigned char p4 = p[4];
9088 unsigned char p5 = p[5];
9089 unsigned char p6 = p[6];
9090 unsigned char p7 = p[7];
9092 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
9093 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
9094 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
9095 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9096 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9097 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9103 }
else if (y_size >= 2) {
9105 unsigned char *p = image.p();
9106 in.read((
char *)p, row_length);
9108 for (
int ci = 0; ci < num_cols; ++ci) {
9109 unsigned char p2 = p[2];
9110 unsigned char p3 = p[3];
9111 unsigned char p4 = p[4];
9113 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
9114 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
9115 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
9120 }
else if (y_size >= 1) {
9122 unsigned char *p = image.p();
9123 in.read((
char *)p, row_length);
9137 PreparedViews::iterator pvi;
9138 pvi = _prepared_views.find(prepared_objects);
9139 if (pvi != _prepared_views.end()) {
9140 Contexts &contexts = (*pvi).second;
9141 Contexts::iterator ci;
9142 ci = contexts.find(view);
9143 if (ci != contexts.end()) {
9147 if (contexts.empty()) {
9148 _prepared_views.erase(pvi);
9158 consider_downgrade(
PNMImage &pnmimage,
int num_channels,
const string &name) {
9167 <<
"Downgrading " << name <<
" from "
9169 << num_channels <<
".\n";
9194 for (
int yi = 0; yi < a.
get_y_size(); ++yi) {
9195 const xel *a_row = a_array + yi * x_size;
9196 const xel *b_row = b_array + yi * x_size;
9197 const xelval *a_alpha_row = a_alpha + yi * x_size;
9198 const xelval *b_alpha_row = b_alpha + yi * x_size;
9199 for (
int xi = 0; xi < x_size; ++xi) {
9200 delta += abs(PPM_GETR(a_row[xi]) - PPM_GETR(b_row[xi]));
9201 delta += abs(PPM_GETG(a_row[xi]) - PPM_GETG(b_row[xi]));
9202 delta += abs(PPM_GETB(a_row[xi]) - PPM_GETB(b_row[xi]));
9203 delta += abs(a_alpha_row[xi] - b_alpha_row[xi]);
9208 return (average_delta <= simple_image_threshold);
9221 do_filter_2d_mipmap_pages(
const CData *cdata,
9222 Texture::RamImage &to,
const Texture::RamImage &from,
9223 int x_size,
int y_size)
const {
9224 Filter2DComponent *filter_component;
9225 Filter2DComponent *filter_alpha;
9227 if (
is_srgb(cdata->_format)) {
9230 nassertv(cdata->_component_type == T_unsigned_byte);
9232 if (has_sse2_sRGB_encode()) {
9233 filter_component = &filter_2d_unsigned_byte_srgb_sse2;
9235 filter_component = &filter_2d_unsigned_byte_srgb;
9239 filter_alpha = &filter_2d_unsigned_byte;
9242 switch (cdata->_component_type) {
9243 case T_unsigned_byte:
9244 filter_component = &filter_2d_unsigned_byte;
9247 case T_unsigned_short:
9248 filter_component = &filter_2d_unsigned_short;
9252 filter_component = &filter_2d_float;
9257 <<
"Unable to generate mipmaps for 2D texture with component type "
9258 << cdata->_component_type <<
"!";
9261 filter_alpha = filter_component;
9264 size_t pixel_size = cdata->_num_components * cdata->_component_width;
9265 size_t row_size = (size_t)x_size * pixel_size;
9267 int to_x_size = max(x_size >> 1, 1);
9268 int to_y_size = max(y_size >> 1, 1);
9270 size_t to_row_size = (size_t)to_x_size * pixel_size;
9271 to._page_size = (size_t)to_y_size * to_row_size;
9272 to._image = PTA_uchar::empty_array(to._page_size * cdata->_z_size * cdata->_num_views, get_class_type());
9275 int num_color_components = cdata->_num_components;
9277 --num_color_components;
9280 int num_pages = cdata->_z_size * cdata->_num_views;
9281 for (
int z = 0; z < num_pages; ++z) {
9283 unsigned char *p = to._image.p() + z * to._page_size;
9284 nassertv(p <= to._image.p() + to._image.size() + to._page_size);
9285 const unsigned char *q = from._image.p() + z * from._page_size;
9286 nassertv(q <= from._image.p() + from._image.size() + from._page_size);
9289 for (y = 0; y < y_size - 1; y += 2) {
9291 nassertv(p == to._image.p() + z * to._page_size + (y / 2) * to_row_size);
9292 nassertv(q == from._image.p() + z * from._page_size + y * row_size);
9295 for (x = 0; x < x_size - 1; x += 2) {
9297 for (
int c = 0; c < num_color_components; ++c) {
9299 filter_component(p, q, pixel_size, row_size);
9302 filter_alpha(p, q, pixel_size, row_size);
9312 for (
int c = 0; c < num_color_components; ++c) {
9314 filter_component(p, q, 0, row_size);
9317 filter_alpha(p, q, 0, row_size);
9331 for (x = 0; x < x_size - 1; x += 2) {
9333 for (
int c = 0; c < num_color_components; ++c) {
9335 filter_component(p, q, pixel_size, 0);
9338 filter_alpha(p, q, pixel_size, 0);
9348 for (
int c = 0; c < num_color_components; ++c) {
9350 filter_component(p, q, 0, 0);
9353 filter_alpha(p, q, pixel_size, 0);
9358 nassertv(p == to._image.p() + (z + 1) * to._page_size);
9359 nassertv(q == from._image.p() + (z + 1) * from._page_size);
9373 do_filter_3d_mipmap_level(
const CData *cdata,
9374 Texture::RamImage &to,
const Texture::RamImage &from,
9375 int x_size,
int y_size,
int z_size)
const {
9376 Filter3DComponent *filter_component;
9377 Filter3DComponent *filter_alpha;
9379 if (
is_srgb(cdata->_format)) {
9382 nassertv(cdata->_component_type == T_unsigned_byte);
9384 if (has_sse2_sRGB_encode()) {
9385 filter_component = &filter_3d_unsigned_byte_srgb_sse2;
9387 filter_component = &filter_3d_unsigned_byte_srgb;
9391 filter_alpha = &filter_3d_unsigned_byte;
9394 switch (cdata->_component_type) {
9395 case T_unsigned_byte:
9396 filter_component = &filter_3d_unsigned_byte;
9399 case T_unsigned_short:
9400 filter_component = &filter_3d_unsigned_short;
9404 filter_component = &filter_3d_float;
9409 <<
"Unable to generate mipmaps for 3D texture with component type "
9410 << cdata->_component_type <<
"!";
9413 filter_alpha = filter_component;
9416 size_t pixel_size = cdata->_num_components * cdata->_component_width;
9417 size_t row_size = (size_t)x_size * pixel_size;
9418 size_t page_size = (size_t)y_size * row_size;
9419 size_t view_size = (size_t)z_size * page_size;
9421 int to_x_size = max(x_size >> 1, 1);
9422 int to_y_size = max(y_size >> 1, 1);
9423 int to_z_size = max(z_size >> 1, 1);
9425 size_t to_row_size = (size_t)to_x_size * pixel_size;
9426 size_t to_page_size = (size_t)to_y_size * to_row_size;
9427 size_t to_view_size = (size_t)to_z_size * to_page_size;
9428 to._page_size = to_page_size;
9429 to._image = PTA_uchar::empty_array(to_page_size * to_z_size * cdata->_num_views, get_class_type());
9432 int num_color_components = cdata->_num_components;
9434 --num_color_components;
9437 for (
int view = 0; view < cdata->_num_views; ++view) {
9438 unsigned char *start_to = to._image.p() + view * to_view_size;
9439 const unsigned char *start_from = from._image.p() + view * view_size;
9440 nassertv(start_to + to_view_size <= to._image.p() + to._image.size());
9441 nassertv(start_from + view_size <= from._image.p() + from._image.size());
9442 unsigned char *p = start_to;
9443 const unsigned char *q = start_from;
9446 for (z = 0; z < z_size - 1; z += 2) {
9448 nassertv(p == start_to + (z / 2) * to_page_size);
9449 nassertv(q == start_from + z * page_size);
9452 for (y = 0; y < y_size - 1; y += 2) {
9454 nassertv(p == start_to + (z / 2) * to_page_size + (y / 2) * to_row_size);
9455 nassertv(q == start_from + z * page_size + y * row_size);
9458 for (x = 0; x < x_size - 1; x += 2) {
9460 for (
int c = 0; c < num_color_components; ++c) {
9462 filter_component(p, q, pixel_size, row_size, page_size);
9465 filter_alpha(p, q, pixel_size, row_size, page_size);
9475 for (
int c = 0; c < num_color_components; ++c) {
9477 filter_component(p, q, 0, row_size, page_size);
9480 filter_alpha(p, q, 0, row_size, page_size);
9494 for (x = 0; x < x_size - 1; x += 2) {
9496 for (
int c = 0; c < num_color_components; ++c) {
9498 filter_component(p, q, pixel_size, 0, page_size);
9501 filter_alpha(p, q, pixel_size, 0, page_size);
9511 for (
int c = 0; c < num_color_components; ++c) {
9513 filter_component(p, q, 0, 0, page_size);
9516 filter_alpha(p, q, 0, 0, page_size);
9530 for (y = 0; y < y_size - 1; y += 2) {
9532 nassertv(p == start_to + (y / 2) * to_row_size);
9533 nassertv(q == start_from + y * row_size);
9536 for (x = 0; x < x_size - 1; x += 2) {
9538 for (
int c = 0; c < num_color_components; ++c) {
9540 filter_component(p, q, pixel_size, row_size, 0);
9543 filter_alpha(p, q, pixel_size, row_size, 0);
9553 for (
int c = 0; c < num_color_components; ++c) {
9555 filter_component(p, q, 0, row_size, 0);
9558 filter_alpha(p, q, 0, row_size, 0);
9572 for (x = 0; x < x_size - 1; x += 2) {
9574 for (
int c = 0; c < num_color_components; ++c) {
9576 filter_component(p, q, pixel_size, 0, 0);
9579 filter_alpha(p, q, pixel_size, 0, 0);
9589 for (
int c = 0; c < num_color_components; ++c) {
9591 filter_component(p, q, 0, 0, 0);
9594 filter_alpha(p, q, 0, 0, 0);
9600 nassertv(p == start_to + to_z_size * to_page_size);
9601 nassertv(q == start_from + z_size * page_size);
9610 filter_2d_unsigned_byte(
unsigned char *&p,
const unsigned char *&q,
9611 size_t pixel_size,
size_t row_size) {
9612 unsigned int result = ((
unsigned int)q[0] +
9613 (
unsigned int)q[pixel_size] +
9614 (
unsigned int)q[row_size] +
9615 (
unsigned int)q[pixel_size + row_size]) >> 2;
9616 *p = (
unsigned char)result;
9626 filter_2d_unsigned_byte_srgb(
unsigned char *&p,
const unsigned char *&q,
9627 size_t pixel_size,
size_t row_size) {
9643 filter_2d_unsigned_byte_srgb_sse2(
unsigned char *&p,
const unsigned char *&q,
9644 size_t pixel_size,
size_t row_size) {
9650 *p = encode_sRGB_uchar_sse2(result * 0.25f);
9660 filter_2d_unsigned_short(
unsigned char *&p,
const unsigned char *&q,
9661 size_t pixel_size,
size_t row_size) {
9662 unsigned int result = ((
unsigned int)*(
unsigned short *)&q[0] +
9663 (
unsigned int)*(
unsigned short *)&q[pixel_size] +
9664 (
unsigned int)*(
unsigned short *)&q[row_size] +
9665 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size]) >> 2;
9666 store_unscaled_short(p, result);
9675 filter_2d_float(
unsigned char *&p,
const unsigned char *&q,
9676 size_t pixel_size,
size_t row_size) {
9677 *(
float *)p = (*(
float *)&q[0] +
9678 *(
float *)&q[pixel_size] +
9679 *(
float *)&q[row_size] +
9680 *(
float *)&q[pixel_size + row_size]) / 4.0f;
9691 filter_3d_unsigned_byte(
unsigned char *&p,
const unsigned char *&q,
9692 size_t pixel_size,
size_t row_size,
size_t page_size) {
9693 unsigned int result = ((
unsigned int)q[0] +
9694 (
unsigned int)q[pixel_size] +
9695 (
unsigned int)q[row_size] +
9696 (
unsigned int)q[pixel_size + row_size] +
9697 (
unsigned int)q[page_size] +
9698 (
unsigned int)q[pixel_size + page_size] +
9699 (
unsigned int)q[row_size + page_size] +
9700 (
unsigned int)q[pixel_size + row_size + page_size]) >> 3;
9701 *p = (
unsigned char)result;
9712 filter_3d_unsigned_byte_srgb(
unsigned char *&p,
const unsigned char *&q,
9713 size_t pixel_size,
size_t row_size,
size_t page_size) {
9734 filter_3d_unsigned_byte_srgb_sse2(
unsigned char *&p,
const unsigned char *&q,
9735 size_t pixel_size,
size_t row_size,
size_t page_size) {
9745 *p = encode_sRGB_uchar_sse2(result * 0.125f);
9756 filter_3d_unsigned_short(
unsigned char *&p,
const unsigned char *&q,
9757 size_t pixel_size,
size_t row_size,
9759 unsigned int result = ((
unsigned int)*(
unsigned short *)&q[0] +
9760 (
unsigned int)*(
unsigned short *)&q[pixel_size] +
9761 (
unsigned int)*(
unsigned short *)&q[row_size] +
9762 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size] +
9763 (
unsigned int)*(
unsigned short *)&q[page_size] +
9764 (
unsigned int)*(
unsigned short *)&q[pixel_size + page_size] +
9765 (
unsigned int)*(
unsigned short *)&q[row_size + page_size] +
9766 (
unsigned int)*(
unsigned short *)&q[pixel_size + row_size + page_size]) >> 3;
9767 store_unscaled_short(p, result);
9777 filter_3d_float(
unsigned char *&p,
const unsigned char *&q,
9778 size_t pixel_size,
size_t row_size,
size_t page_size) {
9779 *(
float *)p = (*(
float *)&q[0] +
9780 *(
float *)&q[pixel_size] +
9781 *(
float *)&q[row_size] +
9782 *(
float *)&q[pixel_size + row_size] +
9783 *(
float *)&q[page_size] +
9784 *(
float *)&q[pixel_size + page_size] +
9785 *(
float *)&q[row_size + page_size] +
9786 *(
float *)&q[pixel_size + row_size + page_size]) / 8.0f;
9795 do_squish(CData *cdata, Texture::CompressionMode compression,
int squish_flags) {
9797 if (!do_has_all_ram_mipmap_images(cdata)) {
9800 do_generate_ram_mipmap_images(cdata,
false);
9803 RamImages compressed_ram_images;
9804 compressed_ram_images.reserve(cdata->_ram_images.size());
9805 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
9806 RamImage compressed_image;
9807 int x_size = do_get_expected_mipmap_x_size(cdata, n);
9808 int y_size = do_get_expected_mipmap_y_size(cdata, n);
9809 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
9810 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
9811 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
9813 compressed_image._page_size = page_size;
9814 compressed_image._image = PTA_uchar::empty_array(page_size * num_pages);
9815 for (
int z = 0; z < num_pages; ++z) {
9816 unsigned char *dest_page = compressed_image._image.p() + z * page_size;
9817 unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * cdata->_ram_images[n]._page_size;
9818 unsigned const char *source_page_end = source_page + cdata->_ram_images[n]._page_size;
9820 unsigned char *d = dest_page;
9821 for (
int y = 0; y < y_size; y += 4) {
9822 for (
int x = 0; x < x_size; x += 4) {
9823 unsigned char tb[16 * 4];
9825 unsigned char *t = tb;
9826 for (
int i = 0; i < 16; ++i) {
9829 unsigned const char *s = source_page + (yi * x_size + xi) * cdata->_num_components;
9830 if (s < source_page_end) {
9831 switch (cdata->_num_components) {
9864 squish::CompressMasked(tb, mask, d, squish_flags);
9870 compressed_ram_images.push_back(compressed_image);
9872 cdata->_ram_images.swap(compressed_ram_images);
9873 cdata->_ram_image_compression = compression;
9886 do_unsquish(CData *cdata,
int squish_flags) {
9888 RamImages uncompressed_ram_images;
9889 uncompressed_ram_images.reserve(cdata->_ram_images.size());
9890 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
9891 RamImage uncompressed_image;
9892 int x_size = do_get_expected_mipmap_x_size(cdata, n);
9893 int y_size = do_get_expected_mipmap_y_size(cdata, n);
9894 int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
9895 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
9896 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
9898 uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
9899 uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * num_pages);
9900 for (
int z = 0; z < num_pages; ++z) {
9901 unsigned char *dest_page = uncompressed_image._image.p() + z * uncompressed_image._page_size;
9902 unsigned char *dest_page_end = dest_page + uncompressed_image._page_size;
9903 unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * page_size;
9905 unsigned const char *s = source_page;
9906 for (
int y = 0; y < y_size; y += 4) {
9907 for (
int x = 0; x < x_size; x += 4) {
9908 unsigned char tb[16 * 4];
9909 squish::Decompress(tb, s, squish_flags);
9912 unsigned char *t = tb;
9913 for (
int i = 0; i < 16; ++i) {
9916 unsigned char *d = dest_page + (yi * x_size + xi) * cdata->_num_components;
9917 if (d < dest_page_end) {
9918 switch (cdata->_num_components) {
9948 uncompressed_ram_images.push_back(uncompressed_image);
9950 cdata->_ram_images.swap(uncompressed_ram_images);
9951 cdata->_ram_image_compression = CM_off;
9976 bool has_rawdata =
false;
9977 do_write_datagram_header(cdata, manager, me, has_rawdata);
9978 do_write_datagram_body(cdata, manager, me);
9982 do_write_datagram_rawdata(cdata, manager, me);
10020 do_write_datagram_header(CData *cdata,
BamWriter *manager,
Datagram &me,
bool &has_rawdata) {
10029 has_rawdata = (file_texture_mode == BamWriter::BTM_rawdata ||
10030 (cdata->_filename.empty() && do_has_bam_rawdata(cdata)));
10031 if (has_rawdata && !do_has_bam_rawdata(cdata)) {
10032 do_get_bam_rawdata(cdata);
10033 if (!do_has_bam_rawdata(cdata)) {
10035 has_rawdata =
false;
10041 Filename filename = cdata->_filename;
10042 Filename alpha_filename = cdata->_alpha_filename;
10046 switch (file_texture_mode) {
10047 case BamWriter::BTM_unchanged:
10048 case BamWriter::BTM_rawdata:
10051 case BamWriter::BTM_fullpath:
10052 filename = cdata->_fullpath;
10053 alpha_filename = cdata->_alpha_fullpath;
10056 case BamWriter::BTM_relative:
10057 filename = cdata->_fullpath;
10058 alpha_filename = cdata->_alpha_fullpath;
10063 if (gobj_cat.is_debug()) {
10065 <<
"Texture file " << cdata->_fullpath
10066 <<
" found as " << filename <<
"\n";
10071 if (gobj_cat.is_debug()) {
10073 <<
"Alpha image " << cdata->_alpha_fullpath
10074 <<
" found as " << alpha_filename <<
"\n";
10078 case BamWriter::BTM_basename:
10080 alpha_filename = cdata->_alpha_fullpath.
get_basename();
10085 <<
"Unsupported bam-texture-mode: " << (int)file_texture_mode <<
"\n";
10088 if (filename.empty()) {
10089 if (do_has_bam_rawdata(cdata) || cdata->_has_clear_color) {
10091 has_rawdata =
true;
10098 me.
add_uint8(cdata->_primary_file_num_channels);
10099 me.
add_uint8(cdata->_alpha_file_channel);
10103 cdata->_texture_type == TT_cube_map) {
10112 me.
add_bool(cdata->_has_read_mipmaps);
10123 cdata->_default_sampler.write_datagram(me);
10141 if (cdata->_texture_type == TT_buffer_texture) {
10146 me.
add_uint8(cdata->_auto_texture_scale);
10158 me.
add_int32(cdata->_simple_image_date_generated);
10159 me.
add_uint32(cdata->_simple_ram_image._image.size());
10160 me.
append_data(cdata->_simple_ram_image._image, cdata->_simple_ram_image._image.size());
10164 me.
add_bool(cdata->_has_clear_color);
10165 if (cdata->_has_clear_color) {
10166 cdata->_clear_color.write_datagram(me);
10191 me.
add_uint8(cdata->_ram_image_compression);
10193 if (cdata->_ram_images.empty() && cdata->_has_clear_color &&
10197 int image_size = do_get_expected_ram_image_size(cdata);
10199 me.
add_uint32(do_get_expected_ram_page_size(cdata));
10203 unsigned char pixel[16];
10204 const int pixel_size = do_get_clear_data(cdata,
pixel);
10205 nassertv(pixel_size > 0);
10207 for (
int i = 0; i < image_size; i += pixel_size) {
10211 me.
add_uint8(cdata->_ram_images.size());
10212 for (
size_t n = 0; n < cdata->_ram_images.size(); ++n) {
10213 me.
add_uint32(cdata->_ram_images[n]._page_size);
10214 me.
add_uint32(cdata->_ram_images[n]._image.size());
10215 me.
append_data(cdata->_ram_images[n]._image, cdata->_ram_images[n]._image.size());
10226 return dummy->make_this_from_bam(params);
10253 int primary_file_num_channels = scan.
get_uint8();
10254 int alpha_file_channel = scan.
get_uint8();
10255 bool has_rawdata = scan.
get_bool();
10256 TextureType texture_type = (TextureType)scan.
get_uint8();
10260 if (texture_type == TT_2d_texture_array) {
10261 texture_type = TT_cube_map;
10264 bool has_read_mipmaps =
false;
10266 has_read_mipmaps = scan.
get_bool();
10276 me->set_name(name);
10277 CDWriter cdata_me(me->_cycler,
true);
10278 cdata_me->_filename = filename;
10279 cdata_me->_alpha_filename = alpha_filename;
10280 cdata_me->_primary_file_num_channels = primary_file_num_channels;
10281 cdata_me->_alpha_file_channel = alpha_file_channel;
10282 cdata_me->_texture_type = texture_type;
10283 cdata_me->_has_read_mipmaps = has_read_mipmaps;
10286 me->do_fillin_body(cdata_me, scan, manager);
10287 me->do_fillin_rawdata(cdata_me, scan, manager);
10299 AutoTextureScale auto_texture_scale = ATS_unspecified;
10301 CDWriter cdata_dummy(dummy->_cycler,
true);
10302 dummy->do_fillin_body(cdata_dummy, scan, manager);
10303 auto_texture_scale = cdata_dummy->_auto_texture_scale;
10306 if (filename.empty()) {
10310 <<
"Cannot create texture '" << name <<
"' with no filename.\n";
10320 if (!alpha_filename.empty()) {
10327 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
10331 switch (texture_type) {
10332 case TT_buffer_texture:
10333 case TT_1d_texture:
10334 case TT_2d_texture:
10335 case TT_1d_texture_array:
10336 if (alpha_filename.empty()) {
10338 has_read_mipmaps, options);
10341 primary_file_num_channels,
10342 alpha_file_channel,
10343 has_read_mipmaps, options);
10347 case TT_3d_texture:
10351 case TT_2d_texture_array:
10352 case TT_cube_map_array:
10362 if (me !=
nullptr) {
10363 me->set_name(name);
10364 CDWriter cdata_me(me->_cycler,
true);
10365 me->do_fillin_from(cdata_me, dummy);
10382 cdata->_default_sampler.read_datagram(scan, manager);
10385 cdata->_compression = (CompressionMode)scan.
get_uint8();
10388 cdata->_quality_level = (QualityLevel)scan.
get_uint8();
10391 cdata->_format = (Format)scan.
get_uint8();
10392 cdata->_num_components = scan.
get_uint8();
10394 if (cdata->_texture_type == TT_buffer_texture) {
10395 cdata->_usage_hint = (GeomEnums::UsageHint)scan.
get_uint8();
10398 cdata->inc_properties_modified();
10400 cdata->_auto_texture_scale = ATS_unspecified;
10402 cdata->_auto_texture_scale = (AutoTextureScale)scan.
get_uint8();
10407 cdata->_orig_file_x_size = scan.
get_uint32();
10408 cdata->_orig_file_y_size = scan.
get_uint32();
10416 cdata->_simple_image_date_generated = scan.
get_int32();
10423 <<
"simple RAM image extends past end of datagram, is texture corrupt?\n";
10427 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
10430 cdata->_simple_ram_image._image = image;
10431 cdata->_simple_ram_image._page_size = u_size;
10432 cdata->inc_simple_image_modified();
10436 cdata->_has_clear_color = scan.
get_bool();
10437 if (cdata->_has_clear_color) {
10438 cdata->_clear_color.read_datagram(scan);
10458 do_set_pad_size(cdata, 0, 0, 0);
10461 cdata->_num_views = 1;
10465 cdata->_component_type = (ComponentType)scan.
get_uint8();
10466 cdata->_component_width = scan.
get_uint8();
10467 cdata->_ram_image_compression = CM_off;
10469 cdata->_ram_image_compression = (CompressionMode)scan.
get_uint8();
10472 int num_ram_images = 1;
10477 cdata->_ram_images.clear();
10478 cdata->_ram_images.reserve(num_ram_images);
10479 for (
int n = 0; n < num_ram_images; ++n) {
10480 cdata->_ram_images.push_back(RamImage());
10483 cdata->_ram_images[n]._page_size = scan.
get_uint32();
10492 <<
"RAM image " << n <<
" extends past end of datagram, is texture corrupt?\n";
10496 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
10499 cdata->_ram_images[n]._image = image;
10501 cdata->_loaded_from_image =
true;
10502 cdata->inc_image_modified();
10511 do_fillin_from(CData *cdata,
const Texture *dummy) {
10518 CDReader cdata_dummy(dummy->_cycler);
10520 do_set_wrap_u(cdata, cdata_dummy->_default_sampler.get_wrap_u());
10521 do_set_wrap_v(cdata, cdata_dummy->_default_sampler.get_wrap_v());
10522 do_set_wrap_w(cdata, cdata_dummy->_default_sampler.get_wrap_w());
10523 do_set_border_color(cdata, cdata_dummy->_default_sampler.get_border_color());
10525 if (cdata_dummy->_default_sampler.get_minfilter() != SamplerState::FT_default) {
10526 do_set_minfilter(cdata, cdata_dummy->_default_sampler.get_minfilter());
10528 if (cdata_dummy->_default_sampler.get_magfilter() != SamplerState::FT_default) {
10529 do_set_magfilter(cdata, cdata_dummy->_default_sampler.get_magfilter());
10531 if (cdata_dummy->_default_sampler.get_anisotropic_degree() != 0) {
10532 do_set_anisotropic_degree(cdata, cdata_dummy->_default_sampler.get_anisotropic_degree());
10534 if (cdata_dummy->_compression != CM_default) {
10535 do_set_compression(cdata, cdata_dummy->_compression);
10537 if (cdata_dummy->_quality_level != QL_default) {
10538 do_set_quality_level(cdata, cdata_dummy->_quality_level);
10541 Format format = cdata_dummy->_format;
10542 int num_components = cdata_dummy->_num_components;
10544 if (num_components == cdata->_num_components) {
10548 do_set_format(cdata, format);
10551 if (!cdata_dummy->_simple_ram_image._image.empty()) {
10554 if (cdata->_simple_ram_image._image.empty() ||
10555 cdata_dummy->_simple_image_date_generated > cdata->_simple_image_date_generated) {
10556 do_set_simple_ram_image(cdata,
10557 cdata_dummy->_simple_ram_image._image,
10558 cdata_dummy->_simple_x_size,
10559 cdata_dummy->_simple_y_size);
10560 cdata->_simple_image_date_generated = cdata_dummy->_simple_image_date_generated;
10570 _primary_file_num_channels = 0;
10571 _alpha_file_channel = 0;
10572 _keep_ram_image =
true;
10573 _compression = CM_default;
10574 _auto_texture_scale = ATS_unspecified;
10575 _ram_image_compression = CM_off;
10576 _render_to_texture =
false;
10577 _match_framebuffer_format =
false;
10578 _post_load_store_cache =
false;
10579 _quality_level = QL_default;
10581 _texture_type = TT_2d_texture;
10593 _usage_hint = GeomEnums::UH_unspecified;
10599 _orig_file_x_size = 0;
10600 _orig_file_y_size = 0;
10602 _loaded_from_image =
false;
10603 _loaded_from_txo =
false;
10604 _has_read_pages =
false;
10605 _has_read_mipmaps =
false;
10606 _num_mipmap_levels_read = 0;
10608 _simple_x_size = 0;
10609 _simple_y_size = 0;
10610 _simple_ram_image._page_size = 0;
10612 _has_clear_color =
false;
10619 CData(
const Texture::CData ©) {
10620 _num_mipmap_levels_read = 0;
10624 _properties_modified = copy._properties_modified;
10625 _image_modified = copy._image_modified;
10626 _simple_image_modified = copy._simple_image_modified;
10633 make_copy()
const {
10634 return new CData(*
this);
10640 void Texture::CData::
10641 do_assign(
const Texture::CData *copy) {
10642 _filename = copy->_filename;
10643 _alpha_filename = copy->_alpha_filename;
10644 if (!copy->_fullpath.empty()) {
10647 _fullpath = copy->_fullpath;
10648 _alpha_fullpath = copy->_alpha_fullpath;
10650 _primary_file_num_channels = copy->_primary_file_num_channels;
10651 _alpha_file_channel = copy->_alpha_file_channel;
10652 _x_size = copy->_x_size;
10653 _y_size = copy->_y_size;
10654 _z_size = copy->_z_size;
10655 _num_views = copy->_num_views;
10656 _pad_x_size = copy->_pad_x_size;
10657 _pad_y_size = copy->_pad_y_size;
10658 _pad_z_size = copy->_pad_z_size;
10659 _orig_file_x_size = copy->_orig_file_x_size;
10660 _orig_file_y_size = copy->_orig_file_y_size;
10661 _num_components = copy->_num_components;
10662 _component_width = copy->_component_width;
10663 _texture_type = copy->_texture_type;
10664 _format = copy->_format;
10665 _component_type = copy->_component_type;
10666 _loaded_from_image = copy->_loaded_from_image;
10667 _loaded_from_txo = copy->_loaded_from_txo;
10668 _has_read_pages = copy->_has_read_pages;
10669 _has_read_mipmaps = copy->_has_read_mipmaps;
10670 _num_mipmap_levels_read = copy->_num_mipmap_levels_read;
10671 _default_sampler = copy->_default_sampler;
10672 _keep_ram_image = copy->_keep_ram_image;
10673 _compression = copy->_compression;
10674 _match_framebuffer_format = copy->_match_framebuffer_format;
10675 _quality_level = copy->_quality_level;
10676 _auto_texture_scale = copy->_auto_texture_scale;
10677 _ram_image_compression = copy->_ram_image_compression;
10678 _ram_images = copy->_ram_images;
10679 _simple_x_size = copy->_simple_x_size;
10680 _simple_y_size = copy->_simple_y_size;
10681 _simple_ram_image = copy->_simple_ram_image;
10688 void Texture::CData::
10696 int Texture::CData::
10705 void Texture::CData::
10713 operator << (ostream &out, Texture::TextureType tt) {
10721 operator << (ostream &out, Texture::ComponentType ct) {
10729 operator << (ostream &out, Texture::Format f) {
10737 operator << (ostream &out, Texture::CompressionMode cm) {
10745 operator << (ostream &out, Texture::QualityLevel tql) {
10753 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.