explicit mipmap control
This commit is contained in:
parent
020a09fc9c
commit
f803ef85ce
|
|
@ -192,7 +192,8 @@ class Loader:
|
|||
return font
|
||||
|
||||
# texture loading funcs
|
||||
def loadTexture(self, texturePath, alphaPath = None):
|
||||
def loadTexture(self, texturePath, alphaPath = None,
|
||||
readMipmaps = False):
|
||||
"""
|
||||
texturePath is a string.
|
||||
|
||||
|
|
@ -203,15 +204,15 @@ class Loader:
|
|||
assert Loader.notify.debug("Loading texture: %s" % (texturePath))
|
||||
if phaseChecker:
|
||||
phaseChecker(texturePath)
|
||||
texture = TexturePool.loadTexture(texturePath)
|
||||
texture = TexturePool.loadTexture(texturePath, 0, readMipmaps)
|
||||
else:
|
||||
assert Loader.notify.debug("Loading texture: %s %s" % (texturePath, alphaPath))
|
||||
if phaseChecker:
|
||||
phaseChecker(texturePath)
|
||||
texture = TexturePool.loadTexture(texturePath, alphaPath)
|
||||
texture = TexturePool.loadTexture(texturePath, alphaPath, 0, 0, readMipmaps)
|
||||
return texture
|
||||
|
||||
def load3DTexture(self, texturePattern):
|
||||
def load3DTexture(self, texturePattern, readMipmaps = False):
|
||||
"""
|
||||
texturePattern is a string that contains a sequence of one or
|
||||
more '#' characters, which will be filled in with the sequence
|
||||
|
|
@ -223,10 +224,10 @@ class Loader:
|
|||
assert Loader.notify.debug("Loading 3-D texture: %s" % (texturePattern))
|
||||
if phaseChecker:
|
||||
phaseChecker(texturePattern)
|
||||
texture = TexturePool.load3dTexture(texturePattern)
|
||||
texture = TexturePool.load3dTexture(texturePattern, readMipmaps)
|
||||
return texture
|
||||
|
||||
def loadCubeMap(self, texturePattern):
|
||||
def loadCubeMap(self, texturePattern, readMipmaps = False):
|
||||
"""
|
||||
texturePattern is a string that contains a sequence of one or
|
||||
more '#' characters, which will be filled in with the sequence
|
||||
|
|
@ -239,7 +240,7 @@ class Loader:
|
|||
assert Loader.notify.debug("Loading cube map: %s" % (texturePattern))
|
||||
if phaseChecker:
|
||||
phaseChecker(texturePattern)
|
||||
texture = TexturePool.loadCubeMap(texturePattern)
|
||||
texture = TexturePool.loadCubeMap(texturePattern, readMipmaps)
|
||||
return texture
|
||||
|
||||
def unloadTexture(self, texture):
|
||||
|
|
|
|||
|
|
@ -139,6 +139,16 @@ appear before they are referenced.
|
|||
alpha channels along with image file formats like JPEG that don't
|
||||
traditionally support alpha channels.
|
||||
|
||||
<Scalar> alpha-file-channel { channel }
|
||||
|
||||
This defines the channel that should be extracted from the file
|
||||
named by alpha-file to determine the alpha channel for the
|
||||
resulting channel. The default is 0, which means the grayscale
|
||||
combination of r, g, b. Otherwise, this should be the 1-based
|
||||
channel number, for instance 1, 2, or 3 for r, g, or b,
|
||||
respectively, or 4 for the alpha channel of a four-component
|
||||
image.
|
||||
|
||||
<Scalar> format { format-definition }
|
||||
|
||||
This defines the load format of the image file. The
|
||||
|
|
@ -223,6 +233,22 @@ appear before they are referenced.
|
|||
present, must be included in the same image with the color
|
||||
channel(s).
|
||||
|
||||
<Scalar> read-mipmaps { flag }
|
||||
|
||||
If this flag is nonzero, then pre-generated mipmap levels will be
|
||||
loaded along with the texture. In this case, the filename should
|
||||
contain a sequence of one or more hash mark ("#") characters,
|
||||
which will be filled in with the mipmap level number; the texture
|
||||
filename thus determines a series of images, one for each mipmap
|
||||
level. The base texture image is mipmap level 0.
|
||||
|
||||
If this flag is specified in conjunction with a 3D or cube map
|
||||
texture (as specified above), then the filename should contain two
|
||||
hash mark sequences, separated by a character such as an
|
||||
underscore, hyphen, or dot. The first sequence will be filled in
|
||||
with the mipmap level index, and the second sequence will be
|
||||
filled in with the 3D sequence or cube map face.
|
||||
|
||||
<Scalar> minfilter { filter-type }
|
||||
<Scalar> magfilter { filter-type }
|
||||
<Scalar> magfilteralpha { filter-type }
|
||||
|
|
@ -327,6 +353,12 @@ appear before they are referenced.
|
|||
<Scalar> combine-alpha-source2 { constant }
|
||||
<Scalar> combine-alpha-operand2 { src-alpha }
|
||||
|
||||
<Scalar> saved-result { flag }
|
||||
|
||||
If flag is nonzero, then it indicates that this particular texture
|
||||
stage will be supplied as the "last_saved_result" source for any
|
||||
future texture stages.
|
||||
|
||||
<Scalar> tex-gen { mode }
|
||||
|
||||
This specifies that texture coordinates for the primitives that
|
||||
|
|
|
|||
|
|
@ -929,6 +929,39 @@ get_alpha_file_channel() const {
|
|||
return _alpha_file_channel;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTexture::set_read_mipmaps
|
||||
// Access: Published
|
||||
// Description: Sets the read_mipmaps flag.
|
||||
//
|
||||
// If read_mipmaps is true, the filename should contain
|
||||
// a hash mark ('#'), which will be filled in with the
|
||||
// mipmap level number; and the texture will be defined
|
||||
// with a series of images, one for each mipmap level.
|
||||
//
|
||||
// If the filename is of a time that already requires a
|
||||
// hash mark, such as a cube map or a 3-d texture, then
|
||||
// the filename should now require two hash marks, and
|
||||
// the first one indicates the mipmap level number,
|
||||
// while the second indicates the face number or 3-d
|
||||
// level number.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggTexture::
|
||||
set_read_mipmaps(bool read_mipmaps) {
|
||||
_read_mipmaps = read_mipmaps;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTexture::get_read_mipmaps
|
||||
// Access: Published
|
||||
// Description: Returns the current setting of the read_mipmaps flag.
|
||||
// See set_read_mipmaps().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggTexture::
|
||||
get_read_mipmaps() const {
|
||||
return _read_mipmaps;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTexture::get_multitexture_sort
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ EggTexture(const string &tref_name, const string &filename)
|
|||
_border_color.set(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
_flags = 0;
|
||||
_alpha_file_channel = 0;
|
||||
_read_mipmaps = false;
|
||||
_multitexture_sort = 0;
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +104,7 @@ operator = (const EggTexture ©) {
|
|||
_alpha_filename = copy._alpha_filename;
|
||||
_alpha_fullpath = copy._alpha_fullpath;
|
||||
_alpha_file_channel = copy._alpha_file_channel;
|
||||
_read_mipmaps = copy._read_mipmaps;
|
||||
_multitexture_sort = 0;
|
||||
_combiner[0] = copy._combiner[0];
|
||||
_combiner[1] = copy._combiner[1];
|
||||
|
|
@ -144,6 +146,11 @@ write(ostream &out, int indent_level) const {
|
|||
<< get_alpha_file_channel() << " }\n";
|
||||
}
|
||||
|
||||
if (get_read_mipmaps()) {
|
||||
indent(out, indent_level + 2)
|
||||
<< "<Scalar> read-mipmaps { 1 }\n";
|
||||
}
|
||||
|
||||
if (get_texture_type() != TT_unspecified) {
|
||||
indent(out, indent_level + 2)
|
||||
<< "<Scalar> texture_type { " << get_texture_type() << " }\n";
|
||||
|
|
|
|||
|
|
@ -254,6 +254,10 @@ PUBLISHED:
|
|||
INLINE bool has_alpha_file_channel() const;
|
||||
INLINE int get_alpha_file_channel() const;
|
||||
|
||||
INLINE void set_read_mipmaps(bool read_mipmaps);
|
||||
INLINE bool get_read_mipmaps() const;
|
||||
|
||||
|
||||
void clear_multitexture();
|
||||
bool multitexture_over(EggTexture *other);
|
||||
INLINE int get_multitexture_sort() const;
|
||||
|
|
@ -312,6 +316,7 @@ private:
|
|||
Filename _alpha_filename;
|
||||
Filename _alpha_fullpath;
|
||||
int _alpha_file_channel;
|
||||
bool _read_mipmaps;
|
||||
int _multitexture_sort;
|
||||
|
||||
class SourceAndOperand {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -654,6 +654,9 @@ texture_body:
|
|||
} else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) {
|
||||
texture->set_alpha_file_channel((int)value);
|
||||
|
||||
} else if (cmp_nocase_uh(name, "read_mipmaps") == 0) {
|
||||
texture->set_read_mipmaps(((int)value) != 0);
|
||||
|
||||
} else {
|
||||
eggyywarning("Unsupported texture scalar: " + name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -886,19 +886,23 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) {
|
|||
tex = TexturePool::load_texture(egg_tex->get_fullpath(),
|
||||
egg_tex->get_alpha_fullpath(),
|
||||
wanted_channels,
|
||||
egg_tex->get_alpha_file_channel());
|
||||
egg_tex->get_alpha_file_channel(),
|
||||
egg_tex->get_read_mipmaps());
|
||||
} else {
|
||||
tex = TexturePool::load_texture(egg_tex->get_fullpath(),
|
||||
wanted_channels);
|
||||
wanted_channels,
|
||||
egg_tex->get_read_mipmaps());
|
||||
}
|
||||
break;
|
||||
|
||||
case EggTexture::TT_3d_texture:
|
||||
tex = TexturePool::load_3d_texture(egg_tex->get_fullpath());
|
||||
tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
|
||||
egg_tex->get_read_mipmaps());
|
||||
break;
|
||||
|
||||
case EggTexture::TT_cube_map:
|
||||
tex = TexturePool::load_cube_map(egg_tex->get_fullpath());
|
||||
tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
|
||||
egg_tex->get_read_mipmaps());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -470,27 +470,47 @@ reset() {
|
|||
if (is_at_least_version(1, 3)) {
|
||||
_supports_compressed_texture = true;
|
||||
|
||||
_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage1D");
|
||||
_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2D");
|
||||
_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage3D");
|
||||
_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage1D");
|
||||
_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2D");
|
||||
_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage3D");
|
||||
_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImage");
|
||||
|
||||
} else if (has_extension("GL_ARB_texture_compression")) {
|
||||
_supports_compressed_texture = true;
|
||||
|
||||
_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage1DARB");
|
||||
_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2DARB");
|
||||
_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage3DARB");
|
||||
_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage1DARB");
|
||||
_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2DARB");
|
||||
_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage3DARB");
|
||||
_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImageARB");
|
||||
}
|
||||
|
||||
if (_supports_compressed_texture) {
|
||||
if (_glCompressedTexImage2D == NULL ||
|
||||
if (_glCompressedTexImage1D == NULL ||
|
||||
_glCompressedTexImage2D == NULL ||
|
||||
_glCompressedTexImage3D == NULL ||
|
||||
_glCompressedTexSubImage1D == NULL ||
|
||||
_glCompressedTexSubImage2D == NULL ||
|
||||
_glCompressedTexSubImage3D == NULL ||
|
||||
_glGetCompressedTexImage == NULL) {
|
||||
GLCAT.warning()
|
||||
<< "Compressed textures advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
|
||||
|
|
@ -2394,77 +2414,28 @@ extract_texture_data(Texture *tex) {
|
|||
PTA_uchar image;
|
||||
size_t page_size = 0;
|
||||
|
||||
if (target == GL_TEXTURE_CUBE_MAP) {
|
||||
// A cube map, compressed or uncompressed. This we must extract
|
||||
// one page at a time.
|
||||
|
||||
// If the cube map is compressed, we assume that all the
|
||||
// compressed pages are exactly the same size. OpenGL doesn't
|
||||
// make this assumption, but it happens to be true for all
|
||||
// currently extant compression schemes, and it makes things
|
||||
// simpler for us. (It also makes things much simpler for the
|
||||
// graphics hardware, so it's likely to continue to be true for a
|
||||
// while at least.)
|
||||
|
||||
GLenum external_format = get_external_image_format(tex);
|
||||
GLenum pixel_type = get_component_type(type);
|
||||
page_size = tex->get_expected_ram_page_size();
|
||||
|
||||
if (compression != Texture::CM_off) {
|
||||
GLint image_size;
|
||||
GLP(GetTexLevelParameteriv)(page_target, 0,
|
||||
GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
|
||||
nassertr(image_size <= (int)page_size, false);
|
||||
page_size = image_size;
|
||||
}
|
||||
|
||||
image = PTA_uchar::empty_array(page_size * 6);
|
||||
|
||||
for (int z = 0; z < 6; ++z) {
|
||||
page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
|
||||
|
||||
if (compression == Texture::CM_off) {
|
||||
GLP(GetTexImage)(page_target, 0, external_format, pixel_type,
|
||||
image.p() + z * page_size);
|
||||
} else {
|
||||
_glGetCompressedTexImage(page_target, 0, image.p() + z * page_size);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (compression == Texture::CM_off) {
|
||||
// An uncompressed 1-d, 2-d, or 3-d texture.
|
||||
image = PTA_uchar::empty_array(tex->get_expected_ram_image_size());
|
||||
GLenum external_format = get_external_image_format(tex);
|
||||
GLenum pixel_type = get_component_type(type);
|
||||
GLP(GetTexImage)(target, 0, external_format, pixel_type, image.p());
|
||||
|
||||
} else {
|
||||
// A compressed 1-d, 2-d, or 3-d texture.
|
||||
GLint image_size;
|
||||
GLP(GetTexLevelParameteriv)(target, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
|
||||
page_size = image_size / tex->get_z_size();
|
||||
image = PTA_uchar::empty_array(image_size);
|
||||
_glGetCompressedTexImage(target, 0, image.p());
|
||||
}
|
||||
|
||||
// Now see if we were successful.
|
||||
error_code = GLP(GetError)();
|
||||
if (error_code != GL_NO_ERROR) {
|
||||
const GLubyte *error_string = GLUP(ErrorString)(error_code);
|
||||
GLCAT.error()
|
||||
<< "Unable to extract texture for " << tex->get_name();
|
||||
if (error_string != (const GLubyte *)NULL) {
|
||||
GLCAT.error(false)
|
||||
<< " : " << error_string;
|
||||
}
|
||||
GLCAT.error(false)
|
||||
<< "\n";
|
||||
|
||||
if (!extract_texture_image(image, page_size, tex, target, page_target,
|
||||
type, compression, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tex->set_ram_image(image, compression, page_size);
|
||||
|
||||
if (tex->uses_mipmaps()) {
|
||||
// Also get the mipmap levels.
|
||||
GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
|
||||
GLint highest_level = num_expected_levels;
|
||||
GLP(GetTexParameteriv)(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
|
||||
highest_level = min(highest_level, num_expected_levels);
|
||||
for (int n = 1; n <= highest_level; ++n) {
|
||||
if (!extract_texture_image(image, page_size, tex, target, page_target,
|
||||
type, compression, n)) {
|
||||
return false;
|
||||
}
|
||||
tex->set_ram_mipmap_image(n, image, page_size);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -5619,8 +5590,7 @@ do_issue_texture() {
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsStateGuardian)::
|
||||
update_standard_texture_bindings()
|
||||
{
|
||||
update_standard_texture_bindings() {
|
||||
int num_stages = _target._texture->get_num_on_stages();
|
||||
int num_old_stages = _max_texture_stages;
|
||||
if (_state._texture != (TextureAttrib *)NULL) {
|
||||
|
|
@ -6147,7 +6117,6 @@ specify_texture(Texture *tex) {
|
|||
Texture::FilterType minfilter = tex->get_minfilter();
|
||||
Texture::FilterType magfilter = tex->get_magfilter();
|
||||
bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
|
||||
Texture::CompressionMode image_compression = tex->get_ram_image_compression();
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (CLP(force_mipmaps)) {
|
||||
|
|
@ -6157,20 +6126,17 @@ specify_texture(Texture *tex) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (_supports_generate_mipmap &&
|
||||
(auto_generate_mipmaps || !tex->might_have_ram_image() ||
|
||||
image_compression != Texture::CM_off)) {
|
||||
// If the hardware can automatically generate mipmaps, ask it to
|
||||
// do so now, but only if the texture requires them.
|
||||
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
|
||||
if (!tex->might_have_ram_image()) {
|
||||
// If it's a dynamically generated texture (that is, the RAM image
|
||||
// isn't available so it didn't pass through the CPU), we should
|
||||
// enable GL-generated mipmaps here if we can.
|
||||
if (_supports_generate_mipmap) {
|
||||
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
|
||||
|
||||
} else if (!tex->might_have_ram_image()) {
|
||||
// If the hardware can't automatically generate mipmaps, but it's
|
||||
// a dynamically generated texture (that is, the RAM image isn't
|
||||
// available so it didn't pass through the CPU), then we'd better
|
||||
// not try to enable mipmap filtering, since we can't generate
|
||||
// mipmaps.
|
||||
uses_mipmaps = false;
|
||||
} else {
|
||||
// Otherwise, don't try to use mipmaps.
|
||||
uses_mipmaps = false;
|
||||
}
|
||||
}
|
||||
|
||||
GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER,
|
||||
|
|
@ -6417,53 +6383,42 @@ upload_texture(CLP(TextureContext) *gtc) {
|
|||
return false;
|
||||
}
|
||||
|
||||
size_t page_size = tex->get_ram_page_size();
|
||||
const unsigned char *image_base = image;
|
||||
|
||||
success = success && upload_texture_image
|
||||
(gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
internal_format, width, height, depth, external_format, component_type,
|
||||
image_base, page_size, image_compression);
|
||||
image_base += page_size;
|
||||
true, 0, image_compression);
|
||||
|
||||
success = success && upload_texture_image
|
||||
(gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
internal_format, width, height, depth, external_format, component_type,
|
||||
image_base, page_size, image_compression);
|
||||
image_base += page_size;
|
||||
true, 1, image_compression);
|
||||
|
||||
success = success && upload_texture_image
|
||||
(gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
internal_format, width, height, depth, external_format, component_type,
|
||||
image_base, page_size, image_compression);
|
||||
image_base += page_size;
|
||||
true, 2, image_compression);
|
||||
|
||||
success = success && upload_texture_image
|
||||
(gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
internal_format, width, height, depth, external_format, component_type,
|
||||
image_base, page_size, image_compression);
|
||||
image_base += page_size;
|
||||
true, 3, image_compression);
|
||||
|
||||
success = success && upload_texture_image
|
||||
(gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
internal_format, width, height, depth, external_format, component_type,
|
||||
image_base, page_size, image_compression);
|
||||
image_base += page_size;
|
||||
true, 4, image_compression);
|
||||
|
||||
success = success && upload_texture_image
|
||||
(gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
internal_format, width, height, depth, external_format, component_type,
|
||||
image_base, page_size, image_compression);
|
||||
image_base += page_size;
|
||||
|
||||
nassertr((size_t)(image_base - image) == image.size(), false);
|
||||
true, 5, image_compression);
|
||||
|
||||
} else {
|
||||
// Any other kind of texture can be loaded all at once.
|
||||
success = upload_texture_image
|
||||
(gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()),
|
||||
internal_format, width, height, depth, external_format, component_type,
|
||||
image, image.size(), image_compression);
|
||||
false, 0, image_compression);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
|
|
@ -6477,12 +6432,6 @@ upload_texture(CLP(TextureContext) *gtc) {
|
|||
gtc->update_data_size_bytes(get_texture_memory_size(tex));
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (uses_mipmaps && CLP(save_mipmaps)) {
|
||||
save_mipmap_images(tex);
|
||||
}
|
||||
#endif
|
||||
|
||||
report_my_gl_errors();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -6503,8 +6452,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
|
|||
GLenum target, GLint internal_format,
|
||||
int width, int height, int depth,
|
||||
GLint external_format, GLenum component_type,
|
||||
const unsigned char *image,
|
||||
size_t image_size,
|
||||
bool one_page_only, int z,
|
||||
Texture::CompressionMode image_compression) {
|
||||
// Make sure the error stack is cleared out before we begin.
|
||||
report_my_gl_errors();
|
||||
|
|
@ -6518,152 +6466,215 @@ upload_texture_image(CLP(TextureContext) *gtc,
|
|||
}
|
||||
|
||||
PStatTimer timer(_load_texture_pcollector);
|
||||
|
||||
if (uses_mipmaps) {
|
||||
#ifdef DO_PSTATS
|
||||
_data_transferred_pcollector.add_level(image_size * 4 / 3);
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
|
||||
build_phony_mipmaps(gtc->get_texture());
|
||||
report_my_gl_errors();
|
||||
return true;
|
||||
|
||||
} else
|
||||
#endif
|
||||
if (!_supports_generate_mipmap ||
|
||||
(!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
|
||||
// We only need to build the mipmaps by hand if (a) the GL
|
||||
// doesn't support generating them automatically, or (b) the
|
||||
// user has specifically requested we don't use GL's
|
||||
// auto-mipmap feature (but if the source texture image is
|
||||
// compressed, we can't build mipmaps, so we ignore
|
||||
// auto_generate_mipmaps in that case).
|
||||
bool success = true;
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D:
|
||||
GLUP(Build1DMipmaps)(target, internal_format, width,
|
||||
external_format, component_type, image);
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_3D:
|
||||
#ifdef GLU_VERSION_1_3
|
||||
GLUP(Build3DMipmaps)(target, internal_format,
|
||||
width, height, depth,
|
||||
external_format, component_type, image);
|
||||
#else // GLU_VERSION_1_3
|
||||
// Prior to GLU 1.3, there was no gluBuild3DMipmaps() call.
|
||||
// Just fall through and load the texture without mipmaps.
|
||||
GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
success = false;
|
||||
#endif // GLU_VERSION_1_3
|
||||
break;
|
||||
|
||||
default:
|
||||
GLUP(Build2DMipmaps)(target, internal_format,
|
||||
width, height,
|
||||
external_format, component_type, image);
|
||||
}
|
||||
|
||||
report_my_gl_errors();
|
||||
if (success) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Texture *tex = gtc->get_texture();
|
||||
|
||||
if (GLCAT.is_debug()) {
|
||||
if (image_compression != Texture::CM_off) {
|
||||
GLCAT.debug()
|
||||
<< "loading pre-compressed texture " << gtc->get_texture()->get_name() << "\n";
|
||||
<< "loading pre-compressed texture " << tex->get_name() << "\n";
|
||||
} else if (is_compressed_format(internal_format)) {
|
||||
GLCAT.debug()
|
||||
<< "compressing texture " << gtc->get_texture()->get_name() << "\n";
|
||||
<< "compressing texture " << tex->get_name() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
int num_ram_mipmap_levels = 1;
|
||||
bool load_ram_mipmaps = false;
|
||||
|
||||
if (uses_mipmaps) {
|
||||
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
|
||||
|
||||
if (num_ram_mipmap_levels == 1) {
|
||||
// No RAM mipmap levels available. Should we generate some?
|
||||
if (!_supports_generate_mipmap ||
|
||||
(!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
|
||||
// Yes, the GL won't generate them, so we need to.
|
||||
tex->generate_ram_mipmap_images();
|
||||
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
|
||||
}
|
||||
}
|
||||
|
||||
if (num_ram_mipmap_levels != 1) {
|
||||
// We will load the mipmap levels from RAM. Don't ask the GL to
|
||||
// generate them.
|
||||
if (_supports_generate_mipmap) {
|
||||
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, false);
|
||||
}
|
||||
load_ram_mipmaps = true;
|
||||
|
||||
} else {
|
||||
// We don't have mipmap levels in RAM. Ask the GL to generate
|
||||
// them if it can.
|
||||
if (_supports_generate_mipmap) {
|
||||
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, true);
|
||||
} else {
|
||||
// If it can't, do without mipmaps.
|
||||
GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
uses_mipmaps = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int highest_level = 0;
|
||||
|
||||
if (!gtc->_already_applied ||
|
||||
gtc->_internal_format != internal_format ||
|
||||
gtc->_width != width ||
|
||||
gtc->_height != height ||
|
||||
gtc->_depth != depth) {
|
||||
// We need to reload a new image.
|
||||
|
||||
for (int n = 0; n < num_ram_mipmap_levels; ++n) {
|
||||
const unsigned char *image = tex->get_ram_mipmap_image(n);
|
||||
if (image == (const unsigned char *)NULL) {
|
||||
GLCAT.warning()
|
||||
<< "No mipmap level " << n << " defined for " << tex->get_name()
|
||||
<< "\n";
|
||||
// No mipmap level n; stop here.
|
||||
break;
|
||||
}
|
||||
size_t image_size = tex->get_ram_mipmap_image_size(n);
|
||||
if (one_page_only) {
|
||||
image_size = tex->get_ram_mipmap_page_size(n);
|
||||
image += image_size * z;
|
||||
}
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
_data_transferred_pcollector.add_level(image_size);
|
||||
_data_transferred_pcollector.add_level(image_size);
|
||||
#endif
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D:
|
||||
nassertr(image_compression == Texture::CM_off, false);
|
||||
GLP(TexImage1D)(target, 0, internal_format,
|
||||
width, 0,
|
||||
external_format, component_type, image);
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_3D:
|
||||
if (_supports_3d_texture) {
|
||||
nassertr(image_compression == Texture::CM_off, false);
|
||||
_glTexImage3D(target, 0, internal_format,
|
||||
width, height, depth, 0,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
report_my_gl_errors();
|
||||
return false;
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D:
|
||||
if (image_compression == Texture::CM_off) {
|
||||
GLP(TexImage1D)(target, n, internal_format,
|
||||
width, 0,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexImage1D(target, n, external_format, width,
|
||||
0, image_size, image);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_3D:
|
||||
if (_supports_3d_texture) {
|
||||
if (image_compression == Texture::CM_off) {
|
||||
_glTexImage3D(target, n, internal_format,
|
||||
width, height, depth, 0,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexImage3D(target, n, external_format, width,
|
||||
height, depth,
|
||||
0, image_size, image);
|
||||
}
|
||||
} else {
|
||||
report_my_gl_errors();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (image_compression == Texture::CM_off) {
|
||||
GLP(TexImage2D)(target, n, internal_format,
|
||||
width, height, 0,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexImage2D(target, n, external_format, width, height,
|
||||
0, image_size, image);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (image_compression == Texture::CM_off) {
|
||||
GLP(TexImage2D)(target, 0, internal_format,
|
||||
width, height, 0,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexImage2D(target, 0, external_format, width, height,
|
||||
0, image_size, image);
|
||||
}
|
||||
highest_level = n;
|
||||
|
||||
width = max(width >> 1, 1);
|
||||
height = max(height >> 1, 1);
|
||||
depth = max(depth >> 1, 1);
|
||||
}
|
||||
} else {
|
||||
// We can reload the image over the previous image, possibly
|
||||
// saving on texture memory fragmentation.
|
||||
for (int n = 0; n < num_ram_mipmap_levels; ++n) {
|
||||
const unsigned char *image = tex->get_ram_mipmap_image(n);
|
||||
if (image == (const unsigned char *)NULL) {
|
||||
GLCAT.warning()
|
||||
<< "No mipmap level " << n << " defined for " << tex->get_name()
|
||||
<< "\n";
|
||||
// No mipmap level n; stop here.
|
||||
break;
|
||||
}
|
||||
size_t image_size = tex->get_ram_mipmap_image_size(n);
|
||||
if (one_page_only) {
|
||||
image_size = tex->get_ram_mipmap_page_size(n);
|
||||
image += image_size * z;
|
||||
}
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
_data_transferred_pcollector.add_level(image_size);
|
||||
_data_transferred_pcollector.add_level(image_size);
|
||||
#endif
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D:
|
||||
nassertr(image_compression == Texture::CM_off, false);
|
||||
GLP(TexSubImage1D)(target, 0, 0, width,
|
||||
external_format, component_type, image);
|
||||
break;
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D:
|
||||
if (image_compression == Texture::CM_off) {
|
||||
GLP(TexSubImage1D)(target, n, 0, width,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexSubImage1D(target, n, 0, width,
|
||||
external_format, image_size, image);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_3D:
|
||||
if (_supports_3d_texture) {
|
||||
nassertr(image_compression == Texture::CM_off, false);
|
||||
_glTexSubImage3D(target, 0, 0, 0, 0, width, height, depth,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
report_my_gl_errors();
|
||||
return false;
|
||||
case GL_TEXTURE_3D:
|
||||
if (_supports_3d_texture) {
|
||||
if (image_compression == Texture::CM_off) {
|
||||
_glTexSubImage3D(target, n, 0, 0, 0, width, height, depth,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexSubImage3D(target, n, 0, 0, 0, width, height, depth,
|
||||
external_format, image_size, image);
|
||||
}
|
||||
} else {
|
||||
report_my_gl_errors();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (image_compression == Texture::CM_off) {
|
||||
GLP(TexSubImage2D)(target, n, 0, 0, width, height,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexSubImage2D(target, n, 0, 0, width, height,
|
||||
external_format, image_size, image);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (image_compression == Texture::CM_off) {
|
||||
GLP(TexSubImage2D)(target, 0, 0, 0, width, height,
|
||||
external_format, component_type, image);
|
||||
} else {
|
||||
_glCompressedTexSubImage2D(target, 0, 0, 0, width, height,
|
||||
external_format, image_size, image);
|
||||
}
|
||||
break;
|
||||
highest_level = n;
|
||||
|
||||
width = max(width >> 1, 1);
|
||||
height = max(height >> 1, 1);
|
||||
depth = max(depth >> 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (load_ram_mipmaps) {
|
||||
// By the time we get here, we have successfully loaded a certain
|
||||
// number of mipmap levels. Tell the GL that's all it's going to
|
||||
// get.
|
||||
GLP(TexParameteri)(target, GL_TEXTURE_MAX_LEVEL, highest_level);
|
||||
|
||||
} else if (uses_mipmaps) {
|
||||
// Since the mipmap levels were auto-generated and are therefore
|
||||
// complete, make sure the GL doesn't remember some previous value
|
||||
// for GL_TEXTURE_MAX_LEVEL from the above call--set it to the
|
||||
// full count of mipmap levels.
|
||||
GLP(TexParameteri)(target, GL_TEXTURE_MAX_LEVEL, tex->get_expected_num_mipmap_levels() - 1);
|
||||
}
|
||||
|
||||
// Report the error message explicitly if the GL texture creation
|
||||
// failed.
|
||||
GLenum error_code = GLP(GetError)();
|
||||
if (error_code != GL_NO_ERROR) {
|
||||
const GLubyte *error_string = GLUP(ErrorString)(error_code);
|
||||
GLCAT.error()
|
||||
<< "GL texture creation failed for " << gtc->get_texture()->get_name();
|
||||
<< "GL texture creation failed for " << tex->get_name();
|
||||
if (error_string != (const GLubyte *)NULL) {
|
||||
GLCAT.error(false)
|
||||
<< " : " << error_string;
|
||||
|
|
@ -6810,6 +6821,91 @@ check_nonresident_texture(BufferContextChain &chain) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::extract_texture_image
|
||||
// Access: Protected
|
||||
// Description: Called from extract_texture_data(), this gets just
|
||||
// the image array for a particular mipmap level (or for
|
||||
// the base image).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CLP(GraphicsStateGuardian)::
|
||||
extract_texture_image(PTA_uchar &image, size_t &page_size,
|
||||
Texture *tex, GLenum target, GLenum page_target,
|
||||
Texture::ComponentType type,
|
||||
Texture::CompressionMode compression, int n) {
|
||||
if (target == GL_TEXTURE_CUBE_MAP) {
|
||||
// A cube map, compressed or uncompressed. This we must extract
|
||||
// one page at a time.
|
||||
|
||||
// If the cube map is compressed, we assume that all the
|
||||
// compressed pages are exactly the same size. OpenGL doesn't
|
||||
// make this assumption, but it happens to be true for all
|
||||
// currently extant compression schemes, and it makes things
|
||||
// simpler for us. (It also makes things much simpler for the
|
||||
// graphics hardware, so it's likely to continue to be true for a
|
||||
// while at least.)
|
||||
|
||||
GLenum external_format = get_external_image_format(tex);
|
||||
GLenum pixel_type = get_component_type(type);
|
||||
page_size = tex->get_expected_ram_mipmap_page_size(n);
|
||||
|
||||
if (compression != Texture::CM_off) {
|
||||
GLint image_size;
|
||||
GLP(GetTexLevelParameteriv)(page_target, n,
|
||||
GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
|
||||
nassertr(image_size <= (int)page_size, false);
|
||||
page_size = image_size;
|
||||
}
|
||||
|
||||
image = PTA_uchar::empty_array(page_size * 6);
|
||||
|
||||
for (int z = 0; z < 6; ++z) {
|
||||
page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
|
||||
|
||||
if (compression == Texture::CM_off) {
|
||||
GLP(GetTexImage)(page_target, n, external_format, pixel_type,
|
||||
image.p() + z * page_size);
|
||||
} else {
|
||||
_glGetCompressedTexImage(page_target, 0, image.p() + z * page_size);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (compression == Texture::CM_off) {
|
||||
// An uncompressed 1-d, 2-d, or 3-d texture.
|
||||
image = PTA_uchar::empty_array(tex->get_expected_ram_mipmap_image_size(n));
|
||||
GLenum external_format = get_external_image_format(tex);
|
||||
GLenum pixel_type = get_component_type(type);
|
||||
GLP(GetTexImage)(target, n, external_format, pixel_type, image.p());
|
||||
|
||||
} else {
|
||||
// A compressed 1-d, 2-d, or 3-d texture.
|
||||
GLint image_size;
|
||||
GLP(GetTexLevelParameteriv)(target, n, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
|
||||
page_size = image_size / tex->get_z_size();
|
||||
image = PTA_uchar::empty_array(image_size);
|
||||
_glGetCompressedTexImage(target, n, image.p());
|
||||
}
|
||||
|
||||
// Now see if we were successful.
|
||||
GLenum error_code = GLP(GetError)();
|
||||
if (error_code != GL_NO_ERROR) {
|
||||
const GLubyte *error_string = GLUP(ErrorString)(error_code);
|
||||
GLCAT.error()
|
||||
<< "Unable to extract texture for " << *tex
|
||||
<< ", mipmap level " << n << ": ";
|
||||
if (error_string != (const GLubyte *)NULL) {
|
||||
GLCAT.error(false)
|
||||
<< " : " << error_string;
|
||||
}
|
||||
GLCAT.error(false)
|
||||
<< "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::do_point_size
|
||||
// Access: Protected
|
||||
|
|
@ -6850,173 +6946,3 @@ do_point_size() {
|
|||
|
||||
report_my_gl_errors();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::build_phony_mipmaps
|
||||
// Access: Protected
|
||||
// Description: Generates a series of colored mipmap levels to aid in
|
||||
// visualizing the mipmap levels as the hardware applies
|
||||
// them.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsStateGuardian)::
|
||||
build_phony_mipmaps(Texture *tex) {
|
||||
int x_size = tex->get_x_size();
|
||||
int y_size = tex->get_y_size();
|
||||
|
||||
GLCAT.info()
|
||||
<< "Building phony mipmap levels for " << tex->get_name() << "\n";
|
||||
int level = 0;
|
||||
while (x_size > 0 && y_size > 0) {
|
||||
GLCAT.info(false)
|
||||
<< " level " << level << " is " << x_size << " by " << y_size << "\n";
|
||||
build_phony_mipmap_level(level, x_size, y_size);
|
||||
|
||||
x_size >>= 1;
|
||||
y_size >>= 1;
|
||||
level++;
|
||||
}
|
||||
|
||||
while (x_size > 0) {
|
||||
GLCAT.info(false)
|
||||
<< " level " << level << " is " << x_size << " by 1\n";
|
||||
build_phony_mipmap_level(level, x_size, 1);
|
||||
|
||||
x_size >>= 1;
|
||||
level++;
|
||||
}
|
||||
|
||||
while (y_size > 0) {
|
||||
GLCAT.info(false)
|
||||
<< " level " << level << " is 1 by " << y_size << "\n";
|
||||
build_phony_mipmap_level(level, 1, y_size);
|
||||
|
||||
y_size >>= 1;
|
||||
level++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::build_phony_mipmap_level
|
||||
// Access: Protected
|
||||
// Description: Generates a single colored mipmap level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsStateGuardian)::
|
||||
build_phony_mipmap_level(int level, int x_size, int y_size) {
|
||||
static const int num_levels = 10;
|
||||
static const char *level_filenames[num_levels] = {
|
||||
"mipmap_level_0.rgb",
|
||||
"mipmap_level_1.rgb",
|
||||
"mipmap_level_2.rgb",
|
||||
"mipmap_level_3.rgb",
|
||||
"mipmap_level_4.rgb",
|
||||
"mipmap_level_5.rgb",
|
||||
"mipmap_level_6.rgb",
|
||||
"mipmap_level_7.rgb",
|
||||
"mipmap_level_8.rgb",
|
||||
"mipmap_level_9.rgb"
|
||||
};
|
||||
static const RGBColorf level_colors[num_levels] = {
|
||||
RGBColorf(1.0f, 1.0f, 1.0f),
|
||||
RGBColorf(1.0f, 0.0f, 0.0f),
|
||||
RGBColorf(0.0f, 1.0f, 0.0f),
|
||||
RGBColorf(0.0f, 0.0f, 1.0f),
|
||||
RGBColorf(1.0f, 1.0f, 0.0f),
|
||||
RGBColorf(0.0f, 1.0f, 1.0f),
|
||||
RGBColorf(1.0f, 0.0f, 1.0f),
|
||||
RGBColorf(1.0f, 0.5, 0.0f),
|
||||
RGBColorf(0.0f, 1.0f, 0.5),
|
||||
RGBColorf(0.83, 0.71, 1.0f)
|
||||
};
|
||||
|
||||
level = level % num_levels;
|
||||
Filename filename(level_filenames[level]);
|
||||
|
||||
PNMImage image_sized(x_size, y_size);
|
||||
PNMImage image_source;
|
||||
if (filename.resolve_filename(get_texture_path()) ||
|
||||
filename.resolve_filename(get_model_path())) {
|
||||
image_source.read(filename);
|
||||
}
|
||||
|
||||
if (image_source.is_valid()) {
|
||||
image_sized.quick_filter_from(image_source);
|
||||
|
||||
} else {
|
||||
GLCAT.info(false)
|
||||
<< " " << filename << " cannot be read, making solid color mipmap.\n";
|
||||
image_sized.fill(level_colors[level][0],
|
||||
level_colors[level][1],
|
||||
level_colors[level][2]);
|
||||
}
|
||||
|
||||
PT(Texture) tex = new Texture;
|
||||
if (!tex->load(image_sized)) {
|
||||
GLCAT.warning()
|
||||
<< "Unable to load phony mipmap image.\n";
|
||||
} else {
|
||||
GLenum internal_format = get_internal_image_format(tex);
|
||||
GLenum external_format = get_external_image_format(tex);
|
||||
GLenum component_type = get_component_type(tex->get_component_type());
|
||||
|
||||
GLP(TexImage2D)(GL_TEXTURE_2D, level, internal_format,
|
||||
tex->get_x_size(), tex->get_y_size(), 0,
|
||||
external_format, component_type, tex->get_ram_image());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::save_mipmap_images
|
||||
// Access: Protected
|
||||
// Description: Saves out each mipmap level of the indicated texture
|
||||
// (which must also be the currently active texture in
|
||||
// the GL state) as a separate image file to disk.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsStateGuardian)::
|
||||
save_mipmap_images(Texture *tex) {
|
||||
if (tex->get_texture_type() != Texture::TT_2d_texture) {
|
||||
// Never mind on unusual texture formats.
|
||||
return;
|
||||
}
|
||||
|
||||
Filename filename = tex->get_name();
|
||||
string name;
|
||||
if (filename.empty()) {
|
||||
static int index = 0;
|
||||
name = "texture" + format_string(index);
|
||||
index++;
|
||||
} else {
|
||||
name = filename.get_basename_wo_extension();
|
||||
}
|
||||
|
||||
GLenum external_format = get_external_image_format(tex);
|
||||
GLenum type = get_component_type(tex->get_component_type());
|
||||
|
||||
int x_size = tex->get_x_size();
|
||||
int y_size = tex->get_y_size();
|
||||
|
||||
// Specify byte-alignment for the pixels on output.
|
||||
GLP(PixelStorei)(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
int mipmap_level = 0;
|
||||
do {
|
||||
x_size = max(x_size, 1);
|
||||
y_size = max(y_size, 1);
|
||||
|
||||
PT(Texture) mtex = new Texture;
|
||||
mtex->setup_2d_texture(x_size, y_size, tex->get_component_type(),
|
||||
tex->get_format());
|
||||
GLP(GetTexImage)(GL_TEXTURE_2D, mipmap_level, external_format,
|
||||
type, mtex->make_ram_image());
|
||||
Filename mipmap_filename = name + "_" + format_string(mipmap_level) + ".rgb";
|
||||
nout << "Writing mipmap level " << mipmap_level
|
||||
<< " (" << x_size << " by " << y_size << ") "
|
||||
<< mipmap_filename << "\n";
|
||||
mtex->write(mipmap_filename);
|
||||
|
||||
x_size >>= 1;
|
||||
y_size >>= 1;
|
||||
mipmap_level++;
|
||||
} while (x_size > 0 || y_size > 0);
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
|
|
|||
|
|
@ -65,11 +65,12 @@ typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset,
|
|||
typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
|
||||
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
|
||||
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
|
||||
typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
|
||||
class CLP(GeomContext);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : GLGraphicsStateGuardian
|
||||
|
|
@ -274,21 +275,18 @@ protected:
|
|||
GLenum target, GLint internal_format,
|
||||
int width, int height, int depth,
|
||||
GLint external_format, GLenum component_type,
|
||||
const unsigned char *image,
|
||||
size_t image_size,
|
||||
bool one_page_only, int z,
|
||||
Texture::CompressionMode image_compression);
|
||||
|
||||
size_t get_texture_memory_size(Texture *tex);
|
||||
void check_nonresident_texture(BufferContextChain &chain);
|
||||
bool extract_texture_image(PTA_uchar &image, size_t &page_size,
|
||||
Texture *tex, GLenum target, GLenum page_target,
|
||||
Texture::ComponentType type,
|
||||
Texture::CompressionMode compression, int n);
|
||||
|
||||
void do_point_size();
|
||||
|
||||
#ifndef NDEBUG
|
||||
void build_phony_mipmaps(Texture *tex);
|
||||
void build_phony_mipmap_level(int level, int x_size, int y_size);
|
||||
void save_mipmap_images(Texture *tex);
|
||||
#endif
|
||||
|
||||
enum AutoAntialiasMode {
|
||||
AA_poly,
|
||||
AA_line,
|
||||
|
|
@ -374,8 +372,12 @@ public:
|
|||
PFNGLTEXIMAGE3DPROC _glTexImage3D;
|
||||
PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
|
||||
|
||||
PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D;
|
||||
PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D;
|
||||
PFNGLCOMPRESSEDTEXIMAGE3DPROC _glCompressedTexImage3D;
|
||||
PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC _glCompressedTexSubImage1D;
|
||||
PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC _glCompressedTexSubImage2D;
|
||||
PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC _glCompressedTexSubImage3D;
|
||||
PFNGLGETCOMPRESSEDTEXIMAGEPROC _glGetCompressedTexImage;
|
||||
|
||||
bool _supports_bgr;
|
||||
|
|
|
|||
|
|
@ -56,16 +56,6 @@ ConfigVariableBool CLP(force_mipmaps)
|
|||
PRC_DESC("Configure this true to enable full trilinear mipmapping on every "
|
||||
"texture, whether it asks for it or not."));
|
||||
|
||||
ConfigVariableBool CLP(show_mipmaps)
|
||||
("gl-show-mipmaps", false,
|
||||
PRC_DESC("Configure this true to cause mipmaps to be rendered with phony "
|
||||
"colors, using mipmap_level_*.rgb if they are available."));
|
||||
|
||||
ConfigVariableBool CLP(save_mipmaps)
|
||||
("gl-save-mipmaps", false,
|
||||
PRC_DESC("Configure this true to cause the generated mipmap images to be "
|
||||
"written out to image files on the disk as they are generated."));
|
||||
|
||||
ConfigVariableBool CLP(color_mask)
|
||||
("gl-color-mask", true,
|
||||
PRC_DESC("Configure this false if your GL's implementation of glColorMask() "
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ extern ConfigVariableBool CLP(support_clamp_to_border);
|
|||
extern ConfigVariableBool CLP(ignore_filters);
|
||||
extern ConfigVariableBool CLP(ignore_mipmaps);
|
||||
extern ConfigVariableBool CLP(force_mipmaps);
|
||||
extern ConfigVariableBool CLP(show_mipmaps);
|
||||
extern ConfigVariableBool CLP(save_mipmaps);
|
||||
extern ConfigVariableBool CLP(color_mask);
|
||||
extern ConfigVariableBool CLP(compile_and_execute);
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,240 @@ setup_cube_map(int size, ComponentType component_type,
|
|||
setup_texture(TT_cube_map, size, size, 6, component_type, format);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::read
|
||||
// Access: Published
|
||||
// Description: Reads the named filename into the texture.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
read(const Filename &fullpath) {
|
||||
return do_read(fullpath, Filename(), 0, 0, 0, 0, false, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::read
|
||||
// Access: Published
|
||||
// Description: Combine a 3-component image with a grayscale image
|
||||
// to get a 4-component image.
|
||||
//
|
||||
// See the description of the full-parameter read()
|
||||
// method for the meaning of the
|
||||
// primary_file_num_channels and alpha_file_channel
|
||||
// parameters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int primary_file_num_channels, int alpha_file_channel) {
|
||||
return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
|
||||
alpha_file_channel, 0, 0, false, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::read
|
||||
// Access: Published
|
||||
// Description: Reads a single file into a single page or mipmap
|
||||
// level, or automatically reads a series of files into
|
||||
// a series of pages and/or mipmap levels.
|
||||
//
|
||||
// See the description of the full-parameter read()
|
||||
// method for the meaning of the various parameters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
read(const Filename &fullpath, int z, int n,
|
||||
bool read_pages, bool read_mipmaps) {
|
||||
return do_read(fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::read
|
||||
// Access: Published
|
||||
// Description: Reads the texture from the indicated filename. If
|
||||
// primary_file_num_channels is not 0, it specifies the
|
||||
// number of components to downgrade the image to if it
|
||||
// is greater than this number.
|
||||
//
|
||||
// If the filename has the extension .txo, this
|
||||
// implicitly reads a texture object instead of a
|
||||
// filename (which replaces all of the texture
|
||||
// properties). In this case, all the rest of the
|
||||
// parameters are ignored, and the filename should not
|
||||
// contain any hash marks; just the one named file will
|
||||
// be read, since a single .txo file can contain all
|
||||
// pages and mipmaps necessary to define a texture.
|
||||
//
|
||||
// If alpha_fullpath is not empty, it specifies the name
|
||||
// of a file from which to retrieve the alpha. In this
|
||||
// case, alpha_file_channel represents the numeric
|
||||
// channel of this image file to use as the resulting
|
||||
// texture's alpha channel; usually, this is 0 to
|
||||
// indicate the grayscale combination of r, g, b; or it
|
||||
// may be a one-based channel number, e.g. 1 for the red
|
||||
// channel, 2 for the green channel, and so on.
|
||||
//
|
||||
// If read pages is false, then z indicates the page
|
||||
// number into which this image will be assigned.
|
||||
// Normally this is 0 for the first (or only) page of
|
||||
// the texture. 3-D textures have one page for each
|
||||
// level of depth, and cube map textures always have six
|
||||
// pages.
|
||||
//
|
||||
// If read_pages is true, multiple images will be read
|
||||
// at once, one for each page of a cube map or a 3-D
|
||||
// texture. In this case, the filename should contain a
|
||||
// sequence of one or more hash marks ("#") which will
|
||||
// be filled in with the z value of each page,
|
||||
// zero-based. In this case, the z parameter indicates
|
||||
// the maximum z value that will be loaded, or 0 to load
|
||||
// all filenames that exist.
|
||||
//
|
||||
// If read_mipmaps is false, then n indicates the mipmap
|
||||
// level to which this image will be assigned. Normally
|
||||
// this is 0 for the base texture image, but it is
|
||||
// possible to load custom mipmap levels into the later
|
||||
// images. After the base texture image is loaded (thus
|
||||
// defining the size of the texture), you can call
|
||||
// get_expected_num_mipmap_levels() to determine the
|
||||
// maximum sensible value for n.
|
||||
//
|
||||
// If read_mipmaps is true, multiple images will be read
|
||||
// as above, but this time the images represent the
|
||||
// different mipmap levels of the texture image. In
|
||||
// this case, the n parameter indicates the maximum n
|
||||
// value that will be loaded, or 0 to load all filenames
|
||||
// that exist (up to the expected number of mipmap
|
||||
// levels).
|
||||
//
|
||||
// If both read_pages and read_mipmaps is true, then
|
||||
// both sequences will be read; the filename should
|
||||
// contain two sequences of hash marks, separated by
|
||||
// some character such as a hyphen, underscore, or dot.
|
||||
// The first hash mark sequence will be filled in with
|
||||
// the mipmap level, while the second hash mark sequence
|
||||
// will be the page index.
|
||||
//
|
||||
// This method implicitly sets keep_ram_image to false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int primary_file_num_channels, int alpha_file_channel,
|
||||
int z, int n, bool read_pages, bool read_mipmaps) {
|
||||
return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
|
||||
alpha_file_channel, z, n, read_pages, read_mipmaps);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::write
|
||||
// Access: Published
|
||||
// Description: Writes the texture to the named filename.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
write(const Filename &fullpath) {
|
||||
return do_write(fullpath, 0, 0, false, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::write
|
||||
// Access: Published
|
||||
// Description: Writes a single page or mipmap level to a single
|
||||
// file, or automatically writes a series of pages
|
||||
// and/or mipmap levels to a numbered series of files.
|
||||
//
|
||||
// If the filename ends in the extension .txo, this
|
||||
// implicitly writes a Panda texture object (.txo)
|
||||
// instead of an image file. In this case, the
|
||||
// remaining parameters are ignored, and only one file
|
||||
// is written, which will contain all of the pages and
|
||||
// resident mipmap levels in the texture.
|
||||
//
|
||||
// If write_pages is false, then z indicates the page
|
||||
// number to write. 3-D textures have one page number
|
||||
// for each level of depth; cube maps have six pages
|
||||
// number 0 through 5. Other kinds of textures have
|
||||
// only one page, numbered 0.
|
||||
//
|
||||
// If write_pages is true, then all pages of the texture
|
||||
// will be written. In this case z is ignored, and the
|
||||
// filename should contain a sequence of hash marks
|
||||
// ("#") which will be filled in with the page index
|
||||
// number.
|
||||
//
|
||||
// If write_mipmaps is false, then n indicates the
|
||||
// mipmap level number to write. Normally, this is 0,
|
||||
// for the base texture image. Normally, the mipmap
|
||||
// levels of a texture are not available in RAM (they
|
||||
// are generated automatically by the graphics card).
|
||||
// However, if you have the mipmap levels available, for
|
||||
// instance because you called
|
||||
// generate_ram_mipmap_images() to generate them
|
||||
// internally, or you called
|
||||
// GraphicsEngine::extract_texture_data() to retrieve
|
||||
// them from the graphics card, then you may write out
|
||||
// each mipmap level with this parameter.
|
||||
//
|
||||
// If write_mipmaps is true, then all mipmap levels of
|
||||
// the texture will be written. In this case n is
|
||||
// ignored, and the filename should contain a sequence
|
||||
// of hash marks ("#") which will be filled in with the
|
||||
// mipmap level number.
|
||||
//
|
||||
// If both write_pages and write_mipmaps is true, then
|
||||
// all pages and all mipmap levels will be written. In
|
||||
// this case, the filename should contain two different
|
||||
// sequences of hash marks, separated by a character
|
||||
// such as a hyphen, underscore, or dot. The first hash
|
||||
// mark sequence will be filled in with the mipmap
|
||||
// level, while the second hash mark sequence will be
|
||||
// the page index.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
write(const Filename &fullpath, int z, int n,
|
||||
bool write_pages, bool write_mipmaps) {
|
||||
return do_write(fullpath, z, n, write_pages, write_mipmaps);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::load
|
||||
// Access: Published
|
||||
// Description: Replaces the texture with the indicated image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
load(const PNMImage &pnmimage) {
|
||||
return do_load_one(pnmimage, 0, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::load
|
||||
// Access: Published
|
||||
// Description: Stores the indicated image in the given page and
|
||||
// mipmap level. See read().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
load(const PNMImage &pnmimage, int z, int n) {
|
||||
return do_load_one(pnmimage, z, n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::store
|
||||
// Access: Published
|
||||
// Description: Saves the texture to the indicated PNMImage, but does
|
||||
// not write it to disk.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
store(PNMImage &pnmimage) const {
|
||||
return do_store_one(pnmimage, 0, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::store
|
||||
// Access: Published
|
||||
// Description: Saves the indicated page and mipmap level of the
|
||||
// texture to the PNMImage.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
store(PNMImage &pnmimage, int z, int n) const {
|
||||
return do_store_one(pnmimage, z, n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::has_filename
|
||||
// Access: Published
|
||||
|
|
@ -462,7 +696,10 @@ might_have_ram_image() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t Texture::
|
||||
get_ram_image_size() const {
|
||||
return _ram_image.size();
|
||||
if (_ram_images.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return _ram_images[0]._image.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -479,7 +716,11 @@ get_ram_image_size() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t Texture::
|
||||
get_ram_page_size() const {
|
||||
return _ram_image_compression != CM_off ? _ram_page_size : get_expected_ram_page_size();
|
||||
if (_ram_image_compression == CM_off || _ram_images.empty()) {
|
||||
return get_expected_ram_page_size();
|
||||
} else {
|
||||
return _ram_images[0]._page_size;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -542,6 +783,99 @@ set_keep_ram_image(bool keep_ram_image) {
|
|||
_keep_ram_image = keep_ram_image;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_num_ram_mipmap_images
|
||||
// Access: Published
|
||||
// Description: Returns the maximum number of mipmap level images
|
||||
// available in system memory. The actual number may be
|
||||
// less than this; use has_ram_mipmap_image() to verify
|
||||
// each level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int Texture::
|
||||
get_num_ram_mipmap_images() const {
|
||||
return _ram_images.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::has_ram_mipmap_image
|
||||
// Access: Published
|
||||
// Description: Returns true if the Texture has the nth mipmap level
|
||||
// available in system memory, false otherwise. If the
|
||||
// texture's minfilter mode requires mipmapping (see
|
||||
// uses_mipmaps()), and all the texture's mipmap levels
|
||||
// are not available when the texture is rendered, they
|
||||
// will be generated automatically.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
has_ram_mipmap_image(int n) const {
|
||||
return (n >= 0 && n < (int)_ram_images.size() && !_ram_images[n]._image.empty());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_ram_mipmap_image_size
|
||||
// Access: Published
|
||||
// Description: Returns the number of bytes used by the in-memory
|
||||
// image for mipmap level n, or 0 if there is no
|
||||
// in-memory image for this mipmap level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t Texture::
|
||||
get_ram_mipmap_image_size(int n) const {
|
||||
if (n >= 0 && n < (int)_ram_images.size()) {
|
||||
return _ram_images[n]._image.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_ram_mipmap_page_size
|
||||
// Access: Published
|
||||
// Description: Returns the number of bytes used by the in-memory
|
||||
// image per page for mipmap level n, or 0 if there is
|
||||
// no in-memory image for this mipmap level.
|
||||
//
|
||||
// For a non-compressed texture, this is the same as
|
||||
// get_expected_ram_mipmap_page_size(). For a compressed
|
||||
// texture, this may be a smaller value. (We do assume
|
||||
// that all pages will be the same size on a compressed
|
||||
// texture).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t Texture::
|
||||
get_ram_mipmap_page_size(int n) const {
|
||||
if (_ram_image_compression != CM_off) {
|
||||
if (n >= 0 && n < (int)_ram_images.size()) {
|
||||
return _ram_images[n]._page_size;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return get_expected_ram_mipmap_page_size(n);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_expected_ram_mipmap_image_size
|
||||
// Access: Published
|
||||
// Description: Returns the number of bytes that *ought* to be used
|
||||
// by the in-memory image for mipmap level n, based on
|
||||
// the texture parameters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t Texture::
|
||||
get_expected_ram_mipmap_image_size(int n) const {
|
||||
return get_expected_ram_mipmap_page_size(n) * (size_t)get_expected_mipmap_z_size(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_expected_ram_mipmap_page_size
|
||||
// Access: Published
|
||||
// Description: Returns the number of bytes that should be used per
|
||||
// each Z page of the 3-d texture, for mipmap level n.
|
||||
// For a 2-d or 1-d texture, this is the same as
|
||||
// get_expected_ram_mipmap_image_size(n).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t Texture::
|
||||
get_expected_ram_mipmap_page_size(int n) const {
|
||||
return (size_t)(get_expected_mipmap_x_size(n) * get_expected_mipmap_y_size(n) * _num_components * _component_width);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_modified
|
||||
// Access: Published
|
||||
|
|
@ -714,28 +1048,29 @@ set_z_size(int z_size) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::set_loaded_from_disk
|
||||
// Function: Texture::set_loaded_from_image
|
||||
// Access: Published
|
||||
// Description: Sets the flag that indicates the texture has been
|
||||
// loaded from a disk file. You should also ensure the
|
||||
// filename has been set correctly. When this flag is
|
||||
// true, the texture may be automatically reloaded when
|
||||
// its ram image needs to be replaced.
|
||||
// loaded from a disk file or PNMImage. You should also
|
||||
// ensure the filename has been set correctly. When
|
||||
// this flag is true, the texture may be automatically
|
||||
// reloaded when its ram image needs to be replaced.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Texture::
|
||||
set_loaded_from_disk() {
|
||||
_loaded_from_disk = true;
|
||||
set_loaded_from_image() {
|
||||
_loaded_from_image = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_loaded_from_disk
|
||||
// Function: Texture::get_loaded_from_image
|
||||
// Access: Published
|
||||
// Description: Returns the flag that indicates the texture has been
|
||||
// loaded from a disk file. See set_loaded_from_disk().
|
||||
// loaded from a disk file or PNMImage. See
|
||||
// set_loaded_from_image().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Texture::
|
||||
get_loaded_from_disk() const {
|
||||
return _loaded_from_disk;
|
||||
get_loaded_from_image() const {
|
||||
return _loaded_from_image;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -800,7 +1135,7 @@ set_match_framebuffer_format(bool flag) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::store_unscaled_byte
|
||||
// Access: Private
|
||||
// Access: Private, Static
|
||||
// Description: This is used by load() to store the next consecutive
|
||||
// component value into the indicated element of the
|
||||
// array, which is taken to be an array of unsigned
|
||||
|
|
@ -808,13 +1143,13 @@ set_match_framebuffer_format(bool flag) {
|
|||
// 0-255.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Texture::
|
||||
store_unscaled_byte(int &index, int value) {
|
||||
_ram_image[index++] = (uchar)value;
|
||||
store_unscaled_byte(unsigned char *&p, int value) {
|
||||
(*p++) = (uchar)value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::store_unscaled_short
|
||||
// Access: Private
|
||||
// Access: Private, Static
|
||||
// Description: This is used by load() to store the next consecutive
|
||||
// component value into the indicated element of the
|
||||
// array, which is taken to be an array of unsigned
|
||||
|
|
@ -822,19 +1157,19 @@ store_unscaled_byte(int &index, int value) {
|
|||
// 0-65535.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Texture::
|
||||
store_unscaled_short(int &index, int value) {
|
||||
store_unscaled_short(unsigned char *&p, int value) {
|
||||
union {
|
||||
ushort us;
|
||||
uchar uc[2];
|
||||
} v;
|
||||
v.us = (ushort)value;
|
||||
_ram_image[index++] = v.uc[0];
|
||||
_ram_image[index++] = v.uc[1];
|
||||
(*p++) = v.uc[0];
|
||||
(*p++) = v.uc[1];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::store_scaled_byte
|
||||
// Access: Private
|
||||
// Access: Private, Static
|
||||
// Description: This is used by load() to store the next consecutive
|
||||
// component value into the indicated element of the
|
||||
// array, which is taken to be an array of unsigned
|
||||
|
|
@ -842,13 +1177,13 @@ store_unscaled_short(int &index, int value) {
|
|||
// factor before storing it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Texture::
|
||||
store_scaled_byte(int &index, int value, double scale) {
|
||||
store_unscaled_byte(index, (int)(value * scale));
|
||||
store_scaled_byte(unsigned char *&p, int value, double scale) {
|
||||
store_unscaled_byte(p, (int)(value * scale));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::store_scaled_short
|
||||
// Access: Private
|
||||
// Access: Private, Static
|
||||
// Description: This is used by load() to store the next consecutive
|
||||
// component value into the indicated element of the
|
||||
// array, which is taken to be an array of unsigned
|
||||
|
|
@ -856,41 +1191,39 @@ store_scaled_byte(int &index, int value, double scale) {
|
|||
// factor before storing it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Texture::
|
||||
store_scaled_short(int &index, int value, double scale) {
|
||||
store_unscaled_short(index, (int)(value * scale));
|
||||
store_scaled_short(unsigned char *&p, int value, double scale) {
|
||||
store_unscaled_short(p, (int)(value * scale));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_unsigned_byte
|
||||
// Access: Private
|
||||
// Description: This is used by store() to retieve the next
|
||||
// Access: Private, Static
|
||||
// Description: This is used by store() to retrieve the next
|
||||
// consecutive component value from the indicated
|
||||
// element of the array, which is taken to be an array
|
||||
// of unsigned bytes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE double Texture::
|
||||
get_unsigned_byte(int &index) const {
|
||||
nassertr(index >= 0 && index < (int)_ram_image.size(), 0.0);
|
||||
return (double)_ram_image[index++] / 255.0;
|
||||
get_unsigned_byte(const unsigned char *&p) {
|
||||
return (double)(*p++) / 255.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::get_unsigned_short
|
||||
// Access: Private
|
||||
// Description: This is used by store() to retieve the next
|
||||
// Access: Private, Static
|
||||
// Description: This is used by store() to retrieve the next
|
||||
// consecutive component value from the indicated
|
||||
// element of the array, which is taken to be an array
|
||||
// of unsigned shorts.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE double Texture::
|
||||
get_unsigned_short(int &index) const {
|
||||
nassertr(index >= 0 && index+1 < (int)_ram_image.size(), 0.0);
|
||||
get_unsigned_short(const unsigned char *&p) {
|
||||
union {
|
||||
ushort us;
|
||||
uchar uc[2];
|
||||
} v;
|
||||
v.uc[0] = _ram_image[index++];
|
||||
v.uc[1] = _ram_image[index++];
|
||||
v.uc[0] = (*p++);
|
||||
v.uc[1] = (*p++);
|
||||
return (double)v.us / 65535.0;
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -146,7 +146,7 @@ PUBLISHED:
|
|||
};
|
||||
|
||||
enum CompressionMode {
|
||||
// Generic compresssion modes. Usually, you should choose one of
|
||||
// Generic compression modes. Usually, you should choose one of
|
||||
// these.
|
||||
CM_default, // on or off, according to compressed-textures
|
||||
CM_off, // uncompressed image
|
||||
|
|
@ -174,6 +174,7 @@ PUBLISHED:
|
|||
virtual ~Texture();
|
||||
|
||||
virtual PT(Texture) make_copy();
|
||||
virtual void clear();
|
||||
|
||||
void setup_texture(TextureType texture_type,
|
||||
int x_size, int y_size, int z_size,
|
||||
|
|
@ -194,21 +195,26 @@ PUBLISHED:
|
|||
|
||||
void generate_normalization_cube_map(int size);
|
||||
|
||||
virtual bool read(const Filename &fullpath, int z = 0,
|
||||
int primary_file_num_channels = 0);
|
||||
virtual bool read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int z = 0,
|
||||
int primary_file_num_channels = 0, int alpha_file_channel = 0);
|
||||
bool write(const Filename &fullpath, int z = 0) const;
|
||||
INLINE bool read(const Filename &fullpath);
|
||||
INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int primary_file_num_channels, int alpha_file_channel);
|
||||
INLINE bool read(const Filename &fullpath, int z, int n,
|
||||
bool read_pages, bool read_mipmaps);
|
||||
INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int primary_file_num_channels, int alpha_file_channel,
|
||||
int z, int n, bool read_pages, bool read_mipmaps);
|
||||
|
||||
INLINE bool write(const Filename &fullpath);
|
||||
INLINE bool write(const Filename &fullpath, int z, int n,
|
||||
bool write_pages, bool write_mipmaps);
|
||||
|
||||
bool read_txo(istream &in, const string &filename = "stream");
|
||||
bool write_txo(ostream &out, const string &filename = "stream") const;
|
||||
|
||||
bool read_pages(Filename fullpath_pattern, int z_size = 0);
|
||||
bool write_pages(Filename fullpath_pattern);
|
||||
|
||||
virtual bool load(const PNMImage &pnmimage, int z = 0);
|
||||
bool store(PNMImage &pnmimage, int z = 0) const;
|
||||
INLINE bool load(const PNMImage &pnmimage);
|
||||
INLINE bool load(const PNMImage &pnmimage, int z, int n);
|
||||
INLINE bool store(PNMImage &pnmimage) const;
|
||||
INLINE bool store(PNMImage &pnmimage, int z, int n) const;
|
||||
|
||||
Texture *load_related(const PT(InternalName) &suffix) const;
|
||||
|
||||
|
|
@ -252,6 +258,11 @@ PUBLISHED:
|
|||
INLINE bool get_render_to_texture() const;
|
||||
INLINE bool uses_mipmaps() const;
|
||||
|
||||
int get_expected_num_mipmap_levels() const;
|
||||
int get_expected_mipmap_x_size(int n) const;
|
||||
int get_expected_mipmap_y_size(int n) const;
|
||||
int get_expected_mipmap_z_size(int n) const;
|
||||
|
||||
virtual bool has_ram_image() const;
|
||||
INLINE bool might_have_ram_image() const;
|
||||
INLINE size_t get_ram_image_size() const;
|
||||
|
|
@ -268,6 +279,21 @@ PUBLISHED:
|
|||
INLINE void set_keep_ram_image(bool keep_ram_image);
|
||||
virtual bool get_keep_ram_image() const;
|
||||
|
||||
INLINE int get_num_ram_mipmap_images() const;
|
||||
INLINE bool has_ram_mipmap_image(int n) const;
|
||||
bool has_all_ram_mipmap_images() const;
|
||||
INLINE size_t get_ram_mipmap_image_size(int n) const;
|
||||
INLINE size_t get_ram_mipmap_page_size(int n) const;
|
||||
INLINE size_t get_expected_ram_mipmap_image_size(int n) const;
|
||||
INLINE size_t get_expected_ram_mipmap_page_size(int n) const;
|
||||
CPTA_uchar get_ram_mipmap_image(int n);
|
||||
PTA_uchar modify_ram_mipmap_image(int n);
|
||||
PTA_uchar make_ram_mipmap_image(int n);
|
||||
void set_ram_mipmap_image(int n, PTA_uchar image, size_t page_size = 0);
|
||||
void clear_ram_mipmap_image(int n);
|
||||
void clear_ram_mipmap_images();
|
||||
void generate_ram_mipmap_images();
|
||||
|
||||
INLINE UpdateSeq get_modified() const;
|
||||
|
||||
void prepare(PreparedGraphicsObjects *prepared_objects);
|
||||
|
|
@ -297,18 +323,18 @@ PUBLISHED:
|
|||
INLINE void set_z_size(int z_size);
|
||||
void set_format(Format format);
|
||||
void set_component_type(ComponentType component_type);
|
||||
INLINE void set_loaded_from_disk();
|
||||
INLINE bool get_loaded_from_disk() const;
|
||||
INLINE void set_loaded_from_image();
|
||||
INLINE bool get_loaded_from_image() const;
|
||||
|
||||
INLINE void set_loaded_from_txo();
|
||||
INLINE bool get_loaded_from_txo() const;
|
||||
|
||||
static bool is_mipmap(FilterType type);
|
||||
|
||||
public:
|
||||
INLINE bool get_match_framebuffer_format() const;
|
||||
INLINE void set_match_framebuffer_format(bool flag);
|
||||
|
||||
static bool is_mipmap(FilterType type);
|
||||
|
||||
TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
|
||||
GraphicsStateGuardianBase *gsg);
|
||||
|
||||
|
|
@ -328,6 +354,18 @@ public:
|
|||
static bool has_alpha(Format format);
|
||||
|
||||
protected:
|
||||
virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int primary_file_num_channels, int alpha_file_channel,
|
||||
int z, int n, bool read_pages, bool read_mipmaps);
|
||||
virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int z, int n, int primary_file_num_channels, int alpha_file_channel);
|
||||
bool do_write(const Filename &fullpath, int z, int n,
|
||||
bool write_pages, bool write_mipmaps) const;
|
||||
bool do_write_one(const Filename &fullpath, int z, int n) const;
|
||||
|
||||
virtual bool do_load_one(const PNMImage &pnmimage, int z, int n);
|
||||
bool do_store_one(PNMImage &pnmimage, int z, int n) const;
|
||||
|
||||
virtual void reconsider_dirty();
|
||||
virtual void reload_ram_image();
|
||||
|
||||
|
|
@ -335,23 +373,65 @@ protected:
|
|||
bool reconsider_image_properties(int x_size, int y_size, int num_components,
|
||||
ComponentType component_type, int z);
|
||||
|
||||
// This nested class declaration is used below.
|
||||
class RamImage {
|
||||
public:
|
||||
PTA_uchar _image;
|
||||
size_t _page_size;
|
||||
};
|
||||
|
||||
private:
|
||||
void convert_from_pnmimage(PTA_uchar &image, size_t page_size, int z,
|
||||
const PNMImage &pnmimage);
|
||||
bool convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
|
||||
CPTA_uchar image, size_t page_size, int z) const;
|
||||
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
|
||||
|
||||
void consider_rescale(PNMImage &pnmimage);
|
||||
void consider_downgrade(PNMImage &pnmimage, int num_channels);
|
||||
|
||||
INLINE void store_unscaled_byte(int &index, int value);
|
||||
INLINE void store_unscaled_short(int &index, int value);
|
||||
INLINE void store_scaled_byte(int &index, int value, double scale);
|
||||
INLINE void store_scaled_short(int &index, int value, double scale);
|
||||
INLINE double get_unsigned_byte(int &index) const;
|
||||
INLINE double get_unsigned_short(int &index) const;
|
||||
INLINE static void store_unscaled_byte(unsigned char *&p, int value);
|
||||
INLINE static void store_unscaled_short(unsigned char *&p, int value);
|
||||
INLINE static void store_scaled_byte(unsigned char *&p, int value, double scale);
|
||||
INLINE static void store_scaled_short(unsigned char *&p, int value, double scale);
|
||||
INLINE static double get_unsigned_byte(const unsigned char *&p);
|
||||
INLINE static double get_unsigned_short(const unsigned char *&p);
|
||||
|
||||
INLINE static bool is_txo_filename(const Filename &fullpath);
|
||||
bool read_txo_file(const Filename &fullpath);
|
||||
bool write_txo_file(const Filename &fullpath) const;
|
||||
|
||||
void filter_2d_mipmap_pages(RamImage &to, const RamImage &from,
|
||||
int x_size, int y_size);
|
||||
|
||||
void filter_3d_mipmap_level(RamImage &to, const RamImage &from,
|
||||
int x_size, int y_size, int z_size);
|
||||
|
||||
typedef void Filter2DComponent(unsigned char *&p,
|
||||
const unsigned char *&q,
|
||||
size_t pixel_size, size_t row_size);
|
||||
|
||||
typedef void Filter3DComponent(unsigned char *&p,
|
||||
const unsigned char *&q,
|
||||
size_t pixel_size, size_t row_size,
|
||||
size_t page_size);
|
||||
|
||||
static void filter_2d_unsigned_byte(unsigned char *&p,
|
||||
const unsigned char *&q,
|
||||
size_t pixel_size, size_t row_size);
|
||||
static void filter_2d_unsigned_short(unsigned char *&p,
|
||||
const unsigned char *&q,
|
||||
size_t pixel_size, size_t row_size);
|
||||
|
||||
static void filter_3d_unsigned_byte(unsigned char *&p,
|
||||
const unsigned char *&q,
|
||||
size_t pixel_size, size_t row_size,
|
||||
size_t page_size);
|
||||
static void filter_3d_unsigned_short(unsigned char *&p,
|
||||
const unsigned char *&q,
|
||||
size_t pixel_size, size_t row_size,
|
||||
size_t page_size);
|
||||
|
||||
protected:
|
||||
Filename _filename;
|
||||
Filename _alpha_filename;
|
||||
|
|
@ -376,8 +456,11 @@ protected:
|
|||
Format _format;
|
||||
ComponentType _component_type;
|
||||
|
||||
bool _loaded_from_disk;
|
||||
bool _loaded_from_image;
|
||||
bool _loaded_from_txo;
|
||||
bool _has_read_pages;
|
||||
bool _has_read_mipmaps;
|
||||
int _num_mipmap_levels_read;
|
||||
|
||||
WrapMode _wrap_u;
|
||||
WrapMode _wrap_v;
|
||||
|
|
@ -407,9 +490,13 @@ protected:
|
|||
typedef pmap<PT(InternalName), PT(Texture)> RelatedTextures;
|
||||
RelatedTextures _related_textures;
|
||||
|
||||
PTA_uchar _ram_image;
|
||||
CompressionMode _ram_image_compression;
|
||||
size_t _ram_page_size;
|
||||
|
||||
// There is usually one RamImage for the mipmap level 0 (the base
|
||||
// image). There may or may not also be additional images for the
|
||||
// additional mipmap levels.
|
||||
typedef pvector<RamImage> RamImages;
|
||||
RamImages _ram_images;
|
||||
|
||||
UpdateSeq _modified;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,10 +51,17 @@ verify_texture(const string &filename) {
|
|||
// If a texture with the same filename was previously
|
||||
// loaded, returns that one instead. If the texture
|
||||
// file cannot be found, returns NULL.
|
||||
//
|
||||
// If read_mipmaps is true, the filename should contain
|
||||
// a hash mark ('#'), which will be filled in with the
|
||||
// mipmap level number; and the texture will be defined
|
||||
// with a series of images, one for each mipmap level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Texture *TexturePool::
|
||||
load_texture(const string &filename, int primary_file_num_channels) {
|
||||
return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels);
|
||||
load_texture(const string &filename, int primary_file_num_channels,
|
||||
bool read_mipmaps) {
|
||||
return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels,
|
||||
read_mipmaps);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -65,13 +72,21 @@ load_texture(const string &filename, int primary_file_num_channels) {
|
|||
// If a texture with the same filename was previously
|
||||
// loaded, returns that one instead. If the texture
|
||||
// file cannot be found, returns NULL.
|
||||
//
|
||||
// If read_mipmaps is true, both filenames should
|
||||
// contain a hash mark ('#'), which will be filled in
|
||||
// with the mipmap level number; and the texture will be
|
||||
// defined with a series of images, two for each mipmap
|
||||
// level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Texture *TexturePool::
|
||||
load_texture(const string &filename, const string &alpha_filename,
|
||||
int primary_file_num_channels, int alpha_file_channel) {
|
||||
int primary_file_num_channels, int alpha_file_channel,
|
||||
bool read_mipmaps) {
|
||||
return get_global_ptr()->ns_load_texture(filename, alpha_filename,
|
||||
primary_file_num_channels,
|
||||
alpha_file_channel);
|
||||
primary_file_num_channels,
|
||||
alpha_file_channel,
|
||||
read_mipmaps);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -82,10 +97,15 @@ load_texture(const string &filename, const string &alpha_filename,
|
|||
// with index 0. The filename should include a sequence
|
||||
// of one or more hash characters ("#") which will be
|
||||
// filled in with the index number of each level.
|
||||
//
|
||||
// If read_mipmaps is true, the filename should contain
|
||||
// an additional hash mark. The first hash mark will be
|
||||
// filled in with the mipmap level number, and the
|
||||
// second with the index number of each 3-d level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Texture *TexturePool::
|
||||
load_3d_texture(const string &filename_pattern) {
|
||||
return get_global_ptr()->ns_load_3d_texture(filename_pattern);
|
||||
load_3d_texture(const string &filename_pattern, bool read_mipmaps) {
|
||||
return get_global_ptr()->ns_load_3d_texture(filename_pattern, read_mipmaps);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -96,10 +116,15 @@ load_3d_texture(const string &filename_pattern) {
|
|||
// filename should include a sequence of one or more
|
||||
// hash characters ("#") which will be filled in with
|
||||
// the index number of each pagee.
|
||||
//
|
||||
// If read_mipmaps is true, the filename should contain
|
||||
// an additional hash mark. The first hash mark will be
|
||||
// filled in with the mipmap level number, and the
|
||||
// second with the face number, 0 through 5.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Texture *TexturePool::
|
||||
load_cube_map(const string &filename_pattern) {
|
||||
return get_global_ptr()->ns_load_cube_map(filename_pattern);
|
||||
load_cube_map(const string &filename_pattern, bool read_mipmaps) {
|
||||
return get_global_ptr()->ns_load_cube_map(filename_pattern, read_mipmaps);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -206,7 +206,8 @@ ns_has_texture(const Filename &orig_filename) {
|
|||
// Description: The nonstatic implementation of load_texture().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Texture *TexturePool::
|
||||
ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) {
|
||||
ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
|
||||
bool read_mipmaps) {
|
||||
Filename filename(orig_filename);
|
||||
|
||||
if (!_fake_texture_image.empty()) {
|
||||
|
|
@ -227,7 +228,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) {
|
|||
gobj_cat.info()
|
||||
<< "Loading texture " << filename << "\n";
|
||||
PT(Texture) tex = make_texture(filename.get_extension());
|
||||
if (!tex->read(filename, 0, primary_file_num_channels)) {
|
||||
if (!tex->read(filename, 0, primary_file_num_channels, false, read_mipmaps)) {
|
||||
// This texture was not found or could not be read.
|
||||
report_texture_unreadable(filename);
|
||||
return NULL;
|
||||
|
|
@ -249,12 +250,14 @@ Texture *TexturePool::
|
|||
ns_load_texture(const Filename &orig_filename,
|
||||
const Filename &orig_alpha_filename,
|
||||
int primary_file_num_channels,
|
||||
int alpha_file_channel) {
|
||||
int alpha_file_channel,
|
||||
bool read_mipmaps) {
|
||||
Filename filename(orig_filename);
|
||||
Filename alpha_filename(orig_alpha_filename);
|
||||
|
||||
if (!_fake_texture_image.empty()) {
|
||||
return ns_load_texture(_fake_texture_image, primary_file_num_channels);
|
||||
return ns_load_texture(_fake_texture_image, primary_file_num_channels,
|
||||
read_mipmaps);
|
||||
}
|
||||
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
|
|
@ -275,8 +278,8 @@ ns_load_texture(const Filename &orig_filename,
|
|||
<< "Loading texture " << filename << " and alpha component "
|
||||
<< alpha_filename << endl;
|
||||
PT(Texture) tex = make_texture(filename.get_extension());
|
||||
if (!tex->read(filename, alpha_filename, 0, primary_file_num_channels,
|
||||
alpha_file_channel)) {
|
||||
if (!tex->read(filename, alpha_filename, primary_file_num_channels,
|
||||
alpha_file_channel, 0, 0, false, read_mipmaps)) {
|
||||
// This texture was not found or could not be read.
|
||||
report_texture_unreadable(filename);
|
||||
return NULL;
|
||||
|
|
@ -296,7 +299,8 @@ ns_load_texture(const Filename &orig_filename,
|
|||
// Description: The nonstatic implementation of load_3d_texture().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Texture *TexturePool::
|
||||
ns_load_3d_texture(const Filename &filename_pattern) {
|
||||
ns_load_3d_texture(const Filename &filename_pattern,
|
||||
bool read_mipmaps) {
|
||||
Filename filename(filename_pattern);
|
||||
filename.set_pattern(true);
|
||||
|
||||
|
|
@ -315,7 +319,7 @@ ns_load_3d_texture(const Filename &filename_pattern) {
|
|||
<< "Loading 3-d texture " << filename << "\n";
|
||||
PT(Texture) tex = make_texture(filename.get_extension());
|
||||
tex->setup_3d_texture();
|
||||
if (!tex->read_pages(filename)) {
|
||||
if (!tex->read(filename, 0, 0, true, read_mipmaps)) {
|
||||
// This texture was not found or could not be read.
|
||||
report_texture_unreadable(filename);
|
||||
return NULL;
|
||||
|
|
@ -334,7 +338,7 @@ ns_load_3d_texture(const Filename &filename_pattern) {
|
|||
// Description: The nonstatic implementation of load_cube_map().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Texture *TexturePool::
|
||||
ns_load_cube_map(const Filename &filename_pattern) {
|
||||
ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
|
||||
Filename filename(filename_pattern);
|
||||
filename.set_pattern(true);
|
||||
|
||||
|
|
@ -353,7 +357,7 @@ ns_load_cube_map(const Filename &filename_pattern) {
|
|||
<< "Loading cube map texture " << filename << "\n";
|
||||
PT(Texture) tex = make_texture(filename.get_extension());
|
||||
tex->setup_cube_map();
|
||||
if (!tex->read_pages(filename)) {
|
||||
if (!tex->read(filename, 0, 0, true, read_mipmaps)) {
|
||||
// This texture was not found or could not be read.
|
||||
report_texture_unreadable(filename);
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -42,13 +42,17 @@ PUBLISHED:
|
|||
INLINE static bool has_texture(const string &filename);
|
||||
INLINE static bool verify_texture(const string &filename);
|
||||
INLINE static Texture *load_texture(const string &filename,
|
||||
int primary_file_num_channels = 0);
|
||||
int primary_file_num_channels = 0,
|
||||
bool read_mipmaps = false);
|
||||
INLINE static Texture *load_texture(const string &filename,
|
||||
const string &alpha_filename,
|
||||
int primary_file_num_channels = 0,
|
||||
int alpha_file_channel = 0);
|
||||
INLINE static Texture *load_3d_texture(const string &filename_pattern);
|
||||
INLINE static Texture *load_cube_map(const string &filename_pattern);
|
||||
int alpha_file_channel = 0,
|
||||
bool read_mipmaps = false);
|
||||
INLINE static Texture *load_3d_texture(const string &filename_pattern,
|
||||
bool read_mipmaps = false);
|
||||
INLINE static Texture *load_cube_map(const string &filename_pattern,
|
||||
bool read_mipmaps = false);
|
||||
|
||||
INLINE static Texture *get_normalization_cube_map(int size);
|
||||
|
||||
|
|
@ -81,13 +85,18 @@ private:
|
|||
TexturePool();
|
||||
|
||||
bool ns_has_texture(const Filename &orig_filename);
|
||||
Texture *ns_load_texture(const Filename &orig_filename, int primary_file_num_channels);
|
||||
Texture *ns_load_texture(const Filename &orig_filename,
|
||||
int primary_file_num_channels,
|
||||
bool read_mipmaps);
|
||||
Texture *ns_load_texture(const Filename &orig_filename,
|
||||
const Filename &orig_alpha_filename,
|
||||
int primary_file_num_channels,
|
||||
int alpha_file_channel);
|
||||
Texture *ns_load_3d_texture(const Filename &filename_pattern);
|
||||
Texture *ns_load_cube_map(const Filename &filename_pattern);
|
||||
int alpha_file_channel,
|
||||
bool read_mipmaps);
|
||||
Texture *ns_load_3d_texture(const Filename &filename_pattern,
|
||||
bool read_mipmaps);
|
||||
Texture *ns_load_cube_map(const Filename &filename_pattern,
|
||||
bool read_mipmaps);
|
||||
Texture *ns_get_normalization_cube_map(int size);
|
||||
|
||||
void ns_add_texture(Texture *texture);
|
||||
|
|
|
|||
|
|
@ -263,13 +263,10 @@ get_alpha_scale() const {
|
|||
// Function: TextureStage::set_saved_result
|
||||
// Access: Published
|
||||
// Description: Sets the saved_result flag. When this is true, the
|
||||
// output of this stage is not part of the normal
|
||||
// pipeline--that is, it will not be supplied as the
|
||||
// "previous" source for the next texture stage--but it
|
||||
// will instead be supplied as the "last_saved_result"
|
||||
// source for any future stages, until the next
|
||||
// TextureStage with a saved_result set true is
|
||||
// encountered.
|
||||
// output of this stage will be supplied as the
|
||||
// "last_saved_result" source for any future stages,
|
||||
// until the next TextureStage with a saved_result set
|
||||
// true is encountered.
|
||||
//
|
||||
// This can be used to reuse the results of this texture
|
||||
// stage as input to more than one stage later in the
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ has_ram_image() const {
|
|||
if (this_frame != _last_frame_update) {
|
||||
return false;
|
||||
}
|
||||
return !_ram_image.empty();
|
||||
return !_ram_images.empty() && !_ram_images[0]._image.empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -85,7 +85,7 @@ has_ram_image() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool VideoTexture::
|
||||
get_keep_ram_image() const {
|
||||
// An VideoTexture should never dump its RAM image.
|
||||
// A VideoTexture should never dump its RAM image.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,136 +103,12 @@ from_camera(int camera_index, int z) {
|
|||
return false;
|
||||
}
|
||||
|
||||
set_loaded_from_disk();
|
||||
set_loaded_from_image();
|
||||
clear_current_frame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenCVTexture::read
|
||||
// Access: Published, Virtual
|
||||
// Description: Takes the video image from the indicated filename.
|
||||
// If the filename is not a video file, attempts to read
|
||||
// it as a still image instead.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool OpenCVTexture::
|
||||
read(const Filename &fullpath, int z, int) {
|
||||
if (!reconsider_z_size(z)) {
|
||||
return false;
|
||||
}
|
||||
nassertr(z >= 0 && z < get_z_size(), false);
|
||||
|
||||
VideoPage &page = modify_page(z);
|
||||
page._alpha.clear();
|
||||
if (!page._color.read(fullpath)) {
|
||||
grutil_cat.error()
|
||||
<< "OpenCV couldn't read " << fullpath << " as video.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!has_name()) {
|
||||
set_name(fullpath.get_basename_wo_extension());
|
||||
}
|
||||
if (!has_filename()) {
|
||||
set_filename(fullpath);
|
||||
clear_alpha_filename();
|
||||
}
|
||||
|
||||
set_fullpath(fullpath);
|
||||
clear_alpha_fullpath();
|
||||
|
||||
_primary_file_num_channels = 3;
|
||||
_alpha_file_channel = 0;
|
||||
|
||||
if (!reconsider_video_properties(page._color, 3, z)) {
|
||||
page._color.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
set_loaded_from_disk();
|
||||
clear_current_frame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenCVTexture::read
|
||||
// Access: Published, Virtual
|
||||
// Description: Combines a color and alpha video image from the two
|
||||
// indicated filenames. Both must be the same kind of
|
||||
// video with similar properties.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool OpenCVTexture::
|
||||
read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int z, int, int alpha_file_channel) {
|
||||
if (!reconsider_z_size(z)) {
|
||||
return false;
|
||||
}
|
||||
nassertr(z >= 0 && z < get_z_size(), false);
|
||||
|
||||
VideoPage &page = modify_page(z);
|
||||
if (!page._color.read(fullpath)) {
|
||||
grutil_cat.error()
|
||||
<< "OpenCV couldn't read " << fullpath << " as video.\n";
|
||||
return false;
|
||||
}
|
||||
if (!page._alpha.read(alpha_fullpath)) {
|
||||
grutil_cat.error()
|
||||
<< "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
|
||||
page._color.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!has_name()) {
|
||||
set_name(fullpath.get_basename_wo_extension());
|
||||
}
|
||||
if (!has_filename()) {
|
||||
set_filename(fullpath);
|
||||
set_alpha_filename(alpha_fullpath);
|
||||
}
|
||||
|
||||
set_fullpath(fullpath);
|
||||
set_alpha_fullpath(alpha_fullpath);
|
||||
|
||||
_primary_file_num_channels = 3;
|
||||
_alpha_file_channel = alpha_file_channel;
|
||||
|
||||
if (!reconsider_video_properties(page._color, 4, z)) {
|
||||
page._color.clear();
|
||||
page._alpha.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reconsider_video_properties(page._alpha, 4, z)) {
|
||||
page._color.clear();
|
||||
page._alpha.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
set_loaded_from_disk();
|
||||
clear_current_frame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenCVTexture::load
|
||||
// Access: Published, Virtual
|
||||
// Description: Resets the texture (or the particular level of the
|
||||
// texture) to the indicated static image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool OpenCVTexture::
|
||||
load(const PNMImage &pnmimage, int z) {
|
||||
if (z <= (int)_pages.size()) {
|
||||
VideoPage &page = modify_page(z);
|
||||
page._color.clear();
|
||||
page._alpha.clear();
|
||||
}
|
||||
|
||||
return Texture::load(pnmimage, z);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenCVTexture::modify_page
|
||||
// Access: Private
|
||||
|
|
@ -295,7 +171,7 @@ reconsider_video_properties(const OpenCVTexture::VideoStream &stream,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (_loaded_from_disk &&
|
||||
if (_loaded_from_image &&
|
||||
(get_video_width() != width || get_video_height() != height ||
|
||||
get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
|
||||
grutil_cat.error()
|
||||
|
|
@ -334,6 +210,7 @@ make_texture() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void OpenCVTexture::
|
||||
update_frame(int frame) {
|
||||
nassertv(has_ram_image());
|
||||
int max_z = max(_z_size, (int)_pages.size());
|
||||
for (int z = 0; z < max_z; ++z) {
|
||||
VideoPage &page = _pages[z];
|
||||
|
|
@ -346,7 +223,7 @@ update_frame(int frame) {
|
|||
const unsigned char *source = page._color.get_frame_data(frame);
|
||||
if (source != NULL) {
|
||||
nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
|
||||
unsigned char *dest = _ram_image.p() + get_expected_ram_page_size() * z;
|
||||
unsigned char *dest = _ram_images[0]._image.p() + get_expected_ram_page_size() * z;
|
||||
|
||||
int dest_row_width = (_x_size * _num_components * _component_width);
|
||||
int source_row_width = get_video_width() * 3;
|
||||
|
|
@ -385,7 +262,7 @@ update_frame(int frame) {
|
|||
const unsigned char *source = page._alpha.get_frame_data(frame);
|
||||
if (source != NULL) {
|
||||
nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
|
||||
unsigned char *dest = _ram_image.p() + get_expected_ram_page_size() * z;
|
||||
unsigned char *dest = _ram_images[0]._image.p() + get_expected_ram_page_size() * z;
|
||||
|
||||
int dest_row_width = (_x_size * _num_components * _component_width);
|
||||
int source_row_width = get_video_width() * 3;
|
||||
|
|
@ -409,6 +286,97 @@ update_frame(int frame) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenCVTexture::do_read_one
|
||||
// Access: Protected, Virtual
|
||||
// Description: Combines a color and alpha video image from the two
|
||||
// indicated filenames. Both must be the same kind of
|
||||
// video with similar properties.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool OpenCVTexture::
|
||||
do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int z, int n, int primary_file_num_channels, int alpha_file_channel) {
|
||||
nassertr(n == 0, false);
|
||||
nassertr(z >= 0 && z < get_z_size(), false);
|
||||
|
||||
VideoPage &page = modify_page(z);
|
||||
if (!page._color.read(fullpath)) {
|
||||
grutil_cat.error()
|
||||
<< "OpenCV couldn't read " << fullpath << " as video.\n";
|
||||
return false;
|
||||
}
|
||||
if (!alpha_fullpath.empty()) {
|
||||
if (!page._alpha.read(alpha_fullpath)) {
|
||||
grutil_cat.error()
|
||||
<< "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
|
||||
page._color.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (z == 0) {
|
||||
if (!has_name()) {
|
||||
set_name(fullpath.get_basename_wo_extension());
|
||||
}
|
||||
if (!has_filename()) {
|
||||
set_filename(fullpath);
|
||||
set_alpha_filename(alpha_fullpath);
|
||||
}
|
||||
|
||||
set_fullpath(fullpath);
|
||||
set_alpha_fullpath(alpha_fullpath);
|
||||
}
|
||||
|
||||
_primary_file_num_channels = 3;
|
||||
_alpha_file_channel = 0;
|
||||
|
||||
if (alpha_fullpath.empty()) {
|
||||
// Only one RGB movie.
|
||||
if (!reconsider_video_properties(page._color, 3, z)) {
|
||||
page._color.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// An RGB movie combined with an alpha movie.
|
||||
_alpha_file_channel = alpha_file_channel;
|
||||
|
||||
if (!reconsider_video_properties(page._color, 4, z)) {
|
||||
page._color.clear();
|
||||
page._alpha.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reconsider_video_properties(page._alpha, 4, z)) {
|
||||
page._color.clear();
|
||||
page._alpha.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
set_loaded_from_image();
|
||||
clear_current_frame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenCVTexture::do_load_one
|
||||
// Access: Protected, Virtual
|
||||
// Description: Resets the texture (or the particular level of the
|
||||
// texture) to the indicated static image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool OpenCVTexture::
|
||||
do_load_one(const PNMImage &pnmimage, int z, int n) {
|
||||
if (z <= (int)_pages.size()) {
|
||||
VideoPage &page = modify_page(z);
|
||||
page._color.clear();
|
||||
page._alpha.clear();
|
||||
}
|
||||
|
||||
return Texture::do_load_one(pnmimage, z, n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenCVTexture::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -47,19 +47,17 @@ PUBLISHED:
|
|||
|
||||
bool from_camera(int camera_index = -1, int z = 0);
|
||||
|
||||
virtual bool read(const Filename &fullpath, int z = 0,
|
||||
int primary_file_num_channels = 0);
|
||||
virtual bool read(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int z = 0,
|
||||
int primary_file_num_channels = 0, int alpha_file_channel = 0);
|
||||
virtual bool load(const PNMImage &pnmimage, int z = 0);
|
||||
|
||||
public:
|
||||
static PT(Texture) make_texture();
|
||||
|
||||
protected:
|
||||
virtual void update_frame(int frame);
|
||||
|
||||
virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
|
||||
int z, int n, int primary_file_num_channels, int alpha_file_channel);
|
||||
|
||||
virtual bool do_load_one(const PNMImage &pnmimage, int z, int n);
|
||||
|
||||
private:
|
||||
class VideoPage;
|
||||
class VideoStream;
|
||||
|
|
|
|||
|
|
@ -36,9 +36,10 @@ static const unsigned short _bam_major_ver = 6;
|
|||
// Bumped to major version 5 on 5/6/05 for new Geom implementation.
|
||||
// Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
|
||||
|
||||
static const unsigned short _bam_minor_ver = 2;
|
||||
static const unsigned short _bam_minor_ver = 3;
|
||||
// Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
|
||||
// Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
|
||||
// Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ EggToBam() :
|
|||
"stored uncompressed. A particular texture that is encoded into "
|
||||
"multiple different bam files in this way cannot be unified into "
|
||||
"the same part of texture memory if the different bam files are loaded "
|
||||
"together. All that being said, this can sometimes be a convenient "
|
||||
"together. That being said, this can sometimes be a convenient "
|
||||
"way to ensure the bam file is completely self-contained.",
|
||||
&EggToBam::dispatch_none, &_tex_rawdata);
|
||||
|
||||
|
|
@ -162,6 +162,16 @@ EggToBam() :
|
|||
"on the particular graphics card that was used to generate them.",
|
||||
&EggToBam::dispatch_none, &_tex_ctex);
|
||||
|
||||
add_option
|
||||
("mipmap", "", 0,
|
||||
"Records the pre-generated mipmap levels in the texture object file "
|
||||
"when using -rawtex or -txo, for textures that use mipmapping. This "
|
||||
"will increase the size of the texture object file by about 33%, but "
|
||||
"it prevents the need to compute the mipmaps at runtime. The default "
|
||||
"is to record mipmap levels only when the texture was specifically "
|
||||
"loaded with them.",
|
||||
&EggToBam::dispatch_none, &_tex_mipmap);
|
||||
|
||||
add_option
|
||||
("load-display", "display name", 0,
|
||||
"Specifies the particular display module to load to perform the texture "
|
||||
|
|
@ -241,10 +251,20 @@ run() {
|
|||
if (_tex_ctex) {
|
||||
tex->set_keep_ram_image(true);
|
||||
tex->set_compression(Texture::CM_on);
|
||||
bool has_mipmap_levels = (tex->get_num_ram_mipmap_images() > 1);
|
||||
if (!_engine->extract_texture_data(tex, _gsg)) {
|
||||
nout << " couldn't compress " << tex->get_name() << "\n";
|
||||
}
|
||||
if (!has_mipmap_levels && !_tex_mipmap) {
|
||||
// Make sure we didn't accidentally introduce mipmap levels
|
||||
// by rendezvousing through the graphics card.
|
||||
tex->clear_ram_mipmap_images();
|
||||
}
|
||||
} else if (_tex_mipmap && tex->uses_mipmaps()) {
|
||||
// Generate mipmap levels.
|
||||
tex->generate_ram_mipmap_images();
|
||||
}
|
||||
|
||||
if (_tex_txo || _tex_txopz) {
|
||||
convert_txo(tex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ private:
|
|||
bool _tex_txo;
|
||||
bool _tex_txopz;
|
||||
bool _tex_ctex;
|
||||
bool _tex_mipmap;
|
||||
string _load_display;
|
||||
|
||||
// The rest of this is required to support -ctex.
|
||||
|
|
|
|||
Loading…
Reference in New Issue