d95794ec8a
As many open source projects have started doing it, we're removing the current year from the copyright notice, so that we don't need to bump it every year. It seems like only the first year of publication is technically relevant for copyright notices, and even that seems to be something that many companies stopped listing altogether (in a version controlled codebase, the commits are a much better source of date of publication than a hardcoded copyright statement). We also now list Godot Engine contributors first as we're collectively the current maintainers of the project, and we clarify that the "exclusive" copyright of the co-founders covers the timespan before opensourcing (their further contributions are included as part of Godot Engine contributors). Also fixed "cf." Frenchism - it's meant as "refer to / see".
4839 lines
176 KiB
C++
4839 lines
176 KiB
C++
/**************************************************************************/
|
|
/* visual_shader.cpp */
|
|
/**************************************************************************/
|
|
/* This file is part of: */
|
|
/* GODOT ENGINE */
|
|
/* https://godotengine.org */
|
|
/**************************************************************************/
|
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
/* */
|
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
/* a copy of this software and associated documentation files (the */
|
|
/* "Software"), to deal in the Software without restriction, including */
|
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
/* the following conditions: */
|
|
/* */
|
|
/* The above copyright notice and this permission notice shall be */
|
|
/* included in all copies or substantial portions of the Software. */
|
|
/* */
|
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
/**************************************************************************/
|
|
|
|
#include "visual_shader.h"
|
|
|
|
#include "core/templates/rb_map.h"
|
|
#include "core/templates/vmap.h"
|
|
#include "servers/rendering/shader_types.h"
|
|
#include "visual_shader_nodes.h"
|
|
#include "visual_shader_particle_nodes.h"
|
|
#include "visual_shader_sdf_nodes.h"
|
|
|
|
String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name) {
|
|
static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
|
|
return p_name + "_" + String(typepf[p_type]) + "_" + itos(p_id);
|
|
}
|
|
|
|
bool VisualShaderNode::is_simple_decl() const {
|
|
return simple_decl;
|
|
}
|
|
|
|
void VisualShaderNode::set_output_port_for_preview(int p_index) {
|
|
port_preview = p_index;
|
|
}
|
|
|
|
int VisualShaderNode::get_output_port_for_preview() const {
|
|
return port_preview;
|
|
}
|
|
|
|
void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) {
|
|
Variant value = p_value;
|
|
|
|
if (p_prev_value.get_type() != Variant::NIL) {
|
|
switch (p_value.get_type()) {
|
|
case Variant::FLOAT: {
|
|
switch (p_prev_value.get_type()) {
|
|
case Variant::INT: {
|
|
value = (float)p_prev_value;
|
|
} break;
|
|
case Variant::FLOAT: {
|
|
value = p_prev_value;
|
|
} break;
|
|
case Variant::VECTOR2: {
|
|
Vector2 pv = p_prev_value;
|
|
value = pv.x;
|
|
} break;
|
|
case Variant::VECTOR3: {
|
|
Vector3 pv = p_prev_value;
|
|
value = pv.x;
|
|
} break;
|
|
case Variant::QUATERNION: {
|
|
Quaternion pv = p_prev_value;
|
|
value = pv.x;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case Variant::INT: {
|
|
switch (p_prev_value.get_type()) {
|
|
case Variant::INT: {
|
|
value = p_prev_value;
|
|
} break;
|
|
case Variant::FLOAT: {
|
|
value = (int)p_prev_value;
|
|
} break;
|
|
case Variant::VECTOR2: {
|
|
Vector2 pv = p_prev_value;
|
|
value = (int)pv.x;
|
|
} break;
|
|
case Variant::VECTOR3: {
|
|
Vector3 pv = p_prev_value;
|
|
value = (int)pv.x;
|
|
} break;
|
|
case Variant::QUATERNION: {
|
|
Quaternion pv = p_prev_value;
|
|
value = (int)pv.x;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case Variant::VECTOR2: {
|
|
switch (p_prev_value.get_type()) {
|
|
case Variant::INT: {
|
|
float pv = (float)(int)p_prev_value;
|
|
value = Vector2(pv, pv);
|
|
} break;
|
|
case Variant::FLOAT: {
|
|
float pv = p_prev_value;
|
|
value = Vector2(pv, pv);
|
|
} break;
|
|
case Variant::VECTOR2: {
|
|
value = p_prev_value;
|
|
} break;
|
|
case Variant::VECTOR3: {
|
|
Vector3 pv = p_prev_value;
|
|
value = Vector2(pv.x, pv.y);
|
|
} break;
|
|
case Variant::QUATERNION: {
|
|
Quaternion pv = p_prev_value;
|
|
value = Vector2(pv.x, pv.y);
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case Variant::VECTOR3: {
|
|
switch (p_prev_value.get_type()) {
|
|
case Variant::INT: {
|
|
float pv = (float)(int)p_prev_value;
|
|
value = Vector3(pv, pv, pv);
|
|
} break;
|
|
case Variant::FLOAT: {
|
|
float pv = p_prev_value;
|
|
value = Vector3(pv, pv, pv);
|
|
} break;
|
|
case Variant::VECTOR2: {
|
|
Vector2 pv = p_prev_value;
|
|
value = Vector3(pv.x, pv.y, pv.y);
|
|
} break;
|
|
case Variant::VECTOR3: {
|
|
value = p_prev_value;
|
|
} break;
|
|
case Variant::QUATERNION: {
|
|
Quaternion pv = p_prev_value;
|
|
value = Vector3(pv.x, pv.y, pv.z);
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case Variant::QUATERNION: {
|
|
switch (p_prev_value.get_type()) {
|
|
case Variant::INT: {
|
|
float pv = (float)(int)p_prev_value;
|
|
value = Quaternion(pv, pv, pv, pv);
|
|
} break;
|
|
case Variant::FLOAT: {
|
|
float pv = p_prev_value;
|
|
value = Quaternion(pv, pv, pv, pv);
|
|
} break;
|
|
case Variant::VECTOR2: {
|
|
Vector2 pv = p_prev_value;
|
|
value = Quaternion(pv.x, pv.y, pv.y, pv.y);
|
|
} break;
|
|
case Variant::VECTOR3: {
|
|
Vector3 pv = p_prev_value;
|
|
value = Quaternion(pv.x, pv.y, pv.z, pv.z);
|
|
} break;
|
|
case Variant::QUATERNION: {
|
|
value = p_prev_value;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
default_input_values[p_port] = value;
|
|
emit_changed();
|
|
}
|
|
|
|
Variant VisualShaderNode::get_input_port_default_value(int p_port) const {
|
|
if (default_input_values.has(p_port)) {
|
|
return default_input_values[p_port];
|
|
}
|
|
|
|
return Variant();
|
|
}
|
|
|
|
void VisualShaderNode::remove_input_port_default_value(int p_port) {
|
|
if (default_input_values.has(p_port)) {
|
|
default_input_values.erase(p_port);
|
|
emit_changed();
|
|
}
|
|
}
|
|
|
|
void VisualShaderNode::clear_default_input_values() {
|
|
if (!default_input_values.is_empty()) {
|
|
default_input_values.clear();
|
|
emit_changed();
|
|
}
|
|
}
|
|
|
|
bool VisualShaderNode::is_port_separator(int p_index) const {
|
|
return false;
|
|
}
|
|
|
|
bool VisualShaderNode::is_output_port_connected(int p_port) const {
|
|
if (connected_output_ports.has(p_port)) {
|
|
return connected_output_ports[p_port] > 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void VisualShaderNode::set_output_port_connected(int p_port, bool p_connected) {
|
|
if (p_connected) {
|
|
connected_output_ports[p_port]++;
|
|
} else {
|
|
connected_output_ports[p_port]--;
|
|
}
|
|
}
|
|
|
|
bool VisualShaderNode::is_input_port_connected(int p_port) const {
|
|
if (connected_input_ports.has(p_port)) {
|
|
return connected_input_ports[p_port];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void VisualShaderNode::set_input_port_connected(int p_port, bool p_connected) {
|
|
connected_input_ports[p_port] = p_connected;
|
|
}
|
|
|
|
bool VisualShaderNode::is_generate_input_var(int p_port) const {
|
|
return true;
|
|
}
|
|
|
|
bool VisualShaderNode::is_output_port_expandable(int p_port) const {
|
|
return false;
|
|
}
|
|
|
|
bool VisualShaderNode::has_output_port_preview(int p_port) const {
|
|
return true;
|
|
}
|
|
|
|
void VisualShaderNode::_set_output_ports_expanded(const Array &p_values) {
|
|
for (int i = 0; i < p_values.size(); i++) {
|
|
expanded_output_ports[p_values[i]] = true;
|
|
}
|
|
emit_changed();
|
|
}
|
|
|
|
Array VisualShaderNode::_get_output_ports_expanded() const {
|
|
Array arr;
|
|
for (int i = 0; i < get_output_port_count(); i++) {
|
|
if (_is_output_port_expanded(i)) {
|
|
arr.push_back(i);
|
|
}
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
void VisualShaderNode::_set_output_port_expanded(int p_port, bool p_expanded) {
|
|
expanded_output_ports[p_port] = p_expanded;
|
|
emit_changed();
|
|
}
|
|
|
|
bool VisualShaderNode::_is_output_port_expanded(int p_port) const {
|
|
if (expanded_output_ports.has(p_port)) {
|
|
return expanded_output_ports[p_port];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int VisualShaderNode::get_expanded_output_port_count() const {
|
|
int count = get_output_port_count();
|
|
int count2 = count;
|
|
for (int i = 0; i < count; i++) {
|
|
if (is_output_port_expandable(i) && _is_output_port_expanded(i)) {
|
|
switch (get_output_port_type(i)) {
|
|
case PORT_TYPE_VECTOR_2D: {
|
|
count2 += 2;
|
|
} break;
|
|
case PORT_TYPE_VECTOR_3D: {
|
|
count2 += 3;
|
|
} break;
|
|
case PORT_TYPE_VECTOR_4D: {
|
|
count2 += 4;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return count2;
|
|
}
|
|
|
|
bool VisualShaderNode::is_code_generated() const {
|
|
return true;
|
|
}
|
|
|
|
bool VisualShaderNode::is_show_prop_names() const {
|
|
return false;
|
|
}
|
|
|
|
bool VisualShaderNode::is_use_prop_slots() const {
|
|
return false;
|
|
}
|
|
|
|
bool VisualShaderNode::is_disabled() const {
|
|
return disabled;
|
|
}
|
|
|
|
void VisualShaderNode::set_disabled(bool p_disabled) {
|
|
disabled = p_disabled;
|
|
}
|
|
|
|
Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
|
|
return Vector<VisualShader::DefaultTextureParam>();
|
|
}
|
|
|
|
String VisualShaderNode::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
|
|
return String();
|
|
}
|
|
|
|
String VisualShaderNode::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
|
|
return String();
|
|
}
|
|
|
|
String VisualShaderNode::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
|
|
return String();
|
|
}
|
|
|
|
Vector<StringName> VisualShaderNode::get_editable_properties() const {
|
|
return Vector<StringName>();
|
|
}
|
|
|
|
HashMap<StringName, String> VisualShaderNode::get_editable_properties_names() const {
|
|
return HashMap<StringName, String>();
|
|
}
|
|
|
|
Array VisualShaderNode::get_default_input_values() const {
|
|
Array ret;
|
|
for (const KeyValue<int, Variant> &E : default_input_values) {
|
|
ret.push_back(E.key);
|
|
ret.push_back(E.value);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void VisualShaderNode::set_default_input_values(const Array &p_values) {
|
|
if (p_values.size() % 2 == 0) {
|
|
for (int i = 0; i < p_values.size(); i += 2) {
|
|
default_input_values[p_values[i + 0]] = p_values[i + 1];
|
|
}
|
|
}
|
|
|
|
emit_changed();
|
|
}
|
|
|
|
String VisualShaderNode::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
|
|
return String();
|
|
}
|
|
|
|
bool VisualShaderNode::is_input_port_default(int p_port, Shader::Mode p_mode) const {
|
|
return false;
|
|
}
|
|
|
|
void VisualShaderNode::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview);
|
|
ClassDB::bind_method(D_METHOD("get_output_port_for_preview"), &VisualShaderNode::get_output_port_for_preview);
|
|
|
|
ClassDB::bind_method(D_METHOD("_set_output_port_expanded", "port"), &VisualShaderNode::_set_output_port_expanded);
|
|
ClassDB::bind_method(D_METHOD("_is_output_port_expanded"), &VisualShaderNode::_is_output_port_expanded);
|
|
|
|
ClassDB::bind_method(D_METHOD("_set_output_ports_expanded", "values"), &VisualShaderNode::_set_output_ports_expanded);
|
|
ClassDB::bind_method(D_METHOD("_get_output_ports_expanded"), &VisualShaderNode::_get_output_ports_expanded);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value", "prev_value"), &VisualShaderNode::set_input_port_default_value, DEFVAL(Variant()));
|
|
ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value);
|
|
|
|
ClassDB::bind_method(D_METHOD("remove_input_port_default_value", "port"), &VisualShaderNode::remove_input_port_default_value);
|
|
ClassDB::bind_method(D_METHOD("clear_default_input_values"), &VisualShaderNode::clear_default_input_values);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_default_input_values", "values"), &VisualShaderNode::set_default_input_values);
|
|
ClassDB::bind_method(D_METHOD("get_default_input_values"), &VisualShaderNode::get_default_input_values);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
|
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_default_input_values", "get_default_input_values");
|
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "expanded_output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_output_ports_expanded", "_get_output_ports_expanded");
|
|
ADD_SIGNAL(MethodInfo("editor_refresh_request"));
|
|
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR_INT);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_2D);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_3D);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_4D);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_SAMPLER);
|
|
BIND_ENUM_CONSTANT(PORT_TYPE_MAX);
|
|
}
|
|
|
|
VisualShaderNode::VisualShaderNode() {
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void VisualShaderNodeCustom::update_ports() {
|
|
{
|
|
input_ports.clear();
|
|
int input_port_count;
|
|
if (GDVIRTUAL_CALL(_get_input_port_count, input_port_count)) {
|
|
for (int i = 0; i < input_port_count; i++) {
|
|
Port port;
|
|
if (!GDVIRTUAL_CALL(_get_input_port_name, i, port.name)) {
|
|
port.name = "in" + itos(i);
|
|
}
|
|
if (!GDVIRTUAL_CALL(_get_input_port_type, i, port.type)) {
|
|
port.type = (int)PortType::PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
input_ports.push_back(port);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
output_ports.clear();
|
|
int output_port_count;
|
|
if (GDVIRTUAL_CALL(_get_output_port_count, output_port_count)) {
|
|
for (int i = 0; i < output_port_count; i++) {
|
|
Port port;
|
|
if (!GDVIRTUAL_CALL(_get_output_port_name, i, port.name)) {
|
|
port.name = "out" + itos(i);
|
|
}
|
|
if (!GDVIRTUAL_CALL(_get_output_port_type, i, port.type)) {
|
|
port.type = (int)PortType::PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
output_ports.push_back(port);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
String VisualShaderNodeCustom::get_caption() const {
|
|
String ret = "Unnamed";
|
|
GDVIRTUAL_CALL(_get_name, ret);
|
|
return ret;
|
|
}
|
|
|
|
int VisualShaderNodeCustom::get_input_port_count() const {
|
|
return input_ports.size();
|
|
}
|
|
|
|
VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_input_port_type(int p_port) const {
|
|
ERR_FAIL_INDEX_V(p_port, input_ports.size(), PORT_TYPE_SCALAR);
|
|
return (PortType)input_ports[p_port].type;
|
|
}
|
|
|
|
String VisualShaderNodeCustom::get_input_port_name(int p_port) const {
|
|
ERR_FAIL_INDEX_V(p_port, input_ports.size(), "");
|
|
return input_ports[p_port].name;
|
|
}
|
|
|
|
int VisualShaderNodeCustom::get_output_port_count() const {
|
|
return output_ports.size();
|
|
}
|
|
|
|
VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_output_port_type(int p_port) const {
|
|
ERR_FAIL_INDEX_V(p_port, output_ports.size(), PORT_TYPE_SCALAR);
|
|
return (PortType)output_ports[p_port].type;
|
|
}
|
|
|
|
String VisualShaderNodeCustom::get_output_port_name(int p_port) const {
|
|
ERR_FAIL_INDEX_V(p_port, output_ports.size(), "");
|
|
return output_ports[p_port].name;
|
|
}
|
|
|
|
String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
ERR_FAIL_COND_V(!GDVIRTUAL_IS_OVERRIDDEN(_get_code), "");
|
|
TypedArray<String> input_vars;
|
|
for (int i = 0; i < get_input_port_count(); i++) {
|
|
input_vars.push_back(p_input_vars[i]);
|
|
}
|
|
TypedArray<String> output_vars;
|
|
for (int i = 0; i < get_output_port_count(); i++) {
|
|
output_vars.push_back(p_output_vars[i]);
|
|
}
|
|
|
|
String _code;
|
|
GDVIRTUAL_CALL(_get_code, input_vars, output_vars, p_mode, p_type, _code);
|
|
if (_is_valid_code(_code)) {
|
|
String code = " {\n";
|
|
bool nend = _code.ends_with("\n");
|
|
_code = _code.insert(0, " ");
|
|
_code = _code.replace("\n", "\n ");
|
|
code += _code;
|
|
if (!nend) {
|
|
code += "\n }";
|
|
} else {
|
|
code.remove_at(code.size() - 1);
|
|
code += "}";
|
|
}
|
|
code += "\n";
|
|
return code;
|
|
}
|
|
return String();
|
|
}
|
|
|
|
String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
|
|
String _code;
|
|
if (GDVIRTUAL_CALL(_get_global_code, p_mode, _code)) {
|
|
if (_is_valid_code(_code)) {
|
|
String code = "// " + get_caption() + "\n";
|
|
code += _code;
|
|
code += "\n";
|
|
return code;
|
|
}
|
|
}
|
|
return String();
|
|
}
|
|
|
|
String VisualShaderNodeCustom::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
|
|
String _code;
|
|
if (GDVIRTUAL_CALL(_get_func_code, p_mode, p_type, _code)) {
|
|
if (_is_valid_code(_code)) {
|
|
bool nend = _code.ends_with("\n");
|
|
String code = "// " + get_caption() + "\n";
|
|
code += " {\n";
|
|
_code = _code.insert(0, " ");
|
|
_code = _code.replace("\n", "\n ");
|
|
code += _code;
|
|
if (!nend) {
|
|
code += "\n }";
|
|
} else {
|
|
code.remove_at(code.size() - 1);
|
|
code += "}";
|
|
}
|
|
code += "\n";
|
|
return code;
|
|
}
|
|
}
|
|
return String();
|
|
}
|
|
|
|
bool VisualShaderNodeCustom::is_available(Shader::Mode p_mode, VisualShader::Type p_type) const {
|
|
bool ret = true;
|
|
GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret);
|
|
return ret;
|
|
}
|
|
|
|
void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) {
|
|
if (!is_initialized) {
|
|
VisualShaderNode::set_input_port_default_value(p_port, p_value, p_prev_value);
|
|
}
|
|
}
|
|
|
|
void VisualShaderNodeCustom::set_default_input_values(const Array &p_values) {
|
|
if (!is_initialized) {
|
|
VisualShaderNode::set_default_input_values(p_values);
|
|
}
|
|
}
|
|
|
|
void VisualShaderNodeCustom::remove_input_port_default_value(int p_port) {
|
|
if (!is_initialized) {
|
|
VisualShaderNode::remove_input_port_default_value(p_port);
|
|
}
|
|
}
|
|
|
|
void VisualShaderNodeCustom::clear_default_input_values() {
|
|
if (!is_initialized) {
|
|
VisualShaderNode::clear_default_input_values();
|
|
}
|
|
}
|
|
|
|
void VisualShaderNodeCustom::_set_input_port_default_value(int p_port, const Variant &p_value) {
|
|
VisualShaderNode::set_input_port_default_value(p_port, p_value);
|
|
}
|
|
|
|
bool VisualShaderNodeCustom::_is_valid_code(const String &p_code) const {
|
|
if (p_code.is_empty() || p_code == "null") {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool VisualShaderNodeCustom::_is_initialized() {
|
|
return is_initialized;
|
|
}
|
|
|
|
void VisualShaderNodeCustom::_set_initialized(bool p_enabled) {
|
|
is_initialized = p_enabled;
|
|
}
|
|
|
|
void VisualShaderNodeCustom::_bind_methods() {
|
|
GDVIRTUAL_BIND(_get_name);
|
|
GDVIRTUAL_BIND(_get_description);
|
|
GDVIRTUAL_BIND(_get_category);
|
|
GDVIRTUAL_BIND(_get_return_icon_type);
|
|
GDVIRTUAL_BIND(_get_input_port_count);
|
|
GDVIRTUAL_BIND(_get_input_port_type, "port");
|
|
GDVIRTUAL_BIND(_get_input_port_name, "port");
|
|
GDVIRTUAL_BIND(_get_output_port_count);
|
|
GDVIRTUAL_BIND(_get_output_port_type, "port");
|
|
GDVIRTUAL_BIND(_get_output_port_name, "port");
|
|
GDVIRTUAL_BIND(_get_code, "input_vars", "output_vars", "mode", "type");
|
|
GDVIRTUAL_BIND(_get_func_code, "mode", "type");
|
|
GDVIRTUAL_BIND(_get_global_code, "mode");
|
|
GDVIRTUAL_BIND(_is_highend);
|
|
GDVIRTUAL_BIND(_is_available, "mode", "type");
|
|
|
|
ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized);
|
|
ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized);
|
|
ClassDB::bind_method(D_METHOD("_set_input_port_default_value", "port", "value"), &VisualShaderNodeCustom::_set_input_port_default_value);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "initialized", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_initialized", "_is_initialized");
|
|
}
|
|
|
|
VisualShaderNodeCustom::VisualShaderNodeCustom() {
|
|
simple_decl = false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void VisualShader::set_shader_type(Type p_type) {
|
|
current_type = p_type;
|
|
}
|
|
|
|
VisualShader::Type VisualShader::get_shader_type() const {
|
|
return current_type;
|
|
}
|
|
|
|
void VisualShader::add_varying(const String &p_name, VaryingMode p_mode, VaryingType p_type) {
|
|
ERR_FAIL_COND(!p_name.is_valid_identifier());
|
|
ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX);
|
|
ERR_FAIL_INDEX((int)p_type, (int)VARYING_TYPE_MAX);
|
|
ERR_FAIL_COND(varyings.has(p_name));
|
|
Varying var = Varying(p_name, p_mode, p_type);
|
|
varyings[p_name] = var;
|
|
varyings_list.push_back(var);
|
|
_queue_update();
|
|
}
|
|
|
|
void VisualShader::remove_varying(const String &p_name) {
|
|
ERR_FAIL_COND(!varyings.has(p_name));
|
|
varyings.erase(p_name);
|
|
for (List<Varying>::Element *E = varyings_list.front(); E; E = E->next()) {
|
|
if (E->get().name == p_name) {
|
|
varyings_list.erase(E);
|
|
break;
|
|
}
|
|
}
|
|
_queue_update();
|
|
}
|
|
|
|
bool VisualShader::has_varying(const String &p_name) const {
|
|
return varyings.has(p_name);
|
|
}
|
|
|
|
int VisualShader::get_varyings_count() const {
|
|
return varyings_list.size();
|
|
}
|
|
|
|
const VisualShader::Varying *VisualShader::get_varying_by_index(int p_idx) const {
|
|
ERR_FAIL_INDEX_V(p_idx, varyings_list.size(), nullptr);
|
|
return &varyings_list[p_idx];
|
|
}
|
|
|
|
void VisualShader::set_varying_mode(const String &p_name, VaryingMode p_mode) {
|
|
ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX);
|
|
ERR_FAIL_COND(!varyings.has(p_name));
|
|
if (varyings[p_name].mode == p_mode) {
|
|
return;
|
|
}
|
|
varyings[p_name].mode = p_mode;
|
|
_queue_update();
|
|
}
|
|
|
|
VisualShader::VaryingMode VisualShader::get_varying_mode(const String &p_name) {
|
|
ERR_FAIL_COND_V(!varyings.has(p_name), VARYING_MODE_MAX);
|
|
return varyings[p_name].mode;
|
|
}
|
|
|
|
void VisualShader::set_varying_type(const String &p_name, VaryingType p_type) {
|
|
ERR_FAIL_INDEX((int)p_type, (int)VARYING_TYPE_MAX);
|
|
ERR_FAIL_COND(!varyings.has(p_name));
|
|
if (varyings[p_name].type == p_type) {
|
|
return;
|
|
}
|
|
varyings[p_name].type = p_type;
|
|
_queue_update();
|
|
}
|
|
|
|
VisualShader::VaryingType VisualShader::get_varying_type(const String &p_name) {
|
|
ERR_FAIL_COND_V(!varyings.has(p_name), VARYING_TYPE_MAX);
|
|
return varyings[p_name].type;
|
|
}
|
|
|
|
void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
|
|
ERR_FAIL_COND(p_node.is_null());
|
|
ERR_FAIL_COND(p_id < 2);
|
|
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
|
Graph *g = &graph[p_type];
|
|
ERR_FAIL_COND(g->nodes.has(p_id));
|
|
Node n;
|
|
n.node = p_node;
|
|
n.position = p_position;
|
|
|
|
Ref<VisualShaderNodeParameter> parameter = n.node;
|
|
if (parameter.is_valid()) {
|
|
String valid_name = validate_parameter_name(parameter->get_parameter_name(), parameter);
|
|
parameter->set_parameter_name(valid_name);
|
|
}
|
|
|
|
Ref<VisualShaderNodeInput> input = n.node;
|
|
if (input.is_valid()) {
|
|
input->shader_mode = shader_mode;
|
|
input->shader_type = p_type;
|
|
}
|
|
|
|
n.node->connect("changed", callable_mp(this, &VisualShader::_queue_update));
|
|
|
|
Ref<VisualShaderNodeCustom> custom = n.node;
|
|
if (custom.is_valid()) {
|
|
custom->update_ports();
|
|
}
|
|
|
|
g->nodes[p_id] = n;
|
|
|
|
_queue_update();
|
|
}
|
|
|
|
void VisualShader::set_node_position(Type p_type, int p_id, const Vector2 &p_position) {
|
|
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
|
Graph *g = &graph[p_type];
|
|
ERR_FAIL_COND(!g->nodes.has(p_id));
|
|
g->nodes[p_id].position = p_position;
|
|
}
|
|
|
|
Vector2 VisualShader::get_node_position(Type p_type, int p_id) const {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Vector2());
|
|
const Graph *g = &graph[p_type];
|
|
ERR_FAIL_COND_V(!g->nodes.has(p_id), Vector2());
|
|
return g->nodes[p_id].position;
|
|
}
|
|
|
|
Ref<VisualShaderNode> VisualShader::get_node(Type p_type, int p_id) const {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Ref<VisualShaderNode>());
|
|
const Graph *g = &graph[p_type];
|
|
ERR_FAIL_COND_V(!g->nodes.has(p_id), Ref<VisualShaderNode>());
|
|
return g->nodes[p_id].node;
|
|
}
|
|
|
|
Vector<int> VisualShader::get_node_list(Type p_type) const {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Vector<int>());
|
|
const Graph *g = &graph[p_type];
|
|
|
|
Vector<int> ret;
|
|
for (const KeyValue<int, Node> &E : g->nodes) {
|
|
ret.push_back(E.key);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int VisualShader::get_valid_node_id(Type p_type) const {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, NODE_ID_INVALID);
|
|
const Graph *g = &graph[p_type];
|
|
return g->nodes.size() ? MAX(2, g->nodes.back()->key() + 1) : 2;
|
|
}
|
|
|
|
int VisualShader::find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const {
|
|
for (const KeyValue<int, Node> &E : graph[p_type].nodes) {
|
|
if (E.value.node == p_node) {
|
|
return E.key;
|
|
}
|
|
}
|
|
|
|
return NODE_ID_INVALID;
|
|
}
|
|
|
|
void VisualShader::remove_node(Type p_type, int p_id) {
|
|
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
|
ERR_FAIL_COND(p_id < 2);
|
|
Graph *g = &graph[p_type];
|
|
ERR_FAIL_COND(!g->nodes.has(p_id));
|
|
|
|
g->nodes[p_id].node->disconnect("changed", callable_mp(this, &VisualShader::_queue_update));
|
|
|
|
g->nodes.erase(p_id);
|
|
|
|
for (List<Connection>::Element *E = g->connections.front(); E;) {
|
|
List<Connection>::Element *N = E->next();
|
|
if (E->get().from_node == p_id || E->get().to_node == p_id) {
|
|
g->connections.erase(E);
|
|
if (E->get().from_node == p_id) {
|
|
g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id);
|
|
g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false);
|
|
}
|
|
}
|
|
E = N;
|
|
}
|
|
|
|
_queue_update();
|
|
}
|
|
|
|
void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_class) {
|
|
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
|
ERR_FAIL_COND(p_id < 2);
|
|
Graph *g = &graph[p_type];
|
|
ERR_FAIL_COND(!g->nodes.has(p_id));
|
|
|
|
if (g->nodes[p_id].node->get_class_name() == p_new_class) {
|
|
return;
|
|
}
|
|
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(p_new_class));
|
|
VisualShaderNode *prev_vsn = g->nodes[p_id].node.ptr();
|
|
|
|
// Update connection data.
|
|
for (int i = 0; i < vsn->get_output_port_count(); i++) {
|
|
if (i < prev_vsn->get_output_port_count()) {
|
|
if (prev_vsn->is_output_port_connected(i)) {
|
|
vsn->set_output_port_connected(i, true);
|
|
}
|
|
|
|
if (prev_vsn->is_output_port_expandable(i) && prev_vsn->_is_output_port_expanded(i) && vsn->is_output_port_expandable(i)) {
|
|
vsn->_set_output_port_expanded(i, true);
|
|
|
|
int component_count = 0;
|
|
switch (prev_vsn->get_output_port_type(i)) {
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D:
|
|
component_count = 2;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
|
|
component_count = 3;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D:
|
|
component_count = 4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (int j = 0; j < component_count; j++) {
|
|
int sub_port = i + 1 + j;
|
|
|
|
if (prev_vsn->is_output_port_connected(sub_port)) {
|
|
vsn->set_output_port_connected(sub_port, true);
|
|
}
|
|
}
|
|
|
|
i += component_count;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update));
|
|
g->nodes[p_id].node = Ref<VisualShaderNode>(vsn);
|
|
|
|
_queue_update();
|
|
}
|
|
|
|
bool VisualShader::is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false);
|
|
const Graph *g = &graph[p_type];
|
|
|
|
for (const Connection &E : g->connections) {
|
|
if (E.from_node == p_from_node && E.from_port == p_from_port && E.to_node == p_to_node && E.to_port == p_to_port) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool VisualShader::is_nodes_connected_relatively(const Graph *p_graph, int p_node, int p_target) const {
|
|
bool result = false;
|
|
|
|
const VisualShader::Node &node = p_graph->nodes[p_node];
|
|
|
|
for (const int &E : node.prev_connected_nodes) {
|
|
if (E == p_target) {
|
|
return true;
|
|
}
|
|
|
|
result = is_nodes_connected_relatively(p_graph, E, p_target);
|
|
if (result) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false);
|
|
const Graph *g = &graph[p_type];
|
|
|
|
if (!g->nodes.has(p_from_node)) {
|
|
return false;
|
|
}
|
|
|
|
if (p_from_node == p_to_node) {
|
|
return false;
|
|
}
|
|
|
|
if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_expanded_output_port_count()) {
|
|
return false;
|
|
}
|
|
|
|
if (!g->nodes.has(p_to_node)) {
|
|
return false;
|
|
}
|
|
|
|
if (p_to_port < 0 || p_to_port >= g->nodes[p_to_node].node->get_input_port_count()) {
|
|
return false;
|
|
}
|
|
|
|
VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
|
|
VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
|
|
|
|
if (!is_port_types_compatible(from_port_type, to_port_type)) {
|
|
return false;
|
|
}
|
|
|
|
for (const Connection &E : g->connections) {
|
|
if (E.from_node == p_from_node && E.from_port == p_from_port && E.to_node == p_to_node && E.to_port == p_to_port) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (is_nodes_connected_relatively(g, p_from_node, p_to_node)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool VisualShader::is_port_types_compatible(int p_a, int p_b) const {
|
|
return MAX(0, p_a - 5) == (MAX(0, p_b - 5));
|
|
}
|
|
|
|
void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
|
|
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
|
Graph *g = &graph[p_type];
|
|
|
|
ERR_FAIL_COND(!g->nodes.has(p_from_node));
|
|
ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count());
|
|
ERR_FAIL_COND(!g->nodes.has(p_to_node));
|
|
ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count());
|
|
|
|
for (const Connection &E : g->connections) {
|
|
if (E.from_node == p_from_node && E.from_port == p_from_port && E.to_node == p_to_node && E.to_port == p_to_port) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
Connection c;
|
|
c.from_node = p_from_node;
|
|
c.from_port = p_from_port;
|
|
c.to_node = p_to_node;
|
|
c.to_port = p_to_port;
|
|
g->connections.push_back(c);
|
|
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
|
|
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
|
|
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
|
|
|
|
_queue_update();
|
|
}
|
|
|
|
Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, ERR_CANT_CONNECT);
|
|
Graph *g = &graph[p_type];
|
|
|
|
ERR_FAIL_COND_V(!g->nodes.has(p_from_node), ERR_INVALID_PARAMETER);
|
|
ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count(), ERR_INVALID_PARAMETER);
|
|
ERR_FAIL_COND_V(!g->nodes.has(p_to_node), ERR_INVALID_PARAMETER);
|
|
ERR_FAIL_INDEX_V(p_to_port, g->nodes[p_to_node].node->get_input_port_count(), ERR_INVALID_PARAMETER);
|
|
|
|
VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
|
|
VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
|
|
|
|
ERR_FAIL_COND_V_MSG(!is_port_types_compatible(from_port_type, to_port_type), ERR_INVALID_PARAMETER, "Incompatible port types (scalar/vec/bool) with transform.");
|
|
|
|
for (const Connection &E : g->connections) {
|
|
if (E.from_node == p_from_node && E.from_port == p_from_port && E.to_node == p_to_node && E.to_port == p_to_port) {
|
|
ERR_FAIL_V(ERR_ALREADY_EXISTS);
|
|
}
|
|
}
|
|
|
|
Connection c;
|
|
c.from_node = p_from_node;
|
|
c.from_port = p_from_port;
|
|
c.to_node = p_to_node;
|
|
c.to_port = p_to_port;
|
|
g->connections.push_back(c);
|
|
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
|
|
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
|
|
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
|
|
|
|
_queue_update();
|
|
return OK;
|
|
}
|
|
|
|
void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
|
|
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
|
Graph *g = &graph[p_type];
|
|
|
|
for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
|
|
if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
|
|
g->connections.erase(E);
|
|
g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node);
|
|
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false);
|
|
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false);
|
|
_queue_update();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
TypedArray<Dictionary> VisualShader::_get_node_connections(Type p_type) const {
|
|
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Array());
|
|
const Graph *g = &graph[p_type];
|
|
|
|
TypedArray<Dictionary> ret;
|
|
for (const Connection &E : g->connections) {
|
|
Dictionary d;
|
|
d["from_node"] = E.from_node;
|
|
d["from_port"] = E.from_port;
|
|
d["to_node"] = E.to_node;
|
|
d["to_port"] = E.to_port;
|
|
ret.push_back(d);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connections) const {
|
|
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
|
const Graph *g = &graph[p_type];
|
|
|
|
for (const Connection &E : g->connections) {
|
|
r_connections->push_back(E);
|
|
}
|
|
}
|
|
|
|
void VisualShader::set_mode(Mode p_mode) {
|
|
ERR_FAIL_INDEX_MSG(p_mode, Mode::MODE_MAX, vformat("Invalid shader mode: %d.", p_mode));
|
|
|
|
if (shader_mode == p_mode) {
|
|
return;
|
|
}
|
|
|
|
//erase input/output connections
|
|
modes.clear();
|
|
flags.clear();
|
|
shader_mode = p_mode;
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
for (KeyValue<int, Node> &E : graph[i].nodes) {
|
|
Ref<VisualShaderNodeInput> input = E.value.node;
|
|
if (input.is_valid()) {
|
|
input->shader_mode = shader_mode;
|
|
//input->input_index = 0;
|
|
}
|
|
}
|
|
|
|
Ref<VisualShaderNodeOutput> output = graph[i].nodes[NODE_ID_OUTPUT].node;
|
|
output->shader_mode = shader_mode;
|
|
|
|
// clear connections since they are no longer valid
|
|
for (List<Connection>::Element *E = graph[i].connections.front(); E;) {
|
|
bool keep = true;
|
|
|
|
List<Connection>::Element *N = E->next();
|
|
|
|
int from = E->get().from_node;
|
|
int to = E->get().to_node;
|
|
|
|
if (!graph[i].nodes.has(from)) {
|
|
keep = false;
|
|
} else {
|
|
Ref<VisualShaderNode> from_node = graph[i].nodes[from].node;
|
|
if (from_node->is_class("VisualShaderNodeOutput") || from_node->is_class("VisualShaderNodeInput")) {
|
|
keep = false;
|
|
}
|
|
}
|
|
|
|
if (!graph[i].nodes.has(to)) {
|
|
keep = false;
|
|
} else {
|
|
Ref<VisualShaderNode> to_node = graph[i].nodes[to].node;
|
|
if (to_node->is_class("VisualShaderNodeOutput") || to_node->is_class("VisualShaderNodeInput")) {
|
|
keep = false;
|
|
}
|
|
}
|
|
|
|
if (!keep) {
|
|
graph[i].connections.erase(E);
|
|
}
|
|
E = N;
|
|
}
|
|
}
|
|
|
|
_queue_update();
|
|
notify_property_list_changed();
|
|
}
|
|
|
|
void VisualShader::set_graph_offset(const Vector2 &p_offset) {
|
|
graph_offset = p_offset;
|
|
}
|
|
|
|
Vector2 VisualShader::get_graph_offset() const {
|
|
return graph_offset;
|
|
}
|
|
|
|
Shader::Mode VisualShader::get_mode() const {
|
|
return shader_mode;
|
|
}
|
|
|
|
bool VisualShader::is_text_shader() const {
|
|
return false;
|
|
}
|
|
|
|
String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &default_tex_params) const {
|
|
Ref<VisualShaderNode> node = get_node(p_type, p_node);
|
|
ERR_FAIL_COND_V(!node.is_valid(), String());
|
|
ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_expanded_output_port_count(), String());
|
|
ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String());
|
|
|
|
StringBuilder global_code;
|
|
StringBuilder global_code_per_node;
|
|
HashMap<Type, StringBuilder> global_code_per_func;
|
|
StringBuilder shader_code;
|
|
HashSet<StringName> classes;
|
|
|
|
global_code += String() + "shader_type canvas_item;\n";
|
|
|
|
String global_expressions;
|
|
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
|
|
for (const KeyValue<int, Node> &E : graph[i].nodes) {
|
|
Ref<VisualShaderNodeGlobalExpression> global_expression = E.value.node;
|
|
if (global_expression.is_valid()) {
|
|
String expr = "";
|
|
expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n";
|
|
expr += global_expression->generate_global(get_mode(), Type(i), -1);
|
|
expr = expr.replace("\n", "\n ");
|
|
expr += "\n";
|
|
global_expressions += expr;
|
|
}
|
|
}
|
|
}
|
|
|
|
global_code += "\n";
|
|
global_code += global_expressions;
|
|
|
|
//make it faster to go around through shader
|
|
VMap<ConnectionKey, const List<Connection>::Element *> input_connections;
|
|
VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
|
|
|
|
for (const List<Connection>::Element *E = graph[p_type].connections.front(); E; E = E->next()) {
|
|
ConnectionKey from_key;
|
|
from_key.node = E->get().from_node;
|
|
from_key.port = E->get().from_port;
|
|
|
|
output_connections.insert(from_key, E);
|
|
|
|
ConnectionKey to_key;
|
|
to_key.node = E->get().to_node;
|
|
to_key.port = E->get().to_port;
|
|
|
|
input_connections.insert(to_key, E);
|
|
}
|
|
|
|
shader_code += "\nvoid fragment() {\n";
|
|
|
|
HashSet<int> processed;
|
|
Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, shader_code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
|
|
ERR_FAIL_COND_V(err != OK, String());
|
|
|
|
switch (node->get_output_port_type(p_port)) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR: {
|
|
shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ");\n";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
|
|
shader_code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
|
|
shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ", 0.0);\n";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ".xyz;\n";
|
|
} break;
|
|
default: {
|
|
shader_code += " COLOR.rgb = vec3(0.0);\n";
|
|
} break;
|
|
}
|
|
|
|
shader_code += "}\n";
|
|
|
|
//set code secretly
|
|
global_code += "\n\n";
|
|
String final_code = global_code;
|
|
final_code += global_code_per_node;
|
|
final_code += shader_code;
|
|
return final_code;
|
|
}
|
|
|
|
String VisualShader::validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const {
|
|
String port_name = p_port_name;
|
|
|
|
if (port_name.is_empty()) {
|
|
return String();
|
|
}
|
|
|
|
while (port_name.length() && !is_ascii_char(port_name[0])) {
|
|
port_name = port_name.substr(1, port_name.length() - 1);
|
|
}
|
|
|
|
if (!port_name.is_empty()) {
|
|
String valid_name;
|
|
|
|
for (int i = 0; i < port_name.length(); i++) {
|
|
if (is_ascii_identifier_char(port_name[i])) {
|
|
valid_name += String::chr(port_name[i]);
|
|
} else if (port_name[i] == ' ') {
|
|
valid_name += "_";
|
|
}
|
|
}
|
|
|
|
port_name = valid_name;
|
|
} else {
|
|
return String();
|
|
}
|
|
|
|
List<String> input_names;
|
|
List<String> output_names;
|
|
|
|
for (int i = 0; i < p_node->get_input_port_count(); i++) {
|
|
if (!p_output && i == p_port_id) {
|
|
continue;
|
|
}
|
|
if (port_name == p_node->get_input_port_name(i)) {
|
|
return String();
|
|
}
|
|
}
|
|
for (int i = 0; i < p_node->get_output_port_count(); i++) {
|
|
if (p_output && i == p_port_id) {
|
|
continue;
|
|
}
|
|
if (port_name == p_node->get_output_port_name(i)) {
|
|
return String();
|
|
}
|
|
}
|
|
|
|
return port_name;
|
|
}
|
|
|
|
String VisualShader::validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const {
|
|
String param_name = p_name; //validate name first
|
|
while (param_name.length() && !is_ascii_char(param_name[0])) {
|
|
param_name = param_name.substr(1, param_name.length() - 1);
|
|
}
|
|
if (!param_name.is_empty()) {
|
|
String valid_name;
|
|
|
|
for (int i = 0; i < param_name.length(); i++) {
|
|
if (is_ascii_identifier_char(param_name[i])) {
|
|
valid_name += String::chr(param_name[i]);
|
|
} else if (param_name[i] == ' ') {
|
|
valid_name += "_";
|
|
}
|
|
}
|
|
|
|
param_name = valid_name;
|
|
}
|
|
|
|
if (param_name.is_empty()) {
|
|
param_name = p_parameter->get_caption();
|
|
}
|
|
|
|
int attempt = 1;
|
|
|
|
while (true) {
|
|
bool exists = false;
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
for (const KeyValue<int, Node> &E : graph[i].nodes) {
|
|
Ref<VisualShaderNodeParameter> node = E.value.node;
|
|
if (node == p_parameter) { //do not test on self
|
|
continue;
|
|
}
|
|
if (node.is_valid() && node->get_parameter_name() == param_name) {
|
|
exists = true;
|
|
break;
|
|
}
|
|
}
|
|
if (exists) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (exists) {
|
|
//remove numbers, put new and try again
|
|
attempt++;
|
|
while (param_name.length() && is_digit(param_name[param_name.length() - 1])) {
|
|
param_name = param_name.substr(0, param_name.length() - 1);
|
|
}
|
|
ERR_FAIL_COND_V(param_name.is_empty(), String());
|
|
param_name += itos(attempt);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return param_name;
|
|
}
|
|
|
|
static const char *type_string[VisualShader::TYPE_MAX] = {
|
|
"vertex",
|
|
"fragment",
|
|
"light",
|
|
"start",
|
|
"process",
|
|
"collide",
|
|
"start_custom",
|
|
"process_custom",
|
|
"sky",
|
|
"fog",
|
|
};
|
|
|
|
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
|
|
String prop_name = p_name;
|
|
if (prop_name == "mode") {
|
|
set_mode(Shader::Mode(int(p_value)));
|
|
return true;
|
|
} else if (prop_name.begins_with("flags/")) {
|
|
StringName flag = prop_name.get_slicec('/', 1);
|
|
bool enable = p_value;
|
|
if (enable) {
|
|
flags.insert(flag);
|
|
} else {
|
|
flags.erase(flag);
|
|
}
|
|
_queue_update();
|
|
return true;
|
|
} else if (prop_name.begins_with("modes/")) {
|
|
String mode_name = prop_name.get_slicec('/', 1);
|
|
int value = p_value;
|
|
if (value == 0) {
|
|
modes.erase(mode_name); //means it's default anyway, so don't store it
|
|
} else {
|
|
modes[mode_name] = value;
|
|
}
|
|
_queue_update();
|
|
return true;
|
|
} else if (prop_name.begins_with("varyings/")) {
|
|
String var_name = prop_name.get_slicec('/', 1);
|
|
Varying value = Varying();
|
|
value.name = var_name;
|
|
if (value.from_string(p_value) && !varyings.has(var_name)) {
|
|
varyings[var_name] = value;
|
|
varyings_list.push_back(value);
|
|
}
|
|
_queue_update();
|
|
return true;
|
|
} else if (prop_name.begins_with("nodes/")) {
|
|
String typestr = prop_name.get_slicec('/', 1);
|
|
Type type = TYPE_VERTEX;
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
if (typestr == type_string[i]) {
|
|
type = Type(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
String index = prop_name.get_slicec('/', 2);
|
|
if (index == "connections") {
|
|
Vector<int> conns = p_value;
|
|
if (conns.size() % 4 == 0) {
|
|
for (int i = 0; i < conns.size(); i += 4) {
|
|
connect_nodes_forced(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int id = index.to_int();
|
|
String what = prop_name.get_slicec('/', 3);
|
|
|
|
if (what == "node") {
|
|
add_node(type, p_value, Vector2(), id);
|
|
return true;
|
|
} else if (what == "position") {
|
|
set_node_position(type, id, p_value);
|
|
return true;
|
|
} else if (what == "size") {
|
|
((VisualShaderNodeResizableBase *)get_node(type, id).ptr())->set_size(p_value);
|
|
return true;
|
|
} else if (what == "input_ports") {
|
|
((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_inputs(p_value);
|
|
return true;
|
|
} else if (what == "output_ports") {
|
|
((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_outputs(p_value);
|
|
return true;
|
|
} else if (what == "expression") {
|
|
((VisualShaderNodeExpression *)get_node(type, id).ptr())->set_expression(p_value);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
|
|
String prop_name = p_name;
|
|
if (prop_name == "mode") {
|
|
r_ret = get_mode();
|
|
return true;
|
|
} else if (prop_name.begins_with("flags/")) {
|
|
StringName flag = prop_name.get_slicec('/', 1);
|
|
r_ret = flags.has(flag);
|
|
return true;
|
|
} else if (prop_name.begins_with("modes/")) {
|
|
String mode_name = prop_name.get_slicec('/', 1);
|
|
if (modes.has(mode_name)) {
|
|
r_ret = modes[mode_name];
|
|
} else {
|
|
r_ret = 0;
|
|
}
|
|
return true;
|
|
} else if (prop_name.begins_with("varyings/")) {
|
|
String var_name = prop_name.get_slicec('/', 1);
|
|
if (varyings.has(var_name)) {
|
|
r_ret = varyings[var_name].to_string();
|
|
} else {
|
|
r_ret = String();
|
|
}
|
|
return true;
|
|
} else if (prop_name.begins_with("nodes/")) {
|
|
String typestr = prop_name.get_slicec('/', 1);
|
|
Type type = TYPE_VERTEX;
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
if (typestr == type_string[i]) {
|
|
type = Type(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
String index = prop_name.get_slicec('/', 2);
|
|
if (index == "connections") {
|
|
Vector<int> conns;
|
|
for (const Connection &E : graph[type].connections) {
|
|
conns.push_back(E.from_node);
|
|
conns.push_back(E.from_port);
|
|
conns.push_back(E.to_node);
|
|
conns.push_back(E.to_port);
|
|
}
|
|
|
|
r_ret = conns;
|
|
return true;
|
|
}
|
|
|
|
int id = index.to_int();
|
|
String what = prop_name.get_slicec('/', 3);
|
|
|
|
if (what == "node") {
|
|
r_ret = get_node(type, id);
|
|
return true;
|
|
} else if (what == "position") {
|
|
r_ret = get_node_position(type, id);
|
|
return true;
|
|
} else if (what == "size") {
|
|
r_ret = ((VisualShaderNodeResizableBase *)get_node(type, id).ptr())->get_size();
|
|
return true;
|
|
} else if (what == "input_ports") {
|
|
r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_inputs();
|
|
return true;
|
|
} else if (what == "output_ports") {
|
|
r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_outputs();
|
|
return true;
|
|
} else if (what == "expression") {
|
|
r_ret = ((VisualShaderNodeExpression *)get_node(type, id).ptr())->get_expression();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void VisualShader::reset_state() {
|
|
// TODO: Everything needs to be cleared here.
|
|
emit_changed();
|
|
}
|
|
|
|
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
//mode
|
|
p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
|
|
//render modes
|
|
|
|
HashMap<String, String> blend_mode_enums;
|
|
HashSet<String> toggles;
|
|
|
|
const Vector<ShaderLanguage::ModeInfo> &rmodes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode));
|
|
|
|
for (int i = 0; i < rmodes.size(); i++) {
|
|
const ShaderLanguage::ModeInfo &info = rmodes[i];
|
|
|
|
if (!info.options.is_empty()) {
|
|
const String begin = String(info.name);
|
|
|
|
for (int j = 0; j < info.options.size(); j++) {
|
|
const String option = String(info.options[j]).capitalize();
|
|
|
|
if (!blend_mode_enums.has(begin)) {
|
|
blend_mode_enums[begin] = option;
|
|
} else {
|
|
blend_mode_enums[begin] += "," + option;
|
|
}
|
|
}
|
|
} else {
|
|
toggles.insert(String(info.name));
|
|
}
|
|
}
|
|
|
|
for (const KeyValue<String, String> &E : blend_mode_enums) {
|
|
p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("modes"), E.key), PROPERTY_HINT_ENUM, E.value));
|
|
}
|
|
|
|
for (const String &E : toggles) {
|
|
p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("flags"), E)));
|
|
}
|
|
|
|
for (const KeyValue<String, Varying> &E : varyings) {
|
|
p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", PNAME("varyings"), E.key)));
|
|
}
|
|
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
for (const KeyValue<int, Node> &E : graph[i].nodes) {
|
|
String prop_name = "nodes/";
|
|
prop_name += type_string[i];
|
|
prop_name += "/" + itos(E.key);
|
|
|
|
if (E.key != NODE_ID_OUTPUT) {
|
|
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
|
|
}
|
|
p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
|
|
if (Object::cast_to<VisualShaderNodeGroupBase>(E.value.node.ptr()) != nullptr) {
|
|
p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/input_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
}
|
|
if (Object::cast_to<VisualShaderNodeExpression>(E.value.node.ptr()) != nullptr) {
|
|
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
}
|
|
}
|
|
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "nodes/" + String(type_string[i]) + "/connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
}
|
|
}
|
|
|
|
Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringBuilder *p_global_code_per_node, HashMap<Type, StringBuilder> *p_global_code_per_func, StringBuilder &r_code, Vector<VisualShader::DefaultTextureParam> &r_def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &p_input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &p_output_connections, int p_node, HashSet<int> &r_processed, bool p_for_preview, HashSet<StringName> &r_classes) const {
|
|
const Ref<VisualShaderNode> vsnode = graph[type].nodes[p_node].node;
|
|
|
|
if (vsnode->is_disabled()) {
|
|
r_code += "// " + vsnode->get_caption() + ":" + itos(p_node) + "\n";
|
|
r_code += " // Node is disabled and code is not generated.\n";
|
|
return OK;
|
|
}
|
|
|
|
//check inputs recursively first
|
|
int input_count = vsnode->get_input_port_count();
|
|
for (int i = 0; i < input_count; i++) {
|
|
ConnectionKey ck;
|
|
ck.node = p_node;
|
|
ck.port = i;
|
|
|
|
if (p_input_connections.has(ck)) {
|
|
int from_node = p_input_connections[ck]->get().from_node;
|
|
if (r_processed.has(from_node)) {
|
|
continue;
|
|
}
|
|
|
|
Error err = _write_node(type, p_global_code, p_global_code_per_node, p_global_code_per_func, r_code, r_def_tex_params, p_input_connections, p_output_connections, from_node, r_processed, p_for_preview, r_classes);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
|
|
// then this node
|
|
|
|
Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, p_node);
|
|
for (int i = 0; i < params.size(); i++) {
|
|
r_def_tex_params.push_back(params[i]);
|
|
}
|
|
|
|
Ref<VisualShaderNodeInput> input = vsnode;
|
|
bool skip_global = input.is_valid() && p_for_preview;
|
|
|
|
if (!skip_global) {
|
|
Ref<VisualShaderNodeParameter> parameter = vsnode;
|
|
if (!parameter.is_valid() || !parameter->is_global_code_generated()) {
|
|
if (p_global_code) {
|
|
*p_global_code += vsnode->generate_global(get_mode(), type, p_node);
|
|
}
|
|
}
|
|
|
|
String class_name = vsnode->get_class_name();
|
|
if (class_name == "VisualShaderNodeCustom") {
|
|
class_name = vsnode->get_script_instance()->get_script()->get_path();
|
|
}
|
|
if (!r_classes.has(class_name)) {
|
|
if (p_global_code_per_node) {
|
|
*p_global_code_per_node += vsnode->generate_global_per_node(get_mode(), p_node);
|
|
}
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
if (p_global_code_per_func) {
|
|
(*p_global_code_per_func)[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), p_node);
|
|
}
|
|
}
|
|
r_classes.insert(class_name);
|
|
}
|
|
}
|
|
|
|
if (!vsnode->is_code_generated()) { // just generate globals and ignore locals
|
|
r_processed.insert(p_node);
|
|
return OK;
|
|
}
|
|
|
|
String node_name = "// " + vsnode->get_caption() + ":" + itos(p_node) + "\n";
|
|
String node_code;
|
|
Vector<String> input_vars;
|
|
|
|
input_vars.resize(vsnode->get_input_port_count());
|
|
String *inputs = input_vars.ptrw();
|
|
|
|
for (int i = 0; i < input_count; i++) {
|
|
ConnectionKey ck;
|
|
ck.node = p_node;
|
|
ck.port = i;
|
|
|
|
if (p_input_connections.has(ck)) {
|
|
//connected to something, use that output
|
|
int from_node = p_input_connections[ck]->get().from_node;
|
|
|
|
if (graph[type].nodes[from_node].node->is_disabled()) {
|
|
continue;
|
|
}
|
|
|
|
int from_port = p_input_connections[ck]->get().from_port;
|
|
|
|
VisualShaderNode::PortType in_type = vsnode->get_input_port_type(i);
|
|
VisualShaderNode::PortType out_type = graph[type].nodes[from_node].node->get_output_port_type(from_port);
|
|
|
|
String src_var = "n_out" + itos(from_node) + "p" + itos(from_port);
|
|
|
|
if (in_type == VisualShaderNode::PORT_TYPE_SAMPLER && out_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
|
|
VisualShaderNode *ptr = const_cast<VisualShaderNode *>(graph[type].nodes[from_node].node.ptr());
|
|
if (ptr->has_method("get_input_real_name")) {
|
|
inputs[i] = ptr->call("get_input_real_name");
|
|
} else if (ptr->has_method("get_parameter_name")) {
|
|
inputs[i] = ptr->call("get_parameter_name");
|
|
} else {
|
|
inputs[i] = "";
|
|
}
|
|
} else if (in_type == out_type) {
|
|
inputs[i] = src_var;
|
|
} else {
|
|
switch (in_type) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR: {
|
|
switch (out_type) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
|
|
inputs[i] = "float(" + src_var + ")";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
|
|
inputs[i] = "(" + src_var + " ? 1.0 : 0.0)";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
inputs[i] = src_var + ".x";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
inputs[i] = src_var + ".x";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
inputs[i] = src_var + ".x";
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
|
|
switch (out_type) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR: {
|
|
inputs[i] = "int(" + src_var + ")";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
|
|
inputs[i] = "(" + src_var + " ? 1 : 0)";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
inputs[i] = "dot(float(" + src_var + "), vec2(0.5, 0.5))";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
inputs[i] = "dot(float(" + src_var + "), vec3(0.333333, 0.333333, 0.333333))";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
inputs[i] = "dot(float(" + src_var + "), vec4(0.25, 0.25, 0.25, 0.25))";
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
|
|
switch (out_type) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR: {
|
|
inputs[i] = src_var + " > 0.0 ? true : false";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
|
|
inputs[i] = src_var + " > 0 ? true : false";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
inputs[i] = "all(bvec2(" + src_var + "))";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
inputs[i] = "all(bvec3(" + src_var + "))";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
inputs[i] = "all(bvec4(" + src_var + "))";
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
switch (out_type) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR: {
|
|
inputs[i] = "vec2(" + src_var + ")";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
|
|
inputs[i] = "vec2(float(" + src_var + "))";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
|
|
inputs[i] = "vec2(" + src_var + " ? 1.0 : 0.0)";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
inputs[i] = "vec2(" + src_var + ".xy)";
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
switch (out_type) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR: {
|
|
inputs[i] = "vec3(" + src_var + ")";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
|
|
inputs[i] = "vec3(float(" + src_var + "))";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
|
|
inputs[i] = "vec3(" + src_var + " ? 1.0 : 0.0)";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
inputs[i] = "vec3(" + src_var + ", 0.0)";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
inputs[i] = "vec3(" + src_var + ".xyz)";
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
switch (out_type) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR: {
|
|
inputs[i] = "vec4(" + src_var + ")";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
|
|
inputs[i] = "vec4(float(" + src_var + "))";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
|
|
inputs[i] = "vec4(" + src_var + " ? 1.0 : 0.0)";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
inputs[i] = "vec4(" + src_var + ", 0.0, 0.0)";
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
inputs[i] = "vec4(" + src_var + ", 0.0)";
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (!vsnode->is_generate_input_var(i)) {
|
|
continue;
|
|
}
|
|
|
|
Variant defval = vsnode->get_input_port_default_value(i);
|
|
if (defval.get_type() == Variant::FLOAT) {
|
|
float val = defval;
|
|
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
|
|
node_code += " float " + inputs[i] + " = " + vformat("%.5f", val) + ";\n";
|
|
} else if (defval.get_type() == Variant::INT) {
|
|
int val = defval;
|
|
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
|
|
node_code += " int " + inputs[i] + " = " + itos(val) + ";\n";
|
|
} else if (defval.get_type() == Variant::BOOL) {
|
|
bool val = defval;
|
|
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
|
|
node_code += " bool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n";
|
|
} else if (defval.get_type() == Variant::VECTOR2) {
|
|
Vector2 val = defval;
|
|
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
|
|
node_code += " vec2 " + inputs[i] + " = " + vformat("vec2(%.5f, %.5f);\n", val.x, val.y);
|
|
} else if (defval.get_type() == Variant::VECTOR3) {
|
|
Vector3 val = defval;
|
|
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
|
|
node_code += " vec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z);
|
|
} else if (defval.get_type() == Variant::QUATERNION) {
|
|
Quaternion val = defval;
|
|
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
|
|
node_code += " vec4 " + inputs[i] + " = " + vformat("vec4(%.5f, %.5f, %.5f, %.5f);\n", val.x, val.y, val.z, val.w);
|
|
} else if (defval.get_type() == Variant::TRANSFORM3D) {
|
|
Transform3D val = defval;
|
|
val.basis.transpose();
|
|
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
|
|
Array values;
|
|
for (int j = 0; j < 3; j++) {
|
|
values.push_back(val.basis[j].x);
|
|
values.push_back(val.basis[j].y);
|
|
values.push_back(val.basis[j].z);
|
|
}
|
|
values.push_back(val.origin.x);
|
|
values.push_back(val.origin.y);
|
|
values.push_back(val.origin.z);
|
|
bool err = false;
|
|
node_code += " mat4 " + inputs[i] + " = " + String("mat4(vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 1.0));\n").sprintf(values, &err);
|
|
} else {
|
|
//will go empty, node is expected to know what it is doing at this point and handle it
|
|
}
|
|
}
|
|
}
|
|
|
|
int output_count = vsnode->get_output_port_count();
|
|
int initial_output_count = output_count;
|
|
|
|
HashMap<int, bool> expanded_output_ports;
|
|
|
|
for (int i = 0; i < initial_output_count; i++) {
|
|
bool expanded = false;
|
|
|
|
if (vsnode->is_output_port_expandable(i) && vsnode->_is_output_port_expanded(i)) {
|
|
expanded = true;
|
|
|
|
switch (vsnode->get_output_port_type(i)) {
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
output_count += 2;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
output_count += 3;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
output_count += 4;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
expanded_output_ports.insert(i, expanded);
|
|
}
|
|
|
|
Vector<String> output_vars;
|
|
output_vars.resize(output_count);
|
|
String *outputs = output_vars.ptrw();
|
|
|
|
if (vsnode->is_simple_decl()) { // less code to generate for some simple_decl nodes
|
|
for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
|
|
String var_name = "n_out" + itos(p_node) + "p" + itos(j);
|
|
switch (vsnode->get_output_port_type(i)) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR:
|
|
outputs[i] = "float " + var_name;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
|
|
outputs[i] = "int " + var_name;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D:
|
|
outputs[i] = "vec2 " + var_name;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
|
|
outputs[i] = "vec3 " + var_name;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D:
|
|
outputs[i] = "vec4 " + var_name;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN:
|
|
outputs[i] = "bool " + var_name;
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_TRANSFORM:
|
|
outputs[i] = "mat4 " + var_name;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (expanded_output_ports[i]) {
|
|
switch (vsnode->get_output_port_type(i)) {
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
j += 2;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
j += 3;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
j += 4;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
|
|
outputs[i] = "n_out" + itos(p_node) + "p" + itos(j);
|
|
switch (vsnode->get_output_port_type(i)) {
|
|
case VisualShaderNode::PORT_TYPE_SCALAR:
|
|
r_code += " float " + outputs[i] + ";\n";
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
|
|
r_code += " int " + outputs[i] + ";\n";
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D:
|
|
r_code += " vec2 " + outputs[i] + ";\n";
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
|
|
r_code += " vec3 " + outputs[i] + ";\n";
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D:
|
|
r_code += " vec4 " + outputs[i] + ";\n";
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_BOOLEAN:
|
|
r_code += " bool " + outputs[i] + ";\n";
|
|
break;
|
|
case VisualShaderNode::PORT_TYPE_TRANSFORM:
|
|
r_code += " mat4 " + outputs[i] + ";\n";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (expanded_output_ports[i]) {
|
|
switch (vsnode->get_output_port_type(i)) {
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
j += 2;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
j += 3;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
j += 4;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
node_code += vsnode->generate_code(get_mode(), type, p_node, inputs, outputs, p_for_preview);
|
|
if (!node_code.is_empty()) {
|
|
r_code += node_name;
|
|
r_code += node_code;
|
|
}
|
|
|
|
for (int i = 0; i < output_count; i++) {
|
|
if (expanded_output_ports[i]) {
|
|
switch (vsnode->get_output_port_type(i)) {
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
|
|
if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
|
|
String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
|
|
r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
|
|
outputs[i + 1] = r;
|
|
}
|
|
|
|
if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
|
|
String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
|
|
r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
|
|
outputs[i + 2] = g;
|
|
}
|
|
|
|
i += 2;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
|
|
if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
|
|
String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
|
|
r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
|
|
outputs[i + 1] = r;
|
|
}
|
|
|
|
if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
|
|
String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
|
|
r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
|
|
outputs[i + 2] = g;
|
|
}
|
|
|
|
if (vsnode->is_output_port_connected(i + 3) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
|
|
String b = "n_out" + itos(p_node) + "p" + itos(i + 3);
|
|
r_code += " float " + b + " = n_out" + itos(p_node) + "p" + itos(i) + ".b;\n";
|
|
outputs[i + 3] = b;
|
|
}
|
|
|
|
i += 3;
|
|
} break;
|
|
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
|
|
if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
|
|
String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
|
|
r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
|
|
outputs[i + 1] = r;
|
|
}
|
|
|
|
if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
|
|
String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
|
|
r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
|
|
outputs[i + 2] = g;
|
|
}
|
|
|
|
if (vsnode->is_output_port_connected(i + 3) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
|
|
String b = "n_out" + itos(p_node) + "p" + itos(i + 3);
|
|
r_code += " float " + b + " = n_out" + itos(p_node) + "p" + itos(i) + ".b;\n";
|
|
outputs[i + 3] = b;
|
|
}
|
|
|
|
if (vsnode->is_output_port_connected(i + 4) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 4))) { // alpha-component
|
|
String a = "n_out" + itos(p_node) + "p" + itos(i + 4);
|
|
r_code += " float " + a + " = n_out" + itos(p_node) + "p" + itos(i) + ".a;\n";
|
|
outputs[i + 4] = a;
|
|
}
|
|
|
|
i += 4;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!node_code.is_empty()) {
|
|
r_code += "\n\n";
|
|
}
|
|
|
|
r_processed.insert(p_node);
|
|
|
|
return OK;
|
|
}
|
|
|
|
bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const {
|
|
if (!ShaderTypes::get_singleton()->get_functions(p_mode).has(p_func_name)) {
|
|
if (p_mode == RenderingServer::ShaderMode::SHADER_PARTICLES) {
|
|
if (p_func_name == "start_custom" || p_func_name == "process_custom" || p_func_name == "collide") {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void VisualShader::_update_shader() const {
|
|
if (!dirty.is_set()) {
|
|
return;
|
|
}
|
|
|
|
dirty.clear();
|
|
|
|
StringBuilder global_code;
|
|
StringBuilder global_code_per_node;
|
|
HashMap<Type, StringBuilder> global_code_per_func;
|
|
StringBuilder shader_code;
|
|
Vector<VisualShader::DefaultTextureParam> default_tex_params;
|
|
HashSet<StringName> classes;
|
|
HashMap<int, int> insertion_pos;
|
|
static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky", "fog" };
|
|
|
|
global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
|
|
|
|
String render_mode;
|
|
|
|
{
|
|
const Vector<ShaderLanguage::ModeInfo> &rmodes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode));
|
|
Vector<String> flag_names;
|
|
|
|
// Add enum modes first.
|
|
for (int i = 0; i < rmodes.size(); i++) {
|
|
const ShaderLanguage::ModeInfo &info = rmodes[i];
|
|
const String temp = String(info.name);
|
|
|
|
if (!info.options.is_empty()) {
|
|
if (modes.has(temp) && modes[temp] < info.options.size()) {
|
|
if (!render_mode.is_empty()) {
|
|
render_mode += ", ";
|
|
}
|
|
render_mode += temp + "_" + info.options[modes[temp]];
|
|
}
|
|
} else if (flags.has(temp)) {
|
|
flag_names.push_back(temp);
|
|
}
|
|
}
|
|
|
|
// Add flags afterward.
|
|
for (int i = 0; i < flag_names.size(); i++) {
|
|
if (!render_mode.is_empty()) {
|
|
render_mode += ", ";
|
|
}
|
|
render_mode += flag_names[i];
|
|
}
|
|
}
|
|
|
|
if (!render_mode.is_empty()) {
|
|
global_code += "render_mode " + render_mode + ";\n\n";
|
|
}
|
|
|
|
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
|
|
|
|
String global_expressions;
|
|
HashSet<String> used_parameter_names;
|
|
List<VisualShaderNodeParameter *> parameters;
|
|
HashMap<int, List<int>> emitters;
|
|
HashMap<int, List<int>> varying_setters;
|
|
|
|
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
|
|
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
|
|
continue;
|
|
}
|
|
|
|
for (const KeyValue<int, Node> &E : graph[i].nodes) {
|
|
Ref<VisualShaderNodeGlobalExpression> global_expression = E.value.node;
|
|
if (global_expression.is_valid()) {
|
|
String expr = "";
|
|
expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n";
|
|
expr += global_expression->generate_global(get_mode(), Type(i), -1);
|
|
expr = expr.replace("\n", "\n ");
|
|
expr += "\n";
|
|
global_expressions += expr;
|
|
}
|
|
Ref<VisualShaderNodeParameterRef> parameter_ref = E.value.node;
|
|
if (parameter_ref.is_valid()) {
|
|
used_parameter_names.insert(parameter_ref->get_parameter_name());
|
|
}
|
|
Ref<VisualShaderNodeParameter> parameter = E.value.node;
|
|
if (parameter.is_valid()) {
|
|
parameters.push_back(parameter.ptr());
|
|
}
|
|
Ref<VisualShaderNodeVaryingSetter> varying_setter = E.value.node;
|
|
if (varying_setter.is_valid() && varying_setter->is_input_port_connected(0)) {
|
|
if (!varying_setters.has(i)) {
|
|
varying_setters.insert(i, List<int>());
|
|
}
|
|
varying_setters[i].push_back(E.key);
|
|
}
|
|
Ref<VisualShaderNodeParticleEmit> emit_particle = E.value.node;
|
|
if (emit_particle.is_valid()) {
|
|
if (!emitters.has(i)) {
|
|
emitters.insert(i, List<int>());
|
|
}
|
|
emitters[i].push_back(E.key);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < parameters.size(); i++) {
|
|
VisualShaderNodeParameter *parameter = parameters[i];
|
|
if (used_parameter_names.has(parameter->get_parameter_name())) {
|
|
global_code += parameter->generate_global(get_mode(), Type(i), -1);
|
|
const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(true);
|
|
} else {
|
|
const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(false);
|
|
}
|
|
}
|
|
|
|
if (!varyings.is_empty()) {
|
|
global_code += "\n// Varyings\n";
|
|
|
|
for (const KeyValue<String, Varying> &E : varyings) {
|
|
global_code += "varying ";
|
|
switch (E.value.type) {
|
|
case VaryingType::VARYING_TYPE_FLOAT:
|
|
global_code += "float ";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_INT:
|
|
if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {
|
|
global_code += "flat ";
|
|
}
|
|
global_code += "int ";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_VECTOR_2D:
|
|
global_code += "vec2 ";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_VECTOR_3D:
|
|
global_code += "vec3 ";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_VECTOR_4D:
|
|
global_code += "vec4 ";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_BOOLEAN:
|
|
if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {
|
|
global_code += "flat ";
|
|
}
|
|
global_code += "bool ";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_TRANSFORM:
|
|
global_code += "mat4 ";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
global_code += E.key + ";\n";
|
|
}
|
|
|
|
global_code += "\n";
|
|
}
|
|
|
|
HashMap<int, String> code_map;
|
|
HashSet<int> empty_funcs;
|
|
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
|
|
continue;
|
|
}
|
|
|
|
//make it faster to go around through shader
|
|
VMap<ConnectionKey, const List<Connection>::Element *> input_connections;
|
|
VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
|
|
|
|
StringBuilder func_code;
|
|
HashSet<int> processed;
|
|
|
|
bool is_empty_func = false;
|
|
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG) {
|
|
is_empty_func = true;
|
|
}
|
|
|
|
String varying_code;
|
|
if (shader_mode == Shader::MODE_SPATIAL || shader_mode == Shader::MODE_CANVAS_ITEM) {
|
|
for (const KeyValue<String, Varying> &E : varyings) {
|
|
if ((E.value.mode == VARYING_MODE_VERTEX_TO_FRAG_LIGHT && i == TYPE_VERTEX) || (E.value.mode == VARYING_MODE_FRAG_TO_LIGHT && i == TYPE_FRAGMENT)) {
|
|
bool found = false;
|
|
for (int key : varying_setters[i]) {
|
|
Ref<VisualShaderNodeVaryingSetter> setter = Object::cast_to<VisualShaderNodeVaryingSetter>(const_cast<VisualShaderNode *>(graph[i].nodes[key].node.ptr()));
|
|
if (setter.is_valid() && E.value.name == setter->get_varying_name()) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
String code2;
|
|
switch (E.value.type) {
|
|
case VaryingType::VARYING_TYPE_FLOAT:
|
|
code2 += "0.0";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_INT:
|
|
code2 += "0";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_VECTOR_2D:
|
|
code2 += "vec2(0.0)";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_VECTOR_3D:
|
|
code2 += "vec3(0.0)";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_VECTOR_4D:
|
|
code2 += "vec4(0.0)";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_BOOLEAN:
|
|
code2 += "false";
|
|
break;
|
|
case VaryingType::VARYING_TYPE_TRANSFORM:
|
|
code2 += "mat4(1.0)";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
varying_code += vformat(" %s = %s;\n", E.key, code2);
|
|
}
|
|
is_empty_func = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) {
|
|
ConnectionKey from_key;
|
|
from_key.node = E->get().from_node;
|
|
from_key.port = E->get().from_port;
|
|
|
|
output_connections.insert(from_key, E);
|
|
|
|
ConnectionKey to_key;
|
|
to_key.node = E->get().to_node;
|
|
to_key.port = E->get().to_port;
|
|
|
|
input_connections.insert(to_key, E);
|
|
|
|
if (is_empty_func && to_key.node == NODE_ID_OUTPUT) {
|
|
is_empty_func = false;
|
|
}
|
|
}
|
|
|
|
if (is_empty_func) {
|
|
empty_funcs.insert(i);
|
|
continue;
|
|
}
|
|
|
|
if (shader_mode != Shader::MODE_PARTICLES) {
|
|
func_code += "\nvoid " + String(func_name[i]) + "() {\n";
|
|
}
|
|
insertion_pos.insert(i, shader_code.get_string_length() + func_code.get_string_length());
|
|
|
|
Error err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
|
|
ERR_FAIL_COND(err != OK);
|
|
|
|
if (varying_setters.has(i)) {
|
|
for (int &E : varying_setters[i]) {
|
|
err = _write_node(Type(i), nullptr, nullptr, nullptr, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes);
|
|
ERR_FAIL_COND(err != OK);
|
|
}
|
|
}
|
|
|
|
if (emitters.has(i)) {
|
|
for (int &E : emitters[i]) {
|
|
err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes);
|
|
ERR_FAIL_COND(err != OK);
|
|
}
|
|
}
|
|
|
|
if (shader_mode == Shader::MODE_PARTICLES) {
|
|
code_map.insert(i, func_code);
|
|
} else {
|
|
func_code += varying_code;
|
|
func_code += "}\n";
|
|
shader_code += func_code;
|
|
}
|
|
}
|
|
|
|
String global_compute_code;
|
|
|
|
if (shader_mode == Shader::MODE_PARTICLES) {
|
|
bool has_start_custom = !code_map[TYPE_START_CUSTOM].is_empty();
|
|
bool has_process = !code_map[TYPE_PROCESS].is_empty();
|
|
bool has_process_custom = !code_map[TYPE_PROCESS_CUSTOM].is_empty();
|
|
bool has_collide = !code_map[TYPE_COLLIDE].is_empty();
|
|
|
|
shader_code += "void start() {\n";
|
|
shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
|
|
shader_code += "\n";
|
|
shader_code += " {\n";
|
|
shader_code += code_map[TYPE_START].replace("\n ", "\n ");
|
|
shader_code += " }\n";
|
|
if (has_start_custom) {
|
|
shader_code += " \n";
|
|
shader_code += " {\n";
|
|
shader_code += code_map[TYPE_START_CUSTOM].replace("\n ", "\n ");
|
|
shader_code += " }\n";
|
|
}
|
|
shader_code += "}\n\n";
|
|
|
|
if (has_process || has_process_custom || has_collide) {
|
|
shader_code += "void process() {\n";
|
|
shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
|
|
shader_code += "\n";
|
|
if (has_process || has_collide) {
|
|
shader_code += " {\n";
|
|
}
|
|
String tab = " ";
|
|
if (has_collide) {
|
|
shader_code += " if (COLLIDED) {\n\n";
|
|
shader_code += code_map[TYPE_COLLIDE].replace("\n ", "\n ");
|
|
if (has_process) {
|
|
shader_code += " } else {\n\n";
|
|
tab += " ";
|
|
}
|
|
}
|
|
if (has_process) {
|
|
shader_code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab);
|
|
}
|
|
if (has_collide) {
|
|
shader_code += " }\n";
|
|
}
|
|
if (has_process || has_collide) {
|
|
shader_code += " }\n";
|
|
}
|
|
|
|
if (has_process_custom) {
|
|
if (has_process || has_collide) {
|
|
shader_code += " \n";
|
|
}
|
|
shader_code += " {\n";
|
|
shader_code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n ");
|
|
shader_code += " }\n";
|
|
}
|
|
|
|
shader_code += "}\n\n";
|
|
}
|
|
|
|
global_compute_code += "float __rand_from_seed(inout uint seed) {\n";
|
|
global_compute_code += " int k;\n";
|
|
global_compute_code += " int s = int(seed);\n";
|
|
global_compute_code += " if (s == 0)\n";
|
|
global_compute_code += " s = 305420679;\n";
|
|
global_compute_code += " k = s / 127773;\n";
|
|
global_compute_code += " s = 16807 * (s - k * 127773) - 2836 * k;\n";
|
|
global_compute_code += " if (s < 0)\n";
|
|
global_compute_code += " s += 2147483647;\n";
|
|
global_compute_code += " seed = uint(s);\n";
|
|
global_compute_code += " return float(seed % uint(65536)) / 65535.0;\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "float __rand_from_seed_m1_p1(inout uint seed) {\n";
|
|
global_compute_code += " return __rand_from_seed(seed) * 2.0 - 1.0;\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "float __randf_range(inout uint seed, float from, float to) {\n";
|
|
global_compute_code += " return __rand_from_seed(seed) * (to - from) + from;\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "vec2 __randv2_range(inout uint seed, vec2 from, vec2 to) {\n";
|
|
global_compute_code += " return vec2(__randf_range(seed, from.x, to.x), __randf_range(seed, from.y, to.y));\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "vec3 __randv3_range(inout uint seed, vec3 from, vec3 to) {\n";
|
|
global_compute_code += " return vec3(__randf_range(seed, from.x, to.x), __randf_range(seed, from.y, to.y), __randf_range(seed, from.z, to.z));\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "uint __hash(uint x) {\n";
|
|
global_compute_code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
|
|
global_compute_code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
|
|
global_compute_code += " x = (x >> uint(16)) ^ x;\n";
|
|
global_compute_code += " return x;\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "mat3 __build_rotation_mat3(vec3 axis, float angle) {\n";
|
|
global_compute_code += " axis = normalize(axis);\n";
|
|
global_compute_code += " float s = sin(angle);\n";
|
|
global_compute_code += " float c = cos(angle);\n";
|
|
global_compute_code += " float oc = 1.0 - c;\n";
|
|
global_compute_code += " return mat3(vec3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s), vec3(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s), vec3(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c));\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "mat4 __build_rotation_mat4(vec3 axis, float angle) {\n";
|
|
global_compute_code += " axis = normalize(axis);\n";
|
|
global_compute_code += " float s = sin(angle);\n";
|
|
global_compute_code += " float c = cos(angle);\n";
|
|
global_compute_code += " float oc = 1.0 - c;\n";
|
|
global_compute_code += " return mat4(vec4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0), vec4(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0), vec4(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0), vec4(0, 0, 0, 1));\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "vec2 __get_random_unit_vec2(inout uint seed) {\n";
|
|
global_compute_code += " return normalize(vec2(__rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed)));\n";
|
|
global_compute_code += "}\n\n";
|
|
|
|
global_compute_code += "vec3 __get_random_unit_vec3(inout uint seed) {\n";
|
|
global_compute_code += " return normalize(vec3(__rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed)));\n";
|
|
global_compute_code += "}\n\n";
|
|
}
|
|
|
|
//set code secretly
|
|
global_code += "\n\n";
|
|
String final_code = global_code;
|
|
final_code += global_compute_code;
|
|
final_code += global_code_per_node;
|
|
final_code += global_expressions;
|
|
String tcode = shader_code;
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
|
|
continue;
|
|
}
|
|
String func_code = global_code_per_func[Type(i)].as_string();
|
|
if (empty_funcs.has(Type(i)) && !func_code.is_empty()) {
|
|
func_code = vformat("%s%s%s", String("\nvoid " + String(func_name[i]) + "() {\n"), func_code, "}\n");
|
|
}
|
|
tcode = tcode.insert(insertion_pos[i], func_code);
|
|
}
|
|
final_code += tcode;
|
|
|
|
const_cast<VisualShader *>(this)->set_code(final_code);
|
|
for (int i = 0; i < default_tex_params.size(); i++) {
|
|
for (int j = 0; j < default_tex_params[i].params.size(); j++) {
|
|
const_cast<VisualShader *>(this)->set_default_texture_parameter(default_tex_params[i].name, default_tex_params[i].params[j], j);
|
|
}
|
|
}
|
|
if (previous_code != final_code) {
|
|
const_cast<VisualShader *>(this)->emit_signal(SNAME("changed"));
|
|
}
|
|
previous_code = final_code;
|
|
}
|
|
|
|
void VisualShader::_queue_update() {
|
|
if (dirty.is_set()) {
|
|
return;
|
|
}
|
|
|
|
dirty.set();
|
|
call_deferred(SNAME("_update_shader"));
|
|
}
|
|
|
|
void VisualShader::rebuild() {
|
|
dirty.set();
|
|
_update_shader();
|
|
}
|
|
|
|
void VisualShader::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShader::set_mode);
|
|
|
|
ClassDB::bind_method(D_METHOD("add_node", "type", "node", "position", "id"), &VisualShader::add_node);
|
|
ClassDB::bind_method(D_METHOD("get_node", "type", "id"), &VisualShader::get_node);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position);
|
|
ClassDB::bind_method(D_METHOD("get_node_position", "type", "id"), &VisualShader::get_node_position);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_node_list", "type"), &VisualShader::get_node_list);
|
|
ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id);
|
|
|
|
ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node);
|
|
ClassDB::bind_method(D_METHOD("replace_node", "type", "id", "new_class"), &VisualShader::replace_node);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
|
|
ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::can_connect_nodes);
|
|
|
|
ClassDB::bind_method(D_METHOD("connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes);
|
|
ClassDB::bind_method(D_METHOD("disconnect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::disconnect_nodes);
|
|
ClassDB::bind_method(D_METHOD("connect_nodes_forced", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes_forced);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
|
|
ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
|
|
|
|
ClassDB::bind_method(D_METHOD("add_varying", "name", "mode", "type"), &VisualShader::add_varying);
|
|
ClassDB::bind_method(D_METHOD("remove_varying", "name"), &VisualShader::remove_varying);
|
|
ClassDB::bind_method(D_METHOD("has_varying", "name"), &VisualShader::has_varying);
|
|
|
|
ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
|
|
|
|
ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs.
|
|
|
|
BIND_ENUM_CONSTANT(TYPE_VERTEX);
|
|
BIND_ENUM_CONSTANT(TYPE_FRAGMENT);
|
|
BIND_ENUM_CONSTANT(TYPE_LIGHT);
|
|
BIND_ENUM_CONSTANT(TYPE_START);
|
|
BIND_ENUM_CONSTANT(TYPE_PROCESS);
|
|
BIND_ENUM_CONSTANT(TYPE_COLLIDE);
|
|
BIND_ENUM_CONSTANT(TYPE_START_CUSTOM);
|
|
BIND_ENUM_CONSTANT(TYPE_PROCESS_CUSTOM);
|
|
BIND_ENUM_CONSTANT(TYPE_SKY);
|
|
BIND_ENUM_CONSTANT(TYPE_FOG);
|
|
BIND_ENUM_CONSTANT(TYPE_MAX);
|
|
|
|
BIND_ENUM_CONSTANT(VARYING_MODE_VERTEX_TO_FRAG_LIGHT);
|
|
BIND_ENUM_CONSTANT(VARYING_MODE_FRAG_TO_LIGHT);
|
|
BIND_ENUM_CONSTANT(VARYING_MODE_MAX);
|
|
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_FLOAT);
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_INT);
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_2D);
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_3D);
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_4D);
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_BOOLEAN);
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_TRANSFORM);
|
|
BIND_ENUM_CONSTANT(VARYING_TYPE_MAX);
|
|
|
|
BIND_CONSTANT(NODE_ID_INVALID);
|
|
BIND_CONSTANT(NODE_ID_OUTPUT);
|
|
}
|
|
|
|
VisualShader::VisualShader() {
|
|
dirty.set();
|
|
for (int i = 0; i < TYPE_MAX; i++) {
|
|
if (i > (int)TYPE_LIGHT && i < (int)TYPE_SKY) {
|
|
Ref<VisualShaderNodeParticleOutput> output;
|
|
output.instantiate();
|
|
output->shader_type = Type(i);
|
|
output->shader_mode = shader_mode;
|
|
graph[i].nodes[NODE_ID_OUTPUT].node = output;
|
|
} else {
|
|
Ref<VisualShaderNodeOutput> output;
|
|
output.instantiate();
|
|
output->shader_type = Type(i);
|
|
output->shader_mode = shader_mode;
|
|
graph[i].nodes[NODE_ID_OUTPUT].node = output;
|
|
}
|
|
|
|
graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
|
|
// Node3D
|
|
|
|
// Node3D, Vertex
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "vertex_id", "VERTEX_ID" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "instance_id", "INSTANCE_ID" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "instance_custom", "INSTANCE_CUSTOM" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_matrix", "MODEL_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "modelview_matrix", "MODELVIEW_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_view_matrix", "INV_VIEW_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "view_matrix", "VIEW_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection_matrix", "PROJECTION_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection_matrix", "INV_PROJECTION_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom0", "CUSTOM0" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom1", "CUSTOM1" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom2", "CUSTOM2" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom3", "CUSTOM3" },
|
|
|
|
// Node3D, Fragment
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "view", "VIEW" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_matrix", "MODEL_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "view_matrix", "VIEW_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_view_matrix", "INV_VIEW_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection_matrix", "PROJECTION_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection_matrix", "INV_PROJECTION_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "front_facing", "FRONT_FACING" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_roughness_texture", "NORMAL_ROUGHNESS_TEXTURE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
|
|
|
|
// Node3D, Light
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "view", "VIEW" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_color", "LIGHT_COLOR" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "attenuation", "ATTENUATION" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "diffuse", "DIFFUSE_LIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_matrix", "MODEL_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "view_matrix", "VIEW_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_view_matrix", "INV_VIEW_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection_matrix", "PROJECTION_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection_matrix", "INV_PROJECTION_MATRIX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
|
|
|
|
// Canvas Item
|
|
|
|
// Canvas Item, Vertex
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_matrix", "MODEL_MATRIX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "canvas_matrix", "CANVAS_MATRIX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "screen_matrix", "SCREEN_MATRIX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "instance_custom", "INSTANCE_CUSTOM" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "instance_id", "INSTANCE_ID" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "vertex_id", "VERTEX_ID" },
|
|
|
|
// Canvas Item, Fragment
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_pixel_size", "SCREEN_PIXEL_SIZE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_texture", "NORMAL_TEXTURE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "specular_shininess", "SPECULAR_SHININESS" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
|
|
|
|
// Canvas Item, Light
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "light", "LIGHT" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "light_color", "LIGHT_COLOR" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_position", "LIGHT_POSITION" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_direction", "LIGHT_DIRECTION" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light_is_directional", "LIGHT_IS_DIRECTIONAL" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_energy", "LIGHT_ENERGY" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_vertex", "LIGHT_VERTEX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "shadow", "SHADOW_MODULATE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "specular_shininess", "SPECULAR_SHININESS" },
|
|
|
|
// Particles, Start
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Particles, Start (Custom)
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Particles, Process
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Particles, Process (Custom)
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Particles, Collide
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "collision_depth", "COLLISION_DEPTH" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "collision_normal", "COLLISION_NORMAL" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Sky, Sky
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_half_res_pass", "AT_HALF_RES_PASS" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_quarter_res_pass", "AT_QUARTER_RES_PASS" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "eyedir", "EYEDIR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "half_res_color", "HALF_RES_COLOR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light0_color", "LIGHT0_COLOR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light0_direction", "LIGHT0_DIRECTION" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light0_enabled", "LIGHT0_ENABLED" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light0_energy", "LIGHT0_ENERGY" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light1_color", "LIGHT1_COLOR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light1_direction", "LIGHT1_DIRECTION" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light1_enabled", "LIGHT1_ENABLED" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light1_energy", "LIGHT1_ENERGY" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light2_color", "LIGHT2_COLOR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light2_direction", "LIGHT2_DIRECTION" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light2_enabled", "LIGHT2_ENABLED" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light2_energy", "LIGHT2_ENERGY" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light3_color", "LIGHT3_COLOR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light3_direction", "LIGHT3_DIRECTION" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light3_enabled", "LIGHT3_ENABLED" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light3_energy", "LIGHT3_ENERGY" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "position", "POSITION" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "quarter_res_color", "QUARTER_RES_COLOR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "sky_coords", "SKY_COORDS" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Fog, Fog
|
|
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "world_position", "WORLD_POSITION" },
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "object_position", "OBJECT_POSITION" },
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "uvw", "UVW" },
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "extents", "EXTENTS" },
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "sdf", "SDF" },
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
|
|
};
|
|
|
|
const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
|
|
// Spatial, Vertex
|
|
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "vec3(0.0, 1.0, 0.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "vec3(1.0, 0.0, 0.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Spatial, Fragment
|
|
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "vec3(0.0, 1.0, 0.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "vec3(1.0, 0.0, 0.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Spatial, Light
|
|
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Canvas Item, Vertex
|
|
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Canvas Item, Fragment
|
|
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec3(1.0)" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Canvas Item, Light
|
|
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Particles
|
|
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Sky
|
|
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
// Fog
|
|
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
|
|
|
|
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
|
|
};
|
|
|
|
int VisualShaderNodeInput::get_input_port_count() const {
|
|
return 0;
|
|
}
|
|
|
|
VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_port_type(int p_port) const {
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeInput::get_input_port_name(int p_port) const {
|
|
return "";
|
|
}
|
|
|
|
int VisualShaderNodeInput::get_output_port_count() const {
|
|
return 1;
|
|
}
|
|
|
|
VisualShaderNodeInput::PortType VisualShaderNodeInput::get_output_port_type(int p_port) const {
|
|
return p_port == 0 ? get_input_type_by_name(input_name) : PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeInput::get_output_port_name(int p_port) const {
|
|
return "";
|
|
}
|
|
|
|
String VisualShaderNodeInput::get_caption() const {
|
|
return "Input";
|
|
}
|
|
|
|
bool VisualShaderNodeInput::is_output_port_expandable(int p_port) const {
|
|
if (p_port == 0) {
|
|
switch (get_input_type_by_name(input_name)) {
|
|
case PORT_TYPE_VECTOR_2D:
|
|
return true;
|
|
case PORT_TYPE_VECTOR_3D:
|
|
return true;
|
|
case PORT_TYPE_VECTOR_4D:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
if (get_output_port_type(0) == PORT_TYPE_SAMPLER) {
|
|
return "";
|
|
}
|
|
|
|
if (p_for_preview) {
|
|
int idx = 0;
|
|
|
|
String code;
|
|
|
|
while (preview_ports[idx].mode != Shader::MODE_MAX) {
|
|
if (preview_ports[idx].mode == shader_mode && preview_ports[idx].shader_type == shader_type && preview_ports[idx].name == input_name) {
|
|
code = " " + p_output_vars[0] + " = " + preview_ports[idx].string + ";\n";
|
|
break;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
if (code.is_empty()) {
|
|
switch (get_output_port_type(0)) {
|
|
case PORT_TYPE_SCALAR: {
|
|
code = " " + p_output_vars[0] + " = 0.0;\n";
|
|
} break;
|
|
case PORT_TYPE_SCALAR_INT: {
|
|
code = " " + p_output_vars[0] + " = 0;\n";
|
|
} break;
|
|
case PORT_TYPE_VECTOR_2D: {
|
|
code = " " + p_output_vars[0] + " = vec2(0.0);\n";
|
|
} break;
|
|
case PORT_TYPE_VECTOR_3D: {
|
|
code = " " + p_output_vars[0] + " = vec3(0.0);\n";
|
|
} break;
|
|
case PORT_TYPE_VECTOR_4D: {
|
|
code = " " + p_output_vars[0] + " = vec4(0.0);\n";
|
|
} break;
|
|
case PORT_TYPE_BOOLEAN: {
|
|
code = " " + p_output_vars[0] + " = false;\n";
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return code;
|
|
|
|
} else {
|
|
int idx = 0;
|
|
|
|
String code;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) {
|
|
code = " " + p_output_vars[0] + " = " + ports[idx].string + ";\n";
|
|
break;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
if (code.is_empty()) {
|
|
code = " " + p_output_vars[0] + " = 0.0;\n"; //default (none found) is scalar
|
|
}
|
|
|
|
return code;
|
|
}
|
|
}
|
|
|
|
void VisualShaderNodeInput::set_input_name(String p_name) {
|
|
PortType prev_type = get_input_type_by_name(input_name);
|
|
input_name = p_name;
|
|
emit_changed();
|
|
if (get_input_type_by_name(input_name) != prev_type) {
|
|
emit_signal(SNAME("input_type_changed"));
|
|
}
|
|
}
|
|
|
|
String VisualShaderNodeInput::get_input_name() const {
|
|
return input_name;
|
|
}
|
|
|
|
String VisualShaderNodeInput::get_input_real_name() const {
|
|
int idx = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) {
|
|
return String(ports[idx].string);
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_type_by_name(String p_name) const {
|
|
int idx = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == p_name) {
|
|
return ports[idx].type;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
int VisualShaderNodeInput::get_input_index_count() const {
|
|
int idx = 0;
|
|
int count = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
count++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_index_type(int p_index) const {
|
|
int idx = 0;
|
|
int count = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
if (count == p_index) {
|
|
return ports[idx].type;
|
|
}
|
|
count++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeInput::get_input_index_name(int p_index) const {
|
|
int idx = 0;
|
|
int count = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
if (count == p_index) {
|
|
return ports[idx].name;
|
|
}
|
|
count++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void VisualShaderNodeInput::_validate_property(PropertyInfo &p_property) const {
|
|
if (p_property.name == "input_name") {
|
|
String port_list;
|
|
|
|
int idx = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
if (!port_list.is_empty()) {
|
|
port_list += ",";
|
|
}
|
|
port_list += ports[idx].name;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
if (port_list.is_empty()) {
|
|
port_list = RTR("None");
|
|
}
|
|
p_property.hint_string = port_list;
|
|
}
|
|
}
|
|
|
|
Vector<StringName> VisualShaderNodeInput::get_editable_properties() const {
|
|
Vector<StringName> props;
|
|
props.push_back("input_name");
|
|
return props;
|
|
}
|
|
|
|
void VisualShaderNodeInput::set_shader_type(VisualShader::Type p_shader_type) {
|
|
shader_type = p_shader_type;
|
|
}
|
|
|
|
void VisualShaderNodeInput::set_shader_mode(Shader::Mode p_shader_mode) {
|
|
shader_mode = p_shader_mode;
|
|
}
|
|
|
|
void VisualShaderNodeInput::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_input_name", "name"), &VisualShaderNodeInput::set_input_name);
|
|
ClassDB::bind_method(D_METHOD("get_input_name"), &VisualShaderNodeInput::get_input_name);
|
|
ClassDB::bind_method(D_METHOD("get_input_real_name"), &VisualShaderNodeInput::get_input_real_name);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "input_name", PROPERTY_HINT_ENUM, ""), "set_input_name", "get_input_name");
|
|
ADD_SIGNAL(MethodInfo("input_type_changed"));
|
|
}
|
|
|
|
VisualShaderNodeInput::VisualShaderNodeInput() {
|
|
}
|
|
|
|
////////////// ParameterRef
|
|
|
|
RBMap<RID, List<VisualShaderNodeParameterRef::Parameter>> parameters;
|
|
|
|
void VisualShaderNodeParameterRef::add_parameter(RID p_shader_rid, const String &p_name, ParameterType p_type) {
|
|
parameters[p_shader_rid].push_back({ p_name, p_type });
|
|
}
|
|
|
|
void VisualShaderNodeParameterRef::clear_parameters(RID p_shader_rid) {
|
|
parameters[p_shader_rid].clear();
|
|
}
|
|
|
|
bool VisualShaderNodeParameterRef::has_parameter(RID p_shader_rid, const String &p_name) {
|
|
for (const VisualShaderNodeParameterRef::Parameter &E : parameters[p_shader_rid]) {
|
|
if (E.name == p_name) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
String VisualShaderNodeParameterRef::get_caption() const {
|
|
return "ParameterRef";
|
|
}
|
|
|
|
int VisualShaderNodeParameterRef::get_input_port_count() const {
|
|
return 0;
|
|
}
|
|
|
|
VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_input_port_type(int p_port) const {
|
|
return PortType::PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeParameterRef::get_input_port_name(int p_port) const {
|
|
return "";
|
|
}
|
|
|
|
int VisualShaderNodeParameterRef::get_output_port_count() const {
|
|
switch (param_type) {
|
|
case PARAMETER_TYPE_FLOAT:
|
|
return 1;
|
|
case PARAMETER_TYPE_INT:
|
|
return 1;
|
|
case PARAMETER_TYPE_BOOLEAN:
|
|
return 1;
|
|
case PARAMETER_TYPE_VECTOR2:
|
|
return 1;
|
|
case PARAMETER_TYPE_VECTOR3:
|
|
return 1;
|
|
case PARAMETER_TYPE_VECTOR4:
|
|
return 1;
|
|
case PARAMETER_TYPE_TRANSFORM:
|
|
return 1;
|
|
case PARAMETER_TYPE_COLOR:
|
|
return 2;
|
|
case UNIFORM_TYPE_SAMPLER:
|
|
return 1;
|
|
default:
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_output_port_type(int p_port) const {
|
|
switch (param_type) {
|
|
case PARAMETER_TYPE_FLOAT:
|
|
return PortType::PORT_TYPE_SCALAR;
|
|
case PARAMETER_TYPE_INT:
|
|
return PortType::PORT_TYPE_SCALAR_INT;
|
|
case PARAMETER_TYPE_BOOLEAN:
|
|
return PortType::PORT_TYPE_BOOLEAN;
|
|
case PARAMETER_TYPE_VECTOR2:
|
|
return PortType::PORT_TYPE_VECTOR_2D;
|
|
case PARAMETER_TYPE_VECTOR3:
|
|
return PortType::PORT_TYPE_VECTOR_3D;
|
|
case PARAMETER_TYPE_VECTOR4:
|
|
return PortType::PORT_TYPE_VECTOR_4D;
|
|
case PARAMETER_TYPE_TRANSFORM:
|
|
return PortType::PORT_TYPE_TRANSFORM;
|
|
case PARAMETER_TYPE_COLOR:
|
|
if (p_port == 0) {
|
|
return PortType::PORT_TYPE_VECTOR_3D;
|
|
} else if (p_port == 1) {
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
break;
|
|
case UNIFORM_TYPE_SAMPLER:
|
|
return PortType::PORT_TYPE_SAMPLER;
|
|
default:
|
|
break;
|
|
}
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeParameterRef::get_output_port_name(int p_port) const {
|
|
switch (param_type) {
|
|
case PARAMETER_TYPE_FLOAT:
|
|
return "";
|
|
case PARAMETER_TYPE_INT:
|
|
return "";
|
|
case PARAMETER_TYPE_BOOLEAN:
|
|
return "";
|
|
case PARAMETER_TYPE_VECTOR2:
|
|
return "";
|
|
case PARAMETER_TYPE_VECTOR3:
|
|
return "";
|
|
case PARAMETER_TYPE_VECTOR4:
|
|
return "";
|
|
case PARAMETER_TYPE_TRANSFORM:
|
|
return "";
|
|
case PARAMETER_TYPE_COLOR:
|
|
if (p_port == 0) {
|
|
return "rgb";
|
|
} else if (p_port == 1) {
|
|
return "alpha";
|
|
}
|
|
break;
|
|
case UNIFORM_TYPE_SAMPLER:
|
|
return "";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
void VisualShaderNodeParameterRef::set_shader_rid(const RID &p_shader_rid) {
|
|
shader_rid = p_shader_rid;
|
|
}
|
|
|
|
void VisualShaderNodeParameterRef::set_parameter_name(const String &p_name) {
|
|
parameter_name = p_name;
|
|
if (shader_rid.is_valid()) {
|
|
update_parameter_type();
|
|
}
|
|
emit_changed();
|
|
}
|
|
|
|
void VisualShaderNodeParameterRef::update_parameter_type() {
|
|
if (parameter_name != "[None]") {
|
|
param_type = get_parameter_type_by_name(parameter_name);
|
|
} else {
|
|
param_type = PARAMETER_TYPE_FLOAT;
|
|
}
|
|
}
|
|
|
|
String VisualShaderNodeParameterRef::get_parameter_name() const {
|
|
return parameter_name;
|
|
}
|
|
|
|
int VisualShaderNodeParameterRef::get_parameters_count() const {
|
|
ERR_FAIL_COND_V(!shader_rid.is_valid(), 0);
|
|
|
|
return parameters[shader_rid].size();
|
|
}
|
|
|
|
String VisualShaderNodeParameterRef::get_parameter_name_by_index(int p_idx) const {
|
|
ERR_FAIL_COND_V(!shader_rid.is_valid(), String());
|
|
|
|
if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
|
|
return parameters[shader_rid][p_idx].name;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_name(const String &p_name) const {
|
|
ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
|
|
|
|
for (int i = 0; i < parameters[shader_rid].size(); i++) {
|
|
if (parameters[shader_rid][i].name == p_name) {
|
|
return parameters[shader_rid][i].type;
|
|
}
|
|
}
|
|
return PARAMETER_TYPE_FLOAT;
|
|
}
|
|
|
|
VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_index(int p_idx) const {
|
|
ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
|
|
|
|
if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
|
|
return parameters[shader_rid][p_idx].type;
|
|
}
|
|
return PARAMETER_TYPE_FLOAT;
|
|
}
|
|
|
|
VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_port_type_by_index(int p_idx) const {
|
|
ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR);
|
|
|
|
if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
|
|
switch (parameters[shader_rid][p_idx].type) {
|
|
case PARAMETER_TYPE_FLOAT:
|
|
return PORT_TYPE_SCALAR;
|
|
case PARAMETER_TYPE_INT:
|
|
return PORT_TYPE_SCALAR_INT;
|
|
case UNIFORM_TYPE_SAMPLER:
|
|
return PORT_TYPE_SAMPLER;
|
|
case PARAMETER_TYPE_VECTOR2:
|
|
return PORT_TYPE_VECTOR_2D;
|
|
case PARAMETER_TYPE_VECTOR3:
|
|
return PORT_TYPE_VECTOR_3D;
|
|
case PARAMETER_TYPE_VECTOR4:
|
|
return PORT_TYPE_VECTOR_4D;
|
|
case PARAMETER_TYPE_TRANSFORM:
|
|
return PORT_TYPE_TRANSFORM;
|
|
case PARAMETER_TYPE_COLOR:
|
|
return PORT_TYPE_VECTOR_3D;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeParameterRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
switch (param_type) {
|
|
case PARAMETER_TYPE_FLOAT:
|
|
if (parameter_name == "[None]") {
|
|
return " " + p_output_vars[0] + " = 0.0;\n";
|
|
}
|
|
break;
|
|
case PARAMETER_TYPE_COLOR: {
|
|
String code = " " + p_output_vars[0] + " = " + get_parameter_name() + ".rgb;\n";
|
|
code += " " + p_output_vars[1] + " = " + get_parameter_name() + ".a;\n";
|
|
return code;
|
|
} break;
|
|
case UNIFORM_TYPE_SAMPLER:
|
|
return String();
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
|
|
}
|
|
|
|
void VisualShaderNodeParameterRef::_set_parameter_type(int p_type) {
|
|
param_type = (ParameterType)p_type;
|
|
}
|
|
|
|
int VisualShaderNodeParameterRef::_get_parameter_type() const {
|
|
return (int)param_type;
|
|
}
|
|
|
|
void VisualShaderNodeParameterRef::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameterRef::set_parameter_name);
|
|
ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameterRef::get_parameter_name);
|
|
|
|
ClassDB::bind_method(D_METHOD("_set_parameter_type", "type"), &VisualShaderNodeParameterRef::_set_parameter_type);
|
|
ClassDB::bind_method(D_METHOD("_get_parameter_type"), &VisualShaderNodeParameterRef::_get_parameter_type);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name", PROPERTY_HINT_ENUM, ""), "set_parameter_name", "get_parameter_name");
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "param_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_parameter_type", "_get_parameter_type");
|
|
}
|
|
|
|
Vector<StringName> VisualShaderNodeParameterRef::get_editable_properties() const {
|
|
Vector<StringName> props;
|
|
props.push_back("parameter_name");
|
|
props.push_back("param_type");
|
|
return props;
|
|
}
|
|
|
|
VisualShaderNodeParameterRef::VisualShaderNodeParameterRef() {
|
|
}
|
|
|
|
////////////////////////////////////////////
|
|
|
|
const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Node3D.
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Node3D, Vertex.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Vertex", "VERTEX" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Tangent", "TANGENT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Binormal", "BINORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV2", "UV2" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Model View Matrix", "MODELVIEW_MATRIX" },
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Node3D, Fragment.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Albedo", "ALBEDO" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Metallic", "METALLIC" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Specular", "SPECULAR" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Emission", "EMISSION" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "AO", "AO" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "AO Light Affect", "AO_LIGHT_AFFECT" },
|
|
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" },
|
|
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim", "RIM" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim Tint", "RIM_TINT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Clearcoat", "CLEARCOAT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Clearcoat Roughness", "CLEARCOAT_ROUGHNESS" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Anisotropy", "ANISOTROPY" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Anisotropy Flow", "ANISOTROPY_FLOW" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Subsurf Scatter", "SSS_STRENGTH" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Backlight", "BACKLIGHT" },
|
|
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha Scissor Threshold", "ALPHA_SCISSOR_THRESHOLD" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha Hash Scale", "ALPHA_HASH_SCALE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha AA Edge", "ALPHA_ANTIALIASING_EDGE" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Alpha UV", "ALPHA_TEXTURE_COORDINATE" },
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Node3D, Light.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Diffuse", "DIFFUSE_LIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Specular", "SPECULAR_LIGHT" },
|
|
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Canvas Item.
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Canvas Item, Vertex.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Vertex", "VERTEX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Canvas Item, Fragment.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light Vertex", "LIGHT_VERTEX" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Shadow Vertex", "SHADOW_VERTEX" },
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Canvas Item, Light.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light", "LIGHT.rgb" },
|
|
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Light Alpha", "LIGHT.a" },
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Sky, Sky.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Fog", "FOG.rgb" },
|
|
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "Fog Alpha", "FOG.a" },
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Fog, Fog.
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "Density", "DENSITY" },
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Albedo", "ALBEDO" },
|
|
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Emission", "EMISSION" },
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
|
|
};
|
|
|
|
int VisualShaderNodeOutput::get_input_port_count() const {
|
|
int idx = 0;
|
|
int count = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
count++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
VisualShaderNodeOutput::PortType VisualShaderNodeOutput::get_input_port_type(int p_port) const {
|
|
int idx = 0;
|
|
int count = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
if (count == p_port) {
|
|
return ports[idx].type;
|
|
}
|
|
count++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeOutput::get_input_port_name(int p_port) const {
|
|
int idx = 0;
|
|
int count = 0;
|
|
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
if (count == p_port) {
|
|
return String(ports[idx].name);
|
|
}
|
|
count++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return String();
|
|
}
|
|
|
|
Variant VisualShaderNodeOutput::get_input_port_default_value(int p_port) const {
|
|
return Variant();
|
|
}
|
|
|
|
int VisualShaderNodeOutput::get_output_port_count() const {
|
|
return 0;
|
|
}
|
|
|
|
VisualShaderNodeOutput::PortType VisualShaderNodeOutput::get_output_port_type(int p_port) const {
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeOutput::get_output_port_name(int p_port) const {
|
|
return String();
|
|
}
|
|
|
|
bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
|
|
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_VERTEX) {
|
|
String port_name = get_input_port_name(p_index);
|
|
return bool(port_name == "Model View Matrix");
|
|
}
|
|
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
|
|
String port_name = get_input_port_name(p_index);
|
|
return bool(port_name == "AO" || port_name == "Normal" || port_name == "Rim" || port_name == "Clearcoat" || port_name == "Anisotropy" || port_name == "Subsurf Scatter" || port_name == "Alpha Scissor Threshold");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
String VisualShaderNodeOutput::get_caption() const {
|
|
return "Output";
|
|
}
|
|
|
|
String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
int idx = 0;
|
|
int count = 0;
|
|
|
|
String shader_code;
|
|
while (ports[idx].mode != Shader::MODE_MAX) {
|
|
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
|
|
if (!p_input_vars[count].is_empty()) {
|
|
String s = ports[idx].string;
|
|
if (s.contains(":")) {
|
|
shader_code += " " + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n";
|
|
} else {
|
|
shader_code += " " + s + " = " + p_input_vars[count] + ";\n";
|
|
}
|
|
}
|
|
count++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return shader_code;
|
|
}
|
|
|
|
VisualShaderNodeOutput::VisualShaderNodeOutput() {
|
|
}
|
|
|
|
///////////////////////////
|
|
|
|
void VisualShaderNodeParameter::set_parameter_name(const String &p_name) {
|
|
parameter_name = p_name;
|
|
emit_signal(SNAME("name_changed"));
|
|
emit_changed();
|
|
}
|
|
|
|
String VisualShaderNodeParameter::get_parameter_name() const {
|
|
return parameter_name;
|
|
}
|
|
|
|
void VisualShaderNodeParameter::set_qualifier(VisualShaderNodeParameter::Qualifier p_qual) {
|
|
ERR_FAIL_INDEX(int(p_qual), int(QUAL_MAX));
|
|
if (qualifier == p_qual) {
|
|
return;
|
|
}
|
|
qualifier = p_qual;
|
|
emit_changed();
|
|
}
|
|
|
|
VisualShaderNodeParameter::Qualifier VisualShaderNodeParameter::get_qualifier() const {
|
|
return qualifier;
|
|
}
|
|
|
|
void VisualShaderNodeParameter::set_global_code_generated(bool p_enabled) {
|
|
global_code_generated = p_enabled;
|
|
}
|
|
|
|
bool VisualShaderNodeParameter::is_global_code_generated() const {
|
|
return global_code_generated;
|
|
}
|
|
|
|
#ifndef DISABLE_DEPRECATED
|
|
// Kept for compatibility from 3.x to 4.0.
|
|
bool VisualShaderNodeParameter::_set(const StringName &p_name, const Variant &p_value) {
|
|
if (p_name == "uniform_name") {
|
|
set_parameter_name(p_value);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
void VisualShaderNodeParameter::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameter::set_parameter_name);
|
|
ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameter::get_parameter_name);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_qualifier", "qualifier"), &VisualShaderNodeParameter::set_qualifier);
|
|
ClassDB::bind_method(D_METHOD("get_qualifier"), &VisualShaderNodeParameter::get_qualifier);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name"), "set_parameter_name", "get_parameter_name");
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "qualifier", PROPERTY_HINT_ENUM, "None,Global,Instance"), "set_qualifier", "get_qualifier");
|
|
|
|
BIND_ENUM_CONSTANT(QUAL_NONE);
|
|
BIND_ENUM_CONSTANT(QUAL_GLOBAL);
|
|
BIND_ENUM_CONSTANT(QUAL_INSTANCE);
|
|
BIND_ENUM_CONSTANT(QUAL_MAX);
|
|
}
|
|
|
|
String VisualShaderNodeParameter::_get_qual_str() const {
|
|
if (is_qualifier_supported(qualifier)) {
|
|
switch (qualifier) {
|
|
case QUAL_NONE:
|
|
break;
|
|
case QUAL_GLOBAL:
|
|
return "global ";
|
|
case QUAL_INSTANCE:
|
|
return "instance ";
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return String();
|
|
}
|
|
|
|
String VisualShaderNodeParameter::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
|
|
List<String> keyword_list;
|
|
ShaderLanguage::get_keyword_list(&keyword_list);
|
|
if (keyword_list.find(parameter_name)) {
|
|
return RTR("Shader keywords cannot be used as parameter names.\nChoose another name.");
|
|
}
|
|
if (!is_qualifier_supported(qualifier)) {
|
|
String qualifier_str;
|
|
switch (qualifier) {
|
|
case QUAL_NONE:
|
|
break;
|
|
case QUAL_GLOBAL:
|
|
qualifier_str = "global";
|
|
break;
|
|
case QUAL_INSTANCE:
|
|
qualifier_str = "instance";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return vformat(RTR("This parameter type does not support the '%s' qualifier."), qualifier_str);
|
|
} else if (qualifier == Qualifier::QUAL_GLOBAL) {
|
|
RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(parameter_name);
|
|
if (gvt == RS::GLOBAL_VAR_TYPE_MAX) {
|
|
return vformat(RTR("Global parameter '%s' does not exist.\nCreate it in the Project Settings."), parameter_name);
|
|
}
|
|
bool incompatible_type = false;
|
|
switch (gvt) {
|
|
case RS::GLOBAL_VAR_TYPE_FLOAT: {
|
|
if (!Object::cast_to<VisualShaderNodeFloatParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_INT: {
|
|
if (!Object::cast_to<VisualShaderNodeIntParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_BOOL: {
|
|
if (!Object::cast_to<VisualShaderNodeBooleanParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_COLOR: {
|
|
if (!Object::cast_to<VisualShaderNodeColorParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_VEC3: {
|
|
if (!Object::cast_to<VisualShaderNodeVec3Parameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_VEC4: {
|
|
if (!Object::cast_to<VisualShaderNodeVec4Parameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
|
|
if (!Object::cast_to<VisualShaderNodeTransformParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
|
|
if (!Object::cast_to<VisualShaderNodeTextureParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
|
|
if (!Object::cast_to<VisualShaderNodeTexture3DParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
|
|
if (!Object::cast_to<VisualShaderNodeTexture2DArrayParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
|
|
if (!Object::cast_to<VisualShaderNodeCubemapParameter>(this)) {
|
|
incompatible_type = true;
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
if (incompatible_type) {
|
|
return vformat(RTR("Global parameter '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), parameter_name);
|
|
}
|
|
}
|
|
|
|
return String();
|
|
}
|
|
|
|
Vector<StringName> VisualShaderNodeParameter::get_editable_properties() const {
|
|
Vector<StringName> props;
|
|
props.push_back("qualifier");
|
|
return props;
|
|
}
|
|
|
|
VisualShaderNodeParameter::VisualShaderNodeParameter() {
|
|
}
|
|
|
|
////////////// ResizeableBase
|
|
|
|
void VisualShaderNodeResizableBase::set_size(const Size2 &p_size) {
|
|
size = p_size;
|
|
}
|
|
|
|
Size2 VisualShaderNodeResizableBase::get_size() const {
|
|
return size;
|
|
}
|
|
|
|
void VisualShaderNodeResizableBase::set_allow_v_resize(bool p_enabled) {
|
|
allow_v_resize = p_enabled;
|
|
}
|
|
|
|
bool VisualShaderNodeResizableBase::is_allow_v_resize() const {
|
|
return allow_v_resize;
|
|
}
|
|
|
|
void VisualShaderNodeResizableBase::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeResizableBase::set_size);
|
|
ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeResizableBase::get_size);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
|
|
}
|
|
|
|
VisualShaderNodeResizableBase::VisualShaderNodeResizableBase() {
|
|
set_allow_v_resize(true);
|
|
}
|
|
|
|
////////////// Comment
|
|
|
|
String VisualShaderNodeComment::get_caption() const {
|
|
return title;
|
|
}
|
|
|
|
int VisualShaderNodeComment::get_input_port_count() const {
|
|
return 0;
|
|
}
|
|
|
|
VisualShaderNodeComment::PortType VisualShaderNodeComment::get_input_port_type(int p_port) const {
|
|
return PortType::PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeComment::get_input_port_name(int p_port) const {
|
|
return String();
|
|
}
|
|
|
|
int VisualShaderNodeComment::get_output_port_count() const {
|
|
return 0;
|
|
}
|
|
|
|
VisualShaderNodeComment::PortType VisualShaderNodeComment::get_output_port_type(int p_port) const {
|
|
return PortType::PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeComment::get_output_port_name(int p_port) const {
|
|
return String();
|
|
}
|
|
|
|
void VisualShaderNodeComment::set_title(const String &p_title) {
|
|
title = p_title;
|
|
}
|
|
|
|
String VisualShaderNodeComment::get_title() const {
|
|
return title;
|
|
}
|
|
|
|
void VisualShaderNodeComment::set_description(const String &p_description) {
|
|
description = p_description;
|
|
}
|
|
|
|
String VisualShaderNodeComment::get_description() const {
|
|
return description;
|
|
}
|
|
|
|
String VisualShaderNodeComment::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
return String();
|
|
}
|
|
|
|
void VisualShaderNodeComment::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_title", "title"), &VisualShaderNodeComment::set_title);
|
|
ClassDB::bind_method(D_METHOD("get_title"), &VisualShaderNodeComment::get_title);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_description", "description"), &VisualShaderNodeComment::set_description);
|
|
ClassDB::bind_method(D_METHOD("get_description"), &VisualShaderNodeComment::get_description);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_description", "get_description");
|
|
}
|
|
|
|
VisualShaderNodeComment::VisualShaderNodeComment() {
|
|
}
|
|
|
|
////////////// GroupBase
|
|
|
|
void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) {
|
|
if (inputs == p_inputs) {
|
|
return;
|
|
}
|
|
|
|
clear_input_ports();
|
|
|
|
inputs = p_inputs;
|
|
|
|
Vector<String> input_strings = inputs.split(";", false);
|
|
|
|
int input_port_count = input_strings.size();
|
|
|
|
for (int i = 0; i < input_port_count; i++) {
|
|
Vector<String> arr = input_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
int port_idx = arr[0].to_int();
|
|
int port_type = arr[1].to_int();
|
|
String port_name = arr[2];
|
|
|
|
Port port;
|
|
port.type = (PortType)port_type;
|
|
port.name = port_name;
|
|
input_ports[port_idx] = port;
|
|
}
|
|
}
|
|
|
|
String VisualShaderNodeGroupBase::get_inputs() const {
|
|
return inputs;
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::set_outputs(const String &p_outputs) {
|
|
if (outputs == p_outputs) {
|
|
return;
|
|
}
|
|
|
|
clear_output_ports();
|
|
|
|
outputs = p_outputs;
|
|
|
|
Vector<String> output_strings = outputs.split(";", false);
|
|
|
|
int output_port_count = output_strings.size();
|
|
|
|
for (int i = 0; i < output_port_count; i++) {
|
|
Vector<String> arr = output_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
int port_idx = arr[0].to_int();
|
|
int port_type = arr[1].to_int();
|
|
String port_name = arr[2];
|
|
|
|
Port port;
|
|
port.type = (PortType)port_type;
|
|
port.name = port_name;
|
|
output_ports[port_idx] = port;
|
|
}
|
|
}
|
|
|
|
String VisualShaderNodeGroupBase::get_outputs() const {
|
|
return outputs;
|
|
}
|
|
|
|
bool VisualShaderNodeGroupBase::is_valid_port_name(const String &p_name) const {
|
|
if (!p_name.is_valid_identifier()) {
|
|
return false;
|
|
}
|
|
for (int i = 0; i < get_input_port_count(); i++) {
|
|
if (get_input_port_name(i) == p_name) {
|
|
return false;
|
|
}
|
|
}
|
|
for (int i = 0; i < get_output_port_count(); i++) {
|
|
if (get_output_port_name(i) == p_name) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const String &p_name) {
|
|
ERR_FAIL_INDEX(p_type, int(PORT_TYPE_MAX));
|
|
ERR_FAIL_COND(!is_valid_port_name(p_name));
|
|
|
|
String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";";
|
|
Vector<String> inputs_strings = inputs.split(";", false);
|
|
int index = 0;
|
|
if (p_id < inputs_strings.size()) {
|
|
for (int i = 0; i < inputs_strings.size(); i++) {
|
|
if (i == p_id) {
|
|
inputs = inputs.insert(index, str);
|
|
break;
|
|
}
|
|
index += inputs_strings[i].size();
|
|
}
|
|
} else {
|
|
inputs += str;
|
|
}
|
|
|
|
inputs_strings = inputs.split(";", false);
|
|
index = 0;
|
|
|
|
for (int i = 0; i < inputs_strings.size(); i++) {
|
|
int count = 0;
|
|
for (int j = 0; j < inputs_strings[i].size(); j++) {
|
|
if (inputs_strings[i][j] == ',') {
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
|
|
inputs = inputs.left(index) + inputs.substr(index + count);
|
|
inputs = inputs.insert(index, itos(i));
|
|
index += inputs_strings[i].size();
|
|
}
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::remove_input_port(int p_id) {
|
|
ERR_FAIL_COND(!has_input_port(p_id));
|
|
|
|
Vector<String> inputs_strings = inputs.split(";", false);
|
|
int count = 0;
|
|
int index = 0;
|
|
for (int i = 0; i < inputs_strings.size(); i++) {
|
|
Vector<String> arr = inputs_strings[i].split(",");
|
|
if (arr[0].to_int() == p_id) {
|
|
count = inputs_strings[i].size();
|
|
break;
|
|
}
|
|
index += inputs_strings[i].size();
|
|
}
|
|
inputs = inputs.left(index) + inputs.substr(index + count);
|
|
|
|
inputs_strings = inputs.split(";", false);
|
|
inputs = inputs.substr(0, index);
|
|
|
|
for (int i = p_id; i < inputs_strings.size(); i++) {
|
|
inputs += inputs_strings[i].replace_first(inputs_strings[i].split(",")[0], itos(i)) + ";";
|
|
}
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
int VisualShaderNodeGroupBase::get_input_port_count() const {
|
|
return input_ports.size();
|
|
}
|
|
|
|
bool VisualShaderNodeGroupBase::has_input_port(int p_id) const {
|
|
return input_ports.has(p_id);
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const String &p_name) {
|
|
ERR_FAIL_INDEX(p_type, int(PORT_TYPE_MAX));
|
|
ERR_FAIL_COND(!is_valid_port_name(p_name));
|
|
|
|
String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";";
|
|
Vector<String> outputs_strings = outputs.split(";", false);
|
|
int index = 0;
|
|
if (p_id < outputs_strings.size()) {
|
|
for (int i = 0; i < outputs_strings.size(); i++) {
|
|
if (i == p_id) {
|
|
outputs = outputs.insert(index, str);
|
|
break;
|
|
}
|
|
index += outputs_strings[i].size();
|
|
}
|
|
} else {
|
|
outputs += str;
|
|
}
|
|
|
|
outputs_strings = outputs.split(";", false);
|
|
index = 0;
|
|
|
|
for (int i = 0; i < outputs_strings.size(); i++) {
|
|
int count = 0;
|
|
for (int j = 0; j < outputs_strings[i].size(); j++) {
|
|
if (outputs_strings[i][j] == ',') {
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
|
|
outputs = outputs.left(index) + outputs.substr(index + count);
|
|
outputs = outputs.insert(index, itos(i));
|
|
index += outputs_strings[i].size();
|
|
}
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::remove_output_port(int p_id) {
|
|
ERR_FAIL_COND(!has_output_port(p_id));
|
|
|
|
Vector<String> outputs_strings = outputs.split(";", false);
|
|
int count = 0;
|
|
int index = 0;
|
|
for (int i = 0; i < outputs_strings.size(); i++) {
|
|
Vector<String> arr = outputs_strings[i].split(",");
|
|
if (arr[0].to_int() == p_id) {
|
|
count = outputs_strings[i].size();
|
|
break;
|
|
}
|
|
index += outputs_strings[i].size();
|
|
}
|
|
outputs = outputs.left(index) + outputs.substr(index + count);
|
|
|
|
outputs_strings = outputs.split(";", false);
|
|
outputs = outputs.substr(0, index);
|
|
|
|
for (int i = p_id; i < outputs_strings.size(); i++) {
|
|
outputs += outputs_strings[i].replace_first(outputs_strings[i].split(",")[0], itos(i)) + ";";
|
|
}
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
int VisualShaderNodeGroupBase::get_output_port_count() const {
|
|
return output_ports.size();
|
|
}
|
|
|
|
bool VisualShaderNodeGroupBase::has_output_port(int p_id) const {
|
|
return output_ports.has(p_id);
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::clear_input_ports() {
|
|
input_ports.clear();
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::clear_output_ports() {
|
|
output_ports.clear();
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) {
|
|
ERR_FAIL_COND(!has_input_port(p_id));
|
|
ERR_FAIL_INDEX(p_type, int(PORT_TYPE_MAX));
|
|
|
|
if (input_ports[p_id].type == p_type) {
|
|
return;
|
|
}
|
|
|
|
Vector<String> inputs_strings = inputs.split(";", false);
|
|
int count = 0;
|
|
int index = 0;
|
|
for (int i = 0; i < inputs_strings.size(); i++) {
|
|
Vector<String> arr = inputs_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
if (arr[0].to_int() == p_id) {
|
|
index += arr[0].size();
|
|
count = arr[1].size() - 1;
|
|
break;
|
|
}
|
|
index += inputs_strings[i].size();
|
|
}
|
|
|
|
inputs = inputs.left(index) + inputs.substr(index + count);
|
|
inputs = inputs.insert(index, itos(p_type));
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_input_port_type(int p_id) const {
|
|
ERR_FAIL_COND_V(!input_ports.has(p_id), (PortType)0);
|
|
return input_ports[p_id].type;
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::set_input_port_name(int p_id, const String &p_name) {
|
|
ERR_FAIL_COND(!has_input_port(p_id));
|
|
ERR_FAIL_COND(!is_valid_port_name(p_name));
|
|
|
|
if (input_ports[p_id].name == p_name) {
|
|
return;
|
|
}
|
|
|
|
Vector<String> inputs_strings = inputs.split(";", false);
|
|
int count = 0;
|
|
int index = 0;
|
|
for (int i = 0; i < inputs_strings.size(); i++) {
|
|
Vector<String> arr = inputs_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
if (arr[0].to_int() == p_id) {
|
|
index += arr[0].size() + arr[1].size();
|
|
count = arr[2].size() - 1;
|
|
break;
|
|
}
|
|
index += inputs_strings[i].size();
|
|
}
|
|
|
|
inputs = inputs.left(index) + inputs.substr(index + count);
|
|
inputs = inputs.insert(index, p_name);
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const {
|
|
ERR_FAIL_COND_V(!input_ports.has(p_id), "");
|
|
return input_ports[p_id].name;
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) {
|
|
ERR_FAIL_COND(!has_output_port(p_id));
|
|
ERR_FAIL_INDEX(p_type, int(PORT_TYPE_MAX));
|
|
|
|
if (output_ports[p_id].type == p_type) {
|
|
return;
|
|
}
|
|
|
|
Vector<String> output_strings = outputs.split(";", false);
|
|
int count = 0;
|
|
int index = 0;
|
|
for (int i = 0; i < output_strings.size(); i++) {
|
|
Vector<String> arr = output_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
if (arr[0].to_int() == p_id) {
|
|
index += arr[0].size();
|
|
count = arr[1].size() - 1;
|
|
break;
|
|
}
|
|
index += output_strings[i].size();
|
|
}
|
|
|
|
outputs = outputs.left(index) + outputs.substr(index + count);
|
|
|
|
outputs = outputs.insert(index, itos(p_type));
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_output_port_type(int p_id) const {
|
|
ERR_FAIL_COND_V(!output_ports.has(p_id), (PortType)0);
|
|
return output_ports[p_id].type;
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::set_output_port_name(int p_id, const String &p_name) {
|
|
ERR_FAIL_COND(!has_output_port(p_id));
|
|
ERR_FAIL_COND(!is_valid_port_name(p_name));
|
|
|
|
if (output_ports[p_id].name == p_name) {
|
|
return;
|
|
}
|
|
|
|
Vector<String> output_strings = outputs.split(";", false);
|
|
int count = 0;
|
|
int index = 0;
|
|
for (int i = 0; i < output_strings.size(); i++) {
|
|
Vector<String> arr = output_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
if (arr[0].to_int() == p_id) {
|
|
index += arr[0].size() + arr[1].size();
|
|
count = arr[2].size() - 1;
|
|
break;
|
|
}
|
|
index += output_strings[i].size();
|
|
}
|
|
|
|
outputs = outputs.left(index) + outputs.substr(index + count);
|
|
|
|
outputs = outputs.insert(index, p_name);
|
|
|
|
_apply_port_changes();
|
|
emit_changed();
|
|
}
|
|
|
|
String VisualShaderNodeGroupBase::get_output_port_name(int p_id) const {
|
|
ERR_FAIL_COND_V(!output_ports.has(p_id), "");
|
|
return output_ports[p_id].name;
|
|
}
|
|
|
|
int VisualShaderNodeGroupBase::get_free_input_port_id() const {
|
|
return input_ports.size();
|
|
}
|
|
|
|
int VisualShaderNodeGroupBase::get_free_output_port_id() const {
|
|
return output_ports.size();
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::set_ctrl_pressed(Control *p_control, int p_index) {
|
|
controls[p_index] = p_control;
|
|
}
|
|
|
|
Control *VisualShaderNodeGroupBase::is_ctrl_pressed(int p_index) {
|
|
ERR_FAIL_COND_V(!controls.has(p_index), nullptr);
|
|
return controls[p_index];
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::_apply_port_changes() {
|
|
Vector<String> inputs_strings = inputs.split(";", false);
|
|
Vector<String> outputs_strings = outputs.split(";", false);
|
|
|
|
clear_input_ports();
|
|
clear_output_ports();
|
|
|
|
for (int i = 0; i < inputs_strings.size(); i++) {
|
|
Vector<String> arr = inputs_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
Port port;
|
|
port.type = (PortType)arr[1].to_int();
|
|
port.name = arr[2];
|
|
input_ports[i] = port;
|
|
}
|
|
for (int i = 0; i < outputs_strings.size(); i++) {
|
|
Vector<String> arr = outputs_strings[i].split(",");
|
|
ERR_FAIL_COND(arr.size() != 3);
|
|
|
|
Port port;
|
|
port.type = (PortType)arr[1].to_int();
|
|
port.name = arr[2];
|
|
output_ports[i] = port;
|
|
}
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::set_editable(bool p_enabled) {
|
|
editable = p_enabled;
|
|
}
|
|
|
|
bool VisualShaderNodeGroupBase::is_editable() const {
|
|
return editable;
|
|
}
|
|
|
|
void VisualShaderNodeGroupBase::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_inputs", "inputs"), &VisualShaderNodeGroupBase::set_inputs);
|
|
ClassDB::bind_method(D_METHOD("get_inputs"), &VisualShaderNodeGroupBase::get_inputs);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_outputs", "outputs"), &VisualShaderNodeGroupBase::set_outputs);
|
|
ClassDB::bind_method(D_METHOD("get_outputs"), &VisualShaderNodeGroupBase::get_outputs);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_valid_port_name", "name"), &VisualShaderNodeGroupBase::is_valid_port_name);
|
|
|
|
ClassDB::bind_method(D_METHOD("add_input_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_input_port);
|
|
ClassDB::bind_method(D_METHOD("remove_input_port", "id"), &VisualShaderNodeGroupBase::remove_input_port);
|
|
ClassDB::bind_method(D_METHOD("get_input_port_count"), &VisualShaderNodeGroupBase::get_input_port_count);
|
|
ClassDB::bind_method(D_METHOD("has_input_port", "id"), &VisualShaderNodeGroupBase::has_input_port);
|
|
ClassDB::bind_method(D_METHOD("clear_input_ports"), &VisualShaderNodeGroupBase::clear_input_ports);
|
|
|
|
ClassDB::bind_method(D_METHOD("add_output_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_output_port);
|
|
ClassDB::bind_method(D_METHOD("remove_output_port", "id"), &VisualShaderNodeGroupBase::remove_output_port);
|
|
ClassDB::bind_method(D_METHOD("get_output_port_count"), &VisualShaderNodeGroupBase::get_output_port_count);
|
|
ClassDB::bind_method(D_METHOD("has_output_port", "id"), &VisualShaderNodeGroupBase::has_output_port);
|
|
ClassDB::bind_method(D_METHOD("clear_output_ports"), &VisualShaderNodeGroupBase::clear_output_ports);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_input_port_name", "id", "name"), &VisualShaderNodeGroupBase::set_input_port_name);
|
|
ClassDB::bind_method(D_METHOD("set_input_port_type", "id", "type"), &VisualShaderNodeGroupBase::set_input_port_type);
|
|
ClassDB::bind_method(D_METHOD("set_output_port_name", "id", "name"), &VisualShaderNodeGroupBase::set_output_port_name);
|
|
ClassDB::bind_method(D_METHOD("set_output_port_type", "id", "type"), &VisualShaderNodeGroupBase::set_output_port_type);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_free_input_port_id"), &VisualShaderNodeGroupBase::get_free_input_port_id);
|
|
ClassDB::bind_method(D_METHOD("get_free_output_port_id"), &VisualShaderNodeGroupBase::get_free_output_port_id);
|
|
}
|
|
|
|
String VisualShaderNodeGroupBase::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
return "";
|
|
}
|
|
|
|
VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() {
|
|
simple_decl = false;
|
|
}
|
|
|
|
////////////// Expression
|
|
|
|
String VisualShaderNodeExpression::get_caption() const {
|
|
return "Expression";
|
|
}
|
|
|
|
void VisualShaderNodeExpression::set_expression(const String &p_expression) {
|
|
expression = p_expression;
|
|
emit_changed();
|
|
}
|
|
|
|
String VisualShaderNodeExpression::get_expression() const {
|
|
return expression;
|
|
}
|
|
|
|
String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
String _expression = expression;
|
|
|
|
_expression = _expression.insert(0, "\n");
|
|
_expression = _expression.replace("\n", "\n ");
|
|
|
|
static Vector<String> pre_symbols;
|
|
if (pre_symbols.is_empty()) {
|
|
pre_symbols.push_back(" ");
|
|
pre_symbols.push_back(",");
|
|
pre_symbols.push_back(";");
|
|
pre_symbols.push_back("{");
|
|
pre_symbols.push_back("[");
|
|
pre_symbols.push_back("]");
|
|
pre_symbols.push_back("(");
|
|
pre_symbols.push_back(" ");
|
|
pre_symbols.push_back("-");
|
|
pre_symbols.push_back("*");
|
|
pre_symbols.push_back("/");
|
|
pre_symbols.push_back("+");
|
|
pre_symbols.push_back("=");
|
|
pre_symbols.push_back("&");
|
|
pre_symbols.push_back("|");
|
|
pre_symbols.push_back("!");
|
|
}
|
|
|
|
static Vector<String> post_symbols;
|
|
if (post_symbols.is_empty()) {
|
|
post_symbols.push_back(" ");
|
|
post_symbols.push_back("\n");
|
|
post_symbols.push_back(",");
|
|
post_symbols.push_back(";");
|
|
post_symbols.push_back("}");
|
|
post_symbols.push_back("[");
|
|
post_symbols.push_back("]");
|
|
post_symbols.push_back(")");
|
|
post_symbols.push_back(" ");
|
|
post_symbols.push_back(".");
|
|
post_symbols.push_back("-");
|
|
post_symbols.push_back("*");
|
|
post_symbols.push_back("/");
|
|
post_symbols.push_back("+");
|
|
post_symbols.push_back("=");
|
|
post_symbols.push_back("&");
|
|
post_symbols.push_back("|");
|
|
post_symbols.push_back("!");
|
|
}
|
|
|
|
for (int i = 0; i < get_input_port_count(); i++) {
|
|
for (int j = 0; j < pre_symbols.size(); j++) {
|
|
for (int k = 0; k < post_symbols.size(); k++) {
|
|
_expression = _expression.replace(pre_symbols[j] + get_input_port_name(i) + post_symbols[k], pre_symbols[j] + p_input_vars[i] + post_symbols[k]);
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < get_output_port_count(); i++) {
|
|
for (int j = 0; j < pre_symbols.size(); j++) {
|
|
for (int k = 0; k < post_symbols.size(); k++) {
|
|
_expression = _expression.replace(pre_symbols[j] + get_output_port_name(i) + post_symbols[k], pre_symbols[j] + p_output_vars[i] + post_symbols[k]);
|
|
}
|
|
}
|
|
}
|
|
|
|
String output_initializer;
|
|
|
|
for (int i = 0; i < get_output_port_count(); i++) {
|
|
int port_type = get_output_port_type(i);
|
|
String tk = "";
|
|
switch (port_type) {
|
|
case PORT_TYPE_SCALAR:
|
|
tk = "0.0";
|
|
break;
|
|
case PORT_TYPE_SCALAR_INT:
|
|
tk = "0";
|
|
break;
|
|
case PORT_TYPE_VECTOR_2D:
|
|
tk = "vec2(0.0, 0.0)";
|
|
break;
|
|
case PORT_TYPE_VECTOR_3D:
|
|
tk = "vec3(0.0, 0.0, 0.0)";
|
|
break;
|
|
case PORT_TYPE_VECTOR_4D:
|
|
tk = "vec4(0.0, 0.0, 0.0, 0.0)";
|
|
break;
|
|
case PORT_TYPE_BOOLEAN:
|
|
tk = "false";
|
|
break;
|
|
case PORT_TYPE_TRANSFORM:
|
|
tk = "mat4(1.0)";
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
output_initializer += " " + p_output_vars[i] + " = " + tk + ";\n";
|
|
}
|
|
|
|
String code;
|
|
code += output_initializer;
|
|
code += " {";
|
|
code += _expression;
|
|
code += "\n }\n";
|
|
|
|
return code;
|
|
}
|
|
|
|
void VisualShaderNodeExpression::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_expression", "expression"), &VisualShaderNodeExpression::set_expression);
|
|
ClassDB::bind_method(D_METHOD("get_expression"), &VisualShaderNodeExpression::get_expression);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "expression"), "set_expression", "get_expression");
|
|
}
|
|
|
|
VisualShaderNodeExpression::VisualShaderNodeExpression() {
|
|
set_editable(true);
|
|
}
|
|
|
|
////////////// Global Expression
|
|
|
|
String VisualShaderNodeGlobalExpression::get_caption() const {
|
|
return "GlobalExpression";
|
|
}
|
|
|
|
String VisualShaderNodeGlobalExpression::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
|
|
return expression;
|
|
}
|
|
|
|
VisualShaderNodeGlobalExpression::VisualShaderNodeGlobalExpression() {
|
|
set_editable(false);
|
|
}
|
|
|
|
////////////// Varying
|
|
|
|
List<VisualShaderNodeVarying::Varying> varyings;
|
|
|
|
void VisualShaderNodeVarying::add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) { // static
|
|
varyings.push_back({ p_name, p_mode, p_type });
|
|
}
|
|
|
|
void VisualShaderNodeVarying::clear_varyings() { // static
|
|
varyings.clear();
|
|
}
|
|
|
|
bool VisualShaderNodeVarying::has_varying(const String &p_name) { // static
|
|
for (const VisualShaderNodeVarying::Varying &E : varyings) {
|
|
if (E.name == p_name) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int VisualShaderNodeVarying::get_varyings_count() const {
|
|
return varyings.size();
|
|
}
|
|
|
|
String VisualShaderNodeVarying::get_varying_name_by_index(int p_idx) const {
|
|
if (p_idx >= 0 && p_idx < varyings.size()) {
|
|
return varyings[p_idx].name;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_name(const String &p_name) const {
|
|
for (int i = 0; i < varyings.size(); i++) {
|
|
if (varyings[i].name == p_name) {
|
|
return varyings[i].type;
|
|
}
|
|
}
|
|
return VisualShader::VARYING_TYPE_FLOAT;
|
|
}
|
|
|
|
VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_index(int p_idx) const {
|
|
if (p_idx >= 0 && p_idx < varyings.size()) {
|
|
return varyings[p_idx].type;
|
|
}
|
|
return VisualShader::VARYING_TYPE_FLOAT;
|
|
}
|
|
|
|
VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_name(const String &p_name) const {
|
|
for (int i = 0; i < varyings.size(); i++) {
|
|
if (varyings[i].name == p_name) {
|
|
return varyings[i].mode;
|
|
}
|
|
}
|
|
return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT;
|
|
}
|
|
|
|
VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_index(int p_idx) const {
|
|
if (p_idx >= 0 && p_idx < varyings.size()) {
|
|
return varyings[p_idx].mode;
|
|
}
|
|
return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT;
|
|
}
|
|
|
|
VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type_by_index(int p_idx) const {
|
|
if (p_idx >= 0 && p_idx < varyings.size()) {
|
|
return get_port_type(varyings[p_idx].type, 0);
|
|
}
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
//////////////
|
|
|
|
void VisualShaderNodeVarying::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_varying_name", "name"), &VisualShaderNodeVarying::set_varying_name);
|
|
ClassDB::bind_method(D_METHOD("get_varying_name"), &VisualShaderNodeVarying::get_varying_name);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_varying_type", "type"), &VisualShaderNodeVarying::set_varying_type);
|
|
ClassDB::bind_method(D_METHOD("get_varying_type"), &VisualShaderNodeVarying::get_varying_type);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "varying_name"), "set_varying_name", "get_varying_name");
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Vector4,Boolean,Transform"), "set_varying_type", "get_varying_type");
|
|
}
|
|
|
|
String VisualShaderNodeVarying::get_type_str() const {
|
|
switch (varying_type) {
|
|
case VisualShader::VARYING_TYPE_FLOAT:
|
|
return "float";
|
|
case VisualShader::VARYING_TYPE_INT:
|
|
return "int";
|
|
case VisualShader::VARYING_TYPE_VECTOR_2D:
|
|
return "vec2";
|
|
case VisualShader::VARYING_TYPE_VECTOR_3D:
|
|
return "vec3";
|
|
case VisualShader::VARYING_TYPE_VECTOR_4D:
|
|
return "vec4";
|
|
case VisualShader::VARYING_TYPE_BOOLEAN:
|
|
return "bool";
|
|
case VisualShader::VARYING_TYPE_TRANSFORM:
|
|
return "mat4";
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type(VisualShader::VaryingType p_type, int p_port) const {
|
|
switch (p_type) {
|
|
case VisualShader::VARYING_TYPE_INT:
|
|
return PORT_TYPE_SCALAR_INT;
|
|
case VisualShader::VARYING_TYPE_VECTOR_2D:
|
|
return PORT_TYPE_VECTOR_2D;
|
|
case VisualShader::VARYING_TYPE_VECTOR_3D:
|
|
return PORT_TYPE_VECTOR_3D;
|
|
case VisualShader::VARYING_TYPE_VECTOR_4D:
|
|
return PORT_TYPE_VECTOR_4D;
|
|
case VisualShader::VARYING_TYPE_BOOLEAN:
|
|
return PORT_TYPE_BOOLEAN;
|
|
case VisualShader::VARYING_TYPE_TRANSFORM:
|
|
return PORT_TYPE_TRANSFORM;
|
|
default:
|
|
break;
|
|
}
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
void VisualShaderNodeVarying::set_varying_name(String p_varying_name) {
|
|
if (varying_name == p_varying_name) {
|
|
return;
|
|
}
|
|
varying_name = p_varying_name;
|
|
emit_changed();
|
|
}
|
|
|
|
String VisualShaderNodeVarying::get_varying_name() const {
|
|
return varying_name;
|
|
}
|
|
|
|
void VisualShaderNodeVarying::set_varying_type(VisualShader::VaryingType p_varying_type) {
|
|
ERR_FAIL_INDEX(p_varying_type, VisualShader::VARYING_TYPE_MAX);
|
|
if (varying_type == p_varying_type) {
|
|
return;
|
|
}
|
|
varying_type = p_varying_type;
|
|
emit_changed();
|
|
}
|
|
|
|
VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type() const {
|
|
return varying_type;
|
|
}
|
|
|
|
VisualShaderNodeVarying::VisualShaderNodeVarying() {
|
|
}
|
|
|
|
////////////// Varying Setter
|
|
|
|
String VisualShaderNodeVaryingSetter::get_caption() const {
|
|
return vformat("VaryingSetter");
|
|
}
|
|
|
|
int VisualShaderNodeVaryingSetter::get_input_port_count() const {
|
|
return 1;
|
|
}
|
|
|
|
VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_input_port_type(int p_port) const {
|
|
return get_port_type(varying_type, p_port);
|
|
}
|
|
|
|
String VisualShaderNodeVaryingSetter::get_input_port_name(int p_port) const {
|
|
return "";
|
|
}
|
|
|
|
int VisualShaderNodeVaryingSetter::get_output_port_count() const {
|
|
return 0;
|
|
}
|
|
|
|
VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_output_port_type(int p_port) const {
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeVaryingSetter::get_output_port_name(int p_port) const {
|
|
return "";
|
|
}
|
|
|
|
String VisualShaderNodeVaryingSetter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
String code;
|
|
if (varying_name == "[None]") {
|
|
return code;
|
|
}
|
|
code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]);
|
|
return code;
|
|
}
|
|
|
|
VisualShaderNodeVaryingSetter::VisualShaderNodeVaryingSetter() {
|
|
}
|
|
|
|
////////////// Varying Getter
|
|
|
|
String VisualShaderNodeVaryingGetter::get_caption() const {
|
|
return vformat("VaryingGetter");
|
|
}
|
|
|
|
int VisualShaderNodeVaryingGetter::get_input_port_count() const {
|
|
return 0;
|
|
}
|
|
|
|
VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_input_port_type(int p_port) const {
|
|
return PORT_TYPE_SCALAR;
|
|
}
|
|
|
|
String VisualShaderNodeVaryingGetter::get_input_port_name(int p_port) const {
|
|
return "";
|
|
}
|
|
|
|
int VisualShaderNodeVaryingGetter::get_output_port_count() const {
|
|
return 1;
|
|
}
|
|
|
|
VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_output_port_type(int p_port) const {
|
|
return get_port_type(varying_type, p_port);
|
|
}
|
|
|
|
String VisualShaderNodeVaryingGetter::get_output_port_name(int p_port) const {
|
|
return "";
|
|
}
|
|
|
|
bool VisualShaderNodeVaryingGetter::has_output_port_preview(int p_port) const {
|
|
return false;
|
|
}
|
|
|
|
String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
|
String from = varying_name;
|
|
String from2;
|
|
|
|
if (varying_name == "[None]") {
|
|
switch (varying_type) {
|
|
case VisualShader::VARYING_TYPE_FLOAT:
|
|
from = "0.0";
|
|
break;
|
|
case VisualShader::VARYING_TYPE_INT:
|
|
from = "0";
|
|
break;
|
|
case VisualShader::VARYING_TYPE_VECTOR_2D:
|
|
from = "vec2(0.0)";
|
|
break;
|
|
case VisualShader::VARYING_TYPE_VECTOR_3D:
|
|
from = "vec3(0.0)";
|
|
break;
|
|
case VisualShader::VARYING_TYPE_VECTOR_4D:
|
|
from = "vec4(0.0)";
|
|
break;
|
|
case VisualShader::VARYING_TYPE_BOOLEAN:
|
|
from = "false";
|
|
break;
|
|
case VisualShader::VARYING_TYPE_TRANSFORM:
|
|
from = "mat4(1.0)";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return vformat(" %s = %s;\n", p_output_vars[0], from);
|
|
}
|
|
|
|
VisualShaderNodeVaryingGetter::VisualShaderNodeVaryingGetter() {
|
|
varying_name = "[None]";
|
|
}
|