Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve layered texture preview #92540

Merged
merged 1 commit into from
Aug 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 93 additions & 34 deletions editor/plugins/texture_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
@@ -30,8 +30,25 @@

#include "texture_3d_editor_plugin.h"

#include "editor/editor_string_names.h"
#include "editor/themes/editor_scale.h"
#include "scene/gui/label.h"

// Shader sources.

constexpr const char *texture_3d_shader = R"(
// Texture3DEditor preview shader.
shader_type canvas_item;
uniform sampler3D tex;
uniform float layer;
void fragment() {
COLOR = textureLod(tex, vec3(UV, layer), 0.0);
}
)";

void Texture3DEditor::_texture_rect_draw() {
texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1));
}
@@ -48,42 +65,41 @@ void Texture3DEditor::_notification(int p_what) {

draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
} break;

case NOTIFICATION_THEME_CHANGED: {
if (info) {
Ref<Font> metadata_label_font = get_theme_font(SNAME("expression"), EditorStringName(EditorFonts));
info->add_theme_font_override(SceneStringName(font), metadata_label_font);
}
} break;
}
}

void Texture3DEditor::_texture_changed() {
if (!is_visible()) {
return;
}

setting = true;
_update_gui();
setting = false;

_update_material(true);
queue_redraw();
}

void Texture3DEditor::_update_material() {
void Texture3DEditor::_update_material(bool p_texture_changed) {
material->set_shader_parameter("layer", (layer->get_value() + 0.5) / texture->get_depth());
material->set_shader_parameter("tex", texture->get_rid());

String format = Image::get_format_name(texture->get_format());

String text;
text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + "x" + itos(texture->get_depth()) + " " + format;

info->set_text(text);
if (p_texture_changed) {
material->set_shader_parameter("tex", texture->get_rid());
}
}

void Texture3DEditor::_make_shaders() {
shader.instantiate();
shader->set_code(R"(
// Texture3DEditor preview shader.
shader_type canvas_item;
uniform sampler3D tex;
uniform float layer;
shader->set_code(texture_3d_shader);

void fragment() {
COLOR = textureLod(tex, vec3(UV, layer), 0.0);
}
)");
material.instantiate();
material->set_shader(shader);
}
@@ -113,6 +129,41 @@ void Texture3DEditor::_texture_rect_update_area() {
texture_rect->set_size(Vector2(tex_width, tex_height));
}

void Texture3DEditor::_update_gui() {
if (texture.is_null()) {
return;
}

_texture_rect_update_area();

layer->set_max(texture->get_depth() - 1);

const String format = Image::get_format_name(texture->get_format());

if (texture->has_mipmaps()) {
const int mip_count = Image::get_image_required_mipmaps(texture->get_width(), texture->get_height(), texture->get_format());
const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), true) * texture->get_depth();

info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("%s Mipmaps") + "\n" + TTR("Memory: %s"),
texture->get_width(),
texture->get_height(),
texture->get_depth(),
format,
mip_count,
String::humanize_size(memory)));

} else {
const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), false) * texture->get_depth();

info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("No Mipmaps") + "\n" + TTR("Memory: %s"),
texture->get_width(),
texture->get_height(),
texture->get_depth(),
format,
String::humanize_size(memory)));
}
}

void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
if (!texture.is_null()) {
texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));
@@ -126,52 +177,61 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
}

texture->connect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));
queue_redraw();
texture_rect->set_material(material);

setting = true;
layer->set_max(texture->get_depth() - 1);
layer->set_value(0);
layer->show();
_update_material();
_update_gui();
setting = false;
_texture_rect_update_area();

_update_material(true);
queue_redraw();

} else {
hide();
}
}

Texture3DEditor::Texture3DEditor() {
set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
set_custom_minimum_size(Size2(1, 150));
set_custom_minimum_size(Size2(1, 256.0) * EDSCALE);

texture_rect = memnew(Control);
texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE);
add_child(texture_rect);
texture_rect->connect(SceneStringName(draw), callable_mp(this, &Texture3DEditor::_texture_rect_draw));

add_child(texture_rect);

layer = memnew(SpinBox);
layer->set_step(1);
layer->set_max(100);
layer->set_h_grow_direction(GROW_DIRECTION_BEGIN);

layer->set_modulate(Color(1, 1, 1, 0.8));
add_child(layer);
layer->set_h_grow_direction(GROW_DIRECTION_BEGIN);
layer->set_anchor(SIDE_RIGHT, 1);
layer->set_anchor(SIDE_LEFT, 1);
layer->connect(SceneStringName(value_changed), callable_mp(this, &Texture3DEditor::_layer_changed));

