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