Add an use_hdr property to GradientTexture to allow storing HDR colors

This is disabled by default to save some memory and preserve the existing
behavior of clamping colors.
This commit is contained in:
Hugo Locurcio 2021-05-02 03:53:10 +02:00
parent 761eb7e06a
commit 1d257d02db
No known key found for this signature in database
GPG key ID: 39E8F8BE30B0A49C
3 changed files with 62 additions and 18 deletions

View file

@ -14,6 +14,9 @@
<member name="gradient" type="Gradient" setter="set_gradient" getter="get_gradient">
The [Gradient] that will be used to fill the texture.
</member>
<member name="use_hdr" type="bool" setter="set_use_hdr" getter="is_using_hdr" default="false">
If [code]true[/code], the generated texture will support high dynamic range ([constant Image.FORMAT_RGBAF] format). This allows for glow effects to work if [member Environment.glow_enabled] is [code]true[/code]. If [code]false[/code], the generated texture will use low dynamic range; overbright colors will be clamped ([constant Image.FORMAT_RGBA8] format).
</member>
<member name="width" type="int" setter="set_width" getter="get_width" default="2048">
The number of color samples that will be obtained from the [Gradient].
</member>

View file

@ -1758,11 +1758,16 @@ void GradientTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gradient"), &GradientTexture::get_gradient);
ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture::set_width);
// The `get_width()` method is already exposed by the parent class Texture2D.
ClassDB::bind_method(D_METHOD("set_use_hdr", "enabled"), &GradientTexture::set_use_hdr);
ClassDB::bind_method(D_METHOD("is_using_hdr"), &GradientTexture::is_using_hdr);
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
}
void GradientTexture::set_gradient(Ref<Gradient> p_gradient) {
@ -1800,30 +1805,49 @@ void GradientTexture::_update() {
return;
}
Vector<uint8_t> data;
data.resize(width * 4);
{
uint8_t *wd8 = data.ptrw();
if (use_hdr) {
// High dynamic range.
Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBAF));
Gradient &g = **gradient;
// `create()` isn't available for non-uint8_t data, so fill in the data manually.
for (int i = 0; i < width; i++) {
float ofs = float(i) / (width - 1);
Color color = g.get_color_at_offset(ofs);
wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
image->set_pixel(i, 0, g.get_color_at_offset(ofs));
}
}
Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
if (texture.is_valid()) {
RID new_texture = RS::get_singleton()->texture_2d_create(image);
RS::get_singleton()->texture_replace(texture, new_texture);
if (texture.is_valid()) {
RID new_texture = RS::get_singleton()->texture_2d_create(image);
RS::get_singleton()->texture_replace(texture, new_texture);
} else {
texture = RS::get_singleton()->texture_2d_create(image);
}
} else {
texture = RS::get_singleton()->texture_2d_create(image);
// Low dynamic range. "Overbright" colors will be clamped.
Vector<uint8_t> data;
data.resize(width * 4);
{
uint8_t *wd8 = data.ptrw();
Gradient &g = **gradient;
for (int i = 0; i < width; i++) {
float ofs = float(i) / (width - 1);
Color color = g.get_color_at_offset(ofs);
wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
}
}
Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
if (texture.is_valid()) {
RID new_texture = RS::get_singleton()->texture_2d_create(image);
RS::get_singleton()->texture_replace(texture, new_texture);
} else {
texture = RS::get_singleton()->texture_2d_create(image);
}
}
emit_changed();
@ -1839,6 +1863,19 @@ int GradientTexture::get_width() const {
return width;
}
void GradientTexture::set_use_hdr(bool p_enabled) {
if (p_enabled == use_hdr) {
return;
}
use_hdr = p_enabled;
_queue_update();
}
bool GradientTexture::is_using_hdr() const {
return use_hdr;
}
Ref<Image> GradientTexture::get_image() const {
if (!texture.is_valid()) {
return Ref<Image>();

View file

@ -686,6 +686,7 @@ private:
bool update_pending = false;
RID texture;
int width = 2048;
bool use_hdr = false;
void _queue_update();
void _update();
@ -700,6 +701,9 @@ public:
void set_width(int p_width);
int get_width() const override;
void set_use_hdr(bool p_enabled);
bool is_using_hdr() const;
virtual RID get_rid() const override { return texture; }
virtual int get_height() const override { return 1; }
virtual bool has_alpha() const override { return true; }