mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
Implement texture clear, fix immutable tex support
This commit is contained in:
parent
cb66a51bbc
commit
01b669ccd8
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user