/*************************************************************************/ /* shader_graph.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 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 "shader_graph.h" #include "scene/scene_string_names.h" Array ShaderGraph::_get_node_list(ShaderType p_type) const { List nodes; get_node_list(p_type, &nodes); Array arr(true); for (List::Element *E = nodes.front(); E; E = E->next()) arr.push_back(E->get()); return arr; } Array ShaderGraph::_get_connections(ShaderType p_type) const { List connections; get_node_connections(p_type, &connections); Array arr(true); for (List::Element *E = connections.front(); E; E = E->next()) { Dictionary d(true); d["src_id"] = E->get().src_id; d["src_slot"] = E->get().src_slot; d["dst_id"] = E->get().dst_id; d["dst_slot"] = E->get().dst_slot; arr.push_back(d); } return arr; } void ShaderGraph::_set_data(const Dictionary &p_data) { Dictionary d = p_data; ERR_FAIL_COND(!d.has("shaders")); Array sh = d["shaders"]; ERR_FAIL_COND(sh.size() != 3); for (int t = 0; t < 3; t++) { Array data = sh[t]; ERR_FAIL_COND((data.size() % 6) != 0); shader[t].node_map.clear(); for (int i = 0; i < data.size(); i += 6) { Node n; n.id = data[i + 0]; n.type = NodeType(int(data[i + 1])); n.pos = data[i + 2]; n.param1 = data[i + 3]; n.param2 = data[i + 4]; Array conns = data[i + 5]; ERR_FAIL_COND((conns.size() % 3) != 0); for (int j = 0; j < conns.size(); j += 3) { SourceSlot ss; int ls = conns[j + 0]; if (ls == SLOT_DEFAULT_VALUE) { n.defaults[conns[j + 1]] = conns[j + 2]; } else { ss.id = conns[j + 1]; ss.slot = conns[j + 2]; n.connections[ls] = ss; } } shader[t].node_map[n.id] = n; } } _pending_update_shader = true; _update_shader(); } Dictionary ShaderGraph::_get_data() const { Array sh; for (int i = 0; i < 3; i++) { Array data; int ec = shader[i].node_map.size(); data.resize(ec * 6); int idx = 0; for (Map::Element *E = shader[i].node_map.front(); E; E = E->next()) { data[idx + 0] = E->key(); data[idx + 1] = E->get().type; data[idx + 2] = E->get().pos; data[idx + 3] = E->get().param1; data[idx + 4] = E->get().param2; Array conns; conns.resize(E->get().connections.size() * 3 + E->get().defaults.size() * 3); int idx2 = 0; for (Map::Element *F = E->get().connections.front(); F; F = F->next()) { conns[idx2 + 0] = F->key(); conns[idx2 + 1] = F->get().id; conns[idx2 + 2] = F->get().slot; idx2 += 3; } for (Map::Element *F = E->get().defaults.front(); F; F = F->next()) { conns[idx2 + 0] = SLOT_DEFAULT_VALUE; conns[idx2 + 1] = F->key(); conns[idx2 + 2] = F->get(); idx2 += 3; } data[idx + 5] = conns; idx += 6; } sh.push_back(data); } Dictionary data; data["shaders"] = sh; return data; } ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const { ERR_FAIL_INDEX_V(p_type, 3, GRAPH_OK); return shader[p_type].error; } int ShaderGraph::node_count(ShaderType p_which, int p_type) { int count = 0; for (Map::Element *E = shader[p_which].node_map.front(); E; E = E->next()) if (E->get().type == p_type) count++; return count; } void ShaderGraph::_bind_methods() { ObjectTypeDB::bind_method(_MD("_update_shader"), &ShaderGraph::_update_shader); ObjectTypeDB::bind_method(_MD("node_add", "shader_type", "node_type", "id"), &ShaderGraph::node_add); ObjectTypeDB::bind_method(_MD("node_remove", "shader_type", "id"), &ShaderGraph::node_remove); ObjectTypeDB::bind_method(_MD("node_set_pos", "shader_type", "id", "pos"), &ShaderGraph::node_set_pos); ObjectTypeDB::bind_method(_MD("node_get_pos", "shader_type", "id"), &ShaderGraph::node_get_pos); ObjectTypeDB::bind_method(_MD("node_get_type", "shader_type", "id"), &ShaderGraph::node_get_type); ObjectTypeDB::bind_method(_MD("get_node_list", "shader_type"), &ShaderGraph::_get_node_list); ObjectTypeDB::bind_method(_MD("default_set_value", "shader_type", "id", "param_id", "value"), &ShaderGraph::default_set_value); ObjectTypeDB::bind_method(_MD("default_get_value", "shader_type", "id", "param_id"), &ShaderGraph::default_get_value); ObjectTypeDB::bind_method(_MD("scalar_const_node_set_value", "shader_type", "id", "value"), &ShaderGraph::scalar_const_node_set_value); ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value", "shader_type", "id"), &ShaderGraph::scalar_const_node_get_value); ObjectTypeDB::bind_method(_MD("vec_const_node_set_value", "shader_type", "id", "value"), &ShaderGraph::vec_const_node_set_value); ObjectTypeDB::bind_method(_MD("vec_const_node_get_value", "shader_type", "id"), &ShaderGraph::vec_const_node_get_value); ObjectTypeDB::bind_method(_MD("rgb_const_node_set_value", "shader_type", "id", "value"), &ShaderGraph::rgb_const_node_set_value); ObjectTypeDB::bind_method(_MD("rgb_const_node_get_value", "shader_type", "id"), &ShaderGraph::rgb_const_node_get_value); ObjectTypeDB::bind_method(_MD("xform_const_node_set_value", "shader_type", "id", "value"), &ShaderGraph::xform_const_node_set_value); ObjectTypeDB::bind_method(_MD("xform_const_node_get_value", "shader_type", "id"), &ShaderGraph::xform_const_node_get_value); // void get_node_list(ShaderType p_which,List *p_node_list) const; ObjectTypeDB::bind_method(_MD("texture_node_set_filter_size", "shader_type", "id", "filter_size"), &ShaderGraph::texture_node_set_filter_size); ObjectTypeDB::bind_method(_MD("texture_node_get_filter_size", "shader_type", "id"), &ShaderGraph::texture_node_get_filter_size); ObjectTypeDB::bind_method(_MD("texture_node_set_filter_strength", "shader_type", "id", "filter_strength"), &ShaderGraph::texture_node_set_filter_strength); ObjectTypeDB::bind_method(_MD("texture_node_get_filter_strength", "shader_type", "id"), &ShaderGraph::texture_node_get_filter_strength); ObjectTypeDB::bind_method(_MD("scalar_op_node_set_op", "shader_type", "id", "op"), &ShaderGraph::scalar_op_node_set_op); ObjectTypeDB::bind_method(_MD("scalar_op_node_get_op", "shader_type", "id"), &ShaderGraph::scalar_op_node_get_op); ObjectTypeDB::bind_method(_MD("vec_op_node_set_op", "shader_type", "id", "op"), &ShaderGraph::vec_op_node_set_op); ObjectTypeDB::bind_method(_MD("vec_op_node_get_op", "shader_type", "id"), &ShaderGraph::vec_op_node_get_op); ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_set_op", "shader_type", "id", "op"), &ShaderGraph::vec_scalar_op_node_set_op); ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_get_op", "shader_type", "id"), &ShaderGraph::vec_scalar_op_node_get_op); ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op", "shader_type", "id", "op"), &ShaderGraph::rgb_op_node_set_op); ObjectTypeDB::bind_method(_MD("rgb_op_node_get_op", "shader_type", "id"), &ShaderGraph::rgb_op_node_get_op); ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_set_no_translation", "shader_type", "id", "disable"), &ShaderGraph::xform_vec_mult_node_set_no_translation); ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_get_no_translation", "shader_type", "id"), &ShaderGraph::xform_vec_mult_node_get_no_translation); ObjectTypeDB::bind_method(_MD("scalar_func_node_set_function", "shader_type", "id", "func"), &ShaderGraph::scalar_func_node_set_function); ObjectTypeDB::bind_method(_MD("scalar_func_node_get_function", "shader_type", "id"), &ShaderGraph::scalar_func_node_get_function); ObjectTypeDB::bind_method(_MD("vec_func_node_set_function", "shader_type", "id", "func"), &ShaderGraph::vec_func_node_set_function); ObjectTypeDB::bind_method(_MD("vec_func_node_get_function", "shader_type", "id"), &ShaderGraph::vec_func_node_get_function); ObjectTypeDB::bind_method(_MD("input_node_set_name", "shader_type", "id", "name"), &ShaderGraph::input_node_set_name); ObjectTypeDB::bind_method(_MD("input_node_get_name", "shader_type", "id"), &ShaderGraph::input_node_get_name); ObjectTypeDB::bind_method(_MD("scalar_input_node_set_value", "shader_type", "id", "value"), &ShaderGraph::scalar_input_node_set_value); ObjectTypeDB::bind_method(_MD("scalar_input_node_get_value", "shader_type", "id"), &ShaderGraph::scalar_input_node_get_value); ObjectTypeDB::bind_method(_MD("vec_input_node_set_value", "shader_type", "id", "value"), &ShaderGraph::vec_input_node_set_value); ObjectTypeDB::bind_method(_MD("vec_input_node_get_value", "shader_type", "id"), &ShaderGraph::vec_input_node_get_value); ObjectTypeDB::bind_method(_MD("rgb_input_node_set_value", "shader_type", "id", "value"), &ShaderGraph::rgb_input_node_set_value); ObjectTypeDB::bind_method(_MD("rgb_input_node_get_value", "shader_type", "id"), &ShaderGraph::rgb_input_node_get_value); ObjectTypeDB::bind_method(_MD("xform_input_node_set_value", "shader_type", "id", "value"), &ShaderGraph::xform_input_node_set_value); ObjectTypeDB::bind_method(_MD("xform_input_node_get_value", "shader_type", "id"), &ShaderGraph::xform_input_node_get_value); ObjectTypeDB::bind_method(_MD("texture_input_node_set_value", "shader_type", "id", "value:Texture"), &ShaderGraph::texture_input_node_set_value); ObjectTypeDB::bind_method(_MD("texture_input_node_get_value:Texture", "shader_type", "id"), &ShaderGraph::texture_input_node_get_value); ObjectTypeDB::bind_method(_MD("cubemap_input_node_set_value", "shader_type", "id", "value:CubeMap"), &ShaderGraph::cubemap_input_node_set_value); ObjectTypeDB::bind_method(_MD("cubemap_input_node_get_value:CubeMap", "shader_type", "id"), &ShaderGraph::cubemap_input_node_get_value); ObjectTypeDB::bind_method(_MD("comment_node_set_text", "shader_type", "id", "text"), &ShaderGraph::comment_node_set_text); ObjectTypeDB::bind_method(_MD("comment_node_get_text", "shader_type", "id"), &ShaderGraph::comment_node_get_text); ObjectTypeDB::bind_method(_MD("color_ramp_node_set_ramp", "shader_type", "id", "colors", "offsets"), &ShaderGraph::color_ramp_node_set_ramp); ObjectTypeDB::bind_method(_MD("color_ramp_node_get_colors", "shader_type", "id"), &ShaderGraph::color_ramp_node_get_colors); ObjectTypeDB::bind_method(_MD("color_ramp_node_get_offsets", "shader_type", "id"), &ShaderGraph::color_ramp_node_get_offsets); ObjectTypeDB::bind_method(_MD("curve_map_node_set_points", "shader_type", "id", "points"), &ShaderGraph::curve_map_node_set_points); ObjectTypeDB::bind_method(_MD("curve_map_node_get_points", "shader_type", "id"), &ShaderGraph::curve_map_node_get_points); ObjectTypeDB::bind_method(_MD("connect_node:Error", "shader_type", "src_id", "src_slot", "dst_id", "dst_slot"), &ShaderGraph::connect_node); ObjectTypeDB::bind_method(_MD("is_node_connected", "shader_type", "src_id", "src_slot", "dst_id", "dst_slot"), &ShaderGraph::is_node_connected); ObjectTypeDB::bind_method(_MD("disconnect_node", "shader_type", "src_id", "src_slot", "dst_id", "dst_slot"), &ShaderGraph::disconnect_node); ObjectTypeDB::bind_method(_MD("get_node_connections", "shader_type"), &ShaderGraph::_get_connections); ObjectTypeDB::bind_method(_MD("clear", "shader_type"), &ShaderGraph::clear); ObjectTypeDB::bind_method(_MD("node_set_state", "shader_type", "id", "state"), &ShaderGraph::node_set_state); ObjectTypeDB::bind_method(_MD("node_get_state:Variant", "shader_type", "id"), &ShaderGraph::node_get_state); ObjectTypeDB::bind_method(_MD("_set_data"), &ShaderGraph::_set_data); ObjectTypeDB::bind_method(_MD("_get_data"), &ShaderGraph::_get_data); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"), _SCS("_get_data")); //void get_connections(ShaderType p_which,List *p_connections) const; BIND_CONSTANT(NODE_INPUT); // all inputs (shader type dependent) BIND_CONSTANT(NODE_SCALAR_CONST); //scalar constant BIND_CONSTANT(NODE_VEC_CONST); //vec3 constant BIND_CONSTANT(NODE_RGB_CONST); //rgb constant (shows a color picker instead) BIND_CONSTANT(NODE_XFORM_CONST); // 4x4 matrix constant BIND_CONSTANT(NODE_TIME); // time in seconds BIND_CONSTANT(NODE_SCREEN_TEX); // screen texture sampler (takes UV) (only usable in fragment shader) BIND_CONSTANT(NODE_SCALAR_OP); // scalar vs scalar op (mul ); add ); div ); etc) BIND_CONSTANT(NODE_VEC_OP); // vec3 vs vec3 op (mul );ad );div );crossprod );etc) BIND_CONSTANT(NODE_VEC_SCALAR_OP); // vec3 vs scalar op (mul ); add ); div ); etc) BIND_CONSTANT(NODE_RGB_OP); // vec3 vs vec3 rgb op (with scalar amount) ); like brighten ); darken ); burn ); dodge ); multiply ); etc. BIND_CONSTANT(NODE_XFORM_MULT); // mat4 x mat4 BIND_CONSTANT(NODE_XFORM_VEC_MULT); // mat4 x vec3 mult (with no-translation option) BIND_CONSTANT(NODE_XFORM_VEC_INV_MULT); // mat4 x vec3 inverse mult (with no-translation option) BIND_CONSTANT(NODE_SCALAR_FUNC); // scalar function (sin ); cos ); etc) BIND_CONSTANT(NODE_VEC_FUNC); // vector function (normalize ); negate ); reciprocal ); rgb2hsv ); hsv2rgb ); etc ); etc) BIND_CONSTANT(NODE_VEC_LEN); // vec3 length BIND_CONSTANT(NODE_DOT_PROD); // vec3 . vec3 (dot product -> scalar output) BIND_CONSTANT(NODE_VEC_TO_SCALAR); // 1 vec3 input ); 3 scalar outputs BIND_CONSTANT(NODE_SCALAR_TO_VEC); // 3 scalar input ); 1 vec3 output BIND_CONSTANT(NODE_VEC_TO_XFORM); // 3 vec input ); 1 xform output BIND_CONSTANT(NODE_XFORM_TO_VEC); // 3 vec input ); 1 xform output BIND_CONSTANT(NODE_SCALAR_INTERP); // scalar interpolation (with optional curve) BIND_CONSTANT(NODE_VEC_INTERP); // vec3 interpolation (with optional curve) BIND_CONSTANT(NODE_COLOR_RAMP); BIND_CONSTANT(NODE_CURVE_MAP); BIND_CONSTANT(NODE_SCALAR_INPUT); // scalar uniform (assignable in material) BIND_CONSTANT(NODE_VEC_INPUT); // vec3 uniform (assignable in material) BIND_CONSTANT(NODE_RGB_INPUT); // color uniform (assignable in material) BIND_CONSTANT(NODE_XFORM_INPUT); // mat4 uniform (assignable in material) BIND_CONSTANT(NODE_TEXTURE_INPUT); // texture input (assignable in material) BIND_CONSTANT(NODE_CUBEMAP_INPUT); // cubemap input (assignable in material) BIND_CONSTANT(NODE_DEFAULT_TEXTURE); BIND_CONSTANT(NODE_OUTPUT); // output (shader type dependent) BIND_CONSTANT(NODE_COMMENT); // comment BIND_CONSTANT(NODE_TYPE_MAX); BIND_CONSTANT(SLOT_TYPE_SCALAR); BIND_CONSTANT(SLOT_TYPE_VEC); BIND_CONSTANT(SLOT_TYPE_XFORM); BIND_CONSTANT(SLOT_TYPE_TEXTURE); BIND_CONSTANT(SLOT_MAX); BIND_CONSTANT(SHADER_TYPE_VERTEX); BIND_CONSTANT(SHADER_TYPE_FRAGMENT); BIND_CONSTANT(SHADER_TYPE_LIGHT); BIND_CONSTANT(SHADER_TYPE_MAX); BIND_CONSTANT(SLOT_IN); BIND_CONSTANT(SLOT_OUT); BIND_CONSTANT(GRAPH_OK); BIND_CONSTANT(GRAPH_ERROR_CYCLIC); BIND_CONSTANT(GRAPH_ERROR_MISSING_CONNECTIONS); BIND_CONSTANT(SCALAR_OP_ADD); BIND_CONSTANT(SCALAR_OP_SUB); BIND_CONSTANT(SCALAR_OP_MUL); BIND_CONSTANT(SCALAR_OP_DIV); BIND_CONSTANT(SCALAR_OP_MOD); BIND_CONSTANT(SCALAR_OP_POW); BIND_CONSTANT(SCALAR_OP_MAX); BIND_CONSTANT(SCALAR_OP_MIN); BIND_CONSTANT(SCALAR_OP_ATAN2); BIND_CONSTANT(SCALAR_MAX_OP); BIND_CONSTANT(VEC_OP_ADD); BIND_CONSTANT(VEC_OP_SUB); BIND_CONSTANT(VEC_OP_MUL); BIND_CONSTANT(VEC_OP_DIV); BIND_CONSTANT(VEC_OP_MOD); BIND_CONSTANT(VEC_OP_POW); BIND_CONSTANT(VEC_OP_MAX); BIND_CONSTANT(VEC_OP_MIN); BIND_CONSTANT(VEC_OP_CROSS); BIND_CONSTANT(VEC_MAX_OP); BIND_CONSTANT(VEC_SCALAR_OP_MUL); BIND_CONSTANT(VEC_SCALAR_OP_DIV); BIND_CONSTANT(VEC_SCALAR_OP_POW); BIND_CONSTANT(VEC_SCALAR_MAX_OP); BIND_CONSTANT(RGB_OP_SCREEN); BIND_CONSTANT(RGB_OP_DIFFERENCE); BIND_CONSTANT(RGB_OP_DARKEN); BIND_CONSTANT(RGB_OP_LIGHTEN); BIND_CONSTANT(RGB_OP_OVERLAY); BIND_CONSTANT(RGB_OP_DODGE); BIND_CONSTANT(RGB_OP_BURN); BIND_CONSTANT(RGB_OP_SOFT_LIGHT); BIND_CONSTANT(RGB_OP_HARD_LIGHT); BIND_CONSTANT(RGB_MAX_OP); BIND_CONSTANT(SCALAR_FUNC_SIN); BIND_CONSTANT(SCALAR_FUNC_COS); BIND_CONSTANT(SCALAR_FUNC_TAN); BIND_CONSTANT(SCALAR_FUNC_ASIN); BIND_CONSTANT(SCALAR_FUNC_ACOS); BIND_CONSTANT(SCALAR_FUNC_ATAN); BIND_CONSTANT(SCALAR_FUNC_SINH); BIND_CONSTANT(SCALAR_FUNC_COSH); BIND_CONSTANT(SCALAR_FUNC_TANH); BIND_CONSTANT(SCALAR_FUNC_LOG); BIND_CONSTANT(SCALAR_FUNC_EXP); BIND_CONSTANT(SCALAR_FUNC_SQRT); BIND_CONSTANT(SCALAR_FUNC_ABS); BIND_CONSTANT(SCALAR_FUNC_SIGN); BIND_CONSTANT(SCALAR_FUNC_FLOOR); BIND_CONSTANT(SCALAR_FUNC_ROUND); BIND_CONSTANT(SCALAR_FUNC_CEIL); BIND_CONSTANT(SCALAR_FUNC_FRAC); BIND_CONSTANT(SCALAR_FUNC_SATURATE); BIND_CONSTANT(SCALAR_FUNC_NEGATE); BIND_CONSTANT(SCALAR_MAX_FUNC); BIND_CONSTANT(VEC_FUNC_NORMALIZE); BIND_CONSTANT(VEC_FUNC_SATURATE); BIND_CONSTANT(VEC_FUNC_NEGATE); BIND_CONSTANT(VEC_FUNC_RECIPROCAL); BIND_CONSTANT(VEC_FUNC_RGB2HSV); BIND_CONSTANT(VEC_FUNC_HSV2RGB); BIND_CONSTANT(VEC_MAX_FUNC); ADD_SIGNAL(MethodInfo("updated")); #if 0 ObjectTypeDB::bind_method(_MD("node_add"),&ShaderGraph::node_add ); ObjectTypeDB::bind_method(_MD("node_remove"),&ShaderGraph::node_remove ); ObjectTypeDB::bind_method(_MD("node_set_param"),&ShaderGraph::node_set_param ); ObjectTypeDB::bind_method(_MD("node_set_pos"),&ShaderGraph::node_set_pos ); ObjectTypeDB::bind_method(_MD("node_get_pos"),&ShaderGraph::node_get_pos ); ObjectTypeDB::bind_method(_MD("node_get_param"),&ShaderGraph::node_get_param); ObjectTypeDB::bind_method(_MD("node_get_type"),&ShaderGraph::node_get_type); ObjectTypeDB::bind_method(_MD("connect"),&ShaderGraph::connect ); ObjectTypeDB::bind_method(_MD("disconnect"),&ShaderGraph::disconnect ); ObjectTypeDB::bind_method(_MD("get_connections"),&ShaderGraph::_get_connections_helper ); ObjectTypeDB::bind_method(_MD("clear"),&ShaderGraph::clear ); BIND_CONSTANT( NODE_IN ); ///< param 0: name BIND_CONSTANT( NODE_OUT ); ///< param 0: name BIND_CONSTANT( NODE_CONSTANT ); ///< param 0: value BIND_CONSTANT( NODE_PARAMETER ); ///< param 0: name BIND_CONSTANT( NODE_ADD ); BIND_CONSTANT( NODE_SUB ); BIND_CONSTANT( NODE_MUL ); BIND_CONSTANT( NODE_DIV ); BIND_CONSTANT( NODE_MOD ); BIND_CONSTANT( NODE_SIN ); BIND_CONSTANT( NODE_COS ); BIND_CONSTANT( NODE_TAN ); BIND_CONSTANT( NODE_ARCSIN ); BIND_CONSTANT( NODE_ARCCOS ); BIND_CONSTANT( NODE_ARCTAN ); BIND_CONSTANT( NODE_POW ); BIND_CONSTANT( NODE_LOG ); BIND_CONSTANT( NODE_MAX ); BIND_CONSTANT( NODE_MIN ); BIND_CONSTANT( NODE_COMPARE ); BIND_CONSTANT( NODE_TEXTURE ); ///< param 0: texture BIND_CONSTANT( NODE_TIME ); ///< param 0: interval length BIND_CONSTANT( NODE_NOISE ); BIND_CONSTANT( NODE_PASS ); BIND_CONSTANT( NODE_VEC_IN ); ///< param 0: name BIND_CONSTANT( NODE_VEC_OUT ); ///< param 0: name BIND_CONSTANT( NODE_VEC_CONSTANT ); ///< param 0: value BIND_CONSTANT( NODE_VEC_PARAMETER ); ///< param 0: name BIND_CONSTANT( NODE_VEC_ADD ); BIND_CONSTANT( NODE_VEC_SUB ); BIND_CONSTANT( NODE_VEC_MUL ); BIND_CONSTANT( NODE_VEC_DIV ); BIND_CONSTANT( NODE_VEC_MOD ); BIND_CONSTANT( NODE_VEC_CROSS ); BIND_CONSTANT( NODE_VEC_DOT ); BIND_CONSTANT( NODE_VEC_POW ); BIND_CONSTANT( NODE_VEC_NORMALIZE ); BIND_CONSTANT( NODE_VEC_TRANSFORM3 ); BIND_CONSTANT( NODE_VEC_TRANSFORM4 ); BIND_CONSTANT( NODE_VEC_COMPARE ); BIND_CONSTANT( NODE_VEC_TEXTURE_2D ); BIND_CONSTANT( NODE_VEC_TEXTURE_CUBE ); BIND_CONSTANT( NODE_VEC_NOISE ); BIND_CONSTANT( NODE_VEC_0 ); BIND_CONSTANT( NODE_VEC_1 ); BIND_CONSTANT( NODE_VEC_2 ); BIND_CONSTANT( NODE_VEC_BUILD ); BIND_CONSTANT( NODE_VEC_PASS ); BIND_CONSTANT( NODE_COLOR_CONSTANT ); BIND_CONSTANT( NODE_COLOR_PARAMETER ); BIND_CONSTANT( NODE_TEXTURE_PARAMETER ); BIND_CONSTANT( NODE_TEXTURE_2D_PARAMETER ); BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER ); BIND_CONSTANT( NODE_TYPE_MAX ); #endif } String ShaderGraph::_find_unique_name(const String &p_base) { int idx = 1; while (true) { String tocmp = p_base; if (idx > 1) { tocmp += "_" + itos(idx); } bool valid = true; for (int i = 0; i < 3; i++) { if (!valid) break; for (Map::Element *E = shader[i].node_map.front(); E; E = E->next()) { if (E->get().type != NODE_SCALAR_INPUT && E->get().type != NODE_VEC_INPUT && E->get().type == NODE_RGB_INPUT && E->get().type == NODE_XFORM_INPUT && E->get().type == NODE_TEXTURE_INPUT && E->get().type == NODE_CUBEMAP_INPUT) continue; String name = E->get().param1; if (name == tocmp) { valid = false; break; } } } if (!valid) { idx++; continue; } return tocmp; } return String(); } void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type, int p_id) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(p_id == 0); ERR_FAIL_COND(p_node_type == NODE_OUTPUT); //can't create output ERR_FAIL_COND(shader[p_type].node_map.has(p_id)); ERR_FAIL_INDEX(p_node_type, NODE_TYPE_MAX); Node node; if (p_node_type == NODE_INPUT) { //see if it already exists for (Map::Element *E = shader[p_type].node_map.front(); E; E = E->next()) { if (E->get().type == NODE_INPUT) { ERR_EXPLAIN("Only one input node can be added to the graph."); ERR_FAIL_COND(E->get().type == NODE_INPUT); } } } node.type = p_node_type; node.id = p_id; switch (p_node_type) { case NODE_INPUT: { } break; // all inputs (shader type dependent) case NODE_SCALAR_CONST: { node.param1 = 0; } break; //scalar constant case NODE_VEC_CONST: { node.param1 = Vector3(); } break; //vec3 constant case NODE_RGB_CONST: { node.param1 = Color(); } break; //rgb constant (shows a color picker instead) case NODE_XFORM_CONST: { node.param1 = Transform(); } break; // 4x4 matrix constant case NODE_TIME: { } break; // time in seconds case NODE_SCREEN_TEX: { Array arr; arr.push_back(0); arr.push_back(0); node.param2 = arr; } break; // screen texture sampler (takes UV) (only usable in fragment shader) case NODE_SCALAR_OP: { node.param1 = SCALAR_OP_ADD; } break; // scalar vs scalar op (mul: {} break; add: {} break; div: {} break; etc) case NODE_VEC_OP: { node.param1 = VEC_OP_ADD; } break; // vec3 vs vec3 op (mul: {} break;ad: {} break;div: {} break;crossprod: {} break;etc) case NODE_VEC_SCALAR_OP: { node.param1 = VEC_SCALAR_OP_MUL; } break; // vec3 vs scalar op (mul: {} break; add: {} break; div: {} break; etc) case NODE_RGB_OP: { node.param1 = RGB_OP_SCREEN; } break; // vec3 vs vec3 rgb op (with scalar amount): {} break; like brighten: {} break; darken: {} break; burn: {} break; dodge: {} break; multiply: {} break; etc. case NODE_XFORM_MULT: { } break; // mat4 x mat4 case NODE_XFORM_VEC_MULT: { } break; // mat4 x vec3 mult (with no-translation option) case NODE_XFORM_VEC_INV_MULT: { } break; // mat4 x vec3 inverse mult (with no-translation option) case NODE_SCALAR_FUNC: { node.param1 = SCALAR_FUNC_SIN; } break; // scalar function (sin: {} break; cos: {} break; etc) case NODE_VEC_FUNC: { node.param1 = VEC_FUNC_NORMALIZE; } break; // vector function (normalize: {} break; negate: {} break; reciprocal: {} break; rgb2hsv: {} break; hsv2rgb: {} break; etc: {} break; etc) case NODE_VEC_LEN: { } break; // vec3 length case NODE_DOT_PROD: { } break; // vec3 . vec3 (dot product -> scalar output) case NODE_VEC_TO_SCALAR: { } break; // 1 vec3 input: {} break; 3 scalar outputs case NODE_SCALAR_TO_VEC: { } break; // 3 scalar input: {} break; 1 vec3 output case NODE_VEC_TO_XFORM: { } break; // 3 scalar input: {} break; 1 vec3 output case NODE_XFORM_TO_VEC: { } break; // 3 scalar input: {} break; 1 vec3 output case NODE_SCALAR_INTERP: { } break; // scalar interpolation (with optional curve) case NODE_VEC_INTERP: { } break; // vec3 interpolation (with optional curve) case NODE_COLOR_RAMP: { node.param1 = DVector(); node.param2 = DVector(); } break; // vec3 interpolation (with optional curve) case NODE_CURVE_MAP: { node.param1 = DVector(); } break; // vec3 interpolation (with optional curve) case NODE_SCALAR_INPUT: { node.param1 = _find_unique_name("Scalar"); node.param2 = 0; } break; // scalar uniform (assignable in material) case NODE_VEC_INPUT: { node.param1 = _find_unique_name("Vec3"); node.param2 = Vector3(); } break; // vec3 uniform (assignable in material) case NODE_RGB_INPUT: { node.param1 = _find_unique_name("Color"); node.param2 = Color(); } break; // color uniform (assignable in material) case NODE_XFORM_INPUT: { node.param1 = _find_unique_name("XForm"); node.param2 = Transform(); } break; // mat4 uniform (assignable in material) case NODE_TEXTURE_INPUT: { node.param1 = _find_unique_name("Tex"); } break; // texture input (assignable in material) case NODE_CUBEMAP_INPUT: { node.param1 = _find_unique_name("Cube"); } break; // cubemap input (assignable in material) case NODE_DEFAULT_TEXTURE: { }; break; case NODE_OUTPUT: { } break; // output (shader type dependent) case NODE_COMMENT: { } break; // comment case NODE_TYPE_MAX: { }; } shader[p_type].node_map[p_id] = node; _request_update(); } void ShaderGraph::node_set_pos(ShaderType p_type, int p_id, const Vector2 &p_pos) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); shader[p_type].node_map[p_id].pos = p_pos; _request_update(); } Vector2 ShaderGraph::node_get_pos(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Vector2()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Vector2()); return shader[p_type].node_map[p_id].pos; } void ShaderGraph::node_remove(ShaderType p_type, int p_id) { ERR_FAIL_COND(p_id == 0); ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); //erase connections associated with node for (Map::Element *E = shader[p_type].node_map.front(); E; E = E->next()) { if (E->key() == p_id) continue; //no self for (Map::Element *F = E->get().connections.front(); F;) { Map::Element *N = F->next(); if (F->get().id == p_id) { E->get().connections.erase(F); } F = N; } } shader[p_type].node_map.erase(p_id); _request_update(); } void ShaderGraph::get_node_list(ShaderType p_type, List *p_node_list) const { ERR_FAIL_INDEX(p_type, 3); Map::Element *E = shader[p_type].node_map.front(); while (E) { p_node_list->push_back(E->key()); E = E->next(); } } ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, NODE_TYPE_MAX); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), NODE_TYPE_MAX); return shader[p_type].node_map[p_id].type; } Error ShaderGraph::connect_node(ShaderType p_type, int p_src_id, int p_src_slot, int p_dst_id, int p_dst_slot) { ERR_FAIL_INDEX_V(p_type, 3, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_src_id == p_dst_id, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_src_id), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_dst_id), ERR_INVALID_PARAMETER); NodeType type_src = shader[p_type].node_map[p_src_id].type; NodeType type_dst = shader[p_type].node_map[p_dst_id].type; ERR_FAIL_INDEX_V(p_src_slot, get_node_output_slot_count(get_mode(), p_type, type_src), ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_dst_slot, get_node_input_slot_count(get_mode(), p_type, type_dst), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(get_node_output_slot_type(get_mode(), p_type, type_src, p_src_slot) != get_node_input_slot_type(get_mode(), p_type, type_dst, p_dst_slot), ERR_INVALID_PARAMETER); SourceSlot ts; ts.id = p_src_id; ts.slot = p_src_slot; shader[p_type].node_map[p_dst_id].connections[p_dst_slot] = ts; _request_update(); return OK; } bool ShaderGraph::is_node_connected(ShaderType p_type, int p_src_id, int p_src_slot, int p_dst_id, int p_dst_slot) const { ERR_FAIL_INDEX_V(p_type, 3, false); SourceSlot ts; ts.id = p_src_id; ts.slot = p_src_slot; return shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) && shader[p_type].node_map[p_dst_id].connections[p_dst_slot] == ts; } void ShaderGraph::disconnect_node(ShaderType p_type, int p_src_id, int p_src_slot, int p_dst_id, int p_dst_slot) { ERR_FAIL_INDEX(p_type, 3); SourceSlot ts; ts.id = p_src_id; ts.slot = p_src_slot; if (shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) && shader[p_type].node_map[p_dst_id].connections[p_dst_slot] == ts) { shader[p_type].node_map[p_dst_id].connections.erase(p_dst_slot); } _request_update(); } void ShaderGraph::get_node_connections(ShaderType p_type, List *p_connections) const { ERR_FAIL_INDEX(p_type, 3); for (const Map::Element *E = shader[p_type].node_map.front(); E; E = E->next()) { for (const Map::Element *F = E->get().connections.front(); F; F = F->next()) { Connection c; c.dst_id = E->key(); c.dst_slot = F->key(); c.src_id = F->get().id; c.src_slot = F->get().slot; p_connections->push_back(c); } } } bool ShaderGraph::is_slot_connected(ShaderGraph::ShaderType p_type, int p_dst_id, int slot_id) { for (const Map::Element *E = shader[p_type].node_map.front(); E; E = E->next()) { for (const Map::Element *F = E->get().connections.front(); F; F = F->next()) { if (p_dst_id == E->key() && slot_id == F->key()) return true; } } return false; } void ShaderGraph::clear(ShaderType p_type) { ERR_FAIL_INDEX(p_type, 3); shader[p_type].node_map.clear(); Node out; out.pos = Vector2(300, 300); out.type = NODE_OUTPUT; shader[p_type].node_map.insert(0, out); _request_update(); } void ShaderGraph::scalar_const_node_set_value(ShaderType p_type, int p_id, float p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_SCALAR_CONST); n.param1 = p_value; _request_update(); } float ShaderGraph::scalar_const_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, 0); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), 0); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_SCALAR_CONST, 0); return n.param1; } void ShaderGraph::vec_const_node_set_value(ShaderType p_type, int p_id, const Vector3 &p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_VEC_CONST); n.param1 = p_value; _request_update(); } Vector3 ShaderGraph::vec_const_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Vector3()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Vector3()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_VEC_CONST, Vector3()); return n.param1; } void ShaderGraph::rgb_const_node_set_value(ShaderType p_type, int p_id, const Color &p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_RGB_CONST); n.param1 = p_value; _request_update(); } Color ShaderGraph::rgb_const_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Color()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Color()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_RGB_CONST, Color()); return n.param1; } void ShaderGraph::xform_const_node_set_value(ShaderType p_type, int p_id, const Transform &p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_XFORM_CONST); n.param1 = p_value; _request_update(); } Transform ShaderGraph::xform_const_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Transform()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Transform()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_XFORM_CONST, Transform()); return n.param1; } void ShaderGraph::texture_node_set_filter_size(ShaderType p_type, int p_id, int p_size) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_TEXTURE_INPUT && n.type != NODE_SCREEN_TEX); Array arr = n.param2; arr[0] = p_size; n.param2 = arr; _request_update(); } int ShaderGraph::texture_node_get_filter_size(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, 0); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), 0); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_TEXTURE_INPUT && n.type != NODE_SCREEN_TEX, 0); Array arr = n.param2; return arr[0]; } void ShaderGraph::texture_node_set_filter_strength(ShaderType p_type, float p_id, float p_strength) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_TEXTURE_INPUT && n.type != NODE_SCREEN_TEX); Array arr = n.param2; arr[1] = p_strength; n.param2 = arr; _request_update(); } float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type, float p_id) const { ERR_FAIL_INDEX_V(p_type, 3, 0); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), 0); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_TEXTURE_INPUT && n.type != NODE_SCREEN_TEX, 0); Array arr = n.param2; return arr[1]; } void ShaderGraph::duplicate_nodes(ShaderType p_which, List &p_nodes) { //Create new node IDs Map duplicates = Map(); int i = 1; for (List::Element *E = p_nodes.front(); E; E = E->next()) { while (shader[p_which].node_map.has(i)) i++; duplicates.insert(E->get(), i); i++; } for (List::Element *E = p_nodes.front(); E; E = E->next()) { const Node &n = shader[p_which].node_map[E->get()]; Node nn = n; nn.id = duplicates.find(n.id)->get(); nn.pos += Vector2(0, 100); for (Map::Element *C = nn.connections.front(); C; C = C->next()) { SourceSlot &c = C->get(); if (p_nodes.find(c.id)) c.id = duplicates.find(c.id)->get(); } shader[p_which].node_map[nn.id] = nn; } _request_update(); } List ShaderGraph::generate_ids(ShaderType p_type, int count) { List ids = List(); int i = 1; while (ids.size() < count) { while (shader[p_type].node_map.has(i)) i++; ids.push_back(i); i++; } return ids; } void ShaderGraph::scalar_op_node_set_op(ShaderType p_type, float p_id, ScalarOp p_op) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_SCALAR_OP); n.param1 = p_op; _request_update(); } ShaderGraph::ScalarOp ShaderGraph::scalar_op_node_get_op(ShaderType p_type, float p_id) const { ERR_FAIL_INDEX_V(p_type, 3, SCALAR_MAX_OP); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), SCALAR_MAX_OP); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_SCALAR_OP, SCALAR_MAX_OP); int op = n.param1; return ScalarOp(op); } void ShaderGraph::vec_op_node_set_op(ShaderType p_type, float p_id, VecOp p_op) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_VEC_OP); n.param1 = p_op; _request_update(); } ShaderGraph::VecOp ShaderGraph::vec_op_node_get_op(ShaderType p_type, float p_id) const { ERR_FAIL_INDEX_V(p_type, 3, VEC_MAX_OP); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), VEC_MAX_OP); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_VEC_OP, VEC_MAX_OP); int op = n.param1; return VecOp(op); } void ShaderGraph::vec_scalar_op_node_set_op(ShaderType p_type, float p_id, VecScalarOp p_op) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_VEC_SCALAR_OP); n.param1 = p_op; _request_update(); } ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_type, float p_id) const { ERR_FAIL_INDEX_V(p_type, 3, VEC_SCALAR_MAX_OP); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), VEC_SCALAR_MAX_OP); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_VEC_SCALAR_OP, VEC_SCALAR_MAX_OP); int op = n.param1; return VecScalarOp(op); } void ShaderGraph::rgb_op_node_set_op(ShaderType p_type, float p_id, RGBOp p_op) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_RGB_OP); n.param1 = p_op; _request_update(); } ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type, float p_id) const { ERR_FAIL_INDEX_V(p_type, 3, RGB_MAX_OP); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), RGB_MAX_OP); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_RGB_OP, RGB_MAX_OP); int op = n.param1; return RGBOp(op); } void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type, int p_id, bool p_no_translation) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_XFORM_VEC_MULT && n.type != NODE_XFORM_VEC_INV_MULT); n.param1 = p_no_translation; _request_update(); } bool ShaderGraph::xform_vec_mult_node_get_no_translation(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, false); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), false); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_XFORM_VEC_MULT && n.type != NODE_XFORM_VEC_INV_MULT, false); return n.param1; } void ShaderGraph::scalar_func_node_set_function(ShaderType p_type, int p_id, ScalarFunc p_func) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_SCALAR_FUNC); int func = p_func; ERR_FAIL_INDEX(func, SCALAR_MAX_FUNC); n.param1 = func; _request_update(); } ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, SCALAR_MAX_FUNC); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), SCALAR_MAX_FUNC); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_SCALAR_FUNC, SCALAR_MAX_FUNC); int func = n.param1; return ScalarFunc(func); } void ShaderGraph::default_set_value(ShaderGraph::ShaderType p_which, int p_id, int p_param, const Variant &p_value) { ERR_FAIL_INDEX(p_which, 3); ERR_FAIL_COND(!shader[p_which].node_map.has(p_id)); Node &n = shader[p_which].node_map[p_id]; if (p_value.get_type() == Variant::NIL) n.defaults.erase(n.defaults.find(p_param)); else n.defaults[p_param] = p_value; _request_update(); } Variant ShaderGraph::default_get_value(ShaderGraph::ShaderType p_which, int p_id, int p_param) { ERR_FAIL_INDEX_V(p_which, 3, Variant()); ERR_FAIL_COND_V(!shader[p_which].node_map.has(p_id), Variant()); const Node &n = shader[p_which].node_map[p_id]; if (!n.defaults.has(p_param)) return Variant(); return n.defaults[p_param]; } void ShaderGraph::vec_func_node_set_function(ShaderType p_type, int p_id, VecFunc p_func) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_VEC_FUNC); int func = p_func; ERR_FAIL_INDEX(func, VEC_MAX_FUNC); n.param1 = func; _request_update(); } ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, VEC_MAX_FUNC); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), VEC_MAX_FUNC); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_VEC_FUNC, VEC_MAX_FUNC); int func = n.param1; return VecFunc(func); } void ShaderGraph::color_ramp_node_set_ramp(ShaderType p_type, int p_id, const DVector &p_colors, const DVector &p_offsets) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); ERR_FAIL_COND(p_colors.size() != p_offsets.size()); Node &n = shader[p_type].node_map[p_id]; n.param1 = p_colors; n.param2 = p_offsets; _request_update(); } DVector ShaderGraph::color_ramp_node_get_colors(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, DVector()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), DVector()); const Node &n = shader[p_type].node_map[p_id]; return n.param1; } DVector ShaderGraph::color_ramp_node_get_offsets(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, DVector()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), DVector()); const Node &n = shader[p_type].node_map[p_id]; return n.param2; } void ShaderGraph::curve_map_node_set_points(ShaderType p_type, int p_id, const DVector &p_points) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; n.param1 = p_points; _request_update(); } DVector ShaderGraph::curve_map_node_get_points(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, DVector()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), DVector()); const Node &n = shader[p_type].node_map[p_id]; return n.param1; } void ShaderGraph::input_node_set_name(ShaderType p_type, int p_id, const String &p_name) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); ERR_FAIL_COND(!p_name.is_valid_identifier()); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_SCALAR_INPUT && n.type != NODE_VEC_INPUT && n.type == NODE_RGB_INPUT && n.type == NODE_XFORM_INPUT && n.type == NODE_TEXTURE_INPUT && n.type == NODE_CUBEMAP_INPUT); n.param1 = ""; n.param1 = _find_unique_name(p_name); _request_update(); } String ShaderGraph::input_node_get_name(ShaderType p_type, int p_id) { ERR_FAIL_INDEX_V(p_type, 3, String()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), String()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_SCALAR_INPUT && n.type != NODE_VEC_INPUT && n.type == NODE_RGB_INPUT && n.type == NODE_XFORM_INPUT && n.type == NODE_TEXTURE_INPUT && n.type == NODE_CUBEMAP_INPUT, String()); return n.param1; } void ShaderGraph::scalar_input_node_set_value(ShaderType p_type, int p_id, float p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_SCALAR_INPUT); n.param2 = p_value; _request_update(); } float ShaderGraph::scalar_input_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, 0); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), 0); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_SCALAR_INPUT, 0); return n.param2; } void ShaderGraph::vec_input_node_set_value(ShaderType p_type, int p_id, const Vector3 &p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_VEC_INPUT); n.param2 = p_value; _request_update(); } Vector3 ShaderGraph::vec_input_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Vector3()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Vector3()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_VEC_INPUT, Vector3()); return n.param2; } void ShaderGraph::rgb_input_node_set_value(ShaderType p_type, int p_id, const Color &p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_RGB_INPUT); n.param2 = p_value; _request_update(); } Color ShaderGraph::rgb_input_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Color()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Color()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_RGB_INPUT, Color()); return n.param2; } void ShaderGraph::xform_input_node_set_value(ShaderType p_type, int p_id, const Transform &p_value) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_XFORM_INPUT); n.param2 = p_value; _request_update(); } Transform ShaderGraph::xform_input_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Transform()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Transform()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_XFORM_INPUT, Transform()); return n.param2; } void ShaderGraph::texture_input_node_set_value(ShaderType p_type, int p_id, const Ref &p_texture) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_TEXTURE_INPUT); n.param2 = p_texture; _request_update(); } Ref ShaderGraph::texture_input_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Ref()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Ref()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_TEXTURE_INPUT, Ref()); return n.param2; } void ShaderGraph::cubemap_input_node_set_value(ShaderType p_type, int p_id, const Ref &p_cubemap) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_CUBEMAP_INPUT); n.param2 = p_cubemap; _request_update(); } Ref ShaderGraph::cubemap_input_node_get_value(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Ref()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Ref()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_CUBEMAP_INPUT, Ref()); return n.param2; } void ShaderGraph::comment_node_set_text(ShaderType p_type, int p_id, const String &p_comment) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND(n.type != NODE_COMMENT); n.param1 = p_comment; } String ShaderGraph::comment_node_get_text(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, String()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), String()); const Node &n = shader[p_type].node_map[p_id]; ERR_FAIL_COND_V(n.type != NODE_COMMENT, String()); return n.param1; } void ShaderGraph::_request_update() { if (_pending_update_shader) return; _pending_update_shader = true; call_deferred("_update_shader"); } Variant ShaderGraph::node_get_state(ShaderType p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, 3, Variant()); ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id), Variant()); const Node &n = shader[p_type].node_map[p_id]; Dictionary s; s["pos"] = n.pos; s["param1"] = n.param1; s["param2"] = n.param2; Array keys; for (Map::Element *E = n.defaults.front(); E; E = E->next()) { keys.append(E->key()); s[E->key()] = E->get(); } s["default_keys"] = keys; return s; } void ShaderGraph::node_set_state(ShaderType p_type, int p_id, const Variant &p_state) { ERR_FAIL_INDEX(p_type, 3); ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); Node &n = shader[p_type].node_map[p_id]; Dictionary d = p_state; ERR_FAIL_COND(!d.has("pos")); ERR_FAIL_COND(!d.has("param1")); ERR_FAIL_COND(!d.has("param2")); ERR_FAIL_COND(!d.has("default_keys")); n.pos = d["pos"]; n.param1 = d["param1"]; n.param2 = d["param2"]; Array keys = d["default_keys"]; for (int i = 0; i < keys.size(); i++) { n.defaults[keys[i]] = d[keys[i]]; } } ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) { //shader = VisualServer::get_singleton()->shader_create(); _pending_update_shader = false; Node input; input.id = 1; input.pos = Vector2(50, 40); input.type = NODE_INPUT; Node output; output.id = 0; output.pos = Vector2(350, 40); output.type = NODE_OUTPUT; for (int i = 0; i < 3; i++) { shader[i].node_map.insert(0, output); shader[i].node_map.insert(1, input); } } ShaderGraph::~ShaderGraph() { //VisualServer::get_singleton()->free(shader); } const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[] = { //material vertex in { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Vertex", "SRC_VERTEX", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Normal", "SRC_NORMAL", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Tangent", "SRC_TANGENT", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "BinormalF", "SRC_BINORMALF", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Color", "SRC_COLOR", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Alpha", "SRC_ALPHA", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "UV", "SRC_UV", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "UV2", "SRC_UV2", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "WorldMatrix", "WORLD_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "InvCameraMatrix", "INV_CAMERA_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "ProjectionMatrix", "PROJECTION_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "ModelviewMatrix", "MODELVIEW_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "InstanceID", "INSTANCE_ID", "", SLOT_TYPE_SCALAR, SLOT_IN }, //material vertex out { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Vertex", "VERTEX", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Normal", "NORMAL", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Tangent", "TANGENT", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Binormal", "BINORMAL", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "UV", "UV", ".xy", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "UV2", "UV2", ".xy", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Color", "COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Alpha", "COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Var1", "VAR1.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "Var2", "VAR2.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "SpecExp", "SPEC_EXP", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_VERTEX, "PointSize", "POINT_SIZE", "", SLOT_TYPE_SCALAR, SLOT_OUT }, //pixel vertex in { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Vertex", "VERTEX", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Position", "POSITION.xyz", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Normal", "IN_NORMAL", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Tangent", "TANGENT", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Binormal", "BINORMAL", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "UV", "vec3(UV,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "UV2", "vec3(UV2,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "UVScreen", "vec3(SCREEN_UV,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "PointCoord", "POINT_COORD", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Color", "COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Alpha", "COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "InvCameraMatrix", "INV_CAMERA_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Var1", "VAR1.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Var2", "VAR2.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, //pixel vertex out { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Diffuse", "DIFFUSE_OUT", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "DiffuseAlpha", "ALPHA_OUT", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Specular", "SPECULAR", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "SpecularExp", "SPEC_EXP", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Emission", "EMISSION", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Glow", "GLOW", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "ShadeParam", "SHADE_PARAM", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Normal", "NORMAL", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "NormalMap", "NORMALMAP", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "NormalMapDepth", "NORMALMAP_DEPTH", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, "Discard", "DISCARD", ">0.5", SLOT_TYPE_SCALAR, SLOT_OUT }, //light in { MODE_MATERIAL, SHADER_TYPE_LIGHT, "Normal", "NORMAL", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "LightDir", "LIGHT_DIR", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "LightDiffuse", "LIGHT_DIFFUSE", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "LightSpecular", "LIGHT_SPECULAR", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "EyeVec", "EYE_VEC", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "Diffuse", "DIFFUSE", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "Specular", "SPECULAR", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "SpecExp", "SPECULAR_EXP", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "ShadeParam", "SHADE_PARAM", "", SLOT_TYPE_SCALAR, SLOT_IN }, //light out { MODE_MATERIAL, SHADER_TYPE_LIGHT, "Light", "LIGHT", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_MATERIAL, SHADER_TYPE_LIGHT, "Shadow", "SHADOW", "", SLOT_TYPE_VEC, SLOT_OUT }, //canvas item vertex in { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Vertex", "vec3(SRC_VERTEX,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "UV", "SRC_UV", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Color", "SRC_COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Alpha", "SRC_COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "WorldMatrix", "WORLD_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "ExtraMatrix", "EXTRA_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "ProjectionMatrix", "PROJECTION_MATRIX", "", SLOT_TYPE_XFORM, SLOT_IN }, //canvas item vertex out { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Vertex", "VERTEX", ".xy", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "UV", "UV", ".xy", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Color", "COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Alpha", "COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Var1", "VAR1.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "Var2", "VAR2.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_VERTEX, "PointSize", "POINT_SIZE", "", SLOT_TYPE_SCALAR, SLOT_OUT }, //canvas item fragment in { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "Color", "SRC_COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "Alpha", "SRC_COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "UV", "vec3(UV,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "UVScreen", "vec3(SCREEN_UV,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "TexPixelSize", "vec3(TEXTURE_PIXEL_SIZE,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "Var1", "VAR1.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "Var2", "VAR2.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "PointCoord", "POINT_COORD", "", SLOT_TYPE_VEC, SLOT_IN }, //canvas item fragment out { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "Color", "COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "Alpha", "COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "Normal", "NORMAL", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "NormalMap", "NORMALMAP", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_FRAGMENT, "NormalMapDepth", "NORMALMAP_DEPTH", "", SLOT_TYPE_SCALAR, SLOT_OUT }, //canvas item light in { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "Color", "COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "Alpha", "COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "Normal", "NORMAL", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "UV", "vec3(UV,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "LightColor", "LIGHT_COLOR.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "LightAlpha", "LIGHT_COLOR.a", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "LightHeight", "LIGHT_HEIGHT", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "ShadowColor", "LIGHT_SHADOW.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "ShadowAlpha", "LIGHT_SHADOW.a", "", SLOT_TYPE_SCALAR, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "TexPixelSize", "vec3(TEXTURE_PIXEL_SIZE,0)", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "Var1", "VAR1.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "Var2", "VAR2.rgb", "", SLOT_TYPE_VEC, SLOT_IN }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "PointCoord", "POINT_COORD", "", SLOT_TYPE_VEC, SLOT_IN }, //canvas item light out { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "LightColor", "LIGHT.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "LightAlpha", "LIGHT.a", "", SLOT_TYPE_SCALAR, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "ShadowColor", "SHADOW.rgb", "", SLOT_TYPE_VEC, SLOT_OUT }, { MODE_CANVAS_ITEM, SHADER_TYPE_LIGHT, "ShadowAlpha", "SHADOW.a", "", SLOT_TYPE_SCALAR, SLOT_OUT }, //end { MODE_MATERIAL, SHADER_TYPE_FRAGMENT, NULL, NULL, NULL, SLOT_TYPE_SCALAR, SLOT_OUT }, }; void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List *r_slots) { const InOutParamInfo *iop = &inout_param_info[0]; while (iop->name) { if (p_mode == iop->shader_mode && p_type == iop->shader_type) { SlotInfo si; si.dir = iop->dir; si.name = iop->name; si.type = iop->slot_type; r_slots->push_back(si); } iop++; } } const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[] = { { NODE_SCALAR_CONST, { SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, //scalar constant { NODE_VEC_CONST, { SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, //vec3 constant { NODE_RGB_CONST, { SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_TYPE_SCALAR, SLOT_MAX } }, //rgb constant (shows a color picker instead) { NODE_XFORM_CONST, { SLOT_MAX }, { SLOT_TYPE_XFORM, SLOT_MAX } }, // 4x4 matrix constant { NODE_TIME, { SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // time in seconds { NODE_SCREEN_TEX, { SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // screen texture sampler (takes UV) (only usable in fragment shader) { NODE_SCALAR_OP, { SLOT_TYPE_SCALAR, SLOT_TYPE_SCALAR, SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) { NODE_VEC_OP, { SLOT_TYPE_VEC, SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) { NODE_VEC_SCALAR_OP, { SLOT_TYPE_VEC, SLOT_TYPE_SCALAR, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) { NODE_RGB_OP, { SLOT_TYPE_VEC, SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) { NODE_XFORM_MULT, { SLOT_TYPE_XFORM, SLOT_TYPE_XFORM, SLOT_MAX }, { SLOT_TYPE_XFORM, SLOT_MAX } }, // mat4 x mat4 { NODE_XFORM_VEC_MULT, { SLOT_TYPE_XFORM, SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // mat4 x vec3 mult (with no-translation option) { NODE_XFORM_VEC_INV_MULT, { SLOT_TYPE_VEC, SLOT_TYPE_XFORM, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // mat4 x vec3 inverse mult (with no-translation option) { NODE_SCALAR_FUNC, { SLOT_TYPE_SCALAR, SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // scalar function (sin,{SLOT_MAX},{SLOT_MAX}}, cos,{SLOT_MAX},{SLOT_MAX}}, etc) { NODE_VEC_FUNC, { SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // vector function (normalize,{SLOT_MAX},{SLOT_MAX}}, negate,{SLOT_MAX},{SLOT_MAX}}, reciprocal,{SLOT_MAX},{SLOT_MAX}}, rgb2hsv,{SLOT_MAX},{SLOT_MAX}}, hsv2rgb,{SLOT_MAX},{SLOT_MAX}}, etc,{SLOT_MAX},{SLOT_MAX}}, etc) { NODE_VEC_LEN, { SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // vec3 length { NODE_DOT_PROD, { SLOT_TYPE_VEC, SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // vec3 . vec3 (dot product -> scalar output) { NODE_VEC_TO_SCALAR, { SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_TYPE_SCALAR, SLOT_TYPE_SCALAR } }, // 1 vec3 input,{SLOT_MAX},{SLOT_MAX}}, 3 scalar outputs { NODE_SCALAR_TO_VEC, { SLOT_TYPE_SCALAR, SLOT_TYPE_SCALAR, SLOT_TYPE_SCALAR }, { SLOT_TYPE_VEC, SLOT_MAX } }, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output { NODE_SCALAR_INTERP, { SLOT_TYPE_SCALAR, SLOT_TYPE_SCALAR, SLOT_TYPE_SCALAR }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // scalar interpolation (with optional curve) { NODE_VEC_INTERP, { SLOT_TYPE_VEC, SLOT_TYPE_VEC, SLOT_TYPE_SCALAR }, { SLOT_TYPE_VEC, SLOT_MAX } }, // vec3 interpolation (with optional curve) { NODE_COLOR_RAMP, { SLOT_TYPE_SCALAR, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_TYPE_SCALAR, SLOT_MAX } }, // vec3 interpolation (with optional curve) { NODE_CURVE_MAP, { SLOT_TYPE_SCALAR, SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // vec3 interpolation (with optional curve) { NODE_SCALAR_INPUT, { SLOT_MAX }, { SLOT_TYPE_SCALAR, SLOT_MAX } }, // scalar uniform (assignable in material) { NODE_VEC_INPUT, { SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_MAX } }, // vec3 uniform (assignable in material) { NODE_RGB_INPUT, { SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_TYPE_SCALAR, SLOT_MAX } }, // color uniform (assignable in material) { NODE_XFORM_INPUT, { SLOT_MAX }, { SLOT_TYPE_XFORM, SLOT_MAX } }, // mat4 uniform (assignable in material) { NODE_TEXTURE_INPUT, { SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_TYPE_SCALAR, SLOT_MAX } }, // texture input (assignable in material) { NODE_CUBEMAP_INPUT, { SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_TYPE_SCALAR, SLOT_MAX } }, // cubemap input (assignable in material) { NODE_DEFAULT_TEXTURE, { SLOT_TYPE_VEC, SLOT_MAX }, { SLOT_TYPE_VEC, SLOT_TYPE_SCALAR, SLOT_MAX } }, // cubemap input (assignable in material) { NODE_COMMENT, { SLOT_MAX }, { SLOT_MAX } }, // comment { NODE_TYPE_MAX, { SLOT_MAX }, { SLOT_MAX } } }; int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type, NodeType p_type) { if (p_type == NODE_INPUT || p_type == NODE_OUTPUT) { const InOutParamInfo *iop = &inout_param_info[0]; int pc = 0; while (iop->name) { if (p_mode == iop->shader_mode && p_shader_type == iop->shader_type) { if (iop->dir == SLOT_OUT) pc++; } iop++; } return pc; } else if (p_type == NODE_VEC_TO_XFORM) { return 4; } else if (p_type == NODE_XFORM_TO_VEC) { return 1; } else { const NodeSlotInfo *nsi = &node_slot_info[0]; while (nsi->type != NODE_TYPE_MAX) { if (nsi->type == p_type) { int pc = 0; for (int i = 0; i < NodeSlotInfo::MAX_INS; i++) { if (nsi->ins[i] == SLOT_MAX) break; pc++; } return pc; } nsi++; } return 0; } } int ShaderGraph::get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type, NodeType p_type) { if (p_type == NODE_INPUT || p_type == NODE_OUTPUT) { const InOutParamInfo *iop = &inout_param_info[0]; int pc = 0; while (iop->name) { if (p_mode == iop->shader_mode && p_shader_type == iop->shader_type) { if (iop->dir == SLOT_IN) pc++; } iop++; } return pc; } else if (p_type == NODE_VEC_TO_XFORM) { return 1; } else if (p_type == NODE_XFORM_TO_VEC) { return 4; } else { const NodeSlotInfo *nsi = &node_slot_info[0]; while (nsi->type != NODE_TYPE_MAX) { if (nsi->type == p_type) { int pc = 0; for (int i = 0; i < NodeSlotInfo::MAX_OUTS; i++) { if (nsi->outs[i] == SLOT_MAX) break; pc++; } return pc; } nsi++; } return 0; } } ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type, NodeType p_type, int p_idx) { if (p_type == NODE_INPUT || p_type == NODE_OUTPUT) { const InOutParamInfo *iop = &inout_param_info[0]; int pc = 0; while (iop->name) { if (p_mode == iop->shader_mode && p_shader_type == iop->shader_type) { if (iop->dir == SLOT_OUT) { if (pc == p_idx) return iop->slot_type; pc++; } } iop++; } ERR_FAIL_V(SLOT_MAX); } else if (p_type == NODE_VEC_TO_XFORM) { return SLOT_TYPE_VEC; } else if (p_type == NODE_XFORM_TO_VEC) { return SLOT_TYPE_XFORM; } else { const NodeSlotInfo *nsi = &node_slot_info[0]; while (nsi->type != NODE_TYPE_MAX) { if (nsi->type == p_type) { for (int i = 0; i < NodeSlotInfo::MAX_INS; i++) { if (nsi->ins[i] == SLOT_MAX) break; if (i == p_idx) return nsi->ins[i]; } } nsi++; } ERR_FAIL_V(SLOT_MAX); } } ShaderGraph::SlotType ShaderGraph::get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type, NodeType p_type, int p_idx) { if (p_type == NODE_INPUT || p_type == NODE_OUTPUT) { const InOutParamInfo *iop = &inout_param_info[0]; int pc = 0; while (iop->name) { if (p_mode == iop->shader_mode && p_shader_type == iop->shader_type) { if (iop->dir == SLOT_IN) { if (pc == p_idx) return iop->slot_type; pc++; } } iop++; } ERR_FAIL_V(SLOT_MAX); } else if (p_type == NODE_VEC_TO_XFORM) { return SLOT_TYPE_XFORM; } else if (p_type == NODE_XFORM_TO_VEC) { return SLOT_TYPE_VEC; } else { const NodeSlotInfo *nsi = &node_slot_info[0]; while (nsi->type != NODE_TYPE_MAX) { if (nsi->type == p_type) { for (int i = 0; i < NodeSlotInfo::MAX_OUTS; i++) { if (nsi->outs[i] == SLOT_MAX) break; if (i == p_idx) return nsi->outs[i]; } } nsi++; } ERR_FAIL_V(SLOT_MAX); } } void ShaderGraph::_update_shader() { String code[3]; List names; get_default_texture_param_list(&names); for (List::Element *E = names.front(); E; E = E->next()) { set_default_texture_param(E->get(), Ref()); } for (int i = 0; i < 3; i++) { int idx = 0; for (Map::Element *E = shader[i].node_map.front(); E; E = E->next()) { E->get().sort_order = idx++; } //simple method for graph solving using bubblesort derived algorithm int iters = 0; int iter_max = shader[i].node_map.size() * shader[i].node_map.size(); while (true) { if (iters > iter_max) break; int swaps = 0; for (Map::Element *E = shader[i].node_map.front(); E; E = E->next()) { for (Map::Element *F = E->get().connections.front(); F; F = F->next()) { //this is kinda slow, could be sped up Map::Element *G = shader[i].node_map.find(F->get().id); ERR_FAIL_COND(!G); if (G->get().sort_order > E->get().sort_order) { SWAP(G->get().sort_order, E->get().sort_order); swaps++; } } } iters++; if (swaps == 0) { iters = 0; break; } } if (iters > 0) { shader[i].error = GRAPH_ERROR_CYCLIC; continue; } Vector order; order.resize(shader[i].node_map.size()); for (Map::Element *E = shader[i].node_map.front(); E; E = E->next()) { order[E->get().sort_order] = &E->get(); } //generate code for the ordered graph bool failed = false; if (i == SHADER_TYPE_FRAGMENT && get_mode() == MODE_MATERIAL) { code[i] += "vec3 DIFFUSE_OUT=vec3(0,0,0);\n"; code[i] += "float ALPHA_OUT=0;\n"; } Map inputs_xlate; Map input_names_xlate; Set inputs_used; for (int j = 0; j < order.size(); j++) { Node *n = order[j]; if (n->type == NODE_INPUT) { const InOutParamInfo *iop = &inout_param_info[0]; int idx = 0; while (iop->name) { if (get_mode() == iop->shader_mode && i == iop->shader_type && SLOT_IN == iop->dir) { const char *typestr[4] = { "float", "vec3", "mat4", "texture" }; String vname = ("nd" + itos(n->id) + "sl" + itos(idx)); inputs_xlate[vname] = String(typestr[iop->slot_type]) + " " + vname + "=" + iop->variable + ";\n"; input_names_xlate[vname] = iop->variable; idx++; } iop++; } } else if (n->type == NODE_OUTPUT) { bool use_alpha = false; const InOutParamInfo *iop = &inout_param_info[0]; int idx = 0; while (iop->name) { if (get_mode() == iop->shader_mode && i == iop->shader_type && SLOT_OUT == iop->dir) { if (n->connections.has(idx)) { String iname = ("nd" + itos(n->connections[idx].id) + "sl" + itos(n->connections[idx].slot)); if (node_get_type(ShaderType(i), n->connections[idx].id) == NODE_INPUT) inputs_used.insert(iname); code[i] += String(iop->variable) + "=" + iname + String(iop->postfix) + ";\n"; if (i == SHADER_TYPE_FRAGMENT && get_mode() == MODE_MATERIAL && String(iop->name) == "DiffuseAlpha") use_alpha = true; } idx++; } iop++; } if (i == SHADER_TYPE_FRAGMENT && get_mode() == MODE_MATERIAL) { if (use_alpha) { code[i] += "DIFFUSE_ALPHA=vec4(DIFFUSE_OUT,ALPHA_OUT);\n"; } else { code[i] += "DIFFUSE=DIFFUSE_OUT;\n"; } } } else { Vector inputs; int max = get_node_input_slot_count(get_mode(), ShaderType(i), n->type); for (int k = 0; k < max; k++) { String iname; if (!n->connections.has(k)) { iname = "nd" + itos(n->id) + "sl" + itos(k) + "def"; } else { iname = "nd" + itos(n->connections[k].id) + "sl" + itos(n->connections[k].slot); if (node_get_type(ShaderType(i), n->connections[k].id) == NODE_INPUT) { inputs_used.insert(iname); } } inputs.push_back(iname); } if (failed) break; if (n->type == NODE_TEXTURE_INPUT || n->type == NODE_CUBEMAP_INPUT) { set_default_texture_param(n->param1, n->param2); } _add_node_code(ShaderType(i), n, inputs, code[i]); } } if (failed) continue; for (Set::Element *E = inputs_used.front(); E; E = E->next()) { ERR_CONTINUE(!inputs_xlate.has(E->get())); code[i] = inputs_xlate[E->get()] + code[i]; String name = input_names_xlate[E->get()]; if (i == SHADER_TYPE_VERTEX && get_mode() == MODE_MATERIAL) { if (name == ("SRC_COLOR")) code[i] = "vec3 SRC_COLOR=COLOR.rgb;\n" + code[i]; if (name == ("SRC_ALPHA")) code[i] = "float SRC_ALPHA=COLOR.a;\n" + code[i]; if (name == ("SRC_UV")) code[i] = "vec3 SRC_UV=vec3(UV,0);\n" + code[i]; if (name == ("SRC_UV2")) code[i] = "float SRC_UV2=vec3(UV2,0);\n" + code[i]; } else if (i == SHADER_TYPE_FRAGMENT && get_mode() == MODE_MATERIAL) { if (name == ("IN_NORMAL")) code[i] = "vec3 IN_NORMAL=NORMAL;\n" + code[i]; } else if (i == SHADER_TYPE_VERTEX && get_mode() == MODE_CANVAS_ITEM) { if (name == ("SRC_COLOR")) code[i] = "vec3 SRC_COLOR=COLOR.rgb;\n" + code[i]; if (name == ("SRC_UV")) code[i] = "vec3 SRC_UV=vec3(UV,0);\n" + code[i]; } } shader[i].error = GRAPH_OK; } bool all_ok = true; for (int i = 0; i < 3; i++) { if (shader[i].error != GRAPH_OK) all_ok = false; } /*print_line("VERTEX: \n"+code[0]); print_line("FRAGMENT: \n"+code[1]); print_line("LIGHT: \n"+code[2]);*/ if (all_ok) { set_code(code[0], code[1], code[2]); } //do shader here _pending_update_shader = false; emit_signal(SceneStringNames::get_singleton()->updated); } void ShaderGraph::_plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d, uint8_t *p_heights, bool *p_useds) { float geometry[4][4]; float tmp1[4][4]; float tmp2[4][4]; float deltas[4][4]; double x, dx, dx2, dx3; double y, dy, dy2, dy3; double d, d2, d3; int lastx, lasty; int newx, newy; int ntimes; int i, j; int xmax = 255; int ymax = 255; /* construct the geometry matrix from the segment */ for (i = 0; i < 4; i++) { geometry[i][2] = 0; geometry[i][3] = 0; } geometry[0][0] = (p_a[0] * xmax); geometry[1][0] = (p_b[0] * xmax); geometry[2][0] = (p_c[0] * xmax); geometry[3][0] = (p_d[0] * xmax); geometry[0][1] = (p_a[1] * ymax); geometry[1][1] = (p_b[1] * ymax); geometry[2][1] = (p_c[1] * ymax); geometry[3][1] = (p_d[1] * ymax); /* subdivide the curve ntimes (1000) times */ ntimes = 4 * xmax; /* ntimes can be adjusted to give a finer or coarser curve */ d = 1.0 / ntimes; d2 = d * d; d3 = d * d * d; /* construct a temporary matrix for determining the forward differencing deltas */ tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1; tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0; tmp2[2][0] = 6 * d3; tmp2[2][1] = 2 * d2; tmp2[2][2] = 0; tmp2[2][3] = 0; tmp2[3][0] = 6 * d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0; /* compose the basis and geometry matrices */ static const float CR_basis[4][4] = { { -0.5, 1.5, -1.5, 0.5 }, { 1.0, -2.5, 2.0, -0.5 }, { -0.5, 0.0, 0.5, 0.0 }, { 0.0, 1.0, 0.0, 0.0 }, }; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] + CR_basis[i][1] * geometry[1][j] + CR_basis[i][2] * geometry[2][j] + CR_basis[i][3] * geometry[3][j]); } } /* compose the above results to get the deltas matrix */ for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { deltas[i][j] = (tmp2[i][0] * tmp1[0][j] + tmp2[i][1] * tmp1[1][j] + tmp2[i][2] * tmp1[2][j] + tmp2[i][3] * tmp1[3][j]); } } /* extract the x deltas */ x = deltas[0][0]; dx = deltas[1][0]; dx2 = deltas[2][0]; dx3 = deltas[3][0]; /* extract the y deltas */ y = deltas[0][1]; dy = deltas[1][1]; dy2 = deltas[2][1]; dy3 = deltas[3][1]; lastx = CLAMP(x, 0, xmax); lasty = CLAMP(y, 0, ymax); p_heights[lastx] = lasty; p_useds[lastx] = true; /* loop over the curve */ for (i = 0; i < ntimes; i++) { /* increment the x values */ x += dx; dx += dx2; dx2 += dx3; /* increment the y values */ y += dy; dy += dy2; dy2 += dy3; newx = CLAMP((Math::round(x)), 0, xmax); newy = CLAMP((Math::round(y)), 0, ymax); /* if this point is different than the last one...then draw it */ if ((lastx != newx) || (lasty != newy)) { p_useds[newx] = true; p_heights[newx] = newy; } lastx = newx; lasty = newy; } } void ShaderGraph::_add_node_code(ShaderType p_type, Node *p_node, const Vector &p_inputs, String &code) { const char *typestr[4] = { "float", "vec3", "mat4", "texture" }; #define OUTNAME(id, slot) (String(typestr[get_node_output_slot_type(get_mode(), p_type, p_node->type, slot)]) + " " + ("nd" + itos(id) + "sl" + itos(slot))) #define OUTVAR(id, slot) ("nd" + itos(id) + "sl" + itos(slot)) #define DEF_VEC(slot) \ if (p_inputs[slot].ends_with("def")) { \ Vector3 v = p_node->defaults[slot]; \ code += String(typestr[1]) + " " + p_inputs[slot] + "=vec3(" + v + ");\n"; \ } #define DEF_SCALAR(slot) \ if (p_inputs[slot].ends_with("def")) { \ double v = p_node->defaults[slot]; \ code += String(typestr[0]) + " " + p_inputs[slot] + "=" + rtos(v) + ";\n"; \ } #define DEF_COLOR(slot) \ if (p_inputs[slot].ends_with("def")) { \ Color col = p_node->defaults[slot]; \ code += String(typestr[1]) + " " + p_inputs[slot] + "=vec3(" + rtos(col.r) + "," + rtos(col.g) + "," + rtos(col.b) + ");\n"; \ } #define DEF_MATRIX(slot) \ if (p_inputs[slot].ends_with("def")) { \ Transform xf = p_node->defaults[slot]; \ code += String(typestr[2]) + " " + p_inputs[slot] + "=mat4(\n"; \ code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(0).x) + "," + rtos(xf.basis.get_axis(0).y) + "," + rtos(xf.basis.get_axis(0).z) + "),0),\n"; \ code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(1).x) + "," + rtos(xf.basis.get_axis(1).y) + "," + rtos(xf.basis.get_axis(1).z) + "),0),\n"; \ code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(2).x) + "," + rtos(xf.basis.get_axis(2).y) + "," + rtos(xf.basis.get_axis(2).z) + "),0),\n"; \ code += "\tvec4(vec3(" + rtos(xf.origin.x) + "," + rtos(xf.origin.y) + "," + rtos(xf.origin.z) + "),1)\n"; \ code += ");\n"; \ } switch (p_node->type) { case NODE_INPUT: { } break; case NODE_SCALAR_CONST: { double scalar = p_node->param1; code += OUTNAME(p_node->id, 0) + "=" + rtos(scalar) + ";\n"; } break; case NODE_VEC_CONST: { Vector3 vec = p_node->param1; code += OUTNAME(p_node->id, 0) + "=vec3(" + rtos(vec.x) + "," + rtos(vec.y) + "," + rtos(vec.z) + ");\n"; } break; case NODE_RGB_CONST: { Color col = p_node->param1; code += OUTNAME(p_node->id, 0) + "=vec3(" + rtos(col.r) + "," + rtos(col.g) + "," + rtos(col.b) + ");\n"; code += OUTNAME(p_node->id, 1) + "=" + rtos(col.a) + ";\n"; } break; case NODE_XFORM_CONST: { Transform xf = p_node->param1; code += OUTNAME(p_node->id, 0) + "=mat4(\n"; code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(0).x) + "," + rtos(xf.basis.get_axis(0).y) + "," + rtos(xf.basis.get_axis(0).z) + "),0),\n"; code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(1).x) + "," + rtos(xf.basis.get_axis(1).y) + "," + rtos(xf.basis.get_axis(1).z) + "),0),\n"; code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(2).x) + "," + rtos(xf.basis.get_axis(2).y) + "," + rtos(xf.basis.get_axis(2).z) + "),0),\n"; code += "\tvec4(vec3(" + rtos(xf.origin.x) + "," + rtos(xf.origin.y) + "," + rtos(xf.origin.z) + "),1)\n"; code += ");"; } break; case NODE_TIME: { code += OUTNAME(p_node->id, 0) + "=TIME;\n"; } break; case NODE_SCREEN_TEX: { DEF_VEC(0); code += OUTNAME(p_node->id, 0) + "=texscreen(" + p_inputs[0] + ".xy);\n"; } break; case NODE_SCALAR_OP: { DEF_SCALAR(0); DEF_SCALAR(1); int op = p_node->param1; String optxt; switch (op) { case SCALAR_OP_ADD: optxt = p_inputs[0] + "+" + p_inputs[1] + ";"; break; case SCALAR_OP_SUB: optxt = p_inputs[0] + "-" + p_inputs[1] + ";"; break; case SCALAR_OP_MUL: optxt = p_inputs[0] + "*" + p_inputs[1] + ";"; break; case SCALAR_OP_DIV: optxt = p_inputs[0] + "/" + p_inputs[1] + ";"; break; case SCALAR_OP_MOD: optxt = "mod(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case SCALAR_OP_POW: optxt = "pow(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case SCALAR_OP_MAX: optxt = "max(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case SCALAR_OP_MIN: optxt = "min(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case SCALAR_OP_ATAN2: optxt = "atan2(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; } code += OUTNAME(p_node->id, 0) + "=" + optxt + "\n"; } break; case NODE_VEC_OP: { DEF_VEC(0); DEF_VEC(1); int op = p_node->param1; String optxt; switch (op) { case VEC_OP_ADD: optxt = p_inputs[0] + "+" + p_inputs[1] + ";"; break; case VEC_OP_SUB: optxt = p_inputs[0] + "-" + p_inputs[1] + ";"; break; case VEC_OP_MUL: optxt = p_inputs[0] + "*" + p_inputs[1] + ";"; break; case VEC_OP_DIV: optxt = p_inputs[0] + "/" + p_inputs[1] + ";"; break; case VEC_OP_MOD: optxt = "mod(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case VEC_OP_POW: optxt = "pow(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case VEC_OP_MAX: optxt = "max(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case VEC_OP_MIN: optxt = "min(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; case VEC_OP_CROSS: optxt = "cross(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; } code += OUTNAME(p_node->id, 0) + "=" + optxt + "\n"; } break; case NODE_VEC_SCALAR_OP: { DEF_VEC(0); DEF_SCALAR(1); int op = p_node->param1; String optxt; switch (op) { case VEC_SCALAR_OP_MUL: optxt = p_inputs[0] + "*" + p_inputs[1] + ";"; break; case VEC_SCALAR_OP_DIV: optxt = p_inputs[0] + "/" + p_inputs[1] + ";"; break; case VEC_SCALAR_OP_POW: optxt = "pow(" + p_inputs[0] + "," + p_inputs[1] + ");"; break; } code += OUTNAME(p_node->id, 0) + "=" + optxt + "\n"; } break; case NODE_RGB_OP: { DEF_COLOR(0); DEF_COLOR(1); int op = p_node->param1; static const char *axisn[3] = { "x", "y", "z" }; switch (op) { case RGB_OP_SCREEN: { code += OUTNAME(p_node->id, 0) + "=vec3(1.0)-(vec3(1.0)-" + p_inputs[0] + ")*(vec3(1.0)-" + p_inputs[1] + ");\n"; } break; case RGB_OP_DIFFERENCE: { code += OUTNAME(p_node->id, 0) + "=abs(" + p_inputs[0] + "-" + p_inputs[1] + ");\n"; } break; case RGB_OP_DARKEN: { code += OUTNAME(p_node->id, 0) + "=min(" + p_inputs[0] + "," + p_inputs[1] + ");\n"; } break; case RGB_OP_LIGHTEN: { code += OUTNAME(p_node->id, 0) + "=max(" + p_inputs[0] + "," + p_inputs[1] + ");\n"; } break; case RGB_OP_OVERLAY: { code += OUTNAME(p_node->id, 0) + ";\n"; for (int i = 0; i < 3; i++) { code += "{\n"; code += "\tfloat base=" + p_inputs[0] + "." + axisn[i] + ";\n"; code += "\tfloat blend=" + p_inputs[1] + "." + axisn[i] + ";\n"; code += "\tif (base < 0.5) {\n"; code += "\t\t" + OUTVAR(p_node->id, 0) + "." + axisn[i] + " = 2.0 * base * blend;\n"; code += "\t} else {\n"; code += "\t\t" + OUTVAR(p_node->id, 0) + "." + axisn[i] + " = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n"; code += "\t}\n"; code += "}\n"; } } break; case RGB_OP_DODGE: { code += OUTNAME(p_node->id, 0) + "=(" + p_inputs[0] + ")/(vec3(1.0)-" + p_inputs[1] + ");\n"; } break; case RGB_OP_BURN: { code += OUTNAME(p_node->id, 0) + "=vec3(1.0)-(vec3(1.0)-" + p_inputs[0] + ")/(" + p_inputs[1] + ");\n"; } break; case RGB_OP_SOFT_LIGHT: { code += OUTNAME(p_node->id, 0) + ";\n"; for (int i = 0; i < 3; i++) { code += "{\n"; code += "\tfloat base=" + p_inputs[0] + "." + axisn[i] + ";\n"; code += "\tfloat blend=" + p_inputs[1] + "." + axisn[i] + ";\n"; code += "\tif (base < 0.5) {\n"; code += "\t\t" + OUTVAR(p_node->id, 0) + "." + axisn[i] + " = (base * (blend+0.5));\n"; code += "\t} else {\n"; code += "\t\t" + OUTVAR(p_node->id, 0) + "." + axisn[i] + " = (1 - (1-base) * (1-(blend-0.5)));\n"; code += "\t}\n"; code += "}\n"; } } break; case RGB_OP_HARD_LIGHT: { code += OUTNAME(p_node->id, 0) + ";\n"; for (int i = 0; i < 3; i++) { code += "{\n"; code += "\tfloat base=" + p_inputs[0] + "." + axisn[i] + ";\n"; code += "\tfloat blend=" + p_inputs[1] + "." + axisn[i] + ";\n"; code += "\tif (base < 0.5) {\n"; code += "\t\t" + OUTVAR(p_node->id, 0) + "." + axisn[i] + " = (base * (2*blend));\n"; code += "\t} else {\n"; code += "\t\t" + OUTVAR(p_node->id, 0) + "." + axisn[i] + " = (1 - (1-base) * (1-2*(blend-0.5)));\n"; code += "\t}\n"; code += "}\n"; } } break; } } break; case NODE_XFORM_MULT: { DEF_MATRIX(0); DEF_MATRIX(1); code += OUTNAME(p_node->id, 0) + "=" + p_inputs[0] + "*" + p_inputs[1] + ";\n"; } break; case NODE_XFORM_VEC_MULT: { DEF_MATRIX(0); DEF_VEC(1); bool no_translation = p_node->param1; if (no_translation) { code += OUTNAME(p_node->id, 0) + "=(" + p_inputs[0] + "*vec4(" + p_inputs[1] + ",0)).xyz;\n"; } else { code += OUTNAME(p_node->id, 0) + "=(" + p_inputs[0] + "*vec4(" + p_inputs[1] + ",1)).xyz;\n"; } } break; case NODE_XFORM_VEC_INV_MULT: { DEF_VEC(0); DEF_MATRIX(1); bool no_translation = p_node->param1; if (no_translation) { code += OUTNAME(p_node->id, 0) + "=(" + p_inputs[1] + "*vec4(" + p_inputs[0] + ",0)).xyz;\n"; } else { code += OUTNAME(p_node->id, 0) + "=(" + p_inputs[1] + "*vec4(" + p_inputs[0] + ",1)).xyz;\n"; } } break; case NODE_SCALAR_FUNC: { DEF_SCALAR(0); static const char *scalar_func_id[SCALAR_MAX_FUNC] = { "sin($)", "cos($)", "tan($)", "asin($)", "acos($)", "atan($)", "sinh($)", "cosh($)", "tanh($)", "log($)", "exp($)", "sqrt($)", "abs($)", "sign($)", "floor($)", "round($)", "ceil($)", "fract($)", "min(max($,0),1)", "-($)", }; int func = p_node->param1; ERR_FAIL_INDEX(func, SCALAR_MAX_FUNC); code += OUTNAME(p_node->id, 0) + "=" + String(scalar_func_id[func]).replace("$", p_inputs[0]) + ";\n"; } break; case NODE_VEC_FUNC: { DEF_VEC(0); static const char *vec_func_id[VEC_MAX_FUNC] = { "normalize($)", "max(min($,vec3(1,1,1)),vec3(0,0,0))", "-($)", "1.0/($)", "", "", }; int func = p_node->param1; ERR_FAIL_INDEX(func, VEC_MAX_FUNC); if (func == VEC_FUNC_RGB2HSV) { code += OUTNAME(p_node->id, 0) + ";\n"; code += "{\n"; code += "\tvec3 c = " + p_inputs[0] + ";\n"; code += "\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; code += "\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n"; code += "\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"; code += "\tfloat d = q.x - min(q.w, q.y);\n"; code += "\tfloat e = 1.0e-10;\n"; code += "\t" + OUTVAR(p_node->id, 0) + "=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; code += "}\n"; } else if (func == VEC_FUNC_HSV2RGB) { code += OUTNAME(p_node->id, 0) + ";\n"; code += "{\n"; code += "\tvec3 c = " + p_inputs[0] + ";\n"; code += "\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; code += "\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"; code += "\t" + OUTVAR(p_node->id, 0) + "=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"; code += "}\n"; } else { code += OUTNAME(p_node->id, 0) + "=" + String(vec_func_id[func]).replace("$", p_inputs[0]) + ";\n"; } } break; case NODE_VEC_LEN: { DEF_VEC(0); code += OUTNAME(p_node->id, 0) + "=length(" + p_inputs[0] + ");\n"; } break; case NODE_DOT_PROD: { DEF_VEC(0); DEF_VEC(1); code += OUTNAME(p_node->id, 0) + "=dot(" + p_inputs[1] + "," + p_inputs[0] + ");\n"; } break; case NODE_VEC_TO_SCALAR: { DEF_VEC(0); code += OUTNAME(p_node->id, 0) + "=" + p_inputs[0] + ".x;\n"; code += OUTNAME(p_node->id, 1) + "=" + p_inputs[0] + ".y;\n"; code += OUTNAME(p_node->id, 2) + "=" + p_inputs[0] + ".z;\n"; } break; case NODE_SCALAR_TO_VEC: { DEF_SCALAR(0); DEF_SCALAR(1); DEF_SCALAR(2); code += OUTNAME(p_node->id, 0) + "=vec3(" + p_inputs[0] + "," + p_inputs[1] + "," + p_inputs[2] + "" + ");\n"; } break; case NODE_VEC_TO_XFORM: { DEF_VEC(0); DEF_VEC(1); DEF_VEC(2); DEF_VEC(3); code += OUTNAME(p_node->id, 0) + "=mat4(" + "vec4(" + p_inputs[0] + ".x," + p_inputs[0] + ".y," + p_inputs[0] + ".z, 0.0)," "vec4(" + p_inputs[1] + ".x," + p_inputs[1] + ".y," + p_inputs[1] + ".z, 0.0)," "vec4(" + p_inputs[2] + ".x," + p_inputs[2] + ".y," + p_inputs[2] + ".z, 0.0)," "vec4(" + p_inputs[3] + ".x," + p_inputs[3] + ".y," + p_inputs[3] + ".z, 1.0));\n"; } break; case NODE_XFORM_TO_VEC: { DEF_MATRIX(0); code += OUTNAME(p_node->id, 0) + ";\n"; code += OUTNAME(p_node->id, 1) + ";\n"; code += OUTNAME(p_node->id, 2) + ";\n"; code += OUTNAME(p_node->id, 3) + ";\n"; code += "{\n"; code += "\tvec4 xform_row_01=" + p_inputs[0] + ".x;\n"; code += "\tvec4 xform_row_02=" + p_inputs[0] + ".y;\n"; code += "\tvec4 xform_row_03=" + p_inputs[0] + ".z;\n"; code += "\tvec4 xform_row_04=" + p_inputs[0] + ".w;\n"; code += "\t" + OUTVAR(p_node->id, 0) + "=vec3(xform_row_01.x, xform_row_01.y, xform_row_01.z);\n"; code += "\t" + OUTVAR(p_node->id, 1) + "=vec3(xform_row_02.x, xform_row_02.y, xform_row_02.z);\n"; code += "\t" + OUTVAR(p_node->id, 2) + "=vec3(xform_row_03.x, xform_row_03.y, xform_row_03.z);\n"; code += "\t" + OUTVAR(p_node->id, 3) + "=vec3(xform_row_04.x, xform_row_04.y, xform_row_04.z);\n"; code += "}\n"; } break; case NODE_SCALAR_INTERP: { DEF_SCALAR(0); DEF_SCALAR(1); DEF_SCALAR(2); code += OUTNAME(p_node->id, 0) + "=mix(" + p_inputs[0] + "," + p_inputs[1] + "," + p_inputs[2] + ");\n"; } break; case NODE_VEC_INTERP: { DEF_VEC(0); DEF_VEC(1); DEF_SCALAR(2); code += OUTNAME(p_node->id, 0) + "=mix(" + p_inputs[0] + "," + p_inputs[1] + "," + p_inputs[2] + ");\n"; } break; case NODE_COLOR_RAMP: { DEF_SCALAR(0); static const int color_ramp_len = 512; DVector cramp; cramp.resize(color_ramp_len * 4); { DVector colors = p_node->param1; DVector offsets = p_node->param2; int cc = colors.size(); DVector::Write crw = cramp.write(); DVector::Read cr = colors.read(); DVector::Read ofr = offsets.read(); int at = 0; Color color_at(0, 0, 0, 1); for (int i = 0; i <= cc; i++) { int pos; Color to; if (i == cc) { if (at == color_ramp_len) break; pos = color_ramp_len; to = Color(1, 1, 1, 1); } else { to = cr[i]; pos = MIN(ofr[i] * color_ramp_len, color_ramp_len); } for (int j = at; j < pos; j++) { float t = (j - at) / float(pos - at); Color c = color_at.linear_interpolate(to, t); crw[j * 4 + 0] = Math::fast_ftoi(CLAMP(c.r * 255.0, 0, 255)); crw[j * 4 + 1] = Math::fast_ftoi(CLAMP(c.g * 255.0, 0, 255)); crw[j * 4 + 2] = Math::fast_ftoi(CLAMP(c.b * 255.0, 0, 255)); crw[j * 4 + 3] = Math::fast_ftoi(CLAMP(c.a * 255.0, 0, 255)); } at = pos; color_at = to; } } Image gradient(color_ramp_len, 1, 0, Image::FORMAT_RGBA, cramp); Ref it = memnew(ImageTexture); it->create_from_image(gradient, Texture::FLAG_FILTER | Texture::FLAG_MIPMAPS); String crampname = "cramp_" + itos(p_node->id); set_default_texture_param(crampname, it); code += "uniform texture " + crampname + ";\n"; code += "vec4 " + crampname + "_r=tex(" + crampname + ",vec2(" + p_inputs[0] + ",0));\n"; code += OUTNAME(p_node->id, 0) + "=" + crampname + "_r.rgb;\n"; code += OUTNAME(p_node->id, 1) + "=" + crampname + "_r.a;\n"; } break; case NODE_CURVE_MAP: { DEF_SCALAR(0); static const int curve_map_len = 256; bool mapped[256]; zeromem(mapped, sizeof(mapped)); DVector cmap; cmap.resize(curve_map_len); { DVector points = p_node->param1; int pc = points.size(); DVector::Write cmw = cmap.write(); DVector::Read pr = points.read(); Vector2 prev = Vector2(0, 0); Vector2 prev2 = Vector2(0, 0); for (int i = -1; i < pc; i++) { Vector2 next; Vector2 next2; if (i + 1 >= pc) { next = Vector2(1, 1); } else { next = Vector2(pr[i + 1].x, pr[i + 1].y); } if (i + 2 >= pc) { next2 = Vector2(1, 1); } else { next2 = Vector2(pr[i + 2].x, pr[i + 2].y); } /*if (i==-1 && prev.offset==next.offset) { prev=next; continue; }*/ _plot_curve(prev2, prev, next, next2, cmw.ptr(), mapped); prev2 = prev; prev = next; } uint8_t pp = 0; for (int i = 0; i < curve_map_len; i++) { if (!mapped[i]) { cmw[i] = pp; } else { pp = cmw[i]; } } } Image gradient(curve_map_len, 1, 0, Image::FORMAT_GRAYSCALE, cmap); Ref it = memnew(ImageTexture); it->create_from_image(gradient, Texture::FLAG_FILTER | Texture::FLAG_MIPMAPS); String cmapname = "cmap_" + itos(p_node->id); set_default_texture_param(cmapname, it); code += "uniform texture " + cmapname + ";\n"; code += OUTNAME(p_node->id, 0) + "=tex(" + cmapname + ",vec2(" + p_inputs[0] + ",0)).r;\n"; } break; case NODE_SCALAR_INPUT: { String name = p_node->param1; float dv = p_node->param2; code += "uniform float " + name + "=" + rtos(dv) + ";\n"; code += OUTNAME(p_node->id, 0) + "=" + name + ";\n"; } break; case NODE_VEC_INPUT: { String name = p_node->param1; Vector3 dv = p_node->param2; code += "uniform vec3 " + name + "=vec3(" + rtos(dv.x) + "," + rtos(dv.y) + "," + rtos(dv.z) + ");\n"; code += OUTNAME(p_node->id, 0) + "=" + name + ";\n"; } break; case NODE_RGB_INPUT: { String name = p_node->param1; Color dv = p_node->param2; code += "uniform color " + name + "=vec4(" + rtos(dv.r) + "," + rtos(dv.g) + "," + rtos(dv.b) + "," + rtos(dv.a) + ");\n"; code += OUTNAME(p_node->id, 0) + "=" + name + ".rgb;\n"; code += OUTNAME(p_node->id, 1) + "=" + name + ".a;\n"; } break; case NODE_XFORM_INPUT: { String name = p_node->param1; Transform dv = p_node->param2; code += "uniform mat4 " + name + "=mat4(\n"; code += "\tvec4(vec3(" + rtos(dv.basis.get_axis(0).x) + "," + rtos(dv.basis.get_axis(0).y) + "," + rtos(dv.basis.get_axis(0).z) + "),0),\n"; code += "\tvec4(vec3(" + rtos(dv.basis.get_axis(1).x) + "," + rtos(dv.basis.get_axis(1).y) + "," + rtos(dv.basis.get_axis(1).z) + "),0),\n"; code += "\tvec4(vec3(" + rtos(dv.basis.get_axis(2).x) + "," + rtos(dv.basis.get_axis(2).y) + "," + rtos(dv.basis.get_axis(2).z) + "),0),\n"; code += "\tvec4(vec3(" + rtos(dv.origin.x) + "," + rtos(dv.origin.y) + "," + rtos(dv.origin.z) + "),1)\n"; code += ");"; code += OUTNAME(p_node->id, 0) + "=" + name + ";\n"; } break; case NODE_TEXTURE_INPUT: { DEF_VEC(0); String name = p_node->param1; String rname = "rt_read_tex" + itos(p_node->id); code += "uniform texture " + name + ";"; code += "vec4 " + rname + "=tex(" + name + "," + p_inputs[0] + ".xy);\n"; code += OUTNAME(p_node->id, 0) + "=" + rname + ".rgb;\n"; code += OUTNAME(p_node->id, 1) + "=" + rname + ".a;\n"; } break; case NODE_CUBEMAP_INPUT: { DEF_VEC(0); String name = p_node->param1; code += "uniform cubemap " + name + ";"; String rname = "rt_read_tex" + itos(p_node->id); code += "vec4 " + rname + "=texcube(" + name + "," + p_inputs[0] + ".xy);\n"; code += OUTNAME(p_node->id, 0) + "=" + rname + ".rgb;\n"; code += OUTNAME(p_node->id, 1) + "=" + rname + ".a;\n"; } break; case NODE_DEFAULT_TEXTURE: { DEF_VEC(0); if (get_mode() == MODE_CANVAS_ITEM && p_type == SHADER_TYPE_FRAGMENT) { String rname = "rt_default_tex" + itos(p_node->id); code += "vec4 " + rname + "=tex(TEXTURE," + p_inputs[0] + ".xy);\n"; code += OUTNAME(p_node->id, 0) + "=" + rname + ".rgb;\n"; code += OUTNAME(p_node->id, 1) + "=" + rname + ".a;\n"; } else { //not supported code += OUTNAME(p_node->id, 0) + "=vec3(0,0,0);\n"; code += OUTNAME(p_node->id, 1) + "=1.0;\n"; } } break; case NODE_OUTPUT: { } break; case NODE_COMMENT: { } break; case NODE_TYPE_MAX: { } } #undef DEF_SCALAR #undef DEF_COLOR #undef DEF_MATRIX #undef DEF_VEC }