add_child(layer);

info = memnew(Label);
info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0));
info->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE);
info->add_theme_color_override("font_outline_color", Color(0, 0, 0));
info->add_theme_constant_override("outline_size", 8 * EDSCALE);

info->set_h_grow_direction(GROW_DIRECTION_BEGIN);
info->set_v_grow_direction(GROW_DIRECTION_BEGIN);
info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5));
info->add_theme_constant_override("shadow_outline_size", 1);
info->add_theme_constant_override("shadow_offset_x", 2);
info->add_theme_constant_override("shadow_offset_y", 2);
add_child(info);
info->set_h_size_flags(Control::SIZE_SHRINK_END);
info->set_v_size_flags(Control::SIZE_SHRINK_END);
info->set_anchor(SIDE_RIGHT, 1);
info->set_anchor(SIDE_LEFT, 1);
info->set_anchor(SIDE_BOTTOM, 1);
info->set_anchor(SIDE_TOP, 1);

add_child(info);
}

Texture3DEditor::~Texture3DEditor() {
@@ -180,7 +240,6 @@ Texture3DEditor::~Texture3DEditor() {
}
}

//
bool EditorInspectorPlugin3DTexture::can_handle(Object *p_object) {
return Object::cast_to<Texture3D>(p_object) != nullptr;
}
8 changes: 6 additions & 2 deletions editor/plugins/texture_3d_editor_plugin.h
Original file line number Diff line number Diff line change
@@ -52,23 +52,27 @@ class Texture3DEditor : public Control {
bool setting = false;

void _make_shaders();
void _update_material();

void _layer_changed(double) {
if (!setting) {
_update_material();
_update_material(false);
}
}

void _texture_changed();

void _texture_rect_update_area();
void _texture_rect_draw();

void _update_material(bool p_texture_changed);
void _update_gui();

protected:
void _notification(int p_what);

public:
void edit(Ref<Texture3D> p_texture);

Texture3DEditor();
~Texture3DEditor();
};
7 changes: 4 additions & 3 deletions editor/plugins/texture_editor_plugin.cpp
Original file line number Diff line number Diff line change
@@ -145,12 +145,13 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
p_texture->connect_changed(callable_mp(this, &TexturePreview::_update_metadata_label_text));

// It's okay that these colors are static since the grid color is static too.
metadata_label->add_theme_color_override(SceneStringName(font_color), Color::named("white"));
metadata_label->add_theme_color_override("font_shadow_color", Color::named("black"));
metadata_label->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1));
metadata_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0));

metadata_label->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE);
metadata_label->add_theme_color_override("font_outline_color", Color::named("black"));
metadata_label->add_theme_color_override("font_outline_color", Color(0, 0, 0));
metadata_label->add_theme_constant_override("outline_size", 8 * EDSCALE);

metadata_label->set_h_size_flags(Control::SIZE_SHRINK_END);
metadata_label->set_v_size_flags(Control::SIZE_SHRINK_END);

241 changes: 159 additions & 82 deletions editor/plugins/texture_layered_editor_plugin.cpp
Original file line number Diff line number Diff line change
@@ -30,23 +30,134 @@

#include "texture_layered_editor_plugin.h"

#include "editor/editor_string_names.h"
#include "editor/themes/editor_scale.h"
#include "scene/gui/label.h"

// Shader sources.

constexpr const char *array_2d_shader = R"(
// TextureLayeredEditor preview shader (2D array).
shader_type canvas_item;
uniform sampler2DArray tex;
uniform float layer;
void fragment() {
COLOR = textureLod(tex, vec3(UV, layer), 0.0);
}
)";

constexpr const char *cubemap_shader = R"(
// TextureLayeredEditor preview shader (cubemap).
shader_type canvas_item;
uniform samplerCube tex;
uniform vec3 normal;
uniform mat3 rot;
void fragment() {
vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z));
COLOR = textureLod(tex, n, 0.0);
}
)";

constexpr const char *cubemap_array_shader = R"(
// TextureLayeredEditor preview shader (cubemap array).
shader_type canvas_item;
uniform samplerCubeArray tex;
uniform vec3 normal;
uniform mat3 rot;
uniform float layer;
void fragment() {
vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z));
COLOR = textureLod(tex, vec4(n, layer), 0.0);
}
)";

void TextureLayeredEditor::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());

Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
y_rot += -mm->get_relative().x * 0.01;
x_rot += mm->get_relative().y * 0.01;
_update_material();
x_rot += -mm->get_relative().y * 0.01;

_update_material(false);
}
}

