Path: blob/master/editor/scene/texture/texture_3d_editor_plugin.cpp
9912 views
/**************************************************************************/1/* texture_3d_editor_plugin.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "texture_3d_editor_plugin.h"3132#include "editor/editor_string_names.h"33#include "editor/scene/texture/color_channel_selector.h"34#include "editor/themes/editor_scale.h"35#include "scene/gui/label.h"3637// Shader sources.3839constexpr const char *texture_3d_shader = R"(40// Texture3DEditor preview shader.4142shader_type canvas_item;4344uniform sampler3D tex;45uniform float layer;4647uniform vec4 u_channel_factors = vec4(1.0);4849vec4 filter_preview_colors(vec4 input_color, vec4 factors) {50// Filter RGB.51vec4 output_color = input_color * vec4(factors.rgb, input_color.a);5253// Remove transparency when alpha is not enabled.54output_color.a = mix(1.0, output_color.a, factors.a);5556// Switch to opaque grayscale when visualizing only one channel.57float csum = factors.r + factors.g + factors.b + factors.a;58float single = clamp(2.0 - csum, 0.0, 1.0);59for (int i = 0; i < 4; i++) {60float c = input_color[i];61output_color = mix(output_color, vec4(c, c, c, 1.0), factors[i] * single);62}6364return output_color;65}6667void fragment() {68COLOR = textureLod(tex, vec3(UV, layer), 0.0);69COLOR = filter_preview_colors(COLOR, u_channel_factors);70}71)";7273void Texture3DEditor::_texture_rect_draw() {74texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1));75}7677void Texture3DEditor::_notification(int p_what) {78switch (p_what) {79case NOTIFICATION_RESIZED: {80_texture_rect_update_area();81} break;8283case NOTIFICATION_DRAW: {84Ref<Texture2D> checkerboard = get_editor_theme_icon(SNAME("Checkerboard"));85draw_texture_rect(checkerboard, texture_rect->get_rect(), true);86_draw_outline();87} break;8889case NOTIFICATION_THEME_CHANGED: {90if (info) {91Ref<Font> metadata_label_font = get_theme_font(SNAME("expression"), EditorStringName(EditorFonts));92info->add_theme_font_override(SceneStringName(font), metadata_label_font);93}94theme_cache.outline_color = get_theme_color(SNAME("extra_border_color_1"), EditorStringName(Editor));95} break;96}97}9899void Texture3DEditor::_texture_changed() {100if (!is_visible()) {101return;102}103104setting = true;105_update_gui();106setting = false;107108_update_material(true);109queue_redraw();110}111112void Texture3DEditor::_update_material(bool p_texture_changed) {113material->set_shader_parameter("layer", (layer->get_value() + 0.5) / texture->get_depth());114115if (p_texture_changed) {116material->set_shader_parameter("tex", texture->get_rid());117}118119material->set_shader_parameter("u_channel_factors", channel_selector->get_selected_channel_factors());120}121122void Texture3DEditor::_draw_outline() {123const float outline_width = Math::round(EDSCALE);124const Rect2 outline_rect = texture_rect->get_rect().grow(outline_width * 0.5);125draw_rect(outline_rect, theme_cache.outline_color, false, outline_width);126}127128void Texture3DEditor::_make_shaders() {129shader.instantiate();130shader->set_code(texture_3d_shader);131132material.instantiate();133material->set_shader(shader);134}135136void Texture3DEditor::_texture_rect_update_area() {137Size2 size = get_size();138int tex_width = texture->get_width() * size.height / texture->get_height();139int tex_height = size.height;140141if (tex_width > size.width) {142tex_width = size.width;143tex_height = texture->get_height() * tex_width / texture->get_width();144}145146// Prevent the texture from being unpreviewable after the rescale, so that we can still see something147if (tex_height <= 0) {148tex_height = 1;149}150if (tex_width <= 0) {151tex_width = 1;152}153154int ofs_x = (size.width - tex_width) / 2;155int ofs_y = (size.height - tex_height) / 2;156157texture_rect->set_position(Vector2(ofs_x, ofs_y - Math::round(EDSCALE)));158texture_rect->set_size(Vector2(tex_width, tex_height));159}160161void Texture3DEditor::_update_gui() {162if (texture.is_null()) {163return;164}165166_texture_rect_update_area();167168layer->set_max(texture->get_depth() - 1);169170const Image::Format format = texture->get_format();171const String format_name = Image::get_format_name(format);172173if (texture->has_mipmaps()) {174const int mip_count = Image::get_image_required_mipmaps(texture->get_width(), texture->get_height(), format);175const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), format, true) * texture->get_depth();176177info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("%s Mipmaps") + "\n" + TTR("Memory: %s"),178texture->get_width(),179texture->get_height(),180texture->get_depth(),181format_name,182mip_count,183String::humanize_size(memory)));184185} else {186const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), format, false) * texture->get_depth();187188info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("No Mipmaps") + "\n" + TTR("Memory: %s"),189texture->get_width(),190texture->get_height(),191texture->get_depth(),192format_name,193String::humanize_size(memory)));194}195196const uint32_t components_mask = Image::get_format_component_mask(format);197if (is_power_of_2(components_mask)) {198// Only one channel available, no point in showing a channel selector.199channel_selector->hide();200} else {201channel_selector->show();202channel_selector->set_available_channels_mask(components_mask);203}204}205206void Texture3DEditor::on_selected_channels_changed() {207_update_material(false);208}209210void Texture3DEditor::edit(Ref<Texture3D> p_texture) {211if (texture.is_valid()) {212texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));213}214215texture = p_texture;216217if (texture.is_valid()) {218if (shader.is_null()) {219_make_shaders();220}221222texture->connect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));223texture_rect->set_material(material);224225setting = true;226layer->set_value(0);227layer->show();228_update_gui();229setting = false;230231_update_material(true);232queue_redraw();233234} else {235hide();236}237}238239Texture3DEditor::Texture3DEditor() {240set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);241set_custom_minimum_size(Size2(1, 256.0) * EDSCALE);242243texture_rect = memnew(Control);244texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE);245texture_rect->connect(SceneStringName(draw), callable_mp(this, &Texture3DEditor::_texture_rect_draw));246247add_child(texture_rect);248249layer = memnew(SpinBox);250layer->set_step(1);251layer->set_max(100);252253layer->set_modulate(Color(1, 1, 1, 0.8));254layer->set_h_grow_direction(GROW_DIRECTION_BEGIN);255layer->set_anchor(SIDE_RIGHT, 1);256layer->set_anchor(SIDE_LEFT, 1);257layer->connect(SceneStringName(value_changed), callable_mp(this, &Texture3DEditor::_layer_changed));258259add_child(layer);260261channel_selector = memnew(ColorChannelSelector);262channel_selector->connect("selected_channels_changed", callable_mp(this, &Texture3DEditor::on_selected_channels_changed));263channel_selector->set_anchors_preset(Control::PRESET_TOP_LEFT);264add_child(channel_selector);265266info = memnew(Label);267info->set_focus_mode(FOCUS_ACCESSIBILITY);268info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1));269info->add_theme_color_override("font_shadow_color", Color(0, 0, 0));270info->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE);271info->add_theme_color_override("font_outline_color", Color(0, 0, 0));272info->add_theme_constant_override("outline_size", 8 * EDSCALE);273274info->set_h_grow_direction(GROW_DIRECTION_BEGIN);275info->set_v_grow_direction(GROW_DIRECTION_BEGIN);276info->set_h_size_flags(Control::SIZE_SHRINK_END);277info->set_v_size_flags(Control::SIZE_SHRINK_END);278info->set_anchor(SIDE_RIGHT, 1);279info->set_anchor(SIDE_LEFT, 1);280info->set_anchor(SIDE_BOTTOM, 1);281info->set_anchor(SIDE_TOP, 1);282283add_child(info);284}285286Texture3DEditor::~Texture3DEditor() {287if (texture.is_valid()) {288texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));289}290}291292bool EditorInspectorPlugin3DTexture::can_handle(Object *p_object) {293return Object::cast_to<Texture3D>(p_object) != nullptr;294}295296void EditorInspectorPlugin3DTexture::parse_begin(Object *p_object) {297Texture3D *texture = Object::cast_to<Texture3D>(p_object);298if (!texture) {299return;300}301Ref<Texture3D> m(texture);302303Texture3DEditor *editor = memnew(Texture3DEditor);304editor->edit(m);305add_custom_control(editor);306}307308Texture3DEditorPlugin::Texture3DEditorPlugin() {309Ref<EditorInspectorPlugin3DTexture> plugin;310plugin.instantiate();311add_inspector_plugin(plugin);312}313314315