Path: blob/master/editor/scene/texture/texture_3d_editor_plugin.cpp
20985 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) {113texture_material->set_shader_parameter("layer", (layer->get_value() + 0.5) / texture->get_depth());114115if (p_texture_changed) {116texture_material->set_shader_parameter("tex", texture->get_rid());117}118119texture_material->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::_texture_rect_update_area() {129Size2 size = get_size();130int tex_width = texture->get_width() * size.height / texture->get_height();131int tex_height = size.height;132133if (tex_width > size.width) {134tex_width = size.width;135tex_height = texture->get_height() * tex_width / texture->get_width();136}137138// Prevent the texture from being unpreviewable after the rescale, so that we can still see something139if (tex_height <= 0) {140tex_height = 1;141}142if (tex_width <= 0) {143tex_width = 1;144}145146int ofs_x = (size.width - tex_width) / 2;147int ofs_y = (size.height - tex_height) / 2;148149texture_rect->set_position(Vector2(ofs_x, ofs_y - Math::round(EDSCALE)));150texture_rect->set_size(Vector2(tex_width, tex_height));151}152153void Texture3DEditor::_update_gui() {154if (texture.is_null()) {155return;156}157158_texture_rect_update_area();159160layer->set_max(texture->get_depth() - 1);161162const Image::Format format = texture->get_format();163const String format_name = Image::get_format_name(format);164165if (texture->has_mipmaps()) {166const int mip_count = Image::get_image_required_mipmaps(texture->get_width(), texture->get_height(), format);167const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), format, true) * texture->get_depth();168169info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("%s Mipmaps") + "\n" + TTR("Memory: %s"),170texture->get_width(),171texture->get_height(),172texture->get_depth(),173format_name,174mip_count,175String::humanize_size(memory)));176177} else {178const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), format, false) * texture->get_depth();179180info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("No Mipmaps") + "\n" + TTR("Memory: %s"),181texture->get_width(),182texture->get_height(),183texture->get_depth(),184format_name,185String::humanize_size(memory)));186}187188const uint32_t components_mask = Image::get_format_component_mask(format);189if (is_power_of_2(components_mask)) {190// Only one channel available, no point in showing a channel selector.191channel_selector->hide();192} else {193channel_selector->show();194channel_selector->set_available_channels_mask(components_mask);195}196}197198void Texture3DEditor::on_selected_channels_changed() {199_update_material(false);200}201202void Texture3DEditor::init_shaders() {203texture_shader.instantiate();204texture_shader->set_code(texture_3d_shader);205}206207void Texture3DEditor::finish_shaders() {208texture_shader.unref();209}210211void Texture3DEditor::edit(Ref<Texture3D> p_texture) {212if (texture.is_valid()) {213texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));214}215216texture = p_texture;217218if (texture.is_valid()) {219if (texture_material.is_null()) {220texture_material.instantiate();221texture_material->set_shader(texture_shader);222}223224texture->connect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));225texture_rect->set_material(texture_material);226227setting = true;228layer->set_value(0);229layer->show();230_update_gui();231setting = false;232233_update_material(true);234queue_redraw();235236} else {237hide();238}239}240241Texture3DEditor::Texture3DEditor() {242set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);243set_custom_minimum_size(Size2(1, 256.0) * EDSCALE);244245texture_rect = memnew(Control);246texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE);247texture_rect->connect(SceneStringName(draw), callable_mp(this, &Texture3DEditor::_texture_rect_draw));248249add_child(texture_rect);250251layer = memnew(SpinBox);252layer->set_step(1);253layer->set_max(100);254255layer->set_modulate(Color(1, 1, 1, 0.8));256layer->set_h_grow_direction(GROW_DIRECTION_BEGIN);257layer->set_anchor(SIDE_RIGHT, 1);258layer->set_anchor(SIDE_LEFT, 1);259layer->connect(SceneStringName(value_changed), callable_mp(this, &Texture3DEditor::_layer_changed));260261add_child(layer);262263channel_selector = memnew(ColorChannelSelector);264channel_selector->connect("selected_channels_changed", callable_mp(this, &Texture3DEditor::on_selected_channels_changed));265channel_selector->set_anchors_preset(Control::PRESET_TOP_LEFT);266add_child(channel_selector);267268info = memnew(Label);269info->set_focus_mode(FOCUS_ACCESSIBILITY);270info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1));271info->add_theme_color_override("font_shadow_color", Color(0, 0, 0));272info->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE);273info->add_theme_color_override("font_outline_color", Color(0, 0, 0));274info->add_theme_constant_override("outline_size", 8 * EDSCALE);275276info->set_h_grow_direction(GROW_DIRECTION_BEGIN);277info->set_v_grow_direction(GROW_DIRECTION_BEGIN);278info->set_h_size_flags(Control::SIZE_SHRINK_END);279info->set_v_size_flags(Control::SIZE_SHRINK_END);280info->set_anchor(SIDE_RIGHT, 1);281info->set_anchor(SIDE_LEFT, 1);282info->set_anchor(SIDE_BOTTOM, 1);283info->set_anchor(SIDE_TOP, 1);284285add_child(info);286}287288Texture3DEditor::~Texture3DEditor() {289if (texture.is_valid()) {290texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));291}292}293294bool EditorInspectorPlugin3DTexture::can_handle(Object *p_object) {295return Object::cast_to<Texture3D>(p_object) != nullptr;296}297298void EditorInspectorPlugin3DTexture::parse_begin(Object *p_object) {299Texture3D *texture = Object::cast_to<Texture3D>(p_object);300if (!texture) {301return;302}303Ref<Texture3D> m(texture);304305Texture3DEditor *editor = memnew(Texture3DEditor);306editor->edit(m);307add_custom_control(editor);308}309310Texture3DEditorPlugin::Texture3DEditorPlugin() {311Ref<EditorInspectorPlugin3DTexture> plugin;312plugin.instantiate();313add_inspector_plugin(plugin);314}315316317