Implement texture clear, fix immutable tex support

This commit is contained in:
rdb 2014-12-21 14:13:49 +01:00
parent cb66a51bbc
commit 01b669ccd8
6 changed files with 413 additions and 104 deletions

View File

@ -800,6 +800,21 @@ reset() {
}
}
_supports_clear_texture = false;
#ifndef OPENGLES
if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_clear_texture")) {
_glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)
get_extension_func("glClearTexImage");
if (_glClearTexImage == NULL) {
GLCAT.warning()
<< "GL_ARB_clear_texture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
} else {
_supports_clear_texture = true;
}
}
#endif
_supports_2d_texture_array = false;
#ifndef OPENGLES
_supports_2d_texture_array = has_extension("GL_EXT_texture_array");
@ -7519,7 +7534,7 @@ get_external_image_format(Texture *tex) const {
// suitable internal format for GL textures.
////////////////////////////////////////////////////////////////////
GLint CLP(GraphicsStateGuardian)::
get_internal_image_format(Texture *tex) const {
get_internal_image_format(Texture *tex, bool force_sized) const {
Texture::CompressionMode compression = tex->get_compression();
if (compression == Texture::CM_default) {
compression = (compressed_textures) ? Texture::CM_on : Texture::CM_off;
@ -7752,7 +7767,7 @@ get_internal_image_format(Texture *tex) const {
} else
#endif
{
return GL_DEPTH_STENCIL;
return force_sized ? GL_DEPTH24_STENCIL8 : GL_DEPTH_STENCIL;
}
}
// Fall through.
@ -7764,7 +7779,7 @@ get_internal_image_format(Texture *tex) const {
} else
#endif
{
return GL_DEPTH_COMPONENT;
return force_sized ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT;
}
case Texture::F_depth_component16:
#ifdef OPENGLES
@ -7811,7 +7826,7 @@ get_internal_image_format(Texture *tex) const {
} else
#endif
{
return GL_RGBA;
return force_sized ? GL_RGBA8 : GL_RGBA;
}
case Texture::F_rgba4:
@ -7821,7 +7836,7 @@ get_internal_image_format(Texture *tex) const {
case Texture::F_rgba8:
return GL_RGBA8_OES;
case Texture::F_rgba12:
return GL_RGBA;
return force_sized ? GL_RGBA8 : GL_RGBA;
#else
case Texture::F_rgba8:
return GL_RGBA8;
@ -7843,7 +7858,7 @@ get_internal_image_format(Texture *tex) const {
if (tex->get_component_type() == Texture::T_float) {
return GL_RGB16F;
} else {
return GL_RGB;
return force_sized ? GL_RGB8 : GL_RGB;
}
case Texture::F_rgb5:
@ -7860,7 +7875,7 @@ get_internal_image_format(Texture *tex) const {
case Texture::F_rgb8:
return GL_RGB8_OES;
case Texture::F_rgb12:
return GL_RGB;
return force_sized ? GL_RGB8 : GL_RGB;
case Texture::F_rgb16:
return GL_RGB16F;
#else
@ -7912,25 +7927,26 @@ get_internal_image_format(Texture *tex) const {
case Texture::F_red:
case Texture::F_green:
case Texture::F_blue:
return GL_RED;
return force_sized ? GL_R8 : GL_RED;
#endif
case Texture::F_alpha:
return GL_ALPHA;
return force_sized ? GL_ALPHA8 : GL_ALPHA;
case Texture::F_luminance:
if (tex->get_component_type() == Texture::T_float) {
return GL_LUMINANCE16F_ARB;
} else if (tex->get_component_type() == Texture::T_unsigned_short) {
return GL_LUMINANCE16;
} else {
return GL_LUMINANCE;
return force_sized ? GL_LUMINANCE8 : GL_LUMINANCE;
}
case Texture::F_luminance_alpha:
case Texture::F_luminance_alphamask:
if (tex->get_component_type() == Texture::T_float || tex->get_component_type() == Texture::T_unsigned_short) {
return GL_LUMINANCE_ALPHA16F_ARB;
} else {
return GL_LUMINANCE_ALPHA;
return force_sized ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA;
}
#ifndef OPENGLES_1
@ -7953,7 +7969,7 @@ get_internal_image_format(Texture *tex) const {
GLCAT.error()
<< "Invalid image format in get_internal_image_format(): "
<< (int)tex->get_format() << "\n";
return GL_RGB;
return force_sized ? GL_RGB8 : GL_RGB;
}
}
@ -9359,6 +9375,8 @@ update_show_usage_texture_bindings(int show_stage_index) {
GLuint index = (*ui).second;
glBindTexture(GL_TEXTURE_2D, index);
}
//TODO: glBindSampler(0) ?
}
report_my_gl_errors();
@ -10052,7 +10070,11 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
int height = tex->get_y_size();
int depth = tex->get_z_size();
GLint internal_format = get_internal_image_format(tex);
// If we'll use immutable texture storage, we have to pick a sized
// image format.
bool force_sized = (gl_immutable_texture_storage && _supports_tex_storage);
GLint internal_format = get_internal_image_format(tex, force_sized);
GLint external_format = get_external_image_format(tex);
GLenum component_type = get_component_type(tex->get_component_type());
@ -10207,6 +10229,8 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
CPTA_uchar image = tex->get_ram_mipmap_image(mipmap_bias);
if (image.is_null()) {
// We don't even have a RAM image, so we have no choice but to let
// mipmaps be generated on the GPU.
if (uses_mipmaps) {
if (_supports_generate_mipmap) {
num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias;
@ -10372,7 +10396,9 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
component_type, false, 0, image_compression);
}
if (gtc->_generate_mipmaps && _glGenerateMipmap != NULL) {
if (gtc->_generate_mipmaps && _glGenerateMipmap != NULL &&
!image.is_null()) {
// We uploaded an image; we may need to generate mipmaps.
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "generating mipmaps for texture " << tex->get_name() << ", "
@ -10470,6 +10496,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
int depth = tex->get_expected_mipmap_z_size(mipmap_bias);
// Determine the number of images to upload.
int num_levels = 1;
if (uses_mipmaps) {
num_levels = tex->get_expected_num_mipmap_levels();
}
int num_ram_mipmap_levels = 0;
if (!image.is_null()) {
if (uses_mipmaps) {
@ -10494,49 +10525,85 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
if (GLCAT.is_debug()) {
if (num_ram_mipmap_levels == 0) {
GLCAT.debug()
<< "not loading NULL image for tex " << tex->get_name() << ", " << width << " x " << height
<< " x " << depth << ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n";
if (tex->has_clear_color()) {
GLCAT.debug()
<< "clearing texture " << tex->get_name() << ", "
<< width << " x " << height << " x " << depth << ", z = " << z
<< ", uses_mipmaps = " << uses_mipmaps << ", clear_color = "
<< tex->get_clear_color() << "\n";
} else {
GLCAT.debug()
<< "not loading NULL image for texture " << tex->get_name()
<< ", " << width << " x " << height << " x " << depth
<< ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n";
}
} else {
GLCAT.debug()
<< "updating image data of texture " << tex->get_name() << ", " << width << " x " << height
<< " x " << depth << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels
<< "updating image data of texture " << tex->get_name()
<< ", " << width << " x " << height << " x " << depth
<< ", z = " << z << ", mipmaps " << num_ram_mipmap_levels
<< ", uses_mipmaps = " << uses_mipmaps << "\n";
}
}
for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) {
for (int n = mipmap_bias; n < num_levels; ++n) {
// we grab the mipmap pointer first, if it is NULL we grab the
// normal mipmap image pointer which is a PTA_uchar
const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n);
CPTA_uchar ptimage;
if (image_ptr == (const unsigned char *)NULL) {
ptimage = tex->get_ram_mipmap_image(n);
if (ptimage == (const unsigned char *)NULL) {
GLCAT.warning()
<< "No mipmap level " << n << " defined for " << tex->get_name()
<< "\n";
// No mipmap level n; stop here.
break;
if (ptimage.is_null()) {
if (n < num_ram_mipmap_levels) {
// We were told we'd have this many RAM mipmap images, but
// we don't. Raise a warning.
GLCAT.warning()
<< "No mipmap level " << n << " defined for " << tex->get_name()
<< "\n";
break;
}
if (tex->has_clear_color()) {
// The texture has a clear color, so we should fill this mipmap
// level to a solid color.
if (_supports_clear_texture) {
// We can do that with the convenient glClearTexImage function.
string clear_data = tex->get_clear_data();
_glClearTexImage(gtc->_index, n - mipmap_bias, external_format,
component_type, (void *)clear_data.data());
continue;
} else {
// Ask the Texture class to create the mipmap level in RAM.
// It'll fill it in with the correct clear color, which we
// can then upload.
ptimage = tex->make_ram_mipmap_image(n);
}
} else {
// No clear color and no more images.
break;
}
}
image_ptr = ptimage;
}
const unsigned char *orig_image_ptr = image_ptr;
size_t view_size = tex->get_ram_mipmap_view_size(n);
image_ptr += view_size * gtc->get_view();
if (one_page_only) {
view_size = tex->get_ram_mipmap_page_size(n);
image_ptr += view_size * z;
}
nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
PTA_uchar bgr_image;
if (!_supports_bgr && image_compression == Texture::CM_off) {
// If the GL doesn't claim to support BGR, we may have to reverse
// the component ordering of the image.
image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size,
external_format, tex);
size_t view_size = tex->get_ram_mipmap_view_size(n);
if (image_ptr != (const unsigned char *)NULL) {
const unsigned char *orig_image_ptr = image_ptr;
image_ptr += view_size * gtc->get_view();
if (one_page_only) {
view_size = tex->get_ram_mipmap_page_size(n);
image_ptr += view_size * z;
}
nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
if (!_supports_bgr && image_compression == Texture::CM_off) {
// If the GL doesn't claim to support BGR, we may have to reverse
// the component ordering of the image.
image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size,
external_format, tex);
}
}
int width = tex->get_expected_mipmap_x_size(n);
@ -10651,63 +10718,56 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
component_type = GL_UNSIGNED_INT_24_8_EXT;
#endif
}
// We don't have any RAM mipmap levels, so we create an uninitialized OpenGL
// texture. Presumably this will be used later for render-to-texture or so.
switch (page_target) {
#ifndef OPENGLES
case GL_TEXTURE_1D:
glTexImage1D(page_target, 0, internal_format, width, 0, external_format, component_type, NULL);
break;
case GL_TEXTURE_2D_ARRAY:
#endif
#ifndef OPENGLES_1
case GL_TEXTURE_3D:
_glTexImage3D(page_target, 0, internal_format, width, height, depth, 0, external_format, component_type, NULL);
break;
#endif
default:
glTexImage2D(page_target, 0, internal_format, width, height, 0, external_format, component_type, NULL);
break;
}
}
for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) {
for (int n = mipmap_bias; n < num_levels; ++n) {
const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n);
CPTA_uchar ptimage;
if (image_ptr == (const unsigned char *)NULL) {
ptimage = tex->get_ram_mipmap_image(n);
if (ptimage == (const unsigned char *)NULL) {
GLCAT.warning()
<< "No mipmap level " << n << " defined for " << tex->get_name()
<< "\n";
// No mipmap level n; stop here.
#ifndef OPENGLES
if (is_at_least_gl_version(1, 2)) {
// Tell the GL we have no more mipmaps for it to use.
glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias);
if (ptimage.is_null()) {
if (n < num_ram_mipmap_levels) {
// We were told we'd have this many RAM mipmap images, but
// we don't. Raise a warning.
GLCAT.warning()
<< "No mipmap level " << n << " defined for " << tex->get_name()
<< "\n";
#ifndef OPENGLES
if (is_at_least_gl_version(1, 2)) {
// Tell the GL we have no more mipmaps for it to use.
glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias);
}
#endif
break;
}
if (tex->has_clear_color()) {
// Ask the Texture class to create the mipmap level in RAM.
// It'll fill it in with the correct clear color, which we
// can then upload.
ptimage = tex->make_ram_mipmap_image(n);
}
#endif
break;
}
image_ptr = ptimage;
}
const unsigned char *orig_image_ptr = image_ptr;
size_t view_size = tex->get_ram_mipmap_view_size(n);
image_ptr += view_size * gtc->get_view();
if (one_page_only) {
view_size = tex->get_ram_mipmap_page_size(n);
image_ptr += view_size * z;
}
nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
PTA_uchar bgr_image;
if (!_supports_bgr && image_compression == Texture::CM_off) {
// If the GL doesn't claim to support BGR, we may have to reverse
// the component ordering of the image.
image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size,
external_format, tex);
size_t view_size = tex->get_ram_mipmap_view_size(n);
if (image_ptr != (const unsigned char *)NULL) {
const unsigned char *orig_image_ptr = image_ptr;
image_ptr += view_size * gtc->get_view();
if (one_page_only) {
view_size = tex->get_ram_mipmap_page_size(n);
image_ptr += view_size * z;
}
nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
if (!_supports_bgr && image_compression == Texture::CM_off) {
// If the GL doesn't claim to support BGR, we may have to reverse
// the component ordering of the image.
image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size,
external_format, tex);
}
}
int width = tex->get_expected_mipmap_x_size(n);

View File

@ -194,6 +194,8 @@ typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pna
typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);
typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
@ -461,7 +463,7 @@ protected:
static SamplerState::FilterType get_panda_filter_type(GLenum ft);
GLenum get_component_type(Texture::ComponentType component_type);
GLint get_external_image_format(Texture *tex) const;
GLint get_internal_image_format(Texture *tex) const;
GLint get_internal_image_format(Texture *tex, bool force_sized=false) const;
static bool is_mipmap_filter(GLenum min_filter);
static bool is_compressed_format(GLenum format);
static GLint get_texture_apply_mode_type(TextureStage::Mode am);
@ -644,6 +646,11 @@ public:
PFNGLTEXSTORAGE2DPROC _glTexStorage2D;
PFNGLTEXSTORAGE3DPROC _glTexStorage3D;
bool _supports_clear_texture;
#ifndef OPENGLES
PFNGLCLEARTEXIMAGEPROC _glClearTexImage;
#endif
PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D;
PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D;
PFNGLCOMPRESSEDTEXIMAGE3DPROC _glCompressedTexImage3D;

View File

@ -1228,17 +1228,14 @@ update_shader_texture_bindings(ShaderContext *prev) {
} else {
//TODO: automatically convert to sized type instead of plain GL_RGBA
// If a base type is used, it will crash.
if (gtc->_internal_format == GL_RGBA || gtc->_internal_format == GL_RGB) {
GLenum internal_format = gtc->_internal_format;
if (internal_format == GL_RGBA || internal_format == GL_RGB) {
GLCAT.error()
<< "Texture " << tex->get_name() << " has an unsized format. Textures bound "
<< "to a shader as an image need a sized format.\n";
// This may not actually be right, but may still prevent a crash.
if (gtc->_internal_format == GL_RGBA) {
gtc->_internal_format = GL_RGBA8;
} else {
gtc->_internal_format = GL_RGB8;
}
internal_format = _glgsg->get_internal_image_format(tex, true);
}
GLenum access = GL_READ_ONLY;

View File

@ -55,7 +55,8 @@ clear() {
// Description: Sets the texture to the indicated type and
// dimensions, presumably in preparation for calling
// read() or load(), or set_ram_image() or
// modify_ram_image().
// modify_ram_image(), or use set_clear_color to let
// the texture be cleared to a solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
@ -71,7 +72,9 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
// Access: Published
// Description: Sets the texture as an empty 1-d texture with no
// dimensions. Follow up with read() or load() to fill
// the texture properties and image data.
// the texture properties and image data, or use
// set_clear_color to let the texture be cleared to a
// solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_1d_texture() {
@ -84,7 +87,8 @@ setup_1d_texture() {
// Description: Sets the texture as an empty 1-d texture with the
// specified dimensions and properties. Follow up with
// set_ram_image() or modify_ram_image() to fill the
// image data.
// image data, or use set_clear_color to let the
// texture be cleared to a solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_1d_texture(int x_size, ComponentType component_type, Format format) {
@ -96,7 +100,9 @@ setup_1d_texture(int x_size, ComponentType component_type, Format format) {
// Access: Published
// Description: Sets the texture as an empty 2-d texture with no
// dimensions. Follow up with read() or load() to fill
// the texture properties and image data.
// the texture properties and image data, or use
// set_clear_color to let the texture be cleared to a
// solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_2d_texture() {
@ -109,7 +115,8 @@ setup_2d_texture() {
// Description: Sets the texture as an empty 2-d texture with the
// specified dimensions and properties. Follow up with
// set_ram_image() or modify_ram_image() to fill the
// image data.
// image data, or use set_clear_color to let the
// texture be cleared to a solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_2d_texture(int x_size, int y_size, ComponentType component_type,
@ -124,7 +131,8 @@ setup_2d_texture(int x_size, int y_size, ComponentType component_type,
// dimensions (though if you know the depth ahead
// of time, it saves a bit of reallocation later).
// Follow up with read() or load() to fill the texture
// properties and image data.
// properties and image data, or use set_clear_color
// to let the texture be cleared to a solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_3d_texture(int z_size) {
@ -152,7 +160,8 @@ setup_3d_texture(int x_size, int y_size, int z_size,
// no dimensions (though if you know the depth ahead
// of time, it saves a bit of reallocation later).
// Follow up with read() or load() to fill the texture
// properties and image data.
// properties and image data, or use set_clear_color
// to let the texture be cleared to a solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_2d_texture_array(int z_size) {
@ -165,7 +174,8 @@ setup_2d_texture_array(int z_size) {
// Description: Sets the texture as an empty 2-d texture array with the
// specified dimensions and properties. Follow up with
// set_ram_image() or modify_ram_image() to fill the
// image data.
// image data, or use set_clear_color to let the
// texture be cleared to a solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_2d_texture_array(int x_size, int y_size, int z_size,
@ -178,7 +188,9 @@ setup_2d_texture_array(int x_size, int y_size, int z_size,
// Access: Published
// Description: Sets the texture as an empty cube map texture with no
// dimensions. Follow up with read() or load() to fill
// the texture properties and image data.
// the texture properties and image data, or use
// set_clear_color to let the texture be cleared to a
// solid color.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
setup_cube_map() {
@ -191,7 +203,8 @@ setup_cube_map() {
// Description: Sets the texture as an empty cube map texture with
// the specified dimensions and properties. Follow up
// with set_ram_image() or modify_ram_image() to fill
// the image data.
// the image data, or use set_clear_color to let the
// texture be cleared to a solid color.
//
// Note that a cube map should always consist of six
// square images, so x_size and y_size will be the same,
@ -202,6 +215,87 @@ setup_cube_map(int size, ComponentType component_type, Format format) {
setup_texture(TT_cube_map, size, size, 6, component_type, format);
}
////////////////////////////////////////////////////////////////////
// Function: Texture::clear_image
// Access: Published
// Description: Clears the texture data without changing its format
// or resolution. The texture is cleared on both the
// graphics hardware and from RAM, unlike clear_ram_image,
// which only removes the data from RAM.
//
// If a clear color has been specified using
// set_clear_color, the texture will be cleared using
// a solid color.
//
// The texture data will be cleared the first time in
// which the texture is used after this method is called.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
clear_image() {
CDWriter cdata(_cycler, true);
do_clear_ram_image(cdata);
do_clear_simple_ram_image(cdata);
cdata->inc_image_modified();
cdata->inc_simple_image_modified();
}
////////////////////////////////////////////////////////////////////
// Function: Texture::has_clear_color
// Access: Published
// Description: Returns true if a color was previously set using
// set_clear_color.
////////////////////////////////////////////////////////////////////
INLINE bool Texture::
has_clear_color() const {
CDReader cdata(_cycler);
return cdata->_has_clear_color;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::get_clear_color
// Access: Published
// Description: Returns the color that was previously set using
// set_clear_color.
////////////////////////////////////////////////////////////////////
INLINE LColor Texture::
get_clear_color() const {
CDReader cdata(_cycler);
return cdata->_clear_color;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::set_clear_color
// Access: Published
// Description: Sets the color that will be used to fill the
// texture image in absence of any image data. It is
// used when any of the setup_texture functions or
// clear_image is called and image data is not
// provided using read() or modify_ram_image().
//
// This does not affect a texture that has already
// been cleared; call clear_image to clear it again.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
set_clear_color(const LColor &color) {
CDWriter cdata(_cycler, true);
cdata->_clear_color = color;
cdata->_has_clear_color = true;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::get_clear_data
// Access: Published
// Description: Returns the raw image data for a single pixel if
// it were set to the clear color.
////////////////////////////////////////////////////////////////////
INLINE string Texture::
get_clear_data() const {
CDReader cdata(_cycler);
unsigned char data[16];
int size = do_get_clear_data(cdata, data);
return string((char *)data, size);
}
////////////////////////////////////////////////////////////////////
// Function: Texture::write
// Access: Published

View File

@ -4258,12 +4258,26 @@ do_modify_ram_image(CData *cdata) {
////////////////////////////////////////////////////////////////////
PTA_uchar Texture::
do_make_ram_image(CData *cdata) {
int image_size = do_get_expected_ram_image_size(cdata);
cdata->_ram_images.clear();
cdata->_ram_images.push_back(RamImage());
cdata->_ram_images[0]._page_size = do_get_expected_ram_page_size(cdata);
cdata->_ram_images[0]._image = PTA_uchar::empty_array(do_get_expected_ram_image_size(cdata), get_class_type());
cdata->_ram_images[0]._image = PTA_uchar::empty_array(image_size, get_class_type());
cdata->_ram_images[0]._pointer_image = NULL;
cdata->_ram_image_compression = CM_off;
if (cdata->_has_clear_color) {
// Fill the image with the clear color.
unsigned char pixel[16];
const int pixel_size = do_get_clear_data(cdata, pixel);
nassertr(pixel_size > 0, cdata->_ram_images[0]._image);
unsigned char *image_data = cdata->_ram_images[0]._image;
for (int i = 0; i < image_size; i += pixel_size) {
memcpy(image_data + i, pixel, pixel_size);
}
}
return cdata->_ram_images[0]._image;
}
@ -4331,9 +4345,23 @@ do_make_ram_mipmap_image(CData *cdata, int n) {
cdata->_ram_images.push_back(RamImage());
}
cdata->_ram_images[n]._image = PTA_uchar::empty_array(do_get_expected_ram_mipmap_image_size(cdata, n), get_class_type());
size_t image_size = do_get_expected_ram_mipmap_image_size(cdata, n);
cdata->_ram_images[n]._image = PTA_uchar::empty_array(image_size, get_class_type());
cdata->_ram_images[n]._pointer_image = NULL;
cdata->_ram_images[n]._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
if (cdata->_has_clear_color) {
// Fill the image with the clear color.
unsigned char pixel[16];
const int pixel_size = do_get_clear_data(cdata, pixel);
nassertr(pixel_size > 0, cdata->_ram_images[n]._image);
unsigned char *image_data = cdata->_ram_images[n]._image;
for (int i = 0; i < image_size; i += pixel_size) {
memcpy(image_data + i, pixel, pixel_size);
}
}
return cdata->_ram_images[n]._image;
}
@ -4362,6 +4390,116 @@ do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size)
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::do_get_clear_color
// Access: Published
// Description: Returns a string with a single pixel representing
// the clear color of the texture in the format of
// this texture.
//
// In other words, to create an uncompressed RAM
// texture filled with the clear color, it should
// be initialized with this string repeated for
// every pixel.
////////////////////////////////////////////////////////////////////
int Texture::
do_get_clear_data(const CData *cdata, unsigned char *into) const {
nassertr(cdata->_has_clear_color, 0);
nassertr(cdata->_num_components <= 4, 0);
//TODO: encode the color into the sRGB color space if used
switch (cdata->_component_type) {
case T_unsigned_byte:
{
LColorf scaled = cdata->_clear_color.fmin(LColorf(1)).fmax(LColorf::zero());
scaled *= 255;
switch (cdata->_num_components) {
case 2:
into[1] = (unsigned char)scaled[1];
case 1:
into[0] = (unsigned char)scaled[0];
break;
case 4:
into[3] = (unsigned char)scaled[3];
case 3: // BGR <-> RGB
into[0] = (unsigned char)scaled[2];
into[1] = (unsigned char)scaled[1];
into[2] = (unsigned char)scaled[0];
break;
}
break;
}
case T_unsigned_short:
{
LColorf scaled = cdata->_clear_color.fmin(LColorf(1)).fmax(LColorf::zero());
scaled *= 65535;
switch (cdata->_num_components) {
case 2:
((unsigned short *)into)[1] = (unsigned short)scaled[1];
case 1:
((unsigned short *)into)[0] = (unsigned short)scaled[0];
break;
case 4:
((unsigned short *)into)[3] = (unsigned short)scaled[3];
case 3: // BGR <-> RGB
((unsigned short *)into)[0] = (unsigned short)scaled[2];
((unsigned short *)into)[1] = (unsigned short)scaled[1];
((unsigned short *)into)[2] = (unsigned short)scaled[0];
break;
}
break;
}
case T_float:
switch (cdata->_num_components) {
case 2:
((float *)into)[1] = cdata->_clear_color[1];
case 1:
((float *)into)[0] = cdata->_clear_color[0];
break;
case 4:
((float *)into)[3] = cdata->_clear_color[3];
case 3: // BGR <-> RGB
((float *)into)[0] = cdata->_clear_color[2];
((float *)into)[1] = cdata->_clear_color[1];
((float *)into)[2] = cdata->_clear_color[0];
break;
}
break;
case T_unsigned_int_24_8:
nassertr(cdata->_num_components == 1, 0);
*((unsigned int *)into) =
((unsigned int)(cdata->_clear_color[0] * 16777215) << 8) +
(unsigned int)max(min(cdata->_clear_color[1], 255), 0);
break;
case T_int:
{
// Note: there are no 32-bit UNORM textures. Therefore, we don't
// do any normalization here, either.
switch (cdata->_num_components) {
case 2:
((int *)into)[1] = (int)cdata->_clear_color[1];
case 1:
((int *)into)[0] = (int)cdata->_clear_color[0];
break;
case 4:
((int *)into)[3] = (int)cdata->_clear_color[3];
case 3: // BGR <-> RGB
((int *)into)[0] = (int)cdata->_clear_color[2];
((int *)into)[1] = (int)cdata->_clear_color[1];
((int *)into)[2] = (int)cdata->_clear_color[0];
break;
}
break;
}
}
return cdata->_num_components * cdata->_component_width;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::consider_auto_process_ram_image
// Access: Protected
@ -8151,6 +8289,8 @@ CData() {
_simple_x_size = 0;
_simple_y_size = 0;
_simple_ram_image._page_size = 0;
_has_clear_color = false;
}
////////////////////////////////////////////////////////////////////

View File

@ -234,6 +234,12 @@ PUBLISHED:
void generate_normalization_cube_map(int size);
void generate_alpha_scale_map();
INLINE void clear_image();
INLINE bool has_clear_color() const;
INLINE LColor get_clear_color() const;
INLINE void set_clear_color(const LColor &color);
INLINE string get_clear_data() const;
BLOCKING bool read(const Filename &fullpath, const LoaderOptions &options = LoaderOptions());
BLOCKING bool read(const Filename &fullpath, const Filename &alpha_fullpath,
int primary_file_num_channels, int alpha_file_channel,
@ -569,6 +575,7 @@ protected:
PTA_uchar do_modify_ram_mipmap_image(CData *cdata, int n);
PTA_uchar do_make_ram_mipmap_image(CData *cdata, int n);
void do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size);
int do_get_clear_data(const CData *cdata, unsigned char *into) const;
bool consider_auto_process_ram_image(bool generate_mipmaps, bool allow_compression);
bool do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps,
@ -844,6 +851,10 @@ protected:
int _simple_y_size;
PN_int32 _simple_image_date_generated;
// This is the color that should be used when no image was given.
bool _has_clear_color;
LColor _clear_color;
UpdateSeq _properties_modified;
UpdateSeq _image_modified;
UpdateSeq _simple_image_modified;