void TextureLayeredEditor::_texture_rect_draw() {
texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1));
}

void TextureLayeredEditor::_update_gui() {
if (texture.is_null()) {
return;
}

_texture_rect_update_area();

const String format = Image::get_format_name(texture->get_format());
String texture_info;

switch (texture->get_layered_type()) {
case TextureLayered::LAYERED_TYPE_2D_ARRAY: {
layer->set_max(texture->get_layers() - 1);

texture_info = vformat(String::utf8("%d×%d (×%d) %s\n"),
texture->get_width(),
texture->get_height(),
texture->get_layers(),
format);

} break;
case TextureLayered::LAYERED_TYPE_CUBEMAP: {
layer->hide();

texture_info = vformat(String::utf8("%d×%d %s\n"),
texture->get_width(),
texture->get_height(),
format);

} break;
case TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY: {
layer->set_max(texture->get_layers() / 6 - 1);

texture_info = vformat(String::utf8("%d×%d (×%d) %s\n"),
texture->get_width(),
texture->get_height(),
texture->get_layers() / 6,
format);

} break;

default: {
}
}

if (texture->has_mipmaps()) {
const int mip_count = Image::get_image_required_mipmaps(texture->get_width(), texture->get_height(), texture->get_format());
const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), true) * texture->get_layers();

texture_info += vformat(TTR("%s Mipmaps") + "\n" + TTR("Memory: %s"),
mip_count,
String::humanize_size(memory));

} else {
const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), false) * texture->get_layers();

texture_info += vformat(TTR("No Mipmaps") + "\n" + TTR("Memory: %s"),
String::humanize_size(memory));
}

info->set_text(texture_info);
}

void TextureLayeredEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_RESIZED: {
@@ -59,20 +170,32 @@ void TextureLayeredEditor::_notification(int p_what) {

draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
} break;

case NOTIFICATION_THEME_CHANGED: {
if (info) {
Ref<Font> metadata_label_font = get_theme_font(SNAME("expression"), EditorStringName(EditorFonts));
info->add_theme_font_override(SceneStringName(font), metadata_label_font);
}
} break;
}
}

void TextureLayeredEditor::_texture_changed() {
if (!is_visible()) {
return;
}

setting = true;
_update_gui();
setting = false;

_update_material(true);
queue_redraw();
}

void TextureLayeredEditor::_update_material() {
void TextureLayeredEditor::_update_material(bool p_texture_changed) {
materials[0]->set_shader_parameter("layer", layer->get_value());
materials[2]->set_shader_parameter("layer", layer->get_value());
materials[texture->get_layered_type()]->set_shader_parameter("tex", texture->get_rid());

Vector3 v(1, 1, 1);
v.normalize();
@@ -86,67 +209,20 @@ void TextureLayeredEditor::_update_material() {
materials[2]->set_shader_parameter("normal", v);
materials[2]->set_shader_parameter("rot", b);

String format = Image::get_format_name(texture->get_format());

String text;
if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) {
text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " (x " + itos(texture->get_layers()) + ")" + format;
} else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP) {
text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " " + format;
} else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY) {
text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " (x " + itos(texture->get_layers() / 6) + ")" + format;
if (p_texture_changed) {
materials[texture->get_layered_type()]->set_shader_parameter("tex", texture->get_rid());
}

info->set_text(text);
}

void TextureLayeredEditor::_make_shaders() {
shaders[0].instantiate();
shaders[0]->set_code(R"(
// TextureLayeredEditor preview shader (2D array).
shader_type canvas_item;
uniform sampler2DArray tex;
uniform float layer;
void fragment() {
COLOR = textureLod(tex, vec3(UV, layer), 0.0);
}
)");
shaders[0]->set_code(array_2d_shader);

shaders[1].instantiate();
shaders[1]->set_code(R"(
// TextureLayeredEditor preview shader (cubemap).
shader_type canvas_item;
uniform samplerCube tex;
uniform vec3 normal;
uniform mat3 rot;
void fragment() {
vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z));
COLOR = textureLod(tex, n, 0.0);
}
)");
shaders[1]->set_code(cubemap_shader);

shaders[2].instantiate();
shaders[2]->set_code(R"(
// TextureLayeredEditor preview shader (cubemap array).
shader_type canvas_item;
uniform samplerCubeArray tex;
uniform vec3 normal;
uniform mat3 rot;
uniform float layer;
void fragment() {
vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z));
COLOR = textureLod(tex, vec4(n, layer), 0.0);
}
)");
shaders[2]->set_code(cubemap_array_shader);

for (int i = 0; i < 3; i++) {
materials[i].instantiate();
@@ -192,68 +268,69 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
}

texture->connect_changed(callable_mp(this, &TextureLayeredEditor::_texture_changed));
queue_redraw();
texture_rect->set_material(materials[texture->get_layered_type()]);

setting = true;
if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) {
layer->set_max(texture->get_layers() - 1);
layer->set_value(0);
layer->show();
} else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY) {
layer->set_max(texture->get_layers() / 6 - 1);
layer->set_value(0);
layer->show();
} else {
layer->hide();
}
layer->set_value(0);
layer->show();
_update_gui();
setting = false;

x_rot = 0;
y_rot = 0;
_update_material();
setting = false;
_texture_rect_update_area();

_update_material(true);
queue_redraw();

} else {
hide();
}
}

TextureLayeredEditor::TextureLayeredEditor() {
set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
set_custom_minimum_size(Size2(1, 150));
set_custom_minimum_size(Size2(0, 256.0) * EDSCALE);

texture_rect = memnew(Control);
texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE);
add_child(texture_rect);
texture_rect->connect(SceneStringName(draw), callable_mp(this, &TextureLayeredEditor::_texture_rect_draw));

add_child(texture_rect);

layer = memnew(SpinBox);
layer->set_step(1);
layer->set_max(100);
layer->set_h_grow_direction(GROW_DIRECTION_BEGIN);

layer->set_modulate(Color(1, 1, 1, 0.8));
add_child(layer);
layer->set_h_grow_direction(GROW_DIRECTION_BEGIN);
layer->set_anchor(SIDE_RIGHT, 1);
layer->set_anchor(SIDE_LEFT, 1);
layer->connect(SceneStringName(value_changed), callable_mp(this, &TextureLayeredEditor::_layer_changed));

add_child(layer);

info = memnew(Label);
info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0));
info->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE);
info->add_theme_color_override("font_outline_color", Color(0, 0, 0));
info->add_theme_constant_override("outline_size", 8 * EDSCALE);

info->set_h_grow_direction(GROW_DIRECTION_BEGIN);
info->set_v_grow_direction(GROW_DIRECTION_BEGIN);
info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5));
info->add_theme_constant_override("shadow_outline_size", 1);
info->add_theme_constant_override("shadow_offset_x", 2);
info->add_theme_constant_override("shadow_offset_y", 2);
add_child(info);
info->set_h_size_flags(Control::SIZE_SHRINK_END);
info->set_v_size_flags(Control::SIZE_SHRINK_END);
info->set_anchor(SIDE_RIGHT, 1);
info->set_anchor(SIDE_LEFT, 1);
info->set_anchor(SIDE_BOTTOM, 1);
info->set_anchor(SIDE_TOP, 1);

add_child(info);
}

TextureLayeredEditor::~TextureLayeredEditor() {
}

//
bool EditorInspectorPluginLayeredTexture::can_handle(Object *p_object) {
return Object::cast_to<TextureLayered>(p_object) != nullptr;
}
8 changes: 6 additions & 2 deletions editor/plugins/texture_layered_editor_plugin.h
Original file line number Diff line number Diff line change
@@ -54,24 +54,28 @@ class TextureLayeredEditor : public Control {
bool setting = false;

void _make_shaders();
void _update_material();
void _update_material(bool p_texture_changed);

void _layer_changed(double) {
if (!setting) {
_update_material();
_update_material(false);
}
}

void _texture_changed();

void _texture_rect_update_area();
void _texture_rect_draw();

void _update_gui();

protected:
void _notification(int p_what);
virtual void gui_input(const Ref<InputEvent> &p_event) override;

public:
void edit(Ref<TextureLayered> p_texture);

TextureLayeredEditor();
~TextureLayeredEditor();
};
4 changes: 4 additions & 0 deletions modules/noise/noise_texture_3d.cpp
Original file line number Diff line number Diff line change
@@ -331,6 +331,10 @@ int NoiseTexture3D::get_depth() const {
return depth;
}

bool NoiseTexture3D::has_mipmaps() const {
return false;
}

RID NoiseTexture3D::get_rid() const {
if (!texture.is_valid()) {
texture = RS::get_singleton()->texture_3d_placeholder_create();
2 changes: 2 additions & 0 deletions modules/noise/noise_texture_3d.h
Original file line number Diff line number Diff line change
@@ -103,6 +103,8 @@ class NoiseTexture3D : public Texture3D {
virtual int get_height() const override;
virtual int get_depth() const override;

virtual bool has_mipmaps() const override;

virtual RID get_rid() const override;

virtual Vector<Ref<Image>> get_data() const override;